Try harder to match outlooks internal filename enc
authorAndre Heinecke <aheinecke@intevation.de>
Thu, 3 Dec 2015 14:38:10 +0000 (15:38 +0100)
committerAndre Heinecke <aheinecke@intevation.de>
Thu, 3 Dec 2015 14:38:10 +0000 (15:38 +0100)
* src/common.c (qp_encode): New. Simple quoted printable encoder.
  (b64_encode): Fix termination of return value.
* src/common.h: Add prototype
* src/mimemaker.c (utf8_to_rfc2047b): Use infer content encoding
  to switch between base64 and quoted printable.

--
As outlook rewrites the attachment filenames in unencrypted mails
we have to guess how they will look so that we sign them correctly.
If it turns out that this is to buggy we should probably replace
non ascii characters in that case.

src/common.c
src/common.h
src/mimemaker.c

index bf1c9e9..2142a80 100644 (file)
@@ -818,6 +818,51 @@ qp_decode (char *buffer, size_t length, int *r_slbrk)
   return d - buffer;
 }
 
+/* Return the a quoted printable encoded version of the
+   input string. If outlen is not null the size of the
+   quoted printable string is returned. String will be
+   malloced and zero terminated. Aborts if the output
+   is more then three times the size of the input.
+   This is only basic and does not handle mutliline data. */
+char *
+qp_encode (const char *input, size_t inlen, size_t *r_outlen)
+{
+  size_t max_len = inlen * 3 +1;
+  char *outbuf = xmalloc (max_len);
+  size_t outlen = 0;
+  const unsigned char *p;
+
+  memset (outbuf, 0, max_len);
+
+  for (p = input; inlen; p++, inlen--)
+    {
+      if (*p >= '!' && *p <= '~' && *p != '=')
+        {
+          outbuf[outlen++] = *p;
+        }
+      else if (*p == ' ')
+        {
+          /* Outlook does it this way */
+          outbuf[outlen++] = '_';
+        }
+      else
+        {
+          outbuf[outlen++] = '=';
+          outbuf[outlen++] = tohex ((*p>>4)&15);
+          outbuf[outlen++] = tohex (*p&15);
+        }
+      if (outlen == max_len -1)
+        {
+          log_error ("Quoted printable too long. Bug.");
+          r_outlen = NULL;
+          return NULL;
+        }
+    }
+  if (r_outlen)
+    *r_outlen = outlen;
+  return outbuf;
+}
+
 
 /* Initialize the Base 64 decoder state.  */
 void b64_init (b64_state_t *state)
@@ -909,6 +954,7 @@ b64_encode (const char *input, size_t length)
       return NULL;
     }
   ret = xmalloc (out_len);
+  memset (ret, 0, out_len);
 
   for (i = 0, j = 0; i < length;)
     {
@@ -933,8 +979,6 @@ b64_encode (const char *input, size_t length)
       ret [j - 2] = '=';
     }
 
-  ret[++j] = '\0';
-  log_debug("Encoded to: %s ", ret);
   return ret;
 }
 
index ea003b9..3d09446 100644 (file)
@@ -197,6 +197,7 @@ const char *default_homedir (void);
 char *get_data_dir (void);
 
 size_t qp_decode (char *buffer, size_t length, int *r_slbrk);
+char *qp_encode (const char *input, size_t length, size_t* outlen);
 void b64_init (b64_state_t *state);
 size_t b64_decode (b64_state_t *state, char *buffer, size_t length);
 char * b64_encode (const char *input, size_t length);
index 461d1e3..057ff9b 100644 (file)
@@ -793,19 +793,45 @@ infer_content_encoding (const void *data, size_t datalen)
 static char *
 utf8_to_rfc2047b (const char *input)
 {
-  char *ret;
+  char *ret,
+       *encoded;
+  int inferred_encoding = 0;
   if (!input)
     {
       return NULL;
     }
-  char *b64_encoded = b64_encode (input, strlen (input));
-  if (gpgrt_asprintf (&ret, "=?UTF-8?B?%s?=", b64_encoded) == -1)
+  inferred_encoding = infer_content_encoding (input, strlen (input));
+  if (!inferred_encoding)
     {
-      log_error ("%s:%s: Error: %i", SRCNAME, __func__, __LINE__);
-      xfree (b64_encoded);
-      return NULL;
+      return xstrdup (input);
+    }
+  log_debug ("%s:%s: Encoding attachment filename. With: %s ",
+             SRCNAME, __func__, inferred_encoding == 2 ? "Base64" : "QP");
+
+  if (inferred_encoding == 2)
+    {
+      encoded = b64_encode (input, strlen (input));
+      if (gpgrt_asprintf (&ret, "=?utf-8?B?%s?=", encoded) == -1)
+        {
+          log_error ("%s:%s: Error: %i", SRCNAME, __func__, __LINE__);
+          xfree (encoded);
+          return NULL;
+        }
+    }
+  else
+    {
+      /* There is a Bug here. If you encode 4 Byte UTF-8 outlook can't
+         handle it itself. And sends out a message with ?? inserted in
+         that place. This triggers an invalid signature. */
+      encoded = qp_encode (input, strlen (input), NULL);
+      if (gpgrt_asprintf (&ret, "=?utf-8?Q?%s?=", encoded) == -1)
+        {
+          log_error ("%s:%s: Error: %i", SRCNAME, __func__, __LINE__);
+          xfree (encoded);
+          return NULL;
+        }
     }
-  xfree (b64_encoded);
+  xfree (encoded);
   return ret;
 }