Nico Golde:
[apps/madmutt.git] / mutt_tunnel.c
1 /*
2  * Copyright notice from original mutt:
3  * Copyright (C) 2000 Manoj Kasichainula <manoj@io.com>
4  * Copyright (C) 2001 Brendan Cully <brendan@kublai.com>
5  *
6  * This file is part of mutt-ng, see http://www.muttng.org/.
7  * It's licensed under the GNU General Public License,
8  * please see the file GPL in the top level source directory.
9  */
10
11 #if HAVE_CONFIG_H
12 # include "config.h"
13 #endif
14
15 #include "mutt.h"
16 #include "mutt_socket.h"
17 #include "mutt_tunnel.h"
18
19 #include "lib/mem.h"
20 #include "lib/intl.h"
21 #include "lib/str.h"
22
23 #include <netinet/in.h>
24 #include <sys/types.h>
25 #include <sys/socket.h>
26 #include <sys/wait.h>
27 #include <fcntl.h>
28 #include <errno.h>
29
30 /* -- data types -- */
31 typedef struct {
32   pid_t pid;
33   int readfd;
34   int writefd;
35 } TUNNEL_DATA;
36
37 /* forward declarations */
38 static int tunnel_socket_open (CONNECTION *);
39 static int tunnel_socket_close (CONNECTION *);
40 static int tunnel_socket_read (CONNECTION * conn, char *buf, size_t len);
41 static int tunnel_socket_write (CONNECTION * conn, const char *buf,
42                                 size_t len);
43
44 /* -- public functions -- */
45 int mutt_tunnel_socket_setup (CONNECTION * conn)
46 {
47   conn->conn_open = tunnel_socket_open;
48   conn->conn_close = tunnel_socket_close;
49   conn->conn_read = tunnel_socket_read;
50   conn->conn_write = tunnel_socket_write;
51
52   return 0;
53 }
54
55 static int tunnel_socket_open (CONNECTION * conn)
56 {
57   TUNNEL_DATA *tunnel;
58   int pid;
59   int rc;
60   int pin[2], pout[2];
61
62   tunnel = (TUNNEL_DATA *) safe_malloc (sizeof (TUNNEL_DATA));
63   conn->sockdata = tunnel;
64
65   mutt_message (_("Connecting with \"%s\"..."), Tunnel);
66
67   if ((rc = pipe (pin)) == -1) {
68     mutt_perror ("pipe");
69     return -1;
70   }
71   if ((rc = pipe (pout)) == -1) {
72     mutt_perror ("pipe");
73     return -1;
74   }
75
76   mutt_block_signals_system ();
77   if ((pid = fork ()) == 0) {
78     mutt_unblock_signals_system (0);
79     if (dup2 (pout[0], STDIN_FILENO) < 0 || dup2 (pin[1], STDOUT_FILENO) < 0)
80       _exit (127);
81     close (pin[0]);
82     close (pin[1]);
83     close (pout[0]);
84     close (pout[1]);
85     close (STDERR_FILENO);
86
87     /* Don't let the subprocess think it can use the controlling tty */
88     setsid ();
89
90     execl (EXECSHELL, "sh", "-c", Tunnel, NULL);
91     _exit (127);
92   }
93   mutt_unblock_signals_system (1);
94
95   if (pid == -1) {
96     close (pin[0]);
97     close (pin[1]);
98     close (pout[0]);
99     close (pout[1]);
100     mutt_perror ("fork");
101     return -1;
102   }
103   if (close (pin[1]) < 0 || close (pout[0]) < 0)
104     mutt_perror ("close");
105
106   fcntl (pin[0], F_SETFD, FD_CLOEXEC);
107   fcntl (pout[1], F_SETFD, FD_CLOEXEC);
108
109   tunnel->readfd = pin[0];
110   tunnel->writefd = pout[1];
111   tunnel->pid = pid;
112
113   conn->fd = 42;                /* stupid hack */
114
115   return 0;
116 }
117
118 static int tunnel_socket_close (CONNECTION * conn)
119 {
120   TUNNEL_DATA *tunnel = (TUNNEL_DATA *) conn->sockdata;
121
122   close (tunnel->readfd);
123   close (tunnel->writefd);
124   waitpid (tunnel->pid, NULL, 0);
125   FREE (&conn->sockdata);
126
127   return 0;
128 }
129
130 static int tunnel_socket_read (CONNECTION * conn, char *buf, size_t len)
131 {
132   TUNNEL_DATA *tunnel = (TUNNEL_DATA *) conn->sockdata;
133   int rc;
134
135   rc = read (tunnel->readfd, buf, len);
136   if (rc == -1) {
137     mutt_error (_("Tunnel error talking to %s: %s"), conn->account.host,
138                 strerror (errno));
139     mutt_sleep (1);
140   }
141
142   return rc;
143 }
144
145 static int tunnel_socket_write (CONNECTION * conn, const char *buf,
146                                 size_t len)
147 {
148   TUNNEL_DATA *tunnel = (TUNNEL_DATA *) conn->sockdata;
149   int rc;
150
151   rc = write (tunnel->writefd, buf, len);
152   if (rc == -1) {
153     mutt_error (_("Tunnel error talking to %s: %s"), conn->account.host,
154                 strerror (errno));
155     mutt_sleep (1);
156   }
157
158   return rc;
159 }