1 /*
2 * ircio.c: A quaint little program to make irc life PING free
3 *
4 * Written By Michael Sandrof
5 *
6 * Copyright (c) 1990 Michael Sandrof.
7 * Copyright (c) 1991, 1992 Troy Rollo.
8 * Copyright (c) 1992-2000 Matthew R. Green.
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. The name of the author may not be used to endorse or promote products
20 * derived from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34
35 #include "irc.h"
36 #include "dma.h"
37 IRCII_RCSID("@(#)$Id: ircio.c,v 2.15 2000/04/04 10:39:43 mrg Exp $");
38
39 #include "defs.h"
40
41 #include <sys/types.h>
42 #include <stdio.h>
43 #ifdef HAVE_SYS_SELECT_H
44 # include <sys/select.h>
45 #endif /* HAVE_SYS_SELECT_H */
46 #if defined(HAVE_UNISTD_H) && !defined(pyr) && !defined(_SEQUENT_)
47 # include <unistd.h>
48 #endif /* HAVE_UNISTD_H && !pyr && !_SEQUENT_ */
49 #include <sys/file.h>
50 #include <netinet/in.h>
51 #include <arpa/inet.h>
52 #include <errno.h>
53 #include <signal.h>
54 #ifdef TIME_WITH_SYS_TIME
55 # include <sys/time.h>
56 # include <time.h>
57 #else
58 # ifdef HAVE_SYS_TIME_H
59 # include <sys/time.h>
60 # else
61 # include <time.h>
62 # endif /* HAVE_SYS_TIME_H */
63 #endif /* TIME_WITH_SYS_TIME */
64
65 #include "newio.h"
66
67 /* machines we don't want to use <unistd.h> on 'cause its broken */
68 #if defined(pyr) || defined(_SEQUENT_)
69 # undef HAVE_UNISTD_H
70 #endif /* pyr || _SEQUENT_ */
71
72 #ifdef HAVE_UNISTD_H
73 # include <unistd.h>
74 #endif /* HAVE_UNISTD_H */
75
76 #ifdef HAVE_SYS_UN_H
77 #include <sys/un.h>
78 static int connect_to_unix _((char *));
79 #endif /* HAVE_SYS_UN_H */
80
81 #undef NON_BLOCKING
82
83 /*
84 void new_free _((char **));
85 char *new_malloc _((size_t));
86 */
87 static int connect_by_number _((int, char *));
88
89 /*
90 *
91 char *
92 new_malloc(size)
93 size_t size;
94 {
95 char *ptr;
96
97 if ((ptr = (char *) malloc(size)) == (char *) 0)
98 {
99 printf("-1 0\n");
100 exit(1);
101 }
102 return (ptr);
103 }
104
105 / *
106 * new_free: Why do this? Why not? Saves me a bit of trouble here and
107 * there
108 * /
109 void
110 new_free(ptr)
111 char **ptr;
112 {
113 if (*ptr)
114 {
115 free(*ptr);
116 *ptr = 0;
117 }
118 }
119 *
120 */
121
122 /*
123 * Connect_By_Number Performs a connecting to socket 'service' on host
124 * 'host'. Host can be a hostname or ip-address. If 'host' is null, the
125 * local host is assumed. The parameter full_hostname will, on return,
126 * contain the expanded hostname (if possible). Note that full_hostname is a
127 * pointer to a char *, and is allocated by connect_by_numbers()
128 *
129 * Errors:
130 *
131 * -1 get service failed
132 *
133 * -2 get host failed
134 *
135 * -3 socket call failed
136 *
137 * -4 connect call failed
138 */
139 static int
connect_by_number(service,host)140 connect_by_number(service, host)
141 int service;
142 char *host;
143 {
144 int s;
145 char buf[100];
146 struct sockaddr_in server;
147 struct hostent *hp;
148
149 if (host == (char *) 0)
150 {
151 gethostname(buf, sizeof(buf));
152 host = buf;
153 }
154 if ((server.sin_addr.s_addr = inet_addr(host)) == -1)
155 {
156 if ((hp = gethostbyname(host)) != NULL)
157 {
158 bzero((char *) &server, sizeof(server));
159 bcopy(hp->h_addr, (char *) &server.sin_addr,
160 (size_t)hp->h_length);
161 server.sin_family = hp->h_addrtype;
162 }
163 else
164 return (-2);
165 }
166 else
167 server.sin_family = AF_INET;
168 server.sin_port = (unsigned short) htons(service);
169 if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0)
170 return (-3);
171 set_socket_options(s);
172 if (connect(s, (struct sockaddr *) &server, sizeof(server)) < 0)
173 {
174 new_close(s);
175 return (-4);
176 }
177 return (s);
178 }
179
180 /*
181 * ircio: This little program connects to the server (given as arg 1) on
182 * the given port (given as arg 2). It then accepts input from stdin and
183 * sends it to that server. Likewise, it reads stuff sent from the server and
184 * sends it to stdout. Simple? Yes, it is. But wait! There's more! It
185 * also intercepts server PINGs and automatically responds to them. This
186 * frees up the process that starts ircio (such as IRCII) to pause without
187 * fear of being pooted off the net.
188 *
189 * Future enhancements: No-blocking io. It will either discard or dynamically
190 * buffer anything that would block.
191 */
192 int
main(argc,argv)193 main(argc, argv)
194 int argc;
195 char **argv;
196 {
197 int des;
198 fd_set rd;
199 int done = 0,
200 c;
201 char *ptr,
202 lbuf[BUFSIZ + 1],
203 pong[BUFSIZ + 1];
204 #ifdef NON_BLOCKING
205 char block_buffer[BUFSIZ + 1];
206 fd_set *wd_ptr = (fd_set *) 0,
207 wd;
208 int wrote;
209 #endif /* NON_BLOCKING */
210
211 if (argc < 3)
212 exit(1);
213 #ifdef SOCKS
214 SOCKSinit(*argv);
215 #endif /* SOCKS */
216 #ifdef HAVE_SYS_UN_H
217 if (*argv[1] == '/')
218 des = connect_to_unix(argv[1]);
219 else
220 #endif /* HAVE_SYS_UN_H */
221 des = connect_by_number(atoi(argv[2]), argv[1]);
222 if (des < 0)
223 exit(des);
224 fflush(stdout);
225
226 (void) MY_SIGNAL(SIGTERM, (sigfunc *) SIG_IGN, 0);
227 (void) MY_SIGNAL(SIGSEGV, (sigfunc *) SIG_IGN, 0);
228 (void) MY_SIGNAL(SIGPIPE, (sigfunc *) SIG_IGN, 0);
229 #ifdef SIGWINCH
230 (void) MY_SIGNAL(SIGWINCH, (sigfunc *) SIG_IGN, 0);
231 #endif /* SIGWINCH */
232 #ifdef SIGBUS
233 (void) MY_SIGNAL(SIGBUS, (sigfunc *) SIG_IGN, 0);
234 #endif /* SIGBUS */
235 #ifdef NON_BLOCKING
236 if (fcntl(1, F_SETFL, FNDELAY))
237 exit(1);
238 #endif /* NON_BLOCKING */
239 while (!done)
240 {
241 fflush(stderr);
242 FD_ZERO(&rd);
243 FD_SET(0, &rd);
244 FD_SET(des, &rd);
245 #ifdef NON_BLOCKING
246 if (wd_ptr)
247 {
248 FD_ZERO(wd_ptr);
249 FD_SET(1, wd_ptr);
250 }
251 switch (new_select(&rd, wd_ptr, NULL))
252 {
253 #else
254 switch (new_select(&rd, (fd_set *) 0, NULL))
255 {
256 #endif /* NON_BLOCKING */
257 case -1:
258 case 0:
259 break;
260 default:
261 #ifdef NON_BLOCKING
262 if (wd_ptr)
263 {
264 if (FD_ISSET(1, wd_ptr))
265 {
266 c = strlen(block_buffer);
267 if ((wrote = write(1, block_buffer,
268 c)) == -1)
269 {
270 wd_ptr = &wd;
271 }
272 else if (wrote < c)
273 {
274 strcpy(block_buffer,
275 &(block_buffer[wrote]));
276 wd_ptr = &wd;
277 }
278 else
279 wd_ptr = (fd_set *) 0;
280 }
281 }
282 #endif /* NON_BLOCKING */
283 if (FD_ISSET(0, &rd))
284 {
285 if (0 != (c = dgets(UP(lbuf), BUFSIZ, 0,
286 (u_char *) 0)))
287 write(des, lbuf, (size_t)c);
288 else
289 done = 1;
290 }
291 if (FD_ISSET(des, &rd))
292 {
293 if (0 != (c = dgets(UP(lbuf), BUFSIZ, des,
294 (u_char *) 0)))
295 {
296 if (strncmp(lbuf, "PING ", 5) == 0)
297 {
298 if ((ptr = (char *)
299 index(lbuf, ' ')) != NULL)
300 {
301 sprintf(pong, "PONG user@host %s\n", ptr + 1);
302 write(des, pong, strlen(pong));
303 }
304 }
305 else
306 {
307 #ifdef NON_BLOCKING
308 if ((wrote = write(1, lbuf,
309 (size_t)c)) == -1)
310 wd_ptr = &wd;
311 else if (wrote < c)
312 {
313 strcpy(block_buffer,
314 &(lbuf[wrote]));
315 wd_ptr = &wd;
316 }
317 #else
318 write(1, lbuf, (size_t)c);
319 #endif /* NON_BLOCKING */
320 }
321 }
322 else
323 done = 1;
324 }
325 }
326 }
327 return 0;
328 }
329
330
331 #ifdef HAVE_SYS_UN_H
332 /*
333 * Connect to a UNIX domain socket. Only works for servers.
334 * submitted by Avalon for use with server 2.7.2 and beyond.
335 */
336 static int
connect_to_unix(path)337 connect_to_unix(path)
338 char *path;
339 {
340 struct sockaddr_un un;
341 int sock;
342
343 sock = socket(AF_UNIX, SOCK_STREAM, 0);
344
345 un.sun_family = AF_UNIX;
346 strcpy(un.sun_path, path);
347 if (connect(sock, (struct sockaddr *)&un, (int)strlen(path)+2) == -1)
348 {
349 new_close(sock);
350 return -1;
351 }
352 return sock;
353 }
354 #endif /* HAVE_SYS_UN_H */
355