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"