diff --git a/src/kcms/kio/kcookiesmain.cpp b/src/kcms/kio/kcookiesmain.cpp index ef96eae9..55b94487 100644 --- a/src/kcms/kio/kcookiesmain.cpp +++ b/src/kcms/kio/kcookiesmain.cpp @@ -1,97 +1,96 @@ /* kcookiesmain.cpp - Cookies configuration * * First version of cookies configuration: * Copyright (C) Waldo Bastian * This dialog box: * Copyright (C) David Faure * */ // Own #include "kcookiesmain.h" // Local #include "kcookiespolicies.h" #include "kcookiesmanagement.h" // Qt #include -#include // KDE #include #include #include K_PLUGIN_FACTORY_DECLARATION (KioConfigFactory) KCookiesMain::KCookiesMain (QWidget* parent, const QVariantList&) : KCModule (parent) { management = nullptr; bool managerOK = true; QVBoxLayout* layout = new QVBoxLayout (this); tab = new QTabWidget (this); layout->addWidget (tab); policies = new KCookiesPolicies (this); tab->addTab (policies, i18n ("&Policy")); connect (policies, SIGNAL (changed(bool)), SIGNAL (changed(bool))); if (managerOK) { management = new KCookiesManagement (this); tab->addTab (management, i18n ("&Management")); connect (management, SIGNAL (changed(bool)), SIGNAL (changed(bool))); } } KCookiesMain::~KCookiesMain() { } void KCookiesMain::save() { policies->save(); if (management) management->save(); } void KCookiesMain::load() { policies->load(); if (management) management->load(); } void KCookiesMain::defaults() { KCModule* module = static_cast (tab->currentWidget()); if (module == policies) policies->defaults(); else if (management) management->defaults(); } QString KCookiesMain::quickHelp() const { return i18n ("

Cookies

Cookies contain information that KDE applications" " using the HTTP protocol (like Konqueror) store on your" " computer, initiated by a remote Internet server. This means that" " a web server can store information about you and your browsing activities" " on your machine for later use. You might consider this an invasion of" " privacy.

However, cookies are useful in certain situations. For example, they" " are often used by Internet shops, so you can 'put things into a shopping basket'." " Some sites require you have a browser that supports cookies.

" " Because most people want a compromise between privacy and the benefits cookies offer," " the HTTP kioslave offers you the ability to customize the way it handles cookies. So you might want" " to set the default policy to ask you whenever a server wants to set a cookie," " allowing you to decide. For your favorite shopping web sites that you trust, you might" " want to set the policy to accept, then you can access the web sites without being prompted" " every time a cookie is received.

"); } diff --git a/src/kcms/kio/kcookiespolicies.cpp b/src/kcms/kio/kcookiespolicies.cpp index 227d20f5..164edaea 100644 --- a/src/kcms/kio/kcookiespolicies.cpp +++ b/src/kcms/kio/kcookiespolicies.cpp @@ -1,457 +1,458 @@ /** * kcookiespolicies.cpp - Cookies configuration * * Original Authors * Copyright (c) Waldo Bastian * Copyright (c) 1999 David Faure * Copyright (c) 2008 Urs Wolfer * * Re-written by: * Copyright (c) 2000- Dawit Alemayehu * * 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 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ // Own #include "kcookiespolicies.h" // Local #include "ksaveioconfig.h" // Qt #include #include -#include +#include +#include // KDE #include #include #include #include #include #include // QUrl::fromAce/toAce don't accept a domain that starts with a '.', like we do here. // So we use these wrappers. QString tolerantFromAce (const QByteArray& _domain) { QByteArray domain (_domain); const bool hasDot = domain.startsWith ('.'); if (hasDot) domain.remove (0, 1); QString ret = QUrl::fromAce(domain); if (hasDot) { ret.prepend ('.'); } return ret; } static QByteArray tolerantToAce (const QString& _domain) { QString domain (_domain); const bool hasDot = domain.startsWith ('.'); if (hasDot) domain.remove (0, 1); QByteArray ret = QUrl::toAce (domain); if (hasDot) { ret.prepend ('.'); } return ret; } KCookiesPolicies::KCookiesPolicies (QWidget* parent) : KCModule (parent), mSelectedItemsCount(0) { mUi.setupUi (this); mUi.kListViewSearchLine->setTreeWidget (mUi.policyTreeWidget); QList columns; columns.append (0); mUi.kListViewSearchLine->setSearchColumns (columns); mUi.pbNew->setIcon (QIcon::fromTheme(QStringLiteral("list-add"))); mUi.pbChange->setIcon (QIcon::fromTheme(QStringLiteral("edit-rename"))); mUi.pbDelete->setIcon (QIcon::fromTheme(QStringLiteral("list-remove"))); mUi.pbDeleteAll->setIcon (QIcon::fromTheme(QStringLiteral("edit-delete"))); // Connect the main swicth :) Enable/disable cookie support connect (mUi.cbEnableCookies, SIGNAL (toggled(bool)), SLOT (cookiesEnabled(bool))); connect (mUi.cbEnableCookies, SIGNAL (toggled(bool)), SLOT (configChanged())); // Connect the preference check boxes... connect (mUi.cbRejectCrossDomainCookies, SIGNAL (toggled(bool)), SLOT (configChanged())); connect (mUi.cbAutoAcceptSessionCookies, SIGNAL (toggled(bool)), SLOT (configChanged())); connect (mUi.rbPolicyAsk, SIGNAL (toggled(bool)), SLOT (configChanged())); connect (mUi.rbPolicyAccept, SIGNAL (toggled(bool)), SLOT (configChanged())); connect (mUi.rbPolicyAcceptForSession, SIGNAL(toggled(bool)), SLOT(configChanged())); connect (mUi.rbPolicyReject, SIGNAL (toggled(bool)), SLOT (configChanged())); // Connect signals from the domain specific policy listview. connect (mUi.policyTreeWidget, SIGNAL (itemSelectionChanged()), SLOT (selectionChanged())); connect (mUi.policyTreeWidget, SIGNAL (itemDoubleClicked(QTreeWidgetItem*,int)), SLOT (changePressed())); // Connect the buttons... connect (mUi.pbNew, SIGNAL (clicked()), SLOT (addPressed())); connect (mUi.pbChange, SIGNAL (clicked()), SLOT (changePressed())); connect (mUi.pbDelete, SIGNAL (clicked()), SLOT (deletePressed())); connect (mUi.pbDeleteAll, SIGNAL (clicked()), SLOT (deleteAllPressed())); } KCookiesPolicies::~KCookiesPolicies() { } void KCookiesPolicies::configChanged () { //kDebug() << "KCookiesPolicies::configChanged..."; emit changed (true); } void KCookiesPolicies::cookiesEnabled (bool enable) { mUi.bgDefault->setEnabled (enable); mUi.bgPreferences->setEnabled (enable); mUi.gbDomainSpecific->setEnabled (enable); } void KCookiesPolicies::setPolicy (const QString& domain) { QTreeWidgetItemIterator it (mUi.policyTreeWidget); bool hasExistingPolicy = false; while (*it) { if ((*it)->text(0) == domain) { hasExistingPolicy = true; break; } ++it; } if (hasExistingPolicy) { changePressed((*it), false); } else { addPressed(domain); } } void KCookiesPolicies::changePressed() { changePressed(mUi.policyTreeWidget->currentItem()); } void KCookiesPolicies::addPressed() { addPressed(QString()); } void KCookiesPolicies::changePressed(QTreeWidgetItem* item, bool state) { Q_ASSERT(item); const QString oldDomain(item->text (0)); KCookiesPolicySelectionDlg pdlg (this); pdlg.setWindowTitle (i18nc ("@title:window", "Change Cookie Policy")); pdlg.setPolicy (KCookieAdvice::strToAdvice (mDomainPolicyMap.value(oldDomain))); pdlg.setEnableHostEdit (state, oldDomain); if (pdlg.exec() && !pdlg.domain().isEmpty()) { const QString newDomain = tolerantFromAce (pdlg.domain().toLatin1()); int advice = pdlg.advice(); if (newDomain == oldDomain || !handleDuplicate (newDomain, advice)) { mDomainPolicyMap[newDomain] = KCookieAdvice::adviceToStr(advice); item->setText(0, newDomain); item->setText(1, i18n (mDomainPolicyMap.value(newDomain))); configChanged(); } } } void KCookiesPolicies::addPressed(const QString& domain, bool state) { KCookiesPolicySelectionDlg pdlg (this); pdlg.setWindowTitle (i18nc ("@title:window", "New Cookie Policy")); pdlg.setEnableHostEdit(state, domain); if (mUi.rbPolicyAccept->isChecked()) pdlg.setPolicy (KCookieAdvice::Reject); else pdlg.setPolicy (KCookieAdvice::Accept); if (pdlg.exec() && !pdlg.domain().isEmpty()) { const QString domain = tolerantFromAce (pdlg.domain().toLatin1()); int advice = pdlg.advice(); if (!handleDuplicate (domain, advice)) { const char* strAdvice = KCookieAdvice::adviceToStr (advice); QTreeWidgetItem* item = new QTreeWidgetItem (mUi.policyTreeWidget, QStringList() << domain << i18n (strAdvice)); mDomainPolicyMap.insert (item->text(0), strAdvice); configChanged(); updateButtons(); } } } bool KCookiesPolicies::handleDuplicate (const QString& domain, int advice) { QTreeWidgetItem* item = mUi.policyTreeWidget->topLevelItem (0); while (item != nullptr) { if (item->text (0) == domain) { const int res = KMessageBox::warningContinueCancel (this, i18n ("A policy already exists for" "
%1
" "Do you want to replace it?
", domain), i18nc ("@title:window", "Duplicate Policy"), KGuiItem (i18n ("Replace"))); if (res == KMessageBox::Continue) { mDomainPolicyMap[domain] = KCookieAdvice::adviceToStr(advice); item->setText (0, domain); item->setText (1, i18n (mDomainPolicyMap.value(domain))); configChanged(); return true; } else return true; // User Cancelled!! } item = mUi.policyTreeWidget->itemBelow (item); } return false; } void KCookiesPolicies::deletePressed() { QTreeWidgetItem* nextItem = nullptr; Q_FOREACH (QTreeWidgetItem * item, mUi.policyTreeWidget->selectedItems()) { nextItem = mUi.policyTreeWidget->itemBelow (item); if (!nextItem) nextItem = mUi.policyTreeWidget->itemAbove (item); mDomainPolicyMap.remove (item->text(0)); delete item; } if (nextItem) nextItem->setSelected (true); updateButtons(); configChanged(); } void KCookiesPolicies::deleteAllPressed() { mDomainPolicyMap.clear(); mUi.policyTreeWidget->clear(); updateButtons(); configChanged(); } void KCookiesPolicies::updateButtons() { bool hasItems = mUi.policyTreeWidget->topLevelItemCount() > 0; mUi.pbChange->setEnabled((hasItems && mSelectedItemsCount == 1)); mUi.pbDelete->setEnabled((hasItems && mSelectedItemsCount > 0)); mUi.pbDeleteAll->setEnabled(hasItems); } void KCookiesPolicies::updateDomainList (const QStringList& domainConfig) { mUi.policyTreeWidget->clear(); QStringList::ConstIterator it = domainConfig.begin(); for (; it != domainConfig.end(); ++it) { QString domain; KCookieAdvice::Value advice = KCookieAdvice::Dunno; splitDomainAdvice (*it, domain, advice); if (!domain.isEmpty()) { QStringList items; items << tolerantFromAce(domain.toLatin1()) << i18n(KCookieAdvice::adviceToStr(advice)); QTreeWidgetItem* item = new QTreeWidgetItem (mUi.policyTreeWidget, items); mDomainPolicyMap[item->text(0)] = KCookieAdvice::adviceToStr(advice); } } mUi.policyTreeWidget->sortItems(0, Qt::AscendingOrder); } void KCookiesPolicies::selectionChanged () { mSelectedItemsCount = mUi.policyTreeWidget->selectedItems().count(); updateButtons (); } void KCookiesPolicies::load() { mSelectedItemsCount = 0; KConfig cfg (QStringLiteral("kcookiejarrc")); KConfigGroup group = cfg.group ("Cookie Policy"); bool enableCookies = group.readEntry ("Cookies", true); mUi.cbEnableCookies->setChecked (enableCookies); cookiesEnabled (enableCookies); // Warning: the default values are duplicated in kcookiejar.cpp KCookieAdvice::Value advice = KCookieAdvice::strToAdvice (group.readEntry ( "CookieGlobalAdvice", "Accept")); switch (advice) { case KCookieAdvice::Accept: mUi.rbPolicyAccept->setChecked (true); break; case KCookieAdvice::AcceptForSession: mUi.rbPolicyAcceptForSession->setChecked (true); break; case KCookieAdvice::Reject: mUi.rbPolicyReject->setChecked (true); break; case KCookieAdvice::Ask: case KCookieAdvice::Dunno: default: mUi.rbPolicyAsk->setChecked (true); } bool enable = group.readEntry ("RejectCrossDomainCookies", true); mUi.cbRejectCrossDomainCookies->setChecked (enable); bool sessionCookies = group.readEntry ("AcceptSessionCookies", true); mUi.cbAutoAcceptSessionCookies->setChecked (sessionCookies); updateDomainList (group.readEntry ("CookieDomainAdvice", QStringList())); if (enableCookies) { updateButtons(); } } void KCookiesPolicies::save() { KConfig cfg (QStringLiteral("kcookiejarrc")); KConfigGroup group = cfg.group ("Cookie Policy"); bool state = mUi.cbEnableCookies->isChecked(); group.writeEntry ("Cookies", state); state = mUi.cbRejectCrossDomainCookies->isChecked(); group.writeEntry ("RejectCrossDomainCookies", state); state = mUi.cbAutoAcceptSessionCookies->isChecked(); group.writeEntry ("AcceptSessionCookies", state); QString advice; if (mUi.rbPolicyAccept->isChecked()) advice = KCookieAdvice::adviceToStr (KCookieAdvice::Accept); else if (mUi.rbPolicyAcceptForSession->isChecked()) advice = KCookieAdvice::adviceToStr (KCookieAdvice::AcceptForSession); else if (mUi.rbPolicyReject->isChecked()) advice = KCookieAdvice::adviceToStr (KCookieAdvice::Reject); else advice = KCookieAdvice::adviceToStr (KCookieAdvice::Ask); group.writeEntry ("CookieGlobalAdvice", advice); QStringList domainConfig; QMapIterator it (mDomainPolicyMap); while (it.hasNext()) { it.next(); QString policy = tolerantToAce(it.key()); policy += QLatin1Char (':'); policy += QLatin1String (it.value()); domainConfig << policy; } group.writeEntry ("CookieDomainAdvice", domainConfig); group.sync(); // Update the cookiejar... if (!mUi.cbEnableCookies->isChecked()) { QDBusInterface kded (QStringLiteral("org.kde.kcookiejar5"), QStringLiteral("/modules/kcookiejar"), QStringLiteral("org.kde.KCookieServer"), QDBusConnection::sessionBus()); kded.call (QStringLiteral("shutdown")); } else { QDBusInterface kded (QStringLiteral("org.kde.kcookiejar5"), QStringLiteral("/modules/kcookiejar"), QStringLiteral("org.kde.KCookieServer"), QDBusConnection::sessionBus()); QDBusReply reply = kded.call (QStringLiteral("reloadPolicy")); if (!reply.isValid()) KMessageBox::sorry (nullptr, i18n ("Unable to communicate with the cookie handler service.\n" "Any changes you made will not take effect until the service " "is restarted.")); } // Force running io-slave to reload configurations... KSaveIOConfig::updateRunningIOSlaves (this); emit changed (false); } void KCookiesPolicies::defaults() { mUi.cbEnableCookies->setChecked (true); mUi.rbPolicyAsk->setChecked (true); mUi.rbPolicyAccept->setChecked (false); mUi.rbPolicyAcceptForSession->setChecked (false); mUi.rbPolicyReject->setChecked (false); mUi.cbRejectCrossDomainCookies->setChecked (true); mUi.cbAutoAcceptSessionCookies->setChecked (false); mUi.policyTreeWidget->clear(); mDomainPolicyMap.clear(); cookiesEnabled (mUi.cbEnableCookies->isChecked()); updateButtons(); } void KCookiesPolicies::splitDomainAdvice (const QString& cfg, QString& domain, KCookieAdvice::Value& advice) { int sepPos = cfg.lastIndexOf (':'); // Ignore any policy that does not contain a domain... if (sepPos <= 0) return; domain = cfg.left (sepPos); advice = KCookieAdvice::strToAdvice (cfg.mid (sepPos + 1)); } QString KCookiesPolicies::quickHelp() const { return i18n ("

Cookies

Cookies contain information that KDE" " application using the HTTP protocol (like Konqueror) stores" " on your computer from a remote Internet server. This means" " that a web server can store information about you and your" " browsing activities on your machine for later use. You might" " consider this an invasion of privacy.

However, cookies are" " useful in certain situations. For example, they are often used" " by Internet shops, so you can 'put things into a shopping" " basket'. Some sites require you have a browser that supports" " cookies.

Because most people want a compromise between privacy" " and the benefits cookies offer, KDE offers you the ability to" " customize the way it handles cookies. You might, for example" " want to set KDE's default policy to ask you whenever a server" " wants to set a cookie or simply reject or accept everything." " For example, you might choose to accept all cookies from your" " favorite shopping web site. For this all you have to do is" " either browse to that particular site and when you are presented" " with the cookie dialog box, click on This domain under" " the 'apply to' tab and choose accept or simply specify the name" " of the site in the Domain Specific Policy tab and set" " it to accept. This enables you to receive cookies from trusted" " web sites without being asked every time KDE receives a cookie.

" ); } diff --git a/src/kcms/kio/ksaveioconfig.cpp b/src/kcms/kio/ksaveioconfig.cpp index 305263e2..9eb29b15 100644 --- a/src/kcms/kio/ksaveioconfig.cpp +++ b/src/kcms/kio/ksaveioconfig.cpp @@ -1,239 +1,242 @@ /* Copyright (C) 2001 Dawit Alemayehu This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ // Own #include "ksaveioconfig.h" // Qt -#include +#include +#include +#include +#include // KDE #include #include #include #include #include class KSaveIOConfigPrivate { public: KSaveIOConfigPrivate (); ~KSaveIOConfigPrivate (); KConfig* config = nullptr; KConfig* http_config = nullptr; }; Q_GLOBAL_STATIC(KSaveIOConfigPrivate, d) KSaveIOConfigPrivate::KSaveIOConfigPrivate () { } KSaveIOConfigPrivate::~KSaveIOConfigPrivate () { delete config; delete http_config; } static KConfig* config() { if (!d->config) d->config = new KConfig(QStringLiteral("kioslaverc"), KConfig::NoGlobals); return d->config; } static KConfig* http_config() { if (!d->http_config) d->http_config = new KConfig(QStringLiteral("kio_httprc"), KConfig::NoGlobals); return d->http_config; } int KSaveIOConfig::proxyDisplayUrlFlags() { KConfigGroup cfg (config(), QString()); return cfg.readEntry("ProxyUrlDisplayFlags", 0); } void KSaveIOConfig::setProxyDisplayUrlFlags (int flags) { KConfigGroup cfg (config(), QString()); cfg.writeEntry("ProxyUrlDisplayFlags", flags); cfg.sync(); } void KSaveIOConfig::reparseConfiguration () { delete d->config; d->config = nullptr; delete d->http_config; d->http_config = nullptr; } void KSaveIOConfig::setReadTimeout( int _timeout ) { KConfigGroup cfg (config(), QString()); cfg.writeEntry("ReadTimeout", qMax(MIN_TIMEOUT_VALUE,_timeout)); cfg.sync(); } void KSaveIOConfig::setConnectTimeout( int _timeout ) { KConfigGroup cfg (config(), QString()); cfg.writeEntry("ConnectTimeout", qMax(MIN_TIMEOUT_VALUE,_timeout)); cfg.sync(); } void KSaveIOConfig::setProxyConnectTimeout( int _timeout ) { KConfigGroup cfg (config(), QString()); cfg.writeEntry("ProxyConnectTimeout", qMax(MIN_TIMEOUT_VALUE,_timeout)); cfg.sync(); } void KSaveIOConfig::setResponseTimeout( int _timeout ) { KConfigGroup cfg (config(), QString()); cfg.writeEntry("ResponseTimeout", qMax(MIN_TIMEOUT_VALUE,_timeout)); cfg.sync(); } void KSaveIOConfig::setMarkPartial( bool _mode ) { KConfigGroup cfg (config(), QString()); cfg.writeEntry( "MarkPartial", _mode ); cfg.sync(); } void KSaveIOConfig::setMinimumKeepSize( int _size ) { KConfigGroup cfg (config(), QString()); cfg.writeEntry( "MinimumKeepSize", _size ); cfg.sync(); } void KSaveIOConfig::setAutoResume( bool _mode ) { KConfigGroup cfg (config(), QString()); cfg.writeEntry( "AutoResume", _mode ); cfg.sync(); } void KSaveIOConfig::setUseCache( bool _mode ) { KConfigGroup cfg (http_config(), QString()); cfg.writeEntry( "UseCache", _mode ); cfg.sync(); } void KSaveIOConfig::setMaxCacheSize( int cache_size ) { KConfigGroup cfg (http_config(), QString()); cfg.writeEntry( "MaxCacheSize", cache_size ); cfg.sync(); } void KSaveIOConfig::setCacheControl(KIO::CacheControl policy) { KConfigGroup cfg (http_config(), QString()); QString tmp = KIO::getCacheControlString(policy); cfg.writeEntry("cache", tmp); cfg.sync(); } void KSaveIOConfig::setMaxCacheAge( int cache_age ) { KConfigGroup cfg (http_config(), QString()); cfg.writeEntry( "MaxCacheAge", cache_age ); cfg.sync(); } void KSaveIOConfig::setUseReverseProxy( bool mode ) { KConfigGroup cfg (config(), "Proxy Settings"); cfg.writeEntry("ReversedException", mode); cfg.sync(); } void KSaveIOConfig::setProxyType(KProtocolManager::ProxyType type) { KConfigGroup cfg (config(), "Proxy Settings"); cfg.writeEntry("ProxyType", static_cast(type)); cfg.sync(); } QString KSaveIOConfig::noProxyFor() { KConfigGroup cfg(config(), "Proxy Settings"); return cfg.readEntry("NoProxyFor"); } void KSaveIOConfig::setNoProxyFor( const QString& _noproxy ) { KConfigGroup cfg (config(), "Proxy Settings"); cfg.writeEntry("NoProxyFor", _noproxy); cfg.sync(); } void KSaveIOConfig::setProxyFor( const QString& protocol, const QString& _proxy ) { KConfigGroup cfg (config(), "Proxy Settings"); cfg.writeEntry(protocol.toLower() + "Proxy", _proxy); cfg.sync(); } void KSaveIOConfig::setProxyConfigScript( const QString& _url ) { KConfigGroup cfg (config(), "Proxy Settings"); cfg.writeEntry("Proxy Config Script", _url); cfg.sync(); } void KSaveIOConfig::updateRunningIOSlaves (QWidget *parent) { // Inform all running io-slaves about the changes... // if we cannot update, ioslaves inform the end user... QDBusMessage message = QDBusMessage::createSignal(QStringLiteral("/KIO/Scheduler"), QStringLiteral("org.kde.KIO.Scheduler"), QStringLiteral("reparseSlaveConfiguration")); message << QString(); if (!QDBusConnection::sessionBus().send(message)) { KMessageBox::information (parent, i18n("You have to restart the running applications " "for these changes to take effect."), i18nc("@title:window", "Update Failed")); } } void KSaveIOConfig::updateProxyScout(QWidget * parent) { // Inform the proxyscout kded module about changes if we cannot update, // ioslaves inform the end user... QDBusInterface kded(QStringLiteral("org.kde.kcookiejar5"), QStringLiteral("/modules/proxyscout"), QStringLiteral("org.kde.KPAC.ProxyScout")); QDBusReply reply = kded.call(QStringLiteral("reset")); if (!reply.isValid()) { KMessageBox::information (parent, i18n("You have to restart KDE for these changes to take effect."), i18nc("@title:window", "Update Failed")); } } diff --git a/src/urifilters/ikws/ikwsopts.cpp b/src/urifilters/ikws/ikwsopts.cpp index a2f41817..82c5ac50 100644 --- a/src/urifilters/ikws/ikwsopts.cpp +++ b/src/urifilters/ikws/ikwsopts.cpp @@ -1,452 +1,453 @@ /* * Copyright (c) 2000 Yves Arrouye * Copyright (c) 2001, 2002 Dawit Alemayehu * Copyright (c) 2009 Nick Shaforostoff * * 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 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "ikwsopts.h" #include "ikwsopts_p.h" #include "kuriikwsfiltereng.h" #include "searchprovider.h" #include "searchproviderdlg.h" #include #include #include #include +#include +#include #include -#include #include //BEGIN ProvidersModel ProvidersModel::~ProvidersModel() { } QVariant ProvidersModel::headerData(int section, Qt::Orientation orientation, int role ) const { Q_UNUSED(orientation); if (role == Qt::DisplayRole) { switch (section) { case Name: return i18nc("@title:column Name label from web shortcuts column", "Name"); case Shortcuts: return i18nc("@title:column", "Shortcuts"); case Preferred: return i18nc("@title:column", "Preferred"); default: break; } } return QVariant(); } Qt::ItemFlags ProvidersModel::flags(const QModelIndex& index) const { if (!index.isValid()) return Qt::ItemIsEnabled; if (index.column()==Preferred) return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable; return Qt::ItemIsEnabled | Qt::ItemIsSelectable; } bool ProvidersModel::setData (const QModelIndex& index, const QVariant& value, int role) { if (role==Qt::CheckStateRole) { if (value.toInt() == Qt::Checked) m_favoriteEngines.insert(m_providers.at(index.row())->desktopEntryName()); else m_favoriteEngines.remove(m_providers.at(index.row())->desktopEntryName()); emit dataModified(); return true; } return false; } QVariant ProvidersModel::data(const QModelIndex& index, int role) const { if (index.isValid()) { if (role == Qt::CheckStateRole && index.column()==Preferred) return (m_favoriteEngines.contains(m_providers.at(index.row())->desktopEntryName()) ? Qt::Checked : Qt::Unchecked); if (role == Qt::DisplayRole) { if (index.column()==Name) return m_providers.at(index.row())->name(); if (index.column()==Shortcuts) return m_providers.at(index.row())->keys().join(QStringLiteral(",")); } if (role == Qt::ToolTipRole || role == Qt::WhatsThisRole) { if (index.column() == Preferred) return xi18nc("@info:tooltip", "Check this box to select the highlighted web shortcut " "as preferred.Preferred web shortcuts are used in " "places where only a few select shortcuts can be shown " "at one time."); } if (role == Qt::UserRole) return index.row();//a nice way to bypass proxymodel } return QVariant(); } void ProvidersModel::setProviders(const QList& providers, const QStringList& favoriteEngines) { m_providers = providers; setFavoriteProviders(favoriteEngines); } void ProvidersModel::setFavoriteProviders(const QStringList& favoriteEngines) { beginResetModel(); m_favoriteEngines = QSet::fromList(favoriteEngines); endResetModel(); } int ProvidersModel::rowCount(const QModelIndex & parent) const { if (parent.isValid()) return 0; return m_providers.size(); } QAbstractListModel* ProvidersModel::createListModel() { ProvidersListModel* pListModel = new ProvidersListModel(m_providers, this); connect(this, SIGNAL(modelAboutToBeReset()), pListModel, SIGNAL(modelAboutToBeReset())); connect(this, SIGNAL(modelReset()), pListModel, SIGNAL(modelReset())); connect(this, SIGNAL(layoutAboutToBeChanged()), pListModel, SIGNAL(modelReset())); connect(this, SIGNAL(layoutChanged()), pListModel, SIGNAL(modelReset())); connect(this, SIGNAL(dataChanged(QModelIndex,QModelIndex)), pListModel, SLOT(emitDataChanged(QModelIndex,QModelIndex))); connect(this, SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)), pListModel, SLOT(emitRowsAboutToBeInserted(QModelIndex,int,int))); connect(this, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)), pListModel, SLOT(emitRowsAboutToBeRemoved(QModelIndex,int,int))); connect(this, SIGNAL(rowsInserted(QModelIndex,int,int)), pListModel, SLOT(emitRowsInserted(QModelIndex,int,int))); connect(this, SIGNAL(rowsRemoved(QModelIndex,int,int)), pListModel, SLOT(emitRowsRemoved(QModelIndex,int,int))); return pListModel; } void ProvidersModel::deleteProvider(SearchProvider* p) { const int row = m_providers.indexOf(p); beginRemoveRows(QModelIndex(), row, row); m_favoriteEngines.remove(m_providers.takeAt(row)->desktopEntryName()); endRemoveRows(); delete p; emit dataModified(); } void ProvidersModel::addProvider(SearchProvider* p) { beginInsertRows(QModelIndex(), m_providers.size(), m_providers.size()); m_providers.append(p); endInsertRows(); emit dataModified(); } void ProvidersModel::changeProvider(SearchProvider* p) { const int row = m_providers.indexOf(p); emit dataChanged(index(row,0),index(row,ColumnCount-1)); emit dataModified(); } QStringList ProvidersModel::favoriteEngines() const { return m_favoriteEngines.toList(); } //END ProvidersModel //BEGIN ProvidersListModel ProvidersListModel::ProvidersListModel(QList& providers, QObject* parent) : QAbstractListModel(parent) , m_providers(providers) {} QVariant ProvidersListModel::data(const QModelIndex& index, int role) const { if (index.isValid()) { if (role==Qt::DisplayRole) { if (index.row() == m_providers.size()) return i18nc("@item:inlistbox No default web shortcut", "None"); return m_providers.at(index.row())->name(); } if (role==ShortNameRole) { if (index.row() == m_providers.size()) return QString(); return m_providers.at(index.row())->desktopEntryName(); } } return QVariant(); } int ProvidersListModel::rowCount (const QModelIndex& parent) const { if (parent.isValid()) return 0; return m_providers.size() + 1; } //END ProvidersListModel static QSortFilterProxyModel* wrapInProxyModel(QAbstractItemModel* model) { QSortFilterProxyModel* proxyModel = new QSortFilterProxyModel(model); proxyModel->setSourceModel(model); proxyModel->setDynamicSortFilter(true); proxyModel->setSortCaseSensitivity(Qt::CaseInsensitive); proxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive); proxyModel->setFilterKeyColumn(-1); return proxyModel; } FilterOptions::FilterOptions(const KAboutData* about, QWidget *parent) : KCModule(about, parent), m_providersModel(new ProvidersModel(this)) { m_dlg.setupUi(this); QSortFilterProxyModel* searchProviderModel = wrapInProxyModel(m_providersModel); m_dlg.lvSearchProviders->setModel(searchProviderModel); m_dlg.cmbDefaultEngine->setModel(wrapInProxyModel(m_providersModel->createListModel())); // Connect all the signals/slots... connect(m_dlg.cbEnableShortcuts, SIGNAL(toggled(bool)), SLOT(changed())); connect(m_dlg.cbEnableShortcuts, SIGNAL(toggled(bool)), SLOT(updateSearchProviderEditingButons())); connect(m_dlg.cbUseSelectedShortcutsOnly, SIGNAL(toggled(bool)), SLOT(changed())); connect(m_providersModel, SIGNAL(dataModified()), SLOT(changed())); connect(m_dlg.cmbDefaultEngine, SIGNAL(currentIndexChanged(int)), SLOT(changed())); connect(m_dlg.cmbDelimiter, SIGNAL(currentIndexChanged(int)), SLOT(changed())); connect(m_dlg.pbNew, SIGNAL(clicked()), SLOT(addSearchProvider())); connect(m_dlg.pbDelete, SIGNAL(clicked()), SLOT(deleteSearchProvider())); connect(m_dlg.pbChange, SIGNAL(clicked()), SLOT(changeSearchProvider())); connect(m_dlg.lvSearchProviders->selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)), SLOT(updateSearchProviderEditingButons())); connect(m_dlg.lvSearchProviders, SIGNAL(doubleClicked(QModelIndex)),SLOT(changeSearchProvider())); connect(m_dlg.searchLineEdit, SIGNAL(textEdited(QString)), searchProviderModel, SLOT(setFilterFixedString(QString))); } QString FilterOptions::quickHelp() const { return xi18nc("@info:whatsthis", "In this module you can configure the web shortcuts feature. " "Web shortcuts allow you to quickly search or lookup words on " "the Internet. For example, to search for information about the " "KDE project using the Google engine, you simply type gg:KDE " "or google:KDE." "If you select a default search engine, then you can search for " "normal words or phrases by simply typing them into the input widget " "of applications that have built-in support for such a feature, e.g " "Konqueror."); } void FilterOptions::setDefaultEngine(int index) { QSortFilterProxyModel* proxy = qobject_cast(m_dlg.cmbDefaultEngine->model()); if (index == -1) index = proxy->rowCount()-1;//"None" is the last const QModelIndex modelIndex = proxy->mapFromSource(proxy->sourceModel()->index(index,0)); m_dlg.cmbDefaultEngine->setCurrentIndex(modelIndex.row()); m_dlg.cmbDefaultEngine->view()->setCurrentIndex(modelIndex); //TODO: remove this when Qt bug is fixed } void FilterOptions::load() { KConfig config(KURISearchFilterEngine::self()->name() + QStringLiteral("rc"), KConfig::NoGlobals); KConfigGroup group = config.group("General"); const QString defaultSearchEngine = group.readEntry("DefaultWebShortcut"); const QStringList favoriteEngines = group.readEntry("PreferredWebShortcuts", DEFAULT_PREFERRED_SEARCH_PROVIDERS); const QList providers = m_registry.findAll(); int defaultProviderIndex = providers.size(); //default is "None", it is last in the list for (SearchProvider *provider : providers) { if (defaultSearchEngine == provider->desktopEntryName()) defaultProviderIndex = providers.size(); } m_providersModel->setProviders(providers, favoriteEngines); m_dlg.lvSearchProviders->setColumnWidth(0,200); m_dlg.lvSearchProviders->resizeColumnToContents(1); m_dlg.lvSearchProviders->sortByColumn(0,Qt::AscendingOrder); m_dlg.cmbDefaultEngine->model()->sort(0,Qt::AscendingOrder); setDefaultEngine(defaultProviderIndex); m_dlg.cbEnableShortcuts->setChecked(group.readEntry("EnableWebShortcuts", true)); m_dlg.cbUseSelectedShortcutsOnly->setChecked(group.readEntry("UsePreferredWebShortcutsOnly", false)); const QString delimiter = group.readEntry ("KeywordDelimiter", ":"); setDelimiter(delimiter.at(0).toLatin1()); } char FilterOptions::delimiter() { const char delimiters[]={':',' '}; return delimiters[m_dlg.cmbDelimiter->currentIndex()]; } void FilterOptions::setDelimiter (char sep) { m_dlg.cmbDelimiter->setCurrentIndex(sep==' '); } void FilterOptions::save() { KConfig config(KURISearchFilterEngine::self()->name() + QStringLiteral("rc"), KConfig::NoGlobals ); KConfigGroup group = config.group("General"); group.writeEntry("EnableWebShortcuts", m_dlg.cbEnableShortcuts->isChecked()); group.writeEntry("KeywordDelimiter", QString(QLatin1Char(delimiter()))); group.writeEntry("DefaultWebShortcut", m_dlg.cmbDefaultEngine->view()->currentIndex().data(ProvidersListModel::ShortNameRole)); group.writeEntry("PreferredWebShortcuts", m_providersModel->favoriteEngines()); group.writeEntry("UsePreferredWebShortcutsOnly", m_dlg.cbUseSelectedShortcutsOnly->isChecked()); int changedProviderCount = 0; QList providers = m_providersModel->providers(); const QString path = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + "/kservices5/searchproviders/"; Q_FOREACH(SearchProvider* provider, providers) { if (!provider->isDirty()) continue; changedProviderCount++; KConfig _service(path + provider->desktopEntryName() + ".desktop", KConfig::SimpleConfig ); KConfigGroup service(&_service, "Desktop Entry"); service.writeEntry("Type", "Service"); service.writeEntry("X-KDE-ServiceTypes", "SearchProvider"); service.writeEntry("Name", provider->name()); service.writeEntry("Query", provider->query()); service.writeEntry("Keys", provider->keys()); service.writeEntry("Charset", provider->charset()); service.writeEntry("Hidden", false); // we might be overwriting a hidden entry } const QStringList servicesDirs = QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QStringLiteral("kservices5/searchproviders/"), QStandardPaths::LocateDirectory); Q_FOREACH(const QString& providerName, m_deletedProviders) { QStringList matches; foreach(const QString& dir, servicesDirs) { QString current = dir + '/' + providerName + ".desktop"; if(QFile::exists(current)) matches += current; } // Shouldn't happen if (!matches.size()) continue; changedProviderCount++; if (matches.size() == 1 && matches.first().startsWith(path)) { // If only the local copy existed, unlink it // TODO: error handling QFile::remove(matches.first()); continue; } KConfig _service(path + providerName + ".desktop", KConfig::SimpleConfig ); KConfigGroup service(&_service, "Desktop Entry"); service.writeEntry("Type", "Service"); service.writeEntry("X-KDE-ServiceTypes", "SearchProvider"); service.writeEntry("Hidden", true); } config.sync(); emit changed(false); // Update filters in running applications... QDBusMessage msg = QDBusMessage::createSignal(QStringLiteral("/"), QStringLiteral("org.kde.KUriFilterPlugin"), QStringLiteral("configure")); QDBusConnection::sessionBus().send(msg); // If the providers changed, tell sycoca to rebuild its database... if (changedProviderCount) KBuildSycocaProgressDialog::rebuildKSycoca(this); } void FilterOptions::defaults() { m_dlg.cbEnableShortcuts->setChecked(true); m_dlg.cbUseSelectedShortcutsOnly->setChecked(false); m_providersModel->setFavoriteProviders(DEFAULT_PREFERRED_SEARCH_PROVIDERS); setDelimiter(':'); setDefaultEngine(-1); } void FilterOptions::addSearchProvider() { QList providers = m_providersModel->providers(); QPointer dlg = new SearchProviderDialog(nullptr, providers, this); if (dlg->exec()) { m_providersModel->addProvider(dlg->provider()); m_providersModel->changeProvider(dlg->provider()); } delete dlg; } void FilterOptions::changeSearchProvider() { QList providers = m_providersModel->providers(); SearchProvider* provider = providers.at(m_dlg.lvSearchProviders->currentIndex().data(Qt::UserRole).toInt()); QPointer dlg = new SearchProviderDialog(provider, providers, this); if (dlg->exec()) m_providersModel->changeProvider(dlg->provider()); delete dlg; } void FilterOptions::deleteSearchProvider() { SearchProvider* provider = m_providersModel->providers().at(m_dlg.lvSearchProviders->currentIndex().data(Qt::UserRole).toInt()); m_deletedProviders.append(provider->desktopEntryName()); m_providersModel->deleteProvider(provider); } void FilterOptions::updateSearchProviderEditingButons() { const bool enable = (m_dlg.cbEnableShortcuts->isChecked() && m_dlg.lvSearchProviders->currentIndex().isValid()); m_dlg.pbChange->setEnabled(enable); m_dlg.pbDelete->setEnabled(enable); } // kate: replace-tabs 1; indent-width 2; diff --git a/src/urifilters/ikws/kuriikwsfilter.cpp b/src/urifilters/ikws/kuriikwsfilter.cpp index b897709a..504c198e 100644 --- a/src/urifilters/ikws/kuriikwsfilter.cpp +++ b/src/urifilters/ikws/kuriikwsfilter.cpp @@ -1,171 +1,172 @@ /* This file is part of the KDE project Copyright (C) 1999 Simon Hausmann Copyright (C) 2000 Yves Arrouye Copyright (C) 2002, 2003 Dawit Alemayehu 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 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kuriikwsfilter.h" #include "kuriikwsfiltereng.h" #include "searchprovider.h" #include "ikwsopts.h" #include #include -#include +#include +#include #define QL1S(x) QLatin1String(x) #define QL1C(x) QLatin1Char(x) namespace { QLoggingCategory category("org.kde.kurifilter-ikws", QtWarningMsg); } /** * IMPORTANT: If you change anything here, make sure you run the kurifiltertest * regression test (this should be included as part of "make test"). */ K_PLUGIN_FACTORY_WITH_JSON(KAutoWebSearchFactory, "kuriikwsfilter.json", registerPlugin();) KAutoWebSearch::KAutoWebSearch(QObject *parent, const QVariantList&) :KUriFilterPlugin( QStringLiteral("kuriikwsfilter"), parent ) { KLocalizedString::insertQtDomain("kurifilter"); QDBusConnection::sessionBus().connect(QString(), QStringLiteral("/"), QStringLiteral("org.kde.KUriFilterPlugin"), QStringLiteral("configure"), this, SLOT(configure())); } KAutoWebSearch::~KAutoWebSearch() { } void KAutoWebSearch::configure() { qCDebug(category) << "Config reload requested..."; KURISearchFilterEngine::self()->loadConfig(); } void KAutoWebSearch::populateProvidersList(QList& searchProviders, const KUriFilterData& data, bool allproviders) const { QList providers; KURISearchFilterEngine *filter = KURISearchFilterEngine::self(); if (allproviders) providers = filter->registry()->findAll(); else { // Start with the search engines marked as preferred... QStringList favEngines = filter->favoriteEngineList(); if (favEngines.isEmpty()) favEngines = data.alternateSearchProviders(); // Get rid of duplicates... favEngines.removeDuplicates(); // Sort the items... qStableSort(favEngines); // Add the search engine set as the default provider... const QString defaultEngine = filter->defaultSearchEngine(); if (!defaultEngine.isEmpty()) { favEngines.removeAll(defaultEngine); favEngines.insert(0, defaultEngine); } QStringListIterator it (favEngines); while (it.hasNext()) { SearchProvider *favProvider = filter->registry()->findByDesktopName(it.next()); if (favProvider) providers << favProvider; } } for (int i = 0, count = providers.count(); i < count; ++i) { searchProviders << providers[i]; } } bool KAutoWebSearch::filterUri( KUriFilterData &data ) const { qCDebug(category) << data.typedString(); KUriFilterData::SearchFilterOptions option = data.searchFilteringOptions(); // Handle the flag to retrieve only preferred providers, no filtering... if (option & KUriFilterData::RetrievePreferredSearchProvidersOnly) { QList searchProviders; populateProvidersList(searchProviders, data); if (searchProviders.isEmpty()) { if (!(option & KUriFilterData::RetrieveSearchProvidersOnly)) { setUriType(data, KUriFilterData::Error); setErrorMsg(data, i18n("No preferred search providers were found.")); return false; } } else { setSearchProvider(data, QString(), data.typedString(), QL1C(KURISearchFilterEngine::self()->keywordDelimiter())); setSearchProviders(data, searchProviders); return true; } } if (option & KUriFilterData::RetrieveSearchProvidersOnly) { QList searchProviders; populateProvidersList(searchProviders, data, true); if (searchProviders.isEmpty()) { setUriType(data, KUriFilterData::Error); setErrorMsg(data, i18n("No search providers were found.")); return false; } setSearchProvider(data, QString(), data.typedString(), QL1C(KURISearchFilterEngine::self()->keywordDelimiter())); setSearchProviders(data, searchProviders); return true; } if ( data.uriType() == KUriFilterData::Unknown && data.uri().password().isEmpty() ) { KURISearchFilterEngine *filter = KURISearchFilterEngine::self(); SearchProvider *provider = filter->autoWebSearchQuery( data.typedString(), data.alternateDefaultSearchProvider() ); if( provider ) { const QUrl result = filter->formatResult(provider->query(), provider->charset(), QString(), data.typedString(), true); setFilteredUri(data, result); setUriType( data, KUriFilterData::NetProtocol ); setSearchProvider(data, provider->name(), data.typedString(), QL1C(filter->keywordDelimiter())); QList searchProviders; populateProvidersList(searchProviders, data); setSearchProviders(data, searchProviders); return true; } } return false; } #include "kuriikwsfilter.moc" diff --git a/src/urifilters/ikws/kurisearchfilter.cpp b/src/urifilters/ikws/kurisearchfilter.cpp index f1e1776e..3b6b1319 100644 --- a/src/urifilters/ikws/kurisearchfilter.cpp +++ b/src/urifilters/ikws/kurisearchfilter.cpp @@ -1,96 +1,98 @@ /* This file is part of the KDE project Copyright (C) 1999 Simon Hausmann Copyright (C) 2000 Yves Arrouye Copyright (C) 2002, 2003 Dawit Alemayehu 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 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kurisearchfilter.h" #include "kuriikwsfiltereng.h" #include "searchprovider.h" #include "ikwsopts.h" -#include #include #include #include +#include +#include + /** * IMPORTANT: If you change anything here, make sure you run the kurifiltertest * regression test (this should be included as part of "make test"). */ K_PLUGIN_FACTORY_WITH_JSON(KUriSearchFilterFactory, "kurisearchfilter.json", registerPlugin();) namespace { QLoggingCategory category("org.kde.kurifilter-ikws", QtWarningMsg); } KUriSearchFilter::KUriSearchFilter(QObject *parent, const QVariantList &) :KUriFilterPlugin( QStringLiteral("kurisearchfilter"), parent ) { KLocalizedString::insertQtDomain("kurifilter"); QDBusConnection::sessionBus().connect(QString(), QStringLiteral("/"), QStringLiteral("org.kde.KUriFilterPlugin"), QStringLiteral("configure"), this, SLOT(configure())); } KUriSearchFilter::~KUriSearchFilter() { } void KUriSearchFilter::configure() { qCDebug(category) << "Config reload requested..."; KURISearchFilterEngine::self()->loadConfig(); } bool KUriSearchFilter::filterUri( KUriFilterData &data ) const { qCDebug(category) << data.typedString() << ":" << data.uri() << ", type =" << data.uriType(); // some URLs like gg:www.kde.org are not accepted by QUrl, but we still want them // This means we also have to allow KUriFilterData::Error if (data.uriType() != KUriFilterData::Unknown && data.uriType() != KUriFilterData::Error) { return false; } QString searchTerm; KURISearchFilterEngine *filter = KURISearchFilterEngine::self(); SearchProvider* provider(filter->webShortcutQuery(data.typedString(), searchTerm)); if (!provider) { return false; } const QUrl result = filter->formatResult(provider->query(), provider->charset(), QString(), searchTerm, true ); setFilteredUri(data, result); setUriType( data, KUriFilterData::NetProtocol ); setSearchProvider( data, provider->name(), searchTerm, QLatin1Char(filter->keywordDelimiter())); return true; } KCModule *KUriSearchFilter::configModule(QWidget *parent, const char *) const { return new FilterOptions( KAboutData::pluginData(QStringLiteral("kcmkurifilt")), parent); } QString KUriSearchFilter::configName() const { return i18n("Search F&ilters"); } #include "kurisearchfilter.moc" diff --git a/src/urifilters/shorturi/kshorturifilter.cpp b/src/urifilters/shorturi/kshorturifilter.cpp index a60088d8..7d4cf087 100644 --- a/src/urifilters/shorturi/kshorturifilter.cpp +++ b/src/urifilters/shorturi/kshorturifilter.cpp @@ -1,567 +1,568 @@ /* -*- c-basic-offset: 2 -*- kshorturifilter.h This file is part of the KDE project Copyright (C) 2000 Dawit Alemayehu Copyright (C) 2000 Malte Starostik 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 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kshorturifilter.h" #include "../../pathhelpers_p.h" #include -#include +#include +#include #include #include #include #include #include #include #include #include #include #include #include namespace { QLoggingCategory category("org.kde.kurifilter-shorturi", QtWarningMsg); } /** * IMPORTANT: If you change anything here, make sure you run the kurifiltertest * regression test (this should be included as part of "make test"). * * If you add anything, make sure to extend kurifiltertest to make sure it is * covered. */ typedef QMap EntryMap; static QRegularExpression sEnvVarExp (QStringLiteral("\\$[a-zA-Z_][a-zA-Z0-9_]*")); static bool isPotentialShortURL(const QString& cmd) { // Host names and IPv4 address... if (cmd.contains(QLatin1Char('.'))) { return true; } // IPv6 Address... if (cmd.startsWith(QLatin1Char('[')) && cmd.contains(QLatin1Char(':'))) { return true; } return false; } static QString removeArgs( const QString& _cmd ) { QString cmd( _cmd ); if( cmd[0] != '\'' && cmd[0] != '"' ) { // Remove command-line options (look for first non-escaped space) int spacePos = 0; do { spacePos = cmd.indexOf( ' ', spacePos+1 ); } while ( spacePos > 1 && cmd[spacePos - 1] == '\\' ); if( spacePos > 0 ) { cmd = cmd.left( spacePos ); qCDebug(category) << "spacePos=" << spacePos << " returning " << cmd; } } return cmd; } static bool isKnownProtocol(const QString &protocol) { if (KProtocolInfo::isKnownProtocol(protocol) || protocol == QLatin1String("mailto")) { return true; } const KService::Ptr service = KMimeTypeTrader::self()->preferredService(QLatin1String("x-scheme-handler/") + protocol); return service; } KShortUriFilter::KShortUriFilter( QObject *parent, const QVariantList & /*args*/ ) :KUriFilterPlugin( QStringLiteral("kshorturifilter"), parent ) { QDBusConnection::sessionBus().connect(QString(), QStringLiteral("/"), QStringLiteral("org.kde.KUriFilterPlugin"), QStringLiteral("configure"), this, SLOT(configure())); configure(); } bool KShortUriFilter::filterUri( KUriFilterData& data ) const { /* * Here is a description of how the shortURI deals with the supplied * data. First it expands any environment variable settings and then * deals with special shortURI cases. These special cases are the "smb:" * URL scheme which is very specific to KDE, "#" and "##" which are * shortcuts for man:/ and info:/ protocols respectively. It then handles * local files. Then it checks to see if the URL is valid and one that is * supported by KDE's IO system. If all the above checks fails, it simply * lookups the URL in the user-defined list and returns without filtering * if it is not found. TODO: the user-defined table is currently only manually * hackable and is missing a config dialog. */ //QUrl url = data.uri(); QString cmd = data.typedString(); int firstNonSlash = 0; while (firstNonSlash < cmd.length() && (cmd.at(firstNonSlash) == '/')) { firstNonSlash++; } if (firstNonSlash > 1) { cmd = cmd.mid(firstNonSlash - 1); } // Replicate what KUrl(cmd) did in KDE4. This could later be folded into the checks further down... QUrl url; if (QDir::isAbsolutePath(cmd)) { url = QUrl::fromLocalFile(cmd); } else { url.setUrl(cmd); } // WORKAROUND: Allow the use of '@' in the username component of a URL since // other browsers such as firefox in their infinite wisdom allow such blatant // violations of RFC 3986. BR# 69326/118413. if (cmd.count(QLatin1Char('@')) > 1) { const int lastIndex = cmd.lastIndexOf(QLatin1Char('@')); // Percent encode all but the last '@'. QString encodedCmd = QUrl::toPercentEncoding(cmd.left(lastIndex), ":/"); encodedCmd += cmd.midRef(lastIndex); cmd = encodedCmd; url.setUrl(encodedCmd); } const bool isMalformed = !url.isValid(); QString protocol = url.scheme(); qCDebug(category) << cmd; // Fix misparsing of "foo:80", QUrl thinks "foo" is the protocol and "80" is the path. // However, be careful not to do that for valid hostless URLs, e.g. file:///foo! if (!protocol.isEmpty() && url.host().isEmpty() && !url.path().isEmpty() && cmd.contains(':') && !isKnownProtocol(protocol)) { protocol.clear(); } qCDebug(category) << "url=" << url << "cmd=" << cmd << "isMalformed=" << isMalformed; // TODO: Make this a bit more intelligent for Minicli! There // is no need to make comparisons if the supplied data is a local // executable and only the argument part, if any, changed! (Dawit) // You mean caching the last filtering, to try and reuse it, to save stat()s? (David) const QString starthere_proto = QStringLiteral("start-here:"); if (cmd.indexOf(starthere_proto) == 0 ) { setFilteredUri( data, QUrl(QStringLiteral("system:/")) ); setUriType( data, KUriFilterData::LocalDir ); return true; } // Handle MAN & INFO pages shortcuts... const QString man_proto = QStringLiteral("man:"); const QString info_proto = QStringLiteral("info:"); if( cmd[0] == '#' || cmd.indexOf( man_proto ) == 0 || cmd.indexOf( info_proto ) == 0 ) { if( cmd.leftRef(2) == QLatin1String("##") ) cmd = QStringLiteral("info:/") + cmd.mid(2); else if ( cmd[0] == '#' ) cmd = QStringLiteral("man:/") + cmd.mid(1); else if ((cmd==info_proto) || (cmd==man_proto)) cmd+='/'; setFilteredUri( data, QUrl( cmd )); setUriType( data, KUriFilterData::Help ); return true; } // Detect UNC style (aka windows SMB) URLs if ( cmd.startsWith( QLatin1String( "\\\\") ) ) { // make sure path is unix style cmd.replace('\\', '/'); cmd.prepend( QLatin1String( "smb:" ) ); setFilteredUri( data, QUrl( cmd )); setUriType( data, KUriFilterData::NetProtocol ); return true; } bool expanded = false; // Expanding shortcut to HOME URL... QString path; QString ref; QString query; QString nameFilter; if (QDir::isRelativePath(cmd) && QUrl(cmd).isRelative()) { path = cmd; qCDebug(category) << "path=cmd=" << path; } else { if (url.isLocalFile()) { qCDebug(category) << "hasRef=" << url.hasFragment(); // Split path from ref/query // but not for "/tmp/a#b", if "a#b" is an existing file, // or for "/tmp/a?b" (#58990) if( ( url.hasFragment() || !url.query().isEmpty() ) && !url.path().endsWith(QLatin1Char('/')) ) // /tmp/?foo is a namefilter, not a query { path = url.path(); ref = url.fragment(); qCDebug(category) << "isLocalFile set path to" << path << "and ref to" << ref; query = url.query(); if (path.isEmpty() && !url.host().isEmpty()) path = '/'; } else { if (cmd.startsWith(QLatin1String("file://"))) { path = cmd.mid(strlen("file://")); } else { path = cmd; } qCDebug(category) << "(2) path=cmd=" << path; } } } if( path[0] == '~' ) { int slashPos = path.indexOf('/'); if( slashPos == -1 ) slashPos = path.length(); if( slashPos == 1 ) // ~/ { path.replace ( 0, 1, QDir::homePath() ); } else // ~username/ { const QString userName (path.mid( 1, slashPos-1 )); KUser user (userName); if( user.isValid() && !user.homeDir().isEmpty()) { path.replace (0, slashPos, user.homeDir()); } else { if (user.isValid()) { setErrorMsg(data, i18n("%1 does not have a home folder.", userName)); } else { setErrorMsg(data, i18n("There is no user called %1.", userName)); } setUriType( data, KUriFilterData::Error ); // Always return true for error conditions so // that other filters will not be invoked !! return true; } } expanded = true; } else if ( path[0] == '$' ) { // Environment variable expansion. auto match = sEnvVarExp.match(path); if ( match.hasMatch() ) { QByteArray exp = qgetenv( path.mid( 1, match.capturedLength() - 1 ).toLocal8Bit().data() ); if (!exp.isEmpty()) { path.replace( 0, match.capturedLength(), QFile::decodeName(exp) ); expanded = true; } } } if ( expanded || cmd.startsWith( '/' ) ) { // Look for #ref again, after $ and ~ expansion (testcase: $QTDIR/doc/html/functions.html#s) // Can't use QUrl here, setPath would escape it... const int pos = path.indexOf('#'); if ( pos > -1 ) { const QString newPath = path.left( pos ); if ( QFile::exists( newPath ) ) { ref = path.mid( pos + 1 ); path = newPath; qCDebug(category) << "Extracted ref: path=" << path << " ref=" << ref; } } } bool isLocalFullPath = QDir::isAbsolutePath(path); // Checking for local resource match... // Determine if "uri" is an absolute path to a local resource OR // A local resource with a supplied absolute path in KUriFilterData const QString abs_path = data.absolutePath(); const bool canBeAbsolute = (protocol.isEmpty() && !abs_path.isEmpty()); const bool canBeLocalAbsolute = (canBeAbsolute && abs_path[0] =='/' && !isMalformed); bool exists = false; /*qCDebug(category) << "abs_path=" << abs_path << "protocol=" << protocol << "canBeAbsolute=" << canBeAbsolute << "canBeLocalAbsolute=" << canBeLocalAbsolute << "isLocalFullPath=" << isLocalFullPath;*/ QT_STATBUF buff; if ( canBeLocalAbsolute ) { QString abs = QDir::cleanPath( abs_path ); // combine absolute path (abs_path) and relative path (cmd) into abs_path int len = path.length(); if( (len==1 && path[0]=='.') || (len==2 && path[0]=='.' && path[1]=='.') ) path += '/'; qCDebug(category) << "adding " << abs << " and " << path; abs = QDir::cleanPath(abs + '/' + path); qCDebug(category) << "checking whether " << abs << " exists."; // Check if it exists if(QT_STAT(QFile::encodeName(abs), &buff) == 0) { path = abs; // yes -> store as the new cmd exists = true; isLocalFullPath = true; } } if (isLocalFullPath && !exists && !isMalformed) { exists = QT_STAT(QFile::encodeName(path), &buff) == 0; if ( !exists ) { // Support for name filter (/foo/*.txt), see also KonqMainWindow::detectNameFilter // If the app using this filter doesn't support it, well, it'll simply error out itself int lastSlash = path.lastIndexOf( '/' ); if ( lastSlash > -1 && path.indexOf( ' ', lastSlash ) == -1 ) // no space after last slash, otherwise it's more likely command-line arguments { QString fileName = path.mid( lastSlash + 1 ); QString testPath = path.left(lastSlash); if ((fileName.indexOf('*') != -1 || fileName.indexOf('[') != -1 || fileName.indexOf( '?' ) != -1) && QT_STAT(QFile::encodeName(testPath), &buff) == 0) { nameFilter = fileName; qCDebug(category) << "Setting nameFilter to" << nameFilter << "and path to" << testPath; path = testPath; exists = true; } } } } qCDebug(category) << "path =" << path << " isLocalFullPath=" << isLocalFullPath << " exists=" << exists << " url=" << url; if( exists ) { QUrl u = QUrl::fromLocalFile(path); qCDebug(category) << "ref=" << ref << "query=" << query; u.setFragment(ref); u.setQuery(query); if (!KUrlAuthorized::authorizeUrlAction( QStringLiteral("open"), QUrl(), u)) { // No authorization, we pretend it's a file will get // an access denied error later on. setFilteredUri( data, u ); setUriType( data, KUriFilterData::LocalFile ); return true; } // Can be abs path to file or directory, or to executable with args bool isDir = ((buff.st_mode & QT_STAT_MASK) == QT_STAT_DIR); if( !isDir && access ( QFile::encodeName(path).data(), X_OK) == 0 ) { qCDebug(category) << "Abs path to EXECUTABLE"; setFilteredUri( data, u ); setUriType( data, KUriFilterData::Executable ); return true; } // Open "uri" as file:/xxx if it is a non-executable local resource. if( isDir || (( buff.st_mode & QT_STAT_MASK ) == QT_STAT_REG) ) { qCDebug(category) << "Abs path as local file or directory"; if ( !nameFilter.isEmpty() ) u.setPath(concatPaths(u.path(), nameFilter)); setFilteredUri( data, u ); setUriType( data, ( isDir ) ? KUriFilterData::LocalDir : KUriFilterData::LocalFile ); return true; } // Should we return LOCAL_FILE for non-regular files too? qCDebug(category) << "File found, but not a regular file nor dir... socket?"; } if( data.checkForExecutables()) { // Let us deal with possible relative URLs to see // if it is executable under the user's $PATH variable. // We try hard to avoid parsing any possible command // line arguments or options that might have been supplied. QString exe = removeArgs( cmd ); qCDebug(category) << "findExe with" << exe; if (!QStandardPaths::findExecutable( exe ).isNull() ) { qCDebug(category) << "EXECUTABLE exe=" << exe; setFilteredUri( data, QUrl::fromLocalFile( exe )); // check if we have command line arguments if( exe != cmd ) setArguments(data, cmd.right(cmd.length() - exe.length())); setUriType( data, KUriFilterData::Executable ); return true; } } // Process URLs of known and supported protocols so we don't have // to resort to the pattern matching scheme below which can possibly // slow things down... if ( !isMalformed && !isLocalFullPath && !protocol.isEmpty() ) { qCDebug(category) << "looking for protocol" << protocol; if (isKnownProtocol(protocol)) { setFilteredUri( data, url ); if ( protocol == QLatin1String("man") || protocol == QLatin1String("help") ) setUriType( data, KUriFilterData::Help ); else setUriType( data, KUriFilterData::NetProtocol ); return true; } } // Short url matches if ( !cmd.contains( ' ' ) ) { // Okay this is the code that allows users to supply custom matches for // specific URLs using Qt's regexp class. This is hard-coded for now. // TODO: Make configurable at some point... Q_FOREACH(const URLHint& hint, m_urlHints) { qCDebug(category) << "testing regexp for" << hint.prepend; if (hint.regexp.indexIn(cmd) == 0) { const QString cmdStr = hint.prepend + cmd; QUrl url(cmdStr); qCDebug(category) << "match - prepending" << hint.prepend << "->" << cmdStr << "->" << url; setFilteredUri( data, url ); setUriType( data, hint.type ); return true; } } // No protocol and not malformed means a valid short URL such as kde.org or // user@192.168.0.1. However, it might also be valid only because it lacks // the scheme component, e.g. www.kde,org (illegal ',' before 'org'). The // check below properly deciphers the difference between the two and sends // back the proper result. if (protocol.isEmpty() && isPotentialShortURL(cmd)) { QString urlStr = data.defaultUrlScheme(); if (urlStr.isEmpty()) urlStr = m_strDefaultUrlScheme; const int index = urlStr.indexOf(QLatin1Char(':')); if (index == -1 || !isKnownProtocol(urlStr.left(index))) urlStr += QStringLiteral("://"); urlStr += cmd; QUrl url (urlStr); if (url.isValid()) { setFilteredUri(data, url); setUriType(data, KUriFilterData::NetProtocol); } else if (isKnownProtocol(url.scheme())) { setFilteredUri(data, data.uri()); setUriType(data, KUriFilterData::Error); } return true; } } // If we previously determined that the URL might be a file, // and if it doesn't exist... we'll pretend it exists. // This allows to use it for completion purposes. // (If you change this logic again, look at the commit that was testing // for KUrlAuthorized::authorizeUrlAction("open")) if( isLocalFullPath && !exists ) { QUrl u = QUrl::fromLocalFile(path); u.setFragment(ref); setFilteredUri(data, u); setUriType(data, KUriFilterData::LocalFile); return true; } // If we reach this point, we cannot filter this thing so simply return false // so that other filters, if present, can take a crack at it. return false; } KCModule* KShortUriFilter::configModule( QWidget*, const char* ) const { return nullptr; //new KShortUriOptions( parent, name ); } QString KShortUriFilter::configName() const { // return i18n("&ShortURLs"); we don't have a configModule so no need for a configName that confuses translators return KUriFilterPlugin::configName(); } void KShortUriFilter::configure() { KConfig config( objectName() + QStringLiteral( "rc"), KConfig::NoGlobals ); KConfigGroup cg( config.group("") ); m_strDefaultUrlScheme = cg.readEntry( "DefaultProtocol", QStringLiteral("http://") ); const EntryMap patterns = config.entryMap( QStringLiteral("Pattern") ); const EntryMap protocols = config.entryMap( QStringLiteral("Protocol") ); KConfigGroup typeGroup(&config, "Type"); for( EntryMap::ConstIterator it = patterns.begin(); it != patterns.end(); ++it ) { QString protocol = protocols[it.key()]; if (!protocol.isEmpty()) { int type = typeGroup.readEntry(it.key(), -1); if (type > -1 && type <= KUriFilterData::Unknown) m_urlHints.append( URLHint(it.value(), protocol, static_cast(type) ) ); else m_urlHints.append( URLHint(it.value(), protocol) ); } } } K_PLUGIN_FACTORY_WITH_JSON(KShortUriFilterFactory, "kshorturifilter.json", registerPlugin();) #include "kshorturifilter.moc"