Merging NetworkConnection into CoreNetwork.
authorMarcus Eggenberger <egs@quassel-irc.org>
Sun, 7 Dec 2008 18:06:24 +0000 (19:06 +0100)
committerMarcus Eggenberger <egs@quassel-irc.org>
Thu, 25 Dec 2008 23:03:49 +0000 (00:03 +0100)
This is a major internal change. Needs thorough testing.

21 files changed:
src/common/ircchannel.cpp
src/common/ircuser.cpp
src/common/network.cpp
src/common/network.h
src/common/signalproxy.cpp
src/core/CMakeLists.txt
src/core/basichandler.cpp
src/core/basichandler.h
src/core/coreirclisthelper.cpp
src/core/corenetwork.cpp
src/core/corenetwork.h
src/core/coresession.cpp
src/core/coresession.h
src/core/ctcphandler.cpp
src/core/ctcphandler.h
src/core/ircserverhandler.cpp
src/core/ircserverhandler.h
src/core/networkconnection.cpp [deleted file]
src/core/networkconnection.h [deleted file]
src/core/userinputhandler.cpp
src/core/userinputhandler.h

index 04ff143..387a270 100644 (file)
@@ -192,8 +192,9 @@ void IrcChannel::part(IrcUser *ircuser) {
     disconnect(ircuser, 0, this, 0);
     emit ircUserParted(ircuser);
     
-    if(network->isMe(ircuser)) {
-      // we left -> clean up the channel and destroy it
+    if(network->isMe(ircuser) || _userModes.isEmpty()) {
+      // in either case we're no longer in the channel
+      //  -> clean up the channel and destroy it
       QList<IrcUser *> users = _userModes.keys();
       _userModes.clear();
       foreach(IrcUser *user, users) {
index ab773d9..f8a1e0a 100644 (file)
@@ -218,7 +218,6 @@ void IrcUser::joinChannel(IrcChannel *channel) {
   if(!_channels.contains(channel)) {
     _channels.insert(channel);
     channel->joinIrcUsers(this);
-    // connect(channel, SIGNAL(destroyed()), this, SLOT(channelDestroyed()));
   }
 }
 
index 9c0f915..df2a837 100644 (file)
 QTextCodec *Network::_defaultCodecForServer = 0;
 QTextCodec *Network::_defaultCodecForEncoding = 0;
 QTextCodec *Network::_defaultCodecForDecoding = 0;
+
+Network::Server Network::Server::fromVariant(const QVariant &variant) {
+  QVariantMap serverMap = variant.toMap();
+  return Server(serverMap["Host"].toString(), serverMap["Port"].toUInt(), serverMap["Password"].toString(), serverMap["UseSSL"].toBool());
+}
+
+QVariant Network::Server::toVariant() const {
+  QVariantMap serverMap;
+  serverMap["Host"] = host;
+  serverMap["Port"] = port;
+  serverMap["Password"] = password;
+  serverMap["UseSSL"] = useSsl;
+  return QVariant::fromValue<QVariantMap>(serverMap);
+}
+
 // ====================
 //  Public:
 // ====================
@@ -79,7 +94,7 @@ NetworkInfo Network::networkInfo() const {
   info.codecForServer = codecForServer();
   info.codecForEncoding = codecForEncoding();
   info.codecForDecoding = codecForDecoding();
-  info.serverList = serverList();
+  info.serverList = variantServerList();
   info.useRandomServer = useRandomServer();
   info.perform = perform();
   info.useAutoIdentify = useAutoIdentify();
@@ -137,6 +152,16 @@ QStringList Network::nicks() const {
   return nicks;
 }
 
+QVariantList Network::variantServerList() const {
+  QVariantList servers;
+  ServerList::const_iterator serverIter = _serverList.constBegin();
+  while(serverIter != _serverList.constEnd()) {
+    servers << serverIter->toVariant();
+    serverIter++;
+  }
+  return servers;
+}
+
 QString Network::prefixes() {
   if(_prefixes.isNull())
     determinePrefixes();
@@ -240,14 +265,21 @@ void Network::removeChansAndUsers() {
   _ircUsers.clear();
   QList<IrcChannel *> channels = ircChannels();
   _ircChannels.clear();
-  
+
   foreach(IrcChannel *channel, channels) {
+    proxy()->detachObject(channel);
     disconnect(channel, 0, this, 0);
   }
   foreach(IrcUser *user, users) {
+    proxy()->detachObject(user);
     disconnect(user, 0, this, 0);
+  }
+
+  // the second loop is needed because quit can have sideffects
+  foreach(IrcUser *user, users) {
     user->quit();
   }
+
   qDeleteAll(users);
   qDeleteAll(channels);
 }
@@ -445,7 +477,10 @@ void Network::setIdentity(IdentityId id) {
 }
 
 void Network::setServerList(const QVariantList &serverList) {
-  _serverList = serverList;
+  _serverList.clear();
+  foreach(QVariant variant, serverList) {
+    _serverList << Server::fromVariant(variant);
+  }
   emit serverListSet(serverList);
 }
 
@@ -569,7 +604,6 @@ void Network::initSetIrcUsersAndChannels(const QVariantMap &usersAndChannels) {
     newIrcChannel(channelIter.key(), channelIter.value().toMap());
     channelIter++;
   }
-
 }
 
 void Network::initSetSupports(const QVariantMap &supports) {
@@ -580,6 +614,12 @@ void Network::initSetSupports(const QVariantMap &supports) {
   }
 }
 
+void Network::initSetServerList(const QVariantList &serverList) {
+  foreach(QVariant variant, serverList) {
+    _serverList << Server::fromVariant(variant);
+  }
+}
+
 IrcUser *Network::updateNickFromMask(const QString &mask) {
   QString nick(nickFromMask(mask).toLower());
   IrcUser *ircuser;
index 4a432d8..84e8699 100644 (file)
@@ -88,6 +88,19 @@ public:
     D_CHANMODE = 0x08
   };
 
+  struct Server {
+    QString host;
+    uint port;
+    QString password;
+    bool useSsl;
+    Server() : port(0), useSsl(false) {}
+    Server(const QString &host, uint port, const QString &password, bool useSsl)
+      : host(host), port(port), password(password), useSsl(useSsl) {}
+
+    static Server fromVariant(const QVariant &variant);
+    QVariant toVariant() const;
+  };
+  typedef QList<Server> ServerList;
 
   Network(const NetworkId &networkid, QObject *parent = 0);
   ~Network();
@@ -122,7 +135,8 @@ public:
   inline IdentityId identity() const { return _identity; }
   QStringList nicks() const;
   inline QStringList channels() const { return _ircChannels.keys(); }
-  inline const QVariantList &serverList() const { return _serverList; }
+  inline const ServerList &serverList() const { return _serverList; }
+  QVariantList variantServerList() const;
   inline bool useRandomServer() const { return _useRandomServer; }
   inline const QStringList &perform() const { return _perform; }
   inline bool useAutoIdentify() const { return _useAutoIdentify; }
@@ -176,16 +190,15 @@ public:
   static void setDefaultCodecForEncoding(const QByteArray &name);
   static void setDefaultCodecForDecoding(const QByteArray &name);
 
-  bool autoAwayActive() const { return _autoAwayActive; }
-  void setAutoAwayActive(bool active) { _autoAwayActive = active; }
+  inline bool autoAwayActive() const { return _autoAwayActive; }
+  inline void setAutoAwayActive(bool active) { _autoAwayActive = active; }
 
 public slots:
   void setNetworkName(const QString &networkName);
   void setCurrentServer(const QString &currentServer);
   void setConnected(bool isConnected);
-  //void setConnectionState(Network::ConnectionState state);
   void setConnectionState(int state);
-  void setMyNick(const QString &mynick);
+  virtual void setMyNick(const QString &mynick);
   void setLatency(int latency);
   void setIdentity(IdentityId);
 
@@ -195,9 +208,9 @@ public slots:
   void setUseAutoIdentify(bool);
   void setAutoIdentifyService(const QString &);
   void setAutoIdentifyPassword(const QString &);
-  void setUseAutoReconnect(bool);
-  void setAutoReconnectInterval(quint32);
-  void setAutoReconnectRetries(quint16);
+  virtual void setUseAutoReconnect(bool);
+  virtual void setAutoReconnectInterval(quint32);
+  virtual void setAutoReconnectRetries(quint16);
   void setUnlimitedReconnectRetries(bool);
   void setRejoinChannels(bool);
 
@@ -213,17 +226,13 @@ public slots:
 
   //init geters
   QVariantMap initSupports() const;
-  inline QVariantList initServerList() const { return serverList(); }
+  inline QVariantList initServerList() const { return variantServerList(); }
   virtual QVariantMap initIrcUsersAndChannels() const;
-//   QStringList initIrcUsers() const;
-//   QStringList initIrcChannels() const;
 
   //init seters
   void initSetSupports(const QVariantMap &supports);
-  inline void initSetServerList(const QVariantList &serverList) { setServerList(serverList); }
+  void initSetServerList(const QVariantList &serverList);
   virtual void initSetIrcUsersAndChannels(const QVariantMap &usersAndChannels);
-//   void initSetIrcUsers(const QStringList &hostmasks);
-//   void initSetIrcChannels(const QStringList &channels);
 
   IrcUser *updateNickFromMask(const QString &mask);
 
@@ -278,8 +287,8 @@ signals:
   void ircChannelAdded(const QString &channelname);
   void ircChannelAdded(IrcChannel *);
 
-  void connectRequested(NetworkId id = 0) const;
-  void disconnectRequested(NetworkId id = 0) const;
+  void connectRequested() const;
+  void disconnectRequested() const;
   void setNetworkInfoRequested(const NetworkInfo &) const;
 
 protected:
@@ -305,7 +314,7 @@ private:
   QHash<QString, IrcChannel *> _ircChannels; // stores all known channels
   QHash<QString, QString> _supports;  // stores results from RPL_ISUPPORT
 
-  QVariantList _serverList;
+  ServerList _serverList;
   bool _useRandomServer;
   QStringList _perform;
 
index 5d30203..c551c24 100644 (file)
@@ -440,8 +440,6 @@ void SignalProxy::setArgTypes(QObject* obj, int methodId) {
 
 const QList<int> &SignalProxy::argTypes(QObject *obj, int methodId) {
   const QMetaObject *meta = metaObject(obj);
-  if(!_classInfo.contains(meta))
-    qDebug() << obj << meta;
   Q_ASSERT(_classInfo.contains(meta));
   if(!_classInfo[meta]->argTypes.contains(methodId))
     setArgTypes(obj, methodId);
@@ -719,9 +717,9 @@ void SignalProxy::detachSender() {
 }
 
 void SignalProxy::detachObject(QObject* obj) {
+  stopSync(static_cast<SyncableObject *>(obj));
   detachSignals(obj);
   detachSlots(obj);
-  stopSync(static_cast<SyncableObject *>(obj));
 }
 
 void SignalProxy::detachSignals(QObject* sender) {
index 4491f56..77525fb 100644 (file)
@@ -24,7 +24,6 @@ set(SOURCES
     coreusersettings.cpp
     ctcphandler.cpp
     ircserverhandler.cpp
-    networkconnection.cpp
     sessionthread.cpp
     sqlitestorage.cpp
     storage.cpp
@@ -46,7 +45,6 @@ set(MOC_HDRS
     coresession.h
     ctcphandler.h
     ircserverhandler.h
-    networkconnection.h
     sqlitestorage.h
     storage.h
     sessionthread.h
index 0bb1438..4df9ea2 100644 (file)
 #include "util.h"
 #include "logger.h"
 
-BasicHandler::BasicHandler(NetworkConnection *parent)
+BasicHandler::BasicHandler(CoreNetwork *parent)
   : QObject(parent),
     defaultHandler(-1),
-    _networkConnection(parent),
+    _network(parent),
     initDone(false)
 {
   connect(this, SIGNAL(displayMsg(Message::Type, BufferInfo::Type, QString, QString, QString, Message::Flags)),
-         networkConnection(), SIGNAL(displayMsg(Message::Type, BufferInfo::Type, QString, QString, QString, Message::Flags)));
+         network(), SIGNAL(displayMsg(Message::Type, BufferInfo::Type, QString, QString, QString, Message::Flags)));
 
   connect(this, SIGNAL(putCmd(QString, const QList<QByteArray> &, const QByteArray &)),
-         networkConnection(), SLOT(putCmd(QString, const QList<QByteArray> &, const QByteArray &)));
+         network(), SLOT(putCmd(QString, const QList<QByteArray> &, const QByteArray &)));
 
   connect(this, SIGNAL(putRawLine(const QByteArray &)),
-          networkConnection(), SLOT(putRawLine(const QByteArray &)));
+          network(), SLOT(putRawLine(const QByteArray &)));
 }
 
 QStringList BasicHandler::providesHandlers() {
@@ -94,64 +94,64 @@ void BasicHandler::handle(const QString &member, QGenericArgument val0,
 }
 
 QString BasicHandler::serverDecode(const QByteArray &string) {
-  return networkConnection()->serverDecode(string);
+  return network()->serverDecode(string);
 }
 
 QStringList BasicHandler::serverDecode(const QList<QByteArray> &stringlist) {
   QStringList list;
-  foreach(QByteArray s, stringlist) list << networkConnection()->serverDecode(s);
+  foreach(QByteArray s, stringlist) list << network()->serverDecode(s);
   return list;
 }
 
 QString BasicHandler::channelDecode(const QString &bufferName, const QByteArray &string) {
-  return networkConnection()->channelDecode(bufferName, string);
+  return network()->channelDecode(bufferName, string);
 }
 
 QStringList BasicHandler::channelDecode(const QString &bufferName, const QList<QByteArray> &stringlist) {
   QStringList list;
-  foreach(QByteArray s, stringlist) list << networkConnection()->channelDecode(bufferName, s);
+  foreach(QByteArray s, stringlist) list << network()->channelDecode(bufferName, s);
   return list;
 }
 
 QString BasicHandler::userDecode(const QString &userNick, const QByteArray &string) {
-  return networkConnection()->userDecode(userNick, string);
+  return network()->userDecode(userNick, string);
 }
 
 QStringList BasicHandler::userDecode(const QString &userNick, const QList<QByteArray> &stringlist) {
   QStringList list;
-  foreach(QByteArray s, stringlist) list << networkConnection()->userDecode(userNick, s);
+  foreach(QByteArray s, stringlist) list << network()->userDecode(userNick, s);
   return list;
 }
 
 /*** ***/
 
 QByteArray BasicHandler::serverEncode(const QString &string) {
-  return networkConnection()->serverEncode(string);
+  return network()->serverEncode(string);
 }
 
 QList<QByteArray> BasicHandler::serverEncode(const QStringList &stringlist) {
   QList<QByteArray> list;
-  foreach(QString s, stringlist) list << networkConnection()->serverEncode(s);
+  foreach(QString s, stringlist) list << network()->serverEncode(s);
   return list;
 }
 
 QByteArray BasicHandler::channelEncode(const QString &bufferName, const QString &string) {
-  return networkConnection()->channelEncode(bufferName, string);
+  return network()->channelEncode(bufferName, string);
 }
 
 QList<QByteArray> BasicHandler::channelEncode(const QString &bufferName, const QStringList &stringlist) {
   QList<QByteArray> list;
-  foreach(QString s, stringlist) list << networkConnection()->channelEncode(bufferName, s);
+  foreach(QString s, stringlist) list << network()->channelEncode(bufferName, s);
   return list;
 }
 
 QByteArray BasicHandler::userEncode(const QString &userNick, const QString &string) {
-  return networkConnection()->userEncode(userNick, string);
+  return network()->userEncode(userNick, string);
 }
 
 QList<QByteArray> BasicHandler::userEncode(const QString &userNick, const QStringList &stringlist) {
   QList<QByteArray> list;
-  foreach(QString s, stringlist) list << networkConnection()->userEncode(userNick, s);
+  foreach(QString s, stringlist) list << network()->userEncode(userNick, s);
   return list;
 }
 
index c276c96..0df1830 100644 (file)
@@ -18,8 +18,8 @@
  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
  ***************************************************************************/
 
-#ifndef _BASICHANDLER_H_
-#define _BASICHANDLER_H_
+#ifndef BASICHANDLER_H_
+#define BASICHANDLER_H_
 
 #include <QObject>
 #include <QString>
@@ -29,7 +29,7 @@
 
 #include "message.h"
 
-#include "networkconnection.h"
+#include "corenetwork.h"
 
 class CoreSession;
 
@@ -37,7 +37,7 @@ class BasicHandler : public QObject {
   Q_OBJECT
 
 public:
-  BasicHandler(NetworkConnection *parent = 0);
+  BasicHandler(CoreNetwork *parent = 0);
 
   QStringList providesHandlers();
 
@@ -71,9 +71,8 @@ protected:
                       QGenericArgument val7 = QGenericArgument(), QGenericArgument val8 = QGenericArgument());
 
 
-  inline Network *network() const { return _networkConnection->network(); }
-  inline NetworkConnection *networkConnection() const { return _networkConnection; }
-  inline CoreSession *coreSession() const { return _networkConnection->coreSession(); }
+  inline CoreNetwork *network() const { return _network; }
+  inline CoreSession *coreSession() const { return _network->coreSession(); }
 
   BufferInfo::Type typeByTarget(const QString &target) const;
 
@@ -81,7 +80,7 @@ private:
   const QHash<QString, int> &handlerHash();
   QHash<QString, int> _handlerHash;
   int defaultHandler;
-  NetworkConnection *_networkConnection;
+  CoreNetwork *_network;
   bool initDone;
 };
 #endif
index dbcdcc4..312ed3d 100644 (file)
@@ -20,7 +20,7 @@
 
 #include "coreirclisthelper.h"
 
-#include "networkconnection.h"
+#include "corenetwork.h"
 #include "userinputhandler.h"
 
 QVariantList CoreIrcListHelper::requestChannelList(const NetworkId &netId, const QStringList &channelFilters) {
@@ -44,10 +44,10 @@ bool CoreIrcListHelper::addChannel(const NetworkId &netId, const QString &channe
 }
 
 bool CoreIrcListHelper::dispatchQuery(const NetworkId &netId, const QString &query) {
-  NetworkConnection *networkConnection = coreSession()->networkConnection(netId);
-  if(networkConnection) {
+  CoreNetwork *network = coreSession()->network(netId);
+  if(network) {
     _channelLists[netId] = QList<ChannelDescription>();
-    networkConnection->userInputHandler()->handleList(BufferInfo(), query);
+    network->userInputHandler()->handleList(BufferInfo(), query);
     _queryTimeout[startTimer(10000)] = netId;
     return true;
   } else {
index a7cbd22..a5c40e6 100644 (file)
  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
  ***************************************************************************/
 
-#include "core.h"
 #include "corenetwork.h"
+
+
+#include "core.h"
 #include "coresession.h"
+#include "identity.h"
 
-#include "logger.h"
+#include "ircserverhandler.h"
+#include "userinputhandler.h"
+#include "ctcphandler.h"
 
 CoreNetwork::CoreNetwork(const NetworkId &networkid, CoreSession *session)
   : Network(networkid, session),
-    _coreSession(session)
+    _coreSession(session),
+    _ircServerHandler(new IrcServerHandler(this)),
+    _userInputHandler(new UserInputHandler(this)),
+    _ctcpHandler(new CtcpHandler(this)),
+    _autoReconnectCount(0),
+    _quitRequested(false),
+
+    _previousConnectionAttemptFailed(false),
+    _lastUsedServerIndex(0),
+
+    // TODO make autowho configurable (possibly per-network)
+    _autoWhoEnabled(true),
+    _autoWhoInterval(90),
+    _autoWhoNickLimit(0), // unlimited
+    _autoWhoDelay(3)
 {
+  _autoReconnectTimer.setSingleShot(true);
+  _socketCloseTimer.setSingleShot(true);
+  connect(&_socketCloseTimer, SIGNAL(timeout()), this, SLOT(socketCloseTimeout()));
+
+  _pingTimer.setInterval(60000);
+  connect(&_pingTimer, SIGNAL(timeout()), this, SLOT(sendPing()));
+
+  _autoWhoTimer.setInterval(_autoWhoDelay * 1000);
+  _autoWhoCycleTimer.setInterval(_autoWhoInterval * 1000);
+
+  QHash<QString, QString> channels = coreSession()->persistentChannels(networkId());
+  foreach(QString chan, channels.keys()) {
+    _channelKeys[chan.toLower()] = channels[chan];
+  }
+
+  connect(&_autoReconnectTimer, SIGNAL(timeout()), this, SLOT(doAutoReconnect()));
+  connect(&_autoWhoTimer, SIGNAL(timeout()), this, SLOT(sendAutoWho()));
+  connect(&_autoWhoCycleTimer, SIGNAL(timeout()), this, SLOT(startAutoWhoCycle()));
+  connect(&_tokenBucketTimer, SIGNAL(timeout()), this, SLOT(fillBucketAndProcessQueue()));
+  connect(this, SIGNAL(connectRequested()), this, SLOT(connectToIrc()));
+
+
+  connect(&socket, SIGNAL(disconnected()), this, SLOT(socketDisconnected()));
+  connect(&socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(socketError(QAbstractSocket::SocketError)));
+  connect(&socket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(socketStateChanged(QAbstractSocket::SocketState)));
+  connect(&socket, SIGNAL(readyRead()), this, SLOT(socketHasData()));
+#ifdef HAVE_SSL
+  connect(&socket, SIGNAL(connected()), this, SLOT(sslSocketConnected()));
+  connect(&socket, SIGNAL(encrypted()), this, SLOT(socketInitialized()));
+  connect(&socket, SIGNAL(sslErrors(const QList<QSslError> &)), this, SLOT(sslErrors(const QList<QSslError> &)));
+#else
+  connect(&socket, SIGNAL(connected()), this, SLOT(socketInitialized()));
+#endif
+}
+
+CoreNetwork::~CoreNetwork() {
+  if(connectionState() != Disconnected && connectionState() != Network::Reconnecting)
+    disconnectFromIrc(false);      // clean up, but this does not count as requested disconnect!
+  disconnect(&socket, 0, this, 0); // this keeps the socket from triggering events during clean up
+  delete _ircServerHandler;
+  delete _userInputHandler;
+  delete _ctcpHandler;
+}
+
+QString CoreNetwork::channelDecode(const QString &bufferName, const QByteArray &string) const {
+  if(!bufferName.isEmpty()) {
+    IrcChannel *channel = ircChannel(bufferName);
+    if(channel)
+      return channel->decodeString(string);
+  }
+  return decodeString(string);
+}
+
+QString CoreNetwork::userDecode(const QString &userNick, const QByteArray &string) const {
+  IrcUser *user = ircUser(userNick);
+  if(user)
+    return user->decodeString(string);
+  return decodeString(string);
+}
+
+QByteArray CoreNetwork::channelEncode(const QString &bufferName, const QString &string) const {
+  if(!bufferName.isEmpty()) {
+    IrcChannel *channel = ircChannel(bufferName);
+    if(channel)
+      return channel->encodeString(string);
+  }
+  return encodeString(string);
+}
+
+QByteArray CoreNetwork::userEncode(const QString &userNick, const QString &string) const {
+  IrcUser *user = ircUser(userNick);
+  if(user)
+    return user->encodeString(string);
+  return encodeString(string);
+}
+
+void CoreNetwork::connectToIrc(bool reconnecting) {
+  if(!reconnecting && useAutoReconnect() && _autoReconnectCount == 0) {
+    _autoReconnectTimer.setInterval(autoReconnectInterval() * 1000);
+    if(unlimitedReconnectRetries())
+      _autoReconnectCount = -1;
+    else
+      _autoReconnectCount = autoReconnectRetries();
+  }
+  if(serverList().isEmpty()) {
+    qWarning() << "Server list empty, ignoring connect request!";
+    return;
+  }
+  Identity *identity = identityPtr();
+  if(!identity) {
+    qWarning() << "Invalid identity configures, ignoring connect request!";
+    return;
+  }
+  // use a random server?
+  if(useRandomServer()) {
+    _lastUsedServerIndex = qrand() % serverList().size();
+  } else if(_previousConnectionAttemptFailed) {
+    // cycle to next server if previous connection attempt failed
+    displayMsg(Message::Server, BufferInfo::StatusBuffer, "", tr("Connection failed. Cycling to next Server"));
+    if(++_lastUsedServerIndex == serverList().size()) {
+      _lastUsedServerIndex = 0;
+    }
+  }
+  _previousConnectionAttemptFailed = false;
+
+  Server server = usedServer();
+  displayStatusMsg(tr("Connecting to %1:%2...").arg(server.host).arg(server.port));
+  displayMsg(Message::Server, BufferInfo::StatusBuffer, "", tr("Connecting to %1:%2...").arg(server.host).arg(server.port));
+  socket.connectToHost(server.host, server.port);
+}
+
+void CoreNetwork::disconnectFromIrc(bool requested, const QString &reason) {
+  _quitRequested = requested; // see socketDisconnected();
+  _autoReconnectTimer.stop();
+  _autoReconnectCount = 0; // prohibiting auto reconnect
+  displayMsg(Message::Server, BufferInfo::StatusBuffer, "", tr("Disconnecting."));
+  if(socket.state() == QAbstractSocket::UnconnectedState) {
+    socketDisconnected();
+  } else if(socket.state() < QAbstractSocket::ConnectedState || !requested) {
+    // we might be in a state waiting for a timeout...
+    // or (!requested) this is a core shutdown...
+    // in both cases we don't really care... set a disconnected state
+    socket.close();
+    socketDisconnected();
+  } else {
+    // quit gracefully if it's user requested quit
+    userInputHandler()->issueQuit(reason);
+    // the irc server has 10 seconds to close the socket
+    _socketCloseTimer.start(10000);
+  }
+}
+
+void CoreNetwork::userInput(BufferInfo buf, QString msg) {
+  userInputHandler()->handleUserInput(buf, msg);
+}
+
+void CoreNetwork::putRawLine(QByteArray s) {
+  if(_tokenBucket > 0)
+    writeToSocket(s);
+  else
+    _msgQueue.append(s);
+}
+
+void CoreNetwork::putCmd(const QString &cmd, const QList<QByteArray> &params, const QByteArray &prefix) {
+  QByteArray msg;
+
+  if(!prefix.isEmpty())
+    msg += ":" + prefix + " ";
+  msg += cmd.toUpper().toAscii();
+
+  for(int i = 0; i < params.size() - 1; i++) {
+    msg += " " + params[i];
+  }
+  if(!params.isEmpty())
+    msg += " :" + params.last();
+
+  putRawLine(msg);
+}
+
+void CoreNetwork::setChannelJoined(const QString &channel) {
+  _autoWhoQueue.prepend(channel.toLower()); // prepend so this new chan is the first to be checked
+
+  Core::setChannelPersistent(userId(), networkId(), channel, true);
+  Core::setPersistentChannelKey(userId(), networkId(), channel, _channelKeys[channel.toLower()]);
+}
+
+void CoreNetwork::setChannelParted(const QString &channel) {
+  removeChannelKey(channel);
+  _autoWhoQueue.removeAll(channel.toLower());
+  _autoWhoInProgress.remove(channel.toLower());
+
+  Core::setChannelPersistent(userId(), networkId(), channel, false);
+}
+
+void CoreNetwork::addChannelKey(const QString &channel, const QString &key) {
+  if(key.isEmpty()) {
+    removeChannelKey(channel);
+  } else {
+    _channelKeys[channel.toLower()] = key;
+  }
+}
+
+void CoreNetwork::removeChannelKey(const QString &channel) {
+  _channelKeys.remove(channel.toLower());
+}
+
+bool CoreNetwork::setAutoWhoDone(const QString &channel) {
+  if(_autoWhoInProgress.value(channel.toLower(), 0) <= 0)
+    return false;
+  _autoWhoInProgress[channel.toLower()]--;
+  return true;
+}
+
+void CoreNetwork::setMyNick(const QString &mynick) {
+  Network::setMyNick(mynick);
+  if(connectionState() == Network::Initializing)
+    networkInitialized();
+}
+
+void CoreNetwork::socketHasData() {
+  while(socket.canReadLine()) {
+    QByteArray s = socket.readLine().trimmed();
+    ircServerHandler()->handleServerMsg(s);
+  }
+}
+
+void CoreNetwork::socketError(QAbstractSocket::SocketError) {
+  _previousConnectionAttemptFailed = true;
+  qWarning() << qPrintable(tr("Could not connect to %1 (%2)").arg(networkName(), socket.errorString()));
+  emit connectionError(socket.errorString());
+  emit displayMsg(Message::Error, BufferInfo::StatusBuffer, "", tr("Connection failure: %1").arg(socket.errorString()));
+  emitConnectionError(socket.errorString());
+  if(socket.state() < QAbstractSocket::ConnectedState) {
+    socketDisconnected();
+  }
+}
+
+#ifdef HAVE_SSL
+void CoreNetwork::sslSocketConnected() {
+  if(!usedServer().useSsl)
+    socketInitialized();
+  else
+    socket.startClientEncryption();
+}
+#endif
+
+void CoreNetwork::socketInitialized() {
+  Identity *identity = identityPtr();
+  if(!identity) {
+    qCritical() << "Identity invalid!";
+    disconnectFromIrc();
+    return;
+  }
+
+  // TokenBucket to avoid sending too much at once
+  _messagesPerSecond = 1;
+  _burstSize = 5;
+  _tokenBucket = 5; // init with a full bucket
+  _tokenBucketTimer.start(_messagesPerSecond * 1000);
+
+  QString passwd = usedServer().password;
+  if(!passwd.isEmpty()) {
+    putRawLine(serverEncode(QString("PASS %1").arg(passwd)));
+  }
+  putRawLine(serverEncode(QString("NICK :%1").arg(identity->nicks()[0])));
+  putRawLine(serverEncode(QString("USER %1 8 * :%2").arg(identity->ident(), identity->realName())));
+}
+
+void CoreNetwork::socketDisconnected() {
+  _pingTimer.stop();
+  _autoWhoCycleTimer.stop();
+  _autoWhoTimer.stop();
+  _autoWhoQueue.clear();
+  _autoWhoInProgress.clear();
+
+  _socketCloseTimer.stop();
+
+  _tokenBucketTimer.stop();
+
+  IrcUser *me_ = me();
+  if(me_) {
+    foreach(QString channel, me_->channels())
+      emit displayMsg(Message::Quit, BufferInfo::ChannelBuffer, channel, "", me_->hostmask());
+  }
+
+  setConnected(false);
+  emit disconnected(networkId());
+  if(_quitRequested) {
+    setConnectionState(Network::Disconnected);
+    Core::setNetworkConnected(userId(), networkId(), false);
+  } else if(_autoReconnectCount != 0) {
+    setConnectionState(Network::Reconnecting);
+    if(_autoReconnectCount == autoReconnectRetries())
+      doAutoReconnect(); // first try is immediate
+    else
+      _autoReconnectTimer.start();
+  }
+}
+
+void CoreNetwork::socketStateChanged(QAbstractSocket::SocketState socketState) {
+  Network::ConnectionState state;
+  switch(socketState) {
+    case QAbstractSocket::UnconnectedState:
+      state = Network::Disconnected;
+      break;
+    case QAbstractSocket::HostLookupState:
+    case QAbstractSocket::ConnectingState:
+      state = Network::Connecting;
+      break;
+    case QAbstractSocket::ConnectedState:
+      state = Network::Initializing;
+      break;
+    case QAbstractSocket::ClosingState:
+      state = Network::Disconnecting;
+      break;
+    default:
+      state = Network::Disconnected;
+  }
+  setConnectionState(state);
+}
+
+void CoreNetwork::networkInitialized() {
+  setConnectionState(Network::Initialized);
+  setConnected(true);
+
+  if(useAutoReconnect()) {
+    // reset counter
+    _autoReconnectCount = autoReconnectRetries();
+  }
+
+  sendPerform();
+
+  _pingTimer.start();
+
+  if(_autoWhoEnabled) {
+    _autoWhoCycleTimer.start();
+    _autoWhoTimer.start();
+    startAutoWhoCycle();  // FIXME wait for autojoin to be completed
+  }
+
+  Core::bufferInfo(userId(), networkId(), BufferInfo::StatusBuffer); // create status buffer
+  Core::setNetworkConnected(userId(), networkId(), true);
+}
+
+void CoreNetwork::sendPerform() {
+  BufferInfo statusBuf = BufferInfo::fakeStatusBuffer(networkId());
+
+  // do auto identify
+  if(useAutoIdentify() && !autoIdentifyService().isEmpty() && !autoIdentifyPassword().isEmpty()) {
+    userInputHandler()->handleMsg(statusBuf, QString("%1 IDENTIFY %2").arg(autoIdentifyService(), autoIdentifyPassword()));
+  }
+
+  // send perform list
+  foreach(QString line, perform()) {
+    if(!line.isEmpty()) userInput(statusBuf, line);
+  }
+
+  // rejoin channels we've been in
+  QStringList channels, keys;
+  foreach(QString chan, persistentChannels()) {
+    QString key = channelKey(chan);
+    if(!key.isEmpty()) {
+      channels.prepend(chan);
+      keys.prepend(key);
+    } else {
+      channels.append(chan);
+    }
+  }
+  QString joinString = QString("%1 %2").arg(channels.join(",")).arg(keys.join(",")).trimmed();
+  if(!joinString.isEmpty())
+    userInputHandler()->handleJoin(statusBuf, joinString);
+}
+
+void CoreNetwork::setUseAutoReconnect(bool use) {
+  Network::setUseAutoReconnect(use);
+  if(!use)
+    _autoReconnectTimer.stop();
+}
+
+void CoreNetwork::setAutoReconnectInterval(quint32 interval) {
+  Network::setAutoReconnectInterval(interval);
+  _autoReconnectTimer.setInterval(interval * 1000);
+}
+
+void CoreNetwork::setAutoReconnectRetries(quint16 retries) {
+  Network::setAutoReconnectRetries(retries);
+  if(_autoReconnectCount != 0) {
+    if(unlimitedReconnectRetries())
+      _autoReconnectCount = -1;
+    else
+      _autoReconnectCount = autoReconnectRetries();
+  }
+}
+
+void CoreNetwork::doAutoReconnect() {
+  if(connectionState() != Network::Disconnected && connectionState() != Network::Reconnecting) {
+    qWarning() << "CoreNetwork::doAutoReconnect(): Cannot reconnect while not being disconnected!";
+    return;
+  }
+  if(_autoReconnectCount > 0)
+    _autoReconnectCount--;
+  connectToIrc(true);
+}
+
+void CoreNetwork::sendPing() {
+  userInputHandler()->handlePing(BufferInfo(), QString());
+}
+
+void CoreNetwork::sendAutoWho() {
+  while(!_autoWhoQueue.isEmpty()) {
+    QString chan = _autoWhoQueue.takeFirst();
+    IrcChannel *ircchan = ircChannel(chan);
+    if(!ircchan) continue;
+    if(_autoWhoNickLimit > 0 && ircchan->ircUsers().count() > _autoWhoNickLimit) continue;
+    _autoWhoInProgress[chan]++;
+    putRawLine("WHO " + serverEncode(chan));
+    if(_autoWhoQueue.isEmpty() && _autoWhoEnabled && !_autoWhoCycleTimer.isActive()) {
+      // Timer was stopped, means a new cycle is due immediately
+      _autoWhoCycleTimer.start();
+      startAutoWhoCycle();
+    }
+    break;
+  }
+}
+
+void CoreNetwork::startAutoWhoCycle() {
+  if(!_autoWhoQueue.isEmpty()) {
+    _autoWhoCycleTimer.stop();
+    return;
+  }
+  _autoWhoQueue = channels();
+}
+
+#ifdef HAVE_SSL
+void CoreNetwork::sslErrors(const QList<QSslError> &sslErrors) {
+  Q_UNUSED(sslErrors)
+  socket.ignoreSslErrors();
+  /* TODO errorhandling
+  QVariantMap errmsg;
+  QVariantList errnums;
+  foreach(QSslError err, errors) errnums << err.error();
+  errmsg["SslErrors"] = errnums;
+  errmsg["SslCert"] = socket.peerCertificate().toPem();
+  errmsg["PeerAddress"] = socket.peerAddress().toString();
+  errmsg["PeerPort"] = socket.peerPort();
+  errmsg["PeerName"] = socket.peerName();
+  emit sslErrors(errmsg);
+  disconnectFromIrc();
+  */
+}
+#endif  // HAVE_SSL
+
+void CoreNetwork::fillBucketAndProcessQueue() {
+  if(_tokenBucket < _burstSize) {
+    _tokenBucket++;
+  }
+
+  while(_msgQueue.size() > 0 && _tokenBucket > 0) {
+    writeToSocket(_msgQueue.takeFirst());
+  }
+}
+
+void CoreNetwork::writeToSocket(const QByteArray &data) {
+  socket.write(data);
+  socket.write("\r\n");
+  _tokenBucket--;
 }
 
 void CoreNetwork::requestConnect() const {
@@ -35,7 +500,7 @@ void CoreNetwork::requestConnect() const {
     qWarning() << "Requesting connect while already being connected!";
     return;
   }
-  emit connectRequested(networkId());
+  Network::requestConnect();
 }
 
 void CoreNetwork::requestDisconnect() const {
@@ -43,7 +508,7 @@ void CoreNetwork::requestDisconnect() const {
     qWarning() << "Requesting disconnect while not being connected!";
     return;
   }
-  emit disconnectRequested(networkId());
+  userInputHandler()->handleQuit(BufferInfo(), QString());
 }
 
 void CoreNetwork::requestSetNetworkInfo(const NetworkInfo &info) {
index 2989932..f227de4 100644 (file)
 #include "network.h"
 #include "coreircchannel.h"
 
-class CoreSession;
+#include <QTimer>
+
+#ifdef HAVE_SSL
+# include <QSslSocket>
+# include <QSslError>
+#else
+# include <QTcpSocket>
+#endif
+
+#include "coresession.h"
+
+class Identity;
+class IrcServerHandler;
+class UserInputHandler;
+class CtcpHandler;
 
 class CoreNetwork : public Network {
   Q_OBJECT
 
 public:
   CoreNetwork(const NetworkId &networkid, CoreSession *session);
-
+  ~CoreNetwork();
   inline virtual const QMetaObject *syncMetaObject() const { return &Network::staticMetaObject; }
 
+  inline Identity *identityPtr() const { return coreSession()->identity(identity()); }
   inline CoreSession *coreSession() const { return _coreSession; }
 
+  inline IrcServerHandler *ircServerHandler() const { return _ircServerHandler; }
+  inline UserInputHandler *userInputHandler() const { return _userInputHandler; }
+  inline CtcpHandler *ctcpHandler() const { return _ctcpHandler; }
+
+  //! Decode a string using the server (network) decoding.
+  inline QString serverDecode(const QByteArray &string) const { return decodeServerString(string); }
+
+  //! Decode a string using a channel-specific encoding if one is set (and use the standard encoding else).
+  QString channelDecode(const QString &channelName, const QByteArray &string) const;
+
+  //! Decode a string using an IrcUser-specific encoding, if one exists (using the standaed encoding else).
+  QString userDecode(const QString &userNick, const QByteArray &string) const;
+
+  //! Encode a string using the server (network) encoding.
+  inline QByteArray serverEncode(const QString &string) const { return encodeServerString(string); }
+
+  //! Encode a string using the channel-specific encoding, if set, and use the standard encoding else.
+  QByteArray channelEncode(const QString &channelName, const QString &string) const;
+
+  //! Encode a string using the user-specific encoding, if set, and use the standard encoding else.
+  QByteArray userEncode(const QString &userNick, const QString &string) const;
+
+  inline QString channelKey(const QString &channel) const { return _channelKeys.value(channel.toLower(), QString()); }
+  inline QStringList persistentChannels() const { return _channelKeys.keys(); }
+
+  inline bool isAutoWhoInProgress(const QString &channel) const { return _autoWhoInProgress.value(channel.toLower(), 0); }
+
+  inline UserId userId() const { return _coreSession->user(); }
+
 public slots:
+  virtual void setMyNick(const QString &mynick);
+
   virtual void requestConnect() const;
   virtual void requestDisconnect() const;
   virtual void requestSetNetworkInfo(const NetworkInfo &info);
 
+  virtual void setUseAutoReconnect(bool);
+  virtual void setAutoReconnectInterval(quint32);
+  virtual void setAutoReconnectRetries(quint16);
+
+  void connectToIrc(bool reconnecting = false);
+  void disconnectFromIrc(bool requested = true, const QString &reason = QString());
+
+  void userInput(BufferInfo bufferInfo, QString msg);
+  void putRawLine(QByteArray input);
+  void putCmd(const QString &cmd, const QList<QByteArray> &params, const QByteArray &prefix = QByteArray());
+
+  void setChannelJoined(const QString &channel);
+  void setChannelParted(const QString &channel);
+  void addChannelKey(const QString &channel, const QString &key);
+  void removeChannelKey(const QString &channel);
+
+  bool setAutoWhoDone(const QString &channel);
+
+  inline const Server &usedServer() const { return serverList()[_lastUsedServerIndex]; }
+
+signals:
+  void recvRawServerMsg(QString);
+  void displayStatusMsg(QString);
+  void displayMsg(Message::Type, BufferInfo::Type, QString target, QString text, QString sender = "", Message::Flags flags = Message::None);
+  void disconnected(NetworkId networkId);
+  void connectionError(const QString &errorMsg);
+
+  void quitRequested(NetworkId networkId);
+  void sslErrors(const QVariant &errorData);
+
 protected:
   inline virtual IrcChannel *ircChannelFactory(const QString &channelname) { return new CoreIrcChannel(channelname, this); }
 
+private slots:
+  void socketHasData();
+  void socketError(QAbstractSocket::SocketError);
+  void socketInitialized();
+  inline void socketCloseTimeout() { socket.disconnectFromHost(); }
+  void socketDisconnected();
+  void socketStateChanged(QAbstractSocket::SocketState);
+  void networkInitialized();
+
+  void sendPerform();
+  void doAutoReconnect();
+  void sendPing();
+  void sendAutoWho();
+  void startAutoWhoCycle();
+
+#ifdef HAVE_SSL
+  void sslSocketConnected();
+  void sslErrors(const QList<QSslError> &errors);
+#endif
+
+  void fillBucketAndProcessQueue();
+
+  void writeToSocket(const QByteArray &data);
+
 private:
   CoreSession *_coreSession;
+
+#ifdef HAVE_SSL
+  QSslSocket socket;
+#else
+  QTcpSocket socket;
+#endif
+
+  IrcServerHandler *_ircServerHandler;
+  UserInputHandler *_userInputHandler;
+  CtcpHandler *_ctcpHandler;
+
+  QHash<QString, QString> _channelKeys;  // stores persistent channels and their passwords, if any
+
+  QTimer _autoReconnectTimer;
+  int _autoReconnectCount;
+
+  QTimer _socketCloseTimer;
+
+  /* this flag triggers quitRequested() once the socket is closed
+   * it is needed to determine whether or not the connection needs to be
+   * in the automatic session restore. */
+  bool _quitRequested;
+
+  bool _previousConnectionAttemptFailed;
+  int _lastUsedServerIndex;
+
+  QTimer _pingTimer;
+
+  bool _autoWhoEnabled;
+  QStringList _autoWhoQueue;
+  QHash<QString, int> _autoWhoInProgress;
+  int _autoWhoInterval;
+  int _autoWhoNickLimit;
+  int _autoWhoDelay;
+  QTimer _autoWhoTimer, _autoWhoCycleTimer;
+
+  QTimer _tokenBucketTimer;
+  int _messagesPerSecond;   // token refill speed
+  int _burstSize;           // size of the token bucket
+  int _tokenBucket;         // the virtual bucket that holds the tokens
+  QList<QByteArray> _msgQueue;
 };
 
 #endif //CORENETWORK_H
index bb4b3dd..2e9184c 100644 (file)
@@ -22,9 +22,7 @@
 
 #include "core.h"
 #include "coresession.h"
-#include "networkconnection.h"
 #include "userinputhandler.h"
-
 #include "signalproxy.h"
 #include "buffersyncer.h"
 #include "corebacklogmanager.h"
@@ -60,11 +58,9 @@ CoreSession::CoreSession(UserId uid, bool restoreState, QObject *parent)
   connect(p, SIGNAL(connected()), this, SLOT(clientsConnected()));
   connect(p, SIGNAL(disconnected()), this, SLOT(clientsDisconnected()));
 
-  //p->attachSlot(SIGNAL(disconnectFromNetwork(NetworkId)), this, SLOT(disconnectFromNetwork(NetworkId))); // FIXME
   p->attachSlot(SIGNAL(sendInput(BufferInfo, QString)), this, SLOT(msgFromClient(BufferInfo, QString)));
   p->attachSignal(this, SIGNAL(displayMsg(Message)));
   p->attachSignal(this, SIGNAL(displayStatusMsg(QString, QString)));
-  p->attachSignal(this, SIGNAL(bufferInfoUpdated(BufferInfo)));
 
   p->attachSignal(this, SIGNAL(identityCreated(const Identity &)));
   p->attachSignal(this, SIGNAL(identityRemoved(IdentityId)));
@@ -111,9 +107,6 @@ CoreSession::CoreSession(UserId uid, bool restoreState, QObject *parent)
 
 CoreSession::~CoreSession() {
   saveSessionState();
-  foreach(NetworkConnection *conn, _connections.values()) {
-    delete conn;
-  }
   foreach(CoreNetwork *net, _networks.values()) {
     delete net;
   }
@@ -124,11 +117,6 @@ CoreNetwork *CoreSession::network(NetworkId id) const {
   return 0;
 }
 
-NetworkConnection *CoreSession::networkConnection(NetworkId id) const {
-  if(_connections.contains(id)) return _connections[id];
-  return 0;
-}
-
 Identity *CoreSession::identity(IdentityId id) const {
   if(_identities.contains(id)) return _identities[id];
   return 0;
@@ -167,67 +155,18 @@ void CoreSession::loadSettings() {
 }
 
 void CoreSession::saveSessionState() const {
-
 }
 
 void CoreSession::restoreSessionState() {
   QList<NetworkId> nets = Core::connectedNetworks(user());
+  CoreNetwork *net = 0;
   foreach(NetworkId id, nets) {
-    connectToNetwork(id);
+    net = network(id);
+    Q_ASSERT(net);
+    net->connectToIrc();
   }
 }
 
-void CoreSession::updateBufferInfo(UserId uid, const BufferInfo &bufinfo) {
-  if(uid == user()) emit bufferInfoUpdated(bufinfo);
-}
-
-void CoreSession::connectToNetwork(NetworkId id) {
-  CoreNetwork *net = network(id);
-  if(!net) {
-    qWarning() << "Connect to unknown network requested! net:" << id << "user:" << user();
-    return;
-  }
-
-  NetworkConnection *conn = networkConnection(id);
-  if(!conn) {
-    conn = new NetworkConnection(net, this);
-    _connections[id] = conn;
-    attachNetworkConnection(conn);
-  }
-  conn->connectToIrc();
-}
-
-void CoreSession::attachNetworkConnection(NetworkConnection *conn) {
-  connect(conn, SIGNAL(connected(NetworkId)), this, SLOT(networkConnected(NetworkId)));
-  connect(conn, SIGNAL(quitRequested(NetworkId)), this, SLOT(networkDisconnected(NetworkId)));
-
-  // I guess we don't need these anymore, client-side can just connect the network's signals directly
-  //signalProxy()->attachSignal(conn, SIGNAL(connected(NetworkId)), SIGNAL(networkConnected(NetworkId)));
-  //signalProxy()->attachSignal(conn, SIGNAL(disconnected(NetworkId)), SIGNAL(networkDisconnected(NetworkId)));
-
-  connect(conn, SIGNAL(displayMsg(Message::Type, BufferInfo::Type, QString, QString, QString, Message::Flags)),
-         this, SLOT(recvMessageFromServer(Message::Type, BufferInfo::Type, QString, QString, QString, Message::Flags)));
-  connect(conn, SIGNAL(displayStatusMsg(QString)), this, SLOT(recvStatusMsgFromServer(QString)));
-
-  connect(conn, SIGNAL(nickChanged(const NetworkId &, const QString &, const QString &)),
-         this, SLOT(renameBuffer(const NetworkId &, const QString &, const QString &)));
-  connect(conn, SIGNAL(channelJoined(NetworkId, const QString &, const QString &)),
-          this, SLOT(channelJoined(NetworkId, const QString &, const QString &)));
-  connect(conn, SIGNAL(channelParted(NetworkId, const QString &)),
-          this, SLOT(channelParted(NetworkId, const QString &)));
-}
-
-void CoreSession::disconnectFromNetwork(NetworkId id) {
-  if(!_connections.contains(id))
-    return;
-
-  //_connections[id]->disconnectFromIrc();
-  _connections[id]->userInputHandler()->handleQuit(BufferInfo(), QString());
-}
-
-void CoreSession::networkStateRequested() {
-}
-
 void CoreSession::addClient(QIODevice *device) {
   if(!device) {
     qCritical() << "Invoking CoreSession::addClient with a QObject that is not a QIODevice!";
@@ -254,35 +193,6 @@ void CoreSession::removeClient(QIODevice *iodev) {
     quInfo() << qPrintable(tr("Client")) << qPrintable(socket->peerAddress().toString()) << qPrintable(tr("disconnected (UserId: %1).").arg(user().toInt()));
 }
 
-SignalProxy *CoreSession::signalProxy() const {
-  return _signalProxy;
-}
-
-// FIXME we need a sane way for creating buffers!
-void CoreSession::networkConnected(NetworkId networkid) {
-  Core::bufferInfo(user(), networkid, BufferInfo::StatusBuffer); // create status buffer
-  Core::setNetworkConnected(user(), networkid, true);
-}
-
-// called now only on /quit and requested disconnects, not on normal disconnects!
-void CoreSession::networkDisconnected(NetworkId networkid) {
-  // if the network has already been removed, we don't have a networkconnection left either, so we don't do anything
-  // make sure to not depend on the network still existing when calling this function!
-  if(_connections.contains(networkid)) {
-    Core::setNetworkConnected(user(), networkid, false);
-    _connections.take(networkid)->deleteLater();
-  }
-}
-
-void CoreSession::channelJoined(NetworkId id, const QString &channel, const QString &key) {
-  Core::setChannelPersistent(user(), id, channel, true);
-  Core::setPersistentChannelKey(user(), id, channel, key);
-}
-
-void CoreSession::channelParted(NetworkId id, const QString &channel) {
-  Core::setChannelPersistent(user(), id, channel, false);
-}
-
 QHash<QString, QString> CoreSession::persistentChannels(NetworkId id) const {
   return Core::persistentChannels(user(), id);
   return QHash<QString, QString>();
@@ -290,9 +200,9 @@ QHash<QString, QString> CoreSession::persistentChannels(NetworkId id) const {
 
 // FIXME switch to BufferId
 void CoreSession::msgFromClient(BufferInfo bufinfo, QString msg) {
-  NetworkConnection *conn = networkConnection(bufinfo.networkId());
-  if(conn) {
-    conn->userInput(bufinfo, msg);
+  CoreNetwork *net = network(bufinfo.networkId());
+  if(net) {
+    net->userInput(bufinfo, msg);
   } else {
     qWarning() << "Trying to send to unconnected network:" << msg;
   }
@@ -302,10 +212,10 @@ void CoreSession::msgFromClient(BufferInfo bufinfo, QString msg) {
 // So this is the perfect place for storing the backlog and log stuff.
 void CoreSession::recvMessageFromServer(Message::Type type, BufferInfo::Type bufferType,
                                         QString target, QString text, QString sender, Message::Flags flags) {
-  NetworkConnection *netCon = qobject_cast<NetworkConnection*>(this->sender());
-  Q_ASSERT(netCon);
+  CoreNetwork *net = qobject_cast<CoreNetwork*>(this->sender());
+  Q_ASSERT(net);
 
-  BufferInfo bufferInfo = Core::bufferInfo(user(), netCon->networkId(), bufferType, target);
+  BufferInfo bufferInfo = Core::bufferInfo(user(), net->networkId(), bufferType, target);
   Message msg(bufferInfo, type, text, sender, flags);
   msg.setMsgId(Core::storeMessage(msg));
   Q_ASSERT(msg.msgId() != 0);
@@ -313,9 +223,9 @@ void CoreSession::recvMessageFromServer(Message::Type type, BufferInfo::Type buf
 }
 
 void CoreSession::recvStatusMsgFromServer(QString msg) {
-  NetworkConnection *s = qobject_cast<NetworkConnection*>(sender());
-  Q_ASSERT(s);
-  emit displayStatusMsg(s->networkName(), msg);
+  CoreNetwork *net = qobject_cast<CoreNetwork*>(sender());
+  Q_ASSERT(net);
+  emit displayStatusMsg(net->networkName(), msg);
 }
 
 QList<BufferInfo> CoreSession::buffers() const {
@@ -423,8 +333,10 @@ void CoreSession::createNetwork(const NetworkInfo &info_) {
   id = info.networkId.toInt();
   if(!_networks.contains(id)) {
     CoreNetwork *net = new CoreNetwork(id, this);
-    connect(net, SIGNAL(connectRequested(NetworkId)), this, SLOT(connectToNetwork(NetworkId)));
-    connect(net, SIGNAL(disconnectRequested(NetworkId)), this, SLOT(disconnectFromNetwork(NetworkId)));
+    connect(net, SIGNAL(displayMsg(Message::Type, BufferInfo::Type, QString, QString, QString, Message::Flags)),
+           this, SLOT(recvMessageFromServer(Message::Type, BufferInfo::Type, QString, QString, QString, Message::Flags)));
+    connect(net, SIGNAL(displayStatusMsg(QString)), this, SLOT(recvStatusMsgFromServer(QString)));
+
     net->setNetworkInfo(info);
     net->setProxy(signalProxy());
     _networks[id] = net;
@@ -438,25 +350,19 @@ void CoreSession::createNetwork(const NetworkInfo &info_) {
 
 void CoreSession::removeNetwork(NetworkId id) {
   // Make sure the network is disconnected!
-  NetworkConnection *conn = _connections.value(id, 0);
-  if(conn) {
-    if(conn->connectionState() != Network::Disconnected) {
-      connect(conn, SIGNAL(disconnected(NetworkId)), this, SLOT(destroyNetwork(NetworkId)));
-      conn->disconnectFromIrc();
-    } else {
-      _connections.take(id)->deleteLater();  // TODO make this saner
-      destroyNetwork(id);
-    }
+  CoreNetwork *net = network(id);
+  if(!net)
+    return;
+
+  if(net->connectionState() != Network::Disconnected) {
+    connect(net, SIGNAL(disconnected(NetworkId)), this, SLOT(destroyNetwork(NetworkId)));
+    net->disconnectFromIrc();
   } else {
     destroyNetwork(id);
   }
 }
 
 void CoreSession::destroyNetwork(NetworkId id) {
-  if(_connections.contains(id)) {
-    // this can happen if the network was reconnecting while being removed
-    _connections.take(id)->deleteLater();
-  }
   QList<BufferId> removedBuffers = Core::requestBufferIdsForNetwork(user(), id);
   Network *net = _networks.take(id);
   if(net && Core::removeNetwork(user(), id)) {
@@ -496,6 +402,7 @@ void CoreSession::removeBufferRequested(BufferId bufferId) {
     emit bufferRemoved(bufferId);
 }
 
+// FIXME: use a coreBufferSyncer for this
 void CoreSession::renameBuffer(const NetworkId &networkId, const QString &newName, const QString &oldName) {
   BufferId bufferId = Core::renameBuffer(user(), networkId, newName, oldName);
   if(bufferId.isValid()) {
@@ -504,54 +411,46 @@ void CoreSession::renameBuffer(const NetworkId &networkId, const QString &newNam
 }
 
 void CoreSession::clientsConnected() {
-  QHash<NetworkId, NetworkConnection *>::iterator conIter = _connections.begin();
+  QHash<NetworkId, CoreNetwork *>::iterator netIter = _networks.begin();
   Identity *identity = 0;
-  NetworkConnection *con = 0;
-  Network *network = 0;
+  CoreNetwork *net = 0;
   IrcUser *me = 0;
   QString awayReason;
-  while(conIter != _connections.end()) {
-    con = *conIter;
-    conIter++;
+  while(netIter != _networks.end()) {
+    net = *netIter;
+    netIter++;
 
-    if(!con->isConnected())
+    if(!net->isConnected())
       continue;
-    identity = con->identity();
+    identity = net->identityPtr();
     if(!identity)
       continue;
-    network = con->network();
-    if(!network)
-      continue;
-    me = network->me();
+    me = net->me();
     if(!me)
       continue;
 
     if(identity->detachAwayEnabled() && me->isAway()) {
-      con->userInputHandler()->handleAway(BufferInfo(), QString());
+      net->userInputHandler()->handleAway(BufferInfo(), QString());
     }
   }
 }
 
 void CoreSession::clientsDisconnected() {
-  QHash<NetworkId, NetworkConnection *>::iterator conIter = _connections.begin();
+  QHash<NetworkId, CoreNetwork *>::iterator netIter = _networks.begin();
   Identity *identity = 0;
-  NetworkConnection *con = 0;
-  Network *network = 0;
+  CoreNetwork *net = 0;
   IrcUser *me = 0;
   QString awayReason;
-  while(conIter != _connections.end()) {
-    con = *conIter;
-    conIter++;
+  while(netIter != _networks.end()) {
+    net = *netIter;
+    netIter++;
 
-    if(!con->isConnected())
+    if(!net->isConnected())
       continue;
-    identity = con->identity();
+    identity = net->identityPtr();
     if(!identity)
       continue;
-    network = con->network();
-    if(!network)
-      continue;
-    me = network->me();
+    me = net->me();
     if(!me)
       continue;
 
@@ -560,8 +459,8 @@ void CoreSession::clientsDisconnected() {
        awayReason = identity->detachAwayReason();
       else
        awayReason = identity->awayReason();
-      network->setAutoAwayActive(true);
-      con->userInputHandler()->handleAway(BufferInfo(), awayReason);
+      net->setAutoAwayActive(true);
+      net->userInputHandler()->handleAway(BufferInfo(), awayReason);
     }
   }
 }
index 91ad27e..8fa8725 100644 (file)
@@ -55,28 +55,23 @@ public:
 
   QVariant sessionState();
 
-  SignalProxy *signalProxy() const;
+  inline SignalProxy *signalProxy() const { return _signalProxy; }
 
   const AliasManager &aliasManager() const { return _aliasManager; }
   AliasManager &aliasManager() { return _aliasManager; }
 
   inline CoreIrcListHelper *ircListHelper() const { return _ircListHelper; }
 
-  void attachNetworkConnection(NetworkConnection *conn);
+//   void attachNetworkConnection(NetworkConnection *conn);
 
   //! Return necessary data for restoring the session after restarting the core
   void saveSessionState() const;
   void restoreSessionState();
 
 public slots:
-  void networkStateRequested();
-
   void addClient(QIODevice *device);
   void addClient(SignalProxy *proxy);
 
-  void connectToNetwork(NetworkId);
-  void disconnectFromNetwork(NetworkId id);
-
   void msgFromClient(BufferInfo, QString message);
 
   //! Create an identity and propagate the changes to the clients.
@@ -113,8 +108,6 @@ public slots:
    */
   void renameBuffer(const NetworkId &networkId, const QString &newName, const QString &oldName);
 
-  void channelJoined(NetworkId id, const QString &channel, const QString &key = QString());
-  void channelParted(NetworkId, const QString &channel);
   QHash<QString, QString> persistentChannels(NetworkId) const;
 
 signals:
@@ -125,11 +118,6 @@ signals:
   void displayMsg(Message message);
   void displayStatusMsg(QString, QString);
 
-  //void connectToIrc(QString net);
-  //void disconnectFromIrc(QString net);
-
-  void bufferInfoUpdated(BufferInfo);
-
   void scriptResult(QString result);
 
   //! Identity has been created.
@@ -154,20 +142,11 @@ private slots:
 
   void recvStatusMsgFromServer(QString msg);
   void recvMessageFromServer(Message::Type, BufferInfo::Type, QString target, QString text, QString sender = "", Message::Flags flags = Message::None);
-  void networkConnected(NetworkId networkid);
-  void networkDisconnected(NetworkId networkid);
 
   void destroyNetwork(NetworkId);
 
   void identityUpdated(const QVariantMap &);
 
-  //! Called when storage updated a BufferInfo.
-  /** This emits bufferInfoUpdated() via SignalProxy, iff it's one of our buffers.
-   *  \param user       The buffer's owner (not necessarily us)
-   *  \param bufferInfo The updated BufferInfo
-   */
-  void updateBufferInfo(UserId user, const BufferInfo &bufferInfo);
-
   void storeBufferLastSeenMsg(BufferId buffer, const MsgId &msgId);
 
   void scriptRequest(QString script);
@@ -183,7 +162,7 @@ private:
 
   SignalProxy *_signalProxy;
   CoreAliasManager _aliasManager;
-  QHash<NetworkId, NetworkConnection *> _connections;
+  // QHash<NetworkId, NetworkConnection *> _connections;
   QHash<NetworkId, CoreNetwork *> _networks;
   //  QHash<NetworkId, CoreNetwork *> _networksToRemove;
   QHash<IdentityId, Identity *> _identities;
index 1ebbfaf..10dfd9a 100644 (file)
@@ -24,7 +24,7 @@
 #include "quassel.h"
 #include "util.h"
 
-CtcpHandler::CtcpHandler(NetworkConnection *parent)
+CtcpHandler::CtcpHandler(CoreNetwork *parent)
   : BasicHandler(parent),
     XDELIM("\001")
 {
index cac2f56..d15f6e6 100644 (file)
@@ -30,7 +30,7 @@ class CtcpHandler : public BasicHandler {
   Q_OBJECT
 
 public:
-  CtcpHandler(NetworkConnection *parent = 0);
+  CtcpHandler(CoreNetwork *parent = 0);
 
   enum CtcpType {CtcpQuery, CtcpReply};
 
index 4f5206a..06f968c 100644 (file)
@@ -23,8 +23,6 @@
 
 #include "coresession.h"
 #include "coreirclisthelper.h"
-#include "networkconnection.h"
-#include "network.h"
 #include "identity.h"
 #include "ctcphandler.h"
 
@@ -34,7 +32,7 @@
 
 #include <QDebug>
 
-IrcServerHandler::IrcServerHandler(NetworkConnection *parent)
+IrcServerHandler::IrcServerHandler(CoreNetwork *parent)
   : BasicHandler(parent),
     _whois(false)
 {
@@ -153,8 +151,8 @@ void IrcServerHandler::defaultHandler(QString cmd, const QString &prefix, const
          // many nets define their own WHOIS fields. we fetch those not in need of special attention here:
          emit displayMsg(Message::Server, BufferInfo::StatusBuffer, "", "[Whois] " + params.join(" "), prefix);
        } else {
-         if(networkConnection()->coreSession()->ircListHelper()->requestInProgress(network()->networkId()))
-           networkConnection()->coreSession()->ircListHelper()->reportError(params.join(" "));
+         if(coreSession()->ircListHelper()->requestInProgress(network()->networkId()))
+           coreSession()->ircListHelper()->reportError(params.join(" "));
          else
            emit displayMsg(Message::Error, BufferInfo::StatusBuffer, "", cmd + " " + params.join(" "), prefix);
        }
@@ -179,7 +177,7 @@ void IrcServerHandler::handleJoin(const QString &prefix, const QList<QByteArray>
   //qDebug() << "IrcServerHandler::handleJoin()" << prefix << params;
   ircuser->joinChannel(channel);
   if(network()->isMe(ircuser)) {
-    networkConnection()->setChannelJoined(channel);
+    network()->setChannelJoined(channel);
     putCmd("MODE", params[0]); // we want to know the modes of the channel we just joined, so we ask politely
   }
 }
@@ -203,7 +201,7 @@ void IrcServerHandler::handleKick(const QString &prefix, const QList<QByteArray>
     msg = victim->nick();
 
   emit displayMsg(Message::Kick, BufferInfo::ChannelBuffer, channel, msg, prefix);
-  //if(network()->isMe(victim)) networkConnection()->setKickedFromChannel(channel);
+  //if(network()->isMe(victim)) network()->setKickedFromChannel(channel);
 }
 
 void IrcServerHandler::handleMode(const QString &prefix, const QList<QByteArray> &params) {
@@ -313,7 +311,7 @@ void IrcServerHandler::handleNick(const QString &prefix, const QList<QByteArray>
     ? newnick
     : prefix;
 
-  emit nickChanged(newnick, oldnick);
+  coreSession()->renameBuffer(network()->networkId(), newnick, oldnick);
   foreach(QString channel, ircuser->channels())
     emit displayMsg(Message::Nick, BufferInfo::ChannelBuffer, channel, newnick, sender);
   
@@ -352,7 +350,7 @@ void IrcServerHandler::handleNotice(const QString &prefix, const QList<QByteArra
       target = nickFromMask(prefix);
   }
 
-  networkConnection()->ctcpHandler()->parse(Message::Notice, prefix, target, params[1]);
+  network()->ctcpHandler()->parse(Message::Notice, prefix, target, params[1]);
 }
 
 void IrcServerHandler::handlePart(const QString &prefix, const QList<QByteArray> &params) {
@@ -373,7 +371,7 @@ void IrcServerHandler::handlePart(const QString &prefix, const QList<QByteArray>
     msg = userDecode(ircuser->nick(), params[1]);
 
   emit displayMsg(Message::Part, BufferInfo::ChannelBuffer, channel, msg, prefix);
-  if(network()->isMe(ircuser)) networkConnection()->setChannelParted(channel);
+  if(network()->isMe(ircuser)) network()->setChannelParted(channel);
 }
 
 void IrcServerHandler::handlePing(const QString &prefix, const QList<QByteArray> &params) {
@@ -424,7 +422,7 @@ void IrcServerHandler::handlePrivmsg(const QString &prefix, const QList<QByteArr
 
   // it's possible to pack multiple privmsgs into one param using ctcp
   // - > we let the ctcpHandler do the work
-  networkConnection()->ctcpHandler()->parse(Message::Plain, prefix, target, msg);
+  network()->ctcpHandler()->parse(Message::Plain, prefix, target, msg);
 }
 
 void IrcServerHandler::handleQuit(const QString &prefix, const QList<QByteArray> &params) {
@@ -706,7 +704,7 @@ void IrcServerHandler::handle315(const QString &prefix, const QList<QByteArray>
     return;
 
   QStringList p = serverDecode(params);
-  if(networkConnection()->setAutoWhoDone(p[0])) {
+  if(network()->setAutoWhoDone(p[0])) {
     return; // stay silent
   }
   p.takeLast(); // should be "End of WHO list"
@@ -798,7 +796,7 @@ void IrcServerHandler::handle322(const QString &prefix, const QList<QByteArray>
   default:
     break;
   }
-  if(!networkConnection()->coreSession()->ircListHelper()->addChannel(network()->networkId(), channelName, userCount, topic))
+  if(!coreSession()->ircListHelper()->addChannel(network()->networkId(), channelName, userCount, topic))
     emit displayMsg(Message::Server, BufferInfo::StatusBuffer, "", tr("Channel %1 has %2 users. Topic is: %3").arg(channelName).arg(userCount).arg(topic));
 }
 
@@ -807,7 +805,7 @@ void IrcServerHandler::handle323(const QString &prefix, const QList<QByteArray>
   Q_UNUSED(prefix)
   Q_UNUSED(params)
 
-  if(!networkConnection()->coreSession()->ircListHelper()->endOfChannelList(network()->networkId()))
+  if(!coreSession()->ircListHelper()->endOfChannelList(network()->networkId()))
     emit displayMsg(Message::Server, BufferInfo::StatusBuffer, "", tr("End of channel list"));
 }
        
@@ -886,7 +884,7 @@ void IrcServerHandler::handle352(const QString &prefix, const QList<QByteArray>
     ircuser->setRealName(serverDecode(params.last()).section(" ", 1));
   }
 
-  if(!networkConnection()->isAutoWhoInProgress(channel)) {
+  if(!network()->isAutoWhoInProgress(channel)) {
     emit displayMsg(Message::Server, BufferInfo::StatusBuffer, "", tr("[Who] %1").arg(serverDecode(params).join(" ")));
   }
 }
@@ -976,7 +974,7 @@ void IrcServerHandler::handle433(const QString &prefix, const QList<QByteArray>
 /* */
 
 void IrcServerHandler::tryNextNick(const QString &errnick) {
-  QStringList desiredNicks = networkConnection()->coreSession()->identity(network()->identity())->nicks();
+  QStringList desiredNicks = coreSession()->identity(network()->identity())->nicks();
   int nextNick = desiredNicks.indexOf(errnick) + 1;
   if(desiredNicks.size() > nextNick) {
     putCmd("NICK", serverEncode(desiredNicks[nextNick]));
index 9624928..406b0a3 100644 (file)
@@ -18,8 +18,8 @@
  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
  ***************************************************************************/
 
-#ifndef _IRCSERVERHANDLER_H_
-#define _IRCSERVERHANDLER_H_
+#ifndef IRCSERVERHANDLER_H
+#define IRCSERVERHANDLER_H
 
 #include "basichandler.h"
 
@@ -27,7 +27,7 @@ class IrcServerHandler : public BasicHandler {
   Q_OBJECT
 
 public:
-  IrcServerHandler(NetworkConnection *parent);
+  IrcServerHandler(CoreNetwork *parent);
   ~IrcServerHandler();
 
   void handleServerMsg(QByteArray rawMsg);
@@ -80,9 +80,6 @@ public slots:
 
   void defaultHandler(QString cmd, const QString &prefix, const QList<QByteArray> &params);
 
-signals:
-  void nickChanged(const QString &newNick, const QString &oldNick); // this signal is inteded to rename query buffers in the storage backend
-  
 private:
   void tryNextNick(const QString &errnick);
   bool checkParamCount(const QString &methodName, const QList<QByteArray> &params, int minParams);
diff --git a/src/core/networkconnection.cpp b/src/core/networkconnection.cpp
deleted file mode 100644 (file)
index d177d4c..0000000
+++ /dev/null
@@ -1,593 +0,0 @@
-/***************************************************************************
- *   Copyright (C) 2005-08 by the Quassel Project                          *
- *   devel@quassel-irc.org                                                 *
- *                                                                         *
- *   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 2 of the License, or     *
- *   (at your option) version 3.                                           *
- *                                                                         *
- *   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, write to the                         *
- *   Free Software Foundation, Inc.,                                       *
- *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
- ***************************************************************************/
-#include "networkconnection.h"
-
-#include <QMetaObject>
-#include <QMetaMethod>
-#include <QDateTime>
-
-#include "util.h"
-#include "core.h"
-#include "coresession.h"
-
-#include "ircchannel.h"
-#include "ircuser.h"
-#include "identity.h"
-
-#include "ircserverhandler.h"
-#include "userinputhandler.h"
-#include "ctcphandler.h"
-
-#include "logger.h"
-
-NetworkConnection::NetworkConnection(Network *network, CoreSession *session)
-  : QObject(network),
-    _connectionState(Network::Disconnected),
-    _network(network),
-    _coreSession(session),
-    _ircServerHandler(new IrcServerHandler(this)),
-    _userInputHandler(new UserInputHandler(this)),
-    _ctcpHandler(new CtcpHandler(this)),
-    _autoReconnectCount(0),
-    _quitRequested(false),
-
-    _previousConnectionAttemptFailed(false),
-    _lastUsedServerlistIndex(0),
-
-    // TODO make autowho configurable (possibly per-network)
-    _autoWhoEnabled(true),
-    _autoWhoInterval(90),
-    _autoWhoNickLimit(0), // unlimited
-    _autoWhoDelay(3),
-
-    // TokenBucket to avaid sending too much at once
-    _messagesPerSecond(1),
-    _burstSize(5),
-    _tokenBucket(5) // init with a full bucket
-{
-  _autoReconnectTimer.setSingleShot(true);
-  _socketCloseTimer.setSingleShot(true);
-  connect(&_socketCloseTimer, SIGNAL(timeout()), this, SLOT(socketCloseTimeout()));
-
-  _pingTimer.setInterval(60000);
-  connect(&_pingTimer, SIGNAL(timeout()), this, SLOT(sendPing()));
-
-  _autoWhoTimer.setInterval(_autoWhoDelay * 1000);
-  _autoWhoCycleTimer.setInterval(_autoWhoInterval * 1000);
-  
-  _tokenBucketTimer.start(_messagesPerSecond * 1000);
-
-  QHash<QString, QString> channels = coreSession()->persistentChannels(networkId());
-  foreach(QString chan, channels.keys()) {
-    _channelKeys[chan.toLower()] = channels[chan];
-  }
-
-  connect(&_autoReconnectTimer, SIGNAL(timeout()), this, SLOT(doAutoReconnect()));
-  connect(&_autoWhoTimer, SIGNAL(timeout()), this, SLOT(sendAutoWho()));
-  connect(&_autoWhoCycleTimer, SIGNAL(timeout()), this, SLOT(startAutoWhoCycle()));
-  connect(&_tokenBucketTimer, SIGNAL(timeout()), this, SLOT(fillBucketAndProcessQueue()));
-
-  connect(network, SIGNAL(currentServerSet(const QString &)), this, SLOT(networkInitialized(const QString &)));
-  connect(network, SIGNAL(useAutoReconnectSet(bool)), this, SLOT(autoReconnectSettingsChanged()));
-  connect(network, SIGNAL(autoReconnectIntervalSet(quint32)), this, SLOT(autoReconnectSettingsChanged()));
-  connect(network, SIGNAL(autoReconnectRetriesSet(quint16)), this, SLOT(autoReconnectSettingsChanged()));
-
-#ifdef HAVE_SSL
-  connect(&socket, SIGNAL(encrypted()), this, SLOT(socketEncrypted()));
-  connect(&socket, SIGNAL(sslErrors(const QList<QSslError> &)), this, SLOT(sslErrors(const QList<QSslError> &)));
-#endif
-  connect(&socket, SIGNAL(connected()), this, SLOT(socketConnected()));
-
-  connect(&socket, SIGNAL(disconnected()), this, SLOT(socketDisconnected()));
-  connect(&socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(socketError(QAbstractSocket::SocketError)));
-  connect(&socket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(socketStateChanged(QAbstractSocket::SocketState)));
-  connect(&socket, SIGNAL(readyRead()), this, SLOT(socketHasData()));
-
-  connect(_ircServerHandler, SIGNAL(nickChanged(const QString &, const QString &)),
-         this, SLOT(nickChanged(const QString &, const QString &)));
-
-  network->proxy()->attachSignal(this, SIGNAL(sslErrors(const QVariant &)));
-}
-
-NetworkConnection::~NetworkConnection() {
-  if(connectionState() != Network::Disconnected && connectionState() != Network::Reconnecting)
-    disconnectFromIrc(false); // clean up, but this does not count as requested disconnect!
-  disconnect(&socket, 0, this, 0); // this keeps the socket from triggering events during clean up
-  delete _ircServerHandler;
-  delete _userInputHandler;
-  delete _ctcpHandler;
-}
-
-void NetworkConnection::setConnectionState(Network::ConnectionState state) {
-  _connectionState = state;
-  network()->setConnectionState(state);
-  emit connectionStateChanged(state);
-}
-
-QString NetworkConnection::serverDecode(const QByteArray &string) const {
-  return network()->decodeServerString(string);
-}
-
-QString NetworkConnection::channelDecode(const QString &bufferName, const QByteArray &string) const {
-  if(!bufferName.isEmpty()) {
-    IrcChannel *channel = network()->ircChannel(bufferName);
-    if(channel) return channel->decodeString(string);
-  }
-  return network()->decodeString(string);
-}
-
-QString NetworkConnection::userDecode(const QString &userNick, const QByteArray &string) const {
-  IrcUser *user = network()->ircUser(userNick);
-  if(user) return user->decodeString(string);
-  return network()->decodeString(string);
-}
-
-QByteArray NetworkConnection::serverEncode(const QString &string) const {
-  return network()->encodeServerString(string);
-}
-
-QByteArray NetworkConnection::channelEncode(const QString &bufferName, const QString &string) const {
-  if(!bufferName.isEmpty()) {
-    IrcChannel *channel = network()->ircChannel(bufferName);
-    if(channel) return channel->encodeString(string);
-  }
-  return network()->encodeString(string);
-}
-
-QByteArray NetworkConnection::userEncode(const QString &userNick, const QString &string) const {
-  IrcUser *user = network()->ircUser(userNick);
-  if(user) return user->encodeString(string);
-  return network()->encodeString(string);
-}
-
-void NetworkConnection::autoReconnectSettingsChanged() {
-  if(!network()->useAutoReconnect()) {
-    _autoReconnectTimer.stop();
-    _autoReconnectCount = 0;
-  } else {
-    _autoReconnectTimer.setInterval(network()->autoReconnectInterval() * 1000);
-    if(_autoReconnectCount != 0) {
-      if(network()->unlimitedReconnectRetries()) _autoReconnectCount = -1;
-      else _autoReconnectCount = network()->autoReconnectRetries();
-    }
-  }
-}
-
-void NetworkConnection::connectToIrc(bool reconnecting) {
-  if(!reconnecting && network()->useAutoReconnect() && _autoReconnectCount == 0) {
-    _autoReconnectTimer.setInterval(network()->autoReconnectInterval() * 1000);
-    if(network()->unlimitedReconnectRetries()) _autoReconnectCount = -1;
-    else _autoReconnectCount = network()->autoReconnectRetries();
-  }
-  QVariantList serverList = network()->serverList();
-  Identity *identity = coreSession()->identity(network()->identity());
-  if(!serverList.count()) {
-    qWarning() << "Server list empty, ignoring connect request!";
-    return;
-  }
-  if(!identity) {
-    qWarning() << "Invalid identity configures, ignoring connect request!";
-    return;
-  }
-  // use a random server?
-  if(network()->useRandomServer()) {
-    _lastUsedServerlistIndex = qrand() % serverList.size();
-  } else if(_previousConnectionAttemptFailed) {
-    // cycle to next server if previous connection attempt failed
-    displayMsg(Message::Server, BufferInfo::StatusBuffer, "", tr("Connection failed. Cycling to next Server"));
-    if(++_lastUsedServerlistIndex == serverList.size()) {
-      _lastUsedServerlistIndex = 0;
-    }
-  }
-  _previousConnectionAttemptFailed = false;
-
-  QString host = serverList[_lastUsedServerlistIndex].toMap()["Host"].toString();
-  quint16 port = serverList[_lastUsedServerlistIndex].toMap()["Port"].toUInt();
-  displayStatusMsg(tr("Connecting to %1:%2...").arg(host).arg(port));
-  displayMsg(Message::Server, BufferInfo::StatusBuffer, "", tr("Connecting to %1:%2...").arg(host).arg(port));
-  socket.connectToHost(host, port);
-}
-
-void NetworkConnection::networkInitialized(const QString &currentServer) {
-  if(currentServer.isEmpty()) return;
-
-  if(network()->useAutoReconnect() && !network()->unlimitedReconnectRetries()) {
-    _autoReconnectCount = network()->autoReconnectRetries(); // reset counter
-  }
-
-  sendPerform();
-
-  // now we are initialized
-  setConnectionState(Network::Initialized);
-  network()->setConnected(true);
-  emit connected(networkId());
-
-  _pingTimer.start();
-
-  if(_autoWhoEnabled) {
-    _autoWhoCycleTimer.start();
-    _autoWhoTimer.start();
-    startAutoWhoCycle();  // FIXME wait for autojoin to be completed
-  }
-}
-
-void NetworkConnection::sendPerform() {
-  BufferInfo statusBuf = Core::bufferInfo(coreSession()->user(), network()->networkId(), BufferInfo::StatusBuffer);
-  // do auto identify
-  if(network()->useAutoIdentify() && !network()->autoIdentifyService().isEmpty() && !network()->autoIdentifyPassword().isEmpty()) {
-    userInputHandler()->handleMsg(statusBuf, QString("%1 IDENTIFY %2").arg(network()->autoIdentifyService(), network()->autoIdentifyPassword()));
-  }
-  // send perform list
-  foreach(QString line, network()->perform()) {
-    if(!line.isEmpty()) userInput(statusBuf, line);
-  }
-
-  // rejoin channels we've been in
-  QStringList channels, keys;
-  foreach(QString chan, persistentChannels()) {
-    QString key = channelKey(chan);
-    if(!key.isEmpty()) {
-      channels.prepend(chan); keys.prepend(key);
-    } else {
-      channels.append(chan);
-    }
-  }
-  QString joinString = QString("%1 %2").arg(channels.join(",")).arg(keys.join(",")).trimmed();
-  if(!joinString.isEmpty()) userInputHandler()->handleJoin(statusBuf, joinString);
-}
-
-void NetworkConnection::disconnectFromIrc(bool requested, const QString &reason) {
-  _quitRequested = requested; // see socketDisconnected();
-  _autoReconnectTimer.stop();
-  _autoReconnectCount = 0; // prohibiting auto reconnect
-  displayMsg(Message::Server, BufferInfo::StatusBuffer, "", tr("Disconnecting."));
-  if(socket.state() == QAbstractSocket::UnconnectedState) {
-    socketDisconnected();
-  } else if(socket.state() < QAbstractSocket::ConnectedState || !requested) {
-    // we might be in a state waiting for a timeout...
-    // or (!requested) this is a core shutdown...
-    // in both cases we don't really care... set a disconnected state
-    socket.close();
-    socketDisconnected();
-  } else {
-    // quit gracefully if it's user requested quit
-    userInputHandler()->issueQuit(reason);
-    // the irc server has 10 seconds to close the socket
-    _socketCloseTimer.start(10000);
-  }
-}
-
-void NetworkConnection::socketHasData() {
-  while(socket.canReadLine()) {
-    QByteArray s = socket.readLine().trimmed();
-    ircServerHandler()->handleServerMsg(s);
-  }
-}
-
-void NetworkConnection::socketError(QAbstractSocket::SocketError) {
-  _previousConnectionAttemptFailed = true;
-  qWarning() << qPrintable(tr("Could not connect to %1 (%2)").arg(network()->networkName(), socket.errorString()));
-  emit connectionError(socket.errorString());
-  emit displayMsg(Message::Error, BufferInfo::StatusBuffer, "", tr("Connection failure: %1").arg(socket.errorString()));
-  network()->emitConnectionError(socket.errorString());
-  if(socket.state() < QAbstractSocket::ConnectedState) {
-    socketDisconnected();
-  }
-  // mark last connection attempt as failed
-  
-  //qDebug() << "exiting...";
-  //exit(1);
-}
-
-#ifdef HAVE_SSL
-
-void NetworkConnection::sslErrors(const QList<QSslError> &sslErrors) {
-  Q_UNUSED(sslErrors)
-  socket.ignoreSslErrors();
-  /* TODO errorhandling
-  QVariantMap errmsg;
-  QVariantList errnums;
-  foreach(QSslError err, errors) errnums << err.error();
-  errmsg["SslErrors"] = errnums;
-  errmsg["SslCert"] = socket.peerCertificate().toPem();
-  errmsg["PeerAddress"] = socket.peerAddress().toString();
-  errmsg["PeerPort"] = socket.peerPort();
-  errmsg["PeerName"] = socket.peerName();
-  emit sslErrors(errmsg);
-  disconnectFromIrc();
-  */
-}
-
-void NetworkConnection::socketEncrypted() {
-  //qDebug() << "encrypted!";
-  socketInitialized();
-}
-
-#endif  // HAVE_SSL
-
-void NetworkConnection::socketConnected() {
-#ifndef HAVE_SSL
-  socketInitialized();
-  return;
-#else
-  if(!network()->serverList()[_lastUsedServerlistIndex].toMap()["UseSSL"].toBool()) {
-    socketInitialized();
-    return;
-  }
-  //qDebug() << "starting handshake";
-  socket.startClientEncryption();
-#endif
-}
-
-void NetworkConnection::socketInitialized() {
-  //emit connected(networkId());  initialize first!
-  Identity *identity = coreSession()->identity(network()->identity());
-  if(!identity) {
-    qCritical() << "Identity invalid!";
-    disconnectFromIrc();
-    return;
-  }
-  QString passwd = network()->serverList()[_lastUsedServerlistIndex].toMap()["Password"].toString();
-  if(!passwd.isEmpty()) {
-    putRawLine(serverEncode(QString("PASS %1").arg(passwd)));
-  }
-  putRawLine(serverEncode(QString("NICK :%1").arg(identity->nicks()[0])));  // FIXME: try more nicks if error occurs
-  putRawLine(serverEncode(QString("USER %1 8 * :%2").arg(identity->ident(), identity->realName())));
-}
-
-void NetworkConnection::socketStateChanged(QAbstractSocket::SocketState socketState) {
-  Network::ConnectionState state;
-  switch(socketState) {
-    case QAbstractSocket::UnconnectedState:
-      state = Network::Disconnected;
-      break;
-    case QAbstractSocket::HostLookupState:
-    case QAbstractSocket::ConnectingState:
-      state = Network::Connecting;
-      break;
-    case QAbstractSocket::ConnectedState:
-      state = Network::Initializing;
-      break;
-    case QAbstractSocket::ClosingState:
-      state = Network::Disconnecting;
-      break;
-    default:
-      state = Network::Disconnected;
-  }
-  setConnectionState(state);
-}
-
-void NetworkConnection::socketCloseTimeout() {
-  socket.disconnectFromHost();
-}
-
-void NetworkConnection::socketDisconnected() {
-  _pingTimer.stop();
-  _autoWhoCycleTimer.stop();
-  _autoWhoTimer.stop();
-  _autoWhoQueue.clear();
-  _autoWhoInProgress.clear();
-
-  _socketCloseTimer.stop();
-
-  IrcUser *me = network()->me();
-  if(me) {
-    foreach(QString channel, me->channels())
-      emit displayMsg(Message::Quit, BufferInfo::ChannelBuffer, channel, "", me->hostmask());
-  }
-
-  network()->setConnected(false);
-  emit disconnected(networkId());
-  if(_quitRequested) {
-    setConnectionState(Network::Disconnected);
-    emit quitRequested(networkId());
-  } else if(_autoReconnectCount != 0) {
-    setConnectionState(Network::Reconnecting);
-    if(_autoReconnectCount == network()->autoReconnectRetries())
-      doAutoReconnect(); // first try is immediate
-    else
-      _autoReconnectTimer.start();
-  }
-}
-
-void NetworkConnection::doAutoReconnect() {
-  if(connectionState() != Network::Disconnected && connectionState() != Network::Reconnecting) {
-    qWarning() << "NetworkConnection::doAutoReconnect(): Cannot reconnect while not being disconnected!";
-    return;
-  }
-  if(_autoReconnectCount > 0) _autoReconnectCount--;
-  connectToIrc(true);
-}
-
-// FIXME switch to BufferId
-void NetworkConnection::userInput(BufferInfo buf, QString msg) {
-  userInputHandler()->handleUserInput(buf, msg);
-}
-
-void NetworkConnection::putRawLine(QByteArray s) {
-  if(_tokenBucket > 0) {
-    // qDebug() << "putRawLine: " << s;
-    writeToSocket(s);
-  } else {
-    _msgQueue.append(s);
-  }
-}
-
-void NetworkConnection::writeToSocket(QByteArray s) {
-  s += "\r\n";
-  // qDebug() << "writeToSocket: " << s.size();
-  socket.write(s);
-  _tokenBucket--;
-}
-
-void NetworkConnection::fillBucketAndProcessQueue() {
-  if(_tokenBucket < _burstSize) {
-    _tokenBucket++;
-  }
-
-  while(_msgQueue.size() > 0 && _tokenBucket > 0) {
-    writeToSocket(_msgQueue.takeFirst());
-  }
-}
-
-// returns 0 if the message will not be chopped by the irc server or number of chopped bytes if message is too long
-int NetworkConnection::lastParamOverrun(const QString &cmd, const QList<QByteArray> &params) {
-  //the server will pass our message that trunkated to 512 bytes including CRLF with the following format:
-  // ":prefix COMMAND param0 param1 :lastparam"
-  // where prefix = "nickname!user@host"
-  // that means that the last message can be as long as:
-  // 512 - nicklen - userlen - hostlen - commandlen - sum(param[0]..param[n-1])) - 2 (for CRLF) - 4 (":!@" + 1space between prefix and command) - max(paramcount - 1, 0) (space for simple params) - 2 (space and colon for last param)
-  IrcUser *me = network()->me();
-  int maxLen = 480 - cmd.toAscii().count(); // educated guess in case we don't know us (yet?)
-
-  if(me)
-    maxLen = 512 - serverEncode(me->nick()).count() - serverEncode(me->user()).count() - serverEncode(me->host()).count() - cmd.toAscii().count() - 6;
-
-  if(!params.isEmpty()) {
-    for(int i = 0; i < params.count() - 1; i++) {
-      maxLen -= (params[i].count() + 1);
-    }
-    maxLen -= 2; // " :" last param separator;
-    
-    if(params.last().count() > maxLen) {
-      return params.last().count() - maxLen;
-    } else {
-      return 0;
-    }
-  } else {
-    return 0;
-  }
-}
-
-void NetworkConnection::putCmd(const QString &cmd, const QList<QByteArray> &params, const QByteArray &prefix) {
-  QByteArray msg;
-  if(cmd == "PRIVMSG" && params.count() > 1) {
-    int overrun = lastParamOverrun(cmd, params);
-    if(overrun) {
-      QList<QByteArray> paramCopy1 = params;
-      paramCopy1.removeLast();
-      QList<QByteArray> paramCopy2 = paramCopy1;
-
-      QByteArray lastPart = params.last();
-      QByteArray splitter(" .,-");
-      int maxSplitPos = params.last().count() - overrun;
-      int splitPos = -1;
-      for(int i = 0; i < splitter.size(); i++) {
-       splitPos = qMax(splitPos, lastPart.lastIndexOf(splitter[i], maxSplitPos));
-      }
-      if(splitPos <= 0) {
-       splitPos = maxSplitPos;
-      }
-      
-      paramCopy1 << lastPart.left(splitPos);
-      paramCopy2 << lastPart.mid(splitPos);
-      putCmd(cmd, paramCopy1, prefix);
-      putCmd(cmd, paramCopy2, prefix);
-      return;
-    }
-  }
-     
-  if(!prefix.isEmpty())
-    msg += ":" + prefix + " ";
-  msg += cmd.toUpper().toAscii();
-
-  for(int i = 0; i < params.size() - 1; i++) {
-    msg += " " + params[i];
-  }
-  if(!params.isEmpty())
-    msg += " :" + params.last();
-
-  putRawLine(msg);
-}
-
-void NetworkConnection::sendPing() {
-  userInputHandler()->handlePing(BufferInfo(), QString());
-}
-
-void NetworkConnection::sendAutoWho() {
-  while(!_autoWhoQueue.isEmpty()) {
-    QString chan = _autoWhoQueue.takeFirst();
-    IrcChannel *ircchan = network()->ircChannel(chan);
-    if(!ircchan) continue;
-    if(_autoWhoNickLimit > 0 && ircchan->ircUsers().count() > _autoWhoNickLimit) continue;
-    _autoWhoInProgress[chan]++;
-    putRawLine("WHO " + serverEncode(chan));
-    if(_autoWhoQueue.isEmpty() && _autoWhoEnabled && !_autoWhoCycleTimer.isActive()) {
-      // Timer was stopped, means a new cycle is due immediately
-      _autoWhoCycleTimer.start();
-      startAutoWhoCycle();
-    }
-    break;
-  }
-}
-
-void NetworkConnection::startAutoWhoCycle() {
-  if(!_autoWhoQueue.isEmpty()) {
-    _autoWhoCycleTimer.stop();
-    return;
-  }
-  _autoWhoQueue = network()->channels();
-}
-
-bool NetworkConnection::setAutoWhoDone(const QString &channel) {
-  if(_autoWhoInProgress.value(channel.toLower(), 0) <= 0) return false;
-  _autoWhoInProgress[channel.toLower()]--;
-  return true;
-}
-
-void NetworkConnection::setChannelJoined(const QString &channel) {
-  emit channelJoined(networkId(), channel, _channelKeys[channel.toLower()]);
-  _autoWhoQueue.prepend(channel.toLower()); // prepend so this new chan is the first to be checked
-}
-
-void NetworkConnection::setChannelParted(const QString &channel) {
-  removeChannelKey(channel);
-  _autoWhoQueue.removeAll(channel.toLower());
-  _autoWhoInProgress.remove(channel.toLower());
-  emit channelParted(networkId(), channel);
-}
-
-void NetworkConnection::addChannelKey(const QString &channel, const QString &key) {
-  if(key.isEmpty()) {
-    removeChannelKey(channel);
-  } else {
-    _channelKeys[channel.toLower()] = key;
-  }
-}
-
-void NetworkConnection::removeChannelKey(const QString &channel) {
-  _channelKeys.remove(channel.toLower());
-}
-
-void NetworkConnection::nickChanged(const QString &newNick, const QString &oldNick) {
-  emit nickChanged(networkId(), newNick, oldNick);
-}
-
-/* Exception classes for message handling */
-NetworkConnection::ParseError::ParseError(QString cmd, QString prefix, QStringList params) {
-  Q_UNUSED(prefix);
-  _msg = QString("Command Parse Error: ") + cmd + params.join(" ");
-}
-
-NetworkConnection::UnknownCmdError::UnknownCmdError(QString cmd, QString prefix, QStringList params) {
-  Q_UNUSED(prefix);
-  _msg = QString("Unknown Command: ") + cmd + params.join(" ");
-}
-
diff --git a/src/core/networkconnection.h b/src/core/networkconnection.h
deleted file mode 100644 (file)
index d947455..0000000
+++ /dev/null
@@ -1,215 +0,0 @@
-/***************************************************************************
- *   Copyright (C) 2005-08 by the Quassel Project                          *
- *   devel@quassel-irc.org                                                 *
- *                                                                         *
- *   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 2 of the License, or     *
- *   (at your option) version 3.                                           *
- *                                                                         *
- *   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, write to the                         *
- *   Free Software Foundation, Inc.,                                       *
- *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
- ***************************************************************************/
-
-#ifndef _NETWORKCONNECTION_H_
-#define _NETWORKCONNECTION_H_
-
-#include <QAbstractSocket>
-#include <QString>
-#include <QStringList>
-#include <QTimer>
-
-#ifdef HAVE_SSL
-# include <QSslSocket>
-# include <QSslError>
-#else
-# include <QTcpSocket>
-#endif
-
-#include "coresession.h"
-#include "identity.h"
-#include "message.h"
-#include "network.h"
-#include "signalproxy.h"
-
-class IrcServerHandler;
-class UserInputHandler;
-class CtcpHandler;
-
-class NetworkConnection : public QObject {
-  Q_OBJECT
-
-public:
-  NetworkConnection(Network *network, CoreSession *session);
-  ~NetworkConnection();
-
-  inline NetworkId networkId() const { return network()->networkId(); }
-  inline QString networkName() const { return network()->networkName(); }
-  inline Network *network() const { return _network; }
-  inline Identity *identity() const { return coreSession()->identity(network()->identity()); }
-  inline CoreSession *coreSession() const { return _coreSession; }
-
-  inline bool isConnected() const { return connectionState() == Network::Initialized; }
-  inline Network::ConnectionState connectionState() const { return _connectionState; }
-
-  inline IrcServerHandler *ircServerHandler() const { return _ircServerHandler; }
-  inline UserInputHandler *userInputHandler() const { return _userInputHandler; }
-  inline CtcpHandler *ctcpHandler() const { return _ctcpHandler; }
-
-  //! Decode a string using the server (network) decoding.
-  QString serverDecode(const QByteArray &string) const;
-
-  //! Decode a string using a channel-specific encoding if one is set (and use the standard encoding else).
-  QString channelDecode(const QString &channelName, const QByteArray &string) const;
-
-  //! Decode a string using an IrcUser-specific encoding, if one exists (using the standaed encoding else).
-  QString userDecode(const QString &userNick, const QByteArray &string) const;
-
-  //! Encode a string using the server (network) encoding.
-  QByteArray serverEncode(const QString &string) const;
-
-  //! Encode a string using the channel-specific encoding, if set, and use the standard encoding else.
-  QByteArray channelEncode(const QString &channelName, const QString &string) const;
-
-  //! Encode a string using the user-specific encoding, if set, and use the standard encoding else.
-  QByteArray userEncode(const QString &userNick, const QString &string) const;
-
-  inline QString channelKey(const QString &channel) const { return _channelKeys.value(channel.toLower(), QString()); }
-  inline QStringList persistentChannels() const { return _channelKeys.keys(); }
-
-  inline bool isAutoWhoInProgress(const QString &channel) const { return _autoWhoInProgress.value(channel.toLower(), 0); }
-
-public slots:
-  // void setServerOptions();
-  void connectToIrc(bool reconnecting = false);
-  void disconnectFromIrc(bool requested = true, const QString &reason = QString());
-  void userInput(BufferInfo bufferInfo, QString msg);
-
-  void putRawLine(QByteArray input);
-  int lastParamOverrun(const QString &cmd, const QList<QByteArray> &params);
-  void putCmd(const QString &cmd, const QList<QByteArray> &params, const QByteArray &prefix = QByteArray());
-
-  void setChannelJoined(const QString &channel);
-  void setChannelParted(const QString &channel);
-  void addChannelKey(const QString &channel, const QString &key);
-  void removeChannelKey(const QString &channel);
-
-  bool setAutoWhoDone(const QString &channel);
-
-signals:
-  // #void networkState(QString net, QVariantMap data);
-  void recvRawServerMsg(QString);
-  void displayStatusMsg(QString);
-  //void displayMsg(Message msg);
-  void displayMsg(Message::Type, BufferInfo::Type, QString target, QString text, QString sender = "", Message::Flags flags = Message::None);
-  void connected(NetworkId networkId);   ///< Emitted after receipt of 001 to indicate that we can now send data to the IRC server
-  void disconnected(NetworkId networkId);
-  void connectionStateChanged(Network::ConnectionState);
-  void connectionInitialized(); ///< Emitted after receipt of 001 to indicate that we can now send data to the IRC server
-  void connectionError(const QString &errorMsg);
-
-  void quitRequested(NetworkId networkId);
-
-  //void queryRequested(QString network, QString nick);
-  void nickChanged(const NetworkId &networkId, const QString &newNick, const QString &oldNick); // this signal is inteded to rename query buffers in the storage backend
-  void channelJoined(NetworkId, const QString &channel, const QString &key = QString());
-  void channelParted(NetworkId, const QString &channel);
-
-  void sslErrors(const QVariant &errorData);
-
-private slots:
-  void socketHasData();
-  void socketError(QAbstractSocket::SocketError);
-  void socketConnected();
-  void socketInitialized();
-  void socketCloseTimeout();
-  void socketDisconnected();
-  void socketStateChanged(QAbstractSocket::SocketState);
-  void setConnectionState(Network::ConnectionState);
-  void networkInitialized(const QString &currentServer);
-
-  void sendPerform();
-  void autoReconnectSettingsChanged();
-  void doAutoReconnect();
-  void sendPing();
-  void sendAutoWho();
-  void startAutoWhoCycle();
-  void nickChanged(const QString &newNick, const QString &oldNick); // this signal is inteded to rename query buffers in the storage backend
-
-#ifdef HAVE_SSL
-  void socketEncrypted();
-  void sslErrors(const QList<QSslError> &errors);
-#endif
-
-  void fillBucketAndProcessQueue();
-
-private:
-#ifdef HAVE_SSL
-  QSslSocket socket;
-#else
-  QTcpSocket socket;
-#endif
-
-  Network::ConnectionState _connectionState;
-
-  Network *_network;
-  CoreSession *_coreSession;
-  BufferInfo _statusBufferInfo;
-
-  IrcServerHandler *_ircServerHandler;
-  UserInputHandler *_userInputHandler;
-  CtcpHandler *_ctcpHandler;
-
-  QHash<QString, QString> _channelKeys;  // stores persistent channels and their passwords, if any
-
-  QTimer _autoReconnectTimer;
-  
-  int _autoReconnectCount;
-
-  QTimer _socketCloseTimer;
-
-  /* this flag triggers quitRequested() once the socket is closed
-   * it is needed to determine whether or not the connection needs to be
-   *in the automatic session restore. */
-  bool _quitRequested;
-
-  bool _previousConnectionAttemptFailed;
-  int _lastUsedServerlistIndex;
-
-  QTimer _pingTimer;
-  
-  bool _autoWhoEnabled;
-  QStringList _autoWhoQueue;
-  QHash<QString, int> _autoWhoInProgress;
-  int _autoWhoInterval;
-  int _autoWhoNickLimit;
-  int _autoWhoDelay;
-  QTimer _autoWhoTimer, _autoWhoCycleTimer;
-
-  QTimer _tokenBucketTimer;
-  int _messagesPerSecond;   // token refill speed
-  int _burstSize;   // size of the token bucket
-  int _tokenBucket; // the virtual bucket that holds the tokens
-  QList<QByteArray> _msgQueue;
-
-  void writeToSocket(QByteArray s);
-
-  class ParseError : public Exception {
-  public:
-    ParseError(QString cmd, QString prefix, QStringList params);
-  };
-
-  class UnknownCmdError : public Exception {
-  public:
-    UnknownCmdError(QString cmd, QString prefix, QStringList params);
-  };
-};
-
-#endif
index 44373b6..8e6896f 100644 (file)
 
 #include "util.h"
 
-#include "networkconnection.h"
-#include "network.h"
 #include "ctcphandler.h"
+#include "identity.h"
 #include "ircuser.h"
 
 #include <QDebug>
 #include <QRegExp>
 
-UserInputHandler::UserInputHandler(NetworkConnection *parent) : BasicHandler(parent) {
+UserInputHandler::UserInputHandler(CoreNetwork *parent)
+  : BasicHandler(parent)
+{
 }
 
 void UserInputHandler::handleUserInput(const BufferInfo &bufferInfo, const QString &msg_) {
@@ -58,7 +59,6 @@ void UserInputHandler::handleUserInput(const BufferInfo &bufferInfo, const QStri
 // ====================
 //  Public Slots
 // ====================
-
 void UserInputHandler::handleAway(const BufferInfo &bufferInfo, const QString &msg) {
   Q_UNUSED(bufferInfo)
 
@@ -68,7 +68,7 @@ void UserInputHandler::handleAway(const BufferInfo &bufferInfo, const QString &m
   // if there is no message supplied we have to check if we are already away or not
   if(msg.isEmpty()) {
     if(me && !me->isAway())
-      awayMsg = networkConnection()->identity()->awayReason();
+      awayMsg = network()->identityPtr()->awayReason();
   }
   if(me)
     me->setAwayMessage(awayMsg);
@@ -124,9 +124,12 @@ void UserInputHandler::banOrUnban(const BufferInfo &bufferInfo, const QString &m
 
 void UserInputHandler::handleCtcp(const BufferInfo &bufferInfo, const QString &msg) {
   Q_UNUSED(bufferInfo)
+
   QString nick = msg.section(' ', 0, 0);
   QString ctcpTag = msg.section(' ', 1, 1).toUpper();
-  if (ctcpTag.isEmpty()) return;
+  if(ctcpTag.isEmpty())
+    return;
+
   QString message = "";
   QString verboseMessage = tr("sending CTCP-%1 request").arg(ctcpTag);
 
@@ -135,7 +138,7 @@ void UserInputHandler::handleCtcp(const BufferInfo &bufferInfo, const QString &m
     message = QString::number(now);
   }
 
-  networkConnection()->ctcpHandler()->query(nick, ctcpTag, message);
+  network()->ctcpHandler()->query(nick, ctcpTag, message);
   emit displayMsg(Message::Action, BufferInfo::StatusBuffer, "", verboseMessage, network()->myNick());
 }
 
@@ -181,10 +184,10 @@ void UserInputHandler::handleJoin(const BufferInfo &bufferInfo, const QString &m
   i = 0;
   for(; i < keys.count(); i++) {
     if(i >= chans.count()) break;
-    networkConnection()->addChannelKey(chans[i], keys[i]);
+    network()->addChannelKey(chans[i], keys[i]);
   }
   for(; i < chans.count(); i++) {
-    networkConnection()->removeChannelKey(chans[i]);
+    network()->removeChannelKey(chans[i]);
   }
 }
 
@@ -192,7 +195,7 @@ void UserInputHandler::handleKick(const BufferInfo &bufferInfo, const QString &m
   QString nick = msg.section(' ', 0, 0, QString::SectionSkipEmpty);
   QString reason = msg.section(' ', 1, -1, QString::SectionSkipEmpty).trimmed();
   if(reason.isEmpty())
-    reason = networkConnection()->identity()->kickReason();
+    reason = network()->identityPtr()->kickReason();
 
   QList<QByteArray> params;
   params << serverEncode(bufferInfo.bufferName()) << serverEncode(nick) << channelEncode(bufferInfo.bufferName(), reason);
@@ -216,7 +219,7 @@ void UserInputHandler::handleList(const BufferInfo &bufferInfo, const QString &m
 
 void UserInputHandler::handleMe(const BufferInfo &bufferInfo, const QString &msg) {
   if(bufferInfo.bufferName().isEmpty()) return; // server buffer
-  networkConnection()->ctcpHandler()->query(bufferInfo.bufferName(), "ACTION", msg);
+  network()->ctcpHandler()->query(bufferInfo.bufferName(), "ACTION", msg);
   emit displayMsg(Message::Action, bufferInfo.type(), bufferInfo.bufferName(), msg, network()->myNick(), Message::Self);
 }
 
@@ -238,11 +241,8 @@ void UserInputHandler::handleMsg(const BufferInfo &bufferInfo, const QString &ms
   if(!msg.contains(' '))
     return;
 
-  QList<QByteArray> params;
-  params << serverEncode(msg.section(' ', 0, 0));
-  params << userEncode(params[0], msg.section(' ', 1));
-
-  emit putCmd("PRIVMSG", params);
+  QByteArray target = serverEncode(msg.section(' ', 0, 0));
+  putPrivmsg(target, userEncode(target, msg.section(' ', 1)));
 }
 
 void UserInputHandler::handleNick(const BufferInfo &bufferInfo, const QString &msg) {
@@ -287,7 +287,7 @@ void UserInputHandler::handlePart(const BufferInfo &bufferInfo, const QString &m
   }
 
   if(partReason.isEmpty())
-    partReason = networkConnection()->identity()->partReason();
+    partReason = network()->identityPtr()->partReason();
 
   params << serverEncode(channelName) << channelEncode(bufferInfo.bufferName(), partReason);
   emit putCmd("PART", params);
@@ -317,13 +317,13 @@ void UserInputHandler::handleQuery(const BufferInfo &bufferInfo, const QString &
 
 void UserInputHandler::handleQuit(const BufferInfo &bufferInfo, const QString &msg) {
   Q_UNUSED(bufferInfo)
-  networkConnection()->disconnectFromIrc(true, msg);
+  network()->disconnectFromIrc(true, msg);
 }
 
 void UserInputHandler::issueQuit(const QString &reason) {
   QString quitReason;
   if(reason.isEmpty())
-    quitReason = networkConnection()->identity()->quitReason();
+    quitReason = network()->identityPtr()->quitReason();
   else
     quitReason = reason;
   emit putCmd("QUIT", serverEncode(quitReason));
@@ -335,10 +335,9 @@ void UserInputHandler::handleQuote(const BufferInfo &bufferInfo, const QString &
 }
 
 void UserInputHandler::handleSay(const BufferInfo &bufferInfo, const QString &msg) {
-  if(bufferInfo.bufferName().isEmpty()) return;  // server buffer
-  QList<QByteArray> params;
-  params << serverEncode(bufferInfo.bufferName()) << channelEncode(bufferInfo.bufferName(), msg);
-  emit putCmd("PRIVMSG", params);
+  if(bufferInfo.bufferName().isEmpty())
+    return;  // server buffer
+  putPrivmsg(serverEncode(bufferInfo.bufferName()), channelEncode(bufferInfo.bufferName(), msg));
   emit displayMsg(Message::Plain, bufferInfo.type(), bufferInfo.bufferName(), msg, network()->myNick(), Message::Self);
 }
 
@@ -422,4 +421,53 @@ void UserInputHandler::expand(const QString &alias, const BufferInfo &bufferInfo
 }
 
 
+void UserInputHandler::putPrivmsg(const QByteArray &target, const QByteArray &message) {
+  static const char *cmd = "PRIVMSG";
+  int overrun = lastParamOverrun(cmd, QList<QByteArray>() << message);
+  if(overrun) {
+    static const char *splitter = " .,-";
+    int maxSplitPos = message.count() - overrun;
+    int splitPos = -1;
+    for(const char *splitChar = splitter; *splitChar != 0; splitChar++) {
+      splitPos = qMax(splitPos, message.lastIndexOf(*splitChar, maxSplitPos));
+    }
+    if(splitPos <= 0) {
+      splitPos = maxSplitPos;
+    }
+    putCmd(cmd, QList<QByteArray>() << target << message.left(splitPos));
+    putPrivmsg(target, message.mid(splitPos));
+    return;
+  } else {
+    putCmd(cmd, QList<QByteArray>() << target << message);
+  }
+}
+
+// returns 0 if the message will not be chopped by the irc server or number of chopped bytes if message is too long
+int UserInputHandler::lastParamOverrun(const QString &cmd, const QList<QByteArray> &params) {
+  // the server will pass our message trunkated to 512 bytes including CRLF with the following format:
+  // ":prefix COMMAND param0 param1 :lastparam"
+  // where prefix = "nickname!user@host"
+  // that means that the last message can be as long as:
+  // 512 - nicklen - userlen - hostlen - commandlen - sum(param[0]..param[n-1])) - 2 (for CRLF) - 4 (":!@" + 1space between prefix and command) - max(paramcount - 1, 0) (space for simple params) - 2 (space and colon for last param)
+  IrcUser *me = network()->me();
+  int maxLen = 480 - cmd.toAscii().count(); // educated guess in case we don't know us (yet?)
+
+  if(me)
+    maxLen = 512 - serverEncode(me->nick()).count() - serverEncode(me->user()).count() - serverEncode(me->host()).count() - cmd.toAscii().count() - 6;
+
+  if(!params.isEmpty()) {
+    for(int i = 0; i < params.count() - 1; i++) {
+      maxLen -= (params[i].count() + 1);
+    }
+    maxLen -= 2; // " :" last param separator;
+
+    if(params.last().count() > maxLen) {
+      return params.last().count() - maxLen;
+    } else {
+      return 0;
+    }
+  } else {
+    return 0;
+  }
+}
 
index f8f936f..f7bd01d 100644 (file)
@@ -29,7 +29,7 @@ class UserInputHandler : public BasicHandler {
   Q_OBJECT
 
 public:
-  UserInputHandler(NetworkConnection *parent = 0);
+  UserInputHandler(CoreNetwork *parent = 0);
 
   void handleUserInput(const BufferInfo &bufferInfo, const QString &text);
   
@@ -71,6 +71,8 @@ public slots:
 private:
   void expand(const QString &alias, const BufferInfo &bufferInfo, const QString &msg);
   void banOrUnban(const BufferInfo &bufferInfo, const QString &text, bool ban);
+  void putPrivmsg(const QByteArray &target, const QByteArray &message);
+  int lastParamOverrun(const QString &cmd, const QList<QByteArray> &params);
 };