Nico Golde:
[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 {
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
49 /* -- public functions -- */
50 int mutt_tunnel_socket_setup (CONNECTION *conn)
51 {
52   conn->open = tunnel_socket_open;
53   conn->close = tunnel_socket_close;
54   conn->read = tunnel_socket_read;
55   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   {
74     mutt_perror ("pipe");
75     return -1;
76   }
77   if ((rc = pipe (pout)) == -1)
78   {
79     mutt_perror ("pipe");
80     return -1;
81   }
82
83   mutt_block_signals_system ();
84   if ((pid = fork ()) == 0)
85   {
86     mutt_unblock_signals_system (0);
87     if (dup2 (pout[0], STDIN_FILENO) < 0 || dup2 (pin[1], STDOUT_FILENO) < 0)
88       _exit (127);
89     close (pin[0]);
90     close (pin[1]);
91     close (pout[0]);
92     close (pout[1]);
93     close (STDERR_FILENO);
94
95     /* Don't let the subprocess think it can use the controlling tty */
96     setsid ();
97
98     execl (EXECSHELL, "sh", "-c", Tunnel, NULL);
99     _exit (127);
100   }
101   mutt_unblock_signals_system (1);
102
103   if (pid == -1)
104   {
105     close (pin[0]);
106     close (pin[1]);
107     close (pout[0]);
108     close (pout[1]);
109     mutt_perror ("fork");
110     return -1;
111   }
112   if (close (pin[1]) < 0 || close (pout[0]) < 0)
113     mutt_perror ("close");
114
115   fcntl (pin[0], F_SETFD, FD_CLOEXEC);
116   fcntl (pout[1], F_SETFD, FD_CLOEXEC);
117
118   tunnel->readfd = pin[0];
119   tunnel->writefd = pout[1];
120   tunnel->pid = pid;
121
122   conn->fd = 42; /* stupid hack */
123
124   return 0;
125 }
126
127 static int tunnel_socket_close (CONNECTION* conn)
128 {
129   TUNNEL_DATA* tunnel = (TUNNEL_DATA*) conn->sockdata;
130
131   close (tunnel->readfd);
132   close (tunnel->writefd);
133   waitpid (tunnel->pid, NULL, 0);
134   FREE (&conn->sockdata);
135
136   return 0;
137 }
138
139 static int tunnel_socket_read (CONNECTION* conn, char* buf, size_t len)
140 {
141   TUNNEL_DATA* tunnel = (TUNNEL_DATA*) conn->sockdata;
142   int rc;
143
144   rc = read (tunnel->readfd, buf, len);
145   if (rc == -1)
146   {
147     mutt_error (_("Tunnel error talking to %s: %s"), conn->account.host,
148                 strerror (errno));
149     mutt_sleep (1);
150   }
151
152   return rc;
153 }
154
155 static int tunnel_socket_write (CONNECTION* conn, const char* buf, size_t len)
156 {
157   TUNNEL_DATA* tunnel = (TUNNEL_DATA*) conn->sockdata;
158   int rc;
159
160   rc = write (tunnel->writefd, buf, len);
161   if (rc == -1)
162   {
163     mutt_error (_("Tunnel error talking to %s: %s"), conn->account.host,
164                 strerror (errno));
165     mutt_sleep (1);
166   }
167
168   return rc;
169 }