summaryrefslogtreecommitdiff
path: root/src/irc/bot/bot-events.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/irc/bot/bot-events.c')
-rw-r--r--src/irc/bot/bot-events.c199
1 files changed, 199 insertions, 0 deletions
diff --git a/src/irc/bot/bot-events.c b/src/irc/bot/bot-events.c
new file mode 100644
index 00000000..ebbe0660
--- /dev/null
+++ b/src/irc/bot/bot-events.c
@@ -0,0 +1,199 @@
+/*
+ bot-events.c : IRC bot plugin for irssi
+
+ Copyright (C) 1999 Timo Sirainen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include "module.h"
+#include "signals.h"
+#include "commands.h"
+
+#include "irc.h"
+#include "irc-server.h"
+#include "channels.h"
+#include "nicklist.h"
+#include "modes.h"
+#include "netsplit.h"
+
+#include "bot-users.h"
+
+static int get_flags(USER_REC *user, CHANNEL_REC *channel)
+{
+ USER_CHAN_REC *userchan;
+
+ g_return_val_if_fail(user != NULL, 0);
+ g_return_val_if_fail(channel != NULL, 0);
+
+ userchan = g_hash_table_lookup(user->channels, channel->name);
+ return (user->flags | (userchan == NULL ? 0 : userchan->flags)) &
+ (~user->not_flags);
+}
+
+static void event_massjoin(CHANNEL_REC *channel, GSList *users)
+{
+ USER_REC *user;
+ USER_CHAN_REC *userchan;
+ NICK_REC *nick;
+ GString *modestr, *nickstr;
+ int flags;
+
+ g_return_if_fail(channel != NULL);
+ g_return_if_fail(users != NULL);
+
+ modestr = g_string_new(NULL);
+ nickstr = g_string_new(NULL);
+
+ for (; users != NULL; users = users->next) {
+ user = users->data;
+ userchan = g_hash_table_lookup(user->channels, channel->name);
+ nick = userchan->nickrec;
+
+ flags = get_flags(user, channel);
+ if (!nick->op && (flags & USER_AUTO_OP)) {
+ g_string_sprintfa(modestr, "+o");
+ g_string_sprintfa(nickstr, "%s,", nick->nick);
+ }
+
+ if (!nick->voice && !nick->op && (flags & USER_AUTO_VOICE)) {
+ g_string_sprintfa(modestr, "+v");
+ g_string_sprintfa(nickstr, "%s,", nick->nick);
+ }
+ }
+
+ if (nickstr->len > 0) {
+ g_string_truncate(nickstr, nickstr->len-1);
+ g_string_sprintfa(modestr, " %s", nickstr->str);
+
+ channel_set_mode(channel->server, channel->name, modestr->str);
+ }
+
+ g_string_free(modestr, TRUE);
+ g_string_free(nickstr, TRUE);
+}
+
+/* Parse channel mode string */
+static void parse_channel_mode(CHANNEL_REC *channel, const char *mode,
+ const char *nick, const char *address)
+{
+ NICK_REC *nickrec, *splitnick;
+ USER_REC *user;
+ GString *str;
+ char *ptr, *curmode, type, *dup, *modestr;
+ int flags;
+
+ g_return_if_fail(channel != NULL);
+ g_return_if_fail(nick != NULL);
+ g_return_if_fail(modestr != NULL);
+
+ user = botuser_find(nick, address);
+ flags = user == NULL ? 0 : get_flags(user, channel);
+
+ if (!channel->chanop || (flags & USER_MASTER) ||
+ g_strcasecmp(nick, channel->server->nick) == 0) {
+ /* can't do anything or we/master did mode change,
+ don't bother checking what */
+ return;
+ }
+
+ str = g_string_new(NULL);
+ dup = modestr = g_strdup(mode);
+
+ type = '+';
+ curmode = cmd_get_param(&modestr);
+ for (; *curmode != '\0'; curmode++) {
+ if (*curmode == '+' || *curmode == '-') {
+ type = *curmode;
+ continue;
+ }
+
+ if (!HAS_MODE_ARG(*curmode))
+ ptr = NULL;
+ else {
+ ptr = cmd_get_param(&modestr);
+ if (*ptr == '\0') continue;
+ }
+
+ if (*curmode != 'o')
+ continue;
+
+ if (type == '-' && strcmp(channel->server->nick, ptr) == 0) {
+ /* we aren't chanop anymore .. */
+ g_string_truncate(str, 0);
+ break;
+ }
+
+ if (type != '+')
+ continue;
+
+ /* check that op is valid */
+ nickrec = nicklist_find(channel, ptr);
+ if (nickrec == NULL || nickrec->host == NULL)
+ continue;
+
+ user = botuser_find(ptr, nickrec->host);
+ flags = user == NULL ? 0 : get_flags(user, channel);
+ if (flags & USER_OP)
+ continue;
+
+ if (address == NULL) {
+ /* server opped, check if user was opped before netsplit. */
+ splitnick = netsplit_find_channel(channel->server, nickrec->nick, nickrec->host, channel->name);
+ if (splitnick != NULL && splitnick->op)
+ continue;
+ }
+
+ /* this one isn't supposed to get ops! */
+ g_string_sprintfa(str, "%s ", ptr);
+ }
+ g_free(dup);
+
+ if (str->len != 0)
+ signal_emit("command deop", 3, str->str, channel->server, channel);
+ g_string_free(str, TRUE);
+}
+
+static void event_mode(const char *data, IRC_SERVER_REC *server,
+ const char *nick, const char *address)
+{
+ CHANNEL_REC *chanrec;
+ char *params, *channel, *mode;
+
+ g_return_if_fail(data != NULL);
+
+ params = event_get_params(data, 2 | PARAM_FLAG_GETREST, &channel, &mode);
+
+ if (ischannel(*channel)) {
+ /* channel mode change */
+ chanrec = channel_find(server, channel);
+ if (chanrec != NULL)
+ parse_channel_mode(chanrec, mode, nick, address);
+ }
+
+ g_free(params);
+}
+
+void bot_events_init(void)
+{
+ signal_add_last("bot massjoin", (SIGNAL_FUNC) event_massjoin);
+ signal_add("event mode", (SIGNAL_FUNC) event_mode);
+}
+
+void bot_events_deinit(void)
+{
+ signal_remove("bot massjoin", (SIGNAL_FUNC) event_massjoin);
+ signal_remove("event mode", (SIGNAL_FUNC) event_mode);
+}