File indexing completed on 2024-04-28 05:41:50

0001 /***************************************************************************
0002  *   Copyright (C) 2005-2009 by Rajko Albrecht  ral@alwins-world.de        *
0003  *   https://kde.org/applications/development/org.kde.kdesvn               *
0004  *                                                                         *
0005  *   This program is free software; you can redistribute it and/or modify  *
0006  *   it under the terms of the GNU General Public License as published by  *
0007  *   the Free Software Foundation; either version 2 of the License, or     *
0008  *   (at your option) any later version.                                   *
0009  *                                                                         *
0010  *   This program is distributed in the hope that it will be useful,       *
0011  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
0012  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
0013  *   GNU General Public License for more details.                          *
0014  *                                                                         *
0015  *   You should have received a copy of the GNU General Public License     *
0016  *   along with this program; if not, write to the                         *
0017  *   Free Software Foundation, Inc.,                                       *
0018  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.         *
0019  ***************************************************************************/
0020 
0021 #include "kdesvnd.h"
0022 #include "helpers/kdesvn_debug.h"
0023 #include "kdesvn-config.h"
0024 #include "kdesvnd_listener.h"
0025 #include "ksvnwidgets/authdialogimpl.h"
0026 #include "ksvnwidgets/commitmsg_impl.h"
0027 #include "ksvnwidgets/pwstorage.h"
0028 #include "ksvnwidgets/ssltrustprompt.h"
0029 
0030 #include "helpers/ktranslateurl.h"
0031 #include "helpers/stringhelper.h"
0032 #include "kdesvndadaptor.h"
0033 #include "ksvnjobview.h"
0034 #include "settings/kdesvnsettings.h"
0035 #include "svnqt/client.h"
0036 #include "svnqt/client_parameter.h"
0037 #include "svnqt/revision.h"
0038 #include "svnqt/status.h"
0039 #include "svnqt/svnqttypes.h"
0040 #include "svnqt/url.h"
0041 
0042 #include <KIO/Global>
0043 #include <KLocalizedString>
0044 #include <KNotification>
0045 #include <KPasswordDialog>
0046 #include <KPluginFactory>
0047 
0048 #include <QApplication>
0049 #include <QDBusConnection>
0050 #include <QFileDialog>
0051 #include <QVariant>
0052 
0053 K_PLUGIN_FACTORY_WITH_JSON(KdeSvndFactory, "kdesvnd.json", registerPlugin<kdesvnd>();)
0054 
0055 #define CHECK_KIO                                                                                                                                              \
0056     if (!progressJobView.contains(kioid)) {                                                                                                                    \
0057         return;                                                                                                                                                \
0058     }
0059 
0060 kdesvnd::kdesvnd(QObject *parent, const QList<QVariant> &)
0061     : KDEDModule(parent)
0062     , m_uiserver(QStringLiteral("org.kde.JobViewServer"), QStringLiteral("/JobViewServer"), QDBusConnection::sessionBus())
0063 {
0064     m_Listener = new KdesvndListener(this);
0065     new KdesvndAdaptor(this);
0066 }
0067 
0068 kdesvnd::~kdesvnd()
0069 {
0070     delete m_Listener;
0071 }
0072 
0073 QStringList kdesvnd::getTopLevelActionMenu(const QStringList &urlList) const
0074 {
0075     // we get correct urls here
0076     QList<QUrl> urls;
0077     urls.reserve(urlList.size());
0078     for (const QString &str : urlList) {
0079         if (str.contains(QLatin1Char('@')))
0080             urls += QUrl(str + QLatin1Char('@'));
0081         else
0082             urls += QUrl(str);
0083     }
0084 
0085     return getActionMenu(urls, true);
0086 }
0087 
0088 QStringList kdesvnd::getActionMenu(const QStringList &urlList) const
0089 {
0090     // we get correct urls here
0091     QList<QUrl> urls;
0092     urls.reserve(urlList.size());
0093     for (const QString &str : urlList) {
0094         if (str.contains(QLatin1Char('@')))
0095             urls += QUrl(str + QLatin1Char('@'));
0096         else
0097             urls += QUrl(str);
0098     }
0099     return getActionMenu(urls, false);
0100 }
0101 
0102 QStringList kdesvnd::getActionMenu(const QList<QUrl> &list, bool toplevel) const
0103 {
0104     QStringList result;
0105     Kdesvnsettings::self()->load();
0106     if (Kdesvnsettings::no_konqueror_contextmenu() || list.isEmpty() || !list.at(0).isLocalFile()
0107         || (toplevel && Kdesvnsettings::no_konqueror_toplevelmenu())) {
0108         return result;
0109     }
0110 
0111     const bool itemIsWc = isWorkingCopy(list[0]);
0112 
0113     const QUrl _dir(list.at(0).adjusted(QUrl::RemoveFilename).adjusted(QUrl::StripTrailingSlash));
0114     const bool parentIsWc = isWorkingCopy(_dir);
0115 
0116     bool itemIsRepository = false;
0117     if (!parentIsWc && !itemIsWc) {
0118         itemIsRepository = isRepository(list[0]);
0119     }
0120 
0121     if (!itemIsWc) {
0122         if (itemIsRepository) {
0123             result << QStringLiteral("Export") << QStringLiteral("Checkout");
0124         } else {
0125             result << QStringLiteral("Exportto") << QStringLiteral("Checkoutto");
0126         }
0127     } else {
0128         result << QStringLiteral("Update") << QStringLiteral("Commit");
0129     }
0130 
0131     if (!parentIsWc && !itemIsWc) {
0132         if (itemIsRepository) {
0133             result << QStringLiteral("Log");
0134             if (!toplevel) {
0135                 result << QStringLiteral("Info");
0136                 const QUrl upUrl = KIO::upUrl(list.at(0));
0137                 if (isRepository(upUrl)) {
0138                     result << QStringLiteral("Blame") << QStringLiteral("Rename");
0139                 }
0140                 result << QStringLiteral("Tree");
0141             }
0142         }
0143     } else if (!toplevel) {
0144         if (!itemIsWc) {
0145             result << QStringLiteral("Add");
0146             return result;
0147         }
0148 
0149         result << QStringLiteral("Log") << QStringLiteral("Tree") << QStringLiteral("Info") << QStringLiteral("Diff") << QStringLiteral("Rename")
0150                << QStringLiteral("Revert");
0151 
0152         const QUrl url = list.at(0);
0153         QFileInfo f(url.path());
0154         if (f.isFile()) {
0155             result << QStringLiteral("Blame");
0156         }
0157 
0158         if (f.isDir()) {
0159             result << QStringLiteral("Addnew");
0160             result << QStringLiteral("Switch");
0161         }
0162     }
0163     return result;
0164 }
0165 
0166 QStringList kdesvnd::getSingleActionMenu(const QString &what) const
0167 {
0168     QList<QUrl> l;
0169     l.append(QUrl(what.contains(QLatin1Char('@')) ? what + QLatin1Char('@') : what));
0170     return getActionMenu(l, false);
0171 }
0172 
0173 QStringList kdesvnd::get_saved_login(const QString &realm, const QString &user) const
0174 {
0175     Q_UNUSED(user);
0176     QString username;
0177     QString password;
0178     PwStorage::self()->getLogin(realm, username, password);
0179     QStringList res;
0180     res.append(username);
0181     res.append(password);
0182     return res;
0183 }
0184 
0185 QStringList kdesvnd::get_login(const QString &realm, const QString &user) const
0186 {
0187     QPointer<AuthDialogImpl> auth(new AuthDialogImpl(realm, user));
0188     QStringList res;
0189     if (auth->exec() == QDialog::Accepted) {
0190         res.append(auth->Username());
0191         res.append(auth->Password());
0192         if (auth->maySave()) {
0193             res.append(QStringLiteral("true"));
0194         } else {
0195             res.append(QStringLiteral("false"));
0196         }
0197     }
0198     delete auth;
0199     return res;
0200 }
0201 
0202 int kdesvnd::get_sslaccept(const QString &hostname,
0203                            const QString &fingerprint,
0204                            const QString &validFrom,
0205                            const QString &validUntil,
0206                            const QString &issuerDName,
0207                            const QString &realm) const
0208 {
0209     bool ok, saveit;
0210     if (!SslTrustPrompt::sslTrust(hostname, fingerprint, validFrom, validUntil, issuerDName, realm, QStringList(), &ok, &saveit)) {
0211         return -1;
0212     }
0213     if (!saveit) {
0214         return 0;
0215     }
0216     return 1;
0217 }
0218 
0219 QString kdesvnd::load_sslclientcertpw(const QString &realm) const
0220 {
0221     QString password;
0222     if (!PwStorage::self()->getCertPw(realm, password)) {
0223         return QString();
0224     }
0225     return password;
0226 }
0227 
0228 QStringList kdesvnd::get_sslclientcertpw(const QString &realm) const
0229 {
0230     QStringList resList;
0231     QPointer<KPasswordDialog> dlg(new KPasswordDialog(nullptr, KPasswordDialog::DomainReadOnly | KPasswordDialog::ShowKeepPassword));
0232     dlg->setDomain(realm);
0233     dlg->setWindowTitle(i18nc("@title:window", "Enter Password for Realm %1", realm));
0234     dlg->setKeepPassword(true);
0235     if (dlg->exec() == KPasswordDialog::Accepted) {
0236         resList.append(dlg->password());
0237         if (dlg->keepPassword()) {
0238             resList.append(QStringLiteral("true"));
0239         } else {
0240             resList.append(QStringLiteral("false"));
0241         }
0242     }
0243     delete dlg;
0244     return resList;
0245 }
0246 
0247 QString kdesvnd::get_sslclientcertfile() const
0248 {
0249     return QFileDialog::getOpenFileName(nullptr, i18n("Open a file with a #PKCS12 certificate"));
0250 }
0251 
0252 QStringList kdesvnd::get_logmsg() const
0253 {
0254     QStringList res;
0255     bool ok;
0256     QString logMessage = Commitmsg_impl::getLogmessage(&ok, nullptr, nullptr, nullptr);
0257     if (ok) {
0258         res.append(logMessage);
0259     }
0260     return res;
0261 }
0262 
0263 QString kdesvnd::cleanUrl(const QUrl &url)
0264 {
0265     return url.adjusted(QUrl::StripTrailingSlash | QUrl::NormalizePathSegments).path();
0266 }
0267 
0268 /* just simple name check of course - no network access! */
0269 bool kdesvnd::isRepository(const QUrl &url) const
0270 {
0271     QString proto = svn::Url::transformProtokoll(url.scheme());
0272     if (proto == QLatin1String("file")) {
0273         // local access - may a repository
0274         svn::StatusParameter params(svn::Path(QLatin1String("file://") + cleanUrl(url)));
0275         try {
0276             m_Listener->m_Svnclient->status(params.depth(svn::DepthEmpty).all(false).update(false).noIgnore(false).revision(svn::Revision::HEAD));
0277         } catch (const svn::ClientException &e) {
0278             qCDebug(KDESVN_LOG) << e.msg() << Qt::endl;
0279             return false;
0280         }
0281         return true;
0282     }
0283     return svn::Url::isValid(proto);
0284 }
0285 
0286 bool kdesvnd::isWorkingCopy(const QUrl &url) const
0287 {
0288     if (url.isEmpty() || !url.isLocalFile() || url.scheme() != QLatin1String("file") || url.path() == QLatin1String("/")) {
0289         return false;
0290     }
0291     svn::Revision peg(svn_opt_revision_unspecified);
0292     svn::Revision rev(svn_opt_revision_unspecified);
0293     svn::InfoEntries e;
0294     try {
0295         e = m_Listener->m_Svnclient->info(cleanUrl(url), svn::DepthEmpty, rev, peg);
0296     } catch (const svn::ClientException &e) {
0297         return false;
0298     }
0299     return true;
0300 }
0301 
0302 bool kdesvnd::canceldKioOperation(qulonglong kioid)
0303 {
0304     if (!progressJobView.contains(kioid)) {
0305         return false;
0306     }
0307     return progressJobView[kioid]->state() == KsvnJobView::CANCELD;
0308 }
0309 
0310 void kdesvnd::maxTransferKioOperation(qulonglong kioid, qulonglong maxtransfer)
0311 {
0312     CHECK_KIO;
0313     progressJobView[kioid]->setState(KsvnJobView::RUNNING);
0314     progressJobView[kioid]->setTotal(maxtransfer);
0315 }
0316 
0317 void kdesvnd::registerKioFeedback(qulonglong kioid)
0318 {
0319     if (progressJobView.contains(kioid)) {
0320         return;
0321     }
0322     QDBusReply<QDBusObjectPath> reply = m_uiserver.requestView(qApp->applicationName(), qApp->applicationName(), 0x0003);
0323     if (reply.isValid()) {
0324         KsvnJobView *jobView = new KsvnJobView(kioid, QStringLiteral("org.kde.JobViewServer"), reply.value().path(), QDBusConnection::sessionBus());
0325         progressJobView.insert(kioid, jobView);
0326         qCDebug(KDESVN_LOG) << "Register " << kioid << Qt::endl;
0327     } else {
0328         qCDebug(KDESVN_LOG) << "Could not register " << kioid << Qt::endl;
0329     }
0330 }
0331 
0332 void kdesvnd::titleKioOperation(qulonglong kioid, const QString &title, const QString &label)
0333 {
0334     CHECK_KIO;
0335     progressJobView[kioid]->setInfoMessage(title);
0336     progressJobView[kioid]->setDescriptionField(0, i18n("Current task"), label);
0337 }
0338 
0339 void kdesvnd::transferredKioOperation(qulonglong kioid, qulonglong transferred)
0340 {
0341     CHECK_KIO;
0342     if (progressJobView[kioid]->max() > -1) {
0343         progressJobView[kioid]->setProcessedAmount(transferred, QStringLiteral("bytes"));
0344         progressJobView[kioid]->setPercent(progressJobView[kioid]->percent(transferred));
0345         progressJobView[kioid]->clearDescriptionField(1);
0346     } else {
0347         progressJobView[kioid]->setPercent(100.0);
0348         progressJobView[kioid]->setDescriptionField(1, i18n("Current transfer"), helpers::ByteToString(transferred));
0349     }
0350 }
0351 
0352 void kdesvnd::unRegisterKioFeedback(qulonglong kioid)
0353 {
0354     CHECK_KIO;
0355     KsvnJobView *jobView = progressJobView.take(kioid);
0356     delete jobView;
0357     qCDebug(KDESVN_LOG) << "Removed " << kioid << Qt::endl;
0358 }
0359 
0360 void kdesvnd::notifyKioOperation(const QString &text)
0361 {
0362     KNotification::event(QLatin1String("kdesvn-kio"), text, QPixmap(), nullptr, KNotification::CloseOnTimeout, QLatin1String("kdesvn"));
0363 }
0364 
0365 void kdesvnd::errorKioOperation(const QString &text)
0366 {
0367     KNotification::event(KNotification::Error, text, QPixmap(), nullptr, KNotification::CloseOnTimeout);
0368 }
0369 
0370 void kdesvnd::setKioStatus(qulonglong kioid, int status, const QString &message)
0371 {
0372     CHECK_KIO;
0373     switch (status) {
0374     case 0:
0375         progressJobView[kioid]->setState(KsvnJobView::STOPPED);
0376         progressJobView[kioid]->terminate(message);
0377         break;
0378     case 2:
0379         progressJobView[kioid]->setState(KsvnJobView::CANCELD);
0380         progressJobView[kioid]->terminate(message);
0381         break;
0382     case 1:
0383         progressJobView[kioid]->setState(KsvnJobView::RUNNING);
0384         progressJobView[kioid]->setSuspended(false);
0385         break;
0386     }
0387 }
0388 
0389 #include "kdesvnd.moc"
0390 
0391 #include "moc_kdesvnd.cpp"