]> source.dussan.org Git - rspamd.git/commitdiff
[Feature] Implement quoted printable decoding
authorVsevolod Stakhov <vsevolod@highsecure.ru>
Mon, 12 Dec 2016 11:22:50 +0000 (11:22 +0000)
committerVsevolod Stakhov <vsevolod@highsecure.ru>
Mon, 12 Dec 2016 11:23:07 +0000 (11:23 +0000)
src/libutil/str_util.c
src/libutil/str_util.h

index c12a9c56219eca4e17b93ece754871efa2679234..5be41f7846d5f4a9c5820aa5adfb834684e33b22 100644 (file)
@@ -1671,7 +1671,7 @@ rspamd_encode_hex (const guchar *in, gsize inlen)
        return out;
 }
 
-gint
+gssize
 rspamd_decode_hex_buf (const gchar *in, gsize inlen,
                guchar *out, gsize outlen)
 {
@@ -1738,6 +1738,93 @@ rspamd_decode_hex (const gchar *in, gsize inlen)
        return NULL;
 }
 
+gssize
+rspamd_decode_qp_buf (const gchar *in, gsize inlen,
+               gchar *out, gsize outlen)
+{
+       gchar *o, *end, *pos, c;
+       const gchar *p;
+       guchar ret;
+       gsize remain, processed;
+
+       p = in;
+       o = out;
+       end = out + outlen;
+       remain = inlen;
+
+       while (remain > 0 && o < end) {
+               if (*p == '=') {
+                       p ++;
+                       remain --;
+
+                       if (remain == 0) {
+                               if (end - o > 0) {
+                                       *o++ = *p;
+                                       break;
+                               }
+                       }
+decode:
+                       /* Decode character after '=' */
+                       c = *p++;
+                       remain --;
+
+                       if      (c >= '0' && c <= '9') { ret = c - '0'; }
+                       else if (c >= 'A' && c <= 'F') { ret = c - 'A' + 10; }
+                       else if (c >= 'a' && c <= 'f') { ret = c - 'a' + 10; }
+                       else if (c == '\r' || c == '\n') {
+                               /* Soft line break */
+                               while (remain > 0 && (*p == '\r' || *p == '\n')) {
+                                       remain --;
+                                       p ++;
+                               }
+
+                               continue;
+                       }
+
+                       if (remain > 0) {
+                               c = *p++;
+                               ret *= 16;
+
+                               if      (c >= '0' && c <= '9') ret += c - '0';
+                               else if (c >= 'A' && c <= 'F') ret += c - 'A' + 10;
+                               else if (c >= 'a' && c <= 'f') ret += c - 'a' + 10;
+
+                               if (end - o > 0) {
+                                       *o++ = (gchar)ret;
+                               }
+                               else {
+                                       return (-1);
+                               }
+
+                               remain --;
+                       }
+               }
+               else {
+                       if (end - o >= remain) {
+                               if ((pos = memccpy (o, p, '=', remain)) == NULL) {
+                                       /* All copied */
+                                       o += remain;
+                                       break;
+                               }
+                               else {
+                                       processed = pos - o;
+                                       remain -= processed;
+                                       p += processed;
+                                       o = pos - 1;
+                                       /* Skip comparison, as we know that we have found match */
+                                       goto decode;
+                               }
+                       }
+                       else {
+                               /* Buffer overflow */
+                               return (-1);
+                       }
+               }
+       }
+
+       return (o - out);
+}
+
 
 /*
  * GString ucl emitting functions
index 9b9bbe0c12788f8e63dd3c25ea539f23c7d39c98..37bd9fe82fa49c679356a502cbda0d582db84ff5 100644 (file)
@@ -180,7 +180,7 @@ gint rspamd_encode_hex_buf (const guchar *in, gsize inlen, gchar *out,
  * @param outlen output buf len
  * @return decoded len if in is valid hex and `outlen` is enough to encode `inlen`
  */
-gint rspamd_decode_hex_buf (const gchar *in, gsize inlen,
+gssize rspamd_decode_hex_buf (const gchar *in, gsize inlen,
                guchar *out, gsize outlen);
 
 /**
@@ -212,6 +212,17 @@ gchar * rspamd_encode_base64_fold (const guchar *in, gsize inlen, gint str_len,
  */
 gsize rspamd_decode_url (gchar *dst, const gchar *src, gsize size);
 
+/**
+ * Decode quoted-printable encoded buffer, input and output must not overlap
+ * @param in input
+ * @param inlen length of input
+ * @param out output
+ * @param outlen length of output
+ * @return real size of decoded output or (-1) if outlen is not enough
+ */
+gssize rspamd_decode_qp_buf (const gchar *in, gsize inlen,
+               gchar *out, gsize outlen);
+
 #ifndef g_tolower
 #   define g_tolower(x) (((x) >= 'A' && (x) <= 'Z') ? (x) - 'A' + 'a' : (x))
 #endif