File indexing completed on 2024-05-12 16:59:53

0001 /*
0002     SPDX-FileCopyrightText: 2020-2022 Harald Sitter <sitter@kde.org>
0003     SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0004 */
0005 
0006 #include "ksambasharemodel.h"
0007 
0008 #include <QApplication> // for kpropertiesdialog parenting
0009 #include <QDBusPendingCallWatcher>
0010 #include <QMetaEnum>
0011 
0012 #include <KPropertiesDialog>
0013 #include <KSambaShare>
0014 
0015 #include "org.freedesktop.Avahi.Server.h"
0016 
0017 KSambaShareModel::KSambaShareModel(QObject *parent)
0018     : QAbstractListModel(parent)
0019 {
0020     connect(KSambaShare::instance(), &KSambaShare::changed, this, &KSambaShareModel::reloadData);
0021     metaObject()->invokeMethod(this, &KSambaShareModel::reloadData);
0022 }
0023 
0024 KSambaShareModel::~KSambaShareModel() = default;
0025 
0026 int KSambaShareModel::rowCount(const QModelIndex &parent) const
0027 {
0028     Q_UNUSED(parent)
0029     return m_list.size();
0030 }
0031 
0032 QVariant KSambaShareModel::data(const QModelIndex &index, int intRole) const
0033 {
0034     if (!index.isValid()) {
0035         return QVariant();
0036     }
0037 
0038     Q_ASSERT(index.row() < m_list.length());
0039 
0040     static QMetaEnum roleEnum = QMetaEnum::fromType<Role>();
0041     if (roleEnum.valueToKey(intRole) == nullptr) {
0042         return QVariant();
0043     }
0044     const auto role = static_cast<Role>(intRole);
0045 
0046     const KSambaShareData &share = m_list.at(index.row());
0047     switch (role) {
0048     case Role::Name:
0049         return share.name();
0050     case Role::Path:
0051         return share.path();
0052     case Role::Comment:
0053         return share.comment();
0054     case Role::ShareUrl: {
0055         if (m_fqdn.isEmpty()) {
0056             return QVariant();
0057         }
0058         QUrl url;
0059         url.setScheme(QStringLiteral("smb"));
0060         url.setHost(m_fqdn);
0061         url.setPath(QStringLiteral("/") + share.name());
0062         return url;
0063     }
0064     }
0065 
0066     return QVariant();
0067 }
0068 
0069 Q_INVOKABLE void KSambaShareModel::showPropertiesDialog(int index)
0070 {
0071     auto dialog = new KPropertiesDialog(QUrl::fromUserInput(m_list.at(index).path()), QApplication::activeWindow());
0072     dialog->setFileNameReadOnly(true);
0073     dialog->showFileSharingPage();
0074     dialog->show();
0075 }
0076 
0077 void KSambaShareModel::reloadData()
0078 {
0079     beginResetModel();
0080     m_list.clear();
0081     const auto samba = KSambaShare::instance();
0082     const QStringList sharedDirectories = samba->sharedDirectories();
0083     for (const auto &path : sharedDirectories) {
0084         m_list += samba->getSharesByPath(path);
0085     }
0086     endResetModel();
0087 
0088     // Reload FQDN
0089     m_fqdn.clear();
0090     auto avahi = new OrgFreedesktopAvahiServerInterface(QStringLiteral("org.freedesktop.Avahi"), QStringLiteral("/"), QDBusConnection::systemBus(), this);
0091     auto watcher = new QDBusPendingCallWatcher(avahi->GetHostNameFqdn(), this);
0092     connect(watcher, &QDBusPendingCallWatcher::finished, this, [this, avahi, watcher] {
0093         watcher->deleteLater();
0094         avahi->deleteLater();
0095         QDBusPendingReply<QString> reply = *watcher;
0096         if (reply.isError()) {
0097             // When Avahi isn't available there's not really a good way to resolve the FQDN. The user could drive
0098             // resolution through LLMNR or NetBios or some other ad-hoc system, neither provide us with an easy
0099             // way to get their configured FQDN. We are therefor opting to not render URLs in that scenario since
0100             // we can't get a name that will reliably work.
0101             m_fqdn.clear();
0102             return;
0103         }
0104         m_fqdn = reply.argumentAt(0).toString();
0105         Q_EMIT dataChanged(createIndex(0, 0), createIndex(m_list.count(), 0), {static_cast<int>(Role::ShareUrl)});
0106     });
0107 }
0108 
0109 bool KSambaShareModel::hasChildren(const QModelIndex &parent) const
0110 {
0111     return !parent.isValid() ? false : (rowCount(parent) > 0);
0112 }
0113 
0114 QHash<int, QByteArray> KSambaShareModel::roleNames() const
0115 {
0116     static QHash<int, QByteArray> roles;
0117     if (!roles.isEmpty()) {
0118         return roles;
0119     }
0120 
0121     const QMetaEnum roleEnum = QMetaEnum::fromType<Role>();
0122     for (int i = 0; i < roleEnum.keyCount(); ++i) {
0123         const int value = roleEnum.value(i);
0124         Q_ASSERT(value != -1);
0125         roles[static_cast<int>(value)] = QByteArray("ROLE_") + roleEnum.valueToKey(value);
0126     }
0127     return roles;
0128 }