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];
* -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;
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
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;
}
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 ();
/* }}} */
/* Authentication {{{ */
-/* SASL authenticator */
static pop_auth_res_t pop_auth_sasl(pop_data_t *pop_data, const char *method)
{
sasl_conn_t *saslconn;
/* 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;
}
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;
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) {
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;
}
}
};
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])
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;
}
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)
* -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;
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.");
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;
}
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) {
}
/* 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) {
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) {
}
m_fclose(&f);
- unlink (tempfile);
return ret;
}
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;
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)
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);
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) {
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);
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) {
/* 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)
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;
}
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) {
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);
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;