summaryrefslogtreecommitdiff
path: root/libsylph/quoted-printable.c
diff options
context:
space:
mode:
authorSimeon Simeonov2018-02-26 11:23:00 +0100
committerSimeon Simeonov2018-02-26 11:23:00 +0100
commit0b3cbf57875fd692e4ba0b336fefa4bee1ed00dc (patch)
treeaf916a30553c78ce9d4f2d8658656a175c5b6921 /libsylph/quoted-printable.c
Initial commit for sylpheed 3.7.0
Diffstat (limited to 'libsylph/quoted-printable.c')
-rw-r--r--libsylph/quoted-printable.c232
1 files changed, 232 insertions, 0 deletions
diff --git a/libsylph/quoted-printable.c b/libsylph/quoted-printable.c
new file mode 100644
index 0000000..adcdb05
--- /dev/null
+++ b/libsylph/quoted-printable.c
@@ -0,0 +1,232 @@
1/*
2 * LibSylph -- E-Mail client library
3 * Copyright (C) 1999-2005 Hiroyuki Yamamoto
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library 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 GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20#include <glib.h>
21#include <ctype.h>
22
23static gboolean get_hex_value(guchar *out, gchar c1, gchar c2);
24static void get_hex_str(gchar *out, guchar ch);
25
26#define MAX_LINELEN 76
27
28#define IS_LBREAK(p) \
29 (*(p) == '\0' || *(p) == '\n' || (*(p) == '\r' && *((p) + 1) == '\n'))
30
31#define SOFT_LBREAK_IF_REQUIRED(n) \
32 if (len + (n) > MAX_LINELEN || \
33 (len + (n) == MAX_LINELEN && (!IS_LBREAK(inp + 1)))) { \
34 *outp++ = '='; \
35 *outp++ = '\n'; \
36 len = 0; \
37 }
38
39void qp_encode_line(gchar *out, const guchar *in)
40{
41 const guchar *inp = in;
42 gchar *outp = out;
43 guchar ch;
44 gint len = 0;
45
46 while (*inp != '\0') {
47 ch = *inp;
48
49 if (IS_LBREAK(inp)) {
50 *outp++ = '\n';
51 len = 0;
52 if (*inp == '\r')
53 inp++;
54 inp++;
55 } else if (ch == '\t' || ch == ' ') {
56 if (IS_LBREAK(inp + 1)) {
57 SOFT_LBREAK_IF_REQUIRED(3);
58 *outp++ = '=';
59 get_hex_str(outp, ch);
60 outp += 2;
61 len += 3;
62 inp++;
63 } else {
64 SOFT_LBREAK_IF_REQUIRED(1);
65 *outp++ = *inp++;
66 len++;
67 }
68 } else if ((ch >= 33 && ch <= 60) || (ch >= 62 && ch <= 126)) {
69 SOFT_LBREAK_IF_REQUIRED(1);
70 *outp++ = *inp++;
71 len++;
72 } else {
73 SOFT_LBREAK_IF_REQUIRED(3);
74 *outp++ = '=';
75 get_hex_str(outp, ch);
76 outp += 2;
77 len += 3;
78 inp++;
79 }
80 }
81
82 if (len > 0)
83 *outp++ = '\n';
84
85 *outp = '\0';
86}
87
88gint qp_decode_line(gchar *str)
89{
90 gchar *inp = str, *outp = str;
91
92 while (*inp != '\0') {
93 if (*inp == '=') {
94 if (inp[1] && inp[2] &&
95 get_hex_value((guchar *)outp, inp[1], inp[2])
96 == TRUE) {
97 inp += 3;
98 } else if (inp[1] == '\0' || g_ascii_isspace(inp[1])) {
99 /* soft line break */
100 break;
101 } else {
102 /* broken QP string */
103 *outp = *inp++;
104 }
105 } else {
106 *outp = *inp++;
107 }
108 outp++;
109 }
110
111 *outp = '\0';
112
113 return outp - str;
114}
115
116gint qp_decode_q_encoding(guchar *out, const gchar *in, gint inlen)
117{
118 const gchar *inp = in;
119 guchar *outp = out;
120
121 if (inlen < 0)
122 inlen = G_MAXINT;
123
124 while (inp - in < inlen && *inp != '\0') {
125 if (*inp == '=' && inp + 3 - in <= inlen) {
126 if (get_hex_value(outp, inp[1], inp[2]) == TRUE) {
127 inp += 3;
128 } else {
129 *outp = *inp++;
130 }
131 } else if (*inp == '_') {
132 *outp = ' ';
133 inp++;
134 } else {
135 *outp = *inp++;
136 }
137 outp++;
138 }
139
140 *outp = '\0';
141
142 return outp - out;
143}
144
145gint qp_get_q_encoding_len(const guchar *str)
146{
147 const guchar *inp = str;
148 gint len = 0;
149
150 while (*inp != '\0') {
151 if (*inp == 0x20)
152 len++;
153 else if (*inp == '=' || *inp == '?' || *inp == '_' ||
154 *inp < 32 || *inp > 127 || g_ascii_isspace(*inp))
155 len += 3;
156 else
157 len++;
158
159 inp++;
160 }
161
162 return len;
163}
164
165void qp_q_encode(gchar *out, const guchar *in)
166{
167 const guchar *inp = in;
168 gchar *outp = out;
169
170 while (*inp != '\0') {
171 if (*inp == 0x20)
172 *outp++ = '_';
173 else if (*inp == '=' || *inp == '?' || *inp == '_' ||
174 *inp < 32 || *inp > 127 || g_ascii_isspace(*inp)) {
175 *outp++ = '=';
176 get_hex_str(outp, *inp);
177 outp += 2;
178 } else
179 *outp++ = *inp;
180
181 inp++;
182 }
183
184 *outp = '\0';
185}
186
187#define HEX_TO_INT(val, hex) \
188{ \
189 gchar c = hex; \
190 \
191 if ('0' <= c && c <= '9') { \
192 val = c - '0'; \
193 } else if ('a' <= c && c <= 'f') { \
194 val = c - 'a' + 10; \
195 } else if ('A' <= c && c <= 'F') { \
196 val = c - 'A' + 10; \
197 } else { \
198 val = -1; \
199 } \
200}
201
202static gboolean get_hex_value(guchar *out, gchar c1, gchar c2)
203{
204 gint hi, lo;
205
206 HEX_TO_INT(hi, c1);
207 HEX_TO_INT(lo, c2);
208
209 if (hi == -1 || lo == -1)
210 return FALSE;
211
212 *out = (hi << 4) + lo;
213 return TRUE;
214}
215
216#define INT_TO_HEX(hex, val) \
217{ \
218 if ((val) < 10) \
219 hex = '0' + (val); \
220 else \
221 hex = 'A' + (val) - 10; \
222}
223
224static void get_hex_str(gchar *out, guchar ch)
225{
226 gchar hex;
227
228 INT_TO_HEX(hex, ch >> 4);
229 *out++ = hex;
230 INT_TO_HEX(hex, ch & 0x0f);
231 *out++ = hex;
232}