2 * Copyright (C) 1998,2000 Michael R. Elkins <me@mutt.org>
3 * Copyright (C) 1999-2006,2008 Brendan Cully <brendan@kublai.com>
4 * Copyright (C) 1999-2000 Tommi Komulainen <Tommi.Komulainen@iki.fi>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26 #include "mutt_socket.h"
27 #include "mutt_tunnel.h"
29 # include "mutt_ssl.h"
32 #include "mutt_idna.h"
35 #include <netinet/in.h>
39 #include <sys/types.h>
40 #ifdef HAVE_SYS_TIME_H
43 #include <sys/socket.h>
44 #ifdef HAVE_SYS_SELECT_H
45 #include <sys/select.h>
50 /* support for multiple socket connections */
51 static CONNECTION *Connections = NULL;
53 /* forward declarations */
54 static int socket_preconnect (void);
55 static int socket_connect (int fd, struct sockaddr* sa);
56 static CONNECTION* socket_new_conn (void);
59 int mutt_socket_open (CONNECTION* conn)
63 if (socket_preconnect ())
66 rc = conn->conn_open (conn);
68 dprint (2, (debugfile, "Connected to %s:%d on fd=%d\n",
69 NONULL (conn->account.host), conn->account.port, conn->fd));
74 int mutt_socket_close (CONNECTION* conn)
79 dprint (1, (debugfile, "mutt_socket_close: Attempt to close closed connection.\n"));
81 rc = conn->conn_close (conn);
89 int mutt_socket_read (CONNECTION* conn, char* buf, size_t len)
95 dprint (1, (debugfile, "mutt_socket_read: attempt to read from closed connection\n"));
99 rc = conn->conn_read (conn, buf, len);
103 mutt_error (_("Connection to %s closed"), conn->account.host);
107 mutt_socket_close (conn);
112 int mutt_socket_write_d (CONNECTION *conn, const char *buf, int len, int dbg)
117 dprint (dbg, (debugfile,"%d> %s", conn->fd, buf));
121 dprint (1, (debugfile, "mutt_socket_write: attempt to write to closed connection\n"));
126 len = mutt_strlen (buf);
130 if ((rc = conn->conn_write (conn, buf + sent, len - sent)) < 0)
132 dprint (1, (debugfile,
133 "mutt_socket_write: error writing (%s), closing socket\n",
135 mutt_socket_close (conn);
141 dprint (3, (debugfile,
142 "mutt_socket_write: short write (%d of %d bytes)\n", rc,
151 /* poll whether reads would block.
152 * Returns: >0 if there is data to read,
153 * 0 if a read would block,
154 * -1 if this connection doesn't support polling */
155 int mutt_socket_poll (CONNECTION* conn)
157 if (conn->bufpos < conn->available)
158 return conn->available - conn->bufpos;
161 return conn->conn_poll (conn);
166 /* simple read buffering to speed things up. */
167 int mutt_socket_readchar (CONNECTION *conn, char *c)
169 if (conn->bufpos >= conn->available)
172 conn->available = conn->conn_read (conn, conn->inbuf, sizeof (conn->inbuf));
175 dprint (1, (debugfile, "mutt_socket_readchar: attempt to read from closed connection.\n"));
179 if (conn->available == 0)
181 mutt_error (_("Connection to %s closed"), conn->account.host);
184 if (conn->available <= 0)
186 mutt_socket_close (conn);
190 *c = conn->inbuf[conn->bufpos];
195 int mutt_socket_readln_d (char* buf, size_t buflen, CONNECTION* conn, int dbg)
200 for (i = 0; i < buflen-1; i++)
202 if (mutt_socket_readchar (conn, &ch) != 1)
213 /* strip \r from \r\n termination */
214 if (i && buf[i-1] == '\r')
218 dprint (dbg, (debugfile, "%d< %s\n", conn->fd, buf));
220 /* number of bytes read, not strlen */
224 CONNECTION* mutt_socket_head (void)
229 /* mutt_socket_free: remove connection from connection list and free it */
230 void mutt_socket_free (CONNECTION* conn)
237 /* head is special case, doesn't need prev updated */
240 Connections = iter->next;
247 if (iter->next == conn)
250 iter->next = tmp->next;
258 /* mutt_conn_find: find a connection off the list of connections whose
259 * account matches account. If start is not null, only search for
260 * connections after the given connection (allows higher level socket code
261 * to make more fine-grained searches than account info - eg in IMAP we may
262 * wish to find a connection which is not in IMAP_SELECTED state) */
263 CONNECTION* mutt_conn_find (const CONNECTION* start, const ACCOUNT* account)
267 char hook[LONG_STRING];
269 /* account isn't actually modified, since url isn't either */
270 mutt_account_tourl ((ACCOUNT*) account, &url);
272 url_ciss_tostring (&url, hook, sizeof (hook), 0);
273 mutt_account_hook (hook);
275 conn = start ? start->next : Connections;
278 if (mutt_account_match (account, &(conn->account)))
283 conn = socket_new_conn ();
284 memcpy (&conn->account, account, sizeof (ACCOUNT));
286 conn->next = Connections;
289 if (Tunnel && *Tunnel)
290 mutt_tunnel_socket_setup (conn);
291 else if (account->flags & M_ACCT_SSL)
294 if (mutt_ssl_socket_setup (conn) < 0)
296 mutt_socket_free (conn);
300 mutt_error _("SSL is unavailable.");
302 mutt_socket_free (conn);
309 conn->conn_read = raw_socket_read;
310 conn->conn_write = raw_socket_write;
311 conn->conn_open = raw_socket_open;
312 conn->conn_close = raw_socket_close;
313 conn->conn_poll = raw_socket_poll;
319 static int socket_preconnect (void)
324 if (mutt_strlen (Preconnect))
326 dprint (2, (debugfile, "Executing preconnect: %s\n", Preconnect));
327 rc = mutt_system (Preconnect);
328 dprint (2, (debugfile, "Preconnect result: %d\n", rc));
332 mutt_perror (_("Preconnect command failed."));
342 /* socket_connect: set up to connect to a socket fd. */
343 static int socket_connect (int fd, struct sockaddr* sa)
348 if (sa->sa_family == AF_INET)
349 sa_size = sizeof (struct sockaddr_in);
350 #ifdef HAVE_GETADDRINFO
351 else if (sa->sa_family == AF_INET6)
352 sa_size = sizeof (struct sockaddr_in6);
356 dprint (1, (debugfile, "Unknown address family!\n"));
360 if (ConnectTimeout > 0)
361 alarm (ConnectTimeout);
363 mutt_allow_interrupt (1);
367 if (connect (fd, sa, sa_size) < 0)
370 dprint (2, (debugfile, "Connection failed. errno: %d...\n", errno));
371 SigInt = 0; /* reset in case we caught SIGINTR while in connect() */
374 if (ConnectTimeout > 0)
376 mutt_allow_interrupt (0);
381 /* socket_new_conn: allocate and initialise a new connection. */
382 static CONNECTION* socket_new_conn (void)
386 conn = (CONNECTION *) safe_calloc (1, sizeof (CONNECTION));
392 int raw_socket_close (CONNECTION *conn)
394 return close (conn->fd);
397 int raw_socket_read (CONNECTION* conn, char* buf, size_t len)
401 if ((rc = read (conn->fd, buf, len)) == -1)
403 mutt_error (_("Error talking to %s (%s)"), conn->account.host,
411 int raw_socket_write (CONNECTION* conn, const char* buf, size_t count)
415 if ((rc = write (conn->fd, buf, count)) == -1)
417 mutt_error (_("Error talking to %s (%s)"), conn->account.host,
425 int raw_socket_poll (CONNECTION* conn)
428 struct timeval tv = { 0, 0 };
434 FD_SET (conn->fd, &rfds);
436 return select (conn->fd + 1, &rfds, NULL, NULL, &tv);
439 int raw_socket_open (CONNECTION* conn)
444 char *host_idna = NULL;
446 #ifdef HAVE_GETADDRINFO
451 struct addrinfo hints;
452 struct addrinfo* res;
453 struct addrinfo* cur;
455 /* we accept v4 or v6 STREAM sockets */
456 memset (&hints, 0, sizeof (hints));
458 if (option (OPTUSEIPV6))
459 hints.ai_family = AF_UNSPEC;
461 hints.ai_family = AF_INET;
463 hints.ai_socktype = SOCK_STREAM;
465 snprintf (port, sizeof (port), "%d", conn->account.port);
468 if (idna_to_ascii_lz (conn->account.host, &host_idna, 1) != IDNA_SUCCESS)
470 mutt_error (_("Bad IDN \"%s\"."), conn->account.host);
474 host_idna = conn->account.host;
477 if (!option(OPTNOCURSES))
478 mutt_message (_("Looking up %s..."), conn->account.host);
480 rc = getaddrinfo (host_idna, port, &hints, &res);
488 mutt_error (_("Could not find the host \"%s\""), conn->account.host);
493 if (!option(OPTNOCURSES))
494 mutt_message (_("Connecting to %s..."), conn->account.host);
497 for (cur = res; cur != NULL; cur = cur->ai_next)
499 fd = socket (cur->ai_family, cur->ai_socktype, cur->ai_protocol);
502 if ((rc = socket_connect (fd, cur->ai_addr)) == 0)
504 fcntl (fd, F_SETFD, FD_CLOEXEC);
516 /* --- IPv4 only --- */
518 struct sockaddr_in sin;
522 memset (&sin, 0, sizeof (sin));
523 sin.sin_port = htons (conn->account.port);
524 sin.sin_family = AF_INET;
527 if (idna_to_ascii_lz (conn->account.host, &host_idna, 1) != IDNA_SUCCESS)
529 mutt_error (_("Bad IDN \"%s\"."), conn->account.host);
533 host_idna = conn->account.host;
536 if (!option(OPTNOCURSES))
537 mutt_message (_("Looking up %s..."), conn->account.host);
539 he = gethostbyname (host_idna);
546 mutt_error (_("Could not find the host \"%s\""), conn->account.host);
551 if (!option(OPTNOCURSES))
552 mutt_message (_("Connecting to %s..."), conn->account.host);
555 for (i = 0; he->h_addr_list[i] != NULL; i++)
557 memcpy (&sin.sin_addr, he->h_addr_list[i], he->h_length);
558 fd = socket (PF_INET, SOCK_STREAM, IPPROTO_IP);
562 if ((rc = socket_connect (fd, (struct sockaddr*) &sin)) == 0)
564 fcntl (fd, F_SETFD, FD_CLOEXEC);
576 mutt_error (_("Could not connect to %s (%s)."), conn->account.host,
577 (rc > 0) ? strerror (rc) : _("unknown error"));