diff --git a/src/chatcleaner/cleanerconfig.cpp b/src/chatcleaner/cleanerconfig.cpp index 50d78575..341316ea 100644 --- a/src/chatcleaner/cleanerconfig.cpp +++ b/src/chatcleaner/cleanerconfig.cpp @@ -43,7 +43,7 @@ using namespace std; CleanerConfig::CleanerConfig() { // !!!! Revisionsnummer der Configdefaults !!!!! - configRev = 7; + configRev = 8; // Pfad und Dateinamen setzen #ifdef _WIN32 @@ -121,6 +121,9 @@ CleanerConfig::CleanerConfig() configList.push_back(ConfigInfo("TextFloodLevelToTrigger", CONFIG_TYPE_INT, "3")); configList.push_back(ConfigInfo("CapsFloodCapsNumberToTrigger", CONFIG_TYPE_INT, "10")); configList.push_back(ConfigInfo("LetterRepeatingNumberToTrigger", CONFIG_TYPE_INT, "10")); + + configList.push_back(ConfigInfo("KickNumberToBan", CONFIG_TYPE_INT, "2")); + configList.push_back(ConfigInfo("SecondsToForgetAboutKick", CONFIG_TYPE_INT, "1800")); list badWordsList; badWordsList.push_back("arsch"); diff --git a/src/chatcleaner/messagefilter.cpp b/src/chatcleaner/messagefilter.cpp index bd8576a4..90fb3a21 100644 --- a/src/chatcleaner/messagefilter.cpp +++ b/src/chatcleaner/messagefilter.cpp @@ -10,156 +10,201 @@ #include "urlcheck.h" enum ActionType { - NOTHING, - WARN, - KICK }; + NOTHING, + WARN, + KICK, + KICKBAN +}; enum OffenceType { - NONE, - BAD_WORD, - TEXT_FLOOD_LINES, - CAPS_FLOOD, - LETTER_REPEATING, - URL + NONE, + BAD_WORD, + TEXT_FLOOD_LINES, + CAPS_FLOOD, + LETTER_REPEATING, + URL }; MessageFilter::MessageFilter(CleanerConfig *c): config(c) { - myBadWordCheck = new BadWordCheck; - myTextFloodCheck = new TextFloodCheck; - myCapsFloodCheck = new CapsFloodCheck; - myLetterRepeatingCheck = new LetterRepeatingCheck; - myUrlCheck = new UrlCheck; + myBadWordCheck = new BadWordCheck; + myTextFloodCheck = new TextFloodCheck; + myCapsFloodCheck = new CapsFloodCheck; + myLetterRepeatingCheck = new LetterRepeatingCheck; + myUrlCheck = new UrlCheck; + + cleanTimer = new QTimer(); + connect(cleanTimer, SIGNAL(timeout()), this, SLOT(cleanKickCounterList())); + cleanTimer->start(30000); } MessageFilter::~MessageFilter() { - delete myBadWordCheck; - delete myTextFloodCheck; - delete myCapsFloodCheck; - delete myLetterRepeatingCheck; - delete myUrlCheck; + delete myBadWordCheck; + delete myTextFloodCheck; + delete myCapsFloodCheck; + delete myLetterRepeatingCheck; + delete myUrlCheck; + delete cleanTimer; } QStringList MessageFilter::check(unsigned playerId, QString nick, QString msg) { - QStringList returnList; - QString returnMessage; - QString returnAction; - - OffenceType offence = NONE; - ActionType action = NOTHING; - - if(myBadWordCheck->run(msg)) offence = BAD_WORD; - if(myCapsFloodCheck->run(msg)) offence = CAPS_FLOOD; - if(myLetterRepeatingCheck->run(msg)) offence = LETTER_REPEATING; - if(myUrlCheck->run(msg)) offence = URL; - if(myTextFloodCheck->run(playerId)) offence = TEXT_FLOOD_LINES; - - if(offence){ - - QMap::const_iterator i = myClientWarnLevelList.find(playerId); - - if(i == myClientWarnLevelList.end()) { - ClientWarnInfos tmpInfos; - tmpInfos.warnLevel = 1; - tmpInfos.lastWarnType = offence; - tmpInfos.nick = nick; - myClientWarnLevelList.insert(playerId, tmpInfos); - action = WARN; - } - else { - if(i.value().warnLevel == warnLevelToKick || i.value().lastWarnType == offence) { -// Kick Command - action = KICK; - //remove playerId from all lists and as LAST from myClientWarnLevelList - myTextFloodCheck->removeNickFromList(i.key()); - myClientWarnLevelList.remove(i.key()); - } - else { - ClientWarnInfos tmpInfos; - tmpInfos.warnLevel = i.value().warnLevel+1; - tmpInfos.lastWarnType = offence; - tmpInfos.nick = nick; - myClientWarnLevelList.insert(playerId, tmpInfos); - action = WARN; - } - } - - if(action == KICK) { - returnMessage = QString("Kick: %1\n").arg(nick); - returnAction = QString("kick"); - } - if(action == WARN) { - - switch(offence) { - case BAD_WORD: { - returnMessage = QString ("%1: Warning! No racial, religious, or sexually inflammatory language!\n").arg(nick); - } - break; - case TEXT_FLOOD_LINES: { - returnMessage = QString ("%1: Warning! You've triggered text flood (lines) protection, slow down your typing!\n").arg(nick); - } - break; - case CAPS_FLOOD: { - returnMessage = QString ("%1: Warning: You've triggered caps flood protection, release your caps!\n").arg(nick); - } - break; - case LETTER_REPEATING: { - returnMessage = QString ("%1: Warning: You've triggered letter repeating protection, stop repeating!\n").arg(nick); - } - break; - case URL: { - returnMessage = QString ("%1: Warning: You've triggered url spam protection, stop posting urls!\n").arg(nick); - } - break; - default:; - } - returnAction = QString("warn"); - } - } - else { - returnAction = QString(""); - returnMessage = QString(""); - } + QStringList returnList; + QString returnMessage; + QString returnAction; - returnList << returnAction << returnMessage; - return returnList; + OffenceType offence = NONE; + ActionType action = NOTHING; + + if(myBadWordCheck->run(msg)) offence = BAD_WORD; + if(myCapsFloodCheck->run(msg)) offence = CAPS_FLOOD; + if(myLetterRepeatingCheck->run(msg)) offence = LETTER_REPEATING; + if(myUrlCheck->run(msg)) offence = URL; + if(myTextFloodCheck->run(playerId)) offence = TEXT_FLOOD_LINES; + + if(offence){ + + QMap::const_iterator i = myClientWarnLevelList.find(playerId); + + if(i == myClientWarnLevelList.end()) { + ClientWarnInfos tmpInfos; + tmpInfos.warnLevel = 1; + tmpInfos.lastWarnType = offence; + tmpInfos.nick = nick; + myClientWarnLevelList.insert(playerId, tmpInfos); + action = WARN; + } + else { + if(i.value().warnLevel == warnLevelToKick || i.value().lastWarnType == offence) { + // Kick Command + action = KICK; + //remove playerId from all lists and as LAST from myClientWarnLevelList + myTextFloodCheck->removeNickFromList(i.key()); + myClientWarnLevelList.remove(i.key()); + //check if player is already on kickCounterList + QMap::const_iterator j = myClientKickCounterList.find(nick); + if(j == myClientKickCounterList.end()) { + //if player is NOT on this list put the playerId on it to ban after multiple offence + ClientKickInfos tmpInfos; + tmpInfos.kickNumber = 1; + tmpInfos.lastKickTimestamp = timer.elapsed().total_seconds(); + myClientKickCounterList.insert(nick, tmpInfos); + } + else { + //please is already on the list: either raise kickNumber or kickban when kickNumerToBan is reached + if(j.value().kickNumber == kickNumberToBan) { + action = KICKBAN; + } + else { + ClientKickInfos tmpInfos; + tmpInfos.kickNumber = j.value().kickNumber+1; + tmpInfos.lastKickTimestamp = timer.elapsed().total_seconds(); + myClientKickCounterList.insert(nick, tmpInfos); + } + } + } + else { + ClientWarnInfos tmpInfos; + tmpInfos.warnLevel = i.value().warnLevel+1; + tmpInfos.lastWarnType = offence; + tmpInfos.nick = nick; + myClientWarnLevelList.insert(playerId, tmpInfos); + action = WARN; + } + } + + if(action == WARN) { + + switch(offence) { + case BAD_WORD: { + returnMessage = QString ("%1: Warning! No racial, religious, or sexually inflammatory language!\n").arg(nick); + } + break; + case TEXT_FLOOD_LINES: { + returnMessage = QString ("%1: Warning! You've triggered text flood (lines) protection, slow down your typing!\n").arg(nick); + } + break; + case CAPS_FLOOD: { + returnMessage = QString ("%1: Warning: You've triggered caps flood protection, release your caps!\n").arg(nick); + } + break; + case LETTER_REPEATING: { + returnMessage = QString ("%1: Warning: You've triggered letter repeating protection, stop repeating!\n").arg(nick); + } + break; + case URL: { + returnMessage = QString ("%1: Warning: You've triggered url spam protection, stop posting urls!\n").arg(nick); + } + break; + default:; + } + returnAction = QString("warn"); + } + else if(action == KICK) { + returnMessage = QString("%1 kicked! Please respect: http://chatrules.pokerth.net\n").arg(nick); + returnAction = QString("kick"); + } + else if(action == KICKBAN) { + returnMessage = QString("%1 kicked and banned! Please respect: http://chatrules.pokerth.net\n").arg(nick); + returnAction = QString("kickban"); + } + } + else { + returnAction = QString(""); + returnMessage = QString(""); + } + + returnList << returnAction << returnMessage; + return returnList; } void MessageFilter::refreshConfig() { - // global settings - warnLevelToKick = config->readConfigInt("WarnLevelToKick"); - - // special check settings - //Bad Words - std::list badWordsList = config->readConfigStringList("BadWordsList"); - std::list::iterator it1; - QStringList bwList; - for(it1= badWordsList.begin(); it1 != badWordsList.end(); it1++) { - bwList << QString::fromUtf8(it1->c_str()); - } - myBadWordCheck->setBadWords(bwList); - - std::list urlStringsList = config->readConfigStringList("UrlStringsList"); - std::list::iterator it2; - QStringList urlList; - for(it2= urlStringsList.begin(); it2 != urlStringsList.end(); it2++) { - urlList << QString::fromUtf8(it2->c_str()); - } - myUrlCheck->setUrlStrings(urlList); - - std::list urlExceptionStringsList = config->readConfigStringList("UrlExceptionStringsList"); - std::list::iterator it3; - QStringList urlExceptionList; - for(it3= urlExceptionStringsList.begin(); it3 != urlExceptionStringsList.end(); it3++) { - urlExceptionList << QString::fromUtf8(it3->c_str()); - } - myUrlCheck->setUrlExceptionStrings(urlExceptionList); - - myTextFloodCheck->setTextFloodLevelToTrigger(config->readConfigInt("TextFloodLevelToTrigger")); - myCapsFloodCheck->setCapsNumberToTrigger(config->readConfigInt("CapsFloodCapsNumberToTrigger")); - myLetterRepeatingCheck->setLetterNumberToTrigger(config->readConfigInt("LetterRepeatingNumberToTrigger")); + // global settings + warnLevelToKick = config->readConfigInt("WarnLevelToKick"); + kickNumberToBan = config->readConfigInt("KickNumberToBan"); + + // special check settings + //Bad Words + std::list badWordsList = config->readConfigStringList("BadWordsList"); + std::list::iterator it1; + QStringList bwList; + for(it1= badWordsList.begin(); it1 != badWordsList.end(); it1++) { + bwList << QString::fromUtf8(it1->c_str()); + } + myBadWordCheck->setBadWords(bwList); + + std::list urlStringsList = config->readConfigStringList("UrlStringsList"); + std::list::iterator it2; + QStringList urlList; + for(it2= urlStringsList.begin(); it2 != urlStringsList.end(); it2++) { + urlList << QString::fromUtf8(it2->c_str()); + } + myUrlCheck->setUrlStrings(urlList); + + std::list urlExceptionStringsList = config->readConfigStringList("UrlExceptionStringsList"); + std::list::iterator it3; + QStringList urlExceptionList; + for(it3= urlExceptionStringsList.begin(); it3 != urlExceptionStringsList.end(); it3++) { + urlExceptionList << QString::fromUtf8(it3->c_str()); + } + myUrlCheck->setUrlExceptionStrings(urlExceptionList); + + myTextFloodCheck->setTextFloodLevelToTrigger(config->readConfigInt("TextFloodLevelToTrigger")); + myCapsFloodCheck->setCapsNumberToTrigger(config->readConfigInt("CapsFloodCapsNumberToTrigger")); + myLetterRepeatingCheck->setLetterNumberToTrigger(config->readConfigInt("LetterRepeatingNumberToTrigger")); } + +void MessageFilter::cleanKickCounterList() +{ + QMapIterator it(myClientKickCounterList); + while (it.hasNext()) { + it.next(); + if(timer.elapsed().total_seconds()-it.value().lastKickTimestamp > config->readConfigInt("SecondsToForgetAboutKick")) { + qDebug() << it.key() << "removed from kick counter list" << endl; + myClientKickCounterList.remove(it.key()); + } + } +} diff --git a/src/chatcleaner/messagefilter.h b/src/chatcleaner/messagefilter.h index 545636c0..8d23b1b4 100644 --- a/src/chatcleaner/messagefilter.h +++ b/src/chatcleaner/messagefilter.h @@ -3,6 +3,7 @@ #include #include +#include class BadWordCheck; class TextFloodCheck; @@ -19,6 +20,7 @@ public: QStringList check(unsigned, QString, QString); void refreshConfig(); + void cleanKickCounterList(); private: BadWordCheck *myBadWordCheck; @@ -32,12 +34,22 @@ private: int lastWarnType; int warnLevel; }; + + struct ClientKickInfos { + size_t lastKickTimestamp; + int kickNumber; + }; QMap myClientWarnLevelList; + QMap myClientKickCounterList; int warnLevelToKick; + int kickNumberToBan; CleanerConfig *config; + + boost::timers::portable::second_timer timer; + QTimer *cleanTimer; }; #endif // MESSAGEFILTER_H