author | zautrix <zautrix> | 2005-03-18 22:05:02 (UTC) |
---|---|---|
committer | zautrix <zautrix> | 2005-03-18 22:05:02 (UTC) |
commit | 297208a61298fceab6d96bbd1c46198b1c0f7a76 (patch) (side-by-side diff) | |
tree | 50f0c6f775393c1eec15b71691a798d1dacab86d | |
parent | f0232b7801f098b5842e3cd5a1fd804af98ab862 (diff) | |
download | kdepimpi-297208a61298fceab6d96bbd1c46198b1c0f7a76.zip kdepimpi-297208a61298fceab6d96bbd1c46198b1c0f7a76.tar.gz kdepimpi-297208a61298fceab6d96bbd1c46198b1c0f7a76.tar.bz2 |
fixes applied
-rw-r--r-- | libetpan/src/data-types/mailstream_helper.c | 11 | ||||
-rw-r--r-- | libetpan/src/driver/implementation/pop3/pop3driver.c | 8 | ||||
-rw-r--r-- | libetpan/src/low-level/imap/mailimap_parser.c | 22 | ||||
-rw-r--r-- | libetpan/src/low-level/maildir/maildir.c | 17 | ||||
-rw-r--r-- | libetpan/src/low-level/mh/mailmh.c | 3 | ||||
-rw-r--r-- | libetpan/src/low-level/pop3/mailpop3.c | 7 |
6 files changed, 59 insertions, 9 deletions
diff --git a/libetpan/src/data-types/mailstream_helper.c b/libetpan/src/data-types/mailstream_helper.c index 2f0b9ae..f0ddf51 100644 --- a/libetpan/src/data-types/mailstream_helper.c +++ b/libetpan/src/data-types/mailstream_helper.c @@ -1,515 +1,522 @@ /* * 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_helper.h" #include <string.h> #include <stdio.h> #include "mail.h" static void remove_trailing_eol(MMAPString * mmapstr) { if (mmapstr->str[mmapstr->len - 1] == '\n') { mmapstr->len --; mmapstr->str[mmapstr->len] = '\0'; } if (mmapstr->str[mmapstr->len - 1] == '\r') { mmapstr->len --; mmapstr->str[mmapstr->len] = '\0'; } } char * mailstream_read_line(mailstream * stream, MMAPString * line) { if (mmap_string_assign(line, "") == NULL) return NULL; return mailstream_read_line_append(stream, line); } static char * mailstream_read_len_append(mailstream * stream, MMAPString * line, size_t i) { size_t cur_size; cur_size = line->len; if (mmap_string_set_size(line, line->len + i) == NULL) return NULL; if (mailstream_read(stream, line->str + cur_size, i) < 0) return NULL; return line->str; } char * mailstream_read_line_append(mailstream * stream, MMAPString * line) { if (stream == NULL) return NULL; do { if (stream->read_buffer_len > 0) { size_t i; i = 0; while (i < stream->read_buffer_len) { if (stream->read_buffer[i] == '\n') return mailstream_read_len_append(stream, line, i + 1); i++; } if (mailstream_read_len_append(stream, line, stream->read_buffer_len) == NULL) return NULL; } else { ssize_t r; r = mailstream_feed_read_buffer(stream); if (r == -1) return NULL; - if (r == 0) - break; + if (r == 0) { + // LR + // this avoids a memory access violation later when trying + // to remove_trailing_eol from a null string + if ( line->len == 0 ) + return NULL; + else + break; + } } } while (1); return line->str; } char * mailstream_read_line_remove_eol(mailstream * stream, MMAPString * line) { if (!mailstream_read_line(stream, line)) return NULL; remove_trailing_eol(line); return line->str; } int mailstream_is_end_multiline(const char * line) { if (line[0] != '.') return FALSE; if (line[1] != 0) return FALSE; return TRUE; } #if 1 char * mailstream_read_multiline(mailstream * s, size_t size, MMAPString * stream_buffer, MMAPString * multiline_buffer, size_t progr_rate, progress_function * progr_fun) { size_t count; char * line; size_t last; if (mmap_string_assign(multiline_buffer, "") == NULL) return NULL; count = 0; last = 0; while ((line = mailstream_read_line_remove_eol(s, stream_buffer)) != NULL) { if (mailstream_is_end_multiline(line)) return multiline_buffer->str; if (line[0] == '.') { if (mmap_string_append(multiline_buffer, line + 1) == NULL) return NULL; } else { if (mmap_string_append(multiline_buffer, line) == NULL) return NULL; } if (mmap_string_append(multiline_buffer, "\r\n") == NULL) return NULL; count += strlen(line); if ((size != 0) && (progr_rate != 0) && (progr_fun != NULL)) if (count - last >= progr_rate) { (* progr_fun)(count, size); last = count; } } return NULL; } #else /* high speed but don't replace the line break with '\n' and neither remove the '.' */ static gboolean end_of_multiline(const char * str, gint len) { gint index; index = len - 1; if (str[index] != '\n') return FALSE; if (index == 0) return FALSE; index --; if (str[index] == '\r') { index --; if (index == 0) return FALSE; } if (str[index] != '.') return FALSE; if (index == 0) return FALSE; index--; if (str[index] != '\n') return FALSE; return TRUE; } char * mailstream_read_multiline(mailstream * stream, size_t size, MMAPString * stream_buffer, MMAPString * line, size_t progr_rate, progress_function * progr_fun) { if (stream == NULL) return NULL; mmap_string_assign(line, ""); do { if (stream->read_buffer_len > 0) { size_t i; i = 0; while (i < stream->read_buffer_len) { if (end_of_multiline(stream->read_buffer, i + 1)) return mailstream_read_len_append(stream, line, i + 1); i++; } if (mailstream_read_len_append(stream, line, stream->read_buffer_len) == NULL) return NULL; if (end_of_multiline(line->str, line->len)) return line->str; } else if (mailstream_feed_read_buffer(stream) == -1) return NULL; } while (1); return line->str; } #endif static inline ssize_t send_data_line(mailstream * s, const char * line, size_t length) { int fix_eol; const char * start; size_t count; start = line; fix_eol = 0; count = 0; while (1) { if (length == 0) break; if (* line == '\r') { line ++; count ++; length --; if (length == 0) { fix_eol = 1; break; } if (* line == '\n') { line ++; count ++; length --; break; } else { fix_eol = 1; break; } } else if (* line == '\n') { line ++; count ++; length --; fix_eol = 1; break; } line ++; length --; count ++; } if (fix_eol) { if (mailstream_write(s, start, count - 1) == -1) goto err; if (mailstream_write(s, "\r\n", 2) == -1) goto err; } else { if (mailstream_write(s, start, count) == -1) goto err; } #if 0 while (* line != '\n') { if (* line == '\r') pos = line; if (* line == '\0') return line; if (mailstream_write(s, line, 1) == -1) goto err; line ++; } if (pos + 1 == line) { if (mailstream_write(s, line, 1) == -1) goto err; } else { if (mailstream_write(s, "\r\n", 2) == -1) goto err; } line ++; #endif return count; err: return -1; } static inline int send_data_crlf(mailstream * s, const char * message, size_t size, int quoted, size_t progr_rate, progress_function * progr_fun) { const char * current; size_t count; size_t last; size_t remaining; count = 0; last = 0; current = message; remaining = size; while (remaining > 0) { ssize_t length; if (quoted) { if (current[0] == '.') if (mailstream_write(s, ".", 1) == -1) goto err; } length = send_data_line(s, current, remaining); if (length < 0) goto err; current += length; count += length; if ((progr_rate != 0) && (progr_fun != NULL)) if (count - last >= progr_rate) { (* progr_fun)(count, size); last = count; } remaining -= length; } return 0; err: return -1; } int mailstream_send_data_crlf(mailstream * s, const char * message, size_t size, size_t progr_rate, progress_function * progr_fun) { return send_data_crlf(s, message, size, 0, progr_rate, progr_fun); } int mailstream_send_data(mailstream * s, const char * message, size_t size, size_t progr_rate, progress_function * progr_fun) { if (send_data_crlf(s, message, size, 1, progr_rate, progr_fun) == -1) goto err; if (mailstream_write(s, "\r\n.\r\n", 5) == -1) goto err; if (mailstream_flush(s) == -1) goto err; return 0; err: return -1; } static inline ssize_t get_data_size(const char * line, size_t length, size_t * result) { int fix_eol; const char * start; size_t count; size_t fixed_count; start = line; fix_eol = 0; count = 0; fixed_count = 0; while (1) { if (length == 0) break; if (* line == '\r') { line ++; count ++; length --; if (length == 0) { fix_eol = 1; fixed_count ++; break; } if (* line == '\n') { line ++; count ++; length --; break; } else { fix_eol = 1; fixed_count ++; break; } } else if (* line == '\n') { line ++; count ++; length --; fix_eol = 1; fixed_count ++; break; } line ++; length --; count ++; } * result = count + fixed_count; return count; } size_t mailstream_get_data_crlf_size(const char * message, size_t size) { const char * current; size_t count; size_t last; size_t remaining; size_t fixed_count; count = 0; last = 0; fixed_count = 0; current = message; remaining = size; while (remaining > 0) { ssize_t length; size_t line_count; length = get_data_size(current, remaining, &line_count); fixed_count += line_count; current += length; count += length; remaining -= length; } return fixed_count; } diff --git a/libetpan/src/driver/implementation/pop3/pop3driver.c b/libetpan/src/driver/implementation/pop3/pop3driver.c index ea69923..6cc6a9a 100644 --- a/libetpan/src/driver/implementation/pop3/pop3driver.c +++ b/libetpan/src/driver/implementation/pop3/pop3driver.c @@ -1,388 +1,394 @@ /* * 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 "pop3driver.h" #include <string.h> #include <stdlib.h> #include "pop3driver_message.h" #include "maildriver_tools.h" #include "pop3driver_tools.h" #include "mailmessage.h" static int pop3driver_initialize(mailsession * session); static void pop3driver_uninitialize(mailsession * session); static int pop3driver_parameters(mailsession * session, int id, void * value); static int pop3driver_connect_stream(mailsession * session, mailstream * s); static int pop3driver_starttls(mailsession * session); static int pop3driver_login(mailsession * session, char * userid, char * password); static int pop3driver_logout(mailsession * session); static int pop3driver_noop(mailsession * session); static int pop3driver_status_folder(mailsession * session, char * mb, uint32_t * result_messages, uint32_t * result_recent, uint32_t * result_unseen); static int pop3driver_messages_number(mailsession * session, char * mb, uint32_t * result); static int pop3driver_remove_message(mailsession * session, uint32_t num); static int pop3driver_get_messages_list(mailsession * session, struct mailmessage_list ** result); static int pop3driver_get_message(mailsession * session, uint32_t num, mailmessage ** result); static mailsession_driver local_pop3_session_driver = { .sess_name = "pop3", .sess_initialize = pop3driver_initialize, .sess_uninitialize = pop3driver_uninitialize, .sess_parameters = pop3driver_parameters, .sess_connect_stream = pop3driver_connect_stream, .sess_connect_path = NULL, .sess_starttls = pop3driver_starttls, .sess_login = pop3driver_login, .sess_logout = pop3driver_logout, .sess_noop = pop3driver_noop, .sess_build_folder_name = NULL, .sess_create_folder = NULL, .sess_delete_folder = NULL, .sess_rename_folder = NULL, .sess_check_folder = NULL, .sess_examine_folder = NULL, .sess_select_folder = NULL, .sess_expunge_folder = NULL, .sess_status_folder = pop3driver_status_folder, .sess_messages_number = pop3driver_messages_number, .sess_recent_number = pop3driver_messages_number, .sess_unseen_number = pop3driver_messages_number, .sess_list_folders = NULL, .sess_lsub_folders = NULL, .sess_subscribe_folder = NULL, .sess_unsubscribe_folder = NULL, .sess_append_message = NULL, .sess_append_message_flags = NULL, .sess_copy_message = NULL, .sess_move_message = NULL, .sess_get_messages_list = pop3driver_get_messages_list, .sess_get_envelopes_list = maildriver_generic_get_envelopes_list, .sess_remove_message = pop3driver_remove_message, #if 0 .sess_search_messages = maildriver_generic_search_messages, #endif .sess_get_message = pop3driver_get_message, .sess_get_message_by_uid = NULL, }; mailsession_driver * pop3_session_driver = &local_pop3_session_driver; static inline struct pop3_session_state_data * get_data(mailsession * session) { return session->sess_data; } static mailpop3 * get_pop3_session(mailsession * session) { return get_data(session)->pop3_session; } static int pop3driver_initialize(mailsession * session) { struct pop3_session_state_data * data; mailpop3 * pop3; pop3 = mailpop3_new(0, NULL); if (session == NULL) goto err; data = malloc(sizeof(* data)); if (data == NULL) goto free; data->pop3_session = pop3; data->pop3_auth_type = POP3DRIVER_AUTH_TYPE_PLAIN; session->sess_data = data; return MAIL_NO_ERROR; free: mailpop3_free(pop3); err: return MAIL_ERROR_MEMORY; } static void pop3driver_uninitialize(mailsession * session) { struct pop3_session_state_data * data; data = get_data(session); mailpop3_free(data->pop3_session); free(data); session->sess_data = data; } static int pop3driver_connect_stream(mailsession * session, mailstream * s) { int r; r = mailpop3_connect(get_pop3_session(session), s); switch (r) { case MAILPOP3_NO_ERROR: return MAIL_NO_ERROR_NON_AUTHENTICATED; default: return pop3driver_pop3_error_to_mail_error(r); } } static int pop3driver_starttls(mailsession * session) { int r; int fd; mailstream_low * low; mailstream_low * new_low; mailpop3 * pop3; pop3 = get_pop3_session(session); r = mailpop3_stls(pop3); switch (r) { case MAILPOP3_NO_ERROR: break; default: return pop3driver_pop3_error_to_mail_error(r); } low = mailstream_get_low(pop3->pop3_stream); fd = mailstream_low_get_fd(low); if (fd == -1) return MAIL_ERROR_STREAM; new_low = mailstream_low_ssl_open(fd); if (new_low == NULL) return MAIL_ERROR_STREAM; mailstream_low_free(low); mailstream_set_low(pop3->pop3_stream, new_low); return MAIL_NO_ERROR; } static int pop3driver_parameters(mailsession * session, int id, void * value) { struct pop3_session_state_data * data; data = get_data(session); switch (id) { case POP3DRIVER_SET_AUTH_TYPE: { int * param; param = value; data->pop3_auth_type = * param; return MAIL_NO_ERROR; } } return MAIL_ERROR_INVAL; } static int pop3driver_login(mailsession * session, char * userid, char * password) { int r; + //LR + int ret; carray * msg_tab; struct pop3_session_state_data * data; data = get_data(session); switch (data->pop3_auth_type) { case POP3DRIVER_AUTH_TYPE_TRY_APOP: r = mailpop3_login_apop(get_pop3_session(session), userid, password); if (r != MAILPOP3_NO_ERROR) r = mailpop3_login(get_pop3_session(session), userid, password); break; case POP3DRIVER_AUTH_TYPE_APOP: r = mailpop3_login_apop(get_pop3_session(session), userid, password); break; default: case POP3DRIVER_AUTH_TYPE_PLAIN: r = mailpop3_login(get_pop3_session(session), userid, password); break; } - mailpop3_list(get_pop3_session(session), &msg_tab); + // LR 2 lines + ret = pop3driver_pop3_error_to_mail_error(r); + if ( ret == MAIL_NO_ERROR ) + mailpop3_list(get_pop3_session(session), &msg_tab); + // LR return pop3driver_pop3_error_to_mail_error(r); } static int pop3driver_logout(mailsession * session) { int r; r = mailpop3_quit(get_pop3_session(session)); return pop3driver_pop3_error_to_mail_error(r); } static int pop3driver_noop(mailsession * session) { int r; r = mailpop3_noop(get_pop3_session(session)); return pop3driver_pop3_error_to_mail_error(r); } static int pop3driver_status_folder(mailsession * session, char * mb, uint32_t * result_messages, uint32_t * result_recent, uint32_t * result_unseen) { uint32_t count; int r; r = pop3driver_messages_number(session, mb, &count); if (r != MAIL_NO_ERROR) return r; * result_messages = count; * result_recent = count; * result_unseen = count; return MAIL_NO_ERROR; } static int pop3driver_messages_number(mailsession * session, char * mb, uint32_t * result) { carray * msg_tab; mailpop3_list(get_pop3_session(session), &msg_tab); * result = carray_count(msg_tab) - get_pop3_session(session)->pop3_deleted_count; return MAIL_NO_ERROR; } /* messages operations */ static int pop3driver_remove_message(mailsession * session, uint32_t num) { mailpop3 * pop3; int r; pop3 = get_pop3_session(session); r = mailpop3_dele(pop3, num); switch (r) { case MAILPOP3_ERROR_BAD_STATE: return MAIL_ERROR_BAD_STATE; case MAILPOP3_ERROR_NO_SUCH_MESSAGE: return MAIL_ERROR_MSG_NOT_FOUND; case MAILPOP3_ERROR_STREAM: return MAIL_ERROR_STREAM; case MAILPOP3_NO_ERROR: return MAIL_NO_ERROR; default: return MAIL_ERROR_REMOVE; } } static int pop3driver_get_messages_list(mailsession * session, struct mailmessage_list ** result) { mailpop3 * pop3; pop3 = get_pop3_session(session); return pop3_get_messages_list(pop3, session, pop3_message_driver, result); } static int pop3driver_get_message(mailsession * session, uint32_t num, mailmessage ** result) { mailmessage * msg_info; int r; msg_info = mailmessage_new(); if (msg_info == NULL) return MAIL_ERROR_MEMORY; r = mailmessage_init(msg_info, session, pop3_message_driver, num, 0); if (r != MAIL_NO_ERROR) { mailmessage_free(msg_info); return r; } * result = msg_info; return MAIL_NO_ERROR; } diff --git a/libetpan/src/low-level/imap/mailimap_parser.c b/libetpan/src/low-level/imap/mailimap_parser.c index ab4db67..071891c 100644 --- a/libetpan/src/low-level/imap/mailimap_parser.c +++ b/libetpan/src/low-level/imap/mailimap_parser.c @@ -1634,1538 +1634,1556 @@ static int mailimap_body_parse(mailstream * fd, MMAPString * buffer, 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; + // LR start + // accept NIL and set type to utf8 + int ret = r; + r = mailimap_char_parse(fd, buffer, &cur_token, 'N'); + if (r == MAILIMAP_NO_ERROR) { + r = mailimap_char_parse(fd, buffer, &cur_token, 'I'); + if (r == MAILIMAP_NO_ERROR) { + r = mailimap_char_parse(fd, buffer, &cur_token, 'L'); + if (r == MAILIMAP_NO_ERROR) { + type = 4; + ret = MAILIMAP_NO_ERROR; + value = NULL; + } + } + } + if ( ret != MAILIMAP_NO_ERROR ) { + res = ret; + goto err; + } + // LR end } } else { res = r; goto err; } body_fld_enc = mailimap_body_fld_enc_new(type, value); if (body_fld_enc == NULL) { res = MAILIMAP_ERROR_MEMORY; goto value_free; } * result = body_fld_enc; * index = cur_token; return MAILIMAP_NO_ERROR; value_free: if (value) mailimap_string_free(value); err: return res; } /* body-fld-id = nstring */ static int mailimap_body_fld_id_parse(mailstream * fd, MMAPString * buffer, size_t * index, char ** result, size_t progr_rate, progress_function * progr_fun) { return mailimap_nstring_parse(fd, buffer, index, result, NULL, progr_rate, progr_fun); } /* body-fld-lang = nstring / "(" string *(SP string) ")" */ /* "(" string *(SP string) ")" */ static int mailimap_body_fld_lang_list_parse(mailstream * fd, MMAPString * buffer, size_t * index, clist ** result, size_t progr_rate, progress_function * progr_fun) { size_t cur_token; clist * list; int r; int res; cur_token = * index; r = mailimap_oparenth_parse(fd, buffer, &cur_token); if (r != MAILIMAP_NO_ERROR) { res = r; goto err; } list = clist_new(); if (list == NULL) { res = MAILIMAP_ERROR_MEMORY; goto err; } while (1) { char * elt; r = mailimap_string_parse(fd, buffer, &cur_token, &elt, NULL, progr_rate, progr_fun); if (r != MAILIMAP_ERROR_PARSE) break; else if (r == MAILIMAP_NO_ERROR) { r = clist_append(list, elt); if (r < 0) { mailimap_string_free(elt); res = r; goto list_free; } } else { res = r; goto list_free; } } r = mailimap_cparenth_parse(fd, buffer, &cur_token); if (r != MAILIMAP_NO_ERROR) { res = r; goto list_free; } * index = cur_token; * result = list; return MAILIMAP_NO_ERROR; list_free: clist_foreach(list, (clist_func) mailimap_string_free, NULL); clist_free(list); err: return res; } /* body-fld-lang = nstring / "(" string *(SP string) ")" */ static int mailimap_body_fld_lang_parse(mailstream * fd, MMAPString * buffer, size_t * index, struct mailimap_body_fld_lang ** result, size_t progr_rate, progress_function * progr_fun) { char * value; clist * list; struct mailimap_body_fld_lang * fld_lang; int type; int r; int res; size_t cur_token; cur_token = * index; value = NULL; list = NULL; type = MAILIMAP_BODY_FLD_LANG_ERROR; /* XXX - removes a gcc warning */ r = mailimap_nstring_parse(fd, buffer, &cur_token, &value, NULL, progr_rate, progr_fun); if (r == MAILIMAP_NO_ERROR) type = MAILIMAP_BODY_FLD_LANG_SINGLE; if (r == MAILIMAP_ERROR_PARSE) { r = mailimap_body_fld_lang_list_parse(fd, buffer, &cur_token, &list, progr_rate, progr_fun); if (r == MAILIMAP_NO_ERROR) type = MAILIMAP_BODY_FLD_LANG_LIST; } if (r != MAILIMAP_NO_ERROR) { res = r; goto err; } fld_lang = mailimap_body_fld_lang_new(type, value, list); if (fld_lang == NULL) { res = MAILIMAP_ERROR_MEMORY; goto free; } * index = cur_token; * result = fld_lang; return MAILIMAP_NO_ERROR; free: if (value) mailimap_nstring_free(value); if (list) { clist_foreach(list, (clist_func) mailimap_string_free, NULL); clist_free(list); } err: return res; } /* body-fld-lines = number */ static int mailimap_body_fld_lines_parse(mailstream * fd, MMAPString * buffer, size_t * index, uint32_t * result) { return mailimap_number_parse(fd, buffer, index, result); } /* body-fld-md5 = nstring */ static int mailimap_body_fld_md5_parse(mailstream * fd, MMAPString * buffer, size_t * index, char ** result, size_t progr_rate, progress_function * progr_fun) { return mailimap_nstring_parse(fd, buffer, index, result, NULL, progr_rate, progr_fun); } /* body-fld-octets = number */ static int mailimap_body_fld_octets_parse(mailstream * fd, MMAPString * buffer, size_t * index, uint32_t * result) { return mailimap_number_parse(fd, buffer, index, result); } /* body-fld-param = "(" string SP string *(SP string SP string) ")" / nil */ /* string SP string */ static int mailimap_single_body_fld_param_parse(mailstream * fd, MMAPString * buffer, size_t * index, struct mailimap_single_body_fld_param ** result, size_t progr_rate, progress_function * progr_fun) { struct mailimap_single_body_fld_param * param; char * name; char * value; size_t cur_token; int r; int res; cur_token = * index; name = NULL; value = NULL; r = mailimap_string_parse(fd, buffer, &cur_token, &name, NULL, progr_rate, progr_fun); if (r != MAILIMAP_NO_ERROR) { res = r; goto err; } r = mailimap_space_parse(fd, buffer, &cur_token); if (r != MAILIMAP_NO_ERROR) { res = r; goto free_name; } r = mailimap_string_parse(fd, buffer, &cur_token, &value, NULL, progr_rate, progr_fun); if (r != MAILIMAP_NO_ERROR) { res = r; goto free_name; } param = mailimap_single_body_fld_param_new(name, value); if (param == NULL) { res = MAILIMAP_ERROR_MEMORY; goto free_value; } * result = param; * index = cur_token; return MAILIMAP_NO_ERROR; free_value: mailimap_string_free(name); free_name: mailimap_string_free(value); err: return res; } /* body-fld-param = "(" string SP string *(SP string SP string) ")" / nil */ static int mailimap_body_fld_param_parse(mailstream * fd, MMAPString * buffer, size_t * index, struct mailimap_body_fld_param ** result, size_t progr_rate, progress_function * progr_fun) { size_t cur_token; clist * param_list; struct mailimap_body_fld_param * fld_param; int r; int res; param_list = NULL; cur_token = * index; r = mailimap_nil_parse(fd, buffer, &cur_token); if (r == MAILIMAP_NO_ERROR) { * result = NULL; * index = cur_token; return MAILIMAP_NO_ERROR; } if (r != MAILIMAP_ERROR_PARSE) { res = r; goto err; } r = mailimap_oparenth_parse(fd, buffer, &cur_token); if (r != MAILIMAP_NO_ERROR) { res = r; goto err; } r = mailimap_struct_spaced_list_parse(fd, buffer, &cur_token, ¶m_list, (mailimap_struct_parser *) mailimap_single_body_fld_param_parse, (mailimap_struct_destructor *) mailimap_single_body_fld_param_free, progr_rate, progr_fun); if (r != MAILIMAP_NO_ERROR) { res = r; goto err; } r = mailimap_cparenth_parse(fd, buffer, &cur_token); if (r != MAILIMAP_NO_ERROR) { res = r; goto free; } fld_param = mailimap_body_fld_param_new(param_list); if (fld_param == NULL) { res = MAILIMAP_ERROR_MEMORY; goto free; } * index = cur_token; * result = fld_param; return MAILIMAP_NO_ERROR; free: clist_foreach(param_list, (clist_func) mailimap_single_body_fld_param_free, NULL); clist_free(param_list); err: return res; } /* body-type-1part = (body-type-basic / body-type-msg / body-type-text) [SP body-ext-1part] */ static int mailimap_body_type_1part_parse(mailstream * fd, MMAPString * buffer, size_t * index, struct mailimap_body_type_1part ** result, size_t progr_rate, progress_function * progr_fun) { size_t cur_token; struct mailimap_body_type_1part * body_type_1part; struct mailimap_body_type_basic * body_type_basic; struct mailimap_body_type_msg * body_type_msg; struct mailimap_body_type_text * body_type_text; struct mailimap_body_ext_1part * body_ext_1part; int type; size_t final_token; int r; int res; cur_token = * index; body_type_basic = NULL; body_type_msg = NULL; body_type_text = NULL; body_ext_1part = NULL; type = MAILIMAP_BODY_TYPE_1PART_ERROR; /* XXX - removes a gcc warning */ r = mailimap_body_type_msg_parse(fd, buffer, &cur_token, &body_type_msg, progr_rate, progr_fun); if (r == MAILIMAP_NO_ERROR) type = MAILIMAP_BODY_TYPE_1PART_MSG; if (r == MAILIMAP_ERROR_PARSE) { r = mailimap_body_type_text_parse(fd, buffer, &cur_token, &body_type_text, progr_rate, progr_fun); if (r == MAILIMAP_NO_ERROR) type = MAILIMAP_BODY_TYPE_1PART_TEXT; } if (r == MAILIMAP_ERROR_PARSE) { r = mailimap_body_type_basic_parse(fd, buffer, &cur_token, &body_type_basic, progr_rate, progr_fun); if (r == MAILIMAP_NO_ERROR) type = MAILIMAP_BODY_TYPE_1PART_BASIC; } if (r != MAILIMAP_NO_ERROR) { res = r; goto err; } final_token = cur_token; body_ext_1part = NULL; r = mailimap_space_parse(fd, buffer, &cur_token); if (r == MAILIMAP_NO_ERROR) { r = mailimap_body_ext_1part_parse(fd, buffer, &cur_token, &body_ext_1part, progr_rate, progr_fun); if (r == MAILIMAP_NO_ERROR) final_token = cur_token; else if (r == MAILIMAP_ERROR_PARSE) { /* do nothing */ } else { res = r; goto free; } } else if (r == MAILIMAP_ERROR_PARSE) { /* do nothing */ } else { res = r; goto free; } body_type_1part = mailimap_body_type_1part_new(type, body_type_basic, body_type_msg, body_type_text, body_ext_1part); if (body_type_1part == NULL) { res = MAILIMAP_ERROR_MEMORY; goto free; } * index = final_token; * result = body_type_1part; return MAILIMAP_NO_ERROR; free: if (body_type_basic) mailimap_body_type_basic_free(body_type_basic); if (body_type_msg) mailimap_body_type_msg_free(body_type_msg); if (body_type_text) mailimap_body_type_text_free(body_type_text); if (body_ext_1part) mailimap_body_ext_1part_free(body_ext_1part); err: return res; } /* body-type-basic = media-basic SP body-fields ; MESSAGE subtype MUST NOT be "RFC822" */ static int mailimap_body_type_basic_parse(mailstream * fd, MMAPString * buffer, size_t * index, struct mailimap_body_type_basic ** result, size_t progr_rate, progress_function * progr_fun) { size_t cur_token; struct mailimap_body_type_basic * body_type_basic; struct mailimap_media_basic * media_basic; struct mailimap_body_fields * body_fields; int r; int res; cur_token = * index; media_basic = NULL; body_fields = NULL; r = mailimap_media_basic_parse(fd, buffer, &cur_token, &media_basic, progr_rate, progr_fun); if (r != MAILIMAP_NO_ERROR) { res = r; goto err; } r = mailimap_space_parse(fd, buffer, &cur_token); if (r != MAILIMAP_NO_ERROR) { res = r; goto free_media_basic; } r = mailimap_body_fields_parse(fd, buffer, &cur_token, &body_fields, progr_rate, progr_fun); if (r != MAILIMAP_NO_ERROR) { res = r; goto free_media_basic; } body_type_basic = mailimap_body_type_basic_new(media_basic, body_fields); if (body_type_basic == NULL) { res = MAILIMAP_ERROR_MEMORY; goto free_body_fields; } * index = cur_token; * result = body_type_basic; return MAILIMAP_NO_ERROR; free_body_fields: mailimap_body_fields_free(body_fields); free_media_basic: mailimap_media_basic_free(media_basic); err: return res; } /* body-type-mpart = 1*body SP media-subtype [SP body-ext-mpart] */ static int mailimap_body_type_mpart_parse(mailstream * fd, MMAPString * buffer, size_t * index, struct mailimap_body_type_mpart ** result, size_t progr_rate, progress_function * progr_fun) { struct mailimap_body_type_mpart * body_type_mpart; clist * body_list; size_t cur_token; size_t final_token; char * media_subtype; struct mailimap_body_ext_mpart * body_ext_mpart; int r; int res; cur_token = * index; body_list = NULL; media_subtype = NULL; body_ext_mpart = NULL; r = mailimap_struct_multiple_parse(fd, buffer, &cur_token, &body_list, (mailimap_struct_parser *) mailimap_body_parse, (mailimap_struct_destructor *) mailimap_body_free, progr_rate, progr_fun); if (r != MAILIMAP_NO_ERROR) { res = r; goto err; } r = mailimap_space_parse(fd, buffer, &cur_token); if (r != MAILIMAP_NO_ERROR) { res = r; goto free_body_list; } r = mailimap_media_subtype_parse(fd, buffer, &cur_token, &media_subtype, progr_rate, progr_fun); if (r != MAILIMAP_NO_ERROR) { res = r; goto free_body_list; } final_token = cur_token; body_ext_mpart = NULL; r = mailimap_space_parse(fd, buffer, &cur_token); if (r == MAILIMAP_NO_ERROR) { r = mailimap_body_ext_mpart_parse(fd, buffer, &cur_token, &body_ext_mpart, progr_rate, progr_fun); if (r == MAILIMAP_NO_ERROR) final_token = cur_token; else if (r == MAILIMAP_ERROR_PARSE) { /* do nothing */ } else { res = r; goto free_body_list; } } else if (r == MAILIMAP_ERROR_PARSE) { /* do nothing */ } else { res = r; goto free_body_list; } body_type_mpart = mailimap_body_type_mpart_new(body_list, media_subtype, body_ext_mpart); if (body_type_mpart == NULL) { res = MAILIMAP_ERROR_MEMORY; goto free_body_ext_mpart; } * result = body_type_mpart; * index = final_token; return MAILIMAP_NO_ERROR; free_body_ext_mpart: if (body_ext_mpart) mailimap_body_ext_mpart_free(body_ext_mpart); mailimap_media_subtype_free(media_subtype); free_body_list: clist_foreach(body_list, (clist_func) mailimap_body_free, NULL); clist_free(body_list); err: return res; } /* body-type-msg = media-message SP body-fields SP envelope SP body SP body-fld-lines */ static int mailimap_body_type_msg_parse(mailstream * fd, MMAPString * buffer, size_t * index, struct mailimap_body_type_msg ** result, size_t progr_rate, progress_function * progr_fun) { struct mailimap_body_fields * body_fields; struct mailimap_envelope * envelope; struct mailimap_body * body; uint32_t body_fld_lines; struct mailimap_body_type_msg * body_type_msg; size_t cur_token; int r; int res; cur_token = * index; body_fields = NULL; envelope = NULL; body = NULL; body_fld_lines = 0; r = mailimap_media_message_parse(fd, buffer, &cur_token); if (r != MAILIMAP_NO_ERROR) { res = r; goto err; } r = mailimap_space_parse(fd, buffer, &cur_token); if (r != MAILIMAP_NO_ERROR) { res = r; goto err; } r = mailimap_body_fields_parse(fd, buffer, &cur_token, &body_fields, progr_rate, progr_fun); if (r != MAILIMAP_NO_ERROR) { res = r; goto err; } r = mailimap_space_parse(fd, buffer, &cur_token); if (r != MAILIMAP_NO_ERROR) { res = r; goto body_fields; } r = mailimap_envelope_parse(fd, buffer, &cur_token, &envelope, progr_rate, progr_fun); if (r != MAILIMAP_NO_ERROR) { res = r; goto body_fields; } r = mailimap_space_parse(fd, buffer, &cur_token); if (r != MAILIMAP_NO_ERROR) { res = r; goto envelope; } r = mailimap_body_parse(fd, buffer, &cur_token, &body, progr_rate, progr_fun); if (r != MAILIMAP_NO_ERROR) { res = r; goto envelope; } r = mailimap_space_parse(fd, buffer, &cur_token); if (r != MAILIMAP_NO_ERROR) { res = r; goto body; } r = mailimap_body_fld_lines_parse(fd, buffer, &cur_token, &body_fld_lines); if (r != MAILIMAP_NO_ERROR) { res = r; goto body; } body_type_msg = mailimap_body_type_msg_new(body_fields, envelope, body, body_fld_lines); if (body_type_msg == NULL) { res = MAILIMAP_ERROR_MEMORY; goto body; } * result = body_type_msg; * index = cur_token; return MAILIMAP_NO_ERROR; body: mailimap_body_free(body); envelope: mailimap_envelope_free(envelope); body_fields: mailimap_body_fields_free(body_fields); err: return res; } /* body-type-text = media-text SP body-fields SP body-fld-lines */ static int mailimap_body_type_text_parse(mailstream * fd, MMAPString * buffer, size_t * index, struct mailimap_body_type_text ** result, size_t progr_rate, progress_function * progr_fun) { char * media_text; struct mailimap_body_fields * body_fields; uint32_t body_fld_lines; struct mailimap_body_type_text * body_type_text; size_t cur_token; int r; int res; media_text = NULL; body_fields = NULL; body_fld_lines = 0; cur_token = * index; r = mailimap_media_text_parse(fd, buffer, &cur_token, &media_text, progr_rate, progr_fun); if (r != MAILIMAP_NO_ERROR) { res = r; goto err; diff --git a/libetpan/src/low-level/maildir/maildir.c b/libetpan/src/low-level/maildir/maildir.c index 98b9f87..e81625d 100644 --- a/libetpan/src/low-level/maildir/maildir.c +++ b/libetpan/src/low-level/maildir/maildir.c @@ -1,798 +1,811 @@ /* * 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; + //LR + struct stat f_stat; 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); - + + // LR changed following lines + if ( stat( filename, &f_stat ) == -1 ) { + char * dup_filename; + + dup_filename = strdup(filename); + if (dup_filename == NULL) { + //unlink(filename); + return NULL; + } + rename (tmpfile,dup_filename ); +#if 0 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; } - +#endif 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/mh/mailmh.c b/libetpan/src/low-level/mh/mailmh.c index 42cab9d..f8c694d 100644 --- a/libetpan/src/low-level/mh/mailmh.c +++ b/libetpan/src/low-level/mh/mailmh.c @@ -155,835 +155,838 @@ struct mailmh_folder * mailmh_folder_new(struct mailmh_folder * parent, 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); } + // LR memory leak fixed + mailmh_msg_info_free( msg_info ); + free(filename); 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/pop3/mailpop3.c b/libetpan/src/low-level/pop3/mailpop3.c index 6f77a3a..bca62d5 100644 --- a/libetpan/src/low-level/pop3/mailpop3.c +++ b/libetpan/src/low-level/pop3/mailpop3.c @@ -1,1230 +1,1233 @@ /* * 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; + if (r != RESPONSE_OK) { + // LR + fprintf(stderr,"POP3 login error. Response from server:\n%s\n",response ); + 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; } |