1 /****************************************************************************
3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 ** This file is part of the demonstration applications of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
10 ** This file contains pre-release code and may not be distributed.
11 ** You may use this file in accordance with the terms and conditions
12 ** contained in the Technology Preview License Agreement accompanying
15 ** GNU Lesser General Public License Usage
16 ** Alternatively, this file may be used under the terms of the GNU Lesser
17 ** General Public License version 2.1 as published by the Free Software
18 ** Foundation and appearing in the file LICENSE.LGPL included in the
19 ** packaging of this file. Please review the following information to
20 ** ensure the GNU Lesser General Public License version 2.1 requirements
21 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23 ** In addition, as a special exception, Nokia gives you certain
24 ** additional rights. These rights are described in the Nokia Qt LGPL
25 ** Exception version 1.1, included in the file LGPL_EXCEPTION.txt in this
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
40 ****************************************************************************/
42 #include "cookiejar.h"
44 #include "autosaver.h"
46 #include <QtCore/QDateTime>
47 #include <QtCore/QDir>
48 #include <QtCore/QFile>
49 #include <QtCore/QMetaEnum>
50 #include <QtCore/QSettings>
51 #include <QtCore/QUrl>
53 #include <QtGui/QCompleter>
54 #include <QtGui/QDesktopServices>
55 #include <QtGui/QFont>
56 #include <QtGui/QFontMetrics>
57 #include <QtGui/QHeaderView>
58 #include <QtGui/QKeyEvent>
59 #include <QtGui/QSortFilterProxyModel>
61 #include <QtWebKit/QWebSettings>
63 #include <QtCore/QDebug>
65 static const unsigned int JAR_VERSION
= 23;
68 QDataStream
&operator<<(QDataStream
&stream
, const QList
<QNetworkCookie
> &list
)
70 stream
<< JAR_VERSION
;
71 stream
<< quint32(list
.size());
72 for (int i
= 0; i
< list
.size(); ++i
)
73 stream
<< list
.at(i
).toRawForm();
77 QDataStream
&operator>>(QDataStream
&stream
, QList
<QNetworkCookie
> &list
)
84 if (version
!= JAR_VERSION
)
89 for(quint32 i
= 0; i
< count
; ++i
)
93 QList
<QNetworkCookie
> newCookies
= QNetworkCookie::parseCookies(value
);
94 if (newCookies
.count() == 0 && value
.length() != 0) {
95 qWarning() << "CookieJar: Unable to parse saved cookie:" << value
;
97 for (int j
= 0; j
< newCookies
.count(); ++j
)
98 list
.append(newCookies
.at(j
));
106 CookieJar::CookieJar(QObject
*parent
)
107 : QNetworkCookieJar(parent
)
109 , m_saveTimer(new AutoSaver(this))
110 , m_acceptCookies(AcceptOnlyFromSitesNavigatedTo
)
114 CookieJar::~CookieJar()
116 if (m_keepCookies
== KeepUntilExit
)
118 m_saveTimer
->saveIfNeccessary();
121 void CookieJar::clear()
123 setAllCookies(QList
<QNetworkCookie
>());
124 m_saveTimer
->changeOccurred();
125 emit
cookiesChanged();
128 void CookieJar::load()
132 // load cookies and exceptions
133 qRegisterMetaTypeStreamOperators
<QList
<QNetworkCookie
> >("QList<QNetworkCookie>");
134 QSettings
cookieSettings(QDesktopServices::storageLocation(QDesktopServices::DataLocation
) + QLatin1String("/cookies.ini"), QSettings::IniFormat
);
135 setAllCookies(qvariant_cast
<QList
<QNetworkCookie
> >(cookieSettings
.value(QLatin1String("cookies"))));
136 cookieSettings
.beginGroup(QLatin1String("Exceptions"));
137 m_exceptions_block
= cookieSettings
.value(QLatin1String("block")).toStringList();
138 m_exceptions_allow
= cookieSettings
.value(QLatin1String("allow")).toStringList();
139 m_exceptions_allowForSession
= cookieSettings
.value(QLatin1String("allowForSession")).toStringList();
140 qSort(m_exceptions_block
.begin(), m_exceptions_block
.end());
141 qSort(m_exceptions_allow
.begin(), m_exceptions_allow
.end());
142 qSort(m_exceptions_allowForSession
.begin(), m_exceptions_allowForSession
.end());
147 void CookieJar::loadSettings()
150 settings
.beginGroup(QLatin1String("cookies"));
151 QByteArray value
= settings
.value(QLatin1String("acceptCookies"),
152 QLatin1String("AcceptOnlyFromSitesNavigatedTo")).toByteArray();
153 QMetaEnum acceptPolicyEnum
= staticMetaObject
.enumerator(staticMetaObject
.indexOfEnumerator("AcceptPolicy"));
154 m_acceptCookies
= acceptPolicyEnum
.keyToValue(value
) == -1 ?
155 AcceptOnlyFromSitesNavigatedTo
:
156 static_cast<AcceptPolicy
>(acceptPolicyEnum
.keyToValue(value
));
158 value
= settings
.value(QLatin1String("keepCookiesUntil"), QLatin1String("KeepUntilExpire")).toByteArray();
159 QMetaEnum keepPolicyEnum
= staticMetaObject
.enumerator(staticMetaObject
.indexOfEnumerator("KeepPolicy"));
160 m_keepCookies
= keepPolicyEnum
.keyToValue(value
) == -1 ?
162 static_cast<KeepPolicy
>(keepPolicyEnum
.keyToValue(value
));
164 if (m_keepCookies
== KeepUntilExit
)
165 setAllCookies(QList
<QNetworkCookie
>());
168 emit
cookiesChanged();
171 void CookieJar::save()
176 QString directory
= QDesktopServices::storageLocation(QDesktopServices::DataLocation
);
177 if (directory
.isEmpty())
178 directory
= QDir::homePath() + QLatin1String("/.") + QCoreApplication::applicationName();
179 if (!QFile::exists(directory
)) {
181 dir
.mkpath(directory
);
183 QSettings
cookieSettings(directory
+ QLatin1String("/cookies.ini"), QSettings::IniFormat
);
184 QList
<QNetworkCookie
> cookies
= allCookies();
185 for (int i
= cookies
.count() - 1; i
>= 0; --i
) {
186 if (cookies
.at(i
).isSessionCookie())
189 cookieSettings
.setValue(QLatin1String("cookies"), qVariantFromValue
<QList
<QNetworkCookie
> >(cookies
));
190 cookieSettings
.beginGroup(QLatin1String("Exceptions"));
191 cookieSettings
.setValue(QLatin1String("block"), m_exceptions_block
);
192 cookieSettings
.setValue(QLatin1String("allow"), m_exceptions_allow
);
193 cookieSettings
.setValue(QLatin1String("allowForSession"), m_exceptions_allowForSession
);
195 // save cookie settings
197 settings
.beginGroup(QLatin1String("cookies"));
198 QMetaEnum acceptPolicyEnum
= staticMetaObject
.enumerator(staticMetaObject
.indexOfEnumerator("AcceptPolicy"));
199 settings
.setValue(QLatin1String("acceptCookies"), QLatin1String(acceptPolicyEnum
.valueToKey(m_acceptCookies
)));
201 QMetaEnum keepPolicyEnum
= staticMetaObject
.enumerator(staticMetaObject
.indexOfEnumerator("KeepPolicy"));
202 settings
.setValue(QLatin1String("keepCookiesUntil"), QLatin1String(keepPolicyEnum
.valueToKey(m_keepCookies
)));
205 void CookieJar::purgeOldCookies()
207 QList
<QNetworkCookie
> cookies
= allCookies();
208 if (cookies
.isEmpty())
210 int oldCount
= cookies
.count();
211 QDateTime now
= QDateTime::currentDateTime();
212 for (int i
= cookies
.count() - 1; i
>= 0; --i
) {
213 if (!cookies
.at(i
).isSessionCookie() && cookies
.at(i
).expirationDate() < now
)
216 if (oldCount
== cookies
.count())
218 setAllCookies(cookies
);
219 emit
cookiesChanged();
222 QList
<QNetworkCookie
> CookieJar::cookiesForUrl(const QUrl
&url
) const
224 CookieJar
*that
= const_cast<CookieJar
*>(this);
228 QWebSettings
*globalSettings
= QWebSettings::globalSettings();
229 if (globalSettings
->testAttribute(QWebSettings::PrivateBrowsingEnabled
)) {
230 QList
<QNetworkCookie
> noCookies
;
234 return QNetworkCookieJar::cookiesForUrl(url
);
237 bool CookieJar::setCookiesFromUrl(const QList
<QNetworkCookie
> &cookieList
, const QUrl
&url
)
242 QWebSettings
*globalSettings
= QWebSettings::globalSettings();
243 if (globalSettings
->testAttribute(QWebSettings::PrivateBrowsingEnabled
))
246 QString host
= url
.host();
247 bool eBlock
= qBinaryFind(m_exceptions_block
.begin(), m_exceptions_block
.end(), host
) != m_exceptions_block
.end();
248 bool eAllow
= qBinaryFind(m_exceptions_allow
.begin(), m_exceptions_allow
.end(), host
) != m_exceptions_allow
.end();
249 bool eAllowSession
= qBinaryFind(m_exceptions_allowForSession
.begin(), m_exceptions_allowForSession
.end(), host
) != m_exceptions_allowForSession
.end();
251 bool addedCookies
= false;
253 bool acceptInitially
= (m_acceptCookies
!= AcceptNever
);
254 if ((acceptInitially
&& !eBlock
)
255 || (!acceptInitially
&& (eAllow
|| eAllowSession
))) {
256 // pass url domain == cookie domain
257 QDateTime soon
= QDateTime::currentDateTime();
258 soon
= soon
.addDays(90);
259 foreach(QNetworkCookie cookie
, cookieList
) {
260 QList
<QNetworkCookie
> lst
;
261 if (m_keepCookies
== KeepUntilTimeLimit
262 && !cookie
.isSessionCookie()
263 && cookie
.expirationDate() > soon
) {
264 cookie
.setExpirationDate(soon
);
267 if (QNetworkCookieJar::setCookiesFromUrl(lst
, url
)) {
270 // finally force it in if wanted
271 if (m_acceptCookies
== AcceptAlways
) {
272 QList
<QNetworkCookie
> cookies
= allCookies();
274 setAllCookies(cookies
);
279 qWarning() << "setCookiesFromUrl failed" << url
<< cookieList
.value(0).toRawForm();
286 m_saveTimer
->changeOccurred();
287 emit
cookiesChanged();
292 CookieJar::AcceptPolicy
CookieJar::acceptPolicy() const
295 (const_cast<CookieJar
*>(this))->load();
296 return m_acceptCookies
;
299 void CookieJar::setAcceptPolicy(AcceptPolicy policy
)
303 if (policy
== m_acceptCookies
)
305 m_acceptCookies
= policy
;
306 m_saveTimer
->changeOccurred();
309 CookieJar::KeepPolicy
CookieJar::keepPolicy() const
312 (const_cast<CookieJar
*>(this))->load();
313 return m_keepCookies
;
316 void CookieJar::setKeepPolicy(KeepPolicy policy
)
320 if (policy
== m_keepCookies
)
322 m_keepCookies
= policy
;
323 m_saveTimer
->changeOccurred();
326 QStringList
CookieJar::blockedCookies() const
329 (const_cast<CookieJar
*>(this))->load();
330 return m_exceptions_block
;
333 QStringList
CookieJar::allowedCookies() const
336 (const_cast<CookieJar
*>(this))->load();
337 return m_exceptions_allow
;
340 QStringList
CookieJar::allowForSessionCookies() const
343 (const_cast<CookieJar
*>(this))->load();
344 return m_exceptions_allowForSession
;
347 void CookieJar::setBlockedCookies(const QStringList
&list
)
351 m_exceptions_block
= list
;
352 qSort(m_exceptions_block
.begin(), m_exceptions_block
.end());
353 m_saveTimer
->changeOccurred();
356 void CookieJar::setAllowedCookies(const QStringList
&list
)
360 m_exceptions_allow
= list
;
361 qSort(m_exceptions_allow
.begin(), m_exceptions_allow
.end());
362 m_saveTimer
->changeOccurred();
365 void CookieJar::setAllowForSessionCookies(const QStringList
&list
)
369 m_exceptions_allowForSession
= list
;
370 qSort(m_exceptions_allowForSession
.begin(), m_exceptions_allowForSession
.end());
371 m_saveTimer
->changeOccurred();
374 CookieModel::CookieModel(CookieJar
*cookieJar
, QObject
*parent
)
375 : QAbstractTableModel(parent
)
376 , m_cookieJar(cookieJar
)
378 connect(m_cookieJar
, SIGNAL(cookiesChanged()), this, SLOT(cookiesChanged()));
382 QVariant
CookieModel::headerData(int section
, Qt::Orientation orientation
, int role
) const
384 if (role
== Qt::SizeHintRole
) {
386 font
.setPointSize(10);
387 QFontMetrics
fm(font
);
388 int height
= fm
.height() + fm
.height()/3;
389 int width
= fm
.width(headerData(section
, orientation
, Qt::DisplayRole
).toString());
390 return QSize(width
, height
);
393 if (orientation
== Qt::Horizontal
) {
394 if (role
!= Qt::DisplayRole
)
399 return tr("Website");
407 return tr("Expires");
409 return tr("Contents");
414 return QAbstractTableModel::headerData(section
, orientation
, role
);
417 QVariant
CookieModel::data(const QModelIndex
&index
, int role
) const
419 QList
<QNetworkCookie
> lst
;
421 lst
= m_cookieJar
->allCookies();
422 if (index
.row() < 0 || index
.row() >= lst
.size())
426 case Qt::DisplayRole
:
428 QNetworkCookie cookie
= lst
.at(index
.row());
429 switch (index
.column()) {
431 return cookie
.domain();
433 return cookie
.name();
435 return cookie
.path();
437 return cookie
.isSecure();
439 return cookie
.expirationDate();
441 return cookie
.value();
446 font
.setPointSize(10);
454 int CookieModel::columnCount(const QModelIndex
&parent
) const
456 return (parent
.isValid()) ? 0 : 6;
459 int CookieModel::rowCount(const QModelIndex
&parent
) const
461 return (parent
.isValid() || !m_cookieJar
) ? 0 : m_cookieJar
->allCookies().count();
464 bool CookieModel::removeRows(int row
, int count
, const QModelIndex
&parent
)
466 if (parent
.isValid() || !m_cookieJar
)
468 int lastRow
= row
+ count
- 1;
469 beginRemoveRows(parent
, row
, lastRow
);
470 QList
<QNetworkCookie
> lst
= m_cookieJar
->allCookies();
471 for (int i
= lastRow
; i
>= row
; --i
) {
474 m_cookieJar
->setAllCookies(lst
);
479 void CookieModel::cookiesChanged()
484 CookiesDialog::CookiesDialog(CookieJar
*cookieJar
, QWidget
*parent
) : QDialog(parent
)
487 setWindowFlags(Qt::Sheet
);
488 CookieModel
*model
= new CookieModel(cookieJar
, this);
489 m_proxyModel
= new QSortFilterProxyModel(this);
490 connect(search
, SIGNAL(textChanged(QString
)),
491 m_proxyModel
, SLOT(setFilterFixedString(QString
)));
492 connect(removeButton
, SIGNAL(clicked()), cookiesTable
, SLOT(removeOne()));
493 connect(removeAllButton
, SIGNAL(clicked()), cookiesTable
, SLOT(removeAll()));
494 m_proxyModel
->setSourceModel(model
);
495 cookiesTable
->verticalHeader()->hide();
496 cookiesTable
->setSelectionBehavior(QAbstractItemView::SelectRows
);
497 cookiesTable
->setModel(m_proxyModel
);
498 cookiesTable
->setAlternatingRowColors(true);
499 cookiesTable
->setTextElideMode(Qt::ElideMiddle
);
500 cookiesTable
->setShowGrid(false);
501 cookiesTable
->setSortingEnabled(true);
505 int height
= fm
.height() + fm
.height()/3;
506 cookiesTable
->verticalHeader()->setDefaultSectionSize(height
);
507 cookiesTable
->verticalHeader()->setMinimumSectionSize(-1);
508 for (int i
= 0; i
< model
->columnCount(); ++i
){
509 int header
= cookiesTable
->horizontalHeader()->sectionSizeHint(i
);
512 header
= fm
.width(QLatin1String("averagehost.domain.com"));
515 header
= fm
.width(QLatin1String("_session_id"));
518 header
= fm
.width(QDateTime::currentDateTime().toString(Qt::LocalDate
));
521 int buffer
= fm
.width(QLatin1String("xx"));
523 cookiesTable
->horizontalHeader()->resizeSection(i
, header
);
525 cookiesTable
->horizontalHeader()->setStretchLastSection(true);
530 CookieExceptionsModel::CookieExceptionsModel(CookieJar
*cookiejar
, QObject
*parent
)
531 : QAbstractTableModel(parent
)
532 , m_cookieJar(cookiejar
)
534 m_allowedCookies
= m_cookieJar
->allowedCookies();
535 m_blockedCookies
= m_cookieJar
->blockedCookies();
536 m_sessionCookies
= m_cookieJar
->allowForSessionCookies();
539 QVariant
CookieExceptionsModel::headerData(int section
, Qt::Orientation orientation
, int role
) const
541 if (role
== Qt::SizeHintRole
) {
543 font
.setPointSize(10);
544 QFontMetrics
fm(font
);
545 int height
= fm
.height() + fm
.height()/3;
546 int width
= fm
.width(headerData(section
, orientation
, Qt::DisplayRole
).toString());
547 return QSize(width
, height
);
550 if (orientation
== Qt::Horizontal
551 && role
== Qt::DisplayRole
) {
554 return tr("Website");
559 return QAbstractTableModel::headerData(section
, orientation
, role
);
562 QVariant
CookieExceptionsModel::data(const QModelIndex
&index
, int role
) const
564 if (index
.row() < 0 || index
.row() >= rowCount())
568 case Qt::DisplayRole
:
570 int row
= index
.row();
571 if (row
< m_allowedCookies
.count()) {
572 switch (index
.column()) {
574 return m_allowedCookies
.at(row
);
579 row
= row
- m_allowedCookies
.count();
580 if (row
< m_blockedCookies
.count()) {
581 switch (index
.column()) {
583 return m_blockedCookies
.at(row
);
588 row
= row
- m_blockedCookies
.count();
589 if (row
< m_sessionCookies
.count()) {
590 switch (index
.column()) {
592 return m_sessionCookies
.at(row
);
594 return tr("Allow For Session");
600 font
.setPointSize(10);
607 int CookieExceptionsModel::columnCount(const QModelIndex
&parent
) const
609 return (parent
.isValid()) ? 0 : 2;
612 int CookieExceptionsModel::rowCount(const QModelIndex
&parent
) const
614 return (parent
.isValid() || !m_cookieJar
) ? 0 : m_allowedCookies
.count() + m_blockedCookies
.count() + m_sessionCookies
.count();
617 bool CookieExceptionsModel::removeRows(int row
, int count
, const QModelIndex
&parent
)
619 if (parent
.isValid() || !m_cookieJar
)
622 int lastRow
= row
+ count
- 1;
623 beginRemoveRows(parent
, row
, lastRow
);
624 for (int i
= lastRow
; i
>= row
; --i
) {
625 if (i
< m_allowedCookies
.count()) {
626 m_allowedCookies
.removeAt(row
);
629 i
= i
- m_allowedCookies
.count();
630 if (i
< m_blockedCookies
.count()) {
631 m_blockedCookies
.removeAt(row
);
634 i
= i
- m_blockedCookies
.count();
635 if (i
< m_sessionCookies
.count()) {
636 m_sessionCookies
.removeAt(row
);
640 m_cookieJar
->setAllowedCookies(m_allowedCookies
);
641 m_cookieJar
->setBlockedCookies(m_blockedCookies
);
642 m_cookieJar
->setAllowForSessionCookies(m_sessionCookies
);
647 CookiesExceptionsDialog::CookiesExceptionsDialog(CookieJar
*cookieJar
, QWidget
*parent
)
649 , m_cookieJar(cookieJar
)
652 setWindowFlags(Qt::Sheet
);
653 connect(removeButton
, SIGNAL(clicked()), exceptionTable
, SLOT(removeOne()));
654 connect(removeAllButton
, SIGNAL(clicked()), exceptionTable
, SLOT(removeAll()));
655 exceptionTable
->verticalHeader()->hide();
656 exceptionTable
->setSelectionBehavior(QAbstractItemView::SelectRows
);
657 exceptionTable
->setAlternatingRowColors(true);
658 exceptionTable
->setTextElideMode(Qt::ElideMiddle
);
659 exceptionTable
->setShowGrid(false);
660 exceptionTable
->setSortingEnabled(true);
661 m_exceptionsModel
= new CookieExceptionsModel(cookieJar
, this);
662 m_proxyModel
= new QSortFilterProxyModel(this);
663 m_proxyModel
->setSourceModel(m_exceptionsModel
);
664 connect(search
, SIGNAL(textChanged(QString
)),
665 m_proxyModel
, SLOT(setFilterFixedString(QString
)));
666 exceptionTable
->setModel(m_proxyModel
);
668 CookieModel
*cookieModel
= new CookieModel(cookieJar
, this);
669 domainLineEdit
->setCompleter(new QCompleter(cookieModel
, domainLineEdit
));
671 connect(domainLineEdit
, SIGNAL(textChanged(const QString
&)),
672 this, SLOT(textChanged(const QString
&)));
673 connect(blockButton
, SIGNAL(clicked()), this, SLOT(block()));
674 connect(allowButton
, SIGNAL(clicked()), this, SLOT(allow()));
675 connect(allowForSessionButton
, SIGNAL(clicked()), this, SLOT(allowForSession()));
680 int height
= fm
.height() + fm
.height()/3;
681 exceptionTable
->verticalHeader()->setDefaultSectionSize(height
);
682 exceptionTable
->verticalHeader()->setMinimumSectionSize(-1);
683 for (int i
= 0; i
< m_exceptionsModel
->columnCount(); ++i
){
684 int header
= exceptionTable
->horizontalHeader()->sectionSizeHint(i
);
687 header
= fm
.width(QLatin1String("averagebiglonghost.domain.com"));
690 header
= fm
.width(QLatin1String("Allow For Session"));
693 int buffer
= fm
.width(QLatin1String("xx"));
695 exceptionTable
->horizontalHeader()->resizeSection(i
, header
);
699 void CookiesExceptionsDialog::textChanged(const QString
&text
)
701 bool enabled
= !text
.isEmpty();
702 blockButton
->setEnabled(enabled
);
703 allowButton
->setEnabled(enabled
);
704 allowForSessionButton
->setEnabled(enabled
);
707 void CookiesExceptionsDialog::block()
709 if (domainLineEdit
->text().isEmpty())
711 m_exceptionsModel
->m_blockedCookies
.append(domainLineEdit
->text());
712 m_cookieJar
->setBlockedCookies(m_exceptionsModel
->m_blockedCookies
);
713 m_exceptionsModel
->reset();
716 void CookiesExceptionsDialog::allow()
718 if (domainLineEdit
->text().isEmpty())
720 m_exceptionsModel
->m_allowedCookies
.append(domainLineEdit
->text());
721 m_cookieJar
->setAllowedCookies(m_exceptionsModel
->m_allowedCookies
);
722 m_exceptionsModel
->reset();
725 void CookiesExceptionsDialog::allowForSession()
727 if (domainLineEdit
->text().isEmpty())
729 m_exceptionsModel
->m_sessionCookies
.append(domainLineEdit
->text());
730 m_cookieJar
->setAllowForSessionCookies(m_exceptionsModel
->m_sessionCookies
);
731 m_exceptionsModel
->reset();