/*
+ * Copyright notice from original mutt:
* Copyright (C) 1998 Michael R. Elkins <me@mutt.org>
- * Copyright (C) 1999-2001 Brendan Cully <brendan@kublai.com>
+ * Copyright (C) 1999-2005 Brendan Cully <brendan@kublai.com>
* Copyright (C) 1999-2000 Tommi Komulainen <Tommi.Komulainen@iki.fi>
- *
- * 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., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
- */
+ *
+ * This file is part of mutt-ng, see http://www.muttng.org/.
+ * It's licensed under the GNU General Public License,
+ * please see the file GPL in the top level source directory.
+ */
#if HAVE_CONFIG_H
# include "config.h"
#include "globals.h"
#include "mutt_socket.h"
#include "mutt_tunnel.h"
-#if defined(USE_SSL) || defined(USE_GNUTLS) || defined(USE_NSS)
+#if defined(USE_SSL) || defined(USE_GNUTLS)
# include "mutt_ssl.h"
#endif
#include "mutt_idna.h"
+#include "lib/mem.h"
+#include "lib/intl.h"
+#include "lib/str.h"
+#include "lib/debug.h"
+
#include <unistd.h>
#include <netinet/in.h>
#include <netdb.h>
/* forward declarations */
static int socket_preconnect (void);
-static int socket_connect (int fd, struct sockaddr* sa);
-static CONNECTION* socket_new_conn ();
+static int socket_connect (int fd, struct sockaddr *sa);
+static CONNECTION *socket_new_conn (void);
/* Wrappers */
-int mutt_socket_open (CONNECTION* conn)
+int mutt_socket_open (CONNECTION * conn)
{
if (socket_preconnect ())
return -1;
- return conn->open (conn);
+ return conn->conn_open (conn);
}
-int mutt_socket_close (CONNECTION* conn)
+int mutt_socket_close (CONNECTION * conn)
{
int rc = -1;
if (conn->fd < 0)
- dprint (1, (debugfile, "mutt_socket_close: Attempt to close closed connection.\n"));
+ debug_print (1, ("Attempt to close closed connection.\n"));
else
- rc = conn->close (conn);
+ rc = conn->conn_close (conn);
conn->fd = -1;
conn->ssf = 0;
return rc;
}
-int mutt_socket_read (CONNECTION* conn, char* buf, size_t len)
+int mutt_socket_read (CONNECTION * conn, char *buf, size_t len)
{
int rc;
- if (conn->fd < 0)
- {
- dprint (1, (debugfile, "mutt_socket_read: attempt to read from closed connection\n"));
+ if (conn->fd < 0) {
+ debug_print (1, ("attempt to read from closed connection\n"));
return -1;
}
- rc = conn->read (conn, buf, len);
+ rc = conn->conn_read (conn, buf, len);
/* EOF */
- if (rc == 0)
- {
+ if (rc == 0) {
mutt_error (_("Connection to %s closed"), conn->account.host);
mutt_sleep (2);
}
return rc;
}
-int mutt_socket_write_d (CONNECTION *conn, const char *buf, int dbg)
+int mutt_socket_write_d (CONNECTION * conn, const char *buf, int dbg)
{
int rc;
int len;
- dprint (dbg, (debugfile,"> %s", buf));
+ debug_print (dbg, ("> %s", buf));
- if (conn->fd < 0)
- {
- dprint (1, (debugfile, "mutt_socket_write: attempt to write to closed connection\n"));
+ if (conn->fd < 0) {
+ debug_print (1, ("attempt to write to closed connection\n"));
return -1;
}
- len = mutt_strlen (buf);
- if ((rc = conn->write (conn, buf, len)) < 0)
- {
- dprint (1, (debugfile,
- "mutt_socket_write: error writing, closing socket\n"));
+ len = str_len (buf);
+ if ((rc = conn->conn_write (conn, buf, len)) < 0) {
+ debug_print (1, ("error writing, closing socket\n"));
mutt_socket_close (conn);
return -1;
}
- if (rc < len)
- {
- dprint (1, (debugfile,
- "mutt_socket_write: ERROR: wrote %d of %d bytes!\n", rc, len));
+ if (rc < len) {
+ debug_print (1, ("ERROR: wrote %d of %d bytes!\n", rc, len));
}
return rc;
}
/* simple read buffering to speed things up. */
-int mutt_socket_readchar (CONNECTION *conn, char *c)
+int mutt_socket_readchar (CONNECTION * conn, char *c)
{
- if (conn->bufpos >= conn->available)
- {
+ if (conn->bufpos >= conn->available) {
if (conn->fd >= 0)
- conn->available = conn->read (conn, conn->inbuf, sizeof (conn->inbuf));
- else
- {
- dprint (1, (debugfile, "mutt_socket_readchar: attempt to read from closed connection.\n"));
+ conn->available =
+ conn->conn_read (conn, conn->inbuf, sizeof (conn->inbuf));
+ else {
+ debug_print (1, ("attempt to read from closed connection.\n"));
return -1;
}
conn->bufpos = 0;
- if (conn->available == 0)
- {
+ if (conn->available == 0) {
mutt_error (_("Connection to %s closed"), conn->account.host);
mutt_sleep (2);
}
- if (conn->available <= 0)
- {
+ if (conn->available <= 0) {
mutt_socket_close (conn);
return -1;
}
return 1;
}
-int mutt_socket_readln_d (char* buf, size_t buflen, CONNECTION* conn, int dbg)
+int mutt_socket_readln_d (char *buf, size_t buflen, CONNECTION * conn,
+ int dbg)
{
char ch;
int i;
- for (i = 0; i < buflen-1; i++)
- {
- if (mutt_socket_readchar (conn, &ch) != 1)
- {
+ for (i = 0; i < buflen - 1; i++) {
+ if (mutt_socket_readchar (conn, &ch) != 1) {
buf[i] = '\0';
return -1;
}
}
/* strip \r from \r\n termination */
- if (i && buf[i-1] == '\r')
+ if (i && buf[i - 1] == '\r')
buf[--i] = '\0';
else
buf[i] = '\0';
- dprint (dbg, (debugfile, "< %s\n", buf));
-
- /* number of bytes read, not strlen */
+ debug_print (dbg, ("< %s\n", buf));
+
+ /* number of bytes read, not str_len */
return i + 1;
}
-CONNECTION* mutt_socket_head (void)
+CONNECTION *mutt_socket_head (void)
{
return Connections;
}
/* mutt_socket_free: remove connection from connection list and free it */
-void mutt_socket_free (CONNECTION* conn)
+void mutt_socket_free (CONNECTION * conn)
{
- CONNECTION* iter;
- CONNECTION* tmp;
+ CONNECTION *iter;
+ CONNECTION *tmp;
iter = Connections;
/* head is special case, doesn't need prev updated */
- if (iter == conn)
- {
+ if (iter == conn) {
Connections = iter->next;
- FREE (&iter);
+ mem_free (&iter);
return;
}
- while (iter->next)
- {
- if (iter->next == conn)
- {
+ while (iter->next) {
+ if (iter->next == conn) {
tmp = iter->next;
iter->next = tmp->next;
- FREE (&tmp);
+ mem_free (&tmp);
return;
}
iter = iter->next;
* connections after the given connection (allows higher level socket code
* to make more fine-grained searches than account info - eg in IMAP we may
* wish to find a connection which is not in IMAP_SELECTED state) */
-CONNECTION* mutt_conn_find (const CONNECTION* start, const ACCOUNT* account)
+CONNECTION *mutt_conn_find (const CONNECTION * start, const ACCOUNT * account)
{
- CONNECTION* conn;
+ CONNECTION *conn;
ciss_url_t url;
char hook[LONG_STRING];
/* account isn't actually modified, since url isn't either */
- mutt_account_tourl ((ACCOUNT*) account, &url);
+ mutt_account_tourl ((ACCOUNT *) account, &url);
url.path = NULL;
url_ciss_tostring (&url, hook, sizeof (hook), 0);
mutt_account_hook (hook);
conn = start ? start->next : Connections;
- while (conn)
- {
+ while (conn) {
if (mutt_account_match (account, &(conn->account)))
return conn;
conn = conn->next;
if (Tunnel && *Tunnel)
mutt_tunnel_socket_setup (conn);
- else if (account->flags & M_ACCT_SSL)
- {
-#ifdef USE_SSL
- ssl_socket_setup (conn);
-#elif USE_NSS
- mutt_nss_socket_setup (conn);
-#elif USE_GNUTLS
- if (mutt_gnutls_socket_setup (conn) < 0)
- {
+ else if (account->flags & M_ACCT_SSL) {
+#if defined (USE_SSL) || defined (USE_GNUTLS)
+ if (mutt_ssl_socket_setup (conn) < 0) {
mutt_socket_free (conn);
return NULL;
}
#else
mutt_error _("SSL is unavailable.");
+
mutt_sleep (2);
mutt_socket_free (conn);
return NULL;
#endif
}
- else
- {
- conn->read = raw_socket_read;
- conn->write = raw_socket_write;
- conn->open = raw_socket_open;
- conn->close = raw_socket_close;
+ else {
+ conn->conn_read = raw_socket_read;
+ conn->conn_write = raw_socket_write;
+ conn->conn_open = raw_socket_open;
+ conn->conn_close = raw_socket_close;
}
return conn;
int rc;
int save_errno;
- if (mutt_strlen (Preconnect))
- {
- dprint (2, (debugfile, "Executing preconnect: %s\n", Preconnect));
+ if (str_len (Preconnect)) {
+ debug_print (2, ("Executing preconnect: %s\n", Preconnect));
rc = mutt_system (Preconnect);
- dprint (2, (debugfile, "Preconnect result: %d\n", rc));
- if (rc)
- {
+ debug_print (2, ("Preconnect result: %d\n", rc));
+ if (rc) {
save_errno = errno;
mutt_perror (_("Preconnect command failed."));
mutt_sleep (1);
-
+
return save_errno;
}
}
}
/* socket_connect: set up to connect to a socket fd. */
-static int socket_connect (int fd, struct sockaddr* sa)
+static int socket_connect (int fd, struct sockaddr *sa)
{
int sa_size;
int save_errno;
else if (sa->sa_family == AF_INET6)
sa_size = sizeof (struct sockaddr_in6);
#endif
- else
- {
- dprint (1, (debugfile, "Unknown address family!\n"));
+ else {
+ debug_print (1, ("Unknown address family!\n"));
return -1;
}
-
+
if (ConnectTimeout > 0)
- alarm (ConnectTimeout);
+ alarm (ConnectTimeout);
mutt_allow_interrupt (1);
save_errno = 0;
- if (connect (fd, sa, sa_size) < 0)
- {
- save_errno = errno;
- dprint (2, (debugfile, "Connection failed. errno: %d...\n", errno));
- SigInt = 0; /* reset in case we caught SIGINTR while in connect() */
+ if (connect (fd, sa, sa_size) < 0) {
+ save_errno = errno;
+ debug_print (2, ("Connection failed. errno: %d...\n", errno));
+ SigInt = 0; /* reset in case we caught SIGINTR while in connect() */
}
if (ConnectTimeout > 0)
- alarm (0);
+ alarm (0);
mutt_allow_interrupt (0);
return save_errno;
}
/* socket_new_conn: allocate and initialise a new connection. */
-static CONNECTION* socket_new_conn ()
+static CONNECTION *socket_new_conn (void)
{
- CONNECTION* conn;
+ CONNECTION *conn;
- conn = (CONNECTION *) safe_calloc (1, sizeof (CONNECTION));
+ conn = (CONNECTION *) mem_calloc (1, sizeof (CONNECTION));
conn->fd = -1;
return conn;
}
-int raw_socket_close (CONNECTION *conn)
+int raw_socket_close (CONNECTION * conn)
{
return close (conn->fd);
}
-int raw_socket_read (CONNECTION* conn, char* buf, size_t len)
+int raw_socket_read (CONNECTION * conn, char *buf, size_t len)
{
int rc;
- if ((rc = read (conn->fd, buf, len)) == -1)
- {
+ if ((rc = read (conn->fd, buf, len)) == -1) {
mutt_error (_("Error talking to %s (%s)"), conn->account.host,
- strerror (errno));
+ strerror (errno));
mutt_sleep (2);
}
return rc;
}
-int raw_socket_write (CONNECTION* conn, const char* buf, size_t count)
+int raw_socket_write (CONNECTION * conn, const char *buf, size_t count)
{
int rc;
- if ((rc = write (conn->fd, buf, count)) == -1)
- {
+ if ((rc = write (conn->fd, buf, count)) == -1) {
mutt_error (_("Error talking to %s (%s)"), conn->account.host,
- strerror (errno));
+ strerror (errno));
mutt_sleep (2);
}
return rc;
}
-int raw_socket_open (CONNECTION* conn)
+int raw_socket_open (CONNECTION * conn)
{
int rc;
int fd;
char *host_idna = NULL;
-
+
#ifdef HAVE_GETADDRINFO
/* --- IPv4/6 --- */
/* "65536\0" */
char port[6];
struct addrinfo hints;
- struct addrinfo* res;
- struct addrinfo* cur;
+ struct addrinfo *res;
+ struct addrinfo *cur;
/* we accept v4 or v6 STREAM sockets */
memset (&hints, 0, sizeof (hints));
hints.ai_socktype = SOCK_STREAM;
snprintf (port, sizeof (port), "%d", conn->account.port);
-
+
# ifdef HAVE_LIBIDN
- if (idna_to_ascii_lz (conn->account.host, &host_idna, 1) != IDNA_SUCCESS)
- {
+ if (idna_to_ascii_lz (conn->account.host, &host_idna, 1) != IDNA_SUCCESS) {
mutt_error (_("Bad IDN \"%s\"."), conn->account.host);
return -1;
}
mutt_message (_("Looking up %s..."), conn->account.host);
-
+
rc = getaddrinfo (host_idna, port, &hints, &res);
# ifdef HAVE_LIBIDN
- FREE (&host_idna);
+ mem_free (&host_idna);
# endif
- if (rc)
- {
+ if (rc) {
mutt_error (_("Could not find the host \"%s\""), conn->account.host);
+ mutt_sleep (2);
return -1;
}
- mutt_message (_("Connecting to %s..."), conn->account.host);
+ mutt_message (_("Connecting to %s..."), conn->account.host);
rc = -1;
- for (cur = res; cur != NULL; cur = cur->ai_next)
- {
+ for (cur = res; cur != NULL; cur = cur->ai_next) {
fd = socket (cur->ai_family, cur->ai_socktype, cur->ai_protocol);
- if (fd >= 0)
- {
- if ((rc = socket_connect (fd, cur->ai_addr)) == 0)
- {
- fcntl (fd, F_SETFD, FD_CLOEXEC);
- conn->fd = fd;
- break;
+ if (fd >= 0) {
+ if ((rc = socket_connect (fd, cur->ai_addr)) == 0) {
+ fcntl (fd, F_SETFD, FD_CLOEXEC);
+ conn->fd = fd;
+ break;
}
else
- close (fd);
+ close (fd);
}
}
/* --- IPv4 only --- */
struct sockaddr_in sin;
- struct hostent* he;
+ struct hostent *he;
int i;
memset (&sin, 0, sizeof (sin));
sin.sin_family = AF_INET;
# ifdef HAVE_LIBIDN
- if (idna_to_ascii_lz (conn->account.host, &host_idna, 1) != IDNA_SUCCESS)
- {
+ if (idna_to_ascii_lz (conn->account.host, &host_idna, 1) != IDNA_SUCCESS) {
mutt_error (_("Bad IDN \"%s\"."), conn->account.host);
return -1;
}
mutt_message (_("Looking up %s..."), conn->account.host);
- if ((he = gethostbyname (host_idna)) == NULL)
- {
+ if ((he = gethostbyname (host_idna)) == NULL) {
# ifdef HAVE_LIBIDN
- FREE (&host_idna);
+ mem_free (&host_idna);
# endif
mutt_error (_("Could not find the host \"%s\""), conn->account.host);
-
+
return -1;
}
# ifdef HAVE_LIBIDN
- FREE (&host_idna);
+ mem_free (&host_idna);
# endif
- mutt_message (_("Connecting to %s..."), conn->account.host);
+ mutt_message (_("Connecting to %s..."), conn->account.host);
rc = -1;
- for (i = 0; he->h_addr_list[i] != NULL; i++)
- {
+ for (i = 0; he->h_addr_list[i] != NULL; i++) {
memcpy (&sin.sin_addr, he->h_addr_list[i], he->h_length);
fd = socket (PF_INET, SOCK_STREAM, IPPROTO_IP);
- if (fd >= 0)
- {
- if ((rc = socket_connect (fd, (struct sockaddr*) &sin)) == 0)
- {
- conn->fd = fd;
- break;
+ if (fd >= 0) {
+ if ((rc = socket_connect (fd, (struct sockaddr *) &sin)) == 0) {
+ conn->fd = fd;
+ break;
}
else
- close (fd);
+ close (fd);
}
}
#endif
- if (rc)
- {
+ if (rc) {
mutt_error (_("Could not connect to %s (%s)."), conn->account.host,
- (rc > 0) ? strerror (rc) : _("unknown error"));
+ (rc > 0) ? strerror (rc) : _("unknown error"));
mutt_sleep (2);
return -1;
}
-
+
return 0;
}