File indexing completed on 2023-10-01 04:06:19
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 0011 #include "hostinfo.h" 0012 0013 #include <KIconLoader> 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 0024 typedef QList<KUriFilterPlugin *> KUriFilterPluginList; 0025 typedef QMap<QString, KUriFilterSearchProvider *> SearchProviderMap; 0026 0027 static QString 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 // Use iconPath rather than loadIcon() as the latter uses QPixmap (not threadsafe) 0044 else if (!KIconLoader::global()->iconPath(exeName, KIconLoader::NoGroup, true).isNull()) { 0045 iconName = exeName; 0046 } else 0047 // not found, use default 0048 { 0049 iconName = QStringLiteral("system-run"); 0050 } 0051 break; 0052 } 0053 case KUriFilterData::Help: { 0054 iconName = QStringLiteral("khelpcenter"); 0055 break; 0056 } 0057 case KUriFilterData::Shell: { 0058 iconName = QStringLiteral("konsole"); 0059 break; 0060 } 0061 case KUriFilterData::Error: 0062 case KUriFilterData::Blocked: { 0063 iconName = QStringLiteral("error"); 0064 break; 0065 } 0066 default: 0067 break; 0068 } 0069 0070 return iconName; 0071 } 0072 0073 class Q_DECL_HIDDEN KUriFilterSearchProvider::KUriFilterSearchProviderPrivate 0074 { 0075 public: 0076 KUriFilterSearchProviderPrivate() 0077 { 0078 } 0079 KUriFilterSearchProviderPrivate(const KUriFilterSearchProviderPrivate &other) 0080 : desktopEntryName(other.desktopEntryName) 0081 , iconName(other.iconName) 0082 , name(other.name) 0083 , keys(other.keys) 0084 { 0085 } 0086 0087 QString desktopEntryName; 0088 QString iconName; 0089 QString name; 0090 QStringList keys; 0091 }; 0092 0093 KUriFilterSearchProvider::KUriFilterSearchProvider() 0094 : d(new KUriFilterSearchProvider::KUriFilterSearchProviderPrivate) 0095 { 0096 } 0097 0098 KUriFilterSearchProvider::KUriFilterSearchProvider(const KUriFilterSearchProvider &other) 0099 : d(new KUriFilterSearchProvider::KUriFilterSearchProviderPrivate(*(other.d))) 0100 { 0101 } 0102 0103 KUriFilterSearchProvider::~KUriFilterSearchProvider() = default; 0104 0105 QString KUriFilterSearchProvider::desktopEntryName() const 0106 { 0107 return d->desktopEntryName; 0108 } 0109 0110 QString KUriFilterSearchProvider::iconName() const 0111 { 0112 return d->iconName; 0113 } 0114 0115 QString KUriFilterSearchProvider::name() const 0116 { 0117 return d->name; 0118 } 0119 0120 QStringList KUriFilterSearchProvider::keys() const 0121 { 0122 return d->keys; 0123 } 0124 0125 QString KUriFilterSearchProvider::defaultKey() const 0126 { 0127 if (d->keys.isEmpty()) { 0128 return QString(); 0129 } 0130 0131 return d->keys.first(); 0132 } 0133 0134 KUriFilterSearchProvider &KUriFilterSearchProvider::operator=(const KUriFilterSearchProvider &other) 0135 { 0136 d->desktopEntryName = other.d->desktopEntryName; 0137 d->iconName = other.d->iconName; 0138 d->keys = other.d->keys; 0139 d->name = other.d->name; 0140 return *this; 0141 } 0142 0143 void KUriFilterSearchProvider::setDesktopEntryName(const QString &desktopEntryName) 0144 { 0145 d->desktopEntryName = desktopEntryName; 0146 } 0147 0148 void KUriFilterSearchProvider::setIconName(const QString &iconName) 0149 { 0150 d->iconName = iconName; 0151 } 0152 0153 void KUriFilterSearchProvider::setName(const QString &name) 0154 { 0155 d->name = name; 0156 } 0157 0158 void KUriFilterSearchProvider::setKeys(const QStringList &keys) 0159 { 0160 d->keys = keys; 0161 } 0162 0163 class KUriFilterDataPrivate 0164 { 0165 public: 0166 explicit KUriFilterDataPrivate(const QUrl &u, const QString &typedUrl) 0167 : checkForExecs(true) 0168 , wasModified(true) 0169 , uriType(KUriFilterData::Unknown) 0170 , searchFilterOptions(KUriFilterData::SearchFilterOptionNone) 0171 , url(u.adjusted(QUrl::NormalizePathSegments)) 0172 , typedString(typedUrl) 0173 { 0174 } 0175 0176 ~KUriFilterDataPrivate() 0177 { 0178 } 0179 0180 void setData(const QUrl &u, const QString &typedUrl) 0181 { 0182 checkForExecs = true; 0183 wasModified = true; 0184 uriType = KUriFilterData::Unknown; 0185 searchFilterOptions = KUriFilterData::SearchFilterOptionNone; 0186 0187 url = u.adjusted(QUrl::NormalizePathSegments); 0188 typedString = typedUrl; 0189 0190 errMsg.clear(); 0191 iconName.clear(); 0192 absPath.clear(); 0193 args.clear(); 0194 searchTerm.clear(); 0195 searchProvider.clear(); 0196 searchTermSeparator = QChar(); 0197 alternateDefaultSearchProvider.clear(); 0198 alternateSearchProviders.clear(); 0199 searchProviderMap.clear(); 0200 defaultUrlScheme.clear(); 0201 } 0202 0203 KUriFilterDataPrivate(KUriFilterDataPrivate *data) 0204 { 0205 wasModified = data->wasModified; 0206 checkForExecs = data->checkForExecs; 0207 uriType = data->uriType; 0208 searchFilterOptions = data->searchFilterOptions; 0209 0210 url = data->url; 0211 typedString = data->typedString; 0212 0213 errMsg = data->errMsg; 0214 iconName = data->iconName; 0215 absPath = data->absPath; 0216 args = data->args; 0217 searchTerm = data->searchTerm; 0218 searchTermSeparator = data->searchTermSeparator; 0219 searchProvider = data->searchProvider; 0220 alternateDefaultSearchProvider = data->alternateDefaultSearchProvider; 0221 alternateSearchProviders = data->alternateSearchProviders; 0222 searchProviderMap = data->searchProviderMap; 0223 defaultUrlScheme = data->defaultUrlScheme; 0224 } 0225 0226 bool checkForExecs; 0227 bool wasModified; 0228 KUriFilterData::UriTypes uriType; 0229 KUriFilterData::SearchFilterOptions searchFilterOptions; 0230 0231 QUrl url; 0232 QString typedString; 0233 QString errMsg; 0234 QString iconName; 0235 QString absPath; 0236 QString args; 0237 QString searchTerm; 0238 QString searchProvider; 0239 QString alternateDefaultSearchProvider; 0240 QString defaultUrlScheme; 0241 QChar searchTermSeparator; 0242 0243 QStringList alternateSearchProviders; 0244 QStringList searchProviderList; 0245 SearchProviderMap searchProviderMap; 0246 }; 0247 0248 KUriFilterData::KUriFilterData() 0249 : d(new KUriFilterDataPrivate(QUrl(), QString())) 0250 { 0251 } 0252 0253 KUriFilterData::KUriFilterData(const QUrl &url) 0254 : d(new KUriFilterDataPrivate(url, url.toString())) 0255 { 0256 } 0257 0258 KUriFilterData::KUriFilterData(const QString &url) 0259 : d(new KUriFilterDataPrivate(QUrl::fromUserInput(url), url)) 0260 { 0261 } 0262 0263 KUriFilterData::KUriFilterData(const KUriFilterData &other) 0264 : d(new KUriFilterDataPrivate(*other.d)) 0265 { 0266 } 0267 0268 KUriFilterData::~KUriFilterData() = default; 0269 0270 QUrl KUriFilterData::uri() const 0271 { 0272 return d->url; 0273 } 0274 0275 QString KUriFilterData::errorMsg() const 0276 { 0277 return d->errMsg; 0278 } 0279 0280 KUriFilterData::UriTypes KUriFilterData::uriType() const 0281 { 0282 return d->uriType; 0283 } 0284 0285 QString KUriFilterData::absolutePath() const 0286 { 0287 return d->absPath; 0288 } 0289 0290 bool KUriFilterData::hasAbsolutePath() const 0291 { 0292 return !d->absPath.isEmpty(); 0293 } 0294 0295 QString KUriFilterData::argsAndOptions() const 0296 { 0297 return d->args; 0298 } 0299 0300 bool KUriFilterData::hasArgsAndOptions() const 0301 { 0302 return !d->args.isEmpty(); 0303 } 0304 0305 bool KUriFilterData::checkForExecutables() const 0306 { 0307 return d->checkForExecs; 0308 } 0309 0310 QString KUriFilterData::typedString() const 0311 { 0312 return d->typedString; 0313 } 0314 0315 QString KUriFilterData::searchTerm() const 0316 { 0317 return d->searchTerm; 0318 } 0319 0320 QChar KUriFilterData::searchTermSeparator() const 0321 { 0322 return d->searchTermSeparator; 0323 } 0324 0325 QString KUriFilterData::searchProvider() const 0326 { 0327 return d->searchProvider; 0328 } 0329 0330 QStringList KUriFilterData::preferredSearchProviders() const 0331 { 0332 return d->searchProviderList; 0333 } 0334 0335 KUriFilterSearchProvider KUriFilterData::queryForSearchProvider(const QString &provider) const 0336 { 0337 const KUriFilterSearchProvider *searchProvider = d->searchProviderMap.value(provider); 0338 0339 if (searchProvider) { 0340 return *(searchProvider); 0341 } 0342 0343 return KUriFilterSearchProvider(); 0344 } 0345 0346 QString KUriFilterData::queryForPreferredSearchProvider(const QString &provider) const 0347 { 0348 const KUriFilterSearchProvider *searchProvider = d->searchProviderMap.value(provider); 0349 if (searchProvider) { 0350 return (searchProvider->defaultKey() % searchTermSeparator() % searchTerm()); 0351 } 0352 return QString(); 0353 } 0354 0355 QStringList KUriFilterData::allQueriesForSearchProvider(const QString &provider) const 0356 { 0357 const KUriFilterSearchProvider *searchProvider = d->searchProviderMap.value(provider); 0358 if (searchProvider) { 0359 return searchProvider->keys(); 0360 } 0361 return QStringList(); 0362 } 0363 0364 QString KUriFilterData::iconNameForPreferredSearchProvider(const QString &provider) const 0365 { 0366 const KUriFilterSearchProvider *searchProvider = d->searchProviderMap.value(provider); 0367 if (searchProvider) { 0368 return searchProvider->iconName(); 0369 } 0370 return QString(); 0371 } 0372 0373 QStringList KUriFilterData::alternateSearchProviders() const 0374 { 0375 return d->alternateSearchProviders; 0376 } 0377 0378 QString KUriFilterData::alternateDefaultSearchProvider() const 0379 { 0380 return d->alternateDefaultSearchProvider; 0381 } 0382 0383 QString KUriFilterData::defaultUrlScheme() const 0384 { 0385 return d->defaultUrlScheme; 0386 } 0387 0388 KUriFilterData::SearchFilterOptions KUriFilterData::searchFilteringOptions() const 0389 { 0390 return d->searchFilterOptions; 0391 } 0392 0393 QString KUriFilterData::iconName() 0394 { 0395 if (d->wasModified) { 0396 d->iconName = lookupIconNameFor(d->url, d->uriType); 0397 d->wasModified = false; 0398 } 0399 0400 return d->iconName; 0401 } 0402 0403 void KUriFilterData::setData(const QUrl &url) 0404 { 0405 d->setData(url, url.toString()); 0406 } 0407 0408 void KUriFilterData::setData(const QString &url) 0409 { 0410 d->setData(QUrl(url), url); 0411 } 0412 0413 bool KUriFilterData::setAbsolutePath(const QString &absPath) 0414 { 0415 // Since a malformed URL could possibly be a relative 0416 // URL we tag it as a possible local resource... 0417 if ((d->url.scheme().isEmpty() || d->url.isLocalFile())) { 0418 d->absPath = absPath; 0419 return true; 0420 } 0421 return false; 0422 } 0423 0424 void KUriFilterData::setCheckForExecutables(bool check) 0425 { 0426 d->checkForExecs = check; 0427 } 0428 0429 void KUriFilterData::setAlternateSearchProviders(const QStringList &providers) 0430 { 0431 d->alternateSearchProviders = providers; 0432 } 0433 0434 void KUriFilterData::setAlternateDefaultSearchProvider(const QString &provider) 0435 { 0436 d->alternateDefaultSearchProvider = provider; 0437 } 0438 0439 void KUriFilterData::setDefaultUrlScheme(const QString &scheme) 0440 { 0441 d->defaultUrlScheme = scheme; 0442 } 0443 0444 void KUriFilterData::setSearchFilteringOptions(SearchFilterOptions options) 0445 { 0446 d->searchFilterOptions = options; 0447 } 0448 0449 KUriFilterData &KUriFilterData::operator=(const QUrl &url) 0450 { 0451 d->setData(url, url.toString()); 0452 return *this; 0453 } 0454 0455 KUriFilterData &KUriFilterData::operator=(const QString &url) 0456 { 0457 d->setData(QUrl(url), url); 0458 return *this; 0459 } 0460 0461 /************************* KUriFilterPlugin ******************************/ 0462 0463 KUriFilterPlugin::KUriFilterPlugin(const QString &name, QObject *parent) 0464 : QObject(parent) 0465 , d(nullptr) 0466 { 0467 setObjectName(name); 0468 } 0469 0470 // KF6 TODO 0471 // KUriFilterPlugin::~KUriFilterPlugin() 0472 //{ 0473 //} 0474 0475 KCModule *KUriFilterPlugin::configModule(QWidget *, const char *) const 0476 { 0477 return nullptr; 0478 } 0479 0480 QString KUriFilterPlugin::configName() const 0481 { 0482 return objectName(); 0483 } 0484 0485 void KUriFilterPlugin::setFilteredUri(KUriFilterData &data, const QUrl &uri) const 0486 { 0487 data.d->url = uri.adjusted(QUrl::NormalizePathSegments); 0488 data.d->wasModified = true; 0489 // qDebug() << "Got filtered to:" << uri; 0490 } 0491 0492 void KUriFilterPlugin::setErrorMsg(KUriFilterData &data, const QString &errmsg) const 0493 { 0494 data.d->errMsg = errmsg; 0495 } 0496 0497 void KUriFilterPlugin::setUriType(KUriFilterData &data, KUriFilterData::UriTypes type) const 0498 { 0499 data.d->uriType = type; 0500 data.d->wasModified = true; 0501 } 0502 0503 void KUriFilterPlugin::setArguments(KUriFilterData &data, const QString &args) const 0504 { 0505 data.d->args = args; 0506 } 0507 0508 void KUriFilterPlugin::setSearchProvider(KUriFilterData &data, const QString &provider, const QString &term, const QChar &separator) const 0509 { 0510 data.d->searchProvider = provider; 0511 data.d->searchTerm = term; 0512 data.d->searchTermSeparator = separator; 0513 } 0514 0515 void KUriFilterPlugin::setSearchProviders(KUriFilterData &data, const QList<KUriFilterSearchProvider *> &providers) const 0516 { 0517 data.d->searchProviderList.reserve(data.d->searchProviderList.size() + providers.size()); 0518 for (KUriFilterSearchProvider *searchProvider : providers) { 0519 data.d->searchProviderList << searchProvider->name(); 0520 data.d->searchProviderMap.insert(searchProvider->name(), searchProvider); 0521 } 0522 } 0523 0524 QString KUriFilterPlugin::iconNameFor(const QUrl &url, KUriFilterData::UriTypes type) const 0525 { 0526 return lookupIconNameFor(url, type); 0527 } 0528 0529 QHostInfo KUriFilterPlugin::resolveName(const QString &hostname, unsigned long timeout) const 0530 { 0531 return KIO::HostInfo::lookupHost(hostname, timeout); 0532 } 0533 0534 /******************************* KUriFilter ******************************/ 0535 0536 class KUriFilterPrivate 0537 { 0538 public: 0539 KUriFilterPrivate() 0540 { 0541 } 0542 ~KUriFilterPrivate() 0543 { 0544 qDeleteAll(pluginList); 0545 pluginList.clear(); 0546 } 0547 QVector<KUriFilterPlugin *> pluginList; 0548 }; 0549 0550 class KUriFilterSingleton 0551 { 0552 public: 0553 KUriFilter instance; 0554 }; 0555 0556 Q_GLOBAL_STATIC(KUriFilterSingleton, m_self) 0557 0558 KUriFilter *KUriFilter::self() 0559 { 0560 return &m_self()->instance; 0561 } 0562 0563 KUriFilter::KUriFilter() 0564 : d(new KUriFilterPrivate()) 0565 { 0566 loadPlugins(); 0567 } 0568 0569 KUriFilter::~KUriFilter() = default; 0570 0571 bool KUriFilter::filterUri(KUriFilterData &data, const QStringList &filters) 0572 { 0573 bool filtered = false; 0574 0575 for (KUriFilterPlugin *plugin : std::as_const(d->pluginList)) { 0576 // If no specific filters were requested, iterate through all the plugins. 0577 // Otherwise, only use available filters. 0578 if (filters.isEmpty() || filters.contains(plugin->objectName())) { 0579 if (plugin->filterUri(data)) { 0580 filtered = true; 0581 } 0582 } 0583 } 0584 0585 return filtered; 0586 } 0587 0588 bool KUriFilter::filterUri(QUrl &uri, const QStringList &filters) 0589 { 0590 KUriFilterData data(uri); 0591 bool filtered = filterUri(data, filters); 0592 if (filtered) { 0593 uri = data.uri(); 0594 } 0595 return filtered; 0596 } 0597 0598 bool KUriFilter::filterUri(QString &uri, const QStringList &filters) 0599 { 0600 KUriFilterData data(uri); 0601 bool filtered = filterUri(data, filters); 0602 if (filtered) { 0603 uri = data.uri().toString(); 0604 } 0605 return filtered; 0606 } 0607 0608 QUrl KUriFilter::filteredUri(const QUrl &uri, const QStringList &filters) 0609 { 0610 KUriFilterData data(uri); 0611 filterUri(data, filters); 0612 return data.uri(); 0613 } 0614 0615 QString KUriFilter::filteredUri(const QString &uri, const QStringList &filters) 0616 { 0617 KUriFilterData data(uri); 0618 filterUri(data, filters); 0619 return data.uri().toString(); 0620 } 0621 0622 #if KIOWIDGETS_BUILD_DEPRECATED_SINCE(4, 6) 0623 bool KUriFilter::filterSearchUri(KUriFilterData &data) 0624 { 0625 return filterSearchUri(data, (NormalTextFilter | WebShortcutFilter)); 0626 } 0627 #endif 0628 0629 bool KUriFilter::filterSearchUri(KUriFilterData &data, SearchFilterTypes types) 0630 { 0631 QStringList filters; 0632 0633 if (types & WebShortcutFilter) { 0634 filters << QStringLiteral("kurisearchfilter"); 0635 } 0636 0637 if (types & NormalTextFilter) { 0638 filters << QStringLiteral("kuriikwsfilter"); 0639 } 0640 0641 return filterUri(data, filters); 0642 } 0643 0644 QStringList KUriFilter::pluginNames() const 0645 { 0646 QStringList res; 0647 res.reserve(d->pluginList.size()); 0648 std::transform(d->pluginList.constBegin(), d->pluginList.constEnd(), std::back_inserter(res), [](const KUriFilterPlugin *plugin) { 0649 return plugin->objectName(); 0650 }); 0651 return res; 0652 } 0653 0654 void KUriFilter::loadPlugins() 0655 { 0656 QVector<KPluginMetaData> plugins = KPluginMetaData::findPlugins(QStringLiteral("kf" QT_STRINGIFY(QT_VERSION_MAJOR) "/urifilters")); 0657 const QString prefKey = QStringLiteral("X-KDE-InitialPreference"); 0658 // Sort the plugins by order of priority 0659 std::sort(plugins.begin(), plugins.end(), [prefKey](const KPluginMetaData &a, const KPluginMetaData &b) { 0660 return a.value(prefKey, 0) > b.value(prefKey, 0); 0661 }); 0662 0663 QStringList pluginNames; 0664 pluginNames.reserve(plugins.count()); 0665 0666 for (const KPluginMetaData &pluginMetaData : std::as_const(plugins)) { 0667 const QString fileName = pluginMetaData.fileName().section(QLatin1Char('/'), -1); 0668 if (!pluginNames.contains(fileName)) { 0669 pluginNames << fileName; 0670 if (auto plugin = KPluginFactory::instantiatePlugin<KUriFilterPlugin>(pluginMetaData).plugin) { 0671 d->pluginList << plugin; 0672 } 0673 } 0674 } 0675 } 0676 0677 #include "moc_kurifilter.cpp"