kcookieserver.cpp
00001 /* 00002 This file is part of KDE 00003 00004 Copyright (C) 1998-2000 Waldo Bastian (bastian@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 00010 copies of the Software, and to permit persons to whom the Software is 00011 furnished to do so, 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 00020 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 00021 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 00022 */ 00023 //---------------------------------------------------------------------------- 00024 // 00025 // KDE Cookie Server 00026 // $Id$ 00027 00028 #define SAVE_DELAY 3 // Save after 3 minutes 00029 00030 #include <unistd.h> 00031 00032 #include <tqtimer.h> 00033 #include <tqptrlist.h> 00034 #include <tqfile.h> 00035 00036 #include <dcopclient.h> 00037 00038 #include <kconfig.h> 00039 #include <kdebug.h> 00040 #include <kapplication.h> 00041 #include <kcmdlineargs.h> 00042 #include <kstandarddirs.h> 00043 00044 #include "kcookiejar.h" 00045 #include "kcookiewin.h" 00046 #include "kcookieserver.h" 00047 00048 extern "C" { 00049 KDE_EXPORT KDEDModule *create_kcookiejar(const TQCString &name) 00050 { 00051 return new KCookieServer(name); 00052 } 00053 } 00054 00055 00056 // Cookie field indexes 00057 enum CookieDetails { CF_DOMAIN=0, CF_PATH, CF_NAME, CF_HOST, 00058 CF_VALUE, CF_EXPIRE, CF_PROVER, CF_SECURE }; 00059 00060 00061 class CookieRequest { 00062 public: 00063 DCOPClient *client; 00064 DCOPClientTransaction *transaction; 00065 TQString url; 00066 bool DOM; 00067 long windowId; 00068 }; 00069 00070 template class TQPtrList<CookieRequest>; 00071 00072 class RequestList : public TQPtrList<CookieRequest> 00073 { 00074 public: 00075 RequestList() : TQPtrList<CookieRequest>() { } 00076 }; 00077 00078 KCookieServer::KCookieServer(const TQCString &name) 00079 :KDEDModule(name) 00080 { 00081 mOldCookieServer = new DCOPClient(); // backwards compatibility. 00082 mOldCookieServer->registerAs("kcookiejar", false); 00083 mOldCookieServer->setDaemonMode( true ); 00084 mCookieJar = new KCookieJar; 00085 mPendingCookies = new KHttpCookieList; 00086 mPendingCookies->setAutoDelete(true); 00087 mRequestList = new RequestList; 00088 mAdvicePending = false; 00089 mTimer = new TQTimer(); 00090 connect( mTimer, TQT_SIGNAL( timeout()), TQT_SLOT( slotSave())); 00091 mConfig = new KConfig("kcookiejarrc"); 00092 mCookieJar->loadConfig( mConfig ); 00093 00094 TQString filename = locateLocal("data", "kcookiejar/cookies"); 00095 00096 // Stay backwards compatible! 00097 TQString filenameOld = locate("data", "kfm/cookies"); 00098 if (!filenameOld.isEmpty()) 00099 { 00100 mCookieJar->loadCookies( filenameOld ); 00101 if (mCookieJar->saveCookies( filename)) 00102 { 00103 unlink(TQFile::encodeName(filenameOld)); // Remove old kfm cookie file 00104 } 00105 } 00106 else 00107 { 00108 mCookieJar->loadCookies( filename); 00109 } 00110 connect(this, TQT_SIGNAL(windowUnregistered(long)), 00111 this, TQT_SLOT(slotDeleteSessionCookies(long))); 00112 } 00113 00114 KCookieServer::~KCookieServer() 00115 { 00116 if (mCookieJar->changed()) 00117 slotSave(); 00118 delete mOldCookieServer; 00119 delete mCookieJar; 00120 delete mTimer; 00121 delete mPendingCookies; 00122 delete mConfig; 00123 } 00124 00125 bool KCookieServer::cookiesPending( const TQString &url, KHttpCookieList *cookieList ) 00126 { 00127 TQString fqdn; 00128 TQStringList domains; 00129 TQString path; 00130 // Check whether 'url' has cookies on the pending list 00131 if (mPendingCookies->isEmpty()) 00132 return false; 00133 if (!KCookieJar::parseURL(url, fqdn, path)) 00134 return false; 00135 00136 mCookieJar->extractDomains( fqdn, domains ); 00137 for( KHttpCookie *cookie = mPendingCookies->first(); 00138 cookie != 0L; 00139 cookie = mPendingCookies->next()) 00140 { 00141 if (cookie->match( fqdn, domains, path)) 00142 { 00143 if (!cookieList) 00144 return true; 00145 cookieList->append(cookie); 00146 } 00147 } 00148 if (!cookieList) 00149 return false; 00150 return cookieList->isEmpty(); 00151 } 00152 00153 void KCookieServer::addCookies( const TQString &url, const TQCString &cookieHeader, 00154 long windowId, bool useDOMFormat ) 00155 { 00156 KHttpCookieList cookieList; 00157 if (useDOMFormat) 00158 cookieList = mCookieJar->makeDOMCookies(url, cookieHeader, windowId); 00159 else 00160 cookieList = mCookieJar->makeCookies(url, cookieHeader, windowId); 00161 00162 checkCookies(&cookieList); 00163 00164 for(KHttpCookiePtr cookie = cookieList.first(); cookie; cookie = cookieList.first()) 00165 mPendingCookies->append(cookieList.take()); 00166 00167 if (!mAdvicePending) 00168 { 00169 mAdvicePending = true; 00170 while (!mPendingCookies->isEmpty()) 00171 { 00172 checkCookies(0); 00173 } 00174 mAdvicePending = false; 00175 } 00176 } 00177 00178 void KCookieServer::checkCookies( KHttpCookieList *cookieList) 00179 { 00180 KHttpCookieList *list; 00181 00182 if (cookieList) 00183 list = cookieList; 00184 else 00185 list = mPendingCookies; 00186 00187 KHttpCookiePtr cookie = list->first(); 00188 while (cookie) 00189 { 00190 kdDebug(7104) << "checkCookies: Asking cookie advice for " << cookie->host() << endl; 00191 KCookieAdvice advice = mCookieJar->cookieAdvice(cookie); 00192 switch(advice) 00193 { 00194 case KCookieAccept: 00195 list->take(); 00196 mCookieJar->addCookie(cookie); 00197 cookie = list->current(); 00198 break; 00199 00200 case KCookieReject: 00201 list->take(); 00202 delete cookie; 00203 cookie = list->current(); 00204 break; 00205 00206 default: 00207 cookie = list->next(); 00208 break; 00209 } 00210 } 00211 00212 if (cookieList || list->isEmpty()) 00213 return; 00214 00215 KHttpCookiePtr currentCookie = mPendingCookies->first(); 00216 00217 KHttpCookieList currentList; 00218 currentList.append(currentCookie); 00219 TQString currentHost = currentCookie->host(); 00220 00221 cookie = mPendingCookies->next(); 00222 while (cookie) 00223 { 00224 if (cookie->host() == currentHost) 00225 { 00226 currentList.append(cookie); 00227 } 00228 cookie = mPendingCookies->next(); 00229 } 00230 00231 KCookieWin *kw = new KCookieWin( 0L, currentList, 00232 mCookieJar->preferredDefaultPolicy(), 00233 mCookieJar->showCookieDetails() ); 00234 KCookieAdvice userAdvice = kw->advice(mCookieJar, currentCookie); 00235 delete kw; 00236 // Save the cookie config if it has changed 00237 mCookieJar->saveConfig( mConfig ); 00238 00239 // Apply the user's choice to all cookies that are currently 00240 // queued for this host. 00241 cookie = mPendingCookies->first(); 00242 while (cookie) 00243 { 00244 if (cookie->host() == currentHost) 00245 { 00246 switch(userAdvice) 00247 { 00248 case KCookieAccept: 00249 mPendingCookies->take(); 00250 mCookieJar->addCookie(cookie); 00251 cookie = mPendingCookies->current(); 00252 break; 00253 00254 case KCookieReject: 00255 mPendingCookies->take(); 00256 delete cookie; 00257 cookie = mPendingCookies->current(); 00258 break; 00259 00260 default: 00261 qWarning(__FILE__":%d Problem!", __LINE__); 00262 cookie = mPendingCookies->next(); 00263 break; 00264 } 00265 } 00266 else 00267 { 00268 cookie = mPendingCookies->next(); 00269 } 00270 } 00271 00272 00273 // Check if we can handle any request 00274 for ( CookieRequest *request = mRequestList->first(); request;) 00275 { 00276 if (!cookiesPending( request->url )) 00277 { 00278 TQCString replyType; 00279 TQByteArray replyData; 00280 TQString res = mCookieJar->findCookies( request->url, request->DOM, request->windowId ); 00281 00282 TQDataStream stream2(replyData, IO_WriteOnly); 00283 stream2 << res; 00284 replyType = "TQString"; 00285 request->client->endTransaction( request->transaction, 00286 replyType, replyData); 00287 CookieRequest *tmp = request; 00288 request = mRequestList->next(); 00289 mRequestList->removeRef( tmp ); 00290 delete tmp; 00291 } 00292 else 00293 { 00294 request = mRequestList->next(); 00295 } 00296 } 00297 if (mCookieJar->changed()) 00298 saveCookieJar(); 00299 } 00300 00301 void KCookieServer::slotSave() 00302 { 00303 TQString filename = locateLocal("data", "kcookiejar/cookies"); 00304 mCookieJar->saveCookies(filename); 00305 } 00306 00307 void KCookieServer::saveCookieJar() 00308 { 00309 if( mTimer->isActive() ) 00310 return; 00311 00312 mTimer->start( 1000*60*SAVE_DELAY, true ); 00313 } 00314 00315 void KCookieServer::putCookie( TQStringList& out, KHttpCookie *cookie, 00316 const TQValueList<int>& fields ) 00317 { 00318 TQValueList<int>::ConstIterator i = fields.begin(); 00319 for ( ; i != fields.end(); ++i ) 00320 { 00321 switch(*i) 00322 { 00323 case CF_DOMAIN : 00324 out << cookie->domain(); 00325 break; 00326 case CF_NAME : 00327 out << cookie->name(); 00328 break; 00329 case CF_PATH : 00330 out << cookie->path(); 00331 break; 00332 case CF_HOST : 00333 out << cookie->host(); 00334 break; 00335 case CF_VALUE : 00336 out << cookie->value(); 00337 break; 00338 case CF_EXPIRE : 00339 out << TQString::number(cookie->expireDate()); 00340 break; 00341 case CF_PROVER : 00342 out << TQString::number(cookie->protocolVersion()); 00343 break; 00344 case CF_SECURE : 00345 out << TQString::number( cookie->isSecure() ? 1 : 0 ); 00346 break; 00347 default : 00348 out << TQString::null; 00349 } 00350 } 00351 } 00352 00353 bool KCookieServer::cookieMatches( KHttpCookiePtr c, 00354 TQString domain, TQString fqdn, 00355 TQString path, TQString name ) 00356 { 00357 if( c ) 00358 { 00359 bool hasDomain = !domain.isEmpty(); 00360 return 00361 ((hasDomain && c->domain() == domain) || 00362 fqdn == c->host()) && 00363 (c->path() == path) && 00364 (c->name() == name) && 00365 (!c->isExpired(time(0))); 00366 } 00367 return false; 00368 } 00369 00370 // DCOP function 00371 TQString 00372 KCookieServer::findCookies(TQString url) 00373 { 00374 return findCookies(url, 0); 00375 } 00376 00377 // DCOP function 00378 TQString 00379 KCookieServer::findCookies(TQString url, long windowId) 00380 { 00381 if (cookiesPending(url)) 00382 { 00383 CookieRequest *request = new CookieRequest; 00384 request->client = callingDcopClient(); 00385 request->transaction = request->client->beginTransaction(); 00386 request->url = url; 00387 request->DOM = false; 00388 request->windowId = windowId; 00389 mRequestList->append( request ); 00390 return TQString::null; // Talk to you later :-) 00391 } 00392 00393 TQString cookies = mCookieJar->findCookies(url, false, windowId); 00394 00395 if (mCookieJar->changed()) 00396 saveCookieJar(); 00397 00398 return cookies; 00399 } 00400 00401 // DCOP function 00402 TQStringList 00403 KCookieServer::findDomains() 00404 { 00405 TQStringList result; 00406 const TQStringList domains = mCookieJar->getDomainList(); 00407 for ( TQStringList::ConstIterator domIt = domains.begin(); 00408 domIt != domains.end(); ++domIt ) 00409 { 00410 // Ignore domains that have policy set for but contain 00411 // no cookies whatsoever... 00412 const KHttpCookieList* list = mCookieJar->getCookieList(*domIt, ""); 00413 if ( list && !list->isEmpty() ) 00414 result << *domIt; 00415 } 00416 return result; 00417 } 00418 00419 // DCOP function 00420 TQStringList 00421 KCookieServer::findCookies(TQValueList<int> fields, 00422 TQString domain, 00423 TQString fqdn, 00424 TQString path, 00425 TQString name) 00426 { 00427 TQStringList result; 00428 bool allDomCookies = name.isEmpty(); 00429 00430 const KHttpCookieList* list = mCookieJar->getCookieList(domain, fqdn); 00431 if ( list && !list->isEmpty() ) 00432 { 00433 TQPtrListIterator<KHttpCookie>it( *list ); 00434 for ( ; it.current(); ++it ) 00435 { 00436 if ( !allDomCookies ) 00437 { 00438 if ( cookieMatches(it.current(), domain, fqdn, path, name) ) 00439 { 00440 putCookie(result, it.current(), fields); 00441 break; 00442 } 00443 } 00444 else 00445 putCookie(result, it.current(), fields); 00446 } 00447 } 00448 return result; 00449 } 00450 00451 // DCOP function 00452 TQString 00453 KCookieServer::findDOMCookies(TQString url) 00454 { 00455 return findDOMCookies(url, 0); 00456 } 00457 00458 // DCOP function 00459 TQString 00460 KCookieServer::findDOMCookies(TQString url, long windowId) 00461 { 00462 // We don't wait for pending cookies because it locks up konqueror 00463 // which can cause a deadlock if it happens to have a popup-menu up. 00464 // Instead we just return pending cookies as if they had been accepted already. 00465 KHttpCookieList pendingCookies; 00466 cookiesPending(url, &pendingCookies); 00467 00468 return mCookieJar->findCookies(url, true, windowId, &pendingCookies); 00469 } 00470 00471 // DCOP function 00472 void 00473 KCookieServer::addCookies(TQString arg1, TQCString arg2, long arg3) 00474 { 00475 addCookies(arg1, arg2, arg3, false); 00476 } 00477 00478 // DCOP function 00479 void 00480 KCookieServer::deleteCookie(TQString domain, TQString fqdn, 00481 TQString path, TQString name) 00482 { 00483 const KHttpCookieList* list = mCookieJar->getCookieList( domain, fqdn ); 00484 if ( list && !list->isEmpty() ) 00485 { 00486 TQPtrListIterator<KHttpCookie>it (*list); 00487 for ( ; it.current(); ++it ) 00488 { 00489 if( cookieMatches(it.current(), domain, fqdn, path, name) ) 00490 { 00491 mCookieJar->eatCookie( it.current() ); 00492 saveCookieJar(); 00493 break; 00494 } 00495 } 00496 } 00497 } 00498 00499 // DCOP function 00500 void 00501 KCookieServer::deleteCookiesFromDomain(TQString domain) 00502 { 00503 mCookieJar->eatCookiesForDomain(domain); 00504 saveCookieJar(); 00505 } 00506 00507 00508 // Qt function 00509 void 00510 KCookieServer::slotDeleteSessionCookies( long windowId ) 00511 { 00512 deleteSessionCookies(windowId); 00513 } 00514 00515 // DCOP function 00516 void 00517 KCookieServer::deleteSessionCookies( long windowId ) 00518 { 00519 mCookieJar->eatSessionCookies( windowId ); 00520 saveCookieJar(); 00521 } 00522 00523 void 00524 KCookieServer::deleteSessionCookiesFor(TQString fqdn, long windowId) 00525 { 00526 mCookieJar->eatSessionCookies( fqdn, windowId ); 00527 saveCookieJar(); 00528 } 00529 00530 // DCOP function 00531 void 00532 KCookieServer::deleteAllCookies() 00533 { 00534 mCookieJar->eatAllCookies(); 00535 saveCookieJar(); 00536 } 00537 00538 // DCOP function 00539 void 00540 KCookieServer::addDOMCookies(TQString arg1, TQCString arg2, long arg3) 00541 { 00542 addCookies(arg1, arg2, arg3, true); 00543 } 00544 00545 // DCOP function 00546 void 00547 KCookieServer::setDomainAdvice(TQString url, TQString advice) 00548 { 00549 TQString fqdn; 00550 TQString dummy; 00551 if (KCookieJar::parseURL(url, fqdn, dummy)) 00552 { 00553 TQStringList domains; 00554 mCookieJar->extractDomains(fqdn, domains); 00555 00556 mCookieJar->setDomainAdvice(domains[domains.count() > 3 ? 3 : 0], 00557 KCookieJar::strToAdvice(advice)); 00558 // Save the cookie config if it has changed 00559 mCookieJar->saveConfig( mConfig ); 00560 } 00561 } 00562 00563 // DCOP function 00564 TQString 00565 KCookieServer::getDomainAdvice(TQString url) 00566 { 00567 KCookieAdvice advice = KCookieDunno; 00568 TQString fqdn; 00569 TQString dummy; 00570 if (KCookieJar::parseURL(url, fqdn, dummy)) 00571 { 00572 TQStringList domains; 00573 mCookieJar->extractDomains(fqdn, domains); 00574 00575 TQStringList::ConstIterator it = domains.begin(); 00576 while ( (advice == KCookieDunno) && (it != domains.end()) ) 00577 { 00578 // Always check advice in both ".domain" and "domain". Note 00579 // that we only want to check "domain" if it matches the 00580 // fqdn of the requested URL. 00581 if ( (*it)[0] == '.' || (*it) == fqdn ) 00582 advice = mCookieJar->getDomainAdvice(*it); 00583 ++it; 00584 } 00585 if (advice == KCookieDunno) 00586 advice = mCookieJar->getGlobalAdvice(); 00587 } 00588 return KCookieJar::adviceToStr(advice); 00589 } 00590 00591 // DCOP function 00592 void 00593 KCookieServer::reloadPolicy() 00594 { 00595 mCookieJar->loadConfig( mConfig, true ); 00596 } 00597 00598 // DCOP function 00599 void 00600 KCookieServer::shutdown() 00601 { 00602 deleteLater(); 00603 } 00604 00605 #include "kcookieserver.moc" 00606