File indexing completed on 2024-05-05 17:50:47

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