/* * ircII: a new irc client. I like it. I hope you will too! * * Written By Michael Sandrof * * Copyright (c) 1990 Michael Sandrof. * Copyright (c) 1991, 1992 Troy Rollo. * Copyright (c) 1992-2000 Matthew R. Green. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #define IRCII_VERSION "4.4Y" /* * INTERNAL_VERSION is the number that the special alias $V returns. * Make sure you are prepared for floods, pestilence, hordes of locusts, * and all sorts of HELL to break loose if you change this number. * Its format is actually YYYYMMDD, for the _release_ date of the * client.. */ #define INTERNAL_VERSION "20000806" #include "irc.h" IRCII_RCSID("@(#)$Id: irc.c,v 1.204 2000/08/05 14:03:57 mrg Exp $"); #include #ifndef __MSDOS__ #include #endif /* __MSDOS__ */ #ifdef ISC22 # include #endif /* ISC22 */ #ifdef ESIX # include #endif /* ESIX */ #ifdef DO_USER2 # include #endif /* DO_USER2 */ #include "status.h" #include "dcc.h" #include "names.h" #include "vars.h" #include "input.h" #include "alias.h" #include "output.h" #include "ircterm.h" #include "exec.h" #include "screen.h" #include "log.h" #include "server.h" #include "hook.h" #include "keys.h" #include "ircaux.h" #include "edit.h" #include "window.h" #include "history.h" #include "exec.h" #include "notify.h" #include "mail.h" #include "debug.h" #include "newio.h" #include "ctcp.h" #include "parse.h" int irc_port = IRC_PORT, /* port of ircd */ icb_port = ICB_PORT, /* port of icbd */ send_text_flag = -1, /* used in the send_text() * routine */ use_flow_control = USE_FLOW_CONTROL, /* true: ^Q/^S used for flow * cntl */ irc_io_loop = 1, /* see irc_io below */ break_io_processing = 0, /* more forceful than * irc_io_loop */ current_numeric, /* this is negative of the * current numeric! */ dumb = 0, /* if true, IRCII is put in * "dumb" mode */ no_fork = 0, /* if true, IRCII won't with * -b or -e */ use_input = 1, /* if 0, stdin is never * checked */ waiting = 0, /* used by /WAIT command */ who_mask = 0; /* keeps track of which /who * switchs are set */ int client_default_icb = 0; /* default to icb server connections */ u_char *zero = UP("0"); u_char *one = UP("1"); u_char oper_command; /* true just after an oper() command is * given. Used to tell the difference * between an incorrect password generated by * an oper() command and one generated when * connecting to a new server */ u_char FAR MyHostName[80]; /* The local machine name. Used by * DCC TALK */ struct in_addr MyHostAddr; /* The local machine address */ extern u_char *last_away_nick; u_char *invite_channel, /* last channel of an INVITE */ *ircrc_file, /* full path .ircrc file */ *ircquick_file, /* full path .ircquick file */ *my_path, /* path to users home dir */ *irc_path, /* paths used by /load */ *irc_lib, /* path to the ircII library */ *nickname, /* users nickname */ FAR hostname[NAME_LEN + 1], /* name of current host */ FAR realname[REALNAME_LEN + 1], /* real name of user */ FAR username[NAME_LEN + 1], /* usernameof user */ *source_host, /* specify a specific source host * for multi-homed machines */ *send_umode, /* sent umode */ *args_str, /* list of command line args */ empty_string[] = "", /* just an empty string */ *who_name, /* extra /who switch info */ *who_file, /* extra /who switch info */ *who_server, /* extra /who switch info */ *who_host, /* extra /who switch info */ *who_nick, /* extra /who switch info */ *who_real, /* extra /who switch info */ *cannot_open, /* extra /who switch info */ *cut_buffer, /* global cut_buffer */ *last_notify_nick; /* last detected nickname */ int away_set; /* set if there is an away * message anywhere */ int qflag; /* set if we ignore .ircrc */ int bflag; /* set if we load .ircrc before connecting */ time_t idle_time; /* last time the user hit a key */ time_t start_time; /* epoch time we started */ static RETSIGTYPE cntl_c _((void)); static RETSIGTYPE sig_user1 _((void)); static RETSIGTYPE sig_refresh_screen _((void)); static void real_sig_user1 _((void)); static int do_sig_user1; #ifdef DO_USER2 static RETSIGTYPE sig_user2 _((void)) ; #endif /* DO_USER2 */ #ifdef MUNIX static RETSIGTYPE cntl_y _((void)); #endif /* MUNIX */ #ifdef CORECATCH static RETSIGTYPE coredump _((void)) ; #endif /* CORECATCH */ static void process_hostname _((void)); static time_t TimerTimeout _((void)); static void quit_response _((u_char *, u_char *)); static void show_version _((void)); static u_char *get_arg _((u_char *, u_char *, int *)); static u_char *parse_args _((u_char **, int)); static int cntl_c_hit = 0; #ifdef DO_USER2 jmp_buf outta_here; #endif /* DO_USER2 */ u_char irc_version[] = IRCII_VERSION; u_char internal_version[] = INTERNAL_VERSION; static char FAR switch_help[] = "Usage: irc [switches] [nickname] [server list] \n\ The [nickname] can be at most 9 characters long on some server\n\ The [server list] is a whitespace separate list of server name\n\ The [switches] may be any or all of the following\n\ -c \tjoins o startup\n\ -p \tdefault IRC server connection port (usually 6667)\n\ -P \tdefault ICB server connection port (usually 7326)\n\ -f\t\tyour terminal uses flow controls (^S/^Q), so IRCII shouldn't\n\ -F\t\tyour terminal doesn't use flow control (default)\n\ -r\t\treverse terminal colours (only if colours are aktivated)\n\ -s\t\tdon't use separate server processes (ircio)\n\ -S\t\tuse separate server processes (ircio)\n\ -h \tsource host, for multihomed machines\n\ -d\t\truns IRCII in \"dumb\" terminal mode\n\ -q\t\tdoes not load .ircrc and not .ircquick\n\ -a\t\tadds default servers and command line servers to server list\n\ -b\t\tload .ircrc before connecting to a server\n\ -l \tloads in place of your .ircrc\n\ -I \tloads in place of your .ircquick\n\ -icb\t\tuse ICB connections by default\n\ -irc\t\tuse IRC connections by default\n\ icb [same switches] (default to -icb)\n"; #ifdef _Windows extern unsigned int hwndMain; #endif /* _Windows */ /* irc_exit: cleans up and leaves */ RETSIGTYPE irc_exit() { do_hook(EXIT_LIST, "Exiting"); close_server(-1, UP("Leaving")); logger(0); set_history_file((u_char *) 0); #ifndef _Windows clean_up_processes(); #endif /* _Windows */ if (!dumb) { cursor_to_input(); /* Needed so that ircII doesn't gobble * the last line of the kill. */ term_cr(); if (term_clear_to_eol()) term_space_erase(0); term_reset(); #ifdef ESIX endwin(); /* Added for curses */ system("tput reset"); new_stty("sane"); #endif /* ESIX */ } #ifdef _Windows DestroyWindow(hwndMain); #else exit(0); #endif /* _Windows */ } #ifdef CORECATCH /* sigsegv: something to handle segfaults in a nice way */ /* this needs to be changed to *NOT* use printf(). */ RETSIGTYPE coredump(sig) int sig; { printf("IRCII has been terminated by a SIG%s\n\r", signals[sig]); printf("Please inform the ircii bugs list (ircii-bugs@eterna.com.au) of this\n\r"); printf("with as much detail as possible about what you were doing when it happened.\n\r"); printf("Please include the version of IRCII (%s) and type of system in the report.\n\r", irc_version); fflush(stdout); irc_exit(); } #endif /* CORECATCH */ /* * quit_response: Used by irc_io when called from irc_quit to see if we got * the right response to our question. If the response was affirmative, the * user gets booted from irc. Otherwise, life goes on. */ static void quit_response(dummy, ptr) u_char *dummy; u_char *ptr; { size_t len; int old_irc_io_loop; old_irc_io_loop = irc_io_loop; irc_io_loop = 0; if ((len = my_strlen(ptr)) != 0) { if (!my_strnicmp(ptr, UP("yes"), len)) { send_to_server("QUIT"); irc_exit(); } } irc_io_loop = old_irc_io_loop; } /* irc_quit: prompts the user if they wish to exit, then does the right thing */ void irc_quit(key, ptr) u_int key; u_char *ptr; { static int in_it = 0; if (in_it) return; in_it = 1; add_wait_prompt(UP("Do you really want to quit? "), quit_response, empty_string, WAIT_PROMPT_LINE); in_it = 0; } /* * cntl_c: emergency exit.... if somehow everything else freezes up, hitting * ^C five times should kill the program. */ static RETSIGTYPE cntl_c() { #ifdef SYSVSIGNALS (void) MY_SIGNAL(SIGINT, (sigfunc *) cntl_c, 0); #endif /* SYSVSIGNALS */ if (cntl_c_hit++ >= 4) irc_exit(); } static RETSIGTYPE sig_user1() { #ifdef SYSVSIGNALS (void) sigfunc *(SIGUSR1, (sigfunc *) sig_user1, 0); #endif /* SYSVSIGNALS */ do_sig_user1++; } static void real_sig_user1() { say("Got SIGUSR1, closing DCC connections and EXECed processes"); close_all_dcc(); #ifndef _Windows close_all_exec(); #endif /* _Windows */ } #ifdef DO_USER2 static RETSIGTYPE sig_user2() { #ifdef SYSVSIGNALS (void) MY_SIGNAL(SIGUSR2, (sigfunc *) sig_user2, 0); #endif /* SYSVSIGNALS */ say("Got SIGUSR2, jumping to normal loop"); /* unsafe */ longjmp(outta_here); } #endif #ifdef MUNIX /* A characteristic of PCS MUNIX - Ctrl-Y produces a SIGQUIT */ static RETSIGTYPE cntl_y() { (void) MY_SIGNAL(SIGQUIT, (sigfunc *) cntl_y, 0); edit_char(25); /* Ctrl-Y */ /* unsafe */ } #endif /* MINUX */ static RETSIGTYPE sig_refresh_screen() { do_refresh_screen++; } /* shows the version of irc */ static void show_version() { printf("ircII version %s (%s)\n\r", irc_version, internal_version); exit (0); } /* * process_hostname: Called at startup and to deal with /SET IRCHOST changes. */ static void process_hostname() { #ifndef INET6 struct hostent *hp; #endif if (source_host) my_strncpy(MyHostName, source_host, sizeof(MyHostName)-1); else gethostname(CP(MyHostName), sizeof(MyHostName)); #ifndef INET6 if ((hp = gethostbyname(CP(MyHostName))) != NULL) bcopy(hp->h_addr, (char *) &MyHostAddr, sizeof(MyHostAddr)); #endif } /* get_arg: used by parse_args() to get an argument after a switch */ static u_char * get_arg(arg, next, ac) u_char *arg; u_char *next; int *ac; { (*ac)++; if (*arg) return (arg); else { if (next) return (next); fprintf(stderr, "irc: missing parameter\n"); exit(1); return (0); /* cleans up a warning */ } } /* * parse_args: parse command line arguments for irc, and sets all initial * flags, etc. */ static u_char * parse_args(argv, argc) u_char **argv; int argc; { u_char *arg, *ptr; int ac; int add_servers = 0; u_char *channel = (u_char *) NULL; struct passwd *entry; int minus_minus = 0; #ifdef _Windows u_char buffer[BIG_BUFFER_SIZE]; #endif if (my_strncmp(argv[0], "icb", 3) == 0 || strstr(CP(argv[0]), "/icb") != 0) client_default_icb = 1; *realname = '\0'; ac = 1; malloc_strcpy(&args_str, argv[0]); malloc_strcat(&args_str, " "); while ((arg = argv[ac++]) != (u_char *) NULL) { malloc_strcat(&args_str, argv[ac-1]); malloc_strcat(&args_str, " "); if ((*arg == '-') != '\0') { ++arg; while (*arg) { switch (*(arg++)) { case 'v': show_version(); break; case 'b': if (qflag) { fprintf(stderr, "Can not use -b with -q\n"); exit(1); } bflag = 1; break; case 'c': malloc_strcpy(&channel, get_arg(arg, argv[ac], &ac)); break; case 'p': irc_port = my_atoi(get_arg(arg, argv[ac], &ac)); break; case 'P': icb_port = my_atoi(get_arg(arg, argv[ac], &ac)); break; case 'f': use_flow_control = 1; break; case 'F': use_flow_control = 0; break; case 'd': dumb = 1; break; case 'h': malloc_strcpy(&source_host, get_arg(arg, argv[ac], &ac)); break; case 'i': if (arg[0] == 'r' && arg[1] == 'c') client_default_icb = 0; else if (arg[0] == 'c' && arg[1] == 'b') client_default_icb = 1; else { printf("irc: invalid -i option; use -irc or -icb"); exit(-1); } arg += 2; break; #ifdef DEBUG case 'D': setdlevel(my_atoi(get_arg(arg, argv[ac], &ac))); break; case 'o': { FILE *fp; u_char *file = get_arg(arg, argv[ac], &ac); if (!file) { printf("irc: need filename for -o\n"); exit(-1); } fp = freopen(file, "w", stderr); if (!fp) { printf("irc: can not open %s: %s\n", file, errno ? "" : strerror(errno)); exit(-1); } } break; #endif /* DEBUG */ case 'l': malloc_strcpy(&ircrc_file, get_arg(arg, argv[ac], &ac)); break; case 'I': malloc_strcpy(&ircquick_file,get_arg(arg, argv[ac], &ac)); break; case 'a': add_servers = 1; break; case 's': using_server_process = 0; break; case 'S': using_server_process = 1; break; case 'q': if (bflag) { fprintf(stderr, "Can not use -q with -b\n"); exit(1); } qflag = 1; break; case 'r': { int oldfg = get_int_var(FOREGROUND_COLOUR_VAR); set_int_var(FOREGROUND_COLOUR_VAR, get_int_var(BACKGROUND_COLOUR_VAR)); set_int_var(BACKGROUND_COLOUR_VAR, oldfg); } break; case '-': if (argv[ac]) { while ((arg = argv[ac++]) != NULL) { malloc_strcat(&command_line, arg); malloc_strcat(&command_line, UP(" ")); /* a bit wasteful; only at startup */ } } minus_minus = 1; break; default: fputs(switch_help, stderr); exit(1); } } } else { if (nickname && *nickname) build_server_list(arg); else malloc_strcpy(&nickname, arg); } if (minus_minus) break; } if ((u_char *) 0 != (ptr = my_getenv("IRCLIB"))) { malloc_strcpy(&irc_lib, ptr); malloc_strcat(&irc_lib, UP("/")); } else malloc_strcpy(&irc_lib, UP(IRCLIB)); /* -h overrides environment variable */ if ((u_char *) 0 == source_host && (u_char *) 0 != (ptr = my_getenv("IRCHOST"))) malloc_strcpy(&source_host, ptr); if ((u_char *) 0 == ircrc_file && (u_char *) 0 != (ptr = my_getenv("IRCRC"))) malloc_strcpy(&ircrc_file, ptr); if ((u_char *) 0 == ircquick_file && (u_char *) 0 != (ptr = my_getenv("IRCQUICK"))) malloc_strcpy(&ircrc_file, ptr); if ((nickname == 0 || *nickname == '\0') && (u_char *) 0 != (ptr = my_getenv("IRCNICK"))) malloc_strcpy(&nickname, ptr); if ((u_char *) 0 != (ptr = my_getenv("IRCUMODE"))) malloc_strcpy(&send_umode, ptr); if ((u_char *) 0 != (ptr = my_getenv("IRCNAME"))) my_strmcpy(realname, ptr, REALNAME_LEN); if ((u_char *) 0 != (ptr = my_getenv("IRCPATH"))) malloc_strcpy(&irc_path, ptr); else { #ifdef IRCPATH malloc_strcpy(&irc_path, UP(IRCPATH)); #else #ifdef __MSDOS__ malloc_strcpy(&irc_path, ".:~/irc:"); #else malloc_strcpy(&irc_path, ".:~/.irc:"); #endif /* __MSDOS__ */ malloc_strcat(&irc_path, irc_lib); malloc_strcat(&irc_path, "script"); #endif /* IRCPATH */ } set_string_var(LOAD_PATH_VAR, irc_path); new_free(&irc_path); if ((u_char *) 0 != (ptr = my_getenv("IRCSERVER"))) build_server_list(ptr); if (0 == number_of_servers || add_servers) { #ifdef SERVERS_FILE if (read_server_file() || (number_of_servers == 0)) #endif /* SERVERS_FILE */ { u_char *s = (u_char *) 0; #ifdef _Windows GetProfileString("IRC", "Server", "Choose.File->Setup.From.Menu", buffer, sizeof(buffer)); malloc_strcpy(&s, buffer); #else malloc_strcpy(&s, UP(DEFAULT_SERVER)); #endif /* _Windows */ build_server_list(s); new_free(&s); } } #ifdef _Windows if (nickname == 0 || !*nickname) { GetProfileString("IRC", "Nick", "ircuser", buffer, BIG_BUFFER_SIZE); malloc_strcpy(&nickname, buffer); } GetProfileString("IRC", "UserName", "ircuser", username, NAME_LEN + 1); GetProfileString("IRC", "RealName", "ircuser", realname, REALNAME_LEN + 1); GetProfileString("IRC", "StartDir", get_path(4), buffer, BIG_BUFFER_SIZE); malloc_strcpy(&my_path, buffer); #else /* _Windows */ if ((struct passwd *) 0 != (entry = getpwuid(getuid()))) { if ((*realname == '\0') && entry->pw_gecos && *(entry->pw_gecos)) { #ifdef GECOS_DELIMITER if ((ptr = my_index(entry->pw_gecos, GECOS_DELIMITER)) != NULL) *ptr = '\0'; #endif /* GECOS_DELIMITER */ if ((ptr = my_index(entry->pw_gecos, '&')) == NULL) my_strmcpy(realname, entry->pw_gecos, REALNAME_LEN); else { size_t len = ptr - (u_char *) entry->pw_gecos; if (len < REALNAME_LEN && *(entry->pw_name)) { u_char *q = realname + len; my_strmcpy(realname, entry->pw_gecos, len); my_strmcat(realname, entry->pw_name, REALNAME_LEN); my_strmcat(realname, ptr + 1, REALNAME_LEN); if (islower(*q) && (q == realname || isspace(*(q - 1)))) *q = toupper(*q); } else my_strmcpy(realname, entry->pw_gecos, REALNAME_LEN); } } if (entry->pw_name && *(entry->pw_name)) my_strmcpy(username, entry->pw_name, NAME_LEN); if (entry->pw_dir && *(entry->pw_dir)) malloc_strcpy(&my_path, UP(entry->pw_dir)); } #endif /* _Windows */ if ((u_char *) 0 != (ptr = my_getenv("HOME"))) malloc_strcpy(&my_path, ptr); else if (*my_path == '\0') malloc_strcpy(&my_path, UP("/")); if ('\0' == *realname) my_strmcpy(realname, "*Unknown*", REALNAME_LEN); if ('\0' == *username) { if ((ptr = my_getenv("USER")) != NULL) my_strmcpy(username, ptr, NAME_LEN); else my_strmcpy(username, "Unknown", NAME_LEN); } if ((u_char *) 0 != (ptr = my_getenv("IRCUSER"))) my_strmcpy(username, ptr, REALNAME_LEN); process_hostname(); if (nickname == 0 || *nickname == '\0') malloc_strcpy(&nickname, username); if ((u_char *) 0 == ircrc_file) { ircrc_file = (u_char *) new_malloc(my_strlen(my_path) + my_strlen(IRCRC_NAME) + 1); my_strcpy(ircrc_file, my_path); my_strcat(ircrc_file, IRCRC_NAME); } if ((u_char *) 0 == ircquick_file) { ircquick_file = (u_char *) new_malloc(my_strlen(my_path) + my_strlen(IRCQUICK_NAME) + 1); my_strcpy(ircquick_file, my_path); my_strcat(ircquick_file, IRCQUICK_NAME); } return (channel); } /* * TimerTimeout: Called from irc_io to help create the timeout * part of the call to select. */ static time_t TimerTimeout() { time_t current; time_t timeout_in; if (!PendingTimers) return 70; /* Just larger than the maximum of 60 */ time(¤t); timeout_in = PendingTimers->time - current; return (timeout_in < 0) ? 0 : timeout_in; } /* * irc_io: the main irc input/output loop. Handles all io from keyboard, * server, exec'd processes, etc. If a prompt is specified, it is displayed * in the input line and cannot be backspaced over, etc. The func is a * function which will take the place of the SEND_LINE function (which is * what happens when you hit return at the end of a line). This function must * decide if it's ok to exit based on anything you really want. It can then * set the global irc_io_loop to false to cause irc_io to exit. */ int irc_io(prompt, func, my_use_input, loop) u_char *prompt; void (*func) _((u_int, u_char *)); int my_use_input; int loop; { static int level = 0; fd_set rd, wd; u_char lbuf[BIG_BUFFER_SIZE + 1]; /* buffer much bigger than * IRCD_BUFFER_SIZE */ struct timeval cursor_timeout, clock_timeout, right_away, timer, *timeptr; int hold_over; int old_loop; u_char *last_input = NULL; u_char *last_prompt = NULL; void (*last_func) _((u_int, u_char *)); int one_key = 0; Screen *screen, *old_current_screen; last_func = get_send_line(); if (my_use_input == -1) one_key = 1, prompt = NULL; /* time before cursor jumps from display area to input line */ cursor_timeout.tv_usec = 0L; cursor_timeout.tv_sec = 1L; /* time delay for updating of internal clock */ clock_timeout.tv_usec = 0L; clock_timeout.tv_sec = 30L; right_away.tv_usec = 0L; right_away.tv_sec = 0L; timer.tv_usec = 0L; old_loop = irc_io_loop; irc_io_loop = loop; /* * irc_io has been recursive to date. * with multiple xterms and screen * windows, this has to change */ if (level++ > 5) { level--; irc_io_loop = old_loop; return (1); } if (!dumb) { if (my_use_input) { malloc_strcpy(&last_input, get_input()); set_input(empty_string); last_func = get_send_line(); change_send_line(func); } if (prompt) { malloc_strcpy(&last_prompt, get_input_prompt()); set_input_prompt(prompt); } } /* * Here we work out if this has been called recursively or * not.. and if not so.. -phone */ #if defined(DEBUG) || defined(DO_USER2) if (level != 1) { #ifdef DEBUG yell("--- Recursive call to irc_io() - careful"); #endif /* DEBUG */ } else { #ifdef DO_USER2 if (setjmp(outta_here)) yell("*** Got SIGUSR2, Aborting"); #endif /* DO_USER2 */ } #endif /* DEBUG || DO_USER2 */ timeptr = &clock_timeout; do { break_io_processing = 0; sed = 0; FD_ZERO(&rd); FD_ZERO(&wd); set_process_bits(&rd); set_server_bits(&rd, &wd); #ifndef _Windows if (my_use_input) for (screen = screen_list; screen; screen = screen->next) if (screen->alive) FD_SET(screen->fdin, &rd); set_dcc_bits(&rd, &wd); if (term_reset_flag) { refresh_screen(0, (u_char *) 0); term_reset_flag = 0; } #endif /* _Windows */ timer.tv_sec = TimerTimeout(); if (timer.tv_sec <= timeptr->tv_sec) timeptr = &timer; if ((hold_over = unhold_windows()) != 0) timeptr = &right_away; Debug((7, "irc_io: selecting with %l:%l timeout", timeptr->tv_sec, timeptr->tv_usec)); switch (new_select(&rd, &wd, timeptr)) { case 0: case -1: /* * yay for the QNX socket manager... drift here, drift there, oops, * i fell down a hole.. */ #ifdef __QNX__ if (errno == EBADF || errno == ESRCH) irc_io_loop = 0; #endif /* __QNX__ */ if (cntl_c_hit) { if (one_key) { irc_io_loop = 0; break; } edit_char((u_int)'\003'); cntl_c_hit = 0; } if (do_status_alarmed) { real_status_alarmed(); do_status_alarmed = 0; } if (do_refresh_screen) { refresh_screen(0, (u_char *) 0); do_refresh_screen = 0; } if (do_sig_user1) { real_sig_user1(); do_sig_user1 =0; } if (!hold_over) cursor_to_input(); break; default: #ifndef _Windows if (term_reset_flag) { refresh_screen(0, (u_char *) 0); term_reset_flag = 0; } #endif /* _Windows */ old_current_screen = current_screen; set_current_screen(last_input_screen); if (!break_io_processing) dcc_check(&rd, &wd); if (!break_io_processing) do_server(&rd, &wd); set_current_screen(old_current_screen); for (screen = screen_list; screen && !break_io_processing; screen = screen->next) { if (!screen->alive) continue; set_current_screen(screen); if (FD_ISSET(screen->fdin, &rd)) { /* * This section of code handles all in put from the terminal(s). * connected to ircII. Perhaps the idle time *shouldn't* be * reset unless its not a screen-fd that was closed.. * * This section indented - phone, jan 1993 */ idle_time = time(0); if (dumb) { int old_timeout; old_timeout = dgets_timeout(1); if (dgets(lbuf, INPUT_BUFFER_SIZE, screen->fdin, (u_char *) 0)) { (void) dgets_timeout(old_timeout); if (one_key) { irc_io_loop = 0; break; } *(lbuf + my_strlen(lbuf) - 1) = '\0'; if (get_int_var(INPUT_ALIASES_VAR)) parse_line(NULL, lbuf, empty_string, 1, 0); else parse_line(NULL, lbuf, NULL, 1, 0); } else { say("IRCII exiting on EOF from stdin"); irc_exit(); } } else { int server; u_char loc_buffer[BIG_BUFFER_SIZE + 1]; int n, i; server = from_server; from_server = get_window_server(0); last_input_screen = screen; if (one_key) { if (read(screen->fdin, lbuf, 1)) { irc_io_loop = 0; break; } /* * Following Fizzy's remark below, if we * don't use window create, we can't kill * then, can we? --FlashMan, October 1994 */ #ifdef WINDOW_CREATE else { #ifndef _Windows if (!is_main_screen(screen)) kill_screen(screen); else #endif /* _Windows */ irc_exit(); } #endif /* WINDOW_CREATE */ } else if ((n = read(screen->fdin, loc_buffer, BIG_BUFFER_SIZE)) != 0) for (i = 0; i < n; i++) edit_char((u_int)loc_buffer[i]); /* * if the current screen isn't the main screen, * then the socket to the current screen must have * closed, so we call kill_screen() to handle * this - phone, jan 1993. * but not when we arent running windows - Fizzy, may 1993 * if it is the main screen we got an EOF on, we exit.. * closed tty -> chew cpu -> bad .. -phone, july 1993. */ #ifdef WINDOW_CREATE else { if (!is_main_screen(screen)) kill_screen(screen); else irc_exit(); } #endif /* WINDOW_CREATE */ cntl_c_hit = 0; from_server = server; } /* End of intendation */ } } set_current_screen(old_current_screen); #ifndef _Windows if (!break_io_processing) do_processes(&rd); #endif /* _Windows */ break; } execute_timer(); #ifndef _Windows check_process_limits(); (void) check_wait_status(-1); #endif /* _Windows */ if ((primary_server == -1) && !never_connected) do_hook(DISCONNECT_LIST, "%s", nickname); timeptr = &clock_timeout; old_current_screen = current_screen; for (current_screen = screen_list; current_screen; current_screen = current_screen->next) if (current_screen->alive && is_cursor_in_display()) timeptr = &cursor_timeout; set_current_screen(old_current_screen); if (update_clock(0, 0, 0)) { if (get_int_var(CLOCK_VAR) || check_mail_status()) { status_update(1); cursor_to_input(); } if (primary_server != -1) do_notify(); } } while (irc_io_loop); level--; irc_io_loop = old_loop; if (! dumb) { if (my_use_input) { set_input(last_input); new_free(&last_input); change_send_line(last_func); } if (prompt) { if (level == 0) set_input_prompt(get_string_var(INPUT_PROMPT_VAR)); else set_input_prompt(last_prompt); new_free(&last_prompt); } } update_input(UPDATE_ALL); return (0); } int #ifdef _Windows old_main(int argc, char **argv) #else /*ARGSUSED*/ main _((int, char *[], char *[])); int main(argc, argv, envp) int argc; char *argv[]; char *envp[]; #endif /* _Windows */ { u_char *channel; #ifdef _Windows reset_pointers(); #endif /* _Windows */ start_time = time((time_t *)0); #ifdef SOCKS SOCKSinit(argv[0]); #endif /* SOCKS */ channel = parse_args((u_char **) argv, argc); #if defined(ESIX) /* Curses code added for ESIX use */ if (!dumb) { initscr(); noecho(); cbreak(); } #endif /* ESIX */ #ifndef _Windows if ((use_input == 0) && !no_fork) { if (fork()) _exit(0); } #endif /* _Windows */ #if defined(ESIX) || defined(_Windows) if (gethostname(CP(hostname), NAME_LEN) == NULL) #else if (gethostname(CP(hostname), NAME_LEN)) #endif /* ESIX */ { #ifdef _Windows switch(WSAGetLastError()) { case WSAEFAULT: MessageBox(0, "Couldn't get host name", 0, MB_OK); break; case WSANOTINITIALISED: MessageBox(0, "Couldn't get host name", 0, MB_OK); break; case WSAENETDOWN: MessageBox(0, "Couldn't get host name", 0, MB_OK); break; case WSAEINPROGRESS: MessageBox(0, "Couldn't get host name", 0, MB_OK); break; default: break; } #else fprintf(stderr, "irc: couldn't figure out the name of your machine!\n"); exit(1); #endif /* _Windows */ } term_set_fp(stdout); if (dumb) new_window(); else { init_screen(); #ifndef _Windows #if !defined(MUNIX) && !defined(_RT) && !defined(ESIX) (void) MY_SIGNAL(SIGCONT, (sigfunc *) term_cont, 0); #endif /* !defined(MUNIX) && !defined(_RT) && !defined(ESIX) */ #if !defined(_RT) && defined(SIGWINCH) (void) MY_SIGNAL(SIGWINCH, (sigfunc *) sig_refresh_screen, 0); #endif /* _RT */ #ifndef ALLOC_DEBUG # ifdef CORECATCH (void) MY_SIGNAL(SIGSEGV, (sigfunc *) coredump, 0); # ifdef SIGBUS (void) MY_SIGNAL(SIGBUS, (sigfunc *) coredump, 0); # endif /* SIGBUS */ # else (void) MY_SIGNAL(SIGSEGV, (sigfunc *) SIG_DFL, 0); /* Linux doesn't have SIGBUS */ # ifdef SIGBUS (void) MY_SIGNAL(SIGBUS, (sigfunc *) SIG_DFL, 0); # endif /* SIGBUS */ # endif /* CORECATCH */ #endif /* ALLOC_DEBUG */ #ifdef MUNIX (void) MY_SIGNAL(SIGQUIT, (sigfunc *) cntl_y, 0); #endif /* MINUX */ (void) MY_SIGNAL(SIGHUP, (sigfunc *) irc_exit, 0); (void) MY_SIGNAL(SIGTERM, (sigfunc *) irc_exit, 0); (void) MY_SIGNAL(SIGPIPE, (sigfunc *) SIG_IGN, 0); (void) MY_SIGNAL(SIGINT, (sigfunc *) cntl_c, 0); #ifdef SIGSTOP (void) MY_SIGNAL(SIGSTOP, (sigfunc *) SIG_IGN, 0); #endif /* SIGSTOP */ (void) MY_SIGNAL(SIGUSR1, (sigfunc *) sig_user1, 0); #ifdef DO_USER2 (void) MY_SIGNAL(SIGUSR2, (sigfunc *) sig_user2, 0); #endif /* DO_USER2 */ #endif /* _Windows */ } init_variables(); if (!dumb) { build_status((u_char *) 0); update_input(UPDATE_ALL); } #ifdef MOTD_FILE { struct stat motd_stat, my_stat; u_char *motd = NULL; int des; malloc_strcpy(&motd, irc_lib); malloc_strcat(&motd, UP(MOTD_FILE)); if (stat_file(CP(motd), &motd_stat) == 0) { u_char *s = (u_char *) 0; malloc_strcpy(&s, my_path); #ifdef __MSDOS__ malloc_strcat(&s, UP("/ircmotd.red")); #else malloc_strcat(&s, UP("/.ircmotd")); #endif /* __MSDOS__ */ if (stat_file(CP(s), &my_stat)) { my_stat.st_atime = 0L; my_stat.st_mtime = 0L; } unlink(CP(s)); if ((des = open(CP(s), O_CREAT, S_IREAD | S_IWRITE)) != -1) new_close(des); new_free(&s); if (motd_stat.st_mtime > my_stat.st_mtime) { put_file(motd); /* Thanks to Mark Dame for this one */ #if defined(PAUSE_AFTER_MOTD) && PAUSE_AFTER_MOTD input_pause(UP("******** Press any key to continue ********")); #endif /* PAUSE_AFTER_MOTD */ clear_window_by_refnum(0); } } new_free(&motd); } #endif /* MOTD_FILE */ if (bflag) load_ircrc(); get_connected(0); if (channel) { if (get_server_version(primary_server) == ServerICB) set_server_icbgroup(primary_server, channel); else { u_char *ptr; ptr = UP(strtok(CP(channel), ",")); if (is_channel(ptr)) add_channel(ptr, 0, CHAN_LIMBO, (ChannelList *) 0); while ((ptr = UP(strtok(NULL,","))) != NULL) if (is_channel(ptr)) add_channel(ptr, 0, CHAN_LIMBO, (ChannelList *) 0); new_free(&channel); } } idle_time = time(0); set_input(empty_string); #ifndef _Windows irc_io(get_string_var(INPUT_PROMPT_VAR), NULL, use_input, irc_io_loop); irc_exit(); #endif /* _Windows */ return 0; } /* * set_irchost: This sets the source host for subsequent connections. */ void set_irchost () { u_char *irchost; irchost = get_string_var(IRCHOST_VAR); if (!irchost || !*irchost) source_host = NULL; else malloc_strcpy(&source_host, irchost); process_hostname(); } .