/*
|
|
* 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
|
|
static 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;
|
|
goto free_display_name;
|
|
}
|