]> granicus.if.org Git - mutt/commitdiff
SASL patch from Brendan Cully.
authorThomas Roessler <roessler@does-not-exist.org>
Fri, 4 Aug 2000 08:06:22 +0000 (08:06 +0000)
committerThomas Roessler <roessler@does-not-exist.org>
Fri, 4 Aug 2000 08:06:22 +0000 (08:06 +0000)
account.c
doc/manual.sgml.head
imap/auth_sasl.c
imap/imap_ssl.c
mutt_sasl.c
mutt_sasl.h
mutt_socket.c
mutt_socket.h

index f095763e7bcd255fcad8a5e0067a6db96f6a19cd..2853d254938d0ca5f328cc48436c72a58832dc07 100644 (file)
--- 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;
   }
 
index 182129f1edb526d1c05c2f5999d5b3546b2433c1..9f6cce7d54dbc74f747273d9b83fd5b804e1b4be 100644 (file)
@@ -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
index 8b78151ca0438b9eef232ad70bd9fdad2fdb39de..946500ec82fa2d8d76e577e89dc07a6d7c92fcd3 100644 (file)
@@ -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;
   }
 
index c16439863f20b3855fb9d29803bec65461db9304..42915e68b583a6f18239807dc62503fba15b34bb 100644 (file)
@@ -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)
index 30764a6fe6f8cd1fccc5a3105c2d7ef94e179378..0bd2491751852cafbff4a3dbbfdea27a4d6ab067 100644 (file)
@@ -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;
+}
index e979e160d7b05b8d325508f0f713fa0829b05d28..777fc74647368e7267515094befb3505798d3fdc 100644 (file)
 #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_ */
index a588fe1e1cecf69697928468021e2bd9c3fe4216..12dc8f455ec128a03f1cbea4260a265e60c346d9 100644 (file)
@@ -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)
index 4e15183645c3fd1afb14b9426284dadd94b2073c..fd776d2d93afe4d8c83e660f672a76f8ea997b52 100644 (file)
@@ -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);