summaryrefslogtreecommitdiffabout
path: root/libetpan/src/low-level/pop3/mailpop3.c
Side-by-side diff
Diffstat (limited to 'libetpan/src/low-level/pop3/mailpop3.c') (more/less context) (ignore whitespace changes)
-rw-r--r--libetpan/src/low-level/pop3/mailpop3.c1230
1 files changed, 1230 insertions, 0 deletions
diff --git a/libetpan/src/low-level/pop3/mailpop3.c b/libetpan/src/low-level/pop3/mailpop3.c
new file mode 100644
index 0000000..6f77a3a
--- a/dev/null
+++ b/libetpan/src/low-level/pop3/mailpop3.c
@@ -0,0 +1,1230 @@
+/*
+ * libEtPan! -- a mail stuff library
+ *
+ * Copyright (C) 2001, 2005 - DINH Viet Hoa
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the libEtPan! project nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * $Id$
+ */
+
+/*
+ POP3 Protocol
+
+ RFC 1734
+ RFC 1939
+ RFC 2449
+
+ */
+
+#include "mailpop3.h"
+#include <stdio.h>
+#include <string.h>
+#include "md5.h"
+#include "mail.h"
+#include <stdlib.h>
+
+
+
+
+enum {
+ POP3_STATE_DISCONNECTED,
+ POP3_STATE_AUTHORIZATION,
+ POP3_STATE_TRANSACTION
+};
+
+
+
+/*
+ mailpop3_msg_info structure
+*/
+
+static struct mailpop3_msg_info *
+mailpop3_msg_info_new(unsigned int index, uint32_t size, char * uidl)
+{
+ struct mailpop3_msg_info * msg;
+
+ msg = malloc(sizeof(* msg));
+ if (msg == NULL)
+ return NULL;
+ msg->msg_index = index;
+ msg->msg_size = size;
+ msg->msg_deleted = FALSE;
+ msg->msg_uidl = uidl;
+
+ return msg;
+}
+
+static void mailpop3_msg_info_free(struct mailpop3_msg_info * msg)
+{
+ if (msg->msg_uidl != NULL)
+ free(msg->msg_uidl);
+ free(msg);
+}
+
+static void mailpop3_msg_info_tab_free(carray * msg_tab)
+{
+ unsigned int i;
+
+ for(i = 0 ; i < carray_count(msg_tab) ; i++) {
+ struct mailpop3_msg_info * msg;
+
+ msg = carray_get(msg_tab, i);
+ mailpop3_msg_info_free(msg);
+ }
+ carray_free(msg_tab);
+}
+
+static void mailpop3_msg_info_tab_reset(carray * msg_tab)
+{
+ unsigned int i;
+
+ for(i = 0 ; i < carray_count(msg_tab) ; i++) {
+ struct mailpop3_msg_info * msg;
+ msg = carray_get(msg_tab, i);
+ msg->msg_deleted = FALSE;
+ }
+}
+
+static inline struct mailpop3_msg_info *
+mailpop3_msg_info_tab_find_msg(carray * msg_tab, unsigned int index)
+{
+ struct mailpop3_msg_info * msg;
+
+ if (index == 0)
+ return NULL;
+
+ if (index > carray_count(msg_tab))
+ return NULL;
+
+ msg = carray_get(msg_tab, index - 1);
+
+ return msg;
+}
+
+
+
+int mailpop3_get_msg_info(mailpop3 * f, unsigned int index,
+ struct mailpop3_msg_info ** result)
+{
+ carray * tab;
+ struct mailpop3_msg_info * info;
+
+ mailpop3_list(f, &tab);
+
+ if (tab == NULL)
+ return MAILPOP3_ERROR_BAD_STATE;
+
+ info = mailpop3_msg_info_tab_find_msg(tab, index);
+ if (info == NULL)
+ return MAILPOP3_ERROR_NO_SUCH_MESSAGE;
+
+ * result = info;
+
+ return MAILPOP3_NO_ERROR;
+}
+
+
+/*
+ mailpop3_capa
+*/
+
+struct mailpop3_capa * mailpop3_capa_new(char * name, clist * param)
+{
+ struct mailpop3_capa * capa;
+
+ capa = malloc(sizeof(* capa));
+ if (capa == NULL)
+ return NULL;
+ capa->cap_name = name;
+ capa->cap_param = param;
+
+ return capa;
+}
+
+
+void mailpop3_capa_free(struct mailpop3_capa * capa)
+{
+ clist_foreach(capa->cap_param, (clist_func) free, NULL);
+ clist_free(capa->cap_param);
+ free(capa->cap_name);
+ free(capa);
+}
+
+/*
+ mailpop3 structure
+*/
+
+mailpop3 * mailpop3_new(size_t progr_rate, progress_function * progr_fun)
+{
+ mailpop3 * f;
+
+ f = malloc(sizeof(* f));
+ if (f == NULL)
+ goto err;
+
+ f->pop3_timestamp = NULL;
+ f->pop3_response = NULL;
+
+ f->pop3_stream = NULL;
+
+ f->pop3_progr_rate = progr_rate;
+ f->pop3_progr_fun = progr_fun;
+
+ f->pop3_stream_buffer = mmap_string_new("");
+ if (f->pop3_stream_buffer == NULL)
+ goto free_f;
+
+ f->pop3_response_buffer = mmap_string_new("");
+ if (f->pop3_response_buffer == NULL)
+ goto free_stream_buffer;
+
+ f->pop3_msg_tab = NULL;
+ f->pop3_deleted_count = 0;
+ f->pop3_state = POP3_STATE_DISCONNECTED;
+
+ return f;
+
+ free_stream_buffer:
+ mmap_string_free(f->pop3_stream_buffer);
+ free_f:
+ free(f);
+ err:
+ return NULL;
+}
+
+
+
+void mailpop3_free(mailpop3 * f)
+{
+ if (f->pop3_stream)
+ mailpop3_quit(f);
+
+ mmap_string_free(f->pop3_response_buffer);
+ mmap_string_free(f->pop3_stream_buffer);
+
+ free(f);
+}
+
+
+
+
+
+
+
+
+
+
+
+/*
+ operations on mailpop3 structure
+*/
+
+#define RESPONSE_OK 0
+#define RESPONSE_ERR -1
+
+static int send_command(mailpop3 * f, char * command);
+
+static char * read_line(mailpop3 * f);
+
+static char * read_multiline(mailpop3 * f, size_t size,
+ MMAPString * multiline_buffer);
+
+static int parse_response(mailpop3 * f, char * response);
+
+
+/* get the timestamp in the connection response */
+
+#define TIMESTAMP_START '<'
+#define TIMESTAMP_END '>'
+
+static char * mailpop3_get_timestamp(char * response)
+{
+ char * begin_timestamp;
+ char * end_timestamp;
+ char * timestamp;
+ int len_timestamp;
+
+ if (response == NULL)
+ return NULL;
+
+ begin_timestamp = strchr(response, TIMESTAMP_START);
+
+ end_timestamp = NULL;
+ if (begin_timestamp != NULL) {
+ end_timestamp = strchr(begin_timestamp, TIMESTAMP_END);
+ if (end_timestamp == NULL)
+ begin_timestamp = NULL;
+ }
+
+ if (!begin_timestamp)
+ return NULL;
+
+ len_timestamp = end_timestamp - begin_timestamp + 1;
+
+ timestamp = malloc(len_timestamp + 1);
+ if (timestamp == NULL)
+ return NULL;
+ strncpy(timestamp, begin_timestamp, len_timestamp);
+ timestamp[len_timestamp] = '\0';
+
+ return timestamp;
+}
+
+/*
+ connect a stream to the mailpop3 structure
+*/
+
+int mailpop3_connect(mailpop3 * f, mailstream * s)
+{
+ char * response;
+ int r;
+ char * timestamp;
+
+ if (f->pop3_state != POP3_STATE_DISCONNECTED)
+ return MAILPOP3_ERROR_BAD_STATE;
+
+ f->pop3_stream = s;
+
+ response = read_line(f);
+
+ r = parse_response(f, response);
+ if (r != RESPONSE_OK)
+ return MAILPOP3_ERROR_UNAUTHORIZED;
+
+ f->pop3_state = POP3_STATE_AUTHORIZATION;
+
+ timestamp = mailpop3_get_timestamp(f->pop3_response);
+ if (timestamp != NULL)
+ f->pop3_timestamp = timestamp;
+
+ return MAILPOP3_NO_ERROR;
+}
+
+
+/*
+ disconnect from a pop3 server
+*/
+
+int mailpop3_quit(mailpop3 * f)
+{
+ char command[POP3_STRING_SIZE];
+ char * response;
+ int r;
+ int res;
+
+ if ((f->pop3_state != POP3_STATE_AUTHORIZATION)
+ && (f->pop3_state != POP3_STATE_TRANSACTION)) {
+ res = MAILPOP3_ERROR_BAD_STATE;
+ goto close;
+ }
+
+ snprintf(command, POP3_STRING_SIZE, "QUIT\r\n");
+ r = send_command(f, command);
+ if (r == -1) {
+ res = MAILPOP3_ERROR_STREAM;
+ goto close;
+ }
+
+ response = read_line(f);
+ if (response == NULL) {
+ res = MAILPOP3_ERROR_STREAM;
+ goto close;
+ }
+ parse_response(f, response);
+
+ res = MAILPOP3_NO_ERROR;
+
+ close:
+ mailstream_close(f->pop3_stream);
+
+ if (f->pop3_timestamp != NULL) {
+ free(f->pop3_timestamp);
+ f->pop3_timestamp = NULL;
+ }
+
+ f->pop3_stream = NULL;
+ if (f->pop3_msg_tab != NULL) {
+ mailpop3_msg_info_tab_free(f->pop3_msg_tab);
+ f->pop3_msg_tab = NULL;
+ }
+
+ f->pop3_state = POP3_STATE_DISCONNECTED;
+
+ return res;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+int mailpop3_apop(mailpop3 * f,
+ const char * user, const char * password)
+{
+ char command[POP3_STRING_SIZE];
+ MD5_CTX md5context;
+ unsigned char md5digest[16];
+ char md5string[33];
+ char * cmd_ptr;
+ int r;
+ int i;
+ char * response;
+
+ if (f->pop3_state != POP3_STATE_AUTHORIZATION)
+ return MAILPOP3_ERROR_BAD_STATE;
+
+ if (f->pop3_timestamp == NULL)
+ return MAILPOP3_ERROR_APOP_NOT_SUPPORTED;
+
+ /* calculate md5 sum */
+
+ MD5Init(&md5context);
+ MD5Update(&md5context, f->pop3_timestamp, strlen (f->pop3_timestamp));
+ MD5Update(&md5context, password, strlen (password));
+ MD5Final(md5digest, &md5context);
+
+ cmd_ptr = md5string;
+ for(i = 0 ; i < 16 ; i++, cmd_ptr += 2)
+ snprintf(cmd_ptr, 3, "%02x", md5digest[i]);
+ * cmd_ptr = 0;
+
+ /* send apop command */
+
+ snprintf(command, POP3_STRING_SIZE, "APOP %s %s\r\n", user, md5string);
+ r = send_command(f, command);
+ if (r == -1)
+ return MAILPOP3_ERROR_STREAM;
+
+ response = read_line(f);
+
+ if (response == NULL)
+ return MAILPOP3_ERROR_STREAM;
+ r = parse_response(f, response);
+ if (r != RESPONSE_OK)
+ return MAILPOP3_ERROR_DENIED;
+
+ f->pop3_state = POP3_STATE_TRANSACTION;
+
+ return MAILPOP3_NO_ERROR;
+}
+
+int mailpop3_user(mailpop3 * f, const char * user)
+{
+ char command[POP3_STRING_SIZE];
+ int r;
+ char * response;
+
+ if (f->pop3_state != POP3_STATE_AUTHORIZATION)
+ return MAILPOP3_ERROR_BAD_STATE;
+
+ /* send user command */
+
+ snprintf(command, POP3_STRING_SIZE, "USER %s\r\n", user);
+ r = send_command(f, command);
+ if (r == -1)
+ return MAILPOP3_ERROR_STREAM;
+
+ response = read_line(f);
+ if (response == NULL)
+ return MAILPOP3_ERROR_STREAM;
+ r = parse_response(f, response);
+
+ if (r != RESPONSE_OK)
+ return MAILPOP3_ERROR_BAD_USER;
+
+ return MAILPOP3_NO_ERROR;
+}
+
+int mailpop3_pass(mailpop3 * f, const char * password)
+{
+ char command[POP3_STRING_SIZE];
+ int r;
+ char * response;
+
+ if (f->pop3_state != POP3_STATE_AUTHORIZATION)
+ return MAILPOP3_ERROR_BAD_STATE;
+
+ /* send password command */
+
+ snprintf(command, POP3_STRING_SIZE, "PASS %s\r\n", password);
+ r = send_command(f, command);
+ if (r == -1)
+ return MAILPOP3_ERROR_STREAM;
+
+ response = read_line(f);
+ if (response == NULL)
+ return MAILPOP3_ERROR_STREAM;
+ r = parse_response(f, response);
+
+ if (r != RESPONSE_OK)
+ return MAILPOP3_ERROR_BAD_PASSWORD;
+
+ f->pop3_state = POP3_STATE_TRANSACTION;
+
+ return MAILPOP3_NO_ERROR;
+}
+
+static int read_list(mailpop3 * f, carray ** result);
+
+
+
+static int read_uidl(mailpop3 * f, carray * msg_tab);
+
+
+
+static int mailpop3_do_uidl(mailpop3 * f, carray * msg_tab)
+{
+ char command[POP3_STRING_SIZE];
+ int r;
+ char * response;
+
+ if (f->pop3_state != POP3_STATE_TRANSACTION)
+ return MAILPOP3_ERROR_BAD_STATE;
+
+ /* send list command */
+
+ snprintf(command, POP3_STRING_SIZE, "UIDL\r\n");
+ r = send_command(f, command);
+ if (r == -1)
+ return MAILPOP3_ERROR_STREAM;
+
+ response = read_line(f);
+ if (response == NULL)
+ return MAILPOP3_ERROR_STREAM;
+ r = parse_response(f, response);
+
+ if (r != RESPONSE_OK)
+ return MAILPOP3_ERROR_CANT_LIST;
+
+ r = read_uidl(f, msg_tab);
+ if (r != MAILPOP3_NO_ERROR)
+ return r;
+
+ return MAILPOP3_NO_ERROR;
+}
+
+
+
+static int mailpop3_do_list(mailpop3 * f)
+{
+ char command[POP3_STRING_SIZE];
+ int r;
+ carray * msg_tab;
+ char * response;
+
+ if (f->pop3_msg_tab != NULL) {
+ mailpop3_msg_info_tab_free(f->pop3_msg_tab);
+ f->pop3_msg_tab = NULL;
+ }
+
+ if (f->pop3_state != POP3_STATE_TRANSACTION)
+ return MAILPOP3_ERROR_BAD_STATE;
+
+ /* send list command */
+
+ snprintf(command, POP3_STRING_SIZE, "LIST\r\n");
+ r = send_command(f, command);
+ if (r == -1)
+ return MAILPOP3_ERROR_STREAM;
+
+ response = read_line(f);
+ if (response == NULL)
+ return MAILPOP3_ERROR_STREAM;
+ r = parse_response(f, response);
+
+ if (r != RESPONSE_OK)
+ return MAILPOP3_ERROR_CANT_LIST;
+
+ r = read_list(f, &msg_tab);
+ if (r != MAILPOP3_NO_ERROR)
+ return r;
+
+ f->pop3_msg_tab = msg_tab;
+ f->pop3_deleted_count = 0;
+
+ mailpop3_do_uidl(f, msg_tab);
+
+ return MAILPOP3_NO_ERROR;
+}
+
+
+
+static void mailpop3_list_if_needed(mailpop3 * f)
+{
+ if (f->pop3_msg_tab == NULL)
+ mailpop3_do_list(f);
+}
+
+/*
+ mailpop3_list
+*/
+
+void mailpop3_list(mailpop3 * f, carray ** result)
+{
+ mailpop3_list_if_needed(f);
+ * result = f->pop3_msg_tab;
+}
+
+static inline struct mailpop3_msg_info *
+find_msg(mailpop3 * f, unsigned int index)
+{
+ mailpop3_list_if_needed(f);
+
+ if (f->pop3_msg_tab == NULL)
+ return NULL;
+
+ return mailpop3_msg_info_tab_find_msg(f->pop3_msg_tab, index);
+}
+
+
+
+
+
+
+
+
+static void mailpop3_multiline_response_free(char * str)
+{
+ mmap_string_unref(str);
+}
+
+void mailpop3_top_free(char * str)
+{
+ mailpop3_multiline_response_free(str);
+}
+
+void mailpop3_retr_free(char * str)
+{
+ mailpop3_multiline_response_free(str);
+}
+
+/*
+ mailpop3_retr
+
+ message content in (* result) is still there until the
+ next retrieve or top operation on the mailpop3 structure
+*/
+
+static int
+mailpop3_get_content(mailpop3 * f, struct mailpop3_msg_info * msginfo,
+ char ** result, size_t * result_len)
+{
+ char * response;
+ char * result_multiline;
+ MMAPString * buffer;
+ int r;
+
+ response = read_line(f);
+ if (response == NULL)
+ return MAILPOP3_ERROR_STREAM;
+ r = parse_response(f, response);
+ if (r != RESPONSE_OK)
+ return MAILPOP3_ERROR_NO_SUCH_MESSAGE;
+
+ buffer = mmap_string_new("");
+ if (buffer == NULL)
+ return MAILPOP3_ERROR_MEMORY;
+
+ result_multiline = read_multiline(f, msginfo->msg_size, buffer);
+ if (result_multiline == NULL) {
+ mmap_string_free(buffer);
+ return MAILPOP3_ERROR_STREAM;
+ }
+ else {
+ r = mmap_string_ref(buffer);
+ if (r < 0) {
+ mmap_string_free(buffer);
+ return MAILPOP3_ERROR_MEMORY;
+ }
+
+ * result = result_multiline;
+ * result_len = buffer->len;
+ return MAILPOP3_NO_ERROR;
+ }
+}
+
+int mailpop3_retr(mailpop3 * f, unsigned int index, char ** result,
+ size_t * result_len)
+{
+ char command[POP3_STRING_SIZE];
+ struct mailpop3_msg_info * msginfo;
+ int r;
+
+ if (f->pop3_state != POP3_STATE_TRANSACTION)
+ return MAILPOP3_ERROR_BAD_STATE;
+
+ msginfo = find_msg(f, index);
+
+ if (msginfo == NULL) {
+ f->pop3_response = NULL;
+ return MAILPOP3_ERROR_NO_SUCH_MESSAGE;
+ }
+
+ snprintf(command, POP3_STRING_SIZE, "RETR %i\r\n", index);
+ r = send_command(f, command);
+ if (r == -1)
+ return MAILPOP3_ERROR_STREAM;
+
+ return mailpop3_get_content(f, msginfo, result, result_len);
+}
+
+int mailpop3_top(mailpop3 * f, unsigned int index,
+ unsigned int count, char ** result,
+ size_t * result_len)
+{
+ char command[POP3_STRING_SIZE];
+ struct mailpop3_msg_info * msginfo;
+ int r;
+
+ if (f->pop3_state != POP3_STATE_TRANSACTION)
+ return MAILPOP3_ERROR_BAD_STATE;
+
+ msginfo = find_msg(f, index);
+
+ if (msginfo == NULL) {
+ f->pop3_response = NULL;
+ return MAILPOP3_ERROR_NO_SUCH_MESSAGE;
+ }
+
+ snprintf(command, POP3_STRING_SIZE, "TOP %i %i\r\n", index, count);
+ r = send_command(f, command);
+ if (r == -1)
+ return MAILPOP3_ERROR_STREAM;
+
+ return mailpop3_get_content(f, msginfo, result, result_len);
+}
+
+int mailpop3_dele(mailpop3 * f, unsigned int index)
+{
+ char command[POP3_STRING_SIZE];
+ struct mailpop3_msg_info * msginfo;
+ char * response;
+ int r;
+
+ if (f->pop3_state != POP3_STATE_TRANSACTION)
+ return MAILPOP3_ERROR_BAD_STATE;
+
+ msginfo = find_msg(f, index);
+
+ if (msginfo == NULL) {
+ f->pop3_response = NULL;
+ return MAILPOP3_ERROR_NO_SUCH_MESSAGE;
+ }
+
+ snprintf(command, POP3_STRING_SIZE, "DELE %i\r\n", index);
+ r = send_command(f, command);
+ if (r == -1)
+ return MAILPOP3_ERROR_STREAM;
+
+ response = read_line(f);
+ if (response == NULL)
+ return MAILPOP3_ERROR_STREAM;
+ r = parse_response(f, response);
+ if (r != RESPONSE_OK)
+ return MAILPOP3_ERROR_NO_SUCH_MESSAGE;
+
+ msginfo->msg_deleted = TRUE;
+ f->pop3_deleted_count ++;
+
+ return MAILPOP3_NO_ERROR;
+}
+
+int mailpop3_noop(mailpop3 * f)
+{
+ char command[POP3_STRING_SIZE];
+ char * response;
+ int r;
+
+ if (f->pop3_state != POP3_STATE_TRANSACTION)
+ return MAILPOP3_ERROR_BAD_STATE;
+
+ snprintf(command, POP3_STRING_SIZE, "NOOP\r\n");
+ r = send_command(f, command);
+ if (r == -1)
+ return MAILPOP3_ERROR_STREAM;
+
+ response = read_line(f);
+ if (response == NULL)
+ return MAILPOP3_ERROR_STREAM;
+ parse_response(f, response);
+
+ return MAILPOP3_NO_ERROR;
+}
+
+int mailpop3_rset(mailpop3 * f)
+{
+ char command[POP3_STRING_SIZE];
+ char * response;
+ int r;
+
+ if (f->pop3_state != POP3_STATE_TRANSACTION)
+ return MAILPOP3_ERROR_BAD_STATE;
+
+ snprintf(command, POP3_STRING_SIZE, "RSET\r\n");
+ r = send_command(f, command);
+ if (r == -1)
+ return MAILPOP3_ERROR_STREAM;
+
+ response = read_line(f);
+ if (response == NULL)
+ return MAILPOP3_ERROR_STREAM;
+ parse_response(f, response);
+
+ if (f->pop3_msg_tab != NULL) {
+ mailpop3_msg_info_tab_reset(f->pop3_msg_tab);
+ f->pop3_deleted_count = 0;
+ }
+
+ return MAILPOP3_NO_ERROR;
+}
+
+
+
+static int read_capa_resp(mailpop3 * f, clist ** result);
+
+int mailpop3_capa(mailpop3 * f, clist ** result)
+{
+ clist * capa_list;
+ char command[POP3_STRING_SIZE];
+ int r;
+ char * response;
+
+ snprintf(command, POP3_STRING_SIZE, "CAPA\r\n");
+ r = send_command(f, command);
+ if (r == -1)
+ return MAILPOP3_ERROR_STREAM;
+
+ response = read_line(f);
+ if (response == NULL)
+ return MAILPOP3_ERROR_STREAM;
+ r = parse_response(f, response);
+
+ if (r != RESPONSE_OK)
+ return MAILPOP3_ERROR_CAPA_NOT_SUPPORTED;
+
+ r = read_capa_resp(f, &capa_list);
+ if (r != MAILPOP3_NO_ERROR)
+ return r;
+
+ * result = capa_list;
+
+ return MAILPOP3_NO_ERROR;
+}
+
+void mailpop3_capa_resp_free(clist * capa_list)
+{
+ clist_foreach(capa_list, (clist_func) mailpop3_capa_free, NULL);
+ clist_free(capa_list);
+}
+
+int mailpop3_stls(mailpop3 * f)
+{
+ char command[POP3_STRING_SIZE];
+ int r;
+ char * response;
+
+ snprintf(command, POP3_STRING_SIZE, "STLS\r\n");
+ r = send_command(f, command);
+ if (r == -1)
+ return MAILPOP3_ERROR_STREAM;
+
+ response = read_line(f);
+ if (response == NULL)
+ return MAILPOP3_ERROR_STREAM;
+ r = parse_response(f, response);
+
+ if (r != RESPONSE_OK)
+ return MAILPOP3_ERROR_STLS_NOT_SUPPORTED;
+
+ return MAILPOP3_NO_ERROR;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#define RESP_OK_STR "+OK"
+#define RESP_ERR_STR "-ERR"
+
+
+static int parse_space(char ** line)
+{
+ char * p;
+
+ p = * line;
+
+ while ((* p == ' ') || (* p == '\t'))
+ p ++;
+
+ if (p != * line) {
+ * line = p;
+ return TRUE;
+ }
+ else
+ return FALSE;
+}
+
+static char * cut_token(char * line)
+{
+ char * p;
+ char * p_tab;
+ char * p_space;
+
+ p = line;
+
+ p_space = strchr(line, ' ');
+ p_tab = strchr(line, '\t');
+ if (p_tab == NULL)
+ p = p_space;
+ else if (p_space == NULL)
+ p = p_tab;
+ else {
+ if (p_tab < p_space)
+ p = p_tab;
+ else
+ p = p_space;
+ }
+ if (p == NULL)
+ return NULL;
+ * p = 0;
+ p ++;
+
+ return p;
+}
+
+
+static int parse_response(mailpop3 * f, char * response)
+{
+ char * msg;
+
+ if (response == NULL) {
+ f->pop3_response = NULL;
+ return RESPONSE_ERR;
+ }
+
+ if (strncmp(response, RESP_OK_STR, strlen(RESP_OK_STR)) == 0) {
+
+ if (response[strlen(RESP_OK_STR)] == ' ')
+ msg = response + strlen(RESP_OK_STR) + 1;
+ else
+ msg = response + strlen(RESP_OK_STR);
+
+ if (mmap_string_assign(f->pop3_response_buffer, msg))
+ f->pop3_response = f->pop3_response_buffer->str;
+ else
+ f->pop3_response = NULL;
+
+ return RESPONSE_OK;
+ }
+ else if (strncmp(response, RESP_ERR_STR, strlen(RESP_ERR_STR)) == 0) {
+
+ if (response[strlen(RESP_ERR_STR)] == ' ')
+ msg = response + strlen(RESP_ERR_STR) + 1;
+ else
+ msg = response + strlen(RESP_ERR_STR);
+
+ if (mmap_string_assign(f->pop3_response_buffer, msg))
+ f->pop3_response = f->pop3_response_buffer->str;
+ else
+ f->pop3_response = NULL;
+ }
+
+ f->pop3_response = NULL;
+ return RESPONSE_ERR;
+}
+
+
+
+
+
+
+
+static int read_list(mailpop3 * f, carray ** result)
+{
+ unsigned int index;
+ uint32_t size;
+ carray * msg_tab;
+ struct mailpop3_msg_info * msg;
+ char * line;
+
+ msg_tab = carray_new(128);
+ if (msg_tab == NULL)
+ goto err;
+
+ while (1) {
+ line = read_line(f);
+ if (line == NULL)
+ goto free_list;
+
+ if (mailstream_is_end_multiline(line))
+ break;
+
+ index = strtol(line, &line, 10);
+
+ if (!parse_space(&line))
+ continue;
+
+ size = strtol(line, &line, 10);
+
+ msg = mailpop3_msg_info_new(index, size, NULL);
+ if (msg == NULL)
+ goto free_list;
+
+ if (carray_count(msg_tab) < index) {
+ int r;
+
+ r = carray_set_size(msg_tab, index);
+ if (r == -1)
+ goto free_list;
+ }
+
+ carray_set(msg_tab, index - 1, msg);
+ }
+
+ * result = msg_tab;
+
+ return MAILPOP3_NO_ERROR;
+
+ free_list:
+ mailpop3_msg_info_tab_free(msg_tab);
+ err:
+ return MAILPOP3_ERROR_STREAM;
+}
+
+
+
+static int read_uidl(mailpop3 * f, carray * msg_tab)
+{
+ unsigned int index;
+ struct mailpop3_msg_info * msg;
+ char * line;
+
+ while (1) {
+ char * uidl;
+
+ line = read_line(f);
+ if (line == NULL)
+ goto err;
+
+ if (mailstream_is_end_multiline(line))
+ break;
+
+ index = strtol(line, &line, 10);
+
+ if (!parse_space(&line))
+ continue;
+
+ uidl = strdup(line);
+ if (uidl == NULL)
+ continue;
+
+ if (index > carray_count(msg_tab)) {
+ free(uidl);
+ continue;
+ }
+
+ msg = carray_get(msg_tab, index - 1);
+ if (msg == NULL) {
+ free(uidl);
+ continue;
+ }
+
+ msg->msg_uidl = uidl;
+ }
+
+ return MAILPOP3_NO_ERROR;
+
+ err:
+ return MAILPOP3_ERROR_STREAM;
+}
+
+
+
+static int read_capa_resp(mailpop3 * f, clist ** result)
+{
+ char * line;
+ int res;
+ clist * list;
+ int r;
+ char * name;
+ clist * param_list;
+
+ list = clist_new();
+ if (list == NULL) {
+ res = MAILPOP3_NO_ERROR;
+ goto err;
+ }
+
+ while (1) {
+ char * next_token;
+ char * param;
+ struct mailpop3_capa * capa;
+
+ line = read_line(f);
+ if (line == NULL) {
+ res = MAILPOP3_ERROR_STREAM;
+ goto free_list;
+ }
+
+ if (mailstream_is_end_multiline(line))
+ break;
+
+ next_token = cut_token(line);
+ name = strdup(line);
+ if (name == NULL) {
+ res = MAILPOP3_ERROR_MEMORY;
+ goto free_list;
+ }
+
+ param_list = clist_new();
+ if (param_list == NULL) {
+ res = MAILPOP3_ERROR_MEMORY;
+ goto free_capa_name;
+ }
+
+ while (next_token != NULL) {
+ line = next_token;
+ next_token = cut_token(line);
+ param = strdup(line);
+ if (param == NULL) {
+ res = MAILPOP3_ERROR_MEMORY;
+ goto free_param_list;
+ }
+ r = clist_append(param_list, param);
+ if (r < 0) {
+ free(param);
+ res = MAILPOP3_ERROR_MEMORY;
+ goto free_param_list;
+ }
+ }
+
+ capa = mailpop3_capa_new(name, param_list);
+ if (capa == NULL) {
+ res = MAILPOP3_ERROR_MEMORY;
+ goto free_param_list;
+ }
+
+ r = clist_append(list, capa);
+ if (r < 0) {
+ mailpop3_capa_free(capa);
+ res = MAILPOP3_ERROR_MEMORY;
+ goto free_list;
+ }
+ }
+
+ * result = list;
+
+ return MAILPOP3_NO_ERROR;
+
+ free_param_list:
+ clist_foreach(param_list, (clist_func) free, NULL);
+ clist_free(param_list);
+ free_capa_name:
+ free(name);
+ free_list:
+ clist_foreach(list, (clist_func) mailpop3_capa_free, NULL);
+ clist_free(list);
+ err:
+ return res;
+}
+
+
+
+static char * read_line(mailpop3 * f)
+{
+ return mailstream_read_line_remove_eol(f->pop3_stream, f->pop3_stream_buffer);
+}
+
+static char * read_multiline(mailpop3 * f, size_t size,
+ MMAPString * multiline_buffer)
+{
+ return mailstream_read_multiline(f->pop3_stream, size,
+ f->pop3_stream_buffer, multiline_buffer,
+ f->pop3_progr_rate, f->pop3_progr_fun);
+}
+
+static int send_command(mailpop3 * f, char * command)
+{
+ ssize_t r;
+
+ r = mailstream_write(f->pop3_stream, command, strlen(command));
+ if (r == -1)
+ return -1;
+
+ r = mailstream_flush(f->pop3_stream);
+ if (r == -1)
+ return -1;
+
+ return 0;
+}