source: trunk/third/nmh/sbr/fmt_rfc2047.c @ 12455

Revision 12455, 5.9 KB checked in by danw, 26 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r12454, which included commits to RCS files with non-trunk default branches.
Line 
1
2/*
3 * fmt_rfc2047.c -- decode RFC-2047 header format
4 *
5 * $Id: fmt_rfc2047.c,v 1.1.1.1 1999-02-07 18:14:08 danw Exp $
6 */
7
8#include <h/mh.h>
9
10static signed char hexindex[] = {
11    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
12    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
13    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
14     0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1,
15    -1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1,
16    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
17    -1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1,
18    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
19};
20
21static signed char index_64[128] = {
22    -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
23    -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
24    -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,62, -1,-1,-1,63,
25    52,53,54,55, 56,57,58,59, 60,61,-1,-1, -1,-1,-1,-1,
26    -1, 0, 1, 2,  3, 4, 5, 6,  7, 8, 9,10, 11,12,13,14,
27    15,16,17,18, 19,20,21,22, 23,24,25,-1, -1,-1,-1,-1,
28    -1,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40,
29    41,42,43,44, 45,46,47,48, 49,50,51,-1, -1,-1,-1,-1
30};
31
32#define char64(c) (((unsigned char) (c) > 127) ? -1 : index_64[(unsigned char) (c)])
33
34static int
35unqp (unsigned char byte1, unsigned char byte2)
36{
37    if (hexindex[byte1] == -1 || hexindex[byte2] == -1)
38        return -1;
39    return (hexindex[byte1] << 4 | hexindex[byte2]);
40}
41
42/* Check if character is linear whitespace */
43#define is_lws(c)  ((c) == ' ' || (c) == '\t' || (c) == '\n')
44
45
46/*
47 * Decode the string as a RFC-2047 header field
48 */
49
50int
51decode_rfc2047 (char *str, char *dst)
52{
53    char *p, *q, *pp;
54    char *startofmime, *endofmime;
55    int c, quoted_printable;
56    int encoding_found = 0;     /* did we decode anything?                */
57    int between_encodings = 0;  /* are we between two encodings?          */
58    int equals_pending = 0;     /* is there a '=' pending?                */
59    int whitespace = 0;         /* how much whitespace between encodings? */
60
61    if (!str)
62        return 0;
63
64    /*
65     * Do a quick and dirty check for the '=' character.
66     * This should quickly eliminate many cases.
67     */
68    if (!strchr (str, '='))
69        return 0;
70
71    for (p = str, q = dst; *p; p++) {
72        /*
73         * If we had an '=' character pending from
74         * last iteration, then add it first.
75         */
76        if (equals_pending) {
77            *q++ = '=';
78            equals_pending = 0;
79            between_encodings = 0;      /* we have added non-whitespace text */
80        }
81
82        if (*p != '=') {
83            /* count linear whitespace while between encodings */
84            if (between_encodings && is_lws(*p))
85                whitespace++;
86            else
87                between_encodings = 0;  /* we have added non-whitespace text */
88            *q++ = *p;
89            continue;
90        }
91
92        equals_pending = 1;     /* we have a '=' pending */
93
94        /* Check for initial =? */
95        if (*p == '=' && p[1] && p[1] == '?' && p[2]) {
96            startofmime = p + 2;
97
98            /* Scan ahead for the next '?' character */
99            for (pp = startofmime; *pp && *pp != '?'; pp++)
100                ;
101
102            if (!*pp)
103                continue;
104
105            /* Check if character set is OK */
106            if (!check_charset(startofmime, pp - startofmime))
107                continue;
108
109            startofmime = pp + 1;
110
111            /* Check for valid encoding type */
112            if (*startofmime != 'B' && *startofmime != 'b' &&
113                *startofmime != 'Q' && *startofmime != 'q')
114                continue;
115
116            /* Is encoding quoted printable or base64? */
117            quoted_printable = (*startofmime == 'Q' || *startofmime == 'q');
118            startofmime++;
119
120            /* Check for next '?' character */
121            if (*startofmime != '?')
122                continue;
123            startofmime++;
124
125            /*
126             * Scan ahead for the ending ?=
127             *
128             * While doing this, we will also check if encoded
129             * word has any embedded linear whitespace.
130             */
131            endofmime = NULL;
132            for (pp = startofmime; *pp && *(pp+1); pp++) {
133                if (is_lws(*pp)) {
134                    break;
135                } else if (*pp == '?' && pp[1] == '=') {
136                    endofmime = pp;
137                    break;
138                }
139            }
140            if (is_lws(*pp) || endofmime == NULL)
141                continue;
142
143            /*
144             * We've found an encoded word, so we can drop
145             * the '=' that was pending
146             */
147            equals_pending = 0;
148
149            /*
150             * If we are between two encoded words separated only by
151             * linear whitespace, then we ignore the whitespace.
152             * We will roll back the buffer the number of whitespace
153             * characters we've seen since last encoded word.
154             */
155            if (between_encodings)
156                q -= whitespace;
157
158            /* Now decode the text */
159            if (quoted_printable) {
160                for (pp = startofmime; pp < endofmime; pp++) {
161                    if (*pp == '=') {
162                        c = unqp (pp[1], pp[2]);
163                        if (c == -1)
164                            continue;
165                        if (c != 0)
166                            *q++ = c;
167                        pp += 2;
168                    } else if (*pp == '_') {
169                        *q++ = ' ';
170                    } else {
171                        *q++ = *pp;
172                    }
173                }
174            } else {
175                /* base64 */
176                int c1, c2, c3, c4;
177
178                pp = startofmime;
179                while (pp < endofmime) {
180                    /* 6 + 2 bits */
181                    while ((pp < endofmime) &&
182                           ((c1 = char64(*pp)) == -1)) {
183                        pp++;
184                    }
185                    if (pp < endofmime) {
186                        pp++;
187                    }
188                    while ((pp < endofmime) &&
189                           ((c2 = char64(*pp)) == -1)) {
190                        pp++;
191                    }
192                    if (pp < endofmime && c1 != -1 && c2 != -1) {
193                        *q++ = (c1 << 2) | (c2 >> 4);
194                        pp++;
195                    }
196                    /* 4 + 4 bits */
197                    while ((pp < endofmime) &&
198                           ((c3 = char64(*pp)) == -1)) {
199                        pp++;
200                    }
201                    if (pp < endofmime && c2 != -1 && c3 != -1) {
202                        *q++ = ((c2 & 0xF) << 4) | (c3 >> 2);
203                        pp++;
204                    }
205                    /* 2 + 6 bits */
206                    while ((pp < endofmime) &&
207                           ((c4 = char64(*pp)) == -1)) {
208                        pp++;
209                    }
210                    if (pp < endofmime && c3 != -1 && c4 != -1) {
211                        *q++ = ((c3 & 0x3) << 6) | (c4);
212                        pp++;
213                    }
214                }
215            }
216
217            /*
218             * Now that we are done decoding this particular
219             * encoded word, advance string to trailing '='.
220             */
221            p = endofmime + 1;
222
223            encoding_found = 1;         /* we found (at least 1) encoded word */
224            between_encodings = 1;      /* we have just decoded something     */
225            whitespace = 0;             /* re-initialize amount of whitespace */
226        }
227    }
228
229    /* If an equals was pending at end of string, add it now. */
230    if (equals_pending)
231        *q++ = '=';
232    *q = '\0';
233
234    return encoding_found;
235}
Note: See TracBrowser for help on using the repository browser.