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