From: Pierre Habouzit Date: Mon, 14 May 2007 20:52:38 +0000 (+0200) Subject: reorder code a bit. X-Git-Url: http://git.madism.org/?p=apps%2Fmadmutt.git;a=commitdiff_plain;h=dc8d838f0323b91b8108dd205e0ac7efe15a24e2 reorder code a bit. Signed-off-by: Pierre Habouzit --- diff --git a/pop.c b/pop.c index bc857a3..55943c5 100644 --- a/pop.c +++ b/pop.c @@ -20,28 +20,25 @@ #include "mutt_sasl.h" #include "pop.h" -#define POP_PORT 110 -#define POP_SSL_PORT 995 - -/* number of entries in the hash table */ -#define POP_CACHE_LEN 10 - +#define POP_PORT 110 +#define POP_SSL_PORT 995 +#define POP_CACHE_LEN 10 /* maximal length of the server response (RFC1939) */ -#define POP_CMD_RESPONSE 512 +#define POP_CMD_RESPONSE 512 enum { - /* Status */ - POP_NONE = 0, - POP_CONNECTED, - POP_DISCONNECTED, - POP_BYE + /* Status */ + POP_NONE = 0, + POP_CONNECTED, + POP_DISCONNECTED, + POP_BYE }; typedef enum { - POP_A_SUCCESS = 0, - POP_A_SOCKET, - POP_A_FAILURE, - POP_A_UNAVAIL + POP_A_SUCCESS = 0, + POP_A_SOCKET, + POP_A_FAILURE, + POP_A_UNAVAIL } pop_auth_res_t; typedef struct { @@ -49,57 +46,56 @@ typedef struct { char *path; } POP_CACHE; -typedef enum pop_query_status_e { - PFD_FUNCT_ERROR = -3, /* pop_fetch_data uses pop_query_status and this return value */ - PQ_ERR = -2, - PQ_NOT_CONNECTED = -1, - PQ_OK = 0 +typedef enum { + /* pop_fetch_data uses pop_query_status and this return value */ + PFD_FUNCT_ERROR = -3, + PQ_ERR = -2, + PQ_NOT_CONNECTED = -1, + PQ_OK = 0 } pop_query_status; -typedef enum cmd_status_e { - CMD_NOT_AVAILABLE = 0, - CMD_AVAILABLE, - CMD_UNKNOWN /* unknown whether it is available or not */ +typedef enum { + CMD_NOT_AVAILABLE = 0, + CMD_AVAILABLE, + CMD_UNKNOWN /* unknown whether it is available or not */ } cmd_status; typedef struct { - CONNECTION *conn; - unsigned int status:2; - unsigned int capabilities:1; - unsigned int use_stls:2; - cmd_status cmd_capa; /* optional command CAPA */ - cmd_status cmd_stls; /* optional command STLS */ - cmd_status cmd_user; /* optional command USER */ - cmd_status cmd_uidl; /* optional command UIDL */ - cmd_status cmd_top; /* optional command TOP */ - unsigned int resp_codes:1; /* server supports extended response codes */ - unsigned int expire:1; /* expire is greater than 0 */ - unsigned int clear_cache:1; - size_t size; - time_t check_time; - time_t login_delay; /* minimal login delay capability */ - char *auth_list; /* list of auth mechanisms */ - char *timestamp; - char err_msg[POP_CMD_RESPONSE]; - POP_CACHE cache[POP_CACHE_LEN]; -} POP_DATA; - -/* Copy error message to err_msg buffer */ -static void pop_error (POP_DATA * pop_data, char *msg) + CONNECTION *conn; + + unsigned status : 2; + unsigned capabilities : 1; + unsigned use_stls : 2; + cmd_status cmd_capa : 2; /* optional command CAPA */ + cmd_status cmd_stls : 2; /* optional command STLS */ + cmd_status cmd_user : 2; /* optional command USER */ + cmd_status cmd_uidl : 2; /* optional command UIDL */ + cmd_status cmd_top : 2; /* optional command TOP */ + unsigned resp_codes : 1; /* server supports extended response codes */ + unsigned expire : 1; /* expire is greater than 0 */ + unsigned clear_cache : 1; + + ssize_t size; + time_t check_time; + time_t login_delay; /* minimal login delay capability */ + char *auth_list; /* list of auth mechanisms */ + char *timestamp; + char err_msg[POP_CMD_RESPONSE]; + POP_CACHE cache[POP_CACHE_LEN]; +} pop_data_t; + +/* pop low level functions {{{ */ + +static void pop_error(pop_data_t *pop_data, const char *msg) { - char *t, *c, *c2; - - t = strchr (pop_data->err_msg, '\0'); - c = msg; - - if (!m_strncmp(msg, "-ERR ", 5)) { - c2 = vskipspaces(msg + 5); - if (*c2) - c = c2; - } + if (!m_strncmp(msg, "-ERR ", 5)) { + const char *s = skipspaces(msg + 5); + if (*s) + msg = s; + } - m_strcpy(t, sizeof(pop_data->err_msg) - strlen(pop_data->err_msg), c); - m_strrtrim(pop_data->err_msg); + m_strcat(pop_data->err_msg, sizeof(pop_data->err_msg), msg); + m_strrtrim(pop_data->err_msg); } /* @@ -108,30 +104,93 @@ static void pop_error (POP_DATA * pop_data, char *msg) * -1 - conection lost, * -2 - invalid command or execution error. */ -static pop_query_status pop_query (POP_DATA * pop_data, char *buf, size_t buflen) +static pop_query_status pop_query(pop_data_t *pop_data, char *buf, ssize_t buflen) { - char *c; + char *c; - if (pop_data->status != POP_CONNECTED) - return PQ_NOT_CONNECTED; + if (pop_data->status != POP_CONNECTED) + return PQ_NOT_CONNECTED; - mutt_socket_write(pop_data->conn, buf); + mutt_socket_write(pop_data->conn, buf); - c = strpbrk (buf, " \r\n"); - *c = '\0'; - snprintf (pop_data->err_msg, sizeof (pop_data->err_msg), "%s: ", buf); + c = strpbrk(buf, " \r\n"); + *c = '\0'; + snprintf(pop_data->err_msg, sizeof(pop_data->err_msg), "%s: ", buf); - if (mutt_socket_readln (buf, buflen, pop_data->conn) < 0) { - pop_data->status = POP_DISCONNECTED; - return PQ_NOT_CONNECTED; - } - if (!m_strncmp(buf, "+OK", 3)) + if (mutt_socket_readln(buf, buflen, pop_data->conn) < 0) { + pop_data->status = POP_DISCONNECTED; + return PQ_NOT_CONNECTED; + } + if (!m_strncmp(buf, "+OK", 3)) + return PQ_OK; + + pop_error(pop_data, buf); + return PQ_ERR; +} + +/* + * Open connection + * 0 - successful, + * -1 - conection lost, + * -2 - invalid response. +*/ +static pop_query_status pop_connect(pop_data_t * pop_data) +{ + char buf[LONG_STRING]; + const char *p, *q; + + if (mutt_socket_open(pop_data->conn) < 0 + || mutt_socket_readln(buf, sizeof(buf), pop_data->conn) < 0) + { + mutt_error(_("Error connecting to server: %s"), + pop_data->conn->account.host); + pop_data->status = POP_NONE; + return PQ_NOT_CONNECTED; + } + + pop_data->status = POP_CONNECTED; + if (m_strncmp(buf, "+OK", 3)) { + pop_data->err_msg[0] = '\0'; + pop_error(pop_data, buf); + mutt_error("%s", pop_data->err_msg); + return PQ_ERR; + } + + p_delete(&pop_data->timestamp); + if ((p = strchr(buf, '<')) && (q = strchr(p, '>'))) { + pop_data->timestamp = p_dupstr(p, q - p); + } return PQ_OK; +} - pop_error (pop_data, buf); - return PQ_ERR; +static void pop_logout (CONTEXT * ctx) +{ + pop_query_status ret = 0; + char buf[LONG_STRING]; + pop_data_t *pop_data = (pop_data_t *) ctx->data; + + if (pop_data->status == POP_CONNECTED) { + mutt_message _("Closing connection to POP server..."); + + if (ctx->readonly) { + m_strcpy(buf, sizeof(buf), "RSET\r\n"); + ret = pop_query (pop_data, buf, sizeof (buf)); + } + + if (ret != PQ_NOT_CONNECTED) { + m_strcpy(buf, sizeof(buf), "QUIT\r\n"); + pop_query (pop_data, buf, sizeof (buf)); + } + + mutt_clear_error (); + } + + pop_data->status = POP_DISCONNECTED; + return; } +/* }}} */ + /* * This function calls funct(*line, *data) for each received line, * funct(NULL, *data) if rewind(*data) needs, exits when fail or done. @@ -142,7 +201,7 @@ static pop_query_status pop_query (POP_DATA * pop_data, char *buf, size_t buflen * -3 - error in funct(*line, *data) */ static pop_query_status -pop_fetch_data(POP_DATA *pop_data, const char *query, progress_t *bar, +pop_fetch_data(pop_data_t *pop_data, const char *query, progress_t *bar, int (*funct)(char *, void *), void *data) { char buf[LONG_STRING]; @@ -151,7 +210,7 @@ pop_fetch_data(POP_DATA *pop_data, const char *query, progress_t *bar, pop_query_status ret; int chunk = 0; long pos = 0; - size_t lenbuf = 0; + ssize_t lenbuf = 0; m_strcpy(buf, sizeof(buf), query); ret = pop_query (pop_data, buf, sizeof (buf)); @@ -196,8 +255,132 @@ pop_fetch_data(POP_DATA *pop_data, const char *query, progress_t *bar, return ret; } +static int fetch_capa (char *line, void *data) +{ + pop_data_t *pop_data = (pop_data_t *) data; + char *c; + + if (!ascii_strncasecmp (line, "SASL", 4)) { + p_delete(&pop_data->auth_list); + c = vskipspaces(line + 4); + pop_data->auth_list = m_strdup(c); + } + + else if (!ascii_strncasecmp (line, "STLS", 4)) + pop_data->cmd_stls = CMD_AVAILABLE; + + else if (!ascii_strncasecmp (line, "USER", 4)) + pop_data->cmd_user = CMD_AVAILABLE; + + else if (!ascii_strncasecmp (line, "UIDL", 4)) + pop_data->cmd_uidl = CMD_AVAILABLE; + + else if (!ascii_strncasecmp (line, "TOP", 3)) + pop_data->cmd_top = CMD_AVAILABLE; + + return 0; +} + +static int fetch_auth (char *line, void *data) +{ + pop_data_t *pop_data = (pop_data_t *) data; + ssize_t auth_list_len; + + if (!pop_data->auth_list) { + auth_list_len = m_strlen(line) + 1; + pop_data->auth_list = p_new(char, auth_list_len); + } else { + auth_list_len = m_strlen(pop_data->auth_list) + m_strlen(line) + 2; + p_realloc(&pop_data->auth_list, auth_list_len); + m_strcat(pop_data->auth_list, auth_list_len, " "); + } + m_strcat(pop_data->auth_list, auth_list_len, line); + + return 0; +} + +/* + * Get capabilities + * 0 - successful, + * -1 - conection lost, + * -2 - execution error. +*/ +static pop_query_status pop_capabilities (pop_data_t * pop_data, int mode) +{ + char buf[LONG_STRING]; + + /* don't check capabilities on reconnect */ + if (pop_data->capabilities) + return 0; + + /* init capabilities */ + if (mode == 0) { + pop_data->cmd_capa = CMD_NOT_AVAILABLE; + pop_data->cmd_stls = CMD_NOT_AVAILABLE; + pop_data->cmd_user = CMD_NOT_AVAILABLE; + pop_data->cmd_uidl = CMD_NOT_AVAILABLE; + pop_data->cmd_top = CMD_NOT_AVAILABLE; + pop_data->resp_codes = 0; + pop_data->expire = 1; + pop_data->login_delay = 0; + p_delete(&pop_data->auth_list); + } + + /* Execute CAPA command */ + if (mode == 0 || pop_data->cmd_capa != CMD_NOT_AVAILABLE) { + m_strcpy(buf, sizeof(buf), "CAPA\r\n"); + switch (pop_fetch_data (pop_data, buf, NULL, fetch_capa, pop_data)) { + case PQ_OK: + { + pop_data->cmd_capa = CMD_AVAILABLE; + break; + } + case PFD_FUNCT_ERROR: + case PQ_ERR: + { + pop_data->cmd_capa = CMD_NOT_AVAILABLE; + break; + } + case PQ_NOT_CONNECTED: + return PQ_NOT_CONNECTED; + } + } + + /* CAPA not supported, use defaults */ + if (mode == 0 && pop_data->cmd_capa == CMD_NOT_AVAILABLE) { + pop_data->cmd_user = CMD_UNKNOWN; + pop_data->cmd_uidl = CMD_UNKNOWN; + pop_data->cmd_top = CMD_UNKNOWN; + + m_strcpy(buf, sizeof(buf), "AUTH\r\n"); + if (pop_fetch_data (pop_data, buf, NULL, fetch_auth, pop_data) == PQ_NOT_CONNECTED) + return PQ_NOT_CONNECTED; + } + + /* Check capabilities */ + if (mode == 2) { + char *msg = NULL; + + if (!pop_data->expire) + msg = _("Unable to leave messages on server."); + if (pop_data->cmd_top == CMD_NOT_AVAILABLE) + msg = _("Command TOP is not supported by server."); + if (pop_data->cmd_uidl == CMD_NOT_AVAILABLE) + msg = _("Command UIDL is not supported by server."); + if (msg && pop_data->cmd_capa != CMD_AVAILABLE) { + mutt_error (msg); + return PQ_ERR; + } + pop_data->capabilities = 1; + } + + return PQ_OK; +} + +/* Authentication {{{ */ + /* SASL authenticator */ -static pop_auth_res_t pop_auth_sasl (POP_DATA * pop_data, const char *method) +static pop_auth_res_t pop_auth_sasl (pop_data_t * pop_data, const char *method) { sasl_conn_t *saslconn; sasl_interact_t *interaction = NULL; @@ -307,21 +490,8 @@ bail: return POP_A_FAILURE; } -/* Get the server timestamp for APOP authentication */ -static void pop_apop_timestamp (POP_DATA * pop_data, char *buf) -{ - char *p1, *p2; - - p_delete(&pop_data->timestamp); - - if ((p1 = strchr (buf, '<')) && (p2 = strchr (p1, '>'))) { - p2[1] = '\0'; - pop_data->timestamp = m_strdup(p1); - } -} - /* APOP authenticator */ -static pop_auth_res_t pop_auth_apop (POP_DATA * pop_data, +static pop_auth_res_t pop_auth_apop (pop_data_t * pop_data, const char *method __attribute__ ((unused))) { MD5_CTX mdContext; @@ -368,7 +538,7 @@ static pop_auth_res_t pop_auth_apop (POP_DATA * pop_data, } /* USER authenticator */ -static pop_auth_res_t pop_auth_user (POP_DATA * pop_data, +static pop_auth_res_t pop_auth_user (pop_data_t * pop_data, const char *method __attribute__ ((unused))) { char buf[LONG_STRING]; @@ -417,41 +587,9 @@ static pop_auth_res_t pop_auth_user (POP_DATA * pop_data, return POP_A_FAILURE; } -/* - * Open connection - * 0 - successful, - * -1 - conection lost, - * -2 - invalid response. -*/ -static pop_query_status pop_connect (POP_DATA * pop_data) -{ - char buf[LONG_STRING]; - - pop_data->status = POP_NONE; - if (mutt_socket_open (pop_data->conn) < 0 || - mutt_socket_readln (buf, sizeof (buf), pop_data->conn) < 0) { - mutt_error (_("Error connecting to server: %s"), - pop_data->conn->account.host); - return PQ_NOT_CONNECTED; - } - - pop_data->status = POP_CONNECTED; - - if (m_strncmp(buf, "+OK", 3)) { - *pop_data->err_msg = '\0'; - pop_error (pop_data, buf); - mutt_error ("%s", pop_data->err_msg); - return PQ_ERR; - } - - pop_apop_timestamp (pop_data, buf); - - return PQ_OK; -} - typedef struct { /* do authentication, using named method or any available if method is NULL */ - pop_auth_res_t (*authenticate) (POP_DATA *, const char *); + pop_auth_res_t (*authenticate) (pop_data_t *, const char *); /* name of authentication method supported, NULL means variable. If this * is not null, authenticate may ignore the second parameter. */ const char *method; @@ -464,7 +602,7 @@ typedef struct { * -2 - login failed, * -3 - authentication canceled. */ -static pop_query_status pop_authenticate (POP_DATA * pop_data) +static pop_query_status pop_authenticate (pop_data_t * pop_data) { static pop_auth_t const pop_authenticators[] = { {pop_auth_sasl, NULL}, @@ -500,16 +638,13 @@ static pop_query_status pop_authenticate (POP_DATA * pop_data) if (!authenticator->method || !ascii_strcasecmp (authenticator->method, method)) { ret = authenticator->authenticate (pop_data, method); - if (ret == POP_A_SOCKET) - switch (pop_connect (pop_data)) { - case PQ_OK: - { - ret = authenticator->authenticate (pop_data, method); - break; - } - default: + if (ret == POP_A_SOCKET) { + if (pop_connect(pop_data) == PQ_OK) { + ret = authenticator->authenticate (pop_data, method); + } else { ret = POP_A_FAILURE; } + } if (ret != POP_A_UNAVAIL) attempts++; @@ -533,17 +668,13 @@ static pop_query_status pop_authenticate (POP_DATA * pop_data) while (authenticator->authenticate) { ret = authenticator->authenticate (pop_data, authenticator->method); - if (ret == POP_A_SOCKET) - switch (pop_connect (pop_data)) { - case PQ_OK: - { - ret = - authenticator->authenticate (pop_data, authenticator->method); - break; - } - default: + if (ret == POP_A_SOCKET) { + if (pop_connect(pop_data) == PQ_OK) { + ret = authenticator->authenticate(pop_data, authenticator->method); + } else { ret = POP_A_FAILURE; } + } if (ret != POP_A_UNAVAIL) attempts++; @@ -567,6 +698,7 @@ static pop_query_status pop_authenticate (POP_DATA * pop_data) return PQ_ERR; } + /* given an POP mailbox name, return host, port, username and password */ static int pop_parse_path (const char *path, ACCOUNT * act) { @@ -596,156 +728,34 @@ static int pop_parse_path (const char *path, ACCOUNT * act) return ret; } -/* Parse CAPA output */ -static int fetch_capa (char *line, void *data) +/* }}} */ + +/* + * Open connection and authenticate + * 0 - successful, + * -1 - conection lost, + * -2 - invalid command or execution error, + * -3 - authentication canceled. +*/ +static pop_query_status pop_open_connection (pop_data_t * pop_data) { - POP_DATA *pop_data = (POP_DATA *) data; - char *c; + pop_query_status ret; + unsigned int n, size; + char buf[LONG_STRING]; - if (!ascii_strncasecmp (line, "SASL", 4)) { - p_delete(&pop_data->auth_list); - c = vskipspaces(line + 4); - pop_data->auth_list = m_strdup(c); + ret = pop_connect(pop_data); + if (ret != PQ_OK) { + mutt_sleep (2); + return ret; } - else if (!ascii_strncasecmp (line, "STLS", 4)) - pop_data->cmd_stls = CMD_AVAILABLE; - - else if (!ascii_strncasecmp (line, "USER", 4)) - pop_data->cmd_user = CMD_AVAILABLE; - - else if (!ascii_strncasecmp (line, "UIDL", 4)) - pop_data->cmd_uidl = CMD_AVAILABLE; - - else if (!ascii_strncasecmp (line, "TOP", 3)) - pop_data->cmd_top = CMD_AVAILABLE; - - return 0; -} - -/* Fetch list of the authentication mechanisms */ -static int fetch_auth (char *line, void *data) -{ - POP_DATA *pop_data = (POP_DATA *) data; - ssize_t auth_list_len; - - if (!pop_data->auth_list) { - auth_list_len = m_strlen(line) + 1; - pop_data->auth_list = p_new(char, auth_list_len); - } else { - auth_list_len = m_strlen(pop_data->auth_list) + m_strlen(line) + 2; - p_realloc(&pop_data->auth_list, auth_list_len); - m_strcat(pop_data->auth_list, auth_list_len, " "); - } - m_strcat(pop_data->auth_list, auth_list_len, line); - - return 0; -} - -/* - * Get capabilities - * 0 - successful, - * -1 - conection lost, - * -2 - execution error. -*/ -static pop_query_status pop_capabilities (POP_DATA * pop_data, int mode) -{ - char buf[LONG_STRING]; - - /* don't check capabilities on reconnect */ - if (pop_data->capabilities) - return 0; - - /* init capabilities */ - if (mode == 0) { - pop_data->cmd_capa = CMD_NOT_AVAILABLE; - pop_data->cmd_stls = CMD_NOT_AVAILABLE; - pop_data->cmd_user = CMD_NOT_AVAILABLE; - pop_data->cmd_uidl = CMD_NOT_AVAILABLE; - pop_data->cmd_top = CMD_NOT_AVAILABLE; - pop_data->resp_codes = 0; - pop_data->expire = 1; - pop_data->login_delay = 0; - p_delete(&pop_data->auth_list); - } - - /* Execute CAPA command */ - if (mode == 0 || pop_data->cmd_capa != CMD_NOT_AVAILABLE) { - m_strcpy(buf, sizeof(buf), "CAPA\r\n"); - switch (pop_fetch_data (pop_data, buf, NULL, fetch_capa, pop_data)) { - case PQ_OK: - { - pop_data->cmd_capa = CMD_AVAILABLE; - break; - } - case PFD_FUNCT_ERROR: - case PQ_ERR: - { - pop_data->cmd_capa = CMD_NOT_AVAILABLE; - break; - } - case PQ_NOT_CONNECTED: - return PQ_NOT_CONNECTED; - } - } - - /* CAPA not supported, use defaults */ - if (mode == 0 && pop_data->cmd_capa == CMD_NOT_AVAILABLE) { - pop_data->cmd_user = CMD_UNKNOWN; - pop_data->cmd_uidl = CMD_UNKNOWN; - pop_data->cmd_top = CMD_UNKNOWN; - - m_strcpy(buf, sizeof(buf), "AUTH\r\n"); - if (pop_fetch_data (pop_data, buf, NULL, fetch_auth, pop_data) == PQ_NOT_CONNECTED) - return PQ_NOT_CONNECTED; - } - - /* Check capabilities */ - if (mode == 2) { - char *msg = NULL; - - if (!pop_data->expire) - msg = _("Unable to leave messages on server."); - if (pop_data->cmd_top == CMD_NOT_AVAILABLE) - msg = _("Command TOP is not supported by server."); - if (pop_data->cmd_uidl == CMD_NOT_AVAILABLE) - msg = _("Command UIDL is not supported by server."); - if (msg && pop_data->cmd_capa != CMD_AVAILABLE) { - mutt_error (msg); - return PQ_ERR; - } - pop_data->capabilities = 1; - } - - return PQ_OK; -} - -/* - * Open connection and authenticate - * 0 - successful, - * -1 - conection lost, - * -2 - invalid command or execution error, - * -3 - authentication canceled. -*/ -static pop_query_status pop_open_connection (POP_DATA * pop_data) -{ - pop_query_status ret; - unsigned int n, size; - char buf[LONG_STRING]; - - ret = pop_connect (pop_data); - if (ret != PQ_OK) { - mutt_sleep (2); - return ret; - } - - ret = pop_capabilities (pop_data, 0); - if (ret == PQ_NOT_CONNECTED) - goto err_conn; - if (ret == PQ_ERR) { - mutt_sleep (2); - return PQ_ERR; - } + ret = pop_capabilities (pop_data, 0); + if (ret == PQ_NOT_CONNECTED) + goto err_conn; + if (ret == PQ_ERR) { + mutt_sleep (2); + return PQ_ERR; + } /* Attempt STLS if available and desired. */ if (!pop_data->conn->ssf && (pop_data->cmd_stls || mod_ssl.force_tls)) { @@ -830,33 +840,6 @@ err_conn: return PQ_NOT_CONNECTED; } -/* logout from POP server */ -static void pop_logout (CONTEXT * ctx) -{ - pop_query_status ret = 0; - char buf[LONG_STRING]; - POP_DATA *pop_data = (POP_DATA *) ctx->data; - - if (pop_data->status == POP_CONNECTED) { - mutt_message _("Closing connection to POP server..."); - - if (ctx->readonly) { - m_strcpy(buf, sizeof(buf), "RSET\r\n"); - ret = pop_query (pop_data, buf, sizeof (buf)); - } - - if (ret != PQ_NOT_CONNECTED) { - m_strcpy(buf, sizeof(buf), "QUIT\r\n"); - pop_query (pop_data, buf, sizeof (buf)); - } - - mutt_clear_error (); - } - - pop_data->status = POP_DISCONNECTED; - return; -} - /* find message with this UIDL and set refno */ static int check_uidl (char *line, void *data) { @@ -878,7 +861,7 @@ static int check_uidl (char *line, void *data) static pop_query_status pop_reconnect (CONTEXT * ctx) { pop_query_status ret; - POP_DATA *pop_data = (POP_DATA *) ctx->data; + pop_data_t *pop_data = (pop_data_t *) ctx->data; progress_t bar; if (pop_data->status == POP_CONNECTED) @@ -889,7 +872,7 @@ static pop_query_status pop_reconnect (CONTEXT * ctx) for (;;) { mutt_socket_close (pop_data->conn); - ret = pop_open_connection (pop_data); + ret = pop_open_connection(pop_data); if (ret == PQ_OK) { int i; @@ -920,6 +903,7 @@ static pop_query_status pop_reconnect (CONTEXT * ctx) return PQ_NOT_CONNECTED; } } + /* write line to file */ static int fetch_message (char *line, void *file) { @@ -940,7 +924,7 @@ static int fetch_message (char *line, void *file) * -2 - invalid command or execution error, * -3 - error writing to tempfile */ -static pop_query_status pop_read_header (POP_DATA * pop_data, HEADER * h) +static pop_query_status pop_read_header (pop_data_t * pop_data, HEADER * h) { FILE *f; int idx; @@ -1017,7 +1001,7 @@ static int fetch_uidl (char *line, void *data) { int i, idx; CONTEXT *ctx = (CONTEXT *) data; - POP_DATA *pop_data = (POP_DATA *) ctx->data; + pop_data_t *pop_data = (pop_data_t *) ctx->data; sscanf (line, "%d %s", &idx, line); for (i = 0; i < ctx->msgcount; i++) @@ -1053,7 +1037,7 @@ static int pop_fetch_headers (CONTEXT * ctx) { int i, old_count, new_count; pop_query_status ret; - POP_DATA *pop_data = (POP_DATA *) ctx->data; + pop_data_t *pop_data = (pop_data_t *) ctx->data; time (&pop_data->check_time); pop_data->clear_cache = 0; @@ -1109,14 +1093,37 @@ static int pop_fetch_headers (CONTEXT * ctx) return (new_count - old_count); } -/* open POP mailbox - fetch only headers */ +/* delete all cached messages */ +static void pop_clear_cache (pop_data_t * pop_data) +{ + int i; + + if (!pop_data->clear_cache) + return; + + for (i = 0; i < POP_CACHE_LEN; i++) { + if (pop_data->cache[i].path) { + unlink (pop_data->cache[i].path); + p_delete(&pop_data->cache[i].path); + } + } +} + +/* pop_mx functions {{{ */ + +static int pop_is_magic(const char* path, struct stat* st) +{ + url_scheme_t s = url_check_scheme(NONULL(path)); + return s == U_POP || s == U_POPS ? M_POP : -1; +} + static int pop_open_mailbox (CONTEXT * ctx) { int ret; char buf[LONG_STRING]; CONNECTION *conn; ACCOUNT act; - POP_DATA *pop_data; + pop_data_t *pop_data; ciss_url_t url; if (pop_parse_path (ctx->path, &act)) { @@ -1135,11 +1142,11 @@ static int pop_open_mailbox (CONTEXT * ctx) p_delete(&ctx->path); ctx->path = m_strdup(buf); - pop_data = p_new(POP_DATA, 1); + pop_data = p_new(pop_data_t, 1); pop_data->conn = conn; ctx->data = pop_data; - if (pop_open_connection (pop_data) < 0) + if (pop_open_connection(pop_data) != PQ_OK) return -1; conn->data = pop_data; @@ -1164,26 +1171,53 @@ static int pop_open_mailbox (CONTEXT * ctx) } } -/* delete all cached messages */ -static void pop_clear_cache (POP_DATA * pop_data) +static int pop_acl_check(CONTEXT *ctx, int bit) { - int i; + switch (bit) { + case ACL_DELETE: /* (un)deletion */ + case ACL_SEEN: /* mark as read */ + return 1; + case ACL_INSERT: /* editing messages */ + case ACL_WRITE: /* change importance */ + default: + return 0; + } +} - if (!pop_data->clear_cache) - return; +static int pop_check_mailbox(CONTEXT * ctx, int *index_hint, int unused) +{ + int ret; + pop_data_t *pop_data = (pop_data_t *) ctx->data; - for (i = 0; i < POP_CACHE_LEN; i++) { - if (pop_data->cache[i].path) { - unlink (pop_data->cache[i].path); - p_delete(&pop_data->cache[i].path); - } - } + if ((pop_data->check_time + PopCheckTimeout) > time (NULL)) + return 0; + + pop_logout (ctx); + + mutt_socket_close (pop_data->conn); + + if (pop_open_connection (pop_data) < 0) + return -1; + + ctx->size = pop_data->size; + + mutt_message _("Checking for new messages..."); + + ret = pop_fetch_headers (ctx); + pop_clear_cache (pop_data); + + if (ret < 0) + return -1; + + if (ret > 0) + return M_NEW_MAIL; + + return 0; } -/* close POP mailbox */ static void pop_close_mailbox (CONTEXT * ctx) { - POP_DATA *pop_data = (POP_DATA *) ctx->data; + pop_data_t *pop_data = (pop_data_t *) ctx->data; if (!pop_data) return; @@ -1204,122 +1238,12 @@ static void pop_close_mailbox (CONTEXT * ctx) return; } -/* fetch message from POP server */ -int pop_fetch_message (MESSAGE * msg, CONTEXT * ctx, int msgno) -{ - int ret; - void *uidl; - char buf[LONG_STRING]; - char path[_POSIX_PATH_MAX]; - progress_t bar; - POP_DATA *pop_data = (POP_DATA *) ctx->data; - POP_CACHE *cache; - HEADER *h = ctx->hdrs[msgno]; - - /* see if we already have the message in our cache */ - cache = &pop_data->cache[h->index % POP_CACHE_LEN]; - - if (cache->path) { - if (cache->index == h->index) { - /* yes, so just return a pointer to the message */ - msg->fp = fopen (cache->path, "r"); - if (msg->fp) - return 0; - - mutt_perror (cache->path); - mutt_sleep (2); - return -1; - } - else { - /* clear the previous entry */ - unlink (cache->path); - p_delete(&cache->path); - } - } - - for (;;) { - if (pop_reconnect (ctx) != PQ_OK) - return -1; - - /* verify that massage index is correct */ - if (h->refno < 0) { - mutt_error - _("The message index is incorrect. Try reopening the mailbox."); - mutt_sleep (2); - return -1; - } - - bar.size = h->content->length + h->content->offset - 1; - bar.msg = _("Fetching message..."); - mutt_progress_bar (&bar, 0); - - msg->fp = m_tempfile(path, sizeof(path), NONULL(MCore.tmpdir), NULL); - if (!msg->fp) { - mutt_error(_("Could not create temporary file")); - mutt_sleep(2); - return -1; - } - - snprintf (buf, sizeof (buf), "RETR %d\r\n", h->refno); - - ret = pop_fetch_data (pop_data, buf, &bar, fetch_message, msg->fp); - if (ret == PQ_OK) - break; - - m_fclose(&msg->fp); - unlink (path); - - if (ret == PQ_ERR) { - mutt_error ("%s", pop_data->err_msg); - mutt_sleep (2); - return -1; - } - - if (ret == PFD_FUNCT_ERROR) { - mutt_error _("Can't write message to temporary file!"); - - mutt_sleep (2); - return -1; - } - } - - /* Update the header information. Previously, we only downloaded a - * portion of the headers, those required for the main display. - */ - cache->index = h->index; - cache->path = m_strdup(path); - rewind (msg->fp); - uidl = h->data; - envelope_delete(&h->env); - h->env = mutt_read_rfc822_header (msg->fp, h, 0, 0); - h->data = uidl; - h->lines = 0; - fgets (buf, sizeof (buf), msg->fp); - while (!feof (msg->fp)) { - ctx->hdrs[msgno]->lines++; - fgets (buf, sizeof (buf), msg->fp); - } - - h->content->length = ftello (msg->fp) - h->content->offset; - - /* This needs to be done in case this is a multipart message */ - h->security = crypt_query (h->content); - - mutt_clear_error (); - rewind (msg->fp); - - return 0; -} - -/* update POP mailbox - delete messages from server */ -static pop_query_status -pop_sync_mailbox (CONTEXT * ctx, int unused __attribute__ ((unused)), - int *index_hint __attribute__ ((unused))) +static int pop_sync_mailbox(CONTEXT * ctx, int unused, int *index_hint) { int i; pop_query_status ret; char buf[LONG_STRING]; - POP_DATA *pop_data = (POP_DATA *) ctx->data; + pop_data_t *pop_data = (pop_data_t *) ctx->data; pop_data->check_time = 0; @@ -1356,41 +1280,25 @@ pop_sync_mailbox (CONTEXT * ctx, int unused __attribute__ ((unused)), } } -/* Check for new messages and fetch headers */ -static int pop_check_mailbox (CONTEXT * ctx, - int *index_hint __attribute__ ((unused)), - int unused __attribute__ ((unused))) -{ - int ret; - POP_DATA *pop_data = (POP_DATA *) ctx->data; - - if ((pop_data->check_time + PopCheckTimeout) > time (NULL)) - return 0; - - pop_logout (ctx); - - mutt_socket_close (pop_data->conn); - - if (pop_open_connection (pop_data) < 0) - return -1; - - ctx->size = pop_data->size; - - mutt_message _("Checking for new messages..."); - - ret = pop_fetch_headers (ctx); - pop_clear_cache (pop_data); +/* }}} */ - if (ret < 0) - return -1; - - if (ret > 0) - return M_NEW_MAIL; +mx_t const pop_mx = { + M_POP, + 0, + pop_is_magic, + NULL, + NULL, + pop_open_mailbox, + NULL, + pop_acl_check, + pop_check_mailbox, + pop_close_mailbox, + pop_sync_mailbox, + NULL, +}; - return 0; -} +/* public API {{{ */ -/* Fetch messages and save them in $spoolfile */ void pop_fetch_mail (void) { char buffer[LONG_STRING]; @@ -1402,7 +1310,7 @@ void pop_fetch_mail (void) CONTEXT ctx; MESSAGE *msg = NULL; ACCOUNT act; - POP_DATA *pop_data; + pop_data_t *pop_data; ssize_t plen; if (!PopHost) { @@ -1430,7 +1338,7 @@ void pop_fetch_mail (void) if (!conn) return; - pop_data = p_new(POP_DATA, 1); + pop_data = p_new(pop_data_t, 1); pop_data->conn = conn; if (pop_open_connection (pop_data) < 0) { @@ -1546,35 +1454,111 @@ fail: p_delete(&pop_data); } -static int pop_is_magic (const char* path, struct stat* st __attribute__ ((unused))) { - url_scheme_t s = url_check_scheme (NONULL (path)); - return ((s == U_POP || s == U_POPS) ? M_POP : -1); -} +/* fetch message from POP server */ +int pop_fetch_message (MESSAGE * msg, CONTEXT * ctx, int msgno) +{ + int ret; + void *uidl; + char buf[LONG_STRING]; + char path[_POSIX_PATH_MAX]; + progress_t bar; + pop_data_t *pop_data = (pop_data_t *) ctx->data; + POP_CACHE *cache; + HEADER *h = ctx->hdrs[msgno]; -static int acl_check_pop (CONTEXT* ctx __attribute__ ((unused)), int bit) { - switch (bit) { - case ACL_INSERT: /* editing messages */ - case ACL_WRITE: /* change importance */ - return (0); - case ACL_DELETE: /* (un)deletion */ - case ACL_SEEN: /* mark as read */ - return (1); - default: - return (0); + /* see if we already have the message in our cache */ + cache = &pop_data->cache[h->index % POP_CACHE_LEN]; + + if (cache->path) { + if (cache->index == h->index) { + /* yes, so just return a pointer to the message */ + msg->fp = fopen (cache->path, "r"); + if (msg->fp) + return 0; + + mutt_perror (cache->path); + mutt_sleep (2); + return -1; + } + else { + /* clear the previous entry */ + unlink (cache->path); + p_delete(&cache->path); + } } + + for (;;) { + if (pop_reconnect (ctx) != PQ_OK) + return -1; + + /* verify that massage index is correct */ + if (h->refno < 0) { + mutt_error + _("The message index is incorrect. Try reopening the mailbox."); + mutt_sleep (2); + return -1; + } + + bar.size = h->content->length + h->content->offset - 1; + bar.msg = _("Fetching message..."); + mutt_progress_bar (&bar, 0); + + msg->fp = m_tempfile(path, sizeof(path), NONULL(MCore.tmpdir), NULL); + if (!msg->fp) { + mutt_error(_("Could not create temporary file")); + mutt_sleep(2); + return -1; + } + + snprintf (buf, sizeof (buf), "RETR %d\r\n", h->refno); + + ret = pop_fetch_data (pop_data, buf, &bar, fetch_message, msg->fp); + if (ret == PQ_OK) + break; + + m_fclose(&msg->fp); + unlink (path); + + if (ret == PQ_ERR) { + mutt_error ("%s", pop_data->err_msg); + mutt_sleep (2); + return -1; + } + + if (ret == PFD_FUNCT_ERROR) { + mutt_error _("Can't write message to temporary file!"); + + mutt_sleep (2); + return -1; + } + } + + /* Update the header information. Previously, we only downloaded a + * portion of the headers, those required for the main display. + */ + cache->index = h->index; + cache->path = m_strdup(path); + rewind (msg->fp); + uidl = h->data; + envelope_delete(&h->env); + h->env = mutt_read_rfc822_header (msg->fp, h, 0, 0); + h->data = uidl; + h->lines = 0; + fgets (buf, sizeof (buf), msg->fp); + while (!feof (msg->fp)) { + ctx->hdrs[msgno]->lines++; + fgets (buf, sizeof (buf), msg->fp); + } + + h->content->length = ftello (msg->fp) - h->content->offset; + + /* This needs to be done in case this is a multipart message */ + h->security = crypt_query (h->content); + + mutt_clear_error (); + rewind (msg->fp); + + return 0; } -mx_t const pop_mx = { - M_POP, - 0, - pop_is_magic, - NULL, - NULL, - pop_open_mailbox, - NULL, - acl_check_pop, - pop_check_mailbox, - pop_close_mailbox, - pop_sync_mailbox, - NULL, -}; +/* }}} */ diff --git a/pop.h b/pop.h index 396a81b..74df068 100644 --- a/pop.h +++ b/pop.h @@ -15,7 +15,7 @@ extern mx_t const pop_mx; -int pop_fetch_message (MESSAGE *, CONTEXT *, int); -void pop_fetch_mail (void); +int pop_fetch_message(MESSAGE *, CONTEXT *, int); +void pop_fetch_mail(void); #endif