From 9e549686b23b6dffdcbd09c9b10dc2cb795fbcdf Mon Sep 17 00:00:00 2001 From: zautrix Date: Fri, 18 Mar 2005 20:17:03 +0000 Subject: Initial revision --- (limited to 'libetpan/src/low-level/imap/mailimap_parser.c') diff --git a/libetpan/src/low-level/imap/mailimap_parser.c b/libetpan/src/low-level/imap/mailimap_parser.c new file mode 100644 index 0000000..ab4db67 --- a/dev/null +++ b/libetpan/src/low-level/imap/mailimap_parser.c @@ -0,0 +1,9506 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#include +#include +#include + +#include "mailstream.h" +#include "mailimap_keywords.h" +#include "mailimap_parser.h" +#include "mmapstring.h" +#include "mail.h" + +#ifndef UNSTRICT_SYNTAX +#define UNSTRICT_SYNTAX +#endif + +/* + Document: internet-drafts/draft-crispin-imapv-15.txt + RFC 2060 (IMAP but rather used draft) + RFC 2234 for all token that are not defined such as ALPHA +*/ + + + +/* ************************************************************************* */ +/* ************************************************************************* */ +/* ************************************************************************* */ +/* ************************************************************************* */ +/* ************************************************************************* */ +/* ************************************************************************* */ + + + + +static int mailimap_address_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_address ** result, + size_t progr_rate, + progress_function * progr_fun); + +static int mailimap_addr_adl_parse(mailstream * fd, MMAPString * buffer, + size_t * index, char ** result, + size_t progr_rate, + progress_function * progr_fun); + +static int mailimap_addr_host_parse(mailstream * fd, MMAPString * buffer, + size_t * index, char ** result, + size_t progr_rate, + progress_function * progr_fun); + +static int mailimap_addr_mailbox_parse(mailstream * fd, MMAPString * buffer, + size_t * index, char ** result, + size_t progr_rate, + progress_function * progr_fun); + +static int mailimap_addr_name_parse(mailstream * fd, MMAPString * buffer, + size_t * index, char ** result, + size_t progr_rate, + progress_function * progr_fun); + + +static int +mailimap_astring_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + char ** result, + size_t progr_rate, + progress_function * progr_fun); + +static int mailimap_atom_parse(mailstream * fd, MMAPString * buffer, + size_t * index, char ** result, + size_t progr_rate, + progress_function * progr_fun); + +static int mailimap_auth_type_parse(mailstream * fd, MMAPString * buffer, + size_t * index, char ** result, + size_t progr_rate, + progress_function * progr_fun); + +static int mailimap_base64_parse(mailstream * fd, MMAPString * buffer, + size_t * index, char ** result, + size_t progr_rate, + progress_function * progr_fun); + +static int mailimap_body_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_body ** result, + size_t progr_rate, + progress_function * progr_fun); + + +static int +mailimap_body_extension_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_body_extension ** result, + size_t progr_rate, + progress_function * progr_fun); + + +static int +mailimap_body_ext_1part_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_body_ext_1part ** result, + size_t progr_rate, + progress_function * progr_fun); + + + +static int +mailimap_body_ext_mpart_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_body_ext_mpart ** result, + size_t progr_rate, + progress_function * progr_fun); + + +static int +mailimap_body_fields_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_body_fields ** result, + size_t progr_rate, + progress_function * progr_fun); + +static int mailimap_body_fld_desc_parse(mailstream * fd, MMAPString * buffer, + size_t * index, char ** result, + size_t progr_rate, + progress_function * progr_fun); + + +static int +mailimap_body_fld_dsp_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_body_fld_dsp ** result, + size_t progr_rate, + progress_function * progr_fun); + + + +static int +mailimap_body_fld_enc_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_body_fld_enc ** result, + size_t progr_rate, + progress_function * progr_fun); + + + +static int mailimap_body_fld_id_parse(mailstream * fd, MMAPString * buffer, + size_t * index, char ** result, + size_t progr_rate, + progress_function * progr_fun); + + +static int +mailimap_body_fld_lang_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_body_fld_lang ** result, + size_t progr_rate, + progress_function * progr_fun); + +static int mailimap_body_fld_lines_parse(mailstream * fd, + MMAPString * buffer, size_t * index, + uint32_t * result); + +static int mailimap_body_fld_md5_parse(mailstream * fd, MMAPString * buffer, + size_t * index, char ** result, + size_t progr_rate, + progress_function * progr_fun); + +static int mailimap_body_fld_octets_parse(mailstream * fd, + MMAPString * buffer, size_t * index, + uint32_t * result); + +static int +mailimap_body_fld_param_parse(mailstream * fd, + MMAPString * buffer, size_t * index, + struct mailimap_body_fld_param ** result, + size_t progr_rate, + progress_function * progr_fun); + + + +static int +mailimap_body_type_1part_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_body_type_1part ** result, + size_t progr_rate, + progress_function * progr_fun); + + + +static int +mailimap_body_type_basic_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_body_type_basic ** result, + size_t progr_rate, + progress_function * progr_fun); + + + +static int +mailimap_body_type_mpart_parse(mailstream * fd, + MMAPString * buffer, + size_t * index, + struct mailimap_body_type_mpart ** result, + size_t progr_rate, + progress_function * progr_fun); + + + +static int +mailimap_body_type_msg_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_body_type_msg ** result, + size_t progr_rate, + progress_function * progr_fun); + + + +static int +mailimap_body_type_text_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_body_type_text ** + result, + size_t progr_rate, + progress_function * progr_fun); + + + +static int +mailimap_capability_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_capability ** result, + size_t progr_rate, + progress_function * progr_fun); + + + +static int +mailimap_capability_data_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_capability_data ** result, + size_t progr_rate, + progress_function * progr_fun); + + +/* +static gboolean mailimap_date_day_parse(mailstream * fd, + MMAPString * buffer, + guint32 * index, + gint * result); +*/ +static int mailimap_date_day_fixed_parse(mailstream * fd, + MMAPString * buffer, + size_t * index, + int * result); + +static int mailimap_date_month_parse(mailstream * fd, MMAPString * buffer, + size_t * index, int * result); + +/* +struct mailimap_date_text { + gint day; + gint month; + gint year; +}; + +static gboolean +mailimap_date_text_parse(mailstream * fd, MMAPString * buffer, + guint32 * index, struct mailimap_date_text ** result); +static void mailimap_date_text_free(struct mailimap_date_text * date_text); +*/ + +static int mailimap_date_year_parse(mailstream * fd, MMAPString * buffer, + size_t * index, int * result); + +static int mailimap_date_time_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_date_time ** t, + size_t progr_rate, + progress_function * progr_fun); + +#ifndef UNSTRICT_SYNTAX +static int mailimap_digit_nz_parse(mailstream * fd, MMAPString * buffer, + size_t * index, int * result); +#endif + + +static int mailimap_envelope_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_envelope ** result, + size_t progr_rate, + progress_function * progr_fun); + + +static int +mailimap_env_bcc_parse(mailstream * fd, MMAPString * buffer, + size_t * index, struct mailimap_env_bcc ** result, + size_t progr_rate, + progress_function * progr_fun); + + +static int +mailimap_env_cc_parse(mailstream * fd, MMAPString * buffer, + size_t * index, struct mailimap_env_cc ** result, + size_t progr_rate, + progress_function * progr_fun); + +static int mailimap_env_date_parse(mailstream * fd, MMAPString * buffer, + size_t * index, char ** result, + size_t progr_rate, + progress_function * progr_fun); + + +static int +mailimap_env_from_parse(mailstream * fd, MMAPString * buffer, + size_t * index, struct mailimap_env_from ** result, + size_t progr_rate, + progress_function * progr_fun); + + +static int mailimap_env_in_reply_to_parse(mailstream * fd, + MMAPString * buffer, + size_t * index, char ** result, + size_t progr_rate, + progress_function * progr_fun); + +static int mailimap_env_message_id_parse(mailstream * fd, + MMAPString * buffer, + size_t * index, char ** result, + size_t progr_rate, + progress_function * progr_fun); + +static int +mailimap_env_reply_to_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_env_reply_to ** result, + size_t progr_rate, + progress_function * progr_fun); + + + +static int +mailimap_env_sender_parse(mailstream * fd, MMAPString * buffer, + size_t * index, struct mailimap_env_sender ** result, + size_t progr_rate, + progress_function * progr_fun); + +static int mailimap_env_subject_parse(mailstream * fd, MMAPString * buffer, + size_t * index, char ** result, + size_t progr_rate, + progress_function * progr_fun); + + +static int +mailimap_env_to_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_env_to ** result, + size_t progr_rate, + progress_function * progr_fun); + + +static int mailimap_flag_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_flag ** result, + size_t progr_rate, + progress_function * progr_fun); + +static int mailimap_flag_extension_parse(mailstream * fd, + MMAPString * buffer, + size_t * index, + char ** result, + size_t progr_rate, + progress_function * progr_fun); + + + + +static int +mailimap_flag_fetch_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_flag_fetch ** result, + size_t progr_rate, + progress_function * progr_fun); + + + +static int +mailimap_flag_perm_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_flag_perm ** result, + size_t progr_rate, + progress_function * progr_fun); + + +static int mailimap_flag_keyword_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + char ** result, + size_t progr_rate, + progress_function * progr_fun); + + +static int mailimap_flag_list_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_flag_list ** result, + size_t progr_rate, + progress_function * progr_fun); + + +static int +mailimap_header_fld_name_parse(mailstream * fd, + MMAPString * buffer, + size_t * index, + char ** result, + size_t progr_rate, + progress_function * progr_fun); + + + + +static int +mailimap_header_list_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_header_list ** result, + size_t progr_rate, + progress_function * progr_fun); + +static int mailimap_literal_parse(mailstream * fd, MMAPString * buffer, + size_t * index, char ** result, + size_t * result_len, + size_t progr_rate, + progress_function * progr_fun); + + +static int +mailimap_mailbox_parse(mailstream * fd, MMAPString * buffer, + size_t * index, char ** result, + size_t progr_rate, + progress_function * progr_fun); + + + + +static int +mailimap_mailbox_data_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_mailbox_data ** result, + size_t progr_rate, + progress_function * progr_fun); + + +static int +mailimap_mbx_list_flags_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_mbx_list_flags ** result, + size_t progr_rate, + progress_function * progr_fun); + + +static int +mailimap_mbx_list_oflag_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_mbx_list_oflag ** result, + size_t progr_rate, + progress_function * progr_fun); + +static int +mailimap_mbx_list_oflag_no_sflag_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_mbx_list_oflag ** result, + size_t progr_rate, + progress_function * progr_fun); + +static int +mailimap_mbx_list_sflag_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + int * result); + + +static int +mailimap_mailbox_list_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_mailbox_list ** result, + size_t progr_rate, + progress_function * progr_fun); + + + +static int +mailimap_media_basic_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_media_basic ** result, + size_t progr_rate, + progress_function * progr_fun); + +static int +mailimap_media_message_parse(mailstream * fd, MMAPString * buffer, + size_t * index); + +static int +mailimap_media_subtype_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + char ** result, + size_t progr_rate, + progress_function * progr_fun); + +static int mailimap_media_text_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + char ** result, + size_t progr_rate, + progress_function * progr_fun); + + + +static int +mailimap_message_data_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_message_data ** result, + size_t progr_rate, + progress_function * progr_fun); + + + + + +static int +mailimap_msg_att_parse(mailstream * fd, MMAPString * buffer, + size_t * index, struct mailimap_msg_att ** result, + size_t progr_rate, + progress_function * progr_fun); + + + +static int +mailimap_msg_att_dynamic_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_msg_att_dynamic ** result, + size_t progr_rate, + progress_function * progr_fun); + + +static int +mailimap_msg_att_static_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_msg_att_static ** result, + size_t progr_rate, + progress_function * progr_fun); + +static int mailimap_nil_parse(mailstream * fd, MMAPString * buffer, + size_t * index); + +static int mailimap_nstring_parse(mailstream * fd, MMAPString * buffer, + size_t * index, char ** result, + size_t * result_len, + size_t progr_rate, + progress_function * progr_fun); + +static int +mailimap_number_parse(mailstream * fd, MMAPString * buffer, + size_t * index, uint32_t * result); + +static int +mailimap_nz_number_parse(mailstream * fd, MMAPString * buffer, + size_t * index, uint32_t * result); + + +static int +mailimap_quoted_parse(mailstream * fd, MMAPString * buffer, + size_t * index, char ** result, + size_t progr_rate, + progress_function * progr_fun); + +static int +mailimap_quoted_char_parse(mailstream * fd, MMAPString * buffer, + size_t * index, char * result); + + +static int +mailimap_quoted_specials_parse(mailstream * fd, MMAPString * buffer, + size_t * index, char * result); + + + + + +static int +mailimap_response_data_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_response_data ** result, + size_t progr_rate, + progress_function * progr_fun); + + + + +static int +mailimap_response_done_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_response_done ** result, + size_t progr_rate, + progress_function * progr_fun); + +static int +mailimap_response_fatal_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_response_fatal ** result, + size_t progr_rate, + progress_function * progr_fun); + + +static int +mailimap_response_tagged_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_response_tagged ** result, + size_t progr_rate, + progress_function * progr_fun); + + +static int +mailimap_resp_cond_auth_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_resp_cond_auth ** result, + size_t progr_rate, + progress_function * progr_fun); + +static int +mailimap_resp_cond_bye_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_resp_cond_bye ** result, + size_t progr_rate, + progress_function * progr_fun); + + +static int +mailimap_resp_cond_state_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_resp_cond_state ** result, + size_t progr_rate, + progress_function * progr_fun); + + +static int +mailimap_resp_text_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_resp_text ** result, + size_t progr_rate, + progress_function * progr_fun); + + +static int +mailimap_resp_text_code_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_resp_text_code ** result, + size_t progr_rate, + progress_function * progr_fun); + + +static int +mailimap_section_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_section ** result, + size_t progr_rate, + progress_function * progr_fun); + + +static int +mailimap_section_msgtext_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_section_msgtext ** result, + size_t progr_rate, + progress_function * progr_fun); + + +static int +mailimap_section_part_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_section_part ** result, + size_t progr_rate, + progress_function * progr_fun); + + + + +static int +mailimap_section_spec_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_section_spec ** result, + size_t progr_rate, + progress_function * progr_fun); + + +static int +mailimap_section_text_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_section_text ** result, + size_t progr_rate, + progress_function * progr_fun); + + +static int mailimap_status_att_parse(mailstream * fd, MMAPString * buffer, + size_t * index, int * result); + +static int +mailimap_string_parse(mailstream * fd, MMAPString * buffer, + size_t * index, char ** result, + size_t * result_len, + size_t progr_rate, + progress_function * progr_fun); + +static int mailimap_tag_parse(mailstream * fd, MMAPString * buffer, + size_t * index, char ** result, + size_t progr_rate, + progress_function * progr_fun); + +static int mailimap_text_parse(mailstream * fd, MMAPString * buffer, + size_t * index, char ** result, + size_t progr_rate, + progress_function * progr_fun); + +static int mailimap_time_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + int * phour, int * pmin, int * psec); + +static int mailimap_uniqueid_parse(mailstream * fd, MMAPString * buffer, + size_t * index, uint32_t * result); + +static int mailimap_zone_parse(mailstream * fd, MMAPString * buffer, + size_t * index, int * result); + + + +/* ************************************************************************* */ +/* ************************************************************************* */ +/* ************************************************************************* */ +/* ************************************************************************* */ +/* ************************************************************************* */ +/* ************************************************************************* */ + + + + + +/* ******************** TOOLS **************************** */ + + +static int mailimap_unstrict_char_parse(mailstream * fd, MMAPString * buffer, + size_t * index, char token) +{ + size_t cur_token; + int r; + + cur_token = * index; + +#ifdef UNSTRICT_SYNTAX + /* can accept unstrict syntax */ + + mailimap_space_parse(fd, buffer, &cur_token); + if (token == ' ') { + * index = cur_token; + return MAILIMAP_NO_ERROR; + } +#endif + + r = mailimap_char_parse(fd, buffer, &cur_token, token); + if (r != MAILIMAP_NO_ERROR) + return r; + + * index = cur_token; + + return MAILIMAP_NO_ERROR; +} + +static int mailimap_oparenth_parse(mailstream * fd, MMAPString * buffer, + size_t * index) +{ + return mailimap_unstrict_char_parse(fd, buffer, index, '('); +} + +static int mailimap_cparenth_parse(mailstream * fd, MMAPString * buffer, + size_t * index) +{ + return mailimap_unstrict_char_parse(fd, buffer, index, ')'); +} + +static int mailimap_oaccolade_parse(mailstream * fd, MMAPString * buffer, + size_t * index) +{ + return mailimap_unstrict_char_parse(fd, buffer, index, '{'); +} + +static int mailimap_caccolade_parse(mailstream * fd, MMAPString * buffer, + size_t * index) +{ + return mailimap_unstrict_char_parse(fd, buffer, index, '}'); +} + +static int mailimap_plus_parse(mailstream * fd, MMAPString * buffer, + size_t * index) +{ + return mailimap_unstrict_char_parse(fd, buffer, index, '+'); +} + +static int mailimap_minus_parse(mailstream * fd, MMAPString * buffer, + size_t * index) +{ + return mailimap_unstrict_char_parse(fd, buffer, index, '-'); +} + +static int mailimap_star_parse(mailstream * fd, MMAPString * buffer, + size_t * index) +{ + return mailimap_unstrict_char_parse(fd, buffer, index, '*'); +} + +static int mailimap_dot_parse(mailstream * fd, MMAPString * buffer, + size_t * index) +{ + return mailimap_unstrict_char_parse(fd, buffer, index, '.'); +} + +static int mailimap_colon_parse(mailstream * fd, MMAPString * buffer, + size_t * index) +{ + return mailimap_unstrict_char_parse(fd, buffer, index, ':'); +} + +static int mailimap_lower_parse(mailstream * fd, MMAPString * buffer, + size_t * index) +{ + return mailimap_unstrict_char_parse(fd, buffer, index, '<'); +} + +static int mailimap_greater_parse(mailstream * fd, MMAPString * buffer, + size_t * index) +{ + return mailimap_unstrict_char_parse(fd, buffer, index, '>'); +} + +static int mailimap_obracket_parse(mailstream * fd, MMAPString * buffer, + size_t * index) +{ + return mailimap_unstrict_char_parse(fd, buffer, index, '['); +} + +static int mailimap_cbracket_parse(mailstream * fd, MMAPString * buffer, + size_t * index) +{ + return mailimap_unstrict_char_parse(fd, buffer, index, ']'); +} + +static int mailimap_dquote_parse(mailstream * fd, MMAPString * buffer, + size_t * index) +{ + return mailimap_char_parse(fd, buffer, index, '\"'); +} + +static int mailimap_crlf_parse(mailstream * fd, MMAPString * buffer, + size_t * index) +{ + size_t cur_token = * index; + +#ifdef UNSTRICT_SYNTAX + mailimap_space_parse(fd, buffer, &cur_token); +#endif + + if (mailimap_token_case_insensitive_parse(fd, buffer, &cur_token, "\r\n")) { + * index = cur_token; + return MAILIMAP_NO_ERROR; + } + +#ifdef UNSTRICT_SYNTAX + else if (mailimap_unstrict_char_parse(fd, buffer, &cur_token, '\n')) { + * index = cur_token; + return MAILIMAP_NO_ERROR; + } +#endif + + else + return MAILIMAP_ERROR_PARSE; +} + +typedef int mailimap_struct_parser(mailstream * fd, MMAPString * buffer, + size_t * index, void * result, + size_t progr_rate, + progress_function * progr_fun); +typedef int mailimap_struct_destructor(void * result); + + +static int +mailimap_struct_multiple_parse(mailstream * fd, MMAPString * buffer, + size_t * index, clist ** result, + mailimap_struct_parser * parser, + mailimap_struct_destructor * destructor, + size_t progr_rate, + progress_function * progr_fun) +{ + clist * struct_list; + size_t cur_token; + void * value; + int r; + int res; + + cur_token = * index; + + r = parser(fd, buffer, &cur_token, &value, progr_rate, progr_fun); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + + struct_list = clist_new(); + if (struct_list == NULL) { + destructor(value); + res = MAILIMAP_ERROR_MEMORY; + goto err; + } + + r = clist_append(struct_list, value); + if (r < 0) { + destructor(value); + res = MAILIMAP_ERROR_MEMORY; + goto free_list; + } + + while (1) { + r = parser(fd, buffer, &cur_token, &value, progr_rate, progr_fun); + if (r == MAILIMAP_ERROR_PARSE) + break; + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto free_list; + } + + r = clist_append(struct_list, value); + if (r < 0) { + destructor(value); + res = MAILIMAP_ERROR_MEMORY; + goto free_list; + } + } + + * result = struct_list; + * index = cur_token; + + return MAILIMAP_NO_ERROR; + + free_list: + clist_foreach(struct_list, (clist_func) destructor, NULL); + clist_free(struct_list); + err: + return res; +} + +static int +mailimap_struct_list_parse(mailstream * fd, MMAPString * buffer, + size_t * index, clist ** result, + char symbol, + mailimap_struct_parser * parser, + mailimap_struct_destructor * destructor, + size_t progr_rate, + progress_function * progr_fun) +{ + clist * struct_list; + size_t cur_token; + void * value; + size_t final_token; + int r; + int res; + + cur_token = * index; + struct_list = NULL; + + r = parser(fd, buffer, &cur_token, &value, progr_rate, progr_fun); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + + struct_list = clist_new(); + if (struct_list == NULL) { + destructor(value); + res = MAILIMAP_ERROR_MEMORY; + goto err; + } + + r = clist_append(struct_list, value); + if (r < 0) { + destructor(value); + res = MAILIMAP_ERROR_MEMORY; + goto free_list; + } + + final_token = cur_token; + + while (1) { + r = mailimap_unstrict_char_parse(fd, buffer, &cur_token, symbol); + if (r == MAILIMAP_ERROR_PARSE) + break; + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto free_list; + } + + r = parser(fd, buffer, &cur_token, &value, progr_rate, progr_fun); + if (r == MAILIMAP_ERROR_PARSE) + break; + + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto free_list; + } + + r = clist_append(struct_list, value); + if (r < 0) { + destructor(value); + res = MAILIMAP_ERROR_MEMORY; + goto free_list; + } + + final_token = cur_token; + } + + * result = struct_list; + * index = final_token; + + return MAILIMAP_NO_ERROR; + + free_list: + clist_foreach(struct_list, (clist_func) destructor, NULL); + clist_free(struct_list); + err: + return res; +} + +static int +mailimap_struct_spaced_list_parse(mailstream * fd, MMAPString * buffer, + size_t * index, clist ** result, + mailimap_struct_parser * parser, + mailimap_struct_destructor * destructor, + size_t progr_rate, + progress_function * progr_fun) +{ + return mailimap_struct_list_parse(fd, buffer, index, result, + ' ', parser, destructor, + progr_rate, progr_fun); +} + + + +static int +mailimap_custom_string_parse(mailstream * fd, MMAPString * buffer, + size_t * index, char ** result, + int (* is_custom_char)(char)) +{ + size_t begin; + size_t end; + char * gstr; + + begin = * index; + +#ifdef UNSTRICT_SYNTAX + mailimap_space_parse(fd, buffer, &begin); +#endif + + end = begin; + + while (is_custom_char(buffer->str[end])) + end ++; + + if (end != begin) { + gstr = malloc(end - begin + 1); + if (gstr == NULL) + return MAILIMAP_ERROR_MEMORY; + + strncpy(gstr, buffer->str + begin, end - begin); + gstr[end - begin] = '\0'; + + * index = end; + * result = gstr; + return MAILIMAP_NO_ERROR; + } + else + return MAILIMAP_ERROR_PARSE; +} + + + +static int +mailimap_nz_number_alloc_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + uint32_t ** result, + size_t progr_rate, + progress_function * progr_fun) +{ + uint32_t number; + uint32_t * number_alloc; + size_t cur_token; + int r; + + cur_token = * index; + + r = mailimap_nz_number_parse(fd, buffer, &cur_token, &number); + if (r != MAILIMAP_NO_ERROR) + return r; + + number_alloc = mailimap_number_alloc_new(number); + if (number_alloc == NULL) + return MAILIMAP_ERROR_MEMORY; + + * index = cur_token; + * result = number_alloc; + + return MAILIMAP_NO_ERROR; +} + + +static int is_ctl(char ch) +{ + unsigned char uch = (unsigned char) ch; + + return (uch <= 0x1F); +} + +static int is_char(char ch) +{ +#ifdef UNSTRICT_SYNTAX + return (ch != 0); +#else + unsigned char uch = ch; + + return (uch >= 0x01) && (uch <= 0x7f); +#endif +} + +static int is_alpha(char ch) +{ + return ((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && (ch <= 'z'))); +} + +static int is_digit(char ch) +{ + return (ch >= '0') && (ch <= '9'); +} + +static int mailimap_digit_parse(mailstream * fd, MMAPString * buffer, + size_t * index, int * result) +{ + size_t cur_token; + + cur_token = * index; + + if (is_digit(buffer->str[cur_token])) { + * result = buffer->str[cur_token] - '0'; + cur_token ++; + * index = cur_token; + return MAILIMAP_NO_ERROR; + } + else + return MAILIMAP_ERROR_PARSE; +} + + +/* ******************** parser **************************** */ + +/* + address = "(" addr-name SP addr-adl SP addr-mailbox SP + addr-host ")" +*/ + +static int mailimap_address_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_address ** result, + size_t progr_rate, + progress_function * progr_fun) +{ + size_t cur_token; + char * addr_name; + char * addr_adl; + char * addr_mailbox; + char * addr_host; + struct mailimap_address * addr; + int r; + int res; + + cur_token = * index; + + addr_name = NULL; + addr_adl = NULL; + addr_mailbox = NULL; + addr_host = NULL; + + r = mailimap_oparenth_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + + r = mailimap_addr_name_parse(fd, buffer, &cur_token, &addr_name, + progr_rate, progr_fun); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + + r = mailimap_space_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto addr_name_free; + } + + r = mailimap_addr_adl_parse(fd, buffer, &cur_token, &addr_adl, + progr_rate, progr_fun); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto addr_name_free; + } + + r = mailimap_space_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto addr_adl_free; + } + + r = mailimap_addr_mailbox_parse(fd, buffer, &cur_token, &addr_mailbox, + progr_rate, progr_fun); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto addr_adl_free; + } + + r = mailimap_space_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto addr_mailbox_free; + } + + r = mailimap_addr_host_parse(fd, buffer, &cur_token, &addr_host, + progr_rate, progr_fun); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto addr_mailbox_free; + } + + r = mailimap_cparenth_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto addr_host_free; + } + + addr = mailimap_address_new(addr_name, addr_adl, addr_mailbox, addr_host); + + if (addr == NULL) { + res = MAILIMAP_ERROR_MEMORY; + goto addr_host_free; + } + + * result = addr; + * index = cur_token; + + return MAILIMAP_NO_ERROR; + + addr_host_free: + mailimap_addr_host_free(addr_host); + addr_mailbox_free: + mailimap_addr_mailbox_free(addr_mailbox); + addr_adl_free: + mailimap_addr_adl_free(addr_adl); + addr_name_free: + mailimap_addr_name_free(addr_name); + err: + return res; +} + +/* + addr-adl = nstring + ; Holds route from [RFC-822] route-addr if + ; non-NIL +*/ + +static int mailimap_addr_adl_parse(mailstream * fd, MMAPString * buffer, + size_t * index, char ** result, + size_t progr_rate, + progress_function * progr_fun) +{ + return mailimap_nstring_parse(fd, buffer, index, result, NULL, + progr_rate, progr_fun); +} + +/* + addr-host = nstring + ; NIL indicates [RFC-822] group syntax. + ; Otherwise, holds [RFC-822] domain name +*/ + +static int mailimap_addr_host_parse(mailstream * fd, MMAPString * buffer, + size_t * index, char ** result, + size_t progr_rate, + progress_function * progr_fun) +{ + return mailimap_nstring_parse(fd, buffer, index, result, NULL, + progr_rate, progr_fun); +} + +/* + addr-mailbox = nstring + ; NIL indicates end of [RFC-822] group; if + ; non-NIL and addr-host is NIL, holds + ; [RFC-822] group name. + ; Otherwise, holds [RFC-822] local-part + ; after removing [RFC-822] quoting + */ + +static int mailimap_addr_mailbox_parse(mailstream * fd, MMAPString * buffer, + size_t * index, char ** result, + size_t progr_rate, + progress_function * progr_fun) +{ + return mailimap_nstring_parse(fd, buffer, index, result, NULL, + progr_rate, progr_fun); +} + + +/* + addr-name = nstring + ; If non-NIL, holds phrase from [RFC-822] + ; mailbox after removing [RFC-822] quoting +*/ + +static int mailimap_addr_name_parse(mailstream * fd, MMAPString * buffer, + size_t * index, char ** result, + size_t progr_rate, + progress_function * progr_fun) +{ + return mailimap_nstring_parse(fd, buffer, index, result, NULL, + progr_rate, progr_fun); +} + + +/* + NOT IMPLEMENTED + append = "APPEND" SP mailbox [SP flag-list] [SP date-time] SP + literal +*/ + +/* + astring = 1*ASTRING-CHAR / string +*/ + +static int is_astring_char(char ch); + +static int +mailimap_atom_astring_parse(mailstream * fd, MMAPString * buffer, + size_t * index, char ** result, + size_t progr_rate, + progress_function * progr_fun) +{ + return mailimap_custom_string_parse(fd, buffer, index, result, + is_astring_char); +} + +static int +mailimap_astring_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + char ** result, + size_t progr_rate, + progress_function * progr_fun) +{ + size_t cur_token; + char * astring; + int r; + + cur_token = * index; + + r = mailimap_atom_astring_parse(fd, buffer, &cur_token, &astring, + progr_rate, progr_fun); + switch (r) { + case MAILIMAP_NO_ERROR: + break; + + case MAILIMAP_ERROR_PARSE: + r = mailimap_string_parse(fd, buffer, &cur_token, &astring, NULL, + progr_rate, progr_fun); + if (r != MAILIMAP_NO_ERROR) + return r; + break; + + default: + return r; + } + + * result = astring; + * index = cur_token; + + return MAILIMAP_NO_ERROR; +} + +/* + ASTRING-CHAR = ATOM-CHAR / resp-specials +*/ + +static int is_atom_char(char ch); +static int is_resp_specials(char ch); + +static int is_astring_char(char ch) +{ + if (is_atom_char(ch)) + return TRUE; + if (is_resp_specials(ch)) + return TRUE; + return FALSE; +} + +/* + atom = 1*ATOM-CHAR +*/ + +static int mailimap_atom_parse(mailstream * fd, MMAPString * buffer, + size_t * index, char ** result, + size_t progr_rate, + progress_function * progr_fun) +{ + return mailimap_custom_string_parse(fd, buffer, index, result, + is_atom_char); +} + +/* + ATOM-CHAR = +*/ + +static int is_atom_specials(char ch); + +static int is_atom_char(char ch) +{ + if (is_atom_specials(ch)) + return FALSE; + + return is_char(ch); +} + +/* + atom-specials = "(" / ")" / "{" / SP / CTL / list-wildcards / + quoted-specials / resp-specials + +no "}" because there is no need (Mark Crispin) +*/ + +static int is_quoted_specials(char ch); +static int is_list_wildcards(char ch); + +static int is_atom_specials(char ch) +{ + switch (ch) { + case '(': + case ')': + case '{': + case ' ': + return TRUE; + }; + if (is_ctl(ch)) + return TRUE; + if (is_list_wildcards(ch)) + return TRUE; + if (is_resp_specials(ch)) + return TRUE; + + return is_quoted_specials(ch); +} + +/* + NOT IMPLEMENTED + authenticate = "AUTHENTICATE" SP auth-type *(CRLF base64) +*/ + +/* + auth-type = atom + ; Defined by [SASL] +*/ + +static int mailimap_auth_type_parse(mailstream * fd, MMAPString * buffer, + size_t * index, char ** result, + size_t progr_rate, + progress_function * progr_fun) +{ + return mailimap_atom_parse(fd, buffer, index, result, + progr_rate, progr_fun); +} + +/* + base64 = *(4base64-char) [base64-terminal] +*/ + +static int is_base64_4char(char * str); +static int is_base64_terminal(char * str); + +static int mailimap_base64_parse(mailstream * fd, MMAPString * buffer, + size_t * index, char ** result, + size_t progr_rate, + progress_function * progr_fun) +{ + size_t begin; + size_t end; + char * gstr; + + begin = * index; + end = begin; + + while (is_base64_4char(buffer->str + end)) + end += 4; + if (is_base64_terminal(buffer->str + end)) + end += 4; + else + return MAILIMAP_ERROR_PARSE; + + gstr = malloc(end - begin + 1); + if (gstr == NULL) + return MAILIMAP_ERROR_MEMORY; + strncpy(gstr, buffer->str + begin, end - begin); + gstr[end - begin] = '\0'; + + * result = gstr; + * index = end; + + return MAILIMAP_NO_ERROR; +} + +/* + base64-char = ALPHA / DIGIT / "+" / "/" + ; Case-sensitive +*/ + +static int is_base64_char(char ch) +{ + return (is_alpha(ch) || is_digit(ch) || ch == '+' || ch == '/'); +} + +static int is_base64_4char(char * str) +{ + size_t i; + + for (i = 0 ; i < 4 ; i++) + if (!is_base64_char(str[i])) + return FALSE; + return TRUE; +} + +/* + base64-terminal = (2base64-char "==") / (3base64-char "=") +*/ + +static int is_base64_terminal(char * str) +{ + if (str[0] == 0) + return FALSE; + if (str[1] == 0) + return FALSE; + if (str[2] == 0) + return FALSE; + if (str[3] == 0) + return FALSE; + + if (is_base64_char(str[0]) || is_base64_char(str[1]) + || str[2] == '=' || str[3] == '=') + return TRUE; + if (is_base64_char(str[0]) || is_base64_char(str[1]) + || is_base64_char(str[2]) || str[3] == '=') + return TRUE; + return FALSE; +} + + +/* + body = "(" (body-type-1part / body-type-mpart) ")" +*/ + +static int mailimap_body_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_body ** result, + size_t progr_rate, + progress_function * progr_fun) +{ + struct mailimap_body_type_1part * body_type_1part; + struct mailimap_body_type_mpart * body_type_mpart; + struct mailimap_body * body; + size_t cur_token; + int type; + int r; + int res; + + cur_token = * index; + + body_type_1part = NULL; + body_type_mpart = NULL; + + r = mailimap_oparenth_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + + type = MAILIMAP_BODY_ERROR; /* XXX - removes a gcc warning */ + + r = mailimap_body_type_1part_parse(fd, buffer, &cur_token, &body_type_1part, + progr_rate, progr_fun); + if (r == MAILIMAP_NO_ERROR) + type = MAILIMAP_BODY_1PART; + + if (r == MAILIMAP_ERROR_PARSE) { + r = mailimap_body_type_mpart_parse(fd, buffer, &cur_token, + &body_type_mpart, + progr_rate, progr_fun); + + if (r == MAILIMAP_NO_ERROR) + type = MAILIMAP_BODY_MPART; + } + + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + + r = mailimap_cparenth_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto free; + } + + body = mailimap_body_new(type, body_type_1part, body_type_mpart); + if (body == NULL) { + res = MAILIMAP_ERROR_MEMORY; + goto free; + } + + * result = body; + * index = cur_token; + + return MAILIMAP_NO_ERROR; + + free: + if (body_type_1part) + mailimap_body_type_1part_free(body_type_1part); + if (body_type_mpart) + mailimap_body_type_mpart_free(body_type_mpart); + err: + return res; +} + +/* + body-extension = nstring / number / + "(" body-extension *(SP body-extension) ")" + ; Future expansion. Client implementations + ; MUST accept body-extension fields. Server + ; implementations MUST NOT generate + ; body-extension fields except as defined by + ; future standard or standards-track + ; revisions of this specification. +*/ + +/* + "(" body-extension *(SP body-extension) ")" +*/ + +static int +mailimap_body_ext_list_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + clist ** result, + size_t progr_rate, + progress_function * progr_fun) +{ + size_t cur_token; + clist * list; + int r; + int res; + + cur_token = * index; + + r = mailimap_oparenth_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + + r = mailimap_struct_spaced_list_parse(fd, buffer, + &cur_token, &list, + (mailimap_struct_parser * ) + mailimap_body_extension_parse, + (mailimap_struct_destructor * ) + mailimap_body_extension_free, + progr_rate, progr_fun); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + + r = mailimap_cparenth_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto free_list; + } + + * index = cur_token; + * result = list; + + return MAILIMAP_NO_ERROR; + + free_list: + clist_foreach(list, (clist_func) mailimap_body_extension_free, NULL); + clist_free(list); + err: + return res; +} + +/* + body-extension = nstring / number / + "(" body-extension *(SP body-extension) ")" + ; Future expansion. Client implementations + ; MUST accept body-extension fields. Server + ; implementations MUST NOT generate + ; body-extension fields except as defined by + ; future standard or standards-track + ; revisions of this specification. +*/ + +static int +mailimap_body_extension_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_body_extension ** result, + size_t progr_rate, + progress_function * progr_fun) +{ + size_t cur_token; + uint32_t number; + char * nstring; + clist * body_extension_list; + struct mailimap_body_extension * body_extension; + int type; + int r; + int res; + + cur_token = * index; + + nstring = NULL; + number = 0; + body_extension_list = NULL; + type = MAILIMAP_BODY_EXTENSION_ERROR; /* XXX - removes a gcc warning */ + + r = mailimap_nstring_parse(fd, buffer, &cur_token, &nstring, NULL, + progr_rate, progr_fun); + if (r == MAILIMAP_NO_ERROR) + type = MAILIMAP_BODY_EXTENSION_NSTRING; + + if (r == MAILIMAP_ERROR_PARSE) { + r = mailimap_number_parse(fd, buffer, &cur_token, &number); + + if (r == MAILIMAP_NO_ERROR) + type = MAILIMAP_BODY_EXTENSION_NUMBER; + } + + if (r == MAILIMAP_ERROR_PARSE) { + r = mailimap_body_ext_list_parse(fd, buffer, &cur_token, + &body_extension_list, + progr_rate, progr_fun); + + if (r == MAILIMAP_NO_ERROR) + type = MAILIMAP_BODY_EXTENSION_LIST; + } + + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + + body_extension = mailimap_body_extension_new(type, nstring, number, + body_extension_list); + + if (body_extension == NULL) { + res = MAILIMAP_ERROR_MEMORY; + goto free; + } + + * result = body_extension; + * index = cur_token; + + return MAILIMAP_NO_ERROR; + + free: + if (nstring != NULL) + mailimap_nstring_free(nstring); + if (body_extension_list) { + clist_foreach(body_extension_list, + (clist_func) mailimap_body_extension_free, + NULL); + clist_free(body_extension_list); + } + err: + return res; +} + +/* + body-ext-1part = body-fld-md5 [SP body-fld-dsp [SP body-fld-lang + *(SP body-extension)]] + ; MUST NOT be returned on non-extensible + ; "BODY" fetch +*/ + +/* + *(SP body-extension) +*/ + +static int +mailimap_body_ext_1part_3_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + clist ** body_ext_list, + size_t progr_rate, + progress_function * progr_fun) +{ + size_t cur_token; + int r; + + cur_token = * index; + * body_ext_list = NULL; + + r = mailimap_space_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_struct_spaced_list_parse(fd, buffer, &cur_token, + body_ext_list, + (mailimap_struct_parser *) + mailimap_body_extension_parse, + (mailimap_struct_destructor *) + mailimap_body_extension_free, + progr_rate, progr_fun); + if (r != MAILIMAP_NO_ERROR) + return r; + + * index = cur_token; + + return MAILIMAP_NO_ERROR; +} + + +/* + [SP body-fld-lang + *(SP body-extension)]] +*/ + +static int +mailimap_body_ext_1part_2_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_body_fld_lang ** fld_lang, + clist ** body_ext_list, + size_t progr_rate, + progress_function * progr_fun) +{ + size_t cur_token; + int r; + + cur_token = * index; + * fld_lang = NULL; + * body_ext_list = NULL; + + r = mailimap_space_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_body_fld_lang_parse(fd, buffer, &cur_token, fld_lang, + progr_rate, progr_fun); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_body_ext_1part_3_parse(fd, buffer, &cur_token, + body_ext_list, progr_rate, progr_fun); + if ((r != MAILIMAP_NO_ERROR) && (r != MAILIMAP_ERROR_PARSE)) + return r; + + * index = cur_token; + + return MAILIMAP_NO_ERROR; +} + + +/* + SP body-fld-dsp [SP body-fld-lang + *(SP body-extension)]] +*/ + +static int +mailimap_body_ext_1part_1_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_body_fld_dsp ** fld_dsp, + struct mailimap_body_fld_lang ** fld_lang, + clist ** body_ext_list, + size_t progr_rate, + progress_function * progr_fun) +{ + size_t cur_token; + int r; + + cur_token = * index; + * fld_dsp = NULL; + * fld_lang = NULL; + * body_ext_list = NULL; + + r = mailimap_space_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_body_fld_dsp_parse(fd, buffer, &cur_token, fld_dsp, + progr_rate, progr_fun); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_body_ext_1part_2_parse(fd, buffer, &cur_token, + fld_lang, body_ext_list, + progr_rate, progr_fun); + if ((r != MAILIMAP_NO_ERROR) && (r != MAILIMAP_ERROR_PARSE)) + return r; + + * index = cur_token; + + return MAILIMAP_NO_ERROR; +} + +/* + body-ext-1part = body-fld-md5 [SP body-fld-dsp [SP body-fld-lang + *(SP body-extension)]] + ; MUST NOT be returned on non-extensible + ; "BODY" fetch +*/ + +static int +mailimap_body_ext_1part_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_body_ext_1part ** result, + size_t progr_rate, + progress_function * progr_fun) +{ + size_t cur_token; + + char * fld_md5; + struct mailimap_body_fld_dsp * fld_dsp; + struct mailimap_body_fld_lang * fld_lang; + clist * body_ext_list; + int r; + int res; + + struct mailimap_body_ext_1part * ext_1part; + + cur_token = * index; + + fld_md5 = NULL; + fld_dsp = NULL; + fld_lang = NULL; + body_ext_list = NULL; + + r = mailimap_body_fld_md5_parse(fd, buffer, &cur_token, &fld_md5, + progr_rate, progr_fun); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + + r = mailimap_body_ext_1part_1_parse(fd, buffer, &cur_token, + &fld_dsp, + &fld_lang, + &body_ext_list, + progr_rate, progr_fun); + if ((r != MAILIMAP_NO_ERROR) && (r != MAILIMAP_ERROR_PARSE)) { + res = r; + goto free; + } + + ext_1part = mailimap_body_ext_1part_new(fld_md5, fld_dsp, fld_lang, + body_ext_list); + + if (ext_1part == NULL) { + res = MAILIMAP_ERROR_MEMORY; + goto free; + } + + * result = ext_1part; + * index = cur_token; + + return MAILIMAP_NO_ERROR; + + free: + if (body_ext_list) { + clist_foreach(body_ext_list, (clist_func) mailimap_body_extension_free, + NULL); + clist_free(body_ext_list); + } + if (fld_lang) + mailimap_body_fld_lang_free(fld_lang); + if (fld_dsp) + mailimap_body_fld_dsp_free(fld_dsp); + mailimap_body_fld_md5_free(fld_md5); + err: + return res; +} + + +/* + body-ext-mpart = body-fld-param [SP body-fld-dsp [SP body-fld-lang + *(SP body-extension)]] + ; MUST NOT be returned on non-extensible + ; "BODY" fetch +*/ + +static int +mailimap_body_ext_mpart_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_body_ext_mpart ** result, + size_t progr_rate, + progress_function * progr_fun) +{ + size_t cur_token; + + struct mailimap_body_fld_dsp * fld_dsp; + struct mailimap_body_fld_lang * fld_lang; + struct mailimap_body_fld_param * fld_param; + clist * body_ext_list; + + struct mailimap_body_ext_mpart * ext_mpart; + int r; + int res; + + cur_token = * index; + + fld_param = NULL; + fld_dsp = NULL; + fld_lang = NULL; + body_ext_list = NULL; + + r = mailimap_body_fld_param_parse(fd, buffer, &cur_token, &fld_param, + progr_rate, progr_fun); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + + r = mailimap_body_ext_1part_1_parse(fd, buffer, &cur_token, + &fld_dsp, + &fld_lang, + &body_ext_list, + progr_rate, progr_fun); + if ((r != MAILIMAP_NO_ERROR) && (r != MAILIMAP_ERROR_PARSE)) { + res = r; + goto free; + } + + ext_mpart = mailimap_body_ext_mpart_new(fld_param, fld_dsp, fld_lang, + body_ext_list); + if (ext_mpart == NULL) { + res = MAILIMAP_ERROR_MEMORY; + goto free; + } + + * result = ext_mpart; + * index = cur_token; + + return MAILIMAP_NO_ERROR; + + free: + if (body_ext_list) { + clist_foreach(body_ext_list, (clist_func) mailimap_body_extension_free, + NULL); + clist_free(body_ext_list); + } + if (fld_lang) + mailimap_body_fld_lang_free(fld_lang); + if (fld_dsp) + mailimap_body_fld_dsp_free(fld_dsp); + if (fld_param != NULL) + mailimap_body_fld_param_free(fld_param); + err: + return res; +} + +/* + body-fields = body-fld-param SP body-fld-id SP body-fld-desc SP + body-fld-enc SP body-fld-octets +*/ + +static int +mailimap_body_fields_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_body_fields ** result, + size_t progr_rate, + progress_function * progr_fun) +{ + struct mailimap_body_fields * body_fields; + size_t cur_token; + struct mailimap_body_fld_param * body_fld_param; + char * body_fld_id; + char * body_fld_desc; + struct mailimap_body_fld_enc * body_fld_enc; + uint32_t body_fld_octets; + int r; + int res; + + body_fld_param = NULL; + body_fld_id = NULL; + body_fld_desc = NULL; + body_fld_enc = NULL; + body_fld_octets = 0; + + cur_token = * index; + + r = mailimap_body_fld_param_parse(fd, buffer, &cur_token, &body_fld_param, + progr_rate, progr_fun); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + + r = mailimap_space_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto fld_param_free; + } + + r = mailimap_body_fld_id_parse(fd, buffer, &cur_token, &body_fld_id, + progr_rate, progr_fun); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto fld_param_free; + } + + r = mailimap_space_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto fld_id_free; + } + + r = mailimap_body_fld_desc_parse(fd, buffer, &cur_token, &body_fld_desc, + progr_rate, progr_fun); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto fld_id_free; + } + + r = mailimap_space_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto fld_desc_free; + } + + r = mailimap_body_fld_enc_parse(fd, buffer, &cur_token, &body_fld_enc, + progr_rate, progr_fun); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto fld_desc_free; + } + + r = mailimap_space_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto fld_enc_free; + } + + r = mailimap_body_fld_octets_parse(fd, buffer, &cur_token, + &body_fld_octets); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto fld_enc_free; + } + + body_fields = mailimap_body_fields_new(body_fld_param, + body_fld_id, + body_fld_desc, + body_fld_enc, + body_fld_octets); + if (body_fields == NULL) { + res = MAILIMAP_ERROR_MEMORY; + goto fld_enc_free; + } + + * result = body_fields; + * index = cur_token; + + return MAILIMAP_NO_ERROR; + + fld_enc_free: + mailimap_body_fld_enc_free(body_fld_enc); + fld_desc_free: + mailimap_body_fld_desc_free(body_fld_desc); + fld_id_free: + mailimap_body_fld_id_free(body_fld_id); + fld_param_free: + if (body_fld_param != NULL) + mailimap_body_fld_param_free(body_fld_param); + err: + return res; +} + +/* + body-fld-desc = nstring +*/ + +static int mailimap_body_fld_desc_parse(mailstream * fd, MMAPString * buffer, + size_t * index, char ** result, + size_t progr_rate, + progress_function * progr_fun) +{ + return mailimap_nstring_parse(fd, buffer, index, result, NULL, + progr_rate, progr_fun); +} + +/* + body-fld-dsp = "(" string SP body-fld-param ")" / nil +*/ + +static int +mailimap_body_fld_dsp_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_body_fld_dsp ** result, + size_t progr_rate, + progress_function * progr_fun) +{ + size_t cur_token; + char * name; + struct mailimap_body_fld_param * body_fld_param; + struct mailimap_body_fld_dsp * body_fld_dsp; + int res; + int r; + + cur_token = * index; + name = NULL; + body_fld_param = NULL; + + r = mailimap_nil_parse(fd, buffer, &cur_token); + if (r == MAILIMAP_NO_ERROR) { + * result = NULL; + * index = cur_token; + return MAILIMAP_NO_ERROR; + } + + if (r != MAILIMAP_ERROR_PARSE) { + res = r; + goto err; + } + + r = mailimap_oparenth_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + + r = mailimap_string_parse(fd, buffer, &cur_token, &name, NULL, + progr_rate, progr_fun); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + + r = mailimap_space_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto string_free; + } + + r = mailimap_body_fld_param_parse(fd, buffer, &cur_token, + &body_fld_param, + progr_rate, progr_fun); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto string_free; + } + + r = mailimap_cparenth_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto string_free; + } + + body_fld_dsp = mailimap_body_fld_dsp_new(name, body_fld_param); + if (body_fld_dsp == NULL) { + res = MAILIMAP_ERROR_MEMORY; + goto fld_param_free; + } + + * index = cur_token; + * result = body_fld_dsp; + + return MAILIMAP_NO_ERROR; + + fld_param_free: + if (body_fld_param != NULL) + mailimap_body_fld_param_free(body_fld_param); + string_free: + mailimap_string_free(name); + err: + return res; +} + +/* + body-fld-enc = (DQUOTE ("7BIT" / "8BIT" / "BINARY" / "BASE64"/ + "QUOTED-PRINTABLE") DQUOTE) / string +*/ + +static inline int +mailimap_body_fld_known_enc_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + int * result, + size_t progr_rate, + progress_function * progr_fun) +{ + size_t cur_token; + int type; + int r; + int res; + + cur_token = * index; + + r = mailimap_dquote_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + + type = mailimap_encoding_get_token_value(fd, buffer, &cur_token); + + if (type == -1) { + res = MAILIMAP_ERROR_PARSE; + goto err; + } + + r = mailimap_dquote_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + + * result = type; + * index = cur_token; + + return MAILIMAP_NO_ERROR; + + err: + return res; +} + +static int +mailimap_body_fld_enc_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_body_fld_enc ** result, + size_t progr_rate, + progress_function * progr_fun) +{ + size_t cur_token; + int type; + char * value; + struct mailimap_body_fld_enc * body_fld_enc; + int r; + int res; + + cur_token = * index; + + r = mailimap_body_fld_known_enc_parse(fd, buffer, &cur_token, + &type, progr_rate, progr_fun); + if (r == MAILIMAP_NO_ERROR) { + value = NULL; + } + else if (r == MAILIMAP_ERROR_PARSE) { + type = MAILIMAP_BODY_FLD_ENC_OTHER; + + r = mailimap_string_parse(fd, buffer, &cur_token, &value, NULL, + progr_rate, progr_fun); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + } + else { + res = r; + goto err; + } + + body_fld_enc = mailimap_body_fld_enc_new(type, value); + if (body_fld_enc == NULL) { + res = MAILIMAP_ERROR_MEMORY; + goto value_free; + } + + * result = body_fld_enc; + * index = cur_token; + + return MAILIMAP_NO_ERROR; + + value_free: + if (value) + mailimap_string_free(value); + err: + return res; +} + +/* + body-fld-id = nstring +*/ + +static int mailimap_body_fld_id_parse(mailstream * fd, MMAPString * buffer, + size_t * index, char ** result, + size_t progr_rate, + progress_function * progr_fun) +{ + return mailimap_nstring_parse(fd, buffer, index, result, NULL, + progr_rate, progr_fun); +} + + +/* + body-fld-lang = nstring / "(" string *(SP string) ")" +*/ + +/* +"(" string *(SP string) ")" +*/ + +static int +mailimap_body_fld_lang_list_parse(mailstream * fd, MMAPString * buffer, + size_t * index, clist ** result, + size_t progr_rate, + progress_function * progr_fun) +{ + size_t cur_token; + clist * list; + int r; + int res; + + cur_token = * index; + + r = mailimap_oparenth_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + + list = clist_new(); + if (list == NULL) { + res = MAILIMAP_ERROR_MEMORY; + goto err; + } + + while (1) { + char * elt; + + r = mailimap_string_parse(fd, buffer, &cur_token, &elt, NULL, + progr_rate, progr_fun); + if (r != MAILIMAP_ERROR_PARSE) + break; + else if (r == MAILIMAP_NO_ERROR) { + r = clist_append(list, elt); + if (r < 0) { + mailimap_string_free(elt); + res = r; + goto list_free; + } + } + else { + res = r; + goto list_free; + } + } + + r = mailimap_cparenth_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto list_free; + } + + * index = cur_token; + * result = list; + + return MAILIMAP_NO_ERROR; + + list_free: + clist_foreach(list, (clist_func) mailimap_string_free, NULL); + clist_free(list); + err: + return res; +} + +/* + body-fld-lang = nstring / "(" string *(SP string) ")" +*/ + +static int +mailimap_body_fld_lang_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_body_fld_lang ** result, + size_t progr_rate, + progress_function * progr_fun) +{ + char * value; + clist * list; + struct mailimap_body_fld_lang * fld_lang; + int type; + int r; + int res; + + size_t cur_token; + + cur_token = * index; + + value = NULL; + list = NULL; + type = MAILIMAP_BODY_FLD_LANG_ERROR; /* XXX - removes a gcc warning */ + + r = mailimap_nstring_parse(fd, buffer, &cur_token, &value, NULL, + progr_rate, progr_fun); + if (r == MAILIMAP_NO_ERROR) + type = MAILIMAP_BODY_FLD_LANG_SINGLE; + + if (r == MAILIMAP_ERROR_PARSE) { + r = mailimap_body_fld_lang_list_parse(fd, buffer, &cur_token, &list, + progr_rate, progr_fun); + if (r == MAILIMAP_NO_ERROR) + type = MAILIMAP_BODY_FLD_LANG_LIST; + } + + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + + fld_lang = mailimap_body_fld_lang_new(type, value, list); + if (fld_lang == NULL) { + res = MAILIMAP_ERROR_MEMORY; + goto free; + } + + * index = cur_token; + * result = fld_lang; + + return MAILIMAP_NO_ERROR; + + free: + if (value) + mailimap_nstring_free(value); + if (list) { + clist_foreach(list, (clist_func) mailimap_string_free, NULL); + clist_free(list); + } + err: + return res; +} + +/* + body-fld-lines = number +*/ + +static int mailimap_body_fld_lines_parse(mailstream * fd, + MMAPString * buffer, size_t * index, + uint32_t * result) +{ + return mailimap_number_parse(fd, buffer, index, result); +} + +/* + body-fld-md5 = nstring +*/ + +static int mailimap_body_fld_md5_parse(mailstream * fd, MMAPString * buffer, + size_t * index, char ** result, + size_t progr_rate, + progress_function * progr_fun) +{ + return mailimap_nstring_parse(fd, buffer, index, result, NULL, + progr_rate, progr_fun); +} + +/* + body-fld-octets = number +*/ + +static int mailimap_body_fld_octets_parse(mailstream * fd, + MMAPString * buffer, size_t * index, + uint32_t * result) +{ + return mailimap_number_parse(fd, buffer, index, result); +} + +/* + body-fld-param = "(" string SP string *(SP string SP string) ")" / nil +*/ + +/* + string SP string +*/ + +static int +mailimap_single_body_fld_param_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_single_body_fld_param ** + result, + size_t progr_rate, + progress_function * progr_fun) +{ + struct mailimap_single_body_fld_param * param; + char * name; + char * value; + size_t cur_token; + int r; + int res; + + cur_token = * index; + + name = NULL; + value = NULL; + + r = mailimap_string_parse(fd, buffer, &cur_token, &name, NULL, + progr_rate, progr_fun); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + + r = mailimap_space_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto free_name; + } + + r = mailimap_string_parse(fd, buffer, &cur_token, &value, NULL, + progr_rate, progr_fun); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto free_name; + } + + param = mailimap_single_body_fld_param_new(name, value); + if (param == NULL) { + res = MAILIMAP_ERROR_MEMORY; + goto free_value; + } + + * result = param; + * index = cur_token; + + return MAILIMAP_NO_ERROR; + + free_value: + mailimap_string_free(name); + free_name: + mailimap_string_free(value); + err: + return res; +} + +/* + body-fld-param = "(" string SP string *(SP string SP string) ")" / nil +*/ + +static int +mailimap_body_fld_param_parse(mailstream * fd, + MMAPString * buffer, size_t * index, + struct mailimap_body_fld_param ** result, + size_t progr_rate, + progress_function * progr_fun) +{ + size_t cur_token; + clist * param_list; + struct mailimap_body_fld_param * fld_param; + int r; + int res; + + param_list = NULL; + cur_token = * index; + + r = mailimap_nil_parse(fd, buffer, &cur_token); + if (r == MAILIMAP_NO_ERROR) { + * result = NULL; + * index = cur_token; + return MAILIMAP_NO_ERROR; + } + + if (r != MAILIMAP_ERROR_PARSE) { + res = r; + goto err; + } + + r = mailimap_oparenth_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + + r = mailimap_struct_spaced_list_parse(fd, buffer, &cur_token, ¶m_list, + (mailimap_struct_parser *) + mailimap_single_body_fld_param_parse, + (mailimap_struct_destructor *) + mailimap_single_body_fld_param_free, + progr_rate, progr_fun); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + + r = mailimap_cparenth_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto free; + } + + fld_param = mailimap_body_fld_param_new(param_list); + if (fld_param == NULL) { + res = MAILIMAP_ERROR_MEMORY; + goto free; + } + + * index = cur_token; + * result = fld_param; + + return MAILIMAP_NO_ERROR; + + free: + clist_foreach(param_list, + (clist_func) mailimap_single_body_fld_param_free, + NULL); + clist_free(param_list); + err: + return res; +} + +/* + body-type-1part = (body-type-basic / body-type-msg / body-type-text) + [SP body-ext-1part] +*/ + +static int +mailimap_body_type_1part_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_body_type_1part ** result, + size_t progr_rate, + progress_function * progr_fun) +{ + size_t cur_token; + struct mailimap_body_type_1part * body_type_1part; + struct mailimap_body_type_basic * body_type_basic; + struct mailimap_body_type_msg * body_type_msg; + struct mailimap_body_type_text * body_type_text; + struct mailimap_body_ext_1part * body_ext_1part; + int type; + size_t final_token; + int r; + int res; + + cur_token = * index; + + body_type_basic = NULL; + body_type_msg = NULL; + body_type_text = NULL; + body_ext_1part = NULL; + + type = MAILIMAP_BODY_TYPE_1PART_ERROR; /* XXX - removes a gcc warning */ + + r = mailimap_body_type_msg_parse(fd, buffer, &cur_token, + &body_type_msg, + progr_rate, progr_fun); + if (r == MAILIMAP_NO_ERROR) + type = MAILIMAP_BODY_TYPE_1PART_MSG; + + if (r == MAILIMAP_ERROR_PARSE) { + r = mailimap_body_type_text_parse(fd, buffer, &cur_token, + &body_type_text, + progr_rate, progr_fun); + if (r == MAILIMAP_NO_ERROR) + type = MAILIMAP_BODY_TYPE_1PART_TEXT; + } + + if (r == MAILIMAP_ERROR_PARSE) { + r = mailimap_body_type_basic_parse(fd, buffer, &cur_token, + &body_type_basic, + progr_rate, progr_fun); + if (r == MAILIMAP_NO_ERROR) + type = MAILIMAP_BODY_TYPE_1PART_BASIC; + } + + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + + final_token = cur_token; + body_ext_1part = NULL; + + r = mailimap_space_parse(fd, buffer, &cur_token); + + if (r == MAILIMAP_NO_ERROR) { + r = mailimap_body_ext_1part_parse(fd, buffer, &cur_token, &body_ext_1part, + progr_rate, progr_fun); + if (r == MAILIMAP_NO_ERROR) + final_token = cur_token; + else if (r == MAILIMAP_ERROR_PARSE) { + /* do nothing */ + } + else { + res = r; + goto free; + } + } + else if (r == MAILIMAP_ERROR_PARSE) { + /* do nothing */ + } + else { + res = r; + goto free; + } + + body_type_1part = mailimap_body_type_1part_new(type, body_type_basic, + body_type_msg, body_type_text, + body_ext_1part); + if (body_type_1part == NULL) { + res = MAILIMAP_ERROR_MEMORY; + goto free; + } + + * index = final_token; + * result = body_type_1part; + + return MAILIMAP_NO_ERROR; + + free: + if (body_type_basic) + mailimap_body_type_basic_free(body_type_basic); + if (body_type_msg) + mailimap_body_type_msg_free(body_type_msg); + if (body_type_text) + mailimap_body_type_text_free(body_type_text); + if (body_ext_1part) + mailimap_body_ext_1part_free(body_ext_1part); + err: + return res; +} + +/* + body-type-basic = media-basic SP body-fields + ; MESSAGE subtype MUST NOT be "RFC822" +*/ + +static int +mailimap_body_type_basic_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_body_type_basic ** result, + size_t progr_rate, + progress_function * progr_fun) +{ + size_t cur_token; + struct mailimap_body_type_basic * body_type_basic; + struct mailimap_media_basic * media_basic; + struct mailimap_body_fields * body_fields; + int r; + int res; + + cur_token = * index; + + media_basic = NULL; + body_fields = NULL; + + r = mailimap_media_basic_parse(fd, buffer, &cur_token, &media_basic, + progr_rate, progr_fun); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + + r = mailimap_space_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto free_media_basic; + } + + r = mailimap_body_fields_parse(fd, buffer, &cur_token, &body_fields, + progr_rate, progr_fun); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto free_media_basic; + } + + body_type_basic = mailimap_body_type_basic_new(media_basic, body_fields); + if (body_type_basic == NULL) { + res = MAILIMAP_ERROR_MEMORY; + goto free_body_fields; + } + + * index = cur_token; + * result = body_type_basic; + + return MAILIMAP_NO_ERROR; + + free_body_fields: + mailimap_body_fields_free(body_fields); + free_media_basic: + mailimap_media_basic_free(media_basic); + err: + return res; +} + +/* + body-type-mpart = 1*body SP media-subtype + [SP body-ext-mpart] +*/ + +static int +mailimap_body_type_mpart_parse(mailstream * fd, + MMAPString * buffer, + size_t * index, + struct mailimap_body_type_mpart ** result, + size_t progr_rate, + progress_function * progr_fun) +{ + struct mailimap_body_type_mpart * body_type_mpart; + clist * body_list; + size_t cur_token; + size_t final_token; + char * media_subtype; + struct mailimap_body_ext_mpart * body_ext_mpart; + int r; + int res; + + cur_token = * index; + + body_list = NULL; + media_subtype = NULL; + body_ext_mpart = NULL; + + r = mailimap_struct_multiple_parse(fd, buffer, &cur_token, + &body_list, + (mailimap_struct_parser *) + mailimap_body_parse, + (mailimap_struct_destructor *) + mailimap_body_free, + progr_rate, progr_fun); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + + r = mailimap_space_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto free_body_list; + } + + r = mailimap_media_subtype_parse(fd, buffer, &cur_token, &media_subtype, + progr_rate, progr_fun); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto free_body_list; + } + + final_token = cur_token; + + body_ext_mpart = NULL; + + r = mailimap_space_parse(fd, buffer, &cur_token); + if (r == MAILIMAP_NO_ERROR) { + r = mailimap_body_ext_mpart_parse(fd, buffer, &cur_token, &body_ext_mpart, + progr_rate, progr_fun); + if (r == MAILIMAP_NO_ERROR) + final_token = cur_token; + else if (r == MAILIMAP_ERROR_PARSE) { + /* do nothing */ + } + else { + res = r; + goto free_body_list; + } + } + else if (r == MAILIMAP_ERROR_PARSE) { + /* do nothing */ + } + else { + res = r; + goto free_body_list; + } + + body_type_mpart = mailimap_body_type_mpart_new(body_list, media_subtype, + body_ext_mpart); + if (body_type_mpart == NULL) { + res = MAILIMAP_ERROR_MEMORY; + goto free_body_ext_mpart; + } + + * result = body_type_mpart; + * index = final_token; + + return MAILIMAP_NO_ERROR; + + free_body_ext_mpart: + if (body_ext_mpart) + mailimap_body_ext_mpart_free(body_ext_mpart); + mailimap_media_subtype_free(media_subtype); + free_body_list: + clist_foreach(body_list, (clist_func) mailimap_body_free, NULL); + clist_free(body_list); + err: + return res; +} + +/* + body-type-msg = media-message SP body-fields SP envelope + SP body SP body-fld-lines +*/ + +static int +mailimap_body_type_msg_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_body_type_msg ** result, + size_t progr_rate, + progress_function * progr_fun) +{ + struct mailimap_body_fields * body_fields; + struct mailimap_envelope * envelope; + struct mailimap_body * body; + uint32_t body_fld_lines; + struct mailimap_body_type_msg * body_type_msg; + size_t cur_token; + int r; + int res; + + cur_token = * index; + + body_fields = NULL; + envelope = NULL; + body = NULL; + body_fld_lines = 0; + + r = mailimap_media_message_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + + r = mailimap_space_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + + r = mailimap_body_fields_parse(fd, buffer, &cur_token, &body_fields, + progr_rate, progr_fun); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + + r = mailimap_space_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto body_fields; + } + + r = mailimap_envelope_parse(fd, buffer, &cur_token, &envelope, + progr_rate, progr_fun); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto body_fields; + } + + r = mailimap_space_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto envelope; + } + + r = mailimap_body_parse(fd, buffer, &cur_token, &body, + progr_rate, progr_fun); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto envelope; + } + + r = mailimap_space_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto body; + } + + r = mailimap_body_fld_lines_parse(fd, buffer, &cur_token, + &body_fld_lines); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto body; + } + + body_type_msg = mailimap_body_type_msg_new(body_fields, envelope, + body, body_fld_lines); + if (body_type_msg == NULL) { + res = MAILIMAP_ERROR_MEMORY; + goto body; + } + + * result = body_type_msg; + * index = cur_token; + + return MAILIMAP_NO_ERROR; + + body: + mailimap_body_free(body); + envelope: + mailimap_envelope_free(envelope); + body_fields: + mailimap_body_fields_free(body_fields); + err: + return res; +} + +/* + body-type-text = media-text SP body-fields SP body-fld-lines +*/ + +static int +mailimap_body_type_text_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_body_type_text ** + result, + size_t progr_rate, + progress_function * progr_fun) +{ + char * media_text; + struct mailimap_body_fields * body_fields; + uint32_t body_fld_lines; + struct mailimap_body_type_text * body_type_text; + size_t cur_token; + int r; + int res; + + media_text = NULL; + body_fields = NULL; + body_fld_lines = 0; + + cur_token = * index; + + r = mailimap_media_text_parse(fd, buffer, &cur_token, &media_text, + progr_rate, progr_fun); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + + r = mailimap_space_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto free_media_text; + } + + r = mailimap_body_fields_parse(fd, buffer, &cur_token, &body_fields, + progr_rate, progr_fun); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto free_media_text; + } + + r = mailimap_space_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto free_body_fields; + } + + r = mailimap_body_fld_lines_parse(fd, buffer, &cur_token, &body_fld_lines); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto free_body_fields; + } + + body_type_text = mailimap_body_type_text_new(media_text, body_fields, + body_fld_lines); + if (body_type_text == NULL) { + res = MAILIMAP_ERROR_MEMORY; + goto free_body_fields; + } + + * result = body_type_text; + * index = cur_token; + + return MAILIMAP_NO_ERROR; + + free_body_fields: + mailimap_body_fields_free(body_fields); + free_media_text: + mailimap_media_text_free(media_text); + err: + return res; +} + + +/* + capability = ("AUTH=" auth-type) / atom + ; New capabilities MUST begin with "X" or be + ; registered with IANA as standard or + ; standards-track +*/ + +static int +mailimap_capability_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_capability ** result, + size_t progr_rate, + progress_function * progr_fun) +{ + size_t cur_token; + int type; + char * auth_type; + char * atom; + struct mailimap_capability * cap; + int r; + int res; + + cur_token = * index; + + auth_type = NULL; + atom = NULL; + + r = mailimap_token_case_insensitive_parse(fd, buffer, &cur_token, "AUTH="); + switch (r) { + case MAILIMAP_NO_ERROR: + type = MAILIMAP_CAPABILITY_AUTH_TYPE; + + r = mailimap_auth_type_parse(fd, buffer, &cur_token, &auth_type, + progr_rate, progr_fun); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + break; + + case MAILIMAP_ERROR_PARSE: + r = mailimap_atom_parse(fd, buffer, &cur_token, &atom, + progr_rate, progr_fun); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + + type = MAILIMAP_CAPABILITY_NAME; + break; + + default: + res = r; + goto err; + } + + cap = mailimap_capability_new(type, auth_type, atom); + if (cap == NULL) { + res = MAILIMAP_ERROR_MEMORY; + goto free; + } + + * result = cap; + * index = cur_token; + + return MAILIMAP_NO_ERROR; + + free: + if (auth_type) + mailimap_auth_type_free(auth_type); + if (atom) + mailimap_atom_free(atom); + err: + return res; +} + +/* + capability-data = "CAPABILITY" *(SP capability) SP "IMAP4rev1" + *(SP capability) + ; IMAP4rev1 servers which offer RFC 1730 + ; compatibility MUST list "IMAP4" as the first + ; capability. +*/ + +/* + SP capability *(SP capability) +*/ + +static int mailimap_capability_list_parse(mailstream * fd, + MMAPString * buffer, + size_t * index, + clist ** result, + size_t progr_rate, + progress_function * progr_fun) +{ + size_t cur_token; + clist * list; + int r; + + cur_token = * index; + + r = mailimap_space_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_struct_spaced_list_parse(fd, buffer, &cur_token, &list, + (mailimap_struct_parser *) + mailimap_capability_parse, + (mailimap_struct_destructor *) + mailimap_capability_free, + progr_rate, progr_fun); + if (r != MAILIMAP_NO_ERROR) + return r; + + * index = cur_token; + * result = list; + + return MAILIMAP_NO_ERROR; +} + +static int +mailimap_capability_data_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_capability_data ** result, + size_t progr_rate, + progress_function * progr_fun) +{ + size_t cur_token; + clist * cap_list; +#if 0 + clist * cap_list_2; +#endif + struct mailimap_capability_data * cap_data; + int r; + int res; + + cur_token = * index; + + cap_list = NULL; +#if 0 + cap_list_2 = NULL; +#endif + + r = mailimap_token_case_insensitive_parse(fd, buffer, + &cur_token, "CAPABILITY"); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + + r = mailimap_capability_list_parse(fd, buffer, &cur_token, + &cap_list, + progr_rate, progr_fun); + + if ((r != MAILIMAP_NO_ERROR) && (r != MAILIMAP_ERROR_PARSE)) { + res = r; + goto err; + } + +#if 0 + if (!mailimap_space_parse(fd, buffer, &cur_token)) { + res = r; + goto free_list; + } + + if (!mailimap_token_case_insensitive_parse(fd, buffer, + &cur_token, "IMAP4rev1")) + goto free_list; + + r = mailimap_capability_list_parse(fd, buffer, &cur_token, + &cap_list_2, + progr_rate, progr_fun); + + cap_list = g_list_concat(cap_list, cap_list_2); +#endif + + cap_data = mailimap_capability_data_new(cap_list); + if (cap_data == NULL) { + res = MAILIMAP_ERROR_MEMORY; + goto free_list; + } + + * result = cap_data; + * index = cur_token; + + return MAILIMAP_NO_ERROR; + + free_list: + if (cap_list) { + clist_foreach(cap_list, (clist_func) mailimap_capability_free, NULL); + clist_free(cap_list); + } + err: + return res; +} + +/* + UNIMPLEMENTED BECAUSE UNUSED (only in literal) + CHAR8 = %x01-ff + ; any OCTET except NUL, %x00 +*/ + +/* +static gboolean is_char8(gchar ch) +{ + return (ch != 0x00); +} +*/ + + +/* +UNIMPLEMENTED + command = tag SP (command-any / command-auth / command-nonauth / + command-select) CRLF + ; Modal based on state +*/ + +/* +UNIMPLEMENTED + command-any = "CAPABILITY" / "LOGOUT" / "NOOP" / x-command + ; Valid in all states +*/ + +/* +UNIMPLEMENTED + command-auth = append / create / delete / examine / list / lsub / + rename / select / status / subscribe / unsubscribe + ; Valid only in Authenticated or Selected state +*/ + +/* +UNIMPLEMENTED + command-nonauth = login / authenticate + ; Valid only when in Not Authenticated state +*/ + +/* +UNIMPLEMENTED + command-select = "CHECK" / "CLOSE" / "EXPUNGE" / copy / fetch / store / + uid / search + ; Valid only when in Selected state +*/ + +/* + continue-req = "+" SP (resp-text / base64) CRLF +*/ + +int +mailimap_continue_req_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_continue_req ** result, + size_t progr_rate, + progress_function * progr_fun) +{ + struct mailimap_resp_text * resp_text; + size_t cur_token; + struct mailimap_continue_req * cont_req; + char * base64; + int type; + int r; + int res; + + cur_token = * index; + + r = mailimap_plus_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_space_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) + return r; + + resp_text = NULL; + base64 = NULL; + + type = MAILIMAP_CONTINUE_REQ_ERROR; /* XXX - removes a gcc warning */ + + r = mailimap_base64_parse(fd, buffer, &cur_token, &base64, + progr_rate, progr_fun); + + if (r == MAILIMAP_NO_ERROR) + type = MAILIMAP_CONTINUE_REQ_BASE64; + + if (r == MAILIMAP_ERROR_PARSE) { + r = mailimap_resp_text_parse(fd, buffer, &cur_token, &resp_text, + progr_rate, progr_fun); + + if (r == MAILIMAP_NO_ERROR) + type = MAILIMAP_CONTINUE_REQ_TEXT; + } + + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + + r = mailimap_crlf_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto free; + } + + cont_req = mailimap_continue_req_new(type, resp_text, base64); + if (cont_req == NULL) { + res = MAILIMAP_ERROR_MEMORY; + goto free; + } + + * result = cont_req; + * index = cur_token; + + return MAILIMAP_NO_ERROR; + + free: + if (base64 != NULL) + mailimap_base64_free(base64); + if (resp_text != NULL) + mailimap_resp_text_free(resp_text); + err: + return res; +} + +/* + UNIMPLEMENTED + copy = "COPY" SP set SP mailbox +*/ + +/* + UNIMPLEMENTED + create = "CREATE" SP mailbox + ; Use of INBOX gives a NO error +*/ + +/* + UNIMPLEMENTED + date = date-text / DQUOTE date-text DQUOTE +*/ + +/* + UNIMPLEMENTED + date-day = 1*2DIGIT + ; Day of month +*/ + +/* +static gboolean mailimap_date_day_parse(mailstream * fd, + MMAPString * buffer, + guint32 * index, + gint * result) +{ + guint32 cur_token; + gint digit; + gint number; + + cur_token = * index; + + if (!mailimap_digit_parse(fd, buffer, &cur_token, &digit)) + return FALSE; + + number = digit; + + if (mailimap_digit_parse(fd, buffer, &cur_token, &digit)) + number = number * 10 + digit; + + * result = number; + * index = cur_token; + + return TRUE; +} +*/ + +/* + date-day-fixed = (SP DIGIT) / 2DIGIT + ; Fixed-format version of date-day +*/ + +static int mailimap_date_day_fixed_parse(mailstream * fd, + MMAPString * buffer, + size_t * index, + int * result) +{ +#ifdef UNSTRICT_SYNTAX + size_t cur_token; + uint32_t day; + int r; + + cur_token = * index; + + r = mailimap_number_parse(fd, buffer, &cur_token, &day); + if (r != MAILIMAP_NO_ERROR) + return r; + + * index = cur_token; + * result = day; + + return MAILIMAP_NO_ERROR; + +#else + size_t cur_token; + int r; + + cur_token = * index; + + if (mailimap_space_parse(fd, buffer, &cur_token)) { + int digit; + + r = mailimap_digit_parse(fd, buffer, &cur_token, &digit); + if (r != MAILIMAP_NO_ERROR) + return r; + + * result = digit; + * index = cur_token; + + return MAILIMAP_NO_ERROR; + } + else { + int digit1; + int digit2; + + r = mailimap_digit_parse(fd, buffer, &cur_token, &digit1); + if (r != MAILIMAP_NO_ERROR) + return r; + r = mailimap_digit_parse(fd, buffer, &cur_token, &digit2); + if (r != MAILIMAP_NO_ERROR) + return r; + + * result = digit1 * 10 + digit2; + * index = cur_token; + + return MAILIMAP_NO_ERROR; + } +#endif +} + + +/* + date-month = "Jan" / "Feb" / "Mar" / "Apr" / "May" / "Jun" / + "Jul" / "Aug" / "Sep" / "Oct" / "Nov" / "Dec" +*/ + +static int mailimap_date_month_parse(mailstream * fd, MMAPString * buffer, + size_t * index, int * result) +{ + size_t cur_token; + int month; + + cur_token = * index; + + month = mailimap_month_get_token_value(fd, buffer, &cur_token); + if (month == -1) + return MAILIMAP_ERROR_PARSE; + + * result = month; + * index = cur_token; + + return MAILIMAP_NO_ERROR; +} + +/* + UNIMPLEMENTED + date-text = date-day "-" date-month "-" date-year +*/ + +/* +static struct mailimap_date_text * +mailimap_date_text_new(gint day, gint month, gint year) +{ + struct mailimap_date_text * date_text; + + date_text = g_new(struct mailimap_date_text, 1); + if (date_text == NULL) + return NULL; + + date_text->day = day; + date_text->month = month; + date_text->year = year; + + return date_text; +} + +static void mailimap_date_text_free(struct mailimap_date_text * date_text) +{ + g_free(date_text); +} + +static gboolean +mailimap_date_text_parse(mailstream * fd, MMAPString * buffer, + guint32 * index, struct mailimap_date_text ** result) +{ + struct mailimap_date_text * date_text; + gint day; + gint month; + gint year; + guint32 cur_token; + + cur_token = * index; + + if (!mailimap_date_day_parse(fd, buffer, &cur_token, &day)) + return FALSE; + + if (!mailimap_minus_parse(fd, buffer, &cur_token)) + return FALSE; + + if (!mailimap_date_month_parse(fd, buffer, &cur_token, &month)) + return FALSE; + + if (!mailimap_minus_parse(fd, buffer, &cur_token)) + return FALSE; + + if (!mailimap_date_year_parse(fd, buffer, &cur_token, &year)) + return FALSE; + + date_text = mailimap_date_text_new(day, month, year); + if (date_text == NULL) + return FALSE; + + * result = date_text; + * index = cur_token; + + return TRUE; +} +*/ + +/* + date-year = 4DIGIT +*/ + +static int mailimap_date_year_parse(mailstream * fd, MMAPString * buffer, + size_t * index, int * result) +{ +#ifdef UNSTRICT_SYNTAX + uint32_t year; + int r; + size_t cur_token; + + cur_token = * index; + + r = mailimap_number_parse(fd, buffer, &cur_token, &year); + if (r != MAILIMAP_NO_ERROR) + return r; + + * result = year; + * index = cur_token; + + return MAILIMAP_NO_ERROR; +#else + int i; + size_t cur_token; + int year; + int digit; + int r; + + cur_token = * index; + year = 0; + + for(i = 0 ; i < 4 ; i ++) { + r = mailimap_digit_parse(fd, buffer, &cur_token, &digit); + if (r != MAILIMAP_NO_ERROR) + return r; + year = year * 10 + digit; + } + + * result = year; + * index = cur_token; + + return MAILIMAP_NO_ERROR; +#endif +} + +/* + date-time = DQUOTE date-day-fixed "-" date-month "-" date-year + SP time SP zone DQUOTE +*/ + +static int mailimap_date_time_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_date_time ** result, + size_t progr_rate, + progress_function * progr_fun) +{ + int day; + int month; + int year; + int hour; + int min; + int sec; + struct mailimap_date_time * date_time; + size_t cur_token; + int zone; + int r; + + cur_token = * index; + + r = mailimap_dquote_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_date_day_fixed_parse(fd, buffer, &cur_token, &day); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_minus_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_date_month_parse(fd, buffer, &cur_token, &month); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_minus_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_date_year_parse(fd, buffer, &cur_token, &year); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_space_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_time_parse(fd, buffer, &cur_token, &hour, &min, &sec); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_space_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_zone_parse(fd, buffer, &cur_token, &zone); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_dquote_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) + return r; + + date_time = mailimap_date_time_new(day, month, year, hour, min, sec, zone); + if (date_time == NULL) + return MAILIMAP_ERROR_MEMORY; + + * result = date_time; + * index = cur_token; + + return MAILIMAP_NO_ERROR; +} + + +/* + UNIMPLEMENTED + delete = "DELETE" SP mailbox + ; Use of INBOX gives a NO error +*/ + +/* + digit-nz = %x31-39 + ; 1-9 +*/ + +#ifndef UNSTRICT_SYNTAX +static int is_digit_nz(char ch) +{ + return (ch >= '1') && (ch <= '9'); +} + +static int mailimap_digit_nz_parse(mailstream * fd, MMAPString * buffer, + size_t * index, int * result) +{ + size_t cur_token; + + cur_token = * index; + + if (is_digit_nz(buffer->str[cur_token])) { + * result = buffer->str[cur_token] - '0'; + cur_token ++; + * index = cur_token; + return MAILIMAP_NO_ERROR; + } + else + return MAILIMAP_ERROR_PARSE; +} +#endif + +/* + envelope = "(" env-date SP env-subject SP env-from SP env-sender SP + env-reply-to SP env-to SP env-cc SP env-bcc SP + env-in-reply-to SP env-message-id ")" +*/ + +static int mailimap_envelope_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_envelope ** result, + size_t progr_rate, + progress_function * progr_fun) +{ + size_t cur_token; + char * date; + char * subject; + struct mailimap_env_from * from; + struct mailimap_env_sender * sender; + struct mailimap_env_reply_to * reply_to; + struct mailimap_env_to * to; + struct mailimap_env_cc * cc; + struct mailimap_env_bcc * bcc; + char * in_reply_to; + char * message_id; + struct mailimap_envelope * envelope; + int r; + int res; + + date = NULL; + subject = NULL; + from = NULL; + sender = NULL; + reply_to = NULL; + to = NULL; + cc = NULL; + bcc = NULL; + in_reply_to = NULL; + message_id = NULL; + + cur_token = * index; + + r = mailimap_oparenth_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + + r = mailimap_env_date_parse(fd, buffer, &cur_token, &date, + progr_rate, progr_fun); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + + r = mailimap_space_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto date; + } + + r = mailimap_env_subject_parse(fd, buffer, &cur_token, &subject, + progr_rate, progr_fun); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto date; + } + + r = mailimap_space_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto subject; + } + + r = mailimap_env_from_parse(fd, buffer, &cur_token, &from, + progr_rate, progr_fun); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto subject; + } + + r = mailimap_space_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto from; + } + + r = mailimap_env_sender_parse(fd, buffer, &cur_token, &sender, + progr_rate, progr_fun); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto from; + } + + r = mailimap_space_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto sender; + } + + r = mailimap_env_reply_to_parse(fd, buffer, &cur_token, &reply_to, + progr_rate, progr_fun); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto sender; + } + + r = mailimap_space_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto reply_to; + } + + r = mailimap_env_to_parse(fd, buffer, &cur_token, &to, + progr_rate, progr_fun); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto reply_to; + } + + r = mailimap_space_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto to; + } + + r = mailimap_env_cc_parse(fd, buffer, &cur_token, &cc, + progr_rate, progr_fun); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto to; + } + + r = mailimap_space_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto cc; + } + + r = mailimap_env_bcc_parse(fd, buffer, &cur_token, &bcc, + progr_rate, progr_fun); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto cc; + } + + r = mailimap_space_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto bcc; + } + + r = mailimap_env_in_reply_to_parse(fd, buffer, &cur_token, &in_reply_to, + progr_rate, progr_fun); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto bcc; + } + + r = mailimap_space_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto in_reply_to; + } + + r = mailimap_env_message_id_parse(fd, buffer, &cur_token, &message_id, + progr_rate, progr_fun); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto in_reply_to; + } + + r = mailimap_cparenth_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto message_id; + } + + envelope = mailimap_envelope_new(date, subject, from, sender, reply_to, to, + cc, bcc, in_reply_to, message_id); + if (envelope == NULL) { + res = MAILIMAP_ERROR_MEMORY; + goto message_id; + } + + * result = envelope; + * index = cur_token; + + return MAILIMAP_NO_ERROR; + + message_id: + mailimap_env_message_id_free(message_id); + in_reply_to: + mailimap_env_in_reply_to_free(in_reply_to); + bcc: + mailimap_env_bcc_free(bcc); + cc: + mailimap_env_cc_free(cc); + to: + mailimap_env_to_free(to); + reply_to: + mailimap_env_reply_to_free(reply_to); + sender: + mailimap_env_sender_free(sender); + from: + mailimap_env_from_free(from); + subject: + mailimap_env_subject_free(date); + date: + mailimap_env_date_free(date); + err: + return res; +} + +/* + "(" 1*address ")" +*/ + +static int mailimap_address_list_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + clist ** result, + size_t progr_rate, + progress_function * progr_fun) +{ + size_t cur_token; + clist * address_list; + int r; + int res; + + cur_token = * index; + + address_list = NULL; + + r = mailimap_nil_parse(fd, buffer, &cur_token); + switch (r) { + case MAILIMAP_NO_ERROR: + address_list = NULL; + break; + + case MAILIMAP_ERROR_PARSE: + r = mailimap_oparenth_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + + r = mailimap_struct_multiple_parse(fd, buffer, &cur_token, &address_list, + (mailimap_struct_parser *) + mailimap_address_parse, + (mailimap_struct_destructor *) + mailimap_address_free, + progr_rate, progr_fun); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + + r = mailimap_cparenth_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto address_list; + } + + break; + + default: + res = r; + goto err; + } + + * result = address_list; + * index = cur_token; + + return MAILIMAP_NO_ERROR; + + address_list: + if (address_list) { + clist_foreach(address_list, (clist_func) mailimap_address_free, NULL); + clist_free(address_list); + } + err: + return res; +} + +/* + env-bcc = "(" 1*address ")" / nil +*/ + +static int +mailimap_env_bcc_parse(mailstream * fd, MMAPString * buffer, + size_t * index, struct mailimap_env_bcc ** result, + size_t progr_rate, + progress_function * progr_fun) +{ + clist * list; + size_t cur_token; + struct mailimap_env_bcc * env_bcc; + int r; + int res; + + cur_token = * index; + list = NULL; + + r = mailimap_address_list_parse(fd, buffer, &cur_token, &list, + progr_rate, progr_fun); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + + env_bcc = mailimap_env_bcc_new(list); + if (env_bcc == NULL) { + res = MAILIMAP_ERROR_MEMORY; + goto free; + } + + * index = cur_token; + * result = env_bcc; + + return MAILIMAP_NO_ERROR; + + free: + clist_foreach(list, (clist_func) mailimap_address_free, NULL); + clist_free(list); + err: + return res; +} + +/* + env-cc = "(" 1*address ")" / nil +*/ + +static int +mailimap_env_cc_parse(mailstream * fd, MMAPString * buffer, + size_t * index, struct mailimap_env_cc ** result, + size_t progr_rate, + progress_function * progr_fun) +{ + clist * list; + size_t cur_token; + struct mailimap_env_cc * env_cc; + int r; + int res; + + cur_token = * index; + list = NULL; + + r = mailimap_address_list_parse(fd, buffer, &cur_token, &list, + progr_rate, progr_fun); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + + env_cc = mailimap_env_cc_new(list); + if (env_cc == NULL) { + res = MAILIMAP_ERROR_MEMORY; + goto free; + } + + * index = cur_token; + * result = env_cc; + + return MAILIMAP_NO_ERROR; + + free: + clist_foreach(list, (clist_func) mailimap_address_free, NULL); + clist_free(list); + err: + return res; +} + +/* + env-date = nstring +*/ + +static int mailimap_env_date_parse(mailstream * fd, MMAPString * buffer, + size_t * index, char ** result, + size_t progr_rate, + progress_function * progr_fun) +{ + return mailimap_nstring_parse(fd, buffer, index, result, NULL, + progr_rate, progr_fun); +} + +/* + env-from = "(" 1*address ")" / nil +*/ + +static int +mailimap_env_from_parse(mailstream * fd, MMAPString * buffer, + size_t * index, struct mailimap_env_from ** result, + size_t progr_rate, + progress_function * progr_fun) +{ + clist * list; + size_t cur_token; + struct mailimap_env_from * env_from; + int r; + int res; + + cur_token = * index; + list = NULL; + + r = mailimap_address_list_parse(fd, buffer, &cur_token, &list, + progr_rate, progr_fun); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + + env_from = mailimap_env_from_new(list); + if (env_from == NULL) { + res = MAILIMAP_ERROR_MEMORY; + goto free; + } + + * index = cur_token; + * result = env_from; + + return MAILIMAP_NO_ERROR; + + free: + clist_foreach(list, (clist_func) mailimap_address_free, NULL); + clist_free(list); + err: + return res; +} + +/* + env-in-reply-to = nstring +*/ + +static int mailimap_env_in_reply_to_parse(mailstream * fd, + MMAPString * buffer, + size_t * index, char ** result, + size_t progr_rate, + progress_function * progr_fun) +{ + return mailimap_nstring_parse(fd, buffer, index, result, NULL, + progr_rate, progr_fun); +} + +/* + env-message-id = nstring +*/ + +static int mailimap_env_message_id_parse(mailstream * fd, + MMAPString * buffer, + size_t * index, char ** result, + size_t progr_rate, + progress_function * progr_fun) +{ + return mailimap_nstring_parse(fd, buffer, index, result, NULL, + progr_rate, progr_fun); +} + +/* + env-reply-to = "(" 1*address ")" / nil +*/ + +static int +mailimap_env_reply_to_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_env_reply_to ** result, + size_t progr_rate, + progress_function * progr_fun) +{ + clist * list; + size_t cur_token; + struct mailimap_env_reply_to * env_reply_to; + int r; + int res; + + cur_token = * index; + list = NULL; + + r = mailimap_address_list_parse(fd, buffer, &cur_token, &list, + progr_rate, progr_fun); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + + env_reply_to = mailimap_env_reply_to_new(list); + if (env_reply_to == NULL) { + res = MAILIMAP_ERROR_MEMORY; + goto free; + } + + * index = cur_token; + * result = env_reply_to; + + return MAILIMAP_NO_ERROR; + + free: + clist_foreach(list, (clist_func) mailimap_address_free, NULL); + clist_free(list); + err: + return res; +} + +/* + env-sender = "(" 1*address ")" / nil +*/ + + +static int +mailimap_env_sender_parse(mailstream * fd, MMAPString * buffer, + size_t * index, struct mailimap_env_sender ** result, + size_t progr_rate, + progress_function * progr_fun) +{ + clist * list; + size_t cur_token; + struct mailimap_env_sender * env_sender; + int r; + int res; + + cur_token = * index; + list = NULL; + + r = mailimap_address_list_parse(fd, buffer, &cur_token, &list, + progr_rate, progr_fun); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + + env_sender = mailimap_env_sender_new(list); + if (env_sender == NULL) { + res = MAILIMAP_ERROR_MEMORY; + goto free; + } + + * index = cur_token; + * result = env_sender; + + return MAILIMAP_NO_ERROR; + + free: + clist_foreach(list, (clist_func) mailimap_address_free, NULL); + clist_free(list); + err: + return res; +} + + +/* + env-subject = nstring +*/ + +static int mailimap_env_subject_parse(mailstream * fd, MMAPString * buffer, + size_t * index, char ** result, + size_t progr_rate, + progress_function * progr_fun) +{ + return mailimap_nstring_parse(fd, buffer, index, result, NULL, + progr_rate, progr_fun); +} + + +/* + env-to = "(" 1*address ")" / nil +*/ + +static int mailimap_env_to_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_env_to ** result, + size_t progr_rate, + progress_function * progr_fun) +{ + clist * list; + size_t cur_token; + struct mailimap_env_to * env_to; + int r; + int res; + + cur_token = * index; + list = NULL; + + r = mailimap_address_list_parse(fd, buffer, &cur_token, &list, + progr_rate, progr_fun); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + + env_to = mailimap_env_to_new(list); + if (env_to == NULL) { + res = MAILIMAP_ERROR_MEMORY; + goto free; + } + + * index = cur_token; + * result = env_to; + + return MAILIMAP_NO_ERROR; + + free: + clist_foreach(list, (clist_func) mailimap_address_free, NULL); + clist_free(list); + err: + return res; +} + + +/* + UNIMPLEMENTED + examine = "EXAMINE" SP mailbox +*/ + +/* + UNIMPLEMENTED + fetch = "FETCH" SP set SP ("ALL" / "FULL" / "FAST" / fetch-att / + "(" fetch-att *(SP fetch-att) ")") +*/ + +/* + UNIMPLEMENTED + fetch-att = "ENVELOPE" / "FLAGS" / "INTERNALDATE" / + "RFC822" [".HEADER" / ".SIZE" / ".TEXT"] / + "BODY" ["STRUCTURE"] / "UID" / + "BODY" [".PEEK"] section ["<" number "." nz-number ">"] +*/ + +/* + flag = "\Answered" / "\Flagged" / "\Deleted" / + "\Seen" / "\Draft" / flag-keyword / flag-extension + ; Does not include "\Recent" +*/ + +static int mailimap_flag_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_flag ** result, + size_t progr_rate, + progress_function * progr_fun) +{ + struct mailimap_flag * flag; + size_t cur_token; + char * flag_keyword; + char * flag_extension; + int type; + int r; + int res; + + cur_token = * index; + + flag_keyword = NULL; + flag_extension = NULL; + + type = mailimap_flag_get_token_value(fd, buffer, &cur_token); + if (type == -1) { + r = mailimap_flag_keyword_parse(fd, buffer, &cur_token, &flag_keyword, + progr_rate, progr_fun); + if (r == MAILIMAP_NO_ERROR) + type = MAILIMAP_FLAG_KEYWORD; + + if (r == MAILIMAP_ERROR_PARSE) { + r = mailimap_flag_extension_parse(fd, buffer, &cur_token, + &flag_extension, + progr_rate, progr_fun); + type = MAILIMAP_FLAG_EXTENSION; + } + + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + } + + flag = mailimap_flag_new(type, flag_keyword, flag_extension); + if (flag == NULL) { + res = MAILIMAP_ERROR_MEMORY; + goto free; + } + + * result = flag; + * index = cur_token; + + return MAILIMAP_NO_ERROR; + + free: + if (flag_keyword != NULL) + mailimap_flag_keyword_free(flag_keyword); + if (flag_extension != NULL) + mailimap_flag_extension_free(flag_extension); + err: + return res; +} + +/* + flag-extension = "\" atom + ; Future expansion. Client implementations + ; MUST accept flag-extension flags. Server + ; implementations MUST NOT generate + ; flag-extension flags except as defined by + ; future standard or standards-track + ; revisions of this specification. +*/ + +static int mailimap_flag_extension_parse(mailstream * fd, + MMAPString * buffer, + size_t * index, + char ** result, + size_t progr_rate, + progress_function * progr_fun) +{ + size_t cur_token; + char * atom; + int r; + + cur_token = * index; + + r = mailimap_char_parse(fd, buffer, &cur_token, '\\'); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_atom_parse(fd, buffer, &cur_token, &atom, + progr_rate, progr_fun); + if (r != MAILIMAP_NO_ERROR) + return r; + + * result = atom; + * index = cur_token; + + return MAILIMAP_NO_ERROR; +} + +/* + flag-fetch = flag / "\Recent" +*/ + +static int +mailimap_flag_fetch_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_flag_fetch ** result, + size_t progr_rate, + progress_function * progr_fun) +{ + size_t cur_token; + struct mailimap_flag * flag; + struct mailimap_flag_fetch * flag_fetch; + int type; + int r; + int res; + + cur_token = * index; + + flag = NULL; + + type = MAILIMAP_FLAG_FETCH_ERROR; /* XXX - removes a gcc warning */ + + r = mailimap_token_case_insensitive_parse(fd, buffer, &cur_token, + "\\Recent"); + if (r == MAILIMAP_NO_ERROR) + type = MAILIMAP_FLAG_FETCH_RECENT; + + if (r == MAILIMAP_ERROR_PARSE) { + r = mailimap_flag_parse(fd, buffer, &cur_token, &flag, + progr_rate, progr_fun); + if (r == MAILIMAP_NO_ERROR) + type = MAILIMAP_FLAG_FETCH_OTHER; + } + + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + + flag_fetch = mailimap_flag_fetch_new(type, flag); + if (flag_fetch == NULL) { + res = MAILIMAP_ERROR_MEMORY; + goto free; + } + + * index = cur_token; + * result = flag_fetch; + + return MAILIMAP_NO_ERROR; + + free: + if (flag != NULL) + mailimap_flag_free(flag); + err: + return res; +} + +/* + flag-keyword = atom +*/ + +static int mailimap_flag_keyword_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + char ** result, + size_t progr_rate, + progress_function * progr_fun) +{ + return mailimap_atom_parse(fd, buffer, index, result, + progr_rate, progr_fun); +} + +/* + flag-list = "(" [flag *(SP flag)] ")" +*/ + +static int mailimap_flag_list_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_flag_list ** result, + size_t progr_rate, + progress_function * progr_fun) +{ + size_t cur_token; + clist * list; + struct mailimap_flag_list * flag_list; + int r; + int res; + + list = NULL; + cur_token = * index; + + r = mailimap_oparenth_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + + r = mailimap_struct_spaced_list_parse(fd, buffer, &cur_token, &list, + (mailimap_struct_parser *) + mailimap_flag_parse, + (mailimap_struct_destructor *) + mailimap_flag_free, + progr_rate, progr_fun); + + if ((r != MAILIMAP_NO_ERROR) && (r != MAILIMAP_ERROR_PARSE)) { + res = r; + goto err; + } + + r = mailimap_cparenth_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto free; + } + + flag_list = mailimap_flag_list_new(list); + if (flag_list == NULL) { + res = MAILIMAP_ERROR_MEMORY; + goto free; + } + + * result = flag_list; + * index = cur_token; + + return MAILIMAP_NO_ERROR; + + free: + if (list != NULL) { + clist_foreach(list, (clist_func) mailimap_flag_free, NULL); + clist_free(list); + } + err: + return res; +} + +/* + flag-perm = flag / "\*" +*/ + +static int +mailimap_flag_perm_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_flag_perm ** result, + size_t progr_rate, + progress_function * progr_fun) +{ + size_t cur_token; + struct mailimap_flag_perm * flag_perm; + struct mailimap_flag * flag; + int type; + int r; + int res; + + flag = NULL; + cur_token = * index; + type = MAILIMAP_FLAG_PERM_ERROR; /* XXX - removes a gcc warning */ + + r = mailimap_flag_parse(fd, buffer, &cur_token, &flag, + progr_rate, progr_fun); + if (r == MAILIMAP_NO_ERROR) + type = MAILIMAP_FLAG_PERM_FLAG; + + if (r == MAILIMAP_ERROR_PARSE) { + r = mailimap_token_case_insensitive_parse(fd, buffer, + &cur_token, "\\*"); + if (r == MAILIMAP_NO_ERROR) + type = MAILIMAP_FLAG_PERM_ALL; + } + + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + + flag_perm = mailimap_flag_perm_new(type, flag); + if (flag_perm == NULL) { + res = MAILIMAP_ERROR_MEMORY; + goto free; + } + + * result = flag_perm; + * index = cur_token; + + return MAILIMAP_NO_ERROR; + + free: + if (flag != NULL) + mailimap_flag_free(flag); + err: + return res; +} + +/* + greeting = "*" SP (resp-cond-auth / resp-cond-bye) CRLF +*/ + +int mailimap_greeting_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_greeting ** result, + size_t progr_rate, + progress_function * progr_fun) +{ + size_t cur_token; + struct mailimap_resp_cond_auth * resp_cond_auth; + struct mailimap_resp_cond_bye * resp_cond_bye; + struct mailimap_greeting * greeting; + int type; + int r; + int res; + + cur_token = * index; + resp_cond_bye = NULL; + resp_cond_auth = NULL; + + r = mailimap_star_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + + r = mailimap_space_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + + type = MAILIMAP_GREETING_RESP_COND_ERROR; /* XXX - removes a gcc warning */ + + r = mailimap_resp_cond_auth_parse(fd, buffer, &cur_token, &resp_cond_auth, + progr_rate, progr_fun); + if (r == MAILIMAP_NO_ERROR) + type = MAILIMAP_GREETING_RESP_COND_AUTH; + + if (r == MAILIMAP_ERROR_PARSE) { + r = mailimap_resp_cond_bye_parse(fd, buffer, &cur_token, + &resp_cond_bye, + progr_rate, progr_fun); + if (r == MAILIMAP_NO_ERROR) + type = MAILIMAP_GREETING_RESP_COND_BYE; + } + + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + + r = mailimap_crlf_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto free; + } + + greeting = mailimap_greeting_new(type, resp_cond_auth, resp_cond_bye); + if (greeting == NULL) { + res = MAILIMAP_ERROR_MEMORY; + goto free; + } + + * result = greeting; + * index = cur_token; + + return MAILIMAP_NO_ERROR; + + free: + if (resp_cond_auth) + mailimap_resp_cond_auth_free(resp_cond_auth); + if (resp_cond_bye) + mailimap_resp_cond_bye_free(resp_cond_bye); + err: + return res; +} + +/* + header-fld-name = astring +*/ + +static int +mailimap_header_fld_name_parse(mailstream * fd, + MMAPString * buffer, + size_t * index, + char ** result, + size_t progr_rate, + progress_function * progr_fun) +{ + return mailimap_astring_parse(fd, buffer, index, result, + progr_rate, progr_fun); +} + +/* + header-list = "(" header-fld-name *(SP header-fld-name) ")" +*/ + +static int +mailimap_header_list_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_header_list ** result, + size_t progr_rate, + progress_function * progr_fun) +{ + size_t cur_token; + struct mailimap_header_list * header_list; + clist * list; + int r; + int res; + + cur_token = * index; + + list = NULL; + + r = mailimap_oparenth_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + + r = mailimap_struct_spaced_list_parse(fd, buffer, &cur_token, &list, + (mailimap_struct_parser *) + mailimap_header_fld_name_parse, + (mailimap_struct_destructor *) + mailimap_header_fld_name_free, + progr_rate, progr_fun); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + + r = mailimap_cparenth_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto free; + } + + header_list = mailimap_header_list_new(list); + if (header_list == NULL) { + res = MAILIMAP_ERROR_MEMORY; + goto free; + } + + * result = header_list; + * index = cur_token; + + return MAILIMAP_NO_ERROR; + + free: + clist_foreach(list, (clist_func) mailimap_header_fld_name_free, NULL); + clist_free(list); + err: + return res; +} + +/* +UNIMPLEMENTED + list = "LIST" SP mailbox SP list-mailbox + +UNIMPLEMENTED + list-mailbox = 1*list-char / string + +UNIMPLEMENTED + list-char = ATOM-CHAR / list-wildcards / resp-specials +*/ + +/* + list-wildcards = "%" / "*" +*/ + +static int is_list_wildcards(char ch) +{ + switch (ch) { + case '%': + case '*': + return TRUE; + } + return FALSE; +} + + +/* + literal = "{" number "}" CRLF *CHAR8 + ; Number represents the number of CHAR8s +*/ + +static int mailimap_literal_parse(mailstream * fd, MMAPString * buffer, + size_t * index, char ** result, + size_t * result_len, + size_t progr_rate, + progress_function * progr_fun) +{ + size_t cur_token; + uint32_t number; + MMAPString * literal; + char * literal_p; + uint32_t left; + int r; + int res; + size_t number_token; + + cur_token = * index; + + r = mailimap_oaccolade_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + + number_token = cur_token; + + r = mailimap_number_parse(fd, buffer, &cur_token, &number); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + + r = mailimap_caccolade_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + + r = mailimap_crlf_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + + literal = mmap_string_sized_new(number); + /* + literal = g_new(char, number + 1); + */ + if (literal == NULL) { + res = MAILIMAP_ERROR_MEMORY; + goto err; + } + + left = buffer->len - cur_token; + + if (left >= number) { + /* + if (number > 0) + strncpy(literal, buffer->str + cur_token, number); + literal[number] = 0; + */ + if (number > 0) + if (mmap_string_append_len(literal, buffer->str + cur_token, + number) == NULL) { + res = MAILIMAP_ERROR_MEMORY; + goto free_literal; + } + if ((progr_fun != NULL) && (progr_rate != 0)) + progr_fun(number, number); + + cur_token = cur_token + number; + } + else { + uint32_t needed; + uint32_t current_prog = 0; + uint32_t last_prog = 0; + + needed = number - left; + memcpy(literal->str, buffer->str + cur_token, left); + literal->len += left; + literal_p = literal->str + left; + current_prog = left; + + while (needed > 0) { + ssize_t read_bytes; + + read_bytes = mailstream_read(fd, literal_p, needed); + if (read_bytes == -1) { + res = MAILIMAP_ERROR_STREAM; + goto free_literal; + } + literal->len += read_bytes; + needed -= read_bytes; + literal_p += read_bytes; + + current_prog += read_bytes; + if ((progr_fun != NULL) && (progr_rate != 0)) + if (current_prog - last_prog > progr_rate) { + progr_fun(current_prog, number); + last_prog = current_prog; + } + } + + literal->str[number] = 0; + +#if 0 + literal->str[number] = 0; + if (mmap_string_append_len(buffer, literal->str + left, + literal->len - left) == NULL) { + res = MAILIMAP_ERROR_STREAM; + goto free_literal; + } +#endif + + if (mmap_string_truncate(buffer, number_token) == NULL) { + res = MAILIMAP_ERROR_MEMORY; + goto free_literal; + } + + if (mmap_string_append(buffer, "0}\r\n") == NULL) { + res = MAILIMAP_ERROR_MEMORY; + goto free_literal; + } + + cur_token = number_token + 4; + } + if ((progr_fun != NULL) && (progr_rate != 0)) + progr_fun(number, number); + + if (mailstream_read_line_append(fd, buffer) == NULL) { + res = MAILIMAP_ERROR_STREAM; + goto free_literal; + } + + if (mmap_string_ref(literal) < 0) { + res = MAILIMAP_ERROR_MEMORY; + goto free_literal; + } + + * result = literal->str; + if (result_len != NULL) + * result_len = literal->len; + * index = cur_token; + + return MAILIMAP_NO_ERROR; + + free_literal: + mmap_string_free(literal); + err: + return res; +} + +/* + UNIMPLEMENTED + login = "LOGIN" SP userid SP password + + UNIMPLEMENTED + lsub = "LSUB" SP mailbox SP list-mailbox +*/ + +/* + mailbox = "INBOX" / astring + ; INBOX is case-insensitive. All case variants of + ; INBOX (e.g. "iNbOx") MUST be interpreted as INBOX + ; not as an astring. An astring which consists of + ; the case-insensitive sequence "I" "N" "B" "O" "X" + ; is considered to be INBOX and not an astring. + ; Refer to section 5.1 for further + ; semantic details of mailbox names. +*/ + +static int +mailimap_mailbox_parse(mailstream * fd, MMAPString * buffer, + size_t * index, char ** result, + size_t progr_rate, + progress_function * progr_fun) +{ + size_t cur_token; + char * name; + int r; + + cur_token = * index; + + r = mailimap_astring_parse(fd, buffer, &cur_token, &name, + progr_rate, progr_fun); + if (r != MAILIMAP_NO_ERROR) + return r; + + * result = name; + * index = cur_token; + + return MAILIMAP_NO_ERROR; +} + + +/* + mailbox-data = "FLAGS" SP flag-list / "LIST" SP mailbox-list / + "LSUB" SP mailbox-list / "SEARCH" *(SP nz-number) / + "STATUS" SP mailbox SP "(" + [status-att SP number *(SP status-att SP number)] ")" / + number SP "EXISTS" / number SP "RECENT" +*/ + +/* + "FLAGS" SP flag-list +*/ + +static int +mailimap_mailbox_data_flags_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_flag_list ** result, + size_t progr_rate, + progress_function * progr_fun) +{ + size_t cur_token; + struct mailimap_flag_list * flag_list; + int r; + + cur_token = * index; + + r = mailimap_token_case_insensitive_parse(fd, buffer, &cur_token, "FLAGS"); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_space_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_flag_list_parse(fd, buffer, &cur_token, &flag_list, + progr_rate, progr_fun); + if (r != MAILIMAP_NO_ERROR) + return r; + + * result = flag_list; + * index = cur_token; + + return MAILIMAP_NO_ERROR; +} + + +/* + "LIST" SP mailbox-list +*/ + +static int +mailimap_mailbox_data_list_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_mailbox_list ** result, + size_t progr_rate, + progress_function * progr_fun) +{ + size_t cur_token; + struct mailimap_mailbox_list * mb_list; + int r; + int res; + + cur_token = * index; + + r = mailimap_token_case_insensitive_parse(fd, buffer, &cur_token, "LIST"); + if (r != MAILIMAP_NO_ERROR) { + res = r; + return r; + } + + r = mailimap_space_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) { + res = r; + return r; + } + + r = mailimap_mailbox_list_parse(fd, buffer, &cur_token, &mb_list, + progr_rate, progr_fun); + if (r != MAILIMAP_NO_ERROR) { + res = r; + return r; + } + + * result = mb_list; + * index = cur_token; + + return MAILIMAP_NO_ERROR; +} + +/* + "LSUB" SP mailbox-list +*/ + +static int +mailimap_mailbox_data_lsub_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_mailbox_list ** result, + size_t progr_rate, + progress_function * progr_fun) +{ + size_t cur_token; + struct mailimap_mailbox_list * mb_list; + int r; + + cur_token = * index; + + r = mailimap_token_case_insensitive_parse(fd, buffer, &cur_token, "LSUB"); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_space_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_mailbox_list_parse(fd, buffer, &cur_token, &mb_list, + progr_rate, progr_fun); + if (r != MAILIMAP_NO_ERROR) + return r; + + * result = mb_list; + * index = cur_token; + + return MAILIMAP_NO_ERROR; +} + +/* + "SEARCH" *(SP nz-number) +*/ + + +static int +mailimap_mailbox_data_search_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + clist ** result, + size_t progr_rate, + progress_function * progr_fun) +{ + size_t cur_token; + size_t final_token; + clist * number_list; + int r; + + cur_token = * index; + + r = mailimap_token_case_insensitive_parse(fd, buffer, + &cur_token, "SEARCH"); + if (r != MAILIMAP_NO_ERROR) + return r; + + final_token = cur_token; + number_list = NULL; + + r = mailimap_space_parse(fd, buffer, &cur_token); + if (r == MAILIMAP_NO_ERROR) { + r = mailimap_struct_spaced_list_parse(fd, buffer, &cur_token, &number_list, + (mailimap_struct_parser *) + mailimap_nz_number_alloc_parse, + (mailimap_struct_destructor *) + mailimap_number_alloc_free, + progr_rate, progr_fun); + if (r == MAILIMAP_NO_ERROR) + final_token = cur_token; + } + + * result = number_list; + * index = final_token; + + return MAILIMAP_NO_ERROR; +} + +/* + "STATUS" SP mailbox SP "(" + [status-att SP number *(SP status-att SP number)] ")" +*/ + +/* + status-att SP number +*/ + +static int +mailimap_status_info_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_status_info ** + result, + size_t progr_rate, + progress_function * progr_fun) +{ + size_t cur_token; + int status_att; + uint32_t value; + struct mailimap_status_info * info; + int r; + + cur_token = * index; + value = 0; + + r = mailimap_status_att_parse(fd, buffer, &cur_token, &status_att); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_space_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_number_parse(fd, buffer, &cur_token, &value); + if (r != MAILIMAP_NO_ERROR) + return r; + + info = mailimap_status_info_new(status_att, value); + if (info == NULL) + return MAILIMAP_ERROR_MEMORY; + + * result = info; + * index = cur_token; + + return MAILIMAP_NO_ERROR; +} + +/* + "STATUS" SP mailbox SP "(" + [status-att SP number *(SP status-att SP number)] ")" +*/ + +static int +mailimap_mailbox_data_status_parse(mailstream * fd, MMAPString * buffer, + size_t * index, struct + mailimap_mailbox_data_status ** result, + size_t progr_rate, + progress_function * progr_fun) +{ + size_t cur_token; + char * mb; + clist * status_info_list; + struct mailimap_mailbox_data_status * data_status; + int r; + int res; + + cur_token = * index; + mb = NULL; + status_info_list = NULL; + + r = mailimap_token_case_insensitive_parse(fd, buffer, &cur_token, "STATUS"); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + + r = mailimap_space_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + + r = mailimap_mailbox_parse(fd, buffer, &cur_token, &mb, + progr_rate, progr_fun); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + + r = mailimap_space_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto mailbox; + } + + r = mailimap_oparenth_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto mailbox; + } + + r = mailimap_struct_spaced_list_parse(fd, buffer, &cur_token, + &status_info_list, + (mailimap_struct_parser *) + mailimap_status_info_parse, + (mailimap_struct_destructor *) + mailimap_status_info_free, + progr_rate, progr_fun); + if ((r != MAILIMAP_NO_ERROR) && (r != MAILIMAP_ERROR_PARSE)) { + res = r; + goto mailbox; + } + + r = mailimap_cparenth_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto status_info_list; + } + + data_status = mailimap_mailbox_data_status_new(mb, status_info_list); + if (data_status == NULL) { + res = MAILIMAP_ERROR_MEMORY; + goto status_info_list; + } + + * result = data_status; + * index = cur_token; + + return MAILIMAP_NO_ERROR; + + status_info_list: + if (status_info_list != NULL) { + clist_foreach(status_info_list, (clist_func) mailimap_status_info_free, + NULL); + clist_free(status_info_list); + } + mailbox: + mailimap_mailbox_free(mb); + err: + return res; +} + +/* + number SP "EXISTS" +*/ + +static int +mailimap_mailbox_data_exists_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + uint32_t * result) +{ + size_t cur_token; + uint32_t number; + int r; + + cur_token = * index; + + r = mailimap_number_parse(fd, buffer, &cur_token, &number); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_space_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_token_case_insensitive_parse(fd, buffer, &cur_token, "EXISTS"); + if (r != MAILIMAP_NO_ERROR) + return r; + + * result = number; + * index = cur_token; + + return MAILIMAP_NO_ERROR; +} + +/* + number SP "RECENT" +*/ + +static int +mailimap_mailbox_data_recent_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + uint32_t * result) +{ + size_t cur_token; + uint32_t number; + int r; + + cur_token = * index; + + r = mailimap_number_parse(fd, buffer, &cur_token, &number); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_space_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_token_case_insensitive_parse(fd, buffer, + &cur_token, "RECENT"); + if (r != MAILIMAP_NO_ERROR) + return r; + + * result = number; + * index = cur_token; + + return MAILIMAP_NO_ERROR; +} + +/* + mailbox-data = "FLAGS" SP flag-list / "LIST" SP mailbox-list / + "LSUB" SP mailbox-list / "SEARCH" *(SP nz-number) / + "STATUS" SP mailbox SP "(" + [status-att SP number *(SP status-att SP number)] ")" / + number SP "EXISTS" / number SP "RECENT" +*/ + +static int +mailimap_mailbox_data_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_mailbox_data ** result, + size_t progr_rate, + progress_function * progr_fun) +{ + int type; + struct mailimap_flag_list * data_flags; + struct mailimap_mailbox_list * data_list; + struct mailimap_mailbox_list * data_lsub; + clist * data_search; + struct mailimap_mailbox_data_status * data_status; + uint32_t data_exists; + uint32_t data_recent; + + struct mailimap_mailbox_data * mailbox_data; + size_t cur_token; + int r; + int res; + + cur_token = * index; + + data_flags = NULL; + data_list = NULL; + data_lsub = NULL; + data_search = NULL; + data_status = NULL; + data_exists = 0; + data_recent = 0; + + type = MAILIMAP_MAILBOX_DATA_ERROR; /* XXX - removes a gcc warning */ + + r = mailimap_mailbox_data_flags_parse(fd, buffer, &cur_token, + &data_flags, + progr_rate, progr_fun); + if (r == MAILIMAP_NO_ERROR) + type = MAILIMAP_MAILBOX_DATA_FLAGS; + + if (r == MAILIMAP_ERROR_PARSE) { + r = mailimap_mailbox_data_list_parse(fd, buffer, &cur_token, + &data_list, + progr_rate, progr_fun); + if (r == MAILIMAP_NO_ERROR) + type = MAILIMAP_MAILBOX_DATA_LIST; + } + + if (r == MAILIMAP_ERROR_PARSE) { + r = mailimap_mailbox_data_lsub_parse(fd, buffer, &cur_token, + &data_lsub, + progr_rate, progr_fun); + if (r == MAILIMAP_NO_ERROR) + type = MAILIMAP_MAILBOX_DATA_LSUB; + } + + if (r == MAILIMAP_ERROR_PARSE) { + r = mailimap_mailbox_data_search_parse(fd, buffer, &cur_token, + &data_search, + progr_rate, progr_fun); + if (r == MAILIMAP_NO_ERROR) + type = MAILIMAP_MAILBOX_DATA_SEARCH; + } + + if (r == MAILIMAP_ERROR_PARSE) { + r = mailimap_mailbox_data_status_parse(fd, buffer, &cur_token, + &data_status, + progr_rate, progr_fun); + if (r == MAILIMAP_NO_ERROR) + type = MAILIMAP_MAILBOX_DATA_STATUS; + } + + if (r == MAILIMAP_ERROR_PARSE) { + r = mailimap_mailbox_data_exists_parse(fd, buffer, &cur_token, + &data_exists); + if (r == MAILIMAP_NO_ERROR) + type = MAILIMAP_MAILBOX_DATA_EXISTS; + } + + if (r == MAILIMAP_ERROR_PARSE) { + r = mailimap_mailbox_data_recent_parse(fd, buffer, &cur_token, + &data_recent); + if (r == MAILIMAP_NO_ERROR) + type = MAILIMAP_MAILBOX_DATA_RECENT; + } + + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + + mailbox_data = mailimap_mailbox_data_new(type, data_flags, data_list, + data_lsub, data_search, + data_status, + data_exists, data_recent); + + if (mailbox_data == NULL) { + res = MAILIMAP_ERROR_MEMORY; + goto free; + } + + * result = mailbox_data; + * index = cur_token; + + return MAILIMAP_NO_ERROR; + + free: + if (data_flags != NULL) + mailimap_flag_list_free(data_flags); + if (data_list != NULL) + mailimap_mailbox_list_free(data_list); + if (data_lsub != NULL) + mailimap_mailbox_list_free(data_lsub); + if (data_search != NULL) + mailimap_mailbox_data_search_free(data_search); + if (data_status != NULL) + mailimap_mailbox_data_status_free(data_status); + err: + return res; +} + +/* + mailbox-list = "(" [mbx-list-flags] ")" SP + (DQUOTE QUOTED-CHAR DQUOTE / nil) SP mailbox +*/ + +/* + DQUOTE QUOTED-CHAR DQUOTE +*/ + +static int +mailimap_mailbox_list_quoted_char_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + char * result) +{ + size_t cur_token; + char ch; + int r; + + cur_token = * index; + + r = mailimap_dquote_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_quoted_char_parse(fd, buffer, &cur_token, &ch); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_dquote_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) + return r; + + * index = cur_token; + * result = ch; + + return MAILIMAP_NO_ERROR; +} + +static int +mailimap_mailbox_list_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_mailbox_list ** result, + size_t progr_rate, + progress_function * progr_fun) +{ + struct mailimap_mailbox_list * mb_list; + struct mailimap_mbx_list_flags * mb_flag_list; + char ch; + char * mb; + size_t cur_token; + int r; + int res; + + cur_token = * index; + + r = mailimap_oparenth_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + + mb_flag_list = NULL; + ch = 0; + mb = NULL; + + r = mailimap_mbx_list_flags_parse(fd, buffer, &cur_token, + &mb_flag_list, progr_rate, progr_fun); + if ((r != MAILIMAP_NO_ERROR) && (r != MAILIMAP_ERROR_PARSE)) { + res = r; + goto err; + } + + r = mailimap_cparenth_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto free_list_flags; + } + + r = mailimap_space_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto free_list_flags; + } + + r = mailimap_mailbox_list_quoted_char_parse(fd, buffer, &cur_token, &ch); + if (r == MAILIMAP_ERROR_PARSE) + r = mailimap_nil_parse(fd, buffer, &cur_token); + + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto free_list_flags; + } + + r = mailimap_space_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto free_list_flags; + } + + r = mailimap_mailbox_parse(fd, buffer, &cur_token, &mb, + progr_rate, progr_fun); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto free_list_flags; + } + + mb_list = mailimap_mailbox_list_new(mb_flag_list, ch, mb); + if (mb_list == NULL) { + res = MAILIMAP_ERROR_MEMORY; + goto free_mailbox; + } + + * result = mb_list; + * index = cur_token; + + return MAILIMAP_NO_ERROR; + + free_mailbox: + mailimap_mailbox_free(mb); + free_list_flags: + if (mb_flag_list != NULL) + mailimap_mbx_list_flags_free(mb_flag_list); + err: + return res; +} + +/* + mbx-list-flags = *(mbx-list-oflag SP) mbx-list-sflag + *(SP mbx-list-oflag) / + mbx-list-oflag *(SP mbx-list-oflag) +*/ + +static int +mailimap_mbx_list_flags_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_mbx_list_flags ** result, + size_t progr_rate, + progress_function * progr_fun) +{ + struct mailimap_mbx_list_flags * mbx_list_flag; + size_t cur_token; + clist * oflags; + clist * oflags_2; + int sflag; + int type; + int r; + int res; + size_t final_token; + int try_sflag; + + cur_token = * index; + final_token = cur_token; + + oflags = clist_new(); + if (oflags == NULL) { + res = MAILIMAP_ERROR_MEMORY; + goto err; + } + + sflag = MAILIMAP_MBX_LIST_SFLAG_ERROR; + oflags_2 = NULL; + + r = mailimap_struct_spaced_list_parse(fd, buffer, &cur_token, + &oflags_2, + (mailimap_struct_parser *) + mailimap_mbx_list_oflag_no_sflag_parse, + (mailimap_struct_destructor *) + mailimap_mbx_list_oflag_free, + progr_rate, progr_fun); + if ((r != MAILIMAP_NO_ERROR) && (r != MAILIMAP_ERROR_PARSE)) { + res = r; + goto free; + } + + try_sflag = 1; + if (r == MAILIMAP_NO_ERROR) { + clist_concat(oflags, oflags_2); + clist_free(oflags_2); + + final_token = cur_token; + try_sflag = 0; + r = mailimap_space_parse(fd, buffer, &cur_token); + if (r == MAILIMAP_NO_ERROR) + try_sflag = 1; + } + + type = MAILIMAP_MBX_LIST_FLAGS_NO_SFLAG; + if (try_sflag) { + r = mailimap_mbx_list_sflag_parse(fd, buffer, &cur_token, &sflag); + switch (r) { + case MAILIMAP_ERROR_PARSE: + type = MAILIMAP_MBX_LIST_FLAGS_NO_SFLAG; + break; + + case MAILIMAP_NO_ERROR: + type = MAILIMAP_MBX_LIST_FLAGS_SFLAG; + + final_token = cur_token; + r = mailimap_space_parse(fd, buffer, &cur_token); + if (r == MAILIMAP_NO_ERROR) { + r = mailimap_struct_spaced_list_parse(fd, buffer, &cur_token, + &oflags_2, + (mailimap_struct_parser *) mailimap_mbx_list_oflag_parse, + (mailimap_struct_destructor *) mailimap_mbx_list_oflag_free, + progr_rate, progr_fun); + if ((r != MAILIMAP_NO_ERROR) && (r != MAILIMAP_ERROR_PARSE)) { + res = r; + goto err; + } + + if (r == MAILIMAP_NO_ERROR) { + clist_concat(oflags, oflags_2); + clist_free(oflags_2); + + final_token = cur_token; + } + } + + break; + + default: + res = r; + goto free; + } + } + + if ((clist_count(oflags) == 0) && (type == MAILIMAP_MBX_LIST_FLAGS_NO_SFLAG)) { + res = MAILIMAP_ERROR_PARSE; + goto free; + } + + cur_token = final_token; + mbx_list_flag = mailimap_mbx_list_flags_new(type, oflags, sflag); + if (mbx_list_flag == NULL) { + res = MAILIMAP_ERROR_MEMORY; + goto free; + } + + * result = mbx_list_flag; + * index = cur_token; + + return MAILIMAP_NO_ERROR; + +free: + clist_foreach(oflags, (clist_func) mailimap_mbx_list_oflag_free, NULL); + clist_free(oflags); +err: + return res; +} + +/* + mbx-list-oflag = "\Noinferiors" / flag-extension + ; Other flags; multiple possible per LIST response +*/ + +static int +mailimap_mbx_list_oflag_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_mbx_list_oflag ** result, + size_t progr_rate, + progress_function * progr_fun) +{ + int type; + size_t cur_token; + struct mailimap_mbx_list_oflag * oflag; + char * flag_ext; + int r; + int res; + int sflag_type; + + cur_token = * index; + flag_ext = NULL; + type = MAILIMAP_MBX_LIST_OFLAG_ERROR; /* XXX - removes a gcc warning */ + + r = mailimap_token_case_insensitive_parse(fd, buffer, &cur_token, + "\\Noinferiors"); + if (r == MAILIMAP_NO_ERROR) + type = MAILIMAP_MBX_LIST_OFLAG_NOINFERIORS; + + if (r == MAILIMAP_ERROR_PARSE) { + r = mailimap_flag_extension_parse(fd, buffer, &cur_token, + &flag_ext, progr_rate, progr_fun); + if (r == MAILIMAP_NO_ERROR) + type = MAILIMAP_MBX_LIST_OFLAG_FLAG_EXT; + } + + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + + oflag = mailimap_mbx_list_oflag_new(type, flag_ext); + if (oflag == NULL) { + res = MAILIMAP_ERROR_MEMORY; + goto free; + } + + * result = oflag; + * index = cur_token; + + return MAILIMAP_NO_ERROR; + + free: + if (flag_ext != NULL) + mailimap_flag_extension_free(flag_ext); + err: + return res; +} + +static int +mailimap_mbx_list_oflag_no_sflag_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_mbx_list_oflag ** result, + size_t progr_rate, + progress_function * progr_fun) +{ + size_t cur_token; + int sflag_type; + int r; + + cur_token = * index; + + r = mailimap_mbx_list_sflag_parse(fd, buffer, &cur_token, &sflag_type); + if (r == MAILIMAP_NO_ERROR) + return MAILIMAP_ERROR_PARSE; + + return mailimap_mbx_list_oflag_parse(fd, buffer, index, result, + progr_rate, progr_fun); +} + + +/* + mbx-list-sflag = "\Noselect" / "\Marked" / "\Unmarked" + ; Selectability flags; only one per LIST response +*/ + +static int +mailimap_mbx_list_sflag_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + int * result) +{ + int type; + size_t cur_token; + + cur_token = * index; + + type = mailimap_mbx_list_sflag_get_token_value(fd, buffer, &cur_token); + if (type == -1) + return MAILIMAP_ERROR_PARSE; + + * result = type; + * index = cur_token; + + return MAILIMAP_NO_ERROR; +} + + +/* + media-basic = ((DQUOTE ("APPLICATION" / "AUDIO" / "IMAGE" / "MESSAGE" / + "VIDEO") DQUOTE) / string) SP media-subtype + ; Defined in [MIME-IMT] +*/ + +/* + DQUOTE ("APPLICATION" / "AUDIO" / "IMAGE" / "MESSAGE" / + "VIDEO") DQUOTE +*/ + +static int +mailimap_media_basic_standard_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + int * result) +{ + size_t cur_token; + int type; + int r; + + cur_token = * index; + + r = mailimap_dquote_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) + return r; + + type = mailimap_media_basic_get_token_value(fd, buffer, &cur_token); + if (type == -1) + return MAILIMAP_ERROR_PARSE; + + r = mailimap_dquote_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) + return FALSE; + + * index = cur_token; + * result = type; + + return MAILIMAP_NO_ERROR; +} + +/* + media-basic = ((DQUOTE ("APPLICATION" / "AUDIO" / "IMAGE" / "MESSAGE" / + "VIDEO") DQUOTE) / string) SP media-subtype + ; Defined in [MIME-IMT] +*/ + +static int +mailimap_media_basic_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_media_basic ** result, + size_t progr_rate, + progress_function * progr_fun) +{ + size_t cur_token; + int type; + char * basic_type; + char * subtype; + struct mailimap_media_basic * media_basic; + int r; + int res; + + cur_token = * index; + + basic_type = NULL; + subtype = NULL; + + r = mailimap_media_basic_standard_parse(fd, buffer, &cur_token, + &type); + + if (r == MAILIMAP_ERROR_PARSE) { + r = mailimap_string_parse(fd, buffer, &cur_token, &basic_type, NULL, + progr_rate, progr_fun); + if (r == MAILIMAP_NO_ERROR) + type = MAILIMAP_MEDIA_BASIC_OTHER; + } + + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + + r = mailimap_space_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto free_basic_type; + } + + r = mailimap_media_subtype_parse(fd, buffer, &cur_token, &subtype, + progr_rate, progr_fun); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto free_basic_type; + } + + media_basic = mailimap_media_basic_new(type, basic_type, subtype); + if (media_basic == NULL) { + res = MAILIMAP_ERROR_MEMORY; + goto free_subtype; + } + + * result = media_basic; + * index = cur_token; + + return MAILIMAP_NO_ERROR; + + free_subtype: + mailimap_media_subtype_free(subtype); + free_basic_type: + if (basic_type != NULL) + mailimap_string_free(basic_type); + err: + return res; +} + + +/* + media-message = DQUOTE "MESSAGE" DQUOTE SP DQUOTE "RFC822" DQUOTE + ; Defined in [MIME-IMT] +*/ + +static int +mailimap_media_message_parse(mailstream * fd, MMAPString * buffer, + size_t * index) +{ + size_t cur_token; + int r; + + cur_token = * index; + + r = mailimap_dquote_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_token_case_insensitive_parse(fd, buffer, &cur_token, + "MESSAGE"); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_dquote_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_space_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_dquote_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_token_case_insensitive_parse(fd, buffer, &cur_token, + "RFC822"); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_dquote_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) + return r; + + * index = cur_token; + + return MAILIMAP_NO_ERROR; +} + +/* + media-subtype = string + ; Defined in [MIME-IMT] +*/ + +static int +mailimap_media_subtype_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + char ** result, + size_t progr_rate, + progress_function * progr_fun) +{ + return mailimap_string_parse(fd, buffer, index, result, NULL, + progr_rate, progr_fun); +} + +/* + media-text = DQUOTE "TEXT" DQUOTE SP media-subtype + ; Defined in [MIME-IMT] +*/ + +static int mailimap_media_text_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + char ** result, + size_t progr_rate, + progress_function * progr_fun) +{ + size_t cur_token; + char * media_subtype; + int r; + + cur_token = * index; + + r = mailimap_dquote_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_token_case_insensitive_parse(fd, buffer, &cur_token, + "TEXT"); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_dquote_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_space_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_media_subtype_parse(fd, buffer, &cur_token, &media_subtype, + progr_rate, progr_fun); + if (r != MAILIMAP_NO_ERROR) + return r; + + * result = media_subtype; + * index = cur_token; + + return MAILIMAP_NO_ERROR; +} + + +/* + message-data = nz-number SP ("EXPUNGE" / ("FETCH" SP msg-att)) +*/ + + +static int +mailimap_message_data_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_message_data ** result, + size_t progr_rate, + progress_function * progr_fun) +{ + size_t cur_token; + uint32_t number; + int type; + struct mailimap_msg_att * msg_att; + struct mailimap_message_data * msg_data; + int r; + int res; + + cur_token = * index; + msg_att = NULL; + + r = mailimap_nz_number_parse(fd, buffer, &cur_token, &number); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + + r = mailimap_space_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + + type = MAILIMAP_MESSAGE_DATA_ERROR; /* XXX - removes a gcc warning */ + + r = mailimap_token_case_insensitive_parse(fd, buffer, &cur_token, + "EXPUNGE"); + if (r == MAILIMAP_NO_ERROR) + type = MAILIMAP_MESSAGE_DATA_EXPUNGE; + + if (r == MAILIMAP_ERROR_PARSE) { + r = mailimap_token_case_insensitive_parse(fd, buffer, &cur_token, + "FETCH"); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + + r = mailimap_space_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + + r = mailimap_msg_att_parse(fd, buffer, &cur_token, &msg_att, + progr_rate, progr_fun); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + + type = MAILIMAP_MESSAGE_DATA_FETCH; + } + + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + + msg_data = mailimap_message_data_new(number, type, msg_att); + if (msg_data == NULL) { + res = MAILIMAP_ERROR_MEMORY; + goto free_msg_att; + } + + * result = msg_data; + * index = cur_token; + + return MAILIMAP_NO_ERROR; + + free_msg_att: + if (msg_att != NULL) + mailimap_msg_att_free(msg_att); + err: + return res; +} + +/* + msg-att = "(" (msg-att-dynamic / msg-att-static) + *(SP (msg-att-dynamic / msg-att-static)) ")" +*/ + +/* + msg-att-dynamic / msg-att-static +*/ + +static int +mailimap_msg_att_item_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_msg_att_item ** result, + size_t progr_rate, + progress_function * progr_fun) +{ + int type; + struct mailimap_msg_att_dynamic * msg_att_dynamic; + struct mailimap_msg_att_static * msg_att_static; + size_t cur_token; + struct mailimap_msg_att_item * item; + int r; + int res; + + cur_token = * index; + + msg_att_dynamic = NULL; + msg_att_static = NULL; + + type = MAILIMAP_MSG_ATT_ITEM_ERROR; /* XXX - removes a gcc warning */ + + r = mailimap_msg_att_dynamic_parse(fd, buffer, &cur_token, + &msg_att_dynamic, + progr_rate, progr_fun); + if (r == MAILIMAP_NO_ERROR) + type = MAILIMAP_MSG_ATT_ITEM_DYNAMIC; + + if (r == MAILIMAP_ERROR_PARSE) { + r = mailimap_msg_att_static_parse(fd, buffer, &cur_token, + &msg_att_static, + progr_rate, progr_fun); + if (r == MAILIMAP_NO_ERROR) + type = MAILIMAP_MSG_ATT_ITEM_STATIC; + } + + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + + item = mailimap_msg_att_item_new(type, msg_att_dynamic, msg_att_static); + if (item == NULL) { + res = MAILIMAP_ERROR_MEMORY; + goto free; + } + + * result = item; + * index = cur_token; + + return MAILIMAP_NO_ERROR; + + free: + if (msg_att_dynamic != NULL) + mailimap_msg_att_dynamic_free(msg_att_dynamic); + if (msg_att_static != NULL) + mailimap_msg_att_static_free(msg_att_static); + err: + return res; +} + +/* + msg-att = "(" (msg-att-dynamic / msg-att-static) + *(SP (msg-att-dynamic / msg-att-static)) ")" +*/ + +static int +mailimap_msg_att_parse(mailstream * fd, MMAPString * buffer, + size_t * index, struct mailimap_msg_att ** result, + size_t progr_rate, + progress_function * progr_fun) +{ + size_t cur_token; + clist * list; + struct mailimap_msg_att * msg_att; + int r; + int res; + + cur_token = * index; + list = NULL; + + r = mailimap_oparenth_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + + r = mailimap_struct_spaced_list_parse(fd, buffer, &cur_token, &list, + (mailimap_struct_parser *) + mailimap_msg_att_item_parse, + (mailimap_struct_destructor *) + mailimap_msg_att_item_free, + progr_rate, progr_fun); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + + r = mailimap_cparenth_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto free; + } + + msg_att = mailimap_msg_att_new(list); + if (msg_att == NULL) { + res = MAILIMAP_ERROR_MEMORY; + goto free; + } + + * index = cur_token; + * result = msg_att; + + return MAILIMAP_NO_ERROR; + + free: + clist_foreach(list, (clist_func) mailimap_msg_att_item_free, NULL); + clist_free(list); + err: + return res; +} + +/* + msg-att-dynamic = "FLAGS" SP "(" [flag-fetch *(SP flag-fetch)] ")" + ; MAY change for a message +*/ + + +static int +mailimap_msg_att_dynamic_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_msg_att_dynamic ** result, + size_t progr_rate, + progress_function * progr_fun) +{ + clist * list; + struct mailimap_msg_att_dynamic * msg_att_dyn; + size_t cur_token; + int r; + int res; + + cur_token = * index; + + list = NULL; + + r = mailimap_token_case_insensitive_parse(fd, buffer, &cur_token, "FLAGS"); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + + r = mailimap_space_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + + r = mailimap_oparenth_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + + r = mailimap_struct_spaced_list_parse(fd, buffer, &cur_token, + &list, + (mailimap_struct_parser *) + mailimap_flag_fetch_parse, + (mailimap_struct_destructor *) + mailimap_flag_fetch_free, + progr_rate, progr_fun); + if ((r != MAILIMAP_NO_ERROR) && (r != MAILIMAP_ERROR_PARSE)) { + res = r; + goto err; + } + + r = mailimap_cparenth_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto free; + } + + msg_att_dyn = mailimap_msg_att_dynamic_new(list); + if (msg_att_dyn == NULL) { + res = MAILIMAP_ERROR_MEMORY; + goto free; + } + + * result = msg_att_dyn; + * index = cur_token; + + return MAILIMAP_NO_ERROR; + + free: + if (list != NULL) { + clist_foreach(list, (clist_func) mailimap_flag_fetch_free, NULL); + clist_free(list); + } + err: + return res; +} + +/* + msg-att-static = "ENVELOPE" SP envelope / "INTERNALDATE" SP date-time / + "RFC822" [".HEADER" / ".TEXT"] SP nstring / + "RFC822.SIZE" SP number / "BODY" ["STRUCTURE"] SP body / + "BODY" section ["<" number ">"] SP nstring / + "UID" SP uniqueid + ; MUST NOT change for a message +*/ + +/* + "ENVELOPE" SP envelope +*/ + + +static int +mailimap_msg_att_envelope_parse(mailstream * fd, + MMAPString * buffer, + size_t * index, + struct mailimap_envelope ** result, + size_t progr_rate, + progress_function * progr_fun) +{ + size_t cur_token; + struct mailimap_envelope * env; + int r; + + cur_token = * index; + + r = mailimap_token_case_insensitive_parse(fd, buffer, + &cur_token, "ENVELOPE"); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_space_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_envelope_parse(fd, buffer, &cur_token, &env, + progr_rate, progr_fun); + if (r != MAILIMAP_NO_ERROR) + return r; + + * index = cur_token; + * result = env; + + return MAILIMAP_NO_ERROR; +} + + +/* + "INTERNALDATE" SP date-time +*/ + + +static int +mailimap_msg_att_internaldate_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_date_time ** result, + size_t progr_rate, + progress_function * progr_fun) +{ + size_t cur_token; + struct mailimap_date_time * date_time; + int r; + + cur_token = * index; + + r = mailimap_token_case_insensitive_parse(fd, buffer, &cur_token, + "INTERNALDATE"); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_space_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) + return FALSE; + + r = mailimap_date_time_parse(fd, buffer, &cur_token, &date_time, + progr_rate, progr_fun); + if (r != MAILIMAP_NO_ERROR) + return r; + + * result = date_time; + * index = cur_token; + + return MAILIMAP_NO_ERROR; +} + +/* + "RFC822" SP nstring +*/ + +static int +mailimap_msg_att_rfc822_parse(mailstream * fd, MMAPString * buffer, + size_t * index, char ** result, + size_t * result_len, + size_t progr_rate, + progress_function * progr_fun) +{ + size_t cur_token; + char * rfc822_message; + int r; + size_t length; + + cur_token = * index; + + r = mailimap_token_case_insensitive_parse(fd, buffer, &cur_token, + "RFC822"); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_space_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_nstring_parse(fd, buffer, &cur_token, &rfc822_message, &length, + progr_rate, progr_fun); + if (r != MAILIMAP_NO_ERROR) + return r; + + * result = rfc822_message; + if (result_len != NULL) + * result_len = length; + * index = cur_token; + + return MAILIMAP_NO_ERROR; +} + +/* + "RFC822" ".HEADER" SP nstring +*/ + +static int +mailimap_msg_att_rfc822_header_parse(mailstream * fd, MMAPString * buffer, + size_t * index, char ** result, + size_t * result_len, + size_t progr_rate, + progress_function * progr_fun) +{ + size_t cur_token; + char * rfc822_header; + int r; + size_t length; + + cur_token = * index; + + r = mailimap_token_case_insensitive_parse(fd, buffer, &cur_token, + "RFC822"); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_token_case_insensitive_parse(fd, buffer, &cur_token, + ".HEADER"); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_space_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_nstring_parse(fd, buffer, &cur_token, &rfc822_header, &length, + progr_rate, progr_fun); + if (r != MAILIMAP_NO_ERROR) + return r; + + * result = rfc822_header; + if (result_len != NULL) + * result_len = length; + * index = cur_token; + + return MAILIMAP_NO_ERROR; +} + +/* + "RFC822" ".TEXT" SP nstring +*/ + +static int +mailimap_msg_att_rfc822_text_parse(mailstream * fd, MMAPString * buffer, + size_t * index, char ** result, + size_t * result_len, + size_t progr_rate, + progress_function * progr_fun) +{ + size_t cur_token; + char * rfc822_text; + int r; + size_t length; + + cur_token = * index; + + r = mailimap_token_case_insensitive_parse(fd, buffer, &cur_token, + "RFC822"); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_token_case_insensitive_parse(fd, buffer, &cur_token, + ".TEXT"); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_space_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_nstring_parse(fd, buffer, &cur_token, &rfc822_text, &length, + progr_rate, progr_fun); + if (r != MAILIMAP_NO_ERROR) + return r; + + * result = rfc822_text; + if (result_len != NULL) + * result_len = length; + * index = cur_token; + + return MAILIMAP_NO_ERROR; +} + +/* + "RFC822.SIZE" SP number +*/ + +static int +mailimap_msg_att_rfc822_size_parse(mailstream * fd, MMAPString * buffer, + size_t * index, uint32_t * result) +{ + size_t cur_token; + uint32_t number; + int r; + + cur_token = * index; + + r = mailimap_token_case_insensitive_parse(fd, buffer, &cur_token, + "RFC822.SIZE"); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_space_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_number_parse(fd, buffer, &cur_token, &number); + if (r != MAILIMAP_NO_ERROR) + return r; + + * result = number; + * index = cur_token; + + return MAILIMAP_NO_ERROR; +} + +/* + "BODY" SP body +*/ + + +static int +mailimap_msg_att_body_parse(mailstream * fd, MMAPString * buffer, + size_t * index, struct mailimap_body ** result, + size_t progr_rate, + progress_function * progr_fun) +{ + struct mailimap_body * body; + size_t cur_token; + int r; + + cur_token = * index; + + r = mailimap_token_case_insensitive_parse(fd, buffer, &cur_token, + "BODY"); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_space_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_body_parse(fd, buffer, &cur_token, &body, + progr_rate, progr_fun); + if (r != MAILIMAP_NO_ERROR) + return r; + + * result = body; + * index = cur_token; + + return MAILIMAP_NO_ERROR; +} + +/* + "BODY" "STRUCTURE" SP body +*/ + + +static int +mailimap_msg_att_bodystructure_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_body ** result, + size_t progr_rate, + progress_function * progr_fun) +{ + struct mailimap_body * body; + size_t cur_token; + int r; + + cur_token = * index; + + r = mailimap_token_case_insensitive_parse(fd, buffer, &cur_token, + "BODY"); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_token_case_insensitive_parse(fd, buffer, &cur_token, + "STRUCTURE"); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_space_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_body_parse(fd, buffer, &cur_token, &body, + progr_rate, progr_fun); + if (r != MAILIMAP_NO_ERROR) + return r; + + * result = body; + * index = cur_token; + + return MAILIMAP_NO_ERROR; +} + +/* + "BODY" section ["<" number ">"] SP nstring +*/ + +static int +mailimap_msg_att_body_section_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_msg_att_body_section ** + result, + size_t progr_rate, + progress_function * progr_fun) +{ + size_t cur_token; + uint32_t number; + struct mailimap_section * section; + char * body_part; + struct mailimap_msg_att_body_section * msg_att_body_section; + int r; + int res; + size_t length; + + cur_token = * index; + + section = NULL; + number = 0; + body_part = NULL; + + r = mailimap_token_case_insensitive_parse(fd, buffer, &cur_token, + "BODY"); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + + r = mailimap_section_parse(fd, buffer, &cur_token, §ion, + progr_rate, progr_fun); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + + r = mailimap_lower_parse(fd, buffer, &cur_token); + switch (r) { + case MAILIMAP_NO_ERROR: + r = mailimap_number_parse(fd, buffer, &cur_token, &number); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto free_section; + } + + r = mailimap_greater_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto free_section; + } + break; + + case MAILIMAP_ERROR_PARSE: + break; + + default: + return r; + } + + r = mailimap_space_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto free_section; + } + + r = mailimap_nstring_parse(fd, buffer, &cur_token, &body_part, &length, + progr_rate, progr_fun); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto free_section; + } + + msg_att_body_section = + mailimap_msg_att_body_section_new(section, number, body_part, length); + if (msg_att_body_section == NULL) { + res = MAILIMAP_ERROR_MEMORY; + goto free_string; + } + + * result = msg_att_body_section; + * index = cur_token; + + return MAILIMAP_NO_ERROR; + + free_string: + mailimap_nstring_free(body_part); + free_section: + if (section != NULL) + mailimap_section_free(section); + err: + return res; +} + +/* + "UID" SP uniqueid +*/ + +static int +mailimap_msg_att_uid_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + uint32_t * result) +{ + size_t cur_token; + uint32_t uid; + int r; + + cur_token = * index; + + r = mailimap_token_case_insensitive_parse(fd, buffer, &cur_token, "UID"); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_space_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_uniqueid_parse(fd, buffer, &cur_token, &uid); + if (r != MAILIMAP_NO_ERROR) + return r; + + * index = cur_token; + * result = uid; + + return MAILIMAP_NO_ERROR; +} + +/* + msg-att-static = "ENVELOPE" SP envelope / "INTERNALDATE" SP date-time / + "RFC822" [".HEADER" / ".TEXT"] SP nstring / + "RFC822.SIZE" SP number / "BODY" ["STRUCTURE"] SP body / + "BODY" section ["<" number ">"] SP nstring / + "UID" SP uniqueid + ; MUST NOT change for a message +*/ + +static int +mailimap_msg_att_static_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_msg_att_static ** result, + size_t progr_rate, + progress_function * progr_fun) +{ + size_t cur_token; + struct mailimap_envelope * env; + struct mailimap_date_time * internal_date; + char * rfc822; + char * rfc822_header; + char * rfc822_text; + uint32_t rfc822_size; + struct mailimap_body * bodystructure; + struct mailimap_body * body; + struct mailimap_msg_att_body_section * body_section; + uint32_t uid; + struct mailimap_msg_att_static * msg_att_static; + int type; + int r; + int res; + size_t length; + + cur_token = * index; + + env = NULL; + internal_date = NULL; + rfc822 = NULL; + rfc822_header = NULL; + rfc822_text = NULL; + rfc822_size = 0; + length = 0; + bodystructure = NULL; + body = NULL; + body_section = NULL; + uid = 0; + + type = MAILIMAP_MSG_ATT_ERROR; /* XXX - removes a gcc warning */ + + r = mailimap_msg_att_envelope_parse(fd, buffer, &cur_token, &env, + progr_rate, progr_fun); + if (r == MAILIMAP_NO_ERROR) + type = MAILIMAP_MSG_ATT_ENVELOPE; + + if (r == MAILIMAP_ERROR_PARSE) { + r = mailimap_msg_att_internaldate_parse(fd, buffer, &cur_token, + &internal_date, + progr_rate, progr_fun); + if (r == MAILIMAP_NO_ERROR) + type = MAILIMAP_MSG_ATT_INTERNALDATE; + } + + if (r == MAILIMAP_ERROR_PARSE) { + r = mailimap_msg_att_rfc822_parse(fd, buffer, &cur_token, + &rfc822, &length, + progr_rate, progr_fun); + if (r == MAILIMAP_NO_ERROR) + type = MAILIMAP_MSG_ATT_RFC822; + } + + if (r == MAILIMAP_ERROR_PARSE) { + r = mailimap_msg_att_rfc822_header_parse(fd, buffer, &cur_token, + &rfc822_header, &length, + progr_rate, progr_fun); + type = MAILIMAP_MSG_ATT_RFC822_HEADER; + } + + if (r == MAILIMAP_ERROR_PARSE) { + r = mailimap_msg_att_rfc822_text_parse(fd, buffer, &cur_token, + &rfc822_text, &length, + progr_rate, progr_fun); + if (r == MAILIMAP_NO_ERROR) + type = MAILIMAP_MSG_ATT_RFC822_TEXT; + } + + if (r == MAILIMAP_ERROR_PARSE) { + r = mailimap_msg_att_rfc822_size_parse(fd, buffer, &cur_token, + &rfc822_size); + if (r == MAILIMAP_NO_ERROR) + type = MAILIMAP_MSG_ATT_RFC822_SIZE; + } + + if (r == MAILIMAP_ERROR_PARSE) { + r = mailimap_msg_att_body_parse(fd, buffer, &cur_token, + &body, progr_rate, progr_fun); + if (r == MAILIMAP_NO_ERROR) + type = MAILIMAP_MSG_ATT_BODY; + } + + if (r == MAILIMAP_ERROR_PARSE) { + r = mailimap_msg_att_bodystructure_parse(fd, buffer, &cur_token, + &bodystructure, + progr_rate, progr_fun); + if (r == MAILIMAP_NO_ERROR) + type = MAILIMAP_MSG_ATT_BODYSTRUCTURE; + } + + if (r == MAILIMAP_ERROR_PARSE) { + r = mailimap_msg_att_body_section_parse(fd, buffer, &cur_token, + &body_section, + progr_rate, progr_fun); + if (r == MAILIMAP_NO_ERROR) + type = MAILIMAP_MSG_ATT_BODY_SECTION; + } + + if (r == MAILIMAP_ERROR_PARSE) { + r = mailimap_msg_att_uid_parse(fd, buffer, &cur_token, + &uid); + if (r == MAILIMAP_NO_ERROR) + type = MAILIMAP_MSG_ATT_UID; + } + + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + + msg_att_static = mailimap_msg_att_static_new(type, env, internal_date, + rfc822, rfc822_header, + rfc822_text, length, + rfc822_size, bodystructure, + body, body_section, uid); + if (msg_att_static == NULL) { + res = MAILIMAP_ERROR_MEMORY; + goto free; + } + + * result = msg_att_static; + * index = cur_token; + + return MAILIMAP_NO_ERROR; + + free: + if (env) + mailimap_msg_att_envelope_free(env); + if (internal_date) + mailimap_msg_att_internaldate_free(internal_date); + if (rfc822) + mailimap_msg_att_rfc822_free(rfc822); + if (rfc822_header) + mailimap_msg_att_rfc822_header_free(rfc822_header); + if (rfc822_text) + mailimap_msg_att_rfc822_text_free(rfc822_text); + if (bodystructure) + mailimap_msg_att_bodystructure_free(bodystructure); + if (body) + mailimap_msg_att_body_free(body); + if (body_section) + mailimap_msg_att_body_section_free(body_section); + err: + return res; +} + + +/* + nil = "NIL" +*/ + +static int mailimap_nil_parse(mailstream * fd, MMAPString * buffer, + size_t * index) +{ + return mailimap_token_case_insensitive_parse(fd, buffer, index, "NIL"); +} + +/* + nstring = string / nil +*/ + + +static int mailimap_nstring_parse(mailstream * fd, MMAPString * buffer, + size_t * index, char ** result, + size_t * result_len, + size_t progr_rate, + progress_function * progr_fun) +{ + int r; + + r = mailimap_string_parse(fd, buffer, index, result, result_len, + progr_rate, progr_fun); + switch (r) { + case MAILIMAP_NO_ERROR: + return MAILIMAP_NO_ERROR; + + case MAILIMAP_ERROR_PARSE: + r = mailimap_nil_parse(fd, buffer, index); + if (r != MAILIMAP_NO_ERROR) { + return r; + } + + * result = NULL; + if (result_len != NULL) + * result_len = 0; + return MAILIMAP_NO_ERROR; + + default: + return r; + } +} + +/* + number = 1*DIGIT + ; Unsigned 32-bit integer + ; (0 <= n < 4,294,967,296) +*/ + +static int +mailimap_number_parse(mailstream * fd, MMAPString * buffer, + size_t * index, uint32_t * result) +{ + size_t cur_token; + int digit; + uint32_t number; + int parsed; + int r; + + cur_token = * index; + parsed = FALSE; + +#ifdef UNSTRICT_SYNTAX + mailimap_space_parse(fd, buffer, &cur_token); +#endif + + number = 0; + while (1) { + r = mailimap_digit_parse(fd, buffer, &cur_token, &digit); + if (r == MAILIMAP_ERROR_PARSE) + break; + else if (r == MAILIMAP_NO_ERROR) { + number *= 10; + number += digit; + parsed = TRUE; + } + else + return r; + } + + if (!parsed) + return MAILIMAP_ERROR_PARSE; + + * result = number; + * index = cur_token; + + return MAILIMAP_NO_ERROR; +} + +/* + nz-number = digit-nz *DIGIT + ; Non-zero unsigned 32-bit integer + ; (0 < n < 4,294,967,296) +*/ + +static int +mailimap_nz_number_parse(mailstream * fd, MMAPString * buffer, + size_t * index, uint32_t * result) +{ +#ifdef UNSTRICT_SYNTAX + size_t cur_token; + uint32_t number; + int r; + + cur_token = * index; + + r = mailimap_number_parse(fd, buffer, &cur_token, &number); + if (r != MAILIMAP_NO_ERROR) + return r; + + if (number == 0) + return MAILIMAP_ERROR_PARSE; + +#else + size_t cur_token; + int digit; + uint32_t number; + int r; + + cur_token = * index; + + r = mailimap_digit_nz_parse(fd, buffer, &cur_token, &digit); + if (r != MAILIMAP_NO_ERROR) + return r; + + number = digit; + + while (1) { + r = mailimap_digit_parse(fd, buffer, &cur_token, &digit); + if (r == MAILIMAP_ERROR_PARSE) + break; + else if (r == MAILIMAP_NO_ERROR) { + number *= 10; + number += (guint32) digit; + } + else + return r; + } +#endif + + * result = number; + * index = cur_token; + + return MAILIMAP_NO_ERROR; +} + +/* + password = astring +*/ + +/* + quoted = DQUOTE *QUOTED-CHAR DQUOTE +*/ + +static int +mailimap_quoted_parse(mailstream * fd, MMAPString * buffer, + size_t * index, char ** result, + size_t progr_rate, + progress_function * progr_fun) +{ + char ch; + size_t cur_token; + MMAPString * gstr_quoted; + int r; + int res; + + cur_token = * index; + +#ifdef UNSTRICT_SYNTAX + r = mailimap_space_parse(fd, buffer, &cur_token); + if ((r != MAILIMAP_NO_ERROR) && (r != MAILIMAP_ERROR_PARSE)) + return r; +#endif + + r = mailimap_dquote_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + + gstr_quoted = mmap_string_new(""); + if (gstr_quoted == NULL) { + res = MAILIMAP_ERROR_MEMORY; + goto err; + } + + while (1) { + r = mailimap_quoted_char_parse(fd, buffer, &cur_token, &ch); + if (r == MAILIMAP_ERROR_PARSE) + break; + else if (r == MAILIMAP_NO_ERROR) { + if (mmap_string_append_c(gstr_quoted, ch) == NULL) { + res = MAILIMAP_ERROR_MEMORY; + goto free; + } + } + else { + res = r; + goto free; + } + } + + r = mailimap_dquote_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto free; + } + + if (mmap_string_ref(gstr_quoted) < 0) { + res = MAILIMAP_ERROR_MEMORY; + goto free; + } + + * index = cur_token; + * result = gstr_quoted->str; + + return MAILIMAP_NO_ERROR; + + free: + mmap_string_free(gstr_quoted); + err: + return res; +} + +/* + QUOTED-CHAR = / + "\" quoted-specials +*/ + +static int is_quoted_specials(char ch); + +static int +mailimap_quoted_char_parse(mailstream * fd, MMAPString * buffer, + size_t * index, char * result) +{ + size_t cur_token; + int r; + + cur_token = * index; + + if (!is_quoted_specials(buffer->str[cur_token])) { + * result = buffer->str[cur_token]; + cur_token ++; + * index = cur_token; + return MAILIMAP_NO_ERROR; + } + else { + char quoted_special; + + r = mailimap_char_parse(fd, buffer, &cur_token, '\\'); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_quoted_specials_parse(fd, buffer, &cur_token, + "ed_special); + if (r != MAILIMAP_NO_ERROR) + return r; + + * result = quoted_special; + * index = cur_token; + + return MAILIMAP_NO_ERROR; + } +} + +/* + quoted-specials = DQUOTE / "\" +*/ + +static int is_quoted_specials(char ch) +{ + return (ch == '\"') || (ch == '\\'); +} + +static int +mailimap_quoted_specials_parse(mailstream * fd, MMAPString * buffer, + size_t * index, char * result) +{ + size_t cur_token; + + cur_token = * index; + + if (is_quoted_specials(buffer->str[cur_token])) { + * result = buffer->str[cur_token]; + cur_token ++; + * index = cur_token; + return MAILIMAP_NO_ERROR; + } + else + return MAILIMAP_ERROR_PARSE; +} + +/* + UNIMPLEMENTED + rename = "RENAME" SP mailbox SP mailbox + ; Use of INBOX as a destination gives a NO error +*/ + +/* + response = *(continue-req / response-data) response-done +*/ + +/* + continue-req / response-data +*/ + +/* static */ int +mailimap_cont_req_or_resp_data_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_cont_req_or_resp_data ** + result, + size_t progr_rate, + progress_function * progr_fun) +{ + size_t cur_token; + struct mailimap_cont_req_or_resp_data * cont_req_or_resp_data; + struct mailimap_continue_req * cont_req; + struct mailimap_response_data * resp_data; + int type; + int r; + int res; + + cur_token = * index; + + cont_req = NULL; + resp_data = NULL; + type = MAILIMAP_RESP_ERROR; /* XXX - removes a gcc warning */ + + r = mailimap_continue_req_parse(fd, buffer, &cur_token, &cont_req, + progr_rate, progr_fun); + if (r == MAILIMAP_NO_ERROR) + type = MAILIMAP_RESP_CONT_REQ; + + if (r == MAILIMAP_ERROR_PARSE) { + r = mailimap_response_data_parse(fd, buffer, &cur_token, &resp_data, + progr_rate, progr_fun); + if (r == MAILIMAP_NO_ERROR) + type = MAILIMAP_RESP_RESP_DATA; + } + + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + + /* + multi-lines response + read another response line because after that token, + there must have something (continue-req, response-data or response-done) + */ + + if (!mailstream_read_line_append(fd, buffer)) { + res = MAILIMAP_ERROR_STREAM; + goto free; + } + + cont_req_or_resp_data = + mailimap_cont_req_or_resp_data_new(type, cont_req, resp_data); + if (cont_req_or_resp_data == NULL) { + res = MAILIMAP_ERROR_MEMORY; + goto free; + } + + * result = cont_req_or_resp_data; + * index = cur_token; + + return MAILIMAP_NO_ERROR; + + free: + if (cont_req != NULL) + mailimap_continue_req_free(cont_req); + if (resp_data != NULL) + mailimap_response_data_free(resp_data); + err: + return res; +} + +/* + response = *(continue-req / response-data) response-done +*/ + +int +mailimap_response_parse(mailstream * fd, MMAPString * buffer, + size_t * index, struct mailimap_response ** result, + size_t progr_rate, + progress_function * progr_fun) +{ + size_t cur_token; + clist * cont_req_or_resp_data_list; + struct mailimap_response * resp; + struct mailimap_response_done * resp_done; + int r; + int res; + + cur_token = * index; + cont_req_or_resp_data_list = NULL; + resp_done = NULL; + + r = mailimap_struct_multiple_parse(fd, buffer, + &cur_token, &cont_req_or_resp_data_list, + (mailimap_struct_parser *) + mailimap_cont_req_or_resp_data_parse, + (mailimap_struct_destructor *) + mailimap_cont_req_or_resp_data_free, + progr_rate, progr_fun); + + if ((r != MAILIMAP_NO_ERROR) && (r != MAILIMAP_ERROR_PARSE)) + return r; + + r = mailimap_response_done_parse(fd, buffer, &cur_token, &resp_done, + progr_rate, progr_fun); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto free_list; + } + + resp = mailimap_response_new(cont_req_or_resp_data_list, resp_done); + if (resp == NULL) { + res = MAILIMAP_ERROR_MEMORY; + goto free_resp_done; + } + + * result = resp; + * index = cur_token; + + return MAILIMAP_NO_ERROR; + + free_resp_done: + mailimap_response_done_free(resp_done); + free_list: + if (cont_req_or_resp_data_list != NULL) { + clist_foreach(cont_req_or_resp_data_list, + (clist_func) mailimap_cont_req_or_resp_data_free, NULL); + clist_free(cont_req_or_resp_data_list); + } + return res; +} + +/* + response-data = "*" SP (resp-cond-state / resp-cond-bye / + mailbox-data / message-data / capability-data) CRLF +*/ + +static int +mailimap_response_data_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_response_data ** result, + size_t progr_rate, + progress_function * progr_fun) +{ + struct mailimap_response_data * resp_data; + size_t cur_token; + int type; + struct mailimap_resp_cond_state * cond_state; + struct mailimap_resp_cond_bye * cond_bye; + struct mailimap_mailbox_data * mb_data; + struct mailimap_message_data * msg_data; + struct mailimap_capability_data * cap_data; + int r; + int res; + + cond_state = NULL; + cond_bye = NULL; + mb_data = NULL; + msg_data = NULL; + cap_data = NULL; + + cur_token = * index; + + r = mailimap_star_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + + r = mailimap_space_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + + type = MAILIMAP_RESP_DATA_TYPE_ERROR; /* XXX - removes a gcc warning */ + + r = mailimap_resp_cond_state_parse(fd, buffer, &cur_token, &cond_state, + progr_rate, progr_fun); + if (r == MAILIMAP_NO_ERROR) + type = MAILIMAP_RESP_DATA_TYPE_COND_STATE; + + if (r == MAILIMAP_ERROR_PARSE) { + r = mailimap_resp_cond_bye_parse(fd, buffer, &cur_token, &cond_bye, + progr_rate, progr_fun); + if (r == MAILIMAP_NO_ERROR) + type = MAILIMAP_RESP_DATA_TYPE_COND_BYE; + } + + if (r == MAILIMAP_ERROR_PARSE) { + r = mailimap_mailbox_data_parse(fd, buffer, &cur_token, &mb_data, + progr_rate, progr_fun); + if (r == MAILIMAP_NO_ERROR) + type = MAILIMAP_RESP_DATA_TYPE_MAILBOX_DATA; + } + + if (r == MAILIMAP_ERROR_PARSE) { + r = mailimap_message_data_parse(fd, buffer, &cur_token, &msg_data, + progr_rate, progr_fun); + if (r == MAILIMAP_NO_ERROR) + type = MAILIMAP_RESP_DATA_TYPE_MESSAGE_DATA; + } + + if (r == MAILIMAP_ERROR_PARSE) { + r = mailimap_capability_data_parse(fd, buffer, &cur_token, &cap_data, + progr_rate, progr_fun); + if (r == MAILIMAP_NO_ERROR) + type = MAILIMAP_RESP_DATA_TYPE_CAPABILITY_DATA; + } + + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + + r = mailimap_crlf_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto free; + } + + resp_data = mailimap_response_data_new(type, cond_state, + cond_bye, mb_data, + msg_data, cap_data); + if (resp_data == NULL) { + res = MAILIMAP_ERROR_MEMORY; + goto free; + } + + * result = resp_data; + * index = cur_token; + + return MAILIMAP_NO_ERROR; + + free: + if (cond_state) + mailimap_resp_cond_state_free(cond_state); + if (cond_bye) + mailimap_resp_cond_bye_free(cond_bye); + if (mb_data) + mailimap_mailbox_data_free(mb_data); + if (msg_data) + mailimap_message_data_free(msg_data); + if (cap_data) + mailimap_capability_data_free(cap_data); + err: + return res; +} + +/* + response-done = response-tagged / response-fatal +*/ + +static int +mailimap_response_done_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_response_done ** result, + size_t progr_rate, + progress_function * progr_fun) +{ + int type; + struct mailimap_response_done * resp_done; + size_t cur_token; + struct mailimap_response_tagged * tagged; + struct mailimap_response_fatal * fatal; + int r; + int res; + + cur_token = * index; + + tagged = NULL; + fatal = NULL; + + type = MAILIMAP_RESP_DONE_TYPE_ERROR; /* removes a gcc warning */ + + r = mailimap_response_tagged_parse(fd, buffer, &cur_token, &tagged, + progr_rate, progr_fun); + if (r == MAILIMAP_NO_ERROR) + type = MAILIMAP_RESP_DONE_TYPE_TAGGED; + + if (r == MAILIMAP_ERROR_PARSE) { + r = mailimap_response_fatal_parse(fd, buffer, &cur_token, &fatal, + progr_rate, progr_fun); + if (r == MAILIMAP_NO_ERROR) + type = MAILIMAP_RESP_DONE_TYPE_FATAL; + } + + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + + resp_done = mailimap_response_done_new(type, tagged, fatal); + if (resp_done == NULL) { + res = MAILIMAP_ERROR_MEMORY; + goto free; + } + + * result = resp_done; + * index = cur_token; + + return MAILIMAP_NO_ERROR; + + free: + if (tagged == NULL) + mailimap_response_tagged_free(tagged); + if (fatal == NULL) + mailimap_response_fatal_free(fatal); + err: + return res; +} + +/* + response-fatal = "*" SP resp-cond-bye CRLF + ; Server closes connection immediately +*/ + +static int +mailimap_response_fatal_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_response_fatal ** result, + size_t progr_rate, + progress_function * progr_fun) +{ + struct mailimap_resp_cond_bye * cond_bye; + struct mailimap_response_fatal * fatal; + size_t cur_token; + int res; + int r; + + cur_token = * index; + + r = mailimap_star_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + + r = mailimap_space_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + + r = mailimap_resp_cond_bye_parse(fd, buffer, &cur_token, &cond_bye, + progr_rate, progr_fun); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + + r = mailimap_crlf_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto free; + } + + fatal = mailimap_response_fatal_new(cond_bye); + if (fatal == NULL) { + res = MAILIMAP_ERROR_MEMORY; + goto free; + } + + * result = fatal; + * index = cur_token; + + return MAILIMAP_NO_ERROR; + + free: + mailimap_resp_cond_bye_free(cond_bye); + err: + return res; +} + +/* + response-tagged = tag SP resp-cond-state CRLF +*/ + +static int +mailimap_response_tagged_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_response_tagged ** result, + size_t progr_rate, + progress_function * progr_fun) +{ + size_t cur_token; + char * tag; + struct mailimap_resp_cond_state * cond_state; + struct mailimap_response_tagged * resp_tagged; + int r; + int res; + + cur_token = * index; + cond_state = NULL; + + r = mailimap_tag_parse(fd, buffer, &cur_token, &tag, + progr_rate, progr_fun); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + + r = mailimap_space_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto free_tag; + } + + r = mailimap_resp_cond_state_parse(fd, buffer, &cur_token, &cond_state, + progr_rate, progr_fun); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto free_tag; + } + + resp_tagged = mailimap_response_tagged_new(tag, cond_state); + if (resp_tagged == NULL) { + res = MAILIMAP_ERROR_MEMORY; + goto free_cond_state; + } + + * result = resp_tagged; + * index = cur_token; + + return MAILIMAP_NO_ERROR; + + free_cond_state: + mailimap_resp_cond_state_free(cond_state); + free_tag: + mailimap_tag_free(tag); + err: + return res; +} + +/* + resp-cond-auth = ("OK" / "PREAUTH") SP resp-text + ; Authentication condition +*/ + +static int +mailimap_resp_cond_auth_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_resp_cond_auth ** result, + size_t progr_rate, + progress_function * progr_fun) +{ + struct mailimap_resp_cond_auth * cond_auth; + size_t cur_token; + struct mailimap_resp_text * text; + int type; + int r; + int res; + + cur_token = * index; + text = NULL; + + type = MAILIMAP_RESP_COND_AUTH_ERROR; /* XXX - removes a gcc warning */ + + r = mailimap_token_case_insensitive_parse(fd, buffer, &cur_token, "OK"); + if (r == MAILIMAP_NO_ERROR) + type = MAILIMAP_RESP_COND_AUTH_OK; + + if (r == MAILIMAP_ERROR_PARSE) { + r = mailimap_token_case_insensitive_parse(fd, buffer, + &cur_token, "PREAUTH"); + if (r == MAILIMAP_NO_ERROR) + type = MAILIMAP_RESP_COND_AUTH_PREAUTH; + } + + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + + r = mailimap_space_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + + r = mailimap_resp_text_parse(fd, buffer, &cur_token, &text, + progr_rate, progr_fun); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + + cond_auth = mailimap_resp_cond_auth_new(type, text); + if (cond_auth == NULL) { + res = MAILIMAP_ERROR_MEMORY; + goto free; + } + + * result = cond_auth; + * index = cur_token; + + return MAILIMAP_NO_ERROR; + + free: + mailimap_resp_text_free(text); + err: + return res; +} + +/* + resp-cond-bye = "BYE" SP resp-text +*/ + +static int +mailimap_resp_cond_bye_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_resp_cond_bye ** result, + size_t progr_rate, + progress_function * progr_fun) +{ + size_t cur_token; + struct mailimap_resp_cond_bye * cond_bye; + struct mailimap_resp_text * text; + int r; + int res; + + cur_token = * index; + + r = mailimap_token_case_insensitive_parse(fd, buffer, + &cur_token, "BYE"); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + + r = mailimap_space_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + + r = mailimap_resp_text_parse(fd, buffer, &cur_token, &text, + progr_rate, progr_fun); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + + cond_bye = mailimap_resp_cond_bye_new(text); + if (cond_bye == NULL) { + res = MAILIMAP_ERROR_MEMORY; + goto free; + } + + * index = cur_token; + * result = cond_bye; + + return MAILIMAP_NO_ERROR; + + free: + mailimap_resp_text_free(text); + err: + return res; +} + +/* + resp-cond-state = ("OK" / "NO" / "BAD") SP resp-text + ; Status condition +*/ + +static int +mailimap_resp_cond_state_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_resp_cond_state ** result, + size_t progr_rate, + progress_function * progr_fun) +{ + struct mailimap_resp_cond_state * cond_state; + size_t cur_token; + struct mailimap_resp_text * text; + int type; + int r; + int res; + + cur_token = * index; + text = NULL; + + type = mailimap_resp_cond_state_get_token_value(fd, buffer, &cur_token); + if (type == -1) { + res = MAILIMAP_ERROR_PARSE; + goto err; + } + + r = mailimap_space_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + + r = mailimap_resp_text_parse(fd, buffer, &cur_token, &text, + progr_rate, progr_fun); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + + cond_state = mailimap_resp_cond_state_new(type, text); + if (cond_state == NULL) { + res = MAILIMAP_ERROR_MEMORY; + goto free; + } + + * result = cond_state; + * index = cur_token; + + return MAILIMAP_NO_ERROR; + + free: + mailimap_resp_text_free(text); + err: + return res; +} + + +/* + resp-specials = "]" +*/ + +static int is_resp_specials(char ch) +{ + switch (ch) { + case ']': + return TRUE; + }; + return FALSE; +} + +/* + resp-text = ["[" resp-text-code "]" SP] text +*/ + +/* "[" resp-text-code "]" */ + +static int +mailimap_resp_text_resp_text_code_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_resp_text_code ** + result, + size_t progr_rate, + progress_function * progr_fun) +{ + struct mailimap_resp_text_code * text_code; + size_t cur_token; + int r; + int res; + + cur_token = * index; + + r = mailimap_obracket_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + + r = mailimap_resp_text_code_parse(fd, buffer, &cur_token, &text_code, + progr_rate, progr_fun); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + + r = mailimap_cbracket_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto free; + } + + r = mailimap_space_parse(fd, buffer, &cur_token); + if ((r != MAILIMAP_NO_ERROR) && (r != MAILIMAP_ERROR_PARSE)) { + res = r; + goto free; + } + + * result = text_code; + * index = cur_token; + + return MAILIMAP_NO_ERROR; + + free: + mailimap_resp_text_code_free(text_code); + err: + return res; +} + +/* + resp-text = ["[" resp-text-code "]" SP] text +*/ + +static int +mailimap_resp_text_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_resp_text ** result, + size_t progr_rate, + progress_function * progr_fun) +{ + size_t cur_token; + struct mailimap_resp_text_code * text_code; + struct mailimap_resp_text * resp_text; + char * text; + int r; + int res; + + cur_token = * index; + text = NULL; + text_code = NULL; + + r = mailimap_resp_text_resp_text_code_parse(fd, buffer, &cur_token, + &text_code, + progr_rate, progr_fun); + if ((r != MAILIMAP_NO_ERROR) && (r != MAILIMAP_ERROR_PARSE)) + return r; + + r = mailimap_text_parse(fd, buffer, &cur_token, &text, + progr_rate, progr_fun); + if ((r != MAILIMAP_NO_ERROR) && (r != MAILIMAP_ERROR_PARSE)) { + res = r; + goto free_resp_text_code; + } + + resp_text = mailimap_resp_text_new(text_code, text); + if (resp_text == NULL) { + res = MAILIMAP_ERROR_MEMORY; + goto free_text; + } + + * result = resp_text; + * index = cur_token; + + return MAILIMAP_NO_ERROR; + + free_resp_text_code: + if (text_code != NULL) + mailimap_resp_text_code_free(text_code); + free_text: + mailimap_text_free(text); + return res; +} + +/* + resp-text-code = "ALERT" / + "BADCHARSET" [SP "(" astring *(SP astring) ")" ] / + capability-data / "PARSE" / + "PERMANENTFLAGS" SP "(" [flag-perm *(SP flag-perm)] ")" / + "READ-ONLY" / "READ-WRITE" / "TRYCREATE" / + "UIDNEXT" SP nz-number / "UIDVALIDITY" SP nz-number / + "UNSEEN" SP nz-number / + atom [SP 1*] +*/ + +/* + ALERT / PARSE / READ-ONLY / READ-WRITE / TRYCREATE +*/ + +static int +mailimap_resp_text_code_1_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + int * result) +{ + int id; + size_t cur_token; + + cur_token = * index; + + id = mailimap_resp_text_code_1_get_token_value(fd, buffer, &cur_token); + + if (id == -1) + return MAILIMAP_ERROR_PARSE; + + * result = id; + * index = cur_token; + + return MAILIMAP_NO_ERROR; +} + + +/* + "BADCHARSET" [SP "(" astring *(SP astring) ")" ] +*/ + +/* + SP "(" astring *(SP astring) ")" +*/ + +static int +mailimap_resp_text_code_badcharset_1_parse(mailstream * fd, + MMAPString * buffer, + size_t * index, + clist ** result, + size_t progr_rate, + progress_function * progr_fun) +{ + size_t cur_token; + clist * charset; + int r; + int res; + + cur_token = * index; + + r = mailimap_space_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + + r = mailimap_oparenth_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + + r = mailimap_struct_spaced_list_parse(fd, buffer, &cur_token, &charset, + (mailimap_struct_parser *) + mailimap_astring_parse, + (mailimap_struct_destructor *) + mailimap_astring_free, + progr_rate, progr_fun); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + + r = mailimap_cparenth_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto charset; + } + + * index = cur_token; + * result = charset; + + return MAILIMAP_NO_ERROR; + + charset: + clist_foreach(charset, (clist_func) mailimap_string_free, NULL); + clist_free(charset); + err: + return res; +} + +/* + "BADCHARSET" [SP "(" astring *(SP astring) ")" ] +*/ + +static int +mailimap_resp_text_code_badcharset_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + clist ** result, + size_t progr_rate, + progress_function * progr_fun) +{ + size_t cur_token; + clist * charset; + int r; + + cur_token = * index; + + r = mailimap_token_case_insensitive_parse(fd, buffer, &cur_token, + "BADCHARSET"); + if (r != MAILIMAP_NO_ERROR) + return r; + + charset = NULL; + + r = mailimap_resp_text_code_badcharset_1_parse(fd, buffer, &cur_token, + &charset, + progr_rate, progr_fun); + if ((r != MAILIMAP_NO_ERROR) && (r != MAILIMAP_ERROR_PARSE)) + return r; + + * result = charset; + * index = cur_token; + + return MAILIMAP_NO_ERROR; +} + +/* + "PERMANENTFLAGS" SP "(" [flag-perm *(SP flag-perm)] ")" +*/ + +static int +mailimap_resp_text_code_permanentflags_parse(mailstream * fd, + MMAPString * buffer, + size_t * index, + clist ** result, + size_t progr_rate, + progress_function * progr_fun) +{ + size_t cur_token; + clist * flaglist; + int r; + int res; + + cur_token = * index; + + flaglist = NULL; + + r = mailimap_token_case_insensitive_parse(fd, buffer, &cur_token, + "PERMANENTFLAGS"); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + + r = mailimap_space_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + + r = mailimap_oparenth_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + + r = mailimap_struct_spaced_list_parse(fd, buffer, &cur_token, &flaglist, + (mailimap_struct_parser *) + mailimap_flag_perm_parse, + (mailimap_struct_destructor *) + mailimap_flag_perm_free, + progr_rate, progr_fun); + if ((r != MAILIMAP_NO_ERROR) && (r != MAILIMAP_ERROR_PARSE)) { + res = r; + goto err; + } + + r = mailimap_cparenth_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto free; + } + + * index = cur_token; + * result = flaglist; + + return MAILIMAP_NO_ERROR; + + free: + clist_foreach(flaglist, (clist_func) mailimap_flag_perm_free, NULL); + clist_free(flaglist); + err: + return res; +} + + +/* + "UIDNEXT" SP nz-number / + "UIDVALIDITY" SP nz-number / + "UNSEEN" SP nz-number +*/ + +static int +mailimap_resp_text_code_number_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_resp_text_code ** result, + size_t progr_rate, + progress_function * progr_fun) +{ + size_t cur_token; + int type; + uint32_t number; + struct mailimap_resp_text_code * resp_text_code; + int r; + + cur_token = * index; + + resp_text_code = NULL; + + type = mailimap_resp_text_code_2_get_token_value(fd, buffer, &cur_token); + if (type == -1) + return MAILIMAP_ERROR_PARSE; + + r = mailimap_space_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_nz_number_parse(fd, buffer, &cur_token, &number); + if (r != MAILIMAP_NO_ERROR) + return r; + + switch (type) { + case MAILIMAP_RESP_TEXT_CODE_UIDNEXT: + resp_text_code = mailimap_resp_text_code_new(type, NULL, NULL, NULL, + number, 0, 0, NULL , NULL); + break; + case MAILIMAP_RESP_TEXT_CODE_UIDVALIDITY: + resp_text_code = mailimap_resp_text_code_new(type, NULL, NULL, NULL, + 0, number, 0, NULL , NULL); + break; + case MAILIMAP_RESP_TEXT_CODE_UNSEEN: + resp_text_code = mailimap_resp_text_code_new(type, NULL, NULL, NULL, + 0, 0, number, NULL , NULL); + break; + } + + if (resp_text_code == NULL) + return MAILIMAP_ERROR_MEMORY; + + * result = resp_text_code; + * index = cur_token; + + return MAILIMAP_NO_ERROR; +} + +/* + atom [SP 1*] +*/ + +static int is_text_char(char ch); + +/* + any TEXT-CHAR except "]" +*/ + +static int is_text_char_1(char ch) +{ + if (ch == ']') + return FALSE; + return is_text_char(ch); +} + +/* + 1* +*/ + +static int +mailimap_resp_text_code_other_1_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + char ** result, + size_t progr_rate, + progress_function * progr_fun) +{ + size_t cur_token; + char * value; + int r; + + cur_token = * index; + + r = mailimap_space_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_resp_text_code_other_2_parse(fd, buffer, &cur_token, + &value, + progr_rate, progr_fun); + if (r != MAILIMAP_NO_ERROR) + return r; + + * result = value; + * index = cur_token; + + return MAILIMAP_NO_ERROR; +} + +/* + atom [SP 1*] +*/ + +static int +mailimap_resp_text_code_other_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_resp_text_code ** result, + size_t progr_rate, + progress_function * progr_fun) +{ + size_t cur_token; + char * atom; + char * value; + struct mailimap_resp_text_code * resp_text_code; + int r; + int res; + + cur_token = * index; + atom = NULL; + value = NULL; + + r = mailimap_atom_parse(fd, buffer, &cur_token, &atom, + progr_rate, progr_fun); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + + r = mailimap_resp_text_code_other_1_parse(fd, buffer, &cur_token, + &value, progr_rate, progr_fun); + if ((r != MAILIMAP_NO_ERROR) && (r != MAILIMAP_ERROR_PARSE)) { + res = r; + goto err; + } + + resp_text_code = mailimap_resp_text_code_new(MAILIMAP_RESP_TEXT_CODE_OTHER, + NULL, NULL, NULL, + 0, 0, 0, atom, value); + if (resp_text_code == NULL) { + res = MAILIMAP_ERROR_MEMORY; + goto free_value; + } + + * result = resp_text_code; + * index = cur_token; + + return MAILIMAP_NO_ERROR; + + free_value: + if (value != NULL) + free(value); + mailimap_atom_free(atom); + err: + return res; +} + + + +/* + resp-text-code = "ALERT" / + "BADCHARSET" [SP "(" astring *(SP astring) ")" ] / + capability-data / "PARSE" / + "PERMANENTFLAGS" SP "(" [flag-perm *(SP flag-perm)] ")" / + "READ-ONLY" / "READ-WRITE" / "TRYCREATE" / + "UIDNEXT" SP nz-number / "UIDVALIDITY" SP nz-number / + "UNSEEN" SP nz-number / + atom [SP 1*] +*/ + +static int +mailimap_resp_text_code_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_resp_text_code ** result, + size_t progr_rate, + progress_function * progr_fun) +{ + size_t cur_token; + struct mailimap_resp_text_code * resp_text_code; + clist * badcharset; + clist * permanentflags; + struct mailimap_capability_data * cap_data; + int type; + int r; + int res; + + cur_token = * index; + + resp_text_code = NULL; + badcharset = NULL; + cap_data = NULL; + permanentflags = NULL; + + r = mailimap_resp_text_code_1_parse(fd, buffer, &cur_token, &type); + if (r == MAILIMAP_NO_ERROR) { + /* do nothing */ + } + + if (r == MAILIMAP_ERROR_PARSE) { + + r = mailimap_resp_text_code_badcharset_parse(fd, buffer, &cur_token, + &badcharset, + progr_rate, progr_fun); + if (r == MAILIMAP_NO_ERROR) + type = MAILIMAP_RESP_TEXT_CODE_BADCHARSET; + } + + if (r == MAILIMAP_ERROR_PARSE) { + + r = mailimap_capability_data_parse(fd, buffer, &cur_token, + &cap_data, + progr_rate, progr_fun); + if (r == MAILIMAP_NO_ERROR) + type = MAILIMAP_RESP_TEXT_CODE_CAPABILITY_DATA; + } + + if (r == MAILIMAP_ERROR_PARSE) { + r = mailimap_resp_text_code_permanentflags_parse(fd, buffer, &cur_token, + &permanentflags, + progr_rate, + progr_fun); + if (r == MAILIMAP_NO_ERROR) + type = MAILIMAP_RESP_TEXT_CODE_PERMANENTFLAGS; + } + + if (r == MAILIMAP_ERROR_PARSE) { + r = mailimap_resp_text_code_number_parse(fd, buffer, &cur_token, + &resp_text_code, + progr_rate, progr_fun); + } + + if (r == MAILIMAP_ERROR_PARSE) { + r = mailimap_resp_text_code_other_parse(fd, buffer, &cur_token, + &resp_text_code, + progr_rate, progr_fun); + } + + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + + if (resp_text_code == NULL) { + resp_text_code = mailimap_resp_text_code_new(type, + badcharset, cap_data, + permanentflags, + 0, 0, 0, NULL, NULL); + if (resp_text_code == NULL) { + res = MAILIMAP_ERROR_MEMORY; + goto free; + } + } + + * result = resp_text_code; + * index = cur_token; + + return MAILIMAP_NO_ERROR; + +free: + if (permanentflags) { + clist_foreach(permanentflags, + (clist_func) mailimap_flag_perm_free, NULL); + clist_free(permanentflags); + } + if (cap_data) + mailimap_capability_data_free(cap_data); + if (badcharset) { + clist_foreach(badcharset, (clist_func) mailimap_astring_free, NULL); + clist_free(badcharset); + } +err: + return res; +} + +/* + UNIMPLEMENTED + search = "SEARCH" [SP "CHARSET" SP astring] 1*(SP search-key) + ; CHARSET argument to MUST be registered with IANA +*/ + +/* + UNIMPLEMENTED + search-key = "ALL" / "ANSWERED" / "BCC" SP astring / + "BEFORE" SP date / "BODY" SP astring / + "CC" SP astring / "DELETED" / "FLAGGED" / + "FROM" SP astring / "KEYWORD" SP flag-keyword / "NEW" / + "OLD" / "ON" SP date / "RECENT" / "SEEN" / + "SINCE" SP date / "SUBJECT" SP astring / + "TEXT" SP astring / "TO" SP astring / + "UNANSWERED" / "UNDELETED" / "UNFLAGGED" / + "UNKEYWORD" SP flag-keyword / "UNSEEN" / + ; Above this line were in [IMAP2] + "DRAFT" / "HEADER" SP header-fld-name SP astring / + "LARGER" SP number / "NOT" SP search-key / + "OR" SP search-key SP search-key / + "SENTBEFORE" SP date / "SENTON" SP date / + "SENTSINCE" SP date / "SMALLER" SP number / + "UID" SP set / "UNDRAFT" / set / + "(" search-key *(SP search-key) ")" +*/ + +/* + section = "[" [section-spec] "]" +*/ + +static int +mailimap_section_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_section ** result, + size_t progr_rate, + progress_function * progr_fun) +{ + struct mailimap_section_spec * section_spec; + size_t cur_token; + struct mailimap_section * section; + int r; + int res; + + cur_token = * index; + + section_spec = NULL; + + r = mailimap_obracket_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + + r = mailimap_section_spec_parse(fd, buffer, &cur_token, §ion_spec, + progr_rate, progr_fun); + if ((r != MAILIMAP_NO_ERROR) && (r != MAILIMAP_ERROR_PARSE)) { + res = r; + goto err; + } + + r = mailimap_cbracket_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + + if (section_spec == NULL) + section = NULL; + else { + section = mailimap_section_new(section_spec); + if (section == NULL) { + res = MAILIMAP_ERROR_MEMORY; + goto free; + } + } + + * result = section; + * index = cur_token; + + return MAILIMAP_NO_ERROR; + + free: + mailimap_section_spec_free(section_spec); + err: + return res; +} + +/* + section-msgtext = "HEADER" / "HEADER.FIELDS" [".NOT"] SP header-list / + "TEXT" + ; top-level or MESSAGE/RFC822 part +*/ + +static int +mailimap_section_msgtext_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_section_msgtext ** result, + size_t progr_rate, + progress_function * progr_fun) +{ + size_t cur_token; + int type; + struct mailimap_header_list * header_list; + struct mailimap_section_msgtext * msgtext; + int r; + int res; + + cur_token = * index; + + header_list = NULL; + + type = mailimap_section_msgtext_get_token_value(fd, buffer, &cur_token); + if (type == -1) { + res = MAILIMAP_ERROR_PARSE; + goto err; + } + + if (type == MAILIMAP_SECTION_MSGTEXT_HEADER_FIELDS) { + r = mailimap_header_list_parse(fd, buffer, &cur_token, &header_list, + progr_rate, progr_fun); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + } + else if (type == MAILIMAP_SECTION_MSGTEXT_HEADER_FIELDS_NOT) { + r = mailimap_header_list_parse(fd, buffer, &cur_token, &header_list, + progr_rate, progr_fun); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + } + + msgtext = mailimap_section_msgtext_new(type, header_list); + if (msgtext == NULL) { + res = MAILIMAP_ERROR_MEMORY; + goto free_header_list; + } + + * result = msgtext; + * index = cur_token; + + return MAILIMAP_NO_ERROR; + + free_header_list: + if (header_list) + mailimap_header_list_free(header_list); + err: + return res; +} + +/* + section-part = nz-number *("." nz-number) + ; body part nesting +*/ + +static int +mailimap_section_part_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_section_part ** result, + size_t progr_rate, + progress_function * progr_fun) +{ + struct mailimap_section_part * section_part; + size_t cur_token; + clist * section_id; + int r; + int res; + + cur_token = * index; + section_id = NULL; + + r = mailimap_struct_list_parse(fd, buffer, &cur_token, §ion_id, '.', + (mailimap_struct_parser *) + mailimap_nz_number_alloc_parse, + (mailimap_struct_destructor *) + mailimap_number_alloc_free, + progr_rate, progr_fun); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + + section_part = mailimap_section_part_new(section_id); + if (section_part == NULL) { + res = MAILIMAP_ERROR_MEMORY; + goto free_section_id; + } + + * result = section_part; + * index = cur_token; + + return MAILIMAP_NO_ERROR; + + free_section_id: + clist_foreach(section_id, (clist_func) mailimap_number_alloc_free, NULL); + clist_free(section_id); + err: + return res; +} + +/* + section-spec = section-msgtext / (section-part ["." section-text]) +*/ + +static int +mailimap_section_spec_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_section_spec ** result, + size_t progr_rate, + progress_function * progr_fun) +{ + int type; + struct mailimap_section_msgtext * section_msgtext; + struct mailimap_section_part * section_part; + struct mailimap_section_text * section_text; + struct mailimap_section_spec * section_spec; + size_t cur_token; + int r; + int res; + size_t final_token; + + cur_token = * index; + + section_msgtext = NULL; + section_part = NULL; + section_text = NULL; + + r = mailimap_section_msgtext_parse(fd, buffer, &cur_token, + §ion_msgtext, + progr_rate, progr_fun); + switch (r) { + case MAILIMAP_NO_ERROR: + type = MAILIMAP_SECTION_SPEC_SECTION_MSGTEXT; + break; + + case MAILIMAP_ERROR_PARSE: + + r = mailimap_section_part_parse(fd, buffer, &cur_token, + §ion_part, + progr_rate, progr_fun); + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + + final_token = cur_token; + + type = MAILIMAP_SECTION_SPEC_SECTION_PART; + + r = mailimap_dot_parse(fd, buffer, &cur_token); + if (r == MAILIMAP_NO_ERROR) { + r = mailimap_section_text_parse(fd, buffer, &cur_token, §ion_text, + progr_rate, progr_fun); + if (r == MAILIMAP_NO_ERROR) { + final_token = cur_token; + } + else if (r != MAILIMAP_ERROR_PARSE) { + res = r; + goto err; + } + } + else if (r != MAILIMAP_ERROR_PARSE) { + res = r; + goto err; + } + + cur_token = final_token; + break; + + default: + res = r; + goto err; + } + + section_spec = mailimap_section_spec_new(type, section_msgtext, + section_part, section_text); + if (section_spec == NULL) { + res = MAILIMAP_ERROR_MEMORY; + goto free; + } + + * result = section_spec; + * index = cur_token; + + return MAILIMAP_NO_ERROR; + + free: + if (section_msgtext) + mailimap_section_msgtext_free(section_msgtext); + if (section_part) + mailimap_section_part_free(section_part); + if (section_text) + mailimap_section_text_free(section_text); + err: + return res; +} + +/* + section-text = section-msgtext / "MIME" + ; text other than actual body part (headers, etc.) +*/ + +static int +mailimap_section_text_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + struct mailimap_section_text ** result, + size_t progr_rate, + progress_function * progr_fun) +{ + struct mailimap_section_msgtext * section_msgtext; + size_t cur_token; + struct mailimap_section_text * section_text; + int type; + int r; + int res; + + cur_token = * index; + + section_msgtext = NULL; + + type = MAILIMAP_SECTION_TEXT_ERROR; /* XXX - removes a gcc warning */ + + r = mailimap_section_msgtext_parse(fd, buffer, &cur_token, §ion_msgtext, + progr_rate, progr_fun); + if (r == MAILIMAP_NO_ERROR) + type = MAILIMAP_SECTION_TEXT_SECTION_MSGTEXT; + + if (r == MAILIMAP_ERROR_PARSE) { + r= mailimap_token_case_insensitive_parse(fd, buffer, &cur_token, "MIME"); + + if (r == MAILIMAP_NO_ERROR) + type = MAILIMAP_SECTION_TEXT_MIME; + } + + if (r != MAILIMAP_NO_ERROR) { + res = r; + goto err; + } + + section_text = mailimap_section_text_new(type, section_msgtext); + if (section_text == NULL) { + res = MAILIMAP_ERROR_MEMORY; + goto free; + } + + * result = section_text; + * index = cur_token; + + return MAILIMAP_NO_ERROR; + + free: + if (section_msgtext) + mailimap_section_msgtext_free(section_msgtext); + err: + return res; +} + +/* + UNIMPLEMENTED + select = "SELECT" SP mailbox +*/ + +/* + UNIMPLEMENTED + sequence-num = nz-number / "*" + ; * is the largest number in use. For message + ; sequence numbers, it is the number of messages + ; in the mailbox. For unique identifiers, it is + ; the unique identifier of the last message in + ; the mailbox. +*/ + +/* + UNIMPLEMENTED + set = sequence-num / (sequence-num ":" sequence-num) / + (set "," set) + ; Identifies a set of messages. For message + ; sequence numbers, these are consecutive + ; numbers from 1 to the number of messages in + ; the mailbox + ; Comma delimits individual numbers, colon + ; delimits between two numbers inclusive. + ; Example: 2,4:7,9,12:* is 2,4,5,6,7,9,12,13, + ; 14,15 for a mailbox with 15 messages. +*/ + +/* + UNIMPLEMENTED + status = "STATUS" SP mailbox SP "(" status-att *(SP status-att) ")" +*/ + +/* + status-att = "MESSAGES" / "RECENT" / "UIDNEXT" / "UIDVALIDITY" / + "UNSEEN" +*/ + +static int mailimap_status_att_parse(mailstream * fd, MMAPString * buffer, + size_t * index, int * result) +{ + int type; + size_t cur_token; + + cur_token = * index; + + type = mailimap_status_att_get_token_value(fd, buffer, &cur_token); + + if (type == -1) + return MAILIMAP_ERROR_PARSE; + + * result = type; + * index = cur_token; + + return MAILIMAP_NO_ERROR; +} + + +/* + UNIMPLEMENTED + store = "STORE" SP set SP store-att-flags +*/ + +/* + UNIMPLEMENTED + store-att-flags = (["+" / "-"] "FLAGS" [".SILENT"]) SP + (flag-list / (flag *(SP flag))) +*/ + +/* + string = quoted / literal +*/ + +static int +mailimap_string_parse(mailstream * fd, MMAPString * buffer, + size_t * index, char ** result, + size_t * result_len, + size_t progr_rate, + progress_function * progr_fun) +{ + size_t cur_token; + char * string; + int r; + size_t len; + + cur_token = * index; + + r = mailimap_quoted_parse(fd, buffer, &cur_token, &string, + progr_rate, progr_fun); + if (r == MAILIMAP_NO_ERROR) + len = strlen(string); + else if (r == MAILIMAP_ERROR_PARSE) { + r = mailimap_literal_parse(fd, buffer, &cur_token, &string, &len, + progr_rate, progr_fun); + } + + if (r != MAILIMAP_NO_ERROR) + return r; + + * result = string; + if (result_len != NULL) + * result_len = len; + * index = cur_token; + + return MAILIMAP_NO_ERROR; +} + + +/* + UNIMPLEMENTED + subscribe = "SUBSCRIBE" SP mailbox +*/ + +/* + tag = 1* +*/ + +/* + any ASTRING-CHAR except "+" +*/ + +static int is_tag_char(char ch) +{ + if (ch == '+') + return FALSE; + return is_astring_char(ch); +} + +/* + tag = 1* +*/ + +static int mailimap_tag_parse(mailstream * fd, MMAPString * buffer, + size_t * index, char ** result, + size_t progr_rate, + progress_function * progr_fun) +{ + size_t cur_token; + char * tag; + int r; + + cur_token = * index; + + r = mailimap_custom_string_parse(fd, buffer, &cur_token, &tag, + is_tag_char); + if (r != MAILIMAP_NO_ERROR) + return r; + + * index = cur_token; + * result = tag; + + return MAILIMAP_NO_ERROR; +} + +/* + text = 1*TEXT-CHAR +*/ + +static int mailimap_text_parse(mailstream * fd, MMAPString * buffer, + size_t * index, char ** result, + size_t progr_rate, + progress_function * progr_fun) +{ + return mailimap_custom_string_parse(fd, buffer, index, result, + is_text_char); +} + + +/* + TEXT-CHAR = +*/ + +static int is_text_char(char ch) +{ + if ((ch == '\r') || (ch == '\n')) + return FALSE; + + return is_char(ch); +} + +/* + time = 2DIGIT ":" 2DIGIT ":" 2DIGIT + ; Hours minutes seconds +*/ + +/* + 2DIGIT +*/ + +static int mailimap_2digit_parse(mailstream * fd, MMAPString * buffer, + size_t * index, int * result) +{ +#ifndef UNSTRICT_SYNTAX + int digit; + int two_digit; + size_t cur_token; + int r; + + cur_token = * index; + + r = mailimap_digit_parse(fd, buffer, &cur_token, &digit); + if (r != MAILIMAP_NO_ERROR) + return r; + + two_digit = digit; + + r = mailimap_digit_parse(fd, buffer, &cur_token, &digit); + if (r != MAILIMAP_NO_ERROR) + return r; + + two_digit = two_digit * 10 + digit; + + * result = two_digit; + * index = cur_token; + + return MAILIMAP_NO_ERROR; +#else + uint32_t number; + size_t cur_token; + int r; + + cur_token = * index; + + r = mailimap_number_parse(fd, buffer, &cur_token, &number); + if (r != MAILIMAP_NO_ERROR) + return r; + + * index = cur_token; + * result = number; + + return MAILIMAP_NO_ERROR; +#endif +} + +/* + time = 2DIGIT ":" 2DIGIT ":" 2DIGIT + ; Hours minutes seconds +*/ + +static int mailimap_time_parse(mailstream * fd, MMAPString * buffer, + size_t * index, + int * phour, int * pmin, int * psec) +{ + size_t cur_token; + int hour; + int min; + int sec; + int r; + + cur_token = * index; + + r = mailimap_2digit_parse(fd, buffer, &cur_token, &hour); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_colon_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_2digit_parse(fd, buffer, &cur_token, &min); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_colon_parse(fd, buffer, &cur_token); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_2digit_parse(fd, buffer, &cur_token, &sec); + if (r != MAILIMAP_NO_ERROR) + return r; + + * phour = hour; + * pmin = min; + * psec = sec; + * index = cur_token; + + return MAILIMAP_NO_ERROR; +} + +/* + UNIMPLEMENTED + uid = "UID" SP (copy / fetch / search / store) + ; Unique identifiers used instead of message + ; sequence numbers +*/ + +/* + uniqueid = nz-number + ; Strictly ascending +*/ + +static int mailimap_uniqueid_parse(mailstream * fd, MMAPString * buffer, + size_t * index, uint32_t * result) +{ + return mailimap_nz_number_parse(fd, buffer, index, result); +} + +/* + UNIMPLEMENTED + unsubscribe = "UNSUBSCRIBE" SP mailbox +*/ + +/* + UNIMPLEMENTED + userid = astring +*/ + +/* + UNIMPLEMENTED + x-command = "X" atom +*/ + +/* + zone = ("+" / "-") 4DIGIT + ; Signed four-digit value of hhmm representing + ; hours and minutes east of Greenwich (that is, + ; the amount that the given time differs from + ; Universal Time). Subtracting the timezone + ; from the given time will give the UT form. + ; The Universal Time zone is "+0000". +*/ + +static int mailimap_zone_parse(mailstream * fd, MMAPString * buffer, + size_t * index, int * result) +{ + size_t cur_token; + uint32_t zone; +#ifndef UNSTRICT_SYNTAX + int i; + int digit; +#endif + int sign; + int r; + + cur_token = * index; + + sign = 1; + r = mailimap_plus_parse(fd, buffer, &cur_token); + if (r == MAILIMAP_NO_ERROR) + sign = 1; + + if (r == MAILIMAP_ERROR_PARSE) { + r = mailimap_minus_parse(fd, buffer, &cur_token); + if (r == MAILIMAP_NO_ERROR) + sign = -1; + } + + if (r != MAILIMAP_NO_ERROR) + return r; + +#ifdef UNSTRICT_SYNTAX + r = mailimap_number_parse(fd, buffer, &cur_token, &zone); + if (r != MAILIMAP_NO_ERROR) + return r; +#else + zone = 0; + for(i = 0 ; i < 4 ; i ++) { + r = mailimap_digit_parse(fd, buffer, &cur_token, &digit); + if (r != MAILIMAP_NO_ERROR) + return r; + zone = zone * 10 + digit; + } +#endif + + zone *= sign; + + * result = zone; + * index = cur_token; + + return MAILIMAP_NO_ERROR; +} -- cgit v0.9.0.2