2012 lines
54 KiB
C
2012 lines
54 KiB
C
/*
|
|
* parse.c: handles messages from the server. Believe it or not. I
|
|
* certainly wouldn't if I were you.
|
|
*
|
|
* Written By Michael Sandrof
|
|
*
|
|
* Copyright(c) 1990
|
|
* Modified Colten Edwards 1997
|
|
*/
|
|
|
|
#include "irc.h"
|
|
static char cvsrevision[] = "$Id$";
|
|
CVS_REVISION(parse_c)
|
|
#include "struct.h"
|
|
|
|
#include "alias.h"
|
|
#include "server.h"
|
|
#include "names.h"
|
|
#include "vars.h"
|
|
#include "cdcc.h"
|
|
#include "ctcp.h"
|
|
#include "hook.h"
|
|
#include "log.h"
|
|
#include "commands.h"
|
|
#include "ignore.h"
|
|
#include "who.h"
|
|
#include "lastlog.h"
|
|
#include "input.h"
|
|
#include "ircaux.h"
|
|
#include "funny.h"
|
|
#include "input.h"
|
|
#include "flood.h"
|
|
#include "window.h"
|
|
#include "screen.h"
|
|
#include "output.h"
|
|
#include "numbers.h"
|
|
#include "parse.h"
|
|
#include "notify.h"
|
|
#include "status.h"
|
|
#include "list.h"
|
|
#include "userlist.h"
|
|
#include "misc.h"
|
|
#include "whowas.h"
|
|
#include "timer.h"
|
|
#include "keys.h"
|
|
#include "hash2.h"
|
|
#include "cset.h"
|
|
#include "module.h"
|
|
#include "hash2.h"
|
|
#include "gui.h"
|
|
#include "tcl_bx.h"
|
|
#define MAIN_SOURCE
|
|
#include "modval.h"
|
|
|
|
|
|
#define STRING_CHANNEL '+'
|
|
#define MULTI_CHANNEL '#'
|
|
#define LOCAL_CHANNEL '&'
|
|
#define ID_CHANNEL '!'
|
|
|
|
static void strip_modes (char *, char *, char *);
|
|
|
|
char *last_split_server = NULL;
|
|
char *last_split_from = NULL;
|
|
|
|
/*
|
|
* joined_nick: the nickname of the last person who joined the current
|
|
* channel
|
|
*/
|
|
char *joined_nick = NULL;
|
|
|
|
/* public_nick: nick of the last person to send a message to your channel */
|
|
char *public_nick = NULL;
|
|
|
|
/* User and host information from server 2.7 */
|
|
char *FromUserHost = empty_string;
|
|
|
|
/* doing a PRIVMSG */
|
|
int doing_privmsg = 0;
|
|
|
|
|
|
#define do_output(x) put_it("%s%s%s", get_int_var(TIMESTAMP_VAR) ? update_clock(GET_TIME):empty_string, get_int_var(TIMESTAMP_VAR) ? space: empty_string, x)
|
|
|
|
/* returns ban if the ban is on the channel already, NULL if not */
|
|
BanList *ban_is_on_channel(register char *ban, register ChannelList *chan)
|
|
{
|
|
register BanList *bans = NULL;
|
|
#if 0
|
|
register BanList *eban = NULL;
|
|
#endif
|
|
for (bans = chan->bans; bans; bans = bans->next)
|
|
{
|
|
if (wild_match(bans->ban, ban) || wild_match(ban, bans->ban))
|
|
break;
|
|
else if (!my_stricmp(bans->ban, ban))
|
|
break;
|
|
}
|
|
return bans;
|
|
#if 0
|
|
for (eban = chan->exemptbans; eban; eban = eban->next)
|
|
{
|
|
if (wild_match(eban->ban, ban) || wild_match(ban, eban->ban))
|
|
break;
|
|
else if (!my_stricmp(eban->ban, ban))
|
|
break;
|
|
}
|
|
return eban ? NULL : bans;
|
|
#endif
|
|
}
|
|
|
|
BanList *eban_is_on_channel(register char *ban, register ChannelList *chan)
|
|
{
|
|
register BanList *eban = NULL;
|
|
|
|
for (eban = chan->exemptbans; eban; eban = eban->next)
|
|
{
|
|
if (wild_match(eban->ban, ban) || wild_match(ban, eban->ban))
|
|
break;
|
|
else if (!my_stricmp(eban->ban, ban))
|
|
break;
|
|
}
|
|
return eban ? eban : NULL;
|
|
}
|
|
|
|
|
|
void fake (void)
|
|
{
|
|
bitchsay("--- Fake Message received!!! ---");
|
|
return;
|
|
}
|
|
|
|
int check_auto_reply(char *str)
|
|
{
|
|
char *p = NULL;
|
|
char *pat;
|
|
|
|
if (!str || !*str || !get_int_var(AUTO_RESPONSE_VAR) || !auto_str)
|
|
return 0;
|
|
|
|
p = LOCAL_COPY(auto_str);
|
|
while ((pat = next_arg(p, &p)))
|
|
{
|
|
switch(get_int_var(NICK_COMPLETION_TYPE_VAR))
|
|
{
|
|
case 3:
|
|
if (!my_stricmp(str, pat))
|
|
goto found_auto;
|
|
continue;
|
|
case 2:
|
|
if (wild_match(pat, str))
|
|
goto found_auto;
|
|
continue;
|
|
case 1:
|
|
if (stristr(str, pat))
|
|
goto found_auto;
|
|
continue;
|
|
default:
|
|
case 0:
|
|
if (!my_strnicmp(str, pat, strlen(pat)))
|
|
goto found_auto;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
found_auto:
|
|
#ifdef GUI
|
|
gui_activity(COLOR_HIGHLIGHT);
|
|
#endif
|
|
return 1;
|
|
}
|
|
|
|
/* Check for more than 75% ALLCAPS */
|
|
static int annoy_caps(const char *crap)
|
|
{
|
|
int total = 0, allcaps = 0;
|
|
/* removed from ComStud client */
|
|
while (*crap)
|
|
{
|
|
if (isalpha((unsigned char)*crap))
|
|
{
|
|
total++;
|
|
if (isupper((unsigned char)*crap))
|
|
allcaps++;
|
|
}
|
|
crap++;
|
|
}
|
|
return total > 12 && (double)allcaps / total >= 0.75;
|
|
}
|
|
|
|
/* Check for more than 75% of printable chars highlighted */
|
|
static int annoy_hl(const char *crap, char hl_tog)
|
|
{
|
|
int total = 0, all_hl = 0, in_highlight = 0;
|
|
|
|
while (*crap)
|
|
{
|
|
if (*crap == hl_tog)
|
|
in_highlight = !in_highlight;
|
|
|
|
if (isgraph((unsigned char)*crap))
|
|
{
|
|
total++;
|
|
if (in_highlight)
|
|
all_hl++;
|
|
}
|
|
|
|
crap++;
|
|
}
|
|
return total > 12 && (double)all_hl / total >= 0.75;
|
|
}
|
|
|
|
int annoy_kicks(int list_type, char *to, char *from, char *ptr, NickList *nick)
|
|
{
|
|
int kick_em = 0;
|
|
ChannelList *chan;
|
|
|
|
if (nick && (nick->userlist && nick->userlist->flags))
|
|
return 0;
|
|
if (!check_channel_match(get_string_var(PROTECT_CHANNELS_VAR), to) || !are_you_opped(to))
|
|
return 0;
|
|
if (!(chan = lookup_channel(to, from_server, CHAN_NOUNLINK)))
|
|
return 0;
|
|
if (get_cset_int_var(chan->csets, ANNOY_KICK_CSET) && !nick_isop(nick))
|
|
{
|
|
char *buffer = NULL;
|
|
if (annoy_hl(ptr, BOLD_TOG))
|
|
malloc_sprintf(&buffer, "KICK %s %s :%s", to, from, "autokick for " BOLD_TOG_STR "bold" BOLD_TOG_STR);
|
|
else if (strchr(ptr, BELL_CHAR))
|
|
malloc_sprintf(&buffer, "KICK %s %s :%s", to, from, "autokick for beeping");
|
|
else if (annoy_hl(ptr, COLOR_CHAR))
|
|
malloc_sprintf(&buffer, "KICK %s %s :%s", to, from, "autokick for " UND_TOG_STR "mirc color" UND_TOG_STR);
|
|
else if (annoy_hl(ptr, UND_TOG))
|
|
malloc_sprintf(&buffer, "KICK %s %s :%s", to, from, "autokick for " UND_TOG_STR "underline" UND_TOG_STR);
|
|
else if (annoy_hl(ptr, REV_TOG))
|
|
malloc_sprintf(&buffer, "KICK %s %s :%s", to, from, "autokick for " REV_TOG_STR "inverse" REV_TOG_STR);
|
|
else if (annoy_hl(ptr, BLINK_TOG))
|
|
malloc_sprintf(&buffer, "KICK %s %s :%s", to, from, "autokick for " BLINK_TOG_STR "flashing" BLINK_TOG_STR);
|
|
else if (annoy_caps(ptr))
|
|
malloc_sprintf(&buffer, "KICK %s %s :%s", to, from, "autokick for CAPS LOCK");
|
|
else if (strstr(ptr, "0000027fed"))
|
|
{
|
|
char *host = NULL, *p;
|
|
malloc_strcpy(&host, FromUserHost);
|
|
p = strchr(host, '@'); *p++ = '\0';
|
|
send_to_server("MODE %s -o+b %s *!*%s", to, from, cluster(FromUserHost));
|
|
send_to_server("KICK %s %s :%s", to, from, "\002Zmodem rocks\002");
|
|
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, to, cluster(FromUserHost)), NULL, current_window->refnum, "auto-unban");
|
|
new_free(&host);
|
|
kick_em = 1;
|
|
}
|
|
if (buffer)
|
|
{
|
|
kick_em = 1;
|
|
send_to_server("%s", buffer);
|
|
new_free(&buffer);
|
|
}
|
|
}
|
|
|
|
if (ban_words)
|
|
{
|
|
WordKickList *word;
|
|
int ops = get_cset_int_var(chan->csets, KICK_OPS_CSET);
|
|
for (word = ban_words; word; word = word->next)
|
|
{
|
|
if (stristr(ptr, word->string))
|
|
{
|
|
if (wild_match(word->channel, to))
|
|
{
|
|
if (!ops && (nick_isop(nick) || nick_isvoice(nick)))
|
|
break;
|
|
send_to_server("KICK %s %s :%s %s", to, from, "\002BitchX BWK\002: ", word->string);
|
|
kick_em = 1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return kick_em;
|
|
}
|
|
|
|
/*
|
|
* is_channel: determines if the argument is a channel. If it's a number,
|
|
* begins with MULTI_CHANNEL and has no '*', or STRING_CHANNEL, then its a
|
|
* channel
|
|
*/
|
|
int BX_is_channel(const char *to)
|
|
{
|
|
return to &&
|
|
(*to == MULTI_CHANNEL ||
|
|
*to == STRING_CHANNEL ||
|
|
*to == ID_CHANNEL ||
|
|
*to == LOCAL_CHANNEL);
|
|
}
|
|
|
|
|
|
char * BX_PasteArgs(char **Args, int StartPoint)
|
|
{
|
|
int i;
|
|
|
|
for (; StartPoint; Args++, StartPoint--)
|
|
if (!*Args)
|
|
return NULL;
|
|
for (i = 0; Args[i] && Args[i+1]; i++)
|
|
Args[i][strlen(Args[i])] = ' ';
|
|
Args[1] = NULL;
|
|
return Args[0];
|
|
}
|
|
|
|
/*
|
|
* BreakArgs: breaks up the line from the server, in to where its from,
|
|
* setting FromUserHost if it should be, and returns all the arguments
|
|
* that are there. Re-written by phone, dec 1992.
|
|
*/
|
|
int BX_BreakArgs(char *Input, char **Sender, char **OutPut, int ig_sender)
|
|
{
|
|
int ArgCount = 0;
|
|
|
|
/*
|
|
* The RFC describes it fully, but in a short form, a line looks like:
|
|
* [:sender[!user@host]] COMMAND ARGUMENT [[:]ARGUMENT]{0..14}
|
|
*/
|
|
|
|
/*
|
|
* Look to see if the optional :sender is present.
|
|
*/
|
|
if (!ig_sender)
|
|
{
|
|
if (*Input == ':')
|
|
{
|
|
*Sender = ++Input;
|
|
while (*Input && *Input != *space)
|
|
Input++;
|
|
if (*Input == *space)
|
|
*Input++ = 0;
|
|
|
|
/*
|
|
* Look to see if the optional !user@host is present.
|
|
* look for @host only as services use it.
|
|
*/
|
|
FromUserHost = *Sender;
|
|
while (*FromUserHost && *FromUserHost != '!' && *FromUserHost != '@')
|
|
FromUserHost++;
|
|
if (*FromUserHost == '!' || *FromUserHost == '@')
|
|
*FromUserHost++ = 0;
|
|
}
|
|
/*
|
|
* No sender present.
|
|
*/
|
|
else
|
|
*Sender = FromUserHost = empty_string;
|
|
}
|
|
/*
|
|
* Now we go through the argument list...
|
|
*/
|
|
for (;;)
|
|
{
|
|
while (*Input && *Input == *space)
|
|
Input++;
|
|
|
|
if (!*Input)
|
|
break;
|
|
|
|
if (*Input == ':')
|
|
{
|
|
/* Squash the : so if PasteArgs() is called it doesn't reappear */
|
|
ov_strcpy(Input, Input + 1);
|
|
OutPut[ArgCount++] = Input;
|
|
break;
|
|
}
|
|
|
|
OutPut[ArgCount++] = Input;
|
|
if (ArgCount >= MAXPARA)
|
|
break;
|
|
|
|
while (*Input && *Input != *space)
|
|
Input++;
|
|
if (*Input == *space)
|
|
*Input++ = 0;
|
|
}
|
|
OutPut[ArgCount] = NULL;
|
|
return ArgCount;
|
|
}
|
|
|
|
/* in response to a TOPIC message from the server */
|
|
static void p_topic(char *from, char **ArgList)
|
|
{
|
|
ChannelList *tmp;
|
|
|
|
|
|
if (!ArgList[1])
|
|
{ fake(); return; }
|
|
if ((tmp = lookup_channel(ArgList[0], from_server, CHAN_NOUNLINK)))
|
|
{
|
|
update_stats(TOPICLIST, find_nicklist_in_channellist(from, tmp, 0), tmp, 0);
|
|
if (tmp->topic_lock)
|
|
{
|
|
if (my_stricmp(from, get_server_nickname(from_server)))
|
|
{
|
|
if (tmp->topic)
|
|
{
|
|
if (!ArgList[1] || my_stricmp(ArgList[1], tmp->topic))
|
|
send_to_server("TOPIC %s :%s", tmp->channel, tmp->topic);
|
|
}
|
|
} else
|
|
malloc_strcpy(&tmp->topic, ArgList[1]);
|
|
} else
|
|
malloc_strcpy(&tmp->topic, ArgList[1]);
|
|
add_last_type(&last_topic[0], 1, from, FromUserHost, tmp->channel, ArgList[1]);
|
|
do_logchannel(LOG_TOPIC, tmp, "%s %s %s", from, ArgList[0], ArgList[1] ? ArgList[1] : empty_string);
|
|
}
|
|
if (tmp && check_ignore(from, FromUserHost, tmp->channel, IGNORE_TOPICS, NULL) != IGNORED)
|
|
{
|
|
set_display_target(ArgList[0], LOG_CRAP);
|
|
if (do_hook(TOPIC_LIST, "%s %s %s", from, ArgList[0], ArgList[1]))
|
|
{
|
|
if (ArgList[1] && *ArgList[1])
|
|
{
|
|
if (fget_string_var(FORMAT_TOPIC_CHANGE_HEADER_FSET))
|
|
put_it("%s",convert_output_format(fget_string_var(FORMAT_TOPIC_CHANGE_HEADER_FSET), "%s %s %s %s", update_clock(GET_TIME), from, ArgList[0], ArgList[1]));
|
|
put_it("%s",convert_output_format(fget_string_var(FORMAT_TOPIC_CHANGE_FSET), "%s %s %s %s", update_clock(GET_TIME), from, ArgList[0], ArgList[1]));
|
|
} else
|
|
put_it("%s",convert_output_format(fget_string_var(FORMAT_TOPIC_UNSET_FSET), "%s %s %s", update_clock(GET_TIME), from, ArgList[0]));
|
|
|
|
}
|
|
reset_display_target();
|
|
}
|
|
logmsg(LOG_TOPIC, from, 0, "%s %s", ArgList[0], ArgList[1] ? ArgList[1]:empty_string);
|
|
#ifdef GUI
|
|
xterm_settitle();
|
|
#endif
|
|
update_all_status(current_window, NULL, 0);
|
|
}
|
|
|
|
static void p_wallops(char *from, char **ArgList)
|
|
{
|
|
char *line;
|
|
int autorep = 0;
|
|
int from_server = strchr(from, '.') ? 1 : 0;
|
|
|
|
|
|
if (!(line = PasteArgs(ArgList, 0)))
|
|
{ fake(); return; }
|
|
|
|
if (from_server || check_flooding(from, WALLOP_FLOOD,line, NULL))
|
|
{
|
|
/* The old server check, don't use the whois stuff for servers */
|
|
int level;
|
|
char *high;
|
|
switch (check_ignore(from, FromUserHost, NULL, IGNORE_WALLOPS, NULL))
|
|
{
|
|
case (IGNORED):
|
|
return;
|
|
case (HIGHLIGHTED):
|
|
high = highlight_char;
|
|
break;
|
|
default:
|
|
high = empty_string;
|
|
break;
|
|
}
|
|
set_display_target(from, LOG_WALLOP);
|
|
level = set_lastlog_msg_level(LOG_WALLOP);
|
|
autorep = check_auto_reply(line);
|
|
add_last_type(&last_wall[0], MAX_LAST_MSG, from, NULL, from_server ? "S":"*", line);
|
|
if (do_hook(WALLOP_LIST, "%s %c %s", from, from_server ? 'S': '*',line))
|
|
put_it("%s",convert_output_format(fget_string_var(from_server? FORMAT_WALLOP_FSET: (autorep? FORMAT_WALL_AR_FSET:FORMAT_WALL_FSET)),
|
|
"%s %s %s %s", update_clock(GET_TIME),
|
|
from, from_server?"!":"*", line));
|
|
if (beep_on_level & LOG_WALLOP)
|
|
beep_em(1);
|
|
logmsg(LOG_WALLOP, from, 0, "%s", line);
|
|
set_lastlog_msg_level(level);
|
|
reset_display_target();
|
|
}
|
|
}
|
|
|
|
static void p_privmsg(char *from, char **Args)
|
|
{
|
|
int level;
|
|
int list_type;
|
|
int flood_type;
|
|
int log_type;
|
|
int ar_true = 0;
|
|
int flooding = 0;
|
|
long ignore_type;
|
|
char *ptr;
|
|
char *to;
|
|
char *high;
|
|
ChannelList *channel = NULL;
|
|
NickList *tmpnick = NULL;
|
|
|
|
if (!from)
|
|
return;
|
|
|
|
PasteArgs(Args, 1);
|
|
to = Args[0];
|
|
ptr = Args[1];
|
|
if (!to || !ptr)
|
|
{ fake(); return; }
|
|
|
|
doing_privmsg = 1;
|
|
|
|
ptr = do_ctcp(from, to, ptr);
|
|
if (!ptr || !*ptr)
|
|
{
|
|
doing_privmsg = 0;
|
|
return;
|
|
}
|
|
|
|
if (is_channel(to) && im_on_channel(to, from_server))
|
|
{
|
|
set_display_target(to, LOG_PUBLIC);
|
|
malloc_strcpy(&public_nick, from);
|
|
log_type = LOG_PUBLIC;
|
|
ignore_type = IGNORE_PUBLIC;
|
|
flood_type = PUBLIC_FLOOD;
|
|
|
|
if (!is_on_channel(to, from_server, from))
|
|
list_type = PUBLIC_MSG_LIST;
|
|
else
|
|
{
|
|
if (is_current_channel(to, from_server, 0))
|
|
list_type = PUBLIC_LIST;
|
|
else
|
|
list_type = PUBLIC_OTHER_LIST;
|
|
channel = lookup_channel(to, from_server, CHAN_NOUNLINK);
|
|
if (channel)
|
|
tmpnick = find_nicklist_in_channellist(from, channel, 0);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
set_display_target(from, LOG_MSG);
|
|
flood_type = MSG_FLOOD;
|
|
if (my_stricmp(to, get_server_nickname(from_server)))
|
|
{
|
|
log_type = LOG_WALL;
|
|
ignore_type = IGNORE_WALLS;
|
|
list_type = MSG_GROUP_LIST;
|
|
flood_type = WALL_FLOOD;
|
|
}
|
|
else
|
|
{
|
|
log_type = LOG_MSG;
|
|
ignore_type = IGNORE_MSGS;
|
|
list_type = MSG_LIST;
|
|
}
|
|
}
|
|
switch (check_ignore(from, FromUserHost, to, ignore_type, ptr))
|
|
{
|
|
case IGNORED:
|
|
if ((list_type == MSG_LIST) && get_int_var(SEND_IGNORE_MSG_VAR))
|
|
send_to_server("NOTICE %s :%s is ignoring you", from, get_server_nickname(from_server));
|
|
doing_privmsg = 0;
|
|
return;
|
|
case HIGHLIGHTED:
|
|
high = highlight_char;
|
|
break;
|
|
case CHANNEL_GREP:
|
|
high = highlight_char;
|
|
break;
|
|
default:
|
|
high = empty_string;
|
|
break;
|
|
}
|
|
|
|
#ifdef WANT_TCL
|
|
switch (list_type)
|
|
{
|
|
case MSG_LIST:
|
|
case MSG_GROUP_LIST:
|
|
{
|
|
char *ctcp_ptr = LOCAL_COPY(ptr);
|
|
char *cmd = next_arg(ctcp_ptr, &ctcp_ptr);
|
|
if (!check_tcl_msg(cmd, from, FromUserHost, from, ctcp_ptr))
|
|
check_tcl_msgm(cmd, from, FromUserHost, from, ctcp_ptr);
|
|
break;
|
|
}
|
|
|
|
case PUBLIC_MSG_LIST:
|
|
case PUBLIC_LIST:
|
|
case PUBLIC_OTHER_LIST:
|
|
{
|
|
if (!check_tcl_pub(from, FromUserHost, to, ptr))
|
|
check_tcl_pubm(from, FromUserHost, to, ptr);
|
|
break;
|
|
}
|
|
}
|
|
#endif
|
|
update_stats(PUBLICLIST, tmpnick, channel, 0);
|
|
|
|
level = set_lastlog_msg_level(log_type);
|
|
if (flood_type == PUBLIC_FLOOD)
|
|
{
|
|
int blah = 0;
|
|
if (is_other_flood(channel, tmpnick, PUBLIC_FLOOD, &blah))
|
|
{
|
|
flooding = 1;
|
|
flood_prot(tmpnick->nick, FromUserHost, flood_type, get_cset_int_var(channel->csets, PUBFLOOD_IGNORE_TIME_CSET), channel->channel);
|
|
}
|
|
}
|
|
else
|
|
flooding = !check_flooding(from, flood_type, ptr, NULL);
|
|
|
|
if (list_type == PUBLIC_LIST || list_type == PUBLIC_OTHER_LIST || list_type == PUBLIC_MSG_LIST)
|
|
{
|
|
if (check_auto_reply(ptr))
|
|
{
|
|
addtabkey(from, "msg", 1);
|
|
ar_true = 1;
|
|
}
|
|
}
|
|
|
|
if (!flooding)
|
|
{
|
|
int do_beep = 0;
|
|
|
|
switch (list_type)
|
|
{
|
|
case PUBLIC_MSG_LIST:
|
|
if (do_hook(list_type, "%s %s %s", from, to, ptr))
|
|
{
|
|
logmsg(LOG_PUBLIC, from, 0, "%s %s", to, ptr);
|
|
put_it("%s",convert_output_format(fget_string_var(ar_true?FORMAT_PUBLIC_MSG_AR_FSET:FORMAT_PUBLIC_MSG_FSET), "%s %s %s %s %s", update_clock(GET_TIME), from, FromUserHost, to, ptr));
|
|
do_beep = 1;
|
|
}
|
|
break;
|
|
|
|
case MSG_GROUP_LIST:
|
|
if (do_hook(list_type, "%s %s %s", from, to, ptr))
|
|
{
|
|
logmsg(LOG_PUBLIC, from, 0,"%s %s", FromUserHost, ptr);
|
|
put_it("%s", convert_output_format(fget_string_var(FORMAT_MSG_GROUP_FSET), "%s %s %s %s", update_clock(GET_TIME), from, to, ptr));
|
|
do_beep = 1;
|
|
}
|
|
break;
|
|
|
|
case MSG_LIST:
|
|
set_server_recv_nick(from_server, from);
|
|
#ifdef WANT_CDCC
|
|
if ((msgcdcc(from, to, ptr)) == NULL)
|
|
break;
|
|
#endif
|
|
if (strbegins(ptr, "PASS") && change_pass(from, ptr))
|
|
break;
|
|
if (forwardnick)
|
|
send_to_server("NOTICE %s :*%s* %s", forwardnick, from, ptr);
|
|
|
|
if (do_hook(list_type, "%s %s", from, ptr))
|
|
{
|
|
if (get_server_away(from_server))
|
|
{
|
|
do_beep = 0;
|
|
beep_em(get_int_var(BEEP_WHEN_AWAY_VAR));
|
|
set_int_var(MSGCOUNT_VAR, get_int_var(MSGCOUNT_VAR)+1);
|
|
}
|
|
else
|
|
do_beep = 1;
|
|
put_it("%s", convert_output_format(fget_string_var(FORMAT_MSG_FSET), "%s %s %s %s", update_clock(GET_TIME), from, FromUserHost, ptr));
|
|
addtabkey(from, "msg", 0);
|
|
logmsg(LOG_MSG, from, 0,"%s %s", FromUserHost, ptr);
|
|
}
|
|
add_last_type(&last_msg[0], MAX_LAST_MSG, from, FromUserHost, to, ptr);
|
|
if (get_server_away(from_server) && get_int_var(SEND_AWAY_MSG_VAR))
|
|
{
|
|
if (!check_last_type(&last_msg[0], MAX_LAST_MSG, from, FromUserHost))
|
|
my_send_to_server(from_server, "NOTICE %s :%s", from, stripansicodes(convert_output_format(fget_string_var(FORMAT_SEND_AWAY_FSET), "%l %l %s", now, get_server_awaytime(from_server), get_int_var(MSGLOG_VAR)?"On":"Off")));
|
|
}
|
|
break;
|
|
|
|
case PUBLIC_LIST:
|
|
annoy_kicks(list_type, to, from, ptr, tmpnick);
|
|
if (ar_true)
|
|
list_type = PUBLIC_AR_LIST;
|
|
if (do_hook(list_type, "%s %s %s", from, to, ptr))
|
|
{
|
|
logmsg(LOG_PUBLIC, from, 0,"%s %s", to, ptr);
|
|
do_logchannel(LOG_PUBLIC, channel, "%s", convert_output_format(fget_string_var((list_type == PUBLIC_AR_LIST)? FORMAT_PUBLIC_AR_FSET:FORMAT_PUBLIC_FSET), "%s %s %s %s", update_clock(GET_TIME), from, to, ptr));
|
|
put_it("%s", convert_output_format(fget_string_var((list_type == PUBLIC_AR_LIST)? FORMAT_PUBLIC_AR_FSET:FORMAT_PUBLIC_FSET), "%s %s %s %s", update_clock(GET_TIME), from, to, ptr));
|
|
do_beep = 1;
|
|
}
|
|
break;
|
|
|
|
case PUBLIC_OTHER_LIST:
|
|
annoy_kicks(list_type, to, from, ptr, tmpnick);
|
|
if (ar_true)
|
|
list_type = PUBLIC_OTHER_AR_LIST;
|
|
if (do_hook(list_type, "%s %s %s", from, to, ptr))
|
|
{
|
|
logmsg(LOG_PUBLIC, from, 0,"%s %s", to, ptr);
|
|
do_logchannel(LOG_PUBLIC, channel, "%s", convert_output_format(fget_string_var(list_type==PUBLIC_OTHER_AR_LIST?FORMAT_PUBLIC_OTHER_AR_FSET:FORMAT_PUBLIC_OTHER_FSET), "%s %s %s %s", update_clock(GET_TIME), from, to, ptr));
|
|
put_it("%s", convert_output_format(fget_string_var(list_type==PUBLIC_OTHER_AR_LIST?FORMAT_PUBLIC_OTHER_AR_FSET:FORMAT_PUBLIC_OTHER_FSET), "%s %s %s %s", update_clock(GET_TIME), from, to, ptr));
|
|
do_beep = 1;
|
|
}
|
|
break;
|
|
} /* switch */
|
|
|
|
if ((beep_on_level & log_type) && do_beep)
|
|
beep_em(1);
|
|
|
|
grab_http(from, to, ptr);
|
|
}
|
|
|
|
set_lastlog_msg_level(level);
|
|
reset_display_target();
|
|
doing_privmsg = 0;
|
|
}
|
|
|
|
static void p_quit(char *from, char **ArgList)
|
|
{
|
|
int one_prints = 0;
|
|
char *reason;
|
|
char *chanlist = NULL;
|
|
ChannelList *chan;
|
|
int netsplit = 0;
|
|
int ignore;
|
|
|
|
PasteArgs(ArgList, 0);
|
|
if (ArgList[0])
|
|
{
|
|
reason = ArgList[0];
|
|
netsplit = check_split(from, reason);
|
|
}
|
|
else
|
|
reason = "?";
|
|
|
|
for (chan = walk_channels(from, 1, from_server); chan;
|
|
chan = walk_channels(from, 0, -1))
|
|
{
|
|
update_stats(CHANNELSIGNOFFLIST,
|
|
find_nicklist_in_channellist(from, chan, 0), chan, netsplit);
|
|
|
|
#ifdef WANT_TCL
|
|
if (netsplit)
|
|
check_tcl_split(from, FromUserHost, from, chan->channel);
|
|
else
|
|
check_tcl_sign(from, FromUserHost, from, chan->channel, reason);
|
|
#endif
|
|
|
|
if (!netsplit)
|
|
{
|
|
do_logchannel(LOG_PART, chan, "%s %s %s %s", from, FromUserHost,
|
|
chan->channel, reason);
|
|
check_channel_limit(chan);
|
|
}
|
|
|
|
if (chanlist)
|
|
m_3cat(&chanlist, ",", chan->channel);
|
|
else
|
|
malloc_strcpy(&chanlist, chan->channel);
|
|
|
|
ignore = check_ignore(from, FromUserHost, chan->channel,
|
|
(netsplit?IGNORE_SPLITS:IGNORE_QUITS), NULL);
|
|
if (ignore != IGNORED)
|
|
{
|
|
set_display_target(chan->channel, LOG_CRAP);
|
|
if (do_hook(CHANNEL_SIGNOFF_LIST, "%s %s %s", chan->channel,
|
|
from, reason))
|
|
one_prints = 1;
|
|
}
|
|
}
|
|
|
|
if (one_prints)
|
|
{
|
|
char *channel = what_channel(from, from_server);
|
|
ignore = check_ignore(from, FromUserHost, channel,
|
|
(netsplit?IGNORE_SPLITS:IGNORE_QUITS), NULL);
|
|
set_display_target(channel, LOG_CRAP);
|
|
if ((ignore != IGNORED) && do_hook(SIGNOFF_LIST, "%s %s", from, reason)
|
|
&& !netsplit)
|
|
put_it("%s", convert_output_format(
|
|
fget_string_var(FORMAT_CHANNEL_SIGNOFF_FSET),
|
|
"%s %s %s %s %s", update_clock(GET_TIME), from, FromUserHost,
|
|
chanlist, reason));
|
|
}
|
|
|
|
logmsg(LOG_PART, from, 0, "%s %s", chanlist ? chanlist : "<NONE>", reason);
|
|
check_orig_nick(from);
|
|
notify_mark(from, FromUserHost, 0, 0);
|
|
remove_from_channel(NULL, from, from_server, netsplit, reason);
|
|
update_all_status(current_window, NULL, 0);
|
|
new_free(&chanlist);
|
|
reset_display_target();
|
|
#ifdef GUI
|
|
gui_update_nicklist(NULL);
|
|
#endif
|
|
}
|
|
|
|
static int sping_reply(char *from, char *sping_dest, int server)
|
|
{
|
|
char buff[50];
|
|
Sping *tmp = get_server_sping(server, sping_dest);
|
|
|
|
if (!tmp)
|
|
return 0;
|
|
|
|
snprintf(buff, sizeof buff, "%2.4f", time_since(&tmp->in_sping));
|
|
|
|
reset_display_target();
|
|
put_it("%s", convert_output_format("$G Server pong from %W$0%n $1 seconds", "%s %s", from, buff));
|
|
clear_server_sping(server, sping_dest);
|
|
return 1;
|
|
}
|
|
|
|
static void p_pong(char *from, char **ArgList)
|
|
{
|
|
int is_server = 0;
|
|
|
|
if (!ArgList[0] || !ArgList[1])
|
|
return;
|
|
|
|
is_server = wild_match("*.*", ArgList[0]);
|
|
|
|
if (check_ignore(from, FromUserHost, NULL, IGNORE_PONGS, NULL) == IGNORED)
|
|
return;
|
|
|
|
if (!is_server)
|
|
return;
|
|
|
|
if (strbegins(ArgList[1], "LAG!"))
|
|
{
|
|
/* PONG for lag check */
|
|
char *p, *q;
|
|
unsigned long cookie;
|
|
struct timeval timenow, timethen;
|
|
|
|
get_time(&timenow);
|
|
p = strchr(ArgList[1], '.');
|
|
if (p)
|
|
{
|
|
*p++ = 0;
|
|
cookie = strtoul(ArgList[1] + 4, NULL, 10);
|
|
|
|
q = strchr(p, '.');
|
|
if (q)
|
|
{
|
|
*q++ = 0;
|
|
timethen.tv_usec = my_atol(q);
|
|
} else
|
|
timethen.tv_usec = 0;
|
|
|
|
timethen.tv_sec = my_atol(p);
|
|
|
|
server_lag_reply(from_server, cookie, timenow, timethen);
|
|
}
|
|
}
|
|
else if (!my_stricmp(ArgList[1], get_server_nickname(from_server)))
|
|
{
|
|
/* PONG from remote server */
|
|
sping_reply(ArgList[0], ArgList[0], from_server);
|
|
}
|
|
else if (wild_match("*.*", ArgList[1]))
|
|
{
|
|
/* PONG from local server, possibly on behalf of remote server */
|
|
sping_reply(ArgList[0], ArgList[1], from_server);
|
|
}
|
|
else
|
|
{
|
|
reset_display_target();
|
|
say("%s: PONG received from %s %s", ArgList[0], from, ArgList[1]);
|
|
}
|
|
}
|
|
|
|
static void p_error(char *from, char **ArgList)
|
|
{
|
|
|
|
PasteArgs(ArgList, 0);
|
|
if (!ArgList[0])
|
|
{
|
|
fake();
|
|
return;
|
|
}
|
|
|
|
say("%s", ArgList[0]);
|
|
}
|
|
|
|
/*
|
|
* This only handles negotiating the SASL capability with the PLAIN method. It would
|
|
* be good to add DH-BLOWFISH, and later, full capability support.
|
|
*/
|
|
static void p_cap(char *from, char **ArgList)
|
|
{
|
|
char *caps, *p;
|
|
|
|
if (!strcmp(ArgList[1], "ACK"))
|
|
{
|
|
caps = LOCAL_COPY(ArgList[2]);
|
|
while ((p = next_arg(caps, &caps)) != NULL)
|
|
{
|
|
/* Only AUTHENTICATE before registration */
|
|
if (!strcmp(p, "sasl") && !is_server_connected(from_server))
|
|
{
|
|
my_send_to_server(from_server, "AUTHENTICATE PLAIN");
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else if (!strcmp(ArgList[1], "NAK"))
|
|
{
|
|
caps = LOCAL_COPY(ArgList[2]);
|
|
while ((p = next_arg(caps, &caps)) != NULL)
|
|
{
|
|
/* End capability negotiation to continue registration */
|
|
if (!strcmp(p, "sasl") && !is_server_connected(from_server))
|
|
{
|
|
my_send_to_server(from_server, "CAP END");
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void p_authenticate(char *from, char **ArgList)
|
|
{
|
|
/* "AUTHENTICATE command MUST be used before registration is complete" */
|
|
if (is_server_connected(from_server))
|
|
return;
|
|
|
|
if (!strcmp(ArgList[0], "+"))
|
|
{
|
|
/* Message is BASE64(nick\0nick\0pass) */
|
|
char buf[IRCD_BUFFER_SIZE];
|
|
char *output = NULL;
|
|
char *nick = get_server_sasl_nick(from_server);
|
|
char *pass = get_server_sasl_pass(from_server);
|
|
size_t nick_len = nick ? strlen(nick) + 1 : 0; /* nick_len includes \0 */
|
|
size_t pass_len = pass ? strlen(pass) : 0;
|
|
|
|
/* "The client can abort an authentication by sending an asterisk as the data" */
|
|
if (!nick || !pass || nick_len * 2 + pass_len > sizeof buf)
|
|
{
|
|
my_send_to_server(from_server, "AUTHENTICATE *");
|
|
return;
|
|
}
|
|
|
|
memcpy(buf, nick, nick_len);
|
|
memcpy(buf + nick_len, nick, nick_len);
|
|
memcpy(buf + nick_len * 2, pass, pass_len);
|
|
|
|
output = base64_encode(buf, nick_len * 2 + pass_len);
|
|
my_send_to_server(from_server, "AUTHENTICATE %s", output);
|
|
new_free(&output);
|
|
}
|
|
}
|
|
|
|
void add_user_who (WhoEntry *w, char *from, char **ArgList)
|
|
{
|
|
char *userhost;
|
|
int op = 0, voice = 0;
|
|
|
|
/* Obviously this is safe. */
|
|
userhost = alloca(strlen(ArgList[1]) + strlen(ArgList[2]) + 2);
|
|
sprintf(userhost, "%s@%s", ArgList[1], ArgList[2]);
|
|
voice = (strchr(ArgList[5], '+') != NULL);
|
|
op = (strchr(ArgList[5], '@') != NULL);
|
|
add_to_channel(ArgList[0], ArgList[4], from_server, op, voice, userhost, ArgList[3], ArgList[5], 0, ArgList[6] ? my_atol(ArgList[6]) : 0);
|
|
#ifdef WANT_NSLOOKUP
|
|
if (get_int_var(AUTO_NSLOOKUP_VAR))
|
|
do_nslookup(ArgList[2], ArgList[4], ArgList[1], ArgList[0], from_server, auto_nslookup, NULL);
|
|
#endif
|
|
}
|
|
|
|
void add_user_end (WhoEntry *w, char *from, char **ArgList)
|
|
{
|
|
got_info(ArgList[0], from_server, GOTWHO);
|
|
/* Nothing to do! */
|
|
}
|
|
|
|
static void p_channel(char *from, char **ArgList)
|
|
{
|
|
char *channel;
|
|
ChannelList *chan = NULL;
|
|
NickList *tmpnick = NULL;
|
|
WhowasList *whowas = NULL;
|
|
int its_me = 0;
|
|
int op = 0, vo = 0;
|
|
char extra[80];
|
|
register char *c;
|
|
Window *old_window = current_window;
|
|
int switched = 0;
|
|
irc_server *irc_serv = NULL;
|
|
|
|
|
|
if (!strcmp(ArgList[0], zero))
|
|
{
|
|
fake();
|
|
return;
|
|
}
|
|
|
|
channel = ArgList[0];
|
|
set_display_target(channel, LOG_CRAP);
|
|
malloc_strcpy(&joined_nick, from);
|
|
|
|
/*
|
|
* Workaround for gratuitous protocol change in ef2.9
|
|
*/
|
|
*extra = 0;
|
|
if ((c = strchr(channel, '\007')))
|
|
{
|
|
for (*c++ = 0; *c; c++)
|
|
{
|
|
if (*c == 'o') op = 1;
|
|
else if (*c == 'v') vo = 1;
|
|
}
|
|
}
|
|
if (op)
|
|
strcat(extra, " (+o)");
|
|
if (vo)
|
|
strcat(extra, " (+v)");
|
|
|
|
if (!my_stricmp(from, get_server_nickname(from_server)))
|
|
{
|
|
int refnum;
|
|
if (!in_join_list(channel, from_server))
|
|
{
|
|
add_to_join_list(channel, from_server, current_window->refnum);
|
|
refnum = current_window->refnum;
|
|
}
|
|
else
|
|
{
|
|
|
|
if (current_window->refnum != (refnum = get_win_from_join_list(channel, from_server)))
|
|
{
|
|
switched = 1;
|
|
make_window_current(get_window_by_refnum(refnum));
|
|
}
|
|
}
|
|
|
|
its_me = 1;
|
|
chan = add_channel(channel, from_server, refnum);
|
|
do_hook(JOIN_ME_LIST, "%s %d", channel, refnum);
|
|
if (*channel == '+')
|
|
{
|
|
got_info(channel, from_server, GOTBANS);
|
|
got_info(channel, from_server, GOTMODE);
|
|
if ((get_server_version(from_server) == Server2_8ts4)
|
|
|| (get_server_version(from_server) == Server2_10))
|
|
got_info(channel, from_server, GOTEXEMPT);
|
|
}
|
|
else
|
|
{
|
|
int ver = get_server_version(from_server);
|
|
if ((ver == Server2_8ts4) || (ver == Server2_10))
|
|
send_to_server("MODE %s\r\nMODE %s b\r\nMODE %s e", channel, channel, channel);
|
|
else
|
|
send_to_server("MODE %s\r\nMODE %s b", channel, channel);
|
|
}
|
|
whobase(channel, add_user_who, add_user_end, NULL);
|
|
}
|
|
else
|
|
{
|
|
if ((whowas = check_whosplitin_buffer(from, FromUserHost, channel, 0)))
|
|
irc_serv = check_split_server(whowas->server1);
|
|
chan = add_to_channel(channel, from, from_server, op, vo, FromUserHost, NULL, NULL, whowas && irc_serv ? 1 : 0, 0);
|
|
if (whowas && whowas->server2 && irc_serv)
|
|
new_free(&whowas->server2);
|
|
|
|
#ifdef WANT_TCL
|
|
check_tcl_join(from, FromUserHost, from, channel);
|
|
#endif
|
|
logmsg(LOG_JOIN, from, 0, "%s %s %s", FromUserHost, channel, extra);
|
|
do_logchannel(LOG_JOIN, chan, "%s, %s %s %s", from, FromUserHost, channel, extra);
|
|
if (!irc_serv)
|
|
check_channel_limit(chan);
|
|
}
|
|
|
|
#ifdef WANT_USERLIST
|
|
if (!in_join_list(channel, from_server) && chan)
|
|
tmpnick = check_auto(channel, find_nicklist_in_channellist(from, chan, 0), chan);
|
|
#endif
|
|
flush_mode_all(chan);
|
|
|
|
if (tmpnick && !tmpnick->ip && get_int_var(AUTO_NSLOOKUP_VAR))
|
|
{
|
|
char *user;
|
|
#ifdef WANT_NSLOOKUP
|
|
char *host;
|
|
#endif
|
|
user = LOCAL_COPY(FromUserHost);
|
|
|
|
#ifdef WANT_NSLOOKUP
|
|
if ((host = strchr(user, '@')))
|
|
{
|
|
*host++ = 0;
|
|
do_nslookup(host, from, user, channel, from_server, auto_nslookup, NULL);
|
|
}
|
|
#endif
|
|
}
|
|
set_display_target(channel, LOG_CRAP);
|
|
if (whowas)
|
|
{
|
|
if (irc_serv)
|
|
{
|
|
if ((do_hook(LLOOK_JOIN_LIST, "%s %s", irc_serv->name, irc_serv->link)))
|
|
put_it("%s", convert_output_format(fget_string_var(FORMAT_NETJOIN_FSET), "%s %s %s %d", update_clock(GET_TIME), irc_serv->name, irc_serv->link, 0));
|
|
remove_split_server(CHAN_SPLIT, irc_serv->name);
|
|
}
|
|
#ifdef WANT_TCL
|
|
check_tcl_rejoin(from, FromUserHost, from, channel);
|
|
#endif
|
|
}
|
|
if (check_ignore(from, FromUserHost, channel, IGNORE_JOINS, NULL) != IGNORED && chan)
|
|
{
|
|
if (do_hook(JOIN_LIST, "%s %s %s %s", from, channel, FromUserHost? FromUserHost : "UnKnown", extra))
|
|
{
|
|
if (chan && (tmpnick = find_nicklist_in_channellist(from, chan, 0)))
|
|
{
|
|
if (tmpnick->userlist)
|
|
put_it("%s",convert_output_format(fget_string_var(FORMAT_FRIEND_JOIN_FSET), "%s %s %s %s %s %s",update_clock(GET_TIME),from,FromUserHost?FromUserHost:"UnKnown",channel, tmpnick->userlist?(tmpnick->userlist->comment?tmpnick->userlist->comment:empty_string):empty_string, extra));
|
|
else
|
|
put_it("%s",convert_output_format(fget_string_var(FORMAT_JOIN_FSET), "%s %s %s %s %s",update_clock(GET_TIME),from,FromUserHost?FromUserHost:"UnKnown",channel, extra));
|
|
}
|
|
else
|
|
put_it("%s",convert_output_format(fget_string_var(FORMAT_JOIN_FSET), "%s %s %s %s %s",update_clock(GET_TIME),from,FromUserHost?FromUserHost:"UnKnown",channel, extra));
|
|
|
|
if (!its_me && chan && chan->have_op)
|
|
{
|
|
if (get_cset_int_var(chan->csets, LAMELIST_CSET))
|
|
{
|
|
if (lame_list && find_in_list((List **)&lame_list, from, 0))
|
|
{
|
|
send_to_server("MODE %s -o+b %s %s!*", chan->channel, from, from);
|
|
send_to_server("KICK %s %s :\002Lame Nick detected\002", chan->channel, from);
|
|
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, from), NULL, current_window->refnum, "auto-unban");
|
|
}
|
|
}
|
|
if (get_cset_int_var(chan->csets, LAMEIDENT_CSET))
|
|
{
|
|
/* This may be obsolete, I don't know of any servers that allow this */
|
|
static const char lame_chars[] =
|
|
"\x01\x02\x03\x04\x05\x06\x07\x08\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a";
|
|
if (strpbrk(FromUserHost, lame_chars))
|
|
{
|
|
char *host = strchr(FromUserHost, '@') + 1;
|
|
send_to_server("MODE %s +b *!*@%s\r\nKICK %s %s :\002Lame Ident detected\002", chan->channel, cluster(host), chan->channel, from);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
reset_display_target();
|
|
#ifdef GUI
|
|
gui_update_nicklist(channel);
|
|
#endif
|
|
set_input_prompt(current_window, get_string_var(INPUT_PROMPT_VAR), 0);
|
|
update_all_status(current_window, NULL, 0);
|
|
notify_mark(from, FromUserHost, 1, 0);
|
|
if (switched)
|
|
make_window_current(old_window);
|
|
}
|
|
|
|
void check_auto_join(int server, char *from, char *channel, char *key)
|
|
{
|
|
ChannelList *chan = NULL;
|
|
WhowasChanList *w_chan = NULL;
|
|
UserList *u = NULL;
|
|
CSetList *cset = NULL;
|
|
if (in_join_list(channel, from_server))
|
|
return;
|
|
if ((w_chan = check_whowas_chan_buffer(channel, -1, 0)))
|
|
{
|
|
chan = w_chan->channellist;
|
|
#ifdef WANT_USERLIST
|
|
if (((get_cset_int_var(chan->csets, AUTO_REJOIN_CSET)) || (!chan && get_int_var(AUTO_REJOIN_VAR))) && (channel && ((u = lookup_userlevelc(from, FromUserHost, channel, NULL)) != NULL)))
|
|
{
|
|
if ((u->flags & ADD_BOT))
|
|
goto got_request;
|
|
}
|
|
else
|
|
#endif
|
|
if (get_cset_int_var(chan->csets, AUTO_JOIN_ON_INVITE_CSET))
|
|
goto got_request;
|
|
}
|
|
else if ((cset = (CSetList *) check_cset_queue(channel, 0)))
|
|
{
|
|
if (get_cset_int_var(cset, AUTO_JOIN_ON_INVITE_CSET))
|
|
goto got_request;
|
|
}
|
|
return;
|
|
got_request:
|
|
bitchsay("Auto-joining %s on invite", channel);
|
|
add_to_join_list(channel, from_server, current_window->refnum);
|
|
send_to_server("JOIN %s", channel);
|
|
|
|
}
|
|
|
|
static void p_invite(char *from, char **ArgList)
|
|
{
|
|
char *high;
|
|
|
|
|
|
switch (check_ignore(from, FromUserHost, ArgList[1] ? ArgList[1] : NULL, IGNORE_INVITES, NULL))
|
|
{
|
|
case IGNORED:
|
|
if (get_int_var(SEND_IGNORE_MSG_VAR))
|
|
send_to_server("NOTICE %s :%s is ignoring you",
|
|
from, get_server_nickname(from_server));
|
|
return;
|
|
case HIGHLIGHTED:
|
|
high = highlight_char;
|
|
break;
|
|
default:
|
|
high = empty_string;
|
|
break;
|
|
}
|
|
if (ArgList[0] && ArgList[1])
|
|
{
|
|
ChannelList *chan = NULL;
|
|
set_display_target(from, LOG_CRAP);
|
|
malloc_strcpy(&invite_channel, ArgList[1]);
|
|
if (check_flooding(from, INVITE_FLOOD, ArgList[1], NULL) &&
|
|
do_hook(INVITE_LIST, "%s %s %s", from, ArgList[1], ArgList[2]?ArgList[2]:empty_string))
|
|
{
|
|
char *s;
|
|
put_it("%s", convert_output_format(fget_string_var(FORMAT_INVITE_FSET), "%s %s %s",update_clock(GET_TIME), from, ArgList[1]));
|
|
if ((s = convert_to_keystr("JOIN_LAST_INVITE")) && *s)
|
|
{
|
|
if (!get_int_var(AUTO_JOIN_ON_INVITE_VAR))
|
|
{
|
|
if (ArgList[2])
|
|
bitchsay("Press %s to join %s (%s)", s, invite_channel, ArgList[2]);
|
|
else
|
|
bitchsay("Press %s to join %s", s, invite_channel);
|
|
}
|
|
}
|
|
logmsg(LOG_INVITE, from, 0, "%s", invite_channel);
|
|
}
|
|
if (!(chan = lookup_channel(invite_channel, from_server, 0)))
|
|
check_auto_join(from_server, from, invite_channel, ArgList[2]);
|
|
add_last_type(&last_invite_channel[0], 1, from, FromUserHost, NULL, ArgList[1]);
|
|
reset_display_target();
|
|
}
|
|
}
|
|
|
|
static void p_silence (char *from, char **ArgList)
|
|
{
|
|
char *target = ArgList[0];
|
|
char *mag = target++;
|
|
|
|
|
|
if (do_hook(SILENCE_LIST, "%c %s", *mag, target))
|
|
put_it("%s", convert_output_format(fget_string_var(FORMAT_SILENCE_FSET), "%s %c %s", update_clock(GET_TIME), *mag, target));
|
|
}
|
|
|
|
|
|
static void p_kill(char *from, char **ArgList)
|
|
{
|
|
int port;
|
|
int localkill;
|
|
int serverkill = strchr(from, '.') != NULL;
|
|
int next_server;
|
|
char sc[20];
|
|
|
|
/*
|
|
* Bogorific Microsoft Exchange ``IRC'' server sends out a KILL
|
|
* protocol message instead of a QUIT protocol message when
|
|
* someone is killed on your server. Do the obviously appropriate
|
|
* thing and reroute this misdirected protocol message to
|
|
* p_quit, where it should have been sent in the first place.
|
|
* Die Microsoft, Die.
|
|
*/
|
|
if (!isme(ArgList[0]))
|
|
{
|
|
/* I don't care if this doesn't work. */
|
|
p_quit(from, ArgList); /* Die Microsoft, Die */
|
|
return;
|
|
}
|
|
|
|
port = get_server_port(from_server);
|
|
snprintf(sc, 19, "+%i %d", from_server, port);
|
|
|
|
localkill = !serverkill && ArgList[1] &&
|
|
strstr(ArgList[1], get_server_name(from_server));
|
|
|
|
next_server = localkill && get_int_var(NEXT_SERVER_ON_LOCAL_KILL_VAR);
|
|
|
|
if (serverkill || (get_int_var(AUTO_RECONNECT_VAR) && !next_server))
|
|
set_server_reconnecting(from_server, 1);
|
|
|
|
close_server(from_server,empty_string);
|
|
window_check_servers(from_server);
|
|
set_input_prompt(current_window, get_string_var(INPUT_PROMPT_VAR), 0);
|
|
if (serverkill)
|
|
{
|
|
say("Server [%s] has rejected you (probably due to a nick collision)", from);
|
|
servercmd(NULL, sc, empty_string, NULL);
|
|
}
|
|
else
|
|
{
|
|
if (localkill)
|
|
{
|
|
int i = from_server + 1;
|
|
if (i >= server_list_size())
|
|
i = 0;
|
|
snprintf(sc, 19, "+%i", i);
|
|
from_server = -1;
|
|
}
|
|
if (do_hook(DISCONNECT_LIST,"Killed by %s (%s)",from,
|
|
ArgList[1] ? ArgList[1] : "(No Reason)"))
|
|
put_it("%s", convert_output_format(fget_string_var(FORMAT_KILL_FSET), "%s %s %s", update_clock(GET_TIME), from, ArgList[1]? ArgList[1] : "You have been Killed"));
|
|
if (get_int_var(CHANGE_NICK_ON_KILL_VAR))
|
|
fudge_nickname(from_server);
|
|
if (get_int_var(AUTO_RECONNECT_VAR))
|
|
servercmd (NULL, sc, empty_string, NULL);
|
|
logmsg(LOG_KILL, from, 0, "%s", ArgList[1]?ArgList[1]:"(No Reason)");
|
|
}
|
|
update_all_status(current_window, NULL, 0);
|
|
}
|
|
|
|
static void p_ping(char *from, char **ArgList)
|
|
{
|
|
|
|
|
|
PasteArgs(ArgList, 0);
|
|
send_to_server("PONG %s", ArgList[0]);
|
|
}
|
|
|
|
static void p_nick(char *from, char **ArgList)
|
|
{
|
|
int one_prints = 0,
|
|
its_me = 0;
|
|
ChannelList *chan;
|
|
char *line;
|
|
|
|
line = ArgList[0];
|
|
if (!my_stricmp(from, get_server_nickname(from_server)))
|
|
{
|
|
accept_server_nickname(from_server, line);
|
|
its_me = 1;
|
|
nick_command_is_pending(from_server, 0);
|
|
}
|
|
if (check_ignore(from, FromUserHost, NULL, IGNORE_NICKS, NULL) == IGNORED)
|
|
goto do_nick_rename;
|
|
for (chan = get_server_channels(from_server); chan; chan = chan->next)
|
|
{
|
|
if (find_nicklist_in_channellist(from, chan, 0)) {
|
|
#ifdef WANT_TCL
|
|
if (!its_me)
|
|
check_tcl_nick(from, FromUserHost, from, chan->channel, line);
|
|
#endif
|
|
set_display_target(chan->channel, LOG_CRAP);
|
|
if (do_hook(CHANNEL_NICK_LIST, "%s %s %s", chan->channel, from, line))
|
|
one_prints = 1;
|
|
do_logchannel(LOG_CRAP, chan, "%s %s", from, line);
|
|
}
|
|
}
|
|
if (one_prints)
|
|
{
|
|
if (its_me)
|
|
{
|
|
set_string_var(AUTO_RESPONSE_STR_VAR, line);
|
|
reset_display_target();
|
|
} else
|
|
set_display_target(what_channel(from, from_server), LOG_CRAP);
|
|
if (do_hook(NICKNAME_LIST, "%s %s", from, line))
|
|
put_it("%s",convert_output_format(
|
|
fget_string_var(its_me?FORMAT_NICKNAME_USER_FSET:
|
|
im_on_channel(what_channel(from, from_server), from_server)?
|
|
FORMAT_NICKNAME_FSET:
|
|
FORMAT_NICKNAME_OTHER_FSET),
|
|
"%s %s %s %s",
|
|
update_clock(GET_TIME),from, "-", line));
|
|
}
|
|
|
|
do_nick_rename:
|
|
|
|
rename_nick(from, line, from_server);
|
|
#ifdef WANT_NSLOOKUP
|
|
ar_rename_nick(from, line, from_server);
|
|
#endif
|
|
if (!its_me)
|
|
{
|
|
notify_mark(from, FromUserHost, 0, 0);
|
|
notify_mark(line, FromUserHost, 1, 0);
|
|
}
|
|
#ifdef GUI
|
|
gui_update_nicklist(NULL);
|
|
#endif
|
|
}
|
|
|
|
static int check_mode_change(NickList *nick, char type_mode, char *from, char *this_nick, char *channel)
|
|
{
|
|
time_t right_now = now;
|
|
int found = 0;
|
|
if (!nick->userlist && !isme(nick->nick))
|
|
{
|
|
if ((!nick_isop(nick) && type_mode == '+') || (nick_isop(nick) && type_mode == '-'))
|
|
{
|
|
switch(type_mode)
|
|
{
|
|
case '-':
|
|
if (nick->sent_deop > 4 && right_now - nick->sent_deop_time < 10)
|
|
return 0;
|
|
nick->sent_deop++;
|
|
nick->sent_deop_time = right_now;
|
|
break;
|
|
case '+':
|
|
if (nick->sent_reop > 4 && right_now - nick->sent_reop_time < 10)
|
|
return 0;
|
|
nick->sent_reop++;
|
|
nick->sent_reop_time = right_now;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
if (my_stricmp(this_nick, from))
|
|
{
|
|
send_to_server("MODE %s %co %s", channel, type_mode, this_nick);
|
|
found++;
|
|
}
|
|
}
|
|
}
|
|
return found;
|
|
}
|
|
|
|
static void check_bitch_mode(char *from, char *uh, char *channel, char *line, ChannelList *chan)
|
|
{
|
|
NickList *nick;
|
|
char *new_mode = NULL;
|
|
char *n = NULL;
|
|
|
|
if (!from || !chan || (chan && (!get_cset_int_var(chan->csets, BITCH_CSET) || !chan->have_op)))
|
|
return;
|
|
if (!get_int_var(HACK_OPS_VAR) && wild_match("%.%", from))
|
|
return;
|
|
if (!(nick = find_nicklist_in_channellist(from, chan, 0)))
|
|
return;
|
|
set_display_target(channel, LOG_CRAP);
|
|
new_mode = LOCAL_COPY(line);
|
|
new_mode = next_arg(new_mode, &n);
|
|
if (!nick->userlist || !check_channel_match(nick->userlist->channels, channel))
|
|
{
|
|
char *p;
|
|
char type_mode = '%' , *this_nick, *list_nicks;
|
|
int found = 0;
|
|
list_nicks = LOCAL_COPY(n);
|
|
for (p = new_mode; *p; p++)
|
|
{
|
|
switch(*p)
|
|
{
|
|
case '-':
|
|
type_mode = '+';
|
|
break;
|
|
case '+':
|
|
type_mode = '-';
|
|
break;
|
|
case 'o':
|
|
this_nick = next_arg(list_nicks, &list_nicks);
|
|
nick = find_nicklist_in_channellist(this_nick, chan, 0);
|
|
found += check_mode_change(nick, type_mode, from, this_nick, channel);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
if (found)
|
|
put_it("%s", convert_output_format(fget_string_var(FORMAT_BITCH_FSET), "%s %s %s %s %s %s", update_clock(GET_TIME), from, uh, channel, new_mode, n));
|
|
}
|
|
reset_display_target();
|
|
}
|
|
|
|
static void update_user_modes(int server, const char *modes)
|
|
{
|
|
int onoff = 1;
|
|
|
|
for (; *modes; modes++)
|
|
{
|
|
char c = *modes;
|
|
|
|
switch (c)
|
|
{
|
|
case '-':
|
|
onoff = 0;
|
|
break;
|
|
case '+':
|
|
onoff = 1;
|
|
break;
|
|
case 'o':
|
|
case 'O':
|
|
set_server_operator(server, onoff);
|
|
/* fallthrough */
|
|
default:
|
|
update_server_umode(server, c, onoff);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void p_mode(char *from, char **ArgList)
|
|
{
|
|
char *target;
|
|
char *line;
|
|
int flag;
|
|
|
|
ChannelList *chan = NULL;
|
|
ChannelList *chan2 = get_server_channels(from_server);
|
|
char buffer[BIG_BUFFER_SIZE+1];
|
|
char *smode;
|
|
char *display_uh = FromUserHost[0] ? FromUserHost : "*";
|
|
#ifdef COMPRESS_MODES
|
|
char *tmpbuf = NULL;
|
|
#endif
|
|
|
|
PasteArgs(ArgList, 1);
|
|
target = ArgList[0];
|
|
line = ArgList[1];
|
|
smode = strchr(from, '.');
|
|
|
|
flag = check_ignore(from, FromUserHost, target, (smode?IGNORE_SMODES : IGNORE_MODES) | IGNORE_CRAP, NULL);
|
|
|
|
if (target && line)
|
|
{
|
|
strcpy(buffer, line);
|
|
if (get_int_var(MODE_STRIPPER_VAR))
|
|
strip_modes(from, target, line);
|
|
if (is_channel(target))
|
|
{
|
|
set_display_target(target, LOG_MODE_CHAN);
|
|
|
|
#ifdef COMPRESS_MODES
|
|
if (chan2)
|
|
chan = (ChannelList *)find_in_list((List **)&chan2, target, 0);
|
|
if (chan && get_cset_int_var(chan->csets, COMPRESS_MODES_CSET))
|
|
{
|
|
tmpbuf = do_compress_modes(chan, from_server, target, line);
|
|
if (tmpbuf)
|
|
strcpy(line, tmpbuf);
|
|
else
|
|
flag = IGNORED;
|
|
}
|
|
#endif
|
|
/* CDE handle mode protection here instead of later */
|
|
update_channel_mode(from, target, from_server, buffer, chan);
|
|
#ifdef WANT_TCL
|
|
check_tcl_mode(from, FromUserHost, from, target, line);
|
|
#endif
|
|
if (my_stricmp(from, get_server_nickname(from_server)))
|
|
{
|
|
check_mode_lock(target, line, from_server);
|
|
check_bitch_mode(from, FromUserHost, target, line, chan);
|
|
}
|
|
|
|
if (flag != IGNORED && do_hook(MODE_LIST, "%s %s %s", from, target, line))
|
|
{
|
|
enum FSET_TYPES fset = smode ? FORMAT_SMODE_FSET : FORMAT_MODE_FSET;
|
|
put_it("%s", convert_output_format(fget_string_var(fset), "%s %s %s %s %s", update_clock(GET_TIME), from, display_uh, target, line));
|
|
}
|
|
logmsg(LOG_MODE_CHAN, from, 0, "%s %s", target, line);
|
|
do_logchannel(LOG_MODE_CHAN, chan, "%s %s, %s", from, target, line);
|
|
}
|
|
else
|
|
{
|
|
set_display_target(target, LOG_MODE_USER);
|
|
|
|
if (flag != IGNORED && do_hook(MODE_LIST, "%s %s %s", from, target, line))
|
|
{
|
|
/* User mode changes where from != target don't occur on
|
|
* standard servers, but are used by services on some networks. */
|
|
enum FSET_TYPES fset = my_stricmp(from, target) ? FORMAT_USERMODE_OTHER_FSET : FORMAT_USERMODE_FSET;
|
|
put_it("%s", convert_output_format(fget_string_var(fset), "%s %s %s %s %s", update_clock(GET_TIME), from, display_uh, target, line));
|
|
}
|
|
if (!my_stricmp(target, get_server_nickname(from_server)))
|
|
update_user_modes(from_server, line);
|
|
logmsg(LOG_MODE_USER, from, 0, "%s %s", target, line);
|
|
}
|
|
update_all_status(current_window, NULL, 0);
|
|
}
|
|
#ifdef GUI
|
|
gui_update_nicklist(target);
|
|
#endif
|
|
reset_display_target();
|
|
}
|
|
|
|
static void strip_modes (char *from, char *channel, char *line)
|
|
{
|
|
char *mode;
|
|
char *pointer;
|
|
char mag = '+'; /* XXXX Bogus */
|
|
char *copy = NULL;
|
|
char free_copy[BIG_BUFFER_SIZE+1];
|
|
|
|
strcpy(free_copy, line);
|
|
|
|
copy = free_copy;
|
|
mode = next_arg(copy, ©);
|
|
if (is_channel(channel))
|
|
{
|
|
for (pointer = mode; *pointer; pointer++)
|
|
{
|
|
char c = *pointer;
|
|
switch (c)
|
|
{
|
|
case '+' :
|
|
case '-' : mag = c; break;
|
|
case 'l' : if (mag == '+')
|
|
do_hook(MODE_STRIPPED_LIST,"%s %s %c%c %s",
|
|
from,channel,mag,c,next_arg(copy,©));
|
|
else
|
|
do_hook(MODE_STRIPPED_LIST,"%s %s %c%c",
|
|
from,channel,mag,c);
|
|
break;
|
|
case 'a' :
|
|
case 'i' :
|
|
case 'm' :
|
|
case 'n' :
|
|
case 'p' :
|
|
case 's' :
|
|
case 't' :
|
|
case 'z' :
|
|
case 'c' :
|
|
case 'r' :
|
|
case 'R' :
|
|
do_hook(MODE_STRIPPED_LIST,"%s %s %c%c",from,
|
|
channel,mag,c);
|
|
break;
|
|
case 'b' :
|
|
case 'k' :
|
|
case 'o' :
|
|
case 'e' :
|
|
case 'I' :
|
|
case 'v' : do_hook(MODE_STRIPPED_LIST,"%s %s %c%c %s",from,
|
|
channel,mag,c,next_arg(copy,©));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else /* User mode */
|
|
{
|
|
for (pointer = mode; *pointer; pointer++)
|
|
{
|
|
char c = *pointer;
|
|
switch (c)
|
|
{
|
|
case '+' :
|
|
case '-' : mag = c; break;
|
|
default : do_hook(MODE_STRIPPED_LIST,"%s %s %c%c",from, channel, mag, c);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void p_kick(char *from, char **ArgList)
|
|
{
|
|
char *channel = ArgList[0];
|
|
char *target = ArgList[1];
|
|
char *comment = ArgList[2] ? ArgList[2] : "(no comment)";
|
|
char *chankey = NULL;
|
|
ChannelList *chan = NULL;
|
|
NickList *from_nick = NULL;
|
|
int t = 0;
|
|
|
|
if ((chan = lookup_channel(channel, from_server, CHAN_NOUNLINK)))
|
|
from_nick = find_nicklist_in_channellist(from, chan, 0);
|
|
set_display_target(channel, LOG_CRAP);
|
|
if (channel && target && chan)
|
|
{
|
|
update_stats(KICKLIST, from_nick, chan, 0);
|
|
#ifdef WANT_TCL
|
|
check_tcl_kick(from, FromUserHost, from, channel, target, comment);
|
|
#endif
|
|
if (!my_stricmp(target, get_server_nickname(from_server)))
|
|
{
|
|
|
|
Window *window = get_window_by_refnum(chan->refnum);/*chan->window;*/
|
|
int rejoin = 0;
|
|
if (chan->key)
|
|
malloc_strcpy(&chankey, chan->key);
|
|
|
|
rejoin = get_cset_int_var(chan->csets, AUTO_REJOIN_CSET);
|
|
switch(rejoin)
|
|
{
|
|
case 0:
|
|
case 1:
|
|
break;
|
|
case 2:
|
|
if (FromUserHost)
|
|
{
|
|
char *username;
|
|
char *ptr;
|
|
username = LOCAL_COPY(FromUserHost);
|
|
if ((ptr = strchr(username, '@')))
|
|
{
|
|
*ptr = 0;
|
|
ptr = clear_server_flags(username);
|
|
} else
|
|
ptr = username;
|
|
do_newuser(NULL, ptr, NULL);
|
|
}
|
|
break;
|
|
|
|
case 3:
|
|
send_to_server("NICK %s", random_str(3,9));
|
|
break;
|
|
case 4:
|
|
do_newuser(NULL, random_str(2,9), NULL);
|
|
case 5:
|
|
default:
|
|
send_to_server("NICK %s", random_str(3,9));
|
|
break;
|
|
}
|
|
do_logchannel(LOG_KICK_USER, chan, "%s %s, %s %s %s", from, FromUserHost, target, channel, comment);
|
|
if (rejoin)
|
|
send_to_server("JOIN %s%s%s", channel, chankey? space : empty_string, chankey ? chankey: empty_string);
|
|
new_free(&chankey);
|
|
if (do_hook(KICK_LIST, "%s %s %s %s", target, from, channel, comment?comment:empty_string))
|
|
put_it("%s",convert_output_format(fget_string_var(FORMAT_KICK_USER_FSET),"%s %s %s %s %s",update_clock(GET_TIME),from, channel, target, comment));
|
|
remove_channel(channel);
|
|
update_all_status(window ? window : current_window, NULL, 0);
|
|
update_input(UPDATE_ALL);
|
|
logmsg(LOG_KICK_USER, from, 0, "%s %s %s %s", FromUserHost, target, channel, comment);
|
|
if (rejoin)
|
|
add_to_join_list(channel, from_server, window ? window->refnum : 0);
|
|
}
|
|
else
|
|
{
|
|
NickList *f_nick = NULL;
|
|
int itsme = !my_stricmp(get_server_nickname(from_server), from);
|
|
|
|
if ((check_ignore(from, FromUserHost, channel, IGNORE_KICKS, NULL) != IGNORED) &&
|
|
do_hook(KICK_LIST, "%s %s %s %s", target, from, channel, comment))
|
|
put_it("%s",convert_output_format(fget_string_var(FORMAT_KICK_FSET),"%s %s %s %s %s",update_clock(GET_TIME),from, channel, target, comment));
|
|
/* if it's me that's doing the kick don't flood check */
|
|
if (!itsme)
|
|
{
|
|
f_nick = find_nicklist_in_channellist(target, chan, 0);
|
|
if (chan->have_op && from_nick && is_other_flood(chan, from_nick, KICK_FLOOD, &t))
|
|
{
|
|
if (get_cset_int_var(chan->csets, KICK_ON_KICKFLOOD_CSET) > get_cset_int_var(chan->csets, DEOP_ON_KICKFLOOD_CSET))
|
|
send_to_server("MODE %s -o %s", chan->channel, from);
|
|
else if (!from_nick->sent_kick++)
|
|
send_to_server("KICK %s %s :\002Mass kick detected - (%d kicks in %dsec%s)\002", chan->channel, from, get_cset_int_var(chan->csets, KICK_ON_KICKFLOOD_CSET), t, plural(t));
|
|
}
|
|
#ifdef WANT_USERLIST
|
|
check_prot(from, target, chan, NULL, f_nick);
|
|
#endif
|
|
}
|
|
remove_from_channel(channel, target, from_server, 0, NULL);
|
|
logmsg(LOG_KICK, from, 0, "%s %s %s %s", FromUserHost, target, channel, comment);
|
|
do_logchannel(LOG_KICK, chan, "%s %s %s %s %s", from, FromUserHost, target, channel, comment);
|
|
}
|
|
|
|
}
|
|
update_all_status(current_window, NULL, 0);
|
|
reset_display_target();
|
|
#ifdef GUI
|
|
gui_update_nicklist(channel);
|
|
#endif
|
|
}
|
|
|
|
static void p_part(char *from, char **ArgList)
|
|
{
|
|
char *channel;
|
|
ChannelList *tmpc;
|
|
|
|
|
|
|
|
if (!from || !*from)
|
|
return;
|
|
channel = ArgList[0];
|
|
|
|
PasteArgs(ArgList, 1);
|
|
set_display_target(channel, LOG_CRAP);
|
|
|
|
if ((tmpc = lookup_channel(channel, from_server, CHAN_NOUNLINK)))
|
|
update_stats(LEAVELIST, find_nicklist_in_channellist(from, tmpc, 0), tmpc, 0);
|
|
|
|
if ((check_ignore(from, FromUserHost, channel, IGNORE_PARTS, NULL) != IGNORED) &&
|
|
do_hook(LEAVE_LIST, "%s %s %s %s", from, channel, FromUserHost, ArgList[1]?ArgList[1]:empty_string))
|
|
put_it("%s",convert_output_format(fget_string_var(FORMAT_LEAVE_FSET), "%s %s %s %s %s", update_clock(GET_TIME), from, FromUserHost, channel, ArgList[1]?ArgList[1]:empty_string));
|
|
if (!my_stricmp(from, get_server_nickname(from_server)))
|
|
{
|
|
remove_channel(channel);
|
|
remove_from_mode_list(channel, from_server);
|
|
remove_from_join_list(channel, from_server);
|
|
set_input_prompt(current_window, get_string_var(INPUT_PROMPT_VAR), 0);
|
|
do_hook(LEAVE_ME_LIST, "%s", channel);
|
|
}
|
|
else
|
|
{
|
|
#ifdef WANT_TCL
|
|
check_tcl_part(from, FromUserHost, from, channel);
|
|
#endif
|
|
remove_from_channel(channel, from, from_server, 0, NULL);
|
|
logmsg(LOG_PART, from, 0, "%s %s", channel, ArgList[1] ? ArgList[1]:empty_string);
|
|
do_logchannel(LOG_PART, tmpc, "%s %s %s", channel, from, ArgList[1] ? ArgList[1]:empty_string);
|
|
}
|
|
update_all_status(current_window, NULL, 0);
|
|
update_input(UPDATE_ALL);
|
|
reset_display_target();
|
|
#ifdef GUI
|
|
gui_update_nicklist(channel);
|
|
#endif
|
|
}
|
|
|
|
static void rfc1459_odd (char *from, char *comm, char **ArgList)
|
|
{
|
|
PasteArgs(ArgList, 0);
|
|
if (do_hook(ODD_SERVER_STUFF_LIST, "%s %s %s", from ? from : "*", comm, ArgList[0]))
|
|
{
|
|
if (from)
|
|
say("Odd server stuff: \"%s %s\" (%s)", comm, ArgList[0], from);
|
|
else
|
|
say("Odd server stuff: \"%s %s\"", comm, ArgList[0]);
|
|
}
|
|
}
|
|
static void p_rpong (char *from, char **ArgList)
|
|
{
|
|
if (!ArgList[3])
|
|
{
|
|
PasteArgs(ArgList, 0);
|
|
say("RPONG %s (from %s)", ArgList[0], from);
|
|
}
|
|
else
|
|
{
|
|
time_t delay = now - atol(ArgList[3]);
|
|
|
|
say("Pingtime %s - %s : %s ms (total delay: %ld s)",
|
|
from, ArgList[1], ArgList[2], delay);
|
|
}
|
|
}
|
|
|
|
|
|
protocol_command rfc1459[] = {
|
|
{ "ADMIN", NULL, NULL, 0, 0, 0},
|
|
{ "AUTHENTICATE", p_authenticate, NULL, 0, 0, 0},
|
|
{ "AWAY", NULL, NULL, 0, 0, 0},
|
|
{ "CAP", p_cap, NULL, 0, 0, 0},
|
|
{ "CONNECT", NULL, NULL, 0, 0, 0},
|
|
{ "ERROR", p_error, NULL, 0, 0, 0},
|
|
{ "ERROR:", p_error, NULL, 0, 0, 0},
|
|
{ "INFO", NULL, NULL, 0, 0, 0},
|
|
{ "INVITE", p_invite, NULL, 0, 0, 0},
|
|
{ "ISON", NULL, NULL, PROTO_NOQUOTE, 0, 0},
|
|
{ "JOIN", p_channel, NULL, PROTO_DEPREC, 0, 0},
|
|
{ "KICK", p_kick, NULL, 0, 0, 0},
|
|
{ "KILL", p_kill, NULL, 0, 0, 0},
|
|
{ "LINKS", NULL, NULL, 0, 0, 0},
|
|
{ "LIST", NULL, NULL, 0, 0, 0},
|
|
{ "MODE", p_mode, NULL, 0, 0, 0},
|
|
{ "NAMES", NULL, NULL, 0, 0, 0},
|
|
{ "NICK", p_nick, NULL, PROTO_NOQUOTE, 0, 0},
|
|
{ "NOTICE", parse_notice, NULL, 0, 0, 0},
|
|
{ "OPER", NULL, NULL, 0, 0, 0},
|
|
{ "PART", p_part, NULL, PROTO_DEPREC, 0, 0},
|
|
{ "PASS", NULL, NULL, 0, 0, 0},
|
|
{ "PING", p_ping, NULL, 0, 0, 0},
|
|
{ "PONG", p_pong, NULL, 0, 0, 0},
|
|
{ "PRIVMSG", p_privmsg, NULL, 0, 0, 0},
|
|
{ "QUIT", p_quit, NULL, PROTO_DEPREC, 0, 0},
|
|
{ "REHASH", NULL, NULL, 0, 0, 0},
|
|
{ "RESTART", NULL, NULL, 0, 0, 0},
|
|
{ "RPONG", p_rpong, NULL, 0, 0, 0},
|
|
{ "SERVER", NULL, NULL, PROTO_NOQUOTE, 0, 0},
|
|
{ "SILENCE", p_silence, NULL, 0, 0, 0},
|
|
{ "SQUIT", NULL, NULL, 0, 0, 0},
|
|
{ "STATS", NULL, NULL, 0, 0, 0},
|
|
{ "SUMMON", NULL, NULL, 0, 0, 0},
|
|
{ "TIME", NULL, NULL, 0, 0, 0},
|
|
{ "TOPIC", p_topic, NULL, 0, 0, 0},
|
|
{ "TRACE", NULL, NULL, 0, 0, 0},
|
|
{ "USER", NULL, NULL, 0, 0, 0},
|
|
{ "USERHOST", NULL, NULL, PROTO_NOQUOTE, 0, 0},
|
|
{ "USERS", NULL, NULL, 0, 0, 0},
|
|
{ "VERSION", NULL, NULL, 0, 0, 0},
|
|
{ "WALLOPS", p_wallops, NULL, 0, 0, 0},
|
|
{ "WHO", NULL, NULL, PROTO_NOQUOTE, 0, 0},
|
|
{ "WHOIS", NULL, NULL, 0, 0, 0},
|
|
{ "WHOWAS", NULL, NULL, 0, 0, 0},
|
|
{ NULL, NULL, NULL, 0, 0, 0}
|
|
};
|
|
#define NUMBER_OF_COMMANDS (sizeof(rfc1459) / sizeof(protocol_command)) - 2;
|
|
int num_protocol_cmds = -1;
|
|
|
|
BUILT_IN_COMMAND(debugmsg)
|
|
{
|
|
int i;
|
|
unsigned long total = 0;
|
|
for (i = 0; rfc1459[i].command; i++)
|
|
{
|
|
put_it("DEBUG_MSG: %10s[%03lu] # %ld -> %ld bytes", rfc1459[i].command, i, rfc1459[i].count, rfc1459[i].bytes);
|
|
total += rfc1459[i].bytes;
|
|
}
|
|
put_it("DEBUG_MSG: Total bytes received %ld", total);
|
|
}
|
|
|
|
void parse_server(char *orig_line)
|
|
{
|
|
char *from,
|
|
*comm,
|
|
*end;
|
|
int numeric;
|
|
char *line = NULL;
|
|
int len = 0;
|
|
char **ArgList;
|
|
char copy[BIG_BUFFER_SIZE+1];
|
|
char *TrueArgs[MAXPARA + 1] = {NULL};
|
|
|
|
#ifdef WANT_DLL
|
|
RawDll *raw = NULL;
|
|
#endif
|
|
int loc;
|
|
int cnt;
|
|
|
|
if (num_protocol_cmds == -1)
|
|
num_protocol_cmds = NUMBER_OF_COMMANDS;
|
|
|
|
|
|
if (!orig_line || !*orig_line)
|
|
return;
|
|
|
|
len = strlen(orig_line);
|
|
|
|
end = len + orig_line;
|
|
if (*--end == '\n')
|
|
*end-- = 0;
|
|
if (*end == '\r')
|
|
*end-- = 0;
|
|
|
|
if (x_debug & DEBUG_INBOUND)
|
|
yell("[%d] <- [%s]", get_server_read(from_server), orig_line);
|
|
|
|
if (*orig_line == ':')
|
|
{
|
|
if (!do_hook(RAW_IRC_LIST, "%s", orig_line + 1))
|
|
return;
|
|
}
|
|
else if (!do_hook(RAW_IRC_LIST, "* %s", orig_line))
|
|
return;
|
|
|
|
if (inbound_line_mangler)
|
|
{
|
|
len = strlen(orig_line) * 3;
|
|
line = alloca(len + 1);
|
|
strcpy(line, orig_line);
|
|
if (mangle_line(line, inbound_line_mangler, len) > len)
|
|
yell("mangle_line truncated its result. Ack.");
|
|
}
|
|
else
|
|
line = orig_line;
|
|
|
|
ArgList = TrueArgs;
|
|
|
|
strncpy(copy, line, BIG_BUFFER_SIZE);
|
|
BreakArgs(line, &from, ArgList, 0);
|
|
|
|
/* XXXX - I don't think 'from' can be null here. */
|
|
if (!(comm = (*ArgList++)) || !from || !*ArgList)
|
|
return; /* Serious protocol violation -- ByeBye */
|
|
|
|
/* Check for egregiously bad nicknames */
|
|
#define islegal(c) (((c) >= 'A' && (c) <= '~') || \
|
|
((c) >= '0' && (c) <= '9') || (c) == '*' || (c & 0x80))
|
|
|
|
if (*from && (!islegal(*from) || strchr(from, ',')))
|
|
{
|
|
rfc1459_odd(from, comm, ArgList);
|
|
return;
|
|
}
|
|
|
|
#ifdef WANT_TCL
|
|
if (check_tcl_raw(copy, comm))
|
|
return;
|
|
#endif
|
|
|
|
#ifdef WANT_DLL
|
|
if ((raw = find_raw_proc(comm, ArgList)))
|
|
if ((raw->func(comm, from, FromUserHost, ArgList)))
|
|
return;
|
|
#endif
|
|
|
|
#if 0
|
|
if (translation)
|
|
{
|
|
unsigned char *q, *p;
|
|
int i = 0;
|
|
q = ArgList[0];
|
|
while (q && *q)
|
|
{
|
|
for (p = q; *p; p++)
|
|
*p = transToClient[(int)*p];
|
|
q = ArgList[++i];
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
* I reformatted these in may '96 by using the output of /stats m
|
|
* from a few busy servers. They are arranged so that the most
|
|
* common types are high on the list (to save the average number
|
|
* of compares.) I will be doing more testing in the future on
|
|
* a live client to see if this is a reasonable order.
|
|
*/
|
|
if ((numeric = atoi(comm)) > 0) /* numbered_command can't handle -ves */
|
|
numbered_command(from, numeric, ArgList);
|
|
else
|
|
{
|
|
find_fixed_array_item((void *)rfc1459, sizeof(protocol_command),
|
|
num_protocol_cmds + 1, comm, &cnt, &loc);
|
|
|
|
if (cnt < 0 && rfc1459[loc].inbound_handler)
|
|
rfc1459[loc].inbound_handler(from, ArgList);
|
|
else
|
|
rfc1459_odd(from, comm, ArgList);
|
|
rfc1459[loc].bytes += len;
|
|
rfc1459[loc].count++;
|
|
}
|
|
FromUserHost = empty_string;
|
|
from_server = -1;
|
|
}
|