summaryrefslogtreecommitdiffabout
path: root/kmicromail/libetpan/imf/mailimf.c
Side-by-side diff
Diffstat (limited to 'kmicromail/libetpan/imf/mailimf.c') (more/less context) (ignore whitespace changes)
-rw-r--r--kmicromail/libetpan/imf/mailimf.c2
1 files changed, 1 insertions, 1 deletions
diff --git a/kmicromail/libetpan/imf/mailimf.c b/kmicromail/libetpan/imf/mailimf.c
index 84d81a1..e0164b8 100644
--- a/kmicromail/libetpan/imf/mailimf.c
+++ b/kmicromail/libetpan/imf/mailimf.c
@@ -1,4147 +1,4147 @@
/*
* 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 <ctype.h>
-#include <mmapstring.h>
+#include "mmapstring.h"
#include <stdlib.h>
#include <string.h>
#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;