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