• Skip to content
  • Skip to link menu
KDE 4.6 API Reference
  • KDE API Reference
  • kdelibs
  • KDE Home
  • Contact Us
 

KDEWebKit

kwebwallet.cpp

Go to the documentation of this file.
00001 /*
00002  * This file is part of the KDE project.
00003  *
00004  * Copyright (C) 2009 Dawit Alemayehu <adawit@kde.org>
00005  *
00006  * This library is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU Library General Public
00008  * License as published by the Free Software Foundation; either
00009  * version 2 of the License, or (at your option) any later version.
00010  *
00011  * This library is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014  * Library General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU Library General Public License
00017  * along with this library; see the file COPYING.LIB.  If not, write to
00018  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00019  * Boston, MA 02110-1301, USA.
00020  *
00021  */
00022 
00023 #include "kwebwallet.h"
00024 
00025 #include <kwallet.h>
00026 #include <kdebug.h>
00027 
00028 #include <QtCore/QSet>
00029 #include <QtCore/QHash>
00030 #include <QtCore/QFile>
00031 #include <QtCore/QPointer>
00032 #include <QtWebKit/QWebPage>
00033 #include <QtWebKit/QWebFrame>
00034 #include <QtWebKit/QWebElement>
00035 #include <QtWebKit/QWebElementCollection>
00036 #include <qwindowdefs.h>
00037 
00038 #define QL1S(x)   QLatin1String(x)
00039 #define QL1C(x)   QLatin1Char(x)
00040 
00045 static QString walletKey(KWebWallet::WebForm form)
00046 {
00047     QString key = form.url.toString(QUrl::RemoveQuery|QUrl::RemoveFragment);
00048     key += QL1C('#');
00049     key += form.name;
00050 
00051     return key;
00052 }
00053 
00054 static int getWebFields(const QWebElement &formElement,
00055                         const QString& selector, QList<KWebWallet::WebForm::WebField> &fields)
00056 {
00057     QWebElementCollection collection = formElement.findAll(selector);
00058     const int count = collection.count();
00059 
00060     for(int i = 0; i < count; ++i) {
00061         QWebElement element = collection.at(i);
00062         const QString value = element.evaluateJavaScript(QL1S("this.value")).toString();
00063         if (!value.isEmpty())
00064             fields << qMakePair(element.attribute(QL1S("name")), value);
00065     }
00066 
00067     return fields.count();
00068 }
00069 
00070 static bool isValidInputElement(const QWebElement& element)
00071 {
00072     return (!element.isNull() &&
00073             !element.hasAttribute(QL1S("readonly")) &&
00074             !element.hasAttribute(QL1S("disabled")));
00075 }
00076 
00077 static void collectAllChildFrames(QWebFrame* frame, QList<QWebFrame*>& list)
00078 {
00079     list << frame->childFrames();
00080     QListIterator<QWebFrame*> it(frame->childFrames());
00081     while (it.hasNext()) {
00082         collectAllChildFrames(it.next(), list);
00083     }
00084 }
00085 
00086 
00087 class KWebWallet::KWebWalletPrivate
00088 {
00089 public:
00090     struct FormsData
00091     {
00092         QPointer<QWebFrame> frame;
00093         KWebWallet::WebFormList forms;
00094     };
00095 
00096     KWebWalletPrivate(KWebWallet* parent);
00097     KWebWallet::WebFormList parseFormData(QWebFrame* frame, bool fillform = true, bool ignorepasswd = false);
00098     void fillDataFromCache(KWebWallet::WebFormList &formList);
00099     void saveDataToCache(const QString &key);
00100     void removeDataFromCache(const WebFormList &formList);
00101 
00102     // Private slots...
00103     void _k_openWalletDone(bool);
00104     void _k_walletClosed();
00105 
00106     WId wid;
00107     KWebWallet *q;
00108     QPointer<KWallet::Wallet> wallet;
00109     KWebWallet::WebFormList pendingRemoveRequests;
00110     QHash<KUrl, FormsData> pendingFillRequests;
00111     QHash<QString, KWebWallet::WebFormList> pendingSaveRequests;
00112     QSet<KUrl> confirmSaveRequestOverwrites;
00113 };
00114 
00115 KWebWallet::KWebWalletPrivate::KWebWalletPrivate(KWebWallet *parent)
00116                               :wid (0), q(parent)
00117 {
00118 }
00119 
00120 KWebWallet::WebFormList KWebWallet::KWebWalletPrivate::parseFormData(QWebFrame *frame, bool fillform, bool ignorepasswd)
00121 {
00122     Q_ASSERT(frame);
00123 
00124     KWebWallet::WebFormList list;
00125     QWebElementCollection formElements = frame->findAllElements(QL1S("form[method=post]"));
00126     const int formElementCount = formElements.count();
00127 
00128     if (fillform) {
00129         for ( int i = 0; i < formElementCount; ++i ) {
00130             const QWebElement formElement = formElements.at(i);
00131 
00132             KWebWallet::WebForm form;
00133             form.url = frame->url();
00134             form.index = QString::number(i);
00135             form.name = formElement.attribute(QL1S("name"));
00136             if (q->hasCachedFormData(form))
00137                 list << form;
00138         }
00139     } else {
00140         int numPasswdFields = 0;
00141         QString passwdSelector;
00142 
00143         if (!ignorepasswd)
00144             passwdSelector = QL1S("input[type=password]:not([autocomplete=off])");
00145 
00146         for (int i = 0; i < formElementCount; ++i) {
00147             const QWebElement formElement = formElements.at(i);
00148 
00149             KWebWallet::WebForm form;
00150             form.url = frame->url();
00151             form.index = QString::number(i);
00152             form.name = formElement.attribute(QL1S("name"));
00153 
00154             // Get all <input> elements of type 'password'
00155             numPasswdFields = getWebFields(formElement, passwdSelector, form.fields);
00156 
00157             // Get all <input> elements of type 'text'
00158             getWebFields(formElement, QL1S("input[type=text]:not([autocomplete=off]), input:not([type])"), form.fields);
00159 
00160             // Add the form the list if it contains a password field...
00161             if ((ignorepasswd || numPasswdFields == 1) && !form.fields.isEmpty())
00162                 list << form;
00163         }
00164     }
00165 
00166     return list;
00167 }
00168 
00169 void KWebWallet::KWebWalletPrivate::fillDataFromCache(KWebWallet::WebFormList &formList)
00170 {
00171     if (wallet) {
00172         QMap<QString, QString> cachedValues;
00173         QMutableListIterator <WebForm> formIt (formList);
00174 
00175         while (formIt.hasNext()) {
00176             KWebWallet::WebForm &form = formIt.next();
00177             const QString key (walletKey(form));
00178             if (wallet->readMap(key, cachedValues) == 0) {
00179                 QMapIterator<QString, QString> valuesIt (cachedValues);
00180                 while (valuesIt.hasNext()) {
00181                     valuesIt.next();
00182                     //kDebug(800) << "wallet key:" << key << valuesIt.key() << valuesIt.value();
00183                     form.fields << qMakePair(valuesIt.key(), valuesIt.value());
00184                 }
00185             } else {
00186                   kWarning(800) << "Unable to read form data for key:" << key;
00187             }
00188         }
00189     } else {
00190         kWarning(800) << "Unable to retreive form data from wallet";
00191     }
00192 }
00193 
00194 void KWebWallet::KWebWalletPrivate::saveDataToCache(const QString &key)
00195 {
00196     bool success = false;
00197     const QUrl url = pendingSaveRequests.value(key).first().url;
00198 
00199     if (wallet) {
00200         int count = 0;
00201         const KWebWallet::WebFormList list = pendingSaveRequests.value(key);
00202         QListIterator<KWebWallet::WebForm> formIt (list);
00203 
00204         while (formIt.hasNext()) {
00205             QMap<QString, QString> values, storedValues;
00206             const KWebWallet::WebForm form = formIt.next();
00207             const QString accessKey = walletKey(form);
00208             if (confirmSaveRequestOverwrites.contains(url)) {
00209                 confirmSaveRequestOverwrites.remove(url);
00210                 const int status = wallet->readMap(accessKey, storedValues);
00211                 if (status == 0 && storedValues.count()) {
00212                     QListIterator<KWebWallet::WebForm::WebField> fieldIt (form.fields);
00213                     while (fieldIt.hasNext()) {
00214                         const KWebWallet::WebForm::WebField field = fieldIt.next();
00215                         if (storedValues.contains(field.first) &&
00216                             storedValues.value(field.first) != field.second) {
00217                             emit q->saveFormDataRequested(key, url);
00218                             return;
00219                         }
00220                     }
00221                     // If we got here it means the new credential is exactly
00222                     // the same as the one already cached ; so skip the
00223                     // re-saving part...
00224                     success = true;
00225                     continue;
00226                 }
00227             }
00228             QListIterator<KWebWallet::WebForm::WebField> fieldIt (form.fields);
00229             while (fieldIt.hasNext()) {
00230                 const KWebWallet::WebForm::WebField field = fieldIt.next();
00231                 values.insert(field.first, field.second);
00232             }
00233 
00234             if (wallet->writeMap(accessKey, values) == 0)
00235                 count++;
00236             else
00237                 kWarning(800) << "Unable to write form data to wallet";
00238         }
00239 
00240         if (list.isEmpty() || count > 0)
00241           success = true;
00242 
00243         pendingSaveRequests.remove(key);
00244     } else {
00245         kWarning(800) << "NULL KWallet instance!";
00246     }
00247 
00248     emit q->saveFormDataCompleted(url, success);
00249 }
00250 
00251 void KWebWallet::KWebWalletPrivate::removeDataFromCache(const WebFormList &formList)
00252 {
00253     if (wallet) {
00254         QListIterator<WebForm> formIt (formList);
00255         while (formIt.hasNext()) {
00256             wallet->removeEntry(walletKey(formIt.next()));
00257         }
00258     } else {
00259         kWarning(800) << "NULL KWallet instance!";
00260     }
00261 }
00262 
00263 void KWebWallet::KWebWalletPrivate::_k_openWalletDone(bool ok)
00264 {
00265     Q_ASSERT (wallet);
00266 
00267     if (ok &&
00268         (wallet->hasFolder(KWallet::Wallet::FormDataFolder()) ||
00269          wallet->createFolder(KWallet::Wallet::FormDataFolder())) &&
00270          wallet->setFolder(KWallet::Wallet::FormDataFolder())) {
00271 
00272         // Do pending fill requests...
00273         if (!pendingFillRequests.isEmpty()) {
00274             KUrl::List urlList;
00275             QMutableHashIterator<KUrl, FormsData> requestIt (pendingFillRequests);
00276             while (requestIt.hasNext()) {
00277                requestIt.next();
00278                KWebWallet::WebFormList list = requestIt.value().forms;
00279                fillDataFromCache(list);
00280                q->fillWebForm(requestIt.key(), list);
00281             }
00282 
00283             pendingFillRequests.clear();
00284         }
00285 
00286          // Do pending save requests...
00287         if (!pendingSaveRequests.isEmpty()) {
00288             QListIterator<QString> keysIt (pendingSaveRequests.keys());
00289             while (keysIt.hasNext())
00290                 saveDataToCache(keysIt.next());
00291         }
00292 
00293         // Do pending remove requests...
00294         if (!pendingRemoveRequests.isEmpty()) {
00295             removeDataFromCache(pendingRemoveRequests);
00296             pendingRemoveRequests.clear();
00297         }
00298     } else {
00299         // Delete the wallet if opening the wallet failed or we were unable
00300         // to change to the folder we wanted to change to.
00301         delete wallet;
00302     }
00303 }
00304 
00305 void KWebWallet::KWebWalletPrivate::_k_walletClosed()
00306 {
00307     if (wallet)
00308       wallet->deleteLater();
00309 
00310     emit q->walletClosed();
00311 }
00312 
00313 KWebWallet::KWebWallet(QObject *parent, WId wid)
00314            :QObject(parent), d(new KWebWalletPrivate(this))
00315 {
00316     if (!wid) {
00317         // If wid is 0, make the best effort the discern it from our parent.
00318         QWebPage *page = qobject_cast<QWebPage*>(parent);
00319         if (page) {
00320             QWidget *widget = page->view();
00321             if (widget && widget->window())
00322                 wid = widget->window()->winId();
00323         }
00324     }
00325 
00326     d->wid = wid;
00327 }
00328 
00329 KWebWallet::~KWebWallet()
00330 {
00331     delete d->wallet;
00332     delete d;
00333 }
00334 
00335 KWebWallet::WebFormList KWebWallet::formsWithCachedData(QWebFrame* frame, bool recursive) const
00336 {
00337     WebFormList list;
00338 
00339     if (frame) {
00340         list << d->parseFormData(frame);
00341 
00342         if (recursive) {
00343             QList<QWebFrame*> childFrameList;
00344             collectAllChildFrames(frame, childFrameList);
00345             QListIterator <QWebFrame *> framesIt (childFrameList);
00346             while (framesIt.hasNext()) {
00347                 list << d->parseFormData(framesIt.next());
00348             }
00349         }
00350     }
00351 
00352     return list;
00353 }
00354 
00355 void KWebWallet::fillFormData(QWebFrame *frame, bool recursive)
00356 {
00357     if (frame) {
00358         KUrl::List urlList;
00359         WebFormList formsList = d->parseFormData(frame);
00360         if (!formsList.isEmpty()) {
00361           const QUrl url (frame->url());
00362           if (d->pendingFillRequests.contains(url)) {
00363               kWarning(800) << "Duplicate request rejected!";
00364           } else {
00365               KWebWalletPrivate::FormsData data;
00366               data.frame = frame;
00367               data.forms << formsList;
00368               d->pendingFillRequests.insert(url, data);
00369               urlList << url;
00370           }
00371         }
00372 
00373         if (recursive) {
00374             QList<QWebFrame*> childFrameList;
00375             collectAllChildFrames(frame, childFrameList);
00376             QListIterator<QWebFrame*> frameIt (childFrameList);
00377             while (frameIt.hasNext()) {
00378                 QWebFrame *childFrame = frameIt.next();
00379                 formsList = d->parseFormData(childFrame);
00380                 if (formsList.isEmpty())
00381                     continue;
00382                 const QUrl url (childFrame->url());
00383                 if (d->pendingFillRequests.contains(url)) {
00384                     kWarning(800) << "Duplicate request rejected!!!";
00385                 } else {
00386                     KWebWalletPrivate::FormsData data;
00387                     data.frame = childFrame;
00388                     data.forms << formsList;
00389                     d->pendingFillRequests.insert(url, data);
00390                     urlList << url;
00391                 }
00392             }
00393         }
00394 
00395         if (!urlList.isEmpty())
00396             fillFormDataFromCache(urlList);
00397     }
00398 }
00399 
00400 void KWebWallet::saveFormData(QWebFrame *frame, bool recursive, bool ignorePasswordFields)
00401 {
00402     if (frame) {
00403         WebFormList list = d->parseFormData(frame, false, ignorePasswordFields);
00404         if (recursive) {
00405             QList<QWebFrame*> childFrameList;
00406             collectAllChildFrames(frame, childFrameList);
00407             QListIterator<QWebFrame*> frameIt (childFrameList);
00408             while (frameIt.hasNext()) {
00409                 list << d->parseFormData(frameIt.next(), false, ignorePasswordFields);
00410             }
00411         }
00412 
00413         if (!list.isEmpty()) {
00414             const QString key = QString::number(qHash(frame->url().toString() + frame->frameName()), 16);
00415             const bool isAlreadyPending = d->pendingSaveRequests.contains(key);
00416             d->pendingSaveRequests.insert(key, list);
00417 
00418             if (!isAlreadyPending) {
00419                 for (int i =0 ; i < list.count(); ++i) {
00420                     if (hasCachedFormData(list.at(i)))
00421                         list.takeAt(i);
00422                 }
00423 
00424                 if (list.isEmpty()) {
00425                     d->confirmSaveRequestOverwrites.insert(frame->url());
00426                     saveFormDataToCache(key);
00427                 } else {
00428                     emit saveFormDataRequested(key, frame->url());
00429                 }
00430             }
00431         }
00432     }
00433 }
00434 
00435 void KWebWallet::removeFormData(QWebFrame *frame, bool recursive)
00436 {
00437     if (frame)
00438         removeFormDataFromCache(formsWithCachedData(frame, recursive));
00439 }
00440 
00441 void KWebWallet::removeFormData(const WebFormList &forms)
00442 {
00443     d->pendingRemoveRequests << forms;
00444     removeFormDataFromCache(forms);
00445 }
00446 
00447 void KWebWallet::acceptSaveFormDataRequest(const QString &key)
00448 {
00449     saveFormDataToCache(key);
00450 }
00451 
00452 void KWebWallet::rejectSaveFormDataRequest(const QString & key)
00453 {
00454     d->pendingSaveRequests.remove(key);
00455 }
00456 
00457 void KWebWallet::fillWebForm(const KUrl &url, const KWebWallet::WebFormList &forms)
00458 {
00459     QWebFrame *frame = d->pendingFillRequests.value(url).frame;
00460     if (frame) {
00461         QWebElement formElement;
00462         bool filledForm = false;
00463         QListIterator<WebForm> formIt (forms);
00464         while (formIt.hasNext()) {
00465             const WebForm form = formIt.next();
00466 
00467             QListIterator<WebForm::WebField> fieldIt (form.fields);
00468             while (fieldIt.hasNext()) {
00469                 const WebForm::WebField field = fieldIt.next();
00470                 if (form.name.isEmpty())
00471                     formElement = frame->findAllElements(QL1S("form[method=post]")).at(form.index.toInt());
00472                 else
00473                     formElement = frame->findFirstElement(QString::fromLatin1("form[method=post][name=%1]")
00474                                                           .arg(form.name));
00475 
00476                 if (!formElement.isNull()) {
00477                     formElement = formElement.findFirst(QString::fromLatin1("input[name=%1]").arg(field.first));
00478                     if (isValidInputElement(formElement)) {
00479                         formElement.setAttribute(QL1S("value"), field.second);
00480                         filledForm = true;
00481                         //kDebug(800) << "Filled out input name=" << field.first;
00482                     }
00483                 }
00484             }
00485         }
00486         emit fillFormRequestCompleted(filledForm);
00487     }
00488 }
00489 
00490 KWebWallet::WebFormList KWebWallet::formsToFill(const KUrl &url) const
00491 {
00492     return d->pendingFillRequests.value(url).forms;
00493 }
00494 
00495 KWebWallet::WebFormList KWebWallet::formsToSave(const QString &key) const
00496 {
00497     return d->pendingSaveRequests.value(key);
00498 }
00499 
00500 bool KWebWallet::hasCachedFormData(const WebForm &form) const
00501 {
00502     return !KWallet::Wallet::keyDoesNotExist(KWallet::Wallet::NetworkWallet(),
00503                                              KWallet::Wallet::FormDataFolder(),
00504                                              walletKey(form));
00505 }
00506 
00507 void KWebWallet::fillFormDataFromCache(const KUrl::List &urlList)
00508 {
00509     if (!d->wallet) {
00510         d->wallet = KWallet::Wallet::openWallet(KWallet::Wallet::NetworkWallet(),
00511                                                 d->wid, KWallet::Wallet::Asynchronous);
00512         connect(d->wallet, SIGNAL(walletOpened(bool)),
00513                 this, SLOT(_k_openWalletDone(bool)));
00514         connect(d->wallet, SIGNAL(walletClosed()),
00515                 this, SLOT(_k_walletClosed()));
00516         return;
00517     }
00518 
00519     QListIterator<KUrl> urlIt (urlList);
00520     while (urlIt.hasNext()) {
00521         const KUrl url = urlIt.next();
00522         WebFormList list = formsToFill(url);
00523         d->fillDataFromCache(list);
00524         fillWebForm(url, list);
00525     }
00526 
00527     d->pendingFillRequests.clear();
00528 }
00529 
00530 void KWebWallet::saveFormDataToCache(const QString &key)
00531 {
00532     if (!d->wallet) {
00533         d->wallet = KWallet::Wallet::openWallet(KWallet::Wallet::NetworkWallet(),
00534                                                 d->wid, KWallet::Wallet::Asynchronous);
00535         connect(d->wallet, SIGNAL(walletOpened(bool)),
00536                 this, SLOT(_k_openWalletDone(bool)));
00537         connect(d->wallet, SIGNAL(walletClosed()),
00538                 this, SLOT(_k_walletClosed()));
00539         return;
00540     }
00541 
00542     d->saveDataToCache(key);
00543 }
00544 
00545 void KWebWallet::removeFormDataFromCache(const WebFormList &forms)
00546 {
00547     if (!d->wallet) {
00548         d->wallet = KWallet::Wallet::openWallet(KWallet::Wallet::NetworkWallet(),
00549                                                 d->wid, KWallet::Wallet::Asynchronous);
00550         connect(d->wallet, SIGNAL(walletOpened(bool)),
00551                 this, SLOT(_k_openWalletDone(bool)));
00552         connect(d->wallet, SIGNAL(walletClosed()),
00553                 this, SLOT(_k_walletClosed()));
00554         return;
00555     }
00556 
00557     d->removeDataFromCache(forms);
00558     d->pendingRemoveRequests.clear();
00559 }
00560 
00561 #include "kwebwallet.moc"

KDEWebKit

Skip menu "KDEWebKit"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Class Members
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.7.3
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal