1 /* mhn.c - multi-media MH */
3 static char ident[] = "@(#)$Id: mhn.c,v 2.42 1995/12/06 22:32:29 jromine Exp $";
12 #include "../zotnet/mts.h"
13 #include <sys/types.h>
24 static struct swit switches[] = {
48 #define FILESW 9 /* interface from show */
115 "moreproc program", -4,
125 "viamail mailpath", -7,
127 "viasubj subject", -7,
129 "viaparm arguments", -7,
135 "viadelay seconds", -8,
137 "viafrom mailpath", -7,
147 static struct swit caches[] = {
148 #define CACHE_NEVER 0
150 #define CACHE_PRIVATE 1
152 #define CACHE_PUBLIC 2
160 static int autosw = 0;
161 static int cachesw = 0;
162 static int checksw = 0;
164 static int ebcdicsw = 0;
165 static char *formsw = NULLCP;
166 static int headsw = 1;
167 static int listsw = 0;
168 static int nolist = 0;
169 static int nomore = 0;
170 static int npart = 0;
171 static char *parts[NPARTS + 1];
172 static int pausesw = 1;
173 static char *progsw = NULLCP;
174 static int rcachesw = CACHE_ASK;
175 static int rfc934sw = 1;
176 static int serialsw = 0;
177 static int showsw = 0;
178 static int sizesw = 1;
179 static int storesw = 0;
180 static int ntype = 0;
181 static char *types[NTYPES + 1];
183 static int wcachesw = CACHE_ASK;
185 static int endian = 0;
186 static char *mm_charset = NULL;
189 static int userrs = 0;
191 static char *cache_public;
192 static char *cache_private;
196 static char *errs = NULL;
203 extern char *sys_errlist[];
211 #define LSTFMT1 "%4s %-5s %-24s %5s %-36s\n"
213 #define LSTFMT2a "%4d "
214 #define LSTFMT2b "%-5s %-24.24s "
215 #define LSTFMT2c1 "%5lu"
216 #define LSTFMT2c2 "%4lu%c"
217 #define LSTFMT2c3 "huge "
218 #define LSTFMT2c4 " "
219 #define LSTFMT2d1 " %-36.36s"
220 #define LSTFMT2d2 "\t %-65.65s\n"
222 static void build_comp ();
224 typedef struct CTinfo {
229 char *ci_attrs[NPARMS + 2];
230 char *ci_values[NPARMS];
236 #define NULLCI ((CI) 0)
238 static int get_ctinfo ();
239 static int get_comment ();
242 typedef struct Content {
243 char *c_partno; /* within multipart content */
245 char *c_vrsn; /* Body-Version: */
247 char *c_ctline; /* Content-Type: */
250 int c_type; /* internal form */
251 #define CT_UNKNOWN 0x00
252 #define CT_APPLICATION 0x01
253 #define CT_AUDIO 0x02
254 #define CT_IMAGE 0x03
255 #define CT_MESSAGE 0x04
256 #define CT_MULTIPART 0x05
258 #define CT_VIDEO 0x07
259 #define CT_EXTENSION 0x08
261 int c_subtype; /* filled-in by c_ctinitfnx */
262 caddr_t c_ctparams; /* .. */
263 caddr_t c_ctextern; /* .. */
264 char *c_showproc; /* default, if not in profile */
265 char *c_termproc; /* for charset madness... */
266 char *c_storeproc; /* overrides profile entry, if any */
268 int (*c_ctinitfnx) (); /* parse content */
269 int (*c_ctlistfnx) (); /* list content */
270 int (*c_ctshowfnx) (); /* show content */
271 int (*c_ctstorefnx) (); /* store content */
272 int (*c_ctfreefnx) (); /* free content-specific structures */
275 char *c_celine; /* Content-Transfer-Encoding: */
277 int c_encoding; /* internal form */
278 #define CE_UNKNOWN 0x00
279 #define CE_BASE64 0x01
280 #define CE_QUOTED 0x02
283 #define CE_BINARY 0x05
284 #define CE_EXTENSION 0x06
285 #define CE_EXTERNAL 0x07 /* for external-body */
287 caddr_t c_ceparams; /* filled-in by encoding initfnx */
289 int (*c_ceopenfnx) (); /* get a stream to decoded contents */
290 int (*c_ceclosefnx) (); /* release stream */
291 int (*c_celistfnx) (); /* list decoding info */
293 (*c_cesizefnx) (); /* size of decoded contents */
294 int (*c_cefreefnx) (); /* free encoding-specific structures */
297 char *c_id; /* Content-ID: */
298 char *c_descr; /* Content-Description: */
300 int c_digested; /* Content-MD5: */
301 unsigned char c_digest[16]; /* .. */
303 FILE *c_fp; /* read contents (stream) */
304 char *c_file; /* read contents (file) */
305 int c_unlink; /* remove file when done? */
306 int c_umask; /* associated umask */
307 long c_begin; /* where content starts in file */
308 long c_end; /* .. ends */
310 int c_pid; /* process doing display */
311 char *c_storage; /* write contents (file) */
313 int c_rfc934; /* rfc934 compatibility */
315 #define NULLCT ((CT) 0)
317 static CT get_content ();
318 static int list_content (), show_content (), store_content ();
319 static int cache_content ();
320 static int user_content (), compose_content (), output_content ();
321 static void free_content (), flush_errors (), set_id ();
323 #if defined(__STDC__) && defined(VSPRINTF)
324 static void content_error (char *, register CT, char *, ...);
326 static void content_error ();
329 static int init_encoding (), type_ok (), copy_some_headers (), set_endian ();
330 static int make_intermediates ();
331 static int find_cache (), find_cache_aux (), find_cache_aux2 ();
332 static int write7Bit (), writeQuoted (), writeBase64 (), writeBase64aux ();
333 static int writeDigest (), readDigest ();
334 static int via_mail (), via_post (), pidcheck ();
336 static CT *cts = NULL;
339 #define quitser pipeser
340 static TYPESIG pipeser ();
341 static char *fgetstr ();
376 setlocale(LC_ALL, "");
378 invo_name = r1bindex (argv[0], '/');
379 if (argv[1] && uprf (argv[1], "-via"))
381 if ((cp = m_find (invo_name)) != NULL) {
382 ap = brkstring (cp = getcpy (cp), " ", "\n");
383 ap = copyip (ap, arguments);
387 (void) copyip (argv + 1, ap);
392 while (cp = *argp++) {
394 switch (smatch (++cp, switches)) {
396 ambigsw (cp, switches);
399 adios (NULLCP, "-%s unknown", cp);
401 (void) sprintf (buf, "%s [+folder] [msgs] [switches]",
403 help (buf, switches);
421 icachesw = &rcachesw;
424 icachesw = &wcachesw;
426 if (!(cp = *argp++) || *cp == '-')
427 adios (NULLCP, "missing argument to %s", argp[-2]);
428 switch (*icachesw = smatch (cp, caches)) {
430 ambigsw (cp, caches);
433 adios (NULLCP, "%s unknown", cp);
458 if (!(cp = *argp++) || *cp == '-')
459 adios (NULLCP, "missing argument to %s", argp[-2]);
462 formsw = getcpy (libpath (cp));
480 if (!(cp = *argp++) || *cp == '-')
481 adios (NULLCP, "missing argument to %s", argp[-2]);
484 "too many parts (starting with %s), %d max",
532 if (!(cp = *argp++) || *cp == '-')
533 adios (NULLCP, "missing argument to %s", argp[-2]);
536 "too many types (starting with %s), %d max",
549 if (!(progsw = *argp++) || *progsw == '-')
550 adios (NULLCP, "missing argument to %s", argp[-2]);
558 if (!(cp = *argp++) || *cp == '-')
559 adios (NULLCP, "missing argument to %s", argp[-2]);
563 if (!(cp = *argp++) || (*cp == '-' && cp[1]))
564 adios (NULLCP, "missing argument to %s", argp[-2]);
565 file = *cp == '-' ? cp : path (cp, TFILE);
570 adios (NULLCP, "missing argument to %s", argp[-2]);
574 adios (NULLCP, "missing argument to %s", argp[-2]);
578 adios (NULLCP, "missing argument to %s", argp[-2]);
582 adios (NULLCP, "missing argument to %s", argp[-2]);
586 adios (NULLCP, "missing argument to %s", argp[-2]);
589 if (!(cp = *argp++) || *cp == '-')
590 adios (NULLCP, "missing argument to %s", argp[-2]);
591 if (sscanf (cp, "%d", &f6) != 1 || f6 < 0)
596 adios (NULLCP, "missing argument to %s", argp[-2]);
599 if (*cp == '+' || *cp == '@') {
601 adios (NULLCP, "only one folder at a time!");
603 folder = path (cp + 1, *cp == '+' ? TFOLDER : TSUBCWF);
608 parts[npart] = NULL, types[ntype] = NULL;
610 formsw = getcpy (libpath ("mhl.headers"));
617 via_mail (f1, f2, f3, f4, f5, f6, f7);
621 if (f2 || f3 || f4 || f5 || f6 || f7)
622 adios (NULLCP, "missing -viamail \"mailpath\" switch");
624 if (cp = getenv ("MHN")) {
625 if (fp = fopen (cp, "r")) {
626 m_readefs ((struct node **) 0, fp, cp, 0);
631 admonish ("", "unable to read $MHN profile (%s)", cp);
633 if (fp = fopen (cp = libpath ("mhn_defaults"), "r")) {
634 m_readefs ((struct node **) 0, fp, cp, 0);
639 (void) sprintf (buf, "%s-cache", invo_name);
640 if ((cache_public = m_find (buf)) && *cache_public != '/')
642 (void) sprintf (buf, "%s-private-cache", invo_name);
643 if (!(cache_private = m_find (buf)))
644 cache_private = ".cache";
645 cache_private = getcpy (m_maildir (cache_private));
647 cwdlen = strlen (cwd = getcpy (pwd ()));
648 (void) sprintf (buf, "%s-storage", invo_name);
649 dir = getcpy ((cp = m_find (buf)) && *cp ? cp : cwd);
650 tmp = cp && *cp ? concat (cp, "/", invo_name, NULLCP)
651 : add (m_maildir (invo_name), NULLCP);
653 if (!m_find ("path"))
654 free (path ("./", TFOLDER));
664 && (cp = getenv ("mhdraft"))
665 && strcmp (cp, msgs[0]) == 0) {
674 adios (NULLCP, "only one file at a time!");
676 if ((cts = (CT *) calloc ((unsigned) 2, sizeof *cts)) == NULL)
677 adios (NULLCP, "out of memory");
680 if (stdinP = (strcmp (file, "-") == 0)) {
683 file = add (m_tmpfil (invo_name), NULLCP);
685 if ((fp = fopen (file, "w+")) == NULL)
686 adios (file, "unable to fopen for writing and reading");
687 (void) chmod (file, 0600);
688 while (fgets (buffer, sizeof buffer, stdin))
689 (void) fputs (buffer, fp);
692 if (ferror (stdin)) {
693 (void) unlink (file);
694 adios ("stdin", "error reading");
698 (void) unlink (file);
699 adios (file, "error writing");
702 (void) fseek (fp, 0L, 0);
705 if ((fp = fopen (file, "r")) == NULL)
706 adios (file, "unable to read");
708 if (ct = get_content (fp, file, 1)) {
713 if (ct -> c_end == 0L) {
714 (void) fseek (fp, 0L, 2);
715 ct -> c_end = ftell (fp);
717 if (ct -> c_ctinitfnx && (*ct -> c_ctinitfnx) (ct) == NOTOK)
723 advise (NULLCP, "unable to decode %s", file);
732 msgs[msgp++] = "cur";
734 folder = m_getfolder ();
735 maildir = m_maildir (folder);
737 if (chdir (maildir) == NOTOK)
738 adios (maildir, "unable to change directory to");
739 if (!(mp = m_gmsg (folder)))
740 adios (NULLCP, "unable to read folder %s", folder);
741 if (mp -> hghmsg == 0)
742 adios (NULLCP, "no messages in %s", folder);
744 for (msgnum = 0; msgnum < msgp; msgnum++)
745 if (!m_convert (mp, msgs[msgnum]))
749 if ((cts = (CT *) calloc ((unsigned) (mp -> numsel + 1), sizeof *cts))
751 adios (NULLCP, "out of memory");
754 for (msgnum = mp -> lowsel; msgnum <= mp -> hghsel; msgnum++)
755 if (mp -> msgstats[msgnum] & SELECTED) {
758 if ((fp = fopen (msgnam = m_name (msgnum), "r")) == NULL)
759 adios (msgnam, "unable to read message");
761 if (ct = get_content (fp, msgnam, 1)) {
763 if (ct -> c_end == 0L) {
764 (void) fseek (fp, 0L, 2);
765 ct -> c_end = ftell (fp);
767 if (ct -> c_ctinitfnx && (*ct -> c_ctinitfnx) (ct) == NOTOK)
773 advise (NULLCP, "unable to decode message %s", msgnam);
782 if (!listsw && !showsw && !storesw && !cachesw)
785 /* listsw && showsw -> user wants per-message listing,
786 so delay until showsw processing
788 && storesw && sizesw -> evaluating size will cause more work,
789 so delay until after storesw processing
792 (void) signal (SIGQUIT, quitser);
793 (void) signal (SIGPIPE, pipeser);
795 for (ctp = cts; ct = *ctp; ctp++)
797 && (ct -> c_ctlistfnx
798 || ct -> c_ctstorefnx
799 || ct -> c_ctshowfnx)) {
803 ct -> c_umask = ~(stat (ct -> c_file, &st) != NOTOK
804 ? (st.st_mode & 0777) : m_gmprot ());
807 if (listsw && !showsw && (!storesw || !sizesw)) {
809 printf (LSTFMT1, "msg", "part", "type/subtype", "size",
812 for (ctp = cts; ct = *ctp; ctp++)
813 if (type_ok (ct, 1) && ct -> c_ctlistfnx) {
814 (void) umask (ct -> c_umask);
815 (void) (*ct -> c_ctlistfnx) (ct, 1);
817 (void) fclose (ct -> c_fp), ct -> c_fp = NULL;
818 if (ct -> c_ceclosefnx)
819 (*ct -> c_ceclosefnx) (ct);
826 for (ctp = cts; ct = *ctp; ctp++)
827 if (type_ok (ct, 1) && ct -> c_ctstorefnx) {
828 (void) umask (ct -> c_umask);
829 (void) (*ct -> c_ctstorefnx) (ct, NULLCP);
831 (void) fclose (ct -> c_fp), ct -> c_fp = NULL;
832 if (ct -> c_ceclosefnx)
833 (*ct -> c_ceclosefnx) (ct);
840 for (ctp = cts; ct = *ctp; ctp++)
841 if (type_ok (ct, 1)) {
844 (void) fclose (ct -> c_fp), ct -> c_fp = NULL;
845 if (ct -> c_ceclosefnx)
846 (*ct -> c_ceclosefnx) (ct);
852 if (listsw && !showsw && storesw && sizesw) {
854 printf (LSTFMT1, "msg", "part", "type/subtype", "size",
857 for (ctp = cts; ct = *ctp; ctp++)
858 if (type_ok (ct, 1) && ct -> c_ctlistfnx) {
859 (void) umask (ct -> c_umask);
860 (void) (*ct -> c_ctlistfnx) (ct, 1);
862 (void) fclose (ct -> c_fp), ct -> c_fp = NULL;
863 if (ct -> c_ceclosefnx)
864 (*ct -> c_ceclosefnx) (ct);
872 for (ctp = cts; ct = *ctp; ctp++) {
873 #if defined(BSD42) && !defined(WAITINT)
878 TYPESIG (*hstat) (), (*istat) (), (*qstat) (), (*tstat) ();
880 if (!type_ok (ct, 0))
883 (void) umask (ct -> c_umask);
887 printf (LSTFMT1, "msg", "part", "type/subtype", "size",
890 if (ct -> c_ctlistfnx)
891 (void) (*ct -> c_ctlistfnx) (ct, 1);
894 if (!ct -> c_ctshowfnx) {
896 (void) fclose (ct -> c_fp), ct -> c_fp = NULL;
897 if (ct -> c_ceclosefnx)
898 (*ct -> c_ceclosefnx) (ct);
902 if (strcmp (formsw, "mhl.null")) {
909 vec[vecp++] = r1bindex (mhlproc, '/');
910 vec[vecp++] = "-form";
911 vec[vecp++] = formsw;
912 vec[vecp++] = "-nobody";
913 vec[vecp++] = ct -> c_file;
915 vec[vecp++] = "-nomoreproc";
918 vec[vecp++] = "-moreproc";
919 vec[vecp++] = progsw;
923 (void) fflush (stdout);
925 for (i = 0; (child_id = vfork ()) == NOTOK && i < 5; i++)
929 adios ("fork", "unable to");
933 (void) execvp (mhlproc, vec);
934 fprintf (stderr, "unable to exec ");
947 (void) (*ct -> c_ctshowfnx) (ct, 1, 0);
949 (void) fclose (ct -> c_fp), ct -> c_fp = NULL;
950 if (ct -> c_ceclosefnx)
951 (*ct -> c_ceclosefnx) (ct);
953 hstat = signal (SIGHUP, SIG_IGN);
954 istat = signal (SIGINT, SIG_IGN);
955 qstat = signal (SIGQUIT, SIG_IGN);
956 tstat = signal (SIGTERM, SIG_IGN);
958 while (wait (&status) != NOTOK) {
959 #if defined(BSD42) && !defined(WAITINT)
960 (void) pidcheck (status.w_status);
962 (void) pidcheck (status);
967 (void) signal (SIGHUP, hstat);
968 (void) signal (SIGINT, istat);
969 (void) signal (SIGQUIT, qstat);
970 (void) signal (SIGTERM, tstat);
977 for (ctp = cts; *ctp; ctp++)
983 m_replace (pfolder, folder);
984 if (mp -> hghsel != mp -> curmsg)
985 m_setcur (mp, mp -> hghsel);
996 static TYPESIG pipeser (i)
1000 (void) unlink ("core");
1002 (void) fflush (stdout);
1004 fprintf (stderr, "\n");
1005 (void) fflush (stderr);
1014 #include "../h/mhn.h"
1024 static int InitApplication (), InitMessage (), InitMultiPart (), InitText (),
1028 static struct str2init str2cts[] = {
1029 "application", CT_APPLICATION, InitApplication,
1030 "audio", CT_AUDIO, InitGeneric,
1031 "image", CT_IMAGE, InitGeneric,
1032 "message", CT_MESSAGE, InitMessage,
1033 "multipart", CT_MULTIPART, InitMultiPart,
1034 "text", CT_TEXT, InitText,
1035 "video", CT_VIDEO, InitGeneric,
1037 NULL, CT_EXTENSION, NULL, /* these two must be last! */
1038 NULL, CT_UNKNOWN, NULL,
1042 static int InitBase64 (), InitQuoted (), Init7Bit ();
1044 static struct str2init str2ces[] = {
1045 "base64", CE_BASE64, InitBase64,
1046 "quoted-printable", CE_QUOTED, InitQuoted,
1047 "8bit", CE_8BIT, Init7Bit,
1048 "7bit", CE_7BIT, Init7Bit,
1049 "binary", CE_BINARY, NULL,
1051 NULL, CE_EXTENSION, NULL, /* these two must be last! */
1052 NULL, CE_UNKNOWN, NULL,
1057 static CT get_content (in, file, toplevel)
1068 if ((ct = (CT) calloc (1, sizeof *ct)) == NULL)
1069 adios (NULLCP, "out of memory");
1071 ct -> c_begin = ftell (ct -> c_fp = in) + 1;
1072 ct -> c_file = add (file, NULLCP);
1073 for (compnum = 1, state = FLD;;) {
1074 switch (state = m_getfld (state, name, buf, sizeof buf, in)) {
1080 if (uleq (name, VRSN_FIELD)) {
1086 cp = add (buf, NULLCP);
1087 while (state == FLDPLUS) {
1088 state = m_getfld (state, name, buf, sizeof buf, in);
1095 "message %s has multiple %s: fields (%s)",
1096 ct -> c_file, VRSN_FIELD, dp = trimcpy (cp));
1107 while (isspace (*cp))
1109 for (dp = index (cp, '\n'); dp; dp = index (dp, '\n'))
1111 for (dp = cp + strlen (cp) - 1; dp >= cp; dp--)
1116 fprintf (stderr, "%s: %s\n", VRSN_FIELD, cp);
1118 if (*cp == '(' && get_comment (ct, &cp, 0) == NOTOK)
1121 for (dp = cp; istoken (*dp); dp++)
1123 c = *dp, *dp = '\0';
1124 ucmp = uleq (cp, VRSN_VALUE);
1128 "message %s has unknown value for %s: field (%s)",
1129 ct -> c_file, VRSN_FIELD, cp);
1133 if (uleq (name, TYPE_FIELD)) {
1135 register struct str2init *s2i;
1136 register CI ci = &ct -> c_ctinfo;
1138 cp = add (buf, NULLCP);
1139 while (state == FLDPLUS) {
1140 state = m_getfld (state, name, buf, sizeof buf, in);
1144 if (ct -> c_ctline) {
1145 char *dp = trimcpy (cp);
1148 "message %s has multiple %s: fields (%s)",
1149 ct -> c_file, TYPE_FIELD, dp);
1155 if (get_ctinfo (cp, ct, 0) == NOTOK)
1157 for (s2i = str2cts; s2i -> si_key; s2i++)
1158 if (uleq (ci -> ci_type, s2i -> si_key))
1160 if (!s2i -> si_key && !uprf (ci -> ci_type, "X-"))
1162 ct -> c_type = s2i -> si_val;
1163 ct -> c_ctinitfnx = s2i -> si_init;
1167 if (uleq (name, ENCODING_FIELD)) {
1171 register struct str2init *s2i;
1173 cp = add (buf, NULLCP);
1174 while (state == FLDPLUS) {
1175 state = m_getfld (state, name, buf, sizeof buf, in);
1179 if (ct -> c_celine) {
1181 "message %s has multiple %s: fields (%s)",
1182 ct -> c_file, ENCODING_FIELD,
1189 ct -> c_celine = cp;
1190 while (isspace (*cp))
1192 for (dp = cp; istoken (*dp); dp++)
1194 c = *dp, *dp = '\0';
1195 for (s2i = str2ces; s2i -> si_key; s2i++)
1196 if (uleq (cp, s2i -> si_key))
1198 if (!s2i -> si_key && !uprf (cp, "X-"))
1201 ct -> c_encoding = s2i -> si_val;
1202 if (s2i -> si_init && (*s2i -> si_init) (ct) == NOTOK)
1207 if (uleq (name, ID_FIELD)) {
1208 ct -> c_id = add (buf, ct -> c_id);
1209 while (state == FLDPLUS) {
1210 state = m_getfld (state, name, buf, sizeof buf, in);
1211 ct -> c_id = add (buf, ct -> c_id);
1216 if (uleq (name, DESCR_FIELD)) {
1217 ct -> c_descr = add (buf, ct -> c_descr);
1218 while (state == FLDPLUS) {
1219 state = m_getfld (state, name, buf, sizeof buf, in);
1220 ct -> c_descr = add (buf, ct -> c_descr);
1225 if (uleq (name, MD5_FIELD)) {
1230 cp = add (buf, NULLCP);
1231 while (state == FLDPLUS) {
1232 state = m_getfld (state, name, buf, sizeof buf, in);
1241 if (ct -> c_digested) {
1243 "message %s has multiple %s: fields (%s)",
1244 ct -> c_file, MD5_FIELD,
1252 while (isspace (*cp))
1254 for (dp = index (cp, '\n'); dp; dp = index (dp, '\n'))
1256 for (dp = cp + strlen (cp) - 1; dp >= cp; dp--)
1261 fprintf (stderr, "%s: %s\n", MD5_FIELD, cp);
1263 if (*cp == '(' && get_comment (ct, &cp, 0) == NOTOK) {
1268 for (dp = cp; *dp && !isspace (*dp); dp++)
1272 (void) readDigest (ct, cp);
1279 if (uprf (name, XXX_FIELD_PRF))
1280 advise (NULLCP, "unknown field (%s) in message %s",
1281 name, ct -> c_file);
1285 while (state == FLDPLUS)
1286 state = m_getfld (state, name, buf, sizeof buf, in);
1288 if (state != FLDEOF) {
1289 ct -> c_begin = ftell (in) + 1;
1296 ct -> c_begin = ftell (in) - strlen (buf);
1300 ct -> c_begin = ftell (in);
1305 adios (NULLCP, "message format error in component #%d",
1309 adios (NULLCP, "getfld() returned %d", state);
1314 if (!ct -> c_ctline) {
1316 if (get_ctinfo ("message/rfc822", ct, 0) == NOTOK)
1318 ct -> c_type = CT_MESSAGE;
1319 ct -> c_ctinitfnx = InitMessage;
1322 if (get_ctinfo ("text/plain", ct, 0) == NOTOK)
1324 ct -> c_type = CT_TEXT;
1325 ct -> c_ctinitfnx = InitText;
1328 if (!ct -> c_ctlistfnx)
1329 ct -> c_ctlistfnx = list_content;
1330 if (!ct -> c_ctshowfnx)
1331 ct -> c_ctshowfnx = show_content;
1332 if (!ct -> c_ctstorefnx)
1333 ct -> c_ctstorefnx = store_content;
1335 if (!ct -> c_celine) {
1336 ct -> c_encoding = CE_7BIT;
1337 (void) Init7Bit (ct);
1349 static int get_ctinfo (cp, ct, magic)
1354 int i = strlen (invo_name) + 2;
1359 register CI ci = &ct -> c_ctinfo;
1361 cp = ct -> c_ctline = add (cp, NULLCP);
1362 while (isspace (*cp))
1364 for (dp = index (cp, '\n'); dp; dp = index (dp, '\n'))
1366 for (dp = cp + strlen (cp) - 1; dp >= cp; dp--)
1371 fprintf (stderr, "%s: %s\n", TYPE_FIELD, cp);
1373 if (*cp == '(' && get_comment (ct, &cp, 1) == NOTOK)
1376 for (dp = cp; istoken (*dp); dp++)
1378 c = *dp, *dp = '\0';
1379 ci -> ci_type = add (cp, NULLCP);
1382 if (!*ci -> ci_type) {
1383 advise (NULLCP, "invalid %s: field in message %s (empty type)",
1384 TYPE_FIELD, ct -> c_file);
1388 for (dp = ci -> ci_type; *dp; dp++)
1389 if (isalpha(*dp) && isupper (*dp))
1390 *dp = tolower (*dp);
1392 while (isspace (*cp))
1395 if (*cp == '(' && get_comment (ct, &cp, 1) == NOTOK)
1400 ci -> ci_subtype = add ("", NULLCP);
1405 while (isspace (*cp))
1408 if (*cp == '(' && get_comment (ct, &cp, 1) == NOTOK)
1411 for (dp = cp; istoken (*dp); dp++)
1413 c = *dp, *dp = '\0';
1414 ci -> ci_subtype = add (cp, NULLCP);
1417 if (!*ci -> ci_subtype) {
1419 "invalid %s: field in message %s (empty subtype for \"%s\")",
1420 TYPE_FIELD, ct -> c_file, ci -> ci_type);
1424 for (dp = ci -> ci_subtype; *dp; dp++)
1425 if (isalpha(*dp) && isupper (*dp))
1426 *dp = tolower (*dp);
1429 while (isspace (*cp))
1432 if (*cp == '(' && get_comment (ct, &cp, 1) == NOTOK)
1435 ep = (ap = ci -> ci_attrs) + NPARMS;
1436 while (*cp == ';') {
1442 "too many parameters in message %s's %s: field (%d max)",
1443 ct -> c_file, TYPE_FIELD, NPARMS);
1448 while (isspace (*cp))
1451 if (*cp == '(' && get_comment (ct, &cp, 1) == NOTOK)
1456 "extraneous trailing ';' in message %s's %s: parameter list",
1457 ct -> c_file, TYPE_FIELD);
1461 for (dp = cp; istoken (*dp); dp++)
1462 if (isalpha(*dp) && isupper (*dp))
1463 *dp = tolower (*dp);
1464 for (up = dp; isspace (*dp); )
1466 if (dp == cp || *dp != '=') {
1468 "invalid parameter in message %s's %s: field\n%*.*sparameter %s (error detected at offset %d)",
1469 ct -> c_file, TYPE_FIELD, i, i, "", cp, dp - cp);
1473 vp = (*ap = add (cp, NULLCP)) + (up - cp);
1475 for (dp++; isspace (*dp); )
1477 ci -> ci_values[ap - ci -> ci_attrs] = vp = *ap + (dp - cp);
1479 for (cp = ++dp, dp = vp;;) {
1480 switch (c = *cp++) {
1484 "invalid quoted-string in message %s's %s: field\n%*.*s(parameter %s)",
1485 ct -> c_file, TYPE_FIELD, i, i, "", *ap);
1490 if ((c = *cp++) == '\0')
1506 for (cp = dp, dp = vp; istoken (*cp); cp++, dp++)
1512 "invalid parameter in message %s's %s: field\n%*.*s(parameter %s)",
1513 ct -> c_file, TYPE_FIELD, i, i, "", *ap);
1518 while (isspace (*cp))
1521 if (*cp == '(' && get_comment (ct, &cp, 1) == NOTOK)
1525 if (magic && *cp == '<') {
1527 free (ct -> c_id), ct -> c_id = NULL;
1529 if (!(dp = index (ct -> c_id = ++cp, '>'))) {
1530 advise (NULLCP, "invalid ID in message %s", ct -> c_file);
1534 c = *dp, *dp = '\0';
1536 ct -> c_id = concat ("<", ct -> c_id, ">\n", NULLCP);
1541 while (isspace (*cp))
1545 if (magic && *cp == '[') {
1546 ct -> c_descr = ++cp;
1547 for (dp = cp + strlen (cp) - 1; dp >= cp; dp--)
1551 advise (NULLCP, "invalid description in message %s", ct -> c_file);
1552 ct -> c_descr = NULL;
1556 c = *dp, *dp = '\0';
1558 ct -> c_descr = concat (ct -> c_descr, "\n", NULLCP);
1560 ct -> c_descr = NULL;
1563 while (isspace (*cp))
1569 ci -> ci_magic = add (cp, NULLCP);
1572 "extraneous information in message %s's %s: field\n%*.*s(%s)",
1573 ct -> c_file, TYPE_FIELD, i, i, "", cp);
1581 static int get_comment (ct, ap, istype)
1592 register CI ci = &ct -> c_ctinfo;
1599 switch (c = *cp++) {
1602 advise (NULLCP, "invalid comment in message %s's %s: field",
1603 ct -> c_file, istype ? TYPE_FIELD : VRSN_FIELD);
1608 if ((c = *cp++) == '\0')
1631 if (dp = ci -> ci_comment) {
1632 ci -> ci_comment = concat (dp, " ", buffer, NULLCP);
1636 ci -> ci_comment = add (buffer, NULLCP);
1639 while (isspace (*cp))
1649 #define empty(s) ((s) ? (s) : "")
1652 static int list_content (ct, toplevel)
1661 register CI ci = &ct -> c_ctinfo;
1663 printf (toplevel > 0 ? LSTFMT2a : toplevel < 0 ? "part " : " ",
1664 atoi (r1bindex (empty (ct -> c_file), '/')));
1665 (void) sprintf (buffer, "%s/%s", empty (ci -> ci_type),
1666 empty (ci -> ci_subtype));
1667 printf (LSTFMT2b, empty (ct -> c_partno), buffer);
1669 size = ct -> c_cesizefnx && sizesw ? (*ct -> c_cesizefnx) (ct)
1670 : ct -> c_end - ct -> c_begin;
1672 for (cp = " KMGT"; size > 9999; size >>= 10)
1677 if (size > 0 || ct -> c_encoding != CE_EXTERNAL)
1678 printf (LSTFMT2c1, size);
1684 printf (LSTFMT2c2, size, *cp);
1691 if (ct -> c_descr) {
1694 dp = trimcpy (cp = add (ct -> c_descr, NULLCP));
1696 printf (LSTFMT2d1, dp);
1702 if (verbosw && ci -> ci_comment) {
1705 dp = trimcpy (cp = add (ci -> ci_comment, NULLCP));
1707 (void) sprintf (buffer, "(%s)", dp);
1709 printf (LSTFMT2d2, buffer);
1715 (void) fflush (stdout);
1717 fprintf (stderr, " partno \"%s\"\n", empty (ct -> c_partno));
1720 fprintf (stderr, " %s:%s\n", VRSN_FIELD, ct -> c_vrsn);
1723 fprintf (stderr, " %s:%s", TYPE_FIELD, ct -> c_ctline);
1725 " type \"%s\" subtype \"%s\" comment \"%s\" magic \"%s\"\n",
1726 empty (ci -> ci_type), empty (ci -> ci_subtype),
1727 empty (ci -> ci_comment), empty (ci -> ci_magic));
1728 for (ap = ci -> ci_attrs, ep = ci -> ci_values; *ap; ap++, ep++)
1729 fprintf (stderr, " parameter %s=\"%s\"\n", *ap, *ep);
1731 " type 0x%x subtype 0x%x params 0x%x\n",
1732 ct -> c_type, ct -> c_subtype, ct -> c_ctparams);
1734 fprintf (stderr, " showproc \"%s\"\n", empty (ct -> c_showproc));
1735 fprintf (stderr, " termproc \"%s\"\n", empty (ct -> c_termproc));
1736 fprintf (stderr, " storeproc \"%s\"\n", empty (ct -> c_storeproc));
1739 fprintf (stderr, " %s:%s", ENCODING_FIELD, ct -> c_celine);
1740 fprintf (stderr, " encoding 0x%x params 0x%x\n",
1741 ct -> c_encoding, ct -> c_ceparams);
1744 fprintf (stderr, " %s:%s", ID_FIELD, ct -> c_id);
1746 fprintf (stderr, " %s:%s", DESCR_FIELD, ct -> c_descr);
1748 fprintf (stderr, " fp 0x%x file \"%s\" begin %d end %d\n",
1749 ct -> c_fp, empty (ct -> c_file), ct -> c_begin, ct -> c_end);
1751 if (ct -> c_celistfnx)
1752 (void) (*ct -> c_celistfnx) (ct);
1764 #include <varargs.h>
1770 static void content_error (char *what, register CT ct, char *fmt, ...)
1772 static void content_error (va_alist)
1775 #else /* !VSPRINTF */
1777 static void content_error (what, ct, fmt, a, b, c, d, e, f)
1792 #if defined(VSPRINTF) && !defined(__STDC__)
1798 char buffer[BUFSIZ];
1803 if (userrs && invo_name && *invo_name) {
1804 (void) sprintf (bp, "%s: ", invo_name);
1810 va_start (arglist, fmt);
1813 what = va_arg(arglist, char *);
1814 ct = va_arg(arglist, CT);
1815 fmt = va_arg(arglist, char *);
1817 (void) vsprintf (bp, fmt, arglist);
1820 (void) sprintf (bp, fmt, a, b, c, d, e, f);
1823 ci = &ct -> c_ctinfo;
1827 (void) sprintf (bp, " %s: ", what);
1831 if (errno > 0 && errno < sys_nerr)
1832 (void) sprintf (bp, "%s", sys_errlist[errno]);
1834 (void) sprintf (bp, "Error %d", errno);
1838 i = strlen (invo_name) + 2;
1839 (void) sprintf (bp, "\n%*.*s(content %s/%s", i, i, "", ci -> ci_type,
1843 (void) sprintf (bp, " in message %s", ct -> c_file);
1845 if (ct -> c_partno) {
1846 (void) sprintf (bp, ", part %s", ct -> c_partno);
1850 (void) sprintf (bp, ")");
1857 errs = add (buffer, errs);
1860 advise (NULLCP, "%s", buffer);
1864 static void flush_errors ()
1867 (void) fflush (stdout);
1868 fprintf (stderr, "%s", errs);
1876 static jmp_buf intrenv;
1881 static TYPESIG intrser (i)
1885 (void) signal (SIGINT, intrser);
1888 (void) putchar ('\n');
1890 longjmp (intrenv, DONE);
1895 static int show_content_aux (), show_content_aux2 ();
1898 static int show_content (ct, serial, alternate)
1904 char buffer[BUFSIZ];
1905 register CI ci = &ct -> c_ctinfo;
1907 (void) sprintf (buffer, "%s-show-%s/%s", invo_name, ci -> ci_type,
1909 if ((cp = m_find (buffer)) == NULL || *cp == 0) {
1910 (void) sprintf (buffer, "%s-show-%s", invo_name, ci -> ci_type);
1911 if (((cp = m_find (buffer)) == NULL || *cp == 0)
1912 && (cp = ct -> c_showproc) == NULL) {
1914 content_error (NULLCP, ct,
1915 "don't know how to display content");
1921 return show_content_aux (ct, serial, alternate, cp, NULLCP);
1925 static int show_content_aux (ct, serial, alternate, cp, cracked)
1940 register CI ci = &ct -> c_ctinfo;
1942 if (!ct -> c_ceopenfnx) {
1944 content_error (NULLCP, ct, "don't know how to decode content");
1950 if ((fd = (*ct -> c_ceopenfnx) (ct, &file)) == NOTOK)
1952 if (ct -> c_showproc && strcmp (ct -> c_showproc, "true") == 0)
1953 return (alternate ? DONE : OK);
1955 xlist = xpause = xstdin = xtty = 0;
1957 (void) strcpy (buffer, cp);
1961 for (bp = buffer; *cp; cp++)
1964 case 'a': /* additional arguments */
1970 for (ap = ci -> ci_attrs, ep = ci -> ci_values;
1973 (void) sprintf (bp, "%s%s=\"%s\"", s, *ap, *ep);
1980 case 'd': /* content description */
1981 if (ct -> c_descr) {
1984 (void) strcpy (bp, s = trimcpy (ct -> c_descr));
1989 case 'e': /* exclusive execution */
1993 case 'F': /* %e, %f, and stdin is terminal not content */
1996 case 'f': /* filename */
1997 (void) sprintf (bp, "%s", file);
2000 case 'p': /* pause prior to displaying content */
2003 case 'l': /* display listing prior to displaying
2008 case 's': /* subtype */
2009 (void) strcpy (bp, ci -> ci_subtype);
2027 if (ct -> c_termproc) {
2030 (void) strcpy (term, buffer);
2031 (void) sprintf (buffer, ct -> c_termproc, term);
2035 return show_content_aux2 (ct, serial, alternate, cracked, buffer,
2036 fd, xlist, xpause, xstdin, xtty);
2040 static int show_content_aux2 (ct, serial, alternate, cracked, buffer,
2041 fd, xlist, xpause, xstdin, xtty)
2056 exec[BUFSIZ + sizeof "exec "];
2057 register CI ci = &ct -> c_ctinfo;
2059 if (debugsw || cracked) {
2060 (void) fflush (stdout);
2062 fprintf (stderr, "%s msg %s", cracked ? "storing" : "show",
2065 fprintf (stderr, " part %s", ct -> c_partno);
2067 fprintf (stderr, " using command (cd %s; %s)\n", cracked, buffer);
2069 fprintf (stderr, " using command %s\n", buffer);
2072 if (xpid < 0 || (xtty && xpid)) {
2075 (void) pidcheck (pidwait (xpid, NOTOK));
2080 char prompt[BUFSIZ];
2082 if (ct -> c_ctlistfnx) {
2083 if (ct -> c_type == CT_MULTIPART)
2084 (void) list_content (ct, -1);
2086 (*ct -> c_ctlistfnx) (ct, -1);
2088 if (xpause && SOprintf ("Press <return> to show content..."))
2089 printf ("Press <return> to show content...");
2095 if (ct -> c_descr) {
2096 (void) sprintf (pp, "%s (", ct -> c_descr);
2100 (void) sprintf (pp, "content %s/%s", ci -> ci_type,
2104 (void) sprintf (pp, " in message %s", ct -> c_file);
2106 if (ct -> c_partno) {
2107 (void) sprintf (pp, ", part %s", ct -> c_partno);
2112 if (ct -> c_descr) {
2113 (void) sprintf (pp, ")");
2118 printf ("%s\n", prompt);
2120 if (SOprintf ("Press <return> to show %s...", prompt))
2121 printf ("Press <return> to show %s...", prompt);
2126 TYPESIG (*istat) ();
2128 istat = signal (SIGINT, intrser);
2129 if ((intr = setjmp (intrenv)) == OK) {
2130 (void) fflush (stdout);
2132 (void) read (fileno (stdout), prompt, sizeof prompt);
2134 (void) signal (SIGINT, istat);
2135 if (intr != OK || prompt[0] == 'q') {
2136 (void) (*ct -> c_ceclosefnx) (ct);
2137 return (alternate ? DONE : NOTOK);
2142 (void) sprintf (exec, "exec %s", buffer);
2149 (void) fflush (stdout);
2151 for (i = 0; (child_id = vfork ()) == NOTOK && i < 5; i++)
2155 advise ("fork", "unable to");
2156 (void) (*ct -> c_ceclosefnx) (ct);
2161 (void) chdir (cracked);
2163 (void) dup2 (fd, 0);
2165 (void) execvp ("/bin/sh", vec);
2166 fprintf (stderr, "unable to exec ");
2173 ct -> c_pid = child_id;
2178 (void) pidcheck (pidXwait (child_id, NULLCP));
2181 (void) (*ct -> c_ceclosefnx) (ct);
2182 return (alternate ? DONE : OK);
2188 static int store_content (ct, append)
2192 int appending = append && *append;
2199 register CI ci = &ct -> c_ctinfo;
2203 (void) strcpy (buffer, append);
2207 if ((cp = ct -> c_storeproc) == NULL || *cp == 0) {
2208 (void) sprintf (buffer, "%s-store-%s/%s", invo_name, ci -> ci_type,
2210 if ((cp = m_find (buffer)) == NULL || *cp == 0) {
2211 (void) sprintf (buffer, "%s-store-%s", invo_name, ci -> ci_type);
2212 if ((cp = m_find (buffer)) == NULL || *cp == 0)
2213 cp = ct -> c_type == CT_MESSAGE ? "+" : "%m%P.%s";
2221 char *folder = cp[1] ? path (cp + 1, *cp == '+' ? TFOLDER
2224 struct msgs *mp = NULL;
2227 if (stat (bp = m_mailpath (folder), &st) == NOTOK) {
2231 if (errno != ENOENT) {
2232 advise (bp, "error on folder");
2236 ep = concat ("Create folder \"", bp, "\"? ", NULLCP);
2237 answer = getanswer (ep);
2242 if (!makedir (bp)) {
2243 advise (NULLCP, "unable to create folder %s", bp);
2248 if (mp = m_gmsg (folder))
2249 (void) sprintf (buffer, "%s/%d", mp -> foldpath,
2252 advise (NULLCP, "unable to read folder %s", folder);
2271 bp = autosw ? cwd : dir;
2272 (void) sprintf (buffer, "%s/", bp[1] ? bp : "");
2273 bp = buffer + strlen (buffer);
2279 case 'a': /* additional arguments */
2280 if (buffer[0] != '|' && buffer[0] != '!') {
2290 for (ap = ci -> ci_attrs, ep = ci -> ci_values;
2293 (void) sprintf (bp, "%s%s=\"%s\"", s, *ap, *ep);
2300 case 'm': /* message */
2301 (void) sprintf (bp, "%s", r1bindex (ct -> c_file, '/'));
2304 case 'P': /* .part */
2306 (void) sprintf (bp, ".%s", ct -> c_partno);
2309 case 'p': /* part */
2311 (void) strcpy (bp, ct -> c_partno);
2314 case 't': /* type */
2315 (void) strcpy (bp, ci -> ci_type);
2318 case 's': /* subtype */
2319 (void) strcpy (bp, ci -> ci_subtype);
2337 if (buffer[0] == '|' || buffer[0] == '!')
2338 return show_content_aux (ct, 1, 0, buffer + 1, autosw ? cwd : dir);
2341 ct -> c_storage = add (buffer, NULLCP);
2342 (void) fflush (stdout);
2343 fprintf (stderr, "storing message %s", ct -> c_file);
2345 fprintf (stderr, " part %s", ct -> c_partno);
2346 fprintf (stderr, " as file %s\n",
2347 strncmp (ct -> c_storage, cwd, cwdlen)
2348 || ct -> c_storage[cwdlen] != '/'
2349 ? ct -> c_storage : ct -> c_storage + cwdlen + 1);
2350 if (index (ct -> c_storage, '/')
2351 && make_intermediates (ct -> c_storage) == NOTOK)
2354 if (ct -> c_encoding != CE_7BIT) {
2358 if (!ct -> c_ceopenfnx) {
2359 advise (NULLCP, "don't know how to decode part %s of message %s",
2360 ct -> c_partno, ct -> c_file);
2364 file = appending || !strcmp (ct -> c_storage, "-") ? NULLCP
2366 if ((fd = (*ct -> c_ceopenfnx) (ct, &file)) == NOTOK)
2368 if (strcmp (file, ct -> c_storage) == 0) {
2369 (void) (*ct -> c_ceclosefnx) (ct);
2373 if (!strcmp (ct -> c_storage, "-")) {
2376 if ((gd = dup (fileno (stdout))) == NOTOK) {
2377 advise ("stdout", "unable to dup");
2379 (void) (*ct -> c_ceclosefnx) (ct);
2382 if ((fp = fdopen (gd, appending ? "a" : "w")) == NULL) {
2383 advise ("stdout", "unable to fdopen (%d, \"%s\") from", gd,
2384 appending ? "a" : "w");
2390 if ((fp = fopen (ct -> c_storage, appending ? "a" : "w"))
2392 advise (ct -> c_storage, "unable to fopen for %s",
2393 appending ? "appending" : "writing");
2397 if (append && !*append)
2398 (void) copy_some_headers (fp, ct);
2401 switch (cc = read (fd, buffer, sizeof buffer)) {
2403 advise (file, "error reading content from");
2410 (void) fwrite (buffer, sizeof *buffer, cc, fp);
2416 (void) (*ct -> c_ceclosefnx) (ct);
2418 if (cc != NOTOK && fflush (fp))
2419 advise (ct -> c_storage, "error writing to");
2423 return (cc != NOTOK ? OK : NOTOK);
2426 if (!ct -> c_fp && (ct -> c_fp = fopen (ct -> c_file, "r")) == NULL) {
2427 advise (ct -> c_file, "unable to open for reading");
2431 (void) fseek (ct -> c_fp, pos = ct -> c_begin, 0);
2434 if (!strcmp (ct -> c_storage, "-")) {
2437 if ((gd = dup (fileno (stdout))) == NOTOK) {
2438 advise ("stdout", "unable to dup");
2441 if ((fp = fdopen (gd, appending ? "a" : "w")) == NULL) {
2442 advise ("stdout", "unable to fdopen (%d, \"%s\") from", gd,
2443 appending ? "a" : "w");
2449 if ((fp = fopen (ct -> c_storage, appending ? "a" : "w")) == NULL) {
2450 advise (ct -> c_storage, "unable to fopen for %s",
2451 appending ? "appending" : "writing");
2455 if (append && !*append) {
2456 (void) copy_some_headers (fp, ct);
2462 while (fgets (buffer, sizeof buffer - 1, ct -> c_fp)) {
2463 if ((pos += strlen (buffer)) > last) {
2464 int diff = strlen (buffer) - (pos - last);
2467 buffer[diff] = '\0';
2471 switch (buffer[0]) {
2483 if (!uprf (buffer, XXX_FIELD_PRF)
2484 && !uprf (buffer, "Encrypted:")
2485 && !uprf (buffer, "Message-ID:")) {
2494 (void) fputs (buffer, fp);
2500 advise (ct -> c_storage, "error writing to");
2504 (void) fclose (ct -> c_fp), ct -> c_fp = NULL;
2510 static int copy_some_headers (out, ct)
2519 if ((in = fopen (ct -> c_file, "r")) == NULL) {
2520 advise (ct -> c_file, "unable to open for reading");
2524 for (state = FLD;;) {
2525 switch (state = m_getfld (state, name, buf, sizeof buf, in)) {
2529 if (uprf (name, XXX_FIELD_PRF)
2530 || uleq (name, "Encrypted")
2531 || uleq (name, "Message-ID")) {
2532 while (state == FLDPLUS)
2533 state = m_getfld (state, name, buf, sizeof buf, in);
2537 fprintf (out, "%s:%s", name, buf);
2538 while (state == FLDPLUS) {
2539 state = m_getfld (state, name, buf, sizeof buf, in);
2540 (void) fputs (buf, out);
2542 if (state != FLDEOF)
2565 static int make_intermediates (file)
2570 for (cp = file + 1; cp = index (cp, '/'); cp++) {
2575 if (stat (file, &st) == NOTOK) {
2579 if (errno != ENOENT) {
2580 advise (file, "error on directory");
2586 ep = concat ("Create directory \"", file, "\"? ", NULLCP);
2587 answer = getanswer (ep);
2591 goto losing_directory;
2592 if (!makedir (file)) {
2593 advise (NULLCP, "unable to create directory %s", file);
2594 goto losing_directory;
2606 static void free_ctinfo (ct)
2610 register CI ci = &ct -> c_ctinfo;
2613 free (ci -> ci_type);
2614 ci -> ci_type = NULL;
2615 if (ci -> ci_subtype)
2616 free (ci -> ci_subtype);
2617 ci -> ci_subtype = NULL;
2618 for (ap = ci -> ci_attrs; *ap; ap++)
2619 free (*ap), *ap = NULL;
2620 if (ci -> ci_comment)
2621 free (ci -> ci_comment);
2622 ci -> ci_comment = NULL;
2624 free (ci -> ci_magic);
2625 ci -> ci_magic = NULL;
2629 static void free_content (ct)
2636 free (ct -> c_partno);
2637 ct -> c_partno = NULL;
2640 free (ct -> c_vrsn);
2641 ct -> c_vrsn = NULL;
2644 free (ct -> c_ctline);
2645 ct -> c_ctline = NULL;
2649 if (ct -> c_ctfreefnx)
2650 (void) (*ct -> c_ctfreefnx) (ct);
2651 ct -> c_ctfreefnx = NULL;
2653 if (ct -> c_showproc)
2654 free (ct -> c_showproc);
2655 ct -> c_showproc = NULL;
2656 if (ct -> c_termproc)
2657 free (ct -> c_termproc);
2658 ct -> c_termproc = NULL;
2659 if (ct -> c_storeproc)
2660 free (ct -> c_storeproc);
2661 ct -> c_storeproc = NULL;
2664 free (ct -> c_celine);
2665 ct -> c_celine = NULL;
2666 if (ct -> c_cefreefnx)
2667 (void) (*ct -> c_cefreefnx) (ct, 1);
2668 ct -> c_cefreefnx = NULL;
2674 free (ct -> c_descr);
2675 ct -> c_descr = NULL;
2679 (void) unlink (ct -> c_file);
2680 free (ct -> c_file);
2681 ct -> c_file = NULL;
2684 (void) fclose (ct -> c_fp);
2687 if (ct -> c_storage)
2688 (void) free (ct -> c_storage);
2689 ct -> c_storage = NULL;
2696 static int part_ok (ct, sP)
2702 if ((ct -> c_type == CT_MULTIPART && (sP || ct -> c_subtype))
2706 for (ap = parts; *ap; ap++)
2707 if (strcmp (*ap, ct -> c_partno) == 0)
2715 static int type_ok (ct, sP)
2720 char buffer[BUFSIZ];
2721 register CI ci = &ct -> c_ctinfo;
2723 if ((ct -> c_type == CT_MULTIPART && (sP || ct -> c_subtype))
2727 (void) sprintf (buffer, "%s/%s", ci -> ci_type, ci -> ci_subtype);
2728 for (ap = types; *ap; ap++)
2729 if (uleq (*ap, ci -> ci_type) || uleq (*ap, buffer))
2743 static int InitGeneric (ct)
2748 register CI ci = &ct -> c_ctinfo;
2750 for (ap = ci -> ci_attrs, ep = ci -> ci_values; *ap; ap++, ep++)
2751 if (autosw && !ct -> c_storeproc && uleq (*ap, "name")) {
2754 if (*(cp = *ep) != '/'
2758 && !index (cp, '%'))
2759 ct -> c_storeproc = add (cp, NULLCP);
2767 #define TEXT_UNKNOWN 0x00
2768 #define TEXT_PLAIN 0x01
2769 #define TEXT_RICHTEXT 0x02
2773 #define CHARSET_UNKNOWN 0x00
2774 #define CHARSET_USASCII 0x01
2775 #define CHARSET_LATIN 0x02
2778 static struct k2v Charset[] = {
2779 "us-ascii", CHARSET_USASCII,
2780 "iso-8859-1", CHARSET_LATIN,
2782 NULL, CHARSET_UNKNOWN /* this one must be last! */
2785 static int free_text (ct)
2788 register struct text *t = (struct text *) ct -> c_ctparams;
2794 ct -> c_ctparams = NULL;
2798 static struct k2v SubText[] = {
2799 "plain", TEXT_PLAIN,
2800 "richtext", TEXT_RICHTEXT,
2802 NULL, TEXT_UNKNOWN /* this one must be last! */
2805 static int InitText (ct)
2808 char buffer[BUFSIZ];
2811 register struct k2v *kv;
2812 register CI ci = &ct -> c_ctinfo;
2814 if (!*ci -> ci_subtype) /* XXX: attmail bogosity! */
2815 ci -> ci_subtype = add ("plain", ci -> ci_subtype);
2816 for (kv = SubText; kv -> kv_key; kv++)
2817 if (uleq (ci -> ci_subtype, kv -> kv_key))
2819 if ((ct -> c_subtype = kv -> kv_value) == TEXT_PLAIN) {
2820 (void) sprintf (buffer, "%%p%s '%%F'",
2822 : moreproc && *moreproc ? moreproc : "more");
2823 ct -> c_showproc = add (buffer, NULLCP);
2826 for (ap = ci -> ci_attrs, ep = ci -> ci_values; *ap; ap++, ep++)
2827 if (!ct -> c_ctparams && uleq (*ap, "charset")) {
2829 register struct text *t;
2831 if ((t = (struct text *) calloc (1, sizeof *t)) == NULL)
2832 adios (NULLCP, "out of memory");
2833 ct -> c_ctparams = (caddr_t) t;
2834 ct -> c_ctfreefnx = free_text;
2836 for (kv = Charset; kv -> kv_key; kv++)
2837 if (uleq (*ep, kv -> kv_key)) {
2838 (void) sprintf (buffer, "%s-charset-%s", invo_name,
2842 t -> tx_charset = kv -> kv_value;
2844 (void) sprintf (buffer, "%s-charset-%s", invo_name, *ep);
2845 if ((!mm_charset || !uleq (mm_charset, *ep))
2846 && (cp = m_find (buffer)))
2847 ct -> c_termproc = getcpy (cp);
2850 if (autosw && !ct -> c_storeproc && uleq (*ap, "name")) {
2853 if (*(cp = *ep) != '/'
2857 && !index (cp, '%'))
2858 ct -> c_storeproc = add (cp, NULLCP);
2866 #define MULTI_UNKNOWN 0x00
2867 #define MULTI_MIXED 0x01
2868 #define MULTI_ALTERNATE 0x02
2869 #define MULTI_DIGEST 0x03
2870 #define MULTI_PARALLEL 0x04
2880 struct part *mp_next;
2885 static int list_multi (ct, toplevel)
2889 register struct multipart *m = (struct multipart *) ct -> c_ctparams;
2890 register struct part *part;
2892 (void) list_content (ct, toplevel);
2894 for (part = m -> mp_parts; part; part = part -> mp_next) {
2895 register CT p = part -> mp_part;
2897 if (part_ok (p, 1) && type_ok (p, 1) && p -> c_ctlistfnx)
2898 (void) (*p -> c_ctlistfnx) (p, 0);
2905 static int show_multi (ct, serial, alternate)
2914 register struct multipart *m = (struct multipart *) ct -> c_ctparams;
2915 register struct part *part;
2917 TYPESIG (*hstat) (), (*istat) (), (*qstat) (), (*tstat) ();
2920 nowalternate = alternate;
2921 switch (ct -> c_subtype) {
2922 case MULTI_PARALLEL:
2923 if (!(nowserial = serialsw)) {
2925 hstat = signal (SIGHUP, SIG_IGN);
2926 istat = signal (SIGINT, SIG_IGN);
2927 qstat = signal (SIGQUIT, SIG_IGN);
2928 tstat = signal (SIGTERM, SIG_IGN);
2932 case MULTI_ALTERNATE:
2933 nowalternate = alternating = 1;
2936 if (!(nowserial = serial))
2941 /* alternate -> we're inside an alternative
2942 alternating -> we are an alternative
2945 result = alternate ? NOTOK : OK;
2946 for (part = m -> mp_parts; part; part = part -> mp_next) {
2947 p = part -> mp_part;
2949 if (part_ok (p, 0) && type_ok (p, 0) && p -> c_ctshowfnx) {
2952 switch (inneresult = (*p -> c_ctshowfnx) (p, nowserial,
2955 if (alternate && !alternating) {
2968 alternate = nowalternate = 0;
2969 if (result == NOTOK)
2970 result = inneresult;
2977 if (alternating && !part) {
2979 content_error (NULLCP, ct,
2980 "don't know how to display any of the contents");
2986 if (serial && !nowserial) {
2989 #if defined(BSD42) && !defined(WAITINT)
2996 for (part = m -> mp_parts; part; part = part -> mp_next) {
2997 p = part -> mp_part;
2999 if (p -> c_pid > OK)
3000 if (kill (p -> c_pid, 0) == NOTOK)
3006 while (kids > 0 && (pid = wait (&status)) != NOTOK) {
3007 #if defined(BSD42) && !defined(WAITINT)
3008 (void) pidcheck (status.w_status);
3010 (void) pidcheck (status);
3013 for (part = m -> mp_parts; part; part = part -> mp_next) {
3014 p = part -> mp_part;
3018 if (p -> c_pid == pid) {
3029 (void) signal (SIGHUP, hstat);
3030 (void) signal (SIGINT, istat);
3031 (void) signal (SIGQUIT, qstat);
3032 (void) signal (SIGTERM, tstat);
3039 static int show_unknown_multi (ct, serial, alternate)
3049 char buffer[BUFSIZ];
3050 register struct multipart *m = (struct multipart *) ct -> c_ctparams;
3051 register struct part *part;
3052 register CI ci = &ct -> c_ctinfo;
3055 (void) sprintf (buffer, "%s-show-%s/%s", invo_name, ci -> ci_type,
3057 if ((cp = m_find (buffer)) == NULL || *cp == 0) {
3058 (void) sprintf (buffer, "%s-show-%s", invo_name, ci -> ci_type);
3059 if (((cp = m_find (buffer)) == NULL || *cp == 0)
3060 && (cp = ct -> c_showproc) == NULL) {
3062 content_error (NULLCP, ct,
3063 "don't know how to display content");
3069 for (part = m -> mp_parts; part; part = part -> mp_next) {
3070 p = part -> mp_part;
3072 if (!p -> c_ceopenfnx) {
3074 content_error (NULLCP, p, "don't know how to decode content");
3079 if (p -> c_storage == NULL) {
3080 if ((*p -> c_ceopenfnx) (p, &p -> c_storage) == NOTOK)
3083 if (p -> c_showproc && strcmp (p -> c_showproc, "true") == 0)
3084 return (alternate ? DONE : OK);
3085 (*p -> c_ceclosefnx) (p);
3089 xlist = xpause = xtty = 0;
3091 for (bp = buffer; *cp; cp++)
3094 case 'a': /* additional arguments */
3100 for (ap = ci -> ci_attrs, ep = ci -> ci_values;
3103 (void) sprintf (bp, "%s%s=\"%s\"", s, *ap, *ep);
3110 case 'd': /* content description */
3111 if (ct -> c_descr) {
3114 (void) strcpy (bp, s = trimcpy (ct -> c_descr));
3119 case 'e': /* exclusive execution */
3123 case 'F': /* %e and %f */
3126 case 'f': /* filename(s) */
3130 for (part = m -> mp_parts;
3132 part = part -> mp_next) {
3133 p = part -> mp_part;
3135 (void) sprintf (bp, "%s'%s'", s, p -> c_storage);
3142 case 'p': /* pause prior to displaying content */
3145 case 'l': /* display listing prior to displaying
3150 case 's': /* subtype */
3151 (void) strcpy (bp, ci -> ci_subtype);
3169 if (ct -> c_termproc) {
3172 (void) strcpy (term, buffer);
3173 (void) sprintf (buffer, ct -> c_termproc, term);
3176 return show_content_aux2 (ct, serial, alternate, NULLCP, buffer,
3177 NOTOK, xlist, xpause, 0, xtty);
3183 static int store_multi (ct, unused)
3188 register struct multipart *m = (struct multipart *) ct -> c_ctparams;
3189 register struct part *part;
3192 for (part = m -> mp_parts; part; part = part -> mp_next) {
3193 register CT p = part -> mp_part;
3197 && p -> c_ctstorefnx
3198 && (result = (*p -> c_ctstorefnx) (p, NULLCP)) == OK
3199 && ct -> c_subtype == MULTI_ALTERNATE)
3207 static int free_multi (ct)
3210 register struct multipart *m = (struct multipart *) ct -> c_ctparams;
3211 register struct part *part,
3218 free (m -> mp_start);
3220 free (m -> mp_stop);
3222 for (part = m -> mp_parts; part; part = next) {
3223 next = part -> mp_next;
3225 free_content (part -> mp_part);
3227 free ((char *) part);
3229 m -> mp_parts = NULL;
3232 ct -> c_ctparams = NULL;
3236 static struct k2v SubMultiPart[] = {
3237 "mixed", MULTI_MIXED,
3238 "alternative", MULTI_ALTERNATE,
3239 "digest", MULTI_DIGEST,
3240 "parallel", MULTI_PARALLEL,
3242 NULL, MULTI_UNKNOWN /* this one must be last! */
3245 static int InitMultiPart (ct)
3257 register struct multipart *m;
3258 register struct k2v *kv;
3259 register struct part *part,
3261 register CI ci = &ct -> c_ctinfo;
3265 ct -> c_ctshowfnx = NULL;
3266 ct -> c_ctstorefnx = NULL;
3268 if (ct -> c_encoding != CE_7BIT) {
3270 "\"%s/%s\" type in message %s should be encoded in 7bit",
3271 ci -> ci_type, ci -> ci_subtype, ct -> c_file);
3275 for (kv = SubMultiPart; kv -> kv_key; kv++)
3276 if (uleq (ci -> ci_subtype, kv -> kv_key))
3278 ct -> c_subtype = kv -> kv_value;
3280 for (ap = ci -> ci_attrs, ep = ci -> ci_values; *ap; ap++, ep++)
3281 if (uleq (*ap, "boundary")) {
3287 "a \"boundary\" parameter is mandatory for \"%s/%s\" type in message %s's %s: field",
3288 ci -> ci_type, ci -> ci_subtype, ct -> c_file, TYPE_FIELD);
3292 if ((m = (struct multipart *) calloc (1, sizeof *m)) == NULL)
3293 adios (NULLCP, "out of memory");
3294 ct -> c_ctparams = (caddr_t) m;
3295 ct -> c_ctlistfnx = list_multi;
3296 ct -> c_ctshowfnx = ct -> c_subtype != MULTI_UNKNOWN ? show_multi
3297 : show_unknown_multi;
3298 ct -> c_ctstorefnx = store_multi;
3299 ct -> c_ctfreefnx = free_multi;
3301 for (cp = bp; isspace (*cp); cp++)
3304 advise (NULLCP, "invalid \"boundary\" parameter for \"%s/%s\" type in message %s's %s: field",
3305 ci -> ci_type, ci -> ci_subtype, ct -> c_file, TYPE_FIELD);
3308 for (cp = bp, dp = cp + strlen (cp) - 1; dp > cp; dp--)
3312 m -> mp_start = concat (bp, "\n", NULLCP);
3313 m -> mp_stop = concat (bp, "--\n", NULLCP);
3315 if (!ct -> c_fp && (ct -> c_fp = fopen (ct -> c_file, "r")) == NULL) {
3316 advise (ct -> c_file, "unable to open for reading");
3320 (void) fseek (fp = ct -> c_fp, pos = ct -> c_begin, 0);
3323 next = &m -> mp_parts, part = NULL, inout = 1;
3324 while (fgets (buffer, sizeof buffer - 1, fp)) {
3328 pos += strlen (buffer);
3330 if (buffer[0] != '-' || buffer[1] != '-')
3334 if (strcmp (buffer + 2, m -> mp_start))
3338 if ((part = (struct part *) calloc (1, sizeof *part)) == NULL)
3339 adios (NULLCP, "out of memory");
3340 *next = part, next = &part -> mp_next;
3342 if ((p = get_content (fp, ct -> c_file,
3343 rfc934sw && ct -> c_subtype == MULTI_DIGEST
3344 ? -1 : 0)) == NULLCT) {
3345 (void) fclose (ct -> c_fp), ct -> c_fp = NULL;
3350 part -> mp_part = p;
3351 (void) fseek (fp, pos = p -> c_begin, 0);
3355 if (strcmp (buffer + 2, m -> mp_start) == 0) {
3359 p = part -> mp_part;
3360 p -> c_end = ftell (fp) - (strlen (buffer) + 1);
3361 if (p -> c_end < p -> c_begin)
3362 p -> c_begin = p -> c_end;
3368 if (strcmp (buffer + 2, m -> mp_stop) == 0)
3371 advise (NULLCP, "bogus multipart content in message %s", ct -> c_file);
3372 if (!inout && part) {
3373 p = part -> mp_part;
3374 p -> c_end = ct -> c_end;
3376 if (p -> c_begin >= p -> c_end) {
3377 for (next = &m -> mp_parts;
3379 next = &((*next) -> mp_next))
3383 free ((char *) part);
3388 if (ct -> c_subtype == MULTI_ALTERNATE
3390 && m -> mp_parts -> mp_next) {
3392 register struct part **base,
3396 for (part = m -> mp_parts; part; part = part -> mp_next)
3398 if ((base = (struct part **) calloc ((unsigned) (i + 1), sizeof *base))
3400 adios (NULLCP, "out of memory");
3402 for (part = m -> mp_parts; part; part = part -> mp_next)
3406 next = &m -> mp_parts;
3407 for (bmp--; bmp >= base; bmp--) {
3409 *next = part, next = &part -> mp_next;
3413 free ((char *) base);
3419 char partnam[BUFSIZ];
3421 if (ct -> c_partno) {
3422 (void) sprintf (partnam, "%s.", ct -> c_partno);
3423 pp = partnam + strlen (partnam);
3428 for (part = m -> mp_parts, partnum = 1;
3430 part = part -> mp_next, partnum++) {
3431 p = part -> mp_part;
3433 (void) sprintf (pp, "%d", partnum);
3434 p -> c_partno = add (partnam, NULLCP);
3436 if (p -> c_ctinitfnx && (*p -> c_ctinitfnx) (p) == NOTOK) {
3437 (void) fclose (ct -> c_fp), ct -> c_fp = NULL;
3443 (void) fclose (ct -> c_fp), ct -> c_fp = NULL;
3450 #define MESSAGE_UNKNOWN 0x00
3451 #define MESSAGE_RFC822 0x01
3452 #define MESSAGE_PARTIAL 0x02
3453 #define MESSAGE_EXTERNAL 0x03
3467 static int list_partial (ct, toplevel)
3471 register struct partial *p = (struct partial *) ct -> c_ctparams;
3473 (void) list_content (ct, toplevel);
3475 printf ("\t [message %s, part %d", p -> pm_partid, p -> pm_partno);
3477 printf (" of %d", p -> pm_maxno);
3485 static int ct_compar (a, b)
3489 register struct partial *am = (struct partial *) ((*a) -> c_ctparams);
3490 register struct partial *bm = (struct partial *) ((*b) -> c_ctparams);
3492 return (am -> pm_marked - bm -> pm_marked);
3498 static int store_partial (ct, unused)
3509 struct partial *qm = (struct partial *) ct -> c_ctparams;
3511 if (qm -> pm_stored)
3515 for (ctp = cts; p = *ctp; ctp++)
3516 if (p -> c_type == CT_MESSAGE && p -> c_subtype == ct -> c_subtype) {
3517 register struct partial *pm = (struct partial *) p -> c_ctparams;
3519 if (!pm -> pm_stored
3520 && strcmp (qm -> pm_partid, pm -> pm_partid) == 0) {
3521 pm -> pm_marked = pm -> pm_partno;
3523 hi = pm -> pm_maxno;
3524 pm -> pm_stored = 1;
3528 pm -> pm_marked = 0;
3531 advise (NULLCP, "missing (at least) last part of multipart message");
3535 if ((base = (CT *) calloc ((unsigned) (i + 1), sizeof *base)) == NULL)
3536 adios (NULLCP, "out of memory");
3539 for (ctp = cts; p = *ctp; ctp++)
3540 if (p -> c_type == CT_MESSAGE && p -> c_subtype == ct -> c_subtype) {
3541 register struct partial *pm = (struct partial *) p -> c_ctparams;
3543 if (pm -> pm_marked)
3549 qsort ((char *) base, i, sizeof *base, ct_compar);
3552 for (ctq = base; p = *ctq; ctq++) {
3553 register struct partial *pm = (struct partial *) p -> c_ctparams;
3555 if (pm -> pm_marked != cur) {
3556 if (pm -> pm_marked == cur - 1) {
3558 "duplicate part %d of %d part multipart message",
3559 pm -> pm_marked, hi);
3565 "missing %spart %d of %d part multipart message",
3566 cur != hi ? "(at least) " : "", cur, hi);
3579 if (store_content (ct, "") == NOTOK) {
3581 free ((char *) base);
3585 for (; p = *ctq; ctq++)
3586 if (store_content (p, ct -> c_storage) == NOTOK)
3589 free ((char *) base);
3594 static int free_partial (ct)
3597 register struct partial *p = (struct partial *) ct -> c_ctparams;
3603 free (p -> pm_partid);
3606 ct -> c_ctparams = NULL;
3619 char *eb_permission;
3633 static int openFile ();
3634 static int openFTP ();
3635 static int openMail ();
3637 /* NOTE WELL: si_key MUST NOT have value of NOTOK */
3639 static struct str2init str2methods[] = {
3641 "anon-ftp", 1, openFTP,
3643 "local-file", 0, openFile,
3644 "mail-server", 0, openMail,
3650 static int params_external (ct, composing)
3656 register struct exbody *e = (struct exbody *) ct -> c_ctparams;
3657 register CI ci = &ct -> c_ctinfo;
3659 for (ap = ci -> ci_attrs, ep = ci -> ci_values; *ap; ap++, ep++) {
3660 if (uleq (*ap, "access-type")) {
3661 register struct str2init *s2i;
3662 register CT p = e -> eb_content;
3664 for (s2i = str2methods; s2i -> si_key; s2i++)
3665 if (uleq (*ep, s2i -> si_key))
3667 if (!s2i -> si_key) {
3668 e -> eb_access = *ep;
3669 e -> eb_flags = NOTOK;
3670 p -> c_encoding = CE_EXTERNAL;
3673 e -> eb_access = s2i -> si_key;
3674 e -> eb_flags = s2i -> si_val;
3675 p -> c_encoding = CE_EXTERNAL;
3676 if (init_encoding (p, s2i -> si_init) == NOTOK)
3680 if (uleq (*ap, "name")) {
3684 if (uleq (*ap, "permission")) {
3685 e -> eb_permission = *ep;
3688 if (uleq (*ap, "site")) {
3692 if (uleq (*ap, "directory")) {
3696 if (uleq (*ap, "mode")) {
3700 if (uleq (*ap, "size")) {
3701 (void) sscanf (*ep, "%lu", &e -> eb_size);
3704 if (uleq (*ap, "server")) {
3705 e -> eb_server = *ep;
3708 if (uleq (*ap, "subject")) {
3709 e -> eb_subject = *ep;
3712 if (composing && uleq (*ap, "body")) {
3713 e -> eb_body = getcpy (*ep);
3718 if (!e -> eb_access) {
3720 "invalid parameters for \"%s/%s\" type in message %s's %s field",
3721 ci -> ci_type, ci -> ci_subtype,
3722 ct -> c_file, TYPE_FIELD);
3729 static int list_external (ct, toplevel)
3733 register struct exbody *e = (struct exbody *) ct -> c_ctparams;
3735 (void) list_content (ct, toplevel);
3738 printf ("\t retrieve %s\n", e -> eb_name);
3740 printf ("\t in directory %s\n", e -> eb_dir);
3742 printf ("\t from %s\n", e -> eb_site);
3744 printf ("\t from mailbox %s\n", e -> eb_server);
3745 if (e -> eb_subject)
3746 printf ("\t with subject %s\n", e -> eb_subject);
3747 printf ("\t using %s", e -> eb_access);
3749 printf (" (in %s mode)", e -> eb_mode);
3750 if (e -> eb_permission)
3751 printf (" (permission %s)", e -> eb_permission);
3752 if (e -> eb_flags == NOTOK)
3753 printf (" [service unavailable]");
3756 (void) list_content (e -> eb_content, 0);
3762 static int show_external (ct, serial, alternate)
3767 register struct exbody *e = (struct exbody *) ct -> c_ctparams;
3768 register CT p = e -> eb_content;
3770 if (!type_ok (p, 0))
3773 if (p -> c_ctshowfnx)
3774 return (*p -> c_ctshowfnx) (p, serial, alternate);
3776 content_error (NULLCP, p, "don't know how to display content");
3781 static int store_external (ct)
3785 register struct exbody *e = (struct exbody *) ct -> c_ctparams;
3786 register CT p = e -> eb_content;
3788 if (!type_ok (p, 1))
3791 p -> c_partno = ct -> c_partno;
3792 if (p -> c_ctstorefnx)
3793 result = (*p -> c_ctstorefnx) (p, NULLCP);
3794 p -> c_partno = NULL;
3800 static int free_external (ct)
3803 register struct exbody *e = (struct exbody *) ct -> c_ctparams;
3808 free_content (e -> eb_content);
3810 free (e -> eb_body);
3813 ct -> c_ctparams = NULL;
3817 static struct k2v SubMessage[] = {
3818 "rfc822", MESSAGE_RFC822,
3819 "partial", MESSAGE_PARTIAL,
3820 "external-body", MESSAGE_EXTERNAL,
3822 NULL, MESSAGE_UNKNOWN /* this one must be last! */
3825 static int InitMessage (ct)
3828 register struct k2v *kv;
3829 register CI ci = &ct -> c_ctinfo;
3831 if (ct -> c_encoding != CE_7BIT) {
3833 "\"%s/%s\" type in message %s should be encoded in 7bit",
3834 ci -> ci_type, ci -> ci_subtype, ct -> c_file);
3838 if (!*ci -> ci_subtype) /* XXX: attmail bogosity! */
3839 ci -> ci_subtype = add ("rfc822", ci -> ci_subtype);
3840 for (kv = SubMessage; kv -> kv_key; kv++)
3841 if (uleq (ci -> ci_subtype, kv -> kv_key))
3844 switch (ct -> c_subtype = kv -> kv_value) {
3845 case MESSAGE_RFC822:
3846 ct -> c_showproc = add ("%pshow -file '%F'", NULLCP);
3849 case MESSAGE_PARTIAL:
3853 register struct partial *p;
3855 ct -> c_ctshowfnx = NULL;
3856 ct -> c_ctstorefnx = NULL;
3858 if ((p = (struct partial *) calloc (1, sizeof *p)) == NULL)
3859 adios (NULLCP, "out of memory");
3860 ct -> c_ctparams = (caddr_t) p;
3861 ct -> c_ctfreefnx = free_partial;
3863 for (ap = ci -> ci_attrs, ep = ci -> ci_values;
3866 if (uleq (*ap, "id")) {
3867 p -> pm_partid = add (*ep, NULLCP);
3872 if (uleq (*ap, "number")) {
3873 if (sscanf (*ep, "%d", &p -> pm_partno) != 1
3874 || p -> pm_partno < 1) {
3877 "invalid %s parameter for \"%s/%s\" type in message %s's %s field",
3878 *ap, ci -> ci_type, ci -> ci_subtype,
3879 ct -> c_file, TYPE_FIELD);
3886 if (uleq (*ap, "total")) {
3887 if (sscanf (*ep, "%d", &p -> pm_maxno) != 1
3888 || p -> pm_maxno < 1)
3897 || (p -> pm_maxno && p -> pm_partno > p -> pm_maxno)) {
3899 "invalid parameters for \"%s/%s\" type in message %s's %s field",
3900 ci -> ci_type, ci -> ci_subtype,
3901 ct -> c_file, TYPE_FIELD);
3905 ct -> c_ctlistfnx = list_partial;
3906 ct -> c_ctstorefnx = store_partial;
3910 case MESSAGE_EXTERNAL:
3913 register struct exbody *e;
3917 ct -> c_ctshowfnx = NULL;
3918 ct -> c_ctstorefnx = NULL;
3920 if ((e = (struct exbody *) calloc (1, sizeof *e)) == NULL)
3921 adios (NULLCP, "out of memory");
3922 ct -> c_ctparams = (caddr_t) e;
3923 ct -> c_ctfreefnx = free_external;
3926 && (ct -> c_fp = fopen (ct -> c_file, "r")) == NULL) {
3927 advise (ct -> c_file, "unable to open for reading");
3931 (void) fseek (fp = ct -> c_fp, ct -> c_begin, 0);
3933 if ((p = get_content (fp, ct -> c_file, 0)) == NULLCT) {
3934 (void) fclose (ct -> c_fp), ct -> c_fp = NULL;
3938 e -> eb_parent = ct;
3939 e -> eb_content = p;
3940 p -> c_ctextern = (caddr_t) e;
3941 if ((exresult = params_external (ct, 0)) != NOTOK
3942 && p -> c_ceopenfnx == openMail) {
3947 if ((size = ct -> c_end - p -> c_begin) <= 0) {
3948 if (!e -> eb_subject)
3949 content_error (NULLCP, ct,
3950 "empty body for access-type=mail-server");
3954 if ((e -> eb_body = bp = malloc ((unsigned) size)) == NULL)
3955 adios (NULLCP, "out of memory");
3956 (void) fseek (p -> c_fp, p -> c_begin, 0);
3958 switch (cc = fread (bp, sizeof *bp, size, p -> c_fp)) {
3960 adios ("failed", "fread");
3963 adios (NULLCP, "unexpected EOF from fread");
3966 bp += cc, size -= cc;
3973 p -> c_end = p -> c_begin;
3975 (void) fclose (ct -> c_fp), ct -> c_fp = NULL;
3977 ct -> c_ctlistfnx = list_external;
3979 if (exresult == NOTOK)
3981 if (e -> eb_flags == NOTOK)
3984 if (e -> eb_name && autosw) {
3985 char *cp = e -> eb_name;
3991 && !index (cp, '%')) {
3992 if (!ct -> c_storeproc)
3993 ct -> c_storeproc = add (cp, NULLCP);
3994 if (!p -> c_storeproc)
3995 p -> c_storeproc = add (cp, NULLCP);
3999 ct -> c_ctshowfnx = show_external;
4000 ct -> c_ctstorefnx = store_external;
4001 switch (p -> c_type) {
4006 if (p -> c_subtype != MESSAGE_RFC822)
4010 e -> eb_partno = ct -> c_partno;
4011 if (p -> c_ctinitfnx)
4012 (void) (*p -> c_ctinitfnx) (p);
4025 /*
\f APPLICATION */
4027 #define APPLICATION_UNKNOWN 0x00
4028 #define APPLICATION_OCTETS 0x01
4029 #define APPLICATION_POSTSCRIPT 0x02
4032 static int list_application (ct, toplevel)
4036 (void) list_content (ct, toplevel);
4040 register CI ci = &ct -> c_ctinfo;
4042 for (ap = ci -> ci_attrs, ep = ci -> ci_values; *ap; ap++, ep++)
4043 printf ("\t %s=\"%s\"\n", *ap, *ep);
4050 static struct k2v SubApplication[] = {
4051 "octet-stream", APPLICATION_OCTETS,
4052 "postscript", APPLICATION_POSTSCRIPT,
4053 NULL, APPLICATION_UNKNOWN /* this one must be last! */
4056 static int InitApplication (ct)
4061 register struct k2v *kv;
4062 register CI ci = &ct -> c_ctinfo;
4064 ct -> c_ctlistfnx = list_application;
4066 for (kv = SubApplication; kv -> kv_key; kv++)
4067 if (uleq (ci -> ci_subtype, kv -> kv_key))
4070 for (ap = ci -> ci_attrs, ep = ci -> ci_values; *ap; ap++, ep++)
4071 if (autosw && !ct -> c_storeproc && uleq (*ap, "name")) {
4074 if (*(cp = *ep) != '/'
4078 && !index (cp, '%'))
4079 ct -> c_storeproc = add (cp, NULLCP);
4082 if ((ct -> c_subtype = kv -> kv_value) == APPLICATION_OCTETS) {
4087 for (ap = ci -> ci_attrs, ep = ci -> ci_values; *ap; ap++, ep++) {
4088 if (uleq (*ap, "type")) {
4089 if (!uleq (*ep, "tar"))
4096 if ((uleq (*ap, "conversions") || uleq (*ap, "x-conversions"))
4097 && (uleq (*ep, "compress") || uleq (*ep, "x-compress"))) {
4104 ct -> c_showproc = add (zP ? "%euncompress | tar tvf -"
4105 : "%etar tvf -", NULLCP);
4106 if (!ct -> c_storeproc)
4108 ct -> c_storeproc = add (zP ? "| uncompress | tar xvpf -"
4109 : "| tar xvpf -", NULLCP);
4110 ct -> c_umask = 0022;
4113 ct -> c_storeproc = add (zP ? "%m%P.tar.Z" : "%m%P.tar",
4134 static int list_encoding (ct)
4137 register struct cefile *ce = (struct cefile *) ct -> c_ceparams;
4140 fprintf (stderr, " decoded fp 0x%x file \"%s\"\n", ce -> ce_fp,
4141 ce -> ce_file ? ce -> ce_file : "");
4147 static int close_encoding (ct)
4150 register struct cefile *ce = (struct cefile *) ct -> c_ceparams;
4156 (void) fclose (ce -> ce_fp);
4162 static unsigned long size_encoding (ct)
4168 register struct cefile *ce = (struct cefile *) ct -> c_ceparams;
4174 return (ct -> c_end - ct -> c_begin);
4177 if (ce -> ce_fp && fstat (fileno (ce -> ce_fp), &st) != NOTOK)
4178 return (long) st.st_size;
4181 return stat (ce -> ce_file, &st) != NOTOK ? (long) st.st_size : 0L;
4183 if (ct -> c_encoding == CE_EXTERNAL)
4187 if ((fd = (*ct -> c_ceopenfnx) (ct, &file)) == NOTOK)
4190 size = fstat (fd, &st) != NOTOK ? (long) st.st_size : 0L;
4192 (*ct -> c_ceclosefnx) (ct);
4198 static int free_encoding (ct, toplevel)
4202 register struct cefile *ce = (struct cefile *) ct -> c_ceparams;
4208 (void) fclose (ce -> ce_fp);
4212 if (ce -> ce_file) {
4213 if (ce -> ce_unlink)
4214 (void) unlink (ce -> ce_file);
4215 free (ce -> ce_file);
4220 ct -> c_ceparams = NULL;
4223 ct -> c_ceopenfnx = NULL;
4227 static init_encoding (ct, openfnx)
4231 register struct cefile *ce;
4233 if ((ce = (struct cefile *) calloc (1, sizeof *ce)) == NULL)
4234 adios (NULLCP, "out of memory");
4236 ct -> c_ceparams = (caddr_t) ce;
4237 ct -> c_ceopenfnx = openfnx;
4238 ct -> c_ceclosefnx = close_encoding;
4239 ct -> c_cesizefnx = size_encoding;
4240 ct -> c_celistfnx = list_encoding;
4241 ct -> c_cefreefnx = free_encoding;
4248 static unsigned char b642nib[0x80] = {
4249 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
4250 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
4251 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
4252 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
4253 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
4254 0xff, 0xff, 0xff, 0x3e, 0xff, 0xff, 0xff, 0x3f,
4255 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b,
4256 0x3c, 0x3d, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
4257 0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
4258 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
4259 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
4260 0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff,
4261 0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
4262 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
4263 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
4264 0x31, 0x32, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff
4268 static int openBase64 (ct, file)
4281 unsigned char value,
4282 *b = (unsigned char *) &bits,
4283 *b1 = &b[endian > 0 ? 1 : 2],
4284 *b2 = &b[endian > 0 ? 2 : 1],
4285 *b3 = &b[endian > 0 ? 3 : 0];
4286 char buffer[BUFSIZ];
4287 register struct cefile *ce = (struct cefile *) ct -> c_ceparams;
4292 if (ce -> ce_file) {
4293 if ((ce -> ce_fp = fopen (ce -> ce_file, "r")) == NULL) {
4294 content_error (ce -> ce_file, ct, "unable to fopen for reading");
4298 *file = ce -> ce_file;
4299 return fileno (ce -> ce_fp);
4302 ce -> ce_unlink = *file == NULL;
4303 if ((ce -> ce_fp = fopen (ce -> ce_file =
4304 add (*file ? *file : m_scratch ("", tmp),
4307 content_error (ce -> ce_file, ct,
4308 "unable to fopen for writing and reading");
4312 if ((len = ct -> c_end - ct -> c_begin) < 0)
4313 adios (NULLCP, "internal error(1)");
4315 if (!ct -> c_fp && (ct -> c_fp = fopen (ct -> c_file, "r")) == NULL) {
4316 content_error (ct -> c_file, ct, "unable to open for reading");
4320 if (digested = ct -> c_digested)
4321 MD5Init (&mdContext);
4323 (void) lseek (fd = fileno (ct -> c_fp), (off_t)ct -> c_begin, 0);
4324 bitno = 18, bits = 0L, skip = 0;
4326 switch (cc = read (fd, buffer, sizeof buffer - 1)) {
4328 content_error (ct -> c_file, ct, "error reading from");
4332 content_error (NULLCP, ct, "premature eof");
4340 for (ep = (cp = buffer) + cc; cp < ep; cp++)
4347 || (value = b642nib[*cp & 0x7f]) > 0x3f) {
4350 "*cp=0x%x pos=%ld skip=%d\n", *cp,
4351 (long) lseek (fd, (off_t)0, 1) - (ep - cp),
4353 content_error (NULLCP, ct,
4354 "invalid BASE64 encoding -- continuing");
4358 bits |= value << bitno;
4360 if ((bitno -= 6) < 0) {
4361 (void) putc ((char) *b1, ce -> ce_fp);
4363 MD5Update (&mdContext, b1, 1);
4365 (void) putc ((char) *b2, ce -> ce_fp);
4367 MD5Update (&mdContext, b2, 1);
4369 (void) putc ((char) *b3, ce -> ce_fp);
4371 MD5Update (&mdContext, b3, 1);
4375 if (ferror (ce -> ce_fp)) {
4376 content_error (ce -> ce_file, ct,
4377 "error writing to");
4380 bitno = 18, bits = 0L, skip = 0;
4386 goto self_delimiting;
4392 fprintf (stderr, "premature ending (bitno %d)\n", bitno);
4394 content_error (NULLCP, ct, "invalid BASE64 encoding");
4398 (void) fseek (ct -> c_fp, 0L, 0);
4400 if (fflush (ce -> ce_fp)) {
4401 content_error (ce -> ce_file, ct, "error writing to");
4406 unsigned char digest[16];
4408 MD5Final (digest, &mdContext);
4409 if (bcmp ((char *) digest, (char *) ct -> c_digest,
4410 sizeof digest / sizeof digest[0]))
4411 content_error (NULLCP, ct,
4412 "content integrity suspect (digest mismatch) -- continuing");
4415 fprintf (stderr, "content integrity confirmed\n");
4419 (void) fseek (ce -> ce_fp, 0L, 0);
4420 *file = ce -> ce_file;
4421 return fileno (ce -> ce_fp);
4424 free_encoding (ct, 0);
4430 static int InitBase64 (ct)
4433 return init_encoding (ct, openBase64);
4437 static int set_endian ()
4442 char c[sizeof (long)];
4446 endian = un.c[0] ? -1 : 1;
4448 fprintf (stderr, "%s endian architecture\n",
4449 endian > 0 ? "big" : "little");
4451 mm_charset = getenv ("MM_CHARSET");
4453 if ((cp = getenv ("MM_NOASK")) && strcmp (cp, "1") == 0) {
4454 nolist = 1, pausesw = 0;
4462 static char hex2nib[0x80] = {
4463 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4464 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4465 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4466 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4467 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4468 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4469 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
4470 0x08, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4471 0x00, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x00,
4472 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4473 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4474 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4475 0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00,
4476 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4477 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4478 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
4482 static int openQuoted (ct, file)
4492 char buffer[BUFSIZ];
4494 register struct cefile *ce = (struct cefile *) ct -> c_ceparams;
4499 if (ce -> ce_file) {
4500 if ((ce -> ce_fp = fopen (ce -> ce_file, "r")) == NULL) {
4501 content_error (ce -> ce_file, ct, "unable to fopen for reading");
4505 *file = ce -> ce_file;
4506 return fileno (ce -> ce_fp);
4509 ce -> ce_unlink = *file == NULL;
4510 if ((ce -> ce_fp = fopen (ce -> ce_file =
4511 add (*file ? *file : m_scratch ("", tmp),
4514 content_error (ce -> ce_file, ct,
4515 "unable to fopen for writing and reading");
4519 if ((len = ct -> c_end - ct -> c_begin) < 0)
4520 adios (NULLCP, "internal error(2)");
4522 if (!ct -> c_fp && (ct -> c_fp = fopen (ct -> c_file, "r")) == NULL) {
4523 content_error (ct -> c_file, ct, "unable to open for reading");
4527 if (digested = ct -> c_digested)
4528 MD5Init (&mdContext);
4530 (void) fseek (ct -> c_fp, ct -> c_begin, 0);
4538 if (fgets (buffer, sizeof buffer - 1, ct -> c_fp) == NULL) {
4539 content_error (NULLCP, ct, "premature eof");
4543 if ((cc = strlen (buffer)) > len)
4547 for (ep = (cp = buffer) + cc - 1; cp <= ep; ep--)
4552 for (; cp < ep; cp++) {
4555 if (!isxdigit (*cp)) {
4557 dp = "expecting hexidecimal-digit";
4558 goto invalid_encoding;
4561 mask |= hex2nib[*cp & 0x7f];
4562 (void) putc (mask, ce -> ce_fp);
4564 MD5Update (&mdContext, &mask, 1);
4569 (void) putc (*cp, ce -> ce_fp);
4571 MD5Update (&mdContext, (unsigned char *) ":",
4576 if (!isxdigit (*cp))
4578 mask = hex2nib[*cp & 0x7f];
4583 if (ferror (ce -> ce_fp)) {
4584 content_error (ce -> ce_file, ct, "error writing to");
4593 if (*cp < '!' || *cp > '~') {
4595 dp = "expecting character in range [!..~]";
4598 i = strlen (invo_name) + 2;
4599 content_error (NULLCP, ct,
4600 "invalid QUOTED-PRINTABLE encoding -- %s,\n%*.*sbut got char 0x%x",
4608 (void) putc (*cp, ce -> ce_fp);
4611 MD5Update (&mdContext, (unsigned char *) "\r\n",2);
4613 MD5Update (&mdContext, (unsigned char *) cp, 1);
4615 if (ferror (ce -> ce_fp)) {
4616 content_error (ce -> ce_file, ct, "error writing to");
4622 if (*++cp != '\n') {
4631 content_error (NULLCP, ct,
4632 "invalid QUOTED-PRINTABLE encoding -- end-of-content while still quoting");
4635 (void) fseek (ct -> c_fp, 0L, 0);
4637 if (fflush (ce -> ce_fp)) {
4638 content_error (ce -> ce_file, ct, "error writing to");
4643 unsigned char digest[16];
4645 MD5Final (digest, &mdContext);
4646 if (bcmp ((char *) digest, (char *) ct -> c_digest,
4647 sizeof digest / sizeof digest[0]))
4648 content_error (NULLCP, ct,
4649 "content integrity suspect (digest mismatch) -- continuing");
4652 fprintf (stderr, "content integrity confirmed\n");
4656 (void) fseek (ce -> ce_fp, 0L, 0);
4657 *file = ce -> ce_file;
4658 return fileno (ce -> ce_fp);
4661 free_encoding (ct, 0);
4667 static int InitQuoted (ct)
4670 return init_encoding (ct, openQuoted);
4675 static int open7Bit (ct, file)
4682 char buffer[BUFSIZ];
4683 register struct cefile *ce = (struct cefile *) ct -> c_ceparams;
4687 if (ce -> ce_file) {
4688 if ((ce -> ce_fp = fopen (ce -> ce_file, "r")) == NULL) {
4689 content_error (ce -> ce_file, ct, "unable to fopen for reading");
4693 *file = ce -> ce_file;
4694 return fileno (ce -> ce_fp);
4697 ce -> ce_unlink = *file == NULL;
4698 if ((ce -> ce_fp = fopen (ce -> ce_file =
4699 add (*file ? *file : m_scratch ("", tmp),
4702 content_error (ce -> ce_file, ct,
4703 "unable to fopen for writing and reading");
4707 if (ct -> c_type == CT_MULTIPART) {
4710 register CI ci = &ct -> c_ctinfo;
4714 fprintf (ce -> ce_fp, "%s: %s/%s", TYPE_FIELD, ci -> ci_type,
4716 len += strlen (TYPE_FIELD) + 2 + strlen (ci -> ci_type)
4717 + 1 + strlen (ci -> ci_subtype);
4718 for (ap = ci -> ci_attrs, ep = ci -> ci_values; *ap; ap++, ep++) {
4719 (void) putc (';', ce -> ce_fp);
4722 (void) sprintf (buffer, "%s=\"%s\"", *ap, *ep);
4724 if (len + 1 + (cc = strlen (buffer)) >= CPERLIN) {
4725 (void) fputs ("\n\t", ce -> ce_fp);
4729 (void) putc (' ', ce -> ce_fp);
4732 fprintf (ce -> ce_fp, "%s", buffer);
4735 if (ci -> ci_comment) {
4736 if (len + 1 + (cc = 2 + strlen (ci -> ci_comment)) >= CPERLIN) {
4737 (void) fputs ("\n\t", ce -> ce_fp);
4741 (void) putc (' ', ce -> ce_fp);
4744 fprintf (ce -> ce_fp, "(%s)", ci -> ci_comment);
4747 fprintf (ce -> ce_fp, "\n");
4749 fprintf (ce -> ce_fp, "%s:%s", ID_FIELD, ct -> c_id);
4751 fprintf (ce -> ce_fp, "%s:%s", DESCR_FIELD, ct -> c_descr);
4752 fprintf (ce -> ce_fp, "\n");
4755 if ((len = ct -> c_end - ct -> c_begin) < 0)
4756 adios (NULLCP, "internal error(3)");
4758 if (!ct -> c_fp && (ct -> c_fp = fopen (ct -> c_file, "r")) == NULL) {
4759 content_error (ct -> c_file, ct, "unable to open for reading");
4763 (void) lseek (fd = fileno (ct -> c_fp), (off_t) ct -> c_begin, 0);
4765 switch (cc = read (fd, buffer, sizeof buffer - 1)) {
4767 content_error (ct -> c_file, ct, "error reading from");
4771 content_error (NULLCP, ct, "premature eof");
4779 (void) fwrite (buffer, sizeof *buffer, cc, ce -> ce_fp);
4780 if (ferror (ce -> ce_fp)) {
4781 content_error (ce -> ce_file, ct, "error writing to");
4785 (void) fseek (ct -> c_fp, 0L, 0);
4787 if (fflush (ce -> ce_fp)) {
4788 content_error (ce -> ce_file, ct, "error writing to");
4793 (void) fseek (ce -> ce_fp, 0L, 0);
4794 *file = ce -> ce_file;
4795 return fileno (ce -> ce_fp);
4798 free_encoding (ct, 0);
4804 static int Init7Bit (ct)
4807 if (init_encoding (ct, open7Bit) == NOTOK)
4809 ct -> c_cesizefnx = NULL;
4816 static int openExternal (ct, cb, ce, file, fd)
4823 char cachefile[BUFSIZ];
4826 (void) fseek (ce -> ce_fp, 0L, 0);
4829 *file = ce -> ce_file, *fd = fileno (ce -> ce_fp);
4833 if (ce -> ce_file) {
4834 if ((ce -> ce_fp = fopen (ce -> ce_file, "r")) == NULL) {
4835 content_error (ce -> ce_file, ct, "unable to fopen for reading");
4842 if (find_cache (ct, rcachesw, (int *) 0, cb -> c_id, cachefile) != NOTOK) {
4843 if (ce -> ce_fp = fopen (cachefile, "r")) {
4844 ce -> ce_unlink = 0;
4845 ce -> ce_file = getcpy (cachefile);
4849 admonish (cachefile, "unable to fopen for reading");
4857 static int openFile (ct, file)
4863 char cachefile[BUFSIZ];
4864 register struct exbody *e = (struct exbody *) ct -> c_ctextern;
4865 register struct cefile *ce = (struct cefile *) ct -> c_ceparams;
4867 switch (openExternal (e -> eb_parent, e -> eb_content, ce, file, &fd)) {
4878 if (!e -> eb_name) {
4879 content_error (NULLCP, ct, "missing name parameter");
4883 ce -> ce_unlink = 0;
4884 if ((ce -> ce_fp = fopen (ce -> ce_file = getcpy (e -> eb_name), "r"))
4886 content_error (ce -> ce_file, ct, "unable to fopen for reading");
4890 if ((!e -> eb_permission || !uleq (e -> eb_permission, "read-write"))
4891 && find_cache (NULLCT, wcachesw, &cachetype,
4892 e -> eb_content -> c_id, cachefile) != NOTOK) {
4896 mask = umask (cachetype ? ~m_gmprot () : 0222);
4897 if (fp = fopen (cachefile, "w")) {
4899 char buffer[BUFSIZ];
4900 FILE *gp = ce -> ce_fp;
4902 (void) fseek (gp, 0L, 0);
4904 while ((cc = fread (buffer, sizeof *buffer, sizeof buffer, gp))
4906 (void) fwrite (buffer, sizeof *buffer, cc, fp);
4910 admonish (ce -> ce_file, "error reading");
4911 (void) unlink (cachefile);
4915 admonish (cachefile, "error writing");
4916 (void) unlink (cachefile);
4920 (void) umask (mask);
4923 (void) fseek (ce -> ce_fp, 0L, 0);
4924 *file = ce -> ce_file;
4925 return fileno (ce -> ce_fp);
4930 static int openFTP (ct, file)
4943 register struct exbody *e = (struct exbody *) ct -> c_ctextern;
4944 register struct cefile *ce = (struct cefile *) ct -> c_ceparams;
4945 static char *username = NULL;
4946 static char *password = NULL;
4948 (void) sprintf (buffer, "%s-access-ftp", invo_name);
4949 if ((ftp = m_find (buffer)) && !*ftp)
4955 switch (openExternal (e -> eb_parent, e -> eb_content, ce, file, &fd)) {
4966 if (!e -> eb_name || !e -> eb_site) {
4967 content_error (NULLCP, ct, "missing %s parameter",
4968 e -> eb_name ? "site": "name");
4975 (void) pidcheck (pidwait (xpid, NOTOK));
4980 (void) sprintf (bp, "Retrieve %s", e -> eb_name);
4982 if (e -> eb_partno) {
4983 (void) sprintf (bp, " (content %s)", e -> eb_partno);
4986 (void) sprintf (bp, "\n using %sFTP from site %s",
4987 e -> eb_flags ? "anonymous " : "", e -> eb_site);
4989 if (e -> eb_size > 0) {
4990 (void) sprintf (bp, " (%lu octets)", e -> eb_size);
4993 (void) sprintf (bp, "? ");
4994 if (!getanswer (buffer))
4997 if (e -> eb_flags) {
4999 (void) sprintf (pass = buffer, "%s@%s", getusr (), LocalName ());
5002 ruserpass (e -> eb_site, &username, &password);
5003 user = username, pass = password;
5006 ce -> ce_unlink = *file == NULL, caching = 0, cachefile[0] = 0;
5007 if ((!e -> eb_permission || !uleq (e -> eb_permission, "read-write"))
5008 && find_cache (NULLCT, wcachesw, &cachetype,
5009 e -> eb_content -> c_id, cachefile) != NOTOK) {
5010 if (*file == NULL) {
5011 ce -> ce_unlink = 0;
5016 if ((ce -> ce_fp = fopen (ce -> ce_file =
5018 : caching ? cachefile
5019 : m_scratch ("", tmp),
5022 content_error (ce -> ce_file, ct,
5023 "unable to fopen for writing and reading");
5037 vec[vecp++] = r1bindex (ftp, '/');
5038 vec[vecp++] = e -> eb_site;
5041 vec[vecp++] = e -> eb_dir;
5042 vec[vecp++] = e -> eb_name;
5043 vec[vecp++] = ce -> ce_file,
5044 vec[vecp++] = e -> eb_mode && uleq (e -> eb_mode, "ascii")
5045 ? "ascii" : "binary";
5048 (void) fflush (stdout);
5050 for (i = 0; (child_id = vfork ()) == NOTOK && i < 5; i++)
5054 adios ("fork", "unable to");
5058 (void) close (fileno (ce -> ce_fp));
5059 (void) execvp (ftp, vec);
5060 fprintf (stderr, "unable to exec ");
5066 if (pidXwait (child_id, NULLCP)) {
5070 username = password = NULL;
5071 ce -> ce_unlink = 1;
5079 if (ftp_get (e -> eb_site, user, pass, e -> eb_dir, e -> eb_name,
5081 !e -> eb_mode || uleq (e -> eb_mode, "ascii"), 0)
5088 (void) chmod (cachefile, cachetype ? m_gmprot () : 0444);
5093 mask = umask (cachetype ? ~m_gmprot () : 0222);
5094 if (fp = fopen (cachefile, "w")) {
5096 FILE *gp = ce -> ce_fp;
5098 (void) fseek (gp, 0L, 0);
5100 while ((cc = fread (buffer, sizeof *buffer, sizeof buffer, gp))
5102 (void) fwrite (buffer, sizeof *buffer, cc, fp);
5106 admonish (ce -> ce_file, "error reading");
5107 (void) unlink (cachefile);
5111 admonish (cachefile, "error writing");
5112 (void) unlink (cachefile);
5116 (void) umask (mask);
5119 (void) fseek (ce -> ce_fp, 0L, 0);
5120 *file = ce -> ce_file;
5121 return fileno (ce -> ce_fp);
5126 static int openMail (ct, file)
5137 register struct exbody *e = (struct exbody *) ct -> c_ctextern;
5138 register struct cefile *ce = (struct cefile *) ct -> c_ceparams;
5140 switch (openExternal (e -> eb_parent, e -> eb_content, ce, file, &fd)) {
5151 if (!e -> eb_server) {
5152 content_error (NULLCP, ct, "missing server parameter");
5159 (void) pidcheck (pidwait (xpid, NOTOK));
5164 (void) sprintf (bp, "Retrieve content");
5166 if (e -> eb_partno) {
5167 (void) sprintf (bp, " %s", e -> eb_partno);
5170 (void) sprintf (bp, " by asking %s\n\n%s\n? ",
5172 e -> eb_subject ? e -> eb_subject : e -> eb_body);
5173 if (!getanswer (buffer))
5177 vec[vecp++] = r1bindex (mailproc, '/');
5178 vec[vecp++] = e -> eb_server;
5179 vec[vecp++] = "-subject";
5180 vec[vecp++] = e -> eb_subject ? e -> eb_subject : "mail-server request";
5181 vec[vecp++] = "-body";
5182 vec[vecp++] = e -> eb_body;
5185 for (i = 0; (child_id = vfork ()) == NOTOK && i < 5; i++)
5189 advise ("fork", "unable to");
5193 (void) execvp (mailproc, vec);
5194 fprintf (stderr, "unable to exec ");
5200 if (pidXwait (child_id, NULLCP) == OK)
5201 advise (NULLCP, "request sent");
5205 ce -> ce_unlink = *file == NULL;
5206 if ((ce -> ce_fp = fopen (ce -> ce_file =
5207 add (*file ? *file : m_scratch ("", tmp),
5210 content_error (ce -> ce_file, ct,
5211 "unable to fopen for writing and reading");
5214 if (ct -> c_showproc)
5215 free (ct -> c_showproc);
5216 ct -> c_showproc = add ("true", NULLCP);
5218 (void) fseek (ce -> ce_fp, 0L, 0);
5219 *file = ce -> ce_file;
5220 return fileno (ce -> ce_fp);
5225 static int find_cache (ct, policy, writing, id, buffer)
5239 fprintf (stderr, "find_cache %s(%d) %s %s\n",
5240 caches[policy].sw, policy, writing ? "writing" : "reading",
5252 && find_cache_aux (writing ? 2 : 0, cache_private, id,
5254 if (access (buffer, 04) != NOTOK) {
5264 && find_cache_aux (writing ? 1 : 0, cache_public, id,
5266 if (writing || access (buffer, 04) != NOTOK) {
5276 && find_cache_aux (writing ? 2 : 0, cache_private, id,
5278 if (writing || access (buffer, 04) != NOTOK)
5285 if (status == OK && policy == CACHE_ASK) {
5292 (void) pidcheck (pidwait (xpid, NOTOK));
5298 (void) sprintf (bp, "Make cached, publically-accessible copy");
5302 (void) sprintf (bp, "Use cached copy");
5304 if (ct -> c_partno) {
5305 (void) sprintf (bp, " of content %s", ct -> c_partno);
5308 (void) stat (buffer, &st);
5309 (void) sprintf (bp, " (size %lu octets)",
5310 (unsigned long) st.st_size);
5313 (void) sprintf (bp, "\n in file %s? ", buffer);
5314 if (!getanswer (query))
5317 if (status == OK && writing) {
5318 if (*writing && index (buffer, '/'))
5319 (void) make_intermediates (buffer);
5320 (void) unlink (buffer);
5329 static int find_cache_aux (writing, directory, id, buffer)
5337 int usemap = index (id, '/') ? 1 : 0;
5341 char mapfile[BUFSIZ],
5346 static long clock = 0L;
5349 fprintf (stderr, "find_cache_aux %s usemap=%d\n", directory, usemap);
5351 (void) sprintf (mapfile, "%s/cache.map", directory);
5352 if (find_cache_aux2 (mapfile, id, mapname) == OK)
5360 (void) sprintf (buffer, "%s/%s", directory, id);
5364 if (!usemap && access (mapfile, 02) == NOTOK)
5377 (void) time (&clock);
5382 clock++, partno = 0;
5384 (void) sprintf (mapname, "%08x%04x%02x", clock & 0xffffffff,
5385 pid & 0xffff, partno++ & 0xff);
5387 fprintf (stderr, "creating mapping %s -> %s\n", mapname, id);
5389 (void) make_intermediates (mapfile);
5390 mask = umask (writing == 2 ? 0077 : 0);
5391 if (!(fp = lkfopen (mapfile, "a")) && errno == ENOENT) {
5392 int fd = creat (mapfile, 0666);
5396 fp = lkfopen (mapfile, "a");
5399 (void) umask (mask);
5402 fprintf (fp, "%s: %s\n", mapname, id);
5403 (void) lkfclose (fp, mapfile);
5406 if (*mapname == '/')
5407 (void) strcpy (buffer, mapname);
5409 (void) sprintf (buffer, "%s/%s", directory, mapname);
5411 fprintf (stderr, "use %s\n", buffer);
5418 static int find_cache_aux2 (mapfile, id, mapname)
5428 if (!(fp = lkfopen (mapfile, "r")))
5431 for (state = FLD;;) {
5436 switch (state = m_getfld (state, name, buf, sizeof buf, fp)) {
5440 (void) strcpy (mapname, name);
5441 if (state != FLDPLUS)
5444 cp = add (buf, NULLCP);
5445 while (state == FLDPLUS) {
5446 state = m_getfld (state, name, buf, sizeof buf, fp);
5454 fprintf (stderr, "compare %s to %s <- %s\n", id, dp,
5456 result = strcmp (id, dp);
5459 (void) lkfclose (fp, mapfile);
5462 if (state != FLDEOF)
5475 (void) lkfclose (fp, mapfile);
5481 static int cache_content (ct)
5487 register struct cefile *ce = (struct cefile *) ct -> c_ceparams;
5490 advise (NULLCP, "no %s: field in %s", ID_FIELD, ct -> c_file);
5495 advise (NULLCP, "unable to decode %s", ct -> c_file);
5499 if (ct -> c_ceopenfnx == openMail) {
5500 advise (NULLCP, "a radish may no know Greek, but I do...");
5504 if (find_cache (NULLCT, wcachesw != CACHE_NEVER ? wcachesw : CACHE_ASK,
5505 &cachetype, ct -> c_id, cachefile)
5507 advise (NULLCP, "unable to cache %s's contents", ct -> c_file);
5510 if (wcachesw != CACHE_NEVER && wcachesw != CACHE_ASK) {
5511 (void) fflush (stdout);
5512 fprintf (stderr, "caching message %s as file %s\n", ct -> c_file,
5516 if (ce -> ce_file) {
5517 int mask = umask (cachetype ? ~m_gmprot () : 0222);
5521 fprintf (stderr, "caching by copying %s...\n", ce -> ce_file);
5524 if ((*ct -> c_ceopenfnx) (ct, &file) == NOTOK)
5527 if (fp = fopen (cachefile, "w")) {
5529 char buffer[BUFSIZ];
5530 FILE *gp = ce -> ce_fp;
5532 (void) fseek (gp, 0L, 0);
5534 while ((cc = fread (buffer, sizeof *buffer, sizeof buffer, gp))
5536 (void) fwrite (buffer, sizeof *buffer, cc, fp);
5540 admonish (ce -> ce_file, "error reading");
5541 (void) unlink (cachefile);
5545 admonish (cachefile, "error writing");
5546 (void) unlink (cachefile);
5551 content_error (cachefile, ct, "unable to fopen for writing");
5553 (void) umask (mask);
5557 fprintf (stderr, "in place caching...\n");
5560 if ((*ct -> c_ceopenfnx) (ct, &file) != NOTOK)
5561 (void) chmod (cachefile, cachetype ? m_gmprot () : 0444);
5565 /*
\f COMPOSITION */
5567 static char prefix[] = "----- =_aaaaaaaaaa";
5569 static char *free_file = NULL;
5570 static CT free_ct = NULL;
5573 static void build_comp (file)
5582 struct multipart *m;
5583 register struct part **pp;
5588 if ((in = fopen (file, "r")) == NULL)
5589 adios (file, "unable to open for reading");
5591 (void) umask (~m_gmprot ());
5593 (void) strcpy (tmpfil, m_scratch (file, invo_name));
5594 if ((out = fopen (tmpfil, "w")) == NULL)
5595 adios (tmpfil, "unable to open for writing");
5598 for (compnum = 1, state = FLD;;) {
5599 switch (state = m_getfld (state, name, buf, sizeof buf, in)) {
5605 if (uleq (name, VRSN_FIELD))
5606 adios (NULLCP, "draft shouldn't contain %s: field",
5609 if (uleq (name, TYPE_FIELD)) {
5610 while (state == FLDPLUS)
5611 state = m_getfld (state, name, buf, sizeof buf, in);
5615 if (uleq (name, ENCODING_FIELD))
5616 adios (NULLCP, "draft shouldn't contain %s: field",
5619 fprintf (out, "%s:%s", name, buf);
5620 while (state == FLDPLUS) {
5621 state = m_getfld (state, name, buf, sizeof buf, in);
5622 (void) fputs (buf, out);
5625 if (state != FLDEOF)
5630 adios (NULLCP, "draft has empty body -- no directives!");
5635 (void) fseek (in, (long) (-strlen (buf)), 1);
5640 adios (NULLCP, "message format error in component #%d",
5644 adios (NULLCP, "getfld() returned %d", state);
5649 if ((free_ct = ct = (CT) calloc (1, sizeof *ct)) == NULL)
5650 adios (NULLCP, "out of memory");
5651 if (get_ctinfo ("multipart/mixed", ct, 0) == NOTOK)
5653 ct -> c_type = CT_MULTIPART;
5654 ct -> c_subtype = MULTI_MIXED;
5655 ct -> c_ctlistfnx = list_multi;
5656 ct -> c_ctfreefnx = free_multi;
5657 ct -> c_file = add (file, NULLCP);
5659 if ((m = (struct multipart *) calloc (1, sizeof *m)) == NULL)
5660 adios (NULLCP, "out of memory");
5661 ct -> c_ctparams = (caddr_t) m;
5663 pp = &m -> mp_parts;
5664 while (fgetstr (buf, sizeof buf - 1, in)) {
5665 register struct part *part;
5668 if (user_content (in, file, buf, &p) == DONE) {
5669 admonish (NULLCP, "ignoring spurious #end");
5675 if ((part = (struct part *) calloc (1, sizeof *part)) == NULL)
5676 adios (NULLCP, "out of memory");
5677 *pp = part, pp = &part -> mp_next;
5678 part -> mp_part = p;
5684 adios (NULLCP, "no content directives found");
5685 if (!m -> mp_parts -> mp_next) {
5686 CT p = m -> mp_parts -> mp_part;
5688 m -> mp_parts -> mp_part = NULL;
5695 if ((cp = index (prefix, 'a')) == NULL)
5696 adios (NULLCP, "internal error(4)");
5698 while (compose_content (ct) == NOTOK)
5704 "giving up trying to find a unique delimiter string");
5708 fprintf (out, "%s: %s\n", VRSN_FIELD, VRSN_VALUE);
5709 (void) output_content (ct, out);
5712 adios (tmpfil, "error writing to");
5714 (void) fclose (out);
5716 if (listsw && ct -> c_ctlistfnx) {
5720 printf (LSTFMT1, "msg", "part", "type/subtype", "size",
5724 savfile = ct -> c_file, ct -> c_file = file;
5725 (*ct -> c_ctlistfnx) (ct, 1);
5726 ct -> c_file = savfile;
5732 (void) sprintf (buf, "%s.orig", m_backup (file));
5733 if (rename (file, buf) == NOTOK)
5734 adios (buf, "unable to rename %s to", file);
5735 if (rename (tmpfil, file) == NOTOK) {
5736 advise (file, "unable to rename %s to", tmpfil);
5737 (void) rename (buf, file);
5747 static char *fgetstr (s, n, stream)
5755 for (ep = (cp = s) + n; cp < ep; ) {
5758 if (!fgets (cp, n, stream))
5759 return (cp != s ? s : NULL);
5760 if (cp == s && *cp != '#')
5763 cp += (i = strlen (cp)) - 1;
5764 if (i <= 1 || *cp-- != '\n' || *cp != '\\')
5766 *cp = 0, n -= (i - 2);
5774 static int user_content (in, file, buf, ctp)
5784 char buffer[BUFSIZ];
5785 struct multipart *m;
5786 register struct part **pp;
5788 register struct str2init *s2i;
5792 if (buf[0] == '\n' || strcmp (buf, "#\n") == 0) {
5797 if ((ct = (CT) calloc (1, sizeof *ct)) == NULL)
5798 adios (NULLCP, "out of memory");
5800 ci = &ct -> c_ctinfo;
5801 ct -> c_ctlistfnx = list_content;
5804 if (buf[0] != '#' || buf[1] == '#' || buf[1] == '<') {
5808 char content[BUFSIZ];
5811 ct -> c_file = add (m_tmpfil (invo_name), NULLCP);
5814 if ((out = fopen (ct -> c_file, "w")) == NULL)
5815 adios (ct -> c_file, "unable to open for writing");
5817 if (buf[0] == '#' && buf[1] == '<') {
5818 (void) strcpy (content, buf + 2);
5825 (void) strcpy (content, "text/plain");
5827 (void) strcpy (buffer, buf[0] != '#' ? buf : buf + 1);
5832 && uprf (buffer, DESCR_FIELD)
5833 && buffer[i = strlen (DESCR_FIELD)] == ':') {
5837 ct -> c_descr = add (buffer + i + 1, ct -> c_descr);
5838 if (!fgetstr (buffer, sizeof buffer - 1, in))
5840 "end-of-file after %s: field in plaintext",
5842 switch (buffer[0]) {
5850 "#-directive after %s: field in plaintext",
5859 if (headers != 1 || buffer[0] != '\n')
5860 (void) fputs (buffer, out);
5865 if ((cp = fgetstr (buffer, sizeof buffer - 1, in)) == NULL)
5867 if (buffer[0] == '#') {
5870 if (buffer[1] != '#')
5872 for (cp = (bp = buffer) + 1; *cp; cp++)
5879 ct -> c_end = ftell (out);
5880 (void) fclose (out);
5882 if (get_ctinfo (content, ct, inlineD) == NOTOK)
5884 for (s2i = str2cts; s2i -> si_key; s2i++)
5885 if (uleq (ci -> ci_type, s2i -> si_key))
5887 if (!s2i -> si_key && !uprf (ci -> ci_type, "X-"))
5889 switch (ct -> c_type = s2i -> si_val) {
5891 if (uleq (ci -> ci_subtype, "rfc822")) {
5892 ct -> c_encoding = CE_7BIT; /* XXX */
5898 "it makes sense to define a in-line %s content... NOT!",
5899 ct -> c_type == CT_MESSAGE ? "message" : "multipart");
5904 if (ct -> c_ctinitfnx = s2i -> si_init)
5905 (void) (*ct -> c_ctinitfnx) (ct);
5910 (void) fseek (in, pos, 0);
5914 extrnal = buf[1] == '@';
5915 if (get_ctinfo (buf + (extrnal ? 2 : 1), ct, 1) == NOTOK)
5918 for (s2i = str2cts; s2i -> si_key; s2i++)
5919 if (uleq (ci -> ci_type, s2i -> si_key))
5921 if (s2i -> si_key) { /* type/subtype [file] */
5922 if (!ci -> ci_subtype)
5923 adios (NULLCP, "missing subtype in \"#%s\"", ci -> ci_type);
5925 switch (ct -> c_type = s2i -> si_val) {
5927 adios (NULLCP, "use \"#begin ... #end\" instead of \"#%s/%s\"",
5928 ci -> ci_type, ci -> ci_subtype);
5932 if (uleq (ci -> ci_subtype, "partial"))
5933 adios (NULLCP, "sorry, \"#%s/%s\" isn't supported",
5934 ci -> ci_type, ci -> ci_subtype);
5935 if (uleq (ci -> ci_subtype, "external-body"))
5936 adios (NULLCP, "use \"#@type/subtype ... [] ...\" instead of \"#%s/%s\"",
5937 ci -> ci_type, ci -> ci_subtype);
5940 "use \"#forw [+folder] [msgs]\" instead of \"#%s/%s\"",
5941 ci -> ci_type, ci -> ci_subtype);
5945 if (ct -> c_ctinitfnx = s2i -> si_init)
5946 (void) (*ct -> c_ctinitfnx) (ct);
5951 register struct exbody *e;
5954 if (!ci -> ci_magic)
5955 adios (NULLCP, "need external information for \"#@%s/%s\"",
5956 ci -> ci_type, ci -> ci_subtype);
5959 (void) sprintf (buffer, "message/external-body; %s",
5961 free (ci -> ci_magic), ci -> ci_magic = NULL;
5963 if ((ct = (CT) calloc (1, sizeof *ct)) == NULL)
5964 adios (NULLCP, "out of memory");
5966 ci = &ct -> c_ctinfo;
5967 ct -> c_ctlistfnx = list_content;
5968 if (get_ctinfo (buffer, ct, 0) == NOTOK)
5970 ct -> c_type = CT_MESSAGE;
5971 ct -> c_subtype = MESSAGE_EXTERNAL;
5973 if ((e = (struct exbody *) calloc (1, sizeof *e)) == NULL)
5974 adios (NULLCP, "out of memory");
5975 ct -> c_ctparams = (caddr_t) e;
5976 ct -> c_ctfreefnx = free_external;
5978 e -> eb_parent = ct;
5979 e -> eb_content = p;
5980 p -> c_ctextern = (caddr_t) e;
5982 ct -> c_ctlistfnx = list_external;
5984 if (params_external (ct, 1) == NOTOK)
5990 if (ci -> ci_magic) {
5991 if (*ci -> ci_magic == '|' || *ci -> ci_magic == '!') {
5992 for (cp = ci -> ci_magic + 1; isspace (*cp); cp++)
5995 adios (NULLCP, "empty pipe command for #%s directive",
5997 cp = add (cp, NULLCP);
5998 free (ci -> ci_magic);
5999 ci -> ci_magic = cp;
6002 if (access (ct -> c_file = ci -> ci_magic, 04) == NOTOK)
6003 adios ("reading", "unable to access %s for", ct -> c_file);
6004 if (listsw && stat (ct -> c_file, &st) != NOTOK)
6005 ct -> c_end = (long) st.st_size;
6006 ci -> ci_magic = NULL;
6011 (void) sprintf (buffer, "%s-compose-%s/%s", invo_name, ci -> ci_type,
6013 if ((cp = m_find (buffer)) == NULL || *cp == 0) {
6014 (void) sprintf (buffer, "%s-compose-%s", invo_name, ci -> ci_type);
6015 if ((cp = m_find (buffer)) == NULL || *cp == 0) {
6016 content_error (NULLCP, ct,
6017 "don't know how to compose content");
6021 ci -> ci_magic = add (cp, NULLCP);
6026 adios (NULLCP, "externally definition not allowed for \"#%s\"",
6029 if (uleq (ci -> ci_type, "forw")) { /* #forw [+folder] [msgs] */
6032 *arguments[MAXARGS];
6035 if (ci -> ci_magic) {
6036 ap = brkstring (ci -> ci_magic, " ", "\n");
6037 ap = copyip (ap, arguments);
6040 arguments[0] = "cur", arguments[1] = NULL;
6043 for (ap = arguments; cp = *ap; ap++)
6044 if (*cp == '+' || *cp == '@')
6046 adios (NULLCP, "only one folder per #forw directive");
6048 folder = path (cp + 1, *cp == '+' ? TFOLDER : TSUBCWF);
6050 folder = add (m_getfolder (), NULLCP);
6052 if ((mp = m_gmsg (folder)) == NULL)
6053 adios (NULLCP, "unable to read folder %s", folder);
6054 for (ap = arguments; cp = *ap; ap++)
6055 if (*cp != '+' && *cp != '@')
6056 if (!m_convert (mp, cp))
6061 if (mp -> numsel > 1) {
6062 if (get_ctinfo ("multipart/digest", ct, 0) == NOTOK)
6064 ct -> c_type = CT_MULTIPART;
6065 ct -> c_subtype = MULTI_DIGEST;
6066 ct -> c_ctlistfnx = list_multi;
6067 ct -> c_ctfreefnx = free_multi;
6069 if ((m = (struct multipart *) calloc (1, sizeof *m)) == NULL)
6070 adios (NULLCP, "out of memory");
6071 ct -> c_ctparams = (caddr_t) m;
6073 pp = &m -> mp_parts;
6077 for (msgnum = mp -> lowsel; msgnum <= mp -> hghsel; msgnum++)
6078 if (mp -> msgstats[msgnum] & SELECTED) {
6079 register struct part *part;
6082 if ((p = (CT) calloc (1, sizeof *p)) == NULL)
6083 adios (NULLCP, "out of memory");
6084 if (get_ctinfo ("message/rfc822", p, 0) == NOTOK)
6086 p -> c_type = CT_MESSAGE;
6087 p -> c_subtype = MESSAGE_RFC822;
6088 p -> c_ctlistfnx = list_content;
6090 (void) sprintf (buffer, "%s/%d", mp -> foldpath, msgnum);
6091 p -> c_file = add (buffer, NULLCP);
6092 if (listsw && stat (p -> c_file, &st) != NOTOK)
6093 p -> c_end = (long) st.st_size;
6095 if (mp -> numsel > 1) {
6096 if ((part = (struct part *) calloc (1, sizeof *part))
6098 adios (NULLCP, "out of memory");
6099 *pp = part, pp = &part -> mp_next;
6100 part -> mp_part = p;
6111 if (uleq (ci -> ci_type, "end")) {
6117 if (!uleq (ci -> ci_type, "begin"))
6118 adios (NULLCP, "unknown directive \"#%s\"", ci -> ci_type);
6120 /* #begin [ alternative | parallel ] */
6121 if (!ci -> ci_magic)
6122 cp = SubMultiPart[(vrsn = MULTI_MIXED) - 1].kv_key;
6124 if (uleq (ci -> ci_magic, "alternative"))
6125 cp = SubMultiPart[(vrsn = MULTI_ALTERNATE) - 1].kv_key;
6127 if (uleq (ci -> ci_magic, "parallel"))
6128 cp = SubMultiPart[(vrsn = MULTI_PARALLEL) - 1].kv_key;
6130 if (uprf (ci -> ci_magic, "digest"))
6133 cp = ci -> ci_magic, vrsn = MULTI_UNKNOWN;
6135 (void) sprintf (buffer, "multipart/%s", cp);
6136 if (get_ctinfo (buffer, ct, 0) == NOTOK)
6138 ct -> c_type = CT_MULTIPART;
6139 ct -> c_subtype = vrsn;
6140 ct -> c_ctlistfnx = list_multi;
6141 ct -> c_ctfreefnx = free_multi;
6143 if ((m = (struct multipart *) calloc (1, sizeof *m)) == NULL)
6144 adios (NULLCP, "out of memory");
6145 ct -> c_ctparams = (caddr_t) m;
6147 pp = &m -> mp_parts;
6148 while (fgetstr (buffer, sizeof buffer - 1, in)) {
6149 register struct part *part;
6152 if (user_content (in, file, buffer, &p) == DONE) {
6154 adios (NULLCP, "empty \"#begin ... #end\" sequence");
6160 if ((part = (struct part *) calloc (1, sizeof *part)) == NULL)
6161 adios (NULLCP, "out of memory");
6162 *pp = part, pp = &part -> mp_next;
6163 part -> mp_part = p;
6165 admonish (NULLCP, "premature end-of-file, missing #end");
6171 static void set_id (ct, top)
6177 static long clock = 0L;
6178 static char *msgfmt;
6181 (void) time (&clock);
6182 (void) sprintf (msgid, "<%d.%ld.%%d@%s>\n", getpid (), clock,
6185 msgfmt = getcpy (msgid);
6187 (void) sprintf (msgid, msgfmt, top ? 0 : ++partno);
6188 ct -> c_id = getcpy (msgid);
6193 static char ebcdicsafe[0x100] = {
6194 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
6195 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
6196 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
6197 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
6198 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01,
6199 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
6200 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
6201 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
6202 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
6203 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
6204 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
6205 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01,
6206 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
6207 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
6208 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
6209 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
6210 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
6211 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
6212 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
6213 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
6214 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
6215 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
6216 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
6217 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
6218 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
6219 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
6220 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
6221 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
6222 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
6223 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
6224 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
6225 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
6228 static int compose_content (ct)
6232 char buffer[BUFSIZ];
6233 register CI ci = &ct -> c_ctinfo;
6235 if (ct -> c_type == CT_MESSAGE && ct -> c_subtype == MESSAGE_EXTERNAL)
6238 switch (ct -> c_type) {
6243 char partnam[BUFSIZ];
6244 struct multipart *m = (struct multipart *) ct -> c_ctparams;
6245 register struct part *part;
6247 if (ct -> c_partno) {
6248 (void) sprintf (partnam, "%s.", ct -> c_partno);
6249 pp = partnam + strlen (partnam);
6254 for (part = m -> mp_parts, partnum = 1;
6256 part = part -> mp_next, partnum++) {
6257 register CT p = part -> mp_part;
6259 (void) sprintf (pp, "%d", partnum);
6260 p -> c_partno = add (partnam, NULLCP);
6262 if (compose_content (p) == NOTOK)
6266 if (rfc934sw && ct -> c_subtype == MULTI_DIGEST) {
6269 for (part = m -> mp_parts; part; part = part -> mp_next) {
6270 register CT p = part -> mp_part;
6272 if (p -> c_subtype != MESSAGE_RFC822) {
6278 ct -> c_rfc934 = is934;
6279 for (part = m -> mp_parts; part; part = part -> mp_next) {
6280 register CT p = part -> mp_part;
6282 if (p -> c_rfc934 = is934)
6288 ct -> c_end = (partnum = strlen (prefix) + 2) + 2;
6292 for (part = m -> mp_parts; part; part = part -> mp_next)
6293 ct -> c_end += part -> mp_part -> c_end + partnum;
6300 if (!ct -> c_file) {
6309 if (!(cp = ci -> ci_magic))
6310 adios (NULLCP, "internal error(5)");
6312 ct -> c_file = add (m_tmpfil (invo_name), NULLCP);
6317 for (bp = buffer; *cp; cp++)
6320 case 'a': /* additional arguments */
6325 for (ap = ci -> ci_attrs, ep = ci -> ci_values;
6328 (void) sprintf (bp, "%s%s=\"%s\"", s,
6336 case 'F': /* %f, and stdout is not-redirected */
6339 case 'f': /* filename */
6340 (void) sprintf (bp, "%s", ct -> c_file);
6343 case 's': /* subtype */
6344 (void) strcpy (bp, ci -> ci_subtype);
6363 printf ("composing content %s/%s from command\n\t%s\n",
6364 ci -> ci_type, ci -> ci_subtype, buffer);
6365 (void) fflush (stdout);
6372 if ((out = fopen (ct -> c_file, "w")) == NULL)
6373 adios (ct -> c_file, "unable to open for writing");
6375 for (i = 0; (child_id = vfork ()) == NOTOK && i > 5; i++)
6379 adios ("fork", "unable to fork");
6384 (void) dup2 (fileno (out), 1);
6385 (void) close (fileno (out));
6386 (void) execvp ("/bin/sh", vec);
6387 fprintf (stderr, "unable to exec ");
6393 (void) fclose (out);
6394 if (pidXwait (child_id, NULLCP))
6399 if (listsw && ct -> c_end == 0L) {
6402 if (stat (ct -> c_file, &st) != NOTOK)
6403 ct -> c_end = (long) st.st_size;
6405 if (ct -> c_type != CT_TEXT && ct -> c_type != CT_APPLICATION)
6417 if ((in = fopen (ct -> c_file, "r")) == NULL)
6418 adios (ct -> c_file, "unable to open for reading");
6420 len = strlen (prefix);
6422 switch (ct -> c_type) {
6424 charset = ct -> c_ctparams ? 0 : -1;
6425 linelen = ct -> c_subtype == TEXT_PLAIN ? 0 : -1;
6428 case CT_APPLICATION:
6429 charset = linelen = ct -> c_encoding ? 0 : -1;
6433 charset = linelen = 0;
6436 while (fgets (buffer, sizeof buffer - 1, in)) {
6437 if (charset == -1) {
6438 for (cp = buffer; *cp; cp++) {
6439 if (!isascii (*cp)) {
6440 charset = CHARSET_UNKNOWN;
6445 && !ebcdicsafe[*cp & 0xff])
6448 if ((linelen == -1) && (cp - buffer > CPERLIN + 1))
6450 if (result == NOTOK)
6454 if ((linelen == -1) && (strlen (buffer) > CPERLIN + 1))
6456 if (result == NOTOK)
6459 if (linelen == -1) {
6460 if ((cp = buffer + strlen (buffer) - 2) > buffer
6464 if ((*(cp = buffer) == '.')
6465 || (strncmp (cp, "From ",
6466 sizeof "From " -1) == 0))
6470 if (buffer[0] == '-' && buffer[1] == '-') {
6471 for (cp = buffer + strlen (buffer) - 1;
6477 if (strncmp (buffer + 2, prefix, len) == 0
6478 && isdigit (buffer[2 + len])) {
6480 if (charset != -1 && linelen != -1)
6485 if (ct -> c_type == CT_APPLICATION && !ct -> c_encoding)
6486 ct -> c_encoding = linelen == -1
6487 && charset != CHARSET_UNKNOWN
6490 != APPLICATION_POSTSCRIPT
6491 ? CE_BASE64 : CE_QUOTED;
6492 if (ct -> c_type == CT_TEXT && !ct -> c_ctparams) {
6495 register struct text *t;
6497 if (charset == CHARSET_UNKNOWN && mm_charset)
6501 charset = CHARSET_USASCII;
6503 if ((t = (struct text *) calloc (1, sizeof *t)) == NULL)
6504 adios (NULLCP, "out of memory");
6505 ct -> c_ctparams = (caddr_t) t;
6506 for (ap = ci -> ci_attrs, ep = ci -> ci_values;
6510 switch (t -> tx_charset = charset) {
6511 case CHARSET_USASCII:
6512 *ap = add ("charset=us-ascii", NULLCP);
6515 case CHARSET_UNKNOWN:
6517 *ap = add ("charset=x-unknown", NULLCP);
6521 *ap = concat ("charset=", mm_charset, NULLCP);
6524 cp = index (*ap++, '=');
6529 if (ct -> c_type == CT_TEXT && ct -> c_subtype != TEXT_PLAIN)
6530 ct -> c_encoding = linelen == -1 ? CE_7BIT : CE_QUOTED;
6543 static int output_content (ct, out)
6552 char buffer[BUFSIZ];
6553 register CI ci = &ct -> c_ctinfo;
6555 if (ct -> c_type == CT_MULTIPART) {
6557 static int encl = 0;
6559 ap = ci -> ci_attrs, ep = ci -> ci_values;
6561 (void) sprintf (buffer, "boundary=%s%d", prefix, encl++);
6562 cp = index (*ap++ = add (buffer, NULLCP), '=');
6568 if (ct -> c_type == CT_MESSAGE && ct -> c_rfc934)
6572 fprintf (out, "%s: %s/%s", TYPE_FIELD, ci -> ci_type, ci -> ci_subtype);
6573 len += strlen (TYPE_FIELD) + 2 + strlen (ci -> ci_type)
6574 + 1 + strlen (ci -> ci_subtype);
6575 mailbody = ct -> c_type == CT_MESSAGE
6576 && ct -> c_subtype == MESSAGE_EXTERNAL
6577 && ((struct exbody *) ct -> c_ctparams) -> eb_body;
6578 for (ap = ci -> ci_attrs, ep = ci -> ci_values; *ap; ap++, ep++) {
6579 if (mailbody && uleq (*ap, "body"))
6582 (void) putc (';', out);
6585 (void) sprintf (buffer, "%s=\"%s\"", *ap, *ep);
6587 if (len + 1 + (cc = strlen (buffer)) >= CPERLIN) {
6588 (void) fputs ("\n\t", out);
6592 (void) putc (' ', out);
6595 fputs (buffer, out);
6598 if (ci -> ci_comment) {
6599 if (len + 1 + (cc = 2 + strlen (ci -> ci_comment)) >= CPERLIN) {
6600 (void) fputs ("\n\t", out);
6604 (void) putc (' ', out);
6607 fprintf (out, "(%s)", ci -> ci_comment);
6610 (void) putc ('\n', out);
6612 fprintf (out, "%s: %s", ID_FIELD, ct -> c_id);
6614 fprintf (out, "%s: %s", DESCR_FIELD, ct -> c_descr);
6617 if (ct -> c_ctextern)
6619 switch (ct -> c_type) {
6622 struct multipart *m = (struct multipart *) ct -> c_ctparams;
6623 register struct part *part;
6626 (void) putc ('\n', out);
6628 for (part = m -> mp_parts; part; part = part -> mp_next) {
6629 register CT p = part -> mp_part;
6631 fprintf (out, "\n--%s\n", ci -> ci_values[0]);
6632 (void) output_content (p, out);
6635 fprintf (out, "\n--%s--\n", ci -> ci_values[0]);
6640 if (ct -> c_ctparams
6641 && ((struct text *) ct -> c_ctparams) -> tx_charset
6642 != CHARSET_USASCII) {
6645 writeDigest (ct, out, 1);
6646 fprintf (out, "%s: %s\n\n", ENCODING_FIELD,
6647 "quoted-printable");
6648 (void) writeQuoted (ct, out);
6651 if ((ct -> c_subtype != TEXT_PLAIN && ct -> c_encoding != CE_7BIT)
6653 goto quoted_printable;
6658 (void) putc ('\n', out);
6659 if (ct -> c_type == CT_MESSAGE
6660 && ct -> c_subtype == MESSAGE_EXTERNAL) {
6661 register struct exbody *e = (struct exbody *) ct -> c_ctparams;
6663 (void) output_content (e -> eb_content, out);
6668 for (cp = e -> eb_body; *cp; cp++) {
6669 CT ct2 = e -> eb_content;
6670 CI ci2 = &ct2 -> c_ctinfo;
6676 char *dp = trimcpy (ct2 -> c_id);
6678 (void) fputs (dp, out);
6684 for (ap = ci2 -> ci_attrs,
6685 ep = ci2 -> ci_values;
6688 if (uleq (*ap, "name")) {
6689 fprintf (out, "%s", *ep);
6695 fprintf (out, "%s/%s", ci2 -> ci_type,
6697 for (ap = ci2 -> ci_attrs,
6698 ep = ci2 -> ci_values;
6701 fprintf (out, "; %s=\"%s\"", *ap, *ep);
6705 (void) putc ('\n', out);
6709 (void) putc ('\t', out);
6721 (void) putc ('\\', out);
6725 (void) putc (*cp, out);
6731 (void) write7Bit (ct, out);
6734 case CT_APPLICATION:
6735 switch (ct -> c_encoding) {
6740 goto quoted_printable;
6749 writeDigest (ct, out, 0);
6750 fprintf (out, "%s: %s\n\n", ENCODING_FIELD, "base64");
6751 (void) writeBase64 (ct, out);
6760 static int write7Bit (ct, out)
6768 if ((in = fopen (ct -> c_file, "r")) == NULL)
6769 adios (ct -> c_file, "unable to open for reading");
6772 while (fgets (buffer, sizeof buffer - 1, in)) {
6773 c = buffer[strlen (buffer) - 1];
6774 (void) fputs (buffer, out);
6777 (void) putc ('\n', out);
6786 static int writeQuoted (ct, out)
6795 if ((in = fopen (ct -> c_file, "r")) == NULL)
6796 adios (ct -> c_file, "unable to open for reading");
6798 while (fgets (buffer, sizeof buffer - 1, in)) {
6801 cp = buffer + strlen (buffer) - 1;
6802 if ((c = *cp) == '\n')
6805 if ((*(cp = buffer) == '.')
6806 || (strncmp (cp, "From ", sizeof "From " - 1) == 0)) {
6807 (void) fprintf (out, "=%02X", *cp++ & 0xff);
6813 if (n > CPERLIN - 3) {
6814 (void) fputs ("=\n", out);
6821 (void) putc (*cp, out);
6828 || (ebcdicsw && !ebcdicsafe[*cp & 0xff]))
6830 (void) putc (*cp, out);
6836 (void) fprintf (out, "=%02X", *cp & 0xff);
6843 if (cp > buffer && (*--cp == ' ' || *cp == '\t'))
6844 (void) fputs ("=\n", out);
6846 (void) putc ('\n', out);
6849 (void) fputs ("=\n", out);
6859 static char nib2b64[0x40+1] =
6860 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
6863 static int writeBase64 (ct, out)
6870 if ((in = fopen (ct -> c_file, "r")) == NULL)
6871 adios (ct -> c_file, "unable to open for reading");
6873 result = writeBase64aux (in, out);
6881 static int writeBase64aux (in, out)
6890 while ((cc = fread (inbuf, sizeof *inbuf, sizeof inbuf, in)) > 0) {
6895 if (cc < sizeof inbuf) {
6897 if (cc < sizeof inbuf - 1)
6900 bits = (inbuf[0] & 0xff) << 16;
6901 bits |= (inbuf[1] & 0xff) << 8;
6902 bits |= inbuf[2] & 0xff;
6904 for (bp = outbuf + sizeof outbuf; bp > outbuf; bits >>= 6)
6905 *--bp = nib2b64[bits & 0x3f];
6906 if (cc < sizeof inbuf) {
6908 if (cc < sizeof inbuf - 1)
6912 (void) fwrite (outbuf, sizeof *outbuf, sizeof outbuf, out);
6914 if (cc < sizeof inbuf) {
6915 (void) putc ('\n', out);
6921 (void) putc ('\n', out);
6925 (void) putc ('\n', out);
6932 static int writeDigest (ct, out, asciiP)
6938 char buffer[BUFSIZ];
6939 register unsigned char *dp;
6940 unsigned char digest[16];
6944 if ((in = fopen (ct -> c_file, "r")) == NULL)
6945 adios (ct -> c_file, "unable to open for reading");
6947 MD5Init (&mdContext);
6949 while (fgets (buffer, sizeof buffer - 1, in)) {
6953 cp = buffer + strlen (buffer) - 1;
6954 if ((c = *cp) == '\n')
6957 MD5Update (&mdContext, (unsigned char *) buffer,
6958 (unsigned int) strlen (buffer));
6961 MD5Update (&mdContext, (unsigned char *) "\r\n", 2);
6965 while ((cc = fread (buffer, sizeof *buffer, sizeof buffer, in)) > 0)
6966 MD5Update (&mdContext, (unsigned char *) buffer,
6968 MD5Final (digest, &mdContext);
6972 fprintf (stderr, "MD5 digest=");
6973 for (ep = (dp = digest) + sizeof digest / sizeof digest[0];
6976 fprintf (stderr, "%02x", *dp & 0xff);
6977 fprintf (stderr, "\n");
6982 fprintf (out, "%s: ", MD5_FIELD);
6983 for (dp = digest, cc = sizeof digest / sizeof digest[0]; cc > 0; cc -= 3) {
6988 bits = (*dp++ & 0xff) << 16;
6990 bits |= (*dp++ & 0xff) << 8;
6992 bits |= *dp++ & 0xff;
6995 for (bp = outbuf + sizeof outbuf; bp > outbuf; bits >>= 6)
6996 *--bp = nib2b64[bits & 0x3f];
7003 (void) fwrite (outbuf, sizeof *outbuf, sizeof outbuf, out);
7005 fprintf (out, "\n");
7010 static int readDigest (ct, cp)
7018 register unsigned char *dp;
7019 unsigned char value,
7021 *b = (unsigned char *) &bits,
7022 *b1 = &b[endian > 0 ? 1 : 2],
7023 *b2 = &b[endian > 0 ? 2 : 1],
7024 *b3 = &b[endian > 0 ? 3 : 0];
7026 bitno = 18, bits = 0L, skip = 0;
7027 for (ep = (dp = ct -> c_digest)
7028 + sizeof ct -> c_digest / sizeof ct -> c_digest[0];
7035 || (value = b642nib[*cp & 0x7f]) > 0x3f) {
7037 fprintf (stderr, "invalid BASE64 encoding\n");
7041 bits |= value << bitno;
7043 if ((bitno -= 6) < 0) {
7044 if (dp + (3 - skip) > ep)
7045 goto invalid_digest;
7052 bitno = 18, bits = 0L, skip = 0;
7058 goto self_delimiting;
7063 fprintf (stderr, "premature ending (bitno %d)\n", bitno);
7073 fprintf (stderr, "invalid MD5 digest (got %d octets)\n",
7081 fprintf (stderr, "MD5 digest=");
7082 for (dp = ct -> c_digest; dp < ep; dp++)
7083 fprintf (stderr, "%02x", *dp & 0xff);
7084 fprintf (stderr, "\n");
7092 #include "../zotnet/tws.h"
7095 static int via_mail (mailsw, subjsw, parmsw, descsw, cmntsw, slowsw, fromsw)
7109 char tmpfil[BUFSIZ];
7113 (void) umask (~m_gmprot ());
7115 (void) strcpy (tmpfil, m_tmpfil (invo_name));
7116 if ((fp = fopen (tmpfil, "w+")) == NULL)
7117 adios (tmpfil, "unable to open for writing");
7118 (void) chmod (tmpfil, 0600);
7120 if (!index (mailsw, '@'))
7121 mailsw = concat (mailsw, "@", LocalName (), NULLCP);
7122 fprintf (fp, "To: %s\n", mailsw);
7125 fprintf (fp, "Subject: %s\n", subjsw), nlines++;
7127 if (!index (fromsw, '@'))
7128 fromsw = concat (fromsw, "@", LocalName (), NULLCP);
7129 fprintf (fp, "From: %s\n", fromsw), nlines++;
7131 fprintf (fp, "%s: %s\n", VRSN_FIELD, VRSN_VALUE), nlines++;
7132 offset = ftell (fp);
7133 fprintf (fp, "%s: application/octet-stream", TYPE_FIELD);
7135 fprintf (fp, "; %s", parmsw);
7137 fprintf (fp, "\n\t(%s)", cmntsw), nlines++;
7139 fprintf (fp, "\n%s: %s", DESCR_FIELD, descsw), nlines++;
7140 fprintf (fp, "\n%s: %s\n\n", ENCODING_FIELD, "base64"), nlines += 2;
7142 adios (tmpfil, "error writing to");
7145 (void) writeBase64aux (stdin, fp);
7147 adios (tmpfil, "error writing to");
7149 if (fstat (fileno (fp), &st) == NOTOK)
7150 adios ("failed", "fstat of %s", tmpfil);
7151 nlines += (((long) st.st_size - pos) + CPERLIN) / (CPERLIN + 1);
7152 nparts = (nlines + (LPERMSG - 1)) / LPERMSG;
7155 status = via_post (tmpfil, 0);
7159 char buffer[BUFSIZ],
7163 printf ("sending binary image as %d partial messages\n", nparts);
7164 (void) fflush (stdout);
7167 (void) time (&clock);
7168 (void) sprintf (msgid, "<%d.%ld@%s>", getpid (), clock, LocalName ());
7170 (void) fseek (fp, offset, 0);
7171 for (partno = 1; partno <= nparts; partno++) {
7173 char tmpdrf[BUFSIZ];
7176 (void) strcpy (tmpdrf, m_tmpfil (invo_name));
7177 if ((out = fopen (tmpdrf, "w")) == NULL)
7178 adios (tmpdrf, "unable to open for writing");
7179 (void) chmod (tmpdrf, 0600);
7181 fprintf (out, "To: %s\n", mailsw);
7183 fprintf (out, "Subject: %s\n", subjsw);
7184 fprintf (out, "%s: %s\n", VRSN_FIELD, VRSN_VALUE);
7186 "%s: message/partial; id=\"%s\";\n\tnumber=%d; total=%d\n",
7187 TYPE_FIELD, msgid, partno, nparts);
7188 fprintf (out, "%s: part %d of %d\n\n", DESCR_FIELD, partno,
7192 fprintf (out, "Message-ID: %s\n", msgid);
7194 for (lineno = LPERMSG; lineno > 0; lineno--) {
7195 if (!fgets (buffer, sizeof buffer, fp)) {
7196 if (partno == nparts)
7198 adios (NULLCP, "premature eof");
7201 (void) fputs (buffer, out);
7203 offset = ftell (fp);
7206 adios (tmpdrf, "error writing to");
7208 (void) fclose (out);
7210 status = via_post (tmpdrf, slowsw == 0);
7211 (void) unlink (tmpdrf);
7215 if (slowsw > 0 && partno < nparts) {
7217 printf ("pausing %d seconds before sending part %d...\n",
7218 slowsw, partno + 1);
7219 (void) fflush (stdout);
7222 sleep ((unsigned) slowsw);
7228 (void) unlink (tmpfil);
7230 done (status ? 1 : 0);
7235 static int via_post (file, queued)
7242 for (i = 0; (child_id = fork ()) == NOTOK && i < 5; i++)
7246 adios ("fork", "unable to");
7250 (void) execlp (postproc, r1bindex (postproc, '/'), file,
7251 queued ? "-queued" : NULLCP, NULLCP);
7252 fprintf (stderr, "unable to exec ");
7258 return pidXwait (child_id, postproc);
7271 free_content (*ctp);
7273 free_content (free_ct);
7275 (void) unlink (free_file);
7281 static int pidcheck (status)
7284 if ((status & 0xff00) == 0xff00 || (status & 0x007f) != SIGQUIT)
7287 (void) unlink ("core");
7289 (void) fflush (stdout);
7291 (void) fflush (stderr);