]> source.dussan.org Git - rspamd.git/commitdiff
[Feature] Add rfc2047 variant for QP decoding
authorVsevolod Stakhov <vsevolod@highsecure.ru>
Mon, 12 Dec 2016 18:07:13 +0000 (18:07 +0000)
committerVsevolod Stakhov <vsevolod@highsecure.ru>
Mon, 12 Dec 2016 18:07:13 +0000 (18:07 +0000)
src/libutil/str_util.c
src/libutil/str_util.h

index 5be41f7846d5f4a9c5820aa5adfb834684e33b22..cbad775cbe4960c929570c2bd6c181aacb8dafdf 100644 (file)
@@ -1825,6 +1825,118 @@ decode:
        return (o - out);
 }
 
+#define BITOP(a,b,op) \
+               ((a)[(gsize)(b)/(8*sizeof *(a))] op (gsize)1<<((gsize)(b)%(8*sizeof *(a))))
+static gsize
+rspamd_memcspn (const gchar *s, const gchar *e, gsize len)
+{
+       gsize byteset[32/sizeof(gsize)];
+       const gchar *p = s, *end = s + len;
+
+       memset(byteset, 0, sizeof byteset);
+
+       for (; *e && BITOP (byteset, *(guchar *)e, |=); e++);
+       for (; p < end && !BITOP (byteset, *(guchar *)p, &); p++);
+
+       return p - s;
+}
+
+gssize
+rspamd_decode_qp2047_buf (const gchar *in, gsize inlen,
+               gchar *out, gsize outlen)
+{
+       gchar *o, *end, 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) {
+                               processed = rspamd_memcspn (p, "=_", remain);
+                               memcpy (o, p, processed);
+                               o += remain;
+
+                               if (processed == remain) {
+                                       break;
+                               }
+                               else {
+
+                                       remain -= processed;
+                                       p += processed;
+
+                                       if (*p == '=') {
+                                               p ++;
+                                               /* Skip comparison, as we know that we have found match */
+                                               goto decode;
+                                       }
+                                       else {
+                                               *o++ = ' ';
+                                               p ++;
+                                       }
+                               }
+                       }
+                       else {
+                               /* Buffer overflow */
+                               return (-1);
+                       }
+               }
+       }
+
+       return (o - out);
+}
+
 
 /*
  * GString ucl emitting functions
index 37bd9fe82fa49c679356a502cbda0d582db84ff5..1fdb1a85786536d9bcfbd9518d3af9c36d30503d 100644 (file)
@@ -223,6 +223,17 @@ gsize rspamd_decode_url (gchar *dst, const gchar *src, gsize size);
 gssize rspamd_decode_qp_buf (const gchar *in, gsize inlen,
                gchar *out, gsize outlen);
 
+/**
+ * Decode quoted-printable encoded buffer using rfc2047 format, 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_qp2047_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