sambausershareplugin.cpp 11.9 KB
Newer Older
1
2
/*
  Copyright (c) 2004 Jan Schaefer <j_schaef@informatik.uni-kl.de>
3
  Copyright (c) 2011 Rodrigo Belem <rclbelem@gmail.com>
4
  Copyright (c) 2015 Harald Sitter <sitter@kde.org>
Nate Graham's avatar
Nate Graham committed
5
  Copyright (c) 2019 Nate Graham <nate@kde.org>
6
7
8
9
10
11
12
13
14
15
16
17
18

  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
Dirk Mueller's avatar
Dirk Mueller committed
19
  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
20
21
22

*/

23
24
#include <QDBusInterface>
#include <QDBusPendingReply>
Harald Sitter's avatar
Harald Sitter committed
25
26
27
#include <QDialogButtonBox>
#include <QFileInfo>
#include <QFrame>
28
#include <QIcon>
29
#include <QPushButton>
30
#include <QStandardPaths>
Harald Sitter's avatar
Harald Sitter committed
31
#include <QStringList>
32
#include <QDebug>
Harald Sitter's avatar
Harald Sitter committed
33
34

#include <KMessageBox>
Ranveer Aggarwal's avatar
Ranveer Aggarwal committed
35
36
#include <KPluginFactory>
#include <KPluginLoader>
Harald Sitter's avatar
Harald Sitter committed
37
38
#include <KSambaShare>
#include <KSambaShareData>
39
#include <ktoolinvocation.h>
40

41
#include "sambausershareplugin.h"
42
43
#include "model.h"
#include "delegate.h"
44

45
K_PLUGIN_FACTORY(SambaUserSharePluginFactory, registerPlugin<SambaUserSharePlugin>();)
46

Pino Toscano's avatar
Pino Toscano committed
47
48
49
50
51
52
53
54
55
56
57
58
59
// copied from kio/src/core/ksambashare.cpp, KSambaSharePrivate::isSambaInstalled()
static bool isSambaInstalled()
{
    if (QFile::exists(QStringLiteral("/usr/sbin/smbd"))
            || QFile::exists(QStringLiteral("/usr/local/sbin/smbd"))) {
        return true;
    }

    //qDebug() << "Samba is not installed!";

    return false;
}

60
61
SambaUserSharePlugin::SambaUserSharePlugin(QObject *parent, const QList<QVariant> &args)
    : KPropertiesDialogPlugin(qobject_cast<KPropertiesDialog *>(parent))
Kai Uwe Broulik's avatar
Kai Uwe Broulik committed
62
    , m_url(properties->item().mostLocalUrl().toLocalFile())
63
    , shareData()
64
{
65
66
    Q_UNUSED(args);

67
    if (m_url.isEmpty()) {
68
69
        return;
    }
Rodrigo Belem's avatar
Rodrigo Belem committed
70

71
    QFileInfo pathInfo(m_url);
72
    if (!pathInfo.permission(QFile::ReadUser | QFile::WriteUser)) {
Rodrigo Belem's avatar
Rodrigo Belem committed
73
74
75
        return;
    }

76
    QFrame *vbox = new QFrame();
Rodrigo Belem's avatar
Rodrigo Belem committed
77
78
    properties->addPage(vbox, i18n("&Share"));
    properties->setFileSharingPage(vbox);
79
    QVBoxLayout *vLayoutMaster = new QVBoxLayout(vbox);
Rodrigo Belem's avatar
Rodrigo Belem committed
80

81
82
83
84
    m_failedSambaWidgets = new QWidget(vbox);
    vLayoutMaster->addWidget(m_failedSambaWidgets);
    QVBoxLayout *vFailedLayout = new QVBoxLayout(m_failedSambaWidgets);
    vFailedLayout->setAlignment(Qt::AlignJustify);
85
    vFailedLayout->setContentsMargins(0, 0, 0, 0);
86
87
88
89
    vFailedLayout->addWidget(new QLabel(i18n("The Samba package failed to install."), m_failedSambaWidgets));
    vFailedLayout->addStretch();
    m_failedSambaWidgets->hide();

90
91
92
93
    m_installSambaWidgets = new QWidget(vbox);
    vLayoutMaster->addWidget(m_installSambaWidgets);
    QVBoxLayout *vLayout = new QVBoxLayout(m_installSambaWidgets);
    vLayout->setAlignment(Qt::AlignJustify);
94
    vLayout->setContentsMargins(0, 0, 0, 0);
Rodrigo Belem's avatar
Rodrigo Belem committed
95

96
97
98
    m_sambaStatusMessage = new QLabel(i18n("Samba must be installed before folders can be shared."));
    m_sambaStatusMessage->setAlignment(Qt::AlignCenter);
    vLayout->addWidget(m_sambaStatusMessage);
Rodrigo Belem's avatar
Rodrigo Belem committed
99

100
#ifdef SAMBA_INSTALL
101
102
103
104
105
106
107
108
109
110
111
112
113
114
    m_justInstalledSambaWidgets = new QWidget(vbox);
    vLayoutMaster->addWidget(m_justInstalledSambaWidgets);
    QVBoxLayout *vJustInstalledLayout = new QVBoxLayout(m_justInstalledSambaWidgets);
    vJustInstalledLayout->setAlignment(Qt::AlignJustify);
    vJustInstalledLayout->addWidget(new QLabel(i18n("Restart the computer to complete the installation."), m_justInstalledSambaWidgets));
    m_restartButton = new QPushButton(i18n("Restart"), m_justInstalledSambaWidgets);
    m_restartButton->setIcon(QIcon::fromTheme(QStringLiteral("system-reboot")));
    connect(m_restartButton, &QPushButton::clicked,
            this, &SambaUserSharePlugin::reboot);
    vJustInstalledLayout->addWidget(m_restartButton);
    vJustInstalledLayout->addStretch();
    m_restartButton->setDefault(false);
    m_justInstalledSambaWidgets->hide();

115
    m_installSambaButton = new QPushButton(i18n("Install Samba"), m_installSambaWidgets);
116
117
    m_installSambaButton->setDefault(false);
    vLayout->addWidget(m_installSambaButton);
Nate Graham's avatar
Nate Graham committed
118
119
    connect(m_installSambaButton, &QPushButton::clicked,
            this, &SambaUserSharePlugin::installSamba);
120
121
122
    m_installProgress = new QProgressBar();
    vLayout->addWidget(m_installProgress);
    m_installProgress->hide();
123
#endif
124

125
126
127
128
129
    // align items on top
    vLayout->addStretch();
    m_shareWidgets = new QWidget(vbox);
    vLayoutMaster->addWidget(m_shareWidgets);
    propertiesUi.setupUi(m_shareWidgets);
130

131
    QList<KSambaShareData> shareList = KSambaShare::instance()->getSharesByPath(m_url);
132
133
134
135
136
137
138
139
140

    if (!shareList.isEmpty()) {
        shareData = shareList.at(0); // FIXME: using just the first in the list for a while
    }

    setupModel();
    setupViews();
    load();

Nate Graham's avatar
Nate Graham committed
141
142
143
144
    connect(propertiesUi.sambaChk, &QCheckBox::toggled,
            this, &SambaUserSharePlugin::toggleShareStatus);
    connect(propertiesUi.sambaNameEdit, &QLineEdit::textChanged,
            this, &SambaUserSharePlugin::checkShareName);
145
146
147
148
149
    connect(propertiesUi.sambaAllowGuestChk, &QCheckBox::toggled,
            this, [=] (bool checked) {
                propertiesUi.tableView->setEnabled(checked && propertiesUi.sambaChk->isChecked());
                setDirty();
            });
Nate Graham's avatar
Nate Graham committed
150
151
    connect(model, &UserPermissionModel::dataChanged,
            this, [=] { setDirty(); });
152
153
154
155
    connect(propertiesUi.sambaStatusMonitorButton, &QPushButton::clicked,
            this, [] {
                KToolInvocation::kdeinitExec(QStringLiteral("kcmshell5"), QStringList() << QStringLiteral("smbstatus"));
            });
156
157
158
159

    for (int i = 0; i < model->rowCount(); ++i) {
        propertiesUi.tableView->openPersistentEditor(model->index(i, 1, QModelIndex()));
    }
Pino Toscano's avatar
Pino Toscano committed
160
    if (!isSambaInstalled()) {
161
162
163
164
165
166
        m_installSambaWidgets->show();
        m_shareWidgets->hide();
    } else {
        m_installSambaWidgets->hide();
        m_shareWidgets->show();
    }
167
168
169
170
171
}

SambaUserSharePlugin::~SambaUserSharePlugin()
{
}
Rodrigo Belem's avatar
Rodrigo Belem committed
172

173
#ifdef SAMBA_INSTALL
174
175
void SambaUserSharePlugin::installSamba()
{
176
    QString package = QStringLiteral(SAMBA_PACKAGE_NAME);
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
    QStringList distroSambaPackages = package.split(QLatin1Char(','));

    PackageKit::Transaction *transaction = PackageKit::Daemon::resolve(distroSambaPackages, PackageKit::Transaction::FilterArch);

    QSharedPointer<QStringList> pkgids(new QStringList);

    connect(transaction, &PackageKit::Transaction::package,
            this, [pkgids] (PackageKit::Transaction::Info /*info*/, const QString& packageId, const QString& /*summary*/) { pkgids->append(packageId); });

    connect(transaction, &PackageKit::Transaction::finished,
            this, [this, pkgids] (PackageKit::Transaction::Exit exit) {
                if (exit != PackageKit::Transaction::ExitSuccess) { return; }
                auto installTransaction = PackageKit::Daemon::installPackages(*pkgids);
                connect(installTransaction, &PackageKit::Transaction::finished,
                        this, &SambaUserSharePlugin::packageFinished);
            }
    );
194
195

    m_sambaStatusMessage->setText(i18n("Installing Samba..."));
196
197
198
199
    m_installProgress->setMaximum(0);
    m_installProgress->setMinimum(0);
    m_installProgress->show();
    m_installSambaButton->hide();
200
201
}

202
203
void SambaUserSharePlugin::packageFinished(PackageKit::Transaction::Exit status, uint runtime)
{
Jonathan Riddell's avatar
Jonathan Riddell committed
204
    Q_UNUSED(runtime);
205
206
    if (status == PackageKit::Transaction::ExitSuccess) {
        m_installSambaWidgets->hide();
207
        m_failedSambaWidgets->hide();
208
209
        m_shareWidgets->hide();
        m_justInstalledSambaWidgets->show();
210
    } else {
211
        m_shareWidgets->hide();
212
213
214
        m_installSambaWidgets->hide();
        m_failedSambaWidgets->show();
    }
Rodrigo Belem's avatar
Rodrigo Belem committed
215
}
216
217
218
219
220
221

void SambaUserSharePlugin::reboot()
{
    QDBusInterface interface(QStringLiteral("org.kde.ksmserver"), QStringLiteral("/KSMServer"), QStringLiteral("org.kde.KSMServerInterface"), QDBusConnection::sessionBus());
    interface.asyncCall(QStringLiteral("logout"), 0, 1, 2); // Options: do not ask again | reboot | force
}
222
#endif // SAMBA_INSTALL
223

224
void SambaUserSharePlugin::setupModel()
225
{
226
    model = new UserPermissionModel(shareData, this);
227
228
}

229
void SambaUserSharePlugin::setupViews()
230
{
231
232
233
    propertiesUi.tableView->setModel(model);
    propertiesUi.tableView->setSelectionMode(QAbstractItemView::NoSelection);
    propertiesUi.tableView->setItemDelegate(new UserPermissionDelegate(this));
234
    propertiesUi.tableView->horizontalHeader()->setSectionResizeMode(1, QHeaderView::Stretch);
235
236
}

237
void SambaUserSharePlugin::load()
238
{
239
    bool guestAllowed = false;
240
    bool sambaShared = KSambaShare::instance()->isDirectoryShared(m_url);
241
242
243
244
245

    propertiesUi.sambaChk->setChecked(sambaShared);
    toggleShareStatus(sambaShared);
    if (sambaShared) {
        guestAllowed = (bool) shareData.guestPermission();
Rodrigo Belem's avatar
Rodrigo Belem committed
246
    }
247
    propertiesUi.sambaAllowGuestChk->setChecked(guestAllowed);
248
249
    propertiesUi.tableView->setEnabled(propertiesUi.sambaChk->isChecked() &&
                                       propertiesUi.sambaAllowGuestChk->isChecked());
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264

    propertiesUi.sambaNameEdit->setText(shareData.name());
}

void SambaUserSharePlugin::applyChanges()
{
    KSambaShareData::UserShareError result;

    if (propertiesUi.sambaChk->isChecked()) {
        if (shareData.setAcl(model->getAcl()) != KSambaShareData::UserShareAclOk) {
            return;
        }

        shareData.setName(propertiesUi.sambaNameEdit->text());

265
        shareData.setPath(m_url);
266
267
268
269
270
271
272
273
274

        KSambaShareData::GuestPermission guestOk(shareData.guestPermission());

        guestOk = (propertiesUi.sambaAllowGuestChk->isChecked() == false)
                  ? KSambaShareData::GuestsNotAllowed : KSambaShareData::GuestsAllowed;

        shareData.setGuestPermission(guestOk);

        result = shareData.save();
275
    } else if (KSambaShare::instance()->isDirectoryShared(m_url)) {
276
277
278
279
280
281
        result = shareData.remove();
    }
}

void SambaUserSharePlugin::toggleShareStatus(bool checked)
{
Nate Graham's avatar
Nate Graham committed
282
    propertiesUi.textLabel1->setEnabled(checked);
283
284
    propertiesUi.sambaNameEdit->setEnabled(checked);
    propertiesUi.sambaAllowGuestChk->setEnabled(checked);
285
    propertiesUi.tableView->setEnabled(checked && propertiesUi.sambaAllowGuestChk->isChecked());
286
287
    if (checked && propertiesUi.sambaNameEdit->text().isEmpty()) {
        propertiesUi.sambaNameEdit->setText(getNewShareName());
288
289
    } else {
        propertiesUi.sambaNameEdit->setText(QString());
290
    }
Nate Graham's avatar
Nate Graham committed
291
    setDirty();
292
293
294
295
}

void SambaUserSharePlugin::checkShareName(const QString &name)
{
296
297
298
299
300
    // Don't ever disable the OK button when the user is trying to remove a share
    if (!propertiesUi.sambaChk->isChecked()) {
        return;
    }

301
302
303
304
305
306
307
308
309
310
311
312
313
314
    bool disableButton = false;

    if (name.isEmpty()) {
        disableButton = true;
    } else if (!KSambaShare::instance()->isShareNameAvailable(name)) {
        // There is another Share with the same name
        KMessageBox::sorry(qobject_cast<KPropertiesDialog *>(this),
                i18n("<qt>There is already a share with the name <strong>%1</strong>.<br /> Please choose another name.</qt>",
                    propertiesUi.sambaNameEdit->text()));
        propertiesUi.sambaNameEdit->selectAll();
        disableButton = true;
    }

    if (disableButton) {
315
        properties->button(QDialogButtonBox::Ok)->setEnabled(false);
316
317
318
319
        propertiesUi.sambaNameEdit->setFocus();
        return;
    }

320
321
    if (!properties->button(QDialogButtonBox::Ok)->isEnabled()) {
        properties->button(QDialogButtonBox::Ok)->setEnabled(true);
Nate Graham's avatar
Nate Graham committed
322
        setDirty();
323
324
325
    }
}

326
QString SambaUserSharePlugin::getNewShareName() const
327
{
Harald Sitter's avatar
Harald Sitter committed
328
    QString shareName = QUrl(m_url).fileName();
329
330
331
332
333
334
335
336
337

    if (!propertiesUi.sambaNameEdit->text().isEmpty()) {
        shareName = propertiesUi.sambaNameEdit->text();
    }

    // Windows could have problems with longer names
    shareName = shareName.left(12);

    return shareName;
338
339
}

Ranveer Aggarwal's avatar
Ranveer Aggarwal committed
340
#include "sambausershareplugin.moc"