if USE_SASL
SASLSOURCES = auth_sasl.c
else
-CRAMSOURCES = auth_cram.c
+CRAMSOURCES = auth_cram.c md5c.c
endif
if USE_SSL
noinst_HEADERS = auth.h imap_private.h md5.h message.h $(SSLHEADERS)
libimap_a_SOURCES = auth.c auth_anon.c auth_login.c browse.c \
- command.c imap.c imap.h md5c.c message.c utf7.c \
+ command.c imap.c imap.h message.c utf7.c \
util.c $(GSSSOURCES) $(SASLSOURCES) $(CRAMSOURCES) $(SSLSOURCES)
/* this is basically a stripped-down version of the cram-md5 method. */
imap_auth_res_t imap_auth_anon (IMAP_DATA* idata)
{
- char buf[LONG_STRING];
+ int rc;
if (!mutt_bit_isset (idata->capabilities, AUTH_ANON))
return IMAP_AUTH_UNAVAIL;
imap_cmd_start (idata, "AUTHENTICATE ANONYMOUS");
- if (mutt_socket_readln (buf, sizeof (buf), idata->conn) < 0)
- {
- dprint (1, (debugfile, "Error receiving server response.\n"));
- goto bail;
- }
+ do
+ rc = imap_cmd_resp (idata);
+ while (rc == IMAP_CMD_CONTINUE);
- if (buf[0] != '+')
+ if (rc != IMAP_CMD_RESPOND)
{
dprint (1, (debugfile, "Invalid response from server.\n"));
goto bail;
}
- strfcpy (buf, "ZHVtbXkK\r\n", sizeof (buf)); /* base64 ("dummy") */
-
- mutt_socket_write (idata->conn, buf);
+ mutt_socket_write (idata->conn, "ZHVtbXkK\r\n"); /* base64 ("dummy") */
- if (mutt_socket_readln (buf, sizeof (buf), idata->conn) < 0)
+ do
+ rc = imap_cmd_resp (idata);
+ while (rc == IMAP_CMD_CONTINUE);
+
+ if (rc != IMAP_CMD_DONE)
{
dprint (1, (debugfile, "Error receiving server response.\n"));
goto bail;
}
- if (imap_code (buf))
+ if (imap_code (idata->buf))
return IMAP_AUTH_SUCCESS;
bail:
char ibuf[LONG_STRING], obuf[LONG_STRING];
unsigned char hmac_response[MD5_DIGEST_LEN];
int len;
+ int rc;
if (!mutt_bit_isset (idata->capabilities, ACRAM_MD5))
return IMAP_AUTH_UNAVAIL;
* primary host name of the server. The syntax of the unencoded form must
* correspond to that of an RFC 822 'msg-id' [RFC822] as described in [POP3].
*/
- if (mutt_socket_readln (ibuf, sizeof (ibuf), idata->conn) < 0)
- {
- dprint (1, (debugfile, "Error receiving server response.\n"));
- goto bail;
- }
-
- if (ibuf[0] != '+')
+ do
+ rc = imap_cmd_resp (idata);
+ while (rc == IMAP_CMD_CONTINUE);
+
+ if (rc != IMAP_CMD_RESPOND)
{
dprint (1, (debugfile, "Invalid response from server: %s\n", ibuf));
goto bail;
}
- if ((len = mutt_from_base64 (obuf, ibuf + 2)) == -1)
+ if ((len = mutt_from_base64 (obuf, idata->buf + 2)) == -1)
{
dprint (1, (debugfile, "Error decoding base64 response.\n"));
goto bail;
strcpy (ibuf + strlen (ibuf), "\r\n");
mutt_socket_write (idata->conn, ibuf);
- if (mutt_socket_readln (ibuf, LONG_STRING, idata->conn) < 0)
+ do
+ rc = imap_cmd_resp (idata);
+ while (rc == IMAP_CMD_CONTINUE);
+
+ if (rc != IMAP_CMD_DONE)
{
dprint (1, (debugfile, "Error receiving server response.\n"));
goto bail;
}
- if (imap_code (ibuf))
+ if (imap_code (idata->buf))
return IMAP_AUTH_SUCCESS;
bail:
OM_uint32 maj_stat, min_stat;
char buf1[GSS_BUFSIZE], buf2[GSS_BUFSIZE], server_conf_flags;
unsigned long buf_size;
+ int rc;
if (!mutt_bit_isset (idata->capabilities, AGSSAPI))
return IMAP_AUTH_UNAVAIL;
imap_cmd_start (idata, "AUTHENTICATE GSSAPI");
/* expect a null continuation response ("+") */
- if (mutt_socket_readln (buf1, sizeof (buf1), idata->conn) < 0)
- {
- dprint (1, (debugfile, "Error receiving server response.\n"));
- gss_release_name (&min_stat, &target_name);
- goto bail;
- }
+ do
+ rc = imap_cmd_resp (idata);
+ while (rc == IMAP_CMD_CONTINUE);
- if (buf1[0] != '+')
+ if (rc != IMAP_CMD_RESPOND)
{
dprint (2, (debugfile, "Invalid response from server: %s\n", buf1));
gss_release_name (&min_stat, &target_name);
gss_release_name (&min_stat, &target_name);
/* end authentication attempt */
mutt_socket_write (idata->conn, "*\r\n");
- mutt_socket_readln (buf1, sizeof (buf1), idata->conn);
+ do
+ rc = imap_cmd_resp (idata);
+ while (rc == IMAP_CMD_CONTINUE);
goto bail;
}
if (maj_stat == GSS_S_CONTINUE_NEEDED)
{
- if (mutt_socket_readln (buf1, sizeof (buf1), idata->conn) < 0)
+ do
+ rc = imap_cmd_resp (idata);
+ while (rc == IMAP_CMD_CONTINUE);
+
+ if (rc != IMAP_CMD_RESPOND)
{
dprint (1, (debugfile, "Error receiving server response.\n"));
gss_release_name (&min_stat, &target_name);
goto bail;
}
- request_buf.length = mutt_from_base64 (buf2, buf1 + 2);
+ request_buf.length = mutt_from_base64 (buf2, idata->buf + 2);
request_buf.value = buf2;
sec_token = &request_buf;
}
gss_release_name (&min_stat, &target_name);
/* get security flags and buffer size */
- if (mutt_socket_readln (buf1, sizeof (buf1), idata->conn) < 0)
+ do
+ rc = imap_cmd_resp (idata);
+ while (rc == IMAP_CMD_CONTINUE);
+
+ if (rc != IMAP_CMD_RESPOND)
{
dprint (1, (debugfile, "Error receiving server response.\n"));
goto bail;
}
- request_buf.length = mutt_from_base64 (buf2, buf1 + 2);
+ request_buf.length = mutt_from_base64 (buf2, idata->buf + 2);
request_buf.value = buf2;
maj_stat = gss_unwrap (&min_stat, context, &request_buf, &send_token,
mutt_socket_write (idata->conn, buf1);
/* Joy of victory or agony of defeat? */
- if (mutt_socket_readln (buf1, GSS_BUFSIZE, idata->conn) < 0)
+ do
+ rc = imap_cmd_resp (idata);
+ while (rc == IMAP_CMD_CONTINUE);
+ if (rc != IMAP_CMD_DONE)
{
dprint (1, (debugfile, "Error receiving server response.\n"));
mutt_socket_write(idata->conn, "*\r\n");
goto bail;
}
- if (imap_code (buf1))
+ if (imap_code (idata->buf))
{
/* flush the security context */
dprint (2, (debugfile, "Releasing GSS credentials\n"));
imap_auth_res_t imap_auth_login (IMAP_DATA* idata)
{
char q_user[SHORT_STRING], q_pass[SHORT_STRING];
- char buf[LONG_STRING];
+ char buf[STRING];
int rc;
if (mutt_account_getuser (&idata->conn->account))
#endif
snprintf (buf, sizeof (buf), "LOGIN %s %s", q_user, q_pass);
- rc = imap_exec (buf, sizeof (buf), idata, buf,
- IMAP_CMD_FAIL_OK | IMAP_CMD_PASS);
+ rc = imap_exec (idata, buf, IMAP_CMD_FAIL_OK | IMAP_CMD_PASS);
if (!rc)
return IMAP_AUTH_SUCCESS;
{
sasl_conn_t* saslconn;
sasl_interact_t* interaction = NULL;
- int rc;
+ int rc, irc;
char buf[LONG_STRING];
const char* mech;
char* pc;
snprintf (buf, sizeof (buf), "AUTHENTICATE %s", mech);
imap_cmd_start (idata, buf);
+ irc = IMAP_CMD_CONTINUE;
/* looping protocol */
while (rc == SASL_CONTINUE)
{
- if (mutt_socket_readln (buf, sizeof (buf), idata->conn) < 0)
+ do
+ irc = imap_cmd_resp (idata);
+ while (irc == IMAP_CMD_CONTINUE);
+
+ if (irc == IMAP_CMD_FAIL)
goto bail;
- if (!mutt_strncmp (buf, "+ ", 2))
+ if (irc == IMAP_CMD_RESPOND)
{
- if (sasl_decode64 (buf+2, strlen (buf+2), buf, &len) != SASL_OK)
+ if (sasl_decode64 (idata->buf+2, strlen (idata->buf+2), buf, &len) !=
+ SASL_OK)
{
dprint (1, (debugfile, "imap_auth_sasl: error base64-decoding server response.\n"));
goto bail;
}
}
- else if ((buf[0] == '*'))
- {
- if (imap_handle_untagged (idata, buf))
- goto bail;
- else continue;
- }
if (!client_start)
do
}
}
- while (mutt_strncmp (buf, idata->seq, SEQLEN))
- if (mutt_socket_readln (buf, sizeof (buf), idata->conn) < 0)
- goto bail;
+ while (irc != IMAP_CMD_DONE)
+ if ((irc = imap_cmd_resp (idata)) != IMAP_CMD_CONTINUE)
+ break;
if (rc != SASL_OK)
goto bail;
- if (imap_code (buf))
+ if (imap_code (idata->buf))
{
mutt_sasl_setup_conn (idata->conn, saslconn);
return IMAP_AUTH_SUCCESS;
static int browse_verify_namespace (IMAP_DATA* idata,
IMAP_NAMESPACE_INFO* nsi, int nns);
+/* imap_browse: IMAP hook into the folder browser, fills out browser_state,
+ * given a current folder to browse */
int imap_browse (char* path, struct browser_state* state)
{
- CONNECTION *conn;
- IMAP_DATA *idata;
+ IMAP_DATA* idata;
char buf[LONG_STRING];
char nsbuf[LONG_STRING];
char mbox[LONG_STRING];
if (!(idata = imap_conn_find (&(mx.account), 0)))
return -1;
- conn = idata->conn;
if (mx.mbox[0] == '\0')
{
if (browse_verify_namespace (idata, nsi, nns) != 0)
return -1;
}
- /* What if you have a shared namespace of ""? You'll never be
- * able to browse it. This isn't conjecture: connect to the Cyrus
- * reference server (cyrus.andrew.cmu.edu) as anonymous. argh! */
-#if 0
- if (!mx.mbox) /* Any explicitly set imap_home_namespace wins */
- {
- for (i = 0; i < nns; i++)
- if (nsi[i].listable &&
- (nsi[i].type == IMAP_NS_PERSONAL || nsi[i].type == IMAP_NS_SHARED))
- {
- mx.mbox = nsi->prefix;
- nsi->home_namespace = 1;
- break;
- }
- }
- else
- dprint (4, (debugfile, "Home namespace: %s\n", mx.mbox));
-#endif
}
mutt_message _("Getting folder list...");
strncpy (mbox, buf, sizeof (mbox) - 1);
n = mutt_strlen (mbox);
- dprint (3, (debugfile, "imap_init_browse: mbox: %s\n", mbox));
+ dprint (3, (debugfile, "imap_browse: mbox: %s\n", mbox));
/* if our target exists and has inferiors, enter it if we
* aren't already going to */
imap_cmd_start (idata, buf);
do
{
- if (imap_parse_list_response(idata, buf, sizeof(buf), &cur_folder,
- &noselect, &noinferiors, &(idata->delim)) != 0)
+ if (imap_parse_list_response (idata, &cur_folder, &noselect,
+ &noinferiors, &idata->delim) != 0)
return -1;
if (cur_folder)
}
}
}
- while ((mutt_strncmp (buf, idata->seq, SEQLEN) != 0));
+ while (mutt_strncmp (idata->buf, idata->seq, SEQLEN));
}
/* if we're descending a folder, mark it as current in browser_state */
static int browse_add_list_result (IMAP_DATA* idata, const char* cmd,
struct browser_state* state, short isparent)
{
- char buf[LONG_STRING];
char *name;
int noselect;
int noinferiors;
do
{
- if (imap_parse_list_response(idata, buf, sizeof(buf), &name,
- &noselect, &noinferiors, &(idata->delim)) != 0)
+ if (imap_parse_list_response(idata, &name, &noselect, &noinferiors,
+ &idata->delim) != 0)
return -1;
if (name)
isparent);
}
}
- while ((mutt_strncmp (buf, idata->seq, SEQLEN) != 0));
+ while ((mutt_strncmp (idata->buf, idata->seq, SEQLEN) != 0));
return 0;
}
static int browse_get_namespace (IMAP_DATA* idata, char* nsbuf, int nsblen,
IMAP_NAMESPACE_INFO* nsi, int nsilen, int* nns)
{
- char buf[LONG_STRING];
char *s;
int n;
char ns[LONG_STRING];
char delim = '/';
int type;
int nsbused = 0;
+ int rc;
*nns = 0;
nsbuf[nsblen-1] = '\0';
do
{
- if (mutt_socket_readln (buf, sizeof (buf), idata->conn) < 0)
- return -1;
+ if ((rc = imap_cmd_resp (idata)) != IMAP_CMD_CONTINUE)
+ break;
- if (buf[0] == '*')
+ s = imap_next_word (idata->buf);
+ if (mutt_strncasecmp ("NAMESPACE", s, 9) == 0)
{
- s = imap_next_word (buf);
- if (mutt_strncasecmp ("NAMESPACE", s, 9) == 0)
+ /* There are three sections to the response, User, Other, Shared,
+ * and maybe more by extension */
+ for (type = IMAP_NS_PERSONAL; *s; type++)
{
- /* There are three sections to the response, User, Other, Shared,
- * and maybe more by extension */
- for (type = IMAP_NS_PERSONAL; *s; type++)
+ s = imap_next_word (s);
+ if (*s && strncmp (s, "NIL", 3))
{
- s = imap_next_word (s);
- if (*s && strncmp (s, "NIL", 3))
+ s++;
+ while (*s && *s != ')')
{
- s++;
- while (*s && *s != ')')
- {
- s++; /* skip ( */
- /* copy namespace */
- n = 0;
- delim = '\0';
+ s++; /* skip ( */
+ /* copy namespace */
+ n = 0;
+ delim = '\0';
- if (*s == '\"')
+ if (*s == '\"')
+ {
+ s++;
+ while (*s && *s != '\"')
{
- s++;
- while (*s && *s != '\"')
- {
- if (*s == '\\')
- s++;
- ns[n++] = *s;
+ if (*s == '\\')
s++;
- }
+ ns[n++] = *s;
+ s++;
}
- else
- while (*s && !ISSPACE (*s))
- {
- ns[n++] = *s;
- s++;
- }
- ns[n] = '\0';
- /* delim? */
- s = imap_next_word (s);
- /* delimiter is meaningless if namespace is "". Why does
- * Cyrus provide one?! */
- if (n && *s && *s == '\"')
- {
- if (s[1] && s[2] == '\"')
- delim = s[1];
- else if (s[1] && s[1] == '\\' && s[2] && s[3] == '\"')
- delim = s[2];
- }
- /* skip "" namespaces, they are already listed at the root */
- if ((ns[0] != '\0') && (nsbused < nsblen) && (*nns < nsilen))
+ }
+ else
+ while (*s && !ISSPACE (*s))
{
- dprint (3, (debugfile, "browse_get_namespace: adding %s\n", ns));
- nsi->type = type;
- /* Cyrus doesn't append the delimiter to the namespace,
- * but UW-IMAP does. We'll strip it here and add it back
- * as if it were a normal directory, from the browser */
- if (n && (ns[n-1] == delim))
- ns[--n] = '\0';
- strncpy(nsbuf+nsbused,ns,nsblen-nsbused-1);
- nsi->prefix = nsbuf+nsbused;
- nsbused += n+1;
- nsi->delim = delim;
- nsi++;
- (*nns)++;
+ ns[n++] = *s;
+ s++;
}
- while (*s && *s != ')') s++;
- s++;
+ ns[n] = '\0';
+ /* delim? */
+ s = imap_next_word (s);
+ /* delimiter is meaningless if namespace is "". Why does
+ * Cyrus provide one?! */
+ if (n && *s && *s == '\"')
+ {
+ if (s[1] && s[2] == '\"')
+ delim = s[1];
+ else if (s[1] && s[1] == '\\' && s[2] && s[3] == '\"')
+ delim = s[2];
+ }
+ /* skip "" namespaces, they are already listed at the root */
+ if ((ns[0] != '\0') && (nsbused < nsblen) && (*nns < nsilen))
+ {
+ dprint (3, (debugfile, "browse_get_namespace: adding %s\n", ns));
+ nsi->type = type;
+ /* Cyrus doesn't append the delimiter to the namespace,
+ * but UW-IMAP does. We'll strip it here and add it back
+ * as if it were a normal directory, from the browser */
+ if (n && (ns[n-1] == delim))
+ ns[--n] = '\0';
+ strncpy (nsbuf+nsbused,ns,nsblen-nsbused-1);
+ nsi->prefix = nsbuf+nsbused;
+ nsbused += n+1;
+ nsi->delim = delim;
+ nsi++;
+ (*nns)++;
}
+ while (*s && *s != ')') s++;
+ s++;
}
}
}
- else
- {
- if (imap_handle_untagged (idata, buf) != 0)
- return (-1);
- }
}
}
- while ((mutt_strncmp (buf, idata->seq, SEQLEN) != 0));
+ while (rc == IMAP_CMD_CONTINUE);
+
+ if (rc != IMAP_CMD_DONE)
+ return -1;
return 0;
}
nsi->home_namespace = 0;
do
{
- if (imap_parse_list_response(idata, buf, sizeof(buf), &name,
- &(nsi->noselect), &(nsi->noinferiors), &delim) != 0)
+ if (imap_parse_list_response(idata, &name, &nsi->noselect,
+ &nsi->noinferiors, &delim) != 0)
return -1;
nsi->listable |= (name != NULL);
}
- while ((mutt_strncmp (buf, idata->seq, SEQLEN) != 0));
+ while ((mutt_strncmp (idata->buf, idata->seq, SEQLEN) != 0));
}
return 0;
#include <ctype.h>
#include <stdlib.h>
+#define IMAP_CMD_BUFSIZE 512
+
/* forward declarations */
static void cmd_make_sequence (char* buf, size_t buflen);
static void cmd_parse_capabilities (IMAP_DATA* idata, char* s);
safe_free ((void**) &out);
}
+/* imap_cmd_resp: Reads server responses from an IMAP command, detects
+ * tagged completion response, handles untagged messages, can read
+ * arbitrarily large strings (using malloc, so don't make it _too_
+ * large!). */
+int imap_cmd_resp (IMAP_DATA* idata)
+{
+ unsigned int len = 0;
+ int c;
+
+ /* read into buffer, expanding buffer as necessary until we have a full
+ * line */
+ do
+ {
+ if (len == idata->blen)
+ {
+ safe_realloc ((void**) &idata->buf, idata->blen + IMAP_CMD_BUFSIZE);
+ idata->blen = idata->blen + IMAP_CMD_BUFSIZE;
+ dprint (3, (debugfile, "imap_cmd_resp: grew buffer to %u bytes\n", idata->blen));
+ }
+
+ if ((c = mutt_socket_readln (idata->buf + len, idata->blen - len,
+ idata->conn)) < 0)
+ {
+ dprint (1, (debugfile, "imap_cmd_resp: Error while reading server response.\n"));
+ return IMAP_CMD_FAIL;
+ }
+
+ len += c;
+ }
+ /* if we've read all the way to the end of the buffer, we haven't read a
+ * full line (mutt_socket_readln strips the \r, so we always have at least
+ * one character free when we've read a full line) */
+ while (len == idata->blen);
+
+ /* don't let one large string make idata->buf hog memory forever */
+ if ((idata->blen > IMAP_CMD_BUFSIZE) && (len <= IMAP_CMD_BUFSIZE))
+ {
+ safe_realloc ((void**) &idata->buf, IMAP_CMD_BUFSIZE);
+ idata->blen = IMAP_CMD_BUFSIZE;
+ dprint (3, (debugfile, "imap_cmd_resp: shrank buffer to %u bytes\n", idata->blen));
+ }
+
+ /* handle untagged messages. The caller still gets its shot afterwards. */
+ if (!strncmp (idata->buf, "* ", 2) &&
+ imap_handle_untagged (idata, idata->buf))
+ return IMAP_CMD_FAIL;
+
+ /* server demands a continuation response from us */
+ if (!strncmp (idata->buf, "+ ", 2))
+ return IMAP_CMD_RESPOND;
+
+ /* tagged completion code */
+ if (!mutt_strncmp (idata->buf, idata->seq, SEQLEN))
+ {
+ imap_cmd_finish (idata);
+ return IMAP_CMD_DONE;
+ }
+
+ return IMAP_CMD_CONTINUE;
+}
+
/* imap_cmd_finish: When the caller has finished reading command responses,
* it must call this routine to perform cleanup (eg fetch new mail if
* detected, do expunge) */
}
idata->status = 0;
- mutt_clear_error ();
}
/* imap_code: returns 1 if the command result was OK, or 0 if NO or BAD */
* IMAP_CMD_PASS: command contains a password. Suppress logging.
* Return 0 on success, -1 on Failure, -2 on OK Failure
*/
-int imap_exec (char* buf, size_t buflen, IMAP_DATA* idata, const char* cmd,
- int flags)
+int imap_exec (IMAP_DATA* idata, const char* cmd, int flags)
{
char* out;
int outlen;
+ int rc;
/* create sequence for command */
cmd_make_sequence (idata->seq, sizeof (idata->seq));
safe_free ((void**) &out);
do
- {
- if (mutt_socket_readln (buf, buflen, idata->conn) < 0)
- return -1;
-
- if (buf[0] == '*' && imap_handle_untagged (idata, buf) != 0)
- return -1;
- }
- while (mutt_strncmp (buf, idata->seq, SEQLEN) != 0);
+ rc = imap_cmd_resp (idata);
+ while (rc == IMAP_CMD_CONTINUE);
- imap_cmd_finish (idata);
+ if (rc != IMAP_CMD_DONE)
+ return -1;
- if (!imap_code (buf))
+ if (!imap_code (idata->buf))
{
char *pc;
if (flags & IMAP_CMD_FAIL_OK)
return -2;
- dprint (1, (debugfile, "imap_exec: command failed: %s\n", buf));
- pc = buf + SEQLEN;
- SKIPWS (pc);
+ dprint (1, (debugfile, "imap_exec: command failed: %s\n", idata->buf));
+ pc = idata->buf;
pc = imap_next_word (pc);
mutt_error ("%s", pc);
- sleep (1);
+ sleep (2);
return -1;
}
}
/* imap_handle_untagged: fallback parser for otherwise unhandled messages. */
-int imap_handle_untagged (IMAP_DATA *idata, char *s)
+int imap_handle_untagged (IMAP_DATA* idata, char* s)
{
char *pn;
int count;
*/
if (mutt_strncasecmp ("EXISTS", s, 6) == 0)
{
+ dprint (2, (debugfile, "Handling EXISTS\n"));
+
/* new mail arrived */
count = atoi (pn);
cmd_parse_myrights (idata, s);
else if (mutt_strncasecmp ("BYE", s, 3) == 0)
{
+ dprint (2, (debugfile, "Handling BYE\n"));
+
+ /* check if we're logging out */
+ if (idata->status == IMAP_BYE)
+ return 0;
+
/* server shut down our connection */
s += 3;
SKIPWS (s);
}
else if (option (OPTIMAPSERVERNOISE) && (mutt_strncasecmp ("NO", s, 2) == 0))
{
+ dprint (2, (debugfile, "Handling untagged NO\n"));
+
/* Display the warning message from the server */
mutt_error ("%s", s+3);
sleep (2);
}
- else
- dprint (1, (debugfile, "imap_handle_untagged(): unhandled request: %s\n",
- s));
return 0;
}
{
int x;
+ dprint (2, (debugfile, "Handling CAPABILITY\n"));
+
idata->capstr = safe_strdup (imap_next_word (s));
while (*s)
int expno, cur;
HEADER* h;
+ dprint (2, (debugfile, "Handling EXPUNGE\n"));
+
expno = atoi (s);
/* walk headers, zero seqno of expunged message, decrement seqno of those
/* cmd_parse_myrights: set rights bits according to MYRIGHTS response */
static void cmd_parse_myrights (IMAP_DATA* idata, char* s)
{
+ dprint (2, (debugfile, "Handling MYRIGHTS\n"));
+
s = imap_next_word (s);
s = imap_next_word (s);
imap_munge_mbox_name (mbox, sizeof (mbox), mailbox);
snprintf (buf, sizeof (buf), "CREATE %s", mbox);
- if (imap_exec (buf, sizeof (buf), CTX_DATA, buf, 0) != 0)
+ if (imap_exec ((IMAP_DATA*) ctx->data, buf, 0) != 0)
{
- imap_error ("imap_create_mailbox()", buf);
+ imap_error ("imap_create_mailbox", CTX_DATA->buf);
return -1;
}
+
return 0;
}
imap_quote_string (mbox, sizeof (mbox), mailbox);
snprintf (buf, sizeof (buf), "DELETE %s", mbox);
- if (imap_exec (buf, sizeof (buf), CTX_DATA, buf, 0) != 0)
+ if (imap_exec ((IMAP_DATA*) ctx->data, buf, 0) != 0)
+ {
+ imap_error ("imap_delete_mailbox", CTX_DATA->buf);
return -1;
+ }
return 0;
}
static int imap_get_delim (IMAP_DATA *idata)
{
- char buf[LONG_STRING];
char *s;
+ int rc;
/* assume that the delim is /. If this fails, we're in bigger trouble
* than getting the delim wrong */
do
{
- if (mutt_socket_readln (buf, sizeof (buf), idata->conn) < 0)
- return -1;
+ if ((rc = imap_cmd_resp (idata)) != IMAP_CMD_CONTINUE)
+ break;
- if (buf[0] == '*')
+ s = imap_next_word (idata->buf);
+ if (mutt_strncasecmp ("LIST", s, 4) == 0)
{
- s = imap_next_word (buf);
- if (mutt_strncasecmp ("LIST", s, 4) == 0)
- {
- s = imap_next_word (s);
- s = imap_next_word (s);
- if (s && s[0] == '\"' && s[1] && s[2] == '\"')
- idata->delim = s[1];
- else if (s && s[0] == '\"' && s[1] && s[1] == '\\' && s[2] && s[3] == '\"')
- idata->delim = s[2];
- }
- else
- {
- if (imap_handle_untagged (idata, buf) != 0)
- return -1;
- }
+ s = imap_next_word (s);
+ s = imap_next_word (s);
+ if (s && s[0] == '\"' && s[1] && s[2] == '\"')
+ idata->delim = s[1];
+ else if (s && s[0] == '\"' && s[1] && s[1] == '\\' && s[2] && s[3] == '\"')
+ idata->delim = s[2];
}
}
- while ((mutt_strncmp (buf, idata->seq, SEQLEN) != 0));
+ while (rc == IMAP_CMD_CONTINUE);
- return 0;
+ if (rc != IMAP_CMD_DONE)
+ {
+ dprint (1, (debugfile, "imap_get_delim: failed.\n"));
+ return -1;
+ }
+
+ dprint (2, (debugfile, "Delimiter: %c\n", idata->delim));
+
+ return -1;
}
/* get rights for folder, let imap_handle_untagged do the rest */
imap_munge_mbox_name (mbox, sizeof(mbox), idata->mailbox);
snprintf (buf, sizeof (buf), "MYRIGHTS %s", mbox);
- if (imap_exec (buf, sizeof (buf), idata, buf, 0) != 0)
+ if (imap_exec (idata, buf, 0) != 0)
{
imap_error ("imap_check_acl", buf);
return -1;
/* imap_check_capabilities: make sure we can log in to this server. */
static int imap_check_capabilities (IMAP_DATA* idata)
{
- char buf[LONG_STRING];
-
- if (imap_exec (buf, sizeof (buf), idata, "CAPABILITY", 0) != 0)
+ if (imap_exec (idata, "CAPABILITY", 0) != 0)
{
- imap_error ("imap_check_capabilities", buf);
+ imap_error ("imap_check_capabilities", idata->buf);
return -1;
}
idata->state = IMAP_CONNECTED;
- if (mutt_socket_readln (buf, sizeof (buf), idata->conn) < 0)
+ if (imap_cmd_resp (idata) != IMAP_CMD_CONTINUE)
goto bail;
- if (mutt_strncmp ("* OK", buf, 4) == 0)
+ if (mutt_strncmp ("* OK", idata->buf, 4) == 0)
{
if (imap_check_capabilities (idata) || imap_authenticate (idata))
goto bail;
}
- else if (mutt_strncmp ("* PREAUTH", buf, 9) == 0)
+ else if (mutt_strncmp ("* PREAUTH", idata->buf, 9) == 0)
{
- if (imap_check_capabilities(idata) != 0)
+ if (imap_check_capabilities (idata) != 0)
goto bail;
}
else
char buf[LONG_STRING];
char bufout[LONG_STRING];
int count = 0;
- int n;
IMAP_MBOX mx;
+ int rc;
if (imap_parse_path (ctx->path, &mx))
{
conn = idata->conn;
/* once again the context is new */
- ctx->data = (void *) idata;
+ ctx->data = idata;
/* Clean up path and replace the one in the ctx */
imap_fix_path (idata, mx.mbox, buf, sizeof (buf));
{
char *pc;
- if (mutt_socket_readln (buf, sizeof (buf), conn) < 0)
+ if ((rc = imap_cmd_resp (idata)) != IMAP_CMD_CONTINUE)
break;
- if (buf[0] == '*')
+ pc = idata->buf + 2;
+ pc = imap_next_word (pc);
+ if (!mutt_strncasecmp ("EXISTS", pc, 6))
{
- pc = buf + 2;
+ /* imap_handle_untagged will have picked up the EXISTS message and
+ * set the NEW_MAIL flag. We clear it here. */
+ idata->status = 0;
+ count = idata->newMailCount;
+ idata->newMailCount = 0;
+ }
- if (isdigit (*pc))
- {
- char *pn = pc;
+ pc = idata->buf + 2;
- while (*pc && isdigit (*pc))
- pc++;
- *pc++ = '\0';
- n = atoi (pn);
- SKIPWS (pc);
- if (mutt_strncasecmp ("EXISTS", pc, 6) == 0)
- count = n;
- }
- /* Obtain list of available flags here, may be overridden by a
- * PERMANENTFLAGS tag in the OK response */
- else if (mutt_strncasecmp ("FLAGS", pc, 5) == 0)
- {
- /* don't override PERMANENTFLAGS */
- if (!idata->flags)
- {
- dprint (2, (debugfile, "Getting mailbox FLAGS\n"));
- if ((pc = imap_get_flags (&(idata->flags), pc)) == NULL)
- return -1;
- }
- }
- /* PERMANENTFLAGS are massaged to look like FLAGS, then override FLAGS */
- else if (mutt_strncasecmp ("OK [PERMANENTFLAGS", pc, 18) == 0)
+ /* Obtain list of available flags here, may be overridden by a
+ * PERMANENTFLAGS tag in the OK response */
+ if (mutt_strncasecmp ("FLAGS", pc, 5) == 0)
+ {
+ /* don't override PERMANENTFLAGS */
+ if (!idata->flags)
{
- dprint (2, (debugfile,
- "Getting mailbox PERMANENTFLAGS\n"));
- /* safe to call on NULL */
- mutt_free_list (&(idata->flags));
- /* skip "OK [PERMANENT" so syntax is the same as FLAGS */
- pc += 13;
- if ((pc = imap_get_flags (&(idata->flags), pc)) == NULL)
- return -1;
+ dprint (2, (debugfile, "Getting mailbox FLAGS\n"));
+ if ((pc = imap_get_flags (&(idata->flags), pc)) == NULL)
+ return -1;
}
- else if (imap_handle_untagged (idata, buf) != 0)
- return (-1);
+ }
+ /* PERMANENTFLAGS are massaged to look like FLAGS, then override FLAGS */
+ else if (mutt_strncasecmp ("OK [PERMANENTFLAGS", pc, 18) == 0)
+ {
+ dprint (2, (debugfile, "Getting mailbox PERMANENTFLAGS\n"));
+ /* safe to call on NULL */
+ mutt_free_list (&(idata->flags));
+ /* skip "OK [PERMANENT" so syntax is the same as FLAGS */
+ pc += 13;
+ if ((pc = imap_get_flags (&(idata->flags), pc)) == NULL)
+ return -1;
}
}
- while (mutt_strncmp (idata->seq, buf, mutt_strlen (idata->seq)) != 0);
+ while (rc == IMAP_CMD_CONTINUE);
+
+ if (rc != IMAP_CMD_DONE)
+ return -1;
+
/* check for READ-ONLY notification */
- if (!strncmp (imap_get_qualifier (buf), "[READ-ONLY]", 11))
+ if (!strncmp (imap_get_qualifier (idata->buf), "[READ-ONLY]", 11))
{
dprint (2, (debugfile, "Mailbox is read-only.\n"));
ctx->readonly = 1;
}
#endif
- if (!imap_code (buf))
+ if (!imap_code (idata->buf))
{
char *s;
- s = imap_next_word (buf); /* skip seq */
+ s = imap_next_word (idata->buf); /* skip seq */
s = imap_next_word (s); /* Skip response */
mutt_error ("%s", s);
idata->state = IMAP_AUTHENTICATED;
return -1;
}
- r = imap_exec (buf, sizeof (buf), idata, buf, IMAP_CMD_FAIL_OK);
+ r = imap_exec (idata, buf, IMAP_CMD_FAIL_OK);
if (r == -2)
{
/* command failed cause folder doesn't exist */
return 0;
}
+/* imap_logout: Gracefully log out of server. */
void imap_logout (IMAP_DATA* idata)
{
- char buf[LONG_STRING];
-
+ /* we set status here to let imap_handle_untagged know we _expect_ to
+ * receive a bye response (so it doesn't freak out and close the conn) */
+ idata->status = IMAP_BYE;
imap_cmd_start (idata, "LOGOUT");
-
- do
- {
- if (mutt_socket_readln (buf, sizeof (buf), idata->conn) < 0)
- break;
- }
- while (mutt_strncmp (idata->seq, buf, SEQLEN) != 0);
+ while (imap_cmd_resp (idata) == IMAP_CMD_CONTINUE)
+ ;
}
int imap_close_connection (CONTEXT *ctx)
mutt_message (_("Marking %d messages deleted..."), deleted);
snprintf (tmp, sizeof (tmp), "UID STORE %s +FLAGS.SILENT (\\Deleted)",
buf);
- if (imap_exec (buf, sizeof (buf), idata, tmp, 0) != 0)
+ if (imap_exec (idata, tmp, 0) != 0)
/* continue, let regular store try before giving up */
dprint(2, (debugfile, "imap_sync_mailbox: fast delete failed\n"));
else
/* after all this it's still possible to have no flags, if you
* have no ACL rights */
- if (*flags && (imap_exec (buf, sizeof (buf), idata, buf, 0) != 0) &&
+ if (*flags && (imap_exec (idata, buf, 0) != 0) &&
(err_continue != M_YES))
{
err_continue = imap_continue ("imap_sync_mailbox: STORE failed", buf);
mutt_bit_isset(idata->rights, IMAP_ACL_DELETE))
{
mutt_message _("Expunging messages from server...");
- if (imap_exec (buf, sizeof (buf), CTX_DATA, "EXPUNGE", 0) != 0)
+ if (imap_exec (idata, "EXPUNGE", 0) != 0)
{
imap_error ("imap_sync_mailbox: EXPUNGE failed", buf);
return -1;
void imap_close_mailbox (CONTEXT* ctx)
{
IMAP_DATA* idata;
- char buf[LONG_STRING];
int i;
idata = (IMAP_DATA*) ctx->data;
if (!(idata->noclose))
{
mutt_message _("Closing mailbox...");
- if (imap_exec (buf, sizeof (buf), idata, "CLOSE", 0) != 0)
- imap_error ("CLOSE failed", buf);
+ if (imap_exec (idata, "CLOSE", 0) != 0)
+ imap_error ("CLOSE failed", idata->buf);
}
idata->state = IMAP_AUTHENTICATED;
*/
int imap_check_mailbox (CONTEXT *ctx, int *index_hint)
{
- char buf[LONG_STRING];
static time_t checktime=0;
+
+ IMAP_DATA* idata;
time_t t = 0;
+ idata = (IMAP_DATA*) ctx->data;
+
/*
* gcc thinks it has to warn about uninitialized use
* of t. This is wrong.
t -= checktime;
}
+ /* TODO: wtf?! */
if ((ImapCheckTimeout && t >= ImapCheckTimeout)
- || ((CTX_DATA->reopen & IMAP_REOPEN_ALLOW) && (CTX_DATA->reopen & ~IMAP_REOPEN_ALLOW)))
+ || ((idata->reopen & IMAP_REOPEN_ALLOW) && (idata->reopen & ~IMAP_REOPEN_ALLOW)))
{
if (ImapCheckTimeout) checktime += t;
- CTX_DATA->check_status = 0;
- if (imap_exec (buf, sizeof (buf), CTX_DATA, "NOOP", 0) != 0)
+ idata->check_status = 0;
+ if (imap_exec (idata, "NOOP", 0) != 0)
{
- imap_error ("imap_check_mailbox()", buf);
+ imap_error ("imap_check_mailbox", idata->buf);
return -1;
}
- if (CTX_DATA->check_status == IMAP_NEW_MAIL)
+ if (idata->check_status == IMAP_NEW_MAIL)
return M_NEW_MAIL;
- if (CTX_DATA->check_status == IMAP_REOPENED)
+ if (idata->check_status == IMAP_REOPENED)
return M_REOPENED;
}
int msgcount = 0;
int connflags = 0;
IMAP_MBOX mx;
+ int rc;
if (imap_parse_path (path, &mx))
return -1;
do
{
- if (mutt_socket_readln (buf, sizeof (buf), conn) < 0)
- return -1;
+ if ((rc = imap_cmd_resp (idata)) != IMAP_CMD_CONTINUE)
+ break;
- if (buf[0] == '*')
+ s = imap_next_word (idata->buf);
+ if (mutt_strncasecmp ("STATUS", s, 6) == 0)
{
- s = imap_next_word (buf);
- if (mutt_strncasecmp ("STATUS", s, 6) == 0)
+ s = imap_next_word (s);
+ /* The mailbox name may or may not be quoted here. We could try to
+ * munge the server response and compare with quoted (or vise versa)
+ * but it is probably more efficient to just strncmp against both. */
+ if (mutt_strncmp (mbox_unquoted, s, mutt_strlen (mbox_unquoted)) == 0
+ || mutt_strncmp (mbox, s, mutt_strlen (mbox)) == 0)
{
s = imap_next_word (s);
- /* The mailbox name may or may not be quoted here. We could try to
- * munge the server response and compare with quoted (or vise versa)
- * but it is probably more efficient to just strncmp against both. */
- if (mutt_strncmp (mbox_unquoted, s, mutt_strlen (mbox_unquoted)) == 0
- || mutt_strncmp (mbox, s, mutt_strlen (mbox)) == 0)
+ s = imap_next_word (s);
+ if (isdigit (*s))
{
- s = imap_next_word (s);
- s = imap_next_word (s);
- if (isdigit (*s))
+ if (*s != '0')
{
- if (*s != '0')
- {
- dprint (1, (debugfile, "Mail in %s\n", path));
- msgcount = atoi(s);
- }
+ dprint (1, (debugfile, "Mail in %s\n", path));
+ msgcount = atoi(s);
}
}
- else
- dprint (1, (debugfile, "imap_mailbox_check: STATUS response doesn't match requested mailbox.\n"));
}
else
- {
- if (conn->data &&
- imap_handle_untagged (idata, buf) != 0)
- return -1;
- }
+ dprint (1, (debugfile, "imap_mailbox_check: STATUS response doesn't match requested mailbox.\n"));
}
}
- while ((mutt_strncmp (buf, idata->seq, SEQLEN) != 0));
-
- imap_cmd_finish (idata);
+ while (rc == IMAP_CMD_CONTINUE);
return msgcount;
}
-int imap_parse_list_response(IMAP_DATA* idata, char *buf, int buflen,
- char **name, int *noselect, int *noinferiors, char *delim)
+/* all this listing/browsing is a mess. I don't like that name is a pointer
+ * into idata->buf (used to be a pointer into the passed in buffer, just
+ * as bad), nor do I like the fact that the fetch is done here. This
+ * code can't possibly handle non-LIST untagged responses properly.
+ * FIXME. ?! */
+int imap_parse_list_response(IMAP_DATA* idata, char **name, int *noselect,
+ int *noinferiors, char *delim)
{
char *s;
long bytes;
+ int rc;
*name = NULL;
- if (mutt_socket_readln (buf, buflen, idata->conn) < 0)
+ rc = imap_cmd_resp (idata);
+ if (rc == IMAP_CMD_DONE)
+ return 0;
+ if (rc != IMAP_CMD_CONTINUE)
return -1;
- if (buf[0] == '*')
+ s = imap_next_word (idata->buf);
+ if ((mutt_strncasecmp ("LIST", s, 4) == 0) ||
+ (mutt_strncasecmp ("LSUB", s, 4) == 0))
{
- s = imap_next_word (buf);
- if ((mutt_strncasecmp ("LIST", s, 4) == 0) ||
- (mutt_strncasecmp ("LSUB", s, 4) == 0))
- {
- *noselect = 0;
- *noinferiors = 0;
+ *noselect = 0;
+ *noinferiors = 0;
- s = imap_next_word (s); /* flags */
- if (*s == '(')
- {
- char *ep;
-
- s++;
- ep = s;
- while (*ep && *ep != ')') ep++;
- do {
- if (!strncasecmp (s, "\\NoSelect", 9))
- *noselect = 1;
- if (!strncasecmp (s, "\\NoInferiors", 12))
- *noinferiors = 1;
- if (*s != ')')
- s++;
- while (*s && *s != '\\' && *s != ')') s++;
- } while (s != ep);
- }
- else
- return (0);
- s = imap_next_word (s); /* delim */
- /* Reset the delimiter, this can change */
- if (strncmp (s, "NIL", 3))
+ s = imap_next_word (s); /* flags */
+ if (*s == '(')
+ {
+ char *ep;
+
+ s++;
+ ep = s;
+ while (*ep && *ep != ')') ep++;
+ do
{
- if (s && s[0] == '\"' && s[1] && s[2] == '\"')
- *delim = s[1];
- else if (s && s[0] == '\"' && s[1] && s[1] == '\\' && s[2] && s[3] == '\"')
- *delim = s[2];
- }
- s = imap_next_word (s); /* name */
- if (s && *s == '{') /* Literal */
- {
- int len;
-
- if (imap_get_literal_count(buf, &bytes) < 0)
- return -1;
- len = mutt_socket_readln (buf, buflen, idata->conn);
- if (len < 0)
- return -1;
- *name = buf;
- }
- else
- *name = s;
+ if (!strncasecmp (s, "\\NoSelect", 9))
+ *noselect = 1;
+ if (!strncasecmp (s, "\\NoInferiors", 12))
+ *noinferiors = 1;
+ if (*s != ')')
+ s++;
+ while (*s && *s != '\\' && *s != ')') s++;
+ } while (s != ep);
}
else
+ return 0;
+ s = imap_next_word (s); /* delim */
+ /* Reset the delimiter, this can change */
+ if (strncmp (s, "NIL", 3))
{
- if (imap_handle_untagged (idata, buf) != 0)
+ if (s && s[0] == '\"' && s[1] && s[2] == '\"')
+ *delim = s[1];
+ else if (s && s[0] == '\"' && s[1] && s[1] == '\\' && s[2] && s[3] == '\"')
+ *delim = s[2];
+ }
+ s = imap_next_word (s); /* name */
+ if (s && *s == '{') /* Literal */
+ {
+ if (imap_get_literal_count(idata->buf, &bytes) < 0)
return -1;
+ if (imap_cmd_resp (idata) != IMAP_CMD_CONTINUE)
+ return -1;
+ *name = idata->buf;
}
+ else
+ *name = s;
}
return 0;
snprintf (buf, sizeof (buf), "%s %s", subscribe ? "SUBSCRIBE" :
"UNSUBSCRIBE", mbox);
- if (imap_exec (buf, sizeof (buf), idata, buf, 0) < 0)
+ if (imap_exec (idata, buf, 0) < 0)
return -1;
return 0;
strfcpy (completion, mx.mbox, sizeof(completion));
do
{
- if (imap_parse_list_response(idata, buf, sizeof(buf), &list_word,
- &noselect, &noinferiors, &delim))
+ if (imap_parse_list_response(idata, &list_word, &noselect, &noinferiors,
+ &delim))
break;
if (list_word)
completions++;
}
}
- while (mutt_strncmp(idata->seq, buf, SEQLEN));
+ while (mutt_strncmp(idata->seq, idata->buf, SEQLEN));
if (completions)
{
#define IMAP_LOG_LTRL 4
#define IMAP_LOG_PASS 5
+/* IMAP command responses */
+#define IMAP_CMD_DONE (0)
+#define IMAP_CMD_FAIL (-1)
+#define IMAP_CMD_CONTINUE (1)
+#define IMAP_CMD_RESPOND (2)
+
/* number of entries in the hash table */
#define IMAP_CACHE_LEN 10
unsigned char status;
unsigned char check_status;
unsigned char capabilities[(CAPMAX + 7)/8];
+ char seq[SEQLEN+1];
+ /* command input buffer */
+ char* buf;
+ unsigned int blen;
/* let me explain capstr: SASL needs the capability string (not bits).
* we have 3 options:
* 1. rerun CAPABILITY inside SASL function.
* tracking all possible capabilities. bah. (1) I don't like because
* it's just no fun to get the same information twice */
char* capstr;
- char seq[SEQLEN+1];
/* The following data is all specific to the currently SELECTED mbox */
char delim;
int imap_open_connection (IMAP_DATA* idata);
IMAP_DATA* imap_conn_find (const ACCOUNT* account, int flags);
time_t imap_parse_date (char* s);
-int imap_parse_list_response(IMAP_DATA* idata, char* buf, int buflen,
- char** name, int* noselect, int* noinferiors, char* delim);
+int imap_parse_list_response(IMAP_DATA* idata, char** name, int* noselect,
+ int* noinferiors, char* delim);
int imap_read_literal (FILE* fp, IMAP_DATA* idata, long bytes);
void imap_expunge_mailbox (IMAP_DATA* idata);
int imap_reopen_mailbox (IMAP_DATA* idata);
/* command.c */
void imap_cmd_start (IMAP_DATA* idata, const char* cmd);
+int imap_cmd_resp (IMAP_DATA* idata);
void imap_cmd_finish (IMAP_DATA* idata);
int imap_code (const char* s);
-int imap_exec (char* buf, size_t buflen, IMAP_DATA* idata, const char* cmd,
- int flags);
+int imap_exec (IMAP_DATA* idata, const char* cmd, int flags);
int imap_handle_untagged (IMAP_DATA* idata, char* s);
/* message.c */
*/
int imap_read_headers (CONTEXT *ctx, int msgbegin, int msgend)
{
+ IMAP_DATA* idata;
char buf[LONG_STRING];
char hdrreq[STRING];
FILE *fp;
char tempfile[_POSIX_PATH_MAX];
int msgno;
IMAP_HEADER h;
- int rc;
+ int rc, mfhrc;
int fetchlast = 0;
const char *want_headers = "DATE FROM SUBJECT TO CC MESSAGE-ID REFERENCES CONTENT-TYPE IN-REPLY-TO REPLY-TO LINES X-LABEL";
+
+ idata = (IMAP_DATA*) ctx->data;
/* define search string */
- if (mutt_bit_isset (CTX_DATA->capabilities,IMAP4REV1))
+ if (mutt_bit_isset (idata->capabilities,IMAP4REV1))
{
snprintf (hdrreq, sizeof (hdrreq), "BODY.PEEK[HEADER.FIELDS (%s)]",
want_headers);
}
- else if (mutt_bit_isset (CTX_DATA->capabilities,IMAP4))
+ else if (mutt_bit_isset (idata->capabilities,IMAP4))
{
snprintf (hdrreq, sizeof (hdrreq), "RFC822.HEADER.LINES (%s)",
want_headers);
else
{ /* Unable to fetch headers for lower versions */
mutt_error _("Unable to fetch headers from this IMAP server version.");
- sleep (1); /* pause a moment to let the user see the error */
+ sleep (2); /* pause a moment to let the user see the error */
return -1;
}
"FETCH %d:%d (UID FLAGS INTERNALDATE RFC822.SIZE %s)", msgno + 1,
msgend + 1, hdrreq);
- imap_cmd_start (CTX_DATA, buf);
+ imap_cmd_start (idata, buf);
fetchlast = msgend + 1;
}
*/
do
{
- rc = 0;
-
- if (mutt_socket_readln (buf, sizeof (buf), CTX_DATA->conn) < 0)
- {
- imap_free_header_data ((void**) &h.data);
- fclose (fp);
- return -1;
- }
-
- if (buf[0] == '*')
- {
- if ((rc = msg_fetch_header (ctx, &h, buf, fp)))
- {
- if (rc == -1 && !imap_handle_untagged (CTX_DATA, buf))
- continue;
- else
- {
- imap_free_header_data ((void**) h.data);
- fclose (fp);
- return -1;
- }
- }
+ mfhrc = 0;
+
+ rc = imap_cmd_resp (idata);
+ if (rc != IMAP_CMD_CONTINUE)
+ break;
+
+ if ((mfhrc = msg_fetch_header (ctx, &h, idata->buf, fp)) == -1)
+ continue;
+ else if (mfhrc < 0)
+ break;
+
+ /* make sure we don't get remnants from older larger message headers */
+ fputs ("\n\n", fp);
+
+ /* update context with message header */
+ ctx->hdrs[msgno] = mutt_new_header ();
+ ctx->hdrs[msgno]->index = ctx->msgcount;
+
+ /* messages which have not been expunged are ACTIVE (borrowed from mh
+ * folders) */
+ ctx->hdrs[msgno]->active = 1;
+ ctx->hdrs[msgno]->read = h.read;
+ ctx->hdrs[msgno]->old = h.old;
+ ctx->hdrs[msgno]->deleted = h.deleted;
+ ctx->hdrs[msgno]->flagged = h.flagged;
+ ctx->hdrs[msgno]->replied = h.replied;
+ ctx->hdrs[msgno]->changed = h.changed;
+ ctx->hdrs[msgno]->received = h.received;
+ ctx->hdrs[msgno]->data = (void *) (h.data);
+
+ rewind (fp);
+ /* NOTE: if Date: header is missing, mutt_read_rfc822_header depends
+ * on h.received being set */
+ ctx->hdrs[msgno]->env = mutt_read_rfc822_header (fp, ctx->hdrs[msgno],
+ 0, 0);
+ /* content built as a side-effect of mutt_read_rfc822_header */
+ ctx->hdrs[msgno]->content->length = h.content_length;
+
+ mx_update_context (ctx); /* increments ->msgcount */
+ }
+ while ((rc != IMAP_CMD_DONE) && ((mfhrc == -1) ||
+ ((msgno + 1) >= fetchlast)));
- /* make sure we don't get remnants from older larger message headers */
- fputs ("\n\n", fp);
-
- /* update context with message header */
- ctx->hdrs[msgno] = mutt_new_header ();
- ctx->hdrs[msgno]->index = ctx->msgcount;
-
- /* messages which have not been expunged are ACTIVE (borrowed from
- * mh folders) */
- ctx->hdrs[msgno]->active = 1;
- ctx->hdrs[msgno]->read = h.read;
- ctx->hdrs[msgno]->old = h.old;
- ctx->hdrs[msgno]->deleted = h.deleted;
- ctx->hdrs[msgno]->flagged = h.flagged;
- ctx->hdrs[msgno]->replied = h.replied;
- ctx->hdrs[msgno]->changed = h.changed;
- ctx->hdrs[msgno]->received = h.received;
- ctx->hdrs[msgno]->data = (void *) (h.data);
-
- rewind (fp);
- /* NOTE: if Date: header is missing, mutt_read_rfc822_header depends
- * on h.received being set */
- ctx->hdrs[msgno]->env = mutt_read_rfc822_header (fp, ctx->hdrs[msgno],
- 0, 0);
- /* content built as a side-effect of mutt_read_rfc822_header */
- ctx->hdrs[msgno]->content->length = h.content_length;
-
- mx_update_context (ctx); /* increments ->msgcount */
+ if ((mfhrc < -1) || ((rc != IMAP_CMD_CONTINUE) && (rc != IMAP_CMD_DONE)))
+ {
+ imap_free_header_data ((void**) &h.data);
+ fclose (fp);
- }
+ return -1;
}
- while ((rc == -1) || ((msgno + 1) >= fetchlast &&
- !mutt_strncmp (CTX_DATA->seq, buf, SEQLEN) != 0));
-
+
/* h.data shouldn't be freed here, it is kept in ctx->headers */
/* in case we get new mail while fetching the headers */
- if (CTX_DATA->status == IMAP_NEW_MAIL)
+ if (idata->status == IMAP_NEW_MAIL)
{
- msgend = CTX_DATA->newMailCount - 1;
+ msgend = idata->newMailCount - 1;
while ((msgend) >= ctx->hdrmax)
mx_alloc_memory (ctx);
- CTX_DATA->status = 0;
+ idata->status = 0;
}
}
int imap_fetch_message (MESSAGE *msg, CONTEXT *ctx, int msgno)
{
+ IMAP_DATA* idata;
char buf[LONG_STRING];
char path[_POSIX_PATH_MAX];
char *pc;
int uid;
int cacheno;
IMAP_CACHE *cache;
+ int rc;
+
+ idata = (IMAP_DATA*) ctx->data;
/* see if we already have the message in our cache */
cacheno = HEADER_DATA(ctx->hdrs[msgno])->uid % IMAP_CACHE_LEN;
- cache = &CTX_DATA->cache[cacheno];
+ cache = &idata->cache[cacheno];
if (cache->path)
{
snprintf (buf, sizeof (buf), "UID FETCH %d RFC822",
HEADER_DATA(ctx->hdrs[msgno])->uid);
- imap_cmd_start (CTX_DATA, buf);
+ imap_cmd_start (idata, buf);
do
{
- if (mutt_socket_readln (buf, sizeof (buf), CTX_DATA->conn) < 0)
- goto bail;
+ if ((rc = imap_cmd_resp (idata)) != IMAP_CMD_CONTINUE)
+ continue;
- if (buf[0] == '*')
+ pc = idata->buf;
+ pc = imap_next_word (pc);
+ pc = imap_next_word (pc);
+ if (!mutt_strncasecmp ("FETCH", pc, 5))
{
- pc = buf;
- pc = imap_next_word (pc);
- pc = imap_next_word (pc);
- if (mutt_strncasecmp ("FETCH", pc, 5) == 0)
+ while (*pc)
{
- while (*pc)
+ pc = imap_next_word (pc);
+ if (pc[0] == '(')
+ pc++;
+ if (strncasecmp ("UID", pc, 3) == 0)
{
pc = imap_next_word (pc);
- if (pc[0] == '(')
- pc++;
- if (strncasecmp ("UID", pc, 3) == 0)
- {
- pc = imap_next_word (pc);
- uid = atoi (pc);
- if (uid != HEADER_DATA(ctx->hdrs[msgno])->uid)
- mutt_error (_("The message index is incorrect. Try reopening the mailbox."));
- }
- else if (strncasecmp ("RFC822", pc, 6) == 0)
+ uid = atoi (pc);
+ if (uid != HEADER_DATA(ctx->hdrs[msgno])->uid)
+ mutt_error (_("The message index is incorrect. Try reopening the mailbox."));
+ }
+ else if (strncasecmp ("RFC822", pc, 6) == 0)
+ {
+ pc = imap_next_word (pc);
+ if (imap_get_literal_count(pc, &bytes) < 0)
{
- pc = imap_next_word (pc);
- if (imap_get_literal_count(pc, &bytes) < 0)
- {
- imap_error ("imap_fetch_message()", buf);
- goto bail;
- }
- if (imap_read_literal (msg->fp, CTX_DATA, bytes) < 0)
- goto bail;
- /* pick up trailing line */
- if (mutt_socket_readln (buf, sizeof (buf), CTX_DATA->conn) < 0)
- goto bail;
- pc = buf;
+ imap_error ("imap_fetch_message()", buf);
+ goto bail;
}
- /* UW-IMAP will provide a FLAGS update here if the FETCH causes a
- * change (eg from \Unseen to \Seen).
- * Uncommitted changes in mutt take precedence. If we decide to
- * incrementally update flags later, this won't stop us syncing */
- else if ((strncasecmp ("FLAGS", pc, 5) == 0) &&
- !ctx->hdrs[msgno]->changed)
- {
- IMAP_HEADER newh;
- HEADER* h = ctx->hdrs[msgno];
- unsigned char readonly;
-
- memset (&newh, 0, sizeof (newh));
- newh.data = safe_calloc (1, sizeof (IMAP_HEADER_DATA));
-
- dprint (2, (debugfile, "imap_fetch_message: parsing FLAGS\n"));
- if ((pc = msg_parse_flags (&newh, pc)) == NULL)
- goto bail;
+ if (imap_read_literal (msg->fp, idata, bytes) < 0)
+ goto bail;
+ /* pick up trailing line */
+ if ((rc = imap_cmd_resp (idata)) != IMAP_CMD_CONTINUE)
+ goto bail;
+ pc = idata->buf;
+ }
+ /* UW-IMAP will provide a FLAGS update here if the FETCH causes a
+ * change (eg from \Unseen to \Seen).
+ * Uncommitted changes in mutt take precedence. If we decide to
+ * incrementally update flags later, this won't stop us syncing */
+ else if ((strncasecmp ("FLAGS", pc, 5) == 0) &&
+ !ctx->hdrs[msgno]->changed)
+ {
+ IMAP_HEADER newh;
+ HEADER* h = ctx->hdrs[msgno];
+ unsigned char readonly;
+
+ memset (&newh, 0, sizeof (newh));
+ newh.data = safe_calloc (1, sizeof (IMAP_HEADER_DATA));
+
+ dprint (2, (debugfile, "imap_fetch_message: parsing FLAGS\n"));
+ if ((pc = msg_parse_flags (&newh, pc)) == NULL)
+ goto bail;
- /* this is less efficient than the code which used to be here,
- * but (1) this is only invoked when fetching messages, and (2)
- * this way, we can make sure that side effects of flag changes
- * are taken account of the proper way.
- */
-
- /* YAUH (yet another ugly hack): temporarily set context to
- * read-write even if it's read-only, so *server* updates of
- * flags can be processed by mutt_set_flag. ctx->changed must
- * be restored afterwards */
- readonly = ctx->readonly;
- ctx->readonly = 0;
+ /* this is less efficient than the code which used to be here,
+ * but (1) this is only invoked when fetching messages, and (2)
+ * this way, we can make sure that side effects of flag changes
+ * are taken account of the proper way.
+ */
+
+ /* YAUH (yet another ugly hack): temporarily set context to
+ * read-write even if it's read-only, so *server* updates of
+ * flags can be processed by mutt_set_flag. ctx->changed must
+ * be restored afterwards */
+ readonly = ctx->readonly;
+ ctx->readonly = 0;
- mutt_set_flag (ctx, h, M_NEW,
- !(newh.read || newh.old || h->read || h->old));
- mutt_set_flag (ctx, h, M_OLD, newh.old);
- mutt_set_flag (ctx, h, M_READ, h->read || newh.read);
- mutt_set_flag (ctx, h, M_DELETE, h->deleted || newh.deleted);
- mutt_set_flag (ctx, h, M_FLAG, h->flagged || newh.flagged);
- mutt_set_flag (ctx, h, M_REPLIED, h->replied || newh.replied);
-
- /* this message is now definitively *not* changed (mutt_set_flag
- * marks things changed as a side-effect) */
- h->changed = 0;
- ctx->changed &= ~readonly;
- ctx->readonly = readonly;
-
- mutt_free_list (&(HEADER_DATA(h)->keywords));
- HEADER_DATA(h)->keywords = newh.data->keywords;
- FREE(&newh.data);
- }
+ mutt_set_flag (ctx, h, M_NEW,
+ !(newh.read || newh.old || h->read || h->old));
+ mutt_set_flag (ctx, h, M_OLD, newh.old);
+ mutt_set_flag (ctx, h, M_READ, h->read || newh.read);
+ mutt_set_flag (ctx, h, M_DELETE, h->deleted || newh.deleted);
+ mutt_set_flag (ctx, h, M_FLAG, h->flagged || newh.flagged);
+ mutt_set_flag (ctx, h, M_REPLIED, h->replied || newh.replied);
+
+ /* this message is now definitively *not* changed (mutt_set_flag
+ * marks things changed as a side-effect) */
+ h->changed = 0;
+ ctx->changed &= ~readonly;
+ ctx->readonly = readonly;
+
+ mutt_free_list (&(HEADER_DATA(h)->keywords));
+ HEADER_DATA(h)->keywords = newh.data->keywords;
+ FREE(&newh.data);
}
}
- else if (imap_handle_untagged (CTX_DATA, buf) != 0)
- goto bail;
}
}
- while (mutt_strncmp (buf, CTX_DATA->seq, SEQLEN) != 0);
+ while (rc == IMAP_CMD_CONTINUE);
- if (!imap_code (buf))
+ if (rc != IMAP_CMD_DONE)
+ goto bail;
+
+ if (!imap_code (idata->buf))
goto bail;
/* Update the header information. Previously, we only downloaded a
int imap_append_message (CONTEXT *ctx, MESSAGE *msg)
{
+ IMAP_DATA* idata;
FILE *fp;
char buf[LONG_STRING];
char mbox[LONG_STRING];
size_t len;
int c, last;
IMAP_MBOX mx;
+ int rc;
+
+ idata = (IMAP_DATA*) ctx->data;
if (imap_parse_path (ctx->path, &mx))
- return (-1);
+ return -1;
- imap_fix_path (CTX_DATA, mx.mbox, mailbox, sizeof (mailbox));
+ imap_fix_path (idata, mx.mbox, mailbox, sizeof (mailbox));
if ((fp = fopen (msg->path, "r")) == NULL)
{
imap_munge_mbox_name (mbox, sizeof (mbox), mailbox);
snprintf (buf, sizeof (buf), "APPEND %s {%d}", mbox, len);
- imap_cmd_start (CTX_DATA, buf);
-
- do
- {
- if (mutt_socket_readln (buf, sizeof (buf), CTX_DATA->conn) < 0)
- {
- fclose (fp);
- return (-1);
- }
+ imap_cmd_start (idata, buf);
- if (buf[0] == '*' && imap_handle_untagged (CTX_DATA, buf) != 0)
- {
- fclose (fp);
- return (-1);
- }
- }
- while ((mutt_strncmp (buf, CTX_DATA->seq, SEQLEN) != 0) && (buf[0] != '+'));
+ do
+ rc = imap_cmd_resp (idata);
+ while (rc == IMAP_CMD_CONTINUE);
- if (buf[0] != '+')
+ if (rc != IMAP_CMD_RESPOND)
{
char *pc;
- dprint (1, (debugfile, "imap_append_message(): command failed: %s\n", buf));
+ dprint (1, (debugfile, "imap_append_message(): command failed: %s\n", idata->buf));
- pc = buf + SEQLEN;
+ pc = idata->buf + SEQLEN;
SKIPWS (pc);
pc = imap_next_word (pc);
mutt_error ("%s", pc);
buf[len++] = c;
if (len > sizeof(buf) - 3)
- flush_buffer(buf, &len, CTX_DATA->conn);
+ flush_buffer(buf, &len, idata->conn);
}
if (len)
- flush_buffer(buf, &len, CTX_DATA->conn);
+ flush_buffer(buf, &len, idata->conn);
- mutt_socket_write (CTX_DATA->conn, "\r\n");
+ mutt_socket_write (idata->conn, "\r\n");
fclose (fp);
do
- {
- if (mutt_socket_readln (buf, sizeof (buf), CTX_DATA->conn) < 0)
- return (-1);
+ rc = imap_cmd_resp (idata);
+ while (rc == IMAP_CMD_CONTINUE);
- if (buf[0] == '*' && imap_handle_untagged (CTX_DATA, buf) != 0)
- return (-1);
- }
- while (mutt_strncmp (buf, CTX_DATA->seq, SEQLEN) != 0);
-
- if (!imap_code (buf))
+ if (!imap_code (idata->buf))
{
char *pc;
- dprint (1, (debugfile, "imap_append_message(): command failed: %s\n", buf));
- pc = buf + SEQLEN;
+ dprint (1, (debugfile, "imap_append_message(): command failed: %s\n", idata->buf));
+ pc = idata->buf + SEQLEN;
SKIPWS (pc);
pc = imap_next_word (pc);
mutt_error ("%s", pc);
* 1: non-fatal error - try fetch/append */
int imap_copy_messages (CONTEXT* ctx, HEADER* h, char* dest, int delete)
{
+ IMAP_DATA* idata;
char buf[HUGE_STRING];
char cmd[LONG_STRING];
char mbox[LONG_STRING];
int n;
IMAP_MBOX mx;
+ idata = (IMAP_DATA*) ctx->data;
+
if (imap_parse_path (dest, &mx))
{
dprint (1, (debugfile, "imap_copy_message: bad destination %s\n", dest));
return 1;
}
- imap_fix_path (CTX_DATA, mx.mbox, cmd, sizeof (cmd));
+ imap_fix_path (idata, mx.mbox, cmd, sizeof (cmd));
/* Null HEADER* means copy tagged messages */
if (!h)
{
- rc = imap_make_msg_set (CTX_DATA, buf, sizeof (buf), M_TAG, 0);
+ rc = imap_make_msg_set (idata, buf, sizeof (buf), M_TAG, 0);
if (!rc)
{
dprint (1, (debugfile, "imap_copy_messages: No messages tagged\n"));
strncpy (mbox, cmd, sizeof (mbox));
imap_munge_mbox_name (mmbox, sizeof (mmbox), cmd);
snprintf (cmd, sizeof (cmd), "UID COPY %s %s", buf, mmbox);
- rc = imap_exec (buf, sizeof (buf), CTX_DATA, cmd, IMAP_CMD_FAIL_OK);
+ rc = imap_exec (idata, cmd, IMAP_CMD_FAIL_OK);
if (rc == -2)
{
/* bail out if command failed for reasons other than nonexistent target */
- if (strncmp (imap_get_qualifier (buf), "[TRYCREATE]", 11))
+ if (strncmp (imap_get_qualifier (idata->buf), "[TRYCREATE]", 11))
{
- imap_error ("imap_copy_messages", buf);
+ imap_error ("imap_copy_messages", idata->buf);
return -1;
}
dprint (2, (debugfile, "imap_copy_messages: server suggests TRYCREATE\n"));
return -1;
/* try again */
- rc = imap_exec (buf, sizeof (buf), CTX_DATA, cmd, 0);
+ rc = imap_exec (idata, cmd, 0);
}
if (rc != 0)
{
- imap_error ("imap_copy_messages", buf);
+ imap_error ("imap_copy_messages", idata->buf);
return -1;
}
* -2 if the string is a corrupt fetch response */
static int msg_fetch_header (CONTEXT* ctx, IMAP_HEADER* h, char* buf, FILE* fp)
{
+ IMAP_DATA* idata;
long bytes;
int rc = -1; /* default now is that string isn't FETCH response*/
+ idata = (IMAP_DATA*) ctx->data;
+
if (buf[0] != '*')
return rc;
if (imap_get_literal_count (buf, &bytes) < 0)
return rc;
- imap_read_literal (fp, CTX_DATA, bytes);
+ imap_read_literal (fp, idata, bytes);
/* we may have other fields of the FETCH _after_ the literal
* (eg Domino puts FLAGS here). Nothing wrong with that, either.
* This all has to go - we should accept literals and nonliterals
* interchangeably at any time. */
- if (mutt_socket_readln (buf, sizeof (buf), CTX_DATA->conn)
- < 0)
- return rc;
-
- if (msg_parse_fetch (h, buf) == -1)
+ if (imap_cmd_resp (idata) != IMAP_CMD_CONTINUE)
+ return -2;
+
+ if (msg_parse_fetch (h, idata->buf) == -1)
return rc;
rc = 0; /* success */
/* strip \r from \r\n termination */
if (i && buf[i-1] == '\r')
- buf[i-1] = '\0';
+ buf[--i] = '\0';
else
buf[i] = '\0';
dprint (dbg, (debugfile, "< %s\n", buf));
- return i+1;
+ /* number of bytes read, not strlen */
+ return i + 1;
}
CONNECTION* mutt_socket_head (void)