Browse Source

Changes:
Moved ActiveClient to another file;
Created Settings File for general settings and server list;
Converted namefun from messages and nicks;
Removed unused library sql from project;
Renamed the path to libqwclient to libqwclient.

Mihawk 12 years ago
parent
commit
8f4e6b35b9
13 changed files with 564 additions and 221 deletions
  1. 144 0
      ActiveClient.cpp
  2. 68 0
      ActiveClient.h
  3. 66 146
      App.cpp
  4. 6 39
      App.h
  5. 18 8
      Client.cpp
  6. 2 2
      Client.h
  7. 16 9
      ServerQueryThread.cpp
  8. 123 0
      Settings.cpp
  9. 55 0
      Settings.h
  10. 45 8
      SshClient.cpp
  11. 5 0
      SshClient.h
  12. 14 8
      cimsqwbot.pro
  13. 2 1
      main.cpp

+ 144 - 0
ActiveClient.cpp

@@ -0,0 +1,144 @@
+/*
+GNU General Public License version 3 notice
+
+Copyright (C) 2012 Mihawk <luiz@netdome.biz>. 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 <QTimer>
+#include <QTime>
+#include "ServerQueryThread.h"
+#include "ActiveClient.h"
+#include "Client.h"
+#include "App.h"
+
+ActiveClient::ActiveClient(App *app):
+  myApp(app),
+  myClient(new Client(app)),
+  myQueryThread(new ServerQueryThread()),
+  myDisconnectTime(new QTime()),
+  myBroadcastReplyTimer(new QTimer()),
+  myUniqueUserCount(0),
+  myUniqueChannelCount(0),
+  myUniqueServerCount(0),
+  myUniquePlayerCount(0),
+  myReplyTimerWasActive(false)
+{
+}
+
+ActiveClient::~ActiveClient()
+{
+  delete myClient;
+
+  if(myQueryThread->isRunning())
+    myQueryThread->stopQueryThread();
+  while(myQueryThread->isRunning());
+
+  delete myQueryThread;
+  delete myBroadcastReplyTimer;
+  delete myDisconnectTime;
+}
+
+Client* ActiveClient::client()
+{
+  return myClient;
+}
+
+ServerQueryThread* ActiveClient::queryThread()
+{
+  return myQueryThread;
+}
+
+void ActiveClient::setAddressAndStartThread(const QHostAddress &address, quint16 port)
+{
+  myQueryThread->setAddress(address, port);
+  myQueryThread->startQueryThread();
+  return;
+}
+
+void ActiveClient::run()
+{
+  /* If the client is disconnect check if there is at least one player connected to the server */
+  if(myClient->state() == Client::DisconnectedState)
+  {
+    int playerCount = myQueryThread->playerCount();
+    if(playerCount > 0 && myDisconnectTime->elapsed() > 10000)
+    {
+      myApp->print("Players online on server " + myQueryThread->serverAddress().toString() + ":" + QString::number(myQueryThread->serverPort()) + ". Joining...\n");
+      myClient->connect(myQueryThread->serverAddress().toString().toAscii(), myQueryThread->serverPort());
+    }
+    return;
+  }
+
+  /* If the client is connected and left alone on the server, disconnect yourself */
+  if(myClient->state() == Client::ConnectedState)
+  {
+    int playerCount = myQueryThread->playerCount();
+    if(playerCount == 1 && myClient->isOnServer())
+    {
+      myApp->print("I was left alone on " + myQueryThread->serverAddress().toString() + ":" + QString::number(myQueryThread->serverPort()) + ". Leaving...\n");
+      myClient->disconnect();
+      myDisconnectTime->restart();
+      return;
+    }
+  }
+
+  /* Say the broadcast count */
+  if(!myBroadcastReplyTimer->isActive() && myReplyTimerWasActive)
+  {
+    myApp->activeClientsReplyCounters(&myUniqueServerCount, &myUniquePlayerCount); //add my internal counter to the list
+    myClient->say("::cims:: Sent to " + QString::number(myUniqueChannelCount) + " channels, " + QString::number(myUniqueUserCount) + " unique users.");
+    myClient->say("::cims:: Sent to " + QString::number(myUniqueServerCount) + " servers, " + QString::number(myUniquePlayerCount) + " unique players.");
+    myUniqueServerCount = myUniquePlayerCount = myUniqueChannelCount = myUniqueUserCount = 0;
+  }
+  myReplyTimerWasActive = myBroadcastReplyTimer->isActive();
+
+  myClient->run();
+}
+
+const QString ActiveClient::serverAddressString()
+{
+  return QString(myQueryThread->serverAddress().toString() + ':' + QString::number(myQueryThread->serverPort()));
+}
+
+void ActiveClient::setReplyHash(const QString &hash)
+{
+  myReplyHash = hash;
+
+  /* Wait for 5 seconds */
+  myBroadcastReplyTimer->setSingleShot(true);
+  myBroadcastReplyTimer->start(5000);
+}
+
+const QString& ActiveClient::replyHash() const
+{
+  return myReplyHash;
+}
+
+bool ActiveClient::isWaitingReply() const
+{
+  return myBroadcastReplyTimer->isActive();
+}
+
+void ActiveClient::incrementReplyCounters(int userCount, int channelCount, int playerCount, int serverCount)
+{
+  if(!myBroadcastReplyTimer->isActive())
+    return;
+
+  myUniqueUserCount += userCount;
+  myUniqueChannelCount += channelCount;
+  myUniqueServerCount += serverCount;
+  myUniquePlayerCount += playerCount;
+}

+ 68 - 0
ActiveClient.h

@@ -0,0 +1,68 @@
+/*
+GNU General Public License version 3 notice
+
+Copyright (C) 2012 Mihawk <luiz@netdome.biz>. 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/ >.
+*/
+
+#ifndef ACTIVECLIENT_H
+#define ACTIVECLIENT_H
+
+#include <QString>
+
+class QHostAddress;
+class ServerQueryThread;
+class QTimer;
+class QTime;
+class Client;
+class App;
+
+class ActiveClient
+{
+public:
+  ActiveClient(App* app);
+  ~ActiveClient();
+
+  Client*           client();
+  ServerQueryThread*queryThread();
+  void              run();
+  void              setAddressAndStartThread(const QHostAddress &address, quint16 port);
+  const QString     serverAddressString();
+  void              setReplyHash(const QString& hash); //this activates the 5 seconds reply timer too
+  const QString&    replyHash() const;
+  void              incrementReplyCounters(int userCount, int channelCount, int playerCount, int serverCount);
+  bool              isWaitingReply() const;
+
+private:
+  App*              myApp;
+  Client*           myClient;
+  ServerQueryThread*myQueryThread;
+  QTime*            myDisconnectTime;
+
+  /* Count server reply while timer is active */
+  QString           myReplyHash;
+  QTimer*           myBroadcastReplyTimer;
+
+  int               myUniqueUserCount;
+  int               myUniqueChannelCount;
+  int               myUniqueServerCount;
+  int               myUniquePlayerCount;
+
+  bool              myReplyTimerWasActive;
+
+  ActiveClient(const ActiveClient&) {}
+};
+
+#endif // ACTIVECLIENT_H

+ 66 - 146
App.cpp

@@ -10,8 +10,11 @@
 #include <QtSql/QSqlQuery>
 #include <QCryptographicHash>
 #include <QHostAddress>
+#include <QThreadPool>
 #include "SshClient.h"
+#include "ActiveClient.h"
 #include "ServerQueryThread.h"
+#include "Settings.h"
 
 App::App(int &argc, char **argv) :
   QCoreApplication(argc, argv),
@@ -32,6 +35,19 @@ App::App(int &argc, char **argv) :
 	myClientsFrameTimerID = startTimer(0);
 
   myQWNETSshClient->connectToHost("stomp", "b4r.org");
+
+  QThreadPool::globalInstance()->setMaxThreadCount(Settings::globalInstance()->maxThreads());
+
+  loadServerList();
+
+  Settings::globalInstance()->save();
+}
+
+App::~App()
+{
+  Settings::globalInstance()->save();
+  cleanup();
+  delete myServer;
 }
 
 void App::onNewConnection()
@@ -43,7 +59,7 @@ void App::onNewConnection()
 		if(mySocket->state() != QTcpSocket::UnconnectedState)
 			mySocket->waitForDisconnected();
 		mySocketConnectedFlag = false;
-	}
+  }
 
 	mySocket = myServer->nextPendingConnection();
   mySocketConnectedFlag = true;
@@ -72,12 +88,38 @@ void App::onDisconnection()
 	mySocket->deleteLater();
 }
 
-void App::loadClients()
+void App::loadServerList()
+{
+  QStringList list = Settings::globalInstance()->serverList();
+  QString sv;
+
+  foreach(sv, list)
+  {
+    ActiveClient* ac = new ActiveClient(this);
+    QStringList parms = sv.split(':');
+    ac->setAddressAndStartThread(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::connectToServer(const QString &args)
+void App::parseAddClientCommand(const QString &args)
 {
 	if(!args.size())
 	{
@@ -104,7 +146,7 @@ void App::connectToServer(const QString &args)
 	}
 }
 
-void App::disconnectFromServer(const QString &args)
+void App::parseRemoveClientCommand(const QString &args)
 {
 	if(!args.size())
 	{
@@ -154,15 +196,15 @@ void App::onDataArrival()
 		QString cmd  = regex.capturedTexts().at(2);
 		QString args = regex.capturedTexts().at(3).trimmed();
 
-		if(cmd == "connect")
+    if(cmd == "add")
 		{
-			connectToServer(args);
+      parseAddClientCommand(args);
 			return;
 		}
 
-		if(cmd == "disconnect")
+    if(cmd == "remove")
 		{
-			disconnectFromServer(args);
+      parseRemoveClientCommand(args);
 			return;
 		}
 
@@ -324,13 +366,17 @@ void App::addClient(const QString &host, quint16 port)
       ac->client()->setSocket(mySocket);
 		}
 	}
-  ac->setAddress(ha, port);
-  ac->client()->setQuakeFolder(mySettings.value("quakeFolder", App::applicationDirPath()).toString().toAscii().data());
-  ac->client()->setName(mySettings.value("botName", "cimsbot").toString().toAscii().data());
-  ac->client()->setSpectator(true);
-  ac->client()->setPing(120);
-  ac->client()->setColor(11, 13);
+  ac->setAddressAndStartThread(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)
@@ -340,14 +386,15 @@ void App::removeClient(const QString &host, quint16 port)
 
   foreach(ac, myClients)
 	{
-    if(QString(ac->client()->host()) == ha.toString() && ac->client()->port() == port)
+    if(ac->serverAddressString() == QString(ha.toString() + ':' + QString::number(port)))
 		{
       ac->client()->disconnect();
       delete ac;
       myClients.removeAll(ac);
 
+      saveServerList();
 
-      print("Client removed.\n");
+      print("Client removed from watch list.\n");
 			return;
 		}
 	}
@@ -402,9 +449,7 @@ void App::listClients()
   ActiveClient* ac;
   foreach(ac, myClients)
 	{
-    QString reply(ac->client()->host());
-    reply.append(":" + QString::number(ac->client()->port()) + "\n");
-		print(reply.toAscii().data());
+    print(QString(ac->serverAddressString() + '\n'));
 	}
 }
 
@@ -443,8 +488,6 @@ void App::timerEvent(QTimerEvent *e)
 
 void App::requestBroadcast(const QString &type, const QString &user, const QString &server, const QString &message)
 {
-  //REQ_BC QDEV,-dev-,qw://123.123,'testuser','test, with '',``twists''$ hehe'
-  qDebug() << "REQ_BC QDEV,-" + type + "-,qw://" + server + ",'" + user + "','" + message + "'";
   myQWNETSshClient->write("REQ_BC QDEV,-" + type + "-,qw://" + server + ",'" + user + "','" + message + "'\n");
 }
 
@@ -455,7 +498,6 @@ void App::broadcast(const QString &msg)
 
 void App::broadcast(const QString &msg, int *serverCount, int *userCount)
 {
-  qDebug() << "Broadcasting" << msg;
   say(msg, serverCount, userCount);
 }
 
@@ -469,12 +511,6 @@ void App::cleanup()
 	}
 }
 
-App::~App()
-{
-	cleanup();
-	delete myServer;
-}
-
 void App::setReplyHash(const QString &serverAddress, const QString &hash)
 {
   ActiveClient* ac;
@@ -488,132 +524,16 @@ void App::setReplyHash(const QString &serverAddress, const QString &hash)
   }
 }
 
-void App::incrementReplyCounters(const QString &hash, int userCount, int serverCount)
+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, serverCount);
-      return;
-    }
-  }
-}
-
-//========================================================================
-
-App::ActiveClient::ActiveClient(App *app):
-  myApp(app),
-  myClient(new Client(app)),
-  myQueryThread(new ServerQueryThread()),
-  myBroadcastReplyTimer(new QTimer()),
-  myUniqueUserCount(0),
-  myUniqueServerCount(0)
-{
-}
-
-App::ActiveClient::~ActiveClient()
-{
-  delete myClient;
-
-  if(queryThread()->isRunning())
-    queryThread()->stopQueryThread();
-  while(queryThread()->isRunning());
-
-  delete myQueryThread;
-  delete myBroadcastReplyTimer;
-}
-
-Client* App::ActiveClient::client()
-{
-  return myClient;
-}
-
-ServerQueryThread* App::ActiveClient::queryThread()
-{
-  return myQueryThread;
-}
-
-void App::ActiveClient::setAddress(const QHostAddress &address, quint16 port)
-{
-  queryThread()->setAddress(address, port);
-}
-
-void App::ActiveClient::run()
-{
-  /* If the client is disconnect check if there is at least one player connected to the server */
-  if(client()->state() == Client::DisconnectedState)
-  {
-    if(!queryThread()->isRunning())
-    {
-      queryThread()->startQueryThread();
-      return;
-    }
-
-    int playerCount = queryThread()->playerCount();
-    if(playerCount != 255 && playerCount > 0 && myDisconnectTime.elapsed() > 10000)
-    {
-      myApp->print("Players online on server " + queryThread()->serverAddress().toString() + ":" + QString::number(queryThread()->serverPort()) + ". Joining...\n");
-      client()->connect(queryThread()->serverAddress().toString().toAscii(), queryThread()->serverPort());
-    }
-    return;
-  }
-
-  /* If the client is connected and left alone on the server, disconnect yourself */
-  if(client()->state() == Client::ConnectedState)
-  {
-    int playerCount = queryThread()->playerCount();
-    if(playerCount == 1 && client()->isOnServer())
-    {
-      myApp->print("I was left alone on " + queryThread()->serverAddress().toString() + ":" + QString::number(queryThread()->serverPort()) + ". Leaving...\n");
-      client()->disconnect();
-      myDisconnectTime.restart();
+      ac->incrementReplyCounters(userCount, channelCount, playerCount, serverCount);
       return;
     }
   }
-
-  /* Say the broadcast count */
-  if(!myBroadcastReplyTimer->isActive() && myReplyTimerWasActive)
-  {
-    myApp->activeClientsReplyCounters(&myUniqueServerCount, &myUniqueUserCount); //add my internal counter to the list
-
-    client()->say("::cims:: Sent to " + QString::number(myUniqueServerCount) + " channels, " + QString::number(myUniqueUserCount) + " unique users.");
-    myUniqueServerCount = myUniqueUserCount = 0;
-  }
-  myReplyTimerWasActive = myBroadcastReplyTimer->isActive();
-
-  client()->run();
-}
-
-const QString App::ActiveClient::serverAddressString()
-{
-  return QString(queryThread()->serverAddress().toString() + ':' + QString::number(queryThread()->serverPort()));
-}
-
-void App::ActiveClient::setReplyHash(const QString &hash)
-{
-  myReplyHash = hash;
-
-  /* Wait for 5 seconds */
-  myBroadcastReplyTimer->setSingleShot(true);
-  myBroadcastReplyTimer->start(5000);
-}
-
-const QString& App::ActiveClient::replyHash() const
-{
-  return myReplyHash;
 }
 
-bool App::ActiveClient::isWaitingReply() const
-{
-  return myBroadcastReplyTimer->isActive();
-}
-
-void App::ActiveClient::incrementReplyCounters(int userCount, int serverCount)
-{
-  if(!myBroadcastReplyTimer->isActive())
-    return;
-  myUniqueUserCount += userCount;
-  myUniqueServerCount += serverCount;
-}

+ 6 - 39
App.h

@@ -5,14 +5,12 @@
 #include <QList>
 #include <QSettings>
 #include <QHostAddress>
-#include <QTime>
-#include <QTimer>
 
 class SshClient;
 class QTcpSocket;
 class QTcpServer;
 class Client;
-class ServerQueryThread;
+class ActiveClient;
 
 class App : public QCoreApplication
 {
@@ -26,45 +24,13 @@ public:
   void                  broadcast(const QString& msg);
   void                  requestBroadcast(const QString& type, const QString& user, const QString& server, const QString& message);
   void                  setReplyHash(const QString& serverAddress, const QString& hash);
-  void                  incrementReplyCounters(const QString& hash, int userCount, int serverCount);
+  void                  incrementReplyCounters(const QString& hash, int userCount, int channelCount, int playerCount, int serverCount);
   void                  activeClientsReplyCounters(int *serverCount, int *playerCount);
 
 protected:
 	void									timerEvent(QTimerEvent *e);
 
 private:
-  class ActiveClient
-  {
-  public:
-    ActiveClient(App* app);
-    ~ActiveClient();
-
-    Client*           client();
-    ServerQueryThread*queryThread();
-    void              run();
-    void              setAddress(const QHostAddress &address, quint16 port);
-
-    const QString     serverAddressString();
-    void              setReplyHash(const QString& hash); //this activates the 5 seconds reply timer too
-    const QString&    replyHash() const;
-    void              incrementReplyCounters(int userCount, int serverCount);
-    bool              isWaitingReply() const;
-
-  private:
-    App*              myApp;
-    Client*           myClient;
-    ServerQueryThread*myQueryThread;
-    ActiveClient(const ActiveClient&) {}
-    QTime             myDisconnectTime;
-
-    /* Count server reply while timer is active */
-    QString           myReplyHash;
-    QTimer*           myBroadcastReplyTimer;
-    int               myUniqueUserCount;
-    int               myUniqueServerCount;
-    bool              myReplyTimerWasActive;
-  };
-
   QTcpSocket*           mySocket;
   QTcpServer*           myServer;
 	bool									mySocketConnectedFlag;
@@ -75,15 +41,16 @@ private:
 	QSettings							mySettings;
 	int										myClientsFrameTimerID; //timer for mainloop
 
-	void									loadClients();
+  void									loadServerList();
+  void                  saveServerList();
 	void									cleanup();
 
 	/* TCP Server */
 	bool									checkPassword(const QString& password);
   void									addClient(const QString& host, quint16 port);
 	void									removeClient(const QString& host, quint16 port);
-	void									connectToServer(const QString& args);
-	void									disconnectFromServer(const QString& args);
+  void									parseAddClientCommand(const QString& args);
+  void									parseRemoveClientCommand(const QString& args);
   void                  say(const QString& msg, int *serverCount, int *userCount);
   void                  say(const QString& msg);
 	void									sayTeam(const QString& msg);

+ 18 - 8
Client.cpp

@@ -3,19 +3,24 @@
 #include <stdio.h>
 #include <QTcpSocket>
 #include <QStringList>
+#include <QTime>
 #include "App.h"
+#include "Settings.h"
 
 Client::Client(App *app):
   QWClient(),
   myApp(app),
   mySocket(NULL),
+  myEndFloodTimer(new QTime()),
   myConnectionRetries(0),
   myOnServerFlag(false)
 {
+  *myEndFloodTimer = QTime::currentTime();
 }
 
 Client::~Client()
 {
+  delete myEndFloodTimer;
 }
 
 void Client::setSocket(QTcpSocket *socket)
@@ -92,22 +97,22 @@ void Client::parsePrintedLine()
 		return;
 
 	/* Flood prot */
-	int elapsed = myTimer.elapsed();
-	if(elapsed < 20000)
+  int timeLeft = QTime::currentTime().secsTo(*myEndFloodTimer);
+  if(timeLeft > 0)
 	{
 		if(!myFloodMsgPrinted)
 		{
-			say("Wait " + QString::number((20000-elapsed) / 1000) + " second(s) before issuing a new command.");
+      say("> Wait " + QString::number(timeLeft) + " second(s) before issuing a new command.");
 			myFloodMsgPrinted = true;
 		}
 		return;
 	}
+  *myEndFloodTimer = QTime::currentTime().addSecs(Settings::globalInstance()->floodProtTime());
 
 	QString nick = regex.capturedTexts().at(1);
 	QString command = regex.capturedTexts().at(2);
 	QString args = regex.capturedTexts().at(3);
 
-	myTimer.restart();
 	myFloodMsgPrinted = false;
 
 	if(command == "help")
@@ -121,7 +126,13 @@ void Client::parsePrintedLine()
 
   if(command == "qw" || command == "spam")
 	{
-    say("Broadcasting...");
+    if(!args.trimmed().size())
+    {
+      say("> The format is ." + command + " <message>.");
+      return;
+    }
+
+    say("> Broadcasting...");
 
     QString server(QString(host()) + ":" + QString::number(port()));
     QString message("-" + command + "- " + nick + " - " + server + " : " + args.trimmed());
@@ -132,7 +143,8 @@ void Client::parsePrintedLine()
     //myApp->requestBroadcast(command, nick, server, args.trimmed());
 
     nick = parseNameFun(nick); //for the irc message namefun must be removed.
-    myApp->requestBroadcast("dev", nick, server, args.trimmed());
+    QString parsedMsg = parseNameFun(args.trimmed());
+    myApp->requestBroadcast("dev", nick, server, parsedMsg);
 
 		return;
 	}
@@ -195,7 +207,6 @@ void Client::onConnection()
 void Client::onConnected()
 {
 	print("connected\n");
-	myTimer.start();
 }
 
 void Client::onDownloadStarted(const char *fileName)
@@ -210,7 +221,6 @@ void Client::onOOBPrint(const char *msg)
 
 void Client::onStuffedCmd(const char *cmd)
 {
-  printf("[%s]\n", cmd);
 	QString strCmd(cmd);
 	if(strCmd == "skins") //connection sequence complete
 	{

+ 2 - 2
Client.h

@@ -4,10 +4,10 @@
 #include "QWClient.h"
 #include <QString>
 #include <QList>
-#include <QTime>
 
 class App;
 class QTcpSocket;
+class QTime;
 
 class Client : public QWClient
 {
@@ -39,7 +39,7 @@ protected:
 private:
 	App*							myApp;
   QTcpSocket*       mySocket;
-	QTime							myTimer;
+  QTime*            myEndFloodTimer;
 	bool							myFloodMsgPrinted;
 	int								myConnectionRetries;
 	static const int	ConnectionRetries = 10;

+ 16 - 9
ServerQueryThread.cpp

@@ -36,9 +36,12 @@ ServerQueryThread::ServerQueryThread():
   myStopMutex(new QReadWriteLock()),
   myServerInfoMutex(new QReadWriteLock()),
   myStopThreadFlag(true),
-  myThreadRunningFlag(false)
+  myThreadRunningFlag(false),
+  myServerPlayerCount(0)
 {
   setAutoDelete(false);
+  myStopMutex->unlock();
+  myServerInfoMutex->unlock();
 }
 
 ServerQueryThread::~ServerQueryThread()
@@ -58,9 +61,9 @@ bool ServerQueryThread::startQueryThread()
 {
   if(!isRunning())
   {
-    QThreadPool::globalInstance()->start(this);
     myStopThreadFlag = false;
     myThreadRunningFlag = true;
+    QThreadPool::globalInstance()->start(this);
     return true;
   }
   return false;
@@ -110,8 +113,12 @@ void ServerQueryThread::run()
     myStopMutex->lockForRead();
     if(myStopThreadFlag)
     {
+      myStopMutex->unlock();
+
+      myStopMutex->lockForWrite();
       myThreadRunningFlag = false;
       myStopMutex->unlock();
+
       delete query;
       return;
     }
@@ -123,13 +130,13 @@ void ServerQueryThread::run()
       myServerPlayerCount = query->playerList().size();
       myServerInfoMutex->unlock();
     }
-    else
-    {
-      /* On fail set to 0xff to indicate bad read, so that the client don't act on this */
-      myServerInfoMutex->lockForWrite();
-      myServerPlayerCount = 0xff;
-      myServerInfoMutex->unlock();
-    }
+    //    else
+    //    {
+    //      /* On fail set to 0xff to indicate bad read, so that the client don't act on this */
+    //      myServerInfoMutex->lockForWrite();
+    //      myServerPlayerCount = 0xff;
+    //      myServerInfoMutex->unlock();
+    //    }
     Sleeper::msleep(1000);
   }
 }

+ 123 - 0
Settings.cpp

@@ -0,0 +1,123 @@
+/*
+GNU General Public License version 3 notice
+
+Copyright (C) 2012 Mihawk <luiz@netdome.biz>. 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 "Settings.h"
+#include <QSettings>
+#include <QCoreApplication>
+#include <QStringList>
+
+Settings* Settings::ourInstance = NULL;
+QSettings* Settings::ourSettings;
+
+Settings::Settings()
+{
+  ourSettings = new QSettings(QCoreApplication::applicationDirPath() + "/cimsqwbot.cfg", QSettings::IniFormat);
+}
+
+Settings::~Settings()
+{
+  delete ourSettings;
+}
+
+Settings* Settings::globalInstance()
+{
+  if(!ourInstance)
+    ourInstance = new Settings();
+  return ourInstance;
+}
+
+QStringList Settings::serverList()
+{
+  QStringList list;
+
+  int size = ourSettings->beginReadArray("servers");
+  for(int i = 0; i < size; ++i)
+  {
+    ourSettings->setArrayIndex(i);
+    list.append(ourSettings->value("address").toString());
+  }
+  ourSettings->endArray();
+
+  return list;
+}
+
+void Settings::setServerList(QStringList &list)
+{
+  ourSettings->beginWriteArray("servers");
+  for(int i = 0; i < list.size(); ++i)
+  {
+    ourSettings->setArrayIndex(i);
+    ourSettings->setValue("address", list.at(i));
+  }
+  ourSettings->endArray();
+}
+
+QString Settings::quakeFolder() const
+{
+  return ourSettings->value("quakeFolder", QCoreApplication::applicationDirPath()).toString();
+}
+
+QString Settings::botName() const
+{
+  return ourSettings->value("botName", "cims").toString();
+}
+
+int Settings::botPing() const
+{
+  return ourSettings->value("botPing", 666).toInt();
+}
+
+int Settings::botTopColor() const
+{
+  return ourSettings->value("botTopColor", 11).toInt();
+}
+
+int Settings::botBottomColor() const
+{
+  return ourSettings->value("botBottomColor", 12).toInt();
+}
+
+bool Settings::botSpectator() const
+{
+  return ourSettings->value("botSpectator", true).toBool();
+}
+
+int Settings::floodProtTime() const
+{
+  return ourSettings->value("floodProtTime", 30).toInt();
+}
+
+unsigned int Settings::maxThreads() const
+{
+  return ourSettings->value("maxThreads", 50).toUInt();
+}
+
+void Settings::save()
+{
+  ourSettings->setValue("quakeFolder", quakeFolder());
+  ourSettings->setValue("botName", botName());
+  ourSettings->setValue("botPing", botPing());
+  ourSettings->setValue("botTopColor", botTopColor());
+  ourSettings->setValue("botBottomColor", botBottomColor());
+  ourSettings->setValue("botSpectator", botSpectator());
+  ourSettings->setValue("floodProtTime", floodProtTime());
+  ourSettings->setValue("maxThreads", maxThreads());
+  QStringList list = serverList();
+  setServerList(list);
+}

+ 55 - 0
Settings.h

@@ -0,0 +1,55 @@
+/*
+GNU General Public License version 3 notice
+
+Copyright (C) 2012 Mihawk <luiz@netdome.biz>. 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/ >.
+*/
+
+#ifndef SETTINGS_H
+#define SETTINGS_H
+
+class QSettings;
+class QString;
+class QStringList;
+
+class Settings
+{
+public:
+  static Settings*  globalInstance();
+
+  QStringList       serverList();
+  void              setServerList(QStringList& list);
+  QString           quakeFolder() const;
+
+  QString           botName() const;
+  int               botPing() const;
+  int               botTopColor() const;
+  int               botBottomColor() const;
+  bool              botSpectator() const;
+  int               floodProtTime() const;
+  unsigned int      maxThreads() const;
+
+  void              save();
+
+private:
+  static Settings*  ourInstance;
+  static QSettings* ourSettings;
+
+  Settings();
+  ~Settings();
+  Settings(Settings&) {}
+};
+
+#endif // SETTINGS_H

+ 45 - 8
SshClient.cpp

@@ -78,7 +78,8 @@ void SshClient::read()
 
 void SshClient::exited(int exitCode)
 {
-  qDebug() << "finished" << exitCode;
+  if(exitCode)
+    reconnect();
 }
 
 void SshClient::ping()
@@ -101,8 +102,6 @@ void SshClient::write(const QString &data)
 
 void SshClient::parse(const QDateTime &time, const QString &command, const QString &commandData)
 {
-  qDebug() << time << command << commandData;
-
   /* JOINED - Another user has just joined central */
   if(command == "JOINED")
   {
@@ -144,7 +143,7 @@ void SshClient::parse(const QDateTime &time, const QString &command, const QStri
   /* SYS - Central generic message */
   if(command == "SYS")
   {
-    qDebug() << "Central Message" << commandData;
+    myApp->print("Central Message: " + commandData + "\n");
     return;
   }
 
@@ -158,7 +157,8 @@ void SshClient::parse(const QDateTime &time, const QString &command, const QStri
     int serverCount, userCount;
 
     myApp->broadcast(a.cap(3) + " " + a.cap(5) + " - " + a.cap(4) + " : " + a.cap(6), &serverCount, &userCount);
-    write("BC_RE " + a.cap(1) + " Players=" + QString::number(userCount) + ",Servers=" + QString::number(serverCount) + "\n");
+    if(userCount)
+      write("BC_RE " + a.cap(1) + " Players=" + QString::number(userCount) + ",Servers=" + QString::number(serverCount) + "\n");
 
     return;
   }
@@ -188,18 +188,49 @@ void SshClient::parse(const QDateTime &time, const QString &command, const QStri
       return;
 
     QString hash = a.cap(1);
-    int     userCount = a.cap(3).toInt();
-    int     serverCount = a.cap(5).toInt();
+    QString userType = a.cap(2);
+    QString channelType = a.cap(4);
+    int     userCount = 0;
+    int     channelCount = 0;
+    int     playerCount = 0;
+    int     serverCount = 0;
+
+    if(userType == "Users")
+    {
+      userCount = a.cap(3).toInt();
+      playerCount = 0;
+    }
+    else if(userType == "Players")
+    {
+      playerCount = a.cap(3).toInt();
+      userCount = 0;
+    }
 
-    myApp->incrementReplyCounters(hash, userCount, serverCount);
+    if(channelType == "Channels")
+    {
+      channelCount = a.cap(5).toInt();
+      serverCount = 0;
+    }
+    else if(channelType == "Servers")
+    {
+      serverCount = a.cap(5).toInt();
+      channelCount = 0;
+    }
+
+    myApp->incrementReplyCounters(hash, userCount, channelCount, playerCount, serverCount);
 
     return;
   }
+
+  myApp->print("Unparsed cmd from central: " + time.toString() + " " + command + " " + commandData + "\n");
 }
 
 bool SshClient::connectToHost(const QString &user, const QString &host)
 {
   myProcess->start("ssh", QStringList() << user + "@" + host);
+  myUsername = user;
+  myHostname = host;
+
   bool r = myProcess->waitForStarted();
   if(!r)
     return false;
@@ -210,6 +241,12 @@ bool SshClient::connectToHost(const QString &user, const QString &host)
   }
 }
 
+void SshClient::reconnect()
+{
+  if(!myUsername.isEmpty() && !myHostname.isEmpty())
+    connectToHost(myUsername, myHostname);
+}
+
 void SshClient::disconnectFromHost()
 {
   killTimer(myConnectionTimerID);

+ 5 - 0
SshClient.h

@@ -22,6 +22,7 @@ along with this program.  If not, see < http://www.gnu.org/licenses/ >.
 #define SSHCLIENT_H
 
 #include <QObject>
+#include <QString>
 
 class QProcess;
 class QDateTime;
@@ -62,11 +63,15 @@ private:
   int       myPingTimerID;
   int       myPongTimerID;
   QStringList* myClients;
+  QString   myUsername;
+  QString   myHostname;
 
   void parse(const QDateTime& time, const QString& command, const QString& commandData);
 
   void ping();
   void pong();
+
+  void reconnect();
 };
 
 #endif // SSHCLIENT_H

+ 14 - 8
cimsqwbot.pro

@@ -1,6 +1,6 @@
 TEMPLATE = app
 CONFIG += console
-QT     += network sql
+QT     += network
 QT     -= gui
 
 SOURCES += main.cpp \
@@ -8,18 +8,24 @@ SOURCES += main.cpp \
     App.cpp \
     ServerQuery.cpp \
     SshClient.cpp \
-    ServerQueryThread.cpp
+    ServerQueryThread.cpp \
+    ActiveClient.cpp \
+    Settings.cpp
 
 HEADERS += \
     Client.h \
     App.h \
     ServerQuery.h \
     SshClient.h \
-    ServerQueryThread.h
+    ServerQueryThread.h \
+    ActiveClient.h \
+    Settings.h
 
-win32:CONFIG(release, debug|release): LIBS += -L$$PWD/../qwclient/release/ -lqwclient
-else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/../qwclient/debug/ -lqwclient
-else:unix:!macx:!symbian: LIBS += -L$$PWD/../qwclient/ -lqwclient
 
-INCLUDEPATH += $$PWD/../qwclient
-DEPENDPATH += $$PWD/../qwclient
+
+win32:CONFIG(release, debug|release): LIBS += -L$$PWD/../libqwclient/release/ -lqwclient
+else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/../libqwclient/debug/ -lqwclient
+else:unix:!symbian: LIBS += -L$$PWD/../libqwclient/ -lqwclient
+
+INCLUDEPATH += $$PWD/../libqwclient
+DEPENDPATH += $$PWD/../libqwclient

+ 2 - 1
main.cpp

@@ -1,6 +1,7 @@
 #include "Client.h"
 #include "App.h"
 #include <QThread>
+#include "Settings.h"
 
 class Sleeper: public QThread
 {
@@ -15,7 +16,7 @@ int main(int argc, char **argv)
 {
 	App a(argc, argv);
 
-	for(;;)
+  for(;;)
 	{
 		App::processEvents();
 		Sleeper::msleep(1);