summaryrefslogtreecommitdiffabout
authorzautrix <zautrix>2005-03-18 22:05:02 (UTC)
committer zautrix <zautrix>2005-03-18 22:05:02 (UTC)
commit297208a61298fceab6d96bbd1c46198b1c0f7a76 (patch) (side-by-side diff)
tree50f0c6f775393c1eec15b71691a798d1dacab86d
parentf0232b7801f098b5842e3cd5a1fd804af98ab862 (diff)
downloadkdepimpi-297208a61298fceab6d96bbd1c46198b1c0f7a76.zip
kdepimpi-297208a61298fceab6d96bbd1c46198b1c0f7a76.tar.gz
kdepimpi-297208a61298fceab6d96bbd1c46198b1c0f7a76.tar.bz2
fixes applied
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--libetpan/src/data-types/mailstream_helper.c11
-rw-r--r--libetpan/src/driver/implementation/pop3/pop3driver.c8
-rw-r--r--libetpan/src/low-level/imap/mailimap_parser.c22
-rw-r--r--libetpan/src/low-level/maildir/maildir.c17
-rw-r--r--libetpan/src/low-level/mh/mailmh.c3
-rw-r--r--libetpan/src/low-level/pop3/mailpop3.c7
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, &param_list,
(mailimap_struct_parser *)
mailimap_single_body_fld_param_parse,
(mailimap_struct_destructor *)
mailimap_single_body_fld_param_free,
progr_rate, progr_fun);
if (r != MAILIMAP_NO_ERROR) {
res = r;
goto err;
}
r = mailimap_cparenth_parse(fd, buffer, &cur_token);
if (r != MAILIMAP_NO_ERROR) {
res = r;
goto free;
}
fld_param = mailimap_body_fld_param_new(param_list);
if (fld_param == NULL) {
res = MAILIMAP_ERROR_MEMORY;
goto free;
}
* index = cur_token;
* result = fld_param;
return MAILIMAP_NO_ERROR;
free:
clist_foreach(param_list,
(clist_func) mailimap_single_body_fld_param_free,
NULL);
clist_free(param_list);
err:
return res;
}
/*
body-type-1part = (body-type-basic / body-type-msg / body-type-text)
[SP body-ext-1part]
*/
static int
mailimap_body_type_1part_parse(mailstream * fd, MMAPString * buffer,
size_t * index,
struct mailimap_body_type_1part ** result,
size_t progr_rate,
progress_function * progr_fun)
{
size_t cur_token;
struct mailimap_body_type_1part * body_type_1part;
struct mailimap_body_type_basic * body_type_basic;
struct mailimap_body_type_msg * body_type_msg;
struct mailimap_body_type_text * body_type_text;
struct mailimap_body_ext_1part * body_ext_1part;
int type;
size_t final_token;
int r;
int res;
cur_token = * index;
body_type_basic = NULL;
body_type_msg = NULL;
body_type_text = NULL;
body_ext_1part = NULL;
type = MAILIMAP_BODY_TYPE_1PART_ERROR; /* XXX - removes a gcc warning */
r = mailimap_body_type_msg_parse(fd, buffer, &cur_token,
&body_type_msg,
progr_rate, progr_fun);
if (r == MAILIMAP_NO_ERROR)
type = MAILIMAP_BODY_TYPE_1PART_MSG;
if (r == MAILIMAP_ERROR_PARSE) {
r = mailimap_body_type_text_parse(fd, buffer, &cur_token,
&body_type_text,
progr_rate, progr_fun);
if (r == MAILIMAP_NO_ERROR)
type = MAILIMAP_BODY_TYPE_1PART_TEXT;
}
if (r == MAILIMAP_ERROR_PARSE) {
r = mailimap_body_type_basic_parse(fd, buffer, &cur_token,
&body_type_basic,
progr_rate, progr_fun);
if (r == MAILIMAP_NO_ERROR)
type = MAILIMAP_BODY_TYPE_1PART_BASIC;
}
if (r != MAILIMAP_NO_ERROR) {
res = r;
goto err;
}
final_token = cur_token;
body_ext_1part = NULL;
r = mailimap_space_parse(fd, buffer, &cur_token);
if (r == MAILIMAP_NO_ERROR) {
r = mailimap_body_ext_1part_parse(fd, buffer, &cur_token, &body_ext_1part,
progr_rate, progr_fun);
if (r == MAILIMAP_NO_ERROR)
final_token = cur_token;
else if (r == MAILIMAP_ERROR_PARSE) {
/* do nothing */
}
else {
res = r;
goto free;
}
}
else if (r == MAILIMAP_ERROR_PARSE) {
/* do nothing */
}
else {
res = r;
goto free;
}
body_type_1part = mailimap_body_type_1part_new(type, body_type_basic,
body_type_msg, body_type_text,
body_ext_1part);
if (body_type_1part == NULL) {
res = MAILIMAP_ERROR_MEMORY;
goto free;
}
* index = final_token;
* result = body_type_1part;
return MAILIMAP_NO_ERROR;
free:
if (body_type_basic)
mailimap_body_type_basic_free(body_type_basic);
if (body_type_msg)
mailimap_body_type_msg_free(body_type_msg);
if (body_type_text)
mailimap_body_type_text_free(body_type_text);
if (body_ext_1part)
mailimap_body_ext_1part_free(body_ext_1part);
err:
return res;
}
/*
body-type-basic = media-basic SP body-fields
; MESSAGE subtype MUST NOT be "RFC822"
*/
static int
mailimap_body_type_basic_parse(mailstream * fd, MMAPString * buffer,
size_t * index,
struct mailimap_body_type_basic ** result,
size_t progr_rate,
progress_function * progr_fun)
{
size_t cur_token;
struct mailimap_body_type_basic * body_type_basic;
struct mailimap_media_basic * media_basic;
struct mailimap_body_fields * body_fields;
int r;
int res;
cur_token = * index;
media_basic = NULL;
body_fields = NULL;
r = mailimap_media_basic_parse(fd, buffer, &cur_token, &media_basic,
progr_rate, progr_fun);
if (r != MAILIMAP_NO_ERROR) {
res = r;
goto err;
}
r = mailimap_space_parse(fd, buffer, &cur_token);
if (r != MAILIMAP_NO_ERROR) {
res = r;
goto free_media_basic;
}
r = mailimap_body_fields_parse(fd, buffer, &cur_token, &body_fields,
progr_rate, progr_fun);
if (r != MAILIMAP_NO_ERROR) {
res = r;
goto free_media_basic;
}
body_type_basic = mailimap_body_type_basic_new(media_basic, body_fields);
if (body_type_basic == NULL) {
res = MAILIMAP_ERROR_MEMORY;
goto free_body_fields;
}
* index = cur_token;
* result = body_type_basic;
return MAILIMAP_NO_ERROR;
free_body_fields:
mailimap_body_fields_free(body_fields);
free_media_basic:
mailimap_media_basic_free(media_basic);
err:
return res;
}
/*
body-type-mpart = 1*body SP media-subtype
[SP body-ext-mpart]
*/
static int
mailimap_body_type_mpart_parse(mailstream * fd,
MMAPString * buffer,
size_t * index,
struct mailimap_body_type_mpart ** result,
size_t progr_rate,
progress_function * progr_fun)
{
struct mailimap_body_type_mpart * body_type_mpart;
clist * body_list;
size_t cur_token;
size_t final_token;
char * media_subtype;
struct mailimap_body_ext_mpart * body_ext_mpart;
int r;
int res;
cur_token = * index;
body_list = NULL;
media_subtype = NULL;
body_ext_mpart = NULL;
r = mailimap_struct_multiple_parse(fd, buffer, &cur_token,
&body_list,
(mailimap_struct_parser *)
mailimap_body_parse,
(mailimap_struct_destructor *)
mailimap_body_free,
progr_rate, progr_fun);
if (r != MAILIMAP_NO_ERROR) {
res = r;
goto err;
}
r = mailimap_space_parse(fd, buffer, &cur_token);
if (r != MAILIMAP_NO_ERROR) {
res = r;
goto free_body_list;
}
r = mailimap_media_subtype_parse(fd, buffer, &cur_token, &media_subtype,
progr_rate, progr_fun);
if (r != MAILIMAP_NO_ERROR) {
res = r;
goto free_body_list;
}
final_token = cur_token;
body_ext_mpart = NULL;
r = mailimap_space_parse(fd, buffer, &cur_token);
if (r == MAILIMAP_NO_ERROR) {
r = mailimap_body_ext_mpart_parse(fd, buffer, &cur_token, &body_ext_mpart,
progr_rate, progr_fun);
if (r == MAILIMAP_NO_ERROR)
final_token = cur_token;
else if (r == MAILIMAP_ERROR_PARSE) {
/* do nothing */
}
else {
res = r;
goto free_body_list;
}
}
else if (r == MAILIMAP_ERROR_PARSE) {
/* do nothing */
}
else {
res = r;
goto free_body_list;
}
body_type_mpart = mailimap_body_type_mpart_new(body_list, media_subtype,
body_ext_mpart);
if (body_type_mpart == NULL) {
res = MAILIMAP_ERROR_MEMORY;
goto free_body_ext_mpart;
}
* result = body_type_mpart;
* index = final_token;
return MAILIMAP_NO_ERROR;
free_body_ext_mpart:
if (body_ext_mpart)
mailimap_body_ext_mpart_free(body_ext_mpart);
mailimap_media_subtype_free(media_subtype);
free_body_list:
clist_foreach(body_list, (clist_func) mailimap_body_free, NULL);
clist_free(body_list);
err:
return res;
}
/*
body-type-msg = media-message SP body-fields SP envelope
SP body SP body-fld-lines
*/
static int
mailimap_body_type_msg_parse(mailstream * fd, MMAPString * buffer,
size_t * index,
struct mailimap_body_type_msg ** result,
size_t progr_rate,
progress_function * progr_fun)
{
struct mailimap_body_fields * body_fields;
struct mailimap_envelope * envelope;
struct mailimap_body * body;
uint32_t body_fld_lines;
struct mailimap_body_type_msg * body_type_msg;
size_t cur_token;
int r;
int res;
cur_token = * index;
body_fields = NULL;
envelope = NULL;
body = NULL;
body_fld_lines = 0;
r = mailimap_media_message_parse(fd, buffer, &cur_token);
if (r != MAILIMAP_NO_ERROR) {
res = r;
goto err;
}
r = mailimap_space_parse(fd, buffer, &cur_token);
if (r != MAILIMAP_NO_ERROR) {
res = r;
goto err;
}
r = mailimap_body_fields_parse(fd, buffer, &cur_token, &body_fields,
progr_rate, progr_fun);
if (r != MAILIMAP_NO_ERROR) {
res = r;
goto err;
}
r = mailimap_space_parse(fd, buffer, &cur_token);
if (r != MAILIMAP_NO_ERROR) {
res = r;
goto body_fields;
}
r = mailimap_envelope_parse(fd, buffer, &cur_token, &envelope,
progr_rate, progr_fun);
if (r != MAILIMAP_NO_ERROR) {
res = r;
goto body_fields;
}
r = mailimap_space_parse(fd, buffer, &cur_token);
if (r != MAILIMAP_NO_ERROR) {
res = r;
goto envelope;
}
r = mailimap_body_parse(fd, buffer, &cur_token, &body,
progr_rate, progr_fun);
if (r != MAILIMAP_NO_ERROR) {
res = r;
goto envelope;
}
r = mailimap_space_parse(fd, buffer, &cur_token);
if (r != MAILIMAP_NO_ERROR) {
res = r;
goto body;
}
r = mailimap_body_fld_lines_parse(fd, buffer, &cur_token,
&body_fld_lines);
if (r != MAILIMAP_NO_ERROR) {
res = r;
goto body;
}
body_type_msg = mailimap_body_type_msg_new(body_fields, envelope,
body, body_fld_lines);
if (body_type_msg == NULL) {
res = MAILIMAP_ERROR_MEMORY;
goto body;
}
* result = body_type_msg;
* index = cur_token;
return MAILIMAP_NO_ERROR;
body:
mailimap_body_free(body);
envelope:
mailimap_envelope_free(envelope);
body_fields:
mailimap_body_fields_free(body_fields);
err:
return res;
}
/*
body-type-text = media-text SP body-fields SP body-fld-lines
*/
static int
mailimap_body_type_text_parse(mailstream * fd, MMAPString * buffer,
size_t * index,
struct mailimap_body_type_text **
result,
size_t progr_rate,
progress_function * progr_fun)
{
char * media_text;
struct mailimap_body_fields * body_fields;
uint32_t body_fld_lines;
struct mailimap_body_type_text * body_type_text;
size_t cur_token;
int r;
int res;
media_text = NULL;
body_fields = NULL;
body_fld_lines = 0;
cur_token = * index;
r = mailimap_media_text_parse(fd, buffer, &cur_token, &media_text,
progr_rate, progr_fun);
if (r != MAILIMAP_NO_ERROR) {
res = r;
goto err;
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;
}