/*
- * Copyright (C) 1999-2000 Brendan Cully <brendan@kublai.com>
+ * Copyright (C) 1999-2001 Brendan Cully <brendan@kublai.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
if (!rc)
return IMAP_AUTH_SUCCESS;
- else if (rc == -1)
- dprint (1, (debugfile, "imap_auth_login: Error logging in.\n"));
-
mutt_error _("Login failed.");
sleep (2);
return IMAP_AUTH_FAILURE;
#include "imap_private.h"
#include "auth.h"
-#include <netinet/in.h>
-#include <netdb.h>
-
#include <sasl.h>
#include <saslutil.h>
if (mutt_sasl_start () != SASL_OK)
return IMAP_AUTH_FAILURE;
- /* TODO: set fourth option to SASL_SECURITY_LAYER once we have a wrapper
- * (ie more than auth code) for SASL. */
- rc = sasl_client_new ("imap", idata->conn->account.host,
- mutt_sasl_get_callbacks (&idata->conn->account), SASL_SECURITY_LAYER,
- &saslconn);
-
- if (rc != SASL_OK)
+ if (mutt_sasl_client_new (idata->conn, &saslconn) < 0)
{
- dprint (1, (debugfile, "imap_auth_sasl: Error allocating SASL connection.\n"));
+ dprint (1, (debugfile,
+ "imap_auth_sasl: Error allocating SASL connection.\n"));
return IMAP_AUTH_FAILURE;
}
- /*** set sasl IP properties, necessary for use with krb4 ***/
- {
- struct sockaddr_in local, remote;
- int r, size;
-
- size = sizeof(local);
- r = getsockname(idata->conn->fd, &local, &size);
- if (r!=0) return IMAP_AUTH_FAILURE;
-
- size = sizeof(remote);
- r = getpeername(idata->conn->fd, &remote, &size);
- if (r!=0) return IMAP_AUTH_FAILURE;
-
-#ifdef SASL_IP_LOCAL
- r = sasl_setprop(saslconn, SASL_IP_LOCAL, &local);
- if (r!=0) return IMAP_AUTH_FAILURE;
-#endif
-
-#ifdef SASL_IP_REMOTE
- r = sasl_setprop(saslconn, SASL_IP_REMOTE, &remote);
- if (r!=0) return IMAP_AUTH_FAILURE;
-#endif
- }
-
/* hack for SASL ANONYMOUS support:
* 1. Fetch username. If it's "" or "anonymous" then
* 2. attempt sasl_client_start with only "AUTH=ANONYMOUS" capability
irc = imap_cmd_step (idata);
while (irc == IMAP_CMD_CONTINUE);
- if (irc == IMAP_CMD_FAIL || irc == IMAP_CMD_NO)
+ if (irc == IMAP_CMD_BAD || irc == IMAP_CMD_NO)
goto bail;
if (irc == IMAP_CMD_RESPOND)
{
- if (sasl_decode64 (idata->buf+2, strlen (idata->buf+2), buf, &len) !=
- SASL_OK)
+ if (sasl_decode64 (idata->cmd.buf+2, strlen (idata->cmd.buf+2), buf,
+ &len) != SASL_OK)
{
dprint (1, (debugfile, "imap_auth_sasl: error base64-decoding server response.\n"));
goto bail;
/* sasl_client_st(art|ep) allocate pc with malloc, expect me to
* free it */
- safe_free (&pc);
+ FREE (&pc);
}
if (olen || rc == SASL_CONTINUE)
}
}
- while (irc != IMAP_CMD_DONE)
+ while (irc != IMAP_CMD_OK)
if ((irc = imap_cmd_step (idata)) != IMAP_CMD_CONTINUE)
break;
if (rc != SASL_OK)
goto bail;
- if (imap_code (idata->buf))
+ if (imap_code (idata->cmd.buf))
{
mutt_sasl_setup_conn (idata->conn, saslconn);
return IMAP_AUTH_SUCCESS;
/*
* Copyright (C) 1996-9 Brandon Long <blong@fiction.net>
- * Copyright (C) 1999-2000 Brendan Cully <brendan@kublai.com>
+ * Copyright (C) 1999-2001 Brendan Cully <brendan@kublai.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
}
}
}
- while (mutt_strncmp (idata->buf, idata->seq, SEQLEN));
+ while (mutt_strncmp (idata->cmd.buf, idata->cmd.seq, SEQLEN));
}
/* if we're descending a folder, mark it as current in browser_state */
}
}
- mutt_clear_error ();
FREE (&mx.mbox);
return 0;
isparent);
}
}
- while ((mutt_strncmp (idata->buf, idata->seq, SEQLEN) != 0));
+ while ((mutt_strncmp (idata->cmd.buf, idata->cmd.seq, SEQLEN) != 0));
FREE (&mx.mbox);
return 0;
if ((rc = imap_cmd_step (idata)) != IMAP_CMD_CONTINUE)
break;
- s = imap_next_word (idata->buf);
+ s = imap_next_word (idata->cmd.buf);
if (mutt_strncasecmp ("NAMESPACE", s, 9) == 0)
{
/* There are three sections to the response, User, Other, Shared,
}
while (rc == IMAP_CMD_CONTINUE);
- if (rc != IMAP_CMD_DONE)
+ if (rc != IMAP_CMD_OK)
return -1;
return 0;
return -1;
nsi->listable |= (name != NULL);
}
- while ((mutt_strncmp (idata->buf, idata->seq, SEQLEN) != 0));
+ while ((mutt_strncmp (idata->cmd.buf, idata->cmd.seq, SEQLEN) != 0));
}
return 0;
/*
* Copyright (C) 1996-8 Michael R. Elkins <me@cs.hmc.edu>
* Copyright (C) 1996-9 Brandon Long <blong@fiction.net>
- * Copyright (C) 1999-2000 Brendan Cully <brendan@kublai.com>
+ * Copyright (C) 1999-2001 Brendan Cully <brendan@kublai.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
static void cmd_finish (IMAP_DATA* idata);
static void cmd_handle_fatal (IMAP_DATA* idata);
static int cmd_handle_untagged (IMAP_DATA* idata);
-static void cmd_make_sequence (char* buf, size_t buflen);
+static void cmd_make_sequence (IMAP_DATA* idata);
static void cmd_parse_capabilities (IMAP_DATA* idata, char* s);
static void cmd_parse_expunge (IMAP_DATA* idata, char* s);
static void cmd_parse_myrights (IMAP_DATA* idata, char* s);
{
char* out;
int outlen;
- int rc = 0;
+ int rc;
if (idata->status == IMAP_FATAL)
{
cmd_handle_fatal (idata);
- return IMAP_CMD_FAIL;
+ return IMAP_CMD_BAD;
}
- cmd_make_sequence (idata->seq, sizeof (idata->seq));
+ cmd_make_sequence (idata);
/* seq, space, cmd, \r\n\0 */
- outlen = strlen (idata->seq) + strlen (cmd) + 4;
+ outlen = strlen (idata->cmd.seq) + strlen (cmd) + 4;
out = (char*) safe_malloc (outlen);
- snprintf (out, outlen, "%s %s\r\n", idata->seq, cmd);
+ snprintf (out, outlen, "%s %s\r\n", idata->cmd.seq, cmd);
rc = mutt_socket_write (idata->conn, out);
FREE (&out);
- return (rc < 0) ? IMAP_CMD_FAIL : 0;
+ return (rc < 0) ? IMAP_CMD_BAD : 0;
}
/* imap_cmd_step: Reads server responses from an IMAP command, detects
* large!). */
int imap_cmd_step (IMAP_DATA* idata)
{
+ IMAP_COMMAND* cmd = &idata->cmd;
unsigned int len = 0;
int c;
if (idata->status == IMAP_FATAL)
{
cmd_handle_fatal (idata);
- return IMAP_CMD_FAIL;
+ return IMAP_CMD_BAD;
}
/* read into buffer, expanding buffer as necessary until we have a full
* line */
do
{
- if (len == idata->blen)
+ if (len == cmd->blen)
{
- safe_realloc ((void**) &idata->buf, idata->blen + IMAP_CMD_BUFSIZE);
- idata->blen = idata->blen + IMAP_CMD_BUFSIZE;
- dprint (3, (debugfile, "imap_cmd_step: grew buffer to %u bytes\n", idata->blen));
+ safe_realloc ((void**) &cmd->buf, cmd->blen + IMAP_CMD_BUFSIZE);
+ cmd->blen = cmd->blen + IMAP_CMD_BUFSIZE;
+ dprint (3, (debugfile, "imap_cmd_step: grew buffer to %u bytes\n",
+ cmd->blen));
}
- if ((c = mutt_socket_readln (idata->buf + len, idata->blen - len,
+ if ((c = mutt_socket_readln (cmd->buf + len, cmd->blen - len,
idata->conn)) < 0)
{
dprint (1, (debugfile, "imap_cmd_step: Error while reading server response, closing connection.\n"));
mutt_socket_close (idata->conn);
idata->status = IMAP_FATAL;
- return IMAP_CMD_FAIL;
+ return IMAP_CMD_BAD;
}
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);
+ while (len == cmd->blen);
- /* don't let one large string make idata->buf hog memory forever */
- if ((idata->blen > IMAP_CMD_BUFSIZE) && (len <= IMAP_CMD_BUFSIZE))
+ /* don't let one large string make cmd->buf hog memory forever */
+ if ((cmd->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_step: shrank buffer to %u bytes\n", idata->blen));
+ safe_realloc ((void**) &cmd->buf, IMAP_CMD_BUFSIZE);
+ cmd->blen = IMAP_CMD_BUFSIZE;
+ dprint (3, (debugfile, "imap_cmd_step: shrank buffer to %u bytes\n", cmd->blen));
}
/* handle untagged messages. The caller still gets its shot afterwards. */
- if (!strncmp (idata->buf, "* ", 2) &&
+ if (!strncmp (cmd->buf, "* ", 2) &&
cmd_handle_untagged (idata))
- return IMAP_CMD_FAIL;
+ return IMAP_CMD_BAD;
/* server demands a continuation response from us */
- if (!strncmp (idata->buf, "+ ", 2))
+ if (!strncmp (cmd->buf, "+ ", 2))
+ {
return IMAP_CMD_RESPOND;
+ }
/* tagged completion code */
- if (!mutt_strncmp (idata->buf, idata->seq, SEQLEN))
+ if (!mutt_strncmp (cmd->buf, cmd->seq, SEQLEN))
{
cmd_finish (idata);
- return imap_code (idata->buf) ? IMAP_CMD_DONE : IMAP_CMD_NO;
+ return imap_code (cmd->buf) ? IMAP_CMD_OK : IMAP_CMD_NO;
}
return IMAP_CMD_CONTINUE;
}
/* create sequence for command */
- cmd_make_sequence (idata->seq, sizeof (idata->seq));
+ cmd_make_sequence (idata);
/* seq, space, cmd, \r\n\0 */
- outlen = strlen (idata->seq) + strlen (cmd) + 4;
+ outlen = strlen (idata->cmd.seq) + strlen (cmd) + 4;
out = (char*) safe_malloc (outlen);
- snprintf (out, outlen, "%s %s\r\n", idata->seq, cmd);
+ snprintf (out, outlen, "%s %s\r\n", idata->cmd.seq, cmd);
rc = mutt_socket_write_d (idata->conn, out,
flags & IMAP_CMD_PASS ? IMAP_LOG_PASS : IMAP_LOG_CMD);
if (rc == IMAP_CMD_NO && (flags & IMAP_CMD_FAIL_OK))
return -2;
- if (rc != IMAP_CMD_DONE)
+ if (rc != IMAP_CMD_OK)
{
char *pc;
if (flags & IMAP_CMD_FAIL_OK)
return -2;
- dprint (1, (debugfile, "imap_exec: command failed: %s\n", idata->buf));
- pc = idata->buf;
+ dprint (1, (debugfile, "imap_exec: command failed: %s\n", idata->cmd.buf));
+ pc = idata->cmd.buf;
pc = imap_next_word (pc);
mutt_error ("%s", pc);
sleep (2);
return 0;
}
+/* imap_cmd_running: Returns whether an IMAP command is in progress. */
+int imap_cmd_running (IMAP_DATA* idata)
+{
+ if (idata->cmd.state == IMAP_CMD_CONTINUE ||
+ idata->cmd.state == IMAP_CMD_RESPOND)
+ return 1;
+
+ return 0;
+}
+
/* 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). Called automatically by imap_cmd_step */
static void cmd_finish (IMAP_DATA* idata)
{
if (!(idata->state == IMAP_SELECTED) || idata->ctx->closing)
- {
- mutt_clear_error ();
return;
- }
if ((idata->reopen & IMAP_REOPEN_ALLOW) &&
(idata->reopen & (IMAP_EXPUNGE_PENDING|IMAP_NEWMAIL_PENDING)))
char* pn;
int count;
- s = imap_next_word (idata->buf);
+ s = imap_next_word (idata->cmd.buf);
if ((idata->state == IMAP_SELECTED) && isdigit (*s))
{
}
/* cmd_make_sequence: make a tag suitable for starting an IMAP command */
-static void cmd_make_sequence (char* buf, size_t buflen)
+static void cmd_make_sequence (IMAP_DATA* idata)
{
- static int sequence = 0;
-
- snprintf (buf, buflen, "a%04d", sequence++);
+ snprintf (idata->cmd.seq, sizeof (idata->cmd.seq), "a%04d", idata->seqno++);
- if (sequence > 9999)
- sequence = 0;
+ if (idata->seqno > 9999)
+ idata->seqno = 0;
}
/* cmd_parse_capabilities: set capability bits according to CAPABILITY
/*
* Copyright (C) 1996-8 Michael R. Elkins <me@cs.hmc.edu>
* Copyright (C) 1996-9 Brandon Long <blong@fiction.net>
- * Copyright (C) 1999-2000 Brendan Cully <brendan@kublai.com>
+ * Copyright (C) 1999-2001 Brendan Cully <brendan@kublai.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
}
}
-/* imap_parse_date: date is of the form: DD-MMM-YYYY HH:MM:SS +ZZzz */
-time_t imap_parse_date (char *s)
-{
- struct tm t;
- time_t tz;
-
- t.tm_mday = (s[0] == ' '? s[1] - '0' : (s[0] - '0') * 10 + (s[1] - '0'));
- s += 2;
- if (*s != '-')
- return 0;
- s++;
- t.tm_mon = mutt_check_month (s);
- s += 3;
- if (*s != '-')
- return 0;
- s++;
- t.tm_year = (s[0] - '0') * 1000 + (s[1] - '0') * 100 + (s[2] - '0') * 10 + (s[3] - '0') - 1900;
- s += 4;
- if (*s != ' ')
- return 0;
- s++;
-
- /* time */
- t.tm_hour = (s[0] - '0') * 10 + (s[1] - '0');
- s += 2;
- if (*s != ':')
- return 0;
- s++;
- t.tm_min = (s[0] - '0') * 10 + (s[1] - '0');
- s += 2;
- if (*s != ':')
- return 0;
- s++;
- t.tm_sec = (s[0] - '0') * 10 + (s[1] - '0');
- s += 2;
- if (*s != ' ')
- return 0;
- s++;
-
- /* timezone */
- tz = ((s[1] - '0') * 10 + (s[2] - '0')) * 3600 +
- ((s[3] - '0') * 10 + (s[4] - '0')) * 60;
- if (s[0] == '+')
- tz = -tz;
-
- return (mutt_mktime (&t, 0) + tz);
-}
-
/* imap_read_literal: read bytes bytes from server into file. Not explicitly
* buffered, relies on FILE buffering. NOTE: strips \r from \r\n.
* Apparently even literals use \r\n-terminated strings ?! */
if ((rc = imap_cmd_step (idata)) != IMAP_CMD_CONTINUE)
break;
- s = imap_next_word (idata->buf);
+ s = imap_next_word (idata->cmd.buf);
if (mutt_strncasecmp ("LIST", s, 4) == 0)
{
s = imap_next_word (s);
}
while (rc == IMAP_CMD_CONTINUE);
- if (rc != IMAP_CMD_DONE)
+ if (rc != IMAP_CMD_OK)
{
dprint (1, (debugfile, "imap_get_delim: failed.\n"));
return -1;
{
if (imap_exec (idata, "CAPABILITY", 0) != 0)
{
- imap_error ("imap_check_capabilities", idata->buf);
+ imap_error ("imap_check_capabilities", idata->cmd.buf);
return -1;
}
/* don't open a new connection if one isn't wanted */
if (flags & M_IMAP_CONN_NONEW)
if (!idata || idata->state == IMAP_DISCONNECTED)
- {
- mutt_socket_free (conn);
-
- return NULL;
- }
+ goto err_conn;
if (!idata)
{
/* The current connection is a new connection */
- idata = safe_calloc (1, sizeof (IMAP_DATA));
+ if (! (idata = imap_new_idata ()))
+ goto err_conn;
+
conn->data = idata;
idata->conn = conn;
}
if (idata->state == IMAP_DISCONNECTED)
if (imap_open_connection (idata) != 0)
- {
- FREE (&idata);
- mutt_socket_free (conn);
-
- return NULL;
- }
+ goto err_idata;
return idata;
+
+ err_idata:
+ imap_free_idata (&idata);
+ err_conn:
+ mutt_socket_free (conn);
+
+ return NULL;
}
int imap_open_connection (IMAP_DATA* idata)
char buf[LONG_STRING];
if (mutt_socket_open (idata->conn) < 0)
+ {
+ mutt_error (_("Connection to %s failed."), idata->conn->account.host);
+ sleep (1);
return -1;
+ }
idata->state = IMAP_CONNECTED;
if (imap_cmd_step (idata) != IMAP_CMD_CONTINUE)
goto bail;
- if (mutt_strncmp ("* OK", idata->buf, 4) == 0)
+ if (mutt_strncmp ("* OK", idata->cmd.buf, 4) == 0)
{
if (imap_check_capabilities (idata) || imap_authenticate (idata))
goto bail;
}
- else if (mutt_strncmp ("* PREAUTH", idata->buf, 9) == 0)
+ else if (mutt_strncmp ("* PREAUTH", idata->cmd.buf, 9) == 0)
{
if (imap_check_capabilities (idata) != 0)
goto bail;
if ((rc = imap_cmd_step (idata)) != IMAP_CMD_CONTINUE)
break;
- pc = idata->buf + 2;
+ pc = idata->cmd.buf + 2;
pc = imap_next_word (pc);
if (!mutt_strncasecmp ("EXISTS", pc, 6))
{
idata->newMailCount = 0;
}
- pc = idata->buf + 2;
+ pc = idata->cmd.buf + 2;
/* Obtain list of available flags here, may be overridden by a
* PERMANENTFLAGS tag in the OK response */
if (rc == IMAP_CMD_NO)
{
char *s;
- s = imap_next_word (idata->buf); /* skip seq */
+ s = imap_next_word (idata->cmd.buf); /* skip seq */
s = imap_next_word (s); /* Skip response */
mutt_error ("%s", s);
sleep (2);
goto fail;
}
- if (rc != IMAP_CMD_DONE)
+ if (rc != IMAP_CMD_OK)
goto fail;
/* check for READ-ONLY notification */
- if (!strncmp (imap_get_qualifier (idata->buf), "[READ-ONLY]", 11))
+ if (!strncmp (imap_get_qualifier (idata->cmd.buf), "[READ-ONLY]", 11))
{
dprint (2, (debugfile, "Mailbox is read-only.\n"));
ctx->readonly = 1;
(err_continue != M_YES))
{
err_continue = imap_continue ("imap_sync_mailbox: STORE failed",
- idata->buf);
+ idata->cmd.buf);
if (err_continue != M_YES)
return -1;
}
mutt_message _("Expunging messages from server...");
if (imap_exec (idata, "EXPUNGE", 0) != 0)
{
- imap_error ("imap_sync_mailbox: EXPUNGE failed", idata->buf);
+ imap_error ("imap_sync_mailbox: EXPUNGE failed", idata->cmd.buf);
return -1;
}
}
(ctx == idata->ctx))
{
if (!(idata->noclose) && imap_exec (idata, "CLOSE", 0))
- imap_error ("CLOSE failed", idata->buf);
+ imap_error ("CLOSE failed", idata->cmd.buf);
idata->reopen &= IMAP_REOPEN_ALLOW;
idata->state = IMAP_AUTHENTICATED;
if (imap_exec (idata, "NOOP", 0) != 0)
{
- imap_error ("imap_check_mailbox", idata->buf);
+ imap_error ("imap_check_mailbox", idata->cmd.buf);
return -1;
}
}
if ((rc = imap_cmd_step (idata)) != IMAP_CMD_CONTINUE)
break;
- s = imap_next_word (idata->buf);
+ s = imap_next_word (idata->cmd.buf);
if (mutt_strncasecmp ("STATUS", s, 6) == 0)
{
s = imap_next_word (s);
*name = NULL;
rc = imap_cmd_step (idata);
- if (rc == IMAP_CMD_DONE)
+ if (rc == IMAP_CMD_OK)
return 0;
if (rc != IMAP_CMD_CONTINUE)
return -1;
- s = imap_next_word (idata->buf);
+ s = imap_next_word (idata->cmd.buf);
if ((mutt_strncasecmp ("LIST", s, 4) == 0) ||
(mutt_strncasecmp ("LSUB", s, 4) == 0))
{
s = imap_next_word (s); /* name */
if (s && *s == '{') /* Literal */
{
- if (imap_get_literal_count(idata->buf, &bytes) < 0)
+ if (imap_get_literal_count(idata->cmd.buf, &bytes) < 0)
return -1;
if (imap_cmd_step (idata) != IMAP_CMD_CONTINUE)
return -1;
- *name = idata->buf;
+ *name = idata->cmd.buf;
}
else
*name = s;
completions++;
}
}
- while (mutt_strncmp(idata->seq, idata->buf, SEQLEN));
+ while (mutt_strncmp(idata->cmd.seq, idata->cmd.buf, SEQLEN));
if (completions)
{
/*
* Copyright (C) 1996-9 Brandon Long <blong@fiction.net>
- * Copyright (C) 1999-2000 Brendan Cully <brendan@kublai.com>
+ * Copyright (C) 1999-2001 Brendan Cully <brendan@kublai.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
#define IMAP_LOG_LTRL 4
#define IMAP_LOG_PASS 5
-/* IMAP command responses */
-#define IMAP_CMD_DONE (0)
-#define IMAP_CMD_FAIL (-1)
+/* IMAP command responses. Used in IMAP_COMMAND.state too */
+/* <tag> OK ... */
+#define IMAP_CMD_OK (0)
+/* <tag> BAD ... */
+#define IMAP_CMD_BAD (-1)
+/* <tag> NO ... */
#define IMAP_CMD_NO (-2)
+/* * ... */
#define IMAP_CMD_CONTINUE (1)
+/* + */
#define IMAP_CMD_RESPOND (2)
/* number of entries in the hash table */
int noinferiors;
} IMAP_NAMESPACE_INFO;
+/* IMAP command structure */
+typedef struct
+{
+ char seq[SEQLEN+1];
+ char* buf;
+ unsigned int blen;
+ int state;
+} IMAP_COMMAND;
+
typedef struct
{
/* This data is specific to a CONNECTION to an IMAP server */
CONNECTION *conn;
unsigned char state;
unsigned char 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;
+ unsigned char capabilities[(CAPMAX + 7)/8];
+ unsigned int seqno;
+ /* who knows, one day we may run multiple commands in parallel */
+ IMAP_COMMAND cmd;
/* The following data is all specific to the currently SELECTED mbox */
char delim;
/* all folder flags - system flags AND keywords */
LIST *flags;
} IMAP_DATA;
+/* I wish that were called IMAP_CONTEXT :( */
/* -- macros -- */
#define CTX_DATA ((IMAP_DATA *) ctx->data)
int changed);
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** name, int* noselect,
int* noinferiors, char* delim);
int imap_read_literal (FILE* fp, IMAP_DATA* idata, long bytes);
/* util.c */
int imap_continue (const char* msg, const char* resp);
void imap_error (const char* where, const char* msg);
+IMAP_DATA* imap_new_idata (void);
+void imap_free_idata (IMAP_DATA** idata);
char* imap_fix_path (IMAP_DATA* idata, char* mailbox, char* path,
size_t plen);
int imap_get_literal_count (const char* buf, long* bytes);
char* imap_get_qualifier (char* buf);
char* imap_next_word (char* s);
+time_t imap_parse_date (char* s);
void imap_qualify_path (char *dest, size_t len, IMAP_MBOX *mx, char* path);
void imap_quote_string (char* dest, size_t slen, const char* src);
void imap_unquote_string (char* s);
if (rc != IMAP_CMD_CONTINUE)
break;
- if ((mfhrc = msg_fetch_header (idata->ctx, &h, idata->buf, fp)) == -1)
+ if ((mfhrc = msg_fetch_header (idata->ctx, &h, idata->cmd.buf, fp)) == -1)
continue;
else if (mfhrc < 0)
break;
mx_update_context (ctx); /* increments ->msgcount */
}
- while ((rc != IMAP_CMD_DONE) && ((mfhrc == -1) ||
+ while ((rc != IMAP_CMD_OK) && ((mfhrc == -1) ||
((msgno + 1) >= fetchlast)));
- if ((mfhrc < -1) || ((rc != IMAP_CMD_CONTINUE) && (rc != IMAP_CMD_DONE)))
+ if ((mfhrc < -1) || ((rc != IMAP_CMD_CONTINUE) && (rc != IMAP_CMD_OK)))
{
imap_free_header_data ((void**) &h.data);
fclose (fp);
if ((rc = imap_cmd_step (idata)) != IMAP_CMD_CONTINUE)
break;
- pc = idata->buf;
+ pc = idata->cmd.buf;
pc = imap_next_word (pc);
pc = imap_next_word (pc);
/* pick up trailing line */
if ((rc = imap_cmd_step (idata)) != IMAP_CMD_CONTINUE)
goto bail;
- pc = idata->buf;
+ pc = idata->cmd.buf;
fetched = 1;
}
}
while (rc == IMAP_CMD_CONTINUE);
- if (rc != IMAP_CMD_DONE)
+ if (rc != IMAP_CMD_OK)
goto bail;
- if (!fetched || !imap_code (idata->buf))
+ if (!fetched || !imap_code (idata->cmd.buf))
goto bail;
/* Update the header information. Previously, we only downloaded a
{
char *pc;
- dprint (1, (debugfile, "imap_append_message(): command failed: %s\n", idata->buf));
+ dprint (1, (debugfile, "imap_append_message(): command failed: %s\n",
+ idata->cmd.buf));
- pc = idata->buf + SEQLEN;
+ pc = idata->cmd.buf + SEQLEN;
SKIPWS (pc);
pc = imap_next_word (pc);
mutt_error ("%s", pc);
rc = imap_cmd_step (idata);
while (rc == IMAP_CMD_CONTINUE);
- if (!imap_code (idata->buf))
+ if (!imap_code (idata->cmd.buf))
{
char *pc;
- dprint (1, (debugfile, "imap_append_message(): command failed: %s\n", idata->buf));
- pc = idata->buf + SEQLEN;
+ dprint (1, (debugfile, "imap_append_message(): command failed: %s\n",
+ idata->cmd.buf));
+ pc = idata->cmd.buf + SEQLEN;
SKIPWS (pc);
pc = imap_next_word (pc);
mutt_error ("%s", pc);
if (rc == -2)
{
/* bail out if command failed for reasons other than nonexistent target */
- if (strncmp (imap_get_qualifier (idata->buf), "[TRYCREATE]", 11))
+ if (strncmp (imap_get_qualifier (idata->cmd.buf), "[TRYCREATE]", 11))
{
- imap_error ("imap_copy_messages", idata->buf);
+ imap_error ("imap_copy_messages", idata->cmd.buf);
goto fail;
}
dprint (2, (debugfile, "imap_copy_messages: server suggests TRYCREATE\n"));
}
if (rc != 0)
{
- imap_error ("imap_copy_messages", idata->buf);
+ imap_error ("imap_copy_messages", idata->cmd.buf);
goto fail;
}
if (imap_cmd_step (idata) != IMAP_CMD_CONTINUE)
return -2;
- if (msg_parse_fetch (h, idata->buf) == -1)
+ if (msg_parse_fetch (h, idata->cmd.buf) == -1)
return rc;
rc = 0; /* success */
/*
* Copyright (C) 1996-8 Michael R. Elkins <me@cs.hmc.edu>
* Copyright (C) 1996-9 Brandon Long <blong@fiction.net>
- * Copyright (C) 1999-2000 Brendan Cully <brendan@kublai.com>
+ * Copyright (C) 1999-2001 Brendan Cully <brendan@kublai.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
sleep (2);
}
+/* imap_new_idata: Allocate and initialise a new IMAP_DATA structure.
+ * Returns NULL on failure (no mem) */
+IMAP_DATA* imap_new_idata (void) {
+ IMAP_DATA* idata;
+
+ idata = safe_calloc (1, sizeof (IMAP_DATA));
+ if (!idata)
+ return NULL;
+
+ idata->conn = NULL;
+ idata->state = IMAP_DISCONNECTED;
+ idata->seqno = 0;
+
+ idata->cmd.buf = NULL;
+ idata->cmd.blen = 0;
+ idata->cmd.state = IMAP_CMD_OK;
+
+ return idata;
+}
+
+/* imap_free_idata: Release and clear storage in an IMAP_DATA structure. */
+void imap_free_idata (IMAP_DATA** idata) {
+ if (!idata)
+ return;
+
+ FREE (&((*idata)->cmd.buf));
+ FREE (idata);
+}
+
/*
* Fix up the imap path. This is necessary because the rest of mutt
* assumes a hierarchy delimiter of '/', which is not necessarily true
return s;
}
+/* imap_parse_date: date is of the form: DD-MMM-YYYY HH:MM:SS +ZZzz */
+time_t imap_parse_date (char *s)
+{
+ struct tm t;
+ time_t tz;
+
+ t.tm_mday = (s[0] == ' '? s[1] - '0' : (s[0] - '0') * 10 + (s[1] - '0'));
+ s += 2;
+ if (*s != '-')
+ return 0;
+ s++;
+ t.tm_mon = mutt_check_month (s);
+ s += 3;
+ if (*s != '-')
+ return 0;
+ s++;
+ t.tm_year = (s[0] - '0') * 1000 + (s[1] - '0') * 100 + (s[2] - '0') * 10 + (s[3] - '0') - 1900;
+ s += 4;
+ if (*s != ' ')
+ return 0;
+ s++;
+
+ /* time */
+ t.tm_hour = (s[0] - '0') * 10 + (s[1] - '0');
+ s += 2;
+ if (*s != ':')
+ return 0;
+ s++;
+ t.tm_min = (s[0] - '0') * 10 + (s[1] - '0');
+ s += 2;
+ if (*s != ':')
+ return 0;
+ s++;
+ t.tm_sec = (s[0] - '0') * 10 + (s[1] - '0');
+ s += 2;
+ if (*s != ' ')
+ return 0;
+ s++;
+
+ /* timezone */
+ tz = ((s[1] - '0') * 10 + (s[2] - '0')) * 3600 +
+ ((s[3] - '0') * 10 + (s[4] - '0')) * 60;
+ if (s[0] == '+')
+ tz = -tz;
+
+ return (mutt_mktime (&t, 0) + tz);
+}
+
/* imap_parse_path: given an IMAP mailbox name, return host, port
* and a path IMAP servers will recognise.
* mx.mbox is malloc'd, caller must free it */
#include "mutt.h"
#include "account.h"
#include "mutt_sasl.h"
+#ifdef USE_SSL
+# include "mutt_ssl.h"
+#endif
#include "mutt_socket.h"
#include <sasl.h>
+#include <netinet/in.h>
+#include <netdb.h>
+
+/* arbitrary. SASL will probably use a smaller buffer anyway. OTOH it's
+ * been a while since I've had access to an SASL server which negotiated
+ * a protection buffer. */
+#define M_SASL_MAXBUF 65536
static sasl_callback_t mutt_sasl_callbacks[5];
return SASL_OK;
}
+/* mutt_sasl_client_new: wrapper for sasl_client_new which also sets various
+ * security properties. If this turns out to be fine for POP too we can
+ * probably stop exporting mutt_sasl_get_callbacks(). */
+int mutt_sasl_client_new (CONNECTION* conn, sasl_conn_t** saslconn)
+{
+ sasl_security_properties_t secprops;
+ sasl_external_properties_t extprops;
+ const char* service;
+ int rc;
+
+ switch (conn->account.type)
+ {
+ case M_ACCT_TYPE_IMAP:
+ service = "imap";
+ break;
+ case M_ACCT_TYPE_POP:
+ service = "pop";
+ break;
+ default:
+ dprint (1, (debugfile, "mutt_sasl_client_new: account type unset\n"));
+ return -1;
+ }
+
+ rc = sasl_client_new (service, conn->account.host,
+ mutt_sasl_get_callbacks (&conn->account), SASL_SECURITY_LAYER, saslconn);
+
+ if (rc != SASL_OK)
+ {
+ dprint (1, (debugfile,
+ "mutt_sasl_client_new: Error allocating SASL connection\n"));
+ return -1;
+ }
+
+ /*** set sasl IP properties, necessary for use with krb4 ***/
+ /* Do we need to fail if this fails? I would assume having these unset
+ * would just disable KRB4. Who wrote this code? I'm not sure how this
+ * interacts with the NSS code either, since that mucks with the fd. */
+ {
+ struct sockaddr_in local, remote;
+ socklen_t size;
+
+ size = sizeof (local);
+ if (getsockname (conn->fd, &local, &size))
+ return -1;
+
+ size = sizeof(remote);
+ if (getpeername(conn->fd, &remote, &size))
+ return -1;
+
+#ifdef SASL_IP_LOCAL
+ if (sasl_setprop(*saslconn, SASL_IP_LOCAL, &local) != SASL_OK)
+ {
+ dprint (1, (debugfile,
+ "mutt_sasl_client_new: Error setting local IP address\n"));
+ return -1;
+ }
+#endif
+
+#ifdef SASL_IP_REMOTE
+ if (sasl_setprop(*saslconn, SASL_IP_REMOTE, &remote) != SASL_OK)
+ {
+ dprint (1, (debugfile,
+ "mutt_sasl_client_new: Error setting remote IP address\n"));
+ return -1;
+ }
+#endif
+ }
+
+ /* set security properties. We use NOPLAINTEXT globally, since we can
+ * just fall back to LOGIN in the IMAP case anyway. If that doesn't
+ * work for POP, we can make it a flag or move this code into
+ * imap/auth_sasl.c */
+ memset (&secprops, 0, sizeof (secprops));
+ secprops.max_ssf = (sasl_ssf_t) -1;
+ secprops.maxbufsize = M_SASL_MAXBUF;
+ secprops.security_flags |= SASL_SEC_NOPLAINTEXT;
+ if (sasl_setprop (*saslconn, SASL_SEC_PROPS, &secprops) != SASL_OK)
+ {
+ dprint (1, (debugfile,
+ "mutt_sasl_client_new: Error setting security properties\n"));
+ return -1;
+ }
+
+ /* we currently don't have an SSF finder for NSS (I don't know the API).
+ * If someone does it'd probably be trivial to write mutt_nss_get_ssf().
+ * I have a feeling more SSL code could be shared between those two files,
+ * but I haven't looked into it yet, since I still don't know the APIs. */
+#if defined(USE_SSL) && !defined(USE_NSS)
+ if (conn->account.flags & M_ACCT_SSL)
+ {
+ memset (&extprops, 0, sizeof (extprops));
+ extprops.ssf = mutt_ssl_get_ssf (conn);
+ dprint (2, (debugfile, "External SSF: %d\n", extprops.ssf));
+ if (sasl_setprop (*saslconn, SASL_SSF_EXTERNAL, &extprops) != SASL_OK)
+ {
+ dprint (1, (debugfile, "mutt_sasl_client_new: Error setting external properties\n"));
+ return -1;
+ }
+ }
+#endif
+
+ return 0;
+}
+
sasl_callback_t* mutt_sasl_get_callbacks (ACCOUNT* account)
{
sasl_callback_t* callback;
/*
- * Copyright (C) 2000 Brendan Cully <brendan@kublai.com>
+ * Copyright (C) 2000-1 Brendan Cully <brendan@kublai.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
#include "mutt_socket.h"
int mutt_sasl_start (void);
-sasl_callback_t* mutt_sasl_get_callbacks (ACCOUNT* account);
-int mutt_sasl_interact (sasl_interact_t* interaction);
-void mutt_sasl_setup_conn (CONNECTION* conn, sasl_conn_t* saslconn);
+int mutt_sasl_client_new (CONNECTION*, sasl_conn_t**);
+sasl_callback_t* mutt_sasl_get_callbacks (ACCOUNT*);
+int mutt_sasl_interact (sasl_interact_t*);
+void mutt_sasl_setup_conn (CONNECTION*, sasl_conn_t*);
typedef struct
{
}
sslsockdata;
+/* mutt_ssl_get_ssf: Return bit strength of connection encryption. SASL
+ * uses this to determine how much additional protection to provide,
+ * if necessary. */
+int mutt_ssl_get_ssf (CONNECTION* conn)
+{
+ sslsockdata* ssldata = (sslsockdata*) conn->sockdata;
+ int maxbits;
+
+ return SSL_CIPHER_get_bits (SSL_get_current_cipher (ssldata->ssl), &maxbits);
+}
+
+
static int add_entropy (const char *file);
/*
* OpenSSL library needs to be fed with sufficient entropy. On systems
extern char *SslCertFile;
extern char *SslEntropyFile;
+int mutt_ssl_get_ssf (CONNECTION* conn);
+
extern int ssl_socket_setup (CONNECTION *conn);
#endif /* _MUTT_SSL_H_ */