File indexing completed on 2024-10-13 12:20:59

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     m_stream.setDevice(m_socket);
0067     connect(m_socket, SIGNAL(readyRead()), this, SLOT(slotSocketRead()));
0068 }
0069 
0070 void Metatlantic::slotSocketRead()
0071 {
0072     if (!m_stream.device())
0073         return;
0074 
0075     const QString line = m_stream.readLine();
0076     if (!line.isNull())
0077     {
0078         processMsg(line);
0079         QTimer::singleShot(0, this, SLOT(slotSocketRead()));
0080     }
0081 }
0082 
0083 void Metatlantic::closeSocket(bool doEmitResult)
0084 {
0085     m_stream.setDevice(nullptr);
0086     m_socket->close();
0087     disconnect(m_socket, nullptr, this, nullptr);
0088     m_socket->deleteLater();
0089     m_socket = nullptr;
0090     if (doEmitResult)
0091         emitResult();
0092 }
0093 
0094 void Metatlantic::processMsg(const QString &msg)
0095 {
0096     qCDebug(ATLANTIK_LOG) << msg;
0097     QXmlStreamReader reader(msg);
0098     if (!reader.readNextStartElement() || reader.name() != QLatin1String("meta_atlantic"))
0099     {
0100         // Invalid data, close the connection
0101         closeSocket();
0102         return;
0103     }
0104     bool do_send_follow = false;
0105     bool do_close = false;
0106     while (reader.readNextStartElement()) {
0107         const auto name = reader.name();
0108         if (name == QLatin1String("metaserver"))
0109         {
0110             const auto serverVersion = reader.attributes().value(QStringLiteral("version"));
0111             if (!serverVersion.isNull())
0112                 qCDebug(ATLANTIK_LOG) << "metaserver version" << serverVersion;
0113             do_send_follow = true;
0114         }
0115         else if (name == QLatin1String("server"))
0116         {
0117             const QXmlStreamAttributes attrs = reader.attributes();
0118             const QString host = attrs.value(QStringLiteral("host")).toString();
0119             const int port = attrs.value(QStringLiteral("port")).toInt();
0120             const QString version = attrs.value(QStringLiteral("version")).toString();
0121             const int users = attrs.value(QStringLiteral("users")).toInt();
0122             Q_EMIT metatlanticAdd(host, port, version, users);
0123             do_close = true;
0124         }
0125         else
0126             qCDebug(ATLANTIK_LOG) << "ignored TAG:" << name;
0127         reader.skipCurrentElement();
0128     }
0129     if (do_send_follow) {
0130         m_stream << "FOLLOW" << '\n';
0131         m_stream.flush();
0132     }
0133     if (do_close)
0134         closeSocket();
0135 }
0136 
0137 #include "moc_metatlantic.cpp"