quoted-printable.c (4224B)
1 /* 2 * Claws Mail -- a GTK based, lightweight, and fast e-mail client 3 * Copyright (C) 1999-2012 Hiroyuki Yamamoto and the Claws Mail team 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 3 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 * 18 */ 19 20 #include <glib.h> 21 #include <ctype.h> 22 23 #include "utils.h" 24 25 #define MAX_LINELEN 76 26 27 #define IS_LBREAK(p) \ 28 (*(p) == '\0' || *(p) == '\n' || (*(p) == '\r' && *((p) + 1) == '\n')) 29 30 #define SOFT_LBREAK_IF_REQUIRED(n) \ 31 if (len + (n) > MAX_LINELEN || \ 32 (len + (n) == MAX_LINELEN && (!IS_LBREAK(inp + 1)))) { \ 33 *outp++ = '='; \ 34 *outp++ = '\n'; \ 35 len = 0; \ 36 } 37 38 void qp_encode_line(gchar *out, const guchar *in) 39 { 40 const guchar *inp = in; 41 gchar *outp = out; 42 guchar ch; 43 gint len = 0; 44 45 while (*inp != '\0') { 46 ch = *inp; 47 48 if (IS_LBREAK(inp)) { 49 *outp++ = '\n'; 50 len = 0; 51 if (*inp == '\r') 52 inp++; 53 inp++; 54 } else if (ch == '\t' || ch == ' ') { 55 if (IS_LBREAK(inp + 1)) { 56 SOFT_LBREAK_IF_REQUIRED(3); 57 *outp++ = '='; 58 get_hex_str(outp, ch); 59 outp += 2; 60 len += 3; 61 inp++; 62 } else { 63 SOFT_LBREAK_IF_REQUIRED(1); 64 *outp++ = *inp++; 65 len++; 66 } 67 } else if ((ch >= 33 && ch <= 60) || (ch >= 62 && ch <= 126)) { 68 SOFT_LBREAK_IF_REQUIRED(1); 69 *outp++ = *inp++; 70 len++; 71 } else { 72 SOFT_LBREAK_IF_REQUIRED(3); 73 *outp++ = '='; 74 get_hex_str(outp, ch); 75 outp += 2; 76 len += 3; 77 inp++; 78 } 79 } 80 81 if (len > 0) 82 *outp++ = '\n'; 83 84 *outp = '\0'; 85 } 86 87 gint qp_decode_line(gchar *str) 88 { 89 gchar *inp = str, *outp = str; 90 91 while (*inp != '\0') { 92 if (*inp == '=') { 93 if (inp[1] && inp[2] && 94 get_hex_value((guchar *)outp, inp[1], inp[2]) 95 == TRUE) { 96 inp += 3; 97 } else if (inp[1] == '\0' || g_ascii_isspace(inp[1])) { 98 /* soft line break */ 99 break; 100 } else { 101 /* broken QP string */ 102 *outp = *inp++; 103 } 104 } else { 105 *outp = *inp++; 106 } 107 outp++; 108 } 109 110 *outp = '\0'; 111 112 return outp - str; 113 } 114 115 gint qp_decode_const(gchar *out, gint avail, const gchar *str) 116 { 117 const gchar *inp = str; 118 gchar *outp = out; 119 120 while (*inp != '\0' && avail > 0) { 121 if (*inp == '=') { 122 if (inp[1] && inp[2] && 123 get_hex_value((guchar *)outp, inp[1], inp[2]) 124 == TRUE) { 125 inp += 3; 126 } else if (inp[1] == '\0' || g_ascii_isspace(inp[1])) { 127 /* soft line break */ 128 break; 129 } else { 130 /* broken QP string */ 131 *outp = *inp++; 132 } 133 } else { 134 *outp = *inp++; 135 } 136 outp++; 137 avail--; 138 } 139 140 *outp = '\0'; 141 142 return outp - out; 143 } 144 145 gint qp_decode_q_encoding(guchar *out, const gchar *in, gint inlen) 146 { 147 const gchar *inp = in; 148 guchar *outp = out; 149 150 if (inlen < 0) 151 inlen = G_MAXINT; 152 153 while (inp - in < inlen && *inp != '\0') { 154 if (*inp == '=' && inp + 3 - in <= inlen) { 155 if (get_hex_value(outp, inp[1], inp[2]) == TRUE) { 156 inp += 3; 157 } else { 158 *outp = *inp++; 159 } 160 } else if (*inp == '_') { 161 *outp = ' '; 162 inp++; 163 } else { 164 *outp = *inp++; 165 } 166 outp++; 167 } 168 169 *outp = '\0'; 170 171 return outp - out; 172 } 173 174 gint qp_get_q_encoding_len(const guchar *str) 175 { 176 const guchar *inp = str; 177 gint len = 0; 178 179 while (*inp != '\0') { 180 if (*inp == 0x20) 181 len++; 182 else if (*inp == '=' || *inp == '?' || *inp == '_' || 183 *inp < 32 || *inp > 127 || g_ascii_isspace(*inp)) 184 len += 3; 185 else 186 len++; 187 188 inp++; 189 } 190 191 return len; 192 } 193 194 void qp_q_encode(gchar *out, const guchar *in) 195 { 196 const guchar *inp = in; 197 gchar *outp = out; 198 199 while (*inp != '\0') { 200 if (*inp == 0x20) 201 *outp++ = '_'; 202 else if (*inp == '=' || *inp == '?' || *inp == '_' || 203 *inp < 32 || *inp > 127 || g_ascii_isspace(*inp)) { 204 *outp++ = '='; 205 get_hex_str(outp, *inp); 206 outp += 2; 207 } else 208 *outp++ = *inp; 209 210 inp++; 211 } 212 213 *outp = '\0'; 214 }