/*====================================================================== FILE: icalmime.c CREATOR: eric 26 July 2000 SPDX-FileCopyrightText: 2000, Eric Busboom SPDX-License-Identifier: LGPL-2.1-only OR MPL-2.0 The Original Code is eric. The Initial Developer of the Original Code is Eric Busboom ======================================================================*/ #ifdef HAVE_CONFIG_H #include #endif #include "icalmime.h" #include "icalerror.h" #include "icalmemory.h" #include "icalparser.h" #include "sspm.h" #include #define TMP_BUF_SIZE 1024 #define TMP_ERR_SIZE 256 /* These *_part routines are called by the MIME parser via the local_action_map */ struct text_part { char *buf; char *buf_pos; size_t buf_size; }; static void *icalmime_text_new_part(void) { #define BUF_SIZE 2048 struct text_part *impl; if ((impl = (struct text_part *)icalmemory_new_buffer(sizeof(struct text_part))) == 0) { return 0; } impl->buf = icalmemory_new_buffer(BUF_SIZE); impl->buf_pos = impl->buf; impl->buf_size = BUF_SIZE; return impl; } static void icalmime_text_add_line(void *part, struct sspm_header *header, const char *line, size_t size) { struct text_part *impl = (struct text_part *)part; _unused(header); _unused(size); icalmemory_append_string(&(impl->buf), &(impl->buf_pos), &(impl->buf_size), line); } static void *icalmime_textcalendar_end_part(void *part) { struct text_part *impl = (struct text_part *)part; icalcomponent *c = icalparser_parse_string(impl->buf); icalmemory_free_buffer(impl->buf); icalmemory_free_buffer(impl); return c; } static void *icalmime_text_end_part_r(void *part) { char *buf; struct text_part *impl = (struct text_part *)part; buf = impl->buf; icalmemory_free_buffer(impl); return buf; } void *icalmime_text_end_part(void *part) { void *buf; buf = icalmime_text_end_part_r(part); icalmemory_add_tmp_buffer(buf); return buf; } static void icalmime_text_free_part(void *part) { _unused(part); } /* Ignore Attachments for now */ static void *icalmime_attachment_new_part(void) { return 0; } static void icalmime_attachment_add_line(void *part, struct sspm_header *header, const char *line, size_t size) { _unused(part); _unused(header); _unused(line); _unused(size); } static void *icalmime_attachment_end_part(void *part) { _unused(part); return 0; } static void icalmime_attachment_free_part(void *part) { _unused(part); } static const struct sspm_action_map icalmime_local_action_map[] = { {SSPM_TEXT_MAJOR_TYPE, SSPM_CALENDAR_MINOR_TYPE, icalmime_text_new_part, icalmime_text_add_line, icalmime_textcalendar_end_part, icalmime_text_free_part}, {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}, {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}, {SSPM_APPLICATION_MAJOR_TYPE, SSPM_CALENDAR_MINOR_TYPE, icalmime_attachment_new_part, icalmime_attachment_add_line, icalmime_attachment_end_part, icalmime_attachment_free_part}, {SSPM_IMAGE_MAJOR_TYPE, SSPM_CALENDAR_MINOR_TYPE, icalmime_attachment_new_part, icalmime_attachment_add_line, icalmime_attachment_end_part, icalmime_attachment_free_part}, {SSPM_AUDIO_MAJOR_TYPE, SSPM_CALENDAR_MINOR_TYPE, icalmime_attachment_new_part, icalmime_attachment_add_line, icalmime_attachment_end_part, icalmime_attachment_free_part}, {SSPM_IMAGE_MAJOR_TYPE, SSPM_CALENDAR_MINOR_TYPE, icalmime_attachment_new_part, icalmime_attachment_add_line, icalmime_attachment_end_part, icalmime_attachment_free_part}, {SSPM_UNKNOWN_MAJOR_TYPE, SSPM_UNKNOWN_MINOR_TYPE, NULL, NULL, NULL, NULL} }; #define NUM_PARTS 100 /* HACK. Hard Limit */ struct sspm_part *icalmime_make_part(icalcomponent *comp) { _unused(comp); return 0; } icalcomponent *icalmime_parse(char *(*get_string) (char *s, size_t size, void *d), void *data) { struct sspm_part *parts; int i, last_level = 0; icalcomponent *root = 0, *parent = 0, *comp = 0, *last = 0; if ((parts = (struct sspm_part *)icalmemory_new_buffer(NUM_PARTS * sizeof(struct sspm_part))) == 0) { icalerror_set_errno(ICAL_NEWFAILED_ERROR); return 0; } memset(parts, 0, NUM_PARTS * sizeof(struct sspm_part)); sspm_parse_mime(parts, NUM_PARTS, /* Max parts */ icalmime_local_action_map, /* Actions */ get_string, data, /* data for get_string */ 0/* First header */); for (i = 0; i < NUM_PARTS && parts[i].header.major != SSPM_NO_MAJOR_TYPE; i++) { char mimetype[TMP_BUF_SIZE]; const char *major = sspm_major_type_string(parts[i].header.major); const char *minor = sspm_minor_type_string(parts[i].header.minor); if (parts[i].header.minor == SSPM_UNKNOWN_MINOR_TYPE) { icalassert(parts[i].header.minor_text != 0); minor = parts[i].header.minor_text; } snprintf(mimetype, sizeof(mimetype), "%s/%s", major, minor); comp = icalcomponent_new(ICAL_XLICMIMEPART_COMPONENT); if (comp == 0) { /* HACK Handle Error */ icalassert(0); } if (parts[i].header.error != SSPM_NO_ERROR) { const char *str = "Unknown error"; char temp[TMP_ERR_SIZE]; icalparameter *errParam; if (parts[i].header.error == SSPM_MALFORMED_HEADER_ERROR) { str = "Malformed header, possibly due to input not in MIME format"; } if (parts[i].header.error == SSPM_UNEXPECTED_BOUNDARY_ERROR) { str = "Got an unexpected boundary, possibly due to a MIME header " "for a MULTIPART part that is missing the Content-Type line"; } if (parts[i].header.error == SSPM_WRONG_BOUNDARY_ERROR) { str = "Got the wrong boundary for the opening of a MULTIPART part."; } if (parts[i].header.error == SSPM_NO_BOUNDARY_ERROR) { str = "Got a multipart header that did not specify a boundary"; } if (parts[i].header.error == SSPM_NO_HEADER_ERROR) { str = "Did not get a header for the part. Is there a blank " "line between the header and the previous boundary\?"; } if (parts[i].header.error_text != 0) { snprintf(temp, TMP_ERR_SIZE, "%s: %s", str, parts[i].header.error_text); } else { strcpy(temp, str); } errParam = icalparameter_new_xlicerrortype(ICAL_XLICERRORTYPE_MIMEPARSEERROR); icalcomponent_add_property( comp, icalproperty_vanew_xlicerror(temp, errParam, (void *)0)); icalparameter_free(errParam); } if (parts[i].header.major != SSPM_NO_MAJOR_TYPE && parts[i].header.major != SSPM_UNKNOWN_MAJOR_TYPE) { char *mimeTypeCopy = icalmemory_strdup(mimetype); icalcomponent_add_property( comp, icalproperty_new_xlicmimecontenttype(mimeTypeCopy)); icalmemory_free_buffer(mimeTypeCopy); } if (parts[i].header.encoding != SSPM_NO_ENCODING) { icalcomponent_add_property( comp, icalproperty_new_xlicmimeencoding(sspm_encoding_string(parts[i].header.encoding))); } if (parts[i].header.filename != 0) { icalcomponent_add_property( comp, icalproperty_new_xlicmimefilename(parts[i].header.filename)); } if (parts[i].header.content_id != 0) { icalcomponent_add_property( comp, icalproperty_new_xlicmimecid(parts[i].header.content_id)); } if (parts[i].header.charset != 0) { icalcomponent_add_property( comp, icalproperty_new_xlicmimecharset(parts[i].header.charset)); } /* Add iCal components as children of the component */ if (parts[i].header.major == SSPM_TEXT_MAJOR_TYPE && parts[i].header.minor == SSPM_CALENDAR_MINOR_TYPE && parts[i].data != 0) { icalcomponent_add_component(comp, (icalcomponent *) parts[i].data); parts[i].data = 0; } else if (parts[i].header.major == SSPM_TEXT_MAJOR_TYPE && parts[i].header.minor != SSPM_CALENDAR_MINOR_TYPE && parts[i].data != 0) { /* Add other text components as "DESCRIPTION" properties */ char *descStr = icalmemory_strdup((char *)parts[i].data); icalcomponent_add_property( comp, icalproperty_new_description(descStr)); icalmemory_free_buffer(descStr); parts[i].data = 0; } if (root != 0 && parts[i].level == 0) { /* We've already assigned the root, but there is another part at the root level. This is probably a parse error */ icalcomponent_free(comp); continue; } if (parts[i].level == last_level && last_level != 0) { icalerror_assert(parent != 0, "No parent for adding component"); icalcomponent_add_component(parent, comp); } else if (parts[i].level == last_level && last_level == 0 && root == 0) { root = comp; parent = comp; } else if (parts[i].level > last_level) { parent = last; icalcomponent_add_component(parent, comp); } else if (parts[i].level < last_level) { if (parent) parent = icalcomponent_get_parent(parent); icalcomponent_add_component(parent, comp); } else { icalassert(0); } last = comp; last_level = parts[i].level; icalassert(parts[i].data == 0); } sspm_free_parts(parts, NUM_PARTS); icalmemory_free_buffer(parts); return root; } int icalmime_test(char *(*get_string) (char *s, size_t size, void *d), void *data) { char *out; struct sspm_part *parts; int i; if ((parts = (struct sspm_part *)icalmemory_new_buffer(NUM_PARTS * sizeof(struct sspm_part))) == 0) { icalerror_set_errno(ICAL_NEWFAILED_ERROR); return 0; } memset(parts, 0, NUM_PARTS * sizeof(struct sspm_part)); sspm_parse_mime(parts, NUM_PARTS, /* Max parts */ icalmime_local_action_map, /* Actions */ get_string, data, /* data for get_string */ 0/* First header */); for (i = 0; i < NUM_PARTS && parts[i].header.major != SSPM_NO_MAJOR_TYPE; i++) { if (parts[i].header.minor == SSPM_CALENDAR_MINOR_TYPE) { parts[i].data = icalcomponent_as_ical_string_r((icalcomponent *) parts[i].data); } } sspm_write_mime(parts, NUM_PARTS, &out, "To: bob@bob.org"); printf("%s\n", out); icalmemory_free_buffer(out); return 0; }