From e3b89230f065c48c84b48c88edb6eb088374c487 Mon Sep 17 00:00:00 2001 From: zautrix Date: Sat, 03 Jul 2004 16:33:12 +0000 Subject: Initial revision --- (limited to 'kmicromail/libetpan/imf/mailimf.c') diff --git a/kmicromail/libetpan/imf/mailimf.c b/kmicromail/libetpan/imf/mailimf.c new file mode 100644 index 0000000..84d81a1 --- a/dev/null +++ b/kmicromail/libetpan/imf/mailimf.c @@ -0,0 +1,7585 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2002 - 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 REGENTS 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 REGENTS 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" + +/* + RFC 2822 + + RFC 2821 ... + A message-originating SMTP system SHOULD NOT send a message that + already contains a Return-path header. SMTP servers performing a + relay function MUST NOT inspect the message data, and especially not + to the extent needed to determine if Return-path headers are present. + SMTP servers making final delivery MAY remove Return-path headers + before adding their own. +*/ + +#include +#include +#include +#include + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + + + + + + + +static inline int is_dtext(char ch); + +static int mailimf_quoted_pair_parse(const char * message, size_t length, + size_t * index, char * result); + +static int mailimf_ccontent_parse(const char * message, size_t length, + size_t * index); + +static int +mailimf_comment_fws_ccontent_parse(const char * message, size_t length, + size_t * index); + +static inline int mailimf_comment_parse(const char * message, size_t length, + size_t * index); + +static int mailimf_qcontent_parse(const char * message, size_t length, + size_t * index, char * ch); + +static int mailimf_phrase_parse(const char * message, size_t length, + size_t * index, char ** result); + +static int mailimf_unstructured_parse(const char * message, size_t length, + size_t * index, char ** result); + +static int mailimf_ignore_unstructured_parse(const char * message, size_t length, + size_t * index); + +static int mailimf_day_of_week_parse(const char * message, size_t length, + size_t * index, int * result); + +static int mailimf_day_name_parse(const char * message, size_t length, + size_t * index, int * result); + +static int mailimf_date_parse(const char * message, size_t length, + size_t * index, + int * pday, int * pmonth, int * pyear); + +static int mailimf_year_parse(const char * message, size_t length, + size_t * index, int * result); + +static int mailimf_month_parse(const char * message, size_t length, + size_t * index, int * result); + +static int mailimf_month_name_parse(const char * message, size_t length, + size_t * index, int * result); + +static int mailimf_day_parse(const char * message, size_t length, + size_t * index, int * result); + +static int mailimf_time_parse(const char * message, size_t length, + size_t * index, + int * phour, int * pmin, + int * psec, + int * zone); +static int mailimf_time_of_day_parse(const char * message, size_t length, + size_t * index, + int * phour, int * pmin, + int * psec); + +static int mailimf_hour_parse(const char * message, size_t length, + size_t * index, int * result); + +static int mailimf_minute_parse(const char * message, size_t length, + size_t * index, int * result); + +static int mailimf_second_parse(const char * message, size_t length, + size_t * index, int * result); + +static int mailimf_zone_parse(const char * message, size_t length, + size_t * index, int * result); + +static int mailimf_name_addr_parse(const char * message, size_t length, + size_t * index, + char ** pdisplay_name, + char ** pangle_addr); + +static int mailimf_angle_addr_parse(const char * message, size_t length, + size_t * index, char ** result); + +static int mailimf_group_parse(const char * message, size_t length, + size_t * index, + struct mailimf_group ** result); + +static int mailimf_display_name_parse(const char * message, size_t length, + size_t * index, char ** result); + +static int mailimf_addr_spec_parse(const char * message, size_t length, + size_t * index, + char ** address); + +#if 0 +static int mailimf_local_part_parse(const char * message, size_t length, + size_t * index, + char ** result); + +static int mailimf_domain_parse(const char * message, size_t length, + size_t * index, + char ** result); +#endif + +#if 0 +static int mailimf_domain_literal_parse(const char * message, size_t length, + size_t * index, char ** result); +#endif + +#if 0 +static int mailimf_dcontent_parse(const char * message, size_t length, + size_t * index, char * result); +#endif + +static int +mailimf_orig_date_parse(const char * message, size_t length, + size_t * index, struct mailimf_orig_date ** result); + +static int +mailimf_from_parse(const char * message, size_t length, + size_t * index, struct mailimf_from ** result); + +static int +mailimf_sender_parse(const char * message, size_t length, + size_t * index, struct mailimf_sender ** result); + +static int +mailimf_reply_to_parse(const char * message, size_t length, + size_t * index, struct mailimf_reply_to ** result); + +static int +mailimf_to_parse(const char * message, size_t length, + size_t * index, struct mailimf_to ** result); + +static int +mailimf_cc_parse(const char * message, size_t length, + size_t * index, struct mailimf_cc ** result); + +static int +mailimf_bcc_parse(const char * message, size_t length, + size_t * index, struct mailimf_bcc ** result); + +static int mailimf_message_id_parse(const char * message, size_t length, + size_t * index, + struct mailimf_message_id ** result); + +static int +mailimf_in_reply_to_parse(const char * message, size_t length, + size_t * index, + struct mailimf_in_reply_to ** result); + +#if 0 +static int mailimf_references_parse(const char * message, size_t length, + size_t * index, + struct mailimf_references ** + result); +#endif + +static int mailimf_unstrict_msg_id_parse(const char * message, size_t length, + size_t * index, + char ** result); + +#if 0 +static int mailimf_id_left_parse(const char * message, size_t length, + size_t * index, char ** result); + +static int mailimf_id_right_parse(const char * message, size_t length, + size_t * index, char ** result); +#endif + +#if 0 +static int mailimf_no_fold_quote_parse(const char * message, size_t length, + size_t * index, char ** result); + +static int mailimf_no_fold_literal_parse(const char * message, size_t length, + size_t * index, char ** result); +#endif + +static int mailimf_subject_parse(const char * message, size_t length, + size_t * index, + struct mailimf_subject ** result); + +static int mailimf_comments_parse(const char * message, size_t length, + size_t * index, + struct mailimf_comments ** result); + +static int mailimf_keywords_parse(const char * message, size_t length, + size_t * index, + struct mailimf_keywords ** result); + +static int +mailimf_resent_date_parse(const char * message, size_t length, + size_t * index, struct mailimf_orig_date ** result); + +static int +mailimf_resent_from_parse(const char * message, size_t length, + size_t * index, struct mailimf_from ** result); + +static int +mailimf_resent_sender_parse(const char * message, size_t length, + size_t * index, struct mailimf_sender ** result); + +static int +mailimf_resent_to_parse(const char * message, size_t length, + size_t * index, struct mailimf_to ** result); + +static int +mailimf_resent_cc_parse(const char * message, size_t length, + size_t * index, struct mailimf_cc ** result); + +static int +mailimf_resent_bcc_parse(const char * message, size_t length, + size_t * index, struct mailimf_bcc ** result); + +static int +mailimf_resent_msg_id_parse(const char * message, size_t length, + size_t * index, + struct mailimf_message_id ** result); + +static int mailimf_return_parse(const char * message, size_t length, + size_t * index, + struct mailimf_return ** result); + +static int +mailimf_path_parse(const char * message, size_t length, + size_t * index, struct mailimf_path ** result); + +static int +mailimf_optional_field_parse(const char * message, size_t length, + size_t * index, + struct mailimf_optional_field ** result); + +static int mailimf_field_name_parse(const char * message, size_t length, + size_t * index, char ** result); + + + + + + + + + + + + + + + + + + + + + + + + + +/* *************************************************************** */ + +static inline int is_digit(char ch) +{ + return (ch >= '0') && (ch <= '9'); +} + +static int mailimf_digit_parse(const char * message, size_t length, + size_t * index, int * result) +{ + size_t cur_token; + + cur_token = * index; + + if (cur_token >= length) + return MAILIMF_ERROR_PARSE; + + if (is_digit(message[cur_token])) { + * result = message[cur_token] - '0'; + cur_token ++; + * index = cur_token; + return MAILIMF_NO_ERROR; + } + else + return MAILIMF_ERROR_PARSE; +} + +int +mailimf_number_parse(const char * message, size_t length, + size_t * index, uint32_t * result) +{ + size_t cur_token; + int digit; + uint32_t number; + int parsed; + int r; + + cur_token = * index; + parsed = FALSE; + + number = 0; + while (1) { + r = mailimf_digit_parse(message, length, &cur_token, &digit); + if (r != MAILIMF_NO_ERROR) { + if (r == MAILIMF_ERROR_PARSE) + break; + else + return r; + } + number *= 10; + number += digit; + parsed = TRUE; + } + + if (!parsed) + return MAILIMF_ERROR_PARSE; + + * result = number; + * index = cur_token; + + return MAILIMF_NO_ERROR; +} + +int mailimf_char_parse(const char * message, size_t length, + size_t * index, char token) +{ + size_t cur_token; + + cur_token = * index; + + if (cur_token >= length) + return MAILIMF_ERROR_PARSE; + + if (message[cur_token] == token) { + cur_token ++; + * index = cur_token; + return MAILIMF_NO_ERROR; + } + else + return MAILIMF_ERROR_PARSE; +} + +int mailimf_unstrict_char_parse(const char * message, size_t length, + size_t * index, char token) +{ + size_t cur_token; + int r; + + cur_token = * index; + + r = mailimf_cfws_parse(message, length, &cur_token); + if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) + return r; + + r = mailimf_char_parse(message, length, &cur_token, token); + if (r != MAILIMF_NO_ERROR) + return r; + + * index = cur_token; + + return MAILIMF_NO_ERROR; +} + +int +mailimf_token_case_insensitive_len_parse(const char * message, size_t length, + size_t * index, char * token, + size_t token_length) +{ + size_t cur_token; + + cur_token = * index; + + if (cur_token + token_length - 1 >= length) + return MAILIMF_ERROR_PARSE; + + if (strncasecmp(message + cur_token, token, token_length) == 0) { + cur_token += token_length; + * index = cur_token; + return MAILIMF_NO_ERROR; + } + else + return MAILIMF_ERROR_PARSE; +} + +static int mailimf_oparenth_parse(const char * message, size_t length, + size_t * index) +{ + return mailimf_char_parse(message, length, index, '('); +} + +static int mailimf_cparenth_parse(const char * message, size_t length, + size_t * index) +{ + return mailimf_char_parse(message, length, index, ')'); +} + +static int mailimf_comma_parse(const char * message, size_t length, + size_t * index) +{ + return mailimf_unstrict_char_parse(message, length, index, ','); +} + +static int mailimf_dquote_parse(const char * message, size_t length, + size_t * index) +{ + return mailimf_char_parse(message, length, index, '\"'); +} + +static int mailimf_colon_parse(const char * message, size_t length, + size_t * index) +{ + return mailimf_unstrict_char_parse(message, length, index, ':'); +} + +static int mailimf_semi_colon_parse(const char * message, size_t length, + size_t * index) +{ + return mailimf_unstrict_char_parse(message, length, index, ';'); +} + +static int mailimf_plus_parse(const char * message, size_t length, + size_t * index) +{ + return mailimf_unstrict_char_parse(message, length, index, '+'); +} + +static int mailimf_minus_parse(const char * message, size_t length, + size_t * index) +{ + return mailimf_unstrict_char_parse(message, length, index, '-'); +} + +static int mailimf_lower_parse(const char * message, size_t length, + size_t * index) +{ + return mailimf_unstrict_char_parse(message, length, index, '<'); +} + +static int mailimf_greater_parse(const char * message, size_t length, + size_t * index) +{ + return mailimf_unstrict_char_parse(message, length, index, '>'); +} + +#if 0 +static int mailimf_obracket_parse(const char * message, size_t length, + size_t * index) +{ + return mailimf_unstrict_char_parse(message, length, index, '['); +} + +static int mailimf_cbracket_parse(const char * message, size_t length, + size_t * index) +{ + return mailimf_unstrict_char_parse(message, length, index, ']'); +} +#endif + +static int mailimf_at_sign_parse(const char * message, size_t length, + size_t * index) +{ + return mailimf_unstrict_char_parse(message, length, index, '@'); +} + +static int mailimf_point_parse(const char * message, size_t length, + size_t * index) +{ + return mailimf_unstrict_char_parse(message, length, index, '.'); +} + +int +mailimf_custom_string_parse(const char * message, size_t length, + size_t * index, char ** result, + int (* is_custom_char)(char)) +{ + size_t begin; + size_t end; + char * gstr; + + begin = * index; + + end = begin; + + if (end >= length) + return MAILIMF_ERROR_PARSE; + + while (is_custom_char(message[end])) { + end ++; + if (end >= length) + break; + } + + if (end != begin) { + /* + gstr = strndup(message + begin, end - begin); + */ + gstr = malloc(end - begin + 1); + if (gstr == NULL) + return MAILIMF_ERROR_MEMORY; + strncpy(gstr, message + begin, end - begin); + gstr[end - begin] = '\0'; + + * index = end; + * result = gstr; + return MAILIMF_NO_ERROR; + } + else + return MAILIMF_ERROR_PARSE; +} + + + + + + + +typedef int mailimf_struct_parser(const char * message, size_t length, + size_t * index, void * result); + +typedef int mailimf_struct_destructor(void * result); + + +static int +mailimf_struct_multiple_parse(const char * message, size_t length, + size_t * index, clist ** result, + mailimf_struct_parser * parser, + mailimf_struct_destructor * destructor) +{ + clist * struct_list; + size_t cur_token; + void * value; + int r; + int res; + + cur_token = * index; + + r = parser(message, length, &cur_token, &value); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto err; + } + + struct_list = clist_new(); + if (struct_list == NULL) { + destructor(value); + res = MAILIMF_ERROR_MEMORY; + goto err; + } + + r = clist_append(struct_list, value); + if (r < 0) { + destructor(value); + res = MAILIMF_ERROR_MEMORY; + goto free; + } + + while (1) { + r = parser(message, length, &cur_token, &value); + if (r != MAILIMF_NO_ERROR) { + if (r == MAILIMF_ERROR_PARSE) + break; + else { + res = r; + goto free; + } + } + r = clist_append(struct_list, value); + if (r < 0) { + (* destructor)(value); + res = MAILIMF_ERROR_MEMORY; + goto free; + } + } + + * result = struct_list; + * index = cur_token; + + return MAILIMF_NO_ERROR; + + free: + clist_foreach(struct_list, (clist_func) destructor, NULL); + clist_free(struct_list); + err: + return res; +} + + + +static int +mailimf_struct_list_parse(const char * message, size_t length, + size_t * index, clist ** result, + char symbol, + mailimf_struct_parser * parser, + mailimf_struct_destructor * destructor) +{ + clist * struct_list; + size_t cur_token; + void * value; + size_t final_token; + int r; + int res; + + cur_token = * index; + + r = parser(message, length, &cur_token, &value); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto err; + } + + struct_list = clist_new(); + if (struct_list == NULL) { + destructor(value); + res = MAILIMF_ERROR_MEMORY; + goto err; + } + + r = clist_append(struct_list, value); + if (r < 0) { + destructor(value); + res = MAILIMF_ERROR_MEMORY; + goto free; + } + + final_token = cur_token; + + while (1) { + r = mailimf_unstrict_char_parse(message, length, &cur_token, symbol); + if (r != MAILIMF_NO_ERROR) { + if (r == MAILIMF_ERROR_PARSE) + break; + else { + res = r; + goto free; + } + } + + r = parser(message, length, &cur_token, &value); + if (r != MAILIMF_NO_ERROR) { + if (r == MAILIMF_ERROR_PARSE) + break; + else { + res = r; + goto free; + } + } + + r = clist_append(struct_list, value); + if (r < 0) { + destructor(value); + res = MAILIMF_ERROR_MEMORY; + goto free; + } + + final_token = cur_token; + } + + * result = struct_list; + * index = final_token; + + return MAILIMF_NO_ERROR; + + free: + clist_foreach(struct_list, (clist_func) destructor, NULL); + clist_free(struct_list); + err: + return res; +} + +static inline int mailimf_wsp_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; + + if ((message[cur_token] != ' ') && (message[cur_token] != '\t')) + return MAILIMF_ERROR_PARSE; + + cur_token ++; + * index = cur_token; + + return MAILIMF_NO_ERROR; +} + + +int mailimf_crlf_parse(const char * message, size_t length, size_t * index) +{ + size_t cur_token; + int r; + + cur_token = * index; + + r = mailimf_char_parse(message, length, &cur_token, '\r'); + if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) + return r; + + r = mailimf_char_parse(message, length, &cur_token, '\n'); + if (r != MAILIMF_NO_ERROR) + return r; + + * index = cur_token; + return MAILIMF_NO_ERROR; +} + +static int mailimf_unstrict_crlf_parse(const char * message, + size_t length, size_t * index) +{ + size_t cur_token; + int r; + + cur_token = * index; + + mailimf_cfws_parse(message, length, &cur_token); + + r = mailimf_char_parse(message, length, &cur_token, '\r'); + if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) + return r; + + r = mailimf_char_parse(message, length, &cur_token, '\n'); + if (r != MAILIMF_NO_ERROR) + return r; + + * index = cur_token; + return MAILIMF_NO_ERROR; +} + +/* ************************************************************************ */ + + + +/* RFC 2822 grammar */ + +/* +NO-WS-CTL = %d1-8 / ; US-ASCII control characters + %d11 / ; that do not include the + %d12 / ; carriage return, line feed, + %d14-31 / ; and white space characters + %d127 +*/ + +static inline int is_no_ws_ctl(char ch) +{ + if ((ch == 9) || (ch == 10) || (ch == 13)) + return FALSE; + + if (ch == 127) + return TRUE; + + return (ch >= 1) && (ch <= 31); +} + +/* +text = %d1-9 / ; Characters excluding CR and LF + %d11 / + %d12 / + %d14-127 / + obs-text +*/ + +/* +specials = "(" / ")" / ; Special characters used in + "<" / ">" / ; other parts of the syntax + "[" / "]" / + ":" / ";" / + "@" / "\" / + "," / "." / + DQUOTE +*/ + +/* +quoted-pair = ("\" text) / obs-qp +*/ + +static inline int mailimf_quoted_pair_parse(const char * message, size_t length, + size_t * index, char * result) +{ + size_t cur_token; + + cur_token = * index; + + if (cur_token + 1 >= length) + return MAILIMF_ERROR_PARSE; + + if (message[cur_token] != '\\') + return MAILIMF_ERROR_PARSE; + + cur_token ++; + * result = message[cur_token]; + cur_token ++; + * index = cur_token; + + return MAILIMF_NO_ERROR; +} + +/* +FWS = ([*WSP CRLF] 1*WSP) / ; Folding white space + obs-FWS +*/ + +int mailimf_fws_parse(const char * message, size_t length, size_t * index) +{ + size_t cur_token; + size_t final_token; + int fws_1; + int fws_2; + int fws_3; + int r; + + cur_token = * index; + + fws_1 = FALSE; + while (1) { + r = mailimf_wsp_parse(message, length, &cur_token); + if (r != MAILIMF_NO_ERROR) { + if (r == MAILIMF_ERROR_PARSE) + break; + else + return r; + } + fws_1 = TRUE; + } + final_token = cur_token; + + r = mailimf_crlf_parse(message, length, &cur_token); + switch (r) { + case MAILIMF_NO_ERROR: + fws_2 = TRUE; + break; + case MAILIMF_ERROR_PARSE: + fws_2 = FALSE; + break; + default: + return r; + } + + fws_3 = FALSE; + if (fws_2) { + while (1) { + r = mailimf_wsp_parse(message, length, &cur_token); + if (r != MAILIMF_NO_ERROR) { + if (r == MAILIMF_ERROR_PARSE) + break; + else + return r; + } + fws_3 = TRUE; + } + } + + if ((!fws_1) && (!fws_3)) + return MAILIMF_ERROR_PARSE; + + if (!fws_3) + cur_token = final_token; + + * index = cur_token; + + return MAILIMF_NO_ERROR; +} + + +/* +ctext = NO-WS-CTL / ; Non white space controls + + %d33-39 / ; The rest of the US-ASCII + %d42-91 / ; characters not including "(", + %d93-126 ; ")", or "\" +*/ + +static inline int is_ctext(char ch) +{ + unsigned char uch = (unsigned char) ch; + + if (is_no_ws_ctl(ch)) + return TRUE; + + if (uch < 33) + return FALSE; + + if ((uch == 40) || (uch == 41)) + return FALSE; + + if (uch == 92) + return FALSE; + + if (uch == 127) + return FALSE; + + return TRUE; +} + +/* +ccontent = ctext / quoted-pair / comment +*/ + +static inline int mailimf_ccontent_parse(const char * message, size_t length, + size_t * index) +{ + size_t cur_token; + char ch; + int r; + + cur_token = * index; + + if (cur_token >= length) + return MAILIMF_ERROR_PARSE; + + if (is_ctext(message[cur_token])) { + cur_token ++; + } + else { + r = mailimf_quoted_pair_parse(message, length, &cur_token, &ch); + + if (r == MAILIMF_ERROR_PARSE) + r = mailimf_comment_parse(message, length, &cur_token); + + if (r == MAILIMF_ERROR_PARSE) + return r; + } + + * index = cur_token; + + return MAILIMF_NO_ERROR; +} + +/* +[FWS] ccontent +*/ + +static inline int +mailimf_comment_fws_ccontent_parse(const char * message, size_t length, + size_t * index) +{ + size_t cur_token; + int r; + + cur_token = * index; + + r = mailimf_fws_parse(message, length, &cur_token); + if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) + return r; + + r = mailimf_ccontent_parse(message, length, &cur_token); + if (r != MAILIMF_NO_ERROR) + return r; + + * index = cur_token; + + return MAILIMF_NO_ERROR; +} + +/* +comment = "(" *([FWS] ccontent) [FWS] ")" +*/ + +static inline int mailimf_comment_parse(const char * message, size_t length, + size_t * index) +{ + size_t cur_token; + int r; + + cur_token = * index; + + r = mailimf_oparenth_parse(message, length, &cur_token); + if (r != MAILIMF_NO_ERROR) + return r; + + while (1) { + r = mailimf_comment_fws_ccontent_parse(message, length, &cur_token); + if (r != MAILIMF_NO_ERROR) { + if (r == MAILIMF_ERROR_PARSE) + break; + else + return r; + } + } + + r = mailimf_fws_parse(message, length, &cur_token); + if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) + return r; + + r = mailimf_cparenth_parse(message, length, &cur_token); + if (r != MAILIMF_NO_ERROR) + return r; + + * index = cur_token; + + return MAILIMF_NO_ERROR; +} + +/* +[FWS] comment +*/ + +static inline int mailimf_cfws_fws_comment_parse(const char * message, size_t length, + size_t * index) +{ + size_t cur_token; + int r; + + cur_token = * index; + + r = mailimf_fws_parse(message, length, &cur_token); + if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) + return r; + + r = mailimf_comment_parse(message, length, &cur_token); + if (r != MAILIMF_NO_ERROR) + return r; + + * index = cur_token; + + return MAILIMF_NO_ERROR; +} + +/* +CFWS = *([FWS] comment) (([FWS] comment) / FWS) +*/ + +int mailimf_cfws_parse(const char * message, size_t length, + size_t * index) +{ + size_t cur_token; + int has_comment; + int r; + + cur_token = * index; + + has_comment = FALSE; + while (1) { + r = mailimf_cfws_fws_comment_parse(message, length, &cur_token); + if (r != MAILIMF_NO_ERROR) { + if (r == MAILIMF_ERROR_PARSE) + break; + else + return r; + } + has_comment = TRUE; + } + + if (!has_comment) { + r = mailimf_fws_parse(message, length, &cur_token); + if (r != MAILIMF_NO_ERROR) + return r; + } + + * index = cur_token; + + return MAILIMF_NO_ERROR; +} + +/* +atext = ALPHA / DIGIT / ; Any character except controls, + "!" / "#" / ; SP, and specials. + "$" / "%" / ; Used for atoms + "&" / "'" / + "*" / "+" / + "-" / "/" / + "=" / "?" / + "^" / "_" / + "`" / "{" / + "|" / "}" / + "~" +*/ + +static inline int is_atext(char ch) +{ + switch (ch) { + case ' ': + case '\t': + case '\n': + case '\r': +#if 0 + case '(': + case ')': +#endif + case '<': + case '>': +#if 0 + case '@': +#endif + case ',': + case '"': + case ':': + case ';': + return FALSE; + default: + return TRUE; + } +} + +/* +atom = [CFWS] 1*atext [CFWS] +*/ + +int mailimf_atom_parse(const char * message, size_t length, + size_t * index, char ** result) +{ + size_t cur_token; + int r; + int res; + char * atom; + size_t end; + + cur_token = * index; + + r = mailimf_cfws_parse(message, length, &cur_token); + if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) { + res = r; + goto err; + } + + end = cur_token; + if (end >= length) { + res = MAILIMF_ERROR_PARSE; + goto err; + } + + while (is_atext(message[end])) { + end ++; + if (end >= length) + break; + } + if (end == cur_token) { + res = MAILIMF_ERROR_PARSE; + goto err; + } + + atom = malloc(end - cur_token + 1); + if (atom == NULL) { + res = MAILIMF_ERROR_MEMORY; + goto err; + } + strncpy(atom, message + cur_token, end - cur_token); + atom[end - cur_token] = '\0'; + + cur_token = end; + + * index = cur_token; + * result = atom; + + return MAILIMF_NO_ERROR; + + err: + return res; +} + +int mailimf_fws_atom_parse(const char * message, size_t length, + size_t * index, char ** result) +{ + size_t cur_token; + int r; + int res; + char * atom; + size_t end; + + cur_token = * index; + + r = mailimf_fws_parse(message, length, &cur_token); + if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) { + res = r; + goto err; + } + + end = cur_token; + if (end >= length) { + res = MAILIMF_ERROR_PARSE; + goto err; + } + + while (is_atext(message[end])) { + end ++; + if (end >= length) + break; + } + if (end == cur_token) { + res = MAILIMF_ERROR_PARSE; + goto err; + } + + atom = malloc(end - cur_token + 1); + if (atom == NULL) { + res = MAILIMF_ERROR_MEMORY; + goto err; + } + strncpy(atom, message + cur_token, end - cur_token); + atom[end - cur_token] = '\0'; + + cur_token = end; + + * index = cur_token; + * result = atom; + + return MAILIMF_NO_ERROR; + + err: + return res; +} + +/* +dot-atom = [CFWS] dot-atom-text [CFWS] +*/ + +#if 0 +static int mailimf_dot_atom_parse(const char * message, size_t length, + size_t * index, char ** result) +{ + return mailimf_atom_parse(message, length, index, result); +} +#endif + +/* +dot-atom-text = 1*atext *("." 1*atext) +*/ + +#if 0 +static int +mailimf_dot_atom_text_parse(const char * message, size_t length, + size_t * index, char ** result) +{ + return mailimf_atom_parse(message, length, index, result); +} +#endif + +/* +qtext = NO-WS-CTL / ; Non white space controls + + %d33 / ; The rest of the US-ASCII + %d35-91 / ; characters not including "\" + %d93-126 ; or the quote character +*/ + +static inline int is_qtext(char ch) +{ + unsigned char uch = (unsigned char) ch; + + if (is_no_ws_ctl(ch)) + return TRUE; + + if (uch < 33) + return FALSE; + + if (uch == 34) + return FALSE; + + if (uch == 92) + return FALSE; + + if (uch == 127) + return FALSE; + + return TRUE; +} + +/* +qcontent = qtext / quoted-pair +*/ + +static int mailimf_qcontent_parse(const char * message, size_t length, + size_t * index, char * result) +{ + size_t cur_token; + char ch; + int r; + + cur_token = * index; + + if (cur_token >= length) + return MAILIMF_ERROR_PARSE; + + if (is_qtext(message[cur_token])) { + ch = message[cur_token]; + cur_token ++; + } + else { + r = mailimf_quoted_pair_parse(message, length, &cur_token, &ch); + + if (r != MAILIMF_NO_ERROR) + return r; + } + + * result = ch; + * index = cur_token; + + return MAILIMF_NO_ERROR; +} + +/* +quoted-string = [CFWS] + DQUOTE *([FWS] qcontent) [FWS] DQUOTE + [CFWS] +*/ + +int mailimf_quoted_string_parse(const char * message, size_t length, + size_t * index, char ** result) +{ + size_t cur_token; + MMAPString * gstr; + char ch; + char * str; + int r; + int res; + + cur_token = * index; + + r = mailimf_cfws_parse(message, length, &cur_token); + if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) { + res = r; + goto err; + } + + r = mailimf_dquote_parse(message, length, &cur_token); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto err; + } + + gstr = mmap_string_new(""); + if (gstr == NULL) { + res = MAILIMF_ERROR_MEMORY; + goto err; + } + +#if 0 + if (mmap_string_append_c(gstr, '\"') == NULL) { + res = MAILIMF_ERROR_MEMORY; + goto free_gstr; + } +#endif + + while (1) { + r = mailimf_fws_parse(message, length, &cur_token); + if (r == MAILIMF_NO_ERROR) { + if (mmap_string_append_c(gstr, ' ') == NULL) { + res = MAILIMF_ERROR_MEMORY; + goto free_gstr; + } + } + else if (r != MAILIMF_ERROR_PARSE) { + res = r; + goto free_gstr; + } + + r = mailimf_qcontent_parse(message, length, &cur_token, &ch); + if (r == MAILIMF_NO_ERROR) { + if (mmap_string_append_c(gstr, ch) == NULL) { + res = MAILIMF_ERROR_MEMORY; + goto free_gstr; + } + } + else if (r == MAILIMF_ERROR_PARSE) + break; + else { + res = r; + goto free_gstr; + } + } + + r = mailimf_dquote_parse(message, length, &cur_token); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto free_gstr; + } + +#if 0 + if (mmap_string_append_c(gstr, '\"') == NULL) { + res = MAILIMF_ERROR_MEMORY; + goto free_gstr; + } +#endif + + str = strdup(gstr->str); + if (str == NULL) { + res = MAILIMF_ERROR_MEMORY; + goto free_gstr; + } + mmap_string_free(gstr); + + * index = cur_token; + * result = str; + + return MAILIMF_NO_ERROR; + + free_gstr: + mmap_string_free(gstr); + err: + return res; +} + +int mailimf_fws_quoted_string_parse(const char * message, size_t length, + size_t * index, char ** result) +{ + size_t cur_token; + MMAPString * gstr; + char ch; + char * str; + int r; + int res; + + cur_token = * index; + + r = mailimf_fws_parse(message, length, &cur_token); + if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) { + res = r; + goto err; + } + + r = mailimf_dquote_parse(message, length, &cur_token); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto err; + } + + gstr = mmap_string_new(""); + if (gstr == NULL) { + res = MAILIMF_ERROR_MEMORY; + goto err; + } + +#if 0 + if (mmap_string_append_c(gstr, '\"') == NULL) { + res = MAILIMF_ERROR_MEMORY; + goto free_gstr; + } +#endif + + while (1) { + r = mailimf_fws_parse(message, length, &cur_token); + if (r == MAILIMF_NO_ERROR) { + if (mmap_string_append_c(gstr, ' ') == NULL) { + res = MAILIMF_ERROR_MEMORY; + goto free_gstr; + } + } + else if (r != MAILIMF_ERROR_PARSE) { + res = r; + goto free_gstr; + } + + r = mailimf_qcontent_parse(message, length, &cur_token, &ch); + if (r == MAILIMF_NO_ERROR) { + if (mmap_string_append_c(gstr, ch) == NULL) { + res = MAILIMF_ERROR_MEMORY; + goto free_gstr; + } + } + else if (r == MAILIMF_ERROR_PARSE) + break; + else { + res = r; + goto free_gstr; + } + } + + r = mailimf_dquote_parse(message, length, &cur_token); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto free_gstr; + } + +#if 0 + if (mmap_string_append_c(gstr, '\"') == NULL) { + res = MAILIMF_ERROR_MEMORY; + goto free_gstr; + } +#endif + + str = strdup(gstr->str); + if (str == NULL) { + res = MAILIMF_ERROR_MEMORY; + goto free_gstr; + } + mmap_string_free(gstr); + + * index = cur_token; + * result = str; + + return MAILIMF_NO_ERROR; + + free_gstr: + mmap_string_free(gstr); + err: + return res; +} + +/* +word = atom / quoted-string +*/ + +int mailimf_word_parse(const char * message, size_t length, + size_t * index, char ** result) +{ + size_t cur_token; + char * word; + int r; + + cur_token = * index; + + r = mailimf_atom_parse(message, length, &cur_token, &word); + + if (r == MAILIMF_ERROR_PARSE) + r = mailimf_quoted_string_parse(message, length, &cur_token, &word); + + if (r != MAILIMF_NO_ERROR) + return r; + + * result = word; + * index = cur_token; + + return MAILIMF_NO_ERROR; +} + +int mailimf_fws_word_parse(const char * message, size_t length, + size_t * index, char ** result) +{ + size_t cur_token; + char * word; + int r; + + cur_token = * index; + + r = mailimf_fws_atom_parse(message, length, &cur_token, &word); + + if (r == MAILIMF_ERROR_PARSE) + r = mailimf_fws_quoted_string_parse(message, length, &cur_token, &word); + + if (r != MAILIMF_NO_ERROR) + return r; + + * result = word; + * index = cur_token; + + return MAILIMF_NO_ERROR; +} + +/* +phrase = 1*word / obs-phrase +*/ + +static int mailimf_phrase_parse(const char * message, size_t length, + size_t * index, char ** result) +{ + MMAPString * gphrase; + char * word; + int first; + size_t cur_token; + int r; + int res; + char * str; + + cur_token = * index; + + gphrase = mmap_string_new(""); + if (gphrase == NULL) { + res = MAILIMF_ERROR_MEMORY; + goto err; + } + + first = TRUE; + + while (1) { + r = mailimf_fws_word_parse(message, length, &cur_token, &word); + if (r == MAILIMF_NO_ERROR) { + if (!first) { + if (mmap_string_append_c(gphrase, ' ') == NULL) { + mailimf_word_free(word); + res = MAILIMF_ERROR_MEMORY; + goto free; + } + } + if (mmap_string_append(gphrase, word) == NULL) { + mailimf_word_free(word); + res = MAILIMF_ERROR_MEMORY; + goto free; + } + mailimf_word_free(word); + first = FALSE; + } + else if (r == MAILIMF_ERROR_PARSE) + break; + else { + res = r; + goto free; + } + } + + if (first) { + res = MAILIMF_ERROR_PARSE; + goto free; + } + + str = strdup(gphrase->str); + if (str == NULL) { + res = MAILIMF_ERROR_MEMORY; + goto free; + } + mmap_string_free(gphrase); + + * result = str; + * index = cur_token; + + return MAILIMF_NO_ERROR; + + free: + mmap_string_free(gphrase); + err: + return res; +} + +/* +utext = NO-WS-CTL / ; Non white space controls + %d33-126 / ; The rest of US-ASCII + obs-utext + +added : WSP +*/ + +enum { + UNSTRUCTURED_START, + UNSTRUCTURED_CR, + UNSTRUCTURED_LF, + UNSTRUCTURED_WSP, + UNSTRUCTURED_OUT +}; + +static int mailimf_unstructured_parse(const char * message, size_t length, + size_t * index, char ** result) +{ + size_t cur_token; + int state; + size_t begin; + size_t terminal; + char * str; + + cur_token = * index; + + + while (1) { + int r; + + r = mailimf_wsp_parse(message, length, &cur_token); + if (r == MAILIMF_NO_ERROR) { + /* do nothing */ + } + else if (r == MAILIMF_ERROR_PARSE) + break; + else { + return r; + } + } + + state = UNSTRUCTURED_START; + begin = cur_token; + terminal = cur_token; + + while (state != UNSTRUCTURED_OUT) { + + switch(state) { + case UNSTRUCTURED_START: + if (cur_token >= length) + return MAILIMF_ERROR_PARSE; + + terminal = cur_token; + switch(message[cur_token]) { + case '\r': + state = UNSTRUCTURED_CR; + break; + case '\n': + state = UNSTRUCTURED_LF; + break; + default: + state = UNSTRUCTURED_START; + break; + } + break; + case UNSTRUCTURED_CR: + if (cur_token >= length) + return MAILIMF_ERROR_PARSE; + + switch(message[cur_token]) { + case '\n': + state = UNSTRUCTURED_LF; + break; + default: + state = UNSTRUCTURED_START; + break; + } + break; + + case UNSTRUCTURED_LF: + if (cur_token >= length) { + state = UNSTRUCTURED_OUT; + break; + } + + switch(message[cur_token]) { + case '\t': + case ' ': + state = UNSTRUCTURED_WSP; + break; + default: + state = UNSTRUCTURED_OUT; + break; + } + break; + case UNSTRUCTURED_WSP: + if (cur_token >= length) + return MAILIMF_ERROR_PARSE; + + switch(message[cur_token]) { + case '\r': + state = UNSTRUCTURED_CR; + break; + case '\n': + state = UNSTRUCTURED_LF; + break; + default: + state = UNSTRUCTURED_START; + break; + } + break; + } + + cur_token ++; + } + + str = malloc(terminal - begin + 1); + if (str == NULL) + return MAILIMF_ERROR_MEMORY; + strncpy(str, message + begin, terminal - begin); + str[terminal - begin] = '\0'; + + * index = terminal; + * result = str; + + return MAILIMF_NO_ERROR; +} + + +static int mailimf_ignore_unstructured_parse(const char * message, size_t length, + size_t * index) +{ + size_t cur_token; + int state; + size_t terminal; + + cur_token = * index; + + state = UNSTRUCTURED_START; + terminal = cur_token; + + while (state != UNSTRUCTURED_OUT) { + + switch(state) { + case UNSTRUCTURED_START: + if (cur_token >= length) + return MAILIMF_ERROR_PARSE; + terminal = cur_token; + switch(message[cur_token]) { + case '\r': + state = UNSTRUCTURED_CR; + break; + case '\n': + state = UNSTRUCTURED_LF; + break; + default: + state = UNSTRUCTURED_START; + break; + } + break; + case UNSTRUCTURED_CR: + if (cur_token >= length) + return MAILIMF_ERROR_PARSE; + switch(message[cur_token]) { + case '\n': + state = UNSTRUCTURED_LF; + break; + default: + state = UNSTRUCTURED_START; + break; + } + break; + case UNSTRUCTURED_LF: + if (cur_token >= length) { + state = UNSTRUCTURED_OUT; + break; + } + switch(message[cur_token]) { + case '\t': + case ' ': + state = UNSTRUCTURED_WSP; + break; + default: + state = UNSTRUCTURED_OUT; + break; + } + break; + case UNSTRUCTURED_WSP: + if (cur_token >= length) + return MAILIMF_ERROR_PARSE; + switch(message[cur_token]) { + case '\r': + state = UNSTRUCTURED_CR; + break; + case '\n': + state = UNSTRUCTURED_LF; + break; + default: + state = UNSTRUCTURED_START; + break; + } + break; + } + + cur_token ++; + } + + * index = terminal; + + return MAILIMF_NO_ERROR; +} + + +int mailimf_ignore_field_parse(const char * message, size_t length, + size_t * index) +{ + int has_field; + size_t cur_token; + int state; + size_t terminal; + + has_field = FALSE; + cur_token = * index; + + terminal = cur_token; + state = UNSTRUCTURED_START; + + /* check if this is not a beginning CRLF */ + + if (cur_token >= length) + return MAILIMF_ERROR_PARSE; + + switch (message[cur_token]) { + case '\r': + return MAILIMF_ERROR_PARSE; + case '\n': + return MAILIMF_ERROR_PARSE; + } + + while (state != UNSTRUCTURED_OUT) { + + switch(state) { + case UNSTRUCTURED_START: + if (cur_token >= length) + return MAILIMF_ERROR_PARSE; + + switch(message[cur_token]) { + case '\r': + state = UNSTRUCTURED_CR; + break; + case '\n': + state = UNSTRUCTURED_LF; + break; + case ':': + has_field = TRUE; + state = UNSTRUCTURED_START; + break; + default: + state = UNSTRUCTURED_START; + break; + } + break; + case UNSTRUCTURED_CR: + if (cur_token >= length) + return MAILIMF_ERROR_PARSE; + + switch(message[cur_token]) { + case '\n': + state = UNSTRUCTURED_LF; + break; + case ':': + has_field = TRUE; + state = UNSTRUCTURED_START; + break; + default: + state = UNSTRUCTURED_START; + break; + } + break; + case UNSTRUCTURED_LF: + if (cur_token >= length) { + terminal = cur_token; + state = UNSTRUCTURED_OUT; + break; + } + + switch(message[cur_token]) { + case '\t': + case ' ': + state = UNSTRUCTURED_WSP; + break; + default: + terminal = cur_token; + state = UNSTRUCTURED_OUT; + break; + } + break; + case UNSTRUCTURED_WSP: + if (cur_token >= length) + return MAILIMF_ERROR_PARSE; + + switch(message[cur_token]) { + case '\r': + state = UNSTRUCTURED_CR; + break; + case '\n': + state = UNSTRUCTURED_LF; + break; + case ':': + has_field = TRUE; + state = UNSTRUCTURED_START; + break; + default: + state = UNSTRUCTURED_START; + break; + } + break; + } + + cur_token ++; + } + + if (!has_field) + return MAILIMF_ERROR_PARSE; + + * index = terminal; + + return MAILIMF_NO_ERROR; +} + + +/* +date-time = [ day-of-week "," ] date FWS time [CFWS] +*/ + +int mailimf_date_time_parse(const char * message, size_t length, + size_t * index, + struct mailimf_date_time ** result) +{ + size_t cur_token; + int day_of_week; + struct mailimf_date_time * date_time; + int day; + int month; + int year; + int hour; + int min; + int sec; + int zone; + int r; + + cur_token = * index; + + day_of_week = -1; + r = mailimf_day_of_week_parse(message, length, &cur_token, &day_of_week); + if (r == MAILIMF_NO_ERROR) { + r = mailimf_comma_parse(message, length, &cur_token); + if (r != MAILIMF_NO_ERROR) + return r; + } + else if (r != MAILIMF_ERROR_PARSE) + return r; + + r = mailimf_date_parse(message, length, &cur_token, &day, &month, &year); + if (r != MAILIMF_NO_ERROR) + return r; + + r = mailimf_fws_parse(message, length, &cur_token); + if (r != MAILIMF_NO_ERROR) + return r; + + r = mailimf_time_parse(message, length, &cur_token, + &hour, &min, &sec, &zone); + if (r != MAILIMF_NO_ERROR) + return r; + + date_time = mailimf_date_time_new(day, month, year, hour, min, sec, zone); + if (date_time == NULL) + return MAILIMF_ERROR_MEMORY; + + * index = cur_token; + * result = date_time; + + return MAILIMF_NO_ERROR; +} + +/* +day-of-week = ([FWS] day-name) / obs-day-of-week +*/ + +static int mailimf_day_of_week_parse(const char * message, size_t length, + size_t * index, int * result) +{ + size_t cur_token; + int day_of_week; + int r; + + cur_token = * index; + + r = mailimf_cfws_parse(message, length, &cur_token); + if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) + return r; + + r = mailimf_day_name_parse(message, length, &cur_token, &day_of_week); + if (r != MAILIMF_NO_ERROR) + return r; + + * index = cur_token; + * result = day_of_week; + + return MAILIMF_NO_ERROR; +} + +/* +day-name = "Mon" / "Tue" / "Wed" / "Thu" / + "Fri" / "Sat" / "Sun" +*/ + +struct mailimf_token_value { + int value; + char * str; +}; + +static struct mailimf_token_value day_names[] = { + {1, "Mon"}, + {2, "Tue"}, + {3, "Wed"}, + {4, "Thu"}, + {5, "Fri"}, + {6, "Sat"}, + {7, "Sun"}, +}; + +enum { + DAY_NAME_START, + DAY_NAME_T, + DAY_NAME_S +}; + +static int guess_day_name(const char * message, size_t length, size_t index) +{ + int state; + + state = DAY_NAME_START; + + while (1) { + + if (index >= length) + return -1; + + switch(state) { + case DAY_NAME_START: + switch((char) toupper((unsigned char) message[index])) { + case 'M': /* Mon */ + return 1; + break; + case 'T': /* Tue Thu */ + state = DAY_NAME_T; + break; + case 'W': /* Wed */ + return 3; + case 'F': + return 5; + case 'S': /* Sat Sun */ + state = DAY_NAME_S; + break; + default: + return -1; + } + break; + case DAY_NAME_T: + switch((char) toupper((unsigned char) message[index])) { + case 'U': + return 2; + case 'H': + return 4; + default: + return -1; + } + break; + case DAY_NAME_S: + switch((char) toupper((unsigned char) message[index])) { + case 'A': + return 6; + case 'U': + return 7; + default: + return -1; + } + break; + } + + index ++; + } +} + +static int mailimf_day_name_parse(const char * message, size_t length, + size_t * index, int * result) +{ + size_t cur_token; + int day_of_week; + int guessed_day; + int r; + + cur_token = * index; + + guessed_day = guess_day_name(message, length, cur_token); + if (guessed_day == -1) + return MAILIMF_ERROR_PARSE; + + r = mailimf_token_case_insensitive_parse(message, length, + &cur_token, + day_names[guessed_day - 1].str); + if (r != MAILIMF_NO_ERROR) + return r; + + day_of_week = guessed_day; + + * result = day_of_week; + * index = cur_token; + + return MAILIMF_NO_ERROR; +} + +/* +date = day month year +*/ + +static int mailimf_date_parse(const char * message, size_t length, + size_t * index, + int * pday, int * pmonth, int * pyear) +{ + size_t cur_token; + int day; + int month; + int year; + int r; + + cur_token = * index; + + r = mailimf_day_parse(message, length, &cur_token, &day); + if (r != MAILIMF_NO_ERROR) + return r; + + r = mailimf_month_parse(message, length, &cur_token, &month); + if (r != MAILIMF_NO_ERROR) + return r; + + r = mailimf_year_parse(message, length, &cur_token, &year); + if (r != MAILIMF_NO_ERROR) + return r; + + * pday = day; + * pmonth = month; + * pyear = year; + + * index = cur_token; + + return MAILIMF_NO_ERROR; +} + +/* +year = 4*DIGIT / obs-year +*/ + +static int mailimf_year_parse(const char * message, size_t length, + size_t * index, int * result) +{ + uint32_t number; + size_t cur_token; + int r; + + cur_token = * index; + + 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, &number); + if (r != MAILIMF_NO_ERROR) + return r; + + * index = cur_token; + * result = number; + + return MAILIMF_NO_ERROR; +} + +/* +month = (FWS month-name FWS) / obs-month +*/ + +static int mailimf_month_parse(const char * message, size_t length, + size_t * index, int * result) +{ + size_t cur_token; + int month; + int r; + + cur_token = * index; + + r = mailimf_cfws_parse(message, length, &cur_token); + if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) + return r; + + r = mailimf_month_name_parse(message, length, &cur_token, &month); + if (r != MAILIMF_NO_ERROR) + return r; + + * result = month; + * index = cur_token; + + return MAILIMF_NO_ERROR; +} + +/* +month-name = "Jan" / "Feb" / "Mar" / "Apr" / + "May" / "Jun" / "Jul" / "Aug" / + "Sep" / "Oct" / "Nov" / "Dec" +*/ + +static struct mailimf_token_value month_names[] = { + {1, "Jan"}, + {2, "Feb"}, + {3, "Mar"}, + {4, "Apr"}, + {5, "May"}, + {6, "Jun"}, + {7, "Jul"}, + {8, "Aug"}, + {9, "Sep"}, + {10, "Oct"}, + {11, "Nov"}, + {12, "Dec"}, +}; + +enum { + MONTH_START, + MONTH_J, + MONTH_JU, + MONTH_M, + MONTH_MA, + MONTH_A +}; + +static int guess_month(const char * message, size_t length, size_t index) +{ + int state; + + state = MONTH_START; + + while (1) { + + if (index >= length) + return -1; + + switch(state) { + case MONTH_START: + switch((char) toupper((unsigned char) message[index])) { + case 'J': /* Jan Jun Jul */ + state = MONTH_J; + break; + case 'F': /* Feb */ + return 2; + case 'M': /* Mar May */ + state = MONTH_M; + break; + case 'A': /* Apr Aug */ + state = MONTH_A; + break; + case 'S': /* Sep */ + return 9; + case 'O': /* Oct */ + return 10; + case 'N': /* Nov */ + return 11; + case 'D': /* Dec */ + return 12; + default: + return -1; + } + break; + case MONTH_J: + switch((char) toupper((unsigned char) message[index])) { + case 'A': + return 1; + case 'U': + state = MONTH_JU; + break; + default: + return -1; + } + break; + case MONTH_JU: + switch((char) toupper((unsigned char) message[index])) { + case 'N': + return 6; + case 'L': + return 7; + default: + return -1; + } + break; + case MONTH_M: + switch((char) toupper((unsigned char) message[index])) { + case 'A': + state = MONTH_MA; + break; + default: + return -1; + } + break; + case MONTH_MA: + switch((char) toupper((unsigned char) message[index])) { + case 'Y': + return 5; + case 'R': + return 3; + default: + return -1; + } + break; + case MONTH_A: + switch((char) toupper((unsigned char) message[index])) { + case 'P': + return 4; + case 'U': + return 8; + default: + return -1; + } + break; + } + + index ++; + } +} + +static int mailimf_month_name_parse(const char * message, size_t length, + size_t * index, int * result) +{ + size_t cur_token; + int month; + int guessed_month; + int r; + + cur_token = * index; + + guessed_month = guess_month(message, length, cur_token); + if (guessed_month == -1) + return MAILIMF_ERROR_PARSE; + + r = mailimf_token_case_insensitive_parse(message, length, + &cur_token, + month_names[guessed_month - 1].str); + if (r != MAILIMF_NO_ERROR) + return r; + + month = guessed_month; + + * result = month; + * index = cur_token; + + return MAILIMF_NO_ERROR; +} + +/* +day = ([FWS] 1*2DIGIT) / obs-day +*/ + +static int mailimf_day_parse(const char * message, size_t length, + size_t * index, int * result) +{ + size_t cur_token; + uint32_t day; + int r; + + cur_token = * index; + + 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, &day); + if (r != MAILIMF_NO_ERROR) + return r; + + * result = day; + * index = cur_token; + + return MAILIMF_NO_ERROR; +} + +/* +time = time-of-day FWS zone +*/ + +static int mailimf_time_parse(const char * message, size_t length, + size_t * index, + int * phour, int * pmin, + int * psec, + int * pzone) +{ + size_t cur_token; + int hour; + int min; + int sec; + int zone; + int r; + + cur_token = * index; + + r = mailimf_cfws_parse(message, length, &cur_token); + if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) + return r; + + r = mailimf_time_of_day_parse(message, length, &cur_token, + &hour, &min, &sec); + if (r != MAILIMF_NO_ERROR) + return r; + + r = mailimf_fws_parse(message, length, &cur_token); + if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) + return r; + + r = mailimf_zone_parse(message, length, &cur_token, &zone); + if (r == MAILIMF_NO_ERROR) { + /* do nothing */ + } + else if (r == MAILIMF_ERROR_PARSE) { + zone = 0; + } + else { + return r; + } + + * phour = hour; + * pmin = min; + * psec = sec; + * pzone = zone; + + * index = cur_token; + + return MAILIMF_NO_ERROR; +} + +/* +time-of-day = hour ":" minute [ ":" second ] +*/ + +static int mailimf_time_of_day_parse(const char * message, size_t length, + size_t * index, + int * phour, int * pmin, + int * psec) +{ + int hour; + int min; + int sec; + size_t cur_token; + int r; + + cur_token = * index; + + r = mailimf_hour_parse(message, length, &cur_token, &hour); + if (r != MAILIMF_NO_ERROR) + return r; + + r = mailimf_colon_parse(message, length, &cur_token); + if (r != MAILIMF_NO_ERROR) + return r; + + r = mailimf_minute_parse(message, length, &cur_token, &min); + if (r != MAILIMF_NO_ERROR) + return r; + + r = mailimf_colon_parse(message, length, &cur_token); + if (r == MAILIMF_NO_ERROR) { + r = mailimf_second_parse(message, length, &cur_token, &sec); + if (r != MAILIMF_NO_ERROR) + return r; + } + else if (r == MAILIMF_ERROR_PARSE) + sec = 0; + else + return r; + + * phour = hour; + * pmin = min; + * psec = sec; + * index = cur_token; + + return MAILIMF_NO_ERROR; +} + +/* +hour = 2DIGIT / obs-hour +*/ + +static int mailimf_hour_parse(const char * message, size_t length, + size_t * index, int * result) +{ + uint32_t hour; + int r; + + r = mailimf_number_parse(message, length, index, &hour); + if (r != MAILIMF_NO_ERROR) + return r; + + * result = hour; + + return MAILIMF_NO_ERROR; +} + +/* +minute = 2DIGIT / obs-minute +*/ + +static int mailimf_minute_parse(const char * message, size_t length, + size_t * index, int * result) +{ + uint32_t minute; + int r; + + r = mailimf_number_parse(message, length, index, &minute); + if (r != MAILIMF_NO_ERROR) + return r; + + * result = minute; + + return MAILIMF_NO_ERROR; +} + +/* +second = 2DIGIT / obs-second +*/ + +static int mailimf_second_parse(const char * message, size_t length, + size_t * index, int * result) +{ + uint32_t second; + int r; + + r = mailimf_number_parse(message, length, index, &second); + if (r != MAILIMF_NO_ERROR) + return r; + + * result = second; + + return MAILIMF_NO_ERROR; +} + +/* +zone = (( "+" / "-" ) 4DIGIT) / obs-zone +*/ + +/* +obs-zone = "UT" / "GMT" / ; Universal Time + ; North American UT + ; offsets + "EST" / "EDT" / ; Eastern: - 5/ - 4 + "CST" / "CDT" / ; Central: - 6/ - 5 + "MST" / "MDT" / ; Mountain: - 7/ - 6 + "PST" / "PDT" / ; Pacific: - 8/ - 7 + + %d65-73 / ; Military zones - "A" + %d75-90 / ; through "I" and "K" + %d97-105 / ; through "Z", both + %d107-122 ; upper and lower case +*/ + +enum { + STATE_ZONE_1 = 0, + STATE_ZONE_2 = 1, + STATE_ZONE_3 = 2, + STATE_ZONE_OK = 3, + STATE_ZONE_ERR = 4, + STATE_ZONE_CONT = 5, +}; + +static int mailimf_zone_parse(const char * message, size_t length, + size_t * index, int * result) +{ + uint32_t zone; + int sign; + size_t cur_token; + int r; + + cur_token = * index; + + if (cur_token + 1 < length) { + if ((message[cur_token] == 'U') && (message[cur_token] == 'T')) { + * result = TRUE; + * index = cur_token + 2; + + return MAILIMF_NO_ERROR; + } + } + + if (cur_token + 2 < length) { + int state; + + state = STATE_ZONE_1; + + while (state <= 2) { + switch (state) { + case STATE_ZONE_1: + switch (message[cur_token]) { + case 'G': + if (message[cur_token + 1] == 'M' && message[cur_token + 2] == 'T') { + zone = 0; + state = STATE_ZONE_OK; + } + else { + state = STATE_ZONE_ERR; + } + break; + case 'E': + zone = -5; + state = STATE_ZONE_2; + break; + case 'C': + zone = -6; + state = STATE_ZONE_2; + break; + case 'M': + zone = -7; + state = STATE_ZONE_2; + break; + case 'P': + zone = -8; + state = STATE_ZONE_2; + break; + default: + state = STATE_ZONE_CONT; + break; + } + break; + case STATE_ZONE_2: + switch (message[cur_token + 1]) { + case 'S': + state = STATE_ZONE_3; + break; + case 'D': + zone ++; + state = STATE_ZONE_3; + break; + default: + state = STATE_ZONE_ERR; + break; + } + break; + case STATE_ZONE_3: + if (message[cur_token + 2] == 'T') { + zone *= 100; + state = STATE_ZONE_OK; + } + else + state = STATE_ZONE_ERR; + break; + } + } + + switch (state) { + case STATE_ZONE_OK: + * result = zone; + * index = cur_token + 3; + return MAILIMF_NO_ERROR; + + case STATE_ZONE_ERR: + return MAILIMF_ERROR_PARSE; + } + } + + sign = 1; + r = mailimf_plus_parse(message, length, &cur_token); + if (r == MAILIMF_NO_ERROR) + sign = 1; + + if (r == MAILIMF_ERROR_PARSE) { + r = mailimf_minus_parse(message, length, &cur_token); + if (r == MAILIMF_NO_ERROR) + sign = -1; + } + + if (r == MAILIMF_NO_ERROR) { + /* do nothing */ + } + else if (r == MAILIMF_ERROR_PARSE) + sign = 1; + else + return r; + + r = mailimf_number_parse(message, length, &cur_token, &zone); + if (r != MAILIMF_NO_ERROR) + return r; + + zone = zone * sign; + + * index = cur_token; + * result = zone; + + return MAILIMF_NO_ERROR; +} + +/* +address = mailbox / group +*/ + +int mailimf_address_parse(const char * message, size_t length, + size_t * index, + struct mailimf_address ** result) +{ + int type; + size_t cur_token; + struct mailimf_mailbox * mailbox; + struct mailimf_group * group; + struct mailimf_address * address; + int r; + int res; + + cur_token = * index; + + mailbox = NULL; + group = NULL; + + type = MAILIMF_ADDRESS_ERROR; /* XXX - removes a gcc warning */ + r = mailimf_group_parse(message, length, &cur_token, &group); + if (r == MAILIMF_NO_ERROR) + type = MAILIMF_ADDRESS_GROUP; + + if (r == MAILIMF_ERROR_PARSE) { + r = mailimf_mailbox_parse(message, length, &cur_token, &mailbox); + if (r == MAILIMF_NO_ERROR) + type = MAILIMF_ADDRESS_MAILBOX; + } + + if (r != MAILIMF_NO_ERROR) { + res = r; + goto err; + } + + address = mailimf_address_new(type, mailbox, group); + if (address == NULL) { + res = MAILIMF_ERROR_MEMORY; + goto free; + } + + * result = address; + * index = cur_token; + + return MAILIMF_NO_ERROR; + + free: + if (mailbox != NULL) + mailimf_mailbox_free(mailbox); + if (group != NULL) + mailimf_group_free(group); + err: + return res; +} + + +/* +mailbox = name-addr / addr-spec +*/ + + +int mailimf_mailbox_parse(const char * message, size_t length, + size_t * index, + struct mailimf_mailbox ** result) +{ + size_t cur_token; + char * display_name; + struct mailimf_mailbox * mailbox; + char * addr_spec; + int r; + int res; + + cur_token = * index; + display_name = NULL; + addr_spec = NULL; + + r = mailimf_name_addr_parse(message, length, &cur_token, + &display_name, &addr_spec); + if (r == MAILIMF_ERROR_PARSE) + r = mailimf_addr_spec_parse(message, length, &cur_token, &addr_spec); + + if (r != MAILIMF_NO_ERROR) { + res = r; + goto err; + } + + mailbox = mailimf_mailbox_new(display_name, addr_spec); + if (mailbox == NULL) { + res = MAILIMF_ERROR_MEMORY; + goto free; + } + + * result = mailbox; + * index = cur_token; + + return MAILIMF_NO_ERROR; + + free: + if (display_name != NULL) + mailimf_display_name_free(display_name); + if (addr_spec != NULL) + mailimf_addr_spec_free(addr_spec); + err: + return res; +} + +/* +name-addr = [display-name] angle-addr +*/ + +static int mailimf_name_addr_parse(const char * message, size_t length, + size_t * index, + char ** pdisplay_name, + char ** pangle_addr) +{ + char * display_name; + char * angle_addr; + size_t cur_token; + int r; + int res; + + cur_token = * index; + + display_name = NULL; + angle_addr = NULL; + + r = mailimf_display_name_parse(message, length, &cur_token, &display_name); + if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) { + res = r; + goto err; + } + + r = mailimf_angle_addr_parse(message, length, &cur_token, &angle_addr); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto free_display_name; + } + + * pdisplay_name = display_name; + * pangle_addr = angle_addr; + * index = cur_token; + + return MAILIMF_NO_ERROR; + + free_display_name: + if (display_name != NULL) + mailimf_display_name_free(display_name); + err: + return res; +} + +/* +angle-addr = [CFWS] "<" addr-spec ">" [CFWS] / obs-angle-addr +*/ + +static int mailimf_angle_addr_parse(const char * message, size_t length, + size_t * index, char ** result) +{ + size_t cur_token; + char * addr_spec; + int r; + + cur_token = * index; + + r = mailimf_cfws_parse(message, length, &cur_token); + if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) + return r; + + r = mailimf_lower_parse(message, length, &cur_token); + if (r != MAILIMF_NO_ERROR) + return r; + + r = mailimf_addr_spec_parse(message, length, &cur_token, &addr_spec); + if (r != MAILIMF_NO_ERROR) + return r; + + r = mailimf_greater_parse(message, length, &cur_token); + if (r != MAILIMF_NO_ERROR) { + free(addr_spec); + return r; + } + + * result = addr_spec; + * index = cur_token; + + return MAILIMF_NO_ERROR; +} + +/* +group = display-name ":" [mailbox-list / CFWS] ";" + [CFWS] +*/ + +static int mailimf_group_parse(const char * message, size_t length, + size_t * index, + struct mailimf_group ** result) +{ + size_t cur_token; + char * display_name; + struct mailimf_mailbox_list * mailbox_list; + struct mailimf_group * group; + int r; + int res; + + cur_token = * index; + + mailbox_list = NULL; + + r = mailimf_display_name_parse(message, length, &cur_token, &display_name); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto err; + } + + r = mailimf_colon_parse(message, length, &cur_token); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto free_display_name; + } + + r = mailimf_mailbox_list_parse(message, length, &cur_token, &mailbox_list); + switch (r) { + case MAILIMF_NO_ERROR: + break; + case MAILIMF_ERROR_PARSE: + r = mailimf_cfws_parse(message, length, &cur_token); + if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) + return r; + break; + default: + return r; + } + + r = mailimf_semi_colon_parse(message, length, &cur_token); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto free_mailbox_list; + } + + group = mailimf_group_new(display_name, mailbox_list); + if (group == NULL) { + res = MAILIMF_ERROR_MEMORY; + goto free_mailbox_list; + } + + * index = cur_token; + * result = group; + + return MAILIMF_NO_ERROR; + + free_mailbox_list: + mailimf_mailbox_list_free(mailbox_list); + free_display_name: + mailimf_display_name_free(display_name); + err: + return res; +} + +/* +display-name = phrase +*/ + +static int mailimf_display_name_parse(const char * message, size_t length, + size_t * index, char ** result) +{ + return mailimf_phrase_parse(message, length, index, result); +} + +/* +mailbox-list = (mailbox *("," mailbox)) / obs-mbox-list +*/ + +int +mailimf_mailbox_list_parse(const char * message, size_t length, + size_t * index, + struct mailimf_mailbox_list ** result) +{ + size_t cur_token; + clist * list; + struct mailimf_mailbox_list * mailbox_list; + int r; + int res; + + cur_token = * index; + + r = mailimf_struct_list_parse(message, length, + &cur_token, &list, ',', + (mailimf_struct_parser *) + mailimf_mailbox_parse, + (mailimf_struct_destructor *) + mailimf_mailbox_free); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto err; + } + + mailbox_list = mailimf_mailbox_list_new(list); + if (mailbox_list == NULL) { + res = MAILIMF_ERROR_MEMORY; + goto free_list; + } + + * result = mailbox_list; + * index = cur_token; + + return MAILIMF_NO_ERROR; + + free_list: + clist_foreach(list, (clist_func) mailimf_mailbox_free, NULL); + clist_free(list); + err: + return res; +} + +/* +address-list = (address *("," address)) / obs-addr-list +*/ + + +int +mailimf_address_list_parse(const char * message, size_t length, + size_t * index, + struct mailimf_address_list ** result) +{ + size_t cur_token; + clist * list; + struct mailimf_address_list * address_list; + int r; + int res; + + cur_token = * index; + + r = mailimf_struct_list_parse(message, length, + &cur_token, &list, ',', + (mailimf_struct_parser *) + mailimf_address_parse, + (mailimf_struct_destructor *) + mailimf_address_free); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto err; + } + + address_list = mailimf_address_list_new(list); + if (address_list == NULL) { + res = MAILIMF_ERROR_MEMORY; + goto free_list; + } + + * result = address_list; + * index = cur_token; + + return MAILIMF_NO_ERROR; + + free_list: + clist_foreach(list, (clist_func) mailimf_address_free, NULL); + clist_free(list); + err: + return res; +} + +/* +addr-spec = local-part "@" domain +*/ + + +static int mailimf_addr_spec_parse(const char * message, size_t length, + size_t * index, + char ** result) +{ + size_t cur_token; +#if 0 + char * local_part; + char * domain; +#endif + char * addr_spec; + int r; + int res; + size_t begin; + size_t end; + int final; + size_t count; + const char * src; + char * dest; + size_t i; + + cur_token = * index; + + r = mailimf_cfws_parse(message, length, &cur_token); + if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) { + res = r; + goto err; + } + + end = cur_token; + if (end >= length) { + res = MAILIMF_ERROR_PARSE; + goto err; + } + + begin = cur_token; + + final = FALSE; + while (1) { + switch (message[end]) { + case '>': + case ',': + case '\r': + case '\n': + case '(': + case ')': + case ':': + case ';': + final = TRUE; + break; + } + + if (final) + break; + + end ++; + if (end >= length) + break; + } + + if (end == begin) { + res = MAILIMF_ERROR_PARSE; + goto err; + } + + addr_spec = malloc(end - cur_token + 1); + if (addr_spec == NULL) { + res = MAILIMF_ERROR_MEMORY; + goto err; + } + + count = end - cur_token; + src = message + cur_token; + dest = addr_spec; + for(i = 0 ; i < count ; i ++) { + if ((* src != ' ') && (* src != '\t')) { + * dest = * src; + dest ++; + } + src ++; + } + * dest = '\0'; + +#if 0 + strncpy(addr_spec, message + cur_token, end - cur_token); + addr_spec[end - cur_token] = '\0'; +#endif + + cur_token = end; + +#if 0 + r = mailimf_local_part_parse(message, length, &cur_token, &local_part); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto err; + } + + r = mailimf_at_sign_parse(message, length, &cur_token); + switch (r) { + case MAILIMF_NO_ERROR: + r = mailimf_domain_parse(message, length, &cur_token, &domain); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto free_local_part; + } + break; + + case MAILIMF_ERROR_PARSE: + domain = NULL; + break; + + default: + res = r; + goto free_local_part; + } + + if (domain) { + addr_spec = malloc(strlen(local_part) + strlen(domain) + 2); + if (addr_spec == NULL) { + res = MAILIMF_ERROR_MEMORY; + goto free_domain; + } + + strcpy(addr_spec, local_part); + strcat(addr_spec, "@"); + strcat(addr_spec, domain); + + mailimf_domain_free(domain); + mailimf_local_part_free(local_part); + } + else { + addr_spec = local_part; + } +#endif + + * result = addr_spec; + * index = cur_token; + + return MAILIMF_NO_ERROR; + +#if 0 + free_domain: + mailimf_domain_free(domain); + free_local_part: + mailimf_local_part_free(local_part); +#endif + err: + return res; +} + +/* +local-part = dot-atom / quoted-string / obs-local-part +*/ + +#if 0 +static int mailimf_local_part_parse(const char * message, size_t length, + size_t * index, + char ** result) +{ + int r; + + r = mailimf_dot_atom_parse(message, length, index, result); + switch (r) { + case MAILIMF_NO_ERROR: + return r; + case MAILIMF_ERROR_PARSE: + break; + default: + return r; + } + + r = mailimf_quoted_string_parse(message, length, index, result); + if (r != MAILIMF_NO_ERROR) + return r; + + return MAILIMF_NO_ERROR; +} +#endif + +/* +domain = dot-atom / domain-literal / obs-domain +*/ + +#if 0 +static int mailimf_domain_parse(const char * message, size_t length, + size_t * index, + char ** result) +{ + int r; + + r = mailimf_dot_atom_parse(message, length, index, result); + switch (r) { + case MAILIMF_NO_ERROR: + return r; + case MAILIMF_ERROR_PARSE: + break; + default: + return r; + } + + r = mailimf_domain_literal_parse(message, length, index, result); + if (r != MAILIMF_NO_ERROR) + return r; + + return MAILIMF_NO_ERROR; +} +#endif + +/* +[FWS] dcontent +*/ + +#if 0 +static int +mailimf_domain_literal_fws_dcontent_parse(const char * message, size_t length, + size_t * index) +{ + size_t cur_token; + char ch; + int r; + + cur_token = * index; + + r = mailimf_cfws_parse(message, length, &cur_token); + if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) + return r; + + r = mailimf_dcontent_parse(message, length, &cur_token, &ch); + if (r != MAILIMF_NO_ERROR) + return r; + + * index = cur_token; + + return MAILIMF_NO_ERROR; +} +#endif + +/* +domain-literal = [CFWS] "[" *([FWS] dcontent) [FWS] "]" [CFWS] +*/ + +#if 0 +static int mailimf_domain_literal_parse(const char * message, size_t length, + size_t * index, char ** result) +{ + size_t cur_token; + int len; + int begin; + char * domain_literal; + int r; + + cur_token = * index; + + r = mailimf_cfws_parse(message, length, &cur_token); + if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) + return r; + + begin = cur_token; + r = mailimf_obracket_parse(message, length, &cur_token); + if (r != MAILIMF_NO_ERROR) + return r; + + while (1) { + r = mailimf_domain_literal_fws_dcontent_parse(message, length, + &cur_token); + if (r == MAILIMF_NO_ERROR) { + /* do nothing */ + } + else if (r == MAILIMF_ERROR_PARSE) + break; + else + return r; + } + + r = mailimf_fws_parse(message, length, &cur_token); + if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) + return r; + + r = mailimf_cbracket_parse(message, length, &cur_token); + if (r != MAILIMF_NO_ERROR) + return r; + + len = cur_token - begin; + + domain_literal = malloc(len + 1); + if (domain_literal == NULL) + return MAILIMF_ERROR_MEMORY; + strncpy(domain_literal, message + begin, len); + domain_literal[len] = '\0'; + + * result = domain_literal; + * index = cur_token; + + return MAILIMF_NO_ERROR; +} +#endif + +/* +dcontent = dtext / quoted-pair +*/ + +#if 0 +static int mailimf_dcontent_parse(const char * message, size_t length, + size_t * index, char * result) +{ + size_t cur_token; + char ch; + int r; + + cur_token = * index; + + if (cur_token >= length) + return MAILIMF_ERROR_PARSE; + + if (is_dtext(message[cur_token])) { + ch = message[cur_token]; + cur_token ++; + } + else { + r = mailimf_quoted_pair_parse(message, length, &cur_token, &ch); + + if (r != MAILIMF_NO_ERROR) + return r; + } + + * index = cur_token; + * result = ch; + + return MAILIMF_NO_ERROR; +} +#endif + + +/* +dtext = NO-WS-CTL / ; Non white space controls + + %d33-90 / ; The rest of the US-ASCII + %d94-126 ; characters not including "[", + ; "]", or "\" +*/ + +static inline int is_dtext(char ch) +{ + unsigned char uch = (unsigned char) ch; + + if (is_no_ws_ctl(ch)) + return TRUE; + + if (uch < 33) + return FALSE; + + if ((uch >= 91) && (uch <= 93)) + return FALSE; + + if (uch == 127) + return FALSE; + + return TRUE; +} + +/* +message = (fields / obs-fields) + [CRLF body] +*/ + +int mailimf_message_parse(const char * message, size_t length, + size_t * index, + struct mailimf_message ** result) +{ + struct mailimf_fields * fields; + struct mailimf_body * body; + struct mailimf_message * msg; + size_t cur_token; + int r; + int res; + + cur_token = * index; + + r = mailimf_fields_parse(message, length, &cur_token, &fields); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto err; + } + + r = mailimf_crlf_parse(message, length, &cur_token); + if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) { + res = r; + goto err; + } + + r = mailimf_body_parse(message, length, &cur_token, &body); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto free_fields; + } + + msg = mailimf_message_new(fields, body); + if (msg == NULL) { + res = MAILIMF_ERROR_MEMORY; + goto free_body; + } + + * index = cur_token; + * result = msg; + + return MAILIMF_NO_ERROR; + + free_body: + mailimf_body_free(body); + free_fields: + mailimf_fields_free(fields); + err: + return res; +} + +/* +body = *(*998text CRLF) *998text +*/ + +int mailimf_body_parse(const char * message, size_t length, + size_t * index, + struct mailimf_body ** result) +{ + size_t cur_token; + struct mailimf_body * body; + + cur_token = * index; + + body = mailimf_body_new(message + cur_token, length - cur_token); + if (body == NULL) + return MAILIMF_ERROR_MEMORY; + + cur_token = length; + + * result = body; + * index = cur_token; + + return MAILIMF_NO_ERROR; +} + +/* +CHANGE TO THE RFC 2822 + +original : + +fields = *(trace + *(resent-date / + resent-from / + resent-sender / + resent-to / + resent-cc / + resent-bcc / + resent-msg-id)) + *(orig-date / + from / + sender / + reply-to / + to / + cc / + bcc / + message-id / + in-reply-to / + references / + subject / + comments / + keywords / + optional-field) + +INTO THE FOLLOWING : +*/ + +/* +resent-fields-list = *(resent-date / + resent-from / + resent-sender / + resent-to / + resent-cc / + resent-bcc / + resent-msg-id)) +*/ + +#if 0 +enum { + RESENT_HEADER_START, +}; + +static int guess_resent_header_type(char * message, + size_t length, size_t index) +{ + int r; + + r = mailimf_token_case_insensitive_parse(message, + length, &index, "Resent-"); + if (r != MAILIMF_NO_ERROR) + return MAILIMF_RESENT_FIELD_NONE; + + if (index >= length) + return MAILIMF_RESENT_FIELD_NONE; + + switch(toupper(message[index])) { + case 'D': + return MAILIMF_RESENT_FIELD_DATE; + case 'F': + return MAILIMF_RESENT_FIELD_FROM; + case 'S': + return MAILIMF_RESENT_FIELD_SENDER; + case 'T': + return MAILIMF_RESENT_FIELD_TO; + case 'C': + return MAILIMF_RESENT_FIELD_CC; + case 'B': + return MAILIMF_RESENT_FIELD_BCC; + case 'M': + return MAILIMF_RESENT_FIELD_MSG_ID; + default: + return MAILIMF_RESENT_FIELD_NONE; + } +} +#endif + +#if 0 +static int +mailimf_resent_field_parse(const char * message, size_t length, + size_t * index, + struct mailimf_resent_field ** result) +{ + struct mailimf_orig_date * resent_date; + struct mailimf_from * resent_from; + struct mailimf_sender * resent_sender; + struct mailimf_to* resent_to; + struct mailimf_cc * resent_cc; + struct mailimf_bcc * resent_bcc; + struct mailimf_message_id * resent_msg_id; + size_t cur_token; + int type; + struct mailimf_resent_field * resent_field; + int r; + int res; + + cur_token = * index; + + resent_date = NULL; + resent_from = NULL; + resent_sender = NULL; + resent_to = NULL; + resent_cc = NULL; + resent_bcc = NULL; + resent_msg_id = NULL; + + type = guess_resent_header_type(message, length, cur_token); + + switch(type) { + case MAILIMF_RESENT_FIELD_DATE: + r = mailimf_resent_date_parse(message, length, &cur_token, + &resent_date); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto err; + } + break; + case MAILIMF_RESENT_FIELD_FROM: + r = mailimf_resent_from_parse(message, length, &cur_token, + &resent_from); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto err; + } + break; + case MAILIMF_RESENT_FIELD_SENDER: + r = mailimf_resent_sender_parse(message, length, &cur_token, + &resent_sender); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto err; + } + break; + case MAILIMF_RESENT_FIELD_TO: + r = mailimf_resent_to_parse(message, length, &cur_token, + &resent_to); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto err; + } + break; + case MAILIMF_RESENT_FIELD_CC: + r= mailimf_resent_cc_parse(message, length, &cur_token, + &resent_cc); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto err; + } + break; + case MAILIMF_RESENT_FIELD_BCC: + r = mailimf_resent_bcc_parse(message, length, &cur_token, + &resent_bcc); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto err; + } + break; + case MAILIMF_RESENT_FIELD_MSG_ID: + r = mailimf_resent_msg_id_parse(message, length, &cur_token, + &resent_msg_id); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto err; + } + break; + default: + res = MAILIMF_ERROR_PARSE; + goto err; + } + + resent_field = mailimf_resent_field_new(type, resent_date, + resent_from, resent_sender, + resent_to, resent_cc, + resent_bcc, resent_msg_id); + if (resent_field == NULL) { + res = MAILIMF_ERROR_MEMORY; + goto free_resent; + } + + * result = resent_field; + * index = cur_token; + + return MAILIMF_NO_ERROR; + + free_resent: + if (resent_msg_id != NULL) + mailimf_message_id_free(resent_msg_id); + if (resent_bcc != NULL) + mailimf_bcc_free(resent_bcc); + if (resent_cc != NULL) + mailimf_cc_free(resent_cc); + if (resent_to != NULL) + mailimf_to_free(resent_to); + if (resent_sender != NULL) + mailimf_sender_free(resent_sender); + if (resent_from != NULL) + mailimf_from_free(resent_from); + if (resent_date != NULL) + mailimf_orig_date_free(resent_date); + err: + return res; +} +#endif + +#if 0 +static int +mailimf_resent_fields_list_parse(const char * message, size_t length, + size_t * index, + struct mailimf_resent_fields_list ** result) +{ + clist * list; + size_t cur_token; + struct mailimf_resent_fields_list * resent_fields_list; + int r; + int res; + + cur_token = * index; + list = NULL; + + r = mailimf_struct_multiple_parse(message, length, &cur_token, &list, + (mailimf_struct_parser *) + mailimf_resent_field_parse, + (mailimf_struct_destructor *) + mailimf_resent_field_free); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto err; + } + + resent_fields_list = mailimf_resent_fields_list_new(list); + if (resent_fields_list == NULL) { + res = MAILIMF_ERROR_MEMORY; + goto free_list; + } + + * result = resent_fields_list; + * index = cur_token; + + return MAILIMF_NO_ERROR; + + free_list: + clist_foreach(list, (clist_func) mailimf_resent_field_free, NULL); + clist_free(list); + err: + return res; +} +#endif + +/* + ([trace] + [resent-fields-list]) +*/ + +#if 0 +static int +mailimf_trace_resent_fields_parse(const char * message, size_t length, + size_t * index, + struct mailimf_trace_resent_fields ** result) +{ + size_t cur_token; + struct mailimf_return * return_path; + struct mailimf_resent_fields_list * resent_fields; + struct mailimf_trace_resent_fields * trace_resent_fields; + int res; + int r; + + cur_token = * index; + + return_path = NULL; + resent_fields = NULL; + + r = mailimf_return_parse(message, length, &cur_token, + &return_path); + if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) { + res = r; + goto err; + } + + r = mailimf_resent_fields_list_parse(message, length, &cur_token, + &resent_fields); + if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) { + res = r; + goto err; + } + + if ((return_path == NULL) && (resent_fields == NULL)) { + res = MAILIMF_ERROR_PARSE; + goto err; + } + + trace_resent_fields = mailimf_trace_resent_fields_new(return_path, + resent_fields); + if (trace_resent_fields == NULL) { + res = MAILIMF_ERROR_MEMORY; + goto free_resent_fields; + } + + * result = trace_resent_fields; + * index = cur_token; + + return MAILIMF_NO_ERROR; + + free_resent_fields: + if (resent_fields != NULL) + mailimf_resent_fields_list_free(resent_fields); + if (return_path != NULL) + mailimf_return_free(return_path); + err: + return res; +} +#endif + +/* +delivering-info = *([trace] + [resent-fields-list]) +*/ + +#if 0 +static int +mailimf_delivering_info_parse(const char * message, size_t length, + size_t * index, + struct mailimf_delivering_info ** result) +{ + size_t cur_token; + clist * list; + struct mailimf_delivering_info * delivering_info; + int r; + int res; + + cur_token = * index; + + r = mailimf_struct_multiple_parse(message, length, &cur_token, + &list, + (mailimf_struct_parser *) + mailimf_trace_resent_fields_parse, + (mailimf_struct_destructor *) + mailimf_trace_resent_fields_free); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto err; + } + + delivering_info = mailimf_delivering_info_new(list); + if (delivering_info == NULL) { + res = MAILIMF_ERROR_MEMORY; + goto free_list; + } + + * result = delivering_info; + * index = cur_token; + + return MAILIMF_NO_ERROR; + + free_list: + clist_foreach(list, (clist_func) mailimf_trace_resent_fields_free, NULL); + clist_free(list); + err: + return res; +} +#endif + +/* +field = delivering-info / + orig-date / + from / + sender / + reply-to / + to / + cc / + bcc / + message-id / + in-reply-to / + references / + subject / + comments / + keywords / + optional-field +*/ + +enum { + HEADER_START, + HEADER_C, + HEADER_R, + HEADER_RE, + HEADER_S, + HEADER_RES, +}; + +static int guess_header_type(const char * message, size_t length, size_t index) +{ + int state; + int r; + + state = HEADER_START; + + while (1) { + + if (index >= length) + return MAILIMF_FIELD_NONE; + + switch(state) { + case HEADER_START: + switch((char) toupper((unsigned char) message[index])) { + case 'B': + return MAILIMF_FIELD_BCC; + case 'C': + state = HEADER_C; + break; + case 'D': + return MAILIMF_FIELD_ORIG_DATE; + case 'F': + return MAILIMF_FIELD_FROM; + case 'I': + return MAILIMF_FIELD_IN_REPLY_TO; + case 'K': + return MAILIMF_FIELD_KEYWORDS; + case 'M': + return MAILIMF_FIELD_MESSAGE_ID; + case 'R': + state = HEADER_R; + break; + case 'T': + return MAILIMF_FIELD_TO; + break; + case 'S': + state = HEADER_S; + break; + default: + return MAILIMF_FIELD_NONE; + } + break; + case HEADER_C: + switch((char) toupper((unsigned char) message[index])) { + case 'O': + return MAILIMF_FIELD_COMMENTS; + case 'C': + return MAILIMF_FIELD_CC; + default: + return MAILIMF_FIELD_NONE; + } + break; + case HEADER_R: + switch((char) toupper((unsigned char) message[index])) { + case 'E': + state = HEADER_RE; + break; + default: + return MAILIMF_FIELD_NONE; + } + break; + case HEADER_RE: + switch((char) toupper((unsigned char) message[index])) { + case 'F': + return MAILIMF_FIELD_REFERENCES; + case 'P': + return MAILIMF_FIELD_REPLY_TO; + case 'S': + state = HEADER_RES; + break; + case 'T': + return MAILIMF_FIELD_RETURN_PATH; + default: + return MAILIMF_FIELD_NONE; + } + break; + case HEADER_S: + switch((char) toupper((unsigned char) message[index])) { + case 'E': + return MAILIMF_FIELD_SENDER; + case 'U': + return MAILIMF_FIELD_SUBJECT; + default: + return MAILIMF_FIELD_NONE; + } + break; + + case HEADER_RES: + r = mailimf_token_case_insensitive_parse(message, + length, &index, "ent-"); + if (r != MAILIMF_NO_ERROR) + return MAILIMF_FIELD_NONE; + + if (index >= length) + return MAILIMF_FIELD_NONE; + + switch((char) toupper((unsigned char) message[index])) { + case 'D': + return MAILIMF_FIELD_RESENT_DATE; + case 'F': + return MAILIMF_FIELD_RESENT_FROM; + case 'S': + return MAILIMF_FIELD_RESENT_SENDER; + case 'T': + return MAILIMF_FIELD_RESENT_TO; + case 'C': + return MAILIMF_FIELD_RESENT_CC; + case 'B': + return MAILIMF_FIELD_RESENT_BCC; + case 'M': + return MAILIMF_FIELD_RESENT_MSG_ID; + default: + return MAILIMF_FIELD_NONE; + } + break; + } + index ++; + } +} + +static int mailimf_field_parse(const char * message, size_t length, + size_t * index, + struct mailimf_field ** result) +{ + size_t cur_token; + int type; + struct mailimf_return * return_path; + struct mailimf_orig_date * resent_date; + struct mailimf_from * resent_from; + struct mailimf_sender * resent_sender; + struct mailimf_to* resent_to; + struct mailimf_cc * resent_cc; + struct mailimf_bcc * resent_bcc; + struct mailimf_message_id * resent_msg_id; + struct mailimf_orig_date * orig_date; + struct mailimf_from * from; + struct mailimf_sender * sender; + struct mailimf_reply_to * reply_to; + struct mailimf_to * to; + struct mailimf_cc * cc; + struct mailimf_bcc * bcc; + struct mailimf_message_id * message_id; + struct mailimf_in_reply_to * in_reply_to; + struct mailimf_references * references; + struct mailimf_subject * subject; + struct mailimf_comments * comments; + struct mailimf_keywords * keywords; + struct mailimf_optional_field * optional_field; + struct mailimf_field * field; + int guessed_type; + int r; + int res; + + cur_token = * index; + + return_path = NULL; + resent_date = NULL; + resent_from = NULL; + resent_sender = NULL; + resent_to = NULL; + resent_cc = NULL; + resent_bcc = NULL; + resent_msg_id = NULL; + orig_date = NULL; + from = NULL; + sender = NULL; + reply_to = NULL; + to = NULL; + cc = NULL; + bcc = NULL; + message_id = NULL; + in_reply_to = NULL; + references = NULL; + subject = NULL; + comments = NULL; + keywords = NULL; + optional_field = NULL; + + guessed_type = guess_header_type(message, length, cur_token); + type = MAILIMF_FIELD_NONE; + + switch (guessed_type) { + case MAILIMF_FIELD_ORIG_DATE: + r = mailimf_orig_date_parse(message, length, &cur_token, + &orig_date); + if (r == MAILIMF_NO_ERROR) + type = MAILIMF_FIELD_ORIG_DATE; + else if (r == MAILIMF_ERROR_PARSE) { + /* do nothing */ + } + else { + res = r; + goto err; + } + break; + case MAILIMF_FIELD_FROM: + r = mailimf_from_parse(message, length, &cur_token, + &from); + if (r == MAILIMF_NO_ERROR) + type = guessed_type; + else if (r == MAILIMF_ERROR_PARSE) { + /* do nothing */ + } + else { + res = r; + goto err; + } + break; + case MAILIMF_FIELD_SENDER: + r = mailimf_sender_parse(message, length, &cur_token, + &sender); + if (r == MAILIMF_NO_ERROR) + type = guessed_type; + else if (r == MAILIMF_ERROR_PARSE) { + /* do nothing */ + } + else { + res = r; + goto err; + } + break; + case MAILIMF_FIELD_REPLY_TO: + r = mailimf_reply_to_parse(message, length, &cur_token, + &reply_to); + if (r == MAILIMF_NO_ERROR) + type = guessed_type; + else if (r == MAILIMF_ERROR_PARSE) { + /* do nothing */ + } + else { + res = r; + goto err; + } + break; + case MAILIMF_FIELD_TO: + r = mailimf_to_parse(message, length, &cur_token, + &to); + if (r == MAILIMF_NO_ERROR) + type = guessed_type; + else if (r == MAILIMF_ERROR_PARSE) { + /* do nothing */ + } + else { + res = r; + goto err; + } + break; + case MAILIMF_FIELD_CC: + r = mailimf_cc_parse(message, length, &cur_token, + &cc); + if (r == MAILIMF_NO_ERROR) + type = guessed_type; + else if (r == MAILIMF_ERROR_PARSE) { + /* do nothing */ + } + else { + res = r; + goto err; + } + break; + case MAILIMF_FIELD_BCC: + r = mailimf_bcc_parse(message, length, &cur_token, + &bcc); + if (r == MAILIMF_NO_ERROR) + type = guessed_type; + else if (r == MAILIMF_ERROR_PARSE) { + /* do nothing */ + } + else { + res = r; + goto err; + } + break; + case MAILIMF_FIELD_MESSAGE_ID: + r = mailimf_message_id_parse(message, length, &cur_token, + &message_id); + if (r == MAILIMF_NO_ERROR) + type = guessed_type; + else if (r == MAILIMF_ERROR_PARSE) { + /* do nothing */ + } + else { + res = r; + goto err; + } + break; + case MAILIMF_FIELD_IN_REPLY_TO: + r = mailimf_in_reply_to_parse(message, length, &cur_token, + &in_reply_to); + if (r == MAILIMF_NO_ERROR) + type = guessed_type; + else if (r == MAILIMF_ERROR_PARSE) { + /* do nothing */ + } + else { + res = r; + goto err; + } + break; + case MAILIMF_FIELD_REFERENCES: + r = mailimf_references_parse(message, length, &cur_token, + &references); + if (r == MAILIMF_NO_ERROR) + type = guessed_type; + else if (r == MAILIMF_ERROR_PARSE) { + /* do nothing */ + } + else { + res = r; + goto err; + } + break; + case MAILIMF_FIELD_SUBJECT: + r = mailimf_subject_parse(message, length, &cur_token, + &subject); + if (r == MAILIMF_NO_ERROR) + type = guessed_type; + else if (r == MAILIMF_ERROR_PARSE) { + /* do nothing */ + } + else { + res = r; + goto err; + } + break; + case MAILIMF_FIELD_COMMENTS: + r = mailimf_comments_parse(message, length, &cur_token, + &comments); + if (r == MAILIMF_NO_ERROR) + type = guessed_type; + else if (r == MAILIMF_ERROR_PARSE) { + /* do nothing */ + } + else { + res = r; + goto err; + } + break; + case MAILIMF_FIELD_KEYWORDS: + r = mailimf_keywords_parse(message, length, &cur_token, + &keywords); + if (r == MAILIMF_NO_ERROR) + type = guessed_type; + else if (r == MAILIMF_ERROR_PARSE) { + /* do nothing */ + } + else { + res = r; + goto err; + } + break; + case MAILIMF_FIELD_RETURN_PATH: + r = mailimf_return_parse(message, length, &cur_token, + &return_path); + if (r == MAILIMF_NO_ERROR) + type = guessed_type; + else if (r == MAILIMF_ERROR_PARSE) { + /* do nothing */ + } + else { + res = r; + goto err; + } + break; + case MAILIMF_FIELD_RESENT_DATE: + r = mailimf_resent_date_parse(message, length, &cur_token, + &resent_date); + if (r == MAILIMF_NO_ERROR) + type = guessed_type; + else if (r == MAILIMF_ERROR_PARSE) { + /* do nothing */ + } + else { + res = r; + goto err; + } + break; + case MAILIMF_FIELD_RESENT_FROM: + r = mailimf_resent_from_parse(message, length, &cur_token, + &resent_from); + if (r == MAILIMF_NO_ERROR) + type = guessed_type; + else if (r == MAILIMF_ERROR_PARSE) { + /* do nothing */ + } + else { + res = r; + goto err; + } + break; + case MAILIMF_FIELD_RESENT_SENDER: + r = mailimf_resent_sender_parse(message, length, &cur_token, + &resent_sender); + if (r == MAILIMF_NO_ERROR) + type = guessed_type; + else if (r == MAILIMF_ERROR_PARSE) { + /* do nothing */ + } + else { + res = r; + goto err; + } + break; + case MAILIMF_FIELD_RESENT_TO: + r = mailimf_resent_to_parse(message, length, &cur_token, + &resent_to); + if (r == MAILIMF_NO_ERROR) + type = guessed_type; + else if (r == MAILIMF_ERROR_PARSE) { + /* do nothing */ + } + else { + res = r; + goto err; + } + break; + case MAILIMF_FIELD_RESENT_CC: + r= mailimf_resent_cc_parse(message, length, &cur_token, + &resent_cc); + if (r == MAILIMF_NO_ERROR) + type = guessed_type; + else if (r == MAILIMF_ERROR_PARSE) { + /* do nothing */ + } + else { + res = r; + goto err; + } + break; + case MAILIMF_FIELD_RESENT_BCC: + r = mailimf_resent_bcc_parse(message, length, &cur_token, + &resent_bcc); + if (r == MAILIMF_NO_ERROR) + type = guessed_type; + else if (r == MAILIMF_ERROR_PARSE) { + /* do nothing */ + } + else { + res = r; + goto err; + } + break; + case MAILIMF_FIELD_RESENT_MSG_ID: + r = mailimf_resent_msg_id_parse(message, length, &cur_token, + &resent_msg_id); + if (r == MAILIMF_NO_ERROR) + type = guessed_type; + else if (r == MAILIMF_ERROR_PARSE) { + /* do nothing */ + } + else { + res = r; + goto err; + } + break; + } + + if (type == MAILIMF_FIELD_NONE) { + r = mailimf_optional_field_parse(message, length, &cur_token, + &optional_field); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto err; + } + + type = MAILIMF_FIELD_OPTIONAL_FIELD; + } + + field = mailimf_field_new(type, return_path, resent_date, + resent_from, resent_sender, resent_to, resent_cc, resent_bcc, + resent_msg_id, orig_date, from, sender, reply_to, to, + cc, bcc, message_id, in_reply_to, references, + subject, comments, keywords, optional_field); + if (field == NULL) { + res = MAILIMF_ERROR_MEMORY; + goto free_field; + } + + * result = field; + * index = cur_token; + + return MAILIMF_NO_ERROR; + + free_field: + if (return_path != NULL) + mailimf_return_free(return_path); + if (resent_date != NULL) + mailimf_orig_date_free(resent_date); + if (resent_from != NULL) + mailimf_from_free(resent_from); + if (resent_sender != NULL) + mailimf_sender_free(resent_sender); + if (resent_to != NULL) + mailimf_to_free(resent_to); + if (resent_cc != NULL) + mailimf_cc_free(resent_cc); + if (resent_bcc != NULL) + mailimf_bcc_free(resent_bcc); + if (resent_msg_id != NULL) + mailimf_message_id_free(resent_msg_id); + if (orig_date != NULL) + mailimf_orig_date_free(orig_date); + if (from != NULL) + mailimf_from_free(from); + if (sender != NULL) + mailimf_sender_free(sender); + if (reply_to != NULL) + mailimf_reply_to_free(reply_to); + if (to != NULL) + mailimf_to_free(to); + if (cc != NULL) + mailimf_cc_free(cc); + if (bcc != NULL) + mailimf_bcc_free(bcc); + if (message_id != NULL) + mailimf_message_id_free(message_id); + if (in_reply_to != NULL) + mailimf_in_reply_to_free(in_reply_to); + if (references != NULL) + mailimf_references_free(references); + if (subject != NULL) + mailimf_subject_free(subject); + if (comments != NULL) + mailimf_comments_free(comments); + if (keywords != NULL) + mailimf_keywords_free(keywords); + if (optional_field != NULL) + mailimf_optional_field_free(optional_field); + err: + return res; +} + + +/* +fields = *(delivering-info / + orig-date / + from / + sender / + reply-to / + to / + cc / + bcc / + message-id / + in-reply-to / + references / + subject / + comments / + keywords / + optional-field) +*/ + +#if 0 +int +mailimf_unparsed_fields_parse(const char * message, size_t length, + size_t * index, + struct mailimf_unparsed_fields ** result) +{ + size_t cur_token; + clist * list; + struct mailimf_unparsed_fields * fields; + int r; + int res; + + cur_token = * index; + + list = NULL; + + r = mailimf_struct_multiple_parse(message, length, &cur_token, + &list, + (mailimf_struct_parser *) + mailimf_optional_field_parse, + (mailimf_struct_destructor *) + mailimf_optional_field_free); + /* + if ((r = MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) { + res = r; + goto err; + } + */ + + switch (r) { + case MAILIMF_NO_ERROR: + /* do nothing */ + break; + + case MAILIMF_ERROR_PARSE: + list = clist_new(); + if (list == NULL) { + res = MAILIMF_ERROR_MEMORY; + goto err; + } + break; + + default: + res = r; + goto err; + } + + fields = mailimf_unparsed_fields_new(list); + if (fields == NULL) { + res = MAILIMF_ERROR_MEMORY; + goto free; + } + + * result = fields; + * index = cur_token; + + return MAILIMF_NO_ERROR; + + free: + if (list != NULL) { + clist_foreach(list, (clist_func) mailimf_optional_field_free, NULL); + clist_free(list); + } + err: + return res; +} +#endif + +int mailimf_fields_parse(const char * message, size_t length, + size_t * index, + struct mailimf_fields ** result) +{ + size_t cur_token; + clist * list; + struct mailimf_fields * fields; + int r; + int res; + + cur_token = * index; + + list = NULL; + + r = mailimf_struct_multiple_parse(message, length, &cur_token, + &list, + (mailimf_struct_parser *) + mailimf_field_parse, + (mailimf_struct_destructor *) + mailimf_field_free); + /* + if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) { + res = r; + goto err; + } + */ + + switch (r) { + case MAILIMF_NO_ERROR: + /* do nothing */ + break; + + case MAILIMF_ERROR_PARSE: + list = clist_new(); + if (list == NULL) { + res = MAILIMF_ERROR_MEMORY; + goto err; + } + break; + + default: + res = r; + goto err; + } + + fields = mailimf_fields_new(list); + if (fields == NULL) { + res = MAILIMF_ERROR_MEMORY; + goto free; + } + + * result = fields; + * index = cur_token; + + return MAILIMF_NO_ERROR; + + free: + if (list != NULL) { + clist_foreach(list, (clist_func) mailimf_field_free, NULL); + clist_free(list); + } + err: + return res; +} + +/* +orig-date = "Date:" date-time CRLF +*/ + + +static int +mailimf_orig_date_parse(const char * message, size_t length, + size_t * index, struct mailimf_orig_date ** result) +{ + struct mailimf_date_time * date_time; + struct mailimf_orig_date * orig_date; + size_t cur_token; + int r; + int res; + + cur_token = * index; + + r = mailimf_token_case_insensitive_parse(message, length, + &cur_token, "Date:"); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto err; + } + + r = mailimf_date_time_parse(message, length, &cur_token, &date_time); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto err; + } + + r = mailimf_ignore_unstructured_parse(message, length, &cur_token); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto free_date_time; + } + + r = mailimf_unstrict_crlf_parse(message, length, &cur_token); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto free_date_time; + } + + orig_date = mailimf_orig_date_new(date_time); + if (orig_date == NULL) { + res = MAILIMF_ERROR_MEMORY; + goto free_date_time; + } + + * result = orig_date; + * index = cur_token; + + return MAILIMF_NO_ERROR; + + free_date_time: + mailimf_date_time_free(date_time); + err: + return res; +} + +/* +from = "From:" mailbox-list CRLF +*/ + +static int +mailimf_from_parse(const char * message, size_t length, + size_t * index, struct mailimf_from ** result) +{ + struct mailimf_mailbox_list * mb_list; + struct mailimf_from * from; + size_t cur_token; + int r; + int res; + + cur_token = * index; + + r = mailimf_token_case_insensitive_parse(message, length, + &cur_token, "From"); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto err; + } + + r = mailimf_colon_parse(message, length, &cur_token); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto err; + } + + r = mailimf_mailbox_list_parse(message, length, &cur_token, &mb_list); + + if (r != MAILIMF_NO_ERROR) { + res = r; + goto err; + } + + r = mailimf_unstrict_crlf_parse(message, length, &cur_token); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto free_mb_list; + } + + from = mailimf_from_new(mb_list); + if (from == NULL) { + res = MAILIMF_ERROR_MEMORY; + goto free_mb_list; + } + + * result = from; + * index = cur_token; + + return MAILIMF_NO_ERROR; + + free_mb_list: + mailimf_mailbox_list_free(mb_list); + err: + return res; +} + +/* +sender = "Sender:" mailbox CRLF +*/ + +static int +mailimf_sender_parse(const char * message, size_t length, + size_t * index, struct mailimf_sender ** result) +{ + struct mailimf_mailbox * mb; + struct mailimf_sender * sender; + size_t cur_token; + int r; + int res; + + cur_token = * index; + + r = mailimf_token_case_insensitive_parse(message, length, + &cur_token, "Sender"); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto err; + } + + r = mailimf_colon_parse(message, length, &cur_token); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto err; + } + + r = mailimf_mailbox_parse(message, length, &cur_token, &mb); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto err; + } + + r = mailimf_unstrict_crlf_parse(message, length, &cur_token); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto free_mb; + } + + sender = mailimf_sender_new(mb); + if (sender == NULL) { + res = MAILIMF_ERROR_MEMORY; + goto free_mb; + } + + * result = sender; + * index = cur_token; + + return MAILIMF_NO_ERROR; + + free_mb: + mailimf_mailbox_free(mb); + err: + return res; +} + +/* +reply-to = "Reply-To:" address-list CRLF +*/ + + +static int +mailimf_reply_to_parse(const char * message, size_t length, + size_t * index, struct mailimf_reply_to ** result) +{ + struct mailimf_address_list * addr_list; + struct mailimf_reply_to * reply_to; + size_t cur_token; + int r; + int res; + + cur_token = * index; + + r = mailimf_token_case_insensitive_parse(message, length, + &cur_token, "Reply-To"); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto err; + } + + r = mailimf_colon_parse(message, length, &cur_token); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto err; + } + + r = mailimf_address_list_parse(message, length, &cur_token, &addr_list); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto err; + } + + r = mailimf_unstrict_crlf_parse(message, length, &cur_token); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto free_addr_list; + } + + reply_to = mailimf_reply_to_new(addr_list); + if (reply_to == NULL) { + res = MAILIMF_ERROR_MEMORY; + goto free_addr_list; + } + + * result = reply_to; + * index = cur_token; + + return MAILIMF_NO_ERROR; + + free_addr_list: + mailimf_address_list_free(addr_list); + err: + return res; +} + +/* +to = "To:" address-list CRLF +*/ + +static int +mailimf_to_parse(const char * message, size_t length, + size_t * index, struct mailimf_to ** result) +{ + struct mailimf_address_list * addr_list; + struct mailimf_to * to; + size_t cur_token; + int r; + int res; + + cur_token = * index; + + r = mailimf_token_case_insensitive_parse(message, length, + &cur_token, "To"); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto err; + } + + r = mailimf_colon_parse(message, length, &cur_token); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto err; + } + + r = mailimf_address_list_parse(message, length, &cur_token, &addr_list); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto err; + } + + r = mailimf_unstrict_crlf_parse(message, length, &cur_token); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto free_addr_list; + } + + to = mailimf_to_new(addr_list); + if (to == NULL) { + res = MAILIMF_ERROR_MEMORY; + goto free_addr_list; + } + + * result = to; + * index = cur_token; + + return MAILIMF_NO_ERROR; + + free_addr_list: + mailimf_address_list_free(addr_list); + err: + return res; +} + +/* +cc = "Cc:" address-list CRLF +*/ + + +static int +mailimf_cc_parse(const char * message, size_t length, + size_t * index, struct mailimf_cc ** result) +{ + struct mailimf_address_list * addr_list; + struct mailimf_cc * cc; + size_t cur_token; + int r; + int res; + + cur_token = * index; + + r = mailimf_token_case_insensitive_parse(message, length, + &cur_token, "Cc"); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto err; + } + + r = mailimf_colon_parse(message, length, &cur_token); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto err; + } + + r = mailimf_address_list_parse(message, length, &cur_token, &addr_list); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto err; + } + + r = mailimf_unstrict_crlf_parse(message, length, &cur_token); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto free_addr_list; + } + + cc = mailimf_cc_new(addr_list); + if (cc == NULL) { + res = MAILIMF_ERROR_MEMORY; + goto free_addr_list; + } + + * result = cc; + * index = cur_token; + + return MAILIMF_NO_ERROR; + + free_addr_list: + mailimf_address_list_free(addr_list); + err: + return res; +} + +/* +bcc = "Bcc:" (address-list / [CFWS]) CRLF +*/ + + +static int +mailimf_bcc_parse(const char * message, size_t length, + size_t * index, struct mailimf_bcc ** result) +{ + struct mailimf_address_list * addr_list; + struct mailimf_bcc * bcc; + size_t cur_token; + int r; + int res; + + cur_token = * index; + addr_list = NULL; + + r = mailimf_token_case_insensitive_parse(message, length, + &cur_token, "Bcc"); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto err; + } + + r = mailimf_colon_parse(message, length, &cur_token); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto err; + } + + r = mailimf_address_list_parse(message, length, &cur_token, &addr_list); + switch (r) { + case MAILIMF_NO_ERROR: + /* do nothing */ + break; + case MAILIMF_ERROR_PARSE: + r = mailimf_cfws_parse(message, length, &cur_token); + if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) { + res = r; + goto err; + } + break; + default: + res = r; + goto err; + } + + r = mailimf_unstrict_crlf_parse(message, length, &cur_token); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto free_addr_list; + } + + bcc = mailimf_bcc_new(addr_list); + if (bcc == NULL) { + res = MAILIMF_ERROR_MEMORY; + goto free_addr_list; + } + + * result = bcc; + * index = cur_token; + + return MAILIMF_NO_ERROR; + + free_addr_list: + mailimf_address_list_free(addr_list); + err: + return res; +} + +/* +message-id = "Message-ID:" msg-id CRLF +*/ + +static int mailimf_message_id_parse(const char * message, size_t length, + size_t * index, + struct mailimf_message_id ** result) +{ + char * value; + size_t cur_token; + struct mailimf_message_id * message_id; + int r; + int res; + + cur_token = * index; + + r = mailimf_token_case_insensitive_parse(message, length, + &cur_token, "Message-ID"); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto err; + } + + r = mailimf_colon_parse(message, length, &cur_token); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto err; + } + + r = mailimf_msg_id_parse(message, length, &cur_token, &value); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto err; + } + + r = mailimf_unstrict_crlf_parse(message, length, &cur_token); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto free_value; + } + + message_id = mailimf_message_id_new(value); + if (message_id == NULL) { + res = MAILIMF_ERROR_MEMORY; + goto free_value; + } + + * result = message_id; + * index = cur_token; + + return MAILIMF_NO_ERROR; + + free_value: + mailimf_msg_id_free(value); + err: + return res; +} + +/* +in-reply-to = "In-Reply-To:" 1*msg-id CRLF +*/ + +int mailimf_msg_id_list_parse(const char * message, size_t length, + size_t * index, clist ** result) +{ + return mailimf_struct_multiple_parse(message, length, index, + result, + (mailimf_struct_parser *) + mailimf_unstrict_msg_id_parse, + (mailimf_struct_destructor *) + mailimf_msg_id_free); +} + +static int mailimf_in_reply_to_parse(const char * message, size_t length, + size_t * index, + struct mailimf_in_reply_to ** result) +{ + struct mailimf_in_reply_to * in_reply_to; + size_t cur_token; + clist * msg_id_list; + int res; + int r; + + cur_token = * index; + + r = mailimf_token_case_insensitive_parse(message, length, + &cur_token, "In-Reply-To"); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto err; + } + + r = mailimf_colon_parse(message, length, &cur_token); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto err; + } + + r = mailimf_msg_id_list_parse(message, length, &cur_token, &msg_id_list); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto err; + } + + r = mailimf_unstrict_crlf_parse(message, length, &cur_token); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto free_list; + } + + in_reply_to = mailimf_in_reply_to_new(msg_id_list); + if (in_reply_to == NULL) { + res = MAILIMF_ERROR_MEMORY; + goto free_list; + } + + * result = in_reply_to; + * index = cur_token; + + return MAILIMF_NO_ERROR; + + free_list: + clist_foreach(msg_id_list, (clist_func) mailimf_msg_id_free, NULL); + clist_free(msg_id_list); + err: + return res; +} + +/* +references = "References:" 1*msg-id CRLF +*/ + +int mailimf_references_parse(const char * message, size_t length, + size_t * index, + struct mailimf_references ** result) +{ + struct mailimf_references * references; + size_t cur_token; + clist * msg_id_list; + int r; + int res; + + cur_token = * index; + + r = mailimf_token_case_insensitive_parse(message, length, + &cur_token, "References"); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto err; + } + + r = mailimf_colon_parse(message, length, &cur_token); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto err; + } + + r = mailimf_msg_id_list_parse(message, length, &cur_token, &msg_id_list); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto err; + } + + r = mailimf_unstrict_crlf_parse(message, length, &cur_token); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto free_list; + } + + references = mailimf_references_new(msg_id_list); + if (references == NULL) { + res = MAILIMF_ERROR_MEMORY; + goto free_list; + } + + * result = references; + * index = cur_token; + + return MAILIMF_NO_ERROR; + + free_list: + clist_foreach(msg_id_list, (clist_func) mailimf_msg_id_free, NULL); + clist_free(msg_id_list); + err: + return res; +} + +/* +msg-id = [CFWS] "<" id-left "@" id-right ">" [CFWS] +*/ + +int mailimf_msg_id_parse(const char * message, size_t length, + size_t * index, + char ** result) +{ + size_t cur_token; +#if 0 + char * id_left; + char * id_right; +#endif + char * msg_id; + int r; + int res; + + cur_token = * index; + + r = mailimf_cfws_parse(message, length, &cur_token); + if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) + return r; + + r = mailimf_lower_parse(message, length, &cur_token); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto err; + } + + r = mailimf_addr_spec_parse(message, length, &cur_token, &msg_id); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto err; + } + + r = mailimf_greater_parse(message, length, &cur_token); + if (r != MAILIMF_NO_ERROR) { + free(msg_id); + res = r; + goto err; + } + +#if 0 + r = mailimf_id_left_parse(message, length, &cur_token, &id_left); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto err; + } + + r = mailimf_at_sign_parse(message, length, &cur_token); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto free_id_left; + } + + r = mailimf_id_right_parse(message, length, &cur_token, &id_right); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto free_id_left; + } + + r = mailimf_greater_parse(message, length, &cur_token); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto free_id_right; + } + + msg_id = malloc(strlen(id_left) + strlen(id_right) + 2); + if (msg_id == NULL) { + res = MAILIMF_ERROR_MEMORY; + goto free_id_right; + } + strcpy(msg_id, id_left); + strcat(msg_id, "@"); + strcat(msg_id, id_right); + + mailimf_id_left_free(id_left); + mailimf_id_right_free(id_right); +#endif + + * result = msg_id; + * index = cur_token; + + return MAILIMF_NO_ERROR; + +#if 0 + free_id_right: + mailimf_id_right_free(id_right); + free_id_left: + mailimf_id_left_free(id_left); +#endif + /* + free: + mailimf_atom_free(msg_id); + */ + err: + return res; +} + +static int mailimf_parse_unwanted_msg_id(const char * message, size_t length, + size_t * index) +{ + size_t cur_token; + int r; + char * word; + int token_parsed; + + cur_token = * index; + + token_parsed = TRUE; + while (token_parsed) { + token_parsed = FALSE; + r = mailimf_word_parse(message, length, &cur_token, &word); + if (r == MAILIMF_NO_ERROR) { + mailimf_word_free(word); + token_parsed = TRUE; + } + else if (r == MAILIMF_ERROR_PARSE) { + /* do nothing */ + } + else + return r; + r = mailimf_semi_colon_parse(message, length, &cur_token); + if (r == MAILIMF_NO_ERROR) + token_parsed = TRUE; + else if (r == MAILIMF_ERROR_PARSE) { + /* do nothing */ + } + else + return r; + r = mailimf_comma_parse(message, length, &cur_token); + if (r == MAILIMF_NO_ERROR) + token_parsed = TRUE; + else if (r == MAILIMF_ERROR_PARSE) { + /* do nothing */ + } + else + return r; + r = mailimf_plus_parse(message, length, &cur_token); + if (r == MAILIMF_NO_ERROR) + token_parsed = TRUE; + else if (r == MAILIMF_ERROR_PARSE) { + /* do nothing */ + } + else + return r; + r = mailimf_colon_parse(message, length, &cur_token); + if (r == MAILIMF_NO_ERROR) + token_parsed = TRUE; + else if (r == MAILIMF_ERROR_PARSE) { + /* do nothing */ + } + else + return r; + r = mailimf_point_parse(message, length, &cur_token); + if (r == MAILIMF_NO_ERROR) + token_parsed = TRUE; + else if (r == MAILIMF_ERROR_PARSE) { + /* do nothing */ + } + else + return r; + r = mailimf_at_sign_parse(message, length, &cur_token); + if (r == MAILIMF_NO_ERROR) + token_parsed = TRUE; + else if (r == MAILIMF_ERROR_PARSE) { + /* do nothing */ + } + else + return r; + } + + return MAILIMF_NO_ERROR; +} + +static int mailimf_unstrict_msg_id_parse(const char * message, size_t length, + size_t * index, + char ** result) +{ + char * msgid; + size_t cur_token; + int r; + + cur_token = * index; + + r = mailimf_cfws_parse(message, length, &cur_token); + if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) + return r; + + r = mailimf_parse_unwanted_msg_id(message, length, &cur_token); + if (r != MAILIMF_NO_ERROR) + return r; + + r = mailimf_msg_id_parse(message, length, &cur_token, &msgid); + if (r != MAILIMF_NO_ERROR) + return r; + + r = mailimf_parse_unwanted_msg_id(message, length, &cur_token); + if (r != MAILIMF_NO_ERROR) + return r; + + * result = msgid; + * index = cur_token; + + return MAILIMF_NO_ERROR; +} + +/* +id-left = dot-atom-text / no-fold-quote / obs-id-left +*/ + +#if 0 +static int mailimf_id_left_parse(const char * message, size_t length, + size_t * index, char ** result) +{ + int r; + + r = mailimf_dot_atom_text_parse(message, length, index, result); + switch (r) { + case MAILIMF_NO_ERROR: + return MAILIMF_NO_ERROR; + case MAILIMF_ERROR_PARSE: + break; + default: + return r; + } + + r = mailimf_no_fold_quote_parse(message, length, index, result); + if (r != MAILIMF_NO_ERROR) + return r; + + return MAILIMF_NO_ERROR; +} +#endif + +/* +id-right = dot-atom-text / no-fold-literal / obs-id-right +*/ + +#if 0 +static int mailimf_id_right_parse(const char * message, size_t length, + size_t * index, char ** result) +{ + int r; + + r = mailimf_dot_atom_text_parse(message, length, index, result); + switch (r) { + case MAILIMF_NO_ERROR: + return MAILIMF_NO_ERROR; + case MAILIMF_ERROR_PARSE: + break; + default: + return r; + } + + r = mailimf_no_fold_literal_parse(message, length, index, result); + if (r != MAILIMF_NO_ERROR) + return r; + + return MAILIMF_NO_ERROR; +} +#endif + +/* +no-fold-quote = DQUOTE *(qtext / quoted-pair) DQUOTE +*/ + +#if 0 +static int mailimf_no_fold_quote_char_parse(const char * message, size_t length, + size_t * index, char * result) +{ + char ch; + size_t cur_token; + int r; + + cur_token = * index; + +#if 0 + r = mailimf_qtext_parse(message, length, &cur_token, &ch); +#endif + + if (cur_token >= length) + return MAILIMF_ERROR_PARSE; + + if (is_qtext(message[cur_token])) { + ch = message[cur_token]; + cur_token ++; + } + else { + r = mailimf_quoted_pair_parse(message, length, &cur_token, &ch); + + if (r != MAILIMF_NO_ERROR) + return r; + } + + * index = cur_token; + * result = ch; + + return MAILIMF_NO_ERROR; +} +#endif + +#if 0 +static int mailimf_no_fold_quote_parse(const char * message, size_t length, + size_t * index, char ** result) +{ + size_t cur_token; + size_t begin; + char ch; + char * no_fold_quote; + int r; + int res; + + begin = cur_token; + r = mailimf_dquote_parse(message, length, &cur_token); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto err; + } + + while (1) { + r = mailimf_no_fold_quote_char_parse(message, length, &cur_token, &ch); + if (r == MAILIMF_NO_ERROR) { + /* do nothing */ + } + else if (r == MAILIMF_ERROR_PARSE) + break; + else { + res = r; + goto err; + } + } + + r = mailimf_dquote_parse(message, length, &cur_token); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto err; + } + + /* no_fold_quote = strndup(message + begin, cur_token - begin); */ + no_fold_quote = malloc(cur_token - begin + 1); + if (no_fold_quote == NULL) { + res = MAILIMF_ERROR_MEMORY; + goto err; + } + strncpy(no_fold_quote, message + begin, cur_token - begin); + no_fold_quote[cur_token - begin] = '\0'; + + * result = no_fold_quote; + * index = cur_token; + + return MAILIMF_NO_ERROR; + + err: + return res; +} +#endif + +/* +no-fold-literal = "[" *(dtext / quoted-pair) "]" +*/ + +#if 0 +static inline int +mailimf_no_fold_literal_char_parse(const char * message, size_t length, + size_t * index, char * result) +{ + char ch; + size_t cur_token; + int r; + + cur_token = * index; + +#if 0 + r = mailimf_dtext_parse(message, length, &cur_token, &ch); +#endif + if (cur_token >= length) + return MAILIMF_ERROR_PARSE; + + if (is_dtext(message[cur_token])) { + ch = message[cur_token]; + cur_token ++; + } + else { + r = mailimf_quoted_pair_parse(message, length, &cur_token, &ch); + + if (r != MAILIMF_NO_ERROR) + return r; + } + + * index = cur_token; + * result = ch; + + return MAILIMF_NO_ERROR; +} +#endif + +#if 0 +static int mailimf_no_fold_literal_parse(const char * message, size_t length, + size_t * index, char ** result) +{ + size_t cur_token; + size_t begin; + char ch; + char * no_fold_literal; + int r; + int res; + + begin = cur_token; + r = mailimf_obracket_parse(message, length, &cur_token); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto err; + } + + while (1) { + r = mailimf_no_fold_literal_char_parse(message, length, + &cur_token, &ch); + if (r == MAILIMF_NO_ERROR) { + /* do nothing */ + } + else if (r == MAILIMF_ERROR_PARSE) + break; + else { + res = r; + goto err; + } + } + + r = mailimf_cbracket_parse(message, length, &cur_token); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto err; + } + + /* + no_fold_literal = strndup(message + begin, cur_token - begin); + */ + no_fold_literal = malloc(cur_token - begin + 1); + if (no_fold_literal == NULL) { + res = MAILIMF_NO_ERROR; + goto err; + } + strncpy(no_fold_literal, message + begin, cur_token - begin); + no_fold_literal[cur_token - begin] = '\0'; + + * result = no_fold_literal; + * index = cur_token; + + return MAILIMF_NO_ERROR; + + err: + return res; +} +#endif + +/* +subject = "Subject:" unstructured CRLF +*/ + +static int mailimf_subject_parse(const char * message, size_t length, + size_t * index, + struct mailimf_subject ** result) +{ + struct mailimf_subject * subject; + char * value; + size_t cur_token; + int r; + int res; + + cur_token = * index; + + r = mailimf_token_case_insensitive_parse(message, length, + &cur_token, "Subject"); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto err; + } + + r = mailimf_colon_parse(message, length, &cur_token); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto err; + } + + r = mailimf_unstructured_parse(message, length, &cur_token, &value); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto err; + } + + r = mailimf_unstrict_crlf_parse(message, length, &cur_token); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto free_value; + } + + subject = mailimf_subject_new(value); + if (subject == NULL) { + res = MAILIMF_ERROR_MEMORY; + goto free_value; + } + + * result = subject; + * index = cur_token; + + return MAILIMF_NO_ERROR; + + free_value: + mailimf_unstructured_free(value); + err: + return res; +} + +/* +comments = "Comments:" unstructured CRLF +*/ + +static int mailimf_comments_parse(const char * message, size_t length, + size_t * index, + struct mailimf_comments ** result) +{ + struct mailimf_comments * comments; + char * value; + size_t cur_token; + int r; + int res; + + cur_token = * index; + + r = mailimf_token_case_insensitive_parse(message, length, + &cur_token, "Comments"); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto err; + } + + r = mailimf_colon_parse(message, length, &cur_token); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto err; + } + + r = mailimf_unstructured_parse(message, length, &cur_token, &value); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto err; + } + + r = mailimf_unstrict_crlf_parse(message, length, &cur_token); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto free_value; + } + + comments = mailimf_comments_new(value); + if (comments == NULL) { + res = MAILIMF_ERROR_MEMORY; + goto free_value; + } + + * result = comments; + * index = cur_token; + + return MAILIMF_NO_ERROR; + + free_value: + mailimf_unstructured_free(value); + err: + return res; +} + +/* +keywords = "Keywords:" phrase *("," phrase) CRLF +*/ + +static int mailimf_keywords_parse(const char * message, size_t length, + size_t * index, + struct mailimf_keywords ** result) +{ + struct mailimf_keywords * keywords; + clist * list; + size_t cur_token; + int r; + int res; + + cur_token = * index; + + r = mailimf_token_case_insensitive_parse(message, length, + &cur_token, "Keywords"); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto err; + } + + r = mailimf_colon_parse(message, length, &cur_token); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto err; + } + + r = mailimf_struct_list_parse(message, length, &cur_token, + &list, ',', + (mailimf_struct_parser *) + mailimf_phrase_parse, + (mailimf_struct_destructor *) + mailimf_phrase_free); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto err; + } + + r = mailimf_unstrict_crlf_parse(message, length, &cur_token); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto free_list; + } + + keywords = mailimf_keywords_new(list); + if (keywords == NULL) { + res = MAILIMF_ERROR_MEMORY; + goto free_list; + } + + * result = keywords; + * index = cur_token; + + return MAILIMF_NO_ERROR; + + free_list: + clist_foreach(list, (clist_func) mailimf_phrase_free, NULL); + clist_free(list); + err: + return res; +} + +/* +resent-date = "Resent-Date:" date-time CRLF +*/ + +static int +mailimf_resent_date_parse(const char * message, size_t length, + size_t * index, struct mailimf_orig_date ** result) +{ + struct mailimf_orig_date * orig_date; + struct mailimf_date_time * date_time; + size_t cur_token; + int r; + int res; + + cur_token = * index; + + r = mailimf_token_case_insensitive_parse(message, length, + &cur_token, "Resent-Date"); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto err; + } + + r = mailimf_colon_parse(message, length, &cur_token); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto err; + } + + r = mailimf_date_time_parse(message, length, &cur_token, &date_time); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto err; + } + + r = mailimf_unstrict_crlf_parse(message, length, &cur_token); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto free_date_time; + } + + orig_date = mailimf_orig_date_new(date_time); + if (orig_date == NULL) { + res = MAILIMF_ERROR_MEMORY; + goto free_date_time; + } + + * result = orig_date; + * index = cur_token; + + return MAILIMF_NO_ERROR; + + free_date_time: + mailimf_date_time_free(date_time); + err: + return res; +} + +/* +resent-from = "Resent-From:" mailbox-list CRLF +*/ + +static int +mailimf_resent_from_parse(const char * message, size_t length, + size_t * index, struct mailimf_from ** result) +{ + struct mailimf_mailbox_list * mb_list; + struct mailimf_from * from; + size_t cur_token; + int r; + int res; + + cur_token = * index; + + r = mailimf_token_case_insensitive_parse(message, length, + &cur_token, "Resent-From"); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto err; + } + + r = mailimf_colon_parse(message, length, &cur_token); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto err; + } + + r = mailimf_mailbox_list_parse(message, length, &cur_token, &mb_list); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto err; + } + + r = mailimf_unstrict_crlf_parse(message, length, &cur_token); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto free_mb_list; + } + + from = mailimf_from_new(mb_list); + if (from == NULL) { + res = MAILIMF_ERROR_MEMORY; + goto free_mb_list; + } + + * result = from; + * index = cur_token; + + return MAILIMF_NO_ERROR; + + free_mb_list: + mailimf_mailbox_list_free(mb_list); + err: + return res; +} + +/* +resent-sender = "Resent-Sender:" mailbox CRLF +*/ + +static int +mailimf_resent_sender_parse(const char * message, size_t length, + size_t * index, struct mailimf_sender ** result) +{ + struct mailimf_mailbox * mb; + struct mailimf_sender * sender; + size_t cur_token; + int r; + int res; + + cur_token = length; + + r = mailimf_token_case_insensitive_parse(message, length, + &cur_token, "Resent-Sender"); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto err; + } + + r = mailimf_colon_parse(message, length, &cur_token); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto err; + } + + r = mailimf_mailbox_parse(message, length, &cur_token, &mb); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto err; + } + + r = mailimf_unstrict_crlf_parse(message, length, &cur_token); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto free_mb; + } + + sender = mailimf_sender_new(mb); + if (sender == NULL) { + res = MAILIMF_ERROR_MEMORY; + goto free_mb; + } + + * result = sender; + * index = cur_token; + + return MAILIMF_NO_ERROR; + + free_mb: + mailimf_mailbox_free(mb); + err: + return res; +} + +/* +resent-to = "Resent-To:" address-list CRLF +*/ + +static int +mailimf_resent_to_parse(const char * message, size_t length, + size_t * index, struct mailimf_to ** result) +{ + struct mailimf_address_list * addr_list; + struct mailimf_to * to; + size_t cur_token; + int r; + int res; + + cur_token = * index; + + r = mailimf_token_case_insensitive_parse(message, length, + &cur_token, "Resent-To"); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto err; + } + + r = mailimf_colon_parse(message, length, &cur_token); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto err; + } + + r = mailimf_address_list_parse(message, length, &cur_token, &addr_list); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto err; + } + + r = mailimf_unstrict_crlf_parse(message, length, &cur_token); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto free_addr_list; + } + + to = mailimf_to_new(addr_list); + if (to == NULL) { + res = MAILIMF_ERROR_MEMORY; + goto free_addr_list; + } + + * result = to; + * index = cur_token; + + return MAILIMF_NO_ERROR; + + free_addr_list: + mailimf_address_list_free(addr_list); + err: + return res; +} + +/* +resent-cc = "Resent-Cc:" address-list CRLF +*/ + +static int +mailimf_resent_cc_parse(const char * message, size_t length, + size_t * index, struct mailimf_cc ** result) +{ + struct mailimf_address_list * addr_list; + struct mailimf_cc * cc; + size_t cur_token; + int r; + int res; + + cur_token = * index; + + r = mailimf_token_case_insensitive_parse(message, length, + &cur_token, "Resent-Cc"); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto err; + } + + r = mailimf_colon_parse(message, length, &cur_token); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto err; + } + + r = mailimf_address_list_parse(message, length, &cur_token, &addr_list); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto err; + } + + r = mailimf_unstrict_crlf_parse(message, length, &cur_token); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto free_addr_list; + } + + cc = mailimf_cc_new(addr_list); + if (cc == NULL) { + res = MAILIMF_ERROR_MEMORY; + goto free_addr_list; + } + + * result = cc; + * index = cur_token; + + return MAILIMF_NO_ERROR; + + free_addr_list: + mailimf_address_list_free(addr_list); + err: + return res; +} + +/* +resent-bcc = "Resent-Bcc:" (address-list / [CFWS]) CRLF +*/ + +static int +mailimf_resent_bcc_parse(const char * message, size_t length, + size_t * index, struct mailimf_bcc ** result) +{ + struct mailimf_address_list * addr_list; + struct mailimf_bcc * bcc; + size_t cur_token; + int r; + int res; + + cur_token = * index; + bcc = NULL; + + r = mailimf_token_case_insensitive_parse(message, length, + &cur_token, "Resent-Bcc"); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto err; + } + + r = mailimf_colon_parse(message, length, &cur_token); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto err; + } + + r = mailimf_address_list_parse(message, length, &cur_token, &addr_list); + if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) { + res = r; + goto err; + } + + r = mailimf_unstrict_crlf_parse(message, length, &cur_token); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto free_addr_list; + } + + bcc = mailimf_bcc_new(addr_list); + if (bcc == NULL) { + res = MAILIMF_ERROR_MEMORY; + goto free_addr_list; + } + + * result = bcc; + * index = cur_token; + + return TRUE; + + free_addr_list: + mailimf_address_list_free(addr_list); + err: + return res; +} + +/* +resent-msg-id = "Resent-Message-ID:" msg-id CRLF +*/ + +static int +mailimf_resent_msg_id_parse(const char * message, size_t length, + size_t * index, + struct mailimf_message_id ** result) +{ + char * value; + size_t cur_token; + struct mailimf_message_id * message_id; + int r; + int res; + + cur_token = * index; + + r = mailimf_token_case_insensitive_parse(message, length, + &cur_token, "Resent-Message-ID"); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto err; + } + + r = mailimf_colon_parse(message, length, &cur_token); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto err; + } + + r = mailimf_msg_id_parse(message, length, &cur_token, &value); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto err; + } + + r = mailimf_unstrict_crlf_parse(message, length, &cur_token); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto free_value; + } + + message_id = mailimf_message_id_new(value); + if (message_id == NULL) { + res = MAILIMF_ERROR_MEMORY; + goto free_value; + } + + * result = message_id; + * index = cur_token; + + return MAILIMF_NO_ERROR; + + free_value: + mailimf_msg_id_free(value); + err: + return res; +} + +/* +trace = [return] + 1*received +*/ + +#if 0 +static int mailimf_trace_parse(const char * message, size_t length, + size_t * index, + struct mailimf_trace ** result) +{ + size_t cur_token; + struct mailimf_return * return_path; + clist * received_list; + struct mailimf_trace * trace; + int r; + int res; + + cur_token = * index; + return_path = NULL; + received_list = NULL; + + r = mailimf_return_parse(message, length, &cur_token, &return_path); + if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) { + res = r; + goto err; + } + + r = mailimf_struct_multiple_parse(message, length, &cur_token, + &received_list, + (mailimf_struct_parser *) + mailimf_received_parse, + (mailimf_struct_destructor *) + mailimf_received_free); + if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) { + res = r; + goto err; + } + + if ((received_list == NULL) && (return_path == NULL)) { + res = MAILIMF_ERROR_PARSE; + goto free_return; + } + + trace = mailimf_trace_new(return_path, received_list); + if (trace == NULL) { + res = MAILIMF_ERROR_MEMORY; + goto free_list; + } + + * result = trace; + * index = cur_token; + + return MAILIMF_NO_ERROR; + + free_list: + clist_foreach(received_list, (clist_func) mailimf_received_free, NULL); + clist_free(received_list); + free_return: + if (return_path != NULL) + mailimf_return_free(return_path); + err: + return res; +} +#endif + +/* +return = "Return-Path:" path CRLF +*/ + +static int mailimf_return_parse(const char * message, size_t length, + size_t * index, + struct mailimf_return ** result) +{ + struct mailimf_path * path; + struct mailimf_return * return_path; + size_t cur_token; + int r; + int res; + + cur_token = * index; + + r = mailimf_token_case_insensitive_parse(message, length, + &cur_token, "Return-Path"); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto err; + } + + r = mailimf_colon_parse(message, length, &cur_token); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto err; + } + + r = mailimf_path_parse(message, length, &cur_token, &path); + if ( r!= MAILIMF_NO_ERROR) { + res = r; + goto err; + } + + r = mailimf_unstrict_crlf_parse(message, length, &cur_token); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto free_path; + } + + return_path = mailimf_return_new(path); + if (return_path == NULL) { + res = MAILIMF_ERROR_MEMORY; + goto free_path; + } + + * result = return_path; + * index = cur_token; + + return MAILIMF_NO_ERROR; + + free_path: + mailimf_path_free(path); + err: + return res; +} + +/* +path = ([CFWS] "<" ([CFWS] / addr-spec) ">" [CFWS]) / + obs-path +*/ + +static int mailimf_path_parse(const char * message, size_t length, + size_t * index, struct mailimf_path ** result) +{ + size_t cur_token; + char * addr_spec; + struct mailimf_path * path; + int res; + int r; + + cur_token = * index; + addr_spec = NULL; + + r = mailimf_cfws_parse(message, length, &cur_token); + if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) { + res = r; + goto err; + } + + r = mailimf_lower_parse(message, length, &cur_token); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto err; + } + + r = mailimf_addr_spec_parse(message, length, &cur_token, &addr_spec); + switch (r) { + case MAILIMF_NO_ERROR: + break; + case MAILIMF_ERROR_PARSE: + r = mailimf_cfws_parse(message, length, &cur_token); + if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) { + res = r; + goto err; + } + break; + default: + return r; + } + + r = mailimf_greater_parse(message, length, &cur_token); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto err; + } + + path = mailimf_path_new(addr_spec); + if (path == NULL) { + res = MAILIMF_ERROR_MEMORY; + goto free_addr_spec; + } + + * index = cur_token; + * result = path; + + return MAILIMF_NO_ERROR; + + free_addr_spec: + if (addr_spec == NULL) + mailimf_addr_spec_free(addr_spec); + err: + return res; +} + +/* +received = "Received:" name-val-list ";" date-time CRLF +*/ + +#if 0 +static int mailimf_received_parse(const char * message, size_t length, + size_t * index, + struct mailimf_received ** result) +{ + size_t cur_token; + struct mailimf_received * received; + struct mailimf_name_val_list * name_val_list; + struct mailimf_date_time * date_time; + int r; + int res; + + cur_token = * index; + + r = mailimf_token_case_insensitive_parse(message, length, + &cur_token, "Received"); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto err; + } + + r = mailimf_colon_parse(message, length, &cur_token); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto err; + } + + r = mailimf_name_val_list_parse(message, length, + &cur_token, &name_val_list); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto err; + } + + r = mailimf_semi_colon_parse(message, length, &cur_token); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto free_name_val_list; + } + + r = mailimf_date_time_parse(message, length, &cur_token, &date_time); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto free_name_val_list; + } + + r = mailimf_unstrict_crlf_parse(message, length, &cur_token); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto free_date_time; + } + + received = mailimf_received_new(name_val_list, date_time); + if (received == NULL) { + res = MAILIMF_ERROR_MEMORY; + goto free_date_time; + } + + * index = cur_token; + * result = received; + + return MAILIMF_NO_ERROR; + + free_date_time: + mailimf_date_time_free(date_time); + free_name_val_list: + mailimf_name_val_list_free(name_val_list); + err: + return res; +} +#endif + +/* +name-val-list = [CFWS] [name-val-pair *(CFWS name-val-pair)] +*/ + +#if 0 +static int +mailimf_name_val_list_parse(const char * message, size_t length, + size_t * index, + struct mailimf_name_val_list ** result) +{ + size_t cur_token; + struct mailimf_name_val_pair * pair; + struct mailimf_name_val_list * name_val_list; + clist* list; + int res; + int r; + + cur_token = * index; + list = NULL; + + r = mailimf_name_val_pair_parse(message, length, &cur_token, &pair); + + if (r == MAILIMF_NO_ERROR){ + size_t final_token; + + list = clist_new(); + if (list == NULL) { + mailimf_name_val_pair_free(pair); + res = MAILIMF_ERROR_MEMORY; + goto err; + } + + r = clist_append(list, pair); + if (r < 0) { + mailimf_name_val_pair_free(pair); + res = MAILIMF_ERROR_MEMORY; + goto free_list; + } + + final_token = cur_token; + + while (1) { + r = mailimf_cfws_parse(message, length, &cur_token); + if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) { + res = r; + goto free_list; + } + + r = mailimf_name_val_pair_parse(message, length, &cur_token, &pair); + if (r == MAILIMF_NO_ERROR) { + /* do nothing */ + } + else if (r == MAILIMF_ERROR_PARSE) + break; + else { + res = r; + goto free_list; + } + + r = clist_append(list, pair); + if (r < 0) { + mailimf_name_val_pair_free(pair); + res = MAILIMF_ERROR_MEMORY; + goto free_list; + } + + final_token = cur_token; + } + cur_token = final_token; + } + + name_val_list = mailimf_name_val_list_new(list); + if (name_val_list == NULL) { + res = MAILIMF_ERROR_MEMORY; + goto free_list; + } + + * index = cur_token; + * result = name_val_list; + + return MAILIMF_NO_ERROR; + + free_list: + if (list != NULL) { + clist_foreach(list, (clist_func) mailimf_name_val_pair_free, NULL); + clist_free(list); + } + err: + return res; +} +#endif + +/* +name-val-pair = item-name CFWS item-value +*/ + +#if 0 +static int +mailimf_name_val_pair_parse(const char * message, size_t length, + size_t * index, + struct mailimf_name_val_pair ** result) +{ + size_t cur_token; + char * item_name; + struct mailimf_item_value * item_value; + struct mailimf_name_val_pair * name_val_pair; + int r; + int res; + + cur_token = * index; + + r = mailimf_cfws_parse(message, length, &cur_token); + if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) { + res = r; + goto err; + } + + r = mailimf_item_name_parse(message, length, &cur_token, &item_name); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto err; + } + + r = mailimf_cfws_parse(message, length, &cur_token); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto free_item_name; + } + + r = mailimf_item_value_parse(message, length, &cur_token, &item_value); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto free_item_name; + } + + name_val_pair = mailimf_name_val_pair_new(item_name, item_value); + if (name_val_pair == NULL) { + res = MAILIMF_ERROR_MEMORY; + goto free_item_value; + } + + * result = name_val_pair; + * index = cur_token; + + return MAILIMF_NO_ERROR; + + free_item_value: + mailimf_item_value_free(item_value); + free_item_name: + mailimf_item_name_free(item_name); + err: + return res; +} +#endif + +/* +item-name = ALPHA *(["-"] (ALPHA / DIGIT)) +*/ + +#if 0 +static int mailimf_item_name_parse(const char * message, size_t length, + size_t * index, char ** result) +{ + size_t cur_token; + size_t begin; + char * item_name; + char ch; + int digit; + int r; + int res; + + cur_token = * index; + + begin = cur_token; + + r = mailimf_alpha_parse(message, length, &cur_token, &ch); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto err; + } + + while (1) { + int minus_sign; + + minus_sign = mailimf_minus_parse(message, length, &cur_token); + + r = mailimf_alpha_parse(message, length, &cur_token, &ch); + if (r == MAILIMF_ERROR_PARSE) + r = mailimf_digit_parse(message, length, &cur_token, &digit); + + if (r == MAILIMF_NO_ERROR) { + /* do nothing */ + } + if (r == MAILIMF_ERROR_PARSE) + break; + else if (r != MAILIMF_NO_ERROR) { + res = r; + goto err; + } + } + + item_name = strndup(message + begin, cur_token - begin); + if (item_name == NULL) { + res = MAILIMF_ERROR_MEMORY; + goto err; + } + + * index = cur_token; + * result = item_name; + + return MAILIMF_NO_ERROR; + + err: + return res; +} +#endif + +/* +item-value = 1*angle-addr / addr-spec / + atom / domain / msg-id +*/ + +#if 0 +static int is_item_value_atext(char ch) +{ + switch (ch) { + case '\t': + case ' ': + case '\r': + case '\n': + case ';': + return FALSE; + default: + return TRUE; + } +} + +static int mailimf_item_value_atom_parse(const char * message, size_t length, + size_t * index, char ** result) +{ + char * atom; + size_t cur_token; + int r; + + cur_token = * index; + + r = mailimf_cfws_parse(message, length, &cur_token); + if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) + return r; + + r = mailimf_custom_string_parse(message, length, &cur_token, + &atom, is_item_value_atext); + 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; + + * index = cur_token; + * result = atom; + + return MAILIMF_NO_ERROR; +} + +static int mailimf_item_value_parse(const char * message, size_t length, + size_t * index, + struct mailimf_item_value ** result) +{ + size_t cur_token; + clist * angle_addr_list; + char * addr_spec; + char * atom; + char * domain; + char * msg_id; + int type; + struct mailimf_item_value * item_value; + int r; + int res; + + cur_token = * index; + + angle_addr_list = NULL; + addr_spec = NULL; + atom = NULL; + domain = NULL; + msg_id = NULL; + + r = mailimf_struct_multiple_parse(message, length, &cur_token, + &angle_addr_list, + (mailimf_struct_parser *) + mailimf_angle_addr_parse, + (mailimf_struct_destructor *) + mailimf_angle_addr_free); + if (r == MAILIMF_NO_ERROR) + type = MAILIMF_ITEM_VALUE_ANGLE_ADDR_LIST; + + if (r == MAILIMF_ERROR_PARSE) { + r = mailimf_addr_spec_parse(message, length, &cur_token, + &addr_spec); + if (r == MAILIMF_NO_ERROR) + type = MAILIMF_ITEM_VALUE_ADDR_SPEC; + } + + if (r == MAILIMF_ERROR_PARSE) { + r = mailimf_msg_id_parse(message, length, &cur_token, + &msg_id); + if (r == MAILIMF_NO_ERROR) + type = MAILIMF_ITEM_VALUE_MSG_ID; + } + + /* + else if (mailimf_domain_parse(message, length, &cur_token, + &domain)) + type = MAILIMF_ITEM_VALUE_DOMAIN; + */ + /* + else if (mailimf_atom_parse(message, length, &cur_token, + &atom)) + type = MAILIMF_ITEM_VALUE_ATOM; + */ + + if (r == MAILIMF_ERROR_PARSE) { + r = mailimf_item_value_atom_parse(message, length, &cur_token, + &atom); + if (r == MAILIMF_NO_ERROR) + type = MAILIMF_ITEM_VALUE_ATOM; + } + + if (r != MAILIMF_NO_ERROR) { + res = r; + goto err; + } + + item_value = mailimf_item_value_new(type, angle_addr_list, addr_spec, + atom, domain, msg_id); + if (item_value == NULL) { + res = MAILIMF_ERROR_MEMORY; + goto free; + } + + * result = item_value; + * index = cur_token; + + return MAILIMF_NO_ERROR; + + free: + if (angle_addr_list != NULL) { + clist_foreach(angle_addr_list, (clist_func) mailimf_angle_addr_free, NULL); + clist_free(angle_addr_list); + } + if (addr_spec != NULL) + mailimf_addr_spec_free(addr_spec); + if (atom != NULL) + mailimf_atom_free(atom); + if (domain != NULL) + mailimf_domain_free(domain); + if (msg_id != NULL) + mailimf_msg_id_free(msg_id); + err: + return res; +} +#endif + +/* +optional-field = field-name ":" unstructured CRLF +*/ + +static int +mailimf_optional_field_parse(const char * message, size_t length, + size_t * index, + struct mailimf_optional_field ** result) +{ + char * name; + char * value; + struct mailimf_optional_field * optional_field; + size_t cur_token; + int r; + int res; + + cur_token = * index; + + r = mailimf_field_name_parse(message, length, &cur_token, &name); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto err; + } + + r = mailimf_colon_parse(message, length, &cur_token); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto free_name; + } + + r = mailimf_unstructured_parse(message, length, &cur_token, &value); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto free_name; + } + + r = mailimf_unstrict_crlf_parse(message, length, &cur_token); + if (r != MAILIMF_NO_ERROR) { + res = r; + goto free_value; + } + + optional_field = mailimf_optional_field_new(name, value); + if (optional_field == NULL) { + res = MAILIMF_ERROR_MEMORY; + goto free_value; + } + + * result = optional_field; + * index = cur_token; + + return MAILIMF_NO_ERROR; + + free_value: + mailimf_unstructured_free(value); + free_name: + mailimf_field_name_free(name); + err: + return res; +} + +/* +field-name = 1*ftext +*/ + +static inline int is_ftext(char ch); + +static int mailimf_field_name_parse(const char * message, size_t length, + size_t * index, char ** result) +{ + char * field_name; + size_t cur_token; + size_t end; + + cur_token = * index; + + end = cur_token; + if (end >= length) { + return MAILIMF_ERROR_PARSE; + } + + while (is_ftext(message[end])) { + end ++; + if (end >= length) + break; + } + if (end == cur_token) { + return MAILIMF_ERROR_PARSE; + } + + /* field_name = strndup(message + cur_token, end - cur_token); */ + field_name = malloc(end - cur_token + 1); + if (field_name == NULL) { + return MAILIMF_ERROR_MEMORY; + } + strncpy(field_name, message + cur_token, end - cur_token); + field_name[end - cur_token] = '\0'; + + cur_token = end; + + * index = cur_token; + * result = field_name; + + return MAILIMF_NO_ERROR; +} + +/* +ftext = %d33-57 / ; Any character except + %d59-126 ; controls, SP, and + ; ":". +*/ + +static inline int is_ftext(char ch) +{ + unsigned char uch = (unsigned char) ch; + + if (uch < 33) + return FALSE; + + if (uch == 58) + return FALSE; + + return TRUE; +} + +/* +static int mailimf_ftext_parse(const char * message, size_t length, + size_t * index, gchar * result) +{ + return mailimf_typed_text_parse(message, length, index, result, is_ftext); +} +*/ + + + + +static int mailimf_envelope_field_parse(const char * message, size_t length, + size_t * index, + struct mailimf_field ** result) +{ + size_t cur_token; + int type; + struct mailimf_orig_date * orig_date; + struct mailimf_from * from; + struct mailimf_sender * sender; + struct mailimf_reply_to * reply_to; + struct mailimf_to * to; + struct mailimf_cc * cc; + struct mailimf_bcc * bcc; + struct mailimf_message_id * message_id; + struct mailimf_in_reply_to * in_reply_to; + struct mailimf_references * references; + struct mailimf_subject * subject; + struct mailimf_optional_field * optional_field; + struct mailimf_field * field; + int guessed_type; + int r; + int res; + + cur_token = * index; + + orig_date = NULL; + from = NULL; + sender = NULL; + reply_to = NULL; + to = NULL; + cc = NULL; + bcc = NULL; + message_id = NULL; + in_reply_to = NULL; + references = NULL; + subject = NULL; + optional_field = NULL; + + guessed_type = guess_header_type(message, length, cur_token); + type = MAILIMF_FIELD_NONE; + + switch (guessed_type) { + case MAILIMF_FIELD_ORIG_DATE: + r = mailimf_orig_date_parse(message, length, &cur_token, + &orig_date); + if (r == MAILIMF_NO_ERROR) + type = guessed_type; + else if (r == MAILIMF_ERROR_PARSE) { + /* do nothing */ + } + else { + res = r; + goto err; + } + break; + case MAILIMF_FIELD_FROM: + r = mailimf_from_parse(message, length, &cur_token, + &from); + if (r == MAILIMF_NO_ERROR) + type = guessed_type; + else if (r == MAILIMF_ERROR_PARSE) { + /* do nothing */ + } + else { + res = r; + goto err; + } + break; + case MAILIMF_FIELD_SENDER: + r = mailimf_sender_parse(message, length, &cur_token, + &sender); + if (r == MAILIMF_NO_ERROR) + type = guessed_type; + else if (r == MAILIMF_ERROR_PARSE) { + /* do nothing */ + } + else { + res = r; + goto err; + } + break; + case MAILIMF_FIELD_REPLY_TO: + r = mailimf_reply_to_parse(message, length, &cur_token, + &reply_to); + if (r == MAILIMF_NO_ERROR) + type = guessed_type; + else if (r == MAILIMF_ERROR_PARSE) { + /* do nothing */ + } + else { + res = r; + goto err; + } + break; + case MAILIMF_FIELD_TO: + r = mailimf_to_parse(message, length, &cur_token, + &to); + if (r == MAILIMF_NO_ERROR) + type = guessed_type; + else if (r == MAILIMF_ERROR_PARSE) { + /* do nothing */ + } + else { + res = r; + goto err; + } + break; + case MAILIMF_FIELD_CC: + r = mailimf_cc_parse(message, length, &cur_token, + &cc); + if (r == MAILIMF_NO_ERROR) + type = guessed_type; + else if (r == MAILIMF_ERROR_PARSE) { + /* do nothing */ + } + else { + res = r; + goto err; + } + break; + case MAILIMF_FIELD_BCC: + r = mailimf_bcc_parse(message, length, &cur_token, + &bcc); + if (r == MAILIMF_NO_ERROR) + type = guessed_type; + else if (r == MAILIMF_ERROR_PARSE) { + /* do nothing */ + } + else { + res = r; + goto err; + } + break; + case MAILIMF_FIELD_MESSAGE_ID: + r = mailimf_message_id_parse(message, length, &cur_token, + &message_id); + if (r == MAILIMF_NO_ERROR) + type = guessed_type; + else if (r == MAILIMF_ERROR_PARSE) { + /* do nothing */ + } + else { + res = r; + goto err; + } + break; + case MAILIMF_FIELD_IN_REPLY_TO: + r = mailimf_in_reply_to_parse(message, length, &cur_token, + &in_reply_to); + if (r == MAILIMF_NO_ERROR) + type = guessed_type; + else if (r == MAILIMF_ERROR_PARSE) { + /* do nothing */ + } + else { + res = r; + goto err; + } + break; + case MAILIMF_FIELD_REFERENCES: + r = mailimf_references_parse(message, length, &cur_token, + &references); + if (r == MAILIMF_NO_ERROR) + type = guessed_type; + else if (r == MAILIMF_ERROR_PARSE) { + /* do nothing */ + } + else { + res = r; + goto err; + } + break; + case MAILIMF_FIELD_SUBJECT: + r = mailimf_subject_parse(message, length, &cur_token, + &subject); + if (r == MAILIMF_NO_ERROR) + type = guessed_type; + else if (r == MAILIMF_ERROR_PARSE) { + /* do nothing */ + } + else { + res = r; + goto err; + } + break; + } + + if (type == MAILIMF_FIELD_NONE) { + res = MAILIMF_ERROR_PARSE; + goto err; + } + + field = mailimf_field_new(type, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, + orig_date, from, sender, reply_to, to, + cc, bcc, message_id, in_reply_to, references, + subject, NULL, NULL, optional_field); + if (field == NULL) { + res = MAILIMF_ERROR_MEMORY; + goto free_field; + } + + * result = field; + * index = cur_token; + + return MAILIMF_NO_ERROR; + + free_field: + if (orig_date != NULL) + mailimf_orig_date_free(orig_date); + if (from != NULL) + mailimf_from_free(from); + if (sender != NULL) + mailimf_sender_free(sender); + if (reply_to != NULL) + mailimf_reply_to_free(reply_to); + if (to != NULL) + mailimf_to_free(to); + if (cc != NULL) + mailimf_cc_free(cc); + if (bcc != NULL) + mailimf_bcc_free(bcc); + if (message_id != NULL) + mailimf_message_id_free(message_id); + if (in_reply_to != NULL) + mailimf_in_reply_to_free(in_reply_to); + if (references != NULL) + mailimf_references_free(references); + if (subject != NULL) + mailimf_subject_free(subject); + if (optional_field != NULL) + mailimf_optional_field_free(optional_field); + err: + return res; +} + +int mailimf_envelope_fields_parse(const char * message, size_t length, + size_t * index, + struct mailimf_fields ** result) +{ + size_t cur_token; + clist * list; + struct mailimf_fields * fields; + int r; + int res; + + cur_token = * index; + + list = clist_new(); + if (list == NULL) { + res = MAILIMF_ERROR_MEMORY; + goto err; + } + + while (1) { + struct mailimf_field * elt; + + r = mailimf_envelope_field_parse(message, length, &cur_token, &elt); + if (r == MAILIMF_NO_ERROR) { + r = clist_append(list, elt); + if (r < 0) { + res = MAILIMF_ERROR_MEMORY; + goto free; + } + } + else if (r == MAILIMF_ERROR_PARSE) { + r = mailimf_ignore_field_parse(message, length, &cur_token); + if (r == MAILIMF_NO_ERROR) { + /* do nothing */ + } + else if (r == MAILIMF_ERROR_PARSE) { + break; + } + else { + res = r; + goto free; + } + } + else { + res = r; + goto free; + } + } + + fields = mailimf_fields_new(list); + if (fields == NULL) { + res = MAILIMF_ERROR_MEMORY; + goto free; + } + + * result = fields; + * index = cur_token; + + return MAILIMF_NO_ERROR; + + free: + if (list != NULL) { + clist_foreach(list, (clist_func) mailimf_field_free, NULL); + clist_free(list); + } + err: + return res; +} + + +static int +mailimf_envelope_or_optional_field_parse(const char * message, + size_t length, + size_t * index, + struct mailimf_field ** result) +{ + int r; + size_t cur_token; + struct mailimf_optional_field * optional_field; + struct mailimf_field * field; + + r = mailimf_envelope_field_parse(message, length, index, result); + if (r == MAILIMF_NO_ERROR) + return MAILIMF_NO_ERROR; + + cur_token = * index; + + r = mailimf_optional_field_parse(message, length, &cur_token, + &optional_field); + if (r != MAILIMF_NO_ERROR) + return r; + + field = mailimf_field_new(MAILIMF_FIELD_OPTIONAL_FIELD, NULL, + NULL, NULL, NULL, + NULL, NULL, NULL, + NULL, NULL, NULL, + NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, optional_field); + if (field == NULL) { + mailimf_optional_field_free(optional_field); + return MAILIMF_ERROR_MEMORY; + } + + * result = field; + * index = cur_token; + + return MAILIMF_NO_ERROR; +} + + +int +mailimf_envelope_and_optional_fields_parse(const char * message, size_t length, + size_t * index, + struct mailimf_fields ** result) +{ + size_t cur_token; + clist * list; + struct mailimf_fields * fields; + int r; + int res; + + cur_token = * index; + + list = NULL; + + r = mailimf_struct_multiple_parse(message, length, &cur_token, + &list, + (mailimf_struct_parser *) + mailimf_envelope_or_optional_field_parse, + (mailimf_struct_destructor *) + mailimf_field_free); + switch (r) { + case MAILIMF_NO_ERROR: + /* do nothing */ + break; + + case MAILIMF_ERROR_PARSE: + list = clist_new(); + if (list == NULL) { + res = MAILIMF_ERROR_MEMORY; + goto err; + } + break; + + default: + res = r; + goto err; + } + + fields = mailimf_fields_new(list); + if (fields == NULL) { + res = MAILIMF_ERROR_MEMORY; + goto free; + } + + * result = fields; + * index = cur_token; + + return MAILIMF_NO_ERROR; + + free: + if (list != NULL) { + clist_foreach(list, (clist_func) mailimf_field_free, NULL); + clist_free(list); + } + err: + return res; +} + + + +static int +mailimf_only_optional_field_parse(const char * message, + size_t length, + size_t * index, + struct mailimf_field ** result) +{ + int r; + size_t cur_token; + struct mailimf_optional_field * optional_field; + struct mailimf_field * field; + + cur_token = * index; + + r = mailimf_optional_field_parse(message, length, &cur_token, + &optional_field); + if (r != MAILIMF_NO_ERROR) + return r; + + field = mailimf_field_new(MAILIMF_FIELD_OPTIONAL_FIELD, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, optional_field); + if (field == NULL) { + mailimf_optional_field_free(optional_field); + return MAILIMF_ERROR_MEMORY; + } + + * result = field; + * index = cur_token; + + return MAILIMF_NO_ERROR; +} + + +int +mailimf_optional_fields_parse(const char * message, size_t length, + size_t * index, + struct mailimf_fields ** result) +{ + size_t cur_token; + clist * list; + struct mailimf_fields * fields; + int r; + int res; + + cur_token = * index; + + list = NULL; + + r = mailimf_struct_multiple_parse(message, length, &cur_token, + &list, + (mailimf_struct_parser *) + mailimf_only_optional_field_parse, + (mailimf_struct_destructor *) + mailimf_field_free); + switch (r) { + case MAILIMF_NO_ERROR: + /* do nothing */ + break; + + case MAILIMF_ERROR_PARSE: + list = clist_new(); + if (list == NULL) { + res = MAILIMF_ERROR_MEMORY; + goto err; + } + break; + + default: + res = r; + goto err; + } + + fields = mailimf_fields_new(list); + if (fields == NULL) { + res = MAILIMF_ERROR_MEMORY; + goto free; + } + + * result = fields; + * index = cur_token; + + return MAILIMF_NO_ERROR; + + free: + if (list != NULL) { + clist_foreach(list, (clist_func) mailimf_field_free, NULL); + clist_free(list); + } + err: + return res; +} -- cgit v0.9.0.2