1 | /*************************************************************************** |
2 | * Copyright (C) 2005-2014 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 "coresession.h" |
22 | |
23 | #include <QtScript> |
24 | |
25 | #include "core.h" |
26 | #include "coreuserinputhandler.h" |
27 | #include "corebuffersyncer.h" |
28 | #include "corebacklogmanager.h" |
29 | #include "corebufferviewmanager.h" |
30 | #include "coreeventmanager.h" |
31 | #include "coreidentity.h" |
32 | #include "coreignorelistmanager.h" |
33 | #include "coreirclisthelper.h" |
34 | #include "corenetwork.h" |
35 | #include "corenetworkconfig.h" |
36 | #include "coresessioneventprocessor.h" |
37 | #include "coretransfermanager.h" |
38 | #include "coreusersettings.h" |
39 | #include "ctcpparser.h" |
40 | #include "eventstringifier.h" |
41 | #include "internalpeer.h" |
42 | #include "ircchannel.h" |
43 | #include "ircparser.h" |
44 | #include "ircuser.h" |
45 | #include "logger.h" |
46 | #include "messageevent.h" |
47 | #include "remotepeer.h" |
48 | #include "storage.h" |
49 | #include "util.h" |
50 | |
51 | |
52 | class ProcessMessagesEvent : public QEvent |
53 | { |
54 | public: |
55 | ProcessMessagesEvent() : QEvent(QEvent::User) {} |
56 | }; |
57 | |
58 | |
59 | CoreSession::CoreSession(UserId uid, bool restoreState, QObject *parent) |
60 | : QObject(parent), |
61 | _user(uid), |
62 | _signalProxy(new SignalProxy(SignalProxy::Server, this)), |
63 | _aliasManager(this), |
64 | _bufferSyncer(new CoreBufferSyncer(this)), |
65 | _backlogManager(new CoreBacklogManager(this)), |
66 | _bufferViewManager(new CoreBufferViewManager(_signalProxy, this)), |
67 | _ircListHelper(new CoreIrcListHelper(this)), |
68 | _networkConfig(new CoreNetworkConfig("GlobalNetworkConfig" , this)), |
69 | _coreInfo(this), |
70 | _transferManager(new CoreTransferManager(this)), |
71 | _eventManager(new CoreEventManager(this)), |
72 | _eventStringifier(new EventStringifier(this)), |
73 | _sessionEventProcessor(new CoreSessionEventProcessor(this)), |
74 | _ctcpParser(new CtcpParser(this)), |
75 | _ircParser(new IrcParser(this)), |
76 | scriptEngine(new QScriptEngine(this)), |
77 | _processMessages(false), |
78 | _ignoreListManager(this) |
79 | { |
80 | SignalProxy *p = signalProxy(); |
81 | p->setHeartBeatInterval(30); |
82 | p->setMaxHeartBeatCount(60); // 30 mins until we throw a dead socket out |
83 | |
84 | connect(p, SIGNAL(peerRemoved(Peer*)), SLOT(removeClient(Peer*))); |
85 | |
86 | connect(p, SIGNAL(connected()), SLOT(clientsConnected())); |
87 | connect(p, SIGNAL(disconnected()), SLOT(clientsDisconnected())); |
88 | |
89 | p->attachSlot(SIGNAL(sendInput(BufferInfo, QString)), this, SLOT(msgFromClient(BufferInfo, QString))); |
90 | p->attachSignal(this, SIGNAL(displayMsg(Message))); |
91 | p->attachSignal(this, SIGNAL(displayStatusMsg(QString, QString))); |
92 | |
93 | p->attachSignal(this, SIGNAL(identityCreated(const Identity &))); |
94 | p->attachSignal(this, SIGNAL(identityRemoved(IdentityId))); |
95 | p->attachSlot(SIGNAL(createIdentity(const Identity &, const QVariantMap &)), this, SLOT(createIdentity(const Identity &, const QVariantMap &))); |
96 | p->attachSlot(SIGNAL(removeIdentity(IdentityId)), this, SLOT(removeIdentity(IdentityId))); |
97 | |
98 | p->attachSignal(this, SIGNAL(networkCreated(NetworkId))); |
99 | p->attachSignal(this, SIGNAL(networkRemoved(NetworkId))); |
100 | p->attachSlot(SIGNAL(createNetwork(const NetworkInfo &, const QStringList &)), this, SLOT(createNetwork(const NetworkInfo &, const QStringList &))); |
101 | p->attachSlot(SIGNAL(removeNetwork(NetworkId)), this, SLOT(removeNetwork(NetworkId))); |
102 | |
103 | loadSettings(); |
104 | initScriptEngine(); |
105 | |
106 | eventManager()->registerObject(ircParser(), EventManager::NormalPriority); |
107 | eventManager()->registerObject(sessionEventProcessor(), EventManager::HighPriority); // needs to process events *before* the stringifier! |
108 | eventManager()->registerObject(ctcpParser(), EventManager::NormalPriority); |
109 | eventManager()->registerObject(eventStringifier(), EventManager::NormalPriority); |
110 | eventManager()->registerObject(this, EventManager::LowPriority); // for sending MessageEvents to the client |
111 | // some events need to be handled after msg generation |
112 | eventManager()->registerObject(sessionEventProcessor(), EventManager::LowPriority, "lateProcess" ); |
113 | eventManager()->registerObject(ctcpParser(), EventManager::LowPriority, "send" ); |
114 | |
115 | // periodically save our session state |
116 | connect(&(Core::instance()->syncTimer()), SIGNAL(timeout()), this, SLOT(saveSessionState())); |
117 | |
118 | p->synchronize(_bufferSyncer); |
119 | p->synchronize(&aliasManager()); |
120 | p->synchronize(_backlogManager); |
121 | p->synchronize(ircListHelper()); |
122 | p->synchronize(networkConfig()); |
123 | p->synchronize(&_coreInfo); |
124 | p->synchronize(&_ignoreListManager); |
125 | p->synchronize(transferManager()); |
126 | // Restore session state |
127 | if (restoreState) |
128 | restoreSessionState(); |
129 | |
130 | emit initialized(); |
131 | } |
132 | |
133 | |
134 | CoreSession::~CoreSession() |
135 | { |
136 | saveSessionState(); |
137 | foreach(CoreNetwork *net, _networks.values()) { |
138 | delete net; |
139 | } |
140 | } |
141 | |
142 | |
143 | CoreNetwork *CoreSession::network(NetworkId id) const |
144 | { |
145 | if (_networks.contains(id)) return _networks[id]; |
146 | return 0; |
147 | } |
148 | |
149 | |
150 | CoreIdentity *CoreSession::identity(IdentityId id) const |
151 | { |
152 | if (_identities.contains(id)) return _identities[id]; |
153 | return 0; |
154 | } |
155 | |
156 | |
157 | void CoreSession::loadSettings() |
158 | { |
159 | CoreUserSettings s(user()); |
160 | |
161 | // migrate to db |
162 | QList<IdentityId> ids = s.identityIds(); |
163 | QList<NetworkInfo> networkInfos = Core::networks(user()); |
164 | foreach(IdentityId id, ids) { |
165 | CoreIdentity identity(s.identity(id)); |
166 | IdentityId newId = Core::createIdentity(user(), identity); |
167 | QList<NetworkInfo>::iterator networkIter = networkInfos.begin(); |
168 | while (networkIter != networkInfos.end()) { |
169 | if (networkIter->identity == id) { |
170 | networkIter->identity = newId; |
171 | Core::updateNetwork(user(), *networkIter); |
172 | networkIter = networkInfos.erase(networkIter); |
173 | } |
174 | else { |
175 | networkIter++; |
176 | } |
177 | } |
178 | s.removeIdentity(id); |
179 | } |
180 | // end of migration |
181 | |
182 | foreach(CoreIdentity identity, Core::identities(user())) { |
183 | createIdentity(identity); |
184 | } |
185 | |
186 | foreach(NetworkInfo info, Core::networks(user())) { |
187 | createNetwork(info); |
188 | } |
189 | } |
190 | |
191 | |
192 | void CoreSession::saveSessionState() const |
193 | { |
194 | _bufferSyncer->storeDirtyIds(); |
195 | _bufferViewManager->saveBufferViews(); |
196 | _networkConfig->save(); |
197 | } |
198 | |
199 | |
200 | void CoreSession::restoreSessionState() |
201 | { |
202 | QList<NetworkId> nets = Core::connectedNetworks(user()); |
203 | CoreNetwork *net = 0; |
204 | foreach(NetworkId id, nets) { |
205 | net = network(id); |
206 | Q_ASSERT(net); |
207 | net->connectToIrc(); |
208 | } |
209 | } |
210 | |
211 | |
212 | void CoreSession::addClient(RemotePeer *peer) |
213 | { |
214 | peer->dispatch(sessionState()); |
215 | signalProxy()->addPeer(peer); |
216 | } |
217 | |
218 | |
219 | void CoreSession::addClient(InternalPeer *peer) |
220 | { |
221 | signalProxy()->addPeer(peer); |
222 | emit sessionState(sessionState()); |
223 | } |
224 | |
225 | |
226 | void CoreSession::removeClient(Peer *peer) |
227 | { |
228 | RemotePeer *p = qobject_cast<RemotePeer *>(peer); |
229 | if (p) |
230 | quInfo() << qPrintable(tr("Client" )) << p->description() << qPrintable(tr("disconnected (UserId: %1)." ).arg(user().toInt())); |
231 | } |
232 | |
233 | |
234 | QHash<QString, QString> CoreSession::persistentChannels(NetworkId id) const |
235 | { |
236 | return Core::persistentChannels(user(), id); |
237 | } |
238 | |
239 | |
240 | // FIXME switch to BufferId |
241 | void CoreSession::msgFromClient(BufferInfo bufinfo, QString msg) |
242 | { |
243 | CoreNetwork *net = network(bufinfo.networkId()); |
244 | if (net) { |
245 | net->userInput(bufinfo, msg); |
246 | } |
247 | else { |
248 | qWarning() << "Trying to send to unconnected network:" << msg; |
249 | } |
250 | } |
251 | |
252 | |
253 | // ALL messages coming pass through these functions before going to the GUI. |
254 | // So this is the perfect place for storing the backlog and log stuff. |
255 | void CoreSession::recvMessageFromServer(NetworkId networkId, Message::Type type, BufferInfo::Type bufferType, |
256 | const QString &target, const QString &text_, const QString &sender, Message::Flags flags) |
257 | { |
258 | // U+FDD0 and U+FDD1 are special characters for Qt's text engine, specifically they mark the boundaries of |
259 | // text frames in a QTextDocument. This might lead to problems in widgets displaying QTextDocuments (such as |
260 | // KDE's notifications), hence we remove those just to be safe. |
261 | QString text = text_; |
262 | text.remove(QChar(0xfdd0)).remove(QChar(0xfdd1)); |
263 | RawMessage rawMsg(networkId, type, bufferType, target, text, sender, flags); |
264 | |
265 | // check for HardStrictness ignore |
266 | CoreNetwork *currentNetwork = network(networkId); |
267 | QString networkName = currentNetwork ? currentNetwork->networkName() : QString("" ); |
268 | if (_ignoreListManager.match(rawMsg, networkName) == IgnoreListManager::HardStrictness) |
269 | return; |
270 | |
271 | _messageQueue << rawMsg; |
272 | if (!_processMessages) { |
273 | _processMessages = true; |
274 | QCoreApplication::postEvent(this, new ProcessMessagesEvent()); |
275 | } |
276 | } |
277 | |
278 | |
279 | void CoreSession::recvStatusMsgFromServer(QString msg) |
280 | { |
281 | CoreNetwork *net = qobject_cast<CoreNetwork *>(sender()); |
282 | Q_ASSERT(net); |
283 | emit displayStatusMsg(net->networkName(), msg); |
284 | } |
285 | |
286 | |
287 | void CoreSession::processMessageEvent(MessageEvent *event) |
288 | { |
289 | recvMessageFromServer(event->networkId(), event->msgType(), event->bufferType(), |
290 | event->target().isNull() ? "" : event->target(), |
291 | event->text().isNull() ? "" : event->text(), |
292 | event->sender().isNull() ? "" : event->sender(), |
293 | event->msgFlags()); |
294 | } |
295 | |
296 | |
297 | QList<BufferInfo> CoreSession::buffers() const |
298 | { |
299 | return Core::requestBuffers(user()); |
300 | } |
301 | |
302 | |
303 | void CoreSession::customEvent(QEvent *event) |
304 | { |
305 | if (event->type() != QEvent::User) |
306 | return; |
307 | |
308 | processMessages(); |
309 | event->accept(); |
310 | } |
311 | |
312 | |
313 | void CoreSession::processMessages() |
314 | { |
315 | if (_messageQueue.count() == 1) { |
316 | const RawMessage &rawMsg = _messageQueue.first(); |
317 | bool createBuffer = !(rawMsg.flags & Message::Redirected); |
318 | BufferInfo bufferInfo = Core::bufferInfo(user(), rawMsg.networkId, rawMsg.bufferType, rawMsg.target, createBuffer); |
319 | if (!bufferInfo.isValid()) { |
320 | Q_ASSERT(!createBuffer); |
321 | bufferInfo = Core::bufferInfo(user(), rawMsg.networkId, BufferInfo::StatusBuffer, "" ); |
322 | } |
323 | Message msg(bufferInfo, rawMsg.type, rawMsg.text, rawMsg.sender, rawMsg.flags); |
324 | Core::storeMessage(msg); |
325 | emit displayMsg(msg); |
326 | } |
327 | else { |
328 | QHash<NetworkId, QHash<QString, BufferInfo> > bufferInfoCache; |
329 | MessageList messages; |
330 | QList<RawMessage> redirectedMessages; // list of Messages which don't enforce a buffer creation |
331 | BufferInfo bufferInfo; |
332 | for (int i = 0; i < _messageQueue.count(); i++) { |
333 | const RawMessage &rawMsg = _messageQueue.at(i); |
334 | if (bufferInfoCache.contains(rawMsg.networkId) && bufferInfoCache[rawMsg.networkId].contains(rawMsg.target)) { |
335 | bufferInfo = bufferInfoCache[rawMsg.networkId][rawMsg.target]; |
336 | } |
337 | else { |
338 | bool createBuffer = !(rawMsg.flags & Message::Redirected); |
339 | bufferInfo = Core::bufferInfo(user(), rawMsg.networkId, rawMsg.bufferType, rawMsg.target, createBuffer); |
340 | if (!bufferInfo.isValid()) { |
341 | Q_ASSERT(!createBuffer); |
342 | redirectedMessages << rawMsg; |
343 | continue; |
344 | } |
345 | bufferInfoCache[rawMsg.networkId][rawMsg.target] = bufferInfo; |
346 | } |
347 | Message msg(bufferInfo, rawMsg.type, rawMsg.text, rawMsg.sender, rawMsg.flags); |
348 | messages << msg; |
349 | } |
350 | |
351 | // recheck if there exists a buffer to store a redirected message in |
352 | for (int i = 0; i < redirectedMessages.count(); i++) { |
353 | const RawMessage &rawMsg = redirectedMessages.at(i); |
354 | if (bufferInfoCache.contains(rawMsg.networkId) && bufferInfoCache[rawMsg.networkId].contains(rawMsg.target)) { |
355 | bufferInfo = bufferInfoCache[rawMsg.networkId][rawMsg.target]; |
356 | } |
357 | else { |
358 | // no luck -> we store them in the StatusBuffer |
359 | bufferInfo = Core::bufferInfo(user(), rawMsg.networkId, BufferInfo::StatusBuffer, "" ); |
360 | // add the StatusBuffer to the Cache in case there are more Messages for the original target |
361 | bufferInfoCache[rawMsg.networkId][rawMsg.target] = bufferInfo; |
362 | } |
363 | Message msg(bufferInfo, rawMsg.type, rawMsg.text, rawMsg.sender, rawMsg.flags); |
364 | messages << msg; |
365 | } |
366 | |
367 | Core::storeMessages(messages); |
368 | // FIXME: extend protocol to a displayMessages(MessageList) |
369 | for (int i = 0; i < messages.count(); i++) { |
370 | emit displayMsg(messages[i]); |
371 | } |
372 | } |
373 | _processMessages = false; |
374 | _messageQueue.clear(); |
375 | } |
376 | |
377 | |
378 | Protocol::SessionState CoreSession::sessionState() const |
379 | { |
380 | QVariantList bufferInfos; |
381 | QVariantList networkIds; |
382 | QVariantList identities; |
383 | |
384 | foreach(const BufferInfo &id, buffers()) |
385 | bufferInfos << QVariant::fromValue(id); |
386 | foreach(const NetworkId &id, _networks.keys()) |
387 | networkIds << QVariant::fromValue(id); |
388 | foreach(const Identity *i, _identities.values()) |
389 | identities << QVariant::fromValue(*i); |
390 | |
391 | return Protocol::SessionState(identities, bufferInfos, networkIds); |
392 | } |
393 | |
394 | |
395 | void CoreSession::initScriptEngine() |
396 | { |
397 | signalProxy()->attachSlot(SIGNAL(scriptRequest(QString)), this, SLOT(scriptRequest(QString))); |
398 | signalProxy()->attachSignal(this, SIGNAL(scriptResult(QString))); |
399 | |
400 | // FIXME |
401 | //QScriptValue storage_ = scriptEngine->newQObject(storage); |
402 | //scriptEngine->globalObject().setProperty("storage", storage_); |
403 | } |
404 | |
405 | |
406 | void CoreSession::scriptRequest(QString script) |
407 | { |
408 | emit scriptResult(scriptEngine->evaluate(script).toString()); |
409 | } |
410 | |
411 | |
412 | /*** Identity Handling ***/ |
413 | void CoreSession::createIdentity(const Identity &identity, const QVariantMap &additional) |
414 | { |
415 | #ifndef HAVE_SSL |
416 | Q_UNUSED(additional) |
417 | #endif |
418 | |
419 | CoreIdentity coreIdentity(identity); |
420 | #ifdef HAVE_SSL |
421 | if (additional.contains("KeyPem" )) |
422 | coreIdentity.setSslKey(additional["KeyPem" ].toByteArray()); |
423 | if (additional.contains("CertPem" )) |
424 | coreIdentity.setSslCert(additional["CertPem" ].toByteArray()); |
425 | #endif |
426 | qDebug() << Q_FUNC_INFO; |
427 | IdentityId id = Core::createIdentity(user(), coreIdentity); |
428 | if (!id.isValid()) |
429 | return; |
430 | else |
431 | createIdentity(coreIdentity); |
432 | } |
433 | |
434 | |
435 | void CoreSession::createIdentity(const CoreIdentity &identity) |
436 | { |
437 | CoreIdentity *coreIdentity = new CoreIdentity(identity, this); |
438 | _identities[identity.id()] = coreIdentity; |
439 | // CoreIdentity has its own synchronize method since its "private" sslManager needs to be synced as well |
440 | coreIdentity->synchronize(signalProxy()); |
441 | connect(coreIdentity, SIGNAL(updated()), this, SLOT(updateIdentityBySender())); |
442 | emit identityCreated(*coreIdentity); |
443 | } |
444 | |
445 | |
446 | void CoreSession::updateIdentityBySender() |
447 | { |
448 | CoreIdentity *identity = qobject_cast<CoreIdentity *>(sender()); |
449 | if (!identity) |
450 | return; |
451 | Core::updateIdentity(user(), *identity); |
452 | } |
453 | |
454 | |
455 | void CoreSession::removeIdentity(IdentityId id) |
456 | { |
457 | CoreIdentity *identity = _identities.take(id); |
458 | if (identity) { |
459 | emit identityRemoved(id); |
460 | Core::removeIdentity(user(), id); |
461 | identity->deleteLater(); |
462 | } |
463 | } |
464 | |
465 | |
466 | /*** Network Handling ***/ |
467 | |
468 | void CoreSession::createNetwork(const NetworkInfo &info_, const QStringList &persistentChans) |
469 | { |
470 | NetworkInfo info = info_; |
471 | int id; |
472 | |
473 | if (!info.networkId.isValid()) |
474 | Core::createNetwork(user(), info); |
475 | |
476 | if (!info.networkId.isValid()) { |
477 | qWarning() << qPrintable(tr("CoreSession::createNetwork(): Got invalid networkId from Core when trying to create network %1!" ).arg(info.networkName)); |
478 | return; |
479 | } |
480 | |
481 | id = info.networkId.toInt(); |
482 | if (!_networks.contains(id)) { |
483 | // create persistent chans |
484 | QRegExp rx("\\s*(\\S+)(?:\\s*(\\S+))?\\s*" ); |
485 | foreach(QString channel, persistentChans) { |
486 | if (!rx.exactMatch(channel)) { |
487 | qWarning() << QString("Invalid persistent channel declaration: %1" ).arg(channel); |
488 | continue; |
489 | } |
490 | Core::bufferInfo(user(), info.networkId, BufferInfo::ChannelBuffer, rx.cap(1), true); |
491 | Core::setChannelPersistent(user(), info.networkId, rx.cap(1), true); |
492 | if (!rx.cap(2).isEmpty()) |
493 | Core::setPersistentChannelKey(user(), info.networkId, rx.cap(1), rx.cap(2)); |
494 | } |
495 | |
496 | CoreNetwork *net = new CoreNetwork(id, this); |
497 | connect(net, SIGNAL(displayMsg(NetworkId, Message::Type, BufferInfo::Type, const QString &, const QString &, const QString &, Message::Flags)), |
498 | SLOT(recvMessageFromServer(NetworkId, Message::Type, BufferInfo::Type, const QString &, const QString &, const QString &, Message::Flags))); |
499 | connect(net, SIGNAL(displayStatusMsg(QString)), SLOT(recvStatusMsgFromServer(QString))); |
500 | connect(net, SIGNAL(disconnected(NetworkId)), SIGNAL(networkDisconnected(NetworkId))); |
501 | |
502 | net->setNetworkInfo(info); |
503 | net->setProxy(signalProxy()); |
504 | _networks[id] = net; |
505 | signalProxy()->synchronize(net); |
506 | emit networkCreated(id); |
507 | } |
508 | else { |
509 | qWarning() << qPrintable(tr("CoreSession::createNetwork(): Trying to create a network that already exists, updating instead!" )); |
510 | _networks[info.networkId]->requestSetNetworkInfo(info); |
511 | } |
512 | } |
513 | |
514 | |
515 | void CoreSession::removeNetwork(NetworkId id) |
516 | { |
517 | // Make sure the network is disconnected! |
518 | CoreNetwork *net = network(id); |
519 | if (!net) |
520 | return; |
521 | |
522 | if (net->connectionState() != Network::Disconnected) { |
523 | // make sure we no longer receive data from the tcp buffer |
524 | disconnect(net, SIGNAL(displayMsg(NetworkId, Message::Type, BufferInfo::Type, const QString &, const QString &, const QString &, Message::Flags)), this, 0); |
525 | disconnect(net, SIGNAL(displayStatusMsg(QString)), this, 0); |
526 | connect(net, SIGNAL(disconnected(NetworkId)), this, SLOT(destroyNetwork(NetworkId))); |
527 | net->disconnectFromIrc(); |
528 | } |
529 | else { |
530 | destroyNetwork(id); |
531 | } |
532 | } |
533 | |
534 | |
535 | void CoreSession::destroyNetwork(NetworkId id) |
536 | { |
537 | QList<BufferId> removedBuffers = Core::requestBufferIdsForNetwork(user(), id); |
538 | Network *net = _networks.take(id); |
539 | if (net && Core::removeNetwork(user(), id)) { |
540 | // make sure that all unprocessed RawMessages from this network are removed |
541 | QList<RawMessage>::iterator messageIter = _messageQueue.begin(); |
542 | while (messageIter != _messageQueue.end()) { |
543 | if (messageIter->networkId == id) { |
544 | messageIter = _messageQueue.erase(messageIter); |
545 | } |
546 | else { |
547 | messageIter++; |
548 | } |
549 | } |
550 | // remove buffers from syncer |
551 | foreach(BufferId bufferId, removedBuffers) { |
552 | _bufferSyncer->removeBuffer(bufferId); |
553 | } |
554 | emit networkRemoved(id); |
555 | net->deleteLater(); |
556 | } |
557 | } |
558 | |
559 | |
560 | void CoreSession::renameBuffer(const NetworkId &networkId, const QString &newName, const QString &oldName) |
561 | { |
562 | BufferInfo bufferInfo = Core::bufferInfo(user(), networkId, BufferInfo::QueryBuffer, oldName, false); |
563 | if (bufferInfo.isValid()) { |
564 | _bufferSyncer->renameBuffer(bufferInfo.bufferId(), newName); |
565 | } |
566 | } |
567 | |
568 | |
569 | void CoreSession::clientsConnected() |
570 | { |
571 | QHash<NetworkId, CoreNetwork *>::iterator netIter = _networks.begin(); |
572 | Identity *identity = 0; |
573 | CoreNetwork *net = 0; |
574 | IrcUser *me = 0; |
575 | while (netIter != _networks.end()) { |
576 | net = *netIter; |
577 | netIter++; |
578 | |
579 | if (!net->isConnected()) |
580 | continue; |
581 | identity = net->identityPtr(); |
582 | if (!identity) |
583 | continue; |
584 | me = net->me(); |
585 | if (!me) |
586 | continue; |
587 | |
588 | if (identity->detachAwayEnabled() && me->isAway()) { |
589 | net->userInputHandler()->handleAway(BufferInfo(), QString()); |
590 | } |
591 | } |
592 | } |
593 | |
594 | |
595 | void CoreSession::clientsDisconnected() |
596 | { |
597 | QHash<NetworkId, CoreNetwork *>::iterator netIter = _networks.begin(); |
598 | Identity *identity = 0; |
599 | CoreNetwork *net = 0; |
600 | IrcUser *me = 0; |
601 | QString awayReason; |
602 | while (netIter != _networks.end()) { |
603 | net = *netIter; |
604 | netIter++; |
605 | |
606 | if (!net->isConnected()) |
607 | continue; |
608 | |
609 | identity = net->identityPtr(); |
610 | if (!identity) |
611 | continue; |
612 | me = net->me(); |
613 | if (!me) |
614 | continue; |
615 | |
616 | if (identity->detachAwayEnabled() && !me->isAway()) { |
617 | if (!identity->detachAwayReason().isEmpty()) |
618 | awayReason = identity->detachAwayReason(); |
619 | net->setAutoAwayActive(true); |
620 | net->userInputHandler()->handleAway(BufferInfo(), awayReason); |
621 | } |
622 | } |
623 | } |
624 | |
625 | |
626 | void CoreSession::globalAway(const QString &msg) |
627 | { |
628 | QHash<NetworkId, CoreNetwork *>::iterator netIter = _networks.begin(); |
629 | CoreNetwork *net = 0; |
630 | while (netIter != _networks.end()) { |
631 | net = *netIter; |
632 | netIter++; |
633 | |
634 | if (!net->isConnected()) |
635 | continue; |
636 | |
637 | net->userInputHandler()->issueAway(msg, false /* no force away */); |
638 | } |
639 | } |
640 | |