kio Library API Documentation

kpasswdserver.cpp

00001 /*
00002     This file is part of the KDE Cookie Jar
00003 
00004     Copyright (C) 2002 Waldo Bastian (bastian@kde.org)
00005 
00006     This library is free software; you can redistribute it and/or
00007     modify it under the terms of the GNU General Public License
00008     version 2 as published by the Free Software Foundation.
00009 
00010     This software is distributed in the hope that it will be useful,
00011     but WITHOUT ANY WARRANTY; without even the implied warranty of
00012     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013     General Public License for more details.
00014 
00015     You should have received a copy of the GNU General Public License
00016     along with this library; see the file COPYING. If not, write to
00017     the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00018     Boston, MA 02111-1307, USA.
00019 */
00020 //----------------------------------------------------------------------------
00021 //
00022 // KDE Password Server
00023 // $Id: kpasswdserver.cpp,v 1.5 2002/08/30 23:57:56 waba Exp $
00024 
00025 #include <time.h>
00026 
00027 #include <qtimer.h>
00028 
00029 #include <kapplication.h>
00030 #include <klocale.h>
00031 #include <kmessagebox.h>
00032 #include <kdebug.h>
00033 #include <kio/passdlg.h>
00034 
00035 #ifdef Q_WS_X11
00036 #include <X11/X.h>
00037 #include <X11/Xlib.h>
00038 #endif
00039 
00040 #include "kpasswdserver.h"
00041 
00042 extern "C" {
00043     KDEDModule *create_kpasswdserver(const QCString &name)
00044     {
00045        return new KPasswdServer(name);
00046     }
00047 };
00048 
00049 int
00050 KPasswdServer::AuthInfoList::compareItems(QPtrCollection::Item n1, QPtrCollection::Item n2)
00051 {
00052    if (!n1 || !n2)
00053       return 0;
00054             
00055    AuthInfo *i1 = (AuthInfo *) n1;
00056    AuthInfo *i2 = (AuthInfo *) n2;
00057          
00058    int l1 = i1->directory.length();
00059    int l2 = i2->directory.length();
00060          
00061    if (l1 > l2)
00062       return -1;
00063    if (l1 < l2)
00064       return 1;
00065    return 0;
00066 }
00067 
00068 
00069 KPasswdServer::KPasswdServer(const QCString &name)
00070  : KDEDModule(name)
00071 {
00072     m_authDict.setAutoDelete(true);
00073     m_authPending.setAutoDelete(true);
00074     m_seqNr = 0;
00075     connect(this, SIGNAL(windowUnregistered(long)), 
00076             this, SLOT(removeAuthForWindowId(long)));
00077 }
00078 
00079 KPasswdServer::~KPasswdServer()
00080 {
00081 }
00082 
00083 KIO::AuthInfo 
00084 KPasswdServer::checkAuthInfo(KIO::AuthInfo info, long windowId)
00085 {
00086     kdDebug() << "KPasswdServer::checkAuthInfo: User= " << info.username
00087               << ", WindowId = " << windowId << endl;
00088 
00089     QString key = createCacheKey(info);
00090 
00091     Request *request = m_authPending.first();
00092     QString path2 = info.url.directory(false, false);
00093     for(; request; request = m_authPending.next())
00094     {
00095        if (request->key != key)
00096            continue;
00097            
00098        if (info.verifyPath)
00099        {
00100           QString path1 = request->info.url.directory(false, false);
00101           if (!path2.startsWith(path1))
00102              continue;
00103        }
00104        
00105        request = new Request;
00106        request->client = callingDcopClient();
00107        request->transaction = request->client->beginTransaction();
00108        request->key = key;
00109        request->info = info;
00110        m_authWait.append(request);
00111        return info;
00112     }
00113 
00114     const AuthInfo *result = findAuthInfoItem(key, info);
00115     if (!result || result->isCanceled)
00116     {
00117        info.setModified(false);
00118        return info;
00119     }
00120 
00121     updateAuthExpire(key, result, windowId, false);
00122     
00123     return copyAuthInfo(result);
00124 }
00125 
00126 KIO::AuthInfo 
00127 KPasswdServer::queryAuthInfo(KIO::AuthInfo info, QString errorMsg, long windowId, long seqNr)
00128 {
00129     kdDebug() << "KPasswdServer::queryAuthInfo: User= " << info.username
00130               << ", Message= " << info.prompt << ", WindowId = " << windowId << endl;
00131     QString key = createCacheKey(info);
00132     Request *request = new Request;
00133     request->client = callingDcopClient();
00134     request->transaction = request->client->beginTransaction();
00135     request->key = key;
00136     request->info = info;
00137     request->windowId = windowId;
00138     request->seqNr = seqNr;
00139     request->errorMsg = errorMsg;
00140     m_authPending.append(request);
00141     
00142     if (m_authPending.count() == 1)
00143        QTimer::singleShot(0, this, SLOT(processRequest()));
00144 
00145     return info;
00146 }
00147 
00148 void
00149 KPasswdServer::addAuthInfo(KIO::AuthInfo info, long windowId)
00150 {
00151     kdDebug() << "KPasswdServer::addAuthInfo: User= " << info.username
00152               << ", RealmValue= " << info.realmValue << ", WindowId = " << windowId << endl;
00153     QString key = createCacheKey(info);
00154 
00155     m_seqNr++;
00156 
00157     addAuthInfoItem(key, info, windowId, m_seqNr, false);
00158 }
00159 
00160 void
00161 KPasswdServer::processRequest()
00162 {
00163     Request *request = m_authPending.first();
00164     if (!request)
00165        return;
00166 
00167     KIO::AuthInfo &info = request->info;
00168 
00169     kdDebug() << "KPasswdServer::processRequest: User= " << info.username
00170               << ", Message= " << info.prompt << endl;
00171               
00172     const AuthInfo *result = findAuthInfoItem(request->key, request->info);
00173     
00174     if (result && (request->seqNr < result->seqNr))
00175     {
00176         kdDebug() << "KPasswdServer::processRequest: auto retry!" << endl;
00177         if (result->isCanceled)
00178         {
00179            info.setModified(false);
00180         }
00181         else
00182         {
00183            updateAuthExpire(request->key, result, request->windowId, false);
00184            info = copyAuthInfo(result);
00185         }
00186     }
00187     else
00188     {
00189         m_seqNr++;
00190         bool askPw = true;
00191         if (result && !info.username.isEmpty() &&
00192             !request->errorMsg.isEmpty())
00193         {
00194            QString prompt = request->errorMsg;
00195            prompt += i18n("  Do you want to retry?");
00196            int dlgResult = KMessageBox::warningContinueCancel(0, prompt, 
00197                            i18n("Authentication"), i18n("Retry"));
00198            if (dlgResult != KMessageBox::Continue)
00199               askPw = false;
00200         }
00201               
00202         int dlgResult = QDialog::Rejected;
00203         if (askPw)
00204         {
00205             KIO::PasswordDialog dlg( info.prompt, info.username, info.keepPassword );
00206             if (info.caption.isEmpty())
00207                dlg.setPlainCaption( i18n("Authorization Dialog") );
00208             else
00209                dlg.setPlainCaption( info.caption );
00210                
00211             if ( !info.comment.isEmpty() )
00212                dlg.addCommentLine( info.commentLabel, info.comment );
00213                
00214             if ( !info.password.isEmpty() )
00215                dlg.setPassword( info.password );
00216              
00217             if (info.readOnly)
00218                dlg.setUserReadOnly( true );
00219               
00220             XSetTransientForHint( qt_xdisplay(), dlg.winId(), request->windowId);
00221             
00222             dlgResult = dlg.exec();
00223             
00224             if (dlgResult == QDialog::Accepted)
00225             {
00226                info.username = dlg.username();
00227                info.password = dlg.password();
00228                info.keepPassword = dlg.keepPassword();
00229             }
00230         }
00231         if ( dlgResult != QDialog::Accepted )
00232         {
00233             addAuthInfoItem(request->key, info, 0, m_seqNr, true);
00234             info.setModified( false );
00235         }
00236         else
00237         {
00238             addAuthInfoItem(request->key, info, request->windowId, m_seqNr, false);
00239             info.setModified( true );
00240         }
00241     }
00242 
00243     QCString replyType;
00244     QByteArray replyData;
00245 
00246     QDataStream stream2(replyData, IO_WriteOnly);
00247     stream2 << info << m_seqNr;
00248     replyType = "KIO::AuthInfo";
00249     request->client->endTransaction( request->transaction,
00250                                      replyType, replyData);
00251 
00252     m_authPending.remove((unsigned int) 0);
00253     
00254     // Check all requests in the wait queue.
00255     for(Request *waitRequest = m_authWait.first();
00256         waitRequest; )
00257     {
00258        bool keepQueued = false;
00259        QString key = waitRequest->key;
00260 
00261        request = m_authPending.first();
00262        QString path2 = waitRequest->info.url.directory(false, false);
00263        for(; request; request = m_authPending.next())
00264        {
00265            if (request->key != key)
00266                continue;
00267            
00268            if (info.verifyPath)
00269            {
00270                QString path1 = request->info.url.directory(false, false);
00271                if (!path2.startsWith(path1))
00272                    continue;
00273            }
00274        
00275            keepQueued = true;
00276            break;
00277        }
00278        if (keepQueued)
00279        {
00280            waitRequest = m_authWait.next();
00281        }
00282        else
00283        {
00284            const AuthInfo *result = findAuthInfoItem(waitRequest->key, waitRequest->info);
00285 
00286            QCString replyType;
00287            QByteArray replyData;
00288 
00289            QDataStream stream2(replyData, IO_WriteOnly);
00290 
00291            if (!result || result->isCanceled)
00292            {
00293                waitRequest->info.setModified(false);
00294                stream2 << waitRequest->info;
00295            }
00296            else
00297            {
00298                updateAuthExpire(waitRequest->key, result, waitRequest->windowId, false);
00299                KIO::AuthInfo info = copyAuthInfo(result);
00300                stream2 << info;
00301            }
00302 
00303            replyType = "KIO::AuthInfo";
00304            waitRequest->client->endTransaction( waitRequest->transaction,
00305                                                 replyType, replyData);
00306        
00307            m_authWait.remove();
00308            waitRequest = m_authWait.current();
00309        }
00310     }
00311 
00312     if (m_authPending.count())
00313        QTimer::singleShot(0, this, SLOT(processRequest()));
00314 
00315 }
00316 
00317 QString KPasswdServer::createCacheKey( const KIO::AuthInfo &info )
00318 {
00319     if( info.url.isMalformed() )
00320         return QString::null;
00321 
00322     // Generate the basic key sequence.
00323     QString key = info.url.protocol();
00324     key += '-';
00325     if (!info.url.user().isEmpty())
00326     {
00327        key += info.url.user();
00328        key += "@";
00329     }
00330     key += info.url.host();
00331     int port = info.url.port();
00332     if( port )
00333     {
00334       key += ':';
00335       key += QString::number(port);
00336     }
00337 
00338     return key;
00339 }
00340 
00341 KIO::AuthInfo 
00342 KPasswdServer::copyAuthInfo(const AuthInfo *i)
00343 {
00344     KIO::AuthInfo result;
00345     result.url = i->url;
00346     result.username = i->username;
00347     result.password = i->password;
00348     result.realmValue = i->realmValue;
00349     result.digestInfo = i->digestInfo; 
00350     result.setModified(true);
00351 
00352     return result;
00353 }
00354 
00355 const KPasswdServer::AuthInfo *
00356 KPasswdServer::findAuthInfoItem(const QString &key, const KIO::AuthInfo &info)
00357 {
00358    AuthInfoList *authList = m_authDict.find(key);
00359    if (!authList)
00360       return 0;
00361       
00362    QString path2 = info.url.directory(false, false);
00363    for(AuthInfo *current = authList->first();
00364        current; )
00365    {
00366        if ((current->expire == AuthInfo::expTime) && 
00367           (difftime(time(0), current->expireTime) > 0))
00368        {
00369           authList->remove();
00370           current = authList->current();
00371           continue;
00372        }
00373           
00374        if (info.verifyPath)
00375        {
00376           QString path1 = current->directory;
00377           if (path2.startsWith(path1))
00378              return current;
00379        }
00380        else
00381        {
00382           if (current->realmValue == info.realmValue)
00383              return current; // TODO: Update directory info, 
00384        }
00385           
00386        current = authList->next();
00387    }
00388    return 0;
00389 }
00390 
00391 void
00392 KPasswdServer::removeAuthInfoItem(const QString &key, const KIO::AuthInfo &info)
00393 {
00394    AuthInfoList *authList = m_authDict.find(key);
00395    if (!authList)
00396       return;
00397       
00398    for(AuthInfo *current = authList->first();
00399        current; )
00400    {
00401        if (current->realmValue == info.realmValue)
00402        {
00403           authList->remove();
00404           current = authList->current();
00405        }
00406        else
00407        {
00408           current = authList->next();
00409        }
00410    }
00411    if (authList->isEmpty())
00412    {
00413        m_authDict.remove(key);
00414    }
00415 }
00416 
00417 
00418 void
00419 KPasswdServer::addAuthInfoItem(const QString &key, const KIO::AuthInfo &info, long windowId, long seqNr, bool canceled)
00420 {
00421    AuthInfoList *authList = m_authDict.find(key);
00422    if (!authList)
00423    {
00424       authList = new AuthInfoList;
00425       m_authDict.insert(key, authList);
00426    }
00427    AuthInfo *current = authList->first();
00428    for(; current; current = authList->next())
00429    {
00430        if (current->realmValue == info.realmValue)
00431        {
00432           authList->take();
00433           break;
00434        }
00435    }
00436 
00437    if (!current)
00438    {
00439       current = new AuthInfo;
00440       current->expire = AuthInfo::expTime;
00441       kdDebug() << "Creating AuthInfo" << endl;
00442    }
00443    else
00444    {
00445       kdDebug() << "Updating AuthInfo" << endl;
00446    }
00447 
00448    current->url = info.url;
00449    current->directory = info.url.directory(false, false);
00450    current->username = info.username;
00451    current->password = info.password;
00452    current->realmValue = info.realmValue;
00453    current->digestInfo = info.digestInfo;
00454    current->seqNr = seqNr;
00455    current->isCanceled = canceled;
00456 
00457    updateAuthExpire(key, current, windowId, info.keepPassword && !canceled);
00458 
00459    // Insert into list, keep the list sorted "longest path" first.
00460    authList->inSort(current);
00461 }
00462 
00463 void 
00464 KPasswdServer::updateAuthExpire(const QString &key, const AuthInfo *auth, long windowId, bool keep)
00465 {
00466    AuthInfo *current = const_cast<AuthInfo *>(auth); 
00467    if (keep)
00468    {
00469       current->expire = AuthInfo::expNever;
00470    }
00471    else if (windowId && (current->expire != AuthInfo::expNever))
00472    {
00473       current->expire = AuthInfo::expWindowClose;
00474       if (!current->windowList.contains(windowId))
00475          current->windowList.append(windowId);
00476    }
00477    else if (current->expire == AuthInfo::expTime)
00478    {
00479       current->expireTime = time(0)+10;
00480    }
00481    
00482    // Update mWindowIdList
00483    if (windowId)
00484    {
00485       QStringList *keysChanged = mWindowIdList.find(windowId);
00486       if (!keysChanged)
00487       {
00488          keysChanged = new QStringList;
00489          mWindowIdList.insert(windowId, keysChanged);
00490       }
00491       if (!keysChanged->contains(key))
00492          keysChanged->append(key);
00493    }
00494 }
00495 
00496 void
00497 KPasswdServer::removeAuthForWindowId(long windowId)
00498 {
00499    QStringList *keysChanged = mWindowIdList.find(windowId);
00500    if (!keysChanged) return;
00501    
00502    for(QStringList::ConstIterator it = keysChanged->begin();
00503        it != keysChanged->end(); ++it)
00504    {
00505       QString key = *it;
00506       AuthInfoList *authList = m_authDict.find(key);
00507       if (!authList)
00508          continue;
00509 
00510       AuthInfo *current = authList->first();
00511       for(; current; )
00512       {
00513         if (current->expire == AuthInfo::expWindowClose)
00514         {
00515            if (current->windowList.remove(windowId) && current->windowList.isEmpty())
00516            {
00517               authList->remove();
00518               current = authList->current();
00519               continue;
00520            }
00521         }
00522         current = authList->next();
00523       }
00524    }
00525 }
00526 
00527 #include "kpasswdserver.moc"
KDE Logo
This file is part of the documentation for kdelibs Version 3.1.0.
Documentation copyright © 1996-2002 the KDE developers.
Generated on Wed Oct 8 12:21:31 2003 by doxygen 1.2.18 written by Dimitri van Heesch, © 1997-2001