*/
#include "bot_NeonSpam.h"
+#include "modcmd.h"
+#include "IRCParser.h"
+#include "IRCEvents.h"
+#include "UserNode.h"
+#include "ChanNode.h"
+#include "ChanUser.h"
+#include "ModeNode.h"
+#include "BanNode.h"
+#include "ClientSocket.h"
+#include "mysqlConn.h"
+#include "lang.h"
+#include "HandleInfoHandler.h"
+#include "WHOHandler.h"
+#include "DBHelper.h"
+#include "tools.h"
+#include "timeq.h"
+#include "version.h"
+#include "EventLogger.h"
+#include "bots.h"
#include "cmd_neonserv.h"
#define BOTID 2
{NULL, NULL}
};
+static int loadNeonSpamSettings(struct ChanNode *chan);
+static void createSpamNode(struct ChanUser *chanuser);
+
//EVENTS
//#include "event_neonspam_join.c"
+#include "event_neonspam_chanmsg.c"
static void neonspam_bot_ready(struct ClientSocket *client) {
MYSQL_RES *res;
}
}
}
-
+}
+
+static int loadNeonSpamSettings(struct ChanNode *chan) {
+ struct NeonSpamSettings *settings = malloc(sizeof(*settings));
+ if(!settings) {
+ perror("malloc() failed");
+ return 0;
+ }
+ settings->flags = SPAMSETTINGS_SCANVOICE | SPAMSETTINGS_FLOODSCAN | SPAMSETTINGS_SPAMSCAN;
+ settings->spam_amount = 3;
+ settings->flood_amount = 4;
+ settings->flood_time = 5;
+ chan->spam_settings = settings;
+ return 1;
+}
+
+static void createSpamNode(struct ChanUser *chanuser) {
+ struct NeonSpamNode *spamnode = malloc(sizeof(*spamnode));
+ if(!spamnode) {
+ perror("malloc() failed");
+ return;
+ }
+ spamnode->lastmsg = 0;
+ spamnode->spamcount = 0;
+ spamnode->floodpenalty = 0;
+ spamnode->last_penalty_update = time(0);
+ chanuser->spamnode = spamnode;
}
void init_NeonSpam() {
//register events
bind_bot_ready(neonspam_bot_ready);
//bind_join(neonspam_event_join);
+ bind_chanmsg(neonspam_event_chanmsg);
bind_privctcp(general_event_privctcp);
set_trigger_callback(BOTID, neonspam_trigger_callback);
--- /dev/null
+/* event_neonspam_chanmsg.c - NeonServ v5.1
+ * Copyright (C) 2011 Philipp Kreil (pk910)
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#define SPAMSERV_CHECK_IGNORE 0
+#define SPAMSERV_CHECK_WARN 1
+#define SPAMSERV_CHECK_PUNISH 2
+
+static int neonspam_spamscan(struct NeonSpamSettings *settings, struct ChanUser *chanuser, char *message);
+static int neonspam_floodscan(struct NeonSpamSettings *settings, struct ChanUser *chanuser);
+
+static void neonspam_event_chanmsg(struct UserNode *user, struct ChanNode *chan, char *message) {
+ struct ClientSocket *client = getChannelBot(chan, BOTID);
+ if(!client) return; //we can't "see" this event
+ loadNeonSpamSettings(chan);
+ struct NeonSpamSettings *settings = chan->spam_settings;
+ struct ChanUser *chanuser = getChanUser(user, chan);
+ if(!settings || !chanuser) return;
+
+ //ignore messages from ops/voices if we ignore them
+ if(!(settings->flags & SPAMSETTINGS_SCANOPS) && (chanuser->flags & CHANUSERFLAG_OPPED)) return;
+ if(!(settings->flags & SPAMSETTINGS_SCANVOICE) && (chanuser->flags & CHANUSERFLAG_VOICED)) return;
+
+ //scan the message
+ int result = 0;
+ if(settings->flags & SPAMSETTINGS_SPAMSCAN) {
+ result = neonspam_spamscan(settings, chanuser, message);
+ switch(result) {
+ case SPAMSERV_CHECK_IGNORE:
+ break;
+ case SPAMSERV_CHECK_WARN:
+ reply(client, user, "SPAM WARNING!");
+ break;
+ case SPAMSERV_CHECK_PUNISH:
+ reply(client, user, "SPAM PUNISHMENT!");
+ break;
+ }
+ }
+ if(settings->flags & SPAMSETTINGS_FLOODSCAN) {
+ result = neonspam_floodscan(settings, chanuser);
+ switch(result) {
+ case SPAMSERV_CHECK_IGNORE:
+ break;
+ case SPAMSERV_CHECK_WARN:
+ reply(client, user, "FLOOD WARNING!");
+ break;
+ case SPAMSERV_CHECK_PUNISH:
+ reply(client, user, "FLOOD PUNISHMENT!");
+ break;
+ }
+ }
+
+}
+
+static int neonspam_spamscan(struct NeonSpamSettings *settings, struct ChanUser *chanuser, char *message) {
+ //crc32 hash of the message
+ unsigned long msghash = crc32(message);
+ if(chanuser->spamnode) {
+ if(chanuser->spamnode->lastmsg == msghash) {
+ chanuser->spamnode->spamcount++;
+ if(chanuser->spamnode->spamcount == settings->spam_amount)
+ return SPAMSERV_CHECK_WARN;
+ else if(chanuser->spamnode->spamcount > settings->spam_amount)
+ return SPAMSERV_CHECK_PUNISH;
+ else
+ return SPAMSERV_CHECK_IGNORE;
+ }
+ } else
+ createSpamNode(chanuser);
+ chanuser->spamnode->lastmsg = msghash;
+ chanuser->spamnode->spamcount = 1;
+ return SPAMSERV_CHECK_IGNORE;
+}
+
+static int neonspam_update_penalty(struct NeonSpamSettings *settings, struct ChanUser *chanuser, int addmsg) {
+ int last_update = time(0) - chanuser->spamnode->last_penalty_update;
+ if(last_update) {
+ if(last_update < MAX_FLOOD_TIME && chanuser->spamnode->floodpenalty) {
+ chanuser->spamnode->floodpenalty -= last_update * (MAX_FLOOD_TIME / settings->flood_time);
+ if(chanuser->spamnode->floodpenalty < 0)
+ chanuser->spamnode->floodpenalty = 0;
+ } else
+ chanuser->spamnode->floodpenalty = 0;
+ chanuser->spamnode->last_penalty_update = time(0);
+ }
+ chanuser->spamnode->floodpenalty += MAX_FLOOD_TIME * addmsg;
+ return chanuser->spamnode->floodpenalty / MAX_FLOOD_TIME + ((chanuser->spamnode->floodpenalty % MAX_FLOOD_TIME) ? 1 : 0);
+}
+
+static int neonspam_floodscan(struct NeonSpamSettings *settings, struct ChanUser *chanuser) {
+ if(!chanuser->spamnode)
+ createSpamNode(chanuser);
+ int messages_pending = neonspam_update_penalty(settings, chanuser, 1);
+ if(messages_pending == settings->flood_amount)
+ return SPAMSERV_CHECK_WARN;
+ else if(messages_pending > settings->flood_amount)
+ return SPAMSERV_CHECK_PUNISH;
+ else
+ return SPAMSERV_CHECK_IGNORE;
+}
+
+