summaryrefslogtreecommitdiffabout
path: root/libetpan/src/low-level/mime/mailmime.c
Side-by-side diff
Diffstat (limited to 'libetpan/src/low-level/mime/mailmime.c') (more/less context) (ignore whitespace changes)
-rw-r--r--libetpan/src/low-level/mime/mailmime.c1408
1 files changed, 1408 insertions, 0 deletions
diff --git a/libetpan/src/low-level/mime/mailmime.c b/libetpan/src/low-level/mime/mailmime.c
new file mode 100644
index 0000000..4bade55
--- a/dev/null
+++ b/libetpan/src/low-level/mime/mailmime.c
@@ -0,0 +1,1408 @@
+/*
+ * libEtPan! -- a mail stuff library
+ *
+ * Copyright (C) 2001, 2005 - DINH Viet Hoa
+ * 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 libEtPan! project nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS 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 THE AUTHORS OR CONTRIBUTORS 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.
+ */
+
+/*
+ * $Id$
+ */
+
+#include "mailmime.h"
+
+/*
+ RFC 2045
+ RFC 2046
+ RFC 2047
+ RFC 2048
+ RFC 2049
+ RFC 2231
+ RFC 2387
+ RFC 2424
+ RFC 2557
+
+ RFC 2183 Content-Disposition
+
+ RFC 1766 Language
+ */
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "mailmime_types.h"
+#include "mailmime_disposition.h"
+#include "mailimf.h"
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+static int mailmime_attribute_parse(const char * message, size_t length,
+ size_t * index,
+ char ** result);
+static int
+mailmime_composite_type_parse(const char * message, size_t length,
+ size_t * index,
+ struct mailmime_composite_type ** result);
+
+static int is_text(char ch);
+
+static int
+mailmime_discrete_type_parse(const char * message, size_t length,
+ size_t * index,
+ struct mailmime_discrete_type ** result);
+
+static int mailmime_mechanism_parse(const char * message, size_t length,
+ size_t * index,
+ struct mailmime_mechanism ** result);
+
+static int mailmime_subtype_parse(const char * message, size_t length,
+ size_t * index, char ** result);
+
+static int is_token(char ch);
+
+static int mailmime_token_parse(const char * message, size_t length,
+ size_t * index,
+ char ** token);
+
+static int is_tspecials(char ch);
+
+static int mailmime_type_parse(const char * message, size_t length,
+ size_t * index,
+ struct mailmime_type ** result);
+
+/*
+int mailmime_version_parse(const char * message, guint32 length,
+ guint32 * index,
+ guint32 * result);
+*/
+
+/*
+static gboolean mailmime_x_token_parse(gconst char * message, guint32 length,
+ guint32 * index,
+ gchar ** result);
+*/
+
+/* ********************************************************************** */
+
+/*
+x attribute := token
+ ; Matching of attributes
+ ; is ALWAYS case-insensitive.
+*/
+
+static int mailmime_attribute_parse(const char * message, size_t length,
+ size_t * index,
+ char ** result)
+{
+ return mailmime_token_parse(message, length, index, result);
+}
+
+/*
+x composite-type := "message" / "multipart" / extension-token
+*/
+
+static int
+mailmime_composite_type_parse(const char * message, size_t length,
+ size_t * index,
+ struct mailmime_composite_type ** result)
+{
+ char * extension_token;
+ int type;
+ struct mailmime_composite_type * ct;
+ size_t cur_token;
+ int r;
+ int res;
+
+ cur_token = * index;
+
+ extension_token = NULL;
+
+ type = MAILMIME_COMPOSITE_TYPE_ERROR; /* XXX - removes a gcc warning */
+
+ r = mailimf_token_case_insensitive_parse(message, length,
+ &cur_token, "message");
+ if (r == MAILIMF_NO_ERROR)
+ type = MAILMIME_COMPOSITE_TYPE_MESSAGE;
+
+ if (r == MAILIMF_ERROR_PARSE) {
+ r = mailimf_token_case_insensitive_parse(message, length,
+ &cur_token, "multipart");
+ if (r == MAILIMF_NO_ERROR)
+ type = MAILMIME_COMPOSITE_TYPE_MULTIPART;
+ }
+
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ ct = mailmime_composite_type_new(type, extension_token);
+ if (ct == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free_extension;
+ }
+
+ * result = ct;
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+
+ free_extension:
+ if (extension_token != NULL)
+ mailmime_extension_token_free(extension_token);
+ err:
+ return res;
+}
+
+/*
+x content := "Content-Type" ":" type "/" subtype
+ *(";" parameter)
+ ; Matching of media type and subtype
+ ; is ALWAYS case-insensitive.
+*/
+
+int mailmime_content_parse(const char * message, size_t length,
+ size_t * index,
+ struct mailmime_content ** result)
+{
+ size_t cur_token;
+ struct mailmime_type * type;
+ char * subtype;
+ clist * parameters_list;
+ struct mailmime_content * content;
+ int r;
+ int res;
+
+ cur_token = * index;
+
+ mailimf_cfws_parse(message, length, &cur_token);
+
+ r = mailmime_type_parse(message, length, &cur_token, &type);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ r = mailimf_unstrict_char_parse(message, length, &cur_token, '/');
+ switch (r) {
+ case MAILIMF_NO_ERROR:
+ r = mailimf_cfws_parse(message, length, &cur_token);
+ if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
+ res = r;
+ goto free_type;
+ }
+
+ r = mailmime_subtype_parse(message, length, &cur_token, &subtype);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto free_type;
+ }
+ break;
+
+ case MAILIMF_ERROR_PARSE:
+ subtype = strdup("unknown");
+ break;
+
+ default:
+ res = r;
+ goto free_type;
+ }
+
+ parameters_list = clist_new();
+ if (parameters_list == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free_type;
+ }
+
+ while (1) {
+ size_t final_token;
+ struct mailmime_parameter * parameter;
+
+ final_token = cur_token;
+ r = mailimf_unstrict_char_parse(message, length, &cur_token, ';');
+ if (r != MAILIMF_NO_ERROR) {
+ cur_token = final_token;
+ break;
+ }
+
+ r = mailimf_cfws_parse(message, length, &cur_token);
+ if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
+ res = r;
+ goto free_type;
+ }
+
+ r = mailmime_parameter_parse(message, length, &cur_token, &parameter);
+ if (r == MAILIMF_NO_ERROR) {
+ /* do nothing */
+ }
+ else if (r == MAILIMF_ERROR_PARSE) {
+ cur_token = final_token;
+ break;
+ }
+ else {
+ res = r;
+ goto err;
+ }
+
+ r = clist_append(parameters_list, parameter);
+ if (r < 0) {
+ mailmime_parameter_free(parameter);
+ res = MAILIMF_ERROR_MEMORY;
+ goto free_parameters;
+ }
+ }
+
+ content = mailmime_content_new(type, subtype, parameters_list);
+ if (content == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free_parameters;
+ }
+
+ * result = content;
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+
+ free_parameters:
+ clist_foreach(parameters_list, (clist_func) mailmime_parameter_free, NULL);
+ clist_free(parameters_list);
+
+ mailmime_subtype_free(subtype);
+ free_type:
+ mailmime_type_free(type);
+ err:
+ return res;
+}
+
+/*
+x description := "Content-Description" ":" *text
+*/
+
+static int is_text(char ch)
+{
+ unsigned char uch = (unsigned char) ch;
+
+ if (uch < 1)
+ return FALSE;
+
+ if ((uch == 10) || (uch == 13))
+ return FALSE;
+
+ return TRUE;
+}
+
+int mailmime_description_parse(const char * message, size_t length,
+ size_t * index,
+ char ** result)
+{
+ return mailimf_custom_string_parse(message, length,
+ index, result,
+ is_text);
+}
+
+/*
+x discrete-type := "text" / "image" / "audio" / "video" /
+ "application" / extension-token
+*/
+
+/* currently porting */
+
+static int
+mailmime_discrete_type_parse(const char * message, size_t length,
+ size_t * index,
+ struct mailmime_discrete_type ** result)
+{
+ char * extension;
+ int type;
+ struct mailmime_discrete_type * discrete_type;
+ size_t cur_token;
+ int r;
+ int res;
+
+ cur_token = * index;
+
+ extension = NULL;
+
+ type = MAILMIME_DISCRETE_TYPE_ERROR; /* XXX - removes a gcc warning */
+
+ r = mailimf_token_case_insensitive_parse(message, length,
+ &cur_token, "text");
+ if (r == MAILIMF_NO_ERROR)
+ type = MAILMIME_DISCRETE_TYPE_TEXT;
+
+ if (r == MAILIMF_ERROR_PARSE) {
+ r = mailimf_token_case_insensitive_parse(message, length,
+ &cur_token, "image");
+ if (r == MAILIMF_NO_ERROR)
+ type = MAILMIME_DISCRETE_TYPE_IMAGE;
+ }
+
+ if (r == MAILIMF_ERROR_PARSE) {
+ r = mailimf_token_case_insensitive_parse(message, length,
+ &cur_token, "audio");
+ if (r == MAILIMF_NO_ERROR)
+ type = MAILMIME_DISCRETE_TYPE_AUDIO;
+ }
+
+ if (r == MAILIMF_ERROR_PARSE) {
+ r = mailimf_token_case_insensitive_parse(message, length,
+ &cur_token, "video");
+ if (r == MAILIMF_NO_ERROR)
+ type = MAILMIME_DISCRETE_TYPE_VIDEO;
+ }
+
+ if (r == MAILIMF_ERROR_PARSE) {
+ r = mailimf_token_case_insensitive_parse(message, length,
+ &cur_token, "application");
+ if (r == MAILIMF_NO_ERROR)
+ type = MAILMIME_DISCRETE_TYPE_APPLICATION;
+ }
+
+ if (r == MAILIMF_ERROR_PARSE) {
+ r = mailmime_extension_token_parse(message, length,
+ &cur_token, &extension);
+ if (r == MAILIMF_NO_ERROR)
+ type = MAILMIME_DISCRETE_TYPE_EXTENSION;
+ }
+
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ discrete_type = mailmime_discrete_type_new(type, extension);
+ if (discrete_type == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free;
+ }
+
+ * result = discrete_type;
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+
+ free:
+ mailmime_extension_token_free(extension);
+ err:
+ return res;
+}
+
+/*
+x encoding := "Content-Transfer-Encoding" ":" mechanism
+*/
+
+int mailmime_encoding_parse(const char * message, size_t length,
+ size_t * index,
+ struct mailmime_mechanism ** result)
+{
+ return mailmime_mechanism_parse(message, length, index, result);
+}
+
+/*
+x entity-headers := [ content CRLF ]
+ [ encoding CRLF ]
+ [ id CRLF ]
+ [ description CRLF ]
+ *( MIME-extension-field CRLF )
+ */
+
+enum {
+ FIELD_STATE_START,
+ FIELD_STATE_T,
+ FIELD_STATE_D
+};
+
+static int guess_field_type(char * name)
+{
+ int state;
+
+ if (* name == 'M')
+ return MAILMIME_FIELD_VERSION;
+
+ if (strncasecmp(name, "Content-", 8) != 0)
+ return MAILMIME_FIELD_NONE;
+
+ name += 8;
+
+ state = FIELD_STATE_START;
+
+ while (1) {
+
+ switch (state) {
+
+ case FIELD_STATE_START:
+ switch ((char) toupper((unsigned char) * name)) {
+ case 'T':
+ state = FIELD_STATE_T;
+ break;
+ case 'I':
+ return MAILMIME_FIELD_ID;
+ case 'D':
+ state = FIELD_STATE_D;
+ break;
+ case 'L':
+ return MAILMIME_FIELD_LANGUAGE;
+ default:
+ return MAILMIME_FIELD_NONE;
+ }
+ break;
+
+ case FIELD_STATE_T:
+ switch ((char) toupper((unsigned char) * name)) {
+ case 'Y':
+ return MAILMIME_FIELD_TYPE;
+ case 'R':
+ return MAILMIME_FIELD_TRANSFER_ENCODING;
+ default:
+ return MAILMIME_FIELD_NONE;
+ }
+ break;
+
+ case FIELD_STATE_D:
+ switch ((char) toupper((unsigned char) * name)) {
+ case 'E':
+ return MAILMIME_FIELD_DESCRIPTION;
+ case 'I':
+ return MAILMIME_FIELD_DISPOSITION;
+ default:
+ return MAILMIME_FIELD_NONE;
+ }
+ break;
+ }
+ name ++;
+ }
+}
+
+int
+mailmime_field_parse(struct mailimf_optional_field * field,
+ struct mailmime_field ** result)
+{
+ char * name;
+ char * value;
+ int guessed_type;
+ size_t cur_token;
+ struct mailmime_content * content;
+ struct mailmime_mechanism * encoding;
+ char * id;
+ char * description;
+ uint32_t version;
+ struct mailmime_field * mime_field;
+ struct mailmime_language * language;
+ struct mailmime_disposition * disposition;
+ int res;
+ int r;
+
+ name = field->fld_name;
+ value = field->fld_value;
+ cur_token = 0;
+
+ content = NULL;
+ encoding = NULL;
+ id = NULL;
+ description = NULL;
+ version = 0;
+ disposition = NULL;
+ language = NULL;
+
+ guessed_type = guess_field_type(name);
+
+ switch (guessed_type) {
+ case MAILMIME_FIELD_TYPE:
+ if (strcasecmp(name, "Content-Type") != 0)
+ return MAILIMF_ERROR_PARSE;
+ r = mailmime_content_parse(value, strlen(value), &cur_token, &content);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ break;
+
+ case MAILMIME_FIELD_TRANSFER_ENCODING:
+ if (strcasecmp(name, "Content-Transfer-Encoding") != 0)
+ return MAILIMF_ERROR_PARSE;
+ r = mailmime_encoding_parse(value, strlen(value), &cur_token, &encoding);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ break;
+
+ case MAILMIME_FIELD_ID:
+ if (strcasecmp(name, "Content-ID") != 0)
+ return MAILIMF_ERROR_PARSE;
+ r = mailmime_id_parse(value, strlen(value), &cur_token, &id);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ break;
+
+ case MAILMIME_FIELD_DESCRIPTION:
+ if (strcasecmp(name, "Content-Description") != 0)
+ return MAILIMF_ERROR_PARSE;
+ r = mailmime_description_parse(value, strlen(value),
+ &cur_token, &description);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ break;
+
+ case MAILMIME_FIELD_VERSION:
+ if (strcasecmp(name, "MIME-Version") != 0)
+ return MAILIMF_ERROR_PARSE;
+ r = mailmime_version_parse(value, strlen(value), &cur_token, &version);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ break;
+
+ case MAILMIME_FIELD_DISPOSITION:
+ if (strcasecmp(name, "Content-Disposition") != 0)
+ return MAILIMF_ERROR_PARSE;
+ r = mailmime_disposition_parse(value, strlen(value),
+ &cur_token, &disposition);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ break;
+
+ case MAILMIME_FIELD_LANGUAGE:
+ if (strcasecmp(name, "Content-Language") != 0)
+ return MAILIMF_ERROR_PARSE;
+ r = mailmime_language_parse(value, strlen(value), &cur_token, &language);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ break;
+
+ default:
+ return MAILIMF_ERROR_PARSE;
+ }
+
+ mime_field = mailmime_field_new(guessed_type, content, encoding,
+ id, description, version, disposition,
+ language);
+ if (mime_field == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free;
+ }
+
+ * result = mime_field;
+
+ return MAILIMF_NO_ERROR;
+
+ free:
+ if (content != NULL)
+ mailmime_content_free(content);
+ if (encoding != NULL)
+ mailmime_encoding_free(encoding);
+ if (id != NULL)
+ mailmime_id_free(id);
+ if (description != NULL)
+ mailmime_description_free(description);
+ return res;
+}
+
+/*
+x extension-token := ietf-token / x-token
+*/
+
+int
+mailmime_extension_token_parse(const char * message, size_t length,
+ size_t * index, char ** result)
+{
+ return mailmime_token_parse(message, length, index, result);
+}
+
+/*
+ hex-octet := "=" 2(DIGIT / "A" / "B" / "C" / "D" / "E" / "F")
+ ; Octet must be used for characters > 127, =,
+ ; SPACEs or TABs at the ends of lines, and is
+ ; recommended for any character not listed in
+ ; RFC 2049 as "mail-safe".
+*/
+
+/*
+x iana-token := <A publicly-defined extension token. Tokens
+ of this form must be registered with IANA
+ as specified in RFC 2048.>
+*/
+
+/*
+x ietf-token := <An extension token defined by a
+ standards-track RFC and registered
+ with IANA.>
+*/
+
+/*
+x id := "Content-ID" ":" msg-id
+*/
+
+int mailmime_id_parse(const char * message, size_t length,
+ size_t * index, char ** result)
+{
+ return mailimf_msg_id_parse(message, length, index, result);
+}
+
+/*
+x mechanism := "7bit" / "8bit" / "binary" /
+ "quoted-printable" / "base64" /
+ ietf-token / x-token
+*/
+
+static int mailmime_mechanism_parse(const char * message, size_t length,
+ size_t * index,
+ struct mailmime_mechanism ** result)
+{
+ char * token;
+ int type;
+ struct mailmime_mechanism * mechanism;
+ size_t cur_token;
+ int r;
+ int res;
+
+ cur_token = * index;
+
+ type = MAILMIME_MECHANISM_ERROR; /* XXX - removes a gcc warning */
+
+ token = NULL;
+ r = mailimf_token_case_insensitive_parse(message, length,
+ &cur_token, "7bit");
+ if (r == MAILIMF_NO_ERROR)
+ type = MAILMIME_MECHANISM_7BIT;
+
+ if (r == MAILIMF_ERROR_PARSE) {
+ r = mailimf_token_case_insensitive_parse(message, length,
+ &cur_token, "8bit");
+ if (r == MAILIMF_NO_ERROR)
+ type = MAILMIME_MECHANISM_8BIT;
+ }
+
+ if (r == MAILIMF_ERROR_PARSE) {
+ r = mailimf_token_case_insensitive_parse(message, length,
+ &cur_token, "binary");
+ if (r == MAILIMF_NO_ERROR)
+ type = MAILMIME_MECHANISM_BINARY;
+ }
+
+ if (r == MAILIMF_ERROR_PARSE) {
+ r = mailimf_token_case_insensitive_parse(message, length,
+ &cur_token, "quoted-printable");
+ if (r == MAILIMF_NO_ERROR)
+ type = MAILMIME_MECHANISM_QUOTED_PRINTABLE;
+ }
+
+ if (r == MAILIMF_ERROR_PARSE) {
+ r = mailimf_token_case_insensitive_parse(message, length,
+ &cur_token, "base64");
+ if (r == MAILIMF_NO_ERROR)
+ type = MAILMIME_MECHANISM_BASE64;
+ }
+
+ if (r == MAILIMF_ERROR_PARSE) {
+ r = mailmime_token_parse(message, length, &cur_token, &token);
+ if (r == MAILIMF_NO_ERROR)
+ type = MAILMIME_MECHANISM_TOKEN;
+ }
+
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ mechanism = mailmime_mechanism_new(type, token);
+ if (mechanism == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free;
+ }
+
+ * result = mechanism;
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+
+ free:
+ if (token != NULL)
+ mailmime_token_free(token);
+ err:
+ return res;
+}
+
+/*
+x MIME-extension-field := <Any RFC 822 header field which
+ begins with the string
+ "Content-">
+*/
+
+/*
+in headers
+
+x MIME-message-headers := entity-headers
+ fields
+ version CRLF
+ ; The ordering of the header
+ ; fields implied by this BNF
+ ; definition should be ignored.
+*/
+
+/*
+in message
+
+x MIME-part-headers := entity-headers
+ [fields]
+ ; Any field not beginning with
+ ; "content-" can have no defined
+ ; meaning and may be ignored.
+ ; The ordering of the header
+ ; fields implied by this BNF
+ ; definition should be ignored.
+*/
+
+#if 0
+int
+mailmime_unparsed_fields_parse(struct mailimf_unparsed_fields *
+ fields,
+ struct mailmime_fields **
+ result)
+{
+ clistiter * cur;
+ struct mailmime_fields * mime_fields;
+ clist * list;
+ int r;
+ int res;
+
+ list = clist_new();
+ if (list == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto err;
+ }
+
+ if (fields->list == NULL) {
+ res = MAILIMF_ERROR_PARSE;
+ goto err;
+ }
+
+ for(cur = clist_begin(fields->list) ; cur != NULL ;
+ cur = clist_next(cur)) {
+ struct mailimf_optional_field * field = cur->data;
+ struct mailmime_field * mime_field;
+
+ r = mailmime_field_parse(field, &mime_field);
+ if (r == MAILIMF_NO_ERROR) {
+ r = clist_append(list, mime_field);
+ if (r < 0) {
+ mailmime_field_free(mime_field);
+ res = MAILIMF_ERROR_MEMORY;
+ goto free_list;
+ }
+ }
+ }
+
+ if (clist_begin(list) == NULL) {
+ res = MAILIMF_ERROR_PARSE;
+ goto free_list;
+ }
+
+ mime_fields = mailmime_fields_new(list);
+ if (mime_fields == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free_list;
+ }
+
+ * result = mime_fields;
+
+ return MAILIMF_NO_ERROR;
+
+ free_list:
+ clist_foreach(list, (clist_func) mailmime_field_free, NULL);
+ clist_free(list);
+ err:
+ return res;
+}
+#endif
+
+int
+mailmime_fields_parse(struct mailimf_fields *
+ fields,
+ struct mailmime_fields **
+ result)
+{
+ clistiter * cur;
+ struct mailmime_fields * mime_fields;
+ clist * list;
+ int r;
+ int res;
+
+ list = clist_new();
+ if (list == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto err;
+ }
+
+ for(cur = clist_begin(fields->fld_list) ; cur != NULL ;
+ cur = clist_next(cur)) {
+ struct mailimf_field * field;
+ struct mailmime_field * mime_field;
+
+ field = clist_content(cur);
+
+ if (field->fld_type == MAILIMF_FIELD_OPTIONAL_FIELD) {
+ r = mailmime_field_parse(field->fld_data.fld_optional_field,
+ &mime_field);
+ if (r == MAILIMF_NO_ERROR) {
+ r = clist_append(list, mime_field);
+ if (r < 0) {
+ mailmime_field_free(mime_field);
+ res = MAILIMF_ERROR_MEMORY;
+ goto free_list;
+ }
+ }
+ else if (r == MAILIMF_ERROR_PARSE) {
+ /* do nothing */
+ }
+ else {
+ res = r;
+ goto free_list;
+ }
+ }
+ }
+
+ if (clist_begin(list) == NULL) {
+ res = MAILIMF_ERROR_PARSE;
+ goto free_list;
+ }
+
+ mime_fields = mailmime_fields_new(list);
+ if (mime_fields == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free_list;
+ }
+
+ * result = mime_fields;
+
+ return MAILIMF_NO_ERROR;
+
+ free_list:
+ clist_foreach(list, (clist_func) mailmime_field_free, NULL);
+ clist_free(list);
+ err:
+ return res;
+}
+
+/*
+x parameter := attribute "=" value
+*/
+
+int mailmime_parameter_parse(const char * message, size_t length,
+ size_t * index,
+ struct mailmime_parameter ** result)
+{
+ char * attribute;
+ char * value;
+ struct mailmime_parameter * parameter;
+ size_t cur_token;
+ int r;
+ int res;
+
+ cur_token = * index;
+
+ r = mailmime_attribute_parse(message, length, &cur_token, &attribute);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ r = mailimf_unstrict_char_parse(message, length, &cur_token, '=');
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto free_attr;
+ }
+
+ r = mailimf_cfws_parse(message, length, &cur_token);
+ if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
+ res = r;
+ goto free_attr;
+ }
+
+ r = mailmime_value_parse(message, length, &cur_token, &value);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto free_attr;
+ }
+
+ parameter = mailmime_parameter_new(attribute, value);
+ if (parameter == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free_value;
+ }
+
+ * result = parameter;
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+
+ free_value:
+ mailmime_value_free(value);
+ free_attr:
+ mailmime_attribute_free(attribute);
+ err:
+ return res;
+}
+
+/*
+ ptext := hex-octet / safe-char
+*/
+
+/*
+ qp-line := *(qp-segment transport-padding CRLF)
+ qp-part transport-padding
+*/
+
+/*
+ qp-part := qp-section
+ ; Maximum length of 76 characters
+*/
+
+/*
+ qp-section := [*(ptext / SPACE / TAB) ptext]
+*/
+
+/*
+ qp-segment := qp-section *(SPACE / TAB) "="
+ ; Maximum length of 76 characters
+*/
+
+/*
+ quoted-printable := qp-line *(CRLF qp-line)
+*/
+
+/*
+ safe-char := <any octet with decimal value of 33 through
+ 60 inclusive, and 62 through 126>
+ ; Characters not listed as "mail-safe" in
+ ; RFC 2049 are also not recommended.
+*/
+
+/*
+x subtype := extension-token / iana-token
+*/
+
+static int mailmime_subtype_parse(const char * message, size_t length,
+ size_t * index, char ** result)
+{
+ return mailmime_extension_token_parse(message, length, index, result);
+}
+
+/*
+x token := 1*<any (US-ASCII) CHAR except SPACE, CTLs,
+ or tspecials>
+*/
+
+static int is_token(char ch)
+{
+ unsigned char uch = (unsigned char) ch;
+
+ if (uch > 0x7F)
+ return FALSE;
+
+ if (uch == ' ')
+ return FALSE;
+
+ if (is_tspecials(ch))
+ return FALSE;
+
+ return TRUE;
+}
+
+
+static int mailmime_token_parse(const char * message, size_t length,
+ size_t * index,
+ char ** token)
+{
+ return mailimf_custom_string_parse(message, length,
+ index, token,
+ is_token);
+}
+
+/*
+ transport-padding := *LWSP-char
+ ; Composers MUST NOT generate
+ ; non-zero length transport
+ ; padding, but receivers MUST
+ ; be able to handle padding
+ ; added by message transports.
+*/
+
+/*
+enum {
+ LWSP_1,
+ LWSP_2,
+ LWSP_3,
+ LWSP_4,
+ LWSP_OK
+};
+
+gboolean mailmime_transport_padding_parse(gconst char * message, guint32 length,
+ guint32 * index)
+{
+ guint32 cur_token;
+ gint state;
+ guint32 last_valid_pos;
+
+ cur_token = * index;
+
+ if (cur_token >= length)
+ return FALSE;
+
+ state = LWSP_1;
+
+ while (state != LWSP_OUT) {
+
+ if (cur_token >= length)
+ return FALSE;
+
+ switch (state) {
+ case LWSP_1:
+ last_valid_pos = cur_token;
+
+ switch (message[cur_token]) {
+ case '\r':
+ state = LWSP_2;
+ break;
+ case '\n':
+ state = LWSP_3;
+ break;
+ case ' ':
+ case '\t':
+ state = LWSP_4;
+ break;
+ default:
+ state = LWSP_OK;
+ break;
+ }
+ case LWSP_2:
+ switch (message[cur_token]) {
+ case '\n':
+ state = LWSP_3;
+ break;
+ default:
+ state = LWSP_OUT;
+ cur_token = last_valid_pos;
+ break;
+ }
+ case LWSP_3:
+ switch (message[cur_token]) {
+ case ' ':
+ case '\t':
+ state = LWSP_1;
+ break;
+ default:
+ state = LWSP_OUT;
+ cur_token = last_valid_pos;
+ break;
+ }
+
+ cur_token ++;
+ }
+ }
+
+ * index = cur_token;
+
+ return TRUE;
+}
+*/
+
+/*
+x tspecials := "(" / ")" / "<" / ">" / "@" /
+ "," / ";" / ":" / "\" / <">
+ "/" / "[" / "]" / "?" / "="
+ ; Must be in quoted-string,
+ ; to use within parameter values
+*/
+
+static int is_tspecials(char ch)
+{
+ switch (ch) {
+ case '(':
+ case ')':
+ case '<':
+ case '>':
+ case '@':
+ case ',':
+ case ';':
+ case ':':
+ case '\\':
+ case '\"':
+ case '/':
+ case '[':
+ case ']':
+ case '?':
+ case '=':
+ return TRUE;
+ default:
+ return FALSE;
+ }
+}
+
+/*
+x type := discrete-type / composite-type
+*/
+
+static int mailmime_type_parse(const char * message, size_t length,
+ size_t * index,
+ struct mailmime_type ** result)
+{
+ struct mailmime_discrete_type * discrete_type;
+ struct mailmime_composite_type * composite_type;
+ size_t cur_token;
+ struct mailmime_type * mime_type;
+ int type;
+ int res;
+ int r;
+
+ cur_token = * index;
+
+ discrete_type = NULL;
+ composite_type = NULL;
+
+ type = MAILMIME_TYPE_ERROR; /* XXX - removes a gcc warning */
+
+ r = mailmime_composite_type_parse(message, length, &cur_token,
+ &composite_type);
+ if (r == MAILIMF_NO_ERROR)
+ type = MAILMIME_TYPE_COMPOSITE_TYPE;
+
+ if (r == MAILIMF_ERROR_PARSE) {
+ r = mailmime_discrete_type_parse(message, length, &cur_token,
+ &discrete_type);
+ if (r == MAILIMF_NO_ERROR)
+ type = MAILMIME_TYPE_DISCRETE_TYPE;
+ }
+
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ mime_type = mailmime_type_new(type, discrete_type, composite_type);
+ if (mime_type == NULL) {
+ res = r;
+ goto free;
+ }
+
+ * result = mime_type;
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+
+ free:
+ if (discrete_type != NULL)
+ mailmime_discrete_type_free(discrete_type);
+ if (composite_type != NULL)
+ mailmime_composite_type_free(composite_type);
+ err:
+ return res;
+}
+
+/*
+x value := token / quoted-string
+*/
+
+int mailmime_value_parse(const char * message, size_t length,
+ size_t * index, char ** result)
+{
+ int r;
+
+ r = mailmime_token_parse(message, length, index, result);
+
+ if (r == MAILIMF_ERROR_PARSE)
+ r = mailimf_quoted_string_parse(message, length, index, result);
+
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ return MAILIMF_NO_ERROR;
+}
+
+/*
+x version := "MIME-Version" ":" 1*DIGIT "." 1*DIGIT
+*/
+
+int mailmime_version_parse(const char * message, size_t length,
+ size_t * index,
+ uint32_t * result)
+{
+ size_t cur_token;
+ uint32_t hi;
+ uint32_t low;
+ uint32_t version;
+ int r;
+
+ cur_token = * index;
+
+ r = mailimf_number_parse(message, length, &cur_token, &hi);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_unstrict_char_parse(message, length, &cur_token, '.');
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_cfws_parse(message, length, &cur_token);
+ if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE))
+ return r;
+
+ r = mailimf_number_parse(message, length, &cur_token, &low);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ version = (hi << 16) + low;
+
+ * result = version;
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+}
+
+/*
+x x-token := <The two characters "X-" or "x-" followed, with
+ no intervening white space, by any token>
+*/
+
+/*
+static gboolean mailmime_x_token_parse(gconst char * message, guint32 length,
+ guint32 * index,
+ gchar ** result)
+{
+ guint32 cur_token;
+ gchar * token;
+ gchar * x_token;
+ gboolean min_x;
+
+ cur_token = * index;
+
+ if (!mailimf_char_parse(message, length, &cur_token, 'x')) {
+ if (!mailimf_char_parse(message, length, &cur_token, 'X'))
+ return FALSE;
+ min_x = FALSE;
+ }
+ else
+ min_x = TRUE;
+
+ if (!mailimf_char_parse(message, length, &cur_token, '-'))
+ return FALSE;
+
+ if (!mailmime_token_parse(message, length, &cur_token, &token))
+ return FALSE;
+
+ if (min_x)
+ x_token = g_strconcat("x-", token, NULL);
+ else
+ x_token = g_strconcat("X-", token, NULL);
+ mailmime_token_free(token);
+
+ if (x_token == NULL)
+ return FALSE;
+
+ * result = x_token;
+ * index = cur_token;
+
+ return TRUE;
+}
+*/
+
+
+int mailmime_language_parse(const char * message, size_t length,
+ size_t * index,
+ struct mailmime_language ** result)
+{
+ size_t cur_token;
+ int r;
+ int res;
+ clist * list;
+ int first;
+ struct mailmime_language * language;
+
+ cur_token = * index;
+
+ list = clist_new();
+ if (list == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto err;
+ }
+
+ first = TRUE;
+
+ while (1) {
+ char * atom;
+
+ r = mailimf_unstrict_char_parse(message, length, &cur_token, ',');
+ if (r == MAILIMF_NO_ERROR) {
+ /* do nothing */
+ }
+ else if (r == MAILIMF_ERROR_PARSE) {
+ break;
+ }
+ else {
+ res = r;
+ goto err;
+ }
+
+ r = mailimf_atom_parse(message, length, &cur_token, &atom);
+ if (r == MAILIMF_NO_ERROR) {
+ /* do nothing */
+ }
+ else if (r == MAILIMF_ERROR_PARSE) {
+ break;
+ }
+ else {
+ res = r;
+ goto err;
+ }
+
+ r = clist_append(list, atom);
+ if (r < 0) {
+ mailimf_atom_free(atom);
+ res = MAILIMF_ERROR_MEMORY;
+ goto free;
+ }
+ }
+
+ language = mailmime_language_new(list);
+ if (language == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free;
+ }
+
+ * result = language;
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+
+ free:
+ clist_foreach(list, (clist_func) mailimf_atom_free, NULL);
+ clist_free(list);
+ err:
+ return res;
+}