2007-01-05 [colin] 2.6.1cvs108
[claws.git] / src / common / quoted-printable.c
index df6cca438973e7dfc3a7a00ecb2984e3bdfb76c8..bf3cc89b8e344e1aa06d9fffdaa02a522215aac3 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
- * Copyright (C) 1999-2002 Hiroyuki Yamamoto
+ * Copyright (C) 1999-2007 Hiroyuki Yamamoto and the Claws Mail team
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  */
 
 #include <glib.h>
 #include <ctype.h>
 
-static gboolean get_hex_value(guchar *out, gchar c1, gchar c2);
-static void get_hex_str(gchar *out, guchar ch);
+#include "utils.h"
+
+#define MAX_LINELEN    76
+
+#define IS_LBREAK(p) \
+       (*(p) == '\0' || *(p) == '\n' || (*(p) == '\r' && *((p) + 1) == '\n'))
+
+#define SOFT_LBREAK_IF_REQUIRED(n)                                     \
+       if (len + (n) > MAX_LINELEN ||                                  \
+           (len + (n) == MAX_LINELEN && (!IS_LBREAK(inp + 1)))) {      \
+               *outp++ = '=';                                          \
+               *outp++ = '\n';                                         \
+               len = 0;                                                \
+       }
+
+void qp_encode_line(gchar *out, const guchar *in)
+{
+       const guchar *inp = in;
+       gchar *outp = out;
+       guchar ch;
+       gint len = 0;
+
+       while (*inp != '\0') {
+               ch = *inp;
+
+               if (IS_LBREAK(inp)) {
+                       *outp++ = '\n';
+                       len = 0;
+                       if (*inp == '\r')
+                               inp++;
+                       inp++;
+               } else if (ch == '\t' || ch == ' ') {
+                       if (IS_LBREAK(inp + 1)) {
+                               SOFT_LBREAK_IF_REQUIRED(3);
+                               *outp++ = '=';
+                               get_hex_str(outp, ch);
+                               outp += 2;
+                               len += 3;
+                               inp++;
+                       } else {
+                               SOFT_LBREAK_IF_REQUIRED(1);
+                               *outp++ = *inp++;
+                               len++;
+                       }
+               } else if ((ch >= 33 && ch <= 60) || (ch >= 62 && ch <= 126)) {
+                       SOFT_LBREAK_IF_REQUIRED(1);
+                       *outp++ = *inp++;
+                       len++;
+               } else {
+                       SOFT_LBREAK_IF_REQUIRED(3);
+                       *outp++ = '=';
+                       get_hex_str(outp, ch);
+                       outp += 2;
+                       len += 3;
+                       inp++;
+               }
+       }
+
+       if (len > 0)
+               *outp++ = '\n';
+
+       *outp = '\0';
+}
 
 gint qp_decode_line(gchar *str)
 {
@@ -29,10 +90,14 @@ gint qp_decode_line(gchar *str)
 
        while (*inp != '\0') {
                if (*inp == '=') {
-                       if (inp[1] && inp[2] &&
-                           get_hex_value(outp, inp[1], inp[2]) == TRUE) {
+                       if (inp[1] && inp[2] && inp[1] == '0' && inp[2] == '0') {
                                inp += 3;
-                       } else if (inp[1] == '\0' || isspace(inp[1])) {
+                               continue;
+                       } else if (inp[1] && inp[2] &&
+                           get_hex_value((guchar *)outp, inp[1], inp[2])
+                           == TRUE) {
+                               inp += 3;
+                       } else if (inp[1] == '\0' || g_ascii_isspace(inp[1])) {
                                /* soft line break */
                                break;
                        } else {
@@ -50,6 +115,39 @@ gint qp_decode_line(gchar *str)
        return outp - str;
 }
 
+gint qp_decode_const(gchar *out, gint avail, const gchar *str)
+{
+       const gchar *inp = str;
+       gchar *outp = out;
+
+       while (*inp != '\0' && avail > 0) {
+               if (*inp == '=') {
+                       if (inp[1] && inp[2] && inp[1] == '0' && inp[2] == '0') {
+                               inp += 3;
+                               continue;
+                       } else if (inp[1] && inp[2] &&
+                           get_hex_value((guchar *)outp, inp[1], inp[2])
+                           == TRUE) {
+                               inp += 3;
+                       } else if (inp[1] == '\0' || g_ascii_isspace(inp[1])) {
+                               /* soft line break */
+                               break;
+                       } else {
+                               /* broken QP string */
+                               *outp = *inp++;
+                       }
+               } else {
+                       *outp = *inp++;
+               }
+               outp++;
+               avail--;
+       }
+
+       *outp = '\0';
+
+       return outp - out;
+}
+
 gint qp_decode_q_encoding(guchar *out, const gchar *in, gint inlen)
 {
        const gchar *inp = in;
@@ -60,7 +158,10 @@ gint qp_decode_q_encoding(guchar *out, const gchar *in, gint inlen)
 
        while (inp - in < inlen && *inp != '\0') {
                if (*inp == '=' && inp + 3 - in <= inlen) {
-                       if (get_hex_value(outp, inp[1], inp[2]) == TRUE) {
+                       if (inp[1] && inp[2] && inp[1] == '0' && inp[2] == '0') {
+                               inp += 3;
+                               continue;
+                       } else if (get_hex_value(outp, inp[1], inp[2]) == TRUE) {
                                inp += 3;
                        } else {
                                *outp = *inp++;
@@ -88,7 +189,7 @@ gint qp_get_q_encoding_len(const guchar *str)
                if (*inp == 0x20)
                        len++;
                else if (*inp == '=' || *inp == '?' || *inp == '_' ||
-                        *inp < 32 || *inp > 127 || isspace(*inp))
+                        *inp < 32 || *inp > 127 || g_ascii_isspace(*inp))
                        len += 3;
                else
                        len++;
@@ -108,7 +209,7 @@ void qp_q_encode(gchar *out, const guchar *in)
                if (*inp == 0x20)
                        *outp++ = '_';
                else if (*inp == '=' || *inp == '?' || *inp == '_' ||
-                        *inp < 32 || *inp > 127 || isspace(*inp)) {
+                        *inp < 32 || *inp > 127 || g_ascii_isspace(*inp)) {
                        *outp++ = '=';
                        get_hex_str(outp, *inp);
                        outp += 2;
@@ -120,50 +221,3 @@ void qp_q_encode(gchar *out, const guchar *in)
 
        *outp = '\0';
 }
-
-#define HEX_TO_INT(val, hex)                   \
-{                                              \
-       gchar c = hex;                          \
-                                               \
-       if ('0' <= c && c <= '9') {             \
-               val = c - '0';                  \
-       } else if ('a' <= c && c <= 'f') {      \
-               val = c - 'a' + 10;             \
-       } else if ('A' <= c && c <= 'F') {      \
-               val = c - 'A' + 10;             \
-       } else {                                \
-               val = -1;                       \
-       }                                       \
-}
-
-static gboolean get_hex_value(guchar *out, gchar c1, gchar c2)
-{
-       gint hi, lo;
-
-       HEX_TO_INT(hi, c1);
-       HEX_TO_INT(lo, c2);
-
-       if (hi == -1 || lo == -1)
-               return FALSE;
-
-       *out = (hi << 4) + lo;
-       return TRUE;
-}
-
-#define INT_TO_HEX(hex, val)           \
-{                                      \
-       if ((val) < 10)                 \
-               hex = '0' + (val);      \
-       else                            \
-               hex = 'A' + (val) - 10; \
-}
-
-static void get_hex_str(gchar *out, guchar ch)
-{
-       gchar hex;
-
-       INT_TO_HEX(hex, ch >> 4);
-       *out++ = hex;
-       INT_TO_HEX(hex, ch & 0x0f);
-       *out++ = hex;
-}