Fix FSF address (Tobias Mueller, #470445)
[platform/upstream/evolution-data-server.git] / camel / camel-mime-filter-basic.c
1 /*
2  *  Copyright (C) 2000 Ximian Inc.
3  *
4  *  Authors: Michael Zucchi <notzed@ximian.com>
5  *           Jeffrey Stedfast <fejj@ximian.com>
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of version 2 of the GNU Lesser General Public
9  * License as published by the Free Software Foundation.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this program; if not, write to the
18  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20  */
21
22 #include <string.h>
23
24 #include "camel-mime-filter-basic.h"
25 #include "camel-mime-utils.h"
26
27 static void reset(CamelMimeFilter *mf);
28 static void complete(CamelMimeFilter *mf, char *in, size_t len, 
29                      size_t prespace, char **out, 
30                      size_t *outlen, size_t *outprespace);
31 static void filter(CamelMimeFilter *mf, char *in, size_t len, 
32                    size_t prespace, char **out, 
33                    size_t *outlen, size_t *outprespace);
34
35 static void camel_mime_filter_basic_class_init (CamelMimeFilterBasicClass *klass);
36 static void camel_mime_filter_basic_init       (CamelMimeFilterBasic *obj);
37
38 static CamelMimeFilterClass *camel_mime_filter_basic_parent;
39
40 static void
41 camel_mime_filter_basic_class_init (CamelMimeFilterBasicClass *klass)
42 {
43         CamelMimeFilterClass *filter_class = (CamelMimeFilterClass *) klass;
44         
45         camel_mime_filter_basic_parent = CAMEL_MIME_FILTER_CLASS(camel_type_get_global_classfuncs (camel_mime_filter_get_type ()));
46
47         filter_class->reset = reset;
48         filter_class->filter = filter;
49         filter_class->complete = complete;
50 }
51
52 static void
53 camel_mime_filter_basic_init (CamelMimeFilterBasic *obj)
54 {
55         obj->state = 0;
56         obj->save = 0;
57 }
58
59
60 CamelType
61 camel_mime_filter_basic_get_type (void)
62 {
63         static CamelType type = CAMEL_INVALID_TYPE;
64         
65         if (type == CAMEL_INVALID_TYPE) {
66                 type = camel_type_register (camel_mime_filter_get_type (), "CamelMimeFilterBasic",
67                                             sizeof (CamelMimeFilterBasic),
68                                             sizeof (CamelMimeFilterBasicClass),
69                                             (CamelObjectClassInitFunc) camel_mime_filter_basic_class_init,
70                                             NULL,
71                                             (CamelObjectInitFunc) camel_mime_filter_basic_init,
72                                             NULL);
73         }
74         
75         return type;
76 }
77
78 /* should this 'flush' outstanding state/data bytes? */
79 static void
80 reset(CamelMimeFilter *mf)
81 {
82         CamelMimeFilterBasic *f = (CamelMimeFilterBasic *)mf;
83         
84         switch(f->type) {
85         case CAMEL_MIME_FILTER_BASIC_QP_ENC:
86                 f->state = -1;
87                 break;
88         default:
89                 f->state = 0;
90         }
91         f->save = 0;
92 }
93
94 static void
95 complete(CamelMimeFilter *mf, char *in, size_t len, size_t prespace, char **out, size_t *outlen, size_t *outprespace)
96 {
97         CamelMimeFilterBasic *f = (CamelMimeFilterBasic *)mf;
98         size_t newlen;
99         
100         switch(f->type) {
101         case CAMEL_MIME_FILTER_BASIC_BASE64_ENC:
102                 /* wont go to more than 2x size (overly conservative) */
103                 camel_mime_filter_set_size(mf, len*2+6, FALSE);
104                 newlen = camel_base64_encode_close(in, len, TRUE, mf->outbuf, &f->state, &f->save);
105                 g_assert(newlen <= len*2+6);
106                 break;
107         case CAMEL_MIME_FILTER_BASIC_QP_ENC:
108                 /* *4 is definetly more than needed ... */
109                 camel_mime_filter_set_size(mf, len*4+4, FALSE);
110                 newlen = camel_quoted_encode_close(in, len, mf->outbuf, &f->state, &f->save);
111                 g_assert(newlen <= len*4+4);
112                 break;
113         case CAMEL_MIME_FILTER_BASIC_UU_ENC:
114                 /* won't go to more than 2 * (x + 2) + 62 */
115                 camel_mime_filter_set_size (mf, (len + 2) * 2 + 62, FALSE);
116                 newlen = camel_uuencode_close (in, len, mf->outbuf, f->uubuf, &f->state, &f->save);
117                 g_assert (newlen <= (len + 2) * 2 + 62);
118                 break;
119         case CAMEL_MIME_FILTER_BASIC_BASE64_DEC:
120                 /* output can't possibly exceed the input size */
121                 camel_mime_filter_set_size(mf, len, FALSE);
122                 newlen = camel_base64_decode_step(in, len, mf->outbuf, &f->state, &f->save);
123                 g_assert(newlen <= len);
124                 break;
125         case CAMEL_MIME_FILTER_BASIC_QP_DEC:
126                 /* output can't possibly exceed the input size, well unless its not really qp, then +2 max */
127                 camel_mime_filter_set_size(mf, len+2, FALSE);
128                 newlen = camel_quoted_decode_step(in, len, mf->outbuf, &f->state, &f->save);
129                 g_assert(newlen <= len+2);
130                 break;
131         case CAMEL_MIME_FILTER_BASIC_UU_DEC:
132                 if ((f->state & CAMEL_UUDECODE_STATE_BEGIN) && !(f->state & CAMEL_UUDECODE_STATE_END)) {
133                         /* "begin <mode> <filename>\n" has been found, so we can now start decoding */
134                         camel_mime_filter_set_size (mf, len + 3, FALSE);
135                         newlen = camel_uudecode_step (in, len, mf->outbuf, &f->state, &f->save);
136                 } else {
137                         newlen = 0;
138                 }
139                 break;
140         default:
141                 g_warning ("unknown type %u in CamelMimeFilterBasic", f->type);
142                 goto donothing;
143         }
144
145         *out = mf->outbuf;
146         *outlen = newlen;
147         *outprespace = mf->outpre;
148
149         return;
150 donothing:
151         *out = in;
152         *outlen = len;
153         *outprespace = prespace;
154 }
155
156 /* here we do all of the basic mime filtering */
157 static void
158 filter(CamelMimeFilter *mf, char *in, size_t len, size_t prespace, char **out, size_t *outlen, size_t *outprespace)
159 {
160         CamelMimeFilterBasic *f = (CamelMimeFilterBasic *)mf;
161         size_t newlen;
162         
163         switch(f->type) {
164         case CAMEL_MIME_FILTER_BASIC_BASE64_ENC:
165                 /* wont go to more than 2x size (overly conservative) */
166                 camel_mime_filter_set_size(mf, len*2+6, FALSE);
167                 newlen = camel_base64_encode_step(in, len, TRUE, mf->outbuf, &f->state, &f->save);
168                 g_assert(newlen <= len*2+6);
169                 break;
170         case CAMEL_MIME_FILTER_BASIC_QP_ENC:
171                 /* *4 is overly conservative, but will do */
172                 camel_mime_filter_set_size(mf, len*4+4, FALSE);
173                 newlen = camel_quoted_encode_step(in, len, mf->outbuf, &f->state, &f->save);
174                 g_assert(newlen <= len*4+4);
175                 break;
176         case CAMEL_MIME_FILTER_BASIC_UU_ENC:
177                 /* won't go to more than 2 * (x + 2) + 62 */
178                 camel_mime_filter_set_size (mf, (len + 2) * 2 + 62, FALSE);
179                 newlen = camel_uuencode_step (in, len, mf->outbuf, f->uubuf, &f->state, &f->save);
180                 g_assert (newlen <= (len + 2) * 2 + 62);
181                 break;
182         case CAMEL_MIME_FILTER_BASIC_BASE64_DEC:
183                 /* output can't possibly exceed the input size */
184                 camel_mime_filter_set_size(mf, len+3, FALSE);
185                 newlen = camel_base64_decode_step(in, len, mf->outbuf, &f->state, &f->save);
186                 g_assert(newlen <= len+3);
187                 break;
188         case CAMEL_MIME_FILTER_BASIC_QP_DEC:
189                 /* output can't possibly exceed the input size */
190                 camel_mime_filter_set_size(mf, len + 2, FALSE);
191                 newlen = camel_quoted_decode_step(in, len, mf->outbuf, &f->state, &f->save);
192                 g_assert(newlen <= len + 2);
193                 break;
194         case CAMEL_MIME_FILTER_BASIC_UU_DEC:
195                 if (!(f->state & CAMEL_UUDECODE_STATE_BEGIN)) {
196                         register char *inptr, *inend;
197                         size_t left;
198                         
199                         inptr = in;
200                         inend = inptr + len;
201                         
202                         while (inptr < inend) {
203                                 left = inend - inptr;
204                                 if (left < 6) {
205                                         if (!strncmp (inptr, "begin ", left))
206                                                 camel_mime_filter_backup (mf, inptr, left);
207                                         break;
208                                 } else if (!strncmp (inptr, "begin ", 6)) {
209                                         for (in = inptr; inptr < inend && *inptr != '\n'; inptr++);
210                                         if (inptr < inend) {
211                                                 inptr++;
212                                                 f->state |= CAMEL_UUDECODE_STATE_BEGIN;
213                                                 /* we can start uudecoding... */
214                                                 in = inptr;
215                                                 len = inend - in;
216                                         } else {
217                                                 camel_mime_filter_backup (mf, in, left);
218                                         }
219                                         break;
220                                 }
221                                 
222                                 /* go to the next line */
223                                 for ( ; inptr < inend && *inptr != '\n'; inptr++);
224                                 
225                                 if (inptr < inend)
226                                         inptr++;
227                         }
228                 }
229                 
230                 if ((f->state & CAMEL_UUDECODE_STATE_BEGIN) && !(f->state & CAMEL_UUDECODE_STATE_END)) {
231                         /* "begin <mode> <filename>\n" has been found, so we can now start decoding */
232                         camel_mime_filter_set_size (mf, len + 3, FALSE);
233                         newlen = camel_uudecode_step (in, len, mf->outbuf, &f->state, &f->save);
234                 } else {
235                         newlen = 0;
236                 }
237                 break;
238         default:
239                 g_warning ("unknown type %u in CamelMimeFilterBasic", f->type);
240                 goto donothing;
241         }
242
243         *out = mf->outbuf;
244         *outlen = newlen;
245         *outprespace = mf->outpre;
246
247         return;
248 donothing:
249         *out = in;
250         *outlen = len;
251         *outprespace = prespace;
252 }
253
254
255 /**
256  * camel_mime_filter_basic_new:
257  *
258  * Create a new #CamelMimeFilterBasic object.
259  * 
260  * Returns a new #CamelMimeFilterBasic object
261  **/
262 CamelMimeFilterBasic *
263 camel_mime_filter_basic_new (void)
264 {
265         CamelMimeFilterBasic *new = CAMEL_MIME_FILTER_BASIC ( camel_object_new (camel_mime_filter_basic_get_type ()));
266         return new;
267 }
268
269
270 /**
271  * camel_mime_filter_basic_new_type:
272  * @type: a #CamelMimeFilterBasicType type
273  *
274  * Create a new #CamelMimeFilterBasic object of type @type.
275  * 
276  * Returns a new #CamelMimeFilterBasic object
277  **/
278 CamelMimeFilterBasic *
279 camel_mime_filter_basic_new_type(CamelMimeFilterBasicType type)
280 {
281         CamelMimeFilterBasic *new;
282
283         switch (type) {
284         case CAMEL_MIME_FILTER_BASIC_BASE64_ENC:
285         case CAMEL_MIME_FILTER_BASIC_QP_ENC:
286         case CAMEL_MIME_FILTER_BASIC_BASE64_DEC:
287         case CAMEL_MIME_FILTER_BASIC_QP_DEC:
288         case CAMEL_MIME_FILTER_BASIC_UU_ENC:
289         case CAMEL_MIME_FILTER_BASIC_UU_DEC:
290                 new = camel_mime_filter_basic_new();
291                 new->type = type;
292                 break;
293         default:
294                 g_warning ("Invalid type of CamelMimeFilterBasic requested: %u", type);
295                 new = NULL;
296                 break;
297         }
298         camel_mime_filter_reset((CamelMimeFilter *)new);
299         return new;
300 }
301