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