diff options
Diffstat (limited to 'trunk/main/minimime/mm_contenttype.c')
-rw-r--r-- | trunk/main/minimime/mm_contenttype.c | 759 |
1 files changed, 759 insertions, 0 deletions
diff --git a/trunk/main/minimime/mm_contenttype.c b/trunk/main/minimime/mm_contenttype.c new file mode 100644 index 000000000..27fbc0c12 --- /dev/null +++ b/trunk/main/minimime/mm_contenttype.c @@ -0,0 +1,759 @@ +/* + * $Id$ + * + * MiniMIME - a library for handling MIME messages + * + * Copyright (C) 2003 Jann Fischer <rezine@mistrust.net> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the author nor the names of the contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY JANN FISCHER AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL JANN FISCHER OR THE VOICES IN HIS HEAD + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <ctype.h> +#include <assert.h> + +#include "mm_internal.h" +#include "mm_util.h" + +/* This file is documented using Doxygen */ + +/** + * @file mm_contenttype.c + * + * This module contains functions for manipulating Content-Type objects. + */ + +/** @defgroup contenttype Accessing and manipulating Content-Type objects */ + +struct mm_encoding_mappings { + const char *idstring; + int type; +}; + +static struct mm_encoding_mappings mm_content_enctypes[] = { + { "Base64", MM_ENCODING_BASE64 }, + { "Quoted-Printable", MM_ENCODING_QUOTEDPRINTABLE }, + { NULL, - 1}, +}; + +static const char *mm_composite_maintypes[] = { + "multipart", + "message", + NULL, +}; + +static const char *mm_composite_encodings[] = { + "7bit", + "8bit", + "binary", + NULL, +}; + +/** @{ + * @name Functions for manipulating Content objects + */ + +/** + * Creates a new object to hold a Content representation. + * The allocated memory must later be freed using mm_content_free() + * + * @return An object representing a MIME Content-Type + * @see mm_content_free + * @ingroup contenttype + */ +struct mm_content * +mm_content_new(void) +{ + struct mm_content *ct; + + ct = (struct mm_content *)xmalloc(sizeof(struct mm_content)); + + ct->maintype = NULL; + ct->subtype = NULL; + + TAILQ_INIT(&ct->type_params); + TAILQ_INIT(&ct->disposition_params); + + ct->encoding = MM_ENCODING_NONE; + ct->encstring = NULL; + + return ct; +} + +/** + * Releases all memory associated with an Content object + * + * @param ct A Content-Type object + * @return Nothing + * @ingroup contenttype + */ +void +mm_content_free(struct mm_content *ct) +{ + struct mm_param *param; + + assert(ct != NULL); + + if (ct->maintype != NULL) { + xfree(ct->maintype); + ct->maintype = NULL; + } + if (ct->subtype != NULL) { + xfree(ct->subtype); + ct->subtype = NULL; + } + if (ct->encstring != NULL) { + xfree(ct->encstring); + ct->encstring = NULL; + } + + TAILQ_FOREACH(param, &ct->type_params, next) { + TAILQ_REMOVE(&ct->type_params, param, next); + mm_param_free(param); + } + TAILQ_FOREACH(param, &ct->disposition_params, next) { + TAILQ_REMOVE(&ct->disposition_params, param, next); + mm_param_free(param); + } + + xfree(ct); +} + +/** + * Attaches a content-type parameter to a Content object + * + * @param ct The target Content object + * @param param The Content-Type parameter which to attach + * @return 0 on success and -1 on failure + * @ingroup contenttype + */ +int +mm_content_attachtypeparam(struct mm_content *ct, struct mm_param *param) +{ + assert(ct != NULL); + assert(param != NULL); + + if (TAILQ_EMPTY(&ct->type_params)) { + TAILQ_INSERT_HEAD(&ct->type_params, param, next); + } else { + TAILQ_INSERT_TAIL(&ct->type_params, param, next); + } + + return 0; +} + + +/** + * Attaches a content-disposition parameter to a Content-Disposition object + * + * @param ct The target Content object + * @param param The Content-Type parameter which to attach + * @return 0 on success and -1 on failure + * @ingroup contenttype + */ +int +mm_content_attachdispositionparam(struct mm_content *ct, struct mm_param *param) +{ + assert(ct != NULL); + assert(param != NULL); + + if (TAILQ_EMPTY(&ct->disposition_params)) { + TAILQ_INSERT_HEAD(&ct->disposition_params, param, next); + } else { + TAILQ_INSERT_TAIL(&ct->disposition_params, param, next); + } + + return 0; +} + + +/** + * Gets a Content-Type parameter value from a Content object. + * + * @param ct the Content object + * @param name the name of the parameter to retrieve + * @return The value of the parameter on success or a NULL pointer on failure + * @ingroup contenttype + */ +char * +mm_content_gettypeparambyname(struct mm_content *ct, const char *name) +{ + struct mm_param *param; + + assert(ct != NULL); + + TAILQ_FOREACH(param, &ct->type_params, next) { + if (!strcasecmp(param->name, name)) { + return param->value; + } + } + + return NULL; +} + +/** + * Gets a Content-Disposition parameter value from a Content object. + * + * @param ct the Content object + * @param name the name of the parameter to retrieve + * @return The value of the parameter on success or a NULL pointer on failure + * @ingroup contenttype + */ +char * +mm_content_getdispositionparambyname(struct mm_content *ct, const char *name) +{ + struct mm_param *param; + + assert(ct != NULL); + + TAILQ_FOREACH(param, &ct->disposition_params, next) { + if (!strcasecmp(param->name, name)) { + return param->value; + } + } + + return NULL; +} + +struct mm_param * +mm_content_gettypeparamobjbyname(struct mm_content *ct, const char *name) +{ + struct mm_param *param; + + assert(ct != NULL); + + TAILQ_FOREACH(param, &ct->type_params, next) { + if (!strcasecmp(param->name, name)) { + return param; + } + } + + return NULL; +} + +struct mm_param * +mm_content_getdispositionparamobjbyname(struct mm_content *ct, const char *name) +{ + struct mm_param *param; + + assert(ct != NULL); + + TAILQ_FOREACH(param, &ct->disposition_params, next) { + if (!strcasecmp(param->name, name)) { + return param; + } + } + + return NULL; +} + +/** + * Sets the MIME main Content-Type for a MIME Content object + * + * @param ct The MIME Content object + * @param value The value which to set the main type to + * @param copy Whether to make a copy of the value (original value must be + * freed afterwards to prevent memory leaks). + */ +int +mm_content_setmaintype(struct mm_content *ct, char *value, int copy) +{ + assert(ct != NULL); + assert(value != NULL); + + if (copy) { + /** + * @bug The xfree() call could lead to undesirable results. + * Do we really need it? + */ + if (ct->maintype != NULL) { + xfree(ct->maintype); + } + ct->maintype = xstrdup(value); + } else { + ct->maintype = value; + } + + return 0; +} + +/** + * Retrieves the main MIME Content-Type stored in a Content object + * + * @param ct A valid Content object + * @returns A pointer to the string representing the main type + * @ingroup contenttype + */ +char * +mm_content_getmaintype(struct mm_content *ct) +{ + assert(ct != NULL); + assert(ct->maintype != NULL); + + return ct->maintype; +} + +/** + * Sets the MIME Content-Disposition type for a MIME Content object + * + * @param ct The MIME Content object + * @param value The value which to set the main type to + * @param copy Whether to make a copy of the value (original value must be + * freed afterwards to prevent memory leaks). + */ +int +mm_content_setdispositiontype(struct mm_content *ct, char *value, int copy) +{ + assert(ct != NULL); + assert(value != NULL); + + if (copy) { + /** + * @bug The xfree() call could lead to undesirable results. + * Do we really need it? + */ + if (ct->disposition_type != NULL) { + xfree(ct->disposition_type); + } + ct->disposition_type = xstrdup(value); + } else { + ct->disposition_type = value; + } + + return 0; +} + +/** + * Retrieves the Content-Disposition MIME type stored in a Content object + * + * @param ct A valid Content-Type object + * @returns A pointer to the string representing the main type + * @ingroup contenttype + */ +char * +mm_content_getdispositiontype(struct mm_content *ct) +{ + assert(ct != NULL); + assert(ct->disposition_type != NULL); + + return ct->disposition_type; +} + +/** + * Retrieves the sub MIME Content-Type stored in a Content object + * + * @param ct A valid Content-Type object + * @return A pointer to the string holding the current sub MIME type + * @ingroup contenttype + */ +char * +mm_content_getsubtype(struct mm_content *ct) +{ + assert(ct != NULL); + assert(ct->subtype != NULL); + + return ct->subtype; +} + +/** + * Sets the MIME sub Content-Type for a MIME Content object + * + * @param ct The MIME Content-Type object + * @param value The value which to set the sub type to + * @param copy Whether to make a copy of the value (original value must be + * freed afterwards to prevent memory leaks). + */ +int +mm_content_setsubtype(struct mm_content *ct, char *value, int copy) +{ + assert(ct != NULL); + assert(value != NULL); + + if (copy) { + /** + * @bug The xfree() call could lead to undesirable results. + * Do we really need it? + */ + if (ct->subtype != NULL) { + xfree(ct->subtype); + } + ct->subtype = xstrdup(value); + } else { + ct->subtype = value; + } + + return 0; +} + +int +mm_content_settype(struct mm_content *ct, const char *fmt, ...) +{ + char *maint, *subt; + char buf[512], *parse; + va_list ap; + + mm_errno = MM_ERROR_NONE; + + va_start(ap, fmt); + /* Make sure no truncation occurs */ + if (vsnprintf(buf, sizeof buf, fmt, ap) > sizeof buf) { + mm_errno = MM_ERROR_ERRNO; + mm_error_setmsg("Input string too long"); + return -1; + } + va_end(ap); + + parse = buf; + maint = strsep(&parse, "/"); + if (maint == NULL) { + mm_errno = MM_ERROR_PARSE; + mm_error_setmsg("Invalid type specifier: %s", buf); + return -1; + } + ct->maintype = xstrdup(maint); + + subt = strsep(&parse, ""); + if (subt == NULL) { + mm_errno = MM_ERROR_PARSE; + mm_error_setmsg("Invalid type specifier: %s", buf); + return -1; + } + ct->subtype = xstrdup(subt); + + return 0; +} + +/** + * Checks whether the Content-Type represents a composite message or not + * + * @param ct A valid Content-Type object + * @returns 1 if the Content-Type object represents a composite message or + * 0 if not. + */ +int +mm_content_iscomposite(struct mm_content *ct) +{ + int i; + + for (i = 0; mm_composite_maintypes[i] != NULL; i++) { + if (!strcasecmp(ct->maintype, mm_composite_maintypes[i])) { + return 1; + } + } + + /* Not found */ + return 0; +} + +/** + * Verifies whether a string represents a valid encoding or not. + * + * @param encoding The string to verify + * @return 1 if the encoding string is valid or 0 if not + * + */ +int +mm_content_isvalidencoding(const char *encoding) +{ + int i; + + for (i = 0; mm_composite_encodings[i] != NULL; i++) { + if (!strcasecmp(encoding, mm_composite_encodings[i])) { + return 1; + } + } + + /* Not found */ + return 0; +} + +/** + * Set the encoding of a MIME entitity according to a mapping table + * + * @param ct A valid content type object + * @param encoding A string representing the content encoding + * @return 0 if successfull or -1 if not (i.e. unknown content encoding) + */ +int +mm_content_setencoding(struct mm_content *ct, const char *encoding) +{ + int i; + + assert(ct != NULL); + assert(encoding != NULL); + + for (i = 0; mm_content_enctypes[i].idstring != NULL; i++) { + if (!strcasecmp(mm_content_enctypes[i].idstring, encoding)) { + ct->encoding = mm_content_enctypes[i].type; + ct->encstring = xstrdup(encoding); + return 0; + } + } + + /* If we didn't find a mapping, set the encoding to unknown */ + ct->encoding = MM_ENCODING_UNKNOWN; + ct->encstring = NULL; + return 1; +} + +/** + * Gets the numerical ID of a content encoding identifier + * + * @param ct A valid Content Type object + * @param encoding A string representing the content encoding identifier + * @return The numerical ID of the content encoding + */ +#if 0 +int +mm_content_getencoding(struct mm_content *ct, const char *encoding) +{ + int i; + + assert(ct != NULL); + + for (i = 0; mm_content_enctypes[i].idstring != NULL; i++) { + if (!strcasecmp(mm_content_enctypes[i].idstring, encoding)) { + return mm_content_enctypes[i].type; + } + } + + /* Not found */ + return MM_ENCODING_UNKNOWN; +} +#endif + +/** + * Constructs a MIME conform string of Content-Type parameters. + * + * @param ct A valid Content Type object + * @return A pointer to a string representing the Content-Type parameters + * in MIME terminology, or NULL if either the Content-Type object + * is invalid, has no parameters or no memory could be allocated. + * + * This function constructs a MIME conform string including all the parameters + * associated with the given Content-Type object. It should NOT be used if + * you need an opaque copy of the current MIME part (e.g. for PGP purposes). + */ +char * +mm_content_typeparamstostring(struct mm_content *ct) +{ + size_t size, new_size; + struct mm_param *param; + char *param_string, *cur_param; + char *buf; + + size = 1; + param_string = NULL; + cur_param = NULL; + + param_string = (char *) xmalloc(size); + *param_string = '\0'; + + /* Concatenate all Content-Type parameters attached to the current + * Content-Type object to a single string. + */ + TAILQ_FOREACH(param, &ct->type_params, next) { + if (asprintf(&cur_param, "; %s=\"%s\"", param->name, + param->value) == -1) { + goto cleanup; + } + + new_size = size + strlen(cur_param) + 1; + + if (new_size < 0 || new_size > 1000) { + size = 0; + goto cleanup; + } + + buf = (char *) xrealloc(param_string, new_size); + if (buf == NULL) { + size = 0; + goto cleanup; + } + + param_string = buf; + size = new_size; + strlcat(param_string, cur_param, size); + + xfree(cur_param); + cur_param = NULL; + } + + return param_string; + +cleanup: + if (param_string != NULL) { + xfree(param_string); + param_string = NULL; + } + if (cur_param != NULL) { + xfree(cur_param); + cur_param = NULL; + } + return NULL; +} + +/** + * Constructs a MIME conformant string of Content-Disposition parameters. + * + * @param ct A valid Content object + * @return A pointer to a string representing the Content-Disposition parameters + * in MIME terminology, or NULL if either the Content object + * is invalid, has no Disposition parameters or no memory could be allocated. + * + * This function constructs a MIME conforming string including all the parameters + * associated with the given Content-Disposition object. It should NOT be used if + * you need an opaque copy of the current MIME part (e.g. for PGP purposes). + */ +char * +mm_content_dispositionparamstostring(struct mm_content *ct) +{ + size_t size, new_size; + struct mm_param *param; + char *param_string, *cur_param; + char *buf; + + size = 1; + param_string = NULL; + cur_param = NULL; + + param_string = (char *) xmalloc(size); + *param_string = '\0'; + + /* Concatenate all Content-Disposition parameters attached to the current + * Content object to a single string. + */ + TAILQ_FOREACH(param, &ct->disposition_params, next) { + if (asprintf(&cur_param, "; %s=\"%s\"", param->name, + param->value) == -1) { + goto cleanup; + } + + new_size = size + strlen(cur_param) + 1; + + if (new_size < 0 || new_size > 1000) { + size = 0; + goto cleanup; + } + + buf = (char *) xrealloc(param_string, new_size); + if (buf == NULL) { + size = 0; + goto cleanup; + } + + param_string = buf; + size = new_size; + strlcat(param_string, cur_param, size); + + xfree(cur_param); + cur_param = NULL; + } + + return param_string; + +cleanup: + if (param_string != NULL) { + xfree(param_string); + param_string = NULL; + } + if (cur_param != NULL) { + xfree(cur_param); + cur_param = NULL; + } + return NULL; +} + +/** + * Creates a Content-Type header according to the object given + * + * @param ct A valid Content-Type object + * + */ +char * +mm_content_tostring(struct mm_content *ct) +{ + char *paramstring; + char *buf; + char *headerstring; + size_t size; + + paramstring = NULL; + headerstring = NULL; + buf = NULL; + + if (ct == NULL) { + return NULL; + } + if (ct->maintype == NULL || ct->subtype == NULL) { + return NULL; + } + + size = strlen(ct->maintype) + strlen(ct->subtype) + 2; + headerstring = (char *)xmalloc(size); + snprintf(headerstring, size, "%s/%s", ct->maintype, ct->subtype); + + paramstring = mm_content_typeparamstostring(ct); + if (paramstring == NULL) { + goto cleanup; + } + + size += strlen(paramstring) + strlen("Content-Type: ") + 1; + buf = (char *)malloc(size); + if (buf == NULL) { + goto cleanup; + } + + snprintf(buf, size, "Content-Type: %s%s", headerstring, paramstring); + + xfree(headerstring); + xfree(paramstring); + + headerstring = NULL; + paramstring = NULL; + + return buf; + +cleanup: + if (paramstring != NULL) { + xfree(paramstring); + paramstring = NULL; + } + if (headerstring != NULL) { + xfree(headerstring); + headerstring = NULL; + } + if (buf != NULL) { + xfree(buf); + buf = NULL; + } + return NULL; +} + +/** @} */ |