summaryrefslogtreecommitdiffabout
path: root/libetpan/src/low-level
authorzautrix <zautrix>2005-03-18 20:17:03 (UTC)
committer zautrix <zautrix>2005-03-18 20:17:03 (UTC)
commit9e549686b23b6dffdcbd09c9b10dc2cb795fbcdf (patch) (side-by-side diff)
tree2528e6cc740225ca0f47d5ac8ff70f7d3bb10621 /libetpan/src/low-level
parent9319998f20f03dcc217fbb39656755dc65226276 (diff)
downloadkdepimpi-9e549686b23b6dffdcbd09c9b10dc2cb795fbcdf.zip
kdepimpi-9e549686b23b6dffdcbd09c9b10dc2cb795fbcdf.tar.gz
kdepimpi-9e549686b23b6dffdcbd09c9b10dc2cb795fbcdf.tar.bz2
Initial revision
Diffstat (limited to 'libetpan/src/low-level') (more/less context) (ignore whitespace changes)
-rw-r--r--libetpan/src/low-level/imap/TODO4
-rw-r--r--libetpan/src/low-level/imap/mailimap.c2164
-rw-r--r--libetpan/src/low-level/imap/mailimap.h598
-rw-r--r--libetpan/src/low-level/imap/mailimap_helper.c205
-rw-r--r--libetpan/src/low-level/imap/mailimap_helper.h66
-rw-r--r--libetpan/src/low-level/imap/mailimap_keywords.c353
-rw-r--r--libetpan/src/low-level/imap/mailimap_keywords.h107
-rw-r--r--libetpan/src/low-level/imap/mailimap_parser.c9506
-rw-r--r--libetpan/src/low-level/imap/mailimap_parser.h69
-rw-r--r--libetpan/src/low-level/imap/mailimap_print.c1615
-rw-r--r--libetpan/src/low-level/imap/mailimap_print.h54
-rw-r--r--libetpan/src/low-level/imap/mailimap_sender.c2742
-rw-r--r--libetpan/src/low-level/imap/mailimap_sender.h164
-rw-r--r--libetpan/src/low-level/imap/mailimap_socket.c73
-rw-r--r--libetpan/src/low-level/imap/mailimap_socket.h54
-rw-r--r--libetpan/src/low-level/imap/mailimap_ssl.c73
-rw-r--r--libetpan/src/low-level/imap/mailimap_ssl.h54
-rw-r--r--libetpan/src/low-level/imap/mailimap_types.c2961
-rw-r--r--libetpan/src/low-level/imap/mailimap_types.h3274
-rw-r--r--libetpan/src/low-level/imap/mailimap_types_helper.c1269
-rw-r--r--libetpan/src/low-level/imap/mailimap_types_helper.h758
-rw-r--r--libetpan/src/low-level/imf/TODO12
-rw-r--r--libetpan/src/low-level/imf/mailimf.c7585
-rw-r--r--libetpan/src/low-level/imf/mailimf.h347
-rw-r--r--libetpan/src/low-level/imf/mailimf_types.c868
-rw-r--r--libetpan/src/low-level/imf/mailimf_types.h793
-rw-r--r--libetpan/src/low-level/imf/mailimf_types_helper.c1636
-rw-r--r--libetpan/src/low-level/imf/mailimf_types_helper.h370
-rw-r--r--libetpan/src/low-level/imf/mailimf_write.c2021
-rw-r--r--libetpan/src/low-level/imf/mailimf_write.h134
-rw-r--r--libetpan/src/low-level/imf/mailimf_write_file.c149
-rw-r--r--libetpan/src/low-level/imf/mailimf_write_file.h169
-rw-r--r--libetpan/src/low-level/imf/mailimf_write_generic.c2028
-rw-r--r--libetpan/src/low-level/imf/mailimf_write_generic.h142
-rw-r--r--libetpan/src/low-level/imf/mailimf_write_mem.c98
-rw-r--r--libetpan/src/low-level/imf/mailimf_write_mem.h135
-rw-r--r--libetpan/src/low-level/maildir/maildir.c798
-rw-r--r--libetpan/src/low-level/maildir/maildir.h67
-rw-r--r--libetpan/src/low-level/maildir/maildir_types.h91
-rw-r--r--libetpan/src/low-level/mbox/TODO0
-rw-r--r--libetpan/src/low-level/mbox/mailmbox.c1525
-rw-r--r--libetpan/src/low-level/mbox/mailmbox.h144
-rw-r--r--libetpan/src/low-level/mbox/mailmbox_parse.c620
-rw-r--r--libetpan/src/low-level/mbox/mailmbox_parse.h56
-rw-r--r--libetpan/src/low-level/mbox/mailmbox_types.c251
-rw-r--r--libetpan/src/low-level/mbox/mailmbox_types.h143
-rw-r--r--libetpan/src/low-level/mh/mailmh.c989
-rw-r--r--libetpan/src/low-level/mh/mailmh.h152
-rw-r--r--libetpan/src/low-level/mime/TODO10
-rw-r--r--libetpan/src/low-level/mime/mailmime.c1408
-rw-r--r--libetpan/src/low-level/mime/mailmime.h102
-rw-r--r--libetpan/src/low-level/mime/mailmime_content.c2381
-rw-r--r--libetpan/src/low-level/mime/mailmime_content.h89
-rw-r--r--libetpan/src/low-level/mime/mailmime_decode.c544
-rw-r--r--libetpan/src/low-level/mime/mailmime_decode.h55
-rw-r--r--libetpan/src/low-level/mime/mailmime_disposition.c595
-rw-r--r--libetpan/src/low-level/mime/mailmime_disposition.h62
-rw-r--r--libetpan/src/low-level/mime/mailmime_types.c753
-rw-r--r--libetpan/src/low-level/mime/mailmime_types.h440
-rw-r--r--libetpan/src/low-level/mime/mailmime_types_helper.c1385
-rw-r--r--libetpan/src/low-level/mime/mailmime_types_helper.h165
-rw-r--r--libetpan/src/low-level/mime/mailmime_write.c1416
-rw-r--r--libetpan/src/low-level/mime/mailmime_write.h73
-rw-r--r--libetpan/src/low-level/mime/mailmime_write_file.c156
-rw-r--r--libetpan/src/low-level/mime/mailmime_write_file.h105
-rw-r--r--libetpan/src/low-level/mime/mailmime_write_generic.c1416
-rw-r--r--libetpan/src/low-level/mime/mailmime_write_generic.h73
-rw-r--r--libetpan/src/low-level/mime/mailmime_write_mem.c106
-rw-r--r--libetpan/src/low-level/mime/mailmime_write_mem.h73
-rw-r--r--libetpan/src/low-level/nntp/newsnntp.c2486
-rw-r--r--libetpan/src/low-level/nntp/newsnntp.h187
-rw-r--r--libetpan/src/low-level/nntp/newsnntp_socket.c74
-rw-r--r--libetpan/src/low-level/nntp/newsnntp_socket.h55
-rw-r--r--libetpan/src/low-level/nntp/newsnntp_ssl.c73
-rw-r--r--libetpan/src/low-level/nntp/newsnntp_ssl.h55
-rw-r--r--libetpan/src/low-level/nntp/newsnntp_types.h144
-rw-r--r--libetpan/src/low-level/pop3/mailpop3.c1230
-rw-r--r--libetpan/src/low-level/pop3/mailpop3.h101
-rw-r--r--libetpan/src/low-level/pop3/mailpop3_helper.c78
-rw-r--r--libetpan/src/low-level/pop3/mailpop3_helper.h64
-rw-r--r--libetpan/src/low-level/pop3/mailpop3_socket.c73
-rw-r--r--libetpan/src/low-level/pop3/mailpop3_socket.h54
-rw-r--r--libetpan/src/low-level/pop3/mailpop3_ssl.c73
-rw-r--r--libetpan/src/low-level/pop3/mailpop3_ssl.h54
-rw-r--r--libetpan/src/low-level/pop3/mailpop3_types.h107
-rw-r--r--libetpan/src/low-level/smtp/TODO1
-rw-r--r--libetpan/src/low-level/smtp/mailsmtp.c984
-rw-r--r--libetpan/src/low-level/smtp/mailsmtp.h94
-rw-r--r--libetpan/src/low-level/smtp/mailsmtp_helper.c228
-rw-r--r--libetpan/src/low-level/smtp/mailsmtp_helper.h74
-rw-r--r--libetpan/src/low-level/smtp/mailsmtp_socket.c99
-rw-r--r--libetpan/src/low-level/smtp/mailsmtp_socket.h56
-rw-r--r--libetpan/src/low-level/smtp/mailsmtp_ssl.c74
-rw-r--r--libetpan/src/low-level/smtp/mailsmtp_ssl.h55
-rw-r--r--libetpan/src/low-level/smtp/mailsmtp_types.h126
95 files changed, 65592 insertions, 0 deletions
diff --git a/libetpan/src/low-level/imap/TODO b/libetpan/src/low-level/imap/TODO
new file mode 100644
index 0000000..a787a3b
--- a/dev/null
+++ b/libetpan/src/low-level/imap/TODO
@@ -0,0 +1,4 @@
+- literal data send progress
+- implement draft-16 (rfc 2822 things)
+- more efficient parser
+
diff --git a/libetpan/src/low-level/imap/mailimap.c b/libetpan/src/low-level/imap/mailimap.c
new file mode 100644
index 0000000..ef38413
--- a/dev/null
+++ b/libetpan/src/low-level/imap/mailimap.c
@@ -0,0 +1,2164 @@
+/*
+ * 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 "mailimap.h"
+#include "mailimap_parser.h"
+#include "mailimap_sender.h"
+#include "mail.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef DEBUG
+#include "mailimap_print.h"
+#endif
+
+/*
+ RFC 2060 : IMAP4rev1
+ draft-crispin-imapv-15
+ RFC 2222 : Simple Authentication and Security Layer
+
+2061 IMAP4 Compatibility with IMAP2bis. M. Crispin. December 1996.
+ (Format: TXT=5867 bytes) (Obsoletes RFC1730) (Status: INFORMATIONAL)
+
+2062 Internet Message Access Protocol - Obsolete Syntax. M. Crispin.
+ December 1996. (Format: TXT=14222 bytes) (Status: INFORMATIONAL)
+
+2086 IMAP4 ACL extension. J. Myers. January 1997. (Format: TXT=13925
+ bytes) (Status: PROPOSED STANDARD)
+
+2087 IMAP4 QUOTA extension. J. Myers. January 1997. (Format: TXT=8542
+ bytes) (Status: PROPOSED STANDARD)
+
+2088 IMAP4 non-synchronizing literals. J. Myers. January 1997.
+ (Format: TXT=4052 bytes) (Status: PROPOSED STANDARD)
+
+2177 IMAP4 IDLE command. B. Leiba. June 1997. (Format: TXT=6770 bytes)
+ (Status: PROPOSED STANDARD)
+
+2180 IMAP4 Multi-Accessed Mailbox Practice. M. Gahrns. July 1997.
+ (Format: TXT=24750 bytes) (Status: INFORMATIONAL)
+
+2192 IMAP URL Scheme. C. Newman. September 1997. (Format: TXT=31426
+ bytes) (Status: PROPOSED STANDARD)
+
+2193 IMAP4 Mailbox Referrals. M. Gahrns. September 1997. (Format:
+ TXT=16248 bytes) (Status: PROPOSED STANDARD)
+
+2195 IMAP/POP AUTHorize Extension for Simple Challenge/Response. J.
+ Klensin, R. Catoe, P. Krumviede. September 1997. (Format: TXT=10468
+ bytes) (Obsoletes RFC2095) (Status: PROPOSED STANDARD)
+
+2221 IMAP4 Login Referrals. M. Gahrns. October 1997. (Format: TXT=9251
+ bytes) (Status: PROPOSED STANDARD)
+
+2342 IMAP4 Namespace. M. Gahrns, C. Newman. May 1998. (Format:
+ TXT=19489 bytes) (Status: PROPOSED STANDARD)
+
+2359 IMAP4 UIDPLUS extension. J. Myers. June 1998. (Format: TXT=10862
+ bytes) (Status: PROPOSED STANDARD)
+
+2595 Using TLS with IMAP, POP3 and ACAP. C. Newman. June 1999.
+ (Format: TXT=32440 bytes) (Status: PROPOSED STANDARD)
+
+2683 IMAP4 Implementation Recommendations. B. Leiba. September 1999.
+ (Format: TXT=56300 bytes) (Status: INFORMATIONAL)
+
+2971 IMAP4 ID extension. T. Showalter. October 2000. (Format:
+ TXT=14670 bytes) (Status: PROPOSED STANDARD)
+
+http://www.ietf.org/ids.by.wg/imapext.html
+*/
+
+static char * read_line(mailimap * session);
+
+static int send_current_tag(mailimap * session);
+
+static int parse_response(mailimap * session,
+ struct mailimap_response ** result);
+
+static int parse_greeting(mailimap * session,
+ struct mailimap_greeting ** result);
+
+
+/* struct mailimap_response_info * */
+
+static void resp_text_store(mailimap * session,
+ struct mailimap_resp_text *
+ resp_text)
+{
+ struct mailimap_resp_text_code * resp_text_code;
+
+ resp_text_code = resp_text->rsp_code;
+
+ if (resp_text_code != NULL) {
+ switch (resp_text_code->rc_type) {
+ case MAILIMAP_RESP_TEXT_CODE_ALERT:
+ if (session->imap_response_info)
+ if (session->imap_response_info->rsp_alert != NULL)
+ free(session->imap_response_info->rsp_alert);
+ session->imap_response_info->rsp_alert = strdup(resp_text->rsp_text);
+ break;
+
+ case MAILIMAP_RESP_TEXT_CODE_BADCHARSET:
+ if (session->imap_response_info) {
+ if (session->imap_response_info->rsp_badcharset != NULL) {
+ clist_foreach(resp_text_code->rc_data.rc_badcharset,
+ (clist_func) mailimap_astring_free, NULL);
+ clist_free(resp_text_code->rc_data.rc_badcharset);
+ }
+ session->imap_response_info->rsp_badcharset =
+ resp_text_code->rc_data.rc_badcharset;
+ resp_text_code->rc_data.rc_badcharset = NULL;
+ }
+ break;
+
+ case MAILIMAP_RESP_TEXT_CODE_CAPABILITY_DATA:
+ if (session->imap_connection_info) {
+ if (session->imap_connection_info->imap_capability != NULL)
+ mailimap_capability_data_free(session->imap_connection_info->imap_capability);
+ session->imap_connection_info->imap_capability =
+ resp_text_code->rc_data.rc_cap_data;
+ /* detach before free */
+ resp_text_code->rc_data.rc_cap_data = NULL;
+ }
+ break;
+
+ case MAILIMAP_RESP_TEXT_CODE_PARSE:
+ if (session->imap_response_info) {
+ if (session->imap_response_info->rsp_parse != NULL)
+ free(session->imap_response_info->rsp_parse);
+ session->imap_response_info->rsp_parse = strdup(resp_text->rsp_text);
+ }
+ break;
+
+ case MAILIMAP_RESP_TEXT_CODE_PERMANENTFLAGS:
+ if (session->imap_selection_info) {
+ if (session->imap_selection_info->sel_perm_flags != NULL) {
+ clist_foreach(session->imap_selection_info->sel_perm_flags,
+ (clist_func) mailimap_flag_perm_free, NULL);
+ clist_free(session->imap_selection_info->sel_perm_flags);
+ }
+ session->imap_selection_info->sel_perm_flags =
+ resp_text_code->rc_data.rc_perm_flags;
+ /* detach before free */
+ resp_text_code->rc_data.rc_perm_flags = NULL;
+ }
+ break;
+
+ case MAILIMAP_RESP_TEXT_CODE_READ_ONLY:
+ if (session->imap_selection_info)
+ session->imap_selection_info->sel_perm = MAILIMAP_MAILBOX_READONLY;
+ break;
+
+ case MAILIMAP_RESP_TEXT_CODE_READ_WRITE:
+ if (session->imap_selection_info)
+ session->imap_selection_info->sel_perm = MAILIMAP_MAILBOX_READWRITE;
+ break;
+
+ case MAILIMAP_RESP_TEXT_CODE_TRY_CREATE:
+ if (session->imap_response_info)
+ session->imap_response_info->rsp_trycreate = TRUE;
+ break;
+
+ case MAILIMAP_RESP_TEXT_CODE_UIDNEXT:
+ if (session->imap_selection_info)
+ session->imap_selection_info->sel_uidnext =
+ resp_text_code->rc_data.rc_uidnext;
+ break;
+
+ case MAILIMAP_RESP_TEXT_CODE_UIDVALIDITY:
+ if (session->imap_selection_info)
+ session->imap_selection_info->sel_uidvalidity =
+ resp_text_code->rc_data.rc_uidvalidity;
+ break;
+
+ case MAILIMAP_RESP_TEXT_CODE_UNSEEN:
+ if (session->imap_selection_info)
+ session->imap_selection_info->sel_first_unseen =
+ resp_text_code->rc_data.rc_first_unseen;
+ break;
+ }
+ }
+}
+
+static void resp_cond_state_store(mailimap * session,
+ struct mailimap_resp_cond_state * resp_cond_state)
+{
+ resp_text_store(session, resp_cond_state->rsp_text);
+}
+
+static void mailbox_data_store(mailimap * session,
+ struct mailimap_mailbox_data * mb_data)
+{
+ int r;
+
+ switch (mb_data->mbd_type) {
+ case MAILIMAP_MAILBOX_DATA_FLAGS:
+ if (session->imap_selection_info) {
+ if (session->imap_selection_info->sel_flags != NULL)
+ mailimap_flag_list_free(session->imap_selection_info->sel_flags);
+ session->imap_selection_info->sel_flags = mb_data->mbd_data.mbd_flags;
+ mb_data->mbd_data.mbd_flags = NULL;
+ }
+ break;
+
+ case MAILIMAP_MAILBOX_DATA_LIST:
+ if (session->imap_response_info) {
+ r = clist_append(session->imap_response_info->rsp_mailbox_list,
+ mb_data->mbd_data.mbd_list);
+ if (r == 0)
+ mb_data->mbd_data.mbd_list = NULL;
+ else {
+ /* TODO must handle error case */
+ }
+ }
+ break;
+
+ case MAILIMAP_MAILBOX_DATA_LSUB:
+ if (session->imap_response_info) {
+ r = clist_append(session->imap_response_info->rsp_mailbox_lsub,
+ mb_data->mbd_data.mbd_lsub);
+ if (r == 0)
+ mb_data->mbd_data.mbd_lsub = NULL;
+ else {
+ /* TODO must handle error case */
+ }
+ }
+ break;
+
+ case MAILIMAP_MAILBOX_DATA_SEARCH:
+ if (session->imap_response_info) {
+ if (session->imap_response_info->rsp_search_result != NULL) {
+ if (mb_data->mbd_data.mbd_search != NULL) {
+ clist_concat(session->imap_response_info->rsp_search_result,
+ mb_data->mbd_data.mbd_search);
+ clist_free(mb_data->mbd_data.mbd_search);
+ mb_data->mbd_data.mbd_search = NULL;
+ }
+ }
+ else {
+ if (mb_data->mbd_data.mbd_search != NULL) {
+ session->imap_response_info->rsp_search_result =
+ mb_data->mbd_data.mbd_search;
+ mb_data->mbd_data.mbd_search = NULL;
+ }
+ }
+ }
+ break;
+
+ case MAILIMAP_MAILBOX_DATA_STATUS:
+ if (session->imap_response_info) {
+ if (session->imap_response_info->rsp_status != NULL)
+ mailimap_mailbox_data_status_free(session->imap_response_info->rsp_status);
+ session->imap_response_info->rsp_status = mb_data->mbd_data.mbd_status;
+#if 0
+ if (session->imap_selection_info != NULL) {
+ clistiter * cur;
+
+ for(cur = clist_begin(mb_data->status->status_info_list)
+ ; cur != NULL ; cur = clist_next(cur)) {
+ struct mailimap_status_info * info;
+
+ info = clist_content(cur);
+ switch (info->att) {
+ case MAILIMAP_STATUS_ATT_MESSAGES:
+ session->imap_selection_info->exists = info->value;
+ break;
+ case MAILIMAP_STATUS_ATT_RECENT:
+ session->imap_selection_info->recent = info->value;
+ break;
+ case MAILIMAP_STATUS_ATT_UIDNEXT:
+ session->imap_selection_info->uidnext = info->value;
+ break;
+ case MAILIMAP_STATUS_ATT_UIDVALIDITY:
+ session->imap_selection_info->uidvalidity = info->value;
+ break;
+ case MAILIMAP_STATUS_ATT_UNSEEN:
+ session->imap_selection_info->unseen = info->value;
+ break;
+ }
+ }
+ }
+#endif
+#if 0
+ mailimap_mailbox_data_status_free(mb_data->status);
+#endif
+ mb_data->mbd_data.mbd_status = NULL;
+ }
+ break;
+
+ case MAILIMAP_MAILBOX_DATA_EXISTS:
+ if (session->imap_selection_info)
+ session->imap_selection_info->sel_exists = mb_data->mbd_data.mbd_exists;
+ break;
+
+ case MAILIMAP_MAILBOX_DATA_RECENT:
+ if (session->imap_selection_info)
+ session->imap_selection_info->sel_recent =
+ mb_data->mbd_data.mbd_recent;
+ break;
+ }
+}
+
+static void
+message_data_store(mailimap * session,
+ struct mailimap_message_data * msg_data)
+{
+ uint32_t * expunged;
+ int r;
+
+ switch (msg_data->mdt_type) {
+ case MAILIMAP_MESSAGE_DATA_EXPUNGE:
+ if (session->imap_response_info) {
+ expunged = mailimap_number_alloc_new(msg_data->mdt_number);
+ if (expunged != NULL) {
+ r = clist_append(session->imap_response_info->rsp_expunged, expunged);
+ if (r == 0) {
+ /* do nothing */
+ }
+ else {
+ /* TODO : must handle error case */
+ mailimap_number_alloc_free(expunged);
+ }
+ if (session->imap_selection_info != NULL)
+ session->imap_selection_info->sel_exists --;
+ }
+ }
+ break;
+
+ case MAILIMAP_MESSAGE_DATA_FETCH:
+ r = clist_append(session->imap_response_info->rsp_fetch_list,
+ msg_data->mdt_msg_att);
+ if (r == 0) {
+ msg_data->mdt_msg_att->att_number = msg_data->mdt_number;
+ msg_data->mdt_msg_att = NULL;
+ }
+ else {
+ /* TODO : must handle error case */
+ }
+ break;
+ }
+}
+
+static void
+cont_req_or_resp_data_store(mailimap * session,
+ struct mailimap_cont_req_or_resp_data * cont_req_or_resp_data)
+{
+ if (cont_req_or_resp_data->rsp_type == MAILIMAP_RESP_RESP_DATA) {
+ struct mailimap_response_data * resp_data;
+
+ resp_data = cont_req_or_resp_data->rsp_data.rsp_resp_data;
+
+ switch (resp_data->rsp_type) {
+ case MAILIMAP_RESP_DATA_TYPE_COND_STATE:
+ resp_cond_state_store(session, resp_data->rsp_data.rsp_cond_state);
+ break;
+ case MAILIMAP_RESP_DATA_TYPE_MAILBOX_DATA:
+ mailbox_data_store(session, resp_data->rsp_data.rsp_mailbox_data);
+ break;
+ case MAILIMAP_RESP_DATA_TYPE_MESSAGE_DATA:
+ message_data_store(session, resp_data->rsp_data.rsp_message_data);
+ break;
+ case MAILIMAP_RESP_DATA_TYPE_CAPABILITY_DATA:
+ if (session->imap_connection_info) {
+ if (session->imap_connection_info->imap_capability != NULL)
+ mailimap_capability_data_free(session->imap_connection_info->imap_capability);
+ session->imap_connection_info->imap_capability = resp_data->rsp_data.rsp_capability_data;
+ resp_data->rsp_data.rsp_capability_data = NULL;
+ }
+ break;
+ }
+ }
+}
+
+static void response_tagged_store(mailimap * session,
+ struct mailimap_response_tagged * tagged)
+{
+ resp_cond_state_store(session, tagged->rsp_cond_state);
+}
+
+static void resp_cond_bye_store(mailimap * session,
+ struct mailimap_resp_cond_bye * resp_cond_bye)
+{
+ resp_text_store(session, resp_cond_bye->rsp_text);
+}
+
+static void response_fatal_store(mailimap * session,
+ struct mailimap_response_fatal * fatal)
+{
+ resp_cond_bye_store(session, fatal->rsp_bye);
+}
+
+static void response_done_store(mailimap * session,
+ struct mailimap_response_done * resp_done)
+{
+ switch(resp_done->rsp_type) {
+ case MAILIMAP_RESP_DONE_TYPE_TAGGED:
+ response_tagged_store(session, resp_done->rsp_data.rsp_tagged);
+ break;
+ case MAILIMAP_RESP_DONE_TYPE_FATAL:
+ response_fatal_store(session, resp_done->rsp_data.rsp_fatal);
+ break;
+ }
+}
+
+static void
+response_store(mailimap * session,
+ struct mailimap_response * response)
+{
+ clistiter * cur;
+
+ if (session->imap_response_info) {
+ mailimap_response_info_free(session->imap_response_info);
+ session->imap_response_info = NULL;
+ }
+
+ session->imap_response_info = mailimap_response_info_new();
+ if (session->imap_response_info == NULL) {
+ /* ignored error */
+ return;
+ }
+
+ if (response->rsp_cont_req_or_resp_data_list != NULL) {
+ for(cur = clist_begin(response->rsp_cont_req_or_resp_data_list) ;
+ cur != NULL ; cur = clist_next(cur)) {
+ struct mailimap_cont_req_or_resp_data * cont_req_or_resp_data;
+
+ cont_req_or_resp_data = clist_content(cur);
+
+ cont_req_or_resp_data_store(session, cont_req_or_resp_data);
+ }
+ }
+
+ response_done_store(session, response->rsp_resp_done);
+}
+
+static void resp_cond_auth_store(mailimap * session,
+ struct mailimap_resp_cond_auth * cond_auth)
+{
+ resp_text_store(session, cond_auth->rsp_text);
+}
+
+static void greeting_store(mailimap * session,
+ struct mailimap_greeting * greeting)
+{
+ switch (greeting->gr_type) {
+ case MAILIMAP_GREETING_RESP_COND_AUTH:
+ resp_cond_auth_store(session, greeting->gr_data.gr_auth);
+ break;
+
+ case MAILIMAP_GREETING_RESP_COND_BYE:
+ resp_cond_bye_store(session, greeting->gr_data.gr_bye);
+ break;
+ }
+}
+
+int mailimap_connect(mailimap * session, mailstream * s)
+{
+ struct mailimap_greeting * greeting;
+ int r;
+ int auth_type;
+ struct mailimap_connection_info * connection_info;
+
+ if (session->imap_state != MAILIMAP_STATE_DISCONNECTED)
+ return MAILIMAP_ERROR_BAD_STATE;
+
+ session->imap_stream = s;
+
+ if (session->imap_connection_info)
+ mailimap_connection_info_free(session->imap_connection_info);
+ connection_info = mailimap_connection_info_new();
+ if (connection_info != NULL)
+ session->imap_connection_info = connection_info;
+
+ if (read_line(session) == NULL) {
+ return MAILIMAP_ERROR_STREAM;
+ }
+
+ r = parse_greeting(session, &greeting);
+ if (r != MAILIMAP_NO_ERROR) {
+ return r;
+ }
+
+ auth_type = greeting->gr_data.gr_auth->rsp_type;
+
+ mailimap_greeting_free(greeting);
+
+ switch (auth_type) {
+ case MAILIMAP_RESP_COND_AUTH_PREAUTH:
+ session->imap_state = MAILIMAP_STATE_AUTHENTICATED;
+ return MAILIMAP_NO_ERROR_AUTHENTICATED;
+ default:
+ session->imap_state = MAILIMAP_STATE_NON_AUTHENTICATED;
+ return MAILIMAP_NO_ERROR_NON_AUTHENTICATED;
+ }
+}
+
+
+
+
+
+
+
+
+/* ********************************************************************** */
+
+
+
+int mailimap_append(mailimap * session, const char * mailbox,
+ struct mailimap_flag_list * flag_list,
+ struct mailimap_date_time * date_time,
+ const char * literal, size_t literal_size)
+{
+ struct mailimap_response * response;
+ int r;
+ int error_code;
+ struct mailimap_continue_req * cont_req;
+ size_t index;
+ size_t fixed_literal_size;
+
+ if ((session->imap_state != MAILIMAP_STATE_AUTHENTICATED) &&
+ (session->imap_state != MAILIMAP_STATE_SELECTED))
+ return MAILIMAP_ERROR_BAD_STATE;
+
+ r = send_current_tag(session);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ fixed_literal_size = mailstream_get_data_crlf_size(literal, literal_size);
+
+ r = mailimap_append_send(session->imap_stream, mailbox, flag_list, date_time,
+ fixed_literal_size);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ if (mailstream_flush(session->imap_stream) == -1)
+ return MAILIMAP_ERROR_STREAM;
+
+ if (read_line(session) == NULL)
+ return MAILIMAP_ERROR_STREAM;
+
+ index = 0;
+
+ r = mailimap_continue_req_parse(session->imap_stream,
+ session->imap_stream_buffer,
+ &index, &cont_req,
+ session->imap_progr_rate, session->imap_progr_fun);
+ if (r == MAILIMAP_NO_ERROR)
+ mailimap_continue_req_free(cont_req);
+
+ if (r == MAILIMAP_ERROR_PARSE) {
+ r = parse_response(session, &response);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ mailimap_response_free(response);
+
+ return MAILIMAP_ERROR_APPEND;
+ }
+
+ r = mailimap_literal_data_send(session->imap_stream, literal, literal_size,
+ session->imap_progr_rate, session->imap_progr_fun);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_crlf_send(session->imap_stream);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ if (mailstream_flush(session->imap_stream) == -1)
+ return MAILIMAP_ERROR_STREAM;
+
+ if (read_line(session) == NULL)
+ return MAILIMAP_ERROR_STREAM;
+
+ r = parse_response(session, &response);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ error_code = response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type;
+
+ mailimap_response_free(response);
+
+ switch (error_code) {
+ case MAILIMAP_RESP_COND_STATE_OK:
+ return MAILIMAP_NO_ERROR;
+
+ default:
+ return MAILIMAP_ERROR_APPEND;
+ }
+}
+
+/*
+gboolean mailimap_authenticate(mailimap * session,
+ gchar * auth_type)
+{
+}
+
+gboolean mailimap_authenticate_resp_send(mailimap * session,
+ gchar * base64)
+{
+}
+*/
+
+int mailimap_noop(mailimap * session)
+{
+ struct mailimap_response * response;
+ int r;
+ int error_code;
+
+ r = send_current_tag(session);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_noop_send(session->imap_stream);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_crlf_send(session->imap_stream);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ if (mailstream_flush(session->imap_stream) == -1)
+ return MAILIMAP_ERROR_STREAM;
+
+ if (read_line(session) == NULL)
+ return MAILIMAP_ERROR_STREAM;
+
+ r = parse_response(session, &response);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ error_code = response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type;
+
+ mailimap_response_free(response);
+
+ switch (error_code) {
+ case MAILIMAP_RESP_COND_STATE_OK:
+ return MAILIMAP_NO_ERROR;
+
+ default:
+ return MAILIMAP_ERROR_NOOP;
+ }
+}
+
+int mailimap_logout(mailimap * session)
+{
+ struct mailimap_response * response;
+ int r;
+ int error_code;
+ int res;
+
+ r = send_current_tag(session);
+ if (r != MAILIMAP_NO_ERROR) {
+ res = r;
+ goto close;
+ }
+
+ r = mailimap_logout_send(session->imap_stream);
+ if (r != MAILIMAP_NO_ERROR) {
+ res = r;
+ goto close;
+ }
+
+ r = mailimap_crlf_send(session->imap_stream);
+ if (r != MAILIMAP_NO_ERROR) {
+ res = r;
+ goto close;
+ }
+
+ if (mailstream_flush(session->imap_stream) == -1) {
+ res = MAILIMAP_ERROR_STREAM;
+ goto close;
+ }
+
+ if (read_line(session) == NULL) {
+ res = MAILIMAP_ERROR_STREAM;
+ goto close;
+ }
+
+ r = parse_response(session, &response);
+ if (r != MAILIMAP_NO_ERROR) {
+ res = r;
+ goto close;
+ }
+
+ error_code = response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type;
+
+ mailimap_response_free(response);
+
+ switch (error_code) {
+ case MAILIMAP_RESP_COND_STATE_OK:
+ if (session->imap_connection_info) {
+ mailimap_connection_info_free(session->imap_connection_info);
+ session->imap_connection_info = NULL;
+ }
+ res = MAILIMAP_NO_ERROR;
+ goto close;
+
+ default:
+ res = MAILIMAP_ERROR_LOGOUT;
+ goto close;
+ }
+
+ close:
+ mailstream_close(session->imap_stream);
+ session->imap_stream = NULL;
+ session->imap_state = MAILIMAP_STATE_DISCONNECTED;
+ return res;
+}
+
+/* send the results back to the caller */
+/* duplicate the result */
+
+static struct mailimap_capability *
+mailimap_capability_dup(struct mailimap_capability * orig_cap)
+{
+ struct mailimap_capability * cap;
+ char * auth_type;
+ char * name;
+
+ name = NULL;
+ auth_type = NULL;
+ switch (orig_cap->cap_type) {
+ case MAILIMAP_CAPABILITY_NAME:
+ name = strdup(orig_cap->cap_data.cap_name);
+ if (name == NULL)
+ goto err;
+ break;
+ case MAILIMAP_CAPABILITY_AUTH_TYPE:
+ auth_type = strdup(orig_cap->cap_data.cap_auth_type);
+ if (auth_type == NULL)
+ goto err;
+ break;
+ }
+
+ cap = mailimap_capability_new(orig_cap->cap_type, auth_type, name);
+ if (cap == NULL)
+ goto free;
+
+ return cap;
+
+ free:
+ if (name != NULL)
+ free(name);
+ if (auth_type != NULL)
+ free(auth_type);
+ err:
+ return NULL;
+}
+
+static struct mailimap_capability_data *
+mailimap_capability_data_dup(struct mailimap_capability_data * orig_cap_data)
+{
+ struct mailimap_capability_data * cap_data;
+ struct mailimap_capability * cap_dup;
+ clist * list;
+ clistiter * cur;
+ int r;
+
+ list = clist_new();
+ if (list == NULL)
+ goto err;
+
+ for(cur = clist_begin(orig_cap_data->cap_list) ;
+ cur != NULL ; cur = clist_next(cur)) {
+ struct mailimap_capability * cap;
+
+ cap = clist_content(cur);
+
+ cap_dup = mailimap_capability_dup(cap);
+ if (cap_dup == NULL)
+ goto list;
+
+ r = clist_append(list, cap_dup);
+ if (r < 0) {
+ mailimap_capability_free(cap_dup);
+ goto list;
+ }
+ }
+
+ cap_data = mailimap_capability_data_new(list);
+ if (cap_data == NULL)
+ goto list;
+
+ return cap_data;
+
+list:
+ clist_foreach(list, (clist_func) mailimap_capability_free, NULL);
+ clist_free(list);
+err:
+ return NULL;
+}
+
+int mailimap_capability(mailimap * session,
+ struct mailimap_capability_data ** result)
+{
+ struct mailimap_response * response;
+ int r;
+ int error_code;
+ struct mailimap_capability_data * cap_data;
+
+ r = send_current_tag(session);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_capability_send(session->imap_stream);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_crlf_send(session->imap_stream);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ if (mailstream_flush(session->imap_stream) == -1)
+ return MAILIMAP_ERROR_STREAM;
+
+ if (read_line(session) == NULL)
+ return MAILIMAP_ERROR_STREAM;
+
+ r = parse_response(session, &response);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ error_code = response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type;
+
+ mailimap_response_free(response);
+
+ switch (error_code) {
+ case MAILIMAP_RESP_COND_STATE_OK:
+ cap_data =
+ mailimap_capability_data_dup(session->imap_connection_info->imap_capability);
+ if (cap_data == NULL)
+ return MAILIMAP_ERROR_MEMORY;
+
+ * result = cap_data;
+
+ return MAILIMAP_NO_ERROR;
+
+ default:
+ return MAILIMAP_ERROR_CAPABILITY;
+ }
+}
+
+int mailimap_check(mailimap * session)
+{
+ struct mailimap_response * response;
+ int r;
+ int error_code;
+
+ if (session->imap_state != MAILIMAP_STATE_SELECTED)
+ return MAILIMAP_ERROR_BAD_STATE;
+
+ r = send_current_tag(session);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_check_send(session->imap_stream);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_crlf_send(session->imap_stream);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ if (mailstream_flush(session->imap_stream) == -1)
+ return MAILIMAP_ERROR_STREAM;
+
+ if (read_line(session) == NULL)
+ return MAILIMAP_ERROR_STREAM;
+
+ r = parse_response(session, &response);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ error_code = response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type;
+
+ mailimap_response_free(response);
+
+ switch (error_code) {
+ case MAILIMAP_RESP_COND_STATE_OK:
+ return MAILIMAP_NO_ERROR;
+
+ default:
+ return MAILIMAP_ERROR_CHECK;
+ }
+}
+
+int mailimap_close(mailimap * session)
+{
+ struct mailimap_response * response;
+ int r;
+ int error_code;
+
+ if (session->imap_state != MAILIMAP_STATE_SELECTED)
+ return MAILIMAP_ERROR_BAD_STATE;
+
+ r = send_current_tag(session);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_close_send(session->imap_stream);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_crlf_send(session->imap_stream);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ if (mailstream_flush(session->imap_stream) == -1)
+ return MAILIMAP_ERROR_STREAM;
+
+ if (read_line(session) == NULL)
+ return MAILIMAP_ERROR_STREAM;
+
+ r = parse_response(session, &response);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ error_code = response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type;
+
+ mailimap_response_free(response);
+
+ switch (error_code) {
+ case MAILIMAP_RESP_COND_STATE_OK:
+ /* leave selected state */
+ mailimap_selection_info_free(session->imap_selection_info);
+ session->imap_selection_info = NULL;
+
+ session->imap_state = MAILIMAP_STATE_AUTHENTICATED;
+ return MAILIMAP_NO_ERROR;
+
+ default:
+ return MAILIMAP_ERROR_CLOSE;
+ }
+}
+
+int mailimap_expunge(mailimap * session)
+{
+ struct mailimap_response * response;
+ int r;
+ int error_code;
+
+ if (session->imap_state != MAILIMAP_STATE_SELECTED)
+ return MAILIMAP_ERROR_BAD_STATE;
+
+ r = send_current_tag(session);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_expunge_send(session->imap_stream);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_crlf_send(session->imap_stream);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ if (mailstream_flush(session->imap_stream) == -1)
+ return MAILIMAP_ERROR_STREAM;
+
+ if (read_line(session) == NULL)
+ return MAILIMAP_ERROR_STREAM;
+
+ r = parse_response(session, &response);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ error_code = response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type;
+
+ mailimap_response_free(response);
+
+ switch (error_code) {
+ case MAILIMAP_RESP_COND_STATE_OK:
+ return MAILIMAP_NO_ERROR;
+
+ default:
+ return MAILIMAP_ERROR_EXPUNGE;
+ }
+}
+
+int mailimap_copy(mailimap * session, struct mailimap_set * set,
+ const char * mb)
+{
+ struct mailimap_response * response;
+ int r;
+ int error_code;
+
+ if (session->imap_state != MAILIMAP_STATE_SELECTED)
+ return MAILIMAP_ERROR_BAD_STATE;
+
+ r = send_current_tag(session);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_copy_send(session->imap_stream, set, mb);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_crlf_send(session->imap_stream);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ if (mailstream_flush(session->imap_stream) == -1)
+ return MAILIMAP_ERROR_STREAM;
+
+ if (read_line(session) == NULL)
+ return MAILIMAP_ERROR_STREAM;
+
+ r = parse_response(session, &response);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ error_code = response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type;
+
+ mailimap_response_free(response);
+
+ switch (error_code) {
+ case MAILIMAP_RESP_COND_STATE_OK:
+ return MAILIMAP_NO_ERROR;
+
+ default:
+ return MAILIMAP_ERROR_COPY;
+ }
+}
+
+int mailimap_uid_copy(mailimap * session, struct mailimap_set * set,
+ const char * mb)
+{
+ struct mailimap_response * response;
+ int r;
+ int error_code;
+
+ if (session->imap_state != MAILIMAP_STATE_SELECTED)
+ return MAILIMAP_ERROR_BAD_STATE;
+
+ r = send_current_tag(session);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_uid_copy_send(session->imap_stream, set, mb);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_crlf_send(session->imap_stream);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ if (mailstream_flush(session->imap_stream) == -1)
+ return MAILIMAP_ERROR_STREAM;
+
+ if (read_line(session) == NULL)
+ return MAILIMAP_ERROR_STREAM;
+
+ r = parse_response(session, &response);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ error_code = response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type;
+
+ mailimap_response_free(response);
+
+ switch (error_code) {
+ case MAILIMAP_RESP_COND_STATE_OK:
+ return MAILIMAP_NO_ERROR;
+
+ default:
+ return MAILIMAP_ERROR_UID_COPY;
+ }
+}
+
+int mailimap_create(mailimap * session, const char * mb)
+{
+ struct mailimap_response * response;
+ int r;
+ int error_code;
+
+ if ((session->imap_state != MAILIMAP_STATE_AUTHENTICATED) &&
+ (session->imap_state != MAILIMAP_STATE_SELECTED))
+ return MAILIMAP_ERROR_BAD_STATE;
+
+ r = send_current_tag(session);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_create_send(session->imap_stream, mb);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_crlf_send(session->imap_stream);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ if (mailstream_flush(session->imap_stream) == -1)
+ return MAILIMAP_ERROR_STREAM;
+
+ if (read_line(session) == NULL)
+ return MAILIMAP_ERROR_STREAM;
+
+ r = parse_response(session, &response);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ error_code = response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type;
+
+ mailimap_response_free(response);
+
+ switch (error_code) {
+ case MAILIMAP_RESP_COND_STATE_OK:
+ return MAILIMAP_NO_ERROR;
+
+ default:
+ return MAILIMAP_ERROR_CREATE;
+ }
+}
+
+
+int mailimap_delete(mailimap * session, const char * mb)
+{
+ struct mailimap_response * response;
+ int r;
+ int error_code;
+
+ if ((session->imap_state != MAILIMAP_STATE_AUTHENTICATED) &&
+ (session->imap_state != MAILIMAP_STATE_SELECTED))
+ return MAILIMAP_ERROR_BAD_STATE;
+
+ r = send_current_tag(session);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_delete_send(session->imap_stream, mb);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_crlf_send(session->imap_stream);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ if (mailstream_flush(session->imap_stream) == -1)
+ return MAILIMAP_ERROR_STREAM;
+
+ if (read_line(session) == NULL)
+ return MAILIMAP_ERROR_STREAM;
+
+ r = parse_response(session, &response);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ error_code = response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type;
+
+ mailimap_response_free(response);
+
+ switch (error_code) {
+ case MAILIMAP_RESP_COND_STATE_OK:
+ return MAILIMAP_NO_ERROR;
+
+ default:
+ return MAILIMAP_ERROR_DELETE;
+ }
+}
+
+int mailimap_examine(mailimap * session, const char * mb)
+{
+ struct mailimap_response * response;
+ int r;
+ int error_code;
+
+ if ((session->imap_state != MAILIMAP_STATE_AUTHENTICATED) &&
+ (session->imap_state != MAILIMAP_STATE_SELECTED))
+ return MAILIMAP_ERROR_BAD_STATE;
+
+ r = send_current_tag(session);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_examine_send(session->imap_stream, mb);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_crlf_send(session->imap_stream);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ if (mailstream_flush(session->imap_stream) == -1)
+ return MAILIMAP_ERROR_STREAM;
+
+ if (read_line(session) == NULL)
+ return MAILIMAP_ERROR_STREAM;
+
+ if (session->imap_selection_info != NULL)
+ mailimap_selection_info_free(session->imap_selection_info);
+ session->imap_selection_info = mailimap_selection_info_new();
+
+ r = parse_response(session, &response);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ error_code = response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type;
+
+ mailimap_response_free(response);
+
+ switch (error_code) {
+ case MAILIMAP_RESP_COND_STATE_OK:
+ session->imap_state = MAILIMAP_STATE_SELECTED;
+ return MAILIMAP_NO_ERROR;
+
+ default:
+ mailimap_selection_info_free(session->imap_selection_info);
+ session->imap_selection_info = NULL;
+ session->imap_state = MAILIMAP_STATE_AUTHENTICATED;
+ return MAILIMAP_ERROR_EXAMINE;
+ }
+}
+
+int
+mailimap_fetch(mailimap * session, struct mailimap_set * set,
+ struct mailimap_fetch_type * fetch_type, clist ** result)
+{
+ struct mailimap_response * response;
+ int r;
+ int error_code;
+
+ if (session->imap_state != MAILIMAP_STATE_SELECTED)
+ return MAILIMAP_ERROR_BAD_STATE;
+
+ r = send_current_tag(session);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_fetch_send(session->imap_stream, set, fetch_type);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_crlf_send(session->imap_stream);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ if (mailstream_flush(session->imap_stream) == -1)
+ return MAILIMAP_ERROR_STREAM;
+
+ if (read_line(session) == NULL)
+ return MAILIMAP_ERROR_STREAM;
+
+ r = parse_response(session, &response);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ * result = session->imap_response_info->rsp_fetch_list;
+ session->imap_response_info->rsp_fetch_list = NULL;
+
+ error_code = response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type;
+
+ mailimap_response_free(response);
+
+ switch (error_code) {
+ case MAILIMAP_RESP_COND_STATE_OK:
+ return MAILIMAP_NO_ERROR;
+
+ default:
+ return MAILIMAP_ERROR_FETCH;
+ }
+}
+
+void mailimap_fetch_list_free(clist * fetch_list)
+{
+ clist_foreach(fetch_list, (clist_func) mailimap_msg_att_free, NULL);
+ clist_free(fetch_list);
+}
+
+int
+mailimap_uid_fetch(mailimap * session,
+ struct mailimap_set * set,
+ struct mailimap_fetch_type * fetch_type, clist ** result)
+{
+ struct mailimap_response * response;
+ int r;
+ int error_code;
+
+ if (session->imap_state != MAILIMAP_STATE_SELECTED)
+ return MAILIMAP_ERROR_BAD_STATE;
+
+ r = send_current_tag(session);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_uid_fetch_send(session->imap_stream, set, fetch_type);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_crlf_send(session->imap_stream);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ if (mailstream_flush(session->imap_stream) == -1)
+ return MAILIMAP_ERROR_STREAM;
+
+ if (read_line(session) == NULL)
+ return MAILIMAP_ERROR_STREAM;
+
+ r = parse_response(session, &response);
+
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ * result = session->imap_response_info->rsp_fetch_list;
+ session->imap_response_info->rsp_fetch_list = NULL;
+
+ error_code = response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type;
+
+ mailimap_response_free(response);
+
+ switch (error_code) {
+ case MAILIMAP_RESP_COND_STATE_OK:
+ return MAILIMAP_NO_ERROR;
+
+ default:
+ return MAILIMAP_ERROR_UID_FETCH;
+ }
+}
+
+int mailimap_list(mailimap * session, const char * mb,
+ const char * list_mb, clist ** result)
+{
+ struct mailimap_response * response;
+ int r;
+ int error_code;
+
+ if ((session->imap_state != MAILIMAP_STATE_AUTHENTICATED) &&
+ (session->imap_state != MAILIMAP_STATE_SELECTED))
+ return MAILIMAP_ERROR_BAD_STATE;
+
+ r = send_current_tag(session);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_list_send(session->imap_stream, mb, list_mb);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_crlf_send(session->imap_stream);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ if (mailstream_flush(session->imap_stream) == -1)
+ return MAILIMAP_ERROR_STREAM;
+
+ if (read_line(session) == NULL)
+ return MAILIMAP_ERROR_STREAM;
+
+ r = parse_response(session, &response);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ * result = session->imap_response_info->rsp_mailbox_list;
+ session->imap_response_info->rsp_mailbox_list = NULL;
+
+ error_code = response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type;
+
+ mailimap_response_free(response);
+
+ switch (error_code) {
+ case MAILIMAP_RESP_COND_STATE_OK:
+ return MAILIMAP_NO_ERROR;
+
+ default:
+ return MAILIMAP_ERROR_LIST;
+ }
+}
+
+int mailimap_login(mailimap * session,
+ const char * userid, const char * password)
+{
+ struct mailimap_response * response;
+ int r;
+ int error_code;
+
+ if (session->imap_state != MAILIMAP_STATE_NON_AUTHENTICATED)
+ return MAILIMAP_ERROR_BAD_STATE;
+
+ r = send_current_tag(session);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_login_send(session->imap_stream, userid, password);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_crlf_send(session->imap_stream);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ if (mailstream_flush(session->imap_stream) == -1)
+ return MAILIMAP_ERROR_STREAM;
+
+ if (read_line(session) == NULL)
+ return MAILIMAP_ERROR_STREAM;
+
+ r = parse_response(session, &response);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ error_code = response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type;
+
+ mailimap_response_free(response);
+
+ switch (error_code) {
+ case MAILIMAP_RESP_COND_STATE_OK:
+ session->imap_state = MAILIMAP_STATE_AUTHENTICATED;
+ return MAILIMAP_NO_ERROR;
+
+ default:
+ return MAILIMAP_ERROR_LOGIN;
+ }
+}
+
+int mailimap_lsub(mailimap * session, const char * mb,
+ const char * list_mb, clist ** result)
+{
+ struct mailimap_response * response;
+ int r;
+ int error_code;
+
+ if ((session->imap_state != MAILIMAP_STATE_AUTHENTICATED) &&
+ (session->imap_state != MAILIMAP_STATE_SELECTED))
+ return MAILIMAP_ERROR_BAD_STATE;
+
+ r = send_current_tag(session);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_lsub_send(session->imap_stream, mb, list_mb);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_crlf_send(session->imap_stream);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ if (mailstream_flush(session->imap_stream) == -1)
+ return MAILIMAP_ERROR_STREAM;
+
+ if (read_line(session) == NULL)
+ return MAILIMAP_ERROR_STREAM;
+
+ r = parse_response(session, &response);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ * result = session->imap_response_info->rsp_mailbox_lsub;
+ session->imap_response_info->rsp_mailbox_lsub = NULL;
+
+ error_code = response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type;
+
+ mailimap_response_free(response);
+
+ switch (error_code) {
+ case MAILIMAP_RESP_COND_STATE_OK:
+ return MAILIMAP_NO_ERROR;
+
+ default:
+ return MAILIMAP_ERROR_LSUB;
+ }
+}
+
+void mailimap_list_result_free(clist * list)
+{
+ clist_foreach(list, (clist_func) mailimap_mailbox_list_free, NULL);
+ clist_free(list);
+}
+
+int mailimap_rename(mailimap * session,
+ const char * mb, const char * new_name)
+{
+ struct mailimap_response * response;
+ int r;
+ int error_code;
+
+ if ((session->imap_state != MAILIMAP_STATE_AUTHENTICATED) &&
+ (session->imap_state != MAILIMAP_STATE_SELECTED))
+ return MAILIMAP_ERROR_BAD_STATE;
+
+ r = send_current_tag(session);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_rename_send(session->imap_stream, mb, new_name);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ if (!mailimap_crlf_send(session->imap_stream))
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ if (mailstream_flush(session->imap_stream) == -1)
+ return MAILIMAP_ERROR_STREAM;
+
+ if (read_line(session) == NULL)
+ return MAILIMAP_ERROR_STREAM;
+
+ r = parse_response(session, &response);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ error_code = response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type;
+
+ mailimap_response_free(response);
+
+ switch (error_code) {
+ case MAILIMAP_RESP_COND_STATE_OK:
+ return MAILIMAP_NO_ERROR;
+
+ default:
+ return MAILIMAP_ERROR_RENAME;
+ }
+}
+
+int
+mailimap_search(mailimap * session, const char * charset,
+ struct mailimap_search_key * key, clist ** result)
+{
+ struct mailimap_response * response;
+ int r;
+ int error_code;
+
+ if (session->imap_state != MAILIMAP_STATE_SELECTED)
+ return MAILIMAP_ERROR_BAD_STATE;
+
+ r = send_current_tag(session);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_search_send(session->imap_stream, charset, key);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_crlf_send(session->imap_stream);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ if (mailstream_flush(session->imap_stream) == -1)
+ return MAILIMAP_ERROR_STREAM;
+
+ if (read_line(session) == NULL)
+ return MAILIMAP_ERROR_STREAM;
+
+ r = parse_response(session, &response);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ * result = session->imap_response_info->rsp_search_result;
+ session->imap_response_info->rsp_search_result = NULL;
+
+ error_code = response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type;
+
+ mailimap_response_free(response);
+
+ switch (error_code) {
+ case MAILIMAP_RESP_COND_STATE_OK:
+ return MAILIMAP_NO_ERROR;
+
+ default:
+ return MAILIMAP_ERROR_SEARCH;
+ }
+}
+
+int
+mailimap_uid_search(mailimap * session, const char * charset,
+ struct mailimap_search_key * key, clist ** result)
+{
+ struct mailimap_response * response;
+ int r;
+ int error_code;
+
+ if (session->imap_state != MAILIMAP_STATE_SELECTED)
+ return MAILIMAP_ERROR_BAD_STATE;
+
+ r = send_current_tag(session);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_uid_search_send(session->imap_stream, charset, key);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_crlf_send(session->imap_stream);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ if (mailstream_flush(session->imap_stream) == -1)
+ return MAILIMAP_ERROR_STREAM;
+
+ if (read_line(session) == NULL)
+ return MAILIMAP_ERROR_STREAM;
+
+ r = parse_response(session, &response);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ * result = session->imap_response_info->rsp_search_result;
+ session->imap_response_info->rsp_search_result = NULL;
+
+ error_code = response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type;
+
+ mailimap_response_free(response);
+
+ switch (error_code) {
+ case MAILIMAP_RESP_COND_STATE_OK:
+ return MAILIMAP_NO_ERROR;
+
+ default:
+ return MAILIMAP_ERROR_UID_SEARCH;
+ }
+}
+
+void mailimap_search_result_free(clist * search_result)
+{
+ clist_foreach(search_result, (clist_func) free, NULL);
+ clist_free(search_result);
+}
+
+int
+mailimap_select(mailimap * session, const char * mb)
+{
+ struct mailimap_response * response;
+ int r;
+ int error_code;
+
+ if ((session->imap_state != MAILIMAP_STATE_AUTHENTICATED) &&
+ (session->imap_state != MAILIMAP_STATE_SELECTED))
+ return MAILIMAP_ERROR_BAD_STATE;
+
+ r = send_current_tag(session);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_select_send(session->imap_stream, mb);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_crlf_send(session->imap_stream);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ if (mailstream_flush(session->imap_stream) == -1)
+ return MAILIMAP_ERROR_STREAM;
+
+ if (read_line(session) == NULL)
+ return MAILIMAP_ERROR_STREAM;
+
+ if (session->imap_selection_info != NULL)
+ mailimap_selection_info_free(session->imap_selection_info);
+ session->imap_selection_info = mailimap_selection_info_new();
+
+ r = parse_response(session, &response);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ error_code = response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type;
+
+ mailimap_response_free(response);
+
+ switch (error_code) {
+ case MAILIMAP_RESP_COND_STATE_OK:
+ session->imap_state = MAILIMAP_STATE_SELECTED;
+ return MAILIMAP_NO_ERROR;
+
+ default:
+ mailimap_selection_info_free(session->imap_selection_info);
+ session->imap_selection_info = NULL;
+ session->imap_state = MAILIMAP_STATE_AUTHENTICATED;
+ return MAILIMAP_ERROR_SELECT;
+ }
+}
+
+int
+mailimap_status(mailimap * session, const char * mb,
+ struct mailimap_status_att_list * status_att_list,
+ struct mailimap_mailbox_data_status ** result)
+{
+ struct mailimap_response * response;
+ int r;
+ int error_code;
+
+ if ((session->imap_state != MAILIMAP_STATE_AUTHENTICATED) &&
+ (session->imap_state != MAILIMAP_STATE_SELECTED))
+ return MAILIMAP_ERROR_BAD_STATE;
+
+ r = send_current_tag(session);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_status_send(session->imap_stream, mb, status_att_list);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_crlf_send(session->imap_stream);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ if (mailstream_flush(session->imap_stream) == -1)
+ return MAILIMAP_ERROR_STREAM;
+
+ if (read_line(session) == NULL)
+ return MAILIMAP_ERROR_STREAM;
+
+ r = parse_response(session, &response);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ * result = session->imap_response_info->rsp_status;
+ session->imap_response_info->rsp_status = NULL;
+
+ error_code = response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type;
+
+ mailimap_response_free(response);
+
+ switch (error_code) {
+ case MAILIMAP_RESP_COND_STATE_OK:
+ return MAILIMAP_NO_ERROR;
+
+ default:
+ return MAILIMAP_ERROR_STATUS;
+ }
+}
+
+
+int
+mailimap_store(mailimap * session,
+ struct mailimap_set * set,
+ struct mailimap_store_att_flags * store_att_flags)
+{
+ struct mailimap_response * response;
+ int r;
+ int error_code;
+
+ if (session->imap_state != MAILIMAP_STATE_SELECTED)
+ return MAILIMAP_ERROR_BAD_STATE;
+
+ r = send_current_tag(session);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_store_send(session->imap_stream, set, store_att_flags);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_crlf_send(session->imap_stream);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ if (mailstream_flush(session->imap_stream) == -1)
+ return MAILIMAP_ERROR_STREAM;
+
+ if (read_line(session) == NULL)
+ return MAILIMAP_ERROR_STREAM;
+
+ r = parse_response(session, &response);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ error_code = response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type;
+
+ mailimap_response_free(response);
+
+ switch (error_code) {
+ case MAILIMAP_RESP_COND_STATE_OK:
+ return MAILIMAP_NO_ERROR;
+
+ default:
+ return MAILIMAP_ERROR_STORE;
+ }
+}
+
+int
+mailimap_uid_store(mailimap * session,
+ struct mailimap_set * set,
+ struct mailimap_store_att_flags * store_att_flags)
+{
+ struct mailimap_response * response;
+ int r;
+ int error_code;
+
+ if (session->imap_state != MAILIMAP_STATE_SELECTED)
+ return MAILIMAP_ERROR_BAD_STATE;
+
+ r = send_current_tag(session);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_uid_store_send(session->imap_stream, set, store_att_flags);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_crlf_send(session->imap_stream);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ if (mailstream_flush(session->imap_stream) == -1)
+ return MAILIMAP_ERROR_STREAM;
+
+ if (read_line(session) == NULL)
+ return MAILIMAP_ERROR_STREAM;
+
+ r = parse_response(session, &response);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ error_code = response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type;
+
+ mailimap_response_free(response);
+
+ switch (error_code) {
+ case MAILIMAP_RESP_COND_STATE_OK:
+ return MAILIMAP_NO_ERROR;
+
+ default:
+ return MAILIMAP_ERROR_UID_STORE;
+ }
+}
+
+int mailimap_subscribe(mailimap * session, const char * mb)
+{
+ struct mailimap_response * response;
+ int r;
+ int error_code;
+
+ if ((session->imap_state != MAILIMAP_STATE_AUTHENTICATED) &&
+ (session->imap_state != MAILIMAP_STATE_SELECTED))
+ return MAILIMAP_ERROR_BAD_STATE;
+
+ r = send_current_tag(session);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_subscribe_send(session->imap_stream, mb);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_crlf_send(session->imap_stream);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ if (mailstream_flush(session->imap_stream) == -1)
+ return MAILIMAP_ERROR_STREAM;
+
+ if (read_line(session) == NULL)
+ return MAILIMAP_ERROR_STREAM;
+
+ r = parse_response(session, &response);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ error_code = response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type;
+
+ mailimap_response_free(response);
+
+ switch (error_code) {
+ case MAILIMAP_RESP_COND_STATE_OK:
+ return MAILIMAP_NO_ERROR;
+
+ default:
+ return MAILIMAP_ERROR_SUBSCRIBE;
+ }
+}
+
+int mailimap_unsubscribe(mailimap * session, const char * mb)
+{
+ struct mailimap_response * response;
+ int r;
+ int error_code;
+
+ if ((session->imap_state != MAILIMAP_STATE_AUTHENTICATED) &&
+ (session->imap_state != MAILIMAP_STATE_SELECTED))
+ return MAILIMAP_ERROR_BAD_STATE;
+
+ r = send_current_tag(session);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_unsubscribe_send(session->imap_stream, mb);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_crlf_send(session->imap_stream);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ if (mailstream_flush(session->imap_stream) == -1)
+ return MAILIMAP_ERROR_STREAM;
+
+ if (read_line(session) == NULL)
+ return MAILIMAP_ERROR_STREAM;
+
+ r = parse_response(session, &response);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ error_code = response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type;
+
+ mailimap_response_free(response);
+
+ switch (error_code) {
+ case MAILIMAP_RESP_COND_STATE_OK:
+ return MAILIMAP_NO_ERROR;
+
+ default:
+ return MAILIMAP_ERROR_UNSUBSCRIBE;
+ }
+}
+
+
+int mailimap_starttls(mailimap * session)
+{
+ struct mailimap_response * response;
+ int r;
+ int error_code;
+
+ r = send_current_tag(session);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_starttls_send(session->imap_stream);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_crlf_send(session->imap_stream);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ if (mailstream_flush(session->imap_stream) == -1)
+ return MAILIMAP_ERROR_STREAM;
+
+ if (read_line(session) == NULL)
+ return MAILIMAP_ERROR_STREAM;
+
+ r = parse_response(session, &response);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ error_code = response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type;
+
+ mailimap_response_free(response);
+
+ switch (error_code) {
+ case MAILIMAP_RESP_COND_STATE_OK:
+ return MAILIMAP_NO_ERROR;
+
+ default:
+ return MAILIMAP_ERROR_STARTTLS;
+ }
+}
+
+
+
+static char * read_line(mailimap * session)
+{
+ return mailstream_read_line(session->imap_stream, session->imap_stream_buffer);
+}
+
+static int send_current_tag(mailimap * session)
+{
+ char tag_str[15];
+ int r;
+
+ session->imap_tag ++;
+ snprintf(tag_str, 15, "%i", session->imap_tag);
+
+ r = mailimap_tag_send(session->imap_stream, tag_str);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_space_send(session->imap_stream);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ return MAILIMAP_NO_ERROR;
+}
+
+static int parse_response(mailimap * session,
+ struct mailimap_response ** result)
+{
+ size_t index;
+ struct mailimap_response * response;
+ char tag_str[15];
+ int r;
+
+ index = 0;
+
+ session->imap_response = NULL;
+
+ r = mailimap_response_parse(session->imap_stream,
+ session->imap_stream_buffer,
+ &index, &response,
+ session->imap_progr_rate, session->imap_progr_fun);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+#if 0
+ mailimap_response_print(response);
+#endif
+
+ response_store(session, response);
+
+ if (mmap_string_assign(session->imap_response_buffer,
+ response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_text->rsp_text)
+ == NULL)
+ return MAILIMAP_ERROR_MEMORY;
+
+ session->imap_response = session->imap_response_buffer->str;
+
+ if (response->rsp_resp_done->rsp_type == MAILIMAP_RESP_DONE_TYPE_FATAL)
+ return MAILIMAP_ERROR_FATAL;
+
+ snprintf(tag_str, 15, "%i", session->imap_tag);
+ if (strcmp(response->rsp_resp_done->rsp_data.rsp_tagged->rsp_tag, tag_str) != 0)
+ return MAILIMAP_ERROR_PROTOCOL;
+
+ if (response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type ==
+ MAILIMAP_RESP_COND_STATE_BAD)
+ return MAILIMAP_ERROR_PROTOCOL;
+
+ * result = response;
+
+ return MAILIMAP_NO_ERROR;
+}
+
+
+static int parse_greeting(mailimap * session,
+ struct mailimap_greeting ** result)
+{
+ size_t index;
+ struct mailimap_greeting * greeting;
+ int r;
+
+ index = 0;
+
+ session->imap_response = NULL;
+
+ r = mailimap_greeting_parse(session->imap_stream,
+ session->imap_stream_buffer,
+ &index, &greeting, session->imap_progr_rate,
+ session->imap_progr_fun);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+#if 0
+ mailimap_greeting_print(greeting);
+#endif
+
+ greeting_store(session, greeting);
+
+ if (greeting->gr_type == MAILIMAP_GREETING_RESP_COND_BYE) {
+ if (mmap_string_assign(session->imap_response_buffer,
+ greeting->gr_data.gr_bye->rsp_text->rsp_text) == NULL)
+ return MAILIMAP_ERROR_MEMORY;
+
+ session->imap_response = session->imap_response_buffer->str;
+
+ return MAILIMAP_ERROR_DONT_ACCEPT_CONNECTION;
+ }
+
+ if (mmap_string_assign(session->imap_response_buffer,
+ greeting->gr_data.gr_auth->rsp_text->rsp_text) == NULL)
+ return MAILIMAP_ERROR_MEMORY;
+
+ session->imap_response = session->imap_response_buffer->str;
+
+ * result = greeting;
+
+ return MAILIMAP_NO_ERROR;
+}
+
+
+mailimap * mailimap_new(size_t imap_progr_rate,
+ progress_function * imap_progr_fun)
+{
+ mailimap * f;
+
+ f = malloc(sizeof(* f));
+ if (f == NULL)
+ goto err;
+
+ f->imap_response = NULL;
+
+ f->imap_stream = NULL;
+
+ f->imap_progr_rate = imap_progr_rate;
+ f->imap_progr_fun = imap_progr_fun;
+
+ f->imap_stream_buffer = mmap_string_new("");
+ if (f->imap_stream_buffer == NULL)
+ goto free_f;
+
+ f->imap_response_buffer = mmap_string_new("");
+ if (f->imap_response_buffer == NULL)
+ goto free_stream_buffer;
+
+ f->imap_state = MAILIMAP_STATE_DISCONNECTED;
+ f->imap_tag = 0;
+
+ f->imap_selection_info = NULL;
+ f->imap_response_info = NULL;
+ f->imap_connection_info = NULL;
+
+ return f;
+
+ free_stream_buffer:
+ mmap_string_free(f->imap_stream_buffer);
+ free_f:
+ free(f);
+ err:
+ return NULL;
+}
+
+void mailimap_free(mailimap * session)
+{
+ if (session->imap_stream)
+ mailimap_logout(session);
+
+ mmap_string_free(session->imap_response_buffer);
+ mmap_string_free(session->imap_stream_buffer);
+
+ if (session->imap_response_info)
+ mailimap_response_info_free(session->imap_response_info);
+ if (session->imap_selection_info)
+ mailimap_selection_info_free(session->imap_selection_info);
+ if (session->imap_connection_info)
+ mailimap_connection_info_free(session->imap_connection_info);
+
+ free(session);
+}
diff --git a/libetpan/src/low-level/imap/mailimap.h b/libetpan/src/low-level/imap/mailimap.h
new file mode 100644
index 0000000..e31e2d2
--- a/dev/null
+++ b/libetpan/src/low-level/imap/mailimap.h
@@ -0,0 +1,598 @@
+/*
+ * 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$
+ */
+
+#ifndef MAILIMAP_H
+
+#define MAILIMAP_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <libetpan/mailimap_types.h>
+#include <libetpan/mailimap_types_helper.h>
+#include <libetpan/mailimap_helper.h>
+
+#include <libetpan/mailimap_socket.h>
+#include <libetpan/mailimap_ssl.h>
+
+/*
+ mailimap_connect()
+
+ This function will connect the IMAP session with the given stream.
+
+ @param session the IMAP session
+ @param s stream to use
+
+ @return the return code is one of MAILIMAP_ERROR_XXX or
+ MAILIMAP_NO_ERROR codes
+
+ note that on success, MAILIMAP_NO_ERROR_AUTHENTICATED or
+ MAILIMAP_NO_ERROR_NON_AUTHENTICATED is returned
+
+ MAILIMAP_NO_ERROR_NON_AUTHENTICATED is returned when you need to
+ use mailimap_login() to authenticate, else
+ MAILIMAP_NO_ERROR_AUTHENTICATED is returned.
+*/
+
+int mailimap_connect(mailimap * session, mailstream * s);
+
+/*
+ mailimap_append()
+
+ This function will append a given message to the given mailbox
+ by sending an APPEND command.
+
+ @param session the IMAP session
+ @param mailbox name of the mailbox
+ @param flag_list flags of the message
+ @param date_time timestamp of the message
+ @param literal content of the message
+ @param literal_size size of the message
+
+ @return the return code is one of MAILIMAP_ERROR_XXX or
+ MAILIMAP_NO_ERROR codes
+*/
+
+int mailimap_append(mailimap * session, const char * mailbox,
+ struct mailimap_flag_list * flag_list,
+ struct mailimap_date_time * date_time,
+ const char * literal, size_t literal_size);
+
+/*
+ mailimap_noop()
+
+ This function will poll for an event on the server by
+ sending a NOOP command to the IMAP server
+
+ @param session IMAP session
+
+ @return the return code is one of MAILIMAP_ERROR_XXX or
+ MAILIMAP_NO_ERROR_XXX codes
+*/
+
+int mailimap_noop(mailimap * session);
+
+/*
+ mailimap_logout()
+
+ This function will logout from an IMAP server by sending
+ a LOGOUT command.
+
+ @param session IMAP session
+
+ @return the return code is one of MAILIMAP_ERROR_XXX or
+ MAILIMAP_NO_ERROR codes
+*/
+
+int mailimap_logout(mailimap * session);
+
+/*
+ mailimap_capability()
+
+ This function will query an IMAP server for his capabilities
+ by sending a CAPABILITY command.
+
+ @param session IMAP session
+ @param result The result of this command is a list of
+ capabilities and it is stored into (* result).
+
+ @return the return code is one of MAILIMAP_ERROR_XXX or
+ MAILIMAP_NO_ERROR codes
+ */
+
+int mailimap_capability(mailimap * session,
+ struct mailimap_capability_data ** result);
+
+/*
+ mailimap_check()
+
+ This function will request for a checkpoint of the mailbox by
+ sending a CHECK command.
+
+ @param session IMAP session
+
+ @return the return code is one of MAILIMAP_ERROR_XXX or
+ MAILIMAP_NO_ERROR codes
+ */
+
+int mailimap_check(mailimap * session);
+
+/*
+ mailimap_close()
+
+ This function will close the selected mailbox by sending
+ a CLOSE command.
+
+ @param session IMAP session
+
+ @return the return code is one of MAILIMAP_ERROR_XXX or
+ MAILIMAP_NO_ERROR codes
+ */
+
+int mailimap_close(mailimap * session);
+
+/*
+ mailimap_expunge()
+
+ This function will permanently remove from the selected mailbox
+ message that have the \Deleted flag set.
+
+ @param session IMAP session
+
+ @return the return code is one of MAILIMAP_ERROR_XXX or
+ MAILIMAP_NO_ERROR codes
+*/
+
+int mailimap_expunge(mailimap * session);
+
+/*
+ mailimap_copy()
+
+ This function will copy the given messages from the selected mailbox
+ to the given mailbox.
+
+ @param session IMAP session
+ @param set This is a set of message numbers.
+ @param mb This is the destination mailbox.
+
+ @return the return code is one of MAILIMAP_ERROR_XXX or
+ MAILIMAP_NO_ERROR codes
+ */
+
+int mailimap_copy(mailimap * session, struct mailimap_set * set,
+ const char * mb);
+
+/*
+ mailimap_uid_copy()
+
+ This function will copy the given messages from the selected mailbox
+ to the given mailbox.
+
+ @param session IMAP session
+ @param set This is a set of message unique identifiers.
+ @param mb This is the destination mailbox.
+
+ @return the return code is one of MAILIMAP_ERROR_XXX or
+ MAILIMAP_NO_ERROR codes
+ */
+
+int mailimap_uid_copy(mailimap * session,
+ struct mailimap_set * set, const char * mb);
+
+/*
+ mailimap_create()
+
+ This function will create a mailbox.
+
+ @param session IMAP session
+ @param mb This is the name of the mailbox to create.
+
+ @return the return code is one of MAILIMAP_ERROR_XXX or
+ MAILIMAP_NO_ERROR codes
+*/
+
+int mailimap_create(mailimap * session, const char * mb);
+
+/*
+ mailimap_delete()
+
+ This function will delete a mailox.
+
+ @param session IMAP session
+ @param mb This is the name of the mailbox to delete.
+
+ @return the return code is one of MAILIMAP_ERROR_XXX or
+ MAILIMAP_NO_ERROR codes
+*/
+
+int mailimap_delete(mailimap * session, const char * mb);
+
+/*
+ mailimap_examine()
+
+ This function will select the mailbox for read-only operations.
+
+ @param session IMAP session
+ @param mb This is the name of the mailbox to select.
+
+ @return the return code is one of MAILIMAP_ERROR_XXX or
+ MAILIMAP_NO_ERROR codes
+*/
+
+int mailimap_examine(mailimap * session, const char * mb);
+
+/*
+ mailimap_fetch()
+
+ This function will retrieve data associated with the given message
+ numbers.
+
+ @param session IMAP session
+ @param set set of message numbers
+ @param fetch_type type of information to be retrieved
+ @param result The result of this command is a clist
+ and it is stored into (* result). Each element of the clist is a
+ (struct mailimap_msg_att *).
+
+ @return the return code is one of MAILIMAP_ERROR_XXX or
+ MAILIMAP_NO_ERROR codes
+*/
+
+int
+mailimap_fetch(mailimap * session, struct mailimap_set * set,
+ struct mailimap_fetch_type * fetch_type, clist ** result);
+
+/*
+ mailimap_fetch()
+
+ This function will retrieve data associated with the given message
+ numbers.
+
+ @param session IMAP session
+ @param set set of message unique identifiers
+ @param fetch_type type of information to be retrieved
+ @param result The result of this command is a clist
+ and it is stored into (* result). Each element of the clist is a
+ (struct mailimap_msg_att *).
+
+ @return the return code is one of MAILIMAP_ERROR_XXX or
+ MAILIMAP_NO_ERROR codes
+*/
+
+int
+mailimap_uid_fetch(mailimap * session,
+ struct mailimap_set * set,
+ struct mailimap_fetch_type * fetch_type, clist ** result);
+
+/*
+ mailimap_fetch_list_free()
+
+ This function will free the result of a fetch command.
+
+ @param fetch_list This is the clist containing
+ (struct mailimap_msg_att *) elements to free.
+*/
+
+void mailimap_fetch_list_free(clist * fetch_list);
+
+/*
+ mailimap_list()
+
+ This function will return the list of the mailbox
+ available on the server.
+
+ @param session IMAP session
+ @param mb This is the reference name that informs
+ of the level of hierarchy
+ @param list_mb mailbox name with possible wildcard
+ @param result This will store a clist of (struct mailimap_mailbox_list *)
+ in (* result)
+
+ @return the return code is one of MAILIMAP_ERROR_XXX or
+ MAILIMAP_NO_ERROR codes
+*/
+
+int mailimap_list(mailimap * session, const char * mb,
+ const char * list_mb, clist ** result);
+
+/*
+ mailimap_login()
+
+ This function will authenticate the client.
+
+ @param session IMAP session
+ @param userid login of the user
+ @param password password of the user
+
+ @return the return code is one of MAILIMAP_ERROR_XXX or
+ MAILIMAP_NO_ERROR codes
+*/
+
+int mailimap_login(mailimap * session,
+ const char * userid, const char * password);
+
+/*
+ mailimap_lsub()
+
+ This function will return the list of the mailbox
+ that the client has subscribed to.
+
+ @param session IMAP session
+ @param mb This is the reference name that informs
+ of the level of hierarchy
+ @param list_mb mailbox name with possible wildcard
+ @param result This will store a list of (struct mailimap_mailbox_list *)
+ in (* result)
+
+ @return the return code is one of MAILIMAP_ERROR_XXX or
+ MAILIMAP_NO_ERROR codes
+*/
+
+int mailimap_lsub(mailimap * session, const char * mb,
+ const char * list_mb, clist ** result);
+
+/*
+ mailimap_list_result_free()
+
+ This function will free the clist of (struct mailimap_mailbox_list *)
+
+ @param list This is the clist to free.
+*/
+
+void mailimap_list_result_free(clist * list);
+
+/*
+ mailimap_rename()
+
+ This function will change the name of a mailbox.
+
+ @param session IMAP session
+ @param mb current name
+ @param new_name new name
+
+ @return the return code is one of MAILIMAP_ERROR_XXX or
+ MAILIMAP_NO_ERROR codes
+*/
+
+int mailimap_rename(mailimap * session,
+ const char * mb, const char * new_name);
+
+/*
+ mailimap_search()
+
+ All mails that match the given criteria will be returned
+ their numbers in the result list.
+
+ @param session IMAP session
+ @param charset This indicates the charset of the strings that appears
+ in the searching criteria
+ @param key This is the searching criteria
+ @param result The result is a clist of (uint32_t *) and will be
+ stored in (* result).
+
+ @return the return code is one of MAILIMAP_ERROR_XXX or
+ MAILIMAP_NO_ERROR codes
+*/
+
+int
+mailimap_search(mailimap * session, const char * charset,
+ struct mailimap_search_key * key, clist ** result);
+
+/*
+ mailimap_uid_search()
+
+
+ All mails that match the given criteria will be returned
+ their unique identifiers in the result list.
+
+ @param session IMAP session
+ @param charset This indicates the charset of the strings that appears
+ in the searching criteria
+ @param key This is the searching criteria
+ @param result The result is a clist of (uint32_t *) and will be
+ stored in (* result).
+
+ @return the return code is one of MAILIMAP_ERROR_XXX or
+ MAILIMAP_NO_ERROR codes
+*/
+
+int
+mailimap_uid_search(mailimap * session, const char * charset,
+ struct mailimap_search_key * key, clist ** result);
+
+/*
+ mailimap_search_result_free()
+
+ This function will free the result of the a search.
+
+ @param search_result This is a clist of (uint32_t *) returned
+ by mailimap_uid_search() or mailimap_search()
+*/
+
+void mailimap_search_result_free(clist * search_result);
+
+/*
+ mailimap_select()
+
+ This function will select a given mailbox so that messages in the
+ mailbox can be accessed.
+
+ @param session IMAP session
+ @param mb This is the name of the mailbox to select.
+
+ @return the return code is one of MAILIMAP_ERROR_XXX or
+ MAILIMAP_NO_ERROR codes
+*/
+
+int
+mailimap_select(mailimap * session, const char * mb);
+
+/*
+ mailimap_status()
+
+ This function will return informations about a given mailbox.
+
+ @param session IMAP session
+ @param mb This is the name of the mailbox
+ @param status_att_list This is the list of mailbox information to return
+ @param result List of returned values
+
+ @return the return code is one of MAILIMAP_ERROR_XXX or
+ MAILIMAP_NO_ERROR codes
+*/
+
+int
+mailimap_status(mailimap * session, const char * mb,
+ struct mailimap_status_att_list * status_att_list,
+ struct mailimap_mailbox_data_status ** result);
+
+/*
+ mailimap_uid_store()
+
+ This function will alter the data associated with some messages
+ (flags of the messages).
+
+ @param session IMAP session
+ @param set This is a list of message numbers.
+ @param store_att_flags This is the data to associate with the
+ given messages
+
+ @return the return code is one of MAILIMAP_ERROR_XXX or
+ MAILIMAP_NO_ERROR codes
+*/
+
+int
+mailimap_store(mailimap * session,
+ struct mailimap_set * set,
+ struct mailimap_store_att_flags * store_att_flags);
+
+/*
+ mailimap_uid_store()
+
+ This function will alter the data associated with some messages
+ (flags of the messages).
+
+ @param session IMAP session
+ @param set This is a list of message unique identifiers.
+ @param store_att_flags This is the data to associate with the
+ given messages
+
+ @return the return code is one of MAILIMAP_ERROR_XXX or
+ MAILIMAP_NO_ERROR codes
+*/
+
+int
+mailimap_uid_store(mailimap * session,
+ struct mailimap_set * set,
+ struct mailimap_store_att_flags * store_att_flags);
+
+/*
+ mailimap_subscribe()
+
+ This function adds the specified mailbox name to the
+ server's set of "active" or "subscribed" mailboxes.
+
+ @param session IMAP session
+ @param mb This is the name of the mailbox
+
+ @return the return code is one of MAILIMAP_ERROR_XXX or
+ MAILIMAP_NO_ERROR codes
+*/
+
+int mailimap_subscribe(mailimap * session, const char * mb);
+
+/*
+ mailimap_unsubscribe()
+
+ This function removes the specified mailbox name to the
+ server's set of "active" or "subscribed" mailboxes.
+
+ @param session IMAP session
+ @param mb This is the name of the mailbox
+
+ @return the return code is one of MAILIMAP_ERROR_XXX or
+ MAILIMAP_NO_ERROR codes
+*/
+
+int mailimap_unsubscribe(mailimap * session, const char * mb);
+
+/*
+ mailimap_starttls()
+
+ This function starts change the mode of the connection to
+ switch to SSL connection.
+
+ @param session IMAP session
+
+ @return the return code is one of MAILIMAP_ERROR_XXX or
+ MAILIMAP_NO_ERROR_XXX codes
+ */
+
+int mailimap_starttls(mailimap * session);
+
+/*
+ mailimap_new()
+
+ This function returns a new IMAP session.
+
+ @param progr_rate When downloading messages, a function will be called
+ each time the amount of bytes downloaded reaches a multiple of this
+ value, this can be 0.
+ @param progr_fun This is the function to call to notify the progress,
+ this can be NULL.
+
+ @return an IMAP session is returned.
+ */
+
+mailimap * mailimap_new(size_t imap_progr_rate,
+ progress_function * imap_progr_fun);
+
+/*
+ mailimap_free()
+
+ This function will free the data structures associated with
+ the IMAP session.
+
+ @param session IMAP session
+ */
+
+void mailimap_free(mailimap * session);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libetpan/src/low-level/imap/mailimap_helper.c b/libetpan/src/low-level/imap/mailimap_helper.c
new file mode 100644
index 0000000..cc2a8e6
--- a/dev/null
+++ b/libetpan/src/low-level/imap/mailimap_helper.c
@@ -0,0 +1,205 @@
+/*
+ * 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 "mailimap_helper.h"
+
+#include <stdlib.h>
+#include "mailimap.h"
+
+int mailimap_fetch_rfc822(mailimap * session,
+ uint32_t msgid, char ** result)
+{
+ int r;
+ clist * fetch_list;
+ struct mailimap_fetch_att * fetch_att;
+ struct mailimap_fetch_type * fetch_type;
+ struct mailimap_set * set;
+ struct mailimap_msg_att * msg_att;
+ struct mailimap_msg_att_item * item;
+ int res;
+
+ fetch_att = mailimap_fetch_att_new_rfc822();
+ fetch_type = mailimap_fetch_type_new_fetch_att(fetch_att);
+ set = mailimap_set_new_single(msgid);
+
+ r = mailimap_fetch(session, set, fetch_type, &fetch_list);
+
+ mailimap_set_free(set);
+ mailimap_fetch_type_free(fetch_type);
+
+ if (r != MAILIMAP_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ if (clist_isempty(fetch_list)) {
+ res = MAILIMAP_ERROR_FETCH;
+ goto free;
+ }
+
+ msg_att = (struct mailimap_msg_att *) clist_begin(fetch_list)->data;
+
+ if (clist_isempty(msg_att->att_list)) {
+ res = MAILIMAP_ERROR_FETCH;
+ goto free;
+ }
+
+ item = (struct mailimap_msg_att_item *) clist_begin(msg_att->att_list)->data;
+
+ if (item->att_type != MAILIMAP_MSG_ATT_ITEM_STATIC) {
+ res = MAILIMAP_ERROR_FETCH;
+ goto free;
+ }
+ if (item->att_data.att_static->att_type != MAILIMAP_MSG_ATT_RFC822) {
+ res = MAILIMAP_ERROR_FETCH;
+ goto free;
+ }
+
+ * result = item->att_data.att_static->att_data.att_rfc822.att_content;
+ item->att_data.att_static->att_data.att_rfc822.att_content = NULL;
+ mailimap_fetch_list_free(fetch_list);
+
+ return MAILIMAP_NO_ERROR;
+
+free:
+ mailimap_fetch_list_free(fetch_list);
+err:
+ return res;
+}
+
+int mailimap_fetch_rfc822_header(mailimap * session,
+ uint32_t msgid, char ** result)
+{
+ int r;
+ int res;
+ clist * fetch_list;
+ struct mailimap_fetch_att * fetch_att;
+ struct mailimap_fetch_type * fetch_type;
+ struct mailimap_set * set;
+ struct mailimap_msg_att * msg_att;
+ struct mailimap_msg_att_item * item;
+
+ fetch_att = mailimap_fetch_att_new_rfc822_header();
+ fetch_type = mailimap_fetch_type_new_fetch_att(fetch_att);
+ set = mailimap_set_new_single(msgid);
+
+ r = mailimap_fetch(session, set, fetch_type, &fetch_list);
+
+ mailimap_set_free(set);
+ mailimap_fetch_type_free(fetch_type);
+
+ if (r != MAILIMAP_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ if (clist_isempty(fetch_list)) {
+ res = MAILIMAP_ERROR_FETCH;
+ goto free;
+ }
+
+ msg_att = (struct mailimap_msg_att *) clist_begin(fetch_list)->data;
+
+ if (clist_isempty(msg_att->att_list)) {
+ res = MAILIMAP_ERROR_FETCH;
+ goto free;
+ }
+
+ item = (struct mailimap_msg_att_item *) clist_begin(msg_att->att_list)->data;
+
+ if (item->att_type != MAILIMAP_MSG_ATT_ITEM_STATIC) {
+ res = MAILIMAP_ERROR_FETCH;
+ goto err;
+ }
+
+ if (item->att_data.att_static->att_type != MAILIMAP_MSG_ATT_RFC822_HEADER) {
+ res = MAILIMAP_ERROR_FETCH;
+ goto err;
+ }
+
+ * result = item->att_data.att_static->att_data.att_rfc822_header.att_content;
+ item->att_data.att_static->att_data.att_rfc822_header.att_content = NULL;
+ mailimap_fetch_list_free(fetch_list);
+
+ return MAILIMAP_NO_ERROR;
+
+free:
+ mailimap_fetch_list_free(fetch_list);
+err:
+ return res;
+}
+
+int mailimap_fetch_envelope(mailimap * session,
+ uint32_t first, uint32_t last,
+ clist ** result)
+{
+ int r;
+ clist * fetch_list;
+ struct mailimap_fetch_att * fetch_att;
+ struct mailimap_fetch_type * fetch_type;
+ struct mailimap_set * set;
+
+ fetch_att = mailimap_fetch_att_new_envelope();
+ fetch_type = mailimap_fetch_type_new_fetch_att(fetch_att);
+ set = mailimap_set_new_interval(first, last);
+
+ r = mailimap_fetch(session, set, fetch_type, &fetch_list);
+
+ mailimap_set_free(set);
+ mailimap_fetch_type_free(fetch_type);
+
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ * result = fetch_list;
+
+ return MAILIMAP_NO_ERROR;
+}
+
+int mailimap_append_simple(mailimap * session, char * mailbox,
+ char * content, uint32_t size)
+{
+ return mailimap_append(session, mailbox, NULL, NULL, content, size);
+}
+
+int mailimap_login_simple(mailimap * session,
+ char * userid, char * password)
+{
+ if (session->imap_state == MAILIMAP_STATE_NON_AUTHENTICATED)
+ return mailimap_login(session, userid, password);
+ else
+ return MAILIMAP_NO_ERROR;
+}
+
diff --git a/libetpan/src/low-level/imap/mailimap_helper.h b/libetpan/src/low-level/imap/mailimap_helper.h
new file mode 100644
index 0000000..b548271
--- a/dev/null
+++ b/libetpan/src/low-level/imap/mailimap_helper.h
@@ -0,0 +1,66 @@
+/*
+ * 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$
+ */
+
+#ifndef MAILIMAP_HELPER_H
+
+#define MAILIMAP_HELPER_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <libetpan/mailimap_types.h>
+
+int mailimap_fetch_rfc822(mailimap * session,
+ uint32_t msgid, char ** result);
+
+int mailimap_fetch_rfc822_header(mailimap * session,
+ uint32_t msgid, char ** result);
+
+int mailimap_fetch_envelope(mailimap * session,
+ uint32_t first, uint32_t last,
+ clist ** result);
+
+int mailimap_append_simple(mailimap * session, char * mailbox,
+ char * content, uint32_t size);
+
+int mailimap_login_simple(mailimap * session,
+ char * userid, char * password);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libetpan/src/low-level/imap/mailimap_keywords.c b/libetpan/src/low-level/imap/mailimap_keywords.c
new file mode 100644
index 0000000..7e832a3
--- a/dev/null
+++ b/libetpan/src/low-level/imap/mailimap_keywords.c
@@ -0,0 +1,353 @@
+/*
+ * 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 "mailimap_keywords.h"
+#include "mailimap_types.h"
+#include <string.h>
+#include <stdio.h>
+
+#ifndef UNSTRICT_SYNTAX
+#define UNSTRICT_SYNTAX
+#endif
+
+struct mailimap_token_value {
+ int value;
+ const char * str;
+};
+
+int mailimap_token_case_insensitive_parse(mailstream * fd,
+ MMAPString * buffer,
+ size_t * index,
+ const char * token)
+{
+ int len;
+ size_t cur_token;
+ int r;
+
+ cur_token = * index;
+ len = strlen(token);
+
+#ifdef UNSTRICT_SYNTAX
+ r = mailimap_space_parse(fd, buffer, &cur_token);
+ if ((r != MAILIMAP_NO_ERROR) && (r != MAILIMAP_ERROR_PARSE))
+ return r;
+#endif
+
+ if (strncasecmp(buffer->str + cur_token, token, len) == 0) {
+ cur_token += len;
+ * index = cur_token;
+ return MAILIMAP_NO_ERROR;
+ }
+ else
+ return MAILIMAP_ERROR_PARSE;
+}
+
+
+static int is_space_or_tab(char ch)
+{
+ return (ch == ' ') || (ch == '\t');
+}
+
+int mailimap_char_parse(mailstream * fd, MMAPString * buffer,
+ size_t * index, char token)
+{
+ int cur_token;
+
+ cur_token = * index;
+
+ if (buffer->str[cur_token] == token) {
+ cur_token ++;
+ * index = cur_token;
+ return MAILIMAP_NO_ERROR;
+ }
+ else
+ return MAILIMAP_ERROR_PARSE;
+}
+
+int mailimap_space_parse(mailstream * fd, MMAPString * buffer,
+ size_t * index)
+{
+#ifdef UNSTRICT_SYNTAX
+
+ /* can accept unstrict syntax */
+ size_t cur_token;
+
+ cur_token = * index;
+
+ while (is_space_or_tab(* (buffer->str + cur_token)))
+ cur_token ++;
+
+ if (cur_token == * index)
+ return MAILIMAP_ERROR_PARSE;
+
+ * index = cur_token;
+
+ return MAILIMAP_NO_ERROR;
+
+#else
+ return mailimap_char_parse(fd, buffer, index, ' ');
+#endif
+}
+
+
+
+#define mailimap_get_token_str(index, tab) \
+ mailimap_get_token_str_size(index, tab, \
+ sizeof(tab) / sizeof(struct mailimap_token_value))
+
+#define mailimap_get_token_value(fd, buffer, index, tab) \
+ mailimap_get_token_value_size(fd, buffer, index, tab, \
+ sizeof(tab) / sizeof(struct mailimap_token_value))
+
+
+static const char * mailimap_get_token_str_size(int index,
+ struct mailimap_token_value * tab,
+ size_t size)
+{
+ size_t i;
+
+ for(i = 0 ; i < size ; i++)
+ if (index == tab[i].value)
+ return tab[i].str;
+
+ return NULL;
+}
+
+
+
+static int mailimap_get_token_value_size(mailstream * fd, MMAPString * buffer,
+ size_t * index,
+ struct mailimap_token_value * tab,
+ size_t size)
+{
+ size_t i;
+ int r;
+
+#ifdef UNSTRICT_SYNTAX
+ /* can accept unstrict syntax */
+ r = mailimap_space_parse(fd, buffer, index);
+ if ((r != MAILIMAP_NO_ERROR) && (r != MAILIMAP_ERROR_PARSE))
+ return r;
+#endif
+
+ for(i = 0 ; i < size ; i++) {
+ r = mailimap_token_case_insensitive_parse(fd, buffer, index, tab[i].str);
+ if (r == MAILIMAP_NO_ERROR)
+ return tab[i].value;
+ }
+
+ return -1;
+}
+
+
+static struct mailimap_token_value status_att_tab[] = {
+ {MAILIMAP_STATUS_ATT_MESSAGES, "MESSAGES"},
+ {MAILIMAP_STATUS_ATT_RECENT, "RECENT"},
+ {MAILIMAP_STATUS_ATT_UIDNEXT, "UIDNEXT"},
+ {MAILIMAP_STATUS_ATT_UIDVALIDITY, "UIDVALIDITY"},
+ {MAILIMAP_STATUS_ATT_UNSEEN, "UNSEEN"}
+};
+
+int mailimap_status_att_get_token_value(mailstream * fd, MMAPString * buffer,
+ size_t * index)
+{
+ int r;
+
+#ifdef UNSTRICT_SYNTAX
+ /* can accept unstrict syntax */
+ r = mailimap_space_parse(fd, buffer, index);
+ if ((r != MAILIMAP_NO_ERROR) && (r != MAILIMAP_ERROR_PARSE))
+ return r;
+#endif
+ return mailimap_get_token_value(fd, buffer, index,
+ status_att_tab);
+}
+
+
+const char * mailimap_status_att_get_token_str(size_t index)
+{
+ return mailimap_get_token_str(index, status_att_tab);
+}
+
+static struct mailimap_token_value month_tab[] = {
+ {1, "Jan"},
+ {2, "Feb"},
+ {3, "Mar"},
+ {4, "Apr"},
+ {5, "May"},
+ {6, "Jun"},
+ {7, "Jul"},
+ {8, "Aug"},
+ {9, "Sep"},
+ {10, "Oct"},
+ {11, "Nov"},
+ {12, "Dec"}
+};
+
+int mailimap_month_get_token_value(mailstream * fd, MMAPString * buffer,
+ size_t * index)
+{
+ return mailimap_get_token_value(fd, buffer, index, month_tab);
+}
+
+
+const char * mailimap_month_get_token_str(size_t index)
+{
+ return mailimap_get_token_str(index, month_tab);
+}
+
+
+
+
+
+static struct mailimap_token_value mailimap_flag_tab[] = {
+ {MAILIMAP_FLAG_ANSWERED, "\\Answered"},
+ {MAILIMAP_FLAG_FLAGGED, "\\Flagged"},
+ {MAILIMAP_FLAG_DELETED, "\\Deleted"},
+ {MAILIMAP_FLAG_SEEN, "\\Seen"},
+ {MAILIMAP_FLAG_DRAFT, "\\Draft"}
+};
+
+int mailimap_flag_get_token_value(mailstream * fd, MMAPString * buffer,
+ size_t * index)
+{
+ return mailimap_get_token_value(fd, buffer, index,
+ mailimap_flag_tab);
+}
+
+
+const char * mailimap_flag_get_token_str(size_t index)
+{
+ return mailimap_get_token_str(index, mailimap_flag_tab);
+}
+
+
+
+
+static struct mailimap_token_value encoding_tab[] = {
+ {MAILIMAP_BODY_FLD_ENC_7BIT, "7BIT"},
+ {MAILIMAP_BODY_FLD_ENC_8BIT, "8BIT"},
+ {MAILIMAP_BODY_FLD_ENC_BINARY, "BINARY"},
+ {MAILIMAP_BODY_FLD_ENC_BASE64, "BASE64"},
+ {MAILIMAP_BODY_FLD_ENC_QUOTED_PRINTABLE, "QUOTED-PRINTABLE"}
+};
+
+int mailimap_encoding_get_token_value(mailstream * fd, MMAPString * buffer,
+ size_t * index)
+{
+ return mailimap_get_token_value(fd, buffer, index, encoding_tab);
+}
+
+static struct mailimap_token_value mbx_list_sflag_tab[] = {
+ {MAILIMAP_MBX_LIST_SFLAG_MARKED, "\\Marked"},
+ {MAILIMAP_MBX_LIST_SFLAG_NOSELECT, "\\Noselect"},
+ {MAILIMAP_MBX_LIST_SFLAG_UNMARKED, "\\Unmarked"}
+};
+
+int mailimap_mbx_list_sflag_get_token_value(mailstream * fd,
+ MMAPString * buffer,
+ size_t * index)
+{
+ return mailimap_get_token_value(fd, buffer, index, mbx_list_sflag_tab);
+}
+
+static struct mailimap_token_value media_basic_tab[] = {
+ {MAILIMAP_MEDIA_BASIC_APPLICATION, "APPLICATION"},
+ {MAILIMAP_MEDIA_BASIC_AUDIO, "AUDIO"},
+ {MAILIMAP_MEDIA_BASIC_IMAGE, "IMAGE"},
+ {MAILIMAP_MEDIA_BASIC_MESSAGE, "MESSAGE"},
+ {MAILIMAP_MEDIA_BASIC_VIDEO, "VIDEO"}
+};
+
+int mailimap_media_basic_get_token_value(mailstream * fd, MMAPString * buffer,
+ size_t * index)
+{
+ return mailimap_get_token_value(fd, buffer, index, media_basic_tab);
+}
+
+static struct mailimap_token_value resp_cond_state_tab[] = {
+ {MAILIMAP_RESP_COND_STATE_OK, "OK"},
+ {MAILIMAP_RESP_COND_STATE_NO, "NO"},
+ {MAILIMAP_RESP_COND_STATE_BAD, "BAD"}
+};
+
+int mailimap_resp_cond_state_get_token_value(mailstream * fd,
+ MMAPString * buffer,
+ size_t * index)
+{
+ return mailimap_get_token_value(fd, buffer, index, resp_cond_state_tab);
+}
+
+static struct mailimap_token_value resp_text_code_1_tab[] = {
+ {MAILIMAP_RESP_TEXT_CODE_ALERT, "ALERT"},
+ {MAILIMAP_RESP_TEXT_CODE_PARSE, "PARSE"},
+ {MAILIMAP_RESP_TEXT_CODE_READ_ONLY, "READ-ONLY"},
+ {MAILIMAP_RESP_TEXT_CODE_READ_WRITE, "READ-WRITE"},
+ {MAILIMAP_RESP_TEXT_CODE_TRY_CREATE, "TRYCREATE"}
+};
+
+int mailimap_resp_text_code_1_get_token_value(mailstream * fd,
+ MMAPString * buffer,
+ size_t * index)
+{
+ return mailimap_get_token_value(fd, buffer, index, resp_text_code_1_tab);
+}
+
+static struct mailimap_token_value resp_text_code_2_tab[] = {
+ {MAILIMAP_RESP_TEXT_CODE_UIDNEXT, "UIDNEXT"},
+ {MAILIMAP_RESP_TEXT_CODE_UIDVALIDITY, "UIDVALIDITY"},
+ {MAILIMAP_RESP_TEXT_CODE_UNSEEN, "UNSEEN"},
+};
+
+int mailimap_resp_text_code_2_get_token_value(mailstream * fd,
+ MMAPString * buffer,
+ size_t * index)
+{
+ return mailimap_get_token_value(fd, buffer, index, resp_text_code_2_tab);
+}
+
+static struct mailimap_token_value section_msgtext_tab[] = {
+ {MAILIMAP_SECTION_MSGTEXT_HEADER_FIELDS_NOT, "HEADER.FIELDS.NOT"},
+ {MAILIMAP_SECTION_MSGTEXT_HEADER_FIELDS, "HEADER.FIELDS"},
+ {MAILIMAP_SECTION_MSGTEXT_HEADER, "HEADER"},
+ {MAILIMAP_SECTION_MSGTEXT_TEXT, "TEXT"}
+};
+
+int mailimap_section_msgtext_get_token_value(mailstream * fd,
+ MMAPString * buffer,
+ size_t * index)
+{
+ return mailimap_get_token_value(fd, buffer, index, section_msgtext_tab);
+}
diff --git a/libetpan/src/low-level/imap/mailimap_keywords.h b/libetpan/src/low-level/imap/mailimap_keywords.h
new file mode 100644
index 0000000..e00f687
--- a/dev/null
+++ b/libetpan/src/low-level/imap/mailimap_keywords.h
@@ -0,0 +1,107 @@
+/*
+ * 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$
+ */
+
+#ifndef MAILIMAP_COMMON_H
+
+#define MAILIMAP_COMMON_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "mailstream.h"
+
+
+/* tools */
+
+int mailimap_char_parse(mailstream * fd, MMAPString * buffer,
+ size_t * index, char token);
+
+int mailimap_space_parse(mailstream * fd, MMAPString * buffer,
+ size_t * index);
+
+/* tokens */
+
+int mailimap_token_case_insensitive_parse(mailstream * fd,
+ MMAPString * buffer,
+ size_t * index,
+ const char * token);
+
+int mailimap_status_att_get_token_value(mailstream * fd, MMAPString * buffer,
+ size_t * index);
+const char * mailimap_status_att_get_token_str(size_t index);
+
+
+int mailimap_month_get_token_value(mailstream * fd, MMAPString * buffer,
+ size_t * index);
+const char * mailimap_month_get_token_str(size_t index);
+
+
+int mailimap_flag_get_token_value(mailstream * fd, MMAPString * buffer,
+ size_t * index);
+
+const char * mailimap_flag_get_token_str(size_t index);
+
+int mailimap_encoding_get_token_value(mailstream * fd, MMAPString * buffer,
+ size_t * index);
+
+int mailimap_mbx_list_sflag_get_token_value(mailstream * fd,
+ MMAPString * buffer,
+ size_t * index);
+
+int mailimap_media_basic_get_token_value(mailstream * fd, MMAPString * buffer,
+ size_t * index);
+
+int mailimap_resp_cond_state_get_token_value(mailstream * fd,
+ MMAPString * buffer,
+ size_t * index);
+
+int mailimap_resp_text_code_1_get_token_value(mailstream * fd,
+ MMAPString * buffer,
+ size_t * index);
+
+int mailimap_resp_text_code_2_get_token_value(mailstream * fd,
+ MMAPString * buffer,
+ size_t * index);
+
+int mailimap_section_msgtext_get_token_value(mailstream * fd,
+ MMAPString * buffer,
+ size_t * index);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
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 <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#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 = <any CHAR except atom-specials>
+*/
+
+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, &param_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, &section,
+ 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 = <any TEXT-CHAR except quoted-specials> /
+ "\" 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,
+ &quoted_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*<any TEXT-CHAR except "]">]
+*/
+
+/*
+ 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*<any TEXT-CHAR except "]">]
+*/
+
+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*<any TEXT-CHAR except "]"
+*/
+
+static int
+mailimap_resp_text_code_other_2_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_1);
+}
+
+/*
+ SP 1*<any TEXT-CHAR except "]">
+*/
+
+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*<any TEXT-CHAR except "]">]
+*/
+
+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*<any TEXT-CHAR except "]">]
+*/
+
+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, &section_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, &section_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,
+ &section_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,
+ &section_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, &section_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, &section_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 "+">
+*/
+
+/*
+ any ASTRING-CHAR except "+"
+*/
+
+static int is_tag_char(char ch)
+{
+ if (ch == '+')
+ return FALSE;
+ return is_astring_char(ch);
+}
+
+/*
+ tag = 1*<any ASTRING-CHAR except "+">
+*/
+
+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 = <any CHAR except CR and LF>
+*/
+
+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 <experimental command arguments>
+*/
+
+/*
+ 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;
+}
diff --git a/libetpan/src/low-level/imap/mailimap_parser.h b/libetpan/src/low-level/imap/mailimap_parser.h
new file mode 100644
index 0000000..e20a310
--- a/dev/null
+++ b/libetpan/src/low-level/imap/mailimap_parser.h
@@ -0,0 +1,69 @@
+/*
+ * 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$
+ */
+
+#ifndef MAILIMAP_PARSER_H
+
+#define MAILIMAP_PARSER_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "mailimap_types.h"
+
+int mailimap_greeting_parse(mailstream * fd, MMAPString * buffer,
+ size_t * index,
+ struct mailimap_greeting ** result,
+ size_t progr_rate,
+ progress_function * progr_fun);
+
+int
+mailimap_response_parse(mailstream * fd, MMAPString * buffer,
+ size_t * index, struct mailimap_response ** result,
+ size_t progr_rate,
+ progress_function * progr_fun);
+
+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);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libetpan/src/low-level/imap/mailimap_print.c b/libetpan/src/low-level/imap/mailimap_print.c
new file mode 100644
index 0000000..005cf09
--- a/dev/null
+++ b/libetpan/src/low-level/imap/mailimap_print.c
@@ -0,0 +1,1615 @@
+/*
+ * 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$
+ */
+#ifdef DEBUG
+#include "mailimap_print.h"
+
+#include <stdio.h>
+
+static void mailimap_body_fields_print(struct mailimap_body_fields *
+ body_fields);
+static void mailimap_envelope_print(struct mailimap_envelope * env);
+static void mailimap_body_print(struct mailimap_body * body);
+static void mailimap_body_fld_enc_print(struct mailimap_body_fld_enc *
+ fld_enc);
+
+static int indent_size = 0;
+
+static void indent()
+{
+ indent_size ++;
+}
+
+static void unindent()
+{
+ indent_size --;
+}
+
+static void print_indent()
+{
+ int i;
+
+ for (i = 0 ; i < indent_size ; i++)
+ printf(" ");
+}
+
+
+static void mailimap_body_fld_lang_print(struct mailimap_body_fld_lang *
+ fld_lang)
+{
+ clistiter * cur;
+
+ print_indent();
+ printf("body-fld-lang { ");
+
+ switch (fld_lang->lg_type) {
+ case MAILIMAP_BODY_FLD_LANG_SINGLE:
+ printf("%s ", fld_lang->lg_data.lg_single);
+ break;
+
+ case MAILIMAP_BODY_FLD_LANG_LIST:
+ for(cur = clist_begin(fld_lang->lg_data.lg_list) ;
+ cur != NULL ; cur = clist_next(cur)) {
+ char * lang;
+
+ lang = clist_content(cur);
+
+ printf("%s ", lang);
+ }
+ break;
+ }
+
+ print_indent();
+ printf("}\n");
+}
+
+static void
+mailimap_single_body_fld_param_print(struct mailimap_single_body_fld_param *
+ single)
+{
+ printf("(%s = %s)", single->pa_name, single->pa_value);
+}
+
+static void mailimap_body_fld_param_print(struct mailimap_body_fld_param *
+ fld_param)
+{
+ clistiter * cur;
+
+ print_indent();
+ printf("body-fld-param { ");
+
+ for(cur = clist_begin(fld_param->pa_list) ; cur != NULL ;
+ cur = clist_next(cur)) {
+ struct mailimap_single_body_fld_param * single;
+
+ single = clist_content(cur);
+
+ mailimap_single_body_fld_param_print(single);
+ printf(" ");
+ }
+ printf("\n");
+}
+
+static void mailimap_body_fld_dsp_print(struct mailimap_body_fld_dsp * fld_dsp)
+{
+ print_indent();
+ printf("body-fld-dsp {\n");
+ indent();
+
+ print_indent();
+ printf("name { %s }\n", fld_dsp->dsp_type);
+
+ mailimap_body_fld_param_print(fld_dsp->dsp_attributes);
+
+ unindent();
+ print_indent();
+ printf("}\n");
+}
+
+static void mailimap_body_extension_list_print(clist * ext_list);
+
+static void mailimap_body_extension_print(struct mailimap_body_extension * ext)
+{
+ print_indent();
+ printf("body-extention {\n");
+ indent();
+
+ switch (ext->ext_type) {
+ case MAILIMAP_BODY_EXTENSION_NSTRING:
+ print_indent();
+ printf("%s\n", ext->ext_data.ext_nstring);
+ break;
+ case MAILIMAP_BODY_EXTENSION_NUMBER:
+ print_indent();
+ printf("%i\n", ext->ext_data.ext_number);
+ break;
+ case MAILIMAP_BODY_EXTENSION_LIST:
+ mailimap_body_extension_list_print(ext->ext_data.ext_body_extension_list);
+ break;
+ }
+
+ unindent();
+ print_indent();
+ printf("}\n");
+
+}
+
+static void mailimap_body_extension_list_print(clist * ext_list)
+{
+ clistiter * cur;
+
+ print_indent();
+ printf("body-extention-list {\n");
+ indent();
+
+ for (cur = clist_begin(ext_list) ; cur != NULL ;
+ cur = clist_next(cur)) {
+ struct mailimap_body_extension * ext;
+
+ ext = clist_content(cur);
+
+ mailimap_body_extension_print(ext);
+ }
+
+ unindent();
+ print_indent();
+ printf("}");
+}
+
+static void mailimap_body_ext_1part_print(struct mailimap_body_ext_1part *
+ body_ext_1part)
+{
+ print_indent();
+ printf("body-type-1part {\n");
+ indent();
+
+ print_indent();
+ printf("md5 { %s }\n", body_ext_1part->bd_md5);
+ if (body_ext_1part->bd_disposition) {
+ mailimap_body_fld_dsp_print(body_ext_1part->bd_disposition);
+ if (body_ext_1part->bd_language) {
+ mailimap_body_fld_lang_print(body_ext_1part->bd_language);
+
+ if (body_ext_1part->bd_extension_list)
+ mailimap_body_extension_list_print(body_ext_1part->bd_extension_list);
+ }
+ }
+
+ unindent();
+ print_indent();
+ printf("}\n");
+}
+
+static void mailimap_body_type_text_print(struct mailimap_body_type_text *
+ body_type_text)
+{
+ print_indent();
+ printf("body-type-text {\n");
+ indent();
+
+ print_indent();
+ printf("media-text { %s }\n", body_type_text->bd_media_text);
+ mailimap_body_fields_print(body_type_text->bd_fields);
+ print_indent();
+ printf("lines { %i }\n", body_type_text->bd_lines);
+
+ unindent();
+ print_indent();
+ printf("}\n");
+}
+
+static void mailimap_body_type_msg_print(struct mailimap_body_type_msg *
+ body_type_msg)
+{
+ print_indent();
+ printf("body-type-msg {\n");
+ indent();
+
+ mailimap_body_fields_print(body_type_msg->bd_fields);
+ mailimap_envelope_print(body_type_msg->bd_envelope);
+ mailimap_body_print(body_type_msg->bd_body);
+
+ print_indent();
+ printf("lines { %i }\n", body_type_msg->bd_lines);
+
+ unindent();
+ print_indent();
+ printf("}\n");
+}
+
+
+static void mailimap_body_fld_enc_print(struct mailimap_body_fld_enc * fld_enc)
+{
+ print_indent();
+ printf("body-fld-enc { ");
+
+ switch (fld_enc->enc_type) {
+ case MAILIMAP_BODY_FLD_ENC_7BIT:
+ print_indent();
+ printf("7bit");
+ break;
+ case MAILIMAP_BODY_FLD_ENC_8BIT:
+ printf("8bit");
+ break;
+ case MAILIMAP_BODY_FLD_ENC_BINARY:
+ printf("binary");
+ break;
+ case MAILIMAP_BODY_FLD_ENC_BASE64:
+ printf("base64");
+ break;
+ case MAILIMAP_BODY_FLD_ENC_QUOTED_PRINTABLE:
+ printf("quoted-printable");
+ break;
+ case MAILIMAP_BODY_FLD_ENC_OTHER:
+ printf("%s", fld_enc->enc_value);
+ break;
+ }
+
+ printf("}\n");
+}
+
+static void mailimap_body_fields_print(struct mailimap_body_fields *
+ body_fields)
+{
+ print_indent();
+ printf("body-fields {\n");
+ indent();
+
+ mailimap_body_fld_param_print(body_fields->bd_parameter);
+
+ print_indent();
+ printf("body-fld-id { %s }\n", body_fields->bd_id);
+ printf("body-fld-desc { %s }\n", body_fields->bd_description);
+ mailimap_body_fld_enc_print(body_fields->bd_encoding);
+ printf("body-fld-octets { %i }\n", body_fields->bd_size);
+
+ unindent();
+ print_indent();
+ printf("}\n");
+}
+
+static void mailimap_media_basic_print(struct mailimap_media_basic *
+ media_basic)
+{
+ print_indent();
+ printf("media-basic {");
+
+ switch (media_basic->med_type) {
+ case MAILIMAP_MEDIA_BASIC_APPLICATION:
+ printf("application");
+ break;
+ case MAILIMAP_MEDIA_BASIC_AUDIO:
+ printf("audio");
+ break;
+ case MAILIMAP_MEDIA_BASIC_IMAGE:
+ printf("image");
+ break;
+ case MAILIMAP_MEDIA_BASIC_MESSAGE:
+ printf("message");
+ break;
+ case MAILIMAP_MEDIA_BASIC_VIDEO:
+ printf("video");
+ break;
+ case MAILIMAP_MEDIA_BASIC_OTHER:
+ printf("%s", media_basic->med_basic_type);
+ break;
+ }
+ printf(" / %s }\n", media_basic->med_subtype);
+}
+
+static void mailimap_body_type_basic_print(struct mailimap_body_type_basic *
+ body_type_basic)
+{
+ print_indent();
+ printf("body-type-basic {\n");
+ indent();
+
+ mailimap_media_basic_print(body_type_basic->bd_media_basic);
+ mailimap_body_fields_print(body_type_basic->bd_fields);
+
+ unindent();
+ print_indent();
+ printf("}\n");
+}
+
+static void mailimap_body_type_1part_print(struct mailimap_body_type_1part *
+ body_type_1part)
+{
+ print_indent();
+ printf("body-type-1part {\n");
+ indent();
+
+ switch (body_type_1part->bd_type) {
+ case MAILIMAP_BODY_TYPE_1PART_BASIC:
+ mailimap_body_type_basic_print(body_type_1part->bd_data.bd_type_basic);
+ break;
+
+ case MAILIMAP_BODY_TYPE_1PART_MSG:
+ mailimap_body_type_msg_print(body_type_1part->bd_data.bd_type_msg);
+ break;
+
+ case MAILIMAP_BODY_TYPE_1PART_TEXT:
+ mailimap_body_type_text_print(body_type_1part->bd_data.bd_type_text);
+ break;
+ }
+
+ if (body_type_1part->bd_ext_1part != NULL)
+ mailimap_body_ext_1part_print(body_type_1part->bd_ext_1part);
+
+ unindent();
+ print_indent();
+ printf("\n");
+}
+
+static void mailimap_body_ext_mpart(struct mailimap_body_ext_mpart * ext_mpart)
+{
+ print_indent();
+ printf("body-ext-mpart {\n");
+ indent();
+
+ mailimap_body_fld_param_print(ext_mpart->bd_parameter);
+ if (ext_mpart->bd_disposition) {
+ mailimap_body_fld_dsp_print(ext_mpart->bd_disposition);
+ if (ext_mpart->bd_language) {
+ mailimap_body_fld_lang_print(ext_mpart->bd_language);
+
+ if (ext_mpart->bd_extension_list)
+ mailimap_body_extension_list_print(ext_mpart->bd_extension_list);
+ }
+ }
+
+ unindent();
+ print_indent();
+ printf("\n");
+}
+
+static void mailimap_body_type_mpart_print(struct mailimap_body_type_mpart *
+ mpart)
+{
+ clistiter * cur;
+
+ print_indent();
+ printf("body-type-mpart {\n");
+ indent();
+
+ for(cur = clist_begin(mpart->bd_list) ; cur != NULL ;
+ cur = clist_next(cur)) {
+ struct mailimap_body * body;
+
+ body = clist_content(cur);
+
+ mailimap_body_print(body);
+ }
+
+ printf("media-subtype { %s }\n", mpart->bd_media_subtype);
+
+ if (mpart->bd_ext_mpart)
+ mailimap_body_ext_mpart(mpart->bd_ext_mpart);
+
+ unindent();
+ print_indent();
+ printf("}\n");
+}
+
+
+static void mailimap_body_print(struct mailimap_body * body)
+{
+ print_indent();
+ printf("body {\n");
+ indent();
+
+ switch (body->bd_type) {
+ case MAILIMAP_BODY_1PART:
+ mailimap_body_type_1part_print(body->bd_data.bd_body_1part);
+ break;
+ case MAILIMAP_BODY_MPART:
+ mailimap_body_type_mpart_print(body->bd_data.bd_body_mpart);
+ break;
+ }
+
+ unindent();
+ print_indent();
+ printf("}\n");
+}
+
+static void mailimap_date_time_print(struct mailimap_date_time * date_time)
+{
+ print_indent();
+ printf("date-time { %i/%i/%i - %i:%i:%i %i }\n",
+ date_time->dt_day, date_time->dt_month, date_time->dt_year,
+ date_time->dt_hour, date_time->dt_min, date_time->dt_month,
+ date_time->dt_zone);
+}
+
+static void mailimap_address_print(struct mailimap_address * address)
+{
+ print_indent();
+ printf("address { name: %s, addr: %s, mailbox: %s, host: %s) }\n",
+ address->ad_personal_name, address->ad_source_route,
+ address->ad_mailbox_name, address->ad_host_name);
+}
+
+static void mailimap_envelope_address_list_print(clist * address)
+{
+ clistiter * cur;
+
+ print_indent();
+ printf("envelope-address-list {\n");
+ indent();
+
+ for(cur = clist_begin(address) ; cur != NULL ;
+ cur = clist_next(cur)) {
+ struct mailimap_address * addr;
+
+ addr = clist_content(cur);
+
+ mailimap_address_print(addr);
+ }
+
+ unindent();
+ print_indent();
+ printf("}\n");
+}
+
+static void mailimap_envelope_print(struct mailimap_envelope * env)
+{
+ print_indent();
+ printf("envelope {\n");
+ indent();
+
+ print_indent();
+ printf("date { %s }\n", env->env_date);
+
+ print_indent();
+ printf("subject { %s }\n", env->env_subject);
+
+ print_indent();
+ printf("from {\n");
+ indent();
+ mailimap_envelope_address_list_print(env->env_from->frm_list);
+ unindent();
+ print_indent();
+ printf("}\n");
+
+ print_indent();
+ printf("sender {\n");
+ indent();
+ mailimap_envelope_address_list_print(env->env_sender->snd_list);
+ unindent();
+ print_indent();
+ printf("}\n");
+
+ print_indent();
+ printf("reply-to {\n");
+ indent();
+ mailimap_envelope_address_list_print(env->env_reply_to->rt_list);
+ unindent();
+ print_indent();
+ printf("}\n");
+
+ print_indent();
+ printf("to {\n");
+ indent();
+ mailimap_envelope_address_list_print(env->env_to->to_list);
+ unindent();
+ print_indent();
+ printf("}\n");
+
+ print_indent();
+ printf("cc {\n");
+ indent();
+ mailimap_envelope_address_list_print(env->env_cc->cc_list);
+ unindent();
+ print_indent();
+ printf("}\n");
+
+ print_indent();
+ printf("bcc {\n");
+ indent();
+ mailimap_envelope_address_list_print(env->env_bcc->bcc_list);
+ unindent();
+ print_indent();
+ printf("}\n");
+
+ printf("in-reply-to { %s }\n", env->env_in_reply_to);
+ printf("message-id { %s }\n", env->env_message_id);
+
+ unindent();
+ print_indent();
+ printf("}\n");
+}
+
+static void mailimap_header_list_print(struct mailimap_header_list *
+ header_list)
+{
+ clistiter * cur;
+
+ print_indent();
+ printf("header-list { ");
+ for(cur = clist_begin(header_list->hdr_list) ; cur != NULL ;
+ cur = clist_next(cur))
+ printf("%s ", (char *) clist_content(cur));
+ printf("}\n");
+}
+
+static void mailimap_section_msgtext_print(struct mailimap_section_msgtext *
+ section_msgtext)
+{
+ print_indent();
+ printf("section-msgtext {\n");
+ indent();
+
+ switch(section_msgtext->sec_type) {
+ case MAILIMAP_SECTION_MSGTEXT_HEADER:
+ print_indent();
+ printf("header\n");
+ break;
+
+ case MAILIMAP_SECTION_MSGTEXT_HEADER_FIELDS:
+ print_indent();
+ printf("header fields {");
+ indent();
+ mailimap_header_list_print(section_msgtext->sec_header_list);
+ unindent();
+ print_indent();
+ printf("}\n");
+ break;
+
+ case MAILIMAP_SECTION_MSGTEXT_HEADER_FIELDS_NOT:
+ print_indent();
+ printf("header fields not {");
+ indent();
+ mailimap_header_list_print(section_msgtext->sec_header_list);
+ unindent();
+ print_indent();
+ printf("}\n");
+ break;
+
+ case MAILIMAP_SECTION_MSGTEXT_TEXT:
+ print_indent();
+ printf("text\n");
+ break;
+ }
+
+ unindent();
+ print_indent();
+ printf("}\n");
+}
+
+static void mailimap_section_part_print(struct mailimap_section_part *
+ section_part)
+{
+ clistiter * cur;
+
+ print_indent();
+ printf("section-part { ");
+
+ for(cur = clist_begin(section_part->sec_id) ;
+ cur != NULL ; cur = clist_next(cur)) {
+ printf("%i", * ((uint32_t *) clist_content(cur)));
+ if (clist_next(cur) != NULL)
+ printf(".");
+ }
+ printf(" }\n");
+}
+
+static void mailimap_section_text_print(struct mailimap_section_text *
+ section_text)
+{
+ print_indent();
+ printf("section-text {\n");
+ indent();
+
+ switch (section_text->sec_type) {
+ case MAILIMAP_SECTION_TEXT_MIME:
+ print_indent();
+ printf("MIME");
+ break;
+ case MAILIMAP_SECTION_TEXT_SECTION_MSGTEXT:
+ mailimap_section_msgtext_print(section_text->sec_msgtext);
+ break;
+ }
+
+ unindent();
+ print_indent();
+ printf("}\n");
+}
+
+static void mailimap_section_spec_print(struct mailimap_section_spec *
+ section_spec)
+{
+ print_indent();
+ printf("section-spec {");
+ indent();
+
+ switch(section_spec->sec_type) {
+ case MAILIMAP_SECTION_SPEC_SECTION_MSGTEXT:
+ mailimap_section_msgtext_print(section_spec->sec_data.sec_msgtext);
+ break;
+ case MAILIMAP_SECTION_SPEC_SECTION_PART:
+ mailimap_section_part_print(section_spec->sec_data.sec_part);
+ if (section_spec->sec_text != NULL)
+ mailimap_section_text_print(section_spec->sec_text);
+ break;
+ }
+
+ unindent();
+ print_indent();
+ printf("}\n");
+}
+
+static void mailimap_section_print(struct mailimap_section * section)
+{
+ print_indent();
+ printf("section {\n");
+ indent();
+
+ if (section != NULL)
+ if (section->sec_spec != NULL)
+ mailimap_section_spec_print(section->sec_spec);
+
+ unindent();
+ print_indent();
+ printf("}\n");
+}
+
+static void mailimap_msg_att_body_section_print(struct
+ mailimap_msg_att_body_section *
+ msg_att_body_section)
+{
+ print_indent();
+ printf("msg-att-body-section {\n");
+ indent();
+
+ mailimap_section_print(msg_att_body_section->sec_section);
+ printf("origin-octet: %i\n", msg_att_body_section->sec_origin_octet);
+ printf("body-part: %s\n", msg_att_body_section->sec_body_part);
+
+ unindent();
+ print_indent();
+ printf("}\n");
+}
+
+
+static void mailimap_msg_att_static_print(struct mailimap_msg_att_static *
+ msg_att_static)
+{
+ print_indent();
+ printf("msg-att-static {\n");
+ indent();
+
+ switch (msg_att_static->att_type) {
+
+ case MAILIMAP_MSG_ATT_ENVELOPE:
+ print_indent();
+ printf("envelope {\n");
+ indent();
+ print_indent();
+ mailimap_envelope_print(msg_att_static->att_data.att_env);
+ unindent();
+ print_indent();
+ printf("}\n");
+ break;
+
+ case MAILIMAP_MSG_ATT_INTERNALDATE:
+ print_indent();
+ printf("internaldate {\n");
+ indent();
+ print_indent();
+ mailimap_date_time_print(msg_att_static->att_data.att_internal_date);
+ unindent();
+ print_indent();
+ printf("}\n");
+ break;
+
+ case MAILIMAP_MSG_ATT_RFC822:
+ print_indent();
+ printf("rfc822 {\n");
+ printf("%s\n", msg_att_static->att_data.att_rfc822.att_content);
+ print_indent();
+ printf("}\n");
+ break;
+
+ case MAILIMAP_MSG_ATT_RFC822_HEADER:
+ print_indent();
+ printf("rfc822-header {\n");
+ printf("%s\n", msg_att_static->att_data.att_rfc822_header.att_content);
+ print_indent();
+ printf("}\n");
+ break;
+
+ case MAILIMAP_MSG_ATT_RFC822_TEXT:
+ print_indent();
+ printf("rfc822-text {\n");
+ printf("%s\n", msg_att_static->att_data.att_rfc822_text.att_content);
+ print_indent();
+ printf("}\n");
+ break;
+
+ case MAILIMAP_MSG_ATT_RFC822_SIZE:
+ print_indent();
+ printf("rfc822-size { %i }\n", msg_att_static->att_data.att_rfc822_size);
+ break;
+
+ case MAILIMAP_MSG_ATT_BODY:
+ print_indent();
+ printf("body {\n");
+ indent();
+ print_indent();
+ mailimap_body_print(msg_att_static->att_data.att_body);
+ unindent();
+ print_indent();
+ printf("}\n");
+ break;
+
+ case MAILIMAP_MSG_ATT_BODYSTRUCTURE:
+ print_indent();
+ printf("bodystructure {\n");
+ indent();
+ print_indent();
+ mailimap_body_print(msg_att_static->att_data.att_bodystructure);
+ unindent();
+ print_indent();
+ printf("}\n");
+ break;
+
+ case MAILIMAP_MSG_ATT_BODY_SECTION:
+ print_indent();
+ printf("body-section {\n");
+ indent();
+ print_indent();
+ mailimap_msg_att_body_section_print(msg_att_static->att_data.att_body_section);
+ unindent();
+ print_indent();
+ printf("}\n");
+ break;
+
+ case MAILIMAP_MSG_ATT_UID:
+ printf("uid { %i }\n", msg_att_static->att_data.att_uid);
+ break;
+ }
+
+ unindent();
+ print_indent();
+ printf("}\n");
+}
+
+static void mailimap_flag_print(struct mailimap_flag * flag);
+
+static void mailimap_flag_fetch_print(struct mailimap_flag_fetch * flag)
+{
+ print_indent();
+ printf("flag fetch {\n");
+ indent();
+
+ switch (flag->fl_type) {
+ case MAILIMAP_FLAG_FETCH_RECENT:
+ printf("recent\n");
+ break;
+ case MAILIMAP_FLAG_FETCH_OTHER:
+ print_indent();
+ printf("flag {\n");
+ indent();
+ mailimap_flag_print(flag->fl_flag);
+ unindent();
+ print_indent();
+ printf("}\n");
+ break;
+ }
+
+ unindent();
+ print_indent();
+ printf("}\n");
+}
+
+static void mailimap_msg_att_dynamic_print(struct mailimap_msg_att_dynamic *
+ dynamic)
+{
+ clistiter * cur;
+
+ print_indent();
+ printf("msg-att-dynamic {\n");
+ indent();
+
+ for(cur = clist_begin(dynamic->att_list) ; cur != NULL ;
+ cur = clist_next(cur)) {
+ struct mailimap_flag_fetch * flag;
+
+ flag = (struct mailimap_flag_fetch *) clist_content(cur);
+ mailimap_flag_fetch_print(flag);
+ }
+
+ unindent();
+ print_indent();
+ printf("}\n");
+}
+
+static void mailimap_msg_att_item_print(struct mailimap_msg_att_item * item)
+{
+ print_indent();
+ printf("msg-att-item {\n");
+ indent();
+
+ switch (item->att_type) {
+ case MAILIMAP_MSG_ATT_ITEM_DYNAMIC:
+ mailimap_msg_att_dynamic_print(item->att_data.att_dyn);
+ break;
+ case MAILIMAP_MSG_ATT_ITEM_STATIC:
+ mailimap_msg_att_static_print(item->att_data.att_static);
+ break;
+ }
+
+ unindent();
+ print_indent();
+ printf("}\n");
+}
+
+static void mailimap_msg_att_print(struct mailimap_msg_att * msg_att)
+{
+ clistiter * cur;
+
+ print_indent();
+ printf("msg-att {\n");
+ indent();
+
+ for(cur = clist_begin(msg_att->att_list) ; cur != NULL ;
+ cur = clist_next(cur)) {
+ struct mailimap_msg_att_item * item;
+
+ item = clist_content(cur);
+
+ mailimap_msg_att_item_print(item);
+ }
+
+ unindent();
+ print_indent();
+ printf("}\n");
+}
+
+static void mailimap_message_data_print(struct mailimap_message_data *
+ msg_data)
+{
+ print_indent();
+ printf("message-data {\n");
+ indent();
+
+ switch (msg_data->mdt_type) {
+ case MAILIMAP_MESSAGE_DATA_EXPUNGE:
+ print_indent();
+ printf("expunged { %i }\n", msg_data->mdt_number);
+ break;
+ case MAILIMAP_MESSAGE_DATA_FETCH:
+ print_indent();
+ printf("message-number { %i }\n", msg_data->mdt_number);
+ mailimap_msg_att_print(msg_data->mdt_msg_att);
+ break;
+ }
+
+ unindent();
+ print_indent();
+ printf("}\n");
+}
+
+static void mailimap_status_att_print(int status_att)
+{
+ print_indent();
+ printf("status-att { ");
+
+ switch(status_att) {
+ case MAILIMAP_STATUS_ATT_MESSAGES:
+ printf("messages");
+ break;
+ case MAILIMAP_STATUS_ATT_RECENT:
+ printf("recent");
+ break;
+ case MAILIMAP_STATUS_ATT_UIDNEXT:
+ printf("uidnext");
+ break;
+ case MAILIMAP_STATUS_ATT_UIDVALIDITY:
+ printf("status att uidvalidity");
+ break;
+ case MAILIMAP_STATUS_ATT_UNSEEN:
+ printf("status att unseen");
+ break;
+ }
+
+ printf(" \n");
+}
+
+static void
+mailimap_status_info_print(struct mailimap_status_info * info)
+{
+ print_indent();
+ printf("status-info {\n");
+ indent();
+
+ mailimap_status_att_print(info->st_att);
+
+ print_indent();
+ printf("value { %i }\n", info->st_value);
+
+ unindent();
+ print_indent();
+ printf("}\n");
+}
+
+static void
+mailimap_mailbox_data_status_print(struct mailimap_mailbox_data_status *
+ mb_data_status)
+{
+ clistiter * cur;
+
+ print_indent();
+ printf("mailbox-data-status {\n");
+ indent();
+
+ print_indent();
+ printf("mailbox { %s }\n", mb_data_status->st_mailbox);
+
+ for(cur = clist_begin(mb_data_status->st_info_list) ;
+ cur != NULL ; cur = clist_next(cur)) {
+ struct mailimap_status_info * info;
+
+ info = clist_content(cur);
+
+ mailimap_status_info_print(info);
+ }
+
+ unindent();
+ print_indent();
+ printf("}\n");
+}
+
+static void mailimap_mbx_list_oflag_print(struct mailimap_mbx_list_oflag *
+ oflag)
+{
+ print_indent();
+ printf("mbx-list-oflag { ");
+
+ switch (oflag->of_type) {
+ case MAILIMAP_MBX_LIST_OFLAG_NOINFERIORS:
+ printf("noinferiors");
+ break;
+ case MAILIMAP_MBX_LIST_OFLAG_FLAG_EXT:
+ printf("%s", oflag->of_flag_ext);
+ break;
+ }
+
+ printf(" }\n");
+}
+
+static void mailimap_mbx_list_sflag_print(int sflag)
+{
+ print_indent();
+ printf("mbx-list-sflag { ");
+
+ switch (sflag) {
+ case MAILIMAP_MBX_LIST_SFLAG_MARKED:
+ printf("marked");
+ break;
+ case MAILIMAP_MBX_LIST_SFLAG_NOSELECT:
+ printf("noselected");
+ break;
+ case MAILIMAP_MBX_LIST_SFLAG_UNMARKED:
+ printf("unmarked");
+ break;
+ }
+
+ printf(" }\n");
+}
+
+static void mailimap_mbx_list_flags_print(struct mailimap_mbx_list_flags *
+ mbx_list_flags)
+{
+ clistiter * cur;
+
+ print_indent();
+ printf("mbx-list-flags {");
+ indent();
+
+ if (mbx_list_flags->mbf_type == MAILIMAP_MBX_LIST_FLAGS_SFLAG)
+ mailimap_mbx_list_sflag_print(mbx_list_flags->mbf_sflag);
+
+ for(cur = clist_begin(mbx_list_flags->mbf_oflags) ; cur != NULL ;
+ cur = clist_next(cur)) {
+ struct mailimap_mbx_list_oflag * oflag;
+
+ oflag = clist_content(cur);
+
+ mailimap_mbx_list_oflag_print(oflag);
+ }
+
+ unindent();
+ print_indent();
+ printf("}\n");
+}
+
+static void mailimap_mailbox_list_print(struct mailimap_mailbox_list * mb_list)
+{
+ print_indent();
+ printf("mailbox-list {\n");
+ indent();
+
+ mailimap_mbx_list_flags_print(mb_list->mb_flag);
+ printf("dir-separator { %c }\n", mb_list->mb_delimiter);
+ printf("mailbox { %s }\n", mb_list->mb_name);
+
+ unindent();
+ print_indent();
+ printf("}\n");
+}
+
+static void mailimap_flag_list_print(struct mailimap_flag_list * flag_list)
+{
+ clistiter * cur;
+
+ print_indent();
+ printf("flag-list {\n");
+ indent();
+
+ for(cur = clist_begin(flag_list->fl_list) ; cur != NULL ;
+ cur = clist_next(cur)) {
+ struct mailimap_flag * flag;
+
+ flag = clist_content(cur);
+
+ print_indent();
+ mailimap_flag_print(flag);
+ printf("\n");
+ }
+
+ unindent();
+ print_indent();
+ printf("}\n");
+}
+
+
+static void mailimap_mailbox_data_print(struct mailimap_mailbox_data * mb_data)
+{
+ clistiter * cur;
+
+ print_indent();
+ printf("mailbox-data {\n");
+ indent();
+
+ switch (mb_data->mbd_type) {
+ case MAILIMAP_MAILBOX_DATA_FLAGS:
+ print_indent();
+ printf("flags {\n");
+ indent();
+ mailimap_flag_list_print(mb_data->mbd_data.mbd_flags);
+ unindent();
+ print_indent();
+ printf("}\n");
+ break;
+
+ case MAILIMAP_MAILBOX_DATA_LIST:
+ print_indent();
+ printf("list {\n");
+ indent();
+ mailimap_mailbox_list_print(mb_data->mbd_data.mbd_list);
+ unindent();
+ print_indent();
+ printf("}\n");
+ break;
+
+ case MAILIMAP_MAILBOX_DATA_LSUB:
+ print_indent();
+ printf("lsub {\n");
+ indent();
+ mailimap_mailbox_list_print(mb_data->mbd_data.mbd_lsub);
+ unindent();
+ print_indent();
+ printf("}\n");
+ break;
+
+ case MAILIMAP_MAILBOX_DATA_SEARCH:
+ print_indent();
+ printf("search { ");
+ for(cur = clist_begin(mb_data->mbd_data.mbd_search) ;
+ cur != NULL ; cur = clist_next(cur)) {
+ uint32_t * id;
+
+ id = clist_content(cur);
+ printf("%i ", * id);
+ }
+ printf(" }\n");
+ break;
+
+ case MAILIMAP_MAILBOX_DATA_STATUS:
+ print_indent();
+ printf("status {\n");
+ indent();
+ mailimap_mailbox_data_status_print(mb_data->mbd_data.mbd_status);
+ unindent();
+ print_indent();
+ printf("}\n");
+ break;
+
+ case MAILIMAP_MAILBOX_DATA_EXISTS:
+ print_indent();
+ printf("exists { %i }\n", mb_data->mbd_data.mbd_exists);
+ break;
+
+ case MAILIMAP_MAILBOX_DATA_RECENT:
+ print_indent();
+ printf("recent { %i }\n", mb_data->mbd_data.mbd_recent);
+ break;
+ }
+
+ unindent();
+ print_indent();
+ printf("}\n");
+}
+
+static void
+mailimap_resp_text_code_print(struct mailimap_resp_text_code * text_code);
+
+static void mailimap_resp_text_print(struct mailimap_resp_text * resp_text);
+
+static void mailimap_resp_cond_bye_print(struct mailimap_resp_cond_bye *
+ resp_cond_bye)
+{
+ print_indent();
+ printf("resp-cond-bye {\n");
+ indent();
+ mailimap_resp_text_print(resp_cond_bye->rsp_text);
+ unindent();
+ print_indent();
+ printf("}\n");
+}
+
+static void mailimap_resp_cond_state_print(struct mailimap_resp_cond_state *
+ resp_cond_state)
+{
+ print_indent();
+ printf("resp-cond-state {\n");
+ indent();
+
+ switch(resp_cond_state->rsp_type) {
+ case MAILIMAP_RESP_COND_STATE_OK:
+ print_indent();
+ printf("OK\n");
+ break;
+ case MAILIMAP_RESP_COND_STATE_NO:
+ print_indent();
+ printf("NO\n");
+ break;
+ case MAILIMAP_RESP_COND_STATE_BAD:
+ print_indent();
+ printf("BAD\n");
+ break;
+ }
+
+ mailimap_resp_text_print(resp_cond_state->rsp_text);
+
+ unindent();
+ print_indent();
+ printf("}\n");
+}
+
+static void mailimap_capability_data_print(struct mailimap_capability_data *
+ cap_data);
+
+static void mailimap_response_data_print(struct mailimap_response_data *
+ resp_data)
+{
+ print_indent();
+ printf("response-data {\n");
+ indent();
+
+ switch (resp_data->rsp_type) {
+ case MAILIMAP_RESP_DATA_TYPE_COND_STATE:
+ mailimap_resp_cond_state_print(resp_data->rsp_data.rsp_cond_state);
+ break;
+ case MAILIMAP_RESP_DATA_TYPE_COND_BYE:
+ mailimap_resp_cond_bye_print(resp_data->rsp_data.rsp_bye);
+ break;
+ case MAILIMAP_RESP_DATA_TYPE_MAILBOX_DATA:
+ mailimap_mailbox_data_print(resp_data->rsp_data.rsp_mailbox_data);
+ break;
+ case MAILIMAP_RESP_DATA_TYPE_MESSAGE_DATA:
+ mailimap_message_data_print(resp_data->rsp_data.rsp_message_data);
+ break;
+ case MAILIMAP_RESP_DATA_TYPE_CAPABILITY_DATA:
+ mailimap_capability_data_print(resp_data->rsp_data.rsp_capability_data);
+ break;
+ }
+
+ unindent();
+ print_indent();
+ printf("}\n");
+}
+
+static void mailimap_flag_print(struct mailimap_flag * flag)
+{
+ printf("flag { ");
+
+ switch (flag->fl_type) {
+ case MAILIMAP_FLAG_ANSWERED:
+ printf("answered");
+ break;
+
+ case MAILIMAP_FLAG_FLAGGED:
+ printf("flagged");
+ break;
+
+ case MAILIMAP_FLAG_DELETED:
+ printf("deleted");
+ break;
+
+ case MAILIMAP_FLAG_SEEN:
+ printf("seen");
+ break;
+
+ case MAILIMAP_FLAG_DRAFT:
+ printf("flag draft");
+ break;
+
+ case MAILIMAP_FLAG_KEYWORD:
+ printf("keyword { %s }", flag->fl_data.fl_keyword);
+ break;
+
+ case MAILIMAP_FLAG_EXTENSION:
+ printf("extention { %s }", flag->fl_data.fl_extension);
+ break;
+ }
+
+ printf(" }");
+}
+
+static void mailimap_flag_perm_print(struct mailimap_flag_perm * flag_perm)
+{
+ print_indent();
+ printf("flag-perm { ");
+
+ switch (flag_perm->fl_type) {
+ case MAILIMAP_FLAG_PERM_FLAG:
+ mailimap_flag_print(flag_perm->fl_flag);
+ break;
+
+ case MAILIMAP_FLAG_PERM_ALL:
+ printf("all");
+ break;
+ }
+
+ printf(" }\n");
+}
+
+static void mailimap_capability_print(struct mailimap_capability * cap)
+{
+ print_indent();
+ printf("capability { ");
+
+ switch (cap->cap_type) {
+ case MAILIMAP_CAPABILITY_AUTH_TYPE:
+ printf("auth { %s }", cap->cap_data.cap_auth_type);
+ break;
+ case MAILIMAP_CAPABILITY_NAME:
+ printf("atom { %s }", cap->cap_data.cap_name);
+ break;
+ }
+
+ printf(" }\n");
+}
+
+static void mailimap_capability_data_print(struct mailimap_capability_data *
+ cap_data)
+{
+ clistiter * cur;
+
+ print_indent();
+ printf("capability-data {\n");
+ indent();
+
+ for(cur = clist_begin(cap_data->cap_list) ; cur != NULL ;
+ cur = clist_next(cur)) {
+ struct mailimap_capability * cap;
+
+ cap = clist_content(cur);
+
+ mailimap_capability_print(cap);
+ }
+
+ unindent();
+ print_indent();
+ printf("}\n");
+}
+
+static void
+mailimap_resp_text_code_print(struct mailimap_resp_text_code * text_code)
+{
+ clistiter * cur;
+
+ print_indent();
+ printf("resp-text-code {\n");
+ indent();
+
+ switch (text_code->rc_type) {
+ case MAILIMAP_RESP_TEXT_CODE_BADCHARSET:
+ print_indent();
+ printf("badcharset { ");
+ for(cur = clist_begin(text_code->rc_data.rc_badcharset) ; cur != NULL ;
+ cur = clist_next(cur))
+ printf("%s ", (char *) clist_content(cur));
+ printf("}\n");
+ break;
+
+ case MAILIMAP_RESP_TEXT_CODE_CAPABILITY_DATA:
+ print_indent();
+ printf("capability {\n");
+ indent();
+ mailimap_capability_data_print(text_code->rc_data.rc_cap_data);
+ unindent();
+ print_indent();
+ printf("}\n");
+ break;
+
+ case MAILIMAP_RESP_TEXT_CODE_PERMANENTFLAGS:
+ print_indent();
+ printf("permanent-flags {\n");
+ indent();
+ cur = clist_begin(text_code->rc_data.rc_perm_flags);
+ while (cur != NULL) {
+ mailimap_flag_perm_print(clist_content(cur));
+ cur = clist_next(cur);
+ }
+ unindent();
+ print_indent();
+ printf("}\n");
+ break;
+
+ case MAILIMAP_RESP_TEXT_CODE_READ_ONLY:
+ print_indent();
+ printf("readonly\n");
+ break;
+
+ case MAILIMAP_RESP_TEXT_CODE_READ_WRITE:
+ print_indent();
+ printf("readwrite\n");
+ break;
+
+ case MAILIMAP_RESP_TEXT_CODE_TRY_CREATE:
+ print_indent();
+ printf("trycreate\n");
+ break;
+
+ case MAILIMAP_RESP_TEXT_CODE_UIDNEXT:
+ print_indent();
+ printf("uidnext { %i }\n", text_code->rc_data.rc_uidnext);
+ break;
+
+ case MAILIMAP_RESP_TEXT_CODE_UIDVALIDITY:
+ print_indent();
+ printf("uidvalidity { %i }\n", text_code->rc_data.rc_uidvalidity);
+ break;
+
+ case MAILIMAP_RESP_TEXT_CODE_UNSEEN:
+ print_indent();
+ printf("unseen { %i }\n", text_code->rc_data.rc_first_unseen);
+ break;
+
+ case MAILIMAP_RESP_TEXT_CODE_OTHER:
+ print_indent();
+ printf("other { %s = %s }\n",
+ text_code->rc_data.rc_atom.atom_name,
+ text_code->rc_data.rc_atom.atom_value);
+ break;
+ }
+
+ unindent();
+ print_indent();
+ printf("}\n");
+}
+
+static void mailimap_resp_text_print(struct mailimap_resp_text * resp_text)
+{
+ print_indent();
+ printf("resp-text {\n");
+ indent();
+
+ if (resp_text->rsp_code)
+ mailimap_resp_text_code_print(resp_text->rsp_code);
+ print_indent();
+ printf("text { %s }\n", resp_text->rsp_text);
+
+ unindent();
+ print_indent();
+ printf("}\n");
+}
+
+static void mailimap_continue_req_print(struct mailimap_continue_req *
+ cont_req)
+{
+ print_indent();
+ printf("continue-req {\n");
+ indent();
+
+ switch (cont_req->cr_type) {
+ case MAILIMAP_CONTINUE_REQ_TEXT:
+ print_indent();
+ printf("resp-text {\n");
+ indent();
+ mailimap_resp_text_print(cont_req->cr_data.cr_text);
+ unindent();
+ print_indent();
+ printf("}\n");
+ break;
+ case MAILIMAP_CONTINUE_REQ_BASE64:
+ printf("base64 { %s }\n", cont_req->cr_data.cr_base64);
+ break;
+ }
+
+ unindent();
+ print_indent();
+ printf("}\n");
+}
+
+static void mailimap_cont_req_or_resp_data_print(struct mailimap_cont_req_or_resp_data * cont_req_or_resp_data)
+{
+ print_indent();
+ printf("cont-req-or-resp-data {\n");
+ indent();
+
+ switch (cont_req_or_resp_data->rsp_type) {
+ case MAILIMAP_RESP_CONT_REQ:
+ mailimap_continue_req_print(cont_req_or_resp_data->rsp_data.rsp_cont_req);
+ break;
+ case MAILIMAP_RESP_RESP_DATA:
+ mailimap_response_data_print(cont_req_or_resp_data->rsp_data.rsp_resp_data);
+ break;
+ }
+
+ unindent();
+ print_indent();
+ printf("}\n");
+}
+
+static void mailimap_response_tagged_print(struct mailimap_response_tagged *
+ tagged)
+{
+ print_indent();
+ printf("response-tagged {\n");
+ indent();
+
+ print_indent();
+ printf("tag { %s }\n", tagged->rsp_tag);
+ mailimap_resp_cond_state_print(tagged->rsp_cond_state);
+
+ unindent();
+ print_indent();
+ printf("}\n");
+}
+
+static void mailimap_response_fatal_print(struct mailimap_response_fatal *
+ fatal)
+{
+ print_indent();
+ printf("response-fatal {\n");
+ indent();
+
+ mailimap_resp_cond_bye_print(fatal->rsp_bye);
+
+ unindent();
+ print_indent();
+ printf("}\n");
+}
+
+static void mailimap_response_done_print(struct mailimap_response_done *
+ resp_done)
+{
+ print_indent();
+ printf("response-done {\n");
+ indent();
+
+ switch (resp_done->rsp_type) {
+ case MAILIMAP_RESP_DONE_TYPE_TAGGED:
+ mailimap_response_tagged_print(resp_done->rsp_data.rsp_tagged);
+ break;
+ case MAILIMAP_RESP_DONE_TYPE_FATAL:
+ mailimap_response_fatal_print(resp_done->rsp_data.rsp_fatal);
+ break;
+ }
+
+ unindent();
+ print_indent();
+ printf("}\n");
+}
+
+void mailimap_response_print(struct mailimap_response * resp)
+{
+ clistiter * cur;
+
+ print_indent();
+ printf("response {\n");
+ indent();
+
+ for(cur = clist_begin(resp->rsp_cont_req_or_resp_data_list) ; cur != NULL ;
+ cur = clist_next(cur)) {
+ struct mailimap_cont_req_or_resp_data * resp;
+
+ resp = clist_content(cur);
+
+ mailimap_cont_req_or_resp_data_print(resp);
+ }
+
+ mailimap_response_done_print(resp->rsp_resp_done);
+
+ unindent();
+ print_indent();
+ printf("}\n");
+}
+
+static void mailimap_resp_cond_auth_print(struct mailimap_resp_cond_auth *
+ cond_auth)
+{
+ print_indent();
+ printf("resp-cond-auth {\n");
+ indent();
+
+ switch (cond_auth->rsp_type) {
+ case MAILIMAP_RESP_COND_AUTH_OK:
+ print_indent();
+ printf("OK\n");
+ case MAILIMAP_RESP_COND_AUTH_PREAUTH:
+ print_indent();
+ printf("PREAUTH\n");
+ }
+ mailimap_resp_text_print(cond_auth->rsp_text);
+
+ unindent();
+ print_indent();
+ printf("}\n");
+}
+
+void mailimap_greeting_print(struct mailimap_greeting * greeting)
+{
+ print_indent();
+ printf("greeting {\n");
+ indent();
+
+ switch(greeting->gr_type) {
+ case MAILIMAP_GREETING_RESP_COND_AUTH:
+ mailimap_resp_cond_auth_print(greeting->gr_data.gr_auth);
+ break;
+ case MAILIMAP_GREETING_RESP_COND_BYE:
+ mailimap_resp_cond_bye_print(greeting->gr_data.gr_bye);
+ break;
+ }
+
+ unindent();
+ print_indent();
+ printf("}\n");
+}
+#endif
diff --git a/libetpan/src/low-level/imap/mailimap_print.h b/libetpan/src/low-level/imap/mailimap_print.h
new file mode 100644
index 0000000..b617cca
--- a/dev/null
+++ b/libetpan/src/low-level/imap/mailimap_print.h
@@ -0,0 +1,54 @@
+/*
+ * 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$
+ */
+
+#ifndef MAILIMAP_PRINT_H
+
+#define MAILIMAP_PRINT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "mailimap_types.h"
+
+void mailimap_response_print(struct mailimap_response * resp);
+
+void mailimap_greeting_print(struct mailimap_greeting * greeting);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libetpan/src/low-level/imap/mailimap_sender.c b/libetpan/src/low-level/imap/mailimap_sender.c
new file mode 100644
index 0000000..caf86e5
--- a/dev/null
+++ b/libetpan/src/low-level/imap/mailimap_sender.c
@@ -0,0 +1,2742 @@
+/*
+ * 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 "mailstream.h"
+#include "mailimap_keywords.h"
+#include "mailimap_sender.h"
+#include "clist.h"
+#include "mail.h"
+#include <string.h>
+
+#include <stdio.h>
+#include <ctype.h>
+
+/*
+ TODO :
+ implement progression for literal
+*/
+
+/* ************************************************************************* */
+/* ************************************************************************* */
+/* ************************************************************************* */
+/* ************************************************************************* */
+/* ************************************************************************* */
+/* ************************************************************************* */
+
+
+
+
+static int mailimap_atom_send(mailstream * fd, const char * atom);
+
+static int mailimap_auth_type_send(mailstream * fd, const char * auth_type);
+
+static int mailimap_base64_send(mailstream * fd, const char * base64);
+
+
+static int mailimap_date_send(mailstream * fd,
+ struct mailimap_date * date);
+
+static int mailimap_date_day_send(mailstream * fd, int day);
+
+static int mailimap_date_month_send(mailstream * fd, int month);
+
+
+/*
+static gboolean mailimap_date_text_send(mailstream * fd,
+ struct mailimap_date_text * date_text);
+*/
+
+
+static int mailimap_date_year_send(mailstream *fd, int year);
+
+static int
+mailimap_date_time_send(mailstream * fd,
+ struct mailimap_date_time * date_time);
+
+static int mailimap_digit_send(mailstream * fd, int digit);
+
+
+
+static int
+mailimap_fetch_type_send(mailstream * fd,
+ struct mailimap_fetch_type * fetch_type);
+
+
+static int mailimap_fetch_att_send(mailstream * fd,
+ struct mailimap_fetch_att * fetch_att);
+
+
+static int mailimap_flag_send(mailstream * fd,
+ struct mailimap_flag * flag);
+
+
+static int mailimap_flag_extension_send(mailstream * fd,
+ const char * flag_extension);
+
+
+static int mailimap_flag_keyword_send(mailstream * fd,
+ const char * flag_keyword);
+
+
+static int mailimap_flag_list_send(mailstream * fd,
+ struct mailimap_flag_list * flag_list);
+
+
+
+static int mailimap_header_fld_name_send(mailstream * fd, const char * header);
+
+
+static int
+mailimap_header_list_send(mailstream * fd,
+ struct mailimap_header_list * header_list);
+
+static int
+mailimap_list_mailbox_send(mailstream * fd, const char * pattern);
+
+
+static int mailimap_mailbox_send(mailstream * fd, const char * mb);
+
+static int mailimap_number_send(mailstream * fd, uint32_t number);
+
+static int mailimap_password_send(mailstream * fd, const char * pass);
+
+static int mailimap_quoted_char_send(mailstream * fd, char ch);
+
+static int mailimap_quoted_send(mailstream * fd, const char * quoted);
+
+
+static int mailimap_search_key_send(mailstream * fd,
+ struct mailimap_search_key * key);
+
+static int
+mailimap_section_send(mailstream * fd,
+ struct mailimap_section * section);
+
+static int
+mailimap_section_msgtext_send(mailstream * fd,
+ struct mailimap_section_msgtext *
+ section_msgtext);
+
+
+static int
+mailimap_section_part_send(mailstream * fd,
+ struct mailimap_section_part * section);
+
+
+static int
+mailimap_section_spec_send(mailstream * fd,
+ struct mailimap_section_spec * section_spec);
+
+
+static int
+mailimap_section_text_send(mailstream * fd,
+ struct mailimap_section_text * section_text);
+
+
+static int
+mailimap_sequence_num_send(mailstream * fd, uint32_t sequence_num);
+
+
+static int mailimap_set_item_send(mailstream * fd,
+ struct mailimap_set_item * item);
+
+
+static int mailimap_set_send(mailstream * fd,
+ struct mailimap_set * set);
+
+
+
+static int mailimap_status_att_send(mailstream * fd, int * status_att);
+
+
+
+static int
+mailimap_store_att_flags_send(mailstream * fd,
+ struct mailimap_store_att_flags * store_flags);
+
+
+static int mailimap_userid_send(mailstream * fd, const char * user);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+/* ************************************************************************* */
+/* ************************************************************************* */
+/* ************************************************************************* */
+/* ************************************************************************* */
+/* ************************************************************************* */
+/* ************************************************************************* */
+
+
+
+
+
+static inline int mailimap_sized_token_send(mailstream * fd, const char * atom,
+ size_t len)
+{
+ if (mailstream_send_data_crlf(fd, atom, len, 0, NULL) == -1)
+ return MAILIMAP_ERROR_STREAM;
+
+ return MAILIMAP_NO_ERROR;
+}
+
+static int mailimap_token_send(mailstream * fd, const char * atom)
+{
+ return mailimap_sized_token_send(fd, atom, strlen(atom));
+}
+
+static int mailimap_char_send(mailstream * fd, char ch)
+{
+ if (mailstream_write(fd, &ch, 1) == -1)
+ return MAILIMAP_ERROR_STREAM;
+
+ return MAILIMAP_NO_ERROR;
+}
+
+typedef int mailimap_struct_sender(mailstream * fd, void * data);
+
+static int
+mailimap_struct_list_send(mailstream * fd, clist * list,
+ char symbol,
+ mailimap_struct_sender * sender)
+{
+ clistiter * cur;
+ void * elt;
+ int r;
+
+ cur = clist_begin(list);
+
+ if (cur == NULL)
+ return MAILIMAP_NO_ERROR;
+
+ elt = clist_content(cur);
+ r = (* sender)(fd, elt);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ cur = clist_next(cur);
+
+ while (cur != NULL) {
+ r = mailimap_char_send(fd, symbol);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ elt = clist_content(cur);
+ r = (* sender)(fd, elt);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ cur = clist_next(cur);
+ }
+
+ return MAILIMAP_NO_ERROR;
+}
+
+
+static int
+mailimap_struct_spaced_list_send(mailstream * fd, clist * list,
+ mailimap_struct_sender * sender)
+{
+ return mailimap_struct_list_send(fd, list, ' ', sender);
+}
+
+int mailimap_space_send(mailstream * fd)
+{
+ return mailimap_char_send(fd, ' ');
+}
+
+int mailimap_crlf_send(mailstream * fd)
+{
+ int r;
+
+ r = mailimap_char_send(fd, '\r');
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ r = mailimap_char_send(fd, '\n');
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ return MAILIMAP_NO_ERROR;
+}
+
+static int mailimap_oparenth_send(mailstream * fd)
+{
+ return mailimap_char_send(fd, '(');
+}
+
+static int mailimap_cparenth_send(mailstream * fd)
+{
+ return mailimap_char_send(fd, ')');
+}
+
+static int mailimap_dquote_send(mailstream * fd)
+{
+ return mailimap_char_send(fd, '"');
+}
+
+/*
+ address = "(" addr-name SP addr-adl SP addr-mailbox SP
+ addr-host ")"
+
+ addr-adl = nstring
+ ; Holds route from [RFC-822] route-addr if
+ ; non-NIL
+
+ addr-host = nstring
+ ; NIL indicates [RFC-822] group syntax.
+ ; Otherwise, holds [RFC-822] domain name
+
+ 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
+
+ addr-name = nstring
+ ; If non-NIL, holds phrase from [RFC-822]
+ ; mailbox after removing [RFC-822] quoting
+*/
+
+/*
+=> append = "APPEND" SP mailbox [SP flag-list] [SP date-time] SP
+ literal
+*/
+
+int mailimap_append_send(mailstream * fd,
+ const char * mailbox,
+ struct mailimap_flag_list * flag_list,
+ struct mailimap_date_time * date_time,
+ size_t literal_size)
+{
+ int r;
+
+ r = mailimap_token_send(fd, "APPEND");
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ r = mailimap_space_send(fd);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ r = mailimap_mailbox_send(fd, mailbox);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ if (flag_list != NULL) {
+ r = mailimap_space_send(fd);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ r = mailimap_flag_list_send(fd, flag_list);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ }
+ if (date_time != NULL) {
+ r = mailimap_space_send(fd);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ r = mailimap_date_time_send(fd, date_time);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ }
+
+ r = mailimap_space_send(fd);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ r = mailimap_literal_count_send(fd, literal_size);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ return MAILIMAP_NO_ERROR;
+}
+
+/*
+ astring = 1*ASTRING-CHAR / string
+
+=> ASTRING-CHAR = ATOM-CHAR / resp-specials
+*/
+
+static int is_atom(const char * str)
+{
+ if (* str == '\0')
+ return 0;
+
+ while (* str != '\0') {
+ unsigned char uch = (unsigned char) * str;
+
+ if (!isalnum(uch))
+ return 0;
+
+ str ++;
+ }
+
+ return 1;
+}
+
+static int mailimap_astring_send(mailstream * fd, const char * astring)
+{
+ /*
+ workaround for buggy Courier-IMAP that does not accept
+ quoted-strings for fields name but prefer atoms.
+ */
+ if (is_atom(astring))
+ return mailimap_atom_send(fd, astring);
+ else
+ return mailimap_quoted_send(fd, astring);
+}
+
+/*
+=> atom = 1*ATOM-CHAR
+*/
+
+static int mailimap_atom_send(mailstream * fd, const char * atom)
+{
+ return mailimap_token_send(fd, atom);
+}
+
+/*
+=> ATOM-CHAR = <any CHAR except atom-specials>
+*/
+
+/*
+=> atom-specials = "(" / ")" / "{" / SP / CTL / list-wildcards /
+ quoted-specials / resp-specials
+*/
+
+/*
+=> authenticate = "AUTHENTICATE" SP auth-type *(CRLF base64)
+*/
+
+int mailimap_authenticate_send(mailstream * fd,
+ const char * auth_type)
+{
+ int r;
+
+ r = mailimap_token_send(fd, "AUTHENTICATE");
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ r = mailimap_space_send(fd);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ r = mailimap_auth_type_send(fd, auth_type);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ return MAILIMAP_NO_ERROR;
+}
+
+int mailimap_authenticate_resp_send(mailstream * fd,
+ const char * base64)
+{
+ int r;
+
+ r = mailimap_base64_send(fd, base64);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ return MAILIMAP_NO_ERROR;
+}
+
+/*
+=> auth-type = atom
+ ; Defined by [SASL]
+*/
+
+static int mailimap_auth_type_send(mailstream * fd, const char * auth_type)
+{
+ return mailimap_atom_send(fd, auth_type);
+}
+
+
+/*
+=> base64 = *(4base64-char) [base64-terminal]
+*/
+
+static int mailimap_base64_send(mailstream * fd, const char * base64)
+{
+ return mailimap_token_send(fd, base64);
+}
+
+/*
+=> base64-char = ALPHA / DIGIT / "+" / "/"
+ ; Case-sensitive
+
+ base64-terminal = (2base64-char "==") / (3base64-char "=")
+
+ body = "(" (body-type-1part / body-type-mpart) ")"
+
+ 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-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
+
+ 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
+
+ body-fields = body-fld-param SP body-fld-id SP body-fld-desc SP
+ body-fld-enc SP body-fld-octets
+
+ body-fld-desc = nstring
+
+ body-fld-dsp = "(" string SP body-fld-param ")" / nil
+
+ body-fld-enc = (DQUOTE ("7BIT" / "8BIT" / "BINARY" / "BASE64"/
+ "QUOTED-PRINTABLE") DQUOTE) / string
+
+ body-fld-id = nstring
+
+ body-fld-lang = nstring / "(" string *(SP string) ")"
+
+ body-fld-lines = number
+
+ body-fld-md5 = nstring
+
+ body-fld-octets = number
+
+ body-fld-param = "(" string SP string *(SP string SP string) ")" / nil
+
+ body-type-1part = (body-type-basic / body-type-msg / body-type-text)
+ [SP body-ext-1part]
+
+ body-type-basic = media-basic SP body-fields
+ ; MESSAGE subtype MUST NOT be "RFC822"
+
+ body-type-mpart = 1*body SP media-subtype
+ [SP body-ext-mpart]
+
+ body-type-msg = media-message SP body-fields SP envelope
+ SP body SP body-fld-lines
+
+ body-type-text = media-text SP body-fields SP body-fld-lines
+
+ capability = ("AUTH=" auth-type) / atom
+ ; New capabilities MUST begin with "X" or be
+ ; registered with IANA as standard or
+ ; standards-track
+
+ capability-data = "CAPABILITY" *(SP capability) SP "IMAP4rev1"
+ *(SP capability)
+ ; IMAP4rev1 servers which offer RFC 1730
+ ; compatibility MUST list "IMAP4" as the first
+ ; capability.
+
+ CHAR8 = %x01-ff
+ ; any OCTET except NUL, %x00
+*/
+
+/*
+=> command = tag SP (command-any / command-auth / command-nonauth /
+ command-select) CRLF
+ ; Modal based on state
+*/
+
+/*
+=> command-any = "CAPABILITY" / "LOGOUT" / "NOOP" / x-command
+ ; Valid in all states
+*/
+
+int mailimap_capability_send(mailstream * fd)
+{
+ int r;
+
+ r = mailimap_token_send(fd, "CAPABILITY");
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ return MAILIMAP_NO_ERROR;
+}
+
+int mailimap_logout_send(mailstream * fd)
+{
+ int r;
+
+ r = mailimap_token_send(fd, "LOGOUT");
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ return MAILIMAP_NO_ERROR;
+}
+
+int mailimap_noop_send(mailstream * fd)
+{
+ int r;
+
+ r = mailimap_token_send(fd, "NOOP");
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ return MAILIMAP_NO_ERROR;
+}
+
+/*
+=> command-auth = append / create / delete / examine / list / lsub /
+ rename / select / status / subscribe / unsubscribe
+ ; Valid only in Authenticated or Selected state
+*/
+
+/*
+=> command-nonauth = login / authenticate
+ ; Valid only when in Not Authenticated state
+*/
+
+/*
+=> command-select = "CHECK" / "CLOSE" / "EXPUNGE" / copy / fetch / store /
+ uid / search
+ ; Valid only when in Selected state
+*/
+
+int mailimap_check_send(mailstream * fd)
+{
+ int r;
+
+ r = mailimap_token_send(fd, "CHECK");
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ return MAILIMAP_NO_ERROR;
+}
+
+int mailimap_close_send(mailstream * fd)
+{
+ int r;
+
+ r = mailimap_token_send(fd, "CLOSE");
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ return MAILIMAP_NO_ERROR;
+}
+
+int mailimap_expunge_send(mailstream * fd)
+{
+ int r;
+
+ r = mailimap_token_send(fd, "EXPUNGE");
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ return MAILIMAP_NO_ERROR;
+}
+
+/*
+ continue-req = "+" SP (resp-text / base64) CRLF
+*/
+
+/*
+=> copy = "COPY" SP set SP mailbox
+*/
+
+int mailimap_copy_send(mailstream * fd,
+ struct mailimap_set * set,
+ const char * mb)
+{
+ int r;
+
+ r = mailimap_token_send(fd, "COPY");
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_space_send(fd);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_set_send(fd, set);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_space_send(fd);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_mailbox_send(fd, mb);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ return MAILIMAP_NO_ERROR;
+}
+
+int mailimap_uid_copy_send(mailstream * fd,
+ struct mailimap_set * set,
+ const char * mb)
+{
+ int r;
+
+ r = mailimap_token_send(fd, "UID");
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_space_send(fd);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ return mailimap_copy_send(fd, set, mb);
+}
+
+/*
+=> create = "CREATE" SP mailbox
+ ; Use of INBOX gives a NO error
+*/
+
+int mailimap_create_send(mailstream * fd,
+ const char * mb)
+{
+ int r;
+
+ r = mailimap_token_send(fd, "CREATE");
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_space_send(fd);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_mailbox_send(fd, mb);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ return MAILIMAP_NO_ERROR;
+}
+
+/*
+=> date = date-text / DQUOTE date-text DQUOTE
+*/
+
+static int mailimap_date_send(mailstream * fd,
+ struct mailimap_date * date)
+{
+ int r;
+
+ r = mailimap_date_day_send(fd, date->dt_day);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_char_send(fd, '-');
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_date_month_send(fd, date->dt_month);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_char_send(fd, '-');
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_date_year_send(fd, date->dt_year);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ return MAILIMAP_NO_ERROR;
+}
+
+/*
+=> date-day = 1*2DIGIT
+ ; Day of month
+*/
+
+static int mailimap_date_day_send(mailstream * fd, int day)
+{
+ return mailimap_number_send(fd, day);
+}
+
+/*
+=> date-day-fixed = (SP DIGIT) / 2DIGIT
+ ; Fixed-format version of date-day
+*/
+
+static int mailimap_date_day_fixed_send(mailstream * fd, int day)
+{
+ int r;
+
+ if (day < 10) {
+ r = mailimap_space_send(fd);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_number_send(fd, day);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ return MAILIMAP_NO_ERROR;
+ }
+ else
+ return mailimap_number_send(fd, day);
+}
+
+/*
+=> date-month = "Jan" / "Feb" / "Mar" / "Apr" / "May" / "Jun" /
+ "Jul" / "Aug" / "Sep" / "Oct" / "Nov" / "Dec"
+*/
+
+static int mailimap_date_month_send(mailstream * fd, int month)
+{
+ const char * name;
+ int r;
+
+ name = mailimap_month_get_token_str(month);
+
+ if (name == NULL)
+ return MAILIMAP_ERROR_INVAL;
+
+ r = mailimap_token_send(fd, name);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ return MAILIMAP_NO_ERROR;
+}
+
+/*
+=> date-text = date-day "-" date-month "-" date-year
+*/
+
+/*
+static gboolean mailimap_date_text_send(mailstream * fd,
+ struct mailimap_date_text * date_text)
+{
+ if (!mailimap_date_day_send(fd, date_text->day))
+ return FALSE;
+ if (!mailimap_char_send(fd, '-'))
+ return FALSE;
+ if (!mailimap_date_month_send(fd, date_text->month))
+ return FALSE;
+ if (!mailimap_char_send(fd, '-'))
+ return FALSE;
+ if (!mailimap_date_year_send(fd, date_text->year))
+ return FALSE;
+
+ return TRUE;
+}
+*/
+
+/*
+=> date-year = 4DIGIT
+*/
+
+static int mailimap_fixed_digit_send(mailstream * fd,
+ int num, int count)
+{
+ int r;
+
+ r = mailimap_fixed_digit_send(fd, num / 10, count);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_digit_send(fd, num % 10);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ return MAILIMAP_NO_ERROR;
+}
+
+static int mailimap_date_year_send(mailstream *fd, int year)
+{
+ int r;
+
+ r = mailimap_fixed_digit_send(fd, year, 4);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ return MAILIMAP_NO_ERROR;
+}
+
+/*
+=> date-time = DQUOTE date-day-fixed "-" date-month "-" date-year
+ SP time SP zone DQUOTE
+*/
+
+static int
+mailimap_date_time_send(mailstream * fd,
+ struct mailimap_date_time * date_time)
+{
+ int r;
+
+ r = mailimap_date_day_fixed_send(fd, date_time->dt_day);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_char_send(fd, '-');
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_date_month_send(fd, date_time->dt_month);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_char_send(fd, '-');
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_date_year_send(fd, date_time->dt_month);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_space_send(fd);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_fixed_digit_send(fd, date_time->dt_hour, 2);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_char_send(fd, ':');
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_fixed_digit_send(fd, date_time->dt_min, 2);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_char_send(fd, ':');
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_fixed_digit_send(fd, date_time->dt_sec, 2);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ return MAILIMAP_NO_ERROR;
+}
+
+/*
+=> delete = "DELETE" SP mailbox
+ ; Use of INBOX gives a NO error
+*/
+
+int mailimap_delete_send(mailstream * fd, const char * mb)
+{
+ int r;
+
+ r = mailimap_token_send(fd, "DELETE");
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_space_send(fd);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_mailbox_send(fd, mb);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ return MAILIMAP_NO_ERROR;
+}
+
+/*
+
+digit
+
+digit-nz = %x31-39
+ ; 1-9
+*/
+
+static int mailimap_digit_send(mailstream * fd, int digit)
+{
+ return mailimap_char_send(fd, digit + '0');
+}
+
+
+/*
+ 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 ")"
+
+ env-bcc = "(" 1*address ")" / nil
+
+ env-cc = "(" 1*address ")" / nil
+
+ env-date = nstring
+
+ env-from = "(" 1*address ")" / nil
+
+ env-in-reply-to = nstring
+
+ env-message-id = nstring
+
+ env-reply-to = "(" 1*address ")" / nil
+
+ env-sender = "(" 1*address ")" / nil
+
+ env-subject = nstring
+
+ env-to = "(" 1*address ")" / nil
+*/
+
+/*
+=> examine = "EXAMINE" SP mailbox
+*/
+
+int mailimap_examine_send(mailstream * fd, const char * mb)
+{
+ int r;
+
+ r = mailimap_token_send(fd, "EXAMINE");
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_space_send(fd);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_mailbox_send(fd, mb);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ return MAILIMAP_NO_ERROR;
+}
+
+/*
+=> fetch = "FETCH" SP set SP ("ALL" / "FULL" / "FAST" / fetch-att /
+ "(" fetch-att *(SP fetch-att) ")")
+*/
+
+static int
+mailimap_fetch_att_list_send(mailstream * fd, clist * fetch_att_list);
+
+static int
+mailimap_fetch_type_send(mailstream * fd,
+ struct mailimap_fetch_type * fetch_type)
+{
+ switch (fetch_type->ft_type) {
+ case MAILIMAP_FETCH_TYPE_ALL:
+ return mailimap_token_send(fd, "ALL");
+ case MAILIMAP_FETCH_TYPE_FULL:
+ return mailimap_token_send(fd, "FULL");
+ case MAILIMAP_FETCH_TYPE_FAST:
+ return mailimap_token_send(fd, "FAST");
+ case MAILIMAP_FETCH_TYPE_FETCH_ATT:
+ return mailimap_fetch_att_send(fd, fetch_type->ft_data.ft_fetch_att);
+ case MAILIMAP_FETCH_TYPE_FETCH_ATT_LIST:
+ return mailimap_fetch_att_list_send(fd,
+ fetch_type->ft_data.ft_fetch_att_list);
+ default:
+ /* should not happen */
+ return MAILIMAP_ERROR_INVAL;
+ }
+}
+
+int mailimap_fetch_send(mailstream * fd,
+ struct mailimap_set * set,
+ struct mailimap_fetch_type * fetch_type)
+{
+ int r;
+
+ r = mailimap_token_send(fd, "FETCH");
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_space_send(fd);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_set_send(fd, set);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_space_send(fd);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_fetch_type_send(fd, fetch_type);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ return MAILIMAP_NO_ERROR;
+}
+
+int
+mailimap_uid_fetch_send(mailstream * fd,
+ struct mailimap_set * set,
+ struct mailimap_fetch_type * fetch_type)
+{
+ int r;
+
+ r = mailimap_token_send(fd, "UID");
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_space_send(fd);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ return mailimap_fetch_send(fd, set, fetch_type);
+}
+
+/* currently porting */
+
+static int
+mailimap_fetch_att_list_send(mailstream * fd, clist * fetch_att_list)
+{
+ int r;
+
+ r = mailimap_oparenth_send(fd);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_struct_spaced_list_send(fd, fetch_att_list,
+ (mailimap_struct_sender *)
+ mailimap_fetch_att_send);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_cparenth_send(fd);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ return MAILIMAP_NO_ERROR;
+}
+
+/*
+=> fetch-att = "ENVELOPE" / "FLAGS" / "INTERNALDATE" /
+ "RFC822" [".HEADER" / ".SIZE" / ".TEXT"] /
+ "BODY" ["STRUCTURE"] / "UID" /
+ "BODY" [".PEEK"] section ["<" number "." nz-number ">"]
+*/
+
+static int mailimap_fetch_att_send(mailstream * fd,
+ struct mailimap_fetch_att * fetch_att)
+{
+ int r;
+
+ switch(fetch_att->att_type) {
+ case MAILIMAP_FETCH_ATT_ENVELOPE:
+ return mailimap_token_send(fd, "ENVELOPE");
+
+ case MAILIMAP_FETCH_ATT_FLAGS:
+ return mailimap_token_send(fd, "FLAGS");
+
+ case MAILIMAP_FETCH_ATT_INTERNALDATE:
+ return mailimap_token_send(fd, "INTERNALDATE");
+
+ case MAILIMAP_FETCH_ATT_RFC822:
+ return mailimap_token_send(fd, "RFC822");
+
+ case MAILIMAP_FETCH_ATT_RFC822_HEADER:
+ return mailimap_token_send(fd, "RFC822.HEADER");
+
+ case MAILIMAP_FETCH_ATT_RFC822_SIZE:
+ return mailimap_token_send(fd, "RFC822.SIZE");
+
+ case MAILIMAP_FETCH_ATT_RFC822_TEXT:
+ return mailimap_token_send(fd, "RFC822.TEXT");
+
+ case MAILIMAP_FETCH_ATT_BODY:
+ return mailimap_token_send(fd, "BODY");
+
+ case MAILIMAP_FETCH_ATT_BODYSTRUCTURE:
+ return mailimap_token_send(fd, "BODYSTRUCTURE");
+
+ case MAILIMAP_FETCH_ATT_UID:
+ return mailimap_token_send(fd, "UID");
+
+ case MAILIMAP_FETCH_ATT_BODY_SECTION:
+
+ r = mailimap_token_send(fd, "BODY");
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ r = mailimap_section_send(fd, fetch_att->att_section);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ if (fetch_att->att_size != 0) {
+ r = mailimap_char_send(fd, '<');
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ r = mailimap_number_send(fd, fetch_att->att_offset);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ r = mailimap_char_send(fd, '.');
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ r = mailimap_number_send(fd, fetch_att->att_size);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ r = mailimap_char_send(fd, '>');
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ }
+
+ return MAILIMAP_NO_ERROR;
+
+ case MAILIMAP_FETCH_ATT_BODY_PEEK_SECTION:
+ r = mailimap_token_send(fd, "BODY.PEEK");
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ r = mailimap_section_send(fd, fetch_att->att_section);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ if (fetch_att->att_size != 0) {
+ r = mailimap_char_send(fd, '<');
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ r = mailimap_number_send(fd, fetch_att->att_offset);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ r = mailimap_char_send(fd, '.');
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ r = mailimap_number_send(fd, fetch_att->att_size);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ r = mailimap_char_send(fd, '>');
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ }
+ return MAILIMAP_NO_ERROR;
+
+ default:
+ /* should not happen */
+ return MAILIMAP_ERROR_INVAL;
+ }
+}
+
+/*
+=> flag = "\Answered" / "\Flagged" / "\Deleted" /
+ "\Seen" / "\Draft" / flag-keyword / flag-extension
+ ; Does not include "\Recent"
+*/
+
+/*
+enum {
+ FLAG_ANSWERED,
+ FLAG_FLAGGED,
+ FLAG_DELETED,
+ FLAG_SEEN,
+ FLAG_DRAFT,
+ FLAG_KEYWORD,
+ FLAG_EXTENSION
+};
+
+struct mailimap_flag {
+ gint type;
+ gchar * flag_keyword;
+ gchar * flag_extension;
+};
+*/
+
+static int mailimap_flag_send(mailstream * fd,
+ struct mailimap_flag * flag)
+{
+ switch(flag->fl_type) {
+ case MAILIMAP_FLAG_ANSWERED:
+ return mailimap_token_send(fd, "\\Answered");
+ case MAILIMAP_FLAG_FLAGGED:
+ return mailimap_token_send(fd, "\\Flagged");
+ case MAILIMAP_FLAG_DELETED:
+ return mailimap_token_send(fd, "\\Deleted");
+ case MAILIMAP_FLAG_SEEN:
+ return mailimap_token_send(fd, "\\Seen");
+ case MAILIMAP_FLAG_DRAFT:
+ return mailimap_token_send(fd, "\\Draft");
+ case MAILIMAP_FLAG_KEYWORD:
+ return mailimap_flag_keyword_send(fd, flag->fl_data.fl_keyword);
+ case MAILIMAP_FLAG_EXTENSION:
+ return mailimap_flag_extension_send(fd, flag->fl_data.fl_extension);
+ default:
+ /* should not happen */
+ return MAILIMAP_ERROR_INVAL;
+ }
+}
+
+
+/*
+=> 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_send(mailstream * fd,
+ const char * flag_extension)
+{
+ int r;
+
+ r = mailimap_char_send(fd, '\\');
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_atom_send(fd, flag_extension);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ return MAILIMAP_NO_ERROR;
+}
+
+/*
+ flag-fetch = flag / "\Recent"
+*/
+
+/*
+=> flag-keyword = atom
+*/
+
+static int mailimap_flag_keyword_send(mailstream * fd,
+ const char * flag_keyword)
+{
+ return mailimap_token_send(fd, flag_keyword);
+}
+
+/*
+=> flag-list = "(" [flag *(SP flag)] ")"
+*/
+
+static int mailimap_flag_list_send(mailstream * fd,
+ struct mailimap_flag_list * flag_list)
+{
+ int r;
+
+ r = mailimap_oparenth_send(fd);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ if (flag_list->fl_list != NULL) {
+ r = mailimap_struct_spaced_list_send(fd, flag_list->fl_list,
+ (mailimap_struct_sender *) mailimap_flag_send);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ }
+
+ r = mailimap_cparenth_send(fd);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ return MAILIMAP_NO_ERROR;
+}
+
+/*
+ flag-perm = flag / "\*"
+
+ greeting = "*" SP (resp-cond-auth / resp-cond-bye) CRLF
+*/
+
+/*
+=> header-fld-name = astring
+*/
+
+static int mailimap_header_fld_name_send(mailstream * fd, const char * header)
+{
+ return mailimap_astring_send(fd, header);
+}
+
+/*
+=> header-list = "(" header-fld-name *(SP header-fld-name) ")"
+*/
+
+static int
+mailimap_header_list_send(mailstream * fd,
+ struct mailimap_header_list * header_list)
+{
+ int r;
+
+ r = mailimap_oparenth_send(fd);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_struct_spaced_list_send(fd, header_list->hdr_list,
+ (mailimap_struct_sender *) mailimap_header_fld_name_send);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_cparenth_send(fd);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ return MAILIMAP_NO_ERROR;
+}
+
+/*
+=> list = "LIST" SP mailbox SP list-mailbox
+*/
+
+int mailimap_list_send(mailstream * fd,
+ const char * mb,
+ const char * list_mb)
+{
+ int r;
+
+ r = mailimap_token_send(fd, "LIST");
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_space_send(fd);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_mailbox_send(fd, mb);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_space_send(fd);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_list_mailbox_send(fd, list_mb);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ return MAILIMAP_NO_ERROR;
+}
+
+/*
+=> list-mailbox = 1*list-char / string
+*/
+
+static int
+mailimap_list_mailbox_send(mailstream * fd, const char * pattern)
+{
+ return mailimap_quoted_send(fd, pattern);
+}
+
+/*
+ list-char = ATOM-CHAR / list-wildcards / resp-specials
+
+ list-wildcards = "%" / "*"
+*/
+
+/*
+=> literal = "{" number "}" CRLF *CHAR8
+ ; Number represents the number of CHAR8s
+*/
+
+int
+mailimap_literal_send(mailstream * fd, const char * literal,
+ size_t progr_rate,
+ progress_function * progr_fun)
+{
+ size_t len;
+ uint32_t literal_len;
+ int r;
+
+ len = strlen(literal);
+ literal_len = mailstream_get_data_crlf_size(literal, len);
+
+ r = mailimap_literal_count_send(fd, literal_len);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ r = mailimap_literal_data_send(fd, literal, len, progr_rate, progr_fun);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ return MAILIMAP_NO_ERROR;
+}
+
+/*
+ "{" number "}" CRLF
+*/
+
+int
+mailimap_literal_count_send(mailstream * fd, uint32_t count)
+{
+ int r;
+
+ r = mailimap_char_send(fd, '{');
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_number_send(fd, count);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_char_send(fd, '}');
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_crlf_send(fd);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ return MAILIMAP_NO_ERROR;
+}
+
+/*
+ *CHAR8
+*/
+
+int
+mailimap_literal_data_send(mailstream * fd, const char * literal, uint32_t len,
+ size_t progr_rate,
+ progress_function * progr_fun)
+{
+ int r;
+
+ r = mailimap_sized_token_send(fd, literal, len);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ return MAILIMAP_NO_ERROR;
+}
+
+
+/*
+=> login = "LOGIN" SP userid SP password
+*/
+
+int mailimap_login_send(mailstream * fd,
+ const char * userid, const char * password)
+{
+ int r;
+
+ r = mailimap_token_send(fd, "LOGIN");
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_space_send(fd);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_userid_send(fd, userid);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_space_send(fd);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_password_send(fd, password);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ return MAILIMAP_NO_ERROR;
+}
+
+/*
+=> lsub = "LSUB" SP mailbox SP list-mailbox
+*/
+
+int mailimap_lsub_send(mailstream * fd,
+ const char * mb, const char * list_mb)
+{
+ int r;
+
+ r = mailimap_token_send(fd, "LSUB");
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_space_send(fd);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_mailbox_send(fd, mb);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_space_send(fd);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_list_mailbox_send(fd, list_mb);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ return MAILIMAP_NO_ERROR;
+}
+
+/*
+ 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_send(mailstream * fd, const char * mb)
+{
+ return mailimap_astring_send(fd, mb);
+}
+
+/*
+ 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"
+
+ mailbox-list = "(" [mbx-list-flags] ")" SP
+ (DQUOTE QUOTED-CHAR DQUOTE / nil) SP mailbox
+
+ mbx-list-flags = *(mbx-list-oflag SP) mbx-list-sflag
+ *(SP mbx-list-oflag) /
+ mbx-list-oflag *(SP mbx-list-oflag)
+
+ mbx-list-oflag = "\Noinferiors" / flag-extension
+ ; Other flags; multiple possible per LIST response
+
+ mbx-list-sflag = "\Noselect" / "\Marked" / "\Unmarked"
+ ; Selectability flags; only one per LIST response
+
+ media-basic = ((DQUOTE ("APPLICATION" / "AUDIO" / "IMAGE" / "MESSAGE" /
+ "VIDEO") DQUOTE) / string) SP media-subtype
+ ; Defined in [MIME-IMT]
+
+ media-message = DQUOTE "MESSAGE" DQUOTE SP DQUOTE "RFC822" DQUOTE
+ ; Defined in [MIME-IMT]
+
+ media-subtype = string
+ ; Defined in [MIME-IMT]
+
+ media-text = DQUOTE "TEXT" DQUOTE SP media-subtype
+ ; Defined in [MIME-IMT]
+
+ message-data = nz-number SP ("EXPUNGE" / ("FETCH" SP msg-att))
+
+ msg-att = "(" (msg-att-dynamic / msg-att-static)
+ *(SP (msg-att-dynamic / msg-att-static)) ")"
+
+ msg-att-dynamic = "FLAGS" SP "(" [flag-fetch *(SP flag-fetch)] ")"
+ ; MAY change for a message
+
+ 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
+
+ nil = "NIL"
+
+ nstring = string / nil
+*/
+
+/*
+=> number = 1*DIGIT
+ ; Unsigned 32-bit integer
+ ; (0 <= n < 4,294,967,296)
+*/
+
+/*
+ nz-number = digit-nz *DIGIT
+ ; Non-zero unsigned 32-bit integer
+ ; (0 < n < 4,294,967,296)
+*/
+
+static int mailimap_number_send(mailstream * fd, uint32_t number)
+{
+ int r;
+
+ if (number / 10 != 0) {
+ r = mailimap_number_send(fd, number / 10);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ }
+
+ r = mailimap_digit_send(fd, number % 10);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ return MAILIMAP_NO_ERROR;
+}
+
+/*
+=> password = astring
+*/
+
+static int mailimap_password_send(mailstream * fd, const char * pass)
+{
+ return mailimap_astring_send(fd, pass);
+}
+
+/*
+=> quoted = DQUOTE *QUOTED-CHAR DQUOTE
+
+=> QUOTED-CHAR = <any TEXT-CHAR except quoted-specials> /
+ "\" quoted-specials
+
+=> quoted-specials = DQUOTE / "\"
+*/
+
+static int is_quoted_specials(char ch)
+{
+ return (ch == '\"') || (ch == '\\');
+}
+
+static int mailimap_quoted_char_send(mailstream * fd, char ch)
+{
+ int r;
+
+ if (is_quoted_specials(ch)) {
+ r = mailimap_char_send(fd, '\\');
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ r = mailimap_char_send(fd, ch);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ return MAILIMAP_NO_ERROR;
+ }
+ else
+ return mailimap_char_send(fd, ch);
+}
+
+static int mailimap_quoted_send(mailstream * fd, const char * quoted)
+{
+ const char * pos;
+ int r;
+
+ pos = quoted;
+
+ r = mailimap_dquote_send(fd);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ while (* pos != 0) {
+ r = mailimap_quoted_char_send(fd, * pos);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ pos ++;
+ }
+
+ r = mailimap_dquote_send(fd);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ return MAILIMAP_NO_ERROR;
+}
+
+/*
+=> rename = "RENAME" SP mailbox SP mailbox
+ ; Use of INBOX as a destination gives a NO error
+*/
+
+int mailimap_rename_send(mailstream * fd, const char * mb,
+ const char * new_name)
+{
+ int r;
+
+ r = mailimap_token_send(fd, "RENAME");
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ r = mailimap_space_send(fd);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ r = mailimap_mailbox_send(fd, mb);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ r = mailimap_space_send(fd);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ r = mailimap_mailbox_send(fd, new_name);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ return MAILIMAP_NO_ERROR;
+}
+
+/*
+ response = *(continue-req / response-data) response-done
+
+ response-data = "*" SP (resp-cond-state / resp-cond-bye /
+ mailbox-data / message-data / capability-data) CRLF
+
+ response-done = response-tagged / response-fatal
+
+ response-fatal = "*" SP resp-cond-bye CRLF
+ ; Server closes connection immediately
+
+ response-tagged = tag SP resp-cond-state CRLF
+
+ resp-cond-auth = ("OK" / "PREAUTH") SP resp-text
+ ; Authentication condition
+
+ resp-cond-bye = "BYE" SP resp-text
+
+ resp-cond-state = ("OK" / "NO" / "BAD") SP resp-text
+ ; Status condition
+
+ resp-specials = "]"
+
+ resp-text = ["[" resp-text-code "]" SP] text
+
+ 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*<any TEXT-CHAR except "]">]
+*/
+
+/*
+=> search = "SEARCH" [SP "CHARSET" SP astring] 1*(SP search-key)
+ ; CHARSET argument to MUST be registered with IANA
+*/
+
+int
+mailimap_search_send(mailstream * fd, const char * charset,
+ struct mailimap_search_key * key)
+{
+ int r;
+
+ r = mailimap_token_send(fd, "SEARCH");
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ if (charset != NULL) {
+ r = mailimap_space_send(fd);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_token_send(fd, "CHARSET");
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ r = mailimap_space_send(fd);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ r = mailimap_astring_send(fd, charset);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ }
+
+ r = mailimap_space_send(fd);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_search_key_send(fd, key);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ return MAILIMAP_NO_ERROR;
+}
+
+int
+mailimap_uid_search_send(mailstream * fd, const char * charset,
+ struct mailimap_search_key * key)
+{
+ int r;
+
+ r = mailimap_token_send(fd, "UID");
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_space_send(fd);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ return mailimap_search_send(fd, charset, key);
+}
+
+
+/*
+=> 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) ")"
+*/
+
+
+static int mailimap_search_key_send(mailstream * fd,
+ struct mailimap_search_key * key)
+{
+ int r;
+
+ switch (key->sk_type) {
+
+ case MAILIMAP_SEARCH_KEY_ALL:
+ return mailimap_token_send(fd, "ALL");
+
+ case MAILIMAP_SEARCH_KEY_ANSWERED:
+ return mailimap_token_send(fd, "ANSWERED");
+
+ case MAILIMAP_SEARCH_KEY_BCC:
+ r = mailimap_token_send(fd, "BCC");
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ r = mailimap_space_send(fd);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ r = mailimap_astring_send(fd, key->sk_data.sk_bcc);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ return MAILIMAP_NO_ERROR;
+
+ case MAILIMAP_SEARCH_KEY_BEFORE:
+ r = mailimap_token_send(fd, "BEFORE");
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ r = mailimap_space_send(fd);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ r = mailimap_date_send(fd, key->sk_data.sk_before);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ return MAILIMAP_NO_ERROR;
+
+ case MAILIMAP_SEARCH_KEY_BODY:
+ r = mailimap_token_send(fd, "BODY");
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ r = mailimap_space_send(fd);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ r = mailimap_astring_send(fd, key->sk_data.sk_body);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ return MAILIMAP_NO_ERROR;
+
+ case MAILIMAP_SEARCH_KEY_CC:
+ r = mailimap_token_send(fd, "CC");
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ r = mailimap_space_send(fd);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ r = mailimap_astring_send(fd, key->sk_data.sk_cc);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ return MAILIMAP_NO_ERROR;
+
+ case MAILIMAP_SEARCH_KEY_DELETED:
+ return mailimap_token_send(fd, "DELETED");
+
+ case MAILIMAP_SEARCH_KEY_FLAGGED:
+ return mailimap_token_send(fd, "FLAGGED");
+
+ case MAILIMAP_SEARCH_KEY_FROM:
+ r = mailimap_token_send(fd, "FROM");
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ r = mailimap_space_send(fd);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ r = mailimap_astring_send(fd, key->sk_data.sk_from);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ return MAILIMAP_NO_ERROR;
+
+ case MAILIMAP_SEARCH_KEY_KEYWORD:
+ r = mailimap_token_send(fd, "KEYWORD");
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ r = mailimap_space_send(fd);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ r = mailimap_flag_keyword_send(fd, key->sk_data.sk_keyword);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ return MAILIMAP_NO_ERROR;
+
+ case MAILIMAP_SEARCH_KEY_NEW:
+ return mailimap_token_send(fd, "NEW");
+
+ case MAILIMAP_SEARCH_KEY_OLD:
+ return mailimap_token_send(fd, "OLD");
+
+ case MAILIMAP_SEARCH_KEY_ON:
+ r = mailimap_token_send(fd, "ON");
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ r = mailimap_space_send(fd);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ r = mailimap_date_send(fd, key->sk_data.sk_on);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ return MAILIMAP_NO_ERROR;
+
+ case MAILIMAP_SEARCH_KEY_RECENT:
+ return mailimap_token_send(fd, "RECENT");
+
+ case MAILIMAP_SEARCH_KEY_SEEN:
+ return mailimap_token_send(fd, "SEEN");
+
+ case MAILIMAP_SEARCH_KEY_SINCE:
+ r = mailimap_token_send(fd, "SINCE");
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ r = mailimap_space_send(fd);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ r = mailimap_date_send(fd, key->sk_data.sk_since);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ return MAILIMAP_NO_ERROR;
+
+ case MAILIMAP_SEARCH_KEY_SUBJECT:
+ r = mailimap_token_send(fd, "SUBJECT");
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ r = mailimap_space_send(fd);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ r = mailimap_astring_send(fd, key->sk_data.sk_subject);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ return MAILIMAP_NO_ERROR;
+
+ case MAILIMAP_SEARCH_KEY_TEXT:
+ r = mailimap_token_send(fd, "TEXT");
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ r = mailimap_space_send(fd);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ r = mailimap_astring_send(fd, key->sk_data.sk_text);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ return MAILIMAP_NO_ERROR;
+
+ case MAILIMAP_SEARCH_KEY_TO:
+ r = mailimap_token_send(fd, "TO");
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ r = mailimap_space_send(fd);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ r = mailimap_astring_send(fd, key->sk_data.sk_text);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ return MAILIMAP_NO_ERROR;
+
+ case MAILIMAP_SEARCH_KEY_UNANSWERED:
+ return mailimap_token_send(fd, "UNANSWERED");
+
+ case MAILIMAP_SEARCH_KEY_UNDELETED:
+ return mailimap_token_send(fd, "UNDELETED");
+
+ case MAILIMAP_SEARCH_KEY_UNFLAGGED:
+ return mailimap_token_send(fd, "UNFLAGGED");
+
+ case MAILIMAP_SEARCH_KEY_UNKEYWORD:
+ r = mailimap_token_send(fd, "UNKEYWORD");
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ r = mailimap_space_send(fd);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ r = mailimap_flag_keyword_send(fd, key->sk_data.sk_keyword);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ return MAILIMAP_NO_ERROR;
+
+ case MAILIMAP_SEARCH_KEY_UNSEEN:
+ return mailimap_token_send(fd, "UNSEEN");
+
+ case MAILIMAP_SEARCH_KEY_DRAFT:
+ return mailimap_token_send(fd, "DRAFT");
+
+ case MAILIMAP_SEARCH_KEY_HEADER:
+ r = mailimap_token_send(fd, "HEADER");
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ r = mailimap_space_send(fd);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ r = mailimap_header_fld_name_send(fd,
+ key->sk_data.sk_header.sk_header_name);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ r = mailimap_space_send(fd);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ r = mailimap_astring_send(fd,
+ key->sk_data.sk_header.sk_header_value);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ return MAILIMAP_NO_ERROR;
+
+ case MAILIMAP_SEARCH_KEY_LARGER:
+ r = mailimap_token_send(fd, "LARGER");
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ r = mailimap_space_send(fd);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ r = mailimap_number_send(fd, key->sk_data.sk_larger);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ return MAILIMAP_NO_ERROR;
+
+ case MAILIMAP_SEARCH_KEY_NOT:
+ r = mailimap_token_send(fd, "NOT");
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ r = mailimap_space_send(fd);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ r = mailimap_search_key_send(fd, key->sk_data.sk_not);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ return MAILIMAP_NO_ERROR;
+
+ case MAILIMAP_SEARCH_KEY_OR:
+ r = mailimap_token_send(fd, "OR");
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ r = mailimap_space_send(fd);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ r = mailimap_search_key_send(fd, key->sk_data.sk_or.sk_or1);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ r = mailimap_space_send(fd);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ r = mailimap_search_key_send(fd, key->sk_data.sk_or.sk_or2);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ return TRUE;
+
+ case MAILIMAP_SEARCH_KEY_SENTBEFORE:
+ r = mailimap_token_send(fd, "SENTBEFORE");
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ r = mailimap_space_send(fd);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ r = mailimap_date_send(fd, key->sk_data.sk_sentbefore);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ return MAILIMAP_NO_ERROR;
+
+ case MAILIMAP_SEARCH_KEY_SENTON:
+ r = mailimap_token_send(fd, "SENTON");
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ r = mailimap_space_send(fd);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ r = mailimap_date_send(fd, key->sk_data.sk_senton);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ return MAILIMAP_NO_ERROR;
+
+ case MAILIMAP_SEARCH_KEY_SENTSINCE:
+ r = mailimap_token_send(fd, "SENTSINCE");
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ r = mailimap_space_send(fd);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ r = mailimap_date_send(fd, key->sk_data.sk_sentsince);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ return MAILIMAP_NO_ERROR;
+
+ case MAILIMAP_SEARCH_KEY_SMALLER:
+ r = mailimap_token_send(fd, "SMALLER");
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ r = mailimap_space_send(fd);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ r = mailimap_number_send(fd, key->sk_data.sk_smaller);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ return MAILIMAP_NO_ERROR;
+
+ case MAILIMAP_SEARCH_KEY_UID:
+ r = mailimap_token_send(fd, "UID");
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ r = mailimap_space_send(fd);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ r = mailimap_set_send(fd, key->sk_data.sk_set);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ return MAILIMAP_NO_ERROR;
+
+ case MAILIMAP_SEARCH_KEY_UNDRAFT:
+ return mailimap_token_send(fd, "UNDRAFT");
+
+ case MAILIMAP_SEARCH_KEY_SET:
+ return mailimap_set_send(fd, key->sk_data.sk_set);
+
+ case MAILIMAP_SEARCH_KEY_MULTIPLE:
+ r = mailimap_oparenth_send(fd);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_struct_spaced_list_send(fd, key->sk_data.sk_multiple,
+ (mailimap_struct_sender *)
+ mailimap_search_key_send);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_cparenth_send(fd);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ return MAILIMAP_NO_ERROR;
+ default:
+ /* should not happend */
+ return MAILIMAP_ERROR_INVAL;
+ }
+}
+
+/*
+=> section = "[" [section-spec] "]"
+*/
+
+static int
+mailimap_section_send(mailstream * fd,
+ struct mailimap_section * section)
+{
+ int r;
+
+ r = mailimap_char_send(fd, '[');
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ if (section != NULL) {
+ if (section->sec_spec != NULL) {
+ r = mailimap_section_spec_send(fd, section->sec_spec);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ }
+ }
+
+ r = mailimap_char_send(fd, ']');
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ return MAILIMAP_NO_ERROR;
+}
+
+/*
+=> section-msgtext = "HEADER" / "HEADER.FIELDS" [".NOT"] SP header-list /
+ "TEXT"
+ ; top-level or MESSAGE/RFC822 part
+*/
+
+static int
+mailimap_section_msgtext_send(mailstream * fd,
+ struct mailimap_section_msgtext *
+ section_msgtext)
+{
+ int r;
+
+ switch (section_msgtext->sec_type) {
+ case MAILIMAP_SECTION_MSGTEXT_HEADER:
+ return mailimap_token_send(fd, "HEADER");
+
+ case MAILIMAP_SECTION_MSGTEXT_HEADER_FIELDS:
+ r = mailimap_token_send(fd, "HEADER.FIELDS");
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ r = mailimap_space_send(fd);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ r = mailimap_header_list_send(fd, section_msgtext->sec_header_list);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ return MAILIMAP_NO_ERROR;
+
+ case MAILIMAP_SECTION_MSGTEXT_HEADER_FIELDS_NOT:
+ r = mailimap_token_send(fd, "HEADER.FIELDS.NOT");
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ r = mailimap_space_send(fd);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ r = mailimap_header_list_send(fd, section_msgtext->sec_header_list);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ return MAILIMAP_NO_ERROR;
+
+ case MAILIMAP_SECTION_MSGTEXT_TEXT:
+ return mailimap_token_send(fd, "TEXT");
+
+ default:
+ /* should not happend */
+ return MAILIMAP_ERROR_INVAL;
+ }
+}
+
+/*
+=> section-part = nz-number *("." nz-number)
+ ; body part nesting
+*/
+
+static int
+mailimap_pnumber_send(mailstream * fd, uint32_t * pnumber)
+{
+ return mailimap_number_send(fd, * pnumber);
+}
+
+static int
+mailimap_section_part_send(mailstream * fd,
+ struct mailimap_section_part * section)
+{
+ int r;
+
+ r = mailimap_struct_list_send(fd, section->sec_id, '.',
+ (mailimap_struct_sender *) mailimap_pnumber_send);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ return MAILIMAP_NO_ERROR;
+}
+
+/*
+=> section-spec = section-msgtext / (section-part ["." section-text])
+*/
+
+static int
+mailimap_section_spec_send(mailstream * fd,
+ struct mailimap_section_spec * section_spec)
+{
+ int r;
+
+ switch (section_spec->sec_type) {
+ case MAILIMAP_SECTION_SPEC_SECTION_MSGTEXT:
+ return mailimap_section_msgtext_send(fd,
+ section_spec->sec_data.sec_msgtext);
+
+ case MAILIMAP_SECTION_SPEC_SECTION_PART:
+ r = mailimap_section_part_send(fd, section_spec->sec_data.sec_part);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ if (section_spec->sec_text != NULL) {
+ r = mailimap_char_send(fd, '.');
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ r = mailimap_section_text_send(fd,
+ section_spec->sec_text);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ }
+
+ return MAILIMAP_NO_ERROR;
+
+ default:
+ /* should not happen */
+ return MAILIMAP_ERROR_INVAL;
+ }
+}
+
+/*
+=> section-text = section-msgtext / "MIME"
+ ; text other than actual body part (headers, etc.)
+*/
+
+static int
+mailimap_section_text_send(mailstream * fd,
+ struct mailimap_section_text * section_text)
+{
+ switch (section_text->sec_type) {
+ case MAILIMAP_SECTION_TEXT_SECTION_MSGTEXT:
+ return mailimap_section_msgtext_send(fd, section_text->sec_msgtext);
+
+ case MAILIMAP_SECTION_TEXT_MIME:
+ return mailimap_token_send(fd, "MIME");
+
+ default:
+ /* should not happen */
+ return MAILIMAP_NO_ERROR;
+ }
+}
+
+/*
+=> select = "SELECT" SP mailbox
+*/
+
+int
+mailimap_select_send(mailstream * fd, const char * mb)
+{
+ int r;
+
+ r = mailimap_token_send(fd, "SELECT");
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ r = mailimap_space_send(fd);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ r = mailimap_mailbox_send(fd, mb);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ return MAILIMAP_NO_ERROR;
+}
+
+/*
+=> 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.
+*/
+
+/* if sequence_num == 0 then "*" */
+
+static int
+mailimap_sequence_num_send(mailstream * fd, uint32_t sequence_num)
+{
+ if (sequence_num == 0)
+ return mailimap_char_send(fd, '*');
+ else
+ return mailimap_number_send(fd, sequence_num);
+}
+
+/*
+=> 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.
+*/
+
+static int mailimap_set_item_send(mailstream * fd,
+ struct mailimap_set_item * item)
+{
+ int r;
+
+ if (item->set_first == item->set_last)
+ return mailimap_sequence_num_send(fd, item->set_first);
+ else {
+ r = mailimap_sequence_num_send(fd, item->set_first);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ r = mailimap_char_send(fd, ':');
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ r = mailimap_sequence_num_send(fd, item->set_last);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ return MAILIMAP_NO_ERROR;
+ }
+}
+
+static int mailimap_set_send(mailstream * fd,
+ struct mailimap_set * set)
+{
+ return mailimap_struct_list_send(fd, set->set_list, ',',
+ (mailimap_struct_sender *) mailimap_set_item_send);
+}
+
+/*
+=> status = "STATUS" SP mailbox SP "(" status-att *(SP status-att) ")"
+*/
+
+static int
+mailimap_status_att_list_send(mailstream * fd,
+ struct mailimap_status_att_list * status_att_list)
+{
+ return mailimap_struct_spaced_list_send(fd, status_att_list->att_list,
+ (mailimap_struct_sender *) mailimap_status_att_send);
+}
+
+int
+mailimap_status_send(mailstream * fd, const char * mb,
+ struct mailimap_status_att_list * status_att_list)
+{
+ int r;
+
+ r = mailimap_token_send(fd, "STATUS");
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_space_send(fd);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_mailbox_send(fd, mb);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_space_send(fd);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_char_send(fd, '(');
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_status_att_list_send(fd, status_att_list);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_char_send(fd, ')');
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ return MAILIMAP_NO_ERROR;
+}
+
+/*
+=> status-att = "MESSAGES" / "RECENT" / "UIDNEXT" / "UIDVALIDITY" /
+ "UNSEEN"
+*/
+
+
+static int mailimap_status_att_send(mailstream * fd, int * status_att)
+{
+ const char * token;
+
+ token = mailimap_status_att_get_token_str(* status_att);
+ if (token == NULL) {
+ /* should not happen */
+ return MAILIMAP_ERROR_INVAL;
+ }
+
+ return mailimap_token_send(fd, token);
+}
+
+/*
+=> store = "STORE" SP set SP store-att-flags
+*/
+
+int
+mailimap_store_send(mailstream * fd,
+ struct mailimap_set * set,
+ struct mailimap_store_att_flags * store_att_flags)
+{
+ int r;
+
+ r = mailimap_token_send(fd, "STORE");
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ r = mailimap_space_send(fd);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ r = mailimap_set_send(fd, set);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ r = mailimap_space_send(fd);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_store_att_flags_send(fd, store_att_flags);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ return MAILIMAP_NO_ERROR;
+}
+
+int
+mailimap_uid_store_send(mailstream * fd,
+ struct mailimap_set * set,
+ struct mailimap_store_att_flags * store_att_flags)
+{
+ int r;
+
+ r = mailimap_token_send(fd, "UID");
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ r = mailimap_space_send(fd);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ return mailimap_store_send(fd, set, store_att_flags);
+}
+
+/*
+=> store-att-flags = (["+" / "-"] "FLAGS" [".SILENT"]) SP
+ (flag-list / (flag *(SP flag)))
+*/
+
+static int
+mailimap_store_att_flags_send(mailstream * fd,
+ struct mailimap_store_att_flags * store_flags)
+{
+ int r;
+
+ switch (store_flags->fl_sign) {
+ case 1:
+ r = mailimap_char_send(fd, '+');
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ case -1:
+ r = mailimap_char_send(fd, '-');
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ }
+
+ r = mailimap_token_send(fd, "FLAGS");
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ if (store_flags->fl_silent) {
+ r = mailimap_token_send(fd, ".SILENT");
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ }
+
+ r = mailimap_space_send(fd);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_flag_list_send(fd, store_flags->fl_flag_list);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ return MAILIMAP_NO_ERROR;
+}
+
+/*
+ string = quoted / literal
+*/
+
+/*
+=> subscribe = "SUBSCRIBE" SP mailbox
+*/
+
+int mailimap_subscribe_send(mailstream * fd, const char * mb)
+{
+ int r;
+
+ r = mailimap_token_send(fd, "SUBSCRIBE");
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_space_send(fd);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ r = mailimap_mailbox_send(fd, mb);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ return MAILIMAP_NO_ERROR;
+}
+
+/*
+=> tag = 1*<any ASTRING-CHAR except "+">
+*/
+
+int mailimap_tag_send(mailstream * fd, const char * tag)
+{
+ return mailimap_token_send(fd, tag);
+}
+
+/*
+ text = 1*TEXT-CHAR
+
+ TEXT-CHAR = <any CHAR except CR and LF>
+
+ time = 2DIGIT ":" 2DIGIT ":" 2DIGIT
+ ; Hours minutes seconds
+*/
+
+/*
+=> uid = "UID" SP (copy / fetch / search / store)
+ ; Unique identifiers used instead of message
+ ; sequence numbers
+
+functions uid_copy, uid_fetch ...
+*/
+
+
+/*
+ uniqueid = nz-number
+ ; Strictly ascending
+*/
+
+/*
+=> unsubscribe = "UNSUBSCRIBE" SP mailbox
+*/
+
+int mailimap_unsubscribe_send(mailstream * fd,
+ const char * mb)
+{
+ int r;
+
+ r = mailimap_token_send(fd, "UNSUBSCRIBE");
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ r = mailimap_space_send(fd);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+ r = mailimap_mailbox_send(fd, mb);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ return MAILIMAP_NO_ERROR;
+}
+
+int mailimap_starttls_send(mailstream * fd)
+{
+ return mailimap_token_send(fd, "STARTTLS");
+}
+
+/*
+=> userid = astring
+*/
+
+static int mailimap_userid_send(mailstream * fd, const char * user)
+{
+ return mailimap_astring_send(fd, user);
+}
+
+/*
+ x-command = "X" atom <experimental command arguments>
+
+ 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".
+*/
diff --git a/libetpan/src/low-level/imap/mailimap_sender.h b/libetpan/src/low-level/imap/mailimap_sender.h
new file mode 100644
index 0000000..34661f5
--- a/dev/null
+++ b/libetpan/src/low-level/imap/mailimap_sender.h
@@ -0,0 +1,164 @@
+/*
+ * 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$
+ */
+
+#ifndef MAILIMAP_SENDER_H
+
+#define MAILIMAP_SENDER_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "mailimap_types.h"
+
+int mailimap_append_send(mailstream * fd,
+ const char * mailbox,
+ struct mailimap_flag_list * flag_list,
+ struct mailimap_date_time * date_time,
+ size_t literal_size);
+
+int mailimap_authenticate_send(mailstream * fd,
+ const char * auth_type);
+
+int mailimap_authenticate_resp_send(mailstream * fd,
+ const char * base64);
+
+int mailimap_noop_send(mailstream * fd);
+
+int mailimap_logout_send(mailstream * fd);
+
+int mailimap_capability_send(mailstream * fd);
+
+int mailimap_check_send(mailstream * fd);
+
+int mailimap_close_send(mailstream * fd);
+
+int mailimap_expunge_send(mailstream * fd);
+
+int mailimap_copy_send(mailstream * fd,
+ struct mailimap_set * set,
+ const char * mb);
+
+int mailimap_uid_copy_send(mailstream * fd,
+ struct mailimap_set * set,
+ const char * mb);
+
+int mailimap_create_send(mailstream * fd,
+ const char * mb);
+
+
+int mailimap_delete_send(mailstream * fd, const char * mb);
+
+int mailimap_examine_send(mailstream * fd, const char * mb);
+
+int
+mailimap_fetch_send(mailstream * fd,
+ struct mailimap_set * set,
+ struct mailimap_fetch_type * fetch_type);
+
+int
+mailimap_uid_fetch_send(mailstream * fd,
+ struct mailimap_set * set,
+ struct mailimap_fetch_type * fetch_type);
+
+int mailimap_list_send(mailstream * fd,
+ const char * mb, const char * list_mb);
+
+int mailimap_login_send(mailstream * fd,
+ const char * userid, const char * password);
+
+int mailimap_lsub_send(mailstream * fd,
+ const char * mb, const char * list_mb);
+
+int mailimap_rename_send(mailstream * fd, const char * mb,
+ const char * new_name);
+
+int
+mailimap_search_send(mailstream * fd, const char * charset,
+ struct mailimap_search_key * key);
+
+int
+mailimap_uid_search_send(mailstream * fd, const char * charset,
+ struct mailimap_search_key * key);
+
+int
+mailimap_select_send(mailstream * fd, const char * mb);
+
+int
+mailimap_status_send(mailstream * fd, const char * mb,
+ struct mailimap_status_att_list * status_att_list);
+
+int
+mailimap_store_send(mailstream * fd,
+ struct mailimap_set * set,
+ struct mailimap_store_att_flags * store_att_flags);
+
+int
+mailimap_uid_store_send(mailstream * fd,
+ struct mailimap_set * set,
+ struct mailimap_store_att_flags * store_att_flags);
+
+int mailimap_subscribe_send(mailstream * fd, const char * mb);
+
+
+int mailimap_tag_send(mailstream * fd, const char * tag);
+
+int mailimap_unsubscribe_send(mailstream * fd,
+ const char * mb);
+
+int mailimap_crlf_send(mailstream * fd);
+
+int mailimap_space_send(mailstream * fd);
+
+int
+mailimap_literal_send(mailstream * fd, const char * literal,
+ size_t progr_rate,
+ progress_function * progr_fun);
+
+int
+mailimap_literal_count_send(mailstream * fd, uint32_t count);
+
+int
+mailimap_literal_data_send(mailstream * fd, const char * literal, uint32_t len,
+ size_t progr_rate,
+ progress_function * progr_fun);
+
+int mailimap_starttls_send(mailstream * fd);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libetpan/src/low-level/imap/mailimap_socket.c b/libetpan/src/low-level/imap/mailimap_socket.c
new file mode 100644
index 0000000..01070b1
--- a/dev/null
+++ b/libetpan/src/low-level/imap/mailimap_socket.c
@@ -0,0 +1,73 @@
+/*
+ * 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 "mailimap_socket.h"
+
+#include "mailimap.h"
+
+#include "connect.h"
+#include <netinet/in.h>
+#include <unistd.h>
+
+#define DEFAULT_IMAP_PORT 143
+#define SERVICE_NAME_IMAP "imap2"
+#define SERVICE_TYPE_TCP "tcp"
+
+int mailimap_socket_connect(mailimap * f, const char * server, uint16_t port)
+{
+ int s;
+ mailstream * stream;
+
+ if (port == 0) {
+ port = mail_get_service_port(SERVICE_NAME_IMAP, SERVICE_TYPE_TCP);
+ if (port == 0)
+ port = DEFAULT_IMAP_PORT;
+ port = ntohs(port);
+ }
+
+ /* Connection */
+
+ s = mail_tcp_connect(server, port);
+ if (s == -1)
+ return MAILIMAP_ERROR_CONNECTION_REFUSED;
+
+ stream = mailstream_socket_open(s);
+ if (stream == NULL) {
+ close(s);
+ return MAILIMAP_ERROR_MEMORY;
+ }
+
+ return mailimap_connect(f, stream);
+}
diff --git a/libetpan/src/low-level/imap/mailimap_socket.h b/libetpan/src/low-level/imap/mailimap_socket.h
new file mode 100644
index 0000000..ed8f369
--- a/dev/null
+++ b/libetpan/src/low-level/imap/mailimap_socket.h
@@ -0,0 +1,54 @@
+/*
+ * 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$
+ */
+
+#ifndef MAILIMAP_SOCKET_H
+
+#define MAILIMAP_SOCKET_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <inttypes.h>
+
+#include <libetpan/mailimap_types.h>
+
+int mailimap_socket_connect(mailimap * f, const char * server, uint16_t port);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libetpan/src/low-level/imap/mailimap_ssl.c b/libetpan/src/low-level/imap/mailimap_ssl.c
new file mode 100644
index 0000000..44ae36e
--- a/dev/null
+++ b/libetpan/src/low-level/imap/mailimap_ssl.c
@@ -0,0 +1,73 @@
+/*
+ * 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 "mailimap_ssl.h"
+
+#include "mailimap.h"
+
+#include "connect.h"
+#include <netinet/in.h>
+#include <unistd.h>
+
+#define DEFAULT_IMAPS_PORT 993
+#define SERVICE_NAME_IMAPS "imaps"
+#define SERVICE_TYPE_TCP "tcp"
+
+int mailimap_ssl_connect(mailimap * f, const char * server, uint16_t port)
+{
+ int s;
+ mailstream * stream;
+
+ if (port == 0) {
+ port = mail_get_service_port(SERVICE_NAME_IMAPS, SERVICE_TYPE_TCP);
+ if (port == 0)
+ port = DEFAULT_IMAPS_PORT;
+ port = ntohs(port);
+ }
+
+ /* Connection */
+
+ s = mail_tcp_connect(server, port);
+ if (s == -1)
+ return MAILIMAP_ERROR_CONNECTION_REFUSED;
+
+ stream = mailstream_ssl_open(s);
+ if (stream == NULL) {
+ close(s);
+ return MAILIMAP_ERROR_CONNECTION_REFUSED;
+ }
+
+ return mailimap_connect(f, stream);
+}
diff --git a/libetpan/src/low-level/imap/mailimap_ssl.h b/libetpan/src/low-level/imap/mailimap_ssl.h
new file mode 100644
index 0000000..4d5146c
--- a/dev/null
+++ b/libetpan/src/low-level/imap/mailimap_ssl.h
@@ -0,0 +1,54 @@
+/*
+ * 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$
+ */
+
+#ifndef MAILIMAP_SSL_H
+
+#define MAILIMAP_SSL_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <inttypes.h>
+
+#include <libetpan/mailimap_types.h>
+
+int mailimap_ssl_connect(mailimap * f, const char * server, uint16_t port);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libetpan/src/low-level/imap/mailimap_types.c b/libetpan/src/low-level/imap/mailimap_types.c
new file mode 100644
index 0000000..5889f32
--- a/dev/null
+++ b/libetpan/src/low-level/imap/mailimap_types.c
@@ -0,0 +1,2961 @@
+/*
+ * 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 "mailimap_types.h"
+#include "mmapstring.h"
+#include "mail.h"
+
+#include <stdlib.h>
+
+/* ************************************************************************* */
+/* ************************************************************************* */
+/* ************************************************************************* */
+/* ************************************************************************* */
+/* ************************************************************************* */
+/* ************************************************************************* */
+
+
+
+
+
+
+/* from parser */
+
+
+uint32_t * mailimap_number_alloc_new(uint32_t number)
+{
+ uint32_t * pnumber;
+
+ pnumber = malloc(sizeof(* pnumber));
+ if (pnumber == NULL)
+ return NULL;
+
+ * pnumber = number;
+
+ return pnumber;
+}
+
+void mailimap_number_alloc_free(uint32_t * pnumber)
+{
+ free(pnumber);
+}
+
+
+/* ************************************************************************* */
+
+
+struct mailimap_address *
+mailimap_address_new(char * ad_personal_name, char * ad_source_route,
+ char * ad_mailbox_name, char * ad_host_name)
+{
+ struct mailimap_address * addr;
+
+ addr = malloc(sizeof(* addr));
+ if (addr == NULL)
+ return NULL;
+
+ addr->ad_personal_name = ad_personal_name;
+ addr->ad_source_route = ad_source_route;
+ addr->ad_mailbox_name = ad_mailbox_name;
+ addr->ad_host_name = ad_host_name;
+
+ return addr;
+}
+
+void mailimap_address_free(struct mailimap_address * addr)
+{
+ mailimap_addr_host_free(addr->ad_host_name);
+ mailimap_addr_mailbox_free(addr->ad_mailbox_name);
+ mailimap_addr_adl_free(addr->ad_source_route);
+ mailimap_addr_name_free(addr->ad_personal_name);
+ free(addr);
+}
+
+void mailimap_addr_host_free(char * addr_host)
+{
+ mailimap_nstring_free(addr_host);
+}
+
+void mailimap_addr_mailbox_free(char * addr_mailbox)
+{
+ mailimap_nstring_free(addr_mailbox);
+}
+
+void mailimap_addr_adl_free(char * addr_adl)
+{
+ mailimap_nstring_free(addr_adl);
+}
+
+void mailimap_addr_name_free(char * addr_name)
+{
+ mailimap_nstring_free(addr_name);
+}
+
+
+
+
+
+/*
+struct mailimap_astring *
+mailimap_astring_new(gint type,
+ gchar * atom_astring,
+ gchar * string)
+{
+ struct mailimap_astring * astring;
+
+ astring = g_new(struct mailimap_astring, 1);
+ if (astring == NULL)
+ return FALSE;
+
+ astring->type = type;
+ astring->atom_astring = atom_astring;
+ astring->string = string;
+
+ return astring;
+}
+
+void mailimap_astring_free(struct mailimap_astring * astring)
+{
+ if (astring->atom_astring)
+ mailimap_atom_astring_free(astring->atom_astring);
+ if (astring->string)
+ mailimap_string_free(astring->string);
+ free(astring);
+}
+*/
+
+void mailimap_astring_free(char * astring)
+{
+ if (mmap_string_unref(astring) != 0)
+ free(astring);
+}
+
+static void mailimap_custom_string_free(char * str)
+{
+ free(str);
+}
+
+
+void mailimap_atom_free(char * atom)
+{
+ free(atom);
+}
+
+
+
+
+void mailimap_auth_type_free(char * auth_type)
+{
+ mailimap_atom_free(auth_type);
+}
+
+
+
+
+
+void mailimap_base64_free(char * base64)
+{
+ free(base64);
+}
+
+
+
+
+struct mailimap_body *
+mailimap_body_new(int bd_type,
+ struct mailimap_body_type_1part * bd_body_1part,
+ struct mailimap_body_type_mpart * bd_body_mpart)
+{
+ struct mailimap_body * body;
+
+ body = malloc(sizeof(* body));
+ if (body == NULL)
+ return NULL;
+
+ body->bd_type = bd_type;
+ switch (bd_type) {
+ case MAILIMAP_BODY_1PART:
+ body->bd_data.bd_body_1part = bd_body_1part;
+ break;
+ case MAILIMAP_BODY_MPART:
+ body->bd_data.bd_body_mpart = bd_body_mpart;
+ break;
+ }
+
+ return body;
+}
+
+void mailimap_body_free(struct mailimap_body * body)
+{
+ switch (body->bd_type) {
+ case MAILIMAP_BODY_1PART:
+ mailimap_body_type_1part_free(body->bd_data.bd_body_1part);
+ break;
+ case MAILIMAP_BODY_MPART:
+ mailimap_body_type_mpart_free(body->bd_data.bd_body_mpart);
+ break;
+ }
+ free(body);
+}
+
+
+struct mailimap_body_extension *
+mailimap_body_extension_new(int ext_type, char * ext_nstring,
+ uint32_t ext_number,
+ clist * ext_body_extension_list)
+{
+ struct mailimap_body_extension * body_extension;
+
+ body_extension = malloc(sizeof(* body_extension));
+ if (body_extension == NULL)
+ return NULL;
+
+ body_extension->ext_type = ext_type;
+ switch (ext_type) {
+ case MAILIMAP_BODY_EXTENSION_NSTRING:
+ body_extension->ext_data.ext_nstring = ext_nstring;
+ break;
+ case MAILIMAP_BODY_EXTENSION_NUMBER:
+ body_extension->ext_data.ext_number = ext_number;
+ break;
+ case MAILIMAP_BODY_EXTENSION_LIST:
+ body_extension->ext_data.ext_body_extension_list = ext_body_extension_list;
+ break;
+ }
+
+ return body_extension;
+}
+
+static void
+mailimap_body_ext_list_free(clist * body_ext_list);
+
+void mailimap_body_extension_free(struct mailimap_body_extension * be)
+{
+ switch (be->ext_type) {
+ case MAILIMAP_BODY_EXTENSION_NSTRING:
+ mailimap_nstring_free(be->ext_data.ext_nstring);
+ break;
+ case MAILIMAP_BODY_EXTENSION_LIST:
+ mailimap_body_ext_list_free(be->ext_data.ext_body_extension_list);
+ break;
+ }
+
+ free(be);
+}
+
+
+static void
+mailimap_body_ext_list_free(clist * body_ext_list)
+{
+ clist_foreach(body_ext_list, (clist_func) mailimap_body_extension_free,
+ NULL);
+ clist_free(body_ext_list);
+}
+
+
+struct mailimap_body_ext_1part *
+mailimap_body_ext_1part_new(char * bd_md5,
+ struct mailimap_body_fld_dsp * bd_disposition,
+ struct mailimap_body_fld_lang * bd_language,
+ clist * bd_extension_list)
+{
+ struct mailimap_body_ext_1part * body_ext_1part;
+
+ body_ext_1part = malloc(sizeof(* body_ext_1part));
+ if (body_ext_1part == NULL)
+ return NULL;
+
+ body_ext_1part->bd_md5 = bd_md5;
+ body_ext_1part->bd_disposition = bd_disposition;
+ body_ext_1part->bd_language = bd_language;
+ body_ext_1part->bd_extension_list = bd_extension_list;
+
+ return body_ext_1part;
+}
+
+void
+mailimap_body_ext_1part_free(struct mailimap_body_ext_1part * body_ext_1part)
+{
+ mailimap_body_fld_md5_free(body_ext_1part->bd_md5);
+ if (body_ext_1part->bd_disposition)
+ mailimap_body_fld_dsp_free(body_ext_1part->bd_disposition);
+ if (body_ext_1part->bd_language)
+ mailimap_body_fld_lang_free(body_ext_1part->bd_language);
+ if (body_ext_1part->bd_extension_list)
+ mailimap_body_ext_list_free(body_ext_1part->bd_extension_list);
+
+ free(body_ext_1part);
+}
+
+struct mailimap_body_ext_mpart *
+mailimap_body_ext_mpart_new(struct mailimap_body_fld_param * bd_parameter,
+ struct mailimap_body_fld_dsp * bd_disposition,
+ struct mailimap_body_fld_lang * bd_language,
+ clist * bd_extension_list)
+{
+ struct mailimap_body_ext_mpart * body_ext_mpart;
+
+ body_ext_mpart = malloc(sizeof(* body_ext_mpart));
+ if (body_ext_mpart == NULL)
+ return NULL;
+
+ body_ext_mpart->bd_parameter = bd_parameter;
+ body_ext_mpart->bd_disposition = bd_disposition;
+ body_ext_mpart->bd_language = bd_language;
+ body_ext_mpart->bd_extension_list = bd_extension_list;
+
+ return body_ext_mpart;
+}
+
+void
+mailimap_body_ext_mpart_free(struct mailimap_body_ext_mpart * body_ext_mpart)
+{
+ if (body_ext_mpart->bd_parameter != NULL)
+ mailimap_body_fld_param_free(body_ext_mpart->bd_parameter);
+ if (body_ext_mpart->bd_disposition)
+ mailimap_body_fld_dsp_free(body_ext_mpart->bd_disposition);
+ if (body_ext_mpart->bd_language)
+ mailimap_body_fld_lang_free(body_ext_mpart->bd_language);
+ if (body_ext_mpart->bd_extension_list)
+ mailimap_body_ext_list_free(body_ext_mpart->bd_extension_list);
+ free(body_ext_mpart);
+}
+
+
+struct mailimap_body_fields *
+mailimap_body_fields_new(struct mailimap_body_fld_param * bd_parameter,
+ char * bd_id,
+ char * bd_description,
+ struct mailimap_body_fld_enc * bd_encoding,
+ uint32_t bd_size)
+{
+ struct mailimap_body_fields * body_fields;
+
+ body_fields = malloc(sizeof(* body_fields));
+ if (body_fields == NULL)
+ return NULL;
+ body_fields->bd_parameter = bd_parameter;
+ body_fields->bd_id = bd_id;
+ body_fields->bd_description = bd_description;
+ body_fields->bd_encoding = bd_encoding;
+ body_fields->bd_size = bd_size;
+
+ return body_fields;
+}
+
+void
+mailimap_body_fields_free(struct mailimap_body_fields * body_fields)
+{
+ if (body_fields->bd_parameter != NULL)
+ mailimap_body_fld_param_free(body_fields->bd_parameter);
+ mailimap_body_fld_id_free(body_fields->bd_id);
+ mailimap_body_fld_desc_free(body_fields->bd_description);
+ mailimap_body_fld_enc_free(body_fields->bd_encoding);
+ free(body_fields);
+}
+
+
+
+
+
+
+void mailimap_body_fld_desc_free(char * body_fld_desc)
+{
+ mailimap_nstring_free(body_fld_desc);
+}
+
+
+
+
+struct mailimap_body_fld_dsp *
+mailimap_body_fld_dsp_new(char * dsp_type,
+ struct mailimap_body_fld_param * dsp_attributes)
+{
+ struct mailimap_body_fld_dsp * body_fld_dsp;
+
+ body_fld_dsp = malloc(sizeof(* body_fld_dsp));
+ if (body_fld_dsp == NULL)
+ return NULL;
+
+ body_fld_dsp->dsp_type = dsp_type;
+ body_fld_dsp->dsp_attributes = dsp_attributes;
+
+ return body_fld_dsp;
+}
+
+void mailimap_body_fld_dsp_free(struct mailimap_body_fld_dsp * bfd)
+{
+ if (bfd->dsp_type != NULL)
+ mailimap_string_free(bfd->dsp_type);
+ if (bfd->dsp_attributes != NULL)
+ mailimap_body_fld_param_free(bfd->dsp_attributes);
+ free(bfd);
+}
+
+
+
+struct mailimap_body_fld_enc *
+mailimap_body_fld_enc_new(int enc_type, char * enc_value)
+{
+ struct mailimap_body_fld_enc * body_fld_enc;
+
+ body_fld_enc = malloc(sizeof(* body_fld_enc));
+ if (body_fld_enc == NULL)
+ return NULL;
+
+ body_fld_enc->enc_type = enc_type;
+ body_fld_enc->enc_value = enc_value;
+
+ return body_fld_enc;
+}
+
+void mailimap_body_fld_enc_free(struct mailimap_body_fld_enc * bfe)
+{
+ if (bfe->enc_value)
+ mailimap_string_free(bfe->enc_value);
+ free(bfe);
+}
+
+
+
+void mailimap_body_fld_id_free(char * body_fld_id)
+{
+ mailimap_nstring_free(body_fld_id);
+}
+
+
+
+struct mailimap_body_fld_lang *
+mailimap_body_fld_lang_new(int lg_type, char * lg_single, clist * lg_list)
+{
+ struct mailimap_body_fld_lang * fld_lang;
+
+ fld_lang = malloc(sizeof(* fld_lang));
+ if (fld_lang == NULL)
+ return NULL;
+
+ fld_lang->lg_type = lg_type;
+ switch (lg_type) {
+ case MAILIMAP_BODY_FLD_LANG_SINGLE:
+ fld_lang->lg_data.lg_single = lg_single;
+ break;
+ case MAILIMAP_BODY_FLD_LANG_LIST:
+ fld_lang->lg_data.lg_list = lg_list;
+ break;
+ }
+
+ return fld_lang;
+}
+
+void
+mailimap_body_fld_lang_free(struct mailimap_body_fld_lang * fld_lang)
+{
+ switch (fld_lang->lg_type) {
+ case MAILIMAP_BODY_FLD_LANG_SINGLE:
+ mailimap_nstring_free(fld_lang->lg_data.lg_single);
+ break;
+ case MAILIMAP_BODY_FLD_LANG_LIST:
+ clist_foreach(fld_lang->lg_data.lg_list,
+ (clist_func) mailimap_string_free, NULL);
+ clist_free(fld_lang->lg_data.lg_list);
+ break;
+ }
+ free(fld_lang);
+}
+
+
+
+void mailimap_body_fld_md5_free(char * body_fld_md5)
+{
+ mailimap_nstring_free(body_fld_md5);
+}
+
+
+
+struct mailimap_single_body_fld_param *
+mailimap_single_body_fld_param_new(char * pa_name, char * pa_value)
+{
+ struct mailimap_single_body_fld_param * param;
+
+ param = malloc(sizeof(* param));
+ if (param == NULL)
+ return NULL;
+ param->pa_name = pa_name;
+ param->pa_value = pa_value;
+
+ return param;
+}
+
+void
+mailimap_single_body_fld_param_free(struct mailimap_single_body_fld_param * p)
+{
+ mailimap_string_free(p->pa_name);
+ mailimap_string_free(p->pa_value);
+ free(p);
+}
+
+
+struct mailimap_body_fld_param *
+mailimap_body_fld_param_new(clist * pa_list)
+{
+ struct mailimap_body_fld_param * fld_param;
+
+ fld_param = malloc(sizeof(* fld_param));
+ if (fld_param == NULL)
+ return NULL;
+ fld_param->pa_list = pa_list;
+
+ return fld_param;
+}
+
+void
+mailimap_body_fld_param_free(struct mailimap_body_fld_param * fld_param)
+{
+ clist_foreach(fld_param->pa_list,
+ (clist_func) mailimap_single_body_fld_param_free, NULL);
+ clist_free(fld_param->pa_list);
+ free(fld_param);
+}
+
+
+struct mailimap_body_type_1part *
+mailimap_body_type_1part_new(int bd_type,
+ struct mailimap_body_type_basic * bd_type_basic,
+ struct mailimap_body_type_msg * bd_type_msg,
+ struct mailimap_body_type_text * bd_type_text,
+ struct mailimap_body_ext_1part * bd_ext_1part)
+{
+ struct mailimap_body_type_1part * body_type_1part;
+
+ body_type_1part = malloc(sizeof(* body_type_1part));
+ if (body_type_1part == NULL)
+ return NULL;
+
+ body_type_1part->bd_type = bd_type;
+ switch (bd_type) {
+ case MAILIMAP_BODY_TYPE_1PART_BASIC:
+ body_type_1part->bd_data.bd_type_basic = bd_type_basic;
+ break;
+ case MAILIMAP_BODY_TYPE_1PART_MSG:
+ body_type_1part->bd_data.bd_type_msg = bd_type_msg;
+ break;
+ case MAILIMAP_BODY_TYPE_1PART_TEXT:
+ body_type_1part->bd_data.bd_type_text = bd_type_text;
+ break;
+ }
+ body_type_1part->bd_ext_1part = bd_ext_1part;
+
+ return body_type_1part;
+}
+
+void
+mailimap_body_type_1part_free(struct mailimap_body_type_1part * bt1p)
+{
+ switch (bt1p->bd_type) {
+ case MAILIMAP_BODY_TYPE_1PART_BASIC:
+ mailimap_body_type_basic_free(bt1p->bd_data.bd_type_basic);
+ break;
+ case MAILIMAP_BODY_TYPE_1PART_MSG:
+ mailimap_body_type_msg_free(bt1p->bd_data.bd_type_msg);
+ break;
+ case MAILIMAP_BODY_TYPE_1PART_TEXT:
+ mailimap_body_type_text_free(bt1p->bd_data.bd_type_text);
+ break;
+ }
+ if (bt1p->bd_ext_1part)
+ mailimap_body_ext_1part_free(bt1p->bd_ext_1part);
+
+ free(bt1p);
+}
+
+
+
+struct mailimap_body_type_basic *
+mailimap_body_type_basic_new(struct mailimap_media_basic * bd_media_basic,
+ struct mailimap_body_fields * bd_fields)
+{
+ struct mailimap_body_type_basic * body_type_basic;
+
+ body_type_basic = malloc(sizeof(* body_type_basic));
+ if (body_type_basic == NULL)
+ return NULL;
+
+ body_type_basic->bd_media_basic = bd_media_basic;
+ body_type_basic->bd_fields = bd_fields;
+
+ return body_type_basic;
+}
+
+void mailimap_body_type_basic_free(struct mailimap_body_type_basic *
+ body_type_basic)
+{
+ mailimap_media_basic_free(body_type_basic->bd_media_basic);
+ mailimap_body_fields_free(body_type_basic->bd_fields);
+ free(body_type_basic);
+}
+
+
+struct mailimap_body_type_mpart *
+mailimap_body_type_mpart_new(clist * bd_list, char * bd_media_subtype,
+ struct mailimap_body_ext_mpart * bd_ext_mpart)
+{
+ struct mailimap_body_type_mpart * body_type_mpart;
+
+ body_type_mpart = malloc(sizeof(* body_type_mpart));
+ if (body_type_mpart == NULL)
+ return NULL;
+
+ body_type_mpart->bd_list = bd_list;
+ body_type_mpart->bd_media_subtype = bd_media_subtype;
+ body_type_mpart->bd_ext_mpart = bd_ext_mpart;
+
+ return body_type_mpart;
+}
+
+void mailimap_body_type_mpart_free(struct mailimap_body_type_mpart *
+ body_type_mpart)
+{
+ clist_foreach(body_type_mpart->bd_list,
+ (clist_func) mailimap_body_free, NULL);
+ clist_free(body_type_mpart->bd_list);
+ mailimap_media_subtype_free(body_type_mpart->bd_media_subtype);
+ if (body_type_mpart->bd_ext_mpart)
+ mailimap_body_ext_mpart_free(body_type_mpart->bd_ext_mpart);
+
+ free(body_type_mpart);
+}
+
+
+struct mailimap_body_type_msg *
+mailimap_body_type_msg_new(struct mailimap_body_fields * bd_fields,
+ struct mailimap_envelope * bd_envelope,
+ struct mailimap_body * bd_body,
+ uint32_t bd_lines)
+{
+ struct mailimap_body_type_msg * body_type_msg;
+
+ body_type_msg = malloc(sizeof(* body_type_msg));
+ if (body_type_msg == NULL)
+ return NULL;
+
+ body_type_msg->bd_fields = bd_fields;
+ body_type_msg->bd_envelope = bd_envelope;
+ body_type_msg->bd_body = bd_body;
+ body_type_msg->bd_lines = bd_lines;
+
+ return body_type_msg;
+}
+
+void
+mailimap_body_type_msg_free(struct mailimap_body_type_msg * body_type_msg)
+{
+ mailimap_body_fields_free(body_type_msg->bd_fields);
+ mailimap_envelope_free(body_type_msg->bd_envelope);
+ mailimap_body_free(body_type_msg->bd_body);
+ free(body_type_msg);
+}
+
+
+
+struct mailimap_body_type_text *
+mailimap_body_type_text_new(char * bd_media_text,
+ struct mailimap_body_fields * bd_fields,
+ uint32_t bd_lines)
+{
+ struct mailimap_body_type_text * body_type_text;
+
+ body_type_text = malloc(sizeof(* body_type_text));
+ if (body_type_text == NULL)
+ return NULL;
+
+ body_type_text->bd_media_text = bd_media_text;
+ body_type_text->bd_fields = bd_fields;
+ body_type_text->bd_lines = bd_lines;
+
+ return body_type_text;
+}
+
+void
+mailimap_body_type_text_free(struct mailimap_body_type_text * body_type_text)
+{
+ mailimap_media_text_free(body_type_text->bd_media_text);
+ mailimap_body_fields_free(body_type_text->bd_fields);
+ free(body_type_text);
+}
+
+
+
+struct mailimap_capability *
+mailimap_capability_new(int cap_type, char * cap_auth_type, char * cap_name)
+{
+ struct mailimap_capability * cap;
+
+ cap = malloc(sizeof(* cap));
+ if (cap == NULL)
+ return NULL;
+ cap->cap_type = cap_type;
+ switch (cap_type) {
+ case MAILIMAP_CAPABILITY_AUTH_TYPE:
+ cap->cap_data.cap_auth_type = cap_auth_type;
+ break;
+ case MAILIMAP_CAPABILITY_NAME:
+ cap->cap_data.cap_name = cap_name;
+ break;
+ }
+
+ return cap;
+}
+
+void mailimap_capability_free(struct mailimap_capability * c)
+{
+ switch (c->cap_type) {
+ case MAILIMAP_CAPABILITY_AUTH_TYPE:
+ free(c->cap_data.cap_auth_type);
+ break;
+ case MAILIMAP_CAPABILITY_NAME:
+ free(c->cap_data.cap_name);
+ break;
+ }
+ free(c);
+}
+
+
+struct mailimap_capability_data *
+mailimap_capability_data_new(clist * cap_list)
+{
+ struct mailimap_capability_data * cap_data;
+
+ cap_data = malloc(sizeof(* cap_data));
+ if (cap_data == NULL)
+ return NULL;
+
+ cap_data->cap_list = cap_list;
+
+ return cap_data;
+}
+
+void
+mailimap_capability_data_free(struct mailimap_capability_data * cap_data)
+{
+ if (cap_data->cap_list) {
+ clist_foreach(cap_data->cap_list,
+ (clist_func) mailimap_capability_free, NULL);
+ clist_free(cap_data->cap_list);
+ }
+ free(cap_data);
+}
+
+
+
+
+struct mailimap_continue_req *
+mailimap_continue_req_new(int cr_type, struct mailimap_resp_text * cr_text,
+ char * cr_base64)
+{
+ struct mailimap_continue_req * cont_req;
+
+ cont_req = malloc(sizeof(* cont_req));
+ if (cont_req == NULL)
+ return NULL;
+ cont_req->cr_type = cr_type;
+ switch (cr_type) {
+ case MAILIMAP_CONTINUE_REQ_TEXT:
+ cont_req->cr_data.cr_text = cr_text;
+ break;
+ case MAILIMAP_CONTINUE_REQ_BASE64:
+ cont_req->cr_data.cr_base64 = cr_base64;
+ break;
+ }
+
+ return cont_req;
+}
+
+void mailimap_continue_req_free(struct mailimap_continue_req * cont_req)
+{
+ switch (cont_req->cr_type) {
+ case MAILIMAP_CONTINUE_REQ_TEXT:
+ mailimap_resp_text_free(cont_req->cr_data.cr_text);
+ break;
+ case MAILIMAP_CONTINUE_REQ_BASE64:
+ mailimap_base64_free(cont_req->cr_data.cr_base64);
+ break;
+ }
+ free(cont_req);
+}
+
+struct mailimap_date_time *
+mailimap_date_time_new(int dt_day, int dt_month, int dt_year, int dt_hour,
+ int dt_min, int dt_sec, int dt_zone)
+{
+ struct mailimap_date_time * date_time;
+
+ date_time = malloc(sizeof(* date_time));
+ if (date_time == NULL)
+ return NULL;
+
+ date_time->dt_day = dt_day;
+ date_time->dt_month = dt_month;
+ date_time->dt_year = dt_year;
+ date_time->dt_hour = dt_hour;
+ date_time->dt_min = dt_min;
+ date_time->dt_day = dt_sec;
+ date_time->dt_zone = dt_zone;
+
+ return date_time;
+}
+
+void mailimap_date_time_free(struct mailimap_date_time * date_time)
+{
+ free(date_time);
+}
+
+
+
+struct mailimap_envelope *
+mailimap_envelope_new(char * env_date, char * env_subject,
+ struct mailimap_env_from * env_from,
+ struct mailimap_env_sender * env_sender,
+ struct mailimap_env_reply_to * env_reply_to,
+ struct mailimap_env_to * env_to,
+ struct mailimap_env_cc* env_cc,
+ struct mailimap_env_bcc * env_bcc,
+ char * env_in_reply_to, char * env_message_id)
+{
+ struct mailimap_envelope * env;
+
+ env = malloc(sizeof(* env));
+ if (env == NULL)
+ return NULL;
+
+ env->env_date = env_date;
+ env->env_subject = env_subject;
+ env->env_from = env_from;
+ env->env_sender = env_sender;
+ env->env_reply_to = env_reply_to;
+ env->env_to = env_to;
+ env->env_cc = env_cc;
+ env->env_bcc = env_bcc;
+ env->env_in_reply_to = env_in_reply_to;
+ env->env_message_id = env_message_id;
+
+ return env;
+}
+
+
+void mailimap_envelope_free(struct mailimap_envelope * env)
+{
+ if (env->env_date)
+ mailimap_env_date_free(env->env_date);
+ if (env->env_subject)
+ mailimap_env_subject_free(env->env_subject);
+ if (env->env_from)
+ mailimap_env_from_free(env->env_from);
+ if (env->env_sender)
+ mailimap_env_sender_free(env->env_sender);
+ if (env->env_reply_to)
+ mailimap_env_reply_to_free(env->env_reply_to);
+ if (env->env_to)
+ mailimap_env_to_free(env->env_to);
+ if (env->env_cc)
+ mailimap_env_cc_free(env->env_cc);
+ if (env->env_bcc)
+ mailimap_env_bcc_free(env->env_bcc);
+ if (env->env_in_reply_to)
+ mailimap_env_in_reply_to_free(env->env_in_reply_to);
+ if (env->env_message_id)
+ mailimap_env_message_id_free(env->env_message_id);
+
+ free(env);
+}
+
+
+static void mailimap_address_list_free(clist * addr_list)
+{
+ if (addr_list != NULL) {
+ clist_foreach(addr_list, (clist_func) mailimap_address_free, NULL);
+ clist_free(addr_list);
+ }
+}
+
+
+struct mailimap_env_bcc * mailimap_env_bcc_new(clist * bcc_list)
+{
+ struct mailimap_env_bcc * env_bcc;
+
+ env_bcc = malloc(sizeof(* env_bcc));
+ if (env_bcc == NULL)
+ return NULL;
+ env_bcc->bcc_list = bcc_list;
+
+ return env_bcc;
+}
+
+void mailimap_env_bcc_free(struct mailimap_env_bcc * env_bcc)
+{
+ mailimap_address_list_free(env_bcc->bcc_list);
+ free(env_bcc);
+}
+
+
+struct mailimap_env_cc * mailimap_env_cc_new(clist * cc_list)
+{
+ struct mailimap_env_cc * env_cc;
+
+ env_cc = malloc(sizeof(* env_cc));
+ if (env_cc == NULL)
+ return NULL;
+ env_cc->cc_list = cc_list;
+
+ return env_cc;
+}
+
+void mailimap_env_cc_free(struct mailimap_env_cc * env_cc)
+{
+ mailimap_address_list_free(env_cc->cc_list);
+ free(env_cc);
+}
+
+
+void mailimap_env_date_free(char * date)
+{
+ mailimap_nstring_free(date);
+}
+
+
+struct mailimap_env_from * mailimap_env_from_new(clist * frm_list)
+{
+ struct mailimap_env_from * env_from;
+
+ env_from = malloc(sizeof(* env_from));
+ if (env_from == NULL)
+ return NULL;
+ env_from->frm_list = frm_list;
+
+ return env_from;
+}
+
+void mailimap_env_from_free(struct mailimap_env_from * env_from)
+{
+ mailimap_address_list_free(env_from->frm_list);
+ free(env_from);
+}
+
+
+void mailimap_env_in_reply_to_free(char * in_reply_to)
+{
+ mailimap_nstring_free(in_reply_to);
+}
+
+void mailimap_env_message_id_free(char * message_id)
+{
+ mailimap_nstring_free(message_id);
+}
+
+struct mailimap_env_reply_to * mailimap_env_reply_to_new(clist * rt_list)
+{
+ struct mailimap_env_reply_to * env_reply_to;
+
+ env_reply_to = malloc(sizeof(* env_reply_to));
+ if (env_reply_to == NULL)
+ return NULL;
+ env_reply_to->rt_list = rt_list;
+
+ return env_reply_to;
+}
+
+void
+mailimap_env_reply_to_free(struct mailimap_env_reply_to * env_reply_to)
+{
+ mailimap_address_list_free(env_reply_to->rt_list);
+ free(env_reply_to);
+}
+
+struct mailimap_env_sender * mailimap_env_sender_new(clist * snd_list)
+{
+ struct mailimap_env_sender * env_sender;
+
+ env_sender = malloc(sizeof(* env_sender));
+ if (env_sender == NULL)
+ return NULL;
+ env_sender->snd_list = snd_list;
+
+ return env_sender;
+}
+
+void mailimap_env_sender_free(struct mailimap_env_sender * env_sender)
+{
+ mailimap_address_list_free(env_sender->snd_list);
+ free(env_sender);
+}
+
+void mailimap_env_subject_free(char * subject)
+{
+ mailimap_nstring_free(subject);
+}
+
+struct mailimap_env_to * mailimap_env_to_new(clist * to_list)
+{
+ struct mailimap_env_to * env_to;
+
+ env_to = malloc(sizeof(* env_to));
+ if (env_to == NULL)
+ return NULL;
+ env_to->to_list = to_list;
+
+ return env_to;
+}
+
+void mailimap_env_to_free(struct mailimap_env_to * env_to)
+{
+ mailimap_address_list_free(env_to->to_list);
+ free(env_to);
+}
+
+
+
+struct mailimap_flag * mailimap_flag_new(int fl_type,
+ char * fl_keyword, char * fl_extension)
+{
+ struct mailimap_flag * f;
+
+ f = malloc(sizeof(* f));
+ if (f == NULL)
+ return NULL;
+ f->fl_type = fl_type;
+ switch (fl_type) {
+ case MAILIMAP_FLAG_KEYWORD:
+ f->fl_data.fl_keyword = fl_keyword;
+ break;
+ case MAILIMAP_FLAG_EXTENSION:
+ f->fl_data.fl_extension = fl_extension;
+ break;
+ }
+
+ return f;
+}
+
+void mailimap_flag_free(struct mailimap_flag * f)
+{
+ switch (f->fl_type) {
+ case MAILIMAP_FLAG_KEYWORD:
+ mailimap_flag_keyword_free(f->fl_data.fl_keyword);
+ break;
+ case MAILIMAP_FLAG_EXTENSION:
+ mailimap_flag_extension_free(f->fl_data.fl_extension);
+ break;
+ }
+ free(f);
+}
+
+
+
+void mailimap_flag_extension_free(char * flag_extension)
+{
+ mailimap_atom_free(flag_extension);
+}
+
+
+
+struct mailimap_flag_fetch *
+mailimap_flag_fetch_new(int fl_type, struct mailimap_flag * fl_flag)
+{
+ struct mailimap_flag_fetch * flag_fetch;
+
+ flag_fetch = malloc(sizeof(* flag_fetch));
+ if (flag_fetch == NULL)
+ return NULL;
+
+ flag_fetch->fl_type = fl_type;
+ flag_fetch->fl_flag = fl_flag;
+
+ return flag_fetch;
+}
+
+void mailimap_flag_fetch_free(struct mailimap_flag_fetch * flag_fetch)
+{
+ if (flag_fetch->fl_flag)
+ mailimap_flag_free(flag_fetch->fl_flag);
+ free(flag_fetch);
+}
+
+
+
+void mailimap_flag_keyword_free(char * flag_keyword)
+{
+ mailimap_atom_free(flag_keyword);
+}
+
+
+
+
+struct mailimap_flag_list *
+mailimap_flag_list_new(clist * fl_list)
+{
+ struct mailimap_flag_list * flag_list;
+
+ flag_list = malloc(sizeof(* flag_list));
+ if (flag_list == NULL)
+ return NULL;
+ flag_list->fl_list = fl_list;
+
+ return flag_list;
+}
+
+void mailimap_flag_list_free(struct mailimap_flag_list * flag_list)
+{
+ clist_foreach(flag_list->fl_list, (clist_func) mailimap_flag_free, NULL);
+ clist_free(flag_list->fl_list);
+ free(flag_list);
+}
+
+
+
+
+
+struct mailimap_flag_perm *
+mailimap_flag_perm_new(int fl_type, struct mailimap_flag * fl_flag)
+{
+ struct mailimap_flag_perm * flag_perm;
+
+ flag_perm = malloc(sizeof(* flag_perm));
+ if (flag_perm == NULL)
+ return NULL;
+
+ flag_perm->fl_type = fl_type;
+ flag_perm->fl_flag = fl_flag;
+
+ return flag_perm;
+}
+
+void mailimap_flag_perm_free(struct mailimap_flag_perm * flag_perm)
+{
+ if (flag_perm->fl_flag != NULL)
+ mailimap_flag_free(flag_perm->fl_flag);
+ free(flag_perm);
+}
+
+
+
+
+struct mailimap_greeting *
+mailimap_greeting_new(int gr_type,
+ struct mailimap_resp_cond_auth * gr_auth,
+ struct mailimap_resp_cond_bye * gr_bye)
+{
+ struct mailimap_greeting * greeting;
+
+ greeting = malloc(sizeof(* greeting));
+ if (greeting == NULL)
+ return NULL;
+ greeting->gr_type = gr_type;
+ switch (gr_type) {
+ case MAILIMAP_GREETING_RESP_COND_AUTH:
+ greeting->gr_data.gr_auth = gr_auth;
+ break;
+ case MAILIMAP_GREETING_RESP_COND_BYE:
+ greeting->gr_data.gr_bye = gr_bye;
+ break;
+ }
+
+ return greeting;
+}
+
+void mailimap_greeting_free(struct mailimap_greeting * greeting)
+{
+ switch (greeting->gr_type) {
+ case MAILIMAP_GREETING_RESP_COND_AUTH:
+ mailimap_resp_cond_auth_free(greeting->gr_data.gr_auth);
+ break;
+ case MAILIMAP_GREETING_RESP_COND_BYE:
+ mailimap_resp_cond_bye_free(greeting->gr_data.gr_bye);
+ break;
+ }
+ free(greeting);
+}
+
+
+
+void
+mailimap_header_fld_name_free(char * header_fld_name)
+{
+ mailimap_astring_free(header_fld_name);
+}
+
+
+
+struct mailimap_header_list *
+mailimap_header_list_new(clist * hdr_list)
+{
+ struct mailimap_header_list * header_list;
+
+ header_list = malloc(sizeof(* header_list));
+ if (header_list == NULL)
+ return NULL;
+
+ header_list->hdr_list = hdr_list;
+
+ return header_list;
+}
+
+void
+mailimap_header_list_free(struct mailimap_header_list * header_list)
+{
+ clist_foreach(header_list->hdr_list,
+ (clist_func) mailimap_header_fld_name_free,
+ NULL);
+ clist_free(header_list->hdr_list);
+ free(header_list);
+}
+
+
+
+void mailimap_literal_free(char * literal)
+{
+ /* free(literal); */
+ mmap_string_unref(literal);
+}
+
+void mailimap_mailbox_free(char * mb)
+{
+ mailimap_astring_free(mb);
+}
+
+
+
+
+struct mailimap_status_info *
+mailimap_status_info_new(int st_att, uint32_t st_value)
+{
+ struct mailimap_status_info * info;
+
+ info = malloc(sizeof(* info));
+ if (info == NULL)
+ return NULL;
+ info->st_att = st_att;
+ info->st_value = st_value;
+
+ return info;
+}
+
+void mailimap_status_info_free(struct mailimap_status_info * info)
+{
+ free(info);
+}
+
+
+
+struct mailimap_mailbox_data_status *
+mailimap_mailbox_data_status_new(char * st_mailbox,
+ clist * st_info_list)
+{
+ struct mailimap_mailbox_data_status * mb_data_status;
+
+ mb_data_status = malloc(sizeof(* mb_data_status));
+ if (mb_data_status == NULL)
+ return NULL;
+ mb_data_status->st_mailbox = st_mailbox;
+ mb_data_status->st_info_list = st_info_list;
+
+ return mb_data_status;
+}
+
+void
+mailimap_mailbox_data_search_free(clist * data_search)
+{
+ clist_foreach(data_search, (clist_func) mailimap_number_alloc_free, NULL);
+ clist_free(data_search);
+}
+
+void
+mailimap_mailbox_data_status_free(struct mailimap_mailbox_data_status * info)
+{
+ mailimap_mailbox_free(info->st_mailbox);
+ clist_foreach(info->st_info_list, (clist_func) mailimap_status_info_free,
+ NULL);
+ clist_free(info->st_info_list);
+ free(info);
+}
+
+
+static void
+mailimap_mailbox_data_flags_free(struct mailimap_flag_list * flag_list)
+{
+ mailimap_flag_list_free(flag_list);
+}
+
+static void
+mailimap_mailbox_data_list_free(struct mailimap_mailbox_list * mb_list)
+{
+ mailimap_mailbox_list_free(mb_list);
+}
+
+static void
+mailimap_mailbox_data_lsub_free(struct mailimap_mailbox_list * mb_lsub)
+{
+ mailimap_mailbox_list_free(mb_lsub);
+}
+
+
+
+
+
+
+struct mailimap_mailbox_data *
+mailimap_mailbox_data_new(int mbd_type, struct mailimap_flag_list * mbd_flags,
+ struct mailimap_mailbox_list * mbd_list,
+ struct mailimap_mailbox_list * mbd_lsub,
+ clist * mbd_search,
+ struct mailimap_mailbox_data_status * mbd_status,
+ uint32_t mbd_exists,
+ uint32_t mbd_recent)
+{
+ struct mailimap_mailbox_data * data;
+
+ data = malloc(sizeof(* data));
+ if (data == NULL)
+ return NULL;
+
+ data->mbd_type = mbd_type;
+ switch (mbd_type) {
+ case MAILIMAP_MAILBOX_DATA_FLAGS:
+ data->mbd_data.mbd_flags = mbd_flags;
+ break;
+ case MAILIMAP_MAILBOX_DATA_LIST:
+ data->mbd_data.mbd_list = mbd_list;
+ break;
+ case MAILIMAP_MAILBOX_DATA_LSUB:
+ data->mbd_data.mbd_lsub = mbd_lsub;
+ break;
+ case MAILIMAP_MAILBOX_DATA_SEARCH:
+ data->mbd_data.mbd_search = mbd_search;
+ break;
+ case MAILIMAP_MAILBOX_DATA_STATUS:
+ data->mbd_data.mbd_status = mbd_status;
+ break;
+ case MAILIMAP_MAILBOX_DATA_EXISTS:
+ data->mbd_data.mbd_exists = mbd_exists;
+ break;
+ case MAILIMAP_MAILBOX_DATA_RECENT:
+ data->mbd_data.mbd_recent = mbd_recent;
+ break;
+ }
+
+ return data;
+}
+
+void
+mailimap_mailbox_data_free(struct mailimap_mailbox_data * mb_data)
+{
+ switch (mb_data->mbd_type) {
+ case MAILIMAP_MAILBOX_DATA_FLAGS:
+ if (mb_data->mbd_data.mbd_flags != NULL)
+ mailimap_mailbox_data_flags_free(mb_data->mbd_data.mbd_flags);
+ break;
+ case MAILIMAP_MAILBOX_DATA_LIST:
+ if (mb_data->mbd_data.mbd_list != NULL)
+ mailimap_mailbox_data_list_free(mb_data->mbd_data.mbd_list);
+ break;
+ case MAILIMAP_MAILBOX_DATA_LSUB:
+ if (mb_data->mbd_data.mbd_lsub != NULL)
+ mailimap_mailbox_data_lsub_free(mb_data->mbd_data.mbd_lsub);
+ break;
+ case MAILIMAP_MAILBOX_DATA_SEARCH:
+ if (mb_data->mbd_data.mbd_search != NULL)
+ mailimap_mailbox_data_search_free(mb_data->mbd_data.mbd_search);
+ break;
+ case MAILIMAP_MAILBOX_DATA_STATUS:
+ if (mb_data->mbd_data.mbd_status != NULL)
+ mailimap_mailbox_data_status_free(mb_data->mbd_data.mbd_status);
+ break;
+ }
+ free(mb_data);
+}
+
+
+
+
+
+struct mailimap_mbx_list_flags *
+mailimap_mbx_list_flags_new(int mbf_type, clist * mbf_oflags,
+ int mbf_sflag)
+{
+ struct mailimap_mbx_list_flags * mbx_list_flags;
+
+ mbx_list_flags = malloc(sizeof(* mbx_list_flags));
+ if (mbx_list_flags == NULL)
+ return NULL;
+
+ mbx_list_flags->mbf_type = mbf_type;
+ mbx_list_flags->mbf_oflags = mbf_oflags;
+ mbx_list_flags->mbf_sflag = mbf_sflag;
+
+ return mbx_list_flags;
+}
+
+void
+mailimap_mbx_list_flags_free(struct mailimap_mbx_list_flags * mbx_list_flags)
+{
+ clist_foreach(mbx_list_flags->mbf_oflags,
+ (clist_func) mailimap_mbx_list_oflag_free,
+ NULL);
+ clist_free(mbx_list_flags->mbf_oflags);
+
+ free(mbx_list_flags);
+}
+
+
+struct mailimap_mbx_list_oflag *
+mailimap_mbx_list_oflag_new(int of_type, char * of_flag_ext)
+{
+ struct mailimap_mbx_list_oflag * oflag;
+
+ oflag = malloc(sizeof(* oflag));
+ if (oflag == NULL)
+ return NULL;
+
+ oflag->of_type = of_type;
+ oflag->of_flag_ext = of_flag_ext;
+
+ return oflag;
+}
+
+void
+mailimap_mbx_list_oflag_free(struct mailimap_mbx_list_oflag * oflag)
+{
+ if (oflag->of_flag_ext != NULL)
+ mailimap_flag_extension_free(oflag->of_flag_ext);
+ free(oflag);
+}
+
+
+
+struct mailimap_mailbox_list *
+mailimap_mailbox_list_new(struct mailimap_mbx_list_flags * mbx_flags,
+ char mb_delimiter, char * mb_name)
+{
+ struct mailimap_mailbox_list * mb_list;
+
+ mb_list = malloc(sizeof(* mb_list));
+ if (mb_list == NULL)
+ return NULL;
+
+ mb_list->mb_flag = mbx_flags;
+ mb_list->mb_delimiter = mb_delimiter;
+ mb_list->mb_name = mb_name;
+
+ return mb_list;
+}
+
+void
+mailimap_mailbox_list_free(struct mailimap_mailbox_list * mb_list)
+{
+ if (mb_list->mb_flag != NULL)
+ mailimap_mbx_list_flags_free(mb_list->mb_flag);
+ if (mb_list->mb_name != NULL)
+ mailimap_mailbox_free(mb_list->mb_name);
+ free(mb_list);
+}
+
+
+
+struct mailimap_media_basic *
+mailimap_media_basic_new(int med_type,
+ char * med_basic_type, char * med_subtype)
+{
+ struct mailimap_media_basic * media_basic;
+
+ media_basic = malloc(sizeof(* media_basic));
+ if (media_basic == NULL)
+ return NULL;
+ media_basic->med_type = med_type;
+ media_basic->med_basic_type = med_basic_type;
+ media_basic->med_subtype = med_subtype;
+
+ return media_basic;
+}
+
+void
+mailimap_media_basic_free(struct mailimap_media_basic * media_basic)
+{
+ mailimap_string_free(media_basic->med_basic_type);
+ mailimap_media_subtype_free(media_basic->med_subtype);
+ free(media_basic);
+}
+
+
+
+void mailimap_media_subtype_free(char * media_subtype)
+{
+ mmap_string_unref(media_subtype);
+}
+
+
+void mailimap_media_text_free(char * media_text)
+{
+ mailimap_media_subtype_free(media_text);
+}
+
+
+
+struct mailimap_message_data *
+mailimap_message_data_new(uint32_t mdt_number, int mdt_type,
+ struct mailimap_msg_att * mdt_msg_att)
+{
+ struct mailimap_message_data * msg_data;
+
+ msg_data = malloc(sizeof(* msg_data));
+ if (msg_data == NULL)
+ free(msg_data);
+
+ msg_data->mdt_number = mdt_number;
+ msg_data->mdt_type = mdt_type;
+ msg_data->mdt_msg_att = mdt_msg_att;
+
+ return msg_data;
+}
+
+void
+mailimap_message_data_free(struct mailimap_message_data * msg_data)
+{
+ if (msg_data->mdt_msg_att != NULL)
+ mailimap_msg_att_free(msg_data->mdt_msg_att);
+ free(msg_data);
+}
+
+
+
+
+struct mailimap_msg_att_item *
+mailimap_msg_att_item_new(int att_type,
+ struct mailimap_msg_att_dynamic * att_dyn,
+ struct mailimap_msg_att_static * att_static)
+{
+ struct mailimap_msg_att_item * item;
+
+ item = malloc(sizeof(* item));
+ if (item == NULL)
+ return item;
+
+ item->att_type = att_type;
+ switch (att_type) {
+ case MAILIMAP_MSG_ATT_ITEM_DYNAMIC:
+ item->att_data.att_dyn = att_dyn;
+ break;
+ case MAILIMAP_MSG_ATT_ITEM_STATIC:
+ item->att_data.att_static = att_static;
+ break;
+ }
+
+ return item;
+}
+
+void
+mailimap_msg_att_item_free(struct mailimap_msg_att_item * item)
+{
+ switch (item->att_type) {
+ case MAILIMAP_MSG_ATT_ITEM_DYNAMIC:
+ mailimap_msg_att_dynamic_free(item->att_data.att_dyn);
+ break;
+ case MAILIMAP_MSG_ATT_ITEM_STATIC:
+ mailimap_msg_att_static_free(item->att_data.att_static);
+ break;
+ }
+ free(item);
+}
+
+
+struct mailimap_msg_att *
+mailimap_msg_att_new(clist * att_list)
+{
+ struct mailimap_msg_att * msg_att;
+
+ msg_att = malloc(sizeof(* msg_att));
+ if (msg_att == NULL)
+ return NULL;
+
+ msg_att->att_list = att_list;
+ msg_att->att_number = 0;
+
+ return msg_att;
+}
+
+void mailimap_msg_att_free(struct mailimap_msg_att * msg_att)
+{
+ clist_foreach(msg_att->att_list,
+ (clist_func) mailimap_msg_att_item_free, NULL);
+ clist_free(msg_att->att_list);
+ free(msg_att);
+}
+
+
+
+struct mailimap_msg_att_dynamic *
+mailimap_msg_att_dynamic_new(clist * att_list)
+{
+ struct mailimap_msg_att_dynamic * msg_att_dyn;
+
+ msg_att_dyn = malloc(sizeof(* msg_att_dyn));
+ if (msg_att_dyn == NULL)
+ return NULL;
+
+ msg_att_dyn->att_list = att_list;
+
+ return msg_att_dyn;
+}
+
+void
+mailimap_msg_att_dynamic_free(struct mailimap_msg_att_dynamic * msg_att_dyn)
+{
+ if (msg_att_dyn->att_list != NULL) {
+ clist_foreach(msg_att_dyn->att_list,
+ (clist_func) mailimap_flag_fetch_free,
+ NULL);
+ clist_free(msg_att_dyn->att_list);
+ }
+ free(msg_att_dyn);
+}
+
+
+struct mailimap_msg_att_body_section *
+mailimap_msg_att_body_section_new(struct mailimap_section * sec_section,
+ uint32_t sec_origin_octet,
+ char * sec_body_part,
+ size_t sec_length)
+{
+ struct mailimap_msg_att_body_section * msg_att_body_section;
+
+ msg_att_body_section = malloc(sizeof(* msg_att_body_section));
+ if (msg_att_body_section == NULL)
+ return NULL;
+
+ msg_att_body_section->sec_section = sec_section;
+ msg_att_body_section->sec_origin_octet = sec_origin_octet;
+ msg_att_body_section->sec_body_part = sec_body_part;
+ msg_att_body_section->sec_length = sec_length;
+
+ return msg_att_body_section;
+}
+
+void
+mailimap_msg_att_body_section_free(struct mailimap_msg_att_body_section *
+ msg_att_body_section)
+{
+ if (msg_att_body_section->sec_section != NULL)
+ mailimap_section_free(msg_att_body_section->sec_section);
+ if (msg_att_body_section->sec_body_part != NULL)
+ mailimap_nstring_free(msg_att_body_section->sec_body_part);
+ free(msg_att_body_section);
+}
+
+
+
+
+
+
+void mailimap_msg_att_envelope_free(struct mailimap_envelope * env)
+{
+ mailimap_envelope_free(env);
+}
+
+void
+mailimap_msg_att_internaldate_free(struct mailimap_date_time * date_time)
+{
+ mailimap_date_time_free(date_time);
+}
+
+void
+mailimap_msg_att_rfc822_free(char * str)
+{
+ mailimap_nstring_free(str);
+}
+
+
+void
+mailimap_msg_att_rfc822_header_free(char * str)
+{
+ mailimap_nstring_free(str);
+}
+
+void
+mailimap_msg_att_rfc822_text_free(char * str)
+{
+ mailimap_nstring_free(str);
+}
+
+void
+mailimap_msg_att_body_free(struct mailimap_body * body)
+{
+ mailimap_body_free(body);
+}
+
+void
+mailimap_msg_att_bodystructure_free(struct mailimap_body * body)
+{
+ mailimap_body_free(body);
+}
+
+
+
+struct mailimap_msg_att_static *
+mailimap_msg_att_static_new(int att_type, struct mailimap_envelope * att_env,
+ struct mailimap_date_time * att_internal_date,
+ char * att_rfc822,
+ char * att_rfc822_header,
+ char * att_rfc822_text,
+ size_t att_length,
+ uint32_t att_rfc822_size,
+ struct mailimap_body * att_bodystructure,
+ struct mailimap_body * att_body,
+ struct mailimap_msg_att_body_section * att_body_section,
+ uint32_t att_uid)
+{
+ struct mailimap_msg_att_static * item;
+
+ item = malloc(sizeof(* item));
+ if (item == NULL)
+ return FALSE;
+
+ item->att_type = att_type;
+ switch (att_type) {
+ case MAILIMAP_MSG_ATT_ENVELOPE:
+ item->att_data.att_env = att_env;
+ break;
+ case MAILIMAP_MSG_ATT_INTERNALDATE:
+ item->att_data.att_internal_date = att_internal_date;
+ break;
+ case MAILIMAP_MSG_ATT_RFC822:
+ item->att_data.att_rfc822.att_content = att_rfc822;
+ item->att_data.att_rfc822.att_length = att_length;
+ break;
+ case MAILIMAP_MSG_ATT_RFC822_HEADER:
+ item->att_data.att_rfc822_header.att_content = att_rfc822_header;
+ item->att_data.att_rfc822_header.att_length = att_length;
+ break;
+ case MAILIMAP_MSG_ATT_RFC822_TEXT:
+ item->att_data.att_rfc822_text.att_content = att_rfc822_text;
+ item->att_data.att_rfc822_text.att_length = att_length;
+ break;
+ case MAILIMAP_MSG_ATT_RFC822_SIZE:
+ item->att_data.att_rfc822_size = att_rfc822_size;
+ break;
+ case MAILIMAP_MSG_ATT_BODY:
+ item->att_data.att_body = att_body;
+ break;
+ case MAILIMAP_MSG_ATT_BODYSTRUCTURE:
+ item->att_data.att_bodystructure = att_bodystructure;
+ break;
+ case MAILIMAP_MSG_ATT_BODY_SECTION:
+ item->att_data.att_body_section = att_body_section;
+ break;
+ case MAILIMAP_MSG_ATT_UID:
+ item->att_data.att_uid = att_uid;
+ break;
+ }
+
+ return item;
+}
+
+void
+mailimap_msg_att_static_free(struct mailimap_msg_att_static * item)
+{
+ switch (item->att_type) {
+ case MAILIMAP_MSG_ATT_ENVELOPE:
+ if (item->att_data.att_env != NULL)
+ mailimap_msg_att_envelope_free(item->att_data.att_env);
+ break;
+ case MAILIMAP_MSG_ATT_INTERNALDATE:
+ if (item->att_data.att_internal_date != NULL)
+ mailimap_msg_att_internaldate_free(item->att_data.att_internal_date);
+ break;
+ case MAILIMAP_MSG_ATT_RFC822:
+ if (item->att_data.att_rfc822.att_content != NULL)
+ mailimap_msg_att_rfc822_free(item->att_data.att_rfc822.att_content);
+ break;
+ case MAILIMAP_MSG_ATT_RFC822_HEADER:
+ if (item->att_data.att_rfc822_header.att_content != NULL)
+ mailimap_msg_att_rfc822_header_free(item->att_data.att_rfc822_header.att_content);
+ break;
+ case MAILIMAP_MSG_ATT_RFC822_TEXT:
+ if (item->att_data.att_rfc822_text.att_content != NULL)
+ mailimap_msg_att_rfc822_text_free(item->att_data.att_rfc822_text.att_content);
+ break;
+ case MAILIMAP_MSG_ATT_BODYSTRUCTURE:
+ if (item->att_data.att_bodystructure != NULL)
+ mailimap_msg_att_bodystructure_free(item->att_data.att_bodystructure);
+ break;
+ case MAILIMAP_MSG_ATT_BODY:
+ if (item->att_data.att_body != NULL)
+ mailimap_msg_att_body_free(item->att_data.att_body);
+ break;
+ case MAILIMAP_MSG_ATT_BODY_SECTION:
+ if (item->att_data.att_body_section != NULL)
+ mailimap_msg_att_body_section_free(item->att_data.att_body_section);
+ break;
+ }
+ free(item);
+}
+
+
+
+
+void mailimap_nstring_free(char * str)
+{
+ if (str != NULL)
+ mailimap_string_free(str);
+}
+
+
+
+
+
+
+
+struct mailimap_cont_req_or_resp_data *
+mailimap_cont_req_or_resp_data_new(int rsp_type,
+ struct mailimap_continue_req * rsp_cont_req,
+ struct mailimap_response_data * rsp_resp_data)
+{
+ struct mailimap_cont_req_or_resp_data * cont_req_or_resp_data;
+
+ cont_req_or_resp_data = malloc(sizeof(* cont_req_or_resp_data));
+ if (cont_req_or_resp_data == NULL)
+ return NULL;
+
+ cont_req_or_resp_data->rsp_type = rsp_type;
+ switch (rsp_type) {
+ case MAILIMAP_RESP_CONT_REQ:
+ cont_req_or_resp_data->rsp_data.rsp_cont_req = rsp_cont_req;
+ break;
+ case MAILIMAP_RESP_RESP_DATA:
+ cont_req_or_resp_data->rsp_data.rsp_resp_data = rsp_resp_data;
+ break;
+ }
+
+ return cont_req_or_resp_data;
+}
+
+void
+mailimap_cont_req_or_resp_data_free(struct mailimap_cont_req_or_resp_data *
+ cont_req_or_resp_data)
+{
+ switch (cont_req_or_resp_data->rsp_type) {
+ case MAILIMAP_RESP_CONT_REQ:
+ if (cont_req_or_resp_data->rsp_data.rsp_cont_req != NULL)
+ mailimap_continue_req_free(cont_req_or_resp_data->rsp_data.rsp_cont_req);
+ break;
+ case MAILIMAP_RESP_RESP_DATA:
+ if (cont_req_or_resp_data->rsp_data.rsp_resp_data != NULL)
+ mailimap_response_data_free(cont_req_or_resp_data->rsp_data.rsp_resp_data);
+ break;
+ }
+ free(cont_req_or_resp_data);
+}
+
+
+
+
+struct mailimap_response *
+mailimap_response_new(clist * rsp_cont_req_or_resp_data_list,
+ struct mailimap_response_done * rsp_resp_done)
+{
+ struct mailimap_response * resp;
+
+ resp = malloc(sizeof(* resp));
+ if (resp == NULL)
+ return NULL;
+
+ resp->rsp_cont_req_or_resp_data_list = rsp_cont_req_or_resp_data_list;
+ resp->rsp_resp_done = rsp_resp_done;
+
+ return resp;
+}
+
+void
+mailimap_response_free(struct mailimap_response * resp)
+{
+ if (resp->rsp_cont_req_or_resp_data_list != NULL) {
+ clist_foreach(resp->rsp_cont_req_or_resp_data_list,
+ (clist_func) mailimap_cont_req_or_resp_data_free, NULL);
+ clist_free(resp->rsp_cont_req_or_resp_data_list);
+ }
+ mailimap_response_done_free(resp->rsp_resp_done);
+ free(resp);
+}
+
+
+
+struct mailimap_response_data *
+mailimap_response_data_new(int rsp_type,
+ struct mailimap_resp_cond_state * rsp_cond_state,
+ struct mailimap_resp_cond_bye * rsp_bye,
+ struct mailimap_mailbox_data * rsp_mailbox_data,
+ struct mailimap_message_data * rsp_message_data,
+ struct mailimap_capability_data * rsp_capability_data)
+{
+ struct mailimap_response_data * resp_data;
+
+ resp_data = malloc(sizeof(* resp_data));
+ if (resp_data == NULL)
+ return NULL;
+ resp_data->rsp_type = rsp_type;
+
+ switch (rsp_type) {
+ case MAILIMAP_RESP_DATA_TYPE_COND_STATE:
+ resp_data->rsp_data.rsp_cond_state = rsp_cond_state;
+ break;
+ case MAILIMAP_RESP_DATA_TYPE_COND_BYE:
+ resp_data->rsp_data.rsp_bye = rsp_bye;
+ break;
+ case MAILIMAP_RESP_DATA_TYPE_MAILBOX_DATA:
+ resp_data->rsp_data.rsp_mailbox_data = rsp_mailbox_data;
+ break;
+ case MAILIMAP_RESP_DATA_TYPE_MESSAGE_DATA:
+ resp_data->rsp_data.rsp_message_data = rsp_message_data;
+ break;
+ case MAILIMAP_RESP_DATA_TYPE_CAPABILITY_DATA:
+ resp_data->rsp_data.rsp_capability_data = rsp_capability_data;
+ break;
+ }
+
+ return resp_data;
+}
+
+void
+mailimap_response_data_free(struct mailimap_response_data * resp_data)
+{
+ switch (resp_data->rsp_type) {
+ case MAILIMAP_RESP_DATA_TYPE_COND_STATE:
+ if (resp_data->rsp_data.rsp_cond_state != NULL)
+ mailimap_resp_cond_state_free(resp_data->rsp_data.rsp_cond_state);
+ break;
+ case MAILIMAP_RESP_DATA_TYPE_COND_BYE:
+ if (resp_data->rsp_data.rsp_bye != NULL)
+ mailimap_resp_cond_bye_free(resp_data->rsp_data.rsp_bye);
+ break;
+ case MAILIMAP_RESP_DATA_TYPE_MAILBOX_DATA:
+ if (resp_data->rsp_data.rsp_mailbox_data != NULL)
+ mailimap_mailbox_data_free(resp_data->rsp_data.rsp_mailbox_data);
+ break;
+ case MAILIMAP_RESP_DATA_TYPE_MESSAGE_DATA:
+ if (resp_data->rsp_data.rsp_message_data != NULL)
+ mailimap_message_data_free(resp_data->rsp_data.rsp_message_data);
+ break;
+ case MAILIMAP_RESP_DATA_TYPE_CAPABILITY_DATA:
+ if (resp_data->rsp_data.rsp_capability_data != NULL)
+ mailimap_capability_data_free(resp_data->rsp_data.rsp_capability_data);
+ break;
+ }
+ free(resp_data);
+}
+
+
+
+struct mailimap_response_done *
+mailimap_response_done_new(int rsp_type,
+ struct mailimap_response_tagged * rsp_tagged,
+ struct mailimap_response_fatal * rsp_fatal)
+{
+ struct mailimap_response_done * resp_done;
+
+ resp_done = malloc(sizeof(* resp_done));
+ if (resp_done == NULL)
+ return NULL;
+
+ resp_done->rsp_type = rsp_type;
+ switch (rsp_type) {
+ case MAILIMAP_RESP_DONE_TYPE_TAGGED:
+ resp_done->rsp_data.rsp_tagged = rsp_tagged;
+ break;
+ case MAILIMAP_RESP_DONE_TYPE_FATAL:
+ resp_done->rsp_data.rsp_fatal = rsp_fatal;
+ break;
+ }
+
+ return resp_done;
+}
+
+void mailimap_response_done_free(struct mailimap_response_done *
+ resp_done)
+{
+ switch (resp_done->rsp_type) {
+ case MAILIMAP_RESP_DONE_TYPE_TAGGED:
+ mailimap_response_tagged_free(resp_done->rsp_data.rsp_tagged);
+ break;
+ case MAILIMAP_RESP_DONE_TYPE_FATAL:
+ mailimap_response_fatal_free(resp_done->rsp_data.rsp_fatal);
+ break;
+ }
+ free(resp_done);
+}
+
+struct mailimap_response_fatal *
+mailimap_response_fatal_new(struct mailimap_resp_cond_bye * rsp_bye)
+{
+ struct mailimap_response_fatal * resp_fatal;
+
+ resp_fatal = malloc(sizeof(* resp_fatal));
+ if (resp_fatal == NULL)
+ return NULL;
+
+ resp_fatal->rsp_bye = rsp_bye;
+
+ return NULL;
+}
+
+void mailimap_response_fatal_free(struct mailimap_response_fatal * resp_fatal)
+{
+ mailimap_resp_cond_bye_free(resp_fatal->rsp_bye);
+ free(resp_fatal);
+}
+
+struct mailimap_response_tagged *
+mailimap_response_tagged_new(char * rsp_tag,
+ struct mailimap_resp_cond_state * rsp_cond_state)
+{
+ struct mailimap_response_tagged * resp_tagged;
+
+ resp_tagged = malloc(sizeof(* resp_tagged));
+ if (resp_tagged == NULL)
+ return NULL;
+
+ resp_tagged->rsp_tag = rsp_tag;
+ resp_tagged->rsp_cond_state = rsp_cond_state;
+
+ return resp_tagged;
+}
+
+void
+mailimap_response_tagged_free(struct mailimap_response_tagged * tagged)
+{
+ mailimap_tag_free(tagged->rsp_tag);
+ mailimap_resp_cond_state_free(tagged->rsp_cond_state);
+ free(tagged);
+}
+
+
+
+struct mailimap_resp_cond_auth *
+mailimap_resp_cond_auth_new(int rsp_type,
+ struct mailimap_resp_text * rsp_text)
+{
+ struct mailimap_resp_cond_auth * cond_auth;
+
+ cond_auth = malloc(sizeof(* cond_auth));
+ if (cond_auth == NULL)
+ return NULL;
+
+ cond_auth->rsp_type = rsp_type;
+ cond_auth->rsp_text = rsp_text;
+
+ return cond_auth;
+}
+
+void
+mailimap_resp_cond_auth_free(struct mailimap_resp_cond_auth * cond_auth)
+{
+ mailimap_resp_text_free(cond_auth->rsp_text);
+ free(cond_auth);
+}
+
+
+
+struct mailimap_resp_cond_bye *
+mailimap_resp_cond_bye_new(struct mailimap_resp_text * rsp_text)
+{
+ struct mailimap_resp_cond_bye * cond_bye;
+
+ cond_bye = malloc(sizeof(* cond_bye));
+ if (cond_bye == NULL)
+ return NULL;
+
+ cond_bye->rsp_text = rsp_text;
+
+ return cond_bye;
+}
+
+
+void
+mailimap_resp_cond_bye_free(struct mailimap_resp_cond_bye * cond_bye)
+{
+ mailimap_resp_text_free(cond_bye->rsp_text);
+ free(cond_bye);
+}
+
+
+struct mailimap_resp_cond_state *
+mailimap_resp_cond_state_new(int rsp_type,
+ struct mailimap_resp_text * rsp_text)
+{
+ struct mailimap_resp_cond_state * cond_state;
+
+ cond_state = malloc(sizeof(* cond_state));
+ if (cond_state == NULL)
+ return NULL;
+
+ cond_state->rsp_type = rsp_type;
+ cond_state->rsp_text = rsp_text;
+
+ return cond_state;
+}
+
+void
+mailimap_resp_cond_state_free(struct mailimap_resp_cond_state * cond_state)
+{
+ mailimap_resp_text_free(cond_state->rsp_text);
+ free(cond_state);
+}
+
+
+struct mailimap_resp_text *
+mailimap_resp_text_new(struct mailimap_resp_text_code * rsp_code,
+ char * rsp_text)
+{
+ struct mailimap_resp_text * resp_text;
+
+ resp_text = malloc(sizeof(* resp_text));
+ if (resp_text == NULL)
+ return NULL;
+
+ resp_text->rsp_code = rsp_code;
+ resp_text->rsp_text = rsp_text;
+
+ return resp_text;
+}
+
+void mailimap_resp_text_free(struct mailimap_resp_text * resp_text)
+{
+ if (resp_text->rsp_code)
+ mailimap_resp_text_code_free(resp_text->rsp_code);
+ if (resp_text->rsp_text)
+ mailimap_text_free(resp_text->rsp_text);
+ free(resp_text);
+}
+
+
+
+
+struct mailimap_resp_text_code *
+mailimap_resp_text_code_new(int rc_type, clist * rc_badcharset,
+ struct mailimap_capability_data * rc_cap_data,
+ clist * rc_perm_flags,
+ uint32_t rc_uidnext, uint32_t rc_uidvalidity,
+ uint32_t rc_first_unseen, char * rc_atom, char * rc_atom_value)
+{
+ struct mailimap_resp_text_code * resp_text_code;
+
+ resp_text_code = malloc(sizeof(* resp_text_code));
+ if (resp_text_code == NULL)
+ return NULL;
+
+ resp_text_code->rc_type = rc_type;
+ switch (rc_type) {
+ case MAILIMAP_RESP_TEXT_CODE_BADCHARSET:
+ resp_text_code->rc_data.rc_badcharset = rc_badcharset;
+ break;
+ case MAILIMAP_RESP_TEXT_CODE_CAPABILITY_DATA:
+ resp_text_code->rc_data.rc_cap_data = rc_cap_data;
+ break;
+ case MAILIMAP_RESP_TEXT_CODE_PERMANENTFLAGS:
+ resp_text_code->rc_data.rc_perm_flags = rc_perm_flags;
+ break;
+ case MAILIMAP_RESP_TEXT_CODE_UIDNEXT:
+ resp_text_code->rc_data.rc_uidnext = rc_uidnext;
+ break;
+ case MAILIMAP_RESP_TEXT_CODE_UIDVALIDITY:
+ resp_text_code->rc_data.rc_uidvalidity = rc_uidvalidity;
+ break;
+ case MAILIMAP_RESP_TEXT_CODE_UNSEEN:
+ resp_text_code->rc_data.rc_first_unseen = rc_first_unseen;
+ break;
+ case MAILIMAP_RESP_TEXT_CODE_OTHER:
+ resp_text_code->rc_data.rc_atom.atom_name = rc_atom;
+ resp_text_code->rc_data.rc_atom.atom_value = rc_atom_value;
+ break;
+ }
+
+ return resp_text_code;
+}
+
+void
+mailimap_resp_text_code_free(struct mailimap_resp_text_code * resp_text_code)
+{
+ switch (resp_text_code->rc_type) {
+ case MAILIMAP_RESP_TEXT_CODE_BADCHARSET:
+ if (resp_text_code->rc_data.rc_badcharset != NULL) {
+ clist_foreach(resp_text_code->rc_data.rc_badcharset,
+ (clist_func) mailimap_astring_free,
+ NULL);
+ clist_free(resp_text_code->rc_data.rc_badcharset);
+ }
+ break;
+ case MAILIMAP_RESP_TEXT_CODE_CAPABILITY_DATA:
+ if (resp_text_code->rc_data.rc_cap_data != NULL)
+ mailimap_capability_data_free(resp_text_code->rc_data.rc_cap_data);
+ break;
+ case MAILIMAP_RESP_TEXT_CODE_PERMANENTFLAGS:
+ if (resp_text_code->rc_data.rc_perm_flags != NULL) {
+ clist_foreach(resp_text_code->rc_data.rc_perm_flags,
+ (clist_func) mailimap_flag_perm_free, NULL);
+ clist_free(resp_text_code->rc_data.rc_perm_flags);
+ }
+ break;
+ case MAILIMAP_RESP_TEXT_CODE_OTHER:
+ if (resp_text_code->rc_data.rc_atom.atom_name != NULL)
+ mailimap_atom_free(resp_text_code->rc_data.rc_atom.atom_name);
+ if (resp_text_code->rc_data.rc_atom.atom_value != NULL)
+ mailimap_custom_string_free(resp_text_code->rc_data.rc_atom.atom_value);
+ break;
+ }
+ free(resp_text_code);
+}
+
+
+struct mailimap_section *
+mailimap_section_new(struct mailimap_section_spec * sec_spec)
+{
+ struct mailimap_section * section;
+
+ section = malloc(sizeof(* section));
+ if (section == NULL)
+ return NULL;
+
+ section->sec_spec = sec_spec;
+
+ return section;
+}
+
+void mailimap_section_free(struct mailimap_section * section)
+{
+ if (section->sec_spec != NULL)
+ mailimap_section_spec_free(section->sec_spec);
+ free(section);
+}
+
+
+
+struct mailimap_section_msgtext *
+mailimap_section_msgtext_new(int sec_type,
+ struct mailimap_header_list * sec_header_list)
+{
+ struct mailimap_section_msgtext * msgtext;
+
+ msgtext = malloc(sizeof(* msgtext));
+ if (msgtext == NULL)
+ return FALSE;
+
+ msgtext->sec_type = sec_type;
+ msgtext->sec_header_list = sec_header_list;
+
+ return msgtext;
+}
+
+void
+mailimap_section_msgtext_free(struct mailimap_section_msgtext * msgtext)
+{
+ if (msgtext->sec_header_list != NULL)
+ mailimap_header_list_free(msgtext->sec_header_list);
+ free(msgtext);
+}
+
+
+struct mailimap_section_part *
+mailimap_section_part_new(clist * sec_id)
+{
+ struct mailimap_section_part * section_part;
+
+ section_part = malloc(sizeof(* section_part));
+ if (section_part == NULL)
+ return NULL;
+
+ section_part->sec_id = sec_id;
+
+ return section_part;
+}
+
+void
+mailimap_section_part_free(struct mailimap_section_part * section_part)
+{
+ clist_foreach(section_part->sec_id,
+ (clist_func) mailimap_number_alloc_free, NULL);
+ clist_free(section_part->sec_id);
+ free(section_part);
+}
+
+
+struct mailimap_section_spec *
+mailimap_section_spec_new(int sec_type,
+ struct mailimap_section_msgtext * sec_msgtext,
+ struct mailimap_section_part * sec_part,
+ struct mailimap_section_text * sec_text)
+{
+ struct mailimap_section_spec * section_spec;
+
+ section_spec = malloc(sizeof(* section_spec));
+ if (section_spec == NULL)
+ return NULL;
+
+ section_spec->sec_type = sec_type;
+ switch (sec_type) {
+ case MAILIMAP_SECTION_SPEC_SECTION_MSGTEXT:
+ section_spec->sec_data.sec_msgtext = sec_msgtext;
+ break;
+ case MAILIMAP_SECTION_SPEC_SECTION_PART:
+ section_spec->sec_data.sec_part = sec_part;
+ break;
+ }
+ section_spec->sec_text = sec_text;
+
+ return section_spec;
+}
+
+void
+mailimap_section_spec_free(struct mailimap_section_spec * section_spec)
+{
+ if (section_spec->sec_text)
+ mailimap_section_text_free(section_spec->sec_text);
+
+ switch (section_spec->sec_type) {
+ case MAILIMAP_SECTION_SPEC_SECTION_PART:
+ if (section_spec->sec_data.sec_part != NULL)
+ mailimap_section_part_free(section_spec->sec_data.sec_part);
+ break;
+ case MAILIMAP_SECTION_SPEC_SECTION_MSGTEXT:
+ /* handle case where it can be detached */
+ if (section_spec->sec_data.sec_msgtext != NULL)
+ mailimap_section_msgtext_free(section_spec->sec_data.sec_msgtext);
+ break;
+ }
+ free(section_spec);
+}
+
+
+struct mailimap_section_text *
+mailimap_section_text_new(int sec_type,
+ struct mailimap_section_msgtext * sec_msgtext)
+{
+ struct mailimap_section_text * section_text;
+
+ section_text = malloc(sizeof(* section_text));
+ if (section_text == NULL)
+ return NULL;
+
+ section_text->sec_type = sec_type;
+ section_text->sec_msgtext = sec_msgtext;
+
+ return section_text;
+}
+
+void
+mailimap_section_text_free(struct mailimap_section_text * section_text)
+{
+ if (section_text->sec_msgtext != NULL)
+ mailimap_section_msgtext_free(section_text->sec_msgtext);
+ free(section_text);
+}
+
+
+
+
+void
+mailimap_string_free(char * str)
+{
+ mmap_string_unref(str);
+}
+
+
+
+
+
+void mailimap_tag_free(char * tag)
+{
+ mailimap_custom_string_free(tag);
+}
+
+
+void mailimap_text_free(char * text)
+{
+ mailimap_custom_string_free(text);
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+/* ************************************************************************* */
+/* ************************************************************************* */
+/* ************************************************************************* */
+/* ************************************************************************* */
+/* ************************************************************************* */
+/* ************************************************************************* */
+
+
+
+
+
+
+/* sender only */
+
+
+/* COPY FETCH SEARCH STORE */
+/* set */
+
+struct mailimap_set_item *
+mailimap_set_item_new(uint32_t set_first, uint32_t set_last)
+{
+ struct mailimap_set_item * item;
+
+ item = malloc(sizeof(* item));
+ if (item == NULL)
+ return NULL;
+
+ item->set_first = set_first;
+ item->set_last = set_last;
+
+ return item;
+}
+
+void mailimap_set_item_free(struct mailimap_set_item * set_item)
+{
+ free(set_item);
+}
+
+struct mailimap_set * mailimap_set_new(clist * set_list)
+{
+ struct mailimap_set * set;
+
+ set = malloc(sizeof(* set));
+ if (set == NULL)
+ return NULL;
+
+ set->set_list = set_list;
+
+ return set;
+}
+
+void mailimap_set_free(struct mailimap_set * set)
+{
+ clist_foreach(set->set_list, (clist_func) mailimap_set_item_free, NULL);
+ clist_free(set->set_list);
+ free(set);
+}
+
+/* SEARCH with date key */
+/* date */
+
+struct mailimap_date *
+mailimap_date_new(int dt_day, int dt_month, int dt_year)
+{
+ struct mailimap_date * date;
+
+ date = malloc(sizeof(* date));
+ if (date == NULL)
+ return NULL;
+
+ date->dt_day = dt_day;
+ date->dt_month = dt_month;
+ date->dt_year = dt_year;
+
+ return date;
+}
+
+void mailimap_date_free(struct mailimap_date * date)
+{
+ free(date);
+}
+
+
+
+struct mailimap_fetch_att *
+mailimap_fetch_att_new(int att_type, struct mailimap_section * att_section,
+ uint32_t att_offset, uint32_t att_size)
+{
+ struct mailimap_fetch_att * fetch_att;
+
+ fetch_att = malloc(sizeof(* fetch_att));
+ if (fetch_att == NULL)
+ return NULL;
+ fetch_att->att_type = att_type;
+ fetch_att->att_section = att_section;
+ fetch_att->att_offset = att_offset;
+ fetch_att->att_size = att_size;
+
+ return fetch_att;
+}
+
+void mailimap_fetch_att_free(struct mailimap_fetch_att * fetch_att)
+{
+ if (fetch_att->att_section != NULL)
+ mailimap_section_free(fetch_att->att_section);
+ free(fetch_att);
+}
+
+
+
+struct mailimap_fetch_type *
+mailimap_fetch_type_new(int ft_type,
+ struct mailimap_fetch_att * ft_fetch_att,
+ clist * ft_fetch_att_list)
+{
+ struct mailimap_fetch_type * fetch_type;
+
+ fetch_type = malloc(sizeof(* fetch_type));
+ if (fetch_type == NULL)
+ return NULL;
+ fetch_type->ft_type = ft_type;
+ switch (ft_type) {
+ case MAILIMAP_FETCH_TYPE_FETCH_ATT:
+ fetch_type->ft_data.ft_fetch_att = ft_fetch_att;
+ break;
+ case MAILIMAP_FETCH_TYPE_FETCH_ATT_LIST:
+ fetch_type->ft_data.ft_fetch_att_list = ft_fetch_att_list;
+ break;
+ }
+
+ return fetch_type;
+}
+
+void mailimap_fetch_type_free(struct mailimap_fetch_type * fetch_type)
+{
+ switch (fetch_type->ft_type) {
+ case MAILIMAP_FETCH_TYPE_FETCH_ATT:
+ mailimap_fetch_att_free(fetch_type->ft_data.ft_fetch_att);
+ break;
+ case MAILIMAP_FETCH_TYPE_FETCH_ATT_LIST:
+ clist_foreach(fetch_type->ft_data.ft_fetch_att_list,
+ (clist_func) mailimap_fetch_att_free, NULL);
+ clist_free(fetch_type->ft_data.ft_fetch_att_list);
+ break;
+ }
+ free(fetch_type);
+}
+
+
+
+
+struct mailimap_store_att_flags *
+mailimap_store_att_flags_new(int fl_sign, int fl_silent,
+ struct mailimap_flag_list * fl_flag_list)
+{
+ struct mailimap_store_att_flags * store_att_flags;
+
+ store_att_flags = malloc(sizeof(* store_att_flags));
+ if (store_att_flags == NULL)
+ return NULL;
+
+ store_att_flags->fl_sign = fl_sign;
+ store_att_flags->fl_silent = fl_silent;
+ store_att_flags->fl_flag_list = fl_flag_list;
+
+ return store_att_flags;
+}
+
+void mailimap_store_att_flags_free(struct mailimap_store_att_flags *
+ store_att_flags)
+{
+ mailimap_flag_list_free(store_att_flags->fl_flag_list);
+ free(store_att_flags);
+}
+
+
+struct mailimap_search_key *
+mailimap_search_key_new(int sk_type,
+ char * sk_bcc, struct mailimap_date * sk_before, char * sk_body,
+ char * sk_cc, char * sk_from, char * sk_keyword,
+ struct mailimap_date * sk_on, struct mailimap_date * sk_since,
+ char * sk_subject, char * sk_text, char * sk_to,
+ char * sk_unkeyword, char * sk_header_name,
+ char * sk_header_value, uint32_t sk_larger,
+ struct mailimap_search_key * sk_not,
+ struct mailimap_search_key * sk_or1,
+ struct mailimap_search_key * sk_or2,
+ struct mailimap_date * sk_sentbefore,
+ struct mailimap_date * sk_senton,
+ struct mailimap_date * sk_sentsince,
+ uint32_t sk_smaller, struct mailimap_set * sk_uid,
+ struct mailimap_set * sk_set, clist * sk_multiple)
+{
+ struct mailimap_search_key * key;
+
+ key = malloc(sizeof(* key));
+ if (key == NULL)
+ return NULL;
+
+ key->sk_type = sk_type;
+ switch (sk_type) {
+ case MAILIMAP_SEARCH_KEY_BCC:
+ key->sk_data.sk_bcc = sk_bcc;
+ break;
+ case MAILIMAP_SEARCH_KEY_BEFORE:
+ key->sk_data.sk_before = sk_before;
+ break;
+ case MAILIMAP_SEARCH_KEY_BODY:
+ key->sk_data.sk_body = sk_body;
+ break;
+ case MAILIMAP_SEARCH_KEY_CC:
+ key->sk_data.sk_cc = sk_cc;
+ break;
+ case MAILIMAP_SEARCH_KEY_FROM:
+ key->sk_data.sk_from = sk_from;
+ break;
+ case MAILIMAP_SEARCH_KEY_KEYWORD:
+ key->sk_data.sk_keyword = sk_keyword;
+ break;
+ case MAILIMAP_SEARCH_KEY_ON:
+ key->sk_data.sk_on = sk_on;
+ break;
+ case MAILIMAP_SEARCH_KEY_SINCE:
+ key->sk_data.sk_since = sk_since;
+ break;
+ case MAILIMAP_SEARCH_KEY_SUBJECT:
+ key->sk_data.sk_subject = sk_subject;
+ break;
+ case MAILIMAP_SEARCH_KEY_TEXT:
+ key->sk_data.sk_text = sk_text;
+ break;
+ case MAILIMAP_SEARCH_KEY_TO:
+ key->sk_data.sk_to = sk_to;
+ break;
+ case MAILIMAP_SEARCH_KEY_UNKEYWORD:
+ key->sk_data.sk_unkeyword = sk_unkeyword;
+ break;
+ case MAILIMAP_SEARCH_KEY_HEADER:
+ key->sk_data.sk_header.sk_header_name = sk_header_name;
+ key->sk_data.sk_header.sk_header_value = sk_header_value;
+ break;
+ case MAILIMAP_SEARCH_KEY_LARGER:
+ key->sk_data.sk_larger = sk_larger;
+ break;
+ case MAILIMAP_SEARCH_KEY_NOT:
+ key->sk_data.sk_not = sk_not;
+ break;
+ case MAILIMAP_SEARCH_KEY_OR:
+ key->sk_data.sk_or.sk_or1 = sk_or1;
+ key->sk_data.sk_or.sk_or2 = sk_or2;
+ break;
+ case MAILIMAP_SEARCH_KEY_SENTBEFORE:
+ key->sk_data.sk_sentbefore = sk_sentbefore;
+ break;
+ case MAILIMAP_SEARCH_KEY_SENTON:
+ key->sk_data.sk_senton = sk_senton;
+ break;
+ case MAILIMAP_SEARCH_KEY_SENTSINCE:
+ key->sk_data.sk_sentsince = sk_sentsince;
+ break;
+ case MAILIMAP_SEARCH_KEY_SMALLER:
+ key->sk_data.sk_smaller = sk_smaller;
+ break;
+ case MAILIMAP_SEARCH_KEY_UID:
+ key->sk_data.sk_uid = sk_uid;
+ break;
+ case MAILIMAP_SEARCH_KEY_SET:
+ key->sk_data.sk_set = sk_set;
+ break;
+ case MAILIMAP_SEARCH_KEY_MULTIPLE:
+ key->sk_data.sk_multiple = sk_multiple;
+ break;
+ }
+ return key;
+}
+
+
+void mailimap_search_key_free(struct mailimap_search_key * key)
+{
+ switch (key->sk_type) {
+ case MAILIMAP_SEARCH_KEY_BCC:
+ mailimap_astring_free(key->sk_data.sk_bcc);
+ break;
+ case MAILIMAP_SEARCH_KEY_BEFORE:
+ mailimap_date_free(key->sk_data.sk_before);
+ break;
+ case MAILIMAP_SEARCH_KEY_BODY:
+ mailimap_astring_free(key->sk_data.sk_body);
+ break;
+ case MAILIMAP_SEARCH_KEY_CC:
+ mailimap_astring_free(key->sk_data.sk_cc);
+ break;
+ case MAILIMAP_SEARCH_KEY_FROM:
+ mailimap_astring_free(key->sk_data.sk_from);
+ break;
+ case MAILIMAP_SEARCH_KEY_KEYWORD:
+ mailimap_flag_keyword_free(key->sk_data.sk_keyword);
+ break;
+ case MAILIMAP_SEARCH_KEY_ON:
+ mailimap_date_free(key->sk_data.sk_on);
+ break;
+ case MAILIMAP_SEARCH_KEY_SINCE:
+ mailimap_date_free(key->sk_data.sk_since);
+ break;
+ case MAILIMAP_SEARCH_KEY_SUBJECT:
+ mailimap_astring_free(key->sk_data.sk_subject);
+ break;
+ case MAILIMAP_SEARCH_KEY_TEXT:
+ mailimap_astring_free(key->sk_data.sk_text);
+ break;
+ case MAILIMAP_SEARCH_KEY_TO:
+ mailimap_astring_free(key->sk_data.sk_to);
+ break;
+ case MAILIMAP_SEARCH_KEY_UNKEYWORD:
+ mailimap_flag_keyword_free(key->sk_data.sk_unkeyword);
+ break;
+ case MAILIMAP_SEARCH_KEY_HEADER:
+ mailimap_header_fld_name_free(key->sk_data.sk_header.sk_header_name);
+ mailimap_astring_free(key->sk_data.sk_header.sk_header_value);
+ break;
+ case MAILIMAP_SEARCH_KEY_NOT:
+ mailimap_search_key_free(key->sk_data.sk_not);
+ break;
+ case MAILIMAP_SEARCH_KEY_OR:
+ mailimap_search_key_free(key->sk_data.sk_or.sk_or1);
+ mailimap_search_key_free(key->sk_data.sk_or.sk_or2);
+ break;
+ case MAILIMAP_SEARCH_KEY_SENTBEFORE:
+ mailimap_date_free(key->sk_data.sk_sentbefore);
+ break;
+ case MAILIMAP_SEARCH_KEY_SENTON:
+ mailimap_date_free(key->sk_data.sk_senton);
+ break;
+ case MAILIMAP_SEARCH_KEY_SENTSINCE:
+ mailimap_date_free(key->sk_data.sk_sentsince);
+ break;
+ case MAILIMAP_SEARCH_KEY_UID:
+ mailimap_set_free(key->sk_data.sk_uid);
+ break;
+ case MAILIMAP_SEARCH_KEY_SET:
+ mailimap_set_free(key->sk_data.sk_set);
+ break;
+ case MAILIMAP_SEARCH_KEY_MULTIPLE:
+ clist_foreach(key->sk_data.sk_multiple,
+ (clist_func) mailimap_search_key_free, NULL);
+ clist_free(key->sk_data.sk_multiple);
+ break;
+ }
+
+ free(key);
+}
+
+
+
+
+
+
+
+
+struct mailimap_status_att_list *
+mailimap_status_att_list_new(clist * att_list)
+{
+ struct mailimap_status_att_list * status_att_list;
+
+ status_att_list = malloc(sizeof(* status_att_list));
+ if (status_att_list == NULL)
+ return NULL;
+ status_att_list->att_list = att_list;
+
+ return status_att_list;
+}
+
+void mailimap_status_att_list_free(struct mailimap_status_att_list *
+ status_att_list)
+{
+ clist_foreach(status_att_list->att_list, (clist_func) free, NULL);
+ clist_free(status_att_list->att_list);
+ free(status_att_list);
+}
+
+
+
+
+/* main */
+
+
+struct mailimap_selection_info *
+mailimap_selection_info_new(void)
+{
+ struct mailimap_selection_info * sel_info;
+
+ sel_info = malloc(sizeof(* sel_info));
+ if (sel_info == NULL)
+ return NULL;
+
+ sel_info->sel_perm_flags = NULL;
+ sel_info->sel_perm = MAILIMAP_MAILBOX_READWRITE;
+ sel_info->sel_uidnext = 0;
+ sel_info->sel_uidvalidity = 0;
+ sel_info->sel_first_unseen = 0;
+ sel_info->sel_flags = NULL;
+ sel_info->sel_exists = 0;
+ sel_info->sel_recent = 0;
+ sel_info->sel_unseen = 0;
+
+ return sel_info;
+}
+
+void
+mailimap_selection_info_free(struct mailimap_selection_info * sel_info)
+{
+ if (sel_info->sel_perm_flags != NULL) {
+ clist_foreach(sel_info->sel_perm_flags,
+ (clist_func) mailimap_flag_perm_free, NULL);
+ clist_free(sel_info->sel_perm_flags);
+ }
+ if (sel_info->sel_flags)
+ mailimap_flag_list_free(sel_info->sel_flags);
+
+ free(sel_info);
+}
+
+struct mailimap_connection_info *
+mailimap_connection_info_new(void)
+{
+ struct mailimap_connection_info * conn_info;
+
+ conn_info = malloc(sizeof(* conn_info));
+ if (conn_info == NULL)
+ return NULL;
+
+ conn_info->imap_capability = NULL;
+
+ return conn_info;
+}
+
+void
+mailimap_connection_info_free(struct mailimap_connection_info * conn_info)
+{
+ if (conn_info->imap_capability != NULL)
+ mailimap_capability_data_free(conn_info->imap_capability);
+ free(conn_info);
+}
+
+struct mailimap_response_info *
+mailimap_response_info_new(void)
+{
+ struct mailimap_response_info * resp_info;
+
+ resp_info = malloc(sizeof(* resp_info));
+ if (resp_info == NULL)
+ goto err;
+
+ resp_info->rsp_alert = NULL;
+ resp_info->rsp_parse = NULL;
+ resp_info->rsp_badcharset = NULL;
+ resp_info->rsp_trycreate = FALSE;
+ resp_info->rsp_mailbox_list = clist_new();
+ if (resp_info->rsp_mailbox_list == NULL)
+ goto free;
+ resp_info->rsp_mailbox_lsub = clist_new();
+ if (resp_info->rsp_mailbox_lsub == NULL)
+ goto free_mb_list;
+ resp_info->rsp_search_result = clist_new();
+ if (resp_info->rsp_search_result == NULL)
+ goto free_mb_lsub;
+ resp_info->rsp_status = NULL;
+ resp_info->rsp_expunged = clist_new();
+ if (resp_info->rsp_expunged == NULL)
+ goto free_search_result;
+ resp_info->rsp_fetch_list = clist_new();
+ if (resp_info->rsp_fetch_list == NULL)
+ goto free_expunged;
+
+ return resp_info;
+
+ free_expunged:
+ clist_free(resp_info->rsp_expunged);
+ free_search_result:
+ clist_free(resp_info->rsp_search_result);
+ free_mb_lsub:
+ clist_free(resp_info->rsp_mailbox_lsub);
+ free_mb_list:
+ clist_free(resp_info->rsp_mailbox_list);
+ free:
+ free(resp_info);
+ err:
+ return NULL;
+}
+
+void
+mailimap_response_info_free(struct mailimap_response_info * resp_info)
+{
+ if (resp_info->rsp_alert != NULL)
+ free(resp_info->rsp_alert);
+ if (resp_info->rsp_parse != NULL)
+ free(resp_info->rsp_parse);
+ if (resp_info->rsp_badcharset != NULL) {
+ clist_foreach(resp_info->rsp_badcharset,
+ (clist_func) mailimap_astring_free, NULL);
+ clist_free(resp_info->rsp_badcharset);
+ }
+ if (resp_info->rsp_mailbox_list != NULL) {
+ clist_foreach(resp_info->rsp_mailbox_list,
+ (clist_func) mailimap_mailbox_list_free, NULL);
+ clist_free(resp_info->rsp_mailbox_list);
+ }
+ if (resp_info->rsp_mailbox_lsub != NULL) {
+ clist_foreach(resp_info->rsp_mailbox_lsub,
+ (clist_func) mailimap_mailbox_list_free, NULL);
+ clist_free(resp_info->rsp_mailbox_lsub);
+ }
+ if (resp_info->rsp_search_result != NULL)
+ mailimap_mailbox_data_search_free(resp_info->rsp_search_result);
+ if (resp_info->rsp_status != NULL)
+ mailimap_mailbox_data_status_free(resp_info->rsp_status);
+ if (resp_info->rsp_expunged != NULL) {
+ clist_foreach(resp_info->rsp_expunged,
+ (clist_func) mailimap_number_alloc_free, NULL);
+ clist_free(resp_info->rsp_expunged);
+ }
+ if (resp_info->rsp_fetch_list != NULL) {
+ clist_foreach(resp_info->rsp_fetch_list,
+ (clist_func) mailimap_msg_att_free, NULL);
+ clist_free(resp_info->rsp_fetch_list);
+ }
+
+ free(resp_info);
+}
diff --git a/libetpan/src/low-level/imap/mailimap_types.h b/libetpan/src/low-level/imap/mailimap_types.h
new file mode 100644
index 0000000..532d2c0
--- a/dev/null
+++ b/libetpan/src/low-level/imap/mailimap_types.h
@@ -0,0 +1,3274 @@
+/*
+ * 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$
+ */
+
+/*
+ IMAP4rev1 grammar
+
+ address = "(" addr-name SP addr-adl SP addr-mailbox SP
+ addr-host ")"
+
+ addr-adl = nstring
+ ; Holds route from [RFC-822] route-addr if
+ ; non-NIL
+
+ addr-host = nstring
+ ; NIL indicates [RFC-822] group syntax.
+ ; Otherwise, holds [RFC-822] domain name
+
+ 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
+
+
+
+ addr-name = nstring
+ ; If non-NIL, holds phrase from [RFC-822]
+ ; mailbox after removing [RFC-822] quoting
+
+ append = "APPEND" SP mailbox [SP flag-list] [SP date-time] SP
+ literal
+
+ astring = 1*ASTRING-CHAR / string
+
+ ASTRING-CHAR = ATOM-CHAR / resp-specials
+
+ atom = 1*ATOM-CHAR
+
+ ATOM-CHAR = <any CHAR except atom-specials>
+
+ atom-specials = "(" / ")" / "{" / SP / CTL / list-wildcards /
+ quoted-specials / resp-specials
+
+ authenticate = "AUTHENTICATE" SP auth-type *(CRLF base64)
+
+ auth-type = atom
+ ; Defined by [SASL]
+
+ base64 = *(4base64-char) [base64-terminal]
+
+ base64-char = ALPHA / DIGIT / "+" / "/"
+ ; Case-sensitive
+
+ base64-terminal = (2base64-char "==") / (3base64-char "=")
+
+ body = "(" (body-type-1part / body-type-mpart) ")"
+
+ 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-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
+
+
+ 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
+
+ body-fields = body-fld-param SP body-fld-id SP body-fld-desc SP
+ body-fld-enc SP body-fld-octets
+
+ body-fld-desc = nstring
+
+ body-fld-dsp = "(" string SP body-fld-param ")" / nil
+
+ body-fld-enc = (DQUOTE ("7BIT" / "8BIT" / "BINARY" / "BASE64"/
+ "QUOTED-PRINTABLE") DQUOTE) / string
+
+ body-fld-id = nstring
+
+ body-fld-lang = nstring / "(" string *(SP string) ")"
+
+ body-fld-lines = number
+
+ body-fld-md5 = nstring
+
+ body-fld-octets = number
+
+ body-fld-param = "(" string SP string *(SP string SP string) ")" / nil
+
+ body-type-1part = (body-type-basic / body-type-msg / body-type-text)
+ [SP body-ext-1part]
+
+ body-type-basic = media-basic SP body-fields
+ ; MESSAGE subtype MUST NOT be "RFC822"
+
+ body-type-mpart = 1*body SP media-subtype
+ [SP body-ext-mpart]
+
+ body-type-msg = media-message SP body-fields SP envelope
+ SP body SP body-fld-lines
+
+ body-type-text = media-text SP body-fields SP body-fld-lines
+
+ capability = ("AUTH=" auth-type) / atom
+ ; New capabilities MUST begin with "X" or be
+ ; registered with IANA as standard or
+ ; standards-track
+
+
+ capability-data = "CAPABILITY" *(SP capability) SP "IMAP4rev1"
+ *(SP capability)
+ ; IMAP4rev1 servers which offer RFC 1730
+ ; compatibility MUST list "IMAP4" as the first
+ ; capability.
+
+ CHAR8 = %x01-ff
+ ; any OCTET except NUL, %x00
+
+ command = tag SP (command-any / command-auth / command-nonauth /
+ command-select) CRLF
+ ; Modal based on state
+
+ command-any = "CAPABILITY" / "LOGOUT" / "NOOP" / x-command
+ ; Valid in all states
+
+ command-auth = append / create / delete / examine / list / lsub /
+ rename / select / status / subscribe / unsubscribe
+ ; Valid only in Authenticated or Selected state
+
+ command-nonauth = login / authenticate
+ ; Valid only when in Not Authenticated state
+
+ command-select = "CHECK" / "CLOSE" / "EXPUNGE" / copy / fetch / store /
+ uid / search
+ ; Valid only when in Selected state
+
+ continue-req = "+" SP (resp-text / base64) CRLF
+
+ copy = "COPY" SP set SP mailbox
+
+ create = "CREATE" SP mailbox
+ ; Use of INBOX gives a NO error
+
+ date = date-text / DQUOTE date-text DQUOTE
+
+ date-day = 1*2DIGIT
+ ; Day of month
+
+ date-day-fixed = (SP DIGIT) / 2DIGIT
+ ; Fixed-format version of date-day
+
+ date-month = "Jan" / "Feb" / "Mar" / "Apr" / "May" / "Jun" /
+ "Jul" / "Aug" / "Sep" / "Oct" / "Nov" / "Dec"
+
+ date-text = date-day "-" date-month "-" date-year
+
+ date-year = 4DIGIT
+
+ date-time = DQUOTE date-day-fixed "-" date-month "-" date-year
+ SP time SP zone DQUOTE
+
+ delete = "DELETE" SP mailbox
+ ; Use of INBOX gives a NO error
+
+ digit-nz = %x31-39
+ ; 1-9
+
+ 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 ")"
+
+ env-bcc = "(" 1*address ")" / nil
+
+ env-cc = "(" 1*address ")" / nil
+
+ env-date = nstring
+
+ env-from = "(" 1*address ")" / nil
+
+ env-in-reply-to = nstring
+
+ env-message-id = nstring
+
+ env-reply-to = "(" 1*address ")" / nil
+
+ env-sender = "(" 1*address ")" / nil
+
+ env-subject = nstring
+
+ env-to = "(" 1*address ")" / nil
+
+ examine = "EXAMINE" SP mailbox
+
+ fetch = "FETCH" SP set SP ("ALL" / "FULL" / "FAST" / fetch-att /
+ "(" fetch-att *(SP fetch-att) ")")
+
+ 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"
+
+ 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.
+
+ flag-fetch = flag / "\Recent"
+
+ flag-keyword = atom
+
+ flag-list = "(" [flag *(SP flag)] ")"
+
+ flag-perm = flag / "\*"
+
+ greeting = "*" SP (resp-cond-auth / resp-cond-bye) CRLF
+
+ header-fld-name = astring
+
+ header-list = "(" header-fld-name *(SP header-fld-name) ")"
+
+ list = "LIST" SP mailbox SP list-mailbox
+
+ list-mailbox = 1*list-char / string
+
+ list-char = ATOM-CHAR / list-wildcards / resp-specials
+
+ list-wildcards = "%" / "*"
+
+ literal = "{" number "}" CRLF *CHAR8
+ ; Number represents the number of CHAR8s
+
+ login = "LOGIN" SP userid SP password
+
+ 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.
+
+ 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"
+
+ mailbox-list = "(" [mbx-list-flags] ")" SP
+ (DQUOTE QUOTED-CHAR DQUOTE / nil) SP mailbox
+
+ mbx-list-flags = *(mbx-list-oflag SP) mbx-list-sflag
+ *(SP mbx-list-oflag) /
+ mbx-list-oflag *(SP mbx-list-oflag)
+
+ mbx-list-oflag = "\Noinferiors" / flag-extension
+ ; Other flags; multiple possible per LIST response
+
+ mbx-list-sflag = "\Noselect" / "\Marked" / "\Unmarked"
+ ; Selectability flags; only one per LIST response
+
+ media-basic = ((DQUOTE ("APPLICATION" / "AUDIO" / "IMAGE" / "MESSAGE" /
+ "VIDEO") DQUOTE) / string) SP media-subtype
+ ; Defined in [MIME-IMT]
+
+ media-message = DQUOTE "MESSAGE" DQUOTE SP DQUOTE "RFC822" DQUOTE
+ ; Defined in [MIME-IMT]
+
+ media-subtype = string
+ ; Defined in [MIME-IMT]
+
+ media-text = DQUOTE "TEXT" DQUOTE SP media-subtype
+ ; Defined in [MIME-IMT]
+
+ message-data = nz-number SP ("EXPUNGE" / ("FETCH" SP msg-att))
+
+ msg-att = "(" (msg-att-dynamic / msg-att-static)
+ *(SP (msg-att-dynamic / msg-att-static)) ")"
+
+ msg-att-dynamic = "FLAGS" SP "(" [flag-fetch *(SP flag-fetch)] ")"
+ ; MAY change for a message
+
+ 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
+
+ nil = "NIL"
+
+ nstring = string / nil
+
+ number = 1*DIGIT
+ ; Unsigned 32-bit integer
+ ; (0 <= n < 4,294,967,296)
+
+ nz-number = digit-nz *DIGIT
+ ; Non-zero unsigned 32-bit integer
+ ; (0 < n < 4,294,967,296)
+
+ password = astring
+
+ quoted = DQUOTE *QUOTED-CHAR DQUOTE
+
+ QUOTED-CHAR = <any TEXT-CHAR except quoted-specials> /
+ "\" quoted-specials
+
+ quoted-specials = DQUOTE / "\"
+
+ rename = "RENAME" SP mailbox SP mailbox
+ ; Use of INBOX as a destination gives a NO error
+
+ response = *(continue-req / response-data) response-done
+
+ response-data = "*" SP (resp-cond-state / resp-cond-bye /
+ mailbox-data / message-data / capability-data) CRLF
+
+ response-done = response-tagged / response-fatal
+
+ response-fatal = "*" SP resp-cond-bye CRLF
+ ; Server closes connection immediately
+
+ response-tagged = tag SP resp-cond-state CRLF
+
+ resp-cond-auth = ("OK" / "PREAUTH") SP resp-text
+ ; Authentication condition
+
+ resp-cond-bye = "BYE" SP resp-text
+
+ resp-cond-state = ("OK" / "NO" / "BAD") SP resp-text
+ ; Status condition
+
+ resp-specials = "]"
+
+ resp-text = ["[" resp-text-code "]" SP] text
+
+ 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*<any TEXT-CHAR except "]">]
+
+ search = "SEARCH" [SP "CHARSET" SP astring] 1*(SP search-key)
+ ; CHARSET argument to MUST be registered with IANA
+
+ 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] "]"
+
+ section-msgtext = "HEADER" / "HEADER.FIELDS" [".NOT"] SP header-list /
+ "TEXT"
+ ; top-level or MESSAGE/RFC822 part
+
+ section-part = nz-number *("." nz-number)
+ ; body part nesting
+
+ section-spec = section-msgtext / (section-part ["." section-text])
+
+ section-text = section-msgtext / "MIME"
+ ; text other than actual body part (headers, etc.)
+
+ select = "SELECT" SP mailbox
+
+ 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.
+
+ 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.
+
+
+ status = "STATUS" SP mailbox SP "(" status-att *(SP status-att) ")"
+
+ status-att = "MESSAGES" / "RECENT" / "UIDNEXT" / "UIDVALIDITY" /
+ "UNSEEN"
+
+ store = "STORE" SP set SP store-att-flags
+
+ store-att-flags = (["+" / "-"] "FLAGS" [".SILENT"]) SP
+ (flag-list / (flag *(SP flag)))
+
+ string = quoted / literal
+
+ subscribe = "SUBSCRIBE" SP mailbox
+
+ tag = 1*<any ASTRING-CHAR except "+">
+
+ text = 1*TEXT-CHAR
+
+ TEXT-CHAR = <any CHAR except CR and LF>
+
+ time = 2DIGIT ":" 2DIGIT ":" 2DIGIT
+ ; Hours minutes seconds
+
+ uid = "UID" SP (copy / fetch / search / store)
+ ; Unique identifiers used instead of message
+ ; sequence numbers
+
+ uniqueid = nz-number
+ ; Strictly ascending
+
+ unsubscribe = "UNSUBSCRIBE" SP mailbox
+
+ userid = astring
+
+ x-command = "X" atom <experimental command arguments>
+
+ 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".
+*/
+
+
+#ifndef MAILIMAP_TYPES_H
+
+#define MAILIMAP_TYPES_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <inttypes.h>
+#include <libetpan/mailstream.h>
+#include <libetpan/clist.h>
+
+
+/*
+ IMPORTANT NOTE:
+
+ All allocation functions will take as argument allocated data
+ and will store these data in the structure they will allocate.
+ Data should be persistant during all the use of the structure
+ and will be freed by the free function of the structure
+
+ allocation functions will return NULL on failure
+*/
+
+
+/*
+ mailimap_address represents a mail address
+
+ - personal_name is the name to display in an address
+ '"name"' in '"name" <address@domain>', should be allocated
+ with a malloc()
+
+ - source_route is the source-route information in the
+ mail address (RFC 822), should be allocated with a malloc()
+
+ - mailbox_name is the name of the mailbox 'address' in
+ '"name" <address@domain>', should be allocated with a malloc()
+
+ - host_name is the name of the host 'domain' in
+ '"name" <address@domain>', should be allocated with a malloc()
+
+ if mailbox_name is not NULL and host_name is NULL, this is the name
+ of a group, the next addresses in the list are elements of the group
+ until we reach an address with a NULL mailbox_name.
+*/
+
+struct mailimap_address {
+ char * ad_personal_name; /* can be NULL */
+ char * ad_source_route; /* can be NULL */
+ char * ad_mailbox_name; /* can be NULL */
+ char * ad_host_name; /* can be NULL */
+};
+
+
+struct mailimap_address *
+mailimap_address_new(char * ad_personal_name, char * ad_source_route,
+ char * ad_mailbox_name, char * ad_host_name);
+
+void mailimap_address_free(struct mailimap_address * addr);
+
+
+/* this is the type of MIME body parsed by IMAP server */
+
+enum {
+ MAILIMAP_BODY_ERROR,
+ MAILIMAP_BODY_1PART, /* single part */
+ MAILIMAP_BODY_MPART, /* multi-part */
+};
+
+/*
+ mailimap_body represent a MIME body parsed by IMAP server
+
+ - type is the type of the MIME part (single part or multipart)
+
+ - body_1part is defined if this is a single part
+
+ - body_mpart is defined if this is a multipart
+*/
+
+struct mailimap_body {
+ int bd_type;
+ /* can be MAILIMAP_BODY_1PART or MAILIMAP_BODY_MPART */
+ union {
+ struct mailimap_body_type_1part * bd_body_1part; /* can be NULL */
+ struct mailimap_body_type_mpart * bd_body_mpart; /* can be NULL */
+ } bd_data;
+};
+
+
+struct mailimap_body *
+mailimap_body_new(int bd_type,
+ struct mailimap_body_type_1part * bd_body_1part,
+ struct mailimap_body_type_mpart * bd_body_mpart);
+
+void mailimap_body_free(struct mailimap_body * body);
+
+
+
+/*
+ this is the type of MIME body extension
+*/
+
+enum {
+ MAILIMAP_BODY_EXTENSION_ERROR,
+ MAILIMAP_BODY_EXTENSION_NSTRING, /* string */
+ MAILIMAP_BODY_EXTENSION_NUMBER, /* number */
+ MAILIMAP_BODY_EXTENSION_LIST, /* list of
+ (struct mailimap_body_extension *) */
+};
+
+/*
+ mailimap_body_extension is a future extension header field value
+
+ - type is the type of the body extension (string, number or
+ list of extension)
+
+ - nstring is a string value if the type is string
+
+ - number is a integer value if the type is number
+
+ - list is a list of body extension if the type is a list
+*/
+
+struct mailimap_body_extension {
+ int ext_type;
+ /*
+ can be MAILIMAP_BODY_EXTENSION_NSTRING, MAILIMAP_BODY_EXTENSION_NUMBER
+ or MAILIMAP_BODY_EXTENSION_LIST
+ */
+ union {
+ char * ext_nstring; /* can be NULL */
+ uint32_t ext_number;
+ clist * ext_body_extension_list;
+ /* list of (struct mailimap_body_extension *) */
+ /* can be NULL */
+ } ext_data;
+};
+
+struct mailimap_body_extension *
+mailimap_body_extension_new(int ext_type, char * ext_nstring,
+ uint32_t ext_number,
+ clist * ext_body_extension_list);
+
+void mailimap_body_extension_free(struct mailimap_body_extension * be);
+
+
+/*
+ mailimap_body_ext_1part is the extended result part of a single part
+ bodystructure.
+
+ - body_md5 is the value of the Content-MD5 header field, should be
+ allocated with malloc()
+
+ - body_disposition is the value of the Content-Disposition header field
+
+ - body_language is the value of the Content-Language header field
+
+ - body_extension_list is the list of extension fields value.
+*/
+
+struct mailimap_body_ext_1part {
+ char * bd_md5; /* != NULL */
+ struct mailimap_body_fld_dsp * bd_disposition; /* can be NULL */
+ struct mailimap_body_fld_lang * bd_language; /* can be NULL */
+
+ clist * bd_extension_list; /* list of (struct mailimap_body_extension *) */
+ /* can be NULL */
+};
+
+struct mailimap_body_ext_1part *
+mailimap_body_ext_1part_new(char * bd_md5,
+ struct mailimap_body_fld_dsp * bd_disposition,
+ struct mailimap_body_fld_lang * bd_language,
+ clist * bd_extension_list);
+
+
+void
+mailimap_body_ext_1part_free(struct mailimap_body_ext_1part * body_ext_1part);
+
+
+/*
+ mailimap_body_ext_mpart is the extended result part of a multipart
+ bodystructure.
+
+ - body_parameter is the list of parameters of Content-Type header field
+
+ - body_disposition is the value of Content-Disposition header field
+
+ - body_language is the value of Content-Language header field
+
+ - body_extension_list is the list of extension fields value.
+*/
+
+struct mailimap_body_ext_mpart {
+ struct mailimap_body_fld_param * bd_parameter; /* != NULL */
+ struct mailimap_body_fld_dsp * bd_disposition; /* can be NULL */
+ struct mailimap_body_fld_lang * bd_language; /* can be NULL */
+ clist * bd_extension_list; /* list of (struct mailimap_body_extension *) */
+ /* can be NULL */
+};
+
+struct mailimap_body_ext_mpart *
+mailimap_body_ext_mpart_new(struct mailimap_body_fld_param * bd_parameter,
+ struct mailimap_body_fld_dsp * bd_disposition,
+ struct mailimap_body_fld_lang * bd_language,
+ clist * bd_extension_list);
+
+void
+mailimap_body_ext_mpart_free(struct mailimap_body_ext_mpart * body_ext_mpart);
+
+
+/*
+ mailimap_body_fields is the MIME fields of a MIME part.
+
+ - body_parameter is the list of parameters of Content-Type header field
+
+ - body_id is the value of Content-ID header field, should be allocated
+ with malloc()
+
+ - body_description is the value of Content-Description header field,
+ should be allocated with malloc()
+
+ - body_encoding is the value of Content-Transfer-Encoding header field
+
+ - body_disposition is the value of Content-Disposition header field
+
+ - body_size is the size of the MIME part
+*/
+
+struct mailimap_body_fields {
+ struct mailimap_body_fld_param * bd_parameter; /* != NULL */
+ char * bd_id; /* can be NULL */
+ char * bd_description; /* can be NULL */
+ struct mailimap_body_fld_enc * bd_encoding; /* != NULL */
+ uint32_t bd_size;
+};
+
+struct mailimap_body_fields *
+mailimap_body_fields_new(struct mailimap_body_fld_param * bd_parameter,
+ char * bd_id,
+ char * bd_description,
+ struct mailimap_body_fld_enc * bd_encoding,
+ uint32_t bd_size);
+
+void
+mailimap_body_fields_free(struct mailimap_body_fields * body_fields);
+
+
+
+/*
+ mailimap_body_fld_dsp is the parsed value of the Content-Disposition field
+
+ - disposition_type is the type of Content-Disposition
+ (usually attachment or inline), should be allocated with malloc()
+
+ - attributes is the list of Content-Disposition attributes
+*/
+
+struct mailimap_body_fld_dsp {
+ char * dsp_type; /* != NULL */
+ struct mailimap_body_fld_param * dsp_attributes; /* != NULL */
+};
+
+struct mailimap_body_fld_dsp *
+mailimap_body_fld_dsp_new(char * dsp_type,
+ struct mailimap_body_fld_param * dsp_attributes);
+
+void mailimap_body_fld_dsp_free(struct mailimap_body_fld_dsp * bfd);
+
+
+
+/* these are the different parsed values for Content-Transfer-Encoding */
+
+enum {
+ MAILIMAP_BODY_FLD_ENC_7BIT, /* 7bit */
+ MAILIMAP_BODY_FLD_ENC_8BIT, /* 8bit */
+ MAILIMAP_BODY_FLD_ENC_BINARY, /* binary */
+ MAILIMAP_BODY_FLD_ENC_BASE64, /* base64 */
+ MAILIMAP_BODY_FLD_ENC_QUOTED_PRINTABLE, /* quoted-printable */
+ MAILIMAP_BODY_FLD_ENC_OTHER, /* other */
+};
+
+/*
+ mailimap_body_fld_enc is a parsed value for Content-Transfer-Encoding
+
+ - type is the kind of Content-Transfer-Encoding, this can be
+ MAILIMAP_BODY_FLD_ENC_7BIT, MAILIMAP_BODY_FLD_ENC_8BIT,
+ MAILIMAP_BODY_FLD_ENC_BINARY, MAILIMAP_BODY_FLD_ENC_BASE64,
+ MAILIMAP_BODY_FLD_ENC_QUOTED_PRINTABLE or MAILIMAP_BODY_FLD_ENC_OTHER
+
+ - in case of MAILIMAP_BODY_FLD_ENC_OTHER, this value is defined,
+ should be allocated with malloc()
+*/
+
+struct mailimap_body_fld_enc {
+ int enc_type;
+ char * enc_value; /* can be NULL */
+};
+
+struct mailimap_body_fld_enc *
+mailimap_body_fld_enc_new(int enc_type, char * enc_value);
+
+void mailimap_body_fld_enc_free(struct mailimap_body_fld_enc * bfe);
+
+
+/* this is the type of Content-Language header field value */
+
+enum {
+ MAILIMAP_BODY_FLD_LANG_ERROR, /* error parse */
+ MAILIMAP_BODY_FLD_LANG_SINGLE, /* single value */
+ MAILIMAP_BODY_FLD_LANG_LIST /* list of values */
+};
+
+/*
+ mailimap_body_fld_lang is the parsed value of the Content-Language field
+
+ - type is the type of content, this can be MAILIMAP_BODY_FLD_LANG_SINGLE
+ if this is a single value or MAILIMAP_BODY_FLD_LANG_LIST if there are
+ several values
+
+ - single is the single value if the type is MAILIMAP_BODY_FLD_LANG_SINGLE,
+ should be allocated with malloc()
+
+ - list is the list of value if the type is MAILIMAP_BODY_FLD_LANG_LIST,
+ all elements of the list should be allocated with malloc()
+*/
+
+struct mailimap_body_fld_lang {
+ int lg_type;
+ union {
+ char * lg_single; /* can be NULL */
+ clist * lg_list; /* list of string (char *), can be NULL */
+ } lg_data;
+};
+
+struct mailimap_body_fld_lang *
+mailimap_body_fld_lang_new(int lg_type, char * lg_single, clist * lg_list);
+
+void
+mailimap_body_fld_lang_free(struct mailimap_body_fld_lang * fld_lang);
+
+
+
+/*
+ mailimap_single_body_fld_param is a body field parameter
+
+ - name is the name of the parameter, should be allocated with malloc()
+
+ - value is the value of the parameter, should be allocated with malloc()
+*/
+
+struct mailimap_single_body_fld_param {
+ char * pa_name; /* != NULL */
+ char * pa_value; /* != NULL */
+};
+
+struct mailimap_single_body_fld_param *
+mailimap_single_body_fld_param_new(char * pa_name, char * pa_value);
+
+void
+mailimap_single_body_fld_param_free(struct mailimap_single_body_fld_param * p);
+
+
+/*
+ mailmap_body_fld_param is a list of parameters
+
+ - list is the list of parameters.
+*/
+
+struct mailimap_body_fld_param {
+ clist * pa_list; /* list of (struct mailimap_single_body_fld_param *) */
+ /* != NULL */
+};
+
+struct mailimap_body_fld_param *
+mailimap_body_fld_param_new(clist * pa_list);
+
+void
+mailimap_body_fld_param_free(struct mailimap_body_fld_param * fld_param);
+
+
+/*
+ this is the kind of single part: a text part
+ (when Content-Type is text/xxx), a message part (when Content-Type is
+ message/rfc2822) or a basic part (others than multpart/xxx)
+*/
+
+enum {
+ MAILIMAP_BODY_TYPE_1PART_ERROR, /* parse error */
+ MAILIMAP_BODY_TYPE_1PART_BASIC, /* others then multipart/xxx */
+ MAILIMAP_BODY_TYPE_1PART_MSG, /* message/rfc2822 */
+ MAILIMAP_BODY_TYPE_1PART_TEXT /* text/xxx */
+};
+
+
+/*
+ mailimap_body_type_1part is
+
+ - type is the kind of single part, this can be
+ MAILIMAP_BODY_TYPE_1PART_BASIC, MAILIMAP_BODY_TYPE_1PART_MSG or
+ MAILIMAP_BODY_TYPE_1PART_TEXT.
+
+ - body_type_basic is the basic part when type is
+ MAILIMAP_BODY_TYPE_1PART_BASIC
+
+ - body_type_msg is the message part when type is
+ MAILIMAP_BODY_TYPE_1PART_MSG
+
+ - body_type_text is the text part when type is
+ MAILIMAP_BODY_TYPE_1PART_TEXT
+*/
+
+struct mailimap_body_type_1part {
+ int bd_type;
+ union {
+ struct mailimap_body_type_basic * bd_type_basic; /* can be NULL */
+ struct mailimap_body_type_msg * bd_type_msg; /* can be NULL */
+ struct mailimap_body_type_text * bd_type_text; /* can be NULL */
+ } bd_data;
+ struct mailimap_body_ext_1part * bd_ext_1part; /* can be NULL */
+};
+
+struct mailimap_body_type_1part *
+mailimap_body_type_1part_new(int bd_type,
+ struct mailimap_body_type_basic * bd_type_basic,
+ struct mailimap_body_type_msg * bd_type_msg,
+ struct mailimap_body_type_text * bd_type_text,
+ struct mailimap_body_ext_1part * bd_ext_1part);
+
+void
+mailimap_body_type_1part_free(struct mailimap_body_type_1part * bt1p);
+
+
+
+/*
+ mailimap_body_type_basic is a basic field (with Content-Type other
+ than multipart/xxx, message/rfc2822 and text/xxx
+
+ - media_basic will be the MIME type of the part
+
+ - body_fields will be the parsed fields of the MIME part
+*/
+
+struct mailimap_body_type_basic {
+ struct mailimap_media_basic * bd_media_basic; /* != NULL */
+ struct mailimap_body_fields * bd_fields; /* != NULL */
+};
+
+struct mailimap_body_type_basic *
+mailimap_body_type_basic_new(struct mailimap_media_basic * bd_media_basic,
+ struct mailimap_body_fields * bd_fields);
+
+void mailimap_body_type_basic_free(struct mailimap_body_type_basic *
+ body_type_basic);
+
+/*
+ mailimap_body_type_mpart is a MIME multipart.
+
+ - body_list is the list of sub-parts.
+
+ - media_subtype is the subtype of the multipart (for example
+ in multipart/alternative, this is "alternative")
+
+ - body_ext_mpart is the extended fields of the MIME multipart
+*/
+
+struct mailimap_body_type_mpart {
+ clist * bd_list; /* list of (struct mailimap_body *) */
+ /* != NULL */
+ char * bd_media_subtype; /* != NULL */
+ struct mailimap_body_ext_mpart * bd_ext_mpart; /* can be NULL */
+};
+
+struct mailimap_body_type_mpart *
+mailimap_body_type_mpart_new(clist * bd_list, char * bd_media_subtype,
+ struct mailimap_body_ext_mpart * bd_ext_mpart);
+
+void mailimap_body_type_mpart_free(struct mailimap_body_type_mpart *
+ body_type_mpart);
+
+/*
+ mailimap_body_type_msg is a MIME message part
+
+ - body_fields is the MIME fields of the MIME message part
+
+ - envelope is the list of parsed RFC 822 fields of the MIME message
+
+ - body is the sub-part of the message
+
+ - body_lines is the number of lines of the message part
+*/
+
+struct mailimap_body_type_msg {
+ struct mailimap_body_fields * bd_fields; /* != NULL */
+ struct mailimap_envelope * bd_envelope; /* != NULL */
+ struct mailimap_body * bd_body; /* != NULL */
+ uint32_t bd_lines;
+};
+
+struct mailimap_body_type_msg *
+mailimap_body_type_msg_new(struct mailimap_body_fields * bd_fields,
+ struct mailimap_envelope * bd_envelope,
+ struct mailimap_body * bd_body,
+ uint32_t bd_lines);
+
+void
+mailimap_body_type_msg_free(struct mailimap_body_type_msg * body_type_msg);
+
+
+
+/*
+ mailimap_body_type_text is a single MIME part where Content-Type is text/xxx
+
+ - media-text is the subtype of the text part (for example, in "text/plain",
+ this is "plain", should be allocated with malloc()
+
+ - body_fields is the MIME fields of the MIME message part
+
+ - body_lines is the number of lines of the message part
+*/
+
+struct mailimap_body_type_text {
+ char * bd_media_text; /* != NULL */
+ struct mailimap_body_fields * bd_fields; /* != NULL */
+ uint32_t bd_lines;
+};
+
+struct mailimap_body_type_text *
+mailimap_body_type_text_new(char * bd_media_text,
+ struct mailimap_body_fields * bd_fields,
+ uint32_t bd_lines);
+
+void
+mailimap_body_type_text_free(struct mailimap_body_type_text * body_type_text);
+
+
+
+/* this is the type of capability field */
+
+enum {
+ MAILIMAP_CAPABILITY_AUTH_TYPE, /* when the capability is an
+ authentication type */
+ MAILIMAP_CAPABILITY_NAME, /* other type of capability */
+};
+
+/*
+ mailimap_capability is a capability of the IMAP server
+
+ - type is the type of capability, this is either a authentication type
+ (MAILIMAP_CAPABILITY_AUTH_TYPE) or an other type of capability
+ (MAILIMAP_CAPABILITY_NAME)
+
+ - auth_type is a type of authentication "name" in "AUTH=name",
+ auth_type can be for example "PLAIN", when this is an authentication type,
+ should be allocated with malloc()
+
+ - name is a type of capability when this is not an authentication type,
+ should be allocated with malloc()
+*/
+
+struct mailimap_capability {
+ int cap_type;
+ union {
+ char * cap_auth_type; /* can be NULL */
+ char * cap_name; /* can be NULL */
+ } cap_data;
+};
+
+struct mailimap_capability *
+mailimap_capability_new(int cap_type, char * cap_auth_type, char * cap_name);
+
+void mailimap_capability_free(struct mailimap_capability * c);
+
+
+
+
+/*
+ mailimap_capability_data is a list of capability
+
+ - list is the list of capability
+*/
+
+struct mailimap_capability_data {
+ clist * cap_list; /* list of (struct mailimap_capability *), != NULL */
+};
+
+struct mailimap_capability_data *
+mailimap_capability_data_new(clist * cap_list);
+
+void
+mailimap_capability_data_free(struct mailimap_capability_data * cap_data);
+
+
+
+/* this is the type of continue request data */
+
+enum {
+ MAILIMAP_CONTINUE_REQ_ERROR, /* on parse error */
+ MAILIMAP_CONTINUE_REQ_TEXT, /* when data is a text response */
+ MAILIMAP_CONTINUE_REQ_BASE64, /* when data is a base64 response */
+};
+
+/*
+ mailimap_continue_req is a continue request (a response prefixed by "+")
+
+ - type is the type of continue request response
+ MAILIMAP_CONTINUE_REQ_TEXT (when information data is text),
+ MAILIMAP_CONTINUE_REQ_BASE64 (when information data is base64)
+
+ - text is the information of type text in case of text data
+
+ - base64 is base64 encoded data in the other case, should be allocated
+ with malloc()
+*/
+
+struct mailimap_continue_req {
+ int cr_type;
+ union {
+ struct mailimap_resp_text * cr_text; /* can be NULL */
+ char * cr_base64; /* can be NULL */
+ } cr_data;
+};
+
+struct mailimap_continue_req *
+mailimap_continue_req_new(int cr_type, struct mailimap_resp_text * cr_text,
+ char * cr_base64);
+
+void mailimap_continue_req_free(struct mailimap_continue_req * cont_req);
+
+
+/*
+ mailimap_date_time is a date
+
+ - day is the day of month (1 to 31)
+
+ - month (1 to 12)
+
+ - year (4 digits)
+
+ - hour (0 to 23)
+
+ - min (0 to 59)
+
+ - sec (0 to 59)
+
+ - zone (this is the decimal value that we can read, for example:
+ for "-0200", the value is -200)
+*/
+
+struct mailimap_date_time {
+ int dt_day;
+ int dt_month;
+ int dt_year;
+ int dt_hour;
+ int dt_min;
+ int dt_sec;
+ int dt_zone;
+};
+
+struct mailimap_date_time *
+mailimap_date_time_new(int dt_day, int dt_month, int dt_year, int dt_hour,
+ int dt_min, int dt_sec, int dt_zone);
+
+void mailimap_date_time_free(struct mailimap_date_time * date_time);
+
+
+
+/*
+ mailimap_envelope is the list of fields that can be parsed by
+ the IMAP server.
+
+ - date is the (non-parsed) content of the "Date" header field,
+ should be allocated with malloc()
+
+ - subject is the subject of the message, should be allocated with
+ malloc()
+
+ - sender is the the parsed content of the "Sender" field
+
+ - reply-to is the parsed content of the "Reply-To" field
+
+ - to is the parsed content of the "To" field
+
+ - cc is the parsed content of the "Cc" field
+
+ - bcc is the parsed content of the "Bcc" field
+
+ - in_reply_to is the content of the "In-Reply-To" field,
+ should be allocated with malloc()
+
+ - message_id is the content of the "Message-ID" field,
+ should be allocated with malloc()
+*/
+
+struct mailimap_envelope {
+ char * env_date; /* can be NULL */
+ char * env_subject; /* can be NULL */
+ struct mailimap_env_from * env_from; /* can be NULL */
+ struct mailimap_env_sender * env_sender; /* can be NULL */
+ struct mailimap_env_reply_to * env_reply_to; /* can be NULL */
+ struct mailimap_env_to * env_to; /* can be NULL */
+ struct mailimap_env_cc * env_cc; /* can be NULL */
+ struct mailimap_env_bcc * env_bcc; /* can be NULL */
+ char * env_in_reply_to; /* can be NULL */
+ char * env_message_id; /* can be NULL */
+};
+
+struct mailimap_envelope *
+mailimap_envelope_new(char * env_date, char * env_subject,
+ struct mailimap_env_from * env_from,
+ struct mailimap_env_sender * env_sender,
+ struct mailimap_env_reply_to * env_reply_to,
+ struct mailimap_env_to * env_to,
+ struct mailimap_env_cc* env_cc,
+ struct mailimap_env_bcc * env_bcc,
+ char * env_in_reply_to, char * env_message_id);
+
+void mailimap_envelope_free(struct mailimap_envelope * env);
+
+
+
+/*
+ mailimap_env_bcc is the parsed "Bcc" field
+
+ - list is the list of addresses
+*/
+
+struct mailimap_env_bcc {
+ clist * bcc_list; /* list of (struct mailimap_address *), != NULL */
+};
+
+struct mailimap_env_bcc * mailimap_env_bcc_new(clist * bcc_list);
+
+void mailimap_env_bcc_free(struct mailimap_env_bcc * env_bcc);
+
+
+/*
+ mailimap_env_cc is the parsed "Cc" field
+
+ - list is the list of addresses
+*/
+
+struct mailimap_env_cc {
+ clist * cc_list; /* list of (struct mailimap_address *), != NULL */
+};
+
+struct mailimap_env_cc * mailimap_env_cc_new(clist * cc_list);
+
+void mailimap_env_cc_free(struct mailimap_env_cc * env_cc);
+
+
+
+/*
+ mailimap_env_from is the parsed "From" field
+
+ - list is the list of addresses
+*/
+
+struct mailimap_env_from {
+ clist * frm_list; /* list of (struct mailimap_address *) */
+ /* != NULL */
+};
+
+struct mailimap_env_from * mailimap_env_from_new(clist * frm_list);
+
+void mailimap_env_from_free(struct mailimap_env_from * env_from);
+
+
+
+/*
+ mailimap_env_reply_to is the parsed "Reply-To" field
+
+ - list is the list of addresses
+*/
+
+struct mailimap_env_reply_to {
+ clist * rt_list; /* list of (struct mailimap_address *), != NULL */
+};
+
+struct mailimap_env_reply_to * mailimap_env_reply_to_new(clist * rt_list);
+
+void
+mailimap_env_reply_to_free(struct mailimap_env_reply_to * env_reply_to);
+
+
+
+/*
+ mailimap_env_sender is the parsed "Sender" field
+
+ - list is the list of addresses
+*/
+
+struct mailimap_env_sender {
+ clist * snd_list; /* list of (struct mailimap_address *), != NULL */
+};
+
+struct mailimap_env_sender * mailimap_env_sender_new(clist * snd_list);
+
+void mailimap_env_sender_free(struct mailimap_env_sender * env_sender);
+
+
+
+/*
+ mailimap_env_to is the parsed "To" field
+
+ - list is the list of addresses
+*/
+
+struct mailimap_env_to {
+ clist * to_list; /* list of (struct mailimap_address *), != NULL */
+};
+
+struct mailimap_env_to * mailimap_env_to_new(clist * to_list);
+
+void mailimap_env_to_free(struct mailimap_env_to * env_to);
+
+
+/* this is the type of flag */
+
+enum {
+ MAILIMAP_FLAG_ANSWERED, /* \Answered flag */
+ MAILIMAP_FLAG_FLAGGED, /* \Flagged flag */
+ MAILIMAP_FLAG_DELETED, /* \Deleted flag */
+ MAILIMAP_FLAG_SEEN, /* \Seen flag */
+ MAILIMAP_FLAG_DRAFT, /* \Draft flag */
+ MAILIMAP_FLAG_KEYWORD, /* keyword flag */
+ MAILIMAP_FLAG_EXTENSION, /* \extension flag */
+};
+
+
+/*
+ mailimap_flag is a message flag (that we can associate with a message)
+
+ - type is the type of the flag, MAILIMAP_FLAG_XXX
+
+ - keyword is the flag when the flag is of keyword type,
+ should be allocated with malloc()
+
+ - extension is the flag when the flag is of extension type, should be
+ allocated with malloc()
+*/
+
+struct mailimap_flag {
+ int fl_type;
+ union {
+ char * fl_keyword; /* can be NULL */
+ char * fl_extension; /* can be NULL */
+ } fl_data;
+};
+
+struct mailimap_flag * mailimap_flag_new(int fl_type,
+ char * fl_keyword, char * fl_extension);
+
+void mailimap_flag_free(struct mailimap_flag * f);
+
+
+
+
+/* this is the type of flag */
+
+enum {
+ MAILIMAP_FLAG_FETCH_ERROR, /* on parse error */
+ MAILIMAP_FLAG_FETCH_RECENT, /* \Recent flag */
+ MAILIMAP_FLAG_FETCH_OTHER, /* other type of flag */
+};
+
+/*
+ mailimap_flag_fetch is a message flag (when we fetch it)
+
+ - type is the type of flag fetch
+
+ - flag is the flag when this is not a \Recent flag
+*/
+
+struct mailimap_flag_fetch {
+ int fl_type;
+ struct mailimap_flag * fl_flag; /* can be NULL */
+};
+
+struct mailimap_flag_fetch *
+mailimap_flag_fetch_new(int fl_type, struct mailimap_flag * fl_flag);
+
+void mailimap_flag_fetch_free(struct mailimap_flag_fetch * flag_fetch);
+
+
+
+
+/* this is the type of flag */
+
+enum {
+ MAILIMAP_FLAG_PERM_ERROR, /* on parse error */
+ MAILIMAP_FLAG_PERM_FLAG, /* to specify that usual flags can be changed */
+ MAILIMAP_FLAG_PERM_ALL /* to specify that new flags can be created */
+};
+
+
+/*
+ mailimap_flag_perm is a flag returned in case of PERMANENTFLAGS response
+
+ - type is the type of returned PERMANENTFLAGS, it can be
+ MAILIMAP_FLAG_PERM_FLAG (the given flag can be changed permanently) or
+ MAILIMAP_FLAG_PERM_ALL (new flags can be created)
+
+ - flag is the given flag when type is MAILIMAP_FLAG_PERM_FLAG
+*/
+
+struct mailimap_flag_perm {
+ int fl_type;
+ struct mailimap_flag * fl_flag; /* can be NULL */
+};
+
+struct mailimap_flag_perm *
+mailimap_flag_perm_new(int fl_type, struct mailimap_flag * fl_flag);
+
+void mailimap_flag_perm_free(struct mailimap_flag_perm * flag_perm);
+
+
+/*
+ mailimap_flag_list is a list of flags
+
+ - list is a list of flags
+*/
+
+struct mailimap_flag_list {
+ clist * fl_list; /* list of (struct mailimap_flag *), != NULL */
+};
+
+struct mailimap_flag_list *
+mailimap_flag_list_new(clist * fl_list);
+
+void mailimap_flag_list_free(struct mailimap_flag_list * flag_list);
+
+
+
+
+/* this is the type of greeting response */
+
+enum {
+ MAILIMAP_GREETING_RESP_COND_ERROR, /* on parse error */
+ MAILIMAP_GREETING_RESP_COND_AUTH, /* when connection is accepted */
+ MAILIMAP_GREETING_RESP_COND_BYE, /* when connection is refused */
+};
+
+/*
+ mailimap_greeting is the response returned on connection
+
+ - type is the type of response on connection, either
+ MAILIMAP_GREETING_RESP_COND_AUTH if connection is accepted or
+ MAIMIMAP_GREETING_RESP_COND_BYE if connection is refused
+*/
+
+struct mailimap_greeting {
+ int gr_type;
+ union {
+ struct mailimap_resp_cond_auth * gr_auth; /* can be NULL */
+ struct mailimap_resp_cond_bye * gr_bye; /* can be NULL */
+ } gr_data;
+};
+
+struct mailimap_greeting *
+mailimap_greeting_new(int gr_type,
+ struct mailimap_resp_cond_auth * gr_auth,
+ struct mailimap_resp_cond_bye * gr_bye);
+
+void mailimap_greeting_free(struct mailimap_greeting * greeting);
+
+
+/*
+ mailimap_header_list is a list of headers that can be specified when
+ we want to fetch fields
+
+ - list is a list of header names, each header name should be allocated
+ with malloc()
+*/
+
+struct mailimap_header_list {
+ clist * hdr_list; /* list of astring (char *), != NULL */
+};
+
+struct mailimap_header_list *
+mailimap_header_list_new(clist * hdr_list);
+
+void
+mailimap_header_list_free(struct mailimap_header_list * header_list);
+
+
+
+/* this is the type of mailbox STATUS that can be returned */
+
+enum {
+ MAILIMAP_STATUS_ATT_MESSAGES, /* when requesting the number of
+ messages */
+ MAILIMAP_STATUS_ATT_RECENT, /* when requesting the number of
+ recent messages */
+ MAILIMAP_STATUS_ATT_UIDNEXT, /* when requesting the next unique
+ identifier */
+ MAILIMAP_STATUS_ATT_UIDVALIDITY, /* when requesting the validity of
+ message unique identifiers*/
+ MAILIMAP_STATUS_ATT_UNSEEN, /* when requesting the number of
+ unseen messages */
+};
+
+/*
+ mailimap_status_info is a returned information when a STATUS of
+ a mailbox is requested
+
+ - att is the type of mailbox STATUS, the value can be
+ MAILIMAP_STATUS_ATT_MESSAGES, MAILIMAP_STATUS_ATT_RECENT,
+ MAILIMAP_STATUS_ATT_UIDNEXT, MAILIMAP_STATUS_ATT_UIDVALIDITY or
+ MAILIMAP_STATUS_ATT_UNSEEN
+
+ - value is the value of the given information
+*/
+
+struct mailimap_status_info {
+ int st_att;
+ uint32_t st_value;
+};
+
+struct mailimap_status_info *
+mailimap_status_info_new(int st_att, uint32_t st_value);
+
+void mailimap_status_info_free(struct mailimap_status_info * info);
+
+
+
+/*
+ mailimap_mailbox_data_status is the list of information returned
+ when a STATUS of a mailbox is requested
+
+ - mailbox is the name of the mailbox, should be allocated with malloc()
+
+ - status_info_list is the list of information returned
+*/
+
+struct mailimap_mailbox_data_status {
+ char * st_mailbox;
+ clist * st_info_list; /* list of (struct mailimap_status_info *) */
+ /* can be NULL */
+};
+
+struct mailimap_mailbox_data_status *
+mailimap_mailbox_data_status_new(char * st_mailbox,
+ clist * st_info_list);
+
+void
+mailimap_mailbox_data_status_free(struct mailimap_mailbox_data_status * info);
+
+
+
+/* this is the type of mailbox information that is returned */
+
+enum {
+ MAILIMAP_MAILBOX_DATA_ERROR, /* on parse error */
+ MAILIMAP_MAILBOX_DATA_FLAGS, /* flag that are applicable to the mailbox */
+ MAILIMAP_MAILBOX_DATA_LIST, /* this is a mailbox in the list of mailboxes
+ returned on LIST command*/
+ MAILIMAP_MAILBOX_DATA_LSUB, /* this is a mailbox in the list of
+ subscribed mailboxes returned on LSUB
+ command */
+ MAILIMAP_MAILBOX_DATA_SEARCH, /* this is a list of messages numbers or
+ unique identifiers returned
+ on a SEARCH command*/
+ MAILIMAP_MAILBOX_DATA_STATUS, /* this is the list of information returned
+ on a STATUS command */
+ MAILIMAP_MAILBOX_DATA_EXISTS, /* this is the number of messages in the
+ mailbox */
+ MAILIMAP_MAILBOX_DATA_RECENT, /* this is the number of recent messages
+ in the mailbox */
+};
+
+/*
+ mailimap_mailbox_data is an information related to a mailbox
+
+ - type is the type of mailbox_data that is filled, the value of this field
+ can be MAILIMAP_MAILBOX_DATA_FLAGS, MAILIMAP_MAILBOX_DATA_LIST,
+ MAILIMAP_MAILBOX_DATA_LSUB, MAILIMAP_MAILBOX_DATA_SEARCH,
+ MAILIMAP_MAILBOX_DATA_STATUS, MAILIMAP_MAILBOX_DATA_EXISTS
+ or MAILIMAP_MAILBOX_DATA_RECENT.
+
+ - flags is the flags that are applicable to the mailbox when
+ type is MAILIMAP_MAILBOX_DATA_FLAGS
+
+ - list is a mailbox in the list of mailboxes returned on LIST command
+ when type is MAILIMAP_MAILBOX_DATA_LIST
+
+ - lsub is a mailbox in the list of subscribed mailboxes returned on
+ LSUB command when type is MAILIMAP_MAILBOX_DATA_LSUB
+
+ - search is a list of messages numbers or unique identifiers returned
+ on SEARCH command when type MAILIMAP_MAILBOX_DATA_SEARCH, each element
+ should be allocated with malloc()
+
+ - status is a list of information returned on STATUS command when
+ type is MAILIMAP_MAILBOX_DATA_STATUS
+
+ - exists is the number of messages in the mailbox when type
+ is MAILIMAP_MAILBOX_DATA_EXISTS
+
+ - recent is the number of recent messages in the mailbox when type
+ is MAILIMAP_MAILBOX_DATA_RECENT
+*/
+
+struct mailimap_mailbox_data {
+ int mbd_type;
+ union {
+ struct mailimap_flag_list * mbd_flags; /* can be NULL */
+ struct mailimap_mailbox_list * mbd_list; /* can be NULL */
+ struct mailimap_mailbox_list * mbd_lsub; /* can be NULL */
+ clist * mbd_search; /* list of nz-number (uint32_t *), can be NULL */
+ struct mailimap_mailbox_data_status * mbd_status; /* can be NULL */
+ uint32_t mbd_exists;
+ uint32_t mbd_recent;
+ } mbd_data;
+};
+
+struct mailimap_mailbox_data *
+mailimap_mailbox_data_new(int mbd_type, struct mailimap_flag_list * mbd_flags,
+ struct mailimap_mailbox_list * mbd_list,
+ struct mailimap_mailbox_list * mbd_lsub,
+ clist * mbd_search,
+ struct mailimap_mailbox_data_status * mbd_status,
+ uint32_t mbd_exists,
+ uint32_t mbd_recent);
+
+void
+mailimap_mailbox_data_free(struct mailimap_mailbox_data * mb_data);
+
+
+
+/* this is the type of mailbox flags */
+
+enum {
+ MAILIMAP_MBX_LIST_FLAGS_SFLAG, /* mailbox single flag - a flag in
+ {\NoSelect, \Marked, \Unmarked} */
+ MAILIMAP_MBX_LIST_FLAGS_NO_SFLAG, /* mailbox other flag - mailbox flag
+ other than \NoSelect \Marked and
+ \Unmarked) */
+};
+
+/* this is a single flag type */
+
+enum {
+ MAILIMAP_MBX_LIST_SFLAG_ERROR,
+ MAILIMAP_MBX_LIST_SFLAG_MARKED,
+ MAILIMAP_MBX_LIST_SFLAG_NOSELECT,
+ MAILIMAP_MBX_LIST_SFLAG_UNMARKED
+};
+
+/*
+ mailimap_mbx_list_flags is a mailbox flag
+
+ - type is the type of mailbox flag, it can be MAILIMAP_MBX_LIST_FLAGS_SFLAG,
+ or MAILIMAP_MBX_LIST_FLAGS_NO_SFLAG.
+
+ - oflags is a list of "mailbox other flag"
+
+ - sflag is a mailbox single flag
+*/
+
+struct mailimap_mbx_list_flags {
+ int mbf_type;
+ clist * mbf_oflags; /* list of
+ (struct mailimap_mbx_list_oflag *), != NULL */
+ int mbf_sflag;
+};
+
+struct mailimap_mbx_list_flags *
+mailimap_mbx_list_flags_new(int mbf_type,
+ clist * mbf_oflags, int mbf_sflag);
+
+void
+mailimap_mbx_list_flags_free(struct mailimap_mbx_list_flags * mbx_list_flags);
+
+
+
+/* this is the type of the mailbox other flag */
+
+enum {
+ MAILIMAP_MBX_LIST_OFLAG_ERROR, /* on parse error */
+ MAILIMAP_MBX_LIST_OFLAG_NOINFERIORS, /* \NoInferior flag */
+ MAILIMAP_MBX_LIST_OFLAG_FLAG_EXT /* other flag */
+};
+
+/*
+ mailimap_mbx_list_oflag is a mailbox other flag
+
+ - type can be MAILIMAP_MBX_LIST_OFLAG_NOINFERIORS when this is
+ a \NoInferior flag or MAILIMAP_MBX_LIST_OFLAG_FLAG_EXT
+
+ - flag_ext is set when MAILIMAP_MBX_LIST_OFLAG_FLAG_EXT and is
+ an extension flag, should be allocated with malloc()
+*/
+
+struct mailimap_mbx_list_oflag {
+ int of_type;
+ char * of_flag_ext; /* can be NULL */
+};
+
+struct mailimap_mbx_list_oflag *
+mailimap_mbx_list_oflag_new(int of_type, char * of_flag_ext);
+
+void
+mailimap_mbx_list_oflag_free(struct mailimap_mbx_list_oflag * oflag);
+
+
+
+/*
+ mailimap_mailbox_list is a list of mailbox flags
+
+ - mb_flag is a list of mailbox flags
+
+ - delimiter is the delimiter of the mailbox path
+
+ - mb is the name of the mailbox, should be allocated with malloc()
+*/
+
+struct mailimap_mailbox_list {
+ struct mailimap_mbx_list_flags * mb_flag; /* can be NULL */
+ char mb_delimiter;
+ char * mb_name; /* != NULL */
+};
+
+struct mailimap_mailbox_list *
+mailimap_mailbox_list_new(struct mailimap_mbx_list_flags * mbx_flags,
+ char mb_delimiter, char * mb_name);
+
+void
+mailimap_mailbox_list_free(struct mailimap_mailbox_list * mb_list);
+
+
+
+/* this is the MIME type */
+
+enum {
+ MAILIMAP_MEDIA_BASIC_APPLICATION, /* application/xxx */
+ MAILIMAP_MEDIA_BASIC_AUDIO, /* audio/xxx */
+ MAILIMAP_MEDIA_BASIC_IMAGE, /* image/xxx */
+ MAILIMAP_MEDIA_BASIC_MESSAGE, /* message/xxx */
+ MAILIMAP_MEDIA_BASIC_VIDEO, /* video/xxx */
+ MAILIMAP_MEDIA_BASIC_OTHER, /* for all other cases */
+};
+
+
+/*
+ mailimap_media_basic is the MIME type
+
+ - type can be MAILIMAP_MEDIA_BASIC_APPLICATION, MAILIMAP_MEDIA_BASIC_AUDIO,
+ MAILIMAP_MEDIA_BASIC_IMAGE, MAILIMAP_MEDIA_BASIC_MESSAGE,
+ MAILIMAP_MEDIA_BASIC_VIDEO or MAILIMAP_MEDIA_BASIC_OTHER
+
+ - basic_type is defined when type is MAILIMAP_MEDIA_BASIC_OTHER, should
+ be allocated with malloc()
+
+ - subtype is the subtype of the MIME type, for example, this is
+ "data" in "application/data", should be allocated with malloc()
+*/
+
+struct mailimap_media_basic {
+ int med_type;
+ char * med_basic_type; /* can be NULL */
+ char * med_subtype; /* != NULL */
+};
+
+struct mailimap_media_basic *
+mailimap_media_basic_new(int med_type,
+ char * med_basic_type, char * med_subtype);
+
+void
+mailimap_media_basic_free(struct mailimap_media_basic * media_basic);
+
+
+
+/* this is the type of message data */
+
+enum {
+ MAILIMAP_MESSAGE_DATA_ERROR,
+ MAILIMAP_MESSAGE_DATA_EXPUNGE,
+ MAILIMAP_MESSAGE_DATA_FETCH
+};
+
+/*
+ mailimap_message_data is an information related to a message
+
+ - number is the number or the unique identifier of the message
+
+ - type is the type of information, this value can be
+ MAILIMAP_MESSAGE_DATA_EXPUNGE or MAILIMAP_MESSAGE_DATA_FETCH
+
+ - msg_att is the message data
+*/
+
+struct mailimap_message_data {
+ uint32_t mdt_number;
+ int mdt_type;
+ struct mailimap_msg_att * mdt_msg_att; /* can be NULL */
+ /* if type = EXPUNGE, can be NULL */
+};
+
+struct mailimap_message_data *
+mailimap_message_data_new(uint32_t mdt_number, int mdt_type,
+ struct mailimap_msg_att * mdt_msg_att);
+
+void
+mailimap_message_data_free(struct mailimap_message_data * msg_data);
+
+
+
+/* this the type of the message attributes */
+
+enum {
+ MAILIMAP_MSG_ATT_ITEM_ERROR, /* on parse error */
+ MAILIMAP_MSG_ATT_ITEM_DYNAMIC, /* dynamic message attributes (flags) */
+ MAILIMAP_MSG_ATT_ITEM_STATIC, /* static messages attributes
+ (message content) */
+};
+
+/*
+ mailimap_msg_att_item is a message attribute
+
+ - type is the type of message attribute, the value can be
+ MAILIMAP_MSG_ATT_ITEM_DYNAMIC or MAILIMAP_MSG_ATT_ITEM_STATIC
+
+ - msg_att_dyn is a dynamic message attribute when type is
+ MAILIMAP_MSG_ATT_ITEM_DYNAMIC
+
+ - msg_att_static is a static message attribute when type is
+ MAILIMAP_MSG_ATT_ITEM_STATIC
+*/
+
+struct mailimap_msg_att_item {
+ int att_type;
+ union {
+ struct mailimap_msg_att_dynamic * att_dyn; /* can be NULL */
+ struct mailimap_msg_att_static * att_static; /* can be NULL */
+ } att_data;
+};
+
+struct mailimap_msg_att_item *
+mailimap_msg_att_item_new(int att_type,
+ struct mailimap_msg_att_dynamic * att_dyn,
+ struct mailimap_msg_att_static * att_static);
+
+void
+mailimap_msg_att_item_free(struct mailimap_msg_att_item * item);
+
+
+/*
+ mailimap_msg_att is a list of attributes
+
+ - list is a list of message attributes
+
+ - number is the message number or unique identifier, this field
+ has been added for implementation purpose
+*/
+
+struct mailimap_msg_att {
+ clist * att_list; /* list of (struct mailimap_msg_att_item *) */
+ /* != NULL */
+ uint32_t att_number; /* extra field to store the message number,
+ used for mailimap */
+};
+
+struct mailimap_msg_att * mailimap_msg_att_new(clist * att_list);
+
+void mailimap_msg_att_free(struct mailimap_msg_att * msg_att);
+
+
+/*
+ mailimap_msg_att_dynamic is a dynamic message attribute
+
+ - list is a list of flags (that have been fetched)
+*/
+
+struct mailimap_msg_att_dynamic {
+ clist * att_list; /* list of (struct mailimap_flag_fetch *) */
+ /* can be NULL */
+};
+
+struct mailimap_msg_att_dynamic *
+mailimap_msg_att_dynamic_new(clist * att_list);
+
+void
+mailimap_msg_att_dynamic_free(struct mailimap_msg_att_dynamic * msg_att_dyn);
+
+
+
+/*
+ mailimap_msg_att_body_section is a MIME part content
+
+ - section is the location of the MIME part in the message
+
+ - origin_octet is the offset of the requested part of the MIME part
+
+ - body_part is the content or partial content of the MIME part,
+ should be allocated through a MMAPString
+
+ - length is the size of the content
+*/
+
+struct mailimap_msg_att_body_section {
+ struct mailimap_section * sec_section; /* != NULL */
+ uint32_t sec_origin_octet;
+ char * sec_body_part; /* can be NULL */
+ size_t sec_length;
+};
+
+struct mailimap_msg_att_body_section *
+mailimap_msg_att_body_section_new(struct mailimap_section * section,
+ uint32_t sec_origin_octet,
+ char * sec_body_part,
+ size_t sec_length);
+
+void
+mailimap_msg_att_body_section_free(struct mailimap_msg_att_body_section *
+ msg_att_body_section);
+
+
+
+/*
+ this is the type of static message attribute
+*/
+
+enum {
+ MAILIMAP_MSG_ATT_ERROR, /* on parse error */
+ MAILIMAP_MSG_ATT_ENVELOPE, /* this is the fields that can be
+ parsed by the server */
+ MAILIMAP_MSG_ATT_INTERNALDATE, /* this is the message date kept
+ by the server */
+ MAILIMAP_MSG_ATT_RFC822, /* this is the message content
+ (header and body) */
+ MAILIMAP_MSG_ATT_RFC822_HEADER, /* this is the message header */
+ MAILIMAP_MSG_ATT_RFC822_TEXT, /* this is the message text part */
+ MAILIMAP_MSG_ATT_RFC822_SIZE, /* this is the size of the message content */
+ MAILIMAP_MSG_ATT_BODY, /* this is the MIME description of
+ the message */
+ MAILIMAP_MSG_ATT_BODYSTRUCTURE, /* this is the MIME description of the
+ message with additional information */
+ MAILIMAP_MSG_ATT_BODY_SECTION, /* this is a MIME part content */
+ MAILIMAP_MSG_ATT_UID, /* this is the message unique identifier */
+};
+
+/*
+ mailimap_msg_att_static is a given part of the message
+
+ - type is the type of the static message attribute, the value can be
+ MAILIMAP_MSG_ATT_ENVELOPE, MAILIMAP_MSG_ATT_INTERNALDATE,
+ MAILIMAP_MSG_ATT_RFC822, MAILIMAP_MSG_ATT_RFC822_HEADER,
+ MAILIMAP_MSG_ATT_RFC822_TEXT, MAILIMAP_MSG_ATT_RFC822_SIZE,
+ MAILIMAP_MSG_ATT_BODY, MAILIMAP_MSG_ATT_BODYSTRUCTURE,
+ MAILIMAP_MSG_ATT_BODY_SECTION, MAILIMAP_MSG_ATT_UID
+
+ - env is the headers parsed by the server if type is
+ MAILIMAP_MSG_ATT_ENVELOPE
+
+ - internal_date is the date of message kept by the server if type is
+ MAILIMAP_MSG_ATT_INTERNALDATE
+
+ - rfc822 is the message content if type is MAILIMAP_MSG_ATT_RFC822,
+ should be allocated through a MMAPString
+
+ - rfc822_header is the message header if type is
+ MAILIMAP_MSG_ATT_RFC822_HEADER, should be allocated through a MMAPString
+
+ - rfc822_text is the message text part if type is
+ MAILIMAP_MSG_ATT_RFC822_TEXT, should be allocated through a MMAPString
+
+ - rfc822_size is the message size if type is MAILIMAP_MSG_ATT_SIZE
+
+ - body is the MIME description of the message
+
+ - bodystructure is the MIME description of the message with additional
+ information
+
+ - body_section is a MIME part content
+
+ - uid is a unique message identifier
+*/
+
+struct mailimap_msg_att_static {
+ int att_type;
+ union {
+ struct mailimap_envelope * att_env; /* can be NULL */
+ struct mailimap_date_time * att_internal_date; /* can be NULL */
+ struct {
+ char * att_content; /* can be NULL */
+ size_t att_length;
+ } att_rfc822;
+ struct {
+ char * att_content; /* can be NULL */
+ size_t att_length;
+ } att_rfc822_header;
+ struct {
+ char * att_content; /* can be NULL */
+ size_t att_length;
+ } att_rfc822_text;
+ uint32_t att_rfc822_size;
+ struct mailimap_body * att_bodystructure; /* can be NULL */
+ struct mailimap_body * att_body; /* can be NULL */
+ struct mailimap_msg_att_body_section * att_body_section; /* can be NULL */
+ uint32_t att_uid;
+ } att_data;
+};
+
+struct mailimap_msg_att_static *
+mailimap_msg_att_static_new(int att_type, struct mailimap_envelope * att_env,
+ struct mailimap_date_time * att_internal_date,
+ char * att_rfc822,
+ char * att_rfc822_header,
+ char * att_rfc822_text,
+ size_t att_length,
+ uint32_t att_rfc822_size,
+ struct mailimap_body * att_bodystructure,
+ struct mailimap_body * att_body,
+ struct mailimap_msg_att_body_section * att_body_section,
+ uint32_t att_uid);
+
+void
+mailimap_msg_att_static_free(struct mailimap_msg_att_static * item);
+
+
+
+/* this is the type of a response element */
+
+enum {
+ MAILIMAP_RESP_ERROR, /* on parse error */
+ MAILIMAP_RESP_CONT_REQ, /* continuation request */
+ MAILIMAP_RESP_RESP_DATA, /* response data */
+};
+
+/*
+ mailimap_cont_req_or_resp_data is a response element
+
+ - type is the type of response, the value can be MAILIMAP_RESP_CONT_REQ
+ or MAILIMAP_RESP_RESP_DATA
+
+ - cont_req is a continuation request
+
+ - resp_data is a reponse data
+*/
+
+struct mailimap_cont_req_or_resp_data {
+ int rsp_type;
+ union {
+ struct mailimap_continue_req * rsp_cont_req; /* can be NULL */
+ struct mailimap_response_data * rsp_resp_data; /* can be NULL */
+ } rsp_data;
+};
+
+struct mailimap_cont_req_or_resp_data *
+mailimap_cont_req_or_resp_data_new(int rsp_type,
+ struct mailimap_continue_req * rsp_cont_req,
+ struct mailimap_response_data * rsp_resp_data);
+
+void
+mailimap_cont_req_or_resp_data_free(struct mailimap_cont_req_or_resp_data *
+ cont_req_or_resp_data);
+
+
+/*
+ mailimap_response is a list of response elements
+
+ - cont_req_or_resp_data_list is a list of response elements
+
+ - resp_done is an ending response element
+*/
+
+struct mailimap_response {
+ clist * rsp_cont_req_or_resp_data_list;
+ /* list of (struct mailiap_cont_req_or_resp_data *) */
+ /* can be NULL */
+ struct mailimap_response_done * rsp_resp_done; /* != NULL */
+};
+
+struct mailimap_response *
+mailimap_response_new(clist * rsp_cont_req_or_resp_data_list,
+ struct mailimap_response_done * rsp_resp_done);
+
+void
+mailimap_response_free(struct mailimap_response * resp);
+
+
+
+/* this is the type of an untagged response */
+
+enum {
+ MAILIMAP_RESP_DATA_TYPE_ERROR, /* on parse error */
+ MAILIMAP_RESP_DATA_TYPE_COND_STATE, /* condition state response */
+ MAILIMAP_RESP_DATA_TYPE_COND_BYE, /* BYE response (server is about
+ to close the connection) */
+ MAILIMAP_RESP_DATA_TYPE_MAILBOX_DATA, /* response related to a mailbox */
+ MAILIMAP_RESP_DATA_TYPE_MESSAGE_DATA, /* response related to a message */
+ MAILIMAP_RESP_DATA_TYPE_CAPABILITY_DATA, /* capability information */
+};
+
+/*
+ mailimap_reponse_data is an untagged response
+
+ - type is the type of the untagged response, it can be
+ MAILIMAP_RESP_DATA_COND_STATE, MAILIMAP_RESP_DATA_COND_BYE,
+ MAILIMAP_RESP_DATA_MAILBOX_DATA, MAILIMAP_RESP_DATA_MESSAGE_DATA
+ or MAILIMAP_RESP_DATA_CAPABILITY_DATA
+
+ - cond_state is a condition state response
+
+ - bye is a BYE response (server is about to close the connection)
+
+ - mailbox_data is a response related to a mailbox
+
+ - message_data is a response related to a message
+
+ - capability is information about capabilities
+*/
+
+struct mailimap_response_data {
+ int rsp_type;
+ union {
+ struct mailimap_resp_cond_state * rsp_cond_state; /* can be NULL */
+ struct mailimap_resp_cond_bye * rsp_bye; /* can be NULL */
+ struct mailimap_mailbox_data * rsp_mailbox_data; /* can be NULL */
+ struct mailimap_message_data * rsp_message_data; /* can be NULL */
+ struct mailimap_capability_data * rsp_capability_data; /* can be NULL */
+ } rsp_data;
+};
+
+struct mailimap_response_data *
+mailimap_response_data_new(int rsp_type,
+ struct mailimap_resp_cond_state * rsp_cond_state,
+ struct mailimap_resp_cond_bye * rsp_bye,
+ struct mailimap_mailbox_data * rsp_mailbox_data,
+ struct mailimap_message_data * rsp_message_data,
+ struct mailimap_capability_data * rsp_capability_data);
+
+void
+mailimap_response_data_free(struct mailimap_response_data * resp_data);
+
+
+
+/* this is the type of an ending response */
+
+enum {
+ MAILIMAP_RESP_DONE_TYPE_ERROR, /* on parse error */
+ MAILIMAP_RESP_DONE_TYPE_TAGGED, /* tagged response */
+ MAILIMAP_RESP_DONE_TYPE_FATAL, /* fatal error response */
+};
+
+/*
+ mailimap_response_done is an ending response
+
+ - type is the type of the ending response
+
+ - tagged is a tagged response
+
+ - fatal is a fatal error response
+*/
+
+struct mailimap_response_done {
+ int rsp_type;
+ union {
+ struct mailimap_response_tagged * rsp_tagged; /* can be NULL */
+ struct mailimap_response_fatal * rsp_fatal; /* can be NULL */
+ } rsp_data;
+};
+
+struct mailimap_response_done *
+mailimap_response_done_new(int rsp_type,
+ struct mailimap_response_tagged * rsp_tagged,
+ struct mailimap_response_fatal * rsp_fatal);
+
+void mailimap_response_done_free(struct mailimap_response_done *
+ resp_done);
+
+
+/*
+ mailimap_response_fatal is a fatal error response
+
+ - bye is a BYE response text
+*/
+
+struct mailimap_response_fatal {
+ struct mailimap_resp_cond_bye * rsp_bye; /* != NULL */
+};
+
+struct mailimap_response_fatal *
+mailimap_response_fatal_new(struct mailimap_resp_cond_bye * rsp_bye);
+
+void mailimap_response_fatal_free(struct mailimap_response_fatal * resp_fatal);
+
+
+
+/*
+ mailimap_response_tagged is a tagged response
+
+ - tag is the sent tag, should be allocated with malloc()
+
+ - cond_state is a condition state response
+*/
+
+struct mailimap_response_tagged {
+ char * rsp_tag; /* != NULL */
+ struct mailimap_resp_cond_state * rsp_cond_state; /* != NULL */
+};
+
+struct mailimap_response_tagged *
+mailimap_response_tagged_new(char * rsp_tag,
+ struct mailimap_resp_cond_state * rsp_cond_state);
+
+void
+mailimap_response_tagged_free(struct mailimap_response_tagged * tagged);
+
+
+/* this is the type of an authentication condition response */
+
+enum {
+ MAILIMAP_RESP_COND_AUTH_ERROR, /* on parse error */
+ MAILIMAP_RESP_COND_AUTH_OK, /* authentication is needed */
+ MAILIMAP_RESP_COND_AUTH_PREAUTH, /* authentication is not needed */
+};
+
+/*
+ mailimap_resp_cond_auth is an authentication condition response
+
+ - type is the type of the authentication condition response,
+ the value can be MAILIMAP_RESP_COND_AUTH_OK or
+ MAILIMAP_RESP_COND_AUTH_PREAUTH
+
+ - text is a text response
+*/
+
+struct mailimap_resp_cond_auth {
+ int rsp_type;
+ struct mailimap_resp_text * rsp_text; /* != NULL */
+};
+
+struct mailimap_resp_cond_auth *
+mailimap_resp_cond_auth_new(int rsp_type,
+ struct mailimap_resp_text * rsp_text);
+
+void
+mailimap_resp_cond_auth_free(struct mailimap_resp_cond_auth * cond_auth);
+
+
+
+/*
+ mailimap_resp_cond_bye is a BYE response
+
+ - text is a text response
+*/
+
+struct mailimap_resp_cond_bye {
+ struct mailimap_resp_text * rsp_text; /* != NULL */
+};
+
+struct mailimap_resp_cond_bye *
+mailimap_resp_cond_bye_new(struct mailimap_resp_text * rsp_text);
+
+void
+mailimap_resp_cond_bye_free(struct mailimap_resp_cond_bye * cond_bye);
+
+
+
+/* this is the type of a condition state response */
+
+enum {
+ MAILIMAP_RESP_COND_STATE_OK,
+ MAILIMAP_RESP_COND_STATE_NO,
+ MAILIMAP_RESP_COND_STATE_BAD
+};
+
+/*
+ mailimap_resp_cond_state is a condition state reponse
+
+ - type is the type of the condition state response
+
+ - text is a text response
+*/
+
+struct mailimap_resp_cond_state {
+ int rsp_type;
+ struct mailimap_resp_text * rsp_text; /* can be NULL */
+};
+
+struct mailimap_resp_cond_state *
+mailimap_resp_cond_state_new(int rsp_type,
+ struct mailimap_resp_text * rsp_text);
+
+void
+mailimap_resp_cond_state_free(struct mailimap_resp_cond_state * cond_state);
+
+
+
+/*
+ mailimap_resp_text is a text response
+
+ - resp_code is a response code
+
+ - text is a human readable text, should be allocated with malloc()
+*/
+
+struct mailimap_resp_text {
+ struct mailimap_resp_text_code * rsp_code; /* can be NULL */
+ char * rsp_text; /* can be NULL */
+};
+
+struct mailimap_resp_text *
+mailimap_resp_text_new(struct mailimap_resp_text_code * resp_code,
+ char * rsp_text);
+
+void mailimap_resp_text_free(struct mailimap_resp_text * resp_text);
+
+
+
+/* this is the type of the response code */
+
+enum {
+ MAILIMAP_RESP_TEXT_CODE_ALERT, /* ALERT response */
+ MAILIMAP_RESP_TEXT_CODE_BADCHARSET, /* BADCHARSET response */
+ MAILIMAP_RESP_TEXT_CODE_CAPABILITY_DATA, /* CAPABILITY response */
+ MAILIMAP_RESP_TEXT_CODE_PARSE, /* PARSE response */
+ MAILIMAP_RESP_TEXT_CODE_PERMANENTFLAGS, /* PERMANENTFLAGS response */
+ MAILIMAP_RESP_TEXT_CODE_READ_ONLY, /* READONLY response */
+ MAILIMAP_RESP_TEXT_CODE_READ_WRITE, /* READWRITE response */
+ MAILIMAP_RESP_TEXT_CODE_TRY_CREATE, /* TRYCREATE response */
+ MAILIMAP_RESP_TEXT_CODE_UIDNEXT, /* UIDNEXT response */
+ MAILIMAP_RESP_TEXT_CODE_UIDVALIDITY, /* UIDVALIDITY response */
+ MAILIMAP_RESP_TEXT_CODE_UNSEEN, /* UNSEEN response */
+ MAILIMAP_RESP_TEXT_CODE_OTHER, /* other type of response */
+};
+
+/*
+ mailimap_resp_text_code is a response code
+
+ - type is the type of the response code, the value can be
+ MAILIMAP_RESP_TEXT_CODE_ALERT, MAILIMAP_RESP_TEXT_CODE_BADCHARSET,
+ MAILIMAP_RESP_TEXT_CODE_CAPABILITY_DATA, MAILIMAP_RESP_TEXT_CODE_PARSE,
+ MAILIMAP_RESP_TEXT_CODE_PERMANENTFLAGS, MAILIMAP_RESP_TEXT_CODE_READ_ONLY,
+ MAILIMAP_RESP_TEXT_CODE_READ_WRITE, MAILIMAP_RESP_TEXT_CODE_TRY_CREATE,
+ MAILIMAP_RESP_TEXT_CODE_UIDNEXT, MAILIMAP_RESP_TEXT_CODE_UIDVALIDITY,
+ MAILIMAP_RESP_TEXT_CODE_UNSEEN or MAILIMAP_RESP_TEXT_CODE_OTHER
+
+ - badcharset is a list of charsets if type
+ is MAILIMAP_RESP_TEXT_CODE_BADCHARSET, each element should be
+ allocated with malloc()
+
+ - cap_data is a list of capabilities
+
+ - perm_flags is a list of flags, this is the flags that can be changed
+ permanently on the messages of the mailbox.
+
+ - uidnext is the next unique identifier of a message
+
+ - uidvalidity is the unique identifier validity value
+
+ - first_unseen is the number of the first message without the \Seen flag
+
+ - atom is a keyword for an extension response code, should be allocated
+ with malloc()
+
+ - atom_value is the data related with the extension response code,
+ should be allocated with malloc()
+*/
+
+struct mailimap_resp_text_code {
+ int rc_type;
+ union {
+ clist * rc_badcharset; /* list of astring (char *) */
+ /* can be NULL */
+ struct mailimap_capability_data * rc_cap_data; /* != NULL */
+ clist * rc_perm_flags; /* list of (struct mailimap_flag_perm *) */
+ /* can be NULL */
+ uint32_t rc_uidnext;
+ uint32_t rc_uidvalidity;
+ uint32_t rc_first_unseen;
+ struct {
+ char * atom_name; /* can be NULL */
+ char * atom_value; /* can be NULL */
+ } rc_atom;
+ } rc_data;
+};
+
+struct mailimap_resp_text_code *
+mailimap_resp_text_code_new(int rc_type, clist * rc_badcharset,
+ struct mailimap_capability_data * rc_cap_data,
+ clist * rc_perm_flags,
+ uint32_t rc_uidnext, uint32_t rc_uidvalidity,
+ uint32_t rc_first_unseen, char * rc_atom, char * rc_atom_value);
+
+void
+mailimap_resp_text_code_free(struct mailimap_resp_text_code * resp_text_code);
+
+
+/*
+ mailimap_section is a MIME part section identifier
+
+ section_spec is the MIME section identifier
+*/
+
+struct mailimap_section {
+ struct mailimap_section_spec * sec_spec; /* can be NULL */
+};
+
+struct mailimap_section *
+mailimap_section_new(struct mailimap_section_spec * sec_spec);
+
+void mailimap_section_free(struct mailimap_section * section);
+
+
+/* this is the type of the message/rfc822 part description */
+
+enum {
+ MAILIMAP_SECTION_MSGTEXT_HEADER, /* header fields part of the
+ message */
+ MAILIMAP_SECTION_MSGTEXT_HEADER_FIELDS, /* given header fields of the
+ message */
+ MAILIMAP_SECTION_MSGTEXT_HEADER_FIELDS_NOT, /* header fields of the
+ message except the given */
+ MAILIMAP_SECTION_MSGTEXT_TEXT, /* text part */
+};
+
+/*
+ mailimap_section_msgtext is a message/rfc822 part description
+
+ - type is the type of the content part and the value can be
+ MAILIMAP_SECTION_MSGTEXT_HEADER, MAILIMAP_SECTION_MSGTEXT_HEADER_FIELDS,
+ MAILIMAP_SECTION_MSGTEXT_HEADER_FIELDS_NOT
+ or MAILIMAP_SECTION_MSGTEXT_TEXT
+
+ - header_list is the list of headers when type is
+ MAILIMAP_SECTION_MSGTEXT_HEADER_FIELDS or
+ MAILIMAP_SECTION_MSGTEXT_HEADER_FIELDS_NOT
+*/
+
+struct mailimap_section_msgtext {
+ int sec_type;
+ struct mailimap_header_list * sec_header_list; /* can be NULL */
+};
+
+struct mailimap_section_msgtext *
+mailimap_section_msgtext_new(int sec_type,
+ struct mailimap_header_list * sec_header_list);
+
+void
+mailimap_section_msgtext_free(struct mailimap_section_msgtext * msgtext);
+
+
+
+/*
+ mailimap_section_part is the MIME part location in a message
+
+ - section_id is a list of number index of the sub-part in the mail structure,
+ each element should be allocated with malloc()
+
+*/
+
+struct mailimap_section_part {
+ clist * sec_id; /* list of nz-number (uint32_t *) */
+ /* != NULL */
+};
+
+struct mailimap_section_part *
+mailimap_section_part_new(clist * sec_id);
+
+void
+mailimap_section_part_free(struct mailimap_section_part * section_part);
+
+
+
+/* this is the type of section specification */
+
+enum {
+ MAILIMAP_SECTION_SPEC_SECTION_MSGTEXT, /* if requesting data of the root
+ MIME message/rfc822 part */
+ MAILIMAP_SECTION_SPEC_SECTION_PART, /* location of the MIME part
+ in the message */
+};
+
+/*
+ mailimap_section_spec is a section specification
+
+ - type is the type of the section specification, the value can be
+ MAILIMAP_SECTION_SPEC_SECTION_MSGTEXT or
+ MAILIMAP_SECTION_SPEC_SECTION_PART
+
+ - section_msgtext is a message/rfc822 part description if type is
+ MAILIMAP_SECTION_SPEC_SECTION_MSGTEXT
+
+ - section_part is a body part location in the message if type is
+ MAILIMAP_SECTION_SPEC_SECTION_PART
+
+ - section_text is a body part location for a given MIME part,
+ this can be NULL if the body of the part is requested (and not
+ the MIME header).
+*/
+
+struct mailimap_section_spec {
+ int sec_type;
+ union {
+ struct mailimap_section_msgtext * sec_msgtext; /* can be NULL */
+ struct mailimap_section_part * sec_part; /* can be NULL */
+ } sec_data;
+ struct mailimap_section_text * sec_text; /* can be NULL */
+};
+
+struct mailimap_section_spec *
+mailimap_section_spec_new(int sec_type,
+ struct mailimap_section_msgtext * sec_msgtext,
+ struct mailimap_section_part * sec_part,
+ struct mailimap_section_text * sec_text);
+
+void
+mailimap_section_spec_free(struct mailimap_section_spec * section_spec);
+
+
+
+/* this is the type of body part location for a given MIME part */
+
+enum {
+ MAILIMAP_SECTION_TEXT_ERROR, /* on parse error **/
+ MAILIMAP_SECTION_TEXT_SECTION_MSGTEXT, /* if the MIME type is
+ message/rfc822, headers or text
+ can be requested */
+ MAILIMAP_SECTION_TEXT_MIME, /* for all MIME types,
+ MIME headers can be requested */
+};
+
+/*
+ mailimap_section_text is the body part location for a given MIME part
+
+ - type can be MAILIMAP_SECTION_TEXT_SECTION_MSGTEXT or
+ MAILIMAP_SECTION_TEXT_MIME
+
+ - section_msgtext is the part of the MIME part when MIME type is
+ message/rfc822 than can be requested, when type is
+ MAILIMAP_TEXT_SECTION_MSGTEXT
+*/
+
+struct mailimap_section_text {
+ int sec_type;
+ struct mailimap_section_msgtext * sec_msgtext; /* can be NULL */
+};
+
+struct mailimap_section_text *
+mailimap_section_text_new(int sec_type,
+ struct mailimap_section_msgtext * sec_msgtext);
+
+void
+mailimap_section_text_free(struct mailimap_section_text * section_text);
+
+
+
+
+
+
+
+
+
+
+/* ************************************************************************* */
+/* the following part concerns only the IMAP command that are sent */
+
+
+/*
+ mailimap_set_item is a message set
+
+ - first is the first message of the set
+ - last is the last message of the set
+
+ this can be message numbers of message unique identifiers
+*/
+
+struct mailimap_set_item {
+ uint32_t set_first;
+ uint32_t set_last;
+};
+
+struct mailimap_set_item *
+mailimap_set_item_new(uint32_t set_first, uint32_t set_last);
+
+void mailimap_set_item_free(struct mailimap_set_item * set_item);
+
+
+
+/*
+ set is a list of message sets
+
+ - list is a list of message sets
+*/
+
+struct mailimap_set {
+ clist * set_list; /* list of (struct mailimap_set_item *) */
+};
+
+struct mailimap_set * mailimap_set_new(clist * list);
+
+void mailimap_set_free(struct mailimap_set * set);
+
+
+/*
+ mailimap_date is a date
+
+ - day is the day in the month (1 to 31)
+
+ - month (1 to 12)
+
+ - year (4 digits)
+*/
+
+struct mailimap_date {
+ int dt_day;
+ int dt_month;
+ int dt_year;
+};
+
+struct mailimap_date *
+mailimap_date_new(int dt_day, int dt_month, int dt_year);
+
+void mailimap_date_free(struct mailimap_date * date);
+
+
+
+
+/* this is the type of fetch attribute for a given message */
+
+enum {
+ MAILIMAP_FETCH_ATT_ENVELOPE, /* to fetch the headers parsed by
+ the IMAP server */
+ MAILIMAP_FETCH_ATT_FLAGS, /* to fetch the flags */
+ MAILIMAP_FETCH_ATT_INTERNALDATE, /* to fetch the date of the message
+ kept by the server */
+ MAILIMAP_FETCH_ATT_RFC822, /* to fetch the entire message */
+ MAILIMAP_FETCH_ATT_RFC822_HEADER, /* to fetch the headers */
+ MAILIMAP_FETCH_ATT_RFC822_SIZE, /* to fetch the size */
+ MAILIMAP_FETCH_ATT_RFC822_TEXT, /* to fetch the text part */
+ MAILIMAP_FETCH_ATT_BODY, /* to fetch the MIME structure */
+ MAILIMAP_FETCH_ATT_BODYSTRUCTURE, /* to fetch the MIME structure with
+ additional information */
+ MAILIMAP_FETCH_ATT_UID, /* to fetch the unique identifier */
+ MAILIMAP_FETCH_ATT_BODY_SECTION, /* to fetch a given part */
+ MAILIMAP_FETCH_ATT_BODY_PEEK_SECTION, /* to fetch a given part without
+ marking the message as read */
+};
+
+
+/*
+ mailimap_fetch_att is the description of the fetch attribute
+
+ - type is the type of fetch attribute, the value can be
+ MAILIMAP_FETCH_ATT_ENVELOPE, MAILIMAP_FETCH_ATT_FLAGS,
+ MAILIMAP_FETCH_ATT_INTERNALDATE, MAILIMAP_FETCH_ATT_RFC822,
+ MAILIMAP_FETCH_ATT_RFC822_HEADER, MAILIMAP_FETCH_ATT_RFC822_SIZE,
+ MAILIMAP_FETCH_ATT_RFC822_TEXT, MAILIMAP_FETCH_ATT_BODY,
+ MAILIMAP_FETCH_ATT_BODYSTRUCTURE, MAILIMAP_FETCH_ATT_UID,
+ MAILIMAP_FETCH_ATT_BODY_SECTION or MAILIMAP_FETCH_ATT_BODY_PEEK_SECTION
+
+ - section is the location of the part to fetch if type is
+ MAILIMAP_FETCH_ATT_BODY_SECTION or MAILIMAP_FETCH_ATT_BODY_PEEK_SECTION
+
+ - offset is the first byte to fetch in the given part
+
+ - size is the maximum size of the part to fetch
+*/
+
+struct mailimap_fetch_att {
+ int att_type;
+ struct mailimap_section * att_section;
+ uint32_t att_offset;
+ uint32_t att_size;
+};
+
+struct mailimap_fetch_att *
+mailimap_fetch_att_new(int att_type, struct mailimap_section * att_section,
+ uint32_t att_offset, uint32_t att_size);
+
+
+void mailimap_fetch_att_free(struct mailimap_fetch_att * fetch_att);
+
+
+/* this is the type of a FETCH operation */
+
+enum {
+ MAILIMAP_FETCH_TYPE_ALL, /* equivalent to (FLAGS INTERNALDATE
+ RFC822.SIZE ENVELOPE) */
+ MAILIMAP_FETCH_TYPE_FULL, /* equivalent to (FLAGS INTERNALDATE
+ RFC822.SIZE ENVELOPE BODY) */
+ MAILIMAP_FETCH_TYPE_FAST, /* equivalent to (FLAGS INTERNALDATE
+ RFC822.SIZE) */
+ MAILIMAP_FETCH_TYPE_FETCH_ATT, /* when there is only of fetch
+ attribute */
+ MAILIMAP_FETCH_TYPE_FETCH_ATT_LIST, /* when there is a list of fetch
+ attributes */
+};
+
+/*
+ mailimap_fetch_type is the description of the FETCH operation
+
+ - type can be MAILIMAP_FETCH_TYPE_ALL, MAILIMAP_FETCH_TYPE_FULL,
+ MAILIMAP_FETCH_TYPE_FAST, MAILIMAP_FETCH_TYPE_FETCH_ATT or
+ MAILIMAP_FETCH_TYPE_FETCH_ATT_LIST
+
+ - fetch_att is a fetch attribute if type is MAILIMAP_FETCH_TYPE_FETCH_ATT
+
+ - fetch_att_list is a list of fetch attributes if type is
+ MAILIMAP_FETCH_TYPE_FETCH_ATT_LIST
+*/
+
+struct mailimap_fetch_type {
+ int ft_type;
+ union {
+ struct mailimap_fetch_att * ft_fetch_att;
+ clist * ft_fetch_att_list; /* list of (struct mailimap_fetch_att *) */
+ } ft_data;
+};
+
+struct mailimap_fetch_type *
+mailimap_fetch_type_new(int ft_type,
+ struct mailimap_fetch_att * ft_fetch_att,
+ clist * ft_fetch_att_list);
+
+
+void mailimap_fetch_type_free(struct mailimap_fetch_type * fetch_type);
+
+
+
+/*
+ mailimap_store_att_flags is the description of the STORE operation
+ (change flags of a message)
+
+ - sign can be 0 (set flag), +1 (add flag) or -1 (remove flag)
+
+ - silent has a value of 1 if the flags are changed with no server
+ response
+
+ - flag_list is the list of flags to change
+*/
+
+struct mailimap_store_att_flags {
+ int fl_sign;
+ int fl_silent;
+ struct mailimap_flag_list * fl_flag_list;
+};
+
+struct mailimap_store_att_flags *
+mailimap_store_att_flags_new(int fl_sign, int fl_silent,
+ struct mailimap_flag_list * fl_flag_list);
+
+void mailimap_store_att_flags_free(struct mailimap_store_att_flags *
+ store_att_flags);
+
+
+
+/* this is the condition of the SEARCH operation */
+
+enum {
+ MAILIMAP_SEARCH_KEY_ALL, /* all messages */
+ MAILIMAP_SEARCH_KEY_ANSWERED, /* messages with the flag \Answered */
+ MAILIMAP_SEARCH_KEY_BCC, /* messages whose Bcc field contains the
+ given string */
+ MAILIMAP_SEARCH_KEY_BEFORE, /* messages whose internal date is earlier
+ than the specified date */
+ MAILIMAP_SEARCH_KEY_BODY, /* message that contains the given string
+ (in header and text parts) */
+ MAILIMAP_SEARCH_KEY_CC, /* messages whose Cc field contains the
+ given string */
+ MAILIMAP_SEARCH_KEY_DELETED, /* messages with the flag \Deleted */
+ MAILIMAP_SEARCH_KEY_FLAGGED, /* messages with the flag \Flagged */
+ MAILIMAP_SEARCH_KEY_FROM, /* messages whose From field contains the
+ given string */
+ MAILIMAP_SEARCH_KEY_KEYWORD, /* messages with the flag keyword set */
+ MAILIMAP_SEARCH_KEY_NEW, /* messages with the flag \Recent and not
+ the \Seen flag */
+ MAILIMAP_SEARCH_KEY_OLD, /* messages that do not have the
+ \Recent flag set */
+ MAILIMAP_SEARCH_KEY_ON, /* messages whose internal date is the
+ specified date */
+ MAILIMAP_SEARCH_KEY_RECENT, /* messages with the flag \Recent */
+ MAILIMAP_SEARCH_KEY_SEEN, /* messages with the flag \Seen */
+ MAILIMAP_SEARCH_KEY_SINCE, /* messages whose internal date is later
+ than specified date */
+ MAILIMAP_SEARCH_KEY_SUBJECT, /* messages whose Subject field contains the
+ given string */
+ MAILIMAP_SEARCH_KEY_TEXT, /* messages whose text part contains the
+ given string */
+ MAILIMAP_SEARCH_KEY_TO, /* messages whose To field contains the
+ given string */
+ MAILIMAP_SEARCH_KEY_UNANSWERED, /* messages with no flag \Answered */
+ MAILIMAP_SEARCH_KEY_UNDELETED, /* messages with no flag \Deleted */
+ MAILIMAP_SEARCH_KEY_UNFLAGGED, /* messages with no flag \Flagged */
+ MAILIMAP_SEARCH_KEY_UNKEYWORD, /* messages with no flag keyword */
+ MAILIMAP_SEARCH_KEY_UNSEEN, /* messages with no flag \Seen */
+ MAILIMAP_SEARCH_KEY_DRAFT, /* messages with no flag \Draft */
+ MAILIMAP_SEARCH_KEY_HEADER, /* messages whose given field
+ contains the given string */
+ MAILIMAP_SEARCH_KEY_LARGER, /* messages whose size is larger then
+ the given size */
+ MAILIMAP_SEARCH_KEY_NOT, /* not operation of the condition */
+ MAILIMAP_SEARCH_KEY_OR, /* or operation between two conditions */
+ MAILIMAP_SEARCH_KEY_SENTBEFORE, /* messages whose date given in Date header
+ is earlier than the specified date */
+ MAILIMAP_SEARCH_KEY_SENTON, /* messages whose date given in Date header
+ is the specified date */
+ MAILIMAP_SEARCH_KEY_SENTSINCE, /* messages whose date given in Date header
+ is later than specified date */
+ MAILIMAP_SEARCH_KEY_SMALLER, /* messages whose size is smaller than
+ the given size */
+ MAILIMAP_SEARCH_KEY_UID, /* messages whose unique identifiers are
+ in the given range */
+ MAILIMAP_SEARCH_KEY_UNDRAFT, /* messages with no flag \Draft */
+ MAILIMAP_SEARCH_KEY_SET, /* messages whose number (or unique
+ identifiers in case of UID SEARCH) are
+ in the given range */
+ MAILIMAP_SEARCH_KEY_MULTIPLE, /* the boolean operator between the
+ conditions is AND */
+};
+
+/*
+ mailimap_search_key is the condition on the messages to return
+
+ - type is the type of the condition
+
+ - bcc is the text to search in the Bcc field when type is
+ MAILIMAP_SEARCH_KEY_BCC, should be allocated with malloc()
+
+ - before is a date when type is MAILIMAP_SEARCH_KEY_BEFORE
+
+ - body is the text to search in the message when type is
+ MAILIMAP_SEARCH_KEY_BODY, should be allocated with malloc()
+
+ - cc is the text to search in the Cc field when type is
+ MAILIMAP_SEARCH_KEY_CC, should be allocated with malloc()
+
+ - from is the text to search in the From field when type is
+ MAILIMAP_SEARCH_KEY_FROM, should be allocated with malloc()
+
+ - keyword is the keyword flag name when type is MAILIMAP_SEARCH_KEY_KEYWORD,
+ should be allocated with malloc()
+
+ - on is a date when type is MAILIMAP_SEARCH_KEY_ON
+
+ - since is a date when type is MAILIMAP_SEARCH_KEY_SINCE
+
+ - subject is the text to search in the Subject field when type is
+ MAILIMAP_SEARCH_KEY_SUBJECT, should be allocated with malloc()
+
+ - text is the text to search in the text part of the message when
+ type is MAILIMAP_SEARCH_KEY_TEXT, should be allocated with malloc()
+
+ - to is the text to search in the To field when type is
+ MAILIMAP_SEARCH_KEY_TO, should be allocated with malloc()
+
+ - unkeyword is the keyword flag name when type is
+ MAILIMAP_SEARCH_KEY_UNKEYWORD, should be allocated with malloc()
+
+ - header_name is the header name when type is MAILIMAP_SEARCH_KEY_HEADER,
+ should be allocated with malloc()
+
+ - header_value is the text to search in the given header when type is
+ MAILIMAP_SEARCH_KEY_HEADER, should be allocated with malloc()
+
+ - larger is a size when type is MAILIMAP_SEARCH_KEY_LARGER
+
+ - not is a condition when type is MAILIMAP_SEARCH_KEY_NOT
+
+ - or1 is a condition when type is MAILIMAP_SEARCH_KEY_OR
+
+ - or2 is a condition when type is MAILIMAP_SEARCH_KEY_OR
+
+ - sentbefore is a date when type is MAILIMAP_SEARCH_KEY_SENTBEFORE
+
+ - senton is a date when type is MAILIMAP_SEARCH_KEY_SENTON
+
+ - sentsince is a date when type is MAILIMAP_SEARCH_KEY_SENTSINCE
+
+ - smaller is a size when type is MAILIMAP_SEARCH_KEY_SMALLER
+
+ - uid is a set of messages when type is MAILIMAP_SEARCH_KEY_UID
+
+ - set is a set of messages when type is MAILIMAP_SEARCH_KEY_SET
+
+ - multiple is a set of message when type is MAILIMAP_SEARCH_KEY_MULTIPLE
+*/
+
+struct mailimap_search_key {
+ int sk_type;
+ union {
+ char * sk_bcc;
+ struct mailimap_date * sk_before;
+ char * sk_body;
+ char * sk_cc;
+ char * sk_from;
+ char * sk_keyword;
+ struct mailimap_date * sk_on;
+ struct mailimap_date * sk_since;
+ char * sk_subject;
+ char * sk_text;
+ char * sk_to;
+ char * sk_unkeyword;
+ struct {
+ char * sk_header_name;
+ char * sk_header_value;
+ } sk_header;
+ uint32_t sk_larger;
+ struct mailimap_search_key * sk_not;
+ struct {
+ struct mailimap_search_key * sk_or1;
+ struct mailimap_search_key * sk_or2;
+ } sk_or;
+ struct mailimap_date * sk_sentbefore;
+ struct mailimap_date * sk_senton;
+ struct mailimap_date * sk_sentsince;
+ uint32_t sk_smaller;
+ struct mailimap_set * sk_uid;
+ struct mailimap_set * sk_set;
+ clist * sk_multiple; /* list of (struct mailimap_search_key *) */
+ } sk_data;
+};
+
+struct mailimap_search_key *
+mailimap_search_key_new(int sk_type,
+ char * sk_bcc, struct mailimap_date * sk_before, char * sk_body,
+ char * sk_cc, char * sk_from, char * sk_keyword,
+ struct mailimap_date * sk_on, struct mailimap_date * sk_since,
+ char * sk_subject, char * sk_text, char * sk_to,
+ char * sk_unkeyword, char * sk_header_name,
+ char * sk_header_value, uint32_t sk_larger,
+ struct mailimap_search_key * sk_not,
+ struct mailimap_search_key * sk_or1,
+ struct mailimap_search_key * sk_or2,
+ struct mailimap_date * sk_sentbefore,
+ struct mailimap_date * sk_senton,
+ struct mailimap_date * sk_sentsince,
+ uint32_t sk_smaller, struct mailimap_set * sk_uid,
+ struct mailimap_set * sk_set, clist * sk_multiple);
+
+
+void mailimap_search_key_free(struct mailimap_search_key * key);
+
+
+/*
+ mailimap_status_att_list is a list of mailbox STATUS request type
+
+ - list is a list of mailbox STATUS request type
+ (value of elements in the list can be MAILIMAP_STATUS_ATT_MESSAGES,
+ MAILIMAP_STATUS_ATT_RECENT, MAILIMAP_STATUS_ATT_UIDNEXT,
+ MAILIMAP_STATUS_ATT_UIDVALIDITY or MAILIMAP_STATUS_ATT_UNSEEN),
+ each element should be allocated with malloc()
+*/
+
+struct mailimap_status_att_list {
+ clist * att_list; /* list of (uint32_t *) */
+};
+
+struct mailimap_status_att_list *
+mailimap_status_att_list_new(clist * att_list);
+
+void mailimap_status_att_list_free(struct mailimap_status_att_list *
+ status_att_list);
+
+
+
+
+/* internal use functions */
+
+
+uint32_t * mailimap_number_alloc_new(uint32_t number);
+
+void mailimap_number_alloc_free(uint32_t * pnumber);
+
+
+void mailimap_addr_host_free(char * addr_host);
+
+void mailimap_addr_mailbox_free(char * addr_mailbox);
+
+void mailimap_addr_adl_free(char * addr_adl);
+
+void mailimap_addr_name_free(char * addr_name);
+
+void mailimap_astring_free(char * astring);
+
+void mailimap_atom_free(char * atom);
+
+void mailimap_auth_type_free(char * auth_type);
+
+void mailimap_base64_free(char * base64);
+
+void mailimap_body_fld_desc_free(char * body_fld_desc);
+
+void mailimap_body_fld_id_free(char * body_fld_id);
+
+void mailimap_body_fld_md5_free(char * body_fld_md5);
+
+void mailimap_env_date_free(char * date);
+
+void mailimap_env_in_reply_to_free(char * in_reply_to);
+
+void mailimap_env_message_id_free(char * message_id);
+
+void mailimap_env_subject_free(char * subject);
+
+void mailimap_flag_extension_free(char * flag_extension);
+
+void mailimap_flag_keyword_free(char * flag_keyword);
+
+void
+mailimap_header_fld_name_free(char * header_fld_name);
+
+void mailimap_literal_free(char * literal);
+
+void mailimap_mailbox_free(char * mailbox);
+
+void
+mailimap_mailbox_data_search_free(clist * data_search);
+
+void mailimap_media_subtype_free(char * media_subtype);
+
+void mailimap_media_text_free(char * media_text);
+
+void mailimap_msg_att_envelope_free(struct mailimap_envelope * env);
+
+void
+mailimap_msg_att_internaldate_free(struct mailimap_date_time * date_time);
+
+void
+mailimap_msg_att_rfc822_free(char * str);
+
+void
+mailimap_msg_att_rfc822_header_free(char * str);
+
+void
+mailimap_msg_att_rfc822_text_free(char * str);
+
+void
+mailimap_msg_att_body_free(struct mailimap_body * body);
+
+void
+mailimap_msg_att_bodystructure_free(struct mailimap_body * body);
+
+void mailimap_nstring_free(char * str);
+
+void
+mailimap_string_free(char * str);
+
+void mailimap_tag_free(char * tag);
+
+void mailimap_text_free(char * text);
+
+
+
+
+
+/* IMAP connection */
+
+/* this is the state of the IMAP connection */
+
+enum {
+ MAILIMAP_STATE_DISCONNECTED,
+ MAILIMAP_STATE_NON_AUTHENTICATED,
+ MAILIMAP_STATE_AUTHENTICATED,
+ MAILIMAP_STATE_SELECTED,
+ MAILIMAP_STATE_LOGOUT
+};
+
+/*
+ mailimap is an IMAP connection
+
+ - response is a human readable message returned with a reponse,
+ must be accessed read-only
+
+ - stream is the connection with the IMAP server
+
+ - stream_buffer is the buffer where the data to parse are stored
+
+ - state is the state of IMAP connection
+
+ - tag is the current tag being used in IMAP connection
+
+ - response_buffer is the buffer for response messages
+
+ - connection_info is the information returned in response
+ for the last command about the connection
+
+ - selection_info is the information returned in response
+ for the last command about the current selected mailbox
+
+ - response_info is the other information returned in response
+ for the last command
+*/
+
+struct mailimap {
+ char * imap_response;
+
+ /* internals */
+ mailstream * imap_stream;
+
+ size_t imap_progr_rate;
+ progress_function * imap_progr_fun;
+
+ MMAPString * imap_stream_buffer;
+ MMAPString * imap_response_buffer;
+
+ int imap_state;
+ int imap_tag;
+
+ struct mailimap_connection_info * imap_connection_info;
+ struct mailimap_selection_info * imap_selection_info;
+ struct mailimap_response_info * imap_response_info;
+};
+
+typedef struct mailimap mailimap;
+
+
+/*
+ mailimap_connection_info is the information about the connection
+
+ - capability is the list of capability of the IMAP server
+*/
+
+struct mailimap_connection_info {
+ struct mailimap_capability_data * imap_capability;
+};
+
+struct mailimap_connection_info *
+mailimap_connection_info_new(void);
+
+void
+mailimap_connection_info_free(struct mailimap_connection_info * conn_info);
+
+
+/* this is the type of mailbox access */
+
+enum {
+ MAILIMAP_MAILBOX_READONLY,
+ MAILIMAP_MAILBOX_READWRITE
+};
+
+/*
+ mailimap_selection_info is information about the current selected mailbox
+
+ - perm_flags is a list of flags that can be changed permanently on the
+ messages of the mailbox
+
+ - perm is the access on the mailbox, value can be
+ MAILIMAP_MAILBOX_READONLY or MAILIMAP_MAILBOX_READWRITE
+
+ - uidnext is the next unique identifier
+
+ - uidvalidity is the unique identifiers validity
+
+ - first_unseen is the number of the first unseen message
+
+ - flags is a list of flags that can be used on the messages of
+ the mailbox
+
+ - exists is the number of messages in the mailbox
+
+ - recent is the number of recent messages in the mailbox
+
+ - unseen is the number of unseen messages in the mailbox
+*/
+
+struct mailimap_selection_info {
+ clist * sel_perm_flags; /* list of (struct flag_perm *) */
+ int sel_perm;
+ uint32_t sel_uidnext;
+ uint32_t sel_uidvalidity;
+ uint32_t sel_first_unseen;
+ struct mailimap_flag_list * sel_flags;
+ uint32_t sel_exists;
+ uint32_t sel_recent;
+ uint32_t sel_unseen;
+};
+
+struct mailimap_selection_info *
+mailimap_selection_info_new(void);
+
+void
+mailimap_selection_info_free(struct mailimap_selection_info * sel_info);
+
+
+/*
+ mailimap_response_info is the other information returned in the
+ response for a command
+
+ - alert is the human readable text returned with ALERT response
+
+ - parse is the human readable text returned with PARSE response
+
+ - badcharset is a list of charset returned with a BADCHARSET response
+
+ - trycreate is set to 1 if a trycreate response was returned
+
+ - mailbox_list is a list of mailboxes
+
+ - mailbox_lsub is a list of subscribed mailboxes
+
+ - search_result is a list of message numbers or unique identifiers
+
+ - status is a STATUS response
+
+ - expunged is a list of message numbers
+
+ - fetch_list is a list of fetch response
+*/
+
+struct mailimap_response_info {
+ char * rsp_alert;
+ char * rsp_parse;
+ clist * rsp_badcharset; /* list of (char *) */
+ int rsp_trycreate;
+ clist * rsp_mailbox_list; /* list of (struct mailimap_mailbox_list *) */
+ clist * rsp_mailbox_lsub; /* list of (struct mailimap_mailbox_list *) */
+ clist * rsp_search_result; /* list of (uint32_t *) */
+ struct mailimap_mailbox_data_status * rsp_status;
+ clist * rsp_expunged; /* list of (uint32_t 32 *) */
+ clist * rsp_fetch_list; /* list of (struct mailimap_msg_att *) */
+};
+
+struct mailimap_response_info *
+mailimap_response_info_new(void);
+
+void
+mailimap_response_info_free(struct mailimap_response_info * resp_info);
+
+
+/* these are the possible returned error codes */
+
+enum {
+ MAILIMAP_NO_ERROR = 0,
+ MAILIMAP_NO_ERROR_AUTHENTICATED = 1,
+ MAILIMAP_NO_ERROR_NON_AUTHENTICATED = 2,
+ MAILIMAP_ERROR_BAD_STATE,
+ MAILIMAP_ERROR_STREAM,
+ MAILIMAP_ERROR_PARSE,
+ MAILIMAP_ERROR_CONNECTION_REFUSED,
+ MAILIMAP_ERROR_MEMORY,
+ MAILIMAP_ERROR_FATAL,
+ MAILIMAP_ERROR_PROTOCOL,
+ MAILIMAP_ERROR_DONT_ACCEPT_CONNECTION,
+ MAILIMAP_ERROR_APPEND,
+ MAILIMAP_ERROR_NOOP,
+ MAILIMAP_ERROR_LOGOUT,
+ MAILIMAP_ERROR_CAPABILITY,
+ MAILIMAP_ERROR_CHECK,
+ MAILIMAP_ERROR_CLOSE,
+ MAILIMAP_ERROR_EXPUNGE,
+ MAILIMAP_ERROR_COPY,
+ MAILIMAP_ERROR_UID_COPY,
+ MAILIMAP_ERROR_CREATE,
+ MAILIMAP_ERROR_DELETE,
+ MAILIMAP_ERROR_EXAMINE,
+ MAILIMAP_ERROR_FETCH,
+ MAILIMAP_ERROR_UID_FETCH,
+ MAILIMAP_ERROR_LIST,
+ MAILIMAP_ERROR_LOGIN,
+ MAILIMAP_ERROR_LSUB,
+ MAILIMAP_ERROR_RENAME,
+ MAILIMAP_ERROR_SEARCH,
+ MAILIMAP_ERROR_UID_SEARCH,
+ MAILIMAP_ERROR_SELECT,
+ MAILIMAP_ERROR_STATUS,
+ MAILIMAP_ERROR_STORE,
+ MAILIMAP_ERROR_UID_STORE,
+ MAILIMAP_ERROR_SUBSCRIBE,
+ MAILIMAP_ERROR_UNSUBSCRIBE,
+ MAILIMAP_ERROR_STARTTLS,
+ MAILIMAP_ERROR_INVAL,
+};
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/libetpan/src/low-level/imap/mailimap_types_helper.c b/libetpan/src/low-level/imap/mailimap_types_helper.c
new file mode 100644
index 0000000..574897b
--- a/dev/null
+++ b/libetpan/src/low-level/imap/mailimap_types_helper.c
@@ -0,0 +1,1269 @@
+/*
+ * 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 "mailimap_types.h"
+#include "mail.h"
+
+#include <stdlib.h>
+
+/* ************************************************************************* */
+/* ************************************************************************* */
+/* ************************************************************************* */
+/* ************************************************************************* */
+/* ************************************************************************* */
+/* ************************************************************************* */
+
+/* in helper */
+
+
+
+
+struct mailimap_set_item * mailimap_set_item_new_single(uint32_t index)
+{
+ return mailimap_set_item_new(index, index);
+}
+
+struct mailimap_set *
+mailimap_set_new_single_item(struct mailimap_set_item * item)
+{
+ struct mailimap_set * set;
+ clist * list;
+ int r;
+
+ list = clist_new();
+ if (list == NULL)
+ return NULL;
+
+ r = clist_append(list, item);
+ if (r < 0) {
+ clist_free(list);
+ return NULL;
+ }
+
+ set = mailimap_set_new(list);
+ if (set == NULL) {
+ clist_free(list);
+ return NULL;
+ }
+
+ return set;
+}
+
+struct mailimap_set * mailimap_set_new_interval(uint32_t first, uint32_t last)
+{
+ struct mailimap_set_item * item;
+ struct mailimap_set * set;
+
+ item = mailimap_set_item_new(first, last);
+ if (item == NULL)
+ return NULL;
+
+ set = mailimap_set_new_single_item(item);
+ if (set == NULL) {
+ mailimap_set_item_free(item);
+ return NULL;
+ }
+
+ return set;
+}
+
+struct mailimap_set * mailimap_set_new_single(uint32_t index)
+{
+ return mailimap_set_new_interval(index, index);
+}
+
+
+struct mailimap_set * mailimap_set_new_empty(void)
+{
+ clist * list;
+
+ list = clist_new();
+ if (list == NULL)
+ return NULL;
+
+ return mailimap_set_new(list);
+}
+
+int mailimap_set_add(struct mailimap_set * set,
+ struct mailimap_set_item * set_item)
+{
+ int r;
+
+ r = clist_append(set->set_list, set_item);
+ if (r < 0)
+ return MAILIMAP_ERROR_MEMORY;
+
+ return MAILIMAP_NO_ERROR;
+}
+
+int mailimap_set_add_interval(struct mailimap_set * set,
+ uint32_t first, uint32_t last)
+{
+ struct mailimap_set_item * item;
+ int r;
+
+ item = mailimap_set_item_new(first, last);
+ if (item == NULL)
+ return MAILIMAP_ERROR_MEMORY;
+
+ r = mailimap_set_add(set, item);
+ if (r != MAILIMAP_NO_ERROR) {
+ mailimap_set_item_free(item);
+ return r;
+ }
+ else
+ return MAILIMAP_NO_ERROR;
+}
+
+int mailimap_set_add_single(struct mailimap_set * set,
+ uint32_t index)
+{
+ return mailimap_set_add_interval(set, index, index);
+}
+
+/* CHECK */
+/* no args */
+
+/* CLOSE */
+/* no args */
+
+/* EXPUNGE */
+/* no args */
+
+/* COPY */
+/* set and gchar */
+
+/* FETCH */
+/* set and gchar fetch_type */
+
+
+
+/* section */
+
+#if 0
+/* not correct XXX */
+
+struct mailimap_section * mailimap_section_new_empty(void)
+{
+ clist * list;
+
+ list = clist_new();
+ if (list == NULL)
+ return NULL;
+
+ return mailimap_section_new(list);
+}
+#endif
+
+static struct mailimap_section *
+mailimap_section_new_msgtext(struct mailimap_section_msgtext * msgtext)
+{
+ struct mailimap_section_spec * spec;
+ struct mailimap_section * section;
+
+ spec = mailimap_section_spec_new(MAILIMAP_SECTION_SPEC_SECTION_MSGTEXT,
+ msgtext, NULL, NULL);
+ if (spec == NULL)
+ return NULL;
+
+ section = mailimap_section_new(spec);
+ if (section == NULL) {
+ /* detach section_msgtext so that it will not be freed */
+ spec->sec_data.sec_msgtext = NULL;
+ mailimap_section_spec_free(spec);
+ return NULL;
+ }
+
+ return section;
+}
+
+static struct mailimap_section *
+mailimap_section_new_part_msgtext(struct mailimap_section_part * part,
+ struct mailimap_section_msgtext * msgtext)
+{
+ struct mailimap_section_spec * spec;
+ struct mailimap_section * section;
+ struct mailimap_section_text * text;
+
+ text = mailimap_section_text_new(MAILIMAP_SECTION_TEXT_SECTION_MSGTEXT,
+ msgtext);
+ if (text == NULL)
+ return NULL;
+
+ spec = mailimap_section_spec_new(MAILIMAP_SECTION_SPEC_SECTION_PART,
+ NULL, part, text);
+ if (spec == NULL) {
+ /* detach section_msgtext so that it will not be freed */
+ text->sec_msgtext = NULL;
+ mailimap_section_text_free(text);
+ return NULL;
+ }
+
+ section = mailimap_section_new(spec);
+ if (section == NULL) {
+ /* detach section_msgtext so that it will not be freed */
+ text->sec_msgtext = NULL;
+ mailimap_section_spec_free(spec);
+ return NULL;
+ }
+
+ return section;
+}
+
+/*
+HEADER
+HEADER.FIELDS fields
+HEADER.FIELDS.NOT fields
+TEXT
+*/
+
+struct mailimap_section * mailimap_section_new_header(void)
+{
+ struct mailimap_section_msgtext * msgtext;
+ struct mailimap_section * section;
+
+ msgtext = mailimap_section_msgtext_new(MAILIMAP_SECTION_MSGTEXT_HEADER,
+ NULL);
+ if (msgtext == NULL)
+ return NULL;
+
+ section = mailimap_section_new_msgtext(msgtext);
+ if (section == NULL) {
+ mailimap_section_msgtext_free(msgtext);
+ return NULL;
+ }
+
+ return section;
+}
+
+struct mailimap_section *
+mailimap_section_new_header_fields(struct mailimap_header_list * header_list)
+{
+ struct mailimap_section * section;
+ struct mailimap_section_msgtext * msgtext;
+
+ msgtext =
+ mailimap_section_msgtext_new(MAILIMAP_SECTION_MSGTEXT_HEADER_FIELDS,
+ header_list);
+ if (msgtext == NULL)
+ return NULL;
+
+ section = mailimap_section_new_msgtext(msgtext);
+ if (section == NULL) {
+ /* detach header_list so that it will not be freed */
+ msgtext->sec_header_list = NULL;
+ mailimap_section_msgtext_free(msgtext);
+ return NULL;
+ }
+
+ return section;
+}
+
+struct mailimap_section *
+mailimap_section_new_header_fields_not(struct mailimap_header_list * header_list)
+{
+ struct mailimap_section * section;
+ struct mailimap_section_msgtext * msgtext;
+
+ msgtext =
+ mailimap_section_msgtext_new(MAILIMAP_SECTION_MSGTEXT_HEADER_FIELDS_NOT,
+ header_list);
+ if (msgtext == NULL)
+ return NULL;
+
+ section = mailimap_section_new_msgtext(msgtext);
+ if (section == NULL) {
+ /* detach header_list so that it will not be freed */
+ msgtext->sec_header_list = NULL;
+ mailimap_section_msgtext_free(msgtext);
+ return NULL;
+ }
+
+ return section;
+}
+
+struct mailimap_section * mailimap_section_new_text(void)
+{
+ struct mailimap_section * section;
+ struct mailimap_section_msgtext * msgtext;
+
+ msgtext = mailimap_section_msgtext_new(MAILIMAP_SECTION_MSGTEXT_TEXT, NULL);
+ if (msgtext == NULL)
+ return NULL;
+
+ section = mailimap_section_new_msgtext(msgtext);
+ if (section == NULL) {
+ mailimap_section_msgtext_free(msgtext);
+ return NULL;
+ }
+
+ return section;
+}
+
+/*
+section-part
+section-part . MIME
+section-part . HEADER
+section-part . HEADER.FIELDS fields
+section-part . HEADER.FIELDS.NOT fields
+section-part . TEXT
+*/
+
+struct mailimap_section *
+mailimap_section_new_part(struct mailimap_section_part * part)
+{
+ struct mailimap_section_spec * spec;
+ struct mailimap_section * section;
+
+ spec = mailimap_section_spec_new(MAILIMAP_SECTION_SPEC_SECTION_PART,
+ NULL, part, NULL);
+ if (spec == NULL)
+ return NULL;
+
+ section = mailimap_section_new(spec);
+ if (section == NULL) {
+ /* detach section_part so that it will not be freed */
+ spec->sec_data.sec_part = NULL;
+ mailimap_section_spec_free(spec);
+ return NULL;
+ }
+
+ return section;
+}
+
+struct mailimap_section *
+mailimap_section_new_part_mime(struct mailimap_section_part * part)
+{
+ struct mailimap_section_spec * spec;
+ struct mailimap_section * section;
+ struct mailimap_section_text * text;
+
+ text = mailimap_section_text_new(MAILIMAP_SECTION_TEXT_MIME, NULL);
+ if (text == NULL)
+ return NULL;
+
+ spec = mailimap_section_spec_new(MAILIMAP_SECTION_SPEC_SECTION_PART,
+ NULL, part, text);
+ if (spec == NULL) {
+ mailimap_section_text_free(text);
+ return NULL;
+ }
+
+ section = mailimap_section_new(spec);
+ if (section == NULL) {
+ /* detach section_part so that it will not be freed */
+ spec->sec_data.sec_part = NULL;
+ mailimap_section_spec_free(spec);
+ return NULL;
+ }
+
+ return section;
+}
+
+struct mailimap_section *
+mailimap_section_new_part_header(struct mailimap_section_part * part)
+{
+ struct mailimap_section_msgtext * msgtext;
+ struct mailimap_section * section;
+
+ msgtext = mailimap_section_msgtext_new(MAILIMAP_SECTION_MSGTEXT_HEADER,
+ NULL);
+ if (msgtext == NULL)
+ return NULL;
+
+ section = mailimap_section_new_part_msgtext(part, msgtext);
+ if (section == NULL) {
+ mailimap_section_msgtext_free(msgtext);
+ return NULL;
+ }
+
+ return section;
+}
+
+struct mailimap_section *
+mailimap_section_new_part_header_fields(struct mailimap_section_part *
+ part,
+ struct mailimap_header_list *
+ header_list)
+{
+ struct mailimap_section * section;
+ struct mailimap_section_msgtext * msgtext;
+
+ msgtext =
+ mailimap_section_msgtext_new(MAILIMAP_SECTION_MSGTEXT_HEADER_FIELDS,
+ header_list);
+ if (msgtext == NULL)
+ return NULL;
+
+ section = mailimap_section_new_part_msgtext(part, msgtext);
+ if (section == NULL) {
+ /* detach header_list so that it will not be freed */
+ msgtext->sec_header_list = NULL;
+ mailimap_section_msgtext_free(msgtext);
+ return NULL;
+ }
+
+ return section;
+}
+
+struct mailimap_section *
+mailimap_section_new_part_header_fields_not(struct mailimap_section_part
+ * part,
+ struct mailimap_header_list
+ * header_list)
+{
+ struct mailimap_section * section;
+ struct mailimap_section_msgtext * msgtext;
+
+ msgtext =
+ mailimap_section_msgtext_new(MAILIMAP_SECTION_MSGTEXT_HEADER_FIELDS_NOT,
+ header_list);
+ if (msgtext == NULL)
+ return NULL;
+
+ section = mailimap_section_new_part_msgtext(part, msgtext);
+ if (section == NULL) {
+ /* detach header_list so that it will not be freed */
+ msgtext->sec_header_list = NULL;
+ mailimap_section_msgtext_free(msgtext);
+ return NULL;
+ }
+
+ return section;
+}
+
+struct mailimap_section *
+mailimap_section_new_part_text(struct mailimap_section_part * part)
+{
+ struct mailimap_section * section;
+ struct mailimap_section_msgtext * msgtext;
+
+ msgtext = mailimap_section_msgtext_new(MAILIMAP_SECTION_MSGTEXT_TEXT, NULL);
+ if (msgtext == NULL)
+ return NULL;
+
+ section = mailimap_section_new_part_msgtext(part, msgtext);
+ if (section == NULL) {
+ mailimap_section_msgtext_free(msgtext);
+ return NULL;
+ }
+
+ return section;
+}
+
+/* end of section */
+
+
+
+
+
+
+struct mailimap_fetch_att *
+mailimap_fetch_att_new_envelope(void)
+{
+ return mailimap_fetch_att_new(MAILIMAP_FETCH_ATT_ENVELOPE, NULL, 0, 0);
+}
+
+struct mailimap_fetch_att *
+mailimap_fetch_att_new_flags(void)
+{
+ return mailimap_fetch_att_new(MAILIMAP_FETCH_ATT_FLAGS, NULL, 0, 0);
+}
+
+struct mailimap_fetch_att *
+mailimap_fetch_att_new_internaldate(void)
+{
+ return mailimap_fetch_att_new(MAILIMAP_FETCH_ATT_INTERNALDATE, NULL, 0, 0);
+}
+
+struct mailimap_fetch_att *
+mailimap_fetch_att_new_rfc822(void)
+{
+ return mailimap_fetch_att_new(MAILIMAP_FETCH_ATT_RFC822, NULL, 0, 0);
+}
+
+struct mailimap_fetch_att *
+mailimap_fetch_att_new_rfc822_header(void)
+{
+ return mailimap_fetch_att_new(MAILIMAP_FETCH_ATT_RFC822_HEADER, NULL, 0, 0);
+}
+
+struct mailimap_fetch_att *
+mailimap_fetch_att_new_rfc822_size(void)
+{
+ return mailimap_fetch_att_new(MAILIMAP_FETCH_ATT_RFC822_SIZE, NULL, 0, 0);
+}
+
+struct mailimap_fetch_att *
+mailimap_fetch_att_new_rfc822_text(void)
+{
+ return mailimap_fetch_att_new(MAILIMAP_FETCH_ATT_RFC822_TEXT, NULL, 0, 0);
+}
+
+struct mailimap_fetch_att *
+mailimap_fetch_att_new_body(void)
+{
+ return mailimap_fetch_att_new(MAILIMAP_FETCH_ATT_BODY, NULL, 0, 0);
+}
+
+struct mailimap_fetch_att *
+mailimap_fetch_att_new_bodystructure(void)
+{
+ return mailimap_fetch_att_new(MAILIMAP_FETCH_ATT_BODYSTRUCTURE, NULL, 0, 0);
+}
+
+struct mailimap_fetch_att *
+mailimap_fetch_att_new_uid(void)
+{
+ return mailimap_fetch_att_new(MAILIMAP_FETCH_ATT_UID, NULL, 0, 0);
+}
+
+struct mailimap_fetch_att *
+mailimap_fetch_att_new_body_section(struct mailimap_section * section)
+{
+ return mailimap_fetch_att_new(MAILIMAP_FETCH_ATT_BODY_SECTION, section, 0, 0);
+}
+
+struct mailimap_fetch_att *
+mailimap_fetch_att_new_body_peek_section(struct mailimap_section * section)
+{
+ return mailimap_fetch_att_new(MAILIMAP_FETCH_ATT_BODY_PEEK_SECTION, section, 0, 0);
+}
+
+struct mailimap_fetch_att *
+mailimap_fetch_att_new_body_section_partial(struct mailimap_section * section,
+ uint32_t offset, uint32_t size)
+{
+ return mailimap_fetch_att_new(MAILIMAP_FETCH_ATT_BODY_SECTION, section,
+ offset, size);
+}
+
+struct mailimap_fetch_att *
+mailimap_fetch_att_new_body_peek_section_partial(struct mailimap_section * section,
+ uint32_t offset, uint32_t size)
+{
+ return mailimap_fetch_att_new(MAILIMAP_FETCH_ATT_BODY_PEEK_SECTION, section,
+ offset, size);
+}
+
+
+
+struct mailimap_fetch_type *
+mailimap_fetch_type_new_all(void)
+{
+ return mailimap_fetch_type_new(MAILIMAP_FETCH_TYPE_ALL, NULL, NULL);
+}
+
+struct mailimap_fetch_type *
+mailimap_fetch_type_new_full(void)
+{
+ return mailimap_fetch_type_new(MAILIMAP_FETCH_TYPE_FULL, NULL, NULL);
+}
+
+struct mailimap_fetch_type *
+mailimap_fetch_type_new_fast(void)
+{
+ return mailimap_fetch_type_new(MAILIMAP_FETCH_TYPE_FAST, NULL, NULL);
+}
+
+struct mailimap_fetch_type *
+mailimap_fetch_type_new_fetch_att(struct mailimap_fetch_att * fetch_att)
+{
+ return mailimap_fetch_type_new(MAILIMAP_FETCH_TYPE_FETCH_ATT, fetch_att, NULL);
+}
+
+struct mailimap_fetch_type *
+mailimap_fetch_type_new_fetch_att_list(clist * fetch_att_list)
+{
+ return mailimap_fetch_type_new(MAILIMAP_FETCH_TYPE_FETCH_ATT_LIST,
+ NULL, fetch_att_list);
+}
+
+struct mailimap_fetch_type *
+mailimap_fetch_type_new_fetch_att_list_empty(void)
+{
+ clist * list;
+
+ list = clist_new();
+ if (list == NULL)
+ return NULL;
+
+ return mailimap_fetch_type_new(MAILIMAP_FETCH_TYPE_FETCH_ATT_LIST,
+ NULL, list);
+}
+
+int
+mailimap_fetch_type_new_fetch_att_list_add(struct mailimap_fetch_type *
+ fetch_type,
+ struct mailimap_fetch_att * fetch_att)
+{
+ int r;
+
+ r = clist_append(fetch_type->ft_data.ft_fetch_att_list, fetch_att);
+ if (r < 0)
+ return MAILIMAP_ERROR_MEMORY;
+
+ return MAILIMAP_NO_ERROR;
+}
+
+
+
+/* STORE */
+/* set and store_att_flags */
+
+struct mailimap_store_att_flags *
+mailimap_store_att_flags_new_set_flags(struct mailimap_flag_list * flags)
+{
+ return mailimap_store_att_flags_new(0, FALSE, flags);
+}
+
+struct mailimap_store_att_flags *
+mailimap_store_att_flags_new_set_flags_silent(struct mailimap_flag_list *
+ flags)
+{
+ return mailimap_store_att_flags_new(0, TRUE, flags);
+}
+
+struct mailimap_store_att_flags *
+mailimap_store_att_flags_new_add_flags(struct mailimap_flag_list * flags)
+{
+ return mailimap_store_att_flags_new(1, FALSE, flags);
+}
+
+struct mailimap_store_att_flags *
+mailimap_store_att_flags_new_add_flags_silent(struct mailimap_flag_list *
+ flags)
+{
+ return mailimap_store_att_flags_new(1, TRUE, flags);
+}
+
+struct mailimap_store_att_flags *
+mailimap_store_att_flags_new_remove_flags(struct mailimap_flag_list * flags)
+{
+ return mailimap_store_att_flags_new(-1, FALSE, flags);
+}
+
+struct mailimap_store_att_flags *
+mailimap_store_att_flags_new_remove_flags_silent(struct mailimap_flag_list *
+ flags)
+{
+ return mailimap_store_att_flags_new(-1, TRUE, flags);
+}
+
+/* SEARCH */
+/* date search-key set */
+
+/*
+ return mailimap_search_key_new(type, bcc, before,
+ body, cc, from, keyword, on, since,
+ subject, text, to, unkeyword, header_name,
+ header_value, larger, not,
+ or1, or2, sentbefore, senton, sentsince,
+ smaller, uid, set, multiple);
+*/
+
+struct mailimap_search_key *
+mailimap_search_key_new_all(void)
+{
+ return mailimap_search_key_new(MAILIMAP_SEARCH_KEY_ALL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL,
+ NULL, 0, NULL,
+ NULL, NULL, NULL, NULL, NULL,
+ 0, NULL, NULL, NULL);
+}
+
+struct mailimap_search_key *
+mailimap_search_key_new_bcc(char * sk_bcc)
+{
+ return mailimap_search_key_new(MAILIMAP_SEARCH_KEY_BCC, sk_bcc, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL,
+ NULL, 0, NULL,
+ NULL, NULL, NULL, NULL, NULL,
+ 0, NULL, NULL, NULL);
+}
+
+struct mailimap_search_key *
+mailimap_search_key_new_before(struct mailimap_date * sk_before)
+{
+ return mailimap_search_key_new(MAILIMAP_SEARCH_KEY_BEFORE, NULL, sk_before,
+ NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL,
+ NULL, 0, NULL,
+ NULL, NULL, NULL, NULL, NULL,
+ 0, NULL, NULL, NULL);
+}
+
+struct mailimap_search_key *
+mailimap_search_key_new_body(char * sk_body)
+{
+ return mailimap_search_key_new(MAILIMAP_SEARCH_KEY_BODY, NULL, NULL,
+ sk_body, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL,
+ NULL, 0, NULL,
+ NULL, NULL, NULL, NULL, NULL,
+ 0, NULL, NULL, NULL);
+}
+
+struct mailimap_search_key *
+mailimap_search_key_new_cc(char * sk_cc)
+{
+ return mailimap_search_key_new(MAILIMAP_SEARCH_KEY_CC, NULL, NULL,
+ NULL, sk_cc, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL,
+ NULL, 0, NULL,
+ NULL, NULL, NULL, NULL, NULL,
+ 0, NULL, NULL, NULL);
+}
+
+struct mailimap_search_key *
+mailimap_search_key_new_from(char * sk_from)
+{
+ return mailimap_search_key_new(MAILIMAP_SEARCH_KEY_FROM, NULL, NULL,
+ NULL, NULL, sk_from, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL,
+ NULL, 0, NULL,
+ NULL, NULL, NULL, NULL, NULL,
+ 0, NULL, NULL, NULL);
+}
+
+struct mailimap_search_key *
+mailimap_search_key_new_keyword(char * sk_keyword)
+{
+ return mailimap_search_key_new(MAILIMAP_SEARCH_KEY_FROM, NULL, NULL,
+ NULL, NULL, NULL, sk_keyword, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL,
+ NULL, 0, NULL,
+ NULL, NULL, NULL, NULL, NULL,
+ 0, NULL, NULL, NULL);
+}
+
+struct mailimap_search_key *
+mailimap_search_key_new_on(struct mailimap_date * sk_on)
+{
+ return mailimap_search_key_new(MAILIMAP_SEARCH_KEY_ON, NULL, NULL,
+ NULL, NULL, NULL, NULL, sk_on, NULL,
+ NULL, NULL, NULL, NULL, NULL,
+ NULL, 0, NULL,
+ NULL, NULL, NULL, NULL, NULL,
+ 0, NULL, NULL, NULL);
+}
+
+struct mailimap_search_key *
+mailimap_search_key_new_since(struct mailimap_date * sk_since)
+{
+ return mailimap_search_key_new(MAILIMAP_SEARCH_KEY_SINCE, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, sk_since,
+ NULL, NULL, NULL, NULL, NULL,
+ NULL, 0, NULL,
+ NULL, NULL, NULL, NULL, NULL,
+ 0, NULL, NULL, NULL);
+}
+
+struct mailimap_search_key *
+mailimap_search_key_new_subject(char * sk_subject)
+{
+ return mailimap_search_key_new(MAILIMAP_SEARCH_KEY_SINCE, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL,
+ sk_subject, NULL, NULL, NULL, NULL,
+ NULL, 0, NULL,
+ NULL, NULL, NULL, NULL, NULL,
+ 0, NULL, NULL, NULL);
+}
+
+struct mailimap_search_key *
+mailimap_search_key_new_text(char * sk_text)
+{
+ return mailimap_search_key_new(MAILIMAP_SEARCH_KEY_TEXT, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, sk_text, NULL, NULL, NULL,
+ NULL, 0, NULL,
+ NULL, NULL, NULL, NULL, NULL,
+ 0, NULL, NULL, NULL);
+}
+
+struct mailimap_search_key *
+mailimap_search_key_new_to(char * sk_to)
+{
+ return mailimap_search_key_new(MAILIMAP_SEARCH_KEY_TO, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, sk_to, NULL, NULL,
+ NULL, 0, NULL,
+ NULL, NULL, NULL, NULL, NULL,
+ 0, NULL, NULL, NULL);
+}
+
+struct mailimap_search_key *
+mailimap_search_key_new_unkeyword(char * sk_unkeyword)
+{
+ return mailimap_search_key_new(MAILIMAP_SEARCH_KEY_UNKEYWORD, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, sk_unkeyword, NULL,
+ NULL, 0, NULL,
+ NULL, NULL, NULL, NULL, NULL,
+ 0, NULL, NULL, NULL);
+}
+
+struct mailimap_search_key *
+mailimap_search_key_new_header(char * sk_header_name, char * sk_header_value)
+{
+ return mailimap_search_key_new(MAILIMAP_SEARCH_KEY_HEADER, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, sk_header_name,
+ sk_header_value, 0, NULL,
+ NULL, NULL, NULL, NULL, NULL,
+ 0, NULL, NULL, NULL);
+}
+
+struct mailimap_search_key *
+mailimap_search_key_new_larger(uint32_t sk_larger)
+{
+ return mailimap_search_key_new(MAILIMAP_SEARCH_KEY_LARGER, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL,
+ NULL, sk_larger, NULL,
+ NULL, NULL, NULL, NULL, NULL,
+ 0, NULL, NULL, NULL);
+}
+
+struct mailimap_search_key *
+mailimap_search_key_new_not(struct mailimap_search_key * sk_not)
+{
+ return mailimap_search_key_new(MAILIMAP_SEARCH_KEY_NOT, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL,
+ NULL, 0, sk_not,
+ NULL, NULL, NULL, NULL, NULL,
+ 0, NULL, NULL, NULL);
+}
+
+struct mailimap_search_key *
+mailimap_search_key_new_or(struct mailimap_search_key * sk_or1,
+ struct mailimap_search_key * sk_or2)
+{
+ return mailimap_search_key_new(MAILIMAP_SEARCH_KEY_OR, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL,
+ NULL, 0, NULL,
+ sk_or1, sk_or2, NULL, NULL, NULL,
+ 0, NULL, NULL, NULL);
+}
+
+struct mailimap_search_key *
+mailimap_search_key_new_sentbefore(struct mailimap_date * sk_sentbefore)
+{
+ return mailimap_search_key_new(MAILIMAP_SEARCH_KEY_NOT, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL,
+ NULL, 0, NULL,
+ NULL, NULL, sk_sentbefore, NULL, NULL,
+ 0, NULL, NULL, NULL);
+}
+
+struct mailimap_search_key *
+mailimap_search_key_new_senton(struct mailimap_date * sk_senton)
+{
+ return mailimap_search_key_new(MAILIMAP_SEARCH_KEY_SENTON, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL,
+ NULL, 0, NULL,
+ NULL, NULL, NULL, sk_senton, NULL,
+ 0, NULL, NULL, NULL);
+}
+
+struct mailimap_search_key *
+mailimap_search_key_new_sentsince(struct mailimap_date * sk_sentsince)
+{
+ return mailimap_search_key_new(MAILIMAP_SEARCH_KEY_SENTSINCE, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL,
+ NULL, 0, NULL,
+ NULL, NULL, NULL, NULL, sk_sentsince,
+ 0, NULL, NULL, NULL);
+}
+
+struct mailimap_search_key *
+mailimap_search_key_new_smaller(uint32_t sk_smaller)
+{
+ return mailimap_search_key_new(MAILIMAP_SEARCH_KEY_SMALLER, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL,
+ NULL, 0, NULL,
+ NULL, NULL, NULL, NULL, NULL,
+ sk_smaller, NULL, NULL, NULL);
+}
+
+struct mailimap_search_key *
+mailimap_search_key_new_uid(struct mailimap_set * sk_uid)
+{
+ return mailimap_search_key_new(MAILIMAP_SEARCH_KEY_UID, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL,
+ NULL, 0, NULL,
+ NULL, NULL, NULL, NULL, NULL,
+ 0, sk_uid, NULL, NULL);
+}
+
+struct mailimap_search_key *
+mailimap_search_key_new_set(struct mailimap_set * sk_set)
+{
+ return mailimap_search_key_new(MAILIMAP_SEARCH_KEY_SET, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL,
+ NULL, 0, NULL,
+ NULL, NULL, NULL, NULL, NULL,
+ 0, NULL, sk_set, NULL);
+}
+
+struct mailimap_search_key *
+mailimap_search_key_new_multiple(clist * sk_multiple)
+{
+ return mailimap_search_key_new(MAILIMAP_SEARCH_KEY_MULTIPLE, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL,
+ NULL, 0, NULL,
+ NULL, NULL, NULL, NULL, NULL,
+ 0, NULL, NULL, sk_multiple);
+}
+
+struct mailimap_search_key *
+mailimap_search_key_new_multiple_empty(void)
+{
+ clist * list;
+
+ list = clist_new();
+ if (list == NULL)
+ return NULL;
+
+ return mailimap_search_key_new_multiple(list);
+}
+
+int
+mailimap_search_key_multiple_add(struct mailimap_search_key * keys,
+ struct mailimap_search_key * key_item)
+{
+ int r;
+
+ r = clist_append(keys->sk_data.sk_multiple, key_item);
+ if (r < 0)
+ return MAILIMAP_ERROR_MEMORY;
+
+ return MAILIMAP_NO_ERROR;
+}
+
+
+
+/* CAPABILITY */
+/* no args */
+
+/* LOGOUT */
+/* no args */
+
+/* NOOP */
+/* no args */
+
+/* APPEND */
+/* gchar flag_list date_time gchar */
+
+struct mailimap_flag_list *
+mailimap_flag_list_new_empty(void)
+{
+ clist * list;
+
+ list = clist_new();
+ if (list == NULL)
+ return NULL;
+
+ return mailimap_flag_list_new(list);
+}
+
+int mailimap_flag_list_add(struct mailimap_flag_list * flag_list,
+ struct mailimap_flag * f)
+{
+ int r;
+
+ r = clist_append(flag_list->fl_list, f);
+ if (r < 0)
+ return MAILIMAP_ERROR_MEMORY;
+
+ return MAILIMAP_NO_ERROR;
+}
+
+struct mailimap_flag * mailimap_flag_new_answered(void)
+{
+ return mailimap_flag_new(MAILIMAP_FLAG_ANSWERED, NULL, NULL);
+}
+
+struct mailimap_flag * mailimap_flag_new_flagged(void)
+{
+ return mailimap_flag_new(MAILIMAP_FLAG_FLAGGED, NULL, NULL);
+}
+
+struct mailimap_flag * mailimap_flag_new_deleted(void)
+{
+ return mailimap_flag_new(MAILIMAP_FLAG_DELETED, NULL, NULL);
+}
+
+struct mailimap_flag * mailimap_flag_new_seen(void)
+{
+ return mailimap_flag_new(MAILIMAP_FLAG_SEEN, NULL, NULL);
+}
+
+struct mailimap_flag * mailimap_flag_new_draft(void)
+{
+ return mailimap_flag_new(MAILIMAP_FLAG_DRAFT, NULL, NULL);
+}
+
+struct mailimap_flag * mailimap_flag_new_flag_keyword(char * flag_keyword)
+{
+ return mailimap_flag_new(MAILIMAP_FLAG_KEYWORD, flag_keyword, NULL);
+}
+
+struct mailimap_flag * mailimap_flag_new_flag_extension(char * flag_extension)
+{
+ return mailimap_flag_new(MAILIMAP_FLAG_EXTENSION, NULL, flag_extension);
+}
+
+
+
+
+/* CREATE */
+/* gchar */
+
+/* DELETE */
+/* gchar */
+
+/* EXAMINE */
+/* gchar */
+
+/* LIST */
+/* gchar gchar */
+
+/* LSUB */
+/* gchar gchar */
+
+/* RENAME */
+/* gchar gchar */
+
+/* SELECT */
+/* gchar */
+
+/* STATUS */
+/* gchar GList of status_att */
+
+struct mailimap_status_att_list * mailimap_status_att_list_new_empty(void)
+{
+ clist * list;
+
+ list = clist_new();
+ if (list == NULL)
+ return NULL;
+
+ return mailimap_status_att_list_new(list);
+}
+
+int
+mailimap_status_att_list_add(struct mailimap_status_att_list * sa_list,
+ int status_att)
+{
+ int * pstatus_att;
+ int r;
+
+ pstatus_att = malloc(sizeof(* pstatus_att));
+ * pstatus_att = status_att;
+
+ r = clist_append(sa_list->att_list, pstatus_att);
+ if (r < 0) {
+ free(pstatus_att);
+ return MAILIMAP_ERROR_MEMORY;
+ }
+
+ return MAILIMAP_NO_ERROR;
+}
+
+/* SUBSCRIBE */
+/* gchar */
+
+/* UNSUBSCRIBE */
+/* gchar */
+
+/* LOGIN */
+/* gchar gchar */
+
+/* AUTHENTICATE */
+/* gchar */
+
+
+static int recursive_build_path(struct mailimap_body * root_part,
+ struct mailimap_body * part,
+ clist ** result);
+
+static int try_build_part(struct mailimap_body * root_part,
+ struct mailimap_body * part, uint32_t count,
+ clist ** result)
+{
+ int r;
+ clist * imap_id_list;
+ uint32_t * id;
+
+ r = recursive_build_path(root_part, part, &imap_id_list);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ id = malloc(sizeof(* id));
+ if (id == NULL) {
+ clist_free(imap_id_list);
+ return MAILIMAP_ERROR_MEMORY;
+ }
+
+ * id = count;
+
+ r = clist_prepend(imap_id_list, id);
+ if (r < 0) {
+ free(id);
+ clist_free(imap_id_list);
+ return MAILIMAP_ERROR_MEMORY;
+ }
+
+ * result = imap_id_list;
+
+ return MAILIMAP_NO_ERROR;
+}
+
+
+static int recursive_build_path(struct mailimap_body * root_part,
+ struct mailimap_body * part,
+ clist ** result)
+{
+ clistiter * cur;
+ uint32_t count;
+ int r;
+ clist * imap_id_list;
+
+ if (part == root_part) {
+ imap_id_list = clist_new();
+ if (imap_id_list == NULL) {
+ return MAILIMAP_ERROR_MEMORY;
+ }
+
+ * result = imap_id_list;
+
+ return MAILIMAP_NO_ERROR;
+ }
+
+ switch (root_part->bd_type) {
+ case MAILIMAP_BODY_MPART:
+ count = 0;
+ for(cur = clist_begin(root_part->bd_data.bd_body_mpart->bd_list) ;
+ cur != NULL ; cur = clist_next(cur)) {
+ struct mailimap_body * current_part;
+
+ current_part = clist_content(cur);
+ count ++;
+
+ r = try_build_part(current_part, part, count, &imap_id_list);
+ if (r == MAILIMAP_ERROR_INVAL) {
+ continue;
+ } if (r != MAILIMAP_NO_ERROR) {
+ return r;
+ }
+ else {
+ * result = imap_id_list;
+ return MAILIMAP_NO_ERROR;
+ }
+ }
+ return MAILIMAP_ERROR_INVAL;
+
+ case MAILIMAP_BODY_1PART:
+ if (root_part->bd_data.bd_body_1part->bd_type ==
+ MAILIMAP_BODY_TYPE_1PART_MSG) {
+ struct mailimap_body * current_part;
+
+ current_part =
+ root_part->bd_data.bd_body_1part->bd_data.bd_type_msg->bd_body;
+
+ r = try_build_part(current_part, part, 1, &imap_id_list);
+ if (r != MAILIMAP_NO_ERROR) {
+ return r;
+ }
+ else {
+ * result = imap_id_list;
+ return MAILIMAP_NO_ERROR;
+ }
+ }
+ else {
+ return MAILIMAP_ERROR_INVAL;
+ }
+ break;
+
+ default:
+ return MAILIMAP_ERROR_INVAL;
+ }
+}
+
+/* return mailimap_section_part from a given mailimap_body */
+
+int mailimap_get_section_part_from_body(struct mailimap_body * root_part,
+ struct mailimap_body * part,
+ struct mailimap_section_part ** result)
+{
+ struct mailimap_section_part * section_part;
+ clist * id_list;
+ int r;
+ int res;
+
+ r = recursive_build_path(root_part, part, &id_list);
+ if (r != MAILIMAP_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ section_part = mailimap_section_part_new(id_list);
+ if (section_part == NULL) {
+ res = MAILIMAP_ERROR_MEMORY;
+ goto free_list;
+ }
+
+ * result = section_part;
+
+ return MAILIMAP_NO_ERROR;
+
+ free_list:
+ clist_foreach(id_list, (clist_func) free, NULL);
+ clist_free(id_list);
+ err:
+ return res;
+}
diff --git a/libetpan/src/low-level/imap/mailimap_types_helper.h b/libetpan/src/low-level/imap/mailimap_types_helper.h
new file mode 100644
index 0000000..10905d4
--- a/dev/null
+++ b/libetpan/src/low-level/imap/mailimap_types_helper.h
@@ -0,0 +1,758 @@
+/*
+ * 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$
+ */
+
+#ifndef MAILIMAP_TYPES_HELPER_H
+
+#define MAILIMAP_TYPES_HELPER_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <libetpan/mailimap_types.h>
+
+/*
+ IMPORTANT NOTE:
+
+ All allocation functions will take as argument allocated data
+ and will store these data in the structure they will allocate.
+ Data should be persistant during all the use of the structure
+ and will be freed by the free function of the structure
+
+ allocation functions will return NULL on failure
+*/
+
+/*
+ this function creates a new set item with a single message
+ given by index
+*/
+
+struct mailimap_set_item * mailimap_set_item_new_single(uint32_t index);
+
+/*
+ this function creates a new set with one set item
+ */
+
+struct mailimap_set *
+mailimap_set_new_single_item(struct mailimap_set_item * item);
+
+/*
+ this function creates a set with a single interval
+*/
+
+struct mailimap_set * mailimap_set_new_interval(uint32_t first, uint32_t last);
+
+/*
+ this function creates a set with a single message
+*/
+
+struct mailimap_set * mailimap_set_new_single(uint32_t index);
+
+/*
+ this function creates an empty set of messages
+*/
+
+struct mailimap_set * mailimap_set_new_empty(void);
+
+/*
+ this function adds a set item to the set of messages
+
+ @return MAILIMAP_NO_ERROR will be returned on success,
+ other code will be returned otherwise
+*/
+
+int mailimap_set_add(struct mailimap_set * set,
+ struct mailimap_set_item * set_item);
+
+/*
+ this function adds an interval to the set
+
+ @return MAILIMAP_NO_ERROR will be returned on success,
+ other code will be returned otherwise
+*/
+
+int mailimap_set_add_interval(struct mailimap_set * set,
+ uint32_t first, uint32_t last);
+
+/*
+ this function adds a single message to the set
+
+ @return MAILIMAP_NO_ERROR will be returned on success,
+ other code will be returned otherwise
+*/
+
+int mailimap_set_add_single(struct mailimap_set * set,
+ uint32_t index);
+
+/*
+ this function creates a mailimap_section structure to request
+ the header of a message
+*/
+
+struct mailimap_section * mailimap_section_new_header(void);
+
+/*
+ this functions creates a mailimap_section structure to describe
+ a list of headers
+*/
+
+struct mailimap_section *
+mailimap_section_new_header_fields(struct mailimap_header_list * header_list);
+
+/*
+ this functions creates a mailimap_section structure to describe headers
+ other than those given
+*/
+
+struct mailimap_section *
+mailimap_section_new_header_fields_not(struct mailimap_header_list * header_list);
+
+/*
+ this function creates a mailimap_section structure to describe the
+ text of a message
+ */
+
+struct mailimap_section * mailimap_section_new_text(void);
+
+/*
+ this function creates a mailimap_section structure to describe the
+ content of a MIME part
+*/
+
+struct mailimap_section *
+mailimap_section_new_part(struct mailimap_section_part * part);
+
+/*
+ this function creates a mailimap_section structure to describe the
+ MIME fields of a MIME part
+*/
+
+struct mailimap_section *
+mailimap_section_new_part_mime(struct mailimap_section_part * part);
+
+/*
+ this function creates a mailimap_section structure to describe the
+ headers of a MIME part if the MIME type is a message/rfc822
+*/
+
+struct mailimap_section *
+mailimap_section_new_part_header(struct mailimap_section_part * part);
+
+/*
+ this function creates a mailimap_section structure to describe
+ a list of headers of a MIME part if the MIME type is a message/rfc822
+*/
+
+struct mailimap_section *
+mailimap_section_new_part_header_fields(struct mailimap_section_part *
+ part,
+ struct mailimap_header_list *
+ header_list);
+
+/*
+ this function creates a mailimap_section structure to describe
+ headers of a MIME part other than those given if the MIME type
+ is a message/rfc822
+*/
+
+struct mailimap_section *
+mailimap_section_new_part_header_fields_not(struct mailimap_section_part
+ * part,
+ struct mailimap_header_list
+ * header_list);
+
+/*
+ this function creates a mailimap_section structure to describe
+ text part of message if the MIME type is a message/rfc822
+*/
+
+struct mailimap_section *
+mailimap_section_new_part_text(struct mailimap_section_part * part);
+
+
+/*
+ this function creates a mailimap_fetch_att structure to request
+ envelope of a message
+*/
+
+struct mailimap_fetch_att *
+mailimap_fetch_att_new_envelope(void);
+
+
+/*
+ this function creates a mailimap_fetch_att structure to request
+ flags of a message
+*/
+
+struct mailimap_fetch_att *
+mailimap_fetch_att_new_flags(void);
+
+/*
+ this function creates a mailimap_fetch_att structure to request
+ internal date of a message
+*/
+
+struct mailimap_fetch_att *
+mailimap_fetch_att_new_internaldate(void);
+
+
+/*
+ this function creates a mailimap_fetch_att structure to request
+ text part of a message
+*/
+
+struct mailimap_fetch_att *
+mailimap_fetch_att_new_rfc822(void);
+
+
+/*
+ this function creates a mailimap_fetch_att structure to request
+ header of a message
+*/
+
+struct mailimap_fetch_att *
+mailimap_fetch_att_new_rfc822_header(void);
+
+/*
+ this function creates a mailimap_fetch_att structure to request
+ size of a message
+*/
+
+struct mailimap_fetch_att *
+mailimap_fetch_att_new_rfc822_size(void);
+
+/*
+ this function creates a mailimap_fetch_att structure to request
+ envelope of a message
+*/
+
+struct mailimap_fetch_att *
+mailimap_fetch_att_new_rfc822_text(void);
+
+/*
+ this function creates a mailimap_fetch_att structure to request
+ the MIME structure of a message
+*/
+
+struct mailimap_fetch_att *
+mailimap_fetch_att_new_body(void);
+
+/*
+ this function creates a mailimap_fetch_att structure to request
+ the MIME structure of a message and additional MIME information
+*/
+
+struct mailimap_fetch_att *
+mailimap_fetch_att_new_bodystructure(void);
+
+/*
+ this function creates a mailimap_fetch_att structure to request
+ unique identifier of a message
+*/
+
+struct mailimap_fetch_att *
+mailimap_fetch_att_new_uid(void);
+
+/*
+ this function creates a mailimap_fetch_att structure to request
+ a given section of a message
+*/
+
+struct mailimap_fetch_att *
+mailimap_fetch_att_new_body_section(struct mailimap_section * section);
+
+/*
+ this function creates a mailimap_fetch_att structure to request
+ a given section of a message without marking it as read
+*/
+
+struct mailimap_fetch_att *
+mailimap_fetch_att_new_body_peek_section(struct mailimap_section * section);
+
+/*
+ this function creates a mailimap_fetch_att structure to request
+ a part of a section of a message
+*/
+
+struct mailimap_fetch_att *
+mailimap_fetch_att_new_body_section_partial(struct mailimap_section * section,
+ uint32_t offset, uint32_t size);
+
+/*
+ this function creates a mailimap_fetch_att structure to request
+ a part of a section of a message without marking it as read
+*/
+
+struct mailimap_fetch_att *
+mailimap_fetch_att_new_body_peek_section_partial(struct mailimap_section * section,
+ uint32_t offset, uint32_t size);
+
+/*
+ this function creates a mailimap_fetch_type structure to request
+ (FLAGS INTERNALDATE RFC822.SIZE ENVELOPE) of a message
+*/
+
+struct mailimap_fetch_type *
+mailimap_fetch_type_new_all(void);
+
+/*
+ this function creates a mailimap_fetch_type structure to request
+ (FLAGS INTERNALDATE RFC822.SIZE ENVELOPE BODY)
+*/
+
+struct mailimap_fetch_type *
+mailimap_fetch_type_new_full(void);
+
+/*
+ this function creates a mailimap_fetch_type structure to request
+ (FLAGS INTERNALDATE RFC822.SIZE)
+*/
+
+struct mailimap_fetch_type *
+mailimap_fetch_type_new_fast(void);
+
+/*
+ this function creates a mailimap_fetch_type structure to request
+ the given fetch attribute
+*/
+
+struct mailimap_fetch_type *
+mailimap_fetch_type_new_fetch_att(struct mailimap_fetch_att * fetch_att);
+
+/*
+ this function creates a mailimap_fetch_type structure to request
+ the list of fetch attributes
+*/
+
+struct mailimap_fetch_type *
+mailimap_fetch_type_new_fetch_att_list(clist * fetch_att_list);
+
+/*
+ this function creates a mailimap_fetch_type structure
+*/
+
+struct mailimap_fetch_type *
+mailimap_fetch_type_new_fetch_att_list_empty(void);
+
+/*
+ this function adds a given fetch attribute to the mailimap_fetch
+ structure
+
+ @return MAILIMAP_NO_ERROR will be returned on success,
+ other code will be returned otherwise
+*/
+
+int
+mailimap_fetch_type_new_fetch_att_list_add(struct mailimap_fetch_type *
+ fetch_type,
+ struct mailimap_fetch_att *
+ fetch_att);
+
+/*
+ this function creates a store attribute to set the given flags
+*/
+
+struct mailimap_store_att_flags *
+mailimap_store_att_flags_new_set_flags(struct mailimap_flag_list * flags);
+
+/*
+ this function creates a store attribute to silently set the given flags
+*/
+
+struct mailimap_store_att_flags *
+mailimap_store_att_flags_new_set_flags_silent(struct mailimap_flag_list *
+ flags);
+
+/*
+ this function creates a store attribute to add the given flags
+*/
+
+struct mailimap_store_att_flags *
+mailimap_store_att_flags_new_add_flags(struct mailimap_flag_list * flags);
+
+/*
+ this function creates a store attribute to add silently the given flags
+*/
+
+struct mailimap_store_att_flags *
+mailimap_store_att_flags_new_add_flags_silent(struct mailimap_flag_list *
+ flags);
+
+/*
+ this function creates a store attribute to remove the given flags
+*/
+
+struct mailimap_store_att_flags *
+mailimap_store_att_flags_new_remove_flags(struct mailimap_flag_list * flags);
+
+/*
+ this function creates a store attribute to remove silently the given flags
+*/
+
+struct mailimap_store_att_flags *
+mailimap_store_att_flags_new_remove_flags_silent(struct mailimap_flag_list *
+ flags);
+
+
+/*
+ this function creates a condition structure to match all messages
+*/
+
+struct mailimap_search_key *
+mailimap_search_key_new_all(void);
+
+/*
+ this function creates a condition structure to match messages with Bcc field
+
+ @param bcc this is the content of Bcc to match, it should be allocated
+ with malloc()
+*/
+
+struct mailimap_search_key *
+mailimap_search_key_new_bcc(char * sk_bcc);
+
+/*
+ this function creates a condition structure to match messages with
+ internal date
+*/
+
+struct mailimap_search_key *
+mailimap_search_key_new_before(struct mailimap_date * sk_before);
+
+/*
+ this function creates a condition structure to match messages with
+ message content
+
+ @param body this is the content of the message to match, it should
+ be allocated with malloc()
+*/
+
+struct mailimap_search_key *
+mailimap_search_key_new_body(char * sk_body);
+
+/*
+ this function creates a condition structure to match messages with
+ Cc field
+
+
+ @param cc this is the content of Cc to match, it should be allocated
+ with malloc()
+*/
+
+struct mailimap_search_key *
+mailimap_search_key_new_cc(char * sk_cc);
+
+/*
+ this function creates a condition structure to match messages with
+ From field
+
+ @param from this is the content of From to match, it should be allocated
+ with malloc()
+*/
+
+struct mailimap_search_key *
+mailimap_search_key_new_from(char * sk_from);
+
+/*
+ this function creates a condition structure to match messages with
+ a flag given by keyword
+*/
+
+struct mailimap_search_key *
+mailimap_search_key_new_keyword(char * sk_keyword);
+
+/*
+ this function creates a condition structure to match messages with
+ internal date
+*/
+
+struct mailimap_search_key *
+mailimap_search_key_new_on(struct mailimap_date * sk_on);
+
+/*
+ this function creates a condition structure to match messages with
+ internal date
+*/
+
+struct mailimap_search_key *
+mailimap_search_key_new_since(struct mailimap_date * sk_since);
+
+/*
+ this function creates a condition structure to match messages with
+ Subject field
+
+ @param subject this is the content of Subject to match, it should
+ be allocated with malloc()
+*/
+
+struct mailimap_search_key *
+mailimap_search_key_new_subject(char * sk_subject);
+
+/*
+ this function creates a condition structure to match messages with
+ message text part
+
+ @param text this is the message text to match, it should
+ be allocated with malloc()
+*/
+
+struct mailimap_search_key *
+mailimap_search_key_new_text(char * sk_text);
+
+/*
+ this function creates a condition structure to match messages with
+ To field
+
+ @param to this is the content of To to match, it should be allocated
+ with malloc()
+*/
+
+struct mailimap_search_key *
+mailimap_search_key_new_to(char * sk_to);
+
+/*
+ this function creates a condition structure to match messages with
+ no a flag given by unkeyword
+*/
+
+struct mailimap_search_key *
+mailimap_search_key_new_unkeyword(char * sk_unkeyword);
+
+/*
+ this function creates a condition structure to match messages with
+ the given field
+
+ @param header_name this is the name of the field to match, it
+ should be allocated with malloc()
+
+ @param header_value this is the content, it should be allocated
+ with malloc()
+*/
+
+struct mailimap_search_key *
+mailimap_search_key_new_header(char * sk_header_name, char * sk_header_value);
+
+
+/*
+ this function creates a condition structure to match messages with size
+*/
+
+struct mailimap_search_key *
+mailimap_search_key_new_larger(uint32_t sk_larger);
+
+/*
+ this function creates a condition structure to match messages that
+ do not match the given condition
+*/
+
+struct mailimap_search_key *
+mailimap_search_key_new_not(struct mailimap_search_key * sk_not);
+
+/*
+ this function creates a condition structure to match messages that
+ match one of the given conditions
+*/
+
+struct mailimap_search_key *
+mailimap_search_key_new_or(struct mailimap_search_key * sk_or1,
+ struct mailimap_search_key * sk_or2);
+
+/*
+ this function creates a condition structure to match messages
+ with Date field
+*/
+
+struct mailimap_search_key *
+mailimap_search_key_new_sentbefore(struct mailimap_date * sk_sentbefore);
+
+/*
+ this function creates a condition structure to match messages
+ with Date field
+*/
+
+struct mailimap_search_key *
+mailimap_search_key_new_senton(struct mailimap_date * sk_senton);
+
+/*
+ this function creates a condition structure to match messages
+ with Date field
+*/
+
+struct mailimap_search_key *
+mailimap_search_key_new_sentsince(struct mailimap_date * sk_sentsince);
+
+/*
+ this function creates a condition structure to match messages with size
+*/
+
+struct mailimap_search_key *
+mailimap_search_key_new_smaller(uint32_t sk_smaller);
+
+/*
+ this function creates a condition structure to match messages with unique
+ identifier
+*/
+
+struct mailimap_search_key *
+mailimap_search_key_new_uid(struct mailimap_set * sk_uid);
+
+/*
+ this function creates a condition structure to match messages with number
+ or unique identifier (depending whether SEARCH or UID SEARCH is used)
+*/
+
+struct mailimap_search_key *
+mailimap_search_key_new_set(struct mailimap_set * sk_set);
+
+/*
+ this function creates a condition structure to match messages that match
+ all the conditions given in the list
+*/
+
+struct mailimap_search_key *
+mailimap_search_key_new_multiple(clist * sk_multiple);
+
+
+/*
+ same as previous but the list is empty
+*/
+
+struct mailimap_search_key *
+mailimap_search_key_new_multiple_empty(void);
+
+/*
+ this function adds a condition to the condition list
+
+ @return MAILIMAP_NO_ERROR will be returned on success,
+ other code will be returned otherwise
+*/
+
+int
+mailimap_search_key_multiple_add(struct mailimap_search_key * keys,
+ struct mailimap_search_key * key_item);
+
+
+/*
+ this function creates an empty list of flags
+*/
+
+struct mailimap_flag_list *
+mailimap_flag_list_new_empty(void);
+
+/*
+ this function adds a flag to the list of flags
+
+ @return MAILIMAP_NO_ERROR will be returned on success,
+ other code will be returned otherwise
+*/
+
+int mailimap_flag_list_add(struct mailimap_flag_list * flag_list,
+ struct mailimap_flag * f);
+
+/*
+ this function creates a \Answered flag
+*/
+
+struct mailimap_flag * mailimap_flag_new_answered(void);
+
+/*
+ this function creates a \Flagged flag
+*/
+
+struct mailimap_flag * mailimap_flag_new_flagged(void);
+
+/*
+ this function creates a \Deleted flag
+*/
+
+struct mailimap_flag * mailimap_flag_new_deleted(void);
+
+/*
+ this function creates a \Seen flag
+*/
+
+struct mailimap_flag * mailimap_flag_new_seen(void);
+
+/*
+ this function creates a \Draft flag
+*/
+
+struct mailimap_flag * mailimap_flag_new_draft(void);
+
+/*
+ this function creates a keyword flag
+
+ @param flag_keyword this should be allocated with malloc()
+*/
+
+struct mailimap_flag * mailimap_flag_new_flag_keyword(char * flag_keyword);
+
+
+/*
+ this function creates an extension flag
+
+ @param flag_extension this should be allocated with malloc()
+*/
+
+struct mailimap_flag * mailimap_flag_new_flag_extension(char * flag_extension);
+
+/*
+ this function creates an empty list of status attributes
+*/
+
+struct mailimap_status_att_list * mailimap_status_att_list_new_empty(void);
+
+/*
+ this function adds status attributes to the list
+
+ @return MAILIMAP_NO_ERROR will be returned on success,
+ other code will be returned otherwise
+*/
+
+int
+mailimap_status_att_list_add(struct mailimap_status_att_list * sa_list,
+ int status_att);
+
+/* return mailimap_section_part from a given mailimap_body */
+
+int mailimap_get_section_part_from_body(struct mailimap_body * root_part,
+ struct mailimap_body * part,
+ struct mailimap_section_part ** result);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libetpan/src/low-level/imf/TODO b/libetpan/src/low-level/imf/TODO
new file mode 100644
index 0000000..f36f55f
--- a/dev/null
+++ b/libetpan/src/low-level/imf/TODO
@@ -0,0 +1,12 @@
+- define a EP_parserstate_s
+- remove clist usage
+- add a errorcode to string function
+- error codes are EP_errornr_s
+- prefix everything with EP_
+- mailimf_dot_atom_text_free
+- mailimf_address_XX -> _new(void) _init(&addr, ...) _free(addr)
+- in fact that data structure should then also contain a
+ 'dynamically' allocated flag
+
+- RFC 822 : test the examples
+- RFC 2822 : obsolete syntax
diff --git a/libetpan/src/low-level/imf/mailimf.c b/libetpan/src/low-level/imf/mailimf.c
new file mode 100644
index 0000000..333767a
--- a/dev/null
+++ b/libetpan/src/low-level/imf/mailimf.c
@@ -0,0 +1,7585 @@
+/*
+ * 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 "mailimf.h"
+
+/*
+ RFC 2822
+
+ RFC 2821 ...
+ A message-originating SMTP system SHOULD NOT send a message that
+ already contains a Return-path header. SMTP servers performing a
+ relay function MUST NOT inspect the message data, and especially not
+ to the extent needed to determine if Return-path headers are present.
+ SMTP servers making final delivery MAY remove Return-path headers
+ before adding their own.
+*/
+
+#include <ctype.h>
+#include "mmapstring.h"
+#include <stdlib.h>
+#include <string.h>
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+
+
+
+
+
+
+static inline int is_dtext(char ch);
+
+static int mailimf_quoted_pair_parse(const char * message, size_t length,
+ size_t * index, char * result);
+
+static int mailimf_ccontent_parse(const char * message, size_t length,
+ size_t * index);
+
+static int
+mailimf_comment_fws_ccontent_parse(const char * message, size_t length,
+ size_t * index);
+
+static inline int mailimf_comment_parse(const char * message, size_t length,
+ size_t * index);
+
+static int mailimf_qcontent_parse(const char * message, size_t length,
+ size_t * index, char * ch);
+
+static int mailimf_phrase_parse(const char * message, size_t length,
+ size_t * index, char ** result);
+
+static int mailimf_unstructured_parse(const char * message, size_t length,
+ size_t * index, char ** result);
+
+static int mailimf_ignore_unstructured_parse(const char * message, size_t length,
+ size_t * index);
+
+static int mailimf_day_of_week_parse(const char * message, size_t length,
+ size_t * index, int * result);
+
+static int mailimf_day_name_parse(const char * message, size_t length,
+ size_t * index, int * result);
+
+static int mailimf_date_parse(const char * message, size_t length,
+ size_t * index,
+ int * pday, int * pmonth, int * pyear);
+
+static int mailimf_year_parse(const char * message, size_t length,
+ size_t * index, int * result);
+
+static int mailimf_month_parse(const char * message, size_t length,
+ size_t * index, int * result);
+
+static int mailimf_month_name_parse(const char * message, size_t length,
+ size_t * index, int * result);
+
+static int mailimf_day_parse(const char * message, size_t length,
+ size_t * index, int * result);
+
+static int mailimf_time_parse(const char * message, size_t length,
+ size_t * index,
+ int * phour, int * pmin,
+ int * psec,
+ int * zone);
+static int mailimf_time_of_day_parse(const char * message, size_t length,
+ size_t * index,
+ int * phour, int * pmin,
+ int * psec);
+
+static int mailimf_hour_parse(const char * message, size_t length,
+ size_t * index, int * result);
+
+static int mailimf_minute_parse(const char * message, size_t length,
+ size_t * index, int * result);
+
+static int mailimf_second_parse(const char * message, size_t length,
+ size_t * index, int * result);
+
+static int mailimf_zone_parse(const char * message, size_t length,
+ size_t * index, int * result);
+
+static int mailimf_name_addr_parse(const char * message, size_t length,
+ size_t * index,
+ char ** pdisplay_name,
+ char ** pangle_addr);
+
+static int mailimf_angle_addr_parse(const char * message, size_t length,
+ size_t * index, char ** result);
+
+static int mailimf_group_parse(const char * message, size_t length,
+ size_t * index,
+ struct mailimf_group ** result);
+
+static int mailimf_display_name_parse(const char * message, size_t length,
+ size_t * index, char ** result);
+
+static int mailimf_addr_spec_parse(const char * message, size_t length,
+ size_t * index,
+ char ** address);
+
+#if 0
+static int mailimf_local_part_parse(const char * message, size_t length,
+ size_t * index,
+ char ** result);
+
+static int mailimf_domain_parse(const char * message, size_t length,
+ size_t * index,
+ char ** result);
+#endif
+
+#if 0
+static int mailimf_domain_literal_parse(const char * message, size_t length,
+ size_t * index, char ** result);
+#endif
+
+#if 0
+static int mailimf_dcontent_parse(const char * message, size_t length,
+ size_t * index, char * result);
+#endif
+
+static int
+mailimf_orig_date_parse(const char * message, size_t length,
+ size_t * index, struct mailimf_orig_date ** result);
+
+static int
+mailimf_from_parse(const char * message, size_t length,
+ size_t * index, struct mailimf_from ** result);
+
+static int
+mailimf_sender_parse(const char * message, size_t length,
+ size_t * index, struct mailimf_sender ** result);
+
+static int
+mailimf_reply_to_parse(const char * message, size_t length,
+ size_t * index, struct mailimf_reply_to ** result);
+
+static int
+mailimf_to_parse(const char * message, size_t length,
+ size_t * index, struct mailimf_to ** result);
+
+static int
+mailimf_cc_parse(const char * message, size_t length,
+ size_t * index, struct mailimf_cc ** result);
+
+static int
+mailimf_bcc_parse(const char * message, size_t length,
+ size_t * index, struct mailimf_bcc ** result);
+
+static int mailimf_message_id_parse(const char * message, size_t length,
+ size_t * index,
+ struct mailimf_message_id ** result);
+
+static int
+mailimf_in_reply_to_parse(const char * message, size_t length,
+ size_t * index,
+ struct mailimf_in_reply_to ** result);
+
+#if 0
+static int mailimf_references_parse(const char * message, size_t length,
+ size_t * index,
+ struct mailimf_references **
+ result);
+#endif
+
+static int mailimf_unstrict_msg_id_parse(const char * message, size_t length,
+ size_t * index,
+ char ** result);
+
+#if 0
+static int mailimf_id_left_parse(const char * message, size_t length,
+ size_t * index, char ** result);
+
+static int mailimf_id_right_parse(const char * message, size_t length,
+ size_t * index, char ** result);
+#endif
+
+#if 0
+static int mailimf_no_fold_quote_parse(const char * message, size_t length,
+ size_t * index, char ** result);
+
+static int mailimf_no_fold_literal_parse(const char * message, size_t length,
+ size_t * index, char ** result);
+#endif
+
+static int mailimf_subject_parse(const char * message, size_t length,
+ size_t * index,
+ struct mailimf_subject ** result);
+
+static int mailimf_comments_parse(const char * message, size_t length,
+ size_t * index,
+ struct mailimf_comments ** result);
+
+static int mailimf_keywords_parse(const char * message, size_t length,
+ size_t * index,
+ struct mailimf_keywords ** result);
+
+static int
+mailimf_resent_date_parse(const char * message, size_t length,
+ size_t * index, struct mailimf_orig_date ** result);
+
+static int
+mailimf_resent_from_parse(const char * message, size_t length,
+ size_t * index, struct mailimf_from ** result);
+
+static int
+mailimf_resent_sender_parse(const char * message, size_t length,
+ size_t * index, struct mailimf_sender ** result);
+
+static int
+mailimf_resent_to_parse(const char * message, size_t length,
+ size_t * index, struct mailimf_to ** result);
+
+static int
+mailimf_resent_cc_parse(const char * message, size_t length,
+ size_t * index, struct mailimf_cc ** result);
+
+static int
+mailimf_resent_bcc_parse(const char * message, size_t length,
+ size_t * index, struct mailimf_bcc ** result);
+
+static int
+mailimf_resent_msg_id_parse(const char * message, size_t length,
+ size_t * index,
+ struct mailimf_message_id ** result);
+
+static int mailimf_return_parse(const char * message, size_t length,
+ size_t * index,
+ struct mailimf_return ** result);
+
+static int
+mailimf_path_parse(const char * message, size_t length,
+ size_t * index, struct mailimf_path ** result);
+
+static int
+mailimf_optional_field_parse(const char * message, size_t length,
+ size_t * index,
+ struct mailimf_optional_field ** result);
+
+static int mailimf_field_name_parse(const char * message, size_t length,
+ size_t * index, char ** result);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+/* *************************************************************** */
+
+static inline int is_digit(char ch)
+{
+ return (ch >= '0') && (ch <= '9');
+}
+
+static int mailimf_digit_parse(const char * message, size_t length,
+ size_t * index, int * result)
+{
+ size_t cur_token;
+
+ cur_token = * index;
+
+ if (cur_token >= length)
+ return MAILIMF_ERROR_PARSE;
+
+ if (is_digit(message[cur_token])) {
+ * result = message[cur_token] - '0';
+ cur_token ++;
+ * index = cur_token;
+ return MAILIMF_NO_ERROR;
+ }
+ else
+ return MAILIMF_ERROR_PARSE;
+}
+
+int
+mailimf_number_parse(const char * message, size_t length,
+ size_t * index, uint32_t * result)
+{
+ size_t cur_token;
+ int digit;
+ uint32_t number;
+ int parsed;
+ int r;
+
+ cur_token = * index;
+ parsed = FALSE;
+
+ number = 0;
+ while (1) {
+ r = mailimf_digit_parse(message, length, &cur_token, &digit);
+ if (r != MAILIMF_NO_ERROR) {
+ if (r == MAILIMF_ERROR_PARSE)
+ break;
+ else
+ return r;
+ }
+ number *= 10;
+ number += digit;
+ parsed = TRUE;
+ }
+
+ if (!parsed)
+ return MAILIMF_ERROR_PARSE;
+
+ * result = number;
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+}
+
+int mailimf_char_parse(const char * message, size_t length,
+ size_t * index, char token)
+{
+ size_t cur_token;
+
+ cur_token = * index;
+
+ if (cur_token >= length)
+ return MAILIMF_ERROR_PARSE;
+
+ if (message[cur_token] == token) {
+ cur_token ++;
+ * index = cur_token;
+ return MAILIMF_NO_ERROR;
+ }
+ else
+ return MAILIMF_ERROR_PARSE;
+}
+
+int mailimf_unstrict_char_parse(const char * message, size_t length,
+ size_t * index, char token)
+{
+ size_t cur_token;
+ int r;
+
+ cur_token = * index;
+
+ r = mailimf_cfws_parse(message, length, &cur_token);
+ if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE))
+ return r;
+
+ r = mailimf_char_parse(message, length, &cur_token, token);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+}
+
+int
+mailimf_token_case_insensitive_len_parse(const char * message, size_t length,
+ size_t * index, char * token,
+ size_t token_length)
+{
+ size_t cur_token;
+
+ cur_token = * index;
+
+ if (cur_token + token_length - 1 >= length)
+ return MAILIMF_ERROR_PARSE;
+
+ if (strncasecmp(message + cur_token, token, token_length) == 0) {
+ cur_token += token_length;
+ * index = cur_token;
+ return MAILIMF_NO_ERROR;
+ }
+ else
+ return MAILIMF_ERROR_PARSE;
+}
+
+static int mailimf_oparenth_parse(const char * message, size_t length,
+ size_t * index)
+{
+ return mailimf_char_parse(message, length, index, '(');
+}
+
+static int mailimf_cparenth_parse(const char * message, size_t length,
+ size_t * index)
+{
+ return mailimf_char_parse(message, length, index, ')');
+}
+
+static int mailimf_comma_parse(const char * message, size_t length,
+ size_t * index)
+{
+ return mailimf_unstrict_char_parse(message, length, index, ',');
+}
+
+static int mailimf_dquote_parse(const char * message, size_t length,
+ size_t * index)
+{
+ return mailimf_char_parse(message, length, index, '\"');
+}
+
+static int mailimf_colon_parse(const char * message, size_t length,
+ size_t * index)
+{
+ return mailimf_unstrict_char_parse(message, length, index, ':');
+}
+
+static int mailimf_semi_colon_parse(const char * message, size_t length,
+ size_t * index)
+{
+ return mailimf_unstrict_char_parse(message, length, index, ';');
+}
+
+static int mailimf_plus_parse(const char * message, size_t length,
+ size_t * index)
+{
+ return mailimf_unstrict_char_parse(message, length, index, '+');
+}
+
+static int mailimf_minus_parse(const char * message, size_t length,
+ size_t * index)
+{
+ return mailimf_unstrict_char_parse(message, length, index, '-');
+}
+
+static int mailimf_lower_parse(const char * message, size_t length,
+ size_t * index)
+{
+ return mailimf_unstrict_char_parse(message, length, index, '<');
+}
+
+static int mailimf_greater_parse(const char * message, size_t length,
+ size_t * index)
+{
+ return mailimf_unstrict_char_parse(message, length, index, '>');
+}
+
+#if 0
+static int mailimf_obracket_parse(const char * message, size_t length,
+ size_t * index)
+{
+ return mailimf_unstrict_char_parse(message, length, index, '[');
+}
+
+static int mailimf_cbracket_parse(const char * message, size_t length,
+ size_t * index)
+{
+ return mailimf_unstrict_char_parse(message, length, index, ']');
+}
+#endif
+
+static int mailimf_at_sign_parse(const char * message, size_t length,
+ size_t * index)
+{
+ return mailimf_unstrict_char_parse(message, length, index, '@');
+}
+
+static int mailimf_point_parse(const char * message, size_t length,
+ size_t * index)
+{
+ return mailimf_unstrict_char_parse(message, length, index, '.');
+}
+
+int
+mailimf_custom_string_parse(const char * message, size_t length,
+ size_t * index, char ** result,
+ int (* is_custom_char)(char))
+{
+ size_t begin;
+ size_t end;
+ char * gstr;
+
+ begin = * index;
+
+ end = begin;
+
+ if (end >= length)
+ return MAILIMF_ERROR_PARSE;
+
+ while (is_custom_char(message[end])) {
+ end ++;
+ if (end >= length)
+ break;
+ }
+
+ if (end != begin) {
+ /*
+ gstr = strndup(message + begin, end - begin);
+ */
+ gstr = malloc(end - begin + 1);
+ if (gstr == NULL)
+ return MAILIMF_ERROR_MEMORY;
+ strncpy(gstr, message + begin, end - begin);
+ gstr[end - begin] = '\0';
+
+ * index = end;
+ * result = gstr;
+ return MAILIMF_NO_ERROR;
+ }
+ else
+ return MAILIMF_ERROR_PARSE;
+}
+
+
+
+
+
+
+
+typedef int mailimf_struct_parser(const char * message, size_t length,
+ size_t * index, void * result);
+
+typedef int mailimf_struct_destructor(void * result);
+
+
+static int
+mailimf_struct_multiple_parse(const char * message, size_t length,
+ size_t * index, clist ** result,
+ mailimf_struct_parser * parser,
+ mailimf_struct_destructor * destructor)
+{
+ clist * struct_list;
+ size_t cur_token;
+ void * value;
+ int r;
+ int res;
+
+ cur_token = * index;
+
+ r = parser(message, length, &cur_token, &value);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ struct_list = clist_new();
+ if (struct_list == NULL) {
+ destructor(value);
+ res = MAILIMF_ERROR_MEMORY;
+ goto err;
+ }
+
+ r = clist_append(struct_list, value);
+ if (r < 0) {
+ destructor(value);
+ res = MAILIMF_ERROR_MEMORY;
+ goto free;
+ }
+
+ while (1) {
+ r = parser(message, length, &cur_token, &value);
+ if (r != MAILIMF_NO_ERROR) {
+ if (r == MAILIMF_ERROR_PARSE)
+ break;
+ else {
+ res = r;
+ goto free;
+ }
+ }
+ r = clist_append(struct_list, value);
+ if (r < 0) {
+ (* destructor)(value);
+ res = MAILIMF_ERROR_MEMORY;
+ goto free;
+ }
+ }
+
+ * result = struct_list;
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+
+ free:
+ clist_foreach(struct_list, (clist_func) destructor, NULL);
+ clist_free(struct_list);
+ err:
+ return res;
+}
+
+
+
+static int
+mailimf_struct_list_parse(const char * message, size_t length,
+ size_t * index, clist ** result,
+ char symbol,
+ mailimf_struct_parser * parser,
+ mailimf_struct_destructor * destructor)
+{
+ clist * struct_list;
+ size_t cur_token;
+ void * value;
+ size_t final_token;
+ int r;
+ int res;
+
+ cur_token = * index;
+
+ r = parser(message, length, &cur_token, &value);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ struct_list = clist_new();
+ if (struct_list == NULL) {
+ destructor(value);
+ res = MAILIMF_ERROR_MEMORY;
+ goto err;
+ }
+
+ r = clist_append(struct_list, value);
+ if (r < 0) {
+ destructor(value);
+ res = MAILIMF_ERROR_MEMORY;
+ goto free;
+ }
+
+ final_token = cur_token;
+
+ while (1) {
+ r = mailimf_unstrict_char_parse(message, length, &cur_token, symbol);
+ if (r != MAILIMF_NO_ERROR) {
+ if (r == MAILIMF_ERROR_PARSE)
+ break;
+ else {
+ res = r;
+ goto free;
+ }
+ }
+
+ r = parser(message, length, &cur_token, &value);
+ if (r != MAILIMF_NO_ERROR) {
+ if (r == MAILIMF_ERROR_PARSE)
+ break;
+ else {
+ res = r;
+ goto free;
+ }
+ }
+
+ r = clist_append(struct_list, value);
+ if (r < 0) {
+ destructor(value);
+ res = MAILIMF_ERROR_MEMORY;
+ goto free;
+ }
+
+ final_token = cur_token;
+ }
+
+ * result = struct_list;
+ * index = final_token;
+
+ return MAILIMF_NO_ERROR;
+
+ free:
+ clist_foreach(struct_list, (clist_func) destructor, NULL);
+ clist_free(struct_list);
+ err:
+ return res;
+}
+
+static inline int mailimf_wsp_parse(const char * message, size_t length,
+ size_t * index)
+{
+ size_t cur_token;
+
+ cur_token = * index;
+
+ if (cur_token >= length)
+ return MAILIMF_ERROR_PARSE;
+
+ if ((message[cur_token] != ' ') && (message[cur_token] != '\t'))
+ return MAILIMF_ERROR_PARSE;
+
+ cur_token ++;
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+}
+
+
+int mailimf_crlf_parse(const char * message, size_t length, size_t * index)
+{
+ size_t cur_token;
+ int r;
+
+ cur_token = * index;
+
+ r = mailimf_char_parse(message, length, &cur_token, '\r');
+ if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE))
+ return r;
+
+ r = mailimf_char_parse(message, length, &cur_token, '\n');
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ * index = cur_token;
+ return MAILIMF_NO_ERROR;
+}
+
+static int mailimf_unstrict_crlf_parse(const char * message,
+ size_t length, size_t * index)
+{
+ size_t cur_token;
+ int r;
+
+ cur_token = * index;
+
+ mailimf_cfws_parse(message, length, &cur_token);
+
+ r = mailimf_char_parse(message, length, &cur_token, '\r');
+ if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE))
+ return r;
+
+ r = mailimf_char_parse(message, length, &cur_token, '\n');
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ * index = cur_token;
+ return MAILIMF_NO_ERROR;
+}
+
+/* ************************************************************************ */
+
+
+
+/* RFC 2822 grammar */
+
+/*
+NO-WS-CTL = %d1-8 / ; US-ASCII control characters
+ %d11 / ; that do not include the
+ %d12 / ; carriage return, line feed,
+ %d14-31 / ; and white space characters
+ %d127
+*/
+
+static inline int is_no_ws_ctl(char ch)
+{
+ if ((ch == 9) || (ch == 10) || (ch == 13))
+ return FALSE;
+
+ if (ch == 127)
+ return TRUE;
+
+ return (ch >= 1) && (ch <= 31);
+}
+
+/*
+text = %d1-9 / ; Characters excluding CR and LF
+ %d11 /
+ %d12 /
+ %d14-127 /
+ obs-text
+*/
+
+/*
+specials = "(" / ")" / ; Special characters used in
+ "<" / ">" / ; other parts of the syntax
+ "[" / "]" /
+ ":" / ";" /
+ "@" / "\" /
+ "," / "." /
+ DQUOTE
+*/
+
+/*
+quoted-pair = ("\" text) / obs-qp
+*/
+
+static inline int mailimf_quoted_pair_parse(const char * message, size_t length,
+ size_t * index, char * result)
+{
+ size_t cur_token;
+
+ cur_token = * index;
+
+ if (cur_token + 1 >= length)
+ return MAILIMF_ERROR_PARSE;
+
+ if (message[cur_token] != '\\')
+ return MAILIMF_ERROR_PARSE;
+
+ cur_token ++;
+ * result = message[cur_token];
+ cur_token ++;
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+}
+
+/*
+FWS = ([*WSP CRLF] 1*WSP) / ; Folding white space
+ obs-FWS
+*/
+
+int mailimf_fws_parse(const char * message, size_t length, size_t * index)
+{
+ size_t cur_token;
+ size_t final_token;
+ int fws_1;
+ int fws_2;
+ int fws_3;
+ int r;
+
+ cur_token = * index;
+
+ fws_1 = FALSE;
+ while (1) {
+ r = mailimf_wsp_parse(message, length, &cur_token);
+ if (r != MAILIMF_NO_ERROR) {
+ if (r == MAILIMF_ERROR_PARSE)
+ break;
+ else
+ return r;
+ }
+ fws_1 = TRUE;
+ }
+ final_token = cur_token;
+
+ r = mailimf_crlf_parse(message, length, &cur_token);
+ switch (r) {
+ case MAILIMF_NO_ERROR:
+ fws_2 = TRUE;
+ break;
+ case MAILIMF_ERROR_PARSE:
+ fws_2 = FALSE;
+ break;
+ default:
+ return r;
+ }
+
+ fws_3 = FALSE;
+ if (fws_2) {
+ while (1) {
+ r = mailimf_wsp_parse(message, length, &cur_token);
+ if (r != MAILIMF_NO_ERROR) {
+ if (r == MAILIMF_ERROR_PARSE)
+ break;
+ else
+ return r;
+ }
+ fws_3 = TRUE;
+ }
+ }
+
+ if ((!fws_1) && (!fws_3))
+ return MAILIMF_ERROR_PARSE;
+
+ if (!fws_3)
+ cur_token = final_token;
+
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+}
+
+
+/*
+ctext = NO-WS-CTL / ; Non white space controls
+
+ %d33-39 / ; The rest of the US-ASCII
+ %d42-91 / ; characters not including "(",
+ %d93-126 ; ")", or "\"
+*/
+
+static inline int is_ctext(char ch)
+{
+ unsigned char uch = (unsigned char) ch;
+
+ if (is_no_ws_ctl(ch))
+ return TRUE;
+
+ if (uch < 33)
+ return FALSE;
+
+ if ((uch == 40) || (uch == 41))
+ return FALSE;
+
+ if (uch == 92)
+ return FALSE;
+
+ if (uch == 127)
+ return FALSE;
+
+ return TRUE;
+}
+
+/*
+ccontent = ctext / quoted-pair / comment
+*/
+
+static inline int mailimf_ccontent_parse(const char * message, size_t length,
+ size_t * index)
+{
+ size_t cur_token;
+ char ch;
+ int r;
+
+ cur_token = * index;
+
+ if (cur_token >= length)
+ return MAILIMF_ERROR_PARSE;
+
+ if (is_ctext(message[cur_token])) {
+ cur_token ++;
+ }
+ else {
+ r = mailimf_quoted_pair_parse(message, length, &cur_token, &ch);
+
+ if (r == MAILIMF_ERROR_PARSE)
+ r = mailimf_comment_parse(message, length, &cur_token);
+
+ if (r == MAILIMF_ERROR_PARSE)
+ return r;
+ }
+
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+}
+
+/*
+[FWS] ccontent
+*/
+
+static inline int
+mailimf_comment_fws_ccontent_parse(const char * message, size_t length,
+ size_t * index)
+{
+ size_t cur_token;
+ int r;
+
+ cur_token = * index;
+
+ r = mailimf_fws_parse(message, length, &cur_token);
+ if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE))
+ return r;
+
+ r = mailimf_ccontent_parse(message, length, &cur_token);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+}
+
+/*
+comment = "(" *([FWS] ccontent) [FWS] ")"
+*/
+
+static inline int mailimf_comment_parse(const char * message, size_t length,
+ size_t * index)
+{
+ size_t cur_token;
+ int r;
+
+ cur_token = * index;
+
+ r = mailimf_oparenth_parse(message, length, &cur_token);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ while (1) {
+ r = mailimf_comment_fws_ccontent_parse(message, length, &cur_token);
+ if (r != MAILIMF_NO_ERROR) {
+ if (r == MAILIMF_ERROR_PARSE)
+ break;
+ else
+ return r;
+ }
+ }
+
+ r = mailimf_fws_parse(message, length, &cur_token);
+ if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE))
+ return r;
+
+ r = mailimf_cparenth_parse(message, length, &cur_token);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+}
+
+/*
+[FWS] comment
+*/
+
+static inline int mailimf_cfws_fws_comment_parse(const char * message, size_t length,
+ size_t * index)
+{
+ size_t cur_token;
+ int r;
+
+ cur_token = * index;
+
+ r = mailimf_fws_parse(message, length, &cur_token);
+ if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE))
+ return r;
+
+ r = mailimf_comment_parse(message, length, &cur_token);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+}
+
+/*
+CFWS = *([FWS] comment) (([FWS] comment) / FWS)
+*/
+
+int mailimf_cfws_parse(const char * message, size_t length,
+ size_t * index)
+{
+ size_t cur_token;
+ int has_comment;
+ int r;
+
+ cur_token = * index;
+
+ has_comment = FALSE;
+ while (1) {
+ r = mailimf_cfws_fws_comment_parse(message, length, &cur_token);
+ if (r != MAILIMF_NO_ERROR) {
+ if (r == MAILIMF_ERROR_PARSE)
+ break;
+ else
+ return r;
+ }
+ has_comment = TRUE;
+ }
+
+ if (!has_comment) {
+ r = mailimf_fws_parse(message, length, &cur_token);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ }
+
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+}
+
+/*
+atext = ALPHA / DIGIT / ; Any character except controls,
+ "!" / "#" / ; SP, and specials.
+ "$" / "%" / ; Used for atoms
+ "&" / "'" /
+ "*" / "+" /
+ "-" / "/" /
+ "=" / "?" /
+ "^" / "_" /
+ "`" / "{" /
+ "|" / "}" /
+ "~"
+*/
+
+static inline int is_atext(char ch)
+{
+ switch (ch) {
+ case ' ':
+ case '\t':
+ case '\n':
+ case '\r':
+#if 0
+ case '(':
+ case ')':
+#endif
+ case '<':
+ case '>':
+#if 0
+ case '@':
+#endif
+ case ',':
+ case '"':
+ case ':':
+ case ';':
+ return FALSE;
+ default:
+ return TRUE;
+ }
+}
+
+/*
+atom = [CFWS] 1*atext [CFWS]
+*/
+
+int mailimf_atom_parse(const char * message, size_t length,
+ size_t * index, char ** result)
+{
+ size_t cur_token;
+ int r;
+ int res;
+ char * atom;
+ size_t end;
+
+ cur_token = * index;
+
+ r = mailimf_cfws_parse(message, length, &cur_token);
+ if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
+ res = r;
+ goto err;
+ }
+
+ end = cur_token;
+ if (end >= length) {
+ res = MAILIMF_ERROR_PARSE;
+ goto err;
+ }
+
+ while (is_atext(message[end])) {
+ end ++;
+ if (end >= length)
+ break;
+ }
+ if (end == cur_token) {
+ res = MAILIMF_ERROR_PARSE;
+ goto err;
+ }
+
+ atom = malloc(end - cur_token + 1);
+ if (atom == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto err;
+ }
+ strncpy(atom, message + cur_token, end - cur_token);
+ atom[end - cur_token] = '\0';
+
+ cur_token = end;
+
+ * index = cur_token;
+ * result = atom;
+
+ return MAILIMF_NO_ERROR;
+
+ err:
+ return res;
+}
+
+int mailimf_fws_atom_parse(const char * message, size_t length,
+ size_t * index, char ** result)
+{
+ size_t cur_token;
+ int r;
+ int res;
+ char * atom;
+ size_t end;
+
+ cur_token = * index;
+
+ r = mailimf_fws_parse(message, length, &cur_token);
+ if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
+ res = r;
+ goto err;
+ }
+
+ end = cur_token;
+ if (end >= length) {
+ res = MAILIMF_ERROR_PARSE;
+ goto err;
+ }
+
+ while (is_atext(message[end])) {
+ end ++;
+ if (end >= length)
+ break;
+ }
+ if (end == cur_token) {
+ res = MAILIMF_ERROR_PARSE;
+ goto err;
+ }
+
+ atom = malloc(end - cur_token + 1);
+ if (atom == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto err;
+ }
+ strncpy(atom, message + cur_token, end - cur_token);
+ atom[end - cur_token] = '\0';
+
+ cur_token = end;
+
+ * index = cur_token;
+ * result = atom;
+
+ return MAILIMF_NO_ERROR;
+
+ err:
+ return res;
+}
+
+/*
+dot-atom = [CFWS] dot-atom-text [CFWS]
+*/
+
+#if 0
+static int mailimf_dot_atom_parse(const char * message, size_t length,
+ size_t * index, char ** result)
+{
+ return mailimf_atom_parse(message, length, index, result);
+}
+#endif
+
+/*
+dot-atom-text = 1*atext *("." 1*atext)
+*/
+
+#if 0
+static int
+mailimf_dot_atom_text_parse(const char * message, size_t length,
+ size_t * index, char ** result)
+{
+ return mailimf_atom_parse(message, length, index, result);
+}
+#endif
+
+/*
+qtext = NO-WS-CTL / ; Non white space controls
+
+ %d33 / ; The rest of the US-ASCII
+ %d35-91 / ; characters not including "\"
+ %d93-126 ; or the quote character
+*/
+
+static inline int is_qtext(char ch)
+{
+ unsigned char uch = (unsigned char) ch;
+
+ if (is_no_ws_ctl(ch))
+ return TRUE;
+
+ if (uch < 33)
+ return FALSE;
+
+ if (uch == 34)
+ return FALSE;
+
+ if (uch == 92)
+ return FALSE;
+
+ if (uch == 127)
+ return FALSE;
+
+ return TRUE;
+}
+
+/*
+qcontent = qtext / quoted-pair
+*/
+
+static int mailimf_qcontent_parse(const char * message, size_t length,
+ size_t * index, char * result)
+{
+ size_t cur_token;
+ char ch;
+ int r;
+
+ cur_token = * index;
+
+ if (cur_token >= length)
+ return MAILIMF_ERROR_PARSE;
+
+ if (is_qtext(message[cur_token])) {
+ ch = message[cur_token];
+ cur_token ++;
+ }
+ else {
+ r = mailimf_quoted_pair_parse(message, length, &cur_token, &ch);
+
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ }
+
+ * result = ch;
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+}
+
+/*
+quoted-string = [CFWS]
+ DQUOTE *([FWS] qcontent) [FWS] DQUOTE
+ [CFWS]
+*/
+
+int mailimf_quoted_string_parse(const char * message, size_t length,
+ size_t * index, char ** result)
+{
+ size_t cur_token;
+ MMAPString * gstr;
+ char ch;
+ char * str;
+ int r;
+ int res;
+
+ cur_token = * index;
+
+ r = mailimf_cfws_parse(message, length, &cur_token);
+ if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
+ res = r;
+ goto err;
+ }
+
+ r = mailimf_dquote_parse(message, length, &cur_token);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ gstr = mmap_string_new("");
+ if (gstr == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto err;
+ }
+
+#if 0
+ if (mmap_string_append_c(gstr, '\"') == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free_gstr;
+ }
+#endif
+
+ while (1) {
+ r = mailimf_fws_parse(message, length, &cur_token);
+ if (r == MAILIMF_NO_ERROR) {
+ if (mmap_string_append_c(gstr, ' ') == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free_gstr;
+ }
+ }
+ else if (r != MAILIMF_ERROR_PARSE) {
+ res = r;
+ goto free_gstr;
+ }
+
+ r = mailimf_qcontent_parse(message, length, &cur_token, &ch);
+ if (r == MAILIMF_NO_ERROR) {
+ if (mmap_string_append_c(gstr, ch) == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free_gstr;
+ }
+ }
+ else if (r == MAILIMF_ERROR_PARSE)
+ break;
+ else {
+ res = r;
+ goto free_gstr;
+ }
+ }
+
+ r = mailimf_dquote_parse(message, length, &cur_token);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto free_gstr;
+ }
+
+#if 0
+ if (mmap_string_append_c(gstr, '\"') == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free_gstr;
+ }
+#endif
+
+ str = strdup(gstr->str);
+ if (str == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free_gstr;
+ }
+ mmap_string_free(gstr);
+
+ * index = cur_token;
+ * result = str;
+
+ return MAILIMF_NO_ERROR;
+
+ free_gstr:
+ mmap_string_free(gstr);
+ err:
+ return res;
+}
+
+int mailimf_fws_quoted_string_parse(const char * message, size_t length,
+ size_t * index, char ** result)
+{
+ size_t cur_token;
+ MMAPString * gstr;
+ char ch;
+ char * str;
+ int r;
+ int res;
+
+ cur_token = * index;
+
+ r = mailimf_fws_parse(message, length, &cur_token);
+ if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
+ res = r;
+ goto err;
+ }
+
+ r = mailimf_dquote_parse(message, length, &cur_token);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ gstr = mmap_string_new("");
+ if (gstr == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto err;
+ }
+
+#if 0
+ if (mmap_string_append_c(gstr, '\"') == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free_gstr;
+ }
+#endif
+
+ while (1) {
+ r = mailimf_fws_parse(message, length, &cur_token);
+ if (r == MAILIMF_NO_ERROR) {
+ if (mmap_string_append_c(gstr, ' ') == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free_gstr;
+ }
+ }
+ else if (r != MAILIMF_ERROR_PARSE) {
+ res = r;
+ goto free_gstr;
+ }
+
+ r = mailimf_qcontent_parse(message, length, &cur_token, &ch);
+ if (r == MAILIMF_NO_ERROR) {
+ if (mmap_string_append_c(gstr, ch) == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free_gstr;
+ }
+ }
+ else if (r == MAILIMF_ERROR_PARSE)
+ break;
+ else {
+ res = r;
+ goto free_gstr;
+ }
+ }
+
+ r = mailimf_dquote_parse(message, length, &cur_token);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto free_gstr;
+ }
+
+#if 0
+ if (mmap_string_append_c(gstr, '\"') == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free_gstr;
+ }
+#endif
+
+ str = strdup(gstr->str);
+ if (str == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free_gstr;
+ }
+ mmap_string_free(gstr);
+
+ * index = cur_token;
+ * result = str;
+
+ return MAILIMF_NO_ERROR;
+
+ free_gstr:
+ mmap_string_free(gstr);
+ err:
+ return res;
+}
+
+/*
+word = atom / quoted-string
+*/
+
+int mailimf_word_parse(const char * message, size_t length,
+ size_t * index, char ** result)
+{
+ size_t cur_token;
+ char * word;
+ int r;
+
+ cur_token = * index;
+
+ r = mailimf_atom_parse(message, length, &cur_token, &word);
+
+ if (r == MAILIMF_ERROR_PARSE)
+ r = mailimf_quoted_string_parse(message, length, &cur_token, &word);
+
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ * result = word;
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+}
+
+int mailimf_fws_word_parse(const char * message, size_t length,
+ size_t * index, char ** result)
+{
+ size_t cur_token;
+ char * word;
+ int r;
+
+ cur_token = * index;
+
+ r = mailimf_fws_atom_parse(message, length, &cur_token, &word);
+
+ if (r == MAILIMF_ERROR_PARSE)
+ r = mailimf_fws_quoted_string_parse(message, length, &cur_token, &word);
+
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ * result = word;
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+}
+
+/*
+phrase = 1*word / obs-phrase
+*/
+
+static int mailimf_phrase_parse(const char * message, size_t length,
+ size_t * index, char ** result)
+{
+ MMAPString * gphrase;
+ char * word;
+ int first;
+ size_t cur_token;
+ int r;
+ int res;
+ char * str;
+
+ cur_token = * index;
+
+ gphrase = mmap_string_new("");
+ if (gphrase == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto err;
+ }
+
+ first = TRUE;
+
+ while (1) {
+ r = mailimf_fws_word_parse(message, length, &cur_token, &word);
+ if (r == MAILIMF_NO_ERROR) {
+ if (!first) {
+ if (mmap_string_append_c(gphrase, ' ') == NULL) {
+ mailimf_word_free(word);
+ res = MAILIMF_ERROR_MEMORY;
+ goto free;
+ }
+ }
+ if (mmap_string_append(gphrase, word) == NULL) {
+ mailimf_word_free(word);
+ res = MAILIMF_ERROR_MEMORY;
+ goto free;
+ }
+ mailimf_word_free(word);
+ first = FALSE;
+ }
+ else if (r == MAILIMF_ERROR_PARSE)
+ break;
+ else {
+ res = r;
+ goto free;
+ }
+ }
+
+ if (first) {
+ res = MAILIMF_ERROR_PARSE;
+ goto free;
+ }
+
+ str = strdup(gphrase->str);
+ if (str == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free;
+ }
+ mmap_string_free(gphrase);
+
+ * result = str;
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+
+ free:
+ mmap_string_free(gphrase);
+ err:
+ return res;
+}
+
+/*
+utext = NO-WS-CTL / ; Non white space controls
+ %d33-126 / ; The rest of US-ASCII
+ obs-utext
+
+added : WSP
+*/
+
+enum {
+ UNSTRUCTURED_START,
+ UNSTRUCTURED_CR,
+ UNSTRUCTURED_LF,
+ UNSTRUCTURED_WSP,
+ UNSTRUCTURED_OUT
+};
+
+static int mailimf_unstructured_parse(const char * message, size_t length,
+ size_t * index, char ** result)
+{
+ size_t cur_token;
+ int state;
+ size_t begin;
+ size_t terminal;
+ char * str;
+
+ cur_token = * index;
+
+
+ while (1) {
+ int r;
+
+ r = mailimf_wsp_parse(message, length, &cur_token);
+ if (r == MAILIMF_NO_ERROR) {
+ /* do nothing */
+ }
+ else if (r == MAILIMF_ERROR_PARSE)
+ break;
+ else {
+ return r;
+ }
+ }
+
+ state = UNSTRUCTURED_START;
+ begin = cur_token;
+ terminal = cur_token;
+
+ while (state != UNSTRUCTURED_OUT) {
+
+ switch(state) {
+ case UNSTRUCTURED_START:
+ if (cur_token >= length)
+ return MAILIMF_ERROR_PARSE;
+
+ terminal = cur_token;
+ switch(message[cur_token]) {
+ case '\r':
+ state = UNSTRUCTURED_CR;
+ break;
+ case '\n':
+ state = UNSTRUCTURED_LF;
+ break;
+ default:
+ state = UNSTRUCTURED_START;
+ break;
+ }
+ break;
+ case UNSTRUCTURED_CR:
+ if (cur_token >= length)
+ return MAILIMF_ERROR_PARSE;
+
+ switch(message[cur_token]) {
+ case '\n':
+ state = UNSTRUCTURED_LF;
+ break;
+ default:
+ state = UNSTRUCTURED_START;
+ break;
+ }
+ break;
+
+ case UNSTRUCTURED_LF:
+ if (cur_token >= length) {
+ state = UNSTRUCTURED_OUT;
+ break;
+ }
+
+ switch(message[cur_token]) {
+ case '\t':
+ case ' ':
+ state = UNSTRUCTURED_WSP;
+ break;
+ default:
+ state = UNSTRUCTURED_OUT;
+ break;
+ }
+ break;
+ case UNSTRUCTURED_WSP:
+ if (cur_token >= length)
+ return MAILIMF_ERROR_PARSE;
+
+ switch(message[cur_token]) {
+ case '\r':
+ state = UNSTRUCTURED_CR;
+ break;
+ case '\n':
+ state = UNSTRUCTURED_LF;
+ break;
+ default:
+ state = UNSTRUCTURED_START;
+ break;
+ }
+ break;
+ }
+
+ cur_token ++;
+ }
+
+ str = malloc(terminal - begin + 1);
+ if (str == NULL)
+ return MAILIMF_ERROR_MEMORY;
+ strncpy(str, message + begin, terminal - begin);
+ str[terminal - begin] = '\0';
+
+ * index = terminal;
+ * result = str;
+
+ return MAILIMF_NO_ERROR;
+}
+
+
+static int mailimf_ignore_unstructured_parse(const char * message, size_t length,
+ size_t * index)
+{
+ size_t cur_token;
+ int state;
+ size_t terminal;
+
+ cur_token = * index;
+
+ state = UNSTRUCTURED_START;
+ terminal = cur_token;
+
+ while (state != UNSTRUCTURED_OUT) {
+
+ switch(state) {
+ case UNSTRUCTURED_START:
+ if (cur_token >= length)
+ return MAILIMF_ERROR_PARSE;
+ terminal = cur_token;
+ switch(message[cur_token]) {
+ case '\r':
+ state = UNSTRUCTURED_CR;
+ break;
+ case '\n':
+ state = UNSTRUCTURED_LF;
+ break;
+ default:
+ state = UNSTRUCTURED_START;
+ break;
+ }
+ break;
+ case UNSTRUCTURED_CR:
+ if (cur_token >= length)
+ return MAILIMF_ERROR_PARSE;
+ switch(message[cur_token]) {
+ case '\n':
+ state = UNSTRUCTURED_LF;
+ break;
+ default:
+ state = UNSTRUCTURED_START;
+ break;
+ }
+ break;
+ case UNSTRUCTURED_LF:
+ if (cur_token >= length) {
+ state = UNSTRUCTURED_OUT;
+ break;
+ }
+ switch(message[cur_token]) {
+ case '\t':
+ case ' ':
+ state = UNSTRUCTURED_WSP;
+ break;
+ default:
+ state = UNSTRUCTURED_OUT;
+ break;
+ }
+ break;
+ case UNSTRUCTURED_WSP:
+ if (cur_token >= length)
+ return MAILIMF_ERROR_PARSE;
+ switch(message[cur_token]) {
+ case '\r':
+ state = UNSTRUCTURED_CR;
+ break;
+ case '\n':
+ state = UNSTRUCTURED_LF;
+ break;
+ default:
+ state = UNSTRUCTURED_START;
+ break;
+ }
+ break;
+ }
+
+ cur_token ++;
+ }
+
+ * index = terminal;
+
+ return MAILIMF_NO_ERROR;
+}
+
+
+int mailimf_ignore_field_parse(const char * message, size_t length,
+ size_t * index)
+{
+ int has_field;
+ size_t cur_token;
+ int state;
+ size_t terminal;
+
+ has_field = FALSE;
+ cur_token = * index;
+
+ terminal = cur_token;
+ state = UNSTRUCTURED_START;
+
+ /* check if this is not a beginning CRLF */
+
+ if (cur_token >= length)
+ return MAILIMF_ERROR_PARSE;
+
+ switch (message[cur_token]) {
+ case '\r':
+ return MAILIMF_ERROR_PARSE;
+ case '\n':
+ return MAILIMF_ERROR_PARSE;
+ }
+
+ while (state != UNSTRUCTURED_OUT) {
+
+ switch(state) {
+ case UNSTRUCTURED_START:
+ if (cur_token >= length)
+ return MAILIMF_ERROR_PARSE;
+
+ switch(message[cur_token]) {
+ case '\r':
+ state = UNSTRUCTURED_CR;
+ break;
+ case '\n':
+ state = UNSTRUCTURED_LF;
+ break;
+ case ':':
+ has_field = TRUE;
+ state = UNSTRUCTURED_START;
+ break;
+ default:
+ state = UNSTRUCTURED_START;
+ break;
+ }
+ break;
+ case UNSTRUCTURED_CR:
+ if (cur_token >= length)
+ return MAILIMF_ERROR_PARSE;
+
+ switch(message[cur_token]) {
+ case '\n':
+ state = UNSTRUCTURED_LF;
+ break;
+ case ':':
+ has_field = TRUE;
+ state = UNSTRUCTURED_START;
+ break;
+ default:
+ state = UNSTRUCTURED_START;
+ break;
+ }
+ break;
+ case UNSTRUCTURED_LF:
+ if (cur_token >= length) {
+ terminal = cur_token;
+ state = UNSTRUCTURED_OUT;
+ break;
+ }
+
+ switch(message[cur_token]) {
+ case '\t':
+ case ' ':
+ state = UNSTRUCTURED_WSP;
+ break;
+ default:
+ terminal = cur_token;
+ state = UNSTRUCTURED_OUT;
+ break;
+ }
+ break;
+ case UNSTRUCTURED_WSP:
+ if (cur_token >= length)
+ return MAILIMF_ERROR_PARSE;
+
+ switch(message[cur_token]) {
+ case '\r':
+ state = UNSTRUCTURED_CR;
+ break;
+ case '\n':
+ state = UNSTRUCTURED_LF;
+ break;
+ case ':':
+ has_field = TRUE;
+ state = UNSTRUCTURED_START;
+ break;
+ default:
+ state = UNSTRUCTURED_START;
+ break;
+ }
+ break;
+ }
+
+ cur_token ++;
+ }
+
+ if (!has_field)
+ return MAILIMF_ERROR_PARSE;
+
+ * index = terminal;
+
+ return MAILIMF_NO_ERROR;
+}
+
+
+/*
+date-time = [ day-of-week "," ] date FWS time [CFWS]
+*/
+
+int mailimf_date_time_parse(const char * message, size_t length,
+ size_t * index,
+ struct mailimf_date_time ** result)
+{
+ size_t cur_token;
+ int day_of_week;
+ struct mailimf_date_time * date_time;
+ int day;
+ int month;
+ int year;
+ int hour;
+ int min;
+ int sec;
+ int zone;
+ int r;
+
+ cur_token = * index;
+
+ day_of_week = -1;
+ r = mailimf_day_of_week_parse(message, length, &cur_token, &day_of_week);
+ if (r == MAILIMF_NO_ERROR) {
+ r = mailimf_comma_parse(message, length, &cur_token);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ }
+ else if (r != MAILIMF_ERROR_PARSE)
+ return r;
+
+ r = mailimf_date_parse(message, length, &cur_token, &day, &month, &year);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_fws_parse(message, length, &cur_token);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_time_parse(message, length, &cur_token,
+ &hour, &min, &sec, &zone);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ date_time = mailimf_date_time_new(day, month, year, hour, min, sec, zone);
+ if (date_time == NULL)
+ return MAILIMF_ERROR_MEMORY;
+
+ * index = cur_token;
+ * result = date_time;
+
+ return MAILIMF_NO_ERROR;
+}
+
+/*
+day-of-week = ([FWS] day-name) / obs-day-of-week
+*/
+
+static int mailimf_day_of_week_parse(const char * message, size_t length,
+ size_t * index, int * result)
+{
+ size_t cur_token;
+ int day_of_week;
+ int r;
+
+ cur_token = * index;
+
+ r = mailimf_cfws_parse(message, length, &cur_token);
+ if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE))
+ return r;
+
+ r = mailimf_day_name_parse(message, length, &cur_token, &day_of_week);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ * index = cur_token;
+ * result = day_of_week;
+
+ return MAILIMF_NO_ERROR;
+}
+
+/*
+day-name = "Mon" / "Tue" / "Wed" / "Thu" /
+ "Fri" / "Sat" / "Sun"
+*/
+
+struct mailimf_token_value {
+ int value;
+ char * str;
+};
+
+static struct mailimf_token_value day_names[] = {
+ {1, "Mon"},
+ {2, "Tue"},
+ {3, "Wed"},
+ {4, "Thu"},
+ {5, "Fri"},
+ {6, "Sat"},
+ {7, "Sun"},
+};
+
+enum {
+ DAY_NAME_START,
+ DAY_NAME_T,
+ DAY_NAME_S
+};
+
+static int guess_day_name(const char * message, size_t length, size_t index)
+{
+ int state;
+
+ state = DAY_NAME_START;
+
+ while (1) {
+
+ if (index >= length)
+ return -1;
+
+ switch(state) {
+ case DAY_NAME_START:
+ switch((char) toupper((unsigned char) message[index])) {
+ case 'M': /* Mon */
+ return 1;
+ break;
+ case 'T': /* Tue Thu */
+ state = DAY_NAME_T;
+ break;
+ case 'W': /* Wed */
+ return 3;
+ case 'F':
+ return 5;
+ case 'S': /* Sat Sun */
+ state = DAY_NAME_S;
+ break;
+ default:
+ return -1;
+ }
+ break;
+ case DAY_NAME_T:
+ switch((char) toupper((unsigned char) message[index])) {
+ case 'U':
+ return 2;
+ case 'H':
+ return 4;
+ default:
+ return -1;
+ }
+ break;
+ case DAY_NAME_S:
+ switch((char) toupper((unsigned char) message[index])) {
+ case 'A':
+ return 6;
+ case 'U':
+ return 7;
+ default:
+ return -1;
+ }
+ break;
+ }
+
+ index ++;
+ }
+}
+
+static int mailimf_day_name_parse(const char * message, size_t length,
+ size_t * index, int * result)
+{
+ size_t cur_token;
+ int day_of_week;
+ int guessed_day;
+ int r;
+
+ cur_token = * index;
+
+ guessed_day = guess_day_name(message, length, cur_token);
+ if (guessed_day == -1)
+ return MAILIMF_ERROR_PARSE;
+
+ r = mailimf_token_case_insensitive_parse(message, length,
+ &cur_token,
+ day_names[guessed_day - 1].str);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ day_of_week = guessed_day;
+
+ * result = day_of_week;
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+}
+
+/*
+date = day month year
+*/
+
+static int mailimf_date_parse(const char * message, size_t length,
+ size_t * index,
+ int * pday, int * pmonth, int * pyear)
+{
+ size_t cur_token;
+ int day;
+ int month;
+ int year;
+ int r;
+
+ cur_token = * index;
+
+ r = mailimf_day_parse(message, length, &cur_token, &day);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_month_parse(message, length, &cur_token, &month);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_year_parse(message, length, &cur_token, &year);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ * pday = day;
+ * pmonth = month;
+ * pyear = year;
+
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+}
+
+/*
+year = 4*DIGIT / obs-year
+*/
+
+static int mailimf_year_parse(const char * message, size_t length,
+ size_t * index, int * result)
+{
+ uint32_t number;
+ size_t cur_token;
+ int r;
+
+ cur_token = * index;
+
+ r = mailimf_cfws_parse(message, length, &cur_token);
+ if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE))
+ return r;
+
+ r = mailimf_number_parse(message, length, &cur_token, &number);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ * index = cur_token;
+ * result = number;
+
+ return MAILIMF_NO_ERROR;
+}
+
+/*
+month = (FWS month-name FWS) / obs-month
+*/
+
+static int mailimf_month_parse(const char * message, size_t length,
+ size_t * index, int * result)
+{
+ size_t cur_token;
+ int month;
+ int r;
+
+ cur_token = * index;
+
+ r = mailimf_cfws_parse(message, length, &cur_token);
+ if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE))
+ return r;
+
+ r = mailimf_month_name_parse(message, length, &cur_token, &month);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ * result = month;
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+}
+
+/*
+month-name = "Jan" / "Feb" / "Mar" / "Apr" /
+ "May" / "Jun" / "Jul" / "Aug" /
+ "Sep" / "Oct" / "Nov" / "Dec"
+*/
+
+static struct mailimf_token_value month_names[] = {
+ {1, "Jan"},
+ {2, "Feb"},
+ {3, "Mar"},
+ {4, "Apr"},
+ {5, "May"},
+ {6, "Jun"},
+ {7, "Jul"},
+ {8, "Aug"},
+ {9, "Sep"},
+ {10, "Oct"},
+ {11, "Nov"},
+ {12, "Dec"},
+};
+
+enum {
+ MONTH_START,
+ MONTH_J,
+ MONTH_JU,
+ MONTH_M,
+ MONTH_MA,
+ MONTH_A
+};
+
+static int guess_month(const char * message, size_t length, size_t index)
+{
+ int state;
+
+ state = MONTH_START;
+
+ while (1) {
+
+ if (index >= length)
+ return -1;
+
+ switch(state) {
+ case MONTH_START:
+ switch((char) toupper((unsigned char) message[index])) {
+ case 'J': /* Jan Jun Jul */
+ state = MONTH_J;
+ break;
+ case 'F': /* Feb */
+ return 2;
+ case 'M': /* Mar May */
+ state = MONTH_M;
+ break;
+ case 'A': /* Apr Aug */
+ state = MONTH_A;
+ break;
+ case 'S': /* Sep */
+ return 9;
+ case 'O': /* Oct */
+ return 10;
+ case 'N': /* Nov */
+ return 11;
+ case 'D': /* Dec */
+ return 12;
+ default:
+ return -1;
+ }
+ break;
+ case MONTH_J:
+ switch((char) toupper((unsigned char) message[index])) {
+ case 'A':
+ return 1;
+ case 'U':
+ state = MONTH_JU;
+ break;
+ default:
+ return -1;
+ }
+ break;
+ case MONTH_JU:
+ switch((char) toupper((unsigned char) message[index])) {
+ case 'N':
+ return 6;
+ case 'L':
+ return 7;
+ default:
+ return -1;
+ }
+ break;
+ case MONTH_M:
+ switch((char) toupper((unsigned char) message[index])) {
+ case 'A':
+ state = MONTH_MA;
+ break;
+ default:
+ return -1;
+ }
+ break;
+ case MONTH_MA:
+ switch((char) toupper((unsigned char) message[index])) {
+ case 'Y':
+ return 5;
+ case 'R':
+ return 3;
+ default:
+ return -1;
+ }
+ break;
+ case MONTH_A:
+ switch((char) toupper((unsigned char) message[index])) {
+ case 'P':
+ return 4;
+ case 'U':
+ return 8;
+ default:
+ return -1;
+ }
+ break;
+ }
+
+ index ++;
+ }
+}
+
+static int mailimf_month_name_parse(const char * message, size_t length,
+ size_t * index, int * result)
+{
+ size_t cur_token;
+ int month;
+ int guessed_month;
+ int r;
+
+ cur_token = * index;
+
+ guessed_month = guess_month(message, length, cur_token);
+ if (guessed_month == -1)
+ return MAILIMF_ERROR_PARSE;
+
+ r = mailimf_token_case_insensitive_parse(message, length,
+ &cur_token,
+ month_names[guessed_month - 1].str);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ month = guessed_month;
+
+ * result = month;
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+}
+
+/*
+day = ([FWS] 1*2DIGIT) / obs-day
+*/
+
+static int mailimf_day_parse(const char * message, size_t length,
+ size_t * index, int * result)
+{
+ size_t cur_token;
+ uint32_t day;
+ int r;
+
+ cur_token = * index;
+
+ r = mailimf_cfws_parse(message, length, &cur_token);
+ if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE))
+ return r;
+
+ r = mailimf_number_parse(message, length, &cur_token, &day);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ * result = day;
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+}
+
+/*
+time = time-of-day FWS zone
+*/
+
+static int mailimf_time_parse(const char * message, size_t length,
+ size_t * index,
+ int * phour, int * pmin,
+ int * psec,
+ int * pzone)
+{
+ size_t cur_token;
+ int hour;
+ int min;
+ int sec;
+ int zone;
+ int r;
+
+ cur_token = * index;
+
+ r = mailimf_cfws_parse(message, length, &cur_token);
+ if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE))
+ return r;
+
+ r = mailimf_time_of_day_parse(message, length, &cur_token,
+ &hour, &min, &sec);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_fws_parse(message, length, &cur_token);
+ if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE))
+ return r;
+
+ r = mailimf_zone_parse(message, length, &cur_token, &zone);
+ if (r == MAILIMF_NO_ERROR) {
+ /* do nothing */
+ }
+ else if (r == MAILIMF_ERROR_PARSE) {
+ zone = 0;
+ }
+ else {
+ return r;
+ }
+
+ * phour = hour;
+ * pmin = min;
+ * psec = sec;
+ * pzone = zone;
+
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+}
+
+/*
+time-of-day = hour ":" minute [ ":" second ]
+*/
+
+static int mailimf_time_of_day_parse(const char * message, size_t length,
+ size_t * index,
+ int * phour, int * pmin,
+ int * psec)
+{
+ int hour;
+ int min;
+ int sec;
+ size_t cur_token;
+ int r;
+
+ cur_token = * index;
+
+ r = mailimf_hour_parse(message, length, &cur_token, &hour);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_colon_parse(message, length, &cur_token);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_minute_parse(message, length, &cur_token, &min);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_colon_parse(message, length, &cur_token);
+ if (r == MAILIMF_NO_ERROR) {
+ r = mailimf_second_parse(message, length, &cur_token, &sec);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ }
+ else if (r == MAILIMF_ERROR_PARSE)
+ sec = 0;
+ else
+ return r;
+
+ * phour = hour;
+ * pmin = min;
+ * psec = sec;
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+}
+
+/*
+hour = 2DIGIT / obs-hour
+*/
+
+static int mailimf_hour_parse(const char * message, size_t length,
+ size_t * index, int * result)
+{
+ uint32_t hour;
+ int r;
+
+ r = mailimf_number_parse(message, length, index, &hour);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ * result = hour;
+
+ return MAILIMF_NO_ERROR;
+}
+
+/*
+minute = 2DIGIT / obs-minute
+*/
+
+static int mailimf_minute_parse(const char * message, size_t length,
+ size_t * index, int * result)
+{
+ uint32_t minute;
+ int r;
+
+ r = mailimf_number_parse(message, length, index, &minute);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ * result = minute;
+
+ return MAILIMF_NO_ERROR;
+}
+
+/*
+second = 2DIGIT / obs-second
+*/
+
+static int mailimf_second_parse(const char * message, size_t length,
+ size_t * index, int * result)
+{
+ uint32_t second;
+ int r;
+
+ r = mailimf_number_parse(message, length, index, &second);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ * result = second;
+
+ return MAILIMF_NO_ERROR;
+}
+
+/*
+zone = (( "+" / "-" ) 4DIGIT) / obs-zone
+*/
+
+/*
+obs-zone = "UT" / "GMT" / ; Universal Time
+ ; North American UT
+ ; offsets
+ "EST" / "EDT" / ; Eastern: - 5/ - 4
+ "CST" / "CDT" / ; Central: - 6/ - 5
+ "MST" / "MDT" / ; Mountain: - 7/ - 6
+ "PST" / "PDT" / ; Pacific: - 8/ - 7
+
+ %d65-73 / ; Military zones - "A"
+ %d75-90 / ; through "I" and "K"
+ %d97-105 / ; through "Z", both
+ %d107-122 ; upper and lower case
+*/
+
+enum {
+ STATE_ZONE_1 = 0,
+ STATE_ZONE_2 = 1,
+ STATE_ZONE_3 = 2,
+ STATE_ZONE_OK = 3,
+ STATE_ZONE_ERR = 4,
+ STATE_ZONE_CONT = 5,
+};
+
+static int mailimf_zone_parse(const char * message, size_t length,
+ size_t * index, int * result)
+{
+ uint32_t zone;
+ int sign;
+ size_t cur_token;
+ int r;
+
+ cur_token = * index;
+
+ if (cur_token + 1 < length) {
+ if ((message[cur_token] == 'U') && (message[cur_token] == 'T')) {
+ * result = TRUE;
+ * index = cur_token + 2;
+
+ return MAILIMF_NO_ERROR;
+ }
+ }
+
+ if (cur_token + 2 < length) {
+ int state;
+
+ state = STATE_ZONE_1;
+
+ while (state <= 2) {
+ switch (state) {
+ case STATE_ZONE_1:
+ switch (message[cur_token]) {
+ case 'G':
+ if (message[cur_token + 1] == 'M' && message[cur_token + 2] == 'T') {
+ zone = 0;
+ state = STATE_ZONE_OK;
+ }
+ else {
+ state = STATE_ZONE_ERR;
+ }
+ break;
+ case 'E':
+ zone = -5;
+ state = STATE_ZONE_2;
+ break;
+ case 'C':
+ zone = -6;
+ state = STATE_ZONE_2;
+ break;
+ case 'M':
+ zone = -7;
+ state = STATE_ZONE_2;
+ break;
+ case 'P':
+ zone = -8;
+ state = STATE_ZONE_2;
+ break;
+ default:
+ state = STATE_ZONE_CONT;
+ break;
+ }
+ break;
+ case STATE_ZONE_2:
+ switch (message[cur_token + 1]) {
+ case 'S':
+ state = STATE_ZONE_3;
+ break;
+ case 'D':
+ zone ++;
+ state = STATE_ZONE_3;
+ break;
+ default:
+ state = STATE_ZONE_ERR;
+ break;
+ }
+ break;
+ case STATE_ZONE_3:
+ if (message[cur_token + 2] == 'T') {
+ zone *= 100;
+ state = STATE_ZONE_OK;
+ }
+ else
+ state = STATE_ZONE_ERR;
+ break;
+ }
+ }
+
+ switch (state) {
+ case STATE_ZONE_OK:
+ * result = zone;
+ * index = cur_token + 3;
+ return MAILIMF_NO_ERROR;
+
+ case STATE_ZONE_ERR:
+ return MAILIMF_ERROR_PARSE;
+ }
+ }
+
+ sign = 1;
+ r = mailimf_plus_parse(message, length, &cur_token);
+ if (r == MAILIMF_NO_ERROR)
+ sign = 1;
+
+ if (r == MAILIMF_ERROR_PARSE) {
+ r = mailimf_minus_parse(message, length, &cur_token);
+ if (r == MAILIMF_NO_ERROR)
+ sign = -1;
+ }
+
+ if (r == MAILIMF_NO_ERROR) {
+ /* do nothing */
+ }
+ else if (r == MAILIMF_ERROR_PARSE)
+ sign = 1;
+ else
+ return r;
+
+ r = mailimf_number_parse(message, length, &cur_token, &zone);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ zone = zone * sign;
+
+ * index = cur_token;
+ * result = zone;
+
+ return MAILIMF_NO_ERROR;
+}
+
+/*
+address = mailbox / group
+*/
+
+int mailimf_address_parse(const char * message, size_t length,
+ size_t * index,
+ struct mailimf_address ** result)
+{
+ int type;
+ size_t cur_token;
+ struct mailimf_mailbox * mailbox;
+ struct mailimf_group * group;
+ struct mailimf_address * address;
+ int r;
+ int res;
+
+ cur_token = * index;
+
+ mailbox = NULL;
+ group = NULL;
+
+ type = MAILIMF_ADDRESS_ERROR; /* XXX - removes a gcc warning */
+ r = mailimf_group_parse(message, length, &cur_token, &group);
+ if (r == MAILIMF_NO_ERROR)
+ type = MAILIMF_ADDRESS_GROUP;
+
+ if (r == MAILIMF_ERROR_PARSE) {
+ r = mailimf_mailbox_parse(message, length, &cur_token, &mailbox);
+ if (r == MAILIMF_NO_ERROR)
+ type = MAILIMF_ADDRESS_MAILBOX;
+ }
+
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ address = mailimf_address_new(type, mailbox, group);
+ if (address == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free;
+ }
+
+ * result = address;
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+
+ free:
+ if (mailbox != NULL)
+ mailimf_mailbox_free(mailbox);
+ if (group != NULL)
+ mailimf_group_free(group);
+ err:
+ return res;
+}
+
+
+/*
+mailbox = name-addr / addr-spec
+*/
+
+
+int mailimf_mailbox_parse(const char * message, size_t length,
+ size_t * index,
+ struct mailimf_mailbox ** result)
+{
+ size_t cur_token;
+ char * display_name;
+ struct mailimf_mailbox * mailbox;
+ char * addr_spec;
+ int r;
+ int res;
+
+ cur_token = * index;
+ display_name = NULL;
+ addr_spec = NULL;
+
+ r = mailimf_name_addr_parse(message, length, &cur_token,
+ &display_name, &addr_spec);
+ if (r == MAILIMF_ERROR_PARSE)
+ r = mailimf_addr_spec_parse(message, length, &cur_token, &addr_spec);
+
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ mailbox = mailimf_mailbox_new(display_name, addr_spec);
+ if (mailbox == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free;
+ }
+
+ * result = mailbox;
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+
+ free:
+ if (display_name != NULL)
+ mailimf_display_name_free(display_name);
+ if (addr_spec != NULL)
+ mailimf_addr_spec_free(addr_spec);
+ err:
+ return res;
+}
+
+/*
+name-addr = [display-name] angle-addr
+*/
+
+static int mailimf_name_addr_parse(const char * message, size_t length,
+ size_t * index,
+ char ** pdisplay_name,
+ char ** pangle_addr)
+{
+ char * display_name;
+ char * angle_addr;
+ size_t cur_token;
+ int r;
+ int res;
+
+ cur_token = * index;
+
+ display_name = NULL;
+ angle_addr = NULL;
+
+ r = mailimf_display_name_parse(message, length, &cur_token, &display_name);
+ if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
+ res = r;
+ goto err;
+ }
+
+ r = mailimf_angle_addr_parse(message, length, &cur_token, &angle_addr);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto free_display_name;
+ }
+
+ * pdisplay_name = display_name;
+ * pangle_addr = angle_addr;
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+
+ free_display_name:
+ if (display_name != NULL)
+ mailimf_display_name_free(display_name);
+ err:
+ return res;
+}
+
+/*
+angle-addr = [CFWS] "<" addr-spec ">" [CFWS] / obs-angle-addr
+*/
+
+static int mailimf_angle_addr_parse(const char * message, size_t length,
+ size_t * index, char ** result)
+{
+ size_t cur_token;
+ char * addr_spec;
+ int r;
+
+ cur_token = * index;
+
+ r = mailimf_cfws_parse(message, length, &cur_token);
+ if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE))
+ return r;
+
+ r = mailimf_lower_parse(message, length, &cur_token);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_addr_spec_parse(message, length, &cur_token, &addr_spec);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_greater_parse(message, length, &cur_token);
+ if (r != MAILIMF_NO_ERROR) {
+ free(addr_spec);
+ return r;
+ }
+
+ * result = addr_spec;
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+}
+
+/*
+group = display-name ":" [mailbox-list / CFWS] ";"
+ [CFWS]
+*/
+
+static int mailimf_group_parse(const char * message, size_t length,
+ size_t * index,
+ struct mailimf_group ** result)
+{
+ size_t cur_token;
+ char * display_name;
+ struct mailimf_mailbox_list * mailbox_list;
+ struct mailimf_group * group;
+ int r;
+ int res;
+
+ cur_token = * index;
+
+ mailbox_list = NULL;
+
+ r = mailimf_display_name_parse(message, length, &cur_token, &display_name);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ r = mailimf_colon_parse(message, length, &cur_token);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto free_display_name;
+ }
+
+ r = mailimf_mailbox_list_parse(message, length, &cur_token, &mailbox_list);
+ switch (r) {
+ case MAILIMF_NO_ERROR:
+ break;
+ case MAILIMF_ERROR_PARSE:
+ r = mailimf_cfws_parse(message, length, &cur_token);
+ if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE))
+ return r;
+ break;
+ default:
+ return r;
+ }
+
+ r = mailimf_semi_colon_parse(message, length, &cur_token);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto free_mailbox_list;
+ }
+
+ group = mailimf_group_new(display_name, mailbox_list);
+ if (group == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free_mailbox_list;
+ }
+
+ * index = cur_token;
+ * result = group;
+
+ return MAILIMF_NO_ERROR;
+
+ free_mailbox_list:
+ mailimf_mailbox_list_free(mailbox_list);
+ free_display_name:
+ mailimf_display_name_free(display_name);
+ err:
+ return res;
+}
+
+/*
+display-name = phrase
+*/
+
+static int mailimf_display_name_parse(const char * message, size_t length,
+ size_t * index, char ** result)
+{
+ return mailimf_phrase_parse(message, length, index, result);
+}
+
+/*
+mailbox-list = (mailbox *("," mailbox)) / obs-mbox-list
+*/
+
+int
+mailimf_mailbox_list_parse(const char * message, size_t length,
+ size_t * index,
+ struct mailimf_mailbox_list ** result)
+{
+ size_t cur_token;
+ clist * list;
+ struct mailimf_mailbox_list * mailbox_list;
+ int r;
+ int res;
+
+ cur_token = * index;
+
+ r = mailimf_struct_list_parse(message, length,
+ &cur_token, &list, ',',
+ (mailimf_struct_parser *)
+ mailimf_mailbox_parse,
+ (mailimf_struct_destructor *)
+ mailimf_mailbox_free);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ mailbox_list = mailimf_mailbox_list_new(list);
+ if (mailbox_list == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free_list;
+ }
+
+ * result = mailbox_list;
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+
+ free_list:
+ clist_foreach(list, (clist_func) mailimf_mailbox_free, NULL);
+ clist_free(list);
+ err:
+ return res;
+}
+
+/*
+address-list = (address *("," address)) / obs-addr-list
+*/
+
+
+int
+mailimf_address_list_parse(const char * message, size_t length,
+ size_t * index,
+ struct mailimf_address_list ** result)
+{
+ size_t cur_token;
+ clist * list;
+ struct mailimf_address_list * address_list;
+ int r;
+ int res;
+
+ cur_token = * index;
+
+ r = mailimf_struct_list_parse(message, length,
+ &cur_token, &list, ',',
+ (mailimf_struct_parser *)
+ mailimf_address_parse,
+ (mailimf_struct_destructor *)
+ mailimf_address_free);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ address_list = mailimf_address_list_new(list);
+ if (address_list == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free_list;
+ }
+
+ * result = address_list;
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+
+ free_list:
+ clist_foreach(list, (clist_func) mailimf_address_free, NULL);
+ clist_free(list);
+ err:
+ return res;
+}
+
+/*
+addr-spec = local-part "@" domain
+*/
+
+
+static int mailimf_addr_spec_parse(const char * message, size_t length,
+ size_t * index,
+ char ** result)
+{
+ size_t cur_token;
+#if 0
+ char * local_part;
+ char * domain;
+#endif
+ char * addr_spec;
+ int r;
+ int res;
+ size_t begin;
+ size_t end;
+ int final;
+ size_t count;
+ const char * src;
+ char * dest;
+ size_t i;
+
+ cur_token = * index;
+
+ r = mailimf_cfws_parse(message, length, &cur_token);
+ if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
+ res = r;
+ goto err;
+ }
+
+ end = cur_token;
+ if (end >= length) {
+ res = MAILIMF_ERROR_PARSE;
+ goto err;
+ }
+
+ begin = cur_token;
+
+ final = FALSE;
+ while (1) {
+ switch (message[end]) {
+ case '>':
+ case ',':
+ case '\r':
+ case '\n':
+ case '(':
+ case ')':
+ case ':':
+ case ';':
+ final = TRUE;
+ break;
+ }
+
+ if (final)
+ break;
+
+ end ++;
+ if (end >= length)
+ break;
+ }
+
+ if (end == begin) {
+ res = MAILIMF_ERROR_PARSE;
+ goto err;
+ }
+
+ addr_spec = malloc(end - cur_token + 1);
+ if (addr_spec == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto err;
+ }
+
+ count = end - cur_token;
+ src = message + cur_token;
+ dest = addr_spec;
+ for(i = 0 ; i < count ; i ++) {
+ if ((* src != ' ') && (* src != '\t')) {
+ * dest = * src;
+ dest ++;
+ }
+ src ++;
+ }
+ * dest = '\0';
+
+#if 0
+ strncpy(addr_spec, message + cur_token, end - cur_token);
+ addr_spec[end - cur_token] = '\0';
+#endif
+
+ cur_token = end;
+
+#if 0
+ r = mailimf_local_part_parse(message, length, &cur_token, &local_part);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ r = mailimf_at_sign_parse(message, length, &cur_token);
+ switch (r) {
+ case MAILIMF_NO_ERROR:
+ r = mailimf_domain_parse(message, length, &cur_token, &domain);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto free_local_part;
+ }
+ break;
+
+ case MAILIMF_ERROR_PARSE:
+ domain = NULL;
+ break;
+
+ default:
+ res = r;
+ goto free_local_part;
+ }
+
+ if (domain) {
+ addr_spec = malloc(strlen(local_part) + strlen(domain) + 2);
+ if (addr_spec == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free_domain;
+ }
+
+ strcpy(addr_spec, local_part);
+ strcat(addr_spec, "@");
+ strcat(addr_spec, domain);
+
+ mailimf_domain_free(domain);
+ mailimf_local_part_free(local_part);
+ }
+ else {
+ addr_spec = local_part;
+ }
+#endif
+
+ * result = addr_spec;
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+
+#if 0
+ free_domain:
+ mailimf_domain_free(domain);
+ free_local_part:
+ mailimf_local_part_free(local_part);
+#endif
+ err:
+ return res;
+}
+
+/*
+local-part = dot-atom / quoted-string / obs-local-part
+*/
+
+#if 0
+static int mailimf_local_part_parse(const char * message, size_t length,
+ size_t * index,
+ char ** result)
+{
+ int r;
+
+ r = mailimf_dot_atom_parse(message, length, index, result);
+ switch (r) {
+ case MAILIMF_NO_ERROR:
+ return r;
+ case MAILIMF_ERROR_PARSE:
+ break;
+ default:
+ return r;
+ }
+
+ r = mailimf_quoted_string_parse(message, length, index, result);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ return MAILIMF_NO_ERROR;
+}
+#endif
+
+/*
+domain = dot-atom / domain-literal / obs-domain
+*/
+
+#if 0
+static int mailimf_domain_parse(const char * message, size_t length,
+ size_t * index,
+ char ** result)
+{
+ int r;
+
+ r = mailimf_dot_atom_parse(message, length, index, result);
+ switch (r) {
+ case MAILIMF_NO_ERROR:
+ return r;
+ case MAILIMF_ERROR_PARSE:
+ break;
+ default:
+ return r;
+ }
+
+ r = mailimf_domain_literal_parse(message, length, index, result);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ return MAILIMF_NO_ERROR;
+}
+#endif
+
+/*
+[FWS] dcontent
+*/
+
+#if 0
+static int
+mailimf_domain_literal_fws_dcontent_parse(const char * message, size_t length,
+ size_t * index)
+{
+ size_t cur_token;
+ char ch;
+ int r;
+
+ cur_token = * index;
+
+ r = mailimf_cfws_parse(message, length, &cur_token);
+ if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE))
+ return r;
+
+ r = mailimf_dcontent_parse(message, length, &cur_token, &ch);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+}
+#endif
+
+/*
+domain-literal = [CFWS] "[" *([FWS] dcontent) [FWS] "]" [CFWS]
+*/
+
+#if 0
+static int mailimf_domain_literal_parse(const char * message, size_t length,
+ size_t * index, char ** result)
+{
+ size_t cur_token;
+ int len;
+ int begin;
+ char * domain_literal;
+ int r;
+
+ cur_token = * index;
+
+ r = mailimf_cfws_parse(message, length, &cur_token);
+ if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE))
+ return r;
+
+ begin = cur_token;
+ r = mailimf_obracket_parse(message, length, &cur_token);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ while (1) {
+ r = mailimf_domain_literal_fws_dcontent_parse(message, length,
+ &cur_token);
+ if (r == MAILIMF_NO_ERROR) {
+ /* do nothing */
+ }
+ else if (r == MAILIMF_ERROR_PARSE)
+ break;
+ else
+ return r;
+ }
+
+ r = mailimf_fws_parse(message, length, &cur_token);
+ if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE))
+ return r;
+
+ r = mailimf_cbracket_parse(message, length, &cur_token);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ len = cur_token - begin;
+
+ domain_literal = malloc(len + 1);
+ if (domain_literal == NULL)
+ return MAILIMF_ERROR_MEMORY;
+ strncpy(domain_literal, message + begin, len);
+ domain_literal[len] = '\0';
+
+ * result = domain_literal;
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+}
+#endif
+
+/*
+dcontent = dtext / quoted-pair
+*/
+
+#if 0
+static int mailimf_dcontent_parse(const char * message, size_t length,
+ size_t * index, char * result)
+{
+ size_t cur_token;
+ char ch;
+ int r;
+
+ cur_token = * index;
+
+ if (cur_token >= length)
+ return MAILIMF_ERROR_PARSE;
+
+ if (is_dtext(message[cur_token])) {
+ ch = message[cur_token];
+ cur_token ++;
+ }
+ else {
+ r = mailimf_quoted_pair_parse(message, length, &cur_token, &ch);
+
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ }
+
+ * index = cur_token;
+ * result = ch;
+
+ return MAILIMF_NO_ERROR;
+}
+#endif
+
+
+/*
+dtext = NO-WS-CTL / ; Non white space controls
+
+ %d33-90 / ; The rest of the US-ASCII
+ %d94-126 ; characters not including "[",
+ ; "]", or "\"
+*/
+
+static inline int is_dtext(char ch)
+{
+ unsigned char uch = (unsigned char) ch;
+
+ if (is_no_ws_ctl(ch))
+ return TRUE;
+
+ if (uch < 33)
+ return FALSE;
+
+ if ((uch >= 91) && (uch <= 93))
+ return FALSE;
+
+ if (uch == 127)
+ return FALSE;
+
+ return TRUE;
+}
+
+/*
+message = (fields / obs-fields)
+ [CRLF body]
+*/
+
+int mailimf_message_parse(const char * message, size_t length,
+ size_t * index,
+ struct mailimf_message ** result)
+{
+ struct mailimf_fields * fields;
+ struct mailimf_body * body;
+ struct mailimf_message * msg;
+ size_t cur_token;
+ int r;
+ int res;
+
+ cur_token = * index;
+
+ r = mailimf_fields_parse(message, length, &cur_token, &fields);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ r = mailimf_crlf_parse(message, length, &cur_token);
+ if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
+ res = r;
+ goto err;
+ }
+
+ r = mailimf_body_parse(message, length, &cur_token, &body);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto free_fields;
+ }
+
+ msg = mailimf_message_new(fields, body);
+ if (msg == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free_body;
+ }
+
+ * index = cur_token;
+ * result = msg;
+
+ return MAILIMF_NO_ERROR;
+
+ free_body:
+ mailimf_body_free(body);
+ free_fields:
+ mailimf_fields_free(fields);
+ err:
+ return res;
+}
+
+/*
+body = *(*998text CRLF) *998text
+*/
+
+int mailimf_body_parse(const char * message, size_t length,
+ size_t * index,
+ struct mailimf_body ** result)
+{
+ size_t cur_token;
+ struct mailimf_body * body;
+
+ cur_token = * index;
+
+ body = mailimf_body_new(message + cur_token, length - cur_token);
+ if (body == NULL)
+ return MAILIMF_ERROR_MEMORY;
+
+ cur_token = length;
+
+ * result = body;
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+}
+
+/*
+CHANGE TO THE RFC 2822
+
+original :
+
+fields = *(trace
+ *(resent-date /
+ resent-from /
+ resent-sender /
+ resent-to /
+ resent-cc /
+ resent-bcc /
+ resent-msg-id))
+ *(orig-date /
+ from /
+ sender /
+ reply-to /
+ to /
+ cc /
+ bcc /
+ message-id /
+ in-reply-to /
+ references /
+ subject /
+ comments /
+ keywords /
+ optional-field)
+
+INTO THE FOLLOWING :
+*/
+
+/*
+resent-fields-list = *(resent-date /
+ resent-from /
+ resent-sender /
+ resent-to /
+ resent-cc /
+ resent-bcc /
+ resent-msg-id))
+*/
+
+#if 0
+enum {
+ RESENT_HEADER_START,
+};
+
+static int guess_resent_header_type(char * message,
+ size_t length, size_t index)
+{
+ int r;
+
+ r = mailimf_token_case_insensitive_parse(message,
+ length, &index, "Resent-");
+ if (r != MAILIMF_NO_ERROR)
+ return MAILIMF_RESENT_FIELD_NONE;
+
+ if (index >= length)
+ return MAILIMF_RESENT_FIELD_NONE;
+
+ switch(toupper(message[index])) {
+ case 'D':
+ return MAILIMF_RESENT_FIELD_DATE;
+ case 'F':
+ return MAILIMF_RESENT_FIELD_FROM;
+ case 'S':
+ return MAILIMF_RESENT_FIELD_SENDER;
+ case 'T':
+ return MAILIMF_RESENT_FIELD_TO;
+ case 'C':
+ return MAILIMF_RESENT_FIELD_CC;
+ case 'B':
+ return MAILIMF_RESENT_FIELD_BCC;
+ case 'M':
+ return MAILIMF_RESENT_FIELD_MSG_ID;
+ default:
+ return MAILIMF_RESENT_FIELD_NONE;
+ }
+}
+#endif
+
+#if 0
+static int
+mailimf_resent_field_parse(const char * message, size_t length,
+ size_t * index,
+ struct mailimf_resent_field ** result)
+{
+ struct mailimf_orig_date * resent_date;
+ struct mailimf_from * resent_from;
+ struct mailimf_sender * resent_sender;
+ struct mailimf_to* resent_to;
+ struct mailimf_cc * resent_cc;
+ struct mailimf_bcc * resent_bcc;
+ struct mailimf_message_id * resent_msg_id;
+ size_t cur_token;
+ int type;
+ struct mailimf_resent_field * resent_field;
+ int r;
+ int res;
+
+ cur_token = * index;
+
+ resent_date = NULL;
+ resent_from = NULL;
+ resent_sender = NULL;
+ resent_to = NULL;
+ resent_cc = NULL;
+ resent_bcc = NULL;
+ resent_msg_id = NULL;
+
+ type = guess_resent_header_type(message, length, cur_token);
+
+ switch(type) {
+ case MAILIMF_RESENT_FIELD_DATE:
+ r = mailimf_resent_date_parse(message, length, &cur_token,
+ &resent_date);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+ break;
+ case MAILIMF_RESENT_FIELD_FROM:
+ r = mailimf_resent_from_parse(message, length, &cur_token,
+ &resent_from);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+ break;
+ case MAILIMF_RESENT_FIELD_SENDER:
+ r = mailimf_resent_sender_parse(message, length, &cur_token,
+ &resent_sender);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+ break;
+ case MAILIMF_RESENT_FIELD_TO:
+ r = mailimf_resent_to_parse(message, length, &cur_token,
+ &resent_to);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+ break;
+ case MAILIMF_RESENT_FIELD_CC:
+ r= mailimf_resent_cc_parse(message, length, &cur_token,
+ &resent_cc);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+ break;
+ case MAILIMF_RESENT_FIELD_BCC:
+ r = mailimf_resent_bcc_parse(message, length, &cur_token,
+ &resent_bcc);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+ break;
+ case MAILIMF_RESENT_FIELD_MSG_ID:
+ r = mailimf_resent_msg_id_parse(message, length, &cur_token,
+ &resent_msg_id);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+ break;
+ default:
+ res = MAILIMF_ERROR_PARSE;
+ goto err;
+ }
+
+ resent_field = mailimf_resent_field_new(type, resent_date,
+ resent_from, resent_sender,
+ resent_to, resent_cc,
+ resent_bcc, resent_msg_id);
+ if (resent_field == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free_resent;
+ }
+
+ * result = resent_field;
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+
+ free_resent:
+ if (resent_msg_id != NULL)
+ mailimf_message_id_free(resent_msg_id);
+ if (resent_bcc != NULL)
+ mailimf_bcc_free(resent_bcc);
+ if (resent_cc != NULL)
+ mailimf_cc_free(resent_cc);
+ if (resent_to != NULL)
+ mailimf_to_free(resent_to);
+ if (resent_sender != NULL)
+ mailimf_sender_free(resent_sender);
+ if (resent_from != NULL)
+ mailimf_from_free(resent_from);
+ if (resent_date != NULL)
+ mailimf_orig_date_free(resent_date);
+ err:
+ return res;
+}
+#endif
+
+#if 0
+static int
+mailimf_resent_fields_list_parse(const char * message, size_t length,
+ size_t * index,
+ struct mailimf_resent_fields_list ** result)
+{
+ clist * list;
+ size_t cur_token;
+ struct mailimf_resent_fields_list * resent_fields_list;
+ int r;
+ int res;
+
+ cur_token = * index;
+ list = NULL;
+
+ r = mailimf_struct_multiple_parse(message, length, &cur_token, &list,
+ (mailimf_struct_parser *)
+ mailimf_resent_field_parse,
+ (mailimf_struct_destructor *)
+ mailimf_resent_field_free);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ resent_fields_list = mailimf_resent_fields_list_new(list);
+ if (resent_fields_list == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free_list;
+ }
+
+ * result = resent_fields_list;
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+
+ free_list:
+ clist_foreach(list, (clist_func) mailimf_resent_field_free, NULL);
+ clist_free(list);
+ err:
+ return res;
+}
+#endif
+
+/*
+ ([trace]
+ [resent-fields-list])
+*/
+
+#if 0
+static int
+mailimf_trace_resent_fields_parse(const char * message, size_t length,
+ size_t * index,
+ struct mailimf_trace_resent_fields ** result)
+{
+ size_t cur_token;
+ struct mailimf_return * return_path;
+ struct mailimf_resent_fields_list * resent_fields;
+ struct mailimf_trace_resent_fields * trace_resent_fields;
+ int res;
+ int r;
+
+ cur_token = * index;
+
+ return_path = NULL;
+ resent_fields = NULL;
+
+ r = mailimf_return_parse(message, length, &cur_token,
+ &return_path);
+ if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
+ res = r;
+ goto err;
+ }
+
+ r = mailimf_resent_fields_list_parse(message, length, &cur_token,
+ &resent_fields);
+ if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
+ res = r;
+ goto err;
+ }
+
+ if ((return_path == NULL) && (resent_fields == NULL)) {
+ res = MAILIMF_ERROR_PARSE;
+ goto err;
+ }
+
+ trace_resent_fields = mailimf_trace_resent_fields_new(return_path,
+ resent_fields);
+ if (trace_resent_fields == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free_resent_fields;
+ }
+
+ * result = trace_resent_fields;
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+
+ free_resent_fields:
+ if (resent_fields != NULL)
+ mailimf_resent_fields_list_free(resent_fields);
+ if (return_path != NULL)
+ mailimf_return_free(return_path);
+ err:
+ return res;
+}
+#endif
+
+/*
+delivering-info = *([trace]
+ [resent-fields-list])
+*/
+
+#if 0
+static int
+mailimf_delivering_info_parse(const char * message, size_t length,
+ size_t * index,
+ struct mailimf_delivering_info ** result)
+{
+ size_t cur_token;
+ clist * list;
+ struct mailimf_delivering_info * delivering_info;
+ int r;
+ int res;
+
+ cur_token = * index;
+
+ r = mailimf_struct_multiple_parse(message, length, &cur_token,
+ &list,
+ (mailimf_struct_parser *)
+ mailimf_trace_resent_fields_parse,
+ (mailimf_struct_destructor *)
+ mailimf_trace_resent_fields_free);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ delivering_info = mailimf_delivering_info_new(list);
+ if (delivering_info == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free_list;
+ }
+
+ * result = delivering_info;
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+
+ free_list:
+ clist_foreach(list, (clist_func) mailimf_trace_resent_fields_free, NULL);
+ clist_free(list);
+ err:
+ return res;
+}
+#endif
+
+/*
+field = delivering-info /
+ orig-date /
+ from /
+ sender /
+ reply-to /
+ to /
+ cc /
+ bcc /
+ message-id /
+ in-reply-to /
+ references /
+ subject /
+ comments /
+ keywords /
+ optional-field
+*/
+
+enum {
+ HEADER_START,
+ HEADER_C,
+ HEADER_R,
+ HEADER_RE,
+ HEADER_S,
+ HEADER_RES,
+};
+
+static int guess_header_type(const char * message, size_t length, size_t index)
+{
+ int state;
+ int r;
+
+ state = HEADER_START;
+
+ while (1) {
+
+ if (index >= length)
+ return MAILIMF_FIELD_NONE;
+
+ switch(state) {
+ case HEADER_START:
+ switch((char) toupper((unsigned char) message[index])) {
+ case 'B':
+ return MAILIMF_FIELD_BCC;
+ case 'C':
+ state = HEADER_C;
+ break;
+ case 'D':
+ return MAILIMF_FIELD_ORIG_DATE;
+ case 'F':
+ return MAILIMF_FIELD_FROM;
+ case 'I':
+ return MAILIMF_FIELD_IN_REPLY_TO;
+ case 'K':
+ return MAILIMF_FIELD_KEYWORDS;
+ case 'M':
+ return MAILIMF_FIELD_MESSAGE_ID;
+ case 'R':
+ state = HEADER_R;
+ break;
+ case 'T':
+ return MAILIMF_FIELD_TO;
+ break;
+ case 'S':
+ state = HEADER_S;
+ break;
+ default:
+ return MAILIMF_FIELD_NONE;
+ }
+ break;
+ case HEADER_C:
+ switch((char) toupper((unsigned char) message[index])) {
+ case 'O':
+ return MAILIMF_FIELD_COMMENTS;
+ case 'C':
+ return MAILIMF_FIELD_CC;
+ default:
+ return MAILIMF_FIELD_NONE;
+ }
+ break;
+ case HEADER_R:
+ switch((char) toupper((unsigned char) message[index])) {
+ case 'E':
+ state = HEADER_RE;
+ break;
+ default:
+ return MAILIMF_FIELD_NONE;
+ }
+ break;
+ case HEADER_RE:
+ switch((char) toupper((unsigned char) message[index])) {
+ case 'F':
+ return MAILIMF_FIELD_REFERENCES;
+ case 'P':
+ return MAILIMF_FIELD_REPLY_TO;
+ case 'S':
+ state = HEADER_RES;
+ break;
+ case 'T':
+ return MAILIMF_FIELD_RETURN_PATH;
+ default:
+ return MAILIMF_FIELD_NONE;
+ }
+ break;
+ case HEADER_S:
+ switch((char) toupper((unsigned char) message[index])) {
+ case 'E':
+ return MAILIMF_FIELD_SENDER;
+ case 'U':
+ return MAILIMF_FIELD_SUBJECT;
+ default:
+ return MAILIMF_FIELD_NONE;
+ }
+ break;
+
+ case HEADER_RES:
+ r = mailimf_token_case_insensitive_parse(message,
+ length, &index, "ent-");
+ if (r != MAILIMF_NO_ERROR)
+ return MAILIMF_FIELD_NONE;
+
+ if (index >= length)
+ return MAILIMF_FIELD_NONE;
+
+ switch((char) toupper((unsigned char) message[index])) {
+ case 'D':
+ return MAILIMF_FIELD_RESENT_DATE;
+ case 'F':
+ return MAILIMF_FIELD_RESENT_FROM;
+ case 'S':
+ return MAILIMF_FIELD_RESENT_SENDER;
+ case 'T':
+ return MAILIMF_FIELD_RESENT_TO;
+ case 'C':
+ return MAILIMF_FIELD_RESENT_CC;
+ case 'B':
+ return MAILIMF_FIELD_RESENT_BCC;
+ case 'M':
+ return MAILIMF_FIELD_RESENT_MSG_ID;
+ default:
+ return MAILIMF_FIELD_NONE;
+ }
+ break;
+ }
+ index ++;
+ }
+}
+
+static int mailimf_field_parse(const char * message, size_t length,
+ size_t * index,
+ struct mailimf_field ** result)
+{
+ size_t cur_token;
+ int type;
+ struct mailimf_return * return_path;
+ struct mailimf_orig_date * resent_date;
+ struct mailimf_from * resent_from;
+ struct mailimf_sender * resent_sender;
+ struct mailimf_to* resent_to;
+ struct mailimf_cc * resent_cc;
+ struct mailimf_bcc * resent_bcc;
+ struct mailimf_message_id * resent_msg_id;
+ struct mailimf_orig_date * orig_date;
+ struct mailimf_from * from;
+ struct mailimf_sender * sender;
+ struct mailimf_reply_to * reply_to;
+ struct mailimf_to * to;
+ struct mailimf_cc * cc;
+ struct mailimf_bcc * bcc;
+ struct mailimf_message_id * message_id;
+ struct mailimf_in_reply_to * in_reply_to;
+ struct mailimf_references * references;
+ struct mailimf_subject * subject;
+ struct mailimf_comments * comments;
+ struct mailimf_keywords * keywords;
+ struct mailimf_optional_field * optional_field;
+ struct mailimf_field * field;
+ int guessed_type;
+ int r;
+ int res;
+
+ cur_token = * index;
+
+ return_path = NULL;
+ resent_date = NULL;
+ resent_from = NULL;
+ resent_sender = NULL;
+ resent_to = NULL;
+ resent_cc = NULL;
+ resent_bcc = NULL;
+ resent_msg_id = NULL;
+ orig_date = NULL;
+ from = NULL;
+ sender = NULL;
+ reply_to = NULL;
+ to = NULL;
+ cc = NULL;
+ bcc = NULL;
+ message_id = NULL;
+ in_reply_to = NULL;
+ references = NULL;
+ subject = NULL;
+ comments = NULL;
+ keywords = NULL;
+ optional_field = NULL;
+
+ guessed_type = guess_header_type(message, length, cur_token);
+ type = MAILIMF_FIELD_NONE;
+
+ switch (guessed_type) {
+ case MAILIMF_FIELD_ORIG_DATE:
+ r = mailimf_orig_date_parse(message, length, &cur_token,
+ &orig_date);
+ if (r == MAILIMF_NO_ERROR)
+ type = MAILIMF_FIELD_ORIG_DATE;
+ else if (r == MAILIMF_ERROR_PARSE) {
+ /* do nothing */
+ }
+ else {
+ res = r;
+ goto err;
+ }
+ break;
+ case MAILIMF_FIELD_FROM:
+ r = mailimf_from_parse(message, length, &cur_token,
+ &from);
+ if (r == MAILIMF_NO_ERROR)
+ type = guessed_type;
+ else if (r == MAILIMF_ERROR_PARSE) {
+ /* do nothing */
+ }
+ else {
+ res = r;
+ goto err;
+ }
+ break;
+ case MAILIMF_FIELD_SENDER:
+ r = mailimf_sender_parse(message, length, &cur_token,
+ &sender);
+ if (r == MAILIMF_NO_ERROR)
+ type = guessed_type;
+ else if (r == MAILIMF_ERROR_PARSE) {
+ /* do nothing */
+ }
+ else {
+ res = r;
+ goto err;
+ }
+ break;
+ case MAILIMF_FIELD_REPLY_TO:
+ r = mailimf_reply_to_parse(message, length, &cur_token,
+ &reply_to);
+ if (r == MAILIMF_NO_ERROR)
+ type = guessed_type;
+ else if (r == MAILIMF_ERROR_PARSE) {
+ /* do nothing */
+ }
+ else {
+ res = r;
+ goto err;
+ }
+ break;
+ case MAILIMF_FIELD_TO:
+ r = mailimf_to_parse(message, length, &cur_token,
+ &to);
+ if (r == MAILIMF_NO_ERROR)
+ type = guessed_type;
+ else if (r == MAILIMF_ERROR_PARSE) {
+ /* do nothing */
+ }
+ else {
+ res = r;
+ goto err;
+ }
+ break;
+ case MAILIMF_FIELD_CC:
+ r = mailimf_cc_parse(message, length, &cur_token,
+ &cc);
+ if (r == MAILIMF_NO_ERROR)
+ type = guessed_type;
+ else if (r == MAILIMF_ERROR_PARSE) {
+ /* do nothing */
+ }
+ else {
+ res = r;
+ goto err;
+ }
+ break;
+ case MAILIMF_FIELD_BCC:
+ r = mailimf_bcc_parse(message, length, &cur_token,
+ &bcc);
+ if (r == MAILIMF_NO_ERROR)
+ type = guessed_type;
+ else if (r == MAILIMF_ERROR_PARSE) {
+ /* do nothing */
+ }
+ else {
+ res = r;
+ goto err;
+ }
+ break;
+ case MAILIMF_FIELD_MESSAGE_ID:
+ r = mailimf_message_id_parse(message, length, &cur_token,
+ &message_id);
+ if (r == MAILIMF_NO_ERROR)
+ type = guessed_type;
+ else if (r == MAILIMF_ERROR_PARSE) {
+ /* do nothing */
+ }
+ else {
+ res = r;
+ goto err;
+ }
+ break;
+ case MAILIMF_FIELD_IN_REPLY_TO:
+ r = mailimf_in_reply_to_parse(message, length, &cur_token,
+ &in_reply_to);
+ if (r == MAILIMF_NO_ERROR)
+ type = guessed_type;
+ else if (r == MAILIMF_ERROR_PARSE) {
+ /* do nothing */
+ }
+ else {
+ res = r;
+ goto err;
+ }
+ break;
+ case MAILIMF_FIELD_REFERENCES:
+ r = mailimf_references_parse(message, length, &cur_token,
+ &references);
+ if (r == MAILIMF_NO_ERROR)
+ type = guessed_type;
+ else if (r == MAILIMF_ERROR_PARSE) {
+ /* do nothing */
+ }
+ else {
+ res = r;
+ goto err;
+ }
+ break;
+ case MAILIMF_FIELD_SUBJECT:
+ r = mailimf_subject_parse(message, length, &cur_token,
+ &subject);
+ if (r == MAILIMF_NO_ERROR)
+ type = guessed_type;
+ else if (r == MAILIMF_ERROR_PARSE) {
+ /* do nothing */
+ }
+ else {
+ res = r;
+ goto err;
+ }
+ break;
+ case MAILIMF_FIELD_COMMENTS:
+ r = mailimf_comments_parse(message, length, &cur_token,
+ &comments);
+ if (r == MAILIMF_NO_ERROR)
+ type = guessed_type;
+ else if (r == MAILIMF_ERROR_PARSE) {
+ /* do nothing */
+ }
+ else {
+ res = r;
+ goto err;
+ }
+ break;
+ case MAILIMF_FIELD_KEYWORDS:
+ r = mailimf_keywords_parse(message, length, &cur_token,
+ &keywords);
+ if (r == MAILIMF_NO_ERROR)
+ type = guessed_type;
+ else if (r == MAILIMF_ERROR_PARSE) {
+ /* do nothing */
+ }
+ else {
+ res = r;
+ goto err;
+ }
+ break;
+ case MAILIMF_FIELD_RETURN_PATH:
+ r = mailimf_return_parse(message, length, &cur_token,
+ &return_path);
+ if (r == MAILIMF_NO_ERROR)
+ type = guessed_type;
+ else if (r == MAILIMF_ERROR_PARSE) {
+ /* do nothing */
+ }
+ else {
+ res = r;
+ goto err;
+ }
+ break;
+ case MAILIMF_FIELD_RESENT_DATE:
+ r = mailimf_resent_date_parse(message, length, &cur_token,
+ &resent_date);
+ if (r == MAILIMF_NO_ERROR)
+ type = guessed_type;
+ else if (r == MAILIMF_ERROR_PARSE) {
+ /* do nothing */
+ }
+ else {
+ res = r;
+ goto err;
+ }
+ break;
+ case MAILIMF_FIELD_RESENT_FROM:
+ r = mailimf_resent_from_parse(message, length, &cur_token,
+ &resent_from);
+ if (r == MAILIMF_NO_ERROR)
+ type = guessed_type;
+ else if (r == MAILIMF_ERROR_PARSE) {
+ /* do nothing */
+ }
+ else {
+ res = r;
+ goto err;
+ }
+ break;
+ case MAILIMF_FIELD_RESENT_SENDER:
+ r = mailimf_resent_sender_parse(message, length, &cur_token,
+ &resent_sender);
+ if (r == MAILIMF_NO_ERROR)
+ type = guessed_type;
+ else if (r == MAILIMF_ERROR_PARSE) {
+ /* do nothing */
+ }
+ else {
+ res = r;
+ goto err;
+ }
+ break;
+ case MAILIMF_FIELD_RESENT_TO:
+ r = mailimf_resent_to_parse(message, length, &cur_token,
+ &resent_to);
+ if (r == MAILIMF_NO_ERROR)
+ type = guessed_type;
+ else if (r == MAILIMF_ERROR_PARSE) {
+ /* do nothing */
+ }
+ else {
+ res = r;
+ goto err;
+ }
+ break;
+ case MAILIMF_FIELD_RESENT_CC:
+ r= mailimf_resent_cc_parse(message, length, &cur_token,
+ &resent_cc);
+ if (r == MAILIMF_NO_ERROR)
+ type = guessed_type;
+ else if (r == MAILIMF_ERROR_PARSE) {
+ /* do nothing */
+ }
+ else {
+ res = r;
+ goto err;
+ }
+ break;
+ case MAILIMF_FIELD_RESENT_BCC:
+ r = mailimf_resent_bcc_parse(message, length, &cur_token,
+ &resent_bcc);
+ if (r == MAILIMF_NO_ERROR)
+ type = guessed_type;
+ else if (r == MAILIMF_ERROR_PARSE) {
+ /* do nothing */
+ }
+ else {
+ res = r;
+ goto err;
+ }
+ break;
+ case MAILIMF_FIELD_RESENT_MSG_ID:
+ r = mailimf_resent_msg_id_parse(message, length, &cur_token,
+ &resent_msg_id);
+ if (r == MAILIMF_NO_ERROR)
+ type = guessed_type;
+ else if (r == MAILIMF_ERROR_PARSE) {
+ /* do nothing */
+ }
+ else {
+ res = r;
+ goto err;
+ }
+ break;
+ }
+
+ if (type == MAILIMF_FIELD_NONE) {
+ r = mailimf_optional_field_parse(message, length, &cur_token,
+ &optional_field);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ type = MAILIMF_FIELD_OPTIONAL_FIELD;
+ }
+
+ field = mailimf_field_new(type, return_path, resent_date,
+ resent_from, resent_sender, resent_to, resent_cc, resent_bcc,
+ resent_msg_id, orig_date, from, sender, reply_to, to,
+ cc, bcc, message_id, in_reply_to, references,
+ subject, comments, keywords, optional_field);
+ if (field == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free_field;
+ }
+
+ * result = field;
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+
+ free_field:
+ if (return_path != NULL)
+ mailimf_return_free(return_path);
+ if (resent_date != NULL)
+ mailimf_orig_date_free(resent_date);
+ if (resent_from != NULL)
+ mailimf_from_free(resent_from);
+ if (resent_sender != NULL)
+ mailimf_sender_free(resent_sender);
+ if (resent_to != NULL)
+ mailimf_to_free(resent_to);
+ if (resent_cc != NULL)
+ mailimf_cc_free(resent_cc);
+ if (resent_bcc != NULL)
+ mailimf_bcc_free(resent_bcc);
+ if (resent_msg_id != NULL)
+ mailimf_message_id_free(resent_msg_id);
+ if (orig_date != NULL)
+ mailimf_orig_date_free(orig_date);
+ if (from != NULL)
+ mailimf_from_free(from);
+ if (sender != NULL)
+ mailimf_sender_free(sender);
+ if (reply_to != NULL)
+ mailimf_reply_to_free(reply_to);
+ if (to != NULL)
+ mailimf_to_free(to);
+ if (cc != NULL)
+ mailimf_cc_free(cc);
+ if (bcc != NULL)
+ mailimf_bcc_free(bcc);
+ if (message_id != NULL)
+ mailimf_message_id_free(message_id);
+ if (in_reply_to != NULL)
+ mailimf_in_reply_to_free(in_reply_to);
+ if (references != NULL)
+ mailimf_references_free(references);
+ if (subject != NULL)
+ mailimf_subject_free(subject);
+ if (comments != NULL)
+ mailimf_comments_free(comments);
+ if (keywords != NULL)
+ mailimf_keywords_free(keywords);
+ if (optional_field != NULL)
+ mailimf_optional_field_free(optional_field);
+ err:
+ return res;
+}
+
+
+/*
+fields = *(delivering-info /
+ orig-date /
+ from /
+ sender /
+ reply-to /
+ to /
+ cc /
+ bcc /
+ message-id /
+ in-reply-to /
+ references /
+ subject /
+ comments /
+ keywords /
+ optional-field)
+*/
+
+#if 0
+int
+mailimf_unparsed_fields_parse(const char * message, size_t length,
+ size_t * index,
+ struct mailimf_unparsed_fields ** result)
+{
+ size_t cur_token;
+ clist * list;
+ struct mailimf_unparsed_fields * fields;
+ int r;
+ int res;
+
+ cur_token = * index;
+
+ list = NULL;
+
+ r = mailimf_struct_multiple_parse(message, length, &cur_token,
+ &list,
+ (mailimf_struct_parser *)
+ mailimf_optional_field_parse,
+ (mailimf_struct_destructor *)
+ mailimf_optional_field_free);
+ /*
+ if ((r = MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
+ res = r;
+ goto err;
+ }
+ */
+
+ switch (r) {
+ case MAILIMF_NO_ERROR:
+ /* do nothing */
+ break;
+
+ case MAILIMF_ERROR_PARSE:
+ list = clist_new();
+ if (list == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto err;
+ }
+ break;
+
+ default:
+ res = r;
+ goto err;
+ }
+
+ fields = mailimf_unparsed_fields_new(list);
+ if (fields == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free;
+ }
+
+ * result = fields;
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+
+ free:
+ if (list != NULL) {
+ clist_foreach(list, (clist_func) mailimf_optional_field_free, NULL);
+ clist_free(list);
+ }
+ err:
+ return res;
+}
+#endif
+
+int mailimf_fields_parse(const char * message, size_t length,
+ size_t * index,
+ struct mailimf_fields ** result)
+{
+ size_t cur_token;
+ clist * list;
+ struct mailimf_fields * fields;
+ int r;
+ int res;
+
+ cur_token = * index;
+
+ list = NULL;
+
+ r = mailimf_struct_multiple_parse(message, length, &cur_token,
+ &list,
+ (mailimf_struct_parser *)
+ mailimf_field_parse,
+ (mailimf_struct_destructor *)
+ mailimf_field_free);
+ /*
+ if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
+ res = r;
+ goto err;
+ }
+ */
+
+ switch (r) {
+ case MAILIMF_NO_ERROR:
+ /* do nothing */
+ break;
+
+ case MAILIMF_ERROR_PARSE:
+ list = clist_new();
+ if (list == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto err;
+ }
+ break;
+
+ default:
+ res = r;
+ goto err;
+ }
+
+ fields = mailimf_fields_new(list);
+ if (fields == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free;
+ }
+
+ * result = fields;
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+
+ free:
+ if (list != NULL) {
+ clist_foreach(list, (clist_func) mailimf_field_free, NULL);
+ clist_free(list);
+ }
+ err:
+ return res;
+}
+
+/*
+orig-date = "Date:" date-time CRLF
+*/
+
+
+static int
+mailimf_orig_date_parse(const char * message, size_t length,
+ size_t * index, struct mailimf_orig_date ** result)
+{
+ struct mailimf_date_time * date_time;
+ struct mailimf_orig_date * orig_date;
+ size_t cur_token;
+ int r;
+ int res;
+
+ cur_token = * index;
+
+ r = mailimf_token_case_insensitive_parse(message, length,
+ &cur_token, "Date:");
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ r = mailimf_date_time_parse(message, length, &cur_token, &date_time);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ r = mailimf_ignore_unstructured_parse(message, length, &cur_token);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto free_date_time;
+ }
+
+ r = mailimf_unstrict_crlf_parse(message, length, &cur_token);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto free_date_time;
+ }
+
+ orig_date = mailimf_orig_date_new(date_time);
+ if (orig_date == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free_date_time;
+ }
+
+ * result = orig_date;
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+
+ free_date_time:
+ mailimf_date_time_free(date_time);
+ err:
+ return res;
+}
+
+/*
+from = "From:" mailbox-list CRLF
+*/
+
+static int
+mailimf_from_parse(const char * message, size_t length,
+ size_t * index, struct mailimf_from ** result)
+{
+ struct mailimf_mailbox_list * mb_list;
+ struct mailimf_from * from;
+ size_t cur_token;
+ int r;
+ int res;
+
+ cur_token = * index;
+
+ r = mailimf_token_case_insensitive_parse(message, length,
+ &cur_token, "From");
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ r = mailimf_colon_parse(message, length, &cur_token);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ r = mailimf_mailbox_list_parse(message, length, &cur_token, &mb_list);
+
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ r = mailimf_unstrict_crlf_parse(message, length, &cur_token);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto free_mb_list;
+ }
+
+ from = mailimf_from_new(mb_list);
+ if (from == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free_mb_list;
+ }
+
+ * result = from;
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+
+ free_mb_list:
+ mailimf_mailbox_list_free(mb_list);
+ err:
+ return res;
+}
+
+/*
+sender = "Sender:" mailbox CRLF
+*/
+
+static int
+mailimf_sender_parse(const char * message, size_t length,
+ size_t * index, struct mailimf_sender ** result)
+{
+ struct mailimf_mailbox * mb;
+ struct mailimf_sender * sender;
+ size_t cur_token;
+ int r;
+ int res;
+
+ cur_token = * index;
+
+ r = mailimf_token_case_insensitive_parse(message, length,
+ &cur_token, "Sender");
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ r = mailimf_colon_parse(message, length, &cur_token);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ r = mailimf_mailbox_parse(message, length, &cur_token, &mb);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ r = mailimf_unstrict_crlf_parse(message, length, &cur_token);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto free_mb;
+ }
+
+ sender = mailimf_sender_new(mb);
+ if (sender == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free_mb;
+ }
+
+ * result = sender;
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+
+ free_mb:
+ mailimf_mailbox_free(mb);
+ err:
+ return res;
+}
+
+/*
+reply-to = "Reply-To:" address-list CRLF
+*/
+
+
+static int
+mailimf_reply_to_parse(const char * message, size_t length,
+ size_t * index, struct mailimf_reply_to ** result)
+{
+ struct mailimf_address_list * addr_list;
+ struct mailimf_reply_to * reply_to;
+ size_t cur_token;
+ int r;
+ int res;
+
+ cur_token = * index;
+
+ r = mailimf_token_case_insensitive_parse(message, length,
+ &cur_token, "Reply-To");
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ r = mailimf_colon_parse(message, length, &cur_token);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ r = mailimf_address_list_parse(message, length, &cur_token, &addr_list);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ r = mailimf_unstrict_crlf_parse(message, length, &cur_token);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto free_addr_list;
+ }
+
+ reply_to = mailimf_reply_to_new(addr_list);
+ if (reply_to == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free_addr_list;
+ }
+
+ * result = reply_to;
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+
+ free_addr_list:
+ mailimf_address_list_free(addr_list);
+ err:
+ return res;
+}
+
+/*
+to = "To:" address-list CRLF
+*/
+
+static int
+mailimf_to_parse(const char * message, size_t length,
+ size_t * index, struct mailimf_to ** result)
+{
+ struct mailimf_address_list * addr_list;
+ struct mailimf_to * to;
+ size_t cur_token;
+ int r;
+ int res;
+
+ cur_token = * index;
+
+ r = mailimf_token_case_insensitive_parse(message, length,
+ &cur_token, "To");
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ r = mailimf_colon_parse(message, length, &cur_token);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ r = mailimf_address_list_parse(message, length, &cur_token, &addr_list);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ r = mailimf_unstrict_crlf_parse(message, length, &cur_token);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto free_addr_list;
+ }
+
+ to = mailimf_to_new(addr_list);
+ if (to == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free_addr_list;
+ }
+
+ * result = to;
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+
+ free_addr_list:
+ mailimf_address_list_free(addr_list);
+ err:
+ return res;
+}
+
+/*
+cc = "Cc:" address-list CRLF
+*/
+
+
+static int
+mailimf_cc_parse(const char * message, size_t length,
+ size_t * index, struct mailimf_cc ** result)
+{
+ struct mailimf_address_list * addr_list;
+ struct mailimf_cc * cc;
+ size_t cur_token;
+ int r;
+ int res;
+
+ cur_token = * index;
+
+ r = mailimf_token_case_insensitive_parse(message, length,
+ &cur_token, "Cc");
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ r = mailimf_colon_parse(message, length, &cur_token);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ r = mailimf_address_list_parse(message, length, &cur_token, &addr_list);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ r = mailimf_unstrict_crlf_parse(message, length, &cur_token);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto free_addr_list;
+ }
+
+ cc = mailimf_cc_new(addr_list);
+ if (cc == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free_addr_list;
+ }
+
+ * result = cc;
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+
+ free_addr_list:
+ mailimf_address_list_free(addr_list);
+ err:
+ return res;
+}
+
+/*
+bcc = "Bcc:" (address-list / [CFWS]) CRLF
+*/
+
+
+static int
+mailimf_bcc_parse(const char * message, size_t length,
+ size_t * index, struct mailimf_bcc ** result)
+{
+ struct mailimf_address_list * addr_list;
+ struct mailimf_bcc * bcc;
+ size_t cur_token;
+ int r;
+ int res;
+
+ cur_token = * index;
+ addr_list = NULL;
+
+ r = mailimf_token_case_insensitive_parse(message, length,
+ &cur_token, "Bcc");
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ r = mailimf_colon_parse(message, length, &cur_token);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ r = mailimf_address_list_parse(message, length, &cur_token, &addr_list);
+ switch (r) {
+ case MAILIMF_NO_ERROR:
+ /* do nothing */
+ break;
+ case MAILIMF_ERROR_PARSE:
+ r = mailimf_cfws_parse(message, length, &cur_token);
+ if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
+ res = r;
+ goto err;
+ }
+ break;
+ default:
+ res = r;
+ goto err;
+ }
+
+ r = mailimf_unstrict_crlf_parse(message, length, &cur_token);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto free_addr_list;
+ }
+
+ bcc = mailimf_bcc_new(addr_list);
+ if (bcc == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free_addr_list;
+ }
+
+ * result = bcc;
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+
+ free_addr_list:
+ mailimf_address_list_free(addr_list);
+ err:
+ return res;
+}
+
+/*
+message-id = "Message-ID:" msg-id CRLF
+*/
+
+static int mailimf_message_id_parse(const char * message, size_t length,
+ size_t * index,
+ struct mailimf_message_id ** result)
+{
+ char * value;
+ size_t cur_token;
+ struct mailimf_message_id * message_id;
+ int r;
+ int res;
+
+ cur_token = * index;
+
+ r = mailimf_token_case_insensitive_parse(message, length,
+ &cur_token, "Message-ID");
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ r = mailimf_colon_parse(message, length, &cur_token);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ r = mailimf_msg_id_parse(message, length, &cur_token, &value);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ r = mailimf_unstrict_crlf_parse(message, length, &cur_token);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto free_value;
+ }
+
+ message_id = mailimf_message_id_new(value);
+ if (message_id == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free_value;
+ }
+
+ * result = message_id;
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+
+ free_value:
+ mailimf_msg_id_free(value);
+ err:
+ return res;
+}
+
+/*
+in-reply-to = "In-Reply-To:" 1*msg-id CRLF
+*/
+
+int mailimf_msg_id_list_parse(const char * message, size_t length,
+ size_t * index, clist ** result)
+{
+ return mailimf_struct_multiple_parse(message, length, index,
+ result,
+ (mailimf_struct_parser *)
+ mailimf_unstrict_msg_id_parse,
+ (mailimf_struct_destructor *)
+ mailimf_msg_id_free);
+}
+
+static int mailimf_in_reply_to_parse(const char * message, size_t length,
+ size_t * index,
+ struct mailimf_in_reply_to ** result)
+{
+ struct mailimf_in_reply_to * in_reply_to;
+ size_t cur_token;
+ clist * msg_id_list;
+ int res;
+ int r;
+
+ cur_token = * index;
+
+ r = mailimf_token_case_insensitive_parse(message, length,
+ &cur_token, "In-Reply-To");
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ r = mailimf_colon_parse(message, length, &cur_token);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ r = mailimf_msg_id_list_parse(message, length, &cur_token, &msg_id_list);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ r = mailimf_unstrict_crlf_parse(message, length, &cur_token);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto free_list;
+ }
+
+ in_reply_to = mailimf_in_reply_to_new(msg_id_list);
+ if (in_reply_to == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free_list;
+ }
+
+ * result = in_reply_to;
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+
+ free_list:
+ clist_foreach(msg_id_list, (clist_func) mailimf_msg_id_free, NULL);
+ clist_free(msg_id_list);
+ err:
+ return res;
+}
+
+/*
+references = "References:" 1*msg-id CRLF
+*/
+
+int mailimf_references_parse(const char * message, size_t length,
+ size_t * index,
+ struct mailimf_references ** result)
+{
+ struct mailimf_references * references;
+ size_t cur_token;
+ clist * msg_id_list;
+ int r;
+ int res;
+
+ cur_token = * index;
+
+ r = mailimf_token_case_insensitive_parse(message, length,
+ &cur_token, "References");
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ r = mailimf_colon_parse(message, length, &cur_token);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ r = mailimf_msg_id_list_parse(message, length, &cur_token, &msg_id_list);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ r = mailimf_unstrict_crlf_parse(message, length, &cur_token);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto free_list;
+ }
+
+ references = mailimf_references_new(msg_id_list);
+ if (references == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free_list;
+ }
+
+ * result = references;
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+
+ free_list:
+ clist_foreach(msg_id_list, (clist_func) mailimf_msg_id_free, NULL);
+ clist_free(msg_id_list);
+ err:
+ return res;
+}
+
+/*
+msg-id = [CFWS] "<" id-left "@" id-right ">" [CFWS]
+*/
+
+int mailimf_msg_id_parse(const char * message, size_t length,
+ size_t * index,
+ char ** result)
+{
+ size_t cur_token;
+#if 0
+ char * id_left;
+ char * id_right;
+#endif
+ char * msg_id;
+ int r;
+ int res;
+
+ cur_token = * index;
+
+ r = mailimf_cfws_parse(message, length, &cur_token);
+ if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE))
+ return r;
+
+ r = mailimf_lower_parse(message, length, &cur_token);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ r = mailimf_addr_spec_parse(message, length, &cur_token, &msg_id);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ r = mailimf_greater_parse(message, length, &cur_token);
+ if (r != MAILIMF_NO_ERROR) {
+ free(msg_id);
+ res = r;
+ goto err;
+ }
+
+#if 0
+ r = mailimf_id_left_parse(message, length, &cur_token, &id_left);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ r = mailimf_at_sign_parse(message, length, &cur_token);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto free_id_left;
+ }
+
+ r = mailimf_id_right_parse(message, length, &cur_token, &id_right);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto free_id_left;
+ }
+
+ r = mailimf_greater_parse(message, length, &cur_token);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto free_id_right;
+ }
+
+ msg_id = malloc(strlen(id_left) + strlen(id_right) + 2);
+ if (msg_id == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free_id_right;
+ }
+ strcpy(msg_id, id_left);
+ strcat(msg_id, "@");
+ strcat(msg_id, id_right);
+
+ mailimf_id_left_free(id_left);
+ mailimf_id_right_free(id_right);
+#endif
+
+ * result = msg_id;
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+
+#if 0
+ free_id_right:
+ mailimf_id_right_free(id_right);
+ free_id_left:
+ mailimf_id_left_free(id_left);
+#endif
+ /*
+ free:
+ mailimf_atom_free(msg_id);
+ */
+ err:
+ return res;
+}
+
+static int mailimf_parse_unwanted_msg_id(const char * message, size_t length,
+ size_t * index)
+{
+ size_t cur_token;
+ int r;
+ char * word;
+ int token_parsed;
+
+ cur_token = * index;
+
+ token_parsed = TRUE;
+ while (token_parsed) {
+ token_parsed = FALSE;
+ r = mailimf_word_parse(message, length, &cur_token, &word);
+ if (r == MAILIMF_NO_ERROR) {
+ mailimf_word_free(word);
+ token_parsed = TRUE;
+ }
+ else if (r == MAILIMF_ERROR_PARSE) {
+ /* do nothing */
+ }
+ else
+ return r;
+ r = mailimf_semi_colon_parse(message, length, &cur_token);
+ if (r == MAILIMF_NO_ERROR)
+ token_parsed = TRUE;
+ else if (r == MAILIMF_ERROR_PARSE) {
+ /* do nothing */
+ }
+ else
+ return r;
+ r = mailimf_comma_parse(message, length, &cur_token);
+ if (r == MAILIMF_NO_ERROR)
+ token_parsed = TRUE;
+ else if (r == MAILIMF_ERROR_PARSE) {
+ /* do nothing */
+ }
+ else
+ return r;
+ r = mailimf_plus_parse(message, length, &cur_token);
+ if (r == MAILIMF_NO_ERROR)
+ token_parsed = TRUE;
+ else if (r == MAILIMF_ERROR_PARSE) {
+ /* do nothing */
+ }
+ else
+ return r;
+ r = mailimf_colon_parse(message, length, &cur_token);
+ if (r == MAILIMF_NO_ERROR)
+ token_parsed = TRUE;
+ else if (r == MAILIMF_ERROR_PARSE) {
+ /* do nothing */
+ }
+ else
+ return r;
+ r = mailimf_point_parse(message, length, &cur_token);
+ if (r == MAILIMF_NO_ERROR)
+ token_parsed = TRUE;
+ else if (r == MAILIMF_ERROR_PARSE) {
+ /* do nothing */
+ }
+ else
+ return r;
+ r = mailimf_at_sign_parse(message, length, &cur_token);
+ if (r == MAILIMF_NO_ERROR)
+ token_parsed = TRUE;
+ else if (r == MAILIMF_ERROR_PARSE) {
+ /* do nothing */
+ }
+ else
+ return r;
+ }
+
+ return MAILIMF_NO_ERROR;
+}
+
+static int mailimf_unstrict_msg_id_parse(const char * message, size_t length,
+ size_t * index,
+ char ** result)
+{
+ char * msgid;
+ size_t cur_token;
+ int r;
+
+ cur_token = * index;
+
+ r = mailimf_cfws_parse(message, length, &cur_token);
+ if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE))
+ return r;
+
+ r = mailimf_parse_unwanted_msg_id(message, length, &cur_token);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_msg_id_parse(message, length, &cur_token, &msgid);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_parse_unwanted_msg_id(message, length, &cur_token);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ * result = msgid;
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+}
+
+/*
+id-left = dot-atom-text / no-fold-quote / obs-id-left
+*/
+
+#if 0
+static int mailimf_id_left_parse(const char * message, size_t length,
+ size_t * index, char ** result)
+{
+ int r;
+
+ r = mailimf_dot_atom_text_parse(message, length, index, result);
+ switch (r) {
+ case MAILIMF_NO_ERROR:
+ return MAILIMF_NO_ERROR;
+ case MAILIMF_ERROR_PARSE:
+ break;
+ default:
+ return r;
+ }
+
+ r = mailimf_no_fold_quote_parse(message, length, index, result);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ return MAILIMF_NO_ERROR;
+}
+#endif
+
+/*
+id-right = dot-atom-text / no-fold-literal / obs-id-right
+*/
+
+#if 0
+static int mailimf_id_right_parse(const char * message, size_t length,
+ size_t * index, char ** result)
+{
+ int r;
+
+ r = mailimf_dot_atom_text_parse(message, length, index, result);
+ switch (r) {
+ case MAILIMF_NO_ERROR:
+ return MAILIMF_NO_ERROR;
+ case MAILIMF_ERROR_PARSE:
+ break;
+ default:
+ return r;
+ }
+
+ r = mailimf_no_fold_literal_parse(message, length, index, result);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ return MAILIMF_NO_ERROR;
+}
+#endif
+
+/*
+no-fold-quote = DQUOTE *(qtext / quoted-pair) DQUOTE
+*/
+
+#if 0
+static int mailimf_no_fold_quote_char_parse(const char * message, size_t length,
+ size_t * index, char * result)
+{
+ char ch;
+ size_t cur_token;
+ int r;
+
+ cur_token = * index;
+
+#if 0
+ r = mailimf_qtext_parse(message, length, &cur_token, &ch);
+#endif
+
+ if (cur_token >= length)
+ return MAILIMF_ERROR_PARSE;
+
+ if (is_qtext(message[cur_token])) {
+ ch = message[cur_token];
+ cur_token ++;
+ }
+ else {
+ r = mailimf_quoted_pair_parse(message, length, &cur_token, &ch);
+
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ }
+
+ * index = cur_token;
+ * result = ch;
+
+ return MAILIMF_NO_ERROR;
+}
+#endif
+
+#if 0
+static int mailimf_no_fold_quote_parse(const char * message, size_t length,
+ size_t * index, char ** result)
+{
+ size_t cur_token;
+ size_t begin;
+ char ch;
+ char * no_fold_quote;
+ int r;
+ int res;
+
+ begin = cur_token;
+ r = mailimf_dquote_parse(message, length, &cur_token);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ while (1) {
+ r = mailimf_no_fold_quote_char_parse(message, length, &cur_token, &ch);
+ if (r == MAILIMF_NO_ERROR) {
+ /* do nothing */
+ }
+ else if (r == MAILIMF_ERROR_PARSE)
+ break;
+ else {
+ res = r;
+ goto err;
+ }
+ }
+
+ r = mailimf_dquote_parse(message, length, &cur_token);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ /* no_fold_quote = strndup(message + begin, cur_token - begin); */
+ no_fold_quote = malloc(cur_token - begin + 1);
+ if (no_fold_quote == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto err;
+ }
+ strncpy(no_fold_quote, message + begin, cur_token - begin);
+ no_fold_quote[cur_token - begin] = '\0';
+
+ * result = no_fold_quote;
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+
+ err:
+ return res;
+}
+#endif
+
+/*
+no-fold-literal = "[" *(dtext / quoted-pair) "]"
+*/
+
+#if 0
+static inline int
+mailimf_no_fold_literal_char_parse(const char * message, size_t length,
+ size_t * index, char * result)
+{
+ char ch;
+ size_t cur_token;
+ int r;
+
+ cur_token = * index;
+
+#if 0
+ r = mailimf_dtext_parse(message, length, &cur_token, &ch);
+#endif
+ if (cur_token >= length)
+ return MAILIMF_ERROR_PARSE;
+
+ if (is_dtext(message[cur_token])) {
+ ch = message[cur_token];
+ cur_token ++;
+ }
+ else {
+ r = mailimf_quoted_pair_parse(message, length, &cur_token, &ch);
+
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ }
+
+ * index = cur_token;
+ * result = ch;
+
+ return MAILIMF_NO_ERROR;
+}
+#endif
+
+#if 0
+static int mailimf_no_fold_literal_parse(const char * message, size_t length,
+ size_t * index, char ** result)
+{
+ size_t cur_token;
+ size_t begin;
+ char ch;
+ char * no_fold_literal;
+ int r;
+ int res;
+
+ begin = cur_token;
+ r = mailimf_obracket_parse(message, length, &cur_token);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ while (1) {
+ r = mailimf_no_fold_literal_char_parse(message, length,
+ &cur_token, &ch);
+ if (r == MAILIMF_NO_ERROR) {
+ /* do nothing */
+ }
+ else if (r == MAILIMF_ERROR_PARSE)
+ break;
+ else {
+ res = r;
+ goto err;
+ }
+ }
+
+ r = mailimf_cbracket_parse(message, length, &cur_token);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ /*
+ no_fold_literal = strndup(message + begin, cur_token - begin);
+ */
+ no_fold_literal = malloc(cur_token - begin + 1);
+ if (no_fold_literal == NULL) {
+ res = MAILIMF_NO_ERROR;
+ goto err;
+ }
+ strncpy(no_fold_literal, message + begin, cur_token - begin);
+ no_fold_literal[cur_token - begin] = '\0';
+
+ * result = no_fold_literal;
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+
+ err:
+ return res;
+}
+#endif
+
+/*
+subject = "Subject:" unstructured CRLF
+*/
+
+static int mailimf_subject_parse(const char * message, size_t length,
+ size_t * index,
+ struct mailimf_subject ** result)
+{
+ struct mailimf_subject * subject;
+ char * value;
+ size_t cur_token;
+ int r;
+ int res;
+
+ cur_token = * index;
+
+ r = mailimf_token_case_insensitive_parse(message, length,
+ &cur_token, "Subject");
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ r = mailimf_colon_parse(message, length, &cur_token);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ r = mailimf_unstructured_parse(message, length, &cur_token, &value);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ r = mailimf_unstrict_crlf_parse(message, length, &cur_token);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto free_value;
+ }
+
+ subject = mailimf_subject_new(value);
+ if (subject == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free_value;
+ }
+
+ * result = subject;
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+
+ free_value:
+ mailimf_unstructured_free(value);
+ err:
+ return res;
+}
+
+/*
+comments = "Comments:" unstructured CRLF
+*/
+
+static int mailimf_comments_parse(const char * message, size_t length,
+ size_t * index,
+ struct mailimf_comments ** result)
+{
+ struct mailimf_comments * comments;
+ char * value;
+ size_t cur_token;
+ int r;
+ int res;
+
+ cur_token = * index;
+
+ r = mailimf_token_case_insensitive_parse(message, length,
+ &cur_token, "Comments");
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ r = mailimf_colon_parse(message, length, &cur_token);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ r = mailimf_unstructured_parse(message, length, &cur_token, &value);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ r = mailimf_unstrict_crlf_parse(message, length, &cur_token);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto free_value;
+ }
+
+ comments = mailimf_comments_new(value);
+ if (comments == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free_value;
+ }
+
+ * result = comments;
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+
+ free_value:
+ mailimf_unstructured_free(value);
+ err:
+ return res;
+}
+
+/*
+keywords = "Keywords:" phrase *("," phrase) CRLF
+*/
+
+static int mailimf_keywords_parse(const char * message, size_t length,
+ size_t * index,
+ struct mailimf_keywords ** result)
+{
+ struct mailimf_keywords * keywords;
+ clist * list;
+ size_t cur_token;
+ int r;
+ int res;
+
+ cur_token = * index;
+
+ r = mailimf_token_case_insensitive_parse(message, length,
+ &cur_token, "Keywords");
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ r = mailimf_colon_parse(message, length, &cur_token);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ r = mailimf_struct_list_parse(message, length, &cur_token,
+ &list, ',',
+ (mailimf_struct_parser *)
+ mailimf_phrase_parse,
+ (mailimf_struct_destructor *)
+ mailimf_phrase_free);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ r = mailimf_unstrict_crlf_parse(message, length, &cur_token);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto free_list;
+ }
+
+ keywords = mailimf_keywords_new(list);
+ if (keywords == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free_list;
+ }
+
+ * result = keywords;
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+
+ free_list:
+ clist_foreach(list, (clist_func) mailimf_phrase_free, NULL);
+ clist_free(list);
+ err:
+ return res;
+}
+
+/*
+resent-date = "Resent-Date:" date-time CRLF
+*/
+
+static int
+mailimf_resent_date_parse(const char * message, size_t length,
+ size_t * index, struct mailimf_orig_date ** result)
+{
+ struct mailimf_orig_date * orig_date;
+ struct mailimf_date_time * date_time;
+ size_t cur_token;
+ int r;
+ int res;
+
+ cur_token = * index;
+
+ r = mailimf_token_case_insensitive_parse(message, length,
+ &cur_token, "Resent-Date");
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ r = mailimf_colon_parse(message, length, &cur_token);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ r = mailimf_date_time_parse(message, length, &cur_token, &date_time);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ r = mailimf_unstrict_crlf_parse(message, length, &cur_token);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto free_date_time;
+ }
+
+ orig_date = mailimf_orig_date_new(date_time);
+ if (orig_date == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free_date_time;
+ }
+
+ * result = orig_date;
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+
+ free_date_time:
+ mailimf_date_time_free(date_time);
+ err:
+ return res;
+}
+
+/*
+resent-from = "Resent-From:" mailbox-list CRLF
+*/
+
+static int
+mailimf_resent_from_parse(const char * message, size_t length,
+ size_t * index, struct mailimf_from ** result)
+{
+ struct mailimf_mailbox_list * mb_list;
+ struct mailimf_from * from;
+ size_t cur_token;
+ int r;
+ int res;
+
+ cur_token = * index;
+
+ r = mailimf_token_case_insensitive_parse(message, length,
+ &cur_token, "Resent-From");
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ r = mailimf_colon_parse(message, length, &cur_token);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ r = mailimf_mailbox_list_parse(message, length, &cur_token, &mb_list);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ r = mailimf_unstrict_crlf_parse(message, length, &cur_token);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto free_mb_list;
+ }
+
+ from = mailimf_from_new(mb_list);
+ if (from == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free_mb_list;
+ }
+
+ * result = from;
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+
+ free_mb_list:
+ mailimf_mailbox_list_free(mb_list);
+ err:
+ return res;
+}
+
+/*
+resent-sender = "Resent-Sender:" mailbox CRLF
+*/
+
+static int
+mailimf_resent_sender_parse(const char * message, size_t length,
+ size_t * index, struct mailimf_sender ** result)
+{
+ struct mailimf_mailbox * mb;
+ struct mailimf_sender * sender;
+ size_t cur_token;
+ int r;
+ int res;
+
+ cur_token = length;
+
+ r = mailimf_token_case_insensitive_parse(message, length,
+ &cur_token, "Resent-Sender");
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ r = mailimf_colon_parse(message, length, &cur_token);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ r = mailimf_mailbox_parse(message, length, &cur_token, &mb);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ r = mailimf_unstrict_crlf_parse(message, length, &cur_token);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto free_mb;
+ }
+
+ sender = mailimf_sender_new(mb);
+ if (sender == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free_mb;
+ }
+
+ * result = sender;
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+
+ free_mb:
+ mailimf_mailbox_free(mb);
+ err:
+ return res;
+}
+
+/*
+resent-to = "Resent-To:" address-list CRLF
+*/
+
+static int
+mailimf_resent_to_parse(const char * message, size_t length,
+ size_t * index, struct mailimf_to ** result)
+{
+ struct mailimf_address_list * addr_list;
+ struct mailimf_to * to;
+ size_t cur_token;
+ int r;
+ int res;
+
+ cur_token = * index;
+
+ r = mailimf_token_case_insensitive_parse(message, length,
+ &cur_token, "Resent-To");
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ r = mailimf_colon_parse(message, length, &cur_token);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ r = mailimf_address_list_parse(message, length, &cur_token, &addr_list);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ r = mailimf_unstrict_crlf_parse(message, length, &cur_token);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto free_addr_list;
+ }
+
+ to = mailimf_to_new(addr_list);
+ if (to == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free_addr_list;
+ }
+
+ * result = to;
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+
+ free_addr_list:
+ mailimf_address_list_free(addr_list);
+ err:
+ return res;
+}
+
+/*
+resent-cc = "Resent-Cc:" address-list CRLF
+*/
+
+static int
+mailimf_resent_cc_parse(const char * message, size_t length,
+ size_t * index, struct mailimf_cc ** result)
+{
+ struct mailimf_address_list * addr_list;
+ struct mailimf_cc * cc;
+ size_t cur_token;
+ int r;
+ int res;
+
+ cur_token = * index;
+
+ r = mailimf_token_case_insensitive_parse(message, length,
+ &cur_token, "Resent-Cc");
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ r = mailimf_colon_parse(message, length, &cur_token);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ r = mailimf_address_list_parse(message, length, &cur_token, &addr_list);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ r = mailimf_unstrict_crlf_parse(message, length, &cur_token);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto free_addr_list;
+ }
+
+ cc = mailimf_cc_new(addr_list);
+ if (cc == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free_addr_list;
+ }
+
+ * result = cc;
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+
+ free_addr_list:
+ mailimf_address_list_free(addr_list);
+ err:
+ return res;
+}
+
+/*
+resent-bcc = "Resent-Bcc:" (address-list / [CFWS]) CRLF
+*/
+
+static int
+mailimf_resent_bcc_parse(const char * message, size_t length,
+ size_t * index, struct mailimf_bcc ** result)
+{
+ struct mailimf_address_list * addr_list;
+ struct mailimf_bcc * bcc;
+ size_t cur_token;
+ int r;
+ int res;
+
+ cur_token = * index;
+ bcc = NULL;
+
+ r = mailimf_token_case_insensitive_parse(message, length,
+ &cur_token, "Resent-Bcc");
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ r = mailimf_colon_parse(message, length, &cur_token);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ r = mailimf_address_list_parse(message, length, &cur_token, &addr_list);
+ if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
+ res = r;
+ goto err;
+ }
+
+ r = mailimf_unstrict_crlf_parse(message, length, &cur_token);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto free_addr_list;
+ }
+
+ bcc = mailimf_bcc_new(addr_list);
+ if (bcc == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free_addr_list;
+ }
+
+ * result = bcc;
+ * index = cur_token;
+
+ return TRUE;
+
+ free_addr_list:
+ mailimf_address_list_free(addr_list);
+ err:
+ return res;
+}
+
+/*
+resent-msg-id = "Resent-Message-ID:" msg-id CRLF
+*/
+
+static int
+mailimf_resent_msg_id_parse(const char * message, size_t length,
+ size_t * index,
+ struct mailimf_message_id ** result)
+{
+ char * value;
+ size_t cur_token;
+ struct mailimf_message_id * message_id;
+ int r;
+ int res;
+
+ cur_token = * index;
+
+ r = mailimf_token_case_insensitive_parse(message, length,
+ &cur_token, "Resent-Message-ID");
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ r = mailimf_colon_parse(message, length, &cur_token);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ r = mailimf_msg_id_parse(message, length, &cur_token, &value);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ r = mailimf_unstrict_crlf_parse(message, length, &cur_token);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto free_value;
+ }
+
+ message_id = mailimf_message_id_new(value);
+ if (message_id == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free_value;
+ }
+
+ * result = message_id;
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+
+ free_value:
+ mailimf_msg_id_free(value);
+ err:
+ return res;
+}
+
+/*
+trace = [return]
+ 1*received
+*/
+
+#if 0
+static int mailimf_trace_parse(const char * message, size_t length,
+ size_t * index,
+ struct mailimf_trace ** result)
+{
+ size_t cur_token;
+ struct mailimf_return * return_path;
+ clist * received_list;
+ struct mailimf_trace * trace;
+ int r;
+ int res;
+
+ cur_token = * index;
+ return_path = NULL;
+ received_list = NULL;
+
+ r = mailimf_return_parse(message, length, &cur_token, &return_path);
+ if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
+ res = r;
+ goto err;
+ }
+
+ r = mailimf_struct_multiple_parse(message, length, &cur_token,
+ &received_list,
+ (mailimf_struct_parser *)
+ mailimf_received_parse,
+ (mailimf_struct_destructor *)
+ mailimf_received_free);
+ if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
+ res = r;
+ goto err;
+ }
+
+ if ((received_list == NULL) && (return_path == NULL)) {
+ res = MAILIMF_ERROR_PARSE;
+ goto free_return;
+ }
+
+ trace = mailimf_trace_new(return_path, received_list);
+ if (trace == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free_list;
+ }
+
+ * result = trace;
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+
+ free_list:
+ clist_foreach(received_list, (clist_func) mailimf_received_free, NULL);
+ clist_free(received_list);
+ free_return:
+ if (return_path != NULL)
+ mailimf_return_free(return_path);
+ err:
+ return res;
+}
+#endif
+
+/*
+return = "Return-Path:" path CRLF
+*/
+
+static int mailimf_return_parse(const char * message, size_t length,
+ size_t * index,
+ struct mailimf_return ** result)
+{
+ struct mailimf_path * path;
+ struct mailimf_return * return_path;
+ size_t cur_token;
+ int r;
+ int res;
+
+ cur_token = * index;
+
+ r = mailimf_token_case_insensitive_parse(message, length,
+ &cur_token, "Return-Path");
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ r = mailimf_colon_parse(message, length, &cur_token);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ r = mailimf_path_parse(message, length, &cur_token, &path);
+ if ( r!= MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ r = mailimf_unstrict_crlf_parse(message, length, &cur_token);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto free_path;
+ }
+
+ return_path = mailimf_return_new(path);
+ if (return_path == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free_path;
+ }
+
+ * result = return_path;
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+
+ free_path:
+ mailimf_path_free(path);
+ err:
+ return res;
+}
+
+/*
+path = ([CFWS] "<" ([CFWS] / addr-spec) ">" [CFWS]) /
+ obs-path
+*/
+
+static int mailimf_path_parse(const char * message, size_t length,
+ size_t * index, struct mailimf_path ** result)
+{
+ size_t cur_token;
+ char * addr_spec;
+ struct mailimf_path * path;
+ int res;
+ int r;
+
+ cur_token = * index;
+ addr_spec = NULL;
+
+ r = mailimf_cfws_parse(message, length, &cur_token);
+ if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
+ res = r;
+ goto err;
+ }
+
+ r = mailimf_lower_parse(message, length, &cur_token);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ r = mailimf_addr_spec_parse(message, length, &cur_token, &addr_spec);
+ switch (r) {
+ case MAILIMF_NO_ERROR:
+ break;
+ case MAILIMF_ERROR_PARSE:
+ r = mailimf_cfws_parse(message, length, &cur_token);
+ if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
+ res = r;
+ goto err;
+ }
+ break;
+ default:
+ return r;
+ }
+
+ r = mailimf_greater_parse(message, length, &cur_token);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ path = mailimf_path_new(addr_spec);
+ if (path == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free_addr_spec;
+ }
+
+ * index = cur_token;
+ * result = path;
+
+ return MAILIMF_NO_ERROR;
+
+ free_addr_spec:
+ if (addr_spec == NULL)
+ mailimf_addr_spec_free(addr_spec);
+ err:
+ return res;
+}
+
+/*
+received = "Received:" name-val-list ";" date-time CRLF
+*/
+
+#if 0
+static int mailimf_received_parse(const char * message, size_t length,
+ size_t * index,
+ struct mailimf_received ** result)
+{
+ size_t cur_token;
+ struct mailimf_received * received;
+ struct mailimf_name_val_list * name_val_list;
+ struct mailimf_date_time * date_time;
+ int r;
+ int res;
+
+ cur_token = * index;
+
+ r = mailimf_token_case_insensitive_parse(message, length,
+ &cur_token, "Received");
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ r = mailimf_colon_parse(message, length, &cur_token);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ r = mailimf_name_val_list_parse(message, length,
+ &cur_token, &name_val_list);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ r = mailimf_semi_colon_parse(message, length, &cur_token);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto free_name_val_list;
+ }
+
+ r = mailimf_date_time_parse(message, length, &cur_token, &date_time);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto free_name_val_list;
+ }
+
+ r = mailimf_unstrict_crlf_parse(message, length, &cur_token);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto free_date_time;
+ }
+
+ received = mailimf_received_new(name_val_list, date_time);
+ if (received == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free_date_time;
+ }
+
+ * index = cur_token;
+ * result = received;
+
+ return MAILIMF_NO_ERROR;
+
+ free_date_time:
+ mailimf_date_time_free(date_time);
+ free_name_val_list:
+ mailimf_name_val_list_free(name_val_list);
+ err:
+ return res;
+}
+#endif
+
+/*
+name-val-list = [CFWS] [name-val-pair *(CFWS name-val-pair)]
+*/
+
+#if 0
+static int
+mailimf_name_val_list_parse(const char * message, size_t length,
+ size_t * index,
+ struct mailimf_name_val_list ** result)
+{
+ size_t cur_token;
+ struct mailimf_name_val_pair * pair;
+ struct mailimf_name_val_list * name_val_list;
+ clist* list;
+ int res;
+ int r;
+
+ cur_token = * index;
+ list = NULL;
+
+ r = mailimf_name_val_pair_parse(message, length, &cur_token, &pair);
+
+ if (r == MAILIMF_NO_ERROR){
+ size_t final_token;
+
+ list = clist_new();
+ if (list == NULL) {
+ mailimf_name_val_pair_free(pair);
+ res = MAILIMF_ERROR_MEMORY;
+ goto err;
+ }
+
+ r = clist_append(list, pair);
+ if (r < 0) {
+ mailimf_name_val_pair_free(pair);
+ res = MAILIMF_ERROR_MEMORY;
+ goto free_list;
+ }
+
+ final_token = cur_token;
+
+ while (1) {
+ r = mailimf_cfws_parse(message, length, &cur_token);
+ if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
+ res = r;
+ goto free_list;
+ }
+
+ r = mailimf_name_val_pair_parse(message, length, &cur_token, &pair);
+ if (r == MAILIMF_NO_ERROR) {
+ /* do nothing */
+ }
+ else if (r == MAILIMF_ERROR_PARSE)
+ break;
+ else {
+ res = r;
+ goto free_list;
+ }
+
+ r = clist_append(list, pair);
+ if (r < 0) {
+ mailimf_name_val_pair_free(pair);
+ res = MAILIMF_ERROR_MEMORY;
+ goto free_list;
+ }
+
+ final_token = cur_token;
+ }
+ cur_token = final_token;
+ }
+
+ name_val_list = mailimf_name_val_list_new(list);
+ if (name_val_list == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free_list;
+ }
+
+ * index = cur_token;
+ * result = name_val_list;
+
+ return MAILIMF_NO_ERROR;
+
+ free_list:
+ if (list != NULL) {
+ clist_foreach(list, (clist_func) mailimf_name_val_pair_free, NULL);
+ clist_free(list);
+ }
+ err:
+ return res;
+}
+#endif
+
+/*
+name-val-pair = item-name CFWS item-value
+*/
+
+#if 0
+static int
+mailimf_name_val_pair_parse(const char * message, size_t length,
+ size_t * index,
+ struct mailimf_name_val_pair ** result)
+{
+ size_t cur_token;
+ char * item_name;
+ struct mailimf_item_value * item_value;
+ struct mailimf_name_val_pair * name_val_pair;
+ int r;
+ int res;
+
+ cur_token = * index;
+
+ r = mailimf_cfws_parse(message, length, &cur_token);
+ if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
+ res = r;
+ goto err;
+ }
+
+ r = mailimf_item_name_parse(message, length, &cur_token, &item_name);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ r = mailimf_cfws_parse(message, length, &cur_token);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto free_item_name;
+ }
+
+ r = mailimf_item_value_parse(message, length, &cur_token, &item_value);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto free_item_name;
+ }
+
+ name_val_pair = mailimf_name_val_pair_new(item_name, item_value);
+ if (name_val_pair == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free_item_value;
+ }
+
+ * result = name_val_pair;
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+
+ free_item_value:
+ mailimf_item_value_free(item_value);
+ free_item_name:
+ mailimf_item_name_free(item_name);
+ err:
+ return res;
+}
+#endif
+
+/*
+item-name = ALPHA *(["-"] (ALPHA / DIGIT))
+*/
+
+#if 0
+static int mailimf_item_name_parse(const char * message, size_t length,
+ size_t * index, char ** result)
+{
+ size_t cur_token;
+ size_t begin;
+ char * item_name;
+ char ch;
+ int digit;
+ int r;
+ int res;
+
+ cur_token = * index;
+
+ begin = cur_token;
+
+ r = mailimf_alpha_parse(message, length, &cur_token, &ch);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ while (1) {
+ int minus_sign;
+
+ minus_sign = mailimf_minus_parse(message, length, &cur_token);
+
+ r = mailimf_alpha_parse(message, length, &cur_token, &ch);
+ if (r == MAILIMF_ERROR_PARSE)
+ r = mailimf_digit_parse(message, length, &cur_token, &digit);
+
+ if (r == MAILIMF_NO_ERROR) {
+ /* do nothing */
+ }
+ if (r == MAILIMF_ERROR_PARSE)
+ break;
+ else if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+ }
+
+ item_name = strndup(message + begin, cur_token - begin);
+ if (item_name == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto err;
+ }
+
+ * index = cur_token;
+ * result = item_name;
+
+ return MAILIMF_NO_ERROR;
+
+ err:
+ return res;
+}
+#endif
+
+/*
+item-value = 1*angle-addr / addr-spec /
+ atom / domain / msg-id
+*/
+
+#if 0
+static int is_item_value_atext(char ch)
+{
+ switch (ch) {
+ case '\t':
+ case ' ':
+ case '\r':
+ case '\n':
+ case ';':
+ return FALSE;
+ default:
+ return TRUE;
+ }
+}
+
+static int mailimf_item_value_atom_parse(const char * message, size_t length,
+ size_t * index, char ** result)
+{
+ char * atom;
+ size_t cur_token;
+ int r;
+
+ cur_token = * index;
+
+ r = mailimf_cfws_parse(message, length, &cur_token);
+ if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE))
+ return r;
+
+ r = mailimf_custom_string_parse(message, length, &cur_token,
+ &atom, is_item_value_atext);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_cfws_parse(message, length, &cur_token);
+ if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE))
+ return r;
+
+ * index = cur_token;
+ * result = atom;
+
+ return MAILIMF_NO_ERROR;
+}
+
+static int mailimf_item_value_parse(const char * message, size_t length,
+ size_t * index,
+ struct mailimf_item_value ** result)
+{
+ size_t cur_token;
+ clist * angle_addr_list;
+ char * addr_spec;
+ char * atom;
+ char * domain;
+ char * msg_id;
+ int type;
+ struct mailimf_item_value * item_value;
+ int r;
+ int res;
+
+ cur_token = * index;
+
+ angle_addr_list = NULL;
+ addr_spec = NULL;
+ atom = NULL;
+ domain = NULL;
+ msg_id = NULL;
+
+ r = mailimf_struct_multiple_parse(message, length, &cur_token,
+ &angle_addr_list,
+ (mailimf_struct_parser *)
+ mailimf_angle_addr_parse,
+ (mailimf_struct_destructor *)
+ mailimf_angle_addr_free);
+ if (r == MAILIMF_NO_ERROR)
+ type = MAILIMF_ITEM_VALUE_ANGLE_ADDR_LIST;
+
+ if (r == MAILIMF_ERROR_PARSE) {
+ r = mailimf_addr_spec_parse(message, length, &cur_token,
+ &addr_spec);
+ if (r == MAILIMF_NO_ERROR)
+ type = MAILIMF_ITEM_VALUE_ADDR_SPEC;
+ }
+
+ if (r == MAILIMF_ERROR_PARSE) {
+ r = mailimf_msg_id_parse(message, length, &cur_token,
+ &msg_id);
+ if (r == MAILIMF_NO_ERROR)
+ type = MAILIMF_ITEM_VALUE_MSG_ID;
+ }
+
+ /*
+ else if (mailimf_domain_parse(message, length, &cur_token,
+ &domain))
+ type = MAILIMF_ITEM_VALUE_DOMAIN;
+ */
+ /*
+ else if (mailimf_atom_parse(message, length, &cur_token,
+ &atom))
+ type = MAILIMF_ITEM_VALUE_ATOM;
+ */
+
+ if (r == MAILIMF_ERROR_PARSE) {
+ r = mailimf_item_value_atom_parse(message, length, &cur_token,
+ &atom);
+ if (r == MAILIMF_NO_ERROR)
+ type = MAILIMF_ITEM_VALUE_ATOM;
+ }
+
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ item_value = mailimf_item_value_new(type, angle_addr_list, addr_spec,
+ atom, domain, msg_id);
+ if (item_value == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free;
+ }
+
+ * result = item_value;
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+
+ free:
+ if (angle_addr_list != NULL) {
+ clist_foreach(angle_addr_list, (clist_func) mailimf_angle_addr_free, NULL);
+ clist_free(angle_addr_list);
+ }
+ if (addr_spec != NULL)
+ mailimf_addr_spec_free(addr_spec);
+ if (atom != NULL)
+ mailimf_atom_free(atom);
+ if (domain != NULL)
+ mailimf_domain_free(domain);
+ if (msg_id != NULL)
+ mailimf_msg_id_free(msg_id);
+ err:
+ return res;
+}
+#endif
+
+/*
+optional-field = field-name ":" unstructured CRLF
+*/
+
+static int
+mailimf_optional_field_parse(const char * message, size_t length,
+ size_t * index,
+ struct mailimf_optional_field ** result)
+{
+ char * name;
+ char * value;
+ struct mailimf_optional_field * optional_field;
+ size_t cur_token;
+ int r;
+ int res;
+
+ cur_token = * index;
+
+ r = mailimf_field_name_parse(message, length, &cur_token, &name);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ r = mailimf_colon_parse(message, length, &cur_token);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto free_name;
+ }
+
+ r = mailimf_unstructured_parse(message, length, &cur_token, &value);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto free_name;
+ }
+
+ r = mailimf_unstrict_crlf_parse(message, length, &cur_token);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto free_value;
+ }
+
+ optional_field = mailimf_optional_field_new(name, value);
+ if (optional_field == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free_value;
+ }
+
+ * result = optional_field;
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+
+ free_value:
+ mailimf_unstructured_free(value);
+ free_name:
+ mailimf_field_name_free(name);
+ err:
+ return res;
+}
+
+/*
+field-name = 1*ftext
+*/
+
+static inline int is_ftext(char ch);
+
+static int mailimf_field_name_parse(const char * message, size_t length,
+ size_t * index, char ** result)
+{
+ char * field_name;
+ size_t cur_token;
+ size_t end;
+
+ cur_token = * index;
+
+ end = cur_token;
+ if (end >= length) {
+ return MAILIMF_ERROR_PARSE;
+ }
+
+ while (is_ftext(message[end])) {
+ end ++;
+ if (end >= length)
+ break;
+ }
+ if (end == cur_token) {
+ return MAILIMF_ERROR_PARSE;
+ }
+
+ /* field_name = strndup(message + cur_token, end - cur_token); */
+ field_name = malloc(end - cur_token + 1);
+ if (field_name == NULL) {
+ return MAILIMF_ERROR_MEMORY;
+ }
+ strncpy(field_name, message + cur_token, end - cur_token);
+ field_name[end - cur_token] = '\0';
+
+ cur_token = end;
+
+ * index = cur_token;
+ * result = field_name;
+
+ return MAILIMF_NO_ERROR;
+}
+
+/*
+ftext = %d33-57 / ; Any character except
+ %d59-126 ; controls, SP, and
+ ; ":".
+*/
+
+static inline int is_ftext(char ch)
+{
+ unsigned char uch = (unsigned char) ch;
+
+ if (uch < 33)
+ return FALSE;
+
+ if (uch == 58)
+ return FALSE;
+
+ return TRUE;
+}
+
+/*
+static int mailimf_ftext_parse(const char * message, size_t length,
+ size_t * index, gchar * result)
+{
+ return mailimf_typed_text_parse(message, length, index, result, is_ftext);
+}
+*/
+
+
+
+
+static int mailimf_envelope_field_parse(const char * message, size_t length,
+ size_t * index,
+ struct mailimf_field ** result)
+{
+ size_t cur_token;
+ int type;
+ struct mailimf_orig_date * orig_date;
+ struct mailimf_from * from;
+ struct mailimf_sender * sender;
+ struct mailimf_reply_to * reply_to;
+ struct mailimf_to * to;
+ struct mailimf_cc * cc;
+ struct mailimf_bcc * bcc;
+ struct mailimf_message_id * message_id;
+ struct mailimf_in_reply_to * in_reply_to;
+ struct mailimf_references * references;
+ struct mailimf_subject * subject;
+ struct mailimf_optional_field * optional_field;
+ struct mailimf_field * field;
+ int guessed_type;
+ int r;
+ int res;
+
+ cur_token = * index;
+
+ orig_date = NULL;
+ from = NULL;
+ sender = NULL;
+ reply_to = NULL;
+ to = NULL;
+ cc = NULL;
+ bcc = NULL;
+ message_id = NULL;
+ in_reply_to = NULL;
+ references = NULL;
+ subject = NULL;
+ optional_field = NULL;
+
+ guessed_type = guess_header_type(message, length, cur_token);
+ type = MAILIMF_FIELD_NONE;
+
+ switch (guessed_type) {
+ case MAILIMF_FIELD_ORIG_DATE:
+ r = mailimf_orig_date_parse(message, length, &cur_token,
+ &orig_date);
+ if (r == MAILIMF_NO_ERROR)
+ type = guessed_type;
+ else if (r == MAILIMF_ERROR_PARSE) {
+ /* do nothing */
+ }
+ else {
+ res = r;
+ goto err;
+ }
+ break;
+ case MAILIMF_FIELD_FROM:
+ r = mailimf_from_parse(message, length, &cur_token,
+ &from);
+ if (r == MAILIMF_NO_ERROR)
+ type = guessed_type;
+ else if (r == MAILIMF_ERROR_PARSE) {
+ /* do nothing */
+ }
+ else {
+ res = r;
+ goto err;
+ }
+ break;
+ case MAILIMF_FIELD_SENDER:
+ r = mailimf_sender_parse(message, length, &cur_token,
+ &sender);
+ if (r == MAILIMF_NO_ERROR)
+ type = guessed_type;
+ else if (r == MAILIMF_ERROR_PARSE) {
+ /* do nothing */
+ }
+ else {
+ res = r;
+ goto err;
+ }
+ break;
+ case MAILIMF_FIELD_REPLY_TO:
+ r = mailimf_reply_to_parse(message, length, &cur_token,
+ &reply_to);
+ if (r == MAILIMF_NO_ERROR)
+ type = guessed_type;
+ else if (r == MAILIMF_ERROR_PARSE) {
+ /* do nothing */
+ }
+ else {
+ res = r;
+ goto err;
+ }
+ break;
+ case MAILIMF_FIELD_TO:
+ r = mailimf_to_parse(message, length, &cur_token,
+ &to);
+ if (r == MAILIMF_NO_ERROR)
+ type = guessed_type;
+ else if (r == MAILIMF_ERROR_PARSE) {
+ /* do nothing */
+ }
+ else {
+ res = r;
+ goto err;
+ }
+ break;
+ case MAILIMF_FIELD_CC:
+ r = mailimf_cc_parse(message, length, &cur_token,
+ &cc);
+ if (r == MAILIMF_NO_ERROR)
+ type = guessed_type;
+ else if (r == MAILIMF_ERROR_PARSE) {
+ /* do nothing */
+ }
+ else {
+ res = r;
+ goto err;
+ }
+ break;
+ case MAILIMF_FIELD_BCC:
+ r = mailimf_bcc_parse(message, length, &cur_token,
+ &bcc);
+ if (r == MAILIMF_NO_ERROR)
+ type = guessed_type;
+ else if (r == MAILIMF_ERROR_PARSE) {
+ /* do nothing */
+ }
+ else {
+ res = r;
+ goto err;
+ }
+ break;
+ case MAILIMF_FIELD_MESSAGE_ID:
+ r = mailimf_message_id_parse(message, length, &cur_token,
+ &message_id);
+ if (r == MAILIMF_NO_ERROR)
+ type = guessed_type;
+ else if (r == MAILIMF_ERROR_PARSE) {
+ /* do nothing */
+ }
+ else {
+ res = r;
+ goto err;
+ }
+ break;
+ case MAILIMF_FIELD_IN_REPLY_TO:
+ r = mailimf_in_reply_to_parse(message, length, &cur_token,
+ &in_reply_to);
+ if (r == MAILIMF_NO_ERROR)
+ type = guessed_type;
+ else if (r == MAILIMF_ERROR_PARSE) {
+ /* do nothing */
+ }
+ else {
+ res = r;
+ goto err;
+ }
+ break;
+ case MAILIMF_FIELD_REFERENCES:
+ r = mailimf_references_parse(message, length, &cur_token,
+ &references);
+ if (r == MAILIMF_NO_ERROR)
+ type = guessed_type;
+ else if (r == MAILIMF_ERROR_PARSE) {
+ /* do nothing */
+ }
+ else {
+ res = r;
+ goto err;
+ }
+ break;
+ case MAILIMF_FIELD_SUBJECT:
+ r = mailimf_subject_parse(message, length, &cur_token,
+ &subject);
+ if (r == MAILIMF_NO_ERROR)
+ type = guessed_type;
+ else if (r == MAILIMF_ERROR_PARSE) {
+ /* do nothing */
+ }
+ else {
+ res = r;
+ goto err;
+ }
+ break;
+ }
+
+ if (type == MAILIMF_FIELD_NONE) {
+ res = MAILIMF_ERROR_PARSE;
+ goto err;
+ }
+
+ field = mailimf_field_new(type, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL,
+ orig_date, from, sender, reply_to, to,
+ cc, bcc, message_id, in_reply_to, references,
+ subject, NULL, NULL, optional_field);
+ if (field == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free_field;
+ }
+
+ * result = field;
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+
+ free_field:
+ if (orig_date != NULL)
+ mailimf_orig_date_free(orig_date);
+ if (from != NULL)
+ mailimf_from_free(from);
+ if (sender != NULL)
+ mailimf_sender_free(sender);
+ if (reply_to != NULL)
+ mailimf_reply_to_free(reply_to);
+ if (to != NULL)
+ mailimf_to_free(to);
+ if (cc != NULL)
+ mailimf_cc_free(cc);
+ if (bcc != NULL)
+ mailimf_bcc_free(bcc);
+ if (message_id != NULL)
+ mailimf_message_id_free(message_id);
+ if (in_reply_to != NULL)
+ mailimf_in_reply_to_free(in_reply_to);
+ if (references != NULL)
+ mailimf_references_free(references);
+ if (subject != NULL)
+ mailimf_subject_free(subject);
+ if (optional_field != NULL)
+ mailimf_optional_field_free(optional_field);
+ err:
+ return res;
+}
+
+int mailimf_envelope_fields_parse(const char * message, size_t length,
+ size_t * index,
+ struct mailimf_fields ** result)
+{
+ size_t cur_token;
+ clist * list;
+ struct mailimf_fields * fields;
+ int r;
+ int res;
+
+ cur_token = * index;
+
+ list = clist_new();
+ if (list == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto err;
+ }
+
+ while (1) {
+ struct mailimf_field * elt;
+
+ r = mailimf_envelope_field_parse(message, length, &cur_token, &elt);
+ if (r == MAILIMF_NO_ERROR) {
+ r = clist_append(list, elt);
+ if (r < 0) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free;
+ }
+ }
+ else if (r == MAILIMF_ERROR_PARSE) {
+ r = mailimf_ignore_field_parse(message, length, &cur_token);
+ if (r == MAILIMF_NO_ERROR) {
+ /* do nothing */
+ }
+ else if (r == MAILIMF_ERROR_PARSE) {
+ break;
+ }
+ else {
+ res = r;
+ goto free;
+ }
+ }
+ else {
+ res = r;
+ goto free;
+ }
+ }
+
+ fields = mailimf_fields_new(list);
+ if (fields == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free;
+ }
+
+ * result = fields;
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+
+ free:
+ if (list != NULL) {
+ clist_foreach(list, (clist_func) mailimf_field_free, NULL);
+ clist_free(list);
+ }
+ err:
+ return res;
+}
+
+
+static int
+mailimf_envelope_or_optional_field_parse(const char * message,
+ size_t length,
+ size_t * index,
+ struct mailimf_field ** result)
+{
+ int r;
+ size_t cur_token;
+ struct mailimf_optional_field * optional_field;
+ struct mailimf_field * field;
+
+ r = mailimf_envelope_field_parse(message, length, index, result);
+ if (r == MAILIMF_NO_ERROR)
+ return MAILIMF_NO_ERROR;
+
+ cur_token = * index;
+
+ r = mailimf_optional_field_parse(message, length, &cur_token,
+ &optional_field);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ field = mailimf_field_new(MAILIMF_FIELD_OPTIONAL_FIELD, NULL,
+ NULL, NULL, NULL,
+ NULL, NULL, NULL,
+ NULL, NULL, NULL,
+ NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, optional_field);
+ if (field == NULL) {
+ mailimf_optional_field_free(optional_field);
+ return MAILIMF_ERROR_MEMORY;
+ }
+
+ * result = field;
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+}
+
+
+int
+mailimf_envelope_and_optional_fields_parse(const char * message, size_t length,
+ size_t * index,
+ struct mailimf_fields ** result)
+{
+ size_t cur_token;
+ clist * list;
+ struct mailimf_fields * fields;
+ int r;
+ int res;
+
+ cur_token = * index;
+
+ list = NULL;
+
+ r = mailimf_struct_multiple_parse(message, length, &cur_token,
+ &list,
+ (mailimf_struct_parser *)
+ mailimf_envelope_or_optional_field_parse,
+ (mailimf_struct_destructor *)
+ mailimf_field_free);
+ switch (r) {
+ case MAILIMF_NO_ERROR:
+ /* do nothing */
+ break;
+
+ case MAILIMF_ERROR_PARSE:
+ list = clist_new();
+ if (list == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto err;
+ }
+ break;
+
+ default:
+ res = r;
+ goto err;
+ }
+
+ fields = mailimf_fields_new(list);
+ if (fields == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free;
+ }
+
+ * result = fields;
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+
+ free:
+ if (list != NULL) {
+ clist_foreach(list, (clist_func) mailimf_field_free, NULL);
+ clist_free(list);
+ }
+ err:
+ return res;
+}
+
+
+
+static int
+mailimf_only_optional_field_parse(const char * message,
+ size_t length,
+ size_t * index,
+ struct mailimf_field ** result)
+{
+ int r;
+ size_t cur_token;
+ struct mailimf_optional_field * optional_field;
+ struct mailimf_field * field;
+
+ cur_token = * index;
+
+ r = mailimf_optional_field_parse(message, length, &cur_token,
+ &optional_field);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ field = mailimf_field_new(MAILIMF_FIELD_OPTIONAL_FIELD, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, optional_field);
+ if (field == NULL) {
+ mailimf_optional_field_free(optional_field);
+ return MAILIMF_ERROR_MEMORY;
+ }
+
+ * result = field;
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+}
+
+
+int
+mailimf_optional_fields_parse(const char * message, size_t length,
+ size_t * index,
+ struct mailimf_fields ** result)
+{
+ size_t cur_token;
+ clist * list;
+ struct mailimf_fields * fields;
+ int r;
+ int res;
+
+ cur_token = * index;
+
+ list = NULL;
+
+ r = mailimf_struct_multiple_parse(message, length, &cur_token,
+ &list,
+ (mailimf_struct_parser *)
+ mailimf_only_optional_field_parse,
+ (mailimf_struct_destructor *)
+ mailimf_field_free);
+ switch (r) {
+ case MAILIMF_NO_ERROR:
+ /* do nothing */
+ break;
+
+ case MAILIMF_ERROR_PARSE:
+ list = clist_new();
+ if (list == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto err;
+ }
+ break;
+
+ default:
+ res = r;
+ goto err;
+ }
+
+ fields = mailimf_fields_new(list);
+ if (fields == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free;
+ }
+
+ * result = fields;
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+
+ free:
+ if (list != NULL) {
+ clist_foreach(list, (clist_func) mailimf_field_free, NULL);
+ clist_free(list);
+ }
+ err:
+ return res;
+}
diff --git a/libetpan/src/low-level/imf/mailimf.h b/libetpan/src/low-level/imf/mailimf.h
new file mode 100644
index 0000000..c2231dd
--- a/dev/null
+++ b/libetpan/src/low-level/imf/mailimf.h
@@ -0,0 +1,347 @@
+/*
+ * 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$
+ */
+
+#ifndef MAILIMF_H
+
+#define MAILIMF_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <libetpan/mailimf_types.h>
+#include <libetpan/mailimf_write_generic.h>
+#include <libetpan/mailimf_write_file.h>
+#include <libetpan/mailimf_write_mem.h>
+#include <libetpan/mailimf_types_helper.h>
+
+#include <inttypes.h>
+#include <sys/types.h>
+
+/*
+ mailimf_message_parse will parse the given message
+
+ @param message this is a string containing the message content
+ @param length this is the size of the given string
+ @param index this is a pointer to the start of the message in
+ the given string, (* index) is modified to point at the end
+ of the parsed data
+ @param result the result of the parse operation is stored in
+ (* result)
+
+ @return MAILIMF_NO_ERROR on success, MAILIMF_ERROR_XXX on error
+*/
+
+int mailimf_message_parse(const char * message, size_t length,
+ size_t * index,
+ struct mailimf_message ** result);
+
+/*
+ mailimf_body_parse will parse the given text part of a message
+
+ @param message this is a string containing the message text part
+ @param length this is the size of the given string
+ @param index this is a pointer to the start of the message text part in
+ the given string, (* index) is modified to point at the end
+ of the parsed data
+ @param result the result of the parse operation is stored in
+ (* result)
+
+ @return MAILIMF_NO_ERROR on success, MAILIMF_ERROR_XXX on error
+*/
+
+int mailimf_body_parse(const char * message, size_t length,
+ size_t * index,
+ struct mailimf_body ** result);
+
+/*
+ mailimf_fields_parse will parse the given header fields
+
+ @param message this is a string containing the header fields
+ @param length this is the size of the given string
+ @param index this is a pointer to the start of the header fields in
+ the given string, (* index) is modified to point at the end
+ of the parsed data
+ @param result the result of the parse operation is stored in
+ (* result)
+
+ @return MAILIMF_NO_ERROR on success, MAILIMF_ERROR_XXX on error
+*/
+
+int mailimf_fields_parse(const char * message, size_t length,
+ size_t * index,
+ struct mailimf_fields ** result);
+
+/*
+ mailimf_mailbox_list_parse will parse the given mailbox list
+
+ @param message this is a string containing the mailbox list
+ @param length this is the size of the given string
+ @param index this is a pointer to the start of the mailbox list in
+ the given string, (* index) is modified to point at the end
+ of the parsed data
+ @param result the result of the parse operation is stored in
+ (* result)
+
+ @return MAILIMF_NO_ERROR on success, MAILIMF_ERROR_XXX on error
+*/
+
+int
+mailimf_mailbox_list_parse(const char * message, size_t length,
+ size_t * index,
+ struct mailimf_mailbox_list ** result);
+
+/*
+ mailimf_address_list_parse will parse the given address list
+
+ @param message this is a string containing the address list
+ @param length this is the size of the given string
+ @param index this is a pointer to the start of the address list in
+ the given string, (* index) is modified to point at the end
+ of the parsed data
+ @param result the result of the parse operation is stored in
+ (* result)
+
+ @return MAILIMF_NO_ERROR on success, MAILIMF_ERROR_XXX on error
+*/
+
+int
+mailimf_address_list_parse(const char * message, size_t length,
+ size_t * index,
+ struct mailimf_address_list ** result);
+
+/*
+ mailimf_address_parse will parse the given address
+
+ @param message this is a string containing the address
+ @param length this is the size of the given string
+ @param index this is a pointer to the start of the address in
+ the given string, (* index) is modified to point at the end
+ of the parsed data
+ @param result the result of the parse operation is stored in
+ (* result)
+
+ @return MAILIMF_NO_ERROR on success, MAILIMF_ERROR_XXX on error
+*/
+
+int mailimf_address_parse(const char * message, size_t length,
+ size_t * index,
+ struct mailimf_address ** result);
+
+/*
+ mailimf_mailbox_parse will parse the given address
+
+ @param message this is a string containing the mailbox
+ @param length this is the size of the given string
+ @param index this is a pointer to the start of the mailbox in
+ the given string, (* index) is modified to point at the end
+ of the parsed data
+ @param result the result of the parse operation is stored in
+ (* result)
+
+ @return MAILIMF_NO_ERROR on success, MAILIMF_ERROR_XXX on error
+*/
+
+int mailimf_mailbox_parse(const char * message, size_t length,
+ size_t * index,
+ struct mailimf_mailbox ** result);
+
+/*
+ mailimf_date_time_parse will parse the given RFC 2822 date
+
+ @param message this is a string containing the date
+ @param length this is the size of the given string
+ @param index this is a pointer to the start of the date in
+ the given string, (* index) is modified to point at the end
+ of the parsed data
+ @param result the result of the parse operation is stored in
+ (* result)
+
+ @return MAILIMF_NO_ERROR on success, MAILIMF_ERROR_XXX on error
+*/
+
+int mailimf_date_time_parse(const char * message, size_t length,
+ size_t * index,
+ struct mailimf_date_time ** result);
+
+/*
+ mailimf_envelope_fields_parse will parse the given fields (Date,
+ From, Sender, Reply-To, To, Cc, Bcc, Message-ID, In-Reply-To,
+ References and Subject)
+
+ @param message this is a string containing the header fields
+ @param length this is the size of the given string
+ @param index this is a pointer to the start of the header fields in
+ the given string, (* index) is modified to point at the end
+ of the parsed data
+ @param result the result of the parse operation is stored in
+ (* result)
+
+ @return MAILIMF_NO_ERROR on success, MAILIMF_ERROR_XXX on error
+*/
+
+int mailimf_envelope_fields_parse(const char * message, size_t length,
+ size_t * index,
+ struct mailimf_fields ** result);
+
+/*
+ mailimf_ignore_field_parse will skip the given field
+
+ @param message this is a string containing the header field
+ @param length this is the size of the given string
+ @param index this is a pointer to the start of the header field in
+ the given string, (* index) is modified to point at the end
+ of the parsed data
+
+ @return MAILIMF_NO_ERROR on success, MAILIMF_ERROR_XXX on error
+*/
+
+
+int mailimf_ignore_field_parse(const char * message, size_t length,
+ size_t * index);
+
+/*
+ mailimf_envelope_fields will parse the given fields (Date,
+ From, Sender, Reply-To, To, Cc, Bcc, Message-ID, In-Reply-To,
+ References and Subject), other fields will be added as optional
+ fields.
+
+ @param message this is a string containing the header fields
+ @param length this is the size of the given string
+ @param index this is a pointer to the start of the header fields in
+ the given string, (* index) is modified to point at the end
+ of the parsed data
+ @param result the result of the parse operation is stored in
+ (* result)
+
+ @return MAILIMF_NO_ERROR on success, MAILIMF_ERROR_XXX on error
+*/
+
+
+int
+mailimf_envelope_and_optional_fields_parse(const char * message, size_t length,
+ size_t * index,
+ struct mailimf_fields ** result);
+
+/*
+ mailimf_envelope_fields will parse the given fields as optional
+ fields.
+
+ @param message this is a string containing the header fields
+ @param length this is the size of the given string
+ @param index this is a pointer to the start of the header fields in
+ the given string, (* index) is modified to point at the end
+ of the parsed data
+ @param result the result of the parse operation is stored in
+ (* result)
+
+ @return MAILIMF_NO_ERROR on success, MAILIMF_ERROR_XXX on error
+*/
+
+int
+mailimf_optional_fields_parse(const char * message, size_t length,
+ size_t * index,
+ struct mailimf_fields ** result);
+
+
+/* internal use, exported for MIME */
+
+int mailimf_fws_parse(const char * message, size_t length, size_t * index);
+
+int mailimf_cfws_parse(const char * message, size_t length,
+ size_t * index);
+
+int mailimf_char_parse(const char * message, size_t length,
+ size_t * index, char token);
+
+int mailimf_unstrict_char_parse(const char * message, size_t length,
+ size_t * index, char token);
+
+int mailimf_crlf_parse(const char * message, size_t length, size_t * index);
+
+int
+mailimf_custom_string_parse(const char * message, size_t length,
+ size_t * index, char ** result,
+ int (* is_custom_char)(char));
+
+int
+mailimf_token_case_insensitive_len_parse(const char * message, size_t length,
+ size_t * index, char * token,
+ size_t token_length);
+
+#define mailimf_token_case_insensitive_parse(message, length, index, token) \
+ mailimf_token_case_insensitive_len_parse(message, length, index, token, \
+ sizeof(token) - 1)
+
+int mailimf_quoted_string_parse(const char * message, size_t length,
+ size_t * index, char ** result);
+
+int
+mailimf_number_parse(const char * message, size_t length,
+ size_t * index, uint32_t * result);
+
+int mailimf_msg_id_parse(const char * message, size_t length,
+ size_t * index,
+ char ** result);
+
+int mailimf_msg_id_list_parse(const char * message, size_t length,
+ size_t * index, clist ** result);
+
+int mailimf_word_parse(const char * message, size_t length,
+ size_t * index, char ** result);
+
+int mailimf_atom_parse(const char * message, size_t length,
+ size_t * index, char ** result);
+
+int mailimf_fws_atom_parse(const char * message, size_t length,
+ size_t * index, char ** result);
+
+int mailimf_fws_word_parse(const char * message, size_t length,
+ size_t * index, char ** result);
+
+int mailimf_fws_quoted_string_parse(const char * message, size_t length,
+ size_t * index, char ** result);
+
+/* exported for IMAP */
+
+int mailimf_references_parse(const char * message, size_t length,
+ size_t * index,
+ struct mailimf_references ** result);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libetpan/src/low-level/imf/mailimf_types.c b/libetpan/src/low-level/imf/mailimf_types.c
new file mode 100644
index 0000000..a6e4db9
--- a/dev/null
+++ b/libetpan/src/low-level/imf/mailimf_types.c
@@ -0,0 +1,868 @@
+/*
+ * 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 "mailimf_types.h"
+#include "mmapstring.h"
+#include <stdlib.h>
+
+void mailimf_atom_free(char * atom)
+{
+ free(atom);
+}
+
+void mailimf_dot_atom_free(char * dot_atom)
+{
+ free(dot_atom);
+}
+
+void mailimf_dot_atom_text_free(char * dot_atom)
+{
+ free(dot_atom);
+}
+
+void mailimf_quoted_string_free(char * quoted_string)
+{
+ free(quoted_string);
+}
+
+void mailimf_word_free(char * word)
+{
+ free(word);
+}
+
+void mailimf_phrase_free(char * phrase)
+{
+ free(phrase);
+}
+
+void mailimf_unstructured_free(char * unstructured)
+{
+ free(unstructured);
+}
+
+
+struct mailimf_date_time *
+mailimf_date_time_new(int dt_day, int dt_month, int dt_year,
+ int dt_hour, int dt_min, int dt_sec, int dt_zone)
+{
+ struct mailimf_date_time * date_time;
+
+ date_time = malloc(sizeof(* date_time));
+ if (date_time == NULL)
+ return NULL;
+
+ date_time->dt_day = dt_day;
+ date_time->dt_month = dt_month;
+ date_time->dt_year = dt_year;
+ date_time->dt_hour = dt_hour;
+ date_time->dt_min = dt_min;
+ date_time->dt_sec = dt_sec;
+ date_time->dt_zone = dt_zone;
+
+ return date_time;
+}
+
+
+void mailimf_date_time_free(struct mailimf_date_time * date_time)
+{
+ free(date_time);
+}
+
+
+
+
+struct mailimf_address *
+mailimf_address_new(int ad_type, struct mailimf_mailbox * ad_mailbox,
+ struct mailimf_group * ad_group)
+{
+ struct mailimf_address * address;
+
+ address = malloc(sizeof(* address));
+ if (address == NULL)
+ return NULL;
+
+ address->ad_type = ad_type;
+ switch (ad_type) {
+ case MAILIMF_ADDRESS_MAILBOX:
+ address->ad_data.ad_mailbox = ad_mailbox;
+ break;
+ case MAILIMF_ADDRESS_GROUP:
+ address->ad_data.ad_group = ad_group;
+ break;
+ }
+
+ return address;
+}
+
+void mailimf_address_free(struct mailimf_address * address)
+{
+ switch (address->ad_type) {
+ case MAILIMF_ADDRESS_MAILBOX:
+ mailimf_mailbox_free(address->ad_data.ad_mailbox);
+ break;
+ case MAILIMF_ADDRESS_GROUP:
+ mailimf_group_free(address->ad_data.ad_group);
+ }
+ free(address);
+}
+
+struct mailimf_mailbox *
+mailimf_mailbox_new(char * mb_display_name, char * mb_addr_spec)
+{
+ struct mailimf_mailbox * mb;
+
+ mb = malloc(sizeof(* mb));
+ if (mb == NULL)
+ return NULL;
+
+ mb->mb_display_name = mb_display_name;
+ mb->mb_addr_spec = mb_addr_spec;
+
+ return mb;
+}
+
+void mailimf_mailbox_free(struct mailimf_mailbox * mailbox)
+{
+ if (mailbox->mb_display_name != NULL)
+ mailimf_display_name_free(mailbox->mb_display_name);
+ mailimf_addr_spec_free(mailbox->mb_addr_spec);
+ free(mailbox);
+}
+
+
+void mailimf_angle_addr_free(char * angle_addr)
+{
+ free(angle_addr);
+}
+
+
+struct mailimf_group *
+mailimf_group_new(char * grp_display_name,
+ struct mailimf_mailbox_list * grp_mb_list)
+{
+ struct mailimf_group * group;
+
+ group = malloc(sizeof(* group));
+ if (group == NULL)
+ return NULL;
+
+ group->grp_display_name = grp_display_name;
+ group->grp_mb_list = grp_mb_list;
+
+ return group;
+}
+
+void mailimf_group_free(struct mailimf_group * group)
+{
+ if (group->grp_mb_list)
+ mailimf_mailbox_list_free(group->grp_mb_list);
+ mailimf_display_name_free(group->grp_display_name);
+ free(group);
+}
+
+void mailimf_display_name_free(char * display_name)
+{
+ mailimf_phrase_free(display_name);
+}
+
+
+struct mailimf_mailbox_list *
+mailimf_mailbox_list_new(clist * mb_list)
+{
+ struct mailimf_mailbox_list * mbl;
+
+ mbl = malloc(sizeof(* mbl));
+ if (mbl == NULL)
+ return NULL;
+
+ mbl->mb_list = mb_list;
+
+ return mbl;
+}
+
+void mailimf_mailbox_list_free(struct mailimf_mailbox_list * mb_list)
+{
+ clist_foreach(mb_list->mb_list, (clist_func) mailimf_mailbox_free, NULL);
+ clist_free(mb_list->mb_list);
+ free(mb_list);
+}
+
+
+
+struct mailimf_address_list *
+mailimf_address_list_new(clist * ad_list)
+{
+ struct mailimf_address_list * addr_list;
+
+ addr_list = malloc(sizeof(* addr_list));
+ if (addr_list == NULL)
+ return NULL;
+
+ addr_list->ad_list = ad_list;
+
+ return addr_list;
+}
+
+void mailimf_address_list_free(struct mailimf_address_list * addr_list)
+{
+ clist_foreach(addr_list->ad_list, (clist_func) mailimf_address_free, NULL);
+ clist_free(addr_list->ad_list);
+ free(addr_list);
+}
+
+
+void mailimf_addr_spec_free(char * addr_spec)
+{
+ free(addr_spec);
+}
+
+void mailimf_local_part_free(char * local_part)
+{
+ free(local_part);
+}
+
+void mailimf_domain_free(char * domain)
+{
+ free(domain);
+}
+
+void mailimf_domain_literal_free(char * domain_literal)
+{
+ free(domain_literal);
+}
+
+
+
+struct mailimf_message *
+mailimf_message_new(struct mailimf_fields * msg_fields,
+ struct mailimf_body * msg_body)
+{
+ struct mailimf_message * message;
+
+ message = malloc(sizeof(* message));
+ if (message == NULL)
+ return NULL;
+
+ message->msg_fields = msg_fields;
+ message->msg_body = msg_body;
+
+ return message;
+}
+
+void mailimf_message_free(struct mailimf_message * message)
+{
+ mailimf_body_free(message->msg_body);
+ mailimf_fields_free(message->msg_fields);
+ free(message);
+}
+
+
+struct mailimf_body * mailimf_body_new(const char * bd_text, size_t bd_size)
+{
+ struct mailimf_body * body;
+
+ body = malloc(sizeof(* body));
+ if (body == NULL)
+ return NULL;
+ body->bd_text = bd_text;
+ body->bd_size = bd_size;
+
+ return body;
+}
+
+void mailimf_body_free(struct mailimf_body * body)
+{
+ free(body);
+}
+
+
+
+struct mailimf_field *
+mailimf_field_new(int fld_type,
+ struct mailimf_return * fld_return_path,
+ struct mailimf_orig_date * fld_resent_date,
+ struct mailimf_from * fld_resent_from,
+ struct mailimf_sender * fld_resent_sender,
+ struct mailimf_to * fld_resent_to,
+ struct mailimf_cc * fld_resent_cc,
+ struct mailimf_bcc * fld_resent_bcc,
+ struct mailimf_message_id * fld_resent_msg_id,
+ struct mailimf_orig_date * fld_orig_date,
+ struct mailimf_from * fld_from,
+ struct mailimf_sender * fld_sender,
+ struct mailimf_reply_to * fld_reply_to,
+ struct mailimf_to * fld_to,
+ struct mailimf_cc * fld_cc,
+ struct mailimf_bcc * fld_bcc,
+ struct mailimf_message_id * fld_message_id,
+ struct mailimf_in_reply_to * fld_in_reply_to,
+ struct mailimf_references * fld_references,
+ struct mailimf_subject * fld_subject,
+ struct mailimf_comments * fld_comments,
+ struct mailimf_keywords * fld_keywords,
+ struct mailimf_optional_field * fld_optional_field)
+{
+ struct mailimf_field * field;
+
+ field = malloc(sizeof(* field));
+ if (field == NULL)
+ return NULL;
+
+ field->fld_type = fld_type;
+ switch (fld_type) {
+ case MAILIMF_FIELD_RETURN_PATH:
+ field->fld_data.fld_return_path = fld_return_path;
+ break;
+ case MAILIMF_FIELD_RESENT_DATE:
+ field->fld_data.fld_resent_date = fld_resent_date;
+ break;
+ case MAILIMF_FIELD_RESENT_FROM:
+ field->fld_data.fld_resent_from = fld_resent_from;
+ break;
+ case MAILIMF_FIELD_RESENT_SENDER:
+ field->fld_data.fld_resent_sender = fld_resent_sender;
+ break;
+ case MAILIMF_FIELD_RESENT_TO:
+ field->fld_data.fld_resent_to = fld_resent_to;
+ break;
+ case MAILIMF_FIELD_RESENT_CC:
+ field->fld_data.fld_resent_cc = fld_resent_cc;
+ break;
+ case MAILIMF_FIELD_RESENT_BCC:
+ field->fld_data.fld_resent_bcc = fld_resent_bcc;
+ break;
+ case MAILIMF_FIELD_RESENT_MSG_ID:
+ field->fld_data.fld_resent_msg_id = fld_resent_msg_id;
+ break;
+ case MAILIMF_FIELD_ORIG_DATE:
+ field->fld_data.fld_orig_date = fld_orig_date;
+ break;
+ case MAILIMF_FIELD_FROM:
+ field->fld_data.fld_from = fld_from;
+ break;
+ case MAILIMF_FIELD_SENDER:
+ field->fld_data.fld_sender = fld_sender;
+ break;
+ case MAILIMF_FIELD_REPLY_TO:
+ field->fld_data.fld_reply_to = fld_reply_to;
+ break;
+ case MAILIMF_FIELD_TO:
+ field->fld_data.fld_to = fld_to;
+ break;
+ case MAILIMF_FIELD_CC:
+ field->fld_data.fld_cc = fld_cc;
+ break;
+ case MAILIMF_FIELD_BCC:
+ field->fld_data.fld_bcc = fld_bcc;
+ break;
+ case MAILIMF_FIELD_MESSAGE_ID:
+ field->fld_data.fld_message_id = fld_message_id;
+ break;
+ case MAILIMF_FIELD_IN_REPLY_TO:
+ field->fld_data.fld_in_reply_to = fld_in_reply_to;
+ break;
+ case MAILIMF_FIELD_REFERENCES:
+ field->fld_data.fld_references = fld_references;
+ break;
+ case MAILIMF_FIELD_SUBJECT:
+ field->fld_data.fld_subject = fld_subject;
+ break;
+ case MAILIMF_FIELD_COMMENTS:
+ field->fld_data.fld_comments = fld_comments;
+ break;
+ case MAILIMF_FIELD_KEYWORDS:
+ field->fld_data.fld_keywords = fld_keywords;
+ break;
+ case MAILIMF_FIELD_OPTIONAL_FIELD:
+ field->fld_data.fld_optional_field = fld_optional_field;
+ break;
+ }
+
+ return field;
+}
+
+void mailimf_field_free(struct mailimf_field * field)
+{
+ switch (field->fld_type) {
+ case MAILIMF_FIELD_RETURN_PATH:
+ mailimf_return_free(field->fld_data.fld_return_path);
+ break;
+ case MAILIMF_FIELD_RESENT_DATE:
+ mailimf_orig_date_free(field->fld_data.fld_resent_date);
+ break;
+ case MAILIMF_FIELD_RESENT_FROM:
+ mailimf_from_free(field->fld_data.fld_resent_from);
+ break;
+ case MAILIMF_FIELD_RESENT_SENDER:
+ mailimf_sender_free(field->fld_data.fld_resent_sender);
+ break;
+ case MAILIMF_FIELD_RESENT_TO:
+ mailimf_to_free(field->fld_data.fld_resent_to);
+ break;
+ case MAILIMF_FIELD_RESENT_CC:
+ mailimf_cc_free(field->fld_data.fld_resent_cc);
+ break;
+ case MAILIMF_FIELD_RESENT_BCC:
+ mailimf_bcc_free(field->fld_data.fld_resent_bcc);
+ break;
+ case MAILIMF_FIELD_RESENT_MSG_ID:
+ mailimf_message_id_free(field->fld_data.fld_resent_msg_id);
+ break;
+ case MAILIMF_FIELD_ORIG_DATE:
+ mailimf_orig_date_free(field->fld_data.fld_orig_date);
+ break;
+ case MAILIMF_FIELD_FROM:
+ mailimf_from_free(field->fld_data.fld_from);
+ break;
+ case MAILIMF_FIELD_SENDER:
+ mailimf_sender_free(field->fld_data.fld_sender);
+ break;
+ case MAILIMF_FIELD_REPLY_TO:
+ mailimf_reply_to_free(field->fld_data.fld_reply_to);
+ break;
+ case MAILIMF_FIELD_TO:
+ mailimf_to_free(field->fld_data.fld_to);
+ break;
+ case MAILIMF_FIELD_CC:
+ mailimf_cc_free(field->fld_data.fld_cc);
+ break;
+ case MAILIMF_FIELD_BCC:
+ mailimf_bcc_free(field->fld_data.fld_bcc);
+ break;
+ case MAILIMF_FIELD_MESSAGE_ID:
+ mailimf_message_id_free(field->fld_data.fld_message_id);
+ break;
+ case MAILIMF_FIELD_IN_REPLY_TO:
+ mailimf_in_reply_to_free(field->fld_data.fld_in_reply_to);
+ break;
+ case MAILIMF_FIELD_REFERENCES:
+ mailimf_references_free(field->fld_data.fld_references);
+ break;
+ case MAILIMF_FIELD_SUBJECT:
+ mailimf_subject_free(field->fld_data.fld_subject);
+ break;
+ case MAILIMF_FIELD_COMMENTS:
+ mailimf_comments_free(field->fld_data.fld_comments);
+ break;
+ case MAILIMF_FIELD_KEYWORDS:
+ mailimf_keywords_free(field->fld_data.fld_keywords);
+ break;
+ case MAILIMF_FIELD_OPTIONAL_FIELD:
+ mailimf_optional_field_free(field->fld_data.fld_optional_field);
+ break;
+ }
+
+ free(field);
+}
+
+struct mailimf_fields * mailimf_fields_new(clist * fld_list)
+{
+ struct mailimf_fields * fields;
+
+ fields = malloc(sizeof(* fields));
+ if (fields == NULL)
+ return NULL;
+
+ fields->fld_list = fld_list;
+
+ return fields;
+}
+
+void mailimf_fields_free(struct mailimf_fields * fields)
+{
+ if (fields->fld_list != NULL) {
+ clist_foreach(fields->fld_list, (clist_func) mailimf_field_free, NULL);
+ clist_free(fields->fld_list);
+ }
+ free(fields);
+}
+
+
+struct mailimf_orig_date * mailimf_orig_date_new(struct mailimf_date_time *
+ dt_date_time)
+{
+ struct mailimf_orig_date * orig_date;
+
+ orig_date = malloc(sizeof(* orig_date));
+ if (orig_date == NULL)
+ return NULL;
+
+ orig_date->dt_date_time = dt_date_time;
+
+ return orig_date;
+}
+
+void mailimf_orig_date_free(struct mailimf_orig_date * orig_date)
+{
+ if (orig_date->dt_date_time != NULL)
+ mailimf_date_time_free(orig_date->dt_date_time);
+ free(orig_date);
+}
+
+struct mailimf_from *
+mailimf_from_new(struct mailimf_mailbox_list * frm_mb_list)
+{
+ struct mailimf_from * from;
+
+ from = malloc(sizeof(* from));
+ if (from == NULL)
+ return NULL;
+
+ from->frm_mb_list = frm_mb_list;
+
+ return from;
+}
+
+void mailimf_from_free(struct mailimf_from * from)
+{
+ if (from->frm_mb_list != NULL)
+ mailimf_mailbox_list_free(from->frm_mb_list);
+ free(from);
+}
+
+struct mailimf_sender * mailimf_sender_new(struct mailimf_mailbox * snd_mb)
+{
+ struct mailimf_sender * sender;
+
+ sender = malloc(sizeof(* sender));
+ if (sender == NULL)
+ return NULL;
+
+ sender->snd_mb = snd_mb;
+
+ return sender;
+}
+
+void mailimf_sender_free(struct mailimf_sender * sender)
+{
+ if (sender->snd_mb != NULL)
+ mailimf_mailbox_free(sender->snd_mb);
+ free(sender);
+}
+
+struct mailimf_reply_to *
+mailimf_reply_to_new(struct mailimf_address_list * rt_addr_list)
+{
+ struct mailimf_reply_to * reply_to;
+
+ reply_to = malloc(sizeof(* reply_to));
+ if (reply_to == NULL)
+ return NULL;
+
+ reply_to->rt_addr_list = rt_addr_list;
+
+ return reply_to;
+}
+
+void mailimf_reply_to_free(struct mailimf_reply_to * reply_to)
+{
+ if (reply_to->rt_addr_list != NULL)
+ mailimf_address_list_free(reply_to->rt_addr_list);
+ free(reply_to);
+}
+
+struct mailimf_to * mailimf_to_new(struct mailimf_address_list * to_addr_list)
+{
+ struct mailimf_to * to;
+
+ to = malloc(sizeof(* to));
+ if (to == NULL)
+ return NULL;
+
+ to->to_addr_list = to_addr_list;
+
+ return to;
+}
+
+void mailimf_to_free(struct mailimf_to * to)
+{
+ if (to->to_addr_list != NULL)
+ mailimf_address_list_free(to->to_addr_list);
+ free(to);
+}
+
+struct mailimf_cc * mailimf_cc_new(struct mailimf_address_list * cc_addr_list)
+{
+ struct mailimf_cc * cc;
+
+ cc = malloc(sizeof(* cc));
+ if (cc == NULL)
+ return NULL;
+
+ cc->cc_addr_list = cc_addr_list;
+
+ return cc;
+}
+
+void mailimf_cc_free(struct mailimf_cc * cc)
+{
+ if (cc->cc_addr_list != NULL)
+ mailimf_address_list_free(cc->cc_addr_list);
+ free(cc);
+}
+
+struct mailimf_bcc *
+mailimf_bcc_new(struct mailimf_address_list * bcc_addr_list)
+{
+ struct mailimf_bcc * bcc;
+
+ bcc = malloc(sizeof(* bcc));
+ if (bcc == NULL)
+ return NULL;
+
+ bcc->bcc_addr_list = bcc_addr_list;
+
+ return bcc;
+}
+
+void mailimf_bcc_free(struct mailimf_bcc * bcc)
+{
+ if (bcc->bcc_addr_list != NULL)
+ mailimf_address_list_free(bcc->bcc_addr_list);
+ free(bcc);
+}
+
+struct mailimf_message_id * mailimf_message_id_new(char * mid_value)
+{
+ struct mailimf_message_id * message_id;
+
+ message_id = malloc(sizeof(* message_id));
+ if (message_id == NULL)
+ return NULL;
+
+ message_id->mid_value = mid_value;
+
+ return message_id;
+}
+
+void mailimf_message_id_free(struct mailimf_message_id * message_id)
+{
+ if (message_id->mid_value != NULL)
+ mailimf_msg_id_free(message_id->mid_value);
+ free(message_id);
+}
+
+struct mailimf_in_reply_to * mailimf_in_reply_to_new(clist * mid_list)
+{
+ struct mailimf_in_reply_to * in_reply_to;
+
+ in_reply_to = malloc(sizeof(* in_reply_to));
+ if (in_reply_to == NULL)
+ return NULL;
+
+ in_reply_to->mid_list = mid_list;
+
+ return in_reply_to;
+}
+
+void mailimf_in_reply_to_free(struct mailimf_in_reply_to * in_reply_to)
+{
+ clist_foreach(in_reply_to->mid_list,
+ (clist_func) mailimf_msg_id_free, NULL);
+ clist_free(in_reply_to->mid_list);
+ free(in_reply_to);
+}
+
+struct mailimf_references * mailimf_references_new(clist * mid_list)
+{
+ struct mailimf_references * ref;
+
+ ref = malloc(sizeof(* ref));
+ if (ref == NULL)
+ return NULL;
+
+ ref->mid_list = mid_list;
+
+ return ref;
+}
+
+void mailimf_references_free(struct mailimf_references * references)
+{
+ clist_foreach(references->mid_list,
+ (clist_func) mailimf_msg_id_free, NULL);
+ clist_free(references->mid_list);
+ free(references);
+}
+
+void mailimf_msg_id_free(char * msg_id)
+{
+ free(msg_id);
+}
+
+void mailimf_id_left_free(char * id_left)
+{
+ free(id_left);
+}
+
+void mailimf_id_right_free(char * id_right)
+{
+ free(id_right);
+}
+
+void mailimf_no_fold_quote_free(char * nfq)
+{
+ free(nfq);
+}
+
+void mailimf_no_fold_literal_free(char * nfl)
+{
+ free(nfl);
+}
+
+struct mailimf_subject * mailimf_subject_new(char * sbj_value)
+{
+ struct mailimf_subject * subject;
+
+ subject = malloc(sizeof(* subject));
+ if (subject == NULL)
+ return NULL;
+
+ subject->sbj_value = sbj_value;
+
+ return subject;
+}
+
+void mailimf_subject_free(struct mailimf_subject * subject)
+{
+ mailimf_unstructured_free(subject->sbj_value);
+ free(subject);
+}
+
+struct mailimf_comments * mailimf_comments_new(char * cm_value)
+{
+ struct mailimf_comments * comments;
+
+ comments = malloc(sizeof(* comments));
+ if (comments == NULL)
+ return NULL;
+
+ comments->cm_value = cm_value;
+
+ return comments;
+}
+
+void mailimf_comments_free(struct mailimf_comments * comments)
+{
+ mailimf_unstructured_free(comments->cm_value);
+ free(comments);
+}
+
+struct mailimf_keywords * mailimf_keywords_new(clist * kw_list)
+{
+ struct mailimf_keywords * keywords;
+
+ keywords = malloc(sizeof(* keywords));
+ if (keywords == NULL)
+ return NULL;
+
+ keywords->kw_list = kw_list;
+
+ return keywords;
+}
+
+void mailimf_keywords_free(struct mailimf_keywords * keywords)
+{
+ clist_foreach(keywords->kw_list, (clist_func) mailimf_phrase_free, NULL);
+ clist_free(keywords->kw_list);
+ free(keywords);
+}
+
+struct mailimf_return *
+mailimf_return_new(struct mailimf_path * ret_path)
+{
+ struct mailimf_return * return_path;
+
+ return_path = malloc(sizeof(* return_path));
+ if (return_path == NULL)
+ return NULL;
+
+ return_path->ret_path = ret_path;
+
+ return return_path;
+}
+
+void mailimf_return_free(struct mailimf_return * return_path)
+{
+ mailimf_path_free(return_path->ret_path);
+ free(return_path);
+}
+
+
+struct mailimf_path * mailimf_path_new(char * pt_addr_spec)
+{
+ struct mailimf_path * path;
+
+ path = malloc(sizeof(* path));
+ if (path == NULL)
+ return NULL;
+
+ path->pt_addr_spec = pt_addr_spec;
+
+ return path;
+}
+
+void mailimf_path_free(struct mailimf_path * path)
+{
+ if (path->pt_addr_spec != NULL)
+ mailimf_addr_spec_free(path->pt_addr_spec);
+ free(path);
+}
+
+struct mailimf_optional_field *
+mailimf_optional_field_new(char * fld_name, char * fld_value)
+{
+ struct mailimf_optional_field * opt_field;
+
+ opt_field = malloc(sizeof(* opt_field));
+ if (opt_field == NULL)
+ return NULL;
+
+ opt_field->fld_name = fld_name;
+ opt_field->fld_value = fld_value;
+
+ return opt_field;
+}
+
+void mailimf_optional_field_free(struct mailimf_optional_field * opt_field)
+{
+ mailimf_field_name_free(opt_field->fld_name);
+ mailimf_unstructured_free(opt_field->fld_value);
+ free(opt_field);
+}
+
+void mailimf_field_name_free(char * field_name)
+{
+ free(field_name);
+}
diff --git a/libetpan/src/low-level/imf/mailimf_types.h b/libetpan/src/low-level/imf/mailimf_types.h
new file mode 100644
index 0000000..e73db48
--- a/dev/null
+++ b/libetpan/src/low-level/imf/mailimf_types.h
@@ -0,0 +1,793 @@
+/*
+ * 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$
+ */
+
+#ifndef MAILIMF_TYPES_H
+
+#define MAILIMF_TYPES_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <libetpan/clist.h>
+#include <sys/types.h>
+
+/*
+ IMPORTANT NOTE:
+
+ All allocation functions will take as argument allocated data
+ and will store these data in the structure they will allocate.
+ Data should be persistant during all the use of the structure
+ and will be freed by the free function of the structure
+
+ allocation functions will return NULL on failure
+*/
+
+/*
+ mailimf_date_time is a date
+
+ - day is the day of month (1 to 31)
+
+ - month (1 to 12)
+
+ - year (4 digits)
+
+ - hour (0 to 23)
+
+ - min (0 to 59)
+
+ - sec (0 to 59)
+
+ - zone (this is the decimal value that we can read, for example:
+ for "-0200", the value is -200)
+*/
+
+struct mailimf_date_time {
+ int dt_day;
+ int dt_month;
+ int dt_year;
+ int dt_hour;
+ int dt_min;
+ int dt_sec;
+ int dt_zone;
+};
+
+struct mailimf_date_time *
+mailimf_date_time_new(int dt_day, int dt_month, int dt_year,
+ int dt_hour, int dt_min, int dt_sec, int dt_zone);
+
+void mailimf_date_time_free(struct mailimf_date_time * date_time);
+
+
+
+/* this is the type of address */
+
+enum {
+ MAILIMF_ADDRESS_ERROR, /* on parse error */
+ MAILIMF_ADDRESS_MAILBOX, /* if this is a mailbox (mailbox@domain) */
+ MAILIMF_ADDRESS_GROUP, /* if this is a group
+ (group_name: address1@domain1,
+ address2@domain2; ) */
+};
+
+/*
+ mailimf_address is an address
+
+ - type can be MAILIMF_ADDRESS_MAILBOX or MAILIMF_ADDRESS_GROUP
+
+ - mailbox is a mailbox if type is MAILIMF_ADDRESS_MAILBOX
+
+ - group is a group if type is MAILIMF_ADDRESS_GROUP
+*/
+
+struct mailimf_address {
+ int ad_type;
+ union {
+ struct mailimf_mailbox * ad_mailbox; /* can be NULL */
+ struct mailimf_group * ad_group; /* can be NULL */
+ } ad_data;
+};
+
+
+struct mailimf_address *
+mailimf_address_new(int ad_type, struct mailimf_mailbox * ad_mailbox,
+ struct mailimf_group * ad_group);
+
+void mailimf_address_free(struct mailimf_address * address);
+
+
+
+/*
+ mailimf_mailbox is a mailbox
+
+ - display_name is the name that will be displayed for this mailbox,
+ for example 'name' in '"name" <mailbox@domain>,
+ should be allocated with malloc()
+
+ - addr_spec is the mailbox, for example 'mailbox@domain'
+ in '"name" <mailbox@domain>, should be allocated with malloc()
+*/
+
+struct mailimf_mailbox {
+ char * mb_display_name; /* can be NULL */
+ char * mb_addr_spec; /* != NULL */
+};
+
+struct mailimf_mailbox *
+mailimf_mailbox_new(char * mb_display_name, char * mb_addr_spec);
+
+void mailimf_mailbox_free(struct mailimf_mailbox * mailbox);
+
+
+
+/*
+ mailimf_group is a group
+
+ - display_name is the name that will be displayed for this group,
+ for example 'group_name' in
+ 'group_name: address1@domain1, address2@domain2;', should be allocated
+ with malloc()
+
+ - mb_list is a list of mailboxes
+*/
+
+struct mailimf_group {
+ char * grp_display_name; /* != NULL */
+ struct mailimf_mailbox_list * grp_mb_list; /* can be NULL */
+};
+
+struct mailimf_group *
+mailimf_group_new(char * grp_display_name,
+ struct mailimf_mailbox_list * grp_mb_list);
+
+void mailimf_group_free(struct mailimf_group * group);
+
+
+
+/*
+ mailimf_mailbox_list is a list of mailboxes
+
+ - list is a list of mailboxes
+*/
+
+struct mailimf_mailbox_list {
+ clist * mb_list; /* list of (struct mailimf_mailbox *), != NULL */
+};
+
+struct mailimf_mailbox_list *
+mailimf_mailbox_list_new(clist * mb_list);
+
+void mailimf_mailbox_list_free(struct mailimf_mailbox_list * mb_list);
+
+
+
+/*
+ mailimf_address_list is a list of addresses
+
+ - list is a list of addresses
+*/
+
+struct mailimf_address_list {
+ clist * ad_list; /* list of (struct mailimf_address *), != NULL */
+};
+
+struct mailimf_address_list *
+mailimf_address_list_new(clist * ad_list);
+
+void mailimf_address_list_free(struct mailimf_address_list * addr_list);
+
+
+
+
+
+/*
+ mailimf_body is the text part of a message
+
+ - text is the beginning of the text part, it is a substring
+ of an other string
+
+ - size is the size of the text part
+*/
+
+struct mailimf_body {
+ const char * bd_text; /* != NULL */
+ size_t bd_size;
+};
+
+struct mailimf_body * mailimf_body_new(const char * bd_text, size_t bd_size);
+
+void mailimf_body_free(struct mailimf_body * body);
+
+
+
+
+/*
+ mailimf_message is the content of the message
+
+ - msg_fields is the header fields of the message
+
+ - msg_body is the text part of the message
+*/
+
+struct mailimf_message {
+ struct mailimf_fields * msg_fields; /* != NULL */
+ struct mailimf_body * msg_body; /* != NULL */
+};
+
+struct mailimf_message *
+mailimf_message_new(struct mailimf_fields * msg_fields,
+ struct mailimf_body * msg_body);
+
+void mailimf_message_free(struct mailimf_message * message);
+
+
+
+
+/*
+ mailimf_fields is a list of header fields
+
+ - fld_list is a list of header fields
+*/
+
+struct mailimf_fields {
+ clist * fld_list; /* list of (struct mailimf_field *), != NULL */
+};
+
+struct mailimf_fields * mailimf_fields_new(clist * fld_list);
+
+void mailimf_fields_free(struct mailimf_fields * fields);
+
+
+
+/* this is a type of field */
+
+enum {
+ MAILIMF_FIELD_NONE, /* on parse error */
+ MAILIMF_FIELD_RETURN_PATH, /* Return-Path */
+ MAILIMF_FIELD_RESENT_DATE, /* Resent-Date */
+ MAILIMF_FIELD_RESENT_FROM, /* Resent-From */
+ MAILIMF_FIELD_RESENT_SENDER, /* Resent-Sender */
+ MAILIMF_FIELD_RESENT_TO, /* Resent-To */
+ MAILIMF_FIELD_RESENT_CC, /* Resent-Cc */
+ MAILIMF_FIELD_RESENT_BCC, /* Resent-Bcc */
+ MAILIMF_FIELD_RESENT_MSG_ID, /* Resent-Message-ID */
+ MAILIMF_FIELD_ORIG_DATE, /* Date */
+ MAILIMF_FIELD_FROM, /* From */
+ MAILIMF_FIELD_SENDER, /* Sender */
+ MAILIMF_FIELD_REPLY_TO, /* Reply-To */
+ MAILIMF_FIELD_TO, /* To */
+ MAILIMF_FIELD_CC, /* Cc */
+ MAILIMF_FIELD_BCC, /* Bcc */
+ MAILIMF_FIELD_MESSAGE_ID, /* Message-ID */
+ MAILIMF_FIELD_IN_REPLY_TO, /* In-Reply-To */
+ MAILIMF_FIELD_REFERENCES, /* References */
+ MAILIMF_FIELD_SUBJECT, /* Subject */
+ MAILIMF_FIELD_COMMENTS, /* Comments */
+ MAILIMF_FIELD_KEYWORDS, /* Keywords */
+ MAILIMF_FIELD_OPTIONAL_FIELD, /* other field */
+};
+
+/*
+ mailimf_field is a field
+
+ - fld_type is the type of the field
+
+ - fld_data.fld_return_path is the parsed content of the Return-Path
+ field if type is MAILIMF_FIELD_RETURN_PATH
+
+ - fld_data.fld_resent_date is the parsed content of the Resent-Date field
+ if type is MAILIMF_FIELD_RESENT_DATE
+
+ - fld_data.fld_resent_from is the parsed content of the Resent-From field
+
+ - fld_data.fld_resent_sender is the parsed content of the Resent-Sender field
+
+ - fld_data.fld_resent_to is the parsed content of the Resent-To field
+
+ - fld_data.fld_resent_cc is the parsed content of the Resent-Cc field
+
+ - fld_data.fld_resent_bcc is the parsed content of the Resent-Bcc field
+
+ - fld_data.fld_resent_msg_id is the parsed content of the Resent-Message-ID
+ field
+
+ - fld_data.fld_orig_date is the parsed content of the Date field
+
+ - fld_data.fld_from is the parsed content of the From field
+
+ - fld_data.fld_sender is the parsed content of the Sender field
+
+ - fld_data.fld_reply_to is the parsed content of the Reply-To field
+
+ - fld_data.fld_to is the parsed content of the To field
+
+ - fld_data.fld_cc is the parsed content of the Cc field
+
+ - fld_data.fld_bcc is the parsed content of the Bcc field
+
+ - fld_data.fld_message_id is the parsed content of the Message-ID field
+
+ - fld_data.fld_in_reply_to is the parsed content of the In-Reply-To field
+
+ - fld_data.fld_references is the parsed content of the References field
+
+ - fld_data.fld_subject is the content of the Subject field
+
+ - fld_data.fld_comments is the content of the Comments field
+
+ - fld_data.fld_keywords is the parsed content of the Keywords field
+
+ - fld_data.fld_optional_field is an other field and is not parsed
+*/
+
+#define LIBETPAN_MAILIMF_FIELD_UNION
+
+struct mailimf_field {
+ int fld_type;
+ union {
+ struct mailimf_return * fld_return_path; /* can be NULL */
+ struct mailimf_orig_date * fld_resent_date; /* can be NULL */
+ struct mailimf_from * fld_resent_from; /* can be NULL */
+ struct mailimf_sender * fld_resent_sender; /* can be NULL */
+ struct mailimf_to * fld_resent_to; /* can be NULL */
+ struct mailimf_cc * fld_resent_cc; /* can be NULL */
+ struct mailimf_bcc * fld_resent_bcc; /* can be NULL */
+ struct mailimf_message_id * fld_resent_msg_id; /* can be NULL */
+ struct mailimf_orig_date * fld_orig_date; /* can be NULL */
+ struct mailimf_from * fld_from; /* can be NULL */
+ struct mailimf_sender * fld_sender; /* can be NULL */
+ struct mailimf_reply_to * fld_reply_to; /* can be NULL */
+ struct mailimf_to * fld_to; /* can be NULL */
+ struct mailimf_cc * fld_cc; /* can be NULL */
+ struct mailimf_bcc * fld_bcc; /* can be NULL */
+ struct mailimf_message_id * fld_message_id; /* can be NULL */
+ struct mailimf_in_reply_to * fld_in_reply_to; /* can be NULL */
+ struct mailimf_references * fld_references; /* can be NULL */
+ struct mailimf_subject * fld_subject; /* can be NULL */
+ struct mailimf_comments * fld_comments; /* can be NULL */
+ struct mailimf_keywords * fld_keywords; /* can be NULL */
+ struct mailimf_optional_field * fld_optional_field; /* can be NULL */
+ } fld_data;
+};
+
+struct mailimf_field *
+mailimf_field_new(int fld_type,
+ struct mailimf_return * fld_return_path,
+ struct mailimf_orig_date * fld_resent_date,
+ struct mailimf_from * fld_resent_from,
+ struct mailimf_sender * fld_resent_sender,
+ struct mailimf_to * fld_resent_to,
+ struct mailimf_cc * fld_resent_cc,
+ struct mailimf_bcc * fld_resent_bcc,
+ struct mailimf_message_id * fld_resent_msg_id,
+ struct mailimf_orig_date * fld_orig_date,
+ struct mailimf_from * fld_from,
+ struct mailimf_sender * fld_sender,
+ struct mailimf_reply_to * fld_reply_to,
+ struct mailimf_to * fld_to,
+ struct mailimf_cc * fld_cc,
+ struct mailimf_bcc * fld_bcc,
+ struct mailimf_message_id * fld_message_id,
+ struct mailimf_in_reply_to * fld_in_reply_to,
+ struct mailimf_references * fld_references,
+ struct mailimf_subject * fld_subject,
+ struct mailimf_comments * fld_comments,
+ struct mailimf_keywords * fld_keywords,
+ struct mailimf_optional_field * fld_optional_field);
+
+void mailimf_field_free(struct mailimf_field * field);
+
+
+
+/*
+ mailimf_orig_date is the parsed Date field
+
+ - date_time is the parsed date
+*/
+
+struct mailimf_orig_date {
+ struct mailimf_date_time * dt_date_time; /* != NULL */
+};
+
+struct mailimf_orig_date * mailimf_orig_date_new(struct mailimf_date_time *
+ dt_date_time);
+
+void mailimf_orig_date_free(struct mailimf_orig_date * orig_date);
+
+
+
+
+/*
+ mailimf_from is the parsed From field
+
+ - mb_list is the parsed mailbox list
+*/
+
+struct mailimf_from {
+ struct mailimf_mailbox_list * frm_mb_list; /* != NULL */
+};
+
+struct mailimf_from *
+mailimf_from_new(struct mailimf_mailbox_list * frm_mb_list);
+
+void mailimf_from_free(struct mailimf_from * from);
+
+
+
+/*
+ mailimf_sender is the parsed Sender field
+
+ - snd_mb is the parsed mailbox
+*/
+
+struct mailimf_sender {
+ struct mailimf_mailbox * snd_mb; /* != NULL */
+};
+
+struct mailimf_sender * mailimf_sender_new(struct mailimf_mailbox * snd_mb);
+
+void mailimf_sender_free(struct mailimf_sender * sender);
+
+
+
+
+/*
+ mailimf_reply_to is the parsed Reply-To field
+
+ - rt_addr_list is the parsed address list
+ */
+
+struct mailimf_reply_to {
+ struct mailimf_address_list * rt_addr_list; /* != NULL */
+};
+
+struct mailimf_reply_to *
+mailimf_reply_to_new(struct mailimf_address_list * rt_addr_list);
+
+void mailimf_reply_to_free(struct mailimf_reply_to * reply_to);
+
+
+
+
+/*
+ mailimf_to is the parsed To field
+
+ - to_addr_list is the parsed address list
+*/
+
+struct mailimf_to {
+ struct mailimf_address_list * to_addr_list; /* != NULL */
+};
+
+struct mailimf_to * mailimf_to_new(struct mailimf_address_list * to_addr_list);
+
+void mailimf_to_free(struct mailimf_to * to);
+
+
+
+
+/*
+ mailimf_cc is the parsed Cc field
+
+ - cc_addr_list is the parsed addres list
+*/
+
+struct mailimf_cc {
+ struct mailimf_address_list * cc_addr_list; /* != NULL */
+};
+
+struct mailimf_cc * mailimf_cc_new(struct mailimf_address_list * cc_addr_list);
+
+void mailimf_cc_free(struct mailimf_cc * cc);
+
+
+
+
+/*
+ mailimf_bcc is the parsed Bcc field
+
+ - bcc_addr_list is the parsed addres list
+*/
+
+struct mailimf_bcc {
+ struct mailimf_address_list * bcc_addr_list; /* can be NULL */
+};
+
+struct mailimf_bcc *
+mailimf_bcc_new(struct mailimf_address_list * bcc_addr_list);
+
+void mailimf_bcc_free(struct mailimf_bcc * bcc);
+
+
+
+/*
+ mailimf_message_id is the parsed Message-ID field
+
+ - mid_value is the message identifier
+*/
+
+struct mailimf_message_id {
+ char * mid_value; /* != NULL */
+};
+
+struct mailimf_message_id * mailimf_message_id_new(char * mid_value);
+
+void mailimf_message_id_free(struct mailimf_message_id * message_id);
+
+
+
+
+/*
+ mailimf_in_reply_to is the parsed In-Reply-To field
+
+ - mid_list is the list of message identifers
+*/
+
+struct mailimf_in_reply_to {
+ clist * mid_list; /* list of (char *), != NULL */
+};
+
+struct mailimf_in_reply_to * mailimf_in_reply_to_new(clist * mid_list);
+
+void mailimf_in_reply_to_free(struct mailimf_in_reply_to * in_reply_to);
+
+
+
+/*
+ mailimf_references is the parsed References field
+
+ - msg_id_list is the list of message identifiers
+ */
+
+struct mailimf_references {
+ clist * mid_list; /* list of (char *) */
+ /* != NULL */
+};
+
+struct mailimf_references * mailimf_references_new(clist * mid_list);
+
+void mailimf_references_free(struct mailimf_references * references);
+
+
+
+/*
+ mailimf_subject is the parsed Subject field
+
+ - sbj_value is the value of the field
+*/
+
+struct mailimf_subject {
+ char * sbj_value; /* != NULL */
+};
+
+struct mailimf_subject * mailimf_subject_new(char * sbj_value);
+
+void mailimf_subject_free(struct mailimf_subject * subject);
+
+
+/*
+ mailimf_comments is the parsed Comments field
+
+ - cm_value is the value of the field
+*/
+
+struct mailimf_comments {
+ char * cm_value; /* != NULL */
+};
+
+struct mailimf_comments * mailimf_comments_new(char * cm_value);
+
+void mailimf_comments_free(struct mailimf_comments * comments);
+
+
+/*
+ mailimf_keywords is the parsed Keywords field
+
+ - kw_list is the list of keywords
+*/
+
+struct mailimf_keywords {
+ clist * kw_list; /* list of (char *), != NULL */
+};
+
+struct mailimf_keywords * mailimf_keywords_new(clist * kw_list);
+
+void mailimf_keywords_free(struct mailimf_keywords * keywords);
+
+
+/*
+ mailimf_return is the parsed Return-Path field
+
+ - ret_path is the parsed value of Return-Path
+*/
+
+struct mailimf_return {
+ struct mailimf_path * ret_path; /* != NULL */
+};
+
+struct mailimf_return *
+mailimf_return_new(struct mailimf_path * ret_path);
+
+void mailimf_return_free(struct mailimf_return * return_path);
+
+
+/*
+ mailimf_path is the parsed value of Return-Path
+
+ - pt_addr_spec is a mailbox
+*/
+
+struct mailimf_path {
+ char * pt_addr_spec; /* can be NULL */
+};
+
+struct mailimf_path * mailimf_path_new(char * pt_addr_spec);
+
+void mailimf_path_free(struct mailimf_path * path);
+
+
+/*
+ mailimf_optional_field is a non-parsed field
+
+ - fld_name is the name of the field
+
+ - fld_value is the value of the field
+*/
+
+struct mailimf_optional_field {
+ char * fld_name; /* != NULL */
+ char * fld_value; /* != NULL */
+};
+
+struct mailimf_optional_field *
+mailimf_optional_field_new(char * fld_name, char * fld_value);
+
+void mailimf_optional_field_free(struct mailimf_optional_field * opt_field);
+
+
+/*
+ mailimf_fields is the native structure that IMF module will use,
+ this module will provide an easier structure to use when parsing fields.
+
+ mailimf_single_fields is an easier structure to get parsed fields,
+ rather than iteration over the list of fields
+
+ - fld_orig_date is the parsed "Date" field
+
+ - fld_from is the parsed "From" field
+
+ - fld_sender is the parsed "Sender "field
+
+ - fld_reply_to is the parsed "Reply-To" field
+
+ - fld_to is the parsed "To" field
+
+ - fld_cc is the parsed "Cc" field
+
+ - fld_bcc is the parsed "Bcc" field
+
+ - fld_message_id is the parsed "Message-ID" field
+
+ - fld_in_reply_to is the parsed "In-Reply-To" field
+
+ - fld_references is the parsed "References" field
+
+ - fld_subject is the parsed "Subject" field
+
+ - fld_comments is the parsed "Comments" field
+
+ - fld_keywords is the parsed "Keywords" field
+*/
+
+struct mailimf_single_fields {
+ struct mailimf_orig_date * fld_orig_date; /* can be NULL */
+ struct mailimf_from * fld_from; /* can be NULL */
+ struct mailimf_sender * fld_sender; /* can be NULL */
+ struct mailimf_reply_to * fld_reply_to; /* can be NULL */
+ struct mailimf_to * fld_to; /* can be NULL */
+ struct mailimf_cc * fld_cc; /* can be NULL */
+ struct mailimf_bcc * fld_bcc; /* can be NULL */
+ struct mailimf_message_id * fld_message_id; /* can be NULL */
+ struct mailimf_in_reply_to * fld_in_reply_to; /* can be NULL */
+ struct mailimf_references * fld_references; /* can be NULL */
+ struct mailimf_subject * fld_subject; /* can be NULL */
+ struct mailimf_comments * fld_comments; /* can be NULL */
+ struct mailimf_keywords * fld_keywords; /* can be NULL */
+};
+
+
+
+
+
+
+/* internal use */
+
+void mailimf_atom_free(char * atom);
+
+void mailimf_dot_atom_free(char * dot_atom);
+
+void mailimf_dot_atom_text_free(char * dot_atom);
+
+void mailimf_quoted_string_free(char * quoted_string);
+
+void mailimf_word_free(char * word);
+
+void mailimf_phrase_free(char * phrase);
+
+void mailimf_unstructured_free(char * unstructured);
+
+void mailimf_angle_addr_free(char * angle_addr);
+
+void mailimf_display_name_free(char * display_name);
+
+void mailimf_addr_spec_free(char * addr_spec);
+
+void mailimf_local_part_free(char * local_part);
+
+void mailimf_domain_free(char * domain);
+
+void mailimf_domain_literal_free(char * domain);
+
+void mailimf_msg_id_free(char * msg_id);
+
+void mailimf_id_left_free(char * id_left);
+
+void mailimf_id_right_free(char * id_right);
+
+void mailimf_no_fold_quote_free(char * nfq);
+
+void mailimf_no_fold_literal_free(char * nfl);
+
+void mailimf_field_name_free(char * field_name);
+
+
+
+/* these are the possible returned error codes */
+
+enum {
+ MAILIMF_NO_ERROR = 0,
+ MAILIMF_ERROR_PARSE,
+ MAILIMF_ERROR_MEMORY,
+ MAILIMF_ERROR_INVAL,
+ MAILIMF_ERROR_FILE,
+};
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libetpan/src/low-level/imf/mailimf_types_helper.c b/libetpan/src/low-level/imf/mailimf_types_helper.c
new file mode 100644
index 0000000..a4f669c
--- a/dev/null
+++ b/libetpan/src/low-level/imf/mailimf_types_helper.c
@@ -0,0 +1,1636 @@
+/*
+ * 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.
+ */
+
+#include "mailimf_types_helper.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "mailimf.h"
+
+struct mailimf_mailbox_list *
+mailimf_mailbox_list_new_empty()
+{
+ clist * list;
+ struct mailimf_mailbox_list * mb_list;
+
+ list = clist_new();
+ if (list == NULL)
+ return NULL;
+
+ mb_list = mailimf_mailbox_list_new(list);
+ if (mb_list == NULL)
+ return NULL;
+
+ return mb_list;
+}
+
+int mailimf_mailbox_list_add(struct mailimf_mailbox_list * mailbox_list,
+ struct mailimf_mailbox * mb)
+{
+ int r;
+
+ r = clist_append(mailbox_list->mb_list, mb);
+ if (r < 0)
+ return MAILIMF_ERROR_MEMORY;
+
+ return MAILIMF_NO_ERROR;
+}
+
+int mailimf_mailbox_list_add_parse(struct mailimf_mailbox_list * mailbox_list,
+ char * mb_str)
+{
+ int r;
+ size_t cur_token;
+ struct mailimf_mailbox * mb;
+ int res;
+
+ cur_token = 0;
+ r = mailimf_mailbox_parse(mb_str, strlen(mb_str), &cur_token, &mb);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ r = mailimf_mailbox_list_add(mailbox_list, mb);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto free;
+ }
+
+ return MAILIMF_NO_ERROR;
+
+ free:
+ mailimf_mailbox_free(mb);
+ err:
+ return res;
+}
+
+int mailimf_mailbox_list_add_mb(struct mailimf_mailbox_list * mailbox_list,
+ char * display_name, char * address)
+{
+ int r;
+ struct mailimf_mailbox * mb;
+ int res;
+
+ mb = mailimf_mailbox_new(display_name, address);
+ if (mb == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto err;
+ }
+
+ r = mailimf_mailbox_list_add(mailbox_list, mb);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto free;
+ }
+
+ return MAILIMF_NO_ERROR;
+
+ free:
+ mailimf_mailbox_free(mb);
+ err:
+ return res;
+}
+
+
+
+struct mailimf_address_list *
+mailimf_address_list_new_empty()
+{
+ clist * list;
+ struct mailimf_address_list * addr_list;
+
+ list = clist_new();
+ if (list == NULL)
+ return NULL;
+
+ addr_list = mailimf_address_list_new(list);
+ if (addr_list == NULL)
+ return NULL;
+
+ return addr_list;
+}
+
+int mailimf_address_list_add(struct mailimf_address_list * address_list,
+ struct mailimf_address * addr)
+{
+ int r;
+
+ r = clist_append(address_list->ad_list, addr);
+ if (r < 0)
+ return MAILIMF_ERROR_MEMORY;
+
+ return MAILIMF_NO_ERROR;
+}
+
+int mailimf_address_list_add_parse(struct mailimf_address_list * address_list,
+ char * addr_str)
+{
+ int r;
+ size_t cur_token;
+ struct mailimf_address * addr;
+ int res;
+
+ cur_token = 0;
+ r = mailimf_address_parse(addr_str, strlen(addr_str), &cur_token, &addr);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ r = mailimf_address_list_add(address_list, addr);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto free;
+ }
+
+ return MAILIMF_NO_ERROR;
+
+ free:
+ mailimf_address_free(addr);
+ err:
+ return res;
+}
+
+int mailimf_address_list_add_mb(struct mailimf_address_list * address_list,
+ char * display_name, char * address)
+{
+ int r;
+ struct mailimf_mailbox * mb;
+ struct mailimf_address * addr;
+ int res;
+
+ mb = mailimf_mailbox_new(display_name, address);
+ if (mb == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto err;
+ }
+
+ addr = mailimf_address_new(MAILIMF_ADDRESS_MAILBOX, mb, NULL);
+ if (addr == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free_mb;
+ }
+
+ r = mailimf_address_list_add(address_list, addr);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto free_addr;
+ }
+
+ return MAILIMF_NO_ERROR;
+
+ free_addr:
+ mailimf_address_free(addr);
+ free_mb:
+ mailimf_mailbox_free(mb);
+ err:
+ return res;
+}
+
+
+#if 0
+struct mailimf_resent_fields_list *
+mailimf_resent_fields_list_new_empty()
+{
+ clist * list;
+ struct mailimf_resent_fields_list * rf_list;
+
+ list = clist_new();
+ if (list == NULL)
+ return NULL;
+
+ rf_list = mailimf_resent_fields_list_new(list);
+ if (rf_list == NULL)
+ return NULL;
+
+ return rf_list;
+}
+
+int mailimf_resent_fields_add(struct mailimf_resent_fields_list * fields,
+ struct mailimf_resent_field * field)
+{
+ int r;
+
+ r = clist_append(fields->list, field);
+ if (r < 0)
+ return MAILIMF_ERROR_MEMORY;
+
+ return MAILIMF_NO_ERROR;
+}
+#endif
+
+
+static void detach_free_common_fields(struct mailimf_orig_date * imf_date,
+ struct mailimf_from * imf_from,
+ struct mailimf_sender * imf_sender,
+ struct mailimf_to * imf_to,
+ struct mailimf_cc * imf_cc,
+ struct mailimf_bcc * imf_bcc,
+ struct mailimf_message_id * imf_msg_id)
+{
+ if (imf_date != NULL) {
+ imf_date->dt_date_time = NULL;
+ mailimf_orig_date_free(imf_date);
+ }
+ if (imf_from != NULL) {
+ imf_from->frm_mb_list = NULL;
+ mailimf_from_free(imf_from);
+ }
+ if (imf_sender != NULL) {
+ imf_sender->snd_mb = NULL;
+ mailimf_sender_free(imf_sender);
+ }
+ if (imf_to != NULL) {
+ imf_to->to_addr_list = NULL;
+ mailimf_to_free(imf_to);
+ }
+ if (imf_cc != NULL) {
+ imf_cc->cc_addr_list = NULL;
+ mailimf_to_free(imf_to);
+ }
+ if (imf_bcc != NULL) {
+ imf_bcc->bcc_addr_list = NULL;
+ mailimf_bcc_free(imf_bcc);
+ }
+ if (imf_msg_id != NULL) {
+ imf_msg_id->mid_value = NULL;
+ mailimf_message_id_free(imf_msg_id);
+ }
+}
+
+static void detach_resent_field(struct mailimf_field * field)
+{
+ field->fld_type = MAILIMF_FIELD_NONE;
+ mailimf_field_free(field);
+}
+
+int
+mailimf_resent_fields_add_data(struct mailimf_fields * fields,
+ struct mailimf_date_time * resent_date,
+ struct mailimf_mailbox_list * resent_from,
+ struct mailimf_mailbox * resent_sender,
+ struct mailimf_address_list * resent_to,
+ struct mailimf_address_list * resent_cc,
+ struct mailimf_address_list * resent_bcc,
+ char * resent_msg_id)
+{
+ struct mailimf_orig_date * imf_resent_date;
+ struct mailimf_from * imf_resent_from;
+ struct mailimf_sender * imf_resent_sender;
+ struct mailimf_to * imf_resent_to;
+ struct mailimf_cc * imf_resent_cc;
+ struct mailimf_bcc * imf_resent_bcc;
+ struct mailimf_message_id * imf_resent_msg_id;
+ struct mailimf_field * field;
+ int r;
+
+ imf_resent_date = NULL;
+ imf_resent_from = NULL;
+ imf_resent_sender = NULL;
+ imf_resent_to = NULL;
+ imf_resent_cc = NULL;
+ imf_resent_bcc = NULL;
+ imf_resent_msg_id = NULL;
+ field = NULL;
+
+ if (resent_date != NULL) {
+ imf_resent_date = mailimf_orig_date_new(resent_date);
+ if (imf_resent_date == NULL)
+ goto free;
+ field = mailimf_field_new(MAILIMF_FIELD_RESENT_DATE,
+ NULL /* return-path */,
+ imf_resent_date /* resent date */,
+ NULL /* resent from */,
+ NULL /* resent sender */,
+ NULL /* resent to */,
+ NULL /* resent cc */,
+ NULL /* resent bcc */,
+ NULL /* resent msg id */,
+ NULL /* date */,
+ NULL /* from */,
+ NULL /* sender */,
+ NULL /* reply-to */,
+ NULL /* to */,
+ NULL /* cc */,
+ NULL /* bcc */,
+ NULL /* message id */,
+ NULL /* in reply to */,
+ NULL /* references */,
+ NULL /* subject */,
+ NULL /* comments */,
+ NULL /* keywords */,
+ NULL /* optional field */);
+ if (field == NULL)
+ goto free;
+ r = mailimf_fields_add(fields, field);
+ if (r != MAILIMF_NO_ERROR)
+ goto free_field;
+ }
+
+ if (resent_from != NULL) {
+ imf_resent_from = mailimf_from_new(resent_from);
+ if (imf_resent_from == NULL)
+ goto free_field;
+ field = mailimf_field_new(MAILIMF_FIELD_RESENT_FROM,
+ NULL /* return-path */,
+ NULL /* resent date */,
+ imf_resent_from /* resent from */,
+ NULL /* resent sender */,
+ NULL /* resent to */,
+ NULL /* resent cc */,
+ NULL /* resent bcc */,
+ NULL /* resent msg id */,
+ NULL /* date */,
+ NULL /* from */,
+ NULL /* sender */,
+ NULL /* reply-to */,
+ NULL /* to */,
+ NULL /* cc */,
+ NULL /* bcc */,
+ NULL /* message id */,
+ NULL /* in reply to */,
+ NULL /* references */,
+ NULL /* subject */,
+ NULL /* comments */,
+ NULL /* keywords */,
+ NULL /* optional field */);
+ if (field == NULL)
+ goto free;
+ r = mailimf_fields_add(fields, field);
+ if (r != MAILIMF_NO_ERROR)
+ goto free_field;
+ }
+
+ if (resent_sender != NULL) {
+ imf_resent_sender = mailimf_sender_new(resent_sender);
+ if (imf_resent_sender == NULL)
+ goto free;
+ field = mailimf_field_new(MAILIMF_FIELD_RESENT_SENDER,
+ NULL /* return-path */,
+ NULL /* resent date */,
+ NULL /* resent from */,
+ imf_resent_sender /* resent sender */,
+ NULL /* resent to */,
+ NULL /* resent cc */,
+ NULL /* resent bcc */,
+ NULL /* resent msg id */,
+ NULL /* date */,
+ NULL /* from */,
+ NULL /* sender */,
+ NULL /* reply-to */,
+ NULL /* to */,
+ NULL /* cc */,
+ NULL /* bcc */,
+ NULL /* message id */,
+ NULL /* in reply to */,
+ NULL /* references */,
+ NULL /* subject */,
+ NULL /* comments */,
+ NULL /* keywords */,
+ NULL /* optional field */);
+ if (field == NULL)
+ goto free;
+ r = mailimf_fields_add(fields, field);
+ if (r != MAILIMF_NO_ERROR)
+ goto free_field;
+ }
+
+ if (resent_to != NULL) {
+ imf_resent_to = mailimf_to_new(resent_to);
+ if (imf_resent_to == NULL)
+ goto free;
+ field = mailimf_field_new(MAILIMF_FIELD_RESENT_TO,
+ NULL /* return-path */,
+ NULL /* resent date */,
+ NULL /* resent from */,
+ NULL /* resent sender */,
+ imf_resent_to /* resent to */,
+ NULL /* resent cc */,
+ NULL /* resent bcc */,
+ NULL /* resent msg id */,
+ NULL /* date */,
+ NULL /* from */,
+ NULL /* sender */,
+ NULL /* reply-to */,
+ NULL /* to */,
+ NULL /* cc */,
+ NULL /* bcc */,
+ NULL /* message id */,
+ NULL /* in reply to */,
+ NULL /* references */,
+ NULL /* subject */,
+ NULL /* comments */,
+ NULL /* keywords */,
+ NULL /* optional field */);
+ if (field == NULL)
+ goto free;
+ r = mailimf_fields_add(fields, field);
+ if (r != MAILIMF_NO_ERROR)
+ goto free_field;
+ }
+
+ if (resent_cc != NULL) {
+ imf_resent_cc = mailimf_cc_new(resent_cc);
+ if (imf_resent_cc == NULL)
+ goto free;
+ field = mailimf_field_new(MAILIMF_FIELD_RESENT_CC,
+ NULL /* return-path */,
+ NULL /* resent date */,
+ NULL /* resent from */,
+ NULL /* resent sender */,
+ NULL /* resent to */,
+ imf_resent_cc /* resent cc */,
+ NULL /* resent bcc */,
+ NULL /* resent msg id */,
+ NULL /* date */,
+ NULL /* from */,
+ NULL /* sender */,
+ NULL /* reply-to */,
+ NULL /* to */,
+ NULL /* cc */,
+ NULL /* bcc */,
+ NULL /* message id */,
+ NULL /* in reply to */,
+ NULL /* references */,
+ NULL /* subject */,
+ NULL /* comments */,
+ NULL /* keywords */,
+ NULL /* optional field */);
+ if (field == NULL)
+ goto free;
+ r = mailimf_fields_add(fields, field);
+ if (r != MAILIMF_NO_ERROR)
+ goto free_field;
+ }
+
+ if (resent_bcc != NULL) {
+ imf_resent_bcc = mailimf_bcc_new(resent_bcc);
+ if (imf_resent_bcc == NULL)
+ goto free;
+ field = mailimf_field_new(MAILIMF_FIELD_RESENT_BCC,
+ NULL /* return-path */,
+ NULL /* resent date */,
+ NULL /* resent from */,
+ NULL /* resent sender */,
+ NULL /* resent to */,
+ NULL /* resent cc */,
+ imf_resent_bcc /* resent bcc */,
+ NULL /* resent msg id */,
+ NULL /* date */,
+ NULL /* from */,
+ NULL /* sender */,
+ NULL /* reply-to */,
+ NULL /* to */,
+ NULL /* cc */,
+ NULL /* bcc */,
+ NULL /* message id */,
+ NULL /* in reply to */,
+ NULL /* references */,
+ NULL /* subject */,
+ NULL /* comments */,
+ NULL /* keywords */,
+ NULL /* optional field */);
+ if (field == NULL)
+ goto free;
+ r = mailimf_fields_add(fields, field);
+ if (r != MAILIMF_NO_ERROR)
+ goto free_field;
+ }
+
+ if (resent_msg_id != NULL) {
+ imf_resent_msg_id = mailimf_message_id_new(resent_msg_id);
+ if (imf_resent_msg_id == NULL)
+ goto free;
+ field = mailimf_field_new(MAILIMF_FIELD_RESENT_MSG_ID,
+ NULL /* return-path */,
+ NULL /* resent date */,
+ NULL /* resent from */,
+ NULL /* resent sender */,
+ NULL /* resent to */,
+ NULL /* resent cc */,
+ NULL /* resent bcc */,
+ imf_resent_msg_id /* resent msg id */,
+ NULL /* date */,
+ NULL /* from */,
+ NULL /* sender */,
+ NULL /* reply-to */,
+ NULL /* to */,
+ NULL /* cc */,
+ NULL /* bcc */,
+ NULL /* message id */,
+ NULL /* in reply to */,
+ NULL /* references */,
+ NULL /* subject */,
+ NULL /* comments */,
+ NULL /* keywords */,
+ NULL /* optional field */);
+ if (field == NULL)
+ goto free;
+ r = mailimf_fields_add(fields, field);
+ if (r != MAILIMF_NO_ERROR)
+ goto free_field;
+ }
+
+ return MAILIMF_NO_ERROR;
+
+ free_field:
+ if (field != NULL) {
+ detach_resent_field(field);
+ mailimf_field_free(field);
+ }
+ free:
+ detach_free_common_fields(imf_resent_date,
+ imf_resent_from,
+ imf_resent_sender,
+ imf_resent_to,
+ imf_resent_cc,
+ imf_resent_bcc,
+ imf_resent_msg_id);
+ return MAILIMF_ERROR_MEMORY;
+}
+
+struct mailimf_fields *
+mailimf_resent_fields_new_with_data_all(struct mailimf_date_time *
+ resent_date,
+ struct mailimf_mailbox_list *
+ resent_from,
+ struct mailimf_mailbox *
+ resent_sender,
+ struct mailimf_address_list *
+ resent_to,
+ struct mailimf_address_list *
+ resent_cc,
+ struct mailimf_address_list *
+ resent_bcc,
+ char * resent_msg_id)
+{
+ struct mailimf_fields * resent_fields;
+ int r;
+
+ resent_fields = mailimf_fields_new_empty();
+ if (resent_fields == NULL)
+ goto err;
+
+ r = mailimf_resent_fields_add_data(resent_fields,
+ resent_date, resent_from,
+ resent_sender, resent_to,
+ resent_cc, resent_bcc,
+ resent_msg_id);
+ if (r != MAILIMF_NO_ERROR)
+ goto free;
+
+ return resent_fields;
+
+ free:
+ mailimf_fields_free(resent_fields);
+ err:
+ return NULL;
+}
+
+
+struct mailimf_fields *
+mailimf_resent_fields_new_with_data(struct mailimf_mailbox_list * from,
+ struct mailimf_mailbox * sender,
+ struct mailimf_address_list * to,
+ struct mailimf_address_list * cc,
+ struct mailimf_address_list * bcc)
+{
+ struct mailimf_date_time * date;
+ char * msg_id;
+ struct mailimf_fields * fields;
+
+ date = mailimf_get_current_date();
+ if (date == NULL)
+ goto err;
+
+ msg_id = mailimf_get_message_id();
+ if (msg_id == NULL)
+ goto free_date;
+
+ fields = mailimf_resent_fields_new_with_data_all(date,
+ from, sender, to, cc, bcc, msg_id);
+ if (fields == NULL)
+ goto free_msg_id;
+
+ return fields;
+
+ free_msg_id:
+ free(msg_id);
+ free_date:
+ mailimf_date_time_free(date);
+ err:
+ return NULL;
+}
+
+
+struct mailimf_fields *
+mailimf_fields_new_empty(void)
+{
+ clist * list;
+ struct mailimf_fields * fields_list;
+
+ list = clist_new();
+ if (list == NULL)
+ return NULL;
+
+ fields_list = mailimf_fields_new(list);
+ if (fields_list == NULL)
+ return NULL;
+
+ return fields_list;
+}
+
+int mailimf_fields_add(struct mailimf_fields * fields,
+ struct mailimf_field * field)
+{
+ int r;
+
+ r = clist_append(fields->fld_list, field);
+ if (r < 0)
+ return MAILIMF_ERROR_MEMORY;
+
+ return MAILIMF_NO_ERROR;
+}
+
+static void detach_free_fields(struct mailimf_orig_date * date,
+ struct mailimf_from * from,
+ struct mailimf_sender * sender,
+ struct mailimf_reply_to * reply_to,
+ struct mailimf_to * to,
+ struct mailimf_cc * cc,
+ struct mailimf_bcc * bcc,
+ struct mailimf_message_id * msg_id,
+ struct mailimf_in_reply_to * in_reply_to,
+ struct mailimf_references * references,
+ struct mailimf_subject * subject)
+{
+ detach_free_common_fields(date,
+ from,
+ sender,
+ to,
+ cc,
+ bcc,
+ msg_id);
+
+ if (reply_to != NULL) {
+ reply_to->rt_addr_list = NULL;
+ mailimf_reply_to_free(reply_to);
+ }
+
+ if (in_reply_to != NULL) {
+ in_reply_to->mid_list = NULL;
+ mailimf_in_reply_to_free(in_reply_to);
+ }
+
+ if (references != NULL) {
+ references->mid_list = NULL;
+ mailimf_references_free(references);
+ }
+
+ if (subject != NULL) {
+ subject->sbj_value = NULL;
+ mailimf_subject_free(subject);
+ }
+}
+
+
+static void detach_field(struct mailimf_field * field)
+{
+ field->fld_type = MAILIMF_FIELD_NONE;
+ mailimf_field_free(field);
+}
+
+int mailimf_fields_add_data(struct mailimf_fields * fields,
+ struct mailimf_date_time * date,
+ struct mailimf_mailbox_list * from,
+ struct mailimf_mailbox * sender,
+ struct mailimf_address_list * reply_to,
+ struct mailimf_address_list * to,
+ struct mailimf_address_list * cc,
+ struct mailimf_address_list * bcc,
+ char * msg_id,
+ clist * in_reply_to,
+ clist * references,
+ char * subject)
+{
+ struct mailimf_orig_date * imf_date;
+ struct mailimf_from * imf_from;
+ struct mailimf_sender * imf_sender;
+ struct mailimf_reply_to * imf_reply_to;
+ struct mailimf_to * imf_to;
+ struct mailimf_cc * imf_cc;
+ struct mailimf_bcc * imf_bcc;
+ struct mailimf_message_id * imf_msg_id;
+ struct mailimf_references * imf_references;
+ struct mailimf_in_reply_to * imf_in_reply_to;
+ struct mailimf_subject * imf_subject;
+ struct mailimf_field * field;
+ int r;
+
+ imf_date = NULL;
+ imf_from = NULL;
+ imf_sender = NULL;
+ imf_reply_to = NULL;
+ imf_to = NULL;
+ imf_cc = NULL;
+ imf_bcc = NULL;
+ imf_msg_id = NULL;
+ imf_references = NULL;
+ imf_in_reply_to = NULL;
+ imf_subject =NULL;
+ field = NULL;
+
+ if (date != NULL) {
+ imf_date = mailimf_orig_date_new(date);
+ if (imf_date == NULL)
+ goto free;
+ field = mailimf_field_new(MAILIMF_FIELD_ORIG_DATE,
+ NULL /* return-path */,
+ NULL /* resent date */,
+ NULL /* resent from */,
+ NULL /* resent sender */,
+ NULL /* resent to */,
+ NULL /* resent cc */,
+ NULL /* resent bcc */,
+ NULL /* resent msg id */,
+ imf_date /* date */,
+ NULL /* from */,
+ NULL /* sender */,
+ NULL /* reply-to */,
+ NULL /* to */,
+ NULL /* cc */,
+ NULL /* bcc */,
+ NULL /* message id */,
+ NULL /* in reply to */,
+ NULL /* references */,
+ NULL /* subject */,
+ NULL /* comments */,
+ NULL /* keywords */,
+ NULL /* optional field */);
+ if (field == NULL)
+ goto free;
+ r = mailimf_fields_add(fields, field);
+ if (r != MAILIMF_NO_ERROR)
+ goto free_field;
+ }
+
+ if (from != NULL) {
+ imf_from = mailimf_from_new(from);
+ if (imf_from == NULL)
+ goto free_field;
+ field = mailimf_field_new(MAILIMF_FIELD_FROM,
+ NULL /* return-path */,
+ NULL /* resent date */,
+ NULL /* resent from */,
+ NULL /* resent sender */,
+ NULL /* resent to */,
+ NULL /* resent cc */,
+ NULL /* resent bcc */,
+ NULL /* resent msg id */,
+ NULL /* date */,
+ imf_from /* from */,
+ NULL /* sender */,
+ NULL /* reply-to */,
+ NULL /* to */,
+ NULL /* cc */,
+ NULL /* bcc */,
+ NULL /* message id */,
+ NULL /* in reply to */,
+ NULL /* references */,
+ NULL /* subject */,
+ NULL /* comments */,
+ NULL /* keywords */,
+ NULL /* optional field */);
+ if (field == NULL)
+ goto free;
+ r = mailimf_fields_add(fields, field);
+ if (r != MAILIMF_NO_ERROR)
+ goto free_field;
+ }
+
+ if (sender != NULL) {
+ imf_sender = mailimf_sender_new(sender);
+ if (imf_sender == NULL)
+ goto free;
+ field = mailimf_field_new(MAILIMF_FIELD_SENDER,
+ NULL /* return-path */,
+ NULL /* resent date */,
+ NULL /* resent from */,
+ NULL /* resent sender */,
+ NULL /* resent to */,
+ NULL /* resent cc */,
+ NULL /* resent bcc */,
+ NULL /* resent msg id */,
+ NULL /* date */,
+ NULL /* from */,
+ imf_sender /* sender */,
+ NULL /* reply-to */,
+ NULL /* to */,
+ NULL /* cc */,
+ NULL /* bcc */,
+ NULL /* message id */,
+ NULL /* in reply to */,
+ NULL /* references */,
+ NULL /* subject */,
+ NULL /* comments */,
+ NULL /* keywords */,
+ NULL /* optional field */);
+ if (field == NULL)
+ goto free;
+ r = mailimf_fields_add(fields, field);
+ if (r != MAILIMF_NO_ERROR)
+ goto free_field;
+ }
+
+ if (reply_to != NULL) {
+ imf_reply_to = mailimf_reply_to_new(reply_to);
+ if (imf_reply_to == NULL)
+ goto free;
+ field = mailimf_field_new(MAILIMF_FIELD_REPLY_TO,
+ NULL /* return-path */,
+ NULL /* resent date */,
+ NULL /* resent from */,
+ NULL /* resent sender */,
+ NULL /* resent to */,
+ NULL /* resent cc */,
+ NULL /* resent bcc */,
+ NULL /* resent msg id */,
+ NULL /* date */,
+ NULL /* from */,
+ NULL /* sender */,
+ imf_reply_to /* reply-to */,
+ NULL /* to */,
+ NULL /* cc */,
+ NULL /* bcc */,
+ NULL /* message id */,
+ NULL /* in reply to */,
+ NULL /* references */,
+ NULL /* subject */,
+ NULL /* comments */,
+ NULL /* keywords */,
+ NULL /* optional field */);
+ if (field == NULL)
+ goto free;
+ r = mailimf_fields_add(fields, field);
+ if (r != MAILIMF_NO_ERROR)
+ goto free_field;
+ }
+
+ if (to != NULL) {
+ imf_to = mailimf_to_new(to);
+ if (imf_to == NULL)
+ goto free;
+ field = mailimf_field_new(MAILIMF_FIELD_TO,
+ NULL /* return-path */,
+ NULL /* resent date */,
+ NULL /* resent from */,
+ NULL /* resent sender */,
+ NULL /* resent to */,
+ NULL /* resent cc */,
+ NULL /* resent bcc */,
+ NULL /* resent msg id */,
+ NULL /* date */,
+ NULL /* from */,
+ NULL /* sender */,
+ NULL /* reply-to */,
+ imf_to /* to */,
+ NULL /* cc */,
+ NULL /* bcc */,
+ NULL /* message id */,
+ NULL /* in reply to */,
+ NULL /* references */,
+ NULL /* subject */,
+ NULL /* comments */,
+ NULL /* keywords */,
+ NULL /* optional field */);
+ if (field == NULL)
+ goto free;
+ r = mailimf_fields_add(fields, field);
+ if (r != MAILIMF_NO_ERROR)
+ goto free_field;
+ }
+
+ if (cc != NULL) {
+ imf_cc = mailimf_cc_new(cc);
+ if (imf_cc == NULL)
+ goto free;
+ field = mailimf_field_new(MAILIMF_FIELD_CC,
+ NULL /* return-path */,
+ NULL /* resent date */,
+ NULL /* resent from */,
+ NULL /* resent sender */,
+ NULL /* resent to */,
+ NULL /* resent cc */,
+ NULL /* resent bcc */,
+ NULL /* resent msg id */,
+ NULL /* date */,
+ NULL /* from */,
+ NULL /* sender */,
+ NULL /* reply-to */,
+ NULL /* to */,
+ imf_cc /* cc */,
+ NULL /* bcc */,
+ NULL /* message id */,
+ NULL /* in reply to */,
+ NULL /* references */,
+ NULL /* subject */,
+ NULL /* comments */,
+ NULL /* keywords */,
+ NULL /* optional field */);
+ if (field == NULL)
+ goto free;
+ r = mailimf_fields_add(fields, field);
+ if (r != MAILIMF_NO_ERROR)
+ goto free_field;
+ }
+
+ if (bcc != NULL) {
+ imf_bcc = mailimf_bcc_new(bcc);
+ if (imf_bcc == NULL)
+ goto free;
+ field = mailimf_field_new(MAILIMF_FIELD_BCC,
+ NULL /* return-path */,
+ NULL /* resent date */,
+ NULL /* resent from */,
+ NULL /* resent sender */,
+ NULL /* resent to */,
+ NULL /* resent cc */,
+ NULL /* resent bcc */,
+ NULL /* resent msg id */,
+ NULL /* date */,
+ NULL /* from */,
+ NULL /* sender */,
+ NULL /* reply-to */,
+ NULL /* to */,
+ NULL /* cc */,
+ imf_bcc /* bcc */,
+ NULL /* message id */,
+ NULL /* in reply to */,
+ NULL /* references */,
+ NULL /* subject */,
+ NULL /* comments */,
+ NULL /* keywords */,
+ NULL /* optional field */);
+ if (field == NULL)
+ goto free;
+ r = mailimf_fields_add(fields, field);
+ if (r != MAILIMF_NO_ERROR)
+ goto free_field;
+ }
+
+ if (msg_id != NULL) {
+ imf_msg_id = mailimf_message_id_new(msg_id);
+ if (imf_msg_id == NULL)
+ goto free;
+ field = mailimf_field_new(MAILIMF_FIELD_MESSAGE_ID,
+ NULL /* return-path */,
+ NULL /* resent date */,
+ NULL /* resent from */,
+ NULL /* resent sender */,
+ NULL /* resent to */,
+ NULL /* resent cc */,
+ NULL /* resent bcc */,
+ NULL /* resent msg id */,
+ NULL /* date */,
+ NULL /* from */,
+ NULL /* sender */,
+ NULL /* reply-to */,
+ NULL /* to */,
+ NULL /* cc */,
+ NULL /* bcc */,
+ imf_msg_id /* message id */,
+ NULL /* in reply to */,
+ NULL /* references */,
+ NULL /* subject */,
+ NULL /* comments */,
+ NULL /* keywords */,
+ NULL /* optional field */);
+ if (field == NULL)
+ goto free;
+ r = mailimf_fields_add(fields, field);
+ if (r != MAILIMF_NO_ERROR)
+ goto free_field;
+ }
+
+ if (in_reply_to != NULL) {
+ imf_in_reply_to = mailimf_in_reply_to_new(in_reply_to);
+ if (imf_in_reply_to == NULL)
+ goto free;
+ field = mailimf_field_new(MAILIMF_FIELD_IN_REPLY_TO,
+ NULL /* return-path */,
+ NULL /* resent date */,
+ NULL /* resent from */,
+ NULL /* resent sender */,
+ NULL /* resent to */,
+ NULL /* resent cc */,
+ NULL /* resent bcc */,
+ NULL /* resent msg id */,
+ NULL /* date */,
+ NULL /* from */,
+ NULL /* sender */,
+ NULL /* reply-to */,
+ NULL /* to */,
+ NULL /* cc */,
+ NULL /* bcc */,
+ NULL /* message id */,
+ imf_in_reply_to /* in reply to */,
+ NULL /* references */,
+ NULL /* subject */,
+ NULL /* comments */,
+ NULL /* keywords */,
+ NULL /* optional field */);
+ if (field == NULL)
+ goto free;
+ r = mailimf_fields_add(fields, field);
+ if (r != MAILIMF_NO_ERROR)
+ goto free_field;
+ }
+
+ if (references != NULL) {
+ imf_references = mailimf_references_new(references);
+ if (imf_references == NULL)
+ goto free;
+ field = mailimf_field_new(MAILIMF_FIELD_REFERENCES,
+ NULL /* return-path */,
+ NULL /* resent date */,
+ NULL /* resent from */,
+ NULL /* resent sender */,
+ NULL /* resent to */,
+ NULL /* resent cc */,
+ NULL /* resent bcc */,
+ NULL /* resent msg id */,
+ NULL /* date */,
+ NULL /* from */,
+ NULL /* sender */,
+ NULL /* reply-to */,
+ NULL /* to */,
+ NULL /* cc */,
+ NULL /* bcc */,
+ NULL /* message id */,
+ NULL /* in reply to */,
+ imf_references /* references */,
+ NULL /* subject */,
+ NULL /* comments */,
+ NULL /* keywords */,
+ NULL /* optional field */);
+ if (field == NULL)
+ goto free;
+ r = mailimf_fields_add(fields, field);
+ if (r != MAILIMF_NO_ERROR)
+ goto free_field;
+ }
+
+ if (subject != NULL) {
+ imf_subject = mailimf_subject_new(subject);
+ if (imf_subject == NULL)
+ goto free;
+ field = mailimf_field_new(MAILIMF_FIELD_SUBJECT,
+ NULL /* return-path */,
+ NULL /* resent date */,
+ NULL /* resent from */,
+ NULL /* resent sender */,
+ NULL /* resent to */,
+ NULL /* resent cc */,
+ NULL /* resent bcc */,
+ NULL /* resent msg id */,
+ NULL /* date */,
+ NULL /* from */,
+ NULL /* sender */,
+ NULL /* reply-to */,
+ NULL /* to */,
+ NULL /* cc */,
+ NULL /* bcc */,
+ NULL /* message id */,
+ NULL /* in reply to */,
+ NULL /* references */,
+ imf_subject /* subject */,
+ NULL /* comments */,
+ NULL /* keywords */,
+ NULL /* optional field */);
+ if (field == NULL)
+ goto free;
+ r = mailimf_fields_add(fields, field);
+ if (r != MAILIMF_NO_ERROR)
+ goto free_field;
+ }
+
+ return MAILIMF_NO_ERROR;
+
+ free_field:
+ if (field != NULL) {
+ detach_field(field);
+ mailimf_field_free(field);
+ }
+ free:
+ detach_free_fields(imf_date,
+ imf_from,
+ imf_sender,
+ imf_reply_to,
+ imf_to,
+ imf_cc,
+ imf_bcc,
+ imf_msg_id,
+ imf_in_reply_to,
+ imf_references,
+ imf_subject);
+
+ return MAILIMF_ERROR_MEMORY;
+}
+
+struct mailimf_fields *
+mailimf_fields_new_with_data_all(struct mailimf_date_time * date,
+ struct mailimf_mailbox_list * from,
+ struct mailimf_mailbox * sender,
+ struct mailimf_address_list * reply_to,
+ struct mailimf_address_list * to,
+ struct mailimf_address_list * cc,
+ struct mailimf_address_list * bcc,
+ char * message_id,
+ clist * in_reply_to,
+ clist * references,
+ char * subject)
+{
+ struct mailimf_fields * fields;
+ int r;
+
+ fields = mailimf_fields_new_empty();
+ if (fields == NULL)
+ goto err;
+
+ r = mailimf_fields_add_data(fields,
+ date,
+ from,
+ sender,
+ reply_to,
+ to,
+ cc,
+ bcc,
+ message_id,
+ in_reply_to,
+ references,
+ subject);
+ if (r != MAILIMF_NO_ERROR)
+ goto free;
+
+ return fields;
+
+ free:
+ mailimf_fields_free(fields);
+ err:
+ return NULL;
+}
+
+struct mailimf_fields *
+mailimf_fields_new_with_data(struct mailimf_mailbox_list * from,
+ struct mailimf_mailbox * sender,
+ struct mailimf_address_list * reply_to,
+ struct mailimf_address_list * to,
+ struct mailimf_address_list * cc,
+ struct mailimf_address_list * bcc,
+ clist * in_reply_to,
+ clist * references,
+ char * subject)
+{
+ struct mailimf_date_time * date;
+ char * msg_id;
+ struct mailimf_fields * fields;
+
+ date = mailimf_get_current_date();
+ if (date == NULL)
+ goto err;
+
+ msg_id = mailimf_get_message_id();
+ if (msg_id == NULL)
+ goto free_date;
+
+ fields = mailimf_fields_new_with_data_all(date,
+ from, sender, reply_to,
+ to, cc, bcc,
+ msg_id,
+ in_reply_to, references,
+ subject);
+ if (fields == NULL)
+ goto free_msg_id;
+
+ return fields;
+
+ free_msg_id:
+ free(msg_id);
+ free_date:
+ mailimf_date_time_free(date);
+ err:
+ return NULL;
+}
+
+
+
+#define MAX_MESSAGE_ID 512
+
+char * mailimf_get_message_id(void)
+{
+ char id[MAX_MESSAGE_ID];
+ time_t now;
+ char name[MAX_MESSAGE_ID];
+ long value;
+
+ now = time(NULL);
+ value = random();
+
+ gethostname(name, MAX_MESSAGE_ID);
+ snprintf(id, MAX_MESSAGE_ID, "etPan.%lx.%lx.%x@%s",
+ now, value, getpid(), name);
+
+ return strdup(id);
+}
+
+
+
+static time_t mkgmtime(struct tm * tmp);
+
+
+struct mailimf_date_time * mailimf_get_current_date(void)
+{
+ struct tm gmt;
+ struct tm lt;
+ int off;
+ time_t now;
+ struct mailimf_date_time * date_time;
+
+ now = time(NULL);
+
+ if (gmtime_r(&now, &gmt) == NULL)
+ return NULL;
+
+ if (localtime_r(&now, &lt) == NULL)
+ return NULL;
+
+ off = (mkgmtime(&lt) - mkgmtime(&gmt)) / (60 * 60) * 100;
+
+ date_time = mailimf_date_time_new(lt.tm_mday, lt.tm_mon + 1, lt.tm_year + 1900,
+ lt.tm_hour, lt.tm_min, lt.tm_sec,
+ off);
+
+ return date_time;
+}
+
+
+
+/* mkgmtime.c - make time corresponding to a GMT timeval struct
+ $Id$
+
+ * Copyright (c) 1998-2000 Carnegie Mellon University. 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. The name "Carnegie Mellon University" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For permission or any other legal
+ * details, please contact
+ * Office of Technology Transfer
+ * Carnegie Mellon University
+ * 5000 Forbes Avenue
+ * Pittsburgh, PA 15213-3890
+ * (412) 268-4387, fax: (412) 268-7395
+ * tech-transfer@andrew.cmu.edu
+ *
+ * 4. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by Computing Services
+ * at Carnegie Mellon University (http://www.cmu.edu/computing/)."
+ *
+ * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
+ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
+ * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ *
+ */
+/*
+ * Copyright (c) 1987, 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Arthur David Olson of the National Cancer Institute.
+ *
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+** Adapted from code provided by Robert Elz, who writes:
+** The "best" way to do mktime I think is based on an idea of Bob
+** Kridle's (so its said...) from a long time ago. (mtxinu!kridle now).
+** It does a binary search of the time_t space. Since time_t's are
+** just 32 bits, its a max of 32 iterations (even at 64 bits it
+** would still be very reasonable).
+*/
+
+/*
+ adapted for libEtPan! by DINH V. Hoa
+*/
+
+#ifndef WRONG
+#define WRONG (-1)
+#endif /* !defined WRONG */
+
+static int tmcomp(struct tm * atmp, struct tm * btmp)
+{
+ register int result;
+
+ if ((result = (atmp->tm_year - btmp->tm_year)) == 0 &&
+ (result = (atmp->tm_mon - btmp->tm_mon)) == 0 &&
+ (result = (atmp->tm_mday - btmp->tm_mday)) == 0 &&
+ (result = (atmp->tm_hour - btmp->tm_hour)) == 0 &&
+ (result = (atmp->tm_min - btmp->tm_min)) == 0)
+ result = atmp->tm_sec - btmp->tm_sec;
+ return result;
+}
+
+static time_t mkgmtime(struct tm * tmp)
+{
+ register int dir;
+ register int bits;
+ register int saved_seconds;
+ time_t t;
+ struct tm yourtm, *mytm;
+
+ yourtm = *tmp;
+ saved_seconds = yourtm.tm_sec;
+ yourtm.tm_sec = 0;
+ /*
+ ** Calculate the number of magnitude bits in a time_t
+ ** (this works regardless of whether time_t is
+ ** signed or unsigned, though lint complains if unsigned).
+ */
+ for (bits = 0, t = 1; t > 0; ++bits, t <<= 1)
+ ;
+ /*
+ ** If time_t is signed, then 0 is the median value,
+ ** if time_t is unsigned, then 1 << bits is median.
+ */
+ t = (t < 0) ? 0 : ((time_t) 1 << bits);
+ for ( ; ; ) {
+ mytm = gmtime(&t);
+ dir = tmcomp(mytm, &yourtm);
+ if (dir != 0) {
+ if (bits-- < 0)
+ return WRONG;
+ if (bits < 0)
+ --t;
+ else if (dir > 0)
+ t -= (time_t) 1 << bits;
+ else t += (time_t) 1 << bits;
+ continue;
+ }
+ break;
+ }
+ t += saved_seconds;
+ return t;
+}
+
+
+
+
+
+
+
+void mailimf_single_fields_init(struct mailimf_single_fields * single_fields,
+ struct mailimf_fields * fields)
+{
+ clistiter * cur;
+
+ memset(single_fields, 0, sizeof(struct mailimf_single_fields));
+
+ cur = clist_begin(fields->fld_list);
+ while (cur != NULL) {
+ struct mailimf_field * field;
+
+ field = clist_content(cur);
+
+ switch (field->fld_type) {
+ case MAILIMF_FIELD_ORIG_DATE:
+ if (single_fields->fld_orig_date == NULL)
+ single_fields->fld_orig_date = field->fld_data.fld_orig_date;
+ cur = clist_next(cur);
+ break;
+ case MAILIMF_FIELD_FROM:
+ if (single_fields->fld_from == NULL) {
+ single_fields->fld_from = field->fld_data.fld_from;
+ cur = clist_next(cur);
+ }
+ else {
+ clist_concat(single_fields->fld_from->frm_mb_list->mb_list,
+ field->fld_data.fld_from->frm_mb_list->mb_list);
+ mailimf_field_free(field);
+ cur = clist_delete(fields->fld_list, cur);
+ }
+ break;
+ case MAILIMF_FIELD_SENDER:
+ if (single_fields->fld_sender == NULL)
+ single_fields->fld_sender = field->fld_data.fld_sender;
+ cur = clist_next(cur);
+ break;
+ case MAILIMF_FIELD_REPLY_TO:
+ if (single_fields->fld_reply_to == NULL) {
+ single_fields->fld_reply_to = field->fld_data.fld_reply_to;
+ cur = clist_next(cur);
+ }
+ else {
+ clist_concat(single_fields->fld_reply_to->rt_addr_list->ad_list,
+ field->fld_data.fld_reply_to->rt_addr_list->ad_list);
+ mailimf_field_free(field);
+ cur = clist_delete(fields->fld_list, cur);
+ }
+ break;
+ case MAILIMF_FIELD_TO:
+ if (single_fields->fld_to == NULL) {
+ single_fields->fld_to = field->fld_data.fld_to;
+ cur = clist_next(cur);
+ }
+ else {
+ clist_concat(single_fields->fld_to->to_addr_list->ad_list,
+ field->fld_data.fld_to->to_addr_list->ad_list);
+ mailimf_field_free(field);
+ cur = clist_delete(fields->fld_list, cur);
+ }
+ break;
+ case MAILIMF_FIELD_CC:
+ if (single_fields->fld_cc == NULL) {
+ single_fields->fld_cc = field->fld_data.fld_cc;
+ cur = clist_next(cur);
+ }
+ else {
+ clist_concat(single_fields->fld_cc->cc_addr_list->ad_list,
+ field->fld_data.fld_cc->cc_addr_list->ad_list);
+ mailimf_field_free(field);
+ cur = clist_delete(fields->fld_list, cur);
+ }
+ break;
+ case MAILIMF_FIELD_BCC:
+ if (single_fields->fld_bcc == NULL) {
+ single_fields->fld_bcc = field->fld_data.fld_bcc;
+ cur = clist_next(cur);
+ }
+ else {
+ clist_concat(single_fields->fld_bcc->bcc_addr_list->ad_list,
+ field->fld_data.fld_bcc->bcc_addr_list->ad_list);
+ mailimf_field_free(field);
+ cur = clist_delete(fields->fld_list, cur);
+ }
+ break;
+ case MAILIMF_FIELD_MESSAGE_ID:
+ if (single_fields->fld_message_id == NULL)
+ single_fields->fld_message_id = field->fld_data.fld_message_id;
+ cur = clist_next(cur);
+ break;
+ case MAILIMF_FIELD_IN_REPLY_TO:
+ if (single_fields->fld_in_reply_to == NULL)
+ single_fields->fld_in_reply_to = field->fld_data.fld_in_reply_to;
+ cur = clist_next(cur);
+ break;
+ case MAILIMF_FIELD_REFERENCES:
+ if (single_fields->fld_references == NULL)
+ single_fields->fld_references = field->fld_data.fld_references;
+ cur = clist_next(cur);
+ break;
+ case MAILIMF_FIELD_SUBJECT:
+ if (single_fields->fld_subject == NULL)
+ single_fields->fld_subject = field->fld_data.fld_subject;
+ cur = clist_next(cur);
+ break;
+ case MAILIMF_FIELD_COMMENTS:
+ if (single_fields->fld_comments == NULL)
+ single_fields->fld_comments = field->fld_data.fld_comments;
+ cur = clist_next(cur);
+ break;
+ case MAILIMF_FIELD_KEYWORDS:
+ if (single_fields->fld_keywords == NULL)
+ single_fields->fld_keywords = field->fld_data.fld_keywords;
+ cur = clist_next(cur);
+ break;
+ default:
+ cur = clist_next(cur);
+ break;
+ }
+ }
+}
+
+
+struct mailimf_single_fields *
+mailimf_single_fields_new(struct mailimf_fields * fields)
+{
+ struct mailimf_single_fields * single_fields;
+
+ single_fields = malloc(sizeof(struct mailimf_single_fields));
+ if (single_fields == NULL)
+ goto err;
+
+ mailimf_single_fields_init(single_fields, fields);
+
+ return single_fields;
+
+ err:
+ return NULL;
+}
+
+void mailimf_single_fields_free(struct mailimf_single_fields *
+ single_fields)
+{
+ free(single_fields);
+}
+
+struct mailimf_field * mailimf_field_new_custom(char * name, char * value)
+{
+ struct mailimf_optional_field * opt_field;
+ struct mailimf_field * field;
+
+ opt_field = mailimf_optional_field_new(name, value);
+ if (opt_field == NULL)
+ goto err;
+
+ field = mailimf_field_new(MAILIMF_FIELD_OPTIONAL_FIELD,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, opt_field);
+ if (field == NULL)
+ goto free_opt_field;
+
+ return field;
+
+ free_opt_field:
+ mailimf_optional_field_free(opt_field);
+ err:
+ return NULL;
+}
diff --git a/libetpan/src/low-level/imf/mailimf_types_helper.h b/libetpan/src/low-level/imf/mailimf_types_helper.h
new file mode 100644
index 0000000..337b1d0
--- a/dev/null
+++ b/libetpan/src/low-level/imf/mailimf_types_helper.h
@@ -0,0 +1,370 @@
+/*
+ * 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$
+ */
+
+#ifndef MAILIMF_TYPES_HELPER
+
+#define MAILIMF_TYPES_HELPER
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <libetpan/mailimf_types.h>
+
+/*
+ IMPORTANT NOTE:
+
+ All allocation functions will take as argument allocated data
+ and will store these data in the structure they will allocate.
+ Data should be persistant during all the use of the structure
+ and will be freed by the free function of the structure
+
+ allocation functions will return NULL on failure
+*/
+
+/*
+ mailimf_mailbox_list_new_empty creates an empty list of mailboxes
+*/
+
+struct mailimf_mailbox_list *
+mailimf_mailbox_list_new_empty();
+
+/*
+ mailimf_mailbox_list_add adds a mailbox to the list of mailboxes
+
+ @return MAILIMF_NO_ERROR will be returned on success,
+ other code will be returned otherwise
+*/
+
+int mailimf_mailbox_list_add(struct mailimf_mailbox_list * mailbox_list,
+ struct mailimf_mailbox * mb);
+
+/*
+ mailimf_mailbox_list_add_parse parse the given string
+ into a mailimf_mailbox structure and adds it to the list of mailboxes
+
+ @return MAILIMF_NO_ERROR will be returned on success,
+ other code will be returned otherwise
+*/
+
+int mailimf_mailbox_list_add_parse(struct mailimf_mailbox_list * mailbox_list,
+ char * mb_str);
+
+/*
+ mailimf_mailbox creates a mailimf_mailbox structure with the given
+ arguments and adds it to the list of mailboxes
+
+ - display_name is the name that will be displayed for this mailbox,
+ for example 'name' in '"name" <mailbox@domain>,
+ should be allocated with malloc()
+
+ - address is the mailbox, for example 'mailbox@domain'
+ in '"name" <mailbox@domain>, should be allocated with malloc()
+
+ @return MAILIMF_NO_ERROR will be returned on success,
+ other code will be returned otherwise
+*/
+
+int mailimf_mailbox_list_add_mb(struct mailimf_mailbox_list * mailbox_list,
+ char * display_name, char * address);
+
+/*
+ mailimf_address_list_new_empty creates an empty list of addresses
+*/
+
+struct mailimf_address_list *
+mailimf_address_list_new_empty();
+
+/*
+ mailimf_address_list_add adds a mailbox to the list of addresses
+
+ @return MAILIMF_NO_ERROR will be returned on success,
+ other code will be returned otherwise
+*/
+
+int mailimf_address_list_add(struct mailimf_address_list * address_list,
+ struct mailimf_address * addr);
+
+/*
+ mailimf_address_list_add_parse parse the given string
+ into a mailimf_address structure and adds it to the list of addresses
+
+ @return MAILIMF_NO_ERROR will be returned on success,
+ other code will be returned otherwise
+*/
+
+int mailimf_address_list_add_parse(struct mailimf_address_list * address_list,
+ char * addr_str);
+
+/*
+ mailimf_address_list_add_mb creates a mailbox mailimf_address
+ with the given arguments and adds it to the list of addresses
+
+ - display_name is the name that will be displayed for this mailbox,
+ for example 'name' in '"name" <mailbox@domain>,
+ should be allocated with malloc()
+
+ - address is the mailbox, for example 'mailbox@domain'
+ in '"name" <mailbox@domain>, should be allocated with malloc()
+
+ @return MAILIMF_NO_ERROR will be returned on success,
+ other code will be returned otherwise
+*/
+
+int mailimf_address_list_add_mb(struct mailimf_address_list * address_list,
+ char * display_name, char * address);
+
+/*
+ mailimf_resent_fields_add_data adds a set of resent fields in the
+ given mailimf_fields structure.
+
+ if you don't want a given field in the set to be added in the list
+ of fields, you can give NULL as argument
+
+ @param resent_msg_id sould be allocated with malloc()
+
+ @return MAILIMF_NO_ERROR will be returned on success,
+ other code will be returned otherwise
+*/
+
+int
+mailimf_resent_fields_add_data(struct mailimf_fields * fields,
+ struct mailimf_date_time * resent_date,
+ struct mailimf_mailbox_list * resent_from,
+ struct mailimf_mailbox * resent_sender,
+ struct mailimf_address_list * resent_to,
+ struct mailimf_address_list * resent_cc,
+ struct mailimf_address_list * resent_bcc,
+ char * resent_msg_id);
+
+/*
+ mailimf_resent_fields_new_with_data_all creates a new mailimf_fields
+ structure with a set of resent fields
+
+ if you don't want a given field in the set to be added in the list
+ of fields, you can give NULL as argument
+
+ @param resent_msg_id sould be allocated with malloc()
+
+ @return MAILIMF_NO_ERROR will be returned on success,
+ other code will be returned otherwise
+*/
+
+struct mailimf_fields *
+mailimf_resent_fields_new_with_data_all(struct mailimf_date_time *
+ resent_date, struct mailimf_mailbox_list * resent_from,
+ struct mailimf_mailbox * resent_sender,
+ struct mailimf_address_list * resent_to,
+ struct mailimf_address_list * resent_cc,
+ struct mailimf_address_list * resent_bcc,
+ char * resent_msg_id);
+
+/*
+ mailimf_resent_fields_new_with_data_all creates a new mailimf_fields
+ structure with a set of resent fields.
+ Resent-Date and Resent-Message-ID fields will be generated for you.
+
+ if you don't want a given field in the set to be added in the list
+ of fields, you can give NULL as argument
+
+ @return MAILIMF_NO_ERROR will be returned on success,
+ other code will be returned otherwise
+*/
+
+struct mailimf_fields *
+mailimf_resent_fields_new_with_data(struct mailimf_mailbox_list * from,
+ struct mailimf_mailbox * sender,
+ struct mailimf_address_list * to,
+ struct mailimf_address_list * cc,
+ struct mailimf_address_list * bcc);
+
+/*
+ this function creates a new mailimf_fields structure with no fields
+*/
+
+struct mailimf_fields *
+mailimf_fields_new_empty(void);
+
+
+/*
+ this function adds a field to the mailimf_fields structure
+
+ @return MAILIMF_NO_ERROR will be returned on success,
+ other code will be returned otherwise
+*/
+
+int mailimf_fields_add(struct mailimf_fields * fields,
+ struct mailimf_field * field);
+
+
+/*
+ mailimf_fields_add_data adds a set of fields in the
+ given mailimf_fields structure.
+
+ if you don't want a given field in the set to be added in the list
+ of fields, you can give NULL as argument
+
+ @param msg_id sould be allocated with malloc()
+ @param subject should be allocated with malloc()
+ @param in_reply_to each elements of this list should be allocated
+ with malloc()
+ @param references each elements of this list should be allocated
+ with malloc()
+
+ @return MAILIMF_NO_ERROR will be returned on success,
+ other code will be returned otherwise
+*/
+
+int mailimf_fields_add_data(struct mailimf_fields * fields,
+ struct mailimf_date_time * date,
+ struct mailimf_mailbox_list * from,
+ struct mailimf_mailbox * sender,
+ struct mailimf_address_list * reply_to,
+ struct mailimf_address_list * to,
+ struct mailimf_address_list * cc,
+ struct mailimf_address_list * bcc,
+ char * msg_id,
+ clist * in_reply_to,
+ clist * references,
+ char * subject);
+
+/*
+ mailimf_fields_new_with_data_all creates a new mailimf_fields
+ structure with a set of fields
+
+ if you don't want a given field in the set to be added in the list
+ of fields, you can give NULL as argument
+
+ @param message_id sould be allocated with malloc()
+ @param subject should be allocated with malloc()
+ @param in_reply_to each elements of this list should be allocated
+ with malloc()
+ @param references each elements of this list should be allocated
+ with malloc()
+
+ @return MAILIMF_NO_ERROR will be returned on success,
+ other code will be returned otherwise
+*/
+
+struct mailimf_fields *
+mailimf_fields_new_with_data_all(struct mailimf_date_time * date,
+ struct mailimf_mailbox_list * from,
+ struct mailimf_mailbox * sender,
+ struct mailimf_address_list * reply_to,
+ struct mailimf_address_list * to,
+ struct mailimf_address_list * cc,
+ struct mailimf_address_list * bcc,
+ char * message_id,
+ clist * in_reply_to,
+ clist * references,
+ char * subject);
+
+/*
+ mailimf_fields_new_with_data creates a new mailimf_fields
+ structure with a set of fields
+ Date and Message-ID fields will be generated for you.
+
+ if you don't want a given field in the set to be added in the list
+ of fields, you can give NULL as argument
+
+ @param subject should be allocated with malloc()
+ @param in_reply_to each elements of this list should be allocated
+ with malloc()
+ @param references each elements of this list should be allocated
+ with malloc()
+
+ @return MAILIMF_NO_ERROR will be returned on success,
+ other code will be returned otherwise
+*/
+
+struct mailimf_fields *
+mailimf_fields_new_with_data(struct mailimf_mailbox_list * from,
+ struct mailimf_mailbox * sender,
+ struct mailimf_address_list * reply_to,
+ struct mailimf_address_list * to,
+ struct mailimf_address_list * cc,
+ struct mailimf_address_list * bcc,
+ clist * in_reply_to,
+ clist * references,
+ char * subject);
+
+/*
+ this function returns an allocated message identifier to
+ use in a Message-ID or Resent-Message-ID field
+*/
+
+char * mailimf_get_message_id(void);
+
+/*
+ this function returns a mailimf_date_time structure to
+ use in a Date or Resent-Date field
+*/
+
+struct mailimf_date_time * mailimf_get_current_date(void);
+
+
+/*
+ mailimf_single_fields_init fills a mailimf_single_fields structure
+ with the content of a mailimf_fields structure
+*/
+
+void mailimf_single_fields_init(struct mailimf_single_fields * single_fields,
+ struct mailimf_fields * fields);
+
+/*
+ mailimf_single_fields_new creates a new mailimf_single_fields and
+ fills the structure with mailimf_fields
+*/
+
+struct mailimf_single_fields *
+mailimf_single_fields_new(struct mailimf_fields * fields);
+
+void mailimf_single_fields_free(struct mailimf_single_fields *
+ single_fields);
+
+/*
+ mailimf_field_new_custom creates a new field of type optional
+
+ @param name should be allocated with malloc()
+ @param value should be allocated with malloc()
+*/
+
+struct mailimf_field * mailimf_field_new_custom(char * name, char * value);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libetpan/src/low-level/imf/mailimf_write.c b/libetpan/src/low-level/imf/mailimf_write.c
new file mode 100644
index 0000000..7301f37
--- a/dev/null
+++ b/libetpan/src/low-level/imf/mailimf_write.c
@@ -0,0 +1,2021 @@
+/*
+ * 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 "mailimf_write.h"
+
+#include <time.h>
+#include <string.h>
+#include <ctype.h>
+
+#define MAX_MAIL_COL 72
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#define MAX_VALID_IMF_LINE 998
+
+static int mailimf_orig_date_write(FILE * f, int * col,
+ struct mailimf_orig_date * date);
+static int mailimf_date_time_write(FILE * f, int * col,
+ struct mailimf_date_time * date_time);
+static int mailimf_from_write(FILE * f, int * col,
+ struct mailimf_from * from);
+static int mailimf_sender_write(FILE * f, int * col,
+ struct mailimf_sender * sender);
+static int mailimf_reply_to_write(FILE * f, int * col,
+ struct mailimf_reply_to * reply_to);
+static int mailimf_to_write(FILE * f, int * col,
+ struct mailimf_to * to);
+static int mailimf_cc_write(FILE * f, int * col,
+ struct mailimf_cc * to);
+static int mailimf_bcc_write(FILE * f, int * col,
+ struct mailimf_bcc * to);
+static int mailimf_message_id_write(FILE * f, int * col,
+ struct mailimf_message_id * message_id);
+static int mailimf_msg_id_list_write(FILE * f, int * col,
+ clist * list);
+static int mailimf_in_reply_to_write(FILE * f, int * col,
+ struct mailimf_in_reply_to *
+ in_reply_to);
+static int mailimf_references_write(FILE * f, int * col,
+ struct mailimf_references * references);
+static int mailimf_subject_write(FILE * f, int * col,
+ struct mailimf_subject * subject);
+
+static int mailimf_address_write(FILE * f, int * col,
+ struct mailimf_address * addr);
+static int mailimf_group_write(FILE * f, int * col,
+ struct mailimf_group * group);
+
+static int mailimf_mailbox_write(FILE * f, int * col,
+ struct mailimf_mailbox * mb);
+
+static int mailimf_comments_write(FILE * f, int * col,
+ struct mailimf_comments * comments);
+
+static int mailimf_optional_field_write(FILE * f, int * col,
+ struct mailimf_optional_field * field);
+
+static int mailimf_keywords_write(FILE * f, int * col,
+ struct mailimf_keywords * keywords);
+
+static int mailimf_return_write(FILE * f, int * col,
+ struct mailimf_return * return_path);
+
+static int mailimf_path_write(FILE * f, int * col,
+ struct mailimf_path * path);
+
+static int mailimf_resent_date_write(FILE * f, int * col,
+ struct mailimf_orig_date * date);
+
+static int mailimf_resent_from_write(FILE * f, int * col,
+ struct mailimf_from * from);
+
+static int mailimf_resent_sender_write(FILE * f, int * col,
+ struct mailimf_sender * sender);
+
+static int mailimf_resent_to_write(FILE * f, int * col,
+ struct mailimf_to * to);
+
+static int mailimf_resent_cc_write(FILE * f, int * col,
+ struct mailimf_cc * cc);
+
+static int mailimf_resent_bcc_write(FILE * f, int * col,
+ struct mailimf_bcc * bcc);
+
+static int
+mailimf_resent_msg_id_write(FILE * f, int * col,
+ struct mailimf_message_id * message_id);
+
+
+
+/* ************************ */
+
+#if 0
+int mailimf_string_write(FILE * f, int * col,
+ char * str, size_t length)
+{
+ int r;
+
+ if (length != 0) {
+ r = fwrite(str, sizeof(char), length, f);
+ if (r < 0)
+ return MAILIMF_ERROR_FILE;
+ * col += length;
+ }
+
+ return MAILIMF_NO_ERROR;
+}
+#endif
+
+#define CRLF "\r\n"
+#define HEADER_FOLD "\r\n "
+
+static inline int flush_buf(FILE * f, const char * str, size_t length)
+{
+ if (length != 0) {
+ int r;
+
+ r = fwrite(str, 1, length, f);
+ if (r == 0)
+ return MAILIMF_ERROR_FILE;
+ }
+ return MAILIMF_NO_ERROR;
+}
+
+#define CUT_AT_MAX_VALID_IMF_LINE
+
+int mailimf_string_write(FILE * f, int * col,
+ const char * str, size_t length)
+{
+ int r;
+ size_t count;
+ const char * block_begin;
+ const char * p;
+ int done;
+
+ p = str;
+ block_begin = str;
+ count = 0;
+
+ while (length > 0) {
+#ifdef CUT_AT_MAX_VALID_IMF_LINE
+ if (count >= 998) {
+ /*
+ cut lines at maximum valid length for internet message
+ format standard (currently RFC 2822)
+
+ This should not happen.
+ In case there are some lines larger than 998 in body,
+ the encoding must be changed into base64 or quoted-printable
+ so that wrapping to 72 columns is done.
+ */
+
+ r = flush_buf(f, block_begin, count);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = fwrite(CRLF, 1, sizeof(CRLF) - 1, f);
+ if (r == 0)
+ return MAILIMF_ERROR_FILE;
+
+ count = 0;
+ block_begin = p;
+
+ * col = 0;
+ }
+#endif
+ switch (* p) {
+ case '\n':
+ r = flush_buf(f, block_begin, count);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = fwrite(CRLF, 1, sizeof(CRLF) - 1, f);
+ if (r == 0)
+ return MAILIMF_ERROR_FILE;
+
+ p ++;
+ length --;
+ count = 0;
+ block_begin = p;
+
+ * col = 0;
+ break;
+
+ case '\r':
+ done = 0;
+ if (length >= 2) {
+ if (* (p + 1) == '\n') {
+ r = flush_buf(f, block_begin, count);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = fwrite(CRLF, 1, sizeof(CRLF) - 1, f);
+ if (r == 0)
+ return MAILIMF_ERROR_FILE;
+
+ p += 2;
+ length -= 2;
+ count = 0;
+ block_begin = p;
+
+ * col = 0;
+
+ done = 1;
+ }
+ }
+ if (!done) {
+ r = flush_buf(f, block_begin, count);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = fwrite(CRLF, 1, sizeof(CRLF) - 1, f);
+ if (r == 0)
+ return MAILIMF_ERROR_FILE;
+
+ p ++;
+ length --;
+ count = 0;
+ block_begin = p;
+
+ * col = 0;
+ }
+ break;
+
+ default:
+ p ++;
+ count ++;
+ length --;
+ break;
+ }
+ }
+
+ r = flush_buf(f, block_begin, count);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ * col += count;
+
+ return MAILIMF_NO_ERROR;
+}
+
+#if 0
+int mailimf_header_string_write(FILE * f, int * col,
+ char * str, size_t length)
+{
+ char * p;
+ char * block_begin;
+ int current_col;
+ char * last_cut;
+ int r;
+ int first;
+
+ if (* col + length < MAX_MAIL_COL)
+ return mailimf_string_write(f, col, str, length);
+
+ first = 1;
+ p = str;
+ block_begin = p;
+ last_cut = block_begin;
+ current_col = * col;
+
+ while (1) {
+ if (current_col >= MAX_MAIL_COL) {
+ /* if we reach the maximum recommanded size of line */
+ if (last_cut == block_begin) {
+ /* if we could not find any place to cut */
+ if (first) {
+ /* fold the header */
+ r = mailimf_string_write(f, col, HEADER_FOLD,
+ sizeof(HEADER_FOLD) - 1);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ current_col = * col + p - block_begin;
+ first = 0;
+ }
+ else {
+ /* cut the header */
+ r = mailimf_string_write(f, col, block_begin, p - block_begin);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ r = mailimf_string_write(f, col, HEADER_FOLD,
+ sizeof(HEADER_FOLD) - 1);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ first = 0;
+ block_begin = p;
+ last_cut = block_begin;
+ current_col = * col + p - block_begin;
+ }
+ }
+ else {
+ /* if we found a place to cut */
+ r = mailimf_string_write(f, col, block_begin, last_cut - block_begin);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ r = mailimf_string_write(f, col, HEADER_FOLD,
+ sizeof(HEADER_FOLD) - 1);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ first = 0;
+ block_begin = last_cut;
+ last_cut = block_begin;
+ current_col = * col + p - block_begin;
+ continue;
+ }
+ }
+ else {
+ if (length == 0)
+ break;
+
+ switch (* p) {
+ case ' ':
+ case '\t':
+ last_cut = p;
+ current_col ++;
+ break;
+
+ case '\r':
+ case '\n':
+ current_col = 0;
+ break;
+
+ default:
+ current_col ++;
+ break;
+ }
+
+ p ++;
+ length --;
+ }
+ }
+
+ return mailimf_string_write(f, col, block_begin, p - block_begin);
+}
+#endif
+
+#if 0
+enum {
+ STATE_LOWER_72,
+ STATE_LOWER_72_CUT,
+ STATE_EQUAL_72,
+ STATE_LOWER_998,
+ STATE_EQUAL_998,
+};
+
+int mailimf_header_string_write(FILE * f, int * col,
+ const char * str, size_t length)
+{
+ int state;
+ const char * p;
+ const char * block_begin;
+ size_t size;
+ const char * cut;
+ int r;
+
+ if (* col < MAX_MAIL_COL)
+ state = STATE_LOWER_72_CUT;
+ else if (* col == MAX_MAIL_COL)
+ state = STATE_EQUAL_72;
+ else if (* col < MAX_VALID_IMF_LINE)
+ state = STATE_LOWER_998;
+ else
+ state = STATE_EQUAL_998;
+
+ p = str;
+ block_begin = p;
+ size = * col;
+ cut = p;
+
+ while (length > 0) {
+ switch (state) {
+ case STATE_LOWER_72:
+ switch (* p) {
+ case '\r':
+ case '\n':
+ p ++;
+ length --;
+ size = 0;
+ break;
+
+ case ' ':
+ case '\t':
+ cut = p;
+ p ++;
+ length --;
+ size ++;
+ state = STATE_LOWER_72_CUT;
+ break;
+
+ default:
+ if (size < MAX_MAIL_COL - 1) {
+ p ++;
+ length --;
+ size ++;
+ }
+ else {
+ state = STATE_EQUAL_72;
+ p ++;
+ length --;
+ size ++;
+ }
+ break;
+ }
+ break; /* end of STATE_LOWER_72 */
+
+ case STATE_LOWER_72_CUT:
+ switch (* p) {
+ case '\r':
+ case '\n':
+ p ++;
+ length --;
+ size = 0;
+ state = STATE_LOWER_72;
+ break;
+
+ case ' ':
+ case '\t':
+ cut = p;
+ p ++;
+ length --;
+ size ++;
+ break;
+
+ default:
+ if (size < MAX_MAIL_COL) {
+ p ++;
+ length --;
+ size ++;
+ }
+ else {
+ r = mailimf_string_write(f, col, block_begin, cut - block_begin);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ r = mailimf_string_write(f, col, HEADER_FOLD,
+ sizeof(HEADER_FOLD) - 1);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ p ++;
+ length --;
+ block_begin = cut;
+ if ((* block_begin == ' ') || (* block_begin == '\t'))
+ block_begin ++;
+ size = p - block_begin + * col;
+ state = STATE_LOWER_72;
+ }
+ break;
+ }
+ break; /* end of STATE_LOWER_72_CUT */
+
+ case STATE_EQUAL_72:
+ switch (* p) {
+ case '\r':
+ case '\n':
+ p ++;
+ length --;
+ size = 0;
+ state = STATE_LOWER_72;
+ break;
+
+ case ' ':
+ case '\t':
+ r = mailimf_string_write(f, col, block_begin, p - block_begin);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ r = mailimf_string_write(f, col, HEADER_FOLD,
+ sizeof(HEADER_FOLD) - 1);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ p ++;
+ length --;
+ block_begin = p;
+ size = p - block_begin + * col;
+ state = STATE_LOWER_72;
+ break;
+
+ default:
+ p ++;
+ length --;
+ size ++;
+ state = STATE_LOWER_998;
+ break;
+ }
+ break; /* end of STATE_EQUAL_72 */
+
+ case STATE_LOWER_998:
+ switch (* p) {
+ case '\r':
+ case '\n':
+ p ++;
+ length --;
+ size = 0;
+ state = STATE_LOWER_72;
+ break;
+
+ case ' ':
+ case '\t':
+ r = mailimf_string_write(f, col, block_begin, p - block_begin);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ r = mailimf_string_write(f, col, HEADER_FOLD,
+ sizeof(HEADER_FOLD) - 1);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ p ++;
+ length --;
+ block_begin = p;
+ size = p - block_begin + * col;
+ state = STATE_LOWER_72;
+ break;
+
+ default:
+ if (size < MAX_VALID_IMF_LINE - 1) {
+ p ++;
+ length --;
+ size ++;
+ }
+ else {
+ p ++;
+ length --;
+ size = 0;
+ state = STATE_EQUAL_998;
+ }
+ break;
+ }
+ break; /* end of STATE_LOWER_998 */
+
+ case STATE_EQUAL_998:
+ switch (* p) {
+ case '\r':
+ case '\n':
+ p ++;
+ length --;
+ size = 0;
+ state = STATE_LOWER_72;
+ break;
+
+ case ' ':
+ case '\t':
+ r = mailimf_string_write(f, col, block_begin, p - block_begin);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ r = mailimf_string_write(f, col, HEADER_FOLD,
+ sizeof(HEADER_FOLD) - 1);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ p ++;
+ length --;
+ block_begin = p;
+ size = p - block_begin + * col;
+ state = STATE_LOWER_72;
+ break;
+
+ default:
+#ifdef CUT_AT_MAX_VALID_IMF_LINE
+ r = mailimf_string_write(f, col, block_begin, p - block_begin);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ r = mailimf_string_write(f, col, HEADER_FOLD,
+ sizeof(HEADER_FOLD) - 1);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ p ++;
+ length --;
+ block_begin = p;
+ size = p - block_begin + * col;
+ state = STATE_LOWER_72;
+#else
+ p ++;
+ length --;
+ size ++;
+#endif
+ break;
+ }
+ break; /* end of STATE_EQUAL_998 */
+ }
+ }
+
+ r = mailimf_string_write(f, col, block_begin, p - block_begin);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ return MAILIMF_NO_ERROR;
+}
+#endif
+
+enum {
+ STATE_BEGIN,
+ STATE_WORD,
+ STATE_SPACE,
+};
+
+int mailimf_header_string_write(FILE * f, int * col,
+ const char * str, size_t length)
+{
+ int state;
+ const char * p;
+ const char * word_begin;
+ const char * word_end;
+ const char * next_word;
+ int first;
+
+ state = STATE_BEGIN;
+
+ p = str;
+ word_begin = p;
+ word_end = p;
+ next_word = p;
+ first = 1;
+
+ while (length > 0) {
+ switch (state) {
+ case STATE_BEGIN:
+ switch (* p) {
+ case '\r':
+ case '\n':
+ case ' ':
+ case '\t':
+ p ++;
+ length --;
+ break;
+
+ default:
+ word_begin = p;
+ state = STATE_WORD;
+ break;
+ }
+ break;
+
+ case STATE_SPACE:
+ switch (* p) {
+ case '\r':
+ case '\n':
+ case ' ':
+ case '\t':
+ p ++;
+ length --;
+ break;
+
+ default:
+ word_begin = p;
+ state = STATE_WORD;
+ break;
+ }
+ break;
+
+ case STATE_WORD:
+ switch (* p) {
+ case '\r':
+ case '\n':
+ case ' ':
+ case '\t':
+ if (p - word_begin + (* col) + 1 > MAX_MAIL_COL)
+ mailimf_string_write(f, col, HEADER_FOLD,
+ sizeof(HEADER_FOLD) - 1);
+ else {
+ if (!first)
+ mailimf_string_write(f, col, " ", 1);
+ }
+ first = 0;
+ mailimf_string_write(f, col, word_begin, p - word_begin);
+ state = STATE_SPACE;
+ break;
+
+ default:
+ if (p - word_begin + (* col) >= MAX_VALID_IMF_LINE) {
+ mailimf_string_write(f, col, word_begin, p - word_begin);
+ mailimf_string_write(f, col, HEADER_FOLD,
+ sizeof(HEADER_FOLD) - 1);
+ word_begin = p;
+ }
+ p ++;
+ length --;
+ break;
+ }
+ break;
+ }
+ }
+
+ if (state == STATE_WORD) {
+ if (p - word_begin + (* col) >= MAX_MAIL_COL)
+ mailimf_string_write(f, col, HEADER_FOLD,
+ sizeof(HEADER_FOLD) - 1);
+ else {
+ if (!first)
+ mailimf_string_write(f, col, " ", 1);
+ }
+ first = 0;
+ mailimf_string_write(f, col, word_begin, p - word_begin);
+ }
+
+ return MAILIMF_NO_ERROR;
+}
+
+int mailimf_envelope_fields_write(FILE * f, int * col,
+ struct mailimf_fields * fields)
+{
+ clistiter * cur;
+
+ for(cur = clist_begin(fields->fld_list) ; cur != NULL ;
+ cur = clist_next(cur)) {
+ int r;
+ struct mailimf_field * field;
+
+ field = clist_content(cur);
+ if (field->fld_type != MAILIMF_FIELD_OPTIONAL_FIELD) {
+ r = mailimf_field_write(f, col, field);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ }
+ }
+
+ return MAILIMF_NO_ERROR;
+}
+
+int mailimf_fields_write(FILE * f, int * col,
+ struct mailimf_fields * fields)
+{
+ clistiter * cur;
+
+ for(cur = clist_begin(fields->fld_list) ; cur != NULL ;
+ cur = clist_next(cur)) {
+ int r;
+
+ r = mailimf_field_write(f, col, clist_content(cur));
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ }
+
+ return MAILIMF_NO_ERROR;
+}
+
+#if 0
+int mailimf_unparsed_fields_write(FILE * f, int * col,
+ struct mailimf_unparsed_fields * fields)
+{
+ clistiter * cur;
+
+ for(cur = clist_begin(fields->list) ; cur != NULL ; cur = cur->next) {
+ int r;
+
+ r = mailimf_optional_field_write(f, col, cur->data);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ }
+
+ return MAILIMF_NO_ERROR;
+}
+#endif
+
+int mailimf_field_write(FILE * f, int * col,
+ struct mailimf_field * field)
+{
+ int r;
+
+ switch (field->fld_type) {
+ case MAILIMF_FIELD_RETURN_PATH:
+ r = mailimf_return_write(f, col, field->fld_data.fld_return_path);
+ break;
+ case MAILIMF_FIELD_RESENT_DATE:
+ r = mailimf_resent_date_write(f, col, field->fld_data.fld_resent_date);
+ break;
+ case MAILIMF_FIELD_RESENT_FROM:
+ r = mailimf_resent_from_write(f, col, field->fld_data.fld_resent_from);
+ break;
+ case MAILIMF_FIELD_RESENT_SENDER:
+ r = mailimf_resent_sender_write(f, col, field->fld_data.fld_resent_sender);
+ break;
+ case MAILIMF_FIELD_RESENT_TO:
+ r = mailimf_resent_to_write(f, col, field->fld_data.fld_resent_to);
+ break;
+ case MAILIMF_FIELD_RESENT_CC:
+ r = mailimf_resent_cc_write(f, col, field->fld_data.fld_resent_cc);
+ break;
+ case MAILIMF_FIELD_RESENT_BCC:
+ r = mailimf_resent_bcc_write(f, col, field->fld_data.fld_resent_bcc);
+ break;
+ case MAILIMF_FIELD_RESENT_MSG_ID:
+ r = mailimf_resent_msg_id_write(f, col, field->fld_data.fld_resent_msg_id);
+ break;
+ case MAILIMF_FIELD_ORIG_DATE:
+ r = mailimf_orig_date_write(f, col, field->fld_data.fld_orig_date);
+ break;
+ case MAILIMF_FIELD_FROM:
+ r = mailimf_from_write(f, col, field->fld_data.fld_from);
+ break;
+ case MAILIMF_FIELD_SENDER:
+ r = mailimf_sender_write(f, col, field->fld_data.fld_sender);
+ break;
+ case MAILIMF_FIELD_REPLY_TO:
+ r = mailimf_reply_to_write(f, col, field->fld_data.fld_reply_to);
+ break;
+ case MAILIMF_FIELD_TO:
+ r = mailimf_to_write(f, col, field->fld_data.fld_to);
+ break;
+ case MAILIMF_FIELD_CC:
+ r = mailimf_cc_write(f, col, field->fld_data.fld_cc);
+ break;
+ case MAILIMF_FIELD_BCC:
+ r = mailimf_bcc_write(f, col, field->fld_data.fld_bcc);
+ break;
+ case MAILIMF_FIELD_MESSAGE_ID:
+ r = mailimf_message_id_write(f, col, field->fld_data.fld_message_id);
+ break;
+ case MAILIMF_FIELD_IN_REPLY_TO:
+ r = mailimf_in_reply_to_write(f, col, field->fld_data.fld_in_reply_to);
+ break;
+ case MAILIMF_FIELD_REFERENCES:
+ r = mailimf_references_write(f, col, field->fld_data.fld_references);
+ break;
+ case MAILIMF_FIELD_SUBJECT:
+ r = mailimf_subject_write(f, col, field->fld_data.fld_subject);
+ break;
+ case MAILIMF_FIELD_COMMENTS:
+ r = mailimf_comments_write(f, col, field->fld_data.fld_comments);
+ break;
+ case MAILIMF_FIELD_KEYWORDS:
+ r = mailimf_keywords_write(f, col, field->fld_data.fld_keywords);
+ break;
+ case MAILIMF_FIELD_OPTIONAL_FIELD:
+ r = mailimf_optional_field_write(f, col, field->fld_data.fld_optional_field);
+ break;
+ default:
+ r = MAILIMF_ERROR_INVAL;
+ break;
+ }
+
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ return MAILIMF_NO_ERROR;
+}
+
+
+static int mailimf_orig_date_write(FILE * f, int * col,
+ struct mailimf_orig_date * date)
+{
+ int r;
+
+ r = mailimf_string_write(f, col, "Date: ", 6);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_date_time_write(f, col, date->dt_date_time);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_string_write(f, col, "\r\n", 2);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+#if 0
+ * col = 0;
+#endif
+
+ return MAILIMF_NO_ERROR;
+}
+
+#define MAX_DATE_STR 256
+
+/* 0 = Sunday */
+/* y > 1752 */
+
+static int dayofweek(int year, int month, int day)
+{
+ static int offset[] = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4};
+
+ year -= month < 3;
+
+ return (year + year/4 - year/100 + year/400 + offset[month-1] + day) % 7;
+}
+
+static const char * week_of_day_str[] = { "Sun", "Mon", "Tue", "Wed", "Thu",
+ "Fri", "Sat"};
+static const char * month_str[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
+
+static int mailimf_date_time_write(FILE * f, int * col,
+ struct mailimf_date_time * date_time)
+{
+ int r;
+ char date_str[MAX_DATE_STR];
+#if 0
+ struct tm tmval;
+ time_t timeval;
+#endif
+ int wday;
+
+#if 0
+ tmval.tm_sec = date_time->sec;
+ tmval.tm_min = date_time->min;
+ tmval.tm_hour = date_time->hour;
+ tmval.tm_sec = date_time->sec;
+ tmval.tm_mday = date_time->day;
+ tmval.tm_mon = date_time->month - 1;
+ tmval.tm_year = date_time->year - 1900;
+ tmval.tm_isdst = 1;
+
+ timeval = mktime(&tmval);
+
+ localtime_r(&timeval, &tmval);
+#endif
+
+ wday = dayofweek(date_time->dt_year, date_time->dt_month, date_time->dt_day);
+
+ snprintf(date_str, MAX_DATE_STR, "%s, %i %s %i %02i:%02i:%02i %+05i",
+ week_of_day_str[wday], date_time->dt_day,
+ month_str[date_time->dt_month - 1],
+ date_time->dt_year, date_time->dt_hour,
+ date_time->dt_min, date_time->dt_sec,
+ date_time->dt_zone);
+
+ r = mailimf_string_write(f, col, date_str, strlen(date_str));
+
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ return MAILIMF_NO_ERROR;
+}
+
+static int mailimf_from_write(FILE * f, int * col,
+ struct mailimf_from * from)
+{
+ int r;
+
+ r = mailimf_string_write(f, col, "From: ", 6);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_mailbox_list_write(f, col, from->frm_mb_list);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_string_write(f, col, "\r\n", 2);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+#if 0
+ * col = 0;
+#endif
+
+ return MAILIMF_NO_ERROR;
+}
+
+static int mailimf_sender_write(FILE * f, int * col,
+ struct mailimf_sender * sender)
+{
+ int r;
+
+ r = mailimf_string_write(f, col, "Sender: ", 8);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_mailbox_write(f, col, sender->snd_mb);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_string_write(f, col, "\r\n", 2);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+#if 0
+ * col = 0;
+#endif
+
+ return MAILIMF_NO_ERROR;
+}
+
+static int mailimf_reply_to_write(FILE * f, int * col,
+ struct mailimf_reply_to * reply_to)
+{
+ int r;
+
+ r = mailimf_string_write(f, col, "Reply-To: ", 10);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_address_list_write(f, col, reply_to->rt_addr_list);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_string_write(f, col, "\r\n", 2);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+#if 0
+ * col = 0;
+#endif
+
+ return MAILIMF_NO_ERROR;
+}
+
+
+static int mailimf_to_write(FILE * f, int * col,
+ struct mailimf_to * to)
+{
+ int r;
+
+ r = mailimf_string_write(f, col, "To: ", 4);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_address_list_write(f, col, to->to_addr_list);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_string_write(f, col, "\r\n", 2);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+#if 0
+ * col = 0;
+#endif
+
+ return MAILIMF_NO_ERROR;
+}
+
+
+static int mailimf_cc_write(FILE * f, int * col,
+ struct mailimf_cc * cc)
+{
+ int r;
+
+ r = mailimf_string_write(f, col, "Cc: ", 4);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_address_list_write(f, col, cc->cc_addr_list);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_string_write(f, col, "\r\n", 2);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+#if 0
+ * col = 0;
+#endif
+
+ return MAILIMF_NO_ERROR;
+}
+
+
+static int mailimf_bcc_write(FILE * f, int * col,
+ struct mailimf_bcc * bcc)
+{
+ int r;
+
+ r = mailimf_string_write(f, col, "Bcc: ", 5);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ if (bcc->bcc_addr_list != NULL) {
+ r = mailimf_address_list_write(f, col, bcc->bcc_addr_list);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ }
+
+ r = mailimf_string_write(f, col, "\r\n", 2);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+#if 0
+ * col = 0;
+#endif
+
+ return MAILIMF_NO_ERROR;
+}
+
+
+static int mailimf_message_id_write(FILE * f, int * col,
+ struct mailimf_message_id * message_id)
+{
+ int r;
+
+ r = mailimf_string_write(f, col, "Message-ID: ", 12);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_string_write(f, col, "<", 1);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_string_write(f, col,
+ message_id->mid_value,
+ strlen(message_id->mid_value));
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_string_write(f, col, ">", 1);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_string_write(f, col, "\r\n", 2);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+#if 0
+ * col = 0;
+#endif
+
+ return MAILIMF_NO_ERROR;
+}
+
+
+static int mailimf_msg_id_list_write(FILE * f, int * col, clist * mid_list)
+{
+ clistiter * cur;
+ int r;
+ int first;
+
+ first = TRUE;
+
+ for(cur = clist_begin(mid_list) ; cur != NULL ; cur = clist_next(cur)) {
+ char * msgid;
+ size_t len;
+
+ msgid = clist_content(cur);
+ len = strlen(msgid);
+
+ /*
+ XXX - if this is the first message ID, don't fold.
+ This is a workaround for a bug of old versions of INN.
+ */
+ if (!first) {
+ if (* col > 1) {
+
+ if (* col + len >= MAX_MAIL_COL) {
+ r = mailimf_string_write(f, col, "\r\n ", 3);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+#if 0
+ * col = 1;
+#endif
+ first = TRUE;
+ }
+ }
+ }
+
+ if (!first) {
+ r = mailimf_string_write(f, col, " ", 1);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ }
+ else {
+ first = FALSE;
+ }
+
+ r = mailimf_string_write(f, col, "<", 1);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_string_write(f, col, msgid, len);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_string_write(f, col, ">", 1);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ }
+
+ return MAILIMF_NO_ERROR;
+}
+
+
+static int mailimf_in_reply_to_write(FILE * f, int * col,
+ struct mailimf_in_reply_to * in_reply_to)
+{
+ int r;
+
+ r = mailimf_string_write(f, col, "In-Reply-To: ", 13);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_msg_id_list_write(f, col, in_reply_to->mid_list);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_string_write(f, col, "\r\n", 2);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+#if 0
+ * col = 0;
+#endif
+
+ return MAILIMF_NO_ERROR;
+}
+
+
+static int mailimf_references_write(FILE * f, int * col,
+ struct mailimf_references * references)
+{
+ int r;
+
+ r = mailimf_string_write(f, col, "References: ", 12);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_msg_id_list_write(f, col, references->mid_list);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_string_write(f, col, "\r\n", 2);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+#if 0
+ * col = 0;
+#endif
+
+ return MAILIMF_NO_ERROR;
+}
+
+
+
+static int mailimf_subject_write(FILE * f, int * col,
+ struct mailimf_subject * subject)
+{
+ int r;
+
+ r = mailimf_string_write(f, col, "Subject: ", 9);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_header_string_write(f, col,
+ subject->sbj_value, strlen(subject->sbj_value));
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_string_write(f, col, "\r\n", 2);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+#if 0
+ * col = 0;
+#endif
+
+ return MAILIMF_NO_ERROR;
+}
+
+int mailimf_address_list_write(FILE * f, int * col,
+ struct mailimf_address_list * addr_list)
+{
+ clistiter * cur;
+ int r;
+ int first;
+
+ first = TRUE;
+
+ for(cur = clist_begin(addr_list->ad_list) ; cur != NULL ;
+ cur = clist_next(cur)) {
+ struct mailimf_address * addr;
+
+ addr = clist_content(cur);
+
+ if (!first) {
+ r = mailimf_string_write(f, col, ", ", 2);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ }
+ else {
+ first = FALSE;
+ }
+
+ r = mailimf_address_write(f, col, addr);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ }
+
+ return MAILIMF_NO_ERROR;
+}
+
+
+static int mailimf_address_write(FILE * f, int * col,
+ struct mailimf_address * addr)
+{
+ int r;
+
+ switch(addr->ad_type) {
+ case MAILIMF_ADDRESS_MAILBOX:
+ r = mailimf_mailbox_write(f, col, addr->ad_data.ad_mailbox);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ break;
+
+ case MAILIMF_ADDRESS_GROUP:
+ r = mailimf_group_write(f, col, addr->ad_data.ad_group);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ break;
+ }
+
+ return MAILIMF_NO_ERROR;
+}
+
+
+static int mailimf_group_write(FILE * f, int * col,
+ struct mailimf_group * group)
+{
+ int r;
+
+ r = mailimf_header_string_write(f, col, group->grp_display_name,
+ strlen(group->grp_display_name));
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_string_write(f, col, ": ", 2);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ if (group->grp_mb_list != NULL) {
+ r = mailimf_mailbox_list_write(f, col, group->grp_mb_list);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ }
+
+ r = mailimf_string_write(f, col, ";", 1);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ return MAILIMF_NO_ERROR;
+}
+
+
+int mailimf_mailbox_list_write(FILE * f, int * col,
+ struct mailimf_mailbox_list * mb_list)
+{
+ clistiter * cur;
+ int r;
+ int first;
+
+ first = TRUE;
+
+ for(cur = clist_begin(mb_list->mb_list) ; cur != NULL ;
+ cur = clist_next(cur)) {
+ struct mailimf_mailbox * mb;
+
+ mb = clist_content(cur);
+
+ if (!first) {
+ r = mailimf_string_write(f, col, ", ", 2);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ }
+ else {
+ first = FALSE;
+ }
+
+ r = mailimf_mailbox_write(f, col, mb);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ }
+
+ return MAILIMF_NO_ERROR;
+}
+
+
+int mailimf_quoted_string_write(FILE * f, int * col,
+ const char * string, size_t len)
+{
+ int r;
+ size_t i;
+
+ fputc('\"', f);
+ for(i = 0 ; i < len ; i ++) {
+ switch (string[i]) {
+ case '\\':
+ case '\"':
+ r = fputc('\\', f);
+ if (r < 0)
+ return MAILIMF_ERROR_FILE;
+ r = fputc(string[i], f);
+ if (r < 0)
+ return MAILIMF_ERROR_FILE;
+ (* col) += 2;
+ break;
+
+ default:
+ r = fputc(string[i], f);
+ if (r < 0)
+ return MAILIMF_ERROR_FILE;
+ (* col) ++;
+ break;
+ }
+ }
+ fputc('\"', f);
+
+ return MAILIMF_NO_ERROR;
+}
+
+
+/*
+static int
+atext = ALPHA / DIGIT / ; Any character except controls,
+ "!" / "#" / ; SP, and specials.
+ "$" / "%" / ; Used for atoms
+ "&" / "'" /
+ "*" / "+" /
+ "-" / "/" /
+ "=" / "?" /
+ "^" / "_" /
+ "`" / "{" /
+ "|" / "}" /
+ "~"
+*/
+
+static int is_atext(const char * s)
+{
+ const char * p;
+
+ for(p = s ; * p != 0 ; p ++) {
+ if (isalpha((unsigned char) * p))
+ continue;
+ if (isdigit((unsigned char) * p))
+ continue;
+ switch (*p) {
+ case ' ':
+ case '\t':
+ case '!':
+ case '#':
+ case '$':
+ case '%':
+ case '&':
+ case '\'':
+ case '*':
+ case '+':
+ case '-':
+ case '/':
+ case '=':
+ case '?':
+ case '^':
+ case '_':
+ case '`':
+ case '{':
+ case '|':
+ case '}':
+ case '~':
+ break;
+ default:
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+static int mailimf_mailbox_write(FILE * f, int * col,
+ struct mailimf_mailbox * mb)
+{
+ int r;
+ int do_fold;
+
+#if 0
+ if (* col > 1) {
+
+ if (mb->mb_display_name != NULL) {
+ if (* col + strlen(mb->mb_display_name) >= MAX_MAIL_COL) {
+ r = mailimf_string_write(f, col, "\r\n ", 3);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+#if 0
+ * col = 1;
+#endif
+ }
+ }
+ }
+#endif
+
+ if (mb->mb_display_name) {
+
+ if (is_atext(mb->mb_display_name)) {
+ r = mailimf_header_string_write(f, col, mb->mb_display_name,
+ strlen(mb->mb_display_name));
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ }
+ else {
+ if (mb->mb_display_name != NULL) {
+ if (* col + strlen(mb->mb_display_name) >= MAX_MAIL_COL) {
+ r = mailimf_string_write(f, col, "\r\n ", 3);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ }
+ }
+
+ if (strlen(mb->mb_display_name) > MAX_VALID_IMF_LINE / 2)
+ return MAILIMF_ERROR_INVAL;
+
+ r = mailimf_quoted_string_write(f, col, mb->mb_display_name,
+ strlen(mb->mb_display_name));
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ }
+
+ do_fold = 0;
+ if (* col > 1) {
+
+ if (* col + strlen(mb->mb_addr_spec) + 3 >= MAX_MAIL_COL) {
+ r = mailimf_string_write(f, col, "\r\n ", 3);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+#if 0
+ * col = 1;
+#endif
+ do_fold = 1;
+ }
+ }
+
+ if (do_fold)
+ r = mailimf_string_write(f, col, "<", 1);
+ else
+ r = mailimf_string_write(f, col, " <", 2);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_string_write(f, col, mb->mb_addr_spec,
+ strlen(mb->mb_addr_spec));
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_string_write(f, col, ">", 1);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ }
+ else {
+ if (* col + strlen(mb->mb_addr_spec) >= MAX_MAIL_COL) {
+ r = mailimf_string_write(f, col, "\r\n ", 3);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ }
+
+ r = mailimf_string_write(f, col,
+ mb->mb_addr_spec, strlen(mb->mb_addr_spec));
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ }
+
+
+ return MAILIMF_NO_ERROR;
+}
+
+static int mailimf_comments_write(FILE * f, int * col,
+ struct mailimf_comments * comments)
+{
+ int r;
+
+ r = mailimf_string_write(f, col, "Comments: ", 10);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_header_string_write(f, col,
+ comments->cm_value, strlen(comments->cm_value));
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_string_write(f, col, "\r\n", 2);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+#if 0
+ * col = 0;
+#endif
+
+ return MAILIMF_NO_ERROR;
+}
+
+static int mailimf_optional_field_write(FILE * f, int * col,
+ struct mailimf_optional_field * field)
+{
+ int r;
+
+ if (strlen(field->fld_name) + 2 > MAX_VALID_IMF_LINE)
+ return MAILIMF_ERROR_INVAL;
+
+ r = mailimf_string_write(f, col, field->fld_name, strlen(field->fld_name));
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_string_write(f, col, ": ", 2);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_header_string_write(f, col, field->fld_value,
+ strlen(field->fld_value));
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+#if 0
+ /* XXX parsing debug */
+ mailimf_string_write(f, col, " (X)", 4);
+#endif
+
+ r = mailimf_string_write(f, col, "\r\n", 2);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+#if 0
+ * col = 0;
+#endif
+
+ return MAILIMF_NO_ERROR;
+}
+
+static int mailimf_keywords_write(FILE * f, int * col,
+ struct mailimf_keywords * keywords)
+{
+ int r;
+ clistiter * cur;
+ int first;
+
+ r = mailimf_string_write(f, col, "Keywords: ", 10);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ first = TRUE;
+
+ for(cur = clist_begin(keywords->kw_list) ; cur != NULL ;
+ cur = clist_next(cur)) {
+ char * keyword;
+ size_t len;
+
+ keyword = clist_content(cur);
+ len = strlen(keyword);
+
+ if (!first) {
+ r = mailimf_string_write(f, col, ", ", 2);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ }
+ else {
+ first = FALSE;
+ }
+
+#if 0
+ if (* col > 1) {
+
+ if (* col + len >= MAX_MAIL_COL) {
+ r = mailimf_string_write(f, col, "\r\n ", 3);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+#if 0
+ * col = 1;
+#endif
+ }
+ }
+#endif
+
+ r = mailimf_header_string_write(f, col, keyword, len);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ }
+
+ r = mailimf_string_write(f, col, "\r\n", 2);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+#if 0
+ * col = 0;
+#endif
+
+ return MAILIMF_NO_ERROR;
+}
+
+#if 0
+static int mailimf_delivering_info_write(FILE * f, int * col,
+ struct mailimf_delivering_info * info)
+{
+ clistiter * cur;
+ int r;
+
+ for(cur = clist_begin(info->received_fields) ;
+ cur != NULL ; cur = cur->next) {
+ struct mailimf_trace_resent_fields * field;
+
+ field = cur->data;
+
+ r = mailimf_trace_resent_fields_write(f, col, field);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ }
+
+ return MAILIMF_NO_ERROR;
+}
+
+
+static int
+mailimf_trace_resent_fields_write(FILE * f, int * col,
+ struct mailimf_trace_resent_fields * field)
+{
+ int r;
+
+ if (field->return_path != NULL) {
+ r = mailimf_return_write(f, col, field->return_path);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ }
+
+ if (field->resent_fields != NULL) {
+ r = mailimf_resent_fields_write(f, col, field->resent_fields);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ }
+
+ return MAILIMF_NO_ERROR;
+}
+#endif
+
+static int mailimf_return_write(FILE * f, int * col,
+ struct mailimf_return * return_path)
+{
+ int r;
+
+ r = mailimf_string_write(f, col, "Return-Path: ", 13);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_path_write(f, col, return_path->ret_path);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_string_write(f, col, "\r\n", 2);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+#if 0
+ * col = 0;
+#endif
+
+ return MAILIMF_NO_ERROR;
+}
+
+static int mailimf_path_write(FILE * f, int * col,
+ struct mailimf_path * path)
+{
+ int r;
+
+ r = mailimf_string_write(f, col, "<", 1);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_string_write(f, col, path->pt_addr_spec,
+ strlen(path->pt_addr_spec));
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_string_write(f, col, ">", 1);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ return MAILIMF_NO_ERROR;
+}
+
+#if 0
+static int mailimf_resent_fields_write(FILE * f, int * col,
+ struct mailimf_resent_fields_list *
+ resent_fields)
+{
+ clistiter * cur;
+ int r;
+
+ for(cur = clist_begin(resent_fields->list) ; cur != NULL ; cur = cur->next) {
+ struct mailimf_resent_field * field;
+
+ field = cur->data;
+
+ r = mailimf_resent_field_write(f, col, field);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ }
+
+ return MAILIMF_NO_ERROR;
+}
+
+
+
+static int mailimf_resent_field_write(FILE * f, int * col,
+ struct mailimf_resent_field *
+ resent_field)
+{
+ int r;
+
+ switch (resent_field->type) {
+ case MAILIMF_RESENT_FIELD_DATE:
+ r = mailimf_resent_date_write(f, col, resent_field->resent_date);
+ break;
+
+ case MAILIMF_RESENT_FIELD_FROM:
+ r = mailimf_resent_from_write(f, col, resent_field->resent_from);
+ break;
+
+ case MAILIMF_RESENT_FIELD_SENDER:
+ r = mailimf_resent_sender_write(f, col, resent_field->resent_sender);
+ break;
+
+ case MAILIMF_RESENT_FIELD_TO:
+ r = mailimf_resent_to_write(f, col, resent_field->resent_to);
+ break;
+
+ case MAILIMF_RESENT_FIELD_CC:
+ r = mailimf_resent_cc_write(f, col, resent_field->resent_cc);
+ break;
+
+ case MAILIMF_RESENT_FIELD_BCC:
+ r = mailimf_resent_bcc_write(f, col, resent_field->resent_bcc);
+ break;
+
+ case MAILIMF_RESENT_FIELD_MSG_ID:
+ r = mailimf_resent_msg_id_write(f, col, resent_field->resent_msg_id);
+ break;
+ default:
+ r = MAILIMF_ERROR_INVAL;
+ break;
+ }
+
+
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ return MAILIMF_NO_ERROR;
+}
+#endif
+
+static int mailimf_resent_date_write(FILE * f, int * col,
+ struct mailimf_orig_date * date)
+{
+ int r;
+
+ r = mailimf_string_write(f, col, "Resent-Date: ", 13);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_date_time_write(f, col, date->dt_date_time);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_string_write(f, col, "\r\n", 2);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+#if 0
+ * col = 0;
+#endif
+
+ return MAILIMF_NO_ERROR;
+}
+
+static int mailimf_resent_from_write(FILE * f, int * col,
+ struct mailimf_from * from)
+{
+ int r;
+
+ r = mailimf_string_write(f, col, "Resent-From: ", 13);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_mailbox_list_write(f, col, from->frm_mb_list);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_string_write(f, col, "\r\n", 2);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+#if 0
+ * col = 0;
+#endif
+
+ return MAILIMF_NO_ERROR;
+}
+
+static int mailimf_resent_sender_write(FILE * f, int * col,
+ struct mailimf_sender * sender)
+{
+ int r;
+
+ r = mailimf_string_write(f, col, "Resent-Sender: ", 15);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_mailbox_write(f, col, sender->snd_mb);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_string_write(f, col, "\r\n", 2);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+#if 0
+ * col = 0;
+#endif
+
+ return MAILIMF_NO_ERROR;
+}
+
+static int mailimf_resent_to_write(FILE * f, int * col,
+ struct mailimf_to * to)
+{
+ int r;
+
+ r = mailimf_string_write(f, col, "Resent-To: ", 11);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_address_list_write(f, col, to->to_addr_list);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_string_write(f, col, "\r\n", 2);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+#if 0
+ * col = 0;
+#endif
+
+ return MAILIMF_NO_ERROR;
+}
+
+
+static int mailimf_resent_cc_write(FILE * f, int * col,
+ struct mailimf_cc * cc)
+{
+ int r;
+
+ r = mailimf_string_write(f, col, "Resent-Cc: ", 11);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_address_list_write(f, col, cc->cc_addr_list);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_string_write(f, col, "\r\n", 2);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+#if 0
+ * col = 0;
+#endif
+
+ return MAILIMF_NO_ERROR;
+}
+
+
+static int mailimf_resent_bcc_write(FILE * f, int * col,
+ struct mailimf_bcc * bcc)
+{
+ int r;
+
+ r = mailimf_string_write(f, col, "Resent-Bcc: ", 12);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ if (bcc->bcc_addr_list != NULL) {
+ r = mailimf_address_list_write(f, col, bcc->bcc_addr_list);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ }
+
+ r = mailimf_string_write(f, col, "\r\n", 2);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+#if 0
+ * col = 0;
+#endif
+
+ return MAILIMF_NO_ERROR;
+}
+
+
+static int
+mailimf_resent_msg_id_write(FILE * f, int * col,
+ struct mailimf_message_id * message_id)
+{
+ int r;
+
+ r = mailimf_string_write(f, col, "Resent-Message-ID: ", 19);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_string_write(f, col, "<", 1);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_string_write(f, col,
+ message_id->mid_value, strlen(message_id->mid_value));
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_string_write(f, col, ">", 1);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_string_write(f, col, "\r\n", 2);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+#if 0
+ * col = 0;
+#endif
+
+ return MAILIMF_NO_ERROR;
+}
diff --git a/libetpan/src/low-level/imf/mailimf_write.h b/libetpan/src/low-level/imf/mailimf_write.h
new file mode 100644
index 0000000..a3441dd
--- a/dev/null
+++ b/libetpan/src/low-level/imf/mailimf_write.h
@@ -0,0 +1,134 @@
+/*
+ * 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$
+ */
+
+#ifndef MAILIMF_WRITE_H
+
+#define MAILIMF_WRITE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdio.h>
+#include <libetpan/mailimf_types.h>
+
+/*
+ mailimf_string_write writes a string to a given stream
+
+ @param f is the stream
+ @param col (* col) is the column number where we will start to
+ write the text, the ending column will be stored in (* col)
+ @param str is the string to write
+*/
+
+int mailimf_string_write(FILE * f, int * col,
+ const char * str, size_t length);
+
+
+/*
+ mailimf_fields_write writes the fields to a given stream
+
+ @param f is the stream
+ @param col (* col) is the column number where we will start to
+ write the text, the ending column will be stored in (* col)
+ @param fields is the fields to write
+*/
+
+int mailimf_fields_write(FILE * f, int * col,
+ struct mailimf_fields * fields);
+
+
+/*
+ mailimf_envelope_fields_write writes only some fields to a given stream
+
+ @param f is the stream
+ @param col (* col) is the column number where we will start to
+ write the text, the ending column will be stored in (* col)
+ @param fields is the fields to write
+*/
+
+int mailimf_envelope_fields_write(FILE * f, int * col,
+ struct mailimf_fields * fields);
+
+
+/*
+ mailimf_field_write writes a field to a given stream
+
+ @param f is the stream
+ @param col (* col) is the column number where we will start to
+ write the text, the ending column will be stored in (* col)
+ @param field is the field to write
+*/
+
+int mailimf_field_write(FILE * f, int * col,
+ struct mailimf_field * field);
+
+/*
+ mailimf_quoted_string_write writes a string that is quoted
+ to a given stream
+
+ @param f is the stream
+ @param col (* col) is the column number where we will start to
+ write the text, the ending column will be stored in (* col)
+ @param string is the string to quote and write
+*/
+
+int mailimf_quoted_string_write(FILE * f, int * col,
+ const char * string, size_t len);
+
+int mailimf_address_list_write(FILE * f, int * col,
+ struct mailimf_address_list * addr_list);
+
+int mailimf_mailbox_list_write(FILE * f, int * col,
+ struct mailimf_mailbox_list * mb_list);
+
+/*
+ mailimf_header_string_write writes a header value and fold the header
+ if needed.
+
+ @param f is the stream
+ @param col (* col) is the column number where we will start to
+ write the text, the ending column will be stored in (* col)
+ @param str is the string to write
+*/
+
+int mailimf_header_string_write(FILE * f, int * col,
+ const char * str, size_t length);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libetpan/src/low-level/imf/mailimf_write_file.c b/libetpan/src/low-level/imf/mailimf_write_file.c
new file mode 100644
index 0000000..a1f7187
--- a/dev/null
+++ b/libetpan/src/low-level/imf/mailimf_write_file.c
@@ -0,0 +1,149 @@
+/*
+ * 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 "mailimf_write_file.h"
+#include "mailimf_write_generic.h"
+
+static int do_write(void * data, const char * str, size_t length)
+{
+ FILE * f;
+
+ f = data;
+
+ return fwrite(str, 1, length, f);
+}
+
+int mailimf_string_write_file(FILE * f, int * col,
+ const char * str, size_t length)
+{
+ return mailimf_string_write_driver(do_write, f, col, str, length);
+}
+
+int mailimf_fields_write_file(FILE * f, int * col,
+ struct mailimf_fields * fields)
+{
+ return mailimf_fields_write_driver(do_write, f, col, fields);
+}
+
+int mailimf_envelope_fields_write_file(FILE * f, int * col,
+ struct mailimf_fields * fields)
+{
+ return mailimf_envelope_fields_write_driver(do_write, f, col, fields);
+}
+
+int mailimf_field_write_file(FILE * f, int * col,
+ struct mailimf_field * field)
+{
+ return mailimf_field_write_driver(do_write, f, col, field);
+}
+
+int mailimf_quoted_string_write_file(FILE * f, int * col,
+ const char * string, size_t len)
+{
+ return mailimf_quoted_string_write_driver(do_write, f, col, string, len);
+}
+
+int mailimf_address_list_write_file(FILE * f, int * col,
+ struct mailimf_address_list * addr_list)
+{
+ return mailimf_address_list_write_driver(do_write, f, col, addr_list);
+}
+
+int mailimf_mailbox_list_write_file(FILE * f, int * col,
+ struct mailimf_mailbox_list * mb_list)
+{
+ return mailimf_mailbox_list_write_driver(do_write, f, col, mb_list);
+}
+
+int mailimf_header_string_write_file(FILE * f, int * col,
+ const char * str, size_t length)
+{
+ return mailimf_header_string_write_driver(do_write, f, col, str, length);
+}
+
+
+/* binary compatibility with 0.34 - begin */
+
+#ifdef MAILIMF_WRITE_COMPATIBILITY
+int mailimf_string_write(FILE * f, int * col,
+ const char * str, size_t length)
+{
+ return mailimf_string_write_file(f, col, str, length);
+}
+
+int mailimf_fields_write(FILE * f, int * col,
+ struct mailimf_fields * fields)
+{
+ return mailimf_fields_write_file(f, col, fields);
+}
+
+int mailimf_envelope_fields_write(FILE * f, int * col,
+ struct mailimf_fields * fields)
+{
+ return mailimf_envelope_fields_write_file(f, col, fields);
+}
+
+int mailimf_field_write(FILE * f, int * col,
+ struct mailimf_field * field)
+{
+ return mailimf_field_write_file(f, col, field);
+}
+
+int mailimf_quoted_string_write(FILE * f, int * col,
+ const char * string, size_t len)
+{
+ return mailimf_quoted_string_write_file(f, col, string, len);
+}
+
+int mailimf_address_list_write(FILE * f, int * col,
+ struct mailimf_address_list * addr_list)
+{
+ return mailimf_address_list_write_file(f, col, addr_list);
+}
+
+int mailimf_mailbox_list_write(FILE * f, int * col,
+ struct mailimf_mailbox_list * mb_list)
+{
+ return mailimf_mailbox_list_write_file(f, col, mb_list);
+}
+
+int mailimf_header_string_write(FILE * f, int * col,
+ const char * str, size_t length)
+{
+ return mailimf_header_string_write_file(f, col, str, length);
+}
+#endif
+
+/* binary compatibility with 0.34 - end */
diff --git a/libetpan/src/low-level/imf/mailimf_write_file.h b/libetpan/src/low-level/imf/mailimf_write_file.h
new file mode 100644
index 0000000..2b7707f
--- a/dev/null
+++ b/libetpan/src/low-level/imf/mailimf_write_file.h
@@ -0,0 +1,169 @@
+/*
+ * 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$
+ */
+
+#ifndef MAILIMF_WRITE_H
+
+#define MAILIMF_WRITE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdio.h>
+#include <libetpan/mailimf_types.h>
+
+ //#define MAILIMF_WRITE_COMPATIBILITY
+
+/*
+ mailimf_string_write_file writes a string to a given stream
+
+ @param f is the stream
+ @param col (* col) is the column number where we will start to
+ write the text, the ending column will be stored in (* col)
+ @param str is the string to write
+*/
+
+int mailimf_string_write_file(FILE * f, int * col,
+ const char * str, size_t length);
+
+
+/*
+ mailimf_fields_write_file writes the fields to a given stream
+
+ @param f is the stream
+ @param col (* col) is the column number where we will start to
+ write the text, the ending column will be stored in (* col)
+ @param fields is the fields to write
+*/
+
+int mailimf_fields_write_file(FILE * f, int * col,
+ struct mailimf_fields * fields);
+
+
+/*
+ mailimf_envelope_fields_write_file writes only some fields to a given stream
+
+ @param f is the stream
+ @param col (* col) is the column number where we will start to
+ write the text, the ending column will be stored in (* col)
+ @param fields is the fields to write
+*/
+
+int mailimf_envelope_fields_write_file(FILE * f, int * col,
+ struct mailimf_fields * fields);
+
+
+/*
+ mailimf_field_write_file writes a field to a given stream
+
+ @param f is the stream
+ @param col (* col) is the column number where we will start to
+ write the text, the ending column will be stored in (* col)
+ @param field is the field to write
+*/
+
+int mailimf_field_write_file(FILE * f, int * col,
+ struct mailimf_field * field);
+
+/*
+ mailimf_quoted_string_write_file writes a string that is quoted
+ to a given stream
+
+ @param f is the stream
+ @param col (* col) is the column number where we will start to
+ write the text, the ending column will be stored in (* col)
+ @param string is the string to quote and write
+*/
+
+int mailimf_quoted_string_write_file(FILE * f, int * col,
+ const char * string, size_t len);
+
+int mailimf_address_list_write_file(FILE * f, int * col,
+ struct mailimf_address_list * addr_list);
+
+int mailimf_mailbox_list_write_file(FILE * f, int * col,
+ struct mailimf_mailbox_list * mb_list);
+
+/*
+ mailimf_header_string_write_file writes a header value and fold the header
+ if needed.
+
+ @param f is the stream
+ @param col (* col) is the column number where we will start to
+ write the text, the ending column will be stored in (* col)
+ @param str is the string to write
+*/
+
+int mailimf_header_string_write_file(FILE * f, int * col,
+ const char * str, size_t length);
+
+
+
+/* binary compatibility with 0.34 - begin */
+
+#ifdef MAILIMF_WRITE_COMPATIBILITY
+int mailimf_string_write(FILE * f, int * col,
+ const char * str, size_t length);
+
+int mailimf_fields_write(FILE * f, int * col,
+ struct mailimf_fields * fields);
+
+int mailimf_envelope_fields_write(FILE * f, int * col,
+ struct mailimf_fields * fields);
+
+int mailimf_field_write(FILE * f, int * col,
+ struct mailimf_field * field);
+
+int mailimf_quoted_string_write(FILE * f, int * col,
+ const char * string, size_t len);
+
+int mailimf_address_list_write(FILE * f, int * col,
+ struct mailimf_address_list * addr_list);
+
+int mailimf_mailbox_list_write(FILE * f, int * col,
+ struct mailimf_mailbox_list * mb_list);
+
+int mailimf_header_string_write(FILE * f, int * col,
+ const char * str, size_t length);
+#endif
+
+/* binary compatibility with 0.34 - end */
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libetpan/src/low-level/imf/mailimf_write_generic.c b/libetpan/src/low-level/imf/mailimf_write_generic.c
new file mode 100644
index 0000000..74c1d43
--- a/dev/null
+++ b/libetpan/src/low-level/imf/mailimf_write_generic.c
@@ -0,0 +1,2028 @@
+/*
+ * 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 "mailimf_write_generic.h"
+
+#include <time.h>
+#include <string.h>
+#include <ctype.h>
+
+#define MAX_MAIL_COL 72
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#define MAX_VALID_IMF_LINE 998
+
+static int mailimf_orig_date_write_driver(int (* do_write)(void *, const char *, size_t), void * data,
+ int * col,
+ struct mailimf_orig_date * date);
+static int mailimf_date_time_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
+ struct mailimf_date_time * date_time);
+static int mailimf_from_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
+ struct mailimf_from * from);
+static int mailimf_sender_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
+ struct mailimf_sender * sender);
+static int mailimf_reply_to_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
+ struct mailimf_reply_to * reply_to);
+static int mailimf_to_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
+ struct mailimf_to * to);
+static int mailimf_cc_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
+ struct mailimf_cc * to);
+static int mailimf_bcc_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
+ struct mailimf_bcc * to);
+static int mailimf_message_id_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
+ struct mailimf_message_id * message_id);
+static int mailimf_msg_id_list_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
+ clist * list);
+static int mailimf_in_reply_to_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
+ struct mailimf_in_reply_to *
+ in_reply_to);
+static int mailimf_references_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
+ struct mailimf_references * references);
+static int mailimf_subject_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
+ struct mailimf_subject * subject);
+
+static int mailimf_address_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
+ struct mailimf_address * addr);
+static int mailimf_group_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
+ struct mailimf_group * group);
+
+static int mailimf_mailbox_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
+ struct mailimf_mailbox * mb);
+
+static int mailimf_comments_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
+ struct mailimf_comments * comments);
+
+static int mailimf_optional_field_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
+ struct mailimf_optional_field * field);
+
+static int mailimf_keywords_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
+ struct mailimf_keywords * keywords);
+
+static int mailimf_return_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
+ struct mailimf_return * return_path);
+
+static int mailimf_path_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
+ struct mailimf_path * path);
+
+static int mailimf_resent_date_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
+ struct mailimf_orig_date * date);
+
+static int mailimf_resent_from_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
+ struct mailimf_from * from);
+
+static int mailimf_resent_sender_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
+ struct mailimf_sender * sender);
+
+static int mailimf_resent_to_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
+ struct mailimf_to * to);
+
+static int mailimf_resent_cc_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
+ struct mailimf_cc * cc);
+
+static int mailimf_resent_bcc_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
+ struct mailimf_bcc * bcc);
+
+static int
+mailimf_resent_msg_id_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
+ struct mailimf_message_id * message_id);
+
+
+
+/* ************************ */
+
+#if 0
+int mailimf_string_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
+ char * str, size_t length)
+{
+ int r;
+
+ if (length != 0) {
+ r = fwrite(str, sizeof(char), length, f);
+ if (r < 0)
+ return MAILIMF_ERROR_FILE;
+ * col += length;
+ }
+
+ return MAILIMF_NO_ERROR;
+}
+#endif
+
+#define CRLF "\r\n"
+#define HEADER_FOLD "\r\n "
+
+static inline int flush_buf(int (* do_write)(void *, const char *, size_t), void * data, const char * str, size_t length)
+{
+ if (length != 0) {
+ int r;
+
+ if (length > 0) {
+ r = do_write(data, str, length);
+ if (r == 0)
+ return MAILIMF_ERROR_FILE;
+ }
+ }
+ return MAILIMF_NO_ERROR;
+}
+
+#define CUT_AT_MAX_VALID_IMF_LINE
+
+int mailimf_string_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
+ const char * str, size_t length)
+{
+ int r;
+ size_t count;
+ const char * block_begin;
+ const char * p;
+ int done;
+
+ p = str;
+ block_begin = str;
+ count = 0;
+
+ while (length > 0) {
+#ifdef CUT_AT_MAX_VALID_IMF_LINE
+ if (count >= 998) {
+ /*
+ cut lines at maximum valid length for internet message
+ format standard (currently RFC 2822)
+
+ This should not happen.
+ In case there are some lines larger than 998 in body,
+ the encoding must be changed into base64 or quoted-printable
+ so that wrapping to 72 columns is done.
+ */
+
+ r = flush_buf(do_write, data, block_begin, count);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = do_write(data, CRLF, sizeof(CRLF) - 1);
+ if (r == 0)
+ return MAILIMF_ERROR_FILE;
+
+ count = 0;
+ block_begin = p;
+
+ * col = 0;
+ }
+#endif
+ switch (* p) {
+ case '\n':
+ r = flush_buf(do_write, data, block_begin, count);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = do_write(data, CRLF, sizeof(CRLF) - 1);
+ if (r == 0)
+ return MAILIMF_ERROR_FILE;
+
+ p ++;
+ length --;
+ count = 0;
+ block_begin = p;
+
+ * col = 0;
+ break;
+
+ case '\r':
+ done = 0;
+ if (length >= 2) {
+ if (* (p + 1) == '\n') {
+ r = flush_buf(do_write, data, block_begin, count);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = do_write(data, CRLF, sizeof(CRLF) - 1);
+ if (r == 0)
+ return MAILIMF_ERROR_FILE;
+
+ p += 2;
+ length -= 2;
+ count = 0;
+ block_begin = p;
+
+ * col = 0;
+
+ done = 1;
+ }
+ }
+ if (!done) {
+ r = flush_buf(do_write, data, block_begin, count);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = do_write(data, CRLF, sizeof(CRLF) - 1);
+ if (r == 0)
+ return MAILIMF_ERROR_FILE;
+
+ p ++;
+ length --;
+ count = 0;
+ block_begin = p;
+
+ * col = 0;
+ }
+ break;
+
+ default:
+ p ++;
+ count ++;
+ length --;
+ break;
+ }
+ }
+
+ r = flush_buf(do_write, data, block_begin, count);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ * col += count;
+
+ return MAILIMF_NO_ERROR;
+}
+
+#if 0
+int mailimf_header_string_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
+ char * str, size_t length)
+{
+ char * p;
+ char * block_begin;
+ int current_col;
+ char * last_cut;
+ int r;
+ int first;
+
+ if (* col + length < MAX_MAIL_COL)
+ return mailimf_string_write_driver(do_write, data, col, str, length);
+
+ first = 1;
+ p = str;
+ block_begin = p;
+ last_cut = block_begin;
+ current_col = * col;
+
+ while (1) {
+ if (current_col >= MAX_MAIL_COL) {
+ /* if we reach the maximum recommanded size of line */
+ if (last_cut == block_begin) {
+ /* if we could not find any place to cut */
+ if (first) {
+ /* fold the header */
+ r = mailimf_string_write_driver(do_write, data, col, HEADER_FOLD,
+ sizeof(HEADER_FOLD) - 1);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ current_col = * col + p - block_begin;
+ first = 0;
+ }
+ else {
+ /* cut the header */
+ r = mailimf_string_write_driver(do_write, data, col, block_begin, p - block_begin);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ r = mailimf_string_write_driver(do_write, data, col, HEADER_FOLD,
+ sizeof(HEADER_FOLD) - 1);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ first = 0;
+ block_begin = p;
+ last_cut = block_begin;
+ current_col = * col + p - block_begin;
+ }
+ }
+ else {
+ /* if we found a place to cut */
+ r = mailimf_string_write_driver(do_write, data, col, block_begin, last_cut - block_begin);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ r = mailimf_string_write_driver(do_write, data, col, HEADER_FOLD,
+ sizeof(HEADER_FOLD) - 1);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ first = 0;
+ block_begin = last_cut;
+ last_cut = block_begin;
+ current_col = * col + p - block_begin;
+ continue;
+ }
+ }
+ else {
+ if (length == 0)
+ break;
+
+ switch (* p) {
+ case ' ':
+ case '\t':
+ last_cut = p;
+ current_col ++;
+ break;
+
+ case '\r':
+ case '\n':
+ current_col = 0;
+ break;
+
+ default:
+ current_col ++;
+ break;
+ }
+
+ p ++;
+ length --;
+ }
+ }
+
+ return mailimf_string_write_driver(do_write, data, col, block_begin, p - block_begin);
+}
+#endif
+
+#if 0
+enum {
+ STATE_LOWER_72,
+ STATE_LOWER_72_CUT,
+ STATE_EQUAL_72,
+ STATE_LOWER_998,
+ STATE_EQUAL_998,
+};
+
+int mailimf_header_string_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
+ const char * str, size_t length)
+{
+ int state;
+ const char * p;
+ const char * block_begin;
+ size_t size;
+ const char * cut;
+ int r;
+
+ if (* col < MAX_MAIL_COL)
+ state = STATE_LOWER_72_CUT;
+ else if (* col == MAX_MAIL_COL)
+ state = STATE_EQUAL_72;
+ else if (* col < MAX_VALID_IMF_LINE)
+ state = STATE_LOWER_998;
+ else
+ state = STATE_EQUAL_998;
+
+ p = str;
+ block_begin = p;
+ size = * col;
+ cut = p;
+
+ while (length > 0) {
+ switch (state) {
+ case STATE_LOWER_72:
+ switch (* p) {
+ case '\r':
+ case '\n':
+ p ++;
+ length --;
+ size = 0;
+ break;
+
+ case ' ':
+ case '\t':
+ cut = p;
+ p ++;
+ length --;
+ size ++;
+ state = STATE_LOWER_72_CUT;
+ break;
+
+ default:
+ if (size < MAX_MAIL_COL - 1) {
+ p ++;
+ length --;
+ size ++;
+ }
+ else {
+ state = STATE_EQUAL_72;
+ p ++;
+ length --;
+ size ++;
+ }
+ break;
+ }
+ break; /* end of STATE_LOWER_72 */
+
+ case STATE_LOWER_72_CUT:
+ switch (* p) {
+ case '\r':
+ case '\n':
+ p ++;
+ length --;
+ size = 0;
+ state = STATE_LOWER_72;
+ break;
+
+ case ' ':
+ case '\t':
+ cut = p;
+ p ++;
+ length --;
+ size ++;
+ break;
+
+ default:
+ if (size < MAX_MAIL_COL) {
+ p ++;
+ length --;
+ size ++;
+ }
+ else {
+ r = mailimf_string_write_driver(do_write, data, col, block_begin, cut - block_begin);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ r = mailimf_string_write_driver(do_write, data, col, HEADER_FOLD,
+ sizeof(HEADER_FOLD) - 1);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ p ++;
+ length --;
+ block_begin = cut;
+ if ((* block_begin == ' ') || (* block_begin == '\t'))
+ block_begin ++;
+ size = p - block_begin + * col;
+ state = STATE_LOWER_72;
+ }
+ break;
+ }
+ break; /* end of STATE_LOWER_72_CUT */
+
+ case STATE_EQUAL_72:
+ switch (* p) {
+ case '\r':
+ case '\n':
+ p ++;
+ length --;
+ size = 0;
+ state = STATE_LOWER_72;
+ break;
+
+ case ' ':
+ case '\t':
+ r = mailimf_string_write_driver(do_write, data, col, block_begin, p - block_begin);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ r = mailimf_string_write_driver(do_write, data, col, HEADER_FOLD,
+ sizeof(HEADER_FOLD) - 1);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ p ++;
+ length --;
+ block_begin = p;
+ size = p - block_begin + * col;
+ state = STATE_LOWER_72;
+ break;
+
+ default:
+ p ++;
+ length --;
+ size ++;
+ state = STATE_LOWER_998;
+ break;
+ }
+ break; /* end of STATE_EQUAL_72 */
+
+ case STATE_LOWER_998:
+ switch (* p) {
+ case '\r':
+ case '\n':
+ p ++;
+ length --;
+ size = 0;
+ state = STATE_LOWER_72;
+ break;
+
+ case ' ':
+ case '\t':
+ r = mailimf_string_write_driver(do_write, data, col, block_begin, p - block_begin);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ r = mailimf_string_write_driver(do_write, data, col, HEADER_FOLD,
+ sizeof(HEADER_FOLD) - 1);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ p ++;
+ length --;
+ block_begin = p;
+ size = p - block_begin + * col;
+ state = STATE_LOWER_72;
+ break;
+
+ default:
+ if (size < MAX_VALID_IMF_LINE - 1) {
+ p ++;
+ length --;
+ size ++;
+ }
+ else {
+ p ++;
+ length --;
+ size = 0;
+ state = STATE_EQUAL_998;
+ }
+ break;
+ }
+ break; /* end of STATE_LOWER_998 */
+
+ case STATE_EQUAL_998:
+ switch (* p) {
+ case '\r':
+ case '\n':
+ p ++;
+ length --;
+ size = 0;
+ state = STATE_LOWER_72;
+ break;
+
+ case ' ':
+ case '\t':
+ r = mailimf_string_write_driver(do_write, data, col, block_begin, p - block_begin);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ r = mailimf_string_write_driver(do_write, data, col, HEADER_FOLD,
+ sizeof(HEADER_FOLD) - 1);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ p ++;
+ length --;
+ block_begin = p;
+ size = p - block_begin + * col;
+ state = STATE_LOWER_72;
+ break;
+
+ default:
+#ifdef CUT_AT_MAX_VALID_IMF_LINE
+ r = mailimf_string_write_driver(do_write, data, col, block_begin, p - block_begin);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ r = mailimf_string_write_driver(do_write, data, col, HEADER_FOLD,
+ sizeof(HEADER_FOLD) - 1);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ p ++;
+ length --;
+ block_begin = p;
+ size = p - block_begin + * col;
+ state = STATE_LOWER_72;
+#else
+ p ++;
+ length --;
+ size ++;
+#endif
+ break;
+ }
+ break; /* end of STATE_EQUAL_998 */
+ }
+ }
+
+ r = mailimf_string_write_driver(do_write, data, col, block_begin, p - block_begin);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ return MAILIMF_NO_ERROR;
+}
+#endif
+
+enum {
+ STATE_BEGIN,
+ STATE_WORD,
+ STATE_SPACE,
+};
+
+int mailimf_header_string_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
+ const char * str, size_t length)
+{
+ int state;
+ const char * p;
+ const char * word_begin;
+ const char * word_end;
+ const char * next_word;
+ int first;
+
+ state = STATE_BEGIN;
+
+ p = str;
+ word_begin = p;
+ word_end = p;
+ next_word = p;
+ first = 1;
+
+ while (length > 0) {
+ switch (state) {
+ case STATE_BEGIN:
+ switch (* p) {
+ case '\r':
+ case '\n':
+ case ' ':
+ case '\t':
+ p ++;
+ length --;
+ break;
+
+ default:
+ word_begin = p;
+ state = STATE_WORD;
+ break;
+ }
+ break;
+
+ case STATE_SPACE:
+ switch (* p) {
+ case '\r':
+ case '\n':
+ case ' ':
+ case '\t':
+ p ++;
+ length --;
+ break;
+
+ default:
+ word_begin = p;
+ state = STATE_WORD;
+ break;
+ }
+ break;
+
+ case STATE_WORD:
+ switch (* p) {
+ case '\r':
+ case '\n':
+ case ' ':
+ case '\t':
+ if (p - word_begin + (* col) + 1 > MAX_MAIL_COL)
+ mailimf_string_write_driver(do_write, data, col, HEADER_FOLD,
+ sizeof(HEADER_FOLD) - 1);
+ else {
+ if (!first)
+ mailimf_string_write_driver(do_write, data, col, " ", 1);
+ }
+ first = 0;
+ mailimf_string_write_driver(do_write, data, col, word_begin, p - word_begin);
+ state = STATE_SPACE;
+ break;
+
+ default:
+ if (p - word_begin + (* col) >= MAX_VALID_IMF_LINE) {
+ mailimf_string_write_driver(do_write, data, col, word_begin, p - word_begin);
+ mailimf_string_write_driver(do_write, data, col, HEADER_FOLD,
+ sizeof(HEADER_FOLD) - 1);
+ word_begin = p;
+ }
+ p ++;
+ length --;
+ break;
+ }
+ break;
+ }
+ }
+
+ if (state == STATE_WORD) {
+ if (p - word_begin + (* col) >= MAX_MAIL_COL)
+ mailimf_string_write_driver(do_write, data, col, HEADER_FOLD,
+ sizeof(HEADER_FOLD) - 1);
+ else {
+ if (!first)
+ mailimf_string_write_driver(do_write, data, col, " ", 1);
+ }
+ first = 0;
+ mailimf_string_write_driver(do_write, data, col, word_begin, p - word_begin);
+ }
+
+ return MAILIMF_NO_ERROR;
+}
+
+int mailimf_envelope_fields_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
+ struct mailimf_fields * fields)
+{
+ clistiter * cur;
+
+ for(cur = clist_begin(fields->fld_list) ; cur != NULL ;
+ cur = clist_next(cur)) {
+ int r;
+ struct mailimf_field * field;
+
+ field = clist_content(cur);
+ if (field->fld_type != MAILIMF_FIELD_OPTIONAL_FIELD) {
+ r = mailimf_field_write_driver(do_write, data, col, field);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ }
+ }
+
+ return MAILIMF_NO_ERROR;
+}
+
+int mailimf_fields_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
+ struct mailimf_fields * fields)
+{
+ clistiter * cur;
+
+ for(cur = clist_begin(fields->fld_list) ; cur != NULL ;
+ cur = clist_next(cur)) {
+ int r;
+
+ r = mailimf_field_write_driver(do_write, data, col, clist_content(cur));
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ }
+
+ return MAILIMF_NO_ERROR;
+}
+
+#if 0
+int mailimf_unparsed_fields_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
+ struct mailimf_unparsed_fields * fields)
+{
+ clistiter * cur;
+
+ for(cur = clist_begin(fields->list) ; cur != NULL ; cur = cur->next) {
+ int r;
+
+ r = mailimf_optional_field_write_driver(do_write, data, col, cur->data);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ }
+
+ return MAILIMF_NO_ERROR;
+}
+#endif
+
+int mailimf_field_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
+ struct mailimf_field * field)
+{
+ int r;
+
+ switch (field->fld_type) {
+ case MAILIMF_FIELD_RETURN_PATH:
+ r = mailimf_return_write_driver(do_write, data, col, field->fld_data.fld_return_path);
+ break;
+ case MAILIMF_FIELD_RESENT_DATE:
+ r = mailimf_resent_date_write_driver(do_write, data, col, field->fld_data.fld_resent_date);
+ break;
+ case MAILIMF_FIELD_RESENT_FROM:
+ r = mailimf_resent_from_write_driver(do_write, data, col, field->fld_data.fld_resent_from);
+ break;
+ case MAILIMF_FIELD_RESENT_SENDER:
+ r = mailimf_resent_sender_write_driver(do_write, data, col, field->fld_data.fld_resent_sender);
+ break;
+ case MAILIMF_FIELD_RESENT_TO:
+ r = mailimf_resent_to_write_driver(do_write, data, col, field->fld_data.fld_resent_to);
+ break;
+ case MAILIMF_FIELD_RESENT_CC:
+ r = mailimf_resent_cc_write_driver(do_write, data, col, field->fld_data.fld_resent_cc);
+ break;
+ case MAILIMF_FIELD_RESENT_BCC:
+ r = mailimf_resent_bcc_write_driver(do_write, data, col, field->fld_data.fld_resent_bcc);
+ break;
+ case MAILIMF_FIELD_RESENT_MSG_ID:
+ r = mailimf_resent_msg_id_write_driver(do_write, data, col, field->fld_data.fld_resent_msg_id);
+ break;
+ case MAILIMF_FIELD_ORIG_DATE:
+ r = mailimf_orig_date_write_driver(do_write, data, col, field->fld_data.fld_orig_date);
+ break;
+ case MAILIMF_FIELD_FROM:
+ r = mailimf_from_write_driver(do_write, data, col, field->fld_data.fld_from);
+ break;
+ case MAILIMF_FIELD_SENDER:
+ r = mailimf_sender_write_driver(do_write, data, col, field->fld_data.fld_sender);
+ break;
+ case MAILIMF_FIELD_REPLY_TO:
+ r = mailimf_reply_to_write_driver(do_write, data, col, field->fld_data.fld_reply_to);
+ break;
+ case MAILIMF_FIELD_TO:
+ r = mailimf_to_write_driver(do_write, data, col, field->fld_data.fld_to);
+ break;
+ case MAILIMF_FIELD_CC:
+ r = mailimf_cc_write_driver(do_write, data, col, field->fld_data.fld_cc);
+ break;
+ case MAILIMF_FIELD_BCC:
+ r = mailimf_bcc_write_driver(do_write, data, col, field->fld_data.fld_bcc);
+ break;
+ case MAILIMF_FIELD_MESSAGE_ID:
+ r = mailimf_message_id_write_driver(do_write, data, col, field->fld_data.fld_message_id);
+ break;
+ case MAILIMF_FIELD_IN_REPLY_TO:
+ r = mailimf_in_reply_to_write_driver(do_write, data, col, field->fld_data.fld_in_reply_to);
+ break;
+ case MAILIMF_FIELD_REFERENCES:
+ r = mailimf_references_write_driver(do_write, data, col, field->fld_data.fld_references);
+ break;
+ case MAILIMF_FIELD_SUBJECT:
+ r = mailimf_subject_write_driver(do_write, data, col, field->fld_data.fld_subject);
+ break;
+ case MAILIMF_FIELD_COMMENTS:
+ r = mailimf_comments_write_driver(do_write, data, col, field->fld_data.fld_comments);
+ break;
+ case MAILIMF_FIELD_KEYWORDS:
+ r = mailimf_keywords_write_driver(do_write, data, col, field->fld_data.fld_keywords);
+ break;
+ case MAILIMF_FIELD_OPTIONAL_FIELD:
+ r = mailimf_optional_field_write_driver(do_write, data, col, field->fld_data.fld_optional_field);
+ break;
+ default:
+ r = MAILIMF_ERROR_INVAL;
+ break;
+ }
+
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ return MAILIMF_NO_ERROR;
+}
+
+
+static int mailimf_orig_date_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
+ struct mailimf_orig_date * date)
+{
+ int r;
+
+ r = mailimf_string_write_driver(do_write, data, col, "Date: ", 6);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_date_time_write_driver(do_write, data, col, date->dt_date_time);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_string_write_driver(do_write, data, col, "\r\n", 2);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+#if 0
+ * col = 0;
+#endif
+
+ return MAILIMF_NO_ERROR;
+}
+
+#define MAX_DATE_STR 256
+
+/* 0 = Sunday */
+/* y > 1752 */
+
+static int dayofweek(int year, int month, int day)
+{
+ static int offset[] = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4};
+
+ year -= month < 3;
+
+ return (year + year/4 - year/100 + year/400 + offset[month-1] + day) % 7;
+}
+
+static const char * week_of_day_str[] = { "Sun", "Mon", "Tue", "Wed", "Thu",
+ "Fri", "Sat"};
+static const char * month_str[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
+
+static int mailimf_date_time_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
+ struct mailimf_date_time * date_time)
+{
+ int r;
+ char date_str[MAX_DATE_STR];
+#if 0
+ struct tm tmval;
+ time_t timeval;
+#endif
+ int wday;
+
+#if 0
+ tmval.tm_sec = date_time->sec;
+ tmval.tm_min = date_time->min;
+ tmval.tm_hour = date_time->hour;
+ tmval.tm_sec = date_time->sec;
+ tmval.tm_mday = date_time->day;
+ tmval.tm_mon = date_time->month - 1;
+ tmval.tm_year = date_time->year - 1900;
+ tmval.tm_isdst = 1;
+
+ timeval = mktime(&tmval);
+
+ localtime_r(&timeval, &tmval);
+#endif
+
+ wday = dayofweek(date_time->dt_year, date_time->dt_month, date_time->dt_day);
+
+ snprintf(date_str, MAX_DATE_STR, "%s, %i %s %i %02i:%02i:%02i %+05i",
+ week_of_day_str[wday], date_time->dt_day,
+ month_str[date_time->dt_month - 1],
+ date_time->dt_year, date_time->dt_hour,
+ date_time->dt_min, date_time->dt_sec,
+ date_time->dt_zone);
+
+ r = mailimf_string_write_driver(do_write, data, col, date_str, strlen(date_str));
+
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ return MAILIMF_NO_ERROR;
+}
+
+static int mailimf_from_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
+ struct mailimf_from * from)
+{
+ int r;
+
+ r = mailimf_string_write_driver(do_write, data, col, "From: ", 6);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_mailbox_list_write_driver(do_write, data, col, from->frm_mb_list);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_string_write_driver(do_write, data, col, "\r\n", 2);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+#if 0
+ * col = 0;
+#endif
+
+ return MAILIMF_NO_ERROR;
+}
+
+static int mailimf_sender_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
+ struct mailimf_sender * sender)
+{
+ int r;
+
+ r = mailimf_string_write_driver(do_write, data, col, "Sender: ", 8);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_mailbox_write_driver(do_write, data, col, sender->snd_mb);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_string_write_driver(do_write, data, col, "\r\n", 2);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+#if 0
+ * col = 0;
+#endif
+
+ return MAILIMF_NO_ERROR;
+}
+
+static int mailimf_reply_to_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
+ struct mailimf_reply_to * reply_to)
+{
+ int r;
+
+ r = mailimf_string_write_driver(do_write, data, col, "Reply-To: ", 10);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_address_list_write_driver(do_write, data, col, reply_to->rt_addr_list);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_string_write_driver(do_write, data, col, "\r\n", 2);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+#if 0
+ * col = 0;
+#endif
+
+ return MAILIMF_NO_ERROR;
+}
+
+
+static int mailimf_to_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
+ struct mailimf_to * to)
+{
+ int r;
+
+ r = mailimf_string_write_driver(do_write, data, col, "To: ", 4);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_address_list_write_driver(do_write, data, col, to->to_addr_list);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_string_write_driver(do_write, data, col, "\r\n", 2);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+#if 0
+ * col = 0;
+#endif
+
+ return MAILIMF_NO_ERROR;
+}
+
+
+static int mailimf_cc_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
+ struct mailimf_cc * cc)
+{
+ int r;
+
+ r = mailimf_string_write_driver(do_write, data, col, "Cc: ", 4);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_address_list_write_driver(do_write, data, col, cc->cc_addr_list);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_string_write_driver(do_write, data, col, "\r\n", 2);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+#if 0
+ * col = 0;
+#endif
+
+ return MAILIMF_NO_ERROR;
+}
+
+
+static int mailimf_bcc_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
+ struct mailimf_bcc * bcc)
+{
+ int r;
+
+ r = mailimf_string_write_driver(do_write, data, col, "Bcc: ", 5);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ if (bcc->bcc_addr_list != NULL) {
+ r = mailimf_address_list_write_driver(do_write, data, col, bcc->bcc_addr_list);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ }
+
+ r = mailimf_string_write_driver(do_write, data, col, "\r\n", 2);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+#if 0
+ * col = 0;
+#endif
+
+ return MAILIMF_NO_ERROR;
+}
+
+
+static int mailimf_message_id_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
+ struct mailimf_message_id * message_id)
+{
+ int r;
+
+ r = mailimf_string_write_driver(do_write, data, col, "Message-ID: ", 12);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_string_write_driver(do_write, data, col, "<", 1);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_string_write_driver(do_write, data, col,
+ message_id->mid_value,
+ strlen(message_id->mid_value));
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_string_write_driver(do_write, data, col, ">", 1);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_string_write_driver(do_write, data, col, "\r\n", 2);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+#if 0
+ * col = 0;
+#endif
+
+ return MAILIMF_NO_ERROR;
+}
+
+
+static int mailimf_msg_id_list_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col, clist * mid_list)
+{
+ clistiter * cur;
+ int r;
+ int first;
+
+ first = TRUE;
+
+ for(cur = clist_begin(mid_list) ; cur != NULL ; cur = clist_next(cur)) {
+ char * msgid;
+ size_t len;
+
+ msgid = clist_content(cur);
+ len = strlen(msgid);
+
+ /*
+ XXX - if this is the first message ID, don't fold.
+ This is a workaround for a bug of old versions of INN.
+ */
+ if (!first) {
+ if (* col > 1) {
+
+ if (* col + len >= MAX_MAIL_COL) {
+ r = mailimf_string_write_driver(do_write, data, col, "\r\n ", 3);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+#if 0
+ * col = 1;
+#endif
+ first = TRUE;
+ }
+ }
+ }
+
+ if (!first) {
+ r = mailimf_string_write_driver(do_write, data, col, " ", 1);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ }
+ else {
+ first = FALSE;
+ }
+
+ r = mailimf_string_write_driver(do_write, data, col, "<", 1);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_string_write_driver(do_write, data, col, msgid, len);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_string_write_driver(do_write, data, col, ">", 1);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ }
+
+ return MAILIMF_NO_ERROR;
+}
+
+
+static int mailimf_in_reply_to_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
+ struct mailimf_in_reply_to * in_reply_to)
+{
+ int r;
+
+ r = mailimf_string_write_driver(do_write, data, col, "In-Reply-To: ", 13);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_msg_id_list_write_driver(do_write, data, col, in_reply_to->mid_list);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_string_write_driver(do_write, data, col, "\r\n", 2);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+#if 0
+ * col = 0;
+#endif
+
+ return MAILIMF_NO_ERROR;
+}
+
+
+static int mailimf_references_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
+ struct mailimf_references * references)
+{
+ int r;
+
+ r = mailimf_string_write_driver(do_write, data, col, "References: ", 12);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_msg_id_list_write_driver(do_write, data, col, references->mid_list);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_string_write_driver(do_write, data, col, "\r\n", 2);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+#if 0
+ * col = 0;
+#endif
+
+ return MAILIMF_NO_ERROR;
+}
+
+
+
+static int mailimf_subject_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
+ struct mailimf_subject * subject)
+{
+ int r;
+
+ r = mailimf_string_write_driver(do_write, data, col, "Subject: ", 9);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_header_string_write_driver(do_write, data, col,
+ subject->sbj_value, strlen(subject->sbj_value));
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_string_write_driver(do_write, data, col, "\r\n", 2);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+#if 0
+ * col = 0;
+#endif
+
+ return MAILIMF_NO_ERROR;
+}
+
+int mailimf_address_list_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
+ struct mailimf_address_list * addr_list)
+{
+ clistiter * cur;
+ int r;
+ int first;
+
+ first = TRUE;
+
+ for(cur = clist_begin(addr_list->ad_list) ; cur != NULL ;
+ cur = clist_next(cur)) {
+ struct mailimf_address * addr;
+
+ addr = clist_content(cur);
+
+ if (!first) {
+ r = mailimf_string_write_driver(do_write, data, col, ", ", 2);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ }
+ else {
+ first = FALSE;
+ }
+
+ r = mailimf_address_write_driver(do_write, data, col, addr);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ }
+
+ return MAILIMF_NO_ERROR;
+}
+
+
+static int mailimf_address_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
+ struct mailimf_address * addr)
+{
+ int r;
+
+ switch(addr->ad_type) {
+ case MAILIMF_ADDRESS_MAILBOX:
+ r = mailimf_mailbox_write_driver(do_write, data, col, addr->ad_data.ad_mailbox);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ break;
+
+ case MAILIMF_ADDRESS_GROUP:
+ r = mailimf_group_write_driver(do_write, data, col, addr->ad_data.ad_group);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ break;
+ }
+
+ return MAILIMF_NO_ERROR;
+}
+
+
+static int mailimf_group_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
+ struct mailimf_group * group)
+{
+ int r;
+
+ r = mailimf_header_string_write_driver(do_write, data, col, group->grp_display_name,
+ strlen(group->grp_display_name));
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_string_write_driver(do_write, data, col, ": ", 2);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ if (group->grp_mb_list != NULL) {
+ r = mailimf_mailbox_list_write_driver(do_write, data, col, group->grp_mb_list);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ }
+
+ r = mailimf_string_write_driver(do_write, data, col, ";", 1);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ return MAILIMF_NO_ERROR;
+}
+
+
+int mailimf_mailbox_list_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
+ struct mailimf_mailbox_list * mb_list)
+{
+ clistiter * cur;
+ int r;
+ int first;
+
+ first = TRUE;
+
+ for(cur = clist_begin(mb_list->mb_list) ; cur != NULL ;
+ cur = clist_next(cur)) {
+ struct mailimf_mailbox * mb;
+
+ mb = clist_content(cur);
+
+ if (!first) {
+ r = mailimf_string_write_driver(do_write, data, col, ", ", 2);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ }
+ else {
+ first = FALSE;
+ }
+
+ r = mailimf_mailbox_write_driver(do_write, data, col, mb);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ }
+
+ return MAILIMF_NO_ERROR;
+}
+
+
+int mailimf_quoted_string_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
+ const char * string, size_t len)
+{
+ int r;
+ size_t i;
+
+ r = do_write(data, "\"", 1);
+ if (r == 0)
+ return MAILIMF_ERROR_FILE;
+ for(i = 0 ; i < len ; i ++) {
+ switch (string[i]) {
+ case '\\':
+ case '\"':
+ r = do_write(data, "\\", 1);
+ if (r == 0)
+ return MAILIMF_ERROR_FILE;
+ r = do_write(data, &string[i], 1);
+ if (r == 0)
+ return MAILIMF_ERROR_FILE;
+ (* col) += 2;
+ break;
+
+ default:
+ r = do_write(data, &string[i], 1);
+ if (r == 0)
+ return MAILIMF_ERROR_FILE;
+ (* col) ++;
+ break;
+ }
+ }
+ r = do_write(data, "\"", 1);
+ if (r == 0)
+ return MAILIMF_ERROR_FILE;
+
+ return MAILIMF_NO_ERROR;
+}
+
+
+/*
+static int
+atext = ALPHA / DIGIT / ; Any character except controls,
+ "!" / "#" / ; SP, and specials.
+ "$" / "%" / ; Used for atoms
+ "&" / "'" /
+ "*" / "+" /
+ "-" / "/" /
+ "=" / "?" /
+ "^" / "_" /
+ "`" / "{" /
+ "|" / "}" /
+ "~"
+*/
+
+static int is_atext(const char * s)
+{
+ const char * p;
+
+ for(p = s ; * p != 0 ; p ++) {
+ if (isalpha((unsigned char) * p))
+ continue;
+ if (isdigit((unsigned char) * p))
+ continue;
+ switch (*p) {
+ case ' ':
+ case '\t':
+ case '!':
+ case '#':
+ case '$':
+ case '%':
+ case '&':
+ case '\'':
+ case '*':
+ case '+':
+ case '-':
+ case '/':
+ case '=':
+ case '?':
+ case '^':
+ case '_':
+ case '`':
+ case '{':
+ case '|':
+ case '}':
+ case '~':
+ break;
+ default:
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+static int mailimf_mailbox_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
+ struct mailimf_mailbox * mb)
+{
+ int r;
+ int do_fold;
+
+#if 0
+ if (* col > 1) {
+
+ if (mb->mb_display_name != NULL) {
+ if (* col + strlen(mb->mb_display_name) >= MAX_MAIL_COL) {
+ r = mailimf_string_write_driver(do_write, data, col, "\r\n ", 3);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+#if 0
+ * col = 1;
+#endif
+ }
+ }
+ }
+#endif
+
+ if (mb->mb_display_name) {
+
+ if (is_atext(mb->mb_display_name)) {
+ r = mailimf_header_string_write_driver(do_write, data, col, mb->mb_display_name,
+ strlen(mb->mb_display_name));
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ }
+ else {
+ if (mb->mb_display_name != NULL) {
+ if (* col + strlen(mb->mb_display_name) >= MAX_MAIL_COL) {
+ r = mailimf_string_write_driver(do_write, data, col, "\r\n ", 3);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ }
+ }
+
+ if (strlen(mb->mb_display_name) > MAX_VALID_IMF_LINE / 2)
+ return MAILIMF_ERROR_INVAL;
+
+ r = mailimf_quoted_string_write_driver(do_write, data, col, mb->mb_display_name,
+ strlen(mb->mb_display_name));
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ }
+
+ do_fold = 0;
+ if (* col > 1) {
+
+ if (* col + strlen(mb->mb_addr_spec) + 3 >= MAX_MAIL_COL) {
+ r = mailimf_string_write_driver(do_write, data, col, "\r\n ", 3);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+#if 0
+ * col = 1;
+#endif
+ do_fold = 1;
+ }
+ }
+
+ if (do_fold)
+ r = mailimf_string_write_driver(do_write, data, col, "<", 1);
+ else
+ r = mailimf_string_write_driver(do_write, data, col, " <", 2);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_string_write_driver(do_write, data, col, mb->mb_addr_spec,
+ strlen(mb->mb_addr_spec));
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_string_write_driver(do_write, data, col, ">", 1);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ }
+ else {
+ if (* col + strlen(mb->mb_addr_spec) >= MAX_MAIL_COL) {
+ r = mailimf_string_write_driver(do_write, data, col, "\r\n ", 3);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ }
+
+ r = mailimf_string_write_driver(do_write, data, col,
+ mb->mb_addr_spec, strlen(mb->mb_addr_spec));
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ }
+
+
+ return MAILIMF_NO_ERROR;
+}
+
+static int mailimf_comments_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
+ struct mailimf_comments * comments)
+{
+ int r;
+
+ r = mailimf_string_write_driver(do_write, data, col, "Comments: ", 10);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_header_string_write_driver(do_write, data, col,
+ comments->cm_value, strlen(comments->cm_value));
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_string_write_driver(do_write, data, col, "\r\n", 2);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+#if 0
+ * col = 0;
+#endif
+
+ return MAILIMF_NO_ERROR;
+}
+
+static int mailimf_optional_field_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
+ struct mailimf_optional_field * field)
+{
+ int r;
+
+ if (strlen(field->fld_name) + 2 > MAX_VALID_IMF_LINE)
+ return MAILIMF_ERROR_INVAL;
+
+ r = mailimf_string_write_driver(do_write, data, col, field->fld_name, strlen(field->fld_name));
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_string_write_driver(do_write, data, col, ": ", 2);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_header_string_write_driver(do_write, data, col, field->fld_value,
+ strlen(field->fld_value));
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+#if 0
+ /* XXX parsing debug */
+ mailimf_string_write_driver(do_write, data, col, " (X)", 4);
+#endif
+
+ r = mailimf_string_write_driver(do_write, data, col, "\r\n", 2);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+#if 0
+ * col = 0;
+#endif
+
+ return MAILIMF_NO_ERROR;
+}
+
+static int mailimf_keywords_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
+ struct mailimf_keywords * keywords)
+{
+ int r;
+ clistiter * cur;
+ int first;
+
+ r = mailimf_string_write_driver(do_write, data, col, "Keywords: ", 10);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ first = TRUE;
+
+ for(cur = clist_begin(keywords->kw_list) ; cur != NULL ;
+ cur = clist_next(cur)) {
+ char * keyword;
+ size_t len;
+
+ keyword = clist_content(cur);
+ len = strlen(keyword);
+
+ if (!first) {
+ r = mailimf_string_write_driver(do_write, data, col, ", ", 2);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ }
+ else {
+ first = FALSE;
+ }
+
+#if 0
+ if (* col > 1) {
+
+ if (* col + len >= MAX_MAIL_COL) {
+ r = mailimf_string_write_driver(do_write, data, col, "\r\n ", 3);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+#if 0
+ * col = 1;
+#endif
+ }
+ }
+#endif
+
+ r = mailimf_header_string_write_driver(do_write, data, col, keyword, len);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ }
+
+ r = mailimf_string_write_driver(do_write, data, col, "\r\n", 2);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+#if 0
+ * col = 0;
+#endif
+
+ return MAILIMF_NO_ERROR;
+}
+
+#if 0
+static int mailimf_delivering_info_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
+ struct mailimf_delivering_info * info)
+{
+ clistiter * cur;
+ int r;
+
+ for(cur = clist_begin(info->received_fields) ;
+ cur != NULL ; cur = cur->next) {
+ struct mailimf_trace_resent_fields * field;
+
+ field = cur->data;
+
+ r = mailimf_trace_resent_fields_write_driver(do_write, data, col, field);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ }
+
+ return MAILIMF_NO_ERROR;
+}
+
+
+static int
+mailimf_trace_resent_fields_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
+ struct mailimf_trace_resent_fields * field)
+{
+ int r;
+
+ if (field->return_path != NULL) {
+ r = mailimf_return_write_driver(do_write, data, col, field->return_path);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ }
+
+ if (field->resent_fields != NULL) {
+ r = mailimf_resent_fields_write_driver(do_write, data, col, field->resent_fields);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ }
+
+ return MAILIMF_NO_ERROR;
+}
+#endif
+
+static int mailimf_return_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
+ struct mailimf_return * return_path)
+{
+ int r;
+
+ r = mailimf_string_write_driver(do_write, data, col, "Return-Path: ", 13);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_path_write_driver(do_write, data, col, return_path->ret_path);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_string_write_driver(do_write, data, col, "\r\n", 2);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+#if 0
+ * col = 0;
+#endif
+
+ return MAILIMF_NO_ERROR;
+}
+
+static int mailimf_path_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
+ struct mailimf_path * path)
+{
+ int r;
+
+ r = mailimf_string_write_driver(do_write, data, col, "<", 1);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_string_write_driver(do_write, data, col, path->pt_addr_spec,
+ strlen(path->pt_addr_spec));
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_string_write_driver(do_write, data, col, ">", 1);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ return MAILIMF_NO_ERROR;
+}
+
+#if 0
+static int mailimf_resent_fields_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
+ struct mailimf_resent_fields_list *
+ resent_fields)
+{
+ clistiter * cur;
+ int r;
+
+ for(cur = clist_begin(resent_fields->list) ; cur != NULL ; cur = cur->next) {
+ struct mailimf_resent_field * field;
+
+ field = cur->data;
+
+ r = mailimf_resent_field_write_driver(do_write, data, col, field);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ }
+
+ return MAILIMF_NO_ERROR;
+}
+
+
+
+static int mailimf_resent_field_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
+ struct mailimf_resent_field *
+ resent_field)
+{
+ int r;
+
+ switch (resent_field->type) {
+ case MAILIMF_RESENT_FIELD_DATE:
+ r = mailimf_resent_date_write_driver(do_write, data, col, resent_field->resent_date);
+ break;
+
+ case MAILIMF_RESENT_FIELD_FROM:
+ r = mailimf_resent_from_write_driver(do_write, data, col, resent_field->resent_from);
+ break;
+
+ case MAILIMF_RESENT_FIELD_SENDER:
+ r = mailimf_resent_sender_write_driver(do_write, data, col, resent_field->resent_sender);
+ break;
+
+ case MAILIMF_RESENT_FIELD_TO:
+ r = mailimf_resent_to_write_driver(do_write, data, col, resent_field->resent_to);
+ break;
+
+ case MAILIMF_RESENT_FIELD_CC:
+ r = mailimf_resent_cc_write_driver(do_write, data, col, resent_field->resent_cc);
+ break;
+
+ case MAILIMF_RESENT_FIELD_BCC:
+ r = mailimf_resent_bcc_write_driver(do_write, data, col, resent_field->resent_bcc);
+ break;
+
+ case MAILIMF_RESENT_FIELD_MSG_ID:
+ r = mailimf_resent_msg_id_write_driver(do_write, data, col, resent_field->resent_msg_id);
+ break;
+ default:
+ r = MAILIMF_ERROR_INVAL;
+ break;
+ }
+
+
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ return MAILIMF_NO_ERROR;
+}
+#endif
+
+static int mailimf_resent_date_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
+ struct mailimf_orig_date * date)
+{
+ int r;
+
+ r = mailimf_string_write_driver(do_write, data, col, "Resent-Date: ", 13);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_date_time_write_driver(do_write, data, col, date->dt_date_time);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_string_write_driver(do_write, data, col, "\r\n", 2);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+#if 0
+ * col = 0;
+#endif
+
+ return MAILIMF_NO_ERROR;
+}
+
+static int mailimf_resent_from_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
+ struct mailimf_from * from)
+{
+ int r;
+
+ r = mailimf_string_write_driver(do_write, data, col, "Resent-From: ", 13);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_mailbox_list_write_driver(do_write, data, col, from->frm_mb_list);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_string_write_driver(do_write, data, col, "\r\n", 2);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+#if 0
+ * col = 0;
+#endif
+
+ return MAILIMF_NO_ERROR;
+}
+
+static int mailimf_resent_sender_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
+ struct mailimf_sender * sender)
+{
+ int r;
+
+ r = mailimf_string_write_driver(do_write, data, col, "Resent-Sender: ", 15);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_mailbox_write_driver(do_write, data, col, sender->snd_mb);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_string_write_driver(do_write, data, col, "\r\n", 2);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+#if 0
+ * col = 0;
+#endif
+
+ return MAILIMF_NO_ERROR;
+}
+
+static int mailimf_resent_to_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
+ struct mailimf_to * to)
+{
+ int r;
+
+ r = mailimf_string_write_driver(do_write, data, col, "Resent-To: ", 11);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_address_list_write_driver(do_write, data, col, to->to_addr_list);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_string_write_driver(do_write, data, col, "\r\n", 2);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+#if 0
+ * col = 0;
+#endif
+
+ return MAILIMF_NO_ERROR;
+}
+
+
+static int mailimf_resent_cc_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
+ struct mailimf_cc * cc)
+{
+ int r;
+
+ r = mailimf_string_write_driver(do_write, data, col, "Resent-Cc: ", 11);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_address_list_write_driver(do_write, data, col, cc->cc_addr_list);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_string_write_driver(do_write, data, col, "\r\n", 2);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+#if 0
+ * col = 0;
+#endif
+
+ return MAILIMF_NO_ERROR;
+}
+
+
+static int mailimf_resent_bcc_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
+ struct mailimf_bcc * bcc)
+{
+ int r;
+
+ r = mailimf_string_write_driver(do_write, data, col, "Resent-Bcc: ", 12);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ if (bcc->bcc_addr_list != NULL) {
+ r = mailimf_address_list_write_driver(do_write, data, col, bcc->bcc_addr_list);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ }
+
+ r = mailimf_string_write_driver(do_write, data, col, "\r\n", 2);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+#if 0
+ * col = 0;
+#endif
+
+ return MAILIMF_NO_ERROR;
+}
+
+
+static int
+mailimf_resent_msg_id_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
+ struct mailimf_message_id * message_id)
+{
+ int r;
+
+ r = mailimf_string_write_driver(do_write, data, col, "Resent-Message-ID: ", 19);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_string_write_driver(do_write, data, col, "<", 1);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_string_write_driver(do_write, data, col,
+ message_id->mid_value, strlen(message_id->mid_value));
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_string_write_driver(do_write, data, col, ">", 1);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_string_write_driver(do_write, data, col, "\r\n", 2);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+#if 0
+ * col = 0;
+#endif
+
+ return MAILIMF_NO_ERROR;
+}
diff --git a/libetpan/src/low-level/imf/mailimf_write_generic.h b/libetpan/src/low-level/imf/mailimf_write_generic.h
new file mode 100644
index 0000000..c207d7e
--- a/dev/null
+++ b/libetpan/src/low-level/imf/mailimf_write_generic.h
@@ -0,0 +1,142 @@
+/*
+ * 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$
+ */
+
+#ifndef MAILIMF_WRITE_GENERIC_H
+
+#define MAILIMF_WRITE_GENERIC_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdio.h>
+#include <libetpan/mailimf_types.h>
+
+/*
+ mailimf_string_write writes a string to a given stream
+
+ @param f is the stream
+ @param col (* col) is the column number where we will start to
+ write the text, the ending column will be stored in (* col)
+ @param str is the string to write
+*/
+
+int mailimf_string_write_driver(int (* do_write)(void *, const char *, size_t), void * data,
+ int * col,
+ const char * str, size_t length);
+
+
+/*
+ mailimf_fields_write writes the fields to a given stream
+
+ @param f is the stream
+ @param col (* col) is the column number where we will start to
+ write the text, the ending column will be stored in (* col)
+ @param fields is the fields to write
+*/
+
+int mailimf_fields_write_driver(int (* do_write)(void *, const char *, size_t), void * data,
+ int * col,
+ struct mailimf_fields * fields);
+
+
+/*
+ mailimf_envelope_fields_write writes only some fields to a given stream
+
+ @param f is the stream
+ @param col (* col) is the column number where we will start to
+ write the text, the ending column will be stored in (* col)
+ @param fields is the fields to write
+*/
+
+int mailimf_envelope_fields_write_driver(int (* do_write)(void *, const char *, size_t), void * data,
+ int * col,
+ struct mailimf_fields * fields);
+
+
+/*
+ mailimf_field_write writes a field to a given stream
+
+ @param f is the stream
+ @param col (* col) is the column number where we will start to
+ write the text, the ending column will be stored in (* col)
+ @param field is the field to write
+*/
+
+int mailimf_field_write_driver(int (* do_write)(void *, const char *, size_t), void * data,
+ int * col,
+ struct mailimf_field * field);
+
+/*
+ mailimf_quoted_string_write writes a string that is quoted
+ to a given stream
+
+ @param f is the stream
+ @param col (* col) is the column number where we will start to
+ write the text, the ending column will be stored in (* col)
+ @param string is the string to quote and write
+*/
+
+int mailimf_quoted_string_write_driver(int (* do_write)(void *, const char *, size_t), void * data,
+ int * col,
+ const char * string, size_t len);
+
+int mailimf_address_list_write_driver(int (* do_write)(void *, const char *, size_t), void * data,
+ int * col,
+ struct mailimf_address_list * addr_list);
+
+int mailimf_mailbox_list_write_driver(int (* do_write)(void *, const char *, size_t), void * data,
+ int * col,
+ struct mailimf_mailbox_list * mb_list);
+
+/*
+ mailimf_header_string_write writes a header value and fold the header
+ if needed.
+
+ @param f is the stream
+ @param col (* col) is the column number where we will start to
+ write the text, the ending column will be stored in (* col)
+ @param str is the string to write
+*/
+
+int mailimf_header_string_write_driver(int (* do_write)(void *, const char *, size_t), void * data,
+ int * col,
+ const char * str, size_t length);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libetpan/src/low-level/imf/mailimf_write_mem.c b/libetpan/src/low-level/imf/mailimf_write_mem.c
new file mode 100644
index 0000000..00c043f
--- a/dev/null
+++ b/libetpan/src/low-level/imf/mailimf_write_mem.c
@@ -0,0 +1,98 @@
+/*
+ * 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 "mailimf_write_mem.h"
+#include "mailimf_write_generic.h"
+
+static int do_write(void * data, const char * str, size_t length)
+{
+ MMAPString * f;
+
+ f = data;
+
+ if (mmap_string_append_len(f, str, length) == NULL)
+ return 0;
+ else
+ return length;
+}
+
+int mailimf_string_write_mem(MMAPString * f, int * col,
+ const char * str, size_t length)
+{
+ return mailimf_string_write_driver(do_write, f, col, str, length);
+}
+
+int mailimf_fields_write_mem(MMAPString * f, int * col,
+ struct mailimf_fields * fields)
+{
+ return mailimf_fields_write_driver(do_write, f, col, fields);
+}
+
+int mailimf_envelope_fields_write_mem(MMAPString * f, int * col,
+ struct mailimf_fields * fields)
+{
+ return mailimf_envelope_fields_write_driver(do_write, f, col, fields);
+}
+
+int mailimf_field_write_mem(MMAPString * f, int * col,
+ struct mailimf_field * field)
+{
+ return mailimf_field_write_driver(do_write, f, col, field);
+}
+
+int mailimf_quoted_string_write_mem(MMAPString * f, int * col,
+ const char * string, size_t len)
+{
+ return mailimf_quoted_string_write_driver(do_write, f, col, string, len);
+}
+
+int mailimf_address_list_write_mem(MMAPString * f, int * col,
+ struct mailimf_address_list * addr_list)
+{
+ return mailimf_address_list_write_driver(do_write, f, col, addr_list);
+}
+
+int mailimf_mailbox_list_write_mem(MMAPString * f, int * col,
+ struct mailimf_mailbox_list * mb_list)
+{
+ return mailimf_mailbox_list_write_driver(do_write, f, col, mb_list);
+}
+
+int mailimf_header_string_write_mem(MMAPString * f, int * col,
+ const char * str, size_t length)
+{
+ return mailimf_header_string_write_driver(do_write, f, col, str, length);
+}
+
diff --git a/libetpan/src/low-level/imf/mailimf_write_mem.h b/libetpan/src/low-level/imf/mailimf_write_mem.h
new file mode 100644
index 0000000..796f178
--- a/dev/null
+++ b/libetpan/src/low-level/imf/mailimf_write_mem.h
@@ -0,0 +1,135 @@
+/*
+ * 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$
+ */
+
+#ifndef MAILIMF_WRITE_MEM_H
+
+#define MAILIMF_WRITE_MEM_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdio.h>
+#include <libetpan/mailimf_types.h>
+#include <libetpan/mmapstring.h>
+
+/*
+ mailimf_string_write_mem appends a string to a given string
+
+ @param f is the string
+ @param col (* col) is the column number where we will start to
+ write the text, the ending column will be stored in (* col)
+ @param str is the string to write
+*/
+
+int mailimf_string_write_mem(MMAPString * f, int * col,
+ const char * str, size_t length);
+
+
+/*
+ mailimf_fields_write_mem appends the fields to a given string
+
+ @param f is the string
+ @param col (* col) is the column number where we will start to
+ write the text, the ending column will be stored in (* col)
+ @param fields is the fields to write
+*/
+
+int mailimf_fields_write_mem(MMAPString * f, int * col,
+ struct mailimf_fields * fields);
+
+
+/*
+ mailimf_envelope_fields_write_mem appends some fields to a given string
+
+ @param f is the string
+ @param col (* col) is the column number where we will start to
+ write the text, the ending column will be stored in (* col)
+ @param fields is the fields to write
+*/
+
+int mailimf_envelope_fields_write_mem(MMAPString * f, int * col,
+ struct mailimf_fields * fields);
+
+
+/*
+ mailimf_field_write_mem appends a field to a given string
+
+ @param f is the string
+ @param col (* col) is the column number where we will start to
+ write the text, the ending column will be stored in (* col)
+ @param field is the field to write
+*/
+
+int mailimf_field_write_mem(MMAPString * f, int * col,
+ struct mailimf_field * field);
+
+/*
+ mailimf_quoted_string_write_mem appends a string that is quoted
+ to a given string
+
+ @param f is the string
+ @param col (* col) is the column number where we will start to
+ write the text, the ending column will be stored in (* col)
+ @param string is the string to quote and write
+*/
+
+int mailimf_quoted_string_write_mem(MMAPString * f, int * col,
+ const char * string, size_t len);
+
+int mailimf_address_list_write_mem(MMAPString * f, int * col,
+ struct mailimf_address_list * addr_list);
+
+int mailimf_mailbox_list_write_mem(MMAPString * f, int * col,
+ struct mailimf_mailbox_list * mb_list);
+
+/*
+ mailimf_header_string_write_mem appends a header value and fold the header
+ if needed.
+
+ @param f is the string
+ @param col (* col) is the column number where we will start to
+ write the text, the ending column will be stored in (* col)
+ @param str is the string to write
+*/
+
+int mailimf_header_string_write_mem(MMAPString * f, int * col,
+ const char * str, size_t length);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libetpan/src/low-level/maildir/maildir.c b/libetpan/src/low-level/maildir/maildir.c
new file mode 100644
index 0000000..98b9f87
--- a/dev/null
+++ b/libetpan/src/low-level/maildir/maildir.c
@@ -0,0 +1,798 @@
+/*
+ * 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 "maildir.h"
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <time.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#ifdef LIBETPAN_SYSTEM_BASENAME
+#include <libgen.h>
+#endif
+
+/*
+ We suppose the maildir mailbox remains on one unique filesystem.
+*/
+
+struct maildir * maildir_new(const char * path)
+{
+ struct maildir * md;
+
+ md = malloc(sizeof(* md));
+ if (md == NULL)
+ goto err;
+
+ md->mdir_counter = 0;
+ md->mdir_mtime_new = (time_t) -1;
+ md->mdir_mtime_cur = (time_t) -1;
+
+ md->mdir_pid = getpid();
+ gethostname(md->mdir_hostname, sizeof(md->mdir_hostname));
+ strncpy(md->mdir_path, path, sizeof(md->mdir_path));
+ md->mdir_path[PATH_MAX - 1] = '\0';
+
+ md->mdir_msg_list = carray_new(128);
+ if (md->mdir_msg_list == NULL)
+ goto free;
+
+ md->mdir_msg_hash = chash_new(CHASH_DEFAULTSIZE, CHASH_COPYNONE);
+ if (md->mdir_msg_hash == NULL)
+ goto free_msg_list;
+
+ return md;
+
+ free_msg_list:
+ carray_free(md->mdir_msg_list);
+ free:
+ free(md);
+ err:
+ return NULL;
+}
+
+static void maildir_flush(struct maildir * md, int msg_new);
+
+void maildir_free(struct maildir * md)
+{
+ maildir_flush(md, 0);
+ maildir_flush(md, 1);
+ chash_free(md->mdir_msg_hash);
+ carray_free(md->mdir_msg_list);
+ free(md);
+}
+
+#define MAX_TRY_ALLOC 32
+
+static char * maildir_get_new_message_filename(struct maildir * md,
+ char * tmpfile)
+{
+ char filename[PATH_MAX];
+ char basename[PATH_MAX];
+ int k;
+ time_t now;
+ int got_file;
+ int r;
+
+ got_file = 0;
+ now = time(NULL);
+ k = 0;
+ while (k < MAX_TRY_ALLOC) {
+ snprintf(basename, sizeof(basename), "%lu.%u_%u.%s",
+ (unsigned long) now, md->mdir_pid, md->mdir_counter, md->mdir_hostname);
+ snprintf(filename, sizeof(filename), "%s/tmp/%s",
+ md->mdir_path, basename);
+
+ if (link(tmpfile, filename) == 0) {
+ got_file = 1;
+ unlink(tmpfile);
+ }
+ else if (errno == EXDEV) {
+ unlink(tmpfile);
+ return NULL;
+ }
+ else if (errno == EPERM) {
+ r = rename(tmpfile, filename);
+ if (r < 0) {
+ unlink(tmpfile);
+ return NULL;
+ }
+ got_file = 1;
+ }
+
+ if (got_file) {
+ char * dup_filename;
+
+ dup_filename = strdup(filename);
+ if (dup_filename == NULL) {
+ unlink(filename);
+ return NULL;
+ }
+
+ md->mdir_counter ++;
+
+ return dup_filename;
+ }
+
+ md->mdir_counter ++;
+ k ++;
+ }
+
+ return NULL;
+}
+
+
+static void msg_free(struct maildir_msg * msg)
+{
+ free(msg->msg_uid);
+ free(msg->msg_filename);
+ free(msg);
+}
+
+/*
+ msg_new()
+
+ filename is given without path
+*/
+
+static struct maildir_msg * msg_new(char * filename, int new_msg)
+{
+ struct maildir_msg * msg;
+ char * p;
+ int flags;
+ size_t uid_len;
+ char * begin_uid;
+
+ /* name of file : xxx-xxx_xxx-xxx:2,SRFT */
+
+ msg = malloc(sizeof(* msg));
+ if (msg == NULL)
+ goto err;
+
+ msg->msg_filename = strdup(filename);
+ if (msg->msg_filename == NULL)
+ goto free;
+
+ begin_uid = filename;
+
+ uid_len = strlen(begin_uid);
+
+ flags = 0;
+ p = strstr(filename, ":2,");
+ if (p != NULL) {
+ uid_len = p - begin_uid;
+
+ p += 3;
+
+ /* parse flags */
+ while (* p != '\0') {
+ switch (* p) {
+ case 'S':
+ flags |= MAILDIR_FLAG_SEEN;
+ break;
+ case 'R':
+ flags |= MAILDIR_FLAG_REPLIED;
+ break;
+ case 'F':
+ flags |= MAILDIR_FLAG_FLAGGED;
+ break;
+ case 'T':
+ flags |= MAILDIR_FLAG_TRASHED;
+ break;
+ }
+ p ++;
+ }
+ }
+
+ if (new_msg)
+ flags |= MAILDIR_FLAG_NEW;
+
+ msg->msg_flags = flags;
+
+ msg->msg_uid = malloc(uid_len + 1);
+ if (msg->msg_uid == NULL)
+ goto free_filename;
+
+ strncpy(msg->msg_uid, begin_uid, uid_len);
+ msg->msg_uid[uid_len] = '\0';
+
+ return msg;
+
+ free_filename:
+ free(msg->msg_filename);
+ free:
+ free(msg);
+ err:
+ return NULL;
+}
+
+static void maildir_flush(struct maildir * md, int msg_new)
+{
+ unsigned int i;
+
+ i = 0;
+ while (i < carray_count(md->mdir_msg_list)) {
+ struct maildir_msg * msg;
+ int delete;
+
+ msg = carray_get(md->mdir_msg_list, i);
+
+ if (msg_new) {
+ delete = 0;
+ if ((msg->msg_flags & MAILDIR_FLAG_NEW) != 0)
+ delete = 1;
+ }
+ else {
+ delete = 1;
+ if ((msg->msg_flags & MAILDIR_FLAG_NEW) != 0)
+ delete = 0;
+ }
+
+ if (delete) {
+ chashdatum key;
+
+ key.data = msg->msg_uid;
+ key.len = strlen(msg->msg_uid);
+ chash_delete(md->mdir_msg_hash, &key, NULL);
+
+ carray_delete(md->mdir_msg_list, i);
+ msg_free(msg);
+ }
+ else {
+ i ++;
+ }
+ }
+}
+
+static int add_message(struct maildir * md,
+ char * filename, int is_new)
+{
+ struct maildir_msg * msg;
+ chashdatum key;
+ chashdatum value;
+ unsigned int i;
+ int res;
+ int r;
+
+ msg = msg_new(filename, is_new);
+ if (msg == NULL) {
+ res = MAILDIR_ERROR_MEMORY;
+ goto err;
+ }
+
+ r = carray_add(md->mdir_msg_list, msg, &i);
+ if (r < 0) {
+ res = MAILDIR_ERROR_MEMORY;
+ goto free_msg;
+ }
+
+ key.data = msg->msg_uid;
+ key.len = strlen(msg->msg_uid);
+ value.data = msg;
+ value.len = 0;
+
+ r = chash_set(md->mdir_msg_hash, &key, &value, NULL);
+ if (r < 0) {
+ res = MAILDIR_ERROR_MEMORY;
+ goto delete;
+ }
+
+ return MAILDIR_NO_ERROR;
+
+ delete:
+ carray_delete(md->mdir_msg_list, i);
+ free_msg:
+ msg_free(msg);
+ err:
+ return res;
+}
+
+static int add_directory(struct maildir * md, char * path, int is_new)
+{
+ DIR * d;
+ struct dirent * entry;
+ int res;
+ int r;
+#if 0
+ char filename[PATH_MAX];
+#endif
+
+ d = opendir(path);
+ if (d == NULL) {
+ res = MAILDIR_ERROR_DIRECTORY;
+ goto err;
+ }
+
+ while ((entry = readdir(d)) != NULL) {
+#if 0
+ struct stat stat_info;
+
+ snprintf(filename, sizeof(filename), "%s/%s", path, entry->d_name);
+
+ r = stat(filename, &stat_info);
+ if (r < 0)
+ continue;
+
+ if (S_ISDIR(stat_info.st_mode))
+ continue;
+#endif
+
+ if (entry->d_name[0] == '.')
+ continue;
+
+ r = add_message(md, entry->d_name, is_new);
+ if (r != MAILDIR_NO_ERROR) {
+ /* ignore errors */
+ }
+ }
+
+ closedir(d);
+
+ return MAILDIR_NO_ERROR;
+
+ err:
+ return res;
+}
+
+int maildir_update(struct maildir * md)
+{
+ struct stat stat_info;
+ char path_new[PATH_MAX];
+ char path_cur[PATH_MAX];
+ char path_maildirfolder[PATH_MAX];
+ int r;
+ int res;
+ int changed;
+
+ snprintf(path_new, sizeof(path_new), "%s/new", md->mdir_path);
+ snprintf(path_cur, sizeof(path_cur), "%s/cur", md->mdir_path);
+
+ changed = 0;
+
+ /* did new/ changed ? */
+
+ r = stat(path_new, &stat_info);
+ if (r < 0) {
+ res = MAILDIR_ERROR_DIRECTORY;
+ goto free;
+ }
+
+ if (md->mdir_mtime_new != stat_info.st_mtime) {
+ md->mdir_mtime_new = stat_info.st_mtime;
+ changed = 1;
+ }
+
+ /* did cur/ changed ? */
+
+ r = stat(path_cur, &stat_info);
+ if (r < 0) {
+ res = MAILDIR_ERROR_DIRECTORY;
+ goto free;
+ }
+
+ if (md->mdir_mtime_cur != stat_info.st_mtime) {
+ md->mdir_mtime_cur = stat_info.st_mtime;
+ changed = 1;
+ }
+
+ if (changed) {
+
+ carray_set_size(md->mdir_msg_list, 0);
+ chash_clear(md->mdir_msg_hash);
+
+ maildir_flush(md, 1);
+
+ /* messages in new */
+ r = add_directory(md, path_new, 1);
+ if (r != MAILDIR_NO_ERROR) {
+ res = r;
+ goto free;
+ }
+
+ maildir_flush(md, 0);
+
+ /* messages in cur */
+ r = add_directory(md, path_cur, 0);
+ if (r != MAILDIR_NO_ERROR) {
+ res = r;
+ goto free;
+ }
+ }
+
+ snprintf(path_maildirfolder, sizeof(path_maildirfolder),
+ "%s/maildirfolder", md->mdir_path);
+
+ if (stat(path_maildirfolder, &stat_info) == -1) {
+ int fd;
+
+ fd = creat(path_maildirfolder, S_IRUSR | S_IWUSR);
+ if (fd != -1)
+ close(fd);
+ }
+
+ return MAILDIR_NO_ERROR;
+
+ free:
+ maildir_flush(md, 0);
+ maildir_flush(md, 1);
+ md->mdir_mtime_cur = (time_t) -1;
+ md->mdir_mtime_new = (time_t) -1;
+ return res;
+}
+
+#ifndef LIBETPAN_SYSTEM_BASENAME
+static char * libetpan_basename(char * filename)
+{
+ char * next;
+ char * p;
+
+ p = filename;
+ next = strchr(p, '/');
+
+ while (next != NULL) {
+ p = next;
+ next = strchr(p + 1, '/');
+ }
+
+ if (p == filename)
+ return filename;
+ else
+ return p + 1;
+}
+#else
+#define libetpan_basename(a) basename(a)
+#endif
+
+int maildir_message_add_uid(struct maildir * md,
+ const char * message, size_t size,
+ char * uid, size_t max_uid_len)
+{
+ char path_new[PATH_MAX];
+ char tmpname[PATH_MAX];
+ int fd;
+ int r;
+ char * mapping;
+ char * delivery_tmp_name;
+ char * delivery_tmp_basename;
+ char delivery_new_name[PATH_MAX];
+ char * delivery_new_basename;
+ int res;
+ struct stat stat_info;
+
+ r = maildir_update(md);
+ if (r != MAILDIR_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ /* write to tmp/ with a classic temporary file */
+
+ snprintf(tmpname, sizeof(tmpname), "%s/tmp/etpan-maildir-XXXXXX",
+ md->mdir_path);
+ fd = mkstemp(tmpname);
+ if (fd < 0) {
+ res = MAILDIR_ERROR_FILE;
+ goto err;
+ }
+
+ r = ftruncate(fd, size);
+ if (r < 0) {
+ res = MAILDIR_ERROR_FILE;
+ goto close;
+ }
+
+ mapping = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+ if (mapping == MAP_FAILED) {
+ res = MAILDIR_ERROR_FILE;
+ goto close;
+ }
+
+ memcpy(mapping, message, size);
+
+ msync(mapping, size, MS_SYNC);
+ munmap(mapping, size);
+
+ close(fd);
+
+ /* write to tmp/ with maildir standard name */
+
+ delivery_tmp_name = maildir_get_new_message_filename(md, tmpname);
+ if (delivery_tmp_name == NULL) {
+ res = MAILDIR_ERROR_FILE;
+ goto unlink;
+ }
+
+ /* write to new/ with maildir standard name */
+
+ strncpy(tmpname, delivery_tmp_name, sizeof(tmpname));
+ tmpname[sizeof(tmpname) - 1] = '\0';
+
+ delivery_tmp_basename = libetpan_basename(tmpname);
+
+ snprintf(delivery_new_name, sizeof(delivery_new_name), "%s/new/%s",
+ md->mdir_path, delivery_tmp_basename);
+
+ r = link(delivery_tmp_name, delivery_new_name);
+ if (r == 0) {
+ unlink(delivery_tmp_name);
+ }
+ else if (errno == EXDEV) {
+ res = MAILDIR_ERROR_FOLDER;
+ goto unlink_tmp;
+ }
+ else if (errno == EPERM) {
+ r = rename(delivery_tmp_name, delivery_new_name);
+ if (r < 0) {
+ res = MAILDIR_ERROR_FILE;
+ goto unlink_tmp;
+ }
+ }
+
+ snprintf(path_new, sizeof(path_new), "%s/new", md->mdir_path);
+ r = stat(path_new, &stat_info);
+ if (r < 0) {
+ unlink(delivery_new_name);
+ res = MAILDIR_ERROR_FILE;
+ goto unlink_tmp;
+ }
+
+ md->mdir_mtime_new = stat_info.st_mtime;
+
+ delivery_new_basename = libetpan_basename(delivery_new_name);
+
+ r = add_message(md, delivery_new_basename, 1);
+ if (r != MAILDIR_NO_ERROR) {
+ unlink(delivery_new_name);
+ res = MAILDIR_ERROR_FILE;
+ goto unlink_tmp;
+ }
+
+ if (uid != NULL)
+ strncpy(uid, delivery_new_basename, max_uid_len);
+
+ free(delivery_tmp_name);
+
+ return MAILDIR_NO_ERROR;
+
+ unlink_tmp:
+ unlink(delivery_tmp_name);
+ free(delivery_tmp_name);
+ goto err;
+ close:
+ close(fd);
+ unlink:
+ unlink(tmpname);
+ err:
+ return res;
+}
+
+int maildir_message_add(struct maildir * md,
+ const char * message, size_t size)
+{
+ return maildir_message_add_uid(md, message, size,
+ NULL, 0);
+}
+
+int maildir_message_add_file_uid(struct maildir * md, int fd,
+ char * uid, size_t max_uid_len)
+{
+ char * message;
+ struct stat buf;
+ int r;
+
+ if (fstat(fd, &buf) == -1)
+ return MAILDIR_ERROR_FILE;
+
+ message = mmap(NULL, buf.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+ if (message == MAP_FAILED)
+ return MAILDIR_ERROR_FILE;
+
+ r = maildir_message_add_uid(md, message, buf.st_size, uid, max_uid_len);
+
+ munmap(message, buf.st_size);
+
+ return r;
+}
+
+int maildir_message_add_file(struct maildir * md, int fd)
+{
+ return maildir_message_add_file_uid(md, fd,
+ NULL, 0);
+}
+
+char * maildir_message_get(struct maildir * md, const char * uid)
+{
+ chashdatum key;
+ chashdatum value;
+ char filename[PATH_MAX];
+ char * dup_filename;
+ struct maildir_msg * msg;
+ char * dir;
+ int r;
+
+ key.data = (void *) uid;
+ key.len = strlen(uid);
+ r = chash_get(md->mdir_msg_hash, &key, &value);
+ if (r < 0)
+ return NULL;
+
+ msg = value.data;
+ if ((msg->msg_flags & MAILDIR_FLAG_NEW) != 0)
+ dir = "new";
+ else
+ dir = "cur";
+
+ snprintf(filename, sizeof(filename), "%s/%s/%s",
+ md->mdir_path, dir, msg->msg_filename);
+
+ dup_filename = strdup(filename);
+ if (dup_filename == NULL)
+ return NULL;
+
+ return dup_filename;
+}
+
+int maildir_message_remove(struct maildir * md, const char * uid)
+{
+ chashdatum key;
+ chashdatum value;
+ char filename[PATH_MAX];
+ struct maildir_msg * msg;
+ char * dir;
+ int r;
+ int res;
+
+ key.data = (void *) uid;
+ key.len = strlen(uid);
+ r = chash_get(md->mdir_msg_hash, &key, &value);
+ if (r < 0) {
+ res = MAILDIR_ERROR_NOT_FOUND;
+ goto err;
+ }
+
+ msg = value.data;
+ if ((msg->msg_flags & MAILDIR_FLAG_NEW) != 0)
+ dir = "new";
+ else
+ dir = "cur";
+
+ snprintf(filename, sizeof(filename), "%s/%s/%s",
+ md->mdir_path, dir, msg->msg_filename);
+
+ r = unlink(filename);
+ if (r < 0) {
+ res = MAILDIR_ERROR_FILE;
+ goto err;
+ }
+
+ return MAILDIR_NO_ERROR;
+
+ err:
+ return res;
+}
+
+int maildir_message_change_flags(struct maildir * md,
+ const char * uid, int new_flags)
+{
+ chashdatum key;
+ chashdatum value;
+ char filename[PATH_MAX];
+ struct maildir_msg * msg;
+ char * dir;
+ int r;
+ char new_filename[PATH_MAX];
+ char flag_str[5];
+ size_t i;
+ int res;
+
+ key.data = (void *) uid;
+ key.len = strlen(uid);
+ r = chash_get(md->mdir_msg_hash, &key, &value);
+ if (r < 0) {
+ res = MAILDIR_ERROR_NOT_FOUND;
+ goto err;
+ }
+
+ msg = value.data;
+ if ((msg->msg_flags & MAILDIR_FLAG_NEW) != 0)
+ dir = "new";
+ else
+ dir = "cur";
+
+ snprintf(filename, sizeof(filename), "%s/%s/%s",
+ md->mdir_path, dir, msg->msg_filename);
+
+ if ((new_flags & MAILDIR_FLAG_NEW) != 0)
+ dir = "new";
+ else
+ dir = "cur";
+
+ i = 0;
+ if ((new_flags & MAILDIR_FLAG_SEEN) != 0) {
+ flag_str[i] = 'S';
+ i ++;
+ }
+ if ((new_flags & MAILDIR_FLAG_REPLIED) != 0) {
+ flag_str[i] = 'R';
+ i ++;
+ }
+ if ((new_flags & MAILDIR_FLAG_FLAGGED) != 0) {
+ flag_str[i] = 'F';
+ i ++;
+ }
+ if ((new_flags & MAILDIR_FLAG_TRASHED) != 0) {
+ flag_str[i] = 'T';
+ i ++;
+ }
+ flag_str[i] = 0;
+
+ if (flag_str[0] == '\0')
+ snprintf(new_filename, sizeof(new_filename), "%s/%s/%s",
+ md->mdir_path, dir, msg->msg_uid);
+ else
+ snprintf(new_filename, sizeof(new_filename), "%s/%s/%s:2,%s",
+ md->mdir_path, dir, msg->msg_uid, flag_str);
+
+ if (strcmp(filename, new_filename) == 0)
+ return MAILDIR_NO_ERROR;
+
+ r = link(filename, new_filename);
+ if (r == 0) {
+ unlink(filename);
+ }
+ else if (errno == EXDEV) {
+ res = MAILDIR_ERROR_FOLDER;
+ goto err;
+ }
+ else if (errno == EPERM) {
+ r = rename(filename, new_filename);
+ if (r < 0) {
+ res = MAILDIR_ERROR_FOLDER;
+ goto err;
+ }
+ }
+
+ return MAILDIR_NO_ERROR;
+
+ err:
+ return res;
+}
diff --git a/libetpan/src/low-level/maildir/maildir.h b/libetpan/src/low-level/maildir/maildir.h
new file mode 100644
index 0000000..d099dc0
--- a/dev/null
+++ b/libetpan/src/low-level/maildir/maildir.h
@@ -0,0 +1,67 @@
+/*
+ * 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$
+ */
+
+#ifndef MAILDIR_H
+
+#define MAILDIR_H
+
+#include <libetpan/maildir_types.h>
+
+struct maildir * maildir_new(const char * path);
+
+void maildir_free(struct maildir * md);
+
+int maildir_update(struct maildir * md);
+
+int maildir_message_add_uid(struct maildir * md,
+ const char * message, size_t size,
+ char * uid, size_t max_uid_len);
+
+int maildir_message_add(struct maildir * md,
+ const char * message, size_t size);
+
+int maildir_message_add_file_uid(struct maildir * md, int fd,
+ char * uid, size_t max_uid_len);
+
+int maildir_message_add_file(struct maildir * md, int fd);
+
+char * maildir_message_get(struct maildir * md, const char * uid);
+
+int maildir_message_remove(struct maildir * md, const char * uid);
+
+int maildir_message_change_flags(struct maildir * md,
+ const char * uid, int new_flags);
+
+#endif
diff --git a/libetpan/src/low-level/maildir/maildir_types.h b/libetpan/src/low-level/maildir/maildir_types.h
new file mode 100644
index 0000000..5be5a78
--- a/dev/null
+++ b/libetpan/src/low-level/maildir/maildir_types.h
@@ -0,0 +1,91 @@
+/*
+ * 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$
+ */
+
+#ifndef MAILDIR_TYPES_H
+
+#define MAILDIR_TYPES_H
+
+#include <sys/types.h>
+#include <unistd.h>
+#include <libetpan/chash.h>
+#include <libetpan/carray.h>
+#include <inttypes.h>
+
+#include <libetpan/libetpan-config.h>
+
+#define LIBETPAN_MAILDIR
+
+enum {
+ MAILDIR_NO_ERROR = 0,
+ MAILDIR_ERROR_CREATE,
+ MAILDIR_ERROR_DIRECTORY,
+ MAILDIR_ERROR_MEMORY,
+ MAILDIR_ERROR_FILE,
+ MAILDIR_ERROR_NOT_FOUND,
+ MAILDIR_ERROR_FOLDER,
+};
+
+#define MAILDIR_FLAG_NEW (1 << 0)
+#define MAILDIR_FLAG_SEEN (1 << 1)
+#define MAILDIR_FLAG_REPLIED (1 << 2)
+#define MAILDIR_FLAG_FLAGGED (1 << 3)
+#define MAILDIR_FLAG_TRASHED (1 << 4)
+
+struct maildir_msg {
+ char * msg_uid;
+ char * msg_filename;
+ int msg_flags;
+};
+
+/*
+ work around for missing #define HOST_NAME_MAX in Linux
+*/
+
+#ifndef HOST_NAME_MAX
+#define HOST_NAME_MAX 255
+#endif
+
+struct maildir {
+ pid_t mdir_pid;
+ char mdir_hostname[HOST_NAME_MAX];
+ char mdir_path[PATH_MAX];
+ uint32_t mdir_counter;
+ time_t mdir_mtime_new;
+ time_t mdir_mtime_cur;
+ carray * mdir_msg_list;
+ chash * mdir_msg_hash;
+};
+
+#endif
diff --git a/libetpan/src/low-level/mbox/TODO b/libetpan/src/low-level/mbox/TODO
new file mode 100644
index 0000000..e69de29
--- a/dev/null
+++ b/libetpan/src/low-level/mbox/TODO
diff --git a/libetpan/src/low-level/mbox/mailmbox.c b/libetpan/src/low-level/mbox/mailmbox.c
new file mode 100644
index 0000000..9937f3a
--- a/dev/null
+++ b/libetpan/src/low-level/mbox/mailmbox.c
@@ -0,0 +1,1525 @@
+/*
+ * 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 "mailmbox.h"
+
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <time.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <string.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libetpan-config.h"
+
+#include "mmapstring.h"
+#include "mailmbox_parse.h"
+#include "maillock.h"
+
+/*
+ http://www.qmail.org/qmail-manual-html/man5/mbox.html
+ RFC 2076
+*/
+
+#define TMPDIR "/tmp"
+
+/* mbox is a file with a corresponding filename */
+
+#define UID_HEADER "X-LibEtPan-UID:"
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+int mailmbox_write_lock(struct mailmbox_folder * folder)
+{
+ int r;
+
+ if (folder->mb_read_only)
+ return MAILMBOX_ERROR_READONLY;
+
+ r = maillock_write_lock(folder->mb_filename, folder->mb_fd);
+ if (r == 0)
+ return MAILMBOX_NO_ERROR;
+ else
+ return MAILMBOX_ERROR_FILE;
+}
+
+int mailmbox_write_unlock(struct mailmbox_folder * folder)
+{
+ int r;
+
+ r = maillock_write_unlock(folder->mb_filename, folder->mb_fd);
+ if (r == 0)
+ return MAILMBOX_NO_ERROR;
+ else
+ return MAILMBOX_ERROR_FILE;
+}
+
+int mailmbox_read_lock(struct mailmbox_folder * folder)
+{
+ int r;
+
+ r = maillock_read_lock(folder->mb_filename, folder->mb_fd);
+ if (r == 0)
+ return MAILMBOX_NO_ERROR;
+ else
+ return MAILMBOX_ERROR_FILE;
+}
+
+int mailmbox_read_unlock(struct mailmbox_folder * folder)
+{
+ int r;
+
+ r = maillock_read_unlock(folder->mb_filename, folder->mb_fd);
+ if (r == 0)
+ return MAILMBOX_NO_ERROR;
+ else
+ return MAILMBOX_ERROR_FILE;
+}
+
+
+/*
+ map the file into memory.
+ the file must be locked.
+*/
+
+int mailmbox_map(struct mailmbox_folder * folder)
+{
+ char * str;
+ struct stat buf;
+ int res;
+ int r;
+
+ r = stat(folder->mb_filename, &buf);
+ if (r < 0) {
+ res = MAILMBOX_ERROR_FILE;
+ goto err;
+ }
+
+ if (folder->mb_read_only)
+ str = (char *) mmap(0, buf.st_size, PROT_READ,
+ MAP_PRIVATE, folder->mb_fd, 0);
+ else
+ str = (char *) mmap(0, buf.st_size, PROT_READ | PROT_WRITE,
+ MAP_SHARED, folder->mb_fd, 0);
+ if (str == MAP_FAILED) {
+ res = MAILMBOX_ERROR_FILE;
+ goto err;
+ }
+
+ folder->mb_mapping = str;
+ folder->mb_mapping_size = buf.st_size;
+
+ return MAILMBOX_NO_ERROR;
+
+ err:
+ return res;
+}
+
+/*
+ unmap the file
+*/
+
+void mailmbox_unmap(struct mailmbox_folder * folder)
+{
+ munmap(folder->mb_mapping, folder->mb_mapping_size);
+ folder->mb_mapping = NULL;
+ folder->mb_mapping_size = 0;
+}
+
+void mailmbox_sync(struct mailmbox_folder * folder)
+{
+ msync(folder->mb_mapping, folder->mb_mapping_size, MS_SYNC);
+}
+
+void mailmbox_timestamp(struct mailmbox_folder * folder)
+{
+ int r;
+ struct stat buf;
+
+ r = stat(folder->mb_filename, &buf);
+ if (r < 0)
+ folder->mb_mtime = (time_t) -1;
+ else
+ folder->mb_mtime = buf.st_mtime;
+}
+
+/*
+ open the file
+*/
+
+int mailmbox_open(struct mailmbox_folder * folder)
+{
+ int fd;
+ int read_only;
+
+ fd = -1;
+ read_only = TRUE;
+
+ if (!folder->mb_read_only) {
+ read_only = FALSE;
+ fd = open(folder->mb_filename, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
+ }
+
+ if (folder->mb_read_only || (fd < 0)) {
+ read_only = TRUE;
+ fd = open(folder->mb_filename, O_RDONLY);
+ if (fd < 0)
+ return MAILMBOX_ERROR_FILE_NOT_FOUND;
+ }
+
+ folder->mb_fd = fd;
+ folder->mb_read_only = read_only;
+
+ return MAILMBOX_NO_ERROR;
+}
+
+/*
+ close the file
+*/
+
+void mailmbox_close(struct mailmbox_folder * folder)
+{
+ close(folder->mb_fd);
+ folder->mb_fd = -1;
+}
+
+
+static int mailmbox_validate_lock(struct mailmbox_folder * folder,
+ int (* custom_lock)(struct mailmbox_folder *),
+ int (* custom_unlock)(struct mailmbox_folder *))
+{
+ struct stat buf;
+ int res;
+ int r;
+
+ r = stat(folder->mb_filename, &buf);
+ if (r < 0) {
+ buf.st_mtime = (time_t) -1;
+ }
+
+ if ((buf.st_mtime != folder->mb_mtime) ||
+ ((size_t) buf.st_size != folder->mb_mapping_size)) {
+ int r;
+
+ mailmbox_unmap(folder);
+ mailmbox_close(folder);
+
+ r = mailmbox_open(folder);
+ if (r != MAILMBOX_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ r = custom_lock(folder);
+ if (r != MAILMBOX_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ r = mailmbox_map(folder);
+ if (r != MAILMBOX_NO_ERROR) {
+ res = r;
+ goto err_unlock;
+ }
+
+ r = mailmbox_parse(folder);
+ if (r != MAILMBOX_NO_ERROR) {
+ res = r;
+ goto err_unlock;
+ }
+
+ folder->mb_mtime = buf.st_mtime;
+
+ return MAILMBOX_NO_ERROR;
+ }
+ else {
+ r = custom_lock(folder);
+ if (r != MAILMBOX_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+ }
+
+ return MAILMBOX_NO_ERROR;
+
+ err_unlock:
+ custom_unlock(folder);
+ err:
+ return res;
+}
+
+
+int mailmbox_validate_write_lock(struct mailmbox_folder * folder)
+{
+ return mailmbox_validate_lock(folder,
+ mailmbox_write_lock,
+ mailmbox_write_unlock);
+}
+
+
+int mailmbox_validate_read_lock(struct mailmbox_folder * folder)
+{
+ return mailmbox_validate_lock(folder,
+ mailmbox_read_lock,
+ mailmbox_read_unlock);
+}
+
+
+/* ********************************************************************** */
+/* append messages */
+
+#define MAX_FROM_LINE_SIZE 256
+
+static inline size_t get_line(const char * line, size_t length,
+ const char ** pnext_line, size_t * pcount)
+{
+ size_t count;
+
+ count = 0;
+
+ while (1) {
+ if (length == 0)
+ break;
+
+ if (* line == '\r') {
+ line ++;
+
+ count ++;
+ length --;
+
+ if (length > 0) {
+ if (* line == '\n') {
+ line ++;
+
+ count ++;
+ length --;
+
+ break;
+ }
+ }
+ }
+ else if (* line == '\n') {
+ line ++;
+
+ count ++;
+ length --;
+
+ break;
+ }
+ else {
+ line ++;
+ length --;
+ count ++;
+ }
+ }
+
+ * pnext_line = line;
+ * pcount = count;
+
+ return count;
+}
+
+/*
+ TODO : should strip \r\n if any
+ see also in write_fixed_line
+*/
+
+static inline size_t get_fixed_line_size(const char * line, size_t length,
+ const char ** pnext_line, size_t * pcount,
+ size_t * pfixed_count)
+{
+ size_t count;
+ const char * next_line;
+ size_t fixed_count;
+
+ if (!get_line(line, length, &next_line, &count))
+ return 0;
+
+ fixed_count = count;
+ if (count >= 5) {
+ if (line[0] == 'F') {
+ if (strncmp(line, "From ", 5) == 0)
+ fixed_count ++;
+ }
+ }
+
+ * pnext_line = next_line;
+ * pcount = count;
+ * pfixed_count = fixed_count;
+
+ return count;
+}
+
+static size_t get_fixed_message_size(const char * message, size_t size,
+ uint32_t uid, int force_no_uid)
+{
+ size_t fixed_size;
+ size_t cur_token;
+ size_t left;
+ const char * next;
+ const char * cur;
+ int end;
+ int r;
+ uint32_t tmp_uid;
+
+ cur_token = 0;
+
+ fixed_size = 0;
+
+ /* headers */
+
+ end = FALSE;
+ while (!end) {
+ size_t begin;
+ int ignore;
+
+ ignore = FALSE;
+ begin = cur_token;
+ if (cur_token + strlen(UID_HEADER) <= size) {
+ if (message[cur_token] == 'X') {
+ if (strncasecmp(message + cur_token, UID_HEADER,
+ strlen(UID_HEADER)) == 0) {
+ ignore = TRUE;
+ }
+ }
+ }
+
+ r = mailimf_ignore_field_parse(message, size, &cur_token);
+ switch (r) {
+ case MAILIMF_NO_ERROR:
+ if (!ignore)
+ fixed_size += cur_token - begin;
+ break;
+ case MAILIMF_ERROR_PARSE:
+ default:
+ end = TRUE;
+ break;
+ }
+ }
+
+ if (!force_no_uid) {
+ /* UID header */
+
+ fixed_size += strlen(UID_HEADER " \r\n");
+
+ tmp_uid = uid;
+ while (tmp_uid >= 10) {
+ tmp_uid /= 10;
+ fixed_size ++;
+ }
+ fixed_size ++;
+ }
+
+ /* body */
+
+ left = size - cur_token;
+ next = message + cur_token;
+ while (left > 0) {
+ size_t count;
+ size_t fixed_count;
+
+ cur = next;
+
+ if (!get_fixed_line_size(cur, left, &next, &count, &fixed_count))
+ break;
+
+ fixed_size += fixed_count;
+ left -= count;
+ }
+
+ return fixed_size;
+}
+
+static inline char * write_fixed_line(char * str,
+ const char * line, size_t length,
+ const char ** pnext_line, size_t * pcount)
+{
+ size_t count;
+ const char * next_line;
+
+ if (!get_line(line, length, &next_line, &count))
+ return str;
+
+ if (count >= 5) {
+ if (line[0] == 'F') {
+ if (strncmp(line, "From ", 5) == 0) {
+ * str = '>';
+ str ++;
+ }
+ }
+ }
+
+ memcpy(str, line, count);
+
+ * pnext_line = next_line;
+ * pcount = count;
+ str += count;
+
+ return str;
+}
+
+static char * write_fixed_message(char * str,
+ const char * message, size_t size,
+ uint32_t uid, int force_no_uid)
+{
+ size_t fixed_size;
+ size_t cur_token;
+ size_t left;
+ int end;
+ int r;
+ const char * cur_src;
+ size_t numlen;
+
+ cur_token = 0;
+
+ fixed_size = 0;
+
+ /* headers */
+
+ end = FALSE;
+ while (!end) {
+ size_t begin;
+ int ignore;
+
+ ignore = FALSE;
+ begin = cur_token;
+ if (cur_token + strlen(UID_HEADER) <= size) {
+ if (message[cur_token] == 'X') {
+ if (strncasecmp(message + cur_token, UID_HEADER,
+ strlen(UID_HEADER)) == 0) {
+ ignore = TRUE;
+ }
+ }
+ }
+
+ r = mailimf_ignore_field_parse(message, size, &cur_token);
+ switch (r) {
+ case MAILIMF_NO_ERROR:
+ if (!ignore) {
+ memcpy(str, message + begin, cur_token - begin);
+ str += cur_token - begin;
+ }
+ break;
+ case MAILIMF_ERROR_PARSE:
+ default:
+ end = TRUE;
+ break;
+ }
+ }
+
+ if (!force_no_uid) {
+ /* UID header */
+
+ memcpy(str, UID_HEADER " ", strlen(UID_HEADER " "));
+ str += strlen(UID_HEADER " ");
+ numlen = snprintf(str, 20, "%i\r\n", uid);
+ str += numlen;
+ }
+
+ /* body */
+
+ cur_src = message + cur_token;
+ left = size - cur_token;
+ while (left > 0) {
+ size_t count;
+ const char * next;
+
+ str = write_fixed_line(str, cur_src, left, &next, &count);
+
+ cur_src = next;
+ left -= count;
+ }
+
+ return str;
+}
+
+#define DEFAULT_FROM_LINE "From - Wed Jun 30 21:49:08 1993\n"
+
+int
+mailmbox_append_message_list_no_lock(struct mailmbox_folder * folder,
+ carray * append_tab)
+{
+ size_t extra_size;
+ int r;
+ char from_line[MAX_FROM_LINE_SIZE] = DEFAULT_FROM_LINE;
+ struct tm time_info;
+ time_t date;
+ int res;
+ size_t old_size;
+ char * str;
+ unsigned int i;
+ size_t from_size;
+ size_t maxuid;
+ size_t left;
+ size_t crlf_count;
+
+ if (folder->mb_read_only) {
+ res = MAILMBOX_ERROR_READONLY;
+ goto err;
+ }
+
+ date = time(NULL);
+ from_size = strlen(DEFAULT_FROM_LINE);
+ if (localtime_r(&date, &time_info) != NULL)
+ from_size = strftime(from_line, MAX_FROM_LINE_SIZE, "From - %c\n", &time_info);
+
+ maxuid = /* */ folder->mb_max_uid;
+
+ extra_size = 0;
+ for(i = 0 ; i < carray_count(append_tab) ; i ++) {
+ struct mailmbox_append_info * info;
+
+ info = carray_get(append_tab, i);
+ extra_size += from_size;
+ extra_size += get_fixed_message_size(info->ai_message, info->ai_size,
+ folder->mb_max_uid + i + 1,
+ folder->mb_no_uid);
+ extra_size += 2; /* CR LF */
+
+ info->ai_uid = folder->mb_max_uid + i + 1;
+ }
+
+ left = folder->mb_mapping_size;
+ crlf_count = 0;
+ while (left >= 1) {
+ if (folder->mb_mapping[left - 1] == '\n') {
+ crlf_count ++;
+ left --;
+ }
+ else if (folder->mb_mapping[left - 1] == '\r') {
+ left --;
+ }
+ else
+ break;
+
+ if (crlf_count == 2)
+ break;
+ }
+
+ old_size = folder->mb_mapping_size;
+ mailmbox_unmap(folder);
+
+ if (old_size != 0) {
+ if (crlf_count != 2)
+ extra_size += (2 - crlf_count) * 2;
+ }
+
+ r = ftruncate(folder->mb_fd, extra_size + old_size);
+ if (r < 0) {
+ mailmbox_map(folder);
+ res = MAILMBOX_ERROR_FILE;
+ goto err;
+ }
+
+ r = mailmbox_map(folder);
+ if (r < 0) {
+ ftruncate(folder->mb_fd, old_size);
+ return MAILMBOX_ERROR_FILE;
+ }
+
+ str = folder->mb_mapping + old_size;
+
+ if (old_size != 0) {
+ for(i = 0 ; i < 2 - crlf_count ; i ++) {
+ * str = '\r';
+ str ++;
+ * str = '\n';
+ str ++;
+ }
+ }
+
+ for(i = 0 ; i < carray_count(append_tab) ; i ++) {
+ struct mailmbox_append_info * info;
+
+ info = carray_get(append_tab, i);
+
+ memcpy(str, from_line, from_size);
+
+ str += strlen(from_line);
+
+ str = write_fixed_message(str, info->ai_message, info->ai_size,
+ folder->mb_max_uid + i + 1,
+ folder->mb_no_uid);
+
+ * str = '\r';
+ str ++;
+ * str = '\n';
+ str ++;
+ }
+
+ folder->mb_max_uid += carray_count(append_tab);
+
+ return MAILMBOX_NO_ERROR;
+
+ err:
+ return res;
+}
+
+int
+mailmbox_append_message_list(struct mailmbox_folder * folder,
+ carray * append_tab)
+{
+ int r;
+ int res;
+ size_t cur_token;
+
+ r = mailmbox_validate_write_lock(folder);
+ if (r != MAILMBOX_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ r = mailmbox_expunge_no_lock(folder);
+ if (r != MAILMBOX_NO_ERROR) {
+ res = r;
+ goto unlock;
+ }
+
+ cur_token = folder->mb_mapping_size;
+
+ r = mailmbox_append_message_list_no_lock(folder, append_tab);
+ if (r != MAILMBOX_NO_ERROR) {
+ res = r;
+ goto unlock;
+ }
+
+ mailmbox_sync(folder);
+
+ r = mailmbox_parse_additionnal(folder, &cur_token);
+ if (r != MAILMBOX_NO_ERROR) {
+ res = r;
+ goto unlock;
+ }
+
+ mailmbox_timestamp(folder);
+
+ mailmbox_write_unlock(folder);
+
+ return MAILMBOX_NO_ERROR;
+
+ unlock:
+ mailmbox_write_unlock(folder);
+ err:
+ return res;
+}
+
+int
+mailmbox_append_message_uid(struct mailmbox_folder * folder,
+ const char * data, size_t len, unsigned int * puid)
+{
+ carray * tab;
+ struct mailmbox_append_info * append_info;
+ int res;
+ int r;
+
+ tab = carray_new(1);
+ if (tab == NULL) {
+ res = MAILMBOX_ERROR_MEMORY;
+ goto err;
+ }
+
+ append_info = mailmbox_append_info_new(data, len);
+ if (append_info == NULL) {
+ res = MAILMBOX_ERROR_MEMORY;
+ goto free_list;
+ }
+
+ r = carray_add(tab, append_info, NULL);
+ if (r < 0) {
+ res = MAILMBOX_ERROR_MEMORY;
+ goto free_append_info;
+ }
+
+ r = mailmbox_append_message_list(folder, tab);
+
+ if (puid != NULL)
+ * puid = append_info->ai_uid;
+
+ mailmbox_append_info_free(append_info);
+ carray_free(tab);
+
+ return r;
+
+ free_append_info:
+ mailmbox_append_info_free(append_info);
+ free_list:
+ carray_free(tab);
+ err:
+ return res;
+}
+
+int
+mailmbox_append_message(struct mailmbox_folder * folder,
+ const char * data, size_t len)
+{
+ return mailmbox_append_message_uid(folder, data, len, NULL);
+}
+
+/* ********************************************************************** */
+
+int mailmbox_fetch_msg_no_lock(struct mailmbox_folder * folder,
+ uint32_t num, char ** result,
+ size_t * result_len)
+{
+ struct mailmbox_msg_info * info;
+ int res;
+ chashdatum key;
+ chashdatum data;
+ int r;
+
+ key.data = &num;
+ key.len = sizeof(num);
+
+ r = chash_get(folder->mb_hash, &key, &data);
+ if (r < 0) {
+ res = MAILMBOX_ERROR_MSG_NOT_FOUND;
+ goto err;
+ }
+
+ info = data.data;
+
+ if (info->msg_deleted) {
+ res = MAILMBOX_ERROR_MSG_NOT_FOUND;
+ goto err;
+ }
+
+ * result = folder->mb_mapping + info->msg_headers;
+ * result_len = info->msg_size - info->msg_start_len;
+
+ return MAILMBOX_NO_ERROR;
+
+ err:
+ return res;
+}
+
+int mailmbox_fetch_msg_headers_no_lock(struct mailmbox_folder * folder,
+ uint32_t num, char ** result,
+ size_t * result_len)
+{
+ struct mailmbox_msg_info * info;
+ int res;
+ chashdatum key;
+ chashdatum data;
+ int r;
+
+ key.data = &num;
+ key.len = sizeof(num);
+
+ r = chash_get(folder->mb_hash, &key, &data);
+ if (r < 0) {
+ res = MAILMBOX_ERROR_MSG_NOT_FOUND;
+ goto err;
+ }
+
+ info = data.data;
+
+ if (info->msg_deleted) {
+ res = MAILMBOX_ERROR_MSG_NOT_FOUND;
+ goto err;
+ }
+
+ * result = folder->mb_mapping + info->msg_headers;
+ * result_len = info->msg_headers_len;
+
+ return MAILMBOX_NO_ERROR;
+
+ err:
+ return res;
+}
+
+int mailmbox_fetch_msg(struct mailmbox_folder * folder,
+ uint32_t num, char ** result,
+ size_t * result_len)
+{
+ MMAPString * mmapstr;
+ int res;
+ char * data;
+ size_t len;
+ int r;
+ size_t fixed_size;
+ char * end;
+
+ r = mailmbox_validate_read_lock(folder);
+ if (r != MAILMBOX_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ r = mailmbox_fetch_msg_no_lock(folder, num, &data, &len);
+ if (r != MAILMBOX_NO_ERROR) {
+ res = r;
+ goto unlock;
+ }
+
+ /* size with no uid */
+ fixed_size = get_fixed_message_size(data, len, 0, 1 /* force no uid */);
+
+#if 0
+ mmapstr = mmap_string_new_len(data, fixed_size);
+ if (mmapstr == NULL) {
+ res = MAILMBOX_ERROR_MEMORY;
+ goto unlock;
+ }
+#endif
+ mmapstr = mmap_string_sized_new(fixed_size);
+ if (mmapstr == NULL) {
+ res = MAILMBOX_ERROR_MEMORY;
+ goto unlock;
+ }
+
+ end = write_fixed_message(mmapstr->str, data, len, 0, 1 /* force no uid */);
+ * end = '\0';
+ mmapstr->len = fixed_size;
+
+ r = mmap_string_ref(mmapstr);
+ if (r < 0) {
+ mmap_string_free(mmapstr);
+ res = MAILMBOX_ERROR_MEMORY;
+ goto unlock;
+ }
+
+ * result = mmapstr->str;
+ * result_len = mmapstr->len;
+
+ mailmbox_read_unlock(folder);
+
+ return MAILMBOX_NO_ERROR;
+
+ unlock:
+ mailmbox_read_unlock(folder);
+ err:
+ return res;
+}
+
+int mailmbox_fetch_msg_headers(struct mailmbox_folder * folder,
+ uint32_t num, char ** result,
+ size_t * result_len)
+{
+ MMAPString * mmapstr;
+ int res;
+ char * data;
+ size_t len;
+ int r;
+ size_t fixed_size;
+ char * end;
+
+ r = mailmbox_validate_read_lock(folder);
+ if (r != MAILMBOX_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ r = mailmbox_fetch_msg_headers_no_lock(folder, num, &data, &len);
+ if (r != MAILMBOX_NO_ERROR) {
+ res = r;
+ goto unlock;
+ }
+
+#if 0
+ mmapstr = mmap_string_new_len(data, len);
+ if (mmapstr == NULL) {
+ res = MAILMBOX_ERROR_MEMORY;
+ goto unlock;
+ }
+#endif
+ /* size with no uid */
+ fixed_size = get_fixed_message_size(data, len, 0, 1 /* force no uid */);
+
+ mmapstr = mmap_string_sized_new(fixed_size);
+ if (mmapstr == NULL) {
+ res = MAILMBOX_ERROR_MEMORY;
+ goto unlock;
+ }
+
+ end = write_fixed_message(mmapstr->str, data, len, 0, 1 /* force no uid */);
+ * end = '\0';
+ mmapstr->len = fixed_size;
+
+ r = mmap_string_ref(mmapstr);
+ if (r < 0) {
+ mmap_string_free(mmapstr);
+ res = MAILMBOX_ERROR_MEMORY;
+ goto unlock;
+ }
+
+ * result = mmapstr->str;
+ * result_len = mmapstr->len;
+
+ mailmbox_read_unlock(folder);
+
+ return MAILMBOX_NO_ERROR;
+
+ unlock:
+ mailmbox_read_unlock(folder);
+ err:
+ return res;
+}
+
+void mailmbox_fetch_result_free(char * msg)
+{
+ mmap_string_unref(msg);
+}
+
+
+int mailmbox_copy_msg_list(struct mailmbox_folder * dest_folder,
+ struct mailmbox_folder * src_folder,
+ carray * tab)
+{
+ int r;
+ int res;
+ carray * append_tab;
+ unsigned int i;
+
+ r = mailmbox_validate_read_lock(src_folder);
+ if (r != MAILMBOX_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ append_tab = carray_new(carray_count(tab));
+ if (append_tab == NULL) {
+ res = MAILMBOX_ERROR_MEMORY;
+ goto src_unlock;
+ }
+
+ for(i = 0 ; i < carray_count(tab) ; i ++) {
+ struct mailmbox_append_info * append_info;
+ char * data;
+ size_t len;
+ uint32_t uid;
+
+ uid = * ((uint32_t *) carray_get(tab, i));
+
+ r = mailmbox_fetch_msg_no_lock(src_folder, uid, &data, &len);
+ if (r != MAILMBOX_NO_ERROR) {
+ res = r;
+ goto free_list;
+ }
+
+ append_info = mailmbox_append_info_new(data, len);
+ if (append_info == NULL) {
+ res = MAILMBOX_ERROR_MEMORY;
+ goto free_list;
+ }
+
+ r = carray_add(append_tab, append_info, NULL);
+ if (r < 0) {
+ mailmbox_append_info_free(append_info);
+ res = MAILMBOX_ERROR_MEMORY;
+ goto free_list;
+ }
+ }
+
+ r = mailmbox_append_message_list(dest_folder, append_tab);
+ if (r != MAILMBOX_NO_ERROR) {
+ res = r;
+ goto src_unlock;
+ }
+
+ for(i = 0 ; i < carray_count(append_tab) ; i ++) {
+ struct mailmbox_append_info * append_info;
+
+ append_info = carray_get(append_tab, i);
+ mailmbox_append_info_free(append_info);
+ }
+ carray_free(append_tab);
+
+ mailmbox_read_unlock(src_folder);
+
+ return MAILMBOX_NO_ERROR;
+
+ free_list:
+ for(i = 0 ; i < carray_count(append_tab) ; i ++) {
+ struct mailmbox_append_info * append_info;
+
+ append_info = carray_get(append_tab, i);
+ mailmbox_append_info_free(append_info);
+ }
+ carray_free(append_tab);
+ src_unlock:
+ mailmbox_read_unlock(src_folder);
+ err:
+ return res;
+}
+
+int mailmbox_copy_msg(struct mailmbox_folder * dest_folder,
+ struct mailmbox_folder * src_folder,
+ uint32_t uid)
+{
+ carray * tab;
+ int res;
+ uint32_t * puid;
+ int r;
+
+ tab = carray_new(1);
+ if (tab == NULL) {
+ res = MAILMBOX_ERROR_MEMORY;
+ goto err;
+ }
+
+ puid = malloc(sizeof(* puid));
+ if (puid == NULL) {
+ res = MAILMBOX_ERROR_MEMORY;
+ goto free_array;
+ }
+ * puid = uid;
+
+ r = mailmbox_copy_msg_list(dest_folder, src_folder, tab);
+ res = r;
+
+ free(puid);
+ free_array:
+ carray_free(tab);
+ err:
+ return res;
+}
+
+static int mailmbox_expunge_to_file_no_lock(char * dest_filename, int dest_fd,
+ struct mailmbox_folder * folder,
+ size_t * result_size)
+{
+ int r;
+ int res;
+ unsigned long i;
+ size_t cur_offset;
+ char * dest;
+ size_t size;
+
+ size = 0;
+ for(i = 0 ; i < carray_count(folder->mb_tab) ; i ++) {
+ struct mailmbox_msg_info * info;
+
+ info = carray_get(folder->mb_tab, i);
+
+ if (!info->msg_deleted) {
+ size += info->msg_size + info->msg_padding;
+
+ if (!folder->mb_no_uid) {
+ if (!info->msg_written_uid) {
+ uint32_t uid;
+
+ size += strlen(UID_HEADER " \r\n");
+
+ uid = info->msg_uid;
+ while (uid >= 10) {
+ uid /= 10;
+ size ++;
+ }
+ size ++;
+ }
+ }
+ }
+ }
+
+ r = ftruncate(dest_fd, size);
+ if (r < 0) {
+ res = MAILMBOX_ERROR_FILE;
+ goto err;
+ }
+
+ dest = (char *) mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, dest_fd, 0);
+ if (dest == MAP_FAILED) {
+ res = MAILMBOX_ERROR_FILE;
+ goto err;
+ }
+
+ cur_offset = 0;
+ for(i = 0 ; i < carray_count(folder->mb_tab) ; i ++) {
+ struct mailmbox_msg_info * info;
+
+ info = carray_get(folder->mb_tab, i);
+
+ if (!info->msg_deleted) {
+ memcpy(dest + cur_offset, folder->mb_mapping + info->msg_start,
+ info->msg_headers_len + info->msg_start_len);
+ cur_offset += info->msg_headers_len + info->msg_start_len;
+
+ if (!folder->mb_no_uid) {
+ if (!info->msg_written_uid) {
+ size_t numlen;
+
+ memcpy(dest + cur_offset, UID_HEADER " ", strlen(UID_HEADER " "));
+ cur_offset += strlen(UID_HEADER " ");
+ numlen = snprintf(dest + cur_offset, size - cur_offset,
+ "%i\r\n", info->msg_uid);
+ cur_offset += numlen;
+ }
+ }
+
+ memcpy(dest + cur_offset,
+ folder->mb_mapping + info->msg_headers + info->msg_headers_len,
+ info->msg_size - (info->msg_start_len + info->msg_headers_len)
+ + info->msg_padding);
+
+ cur_offset += info->msg_size -
+ (info->msg_start_len + info->msg_headers_len)
+ + info->msg_padding;
+ }
+ }
+ fflush(stdout);
+
+ msync(dest, size, MS_SYNC);
+ munmap(dest, size);
+
+ * result_size = size;
+
+ return MAILMBOX_NO_ERROR;
+
+ err:
+ return res;
+}
+
+static int copy_to_old_file(char * source_filename,
+ char * destination_filename, size_t size)
+{
+ int source_fd;
+ int dest_fd;
+ char * source;
+ char * dest;
+ int res;
+ int r;
+
+ source_fd = open(source_filename, O_RDONLY);
+ if (source_fd < 0) {
+ res = MAILMBOX_ERROR_FILE;
+ goto err;
+ }
+
+ source = (char *) mmap(0, size, PROT_READ, MAP_PRIVATE, source_fd, 0);
+ if (source == MAP_FAILED) {
+ res = MAILMBOX_ERROR_FILE;
+ goto close_source;
+ }
+
+ dest_fd = open(destination_filename, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
+ if (dest_fd < 0) {
+ res = MAILMBOX_ERROR_FILE;
+ goto unmap_source;
+ }
+
+ r = ftruncate(dest_fd, size);
+ if (r < 0) {
+ res = MAILMBOX_ERROR_FILE;
+ goto close_dest;
+ }
+
+ dest = (char *) mmap(0, size, PROT_READ | PROT_WRITE,
+ MAP_SHARED, dest_fd, 0);
+ if (dest == MAP_FAILED) {
+ res = MAILMBOX_ERROR_FILE;
+ goto close_dest;
+ }
+
+ memcpy(dest, source, size);
+
+ munmap(dest, size);
+ close(source_fd);
+ munmap(source, size);
+ close(source_fd);
+
+ return MAILMBOX_NO_ERROR;
+
+ unmap_dest:
+ munmap(dest, size);
+ close_dest:
+ close(source_fd);
+ unmap_source:
+ munmap(source, size);
+ close_source:
+ close(source_fd);
+ err:
+ return res;
+}
+
+int mailmbox_expunge_no_lock(struct mailmbox_folder * folder)
+{
+ char tmpfile[PATH_MAX];
+ int r;
+ int res;
+ int dest_fd;
+ size_t size;
+ mode_t old_mask;
+
+ if (folder->mb_read_only)
+ return MAILMBOX_ERROR_READONLY;
+
+ if (((folder->mb_written_uid >= folder->mb_max_uid) || folder->mb_no_uid) &&
+ (!folder->mb_changed)) {
+ /* no need to expunge */
+ return MAILMBOX_NO_ERROR;
+ }
+
+ snprintf(tmpfile, PATH_MAX, "%sXXXXXX", folder->mb_filename);
+ old_mask = umask(0077);
+ dest_fd = mkstemp(tmpfile);
+ umask(old_mask);
+
+ if (dest_fd < 0) {
+ /* fallback to tmp dir */
+
+ snprintf(tmpfile, PATH_MAX, TMPDIR "/etpan-unsafe-XXXXXX");
+
+ old_mask = umask(0077);
+ dest_fd = mkstemp(tmpfile);
+ umask(old_mask);
+
+ if (dest_fd < 0) {
+ res = MAILMBOX_ERROR_FILE;
+ goto err;
+ }
+ }
+
+ r = mailmbox_expunge_to_file_no_lock(tmpfile, dest_fd,
+ folder, &size);
+ if (r != MAILMBOX_NO_ERROR) {
+ res = r;
+ goto unlink;
+ }
+
+ close(dest_fd);
+
+ r = rename(tmpfile, folder->mb_filename);
+ if (r < 0) {
+ mailmbox_unmap(folder);
+ mailmbox_close(folder);
+
+ /* fallback on copy to old file */
+
+ r = copy_to_old_file(tmpfile, folder->mb_filename, size);
+ if (r != MAILMBOX_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ unlink(tmpfile);
+ }
+ else {
+ mailmbox_unmap(folder);
+ mailmbox_close(folder);
+ }
+
+ r = mailmbox_open(folder);
+ if (r != MAILMBOX_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ r = mailmbox_map(folder);
+ if (r != MAILMBOX_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ r = mailmbox_parse(folder);
+ if (r != MAILMBOX_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ mailmbox_timestamp(folder);
+
+ folder->mb_changed = FALSE;
+ folder->mb_deleted_count = 0;
+
+ return MAILMBOX_NO_ERROR;
+
+ unlink:
+ close(dest_fd);
+ unlink(tmpfile);
+ err:
+ return res;
+}
+
+int mailmbox_expunge(struct mailmbox_folder * folder)
+{
+ int r;
+ int res;
+
+ r = mailmbox_validate_write_lock(folder);
+ if (r != MAILMBOX_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ r = mailmbox_expunge_no_lock(folder);
+ res = r;
+
+ mailmbox_write_unlock(folder);
+ err:
+ return res;
+}
+
+int mailmbox_delete_msg(struct mailmbox_folder * folder, uint32_t uid)
+{
+ struct mailmbox_msg_info * info;
+ int res;
+ chashdatum key;
+ chashdatum data;
+ int r;
+
+ if (folder->mb_read_only) {
+ res = MAILMBOX_ERROR_READONLY;
+ goto err;
+ }
+
+ key.data = &uid;
+ key.len = sizeof(uid);
+
+ r = chash_get(folder->mb_hash, &key, &data);
+ if (r < 0) {
+ res = MAILMBOX_ERROR_MSG_NOT_FOUND;
+ goto err;
+ }
+
+ info = data.data;
+
+ if (info->msg_deleted) {
+ res = MAILMBOX_ERROR_MSG_NOT_FOUND;
+ goto err;
+ }
+
+ info->msg_deleted = TRUE;
+ folder->mb_changed = TRUE;
+ folder->mb_deleted_count ++;
+
+ return MAILMBOX_NO_ERROR;
+
+ err:
+ return res;
+}
+
+
+/*
+ INIT of MBOX
+
+ - open file
+ - map the file
+
+ - lock the file
+
+ - parse memory
+
+ - unlock the file
+*/
+
+int mailmbox_init(const char * filename,
+ int force_readonly,
+ int force_no_uid,
+ uint32_t default_written_uid,
+ struct mailmbox_folder ** result_folder)
+{
+ struct mailmbox_folder * folder;
+ int r;
+ int res;
+
+ folder = mailmbox_folder_new(filename);
+ if (folder == NULL) {
+ res = MAILMBOX_ERROR_MEMORY;
+ goto err;
+ }
+ folder->mb_no_uid = force_no_uid;
+ folder->mb_read_only = force_readonly;
+ folder->mb_written_uid = default_written_uid;
+
+ folder->mb_changed = FALSE;
+ folder->mb_deleted_count = 0;
+
+ r = mailmbox_open(folder);
+ if (r != MAILMBOX_NO_ERROR) {
+ res = r;
+ goto free;
+ }
+
+ r = mailmbox_map(folder);
+ if (r != MAILMBOX_NO_ERROR) {
+ res = r;
+ goto close;
+ }
+
+ r = mailmbox_validate_read_lock(folder);
+ if (r != MAILMBOX_NO_ERROR) {
+ res = r;
+ goto unmap;
+ }
+
+ mailmbox_read_unlock(folder);
+
+ * result_folder = folder;
+
+ return MAILMBOX_NO_ERROR;
+
+ unmap:
+ mailmbox_unmap(folder);
+ close:
+ mailmbox_close(folder);
+ free:
+ mailmbox_folder_free(folder);
+ err:
+ return res;
+}
+
+
+/*
+ when MBOX is DONE
+
+ - check for changes
+
+ - unmap the file
+ - close file
+*/
+
+void mailmbox_done(struct mailmbox_folder * folder)
+{
+ if (!folder->mb_read_only)
+ mailmbox_expunge(folder);
+
+ mailmbox_unmap(folder);
+ mailmbox_close(folder);
+
+ mailmbox_folder_free(folder);
+}
diff --git a/libetpan/src/low-level/mbox/mailmbox.h b/libetpan/src/low-level/mbox/mailmbox.h
new file mode 100644
index 0000000..ea21d48
--- a/dev/null
+++ b/libetpan/src/low-level/mbox/mailmbox.h
@@ -0,0 +1,144 @@
+/*
+ * 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$
+ */
+
+#ifndef MAILMBOX_H
+
+#define MAILMBOX_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <libetpan/mailmbox_types.h>
+
+int
+mailmbox_append_message_list(struct mailmbox_folder * folder,
+ carray * append_tab);
+
+int
+mailmbox_append_message(struct mailmbox_folder * folder,
+ const char * data, size_t len);
+
+int
+mailmbox_append_message_uid(struct mailmbox_folder * folder,
+ const char * data, size_t len, unsigned int * puid);
+
+int mailmbox_fetch_msg(struct mailmbox_folder * folder,
+ uint32_t num, char ** result,
+ size_t * result_len);
+
+int mailmbox_fetch_msg_headers(struct mailmbox_folder * folder,
+ uint32_t num, char ** result,
+ size_t * result_len);
+
+void mailmbox_fetch_result_free(char * msg);
+
+int mailmbox_copy_msg_list(struct mailmbox_folder * dest_folder,
+ struct mailmbox_folder * src_folder,
+ carray * tab);
+
+int mailmbox_copy_msg(struct mailmbox_folder * dest_folder,
+ struct mailmbox_folder * src_folder,
+ uint32_t uid);
+
+int mailmbox_expunge(struct mailmbox_folder * folder);
+
+int mailmbox_delete_msg(struct mailmbox_folder * folder, uint32_t uid);
+
+int mailmbox_init(const char * filename,
+ int force_readonly,
+ int force_no_uid,
+ uint32_t default_written_uid,
+ struct mailmbox_folder ** result_folder);
+
+void mailmbox_done(struct mailmbox_folder * folder);
+
+/* low-level access primitives */
+
+int mailmbox_write_lock(struct mailmbox_folder * folder);
+
+int mailmbox_write_unlock(struct mailmbox_folder * folder);
+
+int mailmbox_read_lock(struct mailmbox_folder * folder);
+
+int mailmbox_read_unlock(struct mailmbox_folder * folder);
+
+
+/* memory map */
+
+int mailmbox_map(struct mailmbox_folder * folder);
+
+void mailmbox_unmap(struct mailmbox_folder * folder);
+
+void mailmbox_sync(struct mailmbox_folder * folder);
+
+
+/* open & close file */
+
+int mailmbox_open(struct mailmbox_folder * folder);
+
+void mailmbox_close(struct mailmbox_folder * folder);
+
+
+/* validate cache */
+
+int mailmbox_validate_write_lock(struct mailmbox_folder * folder);
+
+int mailmbox_validate_read_lock(struct mailmbox_folder * folder);
+
+
+/* fetch message */
+
+int mailmbox_fetch_msg_no_lock(struct mailmbox_folder * folder,
+ uint32_t num, char ** result,
+ size_t * result_len);
+
+int mailmbox_fetch_msg_headers_no_lock(struct mailmbox_folder * folder,
+ uint32_t num, char ** result,
+ size_t * result_len);
+
+/* append message */
+
+int
+mailmbox_append_message_list_no_lock(struct mailmbox_folder * folder,
+ carray * append_tab);
+
+int mailmbox_expunge_no_lock(struct mailmbox_folder * folder);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libetpan/src/low-level/mbox/mailmbox_parse.c b/libetpan/src/low-level/mbox/mailmbox_parse.c
new file mode 100644
index 0000000..65642ac
--- a/dev/null
+++ b/libetpan/src/low-level/mbox/mailmbox_parse.c
@@ -0,0 +1,620 @@
+/*
+ * 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 "mailmbox_parse.h"
+
+#include "mailmbox.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <stdlib.h>
+
+#define UID_HEADER "X-LibEtPan-UID:"
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+enum {
+ UNSTRUCTURED_START,
+ UNSTRUCTURED_CR,
+ UNSTRUCTURED_LF,
+ UNSTRUCTURED_WSP,
+ UNSTRUCTURED_OUT
+};
+
+static inline int
+mailmbox_fields_parse(char * str, size_t length,
+ size_t * index,
+ uint32_t * puid,
+ size_t * phlen)
+{
+ size_t cur_token;
+ int r;
+ size_t hlen;
+ size_t uid;
+ int end;
+
+ cur_token = * index;
+
+ end = FALSE;
+ uid = 0;
+ while (!end) {
+ size_t begin;
+
+ begin = cur_token;
+
+ r = mailimf_ignore_field_parse(str, length, &cur_token);
+ switch (r) {
+ case MAILIMF_NO_ERROR:
+ if (str[begin] == 'X') {
+
+ if (strncasecmp(str + begin, UID_HEADER, strlen(UID_HEADER)) == 0) {
+ begin += strlen(UID_HEADER);
+
+ while (str[begin] == ' ')
+ begin ++;
+
+ uid = strtoul(str + begin, NULL, 10);
+ }
+ }
+
+ break;
+ case MAILIMF_ERROR_PARSE:
+ default:
+ end = TRUE;
+ break;
+ }
+ }
+
+ hlen = cur_token - * index;
+
+ * phlen = hlen;
+ * puid = uid;
+ * index = cur_token;
+
+ return MAILMBOX_NO_ERROR;
+}
+
+enum {
+ IN_MAIL,
+ FIRST_CR,
+ FIRST_LF,
+ SECOND_CR,
+ SECOND_LF,
+ PARSING_F,
+ PARSING_R,
+ PARSING_O,
+ PARSING_M,
+ OUT_MAIL
+};
+
+
+
+
+static inline int
+mailmbox_single_parse(char * str, size_t length,
+ size_t * index,
+ size_t * pstart,
+ size_t * pstart_len,
+ size_t * pheaders,
+ size_t * pheaders_len,
+ size_t * pbody,
+ size_t * pbody_len,
+ size_t * psize,
+ size_t * ppadding,
+ uint32_t * puid)
+{
+ size_t cur_token;
+ size_t start;
+ size_t start_len;
+ size_t headers;
+ size_t headers_len;
+ size_t body;
+ size_t end;
+ size_t next;
+ size_t message_length;
+ uint32_t uid;
+ int r;
+#if 0
+ int in_mail_data;
+#endif
+#if 0
+ size_t begin;
+#endif
+
+ int state;
+
+ cur_token = * index;
+
+ if (cur_token >= length)
+ return MAILMBOX_ERROR_PARSE;
+
+ start = cur_token;
+ start_len = 0;
+ headers = cur_token;
+
+ if (cur_token + 5 < length) {
+ if (strncmp(str + cur_token, "From ", 5) == 0) {
+ cur_token += 5;
+ while (str[cur_token] != '\n') {
+ cur_token ++;
+ if (cur_token >= length)
+ break;
+ }
+ if (cur_token < length) {
+ cur_token ++;
+ headers = cur_token;
+ start_len = headers - start;
+ }
+ }
+ }
+
+ next = length;
+
+ r = mailmbox_fields_parse(str, length, &cur_token,
+ &uid, &headers_len);
+ if (r != MAILMBOX_NO_ERROR)
+ return r;
+
+ /* save position */
+#if 0
+ begin = cur_token;
+#endif
+
+ mailimf_crlf_parse(str, length, &cur_token);
+
+#if 0
+ if (str[cur_token] == 'F') {
+ printf("start !\n");
+ printf("%50.50s\n", str + cur_token);
+ getchar();
+ }
+#endif
+
+ body = cur_token;
+
+ /* restore position */
+ /* cur_token = begin; */
+
+ state = FIRST_LF;
+
+ end = length;
+
+#if 0
+ in_mail_data = 0;
+#endif
+ while (state != OUT_MAIL) {
+
+ if (cur_token >= length) {
+ if (state == IN_MAIL)
+ end = length;
+ next = length;
+ break;
+ }
+
+ switch(state) {
+ case IN_MAIL:
+ switch(str[cur_token]) {
+ case '\r':
+ state = FIRST_CR;
+ break;
+ case '\n':
+ state = FIRST_LF;
+ break;
+ case 'F':
+ if (cur_token == body) {
+ end = cur_token;
+ next = cur_token;
+ state = PARSING_F;
+ }
+ break;
+#if 0
+ default:
+ in_mail_data = 1;
+ break;
+#endif
+ }
+ break;
+
+ case FIRST_CR:
+ end = cur_token;
+ switch(str[cur_token]) {
+ case '\r':
+ state = SECOND_CR;
+ break;
+ case '\n':
+ state = FIRST_LF;
+ break;
+ default:
+ state = IN_MAIL;
+#if 0
+ in_mail_data = 1;
+#endif
+ break;
+ }
+ break;
+
+ case FIRST_LF:
+ end = cur_token;
+ switch(str[cur_token]) {
+ case '\r':
+ state = SECOND_CR;
+ break;
+ case '\n':
+ state = SECOND_LF;
+ break;
+ default:
+ state = IN_MAIL;
+#if 0
+ in_mail_data = 1;
+#endif
+ break;
+ }
+ break;
+
+ case SECOND_CR:
+ switch(str[cur_token]) {
+ case '\r':
+ end = cur_token;
+ break;
+ case '\n':
+ state = SECOND_LF;
+ break;
+ case 'F':
+ next = cur_token;
+ state = PARSING_F;
+ break;
+ default:
+ state = IN_MAIL;
+#if 0
+ in_mail_data = 1;
+#endif
+ break;
+ }
+ break;
+
+ case SECOND_LF:
+ switch(str[cur_token]) {
+ case '\r':
+ state = SECOND_CR;
+ break;
+ case '\n':
+ end = cur_token;
+ break;
+ case 'F':
+ next = cur_token;
+ state = PARSING_F;
+ break;
+ default:
+ state = IN_MAIL;
+#if 0
+ in_mail_data = 1;
+#endif
+ break;
+ }
+ break;
+
+ case PARSING_F:
+ switch(str[cur_token]) {
+ case 'r':
+ state = PARSING_R;
+ break;
+ default:
+ state = IN_MAIL;
+#if 0
+ in_mail_data = 1;
+#endif
+ break;
+ }
+ break;
+
+ case PARSING_R:
+ switch(str[cur_token]) {
+ case 'o':
+ state = PARSING_O;
+ break;
+ default:
+ state = IN_MAIL;
+#if 0
+ in_mail_data = 1;
+#endif
+ break;
+ }
+ break;
+
+ case PARSING_O:
+ switch(str[cur_token]) {
+ case 'm':
+ state = PARSING_M;
+ break;
+ default:
+ state = IN_MAIL;
+#if 0
+ in_mail_data = 1;
+#endif
+ break;
+ }
+ break;
+
+ case PARSING_M:
+ switch(str[cur_token]) {
+ case ' ':
+ state = OUT_MAIL;
+ break;
+ default:
+ state = IN_MAIL;
+ break;
+ }
+ break;
+ }
+
+ cur_token ++;
+ }
+
+ message_length = end - start;
+
+ * pstart = start;
+ * pstart_len = start_len;
+ * pheaders = headers;
+ * pheaders_len = headers_len;
+ * pbody = body;
+ * pbody_len = end - body;
+ * psize = message_length;
+ * ppadding = next - end;
+ * puid = uid;
+
+ * index = next;
+
+ return MAILMBOX_NO_ERROR;
+}
+
+
+int
+mailmbox_parse_additionnal(struct mailmbox_folder * folder,
+ size_t * index)
+{
+ size_t cur_token;
+
+ size_t start;
+ size_t start_len;
+ size_t headers;
+ size_t headers_len;
+ size_t body;
+ size_t body_len;
+ size_t size;
+ size_t padding;
+ uint32_t uid;
+ int r;
+ int res;
+
+ uint32_t max_uid;
+ uint32_t first_index;
+ unsigned int i;
+ unsigned int j;
+
+ cur_token = * index;
+
+ /* remove temporary UID that we will parse */
+
+ first_index = carray_count(folder->mb_tab);
+
+ for(i = 0 ; i < carray_count(folder->mb_tab) ; i++) {
+ struct mailmbox_msg_info * info;
+
+ info = carray_get(folder->mb_tab, i);
+
+ if (info->msg_start < cur_token) {
+ continue;
+ }
+
+ if (!info->msg_written_uid) {
+ chashdatum key;
+
+ key.data = &info->msg_uid;
+ key.len = sizeof(info->msg_uid);
+
+ chash_delete(folder->mb_hash, &key, NULL);
+ carray_delete_fast(folder->mb_tab, i);
+ mailmbox_msg_info_free(info);
+ if (i < first_index)
+ first_index = i;
+ }
+ }
+
+ /* make a sequence in the table */
+
+ max_uid = folder->mb_written_uid;
+
+ i = 0;
+ j = 0;
+ while (i < carray_count(folder->mb_tab)) {
+ struct mailmbox_msg_info * info;
+
+ info = carray_get(folder->mb_tab, i);
+ if (info != NULL) {
+ carray_set(folder->mb_tab, j, info);
+
+ if (info->msg_uid > max_uid)
+ max_uid = info->msg_uid;
+
+ info->msg_index = j;
+ j ++;
+ }
+ i ++;
+ }
+ carray_set_size(folder->mb_tab, j);
+
+ /* parse content */
+
+ first_index = j;
+
+ while (1) {
+ struct mailmbox_msg_info * info;
+ chashdatum key;
+ chashdatum data;
+
+ r = mailmbox_single_parse(folder->mb_mapping, folder->mb_mapping_size,
+ &cur_token,
+ &start, &start_len,
+ &headers, &headers_len,
+ &body, &body_len,
+ &size, &padding, &uid);
+ if (r == MAILMBOX_NO_ERROR) {
+ /* do nothing */
+ }
+ else if (r == MAILMBOX_ERROR_PARSE)
+ break;
+ else {
+ res = r;
+ goto err;
+ }
+
+ key.data = &uid;
+ key.len = sizeof(uid);
+
+ r = chash_get(folder->mb_hash, &key, &data);
+ if (r == 0) {
+ info = data.data;
+
+ if (!info->msg_written_uid) {
+ /* some new mail has been written and override an
+ existing temporary UID */
+
+ chash_delete(folder->mb_hash, &key, NULL);
+ info->msg_uid = 0;
+
+ if (info->msg_index < first_index)
+ first_index = info->msg_index;
+ }
+ else
+ uid = 0;
+ }
+
+ if (uid > max_uid)
+ max_uid = uid;
+
+ r = mailmbox_msg_info_update(folder,
+ start, start_len, headers, headers_len,
+ body, body_len, size, padding, uid);
+ if (r != MAILMBOX_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+ }
+
+ * index = cur_token;
+
+ folder->mb_written_uid = max_uid;
+
+ /* attribute uid */
+
+ for(i = first_index ; i < carray_count(folder->mb_tab) ; i ++) {
+ struct mailmbox_msg_info * info;
+ chashdatum key;
+ chashdatum data;
+
+ info = carray_get(folder->mb_tab, i);
+
+ if (info->msg_uid != 0) {
+ continue;
+ }
+
+ max_uid ++;
+ info->msg_uid = max_uid;
+
+ key.data = &info->msg_uid;
+ key.len = sizeof(info->msg_uid);
+ data.data = info;
+ data.len = 0;
+
+ r = chash_set(folder->mb_hash, &key, &data, NULL);
+ if (r < 0) {
+ res = MAILMBOX_ERROR_MEMORY;
+ goto err;
+ }
+ }
+
+ folder->mb_max_uid = max_uid;
+
+ return MAILMBOX_NO_ERROR;
+
+ err:
+ return res;
+}
+
+static void flush_uid(struct mailmbox_folder * folder)
+{
+ unsigned int i;
+
+ for(i = 0 ; i < carray_count(folder->mb_tab) ; i++) {
+ struct mailmbox_msg_info * info;
+
+ info = carray_get(folder->mb_tab, i);
+ if (info != NULL)
+ mailmbox_msg_info_free(info);
+ }
+
+ chash_clear(folder->mb_hash);
+ carray_set_size(folder->mb_tab, 0);
+}
+
+int mailmbox_parse(struct mailmbox_folder * folder)
+{
+ int r;
+ int res;
+ size_t cur_token;
+
+ flush_uid(folder);
+
+ cur_token = 0;
+
+ r = mailmbox_parse_additionnal(folder, &cur_token);
+
+ if (r != MAILMBOX_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ return MAILMBOX_NO_ERROR;
+
+ err:
+ return res;
+}
diff --git a/libetpan/src/low-level/mbox/mailmbox_parse.h b/libetpan/src/low-level/mbox/mailmbox_parse.h
new file mode 100644
index 0000000..6b533a9
--- a/dev/null
+++ b/libetpan/src/low-level/mbox/mailmbox_parse.h
@@ -0,0 +1,56 @@
+/*
+ * 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$
+ */
+
+#ifndef MAILMBOX_PARSE_H
+
+#define MAILMBOX_PARSE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "mailmbox_types.h"
+
+int mailmbox_parse(struct mailmbox_folder * folder);
+
+int
+mailmbox_parse_additionnal(struct mailmbox_folder * folder,
+ size_t * index);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libetpan/src/low-level/mbox/mailmbox_types.c b/libetpan/src/low-level/mbox/mailmbox_types.c
new file mode 100644
index 0000000..aaf76dc
--- a/dev/null
+++ b/libetpan/src/low-level/mbox/mailmbox_types.c
@@ -0,0 +1,251 @@
+/*
+ * 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 "mailmbox_types.h"
+
+#include <string.h>
+#include <stdlib.h>
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+/* *********************************************************************** */
+
+int mailmbox_msg_info_update(struct mailmbox_folder * folder,
+ size_t msg_start, size_t msg_start_len,
+ size_t msg_headers, size_t msg_headers_len,
+ size_t msg_body, size_t msg_body_len,
+ size_t msg_size, size_t msg_padding,
+ uint32_t msg_uid)
+{
+ struct mailmbox_msg_info * info;
+ int res;
+ chashdatum key;
+ chashdatum data;
+ int r;
+
+ key.data = &msg_uid;
+ key.len = sizeof(msg_uid);
+ r = chash_get(folder->mb_hash, &key, &data);
+ if (r < 0) {
+ unsigned int index;
+
+ info = mailmbox_msg_info_new(msg_start, msg_start_len,
+ msg_headers, msg_headers_len,
+ msg_body, msg_body_len, msg_size, msg_padding, msg_uid);
+ if (info == NULL) {
+ res = MAILMBOX_ERROR_MEMORY;
+ goto err;
+ }
+
+ r = carray_add(folder->mb_tab, info, &index);
+ if (r < 0) {
+ mailmbox_msg_info_free(info);
+ res = MAILMBOX_ERROR_MEMORY;
+ goto err;
+ }
+
+ if (msg_uid != 0) {
+ chashdatum key;
+ chashdatum data;
+
+ key.data = &msg_uid;
+ key.len = sizeof(msg_uid);
+ data.data = info;
+ data.len = 0;
+
+ r = chash_set(folder->mb_hash, &key, &data, NULL);
+ if (r < 0) {
+ mailmbox_msg_info_free(info);
+ carray_delete(folder->mb_tab, index);
+ res = MAILMBOX_ERROR_MEMORY;
+ goto err;
+ }
+ }
+
+ info->msg_index = index;
+ }
+ else {
+ info = data.data;
+
+ info->msg_start = msg_start;
+ info->msg_start_len = msg_start_len;
+ info->msg_headers = msg_headers;
+ info->msg_headers_len = msg_headers_len;
+ info->msg_body = msg_body;
+ info->msg_body_len = msg_body_len;
+ info->msg_size = msg_size;
+ info->msg_padding = msg_padding;
+ }
+
+ return MAILMBOX_NO_ERROR;
+
+ err:
+ return res;
+}
+
+
+struct mailmbox_msg_info *
+mailmbox_msg_info_new(size_t msg_start, size_t msg_start_len,
+ size_t msg_headers, size_t msg_headers_len,
+ size_t msg_body, size_t msg_body_len,
+ size_t msg_size, size_t msg_padding,
+ uint32_t msg_uid)
+{
+ struct mailmbox_msg_info * info;
+
+ info = malloc(sizeof(* info));
+ if (info == NULL)
+ return NULL;
+
+ info->msg_index = 0;
+ info->msg_uid = msg_uid;
+ if (msg_uid != 0)
+ info->msg_written_uid = TRUE;
+ else
+ info->msg_written_uid = FALSE;
+ info->msg_deleted = FALSE;
+
+ info->msg_start = msg_start;
+ info->msg_start_len = msg_start_len;
+
+ info->msg_headers = msg_headers;
+ info->msg_headers_len = msg_headers_len;
+
+ info->msg_body = msg_body;
+ info->msg_body_len = msg_body_len;
+
+ info->msg_size = msg_size;
+
+ info->msg_padding = msg_padding;
+
+ return info;
+}
+
+void mailmbox_msg_info_free(struct mailmbox_msg_info * info)
+{
+ free(info);
+}
+
+
+/* append info */
+
+struct mailmbox_append_info *
+mailmbox_append_info_new(const char * ai_message, size_t ai_size)
+{
+ struct mailmbox_append_info * info;
+
+ info = malloc(sizeof(* info));
+ if (info == NULL)
+ return NULL;
+
+ info->ai_message = ai_message;
+ info->ai_size = ai_size;
+ info->ai_uid = 0;
+
+ return info;
+}
+
+void mailmbox_append_info_free(struct mailmbox_append_info * info)
+{
+ free(info);
+}
+
+struct mailmbox_folder * mailmbox_folder_new(const char * mb_filename)
+{
+ struct mailmbox_folder * folder;
+
+ folder = malloc(sizeof(* folder));
+ if (folder == NULL)
+ goto err;
+
+ strncpy(folder->mb_filename, mb_filename, PATH_MAX);
+
+ folder->mb_mtime = (time_t) -1;
+
+ folder->mb_fd = -1;
+ folder->mb_read_only = TRUE;
+ folder->mb_no_uid = TRUE;
+
+ folder->mb_changed = FALSE;
+ folder->mb_deleted_count = 0;
+
+ folder->mb_mapping = NULL;
+ folder->mb_mapping_size = 0;
+
+ folder->mb_written_uid = 0;
+ folder->mb_max_uid = 0;
+
+ folder->mb_hash = chash_new(CHASH_DEFAULTSIZE, CHASH_COPYKEY);
+ if (folder->mb_hash == NULL)
+ goto free;
+
+ folder->mb_tab = carray_new(128);
+ if (folder->mb_tab == NULL)
+ goto free_hash;
+
+ return folder;
+
+ free_hash:
+ chash_free(folder->mb_hash);
+ free:
+ free(folder);
+ err:
+ return NULL;
+}
+
+void mailmbox_folder_free(struct mailmbox_folder * folder)
+{
+ unsigned int i;
+
+ for(i = 0 ; i < carray_count(folder->mb_tab) ; i++) {
+ struct mailmbox_msg_info * info;
+
+ info = carray_get(folder->mb_tab, i);
+ if (info != NULL)
+ mailmbox_msg_info_free(info);
+ }
+
+ carray_free(folder->mb_tab);
+
+ chash_free(folder->mb_hash);
+
+ free(folder);
+}
diff --git a/libetpan/src/low-level/mbox/mailmbox_types.h b/libetpan/src/low-level/mbox/mailmbox_types.h
new file mode 100644
index 0000000..4ce241d
--- a/dev/null
+++ b/libetpan/src/low-level/mbox/mailmbox_types.h
@@ -0,0 +1,143 @@
+/*
+ * 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$
+ */
+
+#ifndef MAILMBOX_TYPES_H
+
+#define MAILMBOX_TYPES_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <sys/types.h>
+
+#include <libetpan/libetpan-config.h>
+
+#include <libetpan/mailimf.h>
+#include <libetpan/carray.h>
+#include <libetpan/chash.h>
+
+enum {
+ MAILMBOX_NO_ERROR = 0,
+ MAILMBOX_ERROR_PARSE,
+ MAILMBOX_ERROR_INVAL,
+ MAILMBOX_ERROR_FILE_NOT_FOUND,
+ MAILMBOX_ERROR_MEMORY,
+ MAILMBOX_ERROR_TEMPORARY_FILE,
+ MAILMBOX_ERROR_FILE,
+ MAILMBOX_ERROR_MSG_NOT_FOUND,
+ MAILMBOX_ERROR_READONLY,
+};
+
+
+struct mailmbox_folder {
+ char mb_filename[PATH_MAX];
+
+ time_t mb_mtime;
+
+ int mb_fd;
+ int mb_read_only;
+ int mb_no_uid;
+
+ int mb_changed;
+ unsigned int mb_deleted_count;
+
+ char * mb_mapping;
+ size_t mb_mapping_size;
+
+ uint32_t mb_written_uid;
+ uint32_t mb_max_uid;
+
+ chash * mb_hash;
+ carray * mb_tab;
+};
+
+struct mailmbox_folder * mailmbox_folder_new(const char * mb_filename);
+void mailmbox_folder_free(struct mailmbox_folder * folder);
+
+
+struct mailmbox_msg_info {
+ unsigned int msg_index;
+ uint32_t msg_uid;
+ int msg_written_uid;
+ int msg_deleted;
+
+ size_t msg_start;
+ size_t msg_start_len;
+
+ size_t msg_headers;
+ size_t msg_headers_len;
+
+ size_t msg_body;
+ size_t msg_body_len;
+
+ size_t msg_size;
+
+ size_t msg_padding;
+};
+
+
+int mailmbox_msg_info_update(struct mailmbox_folder * folder,
+ size_t msg_start, size_t msg_start_len,
+ size_t msg_headers, size_t msg_headers_len,
+ size_t msg_body, size_t msg_body_len,
+ size_t msg_size, size_t msg_padding,
+ uint32_t msg_uid);
+
+struct mailmbox_msg_info *
+mailmbox_msg_info_new(size_t msg_start, size_t msg_start_len,
+ size_t msg_headers, size_t msg_headers_len,
+ size_t msg_body, size_t msg_body_len,
+ size_t msg_size, size_t msg_padding,
+ uint32_t msg_uid);
+
+void mailmbox_msg_info_free(struct mailmbox_msg_info * info);
+
+struct mailmbox_append_info {
+ const char * ai_message;
+ size_t ai_size;
+ unsigned int ai_uid;
+};
+
+struct mailmbox_append_info *
+mailmbox_append_info_new(const char * ai_message, size_t ai_size);
+
+void mailmbox_append_info_free(struct mailmbox_append_info * info);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libetpan/src/low-level/mh/mailmh.c b/libetpan/src/low-level/mh/mailmh.c
new file mode 100644
index 0000000..42cab9d
--- a/dev/null
+++ b/libetpan/src/low-level/mh/mailmh.c
@@ -0,0 +1,989 @@
+/*
+ * 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 "mailmh.h"
+
+/*
+perfs :
+
+/net/home/dinh/Mail/inbox/sylpheed 686
+
+2724 /net/home/dinh/Mail/inbox/sylpheed
+
+bart:~/LibEtPan/libetpan/tests> time ./mhtest >/dev/null
+
+real 0m0.385s
+user 0m0.270s
+sys 0m0.110s
+
+*/
+
+#include <dirent.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "libetpan-config.h"
+
+struct mailmh * mailmh_new(const char * foldername)
+{
+ struct mailmh * f;
+
+ f = malloc(sizeof(*f));
+ if (f == NULL)
+ return NULL;
+
+ f->mh_main = mailmh_folder_new(NULL, foldername);
+ if (f->mh_main == NULL) {
+ free(f);
+ return NULL;
+ }
+
+ return f;
+}
+
+void mailmh_free(struct mailmh * f)
+{
+ mailmh_folder_free(f->mh_main);
+ free(f);
+}
+
+
+
+struct mailmh_msg_info * mailmh_msg_info_new(uint32_t index, size_t size,
+ time_t mtime)
+{
+ struct mailmh_msg_info * msg_info;
+
+ msg_info = malloc(sizeof(* msg_info));
+ if (msg_info == NULL)
+ return NULL;
+ msg_info->msg_index = index;
+ msg_info->msg_size = size;
+ msg_info->msg_mtime = mtime;
+
+ msg_info->msg_array_index = 0;
+
+ return msg_info;
+}
+
+void mailmh_msg_info_free(struct mailmh_msg_info * msg_info)
+{
+ free(msg_info);
+}
+
+struct mailmh_folder * mailmh_folder_new(struct mailmh_folder * parent,
+ const char * name)
+{
+ char * filename;
+ char * parent_filename;
+
+ struct mailmh_folder * folder;
+
+ folder = malloc(sizeof(* folder));
+ if (folder == NULL)
+ goto err;
+
+ if (parent == NULL) {
+ filename = strdup(name);
+ if (filename == NULL)
+ goto free_folder;
+ }
+ else {
+ parent_filename = parent->fl_filename;
+ filename = malloc(strlen(parent_filename) + strlen(name) + 2);
+ if (filename == NULL)
+ goto free_folder;
+
+ strcpy(filename, parent_filename);
+ strcat(filename, MAIL_DIR_SEPARATOR_S);
+ strcat(filename, name);
+ }
+
+ folder->fl_filename = filename;
+
+ folder->fl_name = strdup(name);
+ if (folder->fl_name == NULL)
+ goto free_filename;
+
+ folder->fl_msgs_tab = carray_new(128);
+ if (folder->fl_msgs_tab == NULL)
+ goto free_name;
+
+#if 0
+ folder->fl_msgs_hash = cinthash_new(128);
+ if (folder->fl_msgs_hash == NULL)
+ goto free_msgs_tab;
+#endif
+ folder->fl_msgs_hash = chash_new(CHASH_DEFAULTSIZE, CHASH_COPYKEY);
+ if (folder->fl_msgs_hash == NULL)
+ goto free_msgs_tab;
+
+ folder->fl_subfolders_tab = carray_new(128);
+ if (folder->fl_subfolders_tab == NULL)
+ goto free_msgs_hash;
+
+ folder->fl_subfolders_hash = chash_new(128, CHASH_COPYNONE);
+ if (folder->fl_subfolders_hash == NULL)
+ goto free_subfolders_tab;
+
+ folder->fl_mtime = 0;
+ folder->fl_parent = parent;
+ folder->fl_max_index = 0;
+
+ return folder;
+
+ free_subfolders_tab:
+ carray_free(folder->fl_subfolders_tab);
+ free_msgs_hash:
+#if 0
+ cinthash_free(folder->fl_msgs_hash);
+#endif
+ chash_free(folder->fl_msgs_hash);
+ free_msgs_tab:
+ carray_free(folder->fl_msgs_tab);
+ free_name:
+ free(folder->fl_name);
+ free_filename:
+ free(folder->fl_filename);
+ free_folder:
+ free(folder);
+ err:
+ return NULL;
+}
+
+void mailmh_folder_free(struct mailmh_folder * folder)
+{
+ unsigned int i;
+
+ for(i = 0 ; i < carray_count(folder->fl_subfolders_tab) ; i++) {
+ struct mailmh_folder * subfolder;
+
+ subfolder = carray_get(folder->fl_subfolders_tab, i);
+ if (subfolder != NULL)
+ mailmh_folder_free(subfolder);
+ }
+ carray_free(folder->fl_subfolders_tab);
+ chash_free(folder->fl_subfolders_hash);
+
+ for(i = 0 ; i < carray_count(folder->fl_msgs_tab) ; i++) {
+ struct mailmh_msg_info * msg_info;
+
+ msg_info = carray_get(folder->fl_msgs_tab, i);
+ if (msg_info != NULL)
+ mailmh_msg_info_free(msg_info);
+ }
+ carray_free(folder->fl_msgs_tab);
+ chash_free(folder->fl_msgs_hash);
+#if 0
+ cinthash_free(folder->fl_msgs_hash);
+#endif
+
+ free(folder->fl_filename);
+ free(folder->fl_name);
+
+ free(folder);
+}
+
+struct mailmh_folder * mailmh_folder_find(struct mailmh_folder * root,
+ const char * filename)
+{
+ int r;
+ char pathname[PATH_MAX];
+ char * p;
+ chashdatum key;
+ chashdatum data;
+ struct mailmh_folder * folder;
+ char * start;
+
+ if (strcmp(root->fl_filename, filename) == 0)
+ return root;
+
+#if 0
+ r = mailmh_folder_update(root);
+ if (r != MAILMH_NO_ERROR)
+ return NULL;
+#endif
+
+#if 0
+ for(i = 0 ; i < root->fl_subfolders_tab->len ; i++) {
+ struct mailmh_folder * subfolder;
+
+ subfolder = carray_get(root->fl_subfolders_tab, i);
+ if (subfolder != NULL)
+ if (strncmp(subfolder->fl_filename, filename,
+ strlen(subfolder->fl_filename)) == 0)
+ return mailmh_folder_find(subfolder, filename);
+ }
+#endif
+ strncpy(pathname, filename, PATH_MAX);
+ pathname[PATH_MAX - 1] = 0;
+ start = pathname + strlen(root->fl_filename) + 1;
+
+ p = strchr(start, MAIL_DIR_SEPARATOR);
+ if (p != NULL) {
+ * p = 0;
+
+ root = mailmh_folder_find(root, pathname);
+ if (root != NULL) {
+ folder = mailmh_folder_find(root, filename);
+ if (folder == NULL)
+ return NULL;
+ return folder;
+ }
+
+ return NULL;
+ }
+ else {
+ key.data = pathname;
+ key.len = strlen(pathname);
+ r = chash_get(root->fl_subfolders_hash, &key, &data);
+ if (r < 0)
+ return NULL;
+
+ return data.data;
+ }
+}
+
+int mailmh_folder_update(struct mailmh_folder * folder)
+{
+ DIR * d;
+ struct dirent * ent;
+ struct stat buf;
+ char * mh_seq;
+ char filename[PATH_MAX];
+ int res;
+ int r;
+ uint32_t max_index;
+#if 0
+ int add_folder;
+#endif
+ unsigned int i;
+
+ if (stat(folder->fl_filename, &buf) == -1) {
+ res = MAILMH_ERROR_FOLDER;
+ goto err;
+ }
+
+ if (folder->fl_mtime == buf.st_mtime) {
+ res = MAILMH_NO_ERROR;
+ goto err;
+ }
+
+ folder->fl_mtime = buf.st_mtime;
+
+ d = opendir(folder->fl_filename);
+ if (d == NULL) {
+ res = MAILMH_ERROR_FOLDER;
+ goto err;
+ }
+
+ max_index = 0;
+
+#if 0
+ if (folder->fl_subfolders_tab->len == 0)
+ add_folder = 1;
+ else
+ add_folder = 0;
+#endif
+
+ /* clear the message list */
+
+ for(i = 0 ; i < carray_count(folder->fl_msgs_tab) ; i ++) {
+ struct mailmh_msg_info * msg_info;
+ chashdatum key;
+
+ msg_info = carray_get(folder->fl_msgs_tab, i);
+ if (msg_info == NULL)
+ continue;
+
+#if 0
+ cinthash_remove(folder->fl_msgs_hash, msg_info->msg_index);
+#endif
+ key.data = &msg_info->msg_index;
+ key.len = sizeof(msg_info->msg_index);
+ chash_delete(folder->fl_msgs_hash, &key, NULL);
+
+ mailmh_msg_info_free(msg_info);
+ }
+
+ carray_set_size(folder->fl_msgs_tab, 0);
+
+ do {
+ uint32_t index;
+
+ ent = readdir(d);
+
+ if (ent != NULL) {
+
+ snprintf(filename, PATH_MAX,
+ "%s%c%s", folder->fl_filename, MAIL_DIR_SEPARATOR, ent->d_name);
+
+ if (stat(filename, &buf) == -1)
+ continue;
+
+ if (S_ISREG(buf.st_mode)) {
+ index = strtoul(ent->d_name, NULL, 10);
+ if (index != 0) {
+ struct mailmh_msg_info * msg_info;
+ unsigned int array_index;
+ chashdatum key;
+ chashdatum data;
+
+ msg_info = mailmh_msg_info_new(index, buf.st_size, buf.st_mtime);
+ if (msg_info == NULL) {
+ res = MAILMH_ERROR_MEMORY;
+ goto closedir;
+ }
+
+ r = carray_add(folder->fl_msgs_tab, msg_info, &array_index);
+ if (r < 0) {
+ mailmh_msg_info_free(msg_info);
+ res = MAILMH_ERROR_MEMORY;
+ goto closedir;
+ }
+ msg_info->msg_array_index = array_index;
+
+ if (index > max_index)
+ max_index = index;
+
+#if 0
+ r = cinthash_add(folder->fl_msgs_hash, msg_info->msg_index, msg_info);
+#endif
+ key.data = &msg_info->msg_index;
+ key.len = sizeof(msg_info->msg_index);
+ data.data = msg_info;
+ data.len = 0;
+
+ r = chash_set(folder->fl_msgs_hash, &key, &data, NULL);
+ if (r < 0) {
+ carray_delete_fast(folder->fl_msgs_tab, msg_info->msg_array_index);
+ mailmh_msg_info_free(msg_info);
+ res = MAILMH_ERROR_MEMORY;
+ goto closedir;
+ }
+ }
+ }
+ else if (S_ISDIR(buf.st_mode)) {
+ struct mailmh_folder * subfolder;
+ unsigned int array_index;
+ chashdatum key;
+ chashdatum data;
+
+ if (ent->d_name[0] == '.') {
+ if (ent->d_name[1] == 0)
+ continue;
+ if ((ent->d_name[1] == '.') && (ent->d_name[2] == 0))
+ continue;
+ }
+
+ key.data = ent->d_name;
+ key.len = strlen(ent->d_name);
+ r = chash_get(folder->fl_subfolders_hash, &key, &data);
+ if (r < 0) {
+ subfolder = mailmh_folder_new(folder, ent->d_name);
+ if (subfolder == NULL) {
+ res = MAILMH_ERROR_MEMORY;
+ goto closedir;
+ }
+
+ r = carray_add(folder->fl_subfolders_tab, subfolder, &array_index);
+ if (r < 0) {
+ mailmh_folder_free(subfolder);
+ res = MAILMH_ERROR_MEMORY;
+ goto closedir;
+ }
+ subfolder->fl_array_index = array_index;
+
+ key.data = subfolder->fl_filename;
+ key.len = strlen(subfolder->fl_filename);
+ data.data = subfolder;
+ data.len = 0;
+ r = chash_set(folder->fl_subfolders_hash, &key, &data, NULL);
+ if (r < 0) {
+ carray_delete_fast(folder->fl_subfolders_tab, subfolder->fl_array_index);
+ mailmh_folder_free(subfolder);
+ res = MAILMH_ERROR_MEMORY;
+ goto closedir;
+ }
+ }
+ }
+ }
+ }
+ while (ent != NULL);
+
+ folder->fl_max_index = max_index;
+
+ mh_seq = malloc(strlen(folder->fl_filename) + 2 + sizeof(".mh_sequences"));
+ if (mh_seq == NULL) {
+ res = MAILMH_ERROR_MEMORY;
+ goto closedir;
+ }
+ strcpy(mh_seq, folder->fl_filename);
+ strcat(mh_seq, MAIL_DIR_SEPARATOR_S);
+ strcat(mh_seq, ".mh_sequences");
+
+ if (stat(mh_seq, &buf) == -1) {
+ int fd;
+
+ fd = creat(mh_seq, S_IRUSR | S_IWUSR);
+ if (fd != -1)
+ close(fd);
+ }
+ free(mh_seq);
+
+ closedir(d);
+
+ return MAILMH_NO_ERROR;
+
+ closedir:
+ closedir(d);
+ err:
+ return res;
+}
+
+int mailmh_folder_add_subfolder(struct mailmh_folder * parent,
+ const char * name)
+{
+ char * foldername;
+ int r;
+ struct mailmh_folder * folder;
+ unsigned int array_index;
+ chashdatum key;
+ chashdatum data;
+
+ foldername = malloc(strlen(parent->fl_filename) + strlen(name) + 2);
+ if (foldername == NULL)
+ return MAILMH_ERROR_MEMORY;
+ strcpy(foldername, parent->fl_filename);
+ strcat(foldername, MAIL_DIR_SEPARATOR_S);
+ strcat(foldername, name);
+
+ r = mkdir(foldername, 0700);
+ free(foldername);
+
+ if (r < 0)
+ return MAILMH_ERROR_FOLDER;
+
+ folder = mailmh_folder_new(parent, name);
+ if (folder == NULL)
+ return MAILMH_ERROR_MEMORY;
+
+ r = carray_add(parent->fl_subfolders_tab, folder, &array_index);
+ if (r < 0) {
+ mailmh_folder_free(folder);
+ return MAILMH_ERROR_MEMORY;
+ }
+ folder->fl_array_index = array_index;
+
+ key.data = folder->fl_filename;
+ key.len = strlen(folder->fl_filename);
+ data.data = folder;
+ data.len = 0;
+
+ r = chash_set(parent->fl_subfolders_hash, &key, &data, NULL);
+ if (r < 0) {
+ carray_delete_fast(folder->fl_subfolders_tab, folder->fl_array_index);
+ mailmh_folder_free(folder);
+ return MAILMH_ERROR_MEMORY;
+ }
+
+ return MAILMH_NO_ERROR;
+}
+
+int mailmh_folder_remove_subfolder(struct mailmh_folder * folder)
+{
+ struct mailmh_folder * parent;
+ chashdatum key;
+ chashdatum data;
+ int r;
+
+ parent = folder->fl_parent;
+
+ key.data = folder->fl_filename;
+ key.len = strlen(folder->fl_filename);
+
+ r = chash_get(parent->fl_subfolders_hash, &key, &data);
+ if (r < 0)
+ return MAILMH_ERROR_FOLDER;
+
+ chash_delete(parent->fl_subfolders_hash, &key, NULL);
+ carray_delete_fast(parent->fl_subfolders_tab, folder->fl_array_index);
+
+ mailmh_folder_free(folder);
+
+ return MAILMH_NO_ERROR;
+
+}
+
+int mailmh_folder_rename_subfolder(struct mailmh_folder * src_folder,
+ struct mailmh_folder * dst_folder,
+ const char * new_name)
+{
+ int r;
+ struct mailmh_folder * folder;
+ struct mailmh_folder * parent;
+ char * new_foldername;
+
+ parent = src_folder->fl_parent;
+ if (parent == NULL)
+ return MAILMH_ERROR_RENAME;
+
+ new_foldername = malloc(strlen(dst_folder->fl_filename) + 2 + strlen(new_name));
+ if (new_foldername == NULL)
+ return MAILMH_ERROR_MEMORY;
+
+ strcpy(new_foldername, dst_folder->fl_filename);
+ strcat(new_foldername, MAIL_DIR_SEPARATOR_S);
+ strcat(new_foldername, new_name);
+
+ r = rename(src_folder->fl_filename, new_foldername);
+ free(new_foldername);
+ if (r < 0)
+ return MAILMH_ERROR_RENAME;
+
+ r = mailmh_folder_remove_subfolder(src_folder);
+ if (r != MAILMH_NO_ERROR)
+ return r;
+
+ folder = mailmh_folder_new(dst_folder, new_name);
+ if (folder == NULL)
+ return MAILMH_ERROR_MEMORY;
+
+ r = carray_add(parent->fl_subfolders_tab, folder, NULL);
+ if (r < 0) {
+ mailmh_folder_free(folder);
+ return MAILMH_ERROR_MEMORY;
+ }
+
+ return MAILMH_NO_ERROR;
+}
+
+#define MAX_TRY_ALLOC 32
+
+/* initial file MUST be in the same directory */
+
+static int mailmh_folder_alloc_msg(struct mailmh_folder * folder,
+ char * filename, uint32_t * result)
+{
+ uint32_t max;
+ uint32_t k;
+ char * new_filename;
+ size_t len;
+ int got_file;
+ int r;
+
+ len = strlen(folder->fl_filename) + 20;
+ new_filename = malloc(len);
+ if (new_filename == NULL)
+ return MAILMH_ERROR_MEMORY;
+
+ max = folder->fl_max_index + 1;
+
+ got_file = 0;
+ k = 0;
+ while (k < MAX_TRY_ALLOC) {
+ snprintf(new_filename, len, "%s%c%lu", folder->fl_filename,
+ MAIL_DIR_SEPARATOR, (unsigned long) (max + k));
+
+ if (link(filename, new_filename) == 0) {
+ unlink(filename);
+ }
+ else if (errno == EXDEV) {
+ free(filename);
+ return MAILMH_ERROR_FOLDER;
+ }
+ else if (errno == EPERM) {
+ rename(filename, new_filename);
+ got_file = 1;
+ }
+
+ if (got_file) {
+ free(new_filename);
+
+ if (k > MAX_TRY_ALLOC / 2) {
+ r = mailmh_folder_update(folder);
+ /* ignore errors */
+ }
+
+ * result = max + k;
+
+ folder->fl_max_index = max + k;
+
+ return MAILMH_NO_ERROR;
+ }
+ k ++;
+ }
+
+ free(new_filename);
+
+ return MAILMH_ERROR_FOLDER;
+}
+
+int mailmh_folder_get_message_filename(struct mailmh_folder * folder,
+ uint32_t index, char ** result)
+{
+ char * filename;
+ int len;
+
+#if 0
+ r = mailmh_folder_update(folder);
+ if (r != MAILMH_NO_ERROR)
+ return r;
+#endif
+
+ len = strlen(folder->fl_filename) + 20;
+ filename = malloc(len);
+ if (filename == NULL)
+ return MAILMH_ERROR_MEMORY;
+
+ snprintf(filename, len, "%s%c%lu", folder->fl_filename, MAIL_DIR_SEPARATOR,
+ (unsigned long) index);
+
+ * result = filename;
+
+ return MAILMH_NO_ERROR;;
+}
+
+
+int mailmh_folder_get_message_fd(struct mailmh_folder * folder,
+ uint32_t index, int flags, int * result)
+{
+ char * filename;
+ int fd;
+ int r;
+
+#if 0
+ r = mailmh_folder_update(folder);
+ if (r != MAILMH_NO_ERROR)
+ return r;
+#endif
+
+ r = mailmh_folder_get_message_filename(folder, index, &filename);
+ if (r != MAILMH_NO_ERROR)
+ return r;
+
+ fd = open(filename, flags);
+ free(filename);
+ if (fd == -1)
+ return MAILMH_ERROR_MSG_NOT_FOUND;
+
+ * result = fd;
+
+ return MAILMH_NO_ERROR;
+}
+
+int mailmh_folder_get_message_size(struct mailmh_folder * folder,
+ uint32_t index, size_t * result)
+{
+ int r;
+ char * filename;
+ struct stat buf;
+
+ r = mailmh_folder_get_message_filename(folder, index, &filename);
+ if (r != MAILMH_NO_ERROR)
+ return r;
+
+ r = stat(filename, &buf);
+ free(filename);
+ if (r < 0)
+ return MAILMH_ERROR_FILE;
+
+ * result = buf.st_size;
+
+ return MAILMH_NO_ERROR;
+}
+
+int mailmh_folder_add_message_uid(struct mailmh_folder * folder,
+ const char * message, size_t size,
+ uint32_t * pindex)
+{
+ char * tmpname;
+ int fd;
+ size_t namesize;
+ size_t left;
+ ssize_t res;
+ struct mailmh_msg_info * msg_info;
+ uint32_t index;
+ int error;
+ int r;
+ unsigned int array_index;
+ struct stat buf;
+ chashdatum key;
+ chashdatum data;
+
+#if 0
+ r = mailmh_folder_update(folder);
+ if (r != MAILMH_NO_ERROR) {
+ error = r;
+ goto err;
+ }
+#endif
+
+ namesize = strlen(folder->fl_filename) + 20;
+ tmpname = malloc(namesize);
+ snprintf(tmpname, namesize, "%s%ctmpXXXXXX",
+ folder->fl_filename, MAIL_DIR_SEPARATOR);
+ fd = mkstemp(tmpname);
+ if (fd < 0) {
+ error = MAILMH_ERROR_FILE;
+ goto free;
+ }
+
+ left = size;
+ while (left > 0) {
+ res = write(fd, message, left);
+ if (res == -1) {
+ close(fd);
+ error = MAILMH_ERROR_FILE;
+ goto free;
+ }
+
+ left -= res;
+ }
+ close(fd);
+
+ r = stat(tmpname, &buf);
+ if (r < 0) {
+ error = MAILMH_ERROR_FILE;
+ goto free;
+ }
+
+ r = mailmh_folder_alloc_msg(folder, tmpname, &index);
+ if (r != MAILMH_NO_ERROR) {
+ unlink(tmpname);
+ error = MAILMH_ERROR_COULD_NOT_ALLOC_MSG;
+ goto free;
+ }
+ free(tmpname);
+
+ msg_info = mailmh_msg_info_new(index, size, buf.st_mtime);
+ if (msg_info == NULL) {
+ mailmh_folder_remove_message(folder, index);
+ error = MAILMH_ERROR_MEMORY;
+ goto err;
+ }
+
+ r = carray_add(folder->fl_msgs_tab, msg_info, &array_index);
+ if (r < 0) {
+ mailmh_folder_remove_message(folder, index);
+ mailmh_msg_info_free(msg_info);
+ error = MAILMH_ERROR_MEMORY;
+ goto err;
+ }
+ msg_info->msg_array_index = array_index;
+
+#if 0
+ r = cinthash_add(folder->fl_msgs_hash, index, msg_info);
+#endif
+ key.data = &index;
+ key.len = sizeof(index);
+ data.data = msg_info;
+ data.len = 0;
+
+ if (pindex != NULL)
+ * pindex = index;
+
+ r = chash_set(folder->fl_msgs_hash, &key, &data, NULL);
+ if (r < 0) {
+ carray_delete_fast(folder->fl_msgs_tab, msg_info->msg_array_index);
+ mailmh_msg_info_free(msg_info);
+ error = MAILMH_ERROR_MEMORY;
+ goto err;
+ }
+
+ return MAILMH_NO_ERROR;
+
+ free:
+ free(tmpname);
+ err:
+ return error;
+}
+
+int mailmh_folder_add_message(struct mailmh_folder * folder,
+ const char * message, size_t size)
+{
+ return mailmh_folder_add_message_uid(folder, message, size, NULL);
+}
+
+int mailmh_folder_add_message_file_uid(struct mailmh_folder * folder,
+ int fd, uint32_t * pindex)
+{
+ char * message;
+ struct stat buf;
+ int r;
+
+#if 0
+ r = mailmh_folder_update(folder);
+ if (r != MAILMH_NO_ERROR)
+ return r;
+#endif
+
+ if (fstat(fd, &buf) == -1)
+ return MAILMH_ERROR_FILE;
+
+ message = mmap(NULL, buf.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+ if (message == MAP_FAILED)
+ return MAILMH_ERROR_FILE;
+
+ r = mailmh_folder_add_message_uid(folder, message, buf.st_size, pindex);
+
+ munmap(message, buf.st_size);
+
+ return r;
+}
+
+int mailmh_folder_add_message_file(struct mailmh_folder * folder,
+ int fd)
+{
+ return mailmh_folder_add_message_file_uid(folder, fd, NULL);
+}
+
+int mailmh_folder_remove_message(struct mailmh_folder * folder,
+ uint32_t index)
+{
+ char * filename;
+ struct mailmh_msg_info * msg_info;
+ int res;
+ int r;
+ chashdatum key;
+ chashdatum data;
+
+#if 0
+ r = mailmh_folder_update(folder);
+ if (r != MAILMH_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+#endif
+
+ r = mailmh_folder_get_message_filename(folder, index, &filename);
+ if (filename == NULL) {
+ res = r;
+ goto err;
+ }
+
+ if (unlink(filename) == -1) {
+ res = MAILMH_ERROR_FILE;
+ goto free;
+ }
+
+ key.data = &index;
+ key.len = sizeof(index);
+ r = chash_get(folder->fl_msgs_hash, &key, &data);
+#if 0
+ msg_info = cinthash_find(folder->fl_msgs_hash, index);
+#endif
+ if (r == 0) {
+ msg_info = data.data;
+
+ carray_delete_fast(folder->fl_msgs_tab, msg_info->msg_array_index);
+#if 0
+ cinthash_remove(folder->fl_msgs_hash, index);
+#endif
+ chash_delete(folder->fl_msgs_hash, &key, NULL);
+ }
+
+ return MAILMH_NO_ERROR;
+
+ free:
+ free(filename);
+ err:
+ return res;
+}
+
+
+int mailmh_folder_move_message(struct mailmh_folder * dest_folder,
+ struct mailmh_folder * src_folder,
+ uint32_t index)
+{
+ int fd;
+ char * filename;
+ int r;
+
+#if 0
+ r = mailmh_folder_update(dest_folder);
+ if (r != MAILMH_NO_ERROR)
+ return r;
+ r = mailmh_folder_update(src_folder);
+ if (r != MAILMH_NO_ERROR)
+ return r;
+#endif
+
+ /* move on the same filesystem */
+ r = mailmh_folder_get_message_filename(src_folder, index, &filename);
+ if (r != MAILMH_NO_ERROR)
+ return r;
+
+ r = mailmh_folder_alloc_msg(dest_folder, filename, &index);
+ free(filename);
+ if (r == MAILMH_NO_ERROR)
+ return MAILMH_NO_ERROR;
+
+ /* move on the different filesystems */
+ r = mailmh_folder_get_message_fd(src_folder, index, O_RDONLY, &fd);
+ if (r != MAILMH_NO_ERROR)
+ return r;
+
+ r = mailmh_folder_add_message_file(dest_folder, fd);
+ if (r != MAILMH_NO_ERROR) {
+ close(fd);
+ return r;
+ }
+
+ close(fd);
+
+ r = mailmh_folder_remove_message(src_folder, index);
+
+ return MAILMH_NO_ERROR;
+}
+
+unsigned int mailmh_folder_get_message_number(struct mailmh_folder * folder)
+{
+ unsigned int i;
+ unsigned int count;
+
+ count = 0;
+ for(i = 0 ; i < carray_count(folder->fl_msgs_tab) ; i ++)
+ if (carray_get(folder->fl_msgs_tab, i) != NULL)
+ count ++;
+
+ return count;
+}
diff --git a/libetpan/src/low-level/mh/mailmh.h b/libetpan/src/low-level/mh/mailmh.h
new file mode 100644
index 0000000..dc1861b
--- a/dev/null
+++ b/libetpan/src/low-level/mh/mailmh.h
@@ -0,0 +1,152 @@
+/*
+ * 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$
+ */
+
+#ifndef MAILMH_H
+
+#define MAILMH_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <sys/types.h>
+#include <inttypes.h>
+#include <libetpan/carray.h>
+#if 0
+#include <libetpan/cinthash.h>
+#endif
+#include <libetpan/chash.h>
+
+enum {
+ MAILMH_NO_ERROR = 0,
+ MAILMH_ERROR_FOLDER,
+ MAILMH_ERROR_MEMORY,
+ MAILMH_ERROR_FILE,
+ MAILMH_ERROR_COULD_NOT_ALLOC_MSG,
+ MAILMH_ERROR_RENAME,
+ MAILMH_ERROR_MSG_NOT_FOUND,
+};
+
+struct mailmh {
+ struct mailmh_folder * mh_main;
+};
+
+struct mailmh_msg_info {
+ unsigned int msg_array_index;
+ uint32_t msg_index;
+ size_t msg_size;
+ time_t msg_mtime;
+};
+
+struct mailmh_folder {
+ char * fl_filename;
+ unsigned int fl_array_index;
+
+ char * fl_name;
+ time_t fl_mtime;
+ struct mailmh_folder * fl_parent;
+ uint32_t fl_max_index;
+
+ carray * fl_msgs_tab;
+#if 0
+ cinthash_t * fl_msgs_hash;
+#endif
+ chash * fl_msgs_hash;
+
+ carray * fl_subfolders_tab;
+ chash * fl_subfolders_hash;
+};
+
+struct mailmh * mailmh_new(const char * foldername);
+void mailmh_free(struct mailmh * f);
+
+struct mailmh_msg_info *
+mailmh_msg_info_new(uint32_t index, size_t size, time_t mtime);
+void mailmh_msg_info_free(struct mailmh_msg_info * msg_info);
+
+struct mailmh_folder * mailmh_folder_new(struct mailmh_folder * parent,
+ const char * name);
+void mailmh_folder_free(struct mailmh_folder * folder);
+
+int mailmh_folder_add_subfolder(struct mailmh_folder * parent,
+ const char * name);
+
+struct mailmh_folder * mailmh_folder_find(struct mailmh_folder * root,
+ const char * filename);
+
+int mailmh_folder_remove_subfolder(struct mailmh_folder * folder);
+
+int mailmh_folder_rename_subfolder(struct mailmh_folder * src_folder,
+ struct mailmh_folder * dst_folder,
+ const char * new_name);
+
+int mailmh_folder_get_message_filename(struct mailmh_folder * folder,
+ uint32_t index, char ** result);
+
+int mailmh_folder_get_message_fd(struct mailmh_folder * folder,
+ uint32_t index, int flags, int * result);
+
+int mailmh_folder_get_message_size(struct mailmh_folder * folder,
+ uint32_t index, size_t * result);
+
+int mailmh_folder_add_message_uid(struct mailmh_folder * folder,
+ const char * message, size_t size,
+ uint32_t * pindex);
+
+int mailmh_folder_add_message(struct mailmh_folder * folder,
+ const char * message, size_t size);
+
+int mailmh_folder_add_message_file_uid(struct mailmh_folder * folder,
+ int fd, uint32_t * pindex);
+
+int mailmh_folder_add_message_file(struct mailmh_folder * folder,
+ int fd);
+
+int mailmh_folder_remove_message(struct mailmh_folder * folder,
+ uint32_t index);
+
+int mailmh_folder_move_message(struct mailmh_folder * dest_folder,
+ struct mailmh_folder * src_folder,
+ uint32_t index);
+
+int mailmh_folder_update(struct mailmh_folder * folder);
+
+unsigned int mailmh_folder_get_message_number(struct mailmh_folder * folder);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libetpan/src/low-level/mime/TODO b/libetpan/src/low-level/mime/TODO
new file mode 100644
index 0000000..df02810
--- a/dev/null
+++ b/libetpan/src/low-level/mime/TODO
@@ -0,0 +1,10 @@
+- see about the RFC2047, beginning in mailmime_decode.[ch]
+- content-langage
+- single mime_field
+- RFC 2048
+- RFC 2049
+- RFC 2231
+- RFC 2387
+- RFC 2424
+- RFC 2557
+
diff --git a/libetpan/src/low-level/mime/mailmime.c b/libetpan/src/low-level/mime/mailmime.c
new file mode 100644
index 0000000..4bade55
--- a/dev/null
+++ b/libetpan/src/low-level/mime/mailmime.c
@@ -0,0 +1,1408 @@
+/*
+ * 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 "mailmime.h"
+
+/*
+ RFC 2045
+ RFC 2046
+ RFC 2047
+ RFC 2048
+ RFC 2049
+ RFC 2231
+ RFC 2387
+ RFC 2424
+ RFC 2557
+
+ RFC 2183 Content-Disposition
+
+ RFC 1766 Language
+ */
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "mailmime_types.h"
+#include "mailmime_disposition.h"
+#include "mailimf.h"
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+static int mailmime_attribute_parse(const char * message, size_t length,
+ size_t * index,
+ char ** result);
+static int
+mailmime_composite_type_parse(const char * message, size_t length,
+ size_t * index,
+ struct mailmime_composite_type ** result);
+
+static int is_text(char ch);
+
+static int
+mailmime_discrete_type_parse(const char * message, size_t length,
+ size_t * index,
+ struct mailmime_discrete_type ** result);
+
+static int mailmime_mechanism_parse(const char * message, size_t length,
+ size_t * index,
+ struct mailmime_mechanism ** result);
+
+static int mailmime_subtype_parse(const char * message, size_t length,
+ size_t * index, char ** result);
+
+static int is_token(char ch);
+
+static int mailmime_token_parse(const char * message, size_t length,
+ size_t * index,
+ char ** token);
+
+static int is_tspecials(char ch);
+
+static int mailmime_type_parse(const char * message, size_t length,
+ size_t * index,
+ struct mailmime_type ** result);
+
+/*
+int mailmime_version_parse(const char * message, guint32 length,
+ guint32 * index,
+ guint32 * result);
+*/
+
+/*
+static gboolean mailmime_x_token_parse(gconst char * message, guint32 length,
+ guint32 * index,
+ gchar ** result);
+*/
+
+/* ********************************************************************** */
+
+/*
+x attribute := token
+ ; Matching of attributes
+ ; is ALWAYS case-insensitive.
+*/
+
+static int mailmime_attribute_parse(const char * message, size_t length,
+ size_t * index,
+ char ** result)
+{
+ return mailmime_token_parse(message, length, index, result);
+}
+
+/*
+x composite-type := "message" / "multipart" / extension-token
+*/
+
+static int
+mailmime_composite_type_parse(const char * message, size_t length,
+ size_t * index,
+ struct mailmime_composite_type ** result)
+{
+ char * extension_token;
+ int type;
+ struct mailmime_composite_type * ct;
+ size_t cur_token;
+ int r;
+ int res;
+
+ cur_token = * index;
+
+ extension_token = NULL;
+
+ type = MAILMIME_COMPOSITE_TYPE_ERROR; /* XXX - removes a gcc warning */
+
+ r = mailimf_token_case_insensitive_parse(message, length,
+ &cur_token, "message");
+ if (r == MAILIMF_NO_ERROR)
+ type = MAILMIME_COMPOSITE_TYPE_MESSAGE;
+
+ if (r == MAILIMF_ERROR_PARSE) {
+ r = mailimf_token_case_insensitive_parse(message, length,
+ &cur_token, "multipart");
+ if (r == MAILIMF_NO_ERROR)
+ type = MAILMIME_COMPOSITE_TYPE_MULTIPART;
+ }
+
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ ct = mailmime_composite_type_new(type, extension_token);
+ if (ct == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free_extension;
+ }
+
+ * result = ct;
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+
+ free_extension:
+ if (extension_token != NULL)
+ mailmime_extension_token_free(extension_token);
+ err:
+ return res;
+}
+
+/*
+x content := "Content-Type" ":" type "/" subtype
+ *(";" parameter)
+ ; Matching of media type and subtype
+ ; is ALWAYS case-insensitive.
+*/
+
+int mailmime_content_parse(const char * message, size_t length,
+ size_t * index,
+ struct mailmime_content ** result)
+{
+ size_t cur_token;
+ struct mailmime_type * type;
+ char * subtype;
+ clist * parameters_list;
+ struct mailmime_content * content;
+ int r;
+ int res;
+
+ cur_token = * index;
+
+ mailimf_cfws_parse(message, length, &cur_token);
+
+ r = mailmime_type_parse(message, length, &cur_token, &type);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ r = mailimf_unstrict_char_parse(message, length, &cur_token, '/');
+ switch (r) {
+ case MAILIMF_NO_ERROR:
+ r = mailimf_cfws_parse(message, length, &cur_token);
+ if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
+ res = r;
+ goto free_type;
+ }
+
+ r = mailmime_subtype_parse(message, length, &cur_token, &subtype);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto free_type;
+ }
+ break;
+
+ case MAILIMF_ERROR_PARSE:
+ subtype = strdup("unknown");
+ break;
+
+ default:
+ res = r;
+ goto free_type;
+ }
+
+ parameters_list = clist_new();
+ if (parameters_list == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free_type;
+ }
+
+ while (1) {
+ size_t final_token;
+ struct mailmime_parameter * parameter;
+
+ final_token = cur_token;
+ r = mailimf_unstrict_char_parse(message, length, &cur_token, ';');
+ if (r != MAILIMF_NO_ERROR) {
+ cur_token = final_token;
+ break;
+ }
+
+ r = mailimf_cfws_parse(message, length, &cur_token);
+ if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
+ res = r;
+ goto free_type;
+ }
+
+ r = mailmime_parameter_parse(message, length, &cur_token, &parameter);
+ if (r == MAILIMF_NO_ERROR) {
+ /* do nothing */
+ }
+ else if (r == MAILIMF_ERROR_PARSE) {
+ cur_token = final_token;
+ break;
+ }
+ else {
+ res = r;
+ goto err;
+ }
+
+ r = clist_append(parameters_list, parameter);
+ if (r < 0) {
+ mailmime_parameter_free(parameter);
+ res = MAILIMF_ERROR_MEMORY;
+ goto free_parameters;
+ }
+ }
+
+ content = mailmime_content_new(type, subtype, parameters_list);
+ if (content == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free_parameters;
+ }
+
+ * result = content;
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+
+ free_parameters:
+ clist_foreach(parameters_list, (clist_func) mailmime_parameter_free, NULL);
+ clist_free(parameters_list);
+
+ mailmime_subtype_free(subtype);
+ free_type:
+ mailmime_type_free(type);
+ err:
+ return res;
+}
+
+/*
+x description := "Content-Description" ":" *text
+*/
+
+static int is_text(char ch)
+{
+ unsigned char uch = (unsigned char) ch;
+
+ if (uch < 1)
+ return FALSE;
+
+ if ((uch == 10) || (uch == 13))
+ return FALSE;
+
+ return TRUE;
+}
+
+int mailmime_description_parse(const char * message, size_t length,
+ size_t * index,
+ char ** result)
+{
+ return mailimf_custom_string_parse(message, length,
+ index, result,
+ is_text);
+}
+
+/*
+x discrete-type := "text" / "image" / "audio" / "video" /
+ "application" / extension-token
+*/
+
+/* currently porting */
+
+static int
+mailmime_discrete_type_parse(const char * message, size_t length,
+ size_t * index,
+ struct mailmime_discrete_type ** result)
+{
+ char * extension;
+ int type;
+ struct mailmime_discrete_type * discrete_type;
+ size_t cur_token;
+ int r;
+ int res;
+
+ cur_token = * index;
+
+ extension = NULL;
+
+ type = MAILMIME_DISCRETE_TYPE_ERROR; /* XXX - removes a gcc warning */
+
+ r = mailimf_token_case_insensitive_parse(message, length,
+ &cur_token, "text");
+ if (r == MAILIMF_NO_ERROR)
+ type = MAILMIME_DISCRETE_TYPE_TEXT;
+
+ if (r == MAILIMF_ERROR_PARSE) {
+ r = mailimf_token_case_insensitive_parse(message, length,
+ &cur_token, "image");
+ if (r == MAILIMF_NO_ERROR)
+ type = MAILMIME_DISCRETE_TYPE_IMAGE;
+ }
+
+ if (r == MAILIMF_ERROR_PARSE) {
+ r = mailimf_token_case_insensitive_parse(message, length,
+ &cur_token, "audio");
+ if (r == MAILIMF_NO_ERROR)
+ type = MAILMIME_DISCRETE_TYPE_AUDIO;
+ }
+
+ if (r == MAILIMF_ERROR_PARSE) {
+ r = mailimf_token_case_insensitive_parse(message, length,
+ &cur_token, "video");
+ if (r == MAILIMF_NO_ERROR)
+ type = MAILMIME_DISCRETE_TYPE_VIDEO;
+ }
+
+ if (r == MAILIMF_ERROR_PARSE) {
+ r = mailimf_token_case_insensitive_parse(message, length,
+ &cur_token, "application");
+ if (r == MAILIMF_NO_ERROR)
+ type = MAILMIME_DISCRETE_TYPE_APPLICATION;
+ }
+
+ if (r == MAILIMF_ERROR_PARSE) {
+ r = mailmime_extension_token_parse(message, length,
+ &cur_token, &extension);
+ if (r == MAILIMF_NO_ERROR)
+ type = MAILMIME_DISCRETE_TYPE_EXTENSION;
+ }
+
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ discrete_type = mailmime_discrete_type_new(type, extension);
+ if (discrete_type == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free;
+ }
+
+ * result = discrete_type;
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+
+ free:
+ mailmime_extension_token_free(extension);
+ err:
+ return res;
+}
+
+/*
+x encoding := "Content-Transfer-Encoding" ":" mechanism
+*/
+
+int mailmime_encoding_parse(const char * message, size_t length,
+ size_t * index,
+ struct mailmime_mechanism ** result)
+{
+ return mailmime_mechanism_parse(message, length, index, result);
+}
+
+/*
+x entity-headers := [ content CRLF ]
+ [ encoding CRLF ]
+ [ id CRLF ]
+ [ description CRLF ]
+ *( MIME-extension-field CRLF )
+ */
+
+enum {
+ FIELD_STATE_START,
+ FIELD_STATE_T,
+ FIELD_STATE_D
+};
+
+static int guess_field_type(char * name)
+{
+ int state;
+
+ if (* name == 'M')
+ return MAILMIME_FIELD_VERSION;
+
+ if (strncasecmp(name, "Content-", 8) != 0)
+ return MAILMIME_FIELD_NONE;
+
+ name += 8;
+
+ state = FIELD_STATE_START;
+
+ while (1) {
+
+ switch (state) {
+
+ case FIELD_STATE_START:
+ switch ((char) toupper((unsigned char) * name)) {
+ case 'T':
+ state = FIELD_STATE_T;
+ break;
+ case 'I':
+ return MAILMIME_FIELD_ID;
+ case 'D':
+ state = FIELD_STATE_D;
+ break;
+ case 'L':
+ return MAILMIME_FIELD_LANGUAGE;
+ default:
+ return MAILMIME_FIELD_NONE;
+ }
+ break;
+
+ case FIELD_STATE_T:
+ switch ((char) toupper((unsigned char) * name)) {
+ case 'Y':
+ return MAILMIME_FIELD_TYPE;
+ case 'R':
+ return MAILMIME_FIELD_TRANSFER_ENCODING;
+ default:
+ return MAILMIME_FIELD_NONE;
+ }
+ break;
+
+ case FIELD_STATE_D:
+ switch ((char) toupper((unsigned char) * name)) {
+ case 'E':
+ return MAILMIME_FIELD_DESCRIPTION;
+ case 'I':
+ return MAILMIME_FIELD_DISPOSITION;
+ default:
+ return MAILMIME_FIELD_NONE;
+ }
+ break;
+ }
+ name ++;
+ }
+}
+
+int
+mailmime_field_parse(struct mailimf_optional_field * field,
+ struct mailmime_field ** result)
+{
+ char * name;
+ char * value;
+ int guessed_type;
+ size_t cur_token;
+ struct mailmime_content * content;
+ struct mailmime_mechanism * encoding;
+ char * id;
+ char * description;
+ uint32_t version;
+ struct mailmime_field * mime_field;
+ struct mailmime_language * language;
+ struct mailmime_disposition * disposition;
+ int res;
+ int r;
+
+ name = field->fld_name;
+ value = field->fld_value;
+ cur_token = 0;
+
+ content = NULL;
+ encoding = NULL;
+ id = NULL;
+ description = NULL;
+ version = 0;
+ disposition = NULL;
+ language = NULL;
+
+ guessed_type = guess_field_type(name);
+
+ switch (guessed_type) {
+ case MAILMIME_FIELD_TYPE:
+ if (strcasecmp(name, "Content-Type") != 0)
+ return MAILIMF_ERROR_PARSE;
+ r = mailmime_content_parse(value, strlen(value), &cur_token, &content);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ break;
+
+ case MAILMIME_FIELD_TRANSFER_ENCODING:
+ if (strcasecmp(name, "Content-Transfer-Encoding") != 0)
+ return MAILIMF_ERROR_PARSE;
+ r = mailmime_encoding_parse(value, strlen(value), &cur_token, &encoding);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ break;
+
+ case MAILMIME_FIELD_ID:
+ if (strcasecmp(name, "Content-ID") != 0)
+ return MAILIMF_ERROR_PARSE;
+ r = mailmime_id_parse(value, strlen(value), &cur_token, &id);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ break;
+
+ case MAILMIME_FIELD_DESCRIPTION:
+ if (strcasecmp(name, "Content-Description") != 0)
+ return MAILIMF_ERROR_PARSE;
+ r = mailmime_description_parse(value, strlen(value),
+ &cur_token, &description);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ break;
+
+ case MAILMIME_FIELD_VERSION:
+ if (strcasecmp(name, "MIME-Version") != 0)
+ return MAILIMF_ERROR_PARSE;
+ r = mailmime_version_parse(value, strlen(value), &cur_token, &version);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ break;
+
+ case MAILMIME_FIELD_DISPOSITION:
+ if (strcasecmp(name, "Content-Disposition") != 0)
+ return MAILIMF_ERROR_PARSE;
+ r = mailmime_disposition_parse(value, strlen(value),
+ &cur_token, &disposition);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ break;
+
+ case MAILMIME_FIELD_LANGUAGE:
+ if (strcasecmp(name, "Content-Language") != 0)
+ return MAILIMF_ERROR_PARSE;
+ r = mailmime_language_parse(value, strlen(value), &cur_token, &language);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ break;
+
+ default:
+ return MAILIMF_ERROR_PARSE;
+ }
+
+ mime_field = mailmime_field_new(guessed_type, content, encoding,
+ id, description, version, disposition,
+ language);
+ if (mime_field == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free;
+ }
+
+ * result = mime_field;
+
+ return MAILIMF_NO_ERROR;
+
+ free:
+ if (content != NULL)
+ mailmime_content_free(content);
+ if (encoding != NULL)
+ mailmime_encoding_free(encoding);
+ if (id != NULL)
+ mailmime_id_free(id);
+ if (description != NULL)
+ mailmime_description_free(description);
+ return res;
+}
+
+/*
+x extension-token := ietf-token / x-token
+*/
+
+int
+mailmime_extension_token_parse(const char * message, size_t length,
+ size_t * index, char ** result)
+{
+ return mailmime_token_parse(message, length, index, result);
+}
+
+/*
+ hex-octet := "=" 2(DIGIT / "A" / "B" / "C" / "D" / "E" / "F")
+ ; Octet must be used for characters > 127, =,
+ ; SPACEs or TABs at the ends of lines, and is
+ ; recommended for any character not listed in
+ ; RFC 2049 as "mail-safe".
+*/
+
+/*
+x iana-token := <A publicly-defined extension token. Tokens
+ of this form must be registered with IANA
+ as specified in RFC 2048.>
+*/
+
+/*
+x ietf-token := <An extension token defined by a
+ standards-track RFC and registered
+ with IANA.>
+*/
+
+/*
+x id := "Content-ID" ":" msg-id
+*/
+
+int mailmime_id_parse(const char * message, size_t length,
+ size_t * index, char ** result)
+{
+ return mailimf_msg_id_parse(message, length, index, result);
+}
+
+/*
+x mechanism := "7bit" / "8bit" / "binary" /
+ "quoted-printable" / "base64" /
+ ietf-token / x-token
+*/
+
+static int mailmime_mechanism_parse(const char * message, size_t length,
+ size_t * index,
+ struct mailmime_mechanism ** result)
+{
+ char * token;
+ int type;
+ struct mailmime_mechanism * mechanism;
+ size_t cur_token;
+ int r;
+ int res;
+
+ cur_token = * index;
+
+ type = MAILMIME_MECHANISM_ERROR; /* XXX - removes a gcc warning */
+
+ token = NULL;
+ r = mailimf_token_case_insensitive_parse(message, length,
+ &cur_token, "7bit");
+ if (r == MAILIMF_NO_ERROR)
+ type = MAILMIME_MECHANISM_7BIT;
+
+ if (r == MAILIMF_ERROR_PARSE) {
+ r = mailimf_token_case_insensitive_parse(message, length,
+ &cur_token, "8bit");
+ if (r == MAILIMF_NO_ERROR)
+ type = MAILMIME_MECHANISM_8BIT;
+ }
+
+ if (r == MAILIMF_ERROR_PARSE) {
+ r = mailimf_token_case_insensitive_parse(message, length,
+ &cur_token, "binary");
+ if (r == MAILIMF_NO_ERROR)
+ type = MAILMIME_MECHANISM_BINARY;
+ }
+
+ if (r == MAILIMF_ERROR_PARSE) {
+ r = mailimf_token_case_insensitive_parse(message, length,
+ &cur_token, "quoted-printable");
+ if (r == MAILIMF_NO_ERROR)
+ type = MAILMIME_MECHANISM_QUOTED_PRINTABLE;
+ }
+
+ if (r == MAILIMF_ERROR_PARSE) {
+ r = mailimf_token_case_insensitive_parse(message, length,
+ &cur_token, "base64");
+ if (r == MAILIMF_NO_ERROR)
+ type = MAILMIME_MECHANISM_BASE64;
+ }
+
+ if (r == MAILIMF_ERROR_PARSE) {
+ r = mailmime_token_parse(message, length, &cur_token, &token);
+ if (r == MAILIMF_NO_ERROR)
+ type = MAILMIME_MECHANISM_TOKEN;
+ }
+
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ mechanism = mailmime_mechanism_new(type, token);
+ if (mechanism == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free;
+ }
+
+ * result = mechanism;
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+
+ free:
+ if (token != NULL)
+ mailmime_token_free(token);
+ err:
+ return res;
+}
+
+/*
+x MIME-extension-field := <Any RFC 822 header field which
+ begins with the string
+ "Content-">
+*/
+
+/*
+in headers
+
+x MIME-message-headers := entity-headers
+ fields
+ version CRLF
+ ; The ordering of the header
+ ; fields implied by this BNF
+ ; definition should be ignored.
+*/
+
+/*
+in message
+
+x MIME-part-headers := entity-headers
+ [fields]
+ ; Any field not beginning with
+ ; "content-" can have no defined
+ ; meaning and may be ignored.
+ ; The ordering of the header
+ ; fields implied by this BNF
+ ; definition should be ignored.
+*/
+
+#if 0
+int
+mailmime_unparsed_fields_parse(struct mailimf_unparsed_fields *
+ fields,
+ struct mailmime_fields **
+ result)
+{
+ clistiter * cur;
+ struct mailmime_fields * mime_fields;
+ clist * list;
+ int r;
+ int res;
+
+ list = clist_new();
+ if (list == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto err;
+ }
+
+ if (fields->list == NULL) {
+ res = MAILIMF_ERROR_PARSE;
+ goto err;
+ }
+
+ for(cur = clist_begin(fields->list) ; cur != NULL ;
+ cur = clist_next(cur)) {
+ struct mailimf_optional_field * field = cur->data;
+ struct mailmime_field * mime_field;
+
+ r = mailmime_field_parse(field, &mime_field);
+ if (r == MAILIMF_NO_ERROR) {
+ r = clist_append(list, mime_field);
+ if (r < 0) {
+ mailmime_field_free(mime_field);
+ res = MAILIMF_ERROR_MEMORY;
+ goto free_list;
+ }
+ }
+ }
+
+ if (clist_begin(list) == NULL) {
+ res = MAILIMF_ERROR_PARSE;
+ goto free_list;
+ }
+
+ mime_fields = mailmime_fields_new(list);
+ if (mime_fields == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free_list;
+ }
+
+ * result = mime_fields;
+
+ return MAILIMF_NO_ERROR;
+
+ free_list:
+ clist_foreach(list, (clist_func) mailmime_field_free, NULL);
+ clist_free(list);
+ err:
+ return res;
+}
+#endif
+
+int
+mailmime_fields_parse(struct mailimf_fields *
+ fields,
+ struct mailmime_fields **
+ result)
+{
+ clistiter * cur;
+ struct mailmime_fields * mime_fields;
+ clist * list;
+ int r;
+ int res;
+
+ list = clist_new();
+ if (list == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto err;
+ }
+
+ for(cur = clist_begin(fields->fld_list) ; cur != NULL ;
+ cur = clist_next(cur)) {
+ struct mailimf_field * field;
+ struct mailmime_field * mime_field;
+
+ field = clist_content(cur);
+
+ if (field->fld_type == MAILIMF_FIELD_OPTIONAL_FIELD) {
+ r = mailmime_field_parse(field->fld_data.fld_optional_field,
+ &mime_field);
+ if (r == MAILIMF_NO_ERROR) {
+ r = clist_append(list, mime_field);
+ if (r < 0) {
+ mailmime_field_free(mime_field);
+ res = MAILIMF_ERROR_MEMORY;
+ goto free_list;
+ }
+ }
+ else if (r == MAILIMF_ERROR_PARSE) {
+ /* do nothing */
+ }
+ else {
+ res = r;
+ goto free_list;
+ }
+ }
+ }
+
+ if (clist_begin(list) == NULL) {
+ res = MAILIMF_ERROR_PARSE;
+ goto free_list;
+ }
+
+ mime_fields = mailmime_fields_new(list);
+ if (mime_fields == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free_list;
+ }
+
+ * result = mime_fields;
+
+ return MAILIMF_NO_ERROR;
+
+ free_list:
+ clist_foreach(list, (clist_func) mailmime_field_free, NULL);
+ clist_free(list);
+ err:
+ return res;
+}
+
+/*
+x parameter := attribute "=" value
+*/
+
+int mailmime_parameter_parse(const char * message, size_t length,
+ size_t * index,
+ struct mailmime_parameter ** result)
+{
+ char * attribute;
+ char * value;
+ struct mailmime_parameter * parameter;
+ size_t cur_token;
+ int r;
+ int res;
+
+ cur_token = * index;
+
+ r = mailmime_attribute_parse(message, length, &cur_token, &attribute);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ r = mailimf_unstrict_char_parse(message, length, &cur_token, '=');
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto free_attr;
+ }
+
+ r = mailimf_cfws_parse(message, length, &cur_token);
+ if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
+ res = r;
+ goto free_attr;
+ }
+
+ r = mailmime_value_parse(message, length, &cur_token, &value);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto free_attr;
+ }
+
+ parameter = mailmime_parameter_new(attribute, value);
+ if (parameter == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free_value;
+ }
+
+ * result = parameter;
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+
+ free_value:
+ mailmime_value_free(value);
+ free_attr:
+ mailmime_attribute_free(attribute);
+ err:
+ return res;
+}
+
+/*
+ ptext := hex-octet / safe-char
+*/
+
+/*
+ qp-line := *(qp-segment transport-padding CRLF)
+ qp-part transport-padding
+*/
+
+/*
+ qp-part := qp-section
+ ; Maximum length of 76 characters
+*/
+
+/*
+ qp-section := [*(ptext / SPACE / TAB) ptext]
+*/
+
+/*
+ qp-segment := qp-section *(SPACE / TAB) "="
+ ; Maximum length of 76 characters
+*/
+
+/*
+ quoted-printable := qp-line *(CRLF qp-line)
+*/
+
+/*
+ safe-char := <any octet with decimal value of 33 through
+ 60 inclusive, and 62 through 126>
+ ; Characters not listed as "mail-safe" in
+ ; RFC 2049 are also not recommended.
+*/
+
+/*
+x subtype := extension-token / iana-token
+*/
+
+static int mailmime_subtype_parse(const char * message, size_t length,
+ size_t * index, char ** result)
+{
+ return mailmime_extension_token_parse(message, length, index, result);
+}
+
+/*
+x token := 1*<any (US-ASCII) CHAR except SPACE, CTLs,
+ or tspecials>
+*/
+
+static int is_token(char ch)
+{
+ unsigned char uch = (unsigned char) ch;
+
+ if (uch > 0x7F)
+ return FALSE;
+
+ if (uch == ' ')
+ return FALSE;
+
+ if (is_tspecials(ch))
+ return FALSE;
+
+ return TRUE;
+}
+
+
+static int mailmime_token_parse(const char * message, size_t length,
+ size_t * index,
+ char ** token)
+{
+ return mailimf_custom_string_parse(message, length,
+ index, token,
+ is_token);
+}
+
+/*
+ transport-padding := *LWSP-char
+ ; Composers MUST NOT generate
+ ; non-zero length transport
+ ; padding, but receivers MUST
+ ; be able to handle padding
+ ; added by message transports.
+*/
+
+/*
+enum {
+ LWSP_1,
+ LWSP_2,
+ LWSP_3,
+ LWSP_4,
+ LWSP_OK
+};
+
+gboolean mailmime_transport_padding_parse(gconst char * message, guint32 length,
+ guint32 * index)
+{
+ guint32 cur_token;
+ gint state;
+ guint32 last_valid_pos;
+
+ cur_token = * index;
+
+ if (cur_token >= length)
+ return FALSE;
+
+ state = LWSP_1;
+
+ while (state != LWSP_OUT) {
+
+ if (cur_token >= length)
+ return FALSE;
+
+ switch (state) {
+ case LWSP_1:
+ last_valid_pos = cur_token;
+
+ switch (message[cur_token]) {
+ case '\r':
+ state = LWSP_2;
+ break;
+ case '\n':
+ state = LWSP_3;
+ break;
+ case ' ':
+ case '\t':
+ state = LWSP_4;
+ break;
+ default:
+ state = LWSP_OK;
+ break;
+ }
+ case LWSP_2:
+ switch (message[cur_token]) {
+ case '\n':
+ state = LWSP_3;
+ break;
+ default:
+ state = LWSP_OUT;
+ cur_token = last_valid_pos;
+ break;
+ }
+ case LWSP_3:
+ switch (message[cur_token]) {
+ case ' ':
+ case '\t':
+ state = LWSP_1;
+ break;
+ default:
+ state = LWSP_OUT;
+ cur_token = last_valid_pos;
+ break;
+ }
+
+ cur_token ++;
+ }
+ }
+
+ * index = cur_token;
+
+ return TRUE;
+}
+*/
+
+/*
+x tspecials := "(" / ")" / "<" / ">" / "@" /
+ "," / ";" / ":" / "\" / <">
+ "/" / "[" / "]" / "?" / "="
+ ; Must be in quoted-string,
+ ; to use within parameter values
+*/
+
+static int is_tspecials(char ch)
+{
+ switch (ch) {
+ case '(':
+ case ')':
+ case '<':
+ case '>':
+ case '@':
+ case ',':
+ case ';':
+ case ':':
+ case '\\':
+ case '\"':
+ case '/':
+ case '[':
+ case ']':
+ case '?':
+ case '=':
+ return TRUE;
+ default:
+ return FALSE;
+ }
+}
+
+/*
+x type := discrete-type / composite-type
+*/
+
+static int mailmime_type_parse(const char * message, size_t length,
+ size_t * index,
+ struct mailmime_type ** result)
+{
+ struct mailmime_discrete_type * discrete_type;
+ struct mailmime_composite_type * composite_type;
+ size_t cur_token;
+ struct mailmime_type * mime_type;
+ int type;
+ int res;
+ int r;
+
+ cur_token = * index;
+
+ discrete_type = NULL;
+ composite_type = NULL;
+
+ type = MAILMIME_TYPE_ERROR; /* XXX - removes a gcc warning */
+
+ r = mailmime_composite_type_parse(message, length, &cur_token,
+ &composite_type);
+ if (r == MAILIMF_NO_ERROR)
+ type = MAILMIME_TYPE_COMPOSITE_TYPE;
+
+ if (r == MAILIMF_ERROR_PARSE) {
+ r = mailmime_discrete_type_parse(message, length, &cur_token,
+ &discrete_type);
+ if (r == MAILIMF_NO_ERROR)
+ type = MAILMIME_TYPE_DISCRETE_TYPE;
+ }
+
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ mime_type = mailmime_type_new(type, discrete_type, composite_type);
+ if (mime_type == NULL) {
+ res = r;
+ goto free;
+ }
+
+ * result = mime_type;
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+
+ free:
+ if (discrete_type != NULL)
+ mailmime_discrete_type_free(discrete_type);
+ if (composite_type != NULL)
+ mailmime_composite_type_free(composite_type);
+ err:
+ return res;
+}
+
+/*
+x value := token / quoted-string
+*/
+
+int mailmime_value_parse(const char * message, size_t length,
+ size_t * index, char ** result)
+{
+ int r;
+
+ r = mailmime_token_parse(message, length, index, result);
+
+ if (r == MAILIMF_ERROR_PARSE)
+ r = mailimf_quoted_string_parse(message, length, index, result);
+
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ return MAILIMF_NO_ERROR;
+}
+
+/*
+x version := "MIME-Version" ":" 1*DIGIT "." 1*DIGIT
+*/
+
+int mailmime_version_parse(const char * message, size_t length,
+ size_t * index,
+ uint32_t * result)
+{
+ size_t cur_token;
+ uint32_t hi;
+ uint32_t low;
+ uint32_t version;
+ int r;
+
+ cur_token = * index;
+
+ r = mailimf_number_parse(message, length, &cur_token, &hi);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_unstrict_char_parse(message, length, &cur_token, '.');
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_cfws_parse(message, length, &cur_token);
+ if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE))
+ return r;
+
+ r = mailimf_number_parse(message, length, &cur_token, &low);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ version = (hi << 16) + low;
+
+ * result = version;
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+}
+
+/*
+x x-token := <The two characters "X-" or "x-" followed, with
+ no intervening white space, by any token>
+*/
+
+/*
+static gboolean mailmime_x_token_parse(gconst char * message, guint32 length,
+ guint32 * index,
+ gchar ** result)
+{
+ guint32 cur_token;
+ gchar * token;
+ gchar * x_token;
+ gboolean min_x;
+
+ cur_token = * index;
+
+ if (!mailimf_char_parse(message, length, &cur_token, 'x')) {
+ if (!mailimf_char_parse(message, length, &cur_token, 'X'))
+ return FALSE;
+ min_x = FALSE;
+ }
+ else
+ min_x = TRUE;
+
+ if (!mailimf_char_parse(message, length, &cur_token, '-'))
+ return FALSE;
+
+ if (!mailmime_token_parse(message, length, &cur_token, &token))
+ return FALSE;
+
+ if (min_x)
+ x_token = g_strconcat("x-", token, NULL);
+ else
+ x_token = g_strconcat("X-", token, NULL);
+ mailmime_token_free(token);
+
+ if (x_token == NULL)
+ return FALSE;
+
+ * result = x_token;
+ * index = cur_token;
+
+ return TRUE;
+}
+*/
+
+
+int mailmime_language_parse(const char * message, size_t length,
+ size_t * index,
+ struct mailmime_language ** result)
+{
+ size_t cur_token;
+ int r;
+ int res;
+ clist * list;
+ int first;
+ struct mailmime_language * language;
+
+ cur_token = * index;
+
+ list = clist_new();
+ if (list == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto err;
+ }
+
+ first = TRUE;
+
+ while (1) {
+ char * atom;
+
+ r = mailimf_unstrict_char_parse(message, length, &cur_token, ',');
+ if (r == MAILIMF_NO_ERROR) {
+ /* do nothing */
+ }
+ else if (r == MAILIMF_ERROR_PARSE) {
+ break;
+ }
+ else {
+ res = r;
+ goto err;
+ }
+
+ r = mailimf_atom_parse(message, length, &cur_token, &atom);
+ if (r == MAILIMF_NO_ERROR) {
+ /* do nothing */
+ }
+ else if (r == MAILIMF_ERROR_PARSE) {
+ break;
+ }
+ else {
+ res = r;
+ goto err;
+ }
+
+ r = clist_append(list, atom);
+ if (r < 0) {
+ mailimf_atom_free(atom);
+ res = MAILIMF_ERROR_MEMORY;
+ goto free;
+ }
+ }
+
+ language = mailmime_language_new(list);
+ if (language == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free;
+ }
+
+ * result = language;
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+
+ free:
+ clist_foreach(list, (clist_func) mailimf_atom_free, NULL);
+ clist_free(list);
+ err:
+ return res;
+}
diff --git a/libetpan/src/low-level/mime/mailmime.h b/libetpan/src/low-level/mime/mailmime.h
new file mode 100644
index 0000000..83cba25
--- a/dev/null
+++ b/libetpan/src/low-level/mime/mailmime.h
@@ -0,0 +1,102 @@
+/*
+ * 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$
+ */
+
+#ifndef MAILMIME_H
+
+#define MAILMIME_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <libetpan/mailimf.h>
+#include <libetpan/mailmime_types.h>
+#include <libetpan/mailmime_types_helper.h>
+#include <libetpan/mailmime_content.h>
+#include <libetpan/mailmime_decode.h>
+#include <libetpan/mailmime_disposition.h>
+#include <libetpan/mailmime_write_file.h>
+#include <libetpan/mailmime_write_mem.h>
+#include <libetpan/mailmime_write_generic.h>
+
+int mailmime_content_parse(const char * message, size_t length,
+ size_t * index,
+ struct mailmime_content ** result);
+
+int mailmime_description_parse(const char * message, size_t length,
+ size_t * index,
+ char ** result);
+
+int mailmime_encoding_parse(const char * message, size_t length,
+ size_t * index,
+ struct mailmime_mechanism ** result);
+
+int
+mailmime_field_parse(struct mailimf_optional_field * field,
+ struct mailmime_field ** result);
+
+int mailmime_id_parse(const char * message, size_t length,
+ size_t * index, char ** result);
+
+int
+mailmime_fields_parse(struct mailimf_fields *
+ fields,
+ struct mailmime_fields **
+ result);
+
+int mailmime_version_parse(const char * message, size_t length,
+ size_t * index,
+ uint32_t * result);
+
+int
+mailmime_extension_token_parse(const char * message, size_t length,
+ size_t * index, char ** result);
+
+int mailmime_parameter_parse(const char * message, size_t length,
+ size_t * index,
+ struct mailmime_parameter ** result);
+
+int mailmime_value_parse(const char * message, size_t length,
+ size_t * index, char ** result);
+
+int mailmime_language_parse(const char * message, size_t length,
+ size_t * index,
+ struct mailmime_language ** result);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libetpan/src/low-level/mime/mailmime_content.c b/libetpan/src/low-level/mime/mailmime_content.c
new file mode 100644
index 0000000..6a10dfb
--- a/dev/null
+++ b/libetpan/src/low-level/mime/mailmime_content.c
@@ -0,0 +1,2381 @@
+/*
+ * 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 "mailimf.h"
+
+#include <string.h>
+#include <stdlib.h>
+
+#include "mailmime.h"
+#include "mailmime_types.h"
+#include "mmapstring.h"
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+/*
+ RFC 2045
+ RFC 2046
+ RFC 2047
+
+ RFC 2231
+*/
+
+
+static int mailmime_parse_with_default(const char * message, size_t length,
+ size_t * index, int default_type,
+ struct mailmime_content * content_type,
+ struct mailmime_fields * mime_fields,
+ struct mailmime ** result);
+
+
+
+char * mailmime_content_charset_get(struct mailmime_content * content)
+{
+ char * charset;
+
+ charset = mailmime_content_param_get(content, "charset");
+ if (charset == NULL)
+ return "us-ascii";
+ else
+ return charset;
+}
+
+char * mailmime_content_param_get(struct mailmime_content * content,
+ char * name)
+{
+ clistiter * cur;
+
+ for(cur = clist_begin(content->ct_parameters) ;
+ cur != NULL ; cur = clist_next(cur)) {
+ struct mailmime_parameter * param;
+
+ param = clist_content(cur);
+
+ if (strcasecmp(param->pa_name, name) == 0)
+ return param->pa_value;
+ }
+
+ return NULL;
+}
+
+
+/*
+ boundary := 0*69<bchars> bcharsnospace
+*/
+
+/*
+ bchars := bcharsnospace / " "
+*/
+
+/*
+ bcharsnospace := DIGIT / ALPHA / "'" / "(" / ")" /
+ "+" / "_" / "," / "-" / "." /
+ "/" / ":" / "=" / "?"
+*/
+
+/*
+ body-part := <"message" as defined in RFC 822, with all
+ header fields optional, not starting with the
+ specified dash-boundary, and with the
+ delimiter not occurring anywhere in the
+ body part. Note that the semantics of a
+ part differ from the semantics of a message,
+ as described in the text.>
+*/
+
+/*
+ close-delimiter := delimiter "--"
+*/
+
+/*
+ dash-boundary := "--" boundary
+ ; boundary taken from the value of
+ ; boundary parameter of the
+ ; Content-Type field.
+*/
+
+/*
+ delimiter := CRLF dash-boundary
+*/
+
+/*
+ discard-text := *(*text CRLF)
+ ; May be ignored or discarded.
+*/
+
+/*
+ encapsulation := delimiter transport-padding
+ CRLF body-part
+*/
+
+/*
+ epilogue := discard-text
+*/
+
+/*
+ multipart-body := [preamble CRLF]
+ dash-boundary transport-padding CRLF
+ body-part *encapsulation
+ close-delimiter transport-padding
+ [CRLF epilogue]
+*/
+
+/*
+ preamble := discard-text
+*/
+
+/*
+ transport-padding := *LWSP-char
+ ; Composers MUST NOT generate
+ ; non-zero length transport
+ ; padding, but receivers MUST
+ ; be able to handle padding
+ ; added by message transports.
+*/
+
+
+/*
+ ACCESS-TYPE
+ EXPIRATION
+ SIZE
+ PERMISSION
+*/
+
+/*
+ 5.2.3.2. The 'ftp' and 'tftp' Access-Types
+ NAME
+ SITE
+
+ (3) Before any data are retrieved, using FTP, the user will
+ generally need to be asked to provide a login id and a
+ password for the machine named by the site parameter.
+ For security reasons, such an id and password are not
+ specified as content-type parameters, but must be
+ obtained from the user.
+
+ optional :
+ DIRECTORY
+ MODE
+*/
+
+/*
+5.2.3.3. The 'anon-ftp' Access-Type
+*/
+
+/*
+5.2.3.4. The 'local-file' Access-Type
+NAME
+SITE
+*/
+
+/*
+5.2.3.5. The 'mail-server' Access-Type
+SERVER
+SUBJECT
+*/
+
+
+enum {
+ PREAMBLE_STATE_A0,
+ PREAMBLE_STATE_A,
+ PREAMBLE_STATE_A1,
+ PREAMBLE_STATE_B,
+ PREAMBLE_STATE_C,
+ PREAMBLE_STATE_D,
+ PREAMBLE_STATE_E
+};
+
+static int mailmime_preamble_parse(const char * message, size_t length,
+ size_t * index, int beol)
+{
+ int state;
+ size_t cur_token;
+
+ cur_token = * index;
+ if (beol)
+ state = PREAMBLE_STATE_A0;
+ else
+ state = PREAMBLE_STATE_A;
+
+ while (state != PREAMBLE_STATE_E) {
+
+ if (cur_token >= length)
+ return MAILIMF_ERROR_PARSE;
+
+ switch (state) {
+ case PREAMBLE_STATE_A0:
+ switch (message[cur_token]) {
+ case '-':
+ state = PREAMBLE_STATE_A1;
+ break;
+ case '\r':
+ state = PREAMBLE_STATE_B;
+ break;
+ case '\n':
+ state = PREAMBLE_STATE_C;
+ break;
+ default:
+ state = PREAMBLE_STATE_A;
+ break;
+ }
+ break;
+
+ case PREAMBLE_STATE_A:
+ switch (message[cur_token]) {
+ case '\r':
+ state = PREAMBLE_STATE_B;
+ break;
+ case '\n':
+ state = PREAMBLE_STATE_C;
+ break;
+ default:
+ state = PREAMBLE_STATE_A;
+ break;
+ }
+ break;
+
+ case PREAMBLE_STATE_A1:
+ switch (message[cur_token]) {
+ case '-':
+ state = PREAMBLE_STATE_E;
+ break;
+ case '\r':
+ state = PREAMBLE_STATE_B;
+ break;
+ case '\n':
+ state = PREAMBLE_STATE_C;
+ break;
+ default:
+ state = PREAMBLE_STATE_A;
+ break;
+ }
+ break;
+
+ case PREAMBLE_STATE_B:
+ switch (message[cur_token]) {
+ case '\r':
+ state = PREAMBLE_STATE_B;
+ break;
+ case '\n':
+ state = PREAMBLE_STATE_C;
+ break;
+ case '-':
+ state = PREAMBLE_STATE_D;
+ break;
+ default:
+ state = PREAMBLE_STATE_A0;
+ break;
+ }
+ break;
+
+ case PREAMBLE_STATE_C:
+ switch (message[cur_token]) {
+ case '-':
+ state = PREAMBLE_STATE_D;
+ break;
+ case '\r':
+ state = PREAMBLE_STATE_B;
+ break;
+ case '\n':
+ state = PREAMBLE_STATE_C;
+ break;
+ default:
+ state = PREAMBLE_STATE_A0;
+ break;
+ }
+ break;
+
+ case PREAMBLE_STATE_D:
+ switch (message[cur_token]) {
+ case '-':
+ state = PREAMBLE_STATE_E;
+ break;
+ default:
+ state = PREAMBLE_STATE_A;
+ break;
+ }
+ break;
+ }
+
+ cur_token ++;
+ }
+
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+}
+
+static int mailmime_boundary_parse(const char * message, size_t length,
+ size_t * index, char * boundary)
+{
+ size_t cur_token;
+ size_t len;
+
+ cur_token = * index;
+
+ len = strlen(boundary);
+
+ if (cur_token + len >= length)
+ return MAILIMF_ERROR_PARSE;
+
+ if (strncmp(message + cur_token, boundary, len) != 0)
+ return MAILIMF_ERROR_PARSE;
+
+ cur_token += len;
+
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+}
+
+static int is_wsp(char ch)
+{
+ if ((ch == ' ') || (ch == '\t'))
+ return TRUE;
+
+ return FALSE;
+}
+
+static int mailmime_lwsp_parse(const char * message, size_t length,
+ size_t * index)
+{
+ size_t cur_token;
+
+ cur_token = * index;
+
+ if (cur_token >= length)
+ return MAILIMF_ERROR_PARSE;
+
+ while (is_wsp(message[cur_token])) {
+ cur_token ++;
+ if (cur_token >= length)
+ break;
+ }
+
+ if (cur_token == * index)
+ return MAILIMF_ERROR_PARSE;
+
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+}
+
+/*
+gboolean mailimf_crlf_parse(gchar * message, guint32 length, guint32 * index)
+*/
+
+enum {
+ BODY_PART_DASH2_STATE_0,
+ BODY_PART_DASH2_STATE_1,
+ BODY_PART_DASH2_STATE_2,
+ BODY_PART_DASH2_STATE_3,
+ BODY_PART_DASH2_STATE_4,
+ BODY_PART_DASH2_STATE_5,
+ BODY_PART_DASH2_STATE_6
+};
+
+static int
+mailmime_body_part_dash2_parse(const char * message, size_t length,
+ size_t * index, char * boundary,
+ const char ** result, size_t * result_size)
+{
+ int state;
+ size_t cur_token;
+ size_t size;
+ size_t begin_text;
+ size_t end_text;
+ int r;
+
+ cur_token = * index;
+ state = BODY_PART_DASH2_STATE_0;
+
+ begin_text = cur_token;
+ end_text = length;
+
+ while (state != BODY_PART_DASH2_STATE_5) {
+
+ if (cur_token >= length)
+ break;
+
+ switch(state) {
+
+ case BODY_PART_DASH2_STATE_0:
+ switch (message[cur_token]) {
+ case '\r':
+ state = BODY_PART_DASH2_STATE_1;
+ break;
+ case '\n':
+ state = BODY_PART_DASH2_STATE_2;
+ break;
+ default:
+ state = BODY_PART_DASH2_STATE_0;
+ break;
+ }
+ break;
+
+ case BODY_PART_DASH2_STATE_1:
+ switch (message[cur_token]) {
+ case '\n':
+ state = BODY_PART_DASH2_STATE_2;
+ break;
+ default:
+ state = BODY_PART_DASH2_STATE_0;
+ break;
+ }
+ break;
+
+ case BODY_PART_DASH2_STATE_2:
+ switch (message[cur_token]) {
+ case '-':
+ end_text = cur_token;
+ state = BODY_PART_DASH2_STATE_3;
+ break;
+ case '\r':
+ state = BODY_PART_DASH2_STATE_1;
+ break;
+ case '\n':
+ state = BODY_PART_DASH2_STATE_2;
+ break;
+ default:
+ state = BODY_PART_DASH2_STATE_0;
+ break;
+ }
+ break;
+
+ case BODY_PART_DASH2_STATE_3:
+ switch (message[cur_token]) {
+ case '\r':
+ state = BODY_PART_DASH2_STATE_1;
+ break;
+ case '\n':
+ state = BODY_PART_DASH2_STATE_2;
+ break;
+ case '-':
+ state = BODY_PART_DASH2_STATE_4;
+ break;
+ default:
+ state = BODY_PART_DASH2_STATE_0;
+ break;
+ }
+ break;
+
+ case BODY_PART_DASH2_STATE_4:
+ r = mailmime_boundary_parse(message, length, &cur_token, boundary);
+ if (r == MAILIMF_NO_ERROR)
+ state = BODY_PART_DASH2_STATE_5;
+ else
+ state = BODY_PART_DASH2_STATE_6;
+
+ break;
+ }
+
+ if ((state != BODY_PART_DASH2_STATE_5) &&
+ (state != BODY_PART_DASH2_STATE_6))
+ cur_token ++;
+
+ if (state == BODY_PART_DASH2_STATE_6)
+ state = BODY_PART_DASH2_STATE_0;
+ }
+
+ size = end_text - begin_text;
+
+#if 0
+ if (size > 0) {
+ end_text --;
+ size --;
+ }
+#endif
+
+ if (size >= 1) {
+ if (message[end_text - 1] == '\r') {
+ end_text --;
+ size --;
+ }
+ else if (size >= 1) {
+ if (message[end_text - 1] == '\n') {
+ end_text --;
+ size --;
+ if (size >= 1) {
+ if (message[end_text - 1] == '\r') {
+ end_text --;
+ size --;
+ }
+ }
+ }
+ }
+ }
+
+ size = end_text - begin_text;
+ if (size == 0)
+ return MAILIMF_ERROR_PARSE;
+
+#if 0
+ body_part = mailimf_body_new(message + begin_text, size);
+ if (body_part == NULL)
+ goto err;
+#endif
+
+ * result = message + begin_text;
+ * result_size = size;
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+#if 0
+ err:
+ return MAILIMF_ERROR_PARSE;
+#endif
+}
+
+static int
+mailmime_body_part_dash2_transport_crlf_parse(const char * message,
+ size_t length,
+ size_t * index, char * boundary,
+ const char ** result, size_t * result_size)
+{
+ size_t cur_token;
+ int r;
+ size_t after_boundary;
+ const char * data_str;
+ size_t data_size;
+ const char * begin_text;
+ const char * end_text;
+
+ cur_token = * index;
+
+ begin_text = message + cur_token;
+ end_text = message + cur_token;
+
+ while (1) {
+ r = mailmime_body_part_dash2_parse(message, length, &cur_token,
+ boundary, &data_str, &data_size);
+ if (r == MAILIMF_NO_ERROR) {
+ end_text = data_str + data_size;
+ }
+ else {
+ return r;
+ }
+
+ /* parse transport-padding */
+ while (1) {
+ r = mailmime_lwsp_parse(message, length, &cur_token);
+ if (r == MAILIMF_NO_ERROR) {
+ /* do nothing */
+ }
+ else if (r == MAILIMF_ERROR_PARSE) {
+ break;
+ }
+ else {
+ return r;
+ }
+ }
+
+ r = mailimf_crlf_parse(message, length, &cur_token);
+ if (r == MAILIMF_NO_ERROR) {
+ break;
+ }
+ else if (r == MAILIMF_ERROR_PARSE) {
+ /* do nothing */
+ }
+ else {
+ return r;
+ }
+ }
+
+ * index = cur_token;
+ * result = begin_text;
+ * result_size = end_text - begin_text;
+
+ return MAILIMF_NO_ERROR;
+}
+
+static int mailmime_multipart_close_parse(const char * message, size_t length,
+ size_t * index);
+
+static int
+mailmime_body_part_dash2_close_parse(const char * message,
+ size_t length,
+ size_t * index, char * boundary,
+ const char ** result, size_t * result_size)
+{
+ size_t cur_token;
+ int r;
+ size_t after_boundary;
+ const char * data_str;
+ size_t data_size;
+ const char * begin_text;
+ const char * end_text;
+
+ cur_token = * index;
+
+ begin_text = message + cur_token;
+ end_text = message + cur_token;
+
+ while (1) {
+ r = mailmime_body_part_dash2_parse(message, length,
+ &cur_token, boundary, &data_str, &data_size);
+ if (r == MAILIMF_NO_ERROR) {
+ end_text = data_str + data_size;
+ }
+ else {
+ return r;
+ }
+
+ r = mailmime_multipart_close_parse(message, length, &cur_token);
+ if (r == MAILIMF_NO_ERROR) {
+ break;
+ }
+ else if (r == MAILIMF_ERROR_PARSE) {
+ /* do nothing */
+ }
+ else {
+ return r;
+ }
+ }
+
+ * index = cur_token;
+ * result = data_str;
+ * result_size = data_size;
+
+ return MAILIMF_NO_ERROR;
+}
+
+enum {
+ MULTIPART_CLOSE_STATE_0,
+ MULTIPART_CLOSE_STATE_1,
+ MULTIPART_CLOSE_STATE_2,
+ MULTIPART_CLOSE_STATE_3,
+ MULTIPART_CLOSE_STATE_4
+};
+
+static int mailmime_multipart_close_parse(const char * message, size_t length,
+ size_t * index)
+{
+ int state;
+ size_t cur_token;
+
+ cur_token = * index;
+ state = MULTIPART_CLOSE_STATE_0;
+
+ while (state != MULTIPART_CLOSE_STATE_4) {
+
+ switch(state) {
+
+ case MULTIPART_CLOSE_STATE_0:
+ if (cur_token >= length)
+ return MAILIMF_ERROR_PARSE;
+
+ switch (message[cur_token]) {
+ case '-':
+ state = MULTIPART_CLOSE_STATE_1;
+ break;
+ default:
+ return MAILIMF_ERROR_PARSE;
+ }
+ break;
+
+ case MULTIPART_CLOSE_STATE_1:
+ if (cur_token >= length)
+ return MAILIMF_ERROR_PARSE;
+
+ switch (message[cur_token]) {
+ case '-':
+ state = MULTIPART_CLOSE_STATE_2;
+ break;
+ default:
+ return MAILIMF_ERROR_PARSE;
+ }
+ break;
+
+ case MULTIPART_CLOSE_STATE_2:
+ if (cur_token >= length) {
+ state = MULTIPART_CLOSE_STATE_4;
+ break;
+ }
+
+ switch (message[cur_token]) {
+ case ' ':
+ state = MULTIPART_CLOSE_STATE_2;
+ break;
+ case '\t':
+ state = MULTIPART_CLOSE_STATE_2;
+ break;
+ case '\r':
+ state = MULTIPART_CLOSE_STATE_3;
+ break;
+ case '\n':
+ state = MULTIPART_CLOSE_STATE_4;
+ break;
+ default:
+ state = MULTIPART_CLOSE_STATE_4;
+ break;
+ }
+ break;
+
+ case MULTIPART_CLOSE_STATE_3:
+ if (cur_token >= length) {
+ state = MULTIPART_CLOSE_STATE_4;
+ break;
+ }
+
+ switch (message[cur_token]) {
+ case '\n':
+ state = MULTIPART_CLOSE_STATE_4;
+ break;
+ default:
+ state = MULTIPART_CLOSE_STATE_4;
+ break;
+ }
+ break;
+ }
+
+ cur_token ++;
+ }
+
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+}
+
+enum {
+ MULTIPART_NEXT_STATE_0,
+ MULTIPART_NEXT_STATE_1,
+ MULTIPART_NEXT_STATE_2
+};
+
+int mailmime_multipart_next_parse(const char * message, size_t length,
+ size_t * index)
+{
+ int state;
+ size_t cur_token;
+
+ cur_token = * index;
+ state = MULTIPART_NEXT_STATE_0;
+
+ while (state != MULTIPART_NEXT_STATE_2) {
+
+ if (cur_token >= length)
+ return MAILIMF_ERROR_PARSE;
+
+ switch(state) {
+
+ case MULTIPART_NEXT_STATE_0:
+ switch (message[cur_token]) {
+ case ' ':
+ state = MULTIPART_NEXT_STATE_0;
+ break;
+ case '\t':
+ state = MULTIPART_NEXT_STATE_0;
+ break;
+ case '\r':
+ state = MULTIPART_NEXT_STATE_1;
+ break;
+ case '\n':
+ state = MULTIPART_NEXT_STATE_2;
+ break;
+ default:
+ return MAILIMF_ERROR_PARSE;
+ }
+ break;
+
+ case MULTIPART_NEXT_STATE_1:
+ switch (message[cur_token]) {
+ case '\n':
+ state = MULTIPART_NEXT_STATE_2;
+ break;
+ default:
+ return MAILIMF_ERROR_PARSE;
+ }
+ break;
+ }
+
+ cur_token ++;
+ }
+
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+}
+
+static int
+mailmime_multipart_body_parse(const char * message, size_t length,
+ size_t * index, char * boundary,
+ int default_subtype,
+ clist ** result,
+ struct mailmime_data ** p_preamble,
+ struct mailmime_data ** p_epilogue)
+{
+ size_t cur_token;
+ clist * list;
+ int r;
+ int res;
+#if 0
+ size_t begin;
+#endif
+ size_t preamble_begin;
+ size_t preamble_length;
+ size_t preamble_end;
+#if 0
+ int no_preamble;
+ size_t before_crlf;
+#endif
+ size_t epilogue_begin;
+ size_t epilogue_length;
+ struct mailmime_data * preamble;
+ struct mailmime_data * epilogue;
+ size_t part_begin;
+ int final_part;
+
+ preamble = NULL;
+ epilogue = NULL;
+
+ cur_token = * index;
+ preamble_begin = cur_token;
+
+#if 0
+ no_preamble = FALSE;
+#endif
+ preamble_end = preamble_begin;
+
+#if 0
+ r = mailmime_preamble_parse(message, length, &cur_token);
+ if (r == MAILIMF_NO_ERROR) {
+ /* do nothing */
+#if 0
+ preamble_end = cur_token - 2;
+#endif
+ }
+ else if (r == MAILIMF_ERROR_PARSE) {
+ /* do nothing */
+ no_preamble = TRUE;
+ }
+ else {
+ res = r;
+ goto err;
+ }
+
+ while (1) {
+
+ preamble_end = cur_token;
+ r = mailmime_boundary_parse(message, length, &cur_token, boundary);
+ if (r == MAILIMF_NO_ERROR) {
+ break;
+ }
+ else if (r == MAILIMF_ERROR_PARSE) {
+ /* do nothing */
+ }
+ else {
+ res = r;
+ goto err;
+ }
+
+ r = mailmime_preamble_parse(message, length, &cur_token);
+ if (r == MAILIMF_NO_ERROR) {
+#if 0
+ preamble_end = cur_token - 2;
+#endif
+ }
+ else if (r == MAILIMF_ERROR_PARSE) {
+ no_preamble = TRUE;
+ break;
+ }
+ else {
+ res = r;
+ goto err;
+ }
+ }
+
+ if (no_preamble) {
+#if 0
+ preamble_end = cur_token;
+#endif
+ }
+ else {
+
+ r = mailmime_lwsp_parse(message, length, &cur_token);
+ if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
+ res = r;
+ goto err;
+ }
+
+ before_crlf = cur_token;
+ r = mailimf_crlf_parse(message, length, &cur_token);
+ if (r == MAILIMF_NO_ERROR) {
+#if 0
+ preamble_end = before_crlf;
+#endif
+ /* remove the CR LF at the end of preamble if any */
+ }
+ else if (r == MAILIMF_ERROR_PARSE) {
+ /* do nothing */
+ }
+ else {
+ res = r;
+ goto err;
+ }
+ }
+ preamble_length = preamble_end - begin;
+#endif
+
+ r = mailmime_preamble_parse(message, length, &cur_token, 1);
+ if (r == MAILIMF_NO_ERROR) {
+ while (1) {
+
+ preamble_end = cur_token;
+ r = mailmime_boundary_parse(message, length, &cur_token, boundary);
+ if (r == MAILIMF_NO_ERROR) {
+ break;
+ }
+ else if (r == MAILIMF_ERROR_PARSE) {
+ /* do nothing */
+ }
+ else {
+ res = r;
+ goto err;
+ }
+
+ r = mailmime_preamble_parse(message, length, &cur_token, 0);
+ if (r == MAILIMF_NO_ERROR) {
+ }
+ else if (r == MAILIMF_ERROR_PARSE) {
+ break;
+ }
+ else {
+ res = r;
+ goto err;
+ }
+ }
+ }
+
+ preamble_end -= 2;
+ if (preamble_end != preamble_begin) {
+ /* try to find the real end of the preamble (strip CR LF) */
+ if (message[preamble_end - 1] == '\n') {
+ preamble_end --;
+ if (preamble_end - 1 >= preamble_begin) {
+ if (message[preamble_end - 1] == '\r')
+ preamble_end --;
+ }
+ }
+ else if (message[preamble_end - 1] == '\r') {
+ preamble_end --;
+ }
+ }
+ preamble_length = preamble_end - preamble_begin;
+
+ part_begin = cur_token;
+ while (1) {
+ r = mailmime_lwsp_parse(message, length, &cur_token);
+ if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
+ res = r;
+ goto err;
+ }
+#if 0
+ if (r == MAILIMF_ERROR_PARSE)
+ break;
+#endif
+
+ r = mailimf_crlf_parse(message, length, &cur_token);
+ if (r == MAILIMF_NO_ERROR) {
+ part_begin = cur_token;
+ }
+ else if (r == MAILIMF_ERROR_PARSE) {
+ /* do nothing */
+ break;
+ }
+ else {
+ res = r;
+ goto err;
+ }
+ }
+
+ cur_token = part_begin;
+
+ list = clist_new();
+ if (list == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto err;
+ }
+
+ final_part = 0;
+
+ while (!final_part) {
+ size_t bp_token;
+ struct mailmime * mime_bp;
+ const char * data_str;
+ size_t data_size;
+ struct mailimf_fields * fields;
+ struct mailmime_fields * mime_fields;
+ int got_crlf;
+ size_t after_boundary;
+
+#if 0
+ /* XXX - begin */
+ r = mailmime_body_part_dash2_parse(message, length, &cur_token,
+ boundary, &data_str, &data_size);
+ if (r == MAILIMF_NO_ERROR) {
+ /* do nothing */
+ }
+ else if (r == MAILIMF_ERROR_PARSE) {
+ break;
+ }
+ else {
+ res = r;
+ goto free;
+ }
+
+ after_boundary = cur_token;
+ got_crlf = 0;
+ /* parse transport-padding */
+ while (1) {
+ r = mailmime_lwsp_parse(message, length, &cur_token);
+ if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
+ res = r;
+ goto free;
+ }
+
+ r = mailimf_crlf_parse(message, length, &cur_token);
+ if (r == MAILIMF_NO_ERROR) {
+ got_crlf = 1;
+ break;
+ }
+ else if (r == MAILIMF_ERROR_PARSE) {
+ /* do nothing */
+ break;
+ }
+ else {
+ res = r;
+ goto free;
+ }
+ }
+ if (after_boundary != cur_token) {
+ if (!got_crlf) {
+ r = mailimf_crlf_parse(message, length, &cur_token);
+ if (r == MAILIMF_NO_ERROR) {
+ got_crlf = 1;
+ break;
+ }
+ }
+ }
+ /* XXX - end */
+#endif
+
+ r = mailmime_body_part_dash2_transport_crlf_parse(message, length,
+ &cur_token, boundary, &data_str, &data_size);
+ if (r == MAILIMF_ERROR_PARSE) {
+ r = mailmime_body_part_dash2_close_parse(message, length,
+ &cur_token, boundary, &data_str, &data_size);
+ if (r == MAILIMF_NO_ERROR) {
+ final_part = 1;
+ }
+ }
+
+ if (r == MAILIMF_NO_ERROR) {
+ bp_token = 0;
+
+ r = mailimf_optional_fields_parse(data_str, data_size,
+ &bp_token, &fields);
+ if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
+ res = r;
+ goto free;
+ }
+
+ r = mailimf_crlf_parse(data_str, data_size, &bp_token);
+ if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
+ mailimf_fields_free(fields);
+ res = r;
+ goto free;
+ }
+
+ mime_fields = NULL;
+ r = mailmime_fields_parse(fields, &mime_fields);
+ mailimf_fields_free(fields);
+ if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
+ res = r;
+ goto free;
+ }
+
+ r = mailmime_parse_with_default(data_str, data_size,
+ &bp_token, default_subtype, NULL,
+ mime_fields, &mime_bp);
+ if (r == MAILIMF_NO_ERROR) {
+ r = clist_append(list, mime_bp);
+ if (r < 0) {
+ mailmime_free(mime_bp);
+ res = MAILIMF_ERROR_MEMORY;
+ goto free;
+ }
+ }
+ else if (r == MAILIMF_ERROR_PARSE) {
+ mailmime_fields_free(mime_fields);
+ break;
+ }
+ else {
+ mailmime_fields_free(mime_fields);
+ res = r;
+ goto free;
+ }
+
+ r = mailmime_multipart_next_parse(message, length, &cur_token);
+ if (r == MAILIMF_NO_ERROR) {
+ /* do nothing */
+ }
+ }
+ else {
+ res = r;
+ goto free;
+ }
+
+#if 0
+ else if (r == MAILIMF_ERROR_PARSE) {
+ r = mailmime_body_part_dash2_parse(message, length,
+ &cur_token, boundary, &data_str, &data_size);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto free;
+ }
+
+ r = mailmime_multipart_close_parse(message, length, &cur_token);
+ if (r == MAILIMF_NO_ERROR) {
+ break;
+ }
+ else if (r == MAILIMF_ERROR_PARSE) {
+ res = r;
+ goto free;
+#if 0
+ fprintf(stderr, "close not found, reparse %s\n", boundary);
+ /* reparse */
+ continue;
+#endif
+ }
+ else {
+ res = r;
+ goto free;
+ }
+ }
+ else {
+ res = r;
+ goto free;
+ }
+#endif
+ }
+
+ epilogue_begin = length;
+ /* parse transport-padding */
+ while (1) {
+ r = mailmime_lwsp_parse(message, length, &cur_token);
+ if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
+ res = r;
+ goto free;
+ }
+
+ if (r == MAILIMF_ERROR_PARSE)
+ break;
+
+#if 0
+ if (r == MAILIMF_ERROR_PARSE)
+ break;
+#endif
+
+#if 0
+ before_crlf = cur_token;
+#endif
+ }
+
+ r = mailimf_crlf_parse(message, length, &cur_token);
+ if (r == MAILIMF_NO_ERROR) {
+ epilogue_begin = cur_token;
+ }
+ else if (r != MAILIMF_ERROR_PARSE) {
+ res = r;
+ goto free;
+ }
+
+ /* add preamble and epilogue */
+
+ epilogue_length = length - epilogue_begin;
+
+ if (preamble_length != 0) {
+ preamble = mailmime_data_new(MAILMIME_DATA_TEXT,
+ MAILMIME_MECHANISM_8BIT, 1,
+ message + preamble_begin, preamble_length,
+ NULL);
+ if (preamble == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free;
+ }
+ }
+
+ if (epilogue_length != 0) {
+ epilogue = mailmime_data_new(MAILMIME_DATA_TEXT,
+ MAILMIME_MECHANISM_8BIT, 1,
+ message + epilogue_begin, epilogue_length,
+ NULL);
+ if (epilogue == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free;
+ }
+ }
+
+ /* end of preamble and epilogue */
+
+ cur_token = length;
+
+ * result = list;
+ * p_preamble = preamble;
+ * p_epilogue = epilogue;
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+
+ free:
+ if (epilogue != NULL)
+ mailmime_data_free(epilogue);
+ if (preamble != NULL)
+ mailmime_data_free(preamble);
+ clist_foreach(list, (clist_func) mailmime_free, NULL);
+ clist_free(list);
+ err:
+ return res;
+}
+
+enum {
+ MAILMIME_DEFAULT_TYPE_TEXT_PLAIN,
+ MAILMIME_DEFAULT_TYPE_MESSAGE
+};
+
+
+int mailmime_parse(const char * message, size_t length,
+ size_t * index, struct mailmime ** result)
+{
+ struct mailmime * mime;
+ int r;
+ int res;
+ struct mailmime_content * content_message;
+ size_t cur_token;
+ struct mailmime_fields * mime_fields;
+ const char * data_str;
+ size_t data_size;
+ size_t bp_token;
+
+ cur_token = * index;
+
+ content_message = mailmime_get_content_message();
+ if (content_message == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto err;
+ }
+
+#if 0
+ mime_fields = mailmime_fields_new_with_data(content_message,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL);
+ if (mime_fields == NULL) {
+ mailmime_content_free(content_message);
+ res = MAILIMF_ERROR_MEMORY;
+ goto err;
+ }
+#endif
+ mime_fields = mailmime_fields_new_empty();
+ if (mime_fields == NULL) {
+ mailmime_content_free(content_message);
+ res = MAILIMF_ERROR_MEMORY;
+ goto err;
+ }
+
+ data_str = message + cur_token;
+ data_size = length - cur_token;
+
+ bp_token = 0;
+ r = mailmime_parse_with_default(data_str, data_size,
+ &bp_token, MAILMIME_DEFAULT_TYPE_TEXT_PLAIN,
+ content_message, mime_fields, &mime);
+ cur_token += bp_token;
+ if (r != MAILIMF_NO_ERROR) {
+ mailmime_fields_free(mime_fields);
+ res = r;
+ goto free;
+ }
+
+ * index = cur_token;
+ * result = mime;
+
+ return MAILIMF_NO_ERROR;
+
+ free:
+ mailmime_fields_free(mime_fields);
+ err:
+ return res;
+}
+
+
+char * mailmime_extract_boundary(struct mailmime_content * content_type)
+{
+ char * boundary;
+
+ boundary = mailmime_content_param_get(content_type, "boundary");
+
+ if (boundary != NULL) {
+ int len;
+ char * new_boundary;
+
+ len = strlen(boundary);
+ new_boundary = malloc(len + 1);
+ if (new_boundary == NULL)
+ return NULL;
+
+ if (boundary[0] == '"') {
+ strncpy(new_boundary, boundary + 1, len - 2);
+ new_boundary[len - 2] = 0;
+ }
+ else
+ strcpy(new_boundary, boundary);
+
+ boundary = new_boundary;
+ }
+
+ return boundary;
+}
+
+static void remove_unparsed_mime_headers(struct mailimf_fields * fields)
+{
+ clistiter * cur;
+
+ cur = clist_begin(fields->fld_list);
+ while (cur != NULL) {
+ struct mailimf_field * field;
+ int delete;
+
+ field = clist_content(cur);
+
+ switch (field->fld_type) {
+ case MAILIMF_FIELD_OPTIONAL_FIELD:
+ delete = 0;
+ if (strncasecmp(field->fld_data.fld_optional_field->fld_name,
+ "Content-", 8) == 0) {
+ char * name;
+
+ name = field->fld_data.fld_optional_field->fld_name + 8;
+ if ((strcasecmp(name, "Type") == 0)
+ || (strcasecmp(name, "Transfer-Encoding") == 0)
+ || (strcasecmp(name, "ID") == 0)
+ || (strcasecmp(name, "Description") == 0)
+ || (strcasecmp(name, "Disposition") == 0)
+ || (strcasecmp(name, "Language") == 0)) {
+ delete = 1;
+ }
+ }
+ else if (strcasecmp(field->fld_data.fld_optional_field->fld_name,
+ "MIME-Version") == 0) {
+ delete = 1;
+ }
+
+ if (delete) {
+ cur = clist_delete(fields->fld_list, cur);
+ mailimf_field_free(field);
+ }
+ else {
+ cur = clist_next(cur);
+ }
+ break;
+
+ default:
+ cur = clist_next(cur);
+ }
+ }
+}
+
+static int mailmime_parse_with_default(const char * message, size_t length,
+ size_t * index, int default_type,
+ struct mailmime_content * content_type,
+ struct mailmime_fields * mime_fields,
+ struct mailmime ** result)
+{
+ size_t cur_token;
+
+ int body_type;
+
+ int encoding;
+ struct mailmime_data * body;
+ char * boundary;
+ struct mailimf_fields * fields;
+ clist * list;
+ struct mailmime * msg_mime;
+
+ struct mailmime * mime;
+
+ int r;
+ int res;
+ struct mailmime_data * preamble;
+ struct mailmime_data * epilogue;
+
+ /*
+ note that when this function is called, content type is always detached,
+ even if the function fails
+ */
+
+ preamble = NULL;
+ epilogue = NULL;
+
+ cur_token = * index;
+
+ /* get content type */
+
+ if (content_type == NULL) {
+ if (mime_fields != NULL) {
+ clistiter * cur;
+
+ for(cur = clist_begin(mime_fields->fld_list) ; cur != NULL ;
+ cur = clist_next(cur)) {
+ struct mailmime_field * field;
+
+ field = clist_content(cur);
+ if (field->fld_type == MAILMIME_FIELD_TYPE) {
+ content_type = field->fld_data.fld_content;
+
+ /* detach content type from list */
+ field->fld_data.fld_content = NULL;
+ clist_delete(mime_fields->fld_list, cur);
+ mailmime_field_free(field);
+ /*
+ there may be a leak due to the detached content type
+ in case the function fails
+ */
+ break;
+ }
+ }
+ }
+ }
+
+ /* set default type if no content type */
+
+ if (content_type == NULL) {
+ /* content_type is detached, in any case, we will have to free it */
+ if (default_type == MAILMIME_DEFAULT_TYPE_TEXT_PLAIN) {
+ content_type = mailmime_get_content_text();
+ if (content_type == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto err;
+ }
+ }
+ else /* message */ {
+ body_type = MAILMIME_MESSAGE;
+
+ content_type = mailmime_get_content_message();
+ if (content_type == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto err;
+ }
+ }
+ }
+
+ /* get the body type */
+
+ boundary = NULL; /* XXX - removes a gcc warning */
+
+ switch (content_type->ct_type->tp_type) {
+ case MAILMIME_TYPE_COMPOSITE_TYPE:
+ switch (content_type->ct_type->tp_data.tp_composite_type->ct_type) {
+ case MAILMIME_COMPOSITE_TYPE_MULTIPART:
+ boundary = mailmime_extract_boundary(content_type);
+
+ if (boundary == NULL)
+ body_type = MAILMIME_SINGLE;
+ else
+ body_type = MAILMIME_MULTIPLE;
+ break;
+
+ case MAILMIME_COMPOSITE_TYPE_MESSAGE:
+
+ if (strcasecmp(content_type->ct_subtype, "rfc822") == 0)
+ body_type = MAILMIME_MESSAGE;
+ else
+ body_type = MAILMIME_SINGLE;
+ break;
+
+ default:
+ res = MAILIMF_ERROR_INVAL;
+ goto free_content;
+ }
+ break;
+
+ default: /* MAILMIME_TYPE_DISCRETE_TYPE */
+ body_type = MAILMIME_SINGLE;
+ break;
+ }
+
+ /* set body */
+
+ if (mime_fields != NULL)
+ encoding = mailmime_transfer_encoding_get(mime_fields);
+ else
+ encoding = MAILMIME_MECHANISM_8BIT;
+
+ cur_token = * index;
+ body = mailmime_data_new(MAILMIME_DATA_TEXT, encoding, 1,
+ message + cur_token, length - cur_token,
+ NULL);
+ if (body == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free_content;
+ }
+
+ /* in case of composite, parse the sub-part(s) */
+
+ list = NULL;
+ msg_mime = NULL;
+ fields = NULL;
+
+ switch (body_type) {
+ case MAILMIME_MESSAGE:
+ {
+ struct mailmime_fields * submime_fields;
+
+ r = mailimf_envelope_and_optional_fields_parse(message, length,
+ &cur_token, &fields);
+ if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
+ res = r;
+ goto free_content;
+ }
+
+ r = mailimf_crlf_parse(message, length, &cur_token);
+ if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
+ mailimf_fields_free(fields);
+ res = r;
+ goto free_content;
+ }
+
+ submime_fields = NULL;
+ r = mailmime_fields_parse(fields, &submime_fields);
+ if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
+ mailimf_fields_free(fields);
+ res = r;
+ goto free_content;
+ }
+
+ remove_unparsed_mime_headers(fields);
+
+ r = mailmime_parse_with_default(message, length,
+ &cur_token, MAILMIME_DEFAULT_TYPE_TEXT_PLAIN,
+ NULL, submime_fields, &msg_mime);
+ if (r == MAILIMF_NO_ERROR) {
+ /* do nothing */
+ }
+ else if (r == MAILIMF_ERROR_PARSE) {
+ mailmime_fields_free(mime_fields);
+ msg_mime = NULL;
+ }
+ else {
+ mailmime_fields_free(mime_fields);
+ res = r;
+ goto free_content;
+ }
+ }
+
+ break;
+
+ case MAILMIME_MULTIPLE:
+ {
+ int default_subtype;
+
+ default_subtype = MAILMIME_DEFAULT_TYPE_TEXT_PLAIN;
+ if (content_type != NULL)
+ if (strcasecmp(content_type->ct_subtype, "digest") == 0)
+ default_subtype = MAILMIME_DEFAULT_TYPE_MESSAGE;
+
+ cur_token = * index;
+ r = mailmime_multipart_body_parse(message, length,
+ &cur_token, boundary,
+ default_subtype,
+ &list, &preamble, &epilogue);
+ if (r == MAILIMF_NO_ERROR) {
+ /* do nothing */
+ }
+ else if (r == MAILIMF_ERROR_PARSE) {
+ list = clist_new();
+ if (list == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free_content;
+ }
+ }
+ else {
+ res = r;
+ goto free_content;
+ }
+
+ free(boundary);
+ }
+ break;
+
+ default: /* MAILMIME_SINGLE */
+ /* do nothing */
+ break;
+ }
+
+ mime = mailmime_new(body_type, message, length,
+ mime_fields, content_type,
+ body, preamble, /* preamble */
+ epilogue, /* epilogue */
+ list, fields, msg_mime);
+ if (mime == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free;
+ }
+
+ * result = mime;
+ * index = length;
+
+ return MAILIMF_NO_ERROR;
+
+ free:
+ if (epilogue != NULL)
+ mailmime_data_free(epilogue);
+ if (preamble != NULL)
+ mailmime_data_free(preamble);
+ if (msg_mime != NULL)
+ mailmime_free(msg_mime);
+ if (list != NULL) {
+ clist_foreach(list, (clist_func) mailmime_free, NULL);
+ clist_free(list);
+ }
+ free_content:
+ mailmime_content_free(content_type);
+ err:
+ return res;
+}
+
+static int mailmime_get_section_list(struct mailmime * mime,
+ clistiter * list, struct mailmime ** result)
+{
+ uint32_t id;
+ struct mailmime * data;
+ struct mailmime * submime;
+
+ if (list == NULL) {
+ * result = mime;
+ return MAILIMF_NO_ERROR;
+ }
+
+ id = * ((uint32_t *) clist_content(list));
+
+ data = NULL;
+ switch (mime->mm_type) {
+ case MAILMIME_SINGLE:
+ return MAILIMF_ERROR_INVAL;
+
+ case MAILMIME_MULTIPLE:
+ data = clist_nth_data(mime->mm_data.mm_multipart.mm_mp_list, id - 1);
+ if (data == NULL)
+ return MAILIMF_ERROR_INVAL;
+
+ if (clist_next(list) != NULL)
+ return mailmime_get_section_list(data, clist_next(list), result);
+ else {
+ * result = data;
+ return MAILIMF_NO_ERROR;
+ }
+
+ case MAILMIME_MESSAGE:
+ submime = mime->mm_data.mm_message.mm_msg_mime;
+ switch (submime->mm_type) {
+ case MAILMIME_MULTIPLE:
+ data = clist_nth_data(submime->mm_data.mm_multipart.mm_mp_list, id - 1);
+ if (data == NULL)
+ return MAILIMF_ERROR_INVAL;
+ return mailmime_get_section_list(data, clist_next(list), result);
+
+ default:
+ if (id != 1)
+ return MAILIMF_ERROR_INVAL;
+
+ data = submime;
+ if (data == NULL)
+ return MAILIMF_ERROR_INVAL;
+
+ return mailmime_get_section_list(data, clist_next(list), result);
+ }
+ break;
+
+ default:
+ return MAILIMF_ERROR_INVAL;
+ }
+}
+
+int mailmime_get_section(struct mailmime * mime,
+ struct mailmime_section * section,
+ struct mailmime ** result)
+{
+ return mailmime_get_section_list(mime,
+ clist_begin(section->sec_list), result);
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+/* ************************************************************************* */
+/* MIME part decoding */
+
+static inline signed char get_base64_value(char ch)
+{
+ if ((ch >= 'A') && (ch <= 'Z'))
+ return ch - 'A';
+ if ((ch >= 'a') && (ch <= 'z'))
+ return ch - 'a' + 26;
+ if ((ch >= '0') && (ch <= '9'))
+ return ch - '0' + 52;
+ switch (ch) {
+ case '+':
+ return 62;
+ case '/':
+ return 63;
+ case '=': /* base64 padding */
+ return -1;
+ default:
+ return -1;
+ }
+}
+
+int mailmime_base64_body_parse(const char * message, size_t length,
+ size_t * index, char ** result,
+ size_t * result_len)
+{
+ size_t cur_token;
+ size_t i;
+ char chunk[4];
+ int chunk_index;
+ char out[3];
+ MMAPString * mmapstr;
+ int res;
+ int r;
+ size_t written;
+
+ cur_token = * index;
+ chunk_index = 0;
+ written = 0;
+
+ mmapstr = mmap_string_sized_new((length - cur_token) * 3 / 4);
+ if (mmapstr == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto err;
+ }
+
+ i = 0;
+ while (1) {
+ signed char value;
+
+ value = -1;
+ while (value == -1) {
+
+ if (cur_token >= length)
+ break;
+
+ value = get_base64_value(message[cur_token]);
+ cur_token ++;
+ }
+
+ if (value == -1)
+ break;
+
+ chunk[chunk_index] = value;
+ chunk_index ++;
+
+ if (chunk_index == 4) {
+ out[0] = (chunk[0] << 2) | (chunk[1] >> 4);
+ out[1] = (chunk[1] << 4) | (chunk[2] >> 2);
+ out[2] = (chunk[2] << 6) | (chunk[3]);
+
+ chunk[0] = 0;
+ chunk[1] = 0;
+ chunk[2] = 0;
+ chunk[3] = 0;
+
+ chunk_index = 0;
+
+ if (mmap_string_append_len(mmapstr, out, 3) == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free;
+ }
+ written += 3;
+ }
+ }
+
+ if (chunk_index != 0) {
+ size_t len;
+
+ len = 0;
+ out[0] = (chunk[0] << 2) | (chunk[1] >> 4);
+ len ++;
+
+ if (chunk_index >= 3) {
+ out[1] = (chunk[1] << 4) | (chunk[2] >> 2);
+ len ++;
+ }
+
+ if (mmap_string_append_len(mmapstr, out, len) == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free;
+ }
+ written += len;
+ }
+
+ r = mmap_string_ref(mmapstr);
+ if (r < 0) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free;
+ }
+
+ * index = cur_token;
+ * result = mmapstr->str;
+ * result_len = written;
+
+ return MAILIMF_NO_ERROR;
+
+ free:
+ mmap_string_free(mmapstr);
+ err:
+ return res;
+}
+
+
+
+static inline int hexa_to_char(char hexdigit)
+{
+ if ((hexdigit >= '0') && (hexdigit <= '9'))
+ return hexdigit - '0';
+ if ((hexdigit >= 'a') && (hexdigit <= 'f'))
+ return hexdigit - 'a' + 10;
+ if ((hexdigit >= 'A') && (hexdigit <= 'F'))
+ return hexdigit - 'A' + 10;
+ return 0;
+}
+
+static inline char to_char(const char * hexa)
+{
+ return (hexa_to_char(hexa[0]) << 4) | hexa_to_char(hexa[1]);
+}
+
+enum {
+ STATE_NORMAL,
+ STATE_CODED,
+ STATE_OUT,
+ STATE_CR,
+};
+
+
+static int write_decoded_qp(MMAPString * mmapstr,
+ const char * start, size_t count)
+{
+ if (mmap_string_append_len(mmapstr, start, count) == NULL)
+ return MAILIMF_ERROR_MEMORY;
+
+ return MAILIMF_NO_ERROR;
+}
+
+
+#define WRITE_MAX_QP 512
+
+int mailmime_quoted_printable_body_parse(const char * message, size_t length,
+ size_t * index, char ** result,
+ size_t * result_len, int in_header)
+{
+ size_t cur_token;
+ int state;
+ int r;
+ char ch;
+ size_t count;
+ const char * start;
+ MMAPString * mmapstr;
+ int res;
+ size_t written;
+
+ state = STATE_NORMAL;
+ cur_token = * index;
+
+ count = 0;
+ start = message + cur_token;
+ written = 0;
+
+ mmapstr = mmap_string_sized_new(length - cur_token);
+ if (mmapstr == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto err;
+ }
+
+#if 0
+ if (length >= 1) {
+ if (message[length - 1] == '\n') {
+ length --;
+ if (length >= 1)
+ if (message[length - 1] == '\r') {
+ length --;
+ }
+ }
+ }
+#endif
+
+ while (state != STATE_OUT) {
+
+ if (cur_token >= length) {
+ state = STATE_OUT;
+ break;
+ }
+
+ switch (state) {
+
+ case STATE_CODED:
+
+ if (count > 0) {
+ r = write_decoded_qp(mmapstr, start, count);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto free;
+ }
+ written += count;
+ count = 0;
+ }
+
+ switch (message[cur_token]) {
+ case '=':
+ if (cur_token + 1 >= length) {
+ /* error but ignore it */
+ state = STATE_NORMAL;
+ start = message + cur_token;
+ cur_token ++;
+ count ++;
+ break;
+ }
+
+ switch (message[cur_token + 1]) {
+
+ case '\n':
+ cur_token += 2;
+
+ start = message + cur_token;
+
+ state = STATE_NORMAL;
+ break;
+
+ case '\r':
+ if (cur_token + 2 >= length) {
+ state = STATE_OUT;
+ break;
+ }
+
+ if (message[cur_token + 2] == '\n')
+ cur_token += 3;
+ else
+ cur_token += 2;
+
+ start = message + cur_token;
+
+ state = STATE_NORMAL;
+
+ break;
+
+ default:
+ if (cur_token + 2 >= length) {
+ /* error but ignore it */
+ cur_token ++;
+
+ start = message + cur_token;
+
+ count ++;
+ state = STATE_NORMAL;
+ break;
+ }
+
+#if 0
+ /* flush before writing additionnal information */
+ r = write_decoded_qp(mmapstr, start, count);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto free;
+ }
+ written += count;
+ count = 0;
+#endif
+
+ ch = to_char(message + cur_token + 1);
+
+ if (mmap_string_append_c(mmapstr, ch) == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free;
+ }
+
+ cur_token += 3;
+ written ++;
+
+ start = message + cur_token;
+
+ state = STATE_NORMAL;
+ break;
+ }
+ break;
+ }
+ break; /* end of STATE_ENCODED */
+
+ case STATE_NORMAL:
+
+ switch (message[cur_token]) {
+
+ case '=':
+ state = STATE_CODED;
+ break;
+
+ case '\n':
+ /* flush before writing additionnal information */
+ if (count > 0) {
+ r = write_decoded_qp(mmapstr, start, count);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto free;
+ }
+ written += count;
+
+ count = 0;
+ }
+
+ r = write_decoded_qp(mmapstr, "\r\n", 2);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto free;
+ }
+ written += 2;
+ cur_token ++;
+ start = message + cur_token;
+ break;
+
+ case '\r':
+ state = STATE_CR;
+ cur_token ++;
+ break;
+
+ case '_':
+ if (in_header) {
+ if (count > 0) {
+ r = write_decoded_qp(mmapstr, start, count);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto free;
+ }
+ written += count;
+ count = 0;
+ }
+
+ if (mmap_string_append_c(mmapstr, ' ') == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free;
+ }
+
+ written ++;
+ cur_token ++;
+ start = message + cur_token;
+
+ break;
+ }
+ /* WARINING : must be followed by switch default action */
+
+ default:
+ if (count >= WRITE_MAX_QP) {
+ r = write_decoded_qp(mmapstr, start, count);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto free;
+ }
+ written += count;
+ count = 0;
+ start = message + cur_token;
+ }
+
+ count ++;
+ cur_token ++;
+ break;
+ }
+ break; /* end of STATE_NORMAL */
+
+ case STATE_CR:
+ switch (message[cur_token]) {
+
+ case '\n':
+ /* flush before writing additionnal information */
+ if (count > 0) {
+ r = write_decoded_qp(mmapstr, start, count);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto free;
+ }
+ written += count;
+ count = 0;
+ }
+
+ r = write_decoded_qp(mmapstr, "\r\n", 2);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto free;
+ }
+ written += 2;
+ cur_token ++;
+ start = message + cur_token;
+ state = STATE_NORMAL;
+ break;
+
+ default:
+ /* flush before writing additionnal information */
+ if (count > 0) {
+ r = write_decoded_qp(mmapstr, start, count);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto free;
+ }
+ written += count;
+ count = 0;
+ }
+
+ start = message + cur_token;
+
+ r = write_decoded_qp(mmapstr, "\r\n", 2);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto free;
+ }
+ written += 2;
+ state = STATE_NORMAL;
+ }
+ break; /* end of STATE_CR */
+ }
+ }
+
+ if (count > 0) {
+ r = write_decoded_qp(mmapstr, start, count);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto free;
+ }
+ written += count;
+ count = 0;
+ }
+
+ r = mmap_string_ref(mmapstr);
+ if (r < 0) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free;
+ }
+
+ * index = cur_token;
+ * result = mmapstr->str;
+ * result_len = written;
+
+ return MAILIMF_NO_ERROR;
+
+ free:
+ mmap_string_free(mmapstr);
+ err:
+ return res;
+}
+
+int mailmime_binary_body_parse(const char * message, size_t length,
+ size_t * index, char ** result,
+ size_t * result_len)
+{
+ MMAPString * mmapstr;
+ size_t cur_token;
+ int r;
+ int res;
+
+ cur_token = * index;
+
+ if (length >= 1) {
+ if (message[length - 1] == '\n') {
+ length --;
+ if (length >= 1)
+ if (message[length - 1] == '\r')
+ length --;
+ }
+ }
+
+ mmapstr = mmap_string_new_len(message + cur_token, length - cur_token);
+ if (mmapstr == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto err;
+ }
+
+ r = mmap_string_ref(mmapstr);
+ if (r < 0) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free;
+ }
+
+ * index = length;
+ * result = mmapstr->str;
+ * result_len = length - cur_token;
+
+ return MAILIMF_NO_ERROR;
+
+ free:
+ mmap_string_free(mmapstr);
+ err:
+ return res;
+}
+
+
+int mailmime_part_parse(const char * message, size_t length,
+ size_t * index,
+ int encoding, char ** result, size_t * result_len)
+{
+ switch (encoding) {
+ case MAILMIME_MECHANISM_BASE64:
+ return mailmime_base64_body_parse(message, length, index,
+ result, result_len);
+
+ case MAILMIME_MECHANISM_QUOTED_PRINTABLE:
+ return mailmime_quoted_printable_body_parse(message, length, index,
+ result, result_len, FALSE);
+
+ case MAILMIME_MECHANISM_7BIT:
+ case MAILMIME_MECHANISM_8BIT:
+ case MAILMIME_MECHANISM_BINARY:
+ default:
+ return mailmime_binary_body_parse(message, length, index,
+ result, result_len);
+ }
+}
+
+int mailmime_get_section_id(struct mailmime * mime,
+ struct mailmime_section ** result)
+{
+ clist * list;
+ int res;
+ struct mailmime_section * section_id;
+ int r;
+
+ if (mime->mm_parent == NULL) {
+ list = clist_new();
+ if (list == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto err;
+ }
+
+ section_id = mailmime_section_new(list);
+ if (section_id == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto err;
+ }
+ }
+ else {
+ uint32_t id;
+ uint32_t * p_id;
+ clistiter * cur;
+ struct mailmime * parent;
+
+ r = mailmime_get_section_id(mime->mm_parent, &section_id);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ parent = mime->mm_parent;
+ switch (parent->mm_type) {
+ case MAILMIME_MULTIPLE:
+ id = 1;
+ for(cur = clist_begin(parent->mm_data.mm_multipart.mm_mp_list) ;
+ cur != NULL ; cur = clist_next(cur)) {
+ if (clist_content(cur) == mime)
+ break;
+ id ++;
+ }
+
+ p_id = malloc(sizeof(* p_id));
+ if (p_id == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free;
+ }
+ * p_id = id;
+
+ r = clist_append(section_id->sec_list, p_id);
+ if (r < 0) {
+ free(p_id);
+ res = MAILIMF_ERROR_MEMORY;
+ goto free;
+ }
+ break;
+
+ case MAILMIME_MESSAGE:
+ if ((mime->mm_type == MAILMIME_SINGLE) ||
+ (mime->mm_type == MAILMIME_MESSAGE)) {
+ p_id = malloc(sizeof(* p_id));
+ if (p_id == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free;
+ }
+ * p_id = 1;
+
+ r = clist_append(section_id->sec_list, p_id);
+ if (r < 0) {
+ free(p_id);
+ res = MAILIMF_ERROR_MEMORY;
+ goto free;
+ }
+ }
+ }
+ }
+
+ * result = section_id;
+
+ return MAILIMF_NO_ERROR;
+
+ free:
+ mailmime_section_free(section_id);
+ err:
+ return res;
+}
diff --git a/libetpan/src/low-level/mime/mailmime_content.h b/libetpan/src/low-level/mime/mailmime_content.h
new file mode 100644
index 0000000..989e515
--- a/dev/null
+++ b/libetpan/src/low-level/mime/mailmime_content.h
@@ -0,0 +1,89 @@
+/*
+ * 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$
+ */
+
+#ifndef MAILMIME_CONTENT_H
+
+#define MAILMIME_CONTENT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <libetpan/mailmime_types.h>
+
+char * mailmime_content_charset_get(struct mailmime_content * content);
+
+char * mailmime_content_param_get(struct mailmime_content * content,
+ char * name);
+
+int mailmime_parse(const char * message, size_t length,
+ size_t * index, struct mailmime ** result);
+
+int mailmime_get_section(struct mailmime * mime,
+ struct mailmime_section * section,
+ struct mailmime ** result);
+
+
+char * mailmime_extract_boundary(struct mailmime_content * content_type);
+
+
+/* decode */
+
+int mailmime_base64_body_parse(const char * message, size_t length,
+ size_t * index, char ** result,
+ size_t * result_len);
+
+int mailmime_quoted_printable_body_parse(const char * message, size_t length,
+ size_t * index, char ** result,
+ size_t * result_len, int in_header);
+
+
+int mailmime_binary_body_parse(const char * message, size_t length,
+ size_t * index, char ** result,
+ size_t * result_len);
+
+int mailmime_part_parse(const char * message, size_t length,
+ size_t * index,
+ int encoding, char ** result, size_t * result_len);
+
+
+int mailmime_get_section_id(struct mailmime * mime,
+ struct mailmime_section ** result);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libetpan/src/low-level/mime/mailmime_decode.c b/libetpan/src/low-level/mime/mailmime_decode.c
new file mode 100644
index 0000000..715ddad
--- a/dev/null
+++ b/libetpan/src/low-level/mime/mailmime_decode.c
@@ -0,0 +1,544 @@
+/*
+ * 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$
+ */
+
+/*
+ RFC 2047 : MIME (Multipurpose Internet Mail Extensions) Part Three:
+ Message Header Extensions for Non-ASCII Text
+*/
+
+#include "mailmime_decode.h"
+
+#include <ctype.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "mailmime_content.h"
+
+#include "charconv.h"
+#include "mmapstring.h"
+#include "mailimf.h"
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+static int mailmime_charset_parse(const char * message, size_t length,
+ size_t * index, char ** charset);
+
+enum {
+ MAILMIME_ENCODING_B,
+ MAILMIME_ENCODING_Q
+};
+
+static int mailmime_encoding_parse(const char * message, size_t length,
+ size_t * index, int * result);
+
+static int mailmime_etoken_parse(const char * message, size_t length,
+ size_t * index, char ** result);
+
+static int
+mailmime_non_encoded_word_parse(const char * message, size_t length,
+ size_t * index,
+ char ** result);
+
+static int
+mailmime_encoded_word_parse(const char * message, size_t length,
+ size_t * index,
+ struct mailmime_encoded_word ** result);
+
+
+enum {
+ TYPE_ERROR,
+ TYPE_WORD,
+ TYPE_ENCODED_WORD,
+};
+
+int mailmime_encoded_phrase_parse(const char * default_fromcode,
+ const char * message, size_t length,
+ size_t * index, const char * tocode,
+ char ** result)
+{
+ MMAPString * gphrase;
+ struct mailmime_encoded_word * word;
+ int first;
+ size_t cur_token;
+ int r;
+ int res;
+ char * str;
+ char * wordutf8;
+ int type;
+
+ cur_token = * index;
+
+ gphrase = mmap_string_new("");
+ if (gphrase == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto err;
+ }
+
+ first = TRUE;
+
+ type = TYPE_ERROR; /* XXX - removes a gcc warning */
+
+ while (1) {
+
+ r = mailmime_encoded_word_parse(message, length, &cur_token, &word);
+ if (r == MAILIMF_NO_ERROR) {
+ if (!first) {
+ if (type != TYPE_ENCODED_WORD) {
+ if (mmap_string_append_c(gphrase, ' ') == NULL) {
+ mailmime_encoded_word_free(word);
+ res = MAILIMF_ERROR_MEMORY;
+ goto free;
+ }
+ }
+ }
+ type = TYPE_ENCODED_WORD;
+ wordutf8 = NULL;
+ r = charconv(tocode, word->wd_charset, word->wd_text,
+ strlen(word->wd_text), &wordutf8);
+ switch (r) {
+ case MAIL_CHARCONV_ERROR_MEMORY:
+ mailmime_encoded_word_free(word);
+ res = MAILIMF_ERROR_MEMORY;
+ goto free;
+
+ case MAIL_CHARCONV_ERROR_UNKNOWN_CHARSET:
+ case MAIL_CHARCONV_ERROR_CONV:
+ mailmime_encoded_word_free(word);
+ res = MAILIMF_ERROR_PARSE;
+ goto free;
+ }
+
+ if (wordutf8 != NULL) {
+ if (mmap_string_append(gphrase, wordutf8) == NULL) {
+ mailmime_encoded_word_free(word);
+ free(wordutf8);
+ res = MAILIMF_ERROR_MEMORY;
+ goto free;
+ }
+ free(wordutf8);
+ }
+ mailmime_encoded_word_free(word);
+ first = FALSE;
+ }
+ else if (r == MAILIMF_ERROR_PARSE) {
+ /* do nothing */
+ }
+ else {
+ res = r;
+ goto free;
+ }
+
+ if (r == MAILIMF_ERROR_PARSE) {
+ char * raw_word;
+
+ r = mailmime_non_encoded_word_parse(message, length,
+ &cur_token, &raw_word);
+ if (r == MAILIMF_NO_ERROR) {
+ if (!first) {
+ if (mmap_string_append_c(gphrase, ' ') == NULL) {
+ free(raw_word);
+ res = MAILIMF_ERROR_MEMORY;
+ goto free;
+ }
+ }
+ type = TYPE_WORD;
+
+ wordutf8 = NULL;
+ r = charconv(tocode, default_fromcode, raw_word,
+ strlen(raw_word), &wordutf8);
+
+ switch (r) {
+ case MAIL_CHARCONV_ERROR_MEMORY:
+ free(raw_word);
+ res = MAILIMF_ERROR_MEMORY;
+ goto free;
+
+ case MAIL_CHARCONV_ERROR_UNKNOWN_CHARSET:
+ case MAIL_CHARCONV_ERROR_CONV:
+ free(raw_word);
+ res = MAILIMF_ERROR_PARSE;
+ goto free;
+ }
+
+ if (mmap_string_append(gphrase, wordutf8) == NULL) {
+ free(wordutf8);
+ free(raw_word);
+ res = MAILIMF_ERROR_MEMORY;
+ goto free;
+ }
+
+ free(wordutf8);
+ free(raw_word);
+ first = FALSE;
+ }
+ else if (r == MAILIMF_ERROR_PARSE) {
+ break;
+ }
+ else {
+ res = r;
+ goto free;
+ }
+ }
+ }
+
+ if (first) {
+ res = MAILIMF_ERROR_PARSE;
+ goto free;
+ }
+
+ str = strdup(gphrase->str);
+ if (str == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free;
+ }
+ mmap_string_free(gphrase);
+
+ * result = str;
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+
+ free:
+ mmap_string_free(gphrase);
+ err:
+ return res;
+}
+
+static int
+mailmime_non_encoded_word_parse(const char * message, size_t length,
+ size_t * index,
+ char ** result)
+{
+ int end;
+ size_t cur_token;
+ int res;
+ char * text;
+ int r;
+ size_t begin;
+
+ cur_token = * index;
+
+ r = mailimf_fws_parse(message, length, &cur_token);
+ if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
+ res = r;
+ goto err;
+ }
+
+ begin = cur_token;
+
+ end = FALSE;
+ while (1) {
+ if (cur_token >= length)
+ break;
+
+ switch (message[cur_token]) {
+ case ' ':
+ case '\t':
+ case '\r':
+ case '\n':
+ end = TRUE;
+ break;
+ }
+
+ if (end)
+ break;
+
+ cur_token ++;
+ }
+
+ if (cur_token - begin == 0) {
+ res = MAILIMF_ERROR_PARSE;
+ goto err;
+ }
+
+ text = malloc(cur_token - begin + 1);
+ if (text == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto err;
+ }
+
+ memcpy(text, message + begin, cur_token - begin);
+ text[cur_token - begin] = '\0';
+
+ * index = cur_token;
+ * result = text;
+
+ return MAILIMF_NO_ERROR;
+
+ err:
+ return res;
+}
+
+static int mailmime_encoded_word_parse(const char * message, size_t length,
+ size_t * index,
+ struct mailmime_encoded_word ** result)
+{
+ size_t cur_token;
+ char * charset;
+ int encoding;
+ char * text;
+ size_t end_encoding;
+ char * decoded;
+ size_t decoded_len;
+ struct mailmime_encoded_word * ew;
+ int r;
+ int res;
+ int opening_quote;
+ int end;
+
+ cur_token = * index;
+
+ r = mailimf_fws_parse(message, length, &cur_token);
+ if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
+ res = r;
+ goto err;
+ }
+
+ opening_quote = FALSE;
+ r = mailimf_char_parse(message, length, &cur_token, '\"');
+ if (r == MAILIMF_NO_ERROR) {
+ opening_quote = TRUE;
+ }
+ else if (r == MAILIMF_ERROR_PARSE) {
+ /* do nothing */
+ }
+ else {
+ res = r;
+ goto err;
+ }
+
+ r = mailimf_token_case_insensitive_parse(message, length, &cur_token, "=?");
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ r = mailmime_charset_parse(message, length, &cur_token, &charset);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ r = mailimf_char_parse(message, length, &cur_token, '?');
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto free_charset;
+ }
+
+ r = mailmime_encoding_parse(message, length, &cur_token, &encoding);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto free_charset;
+ }
+
+ r = mailimf_char_parse(message, length, &cur_token, '?');
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto free_charset;
+ }
+
+ end = FALSE;
+ end_encoding = cur_token;
+ while (1) {
+ if (end_encoding >= length)
+ break;
+
+ switch (message[end_encoding]) {
+ case '?':
+#if 0
+ case ' ':
+#endif
+ end = TRUE;
+ break;
+ }
+
+ if (end)
+ break;
+
+ end_encoding ++;
+ }
+
+ decoded_len = 0;
+ decoded = NULL;
+ switch (encoding) {
+ case MAILMIME_ENCODING_B:
+ r = mailmime_base64_body_parse(message, end_encoding,
+ &cur_token, &decoded,
+ &decoded_len);
+
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto free_charset;
+ }
+ break;
+ case MAILMIME_ENCODING_Q:
+ r = mailmime_quoted_printable_body_parse(message, end_encoding,
+ &cur_token, &decoded,
+ &decoded_len, TRUE);
+
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto free_charset;
+ }
+
+ break;
+ }
+
+ text = malloc(decoded_len + 1);
+ if (text == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free_charset;
+ }
+
+ if (decoded_len > 0)
+ memcpy(text, decoded, decoded_len);
+ text[decoded_len] = '\0';
+
+ mailmime_decoded_part_free(decoded);
+
+ r = mailimf_token_case_insensitive_parse(message, length, &cur_token, "?=");
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto free_encoded_text;
+ }
+
+ if (opening_quote) {
+ r = mailimf_char_parse(message, length, &cur_token, '\"');
+ if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
+ res = r;
+ goto free_encoded_text;
+ }
+ }
+
+ ew = mailmime_encoded_word_new(charset, text);
+ if (ew == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free_encoded_text;
+ }
+
+ * result = ew;
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+
+ free_encoded_text:
+ mailmime_encoded_text_free(text);
+ free_charset:
+ mailmime_charset_free(charset);
+ err:
+ return res;
+}
+
+static int mailmime_charset_parse(const char * message, size_t length,
+ size_t * index, char ** charset)
+{
+ return mailmime_etoken_parse(message, length, index, charset);
+}
+
+static int mailmime_encoding_parse(const char * message, size_t length,
+ size_t * index, int * result)
+{
+ size_t cur_token;
+ int encoding;
+
+ cur_token = * index;
+
+ if (cur_token >= length)
+ return MAILIMF_ERROR_PARSE;
+
+ switch ((char) toupper((unsigned char) message[cur_token])) {
+ case 'Q':
+ encoding = MAILMIME_ENCODING_Q;
+ break;
+ case 'B':
+ encoding = MAILMIME_ENCODING_B;
+ break;
+ default:
+ return MAILIMF_ERROR_INVAL;
+ }
+
+ cur_token ++;
+
+ * result = encoding;
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+}
+
+int is_etoken_char(char ch)
+{
+ unsigned char uch = ch;
+
+ if (uch < 31)
+ return FALSE;
+
+ switch (uch) {
+ case ' ':
+ case '(':
+ case ')':
+ case '<':
+ case '>':
+ case '@':
+ case ',':
+ case ';':
+ case ':':
+ case '"':
+ case '/':
+ case '[':
+ case ']':
+ case '?':
+ case '.':
+ case '=':
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static int mailmime_etoken_parse(const char * message, size_t length,
+ size_t * index, char ** result)
+{
+ return mailimf_custom_string_parse(message, length,
+ index, result,
+ is_etoken_char);
+}
diff --git a/libetpan/src/low-level/mime/mailmime_decode.h b/libetpan/src/low-level/mime/mailmime_decode.h
new file mode 100644
index 0000000..7b9d693
--- a/dev/null
+++ b/libetpan/src/low-level/mime/mailmime_decode.h
@@ -0,0 +1,55 @@
+/*
+ * 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$
+ */
+
+#ifndef MAILMIME_DECODE_H
+
+#define MAILMIME_DECODE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <libetpan/mailmime_types.h>
+
+int mailmime_encoded_phrase_parse(const char * default_fromcode,
+ const char * message, size_t length,
+ size_t * index, const char * tocode,
+ char ** result);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libetpan/src/low-level/mime/mailmime_disposition.c b/libetpan/src/low-level/mime/mailmime_disposition.c
new file mode 100644
index 0000000..eb1d846
--- a/dev/null
+++ b/libetpan/src/low-level/mime/mailmime_disposition.c
@@ -0,0 +1,595 @@
+/*
+ * 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 "mailmime_disposition.h"
+#include "mailmime.h"
+
+#include <ctype.h>
+#include <stdlib.h>
+
+static int
+mailmime_disposition_parm_parse(const char * message, size_t length,
+ size_t * index,
+ struct mailmime_disposition_parm **
+ result);
+
+static int
+mailmime_creation_date_parm_parse(const char * message, size_t length,
+ size_t * index, char ** result);
+
+static int
+mailmime_filename_parm_parse(const char * message, size_t length,
+ size_t * index, char ** result);
+
+static int
+mailmime_modification_date_parm_parse(const char * message, size_t length,
+ size_t * index, char ** result);
+
+static int
+mailmime_read_date_parm_parse(const char * message, size_t length,
+ size_t * index, char ** result);
+
+static int
+mailmime_size_parm_parse(const char * message, size_t length,
+ size_t * index, size_t * result);
+
+static int
+mailmime_quoted_date_time_parse(const char * message, size_t length,
+ size_t * index, char ** result);
+
+/*
+ disposition := "Content-Disposition" ":"
+ disposition-type
+ *(";" disposition-parm)
+
+*/
+
+
+int mailmime_disposition_parse(const char * message, size_t length,
+ size_t * index,
+ struct mailmime_disposition ** result)
+{
+ size_t final_token;
+ size_t cur_token;
+ struct mailmime_disposition_type * dsp_type;
+ clist * list;
+ struct mailmime_disposition * dsp;
+ int r;
+ int res;
+
+ cur_token = * index;
+
+ r = mailmime_disposition_type_parse(message, length, &cur_token,
+ &dsp_type);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ list = clist_new();
+ if (list == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free_type;
+ }
+
+ while (1) {
+ struct mailmime_disposition_parm * param;
+
+ final_token = cur_token;
+ r = mailimf_unstrict_char_parse(message, length, &cur_token, ';');
+ if (r == MAILIMF_NO_ERROR) {
+ /* do nothing */
+ }
+ else if (r == MAILIMF_ERROR_PARSE) {
+ break;
+ }
+ else {
+ res = r;
+ goto free_list;
+ }
+
+ r = mailmime_disposition_parm_parse(message, length, &cur_token, &param);
+ if (r == MAILIMF_NO_ERROR) {
+ /* do nothing */
+ }
+ else if (r == MAILIMF_ERROR_PARSE) {
+ cur_token = final_token;
+ break;
+ }
+ else {
+ res = r;
+ goto free_list;
+ }
+
+ r = clist_append(list, param);
+ if (r < 0) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free_list;
+ }
+ }
+
+ dsp = mailmime_disposition_new(dsp_type, list);
+ if (dsp == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free_list;
+ }
+
+ * result = dsp;
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+
+ free_list:
+ clist_foreach(list, (clist_func) mailmime_disposition_parm_free, NULL);
+ clist_free(list);
+ free_type:
+ mailmime_disposition_type_free(dsp_type);
+ err:
+ return res;
+}
+
+/*
+ disposition-type := "inline"
+ / "attachment"
+ / extension-token
+ ; values are not case-sensitive
+
+*/
+
+
+
+int
+mailmime_disposition_type_parse(const char * message, size_t length,
+ size_t * index,
+ struct mailmime_disposition_type ** result)
+{
+ size_t cur_token;
+ int type;
+ char * extension;
+ struct mailmime_disposition_type * dsp_type;
+ int r;
+ int res;
+
+ cur_token = * index;
+
+ r = mailimf_cfws_parse(message, length, &cur_token);
+ if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
+ res = r;
+ goto err;
+ }
+
+ type = MAILMIME_DISPOSITION_TYPE_ERROR; /* XXX - removes a gcc warning */
+
+ extension = NULL;
+ r = mailimf_token_case_insensitive_parse(message, length,
+ &cur_token, "inline");
+ if (r == MAILIMF_NO_ERROR)
+ type = MAILMIME_DISPOSITION_TYPE_INLINE;
+
+ if (r == MAILIMF_ERROR_PARSE) {
+ r = mailimf_token_case_insensitive_parse(message, length,
+ &cur_token, "attachment");
+ if (r == MAILIMF_NO_ERROR)
+ type = MAILMIME_DISPOSITION_TYPE_ATTACHMENT;
+ }
+
+ if (r == MAILIMF_ERROR_PARSE) {
+ r = mailmime_extension_token_parse(message, length, &cur_token,
+ &extension);
+ if (r == MAILIMF_NO_ERROR)
+ type = MAILMIME_DISPOSITION_TYPE_EXTENSION;
+ }
+
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ dsp_type = mailmime_disposition_type_new(type, extension);
+ if (dsp_type == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free;
+ }
+
+ * result = dsp_type;
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+
+ free:
+ if (extension != NULL)
+ free(extension);
+ err:
+ return res;
+}
+
+/*
+ disposition-parm := filename-parm
+ / creation-date-parm
+ / modification-date-parm
+ / read-date-parm
+ / size-parm
+ / parameter
+*/
+
+
+int mailmime_disposition_guess_type(const char * message, size_t length,
+ size_t index)
+{
+ if (index >= length)
+ return MAILMIME_DISPOSITION_PARM_PARAMETER;
+
+ switch ((char) toupper((unsigned char) message[index])) {
+ case 'F':
+ return MAILMIME_DISPOSITION_PARM_FILENAME;
+ case 'C':
+ return MAILMIME_DISPOSITION_PARM_CREATION_DATE;
+ case 'M':
+ return MAILMIME_DISPOSITION_PARM_MODIFICATION_DATE;
+ case 'R':
+ return MAILMIME_DISPOSITION_PARM_READ_DATE;
+ case 'S':
+ return MAILMIME_DISPOSITION_PARM_SIZE;
+ default:
+ return MAILMIME_DISPOSITION_PARM_PARAMETER;
+ }
+}
+
+static int
+mailmime_disposition_parm_parse(const char * message, size_t length,
+ size_t * index,
+ struct mailmime_disposition_parm **
+ result)
+{
+ char * filename;
+ char * creation_date;
+ char * modification_date;
+ char * read_date;
+ size_t size;
+ struct mailmime_parameter * parameter;
+ size_t cur_token;
+ struct mailmime_disposition_parm * dsp_parm;
+ int type;
+ int guessed_type;
+ int r;
+ int res;
+
+ cur_token = * index;
+
+ filename = NULL;
+ creation_date = NULL;
+ modification_date = NULL;
+ read_date = NULL;
+ size = 0;
+ parameter = NULL;
+
+ r = mailimf_cfws_parse(message, length, &cur_token);
+ if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
+ res = r;
+ goto err;
+ }
+
+ guessed_type = mailmime_disposition_guess_type(message, length, cur_token);
+
+ type = MAILMIME_DISPOSITION_PARM_PARAMETER;
+
+ switch (guessed_type) {
+ case MAILMIME_DISPOSITION_PARM_FILENAME:
+ r = mailmime_filename_parm_parse(message, length, &cur_token,
+ &filename);
+ if (r == MAILIMF_NO_ERROR)
+ type = guessed_type;
+ else if (r == MAILIMF_ERROR_PARSE) {
+ /* do nothing */
+ }
+ else {
+ res = r;
+ goto err;
+ }
+ break;
+
+ case MAILMIME_DISPOSITION_PARM_CREATION_DATE:
+ r = mailmime_creation_date_parm_parse(message, length, &cur_token,
+ &creation_date);
+ if (r == MAILIMF_NO_ERROR)
+ type = guessed_type;
+ else if (r == MAILIMF_ERROR_PARSE) {
+ /* do nothing */
+ }
+ else {
+ res = r;
+ goto err;
+ }
+ break;
+
+ case MAILMIME_DISPOSITION_PARM_MODIFICATION_DATE:
+ r = mailmime_modification_date_parm_parse(message, length, &cur_token,
+ &modification_date);
+ if (r == MAILIMF_NO_ERROR)
+ type = guessed_type;
+ else if (r == MAILIMF_ERROR_PARSE) {
+ /* do nothing */
+ }
+ else {
+ res = r;
+ goto err;
+ }
+ break;
+
+ case MAILMIME_DISPOSITION_PARM_READ_DATE:
+ r = mailmime_read_date_parm_parse(message, length, &cur_token,
+ &read_date);
+ if (r == MAILIMF_NO_ERROR)
+ type = guessed_type;
+ else if (r == MAILIMF_ERROR_PARSE) {
+ /* do nothing */
+ }
+ else {
+ res = r;
+ goto err;
+ }
+ break;
+
+ case MAILMIME_DISPOSITION_PARM_SIZE:
+ r = mailmime_size_parm_parse(message, length, &cur_token,
+ &size);
+ if (r == MAILIMF_NO_ERROR)
+ type = guessed_type;
+ else if (r == MAILIMF_ERROR_PARSE) {
+ /* do nothing */
+ }
+ else {
+ res = r;
+ goto err;
+ }
+ break;
+ }
+
+ if (type == MAILMIME_DISPOSITION_PARM_PARAMETER) {
+ r = mailmime_parameter_parse(message, length, &cur_token,
+ &parameter);
+ if (r != MAILIMF_NO_ERROR) {
+ type = guessed_type;
+ res = r;
+ goto err;
+ }
+ }
+
+ dsp_parm = mailmime_disposition_parm_new(type, filename, creation_date,
+ modification_date, read_date,
+ size, parameter);
+
+ if (dsp_parm == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free;
+ }
+
+ * result = dsp_parm;
+ * index = cur_token;
+
+ return MAILIMF_NO_ERROR;
+
+ free:
+ if (filename != NULL)
+ mailmime_filename_parm_free(dsp_parm->pa_data.pa_filename);
+ if (creation_date != NULL)
+ mailmime_creation_date_parm_free(dsp_parm->pa_data.pa_creation_date);
+ if (modification_date != NULL)
+ mailmime_modification_date_parm_free(dsp_parm->pa_data.pa_modification_date);
+ if (read_date != NULL)
+ mailmime_read_date_parm_free(dsp_parm->pa_data.pa_read_date);
+ if (parameter != NULL)
+ mailmime_parameter_free(dsp_parm->pa_data.pa_parameter);
+ err:
+ return res;
+}
+
+/*
+ filename-parm := "filename" "=" value
+*/
+
+static int
+mailmime_filename_parm_parse(const char * message, size_t length,
+ size_t * index, char ** result)
+{
+ char * value;
+ int r;
+ size_t cur_token;
+
+ cur_token = * index;
+
+ r = mailimf_token_case_insensitive_parse(message, length,
+ &cur_token, "filename");
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_unstrict_char_parse(message, length, &cur_token, '=');
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailmime_value_parse(message, length, &cur_token, &value);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ * index = cur_token;
+ * result = value;
+
+ return MAILIMF_NO_ERROR;
+}
+
+/*
+ creation-date-parm := "creation-date" "=" quoted-date-time
+*/
+
+static int
+mailmime_creation_date_parm_parse(const char * message, size_t length,
+ size_t * index, char ** result)
+{
+ char * value;
+ int r;
+ size_t cur_token;
+
+ cur_token = * index;
+
+ r = mailimf_token_case_insensitive_parse(message, length,
+ &cur_token, "creation-date");
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_unstrict_char_parse(message, length, &cur_token, '=');
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailmime_quoted_date_time_parse(message, length, &cur_token, &value);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ * index = cur_token;
+ * result = value;
+
+ return MAILIMF_NO_ERROR;
+}
+
+/*
+ modification-date-parm := "modification-date" "=" quoted-date-time
+*/
+
+static int
+mailmime_modification_date_parm_parse(const char * message, size_t length,
+ size_t * index, char ** result)
+{
+ char * value;
+ size_t cur_token;
+ int r;
+
+ cur_token = * index;
+
+ r = mailimf_token_case_insensitive_parse(message, length,
+ &cur_token, "modification-date");
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_unstrict_char_parse(message, length, &cur_token, '=');
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailmime_quoted_date_time_parse(message, length, &cur_token, &value);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ * index = cur_token;
+ * result = value;
+
+ return MAILIMF_NO_ERROR;
+}
+
+/*
+ read-date-parm := "read-date" "=" quoted-date-time
+*/
+
+static int
+mailmime_read_date_parm_parse(const char * message, size_t length,
+ size_t * index, char ** result)
+{
+ char * value;
+ size_t cur_token;
+ int r;
+
+ cur_token = * index;
+
+ r = mailimf_token_case_insensitive_parse(message, length,
+ &cur_token, "read-date");
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_unstrict_char_parse(message, length, &cur_token, '=');
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailmime_quoted_date_time_parse(message, length, &cur_token, &value);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ * index = cur_token;
+ * result = value;
+
+ return MAILIMF_NO_ERROR;
+}
+
+/*
+ size-parm := "size" "=" 1*DIGIT
+*/
+
+static int
+mailmime_size_parm_parse(const char * message, size_t length,
+ size_t * index, size_t * result)
+{
+ uint32_t value;
+ size_t cur_token;
+ int r;
+
+ cur_token = * index;
+
+ r = mailimf_token_case_insensitive_parse(message, length,
+ &cur_token, "size");
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_unstrict_char_parse(message, length, &cur_token, '=');
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_number_parse(message, length, &cur_token, &value);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ * index = cur_token;
+ * result = value;
+
+ return MAILIMF_NO_ERROR;
+}
+
+/*
+ quoted-date-time := quoted-string
+ ; contents MUST be an RFC 822 `date-time'
+ ; numeric timezones (+HHMM or -HHMM) MUST be used
+*/
+
+static int
+mailmime_quoted_date_time_parse(const char * message, size_t length,
+ size_t * index, char ** result)
+{
+ return mailimf_quoted_string_parse(message, length, index, result);
+}
diff --git a/libetpan/src/low-level/mime/mailmime_disposition.h b/libetpan/src/low-level/mime/mailmime_disposition.h
new file mode 100644
index 0000000..e992d7c
--- a/dev/null
+++ b/libetpan/src/low-level/mime/mailmime_disposition.h
@@ -0,0 +1,62 @@
+/*
+ * 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$
+ */
+
+#ifndef MAILMIME_DISPOSITION_H
+
+#define MAILMIME_DISPOSITION_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <libetpan/mailmime_types.h>
+
+int mailmime_disposition_parse(const char * message, size_t length,
+ size_t * index,
+ struct mailmime_disposition ** result);
+
+int
+mailmime_disposition_type_parse(const char * message, size_t length,
+ size_t * index,
+ struct mailmime_disposition_type ** result);
+
+int mailmime_disposition_guess_type(const char * message, size_t length,
+ size_t index);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libetpan/src/low-level/mime/mailmime_types.c b/libetpan/src/low-level/mime/mailmime_types.c
new file mode 100644
index 0000000..115d17f
--- a/dev/null
+++ b/libetpan/src/low-level/mime/mailmime_types.c
@@ -0,0 +1,753 @@
+/*
+ * 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 "mailmime_types.h"
+#include "mmapstring.h"
+
+#include <string.h>
+#include <stdlib.h>
+
+void mailmime_attribute_free(char * attribute)
+{
+ mailmime_token_free(attribute);
+}
+
+
+
+struct mailmime_composite_type *
+mailmime_composite_type_new(int ct_type, char * ct_token)
+{
+ struct mailmime_composite_type * ct;
+
+ ct = malloc(sizeof(* ct));
+ if (ct == NULL)
+ return NULL;
+
+ ct->ct_type = ct_type;
+ ct->ct_token = ct_token;
+
+ return ct;
+}
+
+void mailmime_composite_type_free(struct mailmime_composite_type * ct)
+{
+ if (ct->ct_token != NULL)
+ mailmime_extension_token_free(ct->ct_token);
+ free(ct);
+}
+
+
+struct mailmime_content *
+mailmime_content_new(struct mailmime_type * ct_type,
+ char * ct_subtype,
+ clist * ct_parameters)
+{
+ struct mailmime_content * content;
+
+ content = malloc(sizeof(* content));
+ if (content == NULL)
+ return NULL;
+
+ content->ct_type = ct_type;
+ content->ct_subtype = ct_subtype;
+ content->ct_parameters = ct_parameters;
+
+ return content;
+}
+
+void mailmime_content_free(struct mailmime_content * content)
+{
+ mailmime_type_free(content->ct_type);
+ mailmime_subtype_free(content->ct_subtype);
+ if (content->ct_parameters != NULL) {
+ clist_foreach(content->ct_parameters,
+ (clist_func) mailmime_parameter_free, NULL);
+ clist_free(content->ct_parameters);
+ }
+
+ free(content);
+}
+
+
+void mailmime_description_free(char * description)
+{
+ free(description);
+}
+
+struct mailmime_discrete_type *
+mailmime_discrete_type_new(int dt_type, char * dt_extension)
+{
+ struct mailmime_discrete_type * discrete_type;
+
+ discrete_type = malloc(sizeof(* discrete_type));
+ if (discrete_type == NULL)
+ return NULL;
+
+ discrete_type->dt_type = dt_type;
+ discrete_type->dt_extension = dt_extension;
+
+ return discrete_type;
+}
+
+void mailmime_discrete_type_free(struct mailmime_discrete_type * discrete_type)
+{
+ if (discrete_type->dt_extension != NULL)
+ mailmime_extension_token_free(discrete_type->dt_extension);
+ free(discrete_type);
+}
+
+void mailmime_encoding_free(struct mailmime_mechanism * encoding)
+{
+ mailmime_mechanism_free(encoding);
+}
+
+void mailmime_extension_token_free(char * extension)
+{
+ mailmime_token_free(extension);
+}
+
+void mailmime_id_free(char * id)
+{
+ mailimf_msg_id_free(id);
+}
+
+struct mailmime_mechanism * mailmime_mechanism_new(int enc_type, char * enc_token)
+{
+ struct mailmime_mechanism * mechanism;
+
+ mechanism = malloc(sizeof(* mechanism));
+ if (mechanism == NULL)
+ return NULL;
+
+ mechanism->enc_type = enc_type;
+ mechanism->enc_token = enc_token;
+
+ return mechanism;
+}
+
+void mailmime_mechanism_free(struct mailmime_mechanism * mechanism)
+{
+ if (mechanism->enc_token != NULL)
+ mailmime_token_free(mechanism->enc_token);
+ free(mechanism);
+}
+
+struct mailmime_parameter *
+mailmime_parameter_new(char * pa_name, char * pa_value)
+{
+ struct mailmime_parameter * parameter;
+
+ parameter = malloc(sizeof(* parameter));
+ if (parameter == NULL)
+ return NULL;
+
+ parameter->pa_name = pa_name;
+ parameter->pa_value = pa_value;
+
+ return parameter;
+}
+
+void mailmime_parameter_free(struct mailmime_parameter * parameter)
+{
+ mailmime_attribute_free(parameter->pa_name);
+ mailmime_value_free(parameter->pa_value);
+ free(parameter);
+}
+
+
+void mailmime_subtype_free(char * subtype)
+{
+ mailmime_extension_token_free(subtype);
+}
+
+
+void mailmime_token_free(char * token)
+{
+ free(token);
+}
+
+
+struct mailmime_type *
+mailmime_type_new(int tp_type,
+ struct mailmime_discrete_type * tp_discrete_type,
+ struct mailmime_composite_type * tp_composite_type)
+{
+ struct mailmime_type * mime_type;
+
+ mime_type = malloc(sizeof(* mime_type));
+ if (mime_type == NULL)
+ return NULL;
+
+ mime_type->tp_type = tp_type;
+ switch (tp_type) {
+ case MAILMIME_TYPE_DISCRETE_TYPE:
+ mime_type->tp_data.tp_discrete_type = tp_discrete_type;
+ break;
+ case MAILMIME_TYPE_COMPOSITE_TYPE:
+ mime_type->tp_data.tp_composite_type = tp_composite_type;
+ break;
+ }
+
+ return mime_type;
+}
+
+void mailmime_type_free(struct mailmime_type * type)
+{
+ switch (type->tp_type) {
+ case MAILMIME_TYPE_DISCRETE_TYPE:
+ mailmime_discrete_type_free(type->tp_data.tp_discrete_type);
+ break;
+ case MAILMIME_TYPE_COMPOSITE_TYPE:
+ mailmime_composite_type_free(type->tp_data.tp_composite_type);
+ break;
+ }
+ free(type);
+}
+
+void mailmime_value_free(char * value)
+{
+ free(value);
+}
+
+
+/*
+void mailmime_x_token_free(gchar * x_token)
+{
+ g_free(x_token);
+}
+*/
+
+struct mailmime_field *
+mailmime_field_new(int fld_type,
+ struct mailmime_content * fld_content,
+ struct mailmime_mechanism * fld_encoding,
+ char * fld_id,
+ char * fld_description,
+ uint32_t fld_version,
+ struct mailmime_disposition * fld_disposition,
+ struct mailmime_language * fld_language)
+{
+ struct mailmime_field * field;
+
+ field = malloc(sizeof(* field));
+ if (field == NULL)
+ return NULL;
+ field->fld_type = fld_type;
+
+ switch (fld_type) {
+ case MAILMIME_FIELD_TYPE:
+ field->fld_data.fld_content = fld_content;
+ break;
+ case MAILMIME_FIELD_TRANSFER_ENCODING:
+ field->fld_data.fld_encoding = fld_encoding;
+ break;
+ case MAILMIME_FIELD_ID:
+ field->fld_data.fld_id = fld_id;
+ break;
+ case MAILMIME_FIELD_DESCRIPTION:
+ field->fld_data.fld_description = fld_description;
+ break;
+ case MAILMIME_FIELD_VERSION:
+ field->fld_data.fld_version = fld_version;
+ break;
+ case MAILMIME_FIELD_DISPOSITION:
+ field->fld_data.fld_disposition = fld_disposition;
+ break;
+ case MAILMIME_FIELD_LANGUAGE:
+ field->fld_data.fld_language = fld_language;
+ break;
+ }
+ return field;
+}
+
+void mailmime_field_free(struct mailmime_field * field)
+{
+ switch (field->fld_type) {
+ case MAILMIME_FIELD_TYPE:
+ if (field->fld_data.fld_content != NULL)
+ mailmime_content_free(field->fld_data.fld_content);
+ break;
+ case MAILMIME_FIELD_TRANSFER_ENCODING:
+ if (field->fld_data.fld_encoding != NULL)
+ mailmime_encoding_free(field->fld_data.fld_encoding);
+ break;
+ case MAILMIME_FIELD_ID:
+ if (field->fld_data.fld_id != NULL)
+ mailmime_id_free(field->fld_data.fld_id);
+ break;
+ case MAILMIME_FIELD_DESCRIPTION:
+ if (field->fld_data.fld_description != NULL)
+ mailmime_description_free(field->fld_data.fld_description);
+ break;
+ case MAILMIME_FIELD_DISPOSITION:
+ if (field->fld_data.fld_disposition != NULL)
+ mailmime_disposition_free(field->fld_data.fld_disposition);
+ break;
+ case MAILMIME_FIELD_LANGUAGE:
+ if (field->fld_data.fld_language != NULL)
+ mailmime_language_free(field->fld_data.fld_language);
+ break;
+ }
+
+ free(field);
+}
+
+struct mailmime_fields * mailmime_fields_new(clist * fld_list)
+{
+ struct mailmime_fields * fields;
+
+ fields = malloc(sizeof(* fields));
+ if (fields == NULL)
+ return NULL;
+
+ fields->fld_list = fld_list;
+
+ return fields;
+}
+
+void mailmime_fields_free(struct mailmime_fields * fields)
+{
+ clist_foreach(fields->fld_list, (clist_func) mailmime_field_free, NULL);
+ clist_free(fields->fld_list);
+ free(fields);
+}
+
+
+/*
+struct mailmime_body_part *
+mailmime_body_part_new(gchar * text, guint32 size)
+{
+ struct mailmime_body_part * body_part;
+
+ body_part = g_new(struct mailmime_body_part, 1);
+ if (body_part == NULL)
+ return NULL;
+
+ body_part->text = text;
+ body_part->size = size;
+
+ return body_part;
+}
+
+void mailmime_body_part_free(struct mailmime_body_part * body_part)
+{
+ g_free(body_part);
+}
+*/
+
+struct mailmime_multipart_body *
+mailmime_multipart_body_new(clist * bd_list)
+{
+ struct mailmime_multipart_body * mp_body;
+
+ mp_body = malloc(sizeof(* mp_body));
+ if (mp_body == NULL)
+ return NULL;
+
+ mp_body->bd_list = bd_list;
+
+ return mp_body;
+}
+
+void mailmime_multipart_body_free(struct mailmime_multipart_body * mp_body)
+{
+ clist_foreach(mp_body->bd_list, (clist_func) mailimf_body_free, NULL);
+ clist_free(mp_body->bd_list);
+ free(mp_body);
+}
+
+
+
+
+struct mailmime * mailmime_new(int mm_type,
+ const char * mm_mime_start, size_t mm_length,
+ struct mailmime_fields * mm_mime_fields,
+ struct mailmime_content * mm_content_type,
+ struct mailmime_data * mm_body,
+ struct mailmime_data * mm_preamble,
+ struct mailmime_data * mm_epilogue,
+ clist * mm_mp_list,
+ struct mailimf_fields * mm_fields,
+ struct mailmime * mm_msg_mime)
+{
+ struct mailmime * mime;
+ clistiter * cur;
+
+ mime = malloc(sizeof(* mime));
+ if (mime == NULL)
+ return NULL;
+
+ mime->mm_parent = NULL;
+ mime->mm_parent_type = MAILMIME_NONE;
+ mime->mm_multipart_pos = NULL;
+
+ mime->mm_type = mm_type;
+ mime->mm_mime_start = mm_mime_start;
+ mime->mm_length = mm_length;
+ mime->mm_mime_fields = mm_mime_fields;
+ mime->mm_content_type = mm_content_type;
+
+ mime->mm_body = mm_body;
+
+ switch (mm_type) {
+ case MAILMIME_SINGLE:
+ mime->mm_data.mm_single = mm_body;
+ break;
+
+ case MAILMIME_MULTIPLE:
+ mime->mm_data.mm_multipart.mm_preamble = mm_preamble;
+ mime->mm_data.mm_multipart.mm_epilogue = mm_epilogue;
+ mime->mm_data.mm_multipart.mm_mp_list = mm_mp_list;
+
+ for(cur = clist_begin(mm_mp_list) ; cur != NULL ;
+ cur = clist_next(cur)) {
+ struct mailmime * submime;
+
+ submime = clist_content(cur);
+ submime->mm_parent = mime;
+ submime->mm_parent_type = MAILMIME_MULTIPLE;
+ submime->mm_multipart_pos = cur;
+ }
+ break;
+
+ case MAILMIME_MESSAGE:
+ mime->mm_data.mm_message.mm_fields = mm_fields;
+ mime->mm_data.mm_message.mm_msg_mime = mm_msg_mime;
+ if (mm_msg_mime != NULL) {
+ mm_msg_mime->mm_parent = mime;
+ mm_msg_mime->mm_parent_type = MAILMIME_MESSAGE;
+ }
+ break;
+
+ }
+
+ return mime;
+}
+
+void mailmime_free(struct mailmime * mime)
+{
+ switch (mime->mm_type) {
+ case MAILMIME_SINGLE:
+ if ((mime->mm_body == NULL) && (mime->mm_data.mm_single != NULL))
+ mailmime_data_free(mime->mm_data.mm_single);
+ /* do nothing */
+ break;
+
+ case MAILMIME_MULTIPLE:
+ if (mime->mm_data.mm_multipart.mm_preamble != NULL)
+ mailmime_data_free(mime->mm_data.mm_multipart.mm_preamble);
+ if (mime->mm_data.mm_multipart.mm_epilogue != NULL)
+ mailmime_data_free(mime->mm_data.mm_multipart.mm_epilogue);
+ clist_foreach(mime->mm_data.mm_multipart.mm_mp_list,
+ (clist_func) mailmime_free, NULL);
+ clist_free(mime->mm_data.mm_multipart.mm_mp_list);
+ break;
+
+ case MAILMIME_MESSAGE:
+ if (mime->mm_data.mm_message.mm_fields != NULL)
+ mailimf_fields_free(mime->mm_data.mm_message.mm_fields);
+ if (mime->mm_data.mm_message.mm_msg_mime != NULL)
+ mailmime_free(mime->mm_data.mm_message.mm_msg_mime);
+ break;
+
+ }
+ if (mime->mm_body != NULL)
+ mailmime_data_free(mime->mm_body);
+
+ if (mime->mm_mime_fields != NULL)
+ mailmime_fields_free(mime->mm_mime_fields);
+ if (mime->mm_content_type != NULL)
+ mailmime_content_free(mime->mm_content_type);
+ free(mime);
+}
+
+
+
+struct mailmime_encoded_word *
+mailmime_encoded_word_new(char * wd_charset, char * wd_text)
+{
+ struct mailmime_encoded_word * ew;
+
+ ew = malloc(sizeof(* ew));
+ if (ew == NULL)
+ return NULL;
+ ew->wd_charset = wd_charset;
+ ew->wd_text = wd_text;
+
+ return ew;
+}
+
+void mailmime_charset_free(char * charset)
+{
+ free(charset);
+}
+
+void mailmime_encoded_text_free(char * text)
+{
+ free(text);
+}
+
+void mailmime_encoded_word_free(struct mailmime_encoded_word * ew)
+{
+ mailmime_charset_free(ew->wd_charset);
+ mailmime_encoded_text_free(ew->wd_text);
+ free(ew);
+}
+
+
+
+/* mailmime_disposition */
+
+
+struct mailmime_disposition *
+mailmime_disposition_new(struct mailmime_disposition_type * dsp_type,
+ clist * dsp_parms)
+{
+ struct mailmime_disposition * dsp;
+
+ dsp = malloc(sizeof(* dsp));
+ if (dsp == NULL)
+ return NULL;
+ dsp->dsp_type = dsp_type;
+ dsp->dsp_parms = dsp_parms;
+
+ return dsp;
+}
+
+void mailmime_disposition_free(struct mailmime_disposition * dsp)
+{
+ mailmime_disposition_type_free(dsp->dsp_type);
+ clist_foreach(dsp->dsp_parms,
+ (clist_func) mailmime_disposition_parm_free, NULL);
+ clist_free(dsp->dsp_parms);
+ free(dsp);
+}
+
+
+
+struct mailmime_disposition_type *
+mailmime_disposition_type_new(int dsp_type, char * dsp_extension)
+{
+ struct mailmime_disposition_type * m_dsp_type;
+
+ m_dsp_type = malloc(sizeof(* m_dsp_type));
+ if (m_dsp_type == NULL)
+ return NULL;
+
+ m_dsp_type->dsp_type = dsp_type;
+ m_dsp_type->dsp_extension = dsp_extension;
+
+ return m_dsp_type;
+}
+
+void mailmime_disposition_type_free(struct mailmime_disposition_type * dsp_type)
+{
+ if (dsp_type->dsp_extension != NULL)
+ free(dsp_type->dsp_extension);
+ free(dsp_type);
+}
+
+
+struct mailmime_disposition_parm *
+mailmime_disposition_parm_new(int pa_type,
+ char * pa_filename,
+ char * pa_creation_date,
+ char * pa_modification_date,
+ char * pa_read_date,
+ size_t pa_size,
+ struct mailmime_parameter * pa_parameter)
+{
+ struct mailmime_disposition_parm * dsp_parm;
+
+ dsp_parm = malloc(sizeof(* dsp_parm));
+ if (dsp_parm == NULL)
+ return NULL;
+
+ dsp_parm->pa_type = pa_type;
+ switch (pa_type) {
+ case MAILMIME_DISPOSITION_PARM_FILENAME:
+ dsp_parm->pa_data.pa_filename = pa_filename;
+ break;
+ case MAILMIME_DISPOSITION_PARM_CREATION_DATE:
+ dsp_parm->pa_data.pa_creation_date = pa_creation_date;
+ break;
+ case MAILMIME_DISPOSITION_PARM_MODIFICATION_DATE:
+ dsp_parm->pa_data.pa_modification_date = pa_modification_date;
+ break;
+ case MAILMIME_DISPOSITION_PARM_READ_DATE:
+ dsp_parm->pa_data.pa_read_date = pa_read_date;
+ break;
+ case MAILMIME_DISPOSITION_PARM_SIZE:
+ dsp_parm->pa_data.pa_size = pa_size;
+ break;
+ case MAILMIME_DISPOSITION_PARM_PARAMETER:
+ dsp_parm->pa_data.pa_parameter = pa_parameter;
+ break;
+ }
+
+ return dsp_parm;
+}
+
+void mailmime_disposition_parm_free(struct mailmime_disposition_parm *
+ dsp_parm)
+{
+ switch (dsp_parm->pa_type) {
+ case MAILMIME_DISPOSITION_PARM_FILENAME:
+ mailmime_filename_parm_free(dsp_parm->pa_data.pa_filename);
+ break;
+ case MAILMIME_DISPOSITION_PARM_CREATION_DATE:
+ mailmime_creation_date_parm_free(dsp_parm->pa_data.pa_creation_date);
+ break;
+ case MAILMIME_DISPOSITION_PARM_MODIFICATION_DATE:
+ mailmime_modification_date_parm_free(dsp_parm->pa_data.pa_modification_date);
+ break;
+ case MAILMIME_DISPOSITION_PARM_READ_DATE:
+ mailmime_read_date_parm_free(dsp_parm->pa_data.pa_read_date);
+ break;
+ case MAILMIME_DISPOSITION_PARM_PARAMETER:
+ mailmime_parameter_free(dsp_parm->pa_data.pa_parameter);
+ break;
+ }
+
+ free(dsp_parm);
+}
+
+
+void mailmime_filename_parm_free(char * filename)
+{
+ mailmime_value_free(filename);
+}
+
+void mailmime_creation_date_parm_free(char * date)
+{
+ mailmime_quoted_date_time_free(date);
+}
+
+void mailmime_modification_date_parm_free(char * date)
+{
+ mailmime_quoted_date_time_free(date);
+}
+
+void mailmime_read_date_parm_free(char * date)
+{
+ mailmime_quoted_date_time_free(date);
+}
+
+void mailmime_quoted_date_time_free(char * date)
+{
+ mailimf_quoted_string_free(date);
+}
+
+struct mailmime_section * mailmime_section_new(clist * sec_list)
+{
+ struct mailmime_section * section;
+
+ section = malloc(sizeof(* section));
+ if (section == NULL)
+ return NULL;
+
+ section->sec_list = sec_list;
+
+ return section;
+}
+
+void mailmime_section_free(struct mailmime_section * section)
+{
+ clist_foreach(section->sec_list, (clist_func) free, NULL);
+ clist_free(section->sec_list);
+ free(section);
+}
+
+
+
+struct mailmime_language * mailmime_language_new(clist * lg_list)
+{
+ struct mailmime_language * lang;
+
+ lang = malloc(sizeof(* lang));
+ if (lang == NULL)
+ return NULL;
+
+ lang->lg_list = lg_list;
+
+ return lang;
+}
+
+void mailmime_language_free(struct mailmime_language * lang)
+{
+ clist_foreach(lang->lg_list, (clist_func) mailimf_atom_free, NULL);
+ clist_free(lang->lg_list);
+ free(lang);
+}
+
+void mailmime_decoded_part_free(char * part)
+{
+ mmap_string_unref(part);
+}
+
+struct mailmime_data * mailmime_data_new(int dt_type, int dt_encoding,
+ int dt_encoded, const char * dt_data, size_t dt_length, char * dt_filename)
+{
+ struct mailmime_data * mime_data;
+
+ mime_data = malloc(sizeof(* mime_data));
+ if (mime_data == NULL)
+ return NULL;
+
+ mime_data->dt_type = dt_type;
+ mime_data->dt_encoding = dt_encoding;
+ mime_data->dt_encoded = dt_encoded;
+ switch (dt_type) {
+ case MAILMIME_DATA_TEXT:
+ mime_data->dt_data.dt_text.dt_data = dt_data;
+ mime_data->dt_data.dt_text.dt_length = dt_length;
+ break;
+ case MAILMIME_DATA_FILE:
+ mime_data->dt_data.dt_filename = dt_filename;
+ break;
+ }
+
+ return mime_data;
+}
+
+void mailmime_data_free(struct mailmime_data * mime_data)
+{
+ switch (mime_data->dt_type) {
+ case MAILMIME_DATA_FILE:
+ free(mime_data->dt_data.dt_filename);
+ break;
+ }
+ free(mime_data);
+}
diff --git a/libetpan/src/low-level/mime/mailmime_types.h b/libetpan/src/low-level/mime/mailmime_types.h
new file mode 100644
index 0000000..21f0d96
--- a/dev/null
+++ b/libetpan/src/low-level/mime/mailmime_types.h
@@ -0,0 +1,440 @@
+/*
+ * 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$
+ */
+
+#ifndef MAILMIME_TYPES_H
+
+#define MAILMIME_TYPES_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <inttypes.h>
+#include <libetpan/mailimf.h>
+#include <libetpan/clist.h>
+
+enum {
+ MAILMIME_COMPOSITE_TYPE_ERROR,
+ MAILMIME_COMPOSITE_TYPE_MESSAGE,
+ MAILMIME_COMPOSITE_TYPE_MULTIPART,
+ MAILMIME_COMPOSITE_TYPE_EXTENSION
+};
+
+struct mailmime_composite_type {
+ int ct_type;
+ char * ct_token;
+};
+
+
+struct mailmime_content {
+ struct mailmime_type * ct_type;
+ char * ct_subtype;
+ clist * ct_parameters; /* elements are (struct mailmime_parameter *) */
+};
+
+
+enum {
+ MAILMIME_DISCRETE_TYPE_ERROR,
+ MAILMIME_DISCRETE_TYPE_TEXT,
+ MAILMIME_DISCRETE_TYPE_IMAGE,
+ MAILMIME_DISCRETE_TYPE_AUDIO,
+ MAILMIME_DISCRETE_TYPE_VIDEO,
+ MAILMIME_DISCRETE_TYPE_APPLICATION,
+ MAILMIME_DISCRETE_TYPE_EXTENSION
+};
+
+struct mailmime_discrete_type {
+ int dt_type;
+ char * dt_extension;
+};
+
+enum {
+ MAILMIME_FIELD_NONE,
+ MAILMIME_FIELD_TYPE,
+ MAILMIME_FIELD_TRANSFER_ENCODING,
+ MAILMIME_FIELD_ID,
+ MAILMIME_FIELD_DESCRIPTION,
+ MAILMIME_FIELD_VERSION,
+ MAILMIME_FIELD_DISPOSITION,
+ MAILMIME_FIELD_LANGUAGE,
+};
+
+struct mailmime_field {
+ int fld_type;
+ union {
+ struct mailmime_content * fld_content;
+ struct mailmime_mechanism * fld_encoding;
+ char * fld_id;
+ char * fld_description;
+ uint32_t fld_version;
+ struct mailmime_disposition * fld_disposition;
+ struct mailmime_language * fld_language;
+ } fld_data;
+};
+
+enum {
+ MAILMIME_MECHANISM_ERROR,
+ MAILMIME_MECHANISM_7BIT,
+ MAILMIME_MECHANISM_8BIT,
+ MAILMIME_MECHANISM_BINARY,
+ MAILMIME_MECHANISM_QUOTED_PRINTABLE,
+ MAILMIME_MECHANISM_BASE64,
+ MAILMIME_MECHANISM_TOKEN
+};
+
+struct mailmime_mechanism {
+ int enc_type;
+ char * enc_token;
+};
+
+
+struct mailmime_fields {
+ clist * fld_list; /* list of (struct mailmime_field *) */
+};
+
+
+struct mailmime_parameter {
+ char * pa_name;
+ char * pa_value;
+};
+
+enum {
+ MAILMIME_TYPE_ERROR,
+ MAILMIME_TYPE_DISCRETE_TYPE,
+ MAILMIME_TYPE_COMPOSITE_TYPE
+};
+
+struct mailmime_type {
+ int tp_type;
+ union {
+ struct mailmime_discrete_type * tp_discrete_type;
+ struct mailmime_composite_type * tp_composite_type;
+ } tp_data;
+};
+
+void mailmime_attribute_free(char * attribute);
+
+struct mailmime_composite_type *
+mailmime_composite_type_new(int ct_type, char * ct_token);
+
+void mailmime_composite_type_free(struct mailmime_composite_type * ct);
+
+struct mailmime_content *
+mailmime_content_new(struct mailmime_type * ct_type,
+ char * ct_subtype,
+ clist * ct_parameters);
+
+void mailmime_content_free(struct mailmime_content * content);
+
+void mailmime_description_free(char * description);
+
+struct mailmime_discrete_type *
+mailmime_discrete_type_new(int dt_type, char * dt_extension);
+
+void mailmime_discrete_type_free(struct mailmime_discrete_type *
+ discrete_type);
+
+void mailmime_encoding_free(struct mailmime_mechanism * encoding);
+
+void mailmime_extension_token_free(char * extension);
+
+void mailmime_id_free(char * id);
+
+struct mailmime_mechanism * mailmime_mechanism_new(int enc_type, char * enc_token);
+
+void mailmime_mechanism_free(struct mailmime_mechanism * mechanism);
+
+struct mailmime_parameter *
+mailmime_parameter_new(char * pa_name, char * pa_value);
+
+void mailmime_parameter_free(struct mailmime_parameter * parameter);
+
+void mailmime_subtype_free(char * subtype);
+
+void mailmime_token_free(char * token);
+
+struct mailmime_type *
+mailmime_type_new(int tp_type,
+ struct mailmime_discrete_type * tp_discrete_type,
+ struct mailmime_composite_type * tp_composite_type);
+
+void mailmime_type_free(struct mailmime_type * type);
+
+void mailmime_value_free(char * value);
+
+
+
+struct mailmime_language {
+ clist * lg_list; /* atom (char *) */
+};
+
+struct mailmime_language * mailmime_language_new(clist * lg_list);
+
+void mailmime_language_free(struct mailmime_language * lang);
+
+
+/*
+void mailmime_x_token_free(gchar * x_token);
+*/
+
+struct mailmime_field *
+mailmime_field_new(int fld_type,
+ struct mailmime_content * fld_content,
+ struct mailmime_mechanism * fld_encoding,
+ char * fld_id,
+ char * fld_description,
+ uint32_t fld_version,
+ struct mailmime_disposition * fld_disposition,
+ struct mailmime_language * fld_language);
+
+void mailmime_field_free(struct mailmime_field * field);
+
+struct mailmime_fields * mailmime_fields_new(clist * fld_list);
+
+void mailmime_fields_free(struct mailmime_fields * fields);
+
+
+struct mailmime_multipart_body {
+ clist * bd_list;
+};
+
+struct mailmime_multipart_body *
+mailmime_multipart_body_new(clist * bd_list);
+
+void mailmime_multipart_body_free(struct mailmime_multipart_body * mp_body);
+
+
+enum {
+ MAILMIME_DATA_TEXT,
+ MAILMIME_DATA_FILE,
+};
+
+struct mailmime_data {
+ int dt_type;
+ int dt_encoding;
+ int dt_encoded;
+ union {
+ struct {
+ const char * dt_data;
+ size_t dt_length;
+ } dt_text;
+ char * dt_filename;
+ } dt_data;
+};
+
+struct mailmime_data * mailmime_data_new(int dt_type, int dt_encoding,
+ int dt_encoded, const char * dt_data, size_t dt_length,
+ char * dt_filename);
+
+void mailmime_data_free(struct mailmime_data * mime_data);
+
+
+enum {
+ MAILMIME_NONE,
+ MAILMIME_SINGLE,
+ MAILMIME_MULTIPLE,
+ MAILMIME_MESSAGE,
+};
+
+struct mailmime {
+ /* parent information */
+ int mm_parent_type;
+ struct mailmime * mm_parent;
+ clistiter * mm_multipart_pos;
+
+ int mm_type;
+ const char * mm_mime_start;
+ size_t mm_length;
+
+ struct mailmime_fields * mm_mime_fields;
+ struct mailmime_content * mm_content_type;
+
+ struct mailmime_data * mm_body;
+ union {
+ /* single part */
+ struct mailmime_data * mm_single; /* XXX - was body */
+
+ /* multi-part */
+ struct {
+ struct mailmime_data * mm_preamble;
+ struct mailmime_data * mm_epilogue;
+ clist * mm_mp_list;
+ } mm_multipart;
+
+ /* message */
+ struct {
+ struct mailimf_fields * mm_fields;
+ struct mailmime * mm_msg_mime;
+ } mm_message;
+
+ } mm_data;
+};
+
+struct mailmime * mailmime_new(int mm_type,
+ const char * mm_mime_start, size_t mm_length,
+ struct mailmime_fields * mm_mime_fields,
+ struct mailmime_content * mm_content_type,
+ struct mailmime_data * mm_body,
+ struct mailmime_data * mm_preamble,
+ struct mailmime_data * mm_epilogue,
+ clist * mm_mp_list,
+ struct mailimf_fields * mm_fields,
+ struct mailmime * mm_msg_mime);
+
+void mailmime_free(struct mailmime * mime);
+
+struct mailmime_encoded_word {
+ char * wd_charset;
+ char * wd_text;
+};
+
+struct mailmime_encoded_word *
+mailmime_encoded_word_new(char * wd_charset, char * wd_text);
+
+void mailmime_encoded_word_free(struct mailmime_encoded_word * ew);
+
+void mailmime_charset_free(char * charset);
+
+void mailmime_encoded_text_free(char * text);
+
+
+struct mailmime_disposition {
+ struct mailmime_disposition_type * dsp_type;
+ clist * dsp_parms; /* struct mailmime_disposition_parm */
+};
+
+
+enum {
+ MAILMIME_DISPOSITION_TYPE_ERROR,
+ MAILMIME_DISPOSITION_TYPE_INLINE,
+ MAILMIME_DISPOSITION_TYPE_ATTACHMENT,
+ MAILMIME_DISPOSITION_TYPE_EXTENSION
+};
+
+struct mailmime_disposition_type {
+ int dsp_type;
+ char * dsp_extension;
+};
+
+
+enum {
+ MAILMIME_DISPOSITION_PARM_FILENAME,
+ MAILMIME_DISPOSITION_PARM_CREATION_DATE,
+ MAILMIME_DISPOSITION_PARM_MODIFICATION_DATE,
+ MAILMIME_DISPOSITION_PARM_READ_DATE,
+ MAILMIME_DISPOSITION_PARM_SIZE,
+ MAILMIME_DISPOSITION_PARM_PARAMETER
+};
+
+struct mailmime_disposition_parm {
+ int pa_type;
+ union {
+ char * pa_filename;
+ char * pa_creation_date;
+ char * pa_modification_date;
+ char * pa_read_date;
+ size_t pa_size;
+ struct mailmime_parameter * pa_parameter;
+ } pa_data;
+};
+
+struct mailmime_disposition *
+mailmime_disposition_new(struct mailmime_disposition_type * dsp_type,
+ clist * dsp_parms);
+
+void mailmime_disposition_free(struct mailmime_disposition * dsp);
+
+struct mailmime_disposition_type *
+mailmime_disposition_type_new(int dt_type, char * dt_extension);
+
+void mailmime_disposition_type_free(struct mailmime_disposition_type * dsp_type);
+
+struct mailmime_disposition_parm *
+mailmime_disposition_parm_new(int pa_type,
+ char * pa_filename,
+ char * pa_creation_date,
+ char * pa_modification_date,
+ char * pa_read_date,
+ size_t pa_size,
+ struct mailmime_parameter * pa_parameter);
+
+void mailmime_disposition_parm_free(struct mailmime_disposition_parm *
+ dsp_parm);
+
+void mailmime_filename_parm_free(char * filename);
+
+void mailmime_creation_date_parm_free(char * date);
+
+void mailmime_modification_date_parm_free(char * date);
+
+void mailmime_read_date_parm_free(char * date);
+
+void mailmime_quoted_date_time_free(char * date);
+
+struct mailmime_section {
+ clist * sec_list; /* list of (uint32 *) */
+};
+
+struct mailmime_section * mailmime_section_new(clist * list);
+
+void mailmime_section_free(struct mailmime_section * section);
+
+
+void mailmime_decoded_part_free(char * part);
+
+struct mailmime_single_fields {
+ struct mailmime_content * fld_content;
+ char * fld_content_charset;
+ char * fld_content_boundary;
+ char * fld_content_name;
+ struct mailmime_mechanism * fld_encoding;
+ char * fld_id;
+ char * fld_description;
+ uint32_t fld_version;
+ struct mailmime_disposition * fld_disposition;
+ char * fld_disposition_filename;
+ char * fld_disposition_creation_date;
+ char * fld_disposition_modification_date;
+ char * fld_disposition_read_date;
+ size_t fld_disposition_size;
+ struct mailmime_language * fld_language;
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/libetpan/src/low-level/mime/mailmime_types_helper.c b/libetpan/src/low-level/mime/mailmime_types_helper.c
new file mode 100644
index 0000000..e45330c
--- a/dev/null
+++ b/libetpan/src/low-level/mime/mailmime_types_helper.c
@@ -0,0 +1,1385 @@
+/*
+ * 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 "mailmime_types_helper.h"
+#include "clist.h"
+
+#include "mailmime.h"
+
+#include <string.h>
+#include <time.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#define MIME_VERSION (1 << 16)
+
+int mailmime_transfer_encoding_get(struct mailmime_fields * fields)
+{
+ clistiter * cur;
+
+ for(cur = clist_begin(fields->fld_list) ;
+ cur != NULL ; cur = clist_next(cur)) {
+ struct mailmime_field * field;
+
+ field = clist_content(cur);
+ if (field->fld_type == MAILMIME_FIELD_TRANSFER_ENCODING)
+ return field->fld_data.fld_encoding->enc_type;
+ }
+
+ return MAILMIME_MECHANISM_8BIT;
+}
+
+struct mailmime_disposition *
+mailmime_disposition_new_filename(int type, char * filename)
+{
+ return mailmime_disposition_new_with_data(type, filename,
+ NULL, NULL, NULL, (size_t) -1);
+
+}
+
+struct mailmime_fields * mailmime_fields_new_empty(void)
+{
+ clist * list;
+ struct mailmime_fields * fields;
+
+ list = clist_new();
+ if (list == NULL)
+ goto err;
+
+ fields = mailmime_fields_new(list);
+ if (fields == NULL)
+ goto free;
+
+ return fields;
+
+ free:
+ clist_free(list);
+ err:
+ return NULL;
+}
+
+int mailmime_fields_add(struct mailmime_fields * fields,
+ struct mailmime_field * field)
+{
+ int r;
+
+ r = clist_append(fields->fld_list, field);
+ if (r < 0)
+ return MAILIMF_ERROR_MEMORY;
+
+ return MAILIMF_NO_ERROR;
+}
+
+static void mailmime_field_detach(struct mailmime_field * field)
+{
+ switch (field->fld_type) {
+ case MAILMIME_FIELD_TYPE:
+ field->fld_data.fld_content = NULL;
+ break;
+ case MAILMIME_FIELD_TRANSFER_ENCODING:
+ field->fld_data.fld_encoding = NULL;
+ break;
+ case MAILMIME_FIELD_ID:
+ field->fld_data.fld_id = NULL;
+ break;
+ case MAILMIME_FIELD_DESCRIPTION:
+ field->fld_data.fld_description = NULL;
+ break;
+ case MAILMIME_FIELD_DISPOSITION:
+ field->fld_data.fld_disposition = NULL;
+ break;
+ case MAILMIME_FIELD_LANGUAGE:
+ field->fld_data.fld_language = NULL;
+ break;
+ }
+}
+
+struct mailmime_fields *
+mailmime_fields_new_with_data(struct mailmime_mechanism * encoding,
+ char * id,
+ char * description,
+ struct mailmime_disposition * disposition,
+ struct mailmime_language * language)
+{
+ struct mailmime_field * field;
+ struct mailmime_fields * fields;
+ int r;
+
+ fields = mailmime_fields_new_empty();
+ if (fields == NULL)
+ goto err;
+
+#if 0
+ if (content != NULL) {
+ field = mailmime_field_new(MAILMIME_FIELD_TYPE,
+ content, NULL, NULL, NULL, 0, NULL, NULL);
+ if (field == NULL)
+ goto free;
+
+ r = mailmime_fields_add(fields, field);
+ if (r != MAILIMF_NO_ERROR) {
+ mailmime_field_detach(field);
+ mailmime_field_free(field);
+ goto free;
+ }
+ }
+#endif
+
+ if (encoding != NULL) {
+ field = mailmime_field_new(MAILMIME_FIELD_TRANSFER_ENCODING,
+ NULL, encoding, NULL, NULL, 0, NULL, NULL);
+ if (field == NULL)
+ goto free;
+
+ r = mailmime_fields_add(fields, field);
+ if (r != MAILIMF_NO_ERROR) {
+ mailmime_field_detach(field);
+ mailmime_field_free(field);
+ goto free;
+ }
+ }
+
+ if (id != NULL) {
+ field = mailmime_field_new(MAILMIME_FIELD_ID,
+ NULL, NULL, id, NULL, 0, NULL, NULL);
+ if (field == NULL)
+ goto free;
+
+ r = mailmime_fields_add(fields, field);
+ if (r != MAILIMF_NO_ERROR) {
+ mailmime_field_detach(field);
+ mailmime_field_free(field);
+ goto free;
+ }
+ }
+
+ if (description != NULL) {
+ field = mailmime_field_new(MAILMIME_FIELD_DESCRIPTION,
+ NULL, NULL, NULL, description, 0, NULL, NULL);
+ if (field == NULL)
+ goto free;
+
+ r = mailmime_fields_add(fields, field);
+ if (r != MAILIMF_NO_ERROR) {
+ mailmime_field_detach(field);
+ mailmime_field_free(field);
+ goto free;
+ }
+ }
+
+ if (disposition != NULL) {
+ field = mailmime_field_new(MAILMIME_FIELD_DISPOSITION,
+ NULL, NULL, NULL, NULL, 0, disposition, NULL);
+ if (field == NULL)
+ goto free;
+
+ r = mailmime_fields_add(fields, field);
+ if (r != MAILIMF_NO_ERROR) {
+ mailmime_field_detach(field);
+ mailmime_field_free(field);
+ goto free;
+ }
+ }
+
+ if (language != NULL) {
+ field = mailmime_field_new(MAILMIME_FIELD_DISPOSITION,
+ NULL, NULL, NULL, NULL, 0, NULL, language);
+ if (field == NULL)
+ goto free;
+
+ r = mailmime_fields_add(fields, field);
+ if (r != MAILIMF_NO_ERROR) {
+ mailmime_field_detach(field);
+ mailmime_field_free(field);
+ goto free;
+ }
+ }
+
+ return fields;
+
+ free:
+ clist_foreach(fields->fld_list, (clist_func) mailmime_field_detach, NULL);
+ mailmime_fields_free(fields);
+ err:
+ return NULL;
+}
+
+struct mailmime_fields *
+mailmime_fields_new_with_version(struct mailmime_mechanism * encoding,
+ char * id,
+ char * description,
+ struct mailmime_disposition * disposition,
+ struct mailmime_language * language)
+{
+ struct mailmime_field * field;
+ struct mailmime_fields * fields;
+ int r;
+
+ fields = mailmime_fields_new_with_data(encoding, id, description,
+ disposition, language);
+ if (fields == NULL)
+ goto err;
+
+ field = mailmime_field_new(MAILMIME_FIELD_VERSION,
+ NULL, NULL, NULL, NULL, MIME_VERSION, NULL, NULL);
+ if (field == NULL)
+ goto free;
+
+ r = mailmime_fields_add(fields, field);
+ if (r != MAILIMF_NO_ERROR) {
+ mailmime_field_detach(field);
+ mailmime_field_free(field);
+ goto free;
+ }
+
+ return fields;
+
+ free:
+ clist_foreach(fields->fld_list, (clist_func) mailmime_field_detach, NULL);
+ mailmime_fields_free(fields);
+ err:
+ return NULL;
+}
+
+
+struct mailmime_content * mailmime_get_content_message(void)
+{
+ clist * list;
+ struct mailmime_composite_type * composite_type;
+ struct mailmime_type * mime_type;
+ struct mailmime_content * content;
+ char * subtype;
+
+ composite_type =
+ mailmime_composite_type_new(MAILMIME_COMPOSITE_TYPE_MESSAGE,
+ NULL);
+ if (composite_type == NULL)
+ goto err;
+
+ mime_type = mailmime_type_new(MAILMIME_TYPE_COMPOSITE_TYPE,
+ NULL, composite_type);
+ if (mime_type == NULL)
+ goto free_composite;
+ composite_type = NULL;
+
+ list = clist_new();
+ if (list == NULL)
+ goto free_mime_type;
+
+ subtype = strdup("rfc822");
+ if (subtype == NULL)
+ goto free_list;
+
+ content = mailmime_content_new(mime_type, subtype, list);
+ if (content == NULL)
+ goto free_subtype;
+
+ return content;
+
+ free_subtype:
+ free(subtype);
+ free_list:
+ clist_free(list);
+ free_mime_type:
+ mailmime_type_free(mime_type);
+ free_composite:
+ if (composite_type != NULL)
+ mailmime_composite_type_free(composite_type);
+ err:
+ return NULL;
+}
+
+struct mailmime_content * mailmime_get_content_text(void)
+{
+ clist * list;
+ struct mailmime_discrete_type * discrete_type;
+ struct mailmime_type * mime_type;
+ struct mailmime_content * content;
+ char * subtype;
+
+ discrete_type = mailmime_discrete_type_new(MAILMIME_DISCRETE_TYPE_TEXT,
+ NULL);
+ if (discrete_type == NULL)
+ goto err;
+
+ mime_type = mailmime_type_new(MAILMIME_TYPE_DISCRETE_TYPE,
+ discrete_type, NULL);
+ if (mime_type == NULL)
+ goto free_discrete;
+ discrete_type = NULL;
+
+ list = clist_new();
+ if (list == NULL)
+ goto free_type;
+
+ subtype = strdup("plain");
+ if (subtype == NULL)
+ goto free_list;
+
+ content = mailmime_content_new(mime_type, subtype, list);
+ if (content == NULL)
+ goto free_subtype;
+
+ return content;
+
+ free_subtype:
+ free(subtype);
+ free_list:
+ clist_free(list);
+ free_type:
+ mailmime_type_free(mime_type);
+ free_discrete:
+ if (discrete_type != NULL)
+ mailmime_discrete_type_free(discrete_type);
+ err:
+ return NULL;
+}
+
+
+
+
+
+
+
+
+/* mailmime build */
+
+
+#if 0
+struct mailmime *
+mailmime_new_message_file(char * filename)
+{
+ struct mailmime_content * content;
+ struct mailmime * build_info;
+ struct mailmime_data * msg_content;
+ struct mailmime_fields * mime_fields;
+
+ content = mailmime_get_content_message();
+ if (content == NULL) {
+ goto err;
+ }
+
+ mime_fields = mailmime_fields_new_with_version(NULL, NULL,
+ NULL, NULL, NULL);
+ if (mime_fields == NULL)
+ goto free_content;
+
+ msg_content = mailmime_data_new(MAILMIME_DATA_FILE, MAILMIME_MECHANISM_8BIT,
+ 1, NULL, 0, filename);
+ if (msg_content == NULL)
+ goto free_fields;
+
+ build_info = mailmime_new(MAILMIME_MESSAGE,
+ NULL, 0, mime_fields, content,
+ msg_content, NULL, NULL, NULL, NULL, NULL);
+ if (build_info == NULL)
+ goto free_msg_content;
+
+ return build_info;
+
+ free_msg_content:
+ mailmime_data_free(msg_content);
+ free_fields:
+ mailmime_fields_free(mime_fields);
+ free_content:
+ mailmime_content_free(content);
+ err:
+ return NULL;
+}
+
+struct mailmime *
+mailmime_new_message_text(char * data_str, size_t length)
+{
+ struct mailmime_content * content;
+ struct mailmime * build_info;
+ struct mailmime_data * msg_content;
+ struct mailmime_fields * mime_fields;
+
+ content = mailmime_get_content_message();
+ if (content == NULL) {
+ goto err;
+ }
+
+ mime_fields = mailmime_fields_new_with_version(NULL, NULL,
+ NULL, NULL, NULL);
+ if (mime_fields == NULL)
+ goto free_fields;
+
+ msg_content = mailmime_data_new(MAILMIME_DATA_TEXT, MAILMIME_MECHANISM_8BIT,
+ 1, data_str, length, NULL);
+ if (msg_content == NULL)
+ goto free_content;
+
+ build_info = mailmime_new(MAILMIME_MESSAGE,
+ NULL, 0, mime_fields, content,
+ msg_content, NULL, NULL, NULL,
+ NULL, NULL);
+ if (build_info == NULL)
+ goto free_msg_content;
+
+ return build_info;
+
+ free_msg_content:
+ mailmime_data_free(msg_content);
+ free_fields:
+ mailmime_fields_free(mime_fields);
+ free_content:
+ mailmime_content_free(content);
+ err:
+ return NULL;
+}
+#endif
+
+struct mailmime *
+mailmime_new_message_data(struct mailmime * msg_mime)
+{
+ struct mailmime_content * content;
+ struct mailmime * build_info;
+ struct mailmime_fields * mime_fields;
+
+ content = mailmime_get_content_message();
+ if (content == NULL)
+ goto err;
+
+ mime_fields = mailmime_fields_new_with_version(NULL, NULL,
+ NULL, NULL, NULL);
+ if (mime_fields == NULL)
+ goto free_content;
+
+ build_info = mailmime_new(MAILMIME_MESSAGE,
+ NULL, 0, mime_fields, content,
+ NULL, NULL, NULL, NULL,
+ NULL, msg_mime);
+ if (build_info == NULL)
+ goto free_fields;
+
+ return build_info;
+
+ free_fields:
+ mailmime_fields_free(mime_fields);
+ free_content:
+ mailmime_content_free(content);
+ err:
+ return NULL;
+}
+
+#define MAX_MESSAGE_ID 512
+
+static char * generate_boundary()
+{
+ char id[MAX_MESSAGE_ID];
+ time_t now;
+ char name[MAX_MESSAGE_ID];
+ long value;
+
+ now = time(NULL);
+ value = random();
+
+ gethostname(name, MAX_MESSAGE_ID);
+ snprintf(id, MAX_MESSAGE_ID, "%lx_%lx_%x", now, value, getpid());
+
+ return strdup(id);
+}
+
+struct mailmime *
+mailmime_new_empty(struct mailmime_content * content,
+ struct mailmime_fields * mime_fields)
+{
+ struct mailmime * build_info;
+ clist * list;
+ int r;
+ int mime_type;
+
+ list = NULL;
+
+ switch (content->ct_type->tp_type) {
+ case MAILMIME_TYPE_DISCRETE_TYPE:
+ mime_type = MAILMIME_SINGLE;
+ break;
+
+ case MAILMIME_TYPE_COMPOSITE_TYPE:
+ switch (content->ct_type->tp_data.tp_composite_type->ct_type) {
+ case MAILMIME_COMPOSITE_TYPE_MULTIPART:
+ mime_type = MAILMIME_MULTIPLE;
+ break;
+
+ case MAILMIME_COMPOSITE_TYPE_MESSAGE:
+ if (strcasecmp(content->ct_subtype, "rfc822") == 0)
+ mime_type = MAILMIME_MESSAGE;
+ else
+ mime_type = MAILMIME_SINGLE;
+ break;
+
+ default:
+ goto err;
+ }
+ break;
+
+ default:
+ goto err;
+ }
+
+ if (mime_type == MAILMIME_MULTIPLE) {
+ char * attr_name;
+ char * attr_value;
+ struct mailmime_parameter * param;
+ clist * parameters;
+ char * boundary;
+
+ list = clist_new();
+ if (list == NULL)
+ goto err;
+
+ attr_name = strdup("boundary");
+ if (attr_name == NULL)
+ goto free_list;
+
+ boundary = generate_boundary();
+ attr_value = boundary;
+ if (attr_name == NULL) {
+ free(attr_name);
+ goto free_list;
+ }
+
+ param = mailmime_parameter_new(attr_name, attr_value);
+ if (param == NULL) {
+ free(attr_value);
+ free(attr_name);
+ goto free_list;
+ }
+
+ if (content->ct_parameters == NULL) {
+ parameters = clist_new();
+ if (parameters == NULL) {
+ mailmime_parameter_free(param);
+ goto free_list;
+ }
+ }
+ else
+ parameters = content->ct_parameters;
+
+ r = clist_append(parameters, param);
+ if (r != 0) {
+ clist_free(parameters);
+ mailmime_parameter_free(param);
+ goto free_list;
+ }
+
+ if (content->ct_parameters == NULL)
+ content->ct_parameters = parameters;
+ }
+
+ build_info = mailmime_new(mime_type,
+ NULL, 0, mime_fields, content,
+ NULL, NULL, NULL, list,
+ NULL, NULL);
+ if (build_info == NULL) {
+ clist_free(list);
+ return NULL;
+ }
+
+ return build_info;
+
+ free_list:
+ clist_free(list);
+ err:
+ return NULL;
+}
+
+
+int
+mailmime_new_with_content(const char * content_type,
+ struct mailmime_fields * mime_fields,
+ struct mailmime ** result)
+{
+ int r;
+ size_t cur_token;
+ struct mailmime_content * content;
+ struct mailmime * build_info;
+#if 0
+ int mime_type;
+#endif
+ int res;
+
+ cur_token = 0;
+ r = mailmime_content_parse(content_type, strlen(content_type),
+ &cur_token,
+ &content);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+#if 0
+ switch (content->type->type) {
+ case MAILMIME_TYPE_DISCRETE_TYPE:
+ mime_type = MAILMIME_SINGLE;
+ break;
+
+ case MAILMIME_TYPE_COMPOSITE_TYPE:
+ switch (content->type->composite_type->type) {
+ case MAILMIME_COMPOSITE_TYPE_MULTIPART:
+ mime_type = MAILMIME_MULTIPLE;
+ break;
+
+ case MAILMIME_COMPOSITE_TYPE_MESSAGE:
+ if (strcasecmp(content->subtype, "rfc822") == 0)
+ mime_type = MAILMIME_MESSAGE;
+ else
+ mime_type = MAILMIME_SINGLE;
+ break;
+
+ default:
+ res = MAILIMF_ERROR_INVAL;
+ goto free;
+ }
+ break;
+
+ default:
+ res = MAILIMF_ERROR_INVAL;
+ goto free;
+ }
+#endif
+
+ build_info = mailmime_new_empty(content, mime_fields);
+ if (build_info == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free;
+ }
+
+ * result = build_info;
+
+ return MAILIMF_NO_ERROR;
+
+ free:
+ mailmime_content_free(content);
+ err:
+ return res;
+}
+
+int mailmime_set_preamble_file(struct mailmime * build_info,
+ char * filename)
+{
+ struct mailmime_data * data;
+
+ data = mailmime_data_new(MAILMIME_DATA_FILE, MAILMIME_MECHANISM_8BIT,
+ 0, NULL, 0, filename);
+ if (data == NULL)
+ return MAILIMF_ERROR_MEMORY;
+
+ build_info->mm_data.mm_multipart.mm_preamble = data;
+
+ return MAILIMF_NO_ERROR;
+}
+
+int mailmime_set_epilogue_file(struct mailmime * build_info,
+ char * filename)
+{
+ struct mailmime_data * data;
+
+ data = mailmime_data_new(MAILMIME_DATA_FILE, MAILMIME_MECHANISM_8BIT,
+ 0, NULL, 0, filename);
+ if (data == NULL)
+ return MAILIMF_ERROR_MEMORY;
+
+ build_info->mm_data.mm_multipart.mm_epilogue = data;
+
+ return MAILIMF_NO_ERROR;
+}
+
+int mailmime_set_preamble_text(struct mailmime * build_info,
+ char * data_str, size_t length)
+{
+ struct mailmime_data * data;
+
+ data = mailmime_data_new(MAILMIME_DATA_TEXT, MAILMIME_MECHANISM_8BIT,
+ 0, data_str, length, NULL);
+ if (data == NULL)
+ return MAILIMF_ERROR_MEMORY;
+
+ build_info->mm_data.mm_multipart.mm_preamble = data;
+
+ return MAILIMF_NO_ERROR;
+}
+
+int mailmime_set_epilogue_text(struct mailmime * build_info,
+ char * data_str, size_t length)
+{
+ struct mailmime_data * data;
+
+ data = mailmime_data_new(MAILMIME_DATA_TEXT, MAILMIME_MECHANISM_8BIT,
+ 0, data_str, length, NULL);
+ if (data == NULL)
+ return MAILIMF_ERROR_MEMORY;
+
+ build_info->mm_data.mm_multipart.mm_epilogue = data;
+
+ return MAILIMF_NO_ERROR;
+}
+
+
+int mailmime_set_body_file(struct mailmime * build_info,
+ char * filename)
+{
+ int encoding;
+ struct mailmime_data * data;
+
+ encoding = mailmime_transfer_encoding_get(build_info->mm_mime_fields);
+
+ data = mailmime_data_new(MAILMIME_DATA_FILE, encoding,
+ 0, NULL, 0, filename);
+ if (data == NULL)
+ return MAILIMF_ERROR_MEMORY;
+
+ build_info->mm_data.mm_single = data;
+
+ return MAILIMF_NO_ERROR;
+}
+
+int mailmime_set_body_text(struct mailmime * build_info,
+ char * data_str, size_t length)
+{
+ int encoding;
+ struct mailmime_data * data;
+
+ encoding = mailmime_transfer_encoding_get(build_info->mm_mime_fields);
+
+ data = mailmime_data_new(MAILMIME_DATA_TEXT, encoding,
+ 0, data_str, length, NULL);
+ if (data == NULL)
+ return MAILIMF_ERROR_MEMORY;
+
+ build_info->mm_data.mm_single = data;
+
+ return MAILIMF_NO_ERROR;
+}
+
+
+/* add a part as subpart of a mime part */
+
+int mailmime_add_part(struct mailmime * build_info,
+ struct mailmime * part)
+{
+ int r;
+
+ if (build_info->mm_type == MAILMIME_MESSAGE) {
+ build_info->mm_data.mm_message.mm_msg_mime = part;
+ part->mm_parent_type = MAILMIME_MESSAGE;
+ part->mm_parent = build_info;
+ }
+ else if (build_info->mm_type == MAILMIME_MULTIPLE) {
+ r = clist_append(build_info->mm_data.mm_multipart.mm_mp_list, part);
+ if (r != 0)
+ return MAILIMF_ERROR_MEMORY;
+
+ part->mm_parent_type = MAILMIME_MULTIPLE;
+ part->mm_parent = build_info;
+ part->mm_multipart_pos =
+ clist_end(build_info->mm_data.mm_multipart.mm_mp_list);
+ }
+ else {
+ return MAILIMF_ERROR_INVAL;
+ }
+ return MAILIMF_NO_ERROR;
+}
+
+/* detach part from parent */
+
+void mailmime_remove_part(struct mailmime * mime)
+{
+ struct mailmime * parent;
+
+ parent = mime->mm_parent;
+ if (parent == NULL)
+ return;
+
+ switch (mime->mm_parent_type) {
+ case MAILMIME_MESSAGE:
+ mime->mm_parent = NULL;
+ parent->mm_data.mm_message.mm_msg_mime = NULL;
+ break;
+
+ case MAILMIME_MULTIPLE:
+ mime->mm_parent = NULL;
+ clist_delete(parent->mm_data.mm_multipart.mm_mp_list,
+ mime->mm_multipart_pos);
+ break;
+ }
+}
+
+
+/*
+ attach a part to a mime part and create multipart/mixed
+ when needed, when the parent part has already some part
+ attached to it.
+*/
+
+int mailmime_smart_add_part(struct mailmime * mime,
+ struct mailmime * mime_sub)
+{
+ struct mailmime * saved_sub;
+ struct mailmime * mp;
+ int res;
+ int r;
+
+ switch (mime->mm_type) {
+ case MAILMIME_SINGLE:
+ res = MAILIMF_ERROR_INVAL;
+ goto err;
+
+ case MAILMIME_MULTIPLE:
+ r = mailmime_add_part(mime, mime_sub);
+ if (r != MAILIMF_NO_ERROR) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto err;
+ }
+
+ return MAILIMF_NO_ERROR;
+ }
+
+ /* MAILMIME_MESSAGE */
+
+ if (mime->mm_data.mm_message.mm_msg_mime == NULL) {
+ /* there is no subpart, we can simply attach it */
+
+ r = mailmime_add_part(mime, mime_sub);
+ if (r != MAILIMF_NO_ERROR) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto err;
+ }
+
+ return MAILIMF_NO_ERROR;
+ }
+
+ if (mime->mm_data.mm_message.mm_msg_mime->mm_type == MAILMIME_MULTIPLE) {
+ /* in case the subpart is multipart, simply attach it to the subpart */
+
+ return mailmime_add_part(mime->mm_data.mm_message.mm_msg_mime, mime_sub);
+ }
+
+ /* we save the current subpart, ... */
+
+ saved_sub = mime->mm_data.mm_message.mm_msg_mime;
+
+ /* create a multipart */
+
+ mp = mailmime_multiple_new("multipart/mixed");
+ if (mp == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto err;
+ }
+
+ /* detach the saved subpart from the parent */
+
+ mailmime_remove_part(saved_sub);
+
+ /* the created multipart is the new child of the parent */
+
+ r = mailmime_add_part(mime, mp);
+ if (r != MAILIMF_NO_ERROR) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free_mp;
+ }
+
+ /* then, attach the saved subpart and ... */
+
+ r = mailmime_add_part(mp, saved_sub);
+ if (r != MAILIMF_NO_ERROR) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free_saved_sub;
+ }
+
+ /* the given part to the parent */
+
+ r = mailmime_add_part(mp, mime_sub);
+ if (r != MAILIMF_NO_ERROR) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto free_saved_sub;
+ }
+
+ return MAILIMF_NO_ERROR;
+
+ free_mp:
+ mailmime_free(mp);
+ free_saved_sub:
+ mailmime_free(saved_sub);
+ err:
+ return res;
+}
+
+
+
+/* detach part from parent and free it only if the part has no child */
+
+int mailmime_smart_remove_part(struct mailmime * mime)
+{
+ struct mailmime * parent;
+ int res;
+
+ parent = mime->mm_parent;
+ if (parent == NULL) {
+ res = MAILIMF_ERROR_INVAL;
+ goto err;
+ }
+
+ switch (mime->mm_type) {
+ case MAILMIME_MESSAGE:
+ if (mime->mm_data.mm_message.mm_msg_mime != NULL) {
+ res = MAILIMF_ERROR_INVAL;
+ goto err;
+ }
+
+ mailmime_remove_part(mime);
+
+ mailmime_free(mime);
+
+ return MAILIMF_NO_ERROR;
+
+ case MAILMIME_MULTIPLE:
+ if (!clist_isempty(mime->mm_data.mm_multipart.mm_mp_list)) {
+ res = MAILIMF_ERROR_INVAL;
+ goto err;
+ }
+
+ mailmime_remove_part(mime);
+
+ mailmime_free(mime);
+
+ return MAILIMF_NO_ERROR;
+
+ case MAILMIME_SINGLE:
+ mailmime_remove_part(mime);
+
+ mailmime_free(mime);
+
+ return MAILIMF_NO_ERROR;
+
+ default:
+ return MAILIMF_ERROR_INVAL;
+ }
+
+ err:
+ return res;
+}
+
+
+/* create a mailmime_content structure (Content-Type field) */
+
+struct mailmime_content * mailmime_content_new_with_str(const char * str)
+{
+ int r;
+ size_t cur_token;
+ struct mailmime_content * content;
+
+ cur_token = 0;
+ r = mailmime_content_parse(str, strlen(str), &cur_token, &content);
+ if (r != MAILIMF_NO_ERROR)
+ return NULL;
+
+ return content;
+}
+
+/* create MIME fields with only the field Content-Transfer-Encoding */
+
+struct mailmime_fields * mailmime_fields_new_encoding(int type)
+{
+ struct mailmime_mechanism * encoding;
+ struct mailmime_fields * mime_fields;
+
+ encoding = mailmime_mechanism_new(type, NULL);
+ if (encoding == NULL)
+ goto err;
+
+ mime_fields = mailmime_fields_new_with_data(encoding,
+ NULL, NULL, NULL, NULL);
+ if (mime_fields == NULL)
+ goto free;
+
+ return mime_fields;
+
+ free:
+ mailmime_mechanism_free(encoding);
+ err:
+ return NULL;
+}
+
+
+/* create a multipart MIME part */
+
+struct mailmime * mailmime_multiple_new(const char * type)
+{
+ struct mailmime_fields * mime_fields;
+ struct mailmime_content * content;
+ struct mailmime * mp;
+
+ mime_fields = mailmime_fields_new_encoding(MAILMIME_MECHANISM_8BIT);
+ if (mime_fields == NULL)
+ goto err;
+
+ content = mailmime_content_new_with_str(type);
+ if (content == NULL)
+ goto free_fields;
+
+ mp = mailmime_new_empty(content, mime_fields);
+ if (mp == NULL)
+ goto free_content;
+
+ return mp;
+
+ free_content:
+ mailmime_content_free(content);
+ free_fields:
+ mailmime_fields_free(mime_fields);
+ err:
+ return NULL;
+}
+
+
+
+void mailmime_set_imf_fields(struct mailmime * build_info,
+ struct mailimf_fields * mm_fields)
+{
+ build_info->mm_data.mm_message.mm_fields = mm_fields;
+}
+
+#if 0
+struct mailmime_content * mailmime_get_content(char * mime_type)
+{
+ struct mailmime_content *content;
+ int r;
+ size_t cur_token;
+
+ cur_token = 0;
+ r = mailmime_content_parse(mime_type, strlen(mime_type),
+ &cur_token, &content);
+ if (r != MAILIMF_NO_ERROR)
+ return NULL;
+
+ return content;
+}
+#endif
+
+
+
+
+struct mailmime_disposition *
+mailmime_disposition_new_with_data(int type,
+ char * filename, char * creation_date, char * modification_date,
+ char * read_date, size_t size)
+{
+ struct mailmime_disposition_type * dsp_type;
+ clist * list;
+ int r;
+ struct mailmime_disposition_parm * parm;
+ struct mailmime_disposition * dsp;
+
+ dsp_type = mailmime_disposition_type_new(type, NULL);
+ if (dsp_type == NULL)
+ goto err;
+
+ list = clist_new();
+ if (list == NULL)
+ goto free_dsp_type;
+
+ if (filename != NULL) {
+ parm = mailmime_disposition_parm_new(MAILMIME_DISPOSITION_PARM_FILENAME,
+ filename, NULL, NULL, NULL, 0, NULL);
+ if (parm == NULL)
+ goto free_list;
+
+ r = clist_append(list, parm);
+ if (r < 0) {
+ mailmime_disposition_parm_free(parm);
+ goto free_list;
+ }
+ }
+
+ if (creation_date != NULL) {
+ parm = mailmime_disposition_parm_new(MAILMIME_DISPOSITION_PARM_CREATION_DATE,
+ NULL, creation_date, NULL, NULL, 0, NULL);
+ if (parm == NULL)
+ goto free_list;
+
+ r = clist_append(list, parm);
+ if (r < 0) {
+ mailmime_disposition_parm_free(parm);
+ goto free_list;
+ }
+ }
+
+ if (modification_date != NULL) {
+ parm = mailmime_disposition_parm_new(MAILMIME_DISPOSITION_PARM_MODIFICATION_DATE,
+ NULL, NULL, modification_date, NULL, 0, NULL);
+ if (parm == NULL)
+ goto free_list;
+
+ r = clist_append(list, parm);
+ if (r < 0) {
+ mailmime_disposition_parm_free(parm);
+ goto free_list;
+ }
+ }
+
+ if (read_date != NULL) {
+ parm = mailmime_disposition_parm_new(MAILMIME_DISPOSITION_PARM_READ_DATE,
+ NULL, NULL, NULL, read_date, 0, NULL);
+ if (parm == NULL)
+ goto free_list;
+
+ r = clist_append(list, parm);
+ if (r < 0) {
+ mailmime_disposition_parm_free(parm);
+ goto free_list;
+ }
+ }
+
+ if (size != (size_t) -1) {
+ parm = mailmime_disposition_parm_new(MAILMIME_DISPOSITION_PARM_SIZE,
+ NULL, NULL, NULL, NULL, size, NULL);
+ if (parm == NULL)
+ goto free_list;
+
+ r = clist_append(list, parm);
+ if (r < 0) {
+ mailmime_disposition_parm_free(parm);
+ goto free_list;
+ }
+ }
+
+ dsp = mailmime_disposition_new(dsp_type, list);
+
+ return dsp;
+
+ free_list:
+ clist_foreach(list, (clist_func) mailmime_disposition_parm_free, NULL);
+ clist_free(list);
+ free_dsp_type:
+ mailmime_disposition_type_free(dsp_type);
+ err:
+ return NULL;
+}
+
+
+static void mailmime_disposition_single_fields_init(struct
+ mailmime_single_fields * single_fields,
+ struct mailmime_disposition * fld_disposition)
+{
+ clistiter * cur;
+
+ single_fields->fld_disposition = fld_disposition;
+
+ for(cur = clist_begin(fld_disposition->dsp_parms) ; cur != NULL ;
+ cur = clist_next(cur)) {
+ struct mailmime_disposition_parm * param;
+
+ param = clist_content(cur);
+
+ switch (param->pa_type) {
+ case MAILMIME_DISPOSITION_PARM_FILENAME:
+ single_fields->fld_disposition_filename = param->pa_data.pa_filename;
+ break;
+
+ case MAILMIME_DISPOSITION_PARM_CREATION_DATE:
+ single_fields->fld_disposition_creation_date =
+ param->pa_data.pa_creation_date;
+ break;
+
+ case MAILMIME_DISPOSITION_PARM_MODIFICATION_DATE:
+ single_fields->fld_disposition_modification_date =
+ param->pa_data.pa_modification_date;
+ break;
+
+ case MAILMIME_DISPOSITION_PARM_READ_DATE:
+ single_fields->fld_disposition_read_date =
+ param->pa_data.pa_read_date;
+ break;
+
+ case MAILMIME_DISPOSITION_PARM_SIZE:
+ single_fields->fld_disposition_size = param->pa_data.pa_size;
+ break;
+ }
+ }
+}
+
+static void mailmime_content_single_fields_init(struct
+ mailmime_single_fields * single_fields,
+ struct mailmime_content * fld_content)
+{
+ clistiter * cur;
+
+ single_fields->fld_content = fld_content;
+
+ for(cur = clist_begin(fld_content->ct_parameters) ;
+ cur != NULL ; cur = clist_next(cur)) {
+ struct mailmime_parameter * param;
+
+ param = clist_content(cur);
+
+ if (strcasecmp(param->pa_name, "boundary") == 0)
+ single_fields->fld_content_boundary = param->pa_value;
+
+ if (strcasecmp(param->pa_name, "charset") == 0)
+ single_fields->fld_content_charset = param->pa_value;
+
+ if (strcasecmp(param->pa_name, "name") == 0)
+ single_fields->fld_content_name = param->pa_value;
+ }
+}
+
+void mailmime_single_fields_init(struct mailmime_single_fields * single_fields,
+ struct mailmime_fields * fld_fields,
+ struct mailmime_content * fld_content)
+{
+ clistiter * cur;
+
+ memset(single_fields, 0, sizeof(struct mailmime_single_fields));
+
+ if (fld_content != NULL)
+ mailmime_content_single_fields_init(single_fields, fld_content);
+
+ if (fld_fields == NULL)
+ return;
+
+ for(cur = clist_begin(fld_fields->fld_list) ; cur != NULL ;
+ cur = clist_next(cur)) {
+ struct mailmime_field * field;
+
+ field = clist_content(cur);
+
+ switch (field->fld_type) {
+ case MAILMIME_FIELD_TYPE:
+ mailmime_content_single_fields_init(single_fields,
+ field->fld_data.fld_content);
+ break;
+
+ case MAILMIME_FIELD_TRANSFER_ENCODING:
+ single_fields->fld_encoding = field->fld_data.fld_encoding;
+ break;
+
+ case MAILMIME_FIELD_ID:
+ single_fields->fld_id = field->fld_data.fld_id;
+ break;
+
+ case MAILMIME_FIELD_DESCRIPTION:
+ single_fields->fld_description = field->fld_data.fld_description;
+ break;
+
+ case MAILMIME_FIELD_VERSION:
+ single_fields->fld_version = field->fld_data.fld_version;
+ break;
+
+ case MAILMIME_FIELD_DISPOSITION:
+ mailmime_disposition_single_fields_init(single_fields,
+ field->fld_data.fld_disposition);
+ break;
+
+ case MAILMIME_FIELD_LANGUAGE:
+ single_fields->fld_language = field->fld_data.fld_language;
+ break;
+ }
+ }
+}
+
+struct mailmime_single_fields *
+mailmime_single_fields_new(struct mailmime_fields * fld_fields,
+ struct mailmime_content * fld_content)
+{
+ struct mailmime_single_fields * single_fields;
+
+ single_fields = malloc(sizeof(struct mailmime_single_fields));
+ if (single_fields == NULL)
+ goto err;
+
+ mailmime_single_fields_init(single_fields, fld_fields, fld_content);
+
+ return single_fields;
+
+ err:
+ return NULL;
+}
+
+
+void mailmime_single_fields_free(struct mailmime_single_fields *
+ single_fields)
+{
+ free(single_fields);
+}
+
+struct mailmime_fields * mailmime_fields_new_filename(int dsp_type,
+ char * filename, int encoding_type)
+{
+ struct mailmime_disposition * dsp;
+ struct mailmime_mechanism * encoding;
+ struct mailmime_fields * mime_fields;
+
+ dsp = mailmime_disposition_new_with_data(dsp_type,
+ filename, NULL, NULL, NULL, (size_t) -1);
+ if (dsp == NULL)
+ goto err;
+
+ encoding = mailmime_mechanism_new(encoding_type, NULL);
+ if (encoding == NULL)
+ goto free_dsp;
+
+ mime_fields = mailmime_fields_new_with_data(encoding,
+ NULL, NULL, dsp, NULL);
+ if (mime_fields == NULL)
+ goto free_encoding;
+
+ return mime_fields;
+
+ free_encoding:
+ mailmime_encoding_free(encoding);
+ free_dsp:
+ mailmime_disposition_free(dsp);
+ err:
+ return NULL;
+}
+
+struct mailmime_data *
+mailmime_data_new_data(int encoding, int encoded,
+ const char * data, size_t length)
+{
+ return mailmime_data_new(MAILMIME_DATA_TEXT, encoding, encoded, data, length, NULL);
+}
+
+struct mailmime_data *
+mailmime_data_new_file(int encoding, int encoded,
+ char * filename)
+{
+ return mailmime_data_new(MAILMIME_DATA_FILE, encoding, encoded, NULL, 0, filename);
+}
+
diff --git a/libetpan/src/low-level/mime/mailmime_types_helper.h b/libetpan/src/low-level/mime/mailmime_types_helper.h
new file mode 100644
index 0000000..cdbbff9
--- a/dev/null
+++ b/libetpan/src/low-level/mime/mailmime_types_helper.h
@@ -0,0 +1,165 @@
+/*
+ * 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$
+ */
+
+#ifndef MAILMIME_TYPES_HELPER_H
+
+#define MAILMIME_TYPES_HELPER_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <libetpan/mailmime_types.h>
+
+int mailmime_transfer_encoding_get(struct mailmime_fields * fields);
+
+struct mailmime_disposition *
+mailmime_disposition_new_filename(int type, char * filename);
+
+struct mailmime_fields * mailmime_fields_new_empty(void);
+
+int mailmime_fields_add(struct mailmime_fields * fields,
+ struct mailmime_field * field);
+
+struct mailmime_fields *
+mailmime_fields_new_with_data(struct mailmime_mechanism * encoding,
+ char * id,
+ char * description,
+ struct mailmime_disposition * disposition,
+ struct mailmime_language * language);
+
+struct mailmime_fields *
+mailmime_fields_new_with_version(struct mailmime_mechanism * encoding,
+ char * id,
+ char * description,
+ struct mailmime_disposition * disposition,
+ struct mailmime_language * language);
+
+struct mailmime_content * mailmime_get_content_message(void);
+struct mailmime_content * mailmime_get_content_text(void);
+/* struct mailmime_content * mailmime_get_content(char * mime_type); */
+
+#define mailmime_get_content mailmime_content_new_with_str
+
+struct mailmime_data *
+mailmime_data_new_data(int encoding, int encoded,
+ const char * data, size_t length);
+
+struct mailmime_data *
+mailmime_data_new_file(int encoding, int encoded,
+ char * filename);
+
+#if 0
+struct mailmime *
+mailmime_new_message_file(char * filename);
+
+struct mailmime *
+mailmime_new_message_text(char * data_str, size_t length);
+#endif
+
+struct mailmime *
+mailmime_new_message_data(struct mailmime * msg_mime);
+
+struct mailmime *
+mailmime_new_empty(struct mailmime_content * content,
+ struct mailmime_fields * mime_fields);
+
+int
+mailmime_new_with_content(const char * content_type,
+ struct mailmime_fields * mime_fields,
+ struct mailmime ** result);
+
+int mailmime_set_preamble_file(struct mailmime * build_info,
+ char * filename);
+
+int mailmime_set_epilogue_file(struct mailmime * build_info,
+ char * filename);
+
+int mailmime_set_preamble_text(struct mailmime * build_info,
+ char * data_str, size_t length);
+
+int mailmime_set_epilogue_text(struct mailmime * build_info,
+ char * data_str, size_t length);
+
+int mailmime_set_body_file(struct mailmime * build_info,
+ char * filename);
+
+int mailmime_set_body_text(struct mailmime * build_info,
+ char * data_str, size_t length);
+
+int mailmime_add_part(struct mailmime * build_info,
+ struct mailmime * part);
+
+void mailmime_remove_part(struct mailmime * mime);
+
+void mailmime_set_imf_fields(struct mailmime * build_info,
+ struct mailimf_fields * fields);
+
+
+struct mailmime_disposition *
+mailmime_disposition_new_with_data(int type,
+ char * filename, char * creation_date, char * modification_date,
+ char * read_date, size_t size);
+
+void mailmime_single_fields_init(struct mailmime_single_fields * single_fields,
+ struct mailmime_fields * fld_fields,
+ struct mailmime_content * fld_content);
+
+struct mailmime_single_fields *
+mailmime_single_fields_new(struct mailmime_fields * fld_fields,
+ struct mailmime_content * fld_content);
+
+void mailmime_single_fields_free(struct mailmime_single_fields *
+ single_fields);
+
+int mailmime_smart_add_part(struct mailmime * mime,
+ struct mailmime * mime_sub);
+
+int mailmime_smart_remove_part(struct mailmime * mime);
+
+struct mailmime_content * mailmime_content_new_with_str(const char * str);
+
+struct mailmime_fields * mailmime_fields_new_encoding(int type);
+
+struct mailmime * mailmime_multiple_new(const char * type);
+
+struct mailmime_fields * mailmime_fields_new_filename(int dsp_type,
+ char * filename, int encoding_type);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libetpan/src/low-level/mime/mailmime_write.c b/libetpan/src/low-level/mime/mailmime_write.c
new file mode 100644
index 0000000..4bce0d5
--- a/dev/null
+++ b/libetpan/src/low-level/mime/mailmime_write.c
@@ -0,0 +1,1416 @@
+/*
+ * 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 "mailmime_write.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+
+#include "mailimf_write.h"
+#include "mailmime_content.h"
+#include "mailmime_types_helper.h"
+
+#define MAX_MAIL_COL 78
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+static int mailmime_field_write(FILE * f, int * col,
+ struct mailmime_field * field);
+
+static int mailmime_id_write(FILE * f, int * col, char * id);
+
+static int mailmime_description_write(FILE * f, int * col, char * descr);
+
+static int mailmime_version_write(FILE * f, int * col, uint32_t version);
+
+static int mailmime_encoding_write(FILE * f, int * col,
+ struct mailmime_mechanism * encoding);
+
+static int mailmime_language_write(FILE * f, int * col,
+ struct mailmime_language * language);
+
+static int mailmime_disposition_write(FILE * f, int * col,
+ struct mailmime_disposition *
+ disposition);
+
+static int
+mailmime_disposition_param_write(FILE * f, int * col,
+ struct mailmime_disposition_parm * param);
+
+static int mailmime_parameter_write(FILE * f, int * col,
+ struct mailmime_parameter * param);
+
+/*
+static int mailmime_content_write(FILE * f, int * col,
+ struct mailmime_content * content);
+*/
+
+static int mailmime_type_write(FILE * f, int * col,
+ struct mailmime_type * type);
+
+static int
+mailmime_discrete_type_write(FILE * f, int * col,
+ struct mailmime_discrete_type * discrete_type);
+
+static int
+mailmime_composite_type_write(FILE * f, int * col,
+ struct mailmime_composite_type * composite_type);
+
+static int mailmime_sub_write(FILE * f, int * col,
+ struct mailmime * build_info);
+
+
+/* ***** */
+
+int mailmime_fields_write(FILE * f, int * col, struct mailmime_fields * fields)
+{
+ int r;
+ clistiter * cur;
+
+ for(cur = clist_begin(fields->fld_list) ; cur != NULL ;
+ cur = clist_next(cur)) {
+ struct mailmime_field * field;
+
+ field = cur->data;
+ r = mailmime_field_write(f, col, field);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ }
+
+ return MAILIMF_NO_ERROR;
+}
+
+static int mailmime_field_write(FILE * f, int * col,
+ struct mailmime_field * field)
+{
+ int r;
+
+ switch (field->fld_type) {
+ case MAILMIME_FIELD_TYPE:
+ r = mailmime_content_write(f, col, field->fld_data.fld_content);
+ break;
+
+ case MAILMIME_FIELD_TRANSFER_ENCODING:
+ r = mailmime_encoding_write(f, col, field->fld_data.fld_encoding);
+ break;
+
+ case MAILMIME_FIELD_ID:
+ r = mailmime_id_write(f, col, field->fld_data.fld_id);
+ break;
+
+ case MAILMIME_FIELD_DESCRIPTION:
+ r = mailmime_description_write(f, col, field->fld_data.fld_description);
+ break;
+
+ case MAILMIME_FIELD_VERSION:
+ r = mailmime_version_write(f, col, field->fld_data.fld_version);
+ break;
+
+ case MAILMIME_FIELD_DISPOSITION:
+ r = mailmime_disposition_write(f, col, field->fld_data.fld_disposition);
+ break;
+
+ case MAILMIME_FIELD_LANGUAGE:
+ r = mailmime_language_write(f, col, field->fld_data.fld_language);
+ break;
+
+ default:
+ r = MAILIMF_ERROR_INVAL;
+ break;
+ }
+
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ return MAILIMF_NO_ERROR;
+}
+
+static int mailmime_id_write(FILE * f, int * col, char * id)
+{
+ int r;
+
+ r = mailimf_string_write(f, col, "Content-ID: ", 12);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_string_write(f, col, "<", 1);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_string_write(f, col, id, strlen(id));
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_string_write(f, col, ">", 1);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_string_write(f, col, "\r\n", 2);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+#if 0
+ * col = 0;
+#endif
+
+ return MAILIMF_NO_ERROR;
+}
+
+static int mailmime_description_write(FILE * f, int * col, char * descr)
+{
+ int r;
+
+ r = mailimf_string_write(f, col, "Content-Description: ", 21);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_string_write(f, col, descr, strlen(descr));
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_string_write(f, col, "\r\n", 2);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+#if 0
+ * col = 0;
+#endif
+
+ return MAILIMF_NO_ERROR;
+}
+
+static int mailmime_version_write(FILE * f, int * col, uint32_t version)
+{
+ int r;
+ char versionstr[40];
+
+ r = mailimf_string_write(f, col, "MIME-Version: ", 14);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ snprintf(versionstr, 40, "%i.%i", version >> 16, version & 0xFFFF);
+
+ r = mailimf_string_write(f, col, versionstr, strlen(versionstr));
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_string_write(f, col, "\r\n", 2);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+#if 0
+ * col = 0;
+#endif
+
+ return MAILIMF_NO_ERROR;
+}
+
+static int mailmime_encoding_write(FILE * f, int * col,
+ struct mailmime_mechanism * encoding)
+{
+ int r;
+
+ r = mailimf_string_write(f, col, "Content-Transfer-Encoding: ", 27);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ switch (encoding->enc_type) {
+ case MAILMIME_MECHANISM_7BIT:
+ r = mailimf_string_write(f, col, "7bit", 4);
+ break;
+
+ case MAILMIME_MECHANISM_8BIT:
+ r = mailimf_string_write(f, col, "8bit", 4);
+ break;
+
+ case MAILMIME_MECHANISM_BINARY:
+ r = mailimf_string_write(f, col, "binary", 6);
+ break;
+
+ case MAILMIME_MECHANISM_QUOTED_PRINTABLE:
+ r = mailimf_string_write(f, col, "quoted-printable", 16);
+ break;
+
+ case MAILMIME_MECHANISM_BASE64:
+ r = mailimf_string_write(f, col, "base64", 6);
+ break;
+
+ case MAILMIME_MECHANISM_TOKEN:
+ r = mailimf_string_write(f, col, encoding->enc_token,
+ strlen(encoding->enc_token));
+ break;
+
+ default:
+ r = MAILIMF_ERROR_INVAL;
+ break;
+ }
+
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_string_write(f, col, "\r\n", 2);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+#if 0
+ * col = 0;
+#endif
+
+ return MAILIMF_NO_ERROR;
+}
+
+static int mailmime_language_write(FILE * f, int * col,
+ struct mailmime_language * language)
+{
+ int r;
+ clistiter * cur;
+ int first;
+
+ r = mailimf_string_write(f, col, "Content-Language: ", 18);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ first = TRUE;
+
+ for(cur = clist_begin(language->lg_list) ; cur != NULL ;
+ cur = clist_next(cur)) {
+ char * lang;
+ size_t len;
+
+ lang = clist_content(cur);
+ len = strlen(lang);
+
+ if (!first) {
+ r = mailimf_string_write(f, col, ", ", 2);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ }
+ else {
+ first = FALSE;
+ }
+
+ if (* col > 1) {
+
+ if (* col + len > MAX_MAIL_COL) {
+ r = mailimf_string_write(f, col, "\r\n ", 3);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+#if 0
+ * col = 1;
+#endif
+ }
+ }
+
+ r = mailimf_string_write(f, col, lang, len);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ }
+
+ r = mailimf_string_write(f, col, "\r\n", 2);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+#if 0
+ * col = 0;
+#endif
+
+ return MAILIMF_NO_ERROR;
+}
+
+static int mailmime_disposition_write(FILE * f, int * col,
+ struct mailmime_disposition *
+ disposition)
+{
+ struct mailmime_disposition_type * dsp_type;
+ int r;
+ clistiter * cur;
+
+ dsp_type = disposition->dsp_type;
+
+ r = mailimf_string_write(f, col, "Content-Disposition: ", 21);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ switch (dsp_type->dsp_type) {
+ case MAILMIME_DISPOSITION_TYPE_INLINE:
+ r = mailimf_string_write(f, col, "inline", 6);
+ break;
+
+ case MAILMIME_DISPOSITION_TYPE_ATTACHMENT:
+ r = mailimf_string_write(f, col, "attachment", 10);
+ break;
+
+ case MAILMIME_DISPOSITION_TYPE_EXTENSION:
+ r = mailimf_string_write(f, col, dsp_type->dsp_extension,
+ strlen(dsp_type->dsp_extension));
+ break;
+
+ default:
+ r = MAILIMF_ERROR_INVAL;
+ break;
+ }
+
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ for(cur = clist_begin(disposition->dsp_parms) ;
+ cur != NULL ; cur = clist_next(cur)) {
+ struct mailmime_disposition_parm * param;
+
+ param = cur->data;
+
+ r = mailimf_string_write(f, col, "; ", 2);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailmime_disposition_param_write(f, col, param);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ }
+
+ r = mailimf_string_write(f, col, "\r\n", 2);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ return MAILIMF_NO_ERROR;
+}
+
+static int
+mailmime_disposition_param_write(FILE * f, int * col,
+ struct mailmime_disposition_parm * param)
+{
+ size_t len;
+ char sizestr[20];
+ int r;
+
+ switch (param->pa_type) {
+ case MAILMIME_DISPOSITION_PARM_FILENAME:
+ len = strlen("filename=") + strlen(param->pa_data.pa_filename);
+ break;
+
+ case MAILMIME_DISPOSITION_PARM_CREATION_DATE:
+ len = strlen("creation-date=") + strlen(param->pa_data.pa_creation_date);
+ break;
+
+ case MAILMIME_DISPOSITION_PARM_MODIFICATION_DATE:
+ len = strlen("modification-date=") +
+ strlen(param->pa_data.pa_modification_date);
+ break;
+
+ case MAILMIME_DISPOSITION_PARM_READ_DATE:
+ len = strlen("read-date=") + strlen(param->pa_data.pa_read_date);
+ break;
+
+ case MAILMIME_DISPOSITION_PARM_SIZE:
+ snprintf(sizestr, 20, "%lu", (unsigned long) param->pa_data.pa_size);
+ len = strlen("size=") + strlen(sizestr);
+ break;
+
+ case MAILMIME_DISPOSITION_PARM_PARAMETER:
+ len = strlen(param->pa_data.pa_parameter->pa_name) + 1 +
+ strlen(param->pa_data.pa_parameter->pa_value);
+ break;
+
+ default:
+ return MAILIMF_ERROR_INVAL;
+ }
+
+ if (* col > 1) {
+
+ if (* col + len > MAX_MAIL_COL) {
+ r = mailimf_string_write(f, col, "\r\n ", 3);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+#if 0
+ * col = 1;
+#endif
+ }
+ }
+
+ switch (param->pa_type) {
+ case MAILMIME_DISPOSITION_PARM_FILENAME:
+ r = mailimf_string_write(f, col, "filename=", 9);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_quoted_string_write(f, col,
+ param->pa_data.pa_filename, strlen(param->pa_data.pa_filename));
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ break;
+
+ case MAILMIME_DISPOSITION_PARM_CREATION_DATE:
+ r = mailimf_string_write(f, col, "creation-date=", 14);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_quoted_string_write(f, col, param->pa_data.pa_creation_date,
+ strlen(param->pa_data.pa_creation_date));
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ break;
+
+ case MAILMIME_DISPOSITION_PARM_MODIFICATION_DATE:
+ r = mailimf_string_write(f, col, "modification-date=", 18);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_quoted_string_write(f, col,
+ param->pa_data.pa_modification_date,
+ strlen(param->pa_data.pa_modification_date));
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ break;
+
+ case MAILMIME_DISPOSITION_PARM_READ_DATE:
+ r = mailimf_string_write(f, col, "read-date=", 10);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_quoted_string_write(f, col, param->pa_data.pa_read_date,
+ strlen(param->pa_data.pa_read_date));
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ break;
+
+ case MAILMIME_DISPOSITION_PARM_SIZE:
+ r = mailimf_string_write(f, col, "size=", 5);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_string_write(f, col, sizestr, strlen(sizestr));
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ break;
+
+ case MAILMIME_DISPOSITION_PARM_PARAMETER:
+ r = mailmime_parameter_write(f, col, param->pa_data.pa_parameter);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ break;
+ }
+
+ return MAILIMF_NO_ERROR;
+}
+
+static int mailmime_parameter_write(FILE * f, int * col,
+ struct mailmime_parameter * param)
+{
+ int r;
+
+ r = mailimf_string_write(f, col, param->pa_name,
+ strlen(param->pa_name));
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_string_write(f, col, "=", 1);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_quoted_string_write(f, col, param->pa_value,
+ strlen(param->pa_value));
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ return MAILIMF_NO_ERROR;
+}
+
+int mailmime_content_type_write(FILE * f, int * col,
+ struct mailmime_content * content)
+{
+ clistiter * cur;
+ size_t len;
+ int r;
+
+ r = mailmime_type_write(f, col, content->ct_type);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_string_write(f, col, "/", 1);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_string_write(f, col, content->ct_subtype,
+ strlen(content->ct_subtype));
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ if (content->ct_parameters != NULL) {
+ for(cur = clist_begin(content->ct_parameters) ;
+ cur != NULL ; cur = clist_next(cur)) {
+ struct mailmime_parameter * param;
+
+ param = cur->data;
+
+ r = mailimf_string_write(f, col, "; ", 2);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ len = strlen(param->pa_name) + 1 + strlen(param->pa_value);
+
+ if (* col > 1) {
+
+ if (* col + len > MAX_MAIL_COL) {
+ r = mailimf_string_write(f, col, "\r\n ", 3);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+#if 0
+ * col = 1;
+#endif
+ }
+ }
+
+ r = mailmime_parameter_write(f, col, param);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ }
+ }
+
+ return MAILIMF_NO_ERROR;
+}
+
+int mailmime_content_write(FILE * f, int * col,
+ struct mailmime_content * content)
+{
+ int r;
+
+ r = mailimf_string_write(f, col, "Content-Type: ", 14);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailmime_content_type_write(f, col, content);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_string_write(f, col, "\r\n", 2);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ return MAILIMF_NO_ERROR;
+}
+
+static int mailmime_type_write(FILE * f, int * col,
+ struct mailmime_type * type)
+{
+ int r;
+
+ switch (type->tp_type) {
+ case MAILMIME_TYPE_DISCRETE_TYPE:
+ r = mailmime_discrete_type_write(f, col, type->tp_data.tp_discrete_type);
+ break;
+
+ case MAILMIME_TYPE_COMPOSITE_TYPE:
+ r = mailmime_composite_type_write(f, col, type->tp_data.tp_composite_type);
+ break;
+
+ default:
+ r = MAILIMF_ERROR_INVAL;
+ break;
+ }
+
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ return MAILIMF_NO_ERROR;
+}
+
+static int
+mailmime_discrete_type_write(FILE * f, int * col,
+ struct mailmime_discrete_type * discrete_type)
+{
+ int r;
+
+ switch (discrete_type->dt_type) {
+ case MAILMIME_DISCRETE_TYPE_TEXT:
+ r = mailimf_string_write(f, col, "text", 4);
+ break;
+
+ case MAILMIME_DISCRETE_TYPE_IMAGE:
+ r = mailimf_string_write(f, col, "image", 5);
+ break;
+
+ case MAILMIME_DISCRETE_TYPE_AUDIO:
+ r = mailimf_string_write(f, col, "audio", 5);
+ break;
+
+ case MAILMIME_DISCRETE_TYPE_VIDEO:
+ r = mailimf_string_write(f, col, "video", 5);
+ break;
+
+ case MAILMIME_DISCRETE_TYPE_APPLICATION:
+ r = mailimf_string_write(f, col, "application", 11);
+ break;
+
+ case MAILMIME_DISCRETE_TYPE_EXTENSION:
+ r = mailimf_string_write(f, col, discrete_type->dt_extension,
+ strlen(discrete_type->dt_extension));
+ break;
+
+ default:
+ r = MAILIMF_ERROR_INVAL;
+ break;
+ }
+
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ return MAILIMF_NO_ERROR;
+}
+
+static int
+mailmime_composite_type_write(FILE * f, int * col,
+ struct mailmime_composite_type * composite_type)
+{
+ int r;
+
+ switch (composite_type->ct_type) {
+ case MAILMIME_COMPOSITE_TYPE_MESSAGE:
+ r = mailimf_string_write(f, col, "message", 7);
+ break;
+
+ case MAILMIME_COMPOSITE_TYPE_MULTIPART:
+ r = mailimf_string_write(f, col, "multipart", 9);
+ break;
+
+ case MAILMIME_COMPOSITE_TYPE_EXTENSION:
+ r = mailimf_string_write(f, col, composite_type->ct_token,
+ strlen(composite_type->ct_token));
+ break;
+
+ default:
+ r = MAILIMF_ERROR_INVAL;
+ break;
+ }
+
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ return MAILIMF_NO_ERROR;
+}
+
+
+
+
+/* ****************************************************************** */
+/* message */
+
+/*
+static int mailmime_data_write(FILE * f, int * col,
+ struct mailmime_data * data,
+ int is_text);
+*/
+
+static int mailmime_text_content_write(FILE * f, int * col, int encoding,
+ int istext,
+ const char * text, size_t size);
+
+/*
+static int mailmime_base64_write(FILE * f, int * col,
+ char * text, size_t size);
+
+static int mailmime_quoted_printable_write(FILE * f, int * col, int istext,
+ char * text, size_t size);
+*/
+
+static int mailmime_part_write(FILE * f, int * col,
+ struct mailmime * build_info)
+{
+ clistiter * cur;
+ int first;
+ int r;
+ char * boundary;
+ int istext;
+
+ istext = TRUE;
+ boundary = NULL;
+
+ if (build_info->mm_content_type != NULL) {
+ if (build_info->mm_type == MAILMIME_MULTIPLE) {
+ boundary = mailmime_extract_boundary(build_info->mm_content_type);
+ if (boundary == NULL)
+ return MAILIMF_ERROR_INVAL;
+ }
+
+ if (build_info->mm_content_type->ct_type->tp_type ==
+ MAILMIME_TYPE_DISCRETE_TYPE) {
+ if (build_info->mm_content_type->ct_type->tp_data.tp_discrete_type->dt_type !=
+ MAILMIME_DISCRETE_TYPE_TEXT)
+ istext = FALSE;
+ }
+ }
+
+ switch (build_info->mm_type) {
+ case MAILMIME_SINGLE:
+
+ /* 1-part body */
+
+ if (build_info->mm_data.mm_single != NULL) {
+ r = mailmime_data_write(f, col, build_info->mm_data.mm_single, istext);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ }
+
+ break;
+
+ case MAILMIME_MULTIPLE:
+
+ /* multi-part */
+
+
+ /* preamble */
+
+ if (build_info->mm_data.mm_multipart.mm_preamble != NULL) {
+ r = mailmime_data_write(f, col,
+ build_info->mm_data.mm_multipart.mm_preamble, TRUE);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_string_write(f, col, "\r\n", 2);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+#if 0
+ * col = 0;
+#endif
+ }
+
+ /* sub-parts */
+
+ first = TRUE;
+
+ for(cur = clist_begin(build_info->mm_data.mm_multipart.mm_mp_list) ;
+ cur != NULL ; cur = clist_next(cur)) {
+ struct mailmime * subpart;
+
+ subpart = cur->data;
+
+ if (!first) {
+ r = mailimf_string_write(f, col, "\r\n", 2);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+#if 0
+ * col = 0;
+#endif
+ }
+ else {
+ first = FALSE;
+ }
+
+ r = mailimf_string_write(f, col, "--", 2);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_string_write(f, col, boundary, strlen(boundary));
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_string_write(f, col, "\r\n", 2);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+#if 0
+ * col = 0;
+#endif
+
+ r = mailmime_sub_write(f, col, subpart);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ }
+
+ r = mailimf_string_write(f, col, "\r\n", 2);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+#if 0
+ * col = 0;
+#endif
+
+ r = mailimf_string_write(f, col, "--", 2);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_string_write(f, col, boundary, strlen(boundary));
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_string_write(f, col, "--", 2);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+
+ /* epilogue */
+
+ r = mailimf_string_write(f, col, "\r\n", 2);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+#if 0
+ * col = 0;
+#endif
+
+ if (build_info->mm_data.mm_multipart.mm_epilogue != NULL) {
+ r = mailmime_data_write(f, col,
+ build_info->mm_data.mm_multipart.mm_epilogue, TRUE);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ }
+
+ break;
+
+ case MAILMIME_MESSAGE:
+
+ if (build_info->mm_data.mm_message.mm_fields != NULL) {
+ r = mailimf_fields_write(f, col,
+ build_info->mm_data.mm_message.mm_fields);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ }
+
+ if (build_info->mm_mime_fields != NULL) {
+ r = mailmime_fields_write(f, col, build_info->mm_mime_fields);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ }
+
+ /* encapsuled message */
+
+ if (build_info->mm_data.mm_message.mm_msg_mime != NULL) {
+ r = mailmime_sub_write(f, col,
+ build_info->mm_data.mm_message.mm_msg_mime);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ }
+ break;
+
+ }
+
+ return MAILIMF_NO_ERROR;
+}
+
+
+static int mailmime_sub_write(FILE * f, int * col,
+ struct mailmime * build_info)
+{
+ int r;
+
+#if 0
+ * col = 0;
+#endif
+ /* MIME field - Content-Type */
+
+ if (build_info->mm_content_type != NULL) {
+ r = mailmime_content_write(f, col, build_info->mm_content_type);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ }
+
+ /* other MIME fields */
+
+ if (build_info->mm_type != MAILMIME_MESSAGE) {
+ if (build_info->mm_mime_fields != NULL) {
+ r = mailmime_fields_write(f, col, build_info->mm_mime_fields);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ }
+ }
+
+ r = mailimf_string_write(f, col, "\r\n", 2);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+#if 0
+ * col = 0;
+#endif
+
+ return mailmime_part_write(f, col, build_info);
+}
+
+int mailmime_write(FILE * f, int * col,
+ struct mailmime * build_info)
+{
+ if (build_info->mm_parent != NULL)
+ return mailmime_sub_write(f, col, build_info);
+ else
+ return mailmime_part_write(f, col, build_info);
+}
+
+
+int mailmime_data_write(FILE * f, int * col,
+ struct mailmime_data * data,
+ int istext)
+{
+ int fd;
+ int r;
+ char * text;
+ struct stat buf;
+ int res;
+
+ switch (data->dt_type) {
+ case MAILMIME_DATA_TEXT:
+
+ if (data->dt_encoded) {
+ r = mailimf_string_write(f, col,
+ data->dt_data.dt_text.dt_data,
+ data->dt_data.dt_text.dt_length);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ }
+ else {
+ r = mailmime_text_content_write(f, col, data->dt_encoding, istext,
+ data->dt_data.dt_text.dt_data,
+ data->dt_data.dt_text.dt_length);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ }
+
+ break;
+
+ case MAILMIME_DATA_FILE:
+ fd = open(data->dt_data.dt_filename, O_RDONLY);
+ if (fd < 0) {
+ res = MAILIMF_ERROR_FILE;
+ goto err;
+ }
+
+ r = fstat(fd, &buf);
+ if (r < 0) {
+ res = MAILIMF_ERROR_FILE;
+ goto close;
+ }
+
+ if (buf.st_size != 0) {
+ text = mmap(NULL, buf.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+ if (text == MAP_FAILED) {
+ res = MAILIMF_ERROR_FILE;
+ goto close;
+ }
+
+ if (data->dt_encoded) {
+ r = mailimf_string_write(f, col, text, buf.st_size);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto unmap;
+ }
+ }
+ else {
+ r = mailmime_text_content_write(f, col, data->dt_encoding, istext,
+ text, buf.st_size);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto unmap;
+ }
+ }
+
+ munmap(text, buf.st_size);
+ }
+ close(fd);
+
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ break;
+
+ unmap:
+ munmap(text, buf.st_size);
+ close:
+ close(fd);
+ err:
+ return res;
+ }
+
+ return MAILIMF_NO_ERROR;
+}
+
+static int mailmime_text_content_write(FILE * f, int * col, int encoding,
+ int istext,
+ const char * text, size_t size)
+{
+ switch (encoding) {
+ case MAILMIME_MECHANISM_QUOTED_PRINTABLE:
+ return mailmime_quoted_printable_write(f, col, istext, text, size);
+ break;
+
+ case MAILMIME_MECHANISM_BASE64:
+ return mailmime_base64_write(f, col, text, size);
+ break;
+
+ case MAILMIME_MECHANISM_7BIT:
+ case MAILMIME_MECHANISM_8BIT:
+ case MAILMIME_MECHANISM_BINARY:
+ default:
+ return mailimf_string_write(f, col, text, size);
+ }
+}
+
+
+static const char base64_encoding[] =
+"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+#define BASE64_MAX_COL 76
+
+int mailmime_base64_write(FILE * f, int * col,
+ const char * text, size_t size)
+{
+ int a;
+ int b;
+ int c;
+ size_t remains;
+ const char * p;
+ size_t count;
+ char ogroup[4];
+ int r;
+
+ remains = size;
+ p = text;
+
+ while (remains > 0) {
+ switch (remains) {
+ case 1:
+ a = (unsigned char) p[0];
+ b = 0;
+ c = 0;
+ count = 1;
+ break;
+ case 2:
+ a = (unsigned char) p[0];
+ b = (unsigned char) p[1];
+ c = 0;
+ count = 2;
+ break;
+ default:
+ a = (unsigned char) p[0];
+ b = (unsigned char) p[1];
+ c = (unsigned char) p[2];
+ count = 3;
+ break;
+ }
+
+ ogroup[0]= base64_encoding[a >> 2];
+ ogroup[1]= base64_encoding[((a & 3) << 4) | (b >> 4)];
+ ogroup[2]= base64_encoding[((b & 0xF) << 2) | (c >> 6)];
+ ogroup[3]= base64_encoding[c & 0x3F];
+
+ switch (count) {
+ case 1:
+ ogroup[2]= '=';
+ ogroup[3]= '=';
+ break;
+ case 2:
+ ogroup[3]= '=';
+ break;
+ }
+
+ if (* col + 4 > BASE64_MAX_COL) {
+ r = mailimf_string_write(f, col, "\r\n", 2);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+#if 0
+ * col = 0;
+#endif
+ }
+
+ r = mailimf_string_write(f, col, ogroup, 4);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ remains -= count;
+ p += count;
+ }
+
+ r = mailimf_string_write(f, col, "\r\n", 2);
+
+ return MAILIMF_NO_ERROR;
+}
+
+#if 0
+#define MAX_WRITE_SIZE 512
+#endif
+
+enum {
+ STATE_INIT,
+ STATE_CR,
+ STATE_SPACE,
+ STATE_SPACE_CR,
+};
+
+#if 0
+static inline int write_try_buf(FILE * f, int * col,
+ char ** pstart, size_t * plen)
+{
+ int r;
+
+ if (* plen >= MAX_WRITE_SIZE) {
+ r = mailimf_string_write(f, col, * pstart, * plen);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ * plen = 0;
+ }
+
+ return MAILIMF_NO_ERROR;
+}
+#endif
+
+static inline int write_remaining(FILE * f, int * col,
+ const char ** pstart, size_t * plen)
+{
+ int r;
+
+ if (* plen > 0) {
+ r = mailimf_string_write(f, col, * pstart, * plen);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ * plen = 0;
+ }
+
+ return MAILIMF_NO_ERROR;
+}
+
+
+
+#define QP_MAX_COL 72
+
+int mailmime_quoted_printable_write(FILE * f, int * col, int istext,
+ const char * text, size_t size)
+{
+ size_t i;
+ const char * start;
+ size_t len;
+ char hexstr[6];
+ int r;
+ int state;
+
+ start = text;
+ len = 0;
+ state = STATE_INIT;
+
+ i = 0;
+ while (i < size) {
+ unsigned char ch;
+
+ if (* col + len > QP_MAX_COL) {
+ r = write_remaining(f, col, &start, &len);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ start = text + i;
+
+ r = mailimf_string_write(f, col, "=\r\n", 3);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ }
+
+ ch = text[i];
+
+ switch (state) {
+
+ case STATE_INIT:
+ switch (ch) {
+ case ' ':
+ case '\t':
+ state = STATE_SPACE;
+ break;
+
+ case '\r':
+ state = STATE_CR;
+ break;
+
+ case '!':
+ case '"':
+ case '#':
+ case '$':
+ case '@':
+ case '[':
+ case '\\':
+ case ']':
+ case '^':
+ case '`':
+ case '{':
+ case '|':
+ case '}':
+ case '~':
+ case '=':
+ case '?':
+ case '_':
+ case 'F': /* there is no more 'From' at the beginning of a line */
+ r = write_remaining(f, col, &start, &len);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ start = text + i + 1;
+
+ snprintf(hexstr, 6, "=%02X", ch);
+
+ r = mailimf_string_write(f, col, hexstr, 3);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ break;
+
+ default:
+ if (istext && (ch == '\n')) {
+ r = write_remaining(f, col, &start, &len);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ start = text + i + 1;
+
+ r = mailimf_string_write(f, col, "\r\n", 2);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ break;
+ }
+ else {
+ if (((ch >= 33) && (ch <= 60)) || ((ch >= 62) && (ch <= 126))) {
+ len ++;
+ }
+ else {
+ r = write_remaining(f, col, &start, &len);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ start = text + i + 1;
+
+ snprintf(hexstr, 6, "=%02X", ch);
+
+ r = mailimf_string_write(f, col, hexstr, 3);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ }
+ }
+
+ break;
+ }
+
+ i ++;
+ break;
+
+ case STATE_CR:
+ switch (ch) {
+ case '\n':
+ r = write_remaining(f, col, &start, &len);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ start = text + i + 1;
+ r = mailimf_string_write(f, col, "\r\n", 2);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ i ++;
+ state = STATE_INIT;
+ break;
+
+ default:
+ r = write_remaining(f, col, &start, &len);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ start = text + i;
+ snprintf(hexstr, 6, "=%02X", '\r');
+ r = mailimf_string_write(f, col, hexstr, 3);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ state = STATE_INIT;
+ break;
+ }
+ break;
+
+ case STATE_SPACE:
+ switch (ch) {
+ case '\r':
+ state = STATE_SPACE_CR;
+ i ++;
+ break;
+
+ case '\n':
+ r = write_remaining(f, col, &start, &len);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ start = text + i + 1;
+ snprintf(hexstr, 6, "=%02X\r\n", text[i - 1]);
+ r = mailimf_string_write(f, col, hexstr, strlen(hexstr));
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ state = STATE_INIT;
+ i ++;
+ break;
+
+ case ' ':
+ case '\t':
+ len ++;
+ i ++;
+ break;
+
+ default:
+#if 0
+ len += 2;
+ state = STATE_INIT;
+ i ++;
+#endif
+ len ++;
+ state = STATE_INIT;
+ break;
+ }
+
+ break;
+
+ case STATE_SPACE_CR:
+ switch (ch) {
+ case '\n':
+ r = write_remaining(f, col, &start, &len);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ start = text + i + 1;
+ snprintf(hexstr, 6, "=%02X\r\n", text[i - 2]);
+ r = mailimf_string_write(f, col, hexstr, strlen(hexstr));
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ state = STATE_INIT;
+ i ++;
+ break;
+
+ default:
+ r = write_remaining(f, col, &start, &len);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ start = text + i + 1;
+ snprintf(hexstr, 6, "%c=%02X", text[i - 2], '\r');
+ r = mailimf_string_write(f, col, hexstr, strlen(hexstr));
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ state = STATE_INIT;
+ break;
+ }
+
+ break;
+ }
+ }
+
+ return MAILIMF_NO_ERROR;
+}
diff --git a/libetpan/src/low-level/mime/mailmime_write.h b/libetpan/src/low-level/mime/mailmime_write.h
new file mode 100644
index 0000000..adca123
--- a/dev/null
+++ b/libetpan/src/low-level/mime/mailmime_write.h
@@ -0,0 +1,73 @@
+/*
+ * 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$
+ */
+
+#ifndef MAILMIME_WRITE_H
+
+#define MAILMIME_WRITE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <libetpan/mailmime_types.h>
+#include <stdio.h>
+
+int mailmime_fields_write(FILE * f, int * col,
+ struct mailmime_fields * fields);
+
+int mailmime_content_write(FILE * f, int * col,
+ struct mailmime_content * content);
+
+int mailmime_content_type_write(FILE * f, int * col,
+ struct mailmime_content * content);
+
+int mailmime_write(FILE * f, int * col,
+ struct mailmime * build_info);
+
+int mailmime_quoted_printable_write(FILE * f, int * col, int istext,
+ const char * text, size_t size);
+
+int mailmime_base64_write(FILE * f, int * col,
+ const char * text, size_t size);
+
+int mailmime_data_write(FILE * f, int * col,
+ struct mailmime_data * data,
+ int istext);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libetpan/src/low-level/mime/mailmime_write_file.c b/libetpan/src/low-level/mime/mailmime_write_file.c
new file mode 100644
index 0000000..3beeff8
--- a/dev/null
+++ b/libetpan/src/low-level/mime/mailmime_write_file.c
@@ -0,0 +1,156 @@
+/*
+ * 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 "mailmime_write_file.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+
+#include "mailmime_content.h"
+#include "mailmime_types_helper.h"
+#include "mailmime_write_generic.h"
+
+static int do_write(void * data, const char * str, size_t length)
+{
+ FILE * f;
+
+ f = data;
+
+ return fwrite(str, 1, length, f);
+}
+
+
+int mailmime_fields_write_file(FILE * f, int * col,
+ struct mailmime_fields * fields)
+{
+ return mailmime_fields_write_driver(do_write, f, col, fields);
+}
+
+int mailmime_content_write_file(FILE * f, int * col,
+ struct mailmime_content * content)
+{
+ return mailmime_content_write_driver(do_write, f, col, content);
+}
+
+int mailmime_content_type_write_file(FILE * f, int * col,
+ struct mailmime_content * content)
+{
+ return mailmime_content_type_write_driver(do_write, f, col, content);
+}
+
+int mailmime_write_file(FILE * f, int * col,
+ struct mailmime * build_info)
+{
+ return mailmime_write_driver(do_write, f, col, build_info);
+}
+
+int mailmime_quoted_printable_write_file(FILE * f, int * col, int istext,
+ const char * text, size_t size)
+{
+ return mailmime_quoted_printable_write_driver(do_write, f, col,
+ istext, text, size);
+}
+
+int mailmime_base64_write_file(FILE * f, int * col,
+ const char * text, size_t size)
+{
+ return mailmime_base64_write_driver(do_write, f, col, text, size);
+}
+
+int mailmime_data_write_file(FILE * f, int * col,
+ struct mailmime_data * data,
+ int istext)
+{
+ return mailmime_data_write_driver(do_write, f, col, data, istext);
+}
+
+
+
+
+/* binary compatibility with 0.34 - begin */
+
+#ifdef MAILMIME_WRITE_COMPATIBILITY
+int mailmime_fields_write(FILE * f, int * col,
+ struct mailmime_fields * fields)
+{
+ return mailmime_fields_write_file(f, col, fields);
+}
+
+int mailmime_content_write(FILE * f, int * col,
+ struct mailmime_content * content)
+{
+ return mailmime_content_write_file(f, col, content);
+}
+
+int mailmime_content_type_write(FILE * f, int * col,
+ struct mailmime_content * content)
+{
+ return mailmime_content_type_write_file(f, col, content);
+}
+
+int mailmime_write(FILE * f, int * col,
+ struct mailmime * build_info)
+{
+ return mailmime_write_file(f, col, build_info);
+}
+
+int mailmime_quoted_printable_write(FILE * f, int * col, int istext,
+ const char * text, size_t size)
+{
+ return mailmime_quoted_printable_write_file(f, col,
+ istext, text, size);
+}
+
+int mailmime_base64_write(FILE * f, int * col,
+ const char * text, size_t size)
+{
+ return mailmime_base64_write_file(f, col, text, size);
+}
+
+int mailmime_data_write(FILE * f, int * col,
+ struct mailmime_data * data,
+ int istext)
+{
+ return mailmime_data_write_file(f, col, data, istext);
+}
+#endif
+
+/* binary compatibility with 0.34 - end */
diff --git a/libetpan/src/low-level/mime/mailmime_write_file.h b/libetpan/src/low-level/mime/mailmime_write_file.h
new file mode 100644
index 0000000..4cfa484
--- a/dev/null
+++ b/libetpan/src/low-level/mime/mailmime_write_file.h
@@ -0,0 +1,105 @@
+/*
+ * 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$
+ */
+
+#ifndef MAILMIME_WRITE_FILE_H
+
+#define MAILMIME_WRITE_FILE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <libetpan/mailmime_types.h>
+#include <stdio.h>
+
+ //#define MAILMIME_WRITE_COMPATIBILITY
+
+
+int mailmime_fields_write_file(FILE * f, int * col,
+ struct mailmime_fields * fields);
+
+int mailmime_content_write_file(FILE * f, int * col,
+ struct mailmime_content * content);
+
+int mailmime_content_type_write_file(FILE * f, int * col,
+ struct mailmime_content * content);
+
+int mailmime_write_file(FILE * f, int * col,
+ struct mailmime * build_info);
+
+int mailmime_quoted_printable_write_file(FILE * f, int * col, int istext,
+ const char * text, size_t size);
+
+int mailmime_base64_write_file(FILE * f, int * col,
+ const char * text, size_t size);
+
+int mailmime_data_write_file(FILE * f, int * col,
+ struct mailmime_data * data,
+ int istext);
+
+
+/* binary compatibility with 0.34 - begin */
+
+#ifdef MAILMIME_WRITE_COMPATIBILITY
+int mailmime_fields_write(FILE * f, int * col,
+ struct mailmime_fields * fields);
+
+int mailmime_content_write(FILE * f, int * col,
+ struct mailmime_content * content);
+
+int mailmime_content_type_write(FILE * f, int * col,
+ struct mailmime_content * content);
+
+int mailmime_write(FILE * f, int * col,
+ struct mailmime * build_info);
+
+int mailmime_quoted_printable_write(FILE * f, int * col, int istext,
+ const char * text, size_t size);
+
+int mailmime_base64_write(FILE * f, int * col,
+ const char * text, size_t size);
+
+int mailmime_data_write(FILE * f, int * col,
+ struct mailmime_data * data,
+ int istext);
+#endif
+
+/* binary compatibility with 0.34 - end */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libetpan/src/low-level/mime/mailmime_write_generic.c b/libetpan/src/low-level/mime/mailmime_write_generic.c
new file mode 100644
index 0000000..4a55881
--- a/dev/null
+++ b/libetpan/src/low-level/mime/mailmime_write_generic.c
@@ -0,0 +1,1416 @@
+/*
+ * 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 "mailmime_write_generic.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+
+#include "mailimf_write_generic.h"
+#include "mailmime_content.h"
+#include "mailmime_types_helper.h"
+
+#define MAX_MAIL_COL 78
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+static int mailmime_field_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
+ struct mailmime_field * field);
+
+static int mailmime_id_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col, char * id);
+
+static int mailmime_description_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col, char * descr);
+
+static int mailmime_version_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col, uint32_t version);
+
+static int mailmime_encoding_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
+ struct mailmime_mechanism * encoding);
+
+static int mailmime_language_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
+ struct mailmime_language * language);
+
+static int mailmime_disposition_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
+ struct mailmime_disposition *
+ disposition);
+
+static int
+mailmime_disposition_param_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
+ struct mailmime_disposition_parm * param);
+
+static int mailmime_parameter_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
+ struct mailmime_parameter * param);
+
+/*
+static int mailmime_content_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
+ struct mailmime_content * content);
+*/
+
+static int mailmime_type_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
+ struct mailmime_type * type);
+
+static int
+mailmime_discrete_type_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
+ struct mailmime_discrete_type * discrete_type);
+
+static int
+mailmime_composite_type_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
+ struct mailmime_composite_type * composite_type);
+
+static int mailmime_sub_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
+ struct mailmime * build_info);
+
+
+/* ***** */
+
+int mailmime_fields_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col, struct mailmime_fields * fields)
+{
+ int r;
+ clistiter * cur;
+
+ for(cur = clist_begin(fields->fld_list) ; cur != NULL ;
+ cur = clist_next(cur)) {
+ struct mailmime_field * field;
+
+ field = cur->data;
+ r = mailmime_field_write_driver(do_write, data, col, field);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ }
+
+ return MAILIMF_NO_ERROR;
+}
+
+static int mailmime_field_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
+ struct mailmime_field * field)
+{
+ int r;
+
+ switch (field->fld_type) {
+ case MAILMIME_FIELD_TYPE:
+ r = mailmime_content_write_driver(do_write, data, col, field->fld_data.fld_content);
+ break;
+
+ case MAILMIME_FIELD_TRANSFER_ENCODING:
+ r = mailmime_encoding_write_driver(do_write, data, col, field->fld_data.fld_encoding);
+ break;
+
+ case MAILMIME_FIELD_ID:
+ r = mailmime_id_write_driver(do_write, data, col, field->fld_data.fld_id);
+ break;
+
+ case MAILMIME_FIELD_DESCRIPTION:
+ r = mailmime_description_write_driver(do_write, data, col, field->fld_data.fld_description);
+ break;
+
+ case MAILMIME_FIELD_VERSION:
+ r = mailmime_version_write_driver(do_write, data, col, field->fld_data.fld_version);
+ break;
+
+ case MAILMIME_FIELD_DISPOSITION:
+ r = mailmime_disposition_write_driver(do_write, data, col, field->fld_data.fld_disposition);
+ break;
+
+ case MAILMIME_FIELD_LANGUAGE:
+ r = mailmime_language_write_driver(do_write, data, col, field->fld_data.fld_language);
+ break;
+
+ default:
+ r = MAILIMF_ERROR_INVAL;
+ break;
+ }
+
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ return MAILIMF_NO_ERROR;
+}
+
+static int mailmime_id_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col, char * id)
+{
+ int r;
+
+ r = mailimf_string_write_driver(do_write, data, col, "Content-ID: ", 12);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_string_write_driver(do_write, data, col, "<", 1);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_string_write_driver(do_write, data, col, id, strlen(id));
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_string_write_driver(do_write, data, col, ">", 1);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_string_write_driver(do_write, data, col, "\r\n", 2);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+#if 0
+ * col = 0;
+#endif
+
+ return MAILIMF_NO_ERROR;
+}
+
+static int mailmime_description_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col, char * descr)
+{
+ int r;
+
+ r = mailimf_string_write_driver(do_write, data, col, "Content-Description: ", 21);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_string_write_driver(do_write, data, col, descr, strlen(descr));
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_string_write_driver(do_write, data, col, "\r\n", 2);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+#if 0
+ * col = 0;
+#endif
+
+ return MAILIMF_NO_ERROR;
+}
+
+static int mailmime_version_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col, uint32_t version)
+{
+ int r;
+ char versionstr[40];
+
+ r = mailimf_string_write_driver(do_write, data, col, "MIME-Version: ", 14);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ snprintf(versionstr, 40, "%i.%i", version >> 16, version & 0xFFFF);
+
+ r = mailimf_string_write_driver(do_write, data, col, versionstr, strlen(versionstr));
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_string_write_driver(do_write, data, col, "\r\n", 2);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+#if 0
+ * col = 0;
+#endif
+
+ return MAILIMF_NO_ERROR;
+}
+
+static int mailmime_encoding_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
+ struct mailmime_mechanism * encoding)
+{
+ int r;
+
+ r = mailimf_string_write_driver(do_write, data, col, "Content-Transfer-Encoding: ", 27);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ switch (encoding->enc_type) {
+ case MAILMIME_MECHANISM_7BIT:
+ r = mailimf_string_write_driver(do_write, data, col, "7bit", 4);
+ break;
+
+ case MAILMIME_MECHANISM_8BIT:
+ r = mailimf_string_write_driver(do_write, data, col, "8bit", 4);
+ break;
+
+ case MAILMIME_MECHANISM_BINARY:
+ r = mailimf_string_write_driver(do_write, data, col, "binary", 6);
+ break;
+
+ case MAILMIME_MECHANISM_QUOTED_PRINTABLE:
+ r = mailimf_string_write_driver(do_write, data, col, "quoted-printable", 16);
+ break;
+
+ case MAILMIME_MECHANISM_BASE64:
+ r = mailimf_string_write_driver(do_write, data, col, "base64", 6);
+ break;
+
+ case MAILMIME_MECHANISM_TOKEN:
+ r = mailimf_string_write_driver(do_write, data, col, encoding->enc_token,
+ strlen(encoding->enc_token));
+ break;
+
+ default:
+ r = MAILIMF_ERROR_INVAL;
+ break;
+ }
+
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_string_write_driver(do_write, data, col, "\r\n", 2);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+#if 0
+ * col = 0;
+#endif
+
+ return MAILIMF_NO_ERROR;
+}
+
+static int mailmime_language_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
+ struct mailmime_language * language)
+{
+ int r;
+ clistiter * cur;
+ int first;
+
+ r = mailimf_string_write_driver(do_write, data, col, "Content-Language: ", 18);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ first = TRUE;
+
+ for(cur = clist_begin(language->lg_list) ; cur != NULL ;
+ cur = clist_next(cur)) {
+ char * lang;
+ size_t len;
+
+ lang = clist_content(cur);
+ len = strlen(lang);
+
+ if (!first) {
+ r = mailimf_string_write_driver(do_write, data, col, ", ", 2);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ }
+ else {
+ first = FALSE;
+ }
+
+ if (* col > 1) {
+
+ if (* col + len > MAX_MAIL_COL) {
+ r = mailimf_string_write_driver(do_write, data, col, "\r\n ", 3);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+#if 0
+ * col = 1;
+#endif
+ }
+ }
+
+ r = mailimf_string_write_driver(do_write, data, col, lang, len);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ }
+
+ r = mailimf_string_write_driver(do_write, data, col, "\r\n", 2);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+#if 0
+ * col = 0;
+#endif
+
+ return MAILIMF_NO_ERROR;
+}
+
+static int mailmime_disposition_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
+ struct mailmime_disposition *
+ disposition)
+{
+ struct mailmime_disposition_type * dsp_type;
+ int r;
+ clistiter * cur;
+
+ dsp_type = disposition->dsp_type;
+
+ r = mailimf_string_write_driver(do_write, data, col, "Content-Disposition: ", 21);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ switch (dsp_type->dsp_type) {
+ case MAILMIME_DISPOSITION_TYPE_INLINE:
+ r = mailimf_string_write_driver(do_write, data, col, "inline", 6);
+ break;
+
+ case MAILMIME_DISPOSITION_TYPE_ATTACHMENT:
+ r = mailimf_string_write_driver(do_write, data, col, "attachment", 10);
+ break;
+
+ case MAILMIME_DISPOSITION_TYPE_EXTENSION:
+ r = mailimf_string_write_driver(do_write, data, col, dsp_type->dsp_extension,
+ strlen(dsp_type->dsp_extension));
+ break;
+
+ default:
+ r = MAILIMF_ERROR_INVAL;
+ break;
+ }
+
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ for(cur = clist_begin(disposition->dsp_parms) ;
+ cur != NULL ; cur = clist_next(cur)) {
+ struct mailmime_disposition_parm * param;
+
+ param = cur->data;
+
+ r = mailimf_string_write_driver(do_write, data, col, "; ", 2);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailmime_disposition_param_write_driver(do_write, data, col, param);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ }
+
+ r = mailimf_string_write_driver(do_write, data, col, "\r\n", 2);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ return MAILIMF_NO_ERROR;
+}
+
+static int
+mailmime_disposition_param_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
+ struct mailmime_disposition_parm * param)
+{
+ size_t len;
+ char sizestr[20];
+ int r;
+
+ switch (param->pa_type) {
+ case MAILMIME_DISPOSITION_PARM_FILENAME:
+ len = strlen("filename=") + strlen(param->pa_data.pa_filename);
+ break;
+
+ case MAILMIME_DISPOSITION_PARM_CREATION_DATE:
+ len = strlen("creation-date=") + strlen(param->pa_data.pa_creation_date);
+ break;
+
+ case MAILMIME_DISPOSITION_PARM_MODIFICATION_DATE:
+ len = strlen("modification-date=") +
+ strlen(param->pa_data.pa_modification_date);
+ break;
+
+ case MAILMIME_DISPOSITION_PARM_READ_DATE:
+ len = strlen("read-date=") + strlen(param->pa_data.pa_read_date);
+ break;
+
+ case MAILMIME_DISPOSITION_PARM_SIZE:
+ snprintf(sizestr, 20, "%lu", (unsigned long) param->pa_data.pa_size);
+ len = strlen("size=") + strlen(sizestr);
+ break;
+
+ case MAILMIME_DISPOSITION_PARM_PARAMETER:
+ len = strlen(param->pa_data.pa_parameter->pa_name) + 1 +
+ strlen(param->pa_data.pa_parameter->pa_value);
+ break;
+
+ default:
+ return MAILIMF_ERROR_INVAL;
+ }
+
+ if (* col > 1) {
+
+ if (* col + len > MAX_MAIL_COL) {
+ r = mailimf_string_write_driver(do_write, data, col, "\r\n ", 3);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+#if 0
+ * col = 1;
+#endif
+ }
+ }
+
+ switch (param->pa_type) {
+ case MAILMIME_DISPOSITION_PARM_FILENAME:
+ r = mailimf_string_write_driver(do_write, data, col, "filename=", 9);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_quoted_string_write_driver(do_write, data, col,
+ param->pa_data.pa_filename, strlen(param->pa_data.pa_filename));
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ break;
+
+ case MAILMIME_DISPOSITION_PARM_CREATION_DATE:
+ r = mailimf_string_write_driver(do_write, data, col, "creation-date=", 14);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_quoted_string_write_driver(do_write, data, col, param->pa_data.pa_creation_date,
+ strlen(param->pa_data.pa_creation_date));
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ break;
+
+ case MAILMIME_DISPOSITION_PARM_MODIFICATION_DATE:
+ r = mailimf_string_write_driver(do_write, data, col, "modification-date=", 18);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_quoted_string_write_driver(do_write, data, col,
+ param->pa_data.pa_modification_date,
+ strlen(param->pa_data.pa_modification_date));
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ break;
+
+ case MAILMIME_DISPOSITION_PARM_READ_DATE:
+ r = mailimf_string_write_driver(do_write, data, col, "read-date=", 10);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_quoted_string_write_driver(do_write, data, col, param->pa_data.pa_read_date,
+ strlen(param->pa_data.pa_read_date));
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ break;
+
+ case MAILMIME_DISPOSITION_PARM_SIZE:
+ r = mailimf_string_write_driver(do_write, data, col, "size=", 5);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_string_write_driver(do_write, data, col, sizestr, strlen(sizestr));
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ break;
+
+ case MAILMIME_DISPOSITION_PARM_PARAMETER:
+ r = mailmime_parameter_write_driver(do_write, data, col, param->pa_data.pa_parameter);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ break;
+ }
+
+ return MAILIMF_NO_ERROR;
+}
+
+static int mailmime_parameter_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
+ struct mailmime_parameter * param)
+{
+ int r;
+
+ r = mailimf_string_write_driver(do_write, data, col, param->pa_name,
+ strlen(param->pa_name));
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_string_write_driver(do_write, data, col, "=", 1);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_quoted_string_write_driver(do_write, data, col, param->pa_value,
+ strlen(param->pa_value));
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ return MAILIMF_NO_ERROR;
+}
+
+int mailmime_content_type_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
+ struct mailmime_content * content)
+{
+ clistiter * cur;
+ size_t len;
+ int r;
+
+ r = mailmime_type_write_driver(do_write, data, col, content->ct_type);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_string_write_driver(do_write, data, col, "/", 1);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_string_write_driver(do_write, data, col, content->ct_subtype,
+ strlen(content->ct_subtype));
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ if (content->ct_parameters != NULL) {
+ for(cur = clist_begin(content->ct_parameters) ;
+ cur != NULL ; cur = clist_next(cur)) {
+ struct mailmime_parameter * param;
+
+ param = cur->data;
+
+ r = mailimf_string_write_driver(do_write, data, col, "; ", 2);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ len = strlen(param->pa_name) + 1 + strlen(param->pa_value);
+
+ if (* col > 1) {
+
+ if (* col + len > MAX_MAIL_COL) {
+ r = mailimf_string_write_driver(do_write, data, col, "\r\n ", 3);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+#if 0
+ * col = 1;
+#endif
+ }
+ }
+
+ r = mailmime_parameter_write_driver(do_write, data, col, param);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ }
+ }
+
+ return MAILIMF_NO_ERROR;
+}
+
+int mailmime_content_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
+ struct mailmime_content * content)
+{
+ int r;
+
+ r = mailimf_string_write_driver(do_write, data, col, "Content-Type: ", 14);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailmime_content_type_write_driver(do_write, data, col, content);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_string_write_driver(do_write, data, col, "\r\n", 2);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ return MAILIMF_NO_ERROR;
+}
+
+static int mailmime_type_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
+ struct mailmime_type * type)
+{
+ int r;
+
+ switch (type->tp_type) {
+ case MAILMIME_TYPE_DISCRETE_TYPE:
+ r = mailmime_discrete_type_write_driver(do_write, data, col, type->tp_data.tp_discrete_type);
+ break;
+
+ case MAILMIME_TYPE_COMPOSITE_TYPE:
+ r = mailmime_composite_type_write_driver(do_write, data, col, type->tp_data.tp_composite_type);
+ break;
+
+ default:
+ r = MAILIMF_ERROR_INVAL;
+ break;
+ }
+
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ return MAILIMF_NO_ERROR;
+}
+
+static int
+mailmime_discrete_type_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
+ struct mailmime_discrete_type * discrete_type)
+{
+ int r;
+
+ switch (discrete_type->dt_type) {
+ case MAILMIME_DISCRETE_TYPE_TEXT:
+ r = mailimf_string_write_driver(do_write, data, col, "text", 4);
+ break;
+
+ case MAILMIME_DISCRETE_TYPE_IMAGE:
+ r = mailimf_string_write_driver(do_write, data, col, "image", 5);
+ break;
+
+ case MAILMIME_DISCRETE_TYPE_AUDIO:
+ r = mailimf_string_write_driver(do_write, data, col, "audio", 5);
+ break;
+
+ case MAILMIME_DISCRETE_TYPE_VIDEO:
+ r = mailimf_string_write_driver(do_write, data, col, "video", 5);
+ break;
+
+ case MAILMIME_DISCRETE_TYPE_APPLICATION:
+ r = mailimf_string_write_driver(do_write, data, col, "application", 11);
+ break;
+
+ case MAILMIME_DISCRETE_TYPE_EXTENSION:
+ r = mailimf_string_write_driver(do_write, data, col, discrete_type->dt_extension,
+ strlen(discrete_type->dt_extension));
+ break;
+
+ default:
+ r = MAILIMF_ERROR_INVAL;
+ break;
+ }
+
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ return MAILIMF_NO_ERROR;
+}
+
+static int
+mailmime_composite_type_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
+ struct mailmime_composite_type * composite_type)
+{
+ int r;
+
+ switch (composite_type->ct_type) {
+ case MAILMIME_COMPOSITE_TYPE_MESSAGE:
+ r = mailimf_string_write_driver(do_write, data, col, "message", 7);
+ break;
+
+ case MAILMIME_COMPOSITE_TYPE_MULTIPART:
+ r = mailimf_string_write_driver(do_write, data, col, "multipart", 9);
+ break;
+
+ case MAILMIME_COMPOSITE_TYPE_EXTENSION:
+ r = mailimf_string_write_driver(do_write, data, col, composite_type->ct_token,
+ strlen(composite_type->ct_token));
+ break;
+
+ default:
+ r = MAILIMF_ERROR_INVAL;
+ break;
+ }
+
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ return MAILIMF_NO_ERROR;
+}
+
+
+
+
+/* ****************************************************************** */
+/* message */
+
+/*
+static int mailmime_data_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
+ struct mailmime_data * data,
+ int is_text);
+*/
+
+static int mailmime_text_content_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col, int encoding,
+ int istext,
+ const char * text, size_t size);
+
+/*
+static int mailmime_base64_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
+ char * text, size_t size);
+
+static int mailmime_quoted_printable_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col, int istext,
+ char * text, size_t size);
+*/
+
+static int mailmime_part_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
+ struct mailmime * build_info)
+{
+ clistiter * cur;
+ int first;
+ int r;
+ char * boundary;
+ int istext;
+
+ istext = TRUE;
+ boundary = NULL;
+
+ if (build_info->mm_content_type != NULL) {
+ if (build_info->mm_type == MAILMIME_MULTIPLE) {
+ boundary = mailmime_extract_boundary(build_info->mm_content_type);
+ if (boundary == NULL)
+ return MAILIMF_ERROR_INVAL;
+ }
+
+ if (build_info->mm_content_type->ct_type->tp_type ==
+ MAILMIME_TYPE_DISCRETE_TYPE) {
+ if (build_info->mm_content_type->ct_type->tp_data.tp_discrete_type->dt_type !=
+ MAILMIME_DISCRETE_TYPE_TEXT)
+ istext = FALSE;
+ }
+ }
+
+ switch (build_info->mm_type) {
+ case MAILMIME_SINGLE:
+
+ /* 1-part body */
+
+ if (build_info->mm_data.mm_single != NULL) {
+ r = mailmime_data_write_driver(do_write, data, col, build_info->mm_data.mm_single, istext);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ }
+
+ break;
+
+ case MAILMIME_MULTIPLE:
+
+ /* multi-part */
+
+
+ /* preamble */
+
+ if (build_info->mm_data.mm_multipart.mm_preamble != NULL) {
+ r = mailmime_data_write_driver(do_write, data, col,
+ build_info->mm_data.mm_multipart.mm_preamble, TRUE);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_string_write_driver(do_write, data, col, "\r\n", 2);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+#if 0
+ * col = 0;
+#endif
+ }
+
+ /* sub-parts */
+
+ first = TRUE;
+
+ for(cur = clist_begin(build_info->mm_data.mm_multipart.mm_mp_list) ;
+ cur != NULL ; cur = clist_next(cur)) {
+ struct mailmime * subpart;
+
+ subpart = cur->data;
+
+ if (!first) {
+ r = mailimf_string_write_driver(do_write, data, col, "\r\n", 2);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+#if 0
+ * col = 0;
+#endif
+ }
+ else {
+ first = FALSE;
+ }
+
+ r = mailimf_string_write_driver(do_write, data, col, "--", 2);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_string_write_driver(do_write, data, col, boundary, strlen(boundary));
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_string_write_driver(do_write, data, col, "\r\n", 2);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+#if 0
+ * col = 0;
+#endif
+
+ r = mailmime_sub_write_driver(do_write, data, col, subpart);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ }
+
+ r = mailimf_string_write_driver(do_write, data, col, "\r\n", 2);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+#if 0
+ * col = 0;
+#endif
+
+ r = mailimf_string_write_driver(do_write, data, col, "--", 2);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_string_write_driver(do_write, data, col, boundary, strlen(boundary));
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ r = mailimf_string_write_driver(do_write, data, col, "--", 2);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+
+ /* epilogue */
+
+ r = mailimf_string_write_driver(do_write, data, col, "\r\n", 2);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+#if 0
+ * col = 0;
+#endif
+
+ if (build_info->mm_data.mm_multipart.mm_epilogue != NULL) {
+ r = mailmime_data_write_driver(do_write, data, col,
+ build_info->mm_data.mm_multipart.mm_epilogue, TRUE);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ }
+
+ break;
+
+ case MAILMIME_MESSAGE:
+
+ if (build_info->mm_data.mm_message.mm_fields != NULL) {
+ r = mailimf_fields_write_driver(do_write, data, col,
+ build_info->mm_data.mm_message.mm_fields);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ }
+
+ if (build_info->mm_mime_fields != NULL) {
+ r = mailmime_fields_write_driver(do_write, data, col, build_info->mm_mime_fields);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ }
+
+ /* encapsuled message */
+
+ if (build_info->mm_data.mm_message.mm_msg_mime != NULL) {
+ r = mailmime_sub_write_driver(do_write, data, col,
+ build_info->mm_data.mm_message.mm_msg_mime);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ }
+ break;
+
+ }
+
+ return MAILIMF_NO_ERROR;
+}
+
+
+static int mailmime_sub_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
+ struct mailmime * build_info)
+{
+ int r;
+
+#if 0
+ * col = 0;
+#endif
+ /* MIME field - Content-Type */
+
+ if (build_info->mm_content_type != NULL) {
+ r = mailmime_content_write_driver(do_write, data, col, build_info->mm_content_type);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ }
+
+ /* other MIME fields */
+
+ if (build_info->mm_type != MAILMIME_MESSAGE) {
+ if (build_info->mm_mime_fields != NULL) {
+ r = mailmime_fields_write_driver(do_write, data, col, build_info->mm_mime_fields);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ }
+ }
+
+ r = mailimf_string_write_driver(do_write, data, col, "\r\n", 2);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+#if 0
+ * col = 0;
+#endif
+
+ return mailmime_part_write_driver(do_write, data, col, build_info);
+}
+
+int mailmime_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
+ struct mailmime * build_info)
+{
+ if (build_info->mm_parent != NULL)
+ return mailmime_sub_write_driver(do_write, data, col, build_info);
+ else
+ return mailmime_part_write_driver(do_write, data, col, build_info);
+}
+
+
+int mailmime_data_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
+ struct mailmime_data * mime_data,
+ int istext)
+{
+ int fd;
+ int r;
+ char * text;
+ struct stat buf;
+ int res;
+
+ switch (mime_data->dt_type) {
+ case MAILMIME_DATA_TEXT:
+
+ if (mime_data->dt_encoded) {
+ r = mailimf_string_write_driver(do_write, data, col,
+ mime_data->dt_data.dt_text.dt_data,
+ mime_data->dt_data.dt_text.dt_length);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ }
+ else {
+ r = mailmime_text_content_write_driver(do_write, data, col, mime_data->dt_encoding, istext,
+ mime_data->dt_data.dt_text.dt_data,
+ mime_data->dt_data.dt_text.dt_length);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ }
+
+ break;
+
+ case MAILMIME_DATA_FILE:
+ fd = open(mime_data->dt_data.dt_filename, O_RDONLY);
+ if (fd < 0) {
+ res = MAILIMF_ERROR_FILE;
+ goto err;
+ }
+
+ r = fstat(fd, &buf);
+ if (r < 0) {
+ res = MAILIMF_ERROR_FILE;
+ goto close;
+ }
+
+ if (buf.st_size != 0) {
+ text = mmap(NULL, buf.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+ if (text == MAP_FAILED) {
+ res = MAILIMF_ERROR_FILE;
+ goto close;
+ }
+
+ if (mime_data->dt_encoded) {
+ r = mailimf_string_write_driver(do_write, data, col, text, buf.st_size);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto unmap;
+ }
+ }
+ else {
+ r = mailmime_text_content_write_driver(do_write, data, col, mime_data->dt_encoding, istext,
+ text, buf.st_size);
+ if (r != MAILIMF_NO_ERROR) {
+ res = r;
+ goto unmap;
+ }
+ }
+
+ munmap(text, buf.st_size);
+ }
+ close(fd);
+
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ break;
+
+ unmap:
+ munmap(text, buf.st_size);
+ close:
+ close(fd);
+ err:
+ return res;
+ }
+
+ return MAILIMF_NO_ERROR;
+}
+
+static int mailmime_text_content_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col, int encoding,
+ int istext,
+ const char * text, size_t size)
+{
+ switch (encoding) {
+ case MAILMIME_MECHANISM_QUOTED_PRINTABLE:
+ return mailmime_quoted_printable_write_driver(do_write, data, col, istext, text, size);
+ break;
+
+ case MAILMIME_MECHANISM_BASE64:
+ return mailmime_base64_write_driver(do_write, data, col, text, size);
+ break;
+
+ case MAILMIME_MECHANISM_7BIT:
+ case MAILMIME_MECHANISM_8BIT:
+ case MAILMIME_MECHANISM_BINARY:
+ default:
+ return mailimf_string_write_driver(do_write, data, col, text, size);
+ }
+}
+
+
+static const char base64_encoding[] =
+"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+#define BASE64_MAX_COL 76
+
+int mailmime_base64_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
+ const char * text, size_t size)
+{
+ int a;
+ int b;
+ int c;
+ size_t remains;
+ const char * p;
+ size_t count;
+ char ogroup[4];
+ int r;
+
+ remains = size;
+ p = text;
+
+ while (remains > 0) {
+ switch (remains) {
+ case 1:
+ a = (unsigned char) p[0];
+ b = 0;
+ c = 0;
+ count = 1;
+ break;
+ case 2:
+ a = (unsigned char) p[0];
+ b = (unsigned char) p[1];
+ c = 0;
+ count = 2;
+ break;
+ default:
+ a = (unsigned char) p[0];
+ b = (unsigned char) p[1];
+ c = (unsigned char) p[2];
+ count = 3;
+ break;
+ }
+
+ ogroup[0]= base64_encoding[a >> 2];
+ ogroup[1]= base64_encoding[((a & 3) << 4) | (b >> 4)];
+ ogroup[2]= base64_encoding[((b & 0xF) << 2) | (c >> 6)];
+ ogroup[3]= base64_encoding[c & 0x3F];
+
+ switch (count) {
+ case 1:
+ ogroup[2]= '=';
+ ogroup[3]= '=';
+ break;
+ case 2:
+ ogroup[3]= '=';
+ break;
+ }
+
+ if (* col + 4 > BASE64_MAX_COL) {
+ r = mailimf_string_write_driver(do_write, data, col, "\r\n", 2);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+#if 0
+ * col = 0;
+#endif
+ }
+
+ r = mailimf_string_write_driver(do_write, data, col, ogroup, 4);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ remains -= count;
+ p += count;
+ }
+
+ r = mailimf_string_write_driver(do_write, data, col, "\r\n", 2);
+
+ return MAILIMF_NO_ERROR;
+}
+
+#if 0
+#define MAX_WRITE_SIZE 512
+#endif
+
+enum {
+ STATE_INIT,
+ STATE_CR,
+ STATE_SPACE,
+ STATE_SPACE_CR,
+};
+
+#if 0
+static inline int write_try_buf(int (* do_write)(void *, const char *, size_t), void * data, int * col,
+ char ** pstart, size_t * plen)
+{
+ int r;
+
+ if (* plen >= MAX_WRITE_SIZE) {
+ r = mailimf_string_write_driver(do_write, data, col, * pstart, * plen);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ * plen = 0;
+ }
+
+ return MAILIMF_NO_ERROR;
+}
+#endif
+
+static inline int write_remaining(int (* do_write)(void *, const char *, size_t), void * data, int * col,
+ const char ** pstart, size_t * plen)
+{
+ int r;
+
+ if (* plen > 0) {
+ r = mailimf_string_write_driver(do_write, data, col, * pstart, * plen);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ * plen = 0;
+ }
+
+ return MAILIMF_NO_ERROR;
+}
+
+
+
+#define QP_MAX_COL 72
+
+int mailmime_quoted_printable_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col, int istext,
+ const char * text, size_t size)
+{
+ size_t i;
+ const char * start;
+ size_t len;
+ char hexstr[6];
+ int r;
+ int state;
+
+ start = text;
+ len = 0;
+ state = STATE_INIT;
+
+ i = 0;
+ while (i < size) {
+ unsigned char ch;
+
+ if (* col + len > QP_MAX_COL) {
+ r = write_remaining(do_write, data, col, &start, &len);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ start = text + i;
+
+ r = mailimf_string_write_driver(do_write, data, col, "=\r\n", 3);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ }
+
+ ch = text[i];
+
+ switch (state) {
+
+ case STATE_INIT:
+ switch (ch) {
+ case ' ':
+ case '\t':
+ state = STATE_SPACE;
+ break;
+
+ case '\r':
+ state = STATE_CR;
+ break;
+
+ case '!':
+ case '"':
+ case '#':
+ case '$':
+ case '@':
+ case '[':
+ case '\\':
+ case ']':
+ case '^':
+ case '`':
+ case '{':
+ case '|':
+ case '}':
+ case '~':
+ case '=':
+ case '?':
+ case '_':
+ case 'F': /* there is no more 'From' at the beginning of a line */
+ r = write_remaining(do_write, data, col, &start, &len);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ start = text + i + 1;
+
+ snprintf(hexstr, 6, "=%02X", ch);
+
+ r = mailimf_string_write_driver(do_write, data, col, hexstr, 3);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ break;
+
+ default:
+ if (istext && (ch == '\n')) {
+ r = write_remaining(do_write, data, col, &start, &len);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ start = text + i + 1;
+
+ r = mailimf_string_write_driver(do_write, data, col, "\r\n", 2);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ break;
+ }
+ else {
+ if (((ch >= 33) && (ch <= 60)) || ((ch >= 62) && (ch <= 126))) {
+ len ++;
+ }
+ else {
+ r = write_remaining(do_write, data, col, &start, &len);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ start = text + i + 1;
+
+ snprintf(hexstr, 6, "=%02X", ch);
+
+ r = mailimf_string_write_driver(do_write, data, col, hexstr, 3);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ }
+ }
+
+ break;
+ }
+
+ i ++;
+ break;
+
+ case STATE_CR:
+ switch (ch) {
+ case '\n':
+ r = write_remaining(do_write, data, col, &start, &len);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ start = text + i + 1;
+ r = mailimf_string_write_driver(do_write, data, col, "\r\n", 2);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ i ++;
+ state = STATE_INIT;
+ break;
+
+ default:
+ r = write_remaining(do_write, data, col, &start, &len);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ start = text + i;
+ snprintf(hexstr, 6, "=%02X", '\r');
+ r = mailimf_string_write_driver(do_write, data, col, hexstr, 3);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ state = STATE_INIT;
+ break;
+ }
+ break;
+
+ case STATE_SPACE:
+ switch (ch) {
+ case '\r':
+ state = STATE_SPACE_CR;
+ i ++;
+ break;
+
+ case '\n':
+ r = write_remaining(do_write, data, col, &start, &len);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ start = text + i + 1;
+ snprintf(hexstr, 6, "=%02X\r\n", text[i - 1]);
+ r = mailimf_string_write_driver(do_write, data, col, hexstr, strlen(hexstr));
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ state = STATE_INIT;
+ i ++;
+ break;
+
+ case ' ':
+ case '\t':
+ len ++;
+ i ++;
+ break;
+
+ default:
+#if 0
+ len += 2;
+ state = STATE_INIT;
+ i ++;
+#endif
+ len ++;
+ state = STATE_INIT;
+ break;
+ }
+
+ break;
+
+ case STATE_SPACE_CR:
+ switch (ch) {
+ case '\n':
+ r = write_remaining(do_write, data, col, &start, &len);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ start = text + i + 1;
+ snprintf(hexstr, 6, "=%02X\r\n", text[i - 2]);
+ r = mailimf_string_write_driver(do_write, data, col, hexstr, strlen(hexstr));
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ state = STATE_INIT;
+ i ++;
+ break;
+
+ default:
+ r = write_remaining(do_write, data, col, &start, &len);
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ start = text + i + 1;
+ snprintf(hexstr, 6, "%c=%02X", text[i - 2], '\r');
+ r = mailimf_string_write_driver(do_write, data, col, hexstr, strlen(hexstr));
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+ state = STATE_INIT;
+ break;
+ }
+
+ break;
+ }
+ }
+
+ return MAILIMF_NO_ERROR;
+}
diff --git a/libetpan/src/low-level/mime/mailmime_write_generic.h b/libetpan/src/low-level/mime/mailmime_write_generic.h
new file mode 100644
index 0000000..0d9a725
--- a/dev/null
+++ b/libetpan/src/low-level/mime/mailmime_write_generic.h
@@ -0,0 +1,73 @@
+/*
+ * 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$
+ */
+
+#ifndef MAILMIME_WRITE_GENERIC_H
+
+#define MAILMIME_WRITE_GENERIC_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <libetpan/mailmime_types.h>
+#include <stdio.h>
+
+int mailmime_fields_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
+ struct mailmime_fields * fields);
+
+int mailmime_content_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
+ struct mailmime_content * content);
+
+int mailmime_content_type_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
+ struct mailmime_content * content);
+
+int mailmime_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
+ struct mailmime * build_info);
+
+int mailmime_quoted_printable_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col, int istext,
+ const char * text, size_t size);
+
+int mailmime_base64_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
+ const char * text, size_t size);
+
+int mailmime_data_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
+ struct mailmime_data * mime_data,
+ int istext);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libetpan/src/low-level/mime/mailmime_write_mem.c b/libetpan/src/low-level/mime/mailmime_write_mem.c
new file mode 100644
index 0000000..4b41d34
--- a/dev/null
+++ b/libetpan/src/low-level/mime/mailmime_write_mem.c
@@ -0,0 +1,106 @@
+/*
+ * 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 "mailmime_write_mem.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+
+#include "mailmime_content.h"
+#include "mailmime_types_helper.h"
+#include "mailmime_write_generic.h"
+
+static int do_write(void * data, const char * str, size_t length)
+{
+ MMAPString * f;
+
+ f = data;
+
+ if (mmap_string_append_len(f, str, length) == NULL)
+ return 0;
+ else
+ return length;
+}
+
+int mailmime_fields_write_mem(MMAPString * f, int * col,
+ struct mailmime_fields * fields)
+{
+ return mailmime_fields_write_driver(do_write, f, col, fields);
+}
+
+int mailmime_content_write_mem(MMAPString * f, int * col,
+ struct mailmime_content * content)
+{
+ return mailmime_content_write_driver(do_write, f, col, content);
+}
+
+int mailmime_content_type_write_mem(MMAPString * f, int * col,
+ struct mailmime_content * content)
+{
+ return mailmime_content_type_write_driver(do_write, f, col, content);
+}
+
+int mailmime_write_mem(MMAPString * f, int * col,
+ struct mailmime * build_info)
+{
+ return mailmime_write_driver(do_write, f, col, build_info);
+}
+
+int mailmime_quoted_printable_write_mem(MMAPString * f, int * col, int istext,
+ const char * text, size_t size)
+{
+ return mailmime_quoted_printable_write_driver(do_write, f, col,
+ istext, text, size);
+}
+
+int mailmime_base64_write_mem(MMAPString * f, int * col,
+ const char * text, size_t size)
+{
+ return mailmime_base64_write_driver(do_write, f, col, text, size);
+}
+
+int mailmime_data_write_mem(MMAPString * f, int * col,
+ struct mailmime_data * data,
+ int istext)
+{
+ return mailmime_data_write_driver(do_write, f, col, data, istext);
+}
+
diff --git a/libetpan/src/low-level/mime/mailmime_write_mem.h b/libetpan/src/low-level/mime/mailmime_write_mem.h
new file mode 100644
index 0000000..f86d129
--- a/dev/null
+++ b/libetpan/src/low-level/mime/mailmime_write_mem.h
@@ -0,0 +1,73 @@
+/*
+ * 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$
+ */
+
+#ifndef MAILMIME_WRITE_MEM_H
+
+#define MAILMIME_WRITE_MEM_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <libetpan/mailmime_types.h>
+#include <libetpan/mmapstring.h>
+
+int mailmime_fields_write_mem(MMAPString * f, int * col,
+ struct mailmime_fields * fields);
+
+int mailmime_content_write_mem(MMAPString * f, int * col,
+ struct mailmime_content * content);
+
+int mailmime_content_type_write_mem(MMAPString * f, int * col,
+ struct mailmime_content * content);
+
+int mailmime_write_mem(MMAPString * f, int * col,
+ struct mailmime * build_info);
+
+int mailmime_quoted_printable_write_mem(MMAPString * f, int * col, int istext,
+ const char * text, size_t size);
+
+int mailmime_base64_write_mem(MMAPString * f, int * col,
+ const char * text, size_t size);
+
+int mailmime_data_write_mem(MMAPString * f, int * col,
+ struct mailmime_data * data,
+ int istext);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libetpan/src/low-level/nntp/newsnntp.c b/libetpan/src/low-level/nntp/newsnntp.c
new file mode 100644
index 0000000..bf2312c
--- a/dev/null
+++ b/libetpan/src/low-level/nntp/newsnntp.c
@@ -0,0 +1,2486 @@
+/*
+ * 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 "newsnntp.h"
+
+
+#include <unistd.h>
+#include <stdio.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <time.h>
+
+#include "connect.h"
+#include "mail.h"
+#include "clist.h"
+
+/*
+ NNTP Protocol
+
+ RFC 977
+ RFC 2980
+
+ TODO :
+
+ XPAT header range|<message-id> pat [pat...]
+
+
+ */
+
+
+
+
+#define NNTP_STRING_SIZE 513
+
+
+
+static char * read_line(newsnntp * f);
+static char * read_multiline(newsnntp * f, size_t size,
+ MMAPString * multiline_buffer);
+static int parse_response(newsnntp * f, char * response);
+
+static int send_command(newsnntp * f, char * command);
+
+newsnntp * newsnntp_new(size_t progr_rate, progress_function * progr_fun)
+{
+ newsnntp * f;
+
+ f = malloc(sizeof(* f));
+ if (f == NULL)
+ goto err;
+
+ f->nntp_stream = NULL;
+ f->nntp_readonly = FALSE;
+
+ f->nntp_progr_rate = progr_rate;
+ f->nntp_progr_fun = progr_fun;
+
+ f->nntp_stream_buffer = mmap_string_new("");
+ if (f->nntp_stream_buffer == NULL)
+ goto free_f;
+
+ f->nntp_response_buffer = mmap_string_new("");
+ if (f->nntp_response_buffer == NULL)
+ goto free_stream_buffer;
+
+ return f;
+
+ free_stream_buffer:
+ mmap_string_free(f->nntp_stream_buffer);
+ free_f:
+ free(f);
+ err:
+ return NULL;
+}
+
+void newsnntp_free(newsnntp * f)
+{
+ if (f->nntp_stream)
+ newsnntp_quit(f);
+
+ mmap_string_free(f->nntp_response_buffer);
+ mmap_string_free(f->nntp_stream_buffer);
+
+ free(f);
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+int newsnntp_quit(newsnntp * f)
+{
+ char command[NNTP_STRING_SIZE];
+ char * response;
+ int r;
+ int res;
+
+ if (f->nntp_stream == NULL)
+ return NEWSNNTP_ERROR_BAD_STATE;
+
+ snprintf(command, NNTP_STRING_SIZE, "QUIT\r\n");
+ r = send_command(f, command);
+ if (r == -1) {
+ res = NEWSNNTP_ERROR_STREAM;
+ goto close;
+ }
+
+ response = read_line(f);
+ if (response == NULL) {
+ res = NEWSNNTP_ERROR_STREAM;
+ goto close;
+ }
+
+ parse_response(f, response);
+
+ res = NEWSNNTP_NO_ERROR;
+
+ close:
+
+ mailstream_close(f->nntp_stream);
+
+ f->nntp_stream = NULL;
+
+ return res;
+}
+
+int newsnntp_connect(newsnntp * f, mailstream * s)
+{
+ char * response;
+ int r;
+
+ if (f->nntp_stream != NULL)
+ return NEWSNNTP_ERROR_BAD_STATE;
+
+ f->nntp_stream = s;
+
+ response = read_line(f);
+ if (response == NULL)
+ return NEWSNNTP_ERROR_STREAM;
+
+ r = parse_response(f, response);
+
+ switch (r) {
+ case 200:
+ f->nntp_readonly = FALSE;
+ return NEWSNNTP_NO_ERROR;
+
+ case 201:
+ f->nntp_readonly = TRUE;
+ return NEWSNNTP_NO_ERROR;
+
+ default:
+ f->nntp_stream = NULL;
+ return NEWSNNTP_ERROR_UNEXPECTED_RESPONSE;
+ }
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+/*
+static struct newsnntp_xover_resp_item * get_xover_info(newsnntp * f,
+ guint32 article);
+*/
+
+static void newsnntp_multiline_response_free(char * str)
+{
+ mmap_string_unref(str);
+}
+
+void newsnntp_head_free(char * str)
+{
+ newsnntp_multiline_response_free(str);
+}
+
+void newsnntp_article_free(char * str)
+{
+ newsnntp_multiline_response_free(str);
+}
+
+void newsnntp_body_free(char * str)
+{
+ newsnntp_multiline_response_free(str);
+}
+
+/* ******************** HEADER ******************************** */
+
+/*
+ message content in (* result) is still there until the
+ next retrieve or top operation on the mailpop3 structure
+*/
+
+static int newsnntp_get_content(newsnntp * f, char ** result,
+ size_t * result_len)
+{
+ int r;
+ char * response;
+ MMAPString * buffer;
+ char * result_multiline;
+
+ response = read_line(f);
+ if (response == NULL)
+ return NEWSNNTP_ERROR_STREAM;
+
+ r = parse_response(f, response);
+
+ switch (r) {
+ case 480:
+ return NEWSNNTP_WARNING_REQUEST_AUTHORIZATION_USERNAME;
+
+ case 381:
+ return NEWSNNTP_WARNING_REQUEST_AUTHORIZATION_PASSWORD;
+
+ case 220:
+ case 221:
+ case 222:
+ case 223:
+ buffer = mmap_string_new("");
+ if (buffer == NULL)
+ return NEWSNNTP_ERROR_MEMORY;
+
+ result_multiline = read_multiline(f, 0, buffer);
+ if (result_multiline == NULL) {
+ mmap_string_free(buffer);
+ return NEWSNNTP_ERROR_MEMORY;
+ }
+ else {
+ r = mmap_string_ref(buffer);
+ if (r < 0) {
+ mmap_string_free(buffer);
+ return NEWSNNTP_ERROR_MEMORY;
+ }
+
+ * result = result_multiline;
+ * result_len = buffer->len;
+ return NEWSNNTP_NO_ERROR;
+ }
+
+ case 412:
+ return NEWSNNTP_ERROR_NO_NEWSGROUP_SELECTED;
+
+ case 420:
+ return NEWSNNTP_ERROR_NO_ARTICLE_SELECTED;
+
+ case 423:
+ return NEWSNNTP_ERROR_INVALID_ARTICLE_NUMBER;
+
+ case 430:
+ return NEWSNNTP_ERROR_ARTICLE_NOT_FOUND;
+
+ default:
+ return NEWSNNTP_ERROR_UNEXPECTED_RESPONSE;
+ }
+}
+
+int newsnntp_head(newsnntp * f, uint32_t index, char ** result,
+ size_t * result_len)
+{
+ char command[NNTP_STRING_SIZE];
+ int r;
+
+ snprintf(command, NNTP_STRING_SIZE, "HEAD %i\r\n", index);
+ r = send_command(f, command);
+ if (r == -1)
+ return NEWSNNTP_ERROR_STREAM;
+
+ return newsnntp_get_content(f, result, result_len);
+}
+
+/* ******************** ARTICLE ******************************** */
+
+int newsnntp_article(newsnntp * f, uint32_t index, char ** result,
+ size_t * result_len)
+{
+ char command[NNTP_STRING_SIZE];
+ int r;
+
+ snprintf(command, NNTP_STRING_SIZE, "ARTICLE %i\r\n", index);
+ r = send_command(f, command);
+ if (r == -1)
+ return NEWSNNTP_ERROR_STREAM;
+
+ return newsnntp_get_content(f, result, result_len);
+}
+
+/* ******************** BODY ******************************** */
+
+int newsnntp_body(newsnntp * f, uint32_t index, char ** result,
+ size_t * result_len)
+{
+ char command[NNTP_STRING_SIZE];
+ int r;
+
+ snprintf(command, NNTP_STRING_SIZE, "BODY %i\r\n", index);
+ r = send_command(f, command);
+ if (r == -1)
+ return NEWSNNTP_ERROR_STREAM;
+
+ return newsnntp_get_content(f, result, result_len);
+}
+
+/* ******************** GROUP ******************************** */
+
+static struct newsnntp_group_info *
+group_info_init(char * name, uint32_t first, uint32_t last, uint32_t count,
+ char type)
+{
+ struct newsnntp_group_info * n;
+
+ n = malloc(sizeof(* n));
+
+ if (n == NULL)
+ return NULL;
+
+ n->grp_name = strdup(name);
+ if (n->grp_name == NULL) {
+ free(n);
+ return NULL;
+ }
+
+ n->grp_first = first;
+ n->grp_last = last;
+ n->grp_count = count;
+ n->grp_type = type;
+
+ return n;
+}
+
+static void group_info_free(struct newsnntp_group_info * n)
+{
+ if (n->grp_name)
+ free(n->grp_name);
+ free(n);
+}
+
+static void group_info_list_free(clist * l)
+{
+ clist_foreach(l, (clist_func) group_info_free, NULL);
+ clist_free(l);
+}
+
+static int parse_group_info(char * response,
+ struct newsnntp_group_info ** info);
+
+int newsnntp_group(newsnntp * f, const char * groupname,
+ struct newsnntp_group_info ** info)
+{
+ char command[NNTP_STRING_SIZE];
+ int r;
+ char * response;
+
+ snprintf(command, NNTP_STRING_SIZE, "GROUP %s\r\n", groupname);
+ r = send_command(f, command);
+ if (r == -1)
+ return NEWSNNTP_ERROR_STREAM;
+
+ response = read_line(f);
+ if (response == NULL)
+ return NEWSNNTP_ERROR_STREAM;
+
+ r = parse_response(f, response);
+
+ switch (r) {
+ case 480:
+ return NEWSNNTP_WARNING_REQUEST_AUTHORIZATION_USERNAME;
+
+ case 381:
+ return NEWSNNTP_WARNING_REQUEST_AUTHORIZATION_PASSWORD;
+
+ case 211:
+ if (!parse_group_info(f->nntp_response, info))
+ return NEWSNNTP_ERROR_INVALID_RESPONSE;
+ return NEWSNNTP_NO_ERROR;
+
+ case 411:
+ return NEWSNNTP_ERROR_NO_SUCH_NEWS_GROUP;
+
+ default:
+ return NEWSNNTP_ERROR_UNEXPECTED_RESPONSE;
+ }
+}
+
+void newsnntp_group_free(struct newsnntp_group_info * info)
+{
+ group_info_free(info);
+}
+
+/* ******************** LIST ******************************** */
+
+static clist * read_groups_list(newsnntp * f);
+
+int newsnntp_list(newsnntp * f, clist ** result)
+{
+ char command[NNTP_STRING_SIZE];
+ int r;
+ char * response;
+
+ snprintf(command, NNTP_STRING_SIZE, "LIST\r\n");
+ r = send_command(f, command);
+ if (r == -1)
+ return NEWSNNTP_ERROR_STREAM;
+
+ response = read_line(f);
+ if (response == NULL)
+ return NEWSNNTP_ERROR_STREAM;
+
+ r = parse_response(f, response);
+
+ switch (r) {
+ case 480:
+ return NEWSNNTP_WARNING_REQUEST_AUTHORIZATION_USERNAME;
+
+ case 381:
+ return NEWSNNTP_WARNING_REQUEST_AUTHORIZATION_PASSWORD;
+
+ case 215:
+ * result = read_groups_list(f);
+ return NEWSNNTP_NO_ERROR;
+
+ default:
+ return NEWSNNTP_ERROR_UNEXPECTED_RESPONSE;
+ }
+}
+
+void newsnntp_list_free(clist * l)
+{
+ group_info_list_free(l);
+}
+
+/* ******************** POST ******************************** */
+
+static void send_data(newsnntp * f, const char * message, uint32_t size)
+{
+ mailstream_send_data(f->nntp_stream, message, size,
+ f->nntp_progr_rate, f->nntp_progr_fun);
+}
+
+
+int newsnntp_post(newsnntp * f, const char * message, size_t size)
+{
+ char command[NNTP_STRING_SIZE];
+ int r;
+ char * response;
+
+ snprintf(command, NNTP_STRING_SIZE, "POST\r\n");
+ r = send_command(f, command);
+ if (r == -1)
+ return NEWSNNTP_ERROR_STREAM;
+
+ response = read_line(f);
+ if (response == NULL)
+ return NEWSNNTP_ERROR_STREAM;
+
+ r = parse_response(f, response);
+
+ switch (r) {
+ case 480:
+ return NEWSNNTP_WARNING_REQUEST_AUTHORIZATION_USERNAME;
+
+ case 381:
+ return NEWSNNTP_WARNING_REQUEST_AUTHORIZATION_PASSWORD;
+
+ case 340:
+ break;
+
+ case 440:
+ return NEWSNNTP_ERROR_POSTING_NOT_ALLOWED;
+
+ default:
+ return NEWSNNTP_ERROR_UNEXPECTED_RESPONSE;
+ }
+
+ send_data(f, message, size);
+
+ response = read_line(f);
+ if (response == NULL)
+ return NEWSNNTP_ERROR_STREAM;
+
+ r = parse_response(f, response);
+
+ switch (r) {
+ case 480:
+ return NEWSNNTP_WARNING_REQUEST_AUTHORIZATION_USERNAME;
+
+ case 381:
+ return NEWSNNTP_WARNING_REQUEST_AUTHORIZATION_PASSWORD;
+
+ case 240:
+ return NEWSNNTP_NO_ERROR;
+ return 1;
+
+ case 441:
+ return NEWSNNTP_ERROR_POSTING_FAILED;
+
+ default:
+ return NEWSNNTP_ERROR_UNEXPECTED_RESPONSE;
+ }
+}
+
+
+/* ******************** AUTHINFO ******************************** */
+
+int newsnntp_authinfo_username(newsnntp * f, const char * username)
+{
+ char command[NNTP_STRING_SIZE];
+ int r;
+ char * response;
+
+ snprintf(command, NNTP_STRING_SIZE, "AUTHINFO USER %s\r\n", username);
+ r = send_command(f, command);
+ if (r == -1)
+ return NEWSNNTP_ERROR_STREAM;
+
+ response = read_line(f);
+ if (response == NULL)
+ return NEWSNNTP_ERROR_STREAM;
+
+ r = parse_response(f, response);
+
+ switch (r) {
+ case 480:
+ return NEWSNNTP_WARNING_REQUEST_AUTHORIZATION_USERNAME;
+
+ case 482:
+ return NEWSNNTP_ERROR_AUTHENTICATION_REJECTED;
+
+ case 381:
+ return NEWSNNTP_WARNING_REQUEST_AUTHORIZATION_PASSWORD;
+
+ case 281:
+ return NEWSNNTP_NO_ERROR;
+
+ default:
+ return NEWSNNTP_ERROR_UNEXPECTED_RESPONSE;
+ }
+}
+
+int newsnntp_authinfo_password(newsnntp * f, const char * password)
+{
+ char command[NNTP_STRING_SIZE];
+ int r;
+ char * response;
+
+ snprintf(command, NNTP_STRING_SIZE, "AUTHINFO PASS %s\r\n", password);
+ r = send_command(f, command);
+ if (r == -1)
+ return NEWSNNTP_ERROR_STREAM;
+
+ response = read_line(f);
+ if (response == NULL)
+ return NEWSNNTP_ERROR_STREAM;
+
+ r = parse_response(f, response);
+
+ switch (r) {
+ case 480:
+ return NEWSNNTP_WARNING_REQUEST_AUTHORIZATION_USERNAME;
+
+ case 482:
+ return NEWSNNTP_ERROR_AUTHENTICATION_REJECTED;
+
+ case 381:
+ return NEWSNNTP_WARNING_REQUEST_AUTHORIZATION_PASSWORD;
+
+ case 281:
+ return NEWSNNTP_NO_ERROR;
+
+ default:
+ return NEWSNNTP_ERROR_UNEXPECTED_RESPONSE;
+ }
+}
+
+/* ******************** LIST OVERVIEW.FMT ******************************** */
+
+static clist * read_headers_list(newsnntp * f);
+
+static void headers_list_free(clist * l)
+{
+ clist_foreach(l, (clist_func) free, NULL);
+ clist_free(l);
+}
+
+int newsnntp_list_overview_fmt(newsnntp * f, clist ** result)
+{
+ char command[NNTP_STRING_SIZE];
+ int r;
+ char * response;
+
+ snprintf(command, NNTP_STRING_SIZE, "LIST OVERVIEW.FMT\r\n");
+ r = send_command(f, command);
+ if (r == -1)
+ return NEWSNNTP_ERROR_STREAM;
+
+ response = read_line(f);
+ if (response == NULL)
+ return NEWSNNTP_ERROR_STREAM;
+
+ r = parse_response(f, response);
+
+ switch (r) {
+ case 480:
+ return NEWSNNTP_WARNING_REQUEST_AUTHORIZATION_USERNAME;
+
+ case 381:
+ return NEWSNNTP_WARNING_REQUEST_AUTHORIZATION_PASSWORD;
+
+ case 215:
+ * result = read_headers_list(f);
+ return NEWSNNTP_NO_ERROR;
+
+ case 503:
+ return NEWSNNTP_ERROR_PROGRAM_ERROR;
+
+ default:
+ return NEWSNNTP_ERROR_UNEXPECTED_RESPONSE;
+ }
+}
+
+void newsnntp_list_overview_fmt_free(clist * l)
+{
+ headers_list_free(l);
+}
+
+
+
+
+
+
+/* ******************** LIST ACTIVE ******************************** */
+
+int newsnntp_list_active(newsnntp * f, const char * wildcard, clist ** result)
+{
+ char command[NNTP_STRING_SIZE];
+ int r;
+ char * response;
+
+ if (wildcard != NULL)
+ snprintf(command, NNTP_STRING_SIZE, "LIST ACTIVE %s\r\n", wildcard);
+ else
+ snprintf(command, NNTP_STRING_SIZE, "LIST ACTIVE\r\n");
+ r = send_command(f, command);
+ if (r == -1)
+ return NEWSNNTP_ERROR_STREAM;
+
+ response = read_line(f);
+ if (response == NULL)
+ return NEWSNNTP_ERROR_STREAM;
+
+ r = parse_response(f, response);
+
+ switch (r) {
+ case 480:
+ return NEWSNNTP_WARNING_REQUEST_AUTHORIZATION_USERNAME;
+
+ case 381:
+ return NEWSNNTP_WARNING_REQUEST_AUTHORIZATION_PASSWORD;
+
+ case 215:
+ * result = read_groups_list(f);
+ return NEWSNNTP_NO_ERROR;
+
+ default:
+ return NEWSNNTP_ERROR_UNEXPECTED_RESPONSE;
+ }
+}
+
+void newsnntp_list_active_free(clist * l)
+{
+ group_info_list_free(l);
+}
+
+
+
+
+
+
+/* ******************** LIST ACTIVE.TIMES ******************************** */
+
+static struct newsnntp_group_time *
+group_time_new(char * group_name, time_t date, char * email)
+{
+ struct newsnntp_group_time * n;
+
+ n = malloc(sizeof(* n));
+
+ if (n == NULL)
+ return NULL;
+
+ n->grp_name = strdup(group_name);
+ if (n->grp_name == NULL) {
+ free(n);
+ return NULL;
+ }
+
+ n->grp_email = strdup(email);
+ if (n->grp_email == NULL) {
+ free(n->grp_name);
+ free(n);
+ return NULL;
+ }
+
+ n->grp_date = date;
+
+ return n;
+}
+
+static void group_time_free(struct newsnntp_group_time * n)
+{
+ if (n->grp_name)
+ free(n->grp_name);
+ if (n->grp_email)
+ free(n->grp_email);
+ free(n);
+}
+
+static void group_time_list_free(clist * l)
+{
+ clist_foreach(l, (clist_func) group_time_free, NULL);
+ clist_free(l);
+}
+
+
+
+
+
+
+
+static clist * read_group_time_list(newsnntp * f);
+
+
+int newsnntp_list_active_times(newsnntp * f, clist ** result)
+{
+ char command[NNTP_STRING_SIZE];
+ int r;
+ char * response;
+
+ snprintf(command, NNTP_STRING_SIZE, "LIST ACTIVE.TIMES\r\n");
+ r = send_command(f, command);
+ if (r == -1)
+ return NEWSNNTP_ERROR_STREAM;
+
+ response = read_line(f);
+ if (response == NULL)
+ return NEWSNNTP_ERROR_STREAM;
+
+ r = parse_response(f, response);
+
+ switch (r) {
+ case 480:
+ return NEWSNNTP_WARNING_REQUEST_AUTHORIZATION_USERNAME;
+
+ case 381:
+ return NEWSNNTP_WARNING_REQUEST_AUTHORIZATION_PASSWORD;
+
+ case 215:
+ * result = read_group_time_list(f);
+ return NEWSNNTP_NO_ERROR;
+
+ case 503:
+ return NEWSNNTP_ERROR_PROGRAM_ERROR;
+
+ default:
+ return NEWSNNTP_ERROR_UNEXPECTED_RESPONSE;
+ }
+}
+
+void newsnntp_list_active_times_free(clist * l)
+{
+ group_time_list_free(l);
+}
+
+
+
+
+
+
+
+
+/* ********************** LIST DISTRIBUTION ***************************** */
+
+static struct newsnntp_distrib_value_meaning *
+distrib_value_meaning_new(char * value, char * meaning)
+{
+ struct newsnntp_distrib_value_meaning * n;
+
+ n = malloc(sizeof(* n));
+
+ if (n == NULL)
+ return NULL;
+
+ n->dst_value = strdup(value);
+ if (n->dst_value == NULL) {
+ free(n);
+ return NULL;
+ }
+
+ n->dst_meaning = strdup(meaning);
+ if (n->dst_meaning == NULL) {
+ free(n->dst_value);
+ free(n);
+ return NULL;
+ }
+
+ return n;
+}
+
+
+static void
+distrib_value_meaning_free(struct newsnntp_distrib_value_meaning * n)
+{
+ if (n->dst_value)
+ free(n->dst_value);
+ if (n->dst_meaning)
+ free(n->dst_meaning);
+ free(n);
+}
+
+static void distrib_value_meaning_list_free(clist * l)
+{
+ clist_foreach(l, (clist_func) distrib_value_meaning_free, NULL);
+ clist_free(l);
+}
+
+static clist * read_distrib_value_meaning_list(newsnntp * f);
+
+
+int newsnntp_list_distribution(newsnntp * f, clist ** result)
+{
+ char command[NNTP_STRING_SIZE];
+ int r;
+ char * response;
+
+ snprintf(command, NNTP_STRING_SIZE, "LIST DISTRIBUTION\r\n");
+ r = send_command(f, command);
+ if (r == -1)
+ return NEWSNNTP_ERROR_STREAM;
+
+ response = read_line(f);
+ if (response == NULL)
+ return NEWSNNTP_ERROR_STREAM;
+
+ r = parse_response(f, response);
+
+ switch (r) {
+ case 480:
+ return NEWSNNTP_WARNING_REQUEST_AUTHORIZATION_USERNAME;
+
+ case 381:
+ return NEWSNNTP_WARNING_REQUEST_AUTHORIZATION_PASSWORD;
+
+ case 215:
+ * result = read_distrib_value_meaning_list(f);
+ return NEWSNNTP_NO_ERROR;
+
+ case 503:
+ return NEWSNNTP_ERROR_PROGRAM_ERROR;
+
+ default:
+ return NEWSNNTP_ERROR_UNEXPECTED_RESPONSE;
+ }
+}
+
+
+void newsnntp_list_distribution_free(clist * l)
+{
+ distrib_value_meaning_list_free(l);
+}
+
+
+
+
+
+
+
+
+
+
+
+/* ********************** LIST DISTRIB.PATS ***************************** */
+
+static struct newsnntp_distrib_default_value *
+distrib_default_value_new(uint32_t weight, char * group_pattern, char * value)
+{
+ struct newsnntp_distrib_default_value * n;
+
+ n = malloc(sizeof(* n));
+ if (n == NULL)
+ return NULL;
+
+ n->dst_group_pattern = strdup(group_pattern);
+ if (n->dst_group_pattern == NULL) {
+ free(n);
+ return NULL;
+ }
+
+ n->dst_value = strdup(value);
+ if (n->dst_value == NULL) {
+ free(n->dst_group_pattern);
+ free(n);
+ return NULL;
+ }
+
+ n->dst_weight = weight;
+
+ return n;
+}
+
+static void
+distrib_default_value_free(struct newsnntp_distrib_default_value * n)
+{
+ if (n->dst_group_pattern)
+ free(n->dst_group_pattern);
+ if (n->dst_value)
+ free(n->dst_value);
+ free(n);
+}
+
+static void distrib_default_value_list_free(clist * l)
+{
+ clist_foreach(l, (clist_func) distrib_default_value_free, NULL);
+ clist_free(l);
+}
+
+static clist * read_distrib_default_value_list(newsnntp * f);
+
+int newsnntp_list_distrib_pats(newsnntp * f, clist ** result)
+{
+ char command[NNTP_STRING_SIZE];
+ int r;
+ char * response;
+
+ snprintf(command, NNTP_STRING_SIZE, "LIST DISTRIB.PATS\r\n");
+ r = send_command(f, command);
+ if (r == -1)
+ return NEWSNNTP_ERROR_STREAM;
+
+ response = read_line(f);
+ if (response == NULL)
+ return NEWSNNTP_ERROR_STREAM;
+
+ r = parse_response(f, response);
+
+ switch (r) {
+ case 480:
+ return NEWSNNTP_WARNING_REQUEST_AUTHORIZATION_USERNAME;
+
+ case 381:
+ return NEWSNNTP_WARNING_REQUEST_AUTHORIZATION_PASSWORD;
+
+ case 215:
+ * result = read_distrib_default_value_list(f);
+ return NEWSNNTP_NO_ERROR;
+
+ case 503:
+ return NEWSNNTP_ERROR_PROGRAM_ERROR;
+
+ default:
+ return NEWSNNTP_ERROR_UNEXPECTED_RESPONSE;
+ }
+}
+
+void newsnntp_list_distrib_pats_free(clist * l)
+{
+ distrib_default_value_list_free(l);
+}
+
+
+
+
+
+
+
+
+
+
+
+
+/* ********************** LIST NEWSGROUPS ***************************** */
+
+static struct newsnntp_group_description *
+group_description_new(char * group_name, char * description)
+{
+ struct newsnntp_group_description * n;
+
+ n = malloc(sizeof(* n));
+ if (n == NULL)
+ return NULL;
+
+ n->grp_name = strdup(group_name);
+ if (n->grp_name == NULL) {
+ free(n);
+ return NULL;
+ }
+
+ n->grp_description = strdup(description);
+ if (n->grp_description == NULL) {
+ free(n->grp_name);
+ free(n);
+ return NULL;
+ }
+
+ return n;
+}
+
+static void group_description_free(struct newsnntp_group_description * n)
+{
+ if (n->grp_name)
+ free(n->grp_name);
+ if (n->grp_description)
+ free(n->grp_description);
+ free(n);
+}
+
+static void group_description_list_free(clist * l)
+{
+ clist_foreach(l, (clist_func) group_description_free, NULL);
+ clist_free(l);
+}
+
+static clist * read_group_description_list(newsnntp * f);
+
+int newsnntp_list_newsgroups(newsnntp * f, const char * pattern,
+ clist ** result)
+{
+ char command[NNTP_STRING_SIZE];
+ int r;
+ char * response;
+
+ if (pattern)
+ snprintf(command, NNTP_STRING_SIZE, "LIST NEWSGROUPS %s\r\n", pattern);
+ else
+ snprintf(command, NNTP_STRING_SIZE, "LIST NEWSGROUPS\r\n");
+
+ r = send_command(f, command);
+ if (r == -1)
+ return NEWSNNTP_ERROR_STREAM;
+
+ response = read_line(f);
+ if (response == NULL)
+ return NEWSNNTP_ERROR_STREAM;
+
+ r = parse_response(f, response);
+
+ switch (r) {
+ case 480:
+ return NEWSNNTP_WARNING_REQUEST_AUTHORIZATION_USERNAME;
+
+ case 381:
+ return NEWSNNTP_WARNING_REQUEST_AUTHORIZATION_PASSWORD;
+
+ case 215:
+ * result = read_group_description_list(f);
+ return NEWSNNTP_NO_ERROR;
+
+ case 503:
+ return NEWSNNTP_ERROR_PROGRAM_ERROR;
+
+ default:
+ return NEWSNNTP_ERROR_UNEXPECTED_RESPONSE;
+ }
+}
+
+void newsnntp_list_newsgroups_free(clist * l)
+{
+ group_description_list_free(l);
+}
+
+
+
+
+
+
+
+
+
+
+
+
+/* ******************** LIST SUBSCRIPTIONS ******************************** */
+
+static void subscriptions_list_free(clist * l)
+{
+ clist_foreach(l, (clist_func) free, NULL);
+ clist_free(l);
+}
+
+static clist * read_subscriptions_list(newsnntp * f);
+
+int newsnntp_list_subscriptions(newsnntp * f, clist ** result)
+{
+ char command[NNTP_STRING_SIZE];
+ int r;
+ char * response;
+
+ snprintf(command, NNTP_STRING_SIZE, "LIST SUBSCRIPTIONS\r\n");
+ r = send_command(f, command);
+ if (r == -1)
+ return NEWSNNTP_ERROR_STREAM;
+
+ response = read_line(f);
+ if (response == NULL)
+ return NEWSNNTP_ERROR_STREAM;
+
+ r = parse_response(f, response);
+
+ switch (r) {
+ case 480:
+ return NEWSNNTP_WARNING_REQUEST_AUTHORIZATION_USERNAME;
+
+ case 381:
+ return NEWSNNTP_WARNING_REQUEST_AUTHORIZATION_PASSWORD;
+
+ case 215:
+ * result = read_subscriptions_list(f);
+ return NEWSNNTP_NO_ERROR;
+
+ case 503:
+ return NEWSNNTP_ERROR_PROGRAM_ERROR;
+
+ default:
+ return NEWSNNTP_ERROR_UNEXPECTED_RESPONSE;
+ }
+}
+
+void newsnntp_list_subscriptions_free(clist * l)
+{
+ subscriptions_list_free(l);
+}
+
+
+
+
+
+
+
+
+
+
+
+
+/* ******************** LISTGROUP ******************************** */
+
+static void articles_list_free(clist * l)
+{
+ clist_foreach(l, (clist_func) free, NULL);
+ clist_free(l);
+}
+
+static clist * read_articles_list(newsnntp * f);
+
+int newsnntp_listgroup(newsnntp * f, const char * group_name,
+ clist ** result)
+{
+ char command[NNTP_STRING_SIZE];
+ int r;
+ char * response;
+
+ if (group_name)
+ snprintf(command, NNTP_STRING_SIZE, "LISTGROUP %s\r\n", group_name);
+ else
+ snprintf(command, NNTP_STRING_SIZE, "LISTGROUP\r\n");
+ r = send_command(f, command);
+ if (r == -1)
+ return NEWSNNTP_ERROR_STREAM;
+
+ response = read_line(f);
+ if (response == NULL)
+ return NEWSNNTP_ERROR_STREAM;
+
+ r = parse_response(f, response);
+
+ switch (r) {
+ case 480:
+ return NEWSNNTP_WARNING_REQUEST_AUTHORIZATION_USERNAME;
+
+ case 381:
+ return NEWSNNTP_WARNING_REQUEST_AUTHORIZATION_PASSWORD;
+
+ case 211:
+ * result = read_articles_list(f);
+ return NEWSNNTP_NO_ERROR;
+
+ case 412:
+ return NEWSNNTP_ERROR_NO_NEWSGROUP_SELECTED;
+
+ case 502:
+ return NEWSNNTP_ERROR_NO_PERMISSION;
+
+ default:
+ return NEWSNNTP_ERROR_UNEXPECTED_RESPONSE;
+ }
+}
+
+void newsnntp_listgroup_free(clist * l)
+{
+ articles_list_free(l);
+}
+
+
+
+
+
+
+
+/* ********************** MODE READER ***************************** */
+
+int newsnntp_mode_reader(newsnntp * f)
+{
+ char command[NNTP_STRING_SIZE];
+ char * response;
+ int r;
+
+ snprintf(command, NNTP_STRING_SIZE, "MODE READER\r\n");
+
+ r = send_command(f, command);
+ if (r == -1)
+ return NEWSNNTP_ERROR_STREAM;
+
+ response = read_line(f);
+ if (response == NULL)
+ return NEWSNNTP_ERROR_STREAM;
+
+ r = parse_response(f, response);
+ switch (r) {
+ case 480:
+ return NEWSNNTP_WARNING_REQUEST_AUTHORIZATION_USERNAME;
+
+ case 381:
+ return NEWSNNTP_WARNING_REQUEST_AUTHORIZATION_PASSWORD;
+
+ case 200:
+ return NEWSNNTP_NO_ERROR;
+
+ default:
+ return NEWSNNTP_ERROR_UNEXPECTED_RESPONSE;
+ }
+}
+
+/* ********************** DATE ***************************** */
+
+#define strfcpy(a,b,c) {if (c) {strncpy(a,b,c);a[c-1]=0;}}
+
+int newsnntp_date(newsnntp * f, struct tm * tm)
+{
+ char command[NNTP_STRING_SIZE];
+ int r;
+ char * response;
+ char year[5];
+ char month[3];
+ char day[3];
+ char hour[3];
+ char minute[3];
+ char second[3];
+
+ snprintf(command, NNTP_STRING_SIZE, "DATE\r\n");
+ r = send_command(f, command);
+ if (r == -1)
+ return NEWSNNTP_ERROR_STREAM;
+
+ response = read_line(f);
+ if (response == NULL)
+ return NEWSNNTP_ERROR_STREAM;
+
+ r = parse_response(f, response);
+
+ switch (r) {
+ case 111:
+ strfcpy(year, f->nntp_response, 4);
+ strfcpy(month, f->nntp_response + 4, 2);
+ strfcpy(day, f->nntp_response + 6, 2);
+ strfcpy(hour, f->nntp_response + 8, 2);
+ strfcpy(minute, f->nntp_response + 10, 2);
+ strfcpy(second, f->nntp_response + 12, 2);
+
+ tm->tm_year = atoi(year);
+ tm->tm_mon = atoi(month);
+ tm->tm_mday = atoi(day);
+ tm->tm_hour = atoi(hour);
+ tm->tm_min = atoi(minute);
+ tm->tm_sec = atoi(second);
+
+ return NEWSNNTP_NO_ERROR;
+
+ default:
+ return NEWSNNTP_ERROR_UNEXPECTED_RESPONSE;
+ }
+}
+
+
+
+
+
+
+
+
+
+/* ********************** XHDR ***************************** */
+
+static struct newsnntp_xhdr_resp_item * xhdr_resp_item_new(uint32_t article,
+ char * value)
+{
+ struct newsnntp_xhdr_resp_item * n;
+
+ n = malloc(sizeof(* n));
+ if (n == NULL)
+ return NULL;
+
+ n->hdr_value = strdup(value);
+ if (n->hdr_value == NULL) {
+ free(n);
+ return NULL;
+ }
+
+ n->hdr_article = article;
+
+ return n;
+}
+
+static void xhdr_resp_item_free(struct newsnntp_xhdr_resp_item * n)
+{
+ if (n->hdr_value)
+ free(n->hdr_value);
+ free(n);
+}
+
+static void xhdr_resp_list_free(clist * l)
+{
+ clist_foreach(l, (clist_func) xhdr_resp_item_free, NULL);
+ clist_free(l);
+}
+
+static clist * read_xhdr_resp_list(newsnntp * f);
+
+static int newsnntp_xhdr_resp(newsnntp * f, clist ** result);
+
+int newsnntp_xhdr_single(newsnntp * f, const char * header, uint32_t article,
+ clist ** result)
+{
+ char command[NNTP_STRING_SIZE];
+ int r;
+
+ snprintf(command, NNTP_STRING_SIZE, "XHDR %s %i\r\n", header, article);
+ r = send_command(f, command);
+ if (r == -1)
+ return NEWSNNTP_ERROR_STREAM;
+
+ return newsnntp_xhdr_resp(f, result);
+}
+
+int newsnntp_xhdr_range(newsnntp * f, const char * header,
+ uint32_t rangeinf, uint32_t rangesup,
+ clist ** result)
+{
+ char command[NNTP_STRING_SIZE];
+ int r;
+
+ snprintf(command, NNTP_STRING_SIZE, "XHDR %s %i-%i\r\n", header,
+ rangeinf, rangesup);
+ r = send_command(f, command);
+ if (r == -1)
+ return NEWSNNTP_ERROR_STREAM;
+
+ return newsnntp_xhdr_resp(f, result);
+}
+
+void newsnntp_xhdr_free(clist * l)
+{
+ xhdr_resp_list_free(l);
+}
+
+static int newsnntp_xhdr_resp(newsnntp * f, clist ** result)
+{
+ int r;
+ char * response;
+
+ response = read_line(f);
+ if (response == NULL)
+ return NEWSNNTP_ERROR_STREAM;
+
+ r = parse_response(f, response);
+
+ switch (r) {
+ case 480:
+ return NEWSNNTP_WARNING_REQUEST_AUTHORIZATION_USERNAME;
+
+ case 381:
+ return NEWSNNTP_WARNING_REQUEST_AUTHORIZATION_PASSWORD;
+
+ case 221:
+ * result = read_xhdr_resp_list(f);
+ return NEWSNNTP_NO_ERROR;
+
+ case 412:
+ return NEWSNNTP_ERROR_NO_NEWSGROUP_SELECTED;
+
+ case 420:
+ return NEWSNNTP_ERROR_NO_ARTICLE_SELECTED;
+
+ case 430:
+ return NEWSNNTP_ERROR_ARTICLE_NOT_FOUND;
+
+ case 502:
+ return NEWSNNTP_ERROR_NO_PERMISSION;
+
+ default:
+ return NEWSNNTP_ERROR_UNEXPECTED_RESPONSE;
+ }
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+/* ********************** XOVER ***************************** */
+
+static struct newsnntp_xover_resp_item *
+xover_resp_item_new(uint32_t article,
+ char * subject,
+ char * author,
+ char * date,
+ char * message_id,
+ char * references,
+ size_t size,
+ uint32_t line_count,
+ clist * others)
+{
+ struct newsnntp_xover_resp_item * n;
+
+ n = malloc(sizeof(* n));
+ if (n == NULL)
+ return NULL;
+
+ n->ovr_subject = strdup(subject);
+ if (n->ovr_subject == NULL) {
+ free(n);
+ return NULL;
+ }
+
+ n->ovr_author = strdup(author);
+ if (n->ovr_author == NULL) {
+ free(n->ovr_subject);
+ free(n);
+ return NULL;
+ }
+
+ n->ovr_date = strdup(date);
+ if (n->ovr_date == NULL) {
+ free(n->ovr_subject);
+ free(n->ovr_author);
+ free(n);
+ return NULL;
+ }
+
+ n->ovr_message_id = strdup(message_id);
+ if (n->ovr_message_id == NULL) {
+ free(n->ovr_subject);
+ free(n->ovr_author);
+ free(n->ovr_date);
+ free(n);
+ return NULL;
+ }
+
+ n->ovr_references = strdup(references);
+ if (n->ovr_references == NULL) {
+ free(n->ovr_subject);
+ free(n->ovr_author);
+ free(n->ovr_date);
+ free(n->ovr_message_id);
+ free(n);
+ return NULL;
+ }
+
+ n->ovr_article = article;
+ n->ovr_size = size;
+ n->ovr_line_count = line_count;
+ n->ovr_others = others;
+
+ return n;
+}
+
+void xover_resp_item_free(struct newsnntp_xover_resp_item * n)
+{
+ if (n->ovr_subject)
+ free(n->ovr_subject);
+ if (n->ovr_author)
+ free(n->ovr_author);
+ if (n->ovr_date)
+ free(n->ovr_date);
+ if (n->ovr_message_id)
+ free(n->ovr_message_id);
+ if (n->ovr_references)
+ free(n->ovr_references);
+ clist_foreach(n->ovr_others, (clist_func) free, NULL);
+ clist_free(n->ovr_others);
+
+ free(n);
+}
+
+void newsnntp_xover_resp_list_free(clist * l)
+{
+ clist_foreach(l, (clist_func) xover_resp_item_free, NULL);
+ clist_free(l);
+}
+
+static clist * read_xover_resp_list(newsnntp * f);
+
+
+static int newsnntp_xover_resp(newsnntp * f, clist ** result);
+
+int newsnntp_xover_single(newsnntp * f, uint32_t article,
+ struct newsnntp_xover_resp_item ** result)
+{
+ char command[NNTP_STRING_SIZE];
+ int r;
+ clist * list;
+ clistiter * cur;
+ struct newsnntp_xover_resp_item * item;
+
+ snprintf(command, NNTP_STRING_SIZE, "XOVER %i\r\n", article);
+ r = send_command(f, command);
+ if (r == -1)
+ return NEWSNNTP_ERROR_STREAM;
+
+ r = newsnntp_xover_resp(f, &list);
+ if (r != NEWSNNTP_NO_ERROR)
+ return r;
+
+ cur = clist_begin(list);
+ item = clist_content(cur);
+ clist_free(list);
+
+ * result = item;
+
+ return r;
+}
+
+int newsnntp_xover_range(newsnntp * f, uint32_t rangeinf, uint32_t rangesup,
+ clist ** result)
+{
+ int r;
+ char command[NNTP_STRING_SIZE];
+
+ snprintf(command, NNTP_STRING_SIZE, "XOVER %i-%i\r\n", rangeinf, rangesup);
+ r = send_command(f, command);
+ if (r == -1)
+ return NEWSNNTP_ERROR_STREAM;
+
+ return newsnntp_xover_resp(f, result);
+}
+
+static int newsnntp_xover_resp(newsnntp * f, clist ** result)
+{
+ int r;
+ char * response;
+
+ response = read_line(f);
+ if (response == NULL)
+ return NEWSNNTP_ERROR_STREAM;
+
+ r = parse_response(f, response);
+
+ switch (r) {
+ case 480:
+ return NEWSNNTP_WARNING_REQUEST_AUTHORIZATION_USERNAME;
+
+ case 381:
+ return NEWSNNTP_WARNING_REQUEST_AUTHORIZATION_PASSWORD;
+
+ case 224:
+ * result = read_xover_resp_list(f);
+ return NEWSNNTP_NO_ERROR;
+
+ case 412:
+ return NEWSNNTP_ERROR_NO_NEWSGROUP_SELECTED;
+
+ case 420:
+ return NEWSNNTP_ERROR_NO_ARTICLE_SELECTED;
+
+ case 502:
+ return NEWSNNTP_ERROR_NO_PERMISSION;
+
+ default:
+ return NEWSNNTP_ERROR_UNEXPECTED_RESPONSE;
+ }
+}
+
+
+
+
+
+
+
+/* ********************** AUTHINFO GENERIC ***************************** */
+
+int newsnntp_authinfo_generic(newsnntp * f, const char * authentificator,
+ const char * arguments)
+{
+ char command[NNTP_STRING_SIZE];
+ int r;
+ char * response;
+
+ snprintf(command, NNTP_STRING_SIZE, "AUTHINFO GENERIC %s %s\r\n",
+ authentificator, arguments);
+ r = send_command(f, command);
+ if (r == -1)
+ return NEWSNNTP_ERROR_STREAM;
+
+ response = read_line(f);
+ if (response == NULL)
+ return NEWSNNTP_ERROR_STREAM;
+
+ r = parse_response(f, response);
+
+ switch (r) {
+ case 480:
+ return NEWSNNTP_WARNING_REQUEST_AUTHORIZATION_USERNAME;
+
+ case 381:
+ return NEWSNNTP_WARNING_REQUEST_AUTHORIZATION_PASSWORD;
+
+ case 281:
+ return NEWSNNTP_NO_ERROR;
+
+ case 500:
+ return NEWSNNTP_ERROR_COMMAND_NOT_UNDERSTOOD;
+
+ case 501:
+ return NEWSNNTP_ERROR_COMMAND_NOT_SUPPORTED;
+
+ case 502:
+ return NEWSNNTP_ERROR_NO_PERMISSION;
+
+ case 503:
+ return NEWSNNTP_ERROR_PROGRAM_ERROR;
+
+ default:
+ return NEWSNNTP_ERROR_UNEXPECTED_RESPONSE;
+ }
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+static int parse_space(char ** line)
+{
+ char * p;
+
+ p = * line;
+
+ while ((* p == ' ') || (* p == '\t'))
+ p ++;
+
+ if (p != * line) {
+ * line = p;
+ return TRUE;
+ }
+ else
+ return FALSE;
+}
+
+static char * cut_token(char * line)
+{
+ char * p;
+ char * p_tab;
+ char * p_space;
+
+ p = line;
+
+ p_space = strchr(line, ' ');
+ p_tab = strchr(line, '\t');
+ if (p_tab == NULL)
+ p = p_space;
+ else if (p_space == NULL)
+ p = p_tab;
+ else {
+ if (p_tab < p_space)
+ p = p_tab;
+ else
+ p = p_space;
+ }
+ if (p == NULL)
+ return NULL;
+ * p = 0;
+ p ++;
+
+ return p;
+}
+
+static int parse_response(newsnntp * f, char * response)
+{
+ int code;
+
+ code = strtol(response, &response, 10);
+
+ if (response == NULL) {
+ f->nntp_response = NULL;
+ return code;
+ }
+
+ parse_space(&response);
+
+ if (mmap_string_assign(f->nntp_response_buffer, response) != NULL)
+ f->nntp_response = f->nntp_response_buffer->str;
+ else
+ f->nntp_response = NULL;
+
+ return code;
+}
+
+
+static char * read_line(newsnntp * f)
+{
+ return mailstream_read_line_remove_eol(f->nntp_stream, f->nntp_stream_buffer);
+}
+
+static char * read_multiline(newsnntp * f, size_t size,
+ MMAPString * multiline_buffer)
+{
+ return mailstream_read_multiline(f->nntp_stream, size,
+ f->nntp_stream_buffer, multiline_buffer,
+ f->nntp_progr_rate, f->nntp_progr_fun);
+}
+
+
+
+
+
+
+
+static int parse_group_info(char * response,
+ struct newsnntp_group_info ** result)
+{
+ char * line;
+ uint32_t first;
+ uint32_t last;
+ uint32_t count;
+ char * name;
+ struct newsnntp_group_info * info;
+
+ line = response;
+
+ count = strtoul(line, &line, 10);
+ if (!parse_space(&line))
+ return FALSE;
+
+ first = strtoul(line, &line, 10);
+ if (!parse_space(&line))
+ return FALSE;
+
+ last = strtoul(line, &line, 10);
+ if (!parse_space(&line))
+ return FALSE;
+
+ name = line;
+
+ info = group_info_init(name, first, last, count, FALSE);
+ if (info == NULL)
+ return FALSE;
+
+ * result = info;
+
+ return TRUE;
+}
+
+
+static clist * read_groups_list(newsnntp * f)
+{
+ char * line;
+ char * group_name;
+ uint32_t first;
+ uint32_t last;
+ uint32_t count;
+ int type;
+ clist * groups_list;
+ struct newsnntp_group_info * n;
+ int r;
+
+ groups_list = clist_new();
+ if (groups_list == NULL)
+ goto err;
+
+ while (1) {
+ char * p;
+
+ line = read_line(f);
+ if (line == NULL)
+ goto free_list;
+
+ if (mailstream_is_end_multiline(line))
+ break;
+
+ p = cut_token(line);
+ if (p == NULL)
+ continue;
+
+ group_name = line;
+ line = p;
+
+ last = strtol(line, &line, 10);
+ if (!parse_space(&line))
+ continue;
+
+ first = strtol(line, &line, 10);
+ if (!parse_space(&line))
+ continue;
+
+ count = last - first + 1;
+
+ type = * line;
+
+ n = group_info_init(group_name, first, last, count, type);
+ if (n == NULL)
+ goto free_list;
+
+ r = clist_append(groups_list, n);
+ if (r < 0) {
+ group_info_free(n);
+ goto free_list;
+ }
+ }
+
+ return groups_list;
+
+ free_list:
+ group_info_list_free(groups_list);
+ err:
+ return NULL;
+}
+
+
+static clist * read_headers_list(newsnntp * f)
+{
+ char * line;
+ clist * headers_list;
+ char * header;
+ int r;
+
+ headers_list = clist_new();
+ if (headers_list == NULL)
+ goto err;
+
+ while (1) {
+ line = read_line(f);
+
+ if (line == NULL)
+ goto free_list;
+
+ if (mailstream_is_end_multiline(line))
+ break;
+
+ header = strdup(line);
+ if (header == NULL)
+ goto free_list;
+
+ r = clist_append(headers_list, header);
+ if (r < 0) {
+ free(header);
+ goto free_list;
+ }
+ }
+
+ return headers_list;
+
+ free_list:
+ headers_list_free(headers_list);
+ err:
+ return NULL;
+}
+
+
+
+
+static clist * read_group_time_list(newsnntp * f)
+{
+ char * line;
+ char * group_name;
+ time_t date;
+ char * email;
+ clist * group_time_list;
+ struct newsnntp_group_time * n;
+ int r;
+
+ group_time_list = clist_new();
+ if (group_time_list == NULL)
+ goto err;
+
+ while (1) {
+ char * p;
+ char * remaining;
+
+ line = read_line(f);
+
+ if (line == NULL)
+ goto free_list;
+
+ if (mailstream_is_end_multiline(line))
+ break;
+
+ p = cut_token(line);
+ if (p == NULL)
+ continue;
+
+ date = strtoul(p, &remaining, 10);
+
+ p = remaining;
+ parse_space(&p);
+
+ email = p;
+
+ group_name = line;
+
+ n = group_time_new(group_name, date, email);
+ if (n == NULL)
+ goto free_list;
+
+ r = clist_append(group_time_list, n);
+ if (r < 0) {
+ group_time_free(n);
+ goto free_list;
+ }
+ }
+
+ return group_time_list;
+
+ free_list:
+ group_time_list_free(group_time_list);
+ err:
+ return NULL;
+}
+
+
+
+
+static clist * read_distrib_value_meaning_list(newsnntp * f)
+{
+ char * line;
+ char * value;
+ char * meaning;
+ clist * distrib_value_meaning_list;
+ struct newsnntp_distrib_value_meaning * n;
+ int r;
+
+ distrib_value_meaning_list = clist_new();
+ if (distrib_value_meaning_list == NULL)
+ goto err;
+
+ while (1) {
+ char * p;
+
+ line = read_line(f);
+ if (line == NULL)
+ goto free_list;
+
+ if (mailstream_is_end_multiline(line))
+ break;
+
+ p = cut_token(line);
+ if (p == NULL)
+ continue;
+
+ meaning = p;
+
+ value = line;
+
+ n = distrib_value_meaning_new(value, meaning);
+ if (n == NULL)
+ goto free_list;
+
+ r = clist_append(distrib_value_meaning_list, n);
+ if (r < 0) {
+ distrib_value_meaning_free(n);
+ goto free_list;
+ }
+ }
+
+ return distrib_value_meaning_list;
+
+ free_list:
+ distrib_value_meaning_list_free(distrib_value_meaning_list);
+ err:
+ return NULL;
+}
+
+
+
+
+static clist * read_distrib_default_value_list(newsnntp * f)
+{
+ char * line;
+ uint32_t weight;
+ char * group_pattern;
+ char * meaning;
+ clist * distrib_default_value_list;
+ struct newsnntp_distrib_default_value * n;
+ int r;
+
+ distrib_default_value_list = clist_new();
+ if (distrib_default_value_list == NULL)
+ goto err;
+
+ while (1) {
+ char * p;
+ char * remaining;
+
+ line = read_line(f);
+ if (line == NULL)
+ goto free_list;
+
+ if (mailstream_is_end_multiline(line))
+ break;
+
+ p = line;
+
+ weight = strtoul(p, &remaining, 10);
+ p = remaining;
+ parse_space(&p);
+
+ p = cut_token(line);
+ if (p == NULL)
+ continue;
+
+ meaning = p;
+ group_pattern = line;
+
+ n = distrib_default_value_new(weight, group_pattern, meaning);
+ if (n == NULL)
+ goto free_list;
+
+ r = clist_append(distrib_default_value_list, n);
+ if (r < 0) {
+ distrib_default_value_free(n);
+ goto free_list;
+ }
+ }
+
+ return distrib_default_value_list;
+
+ free_list:
+ distrib_default_value_list_free(distrib_default_value_list);
+ err:
+ return NULL;
+}
+
+
+
+static clist * read_group_description_list(newsnntp * f)
+{
+ char * line;
+ char * group_name;
+ char * description;
+ clist * group_description_list;
+ struct newsnntp_group_description * n;
+ int r;
+
+ group_description_list = clist_new();
+ if (group_description_list == NULL)
+ goto err;
+
+ while (1) {
+ char * p;
+
+ line = read_line(f);
+ if (line == NULL)
+ goto free_list;
+
+ if (mailstream_is_end_multiline(line))
+ break;
+
+ p = cut_token(line);
+ if (p == NULL)
+ continue;
+
+ description = p;
+
+ group_name = line;
+
+ n = group_description_new(group_name, description);
+ if (n == NULL)
+ goto free_list;
+
+ r = clist_append(group_description_list, n);
+ if (r < 0) {
+ group_description_free(n);
+ goto free_list;
+ }
+ }
+
+ return group_description_list;
+
+ free_list:
+ group_description_list_free(group_description_list);
+ err:
+ return NULL;
+}
+
+
+
+static clist * read_subscriptions_list(newsnntp * f)
+{
+ char * line;
+ clist * subscriptions_list;
+ char * group_name;
+ int r;
+
+ subscriptions_list = clist_new();
+ if (subscriptions_list == NULL)
+ goto err;
+
+ while (1) {
+ line = read_line(f);
+
+ if (line == NULL)
+ goto free_list;
+
+ if (mailstream_is_end_multiline(line))
+ break;
+
+ group_name = strdup(line);
+ if (group_name == NULL)
+ goto free_list;
+
+ r = clist_append(subscriptions_list, group_name);
+ if (r < 0) {
+ free(group_name);
+ goto free_list;
+ }
+ }
+
+ return subscriptions_list;
+
+ free_list:
+ subscriptions_list_free(subscriptions_list);
+ err:
+ return NULL;
+}
+
+
+
+static clist * read_articles_list(newsnntp * f)
+{
+ char * line;
+ clist * articles_list;
+ uint32_t * article_num;
+ int r;
+
+ articles_list = clist_new();
+ if (articles_list == NULL)
+ goto err;
+
+ while (1) {
+ line = read_line(f);
+ if (line == NULL)
+ goto free_list;
+
+ if (mailstream_is_end_multiline(line))
+ break;
+
+ article_num = malloc(sizeof(* article_num));
+ if (article_num == NULL)
+ goto free_list;
+ * article_num = atoi(line);
+
+ r = clist_append(articles_list, article_num);
+ if (r < 0) {
+ free(article_num);
+ goto free_list;
+ }
+ }
+
+ return articles_list;
+
+ free_list:
+ articles_list_free(articles_list);
+ err:
+ return NULL;
+}
+
+static clist * read_xhdr_resp_list(newsnntp * f)
+{
+ char * line;
+ uint32_t article;
+ char * value;
+ clist * xhdr_resp_list;
+ struct newsnntp_xhdr_resp_item * n;
+ int r;
+
+ xhdr_resp_list = clist_new();
+ if (xhdr_resp_list == NULL)
+ goto err;
+
+ while (1) {
+ line = read_line(f);
+
+ if (line == NULL)
+ goto free_list;
+
+ if (mailstream_is_end_multiline(line))
+ break;
+
+ article = strtoul(line, &line, 10);
+ if (!parse_space(&line))
+ continue;
+
+ value = line;
+
+ n = xhdr_resp_item_new(article, value);
+ if (n == NULL)
+ goto free_list;
+
+ r = clist_append(xhdr_resp_list, n);
+ if (r < 0) {
+ xhdr_resp_item_free(n);
+ goto free_list;
+ }
+ }
+
+ return xhdr_resp_list;
+
+ free_list:
+ xhdr_resp_list_free(xhdr_resp_list);
+ err:
+ return NULL;
+}
+
+
+static clist * read_xover_resp_list(newsnntp * f)
+{
+ char * line;
+ clist * xover_resp_list;
+ struct newsnntp_xover_resp_item * n;
+ clist * values_list;
+ clistiter * current;
+ uint32_t article;
+ char * subject;
+ char * author;
+ char * date;
+ char * message_id;
+ char * references;
+ size_t size;
+ uint32_t line_count;
+ clist * others;
+ int r;
+
+ xover_resp_list = clist_new();
+ if (xover_resp_list == NULL)
+ goto err;
+
+ while (1) {
+ char * p;
+
+ line = read_line(f);
+
+ if (line == NULL)
+ goto free_list;
+
+ if (mailstream_is_end_multiline(line))
+ break;
+
+ /* parse the data separated with \t */
+
+ values_list = clist_new();
+ if (values_list == NULL)
+ goto free_list;
+
+ while ((p = strchr(line, '\t')) != NULL) {
+ * p = 0;
+ p ++;
+
+ r = clist_append(values_list, line);
+ if (r < 0)
+ goto free_values_list;
+ line = p;
+ }
+
+ r = clist_append(values_list, line);
+ if (r < 0)
+ goto free_values_list;
+
+ /* set the known data */
+ current = clist_begin(values_list);
+ article = atoi((char *) clist_content(current));
+
+ current = clist_next(current);
+ if (current == NULL) {
+ clist_free(values_list);
+ continue;
+ }
+ subject = clist_content(current);
+
+ current = clist_next(current);
+ if (current == NULL) {
+ clist_free(values_list);
+ continue;
+ }
+ author = clist_content(current);
+
+ current = clist_next(current);
+ if (current == NULL) {
+ clist_free(values_list);
+ continue;
+ }
+ date = clist_content(current);
+
+ current = clist_next(current);
+ if (current == NULL) {
+ clist_free(values_list);
+ continue;
+ }
+ message_id = clist_content(current);
+
+ current = clist_next(current);
+ if (current == NULL) {
+ clist_free(values_list);
+ continue;
+ }
+ references = clist_content(current);
+
+ current = clist_next(current);
+ if (current == NULL) {
+ clist_free(values_list);
+ continue;
+ }
+ size = atoi((char *) clist_content(current));
+
+ current = clist_next(current);
+ if (current == NULL) {
+ clist_free(values_list);
+ continue;
+ }
+ line_count = atoi((char *) clist_content(current));
+
+ current = clist_next(current);
+
+ /* make a copy of the other data */
+ others = clist_new();
+ if (others == NULL) {
+ goto free_values_list;
+ }
+
+ while (current) {
+ char * val;
+
+ val = strdup(clist_content(current));
+ if (val == NULL) {
+ clist_foreach(others, (clist_func) free, NULL);
+ clist_free(others);
+ goto free_list;
+ }
+
+ r = clist_append(others, val);
+ if (r < 0) {
+ goto free_list;
+ }
+
+ current = clist_next(current);
+ }
+
+ clist_free(values_list);
+
+ n = xover_resp_item_new(article, subject, author, date, message_id,
+ references, size, line_count, others);
+ if (n == NULL) {
+ clist_foreach(others, (clist_func) free, NULL);
+ clist_free(others);
+ goto free_list;
+ }
+
+ r = clist_append(xover_resp_list, n);
+ if (r < 0) {
+ xover_resp_item_free(n);
+ goto free_list;
+ }
+ }
+
+ return xover_resp_list;
+
+ free_list:
+ newsnntp_xover_resp_list_free(xover_resp_list);
+ err:
+ return NULL;
+
+ free_values_list:
+ clist_foreach(values_list, (clist_func) free, NULL);
+ clist_free(values_list);
+ return NULL;
+}
+
+static int send_command(newsnntp * f, char * command)
+{
+ ssize_t r;
+
+ r = mailstream_write(f->nntp_stream, command, strlen(command));
+ if (r == -1)
+ return -1;
+
+ r = mailstream_flush(f->nntp_stream);
+ if (r == -1)
+ return -1;
+
+ return 0;
+}
diff --git a/libetpan/src/low-level/nntp/newsnntp.h b/libetpan/src/low-level/nntp/newsnntp.h
new file mode 100644
index 0000000..dd65ee2
--- a/dev/null
+++ b/libetpan/src/low-level/nntp/newsnntp.h
@@ -0,0 +1,187 @@
+/*
+ * 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$
+ */
+
+#ifndef NEWSNNTP_H
+
+#define NEWSNNTP_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <inttypes.h>
+#include <sys/types.h>
+#include <time.h>
+
+#include <libetpan/clist.h>
+#include <libetpan/mailstream.h>
+#include <libetpan/newsnntp_socket.h>
+#include <libetpan/newsnntp_ssl.h>
+#include <libetpan/newsnntp_types.h>
+
+
+newsnntp * newsnntp_new(size_t nntp_progr_rate,
+ progress_function * nntp_progr_fun);
+void newsnntp_free(newsnntp * f);
+
+int newsnntp_quit(newsnntp * f);
+int newsnntp_connect(newsnntp * f, mailstream * s);
+
+int newsnntp_head(newsnntp * f, uint32_t index, char ** result,
+ size_t * result_len);
+int newsnntp_article(newsnntp * f, uint32_t index, char ** result,
+ size_t * result_len);
+int newsnntp_body(newsnntp * f, uint32_t index, char ** result,
+ size_t * result_len);
+
+void newsnntp_head_free(char * str);
+void newsnntp_article_free(char * str);
+void newsnntp_body_free(char * str);
+
+int newsnntp_mode_reader(newsnntp * f);
+
+int newsnntp_date(newsnntp * f, struct tm * tm);
+
+int newsnntp_authinfo_generic(newsnntp * f, const char * authentificator,
+ const char * arguments);
+
+int newsnntp_authinfo_username(newsnntp * f, const char * username);
+int newsnntp_authinfo_password(newsnntp * f, const char * password);
+
+int newsnntp_post(newsnntp * f, const char * message, size_t size);
+
+
+
+
+
+
+/******************* requests ******************************/
+
+int newsnntp_group(newsnntp * f, const char * groupname,
+ struct newsnntp_group_info ** info);
+void newsnntp_group_free(struct newsnntp_group_info * info);
+
+/*
+ elements are struct newsnntp_group_info *
+ */
+
+int newsnntp_list(newsnntp * f, clist ** result);
+void newsnntp_list_free(clist * l);
+
+/*
+ elements are char *
+*/
+
+int newsnntp_list_overview_fmt(newsnntp * f, clist ** result);
+void newsnntp_list_overview_fmt_free(clist * l);
+
+/*
+ elements are struct newsnntp_group_info *
+*/
+
+int newsnntp_list_active(newsnntp * f, const char * wildcard, clist ** result);
+void newsnntp_list_active_free(clist * l);
+
+/*
+ elements are struct newsnntp_group_time *
+*/
+
+int newsnntp_list_active_times(newsnntp * f, clist ** result);
+void newsnntp_list_active_times_free(clist * l);
+
+/*
+ elements are struct newsnntp_distrib_value_meaning *
+*/
+
+int newsnntp_list_distribution(newsnntp * f, clist ** result);
+void newsnntp_list_distribution_free(clist * l);
+
+/*
+ elements are struct newsnntp_distrib_default_value *
+*/
+
+int newsnntp_list_distrib_pats(newsnntp * f, clist ** result);
+void newsnntp_list_distrib_pats_free(clist * l);
+
+/*
+ elements are struct newsnntp_group_description *
+*/
+
+int newsnntp_list_newsgroups(newsnntp * f, const char * pattern,
+ clist ** result);
+void newsnntp_list_newsgroups_free(clist * l);
+
+/*
+ elements are char *
+*/
+
+int newsnntp_list_subscriptions(newsnntp * f, clist ** result);
+void newsnntp_list_subscriptions_free(clist * l);
+
+/*
+ elements are uint32_t *
+*/
+
+int newsnntp_listgroup(newsnntp * f, const char * group_name,
+ clist ** result);
+void newsnntp_listgroup_free(clist * l);
+
+/*
+ elements are struct newsnntp_xhdr_resp_item *
+*/
+
+int newsnntp_xhdr_single(newsnntp * f, const char * header, uint32_t article,
+ clist ** result);
+int newsnntp_xhdr_range(newsnntp * f, const char * header,
+ uint32_t rangeinf, uint32_t rangesup,
+ clist ** result);
+void newsnntp_xhdr_free(clist * l);
+
+/*
+ elements are struct newsnntp_xover_resp_item *
+*/
+
+int newsnntp_xover_single(newsnntp * f, uint32_t article,
+ struct newsnntp_xover_resp_item ** result);
+int newsnntp_xover_range(newsnntp * f, uint32_t rangeinf, uint32_t rangesup,
+ clist ** result);
+void xover_resp_item_free(struct newsnntp_xover_resp_item * n);
+void newsnntp_xover_resp_list_free(clist * l);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libetpan/src/low-level/nntp/newsnntp_socket.c b/libetpan/src/low-level/nntp/newsnntp_socket.c
new file mode 100644
index 0000000..3fdd219
--- a/dev/null
+++ b/libetpan/src/low-level/nntp/newsnntp_socket.c
@@ -0,0 +1,74 @@
+/*
+ * 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 "newsnntp_socket.h"
+
+#include "newsnntp.h"
+
+#include "connect.h"
+
+#include <netinet/in.h>
+#include <unistd.h>
+
+#define DEFAULT_NNTP_PORT 119
+#define SERVICE_NAME_NNTP "nntp"
+#define SERVICE_TYPE_TCP "tcp"
+
+int newsnntp_socket_connect(newsnntp * f, const char * server, uint16_t port)
+{
+ int s;
+ mailstream * stream;
+
+ if (port == 0) {
+ port = mail_get_service_port(SERVICE_NAME_NNTP, SERVICE_TYPE_TCP);
+ if (port == 0)
+ port = DEFAULT_NNTP_PORT;
+ port = ntohs(port);
+ }
+
+ /* Connection */
+
+ s = mail_tcp_connect(server, port);
+ if (s == -1)
+ return NEWSNNTP_ERROR_CONNECTION_REFUSED;
+
+ stream = mailstream_socket_open(s);
+ if (stream == NULL) {
+ close(s);
+ return NEWSNNTP_ERROR_MEMORY;
+ }
+
+ return newsnntp_connect(f, stream);
+}
diff --git a/libetpan/src/low-level/nntp/newsnntp_socket.h b/libetpan/src/low-level/nntp/newsnntp_socket.h
new file mode 100644
index 0000000..4a52f73
--- a/dev/null
+++ b/libetpan/src/low-level/nntp/newsnntp_socket.h
@@ -0,0 +1,55 @@
+/*
+ * 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$
+ */
+
+#ifndef NEWSNNTP_SOCKET_H
+
+#define NEWSNNTP_SOCKET_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <sys/types.h>
+#include <inttypes.h>
+
+#include <libetpan/newsnntp_types.h>
+
+int newsnntp_socket_connect(newsnntp * f, const char * server, uint16_t port);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libetpan/src/low-level/nntp/newsnntp_ssl.c b/libetpan/src/low-level/nntp/newsnntp_ssl.c
new file mode 100644
index 0000000..d2e2c5f
--- a/dev/null
+++ b/libetpan/src/low-level/nntp/newsnntp_ssl.c
@@ -0,0 +1,73 @@
+/*
+ * 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 "newsnntp_ssl.h"
+
+#include "newsnntp.h"
+
+#include "connect.h"
+#include <netinet/in.h>
+#include <unistd.h>
+
+#define DEFAULT_NNTPS_PORT 563
+#define SERVICE_NAME_NNTPS "nntps"
+#define SERVICE_TYPE_TCP "tcp"
+
+int newsnntp_ssl_connect(newsnntp * f, const char * server, uint16_t port)
+{
+ int s;
+ mailstream * stream;
+
+ if (port == 0) {
+ port = mail_get_service_port(SERVICE_NAME_NNTPS, SERVICE_TYPE_TCP);
+ if (port == 0)
+ port = DEFAULT_NNTPS_PORT;
+ port = ntohs(port);
+ }
+
+ /* Connection */
+
+ s = mail_tcp_connect(server, port);
+ if (s == -1)
+ return NEWSNNTP_ERROR_CONNECTION_REFUSED;
+
+ stream = mailstream_ssl_open(s);
+ if (stream == NULL) {
+ close(s);
+ return NEWSNNTP_ERROR_CONNECTION_REFUSED;
+ }
+
+ return newsnntp_connect(f, stream);
+}
diff --git a/libetpan/src/low-level/nntp/newsnntp_ssl.h b/libetpan/src/low-level/nntp/newsnntp_ssl.h
new file mode 100644
index 0000000..845484f
--- a/dev/null
+++ b/libetpan/src/low-level/nntp/newsnntp_ssl.h
@@ -0,0 +1,55 @@
+/*
+ * 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$
+ */
+
+#ifndef NEWSNNTP_SSL_H
+
+#define NEWSNNTP_SSL_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <sys/types.h>
+#include <inttypes.h>
+
+#include <libetpan/newsnntp_types.h>
+
+int newsnntp_ssl_connect(newsnntp * f, const char * server, uint16_t port);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libetpan/src/low-level/nntp/newsnntp_types.h b/libetpan/src/low-level/nntp/newsnntp_types.h
new file mode 100644
index 0000000..821df46
--- a/dev/null
+++ b/libetpan/src/low-level/nntp/newsnntp_types.h
@@ -0,0 +1,144 @@
+/*
+ * 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$
+ */
+
+#ifndef NEWSNNTP_TYPES_H
+
+#define NEWSNNTP_TYPES_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <inttypes.h>
+#include <libetpan/clist.h>
+
+#include <libetpan/mailstream.h>
+#include <libetpan/mmapstring.h>
+
+enum {
+ NEWSNNTP_NO_ERROR = 0,
+ NEWSNNTP_WARNING_REQUEST_AUTHORIZATION_USERNAME,
+ NEWSNNTP_WARNING_REQUEST_AUTHORIZATION_PASSWORD,
+ NEWSNNTP_ERROR_STREAM,
+ NEWSNNTP_ERROR_UNEXPECTED,
+ NEWSNNTP_ERROR_NO_NEWSGROUP_SELECTED,
+ NEWSNNTP_ERROR_NO_ARTICLE_SELECTED,
+ NEWSNNTP_ERROR_INVALID_ARTICLE_NUMBER,
+ NEWSNNTP_ERROR_ARTICLE_NOT_FOUND,
+ NEWSNNTP_ERROR_UNEXPECTED_RESPONSE,
+ NEWSNNTP_ERROR_INVALID_RESPONSE,
+ NEWSNNTP_ERROR_NO_SUCH_NEWS_GROUP,
+ NEWSNNTP_ERROR_POSTING_NOT_ALLOWED,
+ NEWSNNTP_ERROR_POSTING_FAILED,
+ NEWSNNTP_ERROR_PROGRAM_ERROR,
+ NEWSNNTP_ERROR_NO_PERMISSION,
+ NEWSNNTP_ERROR_COMMAND_NOT_UNDERSTOOD,
+ NEWSNNTP_ERROR_COMMAND_NOT_SUPPORTED,
+ NEWSNNTP_ERROR_CONNECTION_REFUSED,
+ NEWSNNTP_ERROR_MEMORY,
+ NEWSNNTP_ERROR_AUTHENTICATION_REJECTED,
+ NEWSNNTP_ERROR_BAD_STATE,
+};
+
+struct newsnntp
+{
+ mailstream * nntp_stream;
+
+ int nntp_readonly;
+
+ uint32_t nntp_progr_rate;
+ progress_function * nntp_progr_fun;
+
+ MMAPString * nntp_stream_buffer;
+ MMAPString * nntp_response_buffer;
+
+ char * nntp_response;
+};
+
+typedef struct newsnntp newsnntp;
+
+struct newsnntp_group_info
+{
+ char * grp_name;
+ uint32_t grp_first;
+ uint32_t grp_last;
+ uint32_t grp_count;
+ char grp_type;
+};
+
+struct newsnntp_group_time {
+ char * grp_name;
+ uint32_t grp_date;
+ char * grp_email;
+};
+
+struct newsnntp_distrib_value_meaning {
+ char * dst_value;
+ char * dst_meaning;
+};
+
+struct newsnntp_distrib_default_value {
+ uint32_t dst_weight;
+ char * dst_group_pattern;
+ char * dst_value;
+};
+
+struct newsnntp_group_description {
+ char * grp_name;
+ char * grp_description;
+};
+
+struct newsnntp_xhdr_resp_item {
+ uint32_t hdr_article;
+ char * hdr_value;
+};
+
+struct newsnntp_xover_resp_item {
+ uint32_t ovr_article;
+ char * ovr_subject;
+ char * ovr_author;
+ char * ovr_date;
+ char * ovr_message_id;
+ char * ovr_references;
+ size_t ovr_size;
+ uint32_t ovr_line_count;
+ clist * ovr_others;
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libetpan/src/low-level/pop3/mailpop3.c b/libetpan/src/low-level/pop3/mailpop3.c
new file mode 100644
index 0000000..6f77a3a
--- a/dev/null
+++ b/libetpan/src/low-level/pop3/mailpop3.c
@@ -0,0 +1,1230 @@
+/*
+ * 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$
+ */
+
+/*
+ POP3 Protocol
+
+ RFC 1734
+ RFC 1939
+ RFC 2449
+
+ */
+
+#include "mailpop3.h"
+#include <stdio.h>
+#include <string.h>
+#include "md5.h"
+#include "mail.h"
+#include <stdlib.h>
+
+
+
+
+enum {
+ POP3_STATE_DISCONNECTED,
+ POP3_STATE_AUTHORIZATION,
+ POP3_STATE_TRANSACTION
+};
+
+
+
+/*
+ mailpop3_msg_info structure
+*/
+
+static struct mailpop3_msg_info *
+mailpop3_msg_info_new(unsigned int index, uint32_t size, char * uidl)
+{
+ struct mailpop3_msg_info * msg;
+
+ msg = malloc(sizeof(* msg));
+ if (msg == NULL)
+ return NULL;
+ msg->msg_index = index;
+ msg->msg_size = size;
+ msg->msg_deleted = FALSE;
+ msg->msg_uidl = uidl;
+
+ return msg;
+}
+
+static void mailpop3_msg_info_free(struct mailpop3_msg_info * msg)
+{
+ if (msg->msg_uidl != NULL)
+ free(msg->msg_uidl);
+ free(msg);
+}
+
+static void mailpop3_msg_info_tab_free(carray * msg_tab)
+{
+ unsigned int i;
+
+ for(i = 0 ; i < carray_count(msg_tab) ; i++) {
+ struct mailpop3_msg_info * msg;
+
+ msg = carray_get(msg_tab, i);
+ mailpop3_msg_info_free(msg);
+ }
+ carray_free(msg_tab);
+}
+
+static void mailpop3_msg_info_tab_reset(carray * msg_tab)
+{
+ unsigned int i;
+
+ for(i = 0 ; i < carray_count(msg_tab) ; i++) {
+ struct mailpop3_msg_info * msg;
+ msg = carray_get(msg_tab, i);
+ msg->msg_deleted = FALSE;
+ }
+}
+
+static inline struct mailpop3_msg_info *
+mailpop3_msg_info_tab_find_msg(carray * msg_tab, unsigned int index)
+{
+ struct mailpop3_msg_info * msg;
+
+ if (index == 0)
+ return NULL;
+
+ if (index > carray_count(msg_tab))
+ return NULL;
+
+ msg = carray_get(msg_tab, index - 1);
+
+ return msg;
+}
+
+
+
+int mailpop3_get_msg_info(mailpop3 * f, unsigned int index,
+ struct mailpop3_msg_info ** result)
+{
+ carray * tab;
+ struct mailpop3_msg_info * info;
+
+ mailpop3_list(f, &tab);
+
+ if (tab == NULL)
+ return MAILPOP3_ERROR_BAD_STATE;
+
+ info = mailpop3_msg_info_tab_find_msg(tab, index);
+ if (info == NULL)
+ return MAILPOP3_ERROR_NO_SUCH_MESSAGE;
+
+ * result = info;
+
+ return MAILPOP3_NO_ERROR;
+}
+
+
+/*
+ mailpop3_capa
+*/
+
+struct mailpop3_capa * mailpop3_capa_new(char * name, clist * param)
+{
+ struct mailpop3_capa * capa;
+
+ capa = malloc(sizeof(* capa));
+ if (capa == NULL)
+ return NULL;
+ capa->cap_name = name;
+ capa->cap_param = param;
+
+ return capa;
+}
+
+
+void mailpop3_capa_free(struct mailpop3_capa * capa)
+{
+ clist_foreach(capa->cap_param, (clist_func) free, NULL);
+ clist_free(capa->cap_param);
+ free(capa->cap_name);
+ free(capa);
+}
+
+/*
+ mailpop3 structure
+*/
+
+mailpop3 * mailpop3_new(size_t progr_rate, progress_function * progr_fun)
+{
+ mailpop3 * f;
+
+ f = malloc(sizeof(* f));
+ if (f == NULL)
+ goto err;
+
+ f->pop3_timestamp = NULL;
+ f->pop3_response = NULL;
+
+ f->pop3_stream = NULL;
+
+ f->pop3_progr_rate = progr_rate;
+ f->pop3_progr_fun = progr_fun;
+
+ f->pop3_stream_buffer = mmap_string_new("");
+ if (f->pop3_stream_buffer == NULL)
+ goto free_f;
+
+ f->pop3_response_buffer = mmap_string_new("");
+ if (f->pop3_response_buffer == NULL)
+ goto free_stream_buffer;
+
+ f->pop3_msg_tab = NULL;
+ f->pop3_deleted_count = 0;
+ f->pop3_state = POP3_STATE_DISCONNECTED;
+
+ return f;
+
+ free_stream_buffer:
+ mmap_string_free(f->pop3_stream_buffer);
+ free_f:
+ free(f);
+ err:
+ return NULL;
+}
+
+
+
+void mailpop3_free(mailpop3 * f)
+{
+ if (f->pop3_stream)
+ mailpop3_quit(f);
+
+ mmap_string_free(f->pop3_response_buffer);
+ mmap_string_free(f->pop3_stream_buffer);
+
+ free(f);
+}
+
+
+
+
+
+
+
+
+
+
+
+/*
+ operations on mailpop3 structure
+*/
+
+#define RESPONSE_OK 0
+#define RESPONSE_ERR -1
+
+static int send_command(mailpop3 * f, char * command);
+
+static char * read_line(mailpop3 * f);
+
+static char * read_multiline(mailpop3 * f, size_t size,
+ MMAPString * multiline_buffer);
+
+static int parse_response(mailpop3 * f, char * response);
+
+
+/* get the timestamp in the connection response */
+
+#define TIMESTAMP_START '<'
+#define TIMESTAMP_END '>'
+
+static char * mailpop3_get_timestamp(char * response)
+{
+ char * begin_timestamp;
+ char * end_timestamp;
+ char * timestamp;
+ int len_timestamp;
+
+ if (response == NULL)
+ return NULL;
+
+ begin_timestamp = strchr(response, TIMESTAMP_START);
+
+ end_timestamp = NULL;
+ if (begin_timestamp != NULL) {
+ end_timestamp = strchr(begin_timestamp, TIMESTAMP_END);
+ if (end_timestamp == NULL)
+ begin_timestamp = NULL;
+ }
+
+ if (!begin_timestamp)
+ return NULL;
+
+ len_timestamp = end_timestamp - begin_timestamp + 1;
+
+ timestamp = malloc(len_timestamp + 1);
+ if (timestamp == NULL)
+ return NULL;
+ strncpy(timestamp, begin_timestamp, len_timestamp);
+ timestamp[len_timestamp] = '\0';
+
+ return timestamp;
+}
+
+/*
+ connect a stream to the mailpop3 structure
+*/
+
+int mailpop3_connect(mailpop3 * f, mailstream * s)
+{
+ char * response;
+ int r;
+ char * timestamp;
+
+ if (f->pop3_state != POP3_STATE_DISCONNECTED)
+ return MAILPOP3_ERROR_BAD_STATE;
+
+ f->pop3_stream = s;
+
+ response = read_line(f);
+
+ r = parse_response(f, response);
+ if (r != RESPONSE_OK)
+ return MAILPOP3_ERROR_UNAUTHORIZED;
+
+ f->pop3_state = POP3_STATE_AUTHORIZATION;
+
+ timestamp = mailpop3_get_timestamp(f->pop3_response);
+ if (timestamp != NULL)
+ f->pop3_timestamp = timestamp;
+
+ return MAILPOP3_NO_ERROR;
+}
+
+
+/*
+ disconnect from a pop3 server
+*/
+
+int mailpop3_quit(mailpop3 * f)
+{
+ char command[POP3_STRING_SIZE];
+ char * response;
+ int r;
+ int res;
+
+ if ((f->pop3_state != POP3_STATE_AUTHORIZATION)
+ && (f->pop3_state != POP3_STATE_TRANSACTION)) {
+ res = MAILPOP3_ERROR_BAD_STATE;
+ goto close;
+ }
+
+ snprintf(command, POP3_STRING_SIZE, "QUIT\r\n");
+ r = send_command(f, command);
+ if (r == -1) {
+ res = MAILPOP3_ERROR_STREAM;
+ goto close;
+ }
+
+ response = read_line(f);
+ if (response == NULL) {
+ res = MAILPOP3_ERROR_STREAM;
+ goto close;
+ }
+ parse_response(f, response);
+
+ res = MAILPOP3_NO_ERROR;
+
+ close:
+ mailstream_close(f->pop3_stream);
+
+ if (f->pop3_timestamp != NULL) {
+ free(f->pop3_timestamp);
+ f->pop3_timestamp = NULL;
+ }
+
+ f->pop3_stream = NULL;
+ if (f->pop3_msg_tab != NULL) {
+ mailpop3_msg_info_tab_free(f->pop3_msg_tab);
+ f->pop3_msg_tab = NULL;
+ }
+
+ f->pop3_state = POP3_STATE_DISCONNECTED;
+
+ return res;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+int mailpop3_apop(mailpop3 * f,
+ const char * user, const char * password)
+{
+ char command[POP3_STRING_SIZE];
+ MD5_CTX md5context;
+ unsigned char md5digest[16];
+ char md5string[33];
+ char * cmd_ptr;
+ int r;
+ int i;
+ char * response;
+
+ if (f->pop3_state != POP3_STATE_AUTHORIZATION)
+ return MAILPOP3_ERROR_BAD_STATE;
+
+ if (f->pop3_timestamp == NULL)
+ return MAILPOP3_ERROR_APOP_NOT_SUPPORTED;
+
+ /* calculate md5 sum */
+
+ MD5Init(&md5context);
+ MD5Update(&md5context, f->pop3_timestamp, strlen (f->pop3_timestamp));
+ MD5Update(&md5context, password, strlen (password));
+ MD5Final(md5digest, &md5context);
+
+ cmd_ptr = md5string;
+ for(i = 0 ; i < 16 ; i++, cmd_ptr += 2)
+ snprintf(cmd_ptr, 3, "%02x", md5digest[i]);
+ * cmd_ptr = 0;
+
+ /* send apop command */
+
+ snprintf(command, POP3_STRING_SIZE, "APOP %s %s\r\n", user, md5string);
+ r = send_command(f, command);
+ if (r == -1)
+ return MAILPOP3_ERROR_STREAM;
+
+ response = read_line(f);
+
+ if (response == NULL)
+ return MAILPOP3_ERROR_STREAM;
+ r = parse_response(f, response);
+ if (r != RESPONSE_OK)
+ return MAILPOP3_ERROR_DENIED;
+
+ f->pop3_state = POP3_STATE_TRANSACTION;
+
+ return MAILPOP3_NO_ERROR;
+}
+
+int mailpop3_user(mailpop3 * f, const char * user)
+{
+ char command[POP3_STRING_SIZE];
+ int r;
+ char * response;
+
+ if (f->pop3_state != POP3_STATE_AUTHORIZATION)
+ return MAILPOP3_ERROR_BAD_STATE;
+
+ /* send user command */
+
+ snprintf(command, POP3_STRING_SIZE, "USER %s\r\n", user);
+ r = send_command(f, command);
+ if (r == -1)
+ return MAILPOP3_ERROR_STREAM;
+
+ response = read_line(f);
+ if (response == NULL)
+ return MAILPOP3_ERROR_STREAM;
+ r = parse_response(f, response);
+
+ if (r != RESPONSE_OK)
+ return MAILPOP3_ERROR_BAD_USER;
+
+ return MAILPOP3_NO_ERROR;
+}
+
+int mailpop3_pass(mailpop3 * f, const char * password)
+{
+ char command[POP3_STRING_SIZE];
+ int r;
+ char * response;
+
+ if (f->pop3_state != POP3_STATE_AUTHORIZATION)
+ return MAILPOP3_ERROR_BAD_STATE;
+
+ /* send password command */
+
+ snprintf(command, POP3_STRING_SIZE, "PASS %s\r\n", password);
+ r = send_command(f, command);
+ if (r == -1)
+ return MAILPOP3_ERROR_STREAM;
+
+ response = read_line(f);
+ if (response == NULL)
+ return MAILPOP3_ERROR_STREAM;
+ r = parse_response(f, response);
+
+ if (r != RESPONSE_OK)
+ return MAILPOP3_ERROR_BAD_PASSWORD;
+
+ f->pop3_state = POP3_STATE_TRANSACTION;
+
+ return MAILPOP3_NO_ERROR;
+}
+
+static int read_list(mailpop3 * f, carray ** result);
+
+
+
+static int read_uidl(mailpop3 * f, carray * msg_tab);
+
+
+
+static int mailpop3_do_uidl(mailpop3 * f, carray * msg_tab)
+{
+ char command[POP3_STRING_SIZE];
+ int r;
+ char * response;
+
+ if (f->pop3_state != POP3_STATE_TRANSACTION)
+ return MAILPOP3_ERROR_BAD_STATE;
+
+ /* send list command */
+
+ snprintf(command, POP3_STRING_SIZE, "UIDL\r\n");
+ r = send_command(f, command);
+ if (r == -1)
+ return MAILPOP3_ERROR_STREAM;
+
+ response = read_line(f);
+ if (response == NULL)
+ return MAILPOP3_ERROR_STREAM;
+ r = parse_response(f, response);
+
+ if (r != RESPONSE_OK)
+ return MAILPOP3_ERROR_CANT_LIST;
+
+ r = read_uidl(f, msg_tab);
+ if (r != MAILPOP3_NO_ERROR)
+ return r;
+
+ return MAILPOP3_NO_ERROR;
+}
+
+
+
+static int mailpop3_do_list(mailpop3 * f)
+{
+ char command[POP3_STRING_SIZE];
+ int r;
+ carray * msg_tab;
+ char * response;
+
+ if (f->pop3_msg_tab != NULL) {
+ mailpop3_msg_info_tab_free(f->pop3_msg_tab);
+ f->pop3_msg_tab = NULL;
+ }
+
+ if (f->pop3_state != POP3_STATE_TRANSACTION)
+ return MAILPOP3_ERROR_BAD_STATE;
+
+ /* send list command */
+
+ snprintf(command, POP3_STRING_SIZE, "LIST\r\n");
+ r = send_command(f, command);
+ if (r == -1)
+ return MAILPOP3_ERROR_STREAM;
+
+ response = read_line(f);
+ if (response == NULL)
+ return MAILPOP3_ERROR_STREAM;
+ r = parse_response(f, response);
+
+ if (r != RESPONSE_OK)
+ return MAILPOP3_ERROR_CANT_LIST;
+
+ r = read_list(f, &msg_tab);
+ if (r != MAILPOP3_NO_ERROR)
+ return r;
+
+ f->pop3_msg_tab = msg_tab;
+ f->pop3_deleted_count = 0;
+
+ mailpop3_do_uidl(f, msg_tab);
+
+ return MAILPOP3_NO_ERROR;
+}
+
+
+
+static void mailpop3_list_if_needed(mailpop3 * f)
+{
+ if (f->pop3_msg_tab == NULL)
+ mailpop3_do_list(f);
+}
+
+/*
+ mailpop3_list
+*/
+
+void mailpop3_list(mailpop3 * f, carray ** result)
+{
+ mailpop3_list_if_needed(f);
+ * result = f->pop3_msg_tab;
+}
+
+static inline struct mailpop3_msg_info *
+find_msg(mailpop3 * f, unsigned int index)
+{
+ mailpop3_list_if_needed(f);
+
+ if (f->pop3_msg_tab == NULL)
+ return NULL;
+
+ return mailpop3_msg_info_tab_find_msg(f->pop3_msg_tab, index);
+}
+
+
+
+
+
+
+
+
+static void mailpop3_multiline_response_free(char * str)
+{
+ mmap_string_unref(str);
+}
+
+void mailpop3_top_free(char * str)
+{
+ mailpop3_multiline_response_free(str);
+}
+
+void mailpop3_retr_free(char * str)
+{
+ mailpop3_multiline_response_free(str);
+}
+
+/*
+ mailpop3_retr
+
+ message content in (* result) is still there until the
+ next retrieve or top operation on the mailpop3 structure
+*/
+
+static int
+mailpop3_get_content(mailpop3 * f, struct mailpop3_msg_info * msginfo,
+ char ** result, size_t * result_len)
+{
+ char * response;
+ char * result_multiline;
+ MMAPString * buffer;
+ int r;
+
+ response = read_line(f);
+ if (response == NULL)
+ return MAILPOP3_ERROR_STREAM;
+ r = parse_response(f, response);
+ if (r != RESPONSE_OK)
+ return MAILPOP3_ERROR_NO_SUCH_MESSAGE;
+
+ buffer = mmap_string_new("");
+ if (buffer == NULL)
+ return MAILPOP3_ERROR_MEMORY;
+
+ result_multiline = read_multiline(f, msginfo->msg_size, buffer);
+ if (result_multiline == NULL) {
+ mmap_string_free(buffer);
+ return MAILPOP3_ERROR_STREAM;
+ }
+ else {
+ r = mmap_string_ref(buffer);
+ if (r < 0) {
+ mmap_string_free(buffer);
+ return MAILPOP3_ERROR_MEMORY;
+ }
+
+ * result = result_multiline;
+ * result_len = buffer->len;
+ return MAILPOP3_NO_ERROR;
+ }
+}
+
+int mailpop3_retr(mailpop3 * f, unsigned int index, char ** result,
+ size_t * result_len)
+{
+ char command[POP3_STRING_SIZE];
+ struct mailpop3_msg_info * msginfo;
+ int r;
+
+ if (f->pop3_state != POP3_STATE_TRANSACTION)
+ return MAILPOP3_ERROR_BAD_STATE;
+
+ msginfo = find_msg(f, index);
+
+ if (msginfo == NULL) {
+ f->pop3_response = NULL;
+ return MAILPOP3_ERROR_NO_SUCH_MESSAGE;
+ }
+
+ snprintf(command, POP3_STRING_SIZE, "RETR %i\r\n", index);
+ r = send_command(f, command);
+ if (r == -1)
+ return MAILPOP3_ERROR_STREAM;
+
+ return mailpop3_get_content(f, msginfo, result, result_len);
+}
+
+int mailpop3_top(mailpop3 * f, unsigned int index,
+ unsigned int count, char ** result,
+ size_t * result_len)
+{
+ char command[POP3_STRING_SIZE];
+ struct mailpop3_msg_info * msginfo;
+ int r;
+
+ if (f->pop3_state != POP3_STATE_TRANSACTION)
+ return MAILPOP3_ERROR_BAD_STATE;
+
+ msginfo = find_msg(f, index);
+
+ if (msginfo == NULL) {
+ f->pop3_response = NULL;
+ return MAILPOP3_ERROR_NO_SUCH_MESSAGE;
+ }
+
+ snprintf(command, POP3_STRING_SIZE, "TOP %i %i\r\n", index, count);
+ r = send_command(f, command);
+ if (r == -1)
+ return MAILPOP3_ERROR_STREAM;
+
+ return mailpop3_get_content(f, msginfo, result, result_len);
+}
+
+int mailpop3_dele(mailpop3 * f, unsigned int index)
+{
+ char command[POP3_STRING_SIZE];
+ struct mailpop3_msg_info * msginfo;
+ char * response;
+ int r;
+
+ if (f->pop3_state != POP3_STATE_TRANSACTION)
+ return MAILPOP3_ERROR_BAD_STATE;
+
+ msginfo = find_msg(f, index);
+
+ if (msginfo == NULL) {
+ f->pop3_response = NULL;
+ return MAILPOP3_ERROR_NO_SUCH_MESSAGE;
+ }
+
+ snprintf(command, POP3_STRING_SIZE, "DELE %i\r\n", index);
+ r = send_command(f, command);
+ if (r == -1)
+ return MAILPOP3_ERROR_STREAM;
+
+ response = read_line(f);
+ if (response == NULL)
+ return MAILPOP3_ERROR_STREAM;
+ r = parse_response(f, response);
+ if (r != RESPONSE_OK)
+ return MAILPOP3_ERROR_NO_SUCH_MESSAGE;
+
+ msginfo->msg_deleted = TRUE;
+ f->pop3_deleted_count ++;
+
+ return MAILPOP3_NO_ERROR;
+}
+
+int mailpop3_noop(mailpop3 * f)
+{
+ char command[POP3_STRING_SIZE];
+ char * response;
+ int r;
+
+ if (f->pop3_state != POP3_STATE_TRANSACTION)
+ return MAILPOP3_ERROR_BAD_STATE;
+
+ snprintf(command, POP3_STRING_SIZE, "NOOP\r\n");
+ r = send_command(f, command);
+ if (r == -1)
+ return MAILPOP3_ERROR_STREAM;
+
+ response = read_line(f);
+ if (response == NULL)
+ return MAILPOP3_ERROR_STREAM;
+ parse_response(f, response);
+
+ return MAILPOP3_NO_ERROR;
+}
+
+int mailpop3_rset(mailpop3 * f)
+{
+ char command[POP3_STRING_SIZE];
+ char * response;
+ int r;
+
+ if (f->pop3_state != POP3_STATE_TRANSACTION)
+ return MAILPOP3_ERROR_BAD_STATE;
+
+ snprintf(command, POP3_STRING_SIZE, "RSET\r\n");
+ r = send_command(f, command);
+ if (r == -1)
+ return MAILPOP3_ERROR_STREAM;
+
+ response = read_line(f);
+ if (response == NULL)
+ return MAILPOP3_ERROR_STREAM;
+ parse_response(f, response);
+
+ if (f->pop3_msg_tab != NULL) {
+ mailpop3_msg_info_tab_reset(f->pop3_msg_tab);
+ f->pop3_deleted_count = 0;
+ }
+
+ return MAILPOP3_NO_ERROR;
+}
+
+
+
+static int read_capa_resp(mailpop3 * f, clist ** result);
+
+int mailpop3_capa(mailpop3 * f, clist ** result)
+{
+ clist * capa_list;
+ char command[POP3_STRING_SIZE];
+ int r;
+ char * response;
+
+ snprintf(command, POP3_STRING_SIZE, "CAPA\r\n");
+ r = send_command(f, command);
+ if (r == -1)
+ return MAILPOP3_ERROR_STREAM;
+
+ response = read_line(f);
+ if (response == NULL)
+ return MAILPOP3_ERROR_STREAM;
+ r = parse_response(f, response);
+
+ if (r != RESPONSE_OK)
+ return MAILPOP3_ERROR_CAPA_NOT_SUPPORTED;
+
+ r = read_capa_resp(f, &capa_list);
+ if (r != MAILPOP3_NO_ERROR)
+ return r;
+
+ * result = capa_list;
+
+ return MAILPOP3_NO_ERROR;
+}
+
+void mailpop3_capa_resp_free(clist * capa_list)
+{
+ clist_foreach(capa_list, (clist_func) mailpop3_capa_free, NULL);
+ clist_free(capa_list);
+}
+
+int mailpop3_stls(mailpop3 * f)
+{
+ char command[POP3_STRING_SIZE];
+ int r;
+ char * response;
+
+ snprintf(command, POP3_STRING_SIZE, "STLS\r\n");
+ r = send_command(f, command);
+ if (r == -1)
+ return MAILPOP3_ERROR_STREAM;
+
+ response = read_line(f);
+ if (response == NULL)
+ return MAILPOP3_ERROR_STREAM;
+ r = parse_response(f, response);
+
+ if (r != RESPONSE_OK)
+ return MAILPOP3_ERROR_STLS_NOT_SUPPORTED;
+
+ return MAILPOP3_NO_ERROR;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#define RESP_OK_STR "+OK"
+#define RESP_ERR_STR "-ERR"
+
+
+static int parse_space(char ** line)
+{
+ char * p;
+
+ p = * line;
+
+ while ((* p == ' ') || (* p == '\t'))
+ p ++;
+
+ if (p != * line) {
+ * line = p;
+ return TRUE;
+ }
+ else
+ return FALSE;
+}
+
+static char * cut_token(char * line)
+{
+ char * p;
+ char * p_tab;
+ char * p_space;
+
+ p = line;
+
+ p_space = strchr(line, ' ');
+ p_tab = strchr(line, '\t');
+ if (p_tab == NULL)
+ p = p_space;
+ else if (p_space == NULL)
+ p = p_tab;
+ else {
+ if (p_tab < p_space)
+ p = p_tab;
+ else
+ p = p_space;
+ }
+ if (p == NULL)
+ return NULL;
+ * p = 0;
+ p ++;
+
+ return p;
+}
+
+
+static int parse_response(mailpop3 * f, char * response)
+{
+ char * msg;
+
+ if (response == NULL) {
+ f->pop3_response = NULL;
+ return RESPONSE_ERR;
+ }
+
+ if (strncmp(response, RESP_OK_STR, strlen(RESP_OK_STR)) == 0) {
+
+ if (response[strlen(RESP_OK_STR)] == ' ')
+ msg = response + strlen(RESP_OK_STR) + 1;
+ else
+ msg = response + strlen(RESP_OK_STR);
+
+ if (mmap_string_assign(f->pop3_response_buffer, msg))
+ f->pop3_response = f->pop3_response_buffer->str;
+ else
+ f->pop3_response = NULL;
+
+ return RESPONSE_OK;
+ }
+ else if (strncmp(response, RESP_ERR_STR, strlen(RESP_ERR_STR)) == 0) {
+
+ if (response[strlen(RESP_ERR_STR)] == ' ')
+ msg = response + strlen(RESP_ERR_STR) + 1;
+ else
+ msg = response + strlen(RESP_ERR_STR);
+
+ if (mmap_string_assign(f->pop3_response_buffer, msg))
+ f->pop3_response = f->pop3_response_buffer->str;
+ else
+ f->pop3_response = NULL;
+ }
+
+ f->pop3_response = NULL;
+ return RESPONSE_ERR;
+}
+
+
+
+
+
+
+
+static int read_list(mailpop3 * f, carray ** result)
+{
+ unsigned int index;
+ uint32_t size;
+ carray * msg_tab;
+ struct mailpop3_msg_info * msg;
+ char * line;
+
+ msg_tab = carray_new(128);
+ if (msg_tab == NULL)
+ goto err;
+
+ while (1) {
+ line = read_line(f);
+ if (line == NULL)
+ goto free_list;
+
+ if (mailstream_is_end_multiline(line))
+ break;
+
+ index = strtol(line, &line, 10);
+
+ if (!parse_space(&line))
+ continue;
+
+ size = strtol(line, &line, 10);
+
+ msg = mailpop3_msg_info_new(index, size, NULL);
+ if (msg == NULL)
+ goto free_list;
+
+ if (carray_count(msg_tab) < index) {
+ int r;
+
+ r = carray_set_size(msg_tab, index);
+ if (r == -1)
+ goto free_list;
+ }
+
+ carray_set(msg_tab, index - 1, msg);
+ }
+
+ * result = msg_tab;
+
+ return MAILPOP3_NO_ERROR;
+
+ free_list:
+ mailpop3_msg_info_tab_free(msg_tab);
+ err:
+ return MAILPOP3_ERROR_STREAM;
+}
+
+
+
+static int read_uidl(mailpop3 * f, carray * msg_tab)
+{
+ unsigned int index;
+ struct mailpop3_msg_info * msg;
+ char * line;
+
+ while (1) {
+ char * uidl;
+
+ line = read_line(f);
+ if (line == NULL)
+ goto err;
+
+ if (mailstream_is_end_multiline(line))
+ break;
+
+ index = strtol(line, &line, 10);
+
+ if (!parse_space(&line))
+ continue;
+
+ uidl = strdup(line);
+ if (uidl == NULL)
+ continue;
+
+ if (index > carray_count(msg_tab)) {
+ free(uidl);
+ continue;
+ }
+
+ msg = carray_get(msg_tab, index - 1);
+ if (msg == NULL) {
+ free(uidl);
+ continue;
+ }
+
+ msg->msg_uidl = uidl;
+ }
+
+ return MAILPOP3_NO_ERROR;
+
+ err:
+ return MAILPOP3_ERROR_STREAM;
+}
+
+
+
+static int read_capa_resp(mailpop3 * f, clist ** result)
+{
+ char * line;
+ int res;
+ clist * list;
+ int r;
+ char * name;
+ clist * param_list;
+
+ list = clist_new();
+ if (list == NULL) {
+ res = MAILPOP3_NO_ERROR;
+ goto err;
+ }
+
+ while (1) {
+ char * next_token;
+ char * param;
+ struct mailpop3_capa * capa;
+
+ line = read_line(f);
+ if (line == NULL) {
+ res = MAILPOP3_ERROR_STREAM;
+ goto free_list;
+ }
+
+ if (mailstream_is_end_multiline(line))
+ break;
+
+ next_token = cut_token(line);
+ name = strdup(line);
+ if (name == NULL) {
+ res = MAILPOP3_ERROR_MEMORY;
+ goto free_list;
+ }
+
+ param_list = clist_new();
+ if (param_list == NULL) {
+ res = MAILPOP3_ERROR_MEMORY;
+ goto free_capa_name;
+ }
+
+ while (next_token != NULL) {
+ line = next_token;
+ next_token = cut_token(line);
+ param = strdup(line);
+ if (param == NULL) {
+ res = MAILPOP3_ERROR_MEMORY;
+ goto free_param_list;
+ }
+ r = clist_append(param_list, param);
+ if (r < 0) {
+ free(param);
+ res = MAILPOP3_ERROR_MEMORY;
+ goto free_param_list;
+ }
+ }
+
+ capa = mailpop3_capa_new(name, param_list);
+ if (capa == NULL) {
+ res = MAILPOP3_ERROR_MEMORY;
+ goto free_param_list;
+ }
+
+ r = clist_append(list, capa);
+ if (r < 0) {
+ mailpop3_capa_free(capa);
+ res = MAILPOP3_ERROR_MEMORY;
+ goto free_list;
+ }
+ }
+
+ * result = list;
+
+ return MAILPOP3_NO_ERROR;
+
+ free_param_list:
+ clist_foreach(param_list, (clist_func) free, NULL);
+ clist_free(param_list);
+ free_capa_name:
+ free(name);
+ free_list:
+ clist_foreach(list, (clist_func) mailpop3_capa_free, NULL);
+ clist_free(list);
+ err:
+ return res;
+}
+
+
+
+static char * read_line(mailpop3 * f)
+{
+ return mailstream_read_line_remove_eol(f->pop3_stream, f->pop3_stream_buffer);
+}
+
+static char * read_multiline(mailpop3 * f, size_t size,
+ MMAPString * multiline_buffer)
+{
+ return mailstream_read_multiline(f->pop3_stream, size,
+ f->pop3_stream_buffer, multiline_buffer,
+ f->pop3_progr_rate, f->pop3_progr_fun);
+}
+
+static int send_command(mailpop3 * f, char * command)
+{
+ ssize_t r;
+
+ r = mailstream_write(f->pop3_stream, command, strlen(command));
+ if (r == -1)
+ return -1;
+
+ r = mailstream_flush(f->pop3_stream);
+ if (r == -1)
+ return -1;
+
+ return 0;
+}
diff --git a/libetpan/src/low-level/pop3/mailpop3.h b/libetpan/src/low-level/pop3/mailpop3.h
new file mode 100644
index 0000000..62275f8
--- a/dev/null
+++ b/libetpan/src/low-level/pop3/mailpop3.h
@@ -0,0 +1,101 @@
+/*
+ * 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$
+ */
+
+#ifndef MAILPOP3_H
+
+#define MAILPOP3_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <libetpan/mailpop3_types.h>
+
+#include <libetpan/mailpop3_helper.h>
+
+#include <libetpan/mailpop3_socket.h>
+#include <libetpan/mailpop3_ssl.h>
+
+#define POP3_STRING_SIZE 513
+
+mailpop3 * mailpop3_new(size_t pop3_progr_rate,
+ progress_function * pop3_progr_fun);
+
+void mailpop3_free(mailpop3 * f);
+
+int mailpop3_connect(mailpop3 * f, mailstream * s);
+
+int mailpop3_quit(mailpop3 * f);
+
+
+int mailpop3_apop(mailpop3 * f, const char * user, const char * password);
+
+int mailpop3_user(mailpop3 * f, const char * user);
+
+int mailpop3_pass(mailpop3 * f, const char * password);
+
+void mailpop3_list(mailpop3 * f, carray ** result);
+
+int mailpop3_retr(mailpop3 * f, unsigned int index, char ** result,
+ size_t * result_len);
+
+int mailpop3_top(mailpop3 * f, unsigned int index,
+ unsigned int count, char ** result,
+ size_t * result_len);
+
+int mailpop3_dele(mailpop3 * f, unsigned int index);
+
+int mailpop3_noop(mailpop3 * f);
+
+int mailpop3_rset(mailpop3 * f);
+
+void mailpop3_top_free(char * str);
+
+void mailpop3_retr_free(char * str);
+
+int mailpop3_get_msg_info(mailpop3 * f, unsigned int index,
+ struct mailpop3_msg_info ** result);
+
+int mailpop3_capa(mailpop3 * f, clist ** result);
+
+void mailpop3_capa_resp_free(clist * capa_list);
+
+int mailpop3_stls(mailpop3 * f);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libetpan/src/low-level/pop3/mailpop3_helper.c b/libetpan/src/low-level/pop3/mailpop3_helper.c
new file mode 100644
index 0000000..ada97b9
--- a/dev/null
+++ b/libetpan/src/low-level/pop3/mailpop3_helper.c
@@ -0,0 +1,78 @@
+/*
+ * 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 "mailpop3_helper.h"
+
+#include <string.h>
+
+int mailpop3_login_apop(mailpop3 * f,
+ char * user,
+ char * password)
+{
+ return mailpop3_apop(f, user, password);
+}
+
+
+/*
+ mailpop3_login
+
+ must be used immediately after connect
+*/
+
+int mailpop3_login(mailpop3 * f,
+ char * user,
+ char * password)
+{
+ int r;
+
+ if ((r = mailpop3_user(f, user)) != MAILPOP3_NO_ERROR)
+ return r;
+
+ if ((r = mailpop3_pass(f, password)) != MAILPOP3_NO_ERROR)
+ return r;
+
+ return MAILPOP3_NO_ERROR;
+}
+
+void mailpop3_header_free(char * str)
+{
+ mailpop3_top_free(str);
+}
+
+int mailpop3_header(mailpop3 * f, uint32_t index, char ** result,
+ size_t * result_len)
+{
+ return mailpop3_top(f, index, 0, result, result_len);
+}
diff --git a/libetpan/src/low-level/pop3/mailpop3_helper.h b/libetpan/src/low-level/pop3/mailpop3_helper.h
new file mode 100644
index 0000000..cec93da
--- a/dev/null
+++ b/libetpan/src/low-level/pop3/mailpop3_helper.h
@@ -0,0 +1,64 @@
+/*
+ * 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$
+ */
+
+#ifndef MAILPOP3_HELPER_H
+
+#define MAILPOP3_HELPER_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "mailpop3.h"
+
+int mailpop3_login_apop(mailpop3 * f,
+ char * user,
+ char * password);
+
+int mailpop3_login(mailpop3 * f,
+ char * user,
+ char * password);
+
+int mailpop3_header(mailpop3 * f, uint32_t index, char ** result,
+ size_t * result_len);
+
+void mailpop3_header_free(char * str);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/libetpan/src/low-level/pop3/mailpop3_socket.c b/libetpan/src/low-level/pop3/mailpop3_socket.c
new file mode 100644
index 0000000..5625f6e
--- a/dev/null
+++ b/libetpan/src/low-level/pop3/mailpop3_socket.c
@@ -0,0 +1,73 @@
+/*
+ * 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 "mailpop3_socket.h"
+
+#include "mailpop3.h"
+
+#include "connect.h"
+#include <netinet/in.h>
+#include <unistd.h>
+
+#define DEFAULT_POP3_PORT 110
+#define SERVICE_NAME_POP3 "pop3"
+#define SERVICE_TYPE_TCP "tcp"
+
+int mailpop3_socket_connect(mailpop3 * f, const char * server, uint16_t port)
+{
+ int s;
+ mailstream * stream;
+
+ if (port == 0) {
+ port = mail_get_service_port(SERVICE_NAME_POP3, SERVICE_TYPE_TCP);
+ if (port == 0)
+ port = DEFAULT_POP3_PORT;
+ port = ntohs(port);
+ }
+
+ /* Connection */
+
+ s = mail_tcp_connect(server, port);
+ if (s == -1)
+ return MAILPOP3_ERROR_CONNECTION_REFUSED;
+
+ stream = mailstream_socket_open(s);
+ if (stream == NULL) {
+ close(s);
+ return MAILPOP3_ERROR_MEMORY;
+ }
+
+ return mailpop3_connect(f, stream);
+}
diff --git a/libetpan/src/low-level/pop3/mailpop3_socket.h b/libetpan/src/low-level/pop3/mailpop3_socket.h
new file mode 100644
index 0000000..262b2ab
--- a/dev/null
+++ b/libetpan/src/low-level/pop3/mailpop3_socket.h
@@ -0,0 +1,54 @@
+/*
+ * 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$
+ */
+
+#ifndef MAILPOP3_SOCKET_H
+
+#define MAILPOP3_SOCKET_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <inttypes.h>
+
+#include <libetpan/mailpop3_types.h>
+
+int mailpop3_socket_connect(mailpop3 * f, const char * server, uint16_t port);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libetpan/src/low-level/pop3/mailpop3_ssl.c b/libetpan/src/low-level/pop3/mailpop3_ssl.c
new file mode 100644
index 0000000..fda6073
--- a/dev/null
+++ b/libetpan/src/low-level/pop3/mailpop3_ssl.c
@@ -0,0 +1,73 @@
+/*
+ * 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 "mailpop3_ssl.h"
+
+#include "mailpop3.h"
+
+#include "connect.h"
+#include <netinet/in.h>
+#include <unistd.h>
+
+#define DEFAULT_POP3S_PORT 995
+#define SERVICE_NAME_POP3S "pop3s"
+#define SERVICE_TYPE_TCP "tcp"
+
+int mailpop3_ssl_connect(mailpop3 * f, const char * server, uint16_t port)
+{
+ int s;
+ mailstream * stream;
+
+ if (port == 0) {
+ port = mail_get_service_port(SERVICE_NAME_POP3S, SERVICE_TYPE_TCP);
+ if (port == 0)
+ port = DEFAULT_POP3S_PORT;
+ port = ntohs(port);
+ }
+
+ /* Connection */
+
+ s = mail_tcp_connect(server, port);
+ if (s == -1)
+ return MAILPOP3_ERROR_CONNECTION_REFUSED;
+
+ stream = mailstream_ssl_open(s);
+ if (stream == NULL) {
+ close(s);
+ return MAILPOP3_ERROR_CONNECTION_REFUSED;
+ }
+
+ return mailpop3_connect(f, stream);
+}
diff --git a/libetpan/src/low-level/pop3/mailpop3_ssl.h b/libetpan/src/low-level/pop3/mailpop3_ssl.h
new file mode 100644
index 0000000..38e0769
--- a/dev/null
+++ b/libetpan/src/low-level/pop3/mailpop3_ssl.h
@@ -0,0 +1,54 @@
+/*
+ * 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$
+ */
+
+#ifndef MAILPOP3_SSL_H
+
+#define MAILPOP3_SSL_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <inttypes.h>
+
+#include <libetpan/mailpop3_types.h>
+
+int mailpop3_ssl_connect(mailpop3 * f, const char * server, uint16_t port);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libetpan/src/low-level/pop3/mailpop3_types.h b/libetpan/src/low-level/pop3/mailpop3_types.h
new file mode 100644
index 0000000..18a68bc
--- a/dev/null
+++ b/libetpan/src/low-level/pop3/mailpop3_types.h
@@ -0,0 +1,107 @@
+/*
+ * 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$
+ */
+
+#ifndef MAILPOP3_TYPES_H
+
+#define MAILPOP3_TYPES_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <libetpan/mailstream.h>
+#include <libetpan/mmapstring.h>
+#include <libetpan/carray.h>
+#include <libetpan/clist.h>
+
+#include <inttypes.h>
+
+enum {
+ MAILPOP3_NO_ERROR = 0,
+ MAILPOP3_ERROR_BAD_STATE,
+ MAILPOP3_ERROR_UNAUTHORIZED,
+ MAILPOP3_ERROR_STREAM,
+ MAILPOP3_ERROR_DENIED,
+ MAILPOP3_ERROR_BAD_USER,
+ MAILPOP3_ERROR_BAD_PASSWORD,
+ MAILPOP3_ERROR_CANT_LIST,
+ MAILPOP3_ERROR_NO_SUCH_MESSAGE,
+ MAILPOP3_ERROR_MEMORY,
+ MAILPOP3_ERROR_CONNECTION_REFUSED,
+ MAILPOP3_ERROR_APOP_NOT_SUPPORTED,
+ MAILPOP3_ERROR_CAPA_NOT_SUPPORTED,
+ MAILPOP3_ERROR_STLS_NOT_SUPPORTED,
+};
+
+struct mailpop3
+{
+ char * pop3_response; /* response message */
+ char * pop3_timestamp; /* connection timestamp */
+
+ /* internals */
+ mailstream * pop3_stream;
+ size_t pop3_progr_rate;
+ progress_function * pop3_progr_fun;
+
+ MMAPString * pop3_stream_buffer; /* buffer for lines reading */
+ MMAPString * pop3_response_buffer; /* buffer for responses */
+
+ carray * pop3_msg_tab; /* list of pop3_msg_info structures */
+ int pop3_state; /* state */
+
+ unsigned int pop3_deleted_count;
+};
+
+typedef struct mailpop3 mailpop3;
+
+struct mailpop3_msg_info
+{
+ unsigned int msg_index;
+ uint32_t msg_size;
+ char * msg_uidl;
+ int msg_deleted;
+};
+
+
+struct mailpop3_capa {
+ char * cap_name;
+ clist * cap_param; /* (char *) */
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libetpan/src/low-level/smtp/TODO b/libetpan/src/low-level/smtp/TODO
new file mode 100644
index 0000000..96f44c6
--- a/dev/null
+++ b/libetpan/src/low-level/smtp/TODO
@@ -0,0 +1 @@
+- STARTTLS
diff --git a/libetpan/src/low-level/smtp/mailsmtp.c b/libetpan/src/low-level/smtp/mailsmtp.c
new file mode 100644
index 0000000..85659e9
--- a/dev/null
+++ b/libetpan/src/low-level/smtp/mailsmtp.c
@@ -0,0 +1,984 @@
+/*
+ * libEtPan! -- a mail stuff library
+ *
+ * Copyright (C) 2001, 2005 - DINH Viet Hoa,
+ * All rights reserved.
+ *
+ * SMTP AUTH support by Juergen Graf
+ *
+ * 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 "mailsmtp.h"
+#include "connect.h"
+#include "md5.h"
+#include "base64.h"
+#include "mail.h"
+
+#include <netinet/in.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+
+
+/*
+ RFC 2821 : SMTP
+ RFC 1891 : SMTP Service Extension for Delivery Status Notifications
+
+ RFC 1428 : Transition of Internet Mail from Just-Send-8 to 8bit-SMTP/MIME
+ RFC 1652 : SMTP Service Extension for 8bit-MIMEtransport
+ RFC 1845 : SMTP Service Extension for Checkpoint/Restart
+ RFC 1846 : SMTP 521 Reply Code
+ RFC 1870 : SMTP Service Extension for Message Size Declaration
+ RFC 1985 : SMTP Service Extension for Remote Message Queue Starting
+ RFC 2034 : SMTP Service Extension for Returning Enhanced Error Codes
+ RFC 2442 : The Batch SMTP Media Type
+ RFC 2487 : SMTP Service Extension for Secure SMTP over TLS
+ RFC 2505 : Anti-Spam Recommendations for SMTP MTAs
+ RFC 2554 : SMTP Service Extension for Authentication
+ RFC 2645 : ON-DEMAND MAIL RELAY (ODMR) SMTP with Dynamic IP Addresses
+ RFC 2852 : Deliver By SMTP Service Extension
+ RFC 2920 : SMTP Service Extension for Command Pipelining
+ RFC 3030 : SMTP Service Extensions for Transmission of Large and Binary MIME
+ Messages
+*/
+
+#define SMTP_STATUS_CONTINUE 0x1000
+
+mailsmtp * mailsmtp_new(size_t progr_rate,
+ progress_function * progr_fun)
+{
+ mailsmtp * session;
+
+ session = malloc(sizeof(* session));
+ if (session == NULL)
+ goto err;
+
+ session->stream = NULL;
+
+ session->progr_rate = progr_rate;
+ session->progr_fun = progr_fun;
+
+ session->response = NULL;
+
+ session->line_buffer = mmap_string_new("");
+ if (session->line_buffer == NULL)
+ goto free_session;
+
+ session->response_buffer = mmap_string_new("");
+ if (session->response_buffer == NULL)
+ goto free_line_buffer;
+
+ session->esmtp = 0;
+ session->auth = MAILSMTP_AUTH_NOT_CHECKED;
+
+ return session;
+
+ free_line_buffer:
+ mmap_string_free(session->line_buffer);
+ free_session:
+ free(session);
+ err:
+ return NULL;
+}
+
+void mailsmtp_free(mailsmtp * session)
+{
+ if (session->stream)
+ mailsmtp_quit(session);
+
+ mmap_string_free(session->line_buffer);
+ mmap_string_free(session->response_buffer);
+ free(session);
+}
+
+static int send_command(mailsmtp * f, char * command);
+
+static int read_response(mailsmtp * session);
+
+/* smtp operations */
+
+int mailsmtp_connect(mailsmtp * session, mailstream * s)
+{
+ int code;
+
+ session->stream = s;
+
+ code = read_response(session);
+
+ switch (code) {
+ case 220:
+ return MAILSMTP_NO_ERROR;
+
+ case 554:
+ session->stream = NULL;
+ mailstream_close(s);
+ return MAILSMTP_ERROR_SERVICE_NOT_AVAILABLE;
+
+ default:
+ session->stream = NULL;
+ mailstream_close(s);
+ return MAILSMTP_ERROR_UNEXPECTED_CODE;
+ }
+}
+
+
+#define SMTP_STRING_SIZE 513
+
+int mailsmtp_quit(mailsmtp * session)
+{
+ char command[SMTP_STRING_SIZE];
+ int r;
+
+ snprintf(command, SMTP_STRING_SIZE, "QUIT\r\n");
+ r = send_command(session, command);
+ if (r == -1)
+ return MAILSMTP_ERROR_STREAM;
+ r = read_response(session);
+ if (r == 0)
+ return MAILSMTP_ERROR_STREAM;
+ mailstream_close(session->stream);
+ session->stream = NULL;
+
+ return MAILSMTP_NO_ERROR;
+}
+
+
+
+#define HOSTNAME_SIZE 256
+
+int mailsmtp_helo(mailsmtp * session)
+{
+ int r;
+ char hostname[HOSTNAME_SIZE];
+ char command[SMTP_STRING_SIZE];
+
+ r = gethostname(hostname, HOSTNAME_SIZE);
+ if (r < 0)
+ return MAILSMTP_ERROR_HOSTNAME;
+
+ snprintf(command, SMTP_STRING_SIZE, "HELO %s\r\n", hostname);
+ r = send_command(session, command);
+ if (r == -1)
+ return MAILSMTP_ERROR_STREAM;
+ r = read_response(session);
+
+ switch (r) {
+ case 250:
+ session->esmtp = 0;
+ session->auth = MAILSMTP_AUTH_NOT_CHECKED;
+ return MAILSMTP_NO_ERROR;
+
+ case 504:
+ return MAILSMTP_ERROR_NOT_IMPLEMENTED;
+
+ case 550:
+ return MAILSMTP_ERROR_ACTION_NOT_TAKEN;
+
+ case 0:
+ return MAILSMTP_ERROR_STREAM;
+
+ default:
+ return MAILSMTP_ERROR_UNEXPECTED_CODE;
+ }
+}
+
+int mailsmtp_mail(mailsmtp * session, const char * from)
+{
+ int r;
+ char command[SMTP_STRING_SIZE];
+
+ snprintf(command, SMTP_STRING_SIZE, "MAIL FROM:<%s>\r\n", from);
+ r = send_command(session, command);
+ if (r == -1)
+ return MAILSMTP_ERROR_STREAM;
+ r = read_response(session);
+
+ switch (r) {
+ case 250:
+ return MAILSMTP_NO_ERROR;
+
+ case 552:
+ return MAILSMTP_ERROR_EXCEED_STORAGE_ALLOCATION;
+
+ case 451:
+ return MAILSMTP_ERROR_IN_PROCESSING;
+
+ case 452:
+ return MAILSMTP_ERROR_INSUFFICIENT_SYSTEM_STORAGE;
+
+ case 550:
+ return MAILSMTP_ERROR_MAILBOX_UNAVAILABLE;
+
+ case 553:
+ return MAILSMTP_ERROR_MAILBOX_NAME_NOT_ALLOWED;
+
+ case 503:
+ return MAILSMTP_ERROR_BAD_SEQUENCE_OF_COMMAND;
+
+ case 0:
+ return MAILSMTP_ERROR_STREAM;
+
+ default:
+ return MAILSMTP_ERROR_UNEXPECTED_CODE;
+ }
+}
+
+int mailsmtp_rcpt(mailsmtp * session, const char * to)
+{
+ return mailesmtp_rcpt(session, to, 0, NULL);
+}
+
+int mailsmtp_data(mailsmtp * session)
+{
+ int r;
+ char command[SMTP_STRING_SIZE];
+
+ snprintf(command, SMTP_STRING_SIZE, "DATA\r\n");
+ r = send_command(session, command);
+ if (r == -1)
+ return MAILSMTP_ERROR_STREAM;
+ r = read_response(session);
+
+ switch (r) {
+ case 354:
+ return MAILSMTP_NO_ERROR;
+
+ case 451:
+ return MAILSMTP_ERROR_IN_PROCESSING;
+
+ case 554:
+ return MAILSMTP_ERROR_TRANSACTION_FAILED;
+
+ case 503:
+ return MAILSMTP_ERROR_BAD_SEQUENCE_OF_COMMAND;
+
+ default:
+ return MAILSMTP_ERROR_UNEXPECTED_CODE;
+ }
+}
+
+static int send_data(mailsmtp * session, const char * message, size_t size);
+
+int mailsmtp_data_message(mailsmtp * session,
+ const char * message,
+ size_t size)
+{
+ int r;
+
+ r = send_data(session, message, size);
+ if (r == -1)
+ return MAILSMTP_ERROR_STREAM;
+
+ r = read_response(session);
+
+ switch(r) {
+ case 250:
+ return MAILSMTP_NO_ERROR;
+
+ case 552:
+ return MAILSMTP_ERROR_EXCEED_STORAGE_ALLOCATION;
+
+ case 554:
+ return MAILSMTP_ERROR_TRANSACTION_FAILED;
+
+ case 451:
+ return MAILSMTP_ERROR_IN_PROCESSING;
+
+ case 452:
+ return MAILSMTP_ERROR_INSUFFICIENT_SYSTEM_STORAGE;
+
+ case 0:
+ return MAILSMTP_ERROR_STREAM;
+
+ default:
+ return MAILSMTP_ERROR_UNEXPECTED_CODE;
+ }
+}
+
+/* esmtp operations */
+
+
+/**
+ * called during mailesmtp_ehlo
+ * checks EHLO answer for server extensions and sets flags
+ * in session->esmtp
+ * checks AUTH methods in session->response and sets flags
+ * in session->auth
+ */
+#define isdelim(x) ((x) == ' ' || (x) == '\r' || (x) == '\n' || (x) == '\0')
+
+int mailesmtp_parse_ehlo(mailsmtp * session)
+{
+ char * response;
+
+ /* restore data */
+ session->esmtp = MAILSMTP_ESMTP;
+ session->auth = MAILSMTP_AUTH_CHECKED;
+
+ response = session->response;
+
+ /* ESMTP supported extensions :
+ DSN
+ EXPN
+ 8BITMIME
+ SIZE [<n>]
+ ETRN
+ STARTTLS
+ AUTH <mechanisms...>
+ */
+ while (response != NULL) {
+ if (!strncasecmp(response, "EXPN", 4) && isdelim(response[4]))
+ session->esmtp |= MAILSMTP_ESMTP_EXPN;
+ else if (!strncasecmp(response, "ETRN", 4) && isdelim(response[4]))
+ session->esmtp |= MAILSMTP_ESMTP_ETRN;
+ else if (!strncasecmp(response, "DSN", 3) && isdelim(response[3]))
+ session->esmtp |= MAILSMTP_ESMTP_DSN;
+ else if (!strncasecmp(response, "8BITMIME", 8) && isdelim(response[8]))
+ session->esmtp |= MAILSMTP_ESMTP_8BITMIME;
+ else if (!strncasecmp(response, "STARTTLS", 8) && isdelim(response[8]))
+ session->esmtp |= MAILSMTP_ESMTP_STARTTLS;
+ else if (!strncasecmp(response, "SIZE", 4) && isdelim(response[4])) {
+ session->esmtp |= MAILSMTP_ESMTP_SIZE;
+ /* TODO: grab optionnal max size */
+ } else if (!strncasecmp(response, "AUTH ", 5)) {
+ response += 5; /* remove "AUTH " */
+ while (response[0] != '\n' && response[0] != '\0') {
+ while (response[0] == ' ') response++;
+ if (strncasecmp(response, "LOGIN", 5) == 0) {
+ session->auth |= MAILSMTP_AUTH_LOGIN;
+ response += 5;
+ } else if (strncasecmp(response, "CRAM-MD5", 8) == 0) {
+ session->auth |= MAILSMTP_AUTH_CRAM_MD5;
+ response += 8;
+ } else if (strncasecmp(response, "PLAIN", 5) == 0) {
+ session->auth |= MAILSMTP_AUTH_PLAIN;
+ response += 5;
+ } else {
+ /* unknown auth method - jump to next word or eol */
+ while (!isdelim(response[0]) || response[0] == '\r')
+ response++;
+ }
+ }
+ }
+ response = strpbrk(response, "\n");
+ if (response != NULL)
+ response++;
+ }
+
+ return MAILSMTP_NO_ERROR;
+}
+
+
+int mailesmtp_ehlo(mailsmtp * session)
+{
+ int r;
+ char hostname[HOSTNAME_SIZE];
+ char command[SMTP_STRING_SIZE];
+
+ r = gethostname(hostname, HOSTNAME_SIZE);
+ if (r != 0)
+ return MAILSMTP_ERROR_HOSTNAME;
+
+ snprintf(command, SMTP_STRING_SIZE, "EHLO %s\r\n", hostname);
+ r = send_command(session, command);
+ if (r == -1)
+ return MAILSMTP_ERROR_STREAM;
+ r = read_response(session);
+
+ switch (r) {
+ case 250:
+ return mailesmtp_parse_ehlo(session);
+
+ case 504:
+ return MAILSMTP_ERROR_NOT_IMPLEMENTED;
+
+ case 550:
+ return MAILSMTP_ERROR_ACTION_NOT_TAKEN;
+
+ case 0:
+ return MAILSMTP_ERROR_STREAM;
+
+ default:
+ return MAILSMTP_ERROR_UNEXPECTED_CODE;
+ }
+}
+
+/*
+ if return_full is TRUE, the entire message is returned on error
+ envid can be NULL
+*/
+
+
+int mailesmtp_mail(mailsmtp * session,
+ const char * from,
+ int return_full,
+ const char * envid)
+{
+ int r;
+ char command[SMTP_STRING_SIZE];
+ char *body = "";
+
+#if notyet
+ /* TODO: figure out a way for the user to explicity enable this or not */
+ if (session->esmtp & MAILSMTP_ESMTP_8BITMIME)
+ body = " BODY=8BITMIME";
+#endif
+
+ if (session->esmtp & MAILSMTP_ESMTP_DSN) {
+ if (envid)
+ snprintf(command, SMTP_STRING_SIZE, "MAIL FROM:<%s> RET=%s ENVID=%s%s\r\n",
+ from, return_full ? "FULL" : "HDRS", envid, body);
+ else
+ snprintf(command, SMTP_STRING_SIZE, "MAIL FROM:<%s> RET=%s%s\r\n",
+ from, return_full ? "FULL" : "HDRS", body);
+ } else
+ snprintf(command, SMTP_STRING_SIZE, "MAIL FROM:<%s>%s\r\n",
+ from, body);
+
+ r = send_command(session, command);
+ if (r == -1)
+ return MAILSMTP_ERROR_STREAM;
+ r = read_response(session);
+
+ switch (r) {
+ case 250:
+ return MAILSMTP_NO_ERROR;
+
+ case 552:
+ return MAILSMTP_ERROR_EXCEED_STORAGE_ALLOCATION;
+
+ case 451:
+ return MAILSMTP_ERROR_IN_PROCESSING;
+
+ case 452:
+ return MAILSMTP_ERROR_INSUFFICIENT_SYSTEM_STORAGE;
+
+ case 550:
+ return MAILSMTP_ERROR_MAILBOX_UNAVAILABLE;
+
+ case 553:
+ return MAILSMTP_ERROR_MAILBOX_NAME_NOT_ALLOWED;
+
+ case 503:
+ return MAILSMTP_ERROR_BAD_SEQUENCE_OF_COMMAND;
+
+ case 0:
+ return MAILSMTP_ERROR_STREAM;
+
+ default:
+ return MAILSMTP_ERROR_UNEXPECTED_CODE;
+ }
+}
+
+int mailesmtp_rcpt(mailsmtp * session,
+ const char * to,
+ int notify,
+ const char * orcpt)
+{
+ int r;
+ char command[SMTP_STRING_SIZE];
+ char notify_str[30] = "";
+ char notify_info_str[30] = "";
+
+ if (notify != 0 && session->esmtp & MAILSMTP_ESMTP_DSN) {
+ if (notify & MAILSMTP_DSN_NOTIFY_SUCCESS)
+ strcat(notify_info_str, ",SUCCESS");
+ if (notify & MAILSMTP_DSN_NOTIFY_FAILURE)
+ strcat(notify_info_str, ",FAILURE");
+ if (notify & MAILSMTP_DSN_NOTIFY_DELAY)
+ strcat(notify_info_str, ",DELAY");
+
+ if (notify & MAILSMTP_DSN_NOTIFY_NEVER)
+ strcpy(notify_info_str, ",NEVER");
+
+ notify_info_str[0] = '=';
+
+ strcpy(notify_str, " NOTIFY");
+ strcat(notify_str, notify_info_str);
+ }
+
+ if (orcpt && session->esmtp & MAILSMTP_ESMTP_DSN)
+ snprintf(command, SMTP_STRING_SIZE, "RCPT TO:<%s>%s ORCPT=%s\r\n",
+ to, notify_str, orcpt);
+ else
+ snprintf(command, SMTP_STRING_SIZE, "RCPT TO:<%s>%s\r\n", to, notify_str);
+
+ r = send_command(session, command);
+ if (r == -1)
+ return MAILSMTP_ERROR_STREAM;
+ r = read_response(session);
+
+ switch (r) {
+ case 250:
+ return MAILSMTP_NO_ERROR;
+
+ case 251: /* not local user, will be forwarded */
+ return MAILSMTP_NO_ERROR;
+
+ case 550:
+ case 450:
+ return MAILSMTP_ERROR_MAILBOX_UNAVAILABLE;
+
+ case 551:
+ return MAILSMTP_ERROR_USER_NOT_LOCAL;
+
+ case 552:
+ return MAILSMTP_ERROR_EXCEED_STORAGE_ALLOCATION;
+
+ case 553:
+ return MAILSMTP_ERROR_MAILBOX_NAME_NOT_ALLOWED;
+
+ case 451:
+ return MAILSMTP_ERROR_IN_PROCESSING;
+
+ case 452:
+ return MAILSMTP_ERROR_INSUFFICIENT_SYSTEM_STORAGE;
+
+ case 503:
+ return MAILSMTP_ERROR_BAD_SEQUENCE_OF_COMMAND;
+
+ case 0:
+ return MAILSMTP_ERROR_STREAM;
+
+ default:
+ return MAILSMTP_ERROR_UNEXPECTED_CODE;
+ }
+}
+
+int auth_map_errors(int err)
+{
+ switch (err) {
+ case 235:
+ return MAILSMTP_NO_ERROR; /* AUTH successfull */
+ case 334:
+ return MAILSMTP_NO_ERROR; /* AUTH in progress */
+ case 432:
+ return MAILSMTP_ERROR_AUTH_TRANSITION_NEEDED;
+ case 454:
+ return MAILSMTP_ERROR_AUTH_TEMPORARY_FAILTURE;
+ case 504:
+ return MAILSMTP_ERROR_AUTH_NOT_SUPPORTED;
+ case 530:
+ return MAILSMTP_ERROR_AUTH_REQUIRED;
+ case 534:
+ return MAILSMTP_ERROR_AUTH_TOO_WEAK;
+ case 538:
+ return MAILSMTP_ERROR_AUTH_ENCRYPTION_REQUIRED;
+ default:
+ /* opportunistic approach ;) */
+ return MAILSMTP_NO_ERROR;
+ }
+}
+
+static int mailsmtp_auth_login(mailsmtp * session,
+ const char * user, const char * pass)
+{
+ int err;
+ char command[SMTP_STRING_SIZE];
+ char * user64, * pass64;
+
+ user64 = NULL;
+ pass64 = NULL;
+
+ user64 = encode_base64(user, strlen(user));
+ if (user64 == NULL) {
+ err = MAILSMTP_ERROR_MEMORY;
+ goto err_free;
+ }
+
+ pass64 = encode_base64(pass, strlen(pass));
+ if (pass64 == NULL) {
+ err = MAILSMTP_ERROR_MEMORY;
+ goto err_free;
+ }
+
+ snprintf(command, SMTP_STRING_SIZE, "%s\r\n", user64);
+ err = send_command(session, command);
+ if (err == -1) {
+ err = MAILSMTP_ERROR_STREAM;
+ goto err_free;
+ }
+ err = read_response(session);
+ err = auth_map_errors(err);
+ if (err != MAILSMTP_NO_ERROR)
+ goto err_free;
+
+ snprintf(command, SMTP_STRING_SIZE, "%s\r\n", pass64);
+ err = send_command(session, command);
+ if (err == -1) {
+ err = MAILSMTP_ERROR_STREAM;
+ goto err_free;
+ }
+ err = read_response(session);
+ err = auth_map_errors(err);
+
+ err_free:
+ free(user64);
+ free(pass64);
+
+ return err;
+}
+
+static int mailsmtp_auth_plain(mailsmtp * session,
+ const char * user, const char * pass)
+{
+ int err, len;
+ char command[SMTP_STRING_SIZE];
+ char * plain, * plain64;
+
+ len = strlen(user) + strlen(pass) + 3;
+ plain = (char *) malloc(len);
+ if (plain == NULL) {
+ err = MAILSMTP_ERROR_MEMORY;
+ goto err;
+ }
+
+ snprintf(plain, len, "%c%s%c%s", '\0', user, '\0', pass);
+ plain64 = encode_base64(plain, len - 1);
+
+ snprintf(command, SMTP_STRING_SIZE, "%s\r\n", plain64);
+ err = send_command(session, command);
+ if (err == -1) {
+ err = MAILSMTP_ERROR_STREAM;
+ goto err_free;
+ }
+
+ err = read_response(session);
+ err = auth_map_errors(err);
+
+err_free:
+ free(plain64);
+ free(plain);
+
+ err:
+ return err;
+}
+
+static char * convert_hex(unsigned char *in, int len)
+{
+ static char hex[] = "0123456789abcdef";
+ char * out;
+ int i;
+
+ out = (char *) malloc(len * 2 + 1);
+ if (out == NULL)
+ return NULL;
+
+ for (i = 0; i < len; i++) {
+ out[i * 2] = hex[in[i] >> 4];
+ out[i * 2 + 1] = hex[in[i] & 15];
+ }
+
+ out[i*2] = 0;
+
+ return out;
+}
+
+static char * hash_md5(const char * sec_key, const char * data, int len)
+{
+ char key[65], digest[24];
+ char * hash_hex;
+
+ int sec_len, i;
+
+ sec_len = strlen(sec_key);
+
+ if (sec_len < 64) {
+ memcpy(key, sec_key, sec_len);
+ for (i = sec_len; i < 64; i++) {
+ key[i] = 0;
+ }
+ } else {
+ memcpy(key, sec_key, 64);
+ }
+
+ hmac_md5(data, len, key, 64, digest);
+ hash_hex = convert_hex(digest, 16);
+
+ return hash_hex;
+}
+
+static int mailsmtp_auth_cram_md5(mailsmtp * session,
+ const char * user, const char * pass)
+{
+ int err;
+ char command[SMTP_STRING_SIZE];
+ char *response, *auth_hex, *auth;
+
+ response = decode_base64(session->response, strlen(session->response));
+ if (response == NULL) return MAILSMTP_ERROR_MEMORY;
+
+ auth_hex = hash_md5(pass, response, strlen(response));
+ if (auth_hex == NULL) {
+ err = MAILSMTP_ERROR_MEMORY;
+ goto err_free_response;
+ }
+
+ snprintf(command, SMTP_STRING_SIZE, "%s %s", user, auth_hex);
+
+ auth = encode_base64(command, strlen(command));
+ if (auth == NULL) {
+ err = MAILSMTP_ERROR_MEMORY;
+ goto err_free_auth_hex;
+ }
+
+ snprintf(command, SMTP_STRING_SIZE, "%s\r\n", auth);
+ err = send_command(session, command);
+ if (err == -1) {
+ err = MAILSMTP_ERROR_STREAM;
+ goto err_free;
+ }
+
+ err = read_response(session);
+ err = auth_map_errors(err);
+
+err_free:
+ free(auth);
+err_free_auth_hex:
+ free(auth_hex);
+err_free_response:
+ free(response);
+ return err;
+}
+
+int mailsmtp_auth_type(mailsmtp * session,
+ const char * user, const char * pass, int type)
+{
+ int err;
+ char command[SMTP_STRING_SIZE];
+
+ if (session->auth == MAILSMTP_AUTH_NOT_CHECKED)
+ return MAILSMTP_ERROR_BAD_SEQUENCE_OF_COMMAND;
+
+ if ( !(session->auth & type) ) return MAILSMTP_ERROR_AUTH_NOT_SUPPORTED;
+
+ switch (type) {
+ case MAILSMTP_AUTH_LOGIN:
+ snprintf(command, SMTP_STRING_SIZE, "AUTH LOGIN\r\n");
+ break;
+ case MAILSMTP_AUTH_PLAIN:
+ snprintf(command, SMTP_STRING_SIZE, "AUTH PLAIN\r\n");
+ break;
+ case MAILSMTP_AUTH_CRAM_MD5:
+ snprintf(command, SMTP_STRING_SIZE, "AUTH CRAM-MD5\r\n");
+ break;
+ default:
+ return MAILSMTP_ERROR_NOT_IMPLEMENTED;
+ }
+
+ err = send_command(session, command);
+ if (err == -1) return MAILSMTP_ERROR_STREAM;
+
+ err = read_response(session);
+ err = auth_map_errors(err);
+ if (err != MAILSMTP_NO_ERROR) return err;
+
+ switch (type) {
+ case MAILSMTP_AUTH_LOGIN:
+ return mailsmtp_auth_login(session, user, pass);
+ case MAILSMTP_AUTH_PLAIN:
+ return mailsmtp_auth_plain(session, user, pass);
+ case MAILSMTP_AUTH_CRAM_MD5:
+ return mailsmtp_auth_cram_md5(session, user, pass);
+ default:
+ return MAILSMTP_ERROR_NOT_IMPLEMENTED;
+ }
+}
+
+
+int mailsmtp_auth(mailsmtp * session, const char * user, const char * pass)
+{
+ if (session->auth == MAILSMTP_AUTH_NOT_CHECKED)
+ return MAILSMTP_ERROR_BAD_SEQUENCE_OF_COMMAND;
+
+ if (session->auth & MAILSMTP_AUTH_CRAM_MD5) {
+ return mailsmtp_auth_type(session, user, pass, MAILSMTP_AUTH_CRAM_MD5);
+ } else if (session->auth & MAILSMTP_AUTH_PLAIN) {
+ return mailsmtp_auth_type(session, user, pass, MAILSMTP_AUTH_PLAIN);
+ } else if (session->auth & MAILSMTP_AUTH_LOGIN) {
+ return mailsmtp_auth_type(session, user, pass, MAILSMTP_AUTH_LOGIN);
+ } else {
+ return MAILSMTP_ERROR_AUTH_NOT_SUPPORTED;
+ }
+}
+
+/* TODO: add mailesmtp_etrn, mailssmtp_expn */
+
+int mailesmtp_starttls(mailsmtp * session) {
+ int r;
+
+ if (!(session->esmtp & MAILSMTP_ESMTP_STARTTLS))
+ return MAILSMTP_ERROR_STARTTLS_NOT_SUPPORTED;
+
+ r = send_command(session, "STARTTLS\r\n");
+ if (r == -1)
+ return MAILSMTP_ERROR_STREAM;
+ r = read_response(session);
+
+ switch (r) {
+ case 220:
+ return MAILSMTP_NO_ERROR;
+
+ case 454:
+ return MAILSMTP_ERROR_STARTTLS_TEMPORARY_FAILURE;
+
+ default:
+ return MAILSMTP_ERROR_UNEXPECTED_CODE;
+ }
+}
+
+static int parse_response(mailsmtp * session,
+ char * response)
+{
+ char * message;
+ int code;
+ int cont = 0;
+
+ code = strtol(response, &message, 10);
+ if (* message == ' ')
+ mmap_string_append(session->response_buffer, message + 1);
+ else if (* message == '-') {
+ cont = SMTP_STATUS_CONTINUE;
+ mmap_string_append(session->response_buffer, message + 1);
+ }
+ else
+ mmap_string_append(session->response_buffer, message);
+
+ return code | cont;
+}
+
+static char * read_line(mailsmtp * session)
+{
+ return mailstream_read_line_remove_eol(session->stream,
+ session->line_buffer);
+}
+
+static int read_response(mailsmtp * session)
+{
+ char * line;
+ int code;
+
+ mmap_string_assign(session->response_buffer, "");
+
+ do {
+ line = read_line(session);
+
+ if (line != NULL) {
+ code = parse_response(session, line);
+ mmap_string_append_c(session->response_buffer, '\n');
+ }
+ else
+ code = 0;
+ }
+ while ((code & SMTP_STATUS_CONTINUE) != 0);
+
+ session->response = session->response_buffer->str;
+
+ return code;
+}
+
+
+
+
+
+static int send_command(mailsmtp * f, char * command)
+{
+ ssize_t r;
+
+ r = mailstream_write(f->stream, command, strlen(command));
+ if (r == -1)
+ return -1;
+
+ r = mailstream_flush(f->stream);
+ if (r == -1)
+ return -1;
+
+ return 0;
+}
+
+static int send_data(mailsmtp * session, const char * message, size_t size)
+{
+ if (mailstream_send_data(session->stream, message, size,
+ session->progr_rate, session->progr_fun) == -1)
+ return -1;
+
+ if (mailstream_flush(session->stream) == -1)
+ return -1;
+
+ return 0;
+}
+
+
+const char * mailsmtp_strerror(int errnum)
+{
+ switch (errnum) {
+ case MAILSMTP_NO_ERROR:
+ return "No error";
+ case MAILSMTP_ERROR_UNEXPECTED_CODE:
+ return "Unexpected error code";
+ case MAILSMTP_ERROR_SERVICE_NOT_AVAILABLE:
+ return "Service not available";
+ case MAILSMTP_ERROR_STREAM:
+ return "Stream error";
+ case MAILSMTP_ERROR_HOSTNAME:
+ return "gethostname() failed";
+ case MAILSMTP_ERROR_NOT_IMPLEMENTED:
+ return "Not implemented";
+ case MAILSMTP_ERROR_ACTION_NOT_TAKEN:
+ return "Error, action not taken";
+ case MAILSMTP_ERROR_EXCEED_STORAGE_ALLOCATION:
+ return "Data exceeds storage allocation";
+ case MAILSMTP_ERROR_IN_PROCESSING:
+ return "Error in processing";
+ case MAILSMTP_ERROR_INSUFFICIENT_SYSTEM_STORAGE:
+ return "Insufficient system storage";
+ case MAILSMTP_ERROR_MAILBOX_UNAVAILABLE:
+ return "Mailbox unavailable";
+ case MAILSMTP_ERROR_MAILBOX_NAME_NOT_ALLOWED:
+ return "Mailbox name not allowed";
+ case MAILSMTP_ERROR_BAD_SEQUENCE_OF_COMMAND:
+ return "Bad command sequence";
+ case MAILSMTP_ERROR_USER_NOT_LOCAL:
+ return "User not local";
+ case MAILSMTP_ERROR_TRANSACTION_FAILED:
+ return "Transaction failed";
+ case MAILSMTP_ERROR_MEMORY:
+ return "Memory error";
+ case MAILSMTP_ERROR_CONNECTION_REFUSED:
+ return "Connection refused";
+ case MAILSMTP_ERROR_STARTTLS_TEMPORARY_FAILURE:
+ return "TLS not available on server for temporary reason";
+ case MAILSMTP_ERROR_STARTTLS_NOT_SUPPORTED:
+ return "TLS not supported by server";
+ default:
+ return "Unknown error code";
+ }
+}
diff --git a/libetpan/src/low-level/smtp/mailsmtp.h b/libetpan/src/low-level/smtp/mailsmtp.h
new file mode 100644
index 0000000..72e1786
--- a/dev/null
+++ b/libetpan/src/low-level/smtp/mailsmtp.h
@@ -0,0 +1,94 @@
+/*
+ * 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$
+ */
+
+#ifndef MAILSMTP_H
+
+#define MAILSMTP_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <libetpan/mailsmtp_types.h>
+#include <libetpan/mailsmtp_helper.h>
+#include <libetpan/mailsmtp_socket.h>
+#include <libetpan/mailsmtp_ssl.h>
+
+
+mailsmtp * mailsmtp_new(size_t progr_rate,
+ progress_function * progr_fun);
+void mailsmtp_free(mailsmtp * session);
+
+int mailsmtp_connect(mailsmtp * session, mailstream * s);
+int mailsmtp_quit(mailsmtp * session);
+
+/**
+ * Tries AUTH with detected method - "better" method first:
+ * CRAM-MD5 -> PLAIN -> LOGIN
+ */
+int mailsmtp_auth(mailsmtp * session, const char * user, const char * pass);
+
+/**
+ * tries to autenticate with the server using given auth-type
+ * returns MAILSMTP_NO_ERROR on success
+ */
+int mailsmtp_auth_type(mailsmtp * session,
+ const char * user, const char * pass, int type);
+
+int mailsmtp_helo(mailsmtp * session);
+int mailsmtp_mail(mailsmtp * session, const char * from);
+int mailsmtp_rcpt(mailsmtp * session, const char * to);
+int mailsmtp_data(mailsmtp * session);
+int mailsmtp_data_message(mailsmtp * session,
+ const char * message,
+ size_t size);
+int mailesmtp_ehlo(mailsmtp * session);
+int mailesmtp_mail(mailsmtp * session,
+ const char * from,
+ int return_full,
+ const char * envid);
+int mailesmtp_rcpt(mailsmtp * session,
+ const char * to,
+ int notify,
+ const char * orcpt);
+int mailesmtp_starttls(mailsmtp * session);
+
+const char * mailsmtp_strerror(int errnum);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libetpan/src/low-level/smtp/mailsmtp_helper.c b/libetpan/src/low-level/smtp/mailsmtp_helper.c
new file mode 100644
index 0000000..69b73cc
--- a/dev/null
+++ b/libetpan/src/low-level/smtp/mailsmtp_helper.c
@@ -0,0 +1,228 @@
+/*
+ * 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 "mailsmtp.h"
+#include <string.h>
+#include <stdlib.h>
+#include "mail.h"
+
+int mailsmtp_init(mailsmtp * session)
+{
+ int r;
+
+ r = mailesmtp_ehlo(session);
+
+ if (r == MAILSMTP_NO_ERROR)
+ return MAILSMTP_NO_ERROR;
+
+ r = mailsmtp_helo(session);
+ if (r == MAILSMTP_NO_ERROR)
+ return MAILSMTP_NO_ERROR;
+
+ return r;
+}
+
+
+
+int mailesmtp_send(mailsmtp * session,
+ const char * from,
+ int return_full,
+ const char * envid,
+ clist * addresses,
+ const char * message, size_t size)
+{
+ int r;
+ clistiter * l;
+
+ if (!session->esmtp)
+ return mailsmtp_send(session, from, addresses, message, size);
+
+ r = mailesmtp_mail(session, from, return_full, envid);
+ if (r != MAILSMTP_NO_ERROR)
+ return r;
+
+ for(l = clist_begin(addresses) ; l != NULL; l = clist_next(l)) {
+ struct esmtp_address * addr;
+
+ addr = clist_content(l);
+
+ r = mailesmtp_rcpt(session, addr->address, addr->notify, addr->orcpt);
+ if (r != MAILSMTP_NO_ERROR)
+ return r;
+ }
+
+ r = mailsmtp_data(session);
+ if (r != MAILSMTP_NO_ERROR)
+ return r;
+
+ r = mailsmtp_data_message(session, message, size);
+ if (r != MAILSMTP_NO_ERROR)
+ return r;
+
+ return MAILSMTP_NO_ERROR;
+}
+
+int mailsmtp_send(mailsmtp * session,
+ const char * from,
+ clist * addresses,
+ const char * message, size_t size)
+{
+ int r;
+ clistiter * l;
+
+ r = mailsmtp_mail(session, from);
+ if (r != MAILSMTP_NO_ERROR)
+ return r;
+
+ for(l = clist_begin(addresses) ; l != NULL; l = clist_next(l)) {
+ struct esmtp_address * addr;
+
+ addr = clist_content(l);
+
+ r = mailsmtp_rcpt(session, addr->address);
+ if (r != MAILSMTP_NO_ERROR)
+ return r;
+ }
+
+ r = mailsmtp_data(session);
+ if (r != MAILSMTP_NO_ERROR)
+ return r;
+
+ r = mailsmtp_data_message(session, message, size);
+ if (r != MAILSMTP_NO_ERROR)
+ return r;
+
+ return MAILSMTP_NO_ERROR;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+/* esmtp addresses and smtp addresses */
+
+static struct esmtp_address * esmtp_address_new(char * addr,
+ int notify, char * orcpt)
+{
+ struct esmtp_address * esmtpa;
+
+ esmtpa = malloc(sizeof(* esmtpa));
+ if (esmtpa == NULL)
+ return NULL;
+
+ esmtpa->address = strdup(addr);
+ if (esmtpa->address == NULL) {
+ free(esmtpa);
+ return NULL;
+ }
+
+ if (orcpt != NULL) {
+ esmtpa->orcpt = strdup(orcpt);
+ if (esmtpa->orcpt == NULL) {
+ free(esmtpa->address);
+ free(esmtpa);
+ return NULL;
+ }
+ }
+ else
+ esmtpa->orcpt = NULL;
+
+ esmtpa->notify = notify;
+
+ return esmtpa;
+}
+
+static void esmtp_address_free(struct esmtp_address * addr)
+{
+ if (addr->orcpt)
+ free(addr->orcpt);
+ if (addr->address)
+ free(addr->address);
+
+ free(addr);
+}
+
+clist * esmtp_address_list_new()
+{
+ return clist_new();
+}
+
+void esmtp_address_list_free(clist * l)
+{
+ clist_foreach(l, (clist_func) esmtp_address_free, NULL);
+ clist_free(l);
+}
+
+int esmtp_address_list_add(clist * list, char * address,
+ int notify, char * orcpt)
+{
+ struct esmtp_address * esmtpa;
+ int r;
+
+ esmtpa = esmtp_address_new(address, notify, orcpt);
+ if (esmtpa == NULL)
+ return -1;
+
+ r = clist_append(list, esmtpa);
+ if (r < 0) {
+ esmtp_address_free(esmtpa);
+ return -1;
+ }
+
+ return 0;
+}
+
+clist * smtp_address_list_new()
+{
+ return esmtp_address_list_new();
+}
+
+int smtp_address_list_add(clist * list, char * address)
+{
+ return esmtp_address_list_add(list, address, 0, NULL);
+}
+
+void smtp_address_list_free(clist * l)
+{
+ esmtp_address_list_free(l);
+}
diff --git a/libetpan/src/low-level/smtp/mailsmtp_helper.h b/libetpan/src/low-level/smtp/mailsmtp_helper.h
new file mode 100644
index 0000000..2178d50
--- a/dev/null
+++ b/libetpan/src/low-level/smtp/mailsmtp_helper.h
@@ -0,0 +1,74 @@
+/*
+ * 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$
+ */
+
+#ifndef MAILSMTP_HELPER_H
+
+#define MAILSMTP_HELPER_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "mailsmtp_types.h"
+#include "clist.h"
+
+int mailsmtp_init(mailsmtp * session);
+
+int mailesmtp_send(mailsmtp * session,
+ const char * from,
+ int return_full,
+ const char * envid,
+ clist * addresses,
+ const char * message, size_t size);
+
+int mailsmtp_send(mailsmtp * session,
+ const char * from,
+ clist * addresses,
+ const char * message, size_t size);
+
+clist * esmtp_address_list_new();
+int esmtp_address_list_add(clist * list, char * address,
+ int notify, char * orcpt);
+void esmtp_address_list_free(clist * l);
+
+clist * smtp_address_list_new();
+int smtp_address_list_add(clist * list, char * address);
+void smtp_address_list_free(clist * l);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libetpan/src/low-level/smtp/mailsmtp_socket.c b/libetpan/src/low-level/smtp/mailsmtp_socket.c
new file mode 100644
index 0000000..6b8d81a
--- a/dev/null
+++ b/libetpan/src/low-level/smtp/mailsmtp_socket.c
@@ -0,0 +1,99 @@
+/*
+ * 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 "mailsmtp_socket.h"
+
+#include "mailsmtp.h"
+
+#include "connect.h"
+#include <netinet/in.h>
+#include <unistd.h>
+
+#define DEFAULT_SMTP_PORT 25
+#define SERVICE_NAME_SMTP "smtp"
+#define SERVICE_TYPE_TCP "tcp"
+
+int mailsmtp_socket_connect(mailsmtp * session,
+ const char * server, uint16_t port)
+{
+ int s;
+ mailstream * stream;
+
+ if (port == 0) {
+ port = mail_get_service_port(SERVICE_NAME_SMTP, SERVICE_TYPE_TCP);
+ if (port == 0)
+ port = DEFAULT_SMTP_PORT;
+ port = ntohs(port);
+ }
+
+ /* Connection */
+
+ s = mail_tcp_connect(server, port);
+ if (s == -1)
+ return MAILSMTP_ERROR_CONNECTION_REFUSED;
+
+ stream = mailstream_socket_open(s);
+ if (stream == NULL) {
+ close(s);
+ return MAILSMTP_ERROR_MEMORY;
+ }
+
+ return mailsmtp_connect(session, stream);
+}
+
+int mailsmtp_socket_starttls(mailsmtp * session) {
+ int r;
+ int fd;
+ mailstream_low * low;
+ mailstream_low * new_low;
+
+ r = mailesmtp_starttls(session);
+ if (r != MAILSMTP_NO_ERROR)
+ return r;
+
+ low = mailstream_get_low(session->stream);
+ fd = mailstream_low_get_fd(low);
+ if (fd == -1)
+ return MAILSMTP_ERROR_STREAM;
+
+ new_low = mailstream_low_ssl_open(fd);
+ if (new_low == NULL)
+ return MAILSMTP_ERROR_STREAM;
+
+ mailstream_low_free(low);
+ mailstream_set_low(session->stream, new_low);
+
+ return MAILSMTP_NO_ERROR;
+}
diff --git a/libetpan/src/low-level/smtp/mailsmtp_socket.h b/libetpan/src/low-level/smtp/mailsmtp_socket.h
new file mode 100644
index 0000000..2726c1d
--- a/dev/null
+++ b/libetpan/src/low-level/smtp/mailsmtp_socket.h
@@ -0,0 +1,56 @@
+/*
+ * 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$
+ */
+
+#ifndef MAILSMTP_SOCKET_H
+
+#define MAILSMTP_SOCKET_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <inttypes.h>
+
+#include <libetpan/mailsmtp_types.h>
+
+int mailsmtp_socket_connect(mailsmtp * session,
+ const char * server, uint16_t port);
+int mailsmtp_socket_starttls(mailsmtp * session);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libetpan/src/low-level/smtp/mailsmtp_ssl.c b/libetpan/src/low-level/smtp/mailsmtp_ssl.c
new file mode 100644
index 0000000..4a42326
--- a/dev/null
+++ b/libetpan/src/low-level/smtp/mailsmtp_ssl.c
@@ -0,0 +1,74 @@
+/*
+ * 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 "mailsmtp_socket.h"
+
+#include "mailsmtp.h"
+
+#include "connect.h"
+#include <netinet/in.h>
+#include <unistd.h>
+
+#define DEFAULT_SMTPS_PORT 465
+#define SERVICE_NAME_SMTPS "smtps"
+#define SERVICE_TYPE_TCP "tcp"
+
+int mailsmtp_ssl_connect(mailsmtp * session,
+ const char * server, uint16_t port)
+{
+ int s;
+ mailstream * stream;
+
+ if (port == 0) {
+ port = mail_get_service_port(SERVICE_NAME_SMTPS, SERVICE_TYPE_TCP);
+ if (port == 0)
+ port = DEFAULT_SMTPS_PORT;
+ port = ntohs(port);
+ }
+
+ /* Connection */
+
+ s = mail_tcp_connect(server, port);
+ if (s == -1)
+ return MAILSMTP_ERROR_CONNECTION_REFUSED;
+
+ stream = mailstream_ssl_open(s);
+ if (stream == NULL) {
+ close(s);
+ return MAILSMTP_ERROR_CONNECTION_REFUSED;
+ }
+
+ return mailsmtp_connect(session, stream);
+}
diff --git a/libetpan/src/low-level/smtp/mailsmtp_ssl.h b/libetpan/src/low-level/smtp/mailsmtp_ssl.h
new file mode 100644
index 0000000..01f4683
--- a/dev/null
+++ b/libetpan/src/low-level/smtp/mailsmtp_ssl.h
@@ -0,0 +1,55 @@
+/*
+ * 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$
+ */
+
+#ifndef MAILSMTP_SSL_H
+
+#define MAILSMTP_SSL_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <inttypes.h>
+
+#include <libetpan/mailsmtp_types.h>
+
+int mailsmtp_ssl_connect(mailsmtp * session,
+ const char * server, uint16_t port);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libetpan/src/low-level/smtp/mailsmtp_types.h b/libetpan/src/low-level/smtp/mailsmtp_types.h
new file mode 100644
index 0000000..0aa2617
--- a/dev/null
+++ b/libetpan/src/low-level/smtp/mailsmtp_types.h
@@ -0,0 +1,126 @@
+/*
+ * 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$
+ */
+
+#ifndef MAILSMTP_TYPES_H
+
+#define MAILSMTP_TYPES_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "mailstream.h"
+#include "mmapstring.h"
+
+enum {
+ MAILSMTP_NO_ERROR = 0,
+ MAILSMTP_ERROR_UNEXPECTED_CODE,
+ MAILSMTP_ERROR_SERVICE_NOT_AVAILABLE,
+ MAILSMTP_ERROR_STREAM,
+ MAILSMTP_ERROR_HOSTNAME,
+ MAILSMTP_ERROR_NOT_IMPLEMENTED,
+ MAILSMTP_ERROR_ACTION_NOT_TAKEN,
+ MAILSMTP_ERROR_EXCEED_STORAGE_ALLOCATION,
+ MAILSMTP_ERROR_IN_PROCESSING,
+ MAILSMTP_ERROR_INSUFFICIENT_SYSTEM_STORAGE,
+ MAILSMTP_ERROR_MAILBOX_UNAVAILABLE,
+ MAILSMTP_ERROR_MAILBOX_NAME_NOT_ALLOWED,
+ MAILSMTP_ERROR_BAD_SEQUENCE_OF_COMMAND,
+ MAILSMTP_ERROR_USER_NOT_LOCAL,
+ MAILSMTP_ERROR_TRANSACTION_FAILED,
+ MAILSMTP_ERROR_MEMORY,
+ MAILSMTP_ERROR_AUTH_NOT_SUPPORTED,
+ MAILSMTP_ERROR_AUTH_LOGIN,
+ MAILSMTP_ERROR_AUTH_REQUIRED,
+ MAILSMTP_ERROR_AUTH_TOO_WEAK,
+ MAILSMTP_ERROR_AUTH_TRANSITION_NEEDED,
+ MAILSMTP_ERROR_AUTH_TEMPORARY_FAILTURE,
+ MAILSMTP_ERROR_AUTH_ENCRYPTION_REQUIRED,
+ MAILSMTP_ERROR_STARTTLS_TEMPORARY_FAILURE,
+ MAILSMTP_ERROR_STARTTLS_NOT_SUPPORTED,
+ MAILSMTP_ERROR_CONNECTION_REFUSED
+};
+
+enum {
+ MAILSMTP_AUTH_NOT_CHECKED = 0,
+ MAILSMTP_AUTH_CHECKED = 1,
+ MAILSMTP_AUTH_CRAM_MD5 = 2,
+ MAILSMTP_AUTH_PLAIN = 4,
+ MAILSMTP_AUTH_LOGIN = 8
+};
+
+enum {
+ MAILSMTP_ESMTP = 1,
+ MAILSMTP_ESMTP_EXPN = 2,
+ MAILSMTP_ESMTP_8BITMIME = 4,
+ MAILSMTP_ESMTP_SIZE = 8,
+ MAILSMTP_ESMTP_ETRN = 16,
+ MAILSMTP_ESMTP_STARTTLS = 32,
+ MAILSMTP_ESMTP_DSN = 64,
+};
+
+struct mailsmtp {
+ mailstream * stream;
+
+ size_t progr_rate;
+ progress_function * progr_fun;
+
+ char * response;
+
+ MMAPString * line_buffer;
+ MMAPString * response_buffer;
+
+ int esmtp; // contains flags MAILSMTP_ESMTP_*
+ int auth; // contains flags MAILSMTP_AUTH_*
+};
+
+typedef struct mailsmtp mailsmtp;
+
+#define MAILSMTP_DSN_NOTIFY_SUCCESS 1
+#define MAILSMTP_DSN_NOTIFY_FAILURE 2
+#define MAILSMTP_DSN_NOTIFY_DELAY 4
+#define MAILSMTP_DSN_NOTIFY_NEVER 8
+
+struct esmtp_address {
+ char * address;
+ int notify;
+ char * orcpt;
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif