work on retrieving parameters and converting them to the correct charset.
uip_burst_SOURCES = uip/burst.c uip/mhparse.c uip/mhmisc.c uip/mhfree.c \
uip/mhcachesbr.c uip/md5.c
-uip_burst_LDADD = $(LDADD) $(POSTLINK)
+uip_burst_LDADD = $(LDADD) $(ICONVLIB) $(POSTLINK)
uip_comp_SOURCES = uip/comp.c uip/whatnowproc.c uip/whatnowsbr.c uip/sendsbr.c \
uip/annosbr.c uip/distsbr.c
uip_mhbuild_SOURCES = uip/mhbuild.c uip/mhbuildsbr.c uip/mhcachesbr.c \
uip/mhlistsbr.c uip/mhoutsbr.c uip/mhmisc.c \
uip/mhfree.c uip/mhparse.c uip/md5.c
-uip_mhbuild_LDADD = $(LDADD) $(TERMLIB) $(POSTLINK)
+uip_mhbuild_LDADD = $(LDADD) $(TERMLIB) $(ICONVLIB) $(POSTLINK)
uip_mhfixmsg_SOURCES = uip/mhfixmsg.c uip/mhparse.c uip/mhcachesbr.c \
uip/mhoutsbr.c uip/mhmisc.c uip/mhfree.c \
uip_mhlist_SOURCES = uip/mhlist.c uip/mhparse.c uip/mhcachesbr.c \
uip/mhlistsbr.c uip/mhmisc.c uip/mhfree.c uip/md5.c
-uip_mhlist_LDADD = $(LDADD) $(TERMLIB) $(POSTLINK)
+uip_mhlist_LDADD = $(LDADD) $(TERMLIB) $(ICONVLIB) $(POSTLINK)
uip_mhn_SOURCES = uip/mhn.c uip/mhparse.c uip/mhcachesbr.c uip/mhshowsbr.c \
uip/mhlistsbr.c uip/mhstoresbr.c uip/mhmisc.c uip/mhfree.c \
uip/md5.c
-uip_mhn_LDADD = $(LDADD) $(TERMLIB) $(POSTLINK)
+uip_mhn_LDADD = $(LDADD) $(TERMLIB) $(ICONVLIB) $(POSTLINK)
uip_mhparam_SOURCES = uip/mhparam.c
uip_mhparam_LDADD = $(LDADD) $(POSTLINK)
uip_mhshow_SOURCES = uip/mhshow.c uip/mhparse.c uip/mhcachesbr.c \
uip/mhshowsbr.c uip/mhlistsbr.c uip/mhmisc.c \
uip/mhfree.c uip/md5.c
-uip_mhshow_LDADD = $(LDADD) $(TERMLIB) $(POSTLINK)
+uip_mhshow_LDADD = $(LDADD) $(TERMLIB) $(ICONVLIB) $(POSTLINK)
uip_mhstore_SOURCES = uip/mhstore.c uip/mhparse.c uip/mhcachesbr.c \
uip/mhshowsbr.c uip/mhlistsbr.c uip/mhstoresbr.c \
uip/mhmisc.c uip/mhfree.c uip/md5.c
-uip_mhstore_LDADD = $(LDADD) $(TERMLIB) $(POSTLINK)
+uip_mhstore_LDADD = $(LDADD) $(TERMLIB) $(ICONVLIB) $(POSTLINK)
uip_msgchk_SOURCES = uip/msgchk.c uip/popsbr.c
uip_msgchk_LDADD = $(LDADD) $(SASLLIB) $(POSTLINK)
uip_mhtest_SOURCES = uip/mhtest.c uip/mhparse.c uip/mhcachesbr.c \
uip/mhoutsbr.c uip/mhmisc.c uip/mhfree.c \
uip/md5.c
-uip_mhtest_LDADD = $(LDADD) $(TERMLIB) $(POSTLINK)
+uip_mhtest_LDADD = $(LDADD) $(TERMLIB) $(ICONVLIB) $(POSTLINK)
uip_post_SOURCES = uip/post.c uip/aliasbr.c
uip_post_LDADD = mts/libmts.a $(LDADD) $(SASLLIB) $(TLSLIB) $(POSTLINK)
* params - Pointer to head of linked list of parameters.
* offsetout - The final line offset after all the parameters have been
* output. May be NULL.
- *
+ * external - If set, outputting an external-body type and will not
+ * output a "body" parameter.
+
* Returns a pointer to the resulting parameter string. This string must
* be free()'d by the caller. Returns NULL on error.
*/
-char *output_params(size_t initialwidth, PM params, int *offsetout);
+char *output_params(size_t initialwidth, PM params, int *offsetout,
+ int external);
/*
* Add a parameter to the parameter linked list.
*/
PM add_param(PM *first, PM *last, const char *name, const char *value);
+/*
+ * Retrieve a parameter value from a parameter linked list. Convert to the
+ * local character set if required.
+ *
+ * Arguments are:
+ *
+ * first - Pointer to head of parameter linked list.
+ * name - Name of parameter.
+ * replace - If characters in the parameter list cannot be converted to
+ * the local character set, replace with this character.
+ * fetchonly - If true, return pointer to original value, no conversion
+ * performed.
+ *
+ * Returns parameter value if found, NULL otherwise. Memory must be free()'d
+ * unless fetchonly is set.
+ */
+
+char *get_param(PM first, const char *name, char replace, int fetchonly);
+
extern int checksw; /* Add Content-MD5 field */
check "$draft" "$expected"
#
-# Try out both!
+# Try out attach with a filename with 8-bit characters
#
+cp "${srcdir}/test/mhbuild/tiny.jpg" "$MH_TEST_DIR/tïny.jpg"
+
cat > "$draft" <<EOF
To: Mr Test <mrtest@example.com>
cc:
Fcc: +outbox
+Attach: $MH_TEST_DIR/tïny.jpg
------
This is a test message
-#image/jpeg {attachment; filename="This is an ëxample of a rather long filename that is longer than would fit on a normal line.jpg"} \
-${srcdir}/test/mhbuild/tiny.jpg
EOF
run_prog mhbuild "$draft"
This is a test message
------- =_aaaaaaaaaa0
-Content-Type: image/jpeg
-Content-Disposition: attachment;
- filename*0*=UTF-8''This%20is%20an%20%C3%ABxample%20of%20a%20rather;
- filename*1=" long filename that is longer than would fit on a norma";
- filename*2="l line.jpg"
+Content-Type: image/jpeg; name*=UTF-8''t%C3%AFny.jpg
+Content-Description: =?UTF-8?B?dMOvbnkuanBn?=
+Content-Disposition: attachment; filename*=UTF-8''t%C3%AFny.jpg
Content-Transfer-Encoding: base64
/9g=
int cc, mailbody, extbody, len;
char *np, *vp, buffer[BUFSIZ];
CI ci = &ct->c_ctinfo;
- PM pm;
/*
* If message is type multipart, then add the multipart
* Append the attribute/value pairs to
* the end of the Content-Type line.
*/
- for (pm = ci->ci_first_pm; pm; pm = pm->pm_next) {
- if (mailbody && !strcasecmp (pm->pm_name, "body"))
- continue;
-
- vp = add (";", vp);
- len++;
-
- /*
- * According to RFC 2017, if we have a URL longer than 40 characters
- * we have to break it across multiple lines
- */
-
- if (extbody && strcasecmp (pm->pm_name, "url") == 0) {
- char *value = pm->pm_value;
-
- /* 7 here refers to " url=\"\"" */
- if (len + 1 + (cc = (min(MAXURLTOKEN, strlen(value)) + 7)) >=
- CPERLIN) {
- vp = add ("\n\t", vp);
- len = 8;
- } else {
- vp = add (" ", vp);
- len++;
- }
-
- vp = add ("url=\"", vp);
- len += 5;
- while (strlen(value) > MAXURLTOKEN) {
- strncpy(buffer, value, MAXURLTOKEN);
- buffer[MAXURLTOKEN] = '\0';
- vp = add (buffer, vp);
- vp = add ("\n\t", vp);
- value += MAXURLTOKEN;
- len = 8;
- }
+ if (ci->ci_first_pm) {
+ char *s = output_params(len, ci->ci_first_pm, &len, mailbody);
- vp = add (value, vp);
- vp = add ("\"", vp);
- len += strlen(value) + 1;
- continue;
- }
+ if (!s)
+ adios(NULL, "Internal error: failed outputting Content-Type "
+ "parameters");
- snprintf (buffer, sizeof(buffer), "%s=\"%s\"", pm->pm_name, pm->pm_value);
- if (len + 1 + (cc = strlen (buffer)) >= CPERLIN) {
- vp = add ("\n\t", vp);
- len = 8;
- } else {
- vp = add (" ", vp);
- len++;
- }
- vp = add (buffer, vp);
- len += cc;
+ vp = add (s, vp);
+ free(s);
}
/*
} else if (ct->c_dispo_type) {
vp = concat (" ", ct->c_dispo_type, NULL);
len = strlen(DISPO_FIELD) + strlen(vp) + 1;
- np = output_params(len, ct->c_dispo_first, NULL);
+ np = output_params(len, ct->c_dispo_first, NULL, 0);
vp = add(np, vp);
vp = add("\n", vp);
if (np)
#include <h/mime.h>
#include <h/mhparse.h>
#include <h/utils.h>
+#ifdef HAVE_ICONV
+# include <iconv.h>
+#endif /* HAVE_ICONV */
extern int debugsw;
fprintf (ce->ce_fp, "%s: %s/%s", TYPE_FIELD, ci->ci_type, ci->ci_subtype);
len += strlen (TYPE_FIELD) + 2 + strlen (ci->ci_type)
+ 1 + strlen (ci->ci_subtype);
- buffer = output_params(len, ci->ci_first_pm, &len);
+ buffer = output_params(len, ci->ci_first_pm, &len, 0);
if (buffer) {
fputs (buffer, ce->ce_fp);
*/
char *
-output_params(size_t initialwidth, PM params, int *offsetout)
+output_params(size_t initialwidth, PM params, int *offsetout, int external)
{
char *paramout = NULL;
char line[CPERLIN * 2], *q;
valoff = 0;
q = line;
+ if (external && strcasecmp(params->pm_name, "body") == 0)
+ continue;
+
if (strlen(params->pm_name) > CPERLIN) {
advise(NULL, "Parameter name \"%s\" is too long", params->pm_name);
if (paramout)
return pm;
}
+
+/*
+ * Retrieve a parameter value from a parameter linked list. If the parameter
+ * value needs converted to the local character set, do that now.
+ */
+
+char *
+get_param(PM first, const char *name, char replace, int fetchonly)
+{
+ while (first != NULL) {
+ if (strcasecmp(name, first->pm_name) == 0) {
+ if (fetchonly)
+ return first->pm_value;
+ else {
+ char convbuf[BUFSIZ];
+ size_t inbytes, outbytes = sizeof(convbuf);
+#ifdef HAVE_ICONV
+ int utf8;
+ iconv_t cd;
+ ICONV_CONST char *p;
+ char *q;
+#endif /* HAVE_ICONV */
+ if (!first->pm_charset ||
+ check_charset(first->pm_charset,
+ strlen(first->pm_charset))) {
+ /*
+ * No conversion necessary
+ */
+ return getcpy(first->pm_value);
+ }
+#ifdef HAVE_ICONV
+ utf8 = strcasecmp(first->pm_charset, "UTF-8") == 0;
+
+ cd = iconv_open(get_charset(), first->pm_charset);
+ if (cd == (iconv_t) -1) {
+ goto noconvert;
+ }
+
+ inbytes = strlen(first->pm_value);
+ outbytes = sizeof(convbuf);
+ p = first->pm_value;
+ q = convbuf;
+
+ while (inbytes) {
+ if (iconv(cd, &p, &inbytes, &q, &outbytes) == -1) {
+ if (errno != EILSEQ) {
+ iconv_close(cd);
+ goto noconvert;
+ }
+ /*
+ * Reset shift state, substitute our character,
+ * try to restart conversion.
+ */
+ iconv(cd, NULL, NULL, &q, &outbytes);
+ if (outbytes == 0) {
+ iconv_close(cd);
+ goto noconvert;
+ }
+ *q++ = replace;
+ outbytes--;
+ if (outbytes == 0) {
+ iconv_close(cd);
+ goto noconvert;
+ }
+ if (utf8) {
+ for (++p, --inbytes; inbytes > 0 &&
+ (((unsigned char) *q) & 0xc0) == 0x80;
+ ++p, --inbytes)
+ continue;
+ } else {
+ p++;
+ inbytes--;
+ }
+ }
+ }
+
+ iconv_close(cd);
+
+ if (outbytes == 0)
+ q--;
+ *q = '\0';
+
+ return getcpy(convbuf);
+#endif /* HAVE_ICONV */
+noconvert:
+ for (p = first->pm_value, q = convbuf; *p && outbytes > 1;
+ p++, q++, outbytes--) {
+ if (isascii((unsigned char) p) &&
+ isprint((unsigned char) p))
+ *q = *p;
+ else
+ *q = replace;
+ }
+
+ *q = '\0';
+
+ return getcpy(convbuf);
+ }
+ }
+
+ first = first->pm_next;
+ }
+
+ return NULL;
+}