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