]> diplodocus.org Git - nmh/commitdiff
Getting closer to getting base64 header encoding working.
authorKen Hornstein <kenh@pobox.com>
Thu, 7 Nov 2013 21:02:14 +0000 (16:02 -0500)
committerKen Hornstein <kenh@pobox.com>
Thu, 7 Nov 2013 21:02:14 +0000 (16:02 -0500)
h/prototypes.h
sbr/base64.c
sbr/encode_rfc2047.c

index e94bee36091327b99a78311dff5da12071065cd8..57e51d7b47128b74673f91ba00f6922cf9f71bc6 100644 (file)
@@ -250,6 +250,7 @@ int what_now (char *, int, int, char *, char *,
 int WhatNow(int, char **);
 int writeBase64aux(FILE *, FILE *);
 int writeBase64 (unsigned char *, size_t, unsigned char *);
 int WhatNow(int, char **);
 int writeBase64aux(FILE *, FILE *);
 int writeBase64 (unsigned char *, size_t, unsigned char *);
+int writeBase64raw (unsigned char *, size_t, unsigned char *);
 
 /*
  * credentials management
 
 /*
  * credentials management
index c3045ab7b21db54e25f4be2382579d140781cdff..5ff9f53c4f91bdea08fdd868d74e8d588d9c0f6b 100644 (file)
@@ -114,3 +114,49 @@ writeBase64 (unsigned char *in, size_t length, unsigned char *out)
 
     return OK;
 }
 
     return OK;
 }
+
+/* 
+ * Essentially a duplicate of writeBase64, but without line wrapping or
+ * newline termination (note: string IS NUL terminated)
+ */
+
+int
+writeBase64raw (unsigned char *in, size_t length, unsigned char *out)
+{
+    while (1) {
+       unsigned long bits;
+       unsigned char *bp;
+       unsigned int cc;
+       for (cc = 0, bp = in; length > 0 && cc < 3; ++cc, ++bp, --length)
+          /* empty */ ;
+
+       if (cc == 0) {
+           break;
+       } else {
+           bits = (in[0] & 0xff) << 16;
+           if (cc > 1) {
+               bits |= (in[1] & 0xff) << 8;
+               if (cc > 2) {
+                   bits |= in[2] & 0xff;
+               }
+           }
+       }
+
+       for (bp = out + 4; bp > out; bits >>= 6)
+           *--bp = nib2b64[bits & 0x3f];
+       if (cc < 3) {
+           out[3] = '=';
+           if (cc < 2)
+               out[2] = '=';
+           out += 4;
+           break;
+       }
+
+       in += 3;
+       out += 4;
+    }
+
+    *out = '\0';
+
+    return OK;
+}
index 2929db1c4527ae2a576e7e8212e264d3d3161075..fcb1c10457921825cd18da2d0d0415413a28f103 100644 (file)
@@ -37,8 +37,15 @@ static char *address_headers[] = {
 
 #define is_fws(c) (c == '\t' || c == ' ' || c == '\n')
 
 
 #define is_fws(c) (c == '\t' || c == ' ' || c == '\n')
 
+#define qphrasevalid(c) ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || \
+                        (c >= 'a' && c <= 'z') || \
+                        c == '!' || c == '*' || c == '+' || c == '-' || \
+                        c == '/' || c == '=' || c == '_')
 #define qpspecial(c) (c < ' ' || c == '=' || c == '?' || c == '_')
 
 #define qpspecial(c) (c < ' ' || c == '=' || c == '?' || c == '_')
 
+#define base64len(n) (((n + 2) / 3 ) * 4)      /* String len to base64 len */
+#define strbase64(n) (n * 3 / 4)               /* Chars that fit in base64 */
+
 #define ENCODELINELIMIT        76
 
 static void unfold_header(char **, int);
 #define ENCODELINELIMIT        76
 
 static void unfold_header(char **, int);
@@ -287,8 +294,72 @@ field_encode_quoted(const char *name, char **value, const char *charset,
  */
 
 static int
  */
 
 static int
-field_encode_base64(const char *name, char **value, const char *encoding)
+field_encode_base64(const char *name, char **value, const char *charset)
 {
 {
+    int prefixlen = name ? strlen(name) + 2 : 0, charsetlen = strlen(charset);
+    int outlen = 0, numencode;
+    char *output = NULL, *p = *value, *q, *linestart;
+
+    /*
+     * If we had a zero-length prefix, then just encode the whole field
+     * as-is, without line wrapping.  Note that in addition to the encoding
+     *
+     * The added length we need is =? + charset + ?B? ... ?=
+     *
+     * That's 7 + strlen(charset) + 2 (for \n NUL).
+     */
+
+    while (prefixlen && ((base64len(strlen(p)) + 7 + charsetlen +
+                         prefixlen) > ENCODELINELIMIT)) {
+
+       /*
+        * Our very first time, don't pad the line in the front
+        */
+
+
+       if (! output) {
+           outlen += ENCODELINELIMIT - prefixlen + 1;
+           output = q = mh_xmalloc(outlen);
+           linestart = q - prefixlen;  /* Yes, this is intentional */
+       } else {
+           int curlen = q - output;
+
+           outlen += ENCODELINELIMIT + 1;
+           output = mh_xrealloc(output, outlen);
+           linestart = q = output + curlen;
+           q += snprintf(q, outlen - (q - output), "%*s", prefixlen, "");
+       }
+
+       /*
+        * We should have enough space now, so prepend the encoding markers
+        * and character set information
+        */
+
+       q += snprintf(q, outlen - (q - output), "=?%s?B?", charset);
+
+       /*
+        * Find out how much room we have left on the line and see how many
+        * characters we can stuff in.  The start of our line is marked
+        * by "linestart", so use that to figure out how many characters
+        * are left out of ENCODELINELIMIT.  Reserve 2 characters for the
+        * end markers, and calculate how many characters we can fit into
+        * that space given the base64 encoding expansion.
+        */
+
+       numencode = strbase64(ENCODELINELIMIT - (q - linestart) - 2);
+
+       if (numencode <= 0) {
+           advise(NULL, "Internal error: tried to encode %d characters "
+                  "in base64", numencode);
+           return 1;
+       }
+
+       /*
+        * RFC 2047 prohibits spanning multibyte characters across tokens.
+        * Right now we only check for UTF-8.
+        */
+    }
+
     return 0;
 }
 
     return 0;
 }