1 /*
2  * ircII: a new irc client.  I like it.  I hope you will too!
3  *
4  * Written By Michael Sandrof
5  *
6  * Copyright (c) 1990 Michael Sandrof.
7  * Copyright (c) 1991, 1992 Troy Rollo.
8  * Copyright (c) 1992-2021 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 #define IRCII_VERSION	"20210314"	/* YYYYMMDD */
36 
37 #include "irc.h"
38 IRCII_RCSID("@(#)$eterna: irc.c,v 1.416 2021/03/14 18:22:31 mrg Exp $");
39 
40 #include <sys/stat.h>
41 #include <pwd.h>
42 
43 #ifdef DO_USER2
44 # include <setjmp.h>
45 #endif /* DO_USER2 */
46 
47 #include "status.h"
48 #include "dcc.h"
49 #include "names.h"
50 #include "vars.h"
51 #include "input.h"
52 #include "alias.h"
53 #include "output.h"
54 #include "ircterm.h"
55 #include "exec.h"
56 #include "screen.h"
57 #include "log.h"
58 #include "server.h"
59 #include "hook.h"
60 #include "keys.h"
61 #include "ircaux.h"
62 #include "edit.h"
63 #include "window.h"
64 #include "history.h"
65 #include "exec.h"
66 #include "notify.h"
67 #include "mail.h"
68 #include "debug.h"
69 #include "newio.h"
70 #include "ctcp.h"
71 #include "parse.h"
72 #include "strsep.h"
73 #include "notice.h"
74 #include "icb.h"
75 #include "signals.h"
76 
77 static	int	qflag;			/* set if we ignore .ircrc */
78 static	int	bflag;			/* set if we load .ircrc before connecting */
79 static	int	tflag = 1;		/* don't use termcap ti/te sequences */
80 static	time_t	current_idle_time;	/* last time the user hit a key */
81 static	time_t  start_time;		/* epoch time we started */
82 
83 static	int	cntl_c_hit = 0,
84 		irc_port_local = IRC_PORT,	/* port of ircd */
85 		add_servers = 0,		/* -a flag */
86 		do_refresh_screen,
87 		no_full_screen = 0,
88 		cur_signal = -1,		/* head of below */
89 		occurred_signals[64],		/* got signal which may
90 						   require /ON action */
91 		client_default_icb = 0,		/* default to irc server
92 						   connections */
93 		fflag = USE_FLOW_CONTROL,	/* true: ^Q/^S used for flow
94 						   cntl */
95 		using_server_process = 0;	/* Don't want to start ircio
96 						   by default... */
97 
98 static	u_char	*irc_path,			/* paths used by /load */
99 		*ircrc_file,			/* full path .ircrc file */
100 		*ircquick_file,			/* full path .ircquick file */
101 		*progname,			/* set from argv[0] */
102 		*send_umode,			/* sent umode */
103 		*args_str,			/* list of command line args */
104 		hostname[NAME_LEN + 1],		/* name of current host */
105 		realname[REALNAME_LEN + 1],	/* real name of user */
106 		username[NAME_LEN + 1],		/* usernameof user */
107 		*nickname,			/* users nickname */
108 		*source_host,			/* specify a specific source
109 						   host for multi-homed
110 						   machines */
111 		*irc_lib,			/* path to the ircII library */
112 		*my_path_dir,			/* path to users home dir */
113 		*log_file,			/* path to debug log file */
114 		*default_proxy,			/* default proxy to use */
115 		irc_version_str[] = IRCII_VERSION;
116 
117 #ifdef DO_USER2
118 static	jmp_buf	outta_here;
119 #endif /* DO_USER2 */
120 
121 static	void	cntl_c(int);
122 static	void	sig_user1(int);
123 static	void	sig_refresh_screen(int);
124 static	void	sig_on(int);
125 static	void	real_sig_user1(void);
126 static	int	do_sig_user1;
127 #ifdef	DO_USER2
128 static	void	sig_user2(int) ;
129 #endif /* DO_USER2 */
130 static	int	irc_do_a_screen(Screen *, fd_set *);
131 static	void	irc_io(void);
132 static	void	quit_response(u_char *, u_char *);
133 static	void	show_version(void);
134 static	u_char	*get_arg(u_char *, u_char *, int *);
135 static	int	parse_arg(u_char *, u_char **, int *, u_char **);
136 static	u_char	*parse_args(u_char **, int);
137 static	void	input_pause(void);
138 
139 #ifdef DEBUG
140 #define DEBUG_USAGE1 \
141 "\
142    -D <level>\tenable debugging at the specified level\n"
143 #define DEBUG_USAGE2 \
144 "\
145    -o <file>\twrite debug output to file\n"
146 #else
147 #define DEBUG_USAGE1 ""
148 #define DEBUG_USAGE2 ""
149 #endif
150 
151 static	char	switch_help[] =
152 "Usage: irc [switches] [nickname] [server list] \n\
153   The [nickname] can be at most 9 characters long on some server\n\
154   The [server list] is a whitespace separated list of server names\n\
155   The [switches] may be any or all of the following:\n\
156    -a\t\tadds default servers and command line servers to server list\n\
157    -b\t\tload .ircrc before connecting to a server\n\
158    -c <channel>\tjoins <channel> on startup\n\
159    -d\t\truns IRCII in non full screen terminal mode\n"
160    DEBUG_USAGE1 "\
161    -f\t\tyour terminal uses flow control (^S/^Q), so IRCII shouldn't\n\
162    -F\t\tyour terminal doesn't use flow control (default)\n\
163    -h <host>\tsource host, for multihomed machines\n\
164    -H <host>\toriginating address for dcc requests (to work behind NATs etc)\n\
165    -icb\t\tuse ICB connections by default\n\
166    -irc\t\tuse IRC connections by default\n\
167    -I <file>\tloads <file> in place of your .ircquick\n\
168    -l <file>\tloads <file> in place of your .ircrc\n"
169    DEBUG_USAGE2 "\
170    -p <port>\tdefault IRC server connection port (usually 6667)\n\
171    -P <port>\tdefault ICB server connection port (usually 7326)\n\
172    -q\t\tdoes not load .ircrc nor .ircquick\n\
173    -r\t\treverse terminal colours (only if colours are activated)\n\
174    -R <host>[:<port>]\tdefault to using HTTP proxy for connections\n\
175    -s\t\tdon't use separate server processes (ircio)\n\
176    -S\t\tuse separate server processes (ircio)\n\
177    -t\t\tdo not use termcap ti and te sequences at startup\n\
178    -T\t\tuse termcap ti and te sequences at startup (default)\n\
179 Usage: icb [same switches]  (default to -icb)\n";
180 
181 /* irc_exit: cleans up and leaves */
182 void
irc_exit(void)183 irc_exit(void)
184 {
185 	do_hook(EXIT_LIST, "Exiting");
186 	close_server(-1, empty_string());
187 	logger(0);
188 	set_history_file(NULL);
189 	clean_up_processes();
190 	if (!term_basic())
191 	{
192 		cursor_to_input();	/* Needed so that ircII doesn't gobble
193 					 * the last line of the kill. */
194 		term_cr();
195 		if (term_clear_to_eol())
196 			term_space_erase(0);
197 		term_reset();
198 	}
199 	exit(0);
200 }
201 
202 /*
203  * quit_response: Used by irc_io when called from irc_quit to see if we got
204  * the right response to our question.  If the response was affirmative, the
205  * user gets booted from irc.  Otherwise, life goes on.
206  */
207 static	void
quit_response(u_char * dummy,u_char * ptr)208 quit_response(u_char *dummy, u_char *ptr)
209 {
210 	size_t	len;
211 
212 	if ((len = my_strlen(ptr)) != 0)
213 	{
214 		if (!my_strnicmp(ptr, UP("yes"), len))
215 		{
216 			send_to_server("QUIT");
217 			irc_exit();
218 		}
219 	}
220 }
221 
222 /* irc_quit: prompts the user if they wish to exit, then does the right thing */
223 void
irc_quit(u_int key,u_char * ptr)224 irc_quit(u_int key, u_char *ptr)
225 {
226 	static	int in_it = 0;
227 
228 	if (in_it)
229 		return;
230 	in_it = 1;
231 	add_wait_prompt(UP("Do you really want to quit? "), quit_response,
232 		empty_string(), WAIT_PROMPT_LINE);
233 	in_it = 0;
234 }
235 
236 void
on_signal_occurred(int signo)237 on_signal_occurred(int signo)
238 {
239 	if (cur_signal > ARRAY_SIZE(occurred_signals))
240 		return;
241 	occurred_signals[++cur_signal] = signo;
242 }
243 
244 /*
245  * cntl_c: emergency exit.... if somehow everything else freezes up, hitting
246  * ^C five times should kill the program.
247  */
248 static	void
cntl_c(int signo)249 cntl_c(int signo)
250 {
251 	on_signal_occurred(signo);
252 
253 	if (cntl_c_hit++ >= 4)
254 		irc_exit();
255 }
256 
257 static void
sig_on(int signo)258 sig_on(int signo)
259 {
260 	on_signal_occurred(signo);
261 }
262 
263 static void
sig_user1(int signo)264 sig_user1(int signo)
265 {
266 	do_sig_user1++;
267 	on_signal_occurred(signo);
268 }
269 
270 static void
real_sig_user1(void)271 real_sig_user1(void)
272 {
273 	say("Got SIGUSR1, closing DCC connections and EXECed processes");
274 	close_all_dcc();
275 	close_all_exec();
276 }
277 
278 #ifdef DO_USER2
279 static void
sig_user2(int signo)280 sig_user2(int signo)
281 {
282 	on_signal_occurred(signo);
283 	say("Got SIGUSR2, jumping to normal loop");	/* unsafe */
284 	longjmp(outta_here);
285 }
286 #endif
287 
288 static void
sig_refresh_screen(int signo)289 sig_refresh_screen(int signo)
290 {
291 	on_signal_occurred(signo);
292 	do_refresh_screen++;
293 }
294 
295 /* shows the version of irc */
296 static	void
show_version(void)297 show_version(void)
298 {
299 	printf("ircII version %s\n\r", irc_version());
300 	exit (0);
301 }
302 
303 /* get_arg: used by parse_args() to get an argument after a switch */
304 static	u_char	*
get_arg(u_char * arg,u_char * next,int * ac)305 get_arg(u_char *arg, u_char *next, int *ac)
306 {
307 	(*ac)++;
308 	if (*arg)
309 		return (arg);
310 	else
311 	{
312 		if (next)
313 			return (next);
314 		fprintf(stderr, "irc: missing parameter\n");
315 		exit(1);
316 		return (0); /* cleans up a warning */
317 	}
318 }
319 
320 /*
321  * parse_arg: parse a single command line argument.  returns 1 when
322  * a "--" sequence is detected.
323  */
324 static	int
parse_arg(u_char * arg,u_char ** argv,int * acp,u_char ** channelp)325 parse_arg(u_char *arg, u_char **argv, int *acp, u_char **channelp)
326 {
327 	while (*arg)
328 	{
329 		switch (*(arg++))
330 		{
331 		case 'a':
332 			add_servers = 1;
333 			break;
334 		case 'b':
335 			if (qflag)
336 			{
337 				fprintf(stderr, "Can not use -b with -q\n");
338 				exit(1);
339 			}
340 			bflag = 1;
341 			break;
342 		case 'c':
343 			malloc_strcpy(channelp, get_arg(arg, argv[*acp], acp));
344 			break;
345 		case 'd':
346 			no_full_screen = 1;
347 			break;
348 #ifdef DEBUG
349 		case 'D':
350 			setdlevel(get_arg(arg, argv[*acp], acp));
351 			break;
352 #endif /* DEBUG */
353 		case 'e':
354 			{
355 				u_char *proto = get_arg(arg, argv[*acp], acp);
356 				server_default_encryption(proto,
357 							  get_arg(arg,
358 							      argv[*acp], acp));
359 			}
360 			break;
361 		case 'f':
362 			fflag = 1;
363 			break;
364 		case 'F':
365 			fflag = 0;
366 			break;
367 		case 'h':
368 			malloc_strcpy(&source_host,
369 				      get_arg(arg, argv[*acp], acp));
370 			break;
371 		case 'H':
372 			set_dcchost(get_arg(arg, argv[*acp], acp));
373 			break;
374 		case 'i':
375 			if (arg[0] == 'r' && arg[1] == 'c')
376 				client_default_icb = 0;
377 			else
378 			if (arg[0] == 'c' && arg[1] == 'b')
379 				client_default_icb = 1;
380 			else
381 			{
382 				printf("irc: invalid -i option; use -irc "
383 				       "or -icb");
384 				exit(-1);
385 			}
386 			arg += 2;
387 			break;
388 		case 'I':
389 			malloc_strcpy(&ircquick_file,get_arg(arg, argv[*acp], acp));
390 			break;
391 		case 'l':
392 			malloc_strcpy(&ircrc_file, get_arg(arg, argv[*acp], acp));
393 			break;
394 #ifdef DEBUG
395 		case 'o':
396 			log_file = get_arg(arg, argv[*acp], acp);
397 			break;
398 #endif /* DEBUG */
399 		case 'p':
400 			irc_port_local = my_atoi(get_arg(arg, argv[*acp], acp));
401 			break;
402 		case 'P':
403 			set_icb_port(my_atoi(get_arg(arg, argv[*acp], acp)));
404 			break;
405 		case 'q':
406 			if (bflag)
407 			{
408 				fprintf(stderr, "Can not use -q with -b\n");
409 				exit(1);
410 			}
411 			qflag = 1;
412 			break;
413 		case 'r':
414 			{
415 				int oldfg = get_int_var(FOREGROUND_COLOUR_VAR);
416 				set_int_var(FOREGROUND_COLOUR_VAR,
417 					    get_int_var(BACKGROUND_COLOUR_VAR));
418 				set_int_var(BACKGROUND_COLOUR_VAR, oldfg);
419 			}
420 			break;
421 		case 'R':
422 			default_proxy = get_arg(arg, argv[*acp], acp);
423 			break;
424 		case 's':
425 			using_server_process = 0;
426 			break;
427 		case 'S':
428 			using_server_process = 1;
429 			break;
430 		case 't':
431 			tflag = 1;
432 			break;
433 		case 'T':
434 			tflag = 0;
435 			break;
436 		case 'v':
437 			show_version();
438 			break;
439 		case '-':
440 			return 1;
441 		default:
442 			fputs(switch_help, stderr);
443 			exit(1);
444 		}
445 	}
446 
447 	return 0;
448 }
449 
450 
451 /*
452  * parse_args: parse command line arguments for irc, and sets all initial
453  * flags, etc.
454  */
455 static	u_char	*
parse_args(u_char ** argv,int argc)456 parse_args(u_char **argv, int argc)
457 {
458 	u_char	*arg,
459 		*ptr;
460 	int	ac;
461 	u_char	*channel = NULL;
462 	struct	passwd	*entry;
463 	int	minus_minus = 0;
464 
465 	if (my_strncmp(argv[0], "icb", 3) == 0 || strstr(CP(argv[0]), "/icb") != 0)
466 		client_default_icb = 1;
467 	*realname = '\0';
468 	ac = 1;
469 	malloc_strcpy(&args_str, argv[0]);
470 	malloc_strcat(&args_str, UP(" "));
471 	while (ac < argc && (arg = argv[ac++]) != NULL)
472 	{
473 		malloc_strcat(&args_str, arg);
474 		malloc_strcat(&args_str, UP(" "));
475 		if (*arg == '-')
476 		{
477 			minus_minus = parse_arg(arg+1, argv, &ac, &channel);
478 			if (minus_minus)
479 				break;
480 		}
481 		else
482 		{
483 			if (nickname && *nickname)
484 				build_server_list(arg);
485 			else
486 				malloc_strcpy(&nickname, arg);
487 		}
488 	}
489 	if (NULL != (ptr = my_getenv("IRCLIB")))
490 	{
491 		malloc_strcpy(&irc_lib, ptr);
492 		malloc_strcat(&irc_lib, UP("/"));
493 	}
494 	else
495 		malloc_strcpy(&irc_lib, UP(IRCLIB));
496 
497 	/* -h overrides environment variable */
498 	if (NULL == source_host && NULL != (ptr = my_getenv("IRCHOST")))
499 		malloc_strcpy(&source_host, ptr);
500 
501 	if (NULL == ircrc_file && NULL != (ptr = my_getenv("IRCRC")))
502 		malloc_strcpy(&ircrc_file, ptr);
503 
504 	if (NULL == ircquick_file && NULL != (ptr = my_getenv("IRCQUICK")))
505 		malloc_strcpy(&ircquick_file, ptr);
506 
507 	if ((nickname == 0 || *nickname == '\0') && NULL != (ptr = my_getenv("IRCNICK")))
508 		malloc_strcpy(&nickname, ptr);
509 
510 	if ((ptr = my_getenv("USER")) != NULL)
511 		my_strmcpy(username, ptr, NAME_LEN);
512 
513 	if (NULL != (ptr = my_getenv("IRCUMODE")))
514 		malloc_strcpy(&send_umode, ptr);
515 
516 	if (NULL != (ptr = my_getenv("IRCNAME")))
517 		my_strmcpy(realname, ptr, REALNAME_LEN);
518 
519 	if (NULL != (ptr = my_getenv("IRCPATH")))
520 		malloc_strcpy(&irc_path, ptr);
521 	else
522 	{
523 #ifdef IRCPATH
524 		malloc_strcpy(&irc_path, UP(IRCPATH));
525 #else
526 		malloc_strcpy(&irc_path, UP(".:~/.irc:"));
527 		malloc_strcat(&irc_path, irc_lib);
528 		malloc_strcat(&irc_path, UP("script"));
529 #endif /* IRCPATH */
530 	}
531 
532 	/* now, open the log file */
533 	if (log_file)
534 		open_log_file(log_file);
535 
536 	if (default_proxy)
537 		server_set_default_proxy(default_proxy);
538 
539 	set_string_var(LOAD_PATH_VAR, irc_path);
540 	new_free(&irc_path);
541 	if (NULL != (ptr = my_getenv("IRCSERVER")))
542 		build_server_list(ptr);
543 	if (0 == number_of_servers() || add_servers)
544 	{
545 		if (read_server_file() || 0 == number_of_servers())
546 		{
547 			u_char *s = NULL;
548 
549 			malloc_strcpy(&s, UP(DEFAULT_SERVER));
550 			build_server_list(s);
551 			new_free(&s);
552 		}
553 	}
554 
555 	if (NULL != (entry = getpwuid(getuid())))
556 	{
557 		if ((*realname == '\0') && entry->pw_gecos && *(entry->pw_gecos))
558 		{
559 #ifdef GECOS_DELIMITER
560 			if ((ptr = my_index(entry->pw_gecos, GECOS_DELIMITER))
561 					!= NULL)
562 				*ptr = '\0';
563 #endif /* GECOS_DELIMITER */
564 			if ((ptr = my_index(entry->pw_gecos, '&')) == NULL)
565 				my_strmcpy(realname, entry->pw_gecos, REALNAME_LEN);
566 			else {
567 				size_t len = ptr - (u_char *) entry->pw_gecos;
568 
569 				if (len < REALNAME_LEN && *(entry->pw_name)) {
570 					u_char *q = realname + len;
571 
572 					my_strmcpy(realname, entry->pw_gecos, len);
573 					my_strmcat(realname, entry->pw_name, REALNAME_LEN);
574 					my_strmcat(realname, ptr + 1, REALNAME_LEN);
575 					if (islower(*q) && (q == realname || isspace(*(q - 1))))
576 						*q = toupper(*q);
577 				} else
578 					my_strmcpy(realname, entry->pw_gecos, REALNAME_LEN);
579 			}
580 		}
581 		if (entry->pw_name && *(entry->pw_name) && '\0' == *username)
582 			my_strmcpy(username, entry->pw_name, NAME_LEN);
583 
584 		if (entry->pw_dir && *(entry->pw_dir))
585 			malloc_strcpy(&my_path_dir, UP(entry->pw_dir));
586 	}
587 	if (NULL != (ptr = my_getenv("HOME")))
588 		malloc_strcpy(&my_path_dir, ptr);
589 	else if (*my_path_dir == '\0')
590 		malloc_strcpy(&my_path_dir, UP("/"));
591 
592 	if ('\0' == *realname)
593 		my_strmcpy(realname, "*Unknown*", REALNAME_LEN);
594 
595 	if ('\0' == *username)
596 		my_strmcpy(username, "Unknown", NAME_LEN);
597 
598 	if (NULL != (ptr = my_getenv("IRCUSER")))
599 		my_strmcpy(username, ptr, REALNAME_LEN);
600 
601 	if (nickname == 0 || *nickname == '\0')
602 		malloc_strcpy(&nickname, username);
603 	if (NULL == ircrc_file)
604 	{
605 		ircrc_file = new_malloc(my_strlen(my_path_dir) +
606 			my_strlen(IRCRC_NAME) + 1);
607 		my_strcpy(ircrc_file, my_path_dir);
608 		my_strcat(ircrc_file, IRCRC_NAME);
609 	}
610 	if (NULL == ircquick_file)
611 	{
612 		ircquick_file = new_malloc(my_strlen(my_path_dir) +
613 			my_strlen(IRCQUICK_NAME) + 1);
614 		my_strcpy(ircquick_file, my_path_dir);
615 		my_strcat(ircquick_file, IRCQUICK_NAME);
616 	}
617 
618 	return (channel);
619 }
620 
621 /*
622  * input_pause: prompt the user for a single keystroke before continuing.
623  * Only call this before calling irc_io().
624  */
625 static void
input_pause(void)626 input_pause(void)
627 {
628 	const u_char *msg = UP("********  Press any key to continue  ********");
629 	char dummy;
630 
631 	if (term_basic())
632 	{
633 		puts(CP(msg));
634 		fflush(stdout);
635 	}
636 	else
637 	{
638 		int cols;
639 
640 		copy_window_size(NULL, &cols);
641 		term_move_cursor(0, cols);
642 		output_line(msg, 0);
643 		cursor_not_in_display();
644 	}
645 	(void)read(0, &dummy, 1);
646 }
647 
648 /*
649  * generally processes one screen's input.  this used to be part of irc_io()
650  * but has been split out because that function was too large and too nested.
651  * it returns 0 if IO processing should continue and 1 if it should stop.
652  */
653 static	int
irc_do_a_screen(Screen * screen,fd_set * rd)654 irc_do_a_screen(Screen *screen, fd_set *rd)
655 {
656 	if (!screen_get_alive(screen))
657 		return 0;
658 	set_current_screen(screen);
659 	if (!is_main_screen(screen) &&
660 	    FD_ISSET(screen_get_wserv_fd(screen), rd))
661 		screen_wserv_message(screen);
662 	if (FD_ISSET(screen_get_fdin(screen), rd))
663 	{
664 		/* buffer much bigger than IRCD_BUFFER_SIZE */
665 		u_char	lbuf[BIG_BUFFER_SIZE + 1];
666 
667 		/*
668 		 * This section of code handles all in put from the terminal(s)
669 		 * connected to ircII.  Perhaps the idle time *shouldn't* be
670 		 * reset unless its not a screen-fd that was closed..
671 		 */
672 		current_idle_time = time(0);
673 		if (term_basic())
674 		{
675 			int     old_timeout;
676 
677 			old_timeout = dgets_timeout(1);
678 			switch (dgets(lbuf, INPUT_BUFFER_SIZE, screen_get_fdin(screen)))
679 			{
680 			case 0:
681 			case -1:
682 				say("IRCII exiting on EOF from stdin");
683 				irc_exit();
684 				break;
685 			default:
686 				(void) dgets_timeout(old_timeout);
687 				*(lbuf + my_strlen(lbuf) - 1) = '\0';
688 				if (get_int_var(INPUT_ALIASES_VAR))
689 					parse_line(NULL, lbuf,
690 					    empty_string(), 1, 0, 0);
691 				else
692 					parse_line(NULL, lbuf,
693 					    NULL, 1, 0, 0);
694 				break;
695 			}
696 		}
697 		else
698 		{
699 			int server;
700 			u_char	loc_buffer[BIG_BUFFER_SIZE + 1];
701 			int	n, i;
702 
703 			server = set_from_server(get_window_server(0));
704 			set_last_input_screen(screen);
705 			if ((n = read(screen_get_fdin(screen), loc_buffer,
706 					sizeof loc_buffer)) != 0)
707 				for (i = 0; i < n; i++)
708 					edit_char((u_int)loc_buffer[i]);
709 				/*
710 				 * if the current screen isn't the main  screen,
711 				 * then the socket to the current screen must have
712 				 * closed, so we call kill_screen() to handle
713 				 * this - phone, jan 1993.
714 				 * but not when we arent running windows - Fizzy, may 1993
715 				 * if it is the main screen we got an EOF on, we exit..
716 				 * closed tty -> chew cpu -> bad .. -phone, july 1993.
717 				 */
718 #ifdef WINDOW_CREATE
719 			else
720 			{
721 				if (!is_main_screen(screen))
722 					kill_screen(screen);
723 				else
724 					irc_exit();
725 			}
726 #endif /* WINDOW_CREATE */
727 			cntl_c_hit = 0;
728 			set_from_server(server);
729 		}
730 	}
731 	return 0;
732 }
733 
734 /*
735  * irc_io: the main irc input/output loop.   Handles all io from keyboard,
736  * server, exec'd processes, etc.  If a prompt is specified, it is displayed
737  * in the input line and cannot be backspaced over, etc. The func is a
738  * function which will take the place of the SEND_LINE function (which is
739  * what happens when you hit return at the end of a line). This function must
740  * decide if it's ok to exit based on anything you really want.
741  */
742 void
irc_io(void)743 irc_io(void)
744 {
745 	fd_set	rd,
746 		wd;
747 	struct	timeval cursor_timeout,
748 		clock_timeout,
749 		right_away,
750 		timer,
751 		*timeptr;
752 	int	hold_over;
753 	Screen	*screen,
754 		*old_current_screen;
755 	int	irc_io_loop = 1;
756 	int	i;
757 
758 	/* time before cursor jumps from display area to input line */
759 	cursor_timeout.tv_usec = 0L;
760 	cursor_timeout.tv_sec = 1L;
761 
762 	/* time delay for updating of internal clock */
763 	clock_timeout.tv_usec = 0L;
764 	clock_timeout.tv_sec = 30L;
765 
766 	right_away.tv_usec = 0L;
767 	right_away.tv_sec = 0L;
768 
769 	if (!term_basic())
770 		set_input_prompt(get_string_var(INPUT_PROMPT_VAR));
771 
772 #ifdef DO_USER2
773 	if (setjmp(outta_here))
774 		yell("*** Got SIGUSR2, Aborting");
775 #endif /* DO_USER2 */
776 
777 	timeptr = &clock_timeout;
778 	do
779 	{
780 		set_ctcp_was_crypted(0);
781 		FD_ZERO(&rd);
782 		FD_ZERO(&wd);
783 		set_process_bits(&rd);
784 		server_set_bits(&rd, &wd);
785 		for (screen = screen_first(); screen; screen = screen_get_next(screen))
786 			if (screen_get_alive(screen))
787 			{
788 				FD_SET(screen_get_fdin(screen), &rd);
789 				if (!is_main_screen(screen))
790 					FD_SET(screen_get_wserv_fd(screen), &rd);
791 			}
792 		set_dcc_bits(&rd, &wd);
793 		term_check_refresh();
794 		timer_timeout(&timer);
795 		if (timer.tv_sec <= timeptr->tv_sec)
796 			timeptr = &timer;
797 		if ((hold_over = unhold_windows()) != 0)
798 			timeptr = &right_away;
799 		Debug(DB_IRCIO, "irc_io: selecting with %lld:%ld timeout",
800 			(long long)timeptr->tv_sec, (long)timeptr->tv_usec);
801 		switch (new_select(&rd, &wd, timeptr))
802 		{
803 		case 0:
804 		case -1:
805 	/*
806 	 * yay for the QNX socket manager... drift here, drift there, oops,
807 	 * i fell down a hole..
808 	 */
809 #ifdef __QNX__
810 			if (errno == EBADF || errno == ESRCH)
811 				irc_io_loop = 0;
812 #endif /* __QNX__ */
813 			if (cntl_c_hit)
814 			{
815 				edit_char((u_int)'\003');
816 				cntl_c_hit = 0;
817 			}
818 			check_status_alarmed();
819 			if (do_refresh_screen)
820 			{
821 				refresh_screen(0, NULL);
822 				do_refresh_screen = 0;
823 			}
824 			if (do_sig_user1)
825 			{
826 				real_sig_user1();
827 				do_sig_user1 = 0;
828 			}
829 			for (i = 0; i <= cur_signal; i++)
830 				if (occurred_signals[i] != 0)
831 					do_hook(OS_SIGNAL_LIST, "%s",
832 					    get_signal(i, 0));
833 			cur_signal = -1;
834 			if (!hold_over)
835 				cursor_to_input();
836 			break;
837 		default:
838 			term_check_refresh();
839 			old_current_screen = get_current_screen();
840 			set_current_screen(get_last_input_screen());
841 			dcc_check(&rd, &wd);
842 			do_server(&rd, &wd);
843 			set_current_screen(old_current_screen);
844 			for (screen = screen_first(); screen;
845 			     screen = screen_get_next(screen))
846 				if (irc_do_a_screen(screen, &rd))
847 					irc_io_loop = 0;
848 			set_current_screen(old_current_screen);
849 			if (irc_io_loop)
850 				do_processes(&rd);
851 			break;
852 		}
853 		if (!irc_io_loop)
854 			break;
855 		execute_timer();
856 		check_process_limits();
857 		while (check_wait_status(-1) >= 0)
858 			;
859 		if (get_primary_server() == -1 && !never_connected())
860 			do_hook(DISCONNECT_LIST, "%s", nickname);
861 		timeptr = &clock_timeout;
862 
863 		old_current_screen = get_current_screen();
864 		for (screen = screen_first(); screen; screen = screen_get_next(screen))
865 		{
866 			set_current_screen(screen);
867 			if (screen_get_alive(screen) && is_cursor_in_display())
868 				timeptr = &cursor_timeout;
869 		}
870 		set_current_screen(old_current_screen);
871 
872 		if (update_clock(0, 0, UPDATE_TIME))
873 		{
874 			Debug(DB_IRCIO, "update_clock(0,0,0) returned true; updating clock");
875 			if (get_int_var(CLOCK_VAR) || check_mail_status())
876 			{
877 				status_update(1);
878 				cursor_to_input();
879 			}
880 			if (get_primary_server() != -1)
881 				do_notify();
882 		}
883 	}
884 	while (irc_io_loop);
885 
886 	update_input(UPDATE_ALL);
887 	return;
888 }
889 
890 int
891 main(int, char *[], char *[]);
892 
893 int
main(int argc,char * argv[],char * envp[])894 main(int argc, char *argv[], char *envp[])
895 {
896 	u_char	*channel;
897 
898 	progname = UP(argv[0]);
899 	srandom(time(NULL) ^ getpid());	/* something */
900 
901 	start_time = time(NULL);
902 #ifdef	SOCKS
903 	SOCKSinit(argv[0]);
904 #endif /* SOCKS */
905 	channel = parse_args((u_char **) argv, argc);
906 	if (gethostname(CP(hostname), NAME_LEN))
907 	{
908 		fprintf(stderr, "irc: couldn't figure out the name of your machine!\n");
909 		exit(1);
910 	}
911 	term_set_fp(stdout);
912 	if (term_basic())
913 		new_window();
914 	else
915 	{
916 		init_screen();
917 
918 #if defined(SIGCONT)
919 		(void) MY_SIGNAL(SIGCONT, (sigfunc *) term_cont, 0);
920 #endif
921 
922 #if defined(SIGWINCH)
923 		(void) MY_SIGNAL(SIGWINCH, (sigfunc *) sig_refresh_screen, 0);
924 #endif
925 
926 		(void) MY_SIGNAL(SIGSEGV, (sigfunc *) SIG_DFL, 0);
927 		(void) MY_SIGNAL(SIGBUS, (sigfunc *) SIG_DFL, 0);
928 		(void) MY_SIGNAL(SIGHUP, (sigfunc *) irc_exit, 0);
929 		(void) MY_SIGNAL(SIGTERM, (sigfunc *) irc_exit, 0);
930 		(void) MY_SIGNAL(SIGPIPE, (sigfunc *) sig_on, 0);
931 		(void) MY_SIGNAL(SIGINT, (sigfunc *) cntl_c, 0);
932 #ifdef SIGSTOP
933 		(void) MY_SIGNAL(SIGSTOP, (sigfunc *) sig_on, 0);
934 #endif /* SIGSTOP */
935 
936 		(void) MY_SIGNAL(SIGUSR1, (sigfunc *) sig_user1, 0);
937 #ifdef DO_USER2
938 		(void) MY_SIGNAL(SIGUSR2, (sigfunc *) sig_user2, 0);
939 #else
940 		(void) MY_SIGNAL(SIGUSR2, (sigfunc *) sig_on, 0);
941 #endif /* DO_USER2 */
942 
943 #ifdef SIGPWR
944 		(void) MY_SIGNAL(SIGPWR, (sigfunc *) sig_on, 0);
945 #endif
946 #ifdef SIGCHLD
947 		(void) MY_SIGNAL(SIGCHLD, (sigfunc *) sig_on, 0);
948 #endif
949 #ifdef SIGURG
950 		(void) MY_SIGNAL(SIGURG, (sigfunc *) sig_on, 0);
951 #endif
952 #ifdef SIGTRAP
953 		(void) MY_SIGNAL(SIGTRAP, (sigfunc *) sig_on, 0);
954 #endif
955 #ifdef SIGTTIN
956 		(void) MY_SIGNAL(SIGTTIN, (sigfunc *) sig_on, 0);
957 #endif
958 #ifdef SIGTTOU
959 		(void) MY_SIGNAL(SIGTTOU, (sigfunc *) sig_on, 0);
960 #endif
961 #ifdef SIGXCPU
962 		(void) MY_SIGNAL(SIGXCPU, (sigfunc *) sig_on, 0);
963 #endif
964 #ifdef SIGXFSZ
965 		(void) MY_SIGNAL(SIGXFSZ, (sigfunc *) sig_on, 0);
966 #endif
967 #ifdef SIGPOLL
968 		(void) MY_SIGNAL(SIGPOLL, (sigfunc *) sig_on, 0);
969 #endif
970 #ifdef SIGINFO
971 		(void) MY_SIGNAL(SIGINFO, (sigfunc *) sig_on, 0);
972 #endif
973 #ifdef SIGWAITING
974 		(void) MY_SIGNAL(SIGWAITING, (sigfunc *) sig_on, 0);
975 #endif
976 #ifdef SIGLWP
977 		(void) MY_SIGNAL(SIGLWP, (sigfunc *) sig_on, 0);
978 #endif
979 #ifdef SIGSYS
980 		(void) MY_SIGNAL(SIGSYS, (sigfunc *) sig_on, 0);
981 #endif
982 #ifdef SIGIO
983 		(void) MY_SIGNAL(SIGIO, (sigfunc *) sig_on, 0);
984 #endif
985 		/* More signals could probably be added, perhaps some
986 		   should be removed */
987 	}
988 
989 	init_variables();
990 
991 	if (!term_basic())
992 	{
993 		build_status(NULL);
994 		update_input(UPDATE_ALL);
995 	}
996 
997 #ifdef MOTD_FILE
998 	{
999 		struct	stat	motd_stat,
1000 				my_stat;
1001 		u_char	*motd = NULL;
1002 		int	des;
1003 
1004 		malloc_strcpy(&motd, irc_lib);
1005 		malloc_strcat(&motd, UP(MOTD_FILE));
1006 		if (stat(CP(motd), &motd_stat) == 0)
1007 		{
1008 			u_char	*s = NULL;
1009 
1010 			malloc_strcpy(&s, my_path_dir);
1011 			malloc_strcat(&s, UP("/.ircmotd"));
1012 			if (stat(CP(s), &my_stat))
1013 			{
1014 				my_stat.st_atime = 0L;
1015 				my_stat.st_mtime = 0L;
1016 			}
1017 			unlink(CP(s));
1018 			if ((des = open(CP(s), O_CREAT, S_IREAD | S_IWRITE))
1019 					!= -1)
1020 				new_close(des);
1021 			new_free(&s);
1022 			if (motd_stat.st_mtime > my_stat.st_mtime)
1023 			{
1024 				put_file(motd);
1025 				/*
1026 				 * Thanks to Mark Dame <mdame@uceng.ec.edu>
1027 				 * for this one
1028 				 */
1029 				input_pause();
1030 				clear_window_by_refnum(0);
1031 			}
1032 		}
1033 		new_free(&motd);
1034 	}
1035 #endif /* MOTD_FILE */
1036 
1037 	if (bflag)
1038 	{
1039 		load_global();
1040 		load_ircrc();
1041 	}
1042 
1043 	get_connected(0);
1044 	if (channel)
1045 	{
1046 		if (server_get_version(get_primary_server()) == ServerICB)
1047 			server_set_icbgroup(get_primary_server(), channel);
1048 		else
1049 		{
1050 			u_char    *ptr;
1051 
1052 			ptr = my_strsep(&channel, UP(","));
1053 			if (is_channel(ptr))
1054 				add_channel(ptr, 0, 0, CHAN_LIMBO, NULL);
1055 			while ((ptr = my_strsep(&channel, UP(","))) != NULL)
1056 				if (is_channel(ptr))
1057 					add_channel(ptr, 0, 0, CHAN_LIMBO, NULL);
1058 			new_free(&channel);
1059 		}
1060 	}
1061 	current_idle_time = time(0);
1062 	set_input(empty_string());
1063 	irc_io();
1064 	irc_exit();
1065 	return 0;
1066 }
1067 
1068 /*
1069  * set_irchost: This sets the source host for subsequent connections.
1070  */
1071 void
set_irchost(u_char * irchost)1072 set_irchost(u_char *irchost)
1073 {
1074 	if (!irchost || !*irchost)
1075 		new_free(&source_host);
1076 	else
1077 		malloc_strcpy(&source_host, irchost);
1078 }
1079 
1080 u_char *
get_irchost(void)1081 get_irchost(void)
1082 {
1083 	return source_host;
1084 }
1085 
1086 int
irc_port(void)1087 irc_port(void)
1088 {
1089 	return irc_port_local;
1090 }
1091 
1092 int
using_ircio(void)1093 using_ircio(void)
1094 {
1095 	return using_server_process;
1096 }
1097 
1098 u_char *
program_name(void)1099 program_name(void)
1100 {
1101 	return progname;
1102 }
1103 
1104 u_char *
irc_version(void)1105 irc_version(void)
1106 {
1107 	return irc_version_str;
1108 }
1109 
1110 time_t
idle_time(void)1111 idle_time(void)
1112 {
1113 	return current_idle_time;
1114 }
1115 
1116 int
client_default_is_icb(void)1117 client_default_is_icb(void)
1118 {
1119 	return client_default_icb;
1120 }
1121 
1122 int
use_flow_control(void)1123 use_flow_control(void)
1124 {
1125 	return fflag;
1126 }
1127 
1128 int
use_termcap_enterexit(void)1129 use_termcap_enterexit(void)
1130 {
1131 	return tflag;
1132 }
1133 
1134 int
use_background_mode(void)1135 use_background_mode(void)
1136 {
1137 	return bflag;
1138 }
1139 
1140 int
ignore_ircrc(void)1141 ignore_ircrc(void)
1142 {
1143 	return qflag;
1144 }
1145 
1146 u_char *
my_path(void)1147 my_path(void)
1148 {
1149 	return my_path_dir;
1150 }
1151 
1152 u_char *
my_hostname(void)1153 my_hostname(void)
1154 {
1155 	return hostname;
1156 }
1157 
1158 u_char *
my_realname(void)1159 my_realname(void)
1160 {
1161 	return realname;
1162 }
1163 
1164 u_char *
my_username(void)1165 my_username(void)
1166 {
1167 	return username;
1168 }
1169 
1170 void
set_realname(u_char * value)1171 set_realname(u_char *value)
1172 {
1173 	if (value)
1174 		strmcpy(realname, value, REALNAME_LEN);
1175 	else
1176 		*realname = '\0';
1177 }
1178 
1179 void
set_username(u_char * value)1180 set_username(u_char *value)
1181 {
1182 	if (value)
1183 		strmcpy(username, value, REALNAME_LEN);
1184 	else
1185 		*username = '\0';
1186 }
1187 
1188 u_char *
my_irc_lib(void)1189 my_irc_lib(void)
1190 {
1191 	return irc_lib;
1192 }
1193 
1194 u_char *
irc_umode(void)1195 irc_umode(void)
1196 {
1197 	return (send_umode && *send_umode) ? send_umode : hostname;
1198 }
1199 
1200 u_char *
irc_extra_args(void)1201 irc_extra_args(void)
1202 {
1203 	return args_str;
1204 }
1205 
1206 int
term_basic(void)1207 term_basic(void)
1208 {
1209 	return no_full_screen;
1210 }
1211 
1212 u_char *
my_nickname(void)1213 my_nickname(void)
1214 {
1215 	return nickname;
1216 }
1217 
1218 void
set_nickname(u_char * value)1219 set_nickname(u_char *value)
1220 {
1221 	if (value)
1222 		malloc_strcpy(&nickname, value);
1223 	else
1224 		new_free(&nickname);
1225 }
1226 
1227 u_char *
ircquick_file_path(void)1228 ircquick_file_path(void)
1229 {
1230 	return ircquick_file;
1231 }
1232 
1233 u_char *
ircrc_file_path(void)1234 ircrc_file_path(void)
1235 {
1236 	return ircrc_file;
1237 }
1238 
1239 void
set_ircrc_file_path(u_char * path)1240 set_ircrc_file_path(u_char *path)
1241 {
1242 	if (path)
1243 		malloc_strcpy(&ircrc_file, path);
1244 	else
1245 		new_free(&ircrc_file);
1246 }
1247 
1248 u_char *
zero(void)1249 zero(void)
1250 {
1251 	static u_char z[] = { '0', '\0' };
1252 	return z;
1253 }
1254 
1255 u_char *
one(void)1256 one(void)
1257 {
1258 	static u_char o[] = { '1', '\0' };
1259 	return o;
1260 }
1261 
1262 u_char *
empty_string(void)1263 empty_string(void)
1264 {
1265 	static u_char e[] = { '\0' };
1266 	return e;
1267 }
1268