Reformat ALL the source!
[quassel.git] / src / common / network.cpp
1 /***************************************************************************
2  *   Copyright (C) 2005-2012 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  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
19  ***************************************************************************/
20 #include <QSettings>
21 #include <QTextCodec>
22
23 #include "network.h"
24 #include "quassel.h"
25
26 QTextCodec *Network::_defaultCodecForServer = 0;
27 QTextCodec *Network::_defaultCodecForEncoding = 0;
28 QTextCodec *Network::_defaultCodecForDecoding = 0;
29 QString Network::_networksIniPath = QString();
30
31 // ====================
32 //  Public:
33 // ====================
34 INIT_SYNCABLE_OBJECT(Network)
35 Network::Network(const NetworkId &networkid, QObject *parent)
36     : SyncableObject(parent),
37     _proxy(0),
38     _networkId(networkid),
39     _identity(0),
40     _myNick(QString()),
41     _latency(0),
42     _networkName(QString("<not initialized>")),
43     _currentServer(QString()),
44     _connected(false),
45     _connectionState(Disconnected),
46     _prefixes(QString()),
47     _prefixModes(QString()),
48     _useRandomServer(false),
49     _useAutoIdentify(false),
50     _useSasl(false),
51     _useAutoReconnect(false),
52     _autoReconnectInterval(60),
53     _autoReconnectRetries(10),
54     _unlimitedReconnectRetries(false),
55     _codecForServer(0),
56     _codecForEncoding(0),
57     _codecForDecoding(0),
58     _autoAwayActive(false)
59 {
60     setObjectName(QString::number(networkid.toInt()));
61 }
62
63
64 Network::~Network()
65 {
66     emit aboutToBeDestroyed();
67 }
68
69
70 bool Network::isChannelName(const QString &channelname) const
71 {
72     if (channelname.isEmpty())
73         return false;
74
75     if (supports("CHANTYPES"))
76         return support("CHANTYPES").contains(channelname[0]);
77     else
78         return QString("#&!+").contains(channelname[0]);
79 }
80
81
82 NetworkInfo Network::networkInfo() const
83 {
84     NetworkInfo info;
85     info.networkName = networkName();
86     info.networkId = networkId();
87     info.identity = identity();
88     info.codecForServer = codecForServer();
89     info.codecForEncoding = codecForEncoding();
90     info.codecForDecoding = codecForDecoding();
91     info.serverList = serverList();
92     info.useRandomServer = useRandomServer();
93     info.perform = perform();
94     info.useAutoIdentify = useAutoIdentify();
95     info.autoIdentifyService = autoIdentifyService();
96     info.autoIdentifyPassword = autoIdentifyPassword();
97     info.useSasl = useSasl();
98     info.saslAccount = saslAccount();
99     info.saslPassword = saslPassword();
100     info.useAutoReconnect = useAutoReconnect();
101     info.autoReconnectInterval = autoReconnectInterval();
102     info.autoReconnectRetries = autoReconnectRetries();
103     info.unlimitedReconnectRetries = unlimitedReconnectRetries();
104     info.rejoinChannels = rejoinChannels();
105     return info;
106 }
107
108
109 void Network::setNetworkInfo(const NetworkInfo &info)
110 {
111     // we don't set our ID!
112     if (!info.networkName.isEmpty() && info.networkName != networkName()) setNetworkName(info.networkName);
113     if (info.identity > 0 && info.identity != identity()) setIdentity(info.identity);
114     if (info.codecForServer != codecForServer()) setCodecForServer(QTextCodec::codecForName(info.codecForServer));
115     if (info.codecForEncoding != codecForEncoding()) setCodecForEncoding(QTextCodec::codecForName(info.codecForEncoding));
116     if (info.codecForDecoding != codecForDecoding()) setCodecForDecoding(QTextCodec::codecForName(info.codecForDecoding));
117     if (info.serverList.count()) setServerList(toVariantList(info.serverList));  // FIXME compare components
118     if (info.useRandomServer != useRandomServer()) setUseRandomServer(info.useRandomServer);
119     if (info.perform != perform()) setPerform(info.perform);
120     if (info.useAutoIdentify != useAutoIdentify()) setUseAutoIdentify(info.useAutoIdentify);
121     if (info.autoIdentifyService != autoIdentifyService()) setAutoIdentifyService(info.autoIdentifyService);
122     if (info.autoIdentifyPassword != autoIdentifyPassword()) setAutoIdentifyPassword(info.autoIdentifyPassword);
123     if (info.useSasl != useSasl()) setUseSasl(info.useSasl);
124     if (info.saslAccount != saslAccount()) setSaslAccount(info.saslAccount);
125     if (info.saslPassword != saslPassword()) setSaslPassword(info.saslPassword);
126     if (info.useAutoReconnect != useAutoReconnect()) setUseAutoReconnect(info.useAutoReconnect);
127     if (info.autoReconnectInterval != autoReconnectInterval()) setAutoReconnectInterval(info.autoReconnectInterval);
128     if (info.autoReconnectRetries != autoReconnectRetries()) setAutoReconnectRetries(info.autoReconnectRetries);
129     if (info.unlimitedReconnectRetries != unlimitedReconnectRetries()) setUnlimitedReconnectRetries(info.unlimitedReconnectRetries);
130     if (info.rejoinChannels != rejoinChannels()) setRejoinChannels(info.rejoinChannels);
131 }
132
133
134 QString Network::prefixToMode(const QString &prefix) const
135 {
136     if (prefixes().contains(prefix))
137         return QString(prefixModes()[prefixes().indexOf(prefix)]);
138     else
139         return QString();
140 }
141
142
143 QString Network::modeToPrefix(const QString &mode) const
144 {
145     if (prefixModes().contains(mode))
146         return QString(prefixes()[prefixModes().indexOf(mode)]);
147     else
148         return QString();
149 }
150
151
152 QStringList Network::nicks() const
153 {
154     // we don't use _ircUsers.keys() since the keys may be
155     // not up to date after a nick change
156     QStringList nicks;
157     foreach(IrcUser *ircuser, _ircUsers.values()) {
158         nicks << ircuser->nick();
159     }
160     return nicks;
161 }
162
163
164 QString Network::prefixes() const
165 {
166     if (_prefixes.isNull())
167         determinePrefixes();
168
169     return _prefixes;
170 }
171
172
173 QString Network::prefixModes() const
174 {
175     if (_prefixModes.isNull())
176         determinePrefixes();
177
178     return _prefixModes;
179 }
180
181
182 // example Unreal IRCD: CHANMODES=beI,kfL,lj,psmntirRcOAQKVCuzNSMTG
183 Network::ChannelModeType Network::channelModeType(const QString &mode)
184 {
185     if (mode.isEmpty())
186         return NOT_A_CHANMODE;
187
188     QString chanmodes = support("CHANMODES");
189     if (chanmodes.isEmpty())
190         return NOT_A_CHANMODE;
191
192     ChannelModeType modeType = A_CHANMODE;
193     for (int i = 0; i < chanmodes.count(); i++) {
194         if (chanmodes[i] == mode[0])
195             break;
196         else if (chanmodes[i] == ',')
197             modeType = (ChannelModeType)(modeType << 1);
198     }
199     if (modeType > D_CHANMODE) {
200         qWarning() << "Network" << networkId() << "supplied invalid CHANMODES:" << chanmodes;
201         modeType = NOT_A_CHANMODE;
202     }
203     return modeType;
204 }
205
206
207 QString Network::support(const QString &param) const
208 {
209     QString support_ = param.toUpper();
210     if (_supports.contains(support_))
211         return _supports[support_];
212     else
213         return QString();
214 }
215
216
217 IrcUser *Network::newIrcUser(const QString &hostmask, const QVariantMap &initData)
218 {
219     QString nick(nickFromMask(hostmask).toLower());
220     if (!_ircUsers.contains(nick)) {
221         IrcUser *ircuser = ircUserFactory(hostmask);
222         if (!initData.isEmpty()) {
223             ircuser->fromVariantMap(initData);
224             ircuser->setInitialized();
225         }
226
227         if (proxy())
228             proxy()->synchronize(ircuser);
229         else
230             qWarning() << "unable to synchronize new IrcUser" << hostmask << "forgot to call Network::setProxy(SignalProxy *)?";
231
232         connect(ircuser, SIGNAL(nickSet(QString)), this, SLOT(ircUserNickChanged(QString)));
233
234         _ircUsers[nick] = ircuser;
235
236         SYNC_OTHER(addIrcUser, ARG(hostmask))
237         // emit ircUserAdded(hostmask);
238         emit ircUserAdded(ircuser);
239     }
240
241     return _ircUsers[nick];
242 }
243
244
245 IrcUser *Network::ircUser(QString nickname) const
246 {
247     nickname = nickname.toLower();
248     if (_ircUsers.contains(nickname))
249         return _ircUsers[nickname];
250     else
251         return 0;
252 }
253
254
255 void Network::removeIrcUser(IrcUser *ircuser)
256 {
257     QString nick = _ircUsers.key(ircuser);
258     if (nick.isNull())
259         return;
260
261     _ircUsers.remove(nick);
262     disconnect(ircuser, 0, this, 0);
263     ircuser->deleteLater();
264 }
265
266
267 void Network::removeIrcChannel(IrcChannel *channel)
268 {
269     QString chanName = _ircChannels.key(channel);
270     if (chanName.isNull())
271         return;
272
273     _ircChannels.remove(chanName);
274     disconnect(channel, 0, this, 0);
275     channel->deleteLater();
276 }
277
278
279 void Network::removeChansAndUsers()
280 {
281     QList<IrcUser *> users = ircUsers();
282     _ircUsers.clear();
283     QList<IrcChannel *> channels = ircChannels();
284     _ircChannels.clear();
285
286     foreach(IrcChannel *channel, channels) {
287         proxy()->detachObject(channel);
288         disconnect(channel, 0, this, 0);
289     }
290     foreach(IrcUser *user, users) {
291         proxy()->detachObject(user);
292         disconnect(user, 0, this, 0);
293     }
294
295     // the second loop is needed because quit can have sideffects
296     foreach(IrcUser *user, users) {
297         user->quit();
298     }
299
300     qDeleteAll(users);
301     qDeleteAll(channels);
302 }
303
304
305 IrcChannel *Network::newIrcChannel(const QString &channelname, const QVariantMap &initData)
306 {
307     if (!_ircChannels.contains(channelname.toLower())) {
308         IrcChannel *channel = ircChannelFactory(channelname);
309         if (!initData.isEmpty()) {
310             channel->fromVariantMap(initData);
311             channel->setInitialized();
312         }
313
314         if (proxy())
315             proxy()->synchronize(channel);
316         else
317             qWarning() << "unable to synchronize new IrcChannel" << channelname << "forgot to call Network::setProxy(SignalProxy *)?";
318
319         _ircChannels[channelname.toLower()] = channel;
320
321         SYNC_OTHER(addIrcChannel, ARG(channelname))
322         // emit ircChannelAdded(channelname);
323         emit ircChannelAdded(channel);
324     }
325     return _ircChannels[channelname.toLower()];
326 }
327
328
329 IrcChannel *Network::ircChannel(QString channelname) const
330 {
331     channelname = channelname.toLower();
332     if (_ircChannels.contains(channelname))
333         return _ircChannels[channelname];
334     else
335         return 0;
336 }
337
338
339 QByteArray Network::defaultCodecForServer()
340 {
341     if (_defaultCodecForServer)
342         return _defaultCodecForServer->name();
343     return QByteArray();
344 }
345
346
347 void Network::setDefaultCodecForServer(const QByteArray &name)
348 {
349     _defaultCodecForServer = QTextCodec::codecForName(name);
350 }
351
352
353 QByteArray Network::defaultCodecForEncoding()
354 {
355     if (_defaultCodecForEncoding)
356         return _defaultCodecForEncoding->name();
357     return QByteArray();
358 }
359
360
361 void Network::setDefaultCodecForEncoding(const QByteArray &name)
362 {
363     _defaultCodecForEncoding = QTextCodec::codecForName(name);
364 }
365
366
367 QByteArray Network::defaultCodecForDecoding()
368 {
369     if (_defaultCodecForDecoding)
370         return _defaultCodecForDecoding->name();
371     return QByteArray();
372 }
373
374
375 void Network::setDefaultCodecForDecoding(const QByteArray &name)
376 {
377     _defaultCodecForDecoding = QTextCodec::codecForName(name);
378 }
379
380
381 QByteArray Network::codecForServer() const
382 {
383     if (_codecForServer)
384         return _codecForServer->name();
385     return QByteArray();
386 }
387
388
389 void Network::setCodecForServer(const QByteArray &name)
390 {
391     setCodecForServer(QTextCodec::codecForName(name));
392 }
393
394
395 void Network::setCodecForServer(QTextCodec *codec)
396 {
397     _codecForServer = codec;
398     QByteArray codecName = codecForServer();
399     SYNC_OTHER(setCodecForServer, ARG(codecName))
400     emit configChanged();
401 }
402
403
404 QByteArray Network::codecForEncoding() const
405 {
406     if (_codecForEncoding)
407         return _codecForEncoding->name();
408     return QByteArray();
409 }
410
411
412 void Network::setCodecForEncoding(const QByteArray &name)
413 {
414     setCodecForEncoding(QTextCodec::codecForName(name));
415 }
416
417
418 void Network::setCodecForEncoding(QTextCodec *codec)
419 {
420     _codecForEncoding = codec;
421     QByteArray codecName = codecForEncoding();
422     SYNC_OTHER(setCodecForEncoding, ARG(codecName))
423     emit configChanged();
424 }
425
426
427 QByteArray Network::codecForDecoding() const
428 {
429     if (_codecForDecoding)
430         return _codecForDecoding->name();
431     else return QByteArray();
432 }
433
434
435 void Network::setCodecForDecoding(const QByteArray &name)
436 {
437     setCodecForDecoding(QTextCodec::codecForName(name));
438 }
439
440
441 void Network::setCodecForDecoding(QTextCodec *codec)
442 {
443     _codecForDecoding = codec;
444     QByteArray codecName = codecForDecoding();
445     SYNC_OTHER(setCodecForDecoding, ARG(codecName))
446     emit configChanged();
447 }
448
449
450 // FIXME use server encoding if appropriate
451 QString Network::decodeString(const QByteArray &text) const
452 {
453     if (_codecForDecoding)
454         return ::decodeString(text, _codecForDecoding);
455     else return ::decodeString(text, _defaultCodecForDecoding);
456 }
457
458
459 QByteArray Network::encodeString(const QString &string) const
460 {
461     if (_codecForEncoding) {
462         return _codecForEncoding->fromUnicode(string);
463     }
464     if (_defaultCodecForEncoding) {
465         return _defaultCodecForEncoding->fromUnicode(string);
466     }
467     return string.toAscii();
468 }
469
470
471 QString Network::decodeServerString(const QByteArray &text) const
472 {
473     if (_codecForServer)
474         return ::decodeString(text, _codecForServer);
475     else
476         return ::decodeString(text, _defaultCodecForServer);
477 }
478
479
480 QByteArray Network::encodeServerString(const QString &string) const
481 {
482     if (_codecForServer) {
483         return _codecForServer->fromUnicode(string);
484     }
485     if (_defaultCodecForServer) {
486         return _defaultCodecForServer->fromUnicode(string);
487     }
488     return string.toAscii();
489 }
490
491
492 /*** Handle networks.ini ***/
493
494 QStringList Network::presetNetworks(bool onlyDefault)
495 {
496     // lazily find the file, make sure to not call one of the other preset functions first (they'll fail else)
497     if (_networksIniPath.isNull()) {
498         _networksIniPath = Quassel::findDataFilePath("networks.ini");
499         if (_networksIniPath.isNull()) {
500             _networksIniPath = ""; // now we won't check again, as it's not null anymore
501             return QStringList();
502         }
503     }
504     if (!_networksIniPath.isEmpty()) {
505         QSettings s(_networksIniPath, QSettings::IniFormat);
506         QStringList networks = s.childGroups();
507         if (!networks.isEmpty()) {
508             // we sort the list case-insensitive
509             QMap<QString, QString> sorted;
510             foreach(QString net, networks) {
511                 if (onlyDefault && !s.value(QString("%1/Default").arg(net)).toBool())
512                     continue;
513                 sorted[net.toLower()] = net;
514             }
515             return sorted.values();
516         }
517     }
518     return QStringList();
519 }
520
521
522 QStringList Network::presetDefaultChannels(const QString &networkName)
523 {
524     if (_networksIniPath.isEmpty()) // be sure to have called presetNetworks() first, else this always fails
525         return QStringList();
526     QSettings s(_networksIniPath, QSettings::IniFormat);
527     return s.value(QString("%1/DefaultChannels").arg(networkName)).toStringList();
528 }
529
530
531 NetworkInfo Network::networkInfoFromPreset(const QString &networkName)
532 {
533     NetworkInfo info;
534     if (!_networksIniPath.isEmpty()) {
535         info.networkName = networkName;
536         QSettings s(_networksIniPath, QSettings::IniFormat);
537         s.beginGroup(info.networkName);
538         foreach(QString server, s.value("Servers").toStringList()) {
539             bool ssl = false;
540             QStringList splitserver = server.split(':', QString::SkipEmptyParts);
541             if (splitserver.count() != 2) {
542                 qWarning() << "Invalid server entry in networks.conf:" << server;
543                 continue;
544             }
545             if (splitserver[1].at(0) == '+')
546                 ssl = true;
547             uint port = splitserver[1].toUInt();
548             if (!port) {
549                 qWarning() << "Invalid port entry in networks.conf:" << server;
550                 continue;
551             }
552             info.serverList << Network::Server(splitserver[0].trimmed(), port, QString(), ssl);
553         }
554     }
555     return info;
556 }
557
558
559 // ====================
560 //  Public Slots:
561 // ====================
562 void Network::setNetworkName(const QString &networkName)
563 {
564     _networkName = networkName;
565     SYNC(ARG(networkName))
566     emit networkNameSet(networkName);
567     emit configChanged();
568 }
569
570
571 void Network::setCurrentServer(const QString &currentServer)
572 {
573     _currentServer = currentServer;
574     SYNC(ARG(currentServer))
575     emit currentServerSet(currentServer);
576 }
577
578
579 void Network::setConnected(bool connected)
580 {
581     if (_connected == connected)
582         return;
583
584     _connected = connected;
585     if (!connected) {
586         setMyNick(QString());
587         setCurrentServer(QString());
588         removeChansAndUsers();
589     }
590     SYNC(ARG(connected))
591     emit connectedSet(connected);
592 }
593
594
595 //void Network::setConnectionState(ConnectionState state) {
596 void Network::setConnectionState(int state)
597 {
598     _connectionState = (ConnectionState)state;
599     //qDebug() << "netstate" << networkId() << networkName() << state;
600     SYNC(ARG(state))
601     emit connectionStateSet(_connectionState);
602 }
603
604
605 void Network::setMyNick(const QString &nickname)
606 {
607     _myNick = nickname;
608     if (!_myNick.isEmpty() && !ircUser(myNick())) {
609         newIrcUser(myNick());
610     }
611     SYNC(ARG(nickname))
612     emit myNickSet(nickname);
613 }
614
615
616 void Network::setLatency(int latency)
617 {
618     if (_latency == latency)
619         return;
620     _latency = latency;
621     SYNC(ARG(latency))
622 }
623
624
625 void Network::setIdentity(IdentityId id)
626 {
627     _identity = id;
628     SYNC(ARG(id))
629     emit identitySet(id);
630     emit configChanged();
631 }
632
633
634 void Network::setServerList(const QVariantList &serverList)
635 {
636     _serverList = fromVariantList<Server>(serverList);
637     SYNC(ARG(serverList))
638     emit configChanged();
639 }
640
641
642 void Network::setUseRandomServer(bool use)
643 {
644     _useRandomServer = use;
645     SYNC(ARG(use))
646     emit configChanged();
647 }
648
649
650 void Network::setPerform(const QStringList &perform)
651 {
652     _perform = perform;
653     SYNC(ARG(perform))
654     emit configChanged();
655 }
656
657
658 void Network::setUseAutoIdentify(bool use)
659 {
660     _useAutoIdentify = use;
661     SYNC(ARG(use))
662     emit configChanged();
663 }
664
665
666 void Network::setAutoIdentifyService(const QString &service)
667 {
668     _autoIdentifyService = service;
669     SYNC(ARG(service))
670     emit configChanged();
671 }
672
673
674 void Network::setAutoIdentifyPassword(const QString &password)
675 {
676     _autoIdentifyPassword = password;
677     SYNC(ARG(password))
678     emit configChanged();
679 }
680
681
682 void Network::setUseSasl(bool use)
683 {
684     _useSasl = use;
685     SYNC(ARG(use))
686     emit configChanged();
687 }
688
689
690 void Network::setSaslAccount(const QString &account)
691 {
692     _saslAccount = account;
693     SYNC(ARG(account))
694     emit configChanged();
695 }
696
697
698 void Network::setSaslPassword(const QString &password)
699 {
700     _saslPassword = password;
701     SYNC(ARG(password))
702     emit configChanged();
703 }
704
705
706 void Network::setUseAutoReconnect(bool use)
707 {
708     _useAutoReconnect = use;
709     SYNC(ARG(use))
710     emit configChanged();
711 }
712
713
714 void Network::setAutoReconnectInterval(quint32 interval)
715 {
716     _autoReconnectInterval = interval;
717     SYNC(ARG(interval))
718     emit configChanged();
719 }
720
721
722 void Network::setAutoReconnectRetries(quint16 retries)
723 {
724     _autoReconnectRetries = retries;
725     SYNC(ARG(retries))
726     emit configChanged();
727 }
728
729
730 void Network::setUnlimitedReconnectRetries(bool unlimited)
731 {
732     _unlimitedReconnectRetries = unlimited;
733     SYNC(ARG(unlimited))
734     emit configChanged();
735 }
736
737
738 void Network::setRejoinChannels(bool rejoin)
739 {
740     _rejoinChannels = rejoin;
741     SYNC(ARG(rejoin))
742     emit configChanged();
743 }
744
745
746 void Network::addSupport(const QString &param, const QString &value)
747 {
748     if (!_supports.contains(param)) {
749         _supports[param] = value;
750         SYNC(ARG(param), ARG(value))
751     }
752 }
753
754
755 void Network::removeSupport(const QString &param)
756 {
757     if (_supports.contains(param)) {
758         _supports.remove(param);
759         SYNC(ARG(param))
760     }
761 }
762
763
764 QVariantMap Network::initSupports() const
765 {
766     QVariantMap supports;
767     QHashIterator<QString, QString> iter(_supports);
768     while (iter.hasNext()) {
769         iter.next();
770         supports[iter.key()] = iter.value();
771     }
772     return supports;
773 }
774
775
776 QVariantMap Network::initIrcUsersAndChannels() const
777 {
778     QVariantMap usersAndChannels;
779     QVariantMap users;
780     QVariantMap channels;
781
782     QHash<QString, IrcUser *>::const_iterator userIter = _ircUsers.constBegin();
783     QHash<QString, IrcUser *>::const_iterator userIterEnd = _ircUsers.constEnd();
784     while (userIter != userIterEnd) {
785         users[userIter.value()->hostmask()] = userIter.value()->toVariantMap();
786         userIter++;
787     }
788     usersAndChannels["users"] = users;
789
790     QHash<QString, IrcChannel *>::const_iterator channelIter = _ircChannels.constBegin();
791     QHash<QString, IrcChannel *>::const_iterator channelIterEnd = _ircChannels.constEnd();
792     while (channelIter != channelIterEnd) {
793         channels[channelIter.value()->name()] = channelIter.value()->toVariantMap();
794         channelIter++;
795     }
796     usersAndChannels["channels"] = channels;
797
798     return usersAndChannels;
799 }
800
801
802 void Network::initSetIrcUsersAndChannels(const QVariantMap &usersAndChannels)
803 {
804     Q_ASSERT(proxy());
805     if (isInitialized()) {
806         qWarning() << "Network" << networkId() << "received init data for users and channels allthough there allready are known users or channels!";
807         return;
808     }
809
810     QVariantMap users = usersAndChannels.value("users").toMap();
811     QVariantMap::const_iterator userIter = users.constBegin();
812     QVariantMap::const_iterator userIterEnd = users.constEnd();
813     while (userIter != userIterEnd) {
814         newIrcUser(userIter.key(), userIter.value().toMap());
815         userIter++;
816     }
817
818     QVariantMap channels = usersAndChannels.value("channels").toMap();
819     QVariantMap::const_iterator channelIter = channels.constBegin();
820     QVariantMap::const_iterator channelIterEnd = channels.constEnd();
821     while (channelIter != channelIterEnd) {
822         newIrcChannel(channelIter.key(), channelIter.value().toMap());
823         channelIter++;
824     }
825 }
826
827
828 void Network::initSetSupports(const QVariantMap &supports)
829 {
830     QMapIterator<QString, QVariant> iter(supports);
831     while (iter.hasNext()) {
832         iter.next();
833         addSupport(iter.key(), iter.value().toString());
834     }
835 }
836
837
838 IrcUser *Network::updateNickFromMask(const QString &mask)
839 {
840     QString nick(nickFromMask(mask).toLower());
841     IrcUser *ircuser;
842
843     if (_ircUsers.contains(nick)) {
844         ircuser = _ircUsers[nick];
845         ircuser->updateHostmask(mask);
846     }
847     else {
848         ircuser = newIrcUser(mask);
849     }
850     return ircuser;
851 }
852
853
854 void Network::ircUserNickChanged(QString newnick)
855 {
856     QString oldnick = _ircUsers.key(qobject_cast<IrcUser *>(sender()));
857
858     if (oldnick.isNull())
859         return;
860
861     if (newnick.toLower() != oldnick) _ircUsers[newnick.toLower()] = _ircUsers.take(oldnick);
862
863     if (myNick().toLower() == oldnick)
864         setMyNick(newnick);
865 }
866
867
868 void Network::emitConnectionError(const QString &errorMsg)
869 {
870     emit connectionError(errorMsg);
871 }
872
873
874 // ====================
875 //  Private:
876 // ====================
877 void Network::determinePrefixes() const
878 {
879     // seems like we have to construct them first
880     QString prefix = support("PREFIX");
881
882     if (prefix.startsWith("(") && prefix.contains(")")) {
883         _prefixes = prefix.section(")", 1);
884         _prefixModes = prefix.mid(1).section(")", 0, 0);
885     }
886     else {
887         QString defaultPrefixes("~&@%+");
888         QString defaultPrefixModes("qaohv");
889
890         if (prefix.isEmpty()) {
891             _prefixes = defaultPrefixes;
892             _prefixModes = defaultPrefixModes;
893             return;
894         }
895         // clear the existing modes, just in case we're run multiple times
896         _prefixes = QString();
897         _prefixModes = QString();
898
899         // we just assume that in PREFIX are only prefix chars stored
900         for (int i = 0; i < defaultPrefixes.size(); i++) {
901             if (prefix.contains(defaultPrefixes[i])) {
902                 _prefixes += defaultPrefixes[i];
903                 _prefixModes += defaultPrefixModes[i];
904             }
905         }
906         // check for success
907         if (!_prefixes.isNull())
908             return;
909
910         // well... our assumption was obviously wrong...
911         // check if it's only prefix modes
912         for (int i = 0; i < defaultPrefixes.size(); i++) {
913             if (prefix.contains(defaultPrefixModes[i])) {
914                 _prefixes += defaultPrefixes[i];
915                 _prefixModes += defaultPrefixModes[i];
916             }
917         }
918         // now we've done all we've could...
919     }
920 }
921
922
923 /************************************************************************
924  * NetworkInfo
925  ************************************************************************/
926
927 NetworkInfo::NetworkInfo()
928     : networkId(0),
929     identity(1),
930     useRandomServer(false),
931     useAutoIdentify(false),
932     autoIdentifyService("NickServ"),
933     useSasl(false),
934     useAutoReconnect(true),
935     autoReconnectInterval(60),
936     autoReconnectRetries(20),
937     unlimitedReconnectRetries(false),
938     rejoinChannels(true)
939 {
940 }
941
942
943 bool NetworkInfo::operator==(const NetworkInfo &other) const
944 {
945     if (networkId != other.networkId) return false;
946     if (networkName != other.networkName) return false;
947     if (identity != other.identity) return false;
948     if (codecForServer != other.codecForServer) return false;
949     if (codecForEncoding != other.codecForEncoding) return false;
950     if (codecForDecoding != other.codecForDecoding) return false;
951     if (serverList != other.serverList) return false;
952     if (useRandomServer != other.useRandomServer) return false;
953     if (perform != other.perform) return false;
954     if (useAutoIdentify != other.useAutoIdentify) return false;
955     if (autoIdentifyService != other.autoIdentifyService) return false;
956     if (autoIdentifyPassword != other.autoIdentifyPassword) return false;
957     if (useSasl != other.useSasl) return false;
958     if (saslAccount != other.saslAccount) return false;
959     if (saslPassword != other.saslPassword) return false;
960     if (useAutoReconnect != other.useAutoReconnect) return false;
961     if (autoReconnectInterval != other.autoReconnectInterval) return false;
962     if (autoReconnectRetries != other.autoReconnectRetries) return false;
963     if (unlimitedReconnectRetries != other.unlimitedReconnectRetries) return false;
964     if (rejoinChannels != other.rejoinChannels) return false;
965     return true;
966 }
967
968
969 bool NetworkInfo::operator!=(const NetworkInfo &other) const
970 {
971     return !(*this == other);
972 }
973
974
975 QDataStream &operator<<(QDataStream &out, const NetworkInfo &info)
976 {
977     QVariantMap i;
978     i["NetworkId"] = QVariant::fromValue<NetworkId>(info.networkId);
979     i["NetworkName"] = info.networkName;
980     i["Identity"] = QVariant::fromValue<IdentityId>(info.identity);
981     i["CodecForServer"] = info.codecForServer;
982     i["CodecForEncoding"] = info.codecForEncoding;
983     i["CodecForDecoding"] = info.codecForDecoding;
984     i["ServerList"] = toVariantList(info.serverList);
985     i["UseRandomServer"] = info.useRandomServer;
986     i["Perform"] = info.perform;
987     i["UseAutoIdentify"] = info.useAutoIdentify;
988     i["AutoIdentifyService"] = info.autoIdentifyService;
989     i["AutoIdentifyPassword"] = info.autoIdentifyPassword;
990     i["UseSasl"] = info.useSasl;
991     i["SaslAccount"] = info.saslAccount;
992     i["SaslPassword"] = info.saslPassword;
993     i["UseAutoReconnect"] = info.useAutoReconnect;
994     i["AutoReconnectInterval"] = info.autoReconnectInterval;
995     i["AutoReconnectRetries"] = info.autoReconnectRetries;
996     i["UnlimitedReconnectRetries"] = info.unlimitedReconnectRetries;
997     i["RejoinChannels"] = info.rejoinChannels;
998     out << i;
999     return out;
1000 }
1001
1002
1003 QDataStream &operator>>(QDataStream &in, NetworkInfo &info)
1004 {
1005     QVariantMap i;
1006     in >> i;
1007     info.networkId = i["NetworkId"].value<NetworkId>();
1008     info.networkName = i["NetworkName"].toString();
1009     info.identity = i["Identity"].value<IdentityId>();
1010     info.codecForServer = i["CodecForServer"].toByteArray();
1011     info.codecForEncoding = i["CodecForEncoding"].toByteArray();
1012     info.codecForDecoding = i["CodecForDecoding"].toByteArray();
1013     info.serverList = fromVariantList<Network::Server>(i["ServerList"].toList());
1014     info.useRandomServer = i["UseRandomServer"].toBool();
1015     info.perform = i["Perform"].toStringList();
1016     info.useAutoIdentify = i["UseAutoIdentify"].toBool();
1017     info.autoIdentifyService = i["AutoIdentifyService"].toString();
1018     info.autoIdentifyPassword = i["AutoIdentifyPassword"].toString();
1019     info.useSasl = i["UseSasl"].toBool();
1020     info.saslAccount = i["SaslAccount"].toString();
1021     info.saslPassword = i["SaslPassword"].toString();
1022     info.useAutoReconnect = i["UseAutoReconnect"].toBool();
1023     info.autoReconnectInterval = i["AutoReconnectInterval"].toUInt();
1024     info.autoReconnectRetries = i["AutoReconnectRetries"].toInt();
1025     info.unlimitedReconnectRetries = i["UnlimitedReconnectRetries"].toBool();
1026     info.rejoinChannels = i["RejoinChannels"].toBool();
1027     return in;
1028 }
1029
1030
1031 QDebug operator<<(QDebug dbg, const NetworkInfo &i)
1032 {
1033     dbg.nospace() << "(id = " << i.networkId << " name = " << i.networkName << " identity = " << i.identity
1034     << " codecForServer = " << i.codecForServer << " codecForEncoding = " << i.codecForEncoding << " codecForDecoding = " << i.codecForDecoding
1035     << " serverList = " << i.serverList << " useRandomServer = " << i.useRandomServer << " perform = " << i.perform
1036     << " useAutoIdentify = " << i.useAutoIdentify << " autoIdentifyService = " << i.autoIdentifyService << " autoIdentifyPassword = " << i.autoIdentifyPassword
1037     << " useSasl = " << i.useSasl << " saslAccount = " << i.saslAccount << " saslPassword = " << i.saslPassword
1038     << " useAutoReconnect = " << i.useAutoReconnect << " autoReconnectInterval = " << i.autoReconnectInterval
1039     << " autoReconnectRetries = " << i.autoReconnectRetries << " unlimitedReconnectRetries = " << i.unlimitedReconnectRetries
1040     << " rejoinChannels = " << i.rejoinChannels << ")";
1041     return dbg.space();
1042 }
1043
1044
1045 QDataStream &operator<<(QDataStream &out, const Network::Server &server)
1046 {
1047     QVariantMap serverMap;
1048     serverMap["Host"] = server.host;
1049     serverMap["Port"] = server.port;
1050     serverMap["Password"] = server.password;
1051     serverMap["UseSSL"] = server.useSsl;
1052     serverMap["sslVersion"] = server.sslVersion;
1053     serverMap["UseProxy"] = server.useProxy;
1054     serverMap["ProxyType"] = server.proxyType;
1055     serverMap["ProxyHost"] = server.proxyHost;
1056     serverMap["ProxyPort"] = server.proxyPort;
1057     serverMap["ProxyUser"] = server.proxyUser;
1058     serverMap["ProxyPass"] = server.proxyPass;
1059     out << serverMap;
1060     return out;
1061 }
1062
1063
1064 QDataStream &operator>>(QDataStream &in, Network::Server &server)
1065 {
1066     QVariantMap serverMap;
1067     in >> serverMap;
1068     server.host = serverMap["Host"].toString();
1069     server.port = serverMap["Port"].toUInt();
1070     server.password = serverMap["Password"].toString();
1071     server.useSsl = serverMap["UseSSL"].toBool();
1072     server.sslVersion = serverMap["sslVersion"].toInt();
1073     server.useProxy = serverMap["UseProxy"].toBool();
1074     server.proxyType = serverMap["ProxyType"].toInt();
1075     server.proxyHost = serverMap["ProxyHost"].toString();
1076     server.proxyPort = serverMap["ProxyPort"].toUInt();
1077     server.proxyUser = serverMap["ProxyUser"].toString();
1078     server.proxyPass = serverMap["ProxyPass"].toString();
1079     return in;
1080 }
1081
1082
1083 bool Network::Server::operator==(const Server &other) const
1084 {
1085     if (host != other.host) return false;
1086     if (port != other.port) return false;
1087     if (password != other.password) return false;
1088     if (useSsl != other.useSsl) return false;
1089     if (sslVersion != other.sslVersion) return false;
1090     if (useProxy != other.useProxy) return false;
1091     if (proxyType != other.proxyType) return false;
1092     if (proxyHost != other.proxyHost) return false;
1093     if (proxyPort != other.proxyPort) return false;
1094     if (proxyUser != other.proxyUser) return false;
1095     if (proxyPass != other.proxyPass) return false;
1096     return true;
1097 }
1098
1099
1100 bool Network::Server::operator!=(const Server &other) const
1101 {
1102     return !(*this == other);
1103 }
1104
1105
1106 QDebug operator<<(QDebug dbg, const Network::Server &server)
1107 {
1108     dbg.nospace() << "Server(host = " << server.host << ":" << server.port << ", useSsl = " << server.useSsl << ")";
1109     return dbg.space();
1110 }