]> git.llucax.com Git - software/mutt-debian.git/blob - mutt_tunnel.c
staging the nntp patch which is not applying cleanly at the moment
[software/mutt-debian.git] / mutt_tunnel.c
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 -- */
36 typedef struct
37 {
38   pid_t pid;
39   int readfd;
40   int writefd;
41 } TUNNEL_DATA;
42
43 /* forward declarations */
44 static int tunnel_socket_open (CONNECTION*);
45 static int tunnel_socket_close (CONNECTION*);
46 static int tunnel_socket_read (CONNECTION* conn, char* buf, size_t len);
47 static int tunnel_socket_write (CONNECTION* conn, const char* buf, size_t len);
48 static int tunnel_socket_poll (CONNECTION* conn);
49
50 /* -- public functions -- */
51 int 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
62 static int tunnel_socket_open (CONNECTION *conn)
63 {
64   TUNNEL_DATA* tunnel;
65   int pid;
66   int rc;
67   int pin[2], pout[2];
68
69   tunnel = (TUNNEL_DATA*) safe_malloc (sizeof (TUNNEL_DATA));
70   conn->sockdata = tunnel;
71
72   mutt_message (_("Connecting with \"%s\"..."), Tunnel);
73
74   if ((rc = pipe (pin)) == -1)
75   {
76     mutt_perror ("pipe");
77     return -1;
78   }
79   if ((rc = pipe (pout)) == -1)
80   {
81     mutt_perror ("pipe");
82     return -1;
83   }
84
85   mutt_block_signals_system ();
86   if ((pid = fork ()) == 0)
87   {
88     mutt_unblock_signals_system (0);
89     if (dup2 (pout[0], STDIN_FILENO) < 0 || dup2 (pin[1], STDOUT_FILENO) < 0)
90       _exit (127);
91     close (pin[0]);
92     close (pin[1]);
93     close (pout[0]);
94     close (pout[1]);
95     close (STDERR_FILENO);
96
97     /* Don't let the subprocess think it can use the controlling tty */
98     setsid ();
99
100     execl (EXECSHELL, "sh", "-c", Tunnel, NULL);
101     _exit (127);
102   }
103   mutt_unblock_signals_system (1);
104
105   if (pid == -1)
106   {
107     close (pin[0]);
108     close (pin[1]);
109     close (pout[0]);
110     close (pout[1]);
111     mutt_perror ("fork");
112     return -1;
113   }
114   if (close (pin[1]) < 0 || close (pout[0]) < 0)
115     mutt_perror ("close");
116
117   fcntl (pin[0], F_SETFD, FD_CLOEXEC);
118   fcntl (pout[1], F_SETFD, FD_CLOEXEC);
119
120   tunnel->readfd = pin[0];
121   tunnel->writefd = pout[1];
122   tunnel->pid = pid;
123
124   conn->fd = 42; /* stupid hack */
125
126   return 0;
127 }
128
129 static int tunnel_socket_close (CONNECTION* conn)
130 {
131   TUNNEL_DATA* tunnel = (TUNNEL_DATA*) conn->sockdata;
132   int status;
133
134   close (tunnel->readfd);
135   close (tunnel->writefd);
136   waitpid (tunnel->pid, &status, 0);
137   if (!WIFEXITED(status) || WEXITSTATUS(status))
138   {
139     mutt_error(_("Tunnel to %s returned error %d (%s)"), conn->account.host,
140                WEXITSTATUS(status),
141                NONULL(mutt_strsysexit(WEXITSTATUS(status))));
142     mutt_sleep (2);
143   }
144   FREE (&conn->sockdata);
145
146   return 0;
147 }
148
149 static int tunnel_socket_read (CONNECTION* conn, char* buf, size_t len)
150 {
151   TUNNEL_DATA* tunnel = (TUNNEL_DATA*) conn->sockdata;
152   int rc;
153
154   rc = read (tunnel->readfd, buf, len);
155   if (rc == -1)
156   {
157     mutt_error (_("Tunnel error talking to %s: %s"), conn->account.host,
158                 strerror (errno));
159     mutt_sleep (1);
160   }
161
162   return rc;
163 }
164
165 static int tunnel_socket_write (CONNECTION* conn, const char* buf, size_t len)
166 {
167   TUNNEL_DATA* tunnel = (TUNNEL_DATA*) conn->sockdata;
168   int rc;
169
170   rc = write (tunnel->writefd, buf, len);
171   if (rc == -1)
172   {
173     mutt_error (_("Tunnel error talking to %s: %s"), conn->account.host,
174                 strerror (errno));
175     mutt_sleep (1);
176   }
177
178   return rc;
179 }
180
181 static int tunnel_socket_poll (CONNECTION* conn)
182 {
183   TUNNEL_DATA* tunnel = (TUNNEL_DATA*) conn->sockdata;
184   int ofd;
185   int rc;
186
187   ofd = conn->fd;
188   conn->fd = tunnel->readfd;
189   rc = raw_socket_poll (conn);
190   conn->fd = ofd;
191
192   return rc;
193 }