X-Git-Url: http://git.madism.org/?p=apps%2Fmadmutt.git;a=blobdiff_plain;f=pop.c;h=a066f6e5dd05562de916dd3f760a506e089e4613;hp=43b895977b1f2b8388de186e5c4a4126346ad00b;hb=8d0d7180fa5c7862e74027b497adab1f427f0020;hpb=c05e2953d8c688f8e1321bbf717298c9177fe5c5 diff --git a/pop.c b/pop.c index 43b8959..a066f6e 100644 --- a/pop.c +++ b/pop.c @@ -13,7 +13,7 @@ #include #include -#include +#include #include "crypt.h" #include "mutt.h" @@ -63,20 +63,20 @@ typedef enum { typedef struct { CONNECTION *conn; - unsigned status : 2; + 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_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; + unsigned use_stls : 2; + cmd_status cmd_capa : 2; /* optional command CAPA */ + cmd_status cmd_stls : 2; /* optional command STLS */ + cmd_status cmd_uidl : 2; /* optional command UIDL */ + cmd_status cmd_top : 2; /* optional command TOP */ + cmd_status cmd_user : 2; /* optional command USER */ + 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]; @@ -103,18 +103,14 @@ static void pop_error(pop_data_t *pop_data, const char *msg) * -1 - conection lost, * -2 - invalid command or execution error. */ -static pop_query_status pop_query(pop_data_t *pop_data, char *buf, ssize_t buflen) +static pop_query_status _pop_query(pop_data_t *pop_data, char *buf, ssize_t buflen) { - char *c; - if (pop_data->status != POP_CONNECTED) return PQ_NOT_CONNECTED; 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); + snprintf(pop_data->err_msg, sizeof(pop_data->err_msg), "%.*s: ", + (int)(strpbrk(buf, " \r\n") - buf), buf); if (mutt_socket_readln(buf, buflen, pop_data->conn) < 0) { pop_data->status = POP_DISCONNECTED; @@ -126,6 +122,8 @@ static pop_query_status pop_query(pop_data_t *pop_data, char *buf, ssize_t bufle pop_error(pop_data, buf); return PQ_ERR; } +#define pop_query(pd, b, l, fmt, ...) \ + (snprintf(b, l, fmt "\r\n", ##__VA_ARGS__), _pop_query(pd, b, l)) /* * Open connection @@ -157,7 +155,7 @@ static pop_query_status pop_connect(pop_data_t * pop_data) p_delete(&pop_data->timestamp); if ((p = strchr(buf, '<')) && (q = strchr(p, '>'))) { - pop_data->timestamp = p_dupstr(p, q - p); + pop_data->timestamp = p_dupstr(p, q + 1 - p); } return PQ_OK; } @@ -172,13 +170,11 @@ static void pop_logout (CONTEXT * ctx) 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)); + ret = pop_query(pop_data, buf, sizeof(buf), "RSET"); } if (ret != PQ_NOT_CONNECTED) { - m_strcpy(buf, sizeof(buf), "QUIT\r\n"); - pop_query (pop_data, buf, sizeof (buf)); + pop_query(pop_data, buf, sizeof(buf), "QUIT"); } mutt_clear_error (); @@ -191,7 +187,6 @@ static void pop_logout (CONTEXT * ctx) /* }}} */ /* Authentication {{{ */ -/* SASL authenticator */ static pop_auth_res_t pop_auth_sasl(pop_data_t *pop_data, const char *method) { sasl_conn_t *saslconn; @@ -285,8 +280,7 @@ static pop_auth_res_t pop_auth_sasl(pop_data_t *pop_data, const char *method) /* terminate SASL session if the last responce is not +OK nor -ERR */ if (!m_strncmp(inbuf, "+ ", 2)) { - snprintf(buf, sizeof(buf), "*\r\n"); - if (pop_query(pop_data, buf, sizeof(buf)) == PQ_NOT_CONNECTED) + if (pop_query(pop_data, buf, sizeof(buf), "*") == PQ_NOT_CONNECTED) return POP_A_SOCKET; } @@ -296,7 +290,6 @@ static pop_auth_res_t pop_auth_sasl(pop_data_t *pop_data, const char *method) return POP_A_FAILURE; } -/* APOP authenticator */ static pop_auth_res_t pop_auth_apop(pop_data_t *pop_data, const char *method) { MD5_CTX mdContext; @@ -321,46 +314,42 @@ static pop_auth_res_t pop_auth_apop(pop_data_t *pop_data, const char *method) for (i = 0; i < countof(digest); i++) sprintf(hash + 2 * i, "%02x", digest[i]); - /* Send APOP command to server */ - snprintf(buf, sizeof(buf), "APOP %s %s\r\n", pop_data->conn->account.user, - hash); - - switch (pop_query(pop_data, buf, sizeof(buf))) { + switch (pop_query(pop_data, buf, sizeof(buf), "APOP %s %s", + pop_data->conn->account.user, hash)) + { case PQ_OK: return POP_A_SUCCESS; case PQ_NOT_CONNECTED: return POP_A_SOCKET; - case PFD_FUNCT_ERROR: - case PQ_ERR: default: - break; + mutt_error("%s %s", _("APOP authentication failed."), pop_data->err_msg); + mutt_sleep(2); + return POP_A_FAILURE; } - - mutt_error("%s %s", _("APOP authentication failed."), pop_data->err_msg); - mutt_sleep(2); - - return POP_A_FAILURE; } -/* USER authenticator */ static pop_auth_res_t pop_auth_user(pop_data_t *pop_data, const char *method) { char buf[LONG_STRING]; pop_query_status ret; - mutt_message(_("Logging in...")); - snprintf(buf, sizeof(buf), "USER %s\r\n", pop_data->conn->account.user); - ret = pop_query(pop_data, buf, sizeof (buf)); + if (pop_data->cmd_user == CMD_NOT_AVAILABLE) + return POP_A_UNAVAIL; - if (ret == PQ_ERR) { - snprintf(pop_data->err_msg, sizeof(pop_data->err_msg), - _("Command USER is not supported by server.")); + mutt_message _("Authenticating (USER)..."); + ret = pop_query(pop_data, buf, sizeof(buf), "USER %s", + pop_data->conn->account.user); + + if (pop_data->cmd_user == CMD_UNKNOWN) { + if (ret == PQ_OK) + pop_data->cmd_user = CMD_AVAILABLE; + if (ret == PQ_ERR) + pop_data->cmd_user = CMD_NOT_AVAILABLE; } if (ret == PQ_OK) { - snprintf(buf, sizeof(buf), "PASS %s\r\n", - pop_data->conn->account.pass); - ret = pop_query(pop_data, buf, sizeof(buf)); + ret = pop_query(pop_data, buf, sizeof(buf), "PASS %s", + pop_data->conn->account.pass); } switch (ret) { @@ -369,8 +358,8 @@ static pop_auth_res_t pop_auth_user(pop_data_t *pop_data, const char *method) case PQ_NOT_CONNECTED: return POP_A_SOCKET; default: - mutt_error ("%s %s", _("Login failed."), pop_data->err_msg); - mutt_sleep (2); + mutt_error("%s %s", _("USER authentication failed."), pop_data->err_msg); + mutt_sleep(2); return POP_A_FAILURE; } } @@ -390,8 +379,8 @@ static pop_query_status pop_authenticate (pop_data_t * pop_data) }; ACCOUNT *act = &pop_data->conn->account; - int attempts = 0, ret = POP_A_UNAVAIL; const pop_auth_t *auth; + int attempts = 0; if (mutt_account_getuser(act) || !act->user[0] || mutt_account_getpass(act) || !act->pass[0]) @@ -416,52 +405,39 @@ static pop_query_status pop_authenticate (pop_data_t * pop_data) if (auth->method && ascii_strcasecmp(auth->method, buf)) continue; - ret = auth->do_auth(pop_data, buf); - if (ret == POP_A_SOCKET) { - if (pop_connect(pop_data) == PQ_OK) { - ret = auth->do_auth(pop_data, buf); - } else { - ret = POP_A_FAILURE; - } - } - - if (ret != POP_A_UNAVAIL) + switch (auth->do_auth(pop_data, buf)) { + case POP_A_SUCCESS: + return PQ_OK; + case POP_A_SOCKET: + return PQ_NOT_CONNECTED; + case POP_A_UNAVAIL: + break; + case POP_A_FAILURE: attempts++; - if (ret == POP_A_SUCCESS || ret == POP_A_SOCKET) { - goto ok; + break; } + mutt_socket_close(pop_data->conn); } } } else { - /* Fall back to default: any authenticator */ for (auth = pop_authenticators; auth->do_auth; auth++) { - ret = auth->do_auth(pop_data, auth->method); - if (ret == POP_A_SOCKET) { - if (pop_connect(pop_data) == PQ_OK) { - ret = auth->do_auth(pop_data, auth->method); - } else { - ret = POP_A_FAILURE; - } - } - - if (ret != POP_A_UNAVAIL) + switch (auth->do_auth(pop_data, auth->method)) { + case POP_A_SUCCESS: + return PQ_OK; + case POP_A_SOCKET: + return PQ_NOT_CONNECTED; + case POP_A_UNAVAIL: + break; + case POP_A_FAILURE: attempts++; - if (ret == POP_A_SUCCESS || ret == POP_A_SOCKET) break; + } + mutt_socket_close(pop_data->conn); } } - ok: - switch (ret) { - case POP_A_SUCCESS: - return PQ_OK; - case POP_A_SOCKET: - return PQ_NOT_CONNECTED; - case POP_A_UNAVAIL: - if (!attempts) - mutt_error(_("No authenticators available")); - } - + if (!attempts) + mutt_error(_("No authenticators available")); return PQ_ERR; } @@ -480,55 +456,48 @@ static pop_query_status pop_fetch_data(pop_data_t *pop_data, const char *query, progress_t *bar, int (*funct)(char *, void *), void *data) { - char buf[LONG_STRING]; - char *inbuf; - char *p; - pop_query_status ret; - int chunk = 0; - long pos = 0; - ssize_t lenbuf = 0; + pop_query_status ret; + char buf[LONG_STRING]; + buffer_t inbuf; + ssize_t pos = 0; - m_strcpy(buf, sizeof(buf), query); - ret = pop_query (pop_data, buf, sizeof (buf)); - if (ret != PQ_OK) - return ret; + buffer_init(&inbuf); - inbuf = p_new(char, sizeof(buf)); + m_strcpy(buf, sizeof(buf), query); + ret = _pop_query(pop_data, buf, sizeof(buf)); + if (ret != PQ_OK) + return ret; - for (;;) { - chunk = - mutt_socket_readln(buf, sizeof (buf), pop_data->conn); - if (chunk < 0) { - pop_data->status = POP_DISCONNECTED; - ret = PQ_NOT_CONNECTED; - break; - } + for (;;) { + int dot = 0; - p = buf; - if (!lenbuf && buf[0] == '.') { - if (buf[1] != '.') - break; - p++; - } + if (mutt_socket_readln2(&inbuf, pop_data->conn) < 0) { + pop_data->status = POP_DISCONNECTED; + ret = PQ_NOT_CONNECTED; + break; + } - m_strcpy(inbuf + lenbuf,sizeof(buf), p); - pos += chunk; + if (bar) { + mutt_progress_bar(bar, pos += inbuf.len); + } - if (chunk >= ssizeof(buf)) { - lenbuf += strlen (p); - } else { - if (bar) - mutt_progress_bar (bar, pos); - if (ret == 0 && funct (inbuf, data) < 0) - ret = PFD_FUNCT_ERROR; - lenbuf = 0; - } + if (inbuf.data[0] == '.') { + if (inbuf.data[1] != '.') + break; + dot = 1; + } - p_realloc(&inbuf, lenbuf + sizeof(buf)); - } + if (funct(inbuf.data + dot, data) < 0) { + buffer_wipe(&inbuf); + ret = PFD_FUNCT_ERROR; + break; + } - p_delete(&inbuf); - return ret; + buffer_reset(&inbuf); + } + + buffer_wipe(&inbuf); + return ret; } static int fetch_capa (char *line, void *data) @@ -578,30 +547,27 @@ static int fetch_auth (char *line, void *data) * -1 - conection lost, * -2 - execution error. */ -static pop_query_status pop_capabilities (pop_data_t * pop_data, int mode) +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_uidl = CMD_NOT_AVAILABLE; - pop_data->cmd_top = CMD_NOT_AVAILABLE; + pop_data->cmd_capa = CMD_NOT_AVAILABLE; + pop_data->cmd_stls = CMD_NOT_AVAILABLE; + pop_data->cmd_uidl = CMD_NOT_AVAILABLE; + pop_data->cmd_top = CMD_NOT_AVAILABLE; + pop_data->cmd_user = CMD_NOT_AVAILABLE; pop_data->resp_codes = 0; - pop_data->expire = 1; - pop_data->login_delay = 0; + pop_data->expire = 1; 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)) { + switch (pop_fetch_data(pop_data, "CAPA\r\n", NULL, fetch_capa, pop_data)) { case PQ_OK: pop_data->cmd_capa = CMD_AVAILABLE; break; @@ -619,14 +585,14 @@ static pop_query_status pop_capabilities (pop_data_t * pop_data, int mode) 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) + if (pop_fetch_data(pop_data, "AUTH\r\n", NULL, fetch_auth, pop_data) == + PQ_NOT_CONNECTED) return PQ_NOT_CONNECTED; } /* Check capabilities */ if (mode == 2) { - char *msg = NULL; + const char *msg = NULL; if (!pop_data->expire) msg = _("Unable to leave messages on server."); @@ -661,7 +627,7 @@ static int pop_parse_path (const char *path, ACCOUNT * act) if (url.scheme == U_POP || url.scheme == U_POPS) { if (url.scheme == U_POPS) { - act->flags |= M_ACCT_SSL; + act->has_ssl = 1; act->port = POP_SSL_PORT; } @@ -710,8 +676,7 @@ static pop_query_status pop_open_connection (pop_data_t * pop_data) pop_data->use_stls = 2; } if (pop_data->use_stls == 2) { - m_strcpy(buf, sizeof(buf), "STLS\r\n"); - ret = pop_query (pop_data, buf, sizeof (buf)); + ret = pop_query(pop_data, buf, sizeof(buf), "STLS"); if (ret == PQ_NOT_CONNECTED) goto err_conn; if (ret != PQ_OK) { @@ -761,8 +726,7 @@ static pop_query_status pop_open_connection (pop_data_t * pop_data) } /* get total size of mailbox */ - m_strcpy(buf, sizeof(buf), "STAT\r\n"); - ret = pop_query (pop_data, buf, sizeof (buf)); + ret = pop_query(pop_data, buf, sizeof(buf), "STAT"); if (ret == PQ_NOT_CONNECTED) goto err_conn; if (ret == PQ_ERR) { @@ -874,21 +838,19 @@ static pop_query_status pop_read_header (pop_data_t * pop_data, HEADER * h) pop_query_status ret; long length; char buf[LONG_STRING]; - char tempfile[_POSIX_PATH_MAX]; - f = m_tempfile(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL); + f = tmpfile(); if (!f) { mutt_error(_("Could not create temporary file")); return PFD_FUNCT_ERROR; } - snprintf (buf, sizeof (buf), "LIST %d\r\n", h->refno); - ret = pop_query (pop_data, buf, sizeof (buf)); + ret = pop_query(pop_data, buf, sizeof(buf), "LIST %d", h->refno); if (ret == PQ_OK) { sscanf (buf, "+OK %d %ld", &idx, &length); snprintf (buf, sizeof (buf), "TOP %d 0\r\n", h->refno); - ret = pop_fetch_data (pop_data, buf, NULL, fetch_message, f); + ret = pop_fetch_data(pop_data, buf, NULL, fetch_message, f); if (pop_data->cmd_top == CMD_UNKNOWN) { if (ret == PQ_OK) { @@ -935,7 +897,6 @@ static pop_query_status pop_read_header (pop_data_t * pop_data, HEADER * h) } m_fclose(&f); - unlink (tempfile); return ret; } @@ -989,7 +950,7 @@ static int pop_fetch_headers (CONTEXT * ctx) ctx->hdrs[i]->refno = -1; old_count = ctx->msgcount; - ret = pop_fetch_data (pop_data, "UIDL\r\n", NULL, fetch_uidl, ctx); + ret = pop_fetch_data(pop_data, "UIDL\r\n", NULL, fetch_uidl, ctx); new_count = ctx->msgcount; ctx->msgcount = old_count; @@ -1098,10 +1059,8 @@ static int pop_open_mailbox (CONTEXT * ctx) if (pop_reconnect (ctx) != PQ_OK) return -1; - ctx->size = pop_data->size; - mutt_message _("Fetching list of messages..."); - + ctx->size = pop_data->size; ret = pop_fetch_headers (ctx); if (ret >= 0) @@ -1142,10 +1101,8 @@ static int pop_check_mailbox(CONTEXT * ctx, int *index_hint, int unused) if (pop_open_connection (pop_data) < 0) return -1; - ctx->size = pop_data->size; - mutt_message _("Checking for new messages..."); - + ctx->size = pop_data->size; ret = pop_fetch_headers (ctx); pop_clear_cache (pop_data); @@ -1198,14 +1155,13 @@ static int pop_sync_mailbox(CONTEXT * ctx, int unused, int *index_hint) for (i = 0, ret = 0; ret == 0 && i < ctx->msgcount; i++) { if (ctx->hdrs[i]->deleted) { - snprintf (buf, sizeof (buf), "DELE %d\r\n", ctx->hdrs[i]->refno); - ret = pop_query (pop_data, buf, sizeof (buf)); + ret = pop_query(pop_data, buf, sizeof(buf), "DELE %d", + ctx->hdrs[i]->refno); } } if (ret == PQ_OK) { - m_strcpy(buf, sizeof(buf), "QUIT\r\n"); - ret = pop_query (pop_data, buf, sizeof (buf)); + ret = pop_query(pop_data, buf, sizeof(buf), "QUIT"); } if (ret == PQ_OK) { @@ -1256,19 +1212,18 @@ void pop_fetch_mail (void) pop_data_t *pop_data; ssize_t plen; - if (!PopHost) { + if (m_strisempty(PopHost)) { mutt_error _("POP host is not defined."); - return; } plen = m_strlen(PopHost) + 7; - url = p = p_new(char, plen); + url = p = p_new(char, plen); if (url_check_scheme (PopHost) == U_UNKNOWN) { - plen -= m_strcpy(url, plen, "pop://"); - p += plen; + snprintf(p, plen, "pop://%s", PopHost); + } else { + m_strcpy(p, plen, PopHost); } - m_strcpy(p, plen, PopHost); ret = pop_parse_path (url, &act); p_delete(&url); @@ -1295,8 +1250,7 @@ void pop_fetch_mail (void) mutt_message _("Checking for new messages..."); /* find out how many messages are in the mailbox. */ - m_strcpy(buffer, sizeof(buffer), "STAT\r\n"); - ret = pop_query (pop_data, buffer, sizeof (buffer)); + ret = pop_query(pop_data, buffer, sizeof(buffer), "STAT"); if (ret == PQ_NOT_CONNECTED) goto fail; if (ret == PQ_ERR) { @@ -1308,8 +1262,7 @@ void pop_fetch_mail (void) /* only get unread messages */ if (msgs > 0 && option (OPTPOPLAST)) { - m_strcpy(buffer, sizeof(buffer), "LAST\r\n"); - ret = pop_query (pop_data, buffer, sizeof (buffer)); + ret = pop_query(pop_data, buffer, sizeof(buffer), "LAST"); if (ret == PQ_NOT_CONNECTED) goto fail; if (ret == PQ_OK) @@ -1337,7 +1290,7 @@ void pop_fetch_mail (void) ret = -3; else { snprintf (buffer, sizeof (buffer), "RETR %d\r\n", i); - ret = pop_fetch_data (pop_data, buffer, NULL, fetch_message, msg->fp); + ret = pop_fetch_data(pop_data, buffer, NULL, fetch_message, msg->fp); if (ret == PFD_FUNCT_ERROR) rset = 1; @@ -1350,9 +1303,7 @@ void pop_fetch_mail (void) } if (ret == PQ_OK && delanswer == M_YES) { - /* delete the message on the server */ - snprintf (buffer, sizeof (buffer), "DELE %d\r\n", i); - ret = pop_query (pop_data, buffer, sizeof (buffer)); + ret = pop_query(pop_data, buffer, sizeof(buffer), "DELE %d", i); } if (ret == PQ_NOT_CONNECTED) { @@ -1377,15 +1328,13 @@ void pop_fetch_mail (void) if (rset) { /* make sure no messages get deleted */ - m_strcpy(buffer, sizeof(buffer), "RSET\r\n"); - if (pop_query (pop_data, buffer, sizeof (buffer)) == PQ_NOT_CONNECTED) + if (pop_query(pop_data, buffer, sizeof(buffer), "RSET") == + PQ_NOT_CONNECTED) goto fail; } finish: - /* exit gracefully */ - m_strcpy(buffer, sizeof(buffer), "QUIT\r\n"); - if (pop_query (pop_data, buffer, sizeof (buffer)) == PQ_NOT_CONNECTED) + if (pop_query(pop_data, buffer, sizeof(buffer), "QUIT") == PQ_NOT_CONNECTED) goto fail; mutt_socket_close (conn); p_delete(&pop_data); @@ -1446,16 +1395,15 @@ int pop_fetch_message (MESSAGE * msg, CONTEXT * ctx, int msgno) bar.msg = _("Fetching message..."); mutt_progress_bar (&bar, 0); - msg->fp = m_tempfile(path, sizeof(path), NONULL(MCore.tmpdir), NULL); + msg->fp = m_tempfile(path, sizeof(path), NONULL(mod_core.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); + 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;