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"