Fix possible overrun
[claws.git] / src / plugins / vcalendar / libical / libical / icalmime.c
1 /* -*- Mode: C -*-*/
2 /*======================================================================
3  FILE: icalmime.c
4  CREATOR: eric 26 July 2000
5
6
7  $Id$
8  $Locker$
9
10  (C) COPYRIGHT 2000, Eric Busboom, http://www.softwarestudio.org
11
12  This program is free software; you can redistribute it and/or modify
13  it under the terms of either: 
14
15     The LGPL as published by the Free Software Foundation, version
16     2.1, available at: http://www.fsf.org/copyleft/lesser.html
17
18   Or:
19
20     The Mozilla Public License Version 1.0. You may obtain a copy of
21     the License at http://www.mozilla.org/MPL/
22
23  The Original Code is eric. The Initial Developer of the Original
24  Code is Eric Busboom
25
26
27 ======================================================================*/
28
29 #include "icalmime.h"
30 #include "icalerror.h"
31 #include "icalmemory.h"
32 #include "sspm.h"
33 #include "stdlib.h"
34 #include <string.h> /* For strdup */
35 #include <stdio.h> /* for snprintf*/
36
37 #ifdef DMALLOC
38 #include "dmalloc.h"
39 #endif
40
41
42 /* These *_part routines are called by the MIME parser via the
43    local_action_map */
44
45 struct text_part
46 {
47         char* buf;
48         char* buf_pos;
49         size_t buf_size;
50 };
51
52 void* icalmime_text_new_part()
53 {
54
55 #define BUF_SIZE 2048
56
57     struct text_part* impl;
58
59     if ( ( impl = (struct text_part*)
60            malloc(sizeof(struct text_part))) == 0) {
61         return 0;
62     }
63
64     impl->buf =  icalmemory_new_buffer(BUF_SIZE);
65     impl->buf_pos = impl->buf;
66     impl->buf_size = BUF_SIZE;
67
68     return impl;    
69 }
70 void icalmime_text_add_line(void *part, 
71                             struct sspm_header *header, 
72                             char* line, size_t size)
73 {
74     struct text_part* impl = (struct text_part*) part;
75
76     icalmemory_append_string(&(impl->buf),&(impl->buf_pos),
77                              &(impl->buf_size),line);
78     
79 }
80
81 void* icalmime_textcalendar_end_part(void* part)
82 {
83
84     struct text_part* impl = (struct text_part*) part;
85     icalcomponent *c = icalparser_parse_string(impl->buf);
86
87     icalmemory_free_buffer(impl->buf);
88     free(impl);
89
90     return c;
91
92 }
93
94 void* icalmime_text_end_part(void* part)
95 {
96     struct text_part* impl = ( struct text_part*) part;
97     char *buf;
98     
99     icalmemory_add_tmp_buffer(impl->buf);
100     buf = impl->buf;
101
102     free(impl);
103
104     return buf;
105 }
106
107 void icalmime_text_free_part(void *part)
108 {
109     part = part;
110 }
111
112
113 /* Ignore Attachments for now */
114
115 void* icalmime_attachment_new_part()
116 {
117     return 0;
118 }
119 void icalmime_attachment_add_line(void *part, struct sspm_header *header, 
120                                   char* line, size_t size)
121 {
122     part = part;
123     header = header;
124     line = line;
125     size = size;
126 }
127
128 void* icalmime_attachment_end_part(void* part)
129 {
130     return 0;
131 }
132
133 void icalmime_attachment_free_part(void *part)
134 {
135 }
136
137
138
139
140 struct sspm_action_map icalmime_local_action_map[] = 
141 {
142     {SSPM_TEXT_MAJOR_TYPE,SSPM_CALENDAR_MINOR_TYPE,icalmime_text_new_part,icalmime_text_add_line,icalmime_textcalendar_end_part,icalmime_text_free_part},
143     {SSPM_TEXT_MAJOR_TYPE,SSPM_ANY_MINOR_TYPE,icalmime_text_new_part,icalmime_text_add_line,icalmime_text_end_part,icalmime_text_free_part},
144     {SSPM_TEXT_MAJOR_TYPE,SSPM_PLAIN_MINOR_TYPE,icalmime_text_new_part,icalmime_text_add_line,icalmime_text_end_part,icalmime_text_free_part},
145     {SSPM_APPLICATION_MAJOR_TYPE,SSPM_CALENDAR_MINOR_TYPE,icalmime_attachment_new_part,icalmime_attachment_add_line,icalmime_attachment_end_part,icalmime_attachment_free_part},
146     {SSPM_IMAGE_MAJOR_TYPE,SSPM_CALENDAR_MINOR_TYPE,icalmime_attachment_new_part,icalmime_attachment_add_line,icalmime_attachment_end_part,icalmime_attachment_free_part},
147     {SSPM_AUDIO_MAJOR_TYPE,SSPM_CALENDAR_MINOR_TYPE,icalmime_attachment_new_part,icalmime_attachment_add_line,icalmime_attachment_end_part,icalmime_attachment_free_part},
148     {SSPM_IMAGE_MAJOR_TYPE,SSPM_CALENDAR_MINOR_TYPE,icalmime_attachment_new_part,icalmime_attachment_add_line,icalmime_attachment_end_part,icalmime_attachment_free_part},
149    {SSPM_UNKNOWN_MAJOR_TYPE,SSPM_UNKNOWN_MINOR_TYPE,0,0,0,0}
150 };
151
152 #define NUM_PARTS 100 /* HACK. Hard Limit */
153
154
155
156 struct sspm_part* icalmime_make_part(icalcomponent* comp)
157 {
158     comp = comp;
159     return 0;
160 }
161
162 char* icalmime_as_mime_string(char* icalcomponent);
163
164 icalcomponent* icalmime_parse(char* (*get_string)(char *s, size_t size, 
165                                                        void *d),
166                                 void *data)
167 {
168     struct sspm_part *parts;
169     int i, last_level=0;
170     icalcomponent *root=0, *parent=0, *comp=0, *last = 0;
171     size_t alloc_len = NUM_PARTS * sizeof(struct sspm_part);
172
173     if ( (parts = (struct sspm_part *)
174           malloc(alloc_len))==0) {
175         icalerror_set_errno(ICAL_NEWFAILED_ERROR);
176         return 0;
177     }
178
179     memset(parts, 0, alloc_len);
180
181     sspm_parse_mime(parts, 
182                     NUM_PARTS, /* Max parts */
183                     icalmime_local_action_map, /* Actions */ 
184                     get_string,
185                     data, /* data for get_string*/
186                     0 /* First header */);
187
188
189
190     for(i = 0; i <NUM_PARTS && parts[i].header.major != SSPM_NO_MAJOR_TYPE ; i++){
191
192 #define TMPSZ 1024
193         char mimetype[TMPSZ];                          
194         char* major = sspm_major_type_string(parts[i].header.major);
195         char* minor = sspm_minor_type_string(parts[i].header.minor);
196
197         if(parts[i].header.minor == SSPM_UNKNOWN_MINOR_TYPE ){
198             assert(parts[i].header.minor_text !=0);
199             minor = parts[i].header.minor_text;
200         }
201         
202         sprintf(mimetype,"%s/%s",major,minor);
203
204         comp = icalcomponent_new(ICAL_XLICMIMEPART_COMPONENT);
205
206         if(comp == 0){
207             /* HACK Handle Error */
208             assert(0);
209         }
210
211         if(parts[i].header.error!=SSPM_NO_ERROR){
212             char *str = NULL;
213             char* temp[256];
214
215             if(parts[i].header.error==SSPM_UNEXPECTED_BOUNDARY_ERROR){
216                 str = "Got an unexpected boundary, possibly due to a MIME header for a MULTIPART part that is missing the Content-Type line";
217             }
218
219             if(parts[i].header.error==SSPM_WRONG_BOUNDARY_ERROR){
220                 str = "Got the wrong boundary for the opening of a MULTIPART part.";
221             }
222
223             if(parts[i].header.error==SSPM_NO_BOUNDARY_ERROR){
224                 str = "Got a multipart header that did not specify a boundary";
225             }
226
227             if(parts[i].header.error==SSPM_NO_HEADER_ERROR){
228                 str = "Did not get a header for the part. Is there a blank\
229 line between the header and the previous boundary\?";
230
231             }
232
233             if(parts[i].header.error_text != 0){
234                 snprintf((char*)temp,256,
235                          "%s: %s",str,parts[i].header.error_text);
236             } else {
237                 strncpy((char*)temp,str, 255);
238             }
239
240             icalcomponent_add_property
241                 (comp,
242                  icalproperty_vanew_xlicerror(
243                      (char*)temp,
244                      icalparameter_new_xlicerrortype(
245                          ICAL_XLICERRORTYPE_MIMEPARSEERROR),
246                      0));  
247         }
248
249         if(parts[i].header.major != SSPM_NO_MAJOR_TYPE &&
250            parts[i].header.major != SSPM_UNKNOWN_MAJOR_TYPE){
251
252             icalcomponent_add_property(comp,
253                 icalproperty_new_xlicmimecontenttype((char*)
254                                 icalmemory_strdup(mimetype)));
255
256         }
257
258         if (parts[i].header.encoding != SSPM_NO_ENCODING){
259
260             icalcomponent_add_property(comp,
261                icalproperty_new_xlicmimeencoding(
262                    sspm_encoding_string(parts[i].header.encoding)));
263         }
264
265         if (parts[i].header.filename != 0){
266             icalcomponent_add_property(comp,
267                icalproperty_new_xlicmimefilename(parts[i].header.filename));
268         }
269
270         if (parts[i].header.content_id != 0){
271             icalcomponent_add_property(comp,
272                icalproperty_new_xlicmimecid(parts[i].header.content_id));
273         }
274
275         if (parts[i].header.charset != 0){
276             icalcomponent_add_property(comp,
277                icalproperty_new_xlicmimecharset(parts[i].header.charset));
278         }
279
280         /* Add iCal components as children of the component */
281         if(parts[i].header.major == SSPM_TEXT_MAJOR_TYPE &&
282            parts[i].header.minor == SSPM_CALENDAR_MINOR_TYPE &&
283            parts[i].data != 0){
284
285             icalcomponent_add_component(comp,
286                                         (icalcomponent*)parts[i].data);
287             parts[i].data = 0;
288
289         } else  if(parts[i].header.major == SSPM_TEXT_MAJOR_TYPE &&
290            parts[i].header.minor != SSPM_CALENDAR_MINOR_TYPE &&
291            parts[i].data != 0){
292
293             /* Add other text components as "DESCRIPTION" properties */
294
295             icalcomponent_add_property(comp,
296                icalproperty_new_description(
297                    (char*)icalmemory_strdup((char*)parts[i].data)));
298
299             parts[i].data = 0;
300         }
301         
302
303         if(root!= 0 && parts[i].level == 0){
304             /* We've already assigned the root, but there is another
305                part at the root level. This is probably a parse
306                error*/
307             icalcomponent_free(comp);
308             continue;
309         }
310
311         if(parts[i].level == last_level && last_level != 0){
312             icalerror_assert(parent!=0,"No parent for adding component");
313
314             icalcomponent_add_component(parent,comp);
315
316         } else if (parts[i].level == last_level && last_level == 0 &&
317             root == 0) {
318
319             root = comp;
320             parent = comp;
321
322         } else if (parts[i].level > last_level){            
323
324             parent = last;
325             icalcomponent_add_component(parent,comp);
326
327             last_level = parts[i].level;
328
329         } else if (parts[i].level < last_level){
330
331             parent = icalcomponent_get_parent(parent);
332             icalcomponent_add_component(parent,comp);
333
334             last_level = parts[i].level;
335         } else { 
336             assert(0);
337         }
338
339         last = comp;
340         last_level = parts[i].level;
341         assert(parts[i].data == 0);
342     }
343
344     sspm_free_parts(parts,NUM_PARTS);
345     free(parts);
346
347     return root;
348 }
349
350
351
352 int icalmime_test(char* (*get_string)(char *s, size_t size, void *d),
353                   void *data)
354 {
355     char *out;
356     struct sspm_part *parts;
357     int i;
358     size_t alloc_len = NUM_PARTS * sizeof(struct sspm_part);
359
360     if ( (parts = (struct sspm_part *)
361           malloc(alloc_len))==0) {
362         icalerror_set_errno(ICAL_NEWFAILED_ERROR);
363         return 0;
364     }
365
366     memset(parts,0,alloc_len);
367
368     sspm_parse_mime(parts, 
369                     NUM_PARTS, /* Max parts */
370                     icalmime_local_action_map, /* Actions */ 
371                     get_string,
372                     data, /* data for get_string*/
373                     0 /* First header */);
374
375    for(i = 0; i <NUM_PARTS && parts[i].header.major != SSPM_NO_MAJOR_TYPE ; 
376        i++){
377        if(parts[i].header.minor == SSPM_CALENDAR_MINOR_TYPE){
378            parts[i].data = icalmemory_strdup(
379                icalcomponent_as_ical_string((icalcomponent*)parts[i].data));
380        }
381    }
382
383     sspm_write_mime(parts,NUM_PARTS,&out,"To: bob@bob.org");
384
385     printf("%s\n",out);
386
387     return 0;
388
389 }
390
391