chanuser->flags = 0;
chanuser->user = user;
chanuser->chan = chan;
+
+ chanuser->changeTime = 0;
chanuser->next_user = chan->user;
chan->user = chanuser;
chanuser->flags = CHANUSERFLAG_INVISIBLE;
chanuser->user = user;
chanuser->chan = chan;
+
+ chanuser->changeTime = 0;
chanuser->next_user = chan->user;
chan->user = chanuser;
#ifndef _ChanUser_h
#define _ChanUser_h
+#include "main.h"
#define CHANUSERFLAG_OPPED 0x01
#define CHANUSERFLAG_VOICED 0x02
struct ChanNode *chan;
struct UserNode *user;
+ int chageEvents;
+ time_t changeTime;
+
struct ChanUser *next_user;
struct ChanUser *next_chan;
};
FUNC_BIND(invite, invite_func_t, BIND_TYPE_INVITE)
FUNC_UNBIND(invite, invite_func_t, BIND_TYPE_INVITE)
-FUNC_EVENT(invite, invite_func_t, BIND_TYPE_INVITE, (struct UserNode *user, char *channel), (user, channel))
+FUNC_EVENT(invite, invite_func_t, BIND_TYPE_INVITE, (struct ClientSocket *client, struct UserNode *user, char *channel), (client, user, channel))
FUNC_BIND(raw, raw_func_t, BIND_TYPE_RAW)
FUNC_UNBIND(raw, raw_func_t, BIND_TYPE_RAW)
void unbind_privctcp(privctcp_func_t *func);
int event_privctcp(struct UserNode *user, struct UserNode *target, char *command, char *text);
-typedef void invite_func_t(struct UserNode *user, char *channel);
+typedef void invite_func_t(struct ClientSocket *client, struct UserNode *user, char *channel);
int bind_invite(invite_func_t *func);
void unbind_invite(invite_func_t *func);
-int event_invite(struct UserNode *user, char *channel);
+int event_invite(struct ClientSocket *client, struct UserNode *user, char *channel);
typedef void raw_func_t(struct ClientSocket *client, char *from, char *cmd, char **argv, int argc);
int bind_raw(raw_func_t *func);
static IRC_CMD(raw_invite) {
if(from == NULL || argc < 2) return 0;
struct UserNode *user = getUserByMask(from);
- event_invite(user, argv[1]);
+ event_invite(client, user, argv[1]);
return 1;
}
{"NS_SEARCH_HEADER", "The following channels were found:"},
{"NS_COMMAND_BINDING", "$b%s$b is a binding of %s %s"}, /* {ARGS: "TestCommand", "TestFunction", "TestParameters"} */
{"NS_COMMAND_ACCESS", "You need at least %d channel access and %d oper access to execute this command."}, /* {ARGS: 500, 100} */
+ {"NS_TOPIC_ACCESS", "You lack sufficient access in %s to change the topic."}, /* {ARGS: "#TestChan"} */
+ {"NS_BOTWAR_DETECTED", "$b$k4BOTWAR DETECTED!$k Please check the channel configuration!$b"},
+ {"NS_BOTWAR_REPORTED", "A supporter has been informed to help you preventing botwars in the future."},
+ {"NS_BOTWAR_ALERT", "$b$k4BOTWAR ALERT:$k$b Botwar in $b%s$b detected. (opponent: $b%s$b) Please join and help them preventing Botwars."}, /* {ARGS: "#TestChan", "OtherBot"} */
+ {"NS_INVITE_FAIL", "$b%s$b is not registered with %s or suspended."}, /* {ARGS: "#TestChan", "NeonServ"} */
{NULL, NULL}
};
#include "cmd_neonserv_raw.c"
#include "cmd_neonserv_reloadlang.c"
#include "cmd_neonserv_oplog.c"
+//#include "cmd_neonserv_rename.c"
//HARDCODED FUN CMD's
//#include "cmd_neonserv_iplocate.c"
//#include "event_neonserv_mode.c"
#include "event_neonserv_ctcp.c"
#include "event_neonserv_notice.c"
-//#include "event_neonserv_invite.c"
-//#include "event_neonserv_topic.c"
+#include "event_neonserv_invite.c"
+#include "event_neonserv_topic.c"
static struct ClientSocket *getBotForChannel(struct ChanNode *chan) {
struct ClientSocket *bot, *use_bot = NULL, *second_bot = NULL, *third_bot = NULL;
bind_chanctcp(neonserv_event_chanctcp);
bind_privctcp(neonserv_event_privctcp);
bind_channotice(neonserv_event_channotice);
+ bind_topic(neonserv_event_topic);
+ bind_invite(neonserv_event_invite);
set_trigger_callback(BOTID, neonserv_trigger_callback);
--- /dev/null
+
+static void neonserv_event_invite(struct ClientSocket *client, struct UserNode *user, char *channel) {
+ MYSQL_RES *res;
+ MYSQL_ROW row;
+ printf_mysql_query("SELECT `botid`, `bot_channels`.`id`, `suspended` FROM `bot_channels` LEFT JOIN `bots` ON `bot_channels`.`botid` = `bots`.`id` LEFT JOIN `channels` ON `chanid` = `channel_id` WHERE `channel_name` = '%s' AND `botclass` = '%d'", escape_string(channel), client->botid);
+ res = mysql_use();
+ if ((row = mysql_fetch_row(res)) == NULL) {
+ reply(client, user, "NS_INVITE_FAIL", channel, client->user->nick);
+ return;
+ }
+ int botid = atoi(row[0]);
+ struct ClientSocket *bot;
+ for(bot = getBots(SOCKET_FLAG_READY, NULL); bot; bot = getBots(SOCKET_FLAG_READY, bot)) {
+ if(bot->clientid == botid)
+ break;
+ }
+ if(bot) {
+ struct ChanNode *chan = getChanByName(channel);
+ if(chan && isUserOnChan(bot->user, chan)) {
+ reply(client, user, "NS_INVITE_ON_CHAN", bot->user->nick, chan->name);
+ } else
+ putsock(bot, "JOIN %s", channel);
+ }
+}
+
--- /dev/null
+
+struct neonserv_event_topic_cache {
+ struct ClientSocket *client;
+ struct UserNode *user;
+ struct ChanNode *chan;
+ char *new_topic;
+};
+
+static USERAUTH_CALLBACK(neonserv_event_topic_nick_lookup);
+static void neonserv_event_topic_async1(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, const char *new_topic);
+
+static void neonserv_event_topic(struct UserNode *user, struct ChanNode *chan, const char *new_topic) {
+ struct ClientSocket *client = getBotForChannel(chan);
+ if(!client) return; //we can't "see" this event
+ if(user->flags & (USERFLAG_ISBOT | USERFLAG_ISIRCOP)) return;
+ loadChannelSettings(chan);
+ if(!(chan->flags & CHANFLAG_CHAN_REGISTERED)) return;
+ if(!(user->flags & USERFLAG_ISAUTHED)) {
+ struct neonserv_event_topic_cache *cache = malloc(sizeof(*cache));
+ if (!cache) {
+ perror("malloc() failed");
+ return;
+ }
+ cache->client = client;
+ cache->user = user;
+ cache->chan = chan;
+ cache->new_topic = strdup(new_topic);
+ get_userauth(user, neonserv_event_topic_nick_lookup, cache);
+ } else
+ neonserv_event_topic_async1(client, user, chan, new_topic);
+}
+
+static USERAUTH_CALLBACK(neonserv_event_topic_nick_lookup) {
+ struct neonserv_event_topic_cache *cache = data;
+ if(user) {
+ neonserv_event_topic_async1(cache->client, cache->user, cache->chan, cache->new_topic);
+ }
+ free(cache->new_topic);
+ free(cache);
+}
+
+static void neonserv_event_topic_async1(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, const char *new_topic) {
+ MYSQL_RES *res;
+ MYSQL_ROW row, defaultrow = NULL, chanuserrow;
+ int uaccess = 0;
+ printf_mysql_query("SELECT `channel_changetopic`, `channel_topicsnarf` FROM `channels` WHERE `channel_id` = '%d'", chan->channel_id);
+ res = mysql_use();
+ if ((row = mysql_fetch_row(res)) == NULL) return;
+ if(!row[0] || !row[1]) {
+ printf_mysql_query("SELECT `channel_changetopic`, `channel_topicsnarf` FROM `channels` WHERE `channel_name` = 'defaults'");
+ res = mysql_use();
+ defaultrow = mysql_fetch_row(res);
+ }
+ int changetopic = atoi((row[0] ? row[0] : defaultrow[0]));
+ int topicsnarf = atoi((row[1] ? row[1] : defaultrow[1]));
+ if((user->flags & USERFLAG_ISAUTHED)) {
+ printf_mysql_query("SELECT `chanuser_access`, `chanuser_flags` FROM `chanusers` LEFT JOIN `users` ON `chanuser_uid` = `user_id` WHERE `chanuser_cid` = '%d' AND `user_user` = '%s'", chan->channel_id, escape_string(user->auth));
+ res = mysql_use();
+ chanuserrow = mysql_fetch_row(res);
+ if(chanuserrow)
+ uaccess = ((atoi(chanuserrow[1]) & DB_CHANUSER_SUSPENDED) ? 0 : atoi(chanuserrow[0]));
+ }
+ if(uaccess < changetopic) {
+ //undo topic change
+ struct ClientSocket *textclient = ((client->flags & SOCKET_FLAG_PREFERRED) ? client : get_prefered_bot(client->botid));
+ struct ChanUser *chanuser = getChanUser(user, chan);
+ if(!chanuser) return; //flying super cow?
+ if(time(0) - chanuser->changeTime > BOTWAR_DETECTION_TIME) {
+ chanuser->changeTime = time(0);
+ chanuser->chageEvents = 1;
+ } else {
+ chanuser->chageEvents++;
+ if(chanuser->chageEvents >= BOTWAR_DETECTION_EVENTS || chanuser->chageEvents < 0) {
+ //BOTWAR!
+ chanuser->changeTime = time(0);
+ if(chanuser->chageEvents > 0) {
+ putsock(client, "NOTICE @%s :%s %s", chan->name, get_language_string(user, "NS_BOTWAR_DETECTED"), (BOTWAR_ALERT_CHAN ? get_language_string(user, "NS_BOTWAR_REPORTED") : ""));
+ if(BOTWAR_ALERT_CHAN) {
+ struct ChanNode *alertchan = getChanByName(BOTWAR_ALERT_CHAN);
+ struct ClientSocket *alertclient;
+ if(alertchan && (alertclient = getBotForChannel(chan)) != NULL) {
+ char msgBuf[MAXLEN];
+ putsock(alertclient, "PRIVMSG %s :%s", alertchan->name, build_language_string(user, msgBuf, "NS_BOTWAR_ALERT", chan->name, user->nick));
+ }
+ }
+ }
+ chanuser->chageEvents = -2;
+ return;
+ }
+ }
+ reply(textclient, user, "NS_TOPIC_ACCESS", chan->name);
+ putsock(client, "TOPIC %s :%s", chan->name, chan->topic);
+ } else if(uaccess >= topicsnarf) {
+ printf_mysql_query("UPDATE `channels` SET `channel_defaulttopic` = '%s' WHERE `channel_id` = '%d'", escape_string(new_topic), chan->channel_id);
+ }
+}
+
#define NEONSERV_VERSION "5.0.1-dev"
#include "config.h"
+#ifndef BOTWAR_ALERT_CHAN
+#define BOTWAR_ALERT_CHAN NULL
+#endif
#include <stdio.h>
#include <stdlib.h>
#define MAXLANGUAGES 5
#define MAXMODES 6
#define INVITE_TIMEOUT 30
+#define BOTWAR_DETECTION_TIME 7
+#define BOTWAR_DETECTION_EVENTS 6
//valid nick chars
#define VALID_NICK_CHARS "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890{|}~[\\]^-_`"