Quassel IRC  Pre-Release
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros
coreconnection.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  * Copyright (C) 2005-2015 by the Quassel Project *
3  * devel@quassel-irc.org *
4  * *
5  * This program is free software; you can redistribute it and/or modify *
6  * it under the terms of the GNU General Public License as published by *
7  * the Free Software Foundation; either version 2 of the License, or *
8  * (at your option) version 3. *
9  * *
10  * This program is distributed in the hope that it will be useful, *
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13  * GNU General Public License for more details. *
14  * *
15  * You should have received a copy of the GNU General Public License *
16  * along with this program; if not, write to the *
17  * Free Software Foundation, Inc., *
18  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
19  ***************************************************************************/
20 
21 #include "coreconnection.h"
22 
23 #include "client.h"
24 #include "clientauthhandler.h"
25 #include "clientsettings.h"
26 #include "coreaccountmodel.h"
27 #include "identity.h"
28 #include "internalpeer.h"
29 #include "network.h"
30 #include "networkmodel.h"
31 #include "quassel.h"
32 #include "signalproxy.h"
33 #include "util.h"
34 
36 
38  : QObject(parent),
39  _authHandler(0),
40  _state(Disconnected),
41  _wantReconnect(false),
42  _wasReconnect(false),
43  _progressMinimum(0),
44  _progressMaximum(-1),
45  _progressValue(-1),
46  _resetting(false)
47 {
48  qRegisterMetaType<ConnectionState>("CoreConnection::ConnectionState");
49 }
50 
51 
53 {
55  connect(Client::signalProxy(), SIGNAL(lagUpdated(int)), SIGNAL(lagUpdated(int)));
56 
57  _reconnectTimer.setSingleShot(true);
58  connect(&_reconnectTimer, SIGNAL(timeout()), SLOT(reconnectTimeout()));
59 
60  _qNetworkConfigurationManager = new QNetworkConfigurationManager(this);
61  connect(_qNetworkConfigurationManager, SIGNAL(onlineStateChanged(bool)), SLOT(onlineStateChanged(bool)));
62 
64  s.initAndNotify("PingTimeoutInterval", this, SLOT(pingTimeoutIntervalChanged(QVariant)), 60);
65  s.initAndNotify("ReconnectInterval", this, SLOT(reconnectIntervalChanged(QVariant)), 60);
66  s.notify("NetworkDetectionMode", this, SLOT(networkDetectionModeChanged(QVariant)));
68 }
69 
70 
72 {
73  return Client::coreAccountModel();
74 }
75 
76 
77 void CoreConnection::setProgressText(const QString &text)
78 {
79  if (_progressText != text) {
80  _progressText = text;
81  emit progressTextChanged(text);
82  }
83 }
84 
85 
87 {
88  if (_progressValue != value) {
89  _progressValue = value;
90  emit progressValueChanged(value);
91  }
92 }
93 
94 
96 {
97  if (_progressMinimum != minimum) {
98  _progressMinimum = minimum;
100  }
101 }
102 
103 
105 {
106  if (_progressMaximum != maximum) {
107  _progressMaximum = maximum;
108  emit progressRangeChanged(_progressMinimum, maximum);
109  }
110 }
111 
112 
113 void CoreConnection::updateProgress(int value, int max)
114 {
115  if (max != _progressMaximum) {
116  _progressMaximum = max;
118  }
119  setProgressValue(value);
120 }
121 
122 
124 {
125  if (!_peer) {
127  if (_wantReconnect && s.autoReconnect()) {
128  // If using QNetworkConfigurationManager, we don't want to reconnect if we're offline
130  if (!_qNetworkConfigurationManager->isOnline()) {
131  return;
132  }
133  }
134  reconnectToCore();
135  }
136  }
137 }
138 
139 
141 {
146  else {
148  }
149 }
150 
151 
152 void CoreConnection::pingTimeoutIntervalChanged(const QVariant &interval)
153 {
156  Client::signalProxy()->setMaxHeartBeatCount(interval.toInt() / 30); // interval is 30 seconds
157 }
158 
159 
160 void CoreConnection::reconnectIntervalChanged(const QVariant &interval)
161 {
162  _reconnectTimer.setInterval(interval.toInt() * 1000);
163 }
164 
165 
167 {
170  return;
171 
172  if(isOnline) {
173  // qDebug() << "QNetworkConfigurationManager reports Online";
174  if (state() == Disconnected) {
175  if (_wantReconnect && s.autoReconnect()) {
176  reconnectToCore();
177  }
178  }
179  } else {
180  // qDebug() << "QNetworkConfigurationManager reports Offline";
181  if (state() != Disconnected && !isLocalConnection())
182  disconnectFromCore(tr("Network is down"), true);
183  }
184 }
185 
186 
188 {
189  return _peer && _peer->isSecure();
190 }
191 
192 
194 {
195  if (!isConnected())
196  return false;
197  if (currentAccount().isInternal())
198  return true;
199  if (_authHandler)
200  return _authHandler->isLocal();
201  if (_peer)
202  return _peer->isLocal();
203 
204  return false;
205 }
206 
207 
209 {
211 }
212 
213 
215 {
216  if (state != _state) {
217  _state = state;
218  emit stateChanged(state);
219  if (state == Disconnected)
220  emit disconnected();
221  }
222 }
223 
224 
225 void CoreConnection::coreSocketError(QAbstractSocket::SocketError error, const QString &errorString)
226 {
227  Q_UNUSED(error)
228 
229  disconnectFromCore(errorString, true);
230 }
231 
232 
234 {
236  _wasReconnect = false;
238 }
239 
240 
242 {
243  disconnectFromCore(QString(), false); // requested disconnect, so don't try to reconnect
244 }
245 
246 
247 void CoreConnection::disconnectFromCore(const QString &errorString, bool wantReconnect)
248 {
249  if (wantReconnect)
250  _reconnectTimer.start();
251  else
252  _reconnectTimer.stop();
253 
254  _wantReconnect = wantReconnect; // store if disconnect was requested
255  _wasReconnect = false;
256 
257  if (_authHandler)
258  _authHandler->close();
259  else if(_peer)
260  _peer->close();
261 
262  if (errorString.isEmpty())
263  emit connectionError(tr("Disconnected"));
264  else
265  emit connectionError(errorString);
266 }
267 
268 
269 void CoreConnection::resetConnection(bool wantReconnect)
270 {
271  if (_resetting)
272  return;
273  _resetting = true;
274 
275  _wantReconnect = wantReconnect;
276 
277  if (_authHandler) {
278  disconnect(_authHandler, 0, this, 0);
279  _authHandler->close();
280  _authHandler->deleteLater();
281  _authHandler = 0;
282  }
283 
284  if (_peer) {
285  disconnect(_peer, 0, this, 0);
286  // peer belongs to the sigproxy and thus gets deleted by it
287  _peer->close();
288  _peer = 0;
289  }
290 
291  _netsToSync.clear();
292  _numNetsToSync = 0;
293 
294  setProgressMaximum(-1); // disable
296  emit lagUpdated(-1);
297 
298  emit connectionMsg(tr("Disconnected from core."));
299  emit encrypted(false);
301 
302  // initiate if a reconnect if appropriate
304  if (wantReconnect && s.autoReconnect()) {
305  _reconnectTimer.start();
306  }
307 
308  _resetting = false;
309 }
310 
311 
313 {
314  if (currentAccount().isValid()) {
315  _wasReconnect = true;
316  connectToCore(currentAccount().accountId());
317  }
318 }
319 
320 
322 {
323  if (isConnected())
324  return false;
325 
327 
328  // FIXME: Don't force connection to internal core in mono client
329  if (Quassel::runMode() == Quassel::Monolithic) {
330  _account = accountModel()->account(accountModel()->internalAccount());
331  Q_ASSERT(_account.isValid());
332  }
333  else {
334  if (!accId.isValid()) {
335  // check our settings and figure out what to do
336  if (!s.autoConnectOnStartup())
337  return false;
339  accId = s.autoConnectAccount();
340  else
341  accId = s.lastAccount();
342  if (!accId.isValid())
343  return false;
344  }
345  _account = accountModel()->account(accId);
346  if (!_account.accountId().isValid()) {
347  return false;
348  }
349  if (Quassel::runMode() != Quassel::Monolithic) {
350  if (_account.isInternal())
351  return false;
352  }
353  }
354 
355  s.setLastAccount(accId);
357  return true;
358 }
359 
360 
362 {
363  if (_authHandler) {
364  qWarning() << Q_FUNC_INFO << "Already connected!";
365  return;
366  }
367 
368  if (currentAccount().isInternal()) {
369  if (Quassel::runMode() != Quassel::Monolithic) {
370  qWarning() << "Cannot connect to internal core in client-only mode!";
371  return;
372  }
373  emit startInternalCore();
374 
375  InternalPeer *peer = new InternalPeer();
376  _peer = peer;
377  Client::instance()->signalProxy()->addPeer(peer); // sigproxy will take ownership
378  emit connectToInternalCore(peer);
380 
381  return;
382  }
383 
385 
386  connect(_authHandler, SIGNAL(disconnected()), SLOT(coreSocketDisconnected()));
387  connect(_authHandler, SIGNAL(connectionReady()), SLOT(onConnectionReady()));
388  connect(_authHandler, SIGNAL(socketError(QAbstractSocket::SocketError,QString)), SLOT(coreSocketError(QAbstractSocket::SocketError,QString)));
389  connect(_authHandler, SIGNAL(transferProgress(int,int)), SLOT(updateProgress(int,int)));
390  connect(_authHandler, SIGNAL(requestDisconnect(QString,bool)), SLOT(disconnectFromCore(QString,bool)));
391 
392  connect(_authHandler, SIGNAL(errorMessage(QString)), SIGNAL(connectionError(QString)));
393  connect(_authHandler, SIGNAL(errorPopup(QString)), SIGNAL(connectionErrorPopup(QString)), Qt::QueuedConnection);
394  connect(_authHandler, SIGNAL(statusMessage(QString)), SIGNAL(connectionMsg(QString)));
395  connect(_authHandler, SIGNAL(encrypted(bool)), SIGNAL(encrypted(bool)));
396  connect(_authHandler, SIGNAL(startCoreSetup(QVariantList)), SIGNAL(startCoreSetup(QVariantList)));
397  connect(_authHandler, SIGNAL(coreSetupFailed(QString)), SIGNAL(coreSetupFailed(QString)));
398  connect(_authHandler, SIGNAL(coreSetupSuccessful()), SIGNAL(coreSetupSuccess()));
399  connect(_authHandler, SIGNAL(userAuthenticationRequired(CoreAccount*,bool*,QString)), SIGNAL(userAuthenticationRequired(CoreAccount*,bool*,QString)));
400  connect(_authHandler, SIGNAL(handleNoSslInClient(bool*)), SIGNAL(handleNoSslInClient(bool*)));
401  connect(_authHandler, SIGNAL(handleNoSslInCore(bool*)), SIGNAL(handleNoSslInCore(bool*)));
402 #ifdef HAVE_SSL
403  connect(_authHandler, SIGNAL(handleSslErrors(const QSslSocket*,bool*,bool*)), SIGNAL(handleSslErrors(const QSslSocket*,bool*,bool*)));
404 #endif
405 
406  connect(_authHandler, SIGNAL(loginSuccessful(CoreAccount)), SLOT(onLoginSuccessful(CoreAccount)));
408 
410  _authHandler->connectToCore();
411 }
412 
413 
415 {
416  _authHandler->setupCore(setupData);
417 }
418 
419 
420 void CoreConnection::loginToCore(const QString &user, const QString &password, bool remember)
421 {
422  _authHandler->login(user, password, remember);
423 }
424 
425 
427 {
428  updateProgress(0, 0);
429 
430  // save current account data
432  accountModel()->save();
433 
434  _reconnectTimer.stop();
435 
436  setProgressText(tr("Receiving session state"));
438  emit connectionMsg(tr("Synchronizing to %1...").arg(account.accountName()));
439 }
440 
441 
443 {
444  updateProgress(100, 100);
445 
446  disconnect(_authHandler, 0, this, 0);
447  _authHandler->deleteLater();
448  _authHandler = 0;
449 
450  _peer = peer;
451  connect(peer, SIGNAL(disconnected()), SLOT(coreSocketDisconnected()));
452  connect(peer, SIGNAL(statusMessage(QString)), SIGNAL(connectionMsg(QString)));
453  connect(peer, SIGNAL(socketError(QAbstractSocket::SocketError,QString)), SLOT(coreSocketError(QAbstractSocket::SocketError,QString)));
454 
455  Client::signalProxy()->addPeer(_peer); // sigproxy takes ownership of the peer!
456 
457  syncToCore(sessionState);
458 }
459 
460 
462 {
463  updateProgress(100, 100);
464 
465  Client::setCoreFeatures(Quassel::features()); // mono connection...
466 
468  syncToCore(sessionState);
469 }
470 
471 
473 {
474  setProgressText(tr("Receiving network states"));
475  updateProgress(0, 100);
476 
477  // create identities
478  foreach(const QVariant &vid, sessionState.identities) {
480  }
481 
482  // create buffers
483  // FIXME: get rid of this crap -- why?
484  NetworkModel *networkModel = Client::networkModel();
485  Q_ASSERT(networkModel);
486  foreach(const QVariant &vinfo, sessionState.bufferInfos)
487  networkModel->bufferUpdated(vinfo.value<BufferInfo>()); // create BufferItems
488 
489  // prepare sync progress thingys...
490  // FIXME: Care about removal of networks
491  _numNetsToSync = sessionState.networkIds.count();
493 
494  // create network objects
495  foreach(const QVariant &networkid, sessionState.networkIds) {
496  NetworkId netid = networkid.value<NetworkId>();
497  if (Client::network(netid))
498  continue;
499  Network *net = new Network(netid, Client::instance());
500  _netsToSync.insert(net);
501  connect(net, SIGNAL(initDone()), SLOT(networkInitDone()));
502  connect(net, SIGNAL(destroyed()), SLOT(networkInitDone()));
503  Client::addNetwork(net);
504  }
505  checkSyncState();
506 }
507 
508 
509 // this is also called for destroyed networks!
511 {
512  QObject *net = sender();
513  Q_ASSERT(net);
514  disconnect(net, 0, this, 0);
515  _netsToSync.remove(net);
517  checkSyncState();
518 }
519 
520 
522 {
523  if (_netsToSync.isEmpty() && state() >= Synchronizing) {
525  setProgressText(tr("Synchronized to %1").arg(currentAccount().accountName()));
526  setProgressMaximum(-1);
527  emit synchronized();
528  }
529 }