/*
* 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 Michael Sandrof.
* Copyright (c) 1991, 1992 Troy Rollo.
* Copyright (c) 1992-2004 Matthew R. Green.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include "irc.h"
IRCII_RCSID("@(#)$eterna: parse.c,v 1.89 2004/01/06 06:06:35 mrg Exp $");
#include "server.h"
#include "names.h"
#include "vars.h"
#include "ctcp.h"
#include "hook.h"
#include "edit.h"
#include "ignore.h"
#include "whois.h"
#include "lastlog.h"
#include "ircaux.h"
#include "funny.h"
#include "crypt.h"
#include "ircterm.h"
#include "flood.h"
#include "window.h"
#include "screen.h"
#include "output.h"
#include "numbers.h"
#include "parse.h"
#include "notify.h"
#define STRING_CHANNEL '+'
#define MULTI_CHANNEL '#'
#define LOCAL_CHANNEL '&'
#define SAFE_CHANNEL '!'
#define MAXPARA 15 /* Taken from the ircd */
static void BreakArgs(u_char *, u_char **, u_char **);
static void p_linreply(u_char **);
static void p_ping(u_char **);
static void p_topic(u_char *, u_char **);
static void p_wall(u_char *, u_char **);
static void p_wallops(u_char *, u_char **);
static void p_privmsg(u_char *, u_char **);
static void p_quit(u_char *, u_char **);
static void p_pong(u_char *, u_char **);
static void p_error(u_char *, u_char **);
static void p_channel(u_char *, u_char **);
static void p_invite(u_char *, u_char **);
static void p_server_kill(u_char *, u_char **);
static void p_nick(u_char *, u_char **);
static void p_mode(u_char *, u_char **);
static void p_kick(u_char *, u_char **);
static void p_part(u_char *, u_char **);
/*
* joined_nick: the nickname of the last person who joined the current
* channel
*/
u_char *joined_nick = (u_char *) 0;
/* public_nick: nick of the last person to send a message to your channel */
u_char *public_nick = (u_char *) 0;
/* User and host information from server 2.7 */
u_char *FromUserHost = (u_char *) 0;
/* doing a PRIVMSG */
int doing_privmsg = 0;
/*
* 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
is_channel(to)
u_char *to;
{
int version;
if (to == 0)
return (0);
version = get_server_version(from_server);
if (version == ServerICB)
return (my_stricmp(to, get_server_icbgroup(from_server)) == 0);
else
return ((version < Server2_7 && (isdigit(*to) || (*to == STRING_CHANNEL) || *to == '-'))
|| (version > Server2_5 && *to == MULTI_CHANNEL)
|| (version > Server2_7 && *to == LOCAL_CHANNEL)
|| (version > Server2_8 && *to == STRING_CHANNEL)
|| (version > Server2_9 && *to == SAFE_CHANNEL));
}
u_char *
PasteArgs(Args, StartPoint)
u_char **Args;
int StartPoint;
{
int i;
for (; StartPoint; Args++, StartPoint--)
if (!*Args)
return (u_char *) 0;
for (i = 0; Args[i] && Args[i+1]; i++)
Args[i][my_strlen(Args[i])] = ' ';
Args[1] = (u_char *) 0;
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 arguements
* that are there. Re-written by phone, dec 1992.
*/
static void
BreakArgs(Input, Sender, OutPut)
u_char *Input;
u_char **Sender;
u_char **OutPut;
{
u_char *s = Input,
*t;
int ArgCount = 0;
/*
* Get sender from :sender and user@host if :nick!user@host
*/
FromUserHost = (u_char *) 0;
if (*Input == ':')
{
u_char *tmp;
*Input++ = '\0';
if ((s = (u_char *) my_index(Input, ' ')) != (u_char *) 0)
*s++ = '\0';
*Sender = Input;
if ((tmp = (u_char *) my_index(*Sender, '!')) != (u_char *) 0)
{
*tmp++ = '\0';
FromUserHost = tmp;
}
}
else
*Sender = empty_string;
if (!s)
return;
for (;;)
{
while (*s == ' ')
*s++ = '\0';
if (!*s)
break;
if (*s == ':')
{
for (t = s; *t; t++)
*t = *(t + 1);
OutPut[ArgCount++] = s;
break;
}
OutPut[ArgCount++] = s;
if (ArgCount >= MAXPARA)
break;
for (; *s != ' ' && *s; s++)
;
}
OutPut[ArgCount] = (u_char *) 0;
}
/* beep_em: Not hard to figure this one out */
void
beep_em(beeps)
int beeps;
{
int cnt,
i;
for (cnt = beeps, i = 0; i < cnt; i++)
term_beep();
}
/* in response to a TOPIC message from the server */
static void
p_topic(from, ArgList)
u_char *from,
**ArgList;
{
int flag;
if (!from)
return;
flag = double_ignore(from, FromUserHost, IGNORE_CRAP);
if (flag == IGNORED)
return;
save_message_from();
if (!ArgList[1])
{
message_from((u_char *) 0, LOG_CRAP);
if (do_hook(TOPIC_LIST, "%s * %s", from, ArgList[0]))
say("%s has changed the topic to %s", from, ArgList[0]);
}
else
{
message_from(ArgList[0], LOG_CRAP);
if (do_hook(TOPIC_LIST, "%s %s %s", from, ArgList[0], ArgList[1]))
say("%s has changed the topic on channel %s to %s",
from, ArgList[0], ArgList[1]);
}
restore_message_from();
}
static void
p_linreply(ArgList)
u_char **ArgList;
{
PasteArgs(ArgList, 0);
say("%s", ArgList[0]);
}
static void
p_wall(from, ArgList)
u_char *from,
**ArgList;
{
int flag,
level;
u_char *line;
u_char *high;
if (!from)
return;
PasteArgs(ArgList, 0);
if (!(line = ArgList[0]))
return;
flag = double_ignore(from, FromUserHost, IGNORE_WALLS);
save_message_from();
message_from(from, LOG_WALL);
if (flag != IGNORED)
{
if (flag == HIGHLIGHTED)
high = &highlight_char;
else
high = empty_string;
if ((flag != DONT_IGNORE) && (ignore_usernames & IGNORE_WALLS)
&& !FromUserHost)
add_to_whois_queue(from, whois_ignore_walls, "%s",line);
else
{
level = set_lastlog_msg_level(LOG_WALL);
if (check_flooding(from,
get_server_nickname(parsing_server_index),
WALL_FLOOD, line) && do_hook(WALL_LIST, "%s %s",
from, line))
put_it("%s#%s#%s %s", high, from, high, line);
if (beep_on_level & LOG_WALL)
beep_em(1);
set_lastlog_msg_level(level);
}
}
restore_message_from();
}
static void
p_wallops(from, ArgList)
u_char *from,
**ArgList;
{
int flag, level;
u_char *line;
if (!from)
return;
if (!(line = PasteArgs(ArgList, 0)))
return;
flag = double_ignore(from, FromUserHost, IGNORE_WALLOPS);
level = set_lastlog_msg_level(LOG_WALLOP);
save_message_from();
message_from(from, LOG_WALLOP);
if (my_index(from, '.'))
{
u_char *high;
if (flag != IGNORED)
{
if (flag == HIGHLIGHTED)
high = &highlight_char;
else
high = empty_string;
if (do_hook(WALLOP_LIST, "%s S %s", from, line))
put_it("%s!%s!%s %s", high, from, high, line);
if (beep_on_level & LOG_WALLOP)
beep_em(1);
}
}
else
{
if (get_int_var(USER_WALLOPS_VAR))
{
if ((flag != DONT_IGNORE) && (check_flooding(from, get_server_nickname(parsing_server_index), WALLOP_FLOOD, line)))
add_to_whois_queue(from, whois_new_wallops, "%s", line);
}
else if (my_strcmp(from, get_server_nickname(get_window_server(0))) != 0)
put_it("!%s! %s", from, line);
}
set_lastlog_msg_level(level);
restore_message_from();
}
/*ARGSUSED*/
void
whoreply(from, ArgList)
u_char **ArgList,
*from;
{
static u_char format[40];
static int last_width = -1;
int ok = 1;
u_char *channel,
*user,
*host,
*server,
*nick,
*status,
*name;
int i;
FILE *fip;
u_char buf_data[BUFSIZ];
if (last_width != get_int_var(CHANNEL_NAME_WIDTH_VAR))
{
if ((last_width = get_int_var(CHANNEL_NAME_WIDTH_VAR)) != 0)
snprintf(CP(format), sizeof format, "%%-%u.%us %%-9s %%-3s %%s@%%s (%%s)",
(u_char) last_width,
(u_char) last_width);
else
my_strcpy(format, "%s\t%-9s %-3s %s@%s (%s)");
}
i = 0;
channel = user = host = server = nick = status = name = empty_string;
if (ArgList[i])
channel = ArgList[i++];
if (ArgList[i])
user = ArgList[i++];
if (ArgList[i])
host = ArgList[i++];
if (ArgList[i])
server = ArgList[i++];
if (ArgList[i])
nick = ArgList[i++];
if (ArgList[i])
status = ArgList[i++];
PasteArgs(ArgList, i);
if (*status == 'S') /* this only true for the header WHOREPLY */
{
channel = UP("Channel");
if (((who_mask & WHO_FILE) == 0) || (fopen (CP(who_file), "r")))
{
if (do_hook(WHO_LIST, "%s %s %s %s %s %s", channel,
nick, status, user, host, ArgList[6]))
put_it(CP(format), channel, nick, status, user,
host, ArgList[6]);
return;
}
}
if (ArgList[i])
name = ArgList[i];
if (who_mask)
{
if (who_mask & WHO_HERE)
ok = ok && (*status == 'H');
if (who_mask & WHO_AWAY)
ok = ok && (*status == 'G');
if (who_mask & WHO_OPS)
ok = ok && (*(status + 1) == '*');
if (who_mask & WHO_LUSERS)
ok = ok && (*(status + 1) != '*');
if (who_mask & WHO_CHOPS)
ok = ok && ((*(status + 1) == '@') ||
(*(status + 2) == '@'));
if (who_mask & WHO_NAME)
ok = ok && wild_match(who_name, user);
if (who_mask & WHO_NICK)
ok = ok && wild_match(who_nick, nick);
if (who_mask & WHO_HOST)
ok = ok && wild_match(who_host, host);
if (who_mask & WHO_REAL)
ok = ok && wild_match(who_real, name);
if (who_mask & WHO_SERVER)
ok = ok && wild_match(who_server, server);
if (who_mask & WHO_FILE)
{
ok = 0;
cannot_open = (u_char *) 0;
if ((fip = fopen(CP(who_file), "r")) != (FILE *) 0)
{
while (fgets ((char *)buf_data, BUFSIZ, fip) !=
(char *) 0)
{
buf_data[my_strlen(buf_data)-1] = '\0';
ok = ok || wild_match(buf_data, nick);
}
fclose (fip);
} else
cannot_open = who_file;
}
}
if (ok)
{
if (do_hook(WHO_LIST, "%s %s %s %s %s %s", channel, nick,
status, user, host, name))
{
if (get_int_var(SHOW_WHO_HOPCOUNT_VAR))
put_it(CP(format), channel, nick, status, user, host,
name);
else
{
u_char *tmp;
if ((tmp = (u_char *) my_index(name, ' ')) !=
(u_char *) 0)
tmp++;
else
tmp = name;
put_it(CP(format), channel, nick, status, user, host,
tmp);
}
}
}
}
static void
p_privmsg(from, Args)
u_char *from,
**Args;
{
int level,
flag,
list_type,
flood_type,
log_type;
u_char ignore_type;
u_char *ptr,
*to;
u_char *high;
int no_flood;
if (!from)
return;
PasteArgs(Args, 1);
to = Args[0];
ptr = Args[1];
if (!to || !ptr)
return;
save_message_from();
if (is_channel(to))
{
malloc_strcpy(&public_nick, from);
if (!is_on_channel(to, parsing_server_index, from))
{
log_type = LOG_PUBLIC;
ignore_type = IGNORE_PUBLIC;
list_type = PUBLIC_MSG_LIST;
flood_type = PUBLIC_FLOOD;
}
else
{
log_type = LOG_PUBLIC;
ignore_type = IGNORE_PUBLIC;
if (is_current_channel(to, parsing_server_index, 0))
list_type = PUBLIC_LIST;
else
list_type = PUBLIC_OTHER_LIST;
flood_type = PUBLIC_FLOOD;
}
message_from(to, log_type);
}
else
{
flood_type = MSG_FLOOD;
if (my_stricmp(to, get_server_nickname(parsing_server_index)))
{
log_type = LOG_WALL;
ignore_type = IGNORE_WALLS;
list_type = MSG_GROUP_LIST;
}
else
{
log_type = LOG_MSG;
ignore_type = IGNORE_MSGS;
list_type = MSG_LIST;
}
message_from(from, log_type);
}
flag = double_ignore(from, FromUserHost, ignore_type);
switch (flag)
{
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(parsing_server_index));
goto out;
case HIGHLIGHTED:
high = &highlight_char;
break;
default:
high = empty_string;
break;
}
level = set_lastlog_msg_level(log_type);
ptr = do_ctcp(from, to, ptr);
if (!ptr || !*ptr)
goto out;
if ((flag != DONT_IGNORE) && (ignore_usernames & ignore_type) && !FromUserHost)
add_to_whois_queue(from, whois_ignore_msgs, "%s", ptr);
else
{
no_flood = check_flooding(from, to, flood_type, ptr);
if (ctcp_was_crypted == 0 || do_hook(ENCRYPTED_PRIVMSG_LIST,"%s %s %s",from, to, ptr))
{
switch (list_type)
{
case PUBLIC_MSG_LIST:
if (no_flood && do_hook(list_type, "%s %s %s", from, to, ptr))
put_it("%s(%s/%s)%s %s", high, from, to, high, ptr);
break;
case MSG_GROUP_LIST:
if (no_flood && do_hook(list_type, "%s %s %s", from, to, ptr))
put_it("%s-%s:%s-%s %s", high, from, to, high, ptr);
break;
case MSG_LIST:
if (!no_flood)
break;
malloc_strcpy(&recv_nick, from);
if (away_set)
beep_em(get_int_var(BEEP_WHEN_AWAY_VAR));
if (do_hook(list_type, "%s %s", from, ptr))
{
if (away_set)
{
time_t t;
u_char *msg = (u_char *) 0;
size_t len = my_strlen(ptr) + 20;
t = time((time_t *) 0);
msg = (u_char *) new_malloc(len);
snprintf(CP(msg), len, "%s <%.16s>", ptr, ctime(&t));
put_it("%s*%s*%s %s", high, from, high, msg);
new_free(&msg);
}
else
put_it("%s*%s*%s %s", high, from, high, ptr);
}
break;
case PUBLIC_LIST:
if (get_int_var(MAKE_NOTICE_MSG_VAR))
doing_privmsg = 1;
if (no_flood && do_hook(list_type, "%s %s %s", from,
to, ptr))
put_it("%s<%s>%s %s", high, from, high, ptr);
doing_privmsg = 0;
break;
case PUBLIC_OTHER_LIST:
if (get_int_var(MAKE_NOTICE_MSG_VAR))
doing_privmsg = 1;
if (no_flood && do_hook(list_type, "%s %s %s", from,
to, ptr))
put_it("%s<%s:%s>%s %s", high, from, to, high,
ptr);
doing_privmsg = 0;
break;
}
if (beep_on_level & log_type)
beep_em(1);
}
}
set_lastlog_msg_level(level);
out:
restore_message_from();
}
/*ARGSUSED*/
static void
p_quit(from, ArgList)
u_char *from,
**ArgList;
{
int one_prints = 0;
u_char *chan;
u_char *Reason;
int flag;
if (!from)
return;
flag = double_ignore(from, FromUserHost, IGNORE_CRAP);
save_message_from();
if (flag != IGNORED)
{
PasteArgs(ArgList, 0);
Reason = ArgList[0] ? ArgList[0] : (u_char *) "?";
for (chan = walk_channels(from, 1, parsing_server_index); chan; chan = walk_channels(from, 0, -1))
{
message_from(chan, LOG_CRAP);
if (do_hook(CHANNEL_SIGNOFF_LIST, "%s %s %s", chan, from, Reason))
one_prints = 1;
}
if (one_prints)
{
message_from(what_channel(from, parsing_server_index), LOG_CRAP);
if (do_hook(SIGNOFF_LIST, "%s %s", from, Reason))
say("Signoff: %s (%s)", from, Reason);
}
}
message_from((u_char *) 0, LOG_CURRENT);
remove_from_channel((u_char *) 0, from, parsing_server_index);
notify_mark(from, 0, 0);
restore_message_from();
}
/*ARGSUSED*/
static void
p_pong(from, ArgList)
u_char *from,
**ArgList;
{
int flag;
if (!from)
return;
flag = double_ignore(from, FromUserHost, IGNORE_CRAP);
if (flag == IGNORED)
return;
if (ArgList[0])
say("%s: PONG received from %s", ArgList[0], from);
}
/*ARGSUSED*/
static void
p_error(from, ArgList)
u_char *from,
**ArgList;
{
PasteArgs(ArgList, 0);
if (!ArgList[0])
return;
say("%s", ArgList[0]);
}
static void
p_channel(from, ArgList)
u_char *from;
u_char **ArgList;
{
int join;
u_char *channel;
int flag;
u_char *s, *ov = NULL;
int chan_oper = 0, chan_voice = 0;
if (!from)
return;
flag = double_ignore(from, FromUserHost, IGNORE_CRAP);
if (my_strcmp(ArgList[0], zero))
{
join = 1;
channel = ArgList[0];
/*
* this \007 should be \a but a lot of compilers are
* broken. *sigh* -mrg
*/
if ((ov = s = my_index(channel, '\007')))
{
*s = '\0';
ov++;
while (*++s)
{
if (*s == 'o')
chan_oper = 1;
if (*s == 'v')
chan_voice = 1;
}
}
malloc_strcpy(&joined_nick, from);
}
else
{
channel = zero;
join = 0;
}
if (!my_stricmp(from, get_server_nickname(parsing_server_index)))
{
if (join)
{
add_channel(channel, 0, parsing_server_index, CHAN_JOINED, (ChannelList *) 0);
if (get_server_version(parsing_server_index) == Server2_5)
send_to_server("NAMES %s", channel);
send_to_server("MODE %s", channel);
}
else
remove_channel(channel, parsing_server_index);
}
else
{
save_message_from();
message_from(channel, LOG_CRAP);
if (join)
add_to_channel(channel, from, parsing_server_index, chan_oper, chan_voice);
else
remove_from_channel(channel, from, parsing_server_index);
restore_message_from();
}
if (join)
{
if (!get_channel_oper(channel, parsing_server_index))
in_on_who = 1;
save_message_from();
message_from(channel, LOG_CRAP);
if (flag != IGNORED && do_hook(JOIN_LIST, "%s %s %s", from,
channel, ov ? ov : (u_char *) ""))
{
if (FromUserHost)
if (ov && *ov)
say("%s (%s) has joined channel %s +%s", from,
FromUserHost, channel, ov);
else
say("%s (%s) has joined channel %s", from,
FromUserHost, channel);
else
if (ov && *ov)
say("%s has joined channel %s +%s", from,
channel, ov);
else
say("%s has joined channel %s", from, channel);
}
restore_message_from();
in_on_who = 0;
}
}
static void
p_invite(from, ArgList)
u_char *from,
**ArgList;
{
u_char *high;
int flag;
if (!from)
return;
flag = double_ignore(from, FromUserHost, IGNORE_INVITES);
switch (flag)
{
case IGNORED:
if (get_int_var(SEND_IGNORE_MSG_VAR))
send_to_server("NOTICE %s :%s is ignoring you",
from, get_server_nickname(parsing_server_index));
return;
case HIGHLIGHTED:
high = &highlight_char;
break;
default:
high = empty_string;
break;
}
if (ArgList[0] && ArgList[1])
{
if ((flag != DONT_IGNORE) && (ignore_usernames & IGNORE_INVITES)
&& !FromUserHost)
add_to_whois_queue(from, whois_ignore_invites,
"%s", ArgList[1]);
else
{
save_message_from();
message_from(from, LOG_CRAP);
if (do_hook(INVITE_LIST, "%s %s", from, ArgList[1]))
say("%s%s%s invites you to channel %s", high,
from, high, ArgList[1]);
restore_message_from();
malloc_strcpy(&invite_channel, ArgList[1]);
malloc_strcpy(&recv_nick, from);
}
}
}
static void
p_server_kill(from, ArgList)
u_char *from,
**ArgList;
{
/*
* this is so bogus checking for a server name having a '.'
* in it - phone, april 1993.
*/
if (my_index(from, '.'))
say("You have been rejected by server %s", from);
else
say("You have been killed by operator %s %s", from,
ArgList[1] ? ArgList[1] : (u_char *) "(No Reason Given)");
close_server(parsing_server_index, empty_string);
window_check_servers();
if (!connected_to_server)
say("Use /SERVER to reconnect to a server");
}
static void
p_ping(ArgList)
u_char **ArgList;
{
PasteArgs(ArgList, 0);
send_to_server("PONG :%s", ArgList[0]);
}
static void
p_nick(from, ArgList)
u_char *from,
**ArgList;
{
int one_prints = 0,
its_me = 0;
u_char *chan;
u_char *line;
int flag;
if (!from)
return;
flag = double_ignore(from, FromUserHost, IGNORE_CRAP);
line = ArgList[0];
if (my_stricmp(from, get_server_nickname(parsing_server_index)) == 0){
if (parsing_server_index == primary_server)
malloc_strcpy(&nickname, line);
set_server_nickname(parsing_server_index, line);
its_me = 1;
}
save_message_from();
if (flag != IGNORED)
{
for (chan = walk_channels(from, 1, parsing_server_index); chan;
chan = walk_channels(from, 0, -1))
{
message_from(chan, LOG_CRAP);
if (do_hook(CHANNEL_NICK_LIST, "%s %s %s", chan, from, line))
one_prints = 1;
}
if (one_prints)
{
if (its_me)
message_from((u_char *) 0, LOG_CRAP);
else
message_from(what_channel(from, parsing_server_index), LOG_CRAP);
if (do_hook(NICKNAME_LIST, "%s %s", from, line))
say("%s is now known as %s", from, line);
}
}
rename_nick(from, line, parsing_server_index);
if (my_stricmp(from, line))
{
message_from((u_char *) 0, LOG_CURRENT);
notify_mark(from, 0, 0);
notify_mark(line, 1, 0);
}
restore_message_from();
}
static void
p_mode(from, ArgList)
u_char *from,
**ArgList;
{
u_char *channel;
u_char *line;
int flag;
if (!from)
return;
flag = double_ignore(from, FromUserHost, IGNORE_CRAP);
PasteArgs(ArgList, 1);
channel = ArgList[0];
line = ArgList[1];
save_message_from();
message_from(channel, LOG_CRAP);
if (channel && line)
{
if (is_channel(channel))
{
if (flag != IGNORED && do_hook(MODE_LIST, "%s %s %s",
from, channel, line))
say("Mode change \"%s\" on channel %s by %s",
line, channel, from);
update_channel_mode(channel, parsing_server_index, line);
}
else
{
if (flag != IGNORED && do_hook(MODE_LIST, "%s %s %s",
from, channel, line))
say("Mode change \"%s\" for user %s by %s",
line, channel, from);
update_user_mode(line);
}
update_all_status();
}
restore_message_from();
}
static void
p_kick(from, ArgList)
u_char *from,
**ArgList;
{
u_char *channel,
*who,
*comment;
if (!from)
return;
channel = ArgList[0];
who = ArgList[1];
comment = ArgList[2];
if (channel && who)
{
save_message_from();
message_from(channel, LOG_CRAP);
if (my_stricmp(who, get_server_nickname(parsing_server_index)) == 0)
{
if (comment && *comment)
{
if (do_hook(KICK_LIST, "%s %s %s %s", who,
from, channel, comment))
say("You have been kicked off channel %s by %s (%s)",
channel, from, comment);
}
else
{
if (do_hook(KICK_LIST, "%s %s %s", who, from,
channel))
say("You have been kicked off channel %s by %s",
channel, from);
}
remove_channel(channel, parsing_server_index);
update_all_status();
}
else
{
if (comment && *comment)
{
if (do_hook(KICK_LIST, "%s %s %s %s", who,
from, channel, comment))
say("%s has been kicked off channel %s by %s (%s)",
who, channel, from, comment);
}
else
{
if (do_hook(KICK_LIST, "%s %s %s", who, from,
channel))
say("%s has been kicked off channel %s by %s",
who, channel, from);
}
remove_from_channel(channel, who, parsing_server_index);
}
restore_message_from();
}
}
static void
p_part(from, ArgList)
u_char *from,
**ArgList;
{
u_char *channel;
u_char *comment;
int flag;
if (!from)
return;
flag = double_ignore(from, FromUserHost, IGNORE_CRAP);
channel = ArgList[0];
if (!is_on_channel(channel, parsing_server_index, from))
return;
comment = ArgList[1];
if (!comment)
comment = empty_string;
in_on_who = 1;
if (flag != IGNORED)
{
save_message_from();
message_from(channel, LOG_CRAP);
if (do_hook(LEAVE_LIST, "%s %s %s", from, channel, comment))
{
if (comment && *comment != '\0')
say("%s has left channel %s (%s)", from, channel, comment);
else
say("%s has left channel %s", from, channel);
}
restore_message_from();
}
if (my_stricmp(from, get_server_nickname(parsing_server_index)) == 0)
remove_channel(channel, parsing_server_index);
else
remove_from_channel(channel, from, parsing_server_index);
in_on_who = 0;
}
/*
* parse_server: parses messages from the server, doing what should be done
* with them
*/
void
parse_server(line)
u_char *line;
{
server_list[parsing_server_index].parse_server(line);
}
void
irc2_parse_server(line)
u_char *line;
{
u_char *from,
*comm,
*end,
*copy = (u_char *) 0;
int numeric;
u_char **ArgList;
u_char *TrueArgs[MAXPARA + 1];
if ((u_char *) 0 == line)
return;
end = my_strlen(line) + line;
if (*--end == '\n')
*end-- = '\0';
if (*end == '\r')
*end-- = '\0';
if (*line == ':')
{
if (!do_hook(RAW_IRC_LIST, "%s", line + 1))
return;
}
else if (!do_hook(RAW_IRC_LIST, "%s %s", "*", line))
return;
malloc_strcpy(©, line);
ArgList = TrueArgs;
BreakArgs(copy, &from, ArgList);
if (!(comm = (*ArgList++)))
return; /* Empty line from server - ByeBye */
/*
* XXX!!!
* this should fail on '1xxx'!!!
*/
if (0 != (numeric = my_atoi(comm)))
numbered_command(from, numeric, ArgList);
else if (my_strcmp(comm, "NAMREPLY") == 0)
funny_namreply(from, ArgList);
else if (my_strcmp(comm, "WHOREPLY") == 0)
whoreply(from, ArgList);
else if (my_strcmp(comm, "NOTICE") == 0)
parse_notice(from, ArgList);
/* everything else is handled locally */
else if (my_strcmp(comm, "PRIVMSG") == 0)
p_privmsg(from, ArgList);
else if (my_strcmp(comm, "JOIN") == 0)
p_channel(from, ArgList);
else if (my_strcmp(comm, "PART") == 0)
p_part(from, ArgList);
else if (my_strcmp(comm, "CHANNEL") == 0)
p_channel(from, ArgList);
else if (my_strcmp(comm, "QUIT") == 0)
p_quit(from, ArgList);
else if (my_strcmp(comm, "WALL") == 0)
p_wall(from, ArgList);
else if (my_strcmp(comm, "WALLOPS") == 0)
p_wallops(from, ArgList);
else if (my_strcmp(comm, "LINREPLY") == 0)
p_linreply(ArgList);
else if (my_strcmp(comm, "PING") == 0)
p_ping(ArgList);
else if (my_strcmp(comm, "TOPIC") == 0)
p_topic(from, ArgList);
else if (my_strcmp(comm, "PONG") == 0)
p_pong(from, ArgList);
else if (my_strcmp(comm, "INVITE") == 0)
p_invite(from, ArgList);
else if (my_strcmp(comm, "NICK") == 0)
p_nick(from, ArgList);
else if (my_strcmp(comm, "KILL") == 0)
p_server_kill(from, ArgList);
else if (my_strcmp(comm, "MODE") == 0)
p_mode(from, ArgList);
else if (my_strcmp(comm, "KICK") == 0)
p_kick(from, ArgList);
else if (my_strcmp(comm, "ERROR") == 0)
p_error(from, ArgList);
else if (my_strcmp(comm, "ERROR:") == 0) /* Server bug makes this a must */
p_error(from, ArgList);
else
{
PasteArgs(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]);
}
new_free(©);
}
syntax highlighted by Code2HTML, v. 0.9.1