File indexing completed on 2024-05-12 17:07:35

0001 // SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0002 // SPDX-FileCopyrightText: 2018 Alexis Lopes Zubeta <contact@azubieta.net>
0003 // SPDX-FileCopyrightText: 2020 Tomaz Canabrava <tcanabrava@kde.org>
0004 
0005 #include "conectionsmodel.h"
0006 
0007 #include <QDebug>
0008 
0009 #include <KLocalizedString>
0010 
0011 #include "netstatclient.h"
0012 
0013 ConnectionsModel::ConnectionsModel(QObject *parent)
0014     : QAbstractListModel(parent)
0015 {
0016     connect(&m_netstatHelper, &NetstatHelper::queryFinished, this, &ConnectionsModel::refreshConnections);
0017     connect(&timer, &QTimer::timeout, &m_netstatHelper, &NetstatHelper::query);
0018     timer.setInterval(10500);
0019 }
0020 
0021 void ConnectionsModel::start()
0022 {
0023     m_busy = true;
0024     Q_EMIT busyChanged();
0025     timer.start();
0026     QTimer::singleShot(0, &m_netstatHelper, &NetstatHelper::query);
0027 }
0028 
0029 void ConnectionsModel::stop()
0030 {
0031     timer.stop();
0032 }
0033 
0034 int ConnectionsModel::rowCount(const QModelIndex &parent) const
0035 {
0036     if (parent.isValid()) {
0037         return 0;
0038     }
0039 
0040     return m_connectionsData.size();
0041 }
0042 
0043 bool ConnectionsModel::busy() const
0044 {
0045     return m_busy;
0046 }
0047 
0048 QVariant ConnectionsModel::data(const QModelIndex &index, int role) const
0049 {
0050     const auto checkIndexFlags = QAbstractItemModel::CheckIndexOption::IndexIsValid | QAbstractItemModel::CheckIndexOption::ParentIsInvalid;
0051 
0052     if (!checkIndex(index, checkIndexFlags)) {
0053         return {};
0054     }
0055 
0056     ConnectionsData data = m_connectionsData.at(index.row());
0057     switch (role) {
0058     case ProtocolRole:
0059         return data.protocol;
0060     case LocalAddressRole:
0061         return data.localAddress;
0062     case ForeignAddressRole:
0063         return data.foreignAddress;
0064     case StatusRole:
0065         return data.status;
0066     case PidRole:
0067         return data.pid;
0068     case ProgramRole:
0069         // HACK. Firefox reports as MainThread
0070         if (data.program == QLatin1String("MainThread")) {
0071             return "Firefox";
0072         } else {
0073             return data.program;
0074         }
0075     }
0076     return {};
0077 }
0078 
0079 QHash<int, QByteArray> ConnectionsModel::roleNames() const
0080 {
0081     return {
0082         {ProtocolRole, "protocol"},
0083         {LocalAddressRole, "localAddress"},
0084         {ForeignAddressRole, "foreignAddress"},
0085         {StatusRole, "status"},
0086         {PidRole, "pid"},
0087         {ProgramRole, "program"},
0088     };
0089 }
0090 
0091 void ConnectionsModel::refreshConnections(const QVector<QStringList> &result)
0092 {
0093     if (m_netstatHelper.hasError()) {
0094         Q_EMIT showErrorMessage(i18n("Failed to get connections: %1", m_netstatHelper.errorString()));
0095         return;
0096     }
0097 
0098     const auto oldConnectionsData = m_connectionsData;
0099     QVector<ConnectionsData> newConnectionsData;
0100 
0101     beginResetModel();
0102     m_connectionsData.clear();
0103     for (const auto &connection : result) {
0104         ConnectionsData conn{.protocol = connection.at(0),
0105                              .localAddress = connection.at(1),
0106                              .foreignAddress = connection.at(2),
0107                              .status = connection.at(3),
0108                              .pid = connection.at(4),
0109                              .program = connection.at(5)};
0110 
0111         if (conn.status == QLatin1String("UNCONN")) {
0112             conn.status = i18n("Not Connected");
0113         } else if (conn.status == QLatin1String("ESTAB")) {
0114             conn.status = i18n("Established");
0115         } else if (conn.status == QLatin1String("LISTEN")) {
0116             conn.status = i18n("Listening");
0117         }
0118 
0119         newConnectionsData.append(conn);
0120     }
0121 
0122     if (newConnectionsData != oldConnectionsData) {
0123         beginResetModel();
0124         m_connectionsData = newConnectionsData;
0125         endResetModel();
0126     }
0127 
0128     if (newConnectionsData.count() != oldConnectionsData.count()) {
0129         Q_EMIT countChanged();
0130     }
0131 
0132     if (m_busy) {
0133         m_busy = false;
0134         Q_EMIT busyChanged();
0135     }
0136 }