File indexing completed on 2024-04-28 03:55:31

0001 /*
0002     This file is part of the KDE libraries
0003     SPDX-FileCopyrightText: 2000 Yves Arrouye <yves@realnames.com>
0004     SPDX-FileCopyrightText: 2000, 2010 Dawit Alemayehu <adawit at kde.org>
0005 
0006     SPDX-License-Identifier: LGPL-2.0-or-later
0007 */
0008 
0009 #include "kurifilter.h"
0010 #include "kurifilterdata_p.h"
0011 
0012 #include "hostinfo.h"
0013 
0014 #include <KService>
0015 #include <kio/global.h>
0016 
0017 #include <KPluginFactory>
0018 #include <KPluginMetaData>
0019 
0020 #include <QHashIterator>
0021 #include <QHostAddress>
0022 #include <QHostInfo>
0023 #include <QIcon>
0024 
0025 #include "kurifilterplugin_p.h"
0026 
0027 QString KUriFilterDataPrivate::lookupIconNameFor(const QUrl &url, KUriFilterData::UriTypes type)
0028 {
0029     QString iconName;
0030 
0031     switch (type) {
0032     case KUriFilterData::NetProtocol:
0033         iconName = KIO::iconNameForUrl(url);
0034         break;
0035     case KUriFilterData::Executable: {
0036         QString exeName = url.path();
0037         exeName.remove(0, exeName.lastIndexOf(QLatin1Char('/')) + 1); // strip path if given
0038         KService::Ptr service = KService::serviceByDesktopName(exeName);
0039         if (service && service->icon() != QLatin1String("unknown")) {
0040             iconName = service->icon();
0041         }
0042         // Try to find an icon with the same name as the binary (useful for non-kde apps)
0043         else if (!QIcon::fromTheme(exeName).isNull()) {
0044             iconName = exeName;
0045         } else {
0046             // not found, use default
0047             iconName = QStringLiteral("system-run");
0048         }
0049         break;
0050     }
0051     case KUriFilterData::Help: {
0052         iconName = QStringLiteral("khelpcenter");
0053         break;
0054     }
0055     case KUriFilterData::Shell: {
0056         iconName = QStringLiteral("konsole");
0057         break;
0058     }
0059     case KUriFilterData::Error:
0060     case KUriFilterData::Blocked: {
0061         iconName = QStringLiteral("error");
0062         break;
0063     }
0064     default:
0065         break;
0066     }
0067 
0068     return iconName;
0069 }
0070 
0071 class Q_DECL_HIDDEN KUriFilterSearchProvider::KUriFilterSearchProviderPrivate
0072 {
0073 public:
0074     KUriFilterSearchProviderPrivate()
0075     {
0076     }
0077     KUriFilterSearchProviderPrivate(const KUriFilterSearchProviderPrivate &other)
0078         : desktopEntryName(other.desktopEntryName)
0079         , iconName(other.iconName)
0080         , name(other.name)
0081         , keys(other.keys)
0082     {
0083     }
0084 
0085     QString desktopEntryName;
0086     QString iconName;
0087     QString name;
0088     QStringList keys;
0089 };
0090 
0091 KUriFilterSearchProvider::KUriFilterSearchProvider()
0092     : d(new KUriFilterSearchProvider::KUriFilterSearchProviderPrivate)
0093 {
0094 }
0095 
0096 KUriFilterSearchProvider::KUriFilterSearchProvider(const KUriFilterSearchProvider &other)
0097     : d(new KUriFilterSearchProvider::KUriFilterSearchProviderPrivate(*(other.d)))
0098 {
0099 }
0100 
0101 KUriFilterSearchProvider::~KUriFilterSearchProvider() = default;
0102 
0103 QString KUriFilterSearchProvider::desktopEntryName() const
0104 {
0105     return d->desktopEntryName;
0106 }
0107 
0108 QString KUriFilterSearchProvider::iconName() const
0109 {
0110     return d->iconName;
0111 }
0112 
0113 QString KUriFilterSearchProvider::name() const
0114 {
0115     return d->name;
0116 }
0117 
0118 QStringList KUriFilterSearchProvider::keys() const
0119 {
0120     return d->keys;
0121 }
0122 
0123 QString KUriFilterSearchProvider::defaultKey() const
0124 {
0125     if (d->keys.isEmpty()) {
0126         return QString();
0127     }
0128 
0129     return d->keys.first();
0130 }
0131 
0132 KUriFilterSearchProvider &KUriFilterSearchProvider::operator=(const KUriFilterSearchProvider &other)
0133 {
0134     d->desktopEntryName = other.d->desktopEntryName;
0135     d->iconName = other.d->iconName;
0136     d->keys = other.d->keys;
0137     d->name = other.d->name;
0138     return *this;
0139 }
0140 
0141 void KUriFilterSearchProvider::setDesktopEntryName(const QString &desktopEntryName)
0142 {
0143     d->desktopEntryName = desktopEntryName;
0144 }
0145 
0146 void KUriFilterSearchProvider::setIconName(const QString &iconName)
0147 {
0148     d->iconName = iconName;
0149 }
0150 
0151 void KUriFilterSearchProvider::setName(const QString &name)
0152 {
0153     d->name = name;
0154 }
0155 
0156 void KUriFilterSearchProvider::setKeys(const QStringList &keys)
0157 {
0158     d->keys = keys;
0159 }
0160 
0161 KUriFilterData::KUriFilterData()
0162     : d(new KUriFilterDataPrivate(QUrl(), QString()))
0163 {
0164 }
0165 
0166 KUriFilterData::KUriFilterData(const QUrl &url)
0167     : d(new KUriFilterDataPrivate(url, url.toString()))
0168 {
0169 }
0170 
0171 KUriFilterData::KUriFilterData(const QString &url)
0172     : d(new KUriFilterDataPrivate(QUrl::fromUserInput(url), url))
0173 {
0174 }
0175 
0176 KUriFilterData::KUriFilterData(const KUriFilterData &other)
0177     : d(new KUriFilterDataPrivate(*other.d))
0178 {
0179 }
0180 
0181 KUriFilterData::~KUriFilterData() = default;
0182 
0183 QUrl KUriFilterData::uri() const
0184 {
0185     return d->url;
0186 }
0187 
0188 QString KUriFilterData::errorMsg() const
0189 {
0190     return d->errMsg;
0191 }
0192 
0193 KUriFilterData::UriTypes KUriFilterData::uriType() const
0194 {
0195     return d->uriType;
0196 }
0197 
0198 QString KUriFilterData::absolutePath() const
0199 {
0200     return d->absPath;
0201 }
0202 
0203 bool KUriFilterData::hasAbsolutePath() const
0204 {
0205     return !d->absPath.isEmpty();
0206 }
0207 
0208 QString KUriFilterData::argsAndOptions() const
0209 {
0210     return d->args;
0211 }
0212 
0213 bool KUriFilterData::hasArgsAndOptions() const
0214 {
0215     return !d->args.isEmpty();
0216 }
0217 
0218 bool KUriFilterData::checkForExecutables() const
0219 {
0220     return d->checkForExecs;
0221 }
0222 
0223 QString KUriFilterData::typedString() const
0224 {
0225     return d->typedString;
0226 }
0227 
0228 QString KUriFilterData::searchTerm() const
0229 {
0230     return d->searchTerm;
0231 }
0232 
0233 QChar KUriFilterData::searchTermSeparator() const
0234 {
0235     return d->searchTermSeparator;
0236 }
0237 
0238 QString KUriFilterData::searchProvider() const
0239 {
0240     return d->searchProvider;
0241 }
0242 
0243 QStringList KUriFilterData::preferredSearchProviders() const
0244 {
0245     return d->searchProviderList;
0246 }
0247 
0248 KUriFilterSearchProvider KUriFilterData::queryForSearchProvider(const QString &provider) const
0249 {
0250     const KUriFilterSearchProvider *searchProvider = d->searchProviderMap.value(provider);
0251 
0252     if (searchProvider) {
0253         return *(searchProvider);
0254     }
0255 
0256     return KUriFilterSearchProvider();
0257 }
0258 
0259 QString KUriFilterData::queryForPreferredSearchProvider(const QString &provider) const
0260 {
0261     const KUriFilterSearchProvider *searchProvider = d->searchProviderMap.value(provider);
0262     if (searchProvider) {
0263         return (searchProvider->defaultKey() % searchTermSeparator() % searchTerm());
0264     }
0265     return QString();
0266 }
0267 
0268 QStringList KUriFilterData::allQueriesForSearchProvider(const QString &provider) const
0269 {
0270     const KUriFilterSearchProvider *searchProvider = d->searchProviderMap.value(provider);
0271     if (searchProvider) {
0272         return searchProvider->keys();
0273     }
0274     return QStringList();
0275 }
0276 
0277 QString KUriFilterData::iconNameForPreferredSearchProvider(const QString &provider) const
0278 {
0279     const KUriFilterSearchProvider *searchProvider = d->searchProviderMap.value(provider);
0280     if (searchProvider) {
0281         return searchProvider->iconName();
0282     }
0283     return QString();
0284 }
0285 
0286 QStringList KUriFilterData::alternateSearchProviders() const
0287 {
0288     return d->alternateSearchProviders;
0289 }
0290 
0291 QString KUriFilterData::alternateDefaultSearchProvider() const
0292 {
0293     return d->alternateDefaultSearchProvider;
0294 }
0295 
0296 QString KUriFilterData::defaultUrlScheme() const
0297 {
0298     return d->defaultUrlScheme;
0299 }
0300 
0301 KUriFilterData::SearchFilterOptions KUriFilterData::searchFilteringOptions() const
0302 {
0303     return d->searchFilterOptions;
0304 }
0305 
0306 QString KUriFilterData::iconName()
0307 {
0308     if (d->wasModified) {
0309         d->iconName = KUriFilterDataPrivate::lookupIconNameFor(d->url, d->uriType);
0310         d->wasModified = false;
0311     }
0312 
0313     return d->iconName;
0314 }
0315 
0316 void KUriFilterData::setData(const QUrl &url)
0317 {
0318     d->setData(url, url.toString());
0319 }
0320 
0321 void KUriFilterData::setData(const QString &url)
0322 {
0323     d->setData(QUrl(url), url);
0324 }
0325 
0326 bool KUriFilterData::setAbsolutePath(const QString &absPath)
0327 {
0328     // Since a malformed URL could possibly be a relative
0329     // URL we tag it as a possible local resource...
0330     if ((d->url.scheme().isEmpty() || d->url.isLocalFile())) {
0331         d->absPath = absPath;
0332         return true;
0333     }
0334     return false;
0335 }
0336 
0337 void KUriFilterData::setCheckForExecutables(bool check)
0338 {
0339     d->checkForExecs = check;
0340 }
0341 
0342 void KUriFilterData::setAlternateSearchProviders(const QStringList &providers)
0343 {
0344     d->alternateSearchProviders = providers;
0345 }
0346 
0347 void KUriFilterData::setAlternateDefaultSearchProvider(const QString &provider)
0348 {
0349     d->alternateDefaultSearchProvider = provider;
0350 }
0351 
0352 void KUriFilterData::setDefaultUrlScheme(const QString &scheme)
0353 {
0354     d->defaultUrlScheme = scheme;
0355 }
0356 
0357 void KUriFilterData::setSearchFilteringOptions(SearchFilterOptions options)
0358 {
0359     d->searchFilterOptions = options;
0360 }
0361 
0362 KUriFilterData &KUriFilterData::operator=(const QUrl &url)
0363 {
0364     d->setData(url, url.toString());
0365     return *this;
0366 }
0367 
0368 KUriFilterData &KUriFilterData::operator=(const QString &url)
0369 {
0370     d->setData(QUrl(url), url);
0371     return *this;
0372 }
0373 
0374 /*******************************  KUriFilter ******************************/
0375 
0376 class KUriFilterPrivate
0377 {
0378 public:
0379     KUriFilterPrivate()
0380     {
0381     }
0382     ~KUriFilterPrivate()
0383     {
0384         qDeleteAll(pluginList);
0385         pluginList.clear();
0386     }
0387     QList<KUriFilterPlugin *> pluginList;
0388 };
0389 
0390 class KUriFilterSingleton
0391 {
0392 public:
0393     KUriFilter instance;
0394 };
0395 
0396 Q_GLOBAL_STATIC(KUriFilterSingleton, m_self)
0397 
0398 KUriFilter *KUriFilter::self()
0399 {
0400     return &m_self()->instance;
0401 }
0402 
0403 KUriFilter::KUriFilter()
0404     : d(new KUriFilterPrivate())
0405 {
0406     QList<KPluginMetaData> plugins = KPluginMetaData::findPlugins(QStringLiteral("kf6/urifilters"));
0407     const QString prefKey = QStringLiteral("X-KDE-InitialPreference");
0408     // Sort the plugins by order of priority
0409     std::sort(plugins.begin(), plugins.end(), [prefKey](const KPluginMetaData &a, const KPluginMetaData &b) {
0410         return a.value(prefKey, 0) > b.value(prefKey, 0);
0411     });
0412 
0413     for (const KPluginMetaData &pluginMetaData : std::as_const(plugins)) {
0414         if (auto plugin = KPluginFactory::instantiatePlugin<KUriFilterPlugin>(pluginMetaData).plugin) {
0415             d->pluginList << plugin;
0416         }
0417     }
0418 }
0419 
0420 KUriFilter::~KUriFilter() = default;
0421 
0422 bool KUriFilter::filterUri(KUriFilterData &data, const QStringList &filters)
0423 {
0424     bool filtered = false;
0425 
0426     for (KUriFilterPlugin *plugin : std::as_const(d->pluginList)) {
0427         // If no specific filters were requested, iterate through all the plugins.
0428         // Otherwise, only use available filters.
0429         if (filters.isEmpty() || filters.contains(plugin->objectName())) {
0430             if (plugin->filterUri(data)) {
0431                 filtered = true;
0432             }
0433         }
0434     }
0435 
0436     return filtered;
0437 }
0438 
0439 bool KUriFilter::filterUri(QUrl &uri, const QStringList &filters)
0440 {
0441     KUriFilterData data(uri);
0442     bool filtered = filterUri(data, filters);
0443     if (filtered) {
0444         uri = data.uri();
0445     }
0446     return filtered;
0447 }
0448 
0449 bool KUriFilter::filterUri(QString &uri, const QStringList &filters)
0450 {
0451     KUriFilterData data(uri);
0452     bool filtered = filterUri(data, filters);
0453     if (filtered) {
0454         uri = data.uri().toString();
0455     }
0456     return filtered;
0457 }
0458 
0459 QUrl KUriFilter::filteredUri(const QUrl &uri, const QStringList &filters)
0460 {
0461     KUriFilterData data(uri);
0462     filterUri(data, filters);
0463     return data.uri();
0464 }
0465 
0466 QString KUriFilter::filteredUri(const QString &uri, const QStringList &filters)
0467 {
0468     KUriFilterData data(uri);
0469     filterUri(data, filters);
0470     return data.uri().toString();
0471 }
0472 
0473 bool KUriFilter::filterSearchUri(KUriFilterData &data, SearchFilterTypes types)
0474 {
0475     QStringList filters;
0476 
0477     if (types & WebShortcutFilter) {
0478         filters << QStringLiteral("kurisearchfilter");
0479     }
0480 
0481     if (types & NormalTextFilter) {
0482         filters << QStringLiteral("kuriikwsfilter");
0483     }
0484 
0485     return filterUri(data, filters);
0486 }
0487 
0488 QStringList KUriFilter::pluginNames() const
0489 {
0490     QStringList res;
0491     res.reserve(d->pluginList.size());
0492     std::transform(d->pluginList.constBegin(), d->pluginList.constEnd(), std::back_inserter(res), [](const KUriFilterPlugin *plugin) {
0493         return plugin->objectName();
0494     });
0495     return res;
0496 }