1
0
mirror of https://github.com/irssi/irssi.git synced 2024-09-01 04:14:16 -04:00

isupport patch by David Leadbeater

git-svn-id: http://svn.irssi.org/repos/irssi/trunk@3211 dbcabf3a-b0e7-0310-adc4-f8d773084564
This commit is contained in:
Timo Sirainen 2004-01-20 10:57:57 +00:00 committed by cras
parent 3ccbd0405b
commit 217283caea
30 changed files with 517 additions and 130 deletions

View File

@ -219,7 +219,7 @@ static void event_connected(SERVER_REC *server)
static int match_nick_flags(SERVER_REC *server, NICK_REC *nick, char flag)
{
const char *flags = server->get_nick_flags();
const char *flags = server->get_nick_flags(server);
return strchr(flags, flag) == NULL ||
(flag == flags[0] && nick->op) ||
@ -259,7 +259,7 @@ void channel_send_autocommands(CHANNEL_REC *channel)
continue;
nick = nicklist_find_mask(channel,
channel->server->isnickflag(*botnick) ?
channel->server->isnickflag(channel->server, *botnick) ?
botnick+1 : botnick);
if (nick != NULL &&
match_nick_flags(channel->server, nick, *botnick)) {

View File

@ -345,7 +345,7 @@ static void cmd_msg(const char *data, SERVER_REC *server, WI_ITEM_REC *item)
GHashTable *optlist;
char *target, *origtarget, *msg;
void *free_arg;
int free_ret, target_type;
int free_ret, target_type = SEND_TARGET_NICK;
g_return_if_fail(data != NULL);
@ -398,7 +398,6 @@ static void cmd_msg(const char *data, SERVER_REC *server, WI_ITEM_REC *item)
if (target != NULL)
server->send_message(server, target, msg, target_type);
signal_emit(target != NULL && target_type == SEND_TARGET_CHANNEL ?
"message own_public" : "message own_private", 4,
server, msg, target, origtarget);

View File

@ -19,6 +19,7 @@ unsigned int send_massjoin:1; /* Waiting to be sent in massjoin signal */
unsigned int op:1;
unsigned int halfop:1;
unsigned int voice:1;
unsigned int other:7;
/*GHashTable *module_data;*/

View File

@ -369,7 +369,10 @@ int nicklist_compare(NICK_REC *p1, NICK_REC *p2)
* returns :-)
* -- yath */
if (p1->op)
/* Treat others as highest - should really use order in 005 numeric */
if (p1->other)
status1 = 5;
else if (p1->op)
status1 = 4;
else if (p1->halfop)
status1 = 3;
@ -378,7 +381,9 @@ int nicklist_compare(NICK_REC *p1, NICK_REC *p2)
else
status1 = 1;
if (p2->op)
if (p2->other)
status2 = 5;
else if (p2->op)
status2 = 4;
else if (p2->halfop)
status2 = 3;

View File

@ -53,12 +53,12 @@ GSList *queries;
channel keys etc. */
void (*channels_join)(SERVER_REC *server, const char *data, int automatic);
/* returns true if `flag' indicates a nick flag (op/voice/halfop) */
int (*isnickflag)(char flag);
int (*isnickflag)(SERVER_REC *server, char flag);
/* returns true if `data' indicates a channel */
int (*ischannel)(SERVER_REC *server, const char *data);
/* returns all nick flag characters in order op, voice, halfop. If some
of them aren't supported '\0' can be used. */
const char *(*get_nick_flags)(void);
const char *(*get_nick_flags)(SERVER_REC *server);
/* send public or private message to server */
void (*send_message)(SERVER_REC *server, const char *target,
const char *msg, int target_type);

View File

@ -118,12 +118,17 @@ static void cmd_upgrade(const char *data)
static void session_save_nick(CHANNEL_REC *channel, NICK_REC *nick,
CONFIG_REC *config, CONFIG_NODE *node)
{
static char other[2];
node = config_node_section(node, NULL, NODE_TYPE_BLOCK);
config_node_set_str(config, node, "nick", nick->nick);
config_node_set_bool(config, node, "op", nick->op);
config_node_set_bool(config, node, "halfop", nick->halfop);
config_node_set_bool(config, node, "voice", nick->voice);
other[0] = nick->other;
other[1] = '\0';
config_node_set_str(config, node, "other", other);
signal_emit("session save nick", 4, channel, nick, config, node);
}

View File

@ -399,7 +399,9 @@ static void display_sorted_nicks(CHANNEL_REC *channel, GSList *nicklist)
for (tmp = nicklist; tmp != NULL; tmp = tmp->next) {
NICK_REC *rec = tmp->data;
if (rec->op)
if (rec->other)
nickmode[0] = rec->other;
else if (rec->op)
nickmode[0] = '@';
else if (rec->halfop)
nickmode[0] = '%';

View File

@ -116,12 +116,19 @@ char *expand_emphasis(WI_ITEM_REC *item, const char *text)
static char *channel_get_nickmode_rec(NICK_REC *nickrec)
{
char *emptystr;
static char nickmode[2]; /* FIXME: bad */
if (!settings_get_bool("show_nickmode"))
return "";
emptystr = settings_get_bool("show_nickmode_empty") ? " " : "";
if (nickrec != NULL && nickrec->other) {
nickmode[0] = nickrec->other;
nickmode[1] = '\0';
return nickmode;
}
return nickrec == NULL ? emptystr :
nickrec->op ? "@" :
nickrec->halfop ? "%" :

View File

@ -945,6 +945,7 @@ void fe_events_numeric_init(void)
signal_add("default event numeric", (SIGNAL_FUNC) event_numeric);
signal_add("event 001", (SIGNAL_FUNC) event_received);
signal_add("event 004", (SIGNAL_FUNC) event_received);
signal_add("event 005", (SIGNAL_FUNC) event_received);
signal_add("event 254", (SIGNAL_FUNC) event_received);
signal_add("event 364", (SIGNAL_FUNC) event_received);
signal_add("event 365", (SIGNAL_FUNC) event_received);
@ -1033,6 +1034,7 @@ void fe_events_numeric_deinit(void)
signal_remove("default event numeric", (SIGNAL_FUNC) event_numeric);
signal_remove("event 001", (SIGNAL_FUNC) event_received);
signal_remove("event 004", (SIGNAL_FUNC) event_received);
signal_remove("event 005", (SIGNAL_FUNC) event_received);
signal_remove("event 254", (SIGNAL_FUNC) event_received);
signal_remove("event 364", (SIGNAL_FUNC) event_received);
signal_remove("event 365", (SIGNAL_FUNC) event_received);

View File

@ -387,7 +387,7 @@ static void msg_mode(IRC_SERVER_REC *server, const char *channel,
show = TRUE;
nick++;
} else {
if (HAS_MODE_ARG(type, *mode) && *nick != NULL)
if (HAS_MODE_ARG(server, type, *mode) && *nick != NULL)
nick++;
show = TRUE;
}

View File

@ -623,28 +623,39 @@ static void cmd_wall(const char *data, IRC_SERVER_REC *server, WI_ITEM_REC *item
chanrec = irc_channel_find(server, channame);
if (chanrec == NULL) cmd_param_error(CMDERR_CHAN_NOT_FOUND);
/* send notice to all ops */
nicks = NULL;
g_hash_table_foreach(chanrec->nicks, (GHFunc) cmd_wall_hash, &nicks);
/* See if the server has advertised support of wallchops */
if (g_hash_table_lookup(chanrec->server->isupport, "statusmsg") ||
g_hash_table_lookup(chanrec->server->isupport, "wallchops"))
irc_send_cmdv(server, "NOTICE @%s :%s", chanrec->name, msg);
else {
/* Fall back to manually noticing each op */
nicks = NULL;
g_hash_table_foreach(chanrec->nicks,
(GHFunc) cmd_wall_hash, &nicks);
args = g_strconcat(chanrec->name, " ", msg, NULL);
msg = parse_special_string(settings_get_str("wall_format"),
SERVER(server), item, args, NULL, 0);
g_free(args);
args = g_strconcat(chanrec->name, " ", msg, NULL);
msg = parse_special_string(settings_get_str("wall_format"),
SERVER(server), item, args, NULL, 0);
g_free(args);
for (tmp = nicks; tmp != NULL; tmp = tmp->next) {
NICK_REC *rec = tmp->data;
for (tmp = nicks; tmp != NULL; tmp = tmp->next) {
NICK_REC *rec = tmp->data;
if (rec != chanrec->ownnick)
irc_send_cmdv(server, "NOTICE %s :%s", rec->nick, msg);
if (rec != chanrec->ownnick) {
irc_send_cmdv(server, "NOTICE %s :%s",
rec->nick, msg);
}
}
g_free(msg);
g_slist_free(nicks);
}
g_free(msg);
g_slist_free(nicks);
cmd_params_free(free_arg);
}
/* SYNTAX: WALLCHOPS <channel> <message> */
/* ircu is the only major server i can see which supports this
and it supports NOTICE @#channel anyway */
static void cmd_wallchops(const char *data, IRC_SERVER_REC *server, WI_ITEM_REC *item)
{
char *channame, *msg;

View File

@ -82,10 +82,19 @@ static char *expando_usermode(SERVER_REC *server, void *item, int *free_ret)
return IS_IRC_SERVER(server) ? IRC_SERVER(server)->usermode : "";
}
/* expands to your usermode on channel, op '@', halfop '%', "+" voice */
/* expands to your usermode on channel, op '@', halfop '%', "+" voice or other */
static char *expando_cumode(SERVER_REC *server, void *item, int *free_ret)
{
if (IS_IRC_CHANNEL(item) && CHANNEL(item)->ownnick) {
char other = NICK(CHANNEL(item)->ownnick)->other;
if (other != '\0') {
char *cumode = g_malloc(2);
cumode[0] = other;
cumode[1] = '\0';
*free_ret = TRUE;
return cumode;
}
return NICK(CHANNEL(item)->ownnick)->op ? "@" :
NICK(CHANNEL(item)->ownnick)->halfop ? "%" :
NICK(CHANNEL(item)->ownnick)->voice ? "+" : "";

View File

@ -74,11 +74,32 @@ char *irc_nick_strip(const char *nick)
return stripped;
}
int irc_nickcmp_rfc1459(const char *m, const char *n)
{
while (*m != '\0' && *n != '\0') {
if (to_rfc1459(*m) != to_rfc1459(*n))
return -1;
m++; n++;
}
return *m == *n ? 0 : 1;
}
int irc_nickcmp_ascii(const char *m, const char *n)
{
while (*m != '\0' && *n != '\0') {
if (to_ascii(*m) != to_ascii(*n))
return -1;
m++; n++;
}
return *m == *n ? 0 : 1;
}
static void event_names_list(IRC_SERVER_REC *server, const char *data)
{
IRC_CHANNEL_REC *chanrec;
NICK_REC *rec;
char *params, *type, *channel, *names, *ptr;
int op, halfop, voice;
int op, halfop, voice, other;
g_return_if_fail(data != NULL);
@ -117,8 +138,8 @@ static void event_names_list(IRC_SERVER_REC *server, const char *data)
showing "@+nick" and since none of these chars are valid
nick chars, just check them until a non-nickflag char is
found. FIXME: we just ignore owner char now. */
op = halfop = voice = FALSE;
while (isnickflag(*ptr)) {
op = halfop = voice = other = FALSE;
while (isnickflag(server, *ptr)) {
switch (*ptr) {
case '@':
op = TRUE;
@ -129,13 +150,17 @@ static void event_names_list(IRC_SERVER_REC *server, const char *data)
case '+':
voice = TRUE;
break;
default:
other = *ptr;
}
ptr++;
}
if (nicklist_find((CHANNEL_REC *) chanrec, ptr) == NULL) {
irc_nicklist_insert(chanrec, ptr, op, halfop,
voice, FALSE);
rec = irc_nicklist_insert(chanrec, ptr, op, halfop,
voice, FALSE);
if (other)
rec->other = other;
}
}
@ -376,17 +401,24 @@ static void sig_usermode(SERVER_REC *server)
nicklist_update_flags(server, server->nick, server->usermode_away, -1);
}
static const char *get_nick_flags(void)
static const char *get_nick_flags(SERVER_REC *server)
{
return "@+%";
IRC_SERVER_REC *irc_server = (IRC_SERVER_REC *) server;
static char *std = "@%+";
char *prefix = g_hash_table_lookup(irc_server->isupport, "prefix");
if (prefix == NULL)
return std;
prefix = strchr(prefix, ')');
if (prefix != NULL || *++prefix == '\0') /* FIXME: ugly to modify it */
return std;
return prefix;
}
static void sig_connected(IRC_SERVER_REC *server)
{
if (IS_IRC_SERVER(server)) {
server->get_nick_flags =
(const char *(*)(void)) get_nick_flags;
}
if (IS_IRC_SERVER(server))
server->get_nick_flags = get_nick_flags;
}
void irc_nicklist_init(void)

View File

@ -10,7 +10,14 @@ NICK_REC *irc_nicklist_insert(IRC_CHANNEL_REC *channel, const char *nick,
/* Remove all "extra" characters from `nick'. Like _nick_ -> nick */
char *irc_nick_strip(const char *nick);
int irc_nickcmp_rfc1459(const char *, const char *);
int irc_nickcmp_ascii(const char *, const char *);
void irc_nicklist_init(void);
void irc_nicklist_deinit(void);
/* FIXME: to_rfc1459() is missing things */
#define to_rfc1459(x) ((x) >= 65 && (x) <= 94 ? (x) + 32 : (x))
#define to_ascii(x) ((x) >= 65 && (x) <= 94 ? (x) + 32 : (x))
#endif

View File

@ -22,6 +22,7 @@
#include "signals.h"
#include "misc.h"
#include "irc-nicklist.h"
#include "irc-servers.h"
#include "irc-queries.h"
@ -40,6 +41,20 @@ QUERY_REC *irc_query_create(const char *server_tag,
return rec;
}
QUERY_REC *irc_query_find(IRC_SERVER_REC *server, const char *nick)
{
GSList *tmp;
for (tmp = server->queries; tmp != NULL; tmp = tmp->next) {
QUERY_REC *rec = tmp->data;
if (server->nick_comp_func(rec->name, nick) == 0)
return rec;
}
return NULL;
}
static void check_query_changes(IRC_SERVER_REC *server, const char *nick,
const char *address, const char *target)
{

View File

@ -14,8 +14,7 @@
void irc_queries_init(void);
void irc_queries_deinit(void);
#define irc_query_find(server, name) \
query_find(SERVER(server), name)
QUERY_REC *irc_query_find(IRC_SERVER_REC *server, const char *nick);
QUERY_REC *irc_query_create(const char *server_tag,
const char *nick, int automatic);

View File

@ -30,6 +30,8 @@
#include "channels.h"
#include "queries.h"
#include "irc-nicklist.h"
#include "irc-queries.h"
#include "irc-servers-setup.h"
#include "irc-servers.h"
#include "channel-rejoin.h"
@ -55,9 +57,11 @@ void irc_servers_reconnect_deinit(void);
static int cmd_tag;
static int isnickflag_func(char flag)
static int isnickflag_func(SERVER_REC *server, char flag)
{
return isnickflag(flag);
IRC_SERVER_REC *irc_server = (IRC_SERVER_REC *) server;
return isnickflag(irc_server, flag);
}
static int ischannel_func(SERVER_REC *server, const char *data)
@ -157,6 +161,9 @@ static void server_init(IRC_SERVER_REC *server)
conn->address, conn->port);
}
server->isupport = g_hash_table_new((GHashFunc) g_istr_hash,
(GCompareFunc) g_istr_equal);
server->cmdcount = 0;
}
@ -198,6 +205,8 @@ SERVER_REC *irc_server_init_connect(SERVER_CONNECT_REC *conn)
ircconn->max_msgs : DEFAULT_MAX_MSGS;
server->connrec->use_ssl = conn->use_ssl;
modes_server_init(server);
server_connect_init((SERVER_REC *) server);
return (SERVER_REC *) server;
}
@ -268,6 +277,9 @@ static void sig_connected(IRC_SERVER_REC *server)
server->isnickflag = isnickflag_func;
server->ischannel = ischannel_func;
server->send_message = send_message;
server->query_find_func =
(QUERY_REC *(*)(SERVER_REC *, const char *)) irc_query_find;
server->nick_comp_func = irc_nickcmp_ascii;
server->splits = g_hash_table_new((GHashFunc) g_istr_hash,
(GCompareFunc) g_istr_equal);
@ -276,6 +288,12 @@ static void sig_connected(IRC_SERVER_REC *server)
server_init(server);
}
static void isupport_destroy_hash(void *key, void *value)
{
g_free(key);
g_free(value);
}
static void sig_disconnected(IRC_SERVER_REC *server)
{
GSList *tmp;
@ -291,6 +309,10 @@ static void sig_disconnected(IRC_SERVER_REC *server)
g_slist_free(server->cmdqueue);
server->cmdqueue = NULL;
g_hash_table_foreach(server->isupport, (GHFunc) isupport_destroy_hash, server);
g_hash_table_destroy(server->isupport);
server->isupport = NULL;
g_free_and_null(server->wanted_usermode);
g_free_and_null(server->real_address);
g_free_and_null(server->usermode);
@ -452,7 +474,7 @@ static int sig_set_user_mode(IRC_SERVER_REC *server)
mode = server->connrec->usermode;
newmode = server->usermode == NULL ? NULL :
modes_join(server->usermode, mode, FALSE);
modes_join(NULL, server->usermode, mode, FALSE);
if (newmode == NULL || strcmp(newmode, server->usermode) != 0) {
/* change the user mode. we used to do some trickery to
@ -521,6 +543,123 @@ static void event_server_info(IRC_SERVER_REC *server, const char *data)
g_free(params);
}
static void parse_chanmodes(IRC_SERVER_REC *server, const char *sptr)
{
mode_func_t *modefuncs[] = {
modes_type_a,
modes_type_b,
modes_type_c,
modes_type_d
};
char **item, **chanmodes;
int i;
chanmodes = g_strsplit(sptr, ",", 5); /* ignore extras */
for (i = 0, item = chanmodes; *item != NULL && i < 4; item++, i++) {
unsigned char *p = *item;
while (*p != '\0') {
server->modes[(int)*p].func = modefuncs[i];
p++;
}
}
g_strfreev(chanmodes);
}
static void parse_prefix(IRC_SERVER_REC *server, const char *sptr)
{
const char *eptr;
if (*sptr++ != '(')
return; /* Unknown prefix format */
eptr = strchr(sptr, ')');
if (eptr == NULL)
return;
eptr++;
while (*sptr != '\0' && *eptr != '\0' && *sptr != ')' && *eptr != ' ') {
server->modes[(int)(unsigned char) *sptr].func =
modes_type_prefix;
server->modes[(int)(unsigned char) *sptr].prefix = *eptr;
server->prefix[(int)(unsigned char) *eptr] = *sptr;
sptr++; eptr++;
}
}
static void event_isupport(IRC_SERVER_REC *server, const char *data)
{
char **item, *sptr, *eptr;
char **isupport;
g_return_if_fail(server != NULL);
server->isupport_sent = TRUE;
sptr = strchr(data, ' ');
if (sptr == NULL)
return;
sptr++;
isupport = g_strsplit(sptr, " ", -1);
for(item = isupport; *item != NULL; item++) {
int removed = FALSE;
gpointer key = NULL, value = NULL;
if (**item == ':')
break;
sptr = strchr(*item, '=');
if (sptr != NULL) {
*sptr = '\0';
sptr++;
}
eptr = *item;
if(*eptr == '-') {
removed = TRUE;
eptr++;
}
if (!g_hash_table_lookup_extended(server->isupport, eptr,
&key, &value) && removed)
continue;
if (removed)
g_hash_table_remove(server->isupport, eptr);
else {
g_hash_table_insert(server->isupport, g_strdup(eptr),
g_strdup(sptr != NULL ? sptr : ""));
}
g_free(key);
g_free(value);
}
g_strfreev(isupport);
if ((sptr = g_hash_table_lookup(server->isupport, "CHANMODES")))
parse_chanmodes(server, sptr);
/* This is after chanmode because some servers define modes in both */
if ((sptr = g_hash_table_lookup(server->isupport, "PREFIX")))
parse_prefix(server, sptr);
if ((sptr = g_hash_table_lookup(server->isupport, "MODES"))) {
server->max_modes_in_cmd = atoi(sptr);
if (server->max_modes_in_cmd < 1)
server->max_modes_in_cmd = DEFAULT_MAX_MODES;
}
if ((sptr = g_hash_table_lookup(server->isupport, "CASEMAPPING"))) {
if (strstr(sptr, "rfc1459") != NULL)
server->nick_comp_func = irc_nickcmp_rfc1459;
else
server->nick_comp_func = irc_nickcmp_ascii;
}
}
static void event_motd(IRC_SERVER_REC *server, const char *data, const char *from)
{
if (server->connected)
@ -599,6 +738,7 @@ void irc_servers_init(void)
signal_add_last("server quit", (SIGNAL_FUNC) sig_server_quit);
signal_add("event 001", (SIGNAL_FUNC) event_connected);
signal_add("event 004", (SIGNAL_FUNC) event_server_info);
signal_add("event 005", (SIGNAL_FUNC) event_isupport);
signal_add("event 375", (SIGNAL_FUNC) event_motd);
signal_add_last("event 376", (SIGNAL_FUNC) event_end_of_motd);
signal_add_last("event 422", (SIGNAL_FUNC) event_end_of_motd); /* no motd */
@ -623,6 +763,7 @@ void irc_servers_deinit(void)
signal_remove("server quit", (SIGNAL_FUNC) sig_server_quit);
signal_remove("event 001", (SIGNAL_FUNC) event_connected);
signal_remove("event 004", (SIGNAL_FUNC) event_server_info);
signal_remove("event 005", (SIGNAL_FUNC) event_isupport);
signal_remove("event 375", (SIGNAL_FUNC) event_motd);
signal_remove("event 376", (SIGNAL_FUNC) event_end_of_motd);
signal_remove("event 422", (SIGNAL_FUNC) event_end_of_motd); /* no motd */

View File

@ -3,6 +3,7 @@
#include "chat-protocols.h"
#include "servers.h"
#include "modes.h"
/* returns IRC_SERVER_REC if it's IRC server, NULL if it isn't */
#define IRC_SERVER(server) \
@ -61,6 +62,7 @@ struct _IRC_SERVER_REC {
unsigned int disable_lag:1; /* Disable lag detection (PING command doesn't exist) */
unsigned int nick_collision:1; /* We're just now being killed because of nick collision */
unsigned int motd_got:1; /* We've received MOTD */
unsigned int isupport_sent:1; /* Server has sent us an isupport reply */
int max_kicks_in_cmd; /* max. number of people to kick with one /KICK command */
int max_modes_in_cmd; /* max. number of mode changes in one /MODE command */
@ -96,6 +98,12 @@ struct _IRC_SERVER_REC {
channels go here if they're "temporarily unavailable"
because of netsplits */
void *chanqueries;
GHashTable *isupport;
struct modes_type modes[256]; /* Stores the modes sent by a server in an isupport reply */
char prefix[256];
int (*nick_comp_func)(const char *, const char *); /* Function for comparing nicknames on this server */
};
SERVER_REC *irc_server_init_connect(SERVER_CONNECT_REC *conn);

View File

@ -22,15 +22,25 @@
#include "signals.h"
#include "net-sendbuffer.h"
#include "lib-config/iconfig.h"
#include "misc.h"
#include "irc-servers.h"
#include "irc-channels.h"
#include "irc-nicklist.h"
struct _isupport_data { CONFIG_REC *config; CONFIG_NODE *node; };
static void session_isupport_foreach(char *key, char *value, struct _isupport_data *data)
{
config_node_set_str(data->config, data->node, key, value);
}
static void sig_session_save_server(IRC_SERVER_REC *server, CONFIG_REC *config,
CONFIG_NODE *node)
{
GSList *tmp;
CONFIG_NODE *isupport;
struct _isupport_data isupport_data;
if (!IS_IRC_SERVER(server))
return;
@ -54,11 +64,19 @@ static void sig_session_save_server(IRC_SERVER_REC *server, CONFIG_REC *config,
config_node_set_bool(config, node, "usermode_away", server->usermode_away);
config_node_set_str(config, node, "away_reason", server->away_reason);
config_node_set_bool(config, node, "emode_known", server->emode_known);
isupport = config_node_section(node, "isupport", NODE_TYPE_BLOCK);
isupport_data.config = config;
isupport_data.node = isupport;
g_hash_table_foreach(server->isupport, (GHFunc) session_isupport_foreach, &isupport_data);
}
static void sig_session_restore_server(IRC_SERVER_REC *server,
CONFIG_NODE *node)
{
GSList *tmp;
if (!IS_IRC_SERVER(server))
return;
@ -69,12 +87,33 @@ static void sig_session_restore_server(IRC_SERVER_REC *server,
server->usermode_away = config_node_get_bool(node, "usermode_away", FALSE);
server->away_reason = g_strdup(config_node_get_str(node, "away_reason", NULL));
server->emode_known = config_node_get_bool(node, "emode_known", FALSE);
if (server->isupport == NULL) {
server->isupport = g_hash_table_new((GHashFunc) g_istr_hash,
(GCompareFunc) g_istr_equal);
}
node = config_node_section(node, "isupport", -1);
tmp = config_node_first(node->value);
if(tmp != NULL)
server->isupport_sent = TRUE;
for (; tmp != NULL; tmp = config_node_next(tmp)) {
node = tmp->data;
if (node == NULL)
break;
g_hash_table_insert(server->isupport, g_strdup(node->key),
g_strdup(node->value));
}
}
static void sig_session_restore_nick(IRC_CHANNEL_REC *channel,
CONFIG_NODE *node)
{
const char *nick;
char *other;
int op, halfop, voice;
NICK_REC *nickrec;
@ -89,6 +128,8 @@ static void sig_session_restore_nick(IRC_CHANNEL_REC *channel,
voice = config_node_get_bool(node, "voice", FALSE);
halfop = config_node_get_bool(node, "halfop", FALSE);
nickrec = irc_nicklist_insert(channel, nick, op, halfop, voice, FALSE);
other = config_node_get_str(node, "other", FALSE);
nickrec->other = other[0];
}
static void session_restore_channel(IRC_CHANNEL_REC *channel)

View File

@ -19,9 +19,8 @@ typedef struct _REDIRECT_REC REDIRECT_REC;
((a) == '^' || (a) == '~' || \
(a) == '+' || (a) == '=' || (a) == '-')
#define isnickflag(a) \
((a) == '@' || (a) == '+' || (a) == '%' || /* op / voice */ \
(a) == '%' || (a) == '.' || (a) == '!') /* extensions: half-op / owners */
#define isnickflag(server, a) \
(server->prefix[(int)(unsigned char) a] != '\0')
#define ischannel(a) \
((a) == '#' || /* normal */ \

View File

@ -32,7 +32,7 @@
/* Change nick's mode in channel */
static void nick_mode_change(IRC_CHANNEL_REC *channel, const char *nick,
const char mode, int type, const char *setby)
char mode, int type, const char *setby)
{
NICK_REC *nickrec;
char modestr[2], typestr[2];
@ -44,8 +44,10 @@ static void nick_mode_change(IRC_CHANNEL_REC *channel, const char *nick,
if (nickrec == NULL) return; /* No /names list got yet */
if (mode == '@') nickrec->op = type == '+';
if (mode == '+') nickrec->voice = type == '+';
if (mode == '%') nickrec->halfop = type == '+';
else if (mode == '+') nickrec->voice = type == '+';
else if (mode == '%') nickrec->halfop = type == '+';
else if (channel->server->prefix[(unsigned char) mode] != '\0')
nickrec->other = (type == '+' ? mode : '\0');
modestr[0] = mode; modestr[1] = '\0';
typestr[0] = type; typestr[1] = '\0';
@ -97,13 +99,15 @@ static void mode_add_arg(GString *str, int pos, int updating, const char *arg)
}
/* Add mode character to list sorted alphabetically */
static void mode_add_sorted(GString *str, char mode, const char *arg)
static void mode_add_sorted(IRC_SERVER_REC *server, GString *str,
char mode, const char *arg, int user)
{
char *p;
int updating, argpos = 0;
/* check that mode isn't already set */
if (!HAS_MODE_ARG_SET(mode) && mode_is_set(str->str, mode))
if ((!user && !HAS_MODE_ARG_SET(server, mode)) &&
mode_is_set(str->str, mode))
return;
updating = FALSE;
@ -114,7 +118,7 @@ static void mode_add_sorted(GString *str, char mode, const char *arg)
updating = TRUE;
break;
}
if (HAS_MODE_ARG_SET(*p))
if (!user && HAS_MODE_ARG_SET(server, *p))
argpos++;
}
@ -154,7 +158,7 @@ static void node_remove_arg(GString *str, int pos)
}
/* remove mode (and it's argument) from string */
static void mode_remove(GString *str, char mode)
static void mode_remove(IRC_SERVER_REC *server, GString *str, char mode, int user)
{
char *p;
int argpos = 0;
@ -162,34 +166,91 @@ static void mode_remove(GString *str, char mode)
for (p = str->str; *p != '\0' && *p != ' '; p++) {
if (mode == *p) {
g_string_erase(str, (int) (p-str->str), 1);
if (HAS_MODE_ARG_SET(mode))
if (!user && HAS_MODE_ARG_SET(server, mode))
node_remove_arg(str, argpos);
break;
}
if (HAS_MODE_ARG_SET(*p))
if (!user && HAS_MODE_ARG_SET(server, *p))
argpos++;
}
}
static void mode_set(GString *str, char type, char mode)
static void mode_set(IRC_SERVER_REC *server, GString *str,
char type, char mode, int user)
{
g_return_if_fail(str != NULL);
if (type == '-')
mode_remove(str, mode);
mode_remove(server, str, mode, user);
else
mode_add_sorted(str, mode, NULL);
mode_add_sorted(server, str, mode, NULL, user);
}
static void mode_set_arg(GString *str, char type, char mode, const char *arg)
static void mode_set_arg(IRC_SERVER_REC *server, GString *str,
char type, char mode, const char *arg)
{
g_return_if_fail(str != NULL);
g_return_if_fail(type == '-' || arg != NULL);
if (type == '-')
mode_remove(str, mode);
mode_remove(server, str, mode, TRUE);
else
mode_add_sorted(str, mode, arg);
mode_add_sorted(server, str, mode, arg, TRUE);
}
/* Mode that needs a parameter of a mask for both setting and removing (eg: bans) */
void modes_type_a(IRC_CHANNEL_REC *channel, const char *setby, char type,
char mode, char *arg, GString *newmode)
{
/* Currently only +b is dealt with */
if (mode == 'b') {
if (type == '+')
banlist_add(channel, arg, setby, time(NULL));
else
banlist_remove(channel, arg);
}
}
/* Mode that needs parameter for both setting and removing (eg: +k) */
void modes_type_b(IRC_CHANNEL_REC *channel, const char *setby, char type,
char mode, char *arg, GString *newmode)
{
if (mode == 'k') {
if (*arg == '\0' && type == '+')
arg = channel->key != NULL ? channel->key : "???";
mode_set_arg(channel->server, newmode, type, 'k', arg);
if (arg != channel->key) {
g_free_and_null(channel->key);
if (type == '+')
channel->key = g_strdup(arg);
}
}
}
/* Mode that needs parameter only for adding */
void modes_type_c(IRC_CHANNEL_REC *channel, const char *setby,
char type, char mode, char *arg, GString *newmode)
{
if (mode == 'l') {
mode_set_arg(channel->server, newmode, type, 'l', arg);
channel->limit = type == '-' ? 0 : atoi(arg);
}
}
/* Mode that takes no parameter */
void modes_type_d(IRC_CHANNEL_REC *channel, const char *setby,
char type, char mode, char *arg, GString *newmode)
{
mode_set(channel->server, newmode, type, mode, FALSE);
}
void modes_type_prefix(IRC_CHANNEL_REC *channel, const char *setby,
char type, char mode, char *arg, GString *newmode)
{
int umode = (unsigned char) mode;
nick_mode_change(channel, arg, channel->server->modes[umode].prefix,
type, setby);
}
int channel_mode_is_set(IRC_CHANNEL_REC *channel, char mode)
@ -204,8 +265,10 @@ int channel_mode_is_set(IRC_CHANNEL_REC *channel, char mode)
void parse_channel_modes(IRC_CHANNEL_REC *channel, const char *setby,
const char *mode, int update_key)
{
IRC_SERVER_REC *server = channel->server;
GString *newmode;
char *dup, *modestr, *arg, *curmode, type;
int umode;
g_return_if_fail(IS_IRC_CHANNEL(channel));
g_return_if_fail(mode != NULL);
@ -216,7 +279,7 @@ void parse_channel_modes(IRC_CHANNEL_REC *channel, const char *setby,
dup = modestr = g_strdup(mode);
curmode = cmd_get_param(&modestr);
while (*curmode != '\0') {
if (HAS_MODE_ARG(type, *curmode)) {
if (HAS_MODE_ARG(server, type, *curmode)) {
/* get the argument for the mode. NOTE: We don't
get the +k's argument when joining to channel. */
arg = cmd_get_param(&modestr);
@ -229,54 +292,17 @@ void parse_channel_modes(IRC_CHANNEL_REC *channel, const char *setby,
case '-':
type = *curmode;
break;
case 'b':
if (type == '+')
banlist_add(channel, arg, setby, time(NULL));
else
banlist_remove(channel, arg);
break;
case 'o':
case 'O': /* channel owner in !channels */
if (g_strcasecmp(channel->server->nick, arg) == 0)
channel->chanop = type == '+';
nick_mode_change(channel, arg, '@', type, setby);
break;
case 'h':
nick_mode_change(channel, arg, '%', type, setby);
break;
case 'v':
nick_mode_change(channel, arg, '+', type, setby);
break;
case 'l':
mode_set_arg(newmode, type, 'l', arg);
channel->limit = type == '-' ? 0 : atoi(arg);
break;
case 'k':
if ((*arg == '\0' && type == '+') ||
(channel->key != NULL && !update_key)) {
arg = channel->key != NULL ? channel->key :
"???";
}
mode_set_arg(newmode, type, 'k', arg);
if (arg != channel->key) {
g_free_and_null(channel->key);
if (type == '+')
channel->key = g_strdup(arg);
}
break;
case 'e':
case 'I':
case 'q':
case 'd':
/* Don't set it as channel mode */
break;
default:
mode_set(newmode, type, *curmode);
break;
umode = (unsigned char) *curmode;
if (server->modes[umode].func != NULL) {
server->modes[umode].func(channel, setby,
type, *curmode, arg,
newmode);
} else {
/* Treat unknown modes as ones without params */
modes_type_d(channel, setby, type, *curmode,
arg, newmode);
}
}
curmode++;
@ -305,7 +331,8 @@ void parse_channel_modes(IRC_CHANNEL_REC *channel, const char *setby,
/* add `mode' to `old' - return newly allocated mode.
`channel' specifies if we're parsing channel mode and we should try
to join mode arguments too. */
char *modes_join(const char *old, const char *mode, int channel)
char *modes_join(IRC_SERVER_REC *server, const char *old,
const char *mode, int channel)
{
GString *newmode;
char *dup, *modestr, *curmode, type;
@ -324,10 +351,10 @@ char *modes_join(const char *old, const char *mode, int channel)
continue;
}
if (!channel || !HAS_MODE_ARG(type, *curmode))
mode_set(newmode, type, *curmode);
if (!channel || !HAS_MODE_ARG(server, type, *curmode))
mode_set(server, newmode, type, *curmode, !channel);
else {
mode_set_arg(newmode, type, *curmode,
mode_set_arg(server, newmode, type, *curmode,
cmd_get_param(&modestr));
}
@ -348,7 +375,7 @@ static void parse_user_mode(IRC_SERVER_REC *server, const char *modestr)
g_return_if_fail(IS_IRC_SERVER(server));
g_return_if_fail(modestr != NULL);
newmode = modes_join(server->usermode, modestr, FALSE);
newmode = modes_join(NULL, server->usermode, modestr, FALSE);
oldmode = server->usermode;
server->usermode = newmode;
server->server_operator = (strchr(newmode, 'o') != NULL);
@ -430,7 +457,7 @@ static void sig_req_usermode_change(IRC_SERVER_REC *server, const char *data,
&target, &mode);
if (!ischannel(*target)) {
/* we requested a user mode change, save this */
mode = modes_join(server->wanted_usermode, mode, FALSE);
mode = modes_join(NULL, server->wanted_usermode, mode, FALSE);
g_free_not_null(server->wanted_usermode);
server->wanted_usermode = mode;
}
@ -520,7 +547,7 @@ void channel_set_mode(IRC_SERVER_REC *server, const char *channel,
}
if (count == server->max_modes_in_cmd &&
HAS_MODE_ARG(type, *curmode)) {
HAS_MODE_ARG(chanrec->server, type, *curmode)) {
irc_send_cmdv(server, "MODE %s %s%s",
channel, tmode->str, targs->str);
@ -535,7 +562,7 @@ void channel_set_mode(IRC_SERVER_REC *server, const char *channel,
}
g_string_append_c(tmode, *curmode);
if (HAS_MODE_ARG(type, *curmode)) {
if (HAS_MODE_ARG(chanrec->server, type, *curmode)) {
char *arg;
count++;
@ -762,6 +789,29 @@ static void cmd_mode(const char *data, IRC_SERVER_REC *server,
cmd_params_free(free_arg);
}
void modes_server_init(IRC_SERVER_REC *server)
{
server->modes['b'].func = modes_type_a;
server->modes['e'].func = modes_type_a;
server->modes['I'].func = modes_type_a;
server->modes['h'].func = modes_type_prefix;
server->modes['h'].prefix = '%';
server->modes['o'].func = modes_type_prefix;
server->modes['o'].prefix = '@';
server->modes['O'].func = modes_type_prefix;
server->modes['O'].prefix = '@';
server->modes['v'].func = modes_type_prefix;
server->modes['v'].prefix = '+';
server->prefix['%'] = 'h';
server->prefix['@'] = 'o';
server->prefix['+'] = 'v';
server->modes['l'].func = modes_type_b;
server->modes['k'].func = modes_type_c;
}
void modes_init(void)
{
settings_add_str("misc", "opermode", "");

View File

@ -1,30 +1,43 @@
#ifndef __MODES_H
#define __MODES_H
#include "irc-channels.h"
typedef void mode_func_t(IRC_CHANNEL_REC *, const char *, char, char,
char *, GString *);
struct modes_type {
mode_func_t *func;
char prefix;
};
/* modes that have argument always */
#define HAS_MODE_ARG_ALWAYS(mode) \
((mode) == 'b' || (mode) == 'e' || (mode) == 'I' || (mode) == 'q' || \
(mode) == 'd' || (mode) == 'o' || (mode) == 'h' || (mode) == 'v' || \
(mode) == 'O' || (mode) == 'k' || (mode) == 'f')
#define HAS_MODE_ARG_ALWAYS(server, mode) \
(server->modes[(int)(unsigned char) mode].func == modes_type_a || \
server->modes[(int)(unsigned char) mode].func == modes_type_b || \
server->modes[(int)(unsigned char) mode].func == modes_type_prefix)
/* modes that have argument when being set (+) */
#define HAS_MODE_ARG_SET(mode) \
(HAS_MODE_ARG_ALWAYS(mode) || (mode) == 'l')
#define HAS_MODE_ARG_SET(server, mode) \
(HAS_MODE_ARG_ALWAYS(server, mode) || \
server->modes[(int)(unsigned char) mode].func == modes_type_c)
/* modes that have argument when being unset (-) */
#define HAS_MODE_ARG_UNSET(mode) \
HAS_MODE_ARG_ALWAYS(mode)
#define HAS_MODE_ARG_UNSET(server, mode) \
HAS_MODE_ARG_ALWAYS(server, mode)
#define HAS_MODE_ARG(type, mode) \
((type) == '+' ? HAS_MODE_ARG_SET(mode) : HAS_MODE_ARG_UNSET(mode))
#define HAS_MODE_ARG(server, type, mode) \
((type) == '+' ? HAS_MODE_ARG_SET(server,mode) : \
HAS_MODE_ARG_UNSET(server, mode))
void modes_init(void);
void modes_deinit(void);
void modes_server_init(IRC_SERVER_REC *);
/* add `mode' to `old' - return newly allocated mode.
`channel' specifies if we're parsing channel mode and we should try
to join mode arguments too. */
char *modes_join(const char *old, const char *mode, int channel);
char *modes_join(IRC_SERVER_REC *server, const char *old, const char *mode, int channel);
int channel_mode_is_set(IRC_CHANNEL_REC *channel, char mode);
@ -36,4 +49,10 @@ void channel_set_singlemode(IRC_CHANNEL_REC *channel, const char *nicks,
void channel_set_mode(IRC_SERVER_REC *server, const char *channel,
const char *mode);
mode_func_t modes_type_a;
mode_func_t modes_type_b;
mode_func_t modes_type_c;
mode_func_t modes_type_d;
mode_func_t modes_type_prefix;
#endif

View File

@ -135,6 +135,7 @@ static NETSPLIT_REC *netsplit_add(IRC_SERVER_REC *server, const char *nick,
splitchan->op = nickrec->op;
splitchan->halfop = nickrec->halfop;
splitchan->voice = nickrec->voice;
splitchan->other = nickrec->other;
rec->channels = g_slist_append(rec->channels, splitchan);
}

View File

@ -28,6 +28,7 @@ typedef struct {
unsigned int op:1;
unsigned int halfop:1;
unsigned int voice:1;
unsigned int other:7;
} NETSPLIT_CHAN_REC;
void netsplit_init(void);

View File

@ -177,7 +177,9 @@ static void dump_join(IRC_CHANNEL_REC *channel, CLIENT_REC *client)
else
g_string_append_c(str, ' ');
if (nick->op)
if (nick->other)
g_string_append_c(str, nick->other);
else if (nick->op)
g_string_append_c(str, '@');
else if (nick->halfop)
g_string_append_c(str, '%');
@ -213,8 +215,15 @@ void proxy_client_reset_nick(CLIENT_REC *client)
client->nick = g_strdup(client->server->nick);
}
static void proxy_dump_data_005(char *key, char *value, GString *output)
{
g_string_sprintfa(output, "%s=%s ", key, value);
}
void proxy_dump_data(CLIENT_REC *client)
{
GString *isupport_out;
proxy_client_reset_nick(client);
/* welcome info */
@ -225,6 +234,17 @@ void proxy_dump_data(CLIENT_REC *client)
proxy_outdata(client, ":%s 004 %s %s %s oirw abiklmnopqstv\n", client->proxy_address, client->nick, client->proxy_address, IRSSI_VERSION);
else
proxy_outdata(client, ":%s 004 %s %s %s oirw abeIiklmnopqstv\n", client->proxy_address, client->nick, client->proxy_address, IRSSI_VERSION);
if (client->server->isupport_sent) {
isupport_out = g_string_new(NULL);
g_string_sprintf(isupport_out, ":%s 005 %s ", client->proxy_address, client->nick);
/* FIXME: should be limited to 15 params */
g_hash_table_foreach(client->server->isupport, proxy_dump_data_005, isupport_out);
g_string_sprintfa(isupport_out, ":are supported by this server\n");
proxy_outdata(client, "%s", isupport_out->str);
g_string_free(isupport_out, TRUE);
}
proxy_outdata(client, ":%s 251 %s :There are 0 users and 0 invisible on 1 servers\n", client->proxy_address, client->nick);
proxy_outdata(client, ":%s 255 %s :I have 0 clients, 0 services and 0 servers\n", client->proxy_address, client->nick);
proxy_outdata(client, ":%s 422 %s :MOTD File is missing\n", client->proxy_address, client->nick);

View File

@ -72,7 +72,7 @@ isnickflag(server, flag)
Irssi::Server server
char flag
CODE:
RETVAL = server->isnickflag(flag);
RETVAL = server->isnickflag(server, flag);
OUTPUT:
RETVAL
@ -89,7 +89,7 @@ char *
get_nick_flags(server)
Irssi::Server server
CODE:
RETVAL = (char *) server->get_nick_flags();
RETVAL = (char *) server->get_nick_flags(server);
OUTPUT:
RETVAL

View File

@ -22,6 +22,7 @@ static void perl_irc_server_fill_hash(HV *hv, IRC_SERVER_REC *server)
hv_store(hv, "max_msgs_in_cmd", 15, newSViv(server->max_msgs_in_cmd), 0);
hv_store(hv, "max_modes_in_cmd", 16, newSViv(server->max_modes_in_cmd), 0);
hv_store(hv, "max_whois_in_cmd", 16, newSViv(server->max_whois_in_cmd), 0);
hv_store(hv, "isupport_sent", 13, newSViv(server->isupport_sent), 0);
}
static void perl_ban_fill_hash(HV *hv, BAN_REC *ban)

View File

@ -4,14 +4,15 @@ MODULE = Irssi::Irc::Modes PACKAGE = Irssi::Irc
PROTOTYPES: ENABLE
void
modes_join(old, mode, channel)
modes_join(server, old, mode, channel)
Irssi::Irc::Server server
char *old
char *mode
int channel
PREINIT:
char *ret;
PPCODE:
ret = modes_join(old, mode, channel);
ret = modes_join(server, old, mode, channel);
XPUSHs(sv_2mortal(new_pv(ret)));
g_free(ret);

View File

@ -129,3 +129,13 @@ CODE:
RETVAL = (char *) server_redirect_peek_signal(server, event, args, &redirection);
OUTPUT:
RETVAL
char *
server_isupport(server, name)
Irssi::Irc::Server server
char *name
CODE:
RETVAL = (char *) g_hash_table_lookup(server->isupport, name);
OUTPUT:
RETVAL

View File

@ -436,6 +436,7 @@ void perl_nick_fill_hash(HV *hv, NICK_REC *nick)
hv_store(hv, "op", 2, newSViv(nick->op), 0);
hv_store(hv, "halfop", 6, newSViv(nick->halfop), 0);
hv_store(hv, "voice", 5, newSViv(nick->voice), 0);
hv_store(hv, "other", 5, newSViv(nick->other), 0);
hv_store(hv, "last_check", 10, newSViv(nick->last_check), 0);
hv_store(hv, "send_massjoin", 13, newSViv(nick->send_massjoin), 0);