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 #include "mutt.h"
21 #include "mutt_socket.h"
22 #include "mutt_tunnel.h"
23
24 #include <netinet/in.h>
25 #include <sys/types.h>
26 #include <sys/socket.h>
27 #include <sys/wait.h>
28 #include <fcntl.h>
29 #include <errno.h>
30
31 /* -- data types -- */
32 typedef struct
33 {
34   pid_t pid;
35   int readfd;
36   int writefd;
37 } TUNNEL_DATA;
38
39 /* forward declarations */
40 static int tunnel_socket_open (CONNECTION*);
41 static int tunnel_socket_close (CONNECTION*);
42 static int tunnel_socket_read (CONNECTION* conn, char* buf, size_t len);
43 static int tunnel_socket_write (CONNECTION* conn, const char* buf, size_t len);
44
45 /* -- public functions -- */
46 int mutt_tunnel_socket_setup (CONNECTION *conn)
47 {
48   conn->open = tunnel_socket_open;
49   conn->close = tunnel_socket_close;
50   conn->read = tunnel_socket_read;
51   conn->write = tunnel_socket_write;
52
53   return 0;
54 }
55
56 static int tunnel_socket_open (CONNECTION *conn)
57 {
58   TUNNEL_DATA* tunnel;
59   int pid;
60   int rc;
61   int pin[2], pout[2];
62
63   tunnel = (TUNNEL_DATA*) safe_malloc (sizeof (TUNNEL_DATA));
64   conn->sockdata = tunnel;
65
66   mutt_message (_("Connecting with \"%s\"..."), Tunnel);
67
68   if ((rc = pipe (pin)) == -1)
69   {
70     mutt_perror ("pipe");
71     return -1;
72   }
73   if ((rc = pipe (pout)) == -1)
74   {
75     mutt_perror ("pipe");
76     return -1;
77   }
78
79   mutt_block_signals_system ();
80   if ((pid = fork ()) == 0)
81   {
82     mutt_unblock_signals_system (0);
83     if (dup2 (pout[0], STDIN_FILENO) < 0 || dup2 (pin[1], STDOUT_FILENO) < 0)
84       _exit (127);
85     close (pin[0]);
86     close (pin[1]);
87     close (pout[0]);
88     close (pout[1]);
89     close (STDERR_FILENO);
90
91     /* Don't let the subprocess think it can use the controlling tty */
92     setsid ();
93
94     execl (EXECSHELL, "sh", "-c", Tunnel, NULL);
95     _exit (127);
96   }
97   mutt_unblock_signals_system (1);
98
99   if (pid == -1)
100   {
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   {
143     mutt_error (_("Tunnel error talking to %s: %s"), conn->account.host,
144                 strerror (errno));
145     mutt_sleep (1);
146   }
147
148   return rc;
149 }
150
151 static int tunnel_socket_write (CONNECTION* conn, const char* buf, 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   {
159     mutt_error (_("Tunnel error talking to %s: %s"), conn->account.host,
160                 strerror (errno));
161     mutt_sleep (1);
162   }
163
164   return rc;
165 }