From 9e549686b23b6dffdcbd09c9b10dc2cb795fbcdf Mon Sep 17 00:00:00 2001 From: zautrix Date: Fri, 18 Mar 2005 20:17:03 +0000 Subject: Initial revision --- (limited to 'libetpan/src/low-level/imap/mailimap.c') 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 +#include +#include + +#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); +} -- cgit v0.9.0.2