1652 lines
37 KiB
C
1652 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 "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
|
|
* switches 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_LIBSSL
|
|
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 .bitchxrc 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 */
|
|
*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 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 const char * const 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-separated list of server descriptions. Each\n"
|
|
" server description is of the form hostname[:port[:password[:nick[:network]]]].\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"
|
|
" -b\t\tload " BITCHXRC_NAME " or " IRCRC_NAME " after connecting to a server\n"
|
|
" -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"
|
|
" -q\t\tdoes not load ~/" IRCRC_NAME "\n"
|
|
" -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_LIBSSL
|
|
" -s\t\tnext server specified is SSL (may be used multiple times)\n"
|
|
#endif
|
|
" -i\t\tignores the autojoin list entries\n"
|
|
" -l <file>\tloads <file> in place of your " IRCRC_NAME "\n"
|
|
" -L <file>\tloads <file> in place of your " IRCRC_NAME " and expands $ expandos\n"
|
|
#if !defined(WINNT) && !defined(__EMX__)
|
|
" -B\t\tforce BitchX to fork and return you to shell. pid check on.\n"
|
|
#endif
|
|
;
|
|
|
|
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 */
|
|
static SIGNAL_HANDLER(sig_refresh_screen)
|
|
{
|
|
refresh_screen(0, NULL);
|
|
}
|
|
|
|
/* irc_exit: cleans up and leaves */
|
|
static 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 don't
|
|
* sit out there as zombies and chew up our fds while we read more.
|
|
*/
|
|
SIGNAL_HANDLER(child_reap)
|
|
{
|
|
dead_children_processes++;
|
|
#ifdef __EMX__
|
|
my_signal(SIGCHLD, SIG_IGN, 0);
|
|
#endif
|
|
}
|
|
|
|
static SIGNAL_HANDLER(nothing)
|
|
{
|
|
/* nothing to do! */
|
|
}
|
|
|
|
SIGNAL_HANDLER(sigpipe)
|
|
{
|
|
static int sigpipe_hit = 0;
|
|
sigpipe_hit++;
|
|
|
|
}
|
|
|
|
#if 0
|
|
static SIGNAL_HANDLER(sigusr2)
|
|
{
|
|
mtrace();
|
|
}
|
|
static 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(). */
|
|
static 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.
|
|
*/
|
|
static 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);
|
|
}
|
|
|
|
static SIGNAL_HANDLER(sig_user1)
|
|
{
|
|
bitchsay("Got SIGUSR1, closing DCC connections and EXECed processes");
|
|
close_all_dcc();
|
|
clean_up_processes();
|
|
}
|
|
|
|
|
|
static 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);
|
|
}
|
|
|
|
#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
|
|
*
|
|
*
|
|
* I'm going to break backwards compatibility here: I think that I'm
|
|
* safer in doing this because there are a lot less shell scripts 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 an argument.
|
|
* (ick: backwards compatibility sucks. ;-)
|
|
* Arguments occurring 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 you're 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;
|
|
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 client version (already done) and exit */
|
|
exit(0);
|
|
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': /* don't 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_LIBSSL
|
|
case 's':
|
|
do_use_ssl = 1;
|
|
break;
|
|
#endif
|
|
case '\0':
|
|
break; /* ignore - alone */
|
|
|
|
default:
|
|
fprintf(stderr, "Unknown flag: %s\n",argv[ac]);
|
|
case 'h':
|
|
fputs(switch_help, stderr);
|
|
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_LIBSSL
|
|
/* -s flag only applies to next server specified */
|
|
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 preceded 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
|
|
if (LocalHostName)
|
|
{
|
|
struct hostent *hp;
|
|
|
|
memset(&LocalHostAddr, 0, sizeof(LocalHostAddr));
|
|
if ((hp = gethostbyname(LocalHostName)))
|
|
memcpy((void *)&LocalHostAddr.sf_addr, hp->h_addr, sizeof(struct in_addr));
|
|
}
|
|
else
|
|
{
|
|
struct hostent *hp;
|
|
|
|
if ((hp = gethostbyname(hostname)))
|
|
memcpy(&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 = m_sprintf("%s/%s", my_path, IRCRC_NAME);
|
|
|
|
if (bircrc_file == NULL)
|
|
bircrc_file = m_sprintf("%s/%s", my_path, BITCHXRC_NAME);
|
|
|
|
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 doesn't 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, "%ld\n", (long)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
|
|
|
|
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 !defined(GUI)
|
|
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();
|
|
|
|
#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_LIBSSL
|
|
{
|
|
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));
|
|
}
|