Statistics
| Revision:

root / src / quoted-printable.c @ 1

History | View | Annotate | Download (4.46 KB)

1
/*
2
 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3
 * Copyright (C) 1999-2003 Hiroyuki Yamamoto
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 2 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, write to the Free Software
17
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
 */
19

    
20
#include <glib.h>
21
#include <ctype.h>
22

    
23
static gboolean get_hex_value(guchar *out, gchar c1, gchar c2);
24
static 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

    
39
void 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

    
88
gint 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(outp, inp[1], inp[2]) == TRUE) {
96
                                inp += 3;
97
                        } else if (inp[1] == '\0' || isspace((guchar)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_q_encoding(guchar *out, const gchar *in, gint inlen)
116
{
117
        const gchar *inp = in;
118
        guchar *outp = out;
119

    
120
        if (inlen < 0)
121
                inlen = G_MAXINT;
122

    
123
        while (inp - in < inlen && *inp != '\0') {
124
                if (*inp == '=' && inp + 3 - in <= inlen) {
125
                        if (get_hex_value(outp, inp[1], inp[2]) == TRUE) {
126
                                inp += 3;
127
                        } else {
128
                                *outp = *inp++;
129
                        }
130
                } else if (*inp == '_') {
131
                        *outp = ' ';
132
                        inp++;
133
                } else {
134
                        *outp = *inp++;
135
                }
136
                outp++;
137
        }
138

    
139
        *outp = '\0';
140

    
141
        return outp - out;
142
}
143

    
144
gint qp_get_q_encoding_len(const guchar *str)
145
{
146
        const guchar *inp = str;
147
        gint len = 0;
148

    
149
        while (*inp != '\0') {
150
                if (*inp == 0x20)
151
                        len++;
152
                else if (*inp == '=' || *inp == '?' || *inp == '_' ||
153
                         *inp < 32 || *inp > 127 || isspace(*inp))
154
                        len += 3;
155
                else
156
                        len++;
157

    
158
                inp++;
159
        }
160

    
161
        return len;
162
}
163

    
164
void qp_q_encode(gchar *out, const guchar *in)
165
{
166
        const guchar *inp = in;
167
        gchar *outp = out;
168

    
169
        while (*inp != '\0') {
170
                if (*inp == 0x20)
171
                        *outp++ = '_';
172
                else if (*inp == '=' || *inp == '?' || *inp == '_' ||
173
                         *inp < 32 || *inp > 127 || isspace(*inp)) {
174
                        *outp++ = '=';
175
                        get_hex_str(outp, *inp);
176
                        outp += 2;
177
                } else
178
                        *outp++ = *inp;
179

    
180
                inp++;
181
        }
182

    
183
        *outp = '\0';
184
}
185

    
186
#define HEX_TO_INT(val, hex)                        \
187
{                                                \
188
        gchar c = hex;                                \
189
                                                \
190
        if ('0' <= c && c <= '9') {                \
191
                val = c - '0';                        \
192
        } else if ('a' <= c && c <= 'f') {        \
193
                val = c - 'a' + 10;                \
194
        } else if ('A' <= c && c <= 'F') {        \
195
                val = c - 'A' + 10;                \
196
        } else {                                \
197
                val = -1;                        \
198
        }                                        \
199
}
200

    
201
static gboolean get_hex_value(guchar *out, gchar c1, gchar c2)
202
{
203
        gint hi, lo;
204

    
205
        HEX_TO_INT(hi, c1);
206
        HEX_TO_INT(lo, c2);
207

    
208
        if (hi == -1 || lo == -1)
209
                return FALSE;
210

    
211
        *out = (hi << 4) + lo;
212
        return TRUE;
213
}
214

    
215
#define INT_TO_HEX(hex, val)                \
216
{                                        \
217
        if ((val) < 10)                        \
218
                hex = '0' + (val);        \
219
        else                                \
220
                hex = 'A' + (val) - 10;        \
221
}
222

    
223
static void get_hex_str(gchar *out, guchar ch)
224
{
225
        gchar hex;
226

    
227
        INT_TO_HEX(hex, ch >> 4);
228
        *out++ = hex;
229
        INT_TO_HEX(hex, ch & 0x0f);
230
        *out++ = hex;
231
}