• Skip to content
  • Skip to link menu
KDE 4.1 API Reference
  • KDE API Reference
  • kdelibs
  • Sitemap
  • Contact Us
 

KIOSlave

kcookiejar.cpp

Go to the documentation of this file.
00001 /* This file is part of the KDE File Manager
00002 
00003    Copyright (C) 1998-2000 Waldo Bastian (bastian@kde.org)
00004    Copyright (C) 2000,2001 Dawit Alemayehu (adawit@kde.org)
00005 
00006    Permission is hereby granted, free of charge, to any person obtaining a copy
00007    of this software and associated documentation files (the "Software"), to deal
00008    in the Software without restriction, including without limitation the rights
00009    to use, copy, modify, merge, publish, distribute, and/or sell copies of the
00010    Software, and to permit persons to whom the Software is furnished to do so,
00011    subject to the following conditions:
00012 
00013    The above copyright notice and this permission notice shall be included in
00014    all copies or substantial portions of the Software.
00015 
00016    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00017    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00018    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
00019    AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
00020    ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
00021    WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00022 */
00023 //----------------------------------------------------------------------------
00024 //
00025 // KDE File Manager -- HTTP Cookies
00026 
00027 //
00028 // The cookie protocol is a mess. RFC2109 is a joke since nobody seems to
00029 // use it. Apart from that it is badly written.
00030 // We try to implement Netscape Cookies and try to behave us according to
00031 // RFC2109 as much as we can.
00032 //
00033 // We assume cookies do not contain any spaces (Netscape spec.)
00034 // According to RFC2109 this is allowed though.
00035 //
00036 
00037 #include "kcookiejar.h"
00038 
00039 #include <config.h>
00040 #include <sys/types.h>
00041 #include <sys/stat.h>
00042 #ifdef HAVE_SYS_PARAM_H
00043 #include <sys/param.h>
00044 #endif
00045 #include <fcntl.h>
00046 #include <unistd.h>
00047 #include <stdio.h>
00048 #include <string.h>
00049 
00050 #ifdef USE_SOLARIS
00051 #include <strings.h>
00052 #endif
00053 
00054 #include <stdlib.h>
00055 
00056 //#include <netinet/in.h>
00057 //#include <arpa/inet.h>
00058 
00059 #include <QtCore/QString>
00060 #include <QtCore/QFile>
00061 #include <QtCore/QDir>
00062 #include <QtCore/QRegExp>
00063 #include <QtCore/QTextStream>
00064 
00065 #include <kurl.h>
00066 #include <kdatetime.h>
00067 #include <kconfig.h>
00068 #include <kconfiggroup.h>
00069 #include <ksavefile.h>
00070 #include <kdebug.h>
00071 
00072 #include <algorithm>
00073 
00074 // BR87227
00075 // Waba: Should the number of cookies be limited?
00076 // I am not convinced of the need of such limit
00077 // Mozilla seems to limit to 20 cookies / domain
00078 // but it is unclear which policy it uses to expire
00079 // cookies when it exceeds that amount
00080 #undef MAX_COOKIE_LIMIT
00081 
00082 #define MAX_COOKIES_PER_HOST 25
00083 #define READ_BUFFER_SIZE 8192
00084 #define IP_ADDRESS_EXPRESSION "(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)"
00085 
00086 // Note with respect to QString::fromLatin1( )
00087 // Cookies are stored as 8 bit data and passed to kio_http as
00088 // latin1 regardless of their actual encoding.
00089 
00090 // L1 is used to indicate latin1 constants
00091 #define L1(x) QString::fromLatin1(x)
00092 
00093 QString KCookieJar::adviceToStr(KCookieAdvice _advice)
00094 {
00095     switch( _advice )
00096     {
00097     case KCookieAccept: return L1("Accept");
00098     case KCookieReject: return L1("Reject");
00099     case KCookieAsk: return L1("Ask");
00100     default: return L1("Dunno");
00101     }
00102 }
00103 
00104 KCookieAdvice KCookieJar::strToAdvice(const QString &_str)
00105 {
00106     if (_str.isEmpty())
00107         return KCookieDunno;
00108 
00109     QString advice = _str.toLower();
00110 
00111     if (advice == QLatin1String("accept"))
00112         return KCookieAccept;
00113     else if (advice == QLatin1String("reject"))
00114         return KCookieReject;
00115     else if (advice == QLatin1String("ask"))
00116         return KCookieAsk;
00117 
00118     return KCookieDunno;
00119 }
00120 
00121 // KHttpCookie
00123 
00124 //
00125 // Cookie constructor
00126 //
00127 KHttpCookie::KHttpCookie(const QString &_host,
00128                  const QString &_domain,
00129                  const QString &_path,
00130                  const QString &_name,
00131                  const QString &_value,
00132                  time_t _expireDate,
00133                  int _protocolVersion,
00134                  bool _secure,
00135                  bool _httpOnly,
00136                  bool _explicitPath) :
00137        mHost(_host),
00138        mDomain(_domain),
00139        mPath(_path.isEmpty() ? QString() : _path),
00140        mName(_name),
00141        mValue(_value),
00142        mExpireDate(_expireDate),
00143        mProtocolVersion(_protocolVersion),
00144        mSecure(_secure),
00145        mHttpOnly(_httpOnly),
00146        mExplicitPath(_explicitPath)
00147 {
00148 }
00149 
00150 //
00151 // Checks if a cookie has been expired
00152 //
00153 bool    KHttpCookie::isExpired(time_t currentDate) const
00154 {
00155     return (mExpireDate != 0) && (mExpireDate < currentDate);
00156 }
00157 
00158 //
00159 // Returns a string for a HTTP-header
00160 //
00161 QString KHttpCookie::cookieStr(bool useDOMFormat) const
00162 {
00163     QString result;
00164 
00165     if (useDOMFormat || (mProtocolVersion == 0))
00166     {
00167         if ( !mName.isEmpty() )
00168            result = mName + '=';
00169         result += mValue;
00170     }
00171     else
00172     {
00173         result = mName + '=' + mValue;
00174         if (mExplicitPath)
00175             result += L1("; $Path=\"") + mPath + L1("\"");
00176         if (!mDomain.isEmpty())
00177             result += L1("; $Domain=\"") + mDomain + L1("\"");
00178     }
00179     return result;
00180 }
00181 
00182 //
00183 // Returns whether this cookie should be send to this location.
00184 bool KHttpCookie::match(const QString &fqdn, const QStringList &domains,
00185                         const QString &path) const
00186 {
00187     // Cookie domain match check
00188     if (mDomain.isEmpty())
00189     {
00190        if (fqdn != mHost)
00191           return false;
00192     }
00193     else if (!domains.contains(mDomain))
00194     {
00195         if (mDomain[0] == '.')
00196             return false;
00197 
00198         // Maybe the domain needs an extra dot.
00199         QString domain = '.' + mDomain;
00200         if ( !domains.contains( domain ) )
00201           if ( fqdn != mDomain )
00202             return false;
00203     }
00204 
00205     // Cookie path match check
00206     if (mPath.isEmpty())
00207         return true;
00208 
00209     // According to the netscape spec both http://www.acme.com/foobar,
00210     // http://www.acme.com/foo.bar and http://www.acme.com/foo/bar
00211     // match http://www.acme.com/foo.
00212     // We only match http://www.acme.com/foo/bar
00213 
00214     if( path.startsWith(mPath) &&
00215         (
00216          (path.length() == mPath.length() ) ||  // Paths are exact match
00217           mPath.endsWith('/') ||            // mPath ended with a slash
00218          (path[mPath.length()] == '/')      // A slash follows
00219          ))
00220         return true; // Path of URL starts with cookie-path
00221 
00222     return false;
00223 }
00224 
00225 // KCookieJar
00227 
00228 //
00229 // Constructs a new cookie jar
00230 //
00231 // One jar should be enough for all cookies.
00232 //
00233 KCookieJar::KCookieJar()
00234 {
00235     m_globalAdvice = KCookieDunno;
00236     m_configChanged = false;
00237     m_cookiesChanged = false;
00238 
00239     KConfig cfg( "khtml/domain_info", KConfig::NoGlobals, "data" );
00240     KConfigGroup group( &cfg, QString() );
00241     QStringList countries = group.readEntry( "twoLevelTLD", QStringList() );
00242     foreach ( const QString& country, countries ) {
00243        m_twoLevelTLD.insert( country, 1 );
00244     }
00245 }
00246 
00247 //
00248 // Destructs the cookie jar
00249 //
00250 // Poor little cookies, they will all be eaten by the cookie monster!
00251 //
00252 KCookieJar::~KCookieJar()
00253 {
00254     qDeleteAll(m_cookieDomains);
00255     // Not much to do here
00256 }
00257 
00258 // cookiePtr is modified: the window ids of the existing cookie in the list are added to it
00259 static void removeDuplicateFromList(KHttpCookieList *list, KHttpCookie& cookiePtr, bool nameMatchOnly=false, bool updateWindowId=false)
00260 {
00261     QString domain1 = cookiePtr.domain();
00262     if (domain1.isEmpty())
00263        domain1 = cookiePtr.host();
00264 
00265     QMutableListIterator<KHttpCookie> cookieIterator(*list);
00266     while (cookieIterator.hasNext()) {
00267         const KHttpCookie& cookie = cookieIterator.next();
00268         QString domain2 = cookie.domain();
00269         if (domain2.isEmpty())
00270             domain2 = cookie.host();
00271 
00272         if (
00273             (cookiePtr.name() == cookie.name()) &&
00274             (
00275               nameMatchOnly ||
00276               ( (domain1 == domain2) && (cookiePtr.path() == cookie.path()) )
00277             )
00278           ) {
00279             if (updateWindowId) {
00280                 Q_FOREACH(long windowId, cookie.windowIds()) {
00281                     if (windowId && (!cookiePtr.windowIds().contains(windowId))) {
00282                         cookiePtr.windowIds().append(windowId);
00283                     }
00284                 }
00285             }
00286             cookieIterator.remove();
00287             break;
00288         }
00289     }
00290 }
00291 
00292 
00293 //
00294 // Looks for cookies in the cookie jar which are appropriate for _url.
00295 // Returned is a string containing all appropriate cookies in a format
00296 // which can be added to a HTTP-header without any additional processing.
00297 //
00298 QString KCookieJar::findCookies(const QString &_url, bool useDOMFormat, long windowId, KHttpCookieList *pendingCookies)
00299 {
00300     QString cookieStr;
00301     QStringList domains;
00302     QString fqdn;
00303     QString path;
00304     KCookieAdvice advice = m_globalAdvice;
00305 
00306     if (!parseUrl(_url, fqdn, path))
00307         return cookieStr;
00308 
00309     bool secureRequest = _url.startsWith( L1("https://"), Qt::CaseInsensitive ) ||
00310                          _url.startsWith( L1("webdavs://"), Qt::CaseInsensitive );
00311 
00312     extractDomains(fqdn, domains);
00313 
00314     KHttpCookieList allCookies;
00315 
00316     for(QStringList::ConstIterator it = domains.begin();
00317         true;
00318         ++it)
00319     {
00320        KHttpCookieList *cookieList;
00321        if (it == domains.end())
00322        {
00323           cookieList = pendingCookies; // Add pending cookies
00324           pendingCookies = 0;
00325           if (!cookieList)
00326              break;
00327        }
00328        else
00329        {
00330           QString key = (*it).isNull() ? L1("") : (*it);
00331           cookieList = m_cookieDomains.value(key);
00332           if (!cookieList)
00333              continue; // No cookies for this domain
00334        }
00335 
00336        if (cookieList->getAdvice() != KCookieDunno)
00337           advice = cookieList->getAdvice();
00338 
00339         for (KHttpCookieList::iterator cookieIterator = cookieList->begin();
00340              cookieIterator != cookieList->end();
00341              ++cookieIterator ) {
00342             KHttpCookie& cookie = *cookieIterator;
00343             // If the we are setup to automatically accept all session cookies and to
00344             // treat all cookies as session cookies or the current cookie is a session
00345             // cookie, then send the cookie back regardless of domain policy.
00346             if (advice == KCookieReject &&
00347                 !(m_autoAcceptSessionCookies &&
00348                   (m_ignoreCookieExpirationDate || cookie.expireDate() == 0)))
00349                 continue;
00350 
00351           if (!cookie.match(fqdn, domains, path))
00352              continue;
00353 
00354           if( cookie.isSecure() && !secureRequest )
00355              continue;
00356 
00357           if( cookie.isHttpOnly() && useDOMFormat )
00358              continue;
00359 
00360           // Do not send expired cookies.
00361           if ( cookie.isExpired (time(0)) )
00362           {
00363              // Note there is no need to actually delete the cookie here
00364              // since the cookieserver will invoke ::saveCookieJar because
00365              // of the state change below. This will then do the job of
00366              // deleting the cookie for us.
00367              m_cookiesChanged = true;
00368              continue;
00369           }
00370 
00371           if (windowId && (cookie.windowIds().indexOf(windowId) == -1))
00372           {
00373              cookie.windowIds().append(windowId);
00374           }
00375 
00376           if (it == domains.end()) // Only needed when processing pending cookies
00377              removeDuplicateFromList(&allCookies, cookie);
00378 
00379           allCookies.append(cookie);
00380        }
00381        if (it == domains.end())
00382           break; // Finished.
00383     }
00384 
00385     int cookieCount = 0;
00386 
00387     int protVersion=0;
00388     Q_FOREACH(const KHttpCookie& cookie, allCookies) {
00389         if (cookie.protocolVersion() > protVersion)
00390             protVersion = cookie.protocolVersion();
00391     }
00392 
00393     Q_FOREACH(const KHttpCookie& cookie, allCookies) {
00394         if (useDOMFormat) {
00395             if (cookieCount > 0)
00396                 cookieStr += L1("; ");
00397             cookieStr += cookie.cookieStr(true);
00398         } else {
00399             if (cookieCount == 0) {
00400                 cookieStr += L1("Cookie: ");
00401                 if (protVersion > 0) {
00402                     QString version;
00403                     version.sprintf("$Version=%d; ", protVersion); // Without quotes
00404                     cookieStr += version;
00405                 }
00406             } else {
00407                 cookieStr += L1("; ");
00408             }
00409             cookieStr += cookie.cookieStr(false);
00410         }
00411         cookieCount++;
00412     }
00413 
00414     return cookieStr;
00415 }
00416 
00417 //
00418 // This function parses a string like 'my_name="my_value";' and returns
00419 // 'my_name' in Name and 'my_value' in Value.
00420 //
00421 // A pointer to the end of the parsed part is returned.
00422 // This pointer points either to:
00423 // '\0' - The end of the string has reached.
00424 // ';'  - Another my_name="my_value" pair follows
00425 // ','  - Another cookie follows
00426 // '\n' - Another header follows
00427 static const char * parseNameValue(const char *header,
00428                                   QString &Name,
00429                                   QString &Value,
00430                                   bool keepQuotes=false,
00431                                   bool rfcQuotes=false)
00432 {
00433     const char *s = header;
00434     // Parse 'my_name' part
00435     for(; (*s != '='); s++)
00436     {
00437         if ((*s=='\0') || (*s==';') || (*s=='\n'))
00438         {
00439             // No '=' sign -> use string as the value, name is empty
00440             // (behavior found in Mozilla and IE)
00441             Name = "";
00442             Value = QString::fromLatin1(header);
00443             Value.truncate( s - header );
00444             Value = Value.trimmed();
00445             return (s);
00446         }
00447     }
00448 
00449     Name = header;
00450     Name.truncate( s - header );
00451     Name = Name.trimmed();
00452 
00453     // *s == '='
00454     s++;
00455 
00456     // Skip any whitespace
00457     for(; (*s == ' ') || (*s == '\t'); s++)
00458     {
00459         if ((*s=='\0') || (*s==';') || (*s=='\n'))
00460         {
00461             // End of Name
00462             Value = "";
00463             return (s);
00464         }
00465     }
00466 
00467     if ((rfcQuotes || !keepQuotes) && (*s == '\"'))
00468     {
00469         // Parse '"my_value"' part (quoted value)
00470         if (keepQuotes)
00471            header = s++;
00472         else
00473            header = ++s; // skip "
00474         for(;(*s != '\"');s++)
00475         {
00476             if ((*s=='\0') || (*s=='\n'))
00477             {
00478                 // End of Name
00479                 Value = QString::fromLatin1(header);
00480                 Value.truncate(s - header);
00481                 return (s);
00482             }
00483         }
00484         Value = QString::fromLatin1(header);
00485         // *s == '\"';
00486         if (keepQuotes)
00487            Value.truncate( ++s - header );
00488         else
00489            Value.truncate( s++ - header );
00490 
00491         // Skip any remaining garbage
00492         for(;; s++)
00493         {
00494             if ((*s=='\0') || (*s==';') || (*s=='\n'))
00495                 break;
00496         }
00497     }
00498     else
00499     {
00500         // Parse 'my_value' part (unquoted value)
00501         header = s;
00502         while ((*s != '\0') && (*s != ';') && (*s != '\n'))
00503             s++;
00504         // End of Name
00505         Value = QString::fromLatin1(header);
00506         Value.truncate( s - header );
00507         Value = Value.trimmed();
00508     }
00509     return (s);
00510 
00511 }
00512 
00513 void KCookieJar::stripDomain(const QString &_fqdn, QString &_domain)
00514 {
00515    QStringList domains;
00516    extractDomains(_fqdn, domains);
00517    if (domains.count() > 3)
00518       _domain = domains[3];
00519    else
00520       _domain = domains[0];
00521 }
00522 
00523 QString KCookieJar::stripDomain(const KHttpCookie& cookie)
00524 {
00525     QString domain; // We file the cookie under this domain.
00526     if (cookie.domain().isEmpty())
00527        stripDomain( cookie.host(), domain);
00528     else
00529        stripDomain( cookie.domain(), domain);
00530     return domain;
00531 }
00532 
00533 bool KCookieJar::parseUrl(const QString &_url,
00534                           QString &_fqdn,
00535                           QString &_path)
00536 {
00537     KUrl kurl(_url);
00538     if (!kurl.isValid())
00539        return false;
00540 
00541     _fqdn = kurl.host().toLower();
00542     if (kurl.port() > 0)
00543     {
00544        if (((kurl.protocol() == L1("http")) && (kurl.port() != 80)) ||
00545            ((kurl.protocol() == L1("https")) && (kurl.port() != 443)))
00546        {
00547           // It's <port>:<host> so that the sorting works as expected
00548           _fqdn = L1("%1:%2").arg(kurl.port()).arg(_fqdn);
00549        }
00550     }
00551 
00552     // Cookie spoofing protection.  Since there is no way a path separator
00553     // or escape encoded character is allowed in the hostname according
00554     // to RFC 2396, reject attempts to include such things there!
00555     if(_fqdn.contains('/') || _fqdn.contains('%'))
00556     {
00557         return false;  // deny everything!!
00558     }
00559 
00560     _path = kurl.path();
00561     if (_path.isEmpty())
00562        _path = L1("/");
00563 
00564     QRegExp exp(L1("[\\\\/]\\.\\.[\\\\/]"));
00565     // Weird path, cookie stealing attempt?
00566     if (exp.indexIn(_path) != -1)
00567        return false; // Deny everything!!
00568 
00569     return true;
00570 }
00571 
00572 void KCookieJar::extractDomains(const QString &_fqdn,
00573                                 QStringList &_domains) const
00574 {
00575     if (_fqdn.isEmpty()) // localhost...
00576         return;
00577 
00578     // Return numeric IPv6 addresses as is...
00579     if (_fqdn[0] == '[')
00580     {
00581        _domains.append( _fqdn );
00582        return;
00583     }
00584     // Return numeric IPv4 addresses as is...
00585     if ((_fqdn[0] >= '0') && (_fqdn[0] <= '9'))
00586     {
00587        if (_fqdn.indexOf(QRegExp(IP_ADDRESS_EXPRESSION)) > -1)
00588        {
00589           _domains.append( _fqdn );
00590           return;
00591        }
00592     }
00593 
00594     QStringList partList = _fqdn.split('.', QString::SkipEmptyParts);
00595 
00596     if (partList.count())
00597         partList.erase(partList.begin()); // Remove hostname
00598 
00599     while(partList.count())
00600     {
00601 
00602        if (partList.count() == 1)
00603          break; // We only have a TLD left.
00604 
00605        if ((partList.count() == 2) && (m_twoLevelTLD.value(partList[1].toLower(), 0) == 1))
00606        {
00607           // This domain uses two-level TLDs in the form xxxx.yy
00608           break;
00609        }
00610 
00611        if ((partList.count() == 2) && (partList[1].length() == 2))
00612        {
00613           // If this is a TLD, we should stop. (e.g. co.uk)
00614           // We assume this is a TLD if it ends with .xx.yy or .x.yy
00615           if (partList[0].length() <= 2)
00616              break; // This is a TLD.
00617 
00618           // Catch some TLDs that we miss with the previous check
00619           // e.g. com.au, org.uk, mil.co
00620           const QString t = partList[0].toLower();
00621           if ((t == "com") || (t == "net") || (t == "org") || (t == "gov") || (t == "edu") || (t == "mil") || (t == "int"))
00622               break;
00623        }
00624 
00625        QString domain = partList.join(L1("."));
00626        _domains.append(domain);
00627        _domains.append('.' + domain);
00628        partList.erase(partList.begin()); // Remove part
00629     }
00630 
00631     // Always add the FQDN at the start of the list for
00632     // hostname == cookie-domainname checks!
00633     _domains.prepend( '.' + _fqdn );
00634     _domains.prepend( _fqdn );
00635 }
00636 
00637 /*
00638    Changes dates in from the following format
00639 
00640       Wed Sep 12 07:00:00 2007 GMT
00641    to
00642       Wed Sep 12 2007 07:00:00 GMT
00643 
00644    to allow KDateTime::fromString to properly parse expiration date formats
00645    used in cookies by some servers such as amazon.com. See BR# 145244.
00646 */
00647 static QString fixupDateTime(const QString& date)
00648 {
00649   QStringList list = date.split(' ');
00650   const int index = list.indexOf(QRegExp("[0-9]{1,2}:[0-9]{1,2}:[0-9]{1,2}"));
00651 
00652   if (index > -1 && (index+1) < list.count())
00653   {
00654     list.insert(index+1, list.takeAt(index));
00655     return list.join(" ");
00656   }
00657 
00658   return date;
00659 }
00660 
00661 //
00662 // This function parses cookie_headers and returns a linked list of
00663 // KHttpCookie objects for all cookies found in cookie_headers.
00664 // If no cookies could be found 0 is returned.
00665 //
00666 // cookie_headers should be a concatenation of all lines of a HTTP-header
00667 // which start with "Set-Cookie". The lines should be separated by '\n's.
00668 //
00669 KHttpCookieList KCookieJar::makeCookies(const QString &_url,
00670                                        const QByteArray &cookie_headers,
00671                                        long windowId)
00672 {
00673     KHttpCookieList cookieList;
00674     KHttpCookieList cookieList2;
00675     KHttpCookieList::iterator lastCookie = cookieList.end();
00676     const char *cookieStr = cookie_headers.data();
00677     QString Name;
00678     QString Value;
00679     QString fqdn;
00680     QString path;
00681     bool crossDomain = false;
00682 
00683     if (!parseUrl(_url, fqdn, path))
00684     {
00685         // Error parsing _url
00686         return KHttpCookieList();
00687     }
00688     QString defaultPath;
00689     int i = path.lastIndexOf('/');
00690     if (i > 0)
00691        defaultPath = path.left(i);
00692 
00693     //  The hard stuff :)
00694     for(;;)
00695     {
00696         // check for "Set-Cookie"
00697         if (strncmp(cookieStr, "Cross-Domain\n", 13) == 0)
00698         {
00699             cookieStr += 13;
00700             crossDomain = true;
00701         }
00702         else if (strncasecmp(cookieStr, "Set-Cookie:", 11) == 0)
00703         {
00704             cookieStr = parseNameValue(cookieStr+11, Name, Value, true);
00705 
00706             // Host = FQDN
00707             // Default domain = ""
00708             // Default path according to rfc2109
00709 
00710             KHttpCookie cookie(fqdn, L1(""), defaultPath, Name, Value);
00711             if (windowId)
00712                cookie.mWindowIds.append(windowId);
00713             cookie.mCrossDomain = crossDomain;
00714 
00715             // Insert cookie in chain
00716             cookieList.append(cookie);
00717             lastCookie = cookieList.end(); --lastCookie;
00718         }
00719         else if (strncasecmp(cookieStr, "Set-Cookie2:", 12) == 0)
00720         {
00721             // Attempt to follow rfc2965
00722             cookieStr = parseNameValue(cookieStr+12, Name, Value, true, true);
00723 
00724             // Host = FQDN
00725             // Default domain = ""
00726             // Default path according to rfc2965
00727 
00728             KHttpCookie cookie(fqdn, L1(""), defaultPath, Name, Value);
00729             if (windowId)
00730                cookie.mWindowIds.append(windowId);
00731             cookie.mCrossDomain = crossDomain;
00732 
00733             // Insert cookie in chain
00734             cookieList2.append(cookie);
00735             lastCookie = cookieList2.end(); --lastCookie;
00736         }
00737         else
00738         {
00739             // This is not the start of a cookie header, skip till next line.
00740             while (*cookieStr && *cookieStr != '\n')
00741                 cookieStr++;
00742 
00743             if (*cookieStr == '\n')
00744                 cookieStr++;
00745 
00746             if (!*cookieStr)
00747                 break; // End of cookie_headers
00748             else
00749                 continue; // end of this header, continue with next.
00750         }
00751 
00752         while ((*cookieStr == ';') || (*cookieStr == ' '))
00753         {
00754             cookieStr++;
00755 
00756             // Name-Value pair follows
00757             cookieStr = parseNameValue(cookieStr, Name, Value);
00758 
00759             QString cName = Name.toLower();
00760             if (cName == "domain")
00761             {
00762                 QString dom = Value.toLower();
00763                 // RFC2965 3.2.2: If an explicitly specified value does not
00764                 // start with a dot, the user agent supplies a leading dot
00765                 if(dom.length() && dom[0] != '.')
00766                     dom.prepend(".");
00767                 // remove a trailing dot
00768                 if(dom.length() > 2 && dom[dom.length()-1] == '.')
00769                     dom = dom.left(dom.length()-1);
00770 
00771                 if(dom.count('.') > 1 || dom == ".local")
00772                     lastCookie->mDomain = dom;
00773             }
00774             else if (cName == "max-age")
00775             {
00776                 int max_age = Value.toInt();
00777                 if (max_age == 0)
00778                     lastCookie->mExpireDate = 1;
00779                 else
00780                     lastCookie->mExpireDate = time(0)+max_age;
00781             }
00782             else if (cName == "expires")
00783             {
00784                 // Parse brain-dead netscape cookie-format
00785                 lastCookie->mExpireDate = KDateTime::fromString(Value, KDateTime::RFCDate).toTime_t();
00786 
00787                 // Workaround for servers that send the expiration date in
00788                 // 'Wed Sep 12 07:00:00 2007 GMT' format. See BR# 145244.
00789                 if (lastCookie->mExpireDate == -1)
00790                   lastCookie->mExpireDate = KDateTime::fromString(fixupDateTime(Value), KDateTime::RFCDate).toTime_t();
00791 
00792                 // We encode parse error/invalid as 0, but KDateTime likes -1, so convert
00793                 if (lastCookie->mExpireDate == -1)
00794                   lastCookie->mExpireDate = 0;
00795             }
00796             else if (cName == "path")
00797             {
00798                 if (Value.isEmpty())
00799                    lastCookie->mPath = QString(); // Catch "" <> QString()
00800                 else
00801                    lastCookie->mPath = QUrl::fromPercentEncoding(Value.toLatin1());
00802                 lastCookie->mExplicitPath = true;
00803             }
00804             else if (cName == "version")
00805             {
00806                 lastCookie->mProtocolVersion = Value.toInt();
00807             }
00808             else if ((cName == "secure") ||
00809                      (cName.isEmpty() && Value.toLower() == L1("secure")))
00810             {
00811                 lastCookie->mSecure = true;
00812             }
00813             else if ((cName == "httponly") ||
00814                      (cName.isEmpty() && Value.toLower() == L1("httponly")))
00815             {
00816                 lastCookie->mHttpOnly = true;
00817             }
00818         }
00819 
00820         if (*cookieStr == '\0')
00821             break; // End of header
00822 
00823         // Skip ';' or '\n'
00824         cookieStr++;
00825     }
00826 
00827     // RFC2965 cookies come last so that they override netscape cookies.
00828     while(!cookieList2.isEmpty()) {
00829         lastCookie = cookieList2.begin();
00830         removeDuplicateFromList(&cookieList, *lastCookie, true);
00831         cookieList.append(*lastCookie);
00832         cookieList2.removeFirst();
00833     }
00834 
00835     return cookieList;
00836 }
00837 
00844 KHttpCookieList KCookieJar::makeDOMCookies(const QString &_url,
00845                                            const QByteArray &cookie_domstring,
00846                                            long windowId)
00847 {
00848     // A lot copied from above
00849     KHttpCookieList cookieList;
00850 
00851     const char *cookieStr = cookie_domstring.data();
00852     QString fqdn;
00853     QString path;
00854 
00855     if (!parseUrl(_url, fqdn, path))
00856     {
00857         // Error parsing _url
00858         return KHttpCookieList();
00859     }
00860 
00861     QString Name;
00862     QString Value;
00863     //  This time it's easy
00864     while(*cookieStr)
00865     {
00866         cookieStr = parseNameValue(cookieStr, Name, Value);
00867 
00868         // Host = FQDN
00869         // Default domain = ""
00870         // Default path = ""
00871         KHttpCookie cookie(fqdn, QString(), QString(),
00872                            Name, Value );
00873         if (windowId)
00874             cookie.mWindowIds.append(windowId);
00875 
00876         cookieList.append(cookie);
00877 
00878         if (*cookieStr != '\0')
00879             cookieStr++;         // Skip ';' or '\n'
00880     }
00881 
00882     return cookieList;
00883 }
00884 
00885 // KHttpCookieList sorting
00887 
00888 // We want the longest path first
00889 static bool compareCookies(const KHttpCookie& item1, const KHttpCookie& item2)
00890 {
00891     return item1.path().length() > item2.path().length();
00892 }
00893 
00894 
00895 #ifdef MAX_COOKIE_LIMIT
00896 static void makeRoom(KHttpCookieList *cookieList, KHttpCookiePtr &cookiePtr)
00897 {
00898      // Too many cookies: throw one away, try to be somewhat clever
00899      KHttpCookiePtr lastCookie = 0;
00900      for(KHttpCookiePtr cookie = cookieList->first(); cookie; cookie = cookieList->next())
00901      {
00902          if (compareCookies(cookie, cookiePtr))
00903             break;
00904          lastCookie = cookie;
00905      }
00906      if (!lastCookie)
00907          lastCookie = cookieList->first();
00908      cookieList->removeRef(lastCookie);
00909 }
00910 #endif
00911 
00912 //
00913 // This function hands a KHttpCookie object over to the cookie jar.
00914 //
00915 void KCookieJar::addCookie(KHttpCookie &cookie)
00916 {
00917     QStringList domains;
00918     KHttpCookieList *cookieList = 0L;
00919 
00920     // We always need to do this to make sure that the
00921     // that cookies of type hostname == cookie-domainname
00922     // are properly removed and/or updated as necessary!
00923     extractDomains( cookie.host(), domains );
00924     for ( QStringList::ConstIterator it = domains.begin();
00925           (it != domains.end() && !cookieList);
00926           ++it )
00927     {
00928         QString key = (*it).isNull() ? L1("") : (*it);
00929         KHttpCookieList *list= m_cookieDomains.value(key);
00930         if ( !list ) continue;
00931 
00932         removeDuplicateFromList(list, cookie, false, true);
00933     }
00934 
00935     QString domain = stripDomain( cookie );
00936     QString key = domain.isNull() ? L1("") : domain;
00937     cookieList = m_cookieDomains.value(key);
00938     if (!cookieList)
00939     {
00940         // Make a new cookie list
00941         cookieList = new KHttpCookieList();
00942 
00943         // All cookies whose domain is not already
00944         // known to us should be added with KCookieDunno.
00945         // KCookieDunno means that we use the global policy.
00946         cookieList->setAdvice( KCookieDunno );
00947 
00948         m_cookieDomains.insert( domain, cookieList);
00949 
00950         // Update the list of domains
00951         m_domainList.append(domain);
00952     }
00953 
00954     // Add the cookie to the cookie list
00955     // The cookie list is sorted 'longest path first'
00956     if (!cookie.isExpired(time(0)))
00957     {
00958 #ifdef MAX_COOKIE_LIMIT
00959         if (cookieList->count() >= MAX_COOKIES_PER_HOST)
00960            makeRoom(cookieList, cookie); // Delete a cookie
00961 #endif
00962         cookieList->push_back(cookie);
00963         // Use a stable sort so that unit tests are reliable.
00964         // In practice it doesn't matter though.
00965         qStableSort(cookieList->begin(), cookieList->end(), compareCookies);
00966 
00967         m_cookiesChanged = true;
00968     }
00969 }
00970 
00971 //
00972 // This function advices whether a single KHttpCookie object should
00973 // be added to the cookie jar.
00974 //
00975 KCookieAdvice KCookieJar::cookieAdvice(KHttpCookie& cookie)
00976 {
00977     if (m_rejectCrossDomainCookies && cookie.isCrossDomain())
00978        return KCookieReject;
00979 
00980     QStringList domains;
00981     extractDomains(cookie.host(), domains);
00982 
00983     // If the cookie specifies a domain, check whether it is valid. Otherwise,
00984     // accept the cookie anyways but removes the domain="" value to prevent
00985     // cross-site cookie injection.
00986     if (!cookie.domain().isEmpty())
00987     {
00988       if (!domains.contains(cookie.domain()) &&
00989           !cookie.domain().endsWith('.'+cookie.host()))
00990          cookie.fixDomain(QString());
00991     }
00992 
00993     if (m_autoAcceptSessionCookies && (cookie.expireDate() == 0 ||
00994         m_ignoreCookieExpirationDate))
00995        return KCookieAccept;
00996 
00997     KCookieAdvice advice = KCookieDunno;
00998     bool isFQDN = true; // First is FQDN
00999     QStringList::Iterator it = domains.begin(); // Start with FQDN which first in the list.
01000     while( (advice == KCookieDunno) && (it != domains.end()))
01001     {
01002        QString domain = *it;
01003        // Check if a policy for the FQDN/domain is set.
01004        if ( domain.startsWith('.') || isFQDN )
01005        {
01006           isFQDN = false;
01007           KHttpCookieList *cookieList = m_cookieDomains.value(domain);
01008           if (cookieList)
01009              advice = cookieList->getAdvice();
01010        }
01011        domains.erase(it);
01012        it = domains.begin(); // Continue from begin of remaining list
01013     }
01014 
01015     if (advice == KCookieDunno)
01016         advice = m_globalAdvice;
01017 
01018     return advice;
01019 }
01020 
01021 //
01022 // This function gets the advice for all cookies originating from
01023 // _domain.
01024 //
01025 KCookieAdvice KCookieJar::getDomainAdvice(const QString &_domain)
01026 {
01027     KHttpCookieList *cookieList = m_cookieDomains.value(_domain);
01028     KCookieAdvice advice;
01029 
01030     if (cookieList)
01031     {
01032         advice = cookieList->getAdvice();
01033     }
01034     else
01035     {
01036         advice = KCookieDunno;
01037     }
01038 
01039     return advice;
01040 }
01041 
01042 //
01043 // This function sets the advice for all cookies originating from
01044 // _domain.
01045 //
01046 void KCookieJar::setDomainAdvice(const QString &_domain, KCookieAdvice _advice)
01047 {
01048     QString domain(_domain);
01049     KHttpCookieList *cookieList = m_cookieDomains.value(domain);
01050 
01051     if (cookieList)
01052     {
01053         if (cookieList->getAdvice() != _advice)
01054         {
01055            m_configChanged = true;
01056            // domain is already known
01057            cookieList->setAdvice( _advice);
01058         }
01059 
01060         if ((cookieList->isEmpty()) &&
01061             (_advice == KCookieDunno))
01062         {
01063             // This deletes cookieList!
01064             delete m_cookieDomains.take(domain);
01065             m_domainList.removeAll(domain);
01066         }
01067     }
01068     else
01069     {
01070         // domain is not yet known
01071         if (_advice != KCookieDunno)
01072         {
01073             // We should create a domain entry
01074             m_configChanged = true;
01075             // Make a new cookie list
01076             cookieList = new KHttpCookieList();
01077             cookieList->setAdvice(_advice);
01078             m_cookieDomains.insert(domain, cookieList);
01079             // Update the list of domains
01080             m_domainList.append( domain);
01081         }
01082     }
01083 }
01084 
01085 //
01086 // This function sets the advice for all cookies originating from
01087 // the same domain as _cookie
01088 //
01089 void KCookieJar::setDomainAdvice(const KHttpCookie& cookie, KCookieAdvice _advice)
01090 {
01091     QString domain;
01092     stripDomain(cookie.host(), domain); // We file the cookie under this domain.
01093 
01094     setDomainAdvice(domain, _advice);
01095 }
01096 
01097 //
01098 // This function sets the global advice for cookies
01099 //
01100 void KCookieJar::setGlobalAdvice(KCookieAdvice _advice)
01101 {
01102     if (m_globalAdvice != _advice)
01103        m_configChanged = true;
01104     m_globalAdvice = _advice;
01105 }
01106 
01107 //
01108 // Get a list of all domains known to the cookie jar.
01109 //
01110 const QStringList& KCookieJar::getDomainList()
01111 {
01112     return m_domainList;
01113 }
01114 
01115 //
01116 // Get a list of all cookies in the cookie jar originating from _domain.
01117 //
01118 KHttpCookieList *KCookieJar::getCookieList(const QString & _domain,
01119                                            const QString & _fqdn )
01120 {
01121     QString domain;
01122 
01123     if (_domain.isEmpty())
01124         stripDomain( _fqdn, domain );
01125     else
01126         domain = _domain;
01127 
01128     return m_cookieDomains.value(domain);
01129 }
01130 
01131 //
01132 // Eat a cookie out of the jar.
01133 // cookieIterator should be one of the cookies returned by getCookieList()
01134 //
01135 void KCookieJar::eatCookie(KHttpCookieList::iterator cookieIterator)
01136 {
01137     const KHttpCookie& cookie = *cookieIterator;
01138     QString domain = stripDomain(cookie); // We file the cookie under this domain.
01139     KHttpCookieList *cookieList = m_cookieDomains.value(domain);
01140 
01141     if (cookieList) {
01142         // This deletes cookie!
01143         cookieList->erase(cookieIterator);
01144 
01145         if ((cookieList->isEmpty()) &&
01146             (cookieList->getAdvice() == KCookieDunno))
01147         {
01148             // This deletes cookieList!
01149             delete m_cookieDomains.take(domain);
01150 
01151             m_domainList.removeAll(domain);
01152         }
01153     }
01154 }
01155 
01156 void KCookieJar::eatCookiesForDomain(const QString &domain)
01157 {
01158    KHttpCookieList *cookieList = m_cookieDomains.value(domain);
01159    if (!cookieList || cookieList->isEmpty()) return;
01160 
01161    cookieList->clear();
01162    if (cookieList->getAdvice() == KCookieDunno)
01163    {
01164        // This deletes cookieList!
01165        delete m_cookieDomains.take(domain);
01166        m_domainList.removeAll(domain);
01167    }
01168    m_cookiesChanged = true;
01169 }
01170 
01171 void KCookieJar::eatSessionCookies( long windowId )
01172 {
01173     if (!windowId)
01174         return;
01175 
01176     QStringList::Iterator it=m_domainList.begin();
01177     for ( ; it != m_domainList.end(); ++it )
01178         eatSessionCookies( *it, windowId, false );
01179 }
01180 
01181 void KCookieJar::eatAllCookies()
01182 {
01183     for ( QStringList::Iterator it=m_domainList.begin();
01184           it != m_domainList.end();)
01185     {
01186         QString domain = *it++;
01187         // This might remove domain from domainList!
01188         eatCookiesForDomain(domain);
01189     }
01190 }
01191 
01192 void KCookieJar::eatSessionCookies( const QString& fqdn, long windowId,
01193                                     bool isFQDN )
01194 {
01195     KHttpCookieList* cookieList;
01196     if ( !isFQDN )
01197         cookieList = m_cookieDomains.value(fqdn);
01198     else {
01199         QString domain;
01200         stripDomain( fqdn, domain );
01201         cookieList = m_cookieDomains.value(domain);
01202     }
01203 
01204     if (cookieList) {
01205         QMutableListIterator<KHttpCookie> cookieIterator(*cookieList);
01206         while (cookieIterator.hasNext()) {
01207             KHttpCookie& cookie = cookieIterator.next();
01208             if ((cookie.expireDate() != 0) && !m_ignoreCookieExpirationDate) {
01209                continue;
01210             }
01211 
01212             QList<long> &ids = cookie.windowIds();
01213 
01214 #ifndef NDEBUG
01215             if (ids.contains(windowId)) {
01216                 if (ids.count() > 1)
01217                     kDebug() << "removing window id" << windowId << "from session cookie";
01218                 else
01219                     kDebug() << "deleting session cookie";
01220             }
01221 #endif
01222             if (!ids.removeAll(windowId) || !ids.isEmpty()) {
01223                continue;
01224             }
01225             cookieIterator.remove();
01226         }
01227     }
01228 }
01229 
01230 //
01231 // Saves all cookies to the file '_filename'.
01232 // On succes 'true' is returned.
01233 // On failure 'false' is returned.
01234 bool KCookieJar::saveCookies(const QString &_filename)
01235 {
01236     KSaveFile saveFile(_filename);
01237 
01238     if (!saveFile.open())
01239        return false;
01240     saveFile.setPermissions(QFile::ReadUser|QFile::WriteUser);
01241 
01242     QTextStream ts(&saveFile);
01243 
01244     time_t curTime = time(0);
01245 
01246     ts << "# KDE Cookie File v2\n#\n";
01247 
01248     QString s;
01249     s.sprintf("%-20s %-20s %-12s %-10s %-4s %-20s %-4s %s\n",
01250               "# Host", "Domain", "Path", "Exp.date", "Prot",
01251               "Name", "Sec", "Value");
01252     ts << s.toLatin1().constData();
01253 
01254     for ( QStringList::Iterator it=m_domainList.begin(); it != m_domainList.end();
01255           it++ )
01256     {
01257         const QString &domain = *it;
01258         bool domainPrinted = false;
01259 
01260         KHttpCookieList *cookieList = m_cookieDomains.value(domain);
01261         QMutableListIterator<KHttpCookie> cookieIterator(*cookieList);
01262         while (cookieIterator.hasNext()) {
01263             const KHttpCookie& cookie = cookieIterator.next();
01264             if (cookie.isExpired(curTime)) {
01265                 // Delete expired cookies
01266                 cookieIterator.remove();
01267             } else if (cookie.expireDate() != 0 && !m_ignoreCookieExpirationDate) {
01268                 // Only save cookies that are not "session-only cookies"
01269                 if (!domainPrinted) {
01270                     domainPrinted = true;
01271                     ts << '[' << domain.toLocal8Bit().data() << "]\n";
01272                 }
01273                 // Store persistent cookies
01274                 QString path = L1("\"");
01275                 path += cookie.path();
01276                 path += '"';
01277                 QString domain = L1("\"");
01278                 domain += cookie.domain();
01279                 domain += '"';
01280                 // TODO: replace with direct QTextStream output ?
01281                 s.sprintf("%-20s %-20s %-12s %10lu  %3d %-20s %-4i %s\n",
01282                         cookie.host().toLatin1().constData(), domain.toLatin1().constData(),
01283                         path.toLatin1().constData(), (unsigned long) cookie.expireDate(),
01284                         cookie.protocolVersion(),
01285                         cookie.name().isEmpty() ? cookie.value().toLatin1().constData() : cookie.name().toLatin1().constData(),
01286                         (cookie.isSecure() ? 1 : 0) + (cookie.isHttpOnly() ? 2 : 0) +
01287                         (cookie.hasExplicitPath() ? 4 : 0) + (cookie.name().isEmpty() ? 8 : 0),
01288                         cookie.value().toLatin1().constData());
01289                 ts << s.toLatin1().constData();
01290             }
01291         }
01292     }
01293 
01294     return saveFile.finalize();
01295 }
01296 
01297 static const char *parseField(char* &buffer, bool keepQuotes=false)
01298 {
01299     char *result;
01300     if (!keepQuotes && (*buffer == '\"'))
01301     {
01302         // Find terminating "
01303         buffer++;
01304         result = buffer;
01305         while((*buffer != '\"') && (*buffer))
01306             buffer++;
01307     }
01308     else
01309     {
01310         // Find first white space
01311         result = buffer;
01312         while((*buffer != ' ') && (*buffer != '\t') && (*buffer != '\n') && (*buffer))
01313             buffer++;
01314     }
01315 
01316     if (!*buffer)
01317         return result; //
01318     *buffer++ = '\0';
01319 
01320     // Skip white-space
01321     while((*buffer == ' ') || (*buffer == '\t') || (*buffer == '\n'))
01322         buffer++;
01323 
01324     return result;
01325 }
01326 
01327 
01328 //
01329 // Reloads all cookies from the file '_filename'.
01330 // On succes 'true' is returned.
01331 // On failure 'false' is returned.
01332 bool KCookieJar::loadCookies(const QString &_filename)
01333 {
01334     FILE *fStream = fopen( QFile::encodeName(_filename), "r");
01335     if (fStream == 0)
01336     {
01337         return false;
01338     }
01339 
01340     time_t curTime = time(0);
01341 
01342     char *buffer = new char[READ_BUFFER_SIZE];
01343 
01344     bool err = false;
01345     err = (fgets(buffer, READ_BUFFER_SIZE, fStream) == 0);
01346 
01347     int version = 1;
01348     if (!err)
01349     {
01350         if (strcmp(buffer, "# KDE Cookie File\n") == 0)
01351         {
01352             // version 1
01353         }
01354         else if (sscanf(buffer, "# KDE Cookie File v%d\n", &version) != 1)
01355         {
01356             err = true;
01357         }
01358     }
01359 
01360     if (!err)
01361     {
01362         while(fgets(buffer, READ_BUFFER_SIZE, fStream) != 0)
01363         {
01364             char *line = buffer;
01365             // Skip lines which begin with '#' or '['
01366             if ((line[0] == '#') || (line[0] == '['))
01367                 continue;
01368 
01369             const char *host( parseField(line) );
01370             const char *domain( parseField(line) );
01371             const char *path( parseField(line) );
01372             const char *expStr( parseField(line) );
01373             if (!expStr) continue;
01374             int expDate  = (time_t) strtoul(expStr, 0, 10);
01375             const char *verStr( parseField(line) );
01376             if (!verStr) continue;
01377             int protVer  = (time_t) strtoul(verStr, 0, 10);
01378             const char *name( parseField(line) );
01379             bool keepQuotes = false;
01380             bool secure = false;
01381             bool httpOnly = false;
01382             bool explicitPath = false;
01383             const char *value = 0;
01384             if ((version == 2) || (protVer >= 200))
01385             {
01386                 if (protVer >= 200)
01387                     protVer -= 200;
01388                 int i = atoi( parseField(line) );
01389                 secure = i & 1;
01390                 httpOnly = i & 2;
01391                 explicitPath = i & 4;
01392                 if (i & 8)
01393                     name = "";
01394                 line[strlen(line)-1] = '\0'; // Strip LF.
01395                 value = line;
01396             }
01397             else
01398             {
01399                 if (protVer >= 100)
01400                 {
01401                     protVer -= 100;
01402                     keepQuotes = true;
01403                 }
01404                 value = parseField(line, keepQuotes);
01405                 secure = atoi( parseField(line) );
01406             }
01407 
01408             // Parse error
01409             if (!value) continue;
01410 
01411             // Expired or parse error
01412             if ((expDate == 0) || (expDate < curTime))
01413                 continue;
01414 
01415             KHttpCookie cookie(QString::fromLatin1(host),
01416                                QString::fromLatin1(domain),
01417                                QString::fromLatin1(path),
01418                                QString::fromLatin1(name),
01419                                QString::fromLatin1(value),
01420                                expDate, protVer,
01421                                secure, httpOnly, explicitPath);
01422             addCookie(cookie);
01423         }
01424     }
01425     delete [] buffer;
01426     m_cookiesChanged = false;
01427 
01428     fclose( fStream);
01429     return err;
01430 }
01431 
01432 //
01433 // Save the cookie configuration
01434 //
01435 
01436 void KCookieJar::saveConfig(KConfig *_config)
01437 {
01438     if (!m_configChanged)
01439         return;
01440 
01441     KConfigGroup dlgGroup(_config, "Cookie Dialog");
01442     dlgGroup.writeEntry("PreferredPolicy", m_preferredPolicy);
01443     dlgGroup.writeEntry("ShowCookieDetails", m_showCookieDetails );
01444     KConfigGroup policyGroup(_config,"Cookie Policy");
01445     policyGroup.writeEntry("CookieGlobalAdvice", adviceToStr( m_globalAdvice));
01446 
01447     QStringList domainSettings;
01448     for ( QStringList::Iterator it=m_domainList.begin();
01449           it != m_domainList.end();
01450           it++ )
01451     {
01452          const QString &domain = *it;
01453          KCookieAdvice advice = getDomainAdvice( domain);
01454          if (advice != KCookieDunno)
01455          {
01456              QString value(domain);
01457              value += ':';
01458              value += adviceToStr(advice);
01459              domainSettings.append(value);
01460          }
01461     }
01462     policyGroup.writeEntry("CookieDomainAdvice", domainSettings);
01463     _config->sync();
01464     m_configChanged = false;
01465 }
01466 
01467 
01468 //
01469 // Load the cookie configuration
01470 //
01471 
01472 void KCookieJar::loadConfig(KConfig *_config, bool reparse )
01473 {
01474     if ( reparse )
01475         _config->reparseConfiguration();
01476 
01477     KConfigGroup dlgGroup(_config, "Cookie Dialog");
01478     m_showCookieDetails = dlgGroup.readEntry( "ShowCookieDetails" , false );
01479     m_preferredPolicy = dlgGroup.readEntry( "PreferredPolicy", 0 );
01480 
01481     KConfigGroup policyGroup(_config,"Cookie Policy");
01482     QStringList domainSettings = policyGroup.readEntry("CookieDomainAdvice", QStringList());
01483     m_rejectCrossDomainCookies = policyGroup.readEntry("RejectCrossDomainCookies", true);
01484     m_autoAcceptSessionCookies = policyGroup.readEntry("AcceptSessionCookies", true);
01485     m_ignoreCookieExpirationDate = policyGroup.readEntry("IgnoreExpirationDate", false);
01486     QString value = policyGroup.readEntry("CookieGlobalAdvice", L1("Accept"));
01487     m_globalAdvice = strToAdvice(value);
01488 
01489     // Reset current domain settings first.
01490     //  (must make a copy because setDomainAdvice() might delete the domain from m_domainList inside the for loop)
01491     const QStringList domains = m_domainList;
01492     foreach( const QString &domain, domains )
01493     {
01494          setDomainAdvice(domain, KCookieDunno);
01495     }
01496 
01497     // Now apply the domain settings read from config file...
01498     for ( QStringList::Iterator it=domainSettings.begin();
01499           it != domainSettings.end(); )
01500     {
01501         const QString &value = *it++;
01502 
01503         int sepPos = value.lastIndexOf(':');
01504 
01505         if (sepPos <= 0)
01506           continue;
01507 
01508         QString domain(value.left(sepPos));
01509         KCookieAdvice advice = strToAdvice( value.mid(sepPos + 1) );
01510         setDomainAdvice(domain, advice);
01511     }
01512 }
01513 
01514 QDebug operator<<(QDebug dbg, const KHttpCookie& cookie)
01515 {
01516     dbg.nospace() << cookie.cookieStr(false);
01517     return dbg.space();
01518 }
01519 
01520 QDebug operator<<(QDebug dbg, const KHttpCookieList& list)
01521 {
01522     Q_FOREACH(const KHttpCookie& cookie, list)
01523         dbg << cookie;
01524     return dbg;
01525 }

KIOSlave

Skip menu "KIOSlave"
  • Main Page
  • 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
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • KIO
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • Kross
  • KUtils
  • Nepomuk
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.5.4
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