File indexing completed on 2025-01-05 04:35:37
0001 /* 0002 SPDX-License-Identifier: GPL-2.0-or-later 0003 SPDX-FileCopyrightText: 2004 Jan Schaefer <j_schaef@informatik.uni-kl.de> 0004 SPDX-FileCopyrightText: 2011 Rodrigo Belem <rclbelem@gmail.com> 0005 SPDX-FileCopyrightText: 2019 Nate Graham <nate@kde.org> 0006 SPDX-FileCopyrightText: 2020 Harald Sitter <sitter@kde.org> 0007 SPDX-FileCopyrightText: 2021 Slava Aseev <nullptrnine@basealt.ru> 0008 */ 0009 0010 #ifndef SAMBAUSERSHAREPLUGIN_H 0011 #define SAMBAUSERSHAREPLUGIN_H 0012 0013 #include <KPropertiesDialogPlugin> 0014 #include <KPropertiesDialog> 0015 #include <KSambaShareData> 0016 #include <KSambaShare> 0017 #include <QFileInfo> 0018 0019 #include <memory> 0020 #include "usermanager.h" 0021 #include "model.h" 0022 #include "permissionshelper.h" 0023 0024 class ShareContext : public QObject 0025 { 0026 Q_OBJECT 0027 Q_PROPERTY(bool enabled READ enabled WRITE setEnabled NOTIFY enabledChanged) 0028 Q_PROPERTY(bool canEnableGuest READ canEnableGuest CONSTANT) 0029 Q_PROPERTY(bool guestEnabled READ guestEnabled WRITE setGuestEnabled NOTIFY guestEnabledChanged) 0030 Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged) 0031 Q_PROPERTY(int maximumNameLength READ maximumNameLength CONSTANT) 0032 Q_PROPERTY(QString path READ path CONSTANT) 0033 public: 0034 explicit ShareContext(const QUrl &url, QObject *parent = nullptr) 0035 : QObject(parent) 0036 , m_shareData(resolveShare(url)) 0037 , m_enabled(KSambaShare::instance()->isDirectoryShared(m_shareData.path())) 0038 // url isn't a member. always use .path()! 0039 { 0040 } 0041 0042 bool enabled() const 0043 { 0044 return m_enabled; 0045 } 0046 0047 void setEnabled(bool enabled) 0048 { 0049 m_enabled = enabled; 0050 Q_EMIT enabledChanged(); 0051 } 0052 0053 bool canEnableGuest() 0054 { 0055 return KSambaShare::instance()->areGuestsAllowed(); 0056 } 0057 0058 bool guestEnabled() const 0059 { 0060 // WTF is that enum even... 0061 switch (m_shareData.guestPermission()) { 0062 case KSambaShareData::GuestsNotAllowed: 0063 return false; 0064 case KSambaShareData::GuestsAllowed: 0065 return true; 0066 } 0067 Q_UNREACHABLE(); 0068 return false; 0069 } 0070 0071 void setGuestEnabled(bool enabled) 0072 { 0073 m_shareData.setGuestPermission(enabled ? KSambaShareData::GuestsAllowed : KSambaShareData::GuestsNotAllowed); 0074 Q_EMIT guestEnabledChanged(); 0075 } 0076 0077 QString name() const 0078 { 0079 return m_shareData.name(); 0080 } 0081 0082 QString path() const { 0083 return m_shareData.path(); 0084 } 0085 0086 void setName(const QString &name) 0087 { 0088 m_shareData.setName(name); 0089 Q_EMIT nameChanged(); 0090 } 0091 0092 static constexpr int maximumNameLength() 0093 { 0094 // Windows 10 allows creating shares with a maximum of 60 characters when measured on 2020-08-13. 0095 // We consider this kind of a soft limit as there appears to be no actual limit specified anywhere. 0096 return 60; 0097 } 0098 0099 0100 Q_INVOKABLE static bool isNameFree(const QString &name) 0101 { 0102 return KSambaShare::instance()->isShareNameAvailable(name); 0103 } 0104 0105 public Q_SLOTS: 0106 QString newShareName(const QUrl &url) 0107 { 0108 Q_ASSERT(url.isValid()); 0109 Q_ASSERT(!url.isEmpty()); 0110 // TODO pretty sure this is buggy for urls with trailing slash where filename would be "" 0111 return url.fileName().left(maximumNameLength()); 0112 } 0113 0114 Q_SIGNALS: 0115 void enabledChanged(); 0116 void guestEnabledChanged(); 0117 void nameChanged(); 0118 0119 private: 0120 KSambaShareData resolveShare(const QUrl &url) 0121 { 0122 QFileInfo info(url.toLocalFile()); 0123 const QString path = info.canonicalFilePath(); 0124 Q_ASSERT(!path.isEmpty()); 0125 const QList<KSambaShareData> shareList = KSambaShare::instance()->getSharesByPath(path); 0126 if (!shareList.isEmpty()) { 0127 return shareList.first(); // FIXME: using just the first in the list for a while 0128 } 0129 KSambaShareData newShare; 0130 newShare.setName(newShareName(url)); 0131 newShare.setGuestPermission(KSambaShareData::GuestsNotAllowed); 0132 newShare.setPath(path); 0133 return newShare; 0134 } 0135 0136 public: 0137 // TODO shouldn't be public may need refactoring though because the ACL model needs an immutable copy 0138 KSambaShareData m_shareData; 0139 private: 0140 bool m_enabled = false; // this gets cached so we can manipulate its state from qml 0141 }; 0142 0143 0144 class SambaUserSharePlugin : public KPropertiesDialogPlugin 0145 { 0146 Q_OBJECT 0147 Q_PROPERTY(bool dirty READ isDirty WRITE setDirty NOTIFY changed) // So qml can mark dirty 0148 Q_PROPERTY(bool ready READ isReady NOTIFY readyChanged) // intentionally not writable from qml 0149 // Expose instance-singleton members so QML may access them. 0150 // They aren't application-wide singletons and also cannot easily be ctor'd from QML. 0151 Q_PROPERTY(UserManager *userManager MEMBER m_userManager CONSTANT) 0152 Q_PROPERTY(UserPermissionModel *userPermissionModel MEMBER m_model CONSTANT) 0153 Q_PROPERTY(ShareContext *shareContext MEMBER m_context CONSTANT) 0154 Q_PROPERTY(PermissionsHelper *permissionsHelper MEMBER m_permissionsHelper CONSTANT) 0155 0156 public: 0157 SambaUserSharePlugin(QObject *parent); 0158 ~SambaUserSharePlugin() override = default; 0159 void applyChanges() override; 0160 0161 Q_INVOKABLE static bool isSambaInstalled(); 0162 Q_INVOKABLE static void reboot(); 0163 Q_INVOKABLE static void showSambaStatus(); 0164 0165 bool isReady() const; 0166 0167 Q_SIGNALS: 0168 void readyChanged(); 0169 0170 private: 0171 void setReady(bool ready); 0172 void reportAdd(KSambaShareData::UserShareError error); 0173 void reportRemove(KSambaShareData::UserShareError error); 0174 0175 const QString m_url; 0176 ShareContext *m_context= nullptr; 0177 UserPermissionModel *m_model = nullptr; 0178 UserManager *m_userManager = nullptr; 0179 PermissionsHelper *m_permissionsHelper = nullptr; 0180 bool m_ready = false; 0181 // Hold the qquickwidget so it gets destroyed with us. Otherwise we'd have bogus reference errors 0182 // as the Plugin instance is exposed as contextProperty to qml but the widget is parented to the PropertiesDialog 0183 // (i.e. our parent). So the lifetime of the widget would usually exceed ours. 0184 std::unique_ptr<QWidget> m_page = nullptr; 0185 }; 0186 0187 #endif // SAMBAUSERSHAREPLUGIN_H