Added all of the MH sources, including RCS files, in
[mmh] / docs / historical / mh-6.8.5 / uip / RCS / mhn.c,v
1 head    2.42;
2 access;
3 symbols;
4 locks; strict;
5 comment @ * @;
6
7
8 2.42
9 date    95.12.06.22.32.29;      author jromine; state Exp;
10 branches;
11 next    2.41;
12
13 2.41
14 date    95.12.06.21.05.46;      author jromine; state Exp;
15 branches;
16 next    2.40;
17
18 2.40
19 date    95.12.06.21.03.37;      author jromine; state Exp;
20 branches;
21 next    2.39;
22
23 2.39
24 date    95.12.06.21.02.05;      author jromine; state Exp;
25 branches;
26 next    2.38;
27
28 2.38
29 date    95.12.06.20.55.31;      author jromine; state Exp;
30 branches;
31 next    2.37;
32
33 2.37
34 date    95.12.06.19.20.22;      author jromine; state Exp;
35 branches;
36 next    2.36;
37
38 2.36
39 date    94.04.21.19.23.38;      author jromine; state Exp;
40 branches;
41 next    2.35;
42
43 2.35
44 date    93.10.26.22.17.44;      author jromine; state Exp;
45 branches;
46 next    2.34;
47
48 2.34
49 date    93.10.26.20.15.00;      author jromine; state Exp;
50 branches;
51 next    2.33;
52
53 2.33
54 date    93.10.26.20.11.27;      author jromine; state Exp;
55 branches;
56 next    2.32;
57
58 2.32
59 date    93.10.26.15.56.01;      author jromine; state Exp;
60 branches;
61 next    2.31;
62
63 2.31
64 date    93.10.26.15.51.19;      author jromine; state Exp;
65 branches;
66 next    2.30;
67
68 2.30
69 date    93.10.26.15.44.42;      author jromine; state Exp;
70 branches;
71 next    2.29;
72
73 2.29
74 date    93.10.26.15.41.33;      author jromine; state Exp;
75 branches;
76 next    2.28;
77
78 2.28
79 date    93.10.25.19.58.19;      author jromine; state Exp;
80 branches;
81 next    2.27;
82
83 2.27
84 date    93.10.25.19.32.05;      author jromine; state Exp;
85 branches;
86 next    2.26;
87
88 2.26
89 date    93.09.09.22.38.43;      author jromine; state Exp;
90 branches;
91 next    2.25;
92
93 2.25
94 date    93.09.01.21.46.58;      author jromine; state Exp;
95 branches;
96 next    2.24;
97
98 2.24
99 date    93.09.01.20.50.03;      author jromine; state Exp;
100 branches;
101 next    2.23;
102
103 2.23
104 date    93.08.25.17.26.22;      author jromine; state Exp;
105 branches;
106 next    2.22;
107
108 2.22
109 date    93.08.20.15.52.01;      author jromine; state Exp;
110 branches;
111 next    2.21;
112
113 2.21
114 date    92.12.15.00.20.22;      author jromine; state Exp;
115 branches;
116 next    2.20;
117
118 2.20
119 date    92.12.14.17.10.25;      author jromine; state Exp;
120 branches;
121 next    2.19;
122
123 2.19
124 date    92.12.10.22.27.15;      author jromine; state Exp;
125 branches;
126 next    2.18;
127
128 2.18
129 date    92.12.09.19.23.22;      author jromine; state Exp;
130 branches;
131 next    2.17;
132
133 2.17
134 date    92.12.03.21.58.18;      author jromine; state Exp;
135 branches;
136 next    2.16;
137
138 2.16
139 date    92.12.02.18.50.39;      author jromine; state Exp;
140 branches;
141 next    2.15;
142
143 2.15
144 date    92.11.24.18.21.54;      author jromine; state Exp;
145 branches;
146 next    2.14;
147
148 2.14
149 date    92.11.24.17.18.52;      author jromine; state Exp;
150 branches;
151 next    2.13;
152
153 2.13
154 date    92.11.24.17.18.04;      author jromine; state Exp;
155 branches;
156 next    2.12;
157
158 2.12
159 date    92.11.23.19.07.08;      author jromine; state Exp;
160 branches;
161 next    2.11;
162
163 2.11
164 date    92.11.23.19.05.18;      author jromine; state Exp;
165 branches;
166 next    2.10;
167
168 2.10
169 date    92.11.23.19.04.27;      author jromine; state Exp;
170 branches;
171 next    2.9;
172
173 2.9
174 date    92.11.11.17.57.04;      author jromine; state Exp;
175 branches;
176 next    2.8;
177
178 2.8
179 date    92.11.09.17.46.01;      author jromine; state Exp;
180 branches;
181 next    2.7;
182
183 2.7
184 date    92.11.09.17.45.19;      author jromine; state Exp;
185 branches;
186 next    2.6;
187
188 2.6
189 date    92.11.06.03.24.40;      author jromine; state Exp;
190 branches;
191 next    2.5;
192
193 2.5
194 date    92.11.04.00.47.59;      author jromine; state Exp;
195 branches;
196 next    2.4;
197
198 2.4
199 date    92.11.02.17.01.08;      author jromine; state Exp;
200 branches;
201 next    2.3;
202
203 2.3
204 date    92.10.26.16.58.47;      author jromine; state Exp;
205 branches;
206 next    2.2;
207
208 2.2
209 date    92.10.20.20.30.08;      author jromine; state Exp;
210 branches;
211 next    2.1;
212
213 2.1
214 date    92.10.20.16.26.29;      author jromine; state Exp;
215 branches;
216 next    2.0;
217
218 2.0
219 date    92.10.20.16.24.21;      author jromine; state Exp;
220 branches;
221 next    1.7;
222
223 1.7
224 date    92.05.19.21.01.53;      author jromine; state Exp;
225 branches;
226 next    1.6;
227
228 1.6
229 date    92.03.03.17.13.54;      author jromine; state Exp;
230 branches;
231 next    1.5;
232
233 1.5
234 date    92.02.18.17.36.22;      author jromine; state Exp;
235 branches;
236 next    1.4;
237
238 1.4
239 date    92.02.14.16.22.17;      author jromine; state Exp;
240 branches;
241 next    1.3;
242
243 1.3
244 date    92.02.07.16.07.46;      author jromine; state Exp;
245 branches;
246 next    1.2;
247
248 1.2
249 date    92.02.07.03.44.12;      author jromine; state Exp;
250 branches;
251 next    1.1;
252
253 1.1
254 date    92.01.31.16.28.15;      author jromine; state Exp;
255 branches;
256 next    ;
257
258
259 desc
260 @multimedia MH
261 @
262
263
264 2.42
265 log
266 @rename si_value for Solaris 2.x
267 @
268 text
269 @/* mhn.c - multi-media MH */
270 #ifndef lint
271 static char ident[] = "@@(#)$Id: mhn.c,v 2.41 1995/12/06 21:05:46 jromine Exp jromine $";
272 #endif  /* lint */
273
274 #include "../h/mh.h"
275 #include <ctype.h>
276 #include <errno.h>
277 #include <setjmp.h>
278 #include <signal.h>
279 #include <stdio.h>
280 #include "../zotnet/mts.h"
281 #include <sys/types.h>
282 #include <sys/stat.h>
283 #ifdef  BSD42
284 #include <sys/wait.h>
285 #endif
286 #ifdef LOCALE
287 #include        <locale.h>
288 #endif
289
290 /* \f */
291
292 static struct swit switches[] = {
293 #define AUTOSW     0
294     "auto", 0,
295 #define NAUTOSW    1
296     "noauto", 0,
297
298 #define CACHESW    2
299     "cache", 0,
300 #define NCACHESW   3
301     "nocache", 0,
302
303 #define CHECKSW    4
304     "check", 0,
305 #define NCHECKSW   5
306     "nocheck", 0,
307
308 #define DEBUGSW    6
309     "debug", -5,
310     
311 #define EBCDICSW   7
312     "ebcdicsafe", 0,
313 #define NEBCDICSW  8
314     "noebcdicsafe", 0,
315
316 #define FILESW   9              /* interface from show */
317     "file file", 0,
318
319 #define FORMSW     10
320     "form formfile", 4,
321
322 #define HEADSW     11
323     "headers", 0,
324 #define NHEADSW   12
325     "noheaders", 0,
326
327 #define LISTSW    13
328     "list", 0,
329 #define NLISTSW   14
330     "nolist", 0,
331
332 #define PARTSW    15
333     "part number", 0,
334
335 #define PAUSESW   16
336     "pause", 0,
337 #define NPAUSESW  17
338     "nopause", 0,
339
340 #define RCACHESW  18
341     "rcache policy", 0,
342
343 #define SIZESW    19
344     "realsize", 0,
345 #define NSIZESW   20
346     "norealsize", 0,
347
348 #define RFC934SW  21
349     "rfc934mode", 0,
350 #define NRFC934SW 22
351     "norfc934mode", 0,
352
353 #define SERIALSW  23
354     "serialonly", 0,
355 #define NSERIALSW 24
356     "noserialonly", 0,
357
358 #define SHOWSW    25
359     "show", 0,
360 #define NSHOWSW   26
361     "noshow", 0,
362
363 #define STORESW   27
364     "store", 0,
365 #define NSTORESW  28
366     "nostore", 0,
367
368 #define TYPESW    29
369     "type content", 0,
370
371 #define VERBSW    30
372     "verbose", 0,
373 #define NVERBSW   31
374     "noverbose", 0,
375
376 #define WCACHESW  32
377     "wcache policy", 0,
378     
379 #define HELPSW   33
380     "help", 4,
381
382 #define PROGSW   34
383     "moreproc program", -4,
384 #define NPROGSW  35
385     "nomoreproc", -3,
386
387 #define LENSW    36
388     "length lines", -4,
389 #define WIDSW    37
390     "width columns", -4,
391
392 #define VIAMSW   38
393     "viamail mailpath", -7,
394 #define VIASSW   39
395     "viasubj subject", -7,
396 #define VIAPSW   40
397     "viaparm arguments", -7,
398 #define VIADSW   41
399     "viadesc text", -7,
400 #define VIACSW   42
401     "viacmnt text", -7,
402 #define VIAZSW   43
403     "viadelay seconds", -8,
404 #define VIAFSW   44
405     "viafrom mailpath", -7,
406
407     NULL, 0
408 };
409
410 /* \f */
411
412 #define NPARTS  50
413 #define NTYPES  20
414
415 static struct swit caches[] = {
416 #define CACHE_NEVER     0
417     "never", 0,
418 #define CACHE_PRIVATE   1
419     "private", 0,
420 #define CACHE_PUBLIC    2
421     "public", 0,
422 #define CACHE_ASK       3
423     "ask", 0,
424
425     NULL, 0
426 };
427
428 static  int     autosw = 0;
429 static  int     cachesw = 0;
430 static  int     checksw = 0;
431         int     debugsw = 0;
432 static  int     ebcdicsw = 0;
433 static  char   *formsw = NULLCP;
434 static  int     headsw = 1;
435 static  int     listsw = 0;
436 static  int     nolist = 0;
437 static  int     nomore = 0;
438 static  int     npart = 0;
439 static  char   *parts[NPARTS + 1];
440 static  int     pausesw = 1;
441 static  char   *progsw = NULLCP;
442 static  int     rcachesw = CACHE_ASK;
443 static  int     rfc934sw = 1;
444 static  int     serialsw = 0;
445 static  int     showsw = 0;
446 static  int     sizesw = 1;
447 static  int     storesw = 0;
448 static  int     ntype = 0;
449 static  char   *types[NTYPES + 1];
450         int     verbosw = 0;
451 static  int     wcachesw = CACHE_ASK;
452
453 static  int     endian = 0;
454 static  char   *mm_charset = NULL;
455
456 static  int     xpid = 0;
457 static  int     userrs = 0;
458
459 static  char   *cache_public;
460 static  char   *cache_private;
461 static  int     cwdlen;
462 static  char   *cwd;
463 static  char   *dir;
464 static  char   *errs = NULL;
465 static  char   *tmp;
466
467
468 extern  int     errno;
469 #ifndef BSD44
470 extern  int     sys_nerr;
471 extern  char   *sys_errlist[];
472 #endif
473
474 off_t   lseek ();
475 time_t  time ();
476
477 /* \f */
478
479 #define LSTFMT1         "%4s %-5s %-24s %5s %-36s\n"
480
481 #define LSTFMT2a        "%4d "
482 #define LSTFMT2b        "%-5s %-24.24s "
483 #define LSTFMT2c1       "%5lu"
484 #define LSTFMT2c2       "%4lu%c"
485 #define LSTFMT2c3       "huge "
486 #define LSTFMT2c4       "     "
487 #define LSTFMT2d1       " %-36.36s"
488 #define LSTFMT2d2       "\t     %-65.65s\n"
489
490 static void  build_comp ();
491
492 typedef struct CTinfo {
493     char   *ci_type;
494     char   *ci_subtype;
495
496 #define NPARMS  10
497     char   *ci_attrs[NPARMS + 2];
498     char   *ci_values[NPARMS];
499
500     char   *ci_comment;
501
502     char   *ci_magic;
503 }       CTInfo, *CI;
504 #define NULLCI  ((CI) 0)
505
506 static int get_ctinfo ();
507 static int get_comment ();
508
509
510 typedef struct Content {
511     char   *c_partno;           /* within multipart content */
512
513     char   *c_vrsn;             /* Body-Version: */
514
515     char   *c_ctline;           /* Content-Type: */
516     CTInfo  c_ctinfo;
517
518     int     c_type;             /* internal form */
519 #define CT_UNKNOWN      0x00
520 #define CT_APPLICATION  0x01
521 #define CT_AUDIO        0x02
522 #define CT_IMAGE        0x03
523 #define CT_MESSAGE      0x04
524 #define CT_MULTIPART    0x05
525 #define CT_TEXT         0x06
526 #define CT_VIDEO        0x07
527 #define CT_EXTENSION    0x08
528
529     int     c_subtype;          /* filled-in by c_ctinitfnx */
530     caddr_t c_ctparams;         /*   .. */
531     caddr_t c_ctextern;         /*   .. */
532     char   *c_showproc;         /* default, if not in profile */
533     char   *c_termproc;         /* for charset madness... */
534     char   *c_storeproc;        /* overrides profile entry, if any */
535
536     int   (*c_ctinitfnx) ();    /* parse content */
537     int   (*c_ctlistfnx) ();    /* list content */
538     int   (*c_ctshowfnx) ();    /* show content */
539     int   (*c_ctstorefnx) ();   /* store content */
540     int   (*c_ctfreefnx) ();    /* free content-specific structures */
541
542
543     char   *c_celine;           /* Content-Transfer-Encoding: */
544
545     int     c_encoding;         /* internal form */
546 #define CE_UNKNOWN      0x00
547 #define CE_BASE64       0x01
548 #define CE_QUOTED       0x02
549 #define CE_8BIT         0x03
550 #define CE_7BIT         0x04
551 #define CE_BINARY       0x05
552 #define CE_EXTENSION    0x06
553 #define CE_EXTERNAL     0x07    /* for external-body */
554
555     caddr_t c_ceparams;         /* filled-in by encoding initfnx */
556
557     int   (*c_ceopenfnx) ();    /* get a stream to decoded contents */
558     int   (*c_ceclosefnx) ();   /* release stream */
559     int   (*c_celistfnx) ();    /* list decoding info */
560     unsigned long
561           (*c_cesizefnx) ();    /* size of decoded contents */
562     int   (*c_cefreefnx) ();    /* free encoding-specific structures */
563
564
565     char   *c_id;               /* Content-ID: */
566     char   *c_descr;            /* Content-Description: */
567
568     int     c_digested;         /* Content-MD5: */
569     unsigned char c_digest[16]; /*   .. */
570
571     FILE   *c_fp;               /* read contents (stream) */
572     char   *c_file;             /* read contents (file) */
573     int     c_unlink;           /* remove file when done? */
574     int     c_umask;            /* associated umask */
575     long    c_begin;            /* where content starts in file */
576     long    c_end;              /*   ..          ends           */
577
578     int     c_pid;              /* process doing display */
579     char   *c_storage;          /* write contents (file) */
580
581     int     c_rfc934;           /* rfc934 compatibility */
582 }       Content, *CT;
583 #define NULLCT  ((CT) 0)
584
585 static CT       get_content ();
586 static int      list_content (), show_content (), store_content ();
587 static int      cache_content ();
588 static int      user_content (), compose_content (), output_content ();
589 static void     free_content (), flush_errors (), set_id ();
590
591 #if     defined(__STDC__) && defined(VSPRINTF)
592 static void content_error (char *, register CT, char *, ...);
593 #else
594 static void content_error ();
595 #endif
596
597 static int   init_encoding (), type_ok (), copy_some_headers (), set_endian ();
598 static int   make_intermediates ();
599 static int   find_cache (), find_cache_aux (), find_cache_aux2 ();
600 static int   write7Bit (), writeQuoted (), writeBase64 (), writeBase64aux ();
601 static int   writeDigest (), readDigest ();
602 static int   via_mail (), via_post (), pidcheck ();
603
604 static  CT    *cts = NULL;
605
606
607 #define quitser pipeser
608 static  TYPESIG pipeser ();
609 static  char   *fgetstr ();
610
611 /* \f */
612
613 /* ARGSUSED */
614
615 main (argc, argv)
616 int     argc;
617 char  **argv;
618 {
619     int     f6 = 0,
620             msgp = 0,
621             msgnum,
622            *icachesw;
623     char   *cp,
624            *f1 = NULL,
625            *f2 = NULL,
626            *f3 = NULL,
627            *f4 = NULL,
628            *f5 = NULL,
629            *f7 = NULL,
630            *file = NULL,
631            *folder = NULL,
632            *maildir,
633             buf[100],
634           **ap,
635           **argp,
636            *arguments[MAXARGS],
637            *msgs[MAXARGS];
638     struct msgs *mp;
639     register CT  ct,
640                 *ctp;
641     FILE        *fp;
642
643 #ifdef LOCALE
644         setlocale(LC_ALL, "");
645 #endif
646     invo_name = r1bindex (argv[0], '/');
647     if (argv[1] && uprf (argv[1], "-via"))
648         m_foil (NULLCP);
649     if ((cp = m_find (invo_name)) != NULL) {
650         ap = brkstring (cp = getcpy (cp), " ", "\n");
651         ap = copyip (ap, arguments);
652     }
653     else
654         ap = arguments;
655     (void) copyip (argv + 1, ap);
656     argp = arguments;
657
658 /* \f */
659
660     while (cp = *argp++) {
661         if (*cp == '-')
662             switch (smatch (++cp, switches)) {
663                 case AMBIGSW: 
664                     ambigsw (cp, switches);
665                     done (1);
666                 case UNKWNSW: 
667                     adios (NULLCP, "-%s unknown", cp);
668                 case HELPSW: 
669                     (void) sprintf (buf, "%s [+folder] [msgs] [switches]",
670                             invo_name);
671                     help (buf, switches);
672                     done (1);
673
674                 case AUTOSW:
675                     autosw++;
676                     continue;
677                 case NAUTOSW:
678                     autosw = 0;
679                     continue;
680
681                 case CACHESW:
682                     cachesw++;
683                     continue;
684                 case NCACHESW:
685                     cachesw = 0;
686                     continue;
687
688                 case RCACHESW:
689                     icachesw = &rcachesw;
690                     goto do_cache;
691                 case WCACHESW:
692                     icachesw = &wcachesw;
693 do_cache: ;
694                     if (!(cp = *argp++) || *cp == '-')
695                         adios (NULLCP, "missing argument to %s", argp[-2]);
696                     switch (*icachesw = smatch (cp, caches)) {
697                         case AMBIGSW:
698                             ambigsw (cp, caches);
699                             done (1);
700                         case UNKWNSW:
701                             adios (NULLCP, "%s unknown", cp);
702                         default:
703                             break;
704                     }
705                     continue;
706
707                 case CHECKSW:
708                     checksw++;
709                     continue;
710                 case NCHECKSW:
711                     checksw = 0;
712                     continue;
713
714                 case DEBUGSW:
715                     debugsw++;
716                     continue;
717     
718                 case EBCDICSW:
719                     ebcdicsw++;
720                     continue;
721                 case NEBCDICSW:
722                     ebcdicsw = 0;
723                     continue;
724
725                 case FORMSW:
726                     if (!(cp = *argp++) || *cp == '-')
727                         adios (NULLCP, "missing argument to %s", argp[-2]);
728                     if (formsw)
729                         free (formsw);
730                     formsw = getcpy (libpath (cp));
731                     continue;
732
733                 case HEADSW:
734                     headsw++;
735                     continue;
736                 case NHEADSW:
737                     headsw = 0;
738                     continue;
739
740                 case LISTSW:
741                     listsw++;
742                     continue;
743                 case NLISTSW:
744                     listsw = 0;
745                     continue;
746
747                 case PARTSW:
748                     if (!(cp = *argp++) || *cp == '-')
749                         adios (NULLCP, "missing argument to %s", argp[-2]);
750                     if (npart >= NPARTS)
751                         adios (NULLCP,
752                                "too many parts (starting with %s), %d max",
753                                cp, NPARTS);
754                     parts[npart++] = cp;
755                     continue;
756
757                 case PAUSESW:
758                     pausesw++;
759                     continue;
760                 case NPAUSESW:
761                     pausesw = 0;
762                     continue;
763
764                 case RFC934SW:
765                     rfc934sw++;
766                     continue;
767                 case NRFC934SW:
768                     rfc934sw = 0;
769                     continue;
770
771                 case SERIALSW:
772                     serialsw++;
773                     continue;
774                 case NSERIALSW:
775                     serialsw = 0;
776                     continue;
777
778                 case SHOWSW:
779                     showsw++;
780                     continue;
781                 case NSHOWSW:
782                     showsw = 0;
783                     continue;
784
785                 case SIZESW:
786                     sizesw++;
787                     continue;
788                 case NSIZESW:
789                     sizesw = 0;
790                     continue;
791
792                 case STORESW:
793                     storesw++;
794                     continue;
795                 case NSTORESW:
796                     storesw = 0;
797                     continue;
798
799                 case TYPESW:
800                     if (!(cp = *argp++) || *cp == '-')
801                         adios (NULLCP, "missing argument to %s", argp[-2]);
802                     if (ntype >= NTYPES)
803                         adios (NULLCP,
804                                "too many types (starting with %s), %d max",
805                                cp, NTYPES);
806                     types[ntype++] = cp;
807                     continue;
808
809                 case VERBSW: 
810                     verbosw++;
811                     continue;
812                 case NVERBSW: 
813                     verbosw = 0;
814                     continue;
815
816                 case PROGSW:
817                     if (!(progsw = *argp++) || *progsw == '-')
818                         adios (NULLCP, "missing argument to %s", argp[-2]);
819                     continue;
820                 case NPROGSW:
821                     nomore++;
822                     continue;
823
824                 case LENSW:
825                 case WIDSW:
826                     if (!(cp = *argp++) || *cp == '-')
827                         adios (NULLCP, "missing argument to %s", argp[-2]);
828                     continue;
829
830                 case FILESW:
831                     if (!(cp = *argp++) || (*cp == '-' && cp[1]))
832                         adios (NULLCP, "missing argument to %s", argp[-2]);
833                     file = *cp == '-' ? cp : path (cp, TFILE);
834                     continue;
835
836                case VIAMSW:
837                     if (!(f1 = *argp++))
838                         adios (NULLCP, "missing argument to %s", argp[-2]);
839                     continue;
840                case VIASSW:
841                     if (!(f2 = *argp++))
842                         adios (NULLCP, "missing argument to %s", argp[-2]);
843                     continue;
844                case VIAPSW:
845                     if (!(f3 = *argp++))
846                         adios (NULLCP, "missing argument to %s", argp[-2]);
847                     continue;
848                case VIADSW:
849                     if (!(f4 = *argp++))
850                         adios (NULLCP, "missing argument to %s", argp[-2]);
851                     continue;
852                case VIACSW:
853                     if (!(f5 = *argp++))
854                         adios (NULLCP, "missing argument to %s", argp[-2]);
855                     continue;
856                case VIAZSW:
857                     if (!(cp = *argp++) || *cp == '-')
858                         adios (NULLCP, "missing argument to %s", argp[-2]);
859                     if (sscanf (cp, "%d", &f6) != 1 || f6 < 0)
860                         f6 = 300;
861                     continue;
862                case VIAFSW:
863                     if (!(f7 = *argp++))
864                         adios (NULLCP, "missing argument to %s", argp[-2]);
865                     continue;
866             }
867         if (*cp == '+' || *cp == '@@') {
868             if (folder)
869                 adios (NULLCP, "only one folder at a time!");
870             else
871                 folder = path (cp + 1, *cp == '+' ? TFOLDER : TSUBCWF);
872         }
873         else
874             msgs[msgp++] = cp;
875     }
876     parts[npart] = NULL, types[ntype] = NULL;
877     if (!formsw)
878         formsw = getcpy (libpath ("mhl.headers"));
879
880     set_endian ();
881
882 /* \f */
883
884     if (f1) {
885         via_mail (f1, f2, f3, f4, f5, f6, f7);
886         /* NOTREACHED */
887     }
888     else
889         if (f2 || f3 || f4 || f5 || f6 || f7)
890             adios (NULLCP, "missing -viamail \"mailpath\" switch");
891
892     if (cp = getenv ("MHN")) {
893         if (fp = fopen (cp, "r")) {
894             m_readefs ((struct node **) 0, fp, cp, 0);
895
896             (void) fclose (fp);
897         }
898         else
899             admonish ("", "unable to read $MHN profile (%s)", cp);
900     }
901     if (fp = fopen (cp = libpath ("mhn_defaults"), "r")) {
902         m_readefs ((struct node **) 0, fp, cp, 0);
903
904         (void) fclose (fp);
905     }
906
907     (void) sprintf (buf, "%s-cache", invo_name);
908     if ((cache_public = m_find (buf)) && *cache_public != '/')
909         cache_public = NULL;
910     (void) sprintf (buf, "%s-private-cache", invo_name);
911     if (!(cache_private = m_find (buf)))
912         cache_private = ".cache";
913     cache_private = getcpy (m_maildir (cache_private));
914
915     cwdlen = strlen (cwd = getcpy (pwd ()));
916     (void) sprintf (buf, "%s-storage", invo_name);
917     dir = getcpy ((cp = m_find (buf)) && *cp ? cp : cwd);
918     tmp = cp && *cp ? concat (cp, "/", invo_name, NULLCP)
919                     : add (m_maildir (invo_name), NULLCP);
920
921     if (!m_find ("path"))
922         free (path ("./", TFOLDER));
923
924     if (msgp == 1
925             && !folder
926             && !npart
927             && !cachesw
928             && !showsw
929             && !storesw
930             && !ntype
931             && !file
932             && (cp = getenv ("mhdraft"))
933             && strcmp (cp, msgs[0]) == 0) {
934         build_comp (cp);
935         /* NOTREACHED */
936     }
937
938     if (file) {
939         int     stdinP;
940
941         if (msgp)
942             adios (NULLCP, "only one file at a time!");
943
944         if ((cts = (CT *) calloc ((unsigned) 2, sizeof *cts)) == NULL)
945             adios (NULLCP, "out of memory");
946
947         ctp = cts;
948         if (stdinP = (strcmp (file, "-") == 0)) {
949             char    buffer[BUFSIZ];
950
951             file = add (m_tmpfil (invo_name), NULLCP);
952
953             if ((fp = fopen (file, "w+")) == NULL)
954                 adios (file, "unable to fopen for writing and reading");
955             (void) chmod (file, 0600);
956             while (fgets (buffer, sizeof buffer, stdin))
957                 (void) fputs (buffer, fp);
958             (void) fflush (fp);
959
960             if (ferror (stdin)) {
961                 (void) unlink (file);
962                 adios ("stdin", "error reading");
963             }
964
965             if (ferror (fp)) {
966                 (void) unlink (file);
967                 adios (file, "error writing");
968             }
969
970             (void) fseek (fp, 0L, 0);
971         }
972         else
973             if ((fp = fopen (file, "r")) == NULL)
974                 adios (file, "unable to read");
975
976         if (ct = get_content (fp, file, 1)) {
977             if (stdinP)
978                 ct -> c_unlink = 1;
979
980             ct -> c_fp = NULL;
981             if (ct -> c_end == 0L) {
982                 (void) fseek (fp, 0L, 2);
983                 ct -> c_end = ftell (fp);
984             }
985             if (ct -> c_ctinitfnx && (*ct -> c_ctinitfnx) (ct) == NOTOK)
986                 free_content (ct);
987             else
988                 *ctp++ = ct;
989         }
990         else
991             advise (NULLCP, "unable to decode %s", file);
992
993         (void) fclose (fp);
994
995         mp = NULL;
996         goto go_to_it;
997     }
998
999     if (!msgp)
1000         msgs[msgp++] = "cur";
1001     if (!folder)
1002         folder = m_getfolder ();
1003     maildir = m_maildir (folder);
1004
1005     if (chdir (maildir) == NOTOK)
1006         adios (maildir, "unable to change directory to");
1007     if (!(mp = m_gmsg (folder)))
1008         adios (NULLCP, "unable to read folder %s", folder);
1009     if (mp -> hghmsg == 0)
1010         adios (NULLCP, "no messages in %s", folder);
1011
1012     for (msgnum = 0; msgnum < msgp; msgnum++)
1013         if (!m_convert (mp, msgs[msgnum]))
1014             done (1);
1015     m_setseq (mp);
1016
1017     if ((cts = (CT *) calloc ((unsigned) (mp -> numsel + 1), sizeof *cts))
1018             == NULL)
1019         adios (NULLCP, "out of memory");
1020
1021     ctp = cts;
1022     for (msgnum = mp -> lowsel; msgnum <= mp -> hghsel; msgnum++)
1023         if (mp -> msgstats[msgnum] & SELECTED) {
1024             char   *msgnam;
1025
1026             if ((fp = fopen (msgnam = m_name (msgnum), "r")) == NULL)
1027                 adios (msgnam, "unable to read message");
1028
1029             if (ct = get_content (fp, msgnam, 1)) {
1030                 ct -> c_fp = NULL;
1031                 if (ct -> c_end == 0L) {
1032                     (void) fseek (fp, 0L, 2);
1033                     ct -> c_end = ftell (fp);
1034                 }
1035                 if (ct -> c_ctinitfnx && (*ct -> c_ctinitfnx) (ct) == NOTOK)
1036                     free_content (ct);
1037                 else
1038                     *ctp++ = ct;
1039             }
1040             else
1041                 advise (NULLCP, "unable to decode message %s", msgnam);
1042
1043             (void) fclose (fp);
1044         }
1045
1046 go_to_it: ;
1047     if (!*cts)
1048         done (1);
1049
1050     if (!listsw && !showsw && !storesw && !cachesw)
1051         showsw++;
1052
1053 /* listsw && showsw             -> user wants per-message listing,
1054                                    so delay until showsw processing
1055
1056           && storesw && sizesw  -> evaluating size will cause more work,
1057                                    so delay until after storesw processing
1058  */
1059     userrs = 1;
1060     (void) signal (SIGQUIT, quitser);
1061     (void) signal (SIGPIPE, pipeser);
1062
1063     for (ctp = cts; ct = *ctp; ctp++)
1064         if (type_ok (ct, 1)
1065                 && (ct -> c_ctlistfnx
1066                         || ct -> c_ctstorefnx
1067                         || ct -> c_ctshowfnx)) {
1068             struct      stat st;
1069
1070             if (!ct -> c_umask)
1071                 ct -> c_umask = ~(stat (ct -> c_file, &st) != NOTOK
1072                                         ? (st.st_mode & 0777) : m_gmprot ());
1073         }
1074
1075     if (listsw && !showsw && (!storesw || !sizesw)) {
1076         if (headsw)
1077             printf (LSTFMT1, "msg", "part", "type/subtype", "size",
1078                     "description");
1079
1080         for (ctp = cts; ct = *ctp; ctp++)
1081             if (type_ok (ct, 1) && ct -> c_ctlistfnx) {
1082                 (void) umask (ct -> c_umask);
1083                 (void) (*ct -> c_ctlistfnx) (ct, 1);
1084                 if (ct -> c_fp)
1085                     (void) fclose (ct -> c_fp), ct -> c_fp = NULL;
1086                 if (ct -> c_ceclosefnx)
1087                     (*ct -> c_ceclosefnx) (ct);
1088             }
1089
1090         flush_errors ();
1091     }
1092
1093     if (storesw) {
1094         for (ctp = cts; ct = *ctp; ctp++)
1095             if (type_ok (ct, 1) && ct -> c_ctstorefnx) {
1096                 (void) umask (ct -> c_umask);
1097                 (void) (*ct -> c_ctstorefnx) (ct, NULLCP);
1098                 if (ct -> c_fp)
1099                     (void) fclose (ct -> c_fp), ct -> c_fp = NULL;
1100                 if (ct -> c_ceclosefnx)
1101                     (*ct -> c_ceclosefnx) (ct);
1102             }
1103
1104         flush_errors ();
1105     }
1106
1107     if (cachesw) {
1108         for (ctp = cts; ct = *ctp; ctp++)
1109             if (type_ok (ct, 1)) {
1110                 cache_content (ct);
1111                 if (ct -> c_fp)
1112                     (void) fclose (ct -> c_fp), ct -> c_fp = NULL;
1113                 if (ct -> c_ceclosefnx)
1114                     (*ct -> c_ceclosefnx) (ct);
1115             }
1116
1117         flush_errors ();
1118     }
1119
1120     if (listsw && !showsw && storesw && sizesw) {
1121         if (headsw)
1122             printf (LSTFMT1, "msg", "part", "type/subtype", "size",
1123                     "description");
1124
1125         for (ctp = cts; ct = *ctp; ctp++)
1126             if (type_ok (ct, 1) && ct -> c_ctlistfnx) {
1127                 (void) umask (ct -> c_umask);
1128                 (void) (*ct -> c_ctlistfnx) (ct, 1);
1129                 if (ct -> c_fp)
1130                     (void) fclose (ct -> c_fp), ct -> c_fp = NULL;
1131                 if (ct -> c_ceclosefnx)
1132                     (*ct -> c_ceclosefnx) (ct);
1133             }
1134
1135         flush_errors ();
1136         listsw = 0;
1137     }
1138
1139     if (showsw)
1140         for (ctp = cts; ct = *ctp; ctp++) {
1141 #if defined(BSD42) && !defined(WAITINT)
1142             union wait status;
1143 #else
1144             int     status;
1145 #endif
1146             TYPESIG (*hstat) (), (*istat) (), (*qstat) (), (*tstat) ();
1147
1148             if (!type_ok (ct, 0))
1149                 continue;
1150
1151             (void) umask (ct -> c_umask);
1152
1153             if (listsw) {
1154                 if (headsw)
1155                     printf (LSTFMT1, "msg", "part", "type/subtype", "size",
1156                             "description");
1157
1158                 if (ct -> c_ctlistfnx)
1159                     (void) (*ct -> c_ctlistfnx) (ct, 1);
1160             }
1161
1162             if (!ct -> c_ctshowfnx) {
1163                 if (ct -> c_fp)
1164                     (void) fclose (ct -> c_fp), ct -> c_fp = NULL;
1165                 if (ct -> c_ceclosefnx)
1166                     (*ct -> c_ceclosefnx) (ct);
1167                 continue;
1168             }
1169
1170             if (strcmp (formsw, "mhl.null")) {
1171                 int     child_id,
1172                         i,
1173                         vecp;
1174                 char   *vec[8];
1175
1176                 vecp = 0;
1177                 vec[vecp++] = r1bindex (mhlproc, '/');
1178                 vec[vecp++] = "-form";
1179                 vec[vecp++] = formsw;
1180                 vec[vecp++] = "-nobody";
1181                 vec[vecp++] = ct -> c_file;
1182                 if (nomore)
1183                     vec[vecp++] = "-nomoreproc";
1184                 else
1185                     if (progsw) {
1186                         vec[vecp++] = "-moreproc";
1187                         vec[vecp++] = progsw;
1188                     }
1189                 vec[vecp] = NULL;
1190
1191                 (void) fflush (stdout);
1192
1193                 for (i = 0; (child_id = vfork ()) == NOTOK && i < 5; i++)
1194                     sleep (5);
1195                 switch (child_id) {
1196                     case NOTOK:
1197                         adios ("fork", "unable to");
1198                         /* NOTREACHED */
1199
1200                     case OK:
1201                         (void) execvp (mhlproc, vec);
1202                         fprintf (stderr, "unable to exec ");
1203                         perror (mhlproc);
1204                         _exit (-1);
1205                         /* NOTREACHED */
1206
1207                     default:
1208                         xpid = -child_id;
1209                         break;
1210                 }
1211             }
1212             else
1213                 xpid = 0;
1214
1215             (void) (*ct -> c_ctshowfnx) (ct, 1, 0);
1216             if (ct -> c_fp)
1217                 (void) fclose (ct -> c_fp), ct -> c_fp = NULL;
1218             if (ct -> c_ceclosefnx)
1219                 (*ct -> c_ceclosefnx) (ct);
1220
1221             hstat = signal (SIGHUP, SIG_IGN);
1222             istat = signal (SIGINT, SIG_IGN);
1223             qstat = signal (SIGQUIT, SIG_IGN);
1224             tstat = signal (SIGTERM, SIG_IGN);
1225
1226             while (wait (&status) != NOTOK) {
1227 #if defined(BSD42) && !defined(WAITINT)
1228                 (void) pidcheck (status.w_status);
1229 #else
1230                 (void) pidcheck (status);
1231 #endif
1232                 continue;
1233             }
1234
1235             (void) signal (SIGHUP, hstat);
1236             (void) signal (SIGINT, istat);
1237             (void) signal (SIGQUIT, qstat);
1238             (void) signal (SIGTERM, tstat);
1239
1240             xpid = 0;
1241
1242             flush_errors ();
1243         }
1244
1245     for (ctp = cts; *ctp; ctp++)
1246         free_content (*ctp);
1247     free ((char *) cts);
1248     cts = NULL;
1249
1250     if (mp) {
1251         m_replace (pfolder, folder);
1252         if (mp -> hghsel != mp -> curmsg)
1253             m_setcur (mp, mp -> hghsel);
1254         m_sync (mp);
1255         m_update ();
1256     }
1257
1258     done (0);
1259     /* NOTREACHED */
1260 }
1261
1262 /* \f */
1263
1264 static TYPESIG  pipeser (i)
1265 int     i;
1266 {
1267     if (i == SIGQUIT) {
1268         (void) unlink ("core");
1269
1270         (void) fflush (stdout);
1271
1272         fprintf (stderr, "\n");
1273         (void) fflush (stderr);
1274     }
1275
1276     done (1);
1277     /* NOTREACHED */
1278 }
1279
1280 /* \f */
1281
1282 #include "../h/mhn.h"
1283
1284
1285 struct str2init {
1286     char   *si_key;
1287     int     si_val;
1288     int   (*si_init) ();
1289 };
1290
1291
1292 static int InitApplication (), InitMessage (), InitMultiPart (), InitText (),
1293            InitGeneric ();
1294         
1295
1296 static struct str2init str2cts[] = {
1297     "application",  CT_APPLICATION, InitApplication,
1298     "audio",        CT_AUDIO,       InitGeneric,
1299     "image",        CT_IMAGE,       InitGeneric,
1300     "message",      CT_MESSAGE,     InitMessage,
1301     "multipart",    CT_MULTIPART,   InitMultiPart,
1302     "text",         CT_TEXT,        InitText,
1303     "video",        CT_VIDEO,       InitGeneric,
1304
1305     NULL,           CT_EXTENSION,   NULL,       /* these two must be last! */
1306     NULL,           CT_UNKNOWN,     NULL,
1307 };
1308
1309
1310 static int InitBase64 (), InitQuoted (), Init7Bit ();
1311
1312 static struct str2init str2ces[] = {
1313     "base64",           CE_BASE64,      InitBase64,
1314     "quoted-printable", CE_QUOTED,      InitQuoted,
1315     "8bit",             CE_8BIT,        Init7Bit,
1316     "7bit",             CE_7BIT,        Init7Bit,
1317     "binary",           CE_BINARY,      NULL,
1318
1319     NULL,               CE_EXTENSION,   NULL,   /* these two must be last! */
1320     NULL,               CE_UNKNOWN,     NULL,
1321 };
1322
1323 /* \f */
1324
1325 static  CT      get_content (in, file, toplevel)
1326 FILE   *in;
1327 char   *file;
1328 int     toplevel;
1329 {
1330     int     compnum,
1331             state;
1332     char    buf[BUFSIZ],
1333             name[NAMESZ];
1334     register CT ct;
1335
1336     if ((ct = (CT) calloc (1, sizeof *ct)) == NULL)
1337         adios (NULLCP, "out of memory");
1338
1339     ct -> c_begin = ftell (ct -> c_fp = in) + 1;
1340     ct -> c_file = add (file, NULLCP);
1341     for (compnum = 1, state = FLD;;) {
1342         switch (state = m_getfld (state, name, buf, sizeof buf, in)) {
1343             case FLD:
1344             case FLDPLUS:
1345             case FLDEOF:
1346                 compnum++;
1347
1348                 if (uleq (name, VRSN_FIELD)) {
1349                     int     ucmp;
1350                     char    c,
1351                            *cp,
1352                            *dp;
1353
1354                     cp = add (buf, NULLCP);
1355                     while (state == FLDPLUS) {
1356                         state = m_getfld (state, name, buf, sizeof buf, in);
1357                         cp = add (buf, cp);
1358                     }
1359
1360                     if (ct -> c_vrsn) {
1361 /*
1362                         advise (NULLCP,
1363                                 "message %s has multiple %s: fields (%s)",
1364                                 ct -> c_file, VRSN_FIELD, dp = trimcpy (cp));
1365                         free (dp);
1366  */
1367                         free (cp);
1368 /*
1369                         goto out;
1370  */
1371                         goto got_header;
1372                     }
1373
1374                     ct -> c_vrsn = cp;
1375                     while (isspace (*cp))
1376                         cp++;
1377                     for (dp = index (cp, '\n'); dp; dp = index (dp, '\n'))
1378                         *dp++ = ' ';
1379                     for (dp = cp + strlen (cp) - 1; dp >= cp; dp--)
1380                         if (!isspace (*dp))
1381                             break;
1382                     *++dp = '\0';
1383                     if (debugsw)
1384                         fprintf (stderr, "%s: %s\n", VRSN_FIELD, cp);
1385
1386                     if (*cp == '(' && get_comment (ct, &cp, 0) == NOTOK)
1387                         goto out;
1388
1389                     for (dp = cp; istoken (*dp); dp++)
1390                         continue;
1391                     c = *dp, *dp = '\0';
1392                     ucmp = uleq (cp, VRSN_VALUE);
1393                     *dp = c;
1394                     if (!ucmp)
1395                         admonish (NULLCP,
1396                                 "message %s has unknown value for %s: field (%s)",
1397                                 ct -> c_file, VRSN_FIELD, cp);
1398                     goto got_header;
1399                 }
1400
1401                 if (uleq (name, TYPE_FIELD)) {
1402                     register char  *cp;
1403                     register struct str2init *s2i;
1404                     register CI     ci = &ct -> c_ctinfo;
1405
1406                     cp = add (buf, NULLCP);
1407                     while (state == FLDPLUS) {
1408                         state = m_getfld (state, name, buf, sizeof buf, in);
1409                         cp = add (buf, cp);
1410                     }
1411
1412                     if (ct -> c_ctline) {
1413                         char   *dp = trimcpy (cp);
1414
1415                         advise (NULLCP,
1416                                 "message %s has multiple %s: fields (%s)",
1417                                 ct -> c_file, TYPE_FIELD, dp);
1418                         free (dp);
1419                         free (cp);
1420                         goto out;
1421                     }
1422
1423                     if (get_ctinfo (cp, ct, 0) == NOTOK)
1424                         goto out;
1425                     for (s2i = str2cts; s2i -> si_key; s2i++)
1426                         if (uleq (ci -> ci_type, s2i -> si_key))
1427                             break;
1428                     if (!s2i -> si_key && !uprf (ci -> ci_type, "X-"))
1429                         s2i++;
1430                     ct -> c_type = s2i -> si_val;
1431                     ct -> c_ctinitfnx = s2i -> si_init;
1432                     goto got_header;
1433                 }
1434
1435                 if (uleq (name, ENCODING_FIELD)) {
1436                     register char *cp,
1437                                   *dp;
1438                     char    c;
1439                     register struct str2init *s2i;
1440
1441                     cp = add (buf, NULLCP);
1442                     while (state == FLDPLUS) {
1443                         state = m_getfld (state, name, buf, sizeof buf, in);
1444                         cp = add (buf, cp);
1445                     }
1446
1447                     if (ct -> c_celine) {
1448                         advise (NULLCP,
1449                                 "message %s has multiple %s: fields (%s)",
1450                                 ct -> c_file, ENCODING_FIELD,
1451                                 dp = trimcpy (cp));
1452                         free (dp);
1453                         free (cp);
1454                         goto out;
1455                     }
1456
1457                     ct -> c_celine = cp;
1458                     while (isspace (*cp))
1459                         cp++;
1460                     for (dp = cp; istoken (*dp); dp++)
1461                         continue;
1462                     c = *dp, *dp = '\0';
1463                     for (s2i = str2ces; s2i -> si_key; s2i++)
1464                         if (uleq (cp, s2i -> si_key))
1465                             break;
1466                     if (!s2i -> si_key && !uprf (cp, "X-"))
1467                         s2i++;
1468                     *dp = c;
1469                     ct -> c_encoding = s2i -> si_val;
1470                     if (s2i -> si_init && (*s2i -> si_init) (ct) == NOTOK)
1471                         goto out;
1472                     goto got_header;
1473                 }
1474
1475                 if (uleq (name, ID_FIELD)) {
1476                     ct -> c_id = add (buf, ct -> c_id);
1477                     while (state == FLDPLUS) {
1478                         state = m_getfld (state, name, buf, sizeof buf, in);
1479                         ct -> c_id = add (buf, ct -> c_id);
1480                     }
1481                     goto got_header;
1482                 }
1483
1484                 if (uleq (name, DESCR_FIELD)) {
1485                     ct -> c_descr = add (buf, ct -> c_descr);
1486                     while (state == FLDPLUS) {
1487                         state = m_getfld (state, name, buf, sizeof buf, in);
1488                         ct -> c_descr = add (buf, ct -> c_descr);
1489                     }
1490                     goto got_header;
1491                 }
1492
1493                 if (uleq (name, MD5_FIELD)) {
1494                     char   *cp,
1495                            *dp,
1496                            *ep;
1497
1498                     cp = add (buf, NULLCP);
1499                     while (state == FLDPLUS) {
1500                         state = m_getfld (state, name, buf, sizeof buf, in);
1501                         cp = add (buf, cp);
1502                     }
1503
1504                     if (!checksw) {
1505                         free (cp);
1506                         goto got_header;
1507                     }
1508
1509                     if (ct -> c_digested) {
1510                         advise (NULLCP,
1511                                 "message %s has multiple %s: fields (%s)",
1512                                 ct -> c_file, MD5_FIELD,
1513                                 dp = trimcpy (cp));
1514                         free (dp);
1515                         free (cp);
1516                         goto out;
1517                     }
1518
1519                     ep = cp;
1520                     while (isspace (*cp))
1521                         cp++;
1522                     for (dp = index (cp, '\n'); dp; dp = index (dp, '\n'))
1523                         *dp++ = ' ';
1524                     for (dp = cp + strlen (cp) - 1; dp >= cp; dp--)
1525                         if (!isspace (*dp))
1526                             break;
1527                     *++dp = '\0';
1528                     if (debugsw)
1529                         fprintf (stderr, "%s: %s\n", MD5_FIELD, cp);
1530
1531                     if (*cp == '(' && get_comment (ct, &cp, 0) == NOTOK) {
1532                         free (ep);
1533                         goto out;
1534                     }
1535
1536                     for (dp = cp; *dp && !isspace (*dp); dp++)
1537                         continue;
1538                     *dp = '\0';
1539
1540                     (void) readDigest (ct, cp);
1541                     free (ep);
1542                     ct -> c_digested++;
1543                     goto got_header;
1544                 }
1545
1546 #ifdef  notdef
1547                 if (uprf (name, XXX_FIELD_PRF))
1548                     advise (NULLCP, "unknown field (%s) in message %s",
1549                             name, ct -> c_file);
1550                 /* and fall... */
1551 #endif
1552
1553                 while (state == FLDPLUS)
1554                     state = m_getfld (state, name, buf, sizeof buf, in);
1555 got_header: ;
1556                 if (state != FLDEOF) {
1557                     ct -> c_begin = ftell (in) + 1;
1558                     continue;
1559                 }
1560                 /* else fall... */
1561
1562             case BODY:
1563             case BODYEOF:
1564                 ct -> c_begin = ftell (in) - strlen (buf);
1565                 break;
1566
1567             case FILEEOF:
1568                 ct -> c_begin = ftell (in);
1569                 break;
1570
1571             case LENERR:
1572             case FMTERR:
1573                 adios (NULLCP, "message format error in component #%d",
1574                        compnum);
1575
1576             default:
1577                 adios (NULLCP, "getfld() returned %d", state);
1578         }
1579         break;
1580     }
1581
1582     if (!ct -> c_ctline) {
1583         if (toplevel < 0) {
1584             if (get_ctinfo ("message/rfc822", ct, 0) == NOTOK)
1585                 goto out;
1586             ct -> c_type = CT_MESSAGE;
1587             ct -> c_ctinitfnx = InitMessage;
1588         }
1589         else {
1590             if (get_ctinfo ("text/plain", ct, 0) == NOTOK)
1591                 goto out;
1592             ct -> c_type = CT_TEXT;
1593             ct -> c_ctinitfnx = InitText;
1594         }
1595     }
1596     if (!ct -> c_ctlistfnx)
1597         ct -> c_ctlistfnx = list_content;
1598     if (!ct -> c_ctshowfnx)
1599         ct -> c_ctshowfnx = show_content;
1600     if (!ct -> c_ctstorefnx)
1601         ct -> c_ctstorefnx = store_content;
1602
1603     if (!ct -> c_celine) {
1604         ct -> c_encoding = CE_7BIT;
1605         (void) Init7Bit (ct);
1606     }
1607
1608     return ct;
1609
1610 out:
1611     free_content (ct);
1612     return NULLCT;
1613 }
1614
1615 /* \f */
1616
1617 static int  get_ctinfo (cp, ct, magic)
1618 char  *cp;
1619 register CT     ct;
1620 int     magic;
1621 {
1622     int     i = strlen (invo_name) + 2;
1623     register char  *dp,
1624                   **ap,
1625                   **ep;
1626     char    c;
1627     register CI     ci = &ct -> c_ctinfo;
1628
1629     cp = ct -> c_ctline = add (cp, NULLCP);
1630     while (isspace (*cp))
1631         cp++;
1632     for (dp = index (cp, '\n'); dp; dp = index (dp, '\n'))
1633         *dp++ = ' ';
1634     for (dp = cp + strlen (cp) - 1; dp >= cp; dp--)
1635         if (!isspace (*dp))
1636             break;
1637     *++dp = '\0';
1638     if (debugsw)
1639         fprintf (stderr, "%s: %s\n", TYPE_FIELD, cp);
1640
1641     if (*cp == '(' && get_comment (ct, &cp, 1) == NOTOK)
1642         return NOTOK;
1643
1644     for (dp = cp; istoken (*dp); dp++)
1645         continue;
1646     c = *dp, *dp = '\0';
1647     ci -> ci_type = add (cp, NULLCP);
1648     *dp = c, cp = dp;
1649
1650     if (!*ci -> ci_type) {
1651         advise (NULLCP, "invalid %s: field in message %s (empty type)", 
1652                 TYPE_FIELD, ct -> c_file);
1653         return NOTOK;
1654     }
1655
1656     for (dp = ci -> ci_type; *dp; dp++)
1657         if (isalpha(*dp) && isupper (*dp))
1658             *dp = tolower (*dp);
1659
1660     while (isspace (*cp))
1661         cp++;
1662
1663     if (*cp == '(' && get_comment (ct, &cp, 1) == NOTOK)
1664         return NOTOK;
1665
1666     if (*cp != '/') {
1667         if (!magic)
1668             ci -> ci_subtype = add ("", NULLCP);
1669         goto magic_skip;
1670     }
1671
1672     cp++;
1673     while (isspace (*cp))
1674         cp++;
1675
1676     if (*cp == '(' && get_comment (ct, &cp, 1) == NOTOK)
1677         return NOTOK;
1678
1679     for (dp = cp; istoken (*dp); dp++)
1680         continue;
1681     c = *dp, *dp = '\0';
1682     ci -> ci_subtype = add (cp, NULLCP);
1683     *dp = c, cp = dp;
1684
1685     if (!*ci -> ci_subtype) {
1686         advise (NULLCP,
1687                 "invalid %s: field in message %s (empty subtype for \"%s\")",
1688                 TYPE_FIELD, ct -> c_file, ci -> ci_type);
1689         return NOTOK;
1690     }
1691
1692     for (dp = ci -> ci_subtype; *dp; dp++)
1693         if (isalpha(*dp) && isupper (*dp))
1694             *dp = tolower (*dp);
1695
1696 magic_skip: ;
1697     while (isspace (*cp))
1698         cp++;
1699
1700     if (*cp == '(' && get_comment (ct, &cp, 1) == NOTOK)
1701         return NOTOK;
1702
1703     ep = (ap = ci -> ci_attrs) + NPARMS;
1704     while (*cp == ';') {
1705         char   *vp,
1706                *up;
1707
1708         if (ap >= ep) {
1709             advise (NULLCP,
1710                     "too many parameters in message %s's %s: field (%d max)",
1711                     ct -> c_file, TYPE_FIELD, NPARMS);
1712             return NOTOK;
1713         }
1714
1715         cp++;
1716         while (isspace (*cp))
1717             cp++;
1718
1719         if (*cp == '(' && get_comment (ct, &cp, 1) == NOTOK)
1720             return NOTOK;
1721
1722         if (*cp == 0) {
1723             advise (NULLCP,
1724                     "extraneous trailing ';' in message %s's %s: parameter list",
1725                     ct -> c_file, TYPE_FIELD);
1726             return OK;
1727         }
1728
1729         for (dp = cp; istoken (*dp); dp++)
1730             if (isalpha(*dp) && isupper (*dp))
1731                 *dp = tolower (*dp);
1732         for (up = dp; isspace (*dp); )
1733             dp++;
1734         if (dp == cp || *dp != '=') {
1735             advise (NULLCP,
1736                     "invalid parameter in message %s's %s: field\n%*.*sparameter %s (error detected at offset %d)",
1737                     ct -> c_file, TYPE_FIELD, i, i, "", cp, dp - cp);
1738             return NOTOK;
1739         }
1740
1741         vp = (*ap = add (cp, NULLCP)) + (up - cp);
1742         *vp = '\0';
1743         for (dp++; isspace (*dp); )
1744             dp++;
1745         ci -> ci_values[ap - ci -> ci_attrs] = vp = *ap + (dp - cp);
1746         if (*dp == '"') {
1747             for (cp = ++dp, dp = vp;;) {
1748                 switch (c = *cp++) {
1749                     case '\0':
1750 bad_quote: ;
1751                         advise (NULLCP,
1752                                 "invalid quoted-string in message %s's %s: field\n%*.*s(parameter %s)",
1753                                 ct -> c_file, TYPE_FIELD, i, i, "", *ap);
1754                         return NOTOK;
1755
1756                     case '\\':
1757                         *dp++ = c;
1758                         if ((c = *cp++) == '\0')
1759                             goto bad_quote;
1760                         /* else fall... */
1761
1762                     default:
1763                         *dp++ = c;
1764                         continue;
1765
1766                     case '"':
1767                         *dp = '\0';
1768                         break;
1769                 }
1770                 break;
1771             }
1772         }
1773         else {
1774             for (cp = dp, dp = vp; istoken (*cp); cp++, dp++)
1775                 continue;
1776             *dp = '\0';
1777         }
1778         if (!*vp) {
1779             advise (NULLCP,
1780                     "invalid parameter in message %s's %s: field\n%*.*s(parameter %s)",
1781                     ct -> c_file, TYPE_FIELD, i, i, "", *ap);
1782             return NOTOK;
1783         }
1784         ap++;
1785
1786         while (isspace (*cp))
1787             cp++;
1788
1789         if (*cp == '(' && get_comment (ct, &cp, 1) == NOTOK)
1790             return NOTOK;
1791     }
1792
1793     if (magic && *cp == '<') {
1794         if (ct -> c_id)
1795             free (ct -> c_id), ct -> c_id = NULL;
1796
1797         if (!(dp = index (ct -> c_id = ++cp, '>'))) {
1798             advise (NULLCP, "invalid ID in message %s", ct -> c_file);
1799             return NOTOK;
1800         }
1801         
1802         c = *dp, *dp = '\0';
1803         if (*ct -> c_id)
1804             ct -> c_id = concat ("<", ct -> c_id, ">\n", NULLCP);
1805         else
1806             ct -> c_id = NULL;
1807         *dp++ = c, cp = dp;
1808
1809         while (isspace (*cp))
1810             cp++;
1811     }
1812
1813     if (magic && *cp == '[') {
1814         ct -> c_descr = ++cp;
1815         for (dp = cp + strlen (cp) - 1; dp >= cp; dp--)
1816             if (*dp == ']')
1817                 break;
1818         if (dp < cp) {
1819             advise (NULLCP, "invalid description in message %s", ct -> c_file);
1820             ct -> c_descr = NULL;
1821             return NOTOK;
1822         }
1823         
1824         c = *dp, *dp = '\0';
1825         if (*ct -> c_descr)
1826             ct -> c_descr = concat (ct -> c_descr, "\n", NULLCP);
1827         else
1828             ct -> c_descr = NULL;
1829         *dp++ = c, cp = dp;
1830
1831         while (isspace (*cp))
1832             cp++;
1833     }
1834
1835     if (*cp) {
1836         if (magic)
1837             ci -> ci_magic = add (cp, NULLCP);
1838         else
1839             advise (NULLCP,
1840                     "extraneous information in message %s's %s: field\n%*.*s(%s)",
1841                 ct -> c_file, TYPE_FIELD, i, i, "", cp);
1842     }
1843
1844     return OK;
1845 }
1846
1847 /* \f */
1848
1849 static int  get_comment (ct, ap, istype)
1850 CT      ct;
1851 char  **ap;
1852 int     istype;
1853 {
1854     register int    i;
1855     register char  *bp,
1856                    *cp;
1857     char    c,
1858             buffer[BUFSIZ],
1859            *dp;
1860     register CI     ci = &ct -> c_ctinfo;
1861
1862     cp = *ap;
1863
1864     bp = buffer;
1865     cp++;
1866     for (i = 0;;) {
1867         switch (c = *cp++) {
1868             case '\0':
1869 invalid: ;
1870                 advise (NULLCP, "invalid comment in message %s's %s: field",
1871                         ct -> c_file, istype ? TYPE_FIELD : VRSN_FIELD);
1872                 return NOTOK;
1873
1874             case '\\':
1875                 *bp++ = c;
1876                 if ((c = *cp++) == '\0')
1877                     goto invalid;
1878                 *bp++ = c;
1879                 continue;
1880
1881             case '(':
1882                 i++;
1883                 /* and fall... */
1884             default:
1885                 *bp++ = c;
1886                 continue;
1887
1888             case ')':
1889                 if (--i < 0)
1890                     break;
1891                 *bp++ = c;
1892                 continue;
1893         }
1894         break;
1895     }
1896     *bp = '\0';
1897
1898     if (istype) {
1899         if (dp = ci -> ci_comment) {
1900             ci -> ci_comment = concat (dp, " ", buffer, NULLCP);
1901             free (dp);
1902         }
1903         else
1904             ci -> ci_comment = add (buffer, NULLCP);
1905     }
1906
1907     while (isspace (*cp))
1908         cp++;
1909
1910     *ap = cp;
1911
1912     return OK;
1913 }
1914
1915 /* \f */
1916
1917 #define empty(s)        ((s) ? (s) : "")
1918
1919
1920 static int  list_content (ct, toplevel)
1921 register CT     ct;
1922 int     toplevel;
1923 {
1924     unsigned long size;
1925     register char **ap,
1926                   **ep;
1927     char   *cp,
1928             buffer[BUFSIZ];
1929     register CI     ci = &ct -> c_ctinfo;
1930
1931     printf (toplevel > 0 ? LSTFMT2a : toplevel < 0 ? "part " : "     ",
1932             atoi (r1bindex (empty (ct -> c_file), '/')));
1933     (void) sprintf (buffer, "%s/%s", empty (ci -> ci_type),
1934                     empty (ci -> ci_subtype));
1935     printf (LSTFMT2b, empty (ct -> c_partno), buffer);
1936
1937     size = ct -> c_cesizefnx && sizesw ? (*ct -> c_cesizefnx) (ct)
1938                                        : ct -> c_end - ct -> c_begin;
1939
1940     for (cp = " KMGT"; size > 9999; size >>= 10)
1941         if (!*++cp)
1942             break;
1943     switch (*cp) {
1944         case ' ':
1945             if (size > 0 || ct -> c_encoding != CE_EXTERNAL)
1946                 printf (LSTFMT2c1, size);
1947             else
1948                 printf (LSTFMT2c4);
1949             break;
1950
1951         default:
1952             printf (LSTFMT2c2, size, *cp);
1953             break;
1954
1955         case '\0':
1956             printf (LSTFMT2c3);
1957     }
1958
1959     if (ct -> c_descr) {
1960         char   *dp;
1961
1962         dp = trimcpy (cp = add (ct -> c_descr, NULLCP));
1963         free (cp);
1964         printf (LSTFMT2d1, dp);
1965         free (dp);
1966     }
1967
1968     printf ("\n");
1969
1970     if (verbosw && ci -> ci_comment) {
1971         char   *dp;
1972
1973         dp = trimcpy (cp = add (ci -> ci_comment, NULLCP));
1974         free (cp);
1975         (void) sprintf (buffer, "(%s)", dp);
1976         free (dp);
1977         printf (LSTFMT2d2, buffer);
1978     }
1979
1980     if (!debugsw)
1981         return OK;
1982
1983     (void) fflush (stdout);
1984
1985     fprintf (stderr, "  partno \"%s\"\n", empty (ct -> c_partno));
1986
1987     if (ct -> c_vrsn)
1988         fprintf (stderr, "  %s:%s\n", VRSN_FIELD, ct -> c_vrsn);
1989
1990     if (ct -> c_ctline)
1991         fprintf (stderr, "  %s:%s", TYPE_FIELD, ct -> c_ctline);
1992     fprintf (stderr,
1993              "    type \"%s\"  subtype \"%s\"  comment \"%s\"  magic \"%s\"\n",
1994              empty (ci -> ci_type), empty (ci -> ci_subtype),
1995              empty (ci -> ci_comment), empty (ci -> ci_magic));
1996     for (ap = ci -> ci_attrs, ep = ci -> ci_values; *ap; ap++, ep++)
1997         fprintf (stderr, "      parameter %s=\"%s\"\n", *ap, *ep);
1998     fprintf (stderr,
1999              "    type 0x%x subtype 0x%x params 0x%x\n",
2000              ct -> c_type, ct -> c_subtype, ct -> c_ctparams);
2001
2002     fprintf (stderr, "     showproc \"%s\"\n", empty (ct -> c_showproc));
2003     fprintf (stderr, "     termproc \"%s\"\n", empty (ct -> c_termproc));
2004     fprintf (stderr, "    storeproc \"%s\"\n", empty (ct -> c_storeproc));
2005
2006     if (ct -> c_celine)
2007         fprintf (stderr, "  %s:%s", ENCODING_FIELD, ct -> c_celine);
2008     fprintf (stderr, "    encoding 0x%x params 0x%x\n",
2009              ct -> c_encoding, ct -> c_ceparams);
2010
2011     if (ct -> c_id)
2012         fprintf (stderr, "  %s:%s", ID_FIELD, ct -> c_id);
2013     if (ct -> c_descr)
2014         fprintf (stderr, "  %s:%s", DESCR_FIELD, ct -> c_descr);
2015
2016     fprintf (stderr, "  fp 0x%x file \"%s\" begin %d end %d\n",
2017              ct -> c_fp, empty (ct -> c_file), ct -> c_begin, ct -> c_end);
2018
2019     if (ct -> c_celistfnx)
2020         (void) (*ct -> c_celistfnx) (ct);
2021
2022     return OK;
2023 }
2024 #undef  empty
2025
2026 /* \f */
2027
2028 #ifdef VSPRINTF
2029 #ifdef __STDC__
2030 #include <stdarg.h>
2031 #else
2032 #include <varargs.h>
2033 #endif
2034 #endif
2035
2036 #ifdef VSPRINTF
2037 #ifdef __STDC__
2038 static void content_error (char *what, register CT ct, char *fmt, ...)
2039 #else
2040 static void  content_error (va_alist)
2041 va_dcl
2042 #endif
2043 #else   /* !VSPRINTF */
2044 /* VARARGS3 */
2045 static void  content_error (what, ct, fmt, a, b, c, d, e, f)
2046 char   *what,
2047        *fmt,
2048        *a,
2049        *b,
2050        *c,
2051        *d,
2052        *e,
2053        *f;
2054 register CT     ct;
2055 #endif
2056 {
2057 #ifdef VSPRINTF
2058     va_list arglist;
2059 #endif
2060 #if defined(VSPRINTF) && !defined(__STDC__)
2061     char *what, *fmt;
2062     register CT ct;
2063 #endif
2064     int     i;
2065     register char *bp;
2066     char   buffer[BUFSIZ];
2067     register CI    ci;
2068
2069     bp = buffer;
2070
2071     if (userrs && invo_name && *invo_name) {
2072         (void) sprintf (bp, "%s: ", invo_name);
2073         bp += strlen (bp);
2074     }
2075
2076 #ifdef VSPRINTF
2077 #ifdef __STDC__
2078     va_start (arglist, fmt);
2079 #else
2080     va_start (arglist);
2081     what = va_arg(arglist, char *);
2082     ct   = va_arg(arglist, CT);
2083     fmt  = va_arg(arglist, char *);
2084 #endif
2085     (void) vsprintf (bp, fmt, arglist);
2086     bp += strlen (bp);
2087 #else
2088     (void) sprintf (bp, fmt, a, b, c, d, e, f);
2089     bp += strlen (bp);
2090 #endif
2091     ci = &ct -> c_ctinfo;
2092
2093     if (what) {
2094         if (*what) {
2095             (void) sprintf (bp, " %s: ", what);
2096             bp += strlen (bp);
2097         }
2098
2099         if (errno > 0 && errno < sys_nerr)
2100             (void) sprintf (bp, "%s", sys_errlist[errno]);
2101         else
2102             (void) sprintf (bp, "Error %d", errno);
2103         bp += strlen (bp);
2104     }
2105
2106     i = strlen (invo_name) + 2;
2107     (void) sprintf (bp, "\n%*.*s(content %s/%s", i, i, "", ci -> ci_type,
2108                     ci -> ci_subtype);
2109     bp += strlen (bp);
2110     if (ct -> c_file) {
2111         (void) sprintf (bp, " in message %s", ct -> c_file);
2112         bp += strlen (bp);
2113         if (ct -> c_partno) {
2114             (void) sprintf (bp, ", part %s", ct -> c_partno);
2115             bp += strlen (bp);
2116         }
2117     }
2118     (void) sprintf (bp, ")");
2119     bp += strlen (bp);
2120
2121     if (userrs) {
2122         *bp++ = '\n';
2123         *bp = '\0';
2124
2125         errs = add (buffer, errs);
2126     }
2127     else
2128         advise (NULLCP, "%s", buffer);
2129 }
2130
2131
2132 static void  flush_errors ()
2133 {
2134     if (errs) {
2135         (void) fflush (stdout);
2136         fprintf (stderr, "%s", errs);
2137         free (errs);
2138         errs = NULL;
2139     }
2140 }
2141
2142 /* \f */
2143
2144 static  jmp_buf intrenv;
2145
2146
2147 /* ARGSUSED */
2148
2149 static TYPESIG  intrser (i)
2150 int     i;
2151 {
2152 #ifdef  BSD42
2153     (void) signal (SIGINT, intrser);
2154 #endif
2155
2156     (void) putchar ('\n');
2157
2158     longjmp (intrenv, DONE);
2159 }
2160
2161 /* \f */
2162
2163 static int      show_content_aux (), show_content_aux2 ();
2164
2165
2166 static int  show_content (ct, serial, alternate)
2167 register CT     ct;
2168 int     serial,
2169         alternate;
2170 {
2171     register char  *cp;
2172     char    buffer[BUFSIZ];
2173     register CI ci = &ct -> c_ctinfo;
2174
2175     (void) sprintf (buffer, "%s-show-%s/%s", invo_name, ci -> ci_type,
2176                     ci -> ci_subtype);
2177     if ((cp = m_find (buffer)) == NULL || *cp == 0) {
2178         (void) sprintf (buffer, "%s-show-%s", invo_name, ci -> ci_type);
2179         if (((cp = m_find (buffer)) == NULL || *cp == 0)
2180                 && (cp = ct -> c_showproc) == NULL) {
2181             if (!alternate)
2182                 content_error (NULLCP, ct,
2183                                "don't know how to display content");
2184
2185             return NOTOK;
2186         }
2187     }
2188
2189     return show_content_aux (ct, serial, alternate, cp, NULLCP);
2190 }
2191
2192
2193 static int  show_content_aux (ct, serial, alternate, cp, cracked)
2194 register CT     ct;
2195 int     serial,
2196         alternate;
2197 register char   *cp;
2198 char   *cracked;
2199 {
2200     int     fd,
2201             xlist,
2202             xpause,
2203             xstdin,
2204             xtty;
2205     register char  *bp;
2206     char   *file,
2207             buffer[BUFSIZ];
2208     register CI ci = &ct -> c_ctinfo;
2209
2210     if (!ct -> c_ceopenfnx) {
2211         if (!alternate)
2212             content_error (NULLCP, ct, "don't know how to decode content");
2213
2214         return NOTOK;
2215     }
2216
2217     file = NULL;
2218     if ((fd = (*ct -> c_ceopenfnx) (ct, &file)) == NOTOK)
2219         return NOTOK;
2220     if (ct -> c_showproc && strcmp (ct -> c_showproc, "true") == 0)
2221         return (alternate ? DONE : OK);
2222     
2223     xlist = xpause = xstdin = xtty = 0;
2224     if (cracked) {
2225         (void) strcpy (buffer, cp);
2226         goto got_command;
2227     }
2228     buffer[0] = '\0';
2229     for (bp = buffer; *cp; cp++)
2230         if (*cp == '%') {
2231             switch (*++cp) {
2232                 case 'a':       /* additional arguments */
2233                     {
2234                         register char **ap,
2235                                       **ep;
2236                         char   *s = "";
2237
2238                         for (ap = ci -> ci_attrs, ep = ci -> ci_values;
2239                                  *ap;
2240                                  ap++, ep++) {
2241                             (void) sprintf (bp, "%s%s=\"%s\"", s, *ap, *ep);
2242                             bp += strlen (bp);
2243                             s = " ";
2244                         }
2245                     }
2246                     break;
2247
2248                 case 'd':       /* content description */
2249                     if (ct -> c_descr) {
2250                         char   *s;
2251
2252                         (void) strcpy (bp, s = trimcpy (ct -> c_descr));
2253                         free (s);
2254                     }
2255                     break;
2256
2257                 case 'e':       /* exclusive execution */
2258                     xtty = 1;
2259                     break;
2260
2261                 case 'F':       /* %e, %f, and stdin is terminal not content */
2262                     xstdin = xtty = 1;
2263                     /* and fall... */
2264                 case 'f':       /* filename */
2265                     (void) sprintf (bp, "%s", file);
2266                     break;
2267
2268                 case 'p':       /* pause prior to displaying content */
2269                     xpause = pausesw;
2270                     /* and fall... */
2271                 case 'l':       /* display listing prior to displaying
2272                                    content */
2273                     xlist = !nolist;
2274                     break;
2275
2276                 case 's':       /* subtype */
2277                     (void) strcpy (bp, ci -> ci_subtype);
2278                     break;
2279
2280                 case '%':
2281                     goto raw;
2282
2283                 default:
2284                     *bp++ = *--cp;
2285                     *bp = '\0';
2286                     continue;
2287             }
2288             bp += strlen (bp);
2289         }
2290         else {
2291 raw: ;
2292             *bp++ = *cp;
2293             *bp = '\0';
2294         }
2295     if (ct -> c_termproc) {
2296         char    term[BUFSIZ];
2297
2298         (void) strcpy (term, buffer);
2299         (void) sprintf (buffer, ct -> c_termproc, term);
2300     }
2301
2302 got_command: ;
2303     return show_content_aux2 (ct, serial, alternate, cracked, buffer,
2304                               fd, xlist, xpause, xstdin, xtty);
2305 }
2306
2307
2308 static int  show_content_aux2 (ct, serial, alternate, cracked, buffer,
2309                               fd, xlist, xpause, xstdin, xtty)
2310 register CT     ct;
2311 int     serial,
2312         alternate;
2313 char   *cracked,
2314        *buffer;
2315 int     fd,
2316         xlist,
2317         xpause,
2318         xstdin,
2319         xtty;
2320 {
2321     int     child_id,
2322             i;
2323     char   *vec[4],
2324             exec[BUFSIZ + sizeof "exec "];
2325     register CI ci = &ct -> c_ctinfo;
2326     
2327     if (debugsw || cracked) {
2328         (void) fflush (stdout);
2329
2330         fprintf (stderr, "%s msg %s", cracked ? "storing" : "show",
2331                  ct -> c_file);
2332         if (ct -> c_partno)
2333             fprintf (stderr, " part %s", ct -> c_partno);
2334         if (cracked)
2335             fprintf (stderr, " using command (cd %s; %s)\n", cracked, buffer);
2336         else
2337             fprintf (stderr, " using command %s\n", buffer);
2338     }
2339
2340     if (xpid < 0 || (xtty && xpid)) {
2341         if (xpid < 0)
2342             xpid = -xpid;
2343         (void) pidcheck (pidwait (xpid, NOTOK));
2344         xpid = 0;
2345     }
2346
2347     if (xlist) {
2348         char    prompt[BUFSIZ];
2349
2350         if (ct -> c_ctlistfnx) {
2351             if (ct -> c_type == CT_MULTIPART)
2352                 (void) list_content (ct, -1);
2353             else
2354                 (*ct -> c_ctlistfnx) (ct, -1);
2355
2356             if (xpause && SOprintf ("Press <return> to show content..."))
2357                 printf ("Press <return> to show content...");
2358         }
2359         else {
2360             register char *pp;
2361
2362             pp = prompt;
2363             if (ct -> c_descr) {
2364                 (void) sprintf (pp, "%s (", ct -> c_descr);
2365                 pp += strlen (pp);
2366             }
2367
2368             (void) sprintf (pp, "content %s/%s", ci -> ci_type,
2369                             ci -> ci_subtype);
2370             pp += strlen (pp);
2371             if (ct -> c_file) {
2372                 (void) sprintf (pp, " in message %s", ct -> c_file);
2373                 pp += strlen (pp);
2374                 if (ct -> c_partno) {
2375                     (void) sprintf (pp, ", part %s", ct -> c_partno);
2376                     pp += strlen (pp);
2377                 }
2378             }
2379
2380             if (ct -> c_descr) {
2381                 (void) sprintf (pp, ")");
2382                 pp += strlen (pp);
2383             }
2384
2385             if (!xpause)
2386                 printf ("%s\n", prompt);
2387             else
2388                 if (SOprintf ("Press <return> to show %s...", prompt))
2389                     printf ("Press <return> to show %s...", prompt);
2390         }
2391
2392         if (xpause) {
2393             int     intr;
2394             TYPESIG (*istat) ();
2395
2396             istat = signal (SIGINT, intrser);
2397             if ((intr = setjmp (intrenv)) == OK) {
2398                 (void) fflush (stdout);
2399                 prompt[0] = 0;
2400                 (void) read (fileno (stdout), prompt, sizeof prompt);
2401             }
2402             (void) signal (SIGINT, istat);
2403             if (intr != OK || prompt[0] == 'q') {
2404                 (void) (*ct -> c_ceclosefnx) (ct);
2405                 return (alternate ? DONE : NOTOK);
2406             }
2407         }
2408     }
2409
2410     (void) sprintf (exec, "exec %s", buffer);
2411
2412     vec[0] = "/bin/sh";
2413     vec[1] = "-c";
2414     vec[2] = exec;
2415     vec[3] = NULL;
2416
2417     (void) fflush (stdout);
2418
2419     for (i = 0; (child_id = vfork ()) == NOTOK && i < 5; i++)
2420         sleep (5);
2421     switch (child_id) {
2422         case NOTOK:
2423             advise ("fork", "unable to");
2424             (void) (*ct -> c_ceclosefnx) (ct);
2425             return NOTOK;
2426
2427         case OK:
2428             if (cracked)
2429                 (void) chdir (cracked);
2430             if (!xstdin)
2431                 (void) dup2 (fd, 0);
2432             (void) close (fd);
2433             (void) execvp ("/bin/sh", vec);
2434             fprintf (stderr, "unable to exec ");
2435             perror ("/bin/sh");
2436             _exit (-1);
2437             /* NOTREACHED */
2438
2439         default:
2440             if (!serial) {
2441                 ct -> c_pid = child_id;
2442                 if (xtty)
2443                     xpid = child_id;
2444             }
2445             else
2446                 (void) pidcheck (pidXwait (child_id, NULLCP));
2447
2448             if (fd != NOTOK)
2449                 (void) (*ct -> c_ceclosefnx) (ct);
2450             return (alternate ? DONE : OK);
2451     }
2452 }
2453
2454 /* \f */
2455
2456 static int  store_content (ct, append)
2457 register CT     ct;
2458 char   *append;
2459 {
2460     int     appending = append && *append;
2461     long    last,
2462             pos;
2463     register char  *bp,
2464                    *cp;
2465     char   *file,
2466             buffer[BUFSIZ];
2467     register CI ci = &ct -> c_ctinfo;
2468     FILE       *fp;
2469
2470     if (appending) {
2471         (void) strcpy (buffer, append);
2472         goto got_filename;
2473     }
2474
2475     if ((cp = ct -> c_storeproc) == NULL || *cp == 0) {
2476         (void) sprintf (buffer, "%s-store-%s/%s", invo_name, ci -> ci_type,
2477                         ci -> ci_subtype);
2478         if ((cp = m_find (buffer)) == NULL || *cp == 0) {
2479             (void) sprintf (buffer, "%s-store-%s", invo_name, ci -> ci_type);
2480             if ((cp = m_find (buffer)) == NULL || *cp == 0)
2481                 cp = ct -> c_type == CT_MESSAGE ? "+" : "%m%P.%s";
2482         }
2483     }
2484
2485     switch (*cp) {
2486         case '+':
2487         case '@@':
2488             {
2489                 char   *folder = cp[1] ? path (cp + 1, *cp == '+' ? TFOLDER 
2490                                                                   : TSUBCWF)
2491                                        : m_getfolder ();
2492                 struct msgs *mp = NULL;
2493                 struct stat st;
2494
2495                 if (stat (bp = m_mailpath (folder), &st) == NOTOK) {
2496                     int     answer;
2497                     char   *ep;
2498
2499                     if (errno != ENOENT) {
2500                         advise (bp, "error on folder");
2501                         goto losing_folder;
2502                     }
2503
2504                     ep = concat ("Create folder \"", bp, "\"? ", NULLCP);
2505                     answer = getanswer (ep);
2506                     free (ep);
2507
2508                     if (!answer)
2509                         goto losing_folder;
2510                     if (!makedir (bp)) {
2511                         advise (NULLCP, "unable to create folder %s", bp);
2512                         goto losing_folder;
2513                     }
2514                 }
2515
2516                 if (mp = m_gmsg (folder))
2517                     (void) sprintf (buffer, "%s/%d", mp -> foldpath,
2518                                    mp -> hghmsg + 1);
2519                 else
2520                     advise (NULLCP, "unable to read folder %s", folder);
2521 losing_folder: ;
2522                 if (cp[1])
2523                     free (folder);
2524                 if (mp)
2525                     m_fmsg (mp);
2526                 else
2527                     return NOTOK;
2528             }
2529             goto got_filename;
2530
2531         case '/':
2532         case '|':
2533         case '!':
2534             bp = buffer;
2535             buffer[0] = '\0';
2536             break;
2537
2538         default:
2539             bp = autosw ? cwd : dir;
2540             (void) sprintf (buffer, "%s/", bp[1] ? bp : "");
2541             bp = buffer + strlen (buffer);
2542             break;
2543     }
2544     for (; *cp; cp++)
2545         if (*cp == '%') {
2546             switch (*++cp) {
2547                 case 'a':       /* additional arguments */
2548                     if (buffer[0] != '|' && buffer[0] != '!') {
2549                         *bp++ = *--cp;
2550                         *bp = '\0';
2551                         continue;
2552                     }
2553                     else {
2554                         register char **ap,
2555                                       **ep;
2556                         char   *s = "";
2557
2558                         for (ap = ci -> ci_attrs, ep = ci -> ci_values;
2559                                  *ap;
2560                                  ap++, ep++) {
2561                             (void) sprintf (bp, "%s%s=\"%s\"", s, *ap, *ep);
2562                             bp += strlen (bp);
2563                             s = " ";
2564                         }
2565                     }
2566                     break;
2567
2568                 case 'm':       /* message */
2569                     (void) sprintf (bp, "%s", r1bindex (ct -> c_file, '/'));
2570                     break;
2571
2572                 case 'P':       /* .part */
2573                     if (ct -> c_partno)
2574                         (void) sprintf (bp, ".%s", ct -> c_partno);
2575                     break;
2576
2577                 case 'p':       /* part */
2578                     if (ct -> c_partno)
2579                         (void) strcpy (bp, ct -> c_partno);
2580                     break;
2581
2582                 case 't':       /* type */
2583                     (void) strcpy (bp, ci -> ci_type);
2584                     break;
2585
2586                 case 's':       /* subtype */
2587                     (void) strcpy (bp, ci -> ci_subtype);
2588                     break;
2589
2590                 case '%':
2591                     goto raw;
2592
2593                 default:
2594                     *bp++ = *--cp;
2595                     *bp = '\0';
2596                     continue;
2597             }
2598             bp += strlen (bp);
2599         }
2600         else {
2601 raw: ;
2602             *bp++ = *cp;
2603             *bp = '\0';
2604         }
2605     if (buffer[0] == '|' || buffer[0] == '!')
2606         return show_content_aux (ct, 1, 0, buffer + 1, autosw ? cwd : dir);
2607 got_filename: ;
2608
2609     ct -> c_storage = add (buffer, NULLCP);
2610     (void) fflush (stdout);
2611     fprintf (stderr, "storing message %s", ct -> c_file);
2612     if (ct -> c_partno)
2613         fprintf (stderr, " part %s", ct -> c_partno);
2614     fprintf (stderr, " as file %s\n",
2615              strncmp (ct -> c_storage, cwd, cwdlen)
2616                     || ct -> c_storage[cwdlen] != '/'
2617                  ? ct -> c_storage : ct -> c_storage + cwdlen + 1);
2618     if (index (ct -> c_storage, '/')
2619             && make_intermediates (ct -> c_storage) == NOTOK)
2620         return NOTOK;
2621
2622     if (ct -> c_encoding != CE_7BIT) {
2623         int     cc,
2624                 fd;
2625
2626         if (!ct -> c_ceopenfnx) {
2627             advise (NULLCP, "don't know how to decode part %s of message %s",
2628                     ct -> c_partno, ct -> c_file);
2629             return NOTOK;
2630         }
2631
2632         file = appending || !strcmp (ct -> c_storage, "-") ? NULLCP
2633                                                            : ct -> c_storage;
2634         if ((fd = (*ct -> c_ceopenfnx) (ct, &file)) == NOTOK)
2635             return NOTOK;
2636         if (strcmp (file, ct -> c_storage) == 0) {
2637             (void) (*ct -> c_ceclosefnx) (ct);
2638             return OK;
2639         }
2640
2641         if (!strcmp (ct -> c_storage, "-")) {
2642             int     gd;
2643
2644             if ((gd = dup (fileno (stdout))) == NOTOK) {
2645                 advise ("stdout", "unable to dup");
2646 losing: ;
2647                 (void) (*ct -> c_ceclosefnx) (ct);
2648                 return NOTOK;
2649             }
2650             if ((fp = fdopen (gd, appending ? "a" : "w")) == NULL) {
2651                 advise ("stdout", "unable to fdopen (%d, \"%s\") from", gd,
2652                         appending ? "a" : "w");
2653                 (void) close (gd);
2654                 goto losing;
2655             }
2656         }
2657         else
2658             if ((fp = fopen (ct -> c_storage, appending ? "a" : "w"))
2659                     == NULL) {
2660                 advise (ct -> c_storage, "unable to fopen for %s",
2661                         appending ? "appending" : "writing");
2662                 goto losing;
2663             }
2664
2665         if (append && !*append)
2666             (void) copy_some_headers (fp, ct);
2667
2668         for (;;) {
2669             switch (cc = read (fd, buffer, sizeof buffer)) {
2670                 case NOTOK:
2671                     advise (file, "error reading content from");
2672                     break;
2673
2674                 case OK:
2675                     break;
2676
2677                 default:
2678                     (void) fwrite (buffer, sizeof *buffer, cc, fp);
2679                     continue;
2680             }
2681             break;
2682         }
2683
2684         (void) (*ct -> c_ceclosefnx) (ct);
2685
2686         if (cc != NOTOK && fflush (fp))
2687             advise (ct -> c_storage, "error writing to");
2688
2689         (void) fclose (fp);
2690
2691         return (cc != NOTOK ? OK : NOTOK);
2692     }
2693
2694     if (!ct -> c_fp && (ct -> c_fp = fopen (ct -> c_file, "r")) == NULL) {
2695         advise (ct -> c_file, "unable to open for reading");
2696         return NOTOK;
2697     }
2698
2699     (void) fseek (ct -> c_fp, pos = ct -> c_begin, 0);
2700     last = ct -> c_end;
2701
2702     if (!strcmp (ct -> c_storage, "-")) {
2703         int     gd;
2704
2705         if ((gd = dup (fileno (stdout))) == NOTOK) {
2706             advise ("stdout", "unable to dup");
2707             return NOTOK;
2708         }
2709         if ((fp = fdopen (gd, appending ? "a" : "w")) == NULL) {
2710             advise ("stdout", "unable to fdopen (%d, \"%s\") from", gd,
2711                     appending ? "a" : "w");
2712             (void) close (gd);
2713             return NOTOK;
2714         }
2715     }
2716     else
2717         if ((fp = fopen (ct -> c_storage, appending ? "a" : "w")) == NULL) {
2718             advise (ct -> c_storage, "unable to fopen for %s",
2719                     appending ? "appending" : "writing");
2720             return NOTOK;
2721         }
2722
2723     if (append && !*append) {
2724         (void) copy_some_headers (fp, ct);
2725         appending = 1;
2726     }
2727     else
2728         appending = 0;
2729
2730     while (fgets (buffer, sizeof buffer - 1, ct -> c_fp)) {
2731         if ((pos += strlen (buffer)) > last) {
2732             int     diff = strlen (buffer) - (pos - last);
2733
2734             if (diff >= 0)
2735                 buffer[diff] = '\0';
2736         }
2737
2738         if (appending)
2739             switch (buffer[0]) {
2740                 case ' ':
2741                 case '\t':
2742                     if (appending < 0)
2743                         buffer[0] = 0;
2744                     break;
2745
2746                 case '\n':
2747                     appending = 0;
2748                     break;
2749
2750                 default:
2751                     if (!uprf (buffer, XXX_FIELD_PRF)
2752                             && !uprf (buffer, "Encrypted:")
2753                             && !uprf (buffer, "Message-ID:")) {
2754                         appending = -1;
2755                         buffer[0] = 0;
2756                         break;
2757                     }
2758                     appending = 1;
2759                     break;
2760             }
2761
2762         (void) fputs (buffer, fp);
2763         if (pos >= last)
2764             break;
2765     }
2766
2767     if (fflush (fp))
2768         advise (ct -> c_storage, "error writing to");
2769
2770     (void) fclose (fp);
2771
2772     (void) fclose (ct -> c_fp), ct -> c_fp = NULL;
2773
2774     return OK;
2775 }
2776
2777
2778 static int  copy_some_headers (out, ct)
2779 FILE   *out;
2780 register CT     ct;
2781 {
2782     int     state;
2783     char    buf[BUFSIZ],
2784             name[NAMESZ];
2785     FILE   *in;
2786
2787     if ((in = fopen (ct -> c_file, "r")) == NULL) {
2788         advise (ct -> c_file, "unable to open for reading");
2789         return NOTOK;
2790     }
2791
2792     for (state = FLD;;) {
2793         switch (state = m_getfld (state, name, buf, sizeof buf, in)) {
2794             case FLD:
2795             case FLDPLUS:
2796             case FLDEOF:
2797                 if (uprf (name, XXX_FIELD_PRF)
2798                         || uleq (name, "Encrypted")
2799                         || uleq (name, "Message-ID")) {
2800                     while (state == FLDPLUS)
2801                         state = m_getfld (state, name, buf, sizeof buf, in);
2802                     continue;
2803                 }
2804
2805                 fprintf (out, "%s:%s", name, buf);
2806                 while (state == FLDPLUS) {
2807                     state = m_getfld (state, name, buf, sizeof buf, in);
2808                     (void) fputs (buf, out);
2809                 }
2810                 if (state != FLDEOF)
2811                     continue;
2812                 /* else fall... */
2813            case BODY:
2814            case BODYEOF:
2815            case FILEEOF:
2816                 break;
2817
2818            case LENERR:
2819            case FMTERR:
2820            default:
2821                 break;
2822         }
2823
2824         break;
2825     }
2826
2827     (void) fclose (in);
2828
2829     return OK;
2830 }
2831
2832
2833 static int make_intermediates (file)
2834 char   *file;
2835 {
2836     register char *cp;
2837
2838     for (cp = file + 1; cp = index (cp, '/'); cp++) {
2839         struct stat st;
2840
2841         *cp = NULL;
2842
2843         if (stat (file, &st) == NOTOK) {
2844             int     answer;
2845             char   *ep;
2846
2847             if (errno != ENOENT) {
2848                 advise (file, "error on directory");
2849 losing_directory: ;
2850                 *cp = '/';
2851                 return NOTOK;
2852             }
2853
2854             ep = concat ("Create directory \"", file, "\"? ", NULLCP);
2855             answer = getanswer (ep);
2856             free (ep);
2857
2858             if (!answer)
2859                 goto losing_directory;
2860             if (!makedir (file)) {
2861                 advise (NULLCP, "unable to create directory %s", file);
2862                 goto losing_directory;
2863             }
2864         }
2865
2866         *cp = '/';
2867     }
2868
2869     return OK;
2870 }
2871
2872 /* \f */
2873
2874 static void  free_ctinfo (ct)
2875 register CT     ct;
2876 {
2877     register char **ap;
2878     register CI ci = &ct -> c_ctinfo;
2879
2880     if (ci -> ci_type)
2881         free (ci -> ci_type);
2882     ci -> ci_type = NULL;
2883     if (ci -> ci_subtype)
2884         free (ci -> ci_subtype);
2885     ci -> ci_subtype = NULL;
2886     for (ap = ci -> ci_attrs; *ap; ap++)
2887         free (*ap), *ap = NULL;
2888     if (ci -> ci_comment)
2889         free (ci -> ci_comment);
2890     ci -> ci_comment = NULL;
2891     if (ci -> ci_magic)
2892         free (ci -> ci_magic);
2893     ci -> ci_magic = NULL;
2894 }
2895
2896
2897 static void  free_content (ct)
2898 register CT     ct;
2899 {
2900     if (!ct)
2901         return;
2902
2903     if (ct -> c_partno)
2904         free (ct -> c_partno);
2905     ct -> c_partno = NULL;
2906
2907     if (ct -> c_vrsn)
2908         free (ct -> c_vrsn);
2909     ct -> c_vrsn = NULL;
2910
2911     if (ct -> c_ctline)
2912         free (ct -> c_ctline);
2913     ct -> c_ctline = NULL;
2914
2915     free_ctinfo (ct);
2916
2917     if (ct -> c_ctfreefnx)
2918         (void) (*ct -> c_ctfreefnx) (ct);
2919     ct -> c_ctfreefnx = NULL;
2920
2921     if (ct -> c_showproc)
2922         free (ct -> c_showproc);
2923     ct -> c_showproc = NULL;
2924     if (ct -> c_termproc)
2925         free (ct -> c_termproc);
2926     ct -> c_termproc = NULL;
2927     if (ct -> c_storeproc)
2928         free (ct -> c_storeproc);
2929     ct -> c_storeproc = NULL;
2930
2931     if (ct -> c_celine)
2932         free (ct -> c_celine);
2933     ct -> c_celine = NULL;
2934     if (ct -> c_cefreefnx)
2935         (void) (*ct -> c_cefreefnx) (ct, 1);
2936     ct -> c_cefreefnx = NULL;
2937
2938     if (ct -> c_id)
2939         free (ct -> c_id);
2940     ct -> c_id = NULL;
2941     if (ct -> c_descr)
2942         free (ct -> c_descr);
2943     ct -> c_descr = NULL;
2944
2945     if (ct -> c_file) {
2946         if (ct -> c_unlink)
2947             (void) unlink (ct -> c_file);
2948         free (ct -> c_file);
2949         ct -> c_file = NULL;
2950     }
2951     if (ct -> c_fp)
2952         (void) fclose (ct -> c_fp);
2953     ct -> c_fp = NULL;
2954
2955     if (ct -> c_storage)
2956         (void) free (ct -> c_storage);
2957     ct -> c_storage = NULL;
2958
2959     free ((char *) ct);
2960 }
2961
2962 /* \f */
2963
2964 static int  part_ok (ct, sP)
2965 register CT     ct;
2966 int     sP;
2967 {
2968     register char **ap;
2969
2970     if ((ct -> c_type == CT_MULTIPART && (sP || ct -> c_subtype))
2971             || npart == 0)
2972         return 1;
2973
2974     for (ap = parts; *ap; ap++)
2975         if (strcmp (*ap, ct -> c_partno) == 0)
2976             return 1;
2977
2978     return 0;
2979 }
2980
2981
2982
2983 static int  type_ok (ct, sP)
2984 register CT     ct;
2985 int     sP;
2986 {
2987     register char **ap;
2988     char    buffer[BUFSIZ];
2989     register CI     ci = &ct -> c_ctinfo;
2990
2991     if ((ct -> c_type == CT_MULTIPART && (sP || ct -> c_subtype))
2992             || ntype == 0)
2993         return 1;
2994
2995     (void) sprintf (buffer, "%s/%s", ci -> ci_type, ci -> ci_subtype);
2996     for (ap = types; *ap; ap++)
2997         if (uleq (*ap, ci -> ci_type) || uleq (*ap, buffer))
2998             return 1;
2999
3000     return 0;
3001 }
3002
3003 /* \f   CONTENTS */
3004
3005 struct k2v {
3006     char   *kv_key;
3007     int     kv_value;
3008 };
3009
3010
3011 static int  InitGeneric (ct)
3012 register CT     ct;
3013 {
3014     register char **ap,
3015                   **ep;
3016     register CI ci = &ct -> c_ctinfo;
3017
3018     for (ap = ci -> ci_attrs, ep = ci -> ci_values; *ap; ap++, ep++)
3019         if (autosw && !ct -> c_storeproc && uleq (*ap, "name")) {
3020             register char   *cp;
3021
3022             if (*(cp = *ep) != '/'
3023                     && *cp != '.'
3024                     && *cp != '|'
3025                     && *cp != '!'
3026                     && !index (cp, '%'))
3027                 ct -> c_storeproc = add (cp, NULLCP);
3028         }
3029
3030     return OK;
3031 }
3032
3033 /* \f   TEXT */
3034
3035 #define TEXT_UNKNOWN    0x00
3036 #define TEXT_PLAIN      0x01
3037 #define TEXT_RICHTEXT   0x02
3038
3039 struct text {
3040     int     tx_charset;
3041 #define CHARSET_UNKNOWN 0x00
3042 #define CHARSET_USASCII 0x01
3043 #define CHARSET_LATIN   0x02
3044 };
3045
3046 static struct k2v       Charset[] = {
3047     "us-ascii",     CHARSET_USASCII,
3048     "iso-8859-1",   CHARSET_LATIN,
3049
3050     NULL,           CHARSET_UNKNOWN             /* this one must be last! */
3051 };
3052
3053 static int  free_text (ct)
3054 register CT     ct;
3055 {
3056     register struct text *t = (struct text *) ct -> c_ctparams;
3057
3058     if (!t)
3059         return;
3060
3061     free ((char *) t);
3062     ct -> c_ctparams = NULL;
3063 }
3064
3065
3066 static struct k2v       SubText[] = {
3067     "plain",        TEXT_PLAIN,
3068     "richtext",     TEXT_RICHTEXT,
3069
3070     NULL,           TEXT_UNKNOWN                /* this one must be last! */
3071 };
3072
3073 static int  InitText (ct)
3074 register CT     ct;
3075 {
3076     char   buffer[BUFSIZ];
3077     register char **ap,
3078                   **ep;
3079     register struct k2v *kv;
3080     register CI ci = &ct -> c_ctinfo;
3081
3082     if (!*ci -> ci_subtype)     /* XXX: attmail bogosity! */
3083         ci -> ci_subtype = add ("plain", ci -> ci_subtype);
3084     for (kv = SubText; kv -> kv_key; kv++)
3085         if (uleq (ci -> ci_subtype, kv -> kv_key))
3086             break;
3087     if ((ct -> c_subtype = kv -> kv_value) == TEXT_PLAIN) {
3088         (void) sprintf (buffer, "%%p%s '%%F'",
3089                         progsw ? progsw
3090                                : moreproc && *moreproc ? moreproc : "more");
3091         ct -> c_showproc = add (buffer, NULLCP);
3092     }
3093
3094     for (ap = ci -> ci_attrs, ep = ci -> ci_values; *ap; ap++, ep++)
3095         if (!ct -> c_ctparams && uleq (*ap, "charset")) {
3096             char   *cp;
3097             register struct text *t;
3098
3099             if ((t = (struct text *) calloc (1, sizeof *t)) == NULL)
3100                 adios (NULLCP, "out of memory");
3101             ct -> c_ctparams = (caddr_t) t;
3102             ct -> c_ctfreefnx = free_text;
3103
3104             for (kv = Charset; kv -> kv_key; kv++)
3105                 if (uleq (*ep, kv -> kv_key)) {
3106                     (void) sprintf (buffer, "%s-charset-%s", invo_name,
3107                                     kv -> kv_key);
3108                     break;
3109                 }
3110             t -> tx_charset = kv -> kv_value;
3111             if (!kv -> kv_key)
3112                 (void) sprintf (buffer, "%s-charset-%s", invo_name, *ep);
3113             if ((!mm_charset || !uleq (mm_charset, *ep))
3114                     && (cp = m_find (buffer)))
3115                 ct -> c_termproc = getcpy (cp);
3116         }
3117         else
3118             if (autosw && !ct -> c_storeproc && uleq (*ap, "name")) {
3119                 register char   *cp;
3120
3121                 if (*(cp = *ep) != '/'
3122                         && *cp != '.'
3123                         && *cp != '|'
3124                         && *cp != '!'
3125                         && !index (cp, '%'))
3126                     ct -> c_storeproc = add (cp, NULLCP);
3127             }
3128
3129     return OK;
3130 }
3131
3132 /* \f   MULTIPART */
3133
3134 #define MULTI_UNKNOWN   0x00
3135 #define MULTI_MIXED     0x01
3136 #define MULTI_ALTERNATE 0x02
3137 #define MULTI_DIGEST    0x03
3138 #define MULTI_PARALLEL  0x04
3139
3140
3141 struct multipart {
3142     char   *mp_start;
3143     char   *mp_stop;
3144
3145     struct part {
3146         CT  mp_part;
3147
3148         struct part *mp_next;
3149     }      *mp_parts;
3150 };
3151
3152
3153 static int  list_multi (ct, toplevel)
3154 register CT     ct;
3155 int     toplevel;
3156 {
3157     register struct multipart *m = (struct multipart *) ct -> c_ctparams;
3158     register struct part *part;
3159
3160     (void) list_content (ct, toplevel);
3161
3162     for (part = m -> mp_parts; part; part = part -> mp_next) {
3163         register CT  p = part -> mp_part;
3164
3165         if (part_ok (p, 1) && type_ok (p, 1) && p -> c_ctlistfnx)
3166             (void) (*p -> c_ctlistfnx) (p, 0);
3167     }
3168
3169     return OK;
3170 }
3171
3172
3173 static int  show_multi (ct, serial, alternate)
3174 register CT     ct;
3175 int     serial,
3176         alternate;
3177 {
3178     int     alternating,
3179             nowalternate,
3180             nowserial,
3181             result;
3182     register struct multipart *m = (struct multipart *) ct -> c_ctparams;
3183     register struct part *part;
3184     register CT  p;
3185     TYPESIG (*hstat) (), (*istat) (), (*qstat) (), (*tstat) ();
3186
3187     alternating = 0;
3188     nowalternate = alternate;
3189     switch (ct -> c_subtype) {
3190         case MULTI_PARALLEL:
3191             if (!(nowserial = serialsw)) {
3192 set_signals: ;
3193                 hstat = signal (SIGHUP, SIG_IGN);
3194                 istat = signal (SIGINT, SIG_IGN);
3195                 qstat = signal (SIGQUIT, SIG_IGN);
3196                 tstat = signal (SIGTERM, SIG_IGN);
3197             }
3198             break;
3199
3200         case MULTI_ALTERNATE:
3201             nowalternate = alternating = 1;
3202             /* and fall... */
3203         default:
3204             if (!(nowserial = serial))
3205                 goto set_signals;
3206             break;
3207     }
3208
3209 /* alternate -> we're inside an alternative
3210    alternating -> we are an alternative
3211  */
3212
3213     result = alternate ? NOTOK : OK;
3214     for (part = m -> mp_parts; part; part = part -> mp_next) {
3215         p = part -> mp_part;
3216
3217         if (part_ok (p, 0) && type_ok (p, 0) && p -> c_ctshowfnx) {
3218             int     inneresult;
3219
3220             switch (inneresult = (*p -> c_ctshowfnx) (p, nowserial,
3221                                                       nowalternate)) {
3222                 case NOTOK:
3223                     if (alternate && !alternating) {
3224                         result = NOTOK;
3225                         goto out;
3226                     }
3227                     continue;
3228
3229                 case OK:
3230                 case DONE:
3231                     if (alternating) {
3232                         result = DONE;
3233                         break;
3234                     }
3235                     if (alternate) {
3236                         alternate = nowalternate = 0;
3237                         if (result == NOTOK)
3238                             result = inneresult;
3239                     }
3240                     continue;
3241             }
3242             break;
3243         }
3244     }
3245     if (alternating && !part) {
3246         if (!alternate)
3247             content_error (NULLCP, ct,
3248                            "don't know how to display any of the contents");
3249
3250         result = NOTOK;
3251         goto out;
3252     }
3253
3254     if (serial && !nowserial) {
3255         int     pid,
3256                 kids;
3257 #if defined(BSD42) && !defined(WAITINT)
3258         union wait status;
3259 #else
3260         int     status;
3261 #endif
3262
3263         kids = 0;
3264         for (part = m -> mp_parts; part; part = part -> mp_next) {
3265             p = part -> mp_part;
3266
3267             if (p -> c_pid > OK)
3268                 if (kill (p -> c_pid, 0) == NOTOK)
3269                     p -> c_pid = 0;
3270                 else
3271                     kids++;
3272         }
3273
3274         while (kids > 0 && (pid = wait (&status)) != NOTOK) {
3275 #if defined(BSD42) && !defined(WAITINT)
3276             (void) pidcheck (status.w_status);
3277 #else
3278             (void) pidcheck (status);
3279 #endif
3280
3281             for (part = m -> mp_parts; part; part = part -> mp_next) {
3282                 p = part -> mp_part;
3283
3284                 if (xpid == pid)
3285                     xpid = 0;
3286                 if (p -> c_pid == pid) {
3287                     p -> c_pid = 0;
3288                     kids--;
3289                     break;
3290                 }
3291             }
3292         }
3293     }
3294
3295 out: ;
3296     if (!nowserial) {
3297         (void) signal (SIGHUP, hstat);
3298         (void) signal (SIGINT, istat);
3299         (void) signal (SIGQUIT, qstat);
3300         (void) signal (SIGTERM, tstat);
3301     }
3302
3303     return result;
3304 }
3305
3306
3307 static int  show_unknown_multi (ct, serial, alternate)
3308 register CT     ct;
3309 int     serial,
3310         alternate;
3311 {
3312     int     xlist,
3313             xpause,
3314             xtty;
3315     register char  *bp,
3316                    *cp;
3317     char    buffer[BUFSIZ];
3318     register struct multipart *m = (struct multipart *) ct -> c_ctparams;
3319     register struct part *part;
3320     register CI ci = &ct -> c_ctinfo;
3321     register CT  p;
3322
3323     (void) sprintf (buffer, "%s-show-%s/%s", invo_name, ci -> ci_type,
3324                     ci -> ci_subtype);
3325     if ((cp = m_find (buffer)) == NULL || *cp == 0) {
3326         (void) sprintf (buffer, "%s-show-%s", invo_name, ci -> ci_type);
3327         if (((cp = m_find (buffer)) == NULL || *cp == 0)
3328                 && (cp = ct -> c_showproc) == NULL) {
3329             if (!alternate)
3330                 content_error (NULLCP, ct,
3331                                "don't know how to display content");
3332
3333             return NOTOK;
3334         }
3335     }
3336
3337     for (part = m -> mp_parts; part; part = part -> mp_next) {
3338         p = part -> mp_part;
3339
3340         if (!p -> c_ceopenfnx) {
3341             if (!alternate)
3342                 content_error (NULLCP, p, "don't know how to decode content");
3343
3344             return NOTOK;
3345         }
3346
3347         if (p -> c_storage == NULL) {
3348             if ((*p -> c_ceopenfnx) (p, &p -> c_storage) == NOTOK)
3349                 return NOTOK;
3350
3351             if (p -> c_showproc && strcmp (p -> c_showproc, "true") == 0)
3352                 return (alternate ? DONE : OK);
3353             (*p -> c_ceclosefnx) (p);
3354         }
3355     }
3356
3357     xlist = xpause = xtty = 0;
3358     buffer[0] = '\0';
3359     for (bp = buffer; *cp; cp++)
3360         if (*cp == '%') {
3361             switch (*++cp) {
3362                 case 'a':       /* additional arguments */
3363                     {
3364                         register char **ap,
3365                                       **ep;
3366                         char   *s = "";
3367
3368                         for (ap = ci -> ci_attrs, ep = ci -> ci_values;
3369                                  *ap;
3370                                  ap++, ep++) {
3371                             (void) sprintf (bp, "%s%s=\"%s\"", s, *ap, *ep);
3372                             bp += strlen (bp);
3373                             s = " ";
3374                         }
3375                     }
3376                     break;
3377
3378                 case 'd':       /* content description */
3379                     if (ct -> c_descr) {
3380                         char   *s;
3381
3382                         (void) strcpy (bp, s = trimcpy (ct -> c_descr));
3383                         free (s);
3384                     }
3385                     break;
3386
3387                 case 'e':       /* exclusive execution */
3388                     xtty = 1;
3389                     break;
3390
3391                 case 'F':       /* %e and %f */
3392                     xtty = 1;
3393                     /* and fall... */
3394                 case 'f':       /* filename(s) */
3395                     {
3396                         char   *s = "";
3397                         
3398                         for (part = m -> mp_parts;
3399                                  part;
3400                                  part = part -> mp_next) {
3401                             p = part -> mp_part;
3402
3403                             (void) sprintf (bp, "%s'%s'", s, p -> c_storage);
3404                             bp += strlen (bp);
3405                             s = " ";
3406                         }
3407                     }
3408                     break;
3409
3410                 case 'p':       /* pause prior to displaying content */
3411                     xpause = pausesw;
3412                     /* and fall... */
3413                 case 'l':       /* display listing prior to displaying
3414                                    content */
3415                     xlist = !nolist;
3416                     break;
3417
3418                 case 's':       /* subtype */
3419                     (void) strcpy (bp, ci -> ci_subtype);
3420                     break;
3421
3422                 case '%':
3423                     goto raw;
3424
3425                 default:
3426                     *bp++ = *--cp;
3427                     *bp = '\0';
3428                     continue;
3429             }
3430             bp += strlen (bp);
3431         }
3432         else {
3433 raw: ;
3434             *bp++ = *cp;
3435             *bp = '\0';
3436         }
3437     if (ct -> c_termproc) {
3438         char    term[BUFSIZ];
3439
3440         (void) strcpy (term, buffer);
3441         (void) sprintf (buffer, ct -> c_termproc, term);
3442     }
3443
3444     return show_content_aux2 (ct, serial, alternate, NULLCP, buffer,
3445                               NOTOK, xlist, xpause, 0, xtty);
3446 }
3447
3448
3449 /* ARGSUSED */
3450
3451 static int  store_multi (ct, unused)
3452 register CT     ct;
3453 char   *unused;
3454 {
3455     int     result;
3456     register struct multipart *m = (struct multipart *) ct -> c_ctparams;
3457     register struct part *part;
3458
3459     result = NOTOK;
3460     for (part = m -> mp_parts; part; part = part -> mp_next) {
3461         register CT  p = part -> mp_part;
3462
3463         if (part_ok (p, 1)
3464                 && type_ok (p, 1)
3465                 && p -> c_ctstorefnx
3466                 && (result = (*p -> c_ctstorefnx) (p, NULLCP)) == OK
3467                 && ct -> c_subtype == MULTI_ALTERNATE)
3468             break;
3469     }
3470
3471     return result;
3472 }
3473
3474
3475 static int  free_multi (ct)
3476 register CT     ct;
3477 {
3478     register struct multipart *m = (struct multipart *) ct -> c_ctparams;
3479     register struct part   *part,
3480                            *next;
3481
3482     if (!m)
3483         return;
3484
3485     if (m -> mp_start)
3486         free (m -> mp_start);
3487     if (m -> mp_stop)
3488         free (m -> mp_stop);
3489         
3490     for (part = m -> mp_parts; part; part = next) {
3491         next = part -> mp_next;
3492
3493         free_content (part -> mp_part);
3494
3495         free ((char *) part);
3496     }
3497     m -> mp_parts = NULL;
3498
3499     free ((char *) m);
3500     ct -> c_ctparams = NULL;
3501 }
3502
3503
3504 static struct k2v SubMultiPart[] = {
3505     "mixed",        MULTI_MIXED,
3506     "alternative",  MULTI_ALTERNATE,
3507     "digest",       MULTI_DIGEST,
3508     "parallel",     MULTI_PARALLEL,
3509
3510     NULL,           MULTI_UNKNOWN               /* this one must be last! */
3511 };
3512
3513 static int  InitMultiPart (ct)
3514 register CT     ct;
3515 {
3516     int     inout;
3517     long    last,
3518             pos;
3519     register char   *cp,
3520                     *dp,
3521                    **ap,
3522                    **ep;
3523     char   *bp,
3524             buffer[BUFSIZ];
3525     register struct multipart *m;
3526     register struct k2v *kv;
3527     register struct part  *part,
3528                          **next;
3529     register CI     ci = &ct -> c_ctinfo;
3530     register CT     p;
3531     FILE   *fp;
3532
3533     ct -> c_ctshowfnx = NULL;
3534     ct -> c_ctstorefnx = NULL;
3535
3536     if (ct -> c_encoding != CE_7BIT) {
3537         admonish (NULLCP,
3538                   "\"%s/%s\" type in message %s should be encoded in 7bit",
3539                   ci -> ci_type, ci -> ci_subtype, ct -> c_file);
3540         return NOTOK;
3541     }
3542
3543     for (kv = SubMultiPart; kv -> kv_key; kv++)
3544         if (uleq (ci -> ci_subtype, kv -> kv_key))
3545             break;
3546     ct -> c_subtype = kv -> kv_value;
3547
3548     for (ap = ci -> ci_attrs, ep = ci -> ci_values; *ap; ap++, ep++)
3549         if (uleq (*ap, "boundary")) {
3550             bp = *ep;
3551             break;
3552         }
3553     if (!*ap) {
3554         advise (NULLCP,
3555                 "a \"boundary\" parameter is mandatory for \"%s/%s\" type in message %s's %s: field",
3556                 ci -> ci_type, ci -> ci_subtype, ct -> c_file, TYPE_FIELD);
3557         return NOTOK;
3558     }
3559     
3560     if ((m = (struct multipart *) calloc (1, sizeof *m)) == NULL)
3561         adios (NULLCP, "out of memory");
3562     ct -> c_ctparams = (caddr_t) m;
3563     ct -> c_ctlistfnx = list_multi;
3564     ct -> c_ctshowfnx = ct -> c_subtype != MULTI_UNKNOWN ? show_multi
3565                                                          : show_unknown_multi;
3566     ct -> c_ctstorefnx = store_multi;
3567     ct -> c_ctfreefnx = free_multi;
3568     
3569     for (cp = bp; isspace (*cp); cp++)
3570         continue;
3571     if (!*cp) {
3572         advise (NULLCP, "invalid \"boundary\" parameter for \"%s/%s\" type in message %s's %s: field",
3573                 ci -> ci_type, ci -> ci_subtype, ct -> c_file, TYPE_FIELD);
3574         return NOTOK;
3575     }
3576     for (cp = bp, dp = cp + strlen (cp) - 1; dp > cp; dp--)
3577         if (!isspace (*dp))
3578             break;
3579     *++dp = '\0';
3580     m -> mp_start = concat (bp, "\n", NULLCP);
3581     m -> mp_stop = concat (bp, "--\n", NULLCP);
3582
3583     if (!ct -> c_fp && (ct -> c_fp = fopen (ct -> c_file, "r")) == NULL) {
3584         advise (ct -> c_file, "unable to open for reading");
3585         return NOTOK;
3586     }
3587
3588     (void) fseek (fp = ct -> c_fp, pos = ct -> c_begin, 0);
3589     last = ct -> c_end;
3590
3591     next = &m -> mp_parts, part = NULL, inout = 1;
3592     while (fgets (buffer, sizeof buffer - 1, fp)) {
3593         if (pos > last)
3594             break;
3595
3596         pos += strlen (buffer);
3597         
3598         if (buffer[0] != '-' || buffer[1] != '-')
3599             continue;
3600
3601         if (inout) {
3602             if (strcmp (buffer + 2, m -> mp_start))
3603                 continue;
3604
3605 next_part: ;
3606             if ((part = (struct part *) calloc (1, sizeof *part)) == NULL)
3607                 adios (NULLCP, "out of memory");
3608             *next = part, next = &part -> mp_next;
3609
3610             if ((p = get_content (fp, ct -> c_file,
3611                                   rfc934sw && ct -> c_subtype == MULTI_DIGEST
3612                                                     ? -1 : 0)) == NULLCT) {
3613                 (void) fclose (ct -> c_fp), ct -> c_fp = NULL;
3614                 return NOTOK;
3615             }
3616             p -> c_fp = NULL;
3617
3618             part -> mp_part = p;
3619             (void) fseek (fp, pos = p -> c_begin, 0);
3620             inout = 0;
3621         }
3622         else
3623             if (strcmp (buffer + 2, m -> mp_start) == 0) {
3624                 inout = 1;
3625
3626 end_part: ;
3627                 p = part -> mp_part;
3628                 p -> c_end = ftell (fp) - (strlen (buffer) + 1);
3629                 if (p -> c_end < p -> c_begin)
3630                     p -> c_begin = p -> c_end;
3631                 if (inout)
3632                     goto next_part;
3633                 goto last_part;
3634             }
3635             else
3636                 if (strcmp (buffer + 2, m -> mp_stop) == 0)
3637                     goto end_part;
3638     }
3639     advise (NULLCP, "bogus multipart content in message %s", ct -> c_file);
3640     if (!inout && part) {
3641         p = part -> mp_part;
3642         p -> c_end = ct -> c_end;
3643
3644         if (p -> c_begin >= p -> c_end) {
3645             for (next = &m -> mp_parts;
3646                      *next != part;
3647                      next = &((*next) -> mp_next))
3648                 continue;
3649             *next = NULL;
3650             free_content (p);
3651             free ((char *) part);
3652         }
3653     }
3654
3655 last_part: ;
3656     if (ct -> c_subtype == MULTI_ALTERNATE
3657             && m -> mp_parts
3658             && m -> mp_parts -> mp_next) {
3659         register int    i;
3660         register struct part **base,
3661                              **bmp;
3662
3663         i = 0;
3664         for (part = m -> mp_parts; part; part = part -> mp_next)
3665             i++;
3666         if ((base = (struct part **) calloc ((unsigned) (i + 1), sizeof *base))
3667                 == NULL)
3668             adios (NULLCP, "out of memory");
3669         bmp = base;
3670         for (part = m -> mp_parts; part; part = part -> mp_next)
3671             *bmp++ = part;
3672         *bmp = NULL;
3673
3674         next = &m -> mp_parts;
3675         for (bmp--; bmp >= base; bmp--) {
3676             part = *bmp;
3677             *next = part, next = &part -> mp_next;
3678         }
3679         *next = NULL;
3680
3681         free ((char *) base);
3682     }
3683
3684     {
3685         int     partnum;
3686         register char *pp;
3687         char    partnam[BUFSIZ];
3688
3689         if (ct -> c_partno) {
3690             (void) sprintf (partnam, "%s.", ct -> c_partno);
3691             pp = partnam + strlen (partnam);
3692         }
3693         else
3694             pp = partnam;
3695
3696         for (part = m -> mp_parts, partnum = 1;
3697                  part;
3698                  part = part -> mp_next, partnum++) {
3699             p = part -> mp_part;
3700
3701             (void) sprintf (pp, "%d", partnum);
3702             p -> c_partno = add (partnam, NULLCP);
3703
3704             if (p -> c_ctinitfnx && (*p -> c_ctinitfnx) (p) == NOTOK) {
3705                 (void) fclose (ct -> c_fp), ct -> c_fp = NULL;
3706                 return NOTOK;
3707             }
3708         }
3709     }
3710
3711     (void) fclose (ct -> c_fp), ct -> c_fp = NULL;
3712
3713     return OK;
3714 }
3715
3716 /* \f   MESSAGE */
3717
3718 #define MESSAGE_UNKNOWN  0x00
3719 #define MESSAGE_RFC822   0x01
3720 #define MESSAGE_PARTIAL  0x02
3721 #define MESSAGE_EXTERNAL 0x03
3722
3723
3724 struct partial {
3725     char   *pm_partid;
3726
3727     int     pm_partno;
3728     int     pm_maxno;
3729
3730     int     pm_marked;
3731     int     pm_stored;
3732 };
3733
3734
3735 static int  list_partial (ct, toplevel)
3736 register CT     ct;
3737 int     toplevel;
3738 {
3739     register struct partial *p = (struct partial *) ct -> c_ctparams;
3740
3741     (void) list_content (ct, toplevel);
3742     if (verbosw) {
3743         printf ("\t     [message %s, part %d", p -> pm_partid, p -> pm_partno);
3744         if (p -> pm_maxno)
3745             printf (" of %d", p -> pm_maxno);
3746         printf ("]\n");
3747     }
3748
3749     return OK;
3750 }
3751
3752
3753 static int  ct_compar (a, b)
3754 CT   *a,
3755      *b;
3756 {
3757     register struct  partial *am = (struct partial *) ((*a) -> c_ctparams);
3758     register struct  partial *bm = (struct partial *) ((*b) -> c_ctparams);
3759
3760     return (am -> pm_marked - bm -> pm_marked);
3761 }
3762
3763
3764 /* ARGSUSED */
3765
3766 static int  store_partial (ct, unused)
3767 register CT     ct;
3768 char   *unused;
3769 {
3770     int     cur,
3771             hi,
3772             i;
3773     register CT     p,
3774                    *ctp,
3775                    *ctq;
3776     CT     *base;
3777     struct partial *qm = (struct partial *) ct -> c_ctparams;
3778
3779     if (qm -> pm_stored)
3780         return OK;
3781
3782     hi = i = 0;
3783     for (ctp = cts; p = *ctp; ctp++)
3784         if (p -> c_type == CT_MESSAGE && p -> c_subtype == ct -> c_subtype) {
3785             register struct partial *pm = (struct partial *) p -> c_ctparams;
3786
3787             if (!pm -> pm_stored
3788                     && strcmp (qm -> pm_partid, pm -> pm_partid) == 0) {
3789                 pm -> pm_marked = pm -> pm_partno;
3790                 if (pm -> pm_maxno)
3791                     hi = pm -> pm_maxno;
3792                 pm -> pm_stored = 1;
3793                 i++;
3794             }
3795             else
3796                 pm -> pm_marked = 0;
3797         }
3798     if (hi == 0) {
3799         advise (NULLCP, "missing (at least) last part of multipart message");
3800         return NOTOK;
3801     }
3802
3803     if ((base = (CT *) calloc ((unsigned) (i + 1), sizeof *base)) == NULL)
3804         adios (NULLCP, "out of memory");
3805
3806     ctq = base;
3807     for (ctp = cts; p = *ctp; ctp++)
3808         if (p -> c_type == CT_MESSAGE && p -> c_subtype == ct -> c_subtype) {
3809             register struct partial *pm = (struct partial *) p -> c_ctparams;
3810
3811             if (pm -> pm_marked)
3812                 *ctq++ = p;
3813         }
3814     *ctq = NULL;
3815
3816     if (i > 1)
3817         qsort ((char *) base, i, sizeof *base, ct_compar);
3818
3819     cur = 1;
3820     for (ctq = base; p = *ctq; ctq++) {
3821         register struct partial *pm = (struct partial *) p -> c_ctparams;
3822
3823         if (pm -> pm_marked != cur) {
3824             if (pm -> pm_marked == cur - 1) {
3825                 admonish (NULLCP,
3826                           "duplicate part %d of %d part multipart message",
3827                           pm -> pm_marked, hi);
3828                 continue;
3829             }
3830
3831 missing_part: ;
3832             advise (NULLCP,
3833                     "missing %spart %d of %d part multipart message",
3834                     cur != hi ? "(at least) " : "", cur, hi);
3835             goto losing;
3836         }
3837         else
3838             cur++;
3839     }
3840     if (hi != --cur) {
3841         cur = hi;
3842         goto missing_part;
3843     }
3844
3845     ctq = base;
3846     ct = *ctq++;
3847     if (store_content (ct, "") == NOTOK) {
3848 losing: ;
3849         free ((char *) base);
3850         return NOTOK;
3851     }
3852
3853     for (; p = *ctq; ctq++)
3854         if (store_content (p, ct -> c_storage) == NOTOK)
3855             goto losing;
3856
3857     free ((char *) base);
3858     return OK;
3859 }
3860
3861
3862 static int  free_partial (ct)
3863 register CT     ct;
3864 {
3865     register struct partial *p = (struct partial *) ct -> c_ctparams;
3866
3867     if (!p)
3868         return;
3869
3870     if (p -> pm_partid)
3871         free (p -> pm_partid);
3872
3873     free ((char *) p);
3874     ct -> c_ctparams = NULL;
3875 }
3876
3877
3878 struct exbody {
3879     CT      eb_parent;
3880     CT      eb_content;
3881     char   *eb_partno;
3882
3883     char   *eb_access;
3884     int     eb_flags;
3885
3886     char   *eb_name;
3887     char   *eb_permission;
3888
3889     char   *eb_site;
3890     char   *eb_dir;
3891     char   *eb_mode;
3892     unsigned long
3893             eb_size;
3894
3895     char   *eb_server;
3896     char   *eb_subject;
3897     char   *eb_body;
3898 };
3899
3900
3901 static  int     openFile ();
3902 static  int     openFTP ();
3903 static  int     openMail ();
3904
3905 /* NOTE WELL: si_key MUST NOT have value of NOTOK */
3906
3907 static struct str2init str2methods[] = {
3908     "afs",         1,   openFile,
3909     "anon-ftp",    1,   openFTP,
3910     "ftp",         0,   openFTP,
3911     "local-file",  0,   openFile,
3912     "mail-server", 0,   openMail,
3913
3914     NULL
3915 };
3916
3917
3918 static int  params_external (ct, composing)
3919 register CT     ct;
3920 int     composing;
3921 {
3922     register char  **ap,
3923                    **ep;
3924     register struct exbody *e = (struct exbody *) ct -> c_ctparams;
3925     register CI     ci = &ct -> c_ctinfo;
3926
3927     for (ap = ci -> ci_attrs, ep = ci -> ci_values; *ap; ap++, ep++) {
3928         if (uleq (*ap, "access-type")) {
3929             register struct str2init *s2i;
3930             register    CT      p = e -> eb_content;
3931
3932             for (s2i = str2methods; s2i -> si_key; s2i++)
3933                 if (uleq (*ep, s2i -> si_key))
3934                     break;
3935             if (!s2i -> si_key) {
3936                 e -> eb_access = *ep;
3937                 e -> eb_flags = NOTOK;
3938                 p -> c_encoding = CE_EXTERNAL;
3939                 continue;
3940             }
3941             e -> eb_access = s2i -> si_key;
3942             e -> eb_flags = s2i -> si_val;
3943             p -> c_encoding = CE_EXTERNAL;
3944             if (init_encoding (p, s2i -> si_init) == NOTOK)
3945                 return NOTOK;
3946             continue;
3947         }
3948         if (uleq (*ap, "name")) {
3949             e -> eb_name = *ep;
3950             continue;
3951         }
3952         if (uleq (*ap, "permission")) {
3953             e -> eb_permission = *ep;
3954             continue;
3955         }
3956         if (uleq (*ap, "site")) {
3957             e -> eb_site = *ep;
3958             continue;
3959         }
3960         if (uleq (*ap, "directory")) {
3961             e -> eb_dir = *ep;
3962             continue;
3963         }
3964         if (uleq (*ap, "mode")) {
3965             e -> eb_mode = *ep;
3966             continue;
3967         }
3968         if (uleq (*ap, "size")) {
3969             (void) sscanf (*ep, "%lu", &e -> eb_size);
3970             continue;
3971         }
3972         if (uleq (*ap, "server")) {
3973             e -> eb_server = *ep;
3974             continue;
3975         }
3976         if (uleq (*ap, "subject")) {
3977             e -> eb_subject = *ep;
3978             continue;
3979         }
3980         if (composing && uleq (*ap, "body")) {
3981             e -> eb_body = getcpy (*ep);
3982             continue;
3983         }
3984     }
3985
3986     if (!e -> eb_access) {
3987         advise (NULLCP,
3988                 "invalid parameters for \"%s/%s\" type in message %s's %s field",
3989                 ci -> ci_type, ci -> ci_subtype,
3990                 ct -> c_file, TYPE_FIELD);
3991         return NOTOK;
3992     }
3993
3994     return OK;
3995 }
3996
3997 static int  list_external (ct, toplevel)
3998 register CT     ct;
3999 int     toplevel;
4000 {
4001     register struct exbody *e = (struct exbody *) ct -> c_ctparams;
4002
4003     (void) list_content (ct, toplevel);
4004     if (verbosw) {
4005         if (e -> eb_name)
4006             printf ("\t     retrieve %s\n", e -> eb_name);
4007         if (e -> eb_dir)
4008             printf ("\t in directory %s\n", e -> eb_dir);
4009         if (e -> eb_site)
4010             printf ("\t         from %s\n", e -> eb_site);
4011         if (e -> eb_server)
4012             printf ("\t from mailbox %s\n", e -> eb_server);
4013         if (e -> eb_subject)
4014             printf ("\t with subject %s\n", e -> eb_subject);
4015         printf     ("\t        using %s", e -> eb_access);
4016         if (e -> eb_mode)
4017             printf (" (in %s mode)", e -> eb_mode);
4018         if (e -> eb_permission)
4019             printf (" (permission %s)", e -> eb_permission);
4020         if (e -> eb_flags == NOTOK)
4021             printf (" [service unavailable]");
4022         printf ("\n");
4023     }
4024     (void) list_content (e -> eb_content, 0);
4025
4026     return OK;
4027 }
4028
4029
4030 static int  show_external (ct, serial, alternate)
4031 register CT     ct;
4032 int     serial,
4033         alternate;
4034 {
4035     register struct exbody *e = (struct exbody *) ct -> c_ctparams;
4036     register CT     p = e -> eb_content;
4037
4038     if (!type_ok (p, 0))
4039         return OK;
4040
4041     if (p -> c_ctshowfnx)
4042         return (*p -> c_ctshowfnx) (p, serial, alternate);
4043
4044     content_error (NULLCP, p, "don't know how to display content");
4045     return NOTOK;
4046 }
4047
4048
4049 static int  store_external (ct)
4050 register CT     ct;
4051 {
4052     int     result = NOTOK;
4053     register struct exbody *e = (struct exbody *) ct -> c_ctparams;
4054     register CT     p = e -> eb_content;
4055
4056     if (!type_ok (p, 1))
4057         return OK;
4058
4059     p -> c_partno = ct -> c_partno;
4060     if (p -> c_ctstorefnx)
4061         result = (*p -> c_ctstorefnx) (p, NULLCP);
4062     p -> c_partno = NULL;
4063
4064     return result;
4065 }
4066
4067
4068 static int  free_external (ct)
4069 register CT     ct;
4070 {
4071     register struct exbody *e = (struct exbody *) ct -> c_ctparams;
4072
4073     if (!e)
4074         return;
4075
4076     free_content (e -> eb_content);
4077     if (e -> eb_body)
4078         free (e -> eb_body);
4079
4080     free ((char *) e);
4081     ct -> c_ctparams = NULL;
4082 }
4083
4084
4085 static struct k2v SubMessage[] = {
4086     "rfc822",        MESSAGE_RFC822,
4087     "partial",       MESSAGE_PARTIAL,
4088     "external-body", MESSAGE_EXTERNAL,
4089
4090     NULL,            MESSAGE_UNKNOWN            /* this one must be last! */
4091 };
4092
4093 static int  InitMessage (ct)
4094 register CT     ct;
4095 {
4096     register struct k2v *kv;
4097     register CI     ci = &ct -> c_ctinfo;
4098
4099     if (ct -> c_encoding != CE_7BIT) {
4100         admonish (NULLCP,
4101                   "\"%s/%s\" type in message %s should be encoded in 7bit",
4102                   ci -> ci_type, ci -> ci_subtype, ct -> c_file);
4103         return NOTOK;
4104     }
4105
4106     if (!*ci -> ci_subtype)     /* XXX: attmail bogosity! */
4107         ci -> ci_subtype = add ("rfc822", ci -> ci_subtype);
4108     for (kv = SubMessage; kv -> kv_key; kv++)
4109         if (uleq (ci -> ci_subtype, kv -> kv_key))
4110             break;
4111
4112     switch (ct -> c_subtype = kv -> kv_value) {
4113         case MESSAGE_RFC822:
4114             ct -> c_showproc = add ("%pshow -file '%F'", NULLCP);
4115             break;
4116
4117         case MESSAGE_PARTIAL:
4118             {
4119                 register char **ap,
4120                               **ep;
4121                 register struct partial *p;
4122
4123                 ct -> c_ctshowfnx = NULL;
4124                 ct -> c_ctstorefnx = NULL;
4125
4126                 if ((p = (struct partial *) calloc (1, sizeof *p)) == NULL)
4127                     adios (NULLCP, "out of memory");
4128                 ct -> c_ctparams = (caddr_t) p;
4129                 ct -> c_ctfreefnx = free_partial;
4130
4131                 for (ap = ci -> ci_attrs, ep = ci -> ci_values;
4132                          *ap; 
4133                          ap++, ep++) {
4134                     if (uleq (*ap, "id")) {
4135                         p -> pm_partid = add (*ep, NULLCP);
4136
4137                         continue;
4138                     }
4139
4140                     if (uleq (*ap, "number")) {
4141                         if (sscanf (*ep, "%d", &p -> pm_partno) != 1
4142                                 || p -> pm_partno < 1) {
4143 invalid_param: ;
4144                             advise (NULLCP,
4145                                     "invalid %s parameter for \"%s/%s\" type in message %s's %s field",
4146                                     *ap, ci -> ci_type, ci -> ci_subtype,
4147                                     ct -> c_file, TYPE_FIELD);
4148                             return NOTOK;
4149                         }
4150
4151                         continue;
4152                     }
4153
4154                     if (uleq (*ap, "total")) {
4155                         if (sscanf (*ep, "%d", &p -> pm_maxno) != 1
4156                                 || p -> pm_maxno < 1)
4157                             goto invalid_param;
4158
4159                         continue;
4160                     }
4161                 }
4162
4163                 if (!p -> pm_partid
4164                         || !p -> pm_partno
4165                         || (p -> pm_maxno && p -> pm_partno > p -> pm_maxno)) {
4166                     advise (NULLCP,
4167                             "invalid parameters for \"%s/%s\" type in message %s's %s field",
4168                             ci -> ci_type, ci -> ci_subtype,
4169                             ct -> c_file, TYPE_FIELD);
4170                     return NOTOK;
4171                 }
4172
4173                 ct -> c_ctlistfnx = list_partial;
4174                 ct -> c_ctstorefnx = store_partial;
4175             }
4176             break;
4177
4178         case MESSAGE_EXTERNAL:
4179             {
4180                 int     exresult;
4181                 register struct exbody *e;
4182                 CT      p;
4183                 FILE   *fp;
4184
4185                 ct -> c_ctshowfnx = NULL;
4186                 ct -> c_ctstorefnx = NULL;
4187
4188                 if ((e = (struct exbody *) calloc (1, sizeof *e)) == NULL)
4189                     adios (NULLCP, "out of memory");
4190                 ct -> c_ctparams = (caddr_t) e;
4191                 ct -> c_ctfreefnx = free_external;
4192
4193                 if (!ct -> c_fp
4194                         && (ct -> c_fp = fopen (ct -> c_file, "r")) == NULL) {
4195                     advise (ct -> c_file, "unable to open for reading");
4196                     return NOTOK;
4197                 }
4198
4199                 (void) fseek (fp = ct -> c_fp, ct -> c_begin, 0);
4200
4201                 if ((p = get_content (fp, ct -> c_file, 0)) == NULLCT) {
4202                     (void) fclose (ct -> c_fp), ct -> c_fp = NULL;
4203                     return NOTOK;
4204                 }
4205
4206                 e -> eb_parent = ct;
4207                 e -> eb_content = p;
4208                 p -> c_ctextern = (caddr_t) e;
4209                 if ((exresult = params_external (ct, 0)) != NOTOK
4210                         && p -> c_ceopenfnx == openMail) {
4211                     int     cc,
4212                             size;
4213                     char   *bp;
4214                     
4215                     if ((size = ct -> c_end - p -> c_begin) <= 0) {
4216                         if (!e -> eb_subject)
4217                             content_error (NULLCP, ct,
4218                                            "empty body for access-type=mail-server");
4219                         goto no_body;
4220                     }
4221                     
4222                     if ((e -> eb_body = bp = malloc ((unsigned) size)) == NULL)
4223                         adios (NULLCP, "out of memory");
4224                     (void) fseek (p -> c_fp, p -> c_begin, 0);
4225                     while (size > 0)
4226                         switch (cc = fread (bp, sizeof *bp, size, p -> c_fp)) {
4227                             case NOTOK:
4228                                 adios ("failed", "fread");
4229
4230                             case OK:
4231                                 adios (NULLCP, "unexpected EOF from fread");
4232
4233                             default:
4234                                 bp += cc, size -= cc;
4235                                 break;
4236                         }
4237                     *bp = 0;
4238 no_body: ;
4239                 }
4240                 p -> c_fp = NULL;
4241                 p -> c_end = p -> c_begin;
4242
4243                 (void) fclose (ct -> c_fp), ct -> c_fp = NULL;
4244
4245                 ct -> c_ctlistfnx = list_external;
4246
4247                 if (exresult == NOTOK)
4248                     return NOTOK;
4249                 if (e -> eb_flags == NOTOK)
4250                     return OK;
4251
4252                 if (e -> eb_name && autosw) {
4253                     char   *cp = e -> eb_name;
4254
4255                     if (*cp != '/'
4256                             && *cp != '.'
4257                             && *cp != '|'
4258                             && *cp != '!'
4259                             && !index (cp, '%')) {
4260                         if (!ct -> c_storeproc)
4261                             ct -> c_storeproc = add (cp, NULLCP);
4262                         if (!p -> c_storeproc)
4263                             p -> c_storeproc = add (cp, NULLCP);
4264                     }
4265                 }
4266
4267                 ct -> c_ctshowfnx = show_external;
4268                 ct -> c_ctstorefnx = store_external;
4269                 switch (p -> c_type) {
4270                     case CT_MULTIPART:
4271                         break;
4272
4273                     case CT_MESSAGE:
4274                         if (p -> c_subtype != MESSAGE_RFC822)
4275                             break;
4276                         /* else fall... */
4277                     default:
4278                         e -> eb_partno = ct -> c_partno;
4279                         if (p -> c_ctinitfnx)
4280                             (void) (*p -> c_ctinitfnx) (p);
4281                         break;
4282                 }
4283             }
4284             break;
4285
4286         default:
4287             break;
4288     }
4289
4290     return OK;
4291 }
4292
4293 /* \f   APPLICATION */
4294
4295 #define APPLICATION_UNKNOWN     0x00
4296 #define APPLICATION_OCTETS      0x01
4297 #define APPLICATION_POSTSCRIPT  0x02
4298
4299
4300 static int  list_application (ct, toplevel)
4301 register CT     ct;
4302 int     toplevel;
4303 {
4304     (void) list_content (ct, toplevel);
4305     if (verbosw) {
4306         register char **ap,
4307                       **ep;
4308         register CI     ci = &ct -> c_ctinfo;
4309
4310         for (ap = ci -> ci_attrs, ep = ci -> ci_values; *ap; ap++, ep++)
4311             printf ("\t     %s=\"%s\"\n", *ap, *ep);
4312     }
4313
4314     return OK;
4315 }
4316
4317
4318 static struct k2v SubApplication[] = {
4319     "octet-stream",       APPLICATION_OCTETS,
4320     "postscript",         APPLICATION_POSTSCRIPT,
4321     NULL,                 APPLICATION_UNKNOWN   /* this one must be last! */
4322 };
4323
4324 static int  InitApplication (ct)
4325 register CT     ct;
4326 {
4327     register char **ap,
4328                   **ep;
4329     register struct k2v *kv;
4330     register CI     ci = &ct -> c_ctinfo;
4331
4332     ct -> c_ctlistfnx = list_application;
4333     
4334     for (kv = SubApplication; kv -> kv_key; kv++)
4335         if (uleq (ci -> ci_subtype, kv -> kv_key))
4336             break;
4337
4338     for (ap = ci -> ci_attrs, ep = ci -> ci_values; *ap; ap++, ep++)
4339         if (autosw && !ct -> c_storeproc && uleq (*ap, "name")) {
4340             register char   *cp;
4341
4342             if (*(cp = *ep) != '/'
4343                     && *cp != '.'
4344                     && *cp != '|'
4345                     && *cp != '!'
4346                     && !index (cp, '%'))
4347                 ct -> c_storeproc = add (cp, NULLCP);
4348         }
4349
4350     if ((ct -> c_subtype = kv -> kv_value) == APPLICATION_OCTETS) {
4351         int     tarP,
4352                 zP;
4353
4354         tarP = zP = 0;
4355         for (ap = ci -> ci_attrs, ep = ci -> ci_values; *ap; ap++, ep++) {
4356             if (uleq (*ap, "type")) {
4357                 if (!uleq (*ep, "tar"))
4358                     break;
4359
4360                 tarP = 1;
4361                 continue;
4362             }
4363
4364             if ((uleq (*ap, "conversions") || uleq (*ap, "x-conversions"))
4365                     && (uleq (*ep, "compress") || uleq (*ep, "x-compress"))) {
4366                 zP = 1;
4367                 continue;
4368             }
4369         }
4370
4371         if (tarP) {
4372             ct -> c_showproc = add (zP ? "%euncompress | tar tvf -"
4373                                        : "%etar tvf -", NULLCP);
4374             if (!ct -> c_storeproc)
4375                 if (autosw) {
4376                     ct -> c_storeproc = add (zP ? "| uncompress | tar xvpf -"
4377                                                 : "| tar xvpf -", NULLCP);
4378                     ct -> c_umask = 0022;
4379                 }
4380                 else
4381                     ct -> c_storeproc = add (zP ? "%m%P.tar.Z" : "%m%P.tar",
4382                                              NULLCP);
4383         }
4384     }
4385
4386     return OK;
4387 }
4388
4389 /* \f   ENCODINGS */
4390
4391 #include "md5.c"
4392
4393
4394 struct cefile {
4395     char   *ce_file;
4396     int     ce_unlink;
4397
4398     FILE   *ce_fp;
4399 };
4400
4401
4402 static int  list_encoding (ct)
4403 register CT     ct;
4404 {
4405     register struct cefile *ce = (struct cefile *) ct -> c_ceparams;
4406
4407     if (ce)
4408         fprintf (stderr, "  decoded fp 0x%x file \"%s\"\n", ce -> ce_fp,
4409                  ce -> ce_file ? ce -> ce_file : "");
4410
4411     return OK;
4412 }
4413
4414
4415 static int  close_encoding (ct)
4416 register CT     ct;
4417 {
4418     register struct cefile *ce = (struct cefile *) ct -> c_ceparams;
4419
4420     if (!ce)
4421         return;
4422
4423     if (ce -> ce_fp) {
4424         (void) fclose (ce -> ce_fp);
4425         ce -> ce_fp = NULL;
4426     }
4427 }
4428
4429
4430 static unsigned long  size_encoding (ct)
4431 register CT     ct;
4432 {
4433     int     fd;
4434     unsigned long size;
4435     char   *file;
4436     register struct cefile *ce = (struct cefile *) ct -> c_ceparams;
4437     struct stat st;
4438
4439     if (!ce) {
4440 estimate: ;
4441
4442         return (ct -> c_end - ct -> c_begin);
4443     }
4444
4445     if (ce -> ce_fp && fstat (fileno (ce -> ce_fp), &st) != NOTOK)
4446         return (long) st.st_size;
4447
4448     if (ce -> ce_file)
4449         return stat (ce -> ce_file, &st) != NOTOK ? (long) st.st_size : 0L;
4450
4451     if (ct -> c_encoding == CE_EXTERNAL)
4452         goto estimate;
4453
4454     file = NULL;
4455     if ((fd = (*ct -> c_ceopenfnx) (ct, &file)) == NOTOK)
4456         goto estimate;
4457
4458     size = fstat (fd, &st) != NOTOK ? (long) st.st_size : 0L;
4459
4460     (*ct -> c_ceclosefnx) (ct);
4461
4462     return size;
4463 }
4464
4465
4466 static int  free_encoding (ct, toplevel)
4467 register CT     ct;
4468 int     toplevel;
4469 {
4470     register struct cefile *ce = (struct cefile *) ct -> c_ceparams;
4471
4472     if (!ce)
4473         return;
4474
4475     if (ce -> ce_fp) {
4476         (void) fclose (ce -> ce_fp);
4477         ce -> ce_fp = NULL;
4478     }
4479
4480     if (ce -> ce_file) {
4481         if (ce -> ce_unlink)
4482             (void) unlink (ce -> ce_file);
4483         free (ce -> ce_file);
4484     }
4485
4486     if (toplevel) {
4487         free ((char *) ce);
4488         ct -> c_ceparams = NULL;
4489     }
4490     else
4491         ct -> c_ceopenfnx = NULL;
4492 }
4493
4494
4495 static  init_encoding (ct, openfnx)
4496 register CT     ct;
4497 int   (*openfnx) ();
4498 {
4499     register struct cefile *ce;
4500
4501     if ((ce = (struct cefile *) calloc (1, sizeof *ce)) == NULL)
4502         adios (NULLCP, "out of memory");
4503
4504     ct -> c_ceparams = (caddr_t) ce;
4505     ct -> c_ceopenfnx = openfnx;
4506     ct -> c_ceclosefnx = close_encoding;
4507     ct -> c_cesizefnx = size_encoding;
4508     ct -> c_celistfnx = list_encoding;
4509     ct -> c_cefreefnx = free_encoding;
4510
4511     return OK;
4512 }
4513
4514 /* \f   BASE64 */
4515
4516 static unsigned char b642nib[0x80] = {
4517     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
4518     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
4519     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
4520     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
4521     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
4522     0xff, 0xff, 0xff, 0x3e, 0xff, 0xff, 0xff, 0x3f,
4523     0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b,
4524     0x3c, 0x3d, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
4525     0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 
4526     0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
4527     0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
4528     0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff,
4529     0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 
4530     0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
4531     0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
4532     0x31, 0x32, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff
4533 };
4534
4535
4536 static int  openBase64 (ct, file)
4537 register CT     ct;
4538 char  **file;
4539 {
4540     int     bitno,
4541             cc,
4542             digested,
4543             fd,
4544             len,
4545             skip;
4546     unsigned long    bits;
4547     register char  *cp,
4548                    *ep;
4549     unsigned char   value,
4550                    *b = (unsigned char *) &bits,
4551                    *b1 = &b[endian > 0 ? 1 : 2],
4552                    *b2 = &b[endian > 0 ? 2 : 1],
4553                    *b3 = &b[endian > 0 ? 3 : 0];
4554     char    buffer[BUFSIZ];
4555     register struct cefile *ce = (struct cefile *) ct -> c_ceparams;
4556     MD5_CTX mdContext;
4557
4558     if (ce -> ce_fp)
4559         goto ready_to_go;
4560     if (ce -> ce_file) {
4561         if ((ce -> ce_fp = fopen (ce -> ce_file, "r")) == NULL) {
4562             content_error (ce -> ce_file, ct, "unable to fopen for reading");
4563             return NOTOK;
4564         }
4565
4566         *file = ce -> ce_file;
4567         return fileno (ce -> ce_fp);
4568     }
4569
4570     ce -> ce_unlink = *file == NULL;
4571     if ((ce -> ce_fp = fopen (ce -> ce_file =
4572                                     add (*file ? *file : m_scratch ("", tmp),
4573                                          NULLCP),
4574                               "w+")) == NULL) {
4575         content_error (ce -> ce_file, ct,
4576                        "unable to fopen for writing and reading");
4577         return NOTOK;
4578     }
4579
4580     if ((len = ct -> c_end - ct -> c_begin) < 0)
4581         adios (NULLCP, "internal error(1)");
4582
4583     if (!ct -> c_fp && (ct -> c_fp = fopen (ct -> c_file, "r")) == NULL) {
4584         content_error (ct -> c_file, ct, "unable to open for reading");
4585         return NOTOK;
4586     }
4587     
4588     if (digested = ct -> c_digested)
4589         MD5Init (&mdContext);
4590
4591     (void) lseek (fd = fileno (ct -> c_fp), (off_t)ct -> c_begin, 0);
4592     bitno = 18, bits = 0L, skip = 0;
4593     while (len > 0)
4594         switch (cc = read (fd, buffer, sizeof buffer - 1)) {
4595             case NOTOK:
4596                 content_error (ct -> c_file, ct, "error reading from");
4597                 goto clean_up;
4598
4599             case OK:
4600                 content_error (NULLCP, ct, "premature eof");
4601                 goto clean_up;
4602
4603             default:
4604                 if (cc > len)
4605                     cc = len;
4606                 len -= cc;
4607
4608                 for (ep = (cp = buffer) + cc; cp < ep; cp++)
4609                     switch (*cp) {
4610                         default:
4611                             if (isspace (*cp))
4612                                 break;
4613                             if (skip
4614                                     || (*cp & 0x80)
4615                                     || (value = b642nib[*cp & 0x7f]) > 0x3f) {
4616                                 if (debugsw)
4617                                     fprintf (stderr,
4618                                              "*cp=0x%x pos=%ld skip=%d\n", *cp,
4619                                              (long) lseek (fd, (off_t)0, 1) - (ep - cp),
4620                                              skip);
4621                                 content_error (NULLCP, ct,
4622                                       "invalid BASE64 encoding -- continuing");
4623                                 continue;
4624                             }
4625
4626                             bits |= value << bitno;
4627 test_end: ;
4628                             if ((bitno -= 6) < 0) {
4629                                 (void) putc ((char) *b1, ce -> ce_fp);
4630                                 if (digested)
4631                                     MD5Update (&mdContext, b1, 1);
4632                                 if (skip < 2) {
4633                                     (void) putc ((char) *b2, ce -> ce_fp);
4634                                     if (digested)
4635                                         MD5Update (&mdContext, b2, 1);
4636                                     if (skip < 1) {
4637                                         (void) putc ((char) *b3, ce -> ce_fp);
4638                                         if (digested)
4639                                             MD5Update (&mdContext, b3, 1);
4640                                     }
4641                                 }
4642
4643                                 if (ferror (ce -> ce_fp)) {
4644                                     content_error (ce -> ce_file, ct,
4645                                                    "error writing to");
4646                                     goto clean_up;
4647                                 }
4648                                 bitno = 18, bits = 0L, skip = 0;
4649                             }
4650                             break;
4651
4652                         case '=':
4653                             if (++skip > 3)
4654                                 goto self_delimiting;
4655                             goto test_end;
4656                     }
4657         }
4658     if (bitno != 18) {
4659         if (debugsw)
4660             fprintf (stderr, "premature ending (bitno %d)\n", bitno);
4661
4662         content_error (NULLCP, ct, "invalid BASE64 encoding");
4663         goto clean_up;
4664     }
4665 self_delimiting: ;
4666     (void) fseek (ct -> c_fp, 0L, 0);
4667
4668     if (fflush (ce -> ce_fp)) {
4669         content_error (ce -> ce_file, ct, "error writing to");
4670         goto clean_up;
4671     }
4672
4673     if (digested) {
4674         unsigned char  digest[16];
4675
4676         MD5Final (digest, &mdContext);
4677         if (bcmp ((char *) digest, (char *) ct -> c_digest,
4678                   sizeof digest / sizeof digest[0]))
4679             content_error (NULLCP, ct,
4680                            "content integrity suspect (digest mismatch) -- continuing");
4681         else
4682             if (debugsw)
4683                 fprintf (stderr, "content integrity confirmed\n");
4684     }
4685
4686 ready_to_go: ;
4687     (void) fseek (ce -> ce_fp, 0L, 0);
4688     *file = ce -> ce_file;
4689     return fileno (ce -> ce_fp);
4690
4691 clean_up: ;
4692     free_encoding (ct, 0);
4693
4694     return NOTOK;
4695 }
4696
4697
4698 static int  InitBase64 (ct)
4699 register CT     ct;
4700 {
4701     return init_encoding (ct, openBase64);
4702 }
4703
4704
4705 static int  set_endian ()
4706 {
4707     char   *cp;
4708     union {
4709         long    l;
4710         char    c[sizeof (long)];
4711     }   un;
4712
4713     un.l = 1;
4714     endian = un.c[0] ? -1 : 1;
4715     if (debugsw)
4716         fprintf (stderr, "%s endian architecture\n",
4717                  endian > 0 ? "big" : "little");
4718
4719     mm_charset = getenv ("MM_CHARSET");
4720
4721     if ((cp = getenv ("MM_NOASK")) && strcmp (cp, "1") == 0) {
4722         nolist = 1, pausesw = 0;
4723         if (showsw)
4724             listsw = 0;
4725     }
4726 }
4727
4728 /* \f   QUOTED */
4729
4730 static char hex2nib[0x80] = {
4731     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4732     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4733     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4734     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4735     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4736     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4737     0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
4738     0x08, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4739     0x00, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x00, 
4740     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4741     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4742     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4743     0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 
4744     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4745     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4746     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
4747 };
4748
4749
4750 static int  openQuoted (ct, file)
4751 register CT     ct;
4752 char  **file;
4753 {
4754     int     cc,
4755             digested,
4756             len,
4757             quoted;
4758     register char  *cp,
4759                    *ep;
4760     char    buffer[BUFSIZ];
4761     unsigned char mask;
4762     register struct cefile *ce = (struct cefile *) ct -> c_ceparams;
4763     MD5_CTX mdContext;
4764
4765     if (ce -> ce_fp)
4766         goto ready_to_go;
4767     if (ce -> ce_file) {
4768         if ((ce -> ce_fp = fopen (ce -> ce_file, "r")) == NULL) {
4769             content_error (ce -> ce_file, ct, "unable to fopen for reading");
4770             return NOTOK;
4771         }
4772
4773         *file = ce -> ce_file;
4774         return fileno (ce -> ce_fp);
4775     }
4776
4777     ce -> ce_unlink = *file == NULL;
4778     if ((ce -> ce_fp = fopen (ce -> ce_file =
4779                                     add (*file ? *file : m_scratch ("", tmp),
4780                                          NULLCP),
4781                               "w+")) == NULL) {
4782         content_error (ce -> ce_file, ct,
4783                        "unable to fopen for writing and reading");
4784         return NOTOK;
4785     }
4786
4787     if ((len = ct -> c_end - ct -> c_begin) < 0)
4788         adios (NULLCP, "internal error(2)");
4789
4790     if (!ct -> c_fp && (ct -> c_fp = fopen (ct -> c_file, "r")) == NULL) {
4791         content_error (ct -> c_file, ct, "unable to open for reading");
4792         return NOTOK;
4793     }
4794
4795     if (digested = ct -> c_digested)
4796         MD5Init (&mdContext);
4797
4798     (void) fseek (ct -> c_fp, ct -> c_begin, 0);
4799     quoted = 0;
4800 #ifdef  lint
4801     mask = 0;
4802 #endif
4803     while (len > 0) {
4804         char   *dp;
4805
4806         if (fgets (buffer, sizeof buffer - 1, ct -> c_fp) == NULL) {
4807             content_error (NULLCP, ct, "premature eof");
4808             goto clean_up;
4809         }
4810
4811         if ((cc = strlen (buffer)) > len)
4812             cc = len;
4813         len -= cc;
4814
4815         for (ep = (cp = buffer) + cc - 1; cp <= ep; ep--)
4816             if (!isspace (*ep))
4817                 break;
4818         *++ep = '\n', ep++;
4819
4820         for (; cp < ep; cp++) {
4821             if (quoted) {
4822                 if (quoted > 1) {
4823                     if (!isxdigit (*cp)) {
4824 invalid_hex: ;
4825                         dp = "expecting hexidecimal-digit";
4826                         goto invalid_encoding;
4827                     }
4828                     mask <<= 4;
4829                     mask |= hex2nib[*cp & 0x7f];
4830                     (void) putc (mask, ce -> ce_fp);
4831                     if (digested)
4832                         MD5Update (&mdContext, &mask, 1);
4833                 }
4834                 else
4835                     switch (*cp) {
4836                         case ':':
4837                             (void) putc (*cp, ce -> ce_fp);
4838                             if (digested)
4839                                 MD5Update (&mdContext, (unsigned char *) ":",
4840                                            1);
4841                             break;
4842
4843                         default:
4844                             if (!isxdigit (*cp))
4845                                 goto invalid_hex;
4846                             mask = hex2nib[*cp & 0x7f];
4847                             quoted = 2;
4848                             continue;
4849                     }
4850
4851                 if (ferror (ce -> ce_fp)) {
4852                     content_error (ce -> ce_file, ct, "error writing to");
4853                     goto clean_up;
4854                 }
4855                 quoted = 0;
4856                 continue;
4857             }
4858
4859             switch (*cp) {
4860                 default:
4861                     if (*cp < '!' || *cp > '~') {
4862                         int     i;
4863                         dp = "expecting character in range [!..~]";
4864
4865 invalid_encoding: ;
4866                         i = strlen (invo_name) + 2;
4867                         content_error (NULLCP, ct,
4868                                        "invalid QUOTED-PRINTABLE encoding -- %s,\n%*.*sbut got char 0x%x",
4869                                        dp, i, i, "", *cp);
4870                         goto clean_up;
4871                     }
4872                     /* and fall...*/
4873                 case ' ':
4874                 case '\t':
4875                 case '\n':
4876                     (void) putc (*cp, ce -> ce_fp);
4877                     if (digested) {
4878                         if (*cp == '\n')
4879                             MD5Update (&mdContext, (unsigned char *) "\r\n",2);
4880                         else
4881                             MD5Update (&mdContext, (unsigned char *) cp, 1);
4882                     }
4883                     if (ferror (ce -> ce_fp)) {
4884                         content_error (ce -> ce_file, ct, "error writing to");
4885                         goto clean_up;
4886                     }
4887                     break;
4888
4889                 case '=':
4890                     if (*++cp != '\n') {
4891                         quoted = 1;
4892                         cp--;
4893                     }
4894                     break;
4895             }
4896         }
4897     }
4898     if (quoted) {
4899         content_error (NULLCP, ct,
4900                        "invalid QUOTED-PRINTABLE encoding -- end-of-content while still quoting");
4901         goto clean_up;
4902     }
4903     (void) fseek (ct -> c_fp, 0L, 0);
4904
4905     if (fflush (ce -> ce_fp)) {
4906         content_error (ce -> ce_file, ct, "error writing to");
4907         goto clean_up;
4908     }
4909
4910     if (digested) {
4911         unsigned char  digest[16];
4912
4913         MD5Final (digest, &mdContext);
4914         if (bcmp ((char *) digest, (char *) ct -> c_digest,
4915                   sizeof digest / sizeof digest[0]))
4916             content_error (NULLCP, ct,
4917                            "content integrity suspect (digest mismatch) -- continuing");
4918         else
4919             if (debugsw)
4920                 fprintf (stderr, "content integrity confirmed\n");
4921     }
4922
4923 ready_to_go: ;
4924     (void) fseek (ce -> ce_fp, 0L, 0);
4925     *file = ce -> ce_file;
4926     return fileno (ce -> ce_fp);
4927
4928 clean_up: ;
4929     free_encoding (ct, 0);
4930
4931     return NOTOK;
4932 }
4933
4934
4935 static int  InitQuoted (ct)
4936 register CT     ct;
4937 {
4938     return init_encoding (ct, openQuoted);
4939 }
4940
4941 /* \f   7BIT */
4942
4943 static int  open7Bit (ct, file)
4944 register CT     ct;
4945 char  **file;
4946 {
4947     int     cc,
4948             fd,
4949             len;
4950     char    buffer[BUFSIZ];
4951     register struct cefile *ce = (struct cefile *) ct -> c_ceparams;
4952
4953     if (ce -> ce_fp)
4954         goto ready_to_go;
4955     if (ce -> ce_file) {
4956         if ((ce -> ce_fp = fopen (ce -> ce_file, "r")) == NULL) {
4957             content_error (ce -> ce_file, ct, "unable to fopen for reading");
4958             return NOTOK;
4959         }
4960
4961         *file = ce -> ce_file;
4962         return fileno (ce -> ce_fp);
4963     }
4964
4965     ce -> ce_unlink = *file == NULL;
4966     if ((ce -> ce_fp = fopen (ce -> ce_file =
4967                                     add (*file ? *file : m_scratch ("", tmp),
4968                                          NULLCP),
4969                               "w+")) == NULL) {
4970         content_error (ce -> ce_file, ct,
4971                        "unable to fopen for writing and reading");
4972         return NOTOK;
4973     }
4974
4975     if (ct -> c_type == CT_MULTIPART) {
4976         register char **ap,
4977                       **ep;
4978         register CI     ci = &ct -> c_ctinfo;
4979
4980         len = 0;
4981
4982         fprintf (ce -> ce_fp, "%s: %s/%s", TYPE_FIELD, ci -> ci_type,
4983                  ci -> ci_subtype);
4984         len += strlen (TYPE_FIELD) + 2 + strlen (ci -> ci_type)
4985                                    + 1 + strlen (ci -> ci_subtype);
4986         for (ap = ci -> ci_attrs, ep = ci -> ci_values; *ap; ap++, ep++) {
4987             (void) putc (';', ce -> ce_fp);
4988             len++;
4989
4990             (void) sprintf (buffer, "%s=\"%s\"", *ap, *ep);
4991
4992             if (len + 1 + (cc = strlen (buffer)) >= CPERLIN) {
4993                 (void) fputs ("\n\t", ce -> ce_fp);
4994                 len = 8;
4995             }
4996             else {
4997                 (void) putc (' ', ce -> ce_fp);
4998                 len++;
4999             }
5000             fprintf (ce -> ce_fp, "%s", buffer);
5001             len += cc;
5002         }
5003         if (ci -> ci_comment) {
5004             if (len + 1 + (cc = 2 + strlen (ci -> ci_comment)) >= CPERLIN) {
5005                 (void) fputs ("\n\t", ce -> ce_fp);
5006                 len = 8;
5007             }
5008             else {
5009                 (void) putc (' ', ce -> ce_fp);
5010                 len++;
5011             }
5012             fprintf (ce -> ce_fp, "(%s)", ci -> ci_comment);
5013             len += cc;
5014         }
5015         fprintf (ce -> ce_fp, "\n");
5016         if (ct -> c_id)
5017             fprintf (ce -> ce_fp, "%s:%s", ID_FIELD, ct -> c_id);
5018         if (ct -> c_descr)
5019             fprintf (ce -> ce_fp, "%s:%s", DESCR_FIELD, ct -> c_descr);
5020         fprintf (ce -> ce_fp, "\n");
5021     }
5022
5023     if ((len = ct -> c_end - ct -> c_begin) < 0)
5024         adios (NULLCP, "internal error(3)");
5025
5026     if (!ct -> c_fp && (ct -> c_fp = fopen (ct -> c_file, "r")) == NULL) {
5027         content_error (ct -> c_file, ct, "unable to open for reading");
5028         return NOTOK;
5029     }
5030
5031     (void) lseek (fd = fileno (ct -> c_fp), (off_t) ct -> c_begin, 0);
5032     while (len > 0)
5033         switch (cc = read (fd, buffer, sizeof buffer - 1)) {
5034             case NOTOK:
5035                 content_error (ct -> c_file, ct, "error reading from");
5036                 goto clean_up;
5037
5038             case OK:
5039                 content_error (NULLCP, ct, "premature eof");
5040                 goto clean_up;
5041
5042             default:
5043                 if (cc > len)
5044                     cc = len;
5045                 len -= cc;
5046
5047                 (void) fwrite (buffer, sizeof *buffer, cc, ce -> ce_fp);
5048                 if (ferror (ce -> ce_fp)) {
5049                     content_error (ce -> ce_file, ct, "error writing to");
5050                     goto clean_up;
5051                 }
5052         }
5053     (void) fseek (ct -> c_fp, 0L, 0);
5054
5055     if (fflush (ce -> ce_fp)) {
5056         content_error (ce -> ce_file, ct, "error writing to");
5057         goto clean_up;
5058     }
5059
5060 ready_to_go: ;
5061     (void) fseek (ce -> ce_fp, 0L, 0);
5062     *file = ce -> ce_file;
5063     return fileno (ce -> ce_fp);
5064
5065 clean_up: ;
5066     free_encoding (ct, 0);
5067
5068     return NOTOK;
5069 }
5070
5071
5072 static int  Init7Bit (ct)
5073 register CT     ct;
5074 {
5075     if (init_encoding (ct, open7Bit) == NOTOK)
5076         return NOTOK;
5077     ct -> c_cesizefnx = NULL;
5078
5079     return OK;
5080 }
5081
5082 /* \f   External */
5083
5084 static int  openExternal (ct, cb, ce, file, fd)
5085 register CT     ct;
5086 CT      cb;
5087 struct cefile *ce;
5088 char  **file;
5089 int    *fd;
5090 {
5091     char    cachefile[BUFSIZ];
5092
5093     if (ce -> ce_fp) {
5094         (void) fseek (ce -> ce_fp, 0L, 0);
5095
5096 ready_already: ;
5097         *file = ce -> ce_file, *fd = fileno (ce -> ce_fp);
5098         return DONE;
5099     }
5100
5101     if (ce -> ce_file) {
5102         if ((ce -> ce_fp = fopen (ce -> ce_file, "r")) == NULL) {
5103             content_error (ce -> ce_file, ct, "unable to fopen for reading");
5104             return NOTOK;
5105         }
5106
5107         goto ready_already;
5108     }
5109
5110     if (find_cache (ct, rcachesw, (int *) 0, cb -> c_id, cachefile) != NOTOK) {
5111         if (ce -> ce_fp = fopen (cachefile, "r")) {
5112             ce -> ce_unlink = 0;
5113             ce -> ce_file = getcpy (cachefile);
5114             goto ready_already;
5115         }
5116         else
5117             admonish (cachefile, "unable to fopen for reading");
5118     }
5119
5120     return OK;
5121 }
5122
5123 /* \f   File */
5124
5125 static int  openFile (ct, file)
5126 register CT     ct;
5127 char  **file;
5128 {
5129     int     fd,
5130             cachetype;
5131     char    cachefile[BUFSIZ];
5132     register struct exbody *e = (struct exbody *) ct -> c_ctextern;
5133     register struct cefile *ce = (struct cefile *) ct -> c_ceparams;
5134
5135     switch (openExternal (e -> eb_parent, e -> eb_content, ce, file, &fd)) {
5136         case NOTOK:
5137             return NOTOK;
5138
5139         case OK:
5140             break;
5141
5142         case DONE:
5143             return fd;
5144     }
5145
5146     if (!e -> eb_name) {
5147         content_error (NULLCP, ct, "missing name parameter");
5148         return NOTOK;
5149     }
5150
5151     ce -> ce_unlink = 0;
5152     if ((ce -> ce_fp = fopen (ce -> ce_file = getcpy (e -> eb_name), "r"))
5153             == NULL) {
5154         content_error (ce -> ce_file, ct, "unable to fopen for reading");
5155         return NOTOK;
5156     }
5157
5158     if ((!e -> eb_permission || !uleq (e -> eb_permission, "read-write"))
5159             && find_cache (NULLCT, wcachesw, &cachetype,
5160                            e -> eb_content -> c_id, cachefile) != NOTOK) {
5161         int     mask;
5162         FILE   *fp;
5163
5164         mask = umask (cachetype ? ~m_gmprot () : 0222);
5165         if (fp = fopen (cachefile, "w")) {
5166             int     cc;
5167             char    buffer[BUFSIZ];
5168             FILE   *gp = ce -> ce_fp;
5169
5170             (void) fseek (gp, 0L, 0);
5171
5172             while ((cc = fread (buffer, sizeof *buffer, sizeof buffer, gp))
5173                        > 0)
5174                 (void) fwrite (buffer, sizeof *buffer, cc, fp);
5175             (void) fflush (fp);
5176
5177             if (ferror (gp)) {
5178                 admonish (ce -> ce_file, "error reading");
5179                 (void) unlink (cachefile);
5180             }
5181             else
5182                 if (ferror (fp)) {
5183                     admonish (cachefile, "error writing");
5184                     (void) unlink (cachefile);
5185                 }
5186             (void) fclose (fp);
5187         }
5188         (void) umask (mask);
5189     }
5190
5191     (void) fseek (ce -> ce_fp, 0L, 0);
5192     *file = ce -> ce_file;
5193     return fileno (ce -> ce_fp);
5194 }
5195
5196 /* \f   FTP */
5197
5198 static int  openFTP (ct, file)
5199 register CT     ct;
5200 char  **file;
5201 {
5202     int     cachetype,
5203             caching,
5204             fd;
5205     char   *bp,
5206            *ftp,
5207            *user,
5208            *pass,
5209             buffer[BUFSIZ],
5210             cachefile[BUFSIZ];
5211     register struct exbody *e = (struct exbody *) ct -> c_ctextern;
5212     register struct cefile *ce = (struct cefile *) ct -> c_ceparams;
5213     static char   *username = NULL;
5214     static char   *password = NULL;
5215
5216     (void) sprintf (buffer, "%s-access-ftp", invo_name);
5217     if ((ftp = m_find (buffer)) && !*ftp)
5218         ftp = NULLCP;
5219 #ifndef FTP
5220     if (!ftp)
5221         return NOTOK;
5222 #endif
5223     switch (openExternal (e -> eb_parent, e -> eb_content, ce, file, &fd)) {
5224         case NOTOK:
5225             return NOTOK;
5226
5227         case OK:
5228             break;
5229
5230         case DONE:
5231             return fd;
5232     }
5233
5234     if (!e -> eb_name || !e -> eb_site) {
5235         content_error (NULLCP, ct, "missing %s parameter",
5236                        e -> eb_name ? "site": "name");
5237         return NOTOK;
5238     }
5239
5240     if (xpid) {
5241         if (xpid < 0)
5242             xpid = -xpid;
5243         (void) pidcheck (pidwait (xpid, NOTOK));
5244         xpid = 0;
5245     }
5246
5247     bp = buffer;
5248     (void) sprintf (bp, "Retrieve %s", e -> eb_name);
5249     bp += strlen (bp);
5250     if (e -> eb_partno) {
5251         (void) sprintf (bp, " (content %s)", e -> eb_partno);
5252         bp += strlen (bp);
5253     }
5254     (void) sprintf (bp, "\n    using %sFTP from site %s",
5255                     e -> eb_flags ? "anonymous " : "", e -> eb_site);
5256     bp += strlen (bp);
5257     if (e -> eb_size > 0) {
5258         (void) sprintf (bp, " (%lu octets)", e -> eb_size);
5259         bp += strlen (bp);
5260     }
5261     (void) sprintf (bp, "? ");
5262     if (!getanswer (buffer))
5263         return NOTOK;
5264
5265     if (e -> eb_flags) {
5266         user = "anonymous";
5267         (void) sprintf (pass = buffer, "%s@@%s", getusr (), LocalName ());
5268     }
5269     else {
5270         ruserpass (e -> eb_site, &username, &password);
5271         user = username, pass = password;
5272     }
5273
5274     ce -> ce_unlink = *file == NULL, caching = 0, cachefile[0] = 0;
5275     if ((!e -> eb_permission || !uleq (e -> eb_permission, "read-write"))
5276             && find_cache (NULLCT, wcachesw, &cachetype,
5277                            e -> eb_content -> c_id, cachefile) != NOTOK) {
5278         if (*file == NULL) {
5279             ce -> ce_unlink = 0;
5280             caching = 1;
5281         }
5282     }
5283
5284     if ((ce -> ce_fp = fopen (ce -> ce_file =
5285                                     add (*file ? *file
5286                                                : caching ? cachefile
5287                                                : m_scratch ("", tmp),
5288                                          NULLCP),
5289                               "w+")) == NULL) {
5290         content_error (ce -> ce_file, ct,
5291                        "unable to fopen for writing and reading");
5292         return NOTOK;
5293     }
5294
5295 #ifdef  FTP
5296     if (ftp)
5297 #endif
5298     {
5299         int     child_id,
5300                 i,
5301                 vecp;
5302         char   *vec[9];
5303
5304         vecp = 0;
5305         vec[vecp++] = r1bindex (ftp, '/');
5306         vec[vecp++] = e -> eb_site;
5307         vec[vecp++] = user;
5308         vec[vecp++] = pass;
5309         vec[vecp++] = e -> eb_dir;
5310         vec[vecp++] = e -> eb_name;
5311         vec[vecp++] = ce -> ce_file,
5312         vec[vecp++] = e -> eb_mode && uleq (e -> eb_mode, "ascii")
5313                         ? "ascii" : "binary";
5314         vec[vecp] = NULL;
5315
5316         (void) fflush (stdout);
5317
5318         for (i = 0; (child_id = vfork ()) == NOTOK && i < 5; i++)
5319             sleep (5);
5320         switch (child_id) {
5321             case NOTOK:
5322                 adios ("fork", "unable to");
5323                 /* NOTREACHED */
5324
5325             case OK:
5326                 (void) close (fileno (ce -> ce_fp));
5327                 (void) execvp (ftp, vec);
5328                 fprintf (stderr, "unable to exec ");
5329                 perror (ftp);
5330                 _exit (-1);
5331                 /* NOTREACHED */
5332
5333             default:
5334                 if (pidXwait (child_id, NULLCP)) {
5335 #ifdef  FTP
5336 losing_ftp: ;
5337 #endif
5338                     username = password = NULL;
5339                     ce -> ce_unlink = 1;
5340                     return NOTOK;
5341                 }
5342                 break;
5343         }
5344     }
5345 #ifdef  FTP
5346     else
5347         if (ftp_get (e -> eb_site, user, pass, e -> eb_dir, e -> eb_name,
5348                      ce -> ce_file,
5349                      !e -> eb_mode || uleq (e -> eb_mode, "ascii"), 0)
5350                 == NOTOK)
5351             goto losing_ftp;
5352 #endif
5353
5354     if (cachefile[0])
5355         if (caching)
5356             (void) chmod (cachefile, cachetype ? m_gmprot () : 0444);
5357         else {
5358             int     mask;
5359             FILE   *fp;
5360
5361             mask = umask (cachetype ? ~m_gmprot () : 0222);
5362             if (fp = fopen (cachefile, "w")) {
5363                 int     cc;
5364                 FILE   *gp = ce -> ce_fp;
5365
5366                 (void) fseek (gp, 0L, 0);
5367
5368                 while ((cc = fread (buffer, sizeof *buffer, sizeof buffer, gp))
5369                            > 0)
5370                     (void) fwrite (buffer, sizeof *buffer, cc, fp);
5371                 (void) fflush (fp);
5372
5373                 if (ferror (gp)) {
5374                     admonish (ce -> ce_file, "error reading");
5375                     (void) unlink (cachefile);
5376                 }
5377                 else
5378                     if (ferror (fp)) {
5379                         admonish (cachefile, "error writing");
5380                         (void) unlink (cachefile);
5381                     }
5382                 (void) fclose (fp);
5383             }
5384             (void) umask (mask);
5385         }
5386
5387     (void) fseek (ce -> ce_fp, 0L, 0);
5388     *file = ce -> ce_file;
5389     return fileno (ce -> ce_fp);
5390 }
5391
5392 /* \f   Mail */
5393
5394 static int  openMail (ct, file)
5395 register CT     ct;
5396 char  **file;
5397 {
5398     int     child_id,
5399             fd,
5400             i,
5401             vecp;
5402     char   *bp,
5403             buffer[BUFSIZ],
5404            *vec[7];
5405     register struct exbody *e = (struct exbody *) ct -> c_ctextern;
5406     register struct cefile *ce = (struct cefile *) ct -> c_ceparams;
5407
5408     switch (openExternal (e -> eb_parent, e -> eb_content, ce, file, &fd)) {
5409         case NOTOK:
5410             return NOTOK;
5411
5412         case OK:
5413             break;
5414
5415         case DONE:
5416             return fd;
5417     }
5418
5419     if (!e -> eb_server) {
5420         content_error (NULLCP, ct, "missing server parameter");
5421         return NOTOK;
5422     }
5423
5424     if (xpid) {
5425         if (xpid < 0)
5426             xpid = -xpid;
5427         (void) pidcheck (pidwait (xpid, NOTOK));
5428         xpid = 0;
5429     }
5430
5431     bp = buffer;
5432     (void) sprintf (bp, "Retrieve content");
5433     bp += strlen (bp);
5434     if (e -> eb_partno) {
5435         (void) sprintf (bp, " %s", e -> eb_partno);
5436         bp += strlen (bp);
5437     }
5438     (void) sprintf (bp, " by asking %s\n\n%s\n? ",
5439                     e -> eb_server,
5440                     e -> eb_subject ? e -> eb_subject : e -> eb_body);
5441     if (!getanswer (buffer))
5442         return NOTOK;
5443
5444     vecp = 0;
5445     vec[vecp++] = r1bindex (mailproc, '/');
5446     vec[vecp++] = e -> eb_server;
5447     vec[vecp++] = "-subject";
5448     vec[vecp++] = e -> eb_subject ? e -> eb_subject : "mail-server request";
5449     vec[vecp++] = "-body";
5450     vec[vecp++] = e -> eb_body;
5451     vec[vecp] = NULL;
5452
5453     for (i = 0; (child_id = vfork ()) == NOTOK && i < 5; i++)
5454         sleep (5);
5455     switch (child_id) {
5456         case NOTOK:
5457             advise ("fork", "unable to");
5458             return NOTOK;
5459
5460         case OK:
5461             (void) execvp (mailproc, vec);
5462             fprintf (stderr, "unable to exec ");
5463             perror (mailproc);
5464             _exit (-1);
5465             /* NOTREACHED */
5466
5467         default:
5468             if (pidXwait (child_id, NULLCP) == OK)
5469                 advise (NULLCP, "request sent");
5470             break;
5471     }
5472
5473     ce -> ce_unlink = *file == NULL;
5474     if ((ce -> ce_fp = fopen (ce -> ce_file =
5475                                     add (*file ? *file : m_scratch ("", tmp),
5476                                          NULLCP),
5477                               "w+")) == NULL) {
5478         content_error (ce -> ce_file, ct,
5479                        "unable to fopen for writing and reading");
5480         return NOTOK;
5481     }
5482     if (ct -> c_showproc)
5483         free (ct -> c_showproc);
5484     ct -> c_showproc = add ("true", NULLCP);
5485
5486     (void) fseek (ce -> ce_fp, 0L, 0);
5487     *file = ce -> ce_file;
5488     return fileno (ce -> ce_fp);
5489 }
5490
5491 /* \f   CACHE */
5492
5493 static int  find_cache (ct, policy, writing, id, buffer)
5494 CT      ct;
5495 int     policy,
5496        *writing;
5497 char   *id,
5498        *buffer;
5499 {
5500     int     status = NOTOK;
5501
5502     if (id == NULL)
5503         return NOTOK;
5504     id = trimcpy (id);
5505
5506     if (debugsw)
5507         fprintf (stderr, "find_cache %s(%d) %s %s\n",
5508                  caches[policy].sw, policy, writing ? "writing" : "reading",
5509                  id);
5510
5511     switch (policy) {
5512         case CACHE_NEVER:
5513         default:
5514             break;
5515
5516         case CACHE_ASK:
5517         case CACHE_PUBLIC:
5518             if (cache_private
5519                     && !writing
5520                     && find_cache_aux (writing ? 2 : 0, cache_private, id,
5521                                        buffer) == OK) {
5522                 if (access (buffer, 04) != NOTOK) {
5523 got_private: ;
5524                     if (writing)
5525                         *writing = 1;
5526 got_it: ; 
5527                     status = OK;
5528                     break;
5529                 }
5530             }
5531             if (cache_public
5532                     && find_cache_aux (writing ? 1 : 0, cache_public, id,
5533                                        buffer) == OK) {
5534                 if (writing || access (buffer, 04) != NOTOK) {
5535                     if (writing)
5536                         *writing = 0;
5537                     goto got_it;
5538                 }
5539             }
5540             break;
5541
5542         case CACHE_PRIVATE:
5543             if (cache_private
5544                     && find_cache_aux (writing ? 2 : 0, cache_private, id,
5545                                        buffer) == OK) {
5546                 if (writing || access (buffer, 04) != NOTOK)
5547                     goto got_private;
5548             }
5549             break;
5550
5551     }
5552
5553     if (status == OK && policy == CACHE_ASK) {
5554         char   *bp,
5555                 query[BUFSIZ];
5556
5557         if (xpid) {
5558             if (xpid < 0)
5559                 xpid = -xpid;
5560             (void) pidcheck (pidwait (xpid, NOTOK));
5561             xpid = 0;
5562         }
5563
5564         bp = query;
5565         if (writing)
5566             (void) sprintf (bp, "Make cached, publically-accessible copy");
5567         else {
5568             struct stat st;
5569
5570             (void) sprintf (bp, "Use cached copy");
5571             bp += strlen (bp);
5572             if (ct -> c_partno) {
5573                 (void) sprintf (bp, " of content %s", ct -> c_partno);
5574                 bp += strlen (bp);
5575             }
5576             (void) stat (buffer, &st);
5577             (void) sprintf (bp, " (size %lu octets)",
5578                             (unsigned long) st.st_size);
5579         }
5580         bp += strlen (bp);
5581         (void) sprintf (bp, "\n    in file %s? ", buffer);
5582         if (!getanswer (query))
5583             status = NOTOK;
5584     }
5585     if (status == OK && writing) {
5586         if (*writing && index (buffer, '/'))
5587             (void) make_intermediates (buffer);
5588         (void) unlink (buffer);
5589     }
5590
5591     free (id);
5592     return status;
5593 }
5594
5595 /* \f */
5596
5597 static int  find_cache_aux (writing, directory, id, buffer)
5598 int     writing;
5599 char   *directory,
5600        *id,
5601        *buffer;
5602 {
5603     int     mask;
5604 #ifdef  BSD42
5605     int     usemap = index (id, '/') ? 1 : 0;
5606 #else
5607     int     usemap = 1;
5608 #endif
5609     char    mapfile[BUFSIZ],
5610             mapname[BUFSIZ];
5611     FILE   *fp;
5612     static int  partno,
5613                 pid;
5614     static long clock = 0L;
5615
5616     if (debugsw)
5617         fprintf (stderr, "find_cache_aux %s usemap=%d\n", directory, usemap);
5618
5619     (void) sprintf (mapfile, "%s/cache.map", directory);
5620     if (find_cache_aux2 (mapfile, id, mapname) == OK)
5621         goto done_map;
5622
5623     if (!writing) {
5624         if (usemap)
5625             return NOTOK;
5626
5627 use_raw: ;
5628         (void) sprintf (buffer, "%s/%s", directory, id);
5629         return OK;
5630     }
5631
5632     if (!usemap && access (mapfile, 02) == NOTOK)
5633         goto use_raw;
5634
5635     if (clock != 0L) {
5636         long    now;
5637         
5638         (void) time (&now);
5639         if (now > clock)
5640             clock = 0L;
5641     }
5642     else
5643         pid = getpid ();
5644     if (clock == 0L) {
5645         (void) time (&clock);
5646         partno = 0;
5647     }
5648     else
5649         if (partno > 0xff)
5650             clock++, partno = 0;
5651
5652     (void) sprintf (mapname, "%08x%04x%02x", clock & 0xffffffff,
5653                     pid & 0xffff, partno++ & 0xff);
5654     if (debugsw)
5655         fprintf (stderr, "creating mapping %s -> %s\n", mapname, id);
5656
5657     (void) make_intermediates (mapfile);
5658     mask = umask (writing == 2 ? 0077 : 0);
5659     if (!(fp = lkfopen (mapfile, "a")) && errno == ENOENT) {
5660         int     fd = creat (mapfile, 0666);
5661
5662         if (fd != NOTOK) {
5663             (void) close (fd);
5664             fp = lkfopen (mapfile, "a");
5665         }
5666     }
5667     (void) umask (mask);
5668     if (!fp)
5669         return NOTOK;
5670     fprintf (fp, "%s: %s\n", mapname, id);
5671     (void) lkfclose (fp, mapfile);
5672
5673 done_map: ;
5674     if (*mapname == '/')
5675         (void) strcpy (buffer, mapname);
5676     else
5677         (void) sprintf (buffer, "%s/%s", directory, mapname);
5678     if (debugsw)
5679         fprintf (stderr, "use %s\n", buffer);
5680
5681     return OK;
5682 }
5683
5684 /* \f */
5685
5686 static int  find_cache_aux2 (mapfile, id, mapname)
5687 char   *mapfile,
5688        *id,
5689        *mapname;
5690 {
5691     int     state;
5692     char    buf[BUFSIZ],
5693             name[NAMESZ];
5694     FILE   *fp;
5695
5696     if (!(fp = lkfopen (mapfile, "r")))
5697         return NOTOK;
5698
5699     for (state = FLD;;) {
5700         int     result;
5701         register char  *cp,
5702                        *dp;
5703
5704         switch (state = m_getfld (state, name, buf, sizeof buf, fp)) {
5705             case FLD:
5706             case FLDPLUS:
5707             case FLDEOF:
5708                 (void) strcpy (mapname, name);
5709                 if (state != FLDPLUS)
5710                     cp = buf;
5711                 else {
5712                     cp = add (buf, NULLCP);
5713                     while (state == FLDPLUS) {
5714                         state = m_getfld (state, name, buf, sizeof buf, fp);
5715                         cp = add (buf, cp);
5716                     }
5717                 }
5718                 dp = trimcpy (cp);
5719                 if (cp != buf)
5720                     free (cp);
5721                 if (debugsw)
5722                     fprintf (stderr, "compare %s to %s <- %s\n", id, dp,
5723                              mapname);
5724                 result = strcmp (id, dp);
5725                 free (dp);
5726                 if (result == 0) {
5727                     (void) lkfclose (fp, mapfile);
5728                     return OK;
5729                 }
5730                 if (state != FLDEOF)
5731                     continue;
5732                 /* else fall... */
5733
5734             case BODY:
5735             case BODYEOF:
5736             case FILEEOF:
5737             default:
5738                 break;
5739         }
5740         break;
5741     }
5742
5743     (void) lkfclose (fp, mapfile);
5744     return NOTOK;
5745 }
5746
5747 /* \f */
5748
5749 static int  cache_content (ct)
5750 register CT    ct;
5751 {
5752     int     cachetype;
5753     char   *file,
5754             cachefile[BUFSIZ];
5755     register struct cefile *ce = (struct cefile *) ct -> c_ceparams;
5756
5757     if (!ct -> c_id) {
5758         advise (NULLCP, "no %s: field in %s", ID_FIELD, ct -> c_file);
5759         return;
5760     }
5761
5762     if (!ce) {
5763         advise (NULLCP, "unable to decode %s", ct -> c_file);
5764         return;
5765     }
5766
5767     if (ct -> c_ceopenfnx == openMail) {
5768         advise (NULLCP, "a radish may no know Greek, but I do...");
5769         return;
5770     }
5771
5772     if (find_cache (NULLCT, wcachesw != CACHE_NEVER ? wcachesw : CACHE_ASK,
5773                     &cachetype, ct -> c_id, cachefile)
5774             == NOTOK) {
5775         advise (NULLCP, "unable to cache %s's contents", ct -> c_file);
5776         return;
5777     }
5778     if (wcachesw != CACHE_NEVER && wcachesw != CACHE_ASK) {
5779         (void) fflush (stdout);
5780         fprintf (stderr, "caching message %s as file %s\n", ct -> c_file,
5781                  cachefile);
5782     }
5783
5784     if (ce -> ce_file) {
5785         int     mask = umask (cachetype ? ~m_gmprot () : 0222);
5786         FILE   *fp;
5787
5788         if (debugsw)
5789             fprintf (stderr, "caching by copying %s...\n", ce -> ce_file);
5790
5791         file = NULL;
5792         if ((*ct -> c_ceopenfnx) (ct, &file) == NOTOK)
5793             goto reset_umask;
5794
5795         if (fp = fopen (cachefile, "w")) {
5796             int     cc;
5797             char    buffer[BUFSIZ];
5798             FILE   *gp = ce -> ce_fp;
5799
5800             (void) fseek (gp, 0L, 0);
5801
5802             while ((cc = fread (buffer, sizeof *buffer, sizeof buffer, gp))
5803                        > 0)
5804                 (void) fwrite (buffer, sizeof *buffer, cc, fp);
5805             (void) fflush (fp);
5806
5807             if (ferror (gp)) {
5808                 admonish (ce -> ce_file, "error reading");
5809                 (void) unlink (cachefile);
5810             }
5811             else
5812                 if (ferror (fp)) {
5813                     admonish (cachefile, "error writing");
5814                     (void) unlink (cachefile);
5815                 }
5816             (void) fclose (fp);
5817         }
5818         else
5819             content_error (cachefile, ct, "unable to fopen for writing");
5820 reset_umask: ;
5821         (void) umask (mask);
5822     }
5823     else {
5824         if (debugsw)
5825             fprintf (stderr, "in place caching...\n");
5826
5827         file = cachefile;
5828         if ((*ct -> c_ceopenfnx) (ct, &file) != NOTOK)
5829             (void) chmod (cachefile, cachetype ? m_gmprot () : 0444);
5830     }
5831 }
5832
5833 /* \f   COMPOSITION */
5834
5835 static  char    prefix[] = "----- =_aaaaaaaaaa";
5836
5837 static  char   *free_file = NULL;
5838 static  CT      free_ct = NULL;
5839
5840
5841 static void  build_comp (file)
5842 char   *file;
5843 {
5844     int     compnum,
5845             state;
5846     char   *cp,
5847             buf[BUFSIZ],
5848             name[NAMESZ],
5849             tmpfil[BUFSIZ];
5850     struct multipart *m;
5851     register struct part **pp;
5852     CT      ct;
5853     FILE   *in,
5854            *out;
5855
5856     if ((in = fopen (file, "r")) == NULL)
5857         adios (file, "unable to open for reading");
5858
5859     (void) umask (~m_gmprot ());
5860
5861     (void) strcpy (tmpfil, m_scratch (file, invo_name));
5862     if ((out = fopen (tmpfil, "w")) == NULL)
5863         adios (tmpfil, "unable to open for writing");
5864     free_file = tmpfil;
5865
5866     for (compnum = 1, state = FLD;;) {
5867         switch (state = m_getfld (state, name, buf, sizeof buf, in)) {
5868             case FLD:
5869             case FLDPLUS:
5870             case FLDEOF:
5871                 compnum++;
5872
5873                 if (uleq (name, VRSN_FIELD))
5874                     adios (NULLCP, "draft shouldn't contain %s: field",
5875                            VRSN_FIELD);
5876
5877                 if (uleq (name, TYPE_FIELD)) {
5878                     while (state == FLDPLUS)
5879                         state = m_getfld (state, name, buf, sizeof buf, in);
5880                     goto finish_field;
5881                 }
5882
5883                 if (uleq (name, ENCODING_FIELD))
5884                     adios (NULLCP, "draft shouldn't contain %s: field",
5885                            ENCODING_FIELD);
5886
5887                 fprintf (out, "%s:%s", name, buf);
5888                 while (state == FLDPLUS) {
5889                     state = m_getfld (state, name, buf, sizeof buf, in);
5890                     (void) fputs (buf, out);
5891                 }
5892 finish_field: ;
5893                 if (state != FLDEOF)
5894                     continue;
5895                 /* else fall... */
5896
5897             case FILEEOF:
5898                 adios (NULLCP, "draft has empty body -- no directives!");
5899                 /* NOTREACHED */
5900
5901             case BODY:
5902             case BODYEOF:
5903                 (void) fseek (in, (long) (-strlen (buf)), 1);
5904                 break;
5905
5906             case LENERR:
5907             case FMTERR:
5908                 adios (NULLCP, "message format error in component #%d",
5909                        compnum);
5910
5911             default:
5912                 adios (NULLCP, "getfld() returned %d", state);
5913         }
5914         break;
5915     }
5916
5917     if ((free_ct = ct = (CT) calloc (1, sizeof *ct)) == NULL)
5918         adios (NULLCP, "out of memory");
5919     if (get_ctinfo ("multipart/mixed", ct, 0) == NOTOK)
5920         done (1);
5921     ct -> c_type = CT_MULTIPART;
5922     ct -> c_subtype = MULTI_MIXED;
5923     ct -> c_ctlistfnx = list_multi;
5924     ct -> c_ctfreefnx = free_multi;
5925     ct -> c_file = add (file, NULLCP);
5926
5927     if ((m = (struct multipart *) calloc (1, sizeof *m)) == NULL)
5928         adios (NULLCP, "out of memory");
5929     ct -> c_ctparams = (caddr_t) m;
5930
5931     pp = &m -> mp_parts;
5932     while (fgetstr (buf, sizeof buf - 1, in)) {
5933         register struct part *part;
5934         CT      p;
5935
5936         if (user_content (in, file, buf, &p) == DONE) {
5937             admonish (NULLCP, "ignoring spurious #end");
5938             continue;
5939         }
5940         if (!p)
5941             continue;
5942
5943         if ((part = (struct part *) calloc (1, sizeof *part)) == NULL)
5944             adios (NULLCP, "out of memory");
5945         *pp = part, pp = &part -> mp_next;
5946         part -> mp_part = p;
5947     }
5948
5949     (void) fclose (in);
5950
5951     if (!m -> mp_parts)
5952         adios (NULLCP, "no content directives found");
5953     if (!m -> mp_parts -> mp_next) {
5954         CT      p = m -> mp_parts -> mp_part;
5955
5956         m -> mp_parts -> mp_part = NULL;
5957         free_content (ct);
5958         free_ct = ct = p;
5959     }
5960     else
5961         set_id (ct, 1);
5962
5963     if ((cp = index (prefix, 'a')) == NULL)
5964         adios (NULLCP, "internal error(4)");
5965
5966     while (compose_content (ct) == NOTOK)
5967         if (*cp < 'z')
5968             (*cp)++;
5969         else
5970             if (*++cp == 0)
5971                 adios (NULLCP,
5972                        "giving up trying to find a unique delimiter string");
5973             else
5974                 (*cp)++;
5975
5976     fprintf (out, "%s: %s\n", VRSN_FIELD, VRSN_VALUE);
5977     (void) output_content (ct, out);
5978
5979     if (fflush (out))
5980         adios (tmpfil, "error writing to");
5981
5982     (void) fclose (out);
5983
5984     if (listsw && ct -> c_ctlistfnx) {
5985         char   *savfile;
5986
5987         if (headsw)
5988             printf (LSTFMT1, "msg", "part", "type/subtype", "size",
5989                     "description");
5990
5991                                 /* to get msgno */
5992         savfile = ct -> c_file, ct -> c_file = file;
5993         (*ct -> c_ctlistfnx) (ct, 1);
5994         ct -> c_file = savfile;
5995     }
5996
5997     free_content (ct);
5998     free_ct = NULL;
5999
6000     (void) sprintf (buf, "%s.orig", m_backup (file));
6001     if (rename (file, buf) == NOTOK)
6002         adios (buf, "unable to rename %s to", file);
6003     if (rename (tmpfil, file) == NOTOK) {
6004         advise (file, "unable to rename %s to", tmpfil);
6005         (void) rename (buf, file);
6006         done (1);
6007     }
6008     free_file = NULL;
6009
6010     done (0);
6011 }
6012
6013 /* \f */
6014
6015 static char *fgetstr (s, n, stream)
6016 char   *s;
6017 int     n;
6018 FILE   *stream;
6019 {
6020     register char *cp,
6021                   *ep;
6022
6023     for (ep = (cp = s) + n; cp < ep; ) {
6024         register int    i;
6025
6026         if (!fgets (cp, n, stream))
6027             return (cp != s ? s : NULL);
6028         if (cp == s && *cp != '#')
6029             return s;
6030
6031         cp += (i = strlen (cp)) - 1;
6032         if (i <= 1 || *cp-- != '\n' || *cp != '\\')
6033             break;
6034         *cp = 0, n -= (i - 2);
6035     }
6036
6037     return s;
6038 }
6039
6040 /* \f */
6041
6042 static int  user_content (in, file, buf, ctp)
6043 FILE   *in;
6044 char   *file,
6045        *buf;
6046 CT     *ctp;
6047 {
6048     int     extrnal,
6049             vrsn;
6050     register char  *cp,
6051                   **ap;
6052     char    buffer[BUFSIZ];
6053     struct multipart *m;
6054     register struct part **pp;
6055     struct stat st;
6056     register struct str2init *s2i;
6057     register CI     ci;
6058     register CT     ct;
6059
6060     if (buf[0] == '\n' || strcmp (buf, "#\n") == 0) {
6061         *ctp = NULL;
6062         return OK;
6063     }
6064
6065     if ((ct = (CT) calloc (1, sizeof *ct)) == NULL)
6066         adios (NULLCP, "out of memory");
6067     *ctp = ct;
6068     ci = &ct -> c_ctinfo;
6069     ct -> c_ctlistfnx = list_content;
6070     set_id (ct, 0);
6071
6072     if (buf[0] != '#' || buf[1] == '#' || buf[1] == '<') {
6073         int     headers,
6074                 inlineD;
6075         long    pos;
6076         char    content[BUFSIZ];
6077         FILE   *out;
6078
6079         ct -> c_file = add (m_tmpfil (invo_name), NULLCP);
6080         ct -> c_unlink = 1;
6081
6082         if ((out = fopen (ct -> c_file, "w")) == NULL)
6083             adios (ct -> c_file, "unable to open for writing");
6084
6085         if (buf[0] == '#' && buf[1] == '<') {
6086             (void) strcpy (content, buf + 2);
6087             inlineD = 1;
6088             goto rock_and_roll;
6089         }
6090         else
6091             inlineD = 0;
6092
6093         (void) strcpy (content, "text/plain");
6094         headers = 0;
6095         (void) strcpy (buffer, buf[0] != '#' ? buf : buf + 1);
6096         for (;;) {
6097             int     i;
6098
6099             if (headers >= 0
6100                     && uprf (buffer, DESCR_FIELD)
6101                     && buffer[i = strlen (DESCR_FIELD)] == ':') {
6102                     headers = 1;
6103
6104 again_descr: ;
6105                     ct -> c_descr = add (buffer + i + 1, ct -> c_descr);
6106                     if (!fgetstr (buffer, sizeof buffer - 1, in))
6107                         adios (NULLCP,
6108                                "end-of-file after %s: field in plaintext",
6109                                DESCR_FIELD);
6110                     switch (buffer[0]) {
6111                         case ' ':
6112                         case '\t':
6113                             i = -1;
6114                             goto again_descr;
6115
6116                         case '#':
6117                             adios (NULLCP,
6118                                    "#-directive after %s: field in plaintext",
6119                                    DESCR_FIELD);
6120                             /* NOTREACHED */
6121
6122                         default:
6123                             break;
6124                     }
6125             }
6126
6127             if (headers != 1 || buffer[0] != '\n')
6128                 (void) fputs (buffer, out);
6129 rock_and_roll: ;
6130             headers = -1;
6131
6132             pos = ftell (in);
6133             if ((cp = fgetstr (buffer, sizeof buffer - 1, in)) == NULL)
6134                 break;
6135             if (buffer[0] == '#') {
6136                 register char  *bp;
6137
6138                 if (buffer[1] != '#')
6139                     break;
6140                 for (cp = (bp = buffer) + 1; *cp; cp++)
6141                     *bp++ = *cp;
6142                 *bp = '\0';
6143             }
6144         }
6145
6146         if (listsw)
6147             ct -> c_end = ftell (out);
6148         (void) fclose (out);
6149
6150         if (get_ctinfo (content, ct, inlineD) == NOTOK)
6151             done (1);
6152         for (s2i = str2cts; s2i -> si_key; s2i++)
6153             if (uleq (ci -> ci_type, s2i -> si_key))
6154                 break;
6155         if (!s2i -> si_key && !uprf (ci -> ci_type, "X-"))
6156             s2i++;
6157         switch (ct -> c_type = s2i -> si_val) {
6158             case CT_MESSAGE:
6159                 if (uleq (ci -> ci_subtype, "rfc822")) {
6160                     ct -> c_encoding = CE_7BIT;         /* XXX */
6161                     goto call_init;
6162                 }
6163                 /* else fall... */
6164             case CT_MULTIPART:
6165                 adios (NULLCP,
6166                        "it makes sense to define a in-line %s content... NOT!",
6167                        ct -> c_type == CT_MESSAGE ? "message" : "multipart");
6168                 /* NOTREACHED */
6169
6170             default:
6171 call_init: ;
6172                 if (ct -> c_ctinitfnx = s2i -> si_init)
6173                     (void) (*ct -> c_ctinitfnx) (ct);
6174                 break;
6175         }
6176
6177         if (cp)
6178             (void) fseek (in, pos, 0);
6179         return OK;
6180     }
6181
6182     extrnal = buf[1] == '@@';
6183     if (get_ctinfo (buf + (extrnal ? 2 : 1), ct, 1) == NOTOK)
6184         done (1);
6185
6186     for (s2i = str2cts; s2i -> si_key; s2i++)
6187         if (uleq (ci -> ci_type, s2i -> si_key))
6188             break;
6189     if (s2i -> si_key) {                /* type/subtype [file] */
6190         if (!ci -> ci_subtype)
6191             adios (NULLCP, "missing subtype in \"#%s\"", ci -> ci_type);
6192
6193         switch (ct -> c_type = s2i -> si_val) {
6194             case CT_MULTIPART:
6195                 adios (NULLCP, "use \"#begin ... #end\" instead of \"#%s/%s\"",
6196                        ci -> ci_type, ci -> ci_subtype);
6197                 /* NOTREACHED */
6198
6199             case CT_MESSAGE:
6200                 if (uleq (ci -> ci_subtype, "partial"))
6201                     adios (NULLCP, "sorry, \"#%s/%s\" isn't supported",
6202                            ci -> ci_type, ci -> ci_subtype);
6203                 if (uleq (ci -> ci_subtype, "external-body"))
6204                     adios (NULLCP, "use \"#@@type/subtype ... [] ...\" instead of \"#%s/%s\"",
6205                            ci -> ci_type, ci -> ci_subtype);
6206 use_forw: ;
6207                 adios (NULLCP,
6208                        "use \"#forw [+folder] [msgs]\" instead of \"#%s/%s\"",
6209                        ci -> ci_type, ci -> ci_subtype);
6210                 /* NOTREACHED */
6211
6212             default:
6213                 if (ct -> c_ctinitfnx = s2i -> si_init)
6214                     (void) (*ct -> c_ctinitfnx) (ct);
6215                 break;
6216         }
6217
6218         if (extrnal) {
6219             register struct exbody *e;
6220             CT      p;
6221
6222             if (!ci -> ci_magic)
6223                 adios (NULLCP, "need external information for \"#@@%s/%s\"",
6224                        ci -> ci_type, ci -> ci_subtype);
6225             p = ct;
6226
6227             (void) sprintf (buffer, "message/external-body; %s",
6228                             ci -> ci_magic);
6229             free (ci -> ci_magic), ci -> ci_magic = NULL;
6230
6231             if ((ct = (CT) calloc (1, sizeof *ct)) == NULL)
6232                 adios (NULLCP, "out of memory");
6233             *ctp = ct;
6234             ci = &ct -> c_ctinfo;
6235             ct -> c_ctlistfnx = list_content;
6236             if (get_ctinfo (buffer, ct, 0) == NOTOK)
6237                 done (1);
6238             ct -> c_type = CT_MESSAGE;
6239             ct -> c_subtype = MESSAGE_EXTERNAL;
6240
6241             if ((e = (struct exbody *) calloc (1, sizeof *e)) == NULL)
6242                 adios (NULLCP, "out of memory");
6243             ct -> c_ctparams = (caddr_t) e;
6244             ct -> c_ctfreefnx = free_external;
6245
6246             e -> eb_parent = ct;
6247             e -> eb_content = p;
6248             p -> c_ctextern = (caddr_t) e;
6249
6250             ct -> c_ctlistfnx = list_external;
6251
6252             if (params_external (ct, 1) == NOTOK)
6253                 done (1);
6254
6255             return OK;
6256         }
6257
6258         if (ci -> ci_magic) {
6259             if (*ci -> ci_magic == '|' || *ci -> ci_magic == '!') {
6260                 for (cp = ci -> ci_magic + 1; isspace (*cp); cp++)
6261                     continue;
6262                 if (!*cp)
6263                     adios (NULLCP, "empty pipe command for #%s directive",
6264                            ci -> ci_type);
6265                 cp = add (cp, NULLCP);
6266                 free (ci -> ci_magic);
6267                 ci -> ci_magic = cp;
6268             }
6269             else {
6270                 if (access (ct -> c_file = ci -> ci_magic, 04) == NOTOK)
6271                     adios ("reading", "unable to access %s for", ct -> c_file);
6272                 if (listsw && stat (ct -> c_file, &st) != NOTOK)
6273                     ct -> c_end = (long) st.st_size;
6274                 ci -> ci_magic = NULL;
6275             }
6276             return OK;
6277         }
6278
6279         (void) sprintf (buffer, "%s-compose-%s/%s", invo_name, ci -> ci_type,
6280                         ci -> ci_subtype);
6281         if ((cp = m_find (buffer)) == NULL || *cp == 0) {
6282             (void) sprintf (buffer, "%s-compose-%s", invo_name, ci -> ci_type);
6283             if ((cp = m_find (buffer)) == NULL || *cp == 0) {
6284                 content_error (NULLCP, ct,
6285                                "don't know how to compose content");
6286                 done (1);
6287             }
6288         }
6289         ci -> ci_magic = add (cp, NULLCP);
6290         return OK;
6291     }
6292
6293     if (extrnal)
6294         adios (NULLCP, "externally definition not allowed for \"#%s\"",
6295                ci -> ci_type);
6296
6297     if (uleq (ci -> ci_type, "forw")) { /* #forw [+folder] [msgs] */
6298         int     msgnum;
6299         char   *folder,
6300                *arguments[MAXARGS];
6301         struct msgs *mp;
6302
6303         if (ci -> ci_magic) {
6304             ap = brkstring (ci -> ci_magic, " ", "\n");
6305             ap = copyip (ap, arguments);
6306         }
6307         else
6308             arguments[0] = "cur", arguments[1] = NULL;
6309
6310         folder = NULL;
6311         for (ap = arguments; cp = *ap; ap++)
6312             if (*cp == '+' || *cp == '@@')
6313                 if (folder)
6314                     adios (NULLCP, "only one folder per #forw directive");
6315                 else
6316                     folder = path (cp + 1, *cp == '+' ? TFOLDER : TSUBCWF);
6317         if (!folder)
6318             folder = add (m_getfolder (), NULLCP);
6319
6320         if ((mp = m_gmsg (folder)) == NULL)
6321             adios (NULLCP, "unable to read folder %s", folder);
6322         for (ap = arguments; cp = *ap; ap++)
6323             if (*cp != '+' && *cp != '@@')
6324                 if (!m_convert (mp, cp))
6325                     done (1);
6326         free (folder);
6327
6328         free_ctinfo (ct);
6329         if (mp -> numsel > 1) {
6330             if (get_ctinfo ("multipart/digest", ct, 0) == NOTOK)
6331                 done (1);
6332             ct -> c_type = CT_MULTIPART;
6333             ct -> c_subtype = MULTI_DIGEST;
6334             ct -> c_ctlistfnx = list_multi;
6335             ct -> c_ctfreefnx = free_multi;
6336
6337             if ((m = (struct multipart *) calloc (1, sizeof *m)) == NULL)
6338                 adios (NULLCP, "out of memory");
6339             ct -> c_ctparams = (caddr_t) m;
6340
6341             pp = &m -> mp_parts;
6342         }
6343         else
6344             free_content (ct);
6345         for (msgnum = mp -> lowsel; msgnum <= mp -> hghsel; msgnum++)
6346             if (mp -> msgstats[msgnum] & SELECTED) {
6347                 register struct part *part;
6348                 register CT     p;
6349
6350                 if ((p = (CT) calloc (1, sizeof *p)) == NULL)
6351                     adios (NULLCP, "out of memory");
6352                 if (get_ctinfo ("message/rfc822", p, 0) == NOTOK)
6353                     done (1);
6354                 p -> c_type = CT_MESSAGE;
6355                 p -> c_subtype = MESSAGE_RFC822;
6356                 p -> c_ctlistfnx = list_content;
6357
6358                 (void) sprintf (buffer, "%s/%d", mp -> foldpath, msgnum);
6359                 p -> c_file = add (buffer, NULLCP);
6360                 if (listsw && stat (p -> c_file, &st) != NOTOK)
6361                     p -> c_end = (long) st.st_size;
6362
6363                 if (mp -> numsel > 1) {
6364                     if ((part = (struct part *) calloc (1, sizeof *part))
6365                             == NULL)
6366                         adios (NULLCP, "out of memory");
6367                     *pp = part, pp = &part -> mp_next;
6368                     part -> mp_part = p;
6369                 }
6370                 else
6371                     *ctp = ct = p;
6372             }
6373
6374         m_fmsg (mp);
6375
6376         return OK;
6377     }
6378
6379     if (uleq (ci -> ci_type, "end")) {
6380         free_content (ct);
6381         *ctp = NULL;
6382         return DONE;
6383     }
6384
6385     if (!uleq (ci -> ci_type, "begin"))
6386         adios (NULLCP, "unknown directive \"#%s\"", ci -> ci_type);
6387
6388                                         /* #begin [ alternative | parallel ] */
6389     if (!ci -> ci_magic)
6390         cp = SubMultiPart[(vrsn = MULTI_MIXED) - 1].kv_key;
6391     else
6392         if (uleq (ci -> ci_magic, "alternative"))
6393             cp = SubMultiPart[(vrsn = MULTI_ALTERNATE) - 1].kv_key;
6394         else
6395             if (uleq (ci -> ci_magic, "parallel"))
6396                 cp = SubMultiPart[(vrsn = MULTI_PARALLEL) - 1].kv_key;
6397         else
6398             if (uprf (ci -> ci_magic, "digest"))
6399                 goto use_forw;
6400             else
6401                 cp = ci -> ci_magic, vrsn = MULTI_UNKNOWN;
6402     free_ctinfo (ct);
6403     (void) sprintf (buffer, "multipart/%s", cp);
6404     if (get_ctinfo (buffer, ct, 0) == NOTOK)
6405         done (1);
6406     ct -> c_type = CT_MULTIPART;
6407     ct -> c_subtype = vrsn;
6408     ct -> c_ctlistfnx = list_multi;
6409     ct -> c_ctfreefnx = free_multi;
6410
6411     if ((m = (struct multipart *) calloc (1, sizeof *m)) == NULL)
6412         adios (NULLCP, "out of memory");
6413     ct -> c_ctparams = (caddr_t) m;
6414
6415     pp = &m -> mp_parts;
6416     while (fgetstr (buffer, sizeof buffer - 1, in)) {
6417         register struct part *part;
6418         CT      p;
6419
6420         if (user_content (in, file, buffer, &p) == DONE) {
6421             if (!m -> mp_parts)
6422                 adios (NULLCP, "empty \"#begin ... #end\" sequence");
6423             return OK;
6424         }
6425         if (!p)
6426             continue;
6427
6428         if ((part = (struct part *) calloc (1, sizeof *part)) == NULL)
6429             adios (NULLCP, "out of memory");
6430         *pp = part, pp = &part -> mp_next;
6431         part -> mp_part = p;
6432     }
6433     admonish (NULLCP, "premature end-of-file, missing #end");
6434     return OK;
6435 }
6436
6437 /* \f */
6438
6439 static void set_id (ct, top)
6440 CT      ct;
6441 int     top;
6442 {
6443     char    msgid[BUFSIZ];
6444     static int  partno;
6445     static long clock = 0L;
6446     static char *msgfmt;
6447
6448     if (clock == 0L) {
6449         (void) time (&clock);
6450         (void) sprintf (msgid, "<%d.%ld.%%d@@%s>\n", getpid (), clock,
6451                         LocalName ());
6452         partno = 0;
6453         msgfmt = getcpy (msgid);
6454     }
6455     (void) sprintf (msgid, msgfmt, top ? 0 : ++partno);
6456     ct -> c_id = getcpy (msgid);
6457 }
6458
6459 /* \f */
6460
6461 static char ebcdicsafe[0x100] = {
6462     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
6463     0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
6464     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
6465     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
6466     0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01,
6467     0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
6468     0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
6469     0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
6470     0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
6471     0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
6472     0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
6473     0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01,
6474     0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
6475     0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
6476     0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
6477     0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
6478     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
6479     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
6480     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
6481     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
6482     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
6483     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
6484     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
6485     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
6486     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
6487     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
6488     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
6489     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
6490     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
6491     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
6492     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
6493     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
6494 };
6495
6496 static int  compose_content (ct)
6497 register CT     ct;
6498 {
6499     register char   *cp;
6500     char    buffer[BUFSIZ];
6501     register CI     ci = &ct -> c_ctinfo;
6502
6503     if (ct -> c_type == CT_MESSAGE && ct -> c_subtype == MESSAGE_EXTERNAL)
6504         return OK;
6505
6506     switch (ct -> c_type) {
6507         case CT_MULTIPART:
6508             {
6509                 int     partnum;
6510                 register char *pp;
6511                 char    partnam[BUFSIZ];
6512                 struct multipart *m = (struct multipart *) ct -> c_ctparams;
6513                 register struct part *part;
6514
6515                 if (ct -> c_partno) {
6516                     (void) sprintf (partnam, "%s.", ct -> c_partno);
6517                     pp = partnam + strlen (partnam);
6518                 }
6519                 else
6520                     pp = partnam;
6521
6522                 for (part = m -> mp_parts, partnum = 1;
6523                          part;
6524                          part = part -> mp_next, partnum++) {
6525                     register CT  p = part -> mp_part;
6526
6527                     (void) sprintf (pp, "%d", partnum);
6528                     p -> c_partno = add (partnam, NULLCP);
6529
6530                     if (compose_content (p) == NOTOK)
6531                         return NOTOK;
6532                 }
6533
6534                 if (rfc934sw && ct -> c_subtype == MULTI_DIGEST) {
6535                     int     is934 = 1;
6536
6537                     for (part = m -> mp_parts; part; part = part -> mp_next) {
6538                         register CT  p = part -> mp_part;
6539
6540                         if (p -> c_subtype != MESSAGE_RFC822) {
6541                             is934 = 0;
6542                             break;
6543                         }
6544                     }
6545
6546                     ct -> c_rfc934 = is934;
6547                     for (part = m -> mp_parts; part; part = part -> mp_next) {
6548                         register CT  p = part -> mp_part;
6549
6550                         if (p -> c_rfc934 = is934)
6551                             p -> c_end++;
6552                     }
6553                 }
6554
6555                 if (listsw) {
6556                     ct -> c_end = (partnum = strlen (prefix) + 2) + 2;
6557                     if (ct -> c_rfc934)
6558                         ct -> c_end += 1;
6559
6560                     for (part = m -> mp_parts; part; part = part -> mp_next)
6561                         ct -> c_end += part -> mp_part -> c_end + partnum;
6562                 }
6563             }
6564             break;
6565
6566
6567         default:
6568             if (!ct -> c_file) {
6569                 int     child_id,
6570                         i,
6571                         xstdout;
6572                 register char  *bp,
6573                               **ap;
6574                 char   *vec[4];
6575                 FILE   *out;
6576
6577                 if (!(cp = ci -> ci_magic))
6578                     adios (NULLCP, "internal error(5)");
6579
6580                 ct -> c_file = add (m_tmpfil (invo_name), NULLCP);
6581                 ct -> c_unlink = 1;
6582
6583                 xstdout = 0;
6584                 buffer[0] = '\0';
6585                 for (bp = buffer; *cp; cp++)
6586                     if (*cp == '%') {
6587                         switch (*++cp) {
6588                             case 'a':   /* additional arguments */
6589                                 {
6590                                     register char **ep;
6591                                     char   *s = "";
6592
6593                                     for (ap = ci -> ci_attrs, ep = ci -> ci_values;
6594                                              *ap;
6595                                              ap++, ep++) {
6596                                         (void) sprintf (bp, "%s%s=\"%s\"", s,
6597                                                         *ap, *ep);
6598                                         bp += strlen (bp);
6599                                         s = " ";
6600                                     }
6601                                 }
6602                                 break;
6603
6604                             case 'F':   /* %f, and stdout is not-redirected */
6605                                 xstdout = 1;
6606                                 /* and fall... */
6607                             case 'f':   /* filename */
6608                                 (void) sprintf (bp, "%s", ct -> c_file);
6609                                 break;
6610
6611                             case 's':   /* subtype */
6612                                 (void) strcpy (bp, ci -> ci_subtype);
6613                                 break;
6614
6615                             case '%':
6616                                 goto raw;
6617
6618                             default:
6619                                 *bp++ = *--cp;
6620                                 *bp = '\0';
6621                                 continue;
6622                         }
6623                         bp += strlen (bp);
6624                     }
6625                     else {
6626 raw: ;
6627                         *bp++ = *cp;
6628                         *bp = '\0';
6629                     }
6630
6631                 printf ("composing content %s/%s from command\n\t%s\n",
6632                         ci -> ci_type, ci -> ci_subtype, buffer);
6633                 (void) fflush (stdout);
6634
6635                 vec[0] = "/bin/sh";
6636                 vec[1] = "-c";
6637                 vec[2] = buffer;
6638                 vec[3] = NULL;
6639
6640                 if ((out = fopen (ct -> c_file, "w")) == NULL)
6641                     adios (ct -> c_file, "unable to open for writing");
6642
6643                 for (i = 0; (child_id = vfork ()) == NOTOK && i > 5; i++)
6644                     sleep (5);
6645                 switch (child_id) {
6646                     case NOTOK:
6647                         adios ("fork", "unable to fork");
6648                         /* NOTREACHED */
6649
6650                     case OK:
6651                         if (!xstdout)
6652                             (void) dup2 (fileno (out), 1);
6653                         (void) close (fileno (out));
6654                         (void) execvp ("/bin/sh", vec);
6655                         fprintf (stderr, "unable to exec ");
6656                         perror ("/bin/sh");
6657                         _exit (-1);
6658                         /* NOTREACHED */
6659
6660                    default:
6661                         (void) fclose (out);
6662                         if (pidXwait (child_id, NULLCP))
6663                             done (1);
6664                         break;
6665                 }
6666             }
6667             if (listsw && ct -> c_end == 0L) {
6668                 struct stat st;
6669
6670                 if (stat (ct -> c_file, &st) != NOTOK)
6671                     ct -> c_end = (long) st.st_size;
6672             }
6673             if (ct -> c_type != CT_TEXT && ct -> c_type != CT_APPLICATION)
6674                 break;
6675             /* else fall... */
6676
6677         case CT_MESSAGE:
6678             {
6679                 int     charset,
6680                         len,
6681                         linelen,
6682                         result;
6683                 FILE   *in;
6684
6685                 if ((in = fopen (ct -> c_file, "r")) == NULL)
6686                     adios (ct -> c_file, "unable to open for reading");
6687
6688                 len = strlen (prefix);
6689                 result = OK;
6690                 switch (ct -> c_type) {
6691                     case CT_TEXT:
6692                         charset = ct -> c_ctparams ? 0 : -1;
6693                         linelen = ct -> c_subtype == TEXT_PLAIN ? 0 : -1;
6694                         break;
6695
6696                     case CT_APPLICATION:
6697                         charset = linelen = ct -> c_encoding ? 0 : -1;
6698                         break;
6699
6700                     default:
6701                         charset = linelen = 0;
6702                         break;
6703                 }
6704                 while (fgets (buffer, sizeof buffer - 1, in)) {
6705                     if (charset == -1) {
6706                         for (cp = buffer; *cp; cp++) {
6707                             if (!isascii (*cp)) {
6708                                 charset = CHARSET_UNKNOWN;
6709                                 break;
6710                             }
6711                             if (linelen == -1
6712                                     && ebcdicsw
6713                                     && !ebcdicsafe[*cp & 0xff])
6714                                 linelen = 1;
6715                         }
6716                         if ((linelen == -1) && (cp - buffer > CPERLIN + 1))
6717                             linelen = 1;
6718                         if (result == NOTOK)
6719                             break;
6720                     }
6721                     else
6722                         if ((linelen == -1) && (strlen (buffer) > CPERLIN + 1))
6723                             linelen = 1;
6724                     if (result == NOTOK)
6725                         continue;
6726
6727                     if (linelen == -1) {
6728                         if ((cp = buffer + strlen (buffer) - 2) > buffer
6729                                 && isspace (*cp))
6730                             linelen = 1;
6731                         else
6732                             if ((*(cp = buffer) == '.')
6733                                     || (strncmp (cp, "From ",
6734                                                  sizeof "From " -1) == 0))
6735                                 linelen = 1;
6736                     }
6737
6738                     if (buffer[0] == '-' && buffer[1] == '-') {
6739                         for (cp = buffer + strlen (buffer) - 1;
6740                                  cp >= buffer;
6741                                  cp--)
6742                             if (!isspace (*cp))
6743                                 break;
6744                         *++cp = '\0';
6745                         if (strncmp (buffer + 2, prefix, len) == 0
6746                                 && isdigit (buffer[2 + len])) {
6747                             result = NOTOK;
6748                             if (charset != -1 && linelen != -1)
6749                                 break;
6750                         }
6751                     }
6752                 }
6753                 if (ct -> c_type == CT_APPLICATION && !ct -> c_encoding)
6754                     ct -> c_encoding = linelen == -1
6755                                                 && charset != CHARSET_UNKNOWN
6756                                             ? CE_7BIT 
6757                                             : ct -> c_subtype
6758                                                     != APPLICATION_POSTSCRIPT
6759                                                 ? CE_BASE64 : CE_QUOTED;
6760                 if (ct -> c_type == CT_TEXT && !ct -> c_ctparams) {
6761                     register char  **ap,
6762                                    **ep;
6763                     register struct text *t;
6764
6765                     if (charset == CHARSET_UNKNOWN && mm_charset)
6766                         charset = -2;
6767                     else
6768                         if (charset == -1)
6769                             charset = CHARSET_USASCII;
6770
6771                     if ((t = (struct text *) calloc (1, sizeof *t)) == NULL)
6772                         adios (NULLCP, "out of memory");
6773                     ct -> c_ctparams = (caddr_t) t;
6774                     for (ap = ci -> ci_attrs, ep = ci -> ci_values;
6775                              *ap;
6776                              ap++, ep++)
6777                         continue;
6778                     switch (t -> tx_charset = charset) {
6779                         case CHARSET_USASCII:
6780                             *ap = add ("charset=us-ascii", NULLCP);
6781                             break;
6782
6783                         case CHARSET_UNKNOWN:
6784                         default:
6785                             *ap = add ("charset=x-unknown", NULLCP);
6786                             break;
6787
6788                         case -2:
6789                             *ap = concat ("charset=", mm_charset, NULLCP);
6790                             break;
6791                     }
6792                     cp = index (*ap++, '=');
6793                     *ap = NULL;
6794                     *cp++ = '\0';
6795                     *ep = cp;
6796                 }
6797                 if (ct -> c_type == CT_TEXT && ct -> c_subtype != TEXT_PLAIN)
6798                     ct -> c_encoding = linelen == -1 ? CE_7BIT : CE_QUOTED;
6799
6800                 (void) fclose (in);
6801
6802                 return result;
6803             }
6804     }
6805
6806     return OK;
6807 }
6808
6809 /* \f */
6810
6811 static int  output_content (ct, out)
6812 register CT     ct;
6813 FILE   *out;
6814 {
6815     int     cc,
6816             mailbody,
6817             len;
6818     register char   **ap,
6819                     **ep;
6820     char    buffer[BUFSIZ];
6821     register CI     ci = &ct -> c_ctinfo;
6822
6823     if (ct -> c_type == CT_MULTIPART) {
6824         register char  *cp;
6825         static  int     encl = 0;
6826
6827         ap = ci -> ci_attrs, ep = ci -> ci_values;
6828
6829         (void) sprintf (buffer, "boundary=%s%d", prefix, encl++);
6830         cp = index (*ap++ = add (buffer, NULLCP), '=');
6831         *ap = NULL;
6832         *cp++ = '\0';
6833         *ep = cp;
6834     }
6835     else
6836         if (ct -> c_type == CT_MESSAGE && ct -> c_rfc934)
6837             goto rfc934_mode;
6838
6839     len = 0;
6840     fprintf (out, "%s: %s/%s", TYPE_FIELD, ci -> ci_type, ci -> ci_subtype);
6841     len += strlen (TYPE_FIELD) + 2 + strlen (ci -> ci_type)
6842                                + 1 + strlen (ci -> ci_subtype);
6843     mailbody = ct -> c_type == CT_MESSAGE
6844                 && ct -> c_subtype == MESSAGE_EXTERNAL
6845                 && ((struct exbody *) ct -> c_ctparams) -> eb_body;
6846     for (ap = ci -> ci_attrs, ep = ci -> ci_values; *ap; ap++, ep++) {
6847         if (mailbody && uleq (*ap, "body"))
6848             continue;
6849
6850         (void) putc (';', out);
6851         len++;
6852
6853         (void) sprintf (buffer, "%s=\"%s\"", *ap, *ep);
6854
6855         if (len + 1 + (cc = strlen (buffer)) >= CPERLIN) {
6856             (void) fputs ("\n\t", out);
6857             len = 8;
6858         }
6859         else {
6860             (void) putc (' ', out);
6861             len++;
6862         }
6863         fputs (buffer, out);
6864         len += cc;
6865     }
6866     if (ci -> ci_comment) {
6867         if (len + 1 + (cc = 2 + strlen (ci -> ci_comment)) >= CPERLIN) {
6868             (void) fputs ("\n\t", out);
6869             len = 8;
6870         }
6871         else {
6872             (void) putc (' ', out);
6873             len++;
6874         }
6875         fprintf (out, "(%s)", ci -> ci_comment);
6876         len += cc;
6877     }
6878     (void) putc ('\n', out);
6879     if (ct -> c_id)
6880         fprintf (out, "%s: %s", ID_FIELD, ct -> c_id);
6881     if (ct -> c_descr)
6882         fprintf (out, "%s: %s", DESCR_FIELD, ct -> c_descr);
6883
6884 rfc934_mode: ;
6885     if (ct -> c_ctextern)
6886         return OK;
6887     switch (ct -> c_type) {
6888         case CT_MULTIPART:
6889             {
6890                 struct multipart *m = (struct multipart *) ct -> c_ctparams;
6891                 register struct part *part;
6892
6893                 if (ct -> c_rfc934)
6894                     (void) putc ('\n', out);
6895
6896                 for (part = m -> mp_parts; part; part = part -> mp_next) {
6897                     register CT  p = part -> mp_part;
6898
6899                     fprintf (out, "\n--%s\n", ci -> ci_values[0]);
6900                     (void) output_content (p, out);
6901                 }
6902
6903                 fprintf (out, "\n--%s--\n", ci -> ci_values[0]);
6904             }
6905             break;
6906
6907         case CT_TEXT:
6908             if (ct -> c_ctparams
6909                             && ((struct text *) ct -> c_ctparams) -> tx_charset
6910                                         != CHARSET_USASCII) {
6911 quoted_printable: ;
6912                 if (checksw)
6913                     writeDigest (ct, out, 1);
6914                 fprintf (out, "%s: %s\n\n", ENCODING_FIELD,
6915                          "quoted-printable");
6916                 (void) writeQuoted (ct, out);
6917                 break;
6918             }
6919             if ((ct -> c_subtype != TEXT_PLAIN && ct -> c_encoding != CE_7BIT)
6920                     || checksw)
6921                 goto quoted_printable;
6922             /* else fall... */
6923
6924         case CT_MESSAGE:
6925 seven_bit: ;
6926             (void) putc ('\n', out);
6927             if (ct -> c_type == CT_MESSAGE
6928                     && ct -> c_subtype == MESSAGE_EXTERNAL) {
6929                 register struct exbody *e = (struct exbody *) ct -> c_ctparams;
6930                 
6931                 (void) output_content (e -> eb_content, out);
6932                 if (e -> eb_body) {
6933                     register char   *cp;
6934
6935                     putc ('\n', out);
6936                     for (cp = e -> eb_body; *cp; cp++) {
6937                         CT      ct2 = e -> eb_content;
6938                         CI      ci2 = &ct2 -> c_ctinfo;
6939
6940                         if (*cp == '\\')
6941                             switch (*++cp) {
6942                                 case 'I':
6943                                     if (ct2 -> c_id) {
6944                                         char *dp = trimcpy (ct2 -> c_id);
6945                                         
6946                                         (void) fputs (dp, out);
6947                                         free (dp);
6948                                     }
6949                                     continue;
6950
6951                                 case 'N':
6952                                     for (ap = ci2 -> ci_attrs,
6953                                                 ep = ci2 -> ci_values;
6954                                              *ap;
6955                                              ap++, ep++)
6956                                         if (uleq (*ap, "name")) {
6957                                             fprintf (out, "%s", *ep);
6958                                             break;
6959                                         }
6960                                     continue;
6961                                             
6962                                 case 'T':
6963                                     fprintf (out, "%s/%s", ci2 -> ci_type,
6964                                              ci2 -> ci_subtype);
6965                                     for (ap = ci2 -> ci_attrs,
6966                                                 ep = ci2 -> ci_values;
6967                                              *ap;
6968                                              ap++, ep++)
6969                                         fprintf (out, "; %s=\"%s\"", *ap, *ep);
6970                                     continue;
6971
6972                                 case 'n':
6973                                     (void) putc ('\n', out);
6974                                     continue;
6975
6976                                 case 't':
6977                                     (void) putc ('\t', out);
6978                                     continue;
6979
6980                                 case '\0':
6981                                     cp--;
6982                                     break;
6983
6984                                 case '\\':
6985                                 case '"':
6986                                     break;
6987
6988                                 default:
6989                                     (void) putc ('\\', out);
6990                                     break;
6991                             }
6992
6993                         (void) putc (*cp, out);
6994                     }
6995                     putc ('\n', out);
6996                 }
6997             }
6998             else
6999                 (void) write7Bit (ct, out);
7000             break;
7001
7002         case CT_APPLICATION:
7003             switch (ct -> c_encoding) {
7004                 case CE_7BIT:
7005                     goto seven_bit;
7006
7007                 case CE_QUOTED:
7008                     goto quoted_printable;
7009
7010                 default:
7011                     break;
7012             }
7013             /* else fall... */
7014
7015         default:
7016             if (checksw)
7017                 writeDigest (ct, out, 0);
7018             fprintf (out, "%s: %s\n\n", ENCODING_FIELD, "base64");
7019             (void) writeBase64 (ct, out);
7020             break;
7021     }
7022
7023     return OK;
7024 }
7025
7026 /* \f */
7027
7028 static int  write7Bit (ct, out)
7029 register CT     ct;
7030 FILE   *out;
7031 {
7032     char    c,
7033             buffer[BUFSIZ];
7034     FILE   *in;
7035
7036     if ((in = fopen (ct -> c_file, "r")) == NULL)
7037         adios (ct -> c_file, "unable to open for reading");
7038
7039     c = '\n';
7040     while (fgets (buffer, sizeof buffer - 1, in)) {
7041         c = buffer[strlen (buffer) - 1];
7042         (void) fputs (buffer, out);
7043     }
7044     if (c != '\n')
7045         (void) putc ('\n', out);
7046
7047     (void) fclose (in);
7048
7049     return OK;
7050 }
7051
7052 /* \f */
7053
7054 static int  writeQuoted (ct, out)
7055 register CT     ct;
7056 FILE   *out;
7057 {
7058     register char *cp;
7059     char    c,
7060             buffer[BUFSIZ];
7061     FILE   *in;
7062
7063     if ((in = fopen (ct -> c_file, "r")) == NULL)
7064         adios (ct -> c_file, "unable to open for reading");
7065
7066     while (fgets (buffer, sizeof buffer - 1, in)) {
7067         register int    n;
7068
7069         cp = buffer + strlen (buffer) - 1;
7070         if ((c = *cp) == '\n')
7071             *cp = '\0';
7072
7073         if ((*(cp = buffer) == '.')
7074                 || (strncmp (cp, "From ", sizeof "From " - 1) == 0)) {
7075             (void) fprintf (out, "=%02X", *cp++ & 0xff);
7076             n = 3;
7077         }
7078         else
7079             n = 0;
7080         for (; *cp; cp++) {
7081             if (n > CPERLIN - 3) {
7082                 (void) fputs ("=\n", out);
7083                 n = 0;
7084             }
7085
7086             switch (*cp) {
7087                 case ' ':
7088                 case '\t':
7089                     (void) putc (*cp, out);
7090                     n++;
7091                     break;
7092
7093                 default:
7094                     if (*cp < '!'
7095                             || *cp > '~'
7096                             || (ebcdicsw && !ebcdicsafe[*cp & 0xff]))
7097                         goto three_print;
7098                     (void) putc (*cp, out);
7099                     n++;
7100                     break;
7101
7102                 case '=':
7103 three_print: ;
7104                     (void) fprintf (out, "=%02X", *cp & 0xff);
7105                     n += 3;
7106                     break;
7107             }
7108         }
7109
7110         if (c == '\n') {
7111             if (cp > buffer && (*--cp == ' ' || *cp == '\t'))
7112                 (void) fputs ("=\n", out);
7113
7114             (void) putc ('\n', out);
7115         }
7116         else
7117             (void) fputs ("=\n", out);
7118     }
7119
7120     (void) fclose (in);
7121
7122     return OK;
7123 }
7124
7125 /* \f */
7126
7127 static char nib2b64[0x40+1] =
7128         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
7129
7130
7131 static int  writeBase64 (ct, out)
7132 register CT     ct;
7133 FILE   *out;
7134 {
7135     int     result;
7136     FILE   *in;
7137
7138     if ((in = fopen (ct -> c_file, "r")) == NULL)
7139         adios (ct -> c_file, "unable to open for reading");
7140
7141     result = writeBase64aux (in, out);
7142
7143     (void) fclose (in);
7144
7145     return result;
7146 }
7147
7148
7149 static int  writeBase64aux (in, out)
7150 FILE   *in,
7151        *out;
7152 {
7153     int     cc,
7154             n;
7155     char    inbuf[3];
7156
7157     n = BPERLIN;
7158     while ((cc = fread (inbuf, sizeof *inbuf, sizeof inbuf, in)) > 0) {
7159         unsigned long bits;
7160         register char *bp;
7161         char    outbuf[4];
7162
7163         if (cc < sizeof inbuf) {
7164             inbuf[2] = 0;
7165             if (cc < sizeof inbuf - 1)
7166                 inbuf[1] = 0;
7167         }
7168         bits = (inbuf[0] & 0xff) << 16;
7169         bits |= (inbuf[1] & 0xff) << 8;
7170         bits |= inbuf[2] & 0xff;
7171
7172         for (bp = outbuf + sizeof outbuf; bp > outbuf; bits >>= 6)
7173             *--bp = nib2b64[bits & 0x3f];
7174         if (cc < sizeof inbuf) {
7175             outbuf[3] = '=';
7176             if (cc < sizeof inbuf - 1)
7177                 outbuf[2] = '=';
7178         }
7179
7180         (void) fwrite (outbuf, sizeof *outbuf, sizeof outbuf, out);
7181
7182         if (cc < sizeof inbuf) {
7183             (void) putc ('\n', out);
7184             return OK;
7185         }
7186
7187         if (--n <= 0) {
7188             n = BPERLIN;
7189             (void) putc ('\n', out);
7190         }
7191     }
7192     if (n != BPERLIN)
7193         (void) putc ('\n', out);
7194
7195     return OK;
7196 }
7197
7198 /* \f */
7199
7200 static int  writeDigest (ct, out, asciiP)
7201 register CT     ct;
7202 FILE   *out;
7203 int     asciiP;
7204 {
7205     int     cc;
7206     char    buffer[BUFSIZ];
7207     register unsigned char *dp;
7208     unsigned char  digest[16];
7209     FILE   *in;
7210     MD5_CTX mdContext;
7211
7212     if ((in = fopen (ct -> c_file, "r")) == NULL)
7213         adios (ct -> c_file, "unable to open for reading");
7214
7215     MD5Init (&mdContext);
7216     if (asciiP) {
7217         while (fgets (buffer, sizeof buffer - 1, in)) {
7218             register char *cp;
7219             char    c;
7220
7221             cp = buffer + strlen (buffer) - 1;
7222             if ((c = *cp) == '\n')
7223                 *cp = '\0';
7224
7225             MD5Update (&mdContext, (unsigned char *) buffer,
7226                        (unsigned int) strlen (buffer));
7227
7228             if (c == '\n')
7229                 MD5Update (&mdContext, (unsigned char *) "\r\n", 2);
7230         }
7231     }
7232     else
7233         while ((cc = fread (buffer, sizeof *buffer, sizeof buffer, in)) > 0)
7234             MD5Update (&mdContext, (unsigned char *) buffer,
7235                        (unsigned int) cc);
7236     MD5Final (digest, &mdContext);
7237     if (debugsw) {
7238         unsigned char *ep;
7239
7240         fprintf (stderr, "MD5 digest=");
7241         for (ep = (dp = digest) + sizeof digest / sizeof digest[0];
7242                  dp < ep;
7243                  dp++)
7244             fprintf (stderr, "%02x", *dp & 0xff);
7245         fprintf (stderr, "\n");
7246     }
7247
7248     (void) fclose (in);
7249
7250     fprintf (out, "%s: ", MD5_FIELD);
7251     for (dp = digest, cc = sizeof digest / sizeof digest[0]; cc > 0; cc -= 3) {
7252         unsigned long bits;
7253         register char *bp;
7254         char outbuf[4];
7255
7256         bits = (*dp++ & 0xff) << 16;
7257         if (cc > 1) {
7258             bits |= (*dp++ & 0xff) << 8;
7259             if (cc > 2)
7260                 bits |= *dp++ & 0xff;
7261         }
7262
7263         for (bp = outbuf + sizeof outbuf; bp > outbuf; bits >>= 6)
7264             *--bp = nib2b64[bits & 0x3f];
7265         if (cc < 3) {
7266             outbuf[3] = '=';
7267             if (cc < 2)
7268                 outbuf[2] = '=';
7269         }
7270
7271         (void) fwrite (outbuf, sizeof *outbuf, sizeof outbuf, out);
7272     }
7273     fprintf (out, "\n");
7274 }
7275
7276 /* \f */
7277
7278 static int  readDigest (ct, cp)
7279 register CT     ct;
7280 register char *cp;
7281 {
7282     int     bitno,
7283             skip;
7284     unsigned long    bits;
7285     char   *bp = cp;
7286     register unsigned char *dp;
7287     unsigned char   value,
7288                    *ep,
7289                    *b = (unsigned char *) &bits,
7290                    *b1 = &b[endian > 0 ? 1 : 2],
7291                    *b2 = &b[endian > 0 ? 2 : 1],
7292                    *b3 = &b[endian > 0 ? 3 : 0];
7293
7294     bitno = 18, bits = 0L, skip = 0;
7295     for (ep = (dp = ct -> c_digest)
7296                  + sizeof ct -> c_digest / sizeof ct -> c_digest[0];
7297              *cp;
7298              cp++)
7299         switch (*cp) {
7300             default:
7301                 if (skip
7302                         || (*cp & 0x80)
7303                         || (value = b642nib[*cp & 0x7f]) > 0x3f) {
7304                     if (debugsw)
7305                         fprintf (stderr, "invalid BASE64 encoding\n");
7306                     return NOTOK;
7307                 }
7308
7309                 bits |= value << bitno;
7310 test_end: ;
7311                 if ((bitno -= 6) < 0) {
7312                     if (dp + (3 - skip) > ep)
7313                         goto invalid_digest;
7314                     *dp++ = *b1;
7315                     if (skip < 2) {
7316                         *dp++ = *b2;
7317                         if (skip < 1)
7318                             *dp++ = *b3;
7319                     }
7320                     bitno = 18, bits = 0L, skip = 0;
7321                 }
7322                 break;
7323
7324             case '=':
7325                 if (++skip > 3)
7326                     goto self_delimiting;
7327                 goto test_end;
7328         }
7329     if (bitno != 18) {
7330         if (debugsw)
7331             fprintf (stderr, "premature ending (bitno %d)\n", bitno);
7332
7333         return NOTOK;
7334     }
7335 self_delimiting: ;
7336     if (dp != ep) {
7337 invalid_digest: ;
7338         if (debugsw) {
7339             while (*cp)
7340                 cp++;
7341             fprintf (stderr, "invalid MD5 digest (got %d octets)\n",
7342                      cp - bp);
7343         }
7344
7345         return NOTOK;
7346     }
7347
7348     if (debugsw) {
7349         fprintf (stderr, "MD5 digest=");
7350         for (dp = ct -> c_digest; dp < ep; dp++)
7351             fprintf (stderr, "%02x", *dp & 0xff);
7352         fprintf (stderr, "\n");
7353     }
7354
7355     return OK;
7356 }
7357
7358 /* \f   VIAMAIL */
7359
7360 #include "../zotnet/tws.h"
7361
7362
7363 static int  via_mail (mailsw, subjsw, parmsw, descsw, cmntsw, slowsw, fromsw)
7364 char   *mailsw,
7365        *subjsw,
7366        *parmsw,
7367        *descsw,
7368        *cmntsw,
7369        *fromsw;
7370 int     slowsw;
7371 {
7372     int     nlines,
7373             nparts,
7374             status;
7375     long    pos;
7376     long    offset;
7377     char    tmpfil[BUFSIZ];
7378     struct stat st;
7379     FILE   *fp;
7380
7381     (void) umask (~m_gmprot ());
7382
7383     (void) strcpy (tmpfil, m_tmpfil (invo_name));
7384     if ((fp = fopen (tmpfil, "w+")) == NULL)
7385         adios (tmpfil, "unable to open for writing");
7386     (void) chmod (tmpfil, 0600);
7387
7388     if (!index (mailsw, '@@'))
7389         mailsw = concat (mailsw, "@@", LocalName (), NULLCP);
7390     fprintf (fp, "To: %s\n", mailsw);
7391     nlines = 1;
7392     if (subjsw)
7393         fprintf (fp, "Subject: %s\n", subjsw), nlines++;
7394     if (fromsw) {
7395         if (!index (fromsw, '@@'))
7396             fromsw = concat (fromsw, "@@", LocalName (), NULLCP);
7397         fprintf (fp, "From: %s\n", fromsw), nlines++;
7398     }
7399     fprintf (fp, "%s: %s\n", VRSN_FIELD, VRSN_VALUE), nlines++;
7400     offset = ftell (fp);
7401     fprintf (fp, "%s: application/octet-stream", TYPE_FIELD);
7402     if (parmsw)
7403         fprintf (fp, "; %s", parmsw);
7404     if (cmntsw)
7405         fprintf (fp, "\n\t(%s)", cmntsw), nlines++;
7406     if (descsw)
7407         fprintf (fp, "\n%s: %s", DESCR_FIELD, descsw), nlines++;
7408     fprintf (fp, "\n%s: %s\n\n", ENCODING_FIELD, "base64"), nlines += 2;
7409     if (fflush (fp))
7410         adios (tmpfil, "error writing to");
7411
7412     pos = ftell (fp);
7413     (void) writeBase64aux (stdin, fp);
7414     if (fflush (fp))
7415         adios (tmpfil, "error writing to");
7416
7417     if (fstat (fileno (fp), &st) == NOTOK)
7418         adios ("failed", "fstat of %s", tmpfil);
7419     nlines += (((long) st.st_size - pos) + CPERLIN) / (CPERLIN + 1);
7420     nparts = (nlines + (LPERMSG - 1)) / LPERMSG;
7421
7422     if (nparts <= 1)
7423         status = via_post (tmpfil, 0);
7424     else {
7425         int     partno;
7426         long    clock;
7427         char    buffer[BUFSIZ],
7428                 msgid[BUFSIZ];
7429
7430         if (verbosw) {
7431             printf ("sending binary image as %d partial messages\n", nparts);
7432             (void) fflush (stdout);
7433         }
7434
7435         (void) time (&clock);
7436         (void) sprintf (msgid, "<%d.%ld@@%s>", getpid (), clock, LocalName ());
7437
7438         (void) fseek (fp, offset, 0);
7439         for (partno = 1; partno <= nparts; partno++) {
7440             int     lineno;
7441             char    tmpdrf[BUFSIZ];
7442             FILE   *out;
7443
7444             (void) strcpy (tmpdrf, m_tmpfil (invo_name));
7445             if ((out = fopen (tmpdrf, "w")) == NULL)
7446                 adios (tmpdrf, "unable to open for writing");
7447             (void) chmod (tmpdrf, 0600);
7448
7449             fprintf (out, "To: %s\n", mailsw);
7450             if (subjsw)
7451                 fprintf (out, "Subject: %s\n", subjsw);
7452             fprintf (out, "%s: %s\n", VRSN_FIELD, VRSN_VALUE);
7453             fprintf (out,
7454                      "%s: message/partial; id=\"%s\";\n\tnumber=%d; total=%d\n",
7455                      TYPE_FIELD, msgid, partno, nparts);
7456             fprintf (out, "%s: part %d of %d\n\n", DESCR_FIELD, partno,
7457                      nparts);
7458
7459             if (partno == 1)
7460                 fprintf (out, "Message-ID: %s\n", msgid);
7461
7462             for (lineno = LPERMSG; lineno > 0; lineno--) {
7463                 if (!fgets (buffer, sizeof buffer, fp)) {
7464                     if (partno == nparts)
7465                         break;
7466                     adios (NULLCP, "premature eof");
7467                 }
7468
7469                 (void) fputs (buffer, out);
7470             }
7471             offset = ftell (fp);
7472
7473             if (fflush (out))
7474                 adios (tmpdrf, "error writing to");
7475
7476             (void) fclose (out);
7477
7478             status = via_post (tmpdrf, slowsw == 0);
7479             (void) unlink (tmpdrf);
7480             if (status)
7481                 break;
7482
7483             if (slowsw > 0 && partno < nparts) {
7484                 if (verbosw) {
7485                     printf ("pausing %d seconds before sending part %d...\n",
7486                             slowsw, partno + 1);
7487                     (void) fflush (stdout);
7488                 }
7489
7490                 sleep ((unsigned) slowsw);
7491             }
7492         }
7493     }
7494
7495     (void) fclose (fp);
7496     (void) unlink (tmpfil);
7497
7498     done (status ? 1 : 0);
7499 }
7500
7501 /* \f */
7502
7503 static int  via_post (file, queued)
7504 char   *file;
7505 int     queued;
7506 {
7507     int     child_id,
7508             i;
7509
7510     for (i = 0; (child_id = fork ()) == NOTOK && i < 5; i++)
7511         sleep (5);
7512     switch (child_id) {
7513         case NOTOK:
7514             adios ("fork", "unable to");
7515             /* NOTREACHED */
7516
7517         case OK:
7518             (void) execlp (postproc, r1bindex (postproc, '/'), file,
7519                            queued ? "-queued" : NULLCP, NULLCP);
7520             fprintf (stderr, "unable to exec ");
7521             perror (postproc);
7522             _exit (-1);
7523             /* NOTREACHED */
7524
7525         default:
7526             return pidXwait (child_id, postproc);
7527     }
7528 }
7529
7530 /* \f */
7531
7532 void done (status)
7533 int     status;
7534 {
7535     register CT    *ctp;
7536
7537     if (ctp = cts)
7538         for (; *ctp; ctp++)
7539             free_content (*ctp);
7540     if (free_ct)
7541         free_content (free_ct);
7542     if (free_file)
7543         (void) unlink (free_file);
7544
7545     exit (status);
7546 }
7547
7548
7549 static int  pidcheck (status)
7550 int     status;
7551 {
7552     if ((status & 0xff00) == 0xff00 || (status & 0x007f) != SIGQUIT)
7553         return status;
7554
7555     (void) unlink ("core");
7556
7557     (void) fflush (stdout);
7558
7559     (void) fflush (stderr);
7560
7561     done (1);
7562     /* NOTREACHED */
7563 }
7564 @
7565
7566
7567 2.41
7568 log
7569 @pgp fixes from mtr
7570 @
7571 text
7572 @d3 1
7573 a3 1
7574 static char ident[] = "@@(#)$Id: mhn.c,v 2.40 1995/12/06 21:03:37 jromine Exp jromine $";
7575 d1019 1
7576 a1019 1
7577     int     si_value;
7578 d1162 1
7579 a1162 1
7580                     ct -> c_type = s2i -> si_value;
7581 d1201 1
7582 a1201 1
7583                     ct -> c_encoding = s2i -> si_value;
7584 d3674 1
7585 a3674 1
7586             e -> eb_flags = s2i -> si_value;
7587 d5889 1
7588 a5889 1
7589         switch (ct -> c_type = s2i -> si_value) {
7590 d5925 1
7591 a5925 1
7592         switch (ct -> c_type = s2i -> si_value) {
7593 @
7594
7595
7596 2.40
7597 log
7598 @mhn bugfix
7599 @
7600 text
7601 @d3 1
7602 a3 1
7603 static char ident[] = "@@(#)$Id: mhn.c,v 2.39 1995/12/06 21:02:05 jromine Exp jromine $";
7604 d1093 1
7605 d1098 1
7606 d1100 1
7607 d1102 2
7608 @
7609
7610
7611 2.39
7612 log
7613 @enhancements for quoted-printable from mtr
7614 @
7615 text
7616 @d3 1
7617 a3 1
7618 static char ident[] = "@@(#)$Id: mhn.c,v 2.38 1995/12/06 20:55:31 jromine Exp jromine $";
7619 d3383 3
7620 a3385 1
7621     if (ct -> c_subtype == MULTI_ALTERNATE && m -> mp_parts -> mp_next) {
7622 @
7623
7624
7625 2.38
7626 log
7627 @fix from mtr
7628 @
7629 text
7630 @d3 1
7631 a3 1
7632 static char ident[] = "@@(#)$Id: mhn.c,v 2.37 1995/12/06 19:20:22 jromine Exp jromine $";
7633 d6452 10
7634 a6461 4
7635                     if (linelen == -1
7636                             && (cp = buffer + strlen (buffer) - 2) > buffer
7637                             && isspace (*cp))
7638                         linelen = 1;
7639 d6798 2
7640 a6799 1
7641         if (strncmp (cp = buffer, "From ", sizeof "From " - 1) == 0) {
7642 @
7643
7644
7645 2.37
7646 log
7647 @fixes from mtr
7648 @
7649 text
7650 @d3 1
7651 a3 1
7652 static char ident[] = "@@(#)$Id: mhn.c,v 2.36 1994/04/21 19:23:38 jromine Exp jromine $";
7653 a6618 4
7654                     if (p -> c_type == CT_MESSAGE
7655                             && p -> c_subtype != MESSAGE_EXTERNAL
7656                             && !p -> c_rfc934)
7657                         fprintf (out, "%s: %s\n", VRSN_FIELD, VRSN_VALUE);
7658 @
7659
7660
7661 2.36
7662 log
7663 @mhn fixes from MTR
7664 @
7665 text
7666 @d3 1
7667 a3 1
7668 static char ident[] = "@@(#)$Id: mhn.c,v 2.35 1993/10/26 22:17:44 jromine Exp jromine $";
7669 d1291 1
7670 d2130 1
7671 a2130 1
7672             if (intr != OK) {
7673 d5074 1
7674 a5074 1
7675                      e -> eb_mode && uleq (e -> eb_mode, "ascii"), 0)
7676 @
7677
7678
7679 2.35
7680 log
7681 @change to re-sync with mtr's version
7682 @
7683 text
7684 @d3 1
7685 a3 1
7686 static char ident[] = "@@(#)$Id: mhn.c,v 2.34 1993/10/26 20:15:00 jromine Exp jromine $";
7687 d2608 1
7688 d2611 1
7689 d2613 1
7690 a2613 1
7691         free (*ap);
7692 d2616 1
7693 d2619 1
7694 d2631 1
7695 d2635 1
7696 d2639 1
7697 d2645 1
7698 d2649 1
7699 d2652 1
7700 d2655 1
7701 d2659 1
7702 d2662 1
7703 d2666 1
7704 d2669 1
7705 d2675 1
7706 d2679 1
7707 d2683 1
7708 d2745 1
7709 a2745 1
7710         if (autosw && !ct -> c_storeproc && uleq (*ap, "x-name")) {
7711 d2844 1
7712 a2844 1
7713             if (autosw && !ct -> c_storeproc && uleq (*ap, "x-name")) {
7714 d4063 1
7715 a4063 1
7716         if (autosw && !ct -> c_storeproc && uleq (*ap, "x-name")) {
7717 d4445 5
7718 a4449 2
7719     if ((cp = getenv ("MM_NOASK")) && strcmp (cp, "1") == 0)
7720         nolist = 1, listsw = pausesw = 0;
7721 d6397 1
7722 a6397 3
7723             if (ct -> c_type != CT_TEXT
7724                     && !(ct -> c_type == CT_APPLICATION
7725                              && ct -> c_subtype == APPLICATION_POSTSCRIPT))
7726 d6474 4
7727 a6477 1
7728                                             ? CE_7BIT : CE_QUOTED;
7729 d6725 2
7730 a6726 2
7731             if (ct -> c_subtype == APPLICATION_POSTSCRIPT) {
7732                 if (ct -> c_encoding == CE_7BIT)
7733 d6728 6
7734 a6733 1
7735                 goto quoted_printable;
7736 @
7737
7738
7739 2.34
7740 log
7741 @fixes from mtr -- content-id?
7742 @
7743 text
7744 @d3 1
7745 a3 1
7746 static char ident[] = "@@(#)$Id: mhn.c,v 2.33 1993/10/26 20:11:27 jromine Exp jromine $";
7747 d12 1
7748 d2564 1
7749 a2564 1
7750     for (cp = file; cp = index (cp, '/'); cp++) {
7751 d3598 2
7752 a3603 3
7753
7754     unsigned long
7755             eb_size;
7756 d3922 3
7757 a3924 2
7758                         content_error (NULLCP, ct,
7759                                        "empty body for access-type=mail-server");
7760 d4682 1
7761 a4682 1
7762         
7763 d5223 1
7764 a5223 1
7765                     && find_cache_aux (writing, cache_private, id,
7766 d5235 1
7767 a5235 1
7768                     && find_cache_aux (writing, cache_public, id,
7769 d5247 1
7770 a5247 1
7771                     && find_cache_aux (writing, cache_private, id,
7772 d5301 1
7773 a5301 1
7774 int    *writing;
7775 d5306 1
7776 d5315 3
7777 d5338 16
7778 a5353 2
7779     (void) sprintf (mapname, "%s/%s", directory, invo_name);
7780     (void) strcpy (mapname, r1bindex (m_scratch (mapname, invo_name), '/'));
7781 d5355 2
7782 d5360 12
7783 a5371 1
7784     if (!(fp = fopen (mapfile, "a")))
7785 d5374 1
7786 a5374 1
7787     (void) fclose (fp);
7788 d5399 1
7789 a5399 1
7790     if (!(fp = fopen (mapfile, "r")))
7791 d5430 1
7792 a5430 1
7793                     (void) fclose (fp);
7794 d5446 1
7795 a5446 1
7796     (void) fclose (fp);
7797 d5862 5
7798 d5874 1
7799 d6032 7
7800 a6038 6
7801         if (get_ctinfo ("multipart/digest", ct, 0) == NOTOK)
7802             done (1);
7803         ct -> c_type = CT_MULTIPART;
7804         ct -> c_subtype = MULTI_DIGEST;
7805         ct -> c_ctlistfnx = list_multi;
7806         ct -> c_ctfreefnx = free_multi;
7807 d6040 3
7808 a6042 3
7809         if ((m = (struct multipart *) calloc (1, sizeof *m)) == NULL)
7810             adios (NULLCP, "out of memory");
7811         ct -> c_ctparams = (caddr_t) m;
7812 d6044 4
7813 a6047 1
7814         pp = &m -> mp_parts;
7815 d6066 9
7816 a6074 4
7817                 if ((part = (struct part *) calloc (1, sizeof *part)) == NULL)
7818                     adios (NULLCP, "out of memory");
7819                 *pp = part, pp = &part -> mp_next;
7820                 part -> mp_part = p;
7821 d6637 3
7822 d6642 30
7823 @
7824
7825
7826 2.33
7827 log
7828 @minor fixup in DESCR/ID_FIELD
7829 @
7830 text
7831 @d3 1
7832 a3 1
7833 static char ident[] = "@@(#)$Id: mhn.c,v 2.32 1993/10/26 15:56:01 jromine Exp jromine $";
7834 d1518 20
7835 a6044 1
7836
7837 d6512 1
7838 a6512 1
7839         fprintf (out, "%s", buffer);
7840 d6527 1
7841 a6527 1
7842     fprintf (out, "\n");
7843 d6543 1
7844 a6543 1
7845                     fprintf (out, "\n");
7846 d6572 2
7847 a6573 1
7848             if (ct -> c_subtype != TEXT_PLAIN && ct -> c_encoding != CE_7BIT)
7849 a6574 2
7850             if (checksw)
7851                 goto quoted_printable;
7852 d6579 1
7853 a6579 1
7854             fprintf (out, "\n");
7855 d6585 32
7856 a6616 2
7857                 if (e -> eb_body)
7858                     fprintf (out, "\n%s\n", e -> eb_body);
7859 @
7860
7861
7862 2.32
7863 log
7864 @formatting fixup (part 2)
7865 @
7866 text
7867 @d3 1
7868 a3 1
7869 static char ident[] = "@@(#)$Id: mhn.c,v 2.28 1993/10/25 19:58:19 jromine Exp jromine $";
7870 d4699 1
7871 a4699 1
7872             fprintf (ce -> ce_fp, "%s: %s", ID_FIELD, ct -> c_id);
7873 d4701 2
7874 a4702 1
7875             fprintf (ce -> ce_fp, "%s: %s", DESCR_FIELD, ct -> c_descr);
7876 @
7877
7878
7879 2.31
7880 log
7881 @fixup formatting
7882 @
7883 text
7884 @d4867 1
7885 a4867 3
7886                 (void) fclose (fp);
7887             }
7888             (void) umask (mask);
7889 d4869 2
7890 @
7891
7892
7893 2.30
7894 log
7895 @cache changes (part 2)
7896 @
7897 text
7898 @d4793 1
7899 a4793 1
7900                 ce -> ce_unlink = 0;
7901 d4795 2
7902 a4796 2
7903                 goto ready_already;
7904             }
7905 d4799 1
7906 a4799 1
7907         }
7908 d4842 2
7909 a4843 2
7910             int     mask;
7911             FILE   *fp;
7912 d4846 2
7913 a4847 2
7914             if (fp = fopen (cachefile, "w")) {
7915                 int     cc;
7916 d4851 1
7917 a4851 1
7918                 (void) fseek (gp, 0L, 0);
7919 d4855 2
7920 a4856 2
7921                     (void) fwrite (buffer, sizeof *buffer, cc, fp);
7922                 (void) fflush (fp);
7923 d4858 4
7924 a4861 4
7925                 if (ferror (gp)) {
7926                     admonish (ce -> ce_file, "error reading");
7927                     (void) unlink (cachefile);
7928                 }
7929 d4959 3
7930 a4961 4
7931             if (*file == NULL) {
7932                 ce -> ce_unlink = 0;
7933                 caching = 1;
7934             }
7935 d4963 1
7936 d5059 4
7937 a5062 4
7938                 if (ferror (fp)) {
7939                     admonish (cachefile, "error writing");
7940                     (void) unlink (cachefile);
7941                 }
7942 @
7943
7944
7945 2.29
7946 log
7947 @add -nocache, -rcache, -wcache
7948 @
7949 text
7950 @d147 7
7951 a153 3
7952 #define CACHE_ALWAYS    0
7953     "always", 0,
7954 #define CACHE_ASK       1
7955 a154 2
7956 #define CACHE_NEVER     2
7957     "never", 0,
7958 d160 1
7959 a160 1
7960 static  int     cachesw = CACHE_ASK;
7961 d173 1
7962 d182 1
7963 d190 2
7964 a191 1
7965 static  char   *cache;
7966 d318 1
7967 d330 1
7968 d352 2
7969 a353 1
7970             msgnum;
7971 d413 12
7972 d427 1
7973 a427 1
7974                     switch (cachesw = smatch (cp, caches)) {
7975 d639 6
7976 a644 1
7977     cache = cachesw != CACHE_NEVER ? m_find (buf) : NULLCP;
7978 d658 1
7979 d781 1
7980 a781 1
7981     if (!listsw && !showsw && !storesw)
7982 d817 2
7983 d831 2
7984 d838 13
7985 d862 2
7986 d896 2
7987 d949 2
7988 d2057 1
7989 a2057 1
7990                 list_content (ct, -1);
7991 a3977 1
7992
7993 a4656 3
7994     if ((len = ct -> c_end - ct -> c_begin) < 0)
7995         adios (NULLCP, "internal error(3)");
7996
7997 a4657 1
7998         int     len = 0;
7999 d4662 2
8000 d4704 3
8001 d4772 1
8002 a4772 1
8003     char   *id;
8004 d4791 2
8005 a4792 33
8006     if (xpid) {
8007         if (xpid < 0)
8008             xpid = -xpid;
8009         (void) pidcheck (pidwait (xpid, NOTOK));
8010         xpid = 0;
8011     }
8012
8013     if (cache && (id = cb -> c_id)) {
8014         char    buffer[BUFSIZ];
8015
8016         (void) sprintf (buffer, "%s/%s", cache, id = trimcpy (id));
8017         free (id);
8018
8019         id = getcpy (buffer);
8020         if (ce -> ce_fp = fopen (id, "r")) {
8021             char   *bp;
8022             struct stat st;
8023
8024             if (cachesw == CACHE_ALWAYS)
8025                 goto do_cache;
8026
8027             (void) fstat (fileno (ce -> ce_fp), &st);
8028             (void) sprintf (bp = buffer,
8029                             "Use cached copy %s of size %lu octets",
8030                             id, (unsigned long) st.st_size);
8031             bp += strlen (bp);
8032             if (ct -> c_partno) {
8033                 (void) sprintf (bp, " (content %s)", ct -> c_partno);
8034                 bp += strlen (bp);
8035             }
8036             (void) sprintf (bp, "? ");
8037             if (getanswer (buffer)) {
8038 do_cache: ;
8039 d4794 1
8040 a4794 1
8041                 ce -> ce_file = id;
8042 d4797 2
8043 a4798 2
8044
8045             (void) fclose (ce -> ce_fp), ce -> ce_fp = NULL;
8046 a4799 2
8047         free (id);
8048     }
8049 d4810 3
8050 a4812 2
8051     int     fd;
8052     char   *id;
8053 d4839 3
8054 a4841 9
8055     if (cache
8056             && (id = e -> eb_content -> c_id)
8057             && (!e -> eb_permission
8058                     || !uleq (e -> eb_permission, "read-write"))) {
8059         char    buffer[BUFSIZ];
8060
8061         (void) sprintf (buffer, "Make cached, publically-accessible copy of %s? ",
8062                         e -> eb_name);
8063         if (cachesw == CACHE_ALWAYS || getanswer (buffer)) {
8064 a4842 1
8065             char    cachefile[BUFSIZ];
8066 d4845 1
8067 a4845 4
8068             (void) sprintf (cachefile, "%s/%s", cache, id = trimcpy (id));
8069             free (id);
8070
8071             mask = umask (0022);
8072 d4848 2
8073 a4849 1
8074                 register FILE   *gp = ce -> ce_fp;
8075 d4853 2
8076 a4854 2
8077                 while ((cc = fread (buffer, sizeof *buffer, sizeof buffer,
8078                                     gp)) > 0)
8079 d4862 1
8080 a4862 1
8081
8082 a4870 1
8083     }
8084 d4883 2
8085 a4884 1
8086     int     caching,
8087 d4886 2
8088 a4887 2
8089     char   *ftp,
8090            *id,
8091 d4921 22
8092 a4942 7
8093     (void) sprintf (buffer,
8094                     e -> eb_size > 0
8095                         ? "Retrieve %s (content %s)\n    using %sFTP from site %s (%lu octets)? "
8096                         : "Retrieve %s (content %s)\n    using %sFTP from site %s? ",
8097                     e -> eb_name, e -> eb_partno,
8098                     e -> eb_flags ? "anonymous " : "",
8099                     e -> eb_site, e -> eb_size);
8100 d4956 3
8101 a4958 9
8102     if (cache
8103             && (id = e -> eb_content -> c_id)
8104             && (!e -> eb_permission
8105                     || !uleq (e -> eb_permission, "read-write"))) {
8106         (void) sprintf (buffer, "Make cached, publically-accessible copy? ");
8107         if (cachesw == CACHE_ALWAYS || getanswer (buffer)) {
8108             (void) sprintf (cachefile, "%s/%s", cache, id = trimcpy (id));
8109             free (id);
8110
8111 a4963 1
8112     }
8113 a4975 1
8114
8115 d5037 1
8116 a5037 1
8117             (void) chmod (cachefile, 0644);
8118 d5040 1
8119 a5040 1
8120             register FILE   *fp;
8121 d5042 1
8122 a5042 1
8123             mask = umask (0022);
8124 d5044 2
8125 a5045 1
8126                 register FILE   *gp = ce -> ce_fp;
8127 d5049 3
8128 a5051 2
8129                 while (fgets (buffer, sizeof buffer - 1, gp))
8130                     (void) fputs (buffer, fp);
8131 d5058 1
8132 a5058 1
8133
8134 a5081 1
8135             result,
8136 a5083 1
8137            *id,
8138 d5105 6
8139 a5110 6
8140     bp = concat ("Retrieve content ", e -> eb_partno, " by asking mailbox ",
8141                  e -> eb_server, "\n\n",
8142                  e -> eb_subject ? e -> eb_subject: e -> eb_body, "\n? ",
8143                  NULLCP);
8144     result = getanswer (bp);
8145     free (bp);
8146 d5112 11
8147 a5122 1
8148     if (!result)
8149 d5129 1
8150 a5129 15
8151     if (e -> eb_subject)
8152         vec[vecp++] = "mail-server request";
8153     else
8154         if (cache
8155                 && (id = e -> eb_content -> c_id)
8156                 && (!e -> eb_permission
8157                         || !uleq (e -> eb_permission, "read-write"))) {
8158             (void) sprintf (buffer, "cache content as %s/%s", cache,
8159                             id = trimcpy (id));
8160             free (id);
8161
8162             vec[vecp++] = buffer;
8163         }
8164         else
8165             vec[vecp++] = "mail-server request";
8166 d5170 311
8167 @
8168
8169
8170 2.28
8171 log
8172 @fixes from mtr (20-sep-93)
8173 @
8174 text
8175 @d3 1
8176 a3 1
8177 static char ident[] = "@@(#)$Id: mhn.c,v 2.27 1993/10/25 19:32:05 jromine Exp jromine $";
8178 d30 3
8179 a32 1
8180     "cache policy", 0,
8181 d34 1
8182 a34 1
8183 #define CHECKSW    3
8184 d36 1
8185 a36 1
8186 #define NCHECKSW   4
8187 d39 1
8188 a39 1
8189 #define DEBUGSW    5
8190 d42 1
8191 a42 1
8192 #define EBCDICSW   6
8193 d44 1
8194 a44 1
8195 #define NEBCDICSW  7
8196 d47 1
8197 a47 1
8198 #define FILESW   8              /* interface from show */
8199 d50 1
8200 a50 1
8201 #define FORMSW     9
8202 d53 1
8203 a53 1
8204 #define HEADSW     10
8205 d55 1
8206 a55 1
8207 #define NHEADSW   11
8208 d58 1
8209 a58 1
8210 #define LISTSW    12
8211 d60 1
8212 a60 1
8213 #define NLISTSW   13
8214 d63 1
8215 a63 1
8216 #define PARTSW    14
8217 d66 1
8218 a66 1
8219 #define PAUSESW   15
8220 d68 1
8221 a68 1
8222 #define NPAUSESW  16
8223 d71 4
8224 a74 1
8225 #define SIZESW    17
8226 d76 1
8227 a76 1
8228 #define NSIZESW   18
8229 d79 1
8230 a79 1
8231 #define RFC934SW  19
8232 d81 1
8233 a81 1
8234 #define NRFC934SW 20
8235 d84 1
8236 a84 1
8237 #define SERIALSW  21
8238 d86 1
8239 a86 1
8240 #define NSERIALSW 22
8241 d89 1
8242 a89 1
8243 #define SHOWSW    23
8244 d91 1
8245 a91 1
8246 #define NSHOWSW   24
8247 d94 1
8248 a94 1
8249 #define STORESW   25
8250 d96 1
8251 a96 1
8252 #define NSTORESW  26
8253 d99 1
8254 a99 1
8255 #define TYPESW    27
8256 d102 1
8257 a102 1
8258 #define VERBSW    28
8259 d104 1
8260 a104 1
8261 #define NVERBSW   29
8262 d106 3
8263 d110 1
8264 a110 1
8265 #define HELPSW   30
8266 d113 1
8267 a113 1
8268 #define PROGSW   31
8269 d115 1
8270 a115 1
8271 #define NPROGSW  32
8272 d118 1
8273 a118 1
8274 #define LENSW    33
8275 d120 1
8276 a120 1
8277 #define WIDSW    34
8278 d123 1
8279 a123 1
8280 #define VIAMSW   35
8281 d125 1
8282 a125 1
8283 #define VIASSW   36
8284 d127 1
8285 a127 1
8286 #define VIAPSW   37
8287 d129 1
8288 a129 1
8289 #define VIADSW   38
8290 d131 1
8291 a131 1
8292 #define VIACSW   39
8293 d133 1
8294 a133 1
8295 #define VIAZSW   40
8296 d135 1
8297 a135 1
8298 #define VIAFSW   41
8299 @
8300
8301
8302 2.27
8303 log
8304 @fixes from mtr: add MHN_SILENT, changes something in printing
8305 multi-part messages
8306 @
8307 text
8308 @d3 1
8309 a3 1
8310 static char ident[] = "@@(#)$Id: mhn.c,v 2.26 1993/09/09 22:38:43 jromine Exp jromine $";
8311 a818 4
8312             int     child_id,
8313                     i,
8314                     vecp;
8315             char   *vec[8];
8316 d846 5
8317 a850 14
8318             vecp = 0;
8319             vec[vecp++] = r1bindex (mhlproc, '/');
8320             vec[vecp++] = "-form";
8321             vec[vecp++] = formsw;
8322             vec[vecp++] = "-nobody";
8323             vec[vecp++] = ct -> c_file;
8324             if (nomore)
8325                 vec[vecp++] = "-nomoreproc";
8326             else
8327                 if (progsw) {
8328                     vec[vecp++] = "-moreproc";
8329                     vec[vecp++] = progsw;
8330                 }
8331             vec[vecp] = NULL;
8332 d852 14
8333 a865 8
8334             (void) fflush (stdout);
8335
8336             for (i = 0; (child_id = vfork ()) == NOTOK && i < 5; i++)
8337                 sleep (5);
8338             switch (child_id) {
8339                 case NOTOK:
8340                     adios ("fork", "unable to");
8341                     /* NOTREACHED */
8342 d867 1
8343 a867 6
8344                 case OK:
8345                     (void) execvp (mhlproc, vec);
8346                     fprintf (stderr, "unable to exec ");
8347                     perror (mhlproc);
8348                     _exit (-1);
8349                     /* NOTREACHED */
8350 d869 18
8351 a886 3
8352                 default:
8353                     xpid = -child_id;
8354                     break;
8355 d888 2
8356 d4336 1
8357 d4350 1
8358 a4350 1
8359     if (getenv ("MHN_SILENT"))
8360 @
8361
8362
8363 2.26
8364 log
8365 @fixes from mtr
8366 @
8367 text
8368 @d3 1
8369 a3 1
8370 static char ident[] = "@@(#)$Id: mhn.c,v 2.25 1993/09/01 21:46:58 jromine Exp jromine $";
8371 d157 1
8372 d1916 1
8373 a1916 1
8374                     xlist = 1;
8375 d1994 4
8376 a1997 1
8377             (*ct -> c_ctlistfnx) (ct, -1);
8378 d3040 1
8379 a3040 1
8380                     xlist = 1;
8381 d4343 3
8382 d4597 46
8383 @
8384
8385
8386 2.25
8387 log
8388 @fix from mrose for quoted-printable 8-bit chars
8389 @
8390 text
8391 @d3 1
8392 a3 1
8393 static char ident[] = "@@(#)$Id: mhn.c,v 2.24 1993/09/01 20:50:03 jromine Exp jromine $";
8394 d302 4
8395 a305 4
8396 static CT get_content ();
8397 static int list_content (), show_content (), store_content ();
8398 static int user_content(), compose_content(), output_content();
8399 static void free_content (), flush_errors ();
8400 d313 1
8401 a313 1
8402 static int   init_encoding(), type_ok(), copy_some_headers(), set_endian();
8403 d315 1
8404 a315 1
8405 static int   write7Bit(), writeQuoted(), writeBase64(), writeBase64aux();
8406 d317 1
8407 a317 1
8408 static int   via_mail(), via_post(), pidcheck();
8409 d760 1
8410 a760 1
8411         if (type_ok (ct)
8412 d777 1
8413 a777 1
8414             if (type_ok (ct) && ct -> c_ctlistfnx) {
8415 d789 1
8416 a789 1
8417             if (type_ok (ct) && ct -> c_ctstorefnx) {
8418 d805 1
8419 a805 1
8420             if (type_ok (ct) && ct -> c_ctlistfnx) {
8421 d829 1
8422 a829 1
8423             if (!type_ok (ct))
8424 d1805 1
8425 a1805 1
8426 static int  show_content_aux ();
8427 d1807 1
8428 d1842 1
8429 a1842 3
8430     int     child_id,
8431             fd,
8432             i,
8433 d1849 1
8434 a1849 3
8435            *vec[4],
8436             buffer[BUFSIZ],
8437             exec[BUFSIZ + sizeof "exec "];
8438 d1890 9
8439 d1943 1
8440 d1945 3
8441 d1949 20
8442 d2087 2
8443 a2088 1
8444             (void) (*ct -> c_ceclosefnx) (ct);
8445 d2249 8
8446 a2256 17
8447 /*
8448     if (debugsw) {
8449  */
8450         (void) fflush (stdout);
8451
8452         fprintf (stderr, "storing message %s", ct -> c_file);
8453         if (ct -> c_partno)
8454             fprintf (stderr, " part %s", ct -> c_partno);
8455         fprintf (stderr, " as file %s\n",
8456                  strncmp (ct -> c_storage, cwd, cwdlen)
8457                         || ct -> c_storage[cwdlen] != '/'
8458                     ? ct -> c_storage
8459                     : ct -> c_storage + cwdlen + 1);
8460 /*
8461     }
8462  */
8463
8464 d2585 1
8465 a2585 1
8466 static int  part_ok (ct)
8467 d2587 1
8468 d2591 2
8469 a2592 1
8470     if (ct -> c_type == CT_MULTIPART || npart == 0)
8471 d2604 1
8472 a2604 1
8473 static int  type_ok (ct)
8474 d2606 1
8475 d2612 2
8476 a2613 1
8477     if (ct -> c_type == CT_MULTIPART || ntype == 0)
8478 d2786 1
8479 a2786 1
8480         if (part_ok (p) && type_ok (p) && p -> c_ctlistfnx)
8481 d2834 1
8482 a2834 1
8483     result = OK;
8484 d2838 5
8485 a2842 4
8486         if (part_ok (p)
8487                 && type_ok (p)
8488                 && p -> c_ctshowfnx) {
8489             switch ((*p -> c_ctshowfnx) (p, nowserial, nowalternate)) {
8490 d2856 1
8491 a2856 1
8492                     if (alternate)
8493 d2858 3
8494 d2928 142
8495 d3084 2
8496 a3085 2
8497         if (part_ok (p)
8498                 && type_ok (p)
8499 d3185 2
8500 a3186 1
8501     ct -> c_ctshowfnx = show_multi;
8502 d3658 1
8503 a3658 1
8504     if (!type_ok (p))
8505 d3676 1
8506 a3676 1
8507     if (!type_ok (p))
8508 d5221 2
8509 d5331 1
8510 d5461 1
8511 a5473 1
8512             char    msgid[BUFSIZ];
8513 a5475 3
8514             static int  partno;
8515             static long clock = 0L;
8516             static char *msgfmt;
8517 a5509 11
8518             if (clock == 0L) {
8519                 (void) time (&clock);
8520                 (void) sprintf (msgid, "<%d.%ld.%%d@@%s>\n", getpid (), clock,
8521                                 LocalName ());
8522                 partno = 0;
8523                 msgfmt = getcpy (msgid);
8524             }
8525
8526             (void) sprintf (msgid, msgfmt, ++partno);
8527             p -> c_id = getcpy (msgid);
8528
8529 d5635 14
8530 a5648 3
8531     vrsn = !ci -> ci_magic ? MULTI_MIXED
8532                 : uprf (ci -> ci_magic, "alt") ? MULTI_ALTERNATE
8533                                                : MULTI_PARALLEL;
8534 d5650 1
8535 a5650 1
8536     (void) sprintf (buffer, "multipart/%s", SubMultiPart[vrsn - 1].kv_key);
8537 d5682 22
8538 @
8539
8540
8541 2.24
8542 log
8543 @document -file
8544 @
8545 text
8546 @d3 1
8547 a3 1
8548 static char ident[] = "@@(#)$Id: mhn.c,v 2.23 1993/08/25 17:26:22 jromine Exp jromine $";
8549 d6075 3
8550 a6077 1
8551                     if (ebcdicsw && !ebcdicsafe[*cp & 0xff])
8552 @
8553
8554
8555 2.23
8556 log
8557 @off_t fixes for BSD44
8558 @
8559 text
8560 @d3 1
8561 a3 1
8562 static char ident[] = "@@(#)$Id: mhn.c,v 2.22 1993/08/20 15:52:01 jromine Exp jromine $";
8563 d45 4
8564 a48 1
8565 #define FORMSW     8
8566 d51 1
8567 a51 1
8568 #define HEADSW     9
8569 d53 1
8570 a53 1
8571 #define NHEADSW   10
8572 d56 1
8573 a56 1
8574 #define LISTSW    11
8575 d58 1
8576 a58 1
8577 #define NLISTSW   12
8578 d61 1
8579 a61 1
8580 #define PARTSW    13
8581 d64 1
8582 a64 1
8583 #define PAUSESW   14
8584 d66 1
8585 a66 1
8586 #define NPAUSESW  15
8587 d69 1
8588 a69 1
8589 #define SIZESW    16
8590 d71 1
8591 a71 1
8592 #define NSIZESW   17
8593 d74 1
8594 a74 1
8595 #define RFC934SW  18
8596 d76 1
8597 a76 1
8598 #define NRFC934SW 19
8599 d79 1
8600 a79 1
8601 #define SERIALSW  20
8602 d81 1
8603 a81 1
8604 #define NSERIALSW 21
8605 d84 1
8606 a84 1
8607 #define SHOWSW    22
8608 d86 1
8609 a86 1
8610 #define NSHOWSW   23
8611 d89 1
8612 a89 1
8613 #define STORESW   24
8614 d91 1
8615 a91 1
8616 #define NSTORESW  25
8617 d94 1
8618 a94 1
8619 #define TYPESW    26
8620 d97 1
8621 a97 1
8622 #define VERBSW    27
8623 d99 1
8624 a99 1
8625 #define NVERBSW   28
8626 d102 1
8627 a102 1
8628 #define HELPSW   29
8629 d105 1
8630 a105 1
8631 #define PROGSW   30
8632 d107 1
8633 a107 1
8634 #define NPROGSW  31
8635 d110 1
8636 a110 1
8637 #define LENSW    32
8638 d112 1
8639 a112 1
8640 #define WIDSW    33
8641 a113 3
8642
8643 #define FILESW   34             /* interface from show */
8644     "file file", -4,
8645 @
8646
8647
8648 2.22
8649 log
8650 @fixes from mtr:
8651 added "-cache policy" switch
8652 added "-[no]pause" switch
8653 remove application/oda content-type (change in MIME standard)
8654 add subject=/size= for external-parts (change in MIME standard)
8655 @
8656 text
8657 @d3 1
8658 a3 1
8659 static char ident[] = "@@(#)$Id: mhn.c,v 2.21 1992/12/15 00:20:22 jromine Exp jromine $";
8660 d186 1
8661 d189 1
8662 d3893 1
8663 a3893 1
8664         return st.st_size;
8665 d3896 1
8666 a3896 1
8667         return stat (ce -> ce_file, &st) != NOTOK ? st.st_size : 0L;
8668 d3905 1
8669 a3905 1
8670     size = fstat (fd, &st) != NOTOK ? st.st_size : 0L;
8671 d4038 1
8672 a4038 1
8673     (void) lseek (fd = fileno (ct -> c_fp), ct -> c_begin, 0);
8674 d4066 1
8675 a4066 1
8676                                              lseek (fd, 0L, 1) - (ep - cp),
8677 d4423 1
8678 a4423 1
8679     (void) lseek (fd = fileno (ct -> c_fp), ct -> c_begin, 0);
8680 d5366 1
8681 a5366 1
8682                     ct -> c_end = st.st_size;
8683 d5450 1
8684 a5450 1
8685                     p -> c_end = st.st_size;
8686 d5723 1
8687 a5723 1
8688                     ct -> c_end = st.st_size;
8689 d6398 1
8690 a6398 1
8691     nlines += ((st.st_size - pos) + CPERLIN) / (CPERLIN + 1);
8692 @
8693
8694
8695 2.21
8696 log
8697 @endif sugar
8698 @
8699 text
8700 @d3 1
8701 a3 1
8702 static char ident[] = "@@(#)$Id: mhn.c,v 2.20 1992/12/14 17:10:25 jromine Exp jromine $";
8703 d24 1
8704 a24 1
8705 #define AUTOSW    0
8706 d26 1
8707 a26 1
8708 #define NAUTOSW   1
8709 d29 9
8710 a37 1
8711 #define DEBUGSW   2
8712 d40 1
8713 a40 1
8714 #define EBCDICSW  3
8715 d42 1
8716 a42 1
8717 #define NEBCDICSW 4
8718 d45 1
8719 a45 1
8720 #define FORMSW    5
8721 d48 1
8722 a48 1
8723 #define HEADSW    6
8724 d50 1
8725 a50 1
8726 #define NHEADSW   7
8727 d53 1
8728 a53 1
8729 #define LISTSW    8
8730 d55 1
8731 a55 1
8732 #define NLISTSW   9
8733 d58 1
8734 a58 1
8735 #define PARTSW   10
8736 d61 6
8737 a66 1
8738 #define SIZESW   11
8739 d68 1
8740 a68 1
8741 #define NSIZESW  12
8742 d71 1
8743 a71 1
8744 #define RFC934SW 13
8745 d73 1
8746 a73 1
8747 #define NRFC934SW 14
8748 d76 1
8749 a76 1
8750 #define SERIALSW 15
8751 d78 1
8752 a78 1
8753 #define NSERIALSW 16
8754 d81 1
8755 a81 1
8756 #define SHOWSW   17
8757 d83 1
8758 a83 1
8759 #define NSHOWSW  18
8760 d86 1
8761 a86 1
8762 #define STORESW  19
8763 d88 1
8764 a88 1
8765 #define NSTORESW 20
8766 d91 1
8767 a91 1
8768 #define TYPESW   21
8769 d94 1
8770 a94 1
8771 #define VERBSW   22
8772 d96 1
8773 a96 1
8774 #define NVERBSW  23
8775 d99 1
8776 a99 1
8777 #define HELPSW   24
8778 d102 1
8779 a102 1
8780 #define PROGSW   25
8781 d104 1
8782 a104 1
8783 #define NPROGSW  26
8784 d107 1
8785 a107 1
8786 #define LENSW    27
8787 d109 1
8788 a109 1
8789 #define WIDSW    28
8790 d112 1
8791 a112 1
8792 #define FILESW   29             /* interface from show */
8793 d115 1
8794 a115 1
8795 #define VIAMSW   30
8796 d117 1
8797 a117 1
8798 #define VIASSW   31
8799 d119 1
8800 a119 1
8801 #define VIAPSW   32
8802 d121 1
8803 a121 1
8804 #define VIADSW   33
8805 d123 1
8806 a123 1
8807 #define VIACSW   34
8808 d125 1
8809 a125 1
8810 #define VIAZSW   35
8811 d127 1
8812 a127 1
8813 #define VIAFSW   36
8814 d138 11
8815 d150 2
8816 d160 1
8817 d249 1
8818 a249 1
8819     char   *c_storeproc;        /* default, if not in profile */
8820 d283 2
8821 d312 1
8822 d314 1
8823 d393 21
8824 d457 7
8825 d589 1
8826 a589 1
8827         if (f2 || f3 || f4 || f5 || f6)
8828 d608 1
8829 a608 1
8830     cache = m_find (buf);
8831 d879 1
8832 a879 1
8833                     xpid = child_id;
8834 d958 2
8835 a959 1
8836 static int InitApplication (), InitMessage (), InitMultiPart (), InitText ();
8837 d964 2
8838 a965 2
8839     "audio",        CT_AUDIO,       NULL,
8840     "image",        CT_IMAGE,       NULL,
8841 d969 1
8842 a969 1
8843     "video",        CT_VIDEO,       NULL,
8844 d1015 4
8845 a1018 1
8846                     register char  *cp;
8847 a1026 2
8848                         char   *dp = trimcpy (cp);
8849
8850 d1029 1
8851 a1029 1
8852                                 ct -> c_file, VRSN_FIELD, dp);
8853 a1035 1
8854 #ifdef  whocares
8855 d1038 12
8856 d1052 6
8857 a1057 6
8858                     c = *dp, *dp = NULL;
8859                     if (!uleq (cp, VRSN_VALUE)) {
8860                         if (!isspace (c))
8861                             *dp = c;
8862                         advise (NULLCP,
8863                                 "message %s has unsupported value for %s: field (%s)",
8864 a1058 4
8865                         goto out;
8866                     }
8867                     *dp = c;
8868 #endif
8869 d1154 53
8870 d1301 1
8871 a1301 1
8872     if (*cp == '(' && get_comment (ct, &cp) == NOTOK)
8873 d1323 1
8874 a1323 1
8875     if (*cp == '(' && get_comment (ct, &cp) == NOTOK)
8876 d1336 1
8877 a1336 1
8878     if (*cp == '(' && get_comment (ct, &cp) == NOTOK)
8879 d1360 1
8880 a1360 1
8881     if (*cp == '(' && get_comment (ct, &cp) == NOTOK)
8882 d1379 1
8883 a1379 1
8884         if (*cp == '(' && get_comment (ct, &cp) == NOTOK)
8885 d1449 1
8886 a1449 1
8887         if (*cp == '(' && get_comment (ct, &cp) == NOTOK)
8888 d1489 1
8889 a1489 1
8890 static int  get_comment (ct, ap)
8891 d1492 1
8892 d1511 1
8893 a1511 1
8894                         ct -> c_file, TYPE_FIELD);
8895 d1538 7
8896 a1544 3
8897     if (dp = ci -> ci_comment) {
8898         ci -> ci_comment = concat (dp, " ", buffer, NULLCP);
8899         free (dp);
8900 a1545 2
8901     else
8902         ci -> ci_comment = add (buffer, NULLCP);
8903 d1628 1
8904 a1628 1
8905         fprintf (stderr, "  %s:%s", VRSN_FIELD, ct -> c_vrsn);
8906 d1903 1
8907 a1903 1
8908                     xpause = 1;
8909 d1950 3
8910 a1952 1
8911     if (xtty && xpid) {
8912 d2233 4
8913 d2367 1
8914 d2412 3
8915 a2414 1
8916                 if (uprf (name, XXX_FIELD_PRF) || uleq (name, "Message-ID")) {
8917 d2447 40
8918 d2603 23
8919 d2688 1
8920 a2688 1
8921         if (uleq (*ap, "charset")) {
8922 a2708 2
8923             
8924             break;
8925 d2710 3
8926 d2714 8
8927 d3338 1
8928 d3421 4
8929 d3458 2
8930 d3742 1
8931 a3742 2
8932 #define APPLICATION_ODA         0x02
8933 #define APPLICATION_POSTSCRIPT  0x03
8934 a3764 1
8935     "oda",                APPLICATION_ODA,
8936 d3783 3
8937 a3785 4
8938     if (autosw && !ct -> c_storeproc)
8939         for (ap = ci -> ci_attrs, ep = ci -> ci_values; *ap; ap++, ep++)
8940             if (uleq (*ap, "name")) {
8941                 register char   *cp;
8942 d3787 7
8943 a3793 8
8944                 if (*(cp = *ep) != '/'
8945                         && *cp != '.'
8946                         && *cp != '|'
8947                         && *cp != '!'
8948                         && !index (cp, '%'))
8949                     ct -> c_storeproc = add (cp, NULLCP);
8950                 break;
8951             }
8952 d3809 1
8953 a3809 1
8954             if (uleq (*ap, "conversions")
8955 d3836 3
8956 d3987 1
8957 d4001 1
8958 d4033 3
8959 d4075 2
8960 d4079 3
8961 a4081 1
8962                                     if (skip < 1)
8963 d4083 3
8964 d4118 13
8965 d4193 1
8966 d4201 1
8967 d4233 3
8968 d4269 2
8969 d4276 3
8970 d4315 6
8971 d4348 13
8972 d4474 1
8973 a4474 1
8974 static int  openExternal (ct, ce, file, fd)
8975 d4476 1
8976 d4501 2
8977 d4507 1
8978 a4507 1
8979     if (cache && (id = ct -> c_id)) {
8980 d4515 1
8981 d4518 3
8982 d4522 9
8983 a4530 4
8984             (void) sprintf (buffer,
8985                             "Use cached copy %s of size %lu octets (content %s)? ",
8986                             id, (unsigned long) st.st_size,
8987                             ct -> c_partno);
8988 d4532 1
8989 d4557 1
8990 a4557 1
8991     switch (openExternal (e -> eb_parent, ce, file, &fd)) {
8992 d4581 1
8993 a4581 1
8994             && (id = e -> eb_parent -> c_id)
8995 d4588 1
8996 a4588 1
8997         if (getanswer (buffer)) {
8998 d4598 1
8999 d4603 3
9000 a4605 2
9001                 while (fgets (buffer, sizeof buffer - 1, gp))
9002                     (void) fputs (buffer, fp);
9003 d4654 1
9004 a4654 1
9005     switch (openExternal (e -> eb_parent, ce, file, &fd)) {
9006 d4692 1
9007 a4692 1
9008             && (id = e -> eb_parent -> c_id)
9009 d4696 1
9010 a4696 1
9011         if (getanswer (buffer)) {
9012 d4832 1
9013 a4832 1
9014     switch (openExternal (e -> eb_parent, ce, file, &fd)) {
9015 d4849 3
9016 a4851 1
9017                  e -> eb_server, "\n\n", e -> eb_body, "\n? ", NULLCP);
9018 d4862 10
9019 a4871 7
9020     if (cache
9021             && (id = e -> eb_parent -> c_id)
9022             && (!e -> eb_permission
9023                     || !uleq (e -> eb_permission, "read-write"))) {
9024         (void) sprintf (buffer, "cache content as %s/%s", cache,
9025                         id = trimcpy (id));
9026         free (id);
9027 d4873 4
9028 a4876 4
9029         vec[vecp++] = buffer;
9030     }
9031     else
9032         vec[vecp++] = "mail-server request";
9033 d5344 1
9034 a5344 1
9035             ct -> c_id = getcpy (msgid);
9036 d5511 35
9037 d5745 1
9038 a5745 1
9039                         linelen = 0;
9040 d5758 1
9041 a5758 1
9042                         for (cp = buffer; *cp; cp++)
9043 d5763 5
9044 d5779 5
9045 d5840 2
9046 d5955 1
9047 a5955 2
9048             if (ct -> c_subtype != TEXT_PLAIN
9049                     || (ct -> c_ctparams
9050 d5957 1
9051 a5957 1
9052                                         != CHARSET_USASCII)) {
9053 d5959 2
9054 d5966 4
9055 d5996 2
9056 d6072 2
9057 a6073 3
9058                 case '@@':
9059                 case '`':
9060                     if (ebcdicsw)
9061 a6074 1
9062 one_print: ;
9063 a6078 12
9064                 default:
9065                     if (('!' <= *cp && *cp <= '$')
9066                             || ('[' <= *cp && *cp <= '^')
9067                             || ('{' <= *cp && *cp <= '~')) {
9068                         if (ebcdicsw)
9069                             goto three_print;
9070                         goto one_print;
9071                     }
9072
9073                     if ('%' <= *cp && *cp <= 'z')
9074                         goto one_print;
9075                     /* else fall... */
9076 d6104 1
9077 a6104 1
9078 static char nib2b64[0x40f] =
9079 d6175 160
9080 d6353 1
9081 d6377 1
9082 d6400 1
9083 a6400 1
9084         status = via_post (tmpfil);
9085 d6406 1
9086 a6406 1
9087         
9088 d6415 1
9089 a6415 5
9090         (void) fseek (fp, 0L, 0);
9091         if (!fgets (buffer, sizeof buffer, fp)
9092                 || !fgets (buffer, sizeof buffer, fp)
9093                 || (subjsw && !fgets (buffer, sizeof buffer, fp)))
9094             adios (NULLCP, "premature eof");
9095 d6448 1
9096 d6455 6
9097 a6460 1
9098             if (slowsw > 0 && 1 < partno && partno < nparts) {
9099 d6463 1
9100 a6463 1
9101                             slowsw, partno);
9102 a6468 5
9103
9104             status = via_post (tmpdrf);
9105             (void) unlink (tmpdrf);
9106             if (status)
9107                 break;
9108 d6480 1
9109 a6480 1
9110 static int  via_post (file)
9111 d6482 1
9112 d6495 2
9113 a6496 1
9114             (void) execlp (postproc, r1bindex (postproc, '/'), file, NULLCP);
9115 @
9116
9117
9118 2.20
9119 log
9120 @WAITINT ifdefs
9121 @
9122 text
9123 @d3 2
9124 a4 2
9125 static char ident[] = "@@(#)$Id: mhn.c,v 2.19 1992/12/10 22:27:15 jromine Exp jromine $";
9126 #endif  lint
9127 @
9128
9129
9130 2.19
9131 log
9132 @fix from mtr
9133 @
9134 text
9135 @d3 1
9136 a3 1
9137 static char ident[] = "@@(#)$Id: mhn.c,v 2.18 1992/12/09 19:23:22 jromine Exp jromine $";
9138 d761 3
9139 a763 1
9140 #ifndef BSD42
9141 a764 2
9142 #else
9143             union wait status;
9144 d834 3
9145 a836 1
9146 #ifndef BSD42
9147 a837 2
9148 #else
9149                 (void) pidcheck (status.w_status);
9150 d2641 3
9151 a2643 1
9152 #ifndef BSD42
9153 a2644 2
9154 #else
9155         union wait status;
9156 d2659 3
9157 a2661 1
9158 #ifndef BSD42
9159 a2662 2
9160 #else
9161             (void) pidcheck (status.w_status);
9162 @
9163
9164
9165 2.18
9166 log
9167 @fix from mtr
9168 @
9169 text
9170 @d3 1
9171 a3 1
9172 static char ident[] = "@@(#)$Id: mhn.c,v 2.17 1992/12/03 21:58:18 jromine Exp jromine $";
9173 d1086 1
9174 d1091 1
9175 @
9176
9177
9178 2.17
9179 log
9180 @ignore return value of vsprintf()
9181 @
9182 text
9183 @d3 1
9184 a3 1
9185 static char ident[] = "@@(#)$Id: mhn.c,v 2.16 1992/12/02 18:50:39 jromine Exp jromine $";
9186 d4481 1
9187 @
9188
9189
9190 2.16
9191 log
9192 @#ifdef bug
9193 @
9194 text
9195 @d3 1
9196 a3 1
9197 static char ident[] = "@@(#)$Id: mhn.c,v 2.15 1992/11/24 18:21:54 jromine Exp jromine $";
9198 d1599 2
9199 a1600 1
9200     bp += vsprintf (bp, fmt, arglist);
9201 @
9202
9203
9204 2.15
9205 log
9206 @add/fixup decl
9207 @
9208 text
9209 @d3 1
9210 a3 1
9211 static char ident[] = "@@(#)$Id: mhn.c,v 2.14 1992/11/24 17:18:52 jromine Exp jromine $";
9212 d1581 1
9213 a1581 1
9214     register CI    ci = &ct -> c_ctinfo;
9215 d1604 1
9216 @
9217
9218
9219 2.14
9220 log
9221 @fix from mtr
9222 @
9223 text
9224 @d3 1
9225 a3 1
9226 static char ident[] = "@@(#)$Id: mhn.c,v 2.13 1992/11/24 17:18:04 jromine Exp jromine $";
9227 d273 1
9228 d282 4
9229 d3136 3
9230 a3138 3
9231 extern  int     openFile ();
9232 extern  int     openFTP ();
9233 extern  int     openMail ();
9234 @
9235
9236
9237 2.13
9238 log
9239 @messed up ifdefs for VSPRINTF & __STDC__
9240 @
9241 text
9242 @d3 1
9243 a3 1
9244 static char ident[] = "@@(#)$Id: mhn.c,v 2.12 1992/11/23 19:07:08 jromine Exp jromine $";
9245 d916 1
9246 a916 1
9247     "8bit",             CE_8BIT,        NULL,
9248 @
9249
9250
9251 2.12
9252 log
9253 @fix from mtr
9254 @
9255 text
9256 @d3 1
9257 a3 1
9258 static char ident[] = "@@(#)$Id: mhn.c,v 2.11 1992/11/23 19:05:18 jromine Exp jromine $";
9259 d275 1
9260 a275 1
9261 #ifdef __STDC__
9262 d1545 1
9263 a1548 1
9264 #ifdef VSPRINTF
9265 d1551 2
9266 a1552 1
9267 #else
9268 a1563 1
9269 #endif
9270 @
9271
9272
9273 2.11
9274 log
9275 @fix from mtr
9276 @
9277 text
9278 @d3 1
9279 a3 1
9280 static char ident[] = "@@(#)$Id: mhn.c,v 2.10 1992/11/23 19:04:27 jromine Exp jromine $";
9281 d2861 2
9282 a2864 3
9283                 if (p -> c_end < p -> c_begin) {
9284                     p -> c_begin = p -> c_end;
9285                 }
9286 @
9287
9288
9289 2.10
9290 log
9291 @fix '-moreproc' -- from mtr
9292 @
9293 text
9294 @d3 1
9295 a3 1
9296 static char ident[] = "@@(#)$Id: mhn.c,v 2.9 1992/11/11 17:57:04 jromine Exp jromine $";
9297 d4300 2
9298 a4301 1
9299         (void) sprintf (buffer, "Make cached, publically-accessible copy? ");
9300 @
9301
9302
9303 2.9
9304 log
9305 @minor fix from mtr
9306 @
9307 text
9308 @d3 1
9309 a3 1
9310 static char ident[] = "@@(#)$Id: mhn.c,v 2.8 1992/11/09 17:46:01 jromine Exp jromine $";
9311 d2477 2
9312 a2478 1
9313                         moreproc && *moreproc ? moreproc : "more");
9314 @
9315
9316
9317 2.8
9318 log
9319 @fixup varargs include
9320 @
9321 text
9322 @d3 1
9323 a3 1
9324 static char ident[] = "@@(#)$Id: mhn.c,v 2.7 1992/11/09 17:45:19 jromine Exp jromine $";
9325 d550 1
9326 a550 1
9327                     : m_maildir (invo_name);
9328 @
9329
9330
9331 2.7
9332 log
9333 @charset changes via MTR
9334 @
9335 text
9336 @d3 1
9337 a3 1
9338 static char ident[] = "@@(#)$Id: mhn.c,v 2.6 1992/11/06 03:24:40 jromine Exp jromine $";
9339 d1538 1
9340 d1540 3
9341 @
9342
9343
9344 2.6
9345 log
9346 @AUX fixups - varargs
9347 @
9348 text
9349 @d3 1
9350 a3 1
9351 static char ident[] = "@@(#)$Id: mhn.c,v 2.5 1992/11/04 00:47:59 jromine Exp jromine $";
9352 d3272 1
9353 d3281 1
9354 a3281 1
9355         (*p -> c_ctstorefnx) (p, NULLCP);
9356 d3284 1
9357 a3284 1
9358     return OK;
9359 d5463 5
9360 a5467 2
9361                     if (charset == -1)
9362                         charset = CHARSET_USASCII;
9363 d5476 15
9364 a5490 6
9365                     cp = index (*ap++ =
9366                                     add ((t -> tx_charset = charset)
9367                                                 == CHARSET_USASCII
9368                                              ? "charset=us-ascii"
9369                                              : "charset=x-unknown", NULLCP),
9370                                 '=');
9371 @
9372
9373
9374 2.5
9375 log
9376 @LOCALE
9377 TYPESIG
9378 isupper with isalpha
9379 @
9380 text
9381 @d3 1
9382 a3 1
9383 static char ident[] = "@@(#)$Id: mhn.c,v 2.4 1992/11/02 17:01:08 jromine Exp jromine $";
9384 d275 1
9385 a275 1
9386 #if     defined(VSPRINTF) && !defined(hpux)
9387 d1541 1
9388 a1541 1
9389 #if     defined(VSPRINTF) && !defined(hpux)
9390 d1544 4
9391 d1560 1
9392 d1565 4
9393 d1582 1
9394 d1584 6
9395 @
9396
9397
9398 2.4
9399 log
9400 @fixes from mtr
9401 @
9402 text
9403 @d3 1
9404 a3 1
9405 static char ident[] = "@@(#)$Id: mhn.c,v 2.3 1992/10/26 16:58:47 jromine Exp jromine $";
9406 d17 3
9407 d285 1
9408 a285 1
9409 static  int     pipeser ();
9410 d319 3
9411 d866 1
9412 a866 1
9413 static int  pipeser (i)
9414 d1189 1
9415 a1189 1
9416         if (isupper (*dp))
9417 d1225 1
9418 a1225 1
9419         if (isupper (*dp))
9420 d1262 1
9421 a1262 1
9422             if (isupper (*dp))
9423 d1636 1
9424 a1636 1
9425 static int  intrser (i)
9426 @
9427
9428
9429 2.3
9430 log
9431 @add single quotes areound %f
9432 @
9433 text
9434 @d3 1
9435 a3 1
9436 static char ident[] = "@@(#)$Id: mhn.c,v 2.2 1992/10/20 20:30:08 jromine Exp jromine $";
9437 d272 1
9438 a272 1
9439 #ifdef VSPRINTF
9440 d1535 1
9441 a1535 1
9442 #ifdef VSPRINTF
9443 d2661 1
9444 d2665 1
9445 d2669 6
9446 a2674 2
9447         if (part_ok (p) && type_ok (p) && p -> c_ctstorefnx)
9448             (void) (*p -> c_ctstorefnx) (p, NULLCP);
9449 d2677 1
9450 a2677 1
9451     return OK;
9452 a3105 1
9453 #ifdef  FTP
9454 a3106 1
9455 #endif
9456 d3112 4
9457 a3115 6
9458     "local-file", 0,    openFile,
9459     "afs",        1,    openFile,
9460 #ifdef  FTP
9461     "ftp",      0,      openFTP,
9462     "anon-ftp", 1,      openFTP,
9463 #endif
9464 d3412 6
9465 a3417 1
9466                     size = ct -> c_end - p -> c_begin;
9467 d3434 1
9468 a4312 1
9469 #ifdef  FTP
9470 d4319 2
9471 a4320 1
9472     char   *id,
9473 d4330 7
9474 d4401 49
9475 a4449 6
9476     if (ftp_get (e -> eb_site, user, pass, e -> eb_dir, e -> eb_name,
9477                     ce -> ce_file,
9478                     e -> eb_mode && uleq (e -> eb_mode, "ascii"), 0)
9479             == NOTOK) {
9480         username = password = NULL;
9481         return NOTOK;
9482 d4451 8
9483 a4494 1
9484 #endif
9485 d4954 6
9486 @
9487
9488
9489 2.2
9490 log
9491 @MIME upgrade 10
9492 @
9493 text
9494 @d3 1
9495 a3 1
9496 static char ident[] = "@@(#)$Id: mhn.c,v 2.1 1992/10/20 16:26:29 jromine Exp jromine $";
9497 d2450 1
9498 a2450 1
9499         (void) sprintf (buffer, "%%p%s %%F",
9500 d3309 1
9501 a3309 1
9502             ct -> c_showproc = add ("%pshow -file %F", NULLCP);
9503 @
9504
9505
9506 2.1
9507 log
9508 @null fixes
9509 @
9510 text
9511 @d3 1
9512 a3 1
9513 static char ident[] = "@@(#)$Id: mhn.c,v 1.5 1992/02/18 17:36:22 jromine Exp $";
9514 d148 1
9515 d461 1
9516 a461 1
9517                     if (!(cp = *argp++) || *cp == '-')
9518 d463 1
9519 a463 1
9520                     file = path (cp, TFILE);
9521 d540 1
9522 a540 1
9523     cwd = getcpy (pwd ());
9524 d563 2
9525 d572 2
9526 a573 2
9527         if ((fp = fopen (file, "r")) == NULL)
9528             adios (file, "unable to read");
9529 d575 25
9530 d601 3
9531 d1262 2
9532 a1263 2
9533                     "invalid parameter in message %s's %s: field\n%*.*s(%s)\n%*.*sstarting at %s",
9534                     ct -> c_file, TYPE_FIELD, i, i, "", cp, i, i, "", dp);
9535 d2063 5
9536 a2067 1
9537         fprintf (stderr, " as file %s\n", ct -> c_storage);
9538 d3410 1
9539 a3413 1
9540                     size = ct -> c_end - p -> c_begin;
9541 d4481 1
9542 a4481 1
9543         (void) sprintf (buffer, "mail-server request (cache as %s/%s)", cache,
9544 @
9545
9546
9547 2.0
9548 log
9549 @new version from /mtr - MIME/update9
9550 @
9551 text
9552 @d1217 1
9553 a1217 1
9554         if (*cp == NULL) {
9555 d2158 1
9556 a2158 1
9557                         buffer[0] = NULL;
9558 d2169 1
9559 a2169 1
9560                         buffer[0] = NULL;
9561 d3391 1
9562 a3391 1
9563                     *bp = NULL;
9564 d4323 1
9565 a4323 1
9566     ce -> ce_unlink = *file == NULL, caching = 0, cachefile[0] = NULL;
9567 d4695 1
9568 a4695 1
9569         *cp = NULL, n -= (i - 2);
9570 @
9571
9572
9573 1.7
9574 log
9575 @NULL->0, AIX
9576 @
9577 text
9578 @d3 1
9579 a3 1
9580 static char ident[] = "@@(#)$Id: mhn.c,v 1.6 1992/03/03 17:13:54 jromine Exp jromine $";
9581 d9 1
9582 d111 2
9583 d141 3
9584 d147 1
9585 d151 1
9586 d217 1
9587 d280 1
9588 d282 1
9589 d301 1
9590 d491 4
9591 d509 2
9592 d514 1
9593 a514 1
9594         via_mail (f1, f2, f3, f4, f5, f6);
9595 d530 1
9596 a530 1
9597     if (fp = fopen (cp = libpath ("mhn_profile"), "r")) {
9598 d536 3
9599 d541 3
9600 a543 1
9601     dir = getcpy ((cp = m_find (buf)) ? cp : cwd);
9602 d653 1
9603 d656 12
9604 d675 1
9605 a683 10
9606     if (storesw || showsw)
9607         for (ctp = cts; ct = *ctp; ctp++)
9608             if (type_ok (ct) && (ct -> c_ctstorefnx || ct -> c_ctshowfnx)) {
9609                 struct  stat st;
9610
9611                 if (!ct -> c_umask)
9612                     ct -> c_umask = ~(stat (ct -> c_file, &st) != NOTOK
9613                                           ? (st.st_mode & 0777) : m_gmprot ());
9614             }
9615
9616 d703 1
9617 d718 1
9618 a718 1
9619             char   *vec[7];
9620 d729 2
9621 a745 1
9622             (void) umask (ct -> c_umask);
9623 d750 1
9624 d761 2
9625 d791 6
9626 a796 1
9627             while (wait (&status) != NOTOK)
9628 d798 1
9629 a828 2
9630 /* ARGSUSED */
9631
9632 d832 9
9633 d913 1
9634 a913 3
9635                     register char  *cp,
9636                                    *dp;
9637                     char    c;
9638 a914 6
9639                     if (ct -> c_vrsn) {
9640                         advise (NULLCP, "message %s has multiple %s: fields",
9641                                 ct -> c_file, VRSN_FIELD);
9642                         goto out;
9643                     }
9644
9645 d921 11
9646 a956 6
9647                     if (ct -> c_ctline) {
9648                         advise (NULLCP, "message %s has multiple %s: fields",
9649                                 ct -> c_file, TYPE_FIELD);
9650                         goto out;
9651                     }
9652
9653 d963 11
9654 a991 6
9655                     if (ct -> c_celine) {
9656                         advise (NULLCP, "message %s has multiple %s: fields",
9657                                 ct -> c_file, ENCODING_FIELD);
9658                         goto out;
9659                     }
9660
9661 d998 10
9662 d1117 1
9663 d1146 2
9664 a1147 3
9665         advise (NULLCP, "invalid %s: field in message %s (empty type)",
9666                 TYPE_FIELD,
9667                 ct -> c_file);
9668 d1162 2
9669 a1163 10
9670         if (magic)
9671             goto magic_skip;
9672
9673 #ifdef  notdef
9674         advise (NULLCP,
9675                 "invalid %s: field in message %s (missing subtype for \"%s\")",
9676                 TYPE_FIELD, ct -> c_file, ci -> ci_type);
9677         return NOTOK;
9678 #else
9679         ci -> ci_subtype = add ("", NULLCP);
9680 a1164 1
9681 #endif
9682 d1200 2
9683 a1201 1
9684         char   *vp;
9685 d1217 7
9686 d1227 2
9687 d1231 2
9688 a1232 2
9689                     "invalid parameter in message %s's %s: field (%s)",
9690                     ct -> c_file, TYPE_FIELD, cp);
9691 d1236 5
9692 a1240 4
9693         vp = (*ap = add (cp, NULLCP)) + (dp - cp);
9694         *vp++ = '\0';
9695         ci -> ci_values[ap - ci -> ci_attrs] = vp;
9696         dp++;
9697 d1247 2
9698 a1248 2
9699                                 "invalid quoted-string in message %s's %s: field (parameter %s)",
9700                                 ct -> c_file, TYPE_FIELD, *ap);
9701 a1264 1
9702
9703 d1275 2
9704 a1276 2
9705                     "invalid parameter in message %s's %s: field (parameter %s)",
9706                     ct -> c_file, TYPE_FIELD, *ap);
9707 d1294 1
9708 a1294 2
9709             advise (NULLCP, "invalid description in message %s's %s: field",
9710                     ct -> c_file, TYPE_FIELD);
9711 d1315 2
9712 a1316 2
9713                     "extraneous information in message %s's %s: field (%s)",
9714                 ct -> c_file, TYPE_FIELD, cp);
9715 d1474 4
9716 d1523 1
9717 d1556 3
9718 a1558 1
9719     (void) sprintf (bp, " (content %s/%s", ci -> ci_type, ci -> ci_subtype);
9720 d1594 19
9721 d1626 1
9722 a1626 1
9723     if ((cp = m_find (buffer)) == NULL) {
9724 d1628 1
9725 a1628 1
9726         if ((cp = m_find (buffer)) == NULL
9727 d1653 1
9728 d1659 2
9729 a1660 1
9730             buffer[BUFSIZ];
9731 d1673 2
9732 d1676 1
9733 a1676 1
9734     xlist = xstdin = xtty = 0;
9735 d1712 3
9736 d1739 6
9737 d1747 1
9738 a1747 1
9739     if (debugsw) {
9740 d1749 2
9741 a1750 1
9742         fprintf (stderr, "%s msg %s", cracked ? "store" : "show",
9743 d1754 4
9744 a1757 1
9745         fprintf (stderr, " using command %s\n", buffer);
9746 a1759 2
9747     (void) fflush (stdout);
9748
9749 d1761 1
9750 a1761 1
9751         (void) pidwait (xpid, NOTOK);
9752 d1765 2
9753 a1766 2
9754     if (xlist && ct -> c_ctlistfnx)
9755         (*ct -> c_ctlistfnx) (ct, -1);
9756 d1768 59
9757 d1829 1
9758 a1829 1
9759     vec[2] = buffer;
9760 d1832 2
9761 d1861 1
9762 a1861 1
9763                 (void) pidXwait (child_id, NULLCP);
9764 d1889 7
9765 a1895 7
9766     (void) sprintf (buffer, "%s-store-%s/%s", invo_name, ci -> ci_type,
9767                     ci -> ci_subtype);
9768     if ((cp = m_find (buffer)) == NULL) {
9769         (void) sprintf (buffer, "%s-store-%s", invo_name, ci -> ci_type);
9770         if ((cp = m_find (buffer)) == NULL
9771                 && (cp = ct -> c_storeproc) == NULL)
9772             cp = ct -> c_type == CT_MESSAGE ? "+" : "%m%P.%s";
9773 d1897 1
9774 d1953 3
9775 a1955 2
9776             (void) sprintf (bp = buffer, "%s/", dir[1] ? dir : "");
9777             bp += strlen (bp);
9778 d2020 1
9779 a2020 1
9780         return show_content_aux (ct, 1, 0, buffer + 1, dir);
9781 d2024 1
9782 d2026 1
9783 d2033 1
9784 d2035 1
9785 d2047 2
9786 a2048 1
9787         file = appending ? NULLCP : ct -> c_storage;
9788 d2056 15
9789 a2070 5
9790         if ((fp = fopen (ct -> c_storage, appending ? "a" : "w")) == NULL) {
9791             advise (ct -> c_storage, "unable to fopen for %s",
9792                     appending ? "appending" : "writing");
9793             (void) (*ct -> c_ceclosefnx) (ct);
9794             return NOTOK;
9795 d2072 7
9796 d2117 13
9797 a2129 4
9798     if ((fp = fopen (ct -> c_storage, appending ? "a" : "w")) == NULL) {
9799         advise (ct -> c_storage, "unable to fopen for %s",
9800                 appending ? "appending" : "writing");
9801         return NOTOK;
9802 d2131 6
9803 d2138 1
9804 a2138 1
9805     if (append && !*append)
9806 d2140 4
9807 d2152 24
9808 d2217 1
9809 a2217 1
9810                 fprintf (out, "%s: %s", name, buf);
9811 d2287 2
9812 d2364 1
9813 a2365 1
9814
9815 d2395 1
9816 d2409 2
9817 d2415 1
9818 a2415 1
9819         (void) sprintf (buffer, "%s %%F",
9820 d2422 8
9821 d2432 2
9822 a2433 8
9823                     register struct text *t;
9824
9825                     if ((t = (struct text *) calloc (1, sizeof *t)) == NULL)
9826                         adios (NULLCP, "out of memory");
9827                     ct -> c_ctparams = (caddr_t) t;
9828                     ct -> c_ctfreefnx = free_text;
9829
9830                     t -> tx_charset = kv -> kv_value;
9831 d2436 7
9832 d2509 1
9833 d2521 2
9834 a2522 1
9835             nowserial = 1;
9836 d2587 7
9837 a2593 1
9838         while (kids > 0 && (pid = wait (&status)) != NOTOK)
9839 d2605 1
9840 d2704 1
9841 a2704 1
9842                   ci -> ci_type, ci -> ci_subtype);
9843 d3042 1
9844 d3044 1
9845 a3044 1
9846     int     eb_didone;
9847 d3050 2
9848 d3055 6
9849 d3064 1
9850 d3068 1
9851 d3073 2
9852 d3079 1
9853 d3085 1
9854 a3085 1
9855 static int  params_external (ct)
9856 d3087 1
9857 d3119 4
9858 d3135 12
9859 d3149 1
9860 a3149 1
9861     if (!e -> eb_access || !e -> eb_name || !e -> eb_site) {
9862 d3168 2
9863 a3169 1
9864         printf ("\t     retrieve %s ", e -> eb_name);
9865 d3171 6
9866 a3176 3
9867             printf ("in directory %s ", e -> eb_dir);
9868         printf ("\n\t\t from %s\n\t\tusing %s", e -> eb_site,
9869                 e -> eb_access);
9870 d3179 2
9871 a3201 14
9872     if (!e -> eb_didone) {
9873         char   *file;
9874
9875         e -> eb_didone = 1;
9876
9877         file = NULL;
9878         if ((*p -> c_ceopenfnx) (p, &file) == NOTOK)
9879             return NOTOK;
9880         (void) (*p -> c_ceclosefnx) (p);
9881
9882         if (p -> c_ctinitfnx && (*p -> c_ctinitfnx) (p) == NOTOK)
9883             return NOTOK;
9884     }
9885
9886 a3218 15
9887     if (!e -> eb_didone) {
9888         char   *file;
9889
9890         e -> eb_didone = 1;
9891
9892         file = NULL;    /* would be great to have this filled in, but it's
9893                            a chicken-and-egg situation... */
9894         if ((*p -> c_ceopenfnx) (p, &file) == NOTOK)
9895             return NOTOK;
9896         (void) (*p -> c_ceclosefnx) (p);
9897
9898         if (p -> c_ctinitfnx && (*p -> c_ctinitfnx) (p) == NOTOK)
9899             return NOTOK;
9900     }
9901
9902 d3237 2
9903 d3262 1
9904 a3262 1
9905                   ci -> ci_type, ci -> ci_subtype);
9906 d3266 2
9907 d3274 1
9908 a3274 1
9909             ct -> c_showproc = add ("show -file %F", NULLCP);
9910 d3340 1
9911 a3364 2
9912                 p -> c_fp = NULL;
9913                 p -> c_end = p -> c_begin;
9914 d3366 1
9915 d3369 14
9916 d3384 12
9917 d3400 1
9918 a3400 1
9919                 if (params_external (ct) == NOTOK)
9920 d3405 15
9921 d3431 1
9922 a3431 1
9923                         e -> eb_didone = 1;
9924 d3483 2
9925 d3493 15
9926 a3510 2
9927         register char  **ap,
9928                        **ep;
9929 d3522 2
9930 a3523 1
9931             if (uleq (*ap, "conversions") && uleq (*ep, "compress")) {
9932 a3526 8
9933
9934             if (autosw && !ct -> c_storeproc && uleq (*ap, "file")) {
9935                 register char   *cp;
9936
9937                 if (*(cp = *ep) != '/' && *cp != '+' && *cp != '@@')
9938                     ct -> c_storeproc = add (cp, NULLCP);
9939                 break;
9940             }
9941 a3700 1
9942     unsigned char   *b = (unsigned char *) &bits;
9943 d3703 5
9944 a3707 1
9945     unsigned char   value;
9946 d3725 1
9947 a3725 3
9948                                     add (*file ? *file
9949                                                : m_scratch ("",
9950                                                             m_maildir (invo_name)),
9951 d3763 2
9952 a3764 1
9953                             if ((*cp & 0x80)
9954 d3767 4
9955 a3770 2
9956                                     fprintf (stderr, "*cp=0x%x pos=%ld\n", *cp,
9957                                              lseek (fd, 0L, 1) - (ep - cp));
9958 d3772 1
9959 a3772 3
9960         "invalid BASE64 encoding (char 0x%x at position %ld) -- continuing",
9961                                                *cp,
9962                                              lseek (fd, 0L, 1) - (ep - cp));
9963 d3779 1
9964 a3779 2
9965 #if     defined(i386) || defined(vax)
9966                                 (void) putc (b[2], ce -> ce_fp);
9967 d3781 1
9968 a3781 1
9969                                     (void) putc (b[1], ce -> ce_fp);
9970 d3783 1
9971 a3783 1
9972                                         (void) putc (b[0], ce -> ce_fp);
9973 d3785 5
9974 a3789 6
9975 #else
9976                                 (void) putc (b[1], ce -> ce_fp);
9977                                 if (skip < 2) {
9978                                     (void) putc (b[2], ce -> ce_fp);
9979                                     if (skip < 1)
9980                                         (void) putc (b[3], ce -> ce_fp);
9981 a3790 2
9982 #endif
9983
9984 d3796 2
9985 a3797 1
9986                             skip++;
9987 a3798 14
9988
9989 #ifdef  notanymore
9990                         case ',':
9991                             if (bitno != 18) {
9992                                 if (debugsw)
9993                                     fprintf (stderr,
9994                                              "unaligned ',' (bitno %d)\n",
9995                                              bitno);
9996
9997                                 goto invalid_encoding;
9998                             }
9999                             (void) putc ('\n', ce -> ce_fp);
10000                             break;
10001 #endif
10002 a3803 3
10003 #ifdef  notanymore
10004 invalid_encoding: ;
10005 #endif
10006 d3808 1
10007 d3834 17
10008 d3900 1
10009 a3900 3
10010                                     add (*file ? *file
10011                                                : m_scratch ("",
10012                                                             m_maildir (invo_name)),
10013 d3964 4
10014 d3990 4
10015 d4061 1
10016 a4061 3
10017                                     add (*file ? *file
10018                                                : m_scratch ("",
10019                                                             m_maildir (invo_name)),
10020 d4094 4
10021 d4128 140
10022 d4275 7
10023 a4281 2
10024     char   *user,
10025            *pass;
10026 d4285 1
10027 a4285 1
10028     static char   *password = NULL;             
10029 d4287 2
10030 a4288 5
10031     if (ce -> ce_fp)
10032         goto ready_to_go;
10033     if (ce -> ce_file) {
10034         if ((ce -> ce_fp = fopen (ce -> ce_file, "r")) == NULL) {
10035             content_error (ce -> ce_file, ct, "unable to fopen for reading");
10036 a4289 1
10037         }
10038 d4291 5
10039 a4295 2
10040         *file = ce -> ce_file;
10041         return fileno (ce -> ce_fp);
10042 d4298 20
10043 a4317 2
10044     if (e -> eb_flags)
10045         user = "anonymous", pass = "guest";
10046 a4318 5
10047         if (xpid) {
10048             (void) pidwait (xpid, NOTOK);
10049             xpid = 0;
10050         }
10051
10052 d4323 17
10053 a4339 1
10054     ce -> ce_unlink = *file == NULL;
10055 d4342 2
10056 a4343 2
10057                                                : m_scratch ("",
10058                                                             m_maildir (invo_name)),
10059 a4350 3
10060     if (verbosw)
10061         printf ("Retrieving %s using %sFTP from site %s\n",
10062                 e -> eb_name, e -> eb_flags ? "Anonymous " : "", e -> eb_site);
10063 d4359 31
10064 a4389 1
10065 ready_to_go: ;
10066 d4396 100
10067 d4523 1
10068 d4550 1
10069 a4550 1
10070                 fprintf (out, "%s: %s", name, buf);
10071 d4595 1
10072 a4595 1
10073     while (fgets (buf, sizeof buf - 1, in)) {
10074 d4631 1
10075 a4631 1
10076             if (*++cp == '\n')
10077 d4676 27
10078 d4732 5
10079 a4736 2
10080     if (buf[0] != '#' || buf[1] == '#') {
10081         int     headers;
10082 d4745 9
10083 d4766 1
10084 a4766 1
10085                     if (!fgets (buffer, sizeof buffer - 1, in))
10086 d4789 1
10087 d4792 2
10088 a4793 1
10089             if ((cp = fgets (buffer, sizeof buffer - 1, in)) == NULL)
10090 d4810 1
10091 a4810 1
10092         if (get_ctinfo ("text/plain", ct, 0) == NOTOK)
10093 d4812 19
10094 a4830 3
10095         ct -> c_type = CT_TEXT;
10096         ct -> c_ctinitfnx = InitText;
10097         (void) (*ct -> c_ctinitfnx) (ct);
10098 d4832 1
10099 a4832 1
10100             (void) fseek (in, (long) (-strlen (cp)), 1);
10101 d4866 1
10102 d4869 3
10103 d4897 1
10104 d4903 1
10105 a4903 1
10106             if (params_external (ct) == NOTOK)
10107 d4906 11
10108 d4943 1
10109 a4943 1
10110         if ((cp = m_find (buffer)) == NULL) {
10111 d4945 1
10112 a4945 1
10113             if ((cp = m_find (buffer)) == NULL) {
10114 d5059 1
10115 a5059 1
10116     while (fgets (buffer, sizeof buffer - 1, in)) {
10117 a5081 20
10118 static char asciiP[0x80] = {
10119     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10120     0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
10121     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10122     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10123     0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
10124     0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
10125     0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
10126     0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
10127     0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
10128     0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
10129     0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
10130     0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
10131     0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
10132     0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
10133     0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
10134     0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00
10135 };
10136
10137
10138 d5144 1
10139 a5144 1
10140                         ct -> c_end += 1 /* notdef 2 */;
10141 d5248 1
10142 a5248 1
10143                         if (pidXwait (child_id, NULLCP) & 0377)
10144 d5259 3
10145 a5261 1
10146             if (ct -> c_type != CT_TEXT)
10147 d5269 1
10148 d5278 14
10149 a5291 1
10150                 charset = ct -> c_type != CT_TEXT || ct -> c_ctparams ? 0 : -1;
10151 d5295 6
10152 a5300 4
10153                             if (!isascii (*cp) || !asciiP[*cp & 0x7f]) {
10154                                     charset = CHARSET_UNKNOWN;
10155                                     break;
10156                                 }
10157 d5304 3
10158 d5320 1
10159 a5320 1
10160                             if (charset != -1)
10161 d5325 4
10162 d5348 1
10163 a5348 1
10164                                              : "charset=iso8859-1", NULLCP),
10165 d5371 1
10166 a5388 4
10167
10168         if (!ci -> ci_comment && ct -> c_rfc934)
10169             ci -> ci_comment = add ("RFC 934 compatible encapsulation",
10170                                     NULLCP);
10171 d5398 3
10172 d5402 3
10173 d5480 1
10174 d5487 2
10175 d5495 3
10176 a5497 1
10177             if (ct -> c_subtype == APPLICATION_POSTSCRIPT)
10178 d5499 1
10179 d5558 7
10180 a5564 2
10181         n = 0;
10182         for (cp = buffer; *cp; cp++) {
10183 a5575 1
10184                     
10185 a5577 3
10186                 case '[':
10187                 case ']':
10188                 case '^':
10189 d5588 1
10190 d5659 5
10191 a5667 4
10192 #if     defined(i386) || defined(vax)
10193         for (bp = outbuf; bp < outbuf + sizeof outbuf; bits >>= 6)
10194             *bp++ = nib2b64[bits & 0x3f];
10195 #else
10196 a5669 1
10197 #endif
10198 d5699 1
10199 a5699 1
10200 static int  via_mail (mailsw, subjsw, parmsw, descsw, cmntsw, slowsw)
10201 d5704 2
10202 a5705 1
10203        *cmntsw;
10204 d5726 1
10205 d5728 7
10206 a5734 2
10207         fprintf (fp, "Subject: %s\n", subjsw);
10208     fprintf (fp, "%s: %s\n", VRSN_FIELD, VRSN_VALUE);
10209 d5739 1
10210 a5739 1
10211         fprintf (fp, "\n\t(%s)", cmntsw);
10212 d5741 2
10213 a5742 3
10214         fprintf (fp, "\n%s: %s", DESCR_FIELD, descsw);
10215     fprintf (fp, "\n%s: %s\n\n", ENCODING_FIELD, "base64");
10216     nlines = 4 + (subjsw ? 1 : 0) + (descsw ? 1 : 0) + (cmntsw ? 1 : 0);
10217 d5797 3
10218 d5881 17
10219 @
10220
10221
10222 1.6
10223 log
10224 @fixes from mtr
10225 @
10226 text
10227 @d3 1
10228 a3 1
10229 static char ident[] = "@@(#)$Id: mhn.c,v 1.5 1992/02/18 17:36:22 jromine Exp jromine $";
10230 d111 1
10231 a111 1
10232     NULL, NULL
10233 d166 1
10234 d182 2
10235 a183 1
10236 int     get_ctinfo ();
10237 d258 3
10238 a260 3
10239 CT      get_content ();
10240 int     list_content (), show_content (), store_content ();
10241 void    free_content (), content_error (), flush_errors ();
10242 d262 6
10243 d812 1
10244 a812 1
10245 int     InitApplication (), InitMessage (), InitMultiPart (), InitText ();
10246 d829 1
10247 a829 1
10248 int     InitBase64 (), InitQuoted (), Init7Bit ();
10249 d956 1
10250 a956 1
10251                     c = *dp, *dp = NULL;
10252 d1074 1
10253 a1074 1
10254     *++dp = NULL;
10255 d1083 1
10256 a1083 1
10257     c = *dp, *dp = NULL;
10258 d1128 1
10259 a1128 1
10260     c = *dp, *dp = NULL;
10261 d1179 1
10262 a1179 1
10263         *vp++ = NULL;
10264 d1185 1
10265 a1185 1
10266                     case NULL:
10267 d1194 1
10268 a1194 1
10269                         if ((c = *cp++) == NULL)
10270 d1203 1
10271 a1203 1
10272                         *dp = NULL;
10273 d1213 1
10274 a1213 1
10275             *dp = NULL;
10276 d1242 1
10277 a1242 1
10278         c = *dp, *dp = NULL;
10279 d1285 1
10280 a1285 1
10281             case NULL:
10282 d1293 1
10283 a1293 1
10284                 if ((c = *cp++) == NULL)
10285 d1313 1
10286 a1313 1
10287     *bp = NULL;
10288 d1370 1
10289 a1370 1
10290         case NULL:
10291 d1439 7
10292 a1446 1
10293
10294 d1457 1
10295 d1459 3
10296 d1473 4
10297 d1479 1
10298 d1509 1
10299 a1509 1
10300         *bp = NULL;
10301 d1530 2
10302 d1594 1
10303 a1594 1
10304     buffer[0] = NULL;
10305 d1639 1
10306 a1639 1
10307                     *bp = NULL;
10308 d1647 1
10309 a1647 1
10310             *bp = NULL;
10311 d1789 1
10312 a1789 1
10313             buffer[0] = NULL;
10314 d1803 1
10315 a1803 1
10316                         *bp = NULL;
10317 d1848 1
10318 a1848 1
10319                     *bp = NULL;
10320 d1856 1
10321 a1856 1
10322             *bp = NULL;
10323 d1948 1
10324 a1948 1
10325                 buffer[diff] = NULL;
10326 d2494 1
10327 a2494 1
10328     *++dp = NULL;
10329 d3544 6
10330 a3549 6
10331     NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
10332     NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
10333     NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
10334     NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
10335     NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
10336     NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
10337 d3551 9
10338 a3559 9
10339     0x08, 0x09, NULL, NULL, NULL, NULL, NULL, NULL,
10340     NULL, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, NULL, 
10341     NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
10342     NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
10343     NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
10344     NULL, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, NULL, 
10345     NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
10346     NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
10347     NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
10348 d3886 1
10349 a3886 1
10350 static int  build_comp (file)
10351 d4142 1
10352 a4142 1
10353                 *bp = NULL;
10354 d4498 1
10355 a4498 1
10356                 buffer[0] = NULL;
10357 d4534 1
10358 a4534 1
10359                                 *bp = NULL;
10360 d4542 1
10361 a4542 1
10362                         *bp = NULL;
10363 d4623 1
10364 a4623 1
10365                         *++cp = NULL;
10366 d4654 1
10367 a4654 1
10368                     *cp++ = NULL;
10369 d4689 1
10370 a4689 1
10371         *cp++ = NULL;
10372 d4850 1
10373 a4850 1
10374             *cp = NULL;
10375 @
10376
10377
10378 1.5
10379 log
10380 @fix from mrose
10381 @
10382 text
10383 @d3 1
10384 a3 1
10385 static char ident[] = "@@(#)$Id: mhn.c,v 1.4 1992/02/14 16:22:17 jromine Exp jromine $";
10386 d1960 1
10387 a1960 1
10388                 if (uprf (name, XXX_FIELD_PRF)) {
10389 @
10390
10391
10392 1.4
10393 log
10394 @fixes from /mtr
10395 @
10396 text
10397 @d3 1
10398 a3 1
10399 static char ident[] = "@@(#)$Id: mhn.c,v 1.3 1992/02/07 16:07:46 jromine Exp jromine $";
10400 a2426 6
10401     if (ct -> c_celine && ct -> c_encoding != CE_7BIT) {
10402         admonish (NULLCP, "%s: field should not be present for \"%s/%s\" type in message %s's %s: field",
10403                 ENCODING_FIELD, ci -> ci_type, ci -> ci_subtype, ct -> c_file,
10404                 TYPE_FIELD);
10405         return NOTOK;
10406     }
10407 a2974 6
10408     if (ct -> c_celine && ct -> c_encoding != CE_7BIT) {
10409         admonish (NULLCP, "%s: field should not be present for \"%s/%s\" type in message %s's %s: field",
10410                 ENCODING_FIELD, ci -> ci_type, ci -> ci_subtype, ct -> c_file,
10411                 TYPE_FIELD);
10412         return NOTOK;
10413     }
10414 @
10415
10416
10417 1.3
10418 log
10419 @patch from mrose
10420 @
10421 text
10422 @d3 1
10423 a3 1
10424 static char ident[] = "@@(#)$Id: mhn.c,v 1.2 1992/02/07 03:44:12 jromine Exp jromine $";
10425 d2427 1
10426 a2427 1
10427     if (ct -> c_celine) {
10428 d2981 1
10429 a2981 1
10430     if (ct -> c_celine) {
10431 d3612 1
10432 a3612 1
10433         for (ep = (cp = buffer) + cc - 2; cp <= ep; ep--)
10434 @
10435
10436
10437 1.2
10438 log
10439 @fix from mrose
10440 @
10441 text
10442 @d3 1
10443 a3 1
10444 static char ident[] = "@@(#)$Id: mhn.c,v 1.1 1992/01/31 16:28:15 jromine Exp jromine $";
10445 d2159 2
10446 a2160 1
10447         (void) sprintf (buffer, "%s %%F", moreproc);
10448 @
10449
10450
10451 1.1
10452 log
10453 @Initial revision
10454 @
10455 text
10456 @d3 1
10457 a3 1
10458 static char ident[] = "@@(#)$Id$";
10459 d1100 1
10460 d1105 4
10461 @