kmail

cachedimapjob.cpp

00001 /*  -*- mode: C++; c-file-style: "gnu" -*-
00002  *
00003  *  This file is part of KMail, the KDE mail client.
00004  *  Copyright (c) 2002-2004  Bo Thorsen <bo@sonofthor.dk>
00005  *                2002-2003  Steffen Hansen <hansen@kde.org>
00006  *                2002-2003  Zack Rusin <zack@kde.org>
00007  *
00008  *  KMail is free software; you can redistribute it and/or modify it
00009  *  under the terms of the GNU General Public License, version 2, as
00010  *  published by the Free Software Foundation.
00011  *
00012  *  KMail is distributed in the hope that it will be useful, but
00013  *  WITHOUT ANY WARRANTY; without even the implied warranty of
00014  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  *  General Public License for more details.
00016  *
00017  *  You should have received a copy of the GNU General Public License
00018  *  along with this program; if not, write to the Free Software
00019  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
00020  *
00021  *  In addition, as a special exception, the copyright holders give
00022  *  permission to link the code of this program with any edition of
00023  *  the Qt library by Trolltech AS, Norway (or with modified versions
00024  *  of Qt that use the same license as Qt), and distribute linked
00025  *  combinations including the two.  You must obey the GNU General
00026  *  Public License in all respects for all of the code used other than
00027  *  Qt.  If you modify this file, you may extend this exception to
00028  *  your version of the file, but you are not obligated to do so.  If
00029  *  you do not wish to do so, delete this exception statement from
00030  *  your version.
00031  */
00032 
00033 #ifdef HAVE_CONFIG_H
00034 #include <config.h>
00035 #endif
00036 
00037 #include "cachedimapjob.h"
00038 #include "imapaccountbase.h"
00039 
00040 #include "kmfoldermgr.h"
00041 #include "kmfolder.h"
00042 #include "kmfoldercachedimap.h"
00043 #include "kmailicalifaceimpl.h"
00044 #include "kmacctcachedimap.h"
00045 #include "kmmsgdict.h"
00046 #include "maildirjob.h"
00047 #include "util.h"
00048 
00049 #include <kio/scheduler.h>
00050 #include <kio/job.h>
00051 
00052 #include <klocale.h>
00053 #include <kdebug.h>
00054 
00055 
00056 namespace KMail {
00057 
00058 // Get messages
00059 CachedImapJob::CachedImapJob( const QValueList<MsgForDownload>& msgs,
00060                               JobType type, KMFolderCachedImap* folder )
00061   : FolderJob( type ), mFolder( folder ), mMsgsForDownload( msgs ),
00062     mTotalBytes(0), mMsg(0), mParentFolder( 0 )
00063 {
00064   QValueList<MsgForDownload>::ConstIterator it = msgs.begin();
00065   for ( ; it != msgs.end() ; ++it )
00066     mTotalBytes += (*it).size;
00067 }
00068 
00069 // Put messages
00070 CachedImapJob::CachedImapJob( const QPtrList<KMMessage>& msgs, JobType type,
00071                               KMFolderCachedImap* folder )
00072   : FolderJob( msgs, QString::null, type, folder?folder->folder():0 ), mFolder( folder ),
00073     mTotalBytes( msgs.count() ), // we abuse it as "total number of messages"
00074     mMsg( 0 ), mParentFolder( 0 )
00075 {
00076 }
00077 
00078 CachedImapJob::CachedImapJob( const QValueList<unsigned long>& msgs,
00079                   JobType type, KMFolderCachedImap* folder )
00080   : FolderJob( QPtrList<KMMessage>(), QString::null, type, folder?folder->folder():0 ),
00081     mFolder( folder ), mSerNumMsgList( msgs ), mTotalBytes( msgs.count() ), mMsg( 0 ),
00082     mParentFolder ( 0 )
00083 {
00084 }
00085 
00086 // Add sub folders
00087 CachedImapJob::CachedImapJob( const QValueList<KMFolderCachedImap*>& fList,
00088                               JobType type, KMFolderCachedImap* folder )
00089   : FolderJob( type ), mFolder( folder ), mFolderList( fList ), mMsg( 0 ),
00090     mParentFolder ( 0 )
00091 {
00092 }
00093 
00094 // Rename folder
00095 CachedImapJob::CachedImapJob( const QString& string1, JobType type,
00096                               KMFolderCachedImap* folder )
00097   : FolderJob( type ), mFolder(folder), mMsg( 0 ), mString( string1 ),
00098     mParentFolder ( 0 )
00099 {
00100   assert( folder );
00101   assert( type != tDeleteMessage ); // moved to another ctor
00102 }
00103 
00104 // Delete folders or messages
00105 CachedImapJob::CachedImapJob( const QStringList& foldersOrMsgs, JobType type,
00106                               KMFolderCachedImap* folder )
00107   : FolderJob( type ), mFolder( folder ), mFoldersOrMessages( foldersOrMsgs ),
00108     mMsg( 0 ), mParentFolder( 0 )
00109 {
00110   assert( folder );
00111 }
00112 
00113 // Other jobs (list messages,expunge folder, check uid validity)
00114 CachedImapJob::CachedImapJob( JobType type, KMFolderCachedImap* folder )
00115   : FolderJob( type ), mFolder( folder ), mMsg( 0 ), mParentFolder ( 0 )
00116 {
00117   assert( folder );
00118 }
00119 
00120 CachedImapJob::~CachedImapJob()
00121 {
00122   mAccount->mJobList.remove(this);
00123 }
00124 
00125 void CachedImapJob::execute()
00126 {
00127   mSentBytes = 0;
00128 
00129   if( !mFolder ) {
00130     if( !mMsgList.isEmpty() ) {
00131       mFolder = static_cast<KMFolderCachedImap*>(mMsgList.first()->storage());
00132     }
00133   }
00134   assert( mFolder );
00135   mAccount = mFolder->account();
00136   assert( mAccount != 0 );
00137   if( mAccount->makeConnection() != ImapAccountBase::Connected ) {
00138     // No connection to the IMAP server
00139     kdDebug(5006) << "mAccount->makeConnection() failed" << endl;
00140     mPassiveDestructor = true;
00141     delete this;
00142     return;
00143   } else
00144     mPassiveDestructor = false;
00145 
00146   // All necessary conditions have been met. Register this job
00147   mAccount->mJobList.append(this);
00148 
00149   switch( mType ) {
00150   case tGetMessage:       slotGetNextMessage();     break;
00151   case tPutMessage:       slotPutNextMessage();     break;
00152   case tDeleteMessage:    slotDeleteNextMessages(); break;
00153   case tExpungeFolder:    expungeFolder();          break;
00154   case tAddSubfolders:    slotAddNextSubfolder();   break;
00155   case tDeleteFolders:    slotDeleteNextFolder();   break;
00156   case tCheckUidValidity: checkUidValidity();       break;
00157   case tRenameFolder:     renameFolder(mString);    break;
00158   case tListMessages:     listMessages();           break;
00159   default:
00160     assert( 0 );
00161   }
00162 }
00163 
00164 void CachedImapJob::listMessages()
00165 {
00166   KURL url = mAccount->getUrl();
00167   url.setPath( mFolder->imapPath() + ";UID=1:*;SECTION=FLAGS RFC822.SIZE");
00168 
00169   KIO::SimpleJob *job = KIO::get(url, false, false);
00170   KIO::Scheduler::assignJobToSlave( mAccount->slave(), job );
00171   ImapAccountBase::jobData jd( url.url(), mFolder->folder() );
00172   jd.cancellable = true;
00173   mAccount->insertJob( job, jd );
00174   connect( job, SIGNAL( result(KIO::Job *) ),
00175            this, SLOT( slotListMessagesResult( KIO::Job* ) ) );
00176   // send the data directly for KMFolderCachedImap
00177   connect( job, SIGNAL( data( KIO::Job*, const QByteArray& ) ),
00178            mFolder, SLOT( slotGetMessagesData( KIO::Job* , const QByteArray& ) ) );
00179 }
00180 
00181 void CachedImapJob::slotDeleteNextMessages( KIO::Job* job )
00182 {
00183   if (job) {
00184     KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
00185     if ( it == mAccount->jobsEnd() ) { // Shouldn't happen
00186       delete this;
00187       return;
00188     }
00189 
00190     if( job->error() ) {
00191       mAccount->handleJobError( job, i18n( "Error while deleting messages on the server: " ) + '\n' );
00192       delete this;
00193       return;
00194     }
00195     mAccount->removeJob(it);
00196   }
00197 
00198   if( mFoldersOrMessages.isEmpty() ) {
00199     // No more messages to delete
00200     delete this;
00201     return;
00202   }
00203 
00204   QString uids = mFoldersOrMessages.front(); mFoldersOrMessages.pop_front();
00205 
00206   KURL url = mAccount->getUrl();
00207   url.setPath( mFolder->imapPath() +
00208                QString::fromLatin1(";UID=%1").arg(uids) );
00209 
00210   KIO::SimpleJob *simpleJob = KIO::file_delete( url, false );
00211   KIO::Scheduler::assignJobToSlave( mAccount->slave(), simpleJob );
00212   ImapAccountBase::jobData jd( url.url(), mFolder->folder() );
00213   mAccount->insertJob( simpleJob, jd );
00214   connect( simpleJob, SIGNAL( result(KIO::Job *) ),
00215            this, SLOT( slotDeleteNextMessages(KIO::Job *) ) );
00216 }
00217 
00218 void CachedImapJob::expungeFolder()
00219 {
00220   KURL url = mAccount->getUrl();
00221   // Special URL that means EXPUNGE
00222   url.setPath( mFolder->imapPath() + QString::fromLatin1(";UID=*") );
00223 
00224   KIO::SimpleJob *job = KIO::file_delete( url, false );
00225   KIO::Scheduler::assignJobToSlave( mAccount->slave(), job );
00226   ImapAccountBase::jobData jd( url.url(), mFolder->folder() );
00227   mAccount->insertJob( job, jd );
00228   connect( job, SIGNAL( result(KIO::Job *) ),
00229            this, SLOT( slotExpungeResult(KIO::Job *) ) );
00230 }
00231 
00232 void CachedImapJob::slotExpungeResult( KIO::Job * job )
00233 {
00234   KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
00235   if ( it == mAccount->jobsEnd() ) { // Shouldn't happen
00236     delete this;
00237     return;
00238   }
00239 
00240   if (job->error()) {
00241     mErrorCode = job->error();
00242     mAccount->handleJobError( job, i18n( "Error while deleting messages on the server: " ) + '\n' );
00243   }
00244   else
00245     mAccount->removeJob(it);
00246 
00247   delete this;
00248 }
00249 
00250 void CachedImapJob::slotGetNextMessage(KIO::Job * job)
00251 {
00252   if (job) {
00253     KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
00254     if ( it == mAccount->jobsEnd() ) { // Shouldn't happen
00255       delete this;
00256       return;
00257     }
00258 
00259     if (job->error()) {
00260       mErrorCode = job->error();
00261       mAccount->handleJobError( job, i18n( "Error while retrieving message on the server: " ) + '\n' );
00262       delete this;
00263       return;
00264     }
00265 
00266     ulong size = 0;
00267     if ((*it).data.size() > 0) {
00268       ulong uid = mMsg->UID();
00269       size = mMsg->msgSizeServer();
00270 
00271       // Convert CR/LF to LF.
00272       size_t dataSize = (*it).data.size();
00273       dataSize = Util::crlf2lf( (*it).data.data(), dataSize ); // always <=
00274       (*it).data.resize( dataSize );
00275 
00276       mMsg->setComplete( true );
00277       mMsg->fromByteArray( (*it).data );
00278       mMsg->setUID(uid);
00279       mMsg->setMsgSizeServer(size);
00280       mMsg->setTransferInProgress( false );
00281       int index = 0;
00282       mFolder->addMsgInternal( mMsg, true, &index );
00283 
00284       if ( kmkernel->iCalIface().isResourceFolder( mFolder->folder() ) ) {
00285         mFolder->setStatus( index, KMMsgStatusRead, false );
00286       }
00287 
00288       emit messageRetrieved( mMsg );
00289       if ( index > 0 ) mFolder->unGetMsg( index );
00290     } else {
00291       emit messageRetrieved( 0 );
00292     }
00293     mMsg = 0;
00294 
00295     mSentBytes += size;
00296     emit progress( mSentBytes, mTotalBytes );
00297     mAccount->removeJob(it);
00298   } else
00299     mFolder->quiet( true );
00300 
00301   if( mMsgsForDownload.isEmpty() ) {
00302     mFolder->quiet( false );
00303     delete this;
00304     return;
00305   }
00306 
00307   MsgForDownload mfd = mMsgsForDownload.front(); mMsgsForDownload.pop_front();
00308 
00309   mMsg = new KMMessage;
00310   mMsg->setUID(mfd.uid);
00311   mMsg->setMsgSizeServer(mfd.size);
00312   if( mfd.flags > 0 )
00313     KMFolderImap::flagsToStatus(mMsg, mfd.flags);
00314   KURL url = mAccount->getUrl();
00315   url.setPath(mFolder->imapPath() + QString(";UID=%1;SECTION=BODY.PEEK[]").arg(mfd.uid));
00316 
00317   ImapAccountBase::jobData jd( url.url(), mFolder->folder() );
00318   jd.cancellable = true;
00319   mMsg->setTransferInProgress(true);
00320   KIO::SimpleJob *simpleJob = KIO::get(url, false, false);
00321   KIO::Scheduler::assignJobToSlave(mAccount->slave(), simpleJob);
00322   mAccount->insertJob(simpleJob, jd);
00323   connect(simpleJob, SIGNAL(processedSize(KIO::Job *, KIO::filesize_t)),
00324           this, SLOT(slotProcessedSize(KIO::Job *, KIO::filesize_t)));
00325   connect(simpleJob, SIGNAL(result(KIO::Job *)),
00326           this, SLOT(slotGetNextMessage(KIO::Job *)));
00327   connect(simpleJob, SIGNAL(data(KIO::Job *, const QByteArray &)),
00328           mFolder, SLOT(slotSimpleData(KIO::Job *, const QByteArray &)));
00329 }
00330 
00331 void CachedImapJob::slotProcessedSize(KIO::Job *, KIO::filesize_t processed)
00332 {
00333   emit progress( mSentBytes + processed, mTotalBytes );
00334 }
00335 
00336 void CachedImapJob::slotPutNextMessage()
00337 {
00338   mMsg = 0;
00339 
00340   // First try the message list
00341   if( !mMsgList.isEmpty() ) {
00342     mMsg = mMsgList.first();
00343     mMsgList.removeFirst();
00344   }
00345 
00346   // Now try the serial number list
00347   while( mMsg == 0 && !mSerNumMsgList.isEmpty() ) {
00348     unsigned long serNum = mSerNumMsgList.first();
00349     mSerNumMsgList.pop_front();
00350 
00351     // Find the message with this serial number
00352     int i = 0;
00353     KMFolder* aFolder = 0;
00354     KMMsgDict::instance()->getLocation( serNum, &aFolder, &i );
00355     if( mFolder->folder() != aFolder )
00356       // This message was moved or something
00357       continue;
00358     mMsg = mFolder->getMsg( i );
00359   }
00360 
00361   if( !mMsg ) {
00362     // No message found for upload
00363     delete this;
00364     return;
00365   }
00366 
00367   KURL url = mAccount->getUrl();
00368   QString flags = KMFolderImap::statusToFlags( mMsg->status() );
00369   url.setPath( mFolder->imapPath() + ";SECTION=" + flags );
00370 
00371   ImapAccountBase::jobData jd( url.url(), mFolder->folder() );
00372 
00373   mMsg->setUID( 0 ); // for the index
00374   QCString cstr(mMsg->asString());
00375   int a = cstr.find("\nX-UID: ");
00376   int b = cstr.find('\n', a);
00377   if (a != -1 && b != -1 && cstr.find("\n\n") > a) cstr.remove(a, b-a);
00378   QCString mData(cstr.length() + cstr.contains('\n'));
00379   unsigned int i = 0;
00380   for( char *ch = cstr.data(); *ch; ch++ ) {
00381     if ( *ch == '\n' ) {
00382       mData.at(i) = '\r';
00383       i++;
00384     }
00385     mData.at(i) = *ch; i++;
00386   }
00387   jd.data = mData;
00388   jd.msgList.append( mMsg );
00389 
00390   mMsg->setTransferInProgress(true);
00391   KIO::SimpleJob *simpleJob = KIO::put(url, 0, false, false, false);
00392   KIO::Scheduler::assignJobToSlave(mAccount->slave(), simpleJob);
00393   mAccount->insertJob(simpleJob, jd);
00394   connect( simpleJob, SIGNAL( result(KIO::Job *) ),
00395            SLOT( slotPutMessageResult(KIO::Job *) ) );
00396   connect( simpleJob, SIGNAL( dataReq(KIO::Job *, QByteArray &) ),
00397            SLOT( slotPutMessageDataReq(KIO::Job *, QByteArray &) ) );
00398   connect( simpleJob, SIGNAL( data(KIO::Job *, const QByteArray &) ),
00399            mFolder, SLOT( slotSimpleData(KIO::Job *, const QByteArray &) ) );
00400   connect( simpleJob, SIGNAL(infoMessage(KIO::Job *, const QString &)),
00401              SLOT(slotPutMessageInfoData(KIO::Job *, const QString &)) );
00402 
00403 }
00404 
00405 //-----------------------------------------------------------------------------
00406 // TODO: port to KIO::StoredTransferJob once it's ok to require kdelibs-3.3
00407 void CachedImapJob::slotPutMessageDataReq(KIO::Job *job, QByteArray &data)
00408 {
00409   KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
00410   if ( it == mAccount->jobsEnd() ) { // Shouldn't happen
00411     delete this;
00412     return;
00413   }
00414   if ((*it).data.size() - (*it).offset > 0x8000) {
00415     data.duplicate((*it).data.data() + (*it).offset, 0x8000);
00416     (*it).offset += 0x8000;
00417   } else if ((*it).data.size() - (*it).offset > 0) {
00418     data.duplicate((*it).data.data() + (*it).offset,
00419                    (*it).data.size() - (*it).offset);
00420     (*it).offset = (*it).data.size();
00421   } else
00422     data.resize(0);
00423 }
00424 
00425 //----------------------------------------------------------------------------
00426 void CachedImapJob::slotPutMessageInfoData(KIO::Job *job, const QString &data)
00427 {
00428   KMFolderCachedImap * imapFolder = static_cast<KMFolderCachedImap*>(mDestFolder->storage());
00429   KMAcctCachedImap *account = imapFolder->account();
00430   ImapAccountBase::JobIterator it = account->findJob( job );
00431   if ( it == account->jobsEnd() ) return;
00432 
00433   if ( data.find("UID") != -1 && mMsg )
00434   {
00435     int uid = (data.right(data.length()-4)).toInt();
00436     kdDebug( 5006 ) << k_funcinfo << "Server told us uid is: " << uid << endl;
00437     mMsg->setUID( uid );
00438   }
00439 }
00440 
00441 
00442 //-----------------------------------------------------------------------------
00443 void CachedImapJob::slotPutMessageResult(KIO::Job *job)
00444 {
00445   KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
00446   if ( it == mAccount->jobsEnd() ) { // Shouldn't happen
00447     delete this;
00448     return;
00449   }
00450 
00451   if ( job->error() ) {
00452     bool cont = mAccount->handlePutError( job, *it, mFolder->folder() );
00453     if ( !cont ) {
00454       delete this;
00455     } else {
00456       mMsg = 0;
00457       slotPutNextMessage();
00458     }
00459     return;
00460   }
00461 
00462   emit messageStored( mMsg );
00463 
00464   // we abuse those fields, the unit is the number of messages, here
00465   ++mSentBytes;
00466   emit progress( mSentBytes, mTotalBytes );
00467 
00468   int i;
00469   if( ( i = mFolder->find(mMsg) ) != -1 ) {
00470      /*
00471       * If we have aquired a uid during upload the server supports the uidnext
00472       * extension and there is no need to redownload this mail, we already have
00473       * it. Otherwise remove it, it will be redownloaded.
00474       */
00475      if ( mMsg->UID() == 0 ) {
00476         mFolder->removeMsg(i);
00477      } else {
00478         // When removing+readding, no point in telling the imap resources about it
00479         bool b = kmkernel->iCalIface().isResourceQuiet();
00480         kmkernel->iCalIface().setResourceQuiet( true );
00481 
00482         mFolder->take( i );
00483         mFolder->addMsgKeepUID( mMsg );
00484         mMsg->setTransferInProgress( false );
00485 
00486         kmkernel->iCalIface().setResourceQuiet( b );
00487      }
00488   }
00489   mMsg = NULL;
00490   mAccount->removeJob( it );
00491   slotPutNextMessage();
00492 }
00493 
00494 
00495 void CachedImapJob::slotAddNextSubfolder( KIO::Job * job )
00496 {
00497   if (job) {
00498     KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
00499     if ( it == mAccount->jobsEnd() ) { // Shouldn't happen
00500       delete this;
00501       return;
00502     }
00503 
00504     // make copy of setting, to reset it before potentially destroying 'it'
00505     bool silentUpload = static_cast<KMFolderCachedImap*>((*it).parent->storage())->silentUpload();
00506     static_cast<KMFolderCachedImap*>((*it).parent->storage())->setSilentUpload( false );
00507 
00508     if ( job->error() && !silentUpload ) {
00509       QString myError = "<p><b>" + i18n("Error while uploading folder")
00510         + "</b></p><p>" + i18n("Could not make the folder <b>%1</b> on the server.").arg((*it).items[0])
00511         + "</p><p>" + i18n("This could be because you do not have permission to do this, or because the folder is already present on the server; the error message from the server communication is here:") + "</p>";
00512       mAccount->handleJobError( job, myError );
00513     }
00514 
00515     if( job->error() ) {
00516       delete this;
00517       return;
00518     }
00519     mAccount->removeJob( it );
00520   }
00521 
00522   if (mFolderList.isEmpty()) {
00523     // No more folders to add
00524     delete this;
00525     return;
00526   }
00527 
00528   KMFolderCachedImap *folder = mFolderList.front();
00529   mFolderList.pop_front();
00530   KURL url = mAccount->getUrl();
00531   QString path = mAccount->createImapPath( mFolder->imapPath(), 
00532       folder->folder()->name() );
00533   if ( !folder->imapPathForCreation().isEmpty() ) {
00534     // the folder knows it's namespace
00535     path = folder->imapPathForCreation();
00536   }
00537   url.setPath( path );
00538 
00539   // Associate the jobData with the parent folder, not with the child
00540   // This is necessary in case of an error while creating the subfolder,
00541   // so that folderComplete is called on the parent (and the sync resetted).
00542   ImapAccountBase::jobData jd( url.url(), mFolder->folder() );
00543   jd.items << folder->label(); // for the err msg
00544   KIO::SimpleJob *simpleJob = KIO::mkdir(url);
00545   KIO::Scheduler::assignJobToSlave(mAccount->slave(), simpleJob);
00546   mAccount->insertJob(simpleJob, jd);
00547   connect( simpleJob, SIGNAL(result(KIO::Job *)),
00548            this, SLOT(slotAddNextSubfolder(KIO::Job *)) );
00549 }
00550 
00551 
00552 void CachedImapJob::slotDeleteNextFolder( KIO::Job *job )
00553 {
00554   if (job) {
00555     KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
00556     if ( it == mAccount->jobsEnd() ) { // Shouldn't happen
00557       delete this;
00558       return;
00559     }
00560 
00561     mAccount->removeDeletedFolder( (*it).path );
00562 
00563     if( job->error() ) {
00564       mAccount->handleJobError( job, i18n( "Error while deleting folder %1 on the server: " ).arg( (*it).path ) + '\n' );
00565       delete this;
00566       return;
00567     }
00568     mAccount->removeJob(it);
00569   }
00570 
00571   if( mFoldersOrMessages.isEmpty() ) {
00572     // No more folders to delete
00573     delete this;
00574     return;
00575   }
00576 
00577   QString folderPath = mFoldersOrMessages.front();
00578   mFoldersOrMessages.pop_front();
00579   KURL url = mAccount->getUrl();
00580   url.setPath(folderPath);
00581   ImapAccountBase::jobData jd( url.url(), mFolder->folder() );
00582   jd.path = url.path();
00583   KIO::SimpleJob *simpleJob = KIO::file_delete(url, false);
00584   KIO::Scheduler::assignJobToSlave(mAccount->slave(), simpleJob);
00585   mAccount->insertJob(simpleJob, jd);
00586   connect( simpleJob, SIGNAL( result(KIO::Job *) ),
00587            SLOT( slotDeleteNextFolder(KIO::Job *) ) );
00588 }
00589 
00590 void CachedImapJob::checkUidValidity()
00591 {
00592   KURL url = mAccount->getUrl();
00593   url.setPath( mFolder->imapPath() + ";UID=0:0" );
00594 
00595   ImapAccountBase::jobData jd( url.url(), mFolder->folder() );
00596   jd.cancellable = true;
00597 
00598   KIO::SimpleJob *job = KIO::get( url, false, false );
00599   KIO::Scheduler::assignJobToSlave( mAccount->slave(), job );
00600   mAccount->insertJob( job, jd );
00601   connect( job, SIGNAL(result(KIO::Job *)),
00602            SLOT(slotCheckUidValidityResult(KIO::Job *)) );
00603   connect( job, SIGNAL(data(KIO::Job *, const QByteArray &)),
00604            mFolder, SLOT(slotSimpleData(KIO::Job *, const QByteArray &)));
00605 }
00606 
00607 void CachedImapJob::slotCheckUidValidityResult(KIO::Job * job)
00608 {
00609   KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
00610   if ( it == mAccount->jobsEnd() ) { // Shouldn't happen
00611     delete this;
00612     return;
00613   }
00614 
00615   if( job->error() ) {
00616     mErrorCode = job->error();
00617     mAccount->handleJobError( job, i18n( "Error while reading folder %1 on the server: " ).arg( (*it).parent->label() ) + '\n' );
00618     delete this;
00619     return;
00620   }
00621 
00622   // Check the uidValidity
00623   QCString cstr((*it).data.data(), (*it).data.size() + 1);
00624   int a = cstr.find("X-uidValidity: ");
00625   if (a < 0) {
00626     // Something is seriously rotten here!
00627     // TODO: Tell the user that he has a problem
00628     kdDebug(5006) << "No uidvalidity available for folder "
00629                   << mFolder->name() << endl;
00630   }
00631   else {
00632     int b = cstr.find("\r\n", a);
00633     if ( (b - a - 15) >= 0 ) {
00634       QString uidv = cstr.mid(a + 15, b - a - 15);
00635       // kdDebug(5006) << "New uidv = " << uidv << ", old uidv = "
00636       //               << mFolder->uidValidity() << endl;
00637       if( !mFolder->uidValidity().isEmpty() && mFolder->uidValidity() != uidv ) {
00638         // kdDebug(5006) << "Expunging the mailbox " << mFolder->name()
00639         //               << "!" << endl;
00640         mFolder->expunge();
00641         mFolder->setLastUid( 0 );
00642         mFolder->clearUidMap();
00643       }
00644     } else
00645       kdDebug(5006) << "No uidvalidity available for folder "
00646                     << mFolder->name() << endl;
00647   }
00648 
00649   mAccount->removeJob(it);
00650   delete this;
00651 }
00652 
00653 
00654 void CachedImapJob::renameFolder( const QString &newName )
00655 {
00656   // Set the source URL
00657   KURL urlSrc = mAccount->getUrl();
00658   urlSrc.setPath( mFolder->imapPath() );
00659 
00660   // Set the destination URL - this is a bit trickier
00661   KURL urlDst = mAccount->getUrl();
00662   QString imapPath( mFolder->imapPath() );
00663   // Destination url = old imappath - oldname + new name
00664   imapPath.truncate( imapPath.length() - mFolder->folder()->name().length() - 1);
00665   imapPath += newName + '/';
00666   urlDst.setPath( imapPath );
00667 
00668   ImapAccountBase::jobData jd( newName, mFolder->folder() );
00669   jd.path = imapPath;
00670 
00671   KIO::SimpleJob *simpleJob = KIO::rename( urlSrc, urlDst, false );
00672   KIO::Scheduler::assignJobToSlave( mAccount->slave(), simpleJob );
00673   mAccount->insertJob( simpleJob, jd );
00674   connect( simpleJob, SIGNAL(result(KIO::Job *)),
00675            SLOT(slotRenameFolderResult(KIO::Job *)) );
00676 }
00677 
00678 static void renameChildFolders( KMFolderDir* dir, const QString& oldPath,
00679                                 const QString& newPath )
00680 {
00681   if( dir ) {
00682     KMFolderNode *node = dir->first();
00683     while( node ) {
00684       if( !node->isDir() ) {
00685         KMFolderCachedImap* imapFolder =
00686           static_cast<KMFolderCachedImap*>(static_cast<KMFolder*>(node)->storage());
00687         if ( !imapFolder->imapPath().isEmpty() )
00688           // Only rename folders that have been accepted by the server
00689           if( imapFolder->imapPath().find( oldPath ) == 0 ) {
00690             QString p = imapFolder->imapPath();
00691             p = p.mid( oldPath.length() );
00692             p.prepend( newPath );
00693             imapFolder->setImapPath( p );
00694             renameChildFolders( imapFolder->folder()->child(), oldPath, newPath );
00695           }
00696       }
00697       node = dir->next();
00698     }
00699   }
00700 }
00701 
00702 void CachedImapJob::slotRenameFolderResult( KIO::Job *job )
00703 {
00704   KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
00705   if ( it == mAccount->jobsEnd() ) { // Shouldn't happen
00706     delete this;
00707     return;
00708   }
00709 
00710 
00711   if( job->error() ) {
00712     // Error, revert label change
00713     QMap<QString, KMAcctCachedImap::RenamedFolder>::ConstIterator renit = mAccount->renamedFolders().find( mFolder->imapPath() );
00714     Q_ASSERT( renit != mAccount->renamedFolders().end() );
00715     if ( renit != mAccount->renamedFolders().end() ) {
00716       mFolder->folder()->setLabel( (*renit).mOldLabel );
00717       mAccount->removeRenamedFolder( mFolder->imapPath() );
00718     }
00719     mAccount->handleJobError( job, i18n( "Error while trying to rename folder %1" ).arg( mFolder->label() ) + '\n' );
00720   } else {
00721     // Okay, the folder seems to be renamed on the server,
00722     // now rename it on disk
00723     QString oldName = mFolder->name();
00724     QString oldPath = mFolder->imapPath();
00725     mAccount->removeRenamedFolder( oldPath );
00726     mFolder->setImapPath( (*it).path );
00727     mFolder->FolderStorage::rename( (*it).url );
00728 
00729     if( oldPath.endsWith( "/" ) ) oldPath.truncate( oldPath.length() -1 );
00730     QString newPath = mFolder->imapPath();
00731     if( newPath.endsWith( "/" ) ) newPath.truncate( newPath.length() -1 );
00732     renameChildFolders( mFolder->folder()->child(), oldPath, newPath );
00733     kmkernel->dimapFolderMgr()->contentsChanged();
00734 
00735     mAccount->removeJob(it);
00736   }
00737   delete this;
00738 }
00739 
00740 void CachedImapJob::slotListMessagesResult( KIO::Job * job )
00741 {
00742   KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
00743   if ( it == mAccount->jobsEnd() ) { // Shouldn't happen
00744     delete this;
00745     return;
00746   }
00747 
00748   if (job->error()) {
00749     mErrorCode = job->error();
00750     mAccount->handleJobError( job, i18n( "Error while deleting messages on the server: " ) + '\n' );
00751   }
00752   else
00753     mAccount->removeJob(it);
00754 
00755   delete this;
00756 }
00757 
00758 //-----------------------------------------------------------------------------
00759 void CachedImapJob::setParentFolder( const KMFolderCachedImap* parent )
00760 {
00761   mParentFolder = const_cast<KMFolderCachedImap*>( parent );
00762 }
00763 
00764 }
00765 
00766 #include "cachedimapjob.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys