#include "App.h" #include "Client.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "SshClient.h" #include "ActiveClient.h" #include "Settings.h" class Sleeper: public QThread { public: static void msleep(unsigned long msecs) { QThread::msleep(msecs); } }; App::App(int &argc, char **argv) : QCoreApplication(argc, argv), myServer(new QTcpServer()), mySocketConnectedFlag(false), myQWNETSshClient(new SshClient(this)) { if(!parseCommandLine()) return; print("CIMS Bot Service v0.101\n========================================================\n"); setApplicationName("CIMSBOT"); setOrganizationDomain("qwbr.tk"); setOrganizationName("CIMS"); setApplicationVersion("0.101"); myClientsFrameTimerID = startTimer(0); myQWNETSshClient->connectToHost("stomp", "b4r.org"); loadServerList(); Settings::globalInstance()->save(); } App::~App() { Settings::globalInstance()->save(); cleanup(); delete myServer; } bool App::parseCommandLine() { if(argc() < 2) return true; QStringList args = App::arguments(); QString arg; QStringList::const_iterator itr; for(itr = args.constBegin()+1; itr != args.constEnd(); ++itr) { arg = *itr; if(arg == "--help" || arg == "-h") { printf("Usage: %s [--config/-c config_file] [-h]\n", args.at(0).section("/", -1).toAscii().data()); QTimer::singleShot(0, this, SLOT(quit())); return false; } else if(arg == "--config" || arg == "-c") { itr++; if(itr == args.constEnd()) { printf("--config: Expected config file path.\n"); QTimer::singleShot(0, this, SLOT(quit())); return false; } arg = *itr; printf("Using config file [%s]...\n", arg.toAscii().data()); Settings::globalInstance()->changeConfigFile(*itr); return true; } } return true; } void App::onNewConnection() { if(mySocketConnectedFlag) { print("Someone just connected to the bot.\nBye Bye.\n"); mySocket->disconnectFromHost(); if(mySocket->state() != QTcpSocket::UnconnectedState) mySocket->waitForDisconnected(); mySocketConnectedFlag = false; } mySocket = myServer->nextPendingConnection(); mySocketConnectedFlag = true; connect(mySocket, SIGNAL(readyRead()), SLOT(onDataArrival())); connect(mySocket, SIGNAL(disconnected()), SLOT(onDisconnection())); print("Connected to CIMS's bot service.\n"); } void App::onDisconnection() { mySocketConnectedFlag = false; mySocket->deleteLater(); } void App::loadServerList() { QStringList list = Settings::globalInstance()->serverList(); QString sv; foreach(sv, list) { ActiveClient* ac = new ActiveClient(this); QStringList parms = sv.split(':'); ac->setAddress(QHostAddress(parms.at(0)), parms.at(1).toUShort()); ac->client()->setQuakeFolder(Settings::globalInstance()->quakeFolder().toAscii().data()); ac->client()->setName(Settings::globalInstance()->botName().toAscii().data()); ac->client()->setSpectator(Settings::globalInstance()->botSpectator()); ac->client()->setPing(Settings::globalInstance()->botPing()); ac->client()->setColor(Settings::globalInstance()->botTopColor(), Settings::globalInstance()->botBottomColor()); myClients.push_back(ac); } } void App::saveServerList() { QStringList list; ActiveClient* ac; foreach(ac, myClients) list.push_back(ac->serverAddressString()); Settings::globalInstance()->setServerList(list); } void App::parseAddClientCommand(const QString &args) { if(!args.size()) { print("No server specified\n"); return; } if(args.contains(" ")) { print("Invalid server address\n"); return; } QStringList clientData = args.split(":"); if(clientData.size() == 1) { addClient(clientData.at(0), 27500); return; } if(clientData.size() == 2) { addClient(clientData.at(0), clientData.at(1).toUShort()); return; } } void App::parseRemoveClientCommand(const QString &args) { if(!args.size()) { print("No server specified\n"); return; } QStringList clientData = args.split(":"); if(clientData.size() == 1) { removeClient(clientData.at(0), 27500); return; } if(clientData.size() == 2) { removeClient(clientData.at(0), clientData.at(1).toUShort()); return; } } void App::onDataArrival() { while(mySocket->canReadLine()) { QByteArray line; line = mySocket->readLine(); QString data(line); QRegExp regex("([0-9a-zA-Z]+)\\s+([a-z]+)\\s+(.*)"); if(regex.indexIn(data) == -1) { print("command format: ?\nEg.: pss help\nDisconnected\n"); mySocket->disconnectFromHost(); return; } QString pass = regex.capturedTexts().at(1); if(!checkPassword(pass)) { print("Wrong password\nDisconnected\n"); mySocket->disconnectFromHost(); return; } QString cmd = regex.capturedTexts().at(2); QString args = regex.capturedTexts().at(3).trimmed(); if(cmd == "add") { parseAddClientCommand(args); return; } if(cmd == "remove") { parseRemoveClientCommand(args); return; } if(cmd == "say") { broadcast(args); return; } if(cmd == "servers") { listClients(); return; } if(cmd == "name") { setNick(args); return; } if(cmd == "color") { setColor(args); return; } if(cmd == "setping") { setPing(args); return; } if(cmd == "team") { setTeam(args); return; } if(cmd == "quit") { mySocket->disconnectFromHost(); return; } if(cmd == "help") { help(); return; } } } const QStringList& App::lastMessages() const { return myLastMessages; } void App::help() { print("connect server:port -> connects the bot on a server\n"); print("disconnect server:port -> removes the bot from a server\n"); print("say message -> says the message on all servers where the bot is connected\n"); print("servers -> lists all servers the bot is connected\n"); print("name nick -> changes the bot name to nick\n"); print("color x x -> changes the player color\n"); print("setping x -> sets the bot ping to x. ofc you can't lower your actual ping with this.\n"); print("team teamname -> sets the bot team\n"); print("help -> displays this message\n"); } void App::setTeam(const QString &args) { ActiveClient* ac; foreach(ac, myClients) { ac->client()->setTeam(args); } print("Team changed.\n"); } void App::setColor(const QString &args) { ActiveClient* ac; quint8 bottom, top; QStringList colors = args.split(" "); if(colors.size() < 2) return; bottom = colors.at(0).toUShort(); top = colors.at(1).toUShort(); foreach(ac, myClients) { ac->client()->setColor(bottom, top); } print("All clients colors have changed.\n"); } void App::setPing(const QString &args) { ActiveClient* ac; foreach(ac, myClients) { ac->client()->setPing(args.toInt()); } print("All clients pings have changed.\n"); } void App::setNick(const QString &args) { ActiveClient* ac; foreach(ac, myClients) { ac->client()->setName(args.toAscii().data()); } print("All clients nicks have changed.\n"); } bool App::checkPassword(const QString &password) { if(QCryptographicHash::hash(password.toAscii(), QCryptographicHash::Md4).toHex().toLower() == "bf4df9f74d05c50ea00492224fb02854") return false; //telnet adm disabled!! return false; } void App::print(const QString &msg) { printf("%s", msg.toAscii().data()); if(mySocketConnectedFlag) { mySocket->write(msg.toAscii()); mySocket->waitForBytesWritten(); } } void App::addClient(const QString &host, quint16 port) { ActiveClient* ac; QHostAddress ha = QHostInfo::fromName(host).addresses().at(0); foreach(ac, myClients) { if(QString(ac->client()->host()) == ha.toString() && ac->client()->port() == port) { print("That client is already on the list.\n"); return; } } ac = new ActiveClient(this, this); ac->setAddress(ha, port); ac->client()->setQuakeFolder(Settings::globalInstance()->quakeFolder().toAscii().data()); ac->client()->setName(Settings::globalInstance()->botName().toAscii().data()); ac->client()->setSpectator(Settings::globalInstance()->botSpectator()); ac->client()->setPing(Settings::globalInstance()->botPing()); ac->client()->setColor(Settings::globalInstance()->botTopColor(), Settings::globalInstance()->botBottomColor()); myClients.push_back(ac); saveServerList(); print("Client added to watch list.\n"); } void App::removeClient(const QString &host, quint16 port) { ActiveClient* ac; QHostAddress ha = QHostInfo::fromName(host).addresses().at(0); foreach(ac, myClients) { if(ac->serverAddressString() == QString(ha.toString() + ':' + QString::number(port))) { ac->client()->disconnect(); delete ac; myClients.removeAll(ac); saveServerList(); print("Client removed from watch list.\n"); return; } } print("Client not found on the list.\n"); } void App::listClients() { ActiveClient* ac; foreach(ac, myClients) { print(QString(ac->serverAddressString() + '\n')); } } void App::activeClientsReplyCounters(int *serverCount, int *playerCount, ActiveClient *ignoreClient) { ActiveClient* ac; foreach(ac, myClients) { if(ac == ignoreClient) continue; if(ac->client()->state() == Client::ConnectedState) { int pc = ac->playerCount(); if(pc == 255 || pc == 0) pc = 0; else pc--; *playerCount += pc; (*serverCount)++; } } } void App::timerEvent(QTimerEvent *e) { if(e->timerId() == myClientsFrameTimerID) { ActiveClient *ac; foreach(ac, myClients) { ac->run(); } } Sleeper::msleep(1); } void App::requestBroadcast(const QString &type, const QString &user, const QString &server, const QString &message) { if(!Settings::globalInstance()->developerMode()) myQWNETSshClient->write("REQ_BC QWalt,-" + type + "-,qw://" + server + ",'" + user + "','" + message + "'\n"); else myQWNETSshClient->write("REQ_BC QDEV,-dev-,qw://" + server + ",'" + user + "','" + message + "'\n"); } void App::addMessageToHistory(const QString &msg) { myLastMessages.push_back(msg); if(myLastMessages.size() > 5) myLastMessages.removeAt(0); } void App::broadcast(const QString &msg, ActiveClient* ignoredClient) { ActiveClient* ac; QString frequency = msg.section(' ', 0, 0); addMessageToHistory(msg); foreach(ac, myClients) { if(ac == ignoredClient) continue; if((frequency == "-qw-" && ac->client()->isQWMuted()) || (frequency == "-spam-" && ac->client()->isSpamMuted())) continue; if(ac->client()->state() == Client::ConnectedState) ac->client()->say(msg); } } void App::broadcast(const QString &msg, int *serverCount, int *userCount) { ActiveClient* ac; *serverCount = 0; *userCount = 0; QString frequency = msg.section(' ', 0, 0); addMessageToHistory(msg); foreach(ac, myClients) { if((frequency == "-qw-" && ac->client()->isQWMuted()) || (frequency == "-spam-" && ac->client()->isSpamMuted())) continue; if(ac->client()->state() == Client::ConnectedState) { ac->client()->say(msg); *userCount += ac->playerCount() - 1; (*serverCount)++; } } } void App::cleanup() { ActiveClient* ac; foreach(ac, myClients) { ac->client()->disconnect(); delete ac; } } void App::setReplyHash(const QString &serverAddress, const QString &hash) { ActiveClient* ac; foreach(ac, myClients) { if(serverAddress == ac->serverAddressString()) { ac->setReplyHash(hash); return; } } } void App::incrementReplyCounters(const QString &hash, int userCount, int channelCount, int playerCount, int serverCount) { ActiveClient* ac; foreach(ac, myClients) { if(ac->replyHash() == hash) { ac->incrementReplyCounters(userCount, channelCount, playerCount, serverCount); return; } } }