/*
* 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-2006 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 "20060725" /* YYYYMMDD */
#include "irc.h"
IRCII_RCSID("@(#)$eterna: irc.c,v 1.298 2006/07/25 11:14:19 mrg Exp $");
#include <sys/stat.h>
#ifndef __MSDOS__
#include <pwd.h>
#endif /* __MSDOS__ */
#ifdef ISC22
# include <sys/bsdtypes.h>
#endif /* ISC22 */
#ifdef DO_USER2
# include <setjmp.h>
#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"
#include "strsep.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 */
cur_signal = -1, /* head of below */
occurred_signals[16]; /* got signal which may
require /ON action */
int client_default_icb = 0; /* default to irc 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 */
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 */
*dcc_source_host, /* source host to use for DCC */
*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 */
int tflag = 1; /* don't use termcap ti/te sequences */
time_t idle_time; /* last time the user hit a key */
time_t start_time; /* epoch time we started */
static RETSIGTYPE cntl_c(int);
static RETSIGTYPE sig_user1(int);
static RETSIGTYPE sig_refresh_screen(int);
static RETSIGTYPE sig_on(int);
static void real_sig_user1(void);
static int do_sig_user1;
#ifdef DO_USER2
static RETSIGTYPE sig_user2(int) ;
#endif /* DO_USER2 */
#ifdef MUNIX
static RETSIGTYPE cntl_y(int);
#endif /* MUNIX */
#ifdef CORECATCH
static RETSIGTYPE coredump(int) ;
#endif /* CORECATCH */
static int irc_do_a_screen(Screen *, fd_set *, int);
static void TimerTimeout(struct timeval *tv);
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;
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 separated list of server names\n\
The [switches] may be any or all of the following:\n\
-c <channel>\tjoins <channel> on startup\n\
-p <port>\tdefault IRC server connection port (usually 6667)\n\
-P <port>\tdefault ICB server connection port (usually 7326)\n\
-f\t\tyour terminal uses flow control (^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 activated)\n\
-s\t\tdon't use separate server processes (ircio)\n\
-S\t\tuse separate server processes (ircio)\n\
-h <host>\tsource host, for multihomed machines\n\
-H <host>\toriginating address for dcc requests (to work behind NATs etc)\n\
-d\t\truns IRCII in \"dumb\" terminal mode\n\
-q\t\tdoes not load .ircrc nor .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 <file>\tloads <file> in place of your .ircrc\n\
-I <file>\tloads <file> in place of your .ircquick\n\
-t\t\tdo not use termcap ti and te sequences at startup\n\
-T\t\tuse termcap ti and te sequences at startup (default)\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, empty_string);
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 _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(signo)
int signo;
{
printf("IRCII has been terminated by a SIG%s\n\r", signals[signo]);
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;
}
void
on_signal_occurred(signo)
int signo;
{
if (cur_signal > 16)
return;
occurred_signals[++cur_signal] = signo;
}
/*
* cntl_c: emergency exit.... if somehow everything else freezes up, hitting
* ^C five times should kill the program.
*/
static RETSIGTYPE
cntl_c(signo)
int signo;
{
#ifdef SYSVSIGNALS
(void) MY_SIGNAL(SIGINT, (sigfunc *) cntl_c, 0);
#endif /* SYSVSIGNALS */
on_signal_occurred(signo);
if (cntl_c_hit++ >= 4)
irc_exit();
}
static RETSIGTYPE
sig_on(signo)
int signo;
{
#ifdef SYSVSIGNALS
(void) sigfunc *(signo, (sigfunc *) sig_on, 0);
#endif /* SYSVSIGNALS */
on_signal_occurred(signo);
}
static RETSIGTYPE
sig_user1(signo)
int signo;
{
#ifdef SYSVSIGNALS
(void) sigfunc *(SIGUSR1, (sigfunc *) sig_user1, 0);
#endif /* SYSVSIGNALS */
do_sig_user1++;
on_signal_occurred(signo);
}
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(signo)
int signo;
{
#ifdef SYSVSIGNALS
(void) MY_SIGNAL(SIGUSR2, (sigfunc *) sig_user2, 0);
#endif /* SYSVSIGNALS */
on_signal_occurred(signo);
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(signo)
int signo;
{
(void) MY_SIGNAL(SIGQUIT, (sigfunc *) cntl_y, 0);
on_signal_occurred(signo);
edit_char(25); /* Ctrl-Y */ /* unsafe */
}
#endif /* MINUX */
static RETSIGTYPE
sig_refresh_screen(signo)
int signo;
{
on_signal_occurred(signo);
do_refresh_screen++;
}
/* shows the version of irc */
static void
show_version()
{
printf("ircII version %s\n\r", irc_version);
exit (0);
}
/* 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 *) 0;
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, UP(" "));
while ((arg = argv[ac++]) != (u_char *) 0)
{
malloc_strcat(&args_str, argv[ac-1]);
malloc_strcat(&args_str, UP(" "));
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(&dcc_source_host, get_arg(arg,
argv[ac], &ac));
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(CP(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 't':
tflag = 1;
break;
case 'T':
tflag = 0;
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])
{
int first = 1;
while ((arg = argv[ac++]) != NULL)
{
malloc_strcat(&command_line, arg);
if (first)
first = 0;
else
malloc_strcat(&command_line, UP(" "));
}
}
minus_minus = 1;
break;
default:
fputs(switch_help, stderr);
exit(1);
}
if (minus_minus)
break;
}
}
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(&ircquick_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, sizeof buffer);
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, sizeof buffer);
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);
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 void
TimerTimeout(tv)
struct timeval *tv;
{
struct timeval current;
tv->tv_usec =0;
tv->tv_sec =0;
if (!PendingTimers)
{
tv->tv_sec = 70; /* Just larger than the maximum of 60 */
return;
}
gettimeofday(¤t, NULL);
if (PendingTimers->time < current.tv_sec ||
(PendingTimers->time == current.tv_sec &&
PendingTimers->microseconds < current.tv_usec))
{
/* No time to lose, the event is now or was */
return;
}
tv->tv_sec = PendingTimers->time - current.tv_sec;
if (PendingTimers->microseconds >= current.tv_usec)
tv->tv_usec = PendingTimers->microseconds - current.tv_usec;
else
{
tv->tv_usec = current.tv_usec - PendingTimers->microseconds;
tv->tv_sec -= 1;
}
}
/*
* generally processes one screen's input. this used to be part of irc_io()
* but has been split out because that function was too large and too nested.
* it returns 0 if IO processing should continue and 1 if it should stop.
*/
static int
irc_do_a_screen(screen, rd, one_key)
Screen *screen;
fd_set *rd;
int one_key;
{
if (!screen->alive)
return 0;
set_current_screen(screen);
if (!is_main_screen(screen) &&
FD_ISSET(screen->wservin, rd))
screen_wserv_message(screen);
if (FD_ISSET(screen->fdin, rd))
{
/* buffer much bigger than IRCD_BUFFER_SIZE */
u_char lbuf[BIG_BUFFER_SIZE + 1];
/*
* 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..
*/
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;
return 1;
}
*(lbuf + my_strlen(lbuf) - 1) = '\0';
if (get_int_var(INPUT_ALIASES_VAR))
parse_line(NULL, lbuf,
empty_string, 1, 0, 0);
else
parse_line(NULL, lbuf,
NULL, 1, 0, 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;
return 1;
}
/*
* 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;
}
}
return 0;
}
/*
* 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;
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;
int i;
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;
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;
ctcp_was_crypted = 0;
FD_ZERO(&rd);
FD_ZERO(&wd);
set_process_bits(&rd);
set_server_bits(&rd, &wd);
if (my_use_input)
for (screen = screen_list; screen; screen = screen->next)
if (screen->alive)
{
FD_SET(screen->fdin, &rd);
if (!is_main_screen(screen))
FD_SET(screen->wservin, &rd);
}
set_dcc_bits(&rd, &wd);
if (term_reset_flag)
{
refresh_screen(0, (u_char *) 0);
term_reset_flag = 0;
}
TimerTimeout(&timer);
if (timer.tv_sec <= timeptr->tv_sec)
timeptr = &timer;
if ((hold_over = unhold_windows()) != 0)
timeptr = &right_away;
Debug((7, "irc_io: selecting with %ld:%ld 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;
}
for (i = 0; i <= cur_signal; i++)
if (occurred_signals[i] != 0)
do_hook(OS_SIGNAL_LIST, "%s",
signals[occurred_signals[i]]);
cur_signal = -1;
if (!hold_over)
cursor_to_input();
break;
default:
if (term_reset_flag)
{
refresh_screen(0, (u_char *) 0);
term_reset_flag = 0;
}
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 (irc_do_a_screen(screen, &rd, one_key))
break;
set_current_screen(old_current_screen);
if (!break_io_processing)
do_processes(&rd);
break;
}
execute_timer();
check_process_limits();
while (check_wait_status(-1) >= 0)
;
if ((primary_server == -1) && !never_connected)
do_hook(DISCONNECT_LIST, "%s", nickname);
timeptr = &clock_timeout;
old_current_screen = current_screen;
for (screen = screen_list; screen; screen = screen->next)
{
set_current_screen(screen);
if (screen->alive && is_cursor_in_display())
timeptr = &cursor_timeout;
}
set_current_screen(old_current_screen);
if (update_clock(0, 0, UPDATE_TIME))
{
Debug((8, "update_clock(0,0,0) returned true; updating clock"));
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
/*ARGSUSED*/
main(int, char *[], char *[]);
int
main(argc, argv, envp)
int argc;
char *argv[];
char *envp[];
{
u_char *channel;
srandom(time(NULL) ^ getpid()); /* something */
start_time = time((time_t *)0);
#ifdef SOCKS
SOCKSinit(argv[0]);
#endif /* SOCKS */
channel = parse_args((u_char **) argv, argc);
if ((use_input == 0) && !no_fork)
{
if (fork())
_exit(0);
}
if (gethostname(CP(hostname), NAME_LEN))
{
fprintf(stderr, "irc: couldn't figure out the name of your machine!\n");
exit(1);
}
term_set_fp(stdout);
if (dumb)
new_window();
else
{
init_screen();
#if !defined(MUNIX) && !defined(_RT)
(void) MY_SIGNAL(SIGCONT, (sigfunc *) term_cont, 0);
#elif defined(SIGCONT)
(void) MY_SIGNAL(SIGCONT, (sigfunc *) sig_on, 0 );
#endif /* !defined(MUNIX) && !defined(_RT) */
#if !defined(_RT) && defined(SIGWINCH)
(void) MY_SIGNAL(SIGWINCH, (sigfunc *) sig_refresh_screen, 0);
#elif defined(SIGWINCH)
(void) MY_SIGNAL(SIGWINCH, (sigfunc *) sig_on, 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_on, 0);
(void) MY_SIGNAL(SIGINT, (sigfunc *) cntl_c, 0);
#ifdef SIGSTOP
(void) MY_SIGNAL(SIGSTOP, (sigfunc *) sig_on, 0);
#endif /* SIGSTOP */
(void) MY_SIGNAL(SIGUSR1, (sigfunc *) sig_user1, 0);
#ifdef DO_USER2
(void) MY_SIGNAL(SIGUSR2, (sigfunc *) sig_user2, 0);
#else
(void) MY_SIGNAL(SIGUSR2, (sigfunc *) sig_on, 0);
#endif /* DO_USER2 */
#ifdef SIGPWR
(void) MY_SIGNAL(SIGPWR, (sigfunc *) sig_on, 0);
#endif
#ifdef SIGCHLD
(void) MY_SIGNAL(SIGCHLD, (sigfunc *) sig_on, 0);
#endif
#ifdef SIGURG
(void) MY_SIGNAL(SIGURG, (sigfunc *) sig_on, 0);
#endif
#ifdef SIGTRAP
(void) MY_SIGNAL(SIGTRAP, (sigfunc *) sig_on, 0);
#endif
#ifdef SIGTTIN
(void) MY_SIGNAL(SIGTTIN, (sigfunc *) sig_on, 0);
#endif
#ifdef SIGTTOU
(void) MY_SIGNAL(SIGTTOU, (sigfunc *) sig_on, 0);
#endif
#ifdef SIGXCPU
(void) MY_SIGNAL(SIGXCPU, (sigfunc *) sig_on, 0);
#endif
#ifdef SIGXFSZ
(void) MY_SIGNAL(SIGXFSZ, (sigfunc *) sig_on, 0);
#endif
#ifdef SIGPOLL
(void) MY_SIGNAL(SIGPOLL, (sigfunc *) sig_on, 0);
#endif
#ifdef SIGINFO
(void) MY_SIGNAL(SIGINFO, (sigfunc *) sig_on, 0);
#endif
#ifdef SIGWAITING
(void) MY_SIGNAL(SIGWAITING, (sigfunc *) sig_on, 0);
#endif
#ifdef SIGLWP
(void) MY_SIGNAL(SIGLWP, (sigfunc *) sig_on, 0);
#endif
#ifdef SIGSYS
(void) MY_SIGNAL(SIGSYS, (sigfunc *) sig_on, 0);
#endif
#ifdef SIGIO
(void) MY_SIGNAL(SIGIO, (sigfunc *) sig_on, 0);
#endif
/* More signals could probably be added, perhaps some
should be removed */
}
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(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(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 <mdame@uceng.ec.edu> 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)
{
loading_global = 1;
load(empty_string, UP("global"), empty_string);
loading_global = 0;
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 = my_strsep(&channel, UP(","));
if (is_channel(ptr))
add_channel(ptr, 0, 0, CHAN_LIMBO, (ChannelList *) 0);
while ((ptr = my_strsep(&channel, UP(","))) != NULL)
if (is_channel(ptr))
add_channel(ptr, 0, 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(irchost)
u_char *irchost;
{
if (!irchost || !*irchost)
new_free(&source_host);
else
malloc_strcpy(&source_host, irchost);
}
/*
* set_dcchost: This sets the source host for subsequent connections.
*/
void
set_dcchost(dcchost)
u_char *dcchost;
{
if (!dcchost || !*dcchost)
new_free(&dcc_source_host);
else
malloc_strcpy(&dcc_source_host, dcchost);
}
syntax highlighted by Code2HTML, v. 0.9.1