-// ==============================
-// 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 *)));
-
- 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(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 &)));
- connect(mainUi, SIGNAL(disconnectFromCore()), this, SLOT(disconnectFromCore()));
- connect(this, SIGNAL(connected()), mainUi, SLOT(connectedToCore()));
- connect(this, SIGNAL(disconnected()), mainUi, SLOT(disconnectedFromCore()));
-
- layoutTimer = new QTimer(this);
- layoutTimer->setInterval(0);
- layoutTimer->setSingleShot(false);
- connect(layoutTimer, SIGNAL(timeout()), this, SLOT(layoutMsg()));
-
-}
-
-bool Client::isConnected() {
- 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(conn["Host"].toString().isEmpty()) {
- clientMode = LocalCore;
- socket = new QBuffer(this);
- connect(socket, SIGNAL(readyRead()), this, SLOT(coreHasData()));
- socket->open(QIODevice::ReadWrite);
- //QVariant state = connectToLocalCore(coreConnectionInfo["User"].toString(), coreConnectionInfo["Password"].toString());
- //syncToCore(state);
- coreSocketConnected();
- } else {
- clientMode = RemoteCore;
- emit coreConnectionMsg(tr("Connecting..."));
- Q_ASSERT(!socket);
- QTcpSocket *sock = new QTcpSocket(this);
- socket = sock;
- connect(sock, SIGNAL(readyRead()), this, SLOT(coreHasData()));
- connect(sock, SIGNAL(connected()), this, SLOT(coreSocketConnected()));
- connect(sock, SIGNAL(disconnected()), this, SLOT(coreSocketDisconnected()));
- connect(signalProxy(), SIGNAL(peerDisconnected()), this, SLOT(coreSocketDisconnected()));
- //connect(sock, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(coreSocketStateChanged(QAbstractSocket::SocketState)));
- connect(sock, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(coreSocketError(QAbstractSocket::SocketError)));
- sock->connectToHost(conn["Host"].toString(), conn["Port"].toUInt());
- }
-}
-
-void Client::disconnectFromCore() {
- if(clientMode == RemoteCore) {
- socket->close();
- //QAbstractSocket *sock = qobject_cast<QAbstractSocket*>(socket);
- //Q_ASSERT(sock);
- //sock->disconnectFromHost();
- } else {
- socket->close();
- //disconnectFromLocalCore();
- coreSocketDisconnected();
- }
-}
-
-void Client::coreSocketConnected() {
- connect(this, SIGNAL(recvPartialItem(uint, uint)), this, SIGNAL(coreConnectionProgress(uint, uint)));
- emit coreConnectionMsg(tr("Synchronizing to core..."));
- QVariantMap clientInit;
- clientInit["GuiProtocol"] = GUI_PROTOCOL;
- clientInit["User"] = coreConnectionInfo["User"].toString();
- clientInit["Password"] = coreConnectionInfo["Password"].toString();
- writeDataToDevice(socket, clientInit);
-}
-
-void Client::coreSocketDisconnected() {
- 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 bufferInfos.
- // So we cannot simply go through the array in a loop (or use qDeleteAll) for deletion...
- 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();
- layoutQueue.clear();
- layoutTimer->stop();
-}
-
-void Client::coreSocketStateChanged(QAbstractSocket::SocketState state) {
- if(state == QAbstractSocket::UnconnectedState) coreSocketDisconnected();
-}
-
-void Client::recvCoreState(const QVariant &state) {
- disconnect(this, SIGNAL(recvPartialItem(uint, uint)), this, SIGNAL(coreConnectionProgress(uint, uint)));
- disconnect(socket, 0, this, 0); // rest of communication happens through SignalProxy
- signalProxy()->addPeer(socket);
- syncToCore(state);
-}
-
-// TODO: auth errors
-void Client::syncToCore(const QVariant &coreState) {
- if(!coreState.toMap().contains("SessionState")) {
- emit coreConnectionError(tr("Invalid data received from core!"));
- disconnectFromCore();
- return;
- }
-
- QVariantMap sessionState = coreState.toMap()["SessionState"].toMap();
-
- // store sessionData
- QVariantMap sessData = sessionState["SessionData"].toMap();
- foreach(QString key, sessData.keys())
- recvSessionData(key, sessData[key]);
-
- // store Buffer details
- QVariantList coreBuffers = sessionState["Buffers"].toList();
- /* make lookups by id faster */
- foreach(QVariant vid, coreBuffers) {
- 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());
- }
-
- 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++;
+
+void Client::removeIdentity(IdentityId id)
+{
+ emit instance()->requestRemoveIdentity(id);
+}
+
+
+void Client::coreIdentityCreated(const Identity &other)
+{
+ if (!_identities.contains(other.id())) {
+ Identity *identity = new Identity(other, this);
+ _identities[other.id()] = identity;
+ identity->setInitialized();
+ signalProxy()->synchronize(identity);
+ emit identityCreated(other.id());
+ }
+ else {
+ qWarning() << tr("Identity already exists in client!");
+ }
+}
+
+
+void Client::coreIdentityRemoved(IdentityId id)
+{
+ if (_identities.contains(id)) {
+ emit identityRemoved(id);
+ Identity *i = _identities.take(id);
+ i->deleteLater();
+ }
+}
+
+
+/*** User input handling ***/
+
+void Client::userInput(const BufferInfo &bufferInfo, const QString &message)
+{
+ // we need to make sure that AliasManager is ready before processing input
+ if (aliasManager() && aliasManager()->isInitialized())
+ inputHandler()->handleUserInput(bufferInfo, message);
+ else
+ instance()->_userInputBuffer.append(qMakePair(bufferInfo, message));
+}
+
+
+void Client::sendBufferedUserInput()
+{
+ for (int i = 0; i < _userInputBuffer.count(); i++)
+ userInput(_userInputBuffer.at(i).first, _userInputBuffer.at(i).second);
+
+ _userInputBuffer.clear();
+}
+
+
+/*** core connection stuff ***/
+
+void Client::connectionStateChanged(CoreConnection::ConnectionState state)
+{
+ switch (state) {
+ case CoreConnection::Disconnected:
+ setDisconnectedFromCore();
+ break;
+ case CoreConnection::Synchronized:
+ setSyncedToCore();
+ break;
+ default:
+ break;
+ }
+}
+
+
+void Client::setSyncedToCore()
+{
+ // create buffersyncer
+ Q_ASSERT(!_bufferSyncer);
+ _bufferSyncer = new BufferSyncer(this);
+ connect(bufferSyncer(), SIGNAL(lastSeenMsgSet(BufferId, MsgId)), _networkModel, SLOT(setLastSeenMsgId(BufferId, MsgId)));
+ connect(bufferSyncer(), SIGNAL(markerLineSet(BufferId, MsgId)), _networkModel, SLOT(setMarkerLineMsgId(BufferId, MsgId)));
+ connect(bufferSyncer(), SIGNAL(bufferRemoved(BufferId)), this, SLOT(bufferRemoved(BufferId)));
+ connect(bufferSyncer(), SIGNAL(bufferRenamed(BufferId, QString)), this, SLOT(bufferRenamed(BufferId, QString)));
+ connect(bufferSyncer(), SIGNAL(buffersPermanentlyMerged(BufferId, BufferId)), this, SLOT(buffersPermanentlyMerged(BufferId, BufferId)));
+ connect(bufferSyncer(), SIGNAL(buffersPermanentlyMerged(BufferId, BufferId)), _messageModel, SLOT(buffersPermanentlyMerged(BufferId, BufferId)));
+ connect(bufferSyncer(), SIGNAL(bufferMarkedAsRead(BufferId)), SIGNAL(bufferMarkedAsRead(BufferId)));
+ connect(networkModel(), SIGNAL(requestSetLastSeenMsg(BufferId, MsgId)), bufferSyncer(), SLOT(requestSetLastSeenMsg(BufferId, const MsgId &)));
+
+ SignalProxy *p = signalProxy();
+ p->synchronize(bufferSyncer());
+
+ // create a new BufferViewManager
+ Q_ASSERT(!_bufferViewManager);
+ _bufferViewManager = new ClientBufferViewManager(p, this);
+ connect(_bufferViewManager, SIGNAL(initDone()), _bufferViewOverlay, SLOT(restore()));
+
+ // create AliasManager
+ Q_ASSERT(!_aliasManager);
+ _aliasManager = new ClientAliasManager(this);
+ connect(aliasManager(), SIGNAL(initDone()), SLOT(sendBufferedUserInput()));
+ p->synchronize(aliasManager());
+
+ // create NetworkConfig
+ Q_ASSERT(!_networkConfig);
+ _networkConfig = new NetworkConfig("GlobalNetworkConfig", this);
+ p->synchronize(networkConfig());
+
+ // create IgnoreListManager
+ Q_ASSERT(!_ignoreListManager);
+ _ignoreListManager = new ClientIgnoreListManager(this);
+ p->synchronize(ignoreListManager());
+
+ Q_ASSERT(!_transferManager);
+ _transferManager = new ClientTransferManager(this);
+ p->synchronize(transferManager());
+
+ // trigger backlog request once all active bufferviews are initialized
+ connect(bufferViewOverlay(), SIGNAL(initDone()), this, SLOT(requestInitialBacklog()));
+
+ _connected = true;
+ emit connected();
+ emit coreConnectionStateChanged(true);
+}
+
+
+void Client::requestInitialBacklog()
+{
+ // usually it _should_ take longer until the bufferViews are initialized, so that's what
+ // triggers this slot. But we have to make sure that we know all buffers yet.
+ // so we check the BufferSyncer and in case it wasn't initialized we wait for that instead
+ if (!bufferSyncer()->isInitialized()) {
+ disconnect(bufferViewOverlay(), SIGNAL(initDone()), this, SLOT(requestInitialBacklog()));
+ connect(bufferSyncer(), SIGNAL(initDone()), this, SLOT(requestInitialBacklog()));
+ return;
+ }
+ disconnect(bufferViewOverlay(), SIGNAL(initDone()), this, SLOT(requestInitialBacklog()));
+ disconnect(bufferSyncer(), SIGNAL(initDone()), this, SLOT(requestInitialBacklog()));
+
+ _backlogManager->requestInitialBacklog();
+}
+
+
+void Client::disconnectFromCore()
+{
+ if (!coreConnection()->isConnected())
+ return;
+
+ coreConnection()->disconnectFromCore();
+}
+
+
+void Client::setDisconnectedFromCore()
+{
+ _connected = false;
+ _coreFeatures = 0;
+
+ emit disconnected();
+ emit coreConnectionStateChanged(false);
+
+ backlogManager()->reset();
+ messageProcessor()->reset();
+
+ // Clear internal data. Hopefully nothing relies on it at this point.
+
+ if (_bufferSyncer) {
+ _bufferSyncer->deleteLater();
+ _bufferSyncer = 0;
+ }
+
+ if (_bufferViewManager) {
+ _bufferViewManager->deleteLater();
+ _bufferViewManager = 0;
+ }
+
+ _bufferViewOverlay->reset();
+
+ if (_aliasManager) {
+ _aliasManager->deleteLater();
+ _aliasManager = 0;