2 /*======================================================================
4 CREATOR: eric 26 July 2000
7 $Id: icalmime.c,v 1.14 2008-01-29 22:25:05 dothebart Exp $
10 (C) COPYRIGHT 2000, Eric Busboom, http://www.softwarestudio.org
12 This program is free software; you can redistribute it and/or modify
13 it under the terms of either:
15 The LGPL as published by the Free Software Foundation, version
16 2.1, available at: http://www.fsf.org/copyleft/lesser.html
20 The Mozilla Public License Version 1.0. You may obtain a copy of
21 the License at http://www.mozilla.org/MPL/
23 The Original Code is eric. The Initial Developer of the Original
27 ======================================================================*/
30 #include "icalerror.h"
31 #include "icalmemory.h"
34 #include <string.h> /* For strdup */
35 #include <stdio.h> /* for snprintf*/
42 #define snprintf _snprintf
43 #define strcasecmp stricmp
46 /* These *_part routines are called by the MIME parser via the
56 void* icalmime_text_new_part(void)
61 struct text_part* impl;
63 if ( ( impl = (struct text_part*)
64 malloc(sizeof(struct text_part))) == 0) {
68 impl->buf = icalmemory_new_buffer(BUF_SIZE);
69 impl->buf_pos = impl->buf;
70 impl->buf_size = BUF_SIZE;
74 void icalmime_text_add_line(void *part,
75 struct sspm_header *header,
76 const char* line, size_t size)
78 struct text_part* impl = (struct text_part*) part;
82 icalmemory_append_string(&(impl->buf),&(impl->buf_pos),
83 &(impl->buf_size),line);
87 void* icalmime_textcalendar_end_part(void* part)
90 struct text_part* impl = (struct text_part*) part;
91 icalcomponent *c = icalparser_parse_string(impl->buf);
93 icalmemory_free_buffer(impl->buf);
100 void* icalmime_text_end_part_r(void* part)
103 struct text_part* impl = ( struct text_part*) part;
111 void* icalmime_text_end_part(void* part)
114 buf = icalmime_text_end_part_r(part);
115 icalmemory_add_tmp_buffer(buf);
120 void icalmime_text_free_part(void *part)
126 /* Ignore Attachments for now */
128 void* icalmime_attachment_new_part(void)
132 void icalmime_attachment_add_line(void *part, struct sspm_header *header,
133 const char* line, size_t size)
141 void* icalmime_attachment_end_part(void* part)
147 void icalmime_attachment_free_part(void *part)
155 static const struct sspm_action_map icalmime_local_action_map[] =
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}
167 #define NUM_PARTS 100 /* HACK. Hard Limit */
171 struct sspm_part* icalmime_make_part(icalcomponent* comp)
177 char* icalmime_as_mime_string(char* icalcomponent);
179 icalcomponent* icalmime_parse(char* (*get_string)(char *s, size_t size,
183 struct sspm_part *parts;
185 icalcomponent *root=0, *parent=0, *comp=0, *last = 0;
187 if ( (parts = (struct sspm_part *)
188 malloc(NUM_PARTS*sizeof(struct sspm_part)))==0) {
189 icalerror_set_errno(ICAL_NEWFAILED_ERROR);
193 memset(parts,0,sizeof(parts));
195 sspm_parse_mime(parts,
196 NUM_PARTS, /* Max parts */
197 icalmime_local_action_map, /* Actions */
199 data, /* data for get_string*/
200 0 /* First header */);
204 for(i = 0; i <NUM_PARTS && parts[i].header.major != SSPM_NO_MAJOR_TYPE ; i++){
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);
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;
216 snprintf(mimetype,sizeof(mimetype),"%s/%s",major,minor);
218 comp = icalcomponent_new(ICAL_XLICMIMEPART_COMPONENT);
221 /* HACK Handle Error */
225 if(parts[i].header.error!=SSPM_NO_ERROR){
226 const char *str="Unknown error";
228 if(parts[i].header.error==SSPM_MALFORMED_HEADER_ERROR){
229 str = "Malformed header, possibly due to input not in MIME format";
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";
236 if(parts[i].header.error==SSPM_WRONG_BOUNDARY_ERROR){
237 str = "Got the wrong boundary for the opening of a MULTIPART part.";
240 if(parts[i].header.error==SSPM_NO_BOUNDARY_ERROR){
241 str = "Got a multipart header that did not specify a boundary";
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\?";
250 if(parts[i].header.error_text != 0){
252 "%s: %s",str,parts[i].header.error_text);
257 icalcomponent_add_property
259 icalproperty_vanew_xlicerror(
261 icalparameter_new_xlicerrortype(
262 ICAL_XLICERRORTYPE_MIMEPARSEERROR),
266 if(parts[i].header.major != SSPM_NO_MAJOR_TYPE &&
267 parts[i].header.major != SSPM_UNKNOWN_MAJOR_TYPE){
269 icalcomponent_add_property(comp,
270 icalproperty_new_xlicmimecontenttype((char*)
271 icalmemory_strdup(mimetype)));
275 if (parts[i].header.encoding != SSPM_NO_ENCODING){
277 icalcomponent_add_property(comp,
278 icalproperty_new_xlicmimeencoding(
279 sspm_encoding_string(parts[i].header.encoding)));
282 if (parts[i].header.filename != 0){
283 icalcomponent_add_property(comp,
284 icalproperty_new_xlicmimefilename(parts[i].header.filename));
287 if (parts[i].header.content_id != 0){
288 icalcomponent_add_property(comp,
289 icalproperty_new_xlicmimecid(parts[i].header.content_id));
292 if (parts[i].header.charset != 0){
293 icalcomponent_add_property(comp,
294 icalproperty_new_xlicmimecharset(parts[i].header.charset));
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 &&
302 icalcomponent_add_component(comp,
303 (icalcomponent*)parts[i].data);
306 } else if(parts[i].header.major == SSPM_TEXT_MAJOR_TYPE &&
307 parts[i].header.minor != SSPM_CALENDAR_MINOR_TYPE &&
310 /* Add other text components as "DESCRIPTION" properties */
312 icalcomponent_add_property(comp,
313 icalproperty_new_description(
314 (char*)icalmemory_strdup((char*)parts[i].data)));
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
324 icalcomponent_free(comp);
328 if(parts[i].level == last_level && last_level != 0){
329 icalerror_assert(parent!=0,"No parent for adding component");
331 icalcomponent_add_component(parent,comp);
333 } else if (parts[i].level == last_level && last_level == 0 &&
339 } else if (parts[i].level > last_level){
342 icalcomponent_add_component(parent,comp);
344 last_level = parts[i].level;
346 } else if (parts[i].level < last_level){
349 parent = icalcomponent_get_parent(parent);
350 icalcomponent_add_component(parent,comp);
352 last_level = parts[i].level;
358 last_level = parts[i].level;
359 assert(parts[i].data == 0);
362 sspm_free_parts(parts,NUM_PARTS);
370 int icalmime_test(char* (*get_string)(char *s, size_t size, void *d),
374 struct sspm_part *parts;
377 if ( (parts = (struct sspm_part *)
378 malloc(NUM_PARTS*sizeof(struct sspm_part)))==0) {
379 icalerror_set_errno(ICAL_NEWFAILED_ERROR);
383 memset(parts,0,sizeof(parts));
385 sspm_parse_mime(parts,
386 NUM_PARTS, /* Max parts */
387 icalmime_local_action_map, /* Actions */
389 data, /* data for get_string*/
390 0 /* First header */);
392 for(i = 0; i <NUM_PARTS && parts[i].header.major != SSPM_NO_MAJOR_TYPE ;
394 if(parts[i].header.minor == SSPM_CALENDAR_MINOR_TYPE){
396 icalcomponent_as_ical_string_r((icalcomponent*)parts[i].data);
400 sspm_write_mime(parts,NUM_PARTS,&out,"To: bob@bob.org");