Previously the server lag check was run by update_clock() if the number of seconds since client startup was a multiple of 20 (unless it had already been done this second). This meant that if update_clock() was not being called frequently (eg. if your IRC connection was very quiet), it might go a long time between lag checks. This commit adds a /set LAG_CHECK_INTERVAL (defaulting to 30). For each server, a lag check ping is scheduled for every LAG_CHECK_INTERVAL seconds after the connection is finalised/registered. Setting this value to 0 disables the lag check pings entirely. The old code set the lag to 'unknown' immediately after sending out a ping, which meant that it was quite unpredictable how long the lag value would stay around for. The new code only sets this once the current lag value has become stale (ie. a ping reply is overdue based on the current lag value). If your lag is staying the same or reducing, you shouldn't see the [Lag ??] at all.
1686 lines
37 KiB
C
1686 lines
37 KiB
C
/*
|
|
* ircII: a new irc client. I like it. I hope you will too!
|
|
*
|
|
* Written By Michael Sandrof
|
|
* Copyright(c) 1990
|
|
* See the COPYRIGHT file, or do a HELP IRCII COPYRIGHT
|
|
*/
|
|
|
|
#define __irc_c
|
|
|
|
#include "irc.h"
|
|
#include "struct.h"
|
|
|
|
static char cvsrevision[] = "$Id$";
|
|
CVS_REVISION(irc_c)
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <pwd.h>
|
|
#ifdef USING_CURSES
|
|
#include <curses.h>
|
|
#endif
|
|
#include <stdarg.h>
|
|
|
|
#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 "flood.h"
|
|
#include "screen.h"
|
|
#include "log.h"
|
|
#include "server.h"
|
|
#include "hook.h"
|
|
#include "keys.h"
|
|
#include "ircaux.h"
|
|
#include "commands.h"
|
|
#include "window.h"
|
|
#include "history.h"
|
|
#include "exec.h"
|
|
#include "notify.h"
|
|
#include "numbers.h"
|
|
#include "mail.h"
|
|
#include "debug.h"
|
|
#include "newio.h"
|
|
#include "timer.h"
|
|
#include "whowas.h"
|
|
#include "misc.h"
|
|
#include "gui.h"
|
|
#include "cdns.h"
|
|
#include "tcl_bx.h"
|
|
#include "ssl.h"
|
|
#include <pwd.h>
|
|
#define MAIN_SOURCE
|
|
#include "modval.h"
|
|
|
|
#ifdef __EMX__
|
|
#include <signame.h>
|
|
#endif
|
|
|
|
const char irc_version[] = VERSION;
|
|
|
|
/* Format of bitchx_numver: MMmmpp
|
|
* MM = major version (eg 10 = 1.0)
|
|
* mm = minor version
|
|
* pp = patchlevel (00 = development, 01 = release)
|
|
*/
|
|
const unsigned long bitchx_numver = 120101;
|
|
|
|
/*
|
|
* 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..
|
|
*/
|
|
const char internal_version[] = "20141114";
|
|
|
|
int irc_port = IRC_PORT, /* port of ircd */
|
|
strip_ansi_in_echo,
|
|
current_on_hook = -1, /* used in the send_text()
|
|
* routine */
|
|
use_flow_control = USE_FLOW_CONTROL, /* true: ^Q/^S used for flow
|
|
* cntl */
|
|
current_numeric, /* this is negative of the
|
|
* current numeric! */
|
|
dumb_mode = 0, /* if true, IRCII is put in
|
|
* "dumb" mode */
|
|
bflag = 1,
|
|
|
|
use_input = 1, /* if 0, stdin is never
|
|
* checked */
|
|
waiting_out = 0, /* used by /WAIT command */
|
|
waiting_in = 0, /* used by /WAIT command */
|
|
who_mask = 0, /* keeps track of which /who
|
|
* switchs are set */
|
|
dead = 0,
|
|
inhibit_logging = 0,
|
|
#ifndef ONLY_STD_CHARS
|
|
startup_ansi = 1, /* display startup ansi */
|
|
#else
|
|
startup_ansi = 0, /* DO NOT display startup ansi */
|
|
#endif
|
|
auto_connect = 1, /* auto-connect to first server*/
|
|
|
|
background = 0,
|
|
do_check_pid = 0,
|
|
do_ignore_ajoin = 0,
|
|
#ifdef HAVE_SSL
|
|
do_use_ssl = 0,
|
|
#endif
|
|
run_level = 0,
|
|
|
|
foreground = 1,
|
|
reconnect = 0, /* reconnecting to old process */
|
|
use_nat_address = 0, /* use NAT address */
|
|
term_initialized = 0;
|
|
|
|
char zero[] = "0",
|
|
one[] = "1",
|
|
space[] = " ",
|
|
space_plus[] = " +",
|
|
space_minus[] = " -",
|
|
dot[] = ".",
|
|
star[] = "*",
|
|
comma[] = ",",
|
|
empty_string[] = "",
|
|
on[] = "ON",
|
|
off[] = "OFF";
|
|
|
|
const char *unknown_userhost = "<UNKNOWN>@<UNKNOWN>";
|
|
|
|
char oper_command = 0; /* 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 */
|
|
struct sockaddr_foobar MyHostAddr; /* The local machine address */
|
|
struct sockaddr_foobar LocalHostAddr;
|
|
char *LocalHostName = NULL;
|
|
|
|
char *channel = NULL;
|
|
|
|
|
|
int inbound_line_mangler = 0,
|
|
logfile_line_mangler = 0,
|
|
operlog_line_mangler = 0,
|
|
outbound_line_mangler = 0;
|
|
|
|
|
|
|
|
char *invite_channel = NULL, /* last channel of an INVITE */
|
|
*ircrc_file = NULL, /* full path .ircrc file */
|
|
*bircrc_file = NULL, /* full path .ircrc file */
|
|
*my_path = NULL, /* path to users home dir */
|
|
*irc_path = NULL, /* paths used by /load */
|
|
*irc_lib = NULL, /* path to the ircII library */
|
|
*ircservers_file = NULL, /* name of server file */
|
|
nickname[NICKNAME_LEN + 1], /* users nickname */
|
|
hostname[NAME_LEN + 1], /* name of current host */
|
|
userhost[(NAME_LEN + 1) * 2],
|
|
realname[REALNAME_LEN + 1], /* real name of user */
|
|
username[NAME_LEN + 1], /* usernameof user */
|
|
attach_ttyname[500], /* ttyname for this term */
|
|
socket_path[500], /* ttyname for this term */
|
|
*forwardnick = NULL, /* used for /forward */
|
|
*send_umode = NULL, /* sent umode */
|
|
*args_str = NULL, /* list of command line args */
|
|
*last_notify_nick = NULL, /* last detected nickname */
|
|
*auto_str = NULL, /* auto response str */
|
|
*new_script = NULL, /* rephacement for .bitchxrc and .ircrc */
|
|
*cut_buffer = NULL; /* global cut_buffer */
|
|
|
|
int quick_startup = 0; /* set if we ignore .ircrc */
|
|
int cpu_saver = 0;
|
|
|
|
int use_socks = 0; /* do we use socks info to connect */
|
|
char *old_tty = NULL, /* re-attach tty and password */
|
|
*old_pass = NULL;
|
|
|
|
extern char *FromUserHost;
|
|
|
|
|
|
int cx_line = 0;
|
|
char cx_file[BIG_BUFFER_SIZE/4]; /* debug file info */
|
|
char cx_function[BIG_BUFFER_SIZE/4];
|
|
extern int doing_privmsg, doing_notice;
|
|
|
|
|
|
|
|
|
|
time_t idle_time = 0,
|
|
now = 0,
|
|
start_time;
|
|
fd_set readables, writables;
|
|
struct in_addr nat_address;
|
|
|
|
|
|
static void quit_response (char *, char *);
|
|
static void versionreply (void);
|
|
static char *parse_args (char **, int, char **);
|
|
static void remove_pid(void);
|
|
void do_ansi_logo(int);
|
|
|
|
extern void set_process_bits(fd_set *rd);
|
|
|
|
static volatile int cntl_c_hit = 0;
|
|
|
|
char version[] = _VERSION_;
|
|
|
|
static char *switch_help[] = {
|
|
"Usage: BitchX [switches] [nickname] [server list] \n",
|
|
" The [nickname] can be at most 15 characters long\n",
|
|
" The [server list] is a whitespace separate list of server name\n",
|
|
" The [switches] may be any or all of the following\n",
|
|
#ifndef WINNT
|
|
" -H <hostname>\tuses the virtual hostname if possible\n",
|
|
#endif
|
|
" -N do not auto-connect to the first server\n",
|
|
" -A do not display the startup ansi\n",
|
|
" -c <channel>\tjoins <channel> on startup. don\'t forget to escape the # using \\\n",
|
|
#if defined(WINNT) || defined(__EMX__)
|
|
" -b\t\tload bx-rc or irc-rc after connecting to a server\n",
|
|
#else
|
|
" -b\t\tload .bitchxrc or .ircrc after connecting to a server\n",
|
|
#endif
|
|
" -p <port>\tdefault server connection port (usually 6667)\n",
|
|
#ifndef WINNT
|
|
" -f\t\tyour terminal uses flow controls (^S/^Q), so BitchX shouldn't\n",
|
|
" -F\t\tyour terminal doesn't use flow control (default)\n",
|
|
#endif
|
|
" -d\t\truns BitchX in \"dumb\" terminal mode\n",
|
|
#if defined(WINNT) || defined(__EMX__)
|
|
" -q\t\tdoes not load ~/irc-rc\n",
|
|
#else
|
|
" -q\t\tdoes not load ~/.ircrc\n",
|
|
#endif
|
|
" -r file\tload file as list of servers\n",
|
|
" -n nickname\tnickname to use\n",
|
|
" -a\t\tadds default servers and command line servers to server list\n",
|
|
" -x\t\truns BitchX in \"debug\" mode\n",
|
|
" -Z\t\tuse NAT address when doing dcc.\n",
|
|
" -P\t\ttoggle check pid.nickname for running program.\n",
|
|
" -v\t\ttells you about the client's version\n",
|
|
#ifdef HAVE_SSL
|
|
" -s\t\tservers specified are SSL.\n",
|
|
#endif
|
|
" -i\t\tignores the autojoin list entries.\n",
|
|
#if defined(WINNT) || defined(__EMX__)
|
|
" -l <file>\tloads <file> in place of your irc-rc\n\
|
|
-L <file>\tloads <file> in place of your irc-rc and expands $ expandos\n",
|
|
#else
|
|
" -l <file>\tloads <file> in place of your .ircrc\n\
|
|
-L <file>\tloads <file> in place of your .ircrc and expands $ expandos\n",
|
|
#endif
|
|
#if !defined(WINNT) && !defined(__EMX__)
|
|
" -B\t\tforce BitchX to fork and return you to shell. pid check on.\n",
|
|
#endif
|
|
NULL };
|
|
|
|
char *time_format = NULL; /* XXX Bogus XXX */
|
|
#ifdef __EMX__
|
|
char *strftime_24hour = "%H:%M";
|
|
#else
|
|
char *strftime_24hour = "%R";
|
|
#endif
|
|
char *strftime_12hour = "%I:%M%p";
|
|
char time_str[61];
|
|
|
|
void detachcmd(char *, char *, char *, char *);
|
|
|
|
|
|
|
|
/* update_clock: figUres out the current time and returns it in a nice format */
|
|
char *BX_update_clock(int flag)
|
|
{
|
|
static int min = -1,
|
|
hour = -1;
|
|
static time_t last_minute = -1;
|
|
time_t idlet;
|
|
static struct tm time_val;
|
|
time_t hideous;
|
|
int new_minute = 0;
|
|
int new_hour = 0;
|
|
|
|
hideous = now;
|
|
|
|
#if !defined(NO_CHEATING)
|
|
if (hideous / 60 > last_minute)
|
|
{
|
|
last_minute = hideous / 60;
|
|
time_val = *localtime(&hideous);
|
|
}
|
|
#else
|
|
time_val = *localtime(&hideous);
|
|
#endif
|
|
|
|
|
|
if (flag == RESET_TIME || time_val.tm_min != min || time_val.tm_hour != hour)
|
|
{
|
|
int ofs = from_server;
|
|
from_server = primary_server;
|
|
|
|
if (time_format) /* XXXX Bogus XXXX */
|
|
strftime(time_str, 60, time_format, &time_val);
|
|
else if (get_int_var(CLOCK_24HOUR_VAR))
|
|
strftime(time_str, 60, strftime_24hour, &time_val);
|
|
else
|
|
strftime(time_str, 60, strftime_12hour, &time_val);
|
|
|
|
lower(time_str);
|
|
if ((time_val.tm_min != min) || (time_val.tm_hour != hour))
|
|
{
|
|
int is_away = 0;
|
|
if (time_val.tm_hour != hour)
|
|
new_hour = 1;
|
|
new_minute = 1;
|
|
hour = time_val.tm_hour;
|
|
min = time_val.tm_min;
|
|
do_hook(TIMER_LIST, "%02d:%02d", hour, min);
|
|
if (min == 0 || new_hour)
|
|
do_hook(TIMER_HOUR_LIST, "%02d:%02d", hour, min);
|
|
idlet = hideous - idle_time;
|
|
if (from_server != -1)
|
|
is_away = get_server_away(from_server) ? 1 : 0;
|
|
if (do_hook(IDLE_LIST, "%lu", (unsigned long)idlet / 60))
|
|
{
|
|
if (is_away && new_hour && get_int_var(TIMESTAMP_AWAYLOG_HOURLY_VAR))
|
|
logmsg(LOG_CRAP, NULL, 4, NULL);
|
|
check_auto_away(idlet);
|
|
}
|
|
check_channel_limits();
|
|
}
|
|
from_server = ofs;
|
|
if (flag != RESET_TIME || new_minute)
|
|
return time_str;
|
|
else
|
|
return NULL;
|
|
}
|
|
if (flag == GET_TIME)
|
|
return time_str;
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
void reset_clock(Window *win, char *unused, int unused1)
|
|
{
|
|
update_clock(RESET_TIME);
|
|
update_all_status(win, NULL, 0);
|
|
}
|
|
|
|
|
|
|
|
/* sig_refresh_screen: the signal-callable version of refresh_screen */
|
|
SIGNAL_HANDLER(sig_refresh_screen)
|
|
{
|
|
refresh_screen(0, NULL);
|
|
}
|
|
|
|
/* irc_exit: cleans up and leaves */
|
|
SIGNAL_HANDLER(irc_exit_old)
|
|
{
|
|
irc_exit(1,NULL, NULL);
|
|
}
|
|
|
|
volatile int dead_children_processes;
|
|
|
|
/* This is needed so that the fork()s we do to read compressed files dont
|
|
* sit out there as zombies and chew up our fd's while we read more.
|
|
*/
|
|
SIGNAL_HANDLER(child_reap)
|
|
{
|
|
dead_children_processes++;
|
|
#ifdef __EMX__
|
|
my_signal(SIGCHLD, SIG_IGN, 0);
|
|
#endif
|
|
}
|
|
|
|
SIGNAL_HANDLER(nothing)
|
|
{
|
|
/* nothing to do! */
|
|
}
|
|
|
|
SIGNAL_HANDLER(sigpipe)
|
|
{
|
|
static int sigpipe_hit = 0;
|
|
sigpipe_hit++;
|
|
|
|
}
|
|
|
|
#if 0
|
|
SIGNAL_HANDLER(sigusr2)
|
|
{
|
|
mtrace();
|
|
}
|
|
SIGNAL_HANDLER(sigusr3)
|
|
{
|
|
muntrace();
|
|
}
|
|
#endif
|
|
|
|
/* irc_exit: cleans up and leaves */
|
|
void BX_irc_exit (int really_quit, char *reason, char *format, ...)
|
|
{
|
|
char buffer[BIG_BUFFER_SIZE];
|
|
|
|
logger(current_window, NULL, 0);
|
|
if (get_int_var(MSGLOG_VAR))
|
|
log_toggle(0, NULL);
|
|
if (format)
|
|
{
|
|
va_list arglist;
|
|
va_start(arglist, format);
|
|
vsprintf(buffer, format, arglist);
|
|
va_end(arglist);
|
|
}
|
|
else
|
|
sprintf(buffer, "%s -- just do it.",irc_version);
|
|
|
|
if (really_quit)
|
|
{
|
|
put_it("%s", convert_output_format("$G Signon time : $0-", "%s", my_ctime(start_time)));
|
|
put_it("%s", convert_output_format("$G Signoff time : $0-", "%s", my_ctime(now)));
|
|
put_it("%s", convert_output_format("$G Total uptime : $0-", "%s", convert_time(now - start_time)));
|
|
}
|
|
do_hook(EXIT_LIST, "%s", reason ? reason : buffer);
|
|
|
|
close_all_servers(reason ? reason : buffer);
|
|
|
|
put_it("%s", !format && reason ? reason : buffer);
|
|
|
|
clean_up_processes();
|
|
if (!dumb_mode && term_initialized)
|
|
{
|
|
cursor_to_input(); /* Needed so that ircII doesn't gobble
|
|
* the last line of the kill. */
|
|
term_cr();
|
|
term_clear_to_eol();
|
|
term_reset();
|
|
}
|
|
|
|
destroy_call_stack();
|
|
|
|
#if defined(THREAD) && defined(WANT_NSLOOKUP)
|
|
kill_dns();
|
|
#endif
|
|
|
|
remove_pid();
|
|
if (really_quit)
|
|
{
|
|
|
|
#ifdef GUI
|
|
gui_exit();
|
|
#else
|
|
#if defined(WANT_DETACH) && !defined(GUI)
|
|
kill_attached_if_needed(0);
|
|
#endif
|
|
fprintf(stdout, "\r");
|
|
fflush(stdout);
|
|
exit(0);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
#ifndef WANT_CORE
|
|
volatile int segv_recurse = 0;
|
|
/* sigsegv: something to handle segfaults in a nice way */
|
|
/* this needs to be changed to *NOT* use printf(). */
|
|
SIGNAL_HANDLER(coredump)
|
|
{
|
|
#if defined(WINNT)
|
|
extern char *sys_siglist[];
|
|
#endif
|
|
if (segv_recurse)
|
|
_exit(1);
|
|
segv_recurse = 1;
|
|
panic_dump_call_stack();
|
|
|
|
#ifdef TDEBUG
|
|
putlog(LOG_ALL, "*", "Error logged. %s at (%d) %s", cx_file, cx_line, cx_function?cx_function:empty_string);
|
|
#endif
|
|
printf("\n\r\n\rIRCII has been terminated by a [%s]\n\r", sys_siglist[unused]);
|
|
printf("Please email " BUG_EMAIL "\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(1, "Hmmmm... BitchX error!!!! unusual :)", NULL);
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
* 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(char *dummy, char *ptr)
|
|
{
|
|
int len;
|
|
|
|
if ((len = strlen(ptr)) != 0)
|
|
if (!my_strnicmp(ptr, "yes", len))
|
|
irc_exit(1, NULL, "IRC][ %s: Rest in peace", irc_version);
|
|
}
|
|
|
|
/* irc_quit: prompts the user if they wish to exit, then does the right thing */
|
|
void irc_quit(char key, char * ptr)
|
|
{
|
|
static int in_it = 0;
|
|
|
|
if (in_it)
|
|
return;
|
|
in_it = 1;
|
|
add_wait_prompt("Do you really want to quit? ", quit_response, empty_string, WAIT_PROMPT_LINE, 1);
|
|
in_it = 0;
|
|
}
|
|
|
|
/*
|
|
* cntl_c: emergency exit.... if somehow everything else freezes up, hitting
|
|
* ^C five times should kill the program.
|
|
*/
|
|
SIGNAL_HANDLER(cntl_c)
|
|
{
|
|
|
|
if (cntl_c_hit++ >= 4)
|
|
irc_exit(1, "User abort with 5 Ctrl-C's", NULL);
|
|
else if (cntl_c_hit > 1)
|
|
kill(getpid(), SIGALRM);
|
|
}
|
|
|
|
SIGNAL_HANDLER(sig_user1)
|
|
{
|
|
bitchsay("Got SIGUSR1, closing DCC connections and EXECed processes");
|
|
close_all_dcc();
|
|
clean_up_processes();
|
|
}
|
|
|
|
|
|
SIGNAL_HANDLER(sig_detach)
|
|
{
|
|
detachcmd(NULL, NULL, NULL, NULL);
|
|
}
|
|
|
|
void set_detach_on_hup(Window *dummy, char *unused, int value)
|
|
{
|
|
if(value)
|
|
my_signal(SIGHUP, sig_detach, 0);
|
|
else
|
|
my_signal(SIGHUP, irc_exit_old, 0);
|
|
}
|
|
|
|
/* shows the version of irc */
|
|
static void versionreply(void)
|
|
{
|
|
printf("BitchX version %s (%s)\n\r", irc_version, internal_version);
|
|
exit (0);
|
|
}
|
|
|
|
#ifndef RAND_MAX
|
|
#define RAND_MAX 2147483647
|
|
#endif
|
|
|
|
void display_bitchx(int j)
|
|
{
|
|
|
|
int i = 0;
|
|
int old_strip_ansi = strip_ansi_in_echo;
|
|
|
|
strip_ansi_in_echo = 0;
|
|
|
|
if (j == -1)
|
|
#ifdef ASCII_LOGO
|
|
i = (int) (5.0*rand()/RAND_MAX);
|
|
#else
|
|
i = (int) (17.0*rand()/RAND_MAX);
|
|
#endif
|
|
else
|
|
i = j;
|
|
|
|
if (!startup_ansi)
|
|
return;
|
|
|
|
#if !defined(WINNT) && !defined(__EMX__)
|
|
charset_ibmpc();
|
|
#endif
|
|
|
|
do_ansi_logo(i);
|
|
#if !defined(WINNT) && !defined(__EMX__)
|
|
#if defined(LATIN1)
|
|
charset_lat1();
|
|
#elif defined(CHARSET_CUSTOM)
|
|
charset_cst();
|
|
#endif
|
|
|
|
#endif
|
|
strip_ansi_in_echo = old_strip_ansi;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* parse_args: parse command line arguments for irc, and sets all initial
|
|
* flags, etc.
|
|
*
|
|
* major rewrite 12/22/94 -jfn
|
|
*
|
|
*
|
|
* Im going to break backwards compatability here: I think that im
|
|
* safer in doing this becuase there are a lot less shell script with
|
|
* the command line flags then there are ircII scripts with old commands/
|
|
* syntax that would be a nasty thing to break..
|
|
*
|
|
* Sanity check:
|
|
* Supported flags: -b, -l, -v, -c, -p, -f, -F, -L, -a, -S, -z
|
|
* New (changed) flags: -s, -I, -i, -n
|
|
*
|
|
* Rules:
|
|
* Each flag must be included by a hyphen: -lb <filename> is not the
|
|
* same as -l <filename> -b any more...
|
|
* Each flag may or may not have a space between the flag and the argument.
|
|
* -lfoo is the same as -l foo
|
|
* Anything surrounded by quotation marks is honored as one word.
|
|
* The -c, -p, -L, -l, -s, -z flags all take arguments. If no argumenTs
|
|
* are given between the flag and the next flag, an error
|
|
* message is printed and the program is halted.
|
|
* Exception: the -s flag will be accepted without a argument.
|
|
* (ick: backwards compatability sucks. ;-)
|
|
* Arguments occuring after a flag that does not take an argument
|
|
* will be parsed in the following way: the first instance
|
|
* will be an assumed nickname, and the second instance will
|
|
* will be an assumed server. (some semblance of back compat.)
|
|
* The -bl sequence will emit a depreciated feature warning.
|
|
* The -I flag forces you to become invisible <NOT YET SUPPORTED>
|
|
* The -i flag forces you to become visible <NOT YET SUPPORTED>
|
|
* The -X flag forces ircII to become an X application <NOT YET SUPPORTED>
|
|
* The -n flag means "nickname"
|
|
*
|
|
* Bugs:
|
|
* The -s flag is hard to use without an argument unless youre careful.
|
|
*/
|
|
#ifdef CLOAKED
|
|
extern char **Argv;
|
|
extern char *LastArgv;
|
|
#endif
|
|
|
|
|
|
static char *parse_args (char *argv[], int argc, char **envp)
|
|
{
|
|
int ac;
|
|
int add_servers = 0;
|
|
#if !defined(WINNT)
|
|
struct passwd *entry;
|
|
#endif
|
|
char *channel = NULL;
|
|
struct hostent * hp;
|
|
char *ptr;
|
|
|
|
*nickname = 0;
|
|
|
|
#ifdef CLOAKED
|
|
Argv = argv;
|
|
while (*envp)
|
|
envp++;
|
|
LastArgv = envp[-1] + strlen(envp[-1]);
|
|
#endif
|
|
|
|
for ( ac = 1; ac < argc; ac++ )
|
|
{
|
|
if (argv[ac][0] == '-')
|
|
{
|
|
switch (argv[ac][1]) {
|
|
|
|
case 'A': /* turn off startup ansi */
|
|
startup_ansi = 0;
|
|
break;
|
|
case 'v': /* Output ircII version */
|
|
{
|
|
versionreply();
|
|
/* NOTREACHED */
|
|
}
|
|
|
|
case 'c': /* Default channel to join */
|
|
{
|
|
char *what = empty_string;
|
|
|
|
if (argv[ac][2])
|
|
what = &(argv[ac][2]);
|
|
else if (argv[ac+1] && argv[ac+1][0] != '-')
|
|
{
|
|
what = argv[ac+1];
|
|
ac++;
|
|
}
|
|
else
|
|
{
|
|
fprintf(stderr, "Missing parameter after -c\n");
|
|
exit(1);
|
|
}
|
|
malloc_strcpy(&channel, what);
|
|
break;
|
|
}
|
|
|
|
case 'p': /* Default port to use */
|
|
{
|
|
char *what = empty_string;
|
|
if (reconnect)
|
|
{
|
|
what = getpass("Enter password : ");
|
|
if (what && *what)
|
|
malloc_strcpy(&old_pass, what);
|
|
break;
|
|
}
|
|
|
|
if (argv[ac][2])
|
|
what = &argv[ac][2];
|
|
else if (argv[ac+1] && argv[ac+1][0] != '-')
|
|
{
|
|
what = argv[ac+1];
|
|
ac++;
|
|
}
|
|
else
|
|
{
|
|
fprintf(stderr, "Missing parameter after -p\n");
|
|
exit(1);
|
|
}
|
|
irc_port = my_atol(what);
|
|
break;
|
|
}
|
|
#ifndef WINNT
|
|
case 'f': /* Use flow control */
|
|
{
|
|
use_flow_control = 1;
|
|
if (argv[ac][2])
|
|
fprintf(stderr, "Ignoring junk after -f\n");
|
|
break;
|
|
}
|
|
|
|
case 'F': /* dont use flow control */
|
|
{
|
|
use_flow_control = 0;
|
|
if (argv[ac][2])
|
|
fprintf(stderr, "Ignoring junk after -F\n");
|
|
break;
|
|
}
|
|
#endif
|
|
case 'd': /* use dumb mode */
|
|
{
|
|
dumb_mode = 1;
|
|
if (argv[ac][2])
|
|
fprintf(stderr, "Ignoring junk after -d\n");
|
|
break;
|
|
}
|
|
|
|
case 'l': /* Load some file instead of ~/.ircrc */
|
|
{
|
|
char *what = empty_string;
|
|
|
|
if (argv[ac][2])
|
|
what = &argv[ac][2];
|
|
else if (argv[ac+1] && argv[ac+1][0] != '-')
|
|
{
|
|
what = argv[ac+1];
|
|
ac++;
|
|
}
|
|
else
|
|
{
|
|
fprintf(stderr, "Missing argument to -l\n");
|
|
exit(1);
|
|
}
|
|
malloc_strcpy(&new_script, what);
|
|
break;
|
|
}
|
|
|
|
case 'L': /* load and expand */
|
|
{
|
|
char *what = empty_string;
|
|
|
|
if (argv[ac][2])
|
|
what = &argv[ac][2];
|
|
else if (argv[ac+1] && argv[ac+1][0] != '-')
|
|
{
|
|
what = argv[ac+1];
|
|
ac++;
|
|
}
|
|
else
|
|
{
|
|
fprintf(stderr, "Missing argument to -L\n");
|
|
exit(1);
|
|
}
|
|
malloc_strcpy(&ircrc_file, what);
|
|
/* malloc_strcat(&ircrc_file, " -");*/
|
|
break;
|
|
}
|
|
|
|
case 'r': /* Load list of servers from this file */
|
|
{
|
|
char *what = empty_string;
|
|
|
|
if (argv[ac][2])
|
|
what = &argv[ac][2];
|
|
else if (argv[ac+1] && argv[ac+1][0] != '-')
|
|
{
|
|
what = argv[ac+1];
|
|
ac++;
|
|
}
|
|
else
|
|
fprintf(stderr, "Missing argumenT to -r\n");
|
|
|
|
if (*what)
|
|
{
|
|
add_servers = 1;
|
|
malloc_strcpy(&ircservers_file, what);
|
|
}
|
|
break;
|
|
}
|
|
case 'R':
|
|
fprintf(stderr, "Use \"scr-bx\" to reconnect\r\n");
|
|
exit(1);
|
|
break;
|
|
case 'a': /* add server, not replace */
|
|
{
|
|
add_servers = 1;
|
|
if (argv[ac][2])
|
|
fprintf(stderr, "Ignoring junk after -a\n");
|
|
break;
|
|
}
|
|
|
|
case 'q': /* quick startup -- no .ircrc */
|
|
{
|
|
quick_startup = 1;
|
|
if (argv[ac][2])
|
|
fprintf(stderr, "Ignoring junk after -q\n");
|
|
break;
|
|
}
|
|
|
|
case 'b':
|
|
{
|
|
bflag = 0;
|
|
break;
|
|
}
|
|
|
|
case 'B':
|
|
{
|
|
if (argv[ac][2] && argv[ac][2] != 'l')
|
|
fprintf(stderr, "Ignoring junk after -B\n");
|
|
else if (argv[ac][2] == 'l')
|
|
{
|
|
fprintf(stderr, "Usage of -bl is decprecated: use -b -l instead.\n");
|
|
exit(1);
|
|
}
|
|
/* dumb_mode = 1;*/
|
|
/* use_input = 0;*/
|
|
background = 1;
|
|
}
|
|
case 'P':
|
|
{
|
|
do_check_pid ^= 1;
|
|
break;
|
|
}
|
|
case 'n':
|
|
{
|
|
char *what = empty_string;
|
|
|
|
if (argv[ac][2])
|
|
what = &(argv[ac][2]);
|
|
else if (argv[ac+1] && argv[ac+1][0] != '-')
|
|
{
|
|
what = argv[ac+1];
|
|
ac++;
|
|
}
|
|
else
|
|
{
|
|
fprintf(stderr,"Missing argument for -n\n");
|
|
exit(1);
|
|
}
|
|
strlcpy(nickname, what, sizeof nickname);
|
|
break;
|
|
}
|
|
case 'N':
|
|
{
|
|
auto_connect = 0;
|
|
break;
|
|
}
|
|
case 'x': /* set server debug */
|
|
{
|
|
x_debug = (unsigned long)0xffffffff;
|
|
if (argv[ac][2])
|
|
fprintf(stderr, "Ignoring junk after -x\n");
|
|
break;
|
|
}
|
|
case 'Z':
|
|
{
|
|
use_nat_address = 1;
|
|
break;
|
|
}
|
|
|
|
case 'z':
|
|
{
|
|
char *what;
|
|
if (argv[ac][2])
|
|
what = &argv[ac][2];
|
|
else if (argv[ac+1] && argv[ac+1][0] != '-')
|
|
{
|
|
what = argv[ac+1];
|
|
ac++;
|
|
}
|
|
else
|
|
break;
|
|
strlcpy(username, what, sizeof username);
|
|
break;
|
|
}
|
|
case 'H':
|
|
{
|
|
char *what = empty_string;
|
|
|
|
if (argv[ac][2])
|
|
what = &(argv[ac][2]);
|
|
else if (argv[ac+1] && argv[ac+1][0] != '-')
|
|
{
|
|
what = argv[ac+1];
|
|
ac++;
|
|
}
|
|
else
|
|
{
|
|
fprintf(stderr, "You forgot to specify a hostname\n");
|
|
|
|
exit(1);
|
|
}
|
|
malloc_strcpy(&LocalHostName, what);
|
|
break;
|
|
}
|
|
case 'S':
|
|
use_socks = 1;
|
|
break;
|
|
case 'i':
|
|
do_ignore_ajoin = 1;
|
|
break;
|
|
#ifdef HAVE_SSL
|
|
case 's':
|
|
do_use_ssl = 1;
|
|
break;
|
|
#endif
|
|
case '\0':
|
|
break; /* ignore - alone */
|
|
|
|
default:
|
|
fprintf(stderr, "Unknown flag: %s\n",argv[ac]);
|
|
case 'h':
|
|
{
|
|
int t = 0;
|
|
|
|
while(switch_help[t])
|
|
{
|
|
fprintf(stderr, "%s", switch_help[t]);
|
|
t++;
|
|
}
|
|
exit(1);
|
|
}
|
|
} /* End of switch */
|
|
}
|
|
else
|
|
{
|
|
if (!strchr(argv[ac], '.') && !strchr(argv[ac], ',') && !*nickname)
|
|
strlcpy(nickname, argv[ac], sizeof nickname);
|
|
else
|
|
build_server_list(argv[ac]);
|
|
#ifdef HAVE_SSL
|
|
do_use_ssl = 0;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
if (!*nickname && (ptr = getenv("IRCNICK")))
|
|
strlcpy(nickname, ptr, sizeof nickname);
|
|
|
|
if (!ircservers_file)
|
|
#if defined(WINNT) || defined(__EMX__)
|
|
malloc_strcpy(&ircservers_file, "irc-serv");
|
|
#else
|
|
malloc_strcpy(&ircservers_file, ".ircservers");
|
|
#endif
|
|
/* v-- right there was a '!' that should not have been there. */
|
|
if ((ptr = getenv("IRCLIB")))
|
|
{
|
|
malloc_strcpy(&irc_lib, ptr);
|
|
malloc_strcat(&irc_lib, "/");
|
|
}
|
|
else
|
|
malloc_strcpy(&irc_lib, IRCLIB);
|
|
|
|
if (!ircrc_file && (ptr = getenv("IRCRC")))
|
|
malloc_strcpy(&ircrc_file, ptr);
|
|
|
|
if ((ptr = getenv("IRCUMODE")))
|
|
malloc_strcpy(&send_umode, ptr);
|
|
|
|
if ((ptr = getenv("IRCNAME")))
|
|
strlcpy(realname, ptr, sizeof realname);
|
|
else if ((ptr = getenv("NAME")))
|
|
strlcpy(realname, ptr, sizeof realname);
|
|
|
|
if ((ptr = getenv("IRCPATH")))
|
|
malloc_strcpy(&irc_path, ptr);
|
|
else
|
|
{
|
|
#ifdef IRCPATH
|
|
malloc_strcpy(&irc_path, IRCPATH);
|
|
#else
|
|
malloc_strcpy(&irc_path, ".:~/.irc:");
|
|
malloc_strcat(&irc_path, irc_lib);
|
|
malloc_strcat(&irc_path, "script");
|
|
#endif
|
|
}
|
|
|
|
set_string_var(LOAD_PATH_VAR, irc_path);
|
|
new_free(&irc_path);
|
|
|
|
/*
|
|
* Yes... this is EXACTLY what you think it is. And if you don't know..
|
|
* then I'm not about to tell you! -- Jake [WinterHawk] Khuon
|
|
*
|
|
* Here we determine our username. It may be set above, by the -z command line
|
|
* option. If not check IRCUSER, then USER, then the IDENT_HACK file, then
|
|
* fallback to gecos below.
|
|
*/
|
|
if (!*username && (ptr = getenv("IRCUSER"))) strlcpy(username, ptr, sizeof username);
|
|
else if (!*username && (ptr = getenv("USER"))) strlcpy(username, ptr, sizeof username);
|
|
else if (!*username)
|
|
{
|
|
#ifdef IDENT_FAKE
|
|
char *p = NULL, *q = NULL;
|
|
FILE *f;
|
|
malloc_sprintf(&p, "~/%s", get_string_var(IDENT_HACK_VAR));
|
|
q = expand_twiddle(p);
|
|
if ((f = fopen(q, "r")))
|
|
{
|
|
fgets(username, NAME_LEN, f);
|
|
if (*username && strchr(username, '\n'))
|
|
username[strlen(username)-1] = 0;
|
|
}
|
|
fclose(f);
|
|
new_free(&p); new_free(&q);
|
|
if (!*username)
|
|
#endif
|
|
strlcpy(username, "Unknown", sizeof username);
|
|
|
|
}
|
|
|
|
#ifndef WINNT
|
|
if ((entry = getpwuid(getuid())))
|
|
{
|
|
if (!*realname && entry->pw_gecos && *(entry->pw_gecos))
|
|
{
|
|
#ifdef GECOS_DELIMITER
|
|
if ((ptr = strchr(entry->pw_gecos, GECOS_DELIMITER)))
|
|
*ptr = 0;
|
|
#endif
|
|
/* The first '&' character in pw_gecos is replaced with pw_name */
|
|
if ((ptr = strchr(entry->pw_gecos, '&')))
|
|
*ptr = 0;
|
|
|
|
strlcpy(realname, entry->pw_gecos, sizeof realname);
|
|
|
|
if (ptr)
|
|
{
|
|
size_t len = ptr - entry->pw_gecos;
|
|
|
|
strlcat(realname, entry->pw_name, sizeof realname);
|
|
strlcat(realname, ptr + 1, sizeof realname);
|
|
|
|
/* Make the first character of the username uppercase, if
|
|
it's preceeded by a space */
|
|
if (len < sizeof realname && *(entry->pw_name) &&
|
|
(len == 0 || isspace((unsigned char)realname[len - 1])))
|
|
{
|
|
realname[len] = toupper((unsigned char)realname[len]);
|
|
}
|
|
}
|
|
}
|
|
if (entry->pw_name && *(entry->pw_name) && !*username)
|
|
strlcpy(username, entry->pw_name, sizeof username);
|
|
if (entry->pw_dir && *(entry->pw_dir))
|
|
malloc_strcpy(&my_path, entry->pw_dir);
|
|
}
|
|
#else
|
|
{
|
|
u_long size=NAME_LEN+1;
|
|
if (!(ptr = getenv("IRCUSER")))
|
|
strcpy(username, "unknown");
|
|
else
|
|
strncpy(username,ptr, size);
|
|
}
|
|
#endif
|
|
|
|
if ((ptr = getenv("HOME")))
|
|
malloc_strcpy(&my_path, ptr);
|
|
else if (!my_path || !*my_path)
|
|
#ifdef WINNT
|
|
malloc_strcpy(&my_path, empty_string);
|
|
#else
|
|
malloc_strcpy(&my_path, "/");
|
|
#endif
|
|
#if defined(WINNT) || defined(__EMX__)
|
|
convert_unix(my_path);
|
|
#endif
|
|
if (!*realname)
|
|
strlcpy(realname, "* I'm too lame to read BitchX.doc *", sizeof realname);
|
|
|
|
if (!LocalHostName && ((ptr = getenv("IRC_HOST")) || (ptr = getenv("IRCHOST"))))
|
|
LocalHostName = m_strdup(ptr);
|
|
|
|
if ((gethostname(hostname, sizeof(hostname))))
|
|
if (!LocalHostName)
|
|
exit(1);
|
|
|
|
if (LocalHostName)
|
|
{
|
|
printf("Your hostname appears to be [%s]\n", LocalHostName);
|
|
#ifndef IPV6
|
|
memset((void *)&LocalHostAddr, 0, sizeof(LocalHostAddr));
|
|
if ((hp = gethostbyname(LocalHostName)))
|
|
memcpy((void *)&LocalHostAddr.sf_addr, hp->h_addr, sizeof(struct in_addr));
|
|
}
|
|
else
|
|
{
|
|
if ((hp = gethostbyname(hostname)))
|
|
memcpy((char *) &MyHostAddr.sf_addr, hp->h_addr, sizeof(struct in_addr));
|
|
#endif
|
|
}
|
|
|
|
if (!*nickname)
|
|
strlcpy(nickname, username, sizeof nickname);
|
|
|
|
if (!check_nickname(nickname))
|
|
{
|
|
fprintf(stderr, "Illegal nickname %s\n", nickname);
|
|
fprintf(stderr, "Please restart IRC II with a valid nickname\n");
|
|
exit(1);
|
|
}
|
|
if (ircrc_file == NULL)
|
|
{
|
|
ircrc_file = (char *) new_malloc(strlen(my_path) + strlen(IRCRC_NAME) + 1);
|
|
strcpy(ircrc_file, my_path);
|
|
strcat(ircrc_file, IRCRC_NAME);
|
|
}
|
|
if (bircrc_file == NULL)
|
|
#if defined(WINNT) || defined(__EMX__)
|
|
malloc_sprintf(&bircrc_file, "%s/bx-rc", my_path);
|
|
#else
|
|
malloc_sprintf(&bircrc_file, "%s/.bitchxrc", my_path);
|
|
#endif
|
|
|
|
if ((ptr = getenv("IRCPORT")))
|
|
irc_port = my_atol(ptr);
|
|
|
|
if ((ptr = getenv("IRCSERVER")))
|
|
build_server_list(ptr);
|
|
|
|
if (!server_list_size() || add_servers)
|
|
{
|
|
if (!read_server_file(ircservers_file) && !server_list_size())
|
|
{
|
|
#ifdef DEFAULT_SERVER
|
|
char *ptr = NULL;
|
|
malloc_strcpy(&ptr, DEFAULT_SERVER);
|
|
build_server_list(ptr);
|
|
new_free(&ptr);
|
|
|
|
#endif
|
|
from_server = -1;
|
|
}
|
|
}
|
|
return (channel);
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* io() is a ONE TIME THROUGH loop! It simply does ONE check on the
|
|
* file descriptors, and if there is nothing waiting, it will time
|
|
* out and drop out. It does everything as far as checking for exec,
|
|
* dcc, ttys, notify, the whole ball o wax, but it does NOT iterate!
|
|
*
|
|
* You should usually NOT call io() unless you are specifically waiting
|
|
* for something from a file descriptor. It doesnt look like bad things
|
|
* will happen if you call this elsewhere, but its long time behavior has
|
|
* not been observed. It *does* however, appear to be much more reliable
|
|
* then the old irc_io, and i even know how this works. >;-)
|
|
*/
|
|
extern void set_screens (fd_set *, fd_set *);
|
|
|
|
void BX_io (const char *what)
|
|
{
|
|
static int level = 0;
|
|
long clock_timeout = 0;
|
|
struct timeval my_now,
|
|
my_timer,
|
|
timeout;
|
|
int hold_over, rc;
|
|
fd_set rd, wd;
|
|
static int old_level = 0;
|
|
static const char *caller[51] = { NULL }; /* XXXX */
|
|
static int last_warn = 0;
|
|
|
|
level++;
|
|
|
|
if (x_debug & DEBUG_WAITS)
|
|
{
|
|
if (level != old_level)
|
|
{
|
|
yell("Moving from io level [%d] to level [%d] from [%s]", old_level, level, what);
|
|
old_level = level;
|
|
}
|
|
}
|
|
|
|
|
|
if (level && (level - last_warn == 5))
|
|
{
|
|
last_warn = level;
|
|
yell("io's nesting level is [%d], [%s]<-[%s]<-[%s]<-[%s]<-[%s]<-[%s]", level, what, caller[level-1], caller[level-2], caller[level-3], caller[level-4], caller[level-5]);
|
|
if ((level % 30) == 0)
|
|
ircpanic("Ahoy there matey! Abandon ship!");
|
|
return;
|
|
}
|
|
else if (level && (last_warn -level == 5))
|
|
last_warn -= 5;
|
|
|
|
caller[level] = what;
|
|
|
|
get_time(&my_now);
|
|
now = my_now.tv_sec;
|
|
|
|
/* CHECK FOR CPU SAVER MODE */
|
|
if (!cpu_saver && get_int_var(CPU_SAVER_AFTER_VAR))
|
|
if (now - idle_time > get_int_var(CPU_SAVER_AFTER_VAR) * 60)
|
|
cpu_saver_on(0, NULL);
|
|
|
|
rd = readables;
|
|
wd = writables;
|
|
FD_ZERO(&wd);
|
|
FD_ZERO(&rd);
|
|
|
|
#ifndef GUI
|
|
set_screens(&rd, &wd);
|
|
#endif
|
|
set_process_bits(&rd);
|
|
set_socket_read(&rd, &wd);
|
|
set_nslookupfd(&rd);
|
|
#ifdef GUI
|
|
gui_setfd(&rd);
|
|
#endif
|
|
|
|
clock_timeout = 60 - (my_now.tv_sec % 60);
|
|
if (cpu_saver && get_int_var(CPU_SAVER_EVERY_VAR))
|
|
clock_timeout += (get_int_var(CPU_SAVER_EVERY_VAR) - 1) * 60;
|
|
|
|
my_timer.tv_sec = my_now.tv_sec + clock_timeout;
|
|
my_timer.tv_usec = 0;
|
|
|
|
set_server_bits(&rd, &wd, &my_timer);
|
|
|
|
tclTimerTimeout(&my_timer);
|
|
|
|
TimerTimeout(&my_timer);
|
|
|
|
if ((hold_over = unhold_windows()) || time_cmp(&my_timer, &my_now) < 0)
|
|
{
|
|
timeout.tv_sec = 0;
|
|
timeout.tv_usec = 0;
|
|
}
|
|
else
|
|
{
|
|
timeout.tv_sec = my_timer.tv_sec - my_now.tv_sec;
|
|
timeout.tv_usec = my_timer.tv_usec - my_now.tv_usec;
|
|
if (timeout.tv_usec < 0)
|
|
{
|
|
timeout.tv_sec--;
|
|
timeout.tv_usec += 1000000;
|
|
}
|
|
}
|
|
|
|
/* GO AHEAD AND WAIT FOR SOME DATA TO COME IN */
|
|
switch ((rc = new_select(&rd, &wd, &timeout)))
|
|
{
|
|
case 0:
|
|
do_idle_server();
|
|
break;
|
|
case -1:
|
|
{
|
|
/* if we just got a sigint */
|
|
if (cntl_c_hit)
|
|
{
|
|
edit_char('\003');
|
|
/* cntl_c_hit = 0; */
|
|
}
|
|
else if (errno != EINTR)
|
|
yell("Select failed with [%s]", strerror(errno));
|
|
break;
|
|
|
|
}
|
|
|
|
/* we got something on one of the descriptors */
|
|
default:
|
|
{
|
|
cntl_c_hit = 0;
|
|
get_time(&my_now);
|
|
now = my_now.tv_sec;
|
|
make_window_current(NULL);
|
|
do_server(&rd, &wd);
|
|
do_processes(&rd);
|
|
do_screens(&rd);
|
|
#ifdef WANT_CDCC
|
|
dcc_sendfrom_queue();
|
|
#endif
|
|
dcc_check_idle();
|
|
print_nslookup(&rd);
|
|
scan_sockets(&rd, &wd);
|
|
#ifdef GUI
|
|
scan_gui(&rd);
|
|
#endif
|
|
break;
|
|
}
|
|
}
|
|
|
|
get_time(&my_now);
|
|
now = my_now.tv_sec;
|
|
ExecuteTimers();
|
|
#ifdef WANT_TCL
|
|
check_utimers();
|
|
#endif
|
|
send_from_server_queue();
|
|
get_child_exit(-1);
|
|
|
|
if (!hold_over)
|
|
cursor_to_input();
|
|
|
|
|
|
#ifdef WANT_LLOOK
|
|
if (get_int_var(LLOOK_VAR) && from_server > -1 && !get_server_linklook(from_server))
|
|
{
|
|
if (now - get_server_linklook_time(from_server) > get_int_var(LLOOK_DELAY_VAR))
|
|
{
|
|
set_server_linklook(from_server, get_server_linklook(from_server)+1);
|
|
my_send_to_server(from_server, "LINKS");
|
|
set_server_linklook_time(from_server, now);
|
|
}
|
|
}
|
|
#endif
|
|
if (update_clock(RESET_TIME))
|
|
{
|
|
do_notify();
|
|
#ifdef WANT_TCL
|
|
check_timers();
|
|
#endif
|
|
clean_whowas_chan_list();
|
|
clean_whowas_list();
|
|
clean_flood_list();
|
|
clean_split_server_list(CHAN_SPLIT, 1800);
|
|
#ifdef WANT_LLOOK
|
|
clean_split_server_list(LLOOK_SPLIT, 3600);
|
|
#endif
|
|
if (get_int_var(CLOCK_VAR) || check_mail_status())
|
|
{
|
|
update_all_status(current_window, NULL, 0);
|
|
cursor_to_input();
|
|
}
|
|
check_server_connect(from_server);
|
|
}
|
|
|
|
/* (set in term.c) -- we should redraw the screen here */
|
|
if (need_redraw)
|
|
refresh_screen(0, NULL);
|
|
|
|
FromUserHost = empty_string;
|
|
|
|
|
|
alloca(0);
|
|
caller[level] = NULL;
|
|
level--;
|
|
return;
|
|
}
|
|
|
|
char pidfile[80];
|
|
|
|
void check_pid(void)
|
|
{
|
|
char *p = NULL;
|
|
FILE *t;
|
|
if (!do_check_pid)
|
|
return;
|
|
p = expand_twiddle(DEFAULT_CTOOLZ_DIR);
|
|
snprintf(pidfile, sizeof pidfile, "%s/pid.%s", p, nickname);
|
|
if ((t = fopen(pidfile, "r")))
|
|
{
|
|
char buffer[80];
|
|
int i;
|
|
fgets(buffer, 10, t);
|
|
i = atol(buffer);
|
|
kill(i, SIGCHLD);
|
|
if (errno != ESRCH)
|
|
{
|
|
fprintf(stderr, "Bitchx already running as %s\n", nickname);
|
|
exit(1);
|
|
}
|
|
}
|
|
}
|
|
|
|
extern int save_ipc;
|
|
|
|
static void remove_pid(void)
|
|
{
|
|
#ifdef WANT_DETACH
|
|
char *p;
|
|
FILE *t;
|
|
if (!do_check_pid)
|
|
return;
|
|
p = expand_twiddle(DEFAULT_CTOOLZ_DIR);
|
|
snprintf(pidfile, sizeof pidfile, "%s/pid.%s", p, nickname);
|
|
if ((t = fopen(pidfile, "r")))
|
|
{
|
|
#if !defined(__EMX__) && !defined(WINNT) && !defined(GUI)
|
|
SocketList *s;
|
|
fclose(t);
|
|
unlink(pidfile);
|
|
if (save_ipc != -1 && (s = get_socket(save_ipc)))
|
|
{
|
|
char buf[500];
|
|
snprintf(buf, sizeof buf, s->server, s->port);
|
|
unlink(buf);
|
|
}
|
|
#endif
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void setup_pid(void)
|
|
{
|
|
#ifdef WANT_DETACH
|
|
pid_t pid;
|
|
if (!do_check_pid)
|
|
return;
|
|
if ((pid = getpid()))
|
|
{
|
|
FILE *t;
|
|
unlink(pidfile);
|
|
if ((t = fopen(pidfile, "w")))
|
|
{
|
|
fprintf(t, "%u\n", pid);
|
|
fclose(t);
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
|
|
int main(int argc, char *argv[], char *envp[])
|
|
{
|
|
srand((unsigned)time(NULL));
|
|
time(&start_time);
|
|
time(&idle_time);
|
|
time(&now);
|
|
|
|
/* We need to zero these early */
|
|
FD_ZERO(&readables);
|
|
FD_ZERO(&writables);
|
|
|
|
/* First thing we need to do is initialize
|
|
* the global function table with the default
|
|
* function pointers.
|
|
*/
|
|
init_global_functions();
|
|
|
|
/* Setup OS/2 */
|
|
#if defined(__EMX__)
|
|
setvbuf(stdout, NULL, _IOLBF, 80);
|
|
#endif
|
|
/* Setup the GUIs */
|
|
#ifdef GUI
|
|
gui_startup(argc, argv);
|
|
#endif
|
|
|
|
#ifdef SOCKS
|
|
SOCKSinit(argv[0]);
|
|
#endif
|
|
|
|
#ifdef TDEBUG
|
|
*cx_file = 0;
|
|
cx_line = 0;
|
|
*cx_function = 0;
|
|
#endif
|
|
|
|
#if !defined(GUI)
|
|
|
|
printf("BitchX - Based on EPIC Software Labs epic ircII (1998).\r\n");
|
|
printf("Version (%s) -- Date (%s).\r\n", irc_version, internal_version);
|
|
printf("Process [%d]", getpid());
|
|
if ((isatty(0) && !background) || (!isatty(0) && background))
|
|
{
|
|
char s[90];
|
|
if (ttyname(0))
|
|
{
|
|
strncpy(s, ttyname(0), 85);
|
|
/* printf(" connected to tty [%s]", s);*/
|
|
strncpy(attach_ttyname, s, 400);
|
|
}
|
|
else if (background)
|
|
strcpy(attach_ttyname, "tty1");
|
|
}
|
|
else
|
|
dumb_mode = 1;
|
|
printf("\n");
|
|
#endif
|
|
|
|
|
|
channel = parse_args(argv, argc, envp);
|
|
check_pid();
|
|
init_socketpath();
|
|
|
|
#ifdef WANT_TCL
|
|
tcl_interp = Tcl_CreateInterp();
|
|
#endif
|
|
|
|
if (!dumb_mode && term_init(NULL))
|
|
_exit(1);
|
|
|
|
if (background)
|
|
{
|
|
#ifdef WANT_DETACH
|
|
#ifndef PUBLIC_ACCESS
|
|
detachcmd(NULL, NULL, NULL, NULL);
|
|
#else
|
|
exit(0);
|
|
#endif
|
|
#else
|
|
fprintf(stderr, "Try compiling with WANT_DETACH\r\n");
|
|
exit(0);
|
|
#endif
|
|
}
|
|
#ifndef WANT_CORE
|
|
my_signal(SIGSEGV, coredump, 0);
|
|
my_signal(SIGBUS, coredump, 0);
|
|
#endif
|
|
my_signal(SIGQUIT, SIG_IGN, 0);
|
|
#ifdef WANT_DETACH
|
|
set_detach_on_hup(NULL, NULL, DEFAULT_DETACH_ON_HUP);
|
|
#else
|
|
my_signal(SIGHUP, irc_exit_old, 0);
|
|
#endif
|
|
my_signal(SIGTERM, irc_exit_old, 0);
|
|
my_signal(SIGPIPE, SIG_IGN, 0);
|
|
my_signal(SIGINT, cntl_c, 0);
|
|
my_signal(SIGCHLD, child_reap, 0);
|
|
my_signal(SIGALRM, nothing, 0);
|
|
my_signal(SIGUSR1, sig_user1, 0);
|
|
#ifdef GTK
|
|
my_signal(SIGTTOU, SIG_IGN, 0);
|
|
#endif
|
|
#if 0
|
|
my_signal(SIGUSR1, sigusr2, 0);
|
|
my_signal(SIGUSR2, sigusr3, 0);
|
|
#endif
|
|
init_output();
|
|
|
|
if (!dumb_mode)
|
|
{
|
|
init_screen();
|
|
if (background)
|
|
{
|
|
use_input = 0;
|
|
main_screen->fdin = main_screen->fdout = open("/dev/null", O_RDWR|O_NOCTTY);
|
|
new_open(main_screen->fdin);
|
|
main_screen->fpout = fdopen(1, "w");
|
|
main_screen->fpin = fdopen(0, "r");
|
|
}
|
|
#ifndef __EMX__
|
|
my_signal(SIGCONT, term_cont, 0);
|
|
#if !defined(WINNT) && !defined(GTK)
|
|
my_signal(SIGWINCH, sig_refresh_screen, 0);
|
|
#endif
|
|
#endif
|
|
|
|
}
|
|
else
|
|
{
|
|
if (background)
|
|
{
|
|
my_signal(SIGHUP, SIG_IGN, 0);
|
|
background = 0;
|
|
#ifndef WANT_DETACH
|
|
term_reset();
|
|
fprintf(stderr, "try recompiling the client with WANT_DETACH defined\r\n");
|
|
exit(0);
|
|
use_input = 0;
|
|
#endif
|
|
}
|
|
create_new_screen();
|
|
new_window(main_screen);
|
|
}
|
|
|
|
setup_pid();
|
|
init_keys();
|
|
init_keys2();
|
|
init_variables();
|
|
init_dcc_table();
|
|
|
|
#if defined(THREAD) && defined(WANT_NSLOOKUP)
|
|
start_dns();
|
|
#endif
|
|
|
|
if (!dumb_mode)
|
|
{
|
|
build_status(current_window, NULL, 0);
|
|
update_input(UPDATE_ALL);
|
|
}
|
|
|
|
start_identd();
|
|
|
|
#ifdef WANT_TCL
|
|
tcl_init();
|
|
#ifdef WANT_TK
|
|
Tk_Init(tcl_interp);
|
|
#endif
|
|
add_tcl_vars();
|
|
#endif
|
|
#ifdef HAVE_SSL
|
|
{
|
|
char *entropy = malloc(100);
|
|
int i;
|
|
|
|
for(i=0;i<100;i++)
|
|
entropy[i] = (char) getrandom(0, 255);
|
|
|
|
/* Many systems don't have /dev/random so we seed */
|
|
RAND_seed(entropy, 100);
|
|
SSLeay_add_ssl_algorithms();
|
|
SSL_load_error_strings();
|
|
free(entropy);
|
|
}
|
|
#endif
|
|
|
|
#ifdef CLOAKED
|
|
initsetproctitle(argc, argv, envp);
|
|
setproctitle("%s", CLOAKED);
|
|
#endif
|
|
|
|
/* We move from run level 0 to run level 1
|
|
* signifying that we have completed the initial
|
|
* startup and are now ready to load scripts.
|
|
*/
|
|
run_level = 1;
|
|
|
|
display_bitchx(-1);
|
|
if (bflag)
|
|
load_scripts();
|
|
|
|
#ifdef GUI
|
|
gui_font_init();
|
|
#endif
|
|
|
|
reinit_autoresponse(current_window, NULL, 0);
|
|
if (auto_connect)
|
|
get_connected(0, -1);
|
|
else
|
|
display_server_list();
|
|
start_memdebug();
|
|
|
|
set_input(empty_string);
|
|
set_input_prompt(current_window, get_string_var(INPUT_PROMPT_VAR), 0);
|
|
|
|
/* We now move from run level 1 to run level 2
|
|
* signifying that we are in normal operation mode.
|
|
*/
|
|
run_level = 2;
|
|
|
|
for (;;)
|
|
io("main");
|
|
#ifdef GUI
|
|
gui_exit();
|
|
#else
|
|
ircpanic("get_line() returned");
|
|
#endif
|
|
return (-((int)0xdead));
|
|
}
|