]> granicus.if.org Git - mutt/commitdiff
Brendan Cully's SASL patch.
authorThomas Roessler <roessler@does-not-exist.org>
Mon, 12 Feb 2001 10:27:10 +0000 (10:27 +0000)
committerThomas Roessler <roessler@does-not-exist.org>
Mon, 12 Feb 2001 10:27:10 +0000 (10:27 +0000)
12 files changed:
imap/auth_login.c
imap/auth_sasl.c
imap/browse.c
imap/command.c
imap/imap.c
imap/imap_private.h
imap/message.c
imap/util.c
mutt_sasl.c
mutt_sasl.h
mutt_ssl.c
mutt_ssl.h

index fff5baa6884992cc0e2487e2c562ce95c984a96a..212d7fdef596c9c66eef7dbf14842a9949168f37 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * 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
@@ -60,9 +60,6 @@ imap_auth_res_t imap_auth_login (IMAP_DATA* idata)
   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;
index 55885e2c2872b325b1a09d40a294095e6318b20d..75d0659cab173c848ce071d1a7c670ebb5b30708 100644 (file)
@@ -23,9 +23,6 @@
 #include "imap_private.h"
 #include "auth.h"
 
-#include <netinet/in.h>
-#include <netdb.h>
-
 #include <sasl.h>
 #include <saslutil.h>
 
@@ -44,42 +41,13 @@ imap_auth_res_t imap_auth_sasl (IMAP_DATA* idata)
   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
@@ -128,13 +96,13 @@ imap_auth_res_t imap_auth_sasl (IMAP_DATA* idata)
       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;
@@ -163,7 +131,7 @@ imap_auth_res_t imap_auth_sasl (IMAP_DATA* idata)
 
       /* sasl_client_st(art|ep) allocate pc with malloc, expect me to 
        * free it */
-      safe_free (&pc);
+      FREE (&pc);
     }
     
     if (olen || rc == SASL_CONTINUE)
@@ -179,14 +147,14 @@ imap_auth_res_t imap_auth_sasl (IMAP_DATA* idata)
     }
   }
 
-  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;
index cf7c4bc51116ca4bbb57cfe44ec28513d1ed88bf..7a31f63d6539694e9ab93930bb9c6afc558e0eda 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * 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
@@ -124,7 +124,7 @@ int imap_browse (char* path, struct browser_state* state)
           }
         }
       }
-      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 */
@@ -222,7 +222,6 @@ int imap_browse (char* path, struct browser_state* state)
       }
   }
 
-  mutt_clear_error ();
   FREE (&mx.mbox);
   return 0;
 
@@ -316,7 +315,7 @@ static int browse_add_list_result (IMAP_DATA* idata, const char* cmd,
           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;
@@ -412,7 +411,7 @@ static int browse_get_namespace (IMAP_DATA* idata, char* nsbuf, int nsblen,
     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,
@@ -485,7 +484,7 @@ static int browse_get_namespace (IMAP_DATA* idata, char* nsbuf, int nsblen,
   }
   while (rc == IMAP_CMD_CONTINUE);
 
-  if (rc != IMAP_CMD_DONE)
+  if (rc != IMAP_CMD_OK)
     return -1;
 
   return 0;
@@ -524,7 +523,7 @@ static int browse_verify_namespace (IMAP_DATA* idata,
        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;
index f26af035c0fe2f1c3909c4a8bae923412ff164b2..b3c3029a4850cf72047cadcd200f34a1117a64c9 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * 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
@@ -35,7 +35,7 @@
 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);
@@ -62,25 +62,25 @@ int imap_cmd_start (IMAP_DATA* idata, const char* cmd)
 {
   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
@@ -89,33 +89,35 @@ int imap_cmd_start (IMAP_DATA* idata, const char* cmd)
  *   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;
@@ -123,30 +125,32 @@ int imap_cmd_step (IMAP_DATA* idata)
   /* 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;
@@ -181,11 +185,11 @@ int imap_exec (IMAP_DATA* idata, const char* cmd, int flags)
   }
 
   /* 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);
@@ -201,15 +205,15 @@ int imap_exec (IMAP_DATA* idata, const char* cmd, int flags)
   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);
@@ -220,16 +224,23 @@ int imap_exec (IMAP_DATA* idata, const char* cmd, int flags)
   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)))
@@ -275,7 +286,7 @@ static int cmd_handle_untagged (IMAP_DATA* idata)
   char* pn;
   int count;
 
-  s = imap_next_word (idata->buf);
+  s = imap_next_word (idata->cmd.buf);
 
   if ((idata->state == IMAP_SELECTED) && isdigit (*s))
   {
@@ -360,14 +371,12 @@ static int cmd_handle_untagged (IMAP_DATA* idata)
 }
 
 /* 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
index 4945952f963927784d4aa69fbdd25ce7b55a232a..ba96e782ec673a2ef07b8b781b0bd4e86ec873c5 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * 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
@@ -97,54 +97,6 @@ void imap_logout_all (void)
   }
 }
 
-/* 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 ?! */
@@ -240,7 +192,7 @@ static int imap_get_delim (IMAP_DATA *idata)
     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);
@@ -253,7 +205,7 @@ static int imap_get_delim (IMAP_DATA *idata)
   }
   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;
@@ -285,7 +237,7 @@ static int imap_check_capabilities (IMAP_DATA* idata)
 {
   if (imap_exec (idata, "CAPABILITY", 0) != 0)
   {
-    imap_error ("imap_check_capabilities", idata->buf);
+    imap_error ("imap_check_capabilities", idata->cmd.buf);
     return -1;
   }
 
@@ -329,29 +281,29 @@ IMAP_DATA* imap_conn_find (const ACCOUNT* account, int flags)
   /* 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)
@@ -359,19 +311,23 @@ 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;
@@ -510,7 +466,7 @@ int imap_open_mailbox (CONTEXT* ctx)
     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))
     {
@@ -521,7 +477,7 @@ int imap_open_mailbox (CONTEXT* ctx)
       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 */
@@ -552,18 +508,18 @@ int imap_open_mailbox (CONTEXT* ctx)
   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;
@@ -934,7 +890,7 @@ int imap_sync_mailbox (CONTEXT* ctx, int expunge, int* index_hint)
         (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;
       }
@@ -951,7 +907,7 @@ int imap_sync_mailbox (CONTEXT* ctx, int expunge, int* index_hint)
     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;
     }
   }
@@ -975,7 +931,7 @@ void imap_close_mailbox (CONTEXT* ctx)
       (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;
@@ -1020,7 +976,7 @@ int imap_check_mailbox (CONTEXT *ctx, int *index_hint)
 
     if (imap_exec (idata, "NOOP", 0) != 0)
     {
-      imap_error ("imap_check_mailbox", idata->buf);
+      imap_error ("imap_check_mailbox", idata->cmd.buf);
       return -1;
     }
   }
@@ -1103,7 +1059,7 @@ int imap_mailbox_check (char* path, int new)
     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);
@@ -1148,12 +1104,12 @@ int imap_parse_list_response(IMAP_DATA* idata, char **name, int *noselect,
   *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))
   {
@@ -1193,11 +1149,11 @@ int imap_parse_list_response(IMAP_DATA* idata, char **name, int *noselect,
     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;
@@ -1324,7 +1280,7 @@ int imap_complete(char* dest, size_t dlen, char* path) {
       completions++;
     }
   }
-  while (mutt_strncmp(idata->seq, idata->buf, SEQLEN));
+  while (mutt_strncmp(idata->cmd.seq, idata->cmd.buf, SEQLEN));
 
   if (completions)
   {
index 84d045daedaa7111329fe024cf6d6f49e11b9287..78f6e62f51999f322525d2a778e95ea38405af72 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * 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 */
@@ -132,17 +137,21 @@ typedef struct
   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.
@@ -152,6 +161,10 @@ typedef struct
    * 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;
@@ -167,6 +180,7 @@ typedef struct
   /* 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)
@@ -178,7 +192,6 @@ int imap_make_msg_set (IMAP_DATA* idata, char* buf, size_t buflen, int flag,
   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);
@@ -202,11 +215,14 @@ int imap_read_headers (IMAP_DATA* idata, int msgbegin, int msgend);
 /* 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);
index 9946778c12c77672a29ad2b66bcfc5235343307d..adaf142b0b55fb038469dcaeb6c4c217c3c95c8b 100644 (file)
@@ -127,7 +127,7 @@ int imap_read_headers (IMAP_DATA* idata, int msgbegin, int msgend)
       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;
@@ -164,10 +164,10 @@ int imap_read_headers (IMAP_DATA* idata, int msgbegin, int msgend)
 
       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);
@@ -257,7 +257,7 @@ int imap_fetch_message (MESSAGE *msg, CONTEXT *ctx, int msgno)
     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);
 
@@ -289,7 +289,7 @@ int imap_fetch_message (MESSAGE *msg, CONTEXT *ctx, int msgno)
          /* pick up trailing line */
          if ((rc = imap_cmd_step (idata)) != IMAP_CMD_CONTINUE)
            goto bail;
-         pc = idata->buf;
+         pc = idata->cmd.buf;
 
          fetched = 1;
        }
@@ -348,10 +348,10 @@ int imap_fetch_message (MESSAGE *msg, CONTEXT *ctx, int msgno)
   }
   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
@@ -453,9 +453,10 @@ int imap_append_message (CONTEXT *ctx, MESSAGE *msg)
   {
     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);
@@ -487,12 +488,13 @@ int imap_append_message (CONTEXT *ctx, MESSAGE *msg)
     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);
@@ -568,9 +570,9 @@ int imap_copy_messages (CONTEXT* ctx, HEADER* h, char* dest, int delete)
   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"));
@@ -588,7 +590,7 @@ int imap_copy_messages (CONTEXT* ctx, HEADER* h, char* dest, int delete)
   }
   if (rc != 0)
   {
-    imap_error ("imap_copy_messages", idata->buf);
+    imap_error ("imap_copy_messages", idata->cmd.buf);
     goto fail;
   }
 
@@ -699,7 +701,7 @@ static int msg_fetch_header (CONTEXT* ctx, IMAP_HEADER* h, char* buf, FILE* fp)
   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 */
index 778d39b239d2fec542f40b47f2fdd6577a4646dd..c0cfa1d71cb9f421a4bbf2fc5f720b6b2514f0da 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * 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
@@ -50,6 +50,35 @@ void imap_error (const char *where, const char *msg)
   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
@@ -127,6 +156,54 @@ char *imap_next_word (char *s)
   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 */
index 6714463e3f89f6a6c19b4ac88d6f6c7dc3cd5e51..581d1c2e420f25273342d8b20026d64d73550f74 100644 (file)
 #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];
 
@@ -77,6 +87,110 @@ int mutt_sasl_start (void)
   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;
index 777fc74647368e7267515094befb3505798d3fdc..3505eafeb2e861a354be946c015eec1cc4f2a325 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * 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 
 {
index 187fd4ee004af68d44abcf5ecfad54b4a99a5ce1..efd1b64387a216c4ce72ef77dabd5d6c717c0ee0 100644 (file)
@@ -68,6 +68,18 @@ typedef struct _sslsockdata
 }
 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
index 575580a3cd13ac55a14d1bd7980be4c96df87c9c..73ece1a1db0f9108b43cbd7492a01c8a470843b8 100644 (file)
@@ -24,6 +24,8 @@
 extern char *SslCertFile;
 extern char *SslEntropyFile;
 
+int mutt_ssl_get_ssf (CONNECTION* conn);
+
 extern int ssl_socket_setup (CONNECTION *conn);
 
 #endif /* _MUTT_SSL_H_ */