]>
diplodocus.org Git - nmh/blob - uip/mhshowsbr.c
d87cd932dbc5e905b212eda7313684b57c61ce23
3 * mhshowsbr.c -- routines to display the contents of MIME messages
5 * This code is Copyright (c) 2002, by the authors of nmh. See the
6 * COPYRIGHT file in the root directory of the nmh distribution for
7 * complete copyright information.
12 #include <h/signals.h>
18 #include <h/mhparse.h>
22 #endif /* ! HAVE_ICONV */
32 /* flags for moreproc/header display */
38 static sigjmp_buf intrenv
;
42 int part_ok (CT
, int);
43 int type_ok (CT
, int);
44 void content_error (char *, CT
, char *, ...);
45 void flush_errors (void);
48 int list_switch (CT
, int, int, int, int);
49 int list_content (CT
, int, int, int, int);
54 void show_all_messages (CT
*);
55 int show_content_aux (CT
, int, int, char *, char *);
60 static void show_single_message (CT
, char *);
61 static void DisplayMsgHeader (CT
, char *);
62 static int show_switch (CT
, int, int);
63 static int show_content (CT
, int, int);
64 static int show_content_aux2 (CT
, int, int, char *, char *, int, int, int, int,
66 static int show_text (CT
, int, int);
67 static int show_multi (CT
, int, int);
68 static int show_multi_internal (CT
, int, int);
69 static int show_multi_aux (CT
, int, int, char *);
70 static int show_message_rfc822 (CT
, int, int);
71 static int show_partial (CT
, int, int);
72 static int show_external (CT
, int, int);
73 static int parse_display_string (CT
, char *, int *, int *, int *, int *, char *,
74 char *, size_t, int multipart
);
75 static int convert_content_charset (CT
, char **);
76 static int parameter_value (CI
, const char *, const char *, const char **);
77 static void intrser (int);
81 * Top level entry point to show/display a group of messages
85 show_all_messages (CT
*cts
)
90 * If form is not specified, then get default form
91 * for showing headers of MIME messages.
94 formsw
= getcpy (etcpath ("mhl.headers"));
97 * If form is "mhl.null", suppress display of header.
99 if (!strcmp (formsw
, "mhl.null"))
102 for (ctp
= cts
; *ctp
; ctp
++) {
105 /* if top-level type is ok, then display message */
107 show_single_message (ct
, formsw
);
113 * Entry point to show/display a single message
117 show_single_message (CT ct
, char *form
)
123 /* Allow user executable bit so that temporary directories created by
124 * the viewer (e.g., lynx) are going to be accessible */
125 umask (ct
->c_umask
& ~(0100));
128 * If you have a format file, then display
129 * the message headers.
132 DisplayMsgHeader(ct
, form
);
136 /* Show the body of the message */
137 show_switch (ct
, 1, 0);
143 if (ct
->c_ceclosefnx
)
144 (*ct
->c_ceclosefnx
) (ct
);
146 /* block a few signals */
148 sigaddset (&set
, SIGHUP
);
149 sigaddset (&set
, SIGINT
);
150 sigaddset (&set
, SIGQUIT
);
151 sigaddset (&set
, SIGTERM
);
152 sigprocmask (SIG_BLOCK
, &set
, &oset
);
154 while (wait (&status
) != NOTOK
) {
159 /* reset the signal mask */
160 sigprocmask (SIG_SETMASK
, &oset
, &set
);
168 * Use the mhlproc to show the header fields
172 DisplayMsgHeader (CT ct
, char *form
)
179 vec
= argsplit(mhlproc
, &file
, &vecp
);
180 vec
[vecp
++] = getcpy("-form");
181 vec
[vecp
++] = getcpy(form
);
182 vec
[vecp
++] = getcpy("-nobody");
183 vec
[vecp
++] = getcpy(ct
->c_file
);
186 * If we've specified -(no)moreproc,
187 * then just pass that along.
190 vec
[vecp
++] = getcpy("-nomoreproc");
192 vec
[vecp
++] = getcpy("-moreproc");
193 vec
[vecp
++] = getcpy(progsw
);
199 for (i
= 0; (child_id
= fork()) == NOTOK
&& i
< 5; i
++)
204 adios ("fork", "unable to");
209 fprintf (stderr
, "unable to exec ");
219 arglist_free(file
, vec
);
224 * Switching routine. Call the correct routine
225 * based on content type.
229 show_switch (CT ct
, int serial
, int alternate
)
231 switch (ct
->c_type
) {
233 return show_multi (ct
, serial
, alternate
);
236 switch (ct
->c_subtype
) {
237 case MESSAGE_PARTIAL
:
238 return show_partial (ct
, serial
, alternate
);
240 case MESSAGE_EXTERNAL
:
241 return show_external (ct
, serial
, alternate
);
245 return show_message_rfc822 (ct
, serial
, alternate
);
249 return show_text (ct
, serial
, alternate
);
255 return show_content (ct
, serial
, alternate
);
258 adios (NULL
, "unknown content type %d", ct
->c_type
);
261 return 0; /* NOT REACHED */
266 * Generic method for displaying content
270 show_content (CT ct
, int serial
, int alternate
)
272 char *cp
, buffer
[BUFSIZ
];
273 CI ci
= &ct
->c_ctinfo
;
275 /* Check for invo_name-show-type/subtype */
276 snprintf (buffer
, sizeof(buffer
), "%s-show-%s/%s",
277 invo_name
, ci
->ci_type
, ci
->ci_subtype
);
278 if ((cp
= context_find (buffer
)) && *cp
!= '\0')
279 return show_content_aux (ct
, serial
, alternate
, cp
, NULL
);
281 /* Check for invo_name-show-type */
282 snprintf (buffer
, sizeof(buffer
), "%s-show-%s", invo_name
, ci
->ci_type
);
283 if ((cp
= context_find (buffer
)) && *cp
!= '\0')
284 return show_content_aux (ct
, serial
, alternate
, cp
, NULL
);
286 if ((cp
= ct
->c_showproc
))
287 return show_content_aux (ct
, serial
, alternate
, cp
, NULL
);
289 /* complain if we are not a part of a multipart/alternative */
291 content_error (NULL
, ct
, "don't know how to display content");
298 * Parse the display string for displaying generic content
302 show_content_aux (CT ct
, int serial
, int alternate
, char *cp
, char *cracked
)
305 int xstdin
= 0, xlist
= 0, xpause
= 0, xtty
= 0;
306 char *file
, buffer
[BUFSIZ
];
308 if (!ct
->c_ceopenfnx
) {
310 content_error (NULL
, ct
, "don't know how to decode content");
316 if ((fd
= (*ct
->c_ceopenfnx
) (ct
, &file
)) == NOTOK
)
318 if (ct
->c_showproc
&& !strcmp (ct
->c_showproc
, "true"))
319 return (alternate
? DONE
: OK
);
321 if (! strcmp(invo_name
, "mhshow") &&
322 ct
->c_type
== CT_TEXT
&& ct
->c_subtype
== TEXT_PLAIN
) {
323 /* This has to be done after calling c_ceopenfnx, so
324 unfortunately the type checks are necessary without
325 some code rearrangement. And to make this really ugly,
326 only do it in mhshow, not mhfixmsg, mhn, or mhstore. */
327 if (convert_content_charset (ct
, &file
) != OK
) {
328 admonish (NULL
, "unable to convert character set%s to %s",
329 ct
->c_partno
? "of part " : "",
330 ct
->c_partno
? ct
->c_partno
: "",
331 content_charset (ct
));
336 strncpy (buffer
, cp
, sizeof(buffer
));
340 if (parse_display_string (ct
, cp
, &xstdin
, &xlist
, &xpause
, &xtty
, file
,
341 buffer
, sizeof(buffer
) - 1, 0)) {
342 admonish (NULL
, "Buffer overflow constructing show command!\n");
347 return show_content_aux2 (ct
, serial
, alternate
, cracked
, buffer
,
348 fd
, xlist
, xpause
, xstdin
, xtty
);
353 * Routine to actually display the content
357 show_content_aux2 (CT ct
, int serial
, int alternate
, char *cracked
, char *buffer
,
358 int fd
, int xlist
, int xpause
, int xstdin
, int xtty
)
364 if (debugsw
|| cracked
) {
367 fprintf (stderr
, "%s msg %s", cracked
? "storing" : "show",
370 fprintf (stderr
, " part %s", ct
->c_partno
);
372 fprintf (stderr
, " using command (cd %s; %s)\n", cracked
, buffer
);
374 fprintf (stderr
, " using command %s\n", buffer
);
377 if (xpid
< 0 || (xtty
&& xpid
)) {
380 pidcheck(pidwait (xpid
, NOTOK
));
387 if (ct
->c_type
== CT_MULTIPART
)
388 list_content (ct
, -1, 1, 0, 0);
390 list_switch (ct
, -1, 1, 0, 0);
392 if (xpause
&& isatty (fileno (stdout
))) {
394 SIGNAL_HANDLER istat
;
396 if (SOprintf ("Press <return> to show content..."))
397 printf ("Press <return> to show content...");
399 istat
= SIGNAL (SIGINT
, intrser
);
400 if ((intr
= sigsetjmp (intrenv
, 1)) == OK
) {
403 read (fileno (stdout
), prompt
, sizeof(prompt
));
405 SIGNAL (SIGINT
, istat
);
406 if (intr
!= OK
|| prompt
[0] == 'n') {
407 (*ct
->c_ceclosefnx
) (ct
);
408 return (alternate
? DONE
: NOTOK
);
410 if (prompt
[0] == 'q') done(OK
);
421 for (i
= 0; (child_id
= fork()) == NOTOK
&& i
< 5; i
++)
425 advise ("fork", "unable to");
426 (*ct
->c_ceclosefnx
) (ct
);
435 execvp ("/bin/sh", vec
);
436 fprintf (stderr
, "unable to exec ");
443 ct
->c_pid
= child_id
;
447 pidcheck (pidXwait (child_id
, NULL
));
451 (*ct
->c_ceclosefnx
) (ct
);
452 return (alternate
? DONE
: OK
);
458 * show content of type "text"
462 show_text (CT ct
, int serial
, int alternate
)
464 char *cp
, buffer
[BUFSIZ
];
465 CI ci
= &ct
->c_ctinfo
;
467 /* Check for invo_name-show-type/subtype */
468 snprintf (buffer
, sizeof(buffer
), "%s-show-%s/%s",
469 invo_name
, ci
->ci_type
, ci
->ci_subtype
);
470 if ((cp
= context_find (buffer
)) && *cp
!= '\0')
471 return show_content_aux (ct
, serial
, alternate
, cp
, NULL
);
473 /* Check for invo_name-show-type */
474 snprintf (buffer
, sizeof(buffer
), "%s-show-%s", invo_name
, ci
->ci_type
);
475 if ((cp
= context_find (buffer
)) && *cp
!= '\0')
476 return show_content_aux (ct
, serial
, alternate
, cp
, NULL
);
479 * Use default method if content is text/plain, or if
480 * if it is not a text part of a multipart/alternative
482 if (!alternate
|| ct
->c_subtype
== TEXT_PLAIN
) {
483 snprintf (buffer
, sizeof(buffer
), "%%p%s '%%F'", progsw
? progsw
:
484 moreproc
&& *moreproc
? moreproc
: DEFAULT_PAGER
);
485 cp
= (ct
->c_showproc
= add (buffer
, NULL
));
486 return show_content_aux (ct
, serial
, alternate
, cp
, NULL
);
494 * show message body of type "multipart"
498 show_multi (CT ct
, int serial
, int alternate
)
500 char *cp
, buffer
[BUFSIZ
];
501 CI ci
= &ct
->c_ctinfo
;
503 /* Check for invo_name-show-type/subtype */
504 snprintf (buffer
, sizeof(buffer
), "%s-show-%s/%s",
505 invo_name
, ci
->ci_type
, ci
->ci_subtype
);
506 if ((cp
= context_find (buffer
)) && *cp
!= '\0')
507 return show_multi_aux (ct
, serial
, alternate
, cp
);
509 /* Check for invo_name-show-type */
510 snprintf (buffer
, sizeof(buffer
), "%s-show-%s", invo_name
, ci
->ci_type
);
511 if ((cp
= context_find (buffer
)) && *cp
!= '\0')
512 return show_multi_aux (ct
, serial
, alternate
, cp
);
514 if ((cp
= ct
->c_showproc
))
515 return show_multi_aux (ct
, serial
, alternate
, cp
);
518 * Use default method to display this multipart content. Even
519 * unknown types are displayable, since they're treated as mixed
522 return show_multi_internal (ct
, serial
, alternate
);
527 * show message body of subtypes of multipart that
528 * we understand directly (mixed, alternate, etc...)
532 show_multi_internal (CT ct
, int serial
, int alternate
)
534 int alternating
, nowalternate
, nowserial
, result
;
535 struct multipart
*m
= (struct multipart
*) ct
->c_ctparams
;
541 nowalternate
= alternate
;
543 if (ct
->c_subtype
== MULTI_PARALLEL
) {
544 nowserial
= serialsw
;
545 } else if (ct
->c_subtype
== MULTI_ALTERNATE
) {
553 * unknown subtypes of multipart (treat as mixed per rfc2046)
558 /* block a few signals */
561 sigaddset (&set
, SIGHUP
);
562 sigaddset (&set
, SIGINT
);
563 sigaddset (&set
, SIGQUIT
);
564 sigaddset (&set
, SIGTERM
);
565 sigprocmask (SIG_BLOCK
, &set
, &oset
);
569 * alternate -> we are a part inside an multipart/alternative
570 * alternating -> we are a multipart/alternative
573 result
= alternate
? NOTOK
: OK
;
575 for (part
= m
->mp_parts
; part
; part
= part
->mp_next
) {
578 if (part_ok (p
, 1) && type_ok (p
, 1)) {
581 inneresult
= show_switch (p
, nowserial
, nowalternate
);
582 switch (inneresult
) {
584 if (alternate
&& !alternating
) {
597 alternate
= nowalternate
= 0;
607 if (alternating
&& !part
) {
609 content_error (NULL
, ct
, "don't know how to display any of the contents");
614 if (serial
&& !nowserial
) {
620 for (part
= m
->mp_parts
; part
; part
= part
->mp_next
) {
624 if (kill (p
->c_pid
, 0) == NOTOK
)
631 while (kids
> 0 && (pid
= wait (&status
)) != NOTOK
) {
634 for (part
= m
->mp_parts
; part
; part
= part
->mp_next
) {
639 if (p
->c_pid
== pid
) {
650 /* reset the signal mask */
651 sigprocmask (SIG_SETMASK
, &oset
, &set
);
659 * Parse display string for multipart content
660 * and use external program to display it.
664 show_multi_aux (CT ct
, int serial
, int alternate
, char *cp
)
666 /* xstdin is only used in the call to parse_display_string():
667 its value is ignored in the function. */
668 int xstdin
= 0, xlist
= 0, xpause
= 0, xtty
= 0;
669 char *file
, buffer
[BUFSIZ
];
670 struct multipart
*m
= (struct multipart
*) ct
->c_ctparams
;
674 for (part
= m
->mp_parts
; part
; part
= part
->mp_next
) {
677 if (!p
->c_ceopenfnx
) {
679 content_error (NULL
, p
, "don't know how to decode content");
683 if (p
->c_storage
== NULL
) {
685 if ((*p
->c_ceopenfnx
) (p
, &file
) == NOTOK
)
688 /* I'm not sure if this is necessary? */
689 p
->c_storage
= add (file
, NULL
);
691 if (p
->c_showproc
&& !strcmp (p
->c_showproc
, "true"))
692 return (alternate
? DONE
: OK
);
693 (*p
->c_ceclosefnx
) (p
);
697 if (parse_display_string (ct
, cp
, &xstdin
, &xlist
, &xpause
, &xtty
, file
,
698 buffer
, sizeof(buffer
) - 1, 1)) {
699 admonish (NULL
, "Buffer overflow constructing show command!\n");
703 return show_content_aux2 (ct
, serial
, alternate
, NULL
, buffer
,
704 NOTOK
, xlist
, xpause
, 0, xtty
);
709 * show content of type "message/rfc822"
713 show_message_rfc822 (CT ct
, int serial
, int alternate
)
715 char *cp
, buffer
[BUFSIZ
];
716 CI ci
= &ct
->c_ctinfo
;
718 /* Check for invo_name-show-type/subtype */
719 snprintf (buffer
, sizeof(buffer
), "%s-show-%s/%s",
720 invo_name
, ci
->ci_type
, ci
->ci_subtype
);
721 if ((cp
= context_find (buffer
)) && *cp
!= '\0')
722 return show_content_aux (ct
, serial
, alternate
, cp
, NULL
);
724 /* Check for invo_name-show-type */
725 snprintf (buffer
, sizeof(buffer
), "%s-show-%s", invo_name
, ci
->ci_type
);
726 if ((cp
= context_find (buffer
)) && *cp
!= '\0')
727 return show_content_aux (ct
, serial
, alternate
, cp
, NULL
);
729 if ((cp
= ct
->c_showproc
))
730 return show_content_aux (ct
, serial
, alternate
, cp
, NULL
);
732 /* default method for message/rfc822 */
733 if (ct
->c_subtype
== MESSAGE_RFC822
) {
734 cp
= (ct
->c_showproc
= add ("%pshow -file '%F'", NULL
));
735 return show_content_aux (ct
, serial
, alternate
, cp
, NULL
);
738 /* complain if we are not a part of a multipart/alternative */
740 content_error (NULL
, ct
, "don't know how to display content");
747 * Show content of type "message/partial".
751 show_partial (CT ct
, int serial
, int alternate
)
754 NMH_UNUSED (alternate
);
756 content_error (NULL
, ct
,
757 "in order to display this message, you must reassemble it");
763 * Show content of type "message/external".
765 * THE ERROR CHECKING IN THIS ONE IS NOT DONE YET.
769 show_external (CT ct
, int serial
, int alternate
)
771 struct exbody
*e
= (struct exbody
*) ct
->c_ctparams
;
772 CT p
= e
->eb_content
;
777 return show_switch (p
, serial
, alternate
);
782 parse_display_string (CT ct
, char *cp
, int *xstdin
, int *xlist
, int *xpause
,
783 int *xtty
, char *file
, char *buffer
, size_t buflen
,
786 char *bp
= buffer
, *pp
;
787 CI ci
= &ct
->c_ctinfo
;
789 bp
[0] = bp
[buflen
] = '\0';
791 for ( ; *cp
&& buflen
> 0; cp
++) {
797 /* insert parameters from Content-Type field */
802 for (ap
= ci
->ci_attrs
, ep
= ci
->ci_values
; *ap
; ap
++, ep
++) {
803 snprintf (bp
, buflen
, "%s%s=\"%s\"", s
, *ap
, *ep
);
813 /* insert content description */
817 s
= trimcpy (ct
->c_descr
);
818 strncpy (bp
, s
, buflen
);
824 /* exclusive execution */
829 /* %e, %f, and stdin is terminal not content */
836 /* insert filename(s) containing content */
837 struct multipart
*m
= (struct multipart
*) ct
->c_ctparams
;
842 for (part
= m
->mp_parts
; part
; part
= part
->mp_next
) {
845 snprintf (bp
, buflen
, "%s'%s'", s
, p
->c_storage
);
851 /* set our starting pointer back to bp, to avoid
852 * requoting the filenames we just added
856 /* insert filename containing content */
857 snprintf (bp
, buflen
, "'%s'", file
);
858 /* since we've quoted the file argument, set things up
859 * to look past it, to avoid problems with the quoting
860 * logic below. (I know, I should figure out what's
861 * broken with the quoting logic, but..)
871 /* %l, and pause prior to displaying content */
876 /* display listing prior to displaying content */
881 /* insert subtype of content */
882 strncpy (bp
, ci
->ci_subtype
, buflen
);
886 /* insert character % */
890 static const char param
[] = "charset";
892 const int found
= parameter_value (ci
, param
, cp
, &value
);
895 /* Because it'll get incremented in the next iteration,
896 just increment by 1 for the '{'. */
897 cp
+= strlen(param
) + 1;
899 /* cp pointed to the param and it's set in the
900 Content-Type header. */
901 strncpy (bp
, value
, buflen
);
903 /* since we've quoted the file argument, set things up
904 * to look past it, to avoid problems with the quoting
905 * logic below. (I know, I should figure out what's
906 * broken with the quoting logic, but..)
914 } else if (found
== 1) {
915 /* cp points to the param and it's not set in the
916 Content-Type header, so skip it. */
917 cp
+= strlen(param
) + 1;
922 if (*(cp
+ 1) == '\0') {
926 /* Increment cp again so that the last
927 character of the %{} token isn't output
928 after falling thru below. */
933 /* cp points to an unrecognized parameter. Output
934 it as-is, starting here with the "%{". */
942 /* No parameter was found, so fall thru to default to
943 output the rest of the text as-is. */
956 /* Did we actually insert something? */
958 /* Insert single quote if not inside quotes already */
959 if (!quoted
&& buflen
) {
961 memmove (pp
+ 1, pp
, len
);
966 /* Escape existing quotes */
967 while ((pp
= strchr (pp
, '\'')) && buflen
> 3) {
969 memmove (pp
+ 3, pp
, len
);
976 /* If pp is still set, that means we ran out of space. */
979 if (!quoted
&& buflen
) {
997 (ct
->c_termproc
&& buflen
<= strlen(ct
->c_termproc
))) {
998 /* content_error would provide a more useful error message
999 * here, except that if we got overrun, it probably would
1005 /* use charset string to modify display method */
1006 if (ct
->c_termproc
) {
1009 strncpy (term
, buffer
, sizeof(term
));
1010 snprintf (buffer
, buflen
, ct
->c_termproc
, term
);
1018 convert_charset (CT ct
, char *dest_charset
, int *message_mods
) {
1019 char *src_charset
= content_charset (ct
);
1022 /* norm_charmap() is case sensitive. */
1023 char *src_charset_u
= upcase (src_charset
);
1024 char *dest_charset_u
= upcase (dest_charset
);
1025 int different_charsets
=
1026 strcmp (norm_charmap (src_charset
), norm_charmap (dest_charset
));
1028 free (dest_charset_u
);
1029 free (src_charset_u
);
1031 if (different_charsets
) {
1033 iconv_t conv_desc
= NULL
;
1040 int opened_input_file
= 0;
1041 char src_buffer
[BUFSIZ
];
1045 if ((conv_desc
= iconv_open (dest_charset
, src_charset
)) ==
1047 advise (NULL
, "Can't convert %s to %s", src_charset
, dest_charset
);
1051 if ((tempfile
= m_mktemp2 (NULL
, invo_name
, &fd
, NULL
)) == NULL
) {
1052 adios (NULL
, "unable to create temporary file in %s",
1055 dest
= add (tempfile
, NULL
);
1057 if (ct
->c_cefile
.ce_file
) {
1058 file
= &ct
->c_cefile
.ce_file
;
1059 fp
= &ct
->c_cefile
.ce_fp
;
1061 } else if (ct
->c_file
) {
1064 begin
= (size_t) ct
->c_begin
;
1065 end
= (size_t) ct
->c_end
;
1066 } /* else no input file: shouldn't happen */
1068 if (file
&& *file
&& fp
) {
1070 if ((*fp
= fopen (*file
, "r")) == NULL
) {
1071 advise (*file
, "unable to open for reading");
1074 opened_input_file
= 1;
1081 size_t bytes_to_read
=
1082 end
> 0 && end
> begin
? end
- begin
: sizeof src_buffer
;
1084 fseeko (*fp
, begin
, SEEK_SET
);
1085 while ((inbytes
= fread (src_buffer
, 1,
1086 min (bytes_to_read
, sizeof src_buffer
),
1088 char dest_buffer
[BUFSIZ
];
1089 ICONV_CONST
char *ib
= src_buffer
;
1090 char *ob
= dest_buffer
;
1091 size_t outbytes
= sizeof dest_buffer
;
1092 size_t outbytes_before
= outbytes
;
1094 if (end
> 0) bytes_to_read
-= inbytes
;
1096 if (iconv (conv_desc
, &ib
, &inbytes
, &ob
, &outbytes
) ==
1101 write (fd
, dest_buffer
, outbytes_before
- outbytes
);
1105 if (opened_input_file
) {
1111 iconv_close (conv_desc
);
1115 /* Replace the decoded file with the converted one. */
1116 if (ct
->c_cefile
.ce_file
) {
1117 if (ct
->c_cefile
.ce_unlink
) {
1118 (void) m_unlink (ct
->c_cefile
.ce_file
);
1120 free (ct
->c_cefile
.ce_file
);
1122 ct
->c_cefile
.ce_file
= dest
;
1123 ct
->c_cefile
.ce_unlink
= 1;
1127 /* Update ci_attrs. */
1128 src_charset
= dest_charset
;
1130 /* Update ct->c_ctline. */
1133 update_attr (ct
->c_ctline
, "charset=", dest_charset
);
1135 free (ct
->c_ctline
);
1136 ct
->c_ctline
= ctline
;
1137 } /* else no CT line, which is odd */
1139 /* Update Content-Type header field. */
1140 for (hf
= ct
->c_first_hf
; hf
; hf
= hf
->next
) {
1141 if (! strcasecmp (TYPE_FIELD
, hf
->name
)) {
1142 char *ctline_less_newline
=
1143 update_attr (hf
->value
, "charset=", dest_charset
);
1144 char *ctline
= concat (ctline_less_newline
, "\n", NULL
);
1145 free (ctline_less_newline
);
1153 (void) m_unlink (dest
);
1155 #else /* ! HAVE_ICONV */
1156 NMH_UNUSED (message_mods
);
1158 advise (NULL
, "Can't convert %s to %s without iconv", src_charset
,
1161 #endif /* ! HAVE_ICONV */
1169 convert_content_charset (CT ct
, char **file
) {
1171 /* Using current locale, see if the content needs to be converted. */
1173 /* content_charset() cannot return NULL. */
1174 char *charset
= content_charset (ct
);
1176 if (! check_charset (charset
, strlen (charset
))) {
1179 if (convert_charset (ct
, get_charset (), &unused
) == 0) {
1180 *file
= ct
->c_cefile
.ce_file
;
1185 #else /* ! HAVE_ICONV */
1188 #endif /* ! HAVE_ICONV */
1196 * NOTOK if cp doesn't point to {param}
1197 * OK if cp points to {param} and that attribute exists, and returns
1199 * 1 if cp points to {param} and that attribute doesn't exist
1202 parameter_value (CI ci
, const char *param
, const char *cp
, const char **value
) {
1204 char *braced_param
= concat ("{", param
, "}", NULL
);
1206 if (! strncasecmp(cp
, braced_param
, strlen (braced_param
))) {
1211 for (ap
= ci
->ci_attrs
, ep
= ci
->ci_values
; *ap
; ++ap
, ++ep
) {
1212 if (!strcasecmp (*ap
, param
)) {
1220 free (braced_param
);
1231 siglongjmp (intrenv
, DONE
);