|  | Home · All Classes · Main Classes · Grouped Classes · Modules · Functions |

# cookiejar.cpp Example File
demos/browser/cookiejar.cpp

     /****************************************************************************
     **
     ** Copyright (C) 2007-2008 Trolltech ASA. All rights reserved.
     **
     ** This file is part of the documentation of the Qt Toolkit.
     **
     ** This file may be used under the terms of the GNU General Public
    ** License versions 2.0 or 3.0 as published by the Free Software
    ** Foundation and appearing in the files LICENSE.GPL2 and LICENSE.GPL3
    ** included in the packaging of this file.  Alternatively you may (at
    ** your option) use any later version of the GNU General Public
    ** License if such license has been publicly approved by Trolltech ASA
    ** (or its successors, if any) and the KDE Free Qt Foundation. In
    ** addition, as a special exception, Trolltech gives you certain
    ** additional rights. These rights are described in the Trolltech GPL
    ** Exception version 1.2, which can be found at
    ** http://www.trolltech.com/products/qt/gplexception/ and in the file
    ** GPL_EXCEPTION.txt in this package.
    **
    ** Please review the following information to ensure GNU General
    ** Public Licensing requirements will be met:
    ** http://trolltech.com/products/qt/licenses/licensing/opensource/. If
    ** you are unsure which license is appropriate for your use, please
    ** review the following information:
    ** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
    ** or contact the sales department at sales@trolltech.com.
    **
    ** In addition, as a special exception, Trolltech, as the sole
    ** copyright holder for Qt Designer, grants users of the Qt/Eclipse
    ** Integration plug-in the right for the Qt/Eclipse Integration to
    ** link to functionality provided by Qt Designer and its related
    ** libraries.
    **
    ** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
    ** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
    ** A PARTICULAR PURPOSE. Trolltech reserves all rights not expressly
    ** granted herein.
     **
     ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
     ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
     **
     ****************************************************************************/

     #include "cookiejar.h"
     #include "autosave.h"

     #include <QtCore/QSettings>
     #include <QtCore/QDateTime>
     #include <QtCore/QUrl>
     #include <QtCore/QMetaEnum>

     #include <QtGui/QFont>
     #include <QtGui/QHeaderView>
     #include <QtGui/QKeyEvent>
     #include <QtGui/QSortFilterProxyModel>
     #include <QtGui/QFontMetrics>
     #include <QtGui/QCompleter>
     #include <QtGui/QDesktopServices>
     #include <qdebug.h>

     static const unsigned int JAR_VERSION = 23;

     QT_BEGIN_NAMESPACE
     QDataStream &operator<<(QDataStream &s, const QList<QNetworkCookie> &l)
     {
         s << JAR_VERSION;
         s << quint32(l.size());
         for (int i = 0; i < l.size(); ++i)
             s << l.at(i).toRawForm();
         return s;
     }

     QDataStream &operator>>(QDataStream &s, QList<QNetworkCookie> &l)
     {
         l.clear();

         quint32 c;
         s >> c;

         if (c != JAR_VERSION)
             return s;

         s >> c;
         for(quint32 i = 0; i < c; ++i)
         {
             QByteArray value;
             s >> value;
             QList<QNetworkCookie> newCookies = QNetworkCookie::parseCookies(value);
             if (newCookies.count() == 0 && value.length() != 0) {
                 qWarning() << "CookieJar: Unable to parse saved cookie:" << value;
             }
             for (int j = 0; j < newCookies.count(); ++j)
                 l.append(newCookies.at(j));
             if (s.atEnd())
                 break;
         }
         return s;
     }
     QT_END_NAMESPACE

     CookieJar::CookieJar(QObject *parent)
         : QNetworkCookieJar(parent)
         , m_loaded(false)
         , m_saveTimer(new AutoSave(this))
         , m_acceptCookies(AcceptOnlyFromSitesNavigatedTo)
     {
     }

     CookieJar::~CookieJar()
     {
         if (m_keepCookies == Exit)
             clear();
         m_saveTimer->saveNow();
     }

     void CookieJar::clear()
     {
         setAllCookies(QList<QNetworkCookie>());
         m_saveTimer->changed();
         emit cookiesChanged();
     }

     void CookieJar::load()
     {
         if (m_loaded)
             return;

         // load cookies and exceptions
         qRegisterMetaTypeStreamOperators<QList<QNetworkCookie> >("QList<QNetworkCookie>");
         QSettings cookieSettings(QDesktopServices::storageLocation(QDesktopServices::DataLocation) + QLatin1String("/cookies.ini"), QSettings::IniFormat);
         setAllCookies(qvariant_cast<QList<QNetworkCookie> >(cookieSettings.value(QLatin1String("cookies"))));
         cookieSettings.beginGroup(QLatin1String("Exceptions"));
         m_exceptions_block = cookieSettings.value(QLatin1String("block")).toStringList();
         m_exceptions_allow = cookieSettings.value(QLatin1String("allow")).toStringList();
         m_exceptions_allowForSession = cookieSettings.value(QLatin1String("allowForSession")).toStringList();
         qSort(m_exceptions_block.begin(), m_exceptions_block.end());
         qSort(m_exceptions_allow.begin(), m_exceptions_allow.end());
         qSort(m_exceptions_allowForSession.begin(), m_exceptions_allowForSession.end());

         // load cookie settings
         QSettings settings;
         settings.beginGroup("cookies");
         QByteArray value = settings.value(QLatin1String("acceptCookies"), "AcceptOnlyFromSitesNavigatedTo").toByteArray();
         QMetaEnum acceptPolicyEnum = staticMetaObject.enumerator(staticMetaObject.indexOfEnumerator("AcceptPolicy"));
         m_acceptCookies = acceptPolicyEnum.keyToValue(value) == -1 ?
                             AcceptOnlyFromSitesNavigatedTo :
                             static_cast<AcceptPolicy>(acceptPolicyEnum.keyToValue(value));

         value = settings.value(QLatin1String("keepCookiesUntil"), "Expire").toByteArray();
         QMetaEnum keepPolicyEnum = staticMetaObject.enumerator(staticMetaObject.indexOfEnumerator("KeepPolicy"));
         m_keepCookies = keepPolicyEnum.keyToValue(value) == -1 ?
                             Expire :
                             static_cast<KeepPolicy>(keepPolicyEnum.keyToValue(value));

         if (m_keepCookies == Exit)
             setAllCookies(QList<QNetworkCookie>());

         m_loaded = true;
         emit cookiesChanged();
     }

     void CookieJar::save()
     {
         if (!m_loaded)
             return;
         purgeOldCookies();
         QSettings cookieSettings(QDesktopServices::storageLocation(QDesktopServices::DataLocation) + QLatin1String("/cookies.ini"), QSettings::IniFormat);
         QList<QNetworkCookie> cookies = allCookies();
         for (int i = cookies.count() - 1; i >= 0; --i) {
             if (cookies.at(i).isSessionCookie())
                 cookies.removeAt(i);
         }
         cookieSettings.setValue(QLatin1String("cookies"), qVariantFromValue<QList<QNetworkCookie> >(cookies));
         cookieSettings.beginGroup(QLatin1String("Exceptions"));
         cookieSettings.setValue(QLatin1String("block"), m_exceptions_block);
         cookieSettings.setValue(QLatin1String("allow"), m_exceptions_allow);
         cookieSettings.setValue(QLatin1String("allowForSession"), m_exceptions_allowForSession);

         // save cookie settings
         QSettings settings;
         settings.beginGroup("cookies");
         QMetaEnum acceptPolicyEnum = staticMetaObject.enumerator(staticMetaObject.indexOfEnumerator("AcceptPolicy"));
         settings.setValue(QLatin1String("acceptCookies"), acceptPolicyEnum.valueToKey(m_acceptCookies));

         QMetaEnum keepPolicyEnum = staticMetaObject.enumerator(staticMetaObject.indexOfEnumerator("KeepPolicy"));
         settings.setValue(QLatin1String("keepCookiesUntil"), keepPolicyEnum.valueToKey(m_keepCookies));
     }

     void CookieJar::purgeOldCookies()
     {
         QList<QNetworkCookie> cookies = allCookies();
         if (cookies.isEmpty())
             return;
         int oldCount = cookies.count();
         QDateTime now = QDateTime::currentDateTime();
         for (int i = cookies.count() - 1; i >= 0; --i) {
             if (!cookies.at(i).isSessionCookie() && cookies.at(i).expirationDate() < now)
                 cookies.removeAt(i);
         }
         if (oldCount == cookies.count())
             return;
         setAllCookies(cookies);
         emit cookiesChanged();
     }

     QList<QNetworkCookie> CookieJar::cookiesForUrl(const QUrl &url) const
     {
         CookieJar *that = const_cast<CookieJar*>(this);
         if (!m_loaded)
             that->load();
         return QNetworkCookieJar::cookiesForUrl(url);
     }

     bool CookieJar::setCookiesFromUrl(const QList<QNetworkCookie> &cookieList, const QUrl &url)
     {
         if (!m_loaded)
             load();

         QString host = url.host();
         bool eBlock = qBinaryFind(m_exceptions_block.begin(), m_exceptions_block.end(), host) != m_exceptions_block.end();
         bool eAllow = qBinaryFind(m_exceptions_allow.begin(), m_exceptions_allow.end(), host) != m_exceptions_allow.end();
         bool eAllowSession = qBinaryFind(m_exceptions_allowForSession.begin(), m_exceptions_allowForSession.end(), host) != m_exceptions_allowForSession.end();

         bool addedCookies = false;
         // pass exceptions
         bool acceptInitially = (m_acceptCookies != AcceptNever);
         if ((acceptInitially && !eBlock)
             || (!acceptInitially && (eAllow || eAllowSession))) {
             // pass url domain == cookie domain
             QDateTime soon = QDateTime::currentDateTime();
             soon = soon.addDays(90);
             foreach(QNetworkCookie cookie, cookieList) {
                 QList<QNetworkCookie> lst;
                 if (m_keepCookies == TimeLimit
                     && !cookie.isSessionCookie()
                     && cookie.expirationDate() > soon) {
                         cookie.setExpirationDate(soon);
                 }
                 lst += cookie;
                 if (QNetworkCookieJar::setCookiesFromUrl(lst, url)) {
                     addedCookies = true;
                 } else {
                     // finally force it in if wanted
                     if (m_acceptCookies == AcceptAlways) {
                         QList<QNetworkCookie> cookies = allCookies();
                         cookies += cookie;
                         setAllCookies(cookies);
                         addedCookies = true;
                     }
     #if 0
                     else
                         qWarning() << "setCookiesFromUrl failed" << url << cookieList.value(0).toRawForm();
     #endif
                 }
             }
         }

         if (addedCookies) {
             m_saveTimer->changed();
             emit cookiesChanged();
         }
         return addedCookies;
     }

     CookieJar::AcceptPolicy CookieJar::acceptPolicy() const
     {
         if (!m_loaded)
             (const_cast<CookieJar*>(this))->load();
         return m_acceptCookies;
     }

     void CookieJar::setAcceptPolicy(AcceptPolicy policy)
     {
         if (!m_loaded)
             load();
         m_acceptCookies = policy;
         m_saveTimer->changed();
     }

     CookieJar::KeepPolicy CookieJar::keepPolicy() const
     {
         if (!m_loaded)
             (const_cast<CookieJar*>(this))->load();
         return m_keepCookies;
     }

     void CookieJar::setKeepPolicy(KeepPolicy policy)
     {
         if (!m_loaded)
             load();
         m_keepCookies = policy;
         m_saveTimer->changed();
     }

     QStringList CookieJar::blockedCookies() const
     {
         if (!m_loaded)
             (const_cast<CookieJar*>(this))->load();
         return m_exceptions_block;
     }

     QStringList CookieJar::allowedCookies() const
     {
         if (!m_loaded)
             (const_cast<CookieJar*>(this))->load();
         return m_exceptions_allow;
     }

     QStringList CookieJar::allowForSessionCookies() const
     {
         if (!m_loaded)
             (const_cast<CookieJar*>(this))->load();
         return m_exceptions_allowForSession;
     }

     void CookieJar::setBlockedCookies(const QStringList &list)
     {
         if (!m_loaded)
             load();
         m_exceptions_block = list;
         qSort(m_exceptions_block.begin(), m_exceptions_block.end());
         m_saveTimer->changed();
     }

     void CookieJar::setAllowedCookies(const QStringList &list)
     {
         if (!m_loaded)
             load();
         m_exceptions_allow = list;
         qSort(m_exceptions_allow.begin(), m_exceptions_allow.end());
         m_saveTimer->changed();
     }

     void CookieJar::setAllowForSessionCookies(const QStringList &list)
     {
         if (!m_loaded)
             load();
         m_exceptions_allowForSession = list;
         qSort(m_exceptions_allowForSession.begin(), m_exceptions_allowForSession.end());
         m_saveTimer->changed();
     }

     CookieModel::CookieModel(CookieJar *jar, QObject *parent)
         : QAbstractTableModel(parent)
         , m_jar(jar)
     {
         connect(m_jar, SIGNAL(cookiesChanged()), this, SLOT(cookiesChanged()));
         m_jar->load();
     }

     QVariant CookieModel::headerData(int section, Qt::Orientation orientation, int role) const
     {
         if (role == Qt::SizeHintRole) {
             QFont font;
             font.setPointSize(10);
             QFontMetrics fm(font);
             int height = fm.height() + fm.height()/3;
             int width = fm.width(headerData(section, orientation, Qt::DisplayRole).toString());
             return QSize(width, height);
         }

         if (orientation == Qt::Horizontal) {
             if (role != Qt::DisplayRole)
                 return QVariant();

             switch (section) {
                 case 0:
                     return tr("Website");
                 case 1:
                     return tr("Name");
                 case 2:
                     return tr("Path");
                 case 3:
                     return tr("Secure");
                 case 4:
                     return tr("Expires");
                 case 5:
                     return tr("Contents");
                 default:
                     return QVariant();
             }
         }
         return QAbstractTableModel::headerData(section, orientation, role);
     }

     QVariant CookieModel::data(const QModelIndex &index, int role) const
     {
         QList<QNetworkCookie> lst;
         if (m_jar)
             lst = m_jar->allCookies();
         if (index.row() < 0 || index.row() >= lst.size())
             return QVariant();

         switch (role) {
         case Qt::DisplayRole:
         case Qt::EditRole: {
             QNetworkCookie cookie = lst.at(index.row());
             switch (index.column()) {
                 case 0:
                     return cookie.domain();
                 case 1:
                     return cookie.name();
                 case 2:
                     return cookie.path();
                 case 3:
                     return cookie.isSecure();
                 case 4:
                     return cookie.expirationDate();
                 case 5:
                     return cookie.value();
             }
             }
         case Qt::FontRole:{
             QFont font;
             font.setPointSize(10);
             return font;
             }
         }

         return QVariant();
     }

     int CookieModel::columnCount(const QModelIndex &parent) const
     {
         return (parent.isValid()) ? 0 : 6;
     }

     int CookieModel::rowCount(const QModelIndex &parent) const
     {
         return (parent.isValid() || !m_jar) ? 0 : m_jar->allCookies().count();
     }

     bool CookieModel::removeRows(int row, int count, const QModelIndex &parent)
     {
         if (parent.isValid() || !m_jar)
             return false;
         int lastRow = row + count - 1;
         beginRemoveRows(parent, row, lastRow);
         QList<QNetworkCookie> lst = m_jar->allCookies();
         for (int i = lastRow; i >= row; --i) {
             lst.removeAt(i);
         }
         m_jar->setAllCookies(lst);
         endRemoveRows();
         return true;
     }

     void CookieModel::cookiesChanged()
     {
         reset();
     }

     CookiesDialog::CookiesDialog(CookieJar *cookieJar, QWidget *parent) : QDialog(parent)
     {
         setupUi(this);
         CookieModel *model = new CookieModel(cookieJar, this);
         m_proxyModel = new QSortFilterProxyModel(this);
         connect(search, SIGNAL(textChanged(QString)), m_proxyModel, SLOT(setFilterFixedString(QString)));
         connect(removeButton, SIGNAL(clicked()), cookiesTable, SLOT(removeOne()));
         connect(removeAllButton, SIGNAL(clicked()), cookiesTable, SLOT(removeAll()));
         m_proxyModel->setSourceModel(model);
         cookiesTable->verticalHeader()->hide();
         cookiesTable->setSelectionBehavior(QAbstractItemView::SelectRows);
         cookiesTable->setModel(m_proxyModel);
         cookiesTable->setAlternatingRowColors(true);
         cookiesTable->setTextElideMode(Qt::ElideMiddle);
         cookiesTable->setShowGrid(false);
         cookiesTable->setSortingEnabled(true);
         QFont f = font();
         f.setPointSize(10);
         QFontMetrics fm(f);
         int height = fm.height() + fm.height()/3;
         cookiesTable->verticalHeader()->setDefaultSectionSize(height);
         cookiesTable->verticalHeader()->setMinimumSectionSize(-1);
         for (int i = 0; i < model->columnCount(); ++i){
             int header = cookiesTable->horizontalHeader()->sectionSizeHint(i);
             switch (i) {
             case 0:
                 header = fm.width("averagehost.domain.com");
                 break;
             case 1:
                 header = fm.width("_session_id");
                 break;
             case 4:
                 header = fm.width(QDateTime::currentDateTime().toString(Qt::LocalDate));
                 break;
             }
             int buffer = fm.width("xx");
             header += buffer;
             cookiesTable->horizontalHeader()->resizeSection(i, header);
         }
         cookiesTable->horizontalHeader()->setStretchLastSection(true);
     }

     CookieExceptionsModel::CookieExceptionsModel(CookieJar *cookiejar, QObject *parent)
         : QAbstractTableModel(parent)
         , m_jar(cookiejar)
     {
         m_allowedCookies = m_jar->allowedCookies();
         m_blockedCookies = m_jar->blockedCookies();
         m_sessionCookies = m_jar->allowForSessionCookies();
     }

     QVariant CookieExceptionsModel::headerData(int section, Qt::Orientation orientation, int role) const
     {
         if (role == Qt::SizeHintRole) {
             QFont font;
             font.setPointSize(10);
             QFontMetrics fm(font);
             int height = fm.height() + fm.height()/3;
             int width = fm.width(headerData(section, orientation, Qt::DisplayRole).toString());
             return QSize(width, height);
         }

         if (orientation == Qt::Horizontal
             && role == Qt::DisplayRole) {
             switch (section) {
                 case 0:
                     return tr("Website");
                 case 1:
                     return tr("Status");
             }
         }
         return QAbstractTableModel::headerData(section, orientation, role);
     }

     QVariant CookieExceptionsModel::data(const QModelIndex &index, int role) const
     {
         if (index.row() < 0 || index.row() >= rowCount())
             return QVariant();

         switch (role) {
         case Qt::DisplayRole:
         case Qt::EditRole: {
             int row = index.row();
             if (row < m_allowedCookies.count()) {
                 switch (index.column()) {
                     case 0:
                         return m_allowedCookies.at(row);
                     case 1:
                         return tr("Allow");
                 }
             }
             row = row - m_allowedCookies.count();
             if (row < m_blockedCookies.count()) {
                 switch (index.column()) {
                     case 0:
                         return m_blockedCookies.at(row);
                     case 1:
                         return tr("Block");
                 }
             }
             row = row - m_blockedCookies.count();
             if (row < m_sessionCookies.count()) {
                 switch (index.column()) {
                     case 0:
                         return m_sessionCookies.at(row);
                     case 1:
                         return tr("Allow For Session");
                 }
             }
             }
         case Qt::FontRole:{
             QFont font;
             font.setPointSize(10);
             return font;
             }
         }
         return QVariant();
     }

     int CookieExceptionsModel::columnCount(const QModelIndex &parent) const
     {
         return (parent.isValid()) ? 0 : 2;
     }

     int CookieExceptionsModel::rowCount(const QModelIndex &parent) const
     {
         return (parent.isValid() || !m_jar) ? 0 : m_allowedCookies.count() + m_blockedCookies.count() + m_sessionCookies.count();
     }

     bool CookieExceptionsModel::removeRows(int row, int count, const QModelIndex &parent)
     {
         if (parent.isValid() || !m_jar)
             return false;

         int lastRow = row + count - 1;
         beginRemoveRows(parent, row, lastRow);
         for (int i = lastRow; i >= row; --i) {
             if (i < m_allowedCookies.count()) {
                 m_allowedCookies.removeAt(row);
                 continue;
             }
             i = i - m_allowedCookies.count();
             if (i < m_blockedCookies.count()) {
                 m_blockedCookies.removeAt(row);
                 continue;
             }
             i = i - m_blockedCookies.count();
             if (i < m_sessionCookies.count()) {
                 m_sessionCookies.removeAt(row);
                 continue;
             }
         }
         m_jar->setAllowedCookies(m_allowedCookies);
         m_jar->setBlockedCookies(m_blockedCookies);
         m_jar->setAllowForSessionCookies(m_sessionCookies);
         endRemoveRows();
         return true;
     }

     CookiesExceptionsDialog::CookiesExceptionsDialog(CookieJar *cookieJar, QWidget *parent)
         : QDialog(parent)
         , m_jar(cookieJar)
     {
         setupUi(this);
         connect(removeButton, SIGNAL(clicked()), exceptionTable, SLOT(removeOne()));
         connect(removeAllButton, SIGNAL(clicked()), exceptionTable, SLOT(removeAll()));
         exceptionTable->verticalHeader()->hide();
         exceptionTable->setSelectionBehavior(QAbstractItemView::SelectRows);
         exceptionTable->setAlternatingRowColors(true);
         exceptionTable->setTextElideMode(Qt::ElideMiddle);
         exceptionTable->setShowGrid(false);
         exceptionTable->setSortingEnabled(true);
         m_model = new CookieExceptionsModel(cookieJar, this);
         m_proxyModel = new QSortFilterProxyModel(this);
         m_proxyModel->setSourceModel(m_model);
         connect(search, SIGNAL(textChanged(QString)), m_proxyModel, SLOT(setFilterFixedString(QString)));
         exceptionTable->setModel(m_proxyModel);

         CookieModel *cookieModel = new CookieModel(cookieJar, this);
         domainLineEdit->setCompleter(new QCompleter(cookieModel, domainLineEdit));

         connect(blockButton, SIGNAL(clicked()), this, SLOT(block()));
         connect(allowButton, SIGNAL(clicked()), this, SLOT(allow()));
         connect(allowForSessionButton, SIGNAL(clicked()), this, SLOT(allowForSession()));

         QFont f = font();
         f.setPointSize(10);
         QFontMetrics fm(f);
         int height = fm.height() + fm.height()/3;
         exceptionTable->verticalHeader()->setDefaultSectionSize(height);
         exceptionTable->verticalHeader()->setMinimumSectionSize(-1);
         for (int i = 0; i < m_model->columnCount(); ++i){
             int header = exceptionTable->horizontalHeader()->sectionSizeHint(i);
             switch (i) {
             case 0:
                 header = fm.width("averagebiglonghost.domain.com");
                 break;
             case 1:
                 header = fm.width("Allow For Session");
                 break;
             }
             int buffer = fm.width("xx");
             header += buffer;
             exceptionTable->horizontalHeader()->resizeSection(i, header);
         }
     }

     void CookiesExceptionsDialog::block()
     {
         m_model->m_blockedCookies.append(domainLineEdit->text());
         m_jar->setBlockedCookies(m_model->m_blockedCookies);
         m_model->reset();
     }

     void CookiesExceptionsDialog::allow()
     {
         m_model->m_allowedCookies.append(domainLineEdit->text());
         m_jar->setAllowedCookies(m_model->m_allowedCookies);
         m_model->reset();
     }

     void CookiesExceptionsDialog::allowForSession()
     {
         m_model->m_sessionCookies.append(domainLineEdit->text());
         m_jar->setAllowForSessionCookies(m_model->m_sessionCookies);
         m_model->reset();
     }