Andreas Krennmair:
[apps/madmutt.git] / mutt_tunnel.c
1 /*
2  * Copyright (C) 2000 Manoj Kasichainula <manoj@io.com>
3  * Copyright (C) 2001 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., 59 Temple Place - Suite 330, Boston, MA  02111, 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   pid_t pid;
38   int readfd;
39   int writefd;
40 } TUNNEL_DATA;
41
42 /* forward declarations */
43 static int tunnel_socket_open (CONNECTION *);
44 static int tunnel_socket_close (CONNECTION *);
45 static int tunnel_socket_read (CONNECTION * conn, char *buf, size_t len);
46 static int tunnel_socket_write (CONNECTION * conn, const char *buf,
47                                 size_t len);
48
49 /* -- public functions -- */
50 int mutt_tunnel_socket_setup (CONNECTION * conn)
51 {
52   conn->conn_open = tunnel_socket_open;
53   conn->conn_close = tunnel_socket_close;
54   conn->conn_read = tunnel_socket_read;
55   conn->conn_write = tunnel_socket_write;
56
57   return 0;
58 }
59
60 static int tunnel_socket_open (CONNECTION * conn)
61 {
62   TUNNEL_DATA *tunnel;
63   int pid;
64   int rc;
65   int pin[2], pout[2];
66
67   tunnel = (TUNNEL_DATA *) safe_malloc (sizeof (TUNNEL_DATA));
68   conn->sockdata = tunnel;
69
70   mutt_message (_("Connecting with \"%s\"..."), Tunnel);
71
72   if ((rc = pipe (pin)) == -1) {
73     mutt_perror ("pipe");
74     return -1;
75   }
76   if ((rc = pipe (pout)) == -1) {
77     mutt_perror ("pipe");
78     return -1;
79   }
80
81   mutt_block_signals_system ();
82   if ((pid = fork ()) == 0) {
83     mutt_unblock_signals_system (0);
84     if (dup2 (pout[0], STDIN_FILENO) < 0 || dup2 (pin[1], STDOUT_FILENO) < 0)
85       _exit (127);
86     close (pin[0]);
87     close (pin[1]);
88     close (pout[0]);
89     close (pout[1]);
90     close (STDERR_FILENO);
91
92     /* Don't let the subprocess think it can use the controlling tty */
93     setsid ();
94
95     execl (EXECSHELL, "sh", "-c", Tunnel, NULL);
96     _exit (127);
97   }
98   mutt_unblock_signals_system (1);
99
100   if (pid == -1) {
101     close (pin[0]);
102     close (pin[1]);
103     close (pout[0]);
104     close (pout[1]);
105     mutt_perror ("fork");
106     return -1;
107   }
108   if (close (pin[1]) < 0 || close (pout[0]) < 0)
109     mutt_perror ("close");
110
111   fcntl (pin[0], F_SETFD, FD_CLOEXEC);
112   fcntl (pout[1], F_SETFD, FD_CLOEXEC);
113
114   tunnel->readfd = pin[0];
115   tunnel->writefd = pout[1];
116   tunnel->pid = pid;
117
118   conn->fd = 42;                /* stupid hack */
119
120   return 0;
121 }
122
123 static int tunnel_socket_close (CONNECTION * conn)
124 {
125   TUNNEL_DATA *tunnel = (TUNNEL_DATA *) conn->sockdata;
126
127   close (tunnel->readfd);
128   close (tunnel->writefd);
129   waitpid (tunnel->pid, NULL, 0);
130   FREE (&conn->sockdata);
131
132   return 0;
133 }
134
135 static int tunnel_socket_read (CONNECTION * conn, char *buf, size_t len)
136 {
137   TUNNEL_DATA *tunnel = (TUNNEL_DATA *) conn->sockdata;
138   int rc;
139
140   rc = read (tunnel->readfd, buf, len);
141   if (rc == -1) {
142     mutt_error (_("Tunnel error talking to %s: %s"), conn->account.host,
143                 strerror (errno));
144     mutt_sleep (1);
145   }
146
147   return rc;
148 }
149
150 static int tunnel_socket_write (CONNECTION * conn, const char *buf,
151                                 size_t len)
152 {
153   TUNNEL_DATA *tunnel = (TUNNEL_DATA *) conn->sockdata;
154   int rc;
155
156   rc = write (tunnel->writefd, buf, len);
157   if (rc == -1) {
158     mutt_error (_("Tunnel error talking to %s: %s"), conn->account.host,
159                 strerror (errno));
160     mutt_sleep (1);
161   }
162
163   return rc;
164 }