Commit c50516af authored by Carl Schwan's avatar Carl Schwan 🚴

Port nic info center module to QML

parent 908d71ce
......@@ -5,29 +5,31 @@ include(CheckSymbolExists)
include(CheckStructHasMember)
include(CheckFunctionExists)
check_include_files(sys/sockio.h HAVE_SYS_SOCKIO_H) # nic.cpp
check_symbol_exists(getnameinfo "sys/socket.h;netdb.h" HAVE_GETNAMEINFO) # nic.cpp
check_struct_has_member("struct sockaddr" "sa_len" "sys/socket.h" HAVE_STRUCT_SOCKADDR_SA_LEN) # nic.cpp
check_function_exists(getifaddrs HAVE_GETIFADDRS) # nic.cpp
configure_file (config-nic.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-nic.h )
check_include_files(sys/sockio.h HAVE_SYS_SOCKIO_H) # networkmodel.cpp
check_symbol_exists(getnameinfo "sys/socket.h;netdb.h" HAVE_GETNAMEINFO) # networkmodel.cpp
check_struct_has_member("struct sockaddr" "sa_len" "sys/socket.h" HAVE_STRUCT_SOCKADDR_SA_LEN) # networkmodel.cpp
check_function_exists(getifaddrs HAVE_GETIFADDRS) # networkmodel.cpp
configure_file(config-nic.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-nic.h)
########### next target ###############
set(kcm_nic_PART_SRCS nic.cpp )
set(kcm_nic_PART_SRCS
nic.cpp
networkmodel.cpp)
add_library(kcm_nic MODULE ${kcm_nic_PART_SRCS})
target_link_libraries(kcm_nic
KF5::I18n
KF5::CoreAddons
KF5::KCMUtils
KF5::QuickAddons)
target_compile_features(kcm_nic PUBLIC cxx_std_14)
target_link_libraries(kcm_nic KF5::KCMUtils KF5::I18n KF5::CoreAddons )
install(TARGETS kcm_nic DESTINATION ${PLUGIN_INSTALL_DIR} )
########### install files ###############
kcoreaddons_desktop_to_json(kcm_nic "kcm_nic.desktop")
install( FILES nic.desktop DESTINATION ${SERVICES_INSTALL_DIR} )
install(FILES kcm_nic.desktop DESTINATION ${SERVICES_INSTALL_DIR})
install(TARGETS kcm_nic DESTINATION ${PLUGIN_INSTALL_DIR}/kcms)
kpackage_install_package(package kcm_nic kcms)
#! /usr/bin/env bash
$XGETTEXT *.cpp -o $podir/kcmnic.pot
$XGETTEXT `find . -name "*.cpp" -o -name "*.qml"` -o $podir/kcm_nic.pot
[Desktop Entry]
Exec=kinfocenter nic
Exec=kinfocenter kcm_nic
Icon=network-card
Type=Service
X-KDE-ServiceTypes=KCModule
Icon=network-card
X-KDE-KInfoCenter-Category=network_information
X-KDE-Library=kcm_nic
X-KDE-ParentApp=kinfocenter
X-KDE-KInfoCenter-Category=network_information
X-KDE-PluginKeyword=kcm_nic
X-DocPath=kinfocenter/index.html#nic
Name=Network Interfaces
......
/**
* SPDX-FileCopyrightText: 2001 Alexander Neundorf <neundorf@kde.org>
* SPDX-FileCopyrightText: 2020 Carl Schwan <carl@carlschwan.eu>
*
* SPDX-LicenseIndentifier: GPL-2.0-or-later
*/
#include "networkmodel.h"
#include <sys/types.h>
#include <sys/param.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/socket.h>
#include "config-nic.h"
#ifdef HAVE_SYS_SOCKIO_H
#include <sys/sockio.h>
#endif
#include <KLocalizedString>
#include <QDebug>
#include <QHash>
#include <net/if.h>
#include <sys/ioctl.h>
#include <KPluginFactory>
#include <KPluginLoader>
#if defined(HAVE_GETNAMEINFO) && defined(HAVE_GETIFADDRS)
#include <ifaddrs.h>
#include <netdb.h>
QString flags_tos(unsigned int flags);
#endif
NetworkModel::NetworkModel(QObject* parent)
: QAbstractListModel(parent)
{
update();
}
QVariant NetworkModel::data(const QModelIndex& index, int role) const
{
Q_UNUSED(role);
if (index.isValid()) {
const auto nic = m_nics.at(index.row());
switch (role) {
case NetworkModel::Roles::NameRole:
return nic->name;
case NetworkModel::Roles::AddrRole:
return nic->addr;
case NetworkModel::Roles::NetMaskRole:
return nic->netmask;
case NetworkModel::Roles::TypeRole:
return nic->type;
case NetworkModel::Roles::HWAddrRole:
return nic->HWaddr;
case NetworkModel::Roles::StateRole:
return nic->state;
}
}
return QVariant{};
}
QHash<int, QByteArray> NetworkModel::roleNames() const
{
return {
{NetworkModel::Roles::NameRole, QByteArrayLiteral("name")},
{NetworkModel::Roles::AddrRole, QByteArrayLiteral("address")},
{NetworkModel::Roles::NetMaskRole, QByteArrayLiteral("netmask")},
{NetworkModel::Roles::TypeRole, QByteArrayLiteral("type")},
{NetworkModel::Roles::HWAddrRole, QByteArrayLiteral("hardwareAddress")},
{NetworkModel::Roles::StateRole, QByteArrayLiteral("state")}
};
}
int NetworkModel::rowCount(const QModelIndex &parent) const
{
Q_UNUSED(parent)
return m_nics.size();
}
QList<NetworkModel::MyNIC *> findNICs();
void NetworkModel::update()
{
m_nics = findNICs();
}
static QString HWaddr2String(const char *hwaddr)
{
QString ret;
for (int i=0; i<6; i++, hwaddr++) {
int v = (*hwaddr & 0xff);
QString num = QStringLiteral("%1").arg(v, 0, 16);
if (num.length() < 2)
num.prepend(QStringLiteral("0"));
if (i>0)
ret.append(QStringLiteral(":"));
ret.append(num);
}
return ret;
}
// Convenience wrapper around sa_len being available or not.
static int getNameInfo(struct sockaddr *addr, struct ifaddrs *ifa, char *hostOut)
{
#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
return getnameinfo(addr,
ifa->ifa_addr->sa_len,
hostOut, 127,
nullptr, 0,
NI_NUMERICHOST);
#else
return getnameinfo(addr,
(ifa->ifa_addr->sa_family == AF_INET) ? sizeof(struct sockaddr_in) :
sizeof(struct sockaddr_in6),
hostOut, NI_MAXHOST,
nullptr, 0,
NI_NUMERICHOST);
#endif
}
QList<NetworkModel::MyNIC*> findNICs() {
QList<NetworkModel::MyNIC*> nl;
#if !defined(HAVE_GETIFADDRS) || !defined(HAVE_GETNAMEINFO)
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
char buf[8*1024];
struct ifconf ifc;
ifc.ifc_len = sizeof(buf);
ifc.ifc_req = (struct ifreq *) buf;
int result=ioctl(sockfd, SIOCGIFCONF, &ifc);
for (char* ptr = buf; ptr < buf + ifc.ifc_len;) {
struct ifreq *ifr =(struct ifreq *) ptr;
#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
int len = sizeof(struct sockaddr);
if (ifr->ifr_addr.sa_len > len)
len = ifr->ifr_addr.sa_len; /* length > 16 */
ptr += sizeof(ifr->ifr_name) + len; /* for next one in buffer */
#else
ptr += sizeof(*ifr); /* for next one in buffer */
#endif
int flags;
struct sockaddr_in *sinptr;
MyNIC *tmp=nullptr;
switch (ifr->ifr_addr.sa_family) {
case AF_INET:
sinptr = (struct sockaddr_in *) &ifr->ifr_addr;
flags=0;
struct ifreq ifcopy;
ifcopy=*ifr;
result=ioctl(sockfd, SIOCGIFFLAGS, &ifcopy);
flags=ifcopy.ifr_flags;
tmp=new MyNIC;
tmp->name=ifr->ifr_name;
tmp->state= ((flags & IFF_UP) == IFF_UP) ? upMessage : downMessage;
if ((flags & IFF_BROADCAST) == IFF_BROADCAST)
tmp->type=i18nc("@item:intext Mode of network card", "Broadcast");
else if ((flags & IFF_POINTOPOINT) == IFF_POINTOPOINT)
tmp->type=i18nc("@item:intext Mode of network card", "Point to Point");
#ifndef _AIX
else if ((flags & IFF_MULTICAST) == IFF_MULTICAST)
tmp->type=i18nc("@item:intext Mode of network card", "Multicast");
#endif
else if ((flags & IFF_LOOPBACK) == IFF_LOOPBACK)
tmp->type=i18nc("@item:intext Mode of network card", "Loopback");
else
tmp->type=i18nc("@item:intext Mode of network card", "Unknown");
tmp->addr=inet_ntoa(sinptr->sin_addr);
ifcopy=*ifr;
result=ioctl(sockfd, SIOCGIFNETMASK, &ifcopy);
if (result==0) {
sinptr = (struct sockaddr_in *) &ifcopy.ifr_addr;
tmp->netmask=inet_ntoa(sinptr->sin_addr);
} else
tmp->netmask=i18nc("Unknown network mask", "Unknown");
ifcopy=*ifr;
result=-1; // if none of the two #ifs below matches, ensure that result!=0 so that "Unknown" is returned as result
#ifdef SIOCGIFHWADDR
result=ioctl(sockfd, SIOCGIFHWADDR, &ifcopy);
if (result==0) {
char *n = &ifcopy.ifr_ifru.ifru_hwaddr.sa_data[0];
tmp->HWaddr = HWaddr2String(n);
}
#elif defined SIOCGENADDR
result=ioctl(sockfd,SIOCGENADDR,&ifcopy);
if (result==0)
{
char *n = &ifcopy.ifr_ifru.ifru_enaddr[0];
tmp->HWaddr = HWaddr2String(n);
}
#endif
if (result!=0) {
tmp->HWaddr = i18nc("Unknown HWaddr", "Unknown");
}
nl.append(tmp);
break;
default:
break;
}
}
#else
struct ifaddrs *ifap, *ifa;
if (getifaddrs(&ifap) != 0) {
return nl;
}
NetworkModel::MyNIC *tmp = nullptr;
for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
if (!ifa->ifa_addr) {
qDebug() << "stumbled over an interface without ifa_addr. You may wish to file a bug against kinfocenter"
<< ifa->ifa_name << ifa->ifa_flags;
continue;
}
switch (ifa->ifa_addr->sa_family) {
case AF_INET6:
case AF_INET: {
tmp = new NetworkModel::MyNIC;
tmp->name = ifa->ifa_name;
char buf[128];
bzero(buf, 128);
getNameInfo(ifa->ifa_addr, ifa, buf);
tmp->addr = buf;
if (ifa->ifa_netmask != nullptr) {
bzero(buf, 128);
getNameInfo(ifa->ifa_netmask, ifa, buf);
tmp->netmask = buf;
}
tmp->state= (ifa->ifa_flags & IFF_UP) ? true : false;
tmp->type = flags_tos(ifa->ifa_flags);
nl.append(tmp);
break;
}
default:
break;
}
}
freeifaddrs(ifap);
#endif
return nl;
}
#if defined(HAVE_GETNAMEINFO) && defined(HAVE_GETIFADDRS)
QString flags_tos(unsigned int flags)
{
QString tmp;
if (flags & IFF_POINTOPOINT) {
tmp += i18nc("@item:intable Network type", "Point to Point");
}
if (flags & IFF_BROADCAST) {
if (tmp.length()) {
tmp += QLatin1String(", ");
}
tmp += i18nc("@item:intable Netork type", "Broadcast");
}
if (flags & IFF_MULTICAST) {
if (tmp.length()) {
tmp += QLatin1String(", ");
}
tmp += i18nc("@item:intable Network type", "Multicast");
}
if (flags & IFF_LOOPBACK) {
if (tmp.length()) {
tmp += QLatin1String(", ");
}
tmp += i18nc("@item:intable Network type", "Loopback");
}
return tmp;
}
#endif
/**
* SPDX-FileCopyrightText: 2020 Carl Schwan <carl@carlschwan.eu>
*
* SPDX-LicenseIndentifier: GPL-2.0-or-later
*/
#pragma once
#include <QAbstractTableModel>
class NetworkModel : public QAbstractListModel
{
Q_OBJECT
public:
struct MyNIC {
QString name;
QString addr;
QString netmask;
bool state;
QString type;
QString HWaddr;
};
enum Roles {
NameRole = Qt::UserRole + 1,
AddrRole,
NetMaskRole,
TypeRole,
HWAddrRole,
StateRole,
};
explicit NetworkModel(QObject *parent = nullptr);
virtual ~NetworkModel() = default;
virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
virtual QHash<int, QByteArray> roleNames() const override;
virtual int rowCount(const QModelIndex &parent = QModelIndex()) const override;
Q_INVOKABLE void update();
private:
QList<MyNIC *> m_nics;
};
/*
* nic.cpp
/**
* SPDX-FileCopyrightText: 2001 Alexander Neundorf <neundorf@kde.org>
* SPDX-FileCopyrightText: 2020 Carl Schwan <carl@carlschwan.eu>
*
* Copyright (C) 2001 Alexander Neundorf <neundorf@kde.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* SPDX-LicenseIndentifier: GPL-2.0-or-later
*/
#include "nic.h"
#include <sys/types.h>
#include <sys/param.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/socket.h>
#include "config-nic.h"
#ifdef HAVE_SYS_SOCKIO_H
#include <sys/sockio.h>
#endif
#include <KAboutData>
#include <KLocalizedString>
#include <QPushButton>
#include <QTimer>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QTreeWidget>
#include <QDebug>
#include <net/if.h>
#include <sys/ioctl.h>
#include <KPluginFactory>
#include <KPluginLoader>
#include <KAboutData>
#include <KLocalizedString>
#include "networkmodel.h"
#if defined(HAVE_GETNAMEINFO) && defined(HAVE_GETIFADDRS)
#include <ifaddrs.h>
#include <netdb.h>
QString flags_tos (unsigned int flags);
#endif
K_PLUGIN_FACTORY(KCMNicFactory,
registerPlugin<KCMNic>();
)
struct MyNIC {
QString name;
QString addr;
QString netmask;
QString state;
QString type;
QString HWaddr;
};
QList<MyNIC*> findNICs();
KCMNic::KCMNic(QWidget *parent, const QVariantList &) :
KCModule(parent) {
QVBoxLayout *box=new QVBoxLayout(this);
box->setContentsMargins(0, 0, 0, 0);
m_list=new QTreeWidget(this);
m_list->setRootIsDecorated(false);
box->addWidget(m_list);
QStringList columns;
columns<<i18n("Name")<<i18n("IP Address")<<i18n("Network Mask")<<i18n("Type")<<i18n("State")<<i18n("HWAddr");
m_list->setHeaderLabels(columns);
QHBoxLayout *hbox=new QHBoxLayout();
box->addItem(hbox);
m_updateButton=new QPushButton(i18n("&Update"),this);
hbox->addStretch(1);
hbox->addWidget(m_updateButton);
QTimer* timer=new QTimer(this);
timer->start(60000);
connect(m_updateButton, &QPushButton::clicked, this, &KCMNic::update);
connect(timer, &QTimer::timeout, this, &KCMNic::update);
update();
KAboutData *about = new KAboutData(i18n("kcminfo"),
i18n("System Information Control Module"),
QString(), QString(), KAboutLicense::GPL,
i18n("(c) 2001 - 2002 Alexander Neundorf"));
about->addAuthor(i18n("Alexander Neundorf"), QString(), QStringLiteral("neundorf@kde.org"));
setAboutData(about);
}
void KCMNic::update() {
m_list->clear();
QList<MyNIC*> nics=findNICs();
foreach(MyNIC* tmp, nics) {
QStringList lst;
lst << tmp->name<<tmp->addr<<tmp->netmask<<tmp->type<<tmp->state<<tmp->HWaddr;
new QTreeWidgetItem(m_list,lst);
delete tmp;
}
nics.clear();
}
static QString HWaddr2String(const char *hwaddr) {
QString ret;
for (int i=0; i<6; i++, hwaddr++) {
int v = (*hwaddr & 0xff);
QString num = QStringLiteral("%1").arg(v, 0, 16);
if (num.length() < 2)
num.prepend(QStringLiteral("0"));
if (i>0)
ret.append(QStringLiteral(":"));
ret.append(num);
}
return ret;
}
// Convenience wrapper around sa_len being available or not.
static int getNameInfo(struct sockaddr *addr, struct ifaddrs *ifa, char *hostOut)
{
#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
return getnameinfo(addr,
ifa->ifa_addr->sa_len,
hostOut, 127,
nullptr, 0,
NI_NUMERICHOST);
#else
return getnameinfo(addr,
(ifa->ifa_addr->sa_family == AF_INET) ? sizeof(struct sockaddr_in) :
sizeof(struct sockaddr_in6),
hostOut, NI_MAXHOST,
nullptr, 0,
NI_NUMERICHOST);
#endif
}
QList<MyNIC*> findNICs() {
QString upMessage(i18nc("State of network card is connected", "Up") );
QString downMessage(i18nc("State of network card is disconnected", "Down") );
QList<MyNIC*> nl;
#if !defined(HAVE_GETIFADDRS) || !defined(HAVE_GETNAMEINFO)
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
char buf[8*1024];
struct ifconf ifc;
ifc.ifc_len = sizeof(buf);
ifc.ifc_req = (struct ifreq *) buf;
int result=ioctl(sockfd, SIOCGIFCONF, &ifc);
for (char* ptr = buf; ptr < buf + ifc.ifc_len;) {
struct ifreq *ifr =(struct ifreq *) ptr;
#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
int len = sizeof(struct sockaddr);
if (ifr->ifr_addr.sa_len > len)
len = ifr->ifr_addr.sa_len; /* length > 16 */
ptr += sizeof(ifr->ifr_name) + len; /* for next one in buffer */
#else
ptr += sizeof(*ifr); /* for next one in buffer */
#endif
int flags;
struct sockaddr_in *sinptr;
MyNIC *tmp=nullptr;
switch (ifr->ifr_addr.sa_family) {
case AF_INET:
sinptr = (struct sockaddr_in *) &ifr->ifr_addr;
flags=0;
struct ifreq ifcopy;
ifcopy=*ifr;
result=ioctl(sockfd, SIOCGIFFLAGS, &ifcopy);
flags=ifcopy.ifr_flags;