1 /***************************************************************************
2 * Copyright (C) 2005-2019 by the Quassel Project *
3 * devel@quassel-irc.org *
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. *
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. *
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 ***************************************************************************/
21 #include "coresession.h"
28 #include "corebacklogmanager.h"
29 #include "corebuffersyncer.h"
30 #include "corebufferviewmanager.h"
31 #include "coredccconfig.h"
32 #include "coreeventmanager.h"
33 #include "coreidentity.h"
34 #include "coreignorelistmanager.h"
36 #include "coreirclisthelper.h"
37 #include "corenetwork.h"
38 #include "corenetworkconfig.h"
39 #include "coresessioneventprocessor.h"
40 #include "coretransfermanager.h"
41 #include "coreuserinputhandler.h"
42 #include "coreusersettings.h"
43 #include "ctcpparser.h"
44 #include "eventstringifier.h"
45 #include "internalpeer.h"
46 #include "ircchannel.h"
47 #include "ircparser.h"
49 #include "messageevent.h"
50 #include "remotepeer.h"
54 class ProcessMessagesEvent : public QEvent
57 ProcessMessagesEvent()
58 : QEvent(QEvent::User)
62 CoreSession::CoreSession(UserId uid, bool restoreState, bool strictIdentEnabled, QObject* parent)
65 , _strictIdentEnabled(strictIdentEnabled)
66 , _signalProxy(new SignalProxy(SignalProxy::Server, this))
68 , _bufferSyncer(new CoreBufferSyncer(this))
69 , _backlogManager(new CoreBacklogManager(this))
70 , _bufferViewManager(new CoreBufferViewManager(_signalProxy, this))
71 , _dccConfig(new CoreDccConfig(this))
72 , _ircListHelper(new CoreIrcListHelper(this))
73 , _networkConfig(new CoreNetworkConfig("GlobalNetworkConfig", this))
74 , _coreInfo(new CoreInfo(this))
75 , _transferManager(new CoreTransferManager(this))
76 , _eventManager(new CoreEventManager(this))
77 , _eventStringifier(new EventStringifier(this))
78 , _sessionEventProcessor(new CoreSessionEventProcessor(this))
79 , _ctcpParser(new CtcpParser(this))
80 , _ircParser(new IrcParser(this))
81 , scriptEngine(new QScriptEngine(this))
82 , _processMessages(false)
83 , _ignoreListManager(this)
84 , _highlightRuleManager(this)
85 , _metricsServer(Core::instance()->metricsServer())
87 SignalProxy* p = signalProxy();
88 p->setHeartBeatInterval(30);
89 p->setMaxHeartBeatCount(60); // 30 mins until we throw a dead socket out
91 connect(p, &SignalProxy::peerRemoved, this, &CoreSession::removeClient);
93 connect(p, &SignalProxy::connected, this, &CoreSession::clientsConnected);
94 connect(p, &SignalProxy::disconnected, this, &CoreSession::clientsDisconnected);
96 p->attachSlot(SIGNAL(sendInput(BufferInfo,QString)), this, &CoreSession::msgFromClient);
97 p->attachSignal(this, &CoreSession::displayMsg);
98 p->attachSignal(this, &CoreSession::displayStatusMsg);
100 p->attachSignal(this, &CoreSession::identityCreated);
101 p->attachSignal(this, &CoreSession::identityRemoved);
102 p->attachSlot(SIGNAL(createIdentity(Identity,QVariantMap)), this, selectOverload<const Identity&, const QVariantMap&>(&CoreSession::createIdentity));
103 p->attachSlot(SIGNAL(removeIdentity(IdentityId)), this, &CoreSession::removeIdentity);
105 p->attachSignal(this, &CoreSession::networkCreated);
106 p->attachSignal(this, &CoreSession::networkRemoved);
107 p->attachSlot(SIGNAL(createNetwork(NetworkInfo,QStringList)), this,&CoreSession::createNetwork);
108 p->attachSlot(SIGNAL(removeNetwork(NetworkId)), this, &CoreSession::removeNetwork);
110 p->attachSlot(SIGNAL(changePassword(PeerPtr,QString,QString,QString)), this, &CoreSession::changePassword);
111 p->attachSignal(this, &CoreSession::passwordChanged);
113 p->attachSlot(SIGNAL(kickClient(int)), this, &CoreSession::kickClient);
114 p->attachSignal(this, &CoreSession::disconnectFromCore);
117 data["quasselVersion"] = Quassel::buildInfo().fancyVersionString;
118 data["quasselBuildDate"] = Quassel::buildInfo().commitDate; // "BuildDate" for compatibility
119 data["startTime"] = Core::startTime();
120 data["sessionConnectedClients"] = 0;
121 _coreInfo->setCoreData(data);
126 eventManager()->registerObject(ircParser(), EventManager::NormalPriority);
127 eventManager()->registerObject(sessionEventProcessor(), EventManager::HighPriority); // needs to process events *before* the stringifier!
128 eventManager()->registerObject(ctcpParser(), EventManager::NormalPriority);
129 eventManager()->registerObject(eventStringifier(), EventManager::NormalPriority);
130 eventManager()->registerObject(this, EventManager::LowPriority); // for sending MessageEvents to the client
131 // some events need to be handled after msg generation
132 eventManager()->registerObject(sessionEventProcessor(), EventManager::LowPriority, "lateProcess");
133 eventManager()->registerObject(ctcpParser(), EventManager::LowPriority, "send");
135 // periodically save our session state
136 connect(Core::syncTimer(), &QTimer::timeout, this, &CoreSession::saveSessionState);
138 p->synchronize(_bufferSyncer);
139 p->synchronize(&aliasManager());
140 p->synchronize(_backlogManager);
141 p->synchronize(dccConfig());
142 p->synchronize(ircListHelper());
143 p->synchronize(networkConfig());
144 p->synchronize(_coreInfo);
145 p->synchronize(&_ignoreListManager);
146 p->synchronize(&_highlightRuleManager);
147 // Listen to network removed events
148 connect(this, &CoreSession::networkRemoved, &_highlightRuleManager, &HighlightRuleManager::networkRemoved);
149 p->synchronize(transferManager());
150 // Restore session state
152 restoreSessionState();
156 if (_metricsServer) {
157 _metricsServer->addSession(user(), Core::instance()->strictSysIdent(_user));
161 void CoreSession::shutdown()
165 // Request disconnect from all connected networks in parallel, and wait until every network
166 // has emitted the disconnected() signal before deleting the session itself
167 for (CoreNetwork* net : _networks.values()) {
168 if (net->socketState() != QAbstractSocket::UnconnectedState) {
169 _networksPendingDisconnect.insert(net->networkId());
170 connect(net, &CoreNetwork::disconnected, this, &CoreSession::onNetworkDisconnected);
175 if (_networksPendingDisconnect.isEmpty()) {
176 // Nothing to do, suicide so the core can shut down
180 if (_metricsServer) {
181 _metricsServer->removeSession(user());
185 void CoreSession::onNetworkDisconnected(NetworkId networkId)
187 _networksPendingDisconnect.remove(networkId);
188 if (_networksPendingDisconnect.isEmpty()) {
189 // We're done, suicide so the core can shut down
194 CoreNetwork* CoreSession::network(NetworkId id) const
196 if (_networks.contains(id))
197 return _networks[id];
201 CoreIdentity* CoreSession::identity(IdentityId id) const
203 if (_identities.contains(id))
204 return _identities[id];
208 void CoreSession::loadSettings()
210 CoreUserSettings s(user());
213 QList<IdentityId> ids = s.identityIds();
214 QList<NetworkInfo> networkInfos = Core::networks(user());
215 for (IdentityId id : ids) {
216 CoreIdentity identity(s.identity(id));
217 IdentityId newId = Core::createIdentity(user(), identity);
218 QList<NetworkInfo>::iterator networkIter = networkInfos.begin();
219 while (networkIter != networkInfos.end()) {
220 if (networkIter->identity == id) {
221 networkIter->identity = newId;
222 Core::updateNetwork(user(), *networkIter);
223 networkIter = networkInfos.erase(networkIter);
229 s.removeIdentity(id);
233 for (const CoreIdentity& identity : Core::identities(user())) {
234 createIdentity(identity);
237 for (const NetworkInfo& info : Core::networks(user())) {
242 void CoreSession::saveSessionState() const
244 _bufferSyncer->storeDirtyIds();
245 _bufferViewManager->saveBufferViews();
246 _networkConfig->save();
249 void CoreSession::restoreSessionState()
251 QList<NetworkId> nets = Core::connectedNetworks(user());
252 CoreNetwork* net = nullptr;
253 for (NetworkId id : nets) {
260 void CoreSession::addClient(RemotePeer* peer)
262 signalProxy()->setTargetPeer(peer);
264 peer->dispatch(sessionState());
265 signalProxy()->addPeer(peer);
266 _coreInfo->setConnectedClientData(signalProxy()->peerCount(), signalProxy()->peerData());
268 signalProxy()->setTargetPeer(nullptr);
270 if (_metricsServer) {
271 _metricsServer->addClient(user());
275 void CoreSession::addClient(InternalPeer* peer)
277 signalProxy()->addPeer(peer);
278 emit sessionStateReceived(sessionState());
281 void CoreSession::removeClient(Peer* peer)
283 auto* p = qobject_cast<RemotePeer*>(peer);
285 qInfo() << qPrintable(tr("Client")) << p->description() << qPrintable(tr("disconnected (UserId: %1).").arg(user().toInt()));
286 _coreInfo->setConnectedClientData(signalProxy()->peerCount(), signalProxy()->peerData());
288 if (_metricsServer) {
289 _metricsServer->removeClient(user());
293 QHash<QString, QString> CoreSession::persistentChannels(NetworkId id) const
295 return Core::persistentChannels(user(), id);
298 QHash<QString, QByteArray> CoreSession::bufferCiphers(NetworkId id) const
300 return Core::bufferCiphers(user(), id);
303 void CoreSession::setBufferCipher(NetworkId id, const QString& bufferName, const QByteArray& cipher) const
305 Core::setBufferCipher(user(), id, bufferName, cipher);
308 // FIXME switch to BufferId
309 void CoreSession::msgFromClient(BufferInfo bufinfo, QString msg)
311 CoreNetwork* net = network(bufinfo.networkId());
313 net->userInput(bufinfo, msg);
316 qWarning() << "Trying to send to unconnected network:" << msg;
320 // ALL messages coming pass through these functions before going to the GUI.
321 // So this is the perfect place for storing the backlog and log stuff.
322 void CoreSession::recvMessageFromServer(RawMessage msg)
324 // U+FDD0 and U+FDD1 are special characters for Qt's text engine, specifically they mark the boundaries of
325 // text frames in a QTextDocument. This might lead to problems in widgets displaying QTextDocuments (such as
326 // KDE's notifications), hence we remove those just to be safe.
327 msg.text.remove(QChar(0xfdd0)).remove(QChar(0xfdd1));
329 // check for HardStrictness ignore
330 CoreNetwork* currentNetwork = network(msg.networkId);
331 QString networkName = currentNetwork ? currentNetwork->networkName() : QString("");
332 if (_ignoreListManager.match(msg, networkName) == IgnoreListManager::HardStrictness)
335 if (currentNetwork && _highlightRuleManager.match(msg, currentNetwork->myNick(), currentNetwork->identityPtr()->nicks()))
336 msg.flags |= Message::Flag::Highlight;
338 _messageQueue << std::move(msg);
339 if (!_processMessages) {
340 _processMessages = true;
341 QCoreApplication::postEvent(this, new ProcessMessagesEvent());
345 void CoreSession::recvStatusMsgFromServer(QString msg)
347 auto* net = qobject_cast<CoreNetwork*>(sender());
349 emit displayStatusMsg(net->networkName(), std::move(msg));
352 void CoreSession::processMessageEvent(MessageEvent* event)
354 recvMessageFromServer(RawMessage{
359 event->target().isNull() ? "" : event->target(),
360 event->text().isNull() ? "" : event->text(),
361 event->sender().isNull() ? "" : event->sender(),
366 QList<BufferInfo> CoreSession::buffers() const
368 return Core::requestBuffers(user());
371 void CoreSession::customEvent(QEvent* event)
373 if (event->type() != QEvent::User)
380 void CoreSession::processMessages()
382 if (_messageQueue.count() == 1) {
383 const RawMessage& rawMsg = _messageQueue.first();
384 bool createBuffer = !(rawMsg.flags & Message::Redirected);
385 BufferInfo bufferInfo = Core::bufferInfo(user(), rawMsg.networkId, rawMsg.bufferType, rawMsg.target, createBuffer);
386 if (!bufferInfo.isValid()) {
387 Q_ASSERT(!createBuffer);
388 bufferInfo = Core::bufferInfo(user(), rawMsg.networkId, BufferInfo::StatusBuffer, "");
390 Message msg(rawMsg.timestamp,
395 senderPrefixes(rawMsg.sender, bufferInfo),
396 realName(rawMsg.sender, rawMsg.networkId),
397 avatarUrl(rawMsg.sender, rawMsg.networkId),
399 if (Core::storeMessage(msg))
400 emit displayMsg(msg);
403 QHash<NetworkId, QHash<QString, BufferInfo>> bufferInfoCache;
404 MessageList messages;
405 QList<RawMessage> redirectedMessages; // list of Messages which don't enforce a buffer creation
406 BufferInfo bufferInfo;
407 for (int i = 0; i < _messageQueue.count(); i++) {
408 const RawMessage& rawMsg = _messageQueue.at(i);
409 if (bufferInfoCache.contains(rawMsg.networkId) && bufferInfoCache[rawMsg.networkId].contains(rawMsg.target)) {
410 bufferInfo = bufferInfoCache[rawMsg.networkId][rawMsg.target];
413 bool createBuffer = !(rawMsg.flags & Message::Redirected);
414 bufferInfo = Core::bufferInfo(user(), rawMsg.networkId, rawMsg.bufferType, rawMsg.target, createBuffer);
415 if (!bufferInfo.isValid()) {
416 Q_ASSERT(!createBuffer);
417 redirectedMessages << rawMsg;
420 bufferInfoCache[rawMsg.networkId][rawMsg.target] = bufferInfo;
422 Message msg(rawMsg.timestamp,
427 senderPrefixes(rawMsg.sender, bufferInfo),
428 realName(rawMsg.sender, rawMsg.networkId),
429 avatarUrl(rawMsg.sender, rawMsg.networkId),
434 // recheck if there exists a buffer to store a redirected message in
435 for (int i = 0; i < redirectedMessages.count(); i++) {
436 const RawMessage& rawMsg = redirectedMessages.at(i);
437 if (bufferInfoCache.contains(rawMsg.networkId) && bufferInfoCache[rawMsg.networkId].contains(rawMsg.target)) {
438 bufferInfo = bufferInfoCache[rawMsg.networkId][rawMsg.target];
441 // no luck -> we store them in the StatusBuffer
442 bufferInfo = Core::bufferInfo(user(), rawMsg.networkId, BufferInfo::StatusBuffer, "");
443 // add the StatusBuffer to the Cache in case there are more Messages for the original target
444 bufferInfoCache[rawMsg.networkId][rawMsg.target] = bufferInfo;
446 Message msg(rawMsg.timestamp,
451 senderPrefixes(rawMsg.sender, bufferInfo),
452 realName(rawMsg.sender, rawMsg.networkId),
453 avatarUrl(rawMsg.sender, rawMsg.networkId),
458 if (Core::storeMessages(messages)) {
459 // FIXME: extend protocol to a displayMessages(MessageList)
460 for (int i = 0; i < messages.count(); i++) {
461 emit displayMsg(messages[i]);
465 _processMessages = false;
466 _messageQueue.clear();
469 QString CoreSession::senderPrefixes(const QString& sender, const BufferInfo& bufferInfo) const
471 CoreNetwork* currentNetwork = network(bufferInfo.networkId());
472 if (!currentNetwork) {
476 if (bufferInfo.type() != BufferInfo::ChannelBuffer) {
480 IrcChannel* currentChannel = currentNetwork->ircChannel(bufferInfo.bufferName());
481 if (!currentChannel) {
485 const QString modes = currentChannel->userModes(nickFromMask(sender).toLower());
486 return currentNetwork->modesToPrefixes(modes);
489 QString CoreSession::realName(const QString& sender, NetworkId networkId) const
491 CoreNetwork* currentNetwork = network(networkId);
492 if (!currentNetwork) {
496 IrcUser* currentUser = currentNetwork->ircUser(nickFromMask(sender));
501 return currentUser->realName();
504 QString CoreSession::avatarUrl(const QString& sender, NetworkId networkId) const
508 // Currently we do not have a way to retrieve this value yet.
510 // This likely will require implementing IRCv3's METADATA spec.
511 // See https://ircv3.net/irc/
512 // And https://blog.irccloud.com/avatars/
516 Protocol::SessionState CoreSession::sessionState() const
518 QVariantList bufferInfos;
519 QVariantList networkIds;
520 QVariantList identities;
522 for (const BufferInfo& id : buffers()) {
523 bufferInfos << QVariant::fromValue(id);
525 for (const NetworkId& id : _networks.keys()) {
526 networkIds << QVariant::fromValue(id);
528 for (const Identity* i : _identities.values()) {
529 identities << QVariant::fromValue(*i);
532 return Protocol::SessionState(identities, bufferInfos, networkIds);
535 void CoreSession::initScriptEngine()
537 signalProxy()->attachSlot(SIGNAL(scriptRequest(QString)), this, &CoreSession::scriptRequest);
538 signalProxy()->attachSignal(this, &CoreSession::scriptResult);
541 // QScriptValue storage_ = scriptEngine->newQObject(storage);
542 // scriptEngine->globalObject().setProperty("storage", storage_);
545 void CoreSession::scriptRequest(QString script)
547 emit scriptResult(scriptEngine->evaluate(script).toString());
550 /*** Identity Handling ***/
551 void CoreSession::createIdentity(const Identity& identity, const QVariantMap& additional)
557 CoreIdentity coreIdentity(identity);
559 if (additional.contains("KeyPem"))
560 coreIdentity.setSslKey(additional["KeyPem"].toByteArray());
561 if (additional.contains("CertPem"))
562 coreIdentity.setSslCert(additional["CertPem"].toByteArray());
564 qDebug() << Q_FUNC_INFO;
565 IdentityId id = Core::createIdentity(user(), coreIdentity);
569 createIdentity(coreIdentity);
572 const QString CoreSession::strictCompliantIdent(const CoreIdentity* identity)
574 if (_strictIdentEnabled) {
575 // Strict mode enabled: only allow the user's Quassel username as an ident
576 return Core::instance()->strictSysIdent(_user);
579 // Strict mode disabled: allow any identity specified
580 return identity->ident();
584 void CoreSession::createIdentity(const CoreIdentity& identity)
586 auto* coreIdentity = new CoreIdentity(identity, this);
587 _identities[identity.id()] = coreIdentity;
588 // CoreIdentity has its own synchronize method since its "private" sslManager needs to be synced as well
589 coreIdentity->synchronize(signalProxy());
590 connect(coreIdentity, &SyncableObject::updated, this, &CoreSession::updateIdentityBySender);
591 emit identityCreated(*coreIdentity);
594 void CoreSession::updateIdentityBySender()
596 auto* identity = qobject_cast<CoreIdentity*>(sender());
599 Core::updateIdentity(user(), *identity);
602 void CoreSession::removeIdentity(IdentityId id)
604 CoreIdentity* identity = _identities.take(id);
606 emit identityRemoved(id);
607 Core::removeIdentity(user(), id);
608 identity->deleteLater();
612 /*** Network Handling ***/
614 void CoreSession::createNetwork(const NetworkInfo& info_, const QStringList& persistentChans)
616 NetworkInfo info = info_;
619 if (!info.networkId.isValid())
620 Core::createNetwork(user(), info);
622 if (!info.networkId.isValid()) {
623 qWarning() << qPrintable(
624 tr("CoreSession::createNetwork(): Got invalid networkId from Core when trying to create network %1!").arg(info.networkName));
628 id = info.networkId.toInt();
629 if (!_networks.contains(id)) {
630 // create persistent chans
631 QRegExp rx(R"(\s*(\S+)(?:\s*(\S+))?\s*)");
632 for (const QString& channel : persistentChans) {
633 if (!rx.exactMatch(channel)) {
634 qWarning() << QString("Invalid persistent channel declaration: %1").arg(channel);
637 Core::bufferInfo(user(), info.networkId, BufferInfo::ChannelBuffer, rx.cap(1), true);
638 Core::setChannelPersistent(user(), info.networkId, rx.cap(1), true);
639 if (!rx.cap(2).isEmpty())
640 Core::setPersistentChannelKey(user(), info.networkId, rx.cap(1), rx.cap(2));
643 CoreNetwork* net = new CoreNetwork(id, this);
644 connect(net, &CoreNetwork::displayMsg, this, &CoreSession::recvMessageFromServer);
645 connect(net, &CoreNetwork::displayStatusMsg, this, &CoreSession::recvStatusMsgFromServer);
646 connect(net, &CoreNetwork::disconnected, this, &CoreSession::networkDisconnected);
648 net->setNetworkInfo(info);
649 net->setProxy(signalProxy());
651 signalProxy()->synchronize(net);
652 emit networkCreated(id);
655 qWarning() << qPrintable(tr("CoreSession::createNetwork(): Trying to create a network that already exists, updating instead!"));
656 _networks[info.networkId]->requestSetNetworkInfo(info);
660 void CoreSession::removeNetwork(NetworkId id)
662 // Make sure the network is disconnected!
663 CoreNetwork* net = network(id);
667 if (net->connectionState() != Network::Disconnected) {
668 // make sure we no longer receive data from the tcp buffer
669 disconnect(net, &CoreNetwork::displayMsg, this, nullptr);
670 disconnect(net, &CoreNetwork::displayStatusMsg, this, nullptr);
671 connect(net, &CoreNetwork::disconnected, this, &CoreSession::destroyNetwork);
672 net->disconnectFromIrc();
679 void CoreSession::destroyNetwork(NetworkId id)
681 QList<BufferId> removedBuffers = Core::requestBufferIdsForNetwork(user(), id);
682 Network* net = _networks.take(id);
683 if (net && Core::removeNetwork(user(), id)) {
684 // make sure that all unprocessed RawMessages from this network are removed
685 QList<RawMessage>::iterator messageIter = _messageQueue.begin();
686 while (messageIter != _messageQueue.end()) {
687 if (messageIter->networkId == id) {
688 messageIter = _messageQueue.erase(messageIter);
694 // remove buffers from syncer
695 for (BufferId bufferId : removedBuffers) {
696 _bufferSyncer->removeBuffer(bufferId);
698 emit networkRemoved(id);
703 void CoreSession::renameBuffer(const NetworkId& networkId, const QString& newName, const QString& oldName)
705 BufferInfo bufferInfo = Core::bufferInfo(user(), networkId, BufferInfo::QueryBuffer, oldName, false);
706 if (bufferInfo.isValid()) {
707 _bufferSyncer->renameBuffer(bufferInfo.bufferId(), newName);
711 void CoreSession::clientsConnected()
713 QHash<NetworkId, CoreNetwork*>::iterator netIter = _networks.begin();
714 Identity* identity = nullptr;
715 CoreNetwork* net = nullptr;
716 IrcUser* me = nullptr;
717 while (netIter != _networks.end()) {
721 if (!net->isConnected())
723 identity = net->identityPtr();
730 if (identity->detachAwayEnabled() && me->isAway()) {
731 net->userInputHandler()->handleAway(BufferInfo(), QString());
736 void CoreSession::clientsDisconnected()
738 QHash<NetworkId, CoreNetwork*>::iterator netIter = _networks.begin();
739 Identity* identity = nullptr;
740 CoreNetwork* net = nullptr;
741 IrcUser* me = nullptr;
743 while (netIter != _networks.end()) {
747 if (!net->isConnected())
750 identity = net->identityPtr();
757 if (identity->detachAwayEnabled() && !me->isAway()) {
758 if (!identity->detachAwayReason().isEmpty())
759 awayReason = identity->detachAwayReason();
760 net->setAutoAwayActive(true);
761 // Allow handleAway() to format the current date/time in the string.
762 net->userInputHandler()->handleAway(BufferInfo(), awayReason);
767 void CoreSession::globalAway(const QString& msg, const bool skipFormatting)
769 QHash<NetworkId, CoreNetwork*>::iterator netIter = _networks.begin();
770 CoreNetwork* net = nullptr;
771 while (netIter != _networks.end()) {
775 if (!net->isConnected())
778 net->userInputHandler()->issueAway(msg, false /* no force away */, skipFormatting);
782 void CoreSession::changePassword(PeerPtr peer, const QString& userName, const QString& oldPassword, const QString& newPassword)
786 bool success = false;
787 UserId uid = Core::validateUser(userName, oldPassword);
788 if (uid.isValid() && uid == user())
789 success = Core::changeUserPassword(uid, newPassword);
791 signalProxy()->restrictTargetPeers(signalProxy()->sourcePeer(), [&] { emit passwordChanged(nullptr, success); });
794 void CoreSession::kickClient(int peerId)
796 auto peer = signalProxy()->peerById(peerId);
797 if (peer == nullptr) {
798 qWarning() << "Invalid peer Id: " << peerId;
801 signalProxy()->restrictTargetPeers(peer, [&] { emit disconnectFromCore(); });