/* GNU General Public License version 3 notice Copyright (C) 2012 Mihawk . All rights reserved. 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/ >. */ #include "Client.h" #include #include #include #include #include #include #include "App.h" #include "Settings.h" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Client::Client(App *app, ActiveClient* ac, bool supportsSendPrivate): QWClient(), myActiveClient(ac), myApp(app), myOnServerFlag(false), mySpamMutedFlag(false), myQWMutedFlag(false), myKeepNickTimer(new QTimer()), myFloodTimer(new QTimer()), myQWBroadcastFloodTimer(new QTimer()), mySpamBroadcastFloodTimer(new QTimer()), mySupportsSendPrivate(supportsSendPrivate), myMaxClients(0) { myKeepNickTimer->setSingleShot(true); myFloodTimer->setSingleShot(true); myQWBroadcastFloodTimer->setSingleShot(true); mySpamBroadcastFloodTimer->setSingleShot(true); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Client::~Client() { delete myKeepNickTimer; delete myFloodTimer; delete myQWBroadcastFloodTimer; delete mySpamBroadcastFloodTimer; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Client::connect(const char *host, quint16 port) { setPing(13); QWClient::connect(host, port); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Client::say(const QString &msg, const QString &nickName) { QString cmd("say "); if(!nickName.isEmpty() && mySupportsSendPrivate) cmd.append("s-p \"" + nickName + "\" "); cmd.append(msg); sendCmd(cmd.toAscii().data()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Client::setTeam(const QString &msg) { sendCmd(QString("setinfo \"team\" \"" + msg + "\"").toAscii().data()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Client::disconnect() { QWClient::disconnect(); myOnServerFlag = false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Client::print(const QString &msg) { QString str; str = "[" + QTime::currentTime().toString(Qt::ISODate) + "] " + QString(host()) + ":" + QString::number(port()) + "> " + msg; QByteArray b = str.toAscii(); Client::stripColor(b.data()); str = QString::fromAscii(b.data()); myApp->print(str); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Client::setPlayerList(PlayerList &playerList) { myPlayerList = playerList; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Client::onDisconnect() { print("Disconnected..\n"); myOnServerFlag = false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Client::isQWMuted() const { return myQWMutedFlag; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Client::isSpamMuted() const { return mySpamMutedFlag; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Client::parsePrintedLine() { // Find the player that printed this line of text Player player, bestPlayer; quint16 lastMatchSize = 0; foreach(player, myPlayerList) { if(player.spectator && myPrintLine.startsWith("[SPEC] " + player.name)) { if(lastMatchSize < (player.name.size() + 7)) { lastMatchSize = (player.name.size() + 7); bestPlayer = player; } continue; } if(myPrintLine.startsWith(player.name)) { if(lastMatchSize < player.name.size()) { lastMatchSize = player.name.size(); bestPlayer = player; } continue; } } if(!lastMatchSize) return; QString nick(bestPlayer.name); if(bestPlayer.spectator) nick.prepend("(spec) "); QString message(myPrintLine.right(myPrintLine.size() - lastMatchSize)); QRegExp regex("^:\\s+\\.(spam|qw|help|qw_mute|qw_unmute|spam_mute|spam_unmute|lm)\\s*(.+)$"); if(regex.indexIn(message) == -1) return; /* Flood prot */ QTime currentTime = QTime::currentTime(); int floodProtTime = Settings::globalInstance()->floodProtTime(); if(myFloodTimer->isActive()) { if(!myFloodMsgPrinted) { say("FloodProt: Not so fast, wait " + QString::number(floodProtTime + currentTime.secsTo(myFloodTimerStart)) + " sec(s).", bestPlayer.name); myFloodMsgPrinted = true; } return; } myFloodTimerStart = currentTime; myFloodTimer->start(floodProtTime*1000); myFloodMsgPrinted = false; QString command = regex.capturedTexts().at(1); QString args = regex.capturedTexts().at(2); if(command == "help") { say("Broadcast a message: .qw and .spam ", bestPlayer.name); say("(Un)Mute: .qw_mute .qw_unmute or .spam_mute .spam_unmute", bestPlayer.name); say("Last 5 messages: .lm", bestPlayer.name); return; } if(command == "qw" || command == "spam") { if(!args.trimmed().size()) { say("The format is ." + command + " .", bestPlayer.name); return; } /* Floodprot for broadcasting commands */ if(command == "qw") { int qwFloodProtTime = Settings::globalInstance()->qwFloodProtTime(); if(myQWBroadcastFloodTimer->isActive()) { say("FloodProt: Wait " + QString::number(qwFloodProtTime + currentTime.secsTo(myQWBroadcastFloodTimerStart)) + " secs before new .qw", bestPlayer.name); return; } myQWBroadcastFloodTimerStart = currentTime; myQWBroadcastFloodTimer->start(qwFloodProtTime*1000); } else if(command == "spam") { int spamFloodProtTime = Settings::globalInstance()->spamFloodProtTime(); if(mySpamBroadcastFloodTimer->isActive()) { say("FloodProt: Wait " + QString::number(spamFloodProtTime + currentTime.secsTo(mySpamBroadcastFloodTimerStart)) + " secs before new .spam", bestPlayer.name); return; } mySpamBroadcastFloodTimerStart = currentTime; mySpamBroadcastFloodTimer->start(spamFloodProtTime*1000); } // Prepare all strings to be broadcasted QString server(QString(host()) + ":" + QString::number(port())); // Tries to find the hostname for this ip in the cache QString resolvedServer(myApp->serverHostName(server)); if(!resolvedServer.isEmpty()) resolvedServer.append(":" + QString::number(port())); else resolvedServer = server; // Internal message to be broadcast within our network of bots (don't need to have namefun parsed) // The internal message uses the resolvedServer, because this message doesn't pass tru central, thus // the server ip isn't replaced by a hostname automatically QString internalMessage("-" + command + "- " + nick + " - " + resolvedServer + " " + QString::number(playerCount()) + "/" + QString::number(myMaxClients) + " : " + args.trimmed()); myApp->broadcast(internalMessage, myActiveClient); // Message that will be broadcast to other networks (needs namefun parsing) // this message passes tru central, thus the server ip will be replaced by a hostname // automatically nick = parseNameFun(nick); QString parsedMsg = parseNameFun(args.trimmed()); server.append(" " + QString::number(playerCount()) + "/" + QString::number(myMaxClients)); // append player count to the server (central needs another parm for this!) if(!Settings::globalInstance()->developerMode()) myApp->requestBroadcast(command, nick, server, parsedMsg); else myApp->requestBroadcast("dev", nick, server, parsedMsg); say("Broadcasting...", bestPlayer.name); return; } if(command == "qw_mute") { say("Qw frequency muted.", bestPlayer.name); myQWMutedFlag = true; return; } if(command == "qw_unmute") { say("Qw frequency unmuted.", bestPlayer.name); myQWMutedFlag = false; return; } if(command == "spam_mute") { say("Spam frequency muted.", bestPlayer.name); mySpamMutedFlag = true; return; } if(command == "spam_unmute") { say("Spam frequency unmuted.", bestPlayer.name); mySpamMutedFlag = false; return; } if(command == "lm") { QStringList messages = myApp->lastMessages(); if(!messages.size()) { say("None", bestPlayer.name); return; } QString msg; int i = 0; foreach(msg, messages) { if(++i > 5) break; say(msg, bestPlayer.name); } return; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - int Client::playerCount() const { Player c; int pc = 0; foreach(c, myPlayerList) { if(c.spectator) continue; pc++; } return pc; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Client::setMaxClients(int maxClients) { myMaxClients = maxClients; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - int Client::maxClients() const { return myMaxClients; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Client::onPrint(int, const char *msg) { if(!strlen(msg)) return; QString text(msg); if(text.endsWith('\n')) { myPrintLine.append(text); parsePrintedLine(); print(myPrintLine); myPrintLine.clear(); } else { myPrintLine.append(text); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Client::isOnServer() const { return myOnServerFlag; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Client::onError(const char *description) { QString desc(description); if(desc == "Client Timed Out.") { print("Error (" + QString(description) + ")\n"); } else { print("Error (" + QString(description) + ")\n"); } myOnServerFlag = false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Client::onLevelChanged(int, const char *levelName, float, float, float, float, float, float, float, float, float, float) { print(QString(levelName) + "\n"); myDownloadProgressPrintedFlag = false; mySpamMutedFlag = false; myQWMutedFlag = false; setPing(13); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Client::onChallenge() { print("challenge\n"); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Client::onConnection() { print("connection\n"); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Client::onConnected() { print("connected\n"); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Client::onDownloadStarted(const char *fileName) { print("Download started " + QString(fileName) + "\n"); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Client::run() { // if(!myJoinMessageTimer->isActive() && !myJoinMessagePrinted) // { // say("Hi, I am QWNET's bot, type .help to see my commands."); // myJoinMessagePrinted = true; // } /* Keep nick... Simply set name again after 30 secs */ if(!myKeepNickTimer->isActive()) { setName(Settings::globalInstance()->botName().toAscii().data()); myKeepNickTimer->start(30000); } QWClient::run(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Client::onOOBPrint(const char *msg) { print(QString(msg)); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Client::onStuffedCmd(const char *cmd) { QString strCmd(cmd); if(strCmd == "skins") //connection sequence complete { myOnServerFlag = true; setPing(Settings::globalInstance()->botPing()); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Client::onDownloadProgress(int percent) { if(!(percent % 10)) { if(!myDownloadProgressPrintedFlag) { print("Download " + QString::number(percent) + "%\n"); myDownloadProgressPrintedFlag = true; } } else { myDownloadProgressPrintedFlag = false; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Client::onDownloadFinished() { print("Download 100% finished.\n"); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Client::supportsSendPrivate() const { return mySupportsSendPrivate; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - QString Client::parseNameFun(const QString &string) { QByteArray b(string.toAscii()); QWClient::stripColor(b.data()); return QString(b); }