X-Git-Url: https://diplodocus.org/git/nmh/blobdiff_plain/4e6bc7b6d19bd083ee0446a3a7f2968a1b9dba20..17378602e0eed3c39e5f5ba9f3b28274b3dd26b2:/sbr/encode_rfc2047.c diff --git a/sbr/encode_rfc2047.c b/sbr/encode_rfc2047.c index 66c736e8..04a74f1a 100644 --- a/sbr/encode_rfc2047.c +++ b/sbr/encode_rfc2047.c @@ -8,6 +8,7 @@ #include #include +#include #include /* @@ -50,8 +51,10 @@ static char *address_headers[] = { static void unfold_header(char **, int); static int field_encode_address(const char *, char **, int, const char *); -static int field_encode_quoted(const char *, char **, const char *, int, int); +static int field_encode_quoted(const char *, char **, const char *, int, + int, int); static int field_encode_base64(const char *, char **, const char *); +static int scanstring(const char *, int *, int *, int *); static int utf8len(const char *); /* @@ -139,7 +142,7 @@ encode_rfc2047(const char *name, char **value, int encoding, case CE_QUOTED: return field_encode_quoted(name, value, charset, asciicount, - eightbitcount + qpspecialcount); + eightbitcount + qpspecialcount, 0); default: advise(NULL, "Internal error: unknown RFC-2047 encoding type"); @@ -153,7 +156,7 @@ encode_rfc2047(const char *name, char **value, int encoding, static int field_encode_quoted(const char *name, char **value, const char *charset, - int ascii, int encoded) + int ascii, int encoded, int phraserules) { int prefixlen = name ? strlen(name) + 2: 0, outlen = 0, column, newline = 1; int charsetlen = strlen(charset), utf8; @@ -225,6 +228,9 @@ field_encode_quoted(const char *name, char **value, const char *charset, /* * Process each character, encoding if necessary + * + * Note that we have a different set of rules if we're processing + * RFC 5322 'phrase' (something you'd see in an address header). */ column++; @@ -232,7 +238,9 @@ field_encode_quoted(const char *name, char **value, const char *charset, if (*p == ' ') { *q++ = '_'; ascii--; - } else if (isascii((int) *p) && !qpspecial((int) *p)) { + } else if (isascii((unsigned char) *p) && + (phraserules ? qphrasevalid((unsigned char) *p) : + !qpspecial((unsigned char) *p))) { *q++ = *p; ascii--; } else { @@ -531,4 +539,59 @@ static int field_encode_address(const char *name, char **value, int encoding, const char *charset) { + int prefixlen = strlen(name) + 2, column = prefixlen, groupflag, errflag; + int eightbitchars; + char *mp, *output = NULL; + struct mailname *mn; + + /* + * Because these are addresses, we need to handle them individually. + * + * Break them down and process them one by one. This means we have to + * rewrite the whole header, but that's unavoidable. + */ + + /* + * The output headers always have to start with a space first. + */ + + output = add(" ", output); + + for (groupflag = 0; mp = getname(*value); ) { + if ((mn = getm(mp, NULL, 0, AD_HOST, NULL)) == NULL) { + errflag++; + continue; + } + + /* + * We only care if the phrase (m_pers) or any trailing comment + * (m_note) have 8-bit characters. If doing q-p, we also need + * to encode anything marked as qspecial(). + */ + } +} + +/* + * Scan a string, check for characters that need to be encoded + */ + +static int +scanstring(const char *string, int *asciilen, int *eightbitchars, + int *specialchars) +{ + *asciilen = 0; + *eightbitchars = 0; + *specialchars = 0; + + for (; *string != '\0'; string++) { + if ((isascii((unsigned char) *string))) { + (*asciilen++); + if (!qphrasevalid((unsigned char) *string)) + (*specialchars)++; + } else { + (*eightbitchars)++; + } + } + + return eightbitchars > 0; }