libetpan - fdik
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

7823 lines
159 KiB

/*
* libEtPan! -- a mail stuff library
*
* Copyright (C) 2001, 2005 - DINH Viet Hoa
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the libEtPan! project nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* $Id: mailimf.c,v 1.50 2011/06/20 23:25:26 hoa Exp $
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#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 <stdlib.h>
#include <string.h>
#include "mailmime_decode.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 * indx, char * result);
static int mailimf_ccontent_parse(const char * message, size_t length,
size_t * indx);
static int
mailimf_comment_fws_ccontent_parse(const char * message, size_t length,
size_t * indx);
static inline int mailimf_comment_parse(const char * message, size_t length,
size_t * indx);
static int mailimf_qcontent_parse(const char * message, size_t length,
size_t * indx, char * ch);
static int mailimf_phrase_parse(const char * message, size_t length,
size_t * indx, char ** result);
static int mailimf_unstructured_parse(const char * message, size_t length,
size_t * indx, char ** result);
static int mailimf_ignore_unstructured_parse(const char * message, size_t length,
size_t * indx);
static int mailimf_day_of_week_parse(const char * message, size_t length,
size_t * indx, int * result);
static int mailimf_day_name_parse(const char * message, size_t length,
size_t * indx, int * result);
static int mailimf_date_parse(const char * message, size_t length,
size_t * indx,
int * pday, int * pmonth, int * pyear);
static int mailimf_year_parse(const char * message, size_t length,
size_t * indx, int * result);
static int mailimf_month_parse(const char * message, size_t length,
size_t * indx, int * result);
static int mailimf_month_name_parse(const char * message, size_t length,
size_t * indx, int * result);
static int mailimf_day_parse(const char * message, size_t length,
size_t * indx, int * result);
static int mailimf_time_parse(const char * message, size_t length,
size_t * indx,
int * phour, int * pmin,
int * psec,
int * zone);
static int mailimf_time_of_day_parse(const char * message, size_t length,
size_t * indx,
int * phour, int * pmin,
int * psec);
static int mailimf_hour_parse(const char * message, size_t length,
size_t * indx, int * result);
static int mailimf_minute_parse(const char * message, size_t length,
size_t * indx, int * result);
static int mailimf_second_parse(const char * message, size_t length,
size_t * indx, int * result);
static int mailimf_zone_parse(const char * message, size_t length,
size_t * indx, int * result);
static int mailimf_name_addr_parse(const char * message, size_t length,
size_t * indx,
char ** pdisplay_name,
char ** pangle_addr);
static int mailimf_angle_addr_parse(const char * message, size_t length,
size_t * indx, char ** result);
static int mailimf_group_parse(const char * message, size_t length,
size_t * indx,
struct mailimf_group ** result);
static int mailimf_display_name_parse(const char * message, size_t length,
size_t * indx, char ** result);
static int mailimf_addr_spec_parse(const char * message, size_t length,
size_t * indx,
char ** address);
static int
mailimf_orig_date_parse(const char * message, size_t length,
size_t * indx, struct mailimf_orig_date ** result);
static int
mailimf_from_parse(const char * message, size_t length,
size_t * indx, struct mailimf_from ** result);
static int
mailimf_sender_parse(const char * message, size_t length,
size_t * indx, struct mailimf_sender ** result);
static int
mailimf_reply_to_parse(const char * message, size_t length,
size_t * indx, struct mailimf_reply_to ** result);
static int
mailimf_to_parse(const char * message, size_t length,
size_t * indx, struct mailimf_to ** result);
static int
mailimf_cc_parse(const char * message, size_t length,
size_t * indx, struct mailimf_cc ** result);
static int
mailimf_bcc_parse(const char * message, size_t length,
size_t * indx, struct mailimf_bcc ** result);
static int mailimf_message_id_parse(const char * message, size_t length,
size_t * indx,
struct mailimf_message_id ** result);
static int
mailimf_in_reply_to_parse(const char * message, size_t length,
size_t * indx,
struct mailimf_in_reply_to ** result);
static int mailimf_unstrict_msg_id_parse(const char * message, size_t length,
size_t * indx,
char ** result);
static int mailimf_subject_parse(const char * message, size_t length,
size_t * indx,
struct mailimf_subject ** result);
static int mailimf_comments_parse(const char * message, size_t length,
size_t * indx,
struct mailimf_comments ** result);
static int mailimf_keywords_parse(const char * message, size_t length,
size_t * indx,
struct mailimf_keywords ** result);
static int
mailimf_resent_date_parse(const char * message, size_t length,
size_t * indx, struct mailimf_orig_date ** result);
static int
mailimf_resent_from_parse(const char * message, size_t length,
size_t * indx, struct mailimf_from ** result);
static int
mailimf_resent_sender_parse(const char * message, size_t length,
size_t * indx, struct mailimf_sender ** result);
static int
mailimf_resent_to_parse(const char * message, size_t length,
size_t * indx, struct mailimf_to ** result);
static int
mailimf_resent_cc_parse(const char * message, size_t length,
size_t * indx, struct mailimf_cc ** result);
static int
mailimf_resent_bcc_parse(const char * message, size_t length,
size_t * indx, struct mailimf_bcc ** result);
static int
mailimf_resent_msg_id_parse(const char * message, size_t length,
size_t * indx,
struct mailimf_message_id ** result);
static int mailimf_return_parse(const char * message, size_t length,
size_t * indx,
struct mailimf_return ** result);
static int
mailimf_path_parse(const char * message, size_t length,
size_t * indx, struct mailimf_path ** result);
static int
mailimf_optional_field_parse(const char * message, size_t length,
size_t * indx,
struct mailimf_optional_field ** result);
static int mailimf_field_name_parse(const char * message, size_t length,
size_t * indx, 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 * indx, int * result)
{
size_t cur_token;
cur_token = * indx;
if (cur_token >= length)
return MAILIMF_ERROR_PARSE;
if (is_digit(message[cur_token])) {
* result = message[cur_token] - '0';
cur_token ++;
* indx = cur_token;
return MAILIMF_NO_ERROR;
}
else
return MAILIMF_ERROR_PARSE;
}
LIBETPAN_EXPORT
int
mailimf_number_parse(const char * message, size_t length,
size_t * indx, uint32_t * result)
{
size_t cur_token;
int digit;
uint32_t number;
int parsed;
int r;
cur_token = * indx;
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;
* indx = cur_token;
return MAILIMF_NO_ERROR;
}
LIBETPAN_EXPORT
int mailimf_char_parse(const char * message, size_t length,
size_t * indx, char token)
{
size_t cur_token;
cur_token = * indx;
if (cur_token >= length)
return MAILIMF_ERROR_PARSE;
if (message[cur_token] == token) {
cur_token ++;
* indx = cur_token;
return MAILIMF_NO_ERROR;
}
else
return MAILIMF_ERROR_PARSE;
}
LIBETPAN_EXPORT
int mailimf_unstrict_char_parse(const char * message, size_t length,
size_t * indx, char token)
{
size_t cur_token;
int r;
cur_token = * indx;
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;
* indx = cur_token;
return MAILIMF_NO_ERROR;
}
LIBETPAN_EXPORT
int
mailimf_token_case_insensitive_len_parse(const char * message, size_t length,
size_t * indx, char * token,
size_t token_length)
{
size_t cur_token;
cur_token = * indx;
if (cur_token + token_length - 1 >= length)
return MAILIMF_ERROR_PARSE;
if (strncasecmp(message + cur_token, token, token_length) == 0) {
cur_token += token_length;
* indx = cur_token;
return MAILIMF_NO_ERROR;
}
else
return MAILIMF_ERROR_PARSE;
}
static int mailimf_oparenth_parse(const char * message, size_t length,
size_t * indx)
{
return mailimf_char_parse(message, length, indx, '(');
}
static int mailimf_cparenth_parse(const char * message, size_t length,
size_t * indx)
{
return mailimf_char_parse(message, length, indx, ')');
}
static int mailimf_comma_parse(const char * message, size_t length,
size_t * indx)
{
return mailimf_unstrict_char_parse(message, length, indx, ',');
}
static int mailimf_dquote_parse(const char * message, size_t length,
size_t * indx)
{
return mailimf_char_parse(message, length, indx, '\"');
}
static int mailimf_colon_parse(const char * message, size_t length,
size_t * indx)
{
return mailimf_unstrict_char_parse(message, length, indx, ':');
}
static int mailimf_semi_colon_parse(const char * message, size_t length,
size_t * indx)
{
return mailimf_unstrict_char_parse(message, length, indx, ';');
}
static int mailimf_plus_parse(const char * message, size_t length,
size_t * indx)
{
return mailimf_unstrict_char_parse(message, length, indx, '+');
}
static int mailimf_minus_parse(const char * message, size_t length,
size_t * indx)
{
return mailimf_unstrict_char_parse(message, length, indx, '-');
}
static int mailimf_lower_parse(const char * message, size_t length,
size_t * indx)
{
return mailimf_unstrict_char_parse(message, length, indx, '<');
}
static int mailimf_greater_parse(const char * message, size_t length,
size_t * indx)
{
return mailimf_unstrict_char_parse(message, length, indx, '>');
}
static int mailimf_at_sign_parse(const char * message, size_t length,
size_t * indx)
{
return mailimf_unstrict_char_parse(message, length, indx, '@');
}
static int mailimf_point_parse(const char * message, size_t length,
size_t * indx)
{
return mailimf_unstrict_char_parse(message, length, indx, '.');
}
LIBETPAN_EXPORT
int
mailimf_custom_string_parse(const char * message, size_t length,
size_t * indx, char ** result,
int (* is_custom_char)(char))
{
size_t begin;
size_t end;
char * gstr;
begin = * indx;
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';
* indx = 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 * indx, void * result);
typedef int mailimf_struct_destructor(void * result);
static int
mailimf_struct_multiple_parse(const char * message, size_t length,
size_t * indx, 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 = * indx;
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;
* indx = 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 * indx, 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 = * indx;
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;
* indx = 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 * indx)
{
size_t cur_token;
cur_token = * indx;
if (cur_token >= length)
return MAILIMF_ERROR_PARSE;
if ((message[cur_token] != ' ') && (message[cur_token] != '\t'))
return MAILIMF_ERROR_PARSE;
cur_token ++;
* indx = cur_token;
return MAILIMF_NO_ERROR;
}
LIBETPAN_EXPORT
int mailimf_crlf_parse(const char * message, size_t length, size_t * indx)
{
size_t cur_token;
int r;
cur_token = * indx;
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;
* indx = cur_token;
return MAILIMF_NO_ERROR;
}
static int mailimf_unstrict_crlf_parse(const char * message,
size_t length, size_t * indx)
{
size_t cur_token;
int r;
cur_token = * indx;
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;
* indx = 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 * indx, char * result)
{
size_t cur_token;
cur_token = * indx;
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 ++;
* indx = cur_token;
return MAILIMF_NO_ERROR;
}
/*
FWS = ([*WSP CRLF] 1*WSP) / ; Folding white space
obs-FWS
*/
LIBETPAN_EXPORT
int mailimf_fws_parse(const char * message, size_t length, size_t * indx)
{
size_t cur_token;
size_t final_token;
int fws_1;
int fws_2;
int fws_3;
int r;
cur_token = * indx;
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;
* indx = 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 * indx)
{
size_t cur_token;
char ch;
int r;
cur_token = * indx;
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;
}
* indx = cur_token;
return MAILIMF_NO_ERROR;
}
/*
[FWS] ccontent
*/
static inline int
mailimf_comment_fws_ccontent_parse(const char * message, size_t length,
size_t * indx)
{
size_t cur_token;
int r;
cur_token = * indx;
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;
* indx = cur_token;
return MAILIMF_NO_ERROR;
}
/*
comment = "(" *([FWS] ccontent) [FWS] ")"
*/
static inline int mailimf_comment_parse(const char * message, size_t length,
size_t * indx)
{
size_t cur_token;
int r;
cur_token = * indx;
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;
* indx = cur_token;
return MAILIMF_NO_ERROR;
}
/*
[FWS] comment
*/
static inline int mailimf_cfws_fws_comment_parse(const char * message, size_t length,
size_t * indx)
{
size_t cur_token;
int r;
cur_token = * indx;
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;
* indx = cur_token;
return MAILIMF_NO_ERROR;
}
/*
CFWS = *([FWS] comment) (([FWS] comment) / FWS)
*/
LIBETPAN_EXPORT
int mailimf_cfws_parse(const char * message, size_t length,
size_t * indx)
{
size_t cur_token;
int has_comment;
int r;
cur_token = * indx;
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;
}
* indx = 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]
*/
LIBETPAN_EXPORT
int mailimf_atom_parse(const char * message, size_t length,
size_t * indx, char ** result)
{
size_t cur_token;
int r;
int res;
char * atom;
size_t end;
cur_token = * indx;
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;
* indx = cur_token;
* result = atom;
return MAILIMF_NO_ERROR;
err:
return res;
}
LIBETPAN_EXPORT
int mailimf_fws_atom_for_word_parse(const char * message, size_t length,
size_t * indx, char ** result, int * p_missing_closing_quote)
{
size_t end;
size_t cur_token;
int r;
int res;
struct mailmime_encoded_word * word;
int has_fwd;
int missing_closing_quote;
char * atom;
cur_token = * indx;
missing_closing_quote = 0;
r = mailimf_fws_parse(message, length, &cur_token);
if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
res = r;
goto err;
}
end = cur_token;
r = mailmime_encoded_word_parse(message, length, &cur_token, &word, &has_fwd, &missing_closing_quote);
if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
res = r;
goto err;
}
if (r == MAILIMF_ERROR_PARSE) {
return mailimf_fws_atom_parse(message, length, indx, result);
}
mailmime_encoded_word_free(word);
atom = malloc(cur_token - end + 1);
if (atom == NULL) {
res = MAILIMF_ERROR_MEMORY;
goto err;
}
strncpy(atom, message + end, cur_token - end);
atom[cur_token - end] = '\0';
* result = atom;
* indx = cur_token;
* p_missing_closing_quote = missing_closing_quote;
return MAILIMF_NO_ERROR;
err:
return res;
}
LIBETPAN_EXPORT
int mailimf_fws_atom_parse(const char * message, size_t length,
size_t * indx, char ** result)
{
size_t cur_token;
int r;
int res;
char * atom;
size_t end;
cur_token = * indx;
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;
* indx = 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 * indx, char ** result)
{
return mailimf_atom_parse(message, length, indx, 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 * indx, char ** result)
{
return mailimf_atom_parse(message, length, indx, 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 * indx, char * result)
{
size_t cur_token;
char ch;
int r;
cur_token = * indx;
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;
* indx = cur_token;
return MAILIMF_NO_ERROR;
}
/*
quoted-string = [CFWS]
DQUOTE *([FWS] qcontent) [FWS] DQUOTE
[CFWS]
*/
LIBETPAN_EXPORT
int mailimf_quoted_string_parse(const char * message, size_t length,
size_t * indx, char ** result)
{
size_t cur_token;
MMAPString * gstr;
char ch;
char * str;
int r;
int res;
cur_token = * indx;
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);
* indx = cur_token;
* result = str;
return MAILIMF_NO_ERROR;
free_gstr:
mmap_string_free(gstr);
err:
return res;
}
LIBETPAN_EXPORT
int mailimf_fws_quoted_string_parse(const char * message, size_t length,
size_t * indx, char ** result)
{
size_t cur_token;
MMAPString * gstr;
char ch;
char * str;
int r;
int res;
cur_token = * indx;
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);
* indx = cur_token;
* result = str;
return MAILIMF_NO_ERROR;
free_gstr:
mmap_string_free(gstr);
err:
return res;
}
/*
word = atom / quoted-string
*/
LIBETPAN_EXPORT
int mailimf_word_parse(const char * message, size_t length,
size_t * indx, char ** result)
{
size_t cur_token;
char * word;
int r;
cur_token = * indx;
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;
* indx = cur_token;
return MAILIMF_NO_ERROR;
}
LIBETPAN_EXPORT
int mailimf_fws_word_parse(const char * message, size_t length,
size_t * indx, char ** result, int * p_missing_closing_quote)
{
size_t cur_token;
char * word;
int r;
int missing_closing_quote;
cur_token = * indx;
missing_closing_quote = 0;
r = mailimf_fws_atom_for_word_parse(message, length, &cur_token, &word, &missing_closing_quote);
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;
* indx = cur_token;
* p_missing_closing_quote = missing_closing_quote;
return MAILIMF_NO_ERROR;
}
/*
phrase = 1*word / obs-phrase
*/
static int mailimf_phrase_parse(const char * message, size_t length,
size_t * indx, char ** result)
{
MMAPString * gphrase;
char * word;
int first;
size_t cur_token;
int r;
int res;
char * str;
int has_missing_closing_quote;
cur_token = * indx;
has_missing_closing_quote = 0;
gphrase = mmap_string_new("");
if (gphrase == NULL) {
res = MAILIMF_ERROR_MEMORY;
goto err;
}
first = TRUE;
while (1) {
int missing_quote = 0;
r = mailimf_fws_word_parse(message, length, &cur_token, &word, &missing_quote);
if (missing_quote) {
has_missing_closing_quote = 1;
}
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;
}
if (has_missing_closing_quote) {
r = mailimf_char_parse(message, length, &cur_token, '\"');
}
str = strdup(gphrase->str);
if (str == NULL) {
res = MAILIMF_ERROR_MEMORY;
goto free;
}
mmap_string_free(gphrase);
* result = str;
* indx = 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 * indx, char ** result)
{
size_t cur_token;
int state;
size_t begin;
size_t terminal;
char * str;
cur_token = * indx;
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';
* indx = terminal;
* result = str;
return MAILIMF_NO_ERROR;
}
static int mailimf_ignore_unstructured_parse(const char * message, size_t length,
size_t * indx)
{
size_t cur_token;
int state;
size_t terminal;
cur_token = * indx;
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 ++;
}
* indx = terminal;
return MAILIMF_NO_ERROR;
}
LIBETPAN_EXPORT
int mailimf_ignore_field_parse(const char * message, size_t length,
size_t * indx)
{
int has_field;
size_t cur_token;
int state;
size_t terminal;
has_field = FALSE;
cur_token = * indx;
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;
* indx = terminal;
return MAILIMF_NO_ERROR;
}
/*
date-time = [ day-of-week "," ] date FWS time [CFWS]
*/
LIBETPAN_EXPORT
int mailimf_date_time_parse(const char * message, size_t length,
size_t * indx,
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 = * indx;
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;
day = 0;
month = 0;
year = 0;
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;
hour = 0;
min = 0;
sec = 0;
zone = 0;
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;
* indx = 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 * indx, int * result)
{
size_t cur_token;
int day_of_week;
int r;
cur_token = * indx;
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;
* indx = 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 indx)
{
int state;
state = DAY_NAME_START;
while (1) {
if (indx >= length)
return -1;
switch(state) {
case DAY_NAME_START:
switch((char) toupper((unsigned char) message[indx])) {
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[indx])) {
case 'U':
return 2;
case 'H':
return 4;
default:
return -1;
}
break;
case DAY_NAME_S:
switch((char) toupper((unsigned char) message[indx])) {
case 'A':
return 6;
case 'U':
return 7;
default:
return -1;
}
break;
}
indx ++;
}
}
static int mailimf_day_name_parse(const char * message, size_t length,
size_t * indx, int * result)
{
size_t cur_token;
int day_of_week;
int guessed_day;
int r;
cur_token = * indx;
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;
* indx = cur_token;
return MAILIMF_NO_ERROR;
}
/*
date = day month year
*/
static int mailimf_date_parse(const char * message, size_t length,
size_t * indx,
int * pday, int * pmonth, int * pyear)
{
size_t cur_token;
int day;
int month;
int year;
int r;
cur_token = * indx;
day = 1;
r = mailimf_day_parse(message, length, &cur_token, &day);
if (r != MAILIMF_NO_ERROR)
return r;
month = 1;
r = mailimf_month_parse(message, length, &cur_token, &month);
if (r != MAILIMF_NO_ERROR)
return r;
year = 2001;
r = mailimf_year_parse(message, length, &cur_token, &year);
if (r != MAILIMF_NO_ERROR)
return r;
* pday = day;
* pmonth = month;
* pyear = year;
* indx = cur_token;
return MAILIMF_NO_ERROR;
}
/*
year = 4*DIGIT / obs-year
*/
static int mailimf_year_parse(const char * message, size_t length,
size_t * indx, int * result)
{
uint32_t number;
size_t cur_token;
int r;
cur_token = * indx;
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;
* indx = 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 * indx, int * result)
{
size_t cur_token;
int month;
int r;
cur_token = * indx;
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;
* indx = 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 indx)
{
int state;
state = MONTH_START;
while (1) {
if (indx >= length)
return -1;
switch(state) {
case MONTH_START:
switch((char) toupper((unsigned char) message[indx])) {
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[indx])) {
case 'A':
return 1;
case 'U':
state = MONTH_JU;
break;
default:
return -1;
}
break;
case MONTH_JU:
switch((char) toupper((unsigned char) message[indx])) {
case 'N':
return 6;
case 'L':
return 7;
default:
return -1;
}
break;
case MONTH_M:
switch((char) toupper((unsigned char) message[indx])) {
case 'A':
state = MONTH_MA;
break;
default:
return -1;
}
break;
case MONTH_MA:
switch((char) toupper((unsigned char) message[indx])) {
case 'Y':
return 5;
case 'R':
return 3;
default:
return -1;
}
break;
case MONTH_A:
switch((char) toupper((unsigned char) message[indx])) {
case 'P':
return 4;
case 'U':
return 8;
default:
return -1;
}
break;
}
indx ++;
}
}
static int mailimf_month_name_parse(const char * message, size_t length,
size_t * indx, int * result)
{
size_t cur_token;
int month;
int guessed_month;
int r;
cur_token = * indx;
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;
* indx = 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 * indx, int * result)
{
size_t cur_token;
uint32_t day;
int r;
cur_token = * indx;
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;
* indx = 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 * indx,
int * phour, int * pmin,
int * psec,
int * pzone)
{
size_t cur_token;
int hour;
int min;
int sec;
int zone;
int r;
cur_token = * indx;
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;
* indx = 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 * indx,
int * phour, int * pmin,
int * psec)
{
int hour;
int min;
int sec;
size_t cur_token;
int r;
cur_token = * indx;
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;
* indx = cur_token;
return MAILIMF_NO_ERROR;
}
/*
hour = 2DIGIT / obs-hour
*/
static int mailimf_hour_parse(const char * message, size_t length,
size_t * indx, int * result)
{
uint32_t hour;
int r;
r = mailimf_number_parse(message, length, indx, &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 * indx, int * result)
{
uint32_t minute;
int r;
r = mailimf_number_parse(message, length, indx, &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 * indx, int * result)
{
uint32_t second;
int r;
r = mailimf_number_parse(message, length, indx, &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 * indx, int * result)
{
int zone;
int sign;
size_t cur_token;
int r;
uint32_t value;
cur_token = * indx;
if (cur_token + 1 < length) {
if ((message[cur_token] == 'U') && (message[cur_token + 1] == 'T')) {
* result = TRUE;
* indx = cur_token + 2;
return MAILIMF_NO_ERROR;
}
}
zone = 0;
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;
* indx = 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, &value);
if (r != MAILIMF_NO_ERROR)
return r;
zone = value * sign;
* indx = cur_token;
* result = zone;
return MAILIMF_NO_ERROR;
}
/*
address = mailbox / group
*/
LIBETPAN_EXPORT
int mailimf_address_parse(const char * message, size_t length,
size_t * indx,
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 = * indx;
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;
* indx = 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
*/
LIBETPAN_EXPORT
int mailimf_mailbox_parse(const char * message, size_t length,
size_t * indx,
struct mailimf_mailbox ** result)
{
size_t cur_token;
char * display_name;
struct mailimf_mailbox * mailbox;
char * addr_spec;
int r;
int res;
cur_token = * indx;
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;
* indx = 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 * indx,
char ** pdisplay_name,
char ** pangle_addr)
{
char * display_name;
char * angle_addr;
size_t cur_token;
int r;
int res;
cur_token = * indx;
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;
* indx = 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 * indx, char ** result)
{
size_t cur_token;
char * addr_spec;
int r;
cur_token = * indx;
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;
* indx = 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 * indx,
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;
clist * list;
cur_token = * indx;
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)) {
res = r;