Statistics
| Branch: | Tag: | Revision:

root / libsylph / quoted-printable.c @ 8d7dcace

History | View | Annotate | Download (4.48 KB)

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

    
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((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

    
116
gint 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

    
145
gint 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

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

    
202
static 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

    
224
static 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
}