kcookiejar.cpp

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