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 726988 2007-10-19 11:48:20Z adawit $ 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 #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]?)" 00086 00087 // Note with respect to QString::fromLatin1( ) 00088 // Cookies are stored as 8 bit data and passed to kio_http as 00089 // latin1 regardless of their actual encoding. 00090 00091 // L1 is used to indicate latin1 constants 00092 #define L1(x) QString::fromLatin1(x) 00093 00094 template class QPtrList<KHttpCookie>; 00095 template class QPtrDict<KHttpCookieList>; 00096 00097 QString KCookieJar::adviceToStr(KCookieAdvice _advice) 00098 { 00099 switch( _advice ) 00100 { 00101 case KCookieAccept: return L1("Accept"); 00102 case KCookieReject: return L1("Reject"); 00103 case KCookieAsk: return L1("Ask"); 00104 default: return L1("Dunno"); 00105 } 00106 } 00107 00108 KCookieAdvice KCookieJar::strToAdvice(const QString &_str) 00109 { 00110 if (_str.isEmpty()) 00111 return KCookieDunno; 00112 00113 QCString advice = _str.lower().latin1(); 00114 00115 if (advice == "accept") 00116 return KCookieAccept; 00117 else if (advice == "reject") 00118 return KCookieReject; 00119 else if (advice == "ask") 00120 return KCookieAsk; 00121 00122 return KCookieDunno; 00123 } 00124 00125 // KHttpCookie 00127 00128 // 00129 // Cookie constructor 00130 // 00131 KHttpCookie::KHttpCookie(const QString &_host, 00132 const QString &_domain, 00133 const QString &_path, 00134 const QString &_name, 00135 const QString &_value, 00136 time_t _expireDate, 00137 int _protocolVersion, 00138 bool _secure, 00139 bool _httpOnly, 00140 bool _explicitPath) : 00141 mHost(_host), 00142 mDomain(_domain), 00143 mPath(_path.isEmpty() ? QString::null : _path), 00144 mName(_name), 00145 mValue(_value), 00146 mExpireDate(_expireDate), 00147 mProtocolVersion(_protocolVersion), 00148 mSecure(_secure), 00149 mHttpOnly(_httpOnly), 00150 mExplicitPath(_explicitPath) 00151 { 00152 } 00153 00154 // 00155 // Checks if a cookie has been expired 00156 // 00157 bool KHttpCookie::isExpired(time_t currentDate) 00158 { 00159 return (mExpireDate != 0) && (mExpireDate < currentDate); 00160 } 00161 00162 // 00163 // Returns a string for a HTTP-header 00164 // 00165 QString KHttpCookie::cookieStr(bool useDOMFormat) 00166 { 00167 QString result; 00168 00169 if (useDOMFormat || (mProtocolVersion == 0)) 00170 { 00171 if ( !mName.isEmpty() ) 00172 result = mName + '='; 00173 result += mValue; 00174 } 00175 else 00176 { 00177 result = mName + '=' + mValue; 00178 if (mExplicitPath) 00179 result += L1("; $Path=\"") + mPath + L1("\""); 00180 if (!mDomain.isEmpty()) 00181 result += L1("; $Domain=\"") + mDomain + L1("\""); 00182 } 00183 return result; 00184 } 00185 00186 // 00187 // Returns whether this cookie should be send to this location. 00188 bool KHttpCookie::match(const QString &fqdn, const QStringList &domains, 00189 const QString &path) 00190 { 00191 // Cookie domain match check 00192 if (mDomain.isEmpty()) 00193 { 00194 if (fqdn != mHost) 00195 return false; 00196 } 00197 else if (!domains.contains(mDomain)) 00198 { 00199 if (mDomain[0] == '.') 00200 return false; 00201 00202 // Maybe the domain needs an extra dot. 00203 QString domain = '.' + mDomain; 00204 if ( !domains.contains( domain ) ) 00205 if ( fqdn != mDomain ) 00206 return false; 00207 } 00208 00209 // Cookie path match check 00210 if (mPath.isEmpty()) 00211 return true; 00212 00213 // According to the netscape spec both http://www.acme.com/foobar, 00214 // http://www.acme.com/foo.bar and http://www.acme.com/foo/bar 00215 // match http://www.acme.com/foo. 00216 // We only match http://www.acme.com/foo/bar 00217 00218 if( path.startsWith(mPath) && 00219 ( 00220 (path.length() == mPath.length() ) || // Paths are exact match 00221 (path[mPath.length()-1] == '/') || // mPath ended with a slash 00222 (path[mPath.length()] == '/') // A slash follows. 00223 )) 00224 return true; // Path of URL starts with cookie-path 00225 00226 return false; 00227 } 00228 00229 // KHttpCookieList 00231 00232 int KHttpCookieList::compareItems( void * item1, void * item2) 00233 { 00234 int pathLen1 = ((KHttpCookie *)item1)->path().length(); 00235 int pathLen2 = ((KHttpCookie *)item2)->path().length(); 00236 if (pathLen1 > pathLen2) 00237 return -1; 00238 if (pathLen1 < pathLen2) 00239 return 1; 00240 return 0; 00241 } 00242 00243 00244 // KCookieJar 00246 00247 // 00248 // Constructs a new cookie jar 00249 // 00250 // One jar should be enough for all cookies. 00251 // 00252 KCookieJar::KCookieJar() 00253 { 00254 m_cookieDomains.setAutoDelete( true ); 00255 m_globalAdvice = KCookieDunno; 00256 m_configChanged = false; 00257 m_cookiesChanged = false; 00258 00259 KConfig cfg("khtml/domain_info", true, false, "data"); 00260 QStringList countries = cfg.readListEntry("twoLevelTLD"); 00261 for(QStringList::ConstIterator it = countries.begin(); 00262 it != countries.end(); ++it) 00263 { 00264 m_twoLevelTLD.replace(*it, (int *) 1); 00265 } 00266 } 00267 00268 // 00269 // Destructs the cookie jar 00270 // 00271 // Poor little cookies, they will all be eaten by the cookie monster! 00272 // 00273 KCookieJar::~KCookieJar() 00274 { 00275 // Not much to do here 00276 } 00277 00278 static void removeDuplicateFromList(KHttpCookieList *list, KHttpCookie *cookiePtr, bool nameMatchOnly=false, bool updateWindowId=false) 00279 { 00280 QString domain1 = cookiePtr->domain(); 00281 if (domain1.isEmpty()) 00282 domain1 = cookiePtr->host(); 00283 00284 for ( KHttpCookiePtr cookie=list->first(); cookie != 0; ) 00285 { 00286 QString domain2 = cookie->domain(); 00287 if (domain2.isEmpty()) 00288 domain2 = cookie->host(); 00289 00290 if ( 00291 (cookiePtr->name() == cookie->name()) && 00292 ( 00293 nameMatchOnly || 00294 ( (domain1 == domain2) && (cookiePtr->path() == cookie->path()) ) 00295 ) 00296 ) 00297 { 00298 if (updateWindowId) 00299 { 00300 for(QValueList<long>::ConstIterator it = cookie->windowIds().begin(); 00301 it != cookie->windowIds().end(); ++it) 00302 { 00303 long windowId = *it; 00304 if (windowId && (cookiePtr->windowIds().find(windowId) == cookiePtr->windowIds().end())) 00305 { 00306 cookiePtr->windowIds().append(windowId); 00307 } 00308 } 00309 } 00310 KHttpCookiePtr old_cookie = cookie; 00311 cookie = list->next(); 00312 list->removeRef( old_cookie ); 00313 break; 00314 } 00315 else 00316 { 00317 cookie = list->next(); 00318 } 00319 } 00320 } 00321 00322 00323 // 00324 // Looks for cookies in the cookie jar which are appropriate for _url. 00325 // Returned is a string containing all appropriate cookies in a format 00326 // which can be added to a HTTP-header without any additional processing. 00327 // 00328 QString KCookieJar::findCookies(const QString &_url, bool useDOMFormat, long windowId, KHttpCookieList *pendingCookies) 00329 { 00330 QString cookieStr; 00331 QStringList domains; 00332 QString fqdn; 00333 QString path; 00334 KHttpCookiePtr cookie; 00335 KCookieAdvice advice = m_globalAdvice; 00336 00337 if (!parseURL(_url, fqdn, path)) 00338 return cookieStr; 00339 00340 bool secureRequest = (_url.find( L1("https://"), 0, false) == 0 || 00341 _url.find( L1("webdavs://"), 0, false) == 0); 00342 00343 // kdDebug(7104) << "findCookies: URL= " << _url << ", secure = " << secureRequest << endl; 00344 00345 extractDomains(fqdn, domains); 00346 00347 KHttpCookieList allCookies; 00348 00349 for(QStringList::ConstIterator it = domains.begin(); 00350 true; 00351 ++it) 00352 { 00353 KHttpCookieList *cookieList; 00354 if (it == domains.end()) 00355 { 00356 cookieList = pendingCookies; // Add pending cookies 00357 pendingCookies = 0; 00358 if (!cookieList) 00359 break; 00360 } 00361 else 00362 { 00363 QString key = (*it).isNull() ? L1("") : (*it); 00364 cookieList = m_cookieDomains[key]; 00365 if (!cookieList) 00366 continue; // No cookies for this domain 00367 } 00368 00369 if (cookieList->getAdvice() != KCookieDunno) 00370 advice = cookieList->getAdvice(); 00371 00372 for ( cookie=cookieList->first(); cookie != 0; cookie=cookieList->next() ) 00373 { 00374 // If the we are setup to automatically accept all session cookies and to 00375 // treat all cookies as session cookies or the current cookie is a session 00376 // cookie, then send the cookie back regardless of either policy. 00377 if (advice == KCookieReject && 00378 !(m_autoAcceptSessionCookies && 00379 (m_ignoreCookieExpirationDate || cookie->expireDate() == 0))) 00380 continue; 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 stripDomain (cookiePtr->domain(), 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 if (_fqdn.find(QRegExp(IP_ADDRESS_EXPRESSION)) > -1) 00624 { 00625 _domains.append( _fqdn ); 00626 return; 00627 } 00628 } 00629 00630 QStringList partList = QStringList::split('.', _fqdn, false); 00631 00632 if (partList.count()) 00633 partList.remove(partList.begin()); // Remove hostname 00634 00635 while(partList.count()) 00636 { 00637 00638 if (partList.count() == 1) 00639 break; // We only have a TLD left. 00640 00641 if ((partList.count() == 2) && (m_twoLevelTLD[partList[1].lower()])) 00642 { 00643 // This domain uses two-level TLDs in the form xxxx.yy 00644 break; 00645 } 00646 00647 if ((partList.count() == 2) && (partList[1].length() == 2)) 00648 { 00649 // If this is a TLD, we should stop. (e.g. co.uk) 00650 // We assume this is a TLD if it ends with .xx.yy or .x.yy 00651 if (partList[0].length() <= 2) 00652 break; // This is a TLD. 00653 00654 // Catch some TLDs that we miss with the previous check 00655 // e.g. com.au, org.uk, mil.co 00656 QCString t = partList[0].lower().utf8(); 00657 if ((t == "com") || (t == "net") || (t == "org") || (t == "gov") || (t == "edu") || (t == "mil") || (t == "int")) 00658 break; 00659 } 00660 00661 QString domain = partList.join(L1(".")); 00662 _domains.append(domain); 00663 _domains.append('.' + domain); 00664 partList.remove(partList.begin()); // Remove part 00665 } 00666 00667 // Always add the FQDN at the start of the list for 00668 // hostname == cookie-domainname checks! 00669 _domains.prepend( '.' + _fqdn ); 00670 _domains.prepend( _fqdn ); 00671 } 00672 00673 00674 /* 00675 Changes dates in from the following format 00676 00677 Wed Sep 12 07:00:00 2007 GMT 00678 to 00679 Wed Sep 12 2007 07:00:00 GMT 00680 00681 to allow KRFCDate::parseDate to properly parse expiration date formats 00682 used in cookies by some servers such as amazon.com. See BR# 145244. 00683 */ 00684 static QString fixupDateTime(const QString& dt) 00685 { 00686 const int index = dt.find(QRegExp("[0-9]{1,2}:[0-9]{1,2}:[0-9]{1,2}")); 00687 00688 if (index > -1) 00689 { 00690 QStringList dateStrList = QStringList::split(' ', dt.mid(index)); 00691 if (dateStrList.count() > 1) 00692 { 00693 QString date = dateStrList[0]; 00694 dateStrList[0] = dateStrList[1]; 00695 dateStrList[1] = date; 00696 date = dt; 00697 return date.replace(index, date.length(), dateStrList.join(" ")); 00698 } 00699 } 00700 00701 return dt; 00702 } 00703 00704 // 00705 // This function parses cookie_headers and returns a linked list of 00706 // KHttpCookie objects for all cookies found in cookie_headers. 00707 // If no cookies could be found 0 is returned. 00708 // 00709 // cookie_headers should be a concatenation of all lines of a HTTP-header 00710 // which start with "Set-Cookie". The lines should be separated by '\n's. 00711 // 00712 KHttpCookieList KCookieJar::makeCookies(const QString &_url, 00713 const QCString &cookie_headers, 00714 long windowId) 00715 { 00716 KHttpCookieList cookieList; 00717 KHttpCookieList cookieList2; 00718 KHttpCookiePtr lastCookie = 0; 00719 const char *cookieStr = cookie_headers.data(); 00720 QString Name; 00721 QString Value; 00722 QString fqdn; 00723 QString path; 00724 bool crossDomain = false; 00725 00726 if (!parseURL(_url, fqdn, path)) 00727 { 00728 // Error parsing _url 00729 return KHttpCookieList(); 00730 } 00731 QString defaultPath; 00732 int i = path.findRev('/'); 00733 if (i > 0) 00734 defaultPath = path.left(i); 00735 00736 // The hard stuff :) 00737 for(;;) 00738 { 00739 // check for "Set-Cookie" 00740 if (strncmp(cookieStr, "Cross-Domain\n", 13) == 0) 00741 { 00742 cookieStr += 13; 00743 crossDomain = true; 00744 } 00745 else if (strncasecmp(cookieStr, "Set-Cookie:", 11) == 0) 00746 { 00747 cookieStr = parseNameValue(cookieStr+11, Name, Value, true); 00748 00749 // Host = FQDN 00750 // Default domain = "" 00751 // Default path according to rfc2109 00752 00753 KHttpCookie *cookie = new KHttpCookie(fqdn, L1(""), defaultPath, Name, Value); 00754 if (windowId) 00755 cookie->mWindowIds.append(windowId); 00756 cookie->mCrossDomain = crossDomain; 00757 00758 // Insert cookie in chain 00759 cookieList.append(cookie); 00760 lastCookie = cookie; 00761 } 00762 else if (strncasecmp(cookieStr, "Set-Cookie2:", 12) == 0) 00763 { 00764 // Attempt to follow rfc2965 00765 cookieStr = parseNameValue(cookieStr+12, Name, Value, true, true); 00766 00767 // Host = FQDN 00768 // Default domain = "" 00769 // Default path according to rfc2965 00770 00771 KHttpCookie *cookie = new KHttpCookie(fqdn, L1(""), defaultPath, Name, Value); 00772 if (windowId) 00773 cookie->mWindowIds.append(windowId); 00774 cookie->mCrossDomain = crossDomain; 00775 00776 // Insert cookie in chain 00777 cookieList2.append(cookie); 00778 lastCookie = cookie; 00779 } 00780 else 00781 { 00782 // This is not the start of a cookie header, skip till next line. 00783 while (*cookieStr && *cookieStr != '\n') 00784 cookieStr++; 00785 00786 if (*cookieStr == '\n') 00787 cookieStr++; 00788 00789 if (!*cookieStr) 00790 break; // End of cookie_headers 00791 else 00792 continue; // end of this header, continue with next. 00793 } 00794 00795 while ((*cookieStr == ';') || (*cookieStr == ' ')) 00796 { 00797 cookieStr++; 00798 00799 // Name-Value pair follows 00800 cookieStr = parseNameValue(cookieStr, Name, Value); 00801 00802 QCString cName = Name.lower().latin1(); 00803 if (cName == "domain") 00804 { 00805 QString dom = Value.lower(); 00806 // RFC2965 3.2.2: If an explicitly specified value does not 00807 // start with a dot, the user agent supplies a leading dot 00808 if(dom.length() && dom[0] != '.') 00809 dom.prepend("."); 00810 // remove a trailing dot 00811 if(dom.length() > 2 && dom[dom.length()-1] == '.') 00812 dom = dom.left(dom.length()-1); 00813 00814 if(dom.contains('.') > 1 || dom == ".local") 00815 lastCookie->mDomain = dom; 00816 } 00817 else if (cName == "max-age") 00818 { 00819 int max_age = Value.toInt(); 00820 if (max_age == 0) 00821 lastCookie->mExpireDate = 1; 00822 else 00823 lastCookie->mExpireDate = time(0)+max_age; 00824 } 00825 else if (cName == "expires") 00826 { 00827 // Parse brain-dead netscape cookie-format 00828 lastCookie->mExpireDate = KRFCDate::parseDate(Value); 00829 00830 // Workaround for servers that send the expiration date in 00831 // 'Wed Sep 12 07:00:00 2007 GMT' format. See BR# 145244. 00832 if (lastCookie->mExpireDate == 0) 00833 lastCookie->mExpireDate = KRFCDate::parseDate(fixupDateTime(Value)); 00834 } 00835 else if (cName == "path") 00836 { 00837 if (Value.isEmpty()) 00838 lastCookie->mPath = QString::null; // Catch "" <> QString::null 00839 else 00840 lastCookie->mPath = KURL::decode_string(Value); 00841 lastCookie->mExplicitPath = true; 00842 } 00843 else if (cName == "version") 00844 { 00845 lastCookie->mProtocolVersion = Value.toInt(); 00846 } 00847 else if ((cName == "secure") || 00848 (cName.isEmpty() && Value.lower() == L1("secure"))) 00849 { 00850 lastCookie->mSecure = true; 00851 } 00852 else if ((cName == "httponly") || 00853 (cName.isEmpty() && Value.lower() == L1("httponly"))) 00854 { 00855 lastCookie->mHttpOnly = true; 00856 } 00857 } 00858 00859 if (*cookieStr == '\0') 00860 break; // End of header 00861 00862 // Skip ';' or '\n' 00863 cookieStr++; 00864 } 00865 00866 // RFC2965 cookies come last so that they override netscape cookies. 00867 while( !cookieList2.isEmpty() && (lastCookie = cookieList2.take(0)) ) 00868 { 00869 removeDuplicateFromList(&cookieList, lastCookie, true); 00870 cookieList.append(lastCookie); 00871 } 00872 00873 return cookieList; 00874 } 00875 00882 KHttpCookieList KCookieJar::makeDOMCookies(const QString &_url, 00883 const QCString &cookie_domstring, 00884 long windowId) 00885 { 00886 // A lot copied from above 00887 KHttpCookieList cookieList; 00888 KHttpCookiePtr lastCookie = 0; 00889 00890 const char *cookieStr = cookie_domstring.data(); 00891 QString Name; 00892 QString Value; 00893 QString fqdn; 00894 QString path; 00895 00896 if (!parseURL(_url, fqdn, path)) 00897 { 00898 // Error parsing _url 00899 return KHttpCookieList(); 00900 } 00901 00902 // This time it's easy 00903 while(*cookieStr) 00904 { 00905 cookieStr = parseNameValue(cookieStr, Name, Value); 00906 00907 // Host = FQDN 00908 // Default domain = "" 00909 // Default path = "" 00910 KHttpCookie *cookie = new KHttpCookie(fqdn, QString::null, QString::null, 00911 Name, Value ); 00912 if (windowId) 00913 cookie->mWindowIds.append(windowId); 00914 00915 cookieList.append(cookie); 00916 lastCookie = cookie; 00917 00918 if (*cookieStr != '\0') 00919 cookieStr++; // Skip ';' or '\n' 00920 } 00921 00922 return cookieList; 00923 } 00924 00925 #ifdef MAX_COOKIE_LIMIT 00926 static void makeRoom(KHttpCookieList *cookieList, KHttpCookiePtr &cookiePtr) 00927 { 00928 // Too much cookies: throw one away, try to be somewhat clever 00929 KHttpCookiePtr lastCookie = 0; 00930 for(KHttpCookiePtr cookie = cookieList->first(); cookie; cookie = cookieList->next()) 00931 { 00932 if (cookieList->compareItems(cookie, cookiePtr) < 0) 00933 break; 00934 lastCookie = cookie; 00935 } 00936 if (!lastCookie) 00937 lastCookie = cookieList->first(); 00938 cookieList->removeRef(lastCookie); 00939 } 00940 #endif 00941 00942 // 00943 // This function hands a KHttpCookie object over to the cookie jar. 00944 // 00945 // On return cookiePtr is set to 0. 00946 // 00947 void KCookieJar::addCookie(KHttpCookiePtr &cookiePtr) 00948 { 00949 QStringList domains; 00950 KHttpCookieList *cookieList = 0L; 00951 00952 // We always need to do this to make sure that the 00953 // that cookies of type hostname == cookie-domainname 00954 // are properly removed and/or updated as necessary! 00955 extractDomains( cookiePtr->host(), domains ); 00956 for ( QStringList::ConstIterator it = domains.begin(); 00957 (it != domains.end() && !cookieList); 00958 ++it ) 00959 { 00960 QString key = (*it).isNull() ? L1("") : (*it); 00961 KHttpCookieList *list= m_cookieDomains[key]; 00962 if ( !list ) continue; 00963 00964 removeDuplicateFromList(list, cookiePtr, false, true); 00965 } 00966 00967 QString domain = stripDomain( cookiePtr ); 00968 QString key = domain.isNull() ? L1("") : domain; 00969 cookieList = m_cookieDomains[ key ]; 00970 if (!cookieList) 00971 { 00972 // Make a new cookie list 00973 cookieList = new KHttpCookieList(); 00974 cookieList->setAutoDelete(true); 00975 00976 // All cookies whose domain is not already 00977 // known to us should be added with KCookieDunno. 00978 // KCookieDunno means that we use the global policy. 00979 cookieList->setAdvice( KCookieDunno ); 00980 00981 m_cookieDomains.insert( domain, cookieList); 00982 00983 // Update the list of domains 00984 m_domainList.append(domain); 00985 } 00986 00987 // Add the cookie to the cookie list 00988 // The cookie list is sorted 'longest path first' 00989 if (!cookiePtr->isExpired(time(0))) 00990 { 00991 #ifdef MAX_COOKIE_LIMIT 00992 if (cookieList->count() >= MAX_COOKIES_PER_HOST) 00993 makeRoom(cookieList, cookiePtr); // Delete a cookie 00994 #endif 00995 cookieList->inSort( cookiePtr ); 00996 m_cookiesChanged = true; 00997 } 00998 else 00999 { 01000 delete cookiePtr; 01001 } 01002 cookiePtr = 0; 01003 } 01004 01005 // 01006 // This function advices whether a single KHttpCookie object should 01007 // be added to the cookie jar. 01008 // 01009 KCookieAdvice KCookieJar::cookieAdvice(KHttpCookiePtr cookiePtr) 01010 { 01011 if (m_rejectCrossDomainCookies && cookiePtr->isCrossDomain()) 01012 return KCookieReject; 01013 01014 QStringList domains; 01015 01016 extractDomains(cookiePtr->host(), domains); 01017 01018 // If the cookie specifies a domain, check whether it is valid. Otherwise, 01019 // accept the cookie anyways but remove the domain="" value to prevent 01020 // cross-site cookie injection. 01021 if (!cookiePtr->domain().isEmpty()) 01022 { 01023 if (!domains.contains(cookiePtr->domain()) && 01024 !cookiePtr->domain().endsWith("."+cookiePtr->host())) 01025 cookiePtr->fixDomain(QString::null); 01026 } 01027 01028 if (m_autoAcceptSessionCookies && (cookiePtr->expireDate() == 0 || 01029 m_ignoreCookieExpirationDate)) 01030 return KCookieAccept; 01031 01032 KCookieAdvice advice = KCookieDunno; 01033 bool isFQDN = true; // First is FQDN 01034 QStringList::Iterator it = domains.begin(); // Start with FQDN which first in the list. 01035 while( (advice == KCookieDunno) && (it != domains.end())) 01036 { 01037 QString domain = *it; 01038 // Check if a policy for the FQDN/domain is set. 01039 if ( domain[0] == '.' || isFQDN ) 01040 { 01041 isFQDN = false; 01042 KHttpCookieList *cookieList = m_cookieDomains[domain]; 01043 if (cookieList) 01044 advice = cookieList->getAdvice(); 01045 } 01046 domains.remove(it); 01047 it = domains.begin(); // Continue from begin of remaining list 01048 } 01049 01050 if (advice == KCookieDunno) 01051 advice = m_globalAdvice; 01052 01053 return advice; 01054 } 01055 01056 // 01057 // This function gets the advice for all cookies originating from 01058 // _domain. 01059 // 01060 KCookieAdvice KCookieJar::getDomainAdvice(const QString &_domain) 01061 { 01062 KHttpCookieList *cookieList = m_cookieDomains[_domain]; 01063 KCookieAdvice advice; 01064 01065 if (cookieList) 01066 { 01067 advice = cookieList->getAdvice(); 01068 } 01069 else 01070 { 01071 advice = KCookieDunno; 01072 } 01073 01074 return advice; 01075 } 01076 01077 // 01078 // This function sets the advice for all cookies originating from 01079 // _domain. 01080 // 01081 void KCookieJar::setDomainAdvice(const QString &_domain, KCookieAdvice _advice) 01082 { 01083 QString domain(_domain); 01084 KHttpCookieList *cookieList = m_cookieDomains[domain]; 01085 01086 if (cookieList) 01087 { 01088 if (cookieList->getAdvice() != _advice) 01089 { 01090 m_configChanged = true; 01091 // domain is already known 01092 cookieList->setAdvice( _advice); 01093 } 01094 01095 if ((cookieList->isEmpty()) && 01096 (_advice == KCookieDunno)) 01097 { 01098 // This deletes cookieList! 01099 m_cookieDomains.remove(domain); 01100 m_domainList.remove(domain); 01101 } 01102 } 01103 else 01104 { 01105 // domain is not yet known 01106 if (_advice != KCookieDunno) 01107 { 01108 // We should create a domain entry 01109 m_configChanged = true; 01110 // Make a new cookie list 01111 cookieList = new KHttpCookieList(); 01112 cookieList->setAutoDelete(true); 01113 cookieList->setAdvice( _advice); 01114 m_cookieDomains.insert( domain, cookieList); 01115 // Update the list of domains 01116 m_domainList.append( domain); 01117 } 01118 } 01119 } 01120 01121 // 01122 // This function sets the advice for all cookies originating from 01123 // the same domain as _cookie 01124 // 01125 void KCookieJar::setDomainAdvice(KHttpCookiePtr cookiePtr, KCookieAdvice _advice) 01126 { 01127 QString domain; 01128 stripDomain(cookiePtr->host(), domain); // We file the cookie under this domain. 01129 01130 setDomainAdvice(domain, _advice); 01131 } 01132 01133 // 01134 // This function sets the global advice for cookies 01135 // 01136 void KCookieJar::setGlobalAdvice(KCookieAdvice _advice) 01137 { 01138 if (m_globalAdvice != _advice) 01139 m_configChanged = true; 01140 m_globalAdvice = _advice; 01141 } 01142 01143 // 01144 // Get a list of all domains known to the cookie jar. 01145 // 01146 const QStringList& KCookieJar::getDomainList() 01147 { 01148 return m_domainList; 01149 } 01150 01151 // 01152 // Get a list of all cookies in the cookie jar originating from _domain. 01153 // 01154 const KHttpCookieList *KCookieJar::getCookieList(const QString & _domain, 01155 const QString & _fqdn ) 01156 { 01157 QString domain; 01158 01159 if (_domain.isEmpty()) 01160 stripDomain( _fqdn, domain ); 01161 else 01162 domain = _domain; 01163 01164 return m_cookieDomains[domain]; 01165 } 01166 01167 // 01168 // Eat a cookie out of the jar. 01169 // cookiePtr should be one of the cookies returned by getCookieList() 01170 // 01171 void KCookieJar::eatCookie(KHttpCookiePtr cookiePtr) 01172 { 01173 QString domain = stripDomain(cookiePtr); // We file the cookie under this domain. 01174 KHttpCookieList *cookieList = m_cookieDomains[domain]; 01175 01176 if (cookieList) 01177 { 01178 // This deletes cookiePtr! 01179 if (cookieList->removeRef( cookiePtr )) 01180 m_cookiesChanged = true; 01181 01182 if ((cookieList->isEmpty()) && 01183 (cookieList->getAdvice() == KCookieDunno)) 01184 { 01185 // This deletes cookieList! 01186 m_cookieDomains.remove(domain); 01187 01188 m_domainList.remove(domain); 01189 } 01190 } 01191 } 01192 01193 void KCookieJar::eatCookiesForDomain(const QString &domain) 01194 { 01195 KHttpCookieList *cookieList = m_cookieDomains[domain]; 01196 if (!cookieList || cookieList->isEmpty()) return; 01197 01198 cookieList->clear(); 01199 if (cookieList->getAdvice() == KCookieDunno) 01200 { 01201 // This deletes cookieList! 01202 m_cookieDomains.remove(domain); 01203 m_domainList.remove(domain); 01204 } 01205 m_cookiesChanged = true; 01206 } 01207 01208 void KCookieJar::eatSessionCookies( long windowId ) 01209 { 01210 if (!windowId) 01211 return; 01212 01213 QStringList::Iterator it=m_domainList.begin(); 01214 for ( ; it != m_domainList.end(); ++it ) 01215 eatSessionCookies( *it, windowId, false ); 01216 } 01217 01218 void KCookieJar::eatAllCookies() 01219 { 01220 for ( QStringList::Iterator it=m_domainList.begin(); 01221 it != m_domainList.end();) 01222 { 01223 QString domain = *it++; 01224 // This might remove domain from domainList! 01225 eatCookiesForDomain(domain); 01226 } 01227 } 01228 01229 void KCookieJar::eatSessionCookies( const QString& fqdn, long windowId, 01230 bool isFQDN ) 01231 { 01232 KHttpCookieList* cookieList; 01233 if ( !isFQDN ) 01234 cookieList = m_cookieDomains[fqdn]; 01235 else 01236 { 01237 QString domain; 01238 stripDomain( fqdn, domain ); 01239 cookieList = m_cookieDomains[domain]; 01240 } 01241 01242 if ( cookieList ) 01243 { 01244 KHttpCookiePtr cookie=cookieList->first(); 01245 for (; cookie != 0;) 01246 { 01247 if ((cookie->expireDate() != 0) && !m_ignoreCookieExpirationDate) 01248 { 01249 cookie = cookieList->next(); 01250 continue; 01251 } 01252 01253 QValueList<long> &ids = cookie->windowIds(); 01254 if (!ids.remove(windowId) || !ids.isEmpty()) 01255 { 01256 cookie = cookieList->next(); 01257 continue; 01258 } 01259 KHttpCookiePtr old_cookie = cookie; 01260 cookie = cookieList->next(); 01261 cookieList->removeRef( old_cookie ); 01262 } 01263 } 01264 } 01265 01266 // 01267 // Saves all cookies to the file '_filename'. 01268 // On succes 'true' is returned. 01269 // On failure 'false' is returned. 01270 bool KCookieJar::saveCookies(const QString &_filename) 01271 { 01272 KSaveFile saveFile(_filename, 0600); 01273 01274 if (saveFile.status() != 0) 01275 return false; 01276 01277 FILE *fStream = saveFile.fstream(); 01278 01279 time_t curTime = time(0); 01280 01281 fprintf(fStream, "# KDE Cookie File v2\n#\n"); 01282 01283 fprintf(fStream, "%-20s %-20s %-12s %-10s %-4s %-20s %-4s %s\n", 01284 "# Host", "Domain", "Path", "Exp.date", "Prot", 01285 "Name", "Sec", "Value"); 01286 01287 for ( QStringList::Iterator it=m_domainList.begin(); it != m_domainList.end(); 01288 it++ ) 01289 { 01290 const QString &domain = *it; 01291 bool domainPrinted = false; 01292 01293 KHttpCookieList *cookieList = m_cookieDomains[domain]; 01294 KHttpCookiePtr cookie=cookieList->last(); 01295 01296 for (; cookie != 0;) 01297 { 01298 if (cookie->isExpired(curTime)) 01299 { 01300 // Delete expired cookies 01301 KHttpCookiePtr old_cookie = cookie; 01302 cookie = cookieList->prev(); 01303 cookieList->removeRef( old_cookie ); 01304 } 01305 else if (cookie->expireDate() != 0 && !m_ignoreCookieExpirationDate) 01306 { 01307 if (!domainPrinted) 01308 { 01309 domainPrinted = true; 01310 fprintf(fStream, "[%s]\n", domain.local8Bit().data()); 01311 } 01312 // Store persistent cookies 01313 QString path = L1("\""); 01314 path += cookie->path(); 01315 path += '"'; 01316 QString domain = L1("\""); 01317 domain += cookie->domain(); 01318 domain += '"'; 01319 fprintf(fStream, "%-20s %-20s %-12s %10lu %3d %-20s %-4i %s\n", 01320 cookie->host().latin1(), domain.latin1(), 01321 path.latin1(), (unsigned long) cookie->expireDate(), 01322 cookie->protocolVersion(), 01323 cookie->name().isEmpty() ? cookie->value().latin1() : cookie->name().latin1(), 01324 (cookie->isSecure() ? 1 : 0) + (cookie->isHttpOnly() ? 2 : 0) + 01325 (cookie->hasExplicitPath() ? 4 : 0) + (cookie->name().isEmpty() ? 8 : 0), 01326 cookie->value().latin1()); 01327 cookie = cookieList->prev(); 01328 } 01329 else 01330 { 01331 // Skip session-only cookies 01332 cookie = cookieList->prev(); 01333 } 01334 } 01335 } 01336 01337 return saveFile.close(); 01338 } 01339 01340 typedef char *charPtr; 01341 01342 static const char *parseField(charPtr &buffer, bool keepQuotes=false) 01343 { 01344 char *result; 01345 if (!keepQuotes && (*buffer == '\"')) 01346 { 01347 // Find terminating " 01348 buffer++; 01349 result = buffer; 01350 while((*buffer != '\"') && (*buffer)) 01351 buffer++; 01352 } 01353 else 01354 { 01355 // Find first white space 01356 result = buffer; 01357 while((*buffer != ' ') && (*buffer != '\t') && (*buffer != '\n') && (*buffer)) 01358 buffer++; 01359 } 01360 01361 if (!*buffer) 01362 return result; // 01363 *buffer++ = '\0'; 01364 01365 // Skip white-space 01366 while((*buffer == ' ') || (*buffer == '\t') || (*buffer == '\n')) 01367 buffer++; 01368 01369 return result; 01370 } 01371 01372 01373 // 01374 // Reloads all cookies from the file '_filename'. 01375 // On succes 'true' is returned. 01376 // On failure 'false' is returned. 01377 bool KCookieJar::loadCookies(const QString &_filename) 01378 { 01379 FILE *fStream = fopen( QFile::encodeName(_filename), "r"); 01380 if (fStream == 0) 01381 { 01382 return false; 01383 } 01384 01385 time_t curTime = time(0); 01386 01387 char *buffer = new char[READ_BUFFER_SIZE]; 01388 01389 bool err = false; 01390 err = (fgets(buffer, READ_BUFFER_SIZE, fStream) == 0); 01391 01392 int version = 1; 01393 if (!err) 01394 { 01395 if (strcmp(buffer, "# KDE Cookie File\n") == 0) 01396 { 01397 // version 1 01398 } 01399 else if (sscanf(buffer, "# KDE Cookie File v%d\n", &version) != 1) 01400 { 01401 err = true; 01402 } 01403 } 01404 01405 if (!err) 01406 { 01407 while(fgets(buffer, READ_BUFFER_SIZE, fStream) != 0) 01408 { 01409 char *line = buffer; 01410 // Skip lines which begin with '#' or '[' 01411 if ((line[0] == '#') || (line[0] == '[')) 01412 continue; 01413 01414 const char *host( parseField(line) ); 01415 const char *domain( parseField(line) ); 01416 const char *path( parseField(line) ); 01417 const char *expStr( parseField(line) ); 01418 if (!expStr) continue; 01419 int expDate = (time_t) strtoul(expStr, 0, 10); 01420 const char *verStr( parseField(line) ); 01421 if (!verStr) continue; 01422 int protVer = (time_t) strtoul(verStr, 0, 10); 01423 const char *name( parseField(line) ); 01424 bool keepQuotes = false; 01425 bool secure = false; 01426 bool httpOnly = false; 01427 bool explicitPath = false; 01428 const char *value = 0; 01429 if ((version == 2) || (protVer >= 200)) 01430 { 01431 if (protVer >= 200) 01432 protVer -= 200; 01433 int i = atoi( parseField(line) ); 01434 secure = i & 1; 01435 httpOnly = i & 2; 01436 explicitPath = i & 4; 01437 if (i & 8) 01438 name = ""; 01439 line[strlen(line)-1] = '\0'; // Strip LF. 01440 value = line; 01441 } 01442 else 01443 { 01444 if (protVer >= 100) 01445 { 01446 protVer -= 100; 01447 keepQuotes = true; 01448 } 01449 value = parseField(line, keepQuotes); 01450 secure = atoi( parseField(line) ); 01451 } 01452 01453 // Parse error 01454 if (!value) continue; 01455 01456 // Expired or parse error 01457 if ((expDate == 0) || (expDate < curTime)) 01458 continue; 01459 01460 KHttpCookie *cookie = new KHttpCookie(QString::fromLatin1(host), 01461 QString::fromLatin1(domain), 01462 QString::fromLatin1(path), 01463 QString::fromLatin1(name), 01464 QString::fromLatin1(value), 01465 expDate, protVer, 01466 secure, httpOnly, explicitPath); 01467 addCookie(cookie); 01468 } 01469 } 01470 delete [] buffer; 01471 m_cookiesChanged = false; 01472 01473 fclose( fStream); 01474 return err; 01475 } 01476 01477 // 01478 // Save the cookie configuration 01479 // 01480 01481 void KCookieJar::saveConfig(KConfig *_config) 01482 { 01483 if (!m_configChanged) 01484 return; 01485 01486 _config->setGroup("Cookie Dialog"); 01487 _config->writeEntry("PreferredPolicy", m_preferredPolicy); 01488 _config->writeEntry("ShowCookieDetails", m_showCookieDetails ); 01489 _config->setGroup("Cookie Policy"); 01490 _config->writeEntry("CookieGlobalAdvice", adviceToStr( m_globalAdvice)); 01491 01492 QStringList domainSettings; 01493 for ( QStringList::Iterator it=m_domainList.begin(); 01494 it != m_domainList.end(); 01495 it++ ) 01496 { 01497 const QString &domain = *it; 01498 KCookieAdvice advice = getDomainAdvice( domain); 01499 if (advice != KCookieDunno) 01500 { 01501 QString value(domain); 01502 value += ':'; 01503 value += adviceToStr(advice); 01504 domainSettings.append(value); 01505 } 01506 } 01507 _config->writeEntry("CookieDomainAdvice", domainSettings); 01508 _config->sync(); 01509 m_configChanged = false; 01510 } 01511 01512 01513 // 01514 // Load the cookie configuration 01515 // 01516 01517 void KCookieJar::loadConfig(KConfig *_config, bool reparse ) 01518 { 01519 if ( reparse ) 01520 _config->reparseConfiguration(); 01521 01522 _config->setGroup("Cookie Dialog"); 01523 m_showCookieDetails = _config->readBoolEntry( "ShowCookieDetails" ); 01524 m_preferredPolicy = _config->readNumEntry( "PreferredPolicy", 0 ); 01525 01526 _config->setGroup("Cookie Policy"); 01527 QStringList domainSettings = _config->readListEntry("CookieDomainAdvice"); 01528 m_rejectCrossDomainCookies = _config->readBoolEntry( "RejectCrossDomainCookies", true ); 01529 m_autoAcceptSessionCookies = _config->readBoolEntry( "AcceptSessionCookies", true ); 01530 m_ignoreCookieExpirationDate = _config->readBoolEntry( "IgnoreExpirationDate", false ); 01531 QString value = _config->readEntry("CookieGlobalAdvice", L1("Ask")); 01532 m_globalAdvice = strToAdvice(value); 01533 01534 // Reset current domain settings first. 01535 for ( QStringList::Iterator it=m_domainList.begin(); it != m_domainList.end(); ) 01536 { 01537 // Make sure to update iterator before calling setDomainAdvice() 01538 // setDomainAdvice() might delete the domain from domainList. 01539 QString domain = *it++; 01540 setDomainAdvice(domain, KCookieDunno); 01541 } 01542 01543 // Now apply the domain settings read from config file... 01544 for ( QStringList::Iterator it=domainSettings.begin(); 01545 it != domainSettings.end(); ) 01546 { 01547 const QString &value = *it++; 01548 01549 int sepPos = value.findRev(':'); 01550 01551 if (sepPos <= 0) 01552 continue; 01553 01554 QString domain(value.left(sepPos)); 01555 KCookieAdvice advice = strToAdvice( value.mid(sepPos + 1) ); 01556 setDomainAdvice(domain, advice); 01557 } 01558 }