summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--account.c13
-rw-r--r--doc/manual.sgml.head59
-rw-r--r--imap/auth_sasl.c41
-rw-r--r--imap/imap_ssl.c6
-rw-r--r--mutt_sasl.c245
-rw-r--r--mutt_sasl.h26
-rw-r--r--mutt_socket.c19
-rw-r--r--mutt_socket.h4
8 files changed, 355 insertions, 58 deletions
diff --git a/account.c b/account.c
index f095763e..2853d254 100644
--- a/account.c
+++ b/account.c
@@ -56,6 +56,8 @@ int mutt_account_match (const ACCOUNT* a1, const ACCOUNT* a2)
/* mutt_account_getuser: retrieve username into ACCOUNT, if neccessary */
int mutt_account_getuser (ACCOUNT* account)
{
+ char prompt[SHORT_STRING];
+
/* already set */
if (account->flags & M_ACCT_USER)
return 0;
@@ -70,9 +72,9 @@ int mutt_account_getuser (ACCOUNT* account)
/* prompt (defaults to unix username), copy into account->user */
else
{
+ snprintf (prompt, sizeof (prompt), _("Username at %s: "), account->host);
strfcpy (account->user, NONULL (Username), sizeof (account->user));
- if (mutt_get_field (_("Username: "), account->user,
- sizeof (account->user), 0))
+ if (mutt_get_field (prompt, account->user, sizeof (account->user), 0))
return -1;
}
@@ -84,6 +86,8 @@ int mutt_account_getuser (ACCOUNT* account)
/* mutt_account_getpass: fetch password into ACCOUNT, if neccessary */
int mutt_account_getpass (ACCOUNT* account)
{
+ char prompt[SHORT_STRING];
+
if (account->flags & M_ACCT_PASS)
return 0;
#ifdef USE_IMAP
@@ -96,9 +100,10 @@ int mutt_account_getpass (ACCOUNT* account)
#endif
else
{
+ snprintf (prompt, sizeof (prompt), _("Password for %s@%s: "),
+ account->user, account->host);
account->pass[0] = '\0';
- if (mutt_get_field (_("Password: "), account->pass,
- sizeof (account->pass), M_PASS))
+ if (mutt_get_field (prompt, account->pass, sizeof (account->pass), M_PASS))
return -1;
}
diff --git a/doc/manual.sgml.head b/doc/manual.sgml.head
index 182129f1..9f6cce7d 100644
--- a/doc/manual.sgml.head
+++ b/doc/manual.sgml.head
@@ -2049,8 +2049,7 @@ You can access the remote inbox by selecting the folder
server and <tt/inbox/ is the special name for your spool mailbox on
the IMAP server. If you want to access another mail folder at the IMAP
server, you should use <tt>{imapserver}path/to/folder</tt> where
-<tt>path/to/folder</tt> is the path of the folder you want to access
-(relative to your home directory if you aren't using Cyrus).
+<tt>path/to/folder</tt> is the path of the folder you want to access.
You can select an alternative port by specifying it with the server, ie:
<tt/{imapserver:port}inbox/.
@@ -2059,7 +2058,7 @@ You can also specify different username for each folder, ie:
<tt/{username@imapserver[:port]}inbox/.
If Mutt was compiled with SSL support (by running the <em/configure/
-script with the <em/--enable-ssl/ flag), connections to IMAP servers
+script with the <em/--with-ssl/ flag), connections to IMAP servers
can be encrypted. This naturally requires that the server supports
SSL encrypted connections. To access a folder with IMAP/SSL, you should
use <tt>{[username@]imapserver[:port]/ssl}path/to/folder</tt> as your
@@ -2080,11 +2079,6 @@ the
<ref id="imap&lowbar;checkinterval" name="&dollar;imap&lowbar;checkinterval">
variable, which defaults to every 60 seconds.
-Mutt is designed to work with IMAP4rev1 servers, and was originally tested
-with both the UWash IMAP server v11.241 and the Cyrus IMAP server v1.5.14.
-Nowadays it is primarily developed against UW-IMAP 12.250. It appears
-to work more-or-less correctly against Cyrus 1.6.11 as well.
-
Note that if you are using mbox as the mail store on UW servers prior to
v12.250, the server has been reported to disconnect a client if another client
selects the same folder.
@@ -2115,34 +2109,37 @@ following differences:
<sect2>Authentication
<p>
-Mutt supports three authentication methods with IMAP servers: GSSAPI, CRAM-MD5,
-and LOGIN (there is a patch by Grant Edwards to add NTLM authentication for you
-poor exchange users out there, but it has yet to be integrated into the main
-tree). Mutt will try whichever methods are available on the server, in order from
-most secure to least. That is, mutt will first try GSSAPI authentication (ie
-Kerberos V), then CRAM-MD5, and finally LOGIN (the worst possible choice - your
-password travels across the net in the clear).
+Mutt supports four authentication methods with IMAP servers: SASL,
+GSSAPI, CRAM-MD5, and LOGIN (there is a patch by Grant Edwards to add
+NTLM authentication for you poor exchange users out there, but it has
+yet to be integrated into the main tree). There is also support for
+the pseudo-protocol ANONYMOUS, which allows you to log in to a public
+IMAP server without having an account. To use ANONYMOUS, simply make
+your username blank or "anonymous".
+<p>
+SASL is a special super-authenticator, which selects among several protocols
+(including GSSAPI, CRAM-MD5, ANONYMOUS, and DIGEST-MD5) the most secure
+method available on your host and the server. Using some of these methods
+(including DIGEST-MD5 and possibly GSSAPI), your entire session will be
+encrypted and invisible to those teeming network snoops. It is the best
+option if you have it. To use it, you must have the Cyrus SASL library
+installed on your system and compile mutt with the <em/--with-sasl/ flag.
+<p>
+Mutt will try whichever methods are compiled in and available on the server,
+in the following order: SASL, ANONYMOUS, GSSAPI, CRAM-MD5, LOGIN.
There are a few variables which control authentication:
<itemize>
-<item><ref id="imap&lowbar;user" name="&dollar;imap&lowbar;user"> - controls the
- username under which you request authentication on the IMAP server, for all
- authenticators.
-<item><ref id="imap&lowbar;pass" name="&dollar;imap&lowbar;pass"> - the password
- to use to authenticate you using the LOGIN method. If this is set, and other
- methods fail, Mutt will use this without asking you. So if you use GSSAPI
- or CRAM-MD5, don't set this variable.
-<item><ref id="imap&lowbar;cramkey" name="&dollar;imap&lowbar;cramkey"> - the
- secret used in CRAM-MD5 authentication (ie your CRAM password). If this is
- not set and your server supports CRAM-MD5, Mutt will prompt you for it.
+<item><ref id="imap&lowbar;user" name="&dollar;imap&lowbar;user"> - controls
+ the username under which you request authentication on the IMAP server,
+ for all authenticators. This is overridden by an explicit username in
+ the mailbox path (ie by using a mailbox name of the form
+ <tt/{user@host}/).
+<item><ref id="imap&lowbar;pass" name="&dollar;imap&lowbar;pass"> - a
+ password which you may preset, used by all authentication methods where
+ a password is needed.
</itemize>
-<bf/Note:/ The IMAP support has had very limited testing due to a lack
-of developers using it. It should work with the reference servers
-mentioned above, but if you need a more stable way to access your
-IMAP folder, consider using a specialized program, such as <htmlurl
-url="http://www.ccil.org/~esr/fetchmail" name="fetchmail">.
-
<sect1>Start a WWW Browser on URLs (EXTERNAL)<label id="urlview">
<p>
If a message contains URLs (<em/unified ressource locator/ = address in the
diff --git a/imap/auth_sasl.c b/imap/auth_sasl.c
index 8b78151c..946500ec 100644
--- a/imap/auth_sasl.c
+++ b/imap/auth_sasl.c
@@ -30,6 +30,7 @@
imap_auth_res_t imap_auth_sasl (IMAP_DATA* idata)
{
sasl_conn_t* saslconn;
+ sasl_interact_t* interaction = NULL;
int rc;
char buf[LONG_STRING];
const char* mech;
@@ -43,7 +44,8 @@ imap_auth_res_t imap_auth_sasl (IMAP_DATA* idata)
/* 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), 0, &saslconn);
+ mutt_sasl_get_callbacks (&idata->conn->account), SASL_SECURITY_LAYER,
+ &saslconn);
if (rc != SASL_OK)
{
@@ -67,8 +69,14 @@ imap_auth_res_t imap_auth_sasl (IMAP_DATA* idata)
&mech);
if (rc != SASL_OK && rc != SASL_CONTINUE)
- rc = sasl_client_start (saslconn, idata->capstr, NULL, NULL, &pc, &olen,
- &mech);
+ do
+ {
+ rc = sasl_client_start (saslconn, idata->capstr, NULL, &interaction,
+ &pc, &olen, &mech);
+ if (rc == SASL_INTERACT)
+ mutt_sasl_interact (interaction);
+ }
+ while (rc == SASL_INTERACT);
client_start = (olen > 0);
@@ -107,17 +115,30 @@ imap_auth_res_t imap_auth_sasl (IMAP_DATA* idata)
}
if (!client_start)
- rc = sasl_client_step (saslconn, buf, len, NULL, &pc, &olen);
+ do
+ {
+ rc = sasl_client_step (saslconn, buf, len, &interaction, &pc, &olen);
+ if (rc == SASL_INTERACT)
+ mutt_sasl_interact (interaction);
+ }
+ while (rc == SASL_INTERACT);
else
client_start = 0;
/* send out response, or line break if none needed */
- if (olen && sasl_encode64 (pc, olen, buf, sizeof (buf), &olen) != SASL_OK)
+ if (pc)
{
- dprint (1, (debugfile, "imap_auth_sasl: error base64-encoding client response.\n"));
- goto bail;
- }
+ if (sasl_encode64 (pc, olen, buf, sizeof (buf), &olen) != SASL_OK)
+ {
+ dprint (1, (debugfile, "imap_auth_sasl: error base64-encoding client response.\n"));
+ goto bail;
+ }
+ /* sasl_client_st(art|ep) allocate pc with malloc, expect me to
+ * free it */
+ free (pc);
+ }
+
if (olen || rc == SASL_CONTINUE)
{
strfcpy (buf + olen, "\r\n", sizeof (buf) - olen);
@@ -134,9 +155,7 @@ imap_auth_res_t imap_auth_sasl (IMAP_DATA* idata)
if (imap_code (buf))
{
- /* later we'll want to keep saslconn, when we support a protection layer.
- * For now it shouldn't hurt to dispose of it at this point. */
- sasl_dispose (&saslconn);
+ mutt_sasl_setup_conn (idata->conn, saslconn);
return IMAP_AUTH_SUCCESS;
}
diff --git a/imap/imap_ssl.c b/imap/imap_ssl.c
index c1643986..42915e68 100644
--- a/imap/imap_ssl.c
+++ b/imap/imap_ssl.c
@@ -161,7 +161,7 @@ static int ssl_socket_open_err (CONNECTION *conn)
static int ssl_check_certificate (sslsockdata * data);
static int ssl_socket_read (CONNECTION * conn);
-static int ssl_socket_write (CONNECTION * conn, const char *buf);
+static int ssl_socket_write (CONNECTION* conn, const char* buf, size_t len);
static int ssl_socket_open (CONNECTION * conn);
static int ssl_socket_close (CONNECTION * conn);
@@ -187,10 +187,10 @@ int ssl_socket_read (CONNECTION * conn)
return SSL_read (data->ssl, conn->inbuf, LONG_STRING);
}
-int ssl_socket_write (CONNECTION * conn, const char *buf)
+int ssl_socket_write (CONNECTION* conn, const char* buf, size_t len)
{
sslsockdata *data = conn->sockdata;
- return SSL_write (data->ssl, buf, mutt_strlen (buf));
+ return SSL_write (data->ssl, buf, len);
}
int ssl_socket_open (CONNECTION * conn)
diff --git a/mutt_sasl.c b/mutt_sasl.c
index 30764a6f..0bd24917 100644
--- a/mutt_sasl.c
+++ b/mutt_sasl.c
@@ -25,7 +25,7 @@
#include <sasl.h>
-static sasl_callback_t mutt_sasl_callbacks[4];
+static sasl_callback_t mutt_sasl_callbacks[5];
/* callbacks */
static int mutt_sasl_cb_log (void* context, int priority, const char* message);
@@ -34,6 +34,13 @@ static int mutt_sasl_cb_authname (void* context, int id, const char** result,
static int mutt_sasl_cb_pass (sasl_conn_t* conn, void* context, int id,
sasl_secret_t** psecret);
+/* socket wrappers for a SASL security layer */
+static int mutt_sasl_conn_open (CONNECTION* conn);
+static int mutt_sasl_conn_close (CONNECTION* conn);
+static int mutt_sasl_conn_read (CONNECTION* conn);
+static int mutt_sasl_conn_write (CONNECTION* conn, const char* buf,
+ size_t count);
+
/* mutt_sasl_start: called before doing a SASL exchange - initialises library
* (if neccessary). */
int mutt_sasl_start (void)
@@ -91,6 +98,11 @@ sasl_callback_t* mutt_sasl_get_callbacks (ACCOUNT* account)
callback->context = account;
callback++;
+ callback->id = SASL_CB_GETREALM;
+ callback->proc = NULL;
+ callback->context = NULL;
+ callback++;
+
callback->id = SASL_CB_LIST_END;
callback->proc = NULL;
callback->context = NULL;
@@ -98,6 +110,77 @@ sasl_callback_t* mutt_sasl_get_callbacks (ACCOUNT* account)
return mutt_sasl_callbacks;
}
+int mutt_sasl_interact (sasl_interact_t* interaction)
+{
+ char prompt[SHORT_STRING];
+ char resp[SHORT_STRING];
+
+ while (interaction->id != SASL_CB_LIST_END)
+ {
+ dprint (2, (debugfile, "mutt_sasl_interact: filling in SASL interaction %ld.\n", interaction->id));
+
+ snprintf (prompt, sizeof (prompt), "%s: ", interaction->prompt);
+ resp[0] = '\0';
+ if (mutt_get_field (prompt, resp, sizeof (resp), 0))
+ return SASL_FAIL;
+
+ interaction->len = mutt_strlen (resp)+1;
+ interaction->result = safe_malloc (interaction->len);
+ memcpy (interaction->result, resp, interaction->len);
+
+ interaction++;
+ }
+
+ return SASL_OK;
+}
+
+/* SASL can stack a protection layer on top of an existing connection.
+ * To handle this, we store a saslconn_t in conn->sockdata, and write
+ * wrappers which en/decode the read/write stream, then replace sockdata
+ * with an embedded copy of the old sockdata and call the underlying
+ * functions (which we've also preserved). I thought about trying to make
+ * a general stackable connection system, but it seemed like overkill -
+ * something is wrong if we have 15 filters on top of a socket. Anyway,
+ * anything else which wishes to stack can use the same method. The only
+ * disadvantage is we have to write wrappers for all the socket methods,
+ * even if we only stack over read and write. Thinking about it, the
+ * abstraction problem is that there is more in CONNECTION than there
+ * needs to be. Ideally it would have only (void*)data and methods. */
+
+/* mutt_sasl_setup_conn: replace connection methods, sockdata with
+ * SASL wrappers, for protection layers. Also get ssf, as a fastpath
+ * for the read/write methods. */
+void mutt_sasl_setup_conn (CONNECTION* conn, sasl_conn_t* saslconn)
+{
+ SASL_DATA* sasldata = (SASL_DATA*) safe_malloc (sizeof (SASL_DATA));
+
+ sasldata->saslconn = saslconn;
+ /* get ssf so we know whether we have to (en|de)code read/write */
+ sasl_getprop (saslconn, SASL_SSF, (void**) &sasldata->ssf);
+ dprint (2, (debugfile, "SASL protection strength: %u\n", *sasldata->ssf));
+ sasl_getprop (saslconn, SASL_MAXOUTBUF, (void**) &sasldata->pbufsize);
+ dprint (2, (debugfile, "SASL protection buffer size: %u\n", *sasldata->pbufsize));
+
+ /* clear input buffer */
+ sasldata->buf = NULL;
+ sasldata->bpos = 0;
+ sasldata->blen = 0;
+
+ /* preserve old functions */
+ sasldata->sockdata = conn->sockdata;
+ sasldata->open = conn->open;
+ sasldata->close = conn->close;
+ sasldata->read = conn->read;
+ sasldata->write = conn->write;
+
+ /* and set up new functions */
+ conn->sockdata = sasldata;
+ conn->open = mutt_sasl_conn_open;
+ conn->close = mutt_sasl_conn_close;
+ conn->read = mutt_sasl_conn_read;
+ conn->write = mutt_sasl_conn_write;
+}
+
/* mutt_sasl_cb_log: callback to log SASL messages */
static int mutt_sasl_cb_log (void* context, int priority, const char* message)
{
@@ -159,3 +242,163 @@ static int mutt_sasl_cb_pass (sasl_conn_t* conn, void* context, int id,
return SASL_OK;
}
+
+/* mutt_sasl_conn_open: empty wrapper for underlying open function. We
+ * don't know in advance that a connection will use SASL, so we
+ * replace conn's methods with sasl methods when authentication
+ * is successful, using mutt_sasl_setup_conn */
+static int mutt_sasl_conn_open (CONNECTION* conn)
+{
+ SASL_DATA* sasldata;
+ int rc;
+
+ sasldata = (SASL_DATA*) conn->sockdata;
+ conn->sockdata = sasldata->sockdata;
+ rc = (sasldata->open) (conn);
+ conn->sockdata = sasldata;
+
+ return rc;
+}
+
+/* mutt_sasl_conn_close: calls underlying close function and disposes of
+ * the sasl_conn_t object, then restores connection to pre-sasl state */
+static int mutt_sasl_conn_close (CONNECTION* conn)
+{
+ SASL_DATA* sasldata;
+ int rc;
+
+ sasldata = (SASL_DATA*) conn->sockdata;
+
+ /* restore connection's underlying methods */
+ conn->sockdata = sasldata->sockdata;
+ conn->open = sasldata->open;
+ conn->close = sasldata->close;
+ conn->read = sasldata->read;
+ conn->write = sasldata->write;
+
+ /* release sasl resources */
+ sasl_dispose (&sasldata->saslconn);
+ FREE (&sasldata->buf);
+ FREE (&sasldata);
+
+ /* call underlying close */
+ rc = (conn->close) (conn);
+
+ return rc;
+}
+
+static int mutt_sasl_conn_read (CONNECTION* conn)
+{
+ SASL_DATA* sasldata;
+ int rc;
+
+ unsigned int olen;
+
+ sasldata = (SASL_DATA*) conn->sockdata;
+
+ /* if we still have data in our read buffer, copy it into conn->inbuf */
+ if (sasldata->blen > sasldata->bpos)
+ {
+ olen = (sasldata->blen - sasldata->bpos > sizeof (conn->inbuf)) ?
+ sizeof (conn->inbuf) : sasldata->blen - sasldata->bpos;
+
+ memcpy (conn->inbuf, sasldata->buf+sasldata->bpos, olen);
+ sasldata->bpos += olen;
+
+ return olen;
+ }
+
+ conn->sockdata = sasldata->sockdata;
+
+ FREE (&sasldata->buf);
+ sasldata->bpos = 0;
+ sasldata->blen = 0;
+
+ /* and decode the result, if necessary */
+ if (*sasldata->ssf)
+ {
+ do
+ {
+ /* call the underlying read function to fill the buffer */
+ rc = (sasldata->read) (conn);
+ if (rc <= 0)
+ goto out;
+
+ rc = sasl_decode (sasldata->saslconn, conn->inbuf, rc, &sasldata->buf,
+ &sasldata->blen);
+ if (rc != SASL_OK)
+ {
+ dprint (1, (debugfile, "SASL decode failed: %s\n",
+ sasl_errstring (rc, NULL, NULL)));
+ goto out;
+ }
+ }
+ while (!sasldata->blen);
+
+ olen = (sasldata->blen - sasldata->bpos > sizeof (conn->inbuf)) ?
+ sizeof (conn->inbuf) : sasldata->blen - sasldata->bpos;
+
+ memcpy (conn->inbuf, sasldata->buf, olen);
+ sasldata->bpos += olen;
+
+ rc = olen;
+ }
+ else
+ rc = (sasldata->read) (conn);
+
+ out:
+ conn->sockdata = sasldata;
+
+ return rc;
+}
+
+static int mutt_sasl_conn_write (CONNECTION* conn, const char* buf,
+ size_t len)
+{
+ SASL_DATA* sasldata;
+ int rc;
+
+ char* pbuf;
+ unsigned int olen, plen;
+
+ sasldata = (SASL_DATA*) conn->sockdata;
+ conn->sockdata = sasldata->sockdata;
+
+ /* encode data, if necessary */
+ if (*sasldata->ssf)
+ {
+ /* handle data larger than MAXOUTBUF */
+ do
+ {
+ olen = (len > *sasldata->pbufsize) ? *sasldata->pbufsize : len;
+
+ rc = sasl_encode (sasldata->saslconn, buf, olen, &pbuf, &plen);
+ if (rc != SASL_OK)
+ {
+ dprint (1, (debugfile, "SASL encoding failed: %s\n",
+ sasl_errstring (rc, NULL, NULL)));
+ goto fail;
+ }
+
+ rc = (sasldata->write) (conn, pbuf, plen);
+ FREE (&pbuf);
+ if (rc != plen)
+ goto fail;
+
+ len -= olen;
+ buf += olen;
+ }
+ while (len > *sasldata->pbufsize);
+ }
+ else
+ /* just write using the underlying socket function */
+ rc = (sasldata->write) (conn, buf, len);
+
+ conn->sockdata = sasldata;
+
+ return rc;
+
+ fail:
+ conn->sockdata = sasldata;
+ return -1;
+}
diff --git a/mutt_sasl.h b/mutt_sasl.h
index e979e160..777fc746 100644
--- a/mutt_sasl.h
+++ b/mutt_sasl.h
@@ -21,11 +21,33 @@
#ifndef _MUTT_SASL_H_
#define _MUTT_SASL_H_ 1
-#include "mutt_socket.h"
-
#include <sasl.h>
+#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);
+
+typedef struct
+{
+ sasl_conn_t* saslconn;
+ const sasl_ssf_t* ssf;
+ const unsigned int* pbufsize;
+
+ /* read buffer */
+ char* buf;
+ unsigned int blen;
+ unsigned int bpos;
+
+ /* underlying socket data */
+ void* sockdata;
+ int (*open) (CONNECTION* conn);
+ int (*close) (CONNECTION* conn);
+ int (*read) (CONNECTION* conn);
+ int (*write) (CONNECTION* conn, const char* buf, size_t count);
+}
+SASL_DATA;
#endif /* _MUTT_SASL_H_ */
diff --git a/mutt_socket.c b/mutt_socket.c
index a588fe1e..12dc8f45 100644
--- a/mutt_socket.c
+++ b/mutt_socket.c
@@ -59,9 +59,19 @@ int mutt_socket_close (CONNECTION* conn)
int mutt_socket_write_d (CONNECTION *conn, const char *buf, int dbg)
{
+ int rc;
+
dprint (dbg, (debugfile,"> %s", buf));
- return conn->write (conn, buf);
+ if ((rc = conn->write (conn, buf, mutt_strlen (buf))) < 0)
+ {
+ dprint (1, (debugfile, "mutt_socket_write: error writing, closing socket\n"));
+ mutt_socket_close (conn);
+
+ return -1;
+ }
+
+ return rc;
}
/* simple read buffering to speed things up. */
@@ -88,8 +98,9 @@ int mutt_socket_readln_d (char* buf, size_t buflen, CONNECTION* conn, int dbg)
{
if (mutt_socket_readchar (conn, &ch) != 1)
{
- dprint (1, (debugfile, "mutt_socket_readln_d: read error"));
+ dprint (1, (debugfile, "mutt_socket_readln_d: read error, closing socket"));
buf[i] = '\0';
+ mutt_socket_close (conn);
return -1;
}
if (ch == '\n')
@@ -230,9 +241,9 @@ int raw_socket_read (CONNECTION *conn)
return read (conn->fd, conn->inbuf, LONG_STRING);
}
-int raw_socket_write (CONNECTION *conn, const char *buf)
+int raw_socket_write (CONNECTION* conn, const char* buf, size_t count)
{
- return write (conn->fd, buf, mutt_strlen (buf));
+ return write (conn->fd, buf, count);
}
int raw_socket_open (CONNECTION* conn)
diff --git a/mutt_socket.h b/mutt_socket.h
index 4e151836..fd776d2d 100644
--- a/mutt_socket.h
+++ b/mutt_socket.h
@@ -42,7 +42,7 @@ typedef struct _connection
void *sockdata;
int (*read) (struct _connection *conn);
- int (*write) (struct _connection *conn, const char *buf);
+ int (*write) (struct _connection *conn, const char *buf, size_t count);
int (*open) (struct _connection *conn);
int (*close) (struct _connection *conn);
} CONNECTION;
@@ -61,7 +61,7 @@ void mutt_socket_free (CONNECTION* conn);
CONNECTION* mutt_conn_find (const CONNECTION* start, const ACCOUNT* account);
int raw_socket_read (CONNECTION *conn);
-int raw_socket_write (CONNECTION *conn, const char *buf);
+int raw_socket_write (CONNECTION* conn, const char* buf, size_t count);
int raw_socket_open (CONNECTION *conn);
int raw_socket_close (CONNECTION *conn);