2069 lines
47 KiB
C
2069 lines
47 KiB
C
/*
|
|
* names.c: This here is used to maintain a list of all the people currently
|
|
* on your channel. Seems to work
|
|
*
|
|
*
|
|
* Written By Michael Sandrof
|
|
*
|
|
* Copyright(c) 1990
|
|
*
|
|
* See the COPYRIGHT file, or do a HELP IRCII COPYRIGHT
|
|
*/
|
|
|
|
|
|
#include "irc.h"
|
|
static char cvsrevision[] = "$Id$";
|
|
CVS_REVISION(names_c)
|
|
#include "struct.h"
|
|
|
|
#include "ircaux.h"
|
|
#include "names.h"
|
|
#include "flood.h"
|
|
#include "window.h"
|
|
#include "screen.h"
|
|
#include "server.h"
|
|
#include "lastlog.h"
|
|
#include "list.h"
|
|
#include "output.h"
|
|
#include "userlist.h"
|
|
#include "timer.h"
|
|
#include "input.h"
|
|
#include "hook.h"
|
|
#include "parse.h"
|
|
#include "whowas.h"
|
|
#include "misc.h"
|
|
#include "vars.h"
|
|
#include "keys.h"
|
|
#include "tcl_bx.h"
|
|
#include "status.h"
|
|
#include "userlist.h"
|
|
#include "hash2.h"
|
|
#include "cset.h"
|
|
#include "gui.h"
|
|
#define MAIN_SOURCE
|
|
#include "modval.h"
|
|
|
|
extern AJoinList *ajoin_list;
|
|
|
|
|
|
static void add_to_mode_list (char *, int, char *);
|
|
static void check_mode_list_join (char *, int);
|
|
static void show_channel (ChannelList *);
|
|
static void clear_channel (ChannelList *);
|
|
char *BX_recreate_mode (ChannelList *);
|
|
static void clear_mode_list (int);
|
|
static void apply_channel_modes (char *, char *, ChannelList *);
|
|
void BX_clear_bans (ChannelList *);
|
|
|
|
static char mode_str[] = "aciklmnprstzR";
|
|
char new_channel_format[BIG_BUFFER_SIZE];
|
|
|
|
static struct modelist
|
|
{
|
|
char *chan;
|
|
int server;
|
|
char *mode;
|
|
struct modelist *next;
|
|
} *mode_list = NULL;
|
|
|
|
|
|
static struct joinlist
|
|
{
|
|
char *chan;
|
|
int server,
|
|
gotinfo,
|
|
winref;
|
|
struct timeval tv;
|
|
struct joinlist *next;
|
|
} *join_list = NULL;
|
|
|
|
/*
|
|
* check_channel_type: checks if the given channel is a normal #channel
|
|
* or a new !channel from irc2.10. If the latter, then it reformats it
|
|
* a bit into a more user-friendly form.
|
|
*/
|
|
char * check_channel_type (char *channel)
|
|
{
|
|
if (*channel != '!' || strlen(channel) < 6)
|
|
return channel;
|
|
|
|
snprintf(new_channel_format, sizeof new_channel_format, "[%.6s] %s", channel, channel + 6);
|
|
return new_channel_format;
|
|
}
|
|
|
|
|
|
/* clear_channel: erases all entries in a nick list for the given channel */
|
|
static void clear_channel(ChannelList *chan)
|
|
{
|
|
NickList *Nick, *n;
|
|
while((Nick = next_nicklist(chan, NULL)))
|
|
{
|
|
n = find_nicklist_in_channellist(Nick->nick, chan, REMOVE_FROM_LIST);
|
|
add_to_whowas_buffer(n, chan->channel, NULL, NULL);
|
|
}
|
|
clear_nicklist_hashtable(chan);
|
|
chan->totalnicks = 0;
|
|
}
|
|
|
|
ChannelList *BX_lookup_channel(const char *channel, int server, int unlink)
|
|
{
|
|
register ChannelList *chan = NULL,
|
|
*last = NULL;
|
|
if (server <= -2)
|
|
return NULL;
|
|
if (server == -1)
|
|
{
|
|
server = primary_server;
|
|
if (server == -1)
|
|
return NULL;
|
|
}
|
|
if (!channel || !*channel || !strcmp(channel, "*"))
|
|
channel = get_current_channel_by_refnum(0);
|
|
|
|
chan = get_server_channels(server);
|
|
if (!chan || !channel || !*channel)
|
|
return NULL;
|
|
while (chan)
|
|
{
|
|
if (chan->channel && !my_stricmp(chan->channel, channel))
|
|
{
|
|
if (unlink == CHAN_UNLINK)
|
|
{
|
|
if (last)
|
|
last->next = chan->next;
|
|
else
|
|
set_server_channels(server, chan->next);
|
|
}
|
|
break;
|
|
}
|
|
last = chan;
|
|
chan = chan->next;
|
|
}
|
|
return chan;
|
|
}
|
|
|
|
extern void set_waiting_channel (int i)
|
|
{
|
|
Window *tmp = NULL;
|
|
|
|
|
|
while ((traverse_all_windows(&tmp)))
|
|
if (tmp->server == i && tmp->current_channel)
|
|
{
|
|
#if 0
|
|
if (tmp->bind_channel)
|
|
tmp->waiting_channel = tmp->current_channel;
|
|
else
|
|
new_free(&tmp->current_channel);
|
|
tmp->current_channel = NULL;
|
|
#else
|
|
if (tmp->waiting_channel)
|
|
continue;
|
|
tmp->waiting_channel = tmp->current_channel;
|
|
tmp->current_channel = NULL;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
/* if the user is on the given channel, it returns 1. */
|
|
extern int BX_im_on_channel (char *channel, int server)
|
|
{
|
|
|
|
return (channel?(lookup_channel(channel, server, 0) ? 1 : 0) : 0);
|
|
}
|
|
|
|
void add_userhost_to_channel (char *channel, char *nick, int server, char *userhost)
|
|
{
|
|
NickList *new;
|
|
ChannelList *chan;
|
|
|
|
if ((chan = lookup_channel(channel, server, 0)) != NULL)
|
|
if ((new = find_nicklist_in_channellist(nick, chan, 0)))
|
|
malloc_strcpy(&new->host, userhost);
|
|
}
|
|
|
|
|
|
/*
|
|
* add_channel: adds the named channel to the channel list. If the channel
|
|
* is already in the list, then the channel gets cleaned, and ready for use
|
|
* again. The added channel becomes the current channel as well.
|
|
*/
|
|
ChannelList * BX_add_channel(char *channel, int server, int refnum)
|
|
{
|
|
ChannelList *new = NULL;
|
|
WhowasChanList *whowaschan;
|
|
|
|
|
|
if ((new = lookup_channel(channel, server, CHAN_NOUNLINK)) != NULL)
|
|
{
|
|
new->connected = 1;
|
|
new->mode = 0;
|
|
new->limit = 0;
|
|
new_free(&new->s_mode);
|
|
new->server = server;
|
|
new->window = current_window;
|
|
new->refnum = new->window->refnum;
|
|
malloc_strcpy(&(new->channel), channel);
|
|
clear_channel(new);
|
|
clear_bans(new);
|
|
}
|
|
else
|
|
{
|
|
Window *tmp = NULL;
|
|
if (!(whowaschan = check_whowas_chan_buffer(channel, refnum, 1)))
|
|
{
|
|
|
|
new = (ChannelList *) new_malloc(sizeof(ChannelList));
|
|
new->connected = 1;
|
|
get_time(&new->channel_create);
|
|
malloc_strcpy(&(new->channel), channel);
|
|
add_to_list((List **)&new->csets, (List *)create_csets_for_channel(channel));
|
|
}
|
|
else
|
|
{
|
|
|
|
new = whowaschan->channellist;
|
|
new_free(&whowaschan->channel);
|
|
new_free((char **)&whowaschan);
|
|
new_free(&(new->key));
|
|
new->mode = 0;
|
|
new_free(&new->s_mode);
|
|
new->limit = new->i_mode = 0;
|
|
clear_channel(new);
|
|
clear_bans(new);
|
|
}
|
|
if ((!new->window || !(tmp = get_window_by_refnum(new->window->refnum))) && current_window)
|
|
{
|
|
new->window = tmp ? tmp : current_window;
|
|
new->refnum = new->window->refnum;
|
|
}
|
|
new->server = server;
|
|
new->flags.got_modes = new->flags.got_who = new->flags.got_bans = 1;
|
|
get_time(&new->join_time);
|
|
add_server_channels(server, new);
|
|
}
|
|
new->have_op = 0;
|
|
new->voice = 0;
|
|
new->hop = 0;
|
|
|
|
if (!is_current_channel(channel, server, 0))
|
|
{
|
|
Window *tmp = NULL;
|
|
|
|
while ((traverse_all_windows(&tmp)))
|
|
{
|
|
if (tmp->server != from_server)
|
|
continue;
|
|
if (tmp->name && (!strcmp(tmp->name, "oper_view") || !strcmp(tmp->name, "debug")))
|
|
continue;
|
|
if (!tmp->waiting_channel && !tmp->bind_channel)
|
|
continue;
|
|
if (tmp->bind_channel && tmp->server == from_server)
|
|
{
|
|
char *p, *q;
|
|
p = LOCAL_COPY(tmp->bind_channel);
|
|
while ((q = next_in_comma_list(p, &p)))
|
|
{
|
|
if (!q || !*q)
|
|
break;
|
|
if (my_stricmp(q, channel))
|
|
continue;
|
|
set_current_channel_by_refnum(tmp->refnum, channel);
|
|
new->window = tmp;
|
|
new->refnum = tmp->refnum;
|
|
update_all_windows();
|
|
return new;
|
|
}
|
|
}
|
|
if (tmp->waiting_channel && tmp->server == from_server)
|
|
{
|
|
char *p, *q;
|
|
p = LOCAL_COPY(tmp->waiting_channel);
|
|
while ((q = next_in_comma_list(p, &p)))
|
|
{
|
|
if (!q || !*q)
|
|
break;
|
|
if (my_stricmp(q, channel))
|
|
continue;
|
|
set_current_channel_by_refnum(tmp->refnum, channel);
|
|
new->window = tmp;
|
|
new->refnum = tmp->refnum;
|
|
new_free(&tmp->waiting_channel);
|
|
update_all_windows();
|
|
return new;
|
|
}
|
|
}
|
|
}
|
|
set_current_channel_by_refnum(new->window?new->window->refnum:0, channel);
|
|
}
|
|
update_all_windows();
|
|
return new;
|
|
}
|
|
|
|
/*
|
|
* add_to_channel: adds the given nickname to the given channel. If the
|
|
* nickname is already on the channel, nothing happens. If the channel is
|
|
* not on the channel list, nothing happens (although perhaps the channel
|
|
* should be addded to the list? but this should never happen)
|
|
*/
|
|
ChannelList *BX_add_to_channel(char *channel, char *nick, int server, int oper, int voice, char *userhost, char *server1, char *away, int serv_split, int server_hops)
|
|
{
|
|
NickList *new = NULL;
|
|
ChannelList *chan = NULL;
|
|
WhowasList *whowas;
|
|
|
|
int ischop = oper;
|
|
|
|
|
|
if (!(*channel == '*'))
|
|
{
|
|
if ((chan = lookup_channel(channel, server, CHAN_NOUNLINK)))
|
|
{
|
|
if (*nick == '+')
|
|
{
|
|
nick++;
|
|
if (!my_stricmp(nick, get_server_nickname(server)))
|
|
{
|
|
check_mode_list_join(channel, server);
|
|
chan->voice = 1;
|
|
}
|
|
}
|
|
if (ischop && ischop != -1)
|
|
{
|
|
if (!my_stricmp(nick, get_server_nickname(server)))
|
|
{
|
|
check_mode_list_join(channel, server);
|
|
chan->have_op = 1;
|
|
}
|
|
}
|
|
if (!(new = find_nicklist_in_channellist(nick, chan, 0)))
|
|
{
|
|
|
|
if (!(whowas = check_whowas_buffer(nick, userhost, channel)))
|
|
{
|
|
new = (NickList *) new_malloc(sizeof(NickList));
|
|
|
|
new->idle_time = new->kicktime =
|
|
new->doptime = new->nicktime =
|
|
new->floodtime = new->bantime = now;
|
|
|
|
new->joincount = 1;
|
|
malloc_strcpy(&(new->nick), nick);
|
|
#ifdef WANT_USERLIST
|
|
new->userlist = lookup_userlevelc("*", userhost, channel, NULL);
|
|
new->shitlist = nickinshit(nick, userhost);
|
|
#endif
|
|
new->serverhops = server_hops;
|
|
}
|
|
else
|
|
{
|
|
new = whowas->nicklist;
|
|
new_free(&whowas->channel);
|
|
new_free(&whowas->server1);
|
|
new_free(&whowas->server2);
|
|
new_free((char **)&whowas);
|
|
malloc_strcpy(&(new->nick), nick);
|
|
|
|
new->idle_time = new->kicktime =
|
|
new->doptime = new->nicktime =
|
|
new->floodtime = new->bantime = now;
|
|
|
|
new->sent_reop = new->sent_deop =
|
|
new->bancount = new->nickcount =
|
|
new->dopcount = new->kickcount =
|
|
new->floodcount = new->ip_count =
|
|
new->sent_voice = new->sent_kick = 0;
|
|
new->flags = 0;
|
|
new->serverhops = server_hops;
|
|
new->next = NULL;
|
|
}
|
|
if (server1)
|
|
malloc_strcpy(&new->server, server1);
|
|
add_nicklist_to_channellist(new, chan);
|
|
update_stats(JOINLIST, new, chan, serv_split);
|
|
}
|
|
malloc_strcpy(&new->host, userhost);
|
|
if (ischop > 0)
|
|
new->flags |= NICK_CHANOP;
|
|
if (voice > 0)
|
|
new->flags |= NICK_VOICE;
|
|
if (away)
|
|
{
|
|
if (strchr(away,'H'))
|
|
new->flags &= ~NICK_AWAY;
|
|
else
|
|
new->flags |= NICK_AWAY;
|
|
|
|
if (strchr(away, '*'))
|
|
new->flags |= NICK_IRCOP;
|
|
|
|
if (strchr(away, '%'))
|
|
new->flags |= NICK_HALFOP;
|
|
}
|
|
}
|
|
else if (check_whowas_chan_buffer(channel, -1, 0))
|
|
{
|
|
if (*nick == '+') nick++;
|
|
new = (NickList *) new_malloc(sizeof(NickList));
|
|
new->idle_time = new->kicktime =
|
|
new->doptime = new->nicktime =
|
|
new->floodtime = new->bantime = now;
|
|
new->joincount = 1;
|
|
malloc_strcpy(&(new->nick), nick);
|
|
malloc_strcpy(&new->host, userhost);
|
|
new->serverhops = server_hops;
|
|
#ifdef WANT_USERLIST
|
|
new->userlist = lookup_userlevelc("*", userhost, channel, NULL);
|
|
new->shitlist = nickinshit(nick, userhost);
|
|
#endif
|
|
if (ischop > 0)
|
|
new->flags |= NICK_CHANOP;
|
|
if (voice > 0)
|
|
new->flags |= NICK_VOICE;
|
|
if (away)
|
|
{
|
|
if (strchr(away,'H'))
|
|
new->flags &= ~NICK_AWAY;
|
|
else
|
|
new->flags |= NICK_AWAY;
|
|
|
|
if (strchr(away, '*'))
|
|
new->flags |= NICK_IRCOP;
|
|
|
|
if (strchr(away, '%'))
|
|
new->flags |= NICK_HALFOP;
|
|
}
|
|
if (server1)
|
|
malloc_strcpy(&new->server, server1);
|
|
add_to_whowas_buffer(new, channel, server1, NULL);
|
|
}
|
|
}
|
|
return chan;
|
|
}
|
|
|
|
char *BX_get_channel_key (char *channel, int server)
|
|
{
|
|
ChannelList *tmp;
|
|
|
|
if ((tmp = lookup_channel(channel, server, 0)) != NULL)
|
|
return (tmp->key ? tmp->key : empty_string);
|
|
return empty_string;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* recreate_mode: converts the bitmap representation of a channels mode into
|
|
* a string
|
|
*
|
|
* This malloces what it returns, but nothing that calls this function
|
|
* is expecting to have to free anything. Therefore, this function
|
|
* should not malloc what it returns. (hop)
|
|
*
|
|
* but this leads to horrible race conditions, so we add a bit to
|
|
* the channel structure, and cache the string value of mode, and
|
|
* the u_long value of the cached string, so that each channel only
|
|
* has one copy of the string. -mrg, june '94.
|
|
*/
|
|
char *BX_recreate_mode(ChannelList *chan)
|
|
{
|
|
int mode_pos = 0,
|
|
mode;
|
|
static char *s;
|
|
char buffer[BIG_BUFFER_SIZE + 1];
|
|
|
|
chan->i_mode = chan->mode;
|
|
buffer[0] = 0;
|
|
s = buffer;
|
|
mode = chan->mode;
|
|
|
|
if (!mode)
|
|
return NULL;
|
|
while (mode)
|
|
{
|
|
if (mode % 2)
|
|
*s++ = mode_str[mode_pos];
|
|
mode /= 2;
|
|
mode_pos++;
|
|
}
|
|
if (chan->key && *chan->key)
|
|
{
|
|
*s++ = ' ';
|
|
strcpy(s, chan->key);
|
|
s += strlen(chan->key);
|
|
}
|
|
if (chan->limit)
|
|
sprintf(s, " %d", chan->limit);
|
|
else
|
|
*s = 0;
|
|
|
|
malloc_strcpy(&chan->s_mode, buffer);
|
|
return chan->s_mode;
|
|
}
|
|
#ifdef COMPRESS_MODES
|
|
/* some structs to help along the process, NickList is way too much of a memory
|
|
hog */
|
|
|
|
typedef struct _UserChanModes {
|
|
struct _UserChanModes *next;
|
|
char *nick;
|
|
int o_ed;
|
|
int v_ed;
|
|
int deo_ed;
|
|
int dev_ed;
|
|
int b_ed;
|
|
int deb_ed;
|
|
} UserChanModes;
|
|
|
|
/*
|
|
* compress_modes: This will return a list of modes which removes duplicates
|
|
*
|
|
* for instance:
|
|
* +oooo Jordy Jordy Jordy Jordy
|
|
*
|
|
* would return:
|
|
* +o Jordy
|
|
*
|
|
* +oo-oo Sheik Jordy Sheik Jordy
|
|
*
|
|
* would return:
|
|
* -oo Sheik jordy
|
|
*
|
|
* also if *!*@* isn't banned on the channel
|
|
* -b *!*@*
|
|
*
|
|
* will return NULL
|
|
*
|
|
* This is a frigging ugly function and because I'm not going to sit and
|
|
* learn every shortcut function in irc, I don't care :)
|
|
*
|
|
* Written by Jordy (jordy@wserv.com)
|
|
*/
|
|
char *BX_do_compress_modes(ChannelList *chan, int server, char *channel, char *modes) {
|
|
int add = 0,
|
|
isbanned = 0,
|
|
isopped = 0,
|
|
isvoiced = 0,
|
|
mod = -1;
|
|
char *tmp = NULL,
|
|
*rest = NULL,
|
|
nmodes[16],
|
|
nargs[100];
|
|
UserChanModes *ucm = NULL,
|
|
*tucm = NULL;
|
|
BanList *tbl = NULL;
|
|
NickList *tnl = NULL;
|
|
|
|
/* now, modes contains the actual modes, and rest contains the arguments
|
|
to those modes */
|
|
|
|
if (!chan || !(modes = next_arg(modes, &rest)))
|
|
return NULL;
|
|
|
|
*nmodes = 0;
|
|
*nargs = 0;
|
|
for (; *modes && (strlen(nmodes) + 2) < sizeof nmodes; modes++)
|
|
{
|
|
isbanned = isopped = isvoiced = 0;
|
|
switch (*modes)
|
|
{
|
|
case '+':
|
|
add = 1;
|
|
break;
|
|
case '-':
|
|
add = 0;
|
|
break;
|
|
case 'o':
|
|
if (!(tmp = next_arg(rest, &rest)))
|
|
break;
|
|
if (!(tucm = (UserChanModes *)find_in_list((List **)&ucm, tmp, 0)))
|
|
{
|
|
tucm = (UserChanModes *) alloca(sizeof(UserChanModes));
|
|
memset(tucm, 0, sizeof(UserChanModes));
|
|
tucm->nick = LOCAL_COPY(tmp);
|
|
add_to_list((List **)&ucm, (List *)tucm);
|
|
}
|
|
|
|
tnl = find_nicklist_in_channellist(tmp, chan, 0);
|
|
if (tnl && (nick_isop(tnl) || tucm->o_ed))
|
|
isopped = 1;
|
|
else if (tnl)
|
|
isopped = 0;
|
|
|
|
if (add && !isopped)
|
|
{
|
|
tucm->o_ed = 1;
|
|
tucm->deo_ed = 0;
|
|
}
|
|
else if (!add && isopped)
|
|
{
|
|
tucm->o_ed = 0;
|
|
tucm->deo_ed = 1;
|
|
}
|
|
break;
|
|
case 'v':
|
|
if (!(tmp = next_arg(rest, &rest)))
|
|
break;
|
|
if (!(tucm = (UserChanModes *)find_in_list((List **)&ucm, tmp, 0)))
|
|
{
|
|
tucm = (UserChanModes *) alloca(sizeof(UserChanModes));
|
|
memset(tucm, 0, sizeof(UserChanModes));
|
|
tucm->nick = LOCAL_COPY(tmp);
|
|
add_to_list((List **)&ucm, (List *)tucm);
|
|
}
|
|
|
|
tnl = find_nicklist_in_channellist(tmp, chan, 0);
|
|
if (tnl && (nick_isvoice(tnl) || tucm->v_ed))
|
|
isvoiced = 1;
|
|
else if (tnl)
|
|
isvoiced = 0;
|
|
|
|
if (add && !isvoiced)
|
|
{
|
|
tucm->v_ed = 1;
|
|
tucm->dev_ed = 0;
|
|
}
|
|
else if (!add && isvoiced)
|
|
{
|
|
tucm->v_ed = 0;
|
|
tucm->dev_ed = 1;
|
|
}
|
|
break;
|
|
case 'b':
|
|
if (!(tmp = next_arg(rest, &rest)))
|
|
break;
|
|
if (!(tucm = (UserChanModes *)find_in_list((List **)&ucm, tmp, 0)))
|
|
{
|
|
tucm = (UserChanModes *) alloca(sizeof(UserChanModes));
|
|
memset(tucm, 0, sizeof(UserChanModes));
|
|
tucm->nick = LOCAL_COPY(tmp);
|
|
add_to_list((List **)&ucm, (List *)tucm);
|
|
}
|
|
if (!tucm->b_ed)
|
|
{
|
|
for (tbl = chan->bans; tbl && !isbanned; tbl = tbl->next)
|
|
{
|
|
if (!my_stricmp(tbl->ban, tmp))
|
|
isbanned = 1;
|
|
else
|
|
isbanned = 0;
|
|
}
|
|
}
|
|
if (add && !isbanned)
|
|
{
|
|
tucm->b_ed = 1;
|
|
tucm->deb_ed = 0;
|
|
}
|
|
else if (!add && isbanned)
|
|
{
|
|
tucm->b_ed = 0;
|
|
tucm->deb_ed = 1;
|
|
}
|
|
break;
|
|
|
|
case 'l':
|
|
case 'k':
|
|
tmp = next_arg(rest, &rest);
|
|
|
|
if (add)
|
|
{
|
|
if (mod == 1)
|
|
{
|
|
strcat(nmodes, "-");
|
|
strextend(nmodes, *modes, 1);
|
|
}
|
|
else
|
|
{
|
|
strcat(nmodes, "+");
|
|
strextend(nmodes, *modes, 1);
|
|
mod = 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!mod)
|
|
{
|
|
strcat(nmodes, "+");
|
|
strextend(nmodes, *modes, 1);
|
|
}
|
|
else
|
|
{
|
|
strcat(nmodes, "-");
|
|
strextend(nmodes, *modes, 1);
|
|
mod = 0;
|
|
}
|
|
}
|
|
if (tmp && *tmp)
|
|
strmopencat(nargs, sizeof(nargs)-1, space, tmp, NULL);
|
|
break;
|
|
|
|
case 'i':
|
|
case 's':
|
|
case 'n':
|
|
case 't':
|
|
case 'm':
|
|
{
|
|
if (add)
|
|
{
|
|
if (mod == 1)
|
|
strextend(nmodes, *modes, 1);
|
|
else
|
|
{
|
|
strextend(nmodes, '+', 1);
|
|
strextend(nmodes, *modes, 1);
|
|
mod = 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!mod)
|
|
strextend(nmodes, *modes, 1);
|
|
else
|
|
{
|
|
strextend(nmodes, '-', 1);
|
|
strextend(nmodes, *modes, 1);
|
|
mod = 0;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* modes which can be done multiple times are added here */
|
|
|
|
for (tucm = ucm; tucm && (strlen(nmodes) + 2) < sizeof nmodes;
|
|
tucm = tucm->next)
|
|
{
|
|
if (tucm->o_ed)
|
|
{
|
|
if (mod == 1)
|
|
strcat(nmodes, "o");
|
|
else
|
|
{
|
|
strcat(nmodes, "+o");
|
|
mod = 1;
|
|
}
|
|
strmopencat(nargs, sizeof(nargs)-1, space, tucm->nick, NULL);
|
|
}
|
|
else if (tucm->deo_ed)
|
|
{
|
|
if (!mod)
|
|
strcat(nmodes, "o");
|
|
else
|
|
{
|
|
strcat(nmodes, "-o");
|
|
mod = 0;
|
|
}
|
|
strmopencat(nargs, sizeof(nargs)-1, space, tucm->nick, NULL);
|
|
}
|
|
if (tucm->v_ed)
|
|
{
|
|
if (mod == 1)
|
|
strcat(nmodes, "v");
|
|
else
|
|
{
|
|
strcat(nmodes, "+v");
|
|
mod = 1;
|
|
}
|
|
strmopencat(nargs, sizeof(nargs)-1, space, tucm->nick, NULL);
|
|
}
|
|
else if (tucm->dev_ed)
|
|
{
|
|
if (!mod)
|
|
strcat(nmodes, "v");
|
|
else
|
|
{
|
|
strcat(nmodes, "-v");
|
|
mod = 0;
|
|
}
|
|
strmopencat(nargs, sizeof(nargs)-1, space, tucm->nick, NULL);
|
|
}
|
|
if (tucm->b_ed)
|
|
{
|
|
if (mod == 1)
|
|
strcat(nmodes, "b");
|
|
else
|
|
{
|
|
strcat(nmodes, "+b");
|
|
mod = 1;
|
|
}
|
|
strmopencat(nargs, sizeof(nargs)-1, space, tucm->nick, NULL);
|
|
}
|
|
else if (tucm->deb_ed)
|
|
{
|
|
if (!mod)
|
|
strcat(nmodes, "b");
|
|
else
|
|
{
|
|
strcat(nmodes, "-b");
|
|
mod = 0;
|
|
}
|
|
strmopencat(nargs, sizeof(nargs)-1, space, tucm->nick, NULL);
|
|
}
|
|
}
|
|
|
|
if (strlen(nmodes) || strlen(nargs))
|
|
return m_sprintf("%s%s", nmodes, nargs);
|
|
return NULL;
|
|
}
|
|
#endif
|
|
|
|
int BX_got_ops(int add, ChannelList *channel)
|
|
{
|
|
int have_op = 0;
|
|
register NickList *tmp;
|
|
int in_join = 0;
|
|
in_join = in_join_list(channel->channel, from_server);
|
|
if (add && add != channel->have_op && !in_join)
|
|
{
|
|
have_op = channel->have_op = add;
|
|
#ifdef WANT_USERLIST
|
|
for(tmp = next_nicklist(channel, NULL); tmp; tmp = next_nicklist(channel, tmp))
|
|
check_auto(channel->channel,tmp, channel);
|
|
#endif
|
|
if ((get_server_version(from_server) == Server2_8hybrid6))
|
|
send_to_server("MODE %s e", channel->channel);
|
|
}
|
|
else if (!add && add != channel->have_op && !in_join)
|
|
{
|
|
for(tmp = next_nicklist(channel, NULL); tmp; tmp = next_nicklist(channel, tmp))
|
|
tmp->sent_reop = tmp->sent_deop = tmp->sent_voice = tmp->sent_kick = 0;
|
|
}
|
|
return have_op;
|
|
}
|
|
|
|
/*
|
|
* apply_channel_modes
|
|
*
|
|
* This looks at a set of channel mode changes from a MODE command and
|
|
* applies them to the Channel structure (old decifer_mode()).
|
|
*/
|
|
static void apply_channel_modes(char *from, char *mode_str,
|
|
ChannelList *channel)
|
|
{
|
|
|
|
register char *person;
|
|
int add = 0;
|
|
int splitter = 0;
|
|
char *rest;
|
|
|
|
NickList *ThisNick = NULL;
|
|
BanList *new;
|
|
unsigned int value = 0;
|
|
int its_me = 0;
|
|
|
|
if (!(mode_str = next_arg(mode_str, &rest)))
|
|
return;
|
|
|
|
its_me = !my_stricmp(from, get_server_nickname(from_server)) ? 1 : 0;
|
|
splitter = wild_match("*.*.*", from);
|
|
|
|
for (; *mode_str; mode_str++)
|
|
{
|
|
switch (*mode_str)
|
|
{
|
|
case '+':
|
|
add = 1;
|
|
value = 0;
|
|
break;
|
|
case '-':
|
|
add = 0;
|
|
value = 0;
|
|
break;
|
|
case 'p':
|
|
value = MODE_PRIVATE;
|
|
break;
|
|
case 'l':
|
|
value = MODE_LIMIT;
|
|
if (add)
|
|
{
|
|
char *limit = next_arg(rest, &rest);
|
|
|
|
if (limit)
|
|
{
|
|
channel->limit = atoi(limit);
|
|
|
|
/* Setting +l 0 is the same as setting -l */
|
|
if (channel->limit == 0)
|
|
add = 0;
|
|
}
|
|
else
|
|
{
|
|
/* +l with no argument - broken server, just ignore
|
|
* it. */
|
|
value = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
channel->limit = 0;
|
|
}
|
|
break;
|
|
case 'a':
|
|
value = MODE_ANONYMOUS;
|
|
break;
|
|
case 't':
|
|
value = MODE_TOPIC;
|
|
break;
|
|
case 'i':
|
|
value = MODE_INVITE;
|
|
break;
|
|
case 'n':
|
|
value = MODE_MSGS;
|
|
break;
|
|
case 'r':
|
|
value = MODE_REGISTERED;
|
|
break;
|
|
case 's':
|
|
value = MODE_SECRET;
|
|
break;
|
|
case 'm':
|
|
value = MODE_MODERATED;
|
|
break;
|
|
case 'R':
|
|
value = MODE_RESTRICTED;
|
|
break;
|
|
case 'z':
|
|
value = MODE_Z;
|
|
break;
|
|
case 'h':
|
|
if (!(person = next_arg(rest, &rest)))
|
|
break;
|
|
if (!my_stricmp(person, get_server_nickname(from_server)))
|
|
{
|
|
channel->hop = add;
|
|
}
|
|
if ((ThisNick = find_nicklist_in_channellist(person, channel, 0)))
|
|
{
|
|
/* ThisNick->halfop=add;*/
|
|
if (add)
|
|
ThisNick->flags |= NICK_HALFOP;
|
|
else
|
|
ThisNick->flags &= ~NICK_HALFOP;
|
|
}
|
|
ThisNick = find_nicklist_in_channellist(from, channel, 0);
|
|
update_stats(add ? MODEHOPLIST: MODEDEHOPLIST, ThisNick, channel, splitter);
|
|
break;
|
|
case 'o':
|
|
{
|
|
if (!(person = next_arg(rest, &rest))) /* av 2.9 */
|
|
person = get_server_nickname(from_server);
|
|
if (!my_stricmp(person, get_server_nickname(from_server)))
|
|
{
|
|
got_ops(add, channel);
|
|
channel->have_op = add;
|
|
if (add)
|
|
do_hook(CHANOP_LIST, "%s", channel->channel);
|
|
}
|
|
ThisNick = find_nicklist_in_channellist(from, channel, 0);
|
|
update_stats(add ? MODEOPLIST: MODEDEOPLIST, ThisNick, channel, splitter);
|
|
if ((ThisNick = find_nicklist_in_channellist(person, channel, 0)))
|
|
{
|
|
if (add)
|
|
ThisNick->flags |= NICK_CHANOP;
|
|
else
|
|
ThisNick->flags &= ~NICK_CHANOP;
|
|
if (add)
|
|
{
|
|
if (ThisNick->sent_reop)
|
|
ThisNick->sent_reop--;
|
|
}
|
|
else if (ThisNick->sent_deop)
|
|
ThisNick->sent_deop--;
|
|
}
|
|
|
|
if (!its_me && channel->have_op)
|
|
{
|
|
if (add && splitter)
|
|
check_hack(person, channel, ThisNick, from);
|
|
#ifdef WANT_USERLIST
|
|
else if (!add)
|
|
check_prot(from, person, channel, NULL, ThisNick);
|
|
else if (ThisNick)
|
|
check_auto(channel->channel,ThisNick,channel);
|
|
#endif
|
|
}
|
|
break;
|
|
}
|
|
case 'c':
|
|
value = MODE_C;
|
|
if (add)
|
|
{
|
|
char *pass;
|
|
pass = next_arg(rest, &rest);
|
|
if (pass)
|
|
malloc_strcpy(&channel->chanpass, pass);
|
|
}
|
|
else
|
|
new_free(&channel->chanpass);
|
|
break;
|
|
case 'k':
|
|
value = MODE_KEY;
|
|
if (add)
|
|
malloc_strcpy(&channel->key, next_arg(rest, &rest));
|
|
else
|
|
{
|
|
if (rest)
|
|
next_arg(rest, &rest);
|
|
|
|
new_free(&channel->key);
|
|
}
|
|
channel->i_mode = -1;
|
|
break;
|
|
case 'v':
|
|
if ((person = next_arg(rest, &rest)))
|
|
{
|
|
if ((ThisNick = find_nicklist_in_channellist(person, channel, 0)))
|
|
{
|
|
if (add)
|
|
ThisNick->flags |= NICK_VOICE;
|
|
else
|
|
ThisNick->flags &= ~NICK_VOICE;
|
|
if (add)
|
|
{
|
|
if (ThisNick->sent_voice)
|
|
ThisNick->sent_voice--;
|
|
}
|
|
else
|
|
ThisNick->sent_voice = 0;
|
|
}
|
|
if (!my_stricmp(person, get_server_nickname(from_server)))
|
|
channel->voice = add;
|
|
}
|
|
break;
|
|
case 'b':
|
|
if (!(person = next_arg(rest, &rest)))
|
|
break;
|
|
|
|
ThisNick = find_nicklist_in_channellist(from, channel, 0);
|
|
update_stats(add?MODEBANLIST:MODEUNBANLIST, ThisNick, channel, splitter);
|
|
if (add)
|
|
{
|
|
ThisNick = find_nicklist_in_channellist(person, channel, 0);
|
|
if (!(new = (BanList *)find_in_list((List **)&channel->bans, person, 0)) || my_stricmp(person, new->ban))
|
|
{
|
|
new = (BanList *) new_malloc(sizeof(BanList));
|
|
malloc_strcpy(&new->ban, person);
|
|
add_to_list((List **)&channel->bans, (List *)new);
|
|
}
|
|
new->sent_unban = 0;
|
|
if (!new->setby)
|
|
malloc_strcpy(&new->setby, from?from:get_server_name(from_server));
|
|
new->time = now;
|
|
#ifdef WANT_USERLIST
|
|
if (!its_me && channel->have_op)
|
|
check_prot(from, person, channel, new, ThisNick);
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
if ((new = (BanList *)remove_from_list((List **)&channel->bans, person)))
|
|
{
|
|
new_free(&new->setby);
|
|
new_free(&new->ban);
|
|
new_free((char **)&new);
|
|
}
|
|
}
|
|
break;
|
|
case 'e':
|
|
if (!(person = next_arg(rest, &rest)))
|
|
break;
|
|
|
|
ThisNick = find_nicklist_in_channellist(from, channel, 0);
|
|
update_stats(add?MODEEBANLIST:MODEUNEBANLIST, ThisNick, channel, splitter);
|
|
if (add)
|
|
{
|
|
ThisNick = find_nicklist_in_channellist(person, channel, 0);
|
|
if (!(new = (BanList *)find_in_list((List **)&channel->exemptbans, person, 0)) || my_stricmp(person, new->ban))
|
|
{
|
|
new = (BanList *) new_malloc(sizeof(BanList));
|
|
malloc_strcpy(&new->ban, person);
|
|
add_to_list((List **)&channel->exemptbans, (List *)new);
|
|
}
|
|
new->sent_unban = 0;
|
|
if (!new->setby)
|
|
malloc_strcpy(&new->setby, from?from:get_server_name(from_server));
|
|
new->time = now;
|
|
}
|
|
else
|
|
{
|
|
if ((new = (BanList *)remove_from_list((List **)&channel->exemptbans, person)))
|
|
{
|
|
new_free(&new->setby);
|
|
new_free(&new->ban);
|
|
new_free((char **)&new);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
if (add)
|
|
channel->mode |= value;
|
|
else
|
|
channel->mode &= ~value;
|
|
}
|
|
#ifdef WANT_USERLIST
|
|
check_shit(channel);
|
|
#endif
|
|
flush_mode_all(channel);
|
|
}
|
|
|
|
/*
|
|
* get_channel_mode: returns the current mode string for the given channel
|
|
*/
|
|
char *BX_get_channel_mode(char *channel, int server)
|
|
{
|
|
ChannelList *tmp;
|
|
|
|
if ((tmp = lookup_channel(channel, server, CHAN_NOUNLINK)))
|
|
return recreate_mode(tmp);
|
|
return empty_string;
|
|
}
|
|
|
|
char *BX_get_channel_bans(char *channel, int server, int type_mode)
|
|
{
|
|
ChannelList *tmp;
|
|
|
|
if ((tmp = lookup_channel(channel, server, CHAN_NOUNLINK)))
|
|
{
|
|
BanList *b;
|
|
char *temp = NULL;
|
|
switch(type_mode)
|
|
{
|
|
case 1: /* ban */
|
|
for (b = tmp->bans; b; b = b->next)
|
|
m_s3cat(&temp, space, b->ban);
|
|
break;
|
|
case 2: /* ban who time */
|
|
for (b = tmp->bans; b; b = b->next)
|
|
{
|
|
m_s3cat(&temp, space, b->ban);
|
|
m_s3cat(&temp, space, b->setby);
|
|
m_s3cat(&temp, space, ltoa(b->time));
|
|
}
|
|
break;
|
|
case 3: /* exemptions [ts4] */
|
|
for (b = tmp->exemptbans; b; b = b->next)
|
|
m_s3cat(&temp, space, b->ban);
|
|
break;
|
|
}
|
|
return temp;
|
|
}
|
|
return m_strdup(empty_string);
|
|
}
|
|
|
|
/*
|
|
* update_channel_mode: This will modify the mode for the given channel
|
|
* according the the new mode given.
|
|
*/
|
|
void update_channel_mode(char *from, char *channel, int server, char *mode, ChannelList *tmp)
|
|
{
|
|
if (!tmp && channel)
|
|
{
|
|
tmp = lookup_channel(channel, server, CHAN_NOUNLINK);
|
|
}
|
|
|
|
if (tmp)
|
|
{
|
|
apply_channel_modes(from, mode, tmp);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* is_channel_mode: returns the logical AND of the given mode with the
|
|
* channels mode. Useful for testing a channels mode
|
|
*/
|
|
int is_channel_mode(char *channel, int mode, int server_index)
|
|
{
|
|
ChannelList *tmp;
|
|
|
|
if ((tmp = lookup_channel(channel, server_index, CHAN_NOUNLINK)))
|
|
return (tmp->mode & mode);
|
|
return 0;
|
|
}
|
|
|
|
void BX_clear_bans(ChannelList *channel)
|
|
{
|
|
BanList *bans,
|
|
*next;
|
|
|
|
if (!channel)
|
|
return;
|
|
for (bans = channel->bans; bans; bans = next)
|
|
{
|
|
next = bans->next;
|
|
new_free(&bans->setby);
|
|
new_free(&bans->ban);
|
|
new_free((char **)&bans);
|
|
}
|
|
channel->bans = NULL;
|
|
for (bans = channel->exemptbans; bans; bans = next)
|
|
{
|
|
next = bans->next;
|
|
new_free(&bans->setby);
|
|
new_free(&bans->ban);
|
|
new_free((char **)&bans);
|
|
}
|
|
channel->exemptbans = NULL;
|
|
}
|
|
|
|
/* remove_channel()
|
|
*
|
|
* Removes the named channel from the channel list for the current context
|
|
* server. If the channel was the current channel for a window, this will
|
|
* select a new current channel if possible.
|
|
*
|
|
* Should be called in direct response to a message from the server indicating
|
|
* that we are no longer on the channel.
|
|
*/
|
|
void BX_remove_channel(const char *channel)
|
|
{
|
|
ChannelList *tmp;
|
|
|
|
if (*channel == '*')
|
|
return;
|
|
if ((tmp = lookup_channel(channel, from_server, CHAN_UNLINK)))
|
|
{
|
|
clear_bans(tmp);
|
|
clear_channel(tmp);
|
|
add_to_whowas_chan_buffer(tmp);
|
|
}
|
|
if (is_current_channel(channel, from_server, 1))
|
|
switch_channels(0, NULL);
|
|
|
|
xterm_settitle();
|
|
update_all_windows();
|
|
}
|
|
|
|
/*
|
|
* remove_from_channel: removes the given nickname from the given channel. If
|
|
* the nickname is not on the channel or the channel doesn't exist, nothing
|
|
* happens.
|
|
*/
|
|
void BX_remove_from_channel(char *channel, char *nick, int server, int netsplit, char *reason)
|
|
{
|
|
ChannelList *chan;
|
|
NickList *tmp = NULL;
|
|
extern char *last_split_server;
|
|
extern char *last_split_from;
|
|
char buf[BIG_BUFFER_SIZE+1];
|
|
char *server1 = NULL, *server2 = NULL;
|
|
|
|
if (netsplit && reason && *reason)
|
|
{
|
|
char *p = NULL;
|
|
strncpy(buf, reason, sizeof(buf)-1);
|
|
if ((p = strchr(buf, ' ')))
|
|
{
|
|
*p++ = '\0';
|
|
server2 = buf;
|
|
server1 = p;
|
|
}
|
|
if (server1 && !check_split_server(server1))
|
|
{
|
|
add_split_server(server1, server2, 0);
|
|
set_display_target(channel, LOG_CRAP);
|
|
malloc_strcpy(&last_split_server, server1);
|
|
malloc_strcpy(&last_split_from, server2);
|
|
if (do_hook(LLOOK_SPLIT_LIST, "%s %s", server2, server1))
|
|
{
|
|
char *s1, *s = NULL, *t = NULL;
|
|
if ((s = convert_to_keystr("WHOLEFT")))
|
|
t = LOCAL_COPY(s);
|
|
s = NULL;
|
|
if ((s1 = convert_to_keystr("CHANGE_TO_SPLIT")))
|
|
s = s1;
|
|
put_it("%s", convert_output_format(fget_string_var(FORMAT_NETSPLIT_FSET), "%s %s %s", update_clock(GET_TIME), server1, server2));
|
|
bitchsay("%s \002%s\002 to see who left \002%s\002 to change to [%s]", t ? "Press" : "", t ? t : "/wholeft", s ? s : "/server", server1);
|
|
}
|
|
reset_display_target();
|
|
}
|
|
}
|
|
|
|
if (channel)
|
|
{
|
|
if ((chan = lookup_channel(channel, server, CHAN_NOUNLINK)))
|
|
{
|
|
if ((tmp = find_nicklist_in_channellist(nick, chan, REMOVE_FROM_LIST)))
|
|
{
|
|
do_hook(NETSPLIT_LIST, "%d", netsplit);
|
|
add_to_whowas_buffer(tmp, channel, server1, server2);
|
|
if (netsplit)
|
|
{
|
|
if (server1 && strchr(server1, '*') && tmp->server)
|
|
server1 = tmp->server;
|
|
add_to_whosplitin_buffer(tmp, channel, server1, server2);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (chan = get_server_channels(server); chan; chan = chan->next)
|
|
{
|
|
if ((tmp = find_nicklist_in_channellist(nick, chan, REMOVE_FROM_LIST)))
|
|
{
|
|
add_to_whowas_buffer(tmp, chan->channel, server1, server2);
|
|
if (netsplit)
|
|
{
|
|
if (server1 && strchr(server1, '*') && tmp->server)
|
|
server1 = tmp->server;
|
|
add_to_whosplitin_buffer(tmp, chan->channel, server1, server2);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void handle_nickflood(char *old_nick, char *new_nick, register NickList *nick, register ChannelList *chan, int flood_time)
|
|
{
|
|
time_t floodtime = now - nick->bantime;
|
|
|
|
if ((!nick->bancount) || (nick->bancount && (floodtime > 3)))
|
|
{
|
|
if (!nick->sent_kick++)
|
|
send_to_server("KICK %s %s :\002Niq flood (%d nicks in %dsecs of %dsecs)\002", chan->channel, new_nick, get_cset_int_var(chan->csets, KICK_ON_NICKFLOOD_CSET), flood_time, get_cset_int_var(chan->csets, NICKFLOOD_TIME_CSET));
|
|
}
|
|
}
|
|
|
|
/*
|
|
* rename_nick: in response to a changed nickname, this looks up the given
|
|
* nickname on all you channels and changes it the new_nick
|
|
*/
|
|
void BX_rename_nick(char *old_nick, char *new_nick, int server)
|
|
{
|
|
register ChannelList *chan;
|
|
register NickList *tmp;
|
|
int t = 0;
|
|
|
|
|
|
for (chan = get_server_channels(server); chan; chan = chan->next)
|
|
{
|
|
if ((chan->server == server))
|
|
{
|
|
if ((tmp = find_nicklist_in_channellist(old_nick, chan, REMOVE_FROM_LIST)))
|
|
{
|
|
tmp->stat_nicks++;
|
|
if (chan->have_op && !isme(new_nick))
|
|
{
|
|
if (is_other_flood(chan, tmp, NICK_FLOOD, &t))
|
|
handle_nickflood(old_nick, new_nick, tmp, chan, t);
|
|
else if (get_cset_int_var(chan->csets, LAMELIST_CSET) && lame_list)
|
|
{
|
|
if (find_in_list((List **)&lame_list, new_nick, 0))
|
|
{
|
|
send_to_server("MODE %s -o+b %s %s!*@*", chan->channel, new_nick, new_nick);
|
|
send_to_server("KICK %s %s :\002Lame Nick detected\002", chan->channel, new_nick);
|
|
tmp->bancount++;
|
|
tmp->bantime = now;
|
|
}
|
|
}
|
|
}
|
|
check_orig_nick(new_nick);
|
|
xterm_settitle();
|
|
malloc_strcpy(&tmp->nick, new_nick);
|
|
add_nicklist_to_channellist(tmp, chan);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* is_on_channel: returns true if the given nickname is in the given channel,
|
|
* false otherwise. Also returns false if the given channel is not on the
|
|
* channel list.
|
|
*/
|
|
int BX_is_on_channel(char *channel, int server, char *nick)
|
|
{
|
|
ChannelList *chan;
|
|
|
|
if (nick && (chan = lookup_channel(channel, server, CHAN_NOUNLINK)) && chan->connected)
|
|
if (find_nicklist_in_channellist(nick, chan, 0))
|
|
return 1;
|
|
return 0;
|
|
}
|
|
|
|
int BX_is_chanop(char *channel, char *nick)
|
|
{
|
|
ChannelList *chan;
|
|
NickList *Nick;
|
|
|
|
if (nick && (chan = lookup_channel(channel, from_server, CHAN_NOUNLINK)))
|
|
{
|
|
if ((Nick = find_nicklist_in_channellist(nick, chan, 0)))
|
|
if (nick_isop(Nick))
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int BX_is_halfop(char *channel, char *nick)
|
|
{
|
|
ChannelList *chan;
|
|
NickList *Nick;
|
|
|
|
if (nick && (chan = lookup_channel(channel, from_server, CHAN_NOUNLINK)))
|
|
{
|
|
if ((Nick = find_nicklist_in_channellist(nick, chan, 0)))
|
|
if (nick_ishalfop(Nick))
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
char *is_chanoper(char *channel, char *nick)
|
|
{
|
|
ChannelList *chan;
|
|
NickList *Nick;
|
|
char *ret = NULL;
|
|
if (nick && (chan = lookup_channel(channel, from_server, CHAN_NOUNLINK)))
|
|
{
|
|
char *n;
|
|
while ((n = next_in_comma_list(nick, &nick)))
|
|
{
|
|
if (!n || !*n) break;
|
|
if ((Nick = find_nicklist_in_channellist(n, chan, 0)))
|
|
m_s3cat(&ret, space, nick_isop(Nick) ?one:zero);
|
|
else
|
|
m_s3cat(&ret, space, zero);
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
static void show_channel(ChannelList *chan)
|
|
{
|
|
NickList *tmp;
|
|
char *ptr, *s;
|
|
char buffer[BIG_BUFFER_SIZE * 10 + 1];
|
|
size_t nick_len = BIG_BUFFER_SIZE * 10;
|
|
int len = 0;
|
|
|
|
*buffer = 0;
|
|
s = recreate_mode(chan);
|
|
ptr = buffer;
|
|
|
|
for (tmp = next_nicklist(chan, NULL); tmp; tmp = next_nicklist(chan, tmp))
|
|
{
|
|
strlcpy(ptr, tmp->nick, nick_len);
|
|
if (tmp->host)
|
|
{
|
|
strlcat(ptr, "!", nick_len);
|
|
strlcat(ptr, tmp->host, nick_len);
|
|
}
|
|
strlcat(ptr, space, nick_len);
|
|
len = strlen(ptr);
|
|
nick_len -= len;
|
|
ptr += len;
|
|
if (nick_len <= 0)
|
|
break;
|
|
}
|
|
say("\t%s %c%s (%s) (Win: %d): %s",
|
|
chan->channel, s ? '+':' ',
|
|
s ? s : "<none>",
|
|
get_server_name(chan->server),
|
|
chan->window ? chan->window->refnum : -1,
|
|
buffer);
|
|
}
|
|
|
|
/* list_channels: displays your current channel and your channel list */
|
|
void list_channels(void)
|
|
{
|
|
ChannelList *tmp;
|
|
int server;
|
|
int shown_current = 0;
|
|
int shown_others = 0;
|
|
|
|
if (get_current_channel_by_refnum(0))
|
|
say("Current channel %s", get_current_channel_by_refnum(0));
|
|
else
|
|
say("No current channel for this window");
|
|
|
|
for (tmp = get_server_channels(get_window_server(0)); tmp; tmp = tmp->next)
|
|
{
|
|
show_channel(tmp);
|
|
shown_current = 1;
|
|
}
|
|
|
|
for (server = 0; server < server_list_size(); server++)
|
|
{
|
|
if (server == get_window_server(0))
|
|
continue;
|
|
for (tmp = get_server_channels(server); tmp; tmp = tmp->next)
|
|
{
|
|
if (!shown_others)
|
|
say("Other servers:");
|
|
show_channel(tmp);
|
|
shown_others = 1;
|
|
}
|
|
}
|
|
|
|
if (!shown_current && !shown_others)
|
|
say("You are not on any channels");
|
|
}
|
|
|
|
void switch_channels(char key, char *ptr)
|
|
{
|
|
ChannelList * tmp = NULL;
|
|
char *nc = get_current_channel_by_refnum(0);
|
|
|
|
if (from_server == -1 || !get_server_channels(from_server))
|
|
return;
|
|
|
|
if (nc)
|
|
if ((tmp = lookup_channel(nc, from_server, CHAN_NOUNLINK)))
|
|
tmp = tmp->next;
|
|
|
|
if (!tmp)
|
|
tmp = get_server_channels(from_server);
|
|
|
|
if (current_window->name && !strcmp(current_window->name, "oper_view"))
|
|
return;
|
|
for (; tmp; tmp = tmp->next)
|
|
{
|
|
if (tmp->server != from_server)
|
|
continue;
|
|
if (is_current_channel(tmp->channel, from_server, 0))
|
|
continue;
|
|
if (current_window == tmp->window)
|
|
{
|
|
set_current_channel_by_refnum(0, tmp->channel);
|
|
update_all_windows();
|
|
do_hook(CHANNEL_SWITCH_LIST, "%s", tmp->channel);
|
|
set_input_prompt(current_window, get_string_var(INPUT_PROMPT_VAR), 0);
|
|
update_input(UPDATE_ALL);
|
|
#ifdef WANT_TCL
|
|
Tcl_SetVar(tcl_interp, "curchan", tmp->channel, TCL_GLOBAL_ONLY);
|
|
#endif
|
|
xterm_settitle();
|
|
return;
|
|
}
|
|
}
|
|
|
|
for (tmp = get_server_channels(from_server); tmp; tmp = tmp->next)
|
|
{
|
|
if (tmp->server != from_server)
|
|
continue;
|
|
if (is_current_channel(tmp->channel, from_server, 0))
|
|
continue;
|
|
if (current_window == tmp->window)
|
|
{
|
|
set_current_channel_by_refnum(0, tmp->channel);
|
|
update_all_windows();
|
|
do_hook(CHANNEL_SWITCH_LIST, "%s", tmp->channel);
|
|
set_input_prompt(current_window, get_string_var(INPUT_PROMPT_VAR), 0);
|
|
update_input(UPDATE_ALL);
|
|
#ifdef WANT_TCL
|
|
Tcl_SetVar(tcl_interp, "curchan", tmp->channel, TCL_GLOBAL_ONLY);
|
|
#endif
|
|
xterm_settitle();
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
void change_server_channels(int old, int new)
|
|
{
|
|
ChannelList *tmp;
|
|
|
|
|
|
if (new == old)
|
|
return;
|
|
if (new > -1 && (tmp = get_server_channels(new)))
|
|
tmp->server = new;
|
|
if (new > -1 && old > -1)
|
|
{
|
|
tmp = get_server_channels(old);
|
|
set_server_channels(new, tmp);
|
|
for (; tmp; tmp = tmp->next)
|
|
tmp->server = new;
|
|
set_server_channels(old, NULL);
|
|
}
|
|
}
|
|
|
|
void clear_channel_list(int server)
|
|
{
|
|
ChannelList *tmp = NULL,
|
|
*next;
|
|
Window *ptr = NULL;
|
|
|
|
while ((traverse_all_windows(&ptr)))
|
|
if (ptr->server == server && ptr->current_channel)
|
|
new_free(&ptr->current_channel);
|
|
|
|
for (tmp = get_server_channels(server); tmp; tmp = next)
|
|
{
|
|
next = tmp->next;
|
|
clear_channel(tmp);
|
|
add_to_whowas_chan_buffer(tmp);
|
|
}
|
|
set_server_channels(server, NULL);
|
|
clear_mode_list(server);
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* reconnect_all_channels: used after you get disconnected from a server,
|
|
* clear each channel nickname list and re-JOINs each channel in the
|
|
* channel_list ..
|
|
*/
|
|
void reconnect_all_channels(int server)
|
|
{
|
|
ChannelList *tmp;
|
|
char *mode;
|
|
char *channel = NULL;
|
|
char *keys = NULL;
|
|
|
|
for (tmp = get_server_channels(server); tmp; tmp = tmp->next)
|
|
{
|
|
if ((mode = recreate_mode(tmp)))
|
|
add_to_mode_list(tmp->channel, server, mode);
|
|
add_to_join_list(tmp->channel, server, tmp->refnum);
|
|
m_s3cat(&channel, ",", tmp->channel);
|
|
m_s3cat(&keys, ",", tmp->key? tmp->key:"-");
|
|
clear_channel(tmp);
|
|
clear_bans(tmp);
|
|
tmp->server = server;
|
|
}
|
|
if (channel)
|
|
my_send_to_server(server, "JOIN %s %s", channel, keys ? keys : empty_string);
|
|
clear_channel_list(from_server);
|
|
new_free(&channel);
|
|
new_free(&keys);
|
|
reset_display_target();
|
|
}
|
|
|
|
char *what_channel(char *nick, int server)
|
|
{
|
|
ChannelList *tmp;
|
|
|
|
|
|
if (current_window->current_channel && is_on_channel(current_window->current_channel, current_window->server, nick))
|
|
return current_window->current_channel;
|
|
|
|
for (tmp = get_server_channels(from_server); tmp; tmp = tmp->next)
|
|
{
|
|
if (find_nicklist_in_channellist(nick, tmp, 0))
|
|
return tmp->channel;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
ChannelList *walk_channels(char *nick, int init, int server)
|
|
{
|
|
static ChannelList *tmp = NULL;
|
|
|
|
if (init)
|
|
tmp = get_server_channels(server);
|
|
else if (tmp)
|
|
tmp = tmp->next;
|
|
|
|
for (;tmp ; tmp = tmp->next)
|
|
{
|
|
if (find_nicklist_in_channellist(nick, tmp, 0))
|
|
return tmp;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
int BX_get_channel_oper(char *channel, int server)
|
|
{
|
|
ChannelList *chan;
|
|
|
|
|
|
if ((chan = lookup_channel(channel, server, CHAN_NOUNLINK)))
|
|
return chan->have_op;
|
|
return 1;
|
|
}
|
|
|
|
int BX_get_channel_halfop(char *channel, int server)
|
|
{
|
|
ChannelList *chan;
|
|
|
|
|
|
if ((chan = lookup_channel(channel, server, CHAN_NOUNLINK)))
|
|
return chan->hop;
|
|
return 1;
|
|
}
|
|
|
|
char *BX_fetch_userhost (int server, char *nick)
|
|
{
|
|
ChannelList *tmp = NULL;
|
|
NickList *user = NULL;
|
|
|
|
for (tmp = get_server_channels(server); tmp; tmp = tmp->next)
|
|
{
|
|
if (((user = (NickList *)find_nicklist_in_channellist(nick, tmp, 0))))
|
|
return user->host;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
int BX_get_channel_voice(char *channel, int server)
|
|
{
|
|
ChannelList *chan;
|
|
|
|
|
|
if ((chan = lookup_channel(channel, server, CHAN_NOUNLINK)))
|
|
return chan->voice;
|
|
return 1;
|
|
}
|
|
|
|
extern void set_channel_window(Window *window, char *channel, int server)
|
|
{
|
|
ChannelList *tmp;
|
|
|
|
|
|
if (!channel || server < 0)
|
|
return;
|
|
for (tmp = get_server_channels(server); tmp; tmp = tmp->next)
|
|
{
|
|
if (!my_stricmp(channel, tmp->channel) && tmp->server == server)
|
|
{
|
|
tmp->window = window;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
extern char * BX_create_channel_list(Window *window)
|
|
{
|
|
ChannelList *chan;
|
|
char buffer[BIG_BUFFER_SIZE];
|
|
|
|
buffer[0] = 0;
|
|
|
|
for (chan = get_server_channels(window->server); chan; chan = chan->next)
|
|
{
|
|
strlcat(buffer, chan->channel, sizeof buffer);
|
|
strlcat(buffer, space, sizeof buffer);
|
|
}
|
|
return m_strdup(buffer);
|
|
}
|
|
|
|
extern void channel_server_delete(int server)
|
|
{
|
|
ChannelList *tmp;
|
|
int i;
|
|
|
|
for (i = server + 1; i < server_list_size(); i++)
|
|
for (tmp = get_server_channels(i); tmp; tmp = tmp->next)
|
|
if (tmp->server >= server)
|
|
tmp->server--;
|
|
}
|
|
|
|
|
|
/* remove_from_join_list: called when mode and names have been received or
|
|
when access has been denied */
|
|
void remove_from_join_list(char *chan, int server)
|
|
{
|
|
struct joinlist *tmp,
|
|
*next,
|
|
*prev = NULL;
|
|
|
|
for (tmp = join_list; tmp; tmp = tmp->next)
|
|
{
|
|
next = tmp->next;
|
|
if (!my_stricmp(chan, tmp->chan) && tmp->server == server)
|
|
{
|
|
if (tmp == join_list)
|
|
join_list = next;
|
|
else
|
|
prev->next = next;
|
|
new_free(&tmp->chan);
|
|
new_free((char **)&tmp);
|
|
return;
|
|
}
|
|
else
|
|
prev = tmp;
|
|
}
|
|
}
|
|
|
|
/* get_win_from_join_list: returns the window refnum associated to the channel
|
|
we're trying to join */
|
|
int get_win_from_join_list(char *chan, int server)
|
|
{
|
|
struct joinlist *tmp;
|
|
int found = 0;
|
|
|
|
for (tmp = join_list; tmp; tmp = tmp->next)
|
|
{
|
|
if (!my_stricmp(tmp->chan, chan) && tmp->server == server)
|
|
found = tmp->winref;
|
|
}
|
|
return found;
|
|
}
|
|
|
|
/* get_chan_from_join_list: returns a pointer on the name of the first channel
|
|
entered into join_list for the specified server */
|
|
char *get_chan_from_join_list(int server)
|
|
{
|
|
struct joinlist *tmp;
|
|
char *found = NULL;
|
|
|
|
for (tmp = join_list; tmp; tmp = tmp->next)
|
|
{
|
|
if (tmp->server == server)
|
|
found = tmp->chan;
|
|
}
|
|
return found;
|
|
}
|
|
|
|
/* in_join_list: returns 1 if we're attempting to join the channel */
|
|
int in_join_list(char *chan, int server)
|
|
{
|
|
struct joinlist *tmp;
|
|
|
|
for (tmp = join_list; tmp; tmp = tmp->next)
|
|
{
|
|
if (!tmp->chan) continue;
|
|
if (!my_stricmp(tmp->chan, chan) && tmp->server == server)
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void channel_sync(struct joinlist *tmp, char *channel)
|
|
{
|
|
double synch_time = time_since(&tmp->tv);
|
|
|
|
if (tmp->gotinfo & GOTNEW)
|
|
{
|
|
/* A channel that we just created. */
|
|
ChannelList *chan;
|
|
char *chanmode;
|
|
|
|
if ((chan = lookup_channel(channel, tmp->server, CHAN_NOUNLINK)))
|
|
if ((chanmode = get_cset_str_var(chan->csets, CHANMODE_CSET)))
|
|
my_send_to_server(tmp->server, "MODE %s :%s", channel, chanmode);
|
|
}
|
|
|
|
set_display_target(channel, LOG_CRAP);
|
|
if (do_hook(CHANNEL_SYNCH_LIST, "%s %1.3f", channel, synch_time))
|
|
bitchsay("Join to %s was synched in %1.3f secs!!", channel, synch_time);
|
|
#ifdef WANT_USERLIST
|
|
delay_check_auto(channel);
|
|
#endif
|
|
update_all_status(current_window, NULL, 0);
|
|
reset_display_target();
|
|
xterm_settitle();
|
|
#ifdef GUI
|
|
gui_update_nicklist(channel);
|
|
#endif
|
|
}
|
|
|
|
/* got_info: increments the gotinfo field when receiving names and mode
|
|
and removes the channel if both have been received */
|
|
int got_info(char *chan, int server, int type)
|
|
{
|
|
struct joinlist *tmp;
|
|
|
|
for (tmp = join_list; tmp; tmp = tmp->next)
|
|
if (!my_stricmp(tmp->chan, chan) && tmp->server == server)
|
|
{
|
|
int required = (GOTNAMES | GOTMODE | GOTBANS | GOTWHO);
|
|
int ver = get_server_version(server);
|
|
|
|
if ((ver == Server2_8ts4) || (ver == Server2_10))
|
|
required |= GOTEXEMPT;
|
|
|
|
tmp->gotinfo |= type;
|
|
|
|
if ((tmp->gotinfo & required) == required)
|
|
{
|
|
channel_sync(tmp, chan);
|
|
remove_from_join_list(chan, tmp->server);
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
/* add_to_join_list: registers a channel we're trying to join */
|
|
void add_to_join_list(char *chan, int server, int winref)
|
|
{
|
|
struct joinlist *tmp;
|
|
|
|
for (tmp = join_list; tmp; tmp = tmp->next)
|
|
{
|
|
if (!my_stricmp(chan, tmp->chan) && (tmp->server == server) && (tmp->winref == winref))
|
|
{
|
|
tmp->winref = winref;
|
|
return;
|
|
}
|
|
}
|
|
tmp = (struct joinlist *) new_malloc(sizeof(struct joinlist));
|
|
tmp->chan = m_strdup(chan);
|
|
tmp->server = server;
|
|
tmp->gotinfo = 0;
|
|
tmp->winref = winref;
|
|
tmp->next = join_list;
|
|
get_time(&tmp->tv);
|
|
join_list = tmp;
|
|
}
|
|
|
|
static void add_to_mode_list(char *channel, int server, char *mode)
|
|
{
|
|
struct modelist *mptr;
|
|
|
|
if (!channel || !*channel || !mode || !*mode)
|
|
return;
|
|
|
|
mptr = (struct modelist *) new_malloc(sizeof(struct modelist));
|
|
mptr->chan = m_strdup(channel);
|
|
mptr->server = server;
|
|
mptr->mode =m_strdup(mode);
|
|
mptr->next = mode_list;
|
|
mode_list = mptr;
|
|
}
|
|
|
|
static void check_mode_list_join(char *channel, int server)
|
|
{
|
|
struct modelist *mptr;
|
|
|
|
|
|
if (!channel)
|
|
return;
|
|
for (mptr = mode_list; mptr; mptr = mptr->next)
|
|
{
|
|
if (!my_stricmp(mptr->chan, channel) && mptr->server == server)
|
|
{
|
|
my_send_to_server(mptr->server, "MODE %s %s", mptr->chan, mptr->mode);
|
|
remove_from_mode_list(channel, server);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
extern void remove_from_mode_list(char *channel, int server)
|
|
{
|
|
struct modelist *curr, *next, *prev = NULL;
|
|
|
|
|
|
for (next = mode_list; next; )
|
|
{
|
|
curr = next;
|
|
next = curr->next;
|
|
if (!my_stricmp(curr->chan, channel) && curr->server == server)
|
|
{
|
|
if (curr == mode_list)
|
|
mode_list = curr->next;
|
|
else
|
|
prev->next = curr->next;
|
|
prev = curr;
|
|
new_free(&curr->chan);
|
|
new_free(&curr->mode);
|
|
new_free((char **)&curr);
|
|
}
|
|
else
|
|
prev = curr;
|
|
}
|
|
}
|
|
|
|
extern void clear_mode_list(int server)
|
|
{
|
|
struct modelist *curr, *next, *prev = NULL;
|
|
|
|
|
|
for (next = mode_list; next; )
|
|
{
|
|
curr = next;
|
|
next = curr->next;
|
|
if (curr == mode_list)
|
|
mode_list = curr->next;
|
|
else
|
|
prev->next = curr->next;
|
|
prev = curr;
|
|
new_free(&curr->chan);
|
|
new_free(&curr->mode);
|
|
new_free((char **)&curr);
|
|
}
|
|
}
|
|
|
|
void BX_flush_channel_stats(void)
|
|
{
|
|
ChannelList *chan;
|
|
for (chan = get_server_channels(from_server); chan; chan = chan->next)
|
|
{
|
|
chan->stats_ops = 0;
|
|
chan->stats_dops = 0;
|
|
chan->stats_bans = 0;
|
|
chan->stats_unbans = 0;
|
|
chan->stats_sops = 0;
|
|
chan->stats_sdops = 0;
|
|
chan->stats_sbans = 0;
|
|
chan->stats_sunbans = 0;
|
|
chan->stats_topics = 0;
|
|
chan->stats_kicks = 0;
|
|
chan->stats_pubs = 0;
|
|
chan->stats_parts = 0;
|
|
chan->stats_signoffs = 0;
|
|
chan->stats_joins = 0;
|
|
chan->maxnicks = 0;
|
|
chan->maxnickstime = 0;
|
|
}
|
|
}
|
|
/*
|
|
* For any given window, re-assign all of the channels that are connected
|
|
* to that window.
|
|
*/
|
|
void unset_window_current_channel (Window *window)
|
|
{
|
|
ChannelList *tmp;
|
|
if (window->server <= -1)
|
|
return;
|
|
for (tmp = get_server_channels(window->server); tmp; tmp = tmp->next)
|
|
{
|
|
if (tmp->window == window && window->current_channel && !my_stricmp(tmp->channel, window->current_channel))
|
|
{
|
|
new_free(&window->current_channel);
|
|
tmp->window = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* For any given window, re-assign all of the channels that are connected
|
|
* to that window.
|
|
*/
|
|
void move_window_channels (Window *window)
|
|
{
|
|
ChannelList *tmp;
|
|
if (window->server <= -1)
|
|
return;
|
|
for (tmp = get_server_channels(window->server); tmp; tmp = tmp->next)
|
|
{
|
|
if (tmp->window == window)
|
|
{
|
|
Window *w = NULL;
|
|
tmp->window = NULL;
|
|
while (traverse_all_windows(&w))
|
|
{
|
|
if (w->server == window->server && w != window)
|
|
{
|
|
tmp->window = w;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void check_channel_limits()
|
|
{
|
|
int i;
|
|
ChannelList *chan;
|
|
for (i = 0; i < server_list_size(); i++)
|
|
{
|
|
for (chan = get_server_channels(i); chan; chan = chan->next)
|
|
{
|
|
if (!chan->have_op || !chan->csets || !chan->csets->set_auto_limit)
|
|
continue;
|
|
if (chan->totalnicks + chan->csets->set_auto_limit != chan->limit)
|
|
my_send_to_server(i, "MODE %s +l %d", chan->channel, chan->totalnicks + chan->csets->set_auto_limit);
|
|
}
|
|
}
|
|
}
|