File indexing completed on 2023-10-01 08:01:43
0001 // Copyright (c) 2015 Pino Toscano <pino@kde.org> 0002 // 0003 // This program is free software; you can redistribute it and/or 0004 // modify it under the terms of the GNU General Public License 0005 // version 2 as published by the Free Software Foundation. 0006 // 0007 // This program is distributed in the hope that it will be useful, 0008 // but WITHOUT ANY WARRANTY; without even the implied warranty of 0009 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0010 // General Public License for more details. 0011 // 0012 // You should have received a copy of the GNU General Public License 0013 // along with this program; see the file COPYING. If not, write to 0014 // the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0015 // Boston, MA 02110-1301, USA. 0016 0017 #include "metatlantic.h" 0018 0019 #include <QTcpSocket> 0020 #include <QTextCodec> 0021 #include <QTimer> 0022 #include <QXmlStreamReader> 0023 0024 #include <atlantik_debug.h> 0025 0026 Metatlantic::Metatlantic(const QString &host, int port, QObject *parent) 0027 : KJob(parent) 0028 , m_host(host) 0029 , m_port(port) 0030 , m_socket(nullptr) 0031 { 0032 setCapabilities(Killable); 0033 } 0034 0035 Metatlantic::~Metatlantic() 0036 { 0037 if (m_socket) 0038 closeSocket(false); 0039 } 0040 0041 void Metatlantic::start() 0042 { 0043 m_socket = new QTcpSocket(this); 0044 m_socket->setSocketOption(QAbstractSocket::LowDelayOption, true); 0045 connect(m_socket, SIGNAL(errorOccurred(QAbstractSocket::SocketError)), this, SLOT(slotSocketError(QAbstractSocket::SocketError))); 0046 connect(m_socket, SIGNAL(connected()), this, SLOT(slotSocketConnected())); 0047 0048 m_socket->connectToHost(m_host, m_port); 0049 } 0050 0051 bool Metatlantic::doKill() 0052 { 0053 closeSocket(false); 0054 return true; 0055 } 0056 0057 void Metatlantic::slotSocketError(QAbstractSocket::SocketError socketError) 0058 { 0059 setError(UserDefinedError + socketError); 0060 setErrorText(m_socket->errorString()); 0061 emitResult(); 0062 } 0063 0064 void Metatlantic::slotSocketConnected() 0065 { 0066 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 0067 m_stream.setCodec(QTextCodec::codecForName("UTF-8")); 0068 #endif 0069 m_stream.setDevice(m_socket); 0070 connect(m_socket, SIGNAL(readyRead()), this, SLOT(slotSocketRead())); 0071 } 0072 0073 void Metatlantic::slotSocketRead() 0074 { 0075 if (!m_stream.device()) 0076 return; 0077 0078 const QString line = m_stream.readLine(); 0079 if (!line.isNull()) 0080 { 0081 processMsg(line); 0082 QTimer::singleShot(0, this, SLOT(slotSocketRead())); 0083 } 0084 } 0085 0086 void Metatlantic::closeSocket(bool doEmitResult) 0087 { 0088 m_stream.setDevice(nullptr); 0089 m_socket->close(); 0090 disconnect(m_socket, nullptr, this, nullptr); 0091 m_socket->deleteLater(); 0092 m_socket = nullptr; 0093 if (doEmitResult) 0094 emitResult(); 0095 } 0096 0097 void Metatlantic::processMsg(const QString &msg) 0098 { 0099 qCDebug(ATLANTIK_LOG) << msg; 0100 QXmlStreamReader reader(msg); 0101 if (!reader.readNextStartElement() || reader.name() != QLatin1String("meta_atlantic")) 0102 { 0103 // Invalid data, close the connection 0104 closeSocket(); 0105 return; 0106 } 0107 bool do_send_follow = false; 0108 bool do_close = false; 0109 while (reader.readNextStartElement()) { 0110 const auto name = reader.name(); 0111 if (name == QLatin1String("metaserver")) 0112 { 0113 const auto serverVersion = reader.attributes().value(QStringLiteral("version")); 0114 if (!serverVersion.isNull()) 0115 qCDebug(ATLANTIK_LOG) << "metaserver version" << serverVersion; 0116 do_send_follow = true; 0117 } 0118 else if (name == QLatin1String("server")) 0119 { 0120 const QXmlStreamAttributes attrs = reader.attributes(); 0121 const QString host = attrs.value(QStringLiteral("host")).toString(); 0122 const int port = attrs.value(QStringLiteral("port")).toInt(); 0123 const QString version = attrs.value(QStringLiteral("version")).toString(); 0124 const int users = attrs.value(QStringLiteral("users")).toInt(); 0125 Q_EMIT metatlanticAdd(host, port, version, users); 0126 do_close = true; 0127 } 0128 else 0129 qCDebug(ATLANTIK_LOG) << "ignored TAG:" << name; 0130 reader.skipCurrentElement(); 0131 } 0132 if (do_send_follow) { 0133 m_stream << "FOLLOW" << '\n'; 0134 m_stream.flush(); 0135 } 0136 if (do_close) 0137 closeSocket(); 0138 } 0139 0140 #include "moc_metatlantic.cpp"