summaryrefslogtreecommitdiffabout
path: root/libetpan/src/low-level/mime/mailmime_content.c
Side-by-side diff
Diffstat (limited to 'libetpan/src/low-level/mime/mailmime_content.c') (more/less context) (ignore whitespace changes)
-rw-r--r--libetpan/src/low-level/mime/mailmime_content.c2381
1 files changed, 2381 insertions, 0 deletions
diff --git a/libetpan/src/low-level/mime/mailmime_content.c b/libetpan/src/low-level/mime/mailmime_content.c
new file mode 100644
index 0000000..6a10dfb
--- a/dev/null
+++ b/libetpan/src/low-level/mime/mailmime_content.c
@@ -0,0 +1,2381 @@
+/*
+ * 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 "mailimf.h"
+
+#include <string.h>
+#include <stdlib.h>
+
+#include "mailmime.h"
+#include "mailmime_types.h"
+#include "mmapstring.h"
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+/*
+ RFC 2045
+ RFC 2046
+ RFC 2047
+
+ RFC 2231
+*/
+
+
+static int mailmime_parse_with_default(const char * message, size_t length,
+ size_t * index, int default_type,
+ struct mailmime_content * content_type,
+ struct mailmime_fields * mime_fields,
+ struct mailmime ** result);
+
+
+
+char * mailmime_content_charset_get(struct mailmime_content * content)
+{
+ char * charset;
+
+ charset = mailmime_content_param_get(content, "charset");
+ if (charset == NULL)
+ return "us-ascii";
+ else
+ return charset;
+}
+
+char * mailmime_content_param_get(struct mailmime_content * content,
+ char * name)
+{
+ clistiter * cur;
+
+ for(cur = clist_begin(content->ct_parameters) ;
+ cur != NULL ; cur = clist_next(cur)) {
+ struct mailmime_parameter * param;
+
+ param = clist_content(cur);
+
+ if (strcasecmp(param->pa_name, name) == 0)
+ return param->pa_value;
+ }
+
+ return NULL;
+}
+
+
+/*
+ boundary := 0*69<bchars> bcharsnospace
+*/
+
+/*
+ bchars := bcharsnospace / " "
+*/
+
+/*
+ bcharsnospace := DIGIT / ALPHA / "'" / "(" / ")" /
+ "+" / "_" / "," / "-" / "." /
+ "/" / ":" / "=" / "?"
+*/
+
+/*
+ body-part := <"message" as defined in RFC 822, with all
+ header fields optional, not starting with the
+ specified dash-boundary, and with the
+ delimiter not occurring anywhere in the
+ body part. Note that the semantics of a
+ part differ from the semantics of a message,
+ as described in the text.>
+*/
+
+/*
+ close-delimiter := delimiter "--"
+*/
+
+/*
+ dash-boundary := "--" boundary
+ ; boundary taken from the value of
+ ; boundary parameter of the
+ ; Content-Type field.
+*/
+
+/*
+ delimiter := CRLF dash-boundary
+*/
+
+/*
+ discard-text := *(*text CRLF)
+ ; May be ignored or discarded.
+*/
+
+/*
+ encapsulation := delimiter transport-padding
+ CRLF body-part
+*/
+
+/*
+ epilogue := discard-text
+*/
+
+/*
+ multipart-body := [preamble CRLF]
+ dash-boundary transport-padding CRLF
+ body-part *encapsulation
+ close-delimiter transport-padding
+ [CRLF epilogue]
+*/
+
+/*
+ preamble := discard-text
+*/
+
+/*
+ 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.
+*/
+
+
+/*
+ ACCESS-TYPE
+ EXPIRATION
+ SIZE
+ PERMISSION
+*/
+
+/*
+ 5.2.3.2. The 'ftp' and 'tftp' Access-Types
+ NAME
+ SITE
+
+ (3) Before any data are retrieved, using FTP, the user will
+ generally need to be asked to provide a login id and a
+ password for the machine named by the site parameter.
+ For security reasons, such an id and password are not
+ specified as content-type parameters, but must be
+ obtained from the user.
+
+ optional :
+ DIRECTORY
+ MODE
+*/
+
+/*
+5.2.3.3. The 'anon-ftp' Access-Type
+*/
+
+/*
+5.2.3.4. The 'local-file' Access-Type
+NAME
+SITE
+*/
+
+/*
+5.2.3.5. The 'mail-server' Access-Type
+SERVER
+SUBJECT
+*/
+
+
+enum {
+ PREAMBLE_STATE_A0,
+ PREAMBLE_STATE_A,
+ PREAMBLE_STATE_A1,
+ PREAMBLE_STATE_B,
+ PREAMBLE_STATE_C,
+ PREAMBLE_STATE_D,
+ PREAMBLE_STATE_E
+};
+
+static int mailmime_preamble_parse(const char * message, size_t length,
+ size_t * index, int beol)
+{
+ int state;
+ size_t cur_token;
+
+ cur_token = * index;
+ if (beol)
+ state = PREAMBLE_STATE_A0;
+ else
+ state = PREAMBLE_STATE_A;
+
+ while (state != PREAMBLE_STATE_E) {
+
+ if (cur_token >= length)
+ return MAILIMF_ERROR_PARSE;
+
+ switch (state) {
+ case PREAMBLE_STATE_A0:
+ switch (message[cur_token]) {
+ case '-':
+ state = PREAMBLE_STATE_A1;
+ break;
+ case '\r':
+ state = PREAMBLE_STATE_B;
+ break;
+ case '\n':
+ state = PREAMBLE_STATE_C;
+ break;
+ default:
+ state = PREAMBLE_STATE_A;
+ break;
+ }
+ break;
+
+ case PREAMBLE_STATE_A:
+ switch (message[cur_token]) {
+ case '\r':
+ state = PREAMBLE_STATE_B;
+ break;
+ case '\n':
+ state = PREAMBLE_STATE_C;
+ break;
+ default:
+ state = PREAMBLE_STATE_A;
+ break;
+ }
+ break;
+
+ case PREAMBLE_STATE_A1:
+ switch (message[cur_token]) {
+ case '-':
+ state = PREAMBLE_STATE_E;
+ break;
+ case '\r':
+ state = PREAMBLE_STATE_B;
+ break;
+ case '\n':
+ state = PREAMBLE_STATE_C;
+ break;
+ default:
+ state = PREAMBLE_STATE_A;
+ break;
+ }
+ break;
+
+ case PREAMBLE_STATE_B:
+ switch (message[cur_token]) {
+ case '\r':
+ state = PREAMBLE_STATE_B;
+ break;
+ case '\n':
+ state = PREAMBLE_STATE_C;
+ break;
+ case '-':
+ state = PREAMBLE_STATE_D;
+ break;
+ default:
+ state = PREAMBLE_STATE_A0;
+ break;
+ }
+ break;
+
+ case PREAMBLE_STATE_C:
+ switch (message[cur_token]) {
+ case '-':
+ state = PREAMBLE_STATE_D;
+ break;
+ case '\r':
+ state = PREAMBLE_STATE_B;
+ break;
+ case '\n':
+ state = PREAMBLE_STATE_C;
+ break;
+ default:
+ state = PREAMBLE_STATE_A0;
+ break;
+ }
+ break;
+
+ case PREAMBLE_STATE_D:
+ switch (message[cur_token]) {
+ case '-':
+ state = PREAMBLE_STATE_E;
+ break;
+ default:
+ state = PREAMBLE_STATE_A;
+ break;
+ }
+ break;
+ }
+
+ cur_token ++;
+ }
+
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+}
+
+static int mailmime_boundary_parse(const char * message, size_t length,
+ size_t * index, char * boundary)
+{
+ size_t cur_token;
+ size_t len;
+
+ cur_token = * index;
+
+ len = strlen(boundary);
+
+ if (cur_token + len >= length)
+ return MAILIMF_ERROR_PARSE;
+
+ if (strncmp(message + cur_token, boundary, len) != 0)
+ return MAILIMF_ERROR_PARSE;
+
+ cur_token += len;
+
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+}
+
+static int is_wsp(char ch)
+{
+ if ((ch == ' ') || (ch == '\t'))
+ return TRUE;
+
+ return FALSE;
+}
+
+static int mailmime_lwsp_parse(const char * message, size_t length,
+ size_t * index)
+{
+ size_t cur_token;
+
+ cur_token = * index;
+
+ if (cur_token >= length)
+ return MAILIMF_ERROR_PARSE;
+
+ while (is_wsp(message[cur_token])) {
+ cur_token ++;
+ if (cur_token >= length)
+ break;
+ }
+
+ if (cur_token == * index)
+ return MAILIMF_ERROR_PARSE;
+
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+}
+
+/*
+gboolean mailimf_crlf_parse(gchar * message, guint32 length, guint32 * index)
+*/
+
+enum {
+ BODY_PART_DASH2_STATE_0,
+ BODY_PART_DASH2_STATE_1,
+ BODY_PART_DASH2_STATE_2,
+ BODY_PART_DASH2_STATE_3,
+ BODY_PART_DASH2_STATE_4,
+ BODY_PART_DASH2_STATE_5,
+ BODY_PART_DASH2_STATE_6
+};
+
+static int
+mailmime_body_part_dash2_parse(const char * message, size_t length,
+ size_t * index, char * boundary,
+ const char ** result, size_t * result_size)
+{
+ int state;
+ size_t cur_token;
+ size_t size;
+ size_t begin_text;
+ size_t end_text;
+ int r;
+
+ cur_token = * index;
+ state = BODY_PART_DASH2_STATE_0;
+
+ begin_text = cur_token;
+ end_text = length;
+
+ while (state != BODY_PART_DASH2_STATE_5) {
+
+ if (cur_token >= length)
+ break;
+
+ switch(state) {
+
+ case BODY_PART_DASH2_STATE_0:
+ switch (message[cur_token]) {
+ case '\r':
+ state = BODY_PART_DASH2_STATE_1;
+ break;
+ case '\n':
+ state = BODY_PART_DASH2_STATE_2;
+ break;
+ default:
+ state = BODY_PART_DASH2_STATE_0;
+ break;
+ }
+ break;
+
+ case BODY_PART_DASH2_STATE_1:
+ switch (message[cur_token]) {
+ case '\n':
+ state = BODY_PART_DASH2_STATE_2;
+ break;
+ default:
+ state = BODY_PART_DASH2_STATE_0;
+ break;
+ }
+ break;
+
+ case BODY_PART_DASH2_STATE_2:
+ switch (message[cur_token]) {
+ case '-':
+ end_text = cur_token;
+ state = BODY_PART_DASH2_STATE_3;
+ break;
+ case '\r':
+ state = BODY_PART_DASH2_STATE_1;
+ break;
+ case '\n':
+ state = BODY_PART_DASH2_STATE_2;
+ break;
+ default:
+ state = BODY_PART_DASH2_STATE_0;
+ break;
+ }
+ break;
+
+ case BODY_PART_DASH2_STATE_3:
+ switch (message[cur_token]) {
+ case '\r':
+ state = BODY_PART_DASH2_STATE_1;
+ break;
+ case '\n':
+ state = BODY_PART_DASH2_STATE_2;
+ break;
+ case '-':
+ state = BODY_PART_DASH2_STATE_4;
+ break;
+ default:
+ state = BODY_PART_DASH2_STATE_0;
+ break;
+ }
+ break;
+
+ case BODY_PART_DASH2_STATE_4:
+ r = mailmime_boundary_parse(message, length, &cur_token, boundary);
+ if (r == MAILIMF_NO_ERROR)
+ state = BODY_PART_DASH2_STATE_5;
+ else
+ state = BODY_PART_DASH2_STATE_6;
+
+ break;
+ }
+
+ if ((state != BODY_PART_DASH2_STATE_5) &&
+ (state != BODY_PART_DASH2_STATE_6))
+ cur_token ++;
+
+ if (state == BODY_PART_DASH2_STATE_6)
+ state = BODY_PART_DASH2_STATE_0;
+ }
+
+ size = end_text - begin_text;
+
+#if 0
+ if (size > 0) {
+ end_text --;
+ size --;
+ }
+#endif
+
+ if (size >= 1) {
+ if (message[end_text - 1] == '\r') {
+ end_text --;
+ size --;
+ }
+ else if (size >= 1) {
+ if (message[end_text - 1] == '\n') {
+ end_text --;
+ size --;
+ if (size >= 1) {
+ if (message[end_text - 1] == '\r') {
+ end_text --;
+ size --;
+ }
+ }
+ }
+ }
+ }
+
+ size = end_text - begin_text;
+ if (size == 0)
+ return MAILIMF_ERROR_PARSE;
+
+#if 0
+ body_part = mailimf_body_new(message + begin_text, size);
+ if (body_part == NULL)
+ goto err;
+#endif
+
+ * result = message + begin_text;
+ * result_size = size;
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+#if 0
+ err:
+ return MAILIMF_ERROR_PARSE;
+#endif
+}
+
+static int
+mailmime_body_part_dash2_transport_crlf_parse(const char * message,
+ size_t length,
+ size_t * index, char * boundary,
+ const char ** result, size_t * result_size)
+{
+ size_t cur_token;
+ int r;
+ size_t after_boundary;
+ const char * data_str;
+ size_t data_size;
+ const char * begin_text;
+ const char * end_text;
+
+ cur_token = * index;
+
+ begin_text = message + cur_token;
+ end_text = message + cur_token;
+
+ while (1) {
+ r = mailmime_body_part_dash2_parse(message, length, &cur_token,
+ boundary, &data_str, &data_size);
+ if (r == MAILIMF_NO_ERROR) {
+ end_text = data_str + data_size;
+ }
+ else {
+ return r;
+ }
+
+ /* parse transport-padding */
+ while (1) {
+ r = mailmime_lwsp_parse(message, length, &cur_token);
+ if (r == MAILIMF_NO_ERROR) {
+ /* do nothing */
+ }
+ else if (r == MAILIMF_ERROR_PARSE) {
+ break;
+ }
+ else {
+ return r;
+ }
+ }
+
+ r = mailimf_crlf_parse(message, length, &cur_token);
+ if (r == MAILIMF_NO_ERROR) {
+ break;
+ }
+ else if (r == MAILIMF_ERROR_PARSE) {
+ /* do nothing */
+ }
+ else {
+ return r;
+ }
+ }
+
+ * index = cur_token;
+ * result = begin_text;
+ * result_size = end_text - begin_text;
+
+ return MAILIMF_NO_ERROR;
+}
+
+static int mailmime_multipart_close_parse(const char * message, size_t length,
+ size_t * index);
+
+static int
+mailmime_body_part_dash2_close_parse(const char * message,
+ size_t length,
+ size_t * index, char * boundary,
+ const char ** result, size_t * result_size)
+{
+ size_t cur_token;
+ int r;
+ size_t after_boundary;
+ const char * data_str;
+ size_t data_size;
+ const char * begin_text;
+ const char * end_text;
+
+ cur_token = * index;
+
+ begin_text = message + cur_token;
+ end_text = message + cur_token;
+
+ while (1) {
+ r = mailmime_body_part_dash2_parse(message, length,
+ &cur_token, boundary, &data_str, &data_size);
+ if (r == MAILIMF_NO_ERROR) {
+ end_text = data_str + data_size;
+ }
+ else {
+ return r;
+ }
+
+ r = mailmime_multipart_close_parse(message, length, &cur_token);
+ if (r == MAILIMF_NO_ERROR) {
+ break;
+ }
+ else if (r == MAILIMF_ERROR_PARSE) {
+ /* do nothing */
+ }
+ else {
+ return r;
+ }
+ }
+
+ * index = cur_token;
+ * result = data_str;
+ * result_size = data_size;
+
+ return MAILIMF_NO_ERROR;
+}
+
+enum {
+ MULTIPART_CLOSE_STATE_0,
+ MULTIPART_CLOSE_STATE_1,
+ MULTIPART_CLOSE_STATE_2,
+ MULTIPART_CLOSE_STATE_3,
+ MULTIPART_CLOSE_STATE_4
+};
+
+static int mailmime_multipart_close_parse(const char * message, size_t length,
+ size_t * index)
+{
+ int state;
+ size_t cur_token;
+
+ cur_token = * index;
+ state = MULTIPART_CLOSE_STATE_0;
+
+ while (state != MULTIPART_CLOSE_STATE_4) {
+
+ switch(state) {
+
+ case MULTIPART_CLOSE_STATE_0:
+ if (cur_token >= length)
+ return MAILIMF_ERROR_PARSE;
+
+ switch (message[cur_token]) {
+ case '-':
+ state = MULTIPART_CLOSE_STATE_1;
+ break;
+ default:
+ return MAILIMF_ERROR_PARSE;
+ }
+ break;
+
+ case MULTIPART_CLOSE_STATE_1:
+ if (cur_token >= length)
+ return MAILIMF_ERROR_PARSE;
+
+ switch (message[cur_token]) {
+ case '-':
+ state = MULTIPART_CLOSE_STATE_2;
+ break;
+ default:
+ return MAILIMF_ERROR_PARSE;
+ }
+ break;
+
+ case MULTIPART_CLOSE_STATE_2:
+ if (cur_token >= length) {
+ state = MULTIPART_CLOSE_STATE_4;
+ break;
+ }
+
+ switch (message[cur_token]) {
+ case ' ':
+ state = MULTIPART_CLOSE_STATE_2;
+ break;
+ case '\t':
+ state = MULTIPART_CLOSE_STATE_2;
+ break;
+ case '\r':
+ state = MULTIPART_CLOSE_STATE_3;
+ break;
+ case '\n':
+ state = MULTIPART_CLOSE_STATE_4;
+ break;
+ default:
+ state = MULTIPART_CLOSE_STATE_4;
+ break;
+ }
+ break;
+
+ case MULTIPART_CLOSE_STATE_3:
+ if (cur_token >= length) {
+ state = MULTIPART_CLOSE_STATE_4;
+ break;
+ }
+
+ switch (message[cur_token]) {
+ case '\n':
+ state = MULTIPART_CLOSE_STATE_4;
+ break;
+ default:
+ state = MULTIPART_CLOSE_STATE_4;
+ break;
+ }
+ break;
+ }
+
+ cur_token ++;
+ }
+
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+}
+
+enum {
+ MULTIPART_NEXT_STATE_0,
+ MULTIPART_NEXT_STATE_1,
+ MULTIPART_NEXT_STATE_2
+};
+
+int mailmime_multipart_next_parse(const char * message, size_t length,
+ size_t * index)
+{
+ int state;
+ size_t cur_token;
+
+ cur_token = * index;
+ state = MULTIPART_NEXT_STATE_0;
+
+ while (state != MULTIPART_NEXT_STATE_2) {
+
+ if (cur_token >= length)
+ return MAILIMF_ERROR_PARSE;
+
+ switch(state) {
+
+ case MULTIPART_NEXT_STATE_0:
+ switch (message[cur_token]) {
+ case ' ':
+ state = MULTIPART_NEXT_STATE_0;
+ break;
+ case '\t':
+ state = MULTIPART_NEXT_STATE_0;
+ break;
+ case '\r':
+ state = MULTIPART_NEXT_STATE_1;
+ break;
+ case '\n':
+ state = MULTIPART_NEXT_STATE_2;
+ break;
+ default:
+ return MAILIMF_ERROR_PARSE;
+ }
+ break;
+
+ case MULTIPART_NEXT_STATE_1:
+ switch (message[cur_token]) {
+ case '\n':
+ state = MULTIPART_NEXT_STATE_2;
+ break;
+ default:
+ return MAILIMF_ERROR_PARSE;
+ }
+ break;
+ }
+
+ cur_token ++;
+ }
+
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+}
+
+static int
+mailmime_multipart_body_parse(const char * message, size_t length,
+ size_t * index, char * boundary,
+ int default_subtype,
+ clist ** result,
+ struct mailmime_data ** p_preamble,
+ struct mailmime_data ** p_epilogue)
+{
+ size_t cur_token;
+ clist * list;
+ int r;
+ int res;
+#if 0
+ size_t begin;
+#endif
+ size_t preamble_begin;
+ size_t preamble_length;
+ size_t preamble_end;
+#if 0
+ int no_preamble;
+ size_t before_crlf;
+#endif
+ size_t epilogue_begin;
+ size_t epilogue_length;
+ struct mailmime_data * preamble;
+ struct mailmime_data * epilogue;
+ size_t part_begin;
+ int final_part;
+
+ preamble = NULL;
+ epilogue = NULL;
+
+ cur_token = * index;
+ preamble_begin = cur_token;
+
+#if 0
+ no_preamble = FALSE;
+#endif
+ preamble_end = preamble_begin;
+
+#if 0
+ r = mailmime_preamble_parse(message, length, &cur_token);
+ if (r == MAILIMF_NO_ERROR) {
+ /* do nothing */
+#if 0
+ preamble_end = cur_token - 2;
+#endif
+ }
+ else if (r == MAILIMF_ERROR_PARSE) {
+ /* do nothing */
+ no_preamble = TRUE;
+ }
+ else {
+ res = r;
+ goto err;
+ }
+
+ while (1) {
+
+ preamble_end = cur_token;
+ r = mailmime_boundary_parse(message, length, &cur_token, boundary);
+ if (r == MAILIMF_NO_ERROR) {
+ break;
+ }
+ else if (r == MAILIMF_ERROR_PARSE) {
+ /* do nothing */
+ }
+ else {
+ res = r;
+ goto err;
+ }
+
+ r = mailmime_preamble_parse(message, length, &cur_token);
+ if (r == MAILIMF_NO_ERROR) {
+#if 0
+ preamble_end = cur_token - 2;
+#endif
+ }
+ else if (r == MAILIMF_ERROR_PARSE) {
+ no_preamble = TRUE;
+ break;
+ }
+ else {
+ res = r;
+ goto err;
+ }
+ }
+
+ if (no_preamble) {
+#if 0
+ preamble_end = cur_token;
+#endif
+ }
+ else {
+
+ r = mailmime_lwsp_parse(message, length, &cur_token);
+ if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
+ res = r;
+ goto err;
+ }
+
+ before_crlf = cur_token;
+ r = mailimf_crlf_parse(message, length, &cur_token);
+ if (r == MAILIMF_NO_ERROR) {
+#if 0
+ preamble_end = before_crlf;
+#endif
+ /* remove the CR LF at the end of preamble if any */
+ }
+ else if (r == MAILIMF_ERROR_PARSE) {
+ /* do nothing */
+ }
+ else {
+ res = r;
+ goto err;
+ }
+ }
+ preamble_length = preamble_end - begin;
+#endif
+
+ r = mailmime_preamble_parse(message, length, &cur_token, 1);
+ if (r == MAILIMF_NO_ERROR) {
+ while (1) {
+
+ preamble_end = cur_token;
+ r = mailmime_boundary_parse(message, length, &cur_token, boundary);
+ if (r == MAILIMF_NO_ERROR) {
+ break;
+ }
+ else if (r == MAILIMF_ERROR_PARSE) {
+ /* do nothing */
+ }
+ else {
+ res = r;
+ goto err;
+ }
+
+ r = mailmime_preamble_parse(message, length, &cur_token, 0);
+ if (r == MAILIMF_NO_ERROR) {
+ }
+ else if (r == MAILIMF_ERROR_PARSE) {
+ break;
+ }
+ else {
+ res = r;
+ goto err;
+ }
+ }
+ }
+
+ preamble_end -= 2;
+ if (preamble_end != preamble_begin) {
+ /* try to find the real end of the preamble (strip CR LF) */
+ if (message[preamble_end - 1] == '\n') {
+ preamble_end --;
+ if (preamble_end - 1 >= preamble_begin) {
+ if (message[preamble_end - 1] == '\r')
+ preamble_end --;
+ }
+ }
+ else if (message[preamble_end - 1] == '\r') {
+ preamble_end --;
+ }
+ }
+ preamble_length = preamble_end - preamble_begin;
+
+ part_begin = cur_token;
+ while (1) {
+ r = mailmime_lwsp_parse(message, length, &cur_token);
+ if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
+ res = r;
+ goto err;
+ }
+#if 0
+ if (r == MAILIMF_ERROR_PARSE)
+ break;
+#endif
+
+ r = mailimf_crlf_parse(message, length, &cur_token);
+ if (r == MAILIMF_NO_ERROR) {
+ part_begin = cur_token;
+ }
+ else if (r == MAILIMF_ERROR_PARSE) {
+ /* do nothing */
+ break;
+ }
+ else {
+ res = r;
+ goto err;
+ }
+ }
+
+ cur_token = part_begin;
+
+ list = clist_new();
+ if (list == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto err;
+ }
+
+ final_part = 0;
+
+ while (!final_part) {
+ size_t bp_token;
+ struct mailmime * mime_bp;
+ const char * data_str;
+ size_t data_size;
+ struct mailimf_fields * fields;
+ struct mailmime_fields * mime_fields;
+ int got_crlf;
+ size_t after_boundary;
+
+#if 0
+ /* XXX - begin */
+ r = mailmime_body_part_dash2_parse(message, length, &cur_token,
+ boundary, &data_str, &data_size);
+ if (r == MAILIMF_NO_ERROR) {
+ /* do nothing */
+ }
+ else if (r == MAILIMF_ERROR_PARSE) {
+ break;
+ }
+ else {
+ res = r;
+ goto free;
+ }
+
+ after_boundary = cur_token;
+ got_crlf = 0;
+ /* parse transport-padding */
+ while (1) {
+ r = mailmime_lwsp_parse(message, length, &cur_token);
+ if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
+ res = r;
+ goto free;
+ }
+
+ r = mailimf_crlf_parse(message, length, &cur_token);
+ if (r == MAILIMF_NO_ERROR) {
+ got_crlf = 1;
+ break;
+ }
+ else if (r == MAILIMF_ERROR_PARSE) {
+ /* do nothing */
+ break;
+ }
+ else {
+ res = r;
+ goto free;
+ }
+ }
+ if (after_boundary != cur_token) {
+ if (!got_crlf) {
+ r = mailimf_crlf_parse(message, length, &cur_token);
+ if (r == MAILIMF_NO_ERROR) {
+ got_crlf = 1;
+ break;
+ }
+ }
+ }
+ /* XXX - end */
+#endif
+
+ r = mailmime_body_part_dash2_transport_crlf_parse(message, length,
+ &cur_token, boundary, &data_str, &data_size);
+ if (r == MAILIMF_ERROR_PARSE) {
+ r = mailmime_body_part_dash2_close_parse(message, length,
+ &cur_token, boundary, &data_str, &data_size);
+ if (r == MAILIMF_NO_ERROR) {
+ final_part = 1;
+ }
+ }
+
+ if (r == MAILIMF_NO_ERROR) {
+ bp_token = 0;
+
+ r = mailimf_optional_fields_parse(data_str, data_size,
+ &bp_token, &fields);
+ if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
+ res = r;
+ goto free;
+ }
+
+ r = mailimf_crlf_parse(data_str, data_size, &bp_token);
+ if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
+ mailimf_fields_free(fields);
+ res = r;
+ goto free;
+ }
+
+ mime_fields = NULL;
+ r = mailmime_fields_parse(fields, &mime_fields);
+ mailimf_fields_free(fields);
+ if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
+ res = r;
+ goto free;
+ }
+
+ r = mailmime_parse_with_default(data_str, data_size,
+ &bp_token, default_subtype, NULL,
+ mime_fields, &mime_bp);
+ if (r == MAILIMF_NO_ERROR) {
+ r = clist_append(list, mime_bp);
+ if (r < 0) {
+ mailmime_free(mime_bp);
+ res = MAILIMF_ERROR_MEMORY;
+ goto free;
+ }
+ }
+ else if (r == MAILIMF_ERROR_PARSE) {
+ mailmime_fields_free(mime_fields);
+ break;
+ }
+ else {
+ mailmime_fields_free(mime_fields);
+ res = r;
+ goto free;
+ }
+
+ r = mailmime_multipart_next_parse(message, length, &cur_token);
+ if (r == MAILIMF_NO_ERROR) {
+ /* do nothing */
+ }
+ }
+ else {
+ res = r;
+ goto free;
+ }
+
+#if 0
+ else if (r == MAILIMF_ERROR_PARSE) {
+ r = mailmime_body_part_dash2_parse(message, length,
+ &cur_token, boundary, &data_str, &data_size);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto free;
+ }
+
+ r = mailmime_multipart_close_parse(message, length, &cur_token);
+ if (r == MAILIMF_NO_ERROR) {
+ break;
+ }
+ else if (r == MAILIMF_ERROR_PARSE) {
+ res = r;
+ goto free;
+#if 0
+ fprintf(stderr, "close not found, reparse %s\n", boundary);
+ /* reparse */
+ continue;
+#endif
+ }
+ else {
+ res = r;
+ goto free;
+ }
+ }
+ else {
+ res = r;
+ goto free;
+ }
+#endif
+ }
+
+ epilogue_begin = length;
+ /* parse transport-padding */
+ while (1) {
+ r = mailmime_lwsp_parse(message, length, &cur_token);
+ if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
+ res = r;
+ goto free;
+ }
+
+ if (r == MAILIMF_ERROR_PARSE)
+ break;
+
+#if 0
+ if (r == MAILIMF_ERROR_PARSE)
+ break;
+#endif
+
+#if 0
+ before_crlf = cur_token;
+#endif
+ }
+
+ r = mailimf_crlf_parse(message, length, &cur_token);
+ if (r == MAILIMF_NO_ERROR) {
+ epilogue_begin = cur_token;
+ }
+ else if (r != MAILIMF_ERROR_PARSE) {
+ res = r;
+ goto free;
+ }
+
+ /* add preamble and epilogue */
+
+ epilogue_length = length - epilogue_begin;
+
+ if (preamble_length != 0) {
+ preamble = mailmime_data_new(MAILMIME_DATA_TEXT,
+ MAILMIME_MECHANISM_8BIT, 1,
+ message + preamble_begin, preamble_length,
+ NULL);
+ if (preamble == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free;
+ }
+ }
+
+ if (epilogue_length != 0) {
+ epilogue = mailmime_data_new(MAILMIME_DATA_TEXT,
+ MAILMIME_MECHANISM_8BIT, 1,
+ message + epilogue_begin, epilogue_length,
+ NULL);
+ if (epilogue == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free;
+ }
+ }
+
+ /* end of preamble and epilogue */
+
+ cur_token = length;
+
+ * result = list;
+ * p_preamble = preamble;
+ * p_epilogue = epilogue;
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+
+ free:
+ if (epilogue != NULL)
+ mailmime_data_free(epilogue);
+ if (preamble != NULL)
+ mailmime_data_free(preamble);
+ clist_foreach(list, (clist_func) mailmime_free, NULL);
+ clist_free(list);
+ err:
+ return res;
+}
+
+enum {
+ MAILMIME_DEFAULT_TYPE_TEXT_PLAIN,
+ MAILMIME_DEFAULT_TYPE_MESSAGE
+};
+
+
+int mailmime_parse(const char * message, size_t length,
+ size_t * index, struct mailmime ** result)
+{
+ struct mailmime * mime;
+ int r;
+ int res;
+ struct mailmime_content * content_message;
+ size_t cur_token;
+ struct mailmime_fields * mime_fields;
+ const char * data_str;
+ size_t data_size;
+ size_t bp_token;
+
+ cur_token = * index;
+
+ content_message = mailmime_get_content_message();
+ if (content_message == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto err;
+ }
+
+#if 0
+ mime_fields = mailmime_fields_new_with_data(content_message,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL);
+ if (mime_fields == NULL) {
+ mailmime_content_free(content_message);
+ res = MAILIMF_ERROR_MEMORY;
+ goto err;
+ }
+#endif
+ mime_fields = mailmime_fields_new_empty();
+ if (mime_fields == NULL) {
+ mailmime_content_free(content_message);
+ res = MAILIMF_ERROR_MEMORY;
+ goto err;
+ }
+
+ data_str = message + cur_token;
+ data_size = length - cur_token;
+
+ bp_token = 0;
+ r = mailmime_parse_with_default(data_str, data_size,
+ &bp_token, MAILMIME_DEFAULT_TYPE_TEXT_PLAIN,
+ content_message, mime_fields, &mime);
+ cur_token += bp_token;
+ if (r != MAILIMF_NO_ERROR) {
+ mailmime_fields_free(mime_fields);
+ res = r;
+ goto free;
+ }
+
+ * index = cur_token;
+ * result = mime;
+
+ return MAILIMF_NO_ERROR;
+
+ free:
+ mailmime_fields_free(mime_fields);
+ err:
+ return res;
+}
+
+
+char * mailmime_extract_boundary(struct mailmime_content * content_type)
+{
+ char * boundary;
+
+ boundary = mailmime_content_param_get(content_type, "boundary");
+
+ if (boundary != NULL) {
+ int len;
+ char * new_boundary;
+
+ len = strlen(boundary);
+ new_boundary = malloc(len + 1);
+ if (new_boundary == NULL)
+ return NULL;
+
+ if (boundary[0] == '"') {
+ strncpy(new_boundary, boundary + 1, len - 2);
+ new_boundary[len - 2] = 0;
+ }
+ else
+ strcpy(new_boundary, boundary);
+
+ boundary = new_boundary;
+ }
+
+ return boundary;
+}
+
+static void remove_unparsed_mime_headers(struct mailimf_fields * fields)
+{
+ clistiter * cur;
+
+ cur = clist_begin(fields->fld_list);
+ while (cur != NULL) {
+ struct mailimf_field * field;
+ int delete;
+
+ field = clist_content(cur);
+
+ switch (field->fld_type) {
+ case MAILIMF_FIELD_OPTIONAL_FIELD:
+ delete = 0;
+ if (strncasecmp(field->fld_data.fld_optional_field->fld_name,
+ "Content-", 8) == 0) {
+ char * name;
+
+ name = field->fld_data.fld_optional_field->fld_name + 8;
+ if ((strcasecmp(name, "Type") == 0)
+ || (strcasecmp(name, "Transfer-Encoding") == 0)
+ || (strcasecmp(name, "ID") == 0)
+ || (strcasecmp(name, "Description") == 0)
+ || (strcasecmp(name, "Disposition") == 0)
+ || (strcasecmp(name, "Language") == 0)) {
+ delete = 1;
+ }
+ }
+ else if (strcasecmp(field->fld_data.fld_optional_field->fld_name,
+ "MIME-Version") == 0) {
+ delete = 1;
+ }
+
+ if (delete) {
+ cur = clist_delete(fields->fld_list, cur);
+ mailimf_field_free(field);
+ }
+ else {
+ cur = clist_next(cur);
+ }
+ break;
+
+ default:
+ cur = clist_next(cur);
+ }
+ }
+}
+
+static int mailmime_parse_with_default(const char * message, size_t length,
+ size_t * index, int default_type,
+ struct mailmime_content * content_type,
+ struct mailmime_fields * mime_fields,
+ struct mailmime ** result)
+{
+ size_t cur_token;
+
+ int body_type;
+
+ int encoding;
+ struct mailmime_data * body;
+ char * boundary;
+ struct mailimf_fields * fields;
+ clist * list;
+ struct mailmime * msg_mime;
+
+ struct mailmime * mime;
+
+ int r;
+ int res;
+ struct mailmime_data * preamble;
+ struct mailmime_data * epilogue;
+
+ /*
+ note that when this function is called, content type is always detached,
+ even if the function fails
+ */
+
+ preamble = NULL;
+ epilogue = NULL;
+
+ cur_token = * index;
+
+ /* get content type */
+
+ if (content_type == NULL) {
+ if (mime_fields != NULL) {
+ clistiter * cur;
+
+ for(cur = clist_begin(mime_fields->fld_list) ; cur != NULL ;
+ cur = clist_next(cur)) {
+ struct mailmime_field * field;
+
+ field = clist_content(cur);
+ if (field->fld_type == MAILMIME_FIELD_TYPE) {
+ content_type = field->fld_data.fld_content;
+
+ /* detach content type from list */
+ field->fld_data.fld_content = NULL;
+ clist_delete(mime_fields->fld_list, cur);
+ mailmime_field_free(field);
+ /*
+ there may be a leak due to the detached content type
+ in case the function fails
+ */
+ break;
+ }
+ }
+ }
+ }
+
+ /* set default type if no content type */
+
+ if (content_type == NULL) {
+ /* content_type is detached, in any case, we will have to free it */
+ if (default_type == MAILMIME_DEFAULT_TYPE_TEXT_PLAIN) {
+ content_type = mailmime_get_content_text();
+ if (content_type == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto err;
+ }
+ }
+ else /* message */ {
+ body_type = MAILMIME_MESSAGE;
+
+ content_type = mailmime_get_content_message();
+ if (content_type == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto err;
+ }
+ }
+ }
+
+ /* get the body type */
+
+ boundary = NULL; /* XXX - removes a gcc warning */
+
+ switch (content_type->ct_type->tp_type) {
+ case MAILMIME_TYPE_COMPOSITE_TYPE:
+ switch (content_type->ct_type->tp_data.tp_composite_type->ct_type) {
+ case MAILMIME_COMPOSITE_TYPE_MULTIPART:
+ boundary = mailmime_extract_boundary(content_type);
+
+ if (boundary == NULL)
+ body_type = MAILMIME_SINGLE;
+ else
+ body_type = MAILMIME_MULTIPLE;
+ break;
+
+ case MAILMIME_COMPOSITE_TYPE_MESSAGE:
+
+ if (strcasecmp(content_type->ct_subtype, "rfc822") == 0)
+ body_type = MAILMIME_MESSAGE;
+ else
+ body_type = MAILMIME_SINGLE;
+ break;
+
+ default:
+ res = MAILIMF_ERROR_INVAL;
+ goto free_content;
+ }
+ break;
+
+ default: /* MAILMIME_TYPE_DISCRETE_TYPE */
+ body_type = MAILMIME_SINGLE;
+ break;
+ }
+
+ /* set body */
+
+ if (mime_fields != NULL)
+ encoding = mailmime_transfer_encoding_get(mime_fields);
+ else
+ encoding = MAILMIME_MECHANISM_8BIT;
+
+ cur_token = * index;
+ body = mailmime_data_new(MAILMIME_DATA_TEXT, encoding, 1,
+ message + cur_token, length - cur_token,
+ NULL);
+ if (body == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free_content;
+ }
+
+ /* in case of composite, parse the sub-part(s) */
+
+ list = NULL;
+ msg_mime = NULL;
+ fields = NULL;
+
+ switch (body_type) {
+ case MAILMIME_MESSAGE:
+ {
+ struct mailmime_fields * submime_fields;
+
+ r = mailimf_envelope_and_optional_fields_parse(message, length,
+ &cur_token, &fields);
+ if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
+ res = r;
+ goto free_content;
+ }
+
+ r = mailimf_crlf_parse(message, length, &cur_token);
+ if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
+ mailimf_fields_free(fields);
+ res = r;
+ goto free_content;
+ }
+
+ submime_fields = NULL;
+ r = mailmime_fields_parse(fields, &submime_fields);
+ if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
+ mailimf_fields_free(fields);
+ res = r;
+ goto free_content;
+ }
+
+ remove_unparsed_mime_headers(fields);
+
+ r = mailmime_parse_with_default(message, length,
+ &cur_token, MAILMIME_DEFAULT_TYPE_TEXT_PLAIN,
+ NULL, submime_fields, &msg_mime);
+ if (r == MAILIMF_NO_ERROR) {
+ /* do nothing */
+ }
+ else if (r == MAILIMF_ERROR_PARSE) {
+ mailmime_fields_free(mime_fields);
+ msg_mime = NULL;
+ }
+ else {
+ mailmime_fields_free(mime_fields);
+ res = r;
+ goto free_content;
+ }
+ }
+
+ break;
+
+ case MAILMIME_MULTIPLE:
+ {
+ int default_subtype;
+
+ default_subtype = MAILMIME_DEFAULT_TYPE_TEXT_PLAIN;
+ if (content_type != NULL)
+ if (strcasecmp(content_type->ct_subtype, "digest") == 0)
+ default_subtype = MAILMIME_DEFAULT_TYPE_MESSAGE;
+
+ cur_token = * index;
+ r = mailmime_multipart_body_parse(message, length,
+ &cur_token, boundary,
+ default_subtype,
+ &list, &preamble, &epilogue);
+ if (r == MAILIMF_NO_ERROR) {
+ /* do nothing */
+ }
+ else if (r == MAILIMF_ERROR_PARSE) {
+ list = clist_new();
+ if (list == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free_content;
+ }
+ }
+ else {
+ res = r;
+ goto free_content;
+ }
+
+ free(boundary);
+ }
+ break;
+
+ default: /* MAILMIME_SINGLE */
+ /* do nothing */
+ break;
+ }
+
+ mime = mailmime_new(body_type, message, length,
+ mime_fields, content_type,
+ body, preamble, /* preamble */
+ epilogue, /* epilogue */
+ list, fields, msg_mime);
+ if (mime == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free;
+ }
+
+ * result = mime;
+ * index = length;
+
+ return MAILIMF_NO_ERROR;
+
+ free:
+ if (epilogue != NULL)
+ mailmime_data_free(epilogue);
+ if (preamble != NULL)
+ mailmime_data_free(preamble);
+ if (msg_mime != NULL)
+ mailmime_free(msg_mime);
+ if (list != NULL) {
+ clist_foreach(list, (clist_func) mailmime_free, NULL);
+ clist_free(list);
+ }
+ free_content:
+ mailmime_content_free(content_type);
+ err:
+ return res;
+}
+
+static int mailmime_get_section_list(struct mailmime * mime,
+ clistiter * list, struct mailmime ** result)
+{
+ uint32_t id;
+ struct mailmime * data;
+ struct mailmime * submime;
+
+ if (list == NULL) {
+ * result = mime;
+ return MAILIMF_NO_ERROR;
+ }
+
+ id = * ((uint32_t *) clist_content(list));
+
+ data = NULL;
+ switch (mime->mm_type) {
+ case MAILMIME_SINGLE:
+ return MAILIMF_ERROR_INVAL;
+
+ case MAILMIME_MULTIPLE:
+ data = clist_nth_data(mime->mm_data.mm_multipart.mm_mp_list, id - 1);
+ if (data == NULL)
+ return MAILIMF_ERROR_INVAL;
+
+ if (clist_next(list) != NULL)
+ return mailmime_get_section_list(data, clist_next(list), result);
+ else {
+ * result = data;
+ return MAILIMF_NO_ERROR;
+ }
+
+ case MAILMIME_MESSAGE:
+ submime = mime->mm_data.mm_message.mm_msg_mime;
+ switch (submime->mm_type) {
+ case MAILMIME_MULTIPLE:
+ data = clist_nth_data(submime->mm_data.mm_multipart.mm_mp_list, id - 1);
+ if (data == NULL)
+ return MAILIMF_ERROR_INVAL;
+ return mailmime_get_section_list(data, clist_next(list), result);
+
+ default:
+ if (id != 1)
+ return MAILIMF_ERROR_INVAL;
+
+ data = submime;
+ if (data == NULL)
+ return MAILIMF_ERROR_INVAL;
+
+ return mailmime_get_section_list(data, clist_next(list), result);
+ }
+ break;
+
+ default:
+ return MAILIMF_ERROR_INVAL;
+ }
+}
+
+int mailmime_get_section(struct mailmime * mime,
+ struct mailmime_section * section,
+ struct mailmime ** result)
+{
+ return mailmime_get_section_list(mime,
+ clist_begin(section->sec_list), result);
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+/* ************************************************************************* */
+/* MIME part decoding */
+
+static inline signed char get_base64_value(char ch)
+{
+ if ((ch >= 'A') && (ch <= 'Z'))
+ return ch - 'A';
+ if ((ch >= 'a') && (ch <= 'z'))
+ return ch - 'a' + 26;
+ if ((ch >= '0') && (ch <= '9'))
+ return ch - '0' + 52;
+ switch (ch) {
+ case '+':
+ return 62;
+ case '/':
+ return 63;
+ case '=': /* base64 padding */
+ return -1;
+ default:
+ return -1;
+ }
+}
+
+int mailmime_base64_body_parse(const char * message, size_t length,
+ size_t * index, char ** result,
+ size_t * result_len)
+{
+ size_t cur_token;
+ size_t i;
+ char chunk[4];
+ int chunk_index;
+ char out[3];
+ MMAPString * mmapstr;
+ int res;
+ int r;
+ size_t written;
+
+ cur_token = * index;
+ chunk_index = 0;
+ written = 0;
+
+ mmapstr = mmap_string_sized_new((length - cur_token) * 3 / 4);
+ if (mmapstr == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto err;
+ }
+
+ i = 0;
+ while (1) {
+ signed char value;
+
+ value = -1;
+ while (value == -1) {
+
+ if (cur_token >= length)
+ break;
+
+ value = get_base64_value(message[cur_token]);
+ cur_token ++;
+ }
+
+ if (value == -1)
+ break;
+
+ chunk[chunk_index] = value;
+ chunk_index ++;
+
+ if (chunk_index == 4) {
+ out[0] = (chunk[0] << 2) | (chunk[1] >> 4);
+ out[1] = (chunk[1] << 4) | (chunk[2] >> 2);
+ out[2] = (chunk[2] << 6) | (chunk[3]);
+
+ chunk[0] = 0;
+ chunk[1] = 0;
+ chunk[2] = 0;
+ chunk[3] = 0;
+
+ chunk_index = 0;
+
+ if (mmap_string_append_len(mmapstr, out, 3) == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free;
+ }
+ written += 3;
+ }
+ }
+
+ if (chunk_index != 0) {
+ size_t len;
+
+ len = 0;
+ out[0] = (chunk[0] << 2) | (chunk[1] >> 4);
+ len ++;
+
+ if (chunk_index >= 3) {
+ out[1] = (chunk[1] << 4) | (chunk[2] >> 2);
+ len ++;
+ }
+
+ if (mmap_string_append_len(mmapstr, out, len) == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free;
+ }
+ written += len;
+ }
+
+ r = mmap_string_ref(mmapstr);
+ if (r < 0) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free;
+ }
+
+ * index = cur_token;
+ * result = mmapstr->str;
+ * result_len = written;
+
+ return MAILIMF_NO_ERROR;
+
+ free:
+ mmap_string_free(mmapstr);
+ err:
+ return res;
+}
+
+
+
+static inline int hexa_to_char(char hexdigit)
+{
+ if ((hexdigit >= '0') && (hexdigit <= '9'))
+ return hexdigit - '0';
+ if ((hexdigit >= 'a') && (hexdigit <= 'f'))
+ return hexdigit - 'a' + 10;
+ if ((hexdigit >= 'A') && (hexdigit <= 'F'))
+ return hexdigit - 'A' + 10;
+ return 0;
+}
+
+static inline char to_char(const char * hexa)
+{
+ return (hexa_to_char(hexa[0]) << 4) | hexa_to_char(hexa[1]);
+}
+
+enum {
+ STATE_NORMAL,
+ STATE_CODED,
+ STATE_OUT,
+ STATE_CR,
+};
+
+
+static int write_decoded_qp(MMAPString * mmapstr,
+ const char * start, size_t count)
+{
+ if (mmap_string_append_len(mmapstr, start, count) == NULL)
+ return MAILIMF_ERROR_MEMORY;
+
+ return MAILIMF_NO_ERROR;
+}
+
+
+#define WRITE_MAX_QP 512
+
+int mailmime_quoted_printable_body_parse(const char * message, size_t length,
+ size_t * index, char ** result,
+ size_t * result_len, int in_header)
+{
+ size_t cur_token;
+ int state;
+ int r;
+ char ch;
+ size_t count;
+ const char * start;
+ MMAPString * mmapstr;
+ int res;
+ size_t written;
+
+ state = STATE_NORMAL;
+ cur_token = * index;
+
+ count = 0;
+ start = message + cur_token;
+ written = 0;
+
+ mmapstr = mmap_string_sized_new(length - cur_token);
+ if (mmapstr == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto err;
+ }
+
+#if 0
+ if (length >= 1) {
+ if (message[length - 1] == '\n') {
+ length --;
+ if (length >= 1)
+ if (message[length - 1] == '\r') {
+ length --;
+ }
+ }
+ }
+#endif
+
+ while (state != STATE_OUT) {
+
+ if (cur_token >= length) {
+ state = STATE_OUT;
+ break;
+ }
+
+ switch (state) {
+
+ case STATE_CODED:
+
+ if (count > 0) {
+ r = write_decoded_qp(mmapstr, start, count);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto free;
+ }
+ written += count;
+ count = 0;
+ }
+
+ switch (message[cur_token]) {
+ case '=':
+ if (cur_token + 1 >= length) {
+ /* error but ignore it */
+ state = STATE_NORMAL;
+ start = message + cur_token;
+ cur_token ++;
+ count ++;
+ break;
+ }
+
+ switch (message[cur_token + 1]) {
+
+ case '\n':
+ cur_token += 2;
+
+ start = message + cur_token;
+
+ state = STATE_NORMAL;
+ break;
+
+ case '\r':
+ if (cur_token + 2 >= length) {
+ state = STATE_OUT;
+ break;
+ }
+
+ if (message[cur_token + 2] == '\n')
+ cur_token += 3;
+ else
+ cur_token += 2;
+
+ start = message + cur_token;
+
+ state = STATE_NORMAL;
+
+ break;
+
+ default:
+ if (cur_token + 2 >= length) {
+ /* error but ignore it */
+ cur_token ++;
+
+ start = message + cur_token;
+
+ count ++;
+ state = STATE_NORMAL;
+ break;
+ }
+
+#if 0
+ /* flush before writing additionnal information */
+ r = write_decoded_qp(mmapstr, start, count);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto free;
+ }
+ written += count;
+ count = 0;
+#endif
+
+ ch = to_char(message + cur_token + 1);
+
+ if (mmap_string_append_c(mmapstr, ch) == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free;
+ }
+
+ cur_token += 3;
+ written ++;
+
+ start = message + cur_token;
+
+ state = STATE_NORMAL;
+ break;
+ }
+ break;
+ }
+ break; /* end of STATE_ENCODED */
+
+ case STATE_NORMAL:
+
+ switch (message[cur_token]) {
+
+ case '=':
+ state = STATE_CODED;
+ break;
+
+ case '\n':
+ /* flush before writing additionnal information */
+ if (count > 0) {
+ r = write_decoded_qp(mmapstr, start, count);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto free;
+ }
+ written += count;
+
+ count = 0;
+ }
+
+ r = write_decoded_qp(mmapstr, "\r\n", 2);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto free;
+ }
+ written += 2;
+ cur_token ++;
+ start = message + cur_token;
+ break;
+
+ case '\r':
+ state = STATE_CR;
+ cur_token ++;
+ break;
+
+ case '_':
+ if (in_header) {
+ if (count > 0) {
+ r = write_decoded_qp(mmapstr, start, count);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto free;
+ }
+ written += count;
+ count = 0;
+ }
+
+ if (mmap_string_append_c(mmapstr, ' ') == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free;
+ }
+
+ written ++;
+ cur_token ++;
+ start = message + cur_token;
+
+ break;
+ }
+ /* WARINING : must be followed by switch default action */
+
+ default:
+ if (count >= WRITE_MAX_QP) {
+ r = write_decoded_qp(mmapstr, start, count);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto free;
+ }
+ written += count;
+ count = 0;
+ start = message + cur_token;
+ }
+
+ count ++;
+ cur_token ++;
+ break;
+ }
+ break; /* end of STATE_NORMAL */
+
+ case STATE_CR:
+ switch (message[cur_token]) {
+
+ case '\n':
+ /* flush before writing additionnal information */
+ if (count > 0) {
+ r = write_decoded_qp(mmapstr, start, count);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto free;
+ }
+ written += count;
+ count = 0;
+ }
+
+ r = write_decoded_qp(mmapstr, "\r\n", 2);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto free;
+ }
+ written += 2;
+ cur_token ++;
+ start = message + cur_token;
+ state = STATE_NORMAL;
+ break;
+
+ default:
+ /* flush before writing additionnal information */
+ if (count > 0) {
+ r = write_decoded_qp(mmapstr, start, count);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto free;
+ }
+ written += count;
+ count = 0;
+ }
+
+ start = message + cur_token;
+
+ r = write_decoded_qp(mmapstr, "\r\n", 2);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto free;
+ }
+ written += 2;
+ state = STATE_NORMAL;
+ }
+ break; /* end of STATE_CR */
+ }
+ }
+
+ if (count > 0) {
+ r = write_decoded_qp(mmapstr, start, count);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto free;
+ }
+ written += count;
+ count = 0;
+ }
+
+ r = mmap_string_ref(mmapstr);
+ if (r < 0) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free;
+ }
+
+ * index = cur_token;
+ * result = mmapstr->str;
+ * result_len = written;
+
+ return MAILIMF_NO_ERROR;
+
+ free:
+ mmap_string_free(mmapstr);
+ err:
+ return res;
+}
+
+int mailmime_binary_body_parse(const char * message, size_t length,
+ size_t * index, char ** result,
+ size_t * result_len)
+{
+ MMAPString * mmapstr;
+ size_t cur_token;
+ int r;
+ int res;
+
+ cur_token = * index;
+
+ if (length >= 1) {
+ if (message[length - 1] == '\n') {
+ length --;
+ if (length >= 1)
+ if (message[length - 1] == '\r')
+ length --;
+ }
+ }
+
+ mmapstr = mmap_string_new_len(message + cur_token, length - cur_token);
+ if (mmapstr == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto err;
+ }
+
+ r = mmap_string_ref(mmapstr);
+ if (r < 0) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free;
+ }
+
+ * index = length;
+ * result = mmapstr->str;
+ * result_len = length - cur_token;
+
+ return MAILIMF_NO_ERROR;
+
+ free:
+ mmap_string_free(mmapstr);
+ err:
+ return res;
+}
+
+
+int mailmime_part_parse(const char * message, size_t length,
+ size_t * index,
+ int encoding, char ** result, size_t * result_len)
+{
+ switch (encoding) {
+ case MAILMIME_MECHANISM_BASE64:
+ return mailmime_base64_body_parse(message, length, index,
+ result, result_len);
+
+ case MAILMIME_MECHANISM_QUOTED_PRINTABLE:
+ return mailmime_quoted_printable_body_parse(message, length, index,
+ result, result_len, FALSE);
+
+ case MAILMIME_MECHANISM_7BIT:
+ case MAILMIME_MECHANISM_8BIT:
+ case MAILMIME_MECHANISM_BINARY:
+ default:
+ return mailmime_binary_body_parse(message, length, index,
+ result, result_len);
+ }
+}
+
+int mailmime_get_section_id(struct mailmime * mime,
+ struct mailmime_section ** result)
+{
+ clist * list;
+ int res;
+ struct mailmime_section * section_id;
+ int r;
+
+ if (mime->mm_parent == NULL) {
+ list = clist_new();
+ if (list == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto err;
+ }
+
+ section_id = mailmime_section_new(list);
+ if (section_id == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto err;
+ }
+ }
+ else {
+ uint32_t id;
+ uint32_t * p_id;
+ clistiter * cur;
+ struct mailmime * parent;
+
+ r = mailmime_get_section_id(mime->mm_parent, &section_id);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ parent = mime->mm_parent;
+ switch (parent->mm_type) {
+ case MAILMIME_MULTIPLE:
+ id = 1;
+ for(cur = clist_begin(parent->mm_data.mm_multipart.mm_mp_list) ;
+ cur != NULL ; cur = clist_next(cur)) {
+ if (clist_content(cur) == mime)
+ break;
+ id ++;
+ }
+
+ p_id = malloc(sizeof(* p_id));
+ if (p_id == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free;
+ }
+ * p_id = id;
+
+ r = clist_append(section_id->sec_list, p_id);
+ if (r < 0) {
+ free(p_id);
+ res = MAILIMF_ERROR_MEMORY;
+ goto free;
+ }
+ break;
+
+ case MAILMIME_MESSAGE:
+ if ((mime->mm_type == MAILMIME_SINGLE) ||
+ (mime->mm_type == MAILMIME_MESSAGE)) {
+ p_id = malloc(sizeof(* p_id));
+ if (p_id == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free;
+ }
+ * p_id = 1;
+
+ r = clist_append(section_id->sec_list, p_id);
+ if (r < 0) {
+ free(p_id);
+ res = MAILIMF_ERROR_MEMORY;
+ goto free;
+ }
+ }
+ }
+ }
+
+ * result = section_id;
+
+ return MAILIMF_NO_ERROR;
+
+ free:
+ mailmime_section_free(section_id);
+ err:
+ return res;
+}