Ok this is the major rework of quassel we've all been waiting for. For the actual...
authorMarcus Eggenberger <egs@quassel-irc.org>
Thu, 18 Oct 2007 13:58:04 +0000 (13:58 +0000)
committerMarcus Eggenberger <egs@quassel-irc.org>
Thu, 18 Oct 2007 13:58:04 +0000 (13:58 +0000)
Major changes:
 - core/server.cpp has been disected into seperate handlers which all derive from core/basichandler
 - the switch from networknames to networkids has been done where possible (connection to irc is still missing since this is undergoing a separate redesign)
 - there are now objects providing information about networks, ircusers and channels. they are avaialbe in the core and in the client
 - BufferId has been renamed to BufferInfo since it's no longer an Identifier. (the actual identifier is BufferInfo.uid())

60 files changed:
src/client/CMakeLists.txt
src/client/buffer.cpp
src/client/buffer.h
src/client/buffertreemodel.cpp
src/client/buffertreemodel.h
src/client/client.cpp
src/client/client.h
src/client/quasselui.h
src/common/CMakeLists.txt
src/common/bufferinfo.cpp [new file with mode: 0644]
src/common/bufferinfo.h [new file with mode: 0644]
src/common/common.pri
src/common/global.cpp
src/common/global.h
src/common/ircchannel.cpp [new file with mode: 0644]
src/common/ircchannel.h [new file with mode: 0644]
src/common/ircuser.cpp
src/common/ircuser.h
src/common/main.cpp
src/common/message.cpp
src/common/message.h
src/common/networkinfo.cpp [new file with mode: 0644]
src/common/networkinfo.h [new file with mode: 0644]
src/common/signalproxy.h
src/common/synchronizer.cpp [new file with mode: 0644]
src/common/synchronizer.h [new file with mode: 0644]
src/core/CMakeLists.txt
src/core/basichandler.cpp [new file with mode: 0644]
src/core/basichandler.h [new file with mode: 0644]
src/core/core.cpp
src/core/core.pri
src/core/coresession.cpp
src/core/coresession.h
src/core/ctcphandler.cpp [new file with mode: 0644]
src/core/ctcphandler.h [new file with mode: 0644]
src/core/ircserverhandler.cpp [new file with mode: 0644]
src/core/ircserverhandler.h [new file with mode: 0644]
src/core/server.cpp
src/core/server.h
src/core/serverinfo.cpp [deleted file]
src/core/serverinfo.h [deleted file]
src/core/sqlitestorage.cpp
src/core/sqlitestorage.h
src/core/storage.cpp
src/core/storage.h
src/core/userinputhandler.cpp [new file with mode: 0644]
src/core/userinputhandler.h [new file with mode: 0644]
src/qtgui/bufferviewfilter.cpp
src/qtgui/chatline.cpp
src/qtgui/chatline.h
src/qtgui/mainwin.cpp
src/qtgui/mainwin.h
src/qtgui/qtgui.pri
src/qtgui/topicwidget.cpp [new file with mode: 0644]
src/qtgui/topicwidget.h [new file with mode: 0644]
src/qtgui/ui/topicwidget.ui [new file with mode: 0644]
src/qtopia/chatline.cpp
src/qtopia/chatline.h
src/qtopia/qtopiamainwin.cpp
src/qtopia/qtopiamainwin.h

index 3ad8f7d..7746c0f 100644 (file)
@@ -5,4 +5,4 @@ SET(client_MOCS buffer.h buffertreemodel.h client.h clientsettings.h quasselui.h
 QT4_WRAP_CPP(_MOC ${client_MOCS})
 
 ADD_LIBRARY(client ${client_SRCS} ${_MOC})
-TARGET_LINK_LIBRARIES(client common)
\ No newline at end of file
+TARGET_LINK_LIBRARIES(client common)
index 917d71a..1fb0797 100644 (file)
 #include "util.h"
 
 
-Buffer::Buffer(BufferId bufid) {
-  id = bufid;
-  _networkName = bufid.network();
-  _bufferName = bufid.buffer();
-
-  if(_bufferName.isEmpty()) type = ServerBuffer;
-  else if(isChannelName(_bufferName)) type = ChannelBuffer;
-  else type = QueryBuffer;
+Buffer::Buffer(BufferInfo bufferid, QObject *parent)
+  : QObject(parent),
+    _bufferInfo(bufferid),
+    _active(false)
+{
+  if(bufferid.buffer().isEmpty())
+    _type = ServerBuffer;
+  else if(isChannelName(bufferid.buffer()))
+    _type = ChannelBuffer;
+  else
+    _type = QueryBuffer;
 
-  active = false;
 /*
   QSettings s;
   s.beginGroup(QString("GUI/BufferStates/%1/%2").arg(netname).arg(bufname));
@@ -55,19 +57,32 @@ Buffer::~Buffer() {
 }
 
 Buffer::Type Buffer::bufferType() const {
-   return type;
+  return _type;
 }
 
 bool Buffer::isActive() const {
-   return active;
+  // FIXME determine status by checking for a networkInfo objekt
+  return true;
+}
+
+BufferInfo Buffer::bufferInfo() const {
+   return _bufferInfo;
+}
+
+void Buffer::updateBufferInfo(BufferInfo bufferid) {
+  _bufferInfo = bufferid;
+}
+
+uint Buffer::networkId() const {
+  return bufferInfo().networkId();
 }
 
 QString Buffer::networkName() const {
-   return _networkName;
+  return bufferInfo().network();
 }
 
 QString Buffer::bufferName() const {
-   return _bufferName;
+  return bufferInfo().buffer();
 }
 
 QString Buffer::displayName() const {
@@ -77,24 +92,23 @@ QString Buffer::displayName() const {
     return bufferName();
 }
 
-BufferId Buffer::bufferId() const {
-   return id;
-}
-
 QList<AbstractUiMsg *> Buffer::contents() const {
-   return layoutedMsgs;
+  return layoutedMsgs;
 }
 
 QVariantMap Buffer::nickList() const {
-   return nicks;
+  // FIXME should return a Map or List of IrcUsers in the future
+  return QVariantMap();
 }
 
 QString Buffer::topic() const {
-   return _topic;
+  // FIXME check if we got a networkInfo() object
+  return QString();
 }
 
 QString Buffer::ownNick() const {
-   return _ownNick;
+  // FIXME check if we got a networkInfo() object
+  return QString();
 }
 
 bool Buffer::isStatusBuffer() const {
@@ -102,10 +116,10 @@ bool Buffer::isStatusBuffer() const {
 }
 
 void Buffer::setActive(bool a) {
-  if(a != active) {
-    active = a;
-    emit bufferUpdated(this);
-  }
+//   if(a != active) {
+//     active = a;
+//     emit bufferUpdated(this);
+//  }
 }
 
 void Buffer::appendMsg(const Message &msg) {
@@ -129,39 +143,41 @@ bool Buffer::layoutMsg() {
 
 void Buffer::processUserInput(QString msg) {
   // TODO User Input processing (plugins) -> well, this goes through MainWin into Core for processing... so...
-  emit userInput(id, msg);
-}
-
-void Buffer::setTopic(QString t) {
-  _topic = t;
-  emit topicSet(t);
-  emit bufferUpdated(this);
-}
-
-void Buffer::addNick(QString nick, QVariantMap props) {
-  if(nick == ownNick()) setActive(true);
-  nicks[nick] = props;
-  emit nickListChanged(nicks);
-}
-
-void Buffer::updateNick(QString nick, QVariantMap props) {
-  nicks[nick] = props;
-  emit nickListChanged(nicks);
-}
-
-void Buffer::renameNick(QString oldnick, QString newnick) {
-  QVariant v = nicks.take(oldnick);
-  nicks[newnick] = v;
-  emit nickListChanged(nicks);
-}
-
-void Buffer::removeNick(QString nick) {
-  if(nick == ownNick()) setActive(false);
-  nicks.remove(nick);
-  emit nickListChanged(nicks);
-}
-
-void Buffer::setOwnNick(QString nick) {
-  _ownNick = nick;
-  emit ownNickSet(nick);
-}
+  emit userInput(_bufferInfo, msg);
+}
+
+// no longer needed
+// back reference:
+// void Buffer::setTopic(QString t) {
+//   _topic = t;
+//   emit topicSet(t);
+//   emit bufferUpdated(this);
+// }
+
+// void Buffer::addNick(QString nick, QVariantMap props) {
+//   if(nick == ownNick()) setActive(true);
+//   nicks[nick] = props;
+//   emit nickListChanged(nicks);
+// }
+
+// void Buffer::updateNick(QString nick, QVariantMap props) {
+//   nicks[nick] = props;
+//   emit nickListChanged(nicks);
+// }
+
+// void Buffer::renameNick(QString oldnick, QString newnick) {
+//   QVariant v = nicks.take(oldnick);
+//   nicks[newnick] = v;
+//   emit nickListChanged(nicks);
+// }
+
+// void Buffer::removeNick(QString nick) {
+//   if(nick == ownNick()) setActive(false);
+//   nicks.remove(nick);
+//   emit nickListChanged(nicks);
+// }
+
+// void Buffer::setOwnNick(QString nick) {
+//   _ownNick = nick;
+//   emit ownNickSet(nick);
+// }
index 68de96a..3465e5f 100644 (file)
 #ifndef _BUFFER_H_
 #define _BUFFER_H_
 
-#include "global.h"
-
 class AbstractUiMsg;
-class Message;
+
 struct BufferState;
 
+#include "message.h"
+#include "bufferinfo.h"
+
+#include <QVariantMap>
+
 //!\brief Encapsulates the contents of a single channel, query or server status context.
 /** A Buffer maintains a list of existing nicks and their status.
  */
 class Buffer : public QObject {
   Q_OBJECT
 
-  public:
-    Buffer(BufferId);
-    ~Buffer();
-
-    enum Type { ServerBuffer, ChannelBuffer, QueryBuffer };
-
-    enum Activity {
-      NoActivity = 0x00,
-      OtherActivity = 0x01,
-      NewMessage = 0x02,
-      Highlight = 0x40
-    };
-    Q_DECLARE_FLAGS(ActivityLevel, Activity);
-
-    Type bufferType() const;
-    bool isActive() const;
-
-    QString networkName() const;
-    QString bufferName() const;
-    QString displayName() const;
-    BufferId bufferId() const;
-    QList<AbstractUiMsg *> contents() const;
-    QVariantMap nickList() const;
-    QString topic() const;
-    QString ownNick() const;
-    bool isStatusBuffer() const;
-
-  signals:
-    void userInput(const BufferId &, QString);
-    void nickListChanged(QVariantMap nicks);
-    void topicSet(QString topic);
-    void ownNickSet(QString ownNick);
-    void bufferUpdated(Buffer *);
-    void bufferDestroyed(Buffer *);
-
-    void msgAppended(AbstractUiMsg *);
-    void msgPrepended(AbstractUiMsg *);
-    void layoutQueueEmpty();
-
-  public slots:
-    void setActive(bool active = true);
-    void appendMsg(const Message &);
-    void prependMsg(const Message &);
-    bool layoutMsg();
-    void setTopic(QString);
-    //void setNicks(QStringList);
-    void addNick(QString nick, QVariantMap props);
-    void renameNick(QString oldnick, QString newnick);
-    void removeNick(QString nick);
-    void updateNick(QString nick, QVariantMap props);
-    void setOwnNick(QString nick);
-
-    void processUserInput(QString);
-
-  private:
-    BufferId id;
-    bool active;
-    Type type;
-
-    QVariantMap nicks;
-    QString _topic;
-    QString _ownNick;
-    QString _networkName, _bufferName;
-    BufferState *state;
-
-    QList<Message> layoutQueue;
-    QList<AbstractUiMsg *> layoutedMsgs;
+public:
+  Buffer(BufferInfo, QObject *parent = 0);
+  ~Buffer();
+
+  enum Type {
+    ServerBuffer,
+    ChannelBuffer,
+    QueryBuffer
+  };
+
+  enum Activity {
+    NoActivity = 0x00,
+    OtherActivity = 0x01,
+    NewMessage = 0x02,
+    Highlight = 0x40
+  };
+  Q_DECLARE_FLAGS(ActivityLevel, Activity)
+
+  bool isStatusBuffer() const;
+  Type bufferType() const;
+  bool isActive() const;
+
+  BufferInfo bufferInfo() const;
+  void updateBufferInfo(BufferInfo bufferid);
+  
+  uint networkId() const;
+  
+  QString networkName() const;
+  QString bufferName() const;
+  QString displayName() const;
+  
+  QList<AbstractUiMsg *> contents() const;
+  
+  QVariantMap nickList() const;
+  QString topic() const;
+  QString ownNick() const;
+
+signals:
+  void userInput(const BufferInfo &, QString);
+  void nickListChanged(QVariantMap nicks);
+  void topicSet(QString topic);
+  void ownNickSet(QString ownNick);
+  void bufferUpdated(Buffer *);
+  void bufferDestroyed(Buffer *);
+
+  void msgAppended(AbstractUiMsg *);
+  void msgPrepended(AbstractUiMsg *);
+  void layoutQueueEmpty();
+
+public slots:
+  void setActive(bool active = true);
+  void appendMsg(const Message &);
+  void prependMsg(const Message &);
+  bool layoutMsg();
+
+  // no longer needed
+//   void setTopic(QString);
+//   //void setNicks(QStringList);
+//   void addNick(QString nick, QVariantMap props);
+//   void renameNick(QString oldnick, QString newnick);
+//   void removeNick(QString nick);
+//   void updateNick(QString nick, QVariantMap props);
+//  void setOwnNick(QString nick);
+
+  void processUserInput(QString);
+
+private:
+  BufferInfo _bufferInfo;
+  bool _active;
+  Type _type;
+  BufferState *state;
+
+  QList<Message> layoutQueue;
+  QList<AbstractUiMsg *> layoutedMsgs;
 
 };
 Q_DECLARE_OPERATORS_FOR_FLAGS(Buffer::ActivityLevel)
index b93f858..fc9ea51 100644 (file)
 
 #include <QColor>  // FIXME Dependency on QtGui!
 
-#include "client.h"
 #include "buffertreemodel.h"
+
+#include "bufferinfo.h"
+#include "client.h"
 #include "signalproxy.h"
 
 /*****************************************
@@ -33,7 +35,7 @@ BufferTreeItem::BufferTreeItem(Buffer *buffer, TreeItem *parent) : TreeItem(pare
 }
 
 uint BufferTreeItem::id() const {
-  return buf->bufferId().uid();
+  return buf->bufferInfo().uid();
 }
 
 void BufferTreeItem::setActivity(const Buffer::ActivityLevel &level) {
@@ -80,8 +82,8 @@ QVariant BufferTreeItem::data(int column, int role) const {
       return buf->bufferType();
     case BufferTreeModel::BufferActiveRole:
       return buf->isActive();
-    case BufferTreeModel::BufferIdRole:
-      return buf->bufferId().uid();
+    case BufferTreeModel::BufferInfoRole:
+      return buf->bufferInfo().uid();
     default:
       return QVariant();
   }
@@ -117,7 +119,7 @@ Qt::ItemFlags NetworkTreeItem::flags() const {
 BufferTreeModel::BufferTreeModel(QObject *parent)
   : TreeModel(BufferTreeModel::defaultHeader(), parent)
 {
-  Client::signalProxy()->attachSignal(this, SIGNAL(fakeUserInput(BufferId, QString)), SIGNAL(sendInput(BufferId, QString)));
+  Client::signalProxy()->attachSignal(this, SIGNAL(fakeUserInput(BufferInfo, QString)), SIGNAL(sendInput(BufferInfo, QString)));
 }
 
 QList<QVariant >BufferTreeModel::defaultHeader() {
@@ -158,7 +160,7 @@ QModelIndex BufferTreeModel::getOrCreateBufferItemIndex(Buffer *buffer) {
   NetworkTreeItem *networkItem = static_cast<NetworkTreeItem*>(networkItemIndex.internalPointer());
   TreeItem *bufferItem;
   
-  if(not(bufferItem = networkItem->childById(buffer->bufferId().uid()))) {
+  if(not(bufferItem = networkItem->childById(buffer->bufferInfo().uid()))) {
     int nextRow = networkItem->childCount();
     bufferItem = new BufferTreeItem(buffer, networkItem);
     
@@ -175,7 +177,7 @@ QStringList BufferTreeModel::mimeTypes() const {
   QStringList types;
   types << "application/Quassel/BufferItem/row"
     << "application/Quassel/BufferItem/network"
-    << "application/Quassel/BufferItem/bufferId";
+    << "application/Quassel/BufferItem/bufferInfo";
   return types;
 }
 
@@ -186,7 +188,7 @@ QMimeData *BufferTreeModel::mimeData(const QModelIndexList &indexes) const {
   
   mimeData->setData("application/Quassel/BufferItem/row", QByteArray::number(index.row()));
   mimeData->setData("application/Quassel/BufferItem/network", getBufferByIndex(index)->networkName().toUtf8());
-  mimeData->setData("application/Quassel/BufferItem/bufferId", QByteArray::number(getBufferByIndex(index)->bufferId().uid()));
+  mimeData->setData("application/Quassel/BufferItem/bufferInfo", QByteArray::number(getBufferByIndex(index)->bufferInfo().uid()));
   return mimeData;
 }
 
@@ -241,7 +243,7 @@ void BufferTreeModel::doubleClickReceived(const QModelIndex &clicked) {
   if(isBufferIndex(clicked)) {
     Buffer *buffer = getBufferByIndex(clicked);
     if(!buffer->isStatusBuffer()) 
-      emit fakeUserInput(buffer->bufferId(), QString("/join " + buffer->bufferName()));
+      emit fakeUserInput(buffer->bufferInfo(), QString("/join " + buffer->bufferName()));
   }
 }
 
index 2d170ec..7053ef7 100644 (file)
@@ -24,6 +24,7 @@
 #include <QtCore>
 
 #include "treemodel.h"
+class BufferInfo;
 #include "buffer.h"
 
 /*****************************************
@@ -78,7 +79,7 @@ public:
     BufferTypeRole = Qt::UserRole,
     BufferActiveRole,
     BufferNameRole,
-    BufferIdRole
+    BufferInfoRole
   };
   
   BufferTreeModel(QObject *parent = 0);
@@ -94,7 +95,7 @@ public slots:
 signals:
   void bufferSelected(Buffer *);
   void invalidateFilter();
-  void fakeUserInput(BufferId, QString);
+  void fakeUserInput(BufferInfo, QString);
   void selectionChanged(const QModelIndex &);
     
 private:
index b561fd1..55bf9c5 100644 (file)
 
 #include "client.h"
 
-#include "buffer.h"
+#include "networkinfo.h"
+#include "ircuser.h"
+#include "ircchannel.h"
+
+#include "message.h"
+
+#include "bufferinfo.h"
 #include "buffertreemodel.h"
 #include "quasselui.h"
 #include "signalproxy.h"
+#include "synchronizer.h"
 #include "util.h"
 
-Client * Client::instanceptr = 0;
-
-bool Client::connectedToCore = false;
-Client::ClientMode Client::clientMode;
-QVariantMap Client::coreConnectionInfo;
-QHash<BufferId, Buffer *> Client::buffers;
-QHash<uint, BufferId> Client::bufferIds;
-QHash<QString, QHash<QString, QVariantMap> > Client::nicks;
-QHash<QString, bool> Client::netConnected;
-QStringList Client::netsAwaitingInit;
-QHash<QString, QString> Client::ownNick;
+QPointer<Client> Client::instanceptr = 0;
 
+// ==============================
+//  public Static Methods
+// ==============================
 Client *Client::instance() {
-  if(instanceptr) return instanceptr;
-  instanceptr = new Client();
+  if(!instanceptr)
+    instanceptr = new Client();
   return instanceptr;
 }
 
 void Client::destroy() {
   delete instanceptr;
-  instanceptr = 0;
-}
-
-Client::Client() {
-  _signalProxy = new SignalProxy(SignalProxy::Client, 0, this);
-
-  connectedToCore = false;
-  socket = 0;
 }
 
 void Client::init(AbstractUi *ui) {
@@ -61,33 +53,135 @@ void Client::init(AbstractUi *ui) {
   instance()->init();
 }
 
+QList<NetworkInfo *> Client::networkInfos() {
+  return instance()->_networkInfo.values();
+}
+
+NetworkInfo *Client::networkInfo(uint networkid) {
+  if(instance()->_networkInfo.contains(networkid))
+    return instance()->_networkInfo[networkid];
+  else
+    return 0;
+}
+
+QList<BufferInfo> Client::allBufferInfos() {
+  QList<BufferInfo> bufferids;
+  foreach(Buffer *buffer, buffers()) {
+    bufferids << buffer->bufferInfo();
+  }
+  return bufferids;
+}
+
+QList<Buffer *> Client::buffers() {
+  return instance()->_buffers.values();
+}
+
+Buffer *Client::buffer(uint bufferUid) {
+  if(instance()->_buffers.contains(bufferUid))
+    return instance()->_buffers[bufferUid];
+  else
+    return 0;
+}
+
+Buffer *Client::buffer(BufferInfo id) {
+  Buffer *buff = buffer(id.uid());
+  
+  if(!buff) {
+    Client *client = Client::instance();
+    Buffer *buff = new Buffer(id, client);
+
+    connect(buff, SIGNAL(userInput(BufferInfo, QString)),
+           client, SLOT(userInput(BufferInfo, QString)));
+    connect(buff, SIGNAL(bufferUpdated(Buffer *)),
+           client, SIGNAL(bufferUpdated(Buffer *)));
+    connect(buff, SIGNAL(bufferDestroyed(Buffer *)),
+           client, SIGNAL(bufferDestroyed(Buffer *)));
+    connect(buff, SIGNAL(bufferDestroyed(Buffer *)),
+           client, SLOT(removeBuffer(Buffer *)));
+    
+    client->_buffers[id.uid()] = buff;
+    emit client->bufferUpdated(buff);
+  }
+  
+  return buff;
+}
+
+// FIXME switch to netids!
+// WHEN IS THIS NEEDED ANYHOW!?
+BufferInfo Client::bufferInfo(QString net, QString buf) {
+  foreach(Buffer *buffer_, buffers()) {
+    BufferInfo bufferInfo = buffer_->bufferInfo();
+    if(bufferInfo.network() == net && bufferInfo.buffer() == buf)
+      return bufferInfo;
+  }
+  Q_ASSERT(false);  // should never happen!
+  return BufferInfo();
+}
+
+BufferInfo Client::statusBufferInfo(QString net) {
+  return bufferInfo(net, "");
+}
+
+BufferTreeModel *Client::bufferModel() {
+  return instance()->_bufferModel;
+}
+
+SignalProxy *Client::signalProxy() {
+  return instance()->_signalProxy;
+}
+
+// ==============================
+//  Constructor / Decon
+// ==============================
+Client::Client(QObject *parent)
+  : QObject(parent),
+    socket(0),
+    _signalProxy(new SignalProxy(SignalProxy::Client, 0, this)),
+    mainUi(0),
+    _bufferModel(0),
+    connectedToCore(false)
+{
+}
+
+Client::~Client() {
+// since we're now the parent of buffers this should be no longer needed
+  
+//   foreach(Buffer *buf, buffers.values()) delete buf; // this is done by disconnectFromCore()! FIXME?
+//   Q_ASSERT(!buffers.count());
+}
+
 void Client::init() {
   blockSize = 0;
 
   _bufferModel = new BufferTreeModel(this);
 
-  connect(this, SIGNAL(bufferSelected(Buffer *)), _bufferModel, SLOT(selectBuffer(Buffer *)));
-  connect(this, SIGNAL(bufferUpdated(Buffer *)), _bufferModel, SLOT(bufferUpdated(Buffer *)));
-  connect(this, SIGNAL(bufferActivity(Buffer::ActivityLevel, Buffer *)), _bufferModel, SLOT(bufferActivity(Buffer::ActivityLevel, Buffer *)));
+  connect(this, SIGNAL(bufferSelected(Buffer *)),
+         _bufferModel, SLOT(selectBuffer(Buffer *)));
+  connect(this, SIGNAL(bufferUpdated(Buffer *)),
+         _bufferModel, SLOT(bufferUpdated(Buffer *)));
+  connect(this, SIGNAL(bufferActivity(Buffer::ActivityLevel, Buffer *)),
+         _bufferModel, SLOT(bufferActivity(Buffer::ActivityLevel, Buffer *)));
 
   SignalProxy *p = signalProxy();
-  p->attachSignal(this, SIGNAL(sendSessionData(const QString &, const QVariant &)), SIGNAL(clientSessionDataChanged(const QString &, const QVariant &)));
-  p->attachSlot(SIGNAL(coreSessionDataChanged(const QString &, const QVariant &)), this, SLOT(recvSessionData(const QString &, const QVariant &)));
-  p->attachSlot(SIGNAL(coreState(const QVariant &)), this, SLOT(recvCoreState(const QVariant &)));
-  p->attachSlot(SIGNAL(networkState(QString, QVariant)), this, SLOT(recvNetworkState(QString, QVariant)));
-  p->attachSlot(SIGNAL(networkConnected(QString)), this, SLOT(networkConnected(QString)));
-  p->attachSlot(SIGNAL(networkDisconnected(QString)), this, SLOT(networkDisconnected(QString)));
-  p->attachSlot(SIGNAL(displayMsg(const Message &)), this, SLOT(recvMessage(const Message &)));
-  p->attachSlot(SIGNAL(displayStatusMsg(QString, QString)), this, SLOT(recvStatusMsg(QString, QString)));
-  p->attachSlot(SIGNAL(topicSet(QString, QString, QString)), this, SLOT(setTopic(QString, QString, QString)));
-  p->attachSlot(SIGNAL(nickAdded(QString, QString, QVariantMap)), this, SLOT(addNick(QString, QString, QVariantMap)));
-  p->attachSlot(SIGNAL(nickRemoved(QString, QString)), this, SLOT(removeNick(QString, QString)));
-  p->attachSlot(SIGNAL(nickRenamed(QString, QString, QString)), this, SLOT(renameNick(QString, QString, QString)));
-  p->attachSlot(SIGNAL(nickUpdated(QString, QString, QVariantMap)), this, SLOT(updateNick(QString, QString, QVariantMap)));
-  p->attachSlot(SIGNAL(ownNickSet(QString, QString)), this, SLOT(setOwnNick(QString, QString)));
-  p->attachSlot(SIGNAL(backlogData(BufferId, const QVariantList &, bool)), this, SLOT(recvBacklogData(BufferId, const QVariantList &, bool)));
-  p->attachSlot(SIGNAL(bufferIdUpdated(BufferId)), this, SLOT(updateBufferId(BufferId)));
-  p->attachSignal(this, SIGNAL(sendInput(BufferId, QString)));
+  p->attachSignal(this, SIGNAL(sendSessionData(const QString &, const QVariant &)),
+                 SIGNAL(clientSessionDataChanged(const QString &, const QVariant &)));
+  p->attachSlot(SIGNAL(coreSessionDataChanged(const QString &, const QVariant &)),
+               this, SLOT(recvSessionData(const QString &, const QVariant &)));
+  p->attachSlot(SIGNAL(coreState(const QVariant &)),
+               this, SLOT(recvCoreState(const QVariant &)));
+  p->attachSlot(SIGNAL(networkConnected(uint)),
+               this, SLOT(networkConnected(uint)));
+  p->attachSlot(SIGNAL(networkDisconnected(uint)),
+               this, SLOT(networkDisconnected(uint)));
+  p->attachSlot(SIGNAL(displayMsg(const Message &)),
+               this, SLOT(recvMessage(const Message &)));
+  p->attachSlot(SIGNAL(displayStatusMsg(QString, QString)),
+               this, SLOT(recvStatusMsg(QString, QString)));
+
+
+  p->attachSlot(SIGNAL(backlogData(BufferInfo, const QVariantList &, bool)), this, SLOT(recvBacklogData(BufferInfo, const QVariantList &, bool)));
+  p->attachSlot(SIGNAL(bufferInfoUpdated(BufferInfo)), this, SLOT(updateBufferInfo(BufferInfo)));
+  p->attachSignal(this, SIGNAL(sendInput(BufferInfo, QString)));
   p->attachSignal(this, SIGNAL(requestNetworkStates()));
 
   connect(mainUi, SIGNAL(connectToCore(const QVariantMap &)), this, SLOT(connectToCore(const QVariantMap &)));
@@ -99,33 +193,25 @@ void Client::init() {
   layoutTimer->setInterval(0);
   layoutTimer->setSingleShot(false);
   connect(layoutTimer, SIGNAL(timeout()), this, SLOT(layoutMsg()));
-}
-
-Client::~Client() {
-  foreach(Buffer *buf, buffers.values()) delete buf; // this is done by disconnectFromCore()! FIXME?
-  Q_ASSERT(!buffers.count());
-}
-
-BufferTreeModel *Client::bufferModel() {
-  return instance()->_bufferModel;
-}
 
-SignalProxy *Client::signalProxy() {
-  return instance()->_signalProxy;
 }
 
 bool Client::isConnected() {
-  return connectedToCore;
+  return instance()->connectedToCore;
 }
 
 void Client::connectToCore(const QVariantMap &conn) {
   // TODO implement SSL
   coreConnectionInfo = conn;
+  
   if(isConnected()) {
     emit coreConnectionError(tr("Already connected to Core!"));
     return;
   }
-  if(socket != 0) socket->deleteLater();
+  
+  if(socket != 0)
+    socket->deleteLater();
+  
   if(conn["Host"].toString().isEmpty()) {
     clientMode = LocalCore;
     socket = new QBuffer(this);
@@ -174,24 +260,26 @@ void Client::coreSocketConnected() {
 }
 
 void Client::coreSocketDisconnected() {
-  connectedToCore = false;
+  instance()->connectedToCore = false;
   emit disconnected();
   socket->deleteLater();
   blockSize = 0;
 
   /* Clear internal data. Hopefully nothing relies on it at this point. */
   _bufferModel->clear();
-  // Buffers, if deleted, send a signal that causes their removal from buffers and bufferIds.
+  // Buffers, if deleted, send a signal that causes their removal from buffers and bufferInfos.
   // So we cannot simply go through the array in a loop (or use qDeleteAll) for deletion...
-  while(buffers.count()) { delete buffers.take(buffers.keys()[0]); }
-  Q_ASSERT(!buffers.count());   // should be empty now!
-  Q_ASSERT(!bufferIds.count());
+  while(!_buffers.empty()) {
+    delete _buffers.take(_buffers.keys()[0]);
+  }
+  Q_ASSERT(_buffers.empty());
+
+  while(!_networkInfo.empty()) {
+    delete _networkInfo.take(_networkInfo.keys()[0]);
+  }
+    
   coreConnectionInfo.clear();
   sessionData.clear();
-  nicks.clear();
-  netConnected.clear();
-  netsAwaitingInit.clear();
-  ownNick.clear();
   layoutQueue.clear();
   layoutTimer->stop();
 }
@@ -214,30 +302,84 @@ void Client::syncToCore(const QVariant &coreState) {
     disconnectFromCore();
     return;
   }
+
   QVariantMap sessionState = coreState.toMap()["SessionState"].toMap();
-  QVariantMap sessData = sessionState["SessionData"].toMap();
 
-  foreach(QString key, sessData.keys()) {
+  // store sessionData
+  QVariantMap sessData = sessionState["SessionData"].toMap();
+  foreach(QString key, sessData.keys())
     recvSessionData(key, sessData[key]);
-  }
-  QList<QVariant> coreBuffers = sessionState["Buffers"].toList();
+
+  // store Buffer details
+  QVariantList coreBuffers = sessionState["Buffers"].toList();
   /* make lookups by id faster */
   foreach(QVariant vid, coreBuffers) {
-    BufferId id = vid.value<BufferId>();
-    bufferIds[id.uid()] = id;  // make lookups by id faster
-    buffer(id);                // create all buffers, so we see them in the network views
+    buffer(vid.value<BufferInfo>()); // create all buffers, so we see them in the network views
+  }
+
+  // create networkInfo objects
+  QVariantList networkids = sessionState["Networks"].toList();
+  foreach(QVariant networkid, networkids) {
+    networkConnected(networkid.toUInt());
   }
-  netsAwaitingInit = sessionState["Networks"].toStringList();
-  connectedToCore = true;
-  if(netsAwaitingInit.count()) {
+  
+  instance()->connectedToCore = true;
+  updateCoreConnectionProgress();
+}
+
+void Client::updateCoreConnectionProgress() {
+  // we'll do this in three steps:
+  // 1.) networks
+  // 2.) channels
+  // 3.) ircusers
+
+  int numNets = networkInfos().count();
+  int numNetsWaiting = 0;
+
+  int numIrcUsers = 0;
+  int numIrcUsersWaiting = 0;
+
+  int numChannels = 0;
+  int numChannelsWaiting = 0;
+
+  foreach(NetworkInfo *net, networkInfos()) {
+    if(not net->initialized())
+      numNetsWaiting++;
+
+    numIrcUsers += net->ircUsers().count();
+    foreach(IrcUser *user, net->ircUsers()) {
+      if(not user->initialized())
+       numIrcUsersWaiting++;
+    }
+
+    numChannels += net->ircChannels().count();
+    foreach(IrcChannel *channel, net->ircChannels()) {
+      if(not channel->initialized())
+       numChannelsWaiting++;
+    }
+
+  }
+
+  if(numNetsWaiting > 0) {
     emit coreConnectionMsg(tr("Requesting network states..."));
-    emit coreConnectionProgress(0, netsAwaitingInit.count());
-    emit requestNetworkStates();
+    emit coreConnectionProgress(numNets - numNetsWaiting, numNets);
+    return;
   }
-  else {
-    emit coreConnectionProgress(1, 1);
-    emit connected();
+
+  if(numIrcUsersWaiting > 0) {
+    emit coreConnectionMsg(tr("Requesting User states..."));
+    emit coreConnectionProgress(numIrcUsers - numIrcUsersWaiting, numIrcUsers);
+    return;
   }
+
+  if(numChannelsWaiting > 0) {
+    emit coreConnectionMsg(tr("Requesting Channel states..."));
+    emit coreConnectionProgress(numChannels - numChannelsWaiting, numChannels);
+    return;
+  }
+
+  emit coreConnectionProgress(1,1);
+  emit connected();
 }
 
 void Client::recvSessionData(const QString &key, const QVariant &data) {
@@ -280,92 +422,42 @@ void Client::coreHasData() {
   }
 }
 
-void Client::networkConnected(QString net) {
-  Q_ASSERT(!netsAwaitingInit.contains(net));
-  netConnected[net] = true;
-  BufferId id = statusBufferId(net);
-  Buffer *b = buffer(id);
-  b->setActive(true);
-  //b->displayMsg(Message(id, Message::Server, tr("Connected.")));
-  // TODO buffersUpdated();
-}
+void Client::networkConnected(uint netid) {
+  // TODO: create statusBuffer / switch to networkids
+  //BufferInfo id = statusBufferInfo(net);
+  //Buffer *b = buffer(id);
+  //b->setActive(true);
 
-void Client::networkDisconnected(QString net) {
-  foreach(BufferId id, buffers.keys()) {
-    if(id.network() != net) continue;
-    Buffer *b = buffer(id);
-    //b->displayMsg(Message(id, Message::Server, tr("Server disconnected."))); FIXME
-    b->setActive(false);
-  }
-  netConnected[net] = false;
-  if(netsAwaitingInit.contains(net)) {
-    qDebug() << "Network" << net << "disconnected while not yet initialized!";
-    netsAwaitingInit.removeAll(net);
-    emit coreConnectionProgress(netConnected.count(), netConnected.count() + netsAwaitingInit.count());
-    if(!netsAwaitingInit.count()) emit connected();
-  }
+  NetworkInfo *netinfo = new NetworkInfo(netid, signalProxy(), this);
+  connect(netinfo, SIGNAL(initDone()), this, SLOT(updateCoreConnectionProgress()));
+  connect(netinfo, SIGNAL(ircUserInitDone()), this, SLOT(updateCoreConnectionProgress()));
+  connect(netinfo, SIGNAL(ircChannelInitDone()), this, SLOT(updateCoreConnectionProgress()));
+  _networkInfo[netid] = netinfo;
 }
 
-void Client::updateBufferId(BufferId id) {
-  bufferIds[id.uid()] = id;  // make lookups by id faster
-  buffer(id);
-}
+void Client::networkDisconnected(uint networkid) {
+  foreach(Buffer *buffer, buffers()) {
+    if(buffer->bufferInfo().networkId() != networkid)
+      continue;
 
-BufferId Client::bufferId(QString net, QString buf) {
-  foreach(BufferId id, buffers.keys()) {
-    if(id.network() == net && id.buffer() == buf) return id;
+    //buffer->displayMsg(Message(bufferid, Message::Server, tr("Server disconnected."))); FIXME
+    buffer->setActive(false);
   }
-  Q_ASSERT(false);  // should never happen!
-  return BufferId();
-}
-
-BufferId Client::statusBufferId(QString net) {
-  return bufferId(net, "");
-}
-
-
-Buffer * Client::buffer(BufferId id) {
-  Client *client = Client::instance();
-  if(!buffers.contains(id)) {
-    Buffer *b = new Buffer(id);
-    b->setOwnNick(ownNick[id.network()]);
-    connect(b, SIGNAL(userInput(BufferId, QString)), client, SLOT(userInput(BufferId, QString)));
-    connect(b, SIGNAL(bufferUpdated(Buffer *)), client, SIGNAL(bufferUpdated(Buffer *)));
-    connect(b, SIGNAL(bufferDestroyed(Buffer *)), client, SIGNAL(bufferDestroyed(Buffer *)));
-    connect(b, SIGNAL(bufferDestroyed(Buffer *)), client, SLOT(removeBuffer(Buffer *)));
-    buffers[id] = b;
-    emit client->bufferUpdated(b);
+  
+  Q_ASSERT(networkInfo(networkid));
+  if(!networkInfo(networkid)->initialized()) {
+    qDebug() << "Network" << networkid << "disconnected while not yet initialized!";
+    updateCoreConnectionProgress();
   }
-  return buffers[id];
 }
 
-QList<BufferId> Client::allBufferIds() {
-  return buffers.keys();
+void Client::updateBufferInfo(BufferInfo id) {
+  buffer(id)->updateBufferInfo(id);
 }
 
+
 void Client::removeBuffer(Buffer *b) {
-  buffers.remove(b->bufferId());
-  bufferIds.remove(b->bufferId().uid());
-}
-
-void Client::recvNetworkState(QString net, QVariant state) {
-  netsAwaitingInit.removeAll(net);
-  netConnected[net] = true;
-  setOwnNick(net, state.toMap()["OwnNick"].toString());
-  buffer(statusBufferId(net))->setActive(true);
-  QVariantMap t = state.toMap()["Topics"].toMap();
-  QVariantMap n = state.toMap()["Nicks"].toMap();
-  foreach(QVariant v, t.keys()) {
-    QString buf = v.toString();
-    BufferId id = bufferId(net, buf);
-    buffer(id)->setActive(true);
-    setTopic(net, buf, t[buf].toString());
-  }
-  foreach(QString nick, n.keys()) {
-    addNick(net, nick, n[nick].toMap());
-  }
-  emit coreConnectionProgress(netConnected.count(), netConnected.count() + netsAwaitingInit.count());
-  if(!netsAwaitingInit.count()) emit connected();
+  _buffers.remove(b->bufferInfo().uid());
 }
 
 void Client::recvMessage(const Message &msg) {
@@ -385,10 +477,9 @@ void Client::recvMessage(const Message &msg) {
 
 void Client::recvStatusMsg(QString /*net*/, QString /*msg*/) {
   //recvMessage(net, Message::server("", QString("[STATUS] %1").arg(msg)));
-
 }
 
-void Client::recvBacklogData(BufferId id, QVariantList msgs, bool /*done*/) {
+void Client::recvBacklogData(BufferInfo id, QVariantList msgs, bool /*done*/) {
   Buffer *b = buffer(id);
   foreach(QVariant v, msgs) {
     Message msg = v.value<Message>();
@@ -401,79 +492,19 @@ void Client::recvBacklogData(BufferId id, QVariantList msgs, bool /*done*/) {
 void Client::layoutMsg() {
   if(layoutQueue.count()) {
     Buffer *b = layoutQueue.takeFirst();  // TODO make this the current buffer
-    if(b->layoutMsg()) layoutQueue.append(b);  // Buffer has more messages in its queue --> Round Robin
+    if(b->layoutMsg())
+      layoutQueue.append(b);  // Buffer has more messages in its queue --> Round Robin
   }
-  if(!layoutQueue.count()) layoutTimer->stop();
+  
+  if(!layoutQueue.count())
+    layoutTimer->stop();
 }
 
 AbstractUiMsg *Client::layoutMsg(const Message &msg) {
   return instance()->mainUi->layoutMsg(msg);
 }
 
-void Client::userInput(BufferId id, QString msg) {
+void Client::userInput(BufferInfo id, QString msg) {
   emit sendInput(id, msg);
 }
 
-void Client::setTopic(QString net, QString buf, QString topic) {
-  BufferId id = bufferId(net, buf);
-  if(!netConnected[id.network()]) return;
-  Buffer *b = buffer(id);
-  b->setTopic(topic);
-  //if(!b->isActive()) {
-  //  b->setActive(true);
-  //  buffersUpdated();
-  //}
-}
-
-void Client::addNick(QString net, QString nick, QVariantMap props) {
-  if(!netConnected[net]) return;
-  nicks[net][nick] = props;
-  QVariantMap chans = props["Channels"].toMap();
-  QStringList c = chans.keys();
-  foreach(QString bufname, c) {
-    buffer(bufferId(net, bufname))->addNick(nick, props);
-  }
-}
-
-void Client::renameNick(QString net, QString oldnick, QString newnick) {
-  if(!netConnected[net]) return;
-  QStringList chans = nicks[net][oldnick]["Channels"].toMap().keys();
-  foreach(QString c, chans) {
-    buffer(bufferId(net, c))->renameNick(oldnick, newnick);
-  }
-  nicks[net][newnick] = nicks[net].take(oldnick);
-}
-
-void Client::updateNick(QString net, QString nick, QVariantMap props) {
-  if(!netConnected[net]) return;
-  QStringList oldchans = nicks[net][nick]["Channels"].toMap().keys();
-  QStringList newchans = props["Channels"].toMap().keys();
-  foreach(QString c, newchans) {
-    if(oldchans.contains(c)) buffer(bufferId(net, c))->updateNick(nick, props);
-    else buffer(bufferId(net, c))->addNick(nick, props);
-  }
-  foreach(QString c, oldchans) {
-    if(!newchans.contains(c)) buffer(bufferId(net, c))->removeNick(nick);
-  }
-  nicks[net][nick] = props;
-}
-
-void Client::removeNick(QString net, QString nick) {
-  if(!netConnected[net]) return;
-  QVariantMap chans = nicks[net][nick]["Channels"].toMap();
-  foreach(QString bufname, chans.keys()) {
-    buffer(bufferId(net, bufname))->removeNick(nick);
-  }
-  nicks[net].remove(nick);
-}
-
-void Client::setOwnNick(QString net, QString nick) {
-  if(!netConnected[net]) return;
-  ownNick[net] = nick;
-  foreach(BufferId id, buffers.keys()) {
-    if(id.network() == net) {
-      buffers[id]->setOwnNick(nick);
-    }
-  }
-}
-
index 2496c66..8a824c3 100644 (file)
 #include <QList>
 #include <QPointer>
 
-#include "buffer.h"
-#include "message.h"
+#include "buffer.h" // needed for activity lvl
+class BufferInfo;
+class Message;
+
+class NetworkInfo;
 
 
 class AbstractUi;
+class AbstractUiMsg;
 class BufferTreeModel;
-class QtGui;
 class SignalProxy;
 
 class QTimer;
 
+
 class Client : public QObject {
   Q_OBJECT
 
-  public:
-    static Client *instance();
-    static void init(AbstractUi *);
-    static void destroy();
-
-    static QList<BufferId> allBufferIds();
-    static Buffer *buffer(BufferId);
-    static BufferId statusBufferId(QString net);
-    static BufferId bufferId(QString net, QString buf);
-
-    static BufferTreeModel *bufferModel();
-    static SignalProxy *signalProxy();
-
-    static AbstractUiMsg *layoutMsg(const Message &);
-
-    static bool isConnected();
-
-    static void storeSessionData(const QString &key, const QVariant &data);
-    static QVariant retrieveSessionData(const QString &key, const QVariant &def = QVariant());
-    static QStringList sessionDataKeys();
-
-    enum ClientMode { LocalCore, RemoteCore };
-    static ClientMode clientMode;
-
-  signals:
-    void sendInput(BufferId, QString message);
-    void showBuffer(Buffer *);
-    void bufferSelected(Buffer *);
-    void bufferUpdated(Buffer *);
-    void bufferActivity(Buffer::ActivityLevel, Buffer *);
-    void bufferDestroyed(Buffer *);
-    void backlogReceived(Buffer *, QList<Message>);
-    void requestBacklog(BufferId, QVariant, QVariant);
-    void requestNetworkStates();
-
-    void recvPartialItem(uint avail, uint size);
-    void coreConnectionError(QString errorMsg);
-    void coreConnectionMsg(const QString &msg);
-    void coreConnectionProgress(uint part, uint total);
-
-    void connected();
-    void disconnected();
-
-    void sessionDataChanged(const QString &key);
-    void sessionDataChanged(const QString &key, const QVariant &data);
-    void sendSessionData(const QString &key, const QVariant &data);
-
-  public slots:
-    //void selectBuffer(Buffer *);
-    //void connectToLocalCore();
-    void connectToCore(const QVariantMap &);
-    void disconnectFromCore();
-
-  private slots:
-    void recvCoreState(const QVariant &state);
-    void recvSessionData(const QString &key, const QVariant &data);
-
-    void coreSocketError(QAbstractSocket::SocketError);
-    void coreHasData();
-    void coreSocketConnected();
-    void coreSocketDisconnected();
-    void coreSocketStateChanged(QAbstractSocket::SocketState);
-
-    void userInput(BufferId, QString);
-    void networkConnected(QString);
-    void networkDisconnected(QString);
-    void recvNetworkState(QString, QVariant);
-    void recvMessage(const Message &message);
-    void recvStatusMsg(QString network, QString message);
-    void setTopic(QString net, QString buf, QString);
-    void addNick(QString net, QString nick, QVariantMap props);
-    void removeNick(QString net, QString nick);
-    void renameNick(QString net, QString oldnick, QString newnick);
-    void updateNick(QString net, QString nick, QVariantMap props);
-    void setOwnNick(QString net, QString nick);
-    void recvBacklogData(BufferId, QVariantList, bool);
-    void updateBufferId(BufferId);
-
-    void removeBuffer(Buffer *);
-
-    void layoutMsg();
-
-  private:
-    Client();
-    ~Client();
-    void init();
-    static Client *instanceptr;
-
-    void syncToCore(const QVariant &coreState);
-    QVariant connectToLocalCore(QString user, QString passwd);  // defined in main.cpp
-    void disconnectFromLocalCore();                             // defined in main.cpp
-
-    AbstractUi *mainUi;
-    SignalProxy *_signalProxy;
-    BufferTreeModel *_bufferModel;
-
-    QPointer<QIODevice> socket;
-    quint32 blockSize;
-
-    static bool connectedToCore;
-    static QVariantMap coreConnectionInfo;
-    static QHash<BufferId, Buffer *> buffers;
-    static QHash<uint, BufferId> bufferIds;
-    static QHash<QString, QHash<QString, QVariantMap> > nicks;
-    static QHash<QString, bool> netConnected;
-    static QStringList netsAwaitingInit;
-    static QHash<QString, QString> ownNick;
-
-    QTimer *layoutTimer;
-    QList<Buffer *> layoutQueue;
-
-    QVariantMap sessionData;
+public:
+  static Client *instance();
+  static void destroy();
+  static void init(AbstractUi *);
+
+  static QList<NetworkInfo *> networkInfos();
+  static NetworkInfo *networkInfo(uint networkid);
+  
+  static QList<BufferInfo> allBufferInfos();
+  static QList<Buffer *> buffers();
+  static Buffer *buffer(uint bufferUid);
+  static Buffer *buffer(BufferInfo);
+  static BufferInfo statusBufferInfo(QString net);
+  static BufferInfo bufferInfo(QString net, QString buf);
+
+  static BufferTreeModel *bufferModel();
+  static SignalProxy *signalProxy();
+
+  static AbstractUiMsg *layoutMsg(const Message &);
+
+  static bool isConnected();
+
+  static void storeSessionData(const QString &key, const QVariant &data);
+  static QVariant retrieveSessionData(const QString &key, const QVariant &def = QVariant());
+  static QStringList sessionDataKeys();
+
+  enum ClientMode { LocalCore, RemoteCore };
+
+signals:
+  void sendInput(BufferInfo, QString message);
+  void showBuffer(Buffer *);
+  void bufferSelected(Buffer *);
+  void bufferUpdated(Buffer *);
+  void bufferActivity(Buffer::ActivityLevel, Buffer *);
+  void bufferDestroyed(Buffer *);
+  void backlogReceived(Buffer *, QList<Message>);
+  void requestBacklog(BufferInfo, QVariant, QVariant);
+  void requestNetworkStates();
+
+  void recvPartialItem(uint avail, uint size);
+  void coreConnectionError(QString errorMsg);
+  void coreConnectionMsg(const QString &msg);
+  void coreConnectionProgress(uint part, uint total);
+
+  void connected();
+  void disconnected();
+
+  void sessionDataChanged(const QString &key);
+  void sessionDataChanged(const QString &key, const QVariant &data);
+  void sendSessionData(const QString &key, const QVariant &data);
+
+public slots:
+  //void selectBuffer(Buffer *);
+  //void connectToLocalCore();
+  void connectToCore(const QVariantMap &);
+  void disconnectFromCore();
+
+private slots:
+  void recvCoreState(const QVariant &state);
+  void recvSessionData(const QString &key, const QVariant &data);
+
+  void coreSocketError(QAbstractSocket::SocketError);
+  void coreHasData();
+  void coreSocketConnected();
+  void coreSocketDisconnected();
+  void coreSocketStateChanged(QAbstractSocket::SocketState);
+
+  void userInput(BufferInfo, QString);
+
+  void networkConnected(uint);
+  void networkDisconnected(uint);
+
+  void updateCoreConnectionProgress();
+  void recvMessage(const Message &message);
+  void recvStatusMsg(QString network, QString message);
+  void recvBacklogData(BufferInfo, QVariantList, bool);
+  void updateBufferInfo(BufferInfo);
+
+  void removeBuffer(Buffer *);
+
+  void layoutMsg();
+
+private:
+  Client(QObject *parent = 0);
+  virtual ~Client();
+  void init();
+  
+  void syncToCore(const QVariant &coreState);
+  QVariant connectToLocalCore(QString user, QString passwd);  // defined in main.cpp
+  void disconnectFromLocalCore();                             // defined in main.cpp
+
+  static QPointer<Client> instanceptr;
+  
+  QPointer<QIODevice> socket;
+  QPointer<SignalProxy> _signalProxy;
+  QPointer<AbstractUi> mainUi;
+  QPointer<BufferTreeModel> _bufferModel;
+
+  ClientMode clientMode;
+
+  quint32 blockSize;
+  bool connectedToCore;
+  
+  QVariantMap coreConnectionInfo;
+  QHash<uint, Buffer *> _buffers;
+  QHash<uint, NetworkInfo*> _networkInfo;
+
+  QTimer *layoutTimer;
+  QList<Buffer *> layoutQueue;
+
+  QVariantMap sessionData;
+
+
 };
 
 #endif
index 414d599..327c37f 100644 (file)
@@ -31,7 +31,7 @@ class AbstractUiMsg {
     virtual QString sender() const = 0;
     virtual QString text() const = 0;
     virtual MsgId msgId() const = 0;
-    virtual BufferId bufferId() const = 0;
+    virtual BufferInfo bufferInfo() const = 0;
     virtual QDateTime timeStamp() const = 0;
 
 };
index 26e087a..b03ef45 100644 (file)
@@ -1,6 +1,6 @@
-SET(common_SRCS global.cpp logger.cpp message.cpp settings.cpp signalproxy.cpp util.cpp ircuser.cpp)
+SET(common_SRCS global.cpp logger.cpp message.cpp settings.cpp signalproxy.cpp util.cpp synchronizer.cpp networkinfo.cpp ircuser.cpp ircchannel.cpp)
 SET(common_HDRS global.h message.h util.h)
-SET(common_MOCS logger.h ircuser.h settings.h signalproxy.h)
+SET(common_MOCS logger.h synchronizer.h networkinfo.h ircuser.h ircchannel.h settings.h signalproxy.h)
 
 QT4_WRAP_CPP(_MOC ${common_MOCS})
 ADD_LIBRARY(common ${common_SRCS} ${_MOC})
diff --git a/src/common/bufferinfo.cpp b/src/common/bufferinfo.cpp
new file mode 100644 (file)
index 0000000..c7cdd73
--- /dev/null
@@ -0,0 +1,68 @@
+/***************************************************************************
+ *   Copyright (C) 2005-07 by The Quassel IRC Development Team             *
+ *   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) any later version.                                   *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program; if not, write to the                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
+ ***************************************************************************/
+
+#include <QString>
+#include <QDataStream>
+#include <QByteArray>
+
+#include "bufferinfo.h"
+
+#include "util.h"
+
+BufferInfo::BufferInfo()
+  : _id(0),
+    _netid(0),
+    _gid(0),
+    _networkName(QString()),
+    _bufferName(QString()) {
+}
+
+BufferInfo::BufferInfo(uint id, uint networkid, uint gid, QString net, QString buf)
+  : _id(id),
+    _netid(networkid),
+    _gid(gid),
+    _networkName(net),
+    _bufferName(buf) {
+}
+
+QString BufferInfo::buffer() const {
+  if(isChannelName(_bufferName))
+    return _bufferName;
+  else
+    return nickFromMask(_bufferName);
+}
+
+QDataStream &operator<<(QDataStream &out, const BufferInfo &bufferInfo) {
+  out << bufferInfo._id << bufferInfo._netid << bufferInfo._gid << bufferInfo._networkName.toUtf8() << bufferInfo._bufferName.toUtf8();
+  return out;
+}
+
+QDataStream &operator>>(QDataStream &in, BufferInfo &bufferInfo) {
+  QByteArray n, b;
+  in >> bufferInfo._id >> bufferInfo._netid >> bufferInfo._gid >> n >> b;
+  bufferInfo._networkName = QString::fromUtf8(n);
+  bufferInfo._bufferName = QString::fromUtf8(b);
+  return in;
+}
+
+uint qHash(const BufferInfo &bufferid) {
+  return qHash(bufferid._id);
+}
+
diff --git a/src/common/bufferinfo.h b/src/common/bufferinfo.h
new file mode 100644 (file)
index 0000000..b743054
--- /dev/null
@@ -0,0 +1,62 @@
+/***************************************************************************
+ *   Copyright (C) 2005-07 by The Quassel IRC Development Team             *
+ *   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) any later version.                                   *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program; if not, write to the                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
+ ***************************************************************************/
+#ifndef _BUFFERINFO_H_
+#define _BUFFERINFO_H_
+
+#include <QtCore>
+
+class QString;
+class QDataStream;
+
+class BufferInfo {
+public:
+  BufferInfo();
+  BufferInfo(uint id, uint networkid, uint gid = 0, QString net = QString(), QString buf = QString());
+  
+  inline uint uid() const { return _id; }
+  inline uint networkId() const { return _netid; }
+  inline uint groupId() const { return _gid; }
+  inline QString network() const { return _networkName; }
+  QString buffer() const;
+  
+  void setGroupId(uint gid) { _gid = gid; }
+  
+  inline bool operator==(const BufferInfo &other) const { return _id == other._id; }
+
+private:
+  uint _id;
+  uint _netid;
+  uint _gid;
+  QString _networkName; // WILL BE REMOVED
+  QString _bufferName;
+  
+  friend uint qHash(const BufferInfo &);
+  friend QDataStream &operator<<(QDataStream &out, const BufferInfo &bufferInfo);
+  friend QDataStream &operator>>(QDataStream &in, BufferInfo &bufferInfo);
+};
+
+QDataStream &operator<<(QDataStream &out, const BufferInfo &bufferInfo);
+QDataStream &operator>>(QDataStream &in, BufferInfo &bufferInfo);
+
+Q_DECLARE_METATYPE(BufferInfo);
+
+uint qHash(const BufferInfo &);
+
+#endif
index c218ee9..0df5568 100644 (file)
@@ -1,4 +1,4 @@
 DEPMOD = contrib/qxt
 QT_MOD = network
-SRCS += global.cpp ircuser.cpp logger.cpp message.cpp settings.cpp signalproxy.cpp util.cpp
-HDRS += global.h ircuser.h logger.h message.h settings.h signalproxy.h util.h
+SRCS += global.cpp logger.cpp message.cpp settings.cpp signalproxy.cpp util.cpp synchronizer.cpp networkinfo.cpp ircuser.cpp ircchannel.cpp bufferinfo.cpp
+HDRS += global.h logger.h message.h settings.h signalproxy.h util.h synchronizer.h networkinfo.h ircuser.h ircchannel.h bufferinfo.h
index ed2d1df..cdb3376 100644 (file)
@@ -46,47 +46,6 @@ void Global::initIconMap() {
 }
 */
 
-/**************************************************************************************/
-BufferId::BufferId()
-  : _id(0),
-    _netid(0),
-    _gid(0),
-    _networkName(QString()),
-    _bufferName(QString()) {
-}
-
-BufferId::BufferId(uint id, uint networkid, uint gid, QString net, QString buf)
-  : _id(id),
-    _netid(networkid),
-    _gid(gid),
-    _networkName(net),
-    _bufferName(buf) {
-}
-
-QString BufferId::buffer() const {
-  if(isChannelName(_bufferName))
-    return _bufferName;
-  else
-    return nickFromMask(_bufferName);
-}
-
-QDataStream &operator<<(QDataStream &out, const BufferId &bufferId) {
-  out << bufferId._id << bufferId._netid << bufferId._gid << bufferId._networkName.toUtf8() << bufferId._bufferName.toUtf8();
-  return out;
-}
-
-QDataStream &operator>>(QDataStream &in, BufferId &bufferId) {
-  QByteArray n, b;
-  in >> bufferId._id >> bufferId._netid >> bufferId._gid >> n >> b;
-  bufferId._networkName = QString::fromUtf8(n);
-  bufferId._bufferName = QString::fromUtf8(b);
-  return in;
-}
-
-uint qHash(const BufferId &bufferid) {
-  return qHash(bufferid._id);
-}
-
 /**
  * Retrieves an icon determined by its symbolic name. The mapping shall later
  * be performed by a theme manager or something like that.
index 1d1d375..fd285ca 100644 (file)
@@ -55,38 +55,4 @@ struct Exception {
 
 };
 
-class BufferId {
-public:
-  BufferId();
-  BufferId(uint _id, uint _networkid, uint _gid = 0, QString _net = QString(), QString _buf = QString());
-  
-  inline uint uid() const { return _id; }
-  inline uint networkId() const { return _netid; }
-  inline uint groupId() const { return _gid; }
-  inline QString network() const { return _networkName; }
-  QString buffer() const;
-  
-  void setGroupId(uint gid) { _gid = gid; }
-  
-  inline bool operator==(const BufferId &other) const { return _id == other._id; }
-
-private:
-  uint _id;
-  uint _netid;
-  uint _gid;
-  QString _networkName; // WILL BE REMOVED
-  QString _bufferName; // IS this actually needed?
-  
-  friend uint qHash(const BufferId &);
-  friend QDataStream &operator<<(QDataStream &out, const BufferId &bufferId);
-  friend QDataStream &operator>>(QDataStream &in, BufferId &bufferId);
-};
-
-QDataStream &operator<<(QDataStream &out, const BufferId &bufferId);
-QDataStream &operator>>(QDataStream &in, BufferId &bufferId);
-
-Q_DECLARE_METATYPE(BufferId);
-
-uint qHash(const BufferId &);
-
 #endif
diff --git a/src/common/ircchannel.cpp b/src/common/ircchannel.cpp
new file mode 100644 (file)
index 0000000..95d0ed1
--- /dev/null
@@ -0,0 +1,202 @@
+/***************************************************************************
+ *   Copyright (C) 2005-07 by The Quassel Team                             *
+ *   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) any later version.                                   *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program; if not, write to the                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
+ ***************************************************************************/
+
+#include "ircchannel.h"
+
+#include "networkinfo.h"
+#include "signalproxy.h"
+#include "ircuser.h"
+
+#include <QMapIterator>
+#include <QHashIterator>
+
+#include <QDebug>
+
+
+IrcChannel::IrcChannel(const QString &channelname, NetworkInfo *networkinfo) 
+  : QObject(networkinfo),
+    _initialized(false),
+    _name(channelname),
+    _topic(QString()),
+    networkInfo(networkinfo)
+{
+  setObjectName(QString::number(networkInfo->networkId()) + "/" +  channelname);
+}
+
+// ====================
+//  PUBLIC:
+// ====================
+bool IrcChannel::isKnownUser(IrcUser *ircuser) const {
+  bool isknown = true;
+
+  if(ircuser == 0) {
+    qWarning() << "Channel" << name() << "received IrcUser Nullpointer!";
+    isknown = false;
+  }
+  
+  if(!_userModes.contains(ircuser) && ircuser) {
+    qWarning() << "Channel" << name() << "received data for unknown User" << ircuser->nick();
+    isknown = false;
+  }
+  
+  return isknown;
+}
+
+bool IrcChannel::isValidChannelUserMode(const QString &mode) const {
+  bool isvalid = true;
+  if(mode.size() > 1) {
+    qWarning() << "Channel" << name() << "received Channel User Mode which is longer then 1 Char:" << mode;
+    isvalid = false;
+  }
+  return isvalid;
+}
+
+bool IrcChannel::initialized() const {
+  return _initialized;
+}
+
+QString IrcChannel::name() const {
+  return _name;
+}
+
+QString IrcChannel::topic() const {
+  return _topic;
+}
+
+QList<IrcUser *> IrcChannel::ircUsers() const {
+  return _userModes.keys();
+}
+
+QString IrcChannel::userMode(IrcUser *ircuser) const {
+  if(_userModes.contains(ircuser))
+    return _userModes[ircuser];
+  else
+    return QString();
+}
+
+QString IrcChannel::userMode(const QString &nick) const {
+  return userMode(networkInfo->ircUser(nick));
+}
+
+// ====================
+//  PUBLIC SLOTS:
+// ====================
+void IrcChannel::setTopic(const QString &topic) {
+  _topic = topic;
+  emit topicSet(topic);
+}
+
+void IrcChannel::join(IrcUser *ircuser) {
+  if(!_userModes.contains(ircuser) && ircuser) {
+    _userModes[ircuser] = QString();
+    ircuser->joinChannel(name());
+    // no emit here since the join is propagated by IrcUser
+  }
+}
+
+void IrcChannel::join(const QString &nick) {
+  join(networkInfo->ircUser(nick));
+}
+
+void IrcChannel::part(IrcUser *ircuser) {
+  if(isKnownUser(ircuser)) {
+    _userModes.remove(ircuser);
+    ircuser->partChannel(name());
+    // no emit here since the part is propagated by IrcUser
+  }
+}
+
+void IrcChannel::part(const QString &nick) {
+  part(networkInfo->ircUser(nick));
+}
+
+// SET USER MODE
+void IrcChannel::setUserModes(IrcUser *ircuser, const QString &modes) {
+  if(isKnownUser(ircuser)) {
+    _userModes[ircuser] = modes;
+    emit userModesSet(ircuser->nick(), modes);
+  }
+}
+
+void IrcChannel::setUserModes(const QString &nick, const QString &modes) {
+  setUserModes(networkInfo->ircUser(nick), modes);
+}
+
+// ADD USER MODE
+void IrcChannel::addUserMode(IrcUser *ircuser, const QString &mode) {
+  if(!isKnownUser(ircuser) || !isValidChannelUserMode(mode))
+    return;
+  
+  if(!_userModes[ircuser].contains(mode)) {
+    _userModes[ircuser] += mode;
+    emit userModeAdded(ircuser->nick(), mode);
+  }
+
+}
+
+void IrcChannel::addUserMode(const QString &nick, const QString &mode) {
+  addUserMode(networkInfo->ircUser(nick), mode);
+}
+
+
+// REMOVE USER MODE
+void IrcChannel::removeUserMode(IrcUser *ircuser, const QString &mode) {
+  if(!isKnownUser(ircuser) || !isValidChannelUserMode(mode))
+    return;
+
+  if(_userModes[ircuser].contains(mode)) {
+    _userModes[ircuser].remove(mode);
+    emit userModeRemoved(ircuser->nick(), mode);
+  }
+
+}
+
+void IrcChannel::removeUserMode(const QString &nick, const QString &mode) {
+  removeUserMode(networkInfo->ircUser(nick), mode);
+}
+
+// INIT SET USER MODES
+QVariantMap IrcChannel::initUserModes() const {
+  QVariantMap usermodes;
+  QHashIterator<IrcUser *, QString> iter(_userModes);
+  while(iter.hasNext()) {
+    iter.next();
+    usermodes[iter.key()->nick()] = iter.value();
+  }
+  return usermodes;
+}
+
+void IrcChannel::initSetUserModes(const QVariantMap &usermodes) {
+  QMapIterator<QString, QVariant> iter(usermodes);
+  while(iter.hasNext()) {
+    iter.next();
+    setUserModes(iter.key(), iter.value().toString());
+  }
+}
+
+void IrcChannel::ircUserDestroyed() {
+  part(qobject_cast<IrcUser *>(sender()));
+}
+
+void IrcChannel::setInitialized() {
+  _initialized = true;
+  emit initDone();
+}
+
diff --git a/src/common/ircchannel.h b/src/common/ircchannel.h
new file mode 100644 (file)
index 0000000..2b43876
--- /dev/null
@@ -0,0 +1,102 @@
+/***************************************************************************
+ *   Copyright (C) 2005/06 by The Quassel Team                             *
+ *   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) any later version.                                   *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program; if not, write to the                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
+ ***************************************************************************/
+
+#ifndef _IRCCHANNEL_H_
+#define _IRCCHANNEL_H_
+
+#include <QHash>
+#include <QString>
+#include <QStringList>
+#include <QVariantMap>
+
+class SignalProxy;
+class NetworkInfo;
+class IrcUser;
+
+class IrcChannel : public QObject {
+  Q_OBJECT
+  
+  Q_PROPERTY(QString name READ name STORED false)
+  Q_PROPERTY(QString topic READ topic WRITE setTopic STORED false)
+
+public:
+  IrcChannel(const QString &channelname, NetworkInfo *networkInfo);
+
+  bool isKnownUser(IrcUser *ircuser) const;
+  bool isValidChannelUserMode(const QString &mode) const;
+
+  bool initialized() const;
+
+  QString name() const;
+  QString topic() const;
+  
+  QList<IrcUser *> ircUsers() const;
+  
+  QString userMode(IrcUser *ircuser) const;
+  QString userMode(const QString &nick) const;
+
+
+public slots:  
+  void setTopic(const QString &topic);
+
+  void join(IrcUser *ircuser);
+  void join(const QString &nick);
+
+  void part(IrcUser *ircuser);
+  void part(const QString &nick);
+
+  void setUserModes(IrcUser *ircuser, const QString &modes);
+  void setUserModes(const QString &nick, const QString &modes);
+  
+  void addUserMode(IrcUser *ircuser, const QString &mode);
+  void addUserMode(const QString &nick, const QString &mode);
+  
+  void removeUserMode(IrcUser *ircuser, const QString &mode);
+  void removeUserMode(const QString &nick, const QString &mode);
+
+  // init geters
+  QVariantMap initUserModes() const;
+
+  // init seters
+  void initSetUserModes(const QVariantMap &usermodes);
+  
+  void ircUserDestroyed();
+  
+  void setInitialized();
+
+signals:
+  void topicSet(QString topic);
+  void userModesSet(QString nick, QString modes);
+  void userModeAdded(QString nick, QString mode);
+  void userModeRemoved(QString nick, QString mode);
+
+  void initDone();
+  
+private:
+  bool _initialized;
+  QString _name;
+  QString _topic;
+
+  QHash<IrcUser *, QString> _userModes; 
+  
+  NetworkInfo *networkInfo;
+};
+
+#endif
index be5f49a..665b10f 100644 (file)
 #include "ircuser.h"
 #include "util.h"
 
-IrcUser::IrcUser(QObject *parent)
-  : QObject(parent) {
+#include "networkinfo.h"
+#include "signalproxy.h"
+#include "ircchannel.h"
+
+#include <QDebug>
+
+IrcUser::IrcUser(const QString &hostmask, NetworkInfo *networkinfo)
+  : QObject(networkinfo),
+    _initialized(false),
+    _nick(nickFromMask(hostmask)),
+    _user(userFromMask(hostmask)),
+    _host(hostFromMask(hostmask)),
+    networkInfo(networkinfo)
+{
+  setObjectName(QString::number(networkInfo->networkId()) + "/" + IrcUser::hostmask());
 }
 
-IrcUser::IrcUser(const QString &hostmask, QObject *parent) 
-  : QObject(parent),
-    nick_(nickFromMask(hostmask)),
-    user_(userFromMask(hostmask)),
-    host_(hostFromMask(hostmask)) {
+// ====================
+//  PUBLIC:
+// ====================
+bool IrcUser::initialized() const {
+  return _initialized;
 }
 
-IrcUser::~IrcUser() {
+QString IrcUser::user() const {
+  return _user;
 }
 
-void IrcUser::setUser(const QString &user) {
-  user_ = user;
+QString IrcUser::host() const {
+  return _host;
 }
 
-QString IrcUser::user() const {
-  return user_;
+QString IrcUser::nick() const {
+  return _nick;
 }
 
-void IrcUser::setHost(const QString &host) {
-  host_ = host;
+QString IrcUser::hostmask() const {
+  return QString("%1!%2@%3").arg(nick()).arg(user()).arg(host());
 }
 
-QString IrcUser::host() const {
-  return host_;
+QString IrcUser::userModes() const {
+  return _userModes;
 }
 
-void IrcUser::setNick(const QString &nick) {
-  nick_ = nick;
+QStringList IrcUser::channels() const {
+  return _channels.toList();
 }
 
-QString IrcUser::nick() const {
-  return nick_;
+void IrcUser::updateObjectName() {
+  setObjectName(QString::number(networkInfo->networkId()) + "/" +  hostmask());
+  emit objectNameSet();
+}
+
+// ====================
+//  PUBLIC SLOTS:
+// ====================
+void IrcUser::setUser(const QString &user) {
+  if(!user.isEmpty() && _user != user) {
+    _user = user;
+    emit userSet(user);
+
+    setObjectName(hostmask());
+    emit objectNameSet();
+  }
 }
 
-void IrcUser::setUsermodes(const QSet<QString> &usermodes) {
-  usermodes_ = usermodes;
+void IrcUser::setHost(const QString &host) {
+  if(!host.isEmpty() && _host != host) {
+    _host = host;
+    emit hostSet(host);
+    updateObjectName();
+  }
 }
 
-QSet<QString> IrcUser::usermodes() const {
-  return usermodes_;
+void IrcUser::setNick(const QString &nick) {
+  if(!nick.isEmpty() && nick != _nick) {
+    QString oldnick(_nick);
+    _nick = nick;
+    emit nickSet(nick);
+    updateObjectName();
+  }
 }
 
-void IrcUser::setChannelmode(const QString &channel, const QSet<QString> &channelmode) {
-  if(channelmodes_.contains(channel))
-    channelmodes_[channel] |= channelmode;
-  else
-    channelmodes_[channel] = channelmode;
+void IrcUser::updateHostmask(const QString &mask) {
+  if(mask == hostmask())
+    return;
+
+  QString user = userFromMask(mask);
+  QString host = hostFromMask(mask);
+
+  // we only need to check user and hostmask.
+  // nick can't have changed since we're identifying IrcUsers by nick
+
+  // we don't use setUser and setHost here.
+  // though this is unpretty code duplication this saves us one emit objectNameSet()
+  // the second one would be erroneous
+  
+  if(!user.isEmpty() && _user != user) {
+    _user = user;
+  }
+
+  if(!host.isEmpty() && _host != host) {
+    _host = host;
+  }
+
+  emit hostmaskUpdated(mask);
+  updateObjectName();
 }
 
-QSet<QString> IrcUser::channelmode(const QString &channel) const {
-  if(channelmodes_.contains(channel))
-    //throw NoSuchChannelException();
-    Q_ASSERT(false); // FIXME: exception disabled for qtopia testing
-  else
-    return QSet<QString>();
+void IrcUser::joinChannel(const QString &channel) {
+  if(!_channels.contains(channel)) {
+    _channels.insert(channel);
+    networkInfo->newIrcChannel(channel)->join(this);
+    emit channelJoined(channel);
+  }
 }
 
-void IrcUser::updateChannelmode(const QString &channel, const QString &channelmode, bool add) {
-  if(add)
-    addChannelmode(channel, channelmode);
-  else
-    removeChannelmode(channel, channelmode);
+void IrcUser::partChannel(const QString &channel) {
+  if(_channels.contains(channel)) {
+    _channels.remove(channel);
+
+    Q_ASSERT(networkInfo->ircChannel(channel));
+    networkInfo->ircChannel(channel)->part(this);
+    
+    emit channelParted(channel);
+  }
 }
 
-void IrcUser::addChannelmode(const QString &channel, const QString &channelmode) {
-  if(!channelmodes_.contains(channel))
-    channelmodes_[channel] = QSet<QString>();
-  channelmodes_[channel] << channelmode;
+void IrcUser::setUserModes(const QString &modes) {
+  _userModes = modes;
+  emit userModesSet(modes);
 }
 
-void IrcUser::removeChannelmode(const QString &channel, const QString &channelmode) {
-  if(channelmodes_.contains(channel))
-    channelmodes_[channel].remove(channelmode);
+void IrcUser::addUserMode(const QString &mode) {
+  if(!_userModes.contains(mode)) {
+    _userModes += mode;
+    emit userModeAdded(mode);
+  }
 }
 
-QStringList IrcUser::channels() const {
-  return channelmodes_.keys();
+void IrcUser::removeUserMode(const QString &mode) {
+  if(_userModes.contains(mode)) {
+    _userModes.remove(mode);
+    emit userModeRemoved(mode);
+  }
 }
 
-void IrcUser::joinChannel(const QString &channel) {
-  if(!channelmodes_.contains(channel))
-    channelmodes_[channel] = QSet<QString>();
+void IrcUser::initSetChannels(const QStringList channels) {
+  foreach(QString channel, channels) {
+    joinChannel(channel);
+  }
 }
 
-void IrcUser::partChannel(const QString &channel) {
-  channelmodes_.remove(channel);
+void IrcUser::setInitialized() {
+  _initialized = true;
+  emit initDone();
 }
+
index b6c4b32..4fe3f37 100644 (file)
 #ifndef _IRCUSER_H_
 #define _IRCUSER_H_
 
-#include <QtCore>
-#include <QObject>
-#include <QHash>
 #include <QSet>
 #include <QString>
 #include <QStringList>
+#include <QVariantMap>
 
-#include "global.h"
+class SignalProxy;
+class NetworkInfo;
+class IrcChannel;
 
 class IrcUser : public QObject {
   Q_OBJECT
   
-//  Q_PROPERTY(QString user READ user WRITE setUser)
-//  Q_PROPERTY(QString host READ host WRITE setHost)
-//  Q_PROPERTY(QString nick READ nick WRITE setNick)
-//  Q_PROPERTY(QSet<QString> usermodes READ usermodes WRITE setUsermodes)
-//  Q_PROPERTY(QStringList channels READ channels)
+  Q_PROPERTY(QString user READ user WRITE setUser STORED false)
+  Q_PROPERTY(QString host READ host WRITE setHost STORED false)
+  Q_PROPERTY(QString nick READ nick WRITE setNick STORED false)
+
+  Q_PROPERTY(QStringList channels READ channels STORED false)
+  //  Q_PROPERTY(QStringList usermodes READ usermodes WRITE setUsermodes)
+
   
 public:
-  IrcUser(QObject *parent = 0);
-  IrcUser(const QString &hostmask, QObject *parent = 0);
-  ~IrcUser();
-  
-  void setUser(const QString &user);
+  IrcUser(const QString &hostmask, NetworkInfo *networkInfo);
+
+  bool initialized() const;
+
   QString user() const;
-  
-  void setHost(const QString &host);
   QString host() const;
-  
-  void setNick(const QString &nick);
   QString nick() const;
-  
-  void setUsermodes(const QSet<QString> &usermodes);
-  QSet<QString> usermodes() const;
-  
-  void setChannelmode(const QString &channel, const QSet<QString> &channelmode);
-  QSet<QString> channelmode(const QString &channel) const;
-  
-  void updateChannelmode(const QString &channel, const QString &channelmode, bool add=true);
-  void addChannelmode(const QString &channel, const QString &channelmode);
-  void removeChannelmode(const QString &channel, const QString &channelmode);
+  QString hostmask() const;
+
+  QString userModes() const;
 
   QStringList channels() const;
-  
+    
+  void updateObjectName();
+                        
+public slots:  
+  void setUser(const QString &user);
+  void setHost(const QString &host);
+  void setNick(const QString &nick);
+  void updateHostmask(const QString &mask);
+                                         
+  void setUserModes(const QString &modes);
+
   void joinChannel(const QString &channel);
   void partChannel(const QString &channel);
+
+  void addUserMode(const QString &mode);
+  void removeUserMode(const QString &mode);
+
+  // init seters
+  void initSetChannels(const QStringList channels);
+  
+  void setInitialized();
+
+signals:
+  void userSet(QString user);
+  void hostSet(QString host);
+  void nickSet(QString newnick);
+  void hostmaskUpdated(QString mask);
+  
+  void channelsSet(QStringList channels);
+  void userModesSet(QString modes);
+  
+  void channelJoined(QString channel);
+  void channelParted(QString channel);
+
+  void userModeAdded(QString mode);
+  void userModeRemoved(QString mode);
+
+  void objectNameSet();
   
+//   void setUsermodes(const QSet<QString> &usermodes);
+//   QSet<QString> usermodes() const;
+
+  void initDone();
+
 private:
   inline bool operator==(const IrcUser &ircuser2) {
-    return (nick_.toLower() == ircuser2.nick().toLower());
+    return (_nick.toLower() == ircuser2.nick().toLower());
   }
 
   inline bool operator==(const QString &nickname) {
-    return (nick_.toLower() == nickname.toLower());
+    return (_nick.toLower() == nickname.toLower());
   }
-  
-  QString nick_;
-  QString user_;
-  QString host_;
-  
-  QHash<QString, QSet<QString> > channelmodes_; //keys: channelnames; values: Set of Channelmodes
-  QSet<QString> usermodes_;
-};
 
-struct IrcUserException : public Exception {};
-struct NoSuchChannelException : public IrcUserException {};
-struct NoSuchNickException : public IrcUserException {};
+  bool _initialized;
+
+  QString _nick;
+  QString _user;
+  QString _host;
 
+  QSet<QString> _channels;
+  QString _userModes;
+  
+  NetworkInfo *networkInfo;
+};
 
 #endif
index 897208f..b86f226 100644 (file)
@@ -61,10 +61,10 @@ int main(int argc, char **argv) {
 
   qRegisterMetaType<QVariant>("QVariant");
   qRegisterMetaType<Message>("Message");
-  qRegisterMetaType<BufferId>("BufferId");
+  qRegisterMetaType<BufferInfo>("BufferInfo");
   qRegisterMetaTypeStreamOperators<QVariant>("QVariant");
   qRegisterMetaTypeStreamOperators<Message>("Message");
-  qRegisterMetaTypeStreamOperators<BufferId>("BufferId");
+  qRegisterMetaTypeStreamOperators<BufferInfo>("BufferInfo");
 
 #if defined BUILD_CORE
   Global::runMode = Global::CoreOnly;
index c4c9bf1..797dfbb 100644 (file)
  ***************************************************************************/
 
 #include "message.h"
+
 #include "util.h"
+
 #include <QDataStream>
 
-Message::Message(BufferId __buffer, Type __type, QString __text, QString __sender, quint8 __flags)
+Message::Message(BufferInfo __buffer, Type __type, QString __text, QString __sender, quint8 __flags)
   : _buffer(__buffer), _text(__text), _sender(__sender), _type(__type), _flags(__flags) {
   _timeStamp = QDateTime::currentDateTime().toUTC();
 }
 
-Message::Message(QDateTime __ts, BufferId __buffer, Type __type, QString __text, QString __sender, quint8 __flags)
+Message::Message(QDateTime __ts, BufferInfo __buffer, Type __type, QString __text, QString __sender, quint8 __flags)
   : _timeStamp(__ts), _buffer(__buffer), _text(__text), _sender(__sender), _type(__type), _flags(__flags) {
 
 }
@@ -40,7 +42,7 @@ void Message::setMsgId(MsgId _id) {
   _msgId = _id;
 }
 
-BufferId Message::buffer() const {
+BufferInfo Message::buffer() const {
   return _buffer;
 }
 
@@ -161,7 +163,7 @@ QDataStream &operator>>(QDataStream &in, Message &msg) {
   quint8 t, f;
   quint32 ts;
   QByteArray s, m;
-  BufferId buf;
+  BufferInfo buf;
   in >> ts >> t >> f >> buf >> s >> m;
   msg._type = (Message::Type)t;
   msg._flags = (quint8)f;
index 05d402e..878acfa 100644 (file)
@@ -25,6 +25,7 @@
 #include <QString>
 #include <QDateTime>
 
+#include "bufferinfo.h"
 #include "global.h"
 
 class Message {
@@ -35,14 +36,14 @@ class Message {
     enum Type { Plain, Notice, Action, Nick, Mode, Join, Part, Quit, Kick, Kill, Server, Info, Error };
     enum Flags { None = 0, Self = 1, PrivMsg = 2, Highlight = 4 };
 
-    Message(BufferId buffer = BufferId(), Type type = Plain, QString text = "", QString sender = "", quint8 flags = None);
+    Message(BufferInfo buffer = BufferInfo(), Type type = Plain, QString text = "", QString sender = "", quint8 flags = None);
 
-    Message(QDateTime ts, BufferId buffer = BufferId(), Type type = Plain, QString text = "", QString sender = "", quint8 flags = None);
+    Message(QDateTime ts, BufferInfo buffer = BufferInfo(), Type type = Plain, QString text = "", QString sender = "", quint8 flags = None);
 
     MsgId msgId() const;
     void setMsgId(MsgId id);
 
-    BufferId buffer() const;
+    BufferInfo buffer() const;
     QString text() const;
     QString sender() const;
     Type type() const;
@@ -58,7 +59,7 @@ class Message {
   private:
     QDateTime _timeStamp;
     MsgId _msgId;
-    BufferId _buffer;
+    BufferInfo _buffer;
     QString _text;
     QString _sender;
     Type _type;
diff --git a/src/common/networkinfo.cpp b/src/common/networkinfo.cpp
new file mode 100644 (file)
index 0000000..114287a
--- /dev/null
@@ -0,0 +1,376 @@
+/***************************************************************************
+ *   Copyright (C) 2005-07 by The Quassel Team                             *
+ *   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) any later version.                                   *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program; if not, write to the                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
+ ***************************************************************************/
+#include "networkinfo.h"
+
+#include "signalproxy.h"
+#include "synchronizer.h"
+#include "ircuser.h"
+#include "ircchannel.h"
+
+#include <QDebug>
+
+#include "util.h"
+
+// ====================
+//  Public:
+// ====================
+NetworkInfo::NetworkInfo(const uint &networkid, SignalProxy *proxy, QObject *parent)
+  : QObject(parent),
+    _networkId(networkid),
+    _initialized(false),
+    _myNick(QString()),
+    _networkName(QString()),
+    _currentServer(QString()),
+    _prefixes(QString()),
+    _prefixModes(QString())
+{
+  setObjectName(QString::number(networkid));
+  _synchronizer = new Synchronizer(this, proxy);
+}
+
+// I think this is unnecessary since IrcUsers have us as their daddy :)
+// NetworkInfo::~NetworkInfo() {
+//   QHashIterator<QString, IrcUser *> ircuser(_ircUsers);
+//   while (ircuser.hasNext()) {
+//     ircuser.next();
+//     delete ircuser.value();
+//   }
+// }
+
+uint NetworkInfo::networkId() const {
+  return _networkId;
+}
+
+bool NetworkInfo::initialized() const {
+  return _initialized;
+}
+
+Synchronizer *NetworkInfo::synchronizer() {
+  return _synchronizer;
+}
+
+bool NetworkInfo::isMyNick(const QString &nick) const {
+  return (myNick().toLower() == nick.toLower());
+}
+
+bool NetworkInfo::isMyNick(IrcUser *ircuser) const {
+  return (ircuser->nick().toLower() == myNick());
+}
+
+bool NetworkInfo::isChannelName(const QString &channelname) const {
+  if(channelname.isEmpty())
+    return false;
+  
+  if(supports("CHANTYPES"))
+    return support("CHANTYPES").contains(channelname[0]);
+  else
+    return QString("#&!+").contains(channelname[0]);
+}
+
+QString NetworkInfo::prefixToMode(const QString &prefix) {
+  if(prefixes().contains(prefix))
+    return QString(prefixModes()[prefixes().indexOf(prefix)]);
+  else
+    return QString();
+}
+
+QString NetworkInfo::prefixToMode(const QCharRef &prefix) {
+  return prefixToMode(QString(prefix));
+}
+
+QString NetworkInfo::modeToPrefix(const QString &mode) {
+  if(prefixModes().contains(mode))
+    return QString(prefixes()[prefixModes().indexOf(mode)]);
+  else
+    return QString();
+}
+
+QString NetworkInfo::modeToPrefix(const QCharRef &mode) {
+  return modeToPrefix(QString(mode));
+}
+  
+QString NetworkInfo::networkName() const {
+  return _networkName;
+}
+
+QString NetworkInfo::currentServer() const {
+  return _currentServer;
+}
+
+QString NetworkInfo::myNick() const {
+  return _myNick;
+}
+
+QStringList NetworkInfo::nicks() const {
+  // we don't use _ircUsers.keys() since the keys may be
+  // not up to date after a nick change
+  QStringList nicks;
+  foreach(IrcUser *ircuser, _ircUsers.values()) {
+    nicks << ircuser->nick();
+  }
+  return nicks;
+}
+
+QStringList NetworkInfo::channels() const {
+  return _ircChannels.keys();
+}
+
+QString NetworkInfo::prefixes() {
+  if(_prefixes.isNull())
+    determinePrefixes();
+  
+  return _prefixes;
+}
+
+QString NetworkInfo::prefixModes() {
+  if(_prefixModes.isNull())
+    determinePrefixes();
+
+  return _prefixModes;
+}
+
+bool NetworkInfo::supports(const QString &param) const {
+  return _supports.contains(param);
+}
+
+QString NetworkInfo::support(const QString &param) const {
+  QString support_ = param.toUpper();
+  if(_supports.contains(support_))
+    return _supports[support_];
+  else
+    return QString();
+}
+
+IrcUser *NetworkInfo::newIrcUser(const QString &hostmask) {
+  QString nick(nickFromMask(hostmask));
+  if(!_ircUsers.contains(nick)) {
+    IrcUser *ircuser = new IrcUser(hostmask, this);
+    new Synchronizer(ircuser, synchronizer()->proxy());
+    connect(ircuser, SIGNAL(nickSet(QString)), this, SLOT(ircUserNickChanged(QString)));
+    connect(ircuser, SIGNAL(initDone()), this, SIGNAL(ircUserInitDone()));
+    connect(ircuser, SIGNAL(destroyed()), this, SLOT(ircUserDestroyed()));
+    _ircUsers[nick] = ircuser;
+    emit ircUserAdded(hostmask);
+  }
+  return  _ircUsers[nick];
+}
+
+IrcUser *NetworkInfo::ircUser(const QString &nickname) const {
+  if(_ircUsers.contains(nickname))
+    return _ircUsers[nickname];
+  else
+    return 0;
+}
+
+QList<IrcUser *> NetworkInfo::ircUsers() const {
+  return _ircUsers.values();
+}
+
+IrcChannel *NetworkInfo::newIrcChannel(const QString &channelname) {
+  if(!_ircChannels.contains(channelname)) {
+    IrcChannel *channel = new IrcChannel(channelname, this);
+    new Synchronizer(channel, synchronizer()->proxy());
+    connect(channel, SIGNAL(initDone()), this, SIGNAL(ircChannelInitDone()));
+    connect(channel, SIGNAL(destroyed()), this, SLOT(channelDestroyed()));
+    _ircChannels[channelname] = channel;
+    emit ircChannelAdded(channelname);
+  }
+  return _ircChannels[channelname];
+}
+
+
+IrcChannel *NetworkInfo::ircChannel(const QString &channelname) {
+  if(_ircChannels.contains(channelname))
+    return _ircChannels[channelname];
+  else
+    return 0;
+}
+
+QList<IrcChannel *> NetworkInfo::ircChannels() const {
+  return _ircChannels.values();
+}
+
+// ====================
+//  Public Slots:
+// ====================
+void NetworkInfo::setNetworkName(const QString &networkName) {
+  _networkName = networkName;
+  emit networkNameSet(networkName);
+}
+
+void NetworkInfo::setCurrentServer(const QString &currentServer) {
+  _currentServer = currentServer;
+  emit currentServerSet(currentServer);
+}
+
+void NetworkInfo::setMyNick(const QString &nickname) {
+  _myNick = nickname;
+  emit myNickSet(nickname);
+}
+
+void NetworkInfo::addSupport(const QString &param, const QString &value) {
+  if(!_supports.contains(param)) {
+    _supports[param] = value;
+    emit supportAdded(param, value);
+  }
+}
+
+void NetworkInfo::removeSupport(const QString &param) {
+  if(_supports.contains(param)) {
+    _supports.remove(param);
+    emit supportRemoved(param);
+  }
+}
+
+QVariantMap NetworkInfo::initSupports() const {
+  QVariantMap supports;
+  QHashIterator<QString, QString> iter(_supports);
+  while(iter.hasNext()) {
+    iter.next();
+    supports[iter.key()] = iter.value();
+  }
+  return supports;
+}
+
+QStringList NetworkInfo::initIrcUsers() const {
+  QStringList hostmasks;
+  foreach(IrcUser *ircuser, ircUsers()) {
+    hostmasks << ircuser->hostmask();
+  }
+  return hostmasks;
+}
+
+QStringList NetworkInfo::initIrcChannels() const {
+  return _ircChannels.keys();
+}
+
+void NetworkInfo::initSetSupports(const QVariantMap &supports) {
+  QMapIterator<QString, QVariant> iter(supports);
+  while(iter.hasNext()) {
+    iter.next();
+    addSupport(iter.key(), iter.value().toString());
+  }
+}
+
+void NetworkInfo::initSetIrcUsers(const QStringList &hostmasks) {
+  if(!_ircUsers.empty())
+    return;
+  foreach(QString hostmask, hostmasks) {
+    newIrcUser(hostmask);
+  }
+}
+
+void NetworkInfo::initSetChannels(const QStringList &channels) {
+  if(!_ircChannels.empty())
+    return;
+  foreach(QString channel, channels)
+    newIrcChannel(channel);
+}
+
+IrcUser *NetworkInfo::updateNickFromMask(const QString &mask) {
+  QString nick(nickFromMask(mask));
+  IrcUser *ircuser;
+  
+  if(_ircUsers.contains(nick)) {
+    ircuser = _ircUsers[nick];
+    ircuser->updateHostmask(mask);
+  } else {
+    ircuser = newIrcUser(mask);
+  }
+  return ircuser;
+}
+
+void NetworkInfo::ircUserNickChanged(QString newnick) {
+  QString oldnick = _ircUsers.key(qobject_cast<IrcUser*>(sender()));
+  if(oldnick.isNull())
+    return;
+  
+  _ircUsers[newnick] = _ircUsers.take(oldnick);
+  
+  if(myNick() == oldnick)
+    setMyNick(newnick);
+}
+
+void NetworkInfo::ircUserDestroyed() {
+  IrcUser *ircuser = qobject_cast<IrcUser *>(sender());
+  QHash<QString, IrcUser*>::iterator i = _ircUsers.begin();
+  while(i != _ircUsers.end()) {
+    if(i.value() == ircuser) {
+      i = _ircUsers.erase(i);
+    } else {
+      i++;
+    }
+  }
+}
+
+void NetworkInfo::channelDestroyed() {
+  IrcChannel *channel = qobject_cast<IrcChannel *>(sender());
+  QHash<QString, IrcChannel*>::iterator i = _ircChannels.begin();
+  while(i != _ircChannels.end()) {
+    if(i.value() == channel) {
+      i = _ircChannels.erase(i);
+    } else {
+      i++;
+    }
+  }
+}
+
+void NetworkInfo::setInitialized() {
+  _initialized = true;
+  emit initDone();
+}
+
+// ====================
+//  Private:
+// ====================
+void NetworkInfo::determinePrefixes() {
+  // seems like we have to construct them first
+  QString PREFIX = support("PREFIX");
+  
+  if(PREFIX.startsWith("(") && PREFIX.contains(")")) {
+    _prefixes = PREFIX.section(")", 1);
+    _prefixModes = PREFIX.mid(1).section(")", 0, 0);
+  } else {
+    QString defaultPrefixes("@%+");
+    QString defaultPrefixModes("ohv");
+
+    // we just assume that in PREFIX are only prefix chars stored
+    for(int i = 0; i < defaultPrefixes.size(); i++) {
+      if(PREFIX.contains(defaultPrefixes[i])) {
+       _prefixes += defaultPrefixes[i];
+       _prefixModes += defaultPrefixModes[i];
+      }
+    }
+    // check for success
+    if(!_prefixes.isNull())
+      return;
+    
+    // well... our assumption was obviously wrong...
+    // check if it's only prefix modes
+    for(int i = 0; i < defaultPrefixes.size(); i++) {
+      if(PREFIX.contains(defaultPrefixModes[i])) {
+       _prefixes += defaultPrefixes[i];
+       _prefixModes += defaultPrefixModes[i];
+      }
+    }
+    // now we've done all we've could...
+  }
+}
+
diff --git a/src/common/networkinfo.h b/src/common/networkinfo.h
new file mode 100644 (file)
index 0000000..6f2ab48
--- /dev/null
@@ -0,0 +1,151 @@
+/***************************************************************************
+ *   Copyright (C) 2005/06 by The Quassel Team                             *
+ *   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) any later version.                                   *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program; if not, write to the                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
+ ***************************************************************************/
+
+#ifndef _NETWORKINFO_H_
+#define _NETWORKINFO_H_
+
+#include <QString>
+#include <QStringList>
+#include <QList>
+#include <QHash>
+#include <QVariantMap>
+#include <QPointer>
+
+class SignalProxy;
+class Synchronizer;
+class IrcUser;
+class IrcChannel;
+
+
+class NetworkInfo : public QObject {
+  Q_OBJECT
+
+  Q_PROPERTY(QString networkName READ networkName WRITE setNetworkName STORED false)
+  Q_PROPERTY(QString currentServer READ currentServer WRITE setCurrentServer STORED false)
+  Q_PROPERTY(QString myNick READ myNick WRITE setMyNick STORED false)
+
+public:
+  NetworkInfo(const uint &networkid, SignalProxy *proxy, QObject *parent = 0);
+  //  virtual ~NetworkInfo();
+
+  uint networkId() const;
+  bool initialized() const;
+  Synchronizer *synchronizer();
+
+  bool isMyNick(const QString &nick) const;
+  bool isMyNick(IrcUser *ircuser) const;
+
+  bool isChannelName(const QString &channelname) const;
+
+  QString prefixToMode(const QString &prefix);
+  QString prefixToMode(const QCharRef &prefix);
+  QString modeToPrefix(const QString &mode);
+  QString modeToPrefix(const QCharRef &mode);
+  
+  QString networkName() const;
+  QString currentServer() const;
+  QString myNick() const;
+  QStringList nicks() const;
+  QStringList channels() const;
+
+  QString prefixes();
+  QString prefixModes();
+
+  bool supports(const QString &param) const;
+  QString support(const QString &param) const;
+  
+  IrcUser *newIrcUser(const QString &hostmask);
+  IrcUser *ircUser(const QString &nickname) const;
+  QList<IrcUser *> ircUsers() const;
+  
+  IrcChannel *newIrcChannel(const QString &channelname);
+  IrcChannel *ircChannel(const QString &channelname);
+  QList<IrcChannel *> ircChannels() const;
+
+public slots:
+  void setNetworkName(const QString &networkName);
+  void setCurrentServer(const QString &currentServer);
+  void setMyNick(const QString &mynick);
+
+  void addSupport(const QString &param, const QString &value = QString());
+  void removeSupport(const QString &param);
+
+  inline void addIrcUser(const QString &hostmask) { newIrcUser(hostmask); }
+  
+  //init geters
+  QVariantMap initSupports() const;
+  QStringList initIrcUsers() const;
+  QStringList initIrcChannels() const;
+  
+  //init seters
+  void initSetSupports(const QVariantMap &supports);
+  void initSetIrcUsers(const QStringList &hostmasks);
+  void initSetChannels(const QStringList &channels);
+  
+  IrcUser *updateNickFromMask(const QString &mask);
+
+  // these slots are to keep the hashlists of all users and the
+  // channel lists up to date
+  void ircUserNickChanged(QString newnick);
+
+  void ircUserDestroyed();
+  void channelDestroyed();
+
+  void setInitialized();
+  
+signals:
+  void networkNameSet(const QString &networkName);
+  void currentServerSet(const QString &currentServer);
+  void myNickSet(const QString &mynick);
+
+  void supportAdded(const QString &param, const QString &value = QString());
+  void supportRemoved(const QString &param);
+  
+  void ircUserAdded(QString hostmask);
+  void ircChannelAdded(QString channelname);
+
+  void initDone();
+  void ircUserInitDone();
+  void ircChannelInitDone();
+  
+private:
+  uint _networkId;
+  bool _initialized;
+  
+  QString _myNick;
+  QString _networkName;
+  QString _currentServer;
+
+  QString _prefixes;
+  QString _prefixModes;
+
+  QHash<QString, IrcUser *> _ircUsers;  // stores all known nicks for the server
+  QHash<QString, IrcChannel *> _ircChannels; // stores all known channels
+  QHash<QString, QString> _supports;  // stores results from RPL_ISUPPORT
+
+  //QVariantMap networkSettings;
+  //QVariantMap identity;
+  
+  QPointer<Synchronizer> _synchronizer;
+  
+  void determinePrefixes();
+};
+
+#endif
index 2f68f94..3e7136a 100644 (file)
@@ -34,6 +34,7 @@ class SignalProxy : public QObject {
     SignalProxy(ProxyType type, QIODevice *device = 0, QObject *parent = 0);
     ~SignalProxy();
 
+  ProxyType proxyType() const { return type; }
     void attachSignal(QObject* sender, const char* signal, const QByteArray& rpcFunction = QByteArray());
     void attachSlot(const QByteArray& rpcFunction, QObject* recv, const char* slot);
 
diff --git a/src/common/synchronizer.cpp b/src/common/synchronizer.cpp
new file mode 100644 (file)
index 0000000..8c29400
--- /dev/null
@@ -0,0 +1,343 @@
+/***************************************************************************
+ *   Copyright (C) 2005-07 by The Quassel Team                             *
+ *   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) any later version.                                   *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program; if not, write to the                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
+ ***************************************************************************/
+#include "synchronizer.h"
+
+#include <QString>
+#include <QRegExp>
+#include <QMetaProperty>
+#include <QMetaMethod>
+
+#include "util.h"
+#include "signalproxy.h"
+
+#include <QByteArray>
+#include <QDebug>
+
+// ====================
+//  Public:
+// ====================
+Synchronizer::Synchronizer(QObject *parent, SignalProxy *signalproxy)
+  : QObject(parent),
+    _initialized(false),
+    _signalproxy(signalproxy)
+{
+  attach();
+  if(!getMethodByName("objectNameSet()").isEmpty())
+    connect(parent,SIGNAL(objectNameSet()), this, SLOT(parentChangedName()));
+}
+
+bool Synchronizer::initialized() const {
+  return _initialized;
+}
+
+SignalProxy *Synchronizer::proxy() const {
+  return _signalproxy;
+}
+
+QVariantMap Synchronizer::initData() const {
+  QVariantMap properties;
+  
+  // we collect data from properties
+  foreach(QMetaProperty property, parentProperties()) {
+    QString name = QString(property.name());
+    QVariant value = property.read(parent());
+    properties[name] = value;
+    // qDebug() << ">>> SYNC:" << name << value;
+  }
+
+  // ...as well as methods, which have names starting with "init"
+  foreach(QMetaMethod method, parentSlots()) {
+    QString methodname = QString(method.signature()).section("(", 0, 0);
+    if(methodname.startsWith("initSet") ||
+       !methodname.startsWith("init"))
+      continue;
+
+    QVariant value = QVariant(QVariant::nameToType(method.typeName()));
+    QGenericReturnArgument genericvalue = QGenericReturnArgument(method.typeName(), &value);
+    QMetaObject::invokeMethod(parent(), methodname.toAscii(), genericvalue);
+
+    properties[methodBaseName(method)] = value;
+    // qDebug() << ">>> SYNC:" << methodBaseName(method) << value;
+  }
+
+  // properties["Payload"] = QByteArray(10000000, 'a');  // for testing purposes
+  return properties;
+}
+
+void Synchronizer::setInitData(const QVariantMap &properties) {
+  if(initialized())
+    return;
+
+  const QMetaObject *metaobject = parent()->metaObject();  
+  QMapIterator<QString, QVariant> iterator(properties);
+  while(iterator.hasNext()) {
+    iterator.next();
+    QString name = iterator.key();
+    int propertyIndex = metaobject->indexOfProperty(name.toAscii());
+    if(propertyIndex == -1) {
+      setInitValue(name, iterator.value());
+    } else {
+      if((metaobject->property(propertyIndex)).isWritable())
+       parent()->setProperty(name.toAscii(), iterator.value());
+      else
+       setInitValue(name, iterator.value());   
+    }
+    // qDebug() << "<<< SYNC:" << name << iterator.value();
+  }
+
+  _initialized = true;
+  emit initDone();
+}
+
+// ====================
+//  Public Slots
+// ====================
+void Synchronizer::synchronizeClients() const {
+  emit sendInitData(initData());
+}
+
+void Synchronizer::recvInitData(QVariantMap properties) {
+  proxy()->detachObject(this);
+  setInitData(properties);
+}
+
+void Synchronizer::parentChangedName() {
+  proxy()->detachObject(parent());
+  proxy()->detachObject(this);
+  attach();
+  if(proxy()->proxyType() == SignalProxy::Client && initialized())
+    proxy()->detachObject(this);
+}
+
+// ====================
+//  Private
+// ====================
+QString Synchronizer::signalPrefix() const {
+  return QString(parent()->metaObject()->className()) + "_" + QString(parent()->objectName()) + "_";
+}
+
+QString Synchronizer::initSignal() const {
+  return QString(metaObject()->className())
+    + "_" + QString(parent()->metaObject()->className())
+    + "_" + QString(parent()->objectName())
+    + "_" + QString(SIGNAL(sendInitData(QVariantMap)));
+}
+
+QString Synchronizer::requestSyncSignal() const {
+  return QString(metaObject()->className())
+    + "_" + QString(parent()->metaObject()->className())
+    + "_" + QString(parent()->objectName())
+    + "_" + QString(SIGNAL(requestSync()));
+}
+
+QString Synchronizer::methodBaseName(const QMetaMethod &method) const {
+  QString methodname = QString(method.signature()).section("(", 0, 0);
+
+  // determine where we have to chop:
+  if(method.methodType() == QMetaMethod::Slot) {
+    // we take evertyhing from the first uppercase char if it's slot
+    methodname = methodname.mid(methodname.indexOf(QRegExp("[A-Z]")));
+  } else {
+    // and if it's a signal we discard everything from the last uppercase char
+    methodname = methodname.left(methodname.lastIndexOf(QRegExp("[A-Z]")));
+  }
+
+  methodname[0] = methodname[0].toUpper();
+
+  return methodname;
+}
+
+bool Synchronizer::methodsMatch(const QMetaMethod &signal, const QMetaMethod &slot) const {
+  // if we don't even have the same basename it's a sure NO
+  if(methodBaseName(signal) != methodBaseName(slot))
+    return false;
+
+  const QMetaObject *metaobject = parent()->metaObject();
+
+  // are the signatures compatible?
+  if(! metaobject->checkConnectArgs(signal.signature(), slot.signature()))
+    return false;
+
+  // we take an educated guess if the signals and slots match
+  QString signalsuffix = QString(signal.signature()).section("(", 0, 0);
+  signalsuffix = signalsuffix.mid(signalsuffix.lastIndexOf(QRegExp("[A-Z]"))).toLower();
+    
+  QString slotprefix = QString(slot.signature()).section("(", 0, 0);
+  slotprefix = slotprefix.left(slotprefix.indexOf(QRegExp("[A-Z]"))).toLower();
+
+  uint sizediff;
+  if(signalsuffix.size() < slotprefix.size())
+    sizediff = slotprefix.size() - signalsuffix.size();
+  else
+    sizediff = signalsuffix.size() - slotprefix.size();
+
+  int ratio = editingDistance(slotprefix, signalsuffix) - sizediff;
+
+  return (ratio < 2);
+}
+
+QList<QMetaProperty> Synchronizer::parentProperties() const {
+  QList<QMetaProperty> _properties;
+
+  const QMetaObject *metaobject = parent()->metaObject();
+  for(int i = metaobject->propertyOffset(); i < metaobject->propertyCount(); i++) {
+    _properties << metaobject->property(i);
+  }
+  
+  return _properties;
+}
+
+QList<QMetaMethod> Synchronizer::parentSlots() const {
+  QList<QMetaMethod> _slots;
+
+  const QMetaObject *metaobject = parent()->metaObject();
+  for(int i = metaobject->methodOffset(); i < metaobject->methodCount(); i++) {
+    QMetaMethod method = metaobject->method(i);
+    if(method.methodType() == QMetaMethod::Slot)
+      _slots << method;
+  }
+
+  return _slots;
+}
+
+
+QList<QMetaMethod> Synchronizer::parentSignals() const {
+  QList<QMetaMethod> _signals;
+
+  const QMetaObject *metaobject = parent()->metaObject();
+  for(int i = metaobject->methodOffset(); i < metaobject->methodCount(); i++) {
+    QMetaMethod method = metaobject->method(i);
+    if(method.methodType() == QMetaMethod::Signal)
+      _signals << method;
+  }
+  
+  return _signals;
+}
+
+QList<QMetaMethod> Synchronizer::getMethodByName(const QString &methodname) {
+  QList<QMetaMethod> _methods;
+  
+  const QMetaObject* metaobject = parent()->metaObject();
+  for(int i = metaobject->methodOffset(); i < metaobject->methodCount(); i++) {
+    if(QString(metaobject->method(i).signature()).startsWith(methodname))
+      _methods << metaobject->method(i);
+  }
+
+  return _methods;
+}
+
+void Synchronizer::attach() {
+  if(proxy()->proxyType() == SignalProxy::Server)
+    attachAsMaster();
+  else
+    attachAsSlave();
+}
+void Synchronizer::attachAsSlave() {
+  QList<QMetaMethod> signals_ = parentSignals();
+  
+  foreach(QMetaMethod slot, parentSlots()) {
+    if(signals_.empty())
+      break;
+    
+    for(int i = 0; i < signals_.count(); i++) {
+      QMetaMethod signal = signals_[i];
+      if(!methodsMatch(signal, slot))
+       continue;
+
+      // we could simply put a "1" in front of the normalized signature
+      // but to guarantee future compatibility we construct a dummy signal
+      // and replace the known the fake signature by ours...
+      QString dummySlot = QString(SIGNAL(dummy()));
+      QString proxySignal = signalPrefix() + QString(signal.signature());
+      QString slotsignature = dummySlot.replace("dummy()", QString(slot.signature()));
+
+      // qDebug() << "attachSlot:" << proxySignal << slotsignature;
+      proxy()->attachSlot(proxySignal.toAscii(), parent(), slotsignature.toAscii());
+      signals_.removeAt(i);
+      break;
+    }
+  }
+
+  // and then we connect ourself, so we can receive init data
+  // qDebug() << "attachSlot:" << initSignal() << "recvInitData(QVariantMap)";
+  // qDebug() << "attachSignal:" << "requestSync()" << requestSyncSignal();
+  proxy()->attachSlot(initSignal().toAscii(), this, SLOT(recvInitData(QVariantMap)));
+  proxy()->attachSignal(this, SIGNAL(requestSync()), requestSyncSignal().toAscii());
+
+  if(!getMethodByName("setInitialized()").isEmpty())
+    connect(this, SIGNAL(initDone()), parent(), SLOT(setInitialized()));
+
+  emit requestSync();
+}
+
+void Synchronizer::attachAsMaster() {
+  QList<QMetaMethod> slots_ = parentSlots();
+  
+  foreach(QMetaMethod signal, parentSignals()) {
+    if(slots_.isEmpty())
+      break;
+
+    // we don't attach all signals, just the ones that have a maching counterpart
+    for(int i = 0; i < slots_.count(); i++) {
+      QMetaMethod slot = slots_[i];
+      if(!methodsMatch(signal, slot))
+       continue;
+      
+      // we could simply put a "2" in front of the normalized signature
+      // but to guarantee future compatibility we construct a dummy signal
+      // and replace the known the fake signature by ours...
+      QString dummySignal = QString(SIGNAL(dummy()));
+      QString proxySignal = signalPrefix() + QString(signal.signature());
+      QString signalsignature = dummySignal.replace("dummy()", QString(signal.signature()));
+    
+      // qDebug() << "attachSignal:" << signalsignature << proxySignal;
+      proxy()->attachSignal(parent(), signalsignature.toAscii(), proxySignal.toAscii());
+      slots_.removeAt(i);
+      break;
+    }
+  }
+  
+  // and then we connect ourself, so we can initialize slaves
+  // qDebug() << "attachSignal:" << "sendInitData(QVariantMap)" << initSignal();
+  // qDebug() << "attachSlot:" << "synchronizeClients()" << requestSyncSignal();
+  proxy()->attachSignal(this, SIGNAL(sendInitData(QVariantMap)), initSignal().toAscii());
+  proxy()->attachSlot(requestSyncSignal().toAscii(), this, SLOT(synchronizeClients()));
+}
+
+bool Synchronizer::setInitValue(const QString &property, const QVariant &value) {
+  QString handlername = QString("initSet") + property;
+  handlername[7] = handlername[7].toUpper();
+
+  //determine param type
+  QByteArray paramtype;
+  foreach(QMetaMethod method, getMethodByName(handlername)) {
+    if(method.parameterTypes().size() == 1) {
+      paramtype = method.parameterTypes()[0];
+      break;
+    }
+  }
+
+  if(paramtype.isNull())
+    return false;
+
+  QGenericArgument param = QGenericArgument(paramtype, &value);
+  return QMetaObject::invokeMethod(parent(), handlername.toAscii(), param);
+}
diff --git a/src/common/synchronizer.h b/src/common/synchronizer.h
new file mode 100644 (file)
index 0000000..97453b2
--- /dev/null
@@ -0,0 +1,79 @@
+/***************************************************************************
+ *   Copyright (C) 2005/06 by The Quassel Team                             *
+ *   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) any later version.                                   *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program; if not, write to the                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
+ ***************************************************************************/
+
+#ifndef _SYNCHRONIZER_H_
+#define _SYNCHRONIZER_H_
+
+class SignalProxy;
+
+#include <QObject>;
+#include <QList>;
+#include <QString>;
+#include <QVariantMap>;
+#include <QMetaMethod>;
+#include <QPointer>
+
+class Synchronizer : public QObject {
+  Q_OBJECT
+
+public:
+  Synchronizer(QObject *parent, SignalProxy *signalproxy);
+  
+  bool initialized() const;
+  SignalProxy *proxy() const;
+
+  QVariantMap initData() const;
+  void setInitData(const QVariantMap &properties);
+
+public slots:
+  void synchronizeClients() const;
+  void recvInitData(QVariantMap properties);
+  void parentChangedName();
+  
+signals:
+  void requestSync() const;
+  void sendInitData(QVariantMap properties) const;
+  void initDone();
+  
+private:
+  bool _initialized;
+  QPointer<SignalProxy> _signalproxy;
+  
+  QString signalPrefix() const;
+  QString initSignal() const;
+  QString requestSyncSignal() const;
+  
+  QString methodBaseName(const QMetaMethod &method) const;
+  bool methodsMatch(const QMetaMethod &signal, const QMetaMethod &slot) const;
+
+  QList<QMetaProperty> parentProperties() const;
+  QList<QMetaMethod> parentSlots() const;
+  QList<QMetaMethod> parentSignals() const;
+  
+  QList<QMetaMethod> getMethodByName(const QString &methodname);
+  
+  void attach();
+  void attachAsSlave();
+  void attachAsMaster();
+                         
+  bool setInitValue(const QString &property, const QVariant &value);
+};
+
+#endif
index cc12ff7..c9f715f 100644 (file)
@@ -1,6 +1,6 @@
-SET(core_SRCS core.cpp coresession.cpp server.cpp serverinfo.cpp sqlitestorage.cpp storage.cpp)
+SET(core_SRCS core.cpp coresession.cpp server.cpp basichandler.cpp ircserverhandler.cpp userinputhandler.cpp ctcphandler.cpp sqlitestorage.cpp storage.cpp)
 SET(core_HDRS )
-SET(core_MOCS core.h coresession.h server.h serverinfo.h sqlitestorage.h storage.h)
+SET(core_MOCS core.h coresession.h server.h basichandler.h ircserverhandler.h userinputhandler.h ctcphandler.h sqlitestorage.h storage.h)
 
 QT4_WRAP_CPP(_MOC ${core_MOCS})
 ADD_LIBRARY(core ${core_SRCS} ${_MOC})
diff --git a/src/core/basichandler.cpp b/src/core/basichandler.cpp
new file mode 100644 (file)
index 0000000..87c7e08
--- /dev/null
@@ -0,0 +1,77 @@
+/***************************************************************************
+ *   Copyright (C) 2005-07 by The Quassel Team                             *
+ *   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) any later version.                                   *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program; if not, write to the                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
+ ***************************************************************************/
+#include "basichandler.h"
+
+#include <QMetaMethod>
+
+#include "server.h"
+
+BasicHandler::BasicHandler(Server *parent)
+  : QObject(parent),
+    server(parent) {
+  
+  connect(this, SIGNAL(displayMsg(Message::Type, QString, QString, QString, quint8)),
+         server, SIGNAL(displayMsg(Message::Type, QString, QString, QString, quint8)));
+
+  connect(this, SIGNAL(putCmd(QString, QStringList, QString)),
+         server, SLOT(putCmd(QString, QStringList, QString)));
+
+  connect(this, SIGNAL(putRawLine(QString)),
+         server, SLOT(putRawLine(QString)));
+}
+
+QStringList BasicHandler::providesHandlers() const {
+  QStringList handlers;
+  for(int i=0; i < metaObject()->methodCount(); i++) {
+    QString methodSignature(metaObject()->method(i).signature());
+    if(!methodSignature.startsWith("handle"))
+      continue;
+
+    methodSignature = methodSignature.section('(',0,0);  // chop the attribute list
+    methodSignature = methodSignature.mid(6); // strip "handle"
+    handlers << methodSignature;
+  }
+  return handlers;
+}
+
+
+void BasicHandler::handle(const QString &member, const QGenericArgument &val0,
+                         const QGenericArgument &val1, const QGenericArgument &val2,
+                         const QGenericArgument &val3, const QGenericArgument &val4,
+                         const QGenericArgument &val5, const QGenericArgument &val6,
+                         const QGenericArgument &val7, const QGenericArgument &val8) {
+
+  // Now we try to find a handler for this message. BTW, I do love the Trolltech guys ;-)
+  QString handler = member.toLower();
+  handler[0] = handler[0].toUpper();
+  handler = "handle" + handler;
+
+  if(!QMetaObject::invokeMethod(this, handler.toAscii(), val0, val1, val2, val3, val4, val5, val6, val7, val8))
+    // Ok. Default handler it is.
+    QMetaObject::invokeMethod(this, "defaultHandler", Q_ARG(QString, member), val0, val1, val2, val3, val4, val5, val6, val7, val8);
+     
+}
+
+// ====================
+//  protected:
+// ====================
+NetworkInfo *BasicHandler::networkInfo() const {
+  return server->networkInfo();
+}
diff --git a/src/core/basichandler.h b/src/core/basichandler.h
new file mode 100644 (file)
index 0000000..61a3f2e
--- /dev/null
@@ -0,0 +1,61 @@
+/***************************************************************************
+ *   Copyright (C) 2005/06 by The Quassel Team                             *
+ *   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) any later version.                                   *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program; if not, write to the                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
+ ***************************************************************************/
+
+#ifndef _BASICHANDLER_H_
+#define _BASICHANDLER_H_
+
+#include <QObject>
+#include <QString>
+#include <QStringList>
+#include <QGenericArgument>
+
+#include "message.h"
+
+class Server;
+class NetworkInfo;
+
+class BasicHandler : public QObject {
+  Q_OBJECT
+
+public:
+  BasicHandler(Server *parent = 0);
+
+  QStringList providesHandlers() const;
+
+signals:
+  void displayMsg(Message::Type, QString target, QString text, QString sender = "", quint8 flags = Message::None);
+  void putCmd(QString cmd, QStringList params, QString prefix = 0);
+  void putRawLine(QString msg);
+  
+protected:
+  virtual void handle(const QString &member, const QGenericArgument &val0 = QGenericArgument(0),
+                     const QGenericArgument &val1 = QGenericArgument(), const QGenericArgument &val2 = QGenericArgument(),
+                     const QGenericArgument &val3 = QGenericArgument(), const QGenericArgument &val4 = QGenericArgument(),
+                     const QGenericArgument &val5 = QGenericArgument(), const QGenericArgument &val6 = QGenericArgument(),
+                     const QGenericArgument &val7 = QGenericArgument(), const QGenericArgument &val8 = QGenericArgument());
+           
+  Server *server;
+  
+
+protected:
+  NetworkInfo *networkInfo() const;
+
+};
+#endif
index 5159f93..7b57661 100644 (file)
@@ -25,7 +25,7 @@
 
 Core *Core::instanceptr = 0;
 
-Core * Core::instance() {
+Core *Core::instance() {
   if(instanceptr) return instanceptr;
   instanceptr = new Core();
   instanceptr->init();
@@ -38,7 +38,6 @@ void Core::destroy() {
 }
 
 Core::Core() {
-
 }
 
 void Core::init() {
@@ -121,7 +120,7 @@ void Core::clientHasData() {
       return;
     }
   }
-  blockSizes[socket] = bsize = 0;  // FIXME blockSizes aufräum0rn!
+  blockSizes[socket] = bsize = 0;  // FIXME blockSizes aufräum0rn!
 }
 
 // FIXME: no longer called, since connection handling is now in SignalProxy
@@ -163,10 +162,10 @@ void Core::processClientInit(QTcpSocket *socket, const QVariant &v) {
 QVariant Core::initSession(UserId uid) {
   // Find or create session for validated user
   CoreSession *sess;
-  if(sessions.contains(uid)) sess = sessions[uid];
-  else {
+  if(sessions.contains(uid))
+    sess = sessions[uid];
+  else
     sess = createSession(uid);
-  }
   QVariantMap reply;
   reply["SessionState"] = sess->sessionState();
   return reply;
index 03c1b8c..32427c1 100644 (file)
@@ -1,4 +1,4 @@
 DEPMOD = common contrib/qxt
 QT_MOD = core network sql
-SRCS = core.cpp coresession.cpp server.cpp serverinfo.cpp sqlitestorage.cpp storage.cpp
-HDRS = core.h coresession.h server.h serverinfo.h sqlitestorage.h storage.h
+SRCS = core.cpp coresession.cpp server.cpp sqlitestorage.cpp storage.cpp basichandler.cpp ircserverhandler.cpp userinputhandler.cpp ctcphandler.cpp 
+HDRS = core.h coresession.h server.h sqlitestorage.h storage.h basichandler.h ircserverhandler.h userinputhandler.h ctcphandler.h 
index bdd2978..28a074f 100644 (file)
 
 #include "coresession.h"
 #include "server.h"
+
 #include "signalproxy.h"
 #include "storage.h"
+
+#include "synchronizer.h"
+#include "networkinfo.h"
+#include "ircuser.h"
+#include "ircchannel.h"
+
 #include "util.h"
 
-CoreSession::CoreSession(UserId uid, Storage *_storage, QObject *parent) : QObject(parent), user(uid), storage(_storage) {
-  _signalProxy = new SignalProxy(SignalProxy::Server, 0, this);
+
+CoreSession::CoreSession(UserId uid, Storage *_storage, QObject *parent)
+  : QObject(parent),
+    user(uid),
+    _signalProxy(new SignalProxy(SignalProxy::Server, 0, this)),
+    storage(_storage)
+{
 
   QSettings s;
   s.beginGroup(QString("SessionData/%1").arg(user));
@@ -37,17 +49,16 @@ CoreSession::CoreSession(UserId uid, Storage *_storage, QObject *parent) : QObje
 
   SignalProxy *p = signalProxy();
 
-  p->attachSlot(SIGNAL(requestNetworkStates()), this, SIGNAL(serverStateRequested()));
+  p->attachSlot(SIGNAL(requestNetworkStates()), this, SLOT(serverStateRequested()));
   p->attachSlot(SIGNAL(requestConnect(QString)), this, SLOT(connectToNetwork(QString)));
-  p->attachSlot(SIGNAL(sendInput(BufferId, QString)), this, SLOT(msgFromGui(BufferId, QString)));
+  p->attachSlot(SIGNAL(sendInput(BufferInfo, QString)), this, SLOT(msgFromGui(BufferInfo, QString)));
   p->attachSlot(SIGNAL(importOldBacklog()), storage, SLOT(importOldBacklog()));
-  p->attachSlot(SIGNAL(requestBacklog(BufferId, QVariant, QVariant)), this, SLOT(sendBacklog(BufferId, QVariant, QVariant)));
-  p->attachSlot(SIGNAL(requestNetworkStates()), this, SLOT(sendServerStates()));
+  p->attachSlot(SIGNAL(requestBacklog(BufferInfo, QVariant, QVariant)), this, SLOT(sendBacklog(BufferInfo, QVariant, QVariant)));
   p->attachSignal(this, SIGNAL(displayMsg(Message)));
   p->attachSignal(this, SIGNAL(displayStatusMsg(QString, QString)));
-  p->attachSignal(this, SIGNAL(backlogData(BufferId, QVariantList, bool)));
-  p->attachSignal(this, SIGNAL(bufferIdUpdated(BufferId)));
-  p->attachSignal(storage, SIGNAL(bufferIdUpdated(BufferId)));
+  p->attachSignal(this, SIGNAL(backlogData(BufferInfo, QVariantList, bool)));
+  p->attachSignal(this, SIGNAL(bufferInfoUpdated(BufferInfo)));
+  p->attachSignal(storage, SIGNAL(bufferInfoUpdated(BufferInfo)));
   p->attachSignal(this, SIGNAL(sessionDataChanged(const QString &, const QVariant &)), SIGNAL(coreSessionDataChanged(const QString &, const QVariant &)));
   p->attachSlot(SIGNAL(clientSessionDataChanged(const QString &, const QVariant &)), this, SLOT(storeSessionData(const QString &, const QVariant &)));
   /* Autoconnect. (When) do we actually do this?
@@ -63,7 +74,6 @@ CoreSession::CoreSession(UserId uid, Storage *_storage, QObject *parent) : QObje
 }
 
 CoreSession::~CoreSession() {
-
 }
 
 UserId CoreSession::userId() const {
@@ -91,41 +101,36 @@ QVariant CoreSession::retrieveSessionData(const QString &key, const QVariant &de
   return data;
 }
 
+// FIXME switch to NetworkIDs
 void CoreSession::connectToNetwork(QString network) {
-  QStringList networks; networks << network; // FIXME obsolete crap
-  foreach(QString net, networks) {
-    if(servers.contains(net)) {
-
-    } else {
-      Server *server = new Server(userId(), net);
-      connect(this, SIGNAL(serverStateRequested()), server, SLOT(sendState()));
-      connect(this, SIGNAL(connectToIrc(QString)), server, SLOT(connectToIrc(QString)));
-      connect(this, SIGNAL(disconnectFromIrc(QString)), server, SLOT(disconnectFromIrc(QString)));
-      connect(this, SIGNAL(msgFromGui(QString, QString, QString)), server, SLOT(userInput(QString, QString, QString)));
-
-      connect(server, SIGNAL(connected(QString)), this, SLOT(serverConnected(QString)));
-      connect(server, SIGNAL(disconnected(QString)), this, SLOT(serverDisconnected(QString)));
-      connect(server, SIGNAL(displayMsg(Message::Type, QString, QString, QString, quint8)), this, SLOT(recvMessageFromServer(Message::Type, QString, QString, QString, quint8)));
-      connect(server, SIGNAL(displayStatusMsg(QString)), this, SLOT(recvStatusMsgFromServer(QString)));
-
-      SignalProxy *p = signalProxy();
-      p->attachSignal(server, SIGNAL(serverState(QString, QVariantMap)), SIGNAL(networkState(QString, QVariantMap)));
-      p->attachSignal(server, SIGNAL(modeSet(QString, QString, QString)));
-      p->attachSignal(server, SIGNAL(nickAdded(QString, QString, QVariantMap)));
-      p->attachSignal(server, SIGNAL(nickRenamed(QString, QString, QString)));
-      p->attachSignal(server, SIGNAL(nickRemoved(QString, QString)));
-      p->attachSignal(server, SIGNAL(nickUpdated(QString, QString, QVariantMap)));
-      p->attachSignal(server, SIGNAL(ownNickSet(QString, QString)));
-      p->attachSignal(server, SIGNAL(queryRequested(QString, QString)));
-      // TODO add error handling
-      p->attachSignal(server, SIGNAL(connected(QString)), SIGNAL(networkConnected(QString)));
-      p->attachSignal(server, SIGNAL(disconnected(QString)), SIGNAL(networkDisconnected(QString)));
-
-      server->start();
-      servers[net] = server;
-    }
-    emit connectToIrc(net);
+  uint networkid = getNetworkId(network);
+  if(!servers.contains(networkid)) {
+    Server *server = new Server(userId(), networkid, network);
+    attachServer(server);
+    server->start();
+    servers[networkid] = server;
   }
+  emit connectToIrc(network);
+}
+
+void CoreSession::attachServer(Server *server) {
+  connect(this, SIGNAL(connectToIrc(QString)), server, SLOT(connectToIrc(QString)));
+  connect(this, SIGNAL(disconnectFromIrc(QString)), server, SLOT(disconnectFromIrc(QString)));
+  connect(this, SIGNAL(msgFromGui(uint, QString, QString)), server, SLOT(userInput(uint, QString, QString)));
+  
+  connect(server, SIGNAL(connected(uint)), this, SLOT(serverConnected(uint)));
+  connect(server, SIGNAL(disconnected(uint)), this, SLOT(serverDisconnected(uint)));
+  connect(server, SIGNAL(displayMsg(Message::Type, QString, QString, QString, quint8)), this, SLOT(recvMessageFromServer(Message::Type, QString, QString, QString, quint8)));
+  connect(server, SIGNAL(displayStatusMsg(QString)), this, SLOT(recvStatusMsgFromServer(QString)));
+
+  // connect serversignals to proxy
+  signalProxy()->attachSignal(server, SIGNAL(serverState(QString, QVariantMap)), SIGNAL(networkState(QString, QVariantMap)));
+  signalProxy()->attachSignal(server, SIGNAL(connected(uint)), SIGNAL(networkConnected(uint)));
+  signalProxy()->attachSignal(server, SIGNAL(disconnected(uint)), SIGNAL(networkDisconnected(uint)));
+  // TODO add error handling
+}
+
+void CoreSession::serverStateRequested() {
 }
 
 void CoreSession::addClient(QIODevice *device) {
@@ -136,31 +141,29 @@ SignalProxy *CoreSession::signalProxy() const {
   return _signalProxy;
 }
 
-void CoreSession::serverConnected(QString net) {
-  storage->getBufferId(userId(), net); // create status buffer
+void CoreSession::serverConnected(uint networkid) {
+  storage->getBufferInfo(userId(), servers[networkid]->networkName()); // create status buffer
 }
 
-void CoreSession::serverDisconnected(QString net) {
-  delete servers[net];
-  servers.remove(net);
-  signalProxy()->sendSignal(SIGNAL(networkDisconnected(QString)), net);  // FIXME does this work?
+void CoreSession::serverDisconnected(uint networkid) {
+  servers.remove(networkid);
+  delete servers[networkid];
 }
 
-void CoreSession::msgFromGui(BufferId bufid, QString msg) {
-  emit msgFromGui(bufid.network(), bufid.buffer(), msg);
+void CoreSession::msgFromGui(BufferInfo bufid, QString msg) {
+  emit msgFromGui(bufid.networkId(), bufid.buffer(), msg);
 }
 
 // ALL messages coming pass through these functions before going to the GUI.
 // So this is the perfect place for storing the backlog and log stuff.
-
 void CoreSession::recvMessageFromServer(Message::Type type, QString target, QString text, QString sender, quint8 flags) {
   Server *s = qobject_cast<Server*>(this->sender());
   Q_ASSERT(s);
-  BufferId buf;
+  BufferInfo buf;
   if((flags & Message::PrivMsg) && !(flags & Message::Self)) {
-    buf = storage->getBufferId(user, s->getNetwork(), nickFromMask(sender));
+    buf = storage->getBufferInfo(user, s->networkName(), nickFromMask(sender));
   } else {
-    buf = storage->getBufferId(user, s->getNetwork(), target);
+    buf = storage->getBufferInfo(user, s->networkName(), target);
   }
   Message msg(buf, type, text, sender, flags);
   msg.setMsgId(storage->logMessage(msg));
@@ -171,33 +174,41 @@ void CoreSession::recvMessageFromServer(Message::Type type, QString target, QStr
 void CoreSession::recvStatusMsgFromServer(QString msg) {
   Server *s = qobject_cast<Server*>(sender());
   Q_ASSERT(s);
-  emit displayStatusMsg(s->getNetwork(), msg);
+  emit displayStatusMsg(s->networkName(), msg);
 }
 
 
-QList<BufferId> CoreSession::buffers() const {
+uint CoreSession::getNetworkId(const QString &net) const {
+  return storage->getNetworkId(user, net);
+}
+
+QList<BufferInfo> CoreSession::buffers() const {
   return storage->requestBuffers(user);
 }
 
 
 QVariant CoreSession::sessionState() {
   QVariantMap v;
-  QList<QVariant> bufs;
-  foreach(BufferId id, storage->requestBuffers(user)) { bufs.append(QVariant::fromValue(id)); }
+
+  QVariantList bufs;
+  foreach(BufferInfo id, storage->requestBuffers(user))
+    bufs.append(QVariant::fromValue(id));
   v["Buffers"] = bufs;
+
   mutex.lock();
   v["SessionData"] = sessionData;
   mutex.unlock();
-  v["Networks"] = QVariant(servers.keys());
+
+  QVariantList networks;
+  foreach(uint networkid, servers.keys())
+    networks.append(QVariant(networkid));
+  v["Networks"] = QVariant(networks);
+
   // v["Payload"] = QByteArray(100000000, 'a');  // for testing purposes
   return v;
 }
 
-void CoreSession::sendServerStates() {
-  emit serverStateRequested();
-}
-
-void CoreSession::sendBacklog(BufferId id, QVariant v1, QVariant v2) {
+void CoreSession::sendBacklog(BufferInfo id, QVariant v1, QVariant v2) {
   QList<QVariant> log;
   QList<Message> msglist;
   if(v1.type() == QVariant::DateTime) {
index 66e2735..009a2ef 100644 (file)
@@ -34,63 +34,65 @@ class Storage;
 class CoreSession : public QObject {
   Q_OBJECT
 
-  public:
-    CoreSession(UserId, Storage *, QObject *parent = 0);
-    ~CoreSession();
-
-    QList<BufferId> buffers() const;
-    UserId userId() const;
-    QVariant sessionState();
-
-  public slots:
-    //! Store a piece session-wide data and distribute it to connected clients.
-    void storeSessionData(const QString &key, const QVariant &data);
-
-    void addClient(QIODevice *connection);
-
-  public:
-    //! Retrieve a piece of session-wide data.
-    QVariant retrieveSessionData(const QString &key, const QVariant &def = QVariant());
-
-    SignalProxy *signalProxy() const;
-
-  public slots:
-    void connectToNetwork(QString);
-    //void processSignal(ClientSignal, QVariant, QVariant, QVariant);
-    void sendBacklog(BufferId, QVariant, QVariant);
-    void msgFromGui(BufferId, QString message);
-    void sendServerStates();
-
-  signals:
-    void msgFromGui(QString net, QString buf, QString message);
-    void displayMsg(Message message);
-    void displayStatusMsg(QString, QString);
-
-    void connectToIrc(QString net);
-    void disconnectFromIrc(QString net);
-    void serverStateRequested();
-
-    void backlogData(BufferId, QVariantList, bool done);
-
-    void bufferIdUpdated(BufferId);
-    void sessionDataChanged(const QString &key);
-    void sessionDataChanged(const QString &key, const QVariant &data);
-
-  private slots:
-    void recvStatusMsgFromServer(QString msg);
-    void recvMessageFromServer(Message::Type, QString target, QString text, QString sender = "", quint8 flags = Message::None);
-    void serverConnected(QString net);
-    void serverDisconnected(QString net);
-
-  private:
-    UserId user;
-
-   SignalProxy *_signalProxy;
-    Storage *storage;
-    QHash<QString, Server *> servers;
-
-    QVariantMap sessionData;
-    QMutex mutex;
+public:
+  CoreSession(UserId, Storage *, QObject *parent = 0);
+  virtual ~CoreSession();
+
+  uint getNetworkId(const QString &network) const;
+  QList<BufferInfo> buffers() const;
+  UserId userId() const;
+  QVariant sessionState();
+
+  //! Retrieve a piece of session-wide data.
+  QVariant retrieveSessionData(const QString &key, const QVariant &def = QVariant());
+  
+  SignalProxy *signalProxy() const;
+                                 
+  void attachServer(Server *server);
+                                  
+public slots:
+  //! Store a piece session-wide data and distribute it to connected clients.
+  void storeSessionData(const QString &key, const QVariant &data);
+
+  void serverStateRequested();
+
+  void addClient(QIODevice *connection);
+  
+  void connectToNetwork(QString);
+  
+  //void processSignal(ClientSignal, QVariant, QVariant, QVariant);
+  void sendBacklog(BufferInfo, QVariant, QVariant);
+  void msgFromGui(BufferInfo, QString message);
+  
+signals:
+  void msgFromGui(uint netid, QString buf, QString message);
+  void displayMsg(Message message);
+  void displayStatusMsg(QString, QString);
+  
+  void connectToIrc(QString net);
+  void disconnectFromIrc(QString net);
+
+  void backlogData(BufferInfo, QVariantList, bool done);
+
+  void bufferInfoUpdated(BufferInfo);
+  void sessionDataChanged(const QString &key);
+  void sessionDataChanged(const QString &key, const QVariant &data);
+
+private slots:
+  void recvStatusMsgFromServer(QString msg);
+  void recvMessageFromServer(Message::Type, QString target, QString text, QString sender = "", quint8 flags = Message::None);
+  void serverConnected(uint networkid);
+  void serverDisconnected(uint networkid);
+
+private:
+  UserId user;
+  
+  SignalProxy *_signalProxy;
+  Storage *storage;
+  QHash<uint, Server *> servers;
+  
+  QVariantMap sessionData;
+  QMutex mutex;
 };
 
 #endif
diff --git a/src/core/ctcphandler.cpp b/src/core/ctcphandler.cpp
new file mode 100644 (file)
index 0000000..788055c
--- /dev/null
@@ -0,0 +1,155 @@
+/***************************************************************************
+ *   Copyright (C) 2005-07 by The Quassel Team                             *
+ *   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) any later version.                                   *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program; if not, write to the                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
+ ***************************************************************************/
+#include "ctcphandler.h"
+
+#include "util.h"
+#include "message.h"
+
+CtcpHandler::CtcpHandler(Server *parent)
+  : BasicHandler(parent) {
+
+  QString MQUOTE = QString('\020');
+  ctcpMDequoteHash[MQUOTE + '0'] = QString('\000');
+  ctcpMDequoteHash[MQUOTE + 'n'] = QString('\n');
+  ctcpMDequoteHash[MQUOTE + 'r'] = QString('\r');
+  ctcpMDequoteHash[MQUOTE + MQUOTE] = MQUOTE;
+
+  XDELIM = QString('\001');
+  QString XQUOTE = QString('\134');
+  ctcpXDelimDequoteHash[XQUOTE + XQUOTE] = XQUOTE;
+  ctcpXDelimDequoteHash[XQUOTE + QString('a')] = XDELIM;
+}
+
+QString CtcpHandler::dequote(QString message) {
+  QString dequotedMessage;
+  QString messagepart;
+  QHash<QString, QString>::iterator ctcpquote;
+  
+  // copy dequote Message
+  for(int i = 0; i < message.size(); i++) {
+    messagepart = message[i];
+    if(i+1 < message.size()) {
+      for(ctcpquote = ctcpMDequoteHash.begin(); ctcpquote != ctcpMDequoteHash.end(); ++ctcpquote) {
+        if(message.mid(i,2) == ctcpquote.key()) {
+          dequotedMessage += ctcpquote.value();
+          i++;
+          break;
+        }
+      }
+    }
+    dequotedMessage += messagepart;
+  }
+  return dequotedMessage;
+}
+
+
+QString CtcpHandler::XdelimDequote(QString message) {
+  QString dequotedMessage;
+  QString messagepart;
+  QHash<QString, QString>::iterator xdelimquote;
+
+  for(int i = 0; i < message.size(); i++) {
+    messagepart = message[i];
+    if(i+1 < message.size()) {
+      for(xdelimquote = ctcpXDelimDequoteHash.begin(); xdelimquote != ctcpXDelimDequoteHash.end(); ++xdelimquote) {
+        if(message.mid(i,2) == xdelimquote.key()) {
+          messagepart = xdelimquote.value();
+          i++;
+          break;
+        }
+      }
+    }
+    dequotedMessage += messagepart;
+  }
+  return dequotedMessage;
+}
+
+QStringList CtcpHandler::parse(CtcpType ctcptype, QString prefix, QString target, QString message) {
+  QStringList messages;
+  QString ctcp;
+  
+  //lowlevel message dequote
+  QString dequotedMessage = dequote(message);
+  
+  // extract tagged / extended data
+  while(dequotedMessage.contains(XDELIM)) {
+    messages << dequotedMessage.section(XDELIM,0,0);
+    ctcp = XdelimDequote(dequotedMessage.section(XDELIM,1,1));
+    dequotedMessage = dequotedMessage.section(XDELIM,2,2);
+    
+    //dispatch the ctcp command
+    QString ctcpcmd = ctcp.section(' ', 0, 0);
+    QString ctcpparam = ctcp.section(' ', 1);
+
+    handle(ctcpcmd, Q_ARG(CtcpType, ctcptype), Q_ARG(QString, prefix), Q_ARG(QString, target), Q_ARG(QString, ctcpparam));
+  }
+  if(!dequotedMessage.isEmpty()) {
+    messages << dequotedMessage;
+  }
+  return messages;
+}
+
+QString CtcpHandler::pack(QString ctcpTag, QString message) {
+  return XDELIM + ctcpTag + ' ' + message + XDELIM;
+}
+
+void CtcpHandler::query(QString bufname, QString ctcpTag, QString message) {
+  QStringList params;
+  params << bufname << pack(ctcpTag, message);
+  emit putCmd("PRIVMSG", params); 
+}
+
+void CtcpHandler::reply(QString bufname, QString ctcpTag, QString message) {
+  QStringList params;
+  params << bufname << pack(ctcpTag, message);
+  emit putCmd("NOTICE", params);
+}
+
+//******************************/
+// CTCP HANDLER
+//******************************/
+void CtcpHandler::handleAction(CtcpType ctcptype, QString prefix, QString target, QString param) {
+  emit displayMsg(Message::Action, target, param, prefix);
+}
+
+void CtcpHandler::handlePing(CtcpType ctcptype, QString prefix, QString target, QString param) {
+  if(ctcptype == CtcpQuery) {
+    reply(nickFromMask(prefix), "PING", param);
+    emit displayMsg(Message::Server, "", tr("Received CTCP PING request from %1").arg(prefix));
+  } else {
+    // display ping answer
+  }
+}
+
+void CtcpHandler::handleVersion(CtcpType ctcptype, QString prefix, QString target, QString param) {
+  if(ctcptype == CtcpQuery) {
+    // FIXME use real Info about quassel :)
+    reply(nickFromMask(prefix), "VERSION", QString("Quassel IRC (Pre-Release) - http://www.quassel-irc.org"));
+    emit displayMsg(Message::Server, "", tr("Received CTCP VERSION request by %1").arg(prefix));
+  } else {
+    // TODO display Version answer
+  }
+}
+
+void CtcpHandler::defaultHandler(QString cmd, CtcpType ctcptype, QString prefix, QString target, QString param) {
+  emit displayMsg(Message::Error, "", tr("Received unknown CTCP %1 by %2").arg(cmd).arg(prefix));
+}
+
+
diff --git a/src/core/ctcphandler.h b/src/core/ctcphandler.h
new file mode 100644 (file)
index 0000000..9cb2c78
--- /dev/null
@@ -0,0 +1,62 @@
+/***************************************************************************
+ *   Copyright (C) 2005/06 by The Quassel Team                             *
+ *   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) any later version.                                   *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program; if not, write to the                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
+ ***************************************************************************/
+
+#ifndef _CTCPHANDLER_H_
+#define _CTCPHANDLER_H_
+
+#include <QHash>
+#include <QStringList>
+
+#include "basichandler.h"
+
+class CtcpHandler : public BasicHandler {
+  Q_OBJECT
+
+public:
+  CtcpHandler(Server *parent = 0);
+
+  enum CtcpType {CtcpQuery, CtcpReply};
+
+  QStringList parse(CtcpType, QString, QString, QString);    
+
+  QString dequote(QString);
+  QString XdelimDequote(QString);
+
+  QString pack(QString ctcpTag, QString message);
+  void query(QString bufname, QString ctcpTag, QString message);
+  void reply(QString bufname, QString ctcpTag, QString message);
+  
+public slots:
+  void handleAction(CtcpType, QString prefix, QString target, QString param);
+  void handlePing(CtcpType, QString prefix, QString target, QString param);
+  void handleVersion(CtcpType, QString prefix, QString target, QString param);
+
+  void defaultHandler(QString cmd, CtcpType ctcptype, QString prefix, QString target, QString param);
+
+private:
+  QString XDELIM;
+  QHash<QString, QString> ctcpMDequoteHash;
+  QHash<QString, QString> ctcpXDelimDequoteHash;    
+
+
+};
+
+
+#endif
diff --git a/src/core/ircserverhandler.cpp b/src/core/ircserverhandler.cpp
new file mode 100644 (file)
index 0000000..ab5c85c
--- /dev/null
@@ -0,0 +1,428 @@
+/***************************************************************************
+ *   Copyright (C) 2005-07 by The Quassel Team                             *
+ *   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) any later version.                                   *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program; if not, write to the                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
+ ***************************************************************************/
+#include "ircserverhandler.h"
+
+#include "util.h"
+
+#include "server.h"
+#include "networkinfo.h"
+#include "ctcphandler.h"
+
+#include "ircuser.h"
+#include "ircchannel.h"
+
+#include <QDebug>
+
+IrcServerHandler::IrcServerHandler(Server *parent)
+  : BasicHandler(parent) {
+}
+
+IrcServerHandler::~IrcServerHandler() {
+}
+
+/*! Handle a raw message string sent by the server. We try to find a suitable handler, otherwise we call a default handler. */
+void IrcServerHandler::handleServerMsg(QByteArray rawmsg) {
+  try {
+    if(rawmsg.isEmpty()) {
+      qWarning() << "Received empty string from server!";
+      return;
+    }
+    // TODO Implement encoding conversion
+    /* At this point, we have a raw message as a byte array. This needs to be converted to a QString somewhere.
+     * Problem is, that at this point we don't know which encoding to use for the various parts of the message.
+     * This is something the command handler needs to take care of (e.g. PRIVMSG needs to first parse for CTCP,
+     * and then convert the raw strings into the correct encoding.
+     * We _can_ safely assume Server encoding for prefix and cmd, but not for the params. Therefore, we need to
+     * change from a QStringList to a QList<QByteArray> in all the handlers, and have the handlers call decodeString
+     * where needed...
+    */
+    QString msg = QString::fromLatin1(rawmsg);
+
+    // OK, first we split the raw message into its various parts...
+    QString prefix = "";
+    QString cmd;
+    QStringList params;
+
+    // a colon as the first chars indicates the existance of a prefix
+    if(msg[0] == ':') {
+      msg.remove(0,1);
+      prefix = msg.section(' ', 0, 0);
+      msg = msg.section(' ', 1);
+    }
+
+    // next string without a whitespace is the command
+    cmd = msg.section(' ', 0, 0).toUpper();
+    msg = msg.mid(cmd.length());
+
+    // get the parameters
+    QString trailing = "";
+    if(msg.contains(" :")) {
+      trailing = msg.section(" :", 1);
+      msg = msg.section(" :", 0, 0);
+    }
+    if(!msg.isEmpty()) {
+      params << msg.split(' ', QString::SkipEmptyParts);
+    }
+    if(!trailing.isEmpty()) {
+      params << trailing;
+    }
+
+    // numeric replies have the target as first param (RFC 2812 - 2.4). this is usually our own nick. Remove this!
+    uint num = cmd.toUInt();
+    if(num > 0) {
+      Q_ASSERT(params.count() > 0); // Violation to RFC
+      params.removeFirst();
+    }
+
+    // Now we try to find a handler for this message. BTW, I do love the Trolltech guys ;-)
+    handle(cmd, Q_ARG(QString, prefix), Q_ARG(QStringList, params));
+    //handle(cmd, Q_ARG(QString, prefix));
+  } catch(Exception e) {
+    emit displayMsg(Message::Error, "", e.msg());
+  }
+}
+
+
+void IrcServerHandler::defaultHandler(QString cmd, QString prefix, QStringList params) {
+  uint num = cmd.toUInt();
+  if(num) {
+    // A lot of server messages don't really need their own handler because they don't do much.
+    // Catch and handle these here.
+    switch(num) {
+      // Welcome, status, info messages. Just display these.
+      case 2: case 3: case 4: case 5: case 251: case 252: case 253: case 254: case 255: case 372: case 375:
+        emit displayMsg(Message::Server, "", params.join(" "), prefix);
+        break;
+      // Server error messages without param, just display them
+      case 409: case 411: case 412: case 422: case 424: case 445: case 446: case 451: case 462:
+      case 463: case 464: case 465: case 466: case 472: case 481: case 483: case 485: case 491: case 501: case 502:
+      case 431: // ERR_NONICKNAMEGIVEN 
+        emit displayMsg(Message::Error, "", params.join(" "), prefix);
+        break;
+      // Server error messages, display them in red. First param will be appended.
+      case 401: case 402: case 403: case 404: case 406: case 408: case 415: case 421: case 442:
+      { QString p = params.takeFirst();
+        emit displayMsg(Message::Error, "", params.join(" ") + " " + p, prefix);
+        break;
+      }
+      // Server error messages which will be displayed with a colon between the first param and the rest
+      case 413: case 414: case 423: case 441: case 444: case 461:
+      case 467: case 471: case 473: case 474: case 475: case 476: case 477: case 478: case 482:
+      case 436: // ERR_NICKCOLLISION
+      { QString p = params.takeFirst();
+        emit displayMsg(Message::Error, "", p + ": " + params.join(" "));
+        break;
+      }
+      // Ignore these commands.
+      case 366: case 376:
+        break;
+
+      // Everything else will be marked in red, so we can add them somewhere.
+      default:
+        emit displayMsg(Message::Error, "", cmd + " " + params.join(" "), prefix);
+    }
+    //qDebug() << prefix <<":"<<cmd<<params;
+  } else {
+    emit displayMsg(Message::Error, "", QString("Unknown: ") + cmd + " " + params.join(" "), prefix);
+    //qDebug() << prefix <<":"<<cmd<<params;
+  }
+}
+
+//******************************/
+// IRC SERVER HANDLER
+//******************************/
+void IrcServerHandler::handleJoin(QString prefix, QStringList params) {
+  Q_ASSERT(params.count() == 1);
+  QString channel = params[0];
+  IrcUser *ircuser = networkInfo()->updateNickFromMask(prefix);
+  emit displayMsg(Message::Join, channel, channel, prefix);
+
+  ircuser->joinChannel(channel);
+}
+
+void IrcServerHandler::handleKick(QString prefix, QStringList params) {
+  networkInfo()->updateNickFromMask(prefix);
+  IrcUser *victim = networkInfo()->ircUser(params[1]);
+  QString channel = params[0];
+  Q_ASSERT(victim);
+
+  victim->partChannel(channel);
+
+  QString msg;
+  if(params.count() > 2) // someone got a reason!
+    msg = QString("%1 %2").arg(victim->nick()).arg(params[2]);
+  else
+    msg = victim->nick();
+  
+  emit displayMsg(Message::Kick, params[0], msg, prefix);
+}
+
+void IrcServerHandler::handleMode(QString prefix, QStringList params) {
+//   if(isChannelName(params[0])) {
+//     // TODO only channel-user modes supported by now
+//     QString prefixes = serverSupports["PrefixModes"].toString();
+//     QString modes = params[1];
+//     int p = 2;
+//     int m = 0;
+//     bool add = true;
+//     while(m < modes.length()) {
+//       if(modes[m] == '+') { add = true; m++; continue; }
+//       if(modes[m] == '-') { add = false; m++; continue; }
+//       if(prefixes.contains(modes[m])) {  // it's a user channel mode
+//         Q_ASSERT(params.count() > m);
+//         QString nick = params[p++];
+//         if(nicks.contains(nick)) {  // sometimes, a server might try to set a MODE on a nick that is no longer there
+//           QVariantMap n = nicks[nick]; QVariantMap clist = n["Channels"].toMap(); QVariantMap chan = clist[params[0]].toMap();
+//           QString mstr = chan["Mode"].toString();
+//           add ? mstr += modes[m] : mstr.remove(modes[m]);
+//           chan["Mode"] = mstr; clist[params[0]] = chan; n["Channels"] = clist; nicks[nick] = n;
+//           emit nickUpdated(network, nick, n);
+//         }
+//         m++;
+//       } else {
+//         // TODO add more modes
+//         m++;
+//       }
+//     }
+//     emit displayMsg(Message::Mode, params[0], params.join(" "), prefix);
+//   } else {
+//     //Q_ASSERT(nicks.contains(params[0]));
+//     //QVariantMap n = nicks[params[0]].toMap();
+//     //QString mode = n["Mode"].toString();
+//     emit displayMsg(Message::Mode, "", params.join(" "));
+//   }
+}
+
+void IrcServerHandler::handleNick(QString prefix, QStringList params) {
+  IrcUser *ircuser = networkInfo()->updateNickFromMask(prefix);
+  Q_ASSERT(ircuser);
+  QString newnick = params[0];
+  QString oldnick = ircuser->nick();
+
+  foreach(QString channel, ircuser->channels()) {
+    if(networkInfo()->isMyNick(oldnick))
+      emit displayMsg(Message::Nick, channel, newnick, prefix);
+    else
+      emit displayMsg(Message::Nick, channel, newnick, newnick);
+  }
+  ircuser->setNick(newnick);
+}
+
+void IrcServerHandler::handleNotice(QString prefix, QStringList params) {
+  if(networkInfo()->currentServer().isEmpty() || networkInfo()->currentServer() == prefix)
+    emit displayMsg(Message::Server, "", params[1], prefix);
+  else
+    emit displayMsg(Message::Notice, "", params[1], prefix);
+}
+
+void IrcServerHandler::handlePart(QString prefix, QStringList params) {
+  IrcUser *ircuser = networkInfo()->updateNickFromMask(prefix);
+  QString channel = params[0];
+  Q_ASSERT(ircuser);
+  
+  ircuser->partChannel(channel);
+  
+  QString msg;
+  if(params.count() > 1)
+    msg = params[1];
+  
+  emit displayMsg(Message::Part, params[0], msg, prefix);
+}
+
+void IrcServerHandler::handlePing(QString prefix, QStringList params) {
+  emit putCmd("PONG", params);
+}
+
+void IrcServerHandler::handlePrivmsg(QString prefix, QStringList params) {
+  networkInfo()->updateNickFromMask(prefix);
+  Q_ASSERT(params.count() >= 2);
+  if(params.count()<2)
+    emit displayMsg(Message::Plain, params[0], "", prefix);
+  else {
+    // it's possible to pack multiple privmsgs into one param using ctcp
+    QStringList messages = server->ctcpHandler()->parse(CtcpHandler::CtcpQuery, prefix, params[0], params[1]);
+
+    // are we the target or is it a channel?
+    if(networkInfo()->isMyNick(params[0])) {
+      foreach(QString message, messages) {
+        if(!message.isEmpty()) {
+          emit displayMsg(Message::Plain, "", message, prefix, Message::PrivMsg);
+        }
+      }
+   
+    } else {
+      Q_ASSERT(isChannelName(params[0]));  // should be channel!
+      foreach(QString message, messages) {
+        if(!message.isEmpty()) {
+          emit displayMsg(Message::Plain, params[0], message, prefix);
+        }
+      }
+    }
+  }
+}
+
+void IrcServerHandler::handleQuit(QString prefix, QStringList params) {
+  IrcUser *ircuser = networkInfo()->updateNickFromMask(prefix);
+  Q_ASSERT(ircuser);
+
+  QString msg;
+  if(params.count())
+    msg = params[0];
+  
+  foreach(QString channel, ircuser->channels())
+    emit displayMsg(Message::Quit, channel, msg, prefix);
+
+  ircuser->deleteLater();
+}
+
+void IrcServerHandler::handleTopic(QString prefix, QStringList params) {
+  IrcUser *ircuser = networkInfo()->updateNickFromMask(prefix);
+  QString channel = params[0];
+  QString topic = params[1];
+  Q_ASSERT(ircuser);
+
+  networkInfo()->ircChannel(channel)->setTopic(topic);
+
+  emit displayMsg(Message::Server, params[0], tr("%1 has changed topic for %2 to: \"%3\"").arg(ircuser->nick()).arg(channel).arg(topic));
+}
+
+/* RPL_WELCOME */
+void IrcServerHandler::handle001(QString prefix, QStringList params) {
+  // there should be only one param: "Welcome to the Internet Relay Network <nick>!<user>@<host>"
+  QString myhostmask = params[0].section(' ', -1, -1);
+  networkInfo()->setCurrentServer(prefix);
+  networkInfo()->setMyNick(nickFromMask(myhostmask));
+
+  emit displayMsg(Message::Server, "", params[0], prefix);
+
+  // TODO: reimplement perform List!
+  //// send performlist
+  //QStringList performList = networkSettings["Perform"].toString().split( "\n" );
+  //int count = performList.count();
+  //for(int a = 0; a < count; a++) {
+  //  if(!performList[a].isEmpty() ) {
+  //    userInput(network, "", performList[a]);
+  //  }
+  //}
+}
+
+/* RPL_ISUPPORT */
+// TODO Complete 005 handling, also use sensible defaults for non-sent stuff
+void IrcServerHandler::handle005(QString prefix, QStringList params) {
+  QString rpl_isupport_suffix = params.takeLast();
+  if(rpl_isupport_suffix.toLower() != QString("are supported by this server")) {
+    qWarning() << "Received invalid RPL_ISUPPORT! Suffix is:" << rpl_isupport_suffix << "Excpected: are supported by this server";
+    return;
+  }
+  
+  foreach(QString param, params) {
+    QString key = param.section("=", 0, 0);
+    QString value = param.section("=", 1);
+    networkInfo()->addSupport(key, value);
+  }
+}
+
+
+/* RPL_NOTOPIC */
+void IrcServerHandler::handle331(QString prefix, QStringList params) {
+  networkInfo()->ircChannel(params[0])->setTopic(QString());
+  emit displayMsg(Message::Server, params[0], tr("No topic is set for %1.").arg(params[0]));
+}
+
+/* RPL_TOPIC */
+void IrcServerHandler::handle332(QString prefix, QStringList params) {
+  networkInfo()->ircChannel(params[0])->setTopic(params[1]);
+  emit displayMsg(Message::Server, params[0], tr("Topic for %1 is \"%2\"").arg(params[0]).arg(params[1]));
+}
+
+/* Topic set by... */
+void IrcServerHandler::handle333(QString prefix, QStringList params) {
+  emit displayMsg(Message::Server, params[0], tr("Topic set by %1 on %2").arg(params[1]).arg(QDateTime::fromTime_t(params[2].toUInt()).toString()));
+}
+
+/* RPL_NAMREPLY */
+void IrcServerHandler::handle353(QString prefix, QStringList params) {
+  params.removeFirst(); // either "=", "*" or "@" indicating a public, private or secret channel
+  QString channelname = params.takeFirst();
+
+  foreach(QString nick, params.takeFirst().split(' ')) {
+    QString mode = QString();
+
+    if(networkInfo()->prefixes().contains(nick[0])) {
+      mode = networkInfo()->prefixToMode(nick[0]);
+      nick = nick.mid(1);
+    }
+    
+    IrcUser *ircuser = networkInfo()->newIrcUser(nick);
+    ircuser->joinChannel(channelname);
+
+    if(!mode.isNull())
+      networkInfo()->ircChannel(channelname)->addUserMode(ircuser, mode);
+  }
+}
+
+/* ERR_ERRONEUSNICKNAME */
+void IrcServerHandler::handle432(QString prefix, QStringList params) {
+//   if(params.size() < 2) {
+//     // handle unreal-ircd bug, where unreal ircd doesnt supply a TARGET in ERR_ERRONEUSNICKNAME during registration phase:
+//     // nick @@@
+//     // :irc.scortum.moep.net 432  @@@ :Erroneous Nickname: Illegal characters
+//     // correct server reply:
+//     // :irc.scortum.moep.net 432 * @@@ :Erroneous Nickname: Illegal characters
+//     emit displayMsg(Message::Error, "", tr("There is a nickname in your identity's nicklist which contains illegal characters"));
+//     emit displayMsg(Message::Error, "", tr("Due to a bug in Unreal IRCd (and maybe other irc-servers too) we're unable to determine the erroneous nick"));
+//     emit displayMsg(Message::Error, "", tr("Please use: /nick <othernick> to continue or clean up your nicklist"));
+//   } else {
+//     QString errnick = params[0];
+//     emit displayMsg(Message::Error, "", tr("Nick %1 contains illegal characters").arg(errnick));
+//     // if there is a problem while connecting to the server -> we handle it
+//     // TODO rely on another source...
+//     if(currentServer.isEmpty()) {
+//       QStringList desiredNicks = identity["NickList"].toStringList();
+//       int nextNick = desiredNicks.indexOf(errnick) + 1;
+//       if (desiredNicks.size() > nextNick) {
+//         putCmd("NICK", QStringList(desiredNicks[nextNick]));
+//       } else {
+//         emit displayMsg(Message::Error, "", tr("No free and valid nicks in nicklist found. use: /nick <othernick> to continue"));
+//       }
+//     }
+//   }
+}
+
+/* ERR_NICKNAMEINUSE */
+void IrcServerHandler::handle433(QString prefix, QStringList params) {
+//   QString errnick = params[0];
+//   emit displayMsg(Message::Error, "", tr("Nick %1 is already taken").arg(errnick));
+//   // if there is a problem while connecting to the server -> we handle it
+//   // TODO rely on another source...
+//   if(currentServer.isEmpty()) {
+//     QStringList desiredNicks = identity["NickList"].toStringList();
+//     int nextNick = desiredNicks.indexOf(errnick) + 1;
+//     if (desiredNicks.size() > nextNick) {
+//       putCmd("NICK", QStringList(desiredNicks[nextNick]));
+//     } else {
+//       emit displayMsg(Message::Error, "", tr("No free and valid nicks in nicklist found. use: /nick <othernick> to continue"));
+//     }
+//   }
+}
+
+/***********************************************************************************/
+
+
diff --git a/src/core/ircserverhandler.h b/src/core/ircserverhandler.h
new file mode 100644 (file)
index 0000000..fe7f4f2
--- /dev/null
@@ -0,0 +1,60 @@
+/***************************************************************************
+ *   Copyright (C) 2005/06 by The Quassel Team                             *
+ *   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) any later version.                                   *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program; if not, write to the                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
+ ***************************************************************************/
+
+#ifndef _IRCSERVERHANDLER_H_
+#define _IRCSERVERHANDLER_H_
+
+#include "basichandler.h"
+
+class IrcServerHandler : public BasicHandler {
+  Q_OBJECT
+
+public:
+  IrcServerHandler(Server *parent = 0);
+  ~IrcServerHandler();
+
+  void handleServerMsg(QByteArray rawMsg);
+  
+public slots:
+  void handleJoin(QString, QStringList);
+  void handleKick(QString, QStringList);
+  void handleMode(QString, QStringList);
+  void handleNick(QString, QStringList);
+  void handleNotice(QString, QStringList);
+  void handlePart(QString, QStringList);
+  void handlePing(QString, QStringList);
+  void handlePrivmsg(QString, QStringList);
+  void handleQuit(QString, QStringList);
+  void handleTopic(QString, QStringList);
+
+  void handle001(QString, QStringList);   // RPL_WELCOME
+  void handle005(QString, QStringList);   // RPL_ISUPPORT
+  void handle331(QString, QStringList);   // RPL_NOTOPIC
+  void handle332(QString, QStringList);   // RPL_TOPIC
+  void handle333(QString, QStringList);   // Topic set by...
+  void handle353(QString, QStringList);   // RPL_NAMREPLY
+  void handle432(QString, QStringList);   // ERR_ERRONEUSNICKNAME
+  void handle433(QString, QStringList);   // ERR_NICKNAMEINUSE
+
+  void defaultHandler(QString cmd, QString prefix, QStringList params);
+};
+
+
+#endif
index 9123801..3af2119 100644 (file)
 #include "core.h"
 #include "coresession.h"
 
-Server::Server(UserId uid, QString net) : user(uid), network(net) {
-  QString MQUOTE = QString('\020');
-  ctcpMDequoteHash[MQUOTE + '0'] = QString('\000');
-  ctcpMDequoteHash[MQUOTE + 'n'] = QString('\n');
-  ctcpMDequoteHash[MQUOTE + 'r'] = QString('\r');
-  ctcpMDequoteHash[MQUOTE + MQUOTE] = MQUOTE;
+#include "networkinfo.h"
+#include "synchronizer.h"
 
-  XDELIM = QString('\001');
-  QString XQUOTE = QString('\134');
-  ctcpXDelimDequoteHash[XQUOTE + XQUOTE] = XQUOTE;
-  ctcpXDelimDequoteHash[XQUOTE + QString('a')] = XDELIM;
-  
-  serverinfo = new ServerInfo();
+#include "ircserverhandler.h"
+#include "userinputhandler.h"
+#include "ctcphandler.h"
+
+Server::Server(UserId uid, uint networkId, QString net)
+  : _userId(uid),
+    _networkId(networkId),
+    _ircServerHandler(new IrcServerHandler(this)),
+    _userInputHandler(new UserInputHandler(this)),
+    _ctcpHandler(new CtcpHandler(this)),
+    _networkInfo(new NetworkInfo(networkId, coreSession()->signalProxy(), this))
+{
+  networkInfo()->setNetworkName(net);
 }
 
 Server::~Server() {
-  delete serverinfo;
+  delete _ircServerHandler;
+  delete _userInputHandler;
+  delete _ctcpHandler;
 }
 
 void Server::run() {
@@ -56,25 +61,15 @@ void Server::run() {
   exec();
 }
 
-void Server::sendState() {
-  QVariantMap s;
-  QVariantMap n, t;
-  foreach(QString key, nicks.keys())  { n[key] = nicks[key]; }
-  foreach(QString key, topics.keys()) { t[key] = topics[key];}
-  s["Nicks"] = n;
-  s["Topics"] = t;
-  s["OwnNick"] = ownNick;
-  s["ServerSupports"] = serverSupports;
-  emit serverState(network, s);
-}
-
 void Server::connectToIrc(QString net) {
-  if(net != network) return; // not me!
-  CoreSession *sess = Core::session(user);
-  //networkSettings = Global::data(user, "Networks").toMap()[net].toMap();
+  if(net != networkName())
+    return; // not me!
+  
+  CoreSession *sess = coreSession();
   networkSettings = sess->retrieveSessionData("Networks").toMap()[net].toMap();
-  //identity = Global::data(user, "Identities").toMap()[networkSettings["Identity"].toString()].toMap();
   identity = sess->retrieveSessionData("Identities").toMap()[networkSettings["Identity"].toString()].toMap();
+
+  //FIXME this will result in a pretty fuckup if there are no servers in the list
   QList<QVariant> servers = networkSettings["Servers"].toList();
   QString host = servers[0].toMap()["Address"].toString();
   quint16 port = servers[0].toMap()["Port"].toUInt();
@@ -83,841 +78,81 @@ void Server::connectToIrc(QString net) {
 }
 
 void Server::disconnectFromIrc(QString net) {
-  if(net != network) return; // not me!
+  if(net != networkName())
+    return; // not me!
   socket.disconnectFromHost();
 }
 
 void Server::socketHasData() {
   while(socket.canReadLine()) {
     QByteArray s = socket.readLine().trimmed();
-    //qDebug() << "Read" << s;
-    //emit recvRawServerMsg(s); // signal not needed, and we should make sure we consider encodings where we need them
-    //Message *msg = Message::createFromServerString(this, s);
-    handleServerMsg(s);
+    ircServerHandler()->handleServerMsg(s);
   }
 }
 
 void Server::socketError( QAbstractSocket::SocketError err ) {
   //qDebug() << "Socket Error!";
-  //emit error(err);
 }
 
 void Server::socketConnected( ) {
-  emit connected(network);
+  emit connected(networkId());
   putRawLine(QString("NICK :%1").arg(identity["NickList"].toStringList()[0]));  // FIXME: try more nicks if error occurs
   putRawLine(QString("USER %1 8 * :%2").arg(identity["Ident"].toString()).arg(identity["RealName"].toString()));
 }
 
 void Server::socketDisconnected( ) {
-  //qDebug() << "Socket disconnected!";
-  emit disconnected(network);
-  topics.clear();
-  nicks.clear();
+  emit disconnected(networkId());
+  // propagate to networkInfo, so we can clear up
 }
 
 void Server::socketStateChanged(QAbstractSocket::SocketState state) {
   //qDebug() << "Socket state changed: " << state;
 }
 
-QString Server::updateNickFromMask(QString mask) {
-  QString user = userFromMask(mask);
-  QString host = hostFromMask(mask);
-  QString nick = nickFromMask(mask);
-  if(nicks.contains(nick) && !user.isEmpty() && !host.isEmpty()) {
-    QVariantMap n = nicks[nick];
-    if(n["User"].toString() != user || n["Host"].toString() != host) {
-      if(!n["User"].toString().isEmpty() || !n["Host"].toString().isEmpty())
-        qWarning(QString("Strange: Hostmask for nick %1 has changed!").arg(nick).toAscii());
-      n["User"] = user; n["Host"] = host;
-      nicks[nick] = n;
-      emit nickUpdated(network, nick, n);
-    }
-  }
-  return nick;
-}
-
-void Server::userInput(QString net, QString buf, QString msg) {
-  if(net != network) return; // not me!
-  //msg = msg.trimmed(); // remove whitespace from start and end
-  if(msg.isEmpty()) return;
-  if(!msg.startsWith('/')) {
-    msg = QString("/SAY ") + msg;
-  }
-  handleUserInput(buf, msg);
+void Server::userInput(uint netid, QString buf, QString msg) {
+  if(netid != networkId())
+    return; // not me!
+  userInputHandler()->handleUserInput(buf, msg);
 }
 
 void Server::putRawLine(QString s) {
-//  qDebug() << "SentRaw: " << s;
   s += "\r\n";
   socket.write(s.toAscii());
 }
 
 void Server::putCmd(QString cmd, QStringList params, QString prefix) {
-  QString m;
-  if(!prefix.isEmpty()) m += ":" + prefix + " ";
-  m += cmd.toUpper();
-  for(int i = 0; i < params.size() - 1; i++) {
-    m += " " + params[i];
-  }
-  if(!params.isEmpty()) m += " :" + params.last();
-//  qDebug() << "Sent: " << m;
-  m += "\r\n";
-  socket.write(m.toAscii());
-}
-
-/*! Handle a raw message string sent by the server. We try to find a suitable handler, otherwise we call a default handler. */
-void Server::handleServerMsg(QByteArray rawmsg) {
-  try {
-    if(rawmsg.isEmpty()) {
-      qWarning() << "Received empty string from server!";
-      return;
-    }
-    // TODO Implement encoding conversion
-    /* At this point, we have a raw message as a byte array. This needs to be converted to a QString somewhere.
-     * Problem is, that at this point we don't know which encoding to use for the various parts of the message.
-     * This is something the command handler needs to take care of (e.g. PRIVMSG needs to first parse for CTCP,
-     * and then convert the raw strings into the correct encoding.
-     * We _can_ safely assume Server encoding for prefix and cmd, but not for the params. Therefore, we need to
-     * change from a QStringList to a QList<QByteArray> in all the handlers, and have the handlers call decodeString
-     * where needed...
-    */
-    QString msg = QString::fromLatin1(rawmsg);
-
-    // OK, first we split the raw message into its various parts...
-    QString prefix = "";
-    QString cmd;
-    QStringList params;
-
-    // check for prefix by checking for a colon as the first char
-    if(msg[0] == ':') {
-      msg.remove(0,1);
-      prefix = msg.section(' ', 0, 0);
-      msg = msg.section(' ', 1);
-    }
-
-    // next string without a whitespace is the command
-    cmd = msg.section(' ', 0, 0).toUpper();
-    msg = msg.mid(cmd.length());
-
-    // get the parameters
-    QString trailing = "";
-    if(msg.contains(" :")) {
-      trailing = msg.section(" :", 1);
-      msg = msg.section(" :", 0, 0);
-    }
-    if(!msg.isEmpty()) {
-      params << msg.split(' ', QString::SkipEmptyParts);
-    }
-    if(!trailing.isEmpty()) {
-      params << trailing;
-    }
-
-    // numeric replies have the target as first param (RFC 2812 - 2.4). this is usually our own nick. Remove this!
-    uint num = cmd.toUInt();
-    if(num > 0) {
-      Q_ASSERT(params.count() > 0); // Violation to RFC
-      params.removeFirst();
-    }
-
-    // Now we try to find a handler for this message. BTW, I do love the Trolltech guys ;-)
-    QString hname = cmd.toLower();
-    hname[0] = hname[0].toUpper();
-    hname = "handleServer" + hname;
-    if(!QMetaObject::invokeMethod(this, hname.toAscii(), Q_ARG(QString, prefix), Q_ARG(QStringList, params))) {
-      // Ok. Default handler it is.
-      defaultServerHandler(cmd, prefix, params);
-    }
-  } catch(Exception e) {
-    emit displayMsg(Message::Error, "", e.msg());
-  }
-}
-
-void Server::defaultServerHandler(QString cmd, QString prefix, QStringList params) {
-  uint num = cmd.toUInt();
-  if(num) {
-    // A lot of server messages don't really need their own handler because they don't do much.
-    // Catch and handle these here.
-    switch(num) {
-      // Welcome, status, info messages. Just display these.
-      case 2: case 3: case 4: case 5: case 251: case 252: case 253: case 254: case 255: case 372: case 375:
-        emit displayMsg(Message::Server, "", params.join(" "), prefix);
-        break;
-      // Server error messages without param, just display them
-      case 409: case 411: case 412: case 422: case 424: case 445: case 446: case 451: case 462:
-      case 463: case 464: case 465: case 466: case 472: case 481: case 483: case 485: case 491: case 501: case 502:
-      case 431: // ERR_NONICKNAMEGIVEN 
-        emit displayMsg(Message::Error, "", params.join(" "), prefix);
-        break;
-      // Server error messages, display them in red. First param will be appended.
-      case 401: case 402: case 403: case 404: case 406: case 408: case 415: case 421: case 442:
-      { QString p = params.takeFirst();
-        emit displayMsg(Message::Error, "", params.join(" ") + " " + p, prefix);
-        break;
-      }
-      // Server error messages which will be displayed with a colon between the first param and the rest
-      case 413: case 414: case 423: case 441: case 444: case 461:
-      case 467: case 471: case 473: case 474: case 475: case 476: case 477: case 478: case 482:
-      case 436: // ERR_NICKCOLLISION
-      { QString p = params.takeFirst();
-        emit displayMsg(Message::Error, "", p + ": " + params.join(" "));
-        break;
-      }
-      // Ignore these commands.
-      case 366: case 376:
-        break;
-
-      // Everything else will be marked in red, so we can add them somewhere.
-      default:
-        emit displayMsg(Message::Error, "", cmd + " " + params.join(" "), prefix);
-    }
-    //qDebug() << prefix <<":"<<cmd<<params;
-  } else {
-    emit displayMsg(Message::Error, "", QString("Unknown: ") + cmd + " " + params.join(" "), prefix);
-    //qDebug() << prefix <<":"<<cmd<<params;
-  }
-}
-
-void Server::handleUserInput(QString bufname, QString usrMsg) {
-  try {
-    /* Looks like we don't need core-side buffers...
-    Buffer *buffer = 0;
-    if(!bufname.isEmpty()) {
-      Q_ASSERT(buffers.contains(bufname));
-      buffer = buffers[bufname];
-    }
-    */
-    QString cmd = usrMsg.section(' ', 0, 0).remove(0, 1).toUpper();
-    QString msg = usrMsg.section(' ', 1);
-    QString hname = cmd.toLower();
-    hname[0] = hname[0].toUpper();
-    hname = "handleUser" + hname;
-    if(!QMetaObject::invokeMethod(this, hname.toAscii(), Q_ARG(QString, bufname), Q_ARG(QString, msg))) {
-        // Ok. Default handler it is.
-      defaultUserHandler(bufname, cmd, msg);
-    }
-  } catch(Exception e) {
-    emit displayMsg(Message::Error, "", e.msg());
-  }
-}
-
-void Server::defaultUserHandler(QString bufname, QString cmd, QString msg) {
-  emit displayMsg(Message::Error, "", QString("Error: %1 %2").arg(cmd).arg(msg));
-
-}
-
-QStringList Server::providesUserHandlers() {
-  QStringList userHandlers;
-  for(int i=0; i < metaObject()->methodCount(); i++) {
-    QString methodSignature(metaObject()->method(i).signature());
-    if (methodSignature.startsWith("handleUser")) {
-      methodSignature = methodSignature.section('(',0,0);  // chop the attribute list
-      methodSignature = methodSignature.mid(10); // strip "handleUser"
-      userHandlers << methodSignature;
-    }
-  }
-  return userHandlers;
-}
-
-QString Server::ctcpDequote(QString message) {
-  QString dequotedMessage;
-  QString messagepart;
-  QHash<QString, QString>::iterator ctcpquote;
-  
-  // copy dequote Message
-  for(int i = 0; i < message.size(); i++) {
-    messagepart = message[i];
-    if(i+1 < message.size()) {
-      for(ctcpquote = ctcpMDequoteHash.begin(); ctcpquote != ctcpMDequoteHash.end(); ++ctcpquote) {
-        if(message.mid(i,2) == ctcpquote.key()) {
-          dequotedMessage += ctcpquote.value();
-          i++;
-          break;
-        }
-      }
-    }
-    dequotedMessage += messagepart;
-  }
-  return dequotedMessage;
-}
-
-
-QString Server::ctcpXdelimDequote(QString message) {
-  QString dequotedMessage;
-  QString messagepart;
-  QHash<QString, QString>::iterator xdelimquote;
-
-  for(int i = 0; i < message.size(); i++) {
-    messagepart = message[i];
-    if(i+1 < message.size()) {
-      for(xdelimquote = ctcpXDelimDequoteHash.begin(); xdelimquote != ctcpXDelimDequoteHash.end(); ++xdelimquote) {
-        if(message.mid(i,2) == xdelimquote.key()) {
-          messagepart = xdelimquote.value();
-          i++;
-          break;
-        }
-      }
-    }
-    dequotedMessage += messagepart;
-  }
-  return dequotedMessage;
-}
-
-QStringList Server::parseCtcp(CtcpType ctcptype, QString prefix, QString target, QString message) {
-  QStringList messages;
-  QString ctcp;
-  
-  //lowlevel message dequote
-  QString dequotedMessage = ctcpDequote(message);
+  QString msg;
+  if(!prefix.isEmpty())
+    msg += ":" + prefix + " ";
+  msg += cmd.toUpper();
   
-  // extract tagged / extended data
-  while(dequotedMessage.contains(XDELIM)) {
-    messages << dequotedMessage.section(XDELIM,0,0);
-    ctcp = ctcpXdelimDequote(dequotedMessage.section(XDELIM,1,1));
-    dequotedMessage = dequotedMessage.section(XDELIM,2,2);
-    
-    //dispatch the ctcp command
-    QString ctcpcmd = ctcp.section(' ', 0, 0);
-    QString ctcpparam = ctcp.section(' ', 1);
-    
-    QString hname = ctcpcmd.toLower();
-    hname[0] = hname[0].toUpper();
-    hname = "handleCtcp" + hname;
-    if(!QMetaObject::invokeMethod(this, hname.toAscii(), Q_ARG(CtcpType, ctcptype), Q_ARG(QString, prefix), Q_ARG(QString, target), Q_ARG(QString, ctcpparam))) {
-      // Ok. Default handler it is.
-      defaultCtcpHandler(ctcptype, prefix, ctcpcmd, target, ctcpparam);
-    }
-  }
-  if(!dequotedMessage.isEmpty()) {
-    messages << dequotedMessage;
+  for(int i = 0; i < params.size() - 1; i++) {
+    msg += " " + params[i];
   }
-  return messages;
-}
-
-QString Server::ctcpPack(QString ctcpTag, QString message) {
-  return XDELIM + ctcpTag + ' ' + message + XDELIM;
-}
-
-void Server::ctcpQuery(QString bufname, QString ctcpTag, QString message) {
-  QStringList params;
-  params << bufname << ctcpPack(ctcpTag, message);
-  putCmd("PRIVMSG", params); 
-}
-
-void Server::ctcpReply(QString bufname, QString ctcpTag, QString message) {
-  QStringList params;
-  params << bufname << ctcpPack(ctcpTag, message);
-  putCmd("NOTICE", params);
-}
-
-/**********************************************************************************/
-
-/*
-void Server::handleUser(QString bufname, QString msg) {
-
-
-}
-*/
-
-void Server::handleUserAway(QString bufname, QString msg) {
-  putCmd("AWAY", QStringList(msg));
-}
-
-void Server::handleUserDeop(QString bufname, QString msg) {
-  QStringList nicks = msg.split(' ', QString::SkipEmptyParts);
-  QString m = "-"; for(int i = 0; i < nicks.count(); i++) m += 'o';
-  QStringList params;
-  params << bufname << m << nicks;
-  putCmd("MODE", params);
-}
-
-void Server::handleUserDevoice(QString bufname, QString msg) {
-  QStringList nicks = msg.split(' ', QString::SkipEmptyParts);
-  QString m = "-"; for(int i = 0; i < nicks.count(); i++) m += 'v';
-  QStringList params;
-  params << bufname << m << nicks;
-  putCmd("MODE", params);
-}
-
-void Server::handleUserInvite(QString bufname, QString msg) {
-  QStringList params;
-  params << msg << bufname;
-  putCmd("INVITE", params);
-}
-
-void Server::handleUserJoin(QString bufname, QString msg) {
-  putCmd("JOIN", QStringList(msg));
-}
-
-void Server::handleUserKick(QString bufname, QString msg) {
-  QStringList params;
-  params << bufname << msg.split(' ', QString::SkipEmptyParts);
-  putCmd("KICK", params);
-}
-
-void Server::handleUserList(QString bufname, QString msg) {
-  putCmd("LIST", msg.split(' ', QString::SkipEmptyParts));
-}
-
-void Server::handleUserMode(QString bufname, QString msg) {
-  putCmd("MODE", msg.split(' ', QString::SkipEmptyParts));
-}
-
-// TODO: show privmsgs
-void Server::handleUserMsg(QString bufname, QString msg) {
-  QString nick = msg.section(" ", 0, 0);
-  msg = msg.section(" ", 1);
-  if(nick.isEmpty() || msg.isEmpty()) return;
-  QStringList params;
-  params << nick << msg;
-  putCmd("PRIVMSG", params);
-}
-
-void Server::handleUserNick(QString bufname, QString msg) {
-  QString nick = msg.section(' ', 0, 0);
-  putCmd("NICK", QStringList(nick));
-}
-
-void Server::handleUserOp(QString bufname, QString msg) {
-  QStringList nicks = msg.split(' ', QString::SkipEmptyParts);
-  QString m = "+"; for(int i = 0; i < nicks.count(); i++) m += 'o';
-  QStringList params;
-  params << bufname << m << nicks;
-  putCmd("MODE", params);
-}
-
-void Server::handleUserPart(QString bufname, QString msg) {
-  QStringList params;
-  params << bufname << msg;
-  putCmd("PART", params);
-}
+  if(!params.isEmpty())
+    msg += " :" + params.last();
 
-// TODO: implement queries
-void Server::handleUserQuery(QString bufname, QString msg) {
-  QString nick = msg.section(' ', 0, 0);
-  if(!nick.isEmpty()) emit queryRequested(network, nick);
-}
-
-void Server::handleUserQuit(QString bufname, QString msg) {
-  putCmd("QUIT", QStringList(msg));
-}
-
-void Server::handleUserQuote(QString bufname, QString msg) {
   putRawLine(msg);
 }
 
-void Server::handleUserSay(QString bufname, QString msg) {
-  if(bufname.isEmpty()) return;  // server buffer
-  QStringList params;
-  params << bufname << msg;
-  putCmd("PRIVMSG", params);
-  if(isChannelName(bufname)) {
-    emit displayMsg(Message::Plain, params[0], msg, ownNick, Message::Self);
-  } else {
-    emit displayMsg(Message::Plain, params[0], msg, ownNick, Message::Self|Message::PrivMsg);
-  }
-}
-
-void Server::handleUserMe(QString bufname, QString msg) {
-  if(bufname.isEmpty()) return; // server buffer
-  ctcpQuery(bufname, "ACTION", msg);
-  emit displayMsg(Message::Action, bufname, msg, ownNick);
-}
-
-void Server::handleUserTopic(QString bufname, QString msg) {
-  if(bufname.isEmpty()) return;
-  QStringList params;
-  params << bufname << msg;
-  putCmd("TOPIC", params);
-}
-
-void Server::handleUserVoice(QString bufname, QString msg) {
-  QStringList nicks = msg.split(' ', QString::SkipEmptyParts);
-  QString m = "+"; for(int i = 0; i < nicks.count(); i++) m += 'v';
-  QStringList params;
-  params << bufname << m << nicks;
-  putCmd("MODE", params);
-}
-
-/**********************************************************************************/
-
-void Server::handleServerJoin(QString prefix, QStringList params) {
-  Q_ASSERT(params.count() == 1);
-  QString nick = updateNickFromMask(prefix);
-  emit displayMsg(Message::Join, params[0], params[0], prefix);
-  if(nick == ownNick) {
-  //  Q_ASSERT(!buffers.contains(params[0]));  // cannot join a buffer twice!
-  //  Buffer *buf = new Buffer(params[0]);
-  //  buffers[params[0]] = buf;
-    topics[params[0]] = "";
-    emit topicSet(network, params[0], "");
-  } //else {
-    QVariantMap n;
-    if(nicks.contains(nick)) {
-      n = nicks[nick];
-      QVariantMap chans = n["Channels"].toMap();
-      // Q_ASSERT(!chans.keys().contains(params[0])); TODO uncomment
-      chans[params[0]] = QVariantMap();
-      n["Channels"] = chans;
-      nicks[nick] = n;
-      emit nickUpdated(network, nick, n);
-    } else {
-      QVariantMap chans;
-      chans[params[0]] = QVariantMap();
-      n["Channels"] = chans;
-      n["User"] = userFromMask(prefix);
-      n["Host"] = hostFromMask(prefix);
-      nicks[nick] = n;
-      emit nickAdded(network, nick, n);
-    }
-    //emit displayMsg(Message::Join, params[0], params[0], prefix);
-  //}
-}
-
-void Server::handleServerKick(QString prefix, QStringList params) {
-  QString kicker = updateNickFromMask(prefix);
-  QString nick = params[1];
-  Q_ASSERT(nicks.contains(nick));
-  QVariantMap n = nicks[nick];
-  QVariantMap chans = n["Channels"].toMap();
-  Q_ASSERT(chans.contains(params[0]));
-  chans.remove(params[0]);
-  QString msg = nick;
-  if(params.count() > 2) msg = QString("%1 %2").arg(msg).arg(params[2]);
-  emit displayMsg(Message::Kick, params[0], msg, prefix);
-  if(chans.count() > 0) {
-    n["Channels"] = chans;
-    nicks[nick] = n;
-    emit nickUpdated(network, nick, n);
-  } else {
-    nicks.remove(nick);
-    emit nickRemoved(network, nick);
-  }
-  if(nick == ownNick) {
-    topics.remove(params[0]);
-  }
-}
-
-void Server::handleServerMode(QString prefix, QStringList params) {
-  if(isChannelName(params[0])) {
-    // TODO only channel-user modes supported by now
-    QString prefixes = serverSupports["PrefixModes"].toString();
-    QString modes = params[1];
-    int p = 2;
-    int m = 0;
-    bool add = true;
-    while(m < modes.length()) {
-      if(modes[m] == '+') { add = true; m++; continue; }
-      if(modes[m] == '-') { add = false; m++; continue; }
-      if(prefixes.contains(modes[m])) {  // it's a user channel mode
-        Q_ASSERT(params.count() > m);
-        QString nick = params[p++];
-        if(nicks.contains(nick)) {  // sometimes, a server might try to set a MODE on a nick that is no longer there
-          QVariantMap n = nicks[nick]; QVariantMap clist = n["Channels"].toMap(); QVariantMap chan = clist[params[0]].toMap();
-          QString mstr = chan["Mode"].toString();
-          add ? mstr += modes[m] : mstr.remove(modes[m]);
-          chan["Mode"] = mstr; clist[params[0]] = chan; n["Channels"] = clist; nicks[nick] = n;
-          emit nickUpdated(network, nick, n);
-        }
-        m++;
-      } else {
-        // TODO add more modes
-        m++;
-      }
-    }
-    emit displayMsg(Message::Mode, params[0], params.join(" "), prefix);
-  } else {
-    //Q_ASSERT(nicks.contains(params[0]));
-    //QVariantMap n = nicks[params[0]].toMap();
-    //QString mode = n["Mode"].toString();
-    emit displayMsg(Message::Mode, "", params.join(" "));
-  }
-}
-
-void Server::handleServerNick(QString prefix, QStringList params) {
-  QString oldnick = updateNickFromMask(prefix);
-  QString newnick = params[0];
-  QVariantMap v = nicks.take(oldnick);
-  nicks[newnick] = v;
-  QVariantMap chans = v["Channels"].toMap();
-  foreach(QString c, chans.keys()) {
-    if(oldnick != ownNick) { emit displayMsg(Message::Nick, c, newnick, prefix); }
-    else { emit displayMsg(Message::Nick, c, newnick, newnick); }
-  }
-  emit nickRenamed(network, oldnick, newnick);
-  if(oldnick == ownNick) {
-    ownNick = newnick;
-    emit ownNickSet(network, newnick);
-  }
-}
-
-void Server::handleServerNotice(QString prefix, QStringList params) {
-  //Message msg(Message::Notice, params[1], prefix);
-  if(currentServer.isEmpty() || prefix == currentServer) emit displayMsg(Message::Server, "", params[1], prefix);
-  else emit displayMsg(Message::Notice, "", params[1], prefix);
-}
-
-void Server::handleServerPart(QString prefix, QStringList params) {
-  QString nick = updateNickFromMask(prefix);
-  Q_ASSERT(nicks.contains(nick));
-  QVariantMap n = nicks[nick];
-  QVariantMap chans = n["Channels"].toMap();
-  Q_ASSERT(chans.contains(params[0]));
-  chans.remove(params[0]);
-  QString msg;
-  if(params.count() > 1) msg = params[1];
-  emit displayMsg(Message::Part, params[0], msg, prefix);
-  if(chans.count() > 0) {
-    n["Channels"] = chans;
-    nicks[nick] = n;
-    emit nickUpdated(network, nick, n);
-  } else {
-    nicks.remove(nick);
-    emit nickRemoved(network, nick);
-  }
-  if(nick == ownNick) {
-    Q_ASSERT(topics.contains(params[0]));
-    topics.remove(params[0]);
-  }
-}
-
-void Server::handleServerPing(QString prefix, QStringList params) {
-  putCmd("PONG", params);
-}
-
-void Server::handleServerPrivmsg(QString prefix, QStringList params) {
-  updateNickFromMask(prefix);
-  Q_ASSERT(params.count() >= 2);
-  if(params.count()<2) emit displayMsg(Message::Plain, params[0], "", prefix);
-  else {
-    // it's possible to pack multiple privmsgs into one param using ctcp
-    QStringList messages = parseCtcp(Server::CtcpQuery, prefix, params[0], params[1]);
-    if(params[0].toLower() == ownNick.toLower()) {  // Freenode sends nickname in lower case!
-      foreach(QString message, messages) {
-        if(!message.isEmpty()) {
-          emit displayMsg(Message::Plain, "", message, prefix, Message::PrivMsg);
-        }
-      }
-      
-    } else {
-      //qDebug() << prefix << params;
-      Q_ASSERT(isChannelName(params[0]));  // should be channel!
-      foreach(QString message, messages) {
-        if(!message.isEmpty()) {
-          emit displayMsg(Message::Plain, params[0], message, prefix);
-        }
-      }
-    }
-  }
-}
-
-void Server::handleServerQuit(QString prefix, QStringList params) {
-  QString nick = updateNickFromMask(prefix);
-  Q_ASSERT(nicks.contains(nick));
-  QVariantMap chans = nicks[nick]["Channels"].toMap();
-  QString msg;
-  if(params.count()) msg = params[0];
-  foreach(QString c, chans.keys()) {
-    emit displayMsg(Message::Quit, c, msg, prefix);
-  }
-  nicks.remove(nick);
-  emit nickRemoved(network, nick);
-}
-
-void Server::handleServerTopic(QString prefix, QStringList params) {
-  QString nick = updateNickFromMask(prefix);
-  Q_ASSERT(nicks.contains(nick));
-  topics[params[0]] = params[1];
-  emit topicSet(network, params[0], params[1]);
-  emit displayMsg(Message::Server, params[0], tr("%1 has changed topic for %2 to: \"%3\"").arg(nick).arg(params[0]).arg(params[1]));
-}
-
-/* RPL_WELCOME */
-void Server::handleServer001(QString prefix, QStringList params) {
-  // there should be only one param: "Welcome to the Internet Relay Network <nick>!<user>@<host>"
-  currentServer = prefix;
-  ownNick = params[0].section(' ', -1, -1).section('!', 0, 0);
-  QVariantMap n;
-  n["Channels"] = QVariantMap();
-  nicks[ownNick] = n;
-  emit ownNickSet(network, ownNick);
-  emit nickAdded(network, ownNick, QVariantMap());
-  emit displayMsg(Message::Server, "", params[0], prefix);
-  // send performlist
-  QStringList performList = networkSettings["Perform"].toString().split( "\n" );
-  int count = performList.count();
-  for(int a = 0; a < count; a++) {
-    if(!performList[a].isEmpty() ) {
-      userInput(network, "", performList[a]);
-    }
-  }
-}
-
-/* RPL_ISUPPORT */
-// TODO Complete 005 handling, also use sensible defaults for non-sent stuff
-void Server::handleServer005(QString prefix, QStringList params) {
-  //qDebug() << prefix << params;
-  params.removeLast();
-  foreach(QString p, params) {
-    QString key = p.section("=", 0, 0);
-    QString val = p.section("=", 1);
-    serverSupports[key] = val;
-    // handle some special cases
-    if(key == "PREFIX") {
-      QVariantMap foo; QString modes, prefixes;
-      Q_ASSERT(val.contains(')') && val.startsWith('('));
-      int m = 1, p;
-      for(p = 2; p < val.length(); p++) if(val[p] == ')') break;
-      p++;
-      for(; val[m] != ')'; m++, p++) {
-        Q_ASSERT(p < val.length());
-        foo[QString(val[m])] = QString(val[p]);
-        modes += val[m]; prefixes += val[p];
-      }
-      serverSupports["PrefixModes"] = modes; serverSupports["Prefixes"] = prefixes;
-      serverSupports["ModePrefixMap"] = foo;
-    }
-  }
-}
-
-
-/* RPL_NOTOPIC */
-void Server::handleServer331(QString prefix, QStringList params) {
-  topics[params[0]] = "";
-  emit topicSet(network, params[0], "");
-  emit displayMsg(Message::Server, params[0], tr("No topic is set for %1.").arg(params[0]));
-}
-
-/* RPL_TOPIC */
-void Server::handleServer332(QString prefix, QStringList params) {
-  topics[params[0]] = params[1];
-  emit topicSet(network, params[0], params[1]);
-  emit displayMsg(Message::Server, params[0], tr("Topic for %1 is \"%2\"").arg(params[0]).arg(params[1]));
-}
-
-/* Topic set by... */
-void Server::handleServer333(QString prefix, QStringList params) {
-  emit displayMsg(Message::Server, params[0],
-                    tr("Topic set by %1 on %2").arg(params[1]).arg(QDateTime::fromTime_t(params[2].toUInt()).toString()));
-}
-
-/* RPL_NAMREPLY */
-void Server::handleServer353(QString prefix, QStringList params) {
-  params.removeFirst(); // = or *
-  QString buf = params.takeFirst();
-  QString prefixes = serverSupports["Prefixes"].toString();
-  foreach(QString nick, params[0].split(' ')) {
-    QString mode = "", pfx = "";
-    if(prefixes.contains(nick[0])) {
-      pfx = nick[0];
-      for(int i = 0;; i++)
-        if(prefixes[i] == nick[0]) { mode = serverSupports["PrefixModes"].toString()[i]; break; }
-      nick.remove(0,1);
-    }
-    QVariantMap c; c["Mode"] = mode; c["Prefix"] = pfx;
-    if(nicks.contains(nick)) {
-      QVariantMap n = nicks[nick];
-      QVariantMap chans = n["Channels"].toMap();
-      chans[buf] = c;
-      n["Channels"] = chans;
-      nicks[nick] = n;
-      emit nickUpdated(network, nick, n);
-    } else {
-      QVariantMap n; QVariantMap c; QVariantMap chans;
-      c["Mode"] = mode;
-      chans[buf] = c;
-      n["Channels"] = chans;
-      nicks[nick] = n;
-      emit nickAdded(network, nick, n);
-    }
-  }
-}
-
-/* ERR_ERRONEUSNICKNAME */
-void Server::handleServer432(QString prefix, QStringList params) {
-  if(params.size() < 2) {
-    // handle unreal-ircd bug, where unreal ircd doesnt supply a TARGET in ERR_ERRONEUSNICKNAME during registration phase:
-    // nick @@@
-    // :irc.scortum.moep.net 432  @@@ :Erroneous Nickname: Illegal characters
-    // correct server reply:
-    // :irc.scortum.moep.net 432 * @@@ :Erroneous Nickname: Illegal characters
-    emit displayMsg(Message::Error, "", tr("There is a nickname in your identity's nicklist which contains illegal characters"));
-    emit displayMsg(Message::Error, "", tr("Due to a bug in Unreal IRCd (and maybe other irc-servers too) we're unable to determine the erroneous nick"));
-    emit displayMsg(Message::Error, "", tr("Please use: /nick <othernick> to continue or clean up your nicklist"));
-  } else {
-    QString errnick = params[0];
-    emit displayMsg(Message::Error, "", tr("Nick %1 contains illegal characters").arg(errnick));
-    // if there is a problem while connecting to the server -> we handle it
-    // TODO rely on another source...
-    if(currentServer.isEmpty()) {
-      QStringList desiredNicks = identity["NickList"].toStringList();
-      int nextNick = desiredNicks.indexOf(errnick) + 1;
-      if (desiredNicks.size() > nextNick) {
-        putCmd("NICK", QStringList(desiredNicks[nextNick]));
-      } else {
-        emit displayMsg(Message::Error, "", tr("No free and valid nicks in nicklist found. use: /nick <othernick> to continue"));
-      }
-    }
-  }
-}
-
-/* ERR_NICKNAMEINUSE */
-void Server::handleServer433(QString prefix, QStringList params) {
-  QString errnick = params[0];
-  emit displayMsg(Message::Error, "", tr("Nick %1 is already taken").arg(errnick));
-  // if there is a problem while connecting to the server -> we handle it
-  // TODO rely on another source...
-  if(currentServer.isEmpty()) {
-    QStringList desiredNicks = identity["NickList"].toStringList();
-    int nextNick = desiredNicks.indexOf(errnick) + 1;
-    if (desiredNicks.size() > nextNick) {
-      putCmd("NICK", QStringList(desiredNicks[nextNick]));
-    } else {
-      emit displayMsg(Message::Error, "", tr("No free and valid nicks in nicklist found. use: /nick <othernick> to continue"));
-    }
-  }
-}
-
-/***********************************************************************************/
-// CTCP HANDLER
 
-void Server::handleCtcpAction(CtcpType ctcptype, QString prefix, QString target, QString param) {
-  emit displayMsg(Message::Action, target, param, prefix);
-}
-
-void Server::handleCtcpPing(CtcpType ctcptype, QString prefix, QString target, QString param) {
-  if(ctcptype == CtcpQuery) {
-    ctcpReply(nickFromMask(prefix), "PING", param);
-    emit displayMsg(Message::Server, "", tr("Received CTCP PING request by %1").arg(prefix));
-  } else {
-    // display ping answer
-  }
+uint Server::networkId() const {
+  return _networkId;
 }
 
-void Server::handleCtcpVersion(CtcpType ctcptype, QString prefix, QString target, QString param) {
-  if(ctcptype == CtcpQuery) {
-    // FIXME use real Info about quassel :)
-    //ctcpReply(nickFromMask(prefix), "VERSION", QString("Quassel:pre Release:*nix"));
-    ctcpReply(nickFromMask(prefix), "VERSION", QString("Quassel IRC (Pre-Release) - http://www.quassel-irc.org"));
-    emit displayMsg(Message::Server, "", tr("Received CTCP VERSION request by %1").arg(prefix));
-  } else {
-    // TODO display Version answer
-  }
+QString Server::networkName() {
+  return networkInfo()->networkName();
 }
 
-void Server::defaultCtcpHandler(CtcpType ctcptype, QString prefix, QString cmd, QString target, QString param) {
-  emit displayMsg(Message::Error, "", tr("Received unknown CTCP %1 by %2").arg(cmd).arg(prefix));
+CoreSession *Server::coreSession() const {
+  return Core::session(userId());
 }
 
-
-/***********************************************************************************/
-
 /* Exception classes for message handling */
 Server::ParseError::ParseError(QString cmd, QString prefix, QStringList params) {
   _msg = QString("Command Parse Error: ") + cmd + params.join(" ");
-
 }
 
 Server::UnknownCmdError::UnknownCmdError(QString cmd, QString prefix, QStringList params) {
   _msg = QString("Unknown Command: ") + cmd;
-
 }
index 360bed8..1b92f16 100644 (file)
 #include <QTimer>
 
 #include "message.h"
-#include "serverinfo.h"
+#include "signalproxy.h"
 
+class NetworkInfo;
+
+class IrcServerHandler;
+class UserInputHandler;
+class CtcpHandler;
+class CoreSession;
 
 /*!
  * This is a server object, managing a single connection to an IRC server, handling the associated channels and so on.
 class Server : public QThread {
   Q_OBJECT
 
-  public:
-    Server(UserId uid, QString network);
-    ~Server();
-
-    UserId userId() const { return user; } 
-    // serverState state();
-    bool isConnected() const { return socket.state() == QAbstractSocket::ConnectedState; }
-    QString getNetwork() { return network; }
-    QStringList providesUserHandlers();
-
-    enum CtcpType {CtcpQuery, CtcpReply};
-
-  public slots:
-    // void setServerOptions();
-    void sendState();
-    void connectToIrc(QString net);
-    void disconnectFromIrc(QString net);
-    void userInput(QString net, QString buffer, QString msg);
-
-    void putRawLine(QString input);
-    void putCmd(QString cmd, QStringList params, QString prefix = 0);
-
-    //void exitThread();
-
-  signals:
-    void serverState(QString net, QVariantMap data);
-    void recvRawServerMsg(QString);
-    void displayStatusMsg(QString);
-    //void displayMsg(Message msg);
-    void displayMsg(Message::Type, QString target, QString text, QString sender = "", quint8 flags = Message::None);
-    void connected(QString network);
-    void disconnected(QString network);
-
-    void nickAdded(QString network, QString nick, QVariantMap props);
-    void nickRenamed(QString network, QString oldnick, QString newnick);
-    void nickRemoved(QString network, QString nick);
-    void nickUpdated(QString network, QString nick, QVariantMap props);
-    void modeSet(QString network, QString target, QString mode);
-    void topicSet(QString network, QString buffer, QString topic);
-    void ownNickSet(QString network, QString newNick);
-    void queryRequested(QString network, QString nick);
-
-
-  private slots:
-    void run();
-    void socketHasData();
-    void socketError(QAbstractSocket::SocketError);
-    void socketConnected();
-    void socketDisconnected();
-    void socketStateChanged(QAbstractSocket::SocketState);
-
-    /* Message Handlers */
-
-    /* void handleUser(QString, QString); */
-    void handleUserAway(QString, QString);
-    void handleUserDeop(QString, QString);
-    void handleUserDevoice(QString, QString);
-    void handleUserInvite(QString, QString);
-    void handleUserJoin(QString, QString);
-    void handleUserKick(QString, QString);
-    void handleUserList(QString, QString);
-    void handleUserMode(QString, QString);
-    void handleUserMsg(QString, QString);
-    void handleUserNick(QString, QString);
-    void handleUserOp(QString, QString);
-    void handleUserPart(QString, QString);
-    void handleUserQuery(QString, QString);
-    void handleUserQuit(QString, QString);
-    void handleUserQuote(QString, QString);
-    void handleUserSay(QString, QString);
-    void handleUserTopic(QString, QString);
-    void handleUserVoice(QString, QString);
-    void handleUserMe(QString, QString);
-
-    /* void handleServer(QString, QStringList); */
-    void handleServerJoin(QString, QStringList);
-    void handleServerKick(QString, QStringList);
-    void handleServerMode(QString, QStringList);
-    void handleServerNick(QString, QStringList);
-    void handleServerNotice(QString, QStringList);
-    void handleServerPart(QString, QStringList);
-    void handleServerPing(QString, QStringList);
-    void handleServerPrivmsg(QString, QStringList);
-    void handleServerQuit(QString, QStringList);
-    void handleServerTopic(QString, QStringList);
-
-    void handleServer001(QString, QStringList);   // RPL_WELCOME
-    void handleServer005(QString, QStringList);   // RPL_ISUPPORT
-    void handleServer331(QString, QStringList);   // RPL_NOTOPIC
-    void handleServer332(QString, QStringList);   // RPL_TOPIC
-    void handleServer333(QString, QStringList);   // Topic set by...
-    void handleServer353(QString, QStringList);   // RPL_NAMREPLY
-    void handleServer432(QString, QStringList);   // ERR_ERRONEUSNICKNAME
-    void handleServer433(QString, QStringList);   // ERR_NICKNAMEINUSE
-
-    void handleCtcpAction(CtcpType, QString, QString, QString);
-    void handleCtcpPing(CtcpType, QString, QString, QString);
-    void handleCtcpVersion(CtcpType, QString, QString, QString);
-
-    void defaultServerHandler(QString cmd, QString prefix, QStringList params);
-    void defaultUserHandler(QString buf, QString cmd, QString msg);
-    void defaultCtcpHandler(CtcpType ctcptype, QString prefix, QString cmd, QString target, QString param);
-
-  private:
-    UserId user;
-    QString network;
-    QTcpSocket socket;
-    //QHash<QString, Buffer*> buffers;
-
-    QString ownNick;
-    QString currentServer;
-    QVariantMap networkSettings;
-    QVariantMap identity;
-    QHash<QString, QVariantMap> nicks;  // stores all known nicks for the server
-    QHash<QString, QString> topics; // stores topics for each buffer
-    QVariantMap serverSupports;  // stores results from RPL_ISUPPORT
-
-    void handleServerMsg(QByteArray rawMsg);
-    void handleUserInput(QString buffer, QString usrMsg);
-
-    // CTCP Stuff
-    QString XDELIM;
-    QHash<QString, QString> ctcpMDequoteHash;
-    QHash<QString, QString> ctcpXDelimDequoteHash;    
-    QString ctcpDequote(QString);
-    QString ctcpXdelimDequote(QString);
-    QStringList parseCtcp(CtcpType, QString, QString, QString);    
-
-    QString ctcpPack(QString ctcpTag, QString message);
-    void ctcpQuery(QString bufname, QString ctcpTag, QString message);
-    void ctcpReply(QString bufname, QString ctcpTag, QString message);
-    
-    QString updateNickFromMask(QString mask);
+public:
+  Server(UserId uid, uint networkId, QString network);
+  ~Server();
+
+  UserId userId() const { return _userId; } 
+
+  // serverState state();
+  bool isConnected() const { return socket.state() == QAbstractSocket::ConnectedState; }
+
+  uint networkId() const;
+  QString networkName();  // hasbeen getNetwork()
+
+  NetworkInfo *networkInfo() { return _networkInfo; }
+  IrcServerHandler *ircServerHandler() {return _ircServerHandler; }
+  UserInputHandler *userInputHandler() {return _userInputHandler; }
+  CtcpHandler *ctcpHandler() {return _ctcpHandler; }
+  
+public slots:
+  // void setServerOptions();
+  void connectToIrc(QString net);
+  void disconnectFromIrc(QString net);
+  void userInput(uint netid, QString buffer, QString msg);
+
+  void putRawLine(QString input);
+  void putCmd(QString cmd, QStringList params, QString prefix = 0);
+
+  //void exitThread();
+
+signals:
+  void serverState(QString net, QVariantMap data);
+  void recvRawServerMsg(QString);
+  void displayStatusMsg(QString);
+  //void displayMsg(Message msg);
+  void displayMsg(Message::Type, QString target, QString text, QString sender = "", quint8 flags = Message::None);
+  void connected(uint networkId);
+  void disconnected(uint networkId);
 
-    class ParseError : public Exception {
-      public:
-        ParseError(QString cmd, QString prefix, QStringList params);
-    };
+  void synchronizeClients();
+  
+  void queryRequested(QString network, QString nick);
 
-    class UnknownCmdError : public Exception {
-      public:
-        UnknownCmdError(QString cmd, QString prefix, QStringList params);
-    };
+
+private slots:
+  void run();
+  void socketHasData();
+  void socketError(QAbstractSocket::SocketError);
+  void socketConnected();
+  void socketDisconnected();
+  void socketStateChanged(QAbstractSocket::SocketState);
+
+private:
+  UserId _userId;
+  uint _networkId;
+
+  QTcpSocket socket;
+
+  IrcServerHandler *_ircServerHandler;
+  UserInputHandler *_userInputHandler;
+  CtcpHandler *_ctcpHandler;
+
+  NetworkInfo *_networkInfo;
+
+  QVariantMap networkSettings;
+  QVariantMap identity;
+
+  CoreSession *coreSession() const;
+  
+  class ParseError : public Exception {
+  public:
+    ParseError(QString cmd, QString prefix, QStringList params);
+  };
+
+  class UnknownCmdError : public Exception {
+  public:
+    UnknownCmdError(QString cmd, QString prefix, QStringList params);
+  };
     
-    // stuff needed for new separation of server information
-    ServerInfo *serverinfo;
 };
 
 #endif
diff --git a/src/core/serverinfo.cpp b/src/core/serverinfo.cpp
deleted file mode 100644 (file)
index bc9fe64..0000000
+++ /dev/null
@@ -1,112 +0,0 @@
-/***************************************************************************
- *   Copyright (C) 2005-07 by The Quassel Team                             *
- *   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) any later version.                                   *
- *                                                                         *
- *   This program is distributed in the hope that it will be useful,       *
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
- *   GNU General Public License for more details.                          *
- *                                                                         *
- *   You should have received a copy of the GNU General Public License     *
- *   along with this program; if not, write to the                         *
- *   Free Software Foundation, Inc.,                                       *
- *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
- ***************************************************************************/
-#include "serverinfo.h"
-
-ServerInfo::ServerInfo(QObject *parent)
-  : QObject(parent) {
-}
-
-ServerInfo::~ServerInfo() {
-}
-
-void ServerInfo::setNetworkname(const QString &networkname) {
-  networkname_ = networkname;
-}
-
-QString ServerInfo::networkname() const {
-  return networkname_;
-}
-
-void ServerInfo::setCurrentServer(const QString &currentServer) {
-  currentServer_ = currentServer;
-}
-
-QString ServerInfo::currentServer() const {
-  return currentServer_;
-}
-
-void ServerInfo::setOwnNick(const QString &ownnick) {
-  ownNick_ = ownnick;
-}
-
-QString ServerInfo::ownNick() const {
-  return ownNick_;
-}
-
-QList<IrcUser *> ServerInfo::ircUsers() const {
-  return ircUsers_.values();
-}
-
-
-IrcUser *ServerInfo::newIrcUser(const QString &hostmask) {
-  IrcUser *ircuser = new IrcUser(hostmask);
-  return ircUsers_[ircuser->nick()] = ircuser;
-}
-
-IrcUser *ServerInfo::ircUser(const QString &nickname) const {
-  if(ircUsers_.contains(nickname))
-    return ircUsers_[nickname];
-  else
-    throw NoSuchNickException();
-}
-
-void ServerInfo::setTopics(const QHash<QString, QString> &topics) {
-  topics_ = topics;
-}
-
-QHash<QString, QString> ServerInfo::topics() const {
-  return topics_;
-}
-
-void ServerInfo::updateTopic(const QString &channel, const QString &topic) {
-  topics_[channel] = topic;
-}
-
-QString ServerInfo::topic(const QString &channel) const {
-  if(topics_.contains(channel))
-    return topics_[channel];
-  else
-    throw NoSuchChannelException();
-}
-
-void ServerInfo::setSupports(const QHash<QString, QString> &supports) {
-  supports_ = supports;
-}
-
-QHash<QString, QString> ServerInfo::supports() const {
-  return supports_;
-}
-
-QString ServerInfo::supports(const QString &feature) const {
-  if(supports_.contains(feature))
-    return supports_[feature];
-  else
-    throw UnsupportedFeatureException();
-}
-
-bool ServerInfo::isOwnNick(const QString &nick) const {
-  return (ownNick_.toLower() == nick.toLower());
-}
-
-bool ServerInfo::isOwnNick(const IrcUser &ircuser) const {
-  return (ircuser.nick().toLower() == ownNick_.toLower());
-}
-
-
diff --git a/src/core/serverinfo.h b/src/core/serverinfo.h
deleted file mode 100644 (file)
index 958c90a..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-/***************************************************************************
- *   Copyright (C) 2005/06 by The Quassel Team                             *
- *   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) any later version.                                   *
- *                                                                         *
- *   This program is distributed in the hope that it will be useful,       *
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
- *   GNU General Public License for more details.                          *
- *                                                                         *
- *   You should have received a copy of the GNU General Public License     *
- *   along with this program; if not, write to the                         *
- *   Free Software Foundation, Inc.,                                       *
- *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
- ***************************************************************************/
-
-#ifndef _SERVERINFO_H_
-#define _SERVERINFO_H_
-
-#include <QString>
-#include <QList>
-#include <QHash>
-
-#include "global.h"
-#include "ircuser.h"
-
-class ServerInfo : public QObject {
-  Q_OBJECT
-  
-  Q_PROPERTY(QString networkname READ networkname WRITE setNetworkname)
-  Q_PROPERTY(QString currentServer READ currentServer WRITE setCurrentServer)
-  Q_PROPERTY(QString ownNick READ ownNick WRITE setOwnNick)
-  Q_PROPERTY(QList<IrcUser *> ircUsers READ ircUsers)
-  
-public:
-  ServerInfo(QObject *parent = 0);
-  ~ServerInfo();
-
-  void setNetworkname(const QString &networkname);
-  QString networkname() const;
-  
-  void setCurrentServer(const QString &currentServer);
-  QString currentServer() const;
-  
-  void setOwnNick(const QString &ownnick);
-  QString ownNick() const;
-  
-  QList<IrcUser *> ircUsers() const;
-  IrcUser *newIrcUser(const QString &hostmask);
-  IrcUser *ircUser(const QString &nickname) const;
-  
-  void setTopics(const QHash<QString, QString> &topics);
-  QHash<QString, QString> topics() const;
-  
-  void updateTopic(const QString &channel, const QString &topic);
-  QString topic(const QString &channel) const;
-  
-  void setSupports(const QHash<QString, QString> &supports);
-  QHash<QString, QString> supports() const;
-  QString supports(const QString &feature) const;
-  
-  bool isOwnNick(const QString &nick) const;
-  bool isOwnNick(const IrcUser &ircuser) const;
-  
-private:
-  QString networkname_;
-  QString currentServer_;
-  QString ownNick_;
-  
-  //QVariantMap networkSettings;
-  //QVariantMap identity;
-  
-  QHash<QString, IrcUser *> ircUsers_;  // stores all known nicks for the server
-  QHash<QString, QString> topics_; // stores topics for each buffer
-  QHash<QString, QString> supports_;  // stores results from RPL_ISUPPORT
-};
-
-struct UnsupportedFeatureException : public Exception {};
-
-#endif
index 3d26a9b..7ba61fc 100644 (file)
@@ -53,8 +53,8 @@ SqliteStorage::SqliteStorage() {
   createNetworkQuery = new QSqlQuery(logDb);
   createNetworkQuery->prepare("INSERT INTO network (userid, networkname) VALUES (:userid, :networkname)");
 
-  getBufferIdQuery = new QSqlQuery(logDb);
-  getBufferIdQuery->prepare("SELECT bufferid FROM buffer "
+  getBufferInfoQuery = new QSqlQuery(logDb);
+  getBufferInfoQuery->prepare("SELECT bufferid FROM buffer "
                             "JOIN network ON buffer.networkid = network.networkid "
                             "WHERE network.networkname = :networkname AND buffer.userid = :userid AND buffer.buffername = :buffername ");
 
@@ -120,7 +120,7 @@ SqliteStorage::~SqliteStorage() {
   delete requestMsgRangeQuery;
   delete createNetworkQuery;
   delete createBufferQuery;
-  delete getBufferIdQuery;
+  delete getBufferInfoQuery;
   logDb.close();
 }
 
@@ -307,32 +307,32 @@ uint SqliteStorage::getNetworkId(UserId user, const QString &network) {
     return 0;
 }
 
-BufferId SqliteStorage::getBufferId(UserId user, const QString &network, const QString &buffer) {
-  BufferId bufferid;
+BufferInfo SqliteStorage::getBufferInfo(UserId user, const QString &network, const QString &buffer) {
+  BufferInfo bufferid;
   uint networkId = getNetworkId(user, network);
-  getBufferIdQuery->bindValue(":networkname", network);
-  getBufferIdQuery->bindValue(":userid", user);
-  getBufferIdQuery->bindValue(":buffername", buffer);
-  getBufferIdQuery->exec();
+  getBufferInfoQuery->bindValue(":networkname", network);
+  getBufferInfoQuery->bindValue(":userid", user);
+  getBufferInfoQuery->bindValue(":buffername", buffer);
+  getBufferInfoQuery->exec();
 
-  if(!getBufferIdQuery->first()) {
+  if(!getBufferInfoQuery->first()) {
     createBuffer(user, network, buffer);
-    getBufferIdQuery->exec();
-    if(getBufferIdQuery->first()) {
-      bufferid = BufferId(getBufferIdQuery->value(0).toUInt(), networkId, 0, network, buffer);
-      emit bufferIdUpdated(bufferid);
+    getBufferInfoQuery->exec();
+    if(getBufferInfoQuery->first()) {
+      bufferid = BufferInfo(getBufferInfoQuery->value(0).toUInt(), networkId, 0, network, buffer);
+      emit bufferInfoUpdated(bufferid);
     }
   } else {
-    bufferid = BufferId(getBufferIdQuery->value(0).toUInt(), networkId, 0, network, buffer);
+    bufferid = BufferInfo(getBufferInfoQuery->value(0).toUInt(), networkId, 0, network, buffer);
   }
 
-  Q_ASSERT(!getBufferIdQuery->next());
+  Q_ASSERT(!getBufferInfoQuery->next());
 
   return bufferid;
 }
 
-QList<BufferId> SqliteStorage::requestBuffers(UserId user, QDateTime since) {
-  QList<BufferId> bufferlist;
+QList<BufferInfo> SqliteStorage::requestBuffers(UserId user, QDateTime since) {
+  QList<BufferInfo> bufferlist;
   QSqlQuery query(logDb);
   query.prepare("SELECT DISTINCT buffer.bufferid, networkname, buffername FROM buffer "
                 "JOIN network ON buffer.networkid = network.networkid "
@@ -348,7 +348,7 @@ QList<BufferId> SqliteStorage::requestBuffers(UserId user, QDateTime since) {
   query.exec();
 
   while(query.next()) {
-    bufferlist << BufferId(query.value(0).toUInt(), getNetworkId(user, query.value(1).toString()), 0, query.value(1).toString(), query.value(2).toString());
+    bufferlist << BufferInfo(query.value(0).toUInt(), getNetworkId(user, query.value(1).toString()), 0, query.value(1).toString(), query.value(2).toString());
   }
   return bufferlist;
 }
@@ -389,7 +389,7 @@ MsgId SqliteStorage::logMessage(Message msg) {
   }
 }
 
-QList<Message> SqliteStorage::requestMsgs(BufferId buffer, int lastmsgs, int offset) {
+QList<Message> SqliteStorage::requestMsgs(BufferInfo buffer, int lastmsgs, int offset) {
   QList<Message> messagelist;
   // we have to determine the real offset first
   requestMsgsOffsetQuery->bindValue(":bufferid", buffer.uid());
@@ -418,7 +418,7 @@ QList<Message> SqliteStorage::requestMsgs(BufferId buffer, int lastmsgs, int off
 }
 
 
-QList<Message> SqliteStorage::requestMsgs(BufferId buffer, QDateTime since, int offset) {
+QList<Message> SqliteStorage::requestMsgs(BufferInfo buffer, QDateTime since, int offset) {
   QList<Message> messagelist;
   // we have to determine the real offset first
   requestMsgsSinceOffsetQuery->bindValue(":bufferid", buffer.uid());
@@ -449,7 +449,7 @@ QList<Message> SqliteStorage::requestMsgs(BufferId buffer, QDateTime since, int
 }
 
 
-QList<Message> SqliteStorage::requestMsgRange(BufferId buffer, int first, int last) {
+QList<Message> SqliteStorage::requestMsgRange(BufferInfo buffer, int first, int last) {
   QList<Message> messagelist;
   requestMsgRangeQuery->bindValue(":bufferid", buffer.uid());
   requestMsgRangeQuery->bindValue(":bufferid2", buffer.uid());
index a4f5fec..c8265d1 100644 (file)
@@ -23,7 +23,6 @@
 
 #include <QCryptographicHash>
 
-#include "global.h"
 #include "storage.h"
 
 class QSqlQuery;
@@ -56,15 +55,15 @@ class SqliteStorage : public Storage {
     virtual uint getNetworkId(UserId user, const QString &network);
 
     /* Buffer handling */
-    virtual BufferId getBufferId(UserId user, const QString &network, const QString &buffer = "");
-    virtual QList<BufferId> requestBuffers(UserId user, QDateTime since = QDateTime());
+    virtual BufferInfo getBufferInfo(UserId user, const QString &network, const QString &buffer = "");
+    virtual QList<BufferInfo> requestBuffers(UserId user, QDateTime since = QDateTime());
 
     /* Message handling */
 
     virtual MsgId logMessage(Message msg);
-    virtual QList<Message> requestMsgs(BufferId buffer, int lastmsgs = -1, int offset = -1);
-    virtual QList<Message> requestMsgs(BufferId buffer, QDateTime since, int offset = -1);
-    virtual QList<Message> requestMsgRange(BufferId buffer, int first, int last);
+    virtual QList<Message> requestMsgs(BufferInfo buffer, int lastmsgs = -1, int offset = -1);
+    virtual QList<Message> requestMsgs(BufferInfo buffer, QDateTime since, int offset = -1);
+    virtual QList<Message> requestMsgRange(BufferInfo buffer, int first, int last);
 
   public slots:
     //! This is just for importing the old file-based backlog */
@@ -75,7 +74,7 @@ class SqliteStorage : public Storage {
     void importOldBacklog();
 
   signals:
-    void bufferIdUpdated(BufferId);
+    void bufferInfoUpdated(BufferInfo);
 
   protected:
 
@@ -92,7 +91,7 @@ class SqliteStorage : public Storage {
     QSqlQuery *requestMsgRangeQuery;
     QSqlQuery *createNetworkQuery;
     QSqlQuery *createBufferQuery;
-    QSqlQuery *getBufferIdQuery;
+    QSqlQuery *getBufferInfoQuery;
 };
 
 
index 3c16dd3..e7dcea5 100644 (file)
@@ -31,7 +31,7 @@ void Storage::importOldBacklog() {
   logDb.exec(QString("DELETE FROM 'Backlog$%1$' WHERE SenderId != '$VERSION$'").arg(user));
   logDb.exec(QString("DELETE FROM 'Senders$%1$'").arg(user));
   logDb.exec(QString("DELETE FROM 'Buffers$%1$'").arg(user));
-  nextMsgId = 1; nextBufferId = 1; nextSenderId = 1;
+  nextMsgId = 1; nextBufferInfo = 1; nextSenderId = 1;
   qDebug() << "Importing old backlog files...";
   initBackLogOld();
   if(!backLogEnabledOld) return;
@@ -98,11 +98,11 @@ void Storage::initBackLogOld(UserId uid) {
         QString target = QString::fromUtf8(targ);
         QString sender = QString::fromUtf8(s);
         QString text = QString::fromUtf8(m);
-        BufferId id;
+        BufferInfo id;
         if((f & Message::PrivMsg) && !(f & Message::Self)) {
-          id = getBufferId(uid, net, sender);
+          id = getBufferInfo(uid, net, sender);
         } else {
-          id = getBufferId(uid, net, target);
+          id = getBufferInfo(uid, net, target);
         }
         Message msg(QDateTime::fromTime_t(ts), id, (Message::Type)t, text, sender, f);
         //backLog[net].append(m);
index a0e05e5..f493721 100644 (file)
@@ -96,19 +96,19 @@ class Storage : public QObject {
     //! Get the unique NetworkId of the network for a user.
     /** \param user    The core user who owns this buffername
      *  \param network The network name
-     *  \return The BufferId corresponding to the given network and buffer name, or 0 if not found
+     *  \return The BufferInfo corresponding to the given network and buffer name, or 0 if not found
      */
     virtual uint getNetworkId(UserId user, const QString &network) = 0;
 
     /* Buffer handling */
 
-    //! Get the unique BufferId for the given combination of network and buffername for a user.
+    //! Get the unique BufferInfo for the given combination of network and buffername for a user.
     /** \param user    The core user who owns this buffername
      *  \param network The network name
      *  \param buffer  The buffer name (if empty, the net's status buffer is returned)
-     *  \return The BufferId corresponding to the given network and buffer name, or 0 if not found
+     *  \return The BufferInfo corresponding to the given network and buffer name, or 0 if not found
      */
-    virtual BufferId getBufferId(UserId user, const QString &network, const QString &buffer = "") = 0;
+    virtual BufferInfo getBufferInfo(UserId user, const QString &network, const QString &buffer = "") = 0;
 
     //! Request a list of all buffers known to a user since a certain point in time.
     /** This method is used to get a list of all buffers we have stored a backlog from.
@@ -116,9 +116,9 @@ class Storage : public QObject {
      *  since that point in time.
      *  \param user  The user whose buffers we request
      *  \param since If this is defined, older buffers will be ignored
-     *  \return A list of the BufferIds for all buffers as requested
+     *  \return A list of the BufferInfos for all buffers as requested
      */
-    virtual QList<BufferId> requestBuffers(UserId user, QDateTime since = QDateTime()) = 0;
+    virtual QList<BufferInfo> requestBuffers(UserId user, QDateTime since = QDateTime()) = 0;
 
     /* Message handling */
 
@@ -134,7 +134,7 @@ class Storage : public QObject {
      *  \param offset   Do not return (but DO count) messages with MsgId >= offset, if offset >= 0
      *  \return The requested list of messages
      */
-    virtual QList<Message> requestMsgs(BufferId buffer, int lastmsgs = -1, int offset = -1) = 0;
+    virtual QList<Message> requestMsgs(BufferInfo buffer, int lastmsgs = -1, int offset = -1) = 0;
 
     //! Request messages stored in a given buffer since a certain point in time.
     /** \param buffer   The buffer we request messages from
@@ -142,7 +142,7 @@ class Storage : public QObject {
      *  \param offset   Do not return messages with MsgId >= offset, if offset >= 0
      *  \return The requested list of messages
      */
-    virtual QList<Message> requestMsgs(BufferId buffer, QDateTime since, int offset = -1) = 0;
+    virtual QList<Message> requestMsgs(BufferInfo buffer, QDateTime since, int offset = -1) = 0;
 
     //! Request a range of messages stored in a given buffer.
     /** \param buffer   The buffer we request messages from
@@ -150,7 +150,7 @@ class Storage : public QObject {
      *  \param last     Return messages with first <= MsgId <= last
      *  \return The requested list of messages
      */
-    virtual QList<Message> requestMsgRange(BufferId buffer, int first, int last) = 0;
+    virtual QList<Message> requestMsgRange(BufferInfo buffer, int first, int last) = 0;
 
   public slots:
     //! This is just for importing the old file-based backlog */
@@ -161,8 +161,8 @@ class Storage : public QObject {
     virtual void importOldBacklog() = 0;
 
   signals:
-    //! Sent when a new BufferId is created, or an existing one changed somehow.
-    void bufferIdUpdated(BufferId);
+    //! Sent when a new BufferInfo is created, or an existing one changed somehow.
+    void bufferInfoUpdated(BufferInfo);
     //! Sent when a new user has been added
     void userAdded(UserId, const QString &username);
     //! Sent when a user has been renamed
diff --git a/src/core/userinputhandler.cpp b/src/core/userinputhandler.cpp
new file mode 100644 (file)
index 0000000..5d4705e
--- /dev/null
@@ -0,0 +1,183 @@
+/***************************************************************************
+ *   Copyright (C) 2005-07 by The Quassel Team                             *
+ *   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) any later version.                                   *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program; if not, write to the                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
+ ***************************************************************************/
+#include "userinputhandler.h"
+
+#include "util.h"
+
+#include "server.h"
+#include "networkinfo.h"
+#include "ctcphandler.h"
+
+#include <QDebug>
+
+UserInputHandler::UserInputHandler(Server *parent)
+  : BasicHandler(parent) {
+}
+
+void UserInputHandler::handleUserInput(QString bufname, QString msg) {
+  try {
+    if(msg.isEmpty())
+      return;
+    QString cmd;
+    if(!msg.startsWith('/')) {
+      cmd = QString("SAY");
+    } else {
+      cmd = msg.section(' ', 0, 0).remove(0, 1).toUpper();
+      msg = msg.section(' ', 1);
+    }
+    handle(cmd, Q_ARG(QString, bufname), Q_ARG(QString, msg));
+  } catch(Exception e) {
+    emit displayMsg(Message::Error, "", e.msg());
+  }
+}
+
+// ====================
+//  Public Slots
+// ====================
+
+void UserInputHandler::handleAway(QString bufname, QString msg) {
+  emit putCmd("AWAY", QStringList(msg));
+}
+
+void UserInputHandler::handleDeop(QString bufname, QString msg) {
+  QStringList nicks = msg.split(' ', QString::SkipEmptyParts);
+  QString m = "-"; for(int i = 0; i < nicks.count(); i++) m += 'o';
+  QStringList params;
+  params << bufname << m << nicks;
+  emit putCmd("MODE", params);
+}
+
+void UserInputHandler::handleDevoice(QString bufname, QString msg) {
+  QStringList nicks = msg.split(' ', QString::SkipEmptyParts);
+  QString m = "-"; for(int i = 0; i < nicks.count(); i++) m += 'v';
+  QStringList params;
+  params << bufname << m << nicks;
+  emit putCmd("MODE", params);
+}
+
+void UserInputHandler::handleInvite(QString bufname, QString msg) {
+  QStringList params;
+  params << msg << bufname;
+  emit putCmd("INVITE", params);
+}
+
+void UserInputHandler::handleJoin(QString bufname, QString msg) {
+  emit putCmd("JOIN", QStringList(msg));
+}
+
+void UserInputHandler::handleKick(QString bufname, QString msg) {
+  QStringList params;
+  params << bufname << msg.split(' ', QString::SkipEmptyParts);
+  emit putCmd("KICK", params);
+}
+
+void UserInputHandler::handleList(QString bufname, QString msg) {
+  emit putCmd("LIST", msg.split(' ', QString::SkipEmptyParts));
+}
+
+void UserInputHandler::handleMode(QString bufname, QString msg) {
+  emit putCmd("MODE", msg.split(' ', QString::SkipEmptyParts));
+}
+
+// TODO: show privmsgs
+void UserInputHandler::handleMsg(QString bufname, QString msg) {
+  QString nick = msg.section(" ", 0, 0);
+  msg = msg.section(" ", 1);
+  if(nick.isEmpty() || msg.isEmpty()) return;
+  QStringList params;
+  params << nick << msg;
+  emit putCmd("PRIVMSG", params);
+}
+
+void UserInputHandler::handleNick(QString bufname, QString msg) {
+  QString nick = msg.section(' ', 0, 0);
+  emit putCmd("NICK", QStringList(nick));
+}
+
+void UserInputHandler::handleOp(QString bufname, QString msg) {
+  QStringList nicks = msg.split(' ', QString::SkipEmptyParts);
+  QString m = "+"; for(int i = 0; i < nicks.count(); i++) m += 'o';
+  QStringList params;
+  params << bufname << m << nicks;
+  emit putCmd("MODE", params);
+}
+
+void UserInputHandler::handlePart(QString bufname, QString msg) {
+  QStringList params;
+  params << bufname << msg;
+  emit putCmd("PART", params);
+}
+
+// TODO: implement queries
+void UserInputHandler::handleQuery(QString bufname, QString msg) {
+  QString nick = msg.section(' ', 0, 0);
+  // TODO: usenetworkids
+//   if(!nick.isEmpty())
+//     emit queryRequested(network, nick);
+}
+
+void UserInputHandler::handleQuit(QString bufname, QString msg) {
+  emit putCmd("QUIT", QStringList(msg));
+}
+
+void UserInputHandler::handleQuote(QString bufname, QString msg) {
+  emit putRawLine(msg);
+}
+
+void UserInputHandler::handleSay(QString bufname, QString msg) {
+  if(bufname.isEmpty()) return;  // server buffer
+  QStringList params;
+  params << bufname << msg;
+  emit putCmd("PRIVMSG", params);
+  if(isChannelName(bufname)) {
+    emit displayMsg(Message::Plain, params[0], msg, networkInfo()->myNick(), Message::Self);
+  } else {
+    emit displayMsg(Message::Plain, params[0], msg, networkInfo()->myNick(), Message::Self|Message::PrivMsg);
+  }
+}
+
+void UserInputHandler::handleMe(QString bufname, QString msg) {
+  if(bufname.isEmpty()) return; // server buffer
+  server->ctcpHandler()->query(bufname, "ACTION", msg);
+  emit displayMsg(Message::Action, bufname, msg, networkInfo()->myNick());
+}
+
+void UserInputHandler::handleTopic(QString bufname, QString msg) {
+  if(bufname.isEmpty()) return;
+  QStringList params;
+  params << bufname << msg;
+  emit putCmd("TOPIC", params);
+}
+
+void UserInputHandler::handleVoice(QString bufname, QString msg) {
+  QStringList nicks = msg.split(' ', QString::SkipEmptyParts);
+  QString m = "+"; for(int i = 0; i < nicks.count(); i++) m += 'v';
+  QStringList params;
+  params << bufname << m << nicks;
+  emit putCmd("MODE", params);
+}
+
+
+void UserInputHandler::defaultHandler(QString cmd, QString bufname, QString msg) {
+  emit displayMsg(Message::Error, "", QString("Error: %1 %2").arg(cmd).arg(msg));
+
+}
+
+
diff --git a/src/core/userinputhandler.h b/src/core/userinputhandler.h
new file mode 100644 (file)
index 0000000..014a7c5
--- /dev/null
@@ -0,0 +1,62 @@
+/***************************************************************************
+ *   Copyright (C) 2005/06 by The Quassel Team                             *
+ *   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) any later version.                                   *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program; if not, write to the                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
+ ***************************************************************************/
+
+#ifndef _USERINPUTHANDLER_H_
+#define _USERINPUTHANDLER_H_
+
+#include "basichandler.h"
+
+class Server;
+
+class UserInputHandler : public BasicHandler {
+  Q_OBJECT
+
+public:
+  UserInputHandler(Server *parent = 0);
+
+  void handleUserInput(QString buffer, QString msg);
+  
+public slots:
+  void handleAway(QString, QString);
+  void handleDeop(QString, QString);
+  void handleDevoice(QString, QString);
+  void handleInvite(QString, QString);
+  void handleJoin(QString, QString);
+  void handleKick(QString, QString);
+  void handleList(QString, QString);
+  void handleMode(QString, QString);
+  void handleMsg(QString, QString);
+  void handleNick(QString, QString);
+  void handleOp(QString, QString);
+  void handlePart(QString, QString);
+  void handleQuery(QString, QString);
+  void handleQuit(QString, QString);
+  void handleQuote(QString, QString);
+  void handleSay(QString, QString);
+  void handleTopic(QString, QString);
+  void handleVoice(QString, QString);
+  void handleMe(QString, QString);
+
+  void defaultHandler(QString cmd, QString buf, QString msg);
+
+};
+
+
+#endif
index 8c56390..8dca8fa 100644 (file)
@@ -65,11 +65,11 @@ void BufferViewFilter::dropEvent(QDropEvent *event) {
   
   if(!(data->hasFormat("application/Quassel/BufferItem/row")
        && data->hasFormat("application/Quassel/BufferItem/network")
-       && data->hasFormat("application/Quassel/BufferItem/bufferId")))
+       && data->hasFormat("application/Quassel/BufferItem/bufferInfo")))
     return; // whatever the drop is... it's not a buffer...
   
   event->accept();
-  uint bufferuid = data->data("application/Quassel/BufferItem/bufferId").toUInt();
+  uint bufferuid = data->data("application/Quassel/BufferItem/bufferInfo").toUInt();
   QString networkname = QString::fromUtf8("application/Quassel/BufferItem/network");
   
   for(int rowid = 0; rowid < rowCount(); rowid++) {
@@ -99,7 +99,7 @@ void BufferViewFilter::removeBuffer(const QModelIndex &index) {
   if(index.parent() == QModelIndex())
     return; // only child elements can be deleted
   
-  uint bufferuid = index.data(BufferTreeModel::BufferIdRole).toUInt();
+  uint bufferuid = index.data(BufferTreeModel::BufferInfoRole).toUInt();
   if(customBuffers.contains(bufferuid)) {
     beginRemoveRows(index.parent(), index.row(), index.row());
     customBuffers.removeAt(customBuffers.indexOf(bufferuid));
@@ -121,7 +121,7 @@ bool BufferViewFilter::filterAcceptBuffer(const QModelIndex &source_bufferIndex)
   if((mode & NoInactive) && !isActive) return false;
 
   if((mode & FullCustom)) {
-    uint bufferuid = source_bufferIndex.data(BufferTreeModel::BufferIdRole).toUInt();
+    uint bufferuid = source_bufferIndex.data(BufferTreeModel::BufferInfoRole).toUInt();
     if(!customBuffers.contains(bufferuid))
       return false;
   }
@@ -138,7 +138,7 @@ bool BufferViewFilter::filterAcceptNetwork(const QModelIndex &source_index) cons
     int childcount = sourceModel()->rowCount(source_index);
     for(int rowid = 0; rowid < childcount; rowid++) {
       QModelIndex child = sourceModel()->index(rowid, 0, source_index);
-      uint bufferuid = child.data(BufferTreeModel::BufferIdRole).toUInt();
+      uint bufferuid = child.data(BufferTreeModel::BufferInfoRole).toUInt();
       if(customBuffers.contains(bufferuid))
         return true;
     }
index 4c03152..335e15b 100644 (file)
@@ -122,7 +122,7 @@ uint ChatLine::msgId() const {
   return msg.buffer().uid();
 }
 
-BufferId ChatLine::bufferId() const {
+BufferInfo ChatLine::bufferInfo() const {
   return msg.buffer();
 }
 
index ac80363..2707a17 100644 (file)
@@ -59,7 +59,7 @@ class ChatLine : public QObject, public AbstractUiMsg {
     QString sender() const;
     QString text() const;
     MsgId msgId() const;
-    BufferId bufferId() const;
+    BufferInfo bufferInfo() const;
 
     bool isUrl(int pos) const;
     QUrl getUrl(int pos) const;
index 36b3675..fc4f8ed 100644 (file)
@@ -29,6 +29,8 @@
 //#include "settingspage.h"
 #include "signalproxy.h"
 
+#include "topicwidget.h"
+
 MainWin::MainWin(QtGui *_gui, QWidget *parent) : QMainWindow(parent), gui(_gui) {
   ui.setupUi(this);
   setWindowTitle("Quassel IRC");
@@ -41,7 +43,7 @@ MainWin::MainWin(QtGui *_gui, QWidget *parent) : QMainWindow(parent), gui(_gui)
 }
 
 void MainWin::init() {
-  Client::signalProxy()->attachSignal(this, SIGNAL(requestBacklog(BufferId, QVariant, QVariant)));
+  Client::signalProxy()->attachSignal(this, SIGNAL(requestBacklog(BufferInfo, QVariant, QVariant)));
   ui.bufferWidget->init();
 
   show();
@@ -56,9 +58,6 @@ void MainWin::init() {
   systray->setIcon(QIcon(":/qirc-icon.png"));
   systray->show();
 
-  serverListDlg = new ServerListDlg(this);
-  serverListDlg->setVisible(serverListDlg->showOnStartup());
-
   //setupSettingsDlg();
 
   setupMenus();
@@ -79,6 +78,29 @@ void MainWin::init() {
   disconnectedFromCore();  // Disable menus and stuff
   showCoreConnectionDlg(true); // autoconnect if appropriate
   //ui.actionConnectCore->activate(QAction::Trigger);
+
+  serverListDlg = new ServerListDlg(this);
+  if(serverListDlg->showOnStartup()) {
+    showServerList();
+  }
+
+  // TESTING
+//   setCorner(Qt::TopLeftCorner, Qt::LeftDockWidgetArea);
+//   setCorner(Qt::BottomLeftCorner, Qt::LeftDockWidgetArea);
+
+//   setCorner(Qt::TopRightCorner, Qt::RightDockWidgetArea);
+//   setCorner(Qt::BottomRightCorner, Qt::RightDockWidgetArea);
+  
+//   QDockWidget *dock = new QDockWidget("Topic Dock", this);
+//   dock->setAllowedAreas(Qt::TopDockWidgetArea | Qt::BottomDockWidgetArea);
+
+//   TopicWidget *topicwidget = new TopicWidget(dock);
+//   dock->setWidget(topicwidget);
+  
+//   addDockWidget(Qt::TopDockWidgetArea, dock);
+
+//   ui.menuViews->addAction(dock->toggleViewAction());
+
 }
 
 MainWin::~MainWin() {
@@ -143,7 +165,7 @@ void MainWin::addBufferView(const QString &viewname, QAbstractItemModel *model,
 }
 
 void MainWin::connectedToCore() {
-  foreach(BufferId id, Client::allBufferIds()) {
+  foreach(BufferInfo id, Client::allBufferInfos()) {
     emit requestBacklog(id, 100, -1);
   }
 
@@ -217,12 +239,12 @@ void MainWin::closeEvent(QCloseEvent *event)
   //}
 }
 
-void MainWin::showBuffer(BufferId id) {
+void MainWin::showBuffer(BufferInfo id) {
   showBuffer(Client::buffer(id));
 }
 
 void MainWin::showBuffer(Buffer *b) {
-  currentBuffer = b->bufferId().groupId();
+  currentBuffer = b->bufferInfo().groupId();
   //emit bufferSelected(b);
   //qApp->processEvents();
       
index f522449..c99b42f 100644 (file)
@@ -60,7 +60,7 @@ class MainWin : public QMainWindow {
     void showCoreConnectionDlg(bool autoConnect = false);
     void coreConnectionDlgFinished(int result);
 
-    void showBuffer(BufferId);
+    void showBuffer(BufferInfo);
     void showBuffer(Buffer *);
 
     void importBacklog();
@@ -68,7 +68,7 @@ class MainWin : public QMainWindow {
   signals:
     void connectToCore(const QVariantMap &connInfo);
     void disconnectFromCore();
-    void requestBacklog(BufferId, QVariant, QVariant);
+    void requestBacklog(BufferInfo, QVariant, QVariant);
     void importOldBacklog();
 
   private:
index c8dd0f8..914b80f 100644 (file)
@@ -3,15 +3,15 @@ QT_MOD = core gui network
 
 SRCS += bufferview.cpp bufferviewfilter.cpp bufferwidget.cpp channelwidgetinput.cpp chatline.cpp \
        chatwidget.cpp coreconnectdlg.cpp \
-       guisettings.cpp identities.cpp mainwin.cpp qtgui.cpp serverlist.cpp settingsdlg.cpp style.cpp tabcompleter.cpp
+       guisettings.cpp identities.cpp mainwin.cpp qtgui.cpp serverlist.cpp settingsdlg.cpp style.cpp tabcompleter.cpp topicwidget.cpp
 
 HDRS += bufferview.h bufferviewfilter.h bufferwidget.h channelwidgetinput.h chatline.h chatwidget.h coreconnectdlg.h \
-       guisettings.h identities.h mainwin.h qtgui.h serverlist.h settingsdlg.h settingspage.h style.h tabcompleter.h
+       guisettings.h identities.h mainwin.h qtgui.h serverlist.h settingsdlg.h settingspage.h style.h tabcompleter.h topicwidget.h
 
 
 FORMNAMES = identitiesdlg.ui identitieseditdlg.ui networkeditdlg.ui mainwin.ui nickeditdlg.ui serverlistdlg.ui \
             servereditdlg.ui coreconnectdlg.ui bufferviewwidget.ui bufferwidget.ui settingsdlg.ui \
-            buffermgmtpage.ui connectionpage.ui usermgmtpage.ui
+            buffermgmtpage.ui connectionpage.ui usermgmtpage.ui topicwidget.ui
 
 for(ui, FORMNAMES) {
   FRMS += ui/$${ui}
diff --git a/src/qtgui/topicwidget.cpp b/src/qtgui/topicwidget.cpp
new file mode 100644 (file)
index 0000000..a16807f
--- /dev/null
@@ -0,0 +1,33 @@
+/***************************************************************************
+ *   Copyright (C) 2005/06 by The Quassel Team                             *
+ *   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) any later version.                                   *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program; if not, write to the                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
+ ***************************************************************************/
+
+#include "topicwidget.h"
+
+#include <QDebug>
+
+TopicWidget::TopicWidget(QWidget *parent)
+  : QWidget(parent)
+{
+  ui.setupUi(this);
+  ui.topicLineEdit->setText("+++ DUMMY TOPIC +++ DUMMY TOPIC +++");
+}
+
+TopicWidget::~TopicWidget() {
+}
diff --git a/src/qtgui/topicwidget.h b/src/qtgui/topicwidget.h
new file mode 100644 (file)
index 0000000..d6c1ab9
--- /dev/null
@@ -0,0 +1,41 @@
+/***************************************************************************
+ *   Copyright (C) 2005/06 by The Quassel Team                             *
+ *   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) any later version.                                   *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program; if not, write to the                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
+ ***************************************************************************/
+
+#ifndef _TOPICWIDGET_H_
+#define _TOPICWIDGET_H_
+
+#include <QWidget>
+
+#include "ui_topicwidget.h"
+
+class TopicWidget : public QWidget {
+  Q_OBJECT
+
+public:
+  TopicWidget(QWidget *parent = 0);
+  virtual ~TopicWidget();
+
+  
+private:
+  Ui::TopicWidget ui;
+};
+
+
+#endif
diff --git a/src/qtgui/ui/topicwidget.ui b/src/qtgui/ui/topicwidget.ui
new file mode 100644 (file)
index 0000000..9d3edb1
--- /dev/null
@@ -0,0 +1,60 @@
+<ui version="4.0" >
+ <class>TopicWidget</class>
+ <widget class="QWidget" name="TopicWidget" >
+  <property name="geometry" >
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>568</width>
+    <height>25</height>
+   </rect>
+  </property>
+  <property name="sizePolicy" >
+   <sizepolicy vsizetype="Preferred" hsizetype="Preferred" >
+    <horstretch>0</horstretch>
+    <verstretch>0</verstretch>
+   </sizepolicy>
+  </property>
+  <property name="minimumSize" >
+   <size>
+    <width>0</width>
+    <height>0</height>
+   </size>
+  </property>
+  <property name="baseSize" >
+   <size>
+    <width>0</width>
+    <height>0</height>
+   </size>
+  </property>
+  <property name="windowTitle" >
+   <string>Form</string>
+  </property>
+  <layout class="QHBoxLayout" >
+   <property name="leftMargin" >
+    <number>0</number>
+   </property>
+   <property name="topMargin" >
+    <number>0</number>
+   </property>
+   <property name="rightMargin" >
+    <number>0</number>
+   </property>
+   <property name="bottomMargin" >
+    <number>0</number>
+   </property>
+   <item>
+    <widget class="QLineEdit" name="topicLineEdit" />
+   </item>
+   <item>
+    <widget class="QToolButton" name="topicEditButton" >
+     <property name="text" >
+      <string>...</string>
+     </property>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
index 28ce89d..c1e9956 100644 (file)
@@ -39,8 +39,8 @@ MsgId ChatLine::msgId() const {
   return _msgId;
 }
 
-BufferId ChatLine::bufferId() const {
-  return _bufferId;
+BufferInfo ChatLine::bufferInfo() const {
+  return _bufferInfo;
 }
 
 QDateTime ChatLine::timeStamp() const {
index 13d3067..c6daddd 100644 (file)
@@ -30,13 +30,13 @@ class ChatLine : public AbstractUiMsg {
     virtual QString sender() const;
     virtual QString text() const;
     virtual MsgId msgId() const;
-    virtual BufferId bufferId() const;
+    virtual BufferInfo bufferInfo() const;
     virtual QDateTime timeStamp() const;
 
   private:
     QString _sender, _text;
     MsgId _msgId;
-    BufferId _bufferId;
+    BufferInfo _bufferInfo;
     QDateTime _timeStamp;
 
 };
index bbeb456..1991da9 100644 (file)
 QtopiaMainWin::QtopiaMainWin(QWidget *parent, Qt::WFlags flags) : QMainWindow(parent, flags) {
   qRegisterMetaType<QVariant>("QVariant");
   qRegisterMetaType<Message>("Message");
-  qRegisterMetaType<BufferId>("BufferId");
+  qRegisterMetaType<BufferInfo>("BufferInfo");
   qRegisterMetaTypeStreamOperators<QVariant>("QVariant");
   qRegisterMetaTypeStreamOperators<Message>("Message");
-  qRegisterMetaTypeStreamOperators<BufferId>("BufferId");
+  qRegisterMetaTypeStreamOperators<BufferInfo>("BufferInfo");
 
   Global::runMode = Global::ClientOnly;
 
@@ -68,7 +68,7 @@ QtopiaMainWin::QtopiaMainWin(QWidget *parent, Qt::WFlags flags) : QMainWindow(pa
 
 // at this point, client is fully initialized
 void QtopiaMainWin::init() {
-  Client::signalProxy()->attachSignal(this, SIGNAL(requestBacklog(BufferId, QVariant, QVariant)));
+  Client::signalProxy()->attachSignal(this, SIGNAL(requestBacklog(BufferInfo, QVariant, QVariant)));
   connect(Client::bufferModel(), SIGNAL(bufferSelected(Buffer *)), this, SLOT(showBuffer(Buffer *)));
 
   CoreConnectDlg *dlg = new CoreConnectDlg(this);
@@ -83,12 +83,12 @@ QtopiaMainWin::~QtopiaMainWin() {
 }
 
 void QtopiaMainWin::connectedToCore() {
-  foreach(BufferId id, Client::allBufferIds()) {
+  foreach(BufferInfo id, Client::allBufferInfos()) {
     emit requestBacklog(id, 100, -1);
   }
   // FIXME just for testing: select first available buffer
-  if(Client::allBufferIds().count()) {
-    Buffer *b = Client::buffer(Client::allBufferIds()[0]);
+  if(Client::allBufferInfos().count()) {
+    Buffer *b = Client::buffer(Client::allBufferInfos()[0]);
     Client::bufferModel()->selectBuffer(b);
   }
 }
index 5d3ab9e..70ab891 100644 (file)
@@ -44,7 +44,7 @@ class QtopiaMainWin : public QMainWindow {
   signals:
     void connectToCore(const QVariantMap &connInfo);
     void disconnectFromCore();
-    void requestBacklog(BufferId, QVariant, QVariant);
+    void requestBacklog(BufferInfo, QVariant, QVariant);
 
   private slots:
     void showBuffer(Buffer *);