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