--- /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;
+}
+
+