]> diplodocus.org Git - nmh/blobdiff - sbr/encode_rfc2047.c
Fixed file descriptor leak in mhfixmsg when run on multiple input files.
[nmh] / sbr / encode_rfc2047.c
index d1ccd2e973c8bd5a6d889f18e62899e6a56ff443..bb45b5c10f396411bbca82ae9426cee1388f33f8 100644 (file)
@@ -1,15 +1,19 @@
-/*
- * Routines to encode message headers using RFC 2047-encoding.
+/* encode_rfc2047.c -- encode message headers using RFC 2047 encoding.
  *
  * This code is Copyright (c) 2002, by the authors of nmh.  See the
  * COPYRIGHT file in the root directory of the nmh distribution for
  * complete copyright information.
  */
 
  *
  * This code is Copyright (c) 2002, by the authors of nmh.  See the
  * COPYRIGHT file in the root directory of the nmh distribution for
  * complete copyright information.
  */
 
-#include <h/mh.h>
-#include <h/mhparse.h>
-#include <h/addrsbr.h>
-#include <h/utils.h>
+#include "h/mh.h"
+#include "encode_rfc2047.h"
+#include "check_charset.h"
+#include "error.h"
+#include "h/mhparse.h"
+#include "h/addrsbr.h"
+#include "h/utils.h"
+#include "base64.h"
+#include "unquote.h"
 
 /*
  * List of headers that contain addresses and as a result require special
 
 /*
  * List of headers that contain addresses and as a result require special
@@ -79,13 +83,13 @@ encode_rfc2047(const char *name, char **value, int encoding,
        if (isascii((unsigned char) *p)) {
            asciicount++;
            if (qpspecial((unsigned char) *p))
        if (isascii((unsigned char) *p)) {
            asciicount++;
            if (qpspecial((unsigned char) *p))
-               qpspecialcount++;
+               qpspecialcount++;
        } else
            eightbitcount++;
     }
 
     if (eightbitcount == 0)
        } else
            eightbitcount++;
     }
 
     if (eightbitcount == 0)
-       return 0;
+       return 0;
 
     /*
      * Some rules from RFC 2047:
 
     /*
      * Some rules from RFC 2047:
@@ -104,10 +108,10 @@ encode_rfc2047(const char *name, char **value, int encoding,
      */
 
     if (charset == NULL)
      */
 
     if (charset == NULL)
-       charset = write_charset_8bit();
+       charset = write_charset_8bit();
 
     if (strcasecmp(charset, "US-ASCII") == 0) {
 
     if (strcasecmp(charset, "US-ASCII") == 0) {
-       advise(NULL, "Cannot use US-ASCII with 8 bit characters in header");
+       inform("Cannot use US-ASCII with 8 bit characters in header");
        return 1;
     }
 
        return 1;
     }
 
@@ -117,7 +121,7 @@ encode_rfc2047(const char *name, char **value, int encoding,
      */
 
     for (i = 0; address_headers[i]; i++) {
      */
 
     for (i = 0; address_headers[i]; i++) {
-       if (strcasecmp(name, address_headers[i]) == 0)
+       if (strcasecmp(name, address_headers[i]) == 0)
            return field_encode_address(name, value, encoding, charset);
     }
 
            return field_encode_address(name, value, encoding, charset);
     }
 
@@ -139,14 +143,14 @@ encode_rfc2047(const char *name, char **value, int encoding,
     switch (encoding) {
 
     case CE_BASE64:
     switch (encoding) {
 
     case CE_BASE64:
-       return field_encode_base64(name, value, charset);
+       return field_encode_base64(name, value, charset);
 
     case CE_QUOTED:
        return field_encode_quoted(name, value, charset, asciicount,
                                   eightbitcount + qpspecialcount, 0);
 
     default:
 
     case CE_QUOTED:
        return field_encode_quoted(name, value, charset, asciicount,
                                   eightbitcount + qpspecialcount, 0);
 
     default:
-       advise(NULL, "Internal error: unknown RFC-2047 encoding type");
+       inform("Internal error: unknown RFC-2047 encoding type");
        return 1;
     }
 }
        return 1;
     }
 }
@@ -159,7 +163,7 @@ static int
 field_encode_quoted(const char *name, char **value, const char *charset,
                    int ascii, int encoded, int phraserules)
 {
 field_encode_quoted(const char *name, char **value, const char *charset,
                    int ascii, int encoded, int phraserules)
 {
-    int prefixlen = name ? strlen(name) + 2: 0, outlen = 0, column, newline = 1;
+    int prefixlen = name ? strlen(name) + 2: 0, outlen = 0, column;
     int charsetlen = strlen(charset), utf8;
     char *output = NULL, *p, *q = NULL;
 
     int charsetlen = strlen(charset), utf8;
     char *output = NULL, *p, *q = NULL;
 
@@ -174,11 +178,12 @@ field_encode_quoted(const char *name, char **value, const char *charset,
 
     utf8 = strcasecmp(charset, "UTF-8") == 0;
 
 
     utf8 = strcasecmp(charset, "UTF-8") == 0;
 
+    bool newline = true;
     while (*p != '\0') {
     while (*p != '\0') {
-       /*
+       /*
         * Start a new line, if it's time
         */
         * Start a new line, if it's time
         */
-       if (newline) {
+       if (newline) {
            /*
             * If it's the start of the header, we don't need to pad it
             *
            /*
             * If it's the start of the header, we don't need to pad it
             *
@@ -210,12 +215,12 @@ field_encode_quoted(const char *name, char **value, const char *charset,
                for (i = 0; i < prefixlen; i++)
                    *q++ = ' ';
            } else {
                for (i = 0; i < prefixlen; i++)
                    *q++ = ' ';
            } else {
-               /*
+               /*
                 * A bit of a hack here; the header can contain multiple
                 * spaces (probably at least one) until we get to the
                 * actual text.  Copy until we get to a non-space.
                 */
                 * A bit of a hack here; the header can contain multiple
                 * spaces (probably at least one) until we get to the
                 * actual text.  Copy until we get to a non-space.
                 */
-               output = mh_xmalloc(outlen);
+               output = mh_xmalloc(outlen);
                q = output;
                while (is_fws(*p))
                    *q++ = *p++;
                q = output;
                while (is_fws(*p))
                    *q++ = *p++;
@@ -224,7 +229,7 @@ field_encode_quoted(const char *name, char **value, const char *charset,
            tokenlen = snprintf(q, outlen - (q - output), "=?%s?Q?", charset);
            q += tokenlen;
            column = prefixlen + tokenlen;
            tokenlen = snprintf(q, outlen - (q - output), "=?%s?Q?", charset);
            q += tokenlen;
            column = prefixlen + tokenlen;
-           newline = 0;
+           newline = false;
        }
 
        /*
        }
 
        /*
@@ -241,7 +246,7 @@ field_encode_quoted(const char *name, char **value, const char *charset,
            ascii--;
        } else if (isascii((unsigned char) *p) &&
                   (phraserules ? qphrasevalid((unsigned char) *p) :
            ascii--;
        } else if (isascii((unsigned char) *p) &&
                   (phraserules ? qphrasevalid((unsigned char) *p) :
-                                       !qpspecial((unsigned char) *p))) {
+                                       !qpspecial((unsigned char) *p))) {
            *q++ = *p;
            ascii--;
        } else {
            *q++ = *p;
            ascii--;
        } else {
@@ -265,7 +270,7 @@ field_encode_quoted(const char *name, char **value, const char *charset,
            continue;
 
        if (column >= ENCODELINELIMIT - 2) {
            continue;
 
        if (column >= ENCODELINELIMIT - 2) {
-           newline = 1;
+           newline = true;
        } else if (utf8) {
            /*
             * Okay, this is a bit weird, but to explain a bit more ...
        } else if (utf8) {
            /*
             * Okay, this is a bit weird, but to explain a bit more ...
@@ -281,7 +286,7 @@ field_encode_quoted(const char *name, char **value, const char *charset,
             * allow for the encoded output.
             */
            if (column + (utf8len(p) * 3) > ENCODELINELIMIT - 2) {
             * allow for the encoded output.
             */
            if (column + (utf8len(p) * 3) > ENCODELINELIMIT - 2) {
-               newline = 1;
+               newline = true;
            }
        }
     }
            }
        }
     }
@@ -289,7 +294,7 @@ field_encode_quoted(const char *name, char **value, const char *charset,
     if (q == NULL) {
        /* This should never happen, but just in case.  Found by
           clang static analyzer. */
     if (q == NULL) {
        /* This should never happen, but just in case.  Found by
           clang static analyzer. */
-       admonish (NULL, "null output encoding for %s", *value);
+       inform("null output encoding for %s, continuing...", *value);
        return 1;
     }
     *q++ = '?';
        return 1;
     }
     *q++ = '?';
@@ -326,7 +331,7 @@ field_encode_base64(const char *name, char **value, const char *charset)
      */
 
     while (*p == ' ' || *p == '\t')
      */
 
     while (*p == ' ' || *p == '\t')
-       p++;
+       p++;
 
     /*
      * If we had a zero-length prefix, then just encode the whole field
 
     /*
      * If we had a zero-length prefix, then just encode the whole field
@@ -338,7 +343,7 @@ field_encode_base64(const char *name, char **value, const char *charset)
      */
 
     while (prefixlen && ((base64len(strlen(p)) + 7 + charsetlen +
      */
 
     while (prefixlen && ((base64len(strlen(p)) + 7 + charsetlen +
-                         prefixlen) > ENCODELINELIMIT)) {
+                         prefixlen) > ENCODELINELIMIT)) {
 
        /*
         * Our very first time, don't pad the line in the front
 
        /*
         * Our very first time, don't pad the line in the front
@@ -381,8 +386,8 @@ field_encode_base64(const char *name, char **value, const char *charset)
        numencode = strbase64(ENCODELINELIMIT - (q - linestart) - 2);
 
        if (numencode <= 0) {
        numencode = strbase64(ENCODELINELIMIT - (q - linestart) - 2);
 
        if (numencode <= 0) {
-           advise(NULL, "Internal error: tried to encode %d characters "
-                  "in base64", numencode);
+           inform("Internal error: tried to encode %d characters "
+                  "in base64", numencode);
            return 1;
        }
 
            return 1;
        }
 
@@ -402,10 +407,10 @@ field_encode_base64(const char *name, char **value, const char *charset)
             */
 
            while (numencode > 0 && ((*(p + numencode) & 0xc0) == 0x80))
             */
 
            while (numencode > 0 && ((*(p + numencode) & 0xc0) == 0x80))
-               numencode--;
+               numencode--;
 
            if (numencode == 0) {
 
            if (numencode == 0) {
-               advise(NULL, "Internal error: could not find start of "
+               inform("Internal error: could not find start of "
                       "UTF-8 character when base64 encoding header");
                return 1;
            }
                       "UTF-8 character when base64 encoding header");
                return 1;
            }
@@ -413,7 +418,7 @@ field_encode_base64(const char *name, char **value, const char *charset)
 
        if (writeBase64raw((unsigned char *) p, numencode,
                           (unsigned char *) q) != OK) {
 
        if (writeBase64raw((unsigned char *) p, numencode,
                           (unsigned char *) q) != OK) {
-           advise(NULL, "Internal error: base64 encoding of header failed");
+           inform("Internal error: base64 encoding of header failed");
            return 1;
        }
 
            return 1;
        }
 
@@ -456,18 +461,18 @@ field_encode_base64(const char *name, char **value, const char *charset)
     q = output + curlen;
 
     q += snprintf(q, outlen - (q - output), "%s=?%s?B?",
     q = output + curlen;
 
     q += snprintf(q, outlen - (q - output), "%s=?%s?B?",
-                 prefixlen ? " " : "", charset);
+                 prefixlen ? " " : "", charset);
 
     if (writeBase64raw((unsigned char *) p, strlen(p),
 
     if (writeBase64raw((unsigned char *) p, strlen(p),
-                      (unsigned char *) q) != OK) {
-       advise(NULL, "Internal error: base64 encoding of header failed");
+                      (unsigned char *) q) != OK) {
+       inform("Internal error: base64 encoding of header failed");
        return 1;
     }
 
     strcat(q, "?=");
 
     if (prefixlen)
        return 1;
     }
 
     strcat(q, "?=");
 
     if (prefixlen)
-       strcat(q, "\n");
+       strcat(q, "\n");
 
     free(*value);
 
 
     free(*value);
 
@@ -489,14 +494,14 @@ utf8len(const char *p)
     int len = 1;
 
     if (*p == '\0')
     int len = 1;
 
     if (*p == '\0')
-       return 0;
+       return 0;
 
     if (isascii((unsigned char) *p) || (((unsigned char) *p) & 0xc0) == 0x80)
 
     if (isascii((unsigned char) *p) || (((unsigned char) *p) & 0xc0) == 0x80)
-       return 0;
+       return 0;
 
     p++;
     while ((((unsigned char) *p++) & 0xc0) == 0x80)
 
     p++;
     while ((((unsigned char) *p++) & 0xc0) == 0x80)
-       len++;
+       len++;
 
     return len;
 }
 
     return len;
 }
@@ -515,7 +520,7 @@ unfold_header(char **value, int len)
     char *p = str, *q = *value;
 
     while (*q != '\0') {
     char *p = str, *q = *value;
 
     while (*q != '\0') {
-       if (*q == '\n') {
+       if (*q == '\n') {
            /*
             * When we get a newline, skip to the next non-whitespace
             * character and add a space to replace all of the whitespace
            /*
             * When we get a newline, skip to the next non-whitespace
             * character and add a space to replace all of the whitespace
@@ -524,9 +529,9 @@ unfold_header(char **value, int len)
             * for the header; we put it back in the encoding routine.
             */
            while (is_fws(*q))
             * for the header; we put it back in the encoding routine.
             */
            while (is_fws(*q))
-               q++;
+               q++;
            if (*q == '\0')
            if (*q == '\0')
-               break;
+               break;
 
            *p++ = ' ';
        } else {
 
            *p++ = ' ';
        } else {
@@ -550,7 +555,11 @@ field_encode_address(const char *name, char **value, int encoding,
                     const char *charset)
 {
     int prefixlen = strlen(name) + 2, column = prefixlen, groupflag;
                     const char *charset)
 {
     int prefixlen = strlen(name) + 2, column = prefixlen, groupflag;
-    int asciichars, specialchars, eightbitchars, reformat = 0, errflag = 0;
+    int asciichars;
+    int specialchars;
+    int eightbitchars;
+    bool reformat = false;
+    bool errflag = false;
     size_t len;
     char *mp, *cp = NULL, *output = NULL;
     char *tmpbuf = NULL;
     size_t len;
     char *mp, *cp = NULL, *output = NULL;
     char *tmpbuf = NULL;
@@ -573,13 +582,13 @@ field_encode_address(const char *name, char **value, int encoding,
     output = add(" ", output);
 
     for (groupflag = 0; (mp = getname(*value)); ) {
     output = add(" ", output);
 
     for (groupflag = 0; (mp = getname(*value)); ) {
-       if ((mn = getm(mp, NULL, 0, errbuf, sizeof(errbuf))) == NULL) {
-           advise(NULL, "%s: %s", errbuf, mp);
-           errflag++;
+       if ((mn = getm(mp, NULL, 0, errbuf, sizeof(errbuf))) == NULL) {
+           inform("%s: %s", errbuf, mp);
+           errflag = true;
            continue;
        }
 
            continue;
        }
 
-       reformat = 0;
+       reformat = false;
 
        /*
         * We only care if the phrase (m_pers) or any trailing comment
 
        /*
         * We only care if the phrase (m_pers) or any trailing comment
@@ -604,7 +613,7 @@ field_encode_address(const char *name, char **value, int encoding,
             */
 
            if (encoding == CE_UNKNOWN)
             */
 
            if (encoding == CE_UNKNOWN)
-               encoding = pref_encoding(asciichars, specialchars,
+               encoding = pref_encoding(asciichars, specialchars,
                                         eightbitchars);
 
            /*
                                         eightbitchars);
 
            /*
@@ -617,27 +626,27 @@ field_encode_address(const char *name, char **value, int encoding,
            switch (encoding) {
 
            case CE_BASE64:
            switch (encoding) {
 
            case CE_BASE64:
-               if (field_encode_base64(NULL, &mn->m_pers, charset)) {
-                   errflag++;
+               if (field_encode_base64(NULL, &mn->m_pers, charset)) {
+                   errflag = true;
                    goto out;
                }
                break;
 
            case CE_QUOTED:
                    goto out;
                }
                break;
 
            case CE_QUOTED:
-               if (field_encode_quoted(NULL, &mn->m_pers, charset, asciichars,
+               if (field_encode_quoted(NULL, &mn->m_pers, charset, asciichars,
                                        eightbitchars + specialchars, 1)) {
                                        eightbitchars + specialchars, 1)) {
-                   errflag++;
+                   errflag = true;
                    goto out;
                }
                break;
 
            default:
                    goto out;
                }
                break;
 
            default:
-               advise(NULL, "Internal error: unknown RFC-2047 encoding type");
-               errflag++;
+               inform("Internal error: unknown RFC-2047 encoding type");
+               errflag = true;
                goto out;
            }
 
                goto out;
            }
 
-           reformat++;
+           reformat = true;
        }
 
        check_note:
        }
 
        check_note:
@@ -658,9 +667,9 @@ field_encode_address(const char *name, char **value, int encoding,
        }
 
        if (mn->m_note[0] != '(' || mn->m_note[len - 1] != ')') {
        }
 
        if (mn->m_note[0] != '(' || mn->m_note[len - 1] != ')') {
-           advise(NULL, "Internal error: Invalid note field \"%s\"",
-                  mn->m_note);
-           errflag++;
+           inform("Internal error: Invalid note field \"%s\"",
+                  mn->m_note);
+           errflag = true;
            goto out;
        }
 
            goto out;
        }
 
@@ -674,33 +683,33 @@ field_encode_address(const char *name, char **value, int encoding,
             */
 
            if (encoding == CE_UNKNOWN)
             */
 
            if (encoding == CE_UNKNOWN)
-               encoding = pref_encoding(asciichars, specialchars,
+               encoding = pref_encoding(asciichars, specialchars,
                                         eightbitchars);
 
            switch (encoding) {
 
            case CE_BASE64:
                                         eightbitchars);
 
            switch (encoding) {
 
            case CE_BASE64:
-               if (field_encode_base64(NULL, &tmpbuf, charset)) {
-                   errflag++;
+               if (field_encode_base64(NULL, &tmpbuf, charset)) {
+                   errflag = true;
                    goto out;
                }
                break;
 
            case CE_QUOTED:
                    goto out;
                }
                break;
 
            case CE_QUOTED:
-               if (field_encode_quoted(NULL, &tmpbuf, charset, asciichars,
+               if (field_encode_quoted(NULL, &tmpbuf, charset, asciichars,
                                        eightbitchars + specialchars, 1)) {
                                        eightbitchars + specialchars, 1)) {
-                   errflag++;
+                   errflag = true;
                    goto out;
                }
                break;
 
            default:
                    goto out;
                }
                break;
 
            default:
-               advise(NULL, "Internal error: unknown RFC-2047 encoding type");
-               errflag++;
+               inform("Internal error: unknown RFC-2047 encoding type");
+               errflag = true;
                goto out;
            }
 
                goto out;
            }
 
-           reformat++;
+           reformat = true;
 
            /*
             * Make sure the size of tmpbuf is correct (it always gets
 
            /*
             * Make sure the size of tmpbuf is correct (it always gets
@@ -737,7 +746,7 @@ do_reformat:
 
        if (groupflag && ! mn->m_ingrp) {
            output = add(";", output);
 
        if (groupflag && ! mn->m_ingrp) {
            output = add(";", output);
-           column += 1;
+           column++;
        }
 
        groupflag = mn->m_ingrp;
        }
 
        groupflag = mn->m_ingrp;
@@ -762,13 +771,13 @@ do_reformat:
        if (column != prefixlen) {
            if (len + column + 2 > OUTPUTLINELEN) {
 
        if (column != prefixlen) {
            if (len + column + 2 > OUTPUTLINELEN) {
 
-               if ((size_t) (prefixlen + 3) < tmpbufsize)
+               if ((size_t) (prefixlen + 3) < tmpbufsize)
                    tmpbuf = mh_xrealloc(tmpbuf, tmpbufsize = prefixlen + 3);
 
                snprintf(tmpbuf, tmpbufsize, ",\n%*s", column = prefixlen, "");
                output = add(tmpbuf, output);
            } else {
                    tmpbuf = mh_xrealloc(tmpbuf, tmpbufsize = prefixlen + 3);
 
                snprintf(tmpbuf, tmpbufsize, ",\n%*s", column = prefixlen, "");
                output = add(tmpbuf, output);
            } else {
-               output = add(", ", output);
+               output = add(", ", output);
                column += 2;
            }
        }
                column += 2;
            }
        }
@@ -798,10 +807,10 @@ do_reformat:
     output = NULL;
 
 out:
     output = NULL;
 
 out:
-    mh_xfree(tmpbuf);
-    mh_xfree(output);
+    free(tmpbuf);
+    free(output);
 
 
-    return errflag > 0;
+    return errflag;
 }
 
 /*
 }
 
 /*
@@ -817,7 +826,7 @@ scanstring(const char *string, int *asciilen, int *eightbitchars,
     *specialchars = 0;
 
     for (; *string != '\0'; string++) {
     *specialchars = 0;
 
     for (; *string != '\0'; string++) {
-       if ((isascii((unsigned char) *string))) {
+       if ((isascii((unsigned char) *string))) {
            (*asciilen)++;
            /*
             * So, a space is not a valid phrase character, but we're counting
            (*asciilen)++;
            /*
             * So, a space is not a valid phrase character, but we're counting
@@ -825,7 +834,7 @@ scanstring(const char *string, int *asciilen, int *eightbitchars,
             * encoded as an underscore.
             */
            if (!qphrasevalid((unsigned char) *string) && *string != ' ')
             * encoded as an underscore.
             */
            if (!qphrasevalid((unsigned char) *string) && *string != ' ')
-               (*specialchars)++;
+               (*specialchars)++;
        } else {
            (*eightbitchars)++;
        }
        } else {
            (*eightbitchars)++;
        }
@@ -864,5 +873,5 @@ pref_encoding(int ascii, int specials, int eightbits)
      */
 
     return base64len(ascii + eightbits) < (ascii - specials +
      */
 
     return base64len(ascii + eightbits) < (ascii - specials +
-                       (specials + eightbits) * 3) ? CE_BASE64 : CE_QUOTED;
+                       (specials + eightbits) * 3) ? CE_BASE64 : CE_QUOTED;
 }
 }