aboutsummaryrefslogtreecommitdiffstats
path: root/trunk/main/minimime/mm_contenttype.c
diff options
context:
space:
mode:
Diffstat (limited to 'trunk/main/minimime/mm_contenttype.c')
-rw-r--r--trunk/main/minimime/mm_contenttype.c759
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;
+}
+
+/** @} */