_autoReconnectCount(0)
{
_autoReconnectTimer.setSingleShot(true);
-
+ _previousConnectionAttemptFailed = false;
+ _lastUsedServerlistIndex = 0;
// TODO make configurable
_whoTimer.setInterval(60 * 1000);
_whoTimer.setSingleShot(false);
+ QHash<QString, QString> channels = coreSession()->persistentChannels(networkId());
+ foreach(QString chan, channels.keys()) {
+ _channelKeys[chan.toLower()] = channels[chan];
+ }
+
connect(&_autoReconnectTimer, SIGNAL(timeout()), this, SLOT(doAutoReconnect()));
connect(&_whoTimer, SIGNAL(timeout()), this, SLOT(sendWho()));
connect(network, SIGNAL(autoReconnectIntervalSet(quint32)), this, SLOT(autoReconnectSettingsChanged()));
connect(network, SIGNAL(autoReconnectRetriesSet(quint16)), this, SLOT(autoReconnectSettingsChanged()));
+#ifndef QT_NO_OPENSSL
+ connect(&socket, SIGNAL(encrypted()), this, SLOT(socketEncrypted()));
+ connect(&socket, SIGNAL(sslErrors(const QList<QSslError> &)), this, SLOT(sslErrors(const QList<QSslError> &)));
+#endif
connect(&socket, SIGNAL(connected()), this, SLOT(socketConnected()));
+
connect(&socket, SIGNAL(disconnected()), this, SLOT(socketDisconnected()));
connect(&socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(socketError(QAbstractSocket::SocketError)));
connect(&socket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(socketStateChanged(QAbstractSocket::SocketState)));
connect(_ircServerHandler, SIGNAL(nickChanged(const QString &, const QString &)),
this, SLOT(nickChanged(const QString &, const QString &)));
+
+ network->proxy()->attachSignal(this, SIGNAL(sslErrors(const QVariant &)));
}
NetworkConnection::~NetworkConnection() {
if(connectionState() != Network::Disconnected && connectionState() != Network::Reconnecting)
- disconnectFromIrc();
+ disconnectFromIrc(false); // clean up, but this does not count as requested disconnect!
delete _ircServerHandler;
delete _userInputHandler;
delete _ctcpHandler;
qWarning() << "Invalid identity configures, ignoring connect request!";
return;
}
- // TODO implement cycling / random servers
- QString host = serverList[0].toMap()["Host"].toString();
- quint16 port = serverList[0].toMap()["Port"].toUInt();
+ // use a random server?
+ if(network()->useRandomServer()) {
+ _lastUsedServerlistIndex = qrand() % serverList.size();
+ } else if(_previousConnectionAttemptFailed) {
+ // cycle to next server if previous connection attempt failed
+ displayMsg(Message::Server, BufferInfo::StatusBuffer, "", tr("Connection failed. Cycling to next Server"));
+ if(++_lastUsedServerlistIndex == serverList.size()) {
+ _lastUsedServerlistIndex = 0;
+ }
+ }
+ _previousConnectionAttemptFailed = false;
+
+ QString host = serverList[_lastUsedServerlistIndex].toMap()["Host"].toString();
+ quint16 port = serverList[_lastUsedServerlistIndex].toMap()["Port"].toUInt();
displayStatusMsg(tr("Connecting to %1:%2...").arg(host).arg(port));
displayMsg(Message::Server, BufferInfo::StatusBuffer, "", tr("Connecting to %1:%2...").arg(host).arg(port));
socket.connectToHost(host, port);
// rejoin channels we've been in
QStringList channels, keys;
- foreach(QString chan, network()->persistentChannels().keys()) {
- QString key = network()->persistentChannels()[chan];
+ foreach(QString chan, persistentChannels()) {
+ QString key = channelKey(chan);
if(!key.isEmpty()) {
channels.prepend(chan); keys.prepend(key);
} else {
channels.append(chan);
}
}
- userInputHandler()->handleJoin(statusBuf, QString("%1 %2").arg(channels.join(",")).arg(keys.join(",")));
+ QString joinString = QString("%1 %2").arg(channels.join(",")).arg(keys.join(",")).trimmed();
+ if(!joinString.isEmpty()) userInputHandler()->handleJoin(statusBuf, joinString);
}
-void NetworkConnection::disconnectFromIrc() {
+void NetworkConnection::disconnectFromIrc(bool requested) {
_autoReconnectTimer.stop();
_autoReconnectCount = 0;
displayMsg(Message::Server, BufferInfo::StatusBuffer, "", tr("Disconnecting."));
setConnectionState(Network::Disconnected);
socketDisconnected();
} else socket.disconnectFromHost();
+
+ if(requested) {
+ emit quitRequested(networkId());
+ }
}
void NetworkConnection::socketHasData() {
while(socket.canReadLine()) {
- QByteArray s = socket.readLine().trimmed();
+ QByteArray s = socket.readLine();
ircServerHandler()->handleServerMsg(s);
}
}
void NetworkConnection::socketError(QAbstractSocket::SocketError) {
+ _previousConnectionAttemptFailed = true;
qDebug() << qPrintable(tr("Could not connect to %1 (%2)").arg(network()->networkName(), socket.errorString()));
emit connectionError(socket.errorString());
emit displayMsg(Message::Error, BufferInfo::StatusBuffer, "", tr("Connection failure: %1").arg(socket.errorString()));
setConnectionState(Network::Disconnected);
socketDisconnected();
}
+ // mark last connection attempt as failed
+
+ //qDebug() << "exiting...";
+ //exit(1);
+}
+
+#ifndef QT_NO_OPENSSL
+
+void NetworkConnection::sslErrors(const QList<QSslError> &errors) {
+ socket.ignoreSslErrors();
+ /* TODO errorhandling
+ QVariantMap errmsg;
+ QVariantList errnums;
+ foreach(QSslError err, errors) errnums << err.error();
+ errmsg["SslErrors"] = errnums;
+ errmsg["SslCert"] = socket.peerCertificate().toPem();
+ errmsg["PeerAddress"] = socket.peerAddress().toString();
+ errmsg["PeerPort"] = socket.peerPort();
+ errmsg["PeerName"] = socket.peerName();
+ emit sslErrors(errmsg);
+ disconnectFromIrc();
+ */
}
+void NetworkConnection::socketEncrypted() {
+ //qDebug() << "encrypted!";
+ socketInitialized();
+}
+
+#endif // QT_NO_OPENSSL
+
void NetworkConnection::socketConnected() {
+#ifdef QT_NO_OPENSSL
+ socketInitialized();
+ return;
+#else
+ if(!network()->serverList()[_lastUsedServerlistIndex].toMap()["UseSSL"].toBool()) {
+ socketInitialized();
+ return;
+ }
+ //qDebug() << "starting handshake";
+ socket.startClientEncryption();
+#endif
+}
+
+void NetworkConnection::socketInitialized() {
//emit connected(networkId()); initialize first!
Identity *identity = coreSession()->identity(network()->identity());
if(!identity) {
disconnectFromIrc();
return;
}
+ QString passwd = network()->serverList()[_lastUsedServerlistIndex].toMap()["Password"].toString();
+ if(!passwd.isEmpty()) {
+ putRawLine(serverEncode(QString("PASS %1").arg(passwd)));
+ }
putRawLine(serverEncode(QString("NICK :%1").arg(identity->nicks()[0]))); // FIXME: try more nicks if error occurs
putRawLine(serverEncode(QString("USER %1 8 * :%2").arg(identity->ident(), identity->realName())));
}
_whoTimer.stop();
network()->setConnected(false);
emit disconnected(networkId());
- if(_autoReconnectCount == 0) emit quitRequested(networkId());
- else {
+ if(_autoReconnectCount != 0) {
setConnectionState(Network::Reconnecting);
if(_autoReconnectCount == network()->autoReconnectRetries()) doAutoReconnect(); // first try is immediate
else _autoReconnectTimer.start();
}
}
+void NetworkConnection::setChannelJoined(const QString &channel) {
+ emit channelJoined(networkId(), channel, _channelKeys[channel.toLower()]);
+}
+
+void NetworkConnection::setChannelParted(const QString &channel) {
+ removeChannelKey(channel);
+ emit channelParted(networkId(), channel);
+}
+
void NetworkConnection::addChannelKey(const QString &channel, const QString &key) {
- if(key.isEmpty()) removeChannelKey(channel);
- else _channelKeys[channel] = key;
+ if(key.isEmpty()) {
+ removeChannelKey(channel);
+ } else {
+ _channelKeys[channel.toLower()] = key;
+ }
}
void NetworkConnection::removeChannelKey(const QString &channel) {
- _channelKeys.remove(channel);
+ _channelKeys.remove(channel.toLower());
}
void NetworkConnection::nickChanged(const QString &newNick, const QString &oldNick) {
- emit nickChanged(_network->networkId(), newNick, oldNick);
+ emit nickChanged(networkId(), newNick, oldNick);
}
/* Exception classes for message handling */