Statistics
| Branch: | Tag: | Revision:

root / libsylph / quoted-printable.c @ aebfd4cc

History | View | Annotate | Download (3.76 KB)

1
/*
2
 * LibSylph -- E-Mail client library
3
 * Copyright (C) 1999-2011 Hiroyuki Yamamoto
4
 */
5

    
6
#include <glib.h>
7
#include <ctype.h>
8

    
9
static gboolean get_hex_value(guchar *out, gchar c1, gchar c2);
10
static void get_hex_str(gchar *out, guchar ch);
11

    
12
#define MAX_LINELEN        76
13

    
14
#define IS_LBREAK(p) \
15
        (*(p) == '\0' || *(p) == '\n' || (*(p) == '\r' && *((p) + 1) == '\n'))
16

    
17
#define SOFT_LBREAK_IF_REQUIRED(n)                                        \
18
        if (len + (n) > MAX_LINELEN ||                                        \
19
            (len + (n) == MAX_LINELEN && (!IS_LBREAK(inp + 1)))) {        \
20
                *outp++ = '=';                                                \
21
                *outp++ = '\n';                                                \
22
                len = 0;                                                \
23
        }
24

    
25
void qp_encode_line(gchar *out, const guchar *in)
26
{
27
        const guchar *inp = in;
28
        gchar *outp = out;
29
        guchar ch;
30
        gint len = 0;
31

    
32
        while (*inp != '\0') {
33
                ch = *inp;
34

    
35
                if (IS_LBREAK(inp)) {
36
                        *outp++ = '\n';
37
                        len = 0;
38
                        if (*inp == '\r')
39
                                inp++;
40
                        inp++;
41
                } else if (ch == '\t' || ch == ' ') {
42
                        if (IS_LBREAK(inp + 1)) {
43
                                SOFT_LBREAK_IF_REQUIRED(3);
44
                                *outp++ = '=';
45
                                get_hex_str(outp, ch);
46
                                outp += 2;
47
                                len += 3;
48
                                inp++;
49
                        } else {
50
                                SOFT_LBREAK_IF_REQUIRED(1);
51
                                *outp++ = *inp++;
52
                                len++;
53
                        }
54
                } else if ((ch >= 33 && ch <= 60) || (ch >= 62 && ch <= 126)) {
55
                        SOFT_LBREAK_IF_REQUIRED(1);
56
                        *outp++ = *inp++;
57
                        len++;
58
                } else {
59
                        SOFT_LBREAK_IF_REQUIRED(3);
60
                        *outp++ = '=';
61
                        get_hex_str(outp, ch);
62
                        outp += 2;
63
                        len += 3;
64
                        inp++;
65
                }
66
        }
67

    
68
        if (len > 0)
69
                *outp++ = '\n';
70

    
71
        *outp = '\0';
72
}
73

    
74
gint qp_decode_line(gchar *str)
75
{
76
        gchar *inp = str, *outp = str;
77

    
78
        while (*inp != '\0') {
79
                if (*inp == '=') {
80
                        if (inp[1] && inp[2] &&
81
                            get_hex_value((guchar *)outp, inp[1], inp[2])
82
                            == TRUE) {
83
                                inp += 3;
84
                        } else if (inp[1] == '\0' || g_ascii_isspace(inp[1])) {
85
                                /* soft line break */
86
                                break;
87
                        } else {
88
                                /* broken QP string */
89
                                *outp = *inp++;
90
                        }
91
                } else {
92
                        *outp = *inp++;
93
                }
94
                outp++;
95
        }
96

    
97
        *outp = '\0';
98

    
99
        return outp - str;
100
}
101

    
102
gint qp_decode_q_encoding(guchar *out, const gchar *in, gint inlen)
103
{
104
        const gchar *inp = in;
105
        guchar *outp = out;
106

    
107
        if (inlen < 0)
108
                inlen = G_MAXINT;
109

    
110
        while (inp - in < inlen && *inp != '\0') {
111
                if (*inp == '=' && inp + 3 - in <= inlen) {
112
                        if (get_hex_value(outp, inp[1], inp[2]) == TRUE) {
113
                                inp += 3;
114
                        } else {
115
                                *outp = *inp++;
116
                        }
117
                } else if (*inp == '_') {
118
                        *outp = ' ';
119
                        inp++;
120
                } else {
121
                        *outp = *inp++;
122
                }
123
                outp++;
124
        }
125

    
126
        *outp = '\0';
127

    
128
        return outp - out;
129
}
130

    
131
gint qp_get_q_encoding_len(const guchar *str)
132
{
133
        const guchar *inp = str;
134
        gint len = 0;
135

    
136
        while (*inp != '\0') {
137
                if (*inp == 0x20)
138
                        len++;
139
                else if (*inp == '=' || *inp == '?' || *inp == '_' ||
140
                         *inp < 32 || *inp > 127 || g_ascii_isspace(*inp))
141
                        len += 3;
142
                else
143
                        len++;
144

    
145
                inp++;
146
        }
147

    
148
        return len;
149
}
150

    
151
void qp_q_encode(gchar *out, const guchar *in)
152
{
153
        const guchar *inp = in;
154
        gchar *outp = out;
155

    
156
        while (*inp != '\0') {
157
                if (*inp == 0x20)
158
                        *outp++ = '_';
159
                else if (*inp == '=' || *inp == '?' || *inp == '_' ||
160
                         *inp < 32 || *inp > 127 || g_ascii_isspace(*inp)) {
161
                        *outp++ = '=';
162
                        get_hex_str(outp, *inp);
163
                        outp += 2;
164
                } else
165
                        *outp++ = *inp;
166

    
167
                inp++;
168
        }
169

    
170
        *outp = '\0';
171
}
172

    
173
#define HEX_TO_INT(val, hex)                        \
174
{                                                \
175
        gchar c = hex;                                \
176
                                                \
177
        if ('0' <= c && c <= '9') {                \
178
                val = c - '0';                        \
179
        } else if ('a' <= c && c <= 'f') {        \
180
                val = c - 'a' + 10;                \
181
        } else if ('A' <= c && c <= 'F') {        \
182
                val = c - 'A' + 10;                \
183
        } else {                                \
184
                val = -1;                        \
185
        }                                        \
186
}
187

    
188
static gboolean get_hex_value(guchar *out, gchar c1, gchar c2)
189
{
190
        gint hi, lo;
191

    
192
        HEX_TO_INT(hi, c1);
193
        HEX_TO_INT(lo, c2);
194

    
195
        if (hi == -1 || lo == -1)
196
                return FALSE;
197

    
198
        *out = (hi << 4) + lo;
199
        return TRUE;
200
}
201

    
202
#define INT_TO_HEX(hex, val)                \
203
{                                        \
204
        if ((val) < 10)                        \
205
                hex = '0' + (val);        \
206
        else                                \
207
                hex = 'A' + (val) - 10;        \
208
}
209

    
210
static void get_hex_str(gchar *out, guchar ch)
211
{
212
        gchar hex;
213

    
214
        INT_TO_HEX(hex, ch >> 4);
215
        *out++ = hex;
216
        INT_TO_HEX(hex, ch & 0x0f);
217
        *out++ = hex;
218
}