b5afd1d596
memcpy() / memmove() are standard everywhere, this lets us remove the configure script checking around bcopy() which helps building on Haiku OS.
5011 lines
124 KiB
C
5011 lines
124 KiB
C
/*
|
||
* Copyright Colten Edwards (c) 1996
|
||
*/
|
||
#include "irc.h"
|
||
static char cvsrevision[] = "$Id$";
|
||
CVS_REVISION(misc_c)
|
||
|
||
#ifdef HAVE_LIBIPHLPAPI
|
||
#define WIN32_LEAN_AND_MEAN
|
||
#include <windows.h>
|
||
#include <iphlpapi.h>
|
||
#endif
|
||
|
||
#include <stdio.h>
|
||
#include <ctype.h>
|
||
|
||
#include <sys/types.h>
|
||
#include <sys/stat.h>
|
||
#include <signal.h>
|
||
|
||
#include <sys/time.h>
|
||
#include <sys/types.h>
|
||
#ifndef __OPENNT
|
||
#include <sys/resource.h>
|
||
#endif
|
||
#include <unistd.h>
|
||
|
||
#if defined(sparc) && defined(sun4c)
|
||
#include <sys/rusage.h>
|
||
#endif
|
||
|
||
#include "struct.h"
|
||
|
||
#include "server.h"
|
||
#include "dcc.h"
|
||
#include "commands.h"
|
||
#include "vars.h"
|
||
#include "ircaux.h"
|
||
#include "lastlog.h"
|
||
#include "window.h"
|
||
#include "screen.h"
|
||
#include "who.h"
|
||
#include "hook.h"
|
||
#include "input.h"
|
||
#include "ignore.h"
|
||
#include "keys.h"
|
||
#include "names.h"
|
||
#include "alias.h"
|
||
#include "history.h"
|
||
#include "funny.h"
|
||
#include "ctcp.h"
|
||
#include "output.h"
|
||
#include "exec.h"
|
||
#include "notify.h"
|
||
#include "status.h"
|
||
#include "list.h"
|
||
#include "timer.h"
|
||
#include "userlist.h"
|
||
#include "misc.h"
|
||
#include "gui.h"
|
||
#include "cdns.h"
|
||
#include "flood.h"
|
||
#include "parse.h"
|
||
#include "whowas.h"
|
||
#include "hash2.h"
|
||
#include "cset.h"
|
||
#include "if.h"
|
||
#define MAIN_SOURCE
|
||
#include "modval.h"
|
||
|
||
#ifdef GUI
|
||
extern int guiipc[2];
|
||
extern int newscrollerpos, lastscrollerpos, lastscrollerwindow;
|
||
#endif
|
||
|
||
|
||
extern int user_count;
|
||
extern int shit_count;
|
||
extern int bot_count;
|
||
|
||
int serv_action = 0;
|
||
|
||
#ifndef WANT_CHELP
|
||
int in_chelp = 0;
|
||
#endif
|
||
|
||
LastMsg last_msg[MAX_LAST_MSG+1] = { { NULL } };
|
||
LastMsg last_dcc[MAX_LAST_MSG+1] = { { NULL } };
|
||
LastMsg last_notice[MAX_LAST_MSG+1] = { { NULL } };
|
||
LastMsg last_servermsg[MAX_LAST_MSG+1] = { { NULL } };
|
||
LastMsg last_sent_msg[MAX_LAST_MSG+1] = {{ NULL }};
|
||
LastMsg last_sent_notice[MAX_LAST_MSG+1] = {{ NULL }};
|
||
LastMsg last_sent_topic[2] = {{ NULL }};
|
||
LastMsg last_sent_wall[2] = {{ NULL }};
|
||
LastMsg last_topic[2] = {{ NULL }};
|
||
LastMsg last_wall[MAX_LAST_MSG+1] = {{ NULL }};
|
||
LastMsg last_invite_channel[2] = {{ NULL }};
|
||
LastMsg last_ctcp[2] = {{ NULL }};
|
||
LastMsg last_ctcp_reply[2] = {{ NULL }};
|
||
LastMsg last_sent_ctcp[2] = {{ NULL }};
|
||
LastMsg last_sent_dcc[MAX_LAST_MSG+1] = {{ NULL }};
|
||
|
||
extern int in_cparse;
|
||
|
||
|
||
ChannelList *idlechan_list = NULL;
|
||
|
||
extern NickTab *tabkey_array, *autoreply_array;
|
||
|
||
|
||
extern Ignore *ignored_nicks;
|
||
|
||
#ifdef REVERSE_WHITE_BLACK
|
||
char *color_str[] = {
|
||
"[0m","[0;34m","[0;32m","[0;36m","[0;31m","[0;35m","[0;33m","[0;30m",
|
||
"[1;37m","[1;34m","[1;32m","[1;36m","[1;31m","[1;35m","[1;33m","[1;30m", "[0m",
|
||
"[0;47m", "[0;41m", "[0;42m","[0;43m", "[0;44m","[0;45m","[0;46m", "[0;40m",
|
||
"[1;47m", "[1;41m", "[1;42m","[1;43m", "[1;44m","[1;45m","[1;46m", "[1;40m",
|
||
"[7m", "[1m", "[5m", "[4m"};
|
||
|
||
#else
|
||
|
||
char *color_str[] = {
|
||
"[0;30m","[0;34m","[0;32m","[0;36m","[0;31m","[0;35m","[0;33m","[0m",
|
||
"[1;30m","[1;34m","[1;32m","[1;36m","[1;31m","[1;35m","[1;33m","[1;37m", "[0m",
|
||
"[0;40m", "[0;41m", "[0;42m","[0;43m", "[0;44m","[0;45m","[0;46m", "[0;47m",
|
||
"[1;40m", "[1;41m", "[1;42m","[1;43m", "[1;44m","[1;45m","[1;46m", "[1;47m",
|
||
"[7m", "[1m", "[5m", "[4m"};
|
||
#endif
|
||
|
||
|
||
va_list VA_NULL = {0,};
|
||
|
||
char *awaymsg = NULL;
|
||
|
||
char *convert_time (time_t ltime)
|
||
{
|
||
unsigned long days = 0,hours = 0,minutes = 0,seconds = 0;
|
||
static char buffer[40];
|
||
|
||
|
||
*buffer = '\0';
|
||
seconds = ltime % 60;
|
||
ltime = (ltime - seconds) / 60;
|
||
minutes = ltime%60;
|
||
ltime = (ltime - minutes) / 60;
|
||
hours = ltime % 24;
|
||
days = (ltime - hours) / 24;
|
||
sprintf(buffer, "%2lud %2luh %2lum %2lus", days, hours, minutes, seconds);
|
||
return(*buffer ? buffer : empty_string);
|
||
}
|
||
|
||
BUILT_IN_COMMAND(do_uptime)
|
||
{
|
||
|
||
#ifdef ONLY_STD_CHARS
|
||
put_it("%s",convert_output_format("%G--[ %WBitchX%g-%wClient%g-%RStatistics %G]------------------------------------------",NULL));
|
||
put_it("%s",convert_output_format("%G| %CClient Version: %W$0 $1","%s %s", irc_version, internal_version));
|
||
put_it("%s",convert_output_format("%G| %CClient Running Since %W$0-","%s",my_ctime(start_time)));
|
||
put_it("%s",convert_output_format("%G| %CClient Uptime: %W$0-","%s",convert_time(now-start_time)));
|
||
put_it("%s",convert_output_format("%G| %CCurrent UserName: %W$0-","%s", username));
|
||
put_it("%s",convert_output_format("%G| %CCurrent RealName: %W$0-","%s", realname));
|
||
put_it("%s",convert_output_format("%G| %CLast Recv Message: %W$0-","%s",last_msg[0].last_msg?last_msg[0].last_msg:"None"));
|
||
put_it("%s",convert_output_format("%G| %CLast Recv Notice: %W$0-","%s",last_notice[0].last_msg?last_notice[0].last_msg:"None"));
|
||
put_it("%s",convert_output_format("%G| %CLast Sent Msg: %W$0-","%s",last_sent_msg[0].last_msg?last_sent_msg[0].last_msg:"None"));
|
||
put_it("%s",convert_output_format("%G| %CLast Sent Notice: %W$0-","%s",last_sent_notice[0].last_msg?last_sent_notice[0].last_msg:"None"));
|
||
put_it("%s",convert_output_format("%G| %CLast Channel invited to: %R$0-","%s",invite_channel?invite_channel:"None"));
|
||
put_it("%s",convert_output_format("%G| %cTotal Users on Userlist: %K[%R$0%K]","%d",user_count));
|
||
put_it("%s",convert_output_format("%G| %cTotal Users on Shitlist: %K[%R$0%K]","%d",shit_count));
|
||
|
||
#else
|
||
put_it("%s",convert_output_format("%G<><47>[ %WBitchX%g<>%wClient%g<>%RStatistics %G]<5D><><EFBFBD><EFBFBD>---%g<>--<2D><>%K-%g<><67><EFBFBD><EFBFBD><EFBFBD>--%G<>--<2D><>%K-%g<><67><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>--- %K--%g -",NULL));
|
||
put_it("%s",convert_output_format("%G| %CClient Version: %W$0 $1","%s %s", irc_version, internal_version));
|
||
put_it("%s",convert_output_format("%G<> %CClient Running Since %W$0-","%s",my_ctime(start_time)));
|
||
put_it("%s",convert_output_format("%G| %CClient Uptime: %W$0-","%s",convert_time(now-start_time)));
|
||
put_it("%s",convert_output_format("%G<> %CCurrent UserName: %W$0-","%s", username));
|
||
put_it("%s",convert_output_format("%G: %CCurrent RealName: %W$0-","%s", realname));
|
||
put_it("%s",convert_output_format("%G. %CLast Recv Message: %W$0-","%s",last_msg[0].last_msg?last_msg[0].last_msg:"None"));
|
||
put_it("%s",convert_output_format("%G: %CLast Recv Notice: %W$0-","%s",last_notice[0].last_msg?last_notice[0].last_msg:"None"));
|
||
put_it("%s",convert_output_format("%G. %CLast Sent Msg: %W$0-","%s",last_sent_msg[0].last_msg?last_sent_msg[0].last_msg:"None"));
|
||
put_it("%s",convert_output_format("%G: %CLast Sent Notice: %W$0-","%s",last_sent_notice[0].last_msg?last_sent_notice[0].last_msg:"None"));
|
||
put_it("%s",convert_output_format("%G<> %CLast Channel invited to: %R$0-","%s",invite_channel?invite_channel:"None"));
|
||
put_it("%s",convert_output_format("%G| %cTotal Users on Userlist: %K[%R$0%K]","%d",user_count));
|
||
put_it("%s",convert_output_format("%G<> %cTotal Users on Shitlist: %K[%R$0%K]","%d",shit_count));
|
||
|
||
#endif
|
||
}
|
||
|
||
/* extern_write -- controls whether others may write to our terminal or not. */
|
||
/* This is basically stolen from bsd -- so its under the bsd copyright */
|
||
BUILT_IN_COMMAND(extern_write)
|
||
{
|
||
char *tty;
|
||
struct stat sbuf;
|
||
const int OTHER_WRITE = 020;
|
||
int on = 0;
|
||
|
||
if (!(tty = ttyname(2)))
|
||
{
|
||
yell("Error in ttyname()");
|
||
return;
|
||
}
|
||
if (stat(tty, &sbuf) < 0)
|
||
{
|
||
yell("Error in stat()");
|
||
return;
|
||
}
|
||
if (!args || !*args)
|
||
{
|
||
if (sbuf.st_mode & 020)
|
||
bitchsay("Mesg is \002On\002");
|
||
else
|
||
bitchsay("Mesg is \002Off\002");
|
||
return;
|
||
}
|
||
if (!my_stricmp(args, "ON") || !my_stricmp(args, "YES"))
|
||
on = 1;
|
||
else if (!my_stricmp(args, "OFF") || !my_stricmp(args, "NO"))
|
||
on = 0;
|
||
else
|
||
return;
|
||
|
||
switch (on)
|
||
{
|
||
case 1 :
|
||
if (chmod(tty, sbuf.st_mode | OTHER_WRITE) < 0)
|
||
{
|
||
yell("Sorry, couldnt set your tty's mode");
|
||
return;
|
||
}
|
||
bitchsay("Mesg is \002On\002");
|
||
break;
|
||
case 0 :
|
||
if (chmod(tty, sbuf.st_mode &~ OTHER_WRITE) < 0)
|
||
{
|
||
yell("Sorry, couldnt set your tty's mode");
|
||
return;
|
||
}
|
||
bitchsay("Mesg is \002Off\002");
|
||
break;
|
||
}
|
||
|
||
}
|
||
|
||
int timer_unban (void *args, char *sub)
|
||
{
|
||
char *p = (char *)args;
|
||
char *channel;
|
||
ChannelList *chan, *chan2;
|
||
char *ban;
|
||
char *serv;
|
||
int server = from_server;
|
||
|
||
serv = next_arg(p, &p);
|
||
if (my_atol(serv) != server)
|
||
server = my_atol(serv);
|
||
if (server < 0 || server > server_list_size() || !is_server_connected(server))
|
||
server = from_server;
|
||
channel = next_arg(p, &p);
|
||
ban = next_arg(p, &p);
|
||
|
||
chan2 = get_server_channels(server);
|
||
if ((chan = (ChannelList *)find_in_list((List **)&chan2, channel, 0)) && ban_is_on_channel(ban, chan))
|
||
my_send_to_server(server, "MODE %s -b %s", channel, ban);
|
||
new_free(&serv); new_free(&sub);
|
||
return 0;
|
||
}
|
||
|
||
int timer_idlekick (void *args, char *sub)
|
||
{
|
||
char *channel = (char *)args;
|
||
ChannelList *tmp = NULL;
|
||
int kick_count = 0;
|
||
UserList *user = NULL;
|
||
|
||
|
||
if (channel && (tmp = lookup_channel(channel, from_server, CHAN_NOUNLINK)) && tmp->have_op && tmp->max_idle && tmp->check_idle)
|
||
{
|
||
NickList *nick;
|
||
for (nick = next_nicklist(tmp, NULL); nick; nick = next_nicklist(tmp, nick))
|
||
{
|
||
if (!my_stricmp(nick->nick, get_server_nickname(from_server)))
|
||
continue;
|
||
if ((nick_isop(nick) || nick_isvoice(nick)) && !get_cset_int_var(tmp->csets, KICK_OPS_CSET))
|
||
continue;
|
||
if ((user=nick->userlist) && check_channel_match(user->channels, channel))
|
||
continue;
|
||
if (now - nick->idle_time >= tmp->max_idle)
|
||
{
|
||
if (kick_count <= get_int_var(MAX_IDLEKICKS_VAR))
|
||
{
|
||
char *p = NULL;
|
||
malloc_sprintf(&p, "%s %s*!*%s", channel, nick->nick, nick->host);
|
||
send_to_server("MODE %s +b %s*!*%s", channel, nick->nick, nick->host);
|
||
send_to_server("KICK %s %s :\002%s\002: (Idle Channel User)", channel, nick->nick, version);
|
||
add_timer(0, empty_string, 60 * 1000, 1, timer_unban, m_sprintf("%d %s", from_server, p), NULL, current_window->refnum, "idle-kick");
|
||
new_free(&p);
|
||
}
|
||
else
|
||
break;
|
||
kick_count++;
|
||
}
|
||
}
|
||
}
|
||
if (tmp && tmp->max_idle && tmp->check_idle)
|
||
add_timer(0, empty_string, get_int_var(IDLE_CHECK_VAR) * 1000, 1, timer_idlekick, channel, NULL, current_window->refnum, "idle-kick");
|
||
else
|
||
new_free(&channel);
|
||
new_free(&sub);
|
||
return 0;
|
||
}
|
||
|
||
BUILT_IN_COMMAND(addidle)
|
||
{
|
||
time_t default_idle = 10 * 60;
|
||
char *channel = NULL, *p;
|
||
time_t seconds = 0;
|
||
ChannelList *tmp, *new = NULL;
|
||
|
||
if ((p = next_arg(args, &args)))
|
||
{
|
||
malloc_strcpy(&channel, make_channel(p));
|
||
if (!channel)
|
||
return;
|
||
if (args && *args)
|
||
seconds = atol(args);
|
||
|
||
if (seconds < default_idle)
|
||
seconds = default_idle;
|
||
|
||
if (!(new = (ChannelList *)find_in_list((List **)&idlechan_list, channel, 0)))
|
||
{
|
||
new = (ChannelList *)new_malloc(sizeof(ChannelList));
|
||
malloc_strcpy(&new->channel, channel);
|
||
add_to_list((List **)&idlechan_list, (List *)new);
|
||
}
|
||
new->max_idle = seconds;
|
||
new->check_idle = (my_strnicmp(command, "UN", 2) == 0) ? 0: 1;
|
||
|
||
tmp = lookup_channel(channel, from_server, CHAN_NOUNLINK);
|
||
if (!new->check_idle)
|
||
{
|
||
bitchsay("Idle checking turned %s for %s", on_off(new->check_idle), channel);
|
||
if (tmp)
|
||
tmp->check_idle = tmp->max_idle = 0;
|
||
new->max_idle = 0;
|
||
}
|
||
else
|
||
{
|
||
bitchsay("Idle checking turned %s for %s %d mins", on_off(tmp->check_idle), channel, (int)(tmp->max_idle/60));
|
||
if (tmp)
|
||
{
|
||
tmp->max_idle = new->max_idle;
|
||
tmp->check_idle = new->check_idle;
|
||
add_timer(0, empty_string, get_int_var(IDLE_CHECK_VAR) * 1000, 1, timer_idlekick, channel, NULL, current_window->refnum, "idle-check");
|
||
}
|
||
}
|
||
new_free(&channel);
|
||
}
|
||
}
|
||
|
||
BUILT_IN_COMMAND(showidle)
|
||
{
|
||
ChannelList *tmp;
|
||
char *channel = NULL;
|
||
int count = 0;
|
||
NickList *nick, *ntmp;
|
||
time_t ltime;
|
||
int server;
|
||
int sorted = 0;
|
||
while (args && *args)
|
||
{
|
||
if (!args || !*args)
|
||
break;
|
||
if ((*args == '-') && !my_strnicmp(args, "-sort", 3))
|
||
{
|
||
next_arg(args, &args);
|
||
sorted = NICKSORT_NONE;
|
||
}
|
||
else if (!my_strnicmp(args, "nick", 3) && sorted)
|
||
{
|
||
next_arg(args, &args);
|
||
sorted = NICKSORT_NICK;
|
||
}
|
||
else if (!my_strnicmp(args, "host", 3) && sorted)
|
||
{
|
||
next_arg(args, &args);
|
||
sorted = NICKSORT_HOST;
|
||
}
|
||
else if (!my_strnicmp(args, "time", 3) && sorted)
|
||
{
|
||
next_arg(args, &args);
|
||
sorted = NICKSORT_TIME;
|
||
}
|
||
else if (!my_strnicmp(args, "ip", 2) && sorted)
|
||
{
|
||
next_arg(args, &args);
|
||
sorted = NICKSORT_IP;
|
||
}
|
||
else
|
||
channel = next_arg(args, &args);
|
||
}
|
||
if (!(tmp = prepare_command(&server, channel, NO_OP)))
|
||
return;
|
||
|
||
ntmp = sorted_nicklist(tmp, sorted);
|
||
for (nick = ntmp; nick; nick = nick->next)
|
||
{
|
||
if (!count && do_hook(SHOWIDLE_HEADER_LIST, "%s %lu", tmp->channel, (unsigned long)tmp->max_idle))
|
||
put_it("%s", convert_output_format("$G %W$a%n: Idle check for %W$0%n Max Idle Time %K[%W$1- %K]", "%s %s", tmp->channel, convert_time(tmp->max_idle)));
|
||
ltime = now - nick->idle_time;
|
||
#ifdef WANT_USERLIST
|
||
if (do_hook(SHOWIDLE_LIST, "%s %s %d %lu", nick->nick, nick->host, find_user_level(nick->nick, nick->host, tmp->channel), (unsigned long)ltime))
|
||
#else
|
||
if (do_hook(SHOWIDLE_LIST, "%s %s %d %lu", nick->nick, nick->host, 0, (unsigned long)ltime))
|
||
#endif
|
||
put_it("%s", convert_output_format("$[20]0 Idle%W: %K[%n$1- %K]", "%s %s", nick->nick, convert_time(ltime)));
|
||
count++;
|
||
}
|
||
if (count)
|
||
do_hook(SHOWIDLE_FOOTER_LIST, "%s", "End of idlelist");
|
||
clear_sorted_nicklist(&ntmp);
|
||
}
|
||
|
||
BUILT_IN_COMMAND(kickidle)
|
||
{
|
||
char *channel = NULL;
|
||
ChannelList *tmp;
|
||
int kick_count = 0;
|
||
int server = from_server;
|
||
|
||
|
||
if (args && *args)
|
||
channel = next_arg(args, &args);
|
||
|
||
if ((tmp = prepare_command(&server, channel, NEED_OP)) && tmp->max_idle)
|
||
{
|
||
NickList *nick;
|
||
for (nick = next_nicklist(tmp, NULL); nick; nick = next_nicklist(tmp, nick))
|
||
{
|
||
if (!my_stricmp(nick->nick, get_server_nickname(from_server)))
|
||
continue;
|
||
if (nick->userlist && check_channel_match(nick->userlist->channels, tmp->channel))
|
||
continue;
|
||
if (nick_isop(nick))
|
||
continue;
|
||
if (now - nick->idle_time >= tmp->max_idle)
|
||
{
|
||
if (kick_count <= get_int_var(MAX_IDLEKICKS_VAR))
|
||
my_send_to_server(server, "KICK %s %s :\002%s\002: (Idle Channel User)", tmp->channel, nick->nick, version);
|
||
else
|
||
bitchsay(" found idle user %-12s channel %s", nick->nick, tmp->channel);
|
||
kick_count++;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
void save_idle(FILE *output)
|
||
{
|
||
ChannelList *chan;
|
||
int count = 0;
|
||
|
||
|
||
if (!output)
|
||
return;
|
||
if (idlechan_list)
|
||
{
|
||
fprintf(output, "# %s Idle Channel list\n", version);
|
||
for (chan = idlechan_list; chan; chan = chan->next)
|
||
{
|
||
if (chan->max_idle)
|
||
{
|
||
fprintf(output, "ADDIDLE %s %d\n", chan->channel, (int)chan->max_idle);
|
||
count++;
|
||
}
|
||
}
|
||
}
|
||
if (count && do_hook(SAVEFILE_LIST, "Idle %d", count))
|
||
bitchsay("Saved %d Idle channels", count);
|
||
}
|
||
|
||
BUILT_IN_COMMAND(channel_stats)
|
||
{
|
||
ChannelList *new = NULL;
|
||
char *channel = NULL;
|
||
WhowasChanList *new1 = NULL;
|
||
int numircops = 0;
|
||
int usershere = 0;
|
||
int usersaway = 0;
|
||
int chanops = 0;
|
||
int chanunop = 0;
|
||
char *ircops = NULL;
|
||
int server = -1;
|
||
int max_hops = 0;
|
||
|
||
NickList *l;
|
||
unsigned long nick_mem = 0,
|
||
ban_mem = 0;
|
||
BanList *b;
|
||
|
||
|
||
|
||
|
||
if (args && *args)
|
||
{
|
||
channel = next_arg(args, &args);
|
||
if (my_strnicmp(channel, "-ALL", strlen(channel)))
|
||
{
|
||
if (!(channel = make_channel(channel)))
|
||
return;
|
||
if (!(new = prepare_command(&server, channel, PC_SILENT)))
|
||
if ((channel && !(new1 = check_whowas_chan_buffer(channel, -1, 0))))
|
||
return;
|
||
}
|
||
else
|
||
{
|
||
|
||
int stats_ops= 0, stats_dops = 0, stats_bans = 0, stats_unbans = 0;
|
||
int stats_topics = 0, stats_kicks = 0, stats_pubs = 0, stats_parts = 0;
|
||
int stats_signoffs = 0, stats_joins = 0;
|
||
int total_nicks = 0, max_nicks = 0, total_bans = 0, max_bans = 0;
|
||
int stats_sops = 0, stats_sdops = 0, stats_sbans = 0, stats_sunbans = 0;
|
||
|
||
NickList *l;
|
||
BanList *b;
|
||
unsigned long chan_mem = 0;
|
||
channel = NULL;
|
||
|
||
if (from_server != -1)
|
||
{
|
||
for (new = get_server_channels(from_server); new; new = new->next)
|
||
{
|
||
if (!channel)
|
||
malloc_strcpy(&channel, new->channel);
|
||
else
|
||
{
|
||
malloc_strcat(&channel, ",");
|
||
malloc_strcat(&channel, new->channel);
|
||
}
|
||
for (l = next_nicklist(new, NULL); l; l = next_nicklist(new, l))
|
||
{
|
||
if (nick_isaway(l))
|
||
usersaway++;
|
||
else
|
||
usershere++;
|
||
if (nick_isircop(l))
|
||
{
|
||
numircops++;
|
||
malloc_strcat(&ircops, " (");
|
||
malloc_strcat(&ircops, l->nick);
|
||
malloc_strcat(&ircops, ")");
|
||
}
|
||
if (nick_isop(l))
|
||
chanops++;
|
||
else
|
||
chanunop++;
|
||
nick_mem += sizeof(NickList);
|
||
if (l->serverhops > max_hops)
|
||
max_hops = l->serverhops;
|
||
}
|
||
for (b = new->bans; b; b = b->next)
|
||
ban_mem += sizeof(BanList);
|
||
chan_mem += sizeof(ChannelList);
|
||
stats_ops += new->stats_ops;
|
||
stats_dops += new->stats_dops;
|
||
stats_bans += new->stats_bans;
|
||
stats_unbans += new->stats_unbans;
|
||
stats_topics += new->stats_topics;
|
||
stats_kicks += new->stats_kicks;
|
||
stats_pubs += new->stats_pubs;
|
||
stats_parts += new->stats_parts;
|
||
stats_signoffs += new->stats_signoffs;
|
||
stats_joins += new->stats_joins;
|
||
|
||
total_nicks += new->totalnicks;
|
||
max_nicks += new->maxnicks;
|
||
total_bans += new->totalbans;
|
||
max_bans += new->maxbans;
|
||
stats_sops += new->stats_sops;
|
||
stats_sdops += new->stats_sdops;
|
||
stats_sbans += new->stats_sbans;
|
||
stats_sunbans += new->stats_sunbans;
|
||
}
|
||
}
|
||
if (!ircops)
|
||
malloc_strcat(&ircops, empty_string);
|
||
if (do_hook(CHANNEL_STATS_LIST, "%s %s %s %lu %lu %lu %lu %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %d %s",
|
||
channel, empty_string, empty_string,
|
||
nick_mem+chan_mem+ban_mem, nick_mem,
|
||
(unsigned long)sizeof(ChannelList),ban_mem,
|
||
stats_ops, stats_dops, stats_bans, stats_unbans,
|
||
stats_topics, stats_kicks, stats_pubs, stats_parts,
|
||
stats_signoffs, stats_joins, total_bans, max_bans,
|
||
stats_sops, stats_sdops,stats_sbans, stats_sunbans,
|
||
usershere, usersaway, chanops, chanunop,total_nicks,max_nicks,
|
||
numircops, max_hops, ircops))
|
||
{
|
||
put_it("%s", convert_output_format("$G %CInformation for channels %K: %W$0", "%s", channel));
|
||
put_it("%s", convert_output_format(" MEM usage%K:%w Total%K:%w %c$0 bytes %K[%cNicks $1 b Chan $2 b Bans $3 b%K]", "%d %d %d %d", (int)(nick_mem+chan_mem+ban_mem), (int)nick_mem, (int)sizeof(ChannelList), (int)ban_mem));
|
||
put_it("%s", convert_output_format("Ops %K[%W$[-5]0%K]%w De-Ops %K[%W$[-5]1%K]%w Bans %K[%W$[-5]2%K]%w Unbans %K[%W$[-5]3%K]%w", "%u %u %u %u", stats_ops, stats_dops, stats_bans, stats_unbans));
|
||
put_it("%s", convert_output_format("Topics %K[%W$[-5]0%K]%w Kicks %K[%W$[-5]1%K]%w Publics %K[%W$[-5]2%K]%w Parts %K[%W$[-5]3%K]%w", "%u %u %u %u", stats_topics, stats_kicks, stats_pubs, stats_parts));
|
||
put_it("%s", convert_output_format("Signoffs %C[%W$[-5]0%K]%w Joins %K[%W$[-5]1%K]%w TotalBans %K[%W$[-5]2%K]%w MaxBans %K[%W$[-5]3%K]%w", "%u %u %u %u", stats_signoffs, stats_joins, total_bans, max_bans));
|
||
put_it("%s", convert_output_format("ServOps %K[%W$[-5]0%K]%w ServDeop %K[%W$[-5]1%K]%w ServBans %K[%W$[-5]2%K]%w ServUB %K[%W$[-5]3%K]%w", "%u %u %u %u", stats_sops, stats_sdops,stats_sbans, stats_sunbans));
|
||
put_it("%s", convert_output_format("Users Here %K[%W$[-5]0%K]%w Users Away %K[%W$[-5]1%K]%w Opped %K[%W$[-5]2%K]%w Unopped %K[%W$[-5]3%K]%w", "%u %u %u %u", usershere, usersaway, chanops, chanunop));
|
||
put_it("%s", convert_output_format("TotalNicks %K[%W$[-5]0%K]%w MaxNicks %K[%W$[-5]1%K]%w ServerHops %K[%W$[-5]2%K]%w", "%d %d %d", total_nicks,max_nicks, max_hops));
|
||
put_it("%s", convert_output_format("IRCops %K[%W$[3]0%K]%w$1-", "%d %s", numircops, ircops));
|
||
}
|
||
new_free(&ircops);
|
||
new_free(&channel);
|
||
return;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if (!(new = prepare_command(&server, channel, PC_SILENT)))
|
||
if ((channel && !(new1 = check_whowas_chan_buffer(channel, -1, 0))))
|
||
return;
|
||
}
|
||
|
||
if (!new && new1)
|
||
new = new1->channellist;
|
||
if (!new)
|
||
{
|
||
bitchsay("Try joining a channel first");
|
||
return;
|
||
}
|
||
if (new)
|
||
{
|
||
for (l = next_nicklist(new, NULL); l; l = next_nicklist(new, l))
|
||
{
|
||
nick_mem += sizeof(NickList);
|
||
if (nick_isaway(l))
|
||
usersaway++;
|
||
else
|
||
usershere++;
|
||
if (nick_isircop(l))
|
||
{
|
||
numircops++;
|
||
malloc_strcat(&ircops, " (");
|
||
malloc_strcat(&ircops, l->nick);
|
||
malloc_strcat(&ircops, ")");
|
||
}
|
||
if (nick_isop(l))
|
||
chanops++;
|
||
else
|
||
chanunop++;
|
||
if (l->serverhops > max_hops)
|
||
max_hops = l->serverhops;
|
||
}
|
||
for (b = new->bans; b; b = b->next)
|
||
ban_mem += sizeof(BanList);
|
||
}
|
||
if (!ircops)
|
||
malloc_strcat(&ircops, empty_string);
|
||
if (do_hook(CHANNEL_STATS_LIST, "%s %s %s %ld %ld %ld %ld %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %d %s",
|
||
new->channel, my_ctime(new->channel_create.tv_sec), convert_time(now-new->join_time.tv_sec),
|
||
nick_mem+sizeof(ChannelList)+ban_mem, nick_mem,
|
||
(unsigned long)sizeof(ChannelList),ban_mem,
|
||
new->stats_ops, new->stats_dops, new->stats_bans, new->stats_unbans,
|
||
new->stats_topics, new->stats_kicks, new->stats_pubs, new->stats_parts,
|
||
new->stats_signoffs, new->stats_joins, new->totalbans, new->maxbans,
|
||
new->stats_sops, new->stats_sdops,new->stats_sbans, new->stats_sunbans,
|
||
usershere, usersaway, chanops, chanunop,new->totalnicks,new->maxnicks,
|
||
numircops, max_hops, ircops))
|
||
{
|
||
put_it("%s", convert_output_format("$G %CInformation for channel %K: %W$0", "%s", new->channel));
|
||
put_it("%s", convert_output_format("$G %CChannel created %K: %W$0 $1 $2 $3%n in memory %W$4-", "%s %s", convert_time(now-new->channel_create.tv_sec), my_ctime(new->join_time.tv_sec)));
|
||
|
||
put_it("%s", convert_output_format(" MEM usage%K:%w Total%K:%w %c$0 bytes %K[%cNicks $1 b Chan $2 b Bans $3 b%K]", "%d %d %d %d", (int)(nick_mem+sizeof(ChannelList)+ban_mem), (int)nick_mem, (int)sizeof(ChannelList), (int)ban_mem));
|
||
put_it("%s", convert_output_format("Ops %K[%W$[-5]0%K]%w De-Ops %K[%W$[-5]1%K]%w Bans %K[%W$[-5]2%K]%w Unbans %K[%W$[-5]3%K]%w", "%u %u %u %u", new->stats_ops, new->stats_dops, new->stats_bans, new->stats_unbans));
|
||
put_it("%s", convert_output_format("Topics %K[%W$[-5]0%K]%w Kicks %K[%W$[-5]1%K]%w Publics %K[%W$[-5]2%K]%w Parts %K[%W$[-5]3%K]%w", "%u %u %u %u", new->stats_topics, new->stats_kicks, new->stats_pubs, new->stats_parts));
|
||
put_it("%s", convert_output_format("Signoffs %K[%W$[-5]0%K]%w Joins %K[%W$[-5]1%K]%w TotalBans %K[%W$[-5]2%K]%w MaxBans %K[%W$[-5]3%K]%w", "%u %u %u %u", new->stats_signoffs, new->stats_joins, new->totalbans, new->maxbans));
|
||
put_it("%s", convert_output_format("ServOps %K[%W$[-5]0%K]%w ServDeop %K[%W$[-5]1%K]%w ServBans %K[%W$[-5]2%K]%w ServUB %K[%W$[-5]3%K]%w", "%u %u %u %u", new->stats_sops, new->stats_sdops,new->stats_sbans, new->stats_sunbans));
|
||
put_it("%s", convert_output_format("Users Here %K[%W$[-5]0%K]%w Users Away %K[%W$[-5]1%K]%w Opped %K[%W$[-5]2%K]%w Unopped %K[%W$[-5]3%K]%w", "%u %u %u %u", usershere, usersaway, chanops, chanunop));
|
||
put_it("%s", convert_output_format("TotalNicks %K[%W$[-5]0%K]%w MaxNicks %K[%W$[-5]1%K]%w ServerHops %K[%W$[-5]2%K]%w", "%d %d %d", new->totalnicks,new->maxnicks, max_hops));
|
||
put_it("%s", convert_output_format("IRCops %K[%W$[3]0%K]%w$1-", "%d %s", numircops, ircops));
|
||
|
||
put_it("%s", convert_output_format(" %CThere is %R$0%C limit and limit checking is %R$1-", "%s %s", new->limit ? ltoa(new->limit): "no", new->tog_limit?"Enabled":"Disabled"));
|
||
put_it("%s", convert_output_format(" %CIdle user check is %K[%R$0-%K]", "%s", new->check_idle?"Enabled":"Disabled"));
|
||
/*put_it("%s", convert_output_format("$G End of channel stats for $0", "%s", new->channel));*/
|
||
/* wtf is do_scan in the channel struct */
|
||
}
|
||
new_free(&ircops);
|
||
|
||
}
|
||
|
||
void update_stats(int what, NickList *nick, ChannelList *chan, int splitter)
|
||
{
|
||
time_t this_time = now;
|
||
int t = 0;
|
||
|
||
|
||
if (!chan || !chan->channel)
|
||
return;
|
||
|
||
switch (what)
|
||
{
|
||
case KICKLIST:
|
||
{
|
||
chan->stats_kicks++;
|
||
chan->totalnicks--;
|
||
if (nick) nick->stat_kicks++;
|
||
break;
|
||
}
|
||
|
||
case LEAVELIST:
|
||
{
|
||
chan->stats_parts++;
|
||
chan->totalnicks--;
|
||
break;
|
||
}
|
||
case JOINLIST:
|
||
{
|
||
chan->stats_joins++;
|
||
chan->totalnicks++;
|
||
if (chan->totalnicks > chan->maxnicks)
|
||
{
|
||
chan->maxnicks = chan->totalnicks;
|
||
chan->maxnickstime = this_time;
|
||
}
|
||
if (!splitter && chan->have_op && is_other_flood(chan, nick, JOIN_FLOOD, &t) &&
|
||
get_cset_int_var(chan->csets, KICK_ON_JOINFLOOD_CSET) && !nick->sent_kick++)
|
||
{
|
||
char *t1, *host, *banstr;
|
||
t1 = LOCAL_COPY(nick->host);
|
||
host = strchr(t1, '@');
|
||
*host++ = 0;
|
||
banstr = ban_it(nick->nick, t1, host, nick->ip);
|
||
send_to_server("MODE %s -o+b %s %s", chan->channel, nick->nick, banstr);
|
||
send_to_server("KICK %s %s :\002Join flood\002 (%d joins in %dsecs of %dsecs)", chan->channel, nick->nick, get_cset_int_var(chan->csets, KICK_ON_JOINFLOOD_CSET), t, get_cset_int_var(chan->csets, JOINFLOOD_TIME_CSET));
|
||
if (get_int_var(AUTO_UNBAN_VAR))
|
||
add_timer(0, empty_string, get_int_var(AUTO_UNBAN_VAR) * 1000, 1, timer_unban, m_sprintf("%d %s %s", from_server, chan->channel, banstr), NULL, current_window->refnum, "join-flood");
|
||
}
|
||
break;
|
||
}
|
||
case CHANNELSIGNOFFLIST:
|
||
{
|
||
chan->stats_signoffs++;
|
||
chan->totalnicks--;
|
||
break;
|
||
}
|
||
case PUBLICLIST:
|
||
case PUBLICOTHERLIST:
|
||
case PUBLICNOTICELIST:
|
||
case NOTICELIST:
|
||
{
|
||
chan->stats_pubs++;
|
||
if (nick)
|
||
{
|
||
nick->stat_pub++;
|
||
nick->idle_time = this_time;
|
||
}
|
||
break;
|
||
}
|
||
case TOPICLIST:
|
||
{
|
||
chan->stats_topics++;
|
||
break;
|
||
}
|
||
case MODEOPLIST:
|
||
if (splitter)
|
||
chan->stats_sops++;
|
||
else
|
||
{
|
||
if (nick) nick->stat_ops++;
|
||
chan->stats_ops++;
|
||
}
|
||
break;
|
||
case MODEHOPLIST:
|
||
if (splitter)
|
||
chan->stats_shops++;
|
||
else
|
||
{
|
||
if (nick) nick->stat_hops++;
|
||
chan->stats_hops++;
|
||
}
|
||
break;
|
||
case MODEDEHOPLIST:
|
||
if (splitter)
|
||
chan->stats_sdehops++;
|
||
else
|
||
{
|
||
if (nick) nick->stat_dhops++;
|
||
chan->stats_dhops++;
|
||
}
|
||
break;
|
||
case MODEDEOPLIST:
|
||
if (splitter)
|
||
chan->stats_sdops++;
|
||
else
|
||
{
|
||
chan->stats_dops++;
|
||
if (nick) nick->stat_dops++;
|
||
}
|
||
|
||
if (chan->have_op && is_other_flood(chan, nick, DEOP_FLOOD, &t))
|
||
{
|
||
if (get_cset_int_var(chan->csets, DEOP_ON_DEOPFLOOD_CSET) < get_cset_int_var(chan->csets, KICK_ON_DEOPFLOOD_CSET))
|
||
send_to_server("MODE %s -o %s", chan->channel, nick->nick);
|
||
else if (!nick->sent_kick++)
|
||
send_to_server("KICK %s %s :\002De-op flood\002 (%d de-ops in %dsecs of %dsecs)", chan->channel, nick->nick, get_cset_int_var(chan->csets, KICK_ON_DEOPFLOOD_CSET), t, get_cset_int_var(chan->csets, DEOPFLOOD_TIME_CSET));
|
||
}
|
||
break;
|
||
case MODEBANLIST:
|
||
if (splitter)
|
||
chan->stats_sbans++;
|
||
else
|
||
{
|
||
if (nick) nick->stat_bans++;
|
||
chan->stats_bans++;
|
||
}
|
||
chan->totalbans++;
|
||
if (chan->stats_bans > chan->maxbans)
|
||
{
|
||
chan->maxbans = chan->stats_bans;
|
||
chan->maxbanstime = this_time;
|
||
}
|
||
break;
|
||
case MODEUNBANLIST:
|
||
if (splitter)
|
||
chan->stats_sunbans++;
|
||
else
|
||
{
|
||
if (nick) nick->stat_unbans++;
|
||
chan->stats_unbans++;
|
||
}
|
||
if (chan->totalbans) chan->totalbans--;
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
}
|
||
|
||
char *clear_server_flags (char *userhost)
|
||
{
|
||
register char *uh = userhost;
|
||
while(uh && (*uh == '~' || *uh == '#' || *uh == '+' || *uh == '-' || *uh == '=' || *uh == '^'))
|
||
uh++;
|
||
return uh;
|
||
}
|
||
|
||
|
||
#ifndef BITCHX_LITE
|
||
|
||
static char newline1[BIG_BUFFER_SIZE+1];
|
||
/*
|
||
* (max server send) and max mirc color change is 256
|
||
* so 256 * 8 should give us a safety margin for hackers.
|
||
* BIG_BUFFER is 1024 * 3 is 3072 whereas 256*8 is 2048
|
||
*/
|
||
|
||
|
||
#if 0
|
||
char *mircansi(unsigned char *line)
|
||
{
|
||
/* mconv v1.00 (c) copyright 1996 Ananda, all rights reserved. */
|
||
/* ----------------------------------------------------------- */
|
||
/* mIRC->ansi color code convertor: 12.26.96 */
|
||
/* map of mIRC color values to ansi color codes */
|
||
/* format: ansi fg color ansi bg color */
|
||
/* modified Colten Edwards */
|
||
struct {
|
||
char *fg, *bg;
|
||
} codes[16] = {
|
||
|
||
{ "[1;37m", "[47m" }, /* white */
|
||
{ "[0;30m", "[40m" }, /* black (grey for us) */
|
||
{ "[0;34m", "[44m" }, /* blue */
|
||
{ "[0;32m", "[42m" }, /* green */
|
||
{ "[0;31m", "[41m" }, /* red */
|
||
{ "[0;33m", "[43m" }, /* brown */
|
||
|
||
{ "[0;35m", "[45m" }, /* magenta */
|
||
{ "[1;31m", "[41m" }, /* bright red */
|
||
{ "[1;33m", "[43m" }, /* yellow */
|
||
|
||
{ "[1;32m", "[42m" }, /* bright green */
|
||
{ "[0;36m", "[46m" }, /* cyan */
|
||
{ "[1;36m", "[46m" }, /* bright cyan */
|
||
{ "[1;34m", "[44m" }, /* bright blue */
|
||
{ "[1;35m", "[45m" }, /* bright magenta */
|
||
{ "[1;30m", "[40m" }, /* dark grey */
|
||
{ "[0;37m", "[47m" } /* grey */
|
||
};
|
||
register unsigned char *sptr = line, *dptr = newline1;
|
||
short code;
|
||
|
||
if (!*line)
|
||
return empty_string;
|
||
*newline1 = 0;
|
||
while (*sptr) {
|
||
if (*sptr == '' && isdigit(sptr[1]))
|
||
{
|
||
sptr++;
|
||
code = atoi(sptr);
|
||
if (code > 15 || code <= 0)
|
||
continue;
|
||
while (isdigit(*sptr))
|
||
sptr++;
|
||
strcpy(dptr, codes[code].fg);
|
||
while (*dptr) dptr++;
|
||
if (*sptr == ',')
|
||
{
|
||
sptr++;
|
||
code = atoi(sptr);
|
||
if (code >= 0 && code <= 15)
|
||
{
|
||
strcpy(dptr, codes[code].bg);
|
||
while (*dptr) dptr++;
|
||
}
|
||
while (isdigit(*sptr))
|
||
sptr++;
|
||
}
|
||
}
|
||
else if (*sptr == '')
|
||
{
|
||
strcpy(dptr, "[0m");
|
||
while(*dptr) dptr++;
|
||
sptr++;
|
||
}
|
||
else *dptr++ = *sptr++;
|
||
}
|
||
*dptr = 0;
|
||
return (char *)newline1;
|
||
}
|
||
#else
|
||
char *mircansi(const char *line)
|
||
{
|
||
/* mconv v1.00 (c) copyright 1996 Ananda, all rights reserved. */
|
||
/* ----------------------------------------------------------- */
|
||
/* mIRC->ansi color code convertor: 12.26.96 */
|
||
/* map of mIRC color values to ansi color codes */
|
||
/* format: ansi fg color ansi bg color */
|
||
/* modified Colten Edwards */
|
||
static const struct {
|
||
const char *fg, *bg;
|
||
} codes[16] = {
|
||
{ "\x1b[1;37m", "\x1b[47m" }, /* white */
|
||
{ "\x1b[0;30m", "\x1b[40m" }, /* black (grey for us) */
|
||
{ "\x1b[0;34m", "\x1b[44m" }, /* blue */
|
||
{ "\x1b[0;32m", "\x1b[42m" }, /* green */
|
||
{ "\x1b[0;31m", "\x1b[41m" }, /* red */
|
||
{ "\x1b[0;33m", "\x1b[43m" }, /* brown */
|
||
{ "\x1b[0;35m", "\x1b[45m" }, /* magenta */
|
||
{ "\x1b[1;31m", "\x1b[41m" }, /* bright red */
|
||
{ "\x1b[1;33m", "\x1b[43m" }, /* yellow */
|
||
{ "\x1b[1;32m", "\x1b[42m" }, /* bright green */
|
||
{ "\x1b[0;36m", "\x1b[46m" }, /* cyan */
|
||
{ "\x1b[1;36m", "\x1b[46m" }, /* bright cyan */
|
||
{ "\x1b[1;34m", "\x1b[44m" }, /* bright blue */
|
||
{ "\x1b[1;35m", "\x1b[45m" }, /* bright magenta */
|
||
{ "\x1b[1;30m", "\x1b[40m" }, /* dark grey */
|
||
{ "\x1b[0;37m", "\x1b[47m" } /* grey */
|
||
};
|
||
|
||
const char *sptr = line;
|
||
char *dptr = newline1;
|
||
unsigned code;
|
||
|
||
if (!*line)
|
||
return empty_string;
|
||
|
||
while (*sptr)
|
||
{
|
||
if (*sptr == '\x03')
|
||
{
|
||
sptr++;
|
||
|
||
if (isdigit((unsigned char)*sptr))
|
||
{
|
||
/* ^C followed by digit*/
|
||
code = *sptr - '0';
|
||
sptr++;
|
||
|
||
if (isdigit((unsigned char)*sptr)) {
|
||
code = code * 10 + *sptr - '0';
|
||
sptr++;
|
||
}
|
||
|
||
code = code % 16;
|
||
strcpy(dptr, codes[code].fg);
|
||
while (*dptr)
|
||
dptr++;
|
||
|
||
/* Do not consume , if not followed by digit */
|
||
if (sptr[0] == ',' && isdigit((unsigned char)sptr[1]))
|
||
{
|
||
code = sptr[1] - '0';
|
||
sptr += 2;
|
||
|
||
if (isdigit ((unsigned char)*sptr)) {
|
||
code = code * 10 + *sptr - '0';
|
||
sptr++;
|
||
}
|
||
|
||
code = code % 16;
|
||
strcpy(dptr, codes[code].bg);
|
||
while (*dptr)
|
||
dptr++;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
/* ^C not followed by digit - assume end of color */
|
||
strcpy(dptr, "\x1b[0m");
|
||
while (*dptr)
|
||
dptr++;
|
||
}
|
||
}
|
||
else
|
||
*dptr++ = *sptr++;
|
||
}
|
||
*dptr = 0;
|
||
|
||
return newline1;
|
||
}
|
||
#endif
|
||
|
||
/* Borrowed with permission from FLiER */
|
||
char *stripansicodes(const char *line)
|
||
{
|
||
const char *tstr = line;
|
||
char *nstr = newline1;
|
||
int gotansi = 0;
|
||
|
||
while (*tstr)
|
||
{
|
||
/* Note that we use '\x9b' here, rather than 0x9b, because the
|
||
* former will have the correct value whether or not char is
|
||
* signed.
|
||
*/
|
||
if (*tstr == '\x1b' || *tstr == '\x9b')
|
||
gotansi = 1;
|
||
if (gotansi && isalpha((unsigned char)*tstr))
|
||
gotansi = 0;
|
||
else if (!gotansi)
|
||
{
|
||
*nstr = *tstr;
|
||
nstr++;
|
||
}
|
||
tstr++;
|
||
}
|
||
*nstr = 0;
|
||
return newline1;
|
||
}
|
||
#else
|
||
char *stripansicodes(const char *line)
|
||
{
|
||
return line;
|
||
}
|
||
char *mircansi(unsigned char *line)
|
||
{
|
||
return line;
|
||
}
|
||
#endif
|
||
|
||
int check_split(char *nick, char *reason)
|
||
{
|
||
char *bogus = get_string_var(FAKE_SPLIT_PATS_VAR);
|
||
char *Reason;
|
||
|
||
Reason = LOCAL_COPY(reason);
|
||
if (word_count(Reason) > 3)
|
||
goto fail_split;
|
||
if (wild_match("%.% %.%", Reason) && !strstr(Reason, "))") )
|
||
{
|
||
char *host1 = next_arg(Reason, &Reason);
|
||
char *host2 = next_arg(Reason, &Reason);
|
||
char *x = NULL;
|
||
|
||
if (!my_stricmp(host1, host2))
|
||
goto fail_split;
|
||
if (wild_match(host1, "*..*") || wild_match(host2, "*..*"))
|
||
goto fail_split;
|
||
if ((x = strrchr(host1, '.')))
|
||
x++;
|
||
if (!x || strlen(x) < 2 || strlen(x) > 3)
|
||
goto fail_split;
|
||
if ((x = strrchr(host2, '.')))
|
||
x++;
|
||
if (!x || strlen(x) < 2 || strlen(x) > 3)
|
||
goto fail_split;
|
||
|
||
if (bogus)
|
||
{
|
||
char *copy = NULL;
|
||
char *b_check;
|
||
copy = LOCAL_COPY(bogus);
|
||
while((b_check = next_arg(copy, ©)))
|
||
{
|
||
if (wild_match(b_check, host1) || wild_match(b_check, host2))
|
||
goto fail_split;
|
||
}
|
||
}
|
||
return 1;
|
||
}
|
||
fail_split:
|
||
return 0;
|
||
}
|
||
|
||
void clear_array(NickTab **tmp, char *nick)
|
||
{
|
||
NickTab *t, *q;
|
||
|
||
if (nick)
|
||
{
|
||
if ((t = (NickTab *)remove_from_list((List **)tmp, nick)))
|
||
{
|
||
new_free(&t->nick);
|
||
new_free(&t->type);
|
||
new_free((char **)&t);
|
||
}
|
||
return;
|
||
}
|
||
for (t = *tmp; t; )
|
||
{
|
||
q = t->next;
|
||
new_free(&t->nick);
|
||
new_free(&t->type);
|
||
new_free((char **)&t);
|
||
t = q;
|
||
}
|
||
*tmp = NULL;
|
||
}
|
||
|
||
|
||
BUILT_IN_COMMAND(clear_tab)
|
||
{
|
||
NickTab **tmp = &tabkey_array;
|
||
char *nick = NULL;
|
||
if (command && *command && !my_stricmp(command, "CLEARAUTO"))
|
||
tmp = &autoreply_array;
|
||
if (args && *args)
|
||
{
|
||
while ((nick = next_arg(args, &args)))
|
||
clear_array(tmp, nick);
|
||
return;
|
||
}
|
||
clear_array(tmp, nick);
|
||
}
|
||
|
||
void BX_userage(char *command, char *use)
|
||
{
|
||
if (command)
|
||
{
|
||
if (do_hook(USAGE_LIST, "%s %s", command, use ? use : "No Help Available for this command"))
|
||
put_it("%s", convert_output_format(fget_string_var(FORMAT_USAGE_FSET), "%s %s", command, convert_output_format(use ? use : "%WNo Help available for this command", NULL, NULL)));
|
||
}
|
||
else
|
||
put_it("Please return the command you just typed to #bitchx on efnet");
|
||
}
|
||
|
||
char *BX_random_str(int min, int max)
|
||
{
|
||
int i, ii;
|
||
static char str[IRCD_BUFFER_SIZE/4+1];
|
||
|
||
while ((i = getrandom(MIN(min, max), MAX(min, max))) > IRCD_BUFFER_SIZE/4)
|
||
;
|
||
for (ii = 0; ii < i; ii++)
|
||
str[ii] = (char) getrandom(97, 122);
|
||
str[ii] = '\0';
|
||
return str;
|
||
}
|
||
|
||
|
||
void check_auto_away(time_t idlet)
|
||
{
|
||
int i;
|
||
char *msg = NULL;
|
||
int auto_away_time = get_int_var(AUTO_AWAY_TIME_VAR);
|
||
int idle_mins = auto_away_time / 60;
|
||
|
||
if (!auto_away_time || !get_int_var(AUTO_AWAY_VAR) || idlet < auto_away_time)
|
||
return;
|
||
|
||
if (awaymsg)
|
||
malloc_sprintf(&msg, "%s: [%d mins]", convert_output_format(awaymsg, NULL), idle_mins);
|
||
else
|
||
malloc_sprintf(&msg, "Auto-Away after %d mins", idle_mins);
|
||
|
||
for (i = 0; i < server_list_size(); i++)
|
||
if (is_server_connected(i) && !get_server_away(i))
|
||
set_server_away(i, msg, 0);
|
||
|
||
update_all_status(current_window, NULL, 0);
|
||
new_free(&msg);
|
||
}
|
||
|
||
/*char *logfile[] = { "tcl.log", "msg.log", NULL };*/
|
||
|
||
/* putlog(level,channel_name,format,...); */
|
||
void putlog(int type, const char *chname, const char *format, ...)
|
||
{
|
||
#ifdef PUBLIC_ACCESS
|
||
return;
|
||
#else
|
||
va_list va;
|
||
char *logfilen;
|
||
char ftime[40];
|
||
FILE *f;
|
||
|
||
if (!get_int_var(BOT_LOG_VAR))
|
||
return;
|
||
if (!(logfilen = get_string_var(BOT_LOGFILE_VAR)))
|
||
return;
|
||
|
||
strftime(ftime, sizeof ftime, "%I:%M%p", localtime(&now));
|
||
|
||
if (chname && *chname =='*')
|
||
{
|
||
if ((f = fopen(logfilen, "a+")) != NULL)
|
||
{
|
||
va_start(va, format);
|
||
fprintf(f, "[%s] ", ftime);
|
||
vfprintf(f, format, va);
|
||
fprintf(f, "\n");
|
||
va_end(va);
|
||
|
||
fclose(f);
|
||
}
|
||
}
|
||
#endif
|
||
}
|
||
|
||
int isme(char *nick)
|
||
{
|
||
return ((my_stricmp(nick, get_server_nickname(from_server)) == 0) ? 1 : 0);
|
||
}
|
||
|
||
|
||
enum REDIR_TYPES { PRIVMSG = 0, KICK, TOPIC, WALL, WALLOP, NOTICE, KBOOT, KILL, DCC, LIST};
|
||
void userhost_ban(UserhostItem *stuff, char *nick1, char *args);
|
||
|
||
static int redirect_msg(char *to, enum REDIR_TYPES what, char *str, int showansi)
|
||
{
|
||
char *new_str;
|
||
if (showansi)
|
||
new_str = str;
|
||
else
|
||
new_str = stripansicodes(str);
|
||
switch(what)
|
||
{
|
||
case PRIVMSG:
|
||
if (*to == '=')
|
||
{
|
||
to++;
|
||
if (dcc_activechat(to))
|
||
dcc_chat_transmit(to, new_str, new_str, 0);
|
||
}
|
||
else
|
||
{
|
||
if (is_channel(to))
|
||
put_it("%s", convert_output_format(fget_string_var(FORMAT_SEND_PUBLIC_FSET), "%s %s %s %s", update_clock(GET_TIME), to, get_server_nickname(from_server), new_str));
|
||
else
|
||
put_it("%s", convert_output_format(fget_string_var(FORMAT_SEND_MSG_FSET), "%s %s %s %s", update_clock(GET_TIME), to, get_server_nickname(from_server), new_str));
|
||
send_to_server("PRIVMSG %s :%s", to, new_str);
|
||
}
|
||
break;
|
||
case KILL:
|
||
send_to_server("KILL %s :%s", to, new_str);
|
||
break;
|
||
case KBOOT:
|
||
userhostbase(to, userhost_ban, 1, "%s", get_current_channel_by_refnum(0));
|
||
case KICK:
|
||
send_to_server("KICK %s %s :%s", get_current_channel_by_refnum(0), to, new_str);
|
||
break;
|
||
case TOPIC:
|
||
send_to_server("TOPIC %s :%s", to, new_str);
|
||
break;
|
||
case WALL:
|
||
{
|
||
ChanWallOp(NULL, new_str, NULL, NULL);
|
||
break;
|
||
}
|
||
case WALLOP:
|
||
put_it("!! %s", str);
|
||
send_to_server("WALLOPS :%s", new_str);
|
||
break;
|
||
case NOTICE:
|
||
put_it("%s", convert_output_format(fget_string_var(FORMAT_SEND_NOTICE_FSET), "%s %s %s %s", update_clock(GET_TIME), to, get_server_nickname(from_server), new_str));
|
||
send_to_server("NOTICE %s :%s", to, new_str);
|
||
break;
|
||
case LIST:
|
||
default:
|
||
break;
|
||
}
|
||
return 1;
|
||
}
|
||
|
||
BUILT_IN_COMMAND(do_dirlasttype)
|
||
{
|
||
char *channel = NULL; int count = -1;
|
||
LastMsg *t = NULL;
|
||
char *form = NULL;
|
||
int numargs = 5;
|
||
int size = 1;
|
||
int len = strlen(command);
|
||
int showansi = 0;
|
||
enum REDIR_TYPES what = PRIVMSG;
|
||
|
||
if (!my_strnicmp(command, "RELCR", 5))
|
||
{
|
||
t = &last_ctcp_reply[0];
|
||
form = fget_string_var(FORMAT_CTCP_REPLY_FSET);
|
||
if (len == 6 && command[len-1] == 'T')
|
||
what = TOPIC;
|
||
}
|
||
else if (!my_strnicmp(command, "RELC", 4))
|
||
{
|
||
t = &last_sent_ctcp[0];
|
||
form = fget_string_var(FORMAT_SEND_CTCP_FSET);
|
||
if (len > 4 && command[len-1] == 'T')
|
||
what = TOPIC;
|
||
}
|
||
else if (!my_strnicmp(command, "RELD", 4))
|
||
{
|
||
t = &last_dcc[0];
|
||
size = MAX_LAST_MSG;
|
||
form = fget_string_var(FORMAT_DCC_CHAT_FSET);
|
||
if (len > 4 && command[len-1] == 'T')
|
||
what = TOPIC;
|
||
numargs = 4;
|
||
}
|
||
else if (!my_strnicmp(command, "RELSD", 5))
|
||
{
|
||
t = &last_sent_dcc[0];
|
||
size = MAX_LAST_MSG;
|
||
form = fget_string_var(FORMAT_DCC_CHAT_FSET);
|
||
if (len > 5 && command[len-1] == 'T')
|
||
what = TOPIC;
|
||
numargs = 4;
|
||
}
|
||
else if (!my_strnicmp(command, "RELI", 4))
|
||
{
|
||
t = &last_invite_channel[0];
|
||
form = fget_string_var(FORMAT_INVITE_FSET);
|
||
numargs = 3;
|
||
if (len > 4 && command[len-1] == 'T')
|
||
what = TOPIC;
|
||
}
|
||
else if (!my_strnicmp(command, "RELM", 4))
|
||
{
|
||
/* ??? */
|
||
t = &last_msg[0]; size = MAX_LAST_MSG;
|
||
form = fget_string_var(FORMAT_RELM_FSET);
|
||
if (len > 4 && command[len-1] == 'T')
|
||
what = TOPIC;
|
||
}
|
||
else if (!my_strnicmp(command, "RELN", 4))
|
||
{
|
||
/* ??? */
|
||
t = &last_notice[0]; size = MAX_LAST_MSG;
|
||
form = fget_string_var(FORMAT_RELN_FSET);
|
||
if (len > 4 && command[len-1] == 'T')
|
||
what = TOPIC;
|
||
}
|
||
else if (!my_strnicmp(command, "RELSM", 5))
|
||
{
|
||
/* ??? */
|
||
t = &last_sent_msg[0]; size = MAX_LAST_MSG;
|
||
form = fget_string_var(FORMAT_RELSM_FSET);
|
||
if (len > 5 && command[len-1] == 'T')
|
||
what = TOPIC;
|
||
}
|
||
else if (!my_strnicmp(command, "RELSN", 5))
|
||
{
|
||
/* ??? */
|
||
t = &last_sent_notice[0]; size = MAX_LAST_MSG;
|
||
form = fget_string_var(FORMAT_RELSN_FSET);
|
||
numargs = 2;
|
||
if (len > 5 && command[len-1] == 'T')
|
||
what = TOPIC;
|
||
}
|
||
else if (!my_strnicmp(command, "RELST", 5))
|
||
{
|
||
/* ??? */
|
||
t = &last_sent_topic[0];
|
||
form = fget_string_var(FORMAT_TOPIC_FSET);
|
||
numargs = 2;
|
||
if (len > 5 && command[len-1] == 'T')
|
||
what = TOPIC;
|
||
}
|
||
else if (!my_strnicmp(command, "RELSW", 5))
|
||
{
|
||
/* ??? */
|
||
t = &last_sent_wall[0];
|
||
form = fget_string_var(FORMAT_WALLOP_FSET);
|
||
if (len > 5 && command[len-1] == 'T')
|
||
what = TOPIC;
|
||
}
|
||
else if (!my_strnicmp(command, "RELS", 4))
|
||
{
|
||
t = &last_servermsg[0]; size = MAX_LAST_MSG;
|
||
form = fget_string_var(FORMAT_RELS_FSET);
|
||
numargs = 4;
|
||
if (len > 4 && command[len-1] == 'T')
|
||
what = TOPIC;
|
||
}
|
||
else if (!my_strnicmp(command, "RELT", 4))
|
||
{
|
||
/* ??? */
|
||
t = &last_topic[0];
|
||
form = fget_string_var(FORMAT_TOPIC_FSET);
|
||
numargs = 2;
|
||
if (len > 4 && command[len-1] == 'T')
|
||
what = TOPIC;
|
||
}
|
||
else if (!my_strnicmp(command, "RELW", 4))
|
||
{
|
||
/* ??? */
|
||
t = &last_wall[0];
|
||
size = MAX_LAST_MSG;
|
||
form = fget_string_var(FORMAT_WALLOP_FSET);
|
||
numargs = 4;
|
||
if (len > 4 && command[len-1] == 'T')
|
||
what = TOPIC;
|
||
}
|
||
else
|
||
{
|
||
what = LIST; size = MAX_LAST_MSG;
|
||
t = &last_msg[0];
|
||
for (count = size - 1; count != -1; count--)
|
||
{
|
||
if (t[count].last_msg)
|
||
put_it("%2d %s", count, convert_output_format(fget_string_var(FORMAT_RELM_FSET), "%s %s %s %s %s", t[count].time, t[count].from, t[count].uh, t[count].to, t[count].last_msg));
|
||
}
|
||
return;
|
||
}
|
||
|
||
while (args && *args)
|
||
{
|
||
char *comm;
|
||
if (!(comm = next_arg(args, &args)))
|
||
break;
|
||
if (!my_strnicmp(comm, "-list", strlen(comm)))
|
||
{
|
||
for (count = size - 1; count != -1; count--)
|
||
{
|
||
if (!t[count].last_msg)
|
||
continue;
|
||
switch(numargs)
|
||
{
|
||
case 2:
|
||
put_it("%2d %s", count, convert_output_format(form, "%s %s %s", t[count].time, t[count].to, t[count].last_msg));
|
||
break;
|
||
case 3:
|
||
put_it("%2d %s", count, convert_output_format(form, "%s %s %s", t[count].time, t[count].from, t[count].last_msg));
|
||
break;
|
||
case 4:
|
||
put_it("%2d %s", count, convert_output_format(form, "%s %s %s %s", t[count].time, t[count].from, t[count].to, t[count].last_msg));
|
||
break;
|
||
case 5:
|
||
put_it("%2d %s", count, convert_output_format(form, "%s %s %s %s %s", t[count].time, t[count].from, t[count].uh, t[count].to, t[count].last_msg));
|
||
}
|
||
}
|
||
return;
|
||
}
|
||
else if (!my_strnicmp(comm, "-kick", strlen(comm)))
|
||
what = KICK;
|
||
else if (!my_strnicmp(comm, "-wall", strlen(comm)))
|
||
what = WALL;
|
||
else if (!my_strnicmp(comm, "-wallop", strlen(comm)))
|
||
what = WALLOP;
|
||
else if (!my_strnicmp(comm, "-msg", strlen(comm)))
|
||
what = PRIVMSG;
|
||
else if (!my_strnicmp(comm, "-notice", strlen(comm)))
|
||
what = NOTICE;
|
||
else if (!my_strnicmp(comm, "-topic", strlen(comm)))
|
||
what = TOPIC;
|
||
else if (!my_strnicmp(comm, "-kboot", strlen(comm)))
|
||
what = KBOOT;
|
||
else if (!my_strnicmp(comm, "-kill", strlen(comm)))
|
||
what = KILL;
|
||
else if (!my_strnicmp(comm, "-ansi", strlen(comm)))
|
||
showansi++;
|
||
else if (!my_strnicmp(comm, "-num", strlen(comm)))
|
||
{
|
||
comm = next_arg(args, &args);
|
||
if (is_number(comm))
|
||
{
|
||
count = my_atol(comm);
|
||
if (count < 0)
|
||
count *= -1;
|
||
}
|
||
else
|
||
channel = comm;
|
||
}
|
||
else
|
||
channel = comm;
|
||
|
||
if (count > size)
|
||
count = size;
|
||
}
|
||
if (count == -1)
|
||
count = 0;
|
||
if (!channel)
|
||
channel = get_target_by_refnum(0);
|
||
if (channel || what == WALLOP)
|
||
{
|
||
char *p = NULL;
|
||
if (!t[count].last_msg)
|
||
{
|
||
bitchsay("No such msg #%d for /%s received", count, command);
|
||
return;
|
||
}
|
||
switch(numargs)
|
||
{
|
||
case 2:
|
||
malloc_strcpy(&p, convert_output_format(form, "%s %s %s", t[count].time, t[count].to, t[count].last_msg));
|
||
break;
|
||
case 3:
|
||
malloc_strcpy(&p, convert_output_format(form, "%s %s %s", t[count].time, t[count].from, t[count].last_msg));
|
||
break;
|
||
case 4:
|
||
malloc_strcpy(&p, convert_output_format(form, "%s %s %s %s", t[count].time, t[count].from, t[count].to, t[count].last_msg));
|
||
break;
|
||
case 5:
|
||
malloc_strcpy(&p, convert_output_format(form, "%s %s %s %s %s", t[count].time, t[count].from, t[count].uh, t[count].to, t[count].last_msg));
|
||
}
|
||
redirect_msg(channel, what, p, showansi);
|
||
new_free(&p);
|
||
}
|
||
else
|
||
bitchsay("Can not %s what you requested", command);
|
||
}
|
||
|
||
/*
|
||
* Wallop Sends NOTICE to all ops of Current Channel!
|
||
*/
|
||
BUILT_IN_COMMAND(ChanWallOp)
|
||
{
|
||
char *channel = NULL;
|
||
char *chops = NULL;
|
||
char *include = NULL;
|
||
char *exclude = NULL;
|
||
ChannelList *chan;
|
||
NickList *tmp;
|
||
int ver = 0;
|
||
int enable_all = 0;
|
||
|
||
char buffer[BIG_BUFFER_SIZE + 1];
|
||
|
||
if (!args || !*args)
|
||
return;
|
||
|
||
if (get_current_channel_by_refnum(0))
|
||
{
|
||
int count = 0;
|
||
int i = 0;
|
||
char *nick = NULL;
|
||
malloc_strcpy(&channel, get_current_channel_by_refnum(0));
|
||
chan = lookup_channel(channel, current_window->server, 0);
|
||
if (((ver = get_server_version(current_window->server)) == Server2_8hybrid6))
|
||
enable_all = 1;
|
||
else if (((ver = get_server_version(current_window->server)) < Server_u2_8))
|
||
{
|
||
while (args && (*args == '-' || *args == '+'))
|
||
{
|
||
nick = next_arg(args, &args);
|
||
if (*nick == '-')
|
||
{
|
||
malloc_strcat(&exclude, nick+1);
|
||
malloc_strcat(&exclude, space);
|
||
}
|
||
else
|
||
{
|
||
malloc_strcat(&include, nick+1);
|
||
malloc_strcat(&include, space);
|
||
}
|
||
}
|
||
}
|
||
if (!args || !*args)
|
||
{
|
||
bitchsay("NO Wallmsg included");
|
||
new_free(&exclude);
|
||
new_free(&include);
|
||
new_free(&channel);
|
||
}
|
||
set_display_target(channel, LOG_WALL);
|
||
sprintf(buffer, "[\002BX-Wall\002/\002%s\002] %s", channel, args);
|
||
if (ver >= Server_u2_10 || enable_all)
|
||
{
|
||
send_to_server(enable_all?"NOTICE @%s :%s":"WALLCHOPS %s :%s", channel, buffer);
|
||
put_it("%s", convert_output_format(fget_string_var(FORMAT_BWALL_FSET), "%s %s %s %s %s", update_clock(GET_TIME), channel, "*", "*", args));
|
||
add_last_type(&last_sent_wall[0], 1, NULL, NULL, channel, buffer);
|
||
new_free(&channel);
|
||
reset_display_target();
|
||
return;
|
||
}
|
||
for (tmp = next_nicklist(chan, NULL); tmp; tmp = next_nicklist(chan, tmp))
|
||
{
|
||
if (!my_stricmp(tmp->nick, get_server_nickname(from_server)))
|
||
continue;
|
||
if (exclude && stristr(exclude, tmp->nick))
|
||
continue;
|
||
if (nick_isop(tmp) || (include && stristr(include, tmp->nick)))
|
||
{
|
||
if (chops)
|
||
malloc_strcat(&chops, ",");
|
||
malloc_strcat(&chops, tmp->nick);
|
||
count++;
|
||
}
|
||
if (count >= 8 && chops)
|
||
{
|
||
send_to_server("%s %s :%s", "NOTICE", chops, buffer);
|
||
i+=count;
|
||
count = 0;
|
||
new_free(&chops);
|
||
}
|
||
}
|
||
i+=count;
|
||
if (chops)
|
||
send_to_server("%s %s :%s", "NOTICE", chops, buffer);
|
||
if (i)
|
||
{
|
||
put_it("%s", convert_output_format(fget_string_var(FORMAT_BWALL_FSET), "%s %s %s %s %s", update_clock(GET_TIME), channel, "*", "*", args));
|
||
add_last_type(&last_sent_wall[0], 1, NULL, NULL, channel, buffer);
|
||
if (exclude)
|
||
bitchsay("Excluded <%s> from wallmsg", exclude);
|
||
if (include)
|
||
bitchsay("Included <%s> in wallmsg", include);
|
||
}
|
||
else
|
||
put_it("%s", convert_output_format("$G No ops on $0", "%s", channel));
|
||
reset_display_target();
|
||
}
|
||
else
|
||
say("No Current Channel for this Window.");
|
||
new_free(&include);
|
||
new_free(&channel);
|
||
new_free(&chops);
|
||
new_free(&exclude);
|
||
}
|
||
|
||
void log_toggle(int flag, ChannelList *chan)
|
||
{
|
||
char *logfile;
|
||
|
||
if (((logfile = get_string_var(MSGLOGFILE_VAR)) == NULL) || !get_string_var(CTOOLZ_DIR_VAR))
|
||
{
|
||
bitchsay("You must set the MSGLOGFILE and CTOOLZ_DIR variables first!");
|
||
set_int_var(MSGLOG_VAR, 0);
|
||
return;
|
||
}
|
||
logmsg(LOG_CURRENT, NULL, flag ? 1 : 2, NULL);
|
||
}
|
||
|
||
int are_you_opped(char *channel)
|
||
{
|
||
return is_chanop(channel, get_server_nickname(from_server));
|
||
}
|
||
|
||
void error_not_opped(const char *channel)
|
||
{
|
||
set_display_target(channel, LOG_CRAP);
|
||
say("You're not opped on %s", channel);
|
||
reset_display_target();
|
||
}
|
||
|
||
/* Reads a single non-empty line from a file. Ignores lines beginning with # */
|
||
int freadln(FILE *stream, char *lin, size_t len)
|
||
{
|
||
char *p;
|
||
|
||
do
|
||
p = fgets(lin, len, stream);
|
||
while (p && (*lin == '#' || *lin == '\n'));
|
||
|
||
if (!p)
|
||
return 0;
|
||
|
||
chop(lin, 1);
|
||
return 1;
|
||
}
|
||
|
||
/* Open a file and read a random non-empty, non-comment line from it. */
|
||
static char *fread_random(const char *filename, char *line, size_t len)
|
||
{
|
||
int count = 0;
|
||
int i = 0;
|
||
FILE *reason_file;
|
||
char *f = m_strdup(filename);
|
||
char buffer[2][IRCD_BUFFER_SIZE];
|
||
|
||
/* This is an algorithm that lets us choose an evenly-distributed
|
||
* random line with one pass through the file. At line N, we replace
|
||
* the previously chosen line with this line, with probability 1/N.
|
||
*/
|
||
if ((reason_file = uzfopen(&f, get_string_var(LOAD_PATH_VAR), 0)))
|
||
{
|
||
while (freadln(reason_file, buffer[i], sizeof buffer[i]))
|
||
{
|
||
count++;
|
||
if (getrandom(0, count - 1) == 0)
|
||
i = !i;
|
||
}
|
||
fclose(reason_file);
|
||
}
|
||
|
||
new_free(&f);
|
||
|
||
if (count > 0)
|
||
{
|
||
strlcpy(line, buffer[!i], len);
|
||
return line;
|
||
}
|
||
return NULL;
|
||
}
|
||
|
||
/* Read a random text format from a file, convert it and strip it. A default
|
||
format is supplied if a format cannot be read from the file.
|
||
arg0 and arg1 replace $0 and $1 in the format.
|
||
*/
|
||
static char *random_text(const char *filename, const char *arg0,
|
||
const char *arg1, const char *default_format)
|
||
{
|
||
char line[IRCD_BUFFER_SIZE];
|
||
const char *format = fread_random(filename, line, sizeof line);
|
||
|
||
if (!format)
|
||
format = default_format;
|
||
|
||
return stripansicodes(convert_output_format(format, "%s %s", arg0, arg1));
|
||
}
|
||
|
||
/* Get a random reason from a specific reason file, defaulting to the kick
|
||
* file if none passed. Format it using target and nick to replace $0 and $1.
|
||
*/
|
||
char *get_reason(const char *target, const char *nick, const char *file)
|
||
{
|
||
if (!file || !*file)
|
||
file = DEFAULT_BITCHX_KICK_FILE;
|
||
|
||
return random_text(file, target, nick, get_string_var(DEFAULT_REASON_VAR));
|
||
}
|
||
|
||
/* Get a random kick reason. Format it using target and nick to replace $0
|
||
* and $1.
|
||
*/
|
||
char *get_kick_reason(const char *target, const char *nick)
|
||
{
|
||
return get_reason(target, nick, NULL);
|
||
}
|
||
|
||
/* Get a random kill reason. Format it using target and nick to replace $0
|
||
* and $1.
|
||
*/
|
||
char *get_kill_reason(const char *target, const char *nick)
|
||
{
|
||
return random_text(DEFAULT_BITCHX_KILL_FILE, target, nick, get_string_var(DEFAULT_REASON_VAR));
|
||
}
|
||
|
||
/* Get a random ircname. Format it using nick to replace $0 and $1. */
|
||
char *get_realname(const char *nick)
|
||
{
|
||
return random_text(DEFAULT_BITCHX_IRCNAME_FILE, nick, nick, "Who cares?");
|
||
}
|
||
|
||
/* Get a quit reason. Format it using nick to replace $0 and $1. */
|
||
char *get_signoffreason(const char *nick)
|
||
{
|
||
return random_text(DEFAULT_BITCHX_QUIT_FILE, nick, nick, "$0 has no reason");
|
||
}
|
||
|
||
#ifdef WANT_NSLOOKUP
|
||
|
||
void auto_nslookup(struct reslist *rptr)
|
||
{
|
||
NickList *nick;
|
||
ChannelList *chan;
|
||
struct in_addr ip;
|
||
|
||
if ((chan = lookup_channel(rptr->channel, rptr->server, 0)))
|
||
{
|
||
if ((nick = find_nicklist_in_channellist(rptr->nick, chan, 0)))
|
||
{
|
||
if (rptr->re_he.h_addr_list[0].s_addr)
|
||
{
|
||
memcpy(&ip, &rptr->re_he.h_addr_list[0], sizeof ip);
|
||
nick->ip = m_strdup(inet_ntoa(ip));
|
||
#ifdef WANT_USERLIST
|
||
check_auto(chan->channel, nick, chan);
|
||
#endif
|
||
}
|
||
else if (++nick->ip_count < 2)
|
||
do_nslookup(rptr->host, rptr->nick, rptr->user, rptr->channel, rptr->server, auto_nslookup, NULL);
|
||
#ifdef PANA_DEBUG
|
||
else
|
||
put_it("got here. nslookup failure %s!%s", nick->nick, nick->host);
|
||
#endif
|
||
}
|
||
}
|
||
return;
|
||
}
|
||
|
||
static void print_ns_succeed(struct reslist *rptr)
|
||
{
|
||
char *u, *n, *h;
|
||
char buffer[BIG_BUFFER_SIZE];
|
||
struct in_addr ip;
|
||
u = rptr->user ? rptr->user : empty_string;
|
||
h = rptr->host;
|
||
n = rptr->nick ? rptr->nick : empty_string;
|
||
if (rptr->command)
|
||
{
|
||
int i;
|
||
if (rptr->nick && rptr->user)
|
||
sprintf(buffer, "%s!%s@%s ", n, u, h);
|
||
else
|
||
sprintf(buffer, "%s ", h);
|
||
for (i = 0; rptr->re_he.h_addr_list[i].s_addr; i++)
|
||
{
|
||
memcpy(&ip, &rptr->re_he.h_addr_list[i], sizeof ip);
|
||
BX_strpcat(buffer, "%s ", inet_ntoa(ip));
|
||
if (strlen(buffer) > 490)
|
||
break;
|
||
}
|
||
parse_line("NSLOOKUP", rptr->command, buffer, 0, 0, 1);
|
||
return;
|
||
}
|
||
if (do_hook(NSLOOKUP_LIST, "%s %s %s %s %s", h, rptr->re_he.h_name?rptr->re_he.h_name:empty_string, (char *)inet_ntoa(rptr->re_he.h_addr_list[0]), n, u))
|
||
{
|
||
int i;
|
||
*buffer = 0;
|
||
if (rptr->nick && rptr->user)
|
||
bitchsay("[%s!%s@%s]: %s", n, u, h, rptr->re_he.h_name ? rptr->re_he.h_name: "invalid hostname");
|
||
else
|
||
bitchsay("%s is %s (%s)", h, rptr->re_he.h_name ? rptr->re_he.h_name:"invalid hostname", (char *)inet_ntoa(rptr->re_he.h_addr_list[0]));
|
||
for (i = 0; rptr->re_he.h_addr_list[i].s_addr; i++)
|
||
{
|
||
memcpy(&ip, &rptr->re_he.h_addr_list[i], sizeof ip);
|
||
BX_strpcat(buffer, "[%s] ", inet_ntoa(ip));
|
||
if (strlen(buffer) > 490)
|
||
break;
|
||
}
|
||
bitchsay("IPs: %s", buffer);
|
||
for (i = 0; rptr->re_he.h_aliases[i]; i++)
|
||
bitchsay("\talias %d = %s", i+1, rptr->re_he.h_aliases[i]);
|
||
}
|
||
}
|
||
|
||
void print_ns_fail(struct reslist *rptr)
|
||
{
|
||
if (rptr->command)
|
||
{
|
||
char buffer[BIG_BUFFER_SIZE];
|
||
if (rptr->nick && rptr->user)
|
||
sprintf(buffer, "%s!%s@%s ", rptr->nick, rptr->user, rptr->host);
|
||
else
|
||
sprintf(buffer, "%s ", rptr->host);
|
||
parse_line("NSLOOKUP", rptr->command, buffer, 0, 0, 1);
|
||
return;
|
||
}
|
||
if (do_hook(NSLOOKUP_LIST, "%s %s %s", rptr->host, rptr->nick?rptr->nick:empty_string, rptr->user?rptr->user:empty_string))
|
||
{
|
||
if (rptr->nick && rptr->user)
|
||
bitchsay("nslookup of %s!%s@%s failed.", rptr->nick, rptr->user, rptr->host);
|
||
else
|
||
bitchsay("nslookup of host %s failed.", rptr->host);
|
||
}
|
||
}
|
||
#ifdef THREAD
|
||
|
||
/* Threaded generic callback to convert from Sheik's
|
||
* return format to the one that is already used in
|
||
* BitchX to maintain threaded and non-threaded
|
||
* compatibility.
|
||
*/
|
||
void cdns_generic_callback(DNS_QUEUE *dns)
|
||
{
|
||
struct reslist *info = dns->callinfo;
|
||
|
||
if(!info)
|
||
return;
|
||
|
||
if(dns->hostentr)
|
||
memcpy(&info->re_he, dns->hostentr, sizeof(struct hent));
|
||
|
||
if(info->func)
|
||
info->func(info);
|
||
else if(dns->out)
|
||
print_ns_succeed(info);
|
||
else
|
||
print_ns_fail(info);
|
||
|
||
new_free(&info->nick);
|
||
new_free(&info->user);
|
||
new_free(&info->host);
|
||
new_free(&info->channel);
|
||
new_free(&info->command);
|
||
new_free(&info);
|
||
}
|
||
|
||
/* Not entirely sure how to handle this at the moment */
|
||
void ar_rename_nick(char *old_nick, char *new_nick, int server)
|
||
{
|
||
}
|
||
|
||
#else
|
||
|
||
|
||
/*
|
||
* arlib.c (C)opyright 1993 Darren Reed. All rights reserved.
|
||
* This file may not be distributed without the author's permission in any
|
||
* shape or form. The author takes no responsibility for any damage or loss
|
||
* of property which results from the use of this software.
|
||
* heavily modified for use in a irc client.
|
||
*/
|
||
|
||
#if !defined( __APPLE__ )
|
||
/* On some systems, eg OpenBSD, we have to define BIND_4_COMPAT to get
|
||
* nameser_compat.h included, to get the "old" bind interface. */
|
||
#if !defined( BIND_4_COMPAT )
|
||
#define BIND_4_COMPAT
|
||
#endif
|
||
#else
|
||
/* After one too many bongs some developer at Apple decided to rename this
|
||
* macro for no good reason. */
|
||
#if !defined( BIND_8_COMPAT )
|
||
#define BIND_8_COMPAT
|
||
#endif
|
||
#endif
|
||
|
||
#include <stdio.h>
|
||
#include <fcntl.h>
|
||
#include <signal.h>
|
||
#include <sys/types.h>
|
||
#include <sys/time.h>
|
||
#include <sys/socket.h>
|
||
#include <netinet/in.h>
|
||
#include <netdb.h>
|
||
#include <arpa/nameser.h>
|
||
#include <resolv.h>
|
||
|
||
#define HOSTLEN 100
|
||
extern int h_errno;
|
||
static char ar_hostbuf[HOSTLEN+1], ar_domainname[HOSTLEN+1];
|
||
static char ar_dot[] = ".";
|
||
static int ar_resfd = -1, ar_vc = 0;
|
||
static struct reslist *ar_last = NULL, *ar_first = NULL;
|
||
|
||
|
||
static int do_query_name(struct resinfo *, char *, register struct reslist *, char *, char *, char *, char *, int , void (*func)(), char *);
|
||
static int do_query_number(struct resinfo *, char *, register struct reslist *, char *, char *, char *, char *, int , void (*func)(), char *);
|
||
static int ar_resend_query(struct reslist *);
|
||
|
||
#define MAX_RETRIES 4
|
||
|
||
#ifndef HFIXEDSZ
|
||
#define HFIXEDSZ 12
|
||
#endif
|
||
|
||
#ifndef INT32SZ
|
||
#define INT32SZ 4
|
||
#endif
|
||
|
||
|
||
/*
|
||
* Statistics structure.
|
||
*/
|
||
static struct resstats {
|
||
int re_errors;
|
||
int re_nu_look;
|
||
int re_na_look;
|
||
int re_replies;
|
||
int re_requests;
|
||
int re_resends;
|
||
int re_sent;
|
||
int re_timeouts;
|
||
} ar_reinfo;
|
||
|
||
#ifdef HAVE_LIBIPHLPAPI
|
||
|
||
void ar_get_windows_dns(void)
|
||
{
|
||
DWORD ret;
|
||
ULONG buflen = 0;
|
||
FIXED_INFO *buf;
|
||
|
||
ret = GetNetworkParams(NULL, &buflen);
|
||
if (ret != ERROR_BUFFER_OVERFLOW)
|
||
return;
|
||
|
||
buf = new_malloc(buflen);
|
||
|
||
ret = GetNetworkParams(buf, &buflen);
|
||
if (ret == NO_ERROR)
|
||
{
|
||
_res.nscount = 1;
|
||
_res.nsaddr_list[0].sin_family = AF_INET;
|
||
_res.nsaddr_list[0].sin_addr.s_addr = inet_addr(buf->DnsServerList.IpAddress.String);
|
||
_res.nsaddr_list[0].sin_port = htons(53);
|
||
}
|
||
|
||
new_free(&buf);
|
||
return;
|
||
}
|
||
#endif /* HAVE_LIBIPHLPAPI */
|
||
|
||
/*
|
||
* ar_init
|
||
*
|
||
* Initializes the various ARLIB internal varilables and related DNS
|
||
* options for res_init().
|
||
*
|
||
* Returns 0 or the socket opened for use with talking to name servers
|
||
* if 0 is passed or ARES_INITSOCK is set.
|
||
*/
|
||
int ar_init(int op)
|
||
{
|
||
int ret = 0;
|
||
|
||
if (!op)
|
||
return ar_resfd;
|
||
if (op & ARES_INITLIST)
|
||
{
|
||
memset(&ar_reinfo, 0, sizeof(ar_reinfo));
|
||
ar_first = ar_last = NULL;
|
||
}
|
||
|
||
if (op & ARES_CALLINIT && !(_res.options & RES_INIT))
|
||
{
|
||
ret = res_init();
|
||
(void)strcpy(ar_domainname, ar_dot);
|
||
(void)strncat(ar_domainname, _res.defdname, HOSTLEN-2);
|
||
#ifdef HAVE_LIBIPHLPAPI
|
||
/* The Cygwin resolver library doesn't fill out _res.nsaddr_list
|
||
* and sets _res.nscount to -1 if there's no /etc/resolv.conf file,
|
||
* so we try fetching the first DNS server address ourselves. */
|
||
if (_res.nscount < 1)
|
||
ar_get_windows_dns();
|
||
#endif
|
||
if (_res.nscount < 1)
|
||
{
|
||
/* Try falling back to the Google public DNS */
|
||
_res.nscount = 1;
|
||
_res.nsaddr_list[0].sin_family = AF_INET;
|
||
_res.nsaddr_list[0].sin_addr.s_addr = inet_addr("8.8.8.8");
|
||
_res.nsaddr_list[0].sin_port = htons(53);
|
||
}
|
||
}
|
||
|
||
if (op & ARES_INITSOCK)
|
||
ret = ar_resfd = ar_open();
|
||
|
||
if (op & ARES_INITDEBG)
|
||
_res.options |= RES_DEBUG;
|
||
return ret;
|
||
}
|
||
|
||
/*
|
||
* ar_open
|
||
*
|
||
* Open a socket to talk to a name server with.
|
||
* Check _res.options to see if we use a TCP or UDP socket.
|
||
*/
|
||
int ar_open(void)
|
||
{
|
||
if (ar_resfd > -1)
|
||
return ar_resfd;
|
||
|
||
if (_res.options & RES_USEVC)
|
||
{
|
||
struct sockaddr_in *sip;
|
||
int i = 0;
|
||
|
||
sip = _res.nsaddr_list;
|
||
ar_vc = 1;
|
||
ar_resfd = socket(AF_INET, SOCK_STREAM, 0);
|
||
|
||
/*
|
||
* Try each name server listed in sequence until we
|
||
* succeed or run out.
|
||
*/
|
||
while (connect(ar_resfd, (struct sockaddr *)sip++,
|
||
sizeof(struct sockaddr)))
|
||
{
|
||
(void)close(ar_resfd);
|
||
ar_resfd = -1;
|
||
if (i >= _res.nscount)
|
||
break;
|
||
ar_resfd = socket(AF_INET, SOCK_STREAM, 0);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
int on = 0;
|
||
ar_resfd = socket(AF_INET, SOCK_DGRAM, 0);
|
||
|
||
if (ar_resfd > -1)
|
||
(void) setsockopt(ar_resfd, SOL_SOCKET, SO_BROADCAST,(char *)&on, sizeof(on));
|
||
}
|
||
|
||
if (ar_resfd < 0)
|
||
return -1;
|
||
|
||
if (set_non_blocking(ar_resfd) < 0)
|
||
{
|
||
(void)close(ar_resfd);
|
||
ar_resfd = -1;
|
||
}
|
||
|
||
return new_open(ar_resfd);
|
||
}
|
||
|
||
/*
|
||
* ar_close
|
||
*
|
||
* Closes and flags the ARLIB socket as closed.
|
||
*/
|
||
void ar_close(void)
|
||
{
|
||
new_close(ar_resfd);
|
||
ar_resfd = -1;
|
||
return;
|
||
}
|
||
|
||
/*
|
||
* ar_add_request
|
||
*
|
||
* Add a new DNS query to the end of the query list.
|
||
*/
|
||
static int ar_add_request(struct reslist *new)
|
||
{
|
||
if (!new)
|
||
return -1;
|
||
if (!ar_first)
|
||
ar_first = ar_last = new;
|
||
else
|
||
{
|
||
ar_last->re_next = new;
|
||
ar_last = new;
|
||
}
|
||
new->re_next = NULL;
|
||
ar_reinfo.re_requests++;
|
||
return 0;
|
||
}
|
||
|
||
/*
|
||
* ar_remrequest
|
||
*
|
||
* Remove a request from the list. This must also free any memory that has
|
||
* been allocated for temporary storage of DNS results.
|
||
*
|
||
* Returns -1 if there are anyy problems removing the requested structure
|
||
* or 0 if the remove is successful.
|
||
*/
|
||
static int ar_remrequest(struct reslist *old)
|
||
{
|
||
struct reslist *rptr, *r2ptr;
|
||
register char **s;
|
||
|
||
if (!old)
|
||
return -1;
|
||
for (rptr = ar_first, r2ptr = NULL; rptr; rptr = rptr->re_next)
|
||
{
|
||
if (rptr == old)
|
||
break;
|
||
r2ptr = rptr;
|
||
}
|
||
|
||
if (!rptr)
|
||
return -1;
|
||
if (rptr == ar_first)
|
||
ar_first = ar_first->re_next;
|
||
else if (rptr == ar_last)
|
||
{
|
||
if ((ar_last = r2ptr))
|
||
ar_last->re_next = NULL;
|
||
}
|
||
else
|
||
r2ptr->re_next = rptr->re_next;
|
||
|
||
if (!ar_first)
|
||
ar_last = ar_first;
|
||
if (rptr->re_he.h_name)
|
||
new_free(&rptr->re_he.h_name);
|
||
if ((s = rptr->re_he.h_aliases))
|
||
{
|
||
for (; *s; s++)
|
||
new_free(s);
|
||
}
|
||
if (rptr->re_rinfo.ri_ptr)
|
||
new_free(&rptr->re_rinfo.ri_ptr);
|
||
|
||
new_free(&rptr->nick);
|
||
new_free(&rptr->user);
|
||
new_free(&rptr->host);
|
||
new_free(&rptr->channel);
|
||
new_free(&rptr->command);
|
||
new_free(&rptr);
|
||
|
||
return 0;
|
||
}
|
||
|
||
/*
|
||
* ar_make_request
|
||
*
|
||
* Create a DNS query recorded for the request being made and place it on the
|
||
* current list awaiting replies. Initialization of the record with set
|
||
* values should also be done.
|
||
*/
|
||
static struct reslist *ar_make_request(register struct resinfo *resi, char *nick, char *user, char *h, char *chan, int server, void (*func)(), char *command)
|
||
{
|
||
register struct reslist *rptr;
|
||
register struct resinfo *rp;
|
||
|
||
rptr = (struct reslist *)new_malloc(sizeof(struct reslist));
|
||
rp = &rptr->re_rinfo;
|
||
|
||
rptr->re_next = NULL; /* where NULL is non-zero ;) */
|
||
rptr->re_sentat = now;
|
||
rptr->re_retries = MAX_RETRIES;/*_res.retry + 2;*/
|
||
rptr->re_sends = 1;
|
||
rptr->re_resend = 1;
|
||
rptr->re_timeout = rptr->re_sentat + _res.retrans;
|
||
rptr->re_he.h_name = NULL;
|
||
rptr->re_he.h_addrtype = AF_INET;
|
||
rptr->re_he.h_aliases[0] = NULL;
|
||
rp->ri_ptr = resi->ri_ptr;
|
||
rp->ri_size = resi->ri_size;
|
||
if (nick)
|
||
malloc_strcpy(&rptr->nick, nick);
|
||
if (user)
|
||
malloc_strcpy(&rptr->user, user);
|
||
if (h)
|
||
malloc_strcpy(&rptr->host, h);
|
||
if (chan)
|
||
rptr->channel = m_strdup(chan);
|
||
if (command)
|
||
rptr->command = m_strdup(command);
|
||
rptr->server = server;
|
||
if (func)
|
||
rptr->func = func;
|
||
(void)ar_add_request(rptr);
|
||
|
||
return rptr;
|
||
}
|
||
|
||
void ar_rename_nick(char *old_nick, char *new_nick, int server)
|
||
{
|
||
register struct reslist *rptr;
|
||
for (rptr = ar_first; rptr; rptr = rptr->re_next)
|
||
{
|
||
if (!rptr->nick) continue;
|
||
if (!strcmp(rptr->nick, old_nick) && rptr->server == server)
|
||
malloc_strcpy(&rptr->nick, new_nick);
|
||
}
|
||
}
|
||
|
||
/*
|
||
* ar_timeout
|
||
*
|
||
* Remove queries from the list which have been there too long without
|
||
* being resolved.
|
||
*/
|
||
long ar_timeout(time_t now, char *info, int size, void (*func)(struct reslist *) )
|
||
{
|
||
register struct reslist *rptr, *r2ptr;
|
||
register long next = 0;
|
||
|
||
for (rptr = ar_first, r2ptr = NULL; rptr; rptr = r2ptr)
|
||
{
|
||
r2ptr = rptr->re_next;
|
||
if (now >= rptr->re_timeout)
|
||
{
|
||
/*
|
||
* If the timeout for the query has been exceeded,
|
||
* then resend the query if we still have some
|
||
* 'retry credit' and reset the timeout. If we have
|
||
* used it all up, then remove the request.
|
||
*/
|
||
if (--rptr->re_retries <= 0)
|
||
{
|
||
ar_reinfo.re_timeouts++;
|
||
if (info && rptr->re_rinfo.ri_ptr)
|
||
memcpy(info, rptr->re_rinfo.ri_ptr,
|
||
MIN(rptr->re_rinfo.ri_size, size));
|
||
if (rptr->func)
|
||
(*rptr->func)(rptr);
|
||
else if (func)
|
||
(*func)(rptr);
|
||
(void)ar_remrequest(rptr);
|
||
return now;
|
||
}
|
||
else
|
||
{
|
||
rptr->re_sends++;
|
||
rptr->re_sentat = now;
|
||
rptr->re_timeout = now + _res.retrans;
|
||
(void)ar_resend_query(rptr);
|
||
}
|
||
}
|
||
if (!next || rptr->re_timeout < next)
|
||
next = rptr->re_timeout;
|
||
}
|
||
return next;
|
||
}
|
||
|
||
/*
|
||
* ar_send_res_msg
|
||
*
|
||
* When sending queries to nameservers listed in the resolv.conf file,
|
||
* don't send a query to every one, but increase the number sent linearly
|
||
* to match the number of resends. This increase only occurs if there are
|
||
* multiple nameserver entries in the resolv.conf file.
|
||
* The return value is the number of messages successfully sent to
|
||
* nameservers or -1 if no successful sends.
|
||
*/
|
||
static int ar_send_res_msg(unsigned char *msg, int len, int rcount)
|
||
{
|
||
register int i;
|
||
int sent = 0;
|
||
|
||
if (!msg)
|
||
return -1;
|
||
|
||
rcount = (_res.nscount > rcount) ? rcount : _res.nscount;
|
||
if (_res.options & RES_PRIMARY)
|
||
rcount = 1;
|
||
if (!rcount)
|
||
rcount = 1;
|
||
if (ar_vc)
|
||
{
|
||
ar_reinfo.re_sent++;
|
||
sent++;
|
||
if (write(ar_resfd, msg, len) == -1)
|
||
{
|
||
int errtmp = errno;
|
||
ar_close();
|
||
errno = errtmp;
|
||
}
|
||
}
|
||
else
|
||
for (i = 0; i < rcount; i++)
|
||
{
|
||
_res.nsaddr_list[i].sin_family = AF_INET;
|
||
if (sendto(ar_resfd, msg, len, 0,
|
||
(struct sockaddr *)&(_res.nsaddr_list[i]),
|
||
sizeof(struct sockaddr_in)) == len)
|
||
{
|
||
ar_reinfo.re_sent++;
|
||
sent++;
|
||
}
|
||
}
|
||
return (sent) ? sent : -1;
|
||
}
|
||
|
||
/*
|
||
* ar_find_id
|
||
*
|
||
* find a dns query record by the id (id is determined by dn_mkquery)
|
||
*/
|
||
static struct reslist *ar_find_id(int id)
|
||
{
|
||
register struct reslist *rptr;
|
||
|
||
for (rptr = ar_first; rptr; rptr = rptr->re_next)
|
||
if (rptr->re_id == id)
|
||
return rptr;
|
||
return NULL;
|
||
}
|
||
|
||
/*
|
||
* ar_delete
|
||
*
|
||
* Delete a request from the waiting list if it has a data pointer which
|
||
* matches the one passed.
|
||
*/
|
||
int ar_delete(char *ptr, int size)
|
||
{
|
||
register struct reslist *rptr;
|
||
register struct reslist *r2ptr;
|
||
int removed = 0;
|
||
|
||
for (rptr = ar_first; rptr; rptr = r2ptr)
|
||
{
|
||
r2ptr = rptr->re_next;
|
||
if (rptr->re_rinfo.ri_ptr && ptr && size &&
|
||
memcmp(rptr->re_rinfo.ri_ptr, ptr, size) == 0)
|
||
{
|
||
(void)ar_remrequest(rptr);
|
||
removed++;
|
||
}
|
||
}
|
||
return removed;
|
||
}
|
||
|
||
/*
|
||
* ar_query_name
|
||
*
|
||
* generate a query based on class, type and name.
|
||
*/
|
||
static int ar_query_name(char *name, int class, int type, struct reslist *rptr)
|
||
{
|
||
static unsigned char buf[MAXPACKET];
|
||
int r,s;
|
||
HEADER *hptr;
|
||
|
||
memset(buf, 0, sizeof(buf));
|
||
r = res_mkquery(QUERY, name, class, type, NULL, 0, NULL,
|
||
buf, sizeof(buf));
|
||
if (r <= 0)
|
||
{
|
||
h_errno = NO_RECOVERY;
|
||
return r;
|
||
}
|
||
hptr = (HEADER *)buf;
|
||
rptr->re_id = ntohs(hptr->id);
|
||
|
||
s = ar_send_res_msg(buf, r, rptr->re_sends);
|
||
|
||
if (s == -1)
|
||
{
|
||
h_errno = TRY_AGAIN;
|
||
return -1;
|
||
}
|
||
else
|
||
rptr->re_sent += s;
|
||
return 0;
|
||
}
|
||
|
||
/*
|
||
* ar_gethostbyname
|
||
*
|
||
* Replacement library function call to gethostbyname(). This one, however,
|
||
* doesn't return the record being looked up but just places the query in the
|
||
* queue to await answers.
|
||
*/
|
||
int ar_gethostbyname(char *name, char *info, int size, char *nick, char *user, char *h, char *chan, int server, void (*func)(), char *command)
|
||
{
|
||
char host[HOSTLEN+1];
|
||
struct resinfo resi = { 0 };
|
||
|
||
if (size && info)
|
||
{
|
||
resi.ri_ptr = new_malloc(size + 1);
|
||
if (*info)
|
||
memcpy(resi.ri_ptr, info, size);
|
||
resi.ri_size = size;
|
||
}
|
||
ar_reinfo.re_na_look++;
|
||
(void)strncpy(host, name, 64);
|
||
host[64] = '\0';
|
||
|
||
return do_query_name(&resi, host, NULL, nick, user, h, chan, server, func, command);
|
||
}
|
||
|
||
static int do_query_name(struct resinfo *resi, char *name, register struct reslist *rptr, char *nick, char *user, char *h, char *chan, int server, void (*func)(), char *command)
|
||
{
|
||
char hname[HOSTLEN];
|
||
int len;
|
||
|
||
len = strlen((char *)strncpy(hname, name, sizeof(hname)-1));
|
||
|
||
if (rptr && (hname[len-1] != '.'))
|
||
{
|
||
(void)strncat(hname, ar_dot, sizeof(hname)-len-1);
|
||
/*
|
||
* NOTE: The logical relationship between DNSRCH and DEFNAMES
|
||
* is implies. ie no DEFNAES, no DNSRCH.
|
||
*/
|
||
if ((_res.options & (RES_DEFNAMES|RES_DNSRCH)) ==
|
||
(RES_DEFNAMES|RES_DNSRCH))
|
||
{
|
||
if (_res.dnsrch[(int)rptr->re_srch])
|
||
(void)strncat(hname, _res.dnsrch[(int)rptr->re_srch],
|
||
sizeof(hname) - ++len -1);
|
||
}
|
||
else if (_res.options & RES_DEFNAMES)
|
||
(void)strncat(hname, ar_domainname, sizeof(hname) - len -1);
|
||
}
|
||
|
||
/*
|
||
* Store the name passed as the one to lookup and generate other host
|
||
* names to pass onto the nameserver(s) for lookups.
|
||
*/
|
||
if (!rptr)
|
||
{
|
||
rptr = ar_make_request(resi, nick, user, h, chan, server, func, command);
|
||
rptr->re_type = T_A;
|
||
(void)strncpy(rptr->re_name, name, sizeof(rptr->re_name)-1);
|
||
}
|
||
return (ar_query_name(hname, C_IN, T_A, rptr));
|
||
}
|
||
|
||
/*
|
||
* ar_gethostbyaddr
|
||
*
|
||
* Generates a query for a given IP address.
|
||
*/
|
||
int ar_gethostbyaddr(char *addr, char *info, int size, char *nick, char *user, char *h, char *chan, int server, void (*func)(), char *command)
|
||
{
|
||
struct resinfo resi = { 0 };
|
||
|
||
if (size && info)
|
||
{
|
||
resi.ri_ptr = new_malloc(size + 1);
|
||
if (*info)
|
||
memcpy(resi.ri_ptr, info, size);
|
||
resi.ri_size = size;
|
||
}
|
||
ar_reinfo.re_nu_look++;
|
||
return do_query_number(&resi, addr, NULL, nick, user, h, chan, server, func, command);
|
||
}
|
||
|
||
/*
|
||
* do_query_number
|
||
*
|
||
* Use this to do reverse IP# lookups.
|
||
*/
|
||
static int do_query_number(struct resinfo *resi, char *numb, register struct reslist *rptr, char *nick, char *user, char *h, char *chan, int server, void (*func)(), char *command)
|
||
{
|
||
register unsigned char *cp;
|
||
static char ipbuf[32];
|
||
|
||
/*
|
||
* Generate name in the "in-addr.arpa" domain. No addings bits to this
|
||
* name to get more names to query!.
|
||
*/
|
||
cp = (unsigned char *)numb;
|
||
(void)sprintf(ipbuf,"%u.%u.%u.%u.in-addr.arpa.",
|
||
(unsigned int)(cp[3]), (unsigned int)(cp[2]),
|
||
(unsigned int)(cp[1]), (unsigned int)(cp[0]));
|
||
|
||
if (!rptr)
|
||
{
|
||
rptr = ar_make_request(resi, nick, user, h, chan, server, func, command);
|
||
rptr->re_type = T_PTR;
|
||
rptr->re_he.h_length = sizeof(struct in_addr);
|
||
memcpy((char *)&rptr->re_addr, numb, rptr->re_he.h_length);
|
||
memcpy((char *)&rptr->re_he.h_addr_list[0].s_addr, numb,
|
||
rptr->re_he.h_length);
|
||
}
|
||
return (ar_query_name(ipbuf, C_IN, T_PTR, rptr));
|
||
}
|
||
|
||
/*
|
||
* ar_resent_query
|
||
*
|
||
* resends a query.
|
||
*/
|
||
static int ar_resend_query(struct reslist *rptr)
|
||
{
|
||
if (!rptr->re_resend)
|
||
return -1;
|
||
|
||
switch(rptr->re_type)
|
||
{
|
||
case T_PTR:
|
||
ar_reinfo.re_resends++;
|
||
return do_query_number(NULL, (char *)&rptr->re_addr, rptr, NULL, NULL, NULL, NULL, -1, NULL, NULL);
|
||
case T_A:
|
||
ar_reinfo.re_resends++;
|
||
return do_query_name(NULL, rptr->re_name, rptr, NULL, NULL, NULL, NULL, -1, NULL, NULL);
|
||
default:
|
||
break;
|
||
}
|
||
|
||
return -1;
|
||
}
|
||
|
||
/*
|
||
* ar_procanswer
|
||
*
|
||
* process an answer received from a nameserver.
|
||
*/
|
||
static int ar_procanswer(struct reslist *rptr, HEADER *hptr, unsigned char *buf, unsigned char *eob)
|
||
{
|
||
unsigned char *cp;
|
||
char **alias;
|
||
int class, type, dlen, len, ans = 0, n;
|
||
unsigned int ttl, dr, *adr;
|
||
|
||
cp = buf + HFIXEDSZ;
|
||
adr = (unsigned int *)rptr->re_he.h_addr_list;
|
||
|
||
while (*adr)
|
||
adr++;
|
||
|
||
alias = rptr->re_he.h_aliases;
|
||
while (*alias)
|
||
alias++;
|
||
|
||
/*
|
||
* Skip over the original question.
|
||
*/
|
||
#ifndef __QNX__
|
||
/* QNX doesn't seem to have this function, not sure
|
||
* what it does at the moment but I may change this
|
||
* in the future. - Brian
|
||
*/
|
||
while (hptr->qdcount-- > 0)
|
||
cp += dn_skipname(cp, eob) + QFIXEDSZ;
|
||
#endif
|
||
/*
|
||
* process each answer sent to us. blech.
|
||
*/
|
||
while (hptr->ancount-- > 0 && cp < eob) {
|
||
n = dn_expand(buf, eob, cp, ar_hostbuf, sizeof(ar_hostbuf)-1);
|
||
cp += n;
|
||
if (n <= 0)
|
||
return ans;
|
||
|
||
ans++;
|
||
/*
|
||
* 'skip' past the general dns crap (ttl, class, etc) to get
|
||
* the pointer to the right spot. Some of thse are actually
|
||
* useful so its not a good idea to skip past in one big jump.
|
||
*/
|
||
GETSHORT(type, cp);
|
||
GETSHORT(class, cp);
|
||
GETLONG(ttl, cp);
|
||
GETSHORT(dlen, cp);
|
||
rptr->re_type = type;
|
||
(void)ttl; /* unused */
|
||
|
||
switch(type)
|
||
{
|
||
case T_A :
|
||
if (dlen != sizeof(struct in_addr))
|
||
return 0;
|
||
rptr->re_he.h_length = dlen;
|
||
if (ans == 1)
|
||
rptr->re_he.h_addrtype=(class == C_IN) ?
|
||
AF_INET : AF_UNSPEC;
|
||
memcpy(&dr, cp, dlen);
|
||
*adr++ = dr;
|
||
*adr = 0;
|
||
cp += dlen;
|
||
len = strlen(ar_hostbuf);
|
||
if (!rptr->re_he.h_name)
|
||
malloc_strcpy(&rptr->re_he.h_name, ar_hostbuf);
|
||
break;
|
||
case T_PTR :
|
||
if ((n = dn_expand(buf, eob, cp, ar_hostbuf,
|
||
sizeof(ar_hostbuf)-1 )) < 0)
|
||
{
|
||
cp += n;
|
||
continue;
|
||
}
|
||
ar_hostbuf[HOSTLEN] = 0;
|
||
cp += n;
|
||
len = strlen(ar_hostbuf)+1;
|
||
/*
|
||
* copy the returned hostname into the host name
|
||
* or alias field if there is a known hostname
|
||
* already.
|
||
*/
|
||
if (!rptr->re_he.h_name)
|
||
malloc_strcpy(&rptr->re_he.h_name, ar_hostbuf);
|
||
else
|
||
{
|
||
*alias = (char *)new_malloc(len);
|
||
strcpy(*alias++, ar_hostbuf);
|
||
*alias = NULL;
|
||
}
|
||
break;
|
||
case T_CNAME :
|
||
cp += dlen;
|
||
if (alias >= &(rptr->re_he.h_aliases[MAXALIASES-1]))
|
||
continue;
|
||
n = strlen(ar_hostbuf)+1;
|
||
*alias = (char *)new_malloc(n);
|
||
(void)strcpy(*alias++, ar_hostbuf);
|
||
*alias = NULL;
|
||
break;
|
||
default :
|
||
cp += dlen;
|
||
break;
|
||
}
|
||
}
|
||
|
||
return ans;
|
||
}
|
||
|
||
/*
|
||
* ar_answer
|
||
*
|
||
* Get an answer from a DNS server and process it. If a query is found to
|
||
* which no answer has been given to yet, copy its 'info' structure back
|
||
* to where "reip" points and return a pointer to the hostent structure.
|
||
*/
|
||
struct hostent *ar_answer(char *reip, int size, void (*func)(struct reslist *) )
|
||
{
|
||
static unsigned char ar_rcvbuf[HFIXEDSZ + MAXPACKET];
|
||
static struct hostent ar_host;
|
||
|
||
HEADER hptr;
|
||
struct reslist *rptr = NULL;
|
||
struct hostent *hp;
|
||
char **s;
|
||
unsigned long *adr;
|
||
int rc, i, n, a;
|
||
|
||
rc = recv(ar_resfd, ar_rcvbuf, sizeof(ar_rcvbuf), 0);
|
||
if (rc <= 0)
|
||
goto getres_err;
|
||
|
||
ar_reinfo.re_replies++;
|
||
/* hptr = (HEADER *)ar_rcvbuf;*/
|
||
memcpy(&hptr, ar_rcvbuf, sizeof(HEADER));
|
||
|
||
/*
|
||
* convert things to be in the right order.
|
||
*/
|
||
hptr.id = ntohs(hptr.id);
|
||
hptr.ancount = ntohs(hptr.ancount);
|
||
hptr.arcount = ntohs(hptr.arcount);
|
||
hptr.nscount = ntohs(hptr.nscount);
|
||
hptr.qdcount = ntohs(hptr.qdcount);
|
||
/*
|
||
* response for an id which we have already received an answer for
|
||
* just ignore this response.
|
||
*/
|
||
rptr = ar_find_id(hptr.id);
|
||
if (!rptr)
|
||
goto getres_err;
|
||
|
||
if ((hptr.rcode != NOERROR) || (hptr.ancount == 0))
|
||
{
|
||
switch (hptr.rcode)
|
||
{
|
||
case NXDOMAIN:
|
||
h_errno = HOST_NOT_FOUND;
|
||
break;
|
||
case SERVFAIL:
|
||
h_errno = TRY_AGAIN;
|
||
break;
|
||
case NOERROR:
|
||
h_errno = NO_DATA;
|
||
break;
|
||
case FORMERR:
|
||
case NOTIMP:
|
||
case REFUSED:
|
||
default:
|
||
h_errno = NO_RECOVERY;
|
||
break;
|
||
}
|
||
ar_reinfo.re_errors++;
|
||
/*
|
||
** If a bad error was returned, we stop here and don't send
|
||
** send any more (no retries granted).
|
||
*/
|
||
if (h_errno != TRY_AGAIN)
|
||
{
|
||
rptr->re_resend = 0;
|
||
rptr->re_retries = 0;
|
||
}
|
||
goto getres_err;
|
||
}
|
||
|
||
a = ar_procanswer(rptr, &hptr, ar_rcvbuf, ar_rcvbuf+rc);
|
||
|
||
if ((rptr->re_type == T_PTR) && (_res.options & RES_CHECKPTR))
|
||
{
|
||
/*
|
||
* For reverse lookups on IP#'s, lookup the name that is given
|
||
* for the ip# and return with that as the official result.
|
||
* -avalon
|
||
*/
|
||
rptr->re_type = T_A;
|
||
/*
|
||
* Clean out the list of addresses already set, even though
|
||
* there should only be one :)
|
||
*/
|
||
adr = (unsigned long *)rptr->re_he.h_addr_list;
|
||
while (*adr)
|
||
*adr++ = 0L;
|
||
/*
|
||
* Lookup the name that we were given for the ip#
|
||
*/
|
||
ar_reinfo.re_na_look++;
|
||
(void)strncpy(rptr->re_name, rptr->re_he.h_name,
|
||
sizeof(rptr->re_name)-1);
|
||
rptr->re_he.h_name = NULL;
|
||
rptr->re_retries = MAX_RETRIES;/*_res.retry + 2;*/
|
||
rptr->re_sends = 1;
|
||
rptr->re_resend = 1;
|
||
if (rptr->re_he.h_name)
|
||
new_free(&rptr->re_he.h_name);
|
||
ar_reinfo.re_na_look++;
|
||
(void)ar_query_name(rptr->re_name, C_IN, T_A, rptr);
|
||
return NULL;
|
||
}
|
||
|
||
if (reip && rptr->re_rinfo.ri_ptr && size)
|
||
memcpy(reip, rptr->re_rinfo.ri_ptr,
|
||
MIN(rptr->re_rinfo.ri_size, size));
|
||
|
||
/*
|
||
* Clean up structure from previous usage.
|
||
*/
|
||
hp = &ar_host;
|
||
if (hp->h_name)
|
||
new_free(&hp->h_name);
|
||
if ((s = hp->h_aliases))
|
||
{
|
||
while (*s)
|
||
{
|
||
new_free(s);
|
||
s++;
|
||
}
|
||
new_free(&hp->h_aliases);
|
||
}
|
||
if ((s = hp->h_addr_list))
|
||
{
|
||
|
||
while (*s)
|
||
{
|
||
new_free(s);
|
||
s++;
|
||
}
|
||
new_free(&hp->h_addr_list);
|
||
hp->h_addr_list = NULL;
|
||
}
|
||
memset ((char *)hp, 0, sizeof(*hp));
|
||
/*
|
||
* Setup and copy details for the structure we return a pointer to.
|
||
*/
|
||
hp->h_addrtype = AF_INET;
|
||
hp->h_length = sizeof(struct in_addr);
|
||
malloc_strcpy(&hp->h_name, rptr->re_he.h_name);
|
||
/*
|
||
* Count IP#'s.
|
||
*/
|
||
for (i = 0, n = 0; i < MAXADDRS; i++, n++)
|
||
if (!rptr->re_he.h_addr_list[i].s_addr)
|
||
break;
|
||
s = hp->h_addr_list = (char **)new_malloc((n + 1) * sizeof(char *));
|
||
if (n)
|
||
{
|
||
*s = (char *)new_malloc(sizeof(struct in_addr));
|
||
memcpy(*s, (char *)&rptr->re_he.h_addr_list[0].s_addr,
|
||
sizeof(struct in_addr));
|
||
s++;
|
||
for (i = 1; i < n; i++, s++)
|
||
{
|
||
*s = (char *)new_malloc(sizeof(struct in_addr));
|
||
memcpy(*s, (char *)&rptr->re_he.h_addr_list[i].s_addr,
|
||
sizeof(struct in_addr));
|
||
}
|
||
}
|
||
*s = NULL;
|
||
/*
|
||
* Count CNAMEs
|
||
*/
|
||
for (i = 0, n = 0; i < MAXADDRS; i++, n++)
|
||
if (!rptr->re_he.h_aliases[i])
|
||
break;
|
||
s = hp->h_aliases = (char **)new_malloc((n + 1) * sizeof(char *));
|
||
for (i = 0; i < n; i++)
|
||
{
|
||
*s++ = rptr->re_he.h_aliases[i];
|
||
rptr->re_he.h_aliases[i] = NULL;
|
||
}
|
||
*s = NULL;
|
||
if (rptr->func)
|
||
(*rptr->func)(rptr);
|
||
else if (func)
|
||
(*func)(rptr);
|
||
if (a > 0)
|
||
(void)ar_remrequest(rptr);
|
||
else
|
||
if (!rptr->re_sent)
|
||
(void)ar_remrequest(rptr);
|
||
return hp;
|
||
|
||
getres_err:
|
||
if (rptr)
|
||
{
|
||
if (reip && rptr->re_rinfo.ri_ptr && size)
|
||
memcpy(reip, rptr->re_rinfo.ri_ptr,
|
||
MIN(rptr->re_rinfo.ri_size, size));
|
||
if ((h_errno != TRY_AGAIN) &&
|
||
((_res.options & (RES_DNSRCH|RES_DEFNAMES)) ==
|
||
(RES_DNSRCH|RES_DEFNAMES) ))
|
||
if (_res.dnsrch[(int)rptr->re_srch])
|
||
{
|
||
rptr->re_retries = MAX_RETRIES; /*_res.retry + 2;*/
|
||
rptr->re_sends = 1;
|
||
rptr->re_resend = 1;
|
||
(void)ar_resend_query(rptr);
|
||
rptr->re_srch++;
|
||
}
|
||
return NULL;
|
||
}
|
||
return NULL;
|
||
}
|
||
|
||
static int ar_seq = 0;
|
||
static int ar_lookup = 0;
|
||
|
||
#endif /* THREAD */
|
||
#endif /* WANT_NSLOOKUP */
|
||
|
||
void set_nslookupfd(fd_set *rd)
|
||
{
|
||
#ifdef WANT_NSLOOKUP
|
||
#ifdef THREAD
|
||
set_dns_output_fd(rd);
|
||
#else
|
||
int s;
|
||
if ((s = ar_init(0)) != -1)
|
||
FD_SET(s, rd);
|
||
#endif /* THREAD */
|
||
#endif /* WANT_NSLOOKUP */
|
||
}
|
||
|
||
long print_nslookup(fd_set *rd)
|
||
{
|
||
#ifdef WANT_NSLOOKUP
|
||
#ifdef THREAD
|
||
dns_check(rd);
|
||
#else
|
||
struct hostent *hp = NULL;
|
||
int ar_del = 0;
|
||
int s;
|
||
if ((s = ar_init(0)) == -1)
|
||
return -1;
|
||
if (!(FD_ISSET(s, rd)))
|
||
{
|
||
unsigned long when = 0;
|
||
when = ar_timeout(now, (char *)&ar_del, sizeof(ar_del), print_ns_fail);
|
||
if (ar_del)
|
||
ar_lookup--;
|
||
return when;
|
||
}
|
||
if ((hp = ar_answer((char *)&ar_del, sizeof(ar_del), print_ns_succeed)))
|
||
{
|
||
char **s;
|
||
ar_lookup--;
|
||
new_free(&hp->h_name);
|
||
if ((s = hp->h_aliases))
|
||
{
|
||
while (*s)
|
||
{
|
||
new_free(s);
|
||
s++;
|
||
}
|
||
new_free(&hp->h_aliases);
|
||
}
|
||
if ((s = hp->h_addr_list))
|
||
{
|
||
while (*s)
|
||
{
|
||
new_free(s);
|
||
s++;
|
||
}
|
||
new_free(&hp->h_addr_list);
|
||
}
|
||
}
|
||
#endif /* THREAD */
|
||
#endif /* WANT_NSLOOKUP */
|
||
return -1;
|
||
}
|
||
|
||
char *do_nslookup(char *host, char *nick, char *user, char *chan, int server, void (*func)(), char *command)
|
||
{
|
||
#ifdef WANT_NSLOOKUP
|
||
#ifdef THREAD
|
||
struct reslist *info = new_malloc(sizeof(struct reslist));
|
||
|
||
info->host = m_strdup(host);
|
||
info->nick = m_strdup(nick);
|
||
info->user = m_strdup(user);
|
||
info->channel = m_strdup(chan);
|
||
if(command)
|
||
info->command = m_strdup(command);
|
||
info->server = server;
|
||
info->func = func;
|
||
|
||
add_to_dns_queue(host, cdns_generic_callback, NULL, info, DNS_URGENT);
|
||
#else
|
||
struct in_addr temp1;
|
||
|
||
if (!host)
|
||
return NULL;
|
||
|
||
if ((ar_init(0) == -1))
|
||
ar_init(ARES_INITLIST|ARES_INITSOCK|ARES_CALLINIT);
|
||
|
||
ar_lookup++;
|
||
if (isdigit((unsigned char)*(host + strlen(host) - 1)))
|
||
{
|
||
ar_seq++;
|
||
temp1.s_addr = inet_addr(host);
|
||
ar_gethostbyaddr((char *)&temp1.s_addr, (char *)&ar_seq, sizeof(ar_seq), nick, user, host, chan, server, func, command);
|
||
}
|
||
else
|
||
{
|
||
ar_seq++;
|
||
ar_gethostbyname(host, (char *)&ar_seq, sizeof(ar_seq), nick, user, host, chan, server, func, command);
|
||
}
|
||
#endif /* THREAD */
|
||
#endif /* WANT_NSLOOKUP */
|
||
return NULL;
|
||
}
|
||
|
||
#ifdef WANT_NSLOOKUP
|
||
void userhost_nsl(UserhostItem *stuff, char *nick, char *args)
|
||
{
|
||
char *nsl = NULL;
|
||
|
||
if (!stuff || !stuff->nick || !strcmp(stuff->user, "<UNKNOWN>") || my_stricmp(stuff->nick, nick))
|
||
{
|
||
say("No information for %s", nick);
|
||
return;
|
||
}
|
||
if (args)
|
||
{
|
||
next_arg(args, &nsl);
|
||
}
|
||
do_nslookup(stuff->host, stuff->nick, stuff->user, NULL, from_server, NULL, (nsl && *nsl) ? nsl : NULL);
|
||
}
|
||
#endif
|
||
|
||
BUILT_IN_COMMAND(nslookup)
|
||
{
|
||
#ifdef WANT_NSLOOKUP
|
||
char *host;
|
||
char *cmd = NULL;
|
||
int count = 0;
|
||
|
||
while ((host = next_arg(args, &args)))
|
||
{
|
||
if (count == 0)
|
||
bitchsay("Checking tables...");
|
||
if (*host == '-' || *host == '/')
|
||
{
|
||
host++;
|
||
|
||
if (host && !my_stricmp(host, "cmd"))
|
||
{
|
||
if (!(cmd = next_expr(&args, '{')))
|
||
bitchsay("Need {...} for -CMD argument");
|
||
else
|
||
host = next_arg(args, &args);
|
||
}
|
||
}
|
||
if (!host || !*host)
|
||
break;
|
||
if (!strchr(host, '.'))
|
||
userhostbase(host, userhost_nsl, 1, "%s%s%s", host, cmd ? space:empty_string, cmd?cmd:empty_string);
|
||
else
|
||
do_nslookup(host, NULL, NULL, NULL, from_server, NULL, cmd ? cmd : NULL);
|
||
count++;
|
||
}
|
||
#else
|
||
put_it("This command is disabled in this client");
|
||
#endif
|
||
}
|
||
|
||
|
||
char *rights(char *string, int num)
|
||
{
|
||
if (strlen(string) < num)
|
||
return string;
|
||
return (string + strlen(string) - num);
|
||
}
|
||
|
||
int numchar(char *string, char c)
|
||
{
|
||
int num = 0;
|
||
|
||
while (*string)
|
||
{
|
||
if (tolower(*string) == tolower(c))
|
||
num++;
|
||
string++;
|
||
}
|
||
return num;
|
||
}
|
||
|
||
char *cluster (char *hostname)
|
||
{
|
||
static char result[IRCD_BUFFER_SIZE/4 + 1];
|
||
char temphost[BIG_BUFFER_SIZE + 1];
|
||
char *host;
|
||
char *atsign;
|
||
|
||
if (!hostname)
|
||
return NULL;
|
||
|
||
*result = 0;
|
||
atsign = strchr(hostname, '@');
|
||
if (atsign) {
|
||
if (*hostname == '~') {
|
||
strcpy(result, "~*@");
|
||
} else {
|
||
size_t ident_len = atsign - hostname;
|
||
|
||
if (ident_len <= 9) {
|
||
/* copy ident@ */
|
||
strncat(result, hostname, ident_len + 1);
|
||
} else {
|
||
strncat(result, hostname, 8);
|
||
strcat(result, "*@");
|
||
}
|
||
}
|
||
hostname = atsign + 1;
|
||
}
|
||
|
||
strlcpy(temphost, hostname, sizeof temphost);
|
||
host = temphost;
|
||
|
||
if (*host && isdigit((unsigned char)*(host + strlen(host) - 1)))
|
||
{
|
||
/* Thanks icebreak for this small patch which fixes this function */
|
||
int i;
|
||
char *tmp;
|
||
char count = 0;
|
||
|
||
tmp = host;
|
||
while((tmp - host) < strlen(host))
|
||
{
|
||
if((tmp = strchr(tmp,'.')) == NULL)
|
||
break;
|
||
count++;
|
||
tmp++;
|
||
}
|
||
tmp = host;
|
||
for (i = 0; i < count; i++)
|
||
tmp = strchr(tmp, '.') + 1;
|
||
*tmp = '\0';
|
||
strlcat(result, host, sizeof result);
|
||
strlcat(result, "*", sizeof result);
|
||
}
|
||
else
|
||
{
|
||
char *tmp;
|
||
int num;
|
||
|
||
num = 1;
|
||
tmp = rights(host, 3);
|
||
if (my_stricmp(tmp, "com") &&
|
||
my_stricmp(tmp, "edu") &&
|
||
my_stricmp(tmp, "net") &&
|
||
(stristr(host, "com") ||
|
||
stristr(host, "edu")))
|
||
num = 2;
|
||
while (host && *host && (numchar(host, '.') > num))
|
||
{
|
||
if ((host = strchr(host, '.')) != NULL)
|
||
host++;
|
||
else
|
||
return (char *) NULL;
|
||
}
|
||
|
||
/* We don't need strlcat for these first two, because
|
||
* at this point the maximum length of the string in
|
||
* result is 11 */
|
||
strcat(result, "*");
|
||
if (my_stricmp(host, temphost))
|
||
strcat(result, ".");
|
||
strlcat(result, host, sizeof result);
|
||
}
|
||
return result;
|
||
}
|
||
|
||
|
||
|
||
|
||
struct _sock_manager
|
||
{
|
||
int init;
|
||
int count;
|
||
int max_fd;
|
||
SocketList sockets[FD_SETSIZE];
|
||
} sock_manager = {0, 0, -1, {{ 0, 0, 0, NULL, 0, 0, NULL, NULL, NULL }}};
|
||
|
||
#define SOCKET_TIMEOUT 120
|
||
|
||
|
||
#ifdef GUI
|
||
char *checkmenu(MenuList *check, int menuid)
|
||
{
|
||
MenuList *tmpml;
|
||
MenuStruct *tmpms;
|
||
char *tmpalias;
|
||
|
||
tmpml=check;
|
||
while(tmpml!=NULL)
|
||
{
|
||
if (tmpml->menutype==GUISUBMENU || tmpml->menutype==GUISHARED || tmpml->menutype==GUIBRKSUBMENU)
|
||
{
|
||
tmpms = (MenuStruct *)findmenu(tmpml->submenu);
|
||
if ((tmpalias=checkmenu(tmpms->menuorigin, menuid))!=NULL)
|
||
return tmpalias;
|
||
}
|
||
if (tmpml->menuid==menuid)
|
||
return tmpml->alias;
|
||
tmpml=tmpml->next;
|
||
}
|
||
return NULL;
|
||
}
|
||
|
||
void scan_gui(fd_set *rd)
|
||
{
|
||
unsigned int guicmd[2];
|
||
extern MenuStruct *morigin;
|
||
extern unsigned long menucmd;
|
||
extern char *codeptr, *paramptr;
|
||
MenuStruct *tmpms;
|
||
int newpos, cursb;
|
||
char *alias;
|
||
Window *scrollwin, *newfocuswindow;
|
||
float bleah;
|
||
Screen *newfocusscreen;
|
||
|
||
#ifdef __EMXPM__
|
||
extern int just_resized;
|
||
extern Screen *just_resized_screen;
|
||
|
||
if(just_resized == 1)
|
||
WinSendMsg(just_resized_screen->hwndFrame, 0x041e, 0, 0);
|
||
#endif
|
||
|
||
/* Read the data from the pipe and decide what to do */
|
||
if(FD_ISSET(guiipc[0], rd))
|
||
{
|
||
read(guiipc[0], (void *)guicmd, sizeof(unsigned int) * 2);
|
||
switch(guicmd[0])
|
||
{
|
||
case EVMENU:
|
||
tmpms = morigin;
|
||
while(tmpms!=NULL)
|
||
{
|
||
if((alias=checkmenu(tmpms->menuorigin, menucmd))!=NULL)
|
||
{
|
||
int save_server = from_server;
|
||
Window *this_window = get_window_by_refnum((int)guicmd[1]);
|
||
|
||
if(this_window)
|
||
from_server = this_window->server;
|
||
make_window_current(this_window);
|
||
parse_line(NULL, alias, empty_string, 0, 0, 1);
|
||
|
||
from_server = save_server;
|
||
break;
|
||
}
|
||
tmpms=tmpms->next;
|
||
}
|
||
break;
|
||
case EVFOCUS:
|
||
gui_flush();
|
||
newfocuswindow=get_window_by_refnum((int)guicmd[1]);
|
||
if(newfocuswindow)
|
||
newfocusscreen=newfocuswindow->screen;
|
||
else
|
||
newfocusscreen=NULL;
|
||
if (newfocusscreen && newfocusscreen->current_window)
|
||
{
|
||
make_window_current(newfocusscreen->current_window);
|
||
output_screen=last_input_screen=newfocusscreen;
|
||
reset_display_target();
|
||
set_input_prompt(current_window, get_string_var(INPUT_PROMPT_VAR), 1);
|
||
}
|
||
update_input(UPDATE_ALL);
|
||
break;
|
||
case EVTITLE:
|
||
xterm_settitle();
|
||
break;
|
||
case EVREFRESH:
|
||
refresh_window_screen(get_window_by_refnum((int)guicmd[1]));
|
||
break;
|
||
case EVSTRACK:
|
||
if(newscrollerpos != lastscrollerpos || lastscrollerwindow != (int)guicmd[1])
|
||
{
|
||
lastscrollerpos=newscrollerpos;
|
||
lastscrollerwindow=(int)guicmd[1];
|
||
scrollwin=get_window_by_refnum((int)guicmd[1]);
|
||
bleah = get_int_var(SCROLLBACK_VAR);
|
||
newpos = (int)(((bleah-newscrollerpos) / bleah) * (scrollwin->display_buffer_size - scrollwin->display_size)) + scrollwin->display_size;
|
||
cursb = scrollwin->distance_from_display;
|
||
if (newpos > cursb)
|
||
scrollback_backwards_lines(newpos-cursb);
|
||
if (newpos < cursb)
|
||
scrollback_forwards_lines(cursb-newpos);
|
||
}
|
||
break;
|
||
case EVSUP:
|
||
scrollback_backwards_lines(1);
|
||
break;
|
||
case EVSDOWN:
|
||
scrollback_forwards_lines(1);
|
||
break;
|
||
case EVSUPPG:
|
||
scrollback_backwards((char)NULL, NULL);
|
||
break;
|
||
case EVSDOWNPG:
|
||
scrollback_forwards((char)NULL, NULL);
|
||
break;
|
||
case EVKEY:
|
||
{
|
||
int old_server = from_server;
|
||
|
||
if(current_window)
|
||
from_server = current_window->server;
|
||
|
||
wm_process((int)guicmd[1]);
|
||
|
||
from_server = old_server;
|
||
}
|
||
break;
|
||
case EVFILE:
|
||
if(codeptr && *codeptr && paramptr)
|
||
{
|
||
make_window_current(get_window_by_refnum((int)guicmd[1]));
|
||
parse_line(NULL, codeptr, paramptr, 0, 0, 1);
|
||
new_free(&codeptr);
|
||
new_free(¶mptr);
|
||
}
|
||
break;
|
||
#ifdef GTK
|
||
case EVPASTE:
|
||
gtk_main_paste((int)guicmd[1]);
|
||
break;
|
||
case EVDELETE:
|
||
scrollwin=get_window_by_refnum((int)guicmd[1]);
|
||
if(scrollwin && scrollwin->screen)
|
||
kill_screen(scrollwin->screen);
|
||
break;
|
||
#endif
|
||
}
|
||
}
|
||
}
|
||
#endif
|
||
|
||
void read_clonelist(int s)
|
||
{
|
||
char buffer[IRCD_BUFFER_SIZE + 1];
|
||
char *str = buffer;
|
||
switch(dgets(str, s, 0, IRCD_BUFFER_SIZE, NULL))
|
||
{
|
||
case -1:
|
||
{
|
||
do_hook(SOCKET_LIST, "%d %s %d", s, sock_manager.sockets[s].server, sock_manager.sockets[s].port);
|
||
close_socketread(s);
|
||
break;
|
||
}
|
||
case 0:
|
||
break;
|
||
default:
|
||
{
|
||
if ((buffer[strlen(buffer)-1] == '\r') || (buffer[strlen(buffer)-1] == '\n'))
|
||
buffer[strlen(buffer)-1] = 0;
|
||
if ((buffer[strlen(buffer)-1] == '\r') || (buffer[strlen(buffer)-1] == '\n'))
|
||
buffer[strlen(buffer)-1] = 0;
|
||
if (*buffer)
|
||
do_hook(SOCKET_LIST, "%d %s %d %s", s, sock_manager.sockets[s].server, sock_manager.sockets[s].port, buffer);
|
||
}
|
||
}
|
||
}
|
||
|
||
void read_clonenotify(int s)
|
||
{
|
||
unsigned long flags = 0;
|
||
flags = get_socketflags(s);
|
||
do_hook(SOCKET_NOTIFY_LIST, "%d %s %d %d", s, sock_manager.sockets[s].server, sock_manager.sockets[s].port, (unsigned int)flags);
|
||
}
|
||
|
||
unsigned long BX_set_socketflags(int s, unsigned long flags)
|
||
{
|
||
if (check_socket(s))
|
||
{
|
||
sock_manager.sockets[s].flags = flags;
|
||
return sock_manager.sockets[s].flags;
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
unsigned long BX_get_socketflags(int s)
|
||
{
|
||
if (check_socket(s))
|
||
return sock_manager.sockets[s].flags;
|
||
return 0;
|
||
}
|
||
|
||
char *get_socketserver(int s)
|
||
{
|
||
if (check_socket(s))
|
||
return sock_manager.sockets[s].server;
|
||
return NULL;
|
||
}
|
||
|
||
void *BX_get_socketinfo(int s)
|
||
{
|
||
if (check_socket(s))
|
||
return sock_manager.sockets[s].info;
|
||
return NULL;
|
||
}
|
||
|
||
void BX_set_socketinfo(int s, void *info)
|
||
{
|
||
if (check_socket(s))
|
||
sock_manager.sockets[s].info = info;
|
||
}
|
||
|
||
int BX_get_max_fd(void)
|
||
{
|
||
return sock_manager.max_fd + 1;
|
||
}
|
||
|
||
int BX_add_socketread(int s, int port, unsigned long flags, char *server, void (*func_read)(int), void (*func_write)(int))
|
||
{
|
||
if (!sock_manager.init)
|
||
{
|
||
fd_set rd;
|
||
FD_ZERO(&rd);
|
||
set_socket_read(&rd, &rd);
|
||
}
|
||
if (s >= FD_SETSIZE)
|
||
{
|
||
yell("File descriptor limit reached, dropping new socket.");
|
||
close(s);
|
||
return -1;
|
||
}
|
||
if (s > sock_manager.max_fd)
|
||
sock_manager.max_fd = s;
|
||
sock_manager.count++;
|
||
sock_manager.sockets[s].is_read = s;
|
||
sock_manager.sockets[s].port = port;
|
||
sock_manager.sockets[s].flags = flags;
|
||
if (server)
|
||
sock_manager.sockets[s].server = m_strdup(server);
|
||
sock_manager.sockets[s].func_read = func_read;
|
||
sock_manager.sockets[s].func_write = func_write;
|
||
new_open(s);
|
||
return s;
|
||
}
|
||
|
||
int BX_set_socketwrite(int s)
|
||
{
|
||
if (s >= FD_SETSIZE)
|
||
return -1;
|
||
if (s > sock_manager.max_fd)
|
||
sock_manager.max_fd = s;
|
||
sock_manager.sockets[s].is_write = s;
|
||
new_open_write(s);
|
||
return s;
|
||
}
|
||
|
||
void BX_add_sockettimeout(int s, time_t timeout, void *func)
|
||
{
|
||
if (timeout < 0)
|
||
{
|
||
timeout = get_int_var(CONNECT_TIMEOUT_VAR);
|
||
if (timeout <= 0)
|
||
timeout = SOCKET_TIMEOUT;
|
||
}
|
||
if (timeout)
|
||
sock_manager.sockets[s].time = now + timeout;
|
||
else
|
||
sock_manager.sockets[s].time = 0;
|
||
sock_manager.sockets[s].cleanup = func;
|
||
}
|
||
|
||
void BX_close_socketread(int s)
|
||
{
|
||
if (!sock_manager.count)
|
||
return;
|
||
if (sock_manager.sockets[s].is_read)
|
||
{
|
||
new_free(&sock_manager.sockets[s].server);
|
||
if (sock_manager.sockets[s].is_write)
|
||
new_close_write(s);
|
||
new_close(s);
|
||
memset(&sock_manager.sockets[s], 0, sizeof(SocketList));
|
||
sock_manager.count--;
|
||
if (s == sock_manager.max_fd)
|
||
{
|
||
int i;
|
||
sock_manager.max_fd = -1;
|
||
for (i = 0; i < FD_SETSIZE; i++)
|
||
if (sock_manager.sockets[i].is_read)
|
||
sock_manager.max_fd = i;
|
||
else if( sock_manager.sockets[i].is_write)
|
||
sock_manager.max_fd = i;
|
||
}
|
||
}
|
||
}
|
||
|
||
int BX_check_socket(int s)
|
||
{
|
||
if (s != -1 && sock_manager.count && sock_manager.sockets[s].is_read)
|
||
return 1;
|
||
return 0;
|
||
}
|
||
|
||
int check_dcc_socket(int s)
|
||
{
|
||
if (sock_manager.count && sock_manager.sockets[s].is_read && sock_manager.sockets[s].info)
|
||
{
|
||
if ( ((dcc_struct_type *)sock_manager.sockets[s].info)->struct_type == DCC_STRUCT_TYPE)
|
||
return 1;
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
int BX_write_sockets(int s, char *str, int len, int nl)
|
||
{
|
||
if (s < 1)
|
||
return -1;
|
||
if (nl)
|
||
{
|
||
char *buf;
|
||
buf = alloca(strlen(str)+4);
|
||
strcpy(buf, str);
|
||
strcat(buf, "\r\n");
|
||
len += 2;
|
||
return write(s, buf, len);
|
||
}
|
||
return write(s, str, len);
|
||
}
|
||
|
||
int BX_read_sockets(int s, char *str, int len)
|
||
{
|
||
if (s < 1)
|
||
return -1;
|
||
return read(s, str, len);
|
||
}
|
||
|
||
void set_socket_read (fd_set *rd, fd_set *wr)
|
||
{
|
||
register int i;
|
||
static int socket_init = 0;
|
||
if (!socket_init)
|
||
{
|
||
memset(&sock_manager, 0, sizeof(sock_manager));
|
||
socket_init++;
|
||
sock_manager.init++;
|
||
}
|
||
if (!sock_manager.count) return;
|
||
for (i = 0; i < sock_manager.max_fd + 1; i++)
|
||
{
|
||
if (sock_manager.sockets[i].is_read)
|
||
FD_SET(sock_manager.sockets[i].is_read, rd);
|
||
if (sock_manager.sockets[i].is_write)
|
||
FD_SET(sock_manager.sockets[i].is_write, wr);
|
||
}
|
||
}
|
||
|
||
void scan_sockets(fd_set *rd, fd_set *wr)
|
||
{
|
||
register int i;
|
||
time_t t = now;
|
||
if (!sock_manager.count) return;
|
||
for (i = 0; i < sock_manager.max_fd+1; i++)
|
||
{
|
||
if (sock_manager.sockets[i].is_read && FD_ISSET(sock_manager.sockets[i].is_read, rd))
|
||
(sock_manager.sockets[i].func_read) (sock_manager.sockets[i].is_read);
|
||
if (sock_manager.sockets[i].func_write && sock_manager.sockets[i].is_write && FD_ISSET(sock_manager.sockets[i].is_write, wr))
|
||
(sock_manager.sockets[i].func_write) (sock_manager.sockets[i].is_write);
|
||
if (sock_manager.sockets[i].time && (t >= sock_manager.sockets[i].time))
|
||
{
|
||
if (sock_manager.sockets[i].cleanup)
|
||
(sock_manager.sockets[i].cleanup)(i);
|
||
else
|
||
close_socketread(i);
|
||
}
|
||
}
|
||
}
|
||
|
||
SocketList *BX_get_socket(int s)
|
||
{
|
||
if (check_socket(s))
|
||
return &sock_manager.sockets[s];
|
||
return NULL;
|
||
}
|
||
|
||
static void handle_socket_connect(int rc)
|
||
{
|
||
struct servent *serv;
|
||
struct sockaddr_foobar addr;
|
||
struct hostent *host;
|
||
char buf[128], *hostname = buf;
|
||
socklen_t address_len;
|
||
|
||
address_len = sizeof(struct sockaddr_foobar);
|
||
if ((getpeername(rc, (struct sockaddr *) &addr, &address_len)) != -1)
|
||
{
|
||
serv = getservbyport(addr.sf_port,"tcp");
|
||
strcpy(hostname, "unknown");
|
||
if (addr.sf_family == AF_INET)
|
||
{
|
||
address_len = sizeof(struct in_addr);
|
||
if ((host = gethostbyaddr((char *)&addr.sf_addr, address_len, AF_INET)))
|
||
hostname = (char *)host->h_name;
|
||
else
|
||
hostname = inet_ntoa(addr.sf_addr);
|
||
}
|
||
#ifdef IPV6
|
||
else
|
||
{
|
||
if (getnameinfo((struct sockaddr*) &addr, sizeof(struct sockaddr_foobar), hostname, 128, NULL, 0, 0))
|
||
hostname = (char *)inet_ntop(AF_INET6, (void*) &(addr.sf_addr6), buf, 128);
|
||
}
|
||
#endif
|
||
put_it("Hostname %s port %d is running (%s)", hostname, htons(addr.sf_port), serv == NULL? "UNKNOWN":serv->s_name);
|
||
}
|
||
close_socketread(rc);
|
||
}
|
||
|
||
static int scan(char *remote_host, int low_port, int high_port)
|
||
{
|
||
unsigned short int port;
|
||
int rc;
|
||
if (low_port == 0) low_port = 1;
|
||
for (port = low_port;port <= high_port;port++)
|
||
{
|
||
if ((rc = connect_by_number(remote_host, &port, SERVICE_CLIENT, PROTOCOL_TCP, 1)) < 0)
|
||
continue;
|
||
if ((add_socketread(rc, port, 0, NULL, handle_socket_connect, NULL)) > -1)
|
||
add_sockettimeout(rc, 120, NULL);
|
||
else
|
||
close_socketread(rc);
|
||
}
|
||
|
||
return 1;
|
||
}
|
||
|
||
void userhost_scanport(UserhostItem *stuff, char *nick, char *args)
|
||
{
|
||
char *t;
|
||
int low_port = 0, high_port = 0;
|
||
|
||
if (!stuff || !stuff->nick || !strcmp(stuff->user, "<UNKNOWN>") || my_stricmp(stuff->nick, nick))
|
||
{
|
||
bitchsay("No such nick [%s] found", nick);
|
||
return;
|
||
}
|
||
next_arg(args, &args);
|
||
t = next_arg(args, &args);
|
||
low_port = atol(t);
|
||
t = next_arg(args, &args);
|
||
high_port = atol(t);
|
||
if (resolv(stuff->host))
|
||
{
|
||
bitchsay("Scanning %s ports %d to %d", stuff->host, low_port, high_port);
|
||
scan(stuff->host, low_port, high_port);
|
||
return;
|
||
}
|
||
bitchsay("Cannot resolv host %s for %s", stuff->host, stuff->nick);
|
||
}
|
||
|
||
BUILT_IN_COMMAND(findports)
|
||
{
|
||
char *remote_host;
|
||
int low_port = 6660;
|
||
int high_port = 7000;
|
||
|
||
if (args && *args)
|
||
{
|
||
char *tmp = NULL;
|
||
remote_host = next_arg(args, &args);
|
||
if (args && *args)
|
||
{
|
||
tmp = next_arg(args, &args);
|
||
low_port = strtoul(tmp, NULL, 10);
|
||
if (args && *args)
|
||
{
|
||
tmp = next_arg(args, &args);
|
||
high_port = strtoul(tmp, NULL, 10);
|
||
}
|
||
else
|
||
high_port = low_port;
|
||
}
|
||
if (strchr(remote_host, '.') || strchr(remote_host, ':'))
|
||
{
|
||
if (resolv(remote_host))
|
||
{
|
||
bitchsay("Scanning %s's tcp ports %d through %d",remote_host, low_port,high_port);
|
||
scan(remote_host, low_port, high_port);
|
||
} else
|
||
bitchsay("No such host %s", remote_host);
|
||
}
|
||
else
|
||
userhostbase(remote_host, userhost_scanport, 1, "%s %d %d", remote_host, low_port, high_port);
|
||
}
|
||
return;
|
||
}
|
||
|
||
void userhost_ignore (UserhostItem *uhi, char *nick1, char *args)
|
||
{
|
||
char *p, *arg;
|
||
char *userhost_buf = NULL;
|
||
char *nick, *user, *host;
|
||
int old_window_display;
|
||
char ignorebuf[BIG_BUFFER_SIZE+1];
|
||
WhowasList *whowas;
|
||
|
||
if (uhi && uhi->nick && strcmp(uhi->user, "<UNKNOWN>") && !my_stricmp(uhi->nick, nick1))
|
||
{
|
||
nick = uhi->nick;
|
||
user = uhi->user;
|
||
host = uhi->host;
|
||
}
|
||
else if ((whowas = check_whowas_nick_buffer(nick1, NULL)))
|
||
{
|
||
nick = whowas->nicklist->nick;
|
||
user = userhost_buf = m_strdup(whowas->nicklist->host);
|
||
host = strchr(user, '@');
|
||
*host++ = 0;
|
||
bitchsay("Using WhoWas info for (un)ignore of %s", nick1);
|
||
}
|
||
else
|
||
{
|
||
say("No match for user %s", nick1);
|
||
return;
|
||
}
|
||
user = clear_server_flags(user);
|
||
|
||
arg = next_arg(args, &args);
|
||
if (!arg || !*arg || !my_stricmp(arg, "+HOST"))
|
||
sprintf(ignorebuf, "*!*@%s ALL -CRAP -PUBLIC", cluster(host));
|
||
else if (!my_stricmp(arg, "+USER"))
|
||
sprintf(ignorebuf, "*%s@%s ALL -CRAP -PUBLIC", user, cluster(host));
|
||
else if (!my_stricmp(arg, "-USER") || !my_stricmp(arg, "-HOST"))
|
||
{
|
||
Ignore *igptr, *igtmp;
|
||
int found = 0;
|
||
|
||
if (!my_stricmp(arg, "-HOST"))
|
||
sprintf(ignorebuf, "*!*@%s", cluster(host));
|
||
else
|
||
sprintf(ignorebuf, "%s!%s@%s", nick, user, host);
|
||
igptr = ignored_nicks;
|
||
while (igptr != NULL)
|
||
{
|
||
igtmp = igptr->next;
|
||
if (wild_match(igptr->nick, ignorebuf) ||
|
||
wild_match(nick, igptr->nick))
|
||
{
|
||
sprintf(ignorebuf, "%s NONE", igptr->nick);
|
||
old_window_display = window_display;
|
||
window_display = 0;
|
||
ignore(NULL, ignorebuf, ignorebuf, NULL);
|
||
window_display = old_window_display;
|
||
bitchsay("Unignored %s!%s@%s", nick, user, host);
|
||
found++;
|
||
}
|
||
igptr = igtmp;
|
||
}
|
||
if (!found)
|
||
bitchsay("No ignore matching %s found", nick);
|
||
new_free(&userhost_buf);
|
||
return;
|
||
}
|
||
old_window_display = window_display;
|
||
window_display = 0;
|
||
ignore(NULL, ignorebuf, ignorebuf, NULL);
|
||
if ((arg = next_arg(args, &args)))
|
||
{
|
||
char tmp[BIG_BUFFER_SIZE+1];
|
||
sprintf(tmp, "%s ^IGNORE %s NONE", arg, ignorebuf);
|
||
timercmd("TIMER", tmp, NULL, NULL);
|
||
}
|
||
window_display = old_window_display;
|
||
if ((p = strchr(ignorebuf, ' ')))
|
||
*p = 0;
|
||
say("Now ignoring ALL except CRAP and PUBLIC from %s", ignorebuf);
|
||
new_free(&userhost_buf);
|
||
return;
|
||
}
|
||
|
||
BUILT_IN_COMMAND(reset)
|
||
{
|
||
refresh_screen(0, NULL);
|
||
}
|
||
|
||
|
||
extern char *channel_key (char *);
|
||
BUILT_IN_COMMAND(cycle)
|
||
{
|
||
char *to = NULL;
|
||
int server = from_server;
|
||
ChannelList *chan;
|
||
|
||
if (args && *args)
|
||
to = make_channel(next_arg(args, &args));
|
||
|
||
if (!(chan = prepare_command(&server, to, NO_OP)))
|
||
return;
|
||
my_send_to_server(server, "PART %s\nJOIN %s%s%s", chan->channel, chan->channel, chan->key?space:empty_string, chan->key?chan->key:empty_string);
|
||
}
|
||
|
||
|
||
int do_newuser(char *command, char *args, char *subargs)
|
||
{
|
||
char *newusername = NULL;
|
||
if ((newusername = next_arg(args, &args)))
|
||
{
|
||
#ifdef IDENT_FAKE
|
||
FILE *outfile;
|
||
char *p = NULL, *q = NULL;
|
||
malloc_sprintf(&p, "~/%s", get_string_var(IDENT_HACK_VAR));
|
||
q = expand_twiddle(p);
|
||
if (!(outfile = fopen(q,"w")))
|
||
return 0;
|
||
#ifdef CIDENTD
|
||
fprintf(outfile,"hideme\nmynameis %s\n", newusername);
|
||
#else
|
||
fprintf(outfile,"%s", newusername);
|
||
#endif
|
||
fclose(outfile);
|
||
#endif
|
||
strlcpy(username, newusername, sizeof username);
|
||
if (subargs && *subargs)
|
||
strlcpy(realname, subargs, sizeof realname);
|
||
#ifdef IDENT_FAKE
|
||
new_free(&p); new_free(&q);
|
||
#endif
|
||
reconnect_cmd(NULL, newusername, NULL, NULL);
|
||
}
|
||
else
|
||
return 0;
|
||
return 1;
|
||
}
|
||
|
||
BUILT_IN_COMMAND(newnick)
|
||
{
|
||
char *newnick, *newusername;
|
||
|
||
if ((newnick = next_arg(args, &args)) &&
|
||
(newusername = next_arg(args, &args)))
|
||
do_newuser(newnick, newusername, args);
|
||
else
|
||
say("You must specify a nick and username");
|
||
}
|
||
|
||
|
||
BUILT_IN_COMMAND(newuser)
|
||
{
|
||
char *newusername;
|
||
|
||
if ((newusername = next_arg(args, &args)))
|
||
{
|
||
if ((do_newuser(NULL, newusername, args)))
|
||
say("You must specify a username.");
|
||
}
|
||
}
|
||
|
||
BUILT_IN_COMMAND(do_ig)
|
||
{
|
||
char *nick;
|
||
char ignore_type[6];
|
||
int got_ignore_type = 0;
|
||
int need_time = 0;
|
||
if (!args || !*args)
|
||
goto bad_ignore;
|
||
|
||
while ((nick = next_arg(args, &args)))
|
||
{
|
||
if (!nick || !*nick)
|
||
goto bad_ignore;
|
||
if (*nick == '-' || *nick == '+')
|
||
{
|
||
if (!my_stricmp(nick, "-USER") || !my_stricmp(nick, "+HOST") || !my_stricmp(nick, "+USER") || !my_stricmp(nick, "-HOST"))
|
||
strcpy(ignore_type, nick);
|
||
if (!args || !*args)
|
||
goto bad_ignore;
|
||
got_ignore_type++;
|
||
continue;
|
||
}
|
||
else if (!got_ignore_type)
|
||
{
|
||
if (command && !my_strnicmp(command, "IGH",3))
|
||
strcpy(ignore_type, "+HOST");
|
||
else if (command && !my_strnicmp(command, "IG",2))
|
||
strcpy(ignore_type, "+USER");
|
||
if (command && !my_strnicmp(command, "UNIGH", 5))
|
||
strcpy(ignore_type, "-HOST");
|
||
else if (command && !my_strnicmp(command, "UNIG", 4))
|
||
strcpy(ignore_type, "-USER");
|
||
if (command && toupper(command[strlen(command)-1]) == 'T')
|
||
need_time ++;
|
||
}
|
||
if (need_time)
|
||
userhostbase(nick, userhost_ignore, 1, "%s %d", ignore_type, get_int_var(IGNORE_TIME_VAR));
|
||
else
|
||
userhostbase(nick, userhost_ignore, 1, "%s", ignore_type);
|
||
}
|
||
bad_ignore:
|
||
return;
|
||
}
|
||
|
||
void put_user(const NickList *nick, const char *channel)
|
||
{
|
||
char *users_format;
|
||
|
||
if (nick->userlist)
|
||
users_format = fget_string_var(FORMAT_USERS_USER_FSET);
|
||
else if (nick->shitlist)
|
||
users_format = fget_string_var(FORMAT_USERS_SHIT_FSET);
|
||
else
|
||
users_format = fget_string_var(FORMAT_USERS_FSET);
|
||
|
||
put_it("%s", convert_output_format(users_format, "%s %s %s %s %d %c",
|
||
#ifdef WANT_USERLIST
|
||
nick->userlist ? convert_flags(nick->userlist->flags) : nick->shitlist?ltoa(nick->shitlist->level):"n/a",
|
||
#else
|
||
"n/a",
|
||
#endif
|
||
channel, nick->nick,
|
||
nick->host, nick->serverhops,
|
||
nick_isop(nick) ? '@' : nick_isvoice(nick)? 'v' : ' '));
|
||
}
|
||
|
||
BUILT_IN_COMMAND(users)
|
||
{
|
||
ChannelList *chan;
|
||
NickList *nicks;
|
||
NickList *sortl = NULL;
|
||
char *to = NULL,
|
||
*spec = "*!*@*",
|
||
*temp1 = NULL;
|
||
char modebuf[BIG_BUFFER_SIZE + 1];
|
||
char msgbuf[BIG_BUFFER_SIZE +1];
|
||
int count = 0,
|
||
ops = 0,
|
||
msg = 0,
|
||
num_kicks = 0,
|
||
hook = 0,
|
||
not = 0,
|
||
server = from_server,
|
||
sorted = NICKSORT_NORMAL;
|
||
|
||
*msgbuf = 0;
|
||
*modebuf = 0;
|
||
|
||
while (args && *args)
|
||
{
|
||
if (!args || !*args)
|
||
break;
|
||
temp1 = next_arg(args, &args);
|
||
if (temp1 && *temp1 == '-')
|
||
{
|
||
if (!my_strnicmp(temp1, "-ops", strlen(temp1)))
|
||
ops = 1;
|
||
else if (!my_strnicmp(temp1, "-nonops", strlen(temp1)))
|
||
ops = 2;
|
||
else if (!my_strnicmp(temp1, "-msg", strlen(temp1)))
|
||
msg = 1;
|
||
else if (!my_strnicmp(temp1, "-notice", strlen(temp1)))
|
||
msg = 2;
|
||
else if (!my_strnicmp(temp1, "-nkill", strlen(temp1)))
|
||
msg = 3;
|
||
else if (!my_strnicmp(temp1, "-kill", strlen(temp1)))
|
||
msg = 4;
|
||
else if (!my_strnicmp(temp1, "-kick", strlen(temp1)))
|
||
msg = 5;
|
||
else if (!my_strnicmp(temp1, "-stats", strlen(temp1)))
|
||
msg = 6;
|
||
else if (!my_strnicmp(temp1, "-ips", strlen(temp1)))
|
||
msg = 7;
|
||
else if (!my_strnicmp(temp1, "-sort", strlen(temp1)) && args && *args)
|
||
{
|
||
if (!my_strnicmp(args, "none", 4))
|
||
sorted = NICKSORT_NONE;
|
||
else if (!my_strnicmp(args, "host", 4))
|
||
sorted = NICKSORT_HOST;
|
||
else if (!my_strnicmp(args, "nick", 4))
|
||
sorted = NICKSORT_NICK;
|
||
else if (!my_strnicmp(args, "ip", 3))
|
||
sorted = NICKSORT_IP;
|
||
else if (!my_strnicmp(args, "time", 3))
|
||
sorted = NICKSORT_TIME;
|
||
if (sorted != NICKSORT_NORMAL)
|
||
next_arg(args, &args);
|
||
}
|
||
else if (strpbrk(temp1, "*!@."))
|
||
{
|
||
spec = temp1+1;
|
||
not = 1;
|
||
}
|
||
}
|
||
else if (temp1 && is_channel(temp1))
|
||
to = temp1;
|
||
else if (temp1 && strpbrk(temp1, "*!@."))
|
||
spec = temp1;
|
||
else
|
||
{
|
||
if (args && *args)
|
||
temp1[strlen(temp1)] = ' ';
|
||
args = temp1;
|
||
break;
|
||
}
|
||
}
|
||
if (!spec || !*spec)
|
||
spec = "*!*@*";
|
||
if (!(chan = prepare_command(&server, to, NO_OP)))
|
||
{
|
||
bitchsay(to?"Not on that channel %s":"No such channel %s", to?to:empty_string);
|
||
return;
|
||
}
|
||
set_display_target(chan->channel, LOG_CRAP);
|
||
if (command && !my_stricmp(command, "CHOPS"))
|
||
ops = 1;
|
||
if (command && !my_stricmp(command, "NOPS"))
|
||
ops = 2;
|
||
|
||
if ((msg == 1 || msg == 2) && (!args || !*args))
|
||
{
|
||
say("No message given");
|
||
reset_display_target();
|
||
return;
|
||
}
|
||
|
||
switch (msg)
|
||
{
|
||
case 6:
|
||
if (do_hook(STAT_HEADER_LIST, "%s %s %s %s %s", "Nick", "dops", "kicks","nicks","publics"))
|
||
put_it("Nick dops kicks nicks publics");
|
||
break;
|
||
case 0:
|
||
{
|
||
char *f;
|
||
if ((f = fget_string_var(FORMAT_USERS_TITLE_FSET)))
|
||
put_it("%s", convert_output_format(f, "%s %s", update_clock(GET_TIME), chan->channel));
|
||
}
|
||
default:
|
||
break;
|
||
}
|
||
|
||
sortl = sorted_nicklist(chan, sorted);
|
||
for (nicks = sortl; nicks; nicks = nicks->next)
|
||
{
|
||
sprintf(modebuf, "%s!%s", nicks->nick,
|
||
nicks->host ? nicks->host : "<UNKNOWN@UNKNOWN>");
|
||
if (msg == 7 && nicks->ip)
|
||
{
|
||
strcat(modebuf, space);
|
||
strcat(modebuf, nicks->ip);
|
||
}
|
||
if (((!not && wild_match(spec, modebuf)) || (not && !wild_match(spec, modebuf))) &&
|
||
(!ops ||
|
||
((ops == 1) && nick_isop(nicks)) ||
|
||
((ops == 2) && !nick_isop(nicks)) ))
|
||
{
|
||
switch(msg)
|
||
{
|
||
case 3: /* nokill */
|
||
count--;
|
||
break;
|
||
case 4: /* kill */
|
||
{
|
||
if (!isme(nicks->nick))
|
||
my_send_to_server(server, "KILL %s :%s (%i", nicks->nick,
|
||
args && *args ? args : get_kill_reason(nicks->nick,
|
||
get_server_nickname(from_server)), count + 1);
|
||
else
|
||
count--;
|
||
break;
|
||
}
|
||
case 5: /* mass kick */
|
||
{
|
||
if (!isme(nicks->nick))
|
||
{
|
||
if (*msgbuf)
|
||
strcat(msgbuf, ",");
|
||
strcat(msgbuf, nicks->nick);
|
||
num_kicks++;
|
||
} else
|
||
count--;
|
||
if ((get_int_var(NUM_KICKS_VAR) && (num_kicks == get_int_var(NUM_KICKS_VAR))) || strlen(msgbuf) >= 450)
|
||
{
|
||
my_send_to_server(server, "KICK %s %s :%s", chan->channel,
|
||
msgbuf, (args && *args) ? args :
|
||
"-=punt=-");
|
||
*msgbuf = 0;
|
||
num_kicks = 0;
|
||
}
|
||
break;
|
||
}
|
||
case 6:
|
||
{
|
||
if (!isme(nicks->nick))
|
||
{
|
||
if (do_hook(STAT_LIST, "%s %d %d %d %d", nicks->nick, nicks->dopcount, nicks->kickcount,
|
||
nicks->nickcount, nicks->floodcount))
|
||
put_it("%-10s %4d %4d %4d %4d",
|
||
nicks->nick, nicks->dopcount, nicks->kickcount,
|
||
nicks->nickcount, nicks->floodcount);
|
||
}
|
||
break;
|
||
}
|
||
case 7:
|
||
if (do_hook(USERS_IP_LIST, "%s %s %s", nicks->nick, nicks->host, nicks->ip?nicks->ip:"Unknown"))
|
||
put_it("%s!%s = %s", nicks->nick, nicks->host, nicks->ip?nicks->ip:"Unknown");
|
||
break;
|
||
case 1:
|
||
case 2:
|
||
{
|
||
if (*msgbuf)
|
||
strcat(msgbuf, ",");
|
||
strcat(msgbuf, nicks->nick);
|
||
if (strlen(msgbuf)+strlen(args) >= 490)
|
||
{
|
||
put_it("%s", convert_output_format(fget_string_var((msg == 1)?FORMAT_SEND_MSG_FSET:FORMAT_SEND_NOTICE_FSET), "%s %s %s %s", update_clock(GET_TIME),msgbuf, get_server_nickname(from_server), args));
|
||
my_send_to_server(server, "%s %s :%s", (msg == 1) ? "PRIVMSG" : "NOTICE", msgbuf, args);
|
||
*msgbuf = 0;
|
||
}
|
||
break;
|
||
}
|
||
default:
|
||
{
|
||
if (!count && do_hook(USERS_HEADER_LIST, "%s %s %s %s %s %s %s", "Level", "aop", "prot", "Channel", "Nick", "+o", "UserHost") && fget_string_var(FORMAT_USERS_HEADER_FSET))
|
||
put_it("%s", convert_output_format(fget_string_var(FORMAT_USERS_HEADER_FSET), "%s", chan->channel));
|
||
|
||
if ((hook = do_hook(USERS_LIST, "%lu %s %s %s %d %c",
|
||
nicks->userlist ? nicks->userlist->flags:nicks->shitlist?nicks->shitlist->level:0,
|
||
chan->channel, nicks->nick,
|
||
nicks->host, nicks->serverhops,
|
||
nick_isop(nicks) ? '@' : nick_isvoice(nicks) ? 'v' :' ')))
|
||
{
|
||
put_user(nicks, chan->channel);
|
||
}
|
||
}
|
||
}
|
||
count++;
|
||
}
|
||
else if (msg == 3)
|
||
{
|
||
count++;
|
||
if (!isme(nicks->nick))
|
||
{
|
||
my_send_to_server(server, "KILL %s :%s (%i", nicks->nick,
|
||
args && *args ? args : get_kill_reason(nicks->nick,
|
||
get_server_nickname(from_server)), count);
|
||
}
|
||
else
|
||
count--;
|
||
}
|
||
}
|
||
clear_sorted_nicklist(&sortl);
|
||
if (!msg && do_hook(USERS_FOOTER_LIST, "%s", "End of Users"))
|
||
;
|
||
else if (msg == 6 && do_hook(STAT_FOOTER_LIST, "%s", "End of stats"))
|
||
;
|
||
else if (!count)
|
||
{
|
||
if (chan)
|
||
{
|
||
if (!command)
|
||
say("No match of %s on %s", spec, chan->channel);
|
||
else
|
||
say("There are no [\002%s\002] on %s", command, chan->channel);
|
||
}
|
||
}
|
||
else if (!msg && !hook)
|
||
bitchsay("End of UserList on %s %d counted", chan->channel, count);
|
||
|
||
if (count && *msgbuf)
|
||
{
|
||
switch(msg)
|
||
{
|
||
case 1:
|
||
case 2:
|
||
{
|
||
put_it("%s", convert_output_format(fget_string_var((msg == 1)?FORMAT_SEND_MSG_FSET:FORMAT_SEND_NOTICE_FSET), "%s %s %s %s", update_clock(GET_TIME),msgbuf, get_server_nickname(from_server), args));
|
||
my_send_to_server(server, "%s %s :%s", (msg == 1) ? "PRIVMSG" : "NOTICE", msgbuf, args);
|
||
break;
|
||
}
|
||
case 5:
|
||
{
|
||
if (chan)
|
||
my_send_to_server(server, "KICK %s %s :%s", chan->channel,
|
||
msgbuf, (args && *args) ? args : "-=punt=-");
|
||
}
|
||
default:
|
||
break;
|
||
}
|
||
}
|
||
reset_display_target();
|
||
|
||
}
|
||
|
||
static char *make_timestamp(int do_timestamp, char *timestr)
|
||
{
|
||
static char time_str[61];
|
||
if (do_timestamp && timestr)
|
||
{
|
||
struct tm timeval;
|
||
*time_str = 0;
|
||
timeval = *localtime(&now);
|
||
strftime(time_str, 60, timestr, &timeval);
|
||
return time_str;
|
||
}
|
||
return empty_string;
|
||
}
|
||
|
||
#ifndef BITCHX_LITE
|
||
#define MAX_RECURSE 5
|
||
#else
|
||
#define MAX_RECURSE 3
|
||
#endif
|
||
#define RECURSE_CPARSE
|
||
|
||
char *convert_output_format_raw(const char *format, const char *str, va_list args)
|
||
{
|
||
#ifdef WANT_CHELP
|
||
extern int in_chelp;
|
||
#endif
|
||
static int cparse_recurse = -1;
|
||
/* One buffer for each recursive invocation. We also keep track of the
|
||
* buffer size, so that it can be resized when necessary.
|
||
*/
|
||
static char *cof_buffer[MAX_RECURSE + 1] = { NULL };
|
||
static size_t cof_buffer_sz[MAX_RECURSE + 1 ] = { 0 };
|
||
#define COF_BUFFER_HEADROOM 100
|
||
#define COF_BUFFER_FREE(p) (cof_buffer[cparse_recurse] + cof_buffer_sz[cparse_recurse] - (p))
|
||
static const char color_mod[] = "kbgcrmywKBGCRMYWn";
|
||
|
||
char buffer2[5 * BIG_BUFFER_SIZE + 1] = "";
|
||
enum color_attributes this_color = BLACK;
|
||
char *s;
|
||
char *copy = NULL;
|
||
char *tmpc = NULL;
|
||
const char *p;
|
||
int old_who_level = who_level;
|
||
int bold = 0;
|
||
int arg_flags;
|
||
int do_timestamp = get_int_var(TIMESTAMP_VAR);
|
||
char *timestamp_str = get_string_var(TIMESTAMP_STRING_VAR);
|
||
|
||
if (!format)
|
||
return empty_string;
|
||
copy = LOCAL_COPY(format);
|
||
|
||
if (cparse_recurse >= MAX_RECURSE)
|
||
{
|
||
yell("cparse_recurse() recursed too many times! this should never happen!");
|
||
return empty_string;
|
||
}
|
||
cparse_recurse++;
|
||
|
||
p = str;
|
||
while (p && *p)
|
||
{
|
||
if (*p == '%')
|
||
{
|
||
switch(*++p)
|
||
{
|
||
case 's':
|
||
{
|
||
char *q, *s = (char *)va_arg(args, char *);
|
||
#ifdef RECURSE_CPARSE
|
||
char buff[(5 * BIG_BUFFER_SIZE)+1];
|
||
q = buff;
|
||
while (s && *s)
|
||
{
|
||
if (*s == '%')
|
||
*q++ = '%';
|
||
else if (*s == '$')
|
||
*q++ = '$';
|
||
*q++ = *s++;
|
||
}
|
||
*q = 0;
|
||
if (*buff)
|
||
strcat(buffer2, buff);
|
||
#else
|
||
if (s)
|
||
strcat(buffer2, s);
|
||
#endif
|
||
break;
|
||
}
|
||
case 'd':
|
||
{
|
||
int d = (int) va_arg(args, int);
|
||
strlcat(buffer2, ltoa((long)d), 5 * BIG_BUFFER_SIZE);
|
||
break;
|
||
}
|
||
case 'c':
|
||
{
|
||
char c = (char )va_arg(args, int);
|
||
#ifdef RECURSE_CPARSE
|
||
if (c == '%')
|
||
buffer2[strlen(buffer2)] = '%';
|
||
else if (c == '$')
|
||
buffer2[strlen(buffer2)] = '$';
|
||
#endif
|
||
buffer2[strlen(buffer2)] = c;
|
||
break;
|
||
}
|
||
case 'u':
|
||
{
|
||
unsigned int d = (unsigned int) va_arg(args, unsigned int);
|
||
strlcat(buffer2, ltoa(d), 5 * BIG_BUFFER_SIZE);
|
||
break;
|
||
}
|
||
case 'l':
|
||
{
|
||
unsigned long d = (unsigned long) va_arg(args, unsigned long);
|
||
strlcat(buffer2, ltoa(d), 5 * BIG_BUFFER_SIZE);
|
||
break;
|
||
}
|
||
case '%':
|
||
{
|
||
buffer2[strlen(buffer2)] = '%';
|
||
p++;
|
||
break;
|
||
}
|
||
default:
|
||
strlcat(buffer2, "%", 5 * BIG_BUFFER_SIZE);
|
||
buffer2[strlen(buffer2)] = *p;
|
||
}
|
||
p++;
|
||
}
|
||
else
|
||
{
|
||
buffer2[strlen(buffer2)] = *p;
|
||
p++;
|
||
}
|
||
}
|
||
|
||
if (!cof_buffer[cparse_recurse])
|
||
{
|
||
cof_buffer_sz[cparse_recurse] = BIG_BUFFER_SIZE;
|
||
cof_buffer[cparse_recurse] = new_malloc(cof_buffer_sz[cparse_recurse]);
|
||
}
|
||
|
||
s = cof_buffer[cparse_recurse];
|
||
*s = 0;
|
||
|
||
tmpc = copy;
|
||
if (!tmpc)
|
||
goto done;
|
||
while (*tmpc)
|
||
{
|
||
/* Ensure some headroom is available in the buffer */
|
||
if (COF_BUFFER_FREE(s) < COF_BUFFER_HEADROOM)
|
||
{
|
||
size_t s_pos = s - cof_buffer[cparse_recurse];
|
||
|
||
cof_buffer_sz[cparse_recurse] += BIG_BUFFER_SIZE;
|
||
RESIZE(cof_buffer[cparse_recurse], char, cof_buffer_sz[cparse_recurse]);
|
||
|
||
s = cof_buffer[cparse_recurse] + s_pos;
|
||
}
|
||
|
||
if (*tmpc == '%')
|
||
{
|
||
char *cs;
|
||
tmpc++;
|
||
this_color = BLACK;
|
||
if (*tmpc == '\0')
|
||
{
|
||
*s++ = '%';
|
||
continue;
|
||
}
|
||
if (*tmpc == '%')
|
||
{
|
||
*s++ = *tmpc++;
|
||
continue;
|
||
}
|
||
if (isdigit((unsigned char)*tmpc))
|
||
{
|
||
char background_mod[] = "01234567";
|
||
char *blah = background_mod;
|
||
if ((cs = strchr(background_mod, *tmpc)))
|
||
{
|
||
this_color = (cs - blah) + (bold ? BACK_BBLACK : BACK_BLACK);
|
||
bold = 0;
|
||
}
|
||
else if (*tmpc == '8')
|
||
{
|
||
this_color = REVERSE_COLOR;
|
||
bold = 0;
|
||
}
|
||
else
|
||
{
|
||
this_color = BOLD_COLOR;
|
||
bold ^= 1;
|
||
}
|
||
}
|
||
else if ((cs = strchr(color_mod, *tmpc)))
|
||
this_color = (cs - color_mod);
|
||
else if (*tmpc == 'F')
|
||
this_color = BLINK_COLOR;
|
||
else if (*tmpc == 'U')
|
||
this_color = UNDERLINE_COLOR;
|
||
else if (*tmpc == 'A')
|
||
this_color = (int) (((float)UNDERLINE_COLOR * rand())/RAND_MAX);
|
||
else if (*tmpc == 'P')
|
||
this_color = MAGENTAB;
|
||
else if (*tmpc == 'p')
|
||
this_color = MAGENTA;
|
||
else if (*tmpc == '@')
|
||
{
|
||
strlcpy(s, make_timestamp(do_timestamp, timestamp_str), COF_BUFFER_FREE(s));
|
||
while(*s) s++;
|
||
tmpc++;
|
||
continue;
|
||
}
|
||
#if 1
|
||
/* do we really wanna do this? */
|
||
else if (*tmpc == '^') /* ibmpc charset */
|
||
{
|
||
strlcpy(s, "\033(U", COF_BUFFER_FREE(s));
|
||
while(*s) s++;
|
||
tmpc++;
|
||
continue;
|
||
}
|
||
else if (*tmpc == '&') /* latin1 charset */
|
||
{
|
||
strlcpy(s, "\033(B", COF_BUFFER_FREE(s));
|
||
while(*s) s++;
|
||
tmpc++;
|
||
continue;
|
||
}
|
||
else if (*tmpc == '$') /* custom charset */
|
||
{
|
||
strlcpy(s, "\033(K", COF_BUFFER_FREE(s));
|
||
while(*s) s++;
|
||
tmpc++;
|
||
continue;
|
||
}
|
||
#endif
|
||
else
|
||
{
|
||
*s++ = *tmpc;
|
||
continue;
|
||
}
|
||
strlcpy(s, color_str[this_color], COF_BUFFER_FREE(s));
|
||
while (*s) s++;
|
||
tmpc++;
|
||
continue;
|
||
}
|
||
else if (*tmpc == '$' && !in_chelp && cparse_recurse < MAX_RECURSE)
|
||
{
|
||
char *new_str = NULL;
|
||
tmpc++;
|
||
if (*tmpc == '\0')
|
||
{
|
||
*s++ = '$';
|
||
continue;
|
||
}
|
||
if (*tmpc == '$')
|
||
{
|
||
*s++ = *tmpc++;
|
||
continue;
|
||
}
|
||
|
||
in_cparse++;
|
||
tmpc = alias_special_char(&new_str, tmpc, buffer2, NULL, &arg_flags);
|
||
in_cparse--;
|
||
|
||
if (new_str)
|
||
{
|
||
char *subformat;
|
||
#ifdef RECURSE_CPARSE
|
||
subformat = convert_output_format_raw((const char *)new_str, NULL, VA_NULL);
|
||
#else
|
||
subformat = new_str;
|
||
#endif
|
||
/* Ensure sufficient buffer space */
|
||
if (COF_BUFFER_FREE(s) < strlen(subformat) + 1)
|
||
{
|
||
size_t s_pos = s - cof_buffer[cparse_recurse];
|
||
|
||
cof_buffer_sz[cparse_recurse] += BIG_BUFFER_SIZE + strlen(subformat);
|
||
RESIZE(cof_buffer[cparse_recurse], char, cof_buffer_sz[cparse_recurse]);
|
||
|
||
s = cof_buffer[cparse_recurse] + s_pos;
|
||
}
|
||
|
||
strlcpy(s, subformat, COF_BUFFER_FREE(s));
|
||
new_free(&new_str);
|
||
while (*s) { s++; }
|
||
}
|
||
if (!tmpc) break;
|
||
continue;
|
||
} else
|
||
*s = *tmpc;
|
||
tmpc++; s++;
|
||
}
|
||
*s = 0;
|
||
|
||
done:
|
||
s = cof_buffer[cparse_recurse];
|
||
who_level = old_who_level;
|
||
cparse_recurse--;
|
||
|
||
return s;
|
||
}
|
||
|
||
char *BX_convert_output_format(const char *format, const char *str, ...)
|
||
{
|
||
char *s;
|
||
int old_alias_debug = alias_debug;
|
||
va_list args;
|
||
|
||
alias_debug = 0;
|
||
va_start(args, str);
|
||
s = convert_output_format_raw(format, str, args);
|
||
va_end(args);
|
||
if (*s)
|
||
strcat(s, color_str[NO_COLOR]);
|
||
alias_debug = old_alias_debug;
|
||
return s;
|
||
}
|
||
|
||
#ifdef GUI
|
||
/* This cut-down version of convert_output_format is used by the GUI menu functions. */
|
||
#define RAW_BUFFER_SIZE (MAX_RECURSE * BIG_BUFFER_SIZE * 2)
|
||
char *convert_output_format2(const char *str)
|
||
{
|
||
char buffer[RAW_BUFFER_SIZE+1];
|
||
char buffer2[RAW_BUFFER_SIZE+1];
|
||
char *s;
|
||
char *copy = NULL;
|
||
char *tmpc = NULL;
|
||
int arg_flags;
|
||
|
||
if (!str)
|
||
return m_strdup(empty_string);
|
||
|
||
memset(buffer, 0, BIG_BUFFER_SIZE);
|
||
strlcpy(buffer2, str, RAW_BUFFER_SIZE);
|
||
copy = tmpc = buffer2;
|
||
s = buffer;
|
||
while (*tmpc)
|
||
{
|
||
if (*tmpc == '$')
|
||
{
|
||
char *new_str = NULL;
|
||
tmpc++;
|
||
in_cparse++;
|
||
tmpc = alias_special_char(&new_str, tmpc, copy, NULL, &arg_flags);
|
||
in_cparse--;
|
||
if (new_str)
|
||
#ifdef RECURSE_CPARSE
|
||
strlcat(s, convert_output_format(new_str, NULL, NULL), RAW_BUFFER_SIZE);
|
||
#else
|
||
strlcat(s, new_str, RAW_BUFFER_SIZE);
|
||
#endif
|
||
s += strlen(new_str);
|
||
new_free(&new_str);
|
||
if (!tmpc) break;
|
||
continue;
|
||
} else
|
||
*s = *tmpc;
|
||
tmpc++; s++;
|
||
}
|
||
*s = 0;
|
||
return m_strdup(buffer);
|
||
}
|
||
#endif /* GUI */
|
||
|
||
void add_last_type(LastMsg *array, int size, const char *from, const char *uh, const char *to, const char *msg)
|
||
{
|
||
int i = size - 1;
|
||
LastMsg new_msg = array[i]; /* Re-use allocations from last entry */
|
||
|
||
malloc_strcpy(&new_msg.last_msg, msg);
|
||
malloc_strcpy(&new_msg.from, from);
|
||
malloc_strcpy(&new_msg.to, to);
|
||
malloc_strcpy(&new_msg.uh, uh);
|
||
malloc_strcpy(&new_msg.time, update_clock(GET_TIME));
|
||
|
||
for (; i > 0; i--)
|
||
{
|
||
array[i].last_msg = array[i - 1].last_msg;
|
||
array[i].from = array[i - 1].from;
|
||
array[i].uh = array[i - 1].uh;
|
||
array[i].to = array[i - 1].to;
|
||
array[i].time = array[i - 1].time;
|
||
}
|
||
|
||
array[0].last_msg = new_msg.last_msg;
|
||
array[0].from = new_msg.from;
|
||
array[0].uh = new_msg.uh;
|
||
array[0].to = new_msg.to;
|
||
array[0].time = new_msg.time;
|
||
}
|
||
|
||
int check_last_type(LastMsg *array, int size, char *from, char *uh)
|
||
{
|
||
int i;
|
||
for (i = 0; i < size-1; i++)
|
||
{
|
||
if (array[i].from && array[i].uh && !my_stricmp(from, array[i].from) && !my_stricmp(uh, array[i].uh))
|
||
return 1;
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
int matchmcommand(char *origline,int count)
|
||
{
|
||
int startnum=0;
|
||
int endnum=0;
|
||
char *tmpstr;
|
||
char tmpbuf[IRCD_BUFFER_SIZE];
|
||
|
||
strncpy(tmpbuf,origline, IRCD_BUFFER_SIZE-1);
|
||
tmpstr=tmpbuf;
|
||
if (*tmpstr=='*') return(1);
|
||
while (tmpstr && *tmpstr)
|
||
{
|
||
startnum=0;
|
||
endnum=0;
|
||
if (tmpstr && *tmpstr && *tmpstr=='-')
|
||
{
|
||
while (tmpstr && *tmpstr && !isdigit((unsigned char)*tmpstr))
|
||
tmpstr++;
|
||
endnum=atoi(tmpstr);
|
||
startnum=1;
|
||
while (tmpstr && *tmpstr && isdigit((unsigned char)*tmpstr))
|
||
tmpstr++;
|
||
}
|
||
else
|
||
{
|
||
while (tmpstr && *tmpstr && !isdigit((unsigned char)*tmpstr))
|
||
tmpstr++;
|
||
startnum=atoi(tmpstr);
|
||
while (tmpstr && *tmpstr && isdigit((unsigned char)*tmpstr))
|
||
tmpstr++;
|
||
if (tmpstr && *tmpstr && *tmpstr=='-') {
|
||
while (tmpstr && *tmpstr && !isdigit((unsigned char)*tmpstr))
|
||
tmpstr++;
|
||
endnum=atoi(tmpstr);
|
||
if (!endnum)
|
||
endnum=1000;
|
||
while (tmpstr && *tmpstr && isdigit((unsigned char)*tmpstr))
|
||
tmpstr++;
|
||
}
|
||
}
|
||
if (count==startnum || (count>=startnum && count<=endnum))
|
||
return(1);
|
||
}
|
||
if (count==startnum || (count>=startnum && count<=endnum))
|
||
return(1);
|
||
return(0);
|
||
}
|
||
|
||
ChannelList *BX_prepare_command(int *active_server, char *channel, int flags)
|
||
{
|
||
int server = 0;
|
||
ChannelList *chan = NULL;
|
||
int need_op;
|
||
|
||
if (!channel) {
|
||
channel = get_current_channel_by_refnum(0);
|
||
|
||
if (!channel) {
|
||
if (flags != PC_SILENT) {
|
||
message_to(current_window->refnum);
|
||
bitchsay("You're not on a channel!");
|
||
message_to(0);
|
||
}
|
||
return NULL;
|
||
}
|
||
}
|
||
server = current_window->server;
|
||
*active_server = server;
|
||
if (!(chan = lookup_channel(channel, server, 0)))
|
||
{
|
||
if (flags != PC_SILENT) {
|
||
message_to(current_window->refnum);
|
||
bitchsay("You're not on the channel: %s", channel);
|
||
message_to(0);
|
||
}
|
||
return NULL;
|
||
}
|
||
|
||
need_op = flags == NEED_OP || (flags == PC_TOPIC && (chan->mode & MODE_TOPIC));
|
||
if (need_op && !chan->have_op && !chan->hop)
|
||
{
|
||
error_not_opped(chan->channel);
|
||
return NULL;
|
||
}
|
||
return chan;
|
||
}
|
||
|
||
char *BX_make_channel (char *chan)
|
||
{
|
||
static char buffer[IRCD_BUFFER_SIZE+1];
|
||
*buffer = 0;
|
||
if (!chan)
|
||
return NULL;
|
||
if (*chan != '#' && *chan != '&' && *chan != '+' && *chan != '!')
|
||
snprintf(buffer, IRCD_BUFFER_SIZE-2, "#%s", chan);
|
||
else
|
||
strlcpy(buffer, chan, sizeof buffer);
|
||
return buffer;
|
||
}
|
||
|
||
|
||
extern int timed_server (void *, char *);
|
||
void check_server_connect(int server)
|
||
{
|
||
#ifndef NON_BLOCKING_CONNECTS
|
||
if (!get_int_var(AUTO_RECONNECT_VAR))
|
||
return;
|
||
if (server == -2)
|
||
return;
|
||
if ((server == -1) || (!get_server_in_timed(server) && get_server_lastmsg(server) + 50 < now))
|
||
{
|
||
if (!timer_callback_exists(timed_server))
|
||
{
|
||
add_timer(0, empty_string, 10 * 1000, 1, timed_server, m_strdup(ltoa(server)), NULL, current_window->refnum, "reconnect");
|
||
set_server_in_timed(server, get_server_in_timed(server)+1);
|
||
}
|
||
}
|
||
#endif
|
||
}
|
||
|
||
const char *country(const char *hostname)
|
||
{
|
||
#ifndef BITCHX_LITE
|
||
static const struct {
|
||
const char *code;
|
||
const char *country;
|
||
} domain[] = {
|
||
{"AC", "Ascension Island" },
|
||
{"AD", "Andorra" },
|
||
{"AE", "United Arab Emirates" },
|
||
{"AF", "Afghanistan" },
|
||
{"AG", "Antigua and Barbuda" },
|
||
{"AI", "Anguilla" },
|
||
{"AL", "Albania" },
|
||
{"AM", "Armenia" },
|
||
{"AN", "Netherlands Antilles" },
|
||
{"AO", "Angola" },
|
||
{"AQ", "Antarctica (BURRR!)" },
|
||
{"AR", "Argentina" },
|
||
{"AS", "American Samoa" },
|
||
{"AT", "Austria" },
|
||
{"AU", "Australia" },
|
||
{"AW", "Aruba" },
|
||
{"AX", "Aland" },
|
||
{"AZ", "Azerbaijan" },
|
||
{"BA", "Bosnia and Herzegovina" },
|
||
{"BB", "Barbados" },
|
||
{"BD", "Bangladesh" },
|
||
{"BE", "Belgium" },
|
||
{"BF", "Burkina Faso" },
|
||
{"BG", "Bulgaria" },
|
||
{"BH", "Bahrain" },
|
||
{"BI", "Burundi" },
|
||
{"BJ", "Benin" },
|
||
{"BM", "Bermuda" },
|
||
{"BN", "Brunei Darussalam" },
|
||
{"BO", "Bolivia" },
|
||
{"BR", "Brazil" },
|
||
{"BS", "Bahamas" },
|
||
{"BT", "Bhutan" },
|
||
{"BV", "Bouvet Island" },
|
||
{"BW", "Botswana" },
|
||
{"BY", "Belarus" },
|
||
{"BZ", "Belize" },
|
||
{"CA", "Canada (pHEAR)" },
|
||
{"CC", "Cocos (Keeling) Islands" },
|
||
{"CD", "Congo-Kinshasa" },
|
||
{"CF", "Central African Republic" },
|
||
{"CG", "Congo-Brazzaville" },
|
||
{"CH", "Switzerland" },
|
||
{"CI", "Cote D'Ivoire" },
|
||
{"CK", "Cook Islands" },
|
||
{"CL", "Chile" },
|
||
{"CM", "Cameroon" },
|
||
{"CN", "China" },
|
||
{"CO", "Colombia" },
|
||
{"CR", "Costa Rica" },
|
||
{"CU", "Cuba" },
|
||
{"CV", "Cape Verde" },
|
||
{"CW", "Curacao" },
|
||
{"CX", "Christmas Island" },
|
||
{"CY", "Cyprus" },
|
||
{"CZ", "Czech Republic" },
|
||
{"DE", "Germany" },
|
||
{"DJ", "Djibouti" },
|
||
{"DK", "Denmark" },
|
||
{"DM", "Dominica" },
|
||
{"DO", "Dominican Republic" },
|
||
{"DZ", "Algeria" },
|
||
{"EC", "Ecuador" },
|
||
{"EE", "Estonia" },
|
||
{"EG", "Egypt" },
|
||
{"EH", "Western Sahara" },
|
||
{"ER", "Eritrea" },
|
||
{"ES", "Spain" },
|
||
{"ET", "Ethiopia" },
|
||
{"EU", "European Union" },
|
||
{"FI", "Finland" },
|
||
{"FJ", "Fiji" },
|
||
{"FK", "Falkland Islands" },
|
||
{"FM", "Micronesia" },
|
||
{"FO", "Faroe Islands" },
|
||
{"FR", "France" },
|
||
{"GA", "Gabon" },
|
||
{"GB", "Great Britain" },
|
||
{"GD", "Grenada" },
|
||
{"GE", "Georgia" },
|
||
{"GF", "French Guiana" },
|
||
{"GG", "Guernsey" },
|
||
{"GH", "Ghana" },
|
||
{"GI", "Gibraltar" },
|
||
{"GL", "Greenland" },
|
||
{"GM", "Gambia" },
|
||
{"GN", "Guinea" },
|
||
{"GP", "Guadeloupe" },
|
||
{"GQ", "Equatorial Guinea" },
|
||
{"GR", "Greece" },
|
||
{"GS", "S. Georgia and S. Sandwich Isles" },
|
||
{"GT", "Guatemala" },
|
||
{"GU", "Guam" },
|
||
{"GW", "Guinea-Bissau" },
|
||
{"GY", "Guyana" },
|
||
{"HK", "Hong Kong" },
|
||
{"HM", "Heard and McDonald Islands" },
|
||
{"HN", "Honduras" },
|
||
{"HR", "Croatia" },
|
||
{"HT", "Haiti" },
|
||
{"HU", "Hungary" },
|
||
{"ID", "Indonesia" },
|
||
{"IE", "Ireland" },
|
||
{"IL", "Israel" },
|
||
{"IM", "Isle of Man" },
|
||
{"IN", "India" },
|
||
{"IO", "British Indian Ocean Territory" },
|
||
{"IQ", "Iraq" },
|
||
{"IR", "Iran" },
|
||
{"IS", "Iceland" },
|
||
{"IT", "Italy" },
|
||
{"JE", "Jersey" },
|
||
{"JM", "Jamaica" },
|
||
{"JO", "Jordan" },
|
||
{"JP", "Japan" },
|
||
{"KE", "Kenya" },
|
||
{"KG", "Kyrgyzstan" },
|
||
{"KH", "Cambodia" },
|
||
{"KI", "Kiribati" },
|
||
{"KM", "Comoros" },
|
||
{"KN", "St. Kitts and Nevis" },
|
||
{"KP", "North Korea" },
|
||
{"KR", "South Korea" },
|
||
{"KW", "Kuwait" },
|
||
{"KY", "Cayman Islands" },
|
||
{"KZ", "Kazakstan" },
|
||
{"LA", "Laos" },
|
||
{"LB", "Lebanon" },
|
||
{"LC", "St. Lucia" },
|
||
{"LI", "Liechtenstein" },
|
||
{"LK", "Sri Lanka" },
|
||
{"LR", "Liberia" },
|
||
{"LS", "Lesotho" },
|
||
{"LT", "Lithuania" },
|
||
{"LU", "Luxembourg" },
|
||
{"LV", "Latvia" },
|
||
{"LY", "Libya" },
|
||
{"MA", "Morocco" },
|
||
{"MC", "Monaco" },
|
||
{"MD", "Moldova" },
|
||
{"ME", "Montenegro" },
|
||
{"MG", "Madagascar" },
|
||
{"MH", "Marshall Islands" },
|
||
{"MK", "Macedonia" },
|
||
{"ML", "Mali" },
|
||
{"MM", "Myanmar" },
|
||
{"MN", "Mongolia" },
|
||
{"MO", "Macau" },
|
||
{"MP", "Northern Mariana Islands" },
|
||
{"MQ", "Martinique" },
|
||
{"MR", "Mauritania" },
|
||
{"MS", "Montserrat" },
|
||
{"MT", "Malta" },
|
||
{"MU", "Mauritius" },
|
||
{"MV", "Maldives" },
|
||
{"MW", "Malawi" },
|
||
{"MX", "Mexico" },
|
||
{"MY", "Malaysia" },
|
||
{"MZ", "Mozambique" },
|
||
{"NA", "Namibia" },
|
||
{"NC", "New Caledonia" },
|
||
{"NE", "Niger" },
|
||
{"NF", "Norfolk Island" },
|
||
{"NG", "Nigeria" },
|
||
{"NI", "Nicaragua" },
|
||
{"NL", "Netherlands" },
|
||
{"NO", "Norway" },
|
||
{"NP", "Nepal" },
|
||
{"NR", "Nauru" },
|
||
{"NU", "Niue" },
|
||
{"NZ", "New Zealand" },
|
||
{"OM", "Oman" },
|
||
{"PA", "Panama" },
|
||
{"PE", "Peru" },
|
||
{"PF", "French Polynesia" },
|
||
{"PG", "Papua New Guinea" },
|
||
{"PH", "Philippines" },
|
||
{"PK", "Pakistan" },
|
||
{"PL", "Poland" },
|
||
{"PM", "St. Pierre and Miquelon" },
|
||
{"PN", "Pitcairn Island" },
|
||
{"PR", "Puerto Rico" },
|
||
{"PS", "Palestinian Territories" },
|
||
{"PT", "Portugal" },
|
||
{"PW", "Palau" },
|
||
{"PY", "Paraguay" },
|
||
{"QA", "Qatar" },
|
||
{"RE", "Reunion Island" },
|
||
{"RO", "Romania" },
|
||
{"RS", "Serbia" },
|
||
{"RU", "Russian Federation (pHEAR)" },
|
||
{"RW", "Rwanda" },
|
||
{"SA", "Saudi Arabia" },
|
||
{"SB", "Solomon Islands" },
|
||
{"SC", "Seychelles" },
|
||
{"SD", "Sudan" },
|
||
{"SE", "Sweden" },
|
||
{"SG", "Singapore" },
|
||
{"SH", "St. Helena" },
|
||
{"SI", "Slovenia" },
|
||
{"SJ", "Svalbard and Jan Mayen Islands" },
|
||
{"SK", "Slovakia" },
|
||
{"SL", "Sierra Leone" },
|
||
{"SM", "San Marino" },
|
||
{"SN", "Senegal" },
|
||
{"SO", "Somalia" },
|
||
{"SR", "Suriname" },
|
||
{"ST", "Sao Tome and Principe" },
|
||
{"SU", "Former USSR (pHEAR)" },
|
||
{"SV", "El Salvador" },
|
||
{"SX", "Sint Maarten" },
|
||
{"SY", "Syria" },
|
||
{"SZ", "Swaziland" },
|
||
{"TC", "Turks and Caicos Islands" },
|
||
{"TD", "Chad" },
|
||
{"TF", "French Southern Territories" },
|
||
{"TG", "Togo" },
|
||
{"TH", "Thailand" },
|
||
{"TJ", "Tajikistan" },
|
||
{"TK", "Tokelau" },
|
||
{"TL", "East Timor" },
|
||
{"TM", "Turkmenistan" },
|
||
{"TN", "Tunisia" },
|
||
{"TO", "Tonga" },
|
||
{"TP", "East Timor" },
|
||
{"TR", "Turkey" },
|
||
{"TT", "Trinidad and Tobago" },
|
||
{"TV", "Tuvalu" },
|
||
{"TW", "Taiwan" },
|
||
{"TZ", "Tanzania" },
|
||
{"UA", "Ukraine" },
|
||
{"UG", "Uganda" },
|
||
{"UK", "United Kingdom" },
|
||
{"UM", "US Minor Outlying Islands" },
|
||
{"US", "United States of America" },
|
||
{"UY", "Uruguay" },
|
||
{"UZ", "Uzbekistan" },
|
||
{"VA", "Vatican City" },
|
||
{"VC", "St. Vincent and the Grenadines" },
|
||
{"VE", "Venezuela" },
|
||
{"VG", "British Virgin Islands" },
|
||
{"VI", "US Virgin Islands" },
|
||
{"VN", "Vietnam" },
|
||
{"VU", "Vanuatu" },
|
||
{"WF", "Wallis and Futuna Islands" },
|
||
{"WS", "Western Samoa" },
|
||
{"YE", "Yemen" },
|
||
{"YT", "Mayotte" },
|
||
{"YU", "Yugoslavia" },
|
||
{"ZA", "South Africa" },
|
||
{"ZM", "Zambia" },
|
||
{"ZR", "Zaire" },
|
||
{"ZW", "Zimbabwe" },
|
||
{"AERO", "Air Transport Industry" },
|
||
{"ARPA", "Reverse DNS" },
|
||
{"ASIA", "Asia-Pacific" },
|
||
{"BIZ", "Business" },
|
||
{"CAT", "Catalan Language" },
|
||
{"COOP", "Cooperative Association" },
|
||
{"COM", "Commercial" },
|
||
{"EDU", "Educational Institution" },
|
||
{"GOV", "United States Government" },
|
||
{"INFO", "Informational" },
|
||
{"INT", "International" },
|
||
{"JOBS", "Employment Advertisements" },
|
||
{"MIL", "United States Military" },
|
||
{"MOBI", "Mobile Device" },
|
||
{"MUSEUM", "Museum" },
|
||
{"NET", "Network" },
|
||
{"NAME", "Individuals" },
|
||
{"ORG", "Organization" },
|
||
{"PRO", "Professional" },
|
||
{"TEL", "Contact Information" },
|
||
{"TRAVEL", "Travel Industry" },
|
||
{"XXX", "Porn" },
|
||
{NULL, NULL}
|
||
};
|
||
const char *p;
|
||
int i = 0;
|
||
|
||
if (!hostname || !*hostname || isdigit((unsigned char)hostname[strlen(hostname)-1]))
|
||
return "unknown";
|
||
if ((p = strrchr(hostname, '.')))
|
||
p++;
|
||
else
|
||
p = hostname;
|
||
for (i = 0; domain[i].code; i++)
|
||
if (!my_stricmp(p, domain[i].code))
|
||
return domain[i].country;
|
||
#endif
|
||
return "unknown";
|
||
}
|
||
|