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 14 năm trước cách đây
mục cha
commit
8f4e6b35b9
13 tập tin đã thay đổi với 564 bổ sung và 221 xóa
  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);