Commit 114dce60 authored by Thomas Roessler's avatar Thomas Roessler

Tommi Komulainen's IMAP/SSL support patches.

parent c42f3d03
......@@ -51,7 +51,8 @@ non_us_sources = pgp.c pgpinvoke.c pgpkey.c pgplib.c sha1dgst.c \
gnupgparse.c sha.h sha_locl.h \
doc/language.txt doc/language50.txt OPS.PGP doc/PGP-Notes.txt \
OPS.MIX remailer.c remailer.h pgpewrap \
contrib/pgp2.rc contrib/pgp5.rc contrib/gpg.rc
contrib/pgp2.rc contrib/pgp5.rc contrib/gpg.rc \
imap/imap_ssl.c imap/imap_ssl.h README.SSL
EXTRA_mutt_SOURCES = pgp.c pgpinvoke.c pgpkey.c pgplib.c sha1dgst.c \
gnupgparse.c resize.c dotlock.c pop.c remailer.c remailer.h browser.h
......@@ -65,7 +66,7 @@ EXTRA_DIST = COPYRIGHT GPL OPS OPS.PGP TODO configure acconfig.h attach.h \
sort.h mime.types VERSION prepare _regex.h OPS.MIX \
README.SECURITY remailer.c remailer.h browser.h \
lib.h extlib.c pgpewrap pgplib.h Muttrc.head Muttrc \
makedoc.c stamp-doc-rc
makedoc.c stamp-doc-rc README.SSL
mutt_dotlock_SOURCES = mutt_dotlock.c
......@@ -142,7 +143,7 @@ us-distdir: distdir dist-hook
us-dist: us-distdir
for file in $(distdir)-us/*.c $(distdir)-us/*.h ; do \
$(srcdir)/reap.pl _PGPPATH < $$file | $(srcdir)/reap.pl MIXMASTER > $$file.n && rm $$file && mv $$file.n $$file ; \
$(srcdir)/reap.pl _PGPPATH < $$file | $(srcdir)/reap.pl MIXMASTER | $(srcdir)/reap.pl USE_SSL > $$file.n && rm $$file && mv $$file.n $$file ; \
done
for file in $(non_us_sources) ; do \
echo "/* This file is only available in the international mutt version */" \
......
Major changes since 1.1
-----------------------
- Tommi Komulainen <[email protected]> contributed SSL support
for mutt's IMAP client code.
Major changes since 0.96.3
--------------------------
......
IMAP/SSL in mutt
================
To have SSL support in mutt, you need to install OpenSSL
(http://www.openssl.org) library before compiling. Versions 0.9.3
and 0.9.4 have been tested.
IMAP/SSL folders can be accessed just like normal IMAP folders, but you
will also have to add '/ssl' before the closing curly brace.
For example:
mailboxes {localhost/ssl}inbox
mailboxes {localhost:994/ssl}inbox
Each time a server is contacted, its certificate is checked against
known valid certificates. When an unknown certificate is encountered,
you are asked to verify it. If you reject the certificate, the
connection will be terminated immediately. If you accept the
certificate, the connection will be established. If you accept the
certificate, you can also save it so that further connections to the
server are automatically accepted. Certificates will be saved in the
file specified by $certificate_file variable. It is empty as default,
so if you don't want to verify certificates each time you connect to a
server, you have set this variable to some reasonable value.
For example:
set certificate_file=~/.mutt/certificates
--
Tommi Komulainen
[email protected]
......@@ -51,6 +51,9 @@
/* Do you want support for IMAP GSSAPI authentication? (--with-gss) */
#undef USE_GSS
/* Do you want support for SSL? (--enable-ssl) */
#undef USE_SSL
/*
* Is mail spooled to the user's home directory? If defined, MAILPATH should
* be set to the filename of the spool mailbox relative the the home
......
......@@ -476,6 +476,18 @@ AC_ARG_WITH(gss, [ --with-gss[=DIR] Compile in GSSAPI authentication for
fi
])
AC_ARG_ENABLE(ssl, [ --enable-ssl Enable SSL support],
[ if test "$need_imap" != "yes"; then
AC_MSG_ERROR([Sorry, SSL support only for IMAP])
fi
AC_CHECK_LIB(crypto, X509_new,, AC_MSG_ERROR([Unable to find SSL library]))
AC_CHECK_LIB(ssl, SSL_new,, AC_MSG_ERROR([Unable to find SSL library]), -lcrypto)
AC_DEFINE(USE_SSL)
need_ssl=yes
])
AM_CONDITIONAL(USE_SSL, test x$need_ssl = xyes)
AC_ARG_ENABLE(debug, [ --enable-debug Enable debugging support],
[ AC_DEFINE(DEBUG) ])
......
......@@ -1951,6 +1951,13 @@ server, you should use <tt>{imapserver}path/to/folder</tt> where
You can select an alternative port by specifying it with the server, ie:
<tt/{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
can be encrypted. This naturally requires that the server supports
SSL encrypted connections. To access a folder with IMAP/SSL, you should
use <tt>{imapserver[:port]/ssl}path/to/folder</tt> as your
folder path.
Note that not all servers use / as the hierarchy separator. Mutt should
correctly notice which separator is being used by the server and convert
paths accordingly.
......
......@@ -2,12 +2,17 @@
AUTOMAKE_OPTIONS = foreign
if USE_SSL
SSLSOURCES = imap_ssl.c
SSLHEADERS = imap_ssl.h
endif
EXTRA_DIST = BUGS README TODO
INCLUDES = -I$(top_srcdir)
noinst_LIBRARIES = libimap.a
noinst_HEADERS = imap_private.h imap_socket.h md5.h message.h
noinst_HEADERS = imap_private.h imap_socket.h md5.h message.h $(SSLHEADERS)
libimap_a_SOURCES = auth.c browse.c command.c imap.c imap.h md5c.c message.c \
socket.c util.c
socket.c util.c $(SSLSOURCES)
......@@ -60,7 +60,7 @@ int imap_init_browse (char *path, struct browser_state *state)
int noselect;
int noinferiors;
if (imap_parse_path (path, host, sizeof (host), &port, &ipath))
if (imap_parse_path (path, host, sizeof (host), &port, NULL, &ipath))
{
mutt_error ("%s is an invalid IMAP path", path);
return -1;
......@@ -255,7 +255,7 @@ static int add_list_result (CONNECTION *conn, const char *seq, const char *cmd,
int noselect;
int noinferiors;
if (imap_parse_path (state->folder, host, sizeof (host), &port, &curfolder))
if (imap_parse_path (state->folder, host, sizeof (host), &port, NULL, &curfolder))
{
dprint (2, (debugfile,
"add_list_result: current folder %s makes no sense\n", state->folder));
......@@ -299,7 +299,7 @@ static void imap_add_folder (char delim, char *folder, int noselect,
char *curfolder;
int flen = strlen (folder);
if (imap_parse_path (state->folder, host, sizeof (host), &port, &curfolder))
if (imap_parse_path (state->folder, host, sizeof (host), &port, NULL, &curfolder))
return;
imap_unquote_string (folder);
......
......@@ -405,7 +405,7 @@ int imap_open_connection (IMAP_DATA *idata, CONNECTION *conn)
if (mutt_socket_read_line_d (buf, sizeof (buf), conn) < 0)
{
close (conn->fd);
mutt_socket_close_connection (conn);
idata->state = IMAP_DISCONNECTED;
return (-1);
}
......@@ -415,7 +415,7 @@ int imap_open_connection (IMAP_DATA *idata, CONNECTION *conn)
if (imap_check_capabilities(idata) != 0
|| imap_authenticate (idata, conn) != 0)
{
close (conn->fd);
mutt_socket_close_connection (conn);
idata->state = IMAP_DISCONNECTED;
return (-1);
}
......@@ -424,7 +424,7 @@ int imap_open_connection (IMAP_DATA *idata, CONNECTION *conn)
{
if (imap_check_capabilities(idata) != 0)
{
close (conn->fd);
mutt_socket_close_connection (conn);
idata->state = IMAP_DISCONNECTED;
return (-1);
}
......@@ -432,7 +432,7 @@ int imap_open_connection (IMAP_DATA *idata, CONNECTION *conn)
else
{
imap_error ("imap_open_connection()", buf);
close (conn->fd);
mutt_socket_close_connection (conn);
idata->state = IMAP_DISCONNECTED;
return (-1);
}
......@@ -512,8 +512,9 @@ int imap_open_mailbox (CONTEXT *ctx)
int count = 0;
int n;
int port;
int socktype;
if (imap_parse_path (ctx->path, host, sizeof (host), &port, &pc))
if (imap_parse_path (ctx->path, host, sizeof (host), &port, &socktype, &pc))
{
mutt_error ("%s is an invalid IMAP path", ctx->path);
return -1;
......@@ -530,7 +531,7 @@ int imap_open_mailbox (CONTEXT *ctx)
/* We need to create a new connection, the current one isn't useful */
idata = safe_calloc (1, sizeof (IMAP_DATA));
conn = mutt_socket_select_connection (host, port, M_NEW_SOCKET);
conn = mutt_socket_select_connection (host, port, socktype);
conn->data = idata;
idata->conn = conn;
}
......@@ -687,7 +688,7 @@ int imap_select_mailbox (CONTEXT* ctx, const char* path)
strfcpy (curpath, path, sizeof (curpath));
/* check that the target folder makes sense */
if (imap_parse_path (curpath, host, sizeof (host), &port, &mbox))
if (imap_parse_path (curpath, host, sizeof (host), &port, NULL, &mbox))
return -1;
/* and that it's on the same server as the current folder */
......@@ -736,8 +737,9 @@ int imap_open_mailbox_append (CONTEXT *ctx)
char *pc;
int r;
int port;
int socktype;
if (imap_parse_path (ctx->path, host, sizeof (host), &port, &pc))
if (imap_parse_path (ctx->path, host, sizeof (host), &port, &socktype, &pc))
return (-1);
ctx->magic = M_IMAP;
......@@ -831,7 +833,7 @@ int imap_close_connection (CONTEXT *ctx)
while (mutt_strncmp (seq, buf, SEQLEN) != 0);
mutt_clear_error ();
}
close (CTX_DATA->conn->fd);
mutt_socket_close_connection (CTX_DATA->conn);
CTX_DATA->state = IMAP_DISCONNECTED;
CTX_DATA->conn->uses = 0;
CTX_DATA->conn->data = NULL;
......@@ -1159,7 +1161,7 @@ int imap_mailbox_check (char *path, int new)
int msgcount = 0;
int port;
if (imap_parse_path (path, host, sizeof (host), &port, &pc))
if (imap_parse_path (path, host, sizeof (host), &port, NULL, &pc))
return -1;
conn = mutt_socket_select_connection (host, port, 0);
......@@ -1344,7 +1346,7 @@ int imap_subscribe (char *path, int subscribe)
char *ipath = NULL;
int port;
if (imap_parse_path (path, host, sizeof (host), &port, &ipath))
if (imap_parse_path (path, host, sizeof (host), &port, NULL, &ipath))
return (-1);
conn = mutt_socket_select_connection (host, port, 0);
......@@ -1399,7 +1401,7 @@ int imap_complete(char* dest, size_t dlen, char* path) {
int pos = 0;
/* verify passed in path is an IMAP path */
if (imap_parse_path (path, host, sizeof(host), &port, &mbox))
if (imap_parse_path (path, host, sizeof(host), &port, NULL, &mbox))
{
dprint(2, (debugfile, "imap_complete: bad path %s\n", path));
return -1;
......
......@@ -45,7 +45,7 @@ int imap_fetch_message (MESSAGE* msg, CONTEXT* ctx, int msgno);
/* util.c */
int imap_parse_path (char* path, char* host, size_t hlen, int* port,
char** mbox);
int *socktype, char** mbox);
void imap_qualify_path (char* dest, size_t len, const char* host, int port,
const char* path, const char* name);
......
......@@ -25,6 +25,7 @@
/* -- symbols -- */
#define IMAP_PORT 143
#define IMAP_SSL_PORT 993
/* number of entries in the hash table */
#define IMAP_CACHE_LEN 10
......
......@@ -32,14 +32,26 @@ typedef struct _connection
int available;
void *data;
struct _connection *next;
void *sockdata;
int (*read) (struct _connection *conn);
int (*write) (struct _connection *conn, const char *buf);
int (*open) (struct _connection *conn);
int (*close) (struct _connection *conn);
} CONNECTION;
int mutt_socket_readchar (CONNECTION *conn, char *c);
int mutt_socket_read_line (char *buf, size_t buflen, CONNECTION *conn);
int mutt_socket_read_line_d (char *buf, size_t buflen, CONNECTION *conn);
int mutt_socket_write (CONNECTION *conn, const char *buf);
CONNECTION *mutt_socket_select_connection (char *host, int port, int flags);
int mutt_socket_open_connection (CONNECTION *conn);
int mutt_socket_close_connection (CONNECTION *conn);
int raw_socket_read (CONNECTION *conn);
int raw_socket_write (CONNECTION *conn, const char *buf);
int raw_socket_open (CONNECTION *conn);
int raw_socket_close (CONNECTION *conn);
#endif /* _IMAP_SOCKET_H_ */
/*
* Copyright (C) 1999 Tommi Komulainen <[email protected]>
*
* 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <openssl/ssl.h>
#include <openssl/x509.h>
#include <openssl/err.h>
#undef _
#include <string.h>
#include "mutt.h"
#include "imap_socket.h"
#include "mutt_menu.h"
#include "mutt_curses.h"
#include "imap_ssl.h"
char *SslCertFile = NULL;
typedef struct _sslsockdata
{
SSL_CTX *ctx;
SSL *ssl;
X509 *cert;
}
sslsockdata;
static int ssl_check_certificate (sslsockdata * data);
int ssl_socket_read (CONNECTION * conn)
{
sslsockdata *data = conn->sockdata;
return SSL_read (data->ssl, conn->inbuf, LONG_STRING);
}
int ssl_socket_write (CONNECTION * conn, const char *buf)
{
sslsockdata *data = conn->sockdata;
dprint (1, (debugfile, "ssl_socket_write():%s", buf));
return SSL_write (data->ssl, buf, mutt_strlen (buf));
}
int ssl_socket_open (CONNECTION * conn)
{
sslsockdata *data;
int err;
if (raw_socket_open (conn) < 0)
return -1;
data = (sslsockdata *) safe_calloc (1, sizeof (sslsockdata));
conn->sockdata = data;
SSLeay_add_ssl_algorithms ();
data->ctx = SSL_CTX_new (SSLv23_client_method ());
data->ssl = SSL_new (data->ctx);
SSL_set_fd (data->ssl, conn->fd);
if ((err = SSL_connect (data->ssl)) < 0)
{
ssl_socket_close (conn);
return -1;
}
data->cert = SSL_get_peer_certificate (data->ssl);
if (!data->cert)
{
mutt_error (_("Unable to get certificate from peer"));
sleep (1);
return -1;
}
if (!ssl_check_certificate (data))
{
ssl_socket_close (conn);
return -1;
}
mutt_message (_("SSL connection using %s"), SSL_get_cipher (data->ssl));
sleep (1);
return 0;
}
int ssl_socket_close (CONNECTION * conn)
{
sslsockdata *data = conn->sockdata;
SSL_shutdown (data->ssl);
X509_free (data->cert);
SSL_free (data->ssl);
SSL_CTX_free (data->ctx);
return raw_socket_close (conn);
}
static char *x509_get_part (char *line, const char *ndx)
{
static char ret[SHORT_STRING];
char *c, *c2;
strncpy (ret, _("Unknown"), sizeof (ret));
c = strstr (line, ndx);
if (c)
{
c += strlen (ndx);
c2 = strchr (c, '/');
if (c2)
*c2 = '\0';
strncpy (ret, c, sizeof (ret));
if (c2)
*c2 = '/';
}
return ret;
}
static void x509_fingerprint (char *s, int l, X509 * cert)
{
unsigned char md[EVP_MAX_MD_SIZE];
unsigned int n;
int j;
if (!X509_digest (cert, EVP_md5 (), md, &n))
{
snprintf (s, l, _("[unable to calculate]"));
}
else
{
for (j = 0; j < (int) n; j++)
{
char ch[8];
snprintf (ch, 8, "%02X%s", md[j], (j % 2 ? " " : ""));
strncat (s, ch, l);
}
}
}
static int ssl_check_certificate (sslsockdata * data)
{
char *part[] =
{"/CN=", "/Email=", "/O=", "/OU=", "/L=", "/ST=", "/C="};
char helpstr[SHORT_STRING];
char buf[SHORT_STRING];
MUTTMENU *menu;
int done, i;
FILE *fp;
char *line = NULL, *c;
/* automatic check from user's database */
fp = fopen (SslCertFile, "rt");
if (fp)
{
EVP_PKEY *peer = X509_get_pubkey (data->cert);
X509 *savedkey = NULL;
int pass = 0;
while ((savedkey = PEM_read_X509 (fp, &savedkey, NULL)))
{
if (X509_verify (savedkey, peer))
{
pass = 1;
break;
}
}
fclose (fp);
if (pass)
return 1;
}
menu = mutt_new_menu ();
menu->max = 15;
menu->dialog = (char **) safe_calloc (1, menu->max * sizeof (char *));
for (i = 0; i < menu->max; i++)
menu->dialog[i] = (char *) safe_calloc (1, SHORT_STRING * sizeof (char));
strncpy (menu->dialog[0], _("This certificate belongs to:"), SHORT_STRING);
line = X509_NAME_oneline (X509_get_subject_name (data->cert),
buf, sizeof (buf));
for (i = 1; i <= 5; i++)
{
c = x509_get_part (line, part[i - 1]);
snprintf (menu->dialog[i], SHORT_STRING, " %s", c);
}
strncpy (menu->dialog[7], _("This certificate was issued by:"), SHORT_STRING);
line = X509_NAME_oneline (X509_get_subject_name (data->cert),
buf, sizeof (buf));
for (i = 8; i <= 12; i++)
{
c = x509_get_part (line, part[i - 8]);
snprintf (menu->dialog[i], SHORT_STRING, " %s", c);
}
buf[0] = '\0';
x509_fingerprint (buf, sizeof (buf), data->cert);
snprintf (menu->dialog[14], SHORT_STRING, _("Fingerprint: %s"), buf);
menu->title = _("SSL Certificate check");
menu->prompt = _("(r)eject, accept (o)nce, (a)ccept always");
menu->keys = _("roa");
helpstr[0] = '\0';
mutt_make_help (buf, sizeof (buf), _("Exit "), MENU_GENERIC, OP_EXIT);
strncat (helpstr, buf, sizeof (helpstr));
mutt_make_help (buf, sizeof (buf), _("Help"), MENU_GENERIC, OP_HELP);
strncat (helpstr, buf, sizeof (helpstr));
menu->help = helpstr;
done = 0;
while (!done)
{
switch (mutt_menuLoop (menu))
{
case -1: /* abort */
case OP_MAX + 1: /* reject */
case OP_EXIT:
done = 1;
break;
case OP_MAX + 3: /* accept always */
done = 0;
fp = fopen (SslCertFile, "w+t");
if (fp)
{
if (PEM_write_X509 (fp, data->cert))
done = 1;
fclose (fp);
}
if (!done)
mutt_error (_("Warning: Couldn't save certificate"));
else
mutt_message (_("Certificate saved"));
sleep (1);
/* fall through */
case OP_MAX + 2: /* accept once */
done = 2;
break;
}
}
mutt_menuDestroy (&menu);
return (done == 2);
}
/*
* Copyright (C) 1999 Tommi Komulainen <[email protected]>
*
* 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef _MUTT_SSL_H_
#define _MUTT_SSL_H_ 1
extern char *SslCertFile;
extern int ssl_socket_read (CONNECTION *conn);
extern int ssl_socket_write (CONNECTION *conn, const char *buf);
extern int ssl_socket_open (CONNECTION *conn);
extern int ssl_socket_close (CONNECTION *conn);
#endif
......@@ -404,7 +404,7 @@ int imap_append_message (CONTEXT *ctx, MESSAGE *msg)
size_t len;
int c, last;
if (imap_parse_path (ctx->path, host, sizeof (host), &port, &pc))
if (imap_parse_path (ctx->path, host, sizeof (host), &port, NULL, &pc))
return (-1);
imap_fix_path (CTX_DATA, pc, mailbox, sizeof (mailbox));
......@@ -526,7 +526,7 @@ int imap_copy_messages (CONTEXT* ctx, HEADER* h, char* dest, int delete)
int rc;
int n;
if (imap_parse_path (dest, host, sizeof (host), &port, &pc))
if (imap_parse_path (dest, host, sizeof (host), &port, NULL, &pc))
{
dprint (1, (debugfile, "imap_copy_message: bad destination %s\n", dest));
return -1;
......
......@@ -19,6 +19,9 @@
#include "mutt.h"
#include "globals.h"
#include "imap_socket.h"
#ifdef USE_SSL
#include "imap_ssl.h"
#endif
#include <unistd.h>
#include <netinet/in.h>
......@@ -32,12 +35,32 @@
static CONNECTION *Connections = NULL;
/* Wrappers */
int mutt_socket_open_connection (CONNECTION *conn)
{
return conn->open (conn);
}
int mutt_socket_close_connection (CONNECTION *conn)
{
return conn->close (conn);
}
int mutt_socket_write (CONNECTION *conn, const char *buf)
{
dprint (1,(debugfile,"> %s", buf));
return conn->write (conn, buf);
}
/* simple read buffering to speed things up. */
int mutt_socket_readchar (CONNECTION *conn, char *c)
{
if (conn->bufpos >= conn->available)
{
conn->available = read (conn->fd, conn->inbuf, LONG_STRING);
conn->available = conn->read (conn);
conn->bufpos = 0;
if (conn->available <= 0)
return conn->available; /* returns 0 for EOF or -1 for other error */
......@@ -74,17 +97,15 @@ int mutt_socket_read_line_d (char *buf, size_t buflen, CONNECTION *conn)
return r;
}
int mutt_socket_write (CONNECTION *conn, const char *buf)
{
dprint (1,(debugfile,"> %s", buf));
return (write (conn->fd, buf, mutt_strlen (buf)));
}
CONNECTION *mutt_socket_select_connection (char *host, int port, int flags)
{
CONNECTION *conn;
#ifdef USE_SSL
if (flags != M_NEW_SOCKET && flags != M_NEW_SSL_SOCKET)
#else
if (flags != M_NEW_SOCKET)
#endif
{
conn = Connections;
while (conn)
......@@ -104,6 +125,21 @@ CONNECTION *mutt_socket_select_connection (char *host, int port, int flags)
conn->next = Connections;
Connections = conn;
conn->read = raw_socket_read;
conn->write = raw_socket_write;
conn->open = raw_socket_open;
conn->close = raw_socket_close;
#ifdef USE_SSL
if (flags == M_NEW_SSL_SOCKET)
{
conn->read = ssl_socket_read;
conn->write = ssl_socket_write;
conn->open = ssl_socket_open;
conn->close = ssl_socket_close;
}
#endif
return conn;
}
......@@ -131,7 +167,22 @@ static int try_socket_and_connect (CONNECTION *conn, struct sockaddr_in sin,
return 0;
}
int mutt_socket_open_connection (CONNECTION *conn)
int raw_socket_close (CONNECTION *conn)
{
return close (conn->fd);
}
int raw_socket_read (CONNECTION *conn)
{
return read (conn->fd, conn->inbuf, LONG_STRING);
}
int raw_socket_write (CONNECTION *conn, const char *buf)
{
return write (conn->fd, buf, mutt_strlen (buf));
}
int raw_socket_open (CONNECTION *conn)
{
struct sockaddr_in sin;
struct hostent *he;
......
......@@ -121,20 +121,22 @@ char *imap_next_word (char *s)
/* imap_parse_path: given an IMAP mailbox name, return host, port