[12454] | 1 | |
---|
| 2 | /* |
---|
| 3 | * mhoutsbr.c -- routines to output MIME messages |
---|
| 4 | * -- given a Content structure |
---|
| 5 | * |
---|
| 6 | * $Id: mhoutsbr.c,v 1.1.1.1 1999-02-07 18:14:14 danw Exp $ |
---|
| 7 | */ |
---|
| 8 | |
---|
| 9 | #include <h/mh.h> |
---|
| 10 | #include <fcntl.h> |
---|
| 11 | #include <h/signals.h> |
---|
| 12 | #include <h/md5.h> |
---|
| 13 | #include <errno.h> |
---|
| 14 | #include <signal.h> |
---|
| 15 | #include <zotnet/mts/mts.h> |
---|
| 16 | #include <zotnet/tws/tws.h> |
---|
| 17 | #include <h/mime.h> |
---|
| 18 | #include <h/mhparse.h> |
---|
| 19 | |
---|
| 20 | #ifdef HAVE_SYS_WAIT_H |
---|
| 21 | # include <sys/wait.h> |
---|
| 22 | #endif |
---|
| 23 | |
---|
| 24 | |
---|
| 25 | extern int errno; |
---|
| 26 | extern int ebcdicsw; |
---|
| 27 | |
---|
| 28 | static char ebcdicsafe[0x100] = { |
---|
| 29 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
---|
| 30 | 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, |
---|
| 31 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
---|
| 32 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
---|
| 33 | 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, |
---|
| 34 | 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, |
---|
| 35 | 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, |
---|
| 36 | 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, |
---|
| 37 | 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, |
---|
| 38 | 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, |
---|
| 39 | 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, |
---|
| 40 | 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, |
---|
| 41 | 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, |
---|
| 42 | 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, |
---|
| 43 | 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, |
---|
| 44 | 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, |
---|
| 45 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
---|
| 46 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
---|
| 47 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
---|
| 48 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
---|
| 49 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
---|
| 50 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
---|
| 51 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
---|
| 52 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
---|
| 53 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
---|
| 54 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
---|
| 55 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
---|
| 56 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
---|
| 57 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
---|
| 58 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
---|
| 59 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
---|
| 60 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 |
---|
| 61 | }; |
---|
| 62 | |
---|
| 63 | static char nib2b64[0x40+1] = |
---|
| 64 | "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; |
---|
| 65 | |
---|
| 66 | /* |
---|
| 67 | * prototypes |
---|
| 68 | */ |
---|
| 69 | int output_message (CT, char *); |
---|
| 70 | int writeBase64aux (FILE *, FILE *); |
---|
| 71 | |
---|
| 72 | /* |
---|
| 73 | * static prototypes |
---|
| 74 | */ |
---|
| 75 | static int output_content (CT, FILE *); |
---|
| 76 | static int output_headers (CT, FILE *); |
---|
| 77 | static int writeExternalBody (CT, FILE *); |
---|
| 78 | static int write8Bit (CT, FILE *); |
---|
| 79 | static int writeQuoted (CT, FILE *); |
---|
| 80 | static int writeBase64 (CT, FILE *); |
---|
| 81 | |
---|
| 82 | |
---|
| 83 | /* |
---|
| 84 | * Main routine to output a MIME message contained |
---|
| 85 | * in a Content structure, to a file. Any necessary |
---|
| 86 | * transfer encoding is added. |
---|
| 87 | */ |
---|
| 88 | |
---|
| 89 | int |
---|
| 90 | output_message (CT ct, char *file) |
---|
| 91 | { |
---|
| 92 | FILE *fp; |
---|
| 93 | |
---|
| 94 | if ((fp = fopen (file, "w")) == NULL) { |
---|
| 95 | advise (file, "unable to open for writing"); |
---|
| 96 | return NOTOK; |
---|
| 97 | } |
---|
| 98 | |
---|
| 99 | if (output_content (ct, fp) == NOTOK) |
---|
| 100 | return NOTOK; |
---|
| 101 | |
---|
| 102 | if (fflush (fp)) { |
---|
| 103 | advise (file, "error writing to"); |
---|
| 104 | return NOTOK; |
---|
| 105 | } |
---|
| 106 | fclose (fp); |
---|
| 107 | |
---|
| 108 | return OK; |
---|
| 109 | } |
---|
| 110 | |
---|
| 111 | |
---|
| 112 | /* |
---|
| 113 | * Output a Content structure to a file. |
---|
| 114 | */ |
---|
| 115 | |
---|
| 116 | static int |
---|
| 117 | output_content (CT ct, FILE *out) |
---|
| 118 | { |
---|
| 119 | int result = 0; |
---|
| 120 | CI ci = &ct->c_ctinfo; |
---|
| 121 | |
---|
| 122 | /* |
---|
| 123 | * Output all header fields for this content |
---|
| 124 | */ |
---|
| 125 | output_headers (ct, out); |
---|
| 126 | |
---|
| 127 | /* |
---|
| 128 | * If this is the internal content structure for a |
---|
| 129 | * "message/external", then we are done with the |
---|
| 130 | * headers (since it has no body). |
---|
| 131 | */ |
---|
| 132 | if (ct->c_ctexbody) |
---|
| 133 | return OK; |
---|
| 134 | |
---|
| 135 | /* |
---|
| 136 | * Now output the content bodies. |
---|
| 137 | */ |
---|
| 138 | switch (ct->c_type) { |
---|
| 139 | case CT_MULTIPART: |
---|
| 140 | { |
---|
| 141 | struct multipart *m; |
---|
| 142 | struct part *part; |
---|
| 143 | |
---|
| 144 | if (ct->c_rfc934) |
---|
| 145 | putc ('\n', out); |
---|
| 146 | |
---|
| 147 | m = (struct multipart *) ct->c_ctparams; |
---|
| 148 | for (part = m->mp_parts; part; part = part->mp_next) { |
---|
| 149 | CT p = part->mp_part; |
---|
| 150 | |
---|
| 151 | fprintf (out, "\n--%s\n", ci->ci_values[0]); |
---|
| 152 | if (output_content (p, out) == NOTOK) |
---|
| 153 | return NOTOK; |
---|
| 154 | } |
---|
| 155 | fprintf (out, "\n--%s--\n", ci->ci_values[0]); |
---|
| 156 | } |
---|
| 157 | break; |
---|
| 158 | |
---|
| 159 | case CT_MESSAGE: |
---|
| 160 | putc ('\n', out); |
---|
| 161 | if (ct->c_subtype == MESSAGE_EXTERNAL) { |
---|
| 162 | struct exbody *e; |
---|
| 163 | |
---|
| 164 | e = (struct exbody *) ct->c_ctparams; |
---|
| 165 | if (output_content (e->eb_content, out) == NOTOK) |
---|
| 166 | return NOTOK; |
---|
| 167 | |
---|
| 168 | /* output phantom body for access-type "mail-server" */ |
---|
| 169 | if (e->eb_body) |
---|
| 170 | writeExternalBody (ct, out); |
---|
| 171 | } else { |
---|
| 172 | result = write8Bit (ct, out); |
---|
| 173 | } |
---|
| 174 | break; |
---|
| 175 | |
---|
| 176 | /* |
---|
| 177 | * Handle discrete types (text/application/audio/image/video) |
---|
| 178 | */ |
---|
| 179 | default: |
---|
| 180 | switch (ct->c_encoding) { |
---|
| 181 | case CE_7BIT: |
---|
| 182 | putc ('\n', out); |
---|
| 183 | result = write8Bit (ct, out); |
---|
| 184 | break; |
---|
| 185 | |
---|
| 186 | case CE_8BIT: |
---|
| 187 | putc ('\n', out); |
---|
| 188 | result = write8Bit (ct, out); |
---|
| 189 | break; |
---|
| 190 | |
---|
| 191 | case CE_QUOTED: |
---|
| 192 | putc ('\n', out); |
---|
| 193 | result = writeQuoted (ct, out); |
---|
| 194 | break; |
---|
| 195 | |
---|
| 196 | case CE_BASE64: |
---|
| 197 | putc ('\n', out); |
---|
| 198 | result = writeBase64 (ct, out); |
---|
| 199 | break; |
---|
| 200 | |
---|
| 201 | case CE_BINARY: |
---|
| 202 | advise (NULL, "can't handle binary transfer encoding in content"); |
---|
| 203 | result = NOTOK; |
---|
| 204 | break; |
---|
| 205 | |
---|
| 206 | default: |
---|
| 207 | advise (NULL, "unknown transfer encoding in content"); |
---|
| 208 | result = NOTOK; |
---|
| 209 | break; |
---|
| 210 | } |
---|
| 211 | break; |
---|
| 212 | } |
---|
| 213 | |
---|
| 214 | return result; |
---|
| 215 | } |
---|
| 216 | |
---|
| 217 | |
---|
| 218 | /* |
---|
| 219 | * Output all the header fields for a content |
---|
| 220 | */ |
---|
| 221 | |
---|
| 222 | static int |
---|
| 223 | output_headers (CT ct, FILE *out) |
---|
| 224 | { |
---|
| 225 | HF hp; |
---|
| 226 | |
---|
| 227 | hp = ct->c_first_hf; |
---|
| 228 | while (hp) { |
---|
| 229 | fprintf (out, "%s:%s", hp->name, hp->value); |
---|
| 230 | hp = hp->next; |
---|
| 231 | } |
---|
| 232 | } |
---|
| 233 | |
---|
| 234 | |
---|
| 235 | /* |
---|
| 236 | * Write the phantom body for access-type "mail-server". |
---|
| 237 | */ |
---|
| 238 | |
---|
| 239 | static int |
---|
| 240 | writeExternalBody (CT ct, FILE *out) |
---|
| 241 | { |
---|
| 242 | char **ap, **ep, *cp; |
---|
| 243 | struct exbody *e = (struct exbody *) ct->c_ctparams; |
---|
| 244 | |
---|
| 245 | putc ('\n', out); |
---|
| 246 | for (cp = e->eb_body; *cp; cp++) { |
---|
| 247 | CT ct2 = e->eb_content; |
---|
| 248 | CI ci2 = &ct2->c_ctinfo; |
---|
| 249 | |
---|
| 250 | if (*cp == '\\') { |
---|
| 251 | switch (*++cp) { |
---|
| 252 | case 'I': |
---|
| 253 | if (ct2->c_id) { |
---|
| 254 | char *dp = trimcpy (ct2->c_id); |
---|
| 255 | |
---|
| 256 | fputs (dp, out); |
---|
| 257 | free (dp); |
---|
| 258 | } |
---|
| 259 | continue; |
---|
| 260 | |
---|
| 261 | case 'N': |
---|
| 262 | for (ap = ci2->ci_attrs, ep = ci2->ci_values; *ap; ap++, ep++) |
---|
| 263 | if (!strcasecmp (*ap, "name")) { |
---|
| 264 | fprintf (out, "%s", *ep); |
---|
| 265 | break; |
---|
| 266 | } |
---|
| 267 | continue; |
---|
| 268 | |
---|
| 269 | case 'T': |
---|
| 270 | fprintf (out, "%s/%s", ci2->ci_type, ci2->ci_subtype); |
---|
| 271 | for (ap = ci2->ci_attrs, ep = ci2->ci_values; *ap; ap++, ep++) |
---|
| 272 | fprintf (out, "; %s=\"%s\"", *ap, *ep); |
---|
| 273 | continue; |
---|
| 274 | |
---|
| 275 | case 'n': |
---|
| 276 | putc ('\n', out); |
---|
| 277 | continue; |
---|
| 278 | |
---|
| 279 | case 't': |
---|
| 280 | putc ('\t', out); |
---|
| 281 | continue; |
---|
| 282 | |
---|
| 283 | case '\0': |
---|
| 284 | cp--; |
---|
| 285 | break; |
---|
| 286 | |
---|
| 287 | case '\\': |
---|
| 288 | case '"': |
---|
| 289 | break; |
---|
| 290 | |
---|
| 291 | default: |
---|
| 292 | putc ('\\', out); |
---|
| 293 | break; |
---|
| 294 | } |
---|
| 295 | } |
---|
| 296 | putc (*cp, out); |
---|
| 297 | } |
---|
| 298 | putc ('\n', out); |
---|
| 299 | |
---|
| 300 | return OK; |
---|
| 301 | } |
---|
| 302 | |
---|
| 303 | |
---|
| 304 | /* |
---|
| 305 | * Output a content without any transfer encoding |
---|
| 306 | */ |
---|
| 307 | |
---|
| 308 | static int |
---|
| 309 | write8Bit (CT ct, FILE *out) |
---|
| 310 | { |
---|
| 311 | int fd; |
---|
| 312 | char c, *file, buffer[BUFSIZ]; |
---|
| 313 | CE ce = ct->c_cefile; |
---|
| 314 | |
---|
| 315 | file = NULL; |
---|
| 316 | if ((fd = (*ct->c_ceopenfnx) (ct, &file)) == NOTOK) |
---|
| 317 | return NOTOK; |
---|
| 318 | |
---|
| 319 | c = '\n'; |
---|
| 320 | while (fgets (buffer, sizeof(buffer) - 1, ce->ce_fp)) { |
---|
| 321 | c = buffer[strlen (buffer) - 1]; |
---|
| 322 | fputs (buffer, out); |
---|
| 323 | } |
---|
| 324 | if (c != '\n') |
---|
| 325 | putc ('\n', out); |
---|
| 326 | |
---|
| 327 | (*ct->c_ceclosefnx) (ct); |
---|
| 328 | return OK; |
---|
| 329 | } |
---|
| 330 | |
---|
| 331 | |
---|
| 332 | /* |
---|
| 333 | * Output a content using quoted-printable |
---|
| 334 | */ |
---|
| 335 | |
---|
| 336 | static int |
---|
| 337 | writeQuoted (CT ct, FILE *out) |
---|
| 338 | { |
---|
| 339 | int fd; |
---|
| 340 | char *cp, *file; |
---|
| 341 | char c, buffer[BUFSIZ]; |
---|
| 342 | CE ce = ct->c_cefile; |
---|
| 343 | |
---|
| 344 | file = NULL; |
---|
| 345 | if ((fd = (*ct->c_ceopenfnx) (ct, &file)) == NOTOK) |
---|
| 346 | return NOTOK; |
---|
| 347 | |
---|
| 348 | while (fgets (buffer, sizeof(buffer) - 1, ce->ce_fp)) { |
---|
| 349 | int n; |
---|
| 350 | |
---|
| 351 | cp = buffer + strlen (buffer) - 1; |
---|
| 352 | if ((c = *cp) == '\n') |
---|
| 353 | *cp = '\0'; |
---|
| 354 | |
---|
| 355 | if (strncmp (cp = buffer, "From ", sizeof("From ") - 1) == 0) { |
---|
| 356 | fprintf (out, "=%02X", *cp++ & 0xff); |
---|
| 357 | n = 3; |
---|
| 358 | } else { |
---|
| 359 | n = 0; |
---|
| 360 | } |
---|
| 361 | for (; *cp; cp++) { |
---|
| 362 | if (n > CPERLIN - 3) { |
---|
| 363 | fputs ("=\n", out); |
---|
| 364 | n = 0; |
---|
| 365 | } |
---|
| 366 | |
---|
| 367 | switch (*cp) { |
---|
| 368 | case ' ': |
---|
| 369 | case '\t': |
---|
| 370 | putc (*cp, out); |
---|
| 371 | n++; |
---|
| 372 | break; |
---|
| 373 | |
---|
| 374 | default: |
---|
| 375 | if (*cp < '!' || *cp > '~' |
---|
| 376 | || (ebcdicsw && !ebcdicsafe[*cp & 0xff])) |
---|
| 377 | goto three_print; |
---|
| 378 | putc (*cp, out); |
---|
| 379 | n++; |
---|
| 380 | break; |
---|
| 381 | |
---|
| 382 | case '=': |
---|
| 383 | three_print: |
---|
| 384 | fprintf (out, "=%02X", *cp & 0xff); |
---|
| 385 | n += 3; |
---|
| 386 | break; |
---|
| 387 | } |
---|
| 388 | } |
---|
| 389 | |
---|
| 390 | if (c == '\n') { |
---|
| 391 | if (cp > buffer && (*--cp == ' ' || *cp == '\t')) |
---|
| 392 | fputs ("=\n", out); |
---|
| 393 | |
---|
| 394 | putc ('\n', out); |
---|
| 395 | } else { |
---|
| 396 | fputs ("=\n", out); |
---|
| 397 | } |
---|
| 398 | } |
---|
| 399 | |
---|
| 400 | (*ct->c_ceclosefnx) (ct); |
---|
| 401 | return OK; |
---|
| 402 | } |
---|
| 403 | |
---|
| 404 | |
---|
| 405 | /* |
---|
| 406 | * Output a content using base64 |
---|
| 407 | */ |
---|
| 408 | |
---|
| 409 | static int |
---|
| 410 | writeBase64 (CT ct, FILE *out) |
---|
| 411 | { |
---|
| 412 | int fd, result; |
---|
| 413 | char *file; |
---|
| 414 | CE ce = ct->c_cefile; |
---|
| 415 | |
---|
| 416 | file = NULL; |
---|
| 417 | if ((fd = (*ct->c_ceopenfnx) (ct, &file)) == NOTOK) |
---|
| 418 | return NOTOK; |
---|
| 419 | |
---|
| 420 | result = writeBase64aux (ce->ce_fp, out); |
---|
| 421 | (*ct->c_ceclosefnx) (ct); |
---|
| 422 | return result; |
---|
| 423 | } |
---|
| 424 | |
---|
| 425 | |
---|
| 426 | int |
---|
| 427 | writeBase64aux (FILE *in, FILE *out) |
---|
| 428 | { |
---|
| 429 | int cc, n; |
---|
| 430 | char inbuf[3]; |
---|
| 431 | |
---|
| 432 | n = BPERLIN; |
---|
| 433 | while ((cc = fread (inbuf, sizeof(*inbuf), sizeof(inbuf), in)) > 0) { |
---|
| 434 | unsigned long bits; |
---|
| 435 | char *bp; |
---|
| 436 | char outbuf[4]; |
---|
| 437 | |
---|
| 438 | if (cc < sizeof(inbuf)) { |
---|
| 439 | inbuf[2] = 0; |
---|
| 440 | if (cc < sizeof(inbuf) - 1) |
---|
| 441 | inbuf[1] = 0; |
---|
| 442 | } |
---|
| 443 | bits = (inbuf[0] & 0xff) << 16; |
---|
| 444 | bits |= (inbuf[1] & 0xff) << 8; |
---|
| 445 | bits |= inbuf[2] & 0xff; |
---|
| 446 | |
---|
| 447 | for (bp = outbuf + sizeof(outbuf); bp > outbuf; bits >>= 6) |
---|
| 448 | *--bp = nib2b64[bits & 0x3f]; |
---|
| 449 | if (cc < sizeof(inbuf)) { |
---|
| 450 | outbuf[3] = '='; |
---|
| 451 | if (cc < sizeof inbuf - 1) |
---|
| 452 | outbuf[2] = '='; |
---|
| 453 | } |
---|
| 454 | |
---|
| 455 | fwrite (outbuf, sizeof(*outbuf), sizeof(outbuf), out); |
---|
| 456 | |
---|
| 457 | if (cc < sizeof(inbuf)) { |
---|
| 458 | putc ('\n', out); |
---|
| 459 | return OK; |
---|
| 460 | } |
---|
| 461 | |
---|
| 462 | if (--n <= 0) { |
---|
| 463 | n = BPERLIN; |
---|
| 464 | putc ('\n', out); |
---|
| 465 | } |
---|
| 466 | } |
---|
| 467 | if (n != BPERLIN) |
---|
| 468 | putc ('\n', out); |
---|
| 469 | |
---|
| 470 | return OK; |
---|
| 471 | } |
---|