mutt stable branch with some hacks
1/*
2 * Copyright (C) 2000 Manoj Kasichainula <manoj@io.com>
3 * Copyright (C) 2001,2005 Brendan Cully <brendan@kublai.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 */
19
20#if HAVE_CONFIG_H
21# include "config.h"
22#endif
23
24#include "mutt.h"
25#include "mutt_socket.h"
26#include "mutt_tunnel.h"
27
28#include <netinet/in.h>
29#include <sys/types.h>
30#include <sys/socket.h>
31#include <sys/wait.h>
32#include <fcntl.h>
33#include <errno.h>
34
35/* -- data types -- */
36typedef struct
37{
38 pid_t pid;
39 int readfd;
40 int writefd;
41} TUNNEL_DATA;
42
43/* forward declarations */
44static int tunnel_socket_open (CONNECTION*);
45static int tunnel_socket_close (CONNECTION*);
46static int tunnel_socket_read (CONNECTION* conn, char* buf, size_t len);
47static int tunnel_socket_write (CONNECTION* conn, const char* buf, size_t len);
48static int tunnel_socket_poll (CONNECTION* conn);
49
50/* -- public functions -- */
51int mutt_tunnel_socket_setup (CONNECTION *conn)
52{
53 conn->conn_open = tunnel_socket_open;
54 conn->conn_close = tunnel_socket_close;
55 conn->conn_read = tunnel_socket_read;
56 conn->conn_write = tunnel_socket_write;
57 conn->conn_poll = tunnel_socket_poll;
58
59 return 0;
60}
61
62static int tunnel_socket_open (CONNECTION *conn)
63{
64 TUNNEL_DATA* tunnel;
65 int pid;
66 int rc;
67 int pin[2], pout[2];
68 int devnull;
69
70 tunnel = (TUNNEL_DATA*) safe_malloc (sizeof (TUNNEL_DATA));
71 conn->sockdata = tunnel;
72
73 mutt_message (_("Connecting with \"%s\"..."), Tunnel);
74
75 if ((rc = pipe (pin)) == -1)
76 {
77 mutt_perror ("pipe");
78 FREE (&conn->sockdata);
79 return -1;
80 }
81 if ((rc = pipe (pout)) == -1)
82 {
83 mutt_perror ("pipe");
84 close (pin[0]);
85 close (pin[1]);
86 FREE (&conn->sockdata);
87 return -1;
88 }
89
90 mutt_block_signals_system ();
91 if ((pid = fork ()) == 0)
92 {
93 mutt_unblock_signals_system (0);
94 devnull = open ("/dev/null", O_RDWR);
95 if (devnull < 0 ||
96 dup2 (pout[0], STDIN_FILENO) < 0 ||
97 dup2 (pin[1], STDOUT_FILENO) < 0 ||
98 dup2 (devnull, STDERR_FILENO) < 0)
99 _exit (127);
100 close (pin[0]);
101 close (pin[1]);
102 close (pout[0]);
103 close (pout[1]);
104 close (devnull);
105
106 /* Don't let the subprocess think it can use the controlling tty */
107 setsid ();
108
109 execl (EXECSHELL, "sh", "-c", Tunnel, NULL);
110 _exit (127);
111 }
112 mutt_unblock_signals_system (1);
113
114 if (pid == -1)
115 {
116 mutt_perror ("fork");
117 close (pin[0]);
118 close (pin[1]);
119 close (pout[0]);
120 close (pout[1]);
121 FREE (&conn->sockdata);
122 return -1;
123 }
124 if (close (pin[1]) < 0 || close (pout[0]) < 0)
125 mutt_perror ("close");
126
127 fcntl (pin[0], F_SETFD, FD_CLOEXEC);
128 fcntl (pout[1], F_SETFD, FD_CLOEXEC);
129
130 tunnel->readfd = pin[0];
131 tunnel->writefd = pout[1];
132 tunnel->pid = pid;
133
134 conn->fd = 42; /* stupid hack */
135
136 return 0;
137}
138
139static int tunnel_socket_close (CONNECTION* conn)
140{
141 TUNNEL_DATA* tunnel = (TUNNEL_DATA*) conn->sockdata;
142 int status;
143
144 close (tunnel->readfd);
145 close (tunnel->writefd);
146 waitpid (tunnel->pid, &status, 0);
147 if (!WIFEXITED(status) || WEXITSTATUS(status))
148 {
149 mutt_error(_("Tunnel to %s returned error %d (%s)"), conn->account.host,
150 WEXITSTATUS(status),
151 NONULL(mutt_strsysexit(WEXITSTATUS(status))));
152 mutt_sleep (2);
153 }
154 FREE (&conn->sockdata);
155
156 return 0;
157}
158
159static int tunnel_socket_read (CONNECTION* conn, char* buf, size_t len)
160{
161 TUNNEL_DATA* tunnel = (TUNNEL_DATA*) conn->sockdata;
162 int rc;
163
164 rc = read (tunnel->readfd, buf, len);
165 if (rc == -1)
166 {
167 mutt_error (_("Tunnel error talking to %s: %s"), conn->account.host,
168 strerror (errno));
169 mutt_sleep (1);
170 }
171
172 return rc;
173}
174
175static int tunnel_socket_write (CONNECTION* conn, const char* buf, size_t len)
176{
177 TUNNEL_DATA* tunnel = (TUNNEL_DATA*) conn->sockdata;
178 int rc;
179
180 rc = write (tunnel->writefd, buf, len);
181 if (rc == -1)
182 {
183 mutt_error (_("Tunnel error talking to %s: %s"), conn->account.host,
184 strerror (errno));
185 mutt_sleep (1);
186 }
187
188 return rc;
189}
190
191static int tunnel_socket_poll (CONNECTION* conn)
192{
193 TUNNEL_DATA* tunnel = (TUNNEL_DATA*) conn->sockdata;
194 int ofd;
195 int rc;
196
197 ofd = conn->fd;
198 conn->fd = tunnel->readfd;
199 rc = raw_socket_poll (conn);
200 conn->fd = ofd;
201
202 return rc;
203}