summaryrefslogtreecommitdiffstats
path: root/innbbsd/str_decode.c
blob: 4da40bcfe9f4c98835abff9c1e431ed9b6778b79 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
/*
 * 使用方法大致如下: innbbsd 中 在 SUBJECT 從 news 讀進來後, 呼叫
 * str_decode_M3(SUBJECT) 就行了
 */

/*
 * bsd 底下使用要編譯時要加  -I/usr/local/include -L/usr/local/lib -liconv
 * 並安裝 libiconv, 若真的沒有iconv就把底下的 #define USE_ICONV 1 刪了
 */

/*-------------------------------------------------------*/
/* lib/str_decode.c ( NTHU CS MapleBBS Ver 3.00 )    */
/*-------------------------------------------------------*/
/* target : included C for QP/BASE64 decoding        */
/* create : 95/03/29                     */
/* update : 97/03/29                     */
/*-------------------------------------------------------*/


/* ----------------------------------------------------- */
/* QP code : "0123456789ABCDEF"              */
/* ----------------------------------------------------- */

#include <stdio.h>
#include <errno.h>
#include <string.h>

#define USE_ICONV 1
/*
 * bsd 底下使用要編譯時要加  -I/usr/local/include -L/usr/local/lib -liconv
 * 若真的沒有iconv就把上面這行 #define 刪了
 */

#ifdef USE_ICONV
#include <iconv.h>
#endif

static int 
qp_code(int x)
{
    if (x >= '0' && x <= '9')
    return x - '0';
    if (x >= 'a' && x <= 'f')
    return x - 'a' + 10;
    if (x >= 'A' && x <= 'F')
    return x - 'A' + 10;
    return -1;
}


/* ------------------------------------------------------------------ */
/* BASE64 :                               */
/* "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" */
/* ------------------------------------------------------------------ */


static int 
base64_code(int x)
{
    if (x >= 'A' && x <= 'Z')
    return x - 'A';
    if (x >= 'a' && x <= 'z')
    return x - 'a' + 26;
    if (x >= '0' && x <= '9')
    return x - '0' + 52;
    if (x == '+')
    return 62;
    if (x == '/')
    return 63;
    return -1;
}


/* ----------------------------------------------------- */
/* judge & decode QP / BASE64                */
/* ----------------------------------------------------- */

static inline int 
isreturn(unsigned char c)
{
    return c == '\r' || c == '\n';
}

static inline int 
isspace(unsigned char c)
{
    return c == ' ' || c == '\t' || isreturn(c);
}

/* static inline */
int 
mmdecode(unsigned char *src, unsigned char encode, unsigned char *dst)
{
    /* Thor.980901: src和dst可相同, 但src 一定有?或\0結束 */
    /* Thor.980901: 注意, decode出的結果不會自己加上 \0 */
    unsigned char  *t = dst;
    int             pattern = 0, bits = 0;
    encode |= 0x20;     /* Thor: to lower */
    switch (encode) {
    case 'q':           /* Thor: quoted-printable */
    while (*src && *src != '?') {   /* Thor: delimiter *//* Thor.980901:
                     * 0 算是 delimiter */
        if (*src == '=') {
        int             x = *++src, y = x ? *++src : 0;
        if (isreturn(x))
            continue;
        if ((x = qp_code(x)) < 0 || (y = qp_code(y)) < 0)
            return -1;
        *t++ = (x << 4) + y, src++;
        } else if (*src == '_')
        *t++ = ' ', src++;
#if 0
        else if (!*src) /* Thor: no delimiter is not successful */
        return -1;
#endif
        else        /* Thor: *src != '=' '_' */
        *t++ = *src++;
    }
    return t - dst;
    case 'b':           /* Thor: base 64 */
    while (*src && *src != '?') {   /* Thor: delimiter */
        /*
         * Thor.980901: 0也算 *//* Thor: pattern & bits are cleared
         * outside
         */
        int             x;
#if 0
        if (!*src)
        return -1;  /* Thor: no delimiter is not successful */
#endif
        x = base64_code(*src++);
        if (x < 0)
        continue;   /* Thor: ignore everything not in the
                 * base64,=,.. */
        pattern = (pattern << 6) | x;
        bits += 6;      /* Thor: 1 code gains 6 bits */
        if (bits >= 8) {    /* Thor: enough to form a byte */
        bits -= 8;
        *t++ = (pattern >> bits) & 0xff;
        }
    }
    return t - dst;
    }
    return -1;
}

#ifdef USE_ICONV
size_t 
str_iconv(
      const char *fromcode, /* charset of source string */
      const char *tocode,   /* charset of destination string */
      char *src,        /* source string */
      size_t srclen,        /* source string length */
      char *dst,        /* destination string */
      size_t dstlen)
{               /* destination string length */
    /*
     * 這個函式會將一個字串 (src) 從 charset=fromcode 轉成 charset=tocode,
     * srclen 是 src 的長度, dst 是輸出的buffer, dstlen 則指定了 dst 的大小,
     * 最後會補 '\0', 所以要留一個byte給'\0'. 如果遇到 src 中有非字集的字,
     * 或是 src 中有未完整的 byte, 都會砍掉.
     */
    iconv_t         iconv_descriptor;
    size_t          iconv_ret, dstlen_old;

    dstlen--;           /* keep space for '\0' */

    dstlen_old = dstlen;

    /* Open a descriptor for iconv */
    iconv_descriptor = iconv_open(tocode, fromcode);

    if (iconv_descriptor == ((iconv_t) (-1))) { /* if open fail */
    strncpy(dst, src, dstlen);
    return dstlen;
    }
    /* Start translation */
    while (srclen > 0 && dstlen > 0) {
    iconv_ret = iconv(iconv_descriptor, (const char **)&src, &srclen,
              &dst, &dstlen);
    if (iconv_ret != 0) {
        switch (errno) {
        /* invalid multibyte happened */
        case EILSEQ:
        /* forward that byte */
        *dst = *src;
        src++;
        srclen--;
        dst++;
        dstlen--;
        break;
        /* incomplete multibyte happened */
        case EINVAL:
        /* forward that byte (maybe wrong) */
        *dst = *src;
        src++;
        srclen--;
        dst++;
        dstlen--;
        break;
        /* dst no rooms */
        case E2BIG:
        /* break out the while loop */
        srclen = 0;
        break;
        }
    }
    }
    *dst = '\0';
    /* close descriptor of iconv */
    iconv_close(iconv_descriptor);

    return (dstlen_old - dstlen);
}
#endif


void 
str_decode_M3(unsigned char *str)
{
    int             adj;
    int             i;
    unsigned char  *src, *dst;
    unsigned char   buf[512];
    unsigned char   charset[512], dst1[512];


    src = str;
    dst = buf;
    adj = 0;

    while (*src && (dst - buf) < sizeof(buf) - 1) {
    if (*src != '=') {  /* Thor: not coded */
        unsigned char  *tmp = src;
        while (adj && *tmp && isspace(*tmp))
        tmp++;
        if (adj && *tmp == '=') {   /* Thor: jump over space */
        adj = 0;
        src = tmp;
        } else
        *dst++ = *src++;
        /* continue; *//* Thor: take out */
    } else {        /* Thor: *src == '=' */
        unsigned char  *tmp = src + 1;
        if (*tmp == '?') {  /* Thor: =? coded */
        /* "=?%s?Q?" for QP, "=?%s?B?" for BASE64 */
        tmp++;
        i = 0;
        while (*tmp && *tmp != '?') {
            if (i + 1 < sizeof(charset)) {
            charset[i] = *tmp;
            charset[i + 1] = '\0';
            i++;
            }
            tmp++;
        }
        if (*tmp && tmp[1] && tmp[2] == '?') {  /* Thor: *tmp == '?' */
#ifdef USE_ICONV
            int             i = mmdecode(tmp + 3, tmp[1], dst1);
            i = str_iconv(charset, "big5", dst1, i, dst,
                  sizeof(buf) - ((int)(dst - buf)));
#else
            int             i = mmdecode(tmp + 3, tmp[1], dst);
#endif
            if (i >= 0) {
            tmp += 3;   /* Thor: decode's src */
#if 0
            while (*tmp++ != '?');  /* Thor: no ? end, mmdecode
                         * -1 */
#endif
            while (*tmp && *tmp++ != '?');  /* Thor: no ? end,
                             * mmdecode -1 */
            /* Thor.980901: 0 也算 decode 結束 */
            if (*tmp == '=')
                tmp++;
            src = tmp;  /* Thor: decode over */
            dst += i;
            adj = 1;/* Thor: adjcent */
            }
        }
        }
        while (src != tmp)  /* Thor: not coded */
        *dst++ = *src++;
    }
    }
    *dst = 0;
    strcpy(str, buf);
}