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 "scalix.h"
00048 #include "util.h"
00049 
00050 #include <kio/scheduler.h>
00051 #include <kio/job.h>
00052 
00053 #include <klocale.h>
00054 #include <kdebug.h>
00055 
00056 /*
00057 static QString typeStr( FolderJob::JobType type )
00058 {
00059   switch( type ) {
00060     case FolderJob::tListMessages:
00061       return "tListMessages";
00062     case FolderJob::tGetFolder:
00063       return "tGetFolder";
00064     case FolderJob::tCreateFolder:
00065       return "tCreateFolder";
00066     case FolderJob::tExpungeFolder:
00067       return "tExpungeFolder";
00068     case FolderJob::tDeleteMessage:
00069       return "tDeleteMessage";
00070     case FolderJob::tGetMessage:
00071       return "tGetMessage";
00072     case FolderJob::tPutMessage:
00073       return "tPutMessage";
00074     case FolderJob::tAddSubfolders:
00075       return "tAddSubfolders";
00076     case FolderJob::tDeleteFolders:
00077       return "tDeleteFolders";
00078     case FolderJob::tCheckUidValidity:
00079       return "tCheckUidValidity";
00080     case FolderJob::tRenameFolder:
00081       return "tRenameFolder";
00082     case FolderJob::tCopyMessage:
00083       return "tCopyMessage";
00084     case FolderJob::tMoveMessage:
00085       return "tMoveMessage";
00086     case FolderJob::tOther:
00087       return "tOther";
00088   }
00089 } */
00090 
00091 //int KMail::CachedImapJob::sJobCount = 0;
00092 
00093 namespace KMail {
00094 
00095 // Get messages
00096 CachedImapJob::CachedImapJob( const QValueList<MsgForDownload>& msgs,
00097                               JobType type, KMFolderCachedImap* folder )
00098   : FolderJob( type ), mFolder( folder ), mMsgsForDownload( msgs ),
00099     mTotalBytes(0), mMsg(0), mParentFolder( 0 ), m_dbgCurrentSerNum( 0 )
00100 {
00101   /*
00102   sJobCount++;
00103   QString prep = "";
00104   for ( int i = 0; i< sJobCount; i++ )
00105   {
00106     prep += "+";
00107   }
00108   //kdDebug(5006) <<prep<< "DEBUG CachedImapJob()0: " << this << " " << typestr(type) << msgs.count() << endl;
00109   */
00110   QValueList<MsgForDownload>::ConstIterator it = msgs.begin();
00111   for ( ; it != msgs.end() ; ++it )
00112     mTotalBytes += (*it).size;
00113 }
00114 
00115 // Put messages
00116 CachedImapJob::CachedImapJob( const QPtrList<KMMessage>& msgs, JobType type,
00117                               KMFolderCachedImap* folder )
00118   : FolderJob( msgs, QString::null, type, folder?folder->folder():0 ), mFolder( folder ),
00119     mTotalBytes( msgs.count() ), // we abuse it as "total number of messages"
00120     mMsg( 0 ), mParentFolder( 0 ), m_dbgCurrentSerNum( 0 )
00121 {
00122   /*
00123   sJobCount++;
00124   QString prep = "";
00125   for ( int i = 0; i< sJobCount; i++ )
00126   {
00127     prep += "+";
00128   }
00129   kdDebug(5006) <<prep<< "DEBUG CachedImapJob()1 "  << this << " "<< typeStr(type) << endl;
00130   */
00131 }
00132 
00133 CachedImapJob::CachedImapJob( const QValueList<unsigned long>& msgs,
00134                   JobType type, KMFolderCachedImap* folder )
00135   : FolderJob( QPtrList<KMMessage>(), QString::null, type, folder?folder->folder():0 ),
00136     mFolder( folder ), mSerNumMsgList( msgs ), mTotalBytes( msgs.count() ), mMsg( 0 ),
00137     mParentFolder ( 0 ), m_dbgCurrentSerNum( 0 )
00138 {
00139   /*
00140   sJobCount++;
00141   QString prep = "";
00142   for ( int i = 0; i< sJobCount; i++ )
00143   {
00144     prep += "+";
00145   }
00146   kdDebug(5006) << prep << "DEBUG CachedImapJob()2 " << this <<" "<< typeStr(type) << endl;
00147   */
00148 }
00149 
00150 // Add sub folders
00151 CachedImapJob::CachedImapJob( const QValueList<KMFolderCachedImap*>& fList,
00152                               JobType type, KMFolderCachedImap* folder )
00153   : FolderJob( type ), mFolder( folder ), mFolderList( fList ), mMsg( 0 ),
00154     mParentFolder ( 0 ), m_dbgCurrentSerNum( 0 )
00155 {
00156   /*
00157   sJobCount++;
00158   QString prep = "";
00159   for ( int i = 0; i< sJobCount; i++ )
00160   {
00161     prep += "+";
00162   }
00163   kdDebug(5006) <<prep<< "DEBUG CachedImapJob()3 " << this <<" "<< typeStr(type) << endl;
00164   */
00165 }
00166 
00167 // Rename folder
00168 CachedImapJob::CachedImapJob( const QString& string1, JobType type,
00169                               KMFolderCachedImap* folder )
00170   : FolderJob( type ), mFolder(folder), mMsg( 0 ), mString( string1 ),
00171     mParentFolder ( 0 ), m_dbgCurrentSerNum( 0 )
00172 {
00173   /*
00174   sJobCount++;
00175    QString prep = "";
00176   for ( int i = 0; i< sJobCount; i++ )
00177   {
00178     prep += "+";
00179   }
00180   kdDebug(5006) <<prep<< "DEBUG CachedImapJob()4 " << this <<" "<<typeStr(type) << endl;
00181   */
00182   assert( folder );
00183   assert( type != tDeleteMessage ); // moved to another ctor
00184 }
00185 
00186 // Delete folders or messages
00187 CachedImapJob::CachedImapJob( const QStringList& foldersOrMsgs, JobType type,
00188                               KMFolderCachedImap* folder )
00189   : FolderJob( type ), mFolder( folder ), mFoldersOrMessages( foldersOrMsgs ),
00190     mMsg( 0 ), mParentFolder( 0 ), m_dbgCurrentSerNum( 0 )
00191 {
00192   /*
00193   sJobCount++;
00194   QString prep = "";
00195   for ( int i = 0; i< sJobCount; i++ )
00196   {
00197     prep += "+";
00198   }
00199   kdDebug(5006) <<prep<< "DEBUG CachedImapJob()5 " << this <<" "<< typeStr(type) << endl;
00200   */
00201   assert( folder );
00202 }
00203 
00204 // Other jobs (list messages,expunge folder, check uid validity)
00205 CachedImapJob::CachedImapJob( JobType type, KMFolderCachedImap* folder )
00206   : FolderJob( type ), mFolder( folder ), mMsg( 0 ), mParentFolder ( 0 ), m_dbgCurrentSerNum( 0 )
00207 {
00208   /*
00209   sJobCount++;
00210   QString prep = "";
00211   for ( int i = 0; i< sJobCount; i++ )
00212   {
00213     prep += "+";
00214   }
00215   kdDebug(5006) <<prep<< "DEBUG CachedImapJob()6" << this << " type=" << typeStr(type) << endl;
00216   */
00217   assert( folder );
00218 }
00219 
00220 CachedImapJob::~CachedImapJob()
00221 {
00222   mAccount->mJobList.remove(this);
00223   /*
00224   sJobCount--;
00225   QString prep = "~";
00226   for ( int i = 0; i< sJobCount; i++ )
00227   {
00228     prep += "~";
00229   }
00230   kdDebug(5006) << prep << "DEBUG ~CachedImapJob:: of type " << typeStr( mType ) << "("<< this << ")"<<endl;
00231   */
00232 }
00233 
00234 void CachedImapJob::execute()
00235 {
00236   mSentBytes = 0;
00237 
00238   if( !mFolder ) {
00239     if( !mMsgList.isEmpty() ) {
00240       mFolder = static_cast<KMFolderCachedImap*>(mMsgList.first()->storage());
00241     }
00242   }
00243   assert( mFolder );
00244   mAccount = mFolder->account();
00245   assert( mAccount != 0 );
00246   if( mAccount->makeConnection() != ImapAccountBase::Connected ) {
00247     // No connection to the IMAP server
00248     kdDebug(5006) << "mAccount->makeConnection() failed" << endl;
00249     mPassiveDestructor = true;
00250     delete this;
00251     return;
00252   } else
00253     mPassiveDestructor = false;
00254 
00255   // All necessary conditions have been met. Register this job
00256   mAccount->mJobList.append(this);
00257 
00264   if ( mAccount->groupwareType() == KMAcctCachedImap::GroupwareScalix ) {
00265     if ( !mAccount->sentCustomLoginCommand() ) {
00266       QByteArray packedArgs;
00267       QDataStream stream( packedArgs, IO_WriteOnly );
00268 
00269       const QString command = QString( "X-SCALIX-ID " );
00270       const QString argument = QString( "(\"name\" \"Evolution\" \"version\" \"2.10.0\")" );
00271 
00272       stream << (int) 'X' << 'N' << command << argument;
00273 
00274       const KURL url = mAccount->getUrl();
00275 
00276       ImapAccountBase::jobData jd( url.url(), mFolder->folder() );
00277       jd.items << mFolder->label(); // for the err msg
00278       KIO::SimpleJob *simpleJob = KIO::special( url.url(), packedArgs, false );
00279       KIO::Scheduler::assignJobToSlave(mAccount->slave(), simpleJob);
00280       mAccount->insertJob(simpleJob, jd);
00281 
00282       mAccount->setSentCustomLoginCommand( true );
00283     }
00284   }
00285 
00286   switch( mType ) {
00287   case tGetMessage:       slotGetNextMessage();     break;
00288   case tPutMessage:       slotPutNextMessage();     break;
00289   case tDeleteMessage:    slotDeleteNextMessages(); break;
00290   case tExpungeFolder:    expungeFolder();          break;
00291   case tAddSubfolders:    slotAddNextSubfolder();   break;
00292   case tDeleteFolders:    slotDeleteNextFolder();   break;
00293   case tCheckUidValidity: checkUidValidity();       break;
00294   case tRenameFolder:     renameFolder(mString);    break;
00295   case tListMessages:     listMessages();           break;
00296   default:
00297     assert( 0 );
00298   }
00299 }
00300 
00301 void CachedImapJob::listMessages()
00302 {
00303   KURL url = mAccount->getUrl();
00304   url.setPath( mFolder->imapPath() + ";UID=1:*;SECTION=FLAGS RFC822.SIZE");
00305 
00306   KIO::SimpleJob *job = KIO::get(url, false, false);
00307   KIO::Scheduler::assignJobToSlave( mAccount->slave(), job );
00308   ImapAccountBase::jobData jd( url.url(), mFolder->folder() );
00309   jd.cancellable = true;
00310   mAccount->insertJob( job, jd );
00311   connect( job, SIGNAL( result(KIO::Job *) ),
00312            this, SLOT( slotListMessagesResult( KIO::Job* ) ) );
00313   // send the data directly for KMFolderCachedImap
00314   connect( job, SIGNAL( data( KIO::Job*, const QByteArray& ) ),
00315            mFolder, SLOT( slotGetMessagesData( KIO::Job* , const QByteArray& ) ) );
00316 }
00317 
00318 void CachedImapJob::slotDeleteNextMessages( KIO::Job* job )
00319 {
00320   if (job) {
00321     KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
00322     if ( it == mAccount->jobsEnd() ) { // Shouldn't happen
00323       delete this;
00324       return;
00325     }
00326 
00327     if( job->error() ) {
00328       mAccount->handleJobError( job, i18n( "Error while deleting messages on the server: " ) + '\n' );
00329       delete this;
00330       return;
00331     }
00332     mAccount->removeJob(it);
00333   }
00334 
00335   if( mFoldersOrMessages.isEmpty() ) {
00336     // No more messages to delete
00337     delete this;
00338     return;
00339   }
00340 
00341   QString uids = mFoldersOrMessages.front(); mFoldersOrMessages.pop_front();
00342 
00343   KURL url = mAccount->getUrl();
00344   url.setPath( mFolder->imapPath() +
00345                QString::fromLatin1(";UID=%1").arg(uids) );
00346 
00347   KIO::SimpleJob *simpleJob = KIO::file_delete( url, false );
00348   KIO::Scheduler::assignJobToSlave( mAccount->slave(), simpleJob );
00349   ImapAccountBase::jobData jd( url.url(), mFolder->folder() );
00350   mAccount->insertJob( simpleJob, jd );
00351   connect( simpleJob, SIGNAL( result(KIO::Job *) ),
00352            this, SLOT( slotDeleteNextMessages(KIO::Job *) ) );
00353 }
00354 
00355 void CachedImapJob::expungeFolder()
00356 {
00357   KURL url = mAccount->getUrl();
00358   // Special URL that means EXPUNGE
00359   url.setPath( mFolder->imapPath() + QString::fromLatin1(";UID=*") );
00360 
00361   KIO::SimpleJob *job = KIO::file_delete( url, false );
00362   KIO::Scheduler::assignJobToSlave( mAccount->slave(), job );
00363   ImapAccountBase::jobData jd( url.url(), mFolder->folder() );
00364   mAccount->insertJob( job, jd );
00365   connect( job, SIGNAL( result(KIO::Job *) ),
00366            this, SLOT( slotExpungeResult(KIO::Job *) ) );
00367 }
00368 
00369 void CachedImapJob::slotExpungeResult( KIO::Job * job )
00370 {
00371   KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
00372   if ( it == mAccount->jobsEnd() ) { // Shouldn't happen
00373     delete this;
00374     return;
00375   }
00376 
00377   if (job->error()) {
00378     mErrorCode = job->error();
00379     mAccount->handleJobError( job, i18n( "Error while deleting messages on the server: " ) + '\n' );
00380   }
00381   else
00382     mAccount->removeJob(it);
00383 
00384   delete this;
00385 }
00386 
00387 void CachedImapJob::slotGetNextMessage(KIO::Job * job)
00388 {
00389   if (job) {
00390     KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
00391     if ( it == mAccount->jobsEnd() ) { // Shouldn't happen
00392       delete this;
00393       return;
00394     }
00395 
00396     if (job->error()) {
00397       mErrorCode = job->error();
00398       mAccount->handleJobError( job, i18n( "Error while retrieving message on the server: " ) + '\n' );
00399       delete this;
00400       return;
00401     }
00402 
00403     ulong size = 0;
00404     if ((*it).data.size() > 0) {
00405       ulong uid = mMsg->UID();
00406       size = mMsg->msgSizeServer();
00407 
00408       // Convert CR/LF to LF.
00409       size_t dataSize = (*it).data.size();
00410       dataSize = Util::crlf2lf( (*it).data.data(), dataSize ); // always <=
00411       (*it).data.resize( dataSize );
00412 
00413       mMsg->setComplete( true );
00414       mMsg->fromByteArray( (*it).data );
00415       mMsg->setUID(uid);
00416       mMsg->setMsgSizeServer(size);
00417       mMsg->setTransferInProgress( false );
00418       int index = -1;
00419       mFolder->open( "KMFolderCachedImap::slotGetNextMessage" );
00420       //kdDebug(5006) << "/DEBUG CachedImapJob: slotGetNextMessage: " << this << endl;
00421       mFolder->addMsgInternal( mMsg, true, &index );
00422 
00423       if ( kmkernel->iCalIface().isResourceFolder( mFolder->folder() ) ) {
00424         mFolder->setStatus( index, KMMsgStatusRead, false );
00425       }
00426       mFolder->close( "KMFolderCachedImap::slotGetNextMessage" );
00427 
00428       emit messageRetrieved( mMsg );
00429       if ( index >= 0 ) mFolder->unGetMsg( index );
00430     } else {
00431       emit messageRetrieved( 0 );
00432     }
00433     mMsg = 0;
00434 
00435     mSentBytes += size;
00436     emit progress( mSentBytes, mTotalBytes );
00437     mAccount->removeJob(it);
00438   } else
00439     mFolder->quiet( true );
00440 
00441   if( mMsgsForDownload.isEmpty() ) {
00442     mFolder->quiet( false );
00443     delete this;
00444     return;
00445   }
00446 
00447   MsgForDownload mfd = mMsgsForDownload.front(); mMsgsForDownload.pop_front();
00448 
00449   mMsg = new KMMessage;
00450   mMsg->setUID(mfd.uid);
00451   mMsg->setMsgSizeServer(mfd.size);
00452   if( mfd.flags > 0 )
00453     KMFolderImap::flagsToStatus(mMsg, mfd.flags, true, GlobalSettings::allowLocalFlags() ? mFolder->permanentFlags() : INT_MAX);
00454   KURL url = mAccount->getUrl();
00455   url.setPath(mFolder->imapPath() + QString(";UID=%1;SECTION=BODY.PEEK[]").arg(mfd.uid));
00456 
00457   ImapAccountBase::jobData jd( url.url(), mFolder->folder() );
00458   jd.cancellable = true;
00459   mMsg->setTransferInProgress(true);
00460   KIO::SimpleJob *simpleJob = KIO::get(url, false, false);
00461   KIO::Scheduler::assignJobToSlave(mAccount->slave(), simpleJob);
00462   mAccount->insertJob(simpleJob, jd);
00463   connect(simpleJob, SIGNAL(processedSize(KIO::Job *, KIO::filesize_t)),
00464           this, SLOT(slotProcessedSize(KIO::Job *, KIO::filesize_t)));
00465   connect(simpleJob, SIGNAL(result(KIO::Job *)),
00466           this, SLOT(slotGetNextMessage(KIO::Job *)));
00467   connect(simpleJob, SIGNAL(data(KIO::Job *, const QByteArray &)),
00468           mFolder, SLOT(slotSimpleData(KIO::Job *, const QByteArray &)));
00469 }
00470 
00471 void CachedImapJob::slotProcessedSize(KIO::Job *, KIO::filesize_t processed)
00472 {
00473   emit progress( mSentBytes + processed, mTotalBytes );
00474 }
00475 
00476 void CachedImapJob::slotPutNextMessage()
00477 {
00478   mMsg = 0;
00479 
00480   // First try the message list
00481   if( !mMsgList.isEmpty() ) {
00482     mMsg = mMsgList.first();
00483     mMsgList.removeFirst();
00484   }
00485 
00486   // Now try the serial number list
00487   while( mMsg == 0 && !mSerNumMsgList.isEmpty() ) {
00488     unsigned long serNum = mSerNumMsgList.first();
00489     mSerNumMsgList.pop_front();
00490     m_dbgCurrentSerNum = serNum;
00491 
00492     // Find the message with this serial number
00493     int i = 0;
00494     KMFolder* aFolder = 0;
00495     KMMsgDict::instance()->getLocation( serNum, &aFolder, &i );
00496     if( mFolder->folder() != aFolder )
00497       // This message was moved or something
00498       continue;
00499     mMsg = mFolder->getMsg( i );
00500   }
00501 
00502   if( !mMsg ) {
00503     // No message found for upload
00504     delete this;
00505     return;
00506   }
00507 
00508   KURL url = mAccount->getUrl();
00509   QString flags = KMFolderImap::statusToFlags( mMsg->status(), mFolder->permanentFlags() );
00510   url.setPath( mFolder->imapPath() + ";SECTION=" + flags );
00511 
00512   ImapAccountBase::jobData jd( url.url(), mFolder->folder() );
00513 
00514   mMsg->setUID( 0 ); // for the index
00515   QCString cstr(mMsg->asString());
00516   int a = cstr.find("\nX-UID: ");
00517   int b = cstr.find('\n', a);
00518   if (a != -1 && b != -1 && cstr.find("\n\n") > a) cstr.remove(a, b-a);
00519   QCString mData(cstr.length() + cstr.contains('\n'));
00520   unsigned int i = 0;
00521   for( char *ch = cstr.data(); *ch; ch++ ) {
00522     if ( *ch == '\n' ) {
00523       mData.at(i) = '\r';
00524       i++;
00525     }
00526     mData.at(i) = *ch; i++;
00527   }
00528   jd.data = mData;
00529   jd.msgList.append( mMsg );
00530 
00531   mMsg->setTransferInProgress(true);
00532   //kdDebug(5006) << "DEBUG slotPutNextMessage() creating the simplejob " << endl;
00533   KIO::SimpleJob *simpleJob = KIO::put(url, 0, false, false, false);
00534   KIO::Scheduler::assignJobToSlave(mAccount->slave(), simpleJob);
00535   mAccount->insertJob(simpleJob, jd);
00536   connect( simpleJob, SIGNAL( result(KIO::Job *) ),
00537            SLOT( slotPutMessageResult(KIO::Job *) ) );
00538   connect( simpleJob, SIGNAL( dataReq(KIO::Job *, QByteArray &) ),
00539            SLOT( slotPutMessageDataReq(KIO::Job *, QByteArray &) ) );
00540   connect( simpleJob, SIGNAL( data(KIO::Job *, const QByteArray &) ),
00541            mFolder, SLOT( slotSimpleData(KIO::Job *, const QByteArray &) ) );
00542   connect( simpleJob, SIGNAL(infoMessage(KIO::Job *, const QString &)),
00543              SLOT(slotPutMessageInfoData(KIO::Job *, const QString &)) );
00544 
00545 }
00546 
00547 //-----------------------------------------------------------------------------
00548 // TODO: port to KIO::StoredTransferJob once it's ok to require kdelibs-3.3
00549 void CachedImapJob::slotPutMessageDataReq(KIO::Job *job, QByteArray &data)
00550 {
00551   KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
00552   if ( it == mAccount->jobsEnd() ) { // Shouldn't happen
00553     delete this;
00554     return;
00555   }
00556   if ((*it).data.size() - (*it).offset > 0x8000) {
00557     data.duplicate((*it).data.data() + (*it).offset, 0x8000);
00558     (*it).offset += 0x8000;
00559   } else if ((*it).data.size() - (*it).offset > 0) {
00560     data.duplicate((*it).data.data() + (*it).offset,
00561                    (*it).data.size() - (*it).offset);
00562     (*it).offset = (*it).data.size();
00563   } else
00564     data.resize(0);
00565 }
00566 
00567 //----------------------------------------------------------------------------
00568 void CachedImapJob::slotPutMessageInfoData( KIO::Job *job, const QString &data )
00569 {
00570   KMFolderCachedImap *imapFolder = static_cast<KMFolderCachedImap*>( mDestFolder->storage() );
00571   if ( imapFolder ) {
00572     KMAcctCachedImap *account = imapFolder->account();
00573     ImapAccountBase::JobIterator it = account->findJob( job );
00574     if ( it == account->jobsEnd() ) {
00575       return;
00576     }
00577     if ( data.find( "UID" ) != -1 && mMsg ) {
00578       int uid = ( data.right( data.length() - 4 ) ).toInt();
00579       if ( m_dbgCurrentSerNum != 0 ) {
00580         // Debug block
00581        KMMessage *oldMsg = KMailICalIfaceImpl::findMessageBySerNum( m_dbgCurrentSerNum, mDestFolder );
00582        if ( !oldMsg || oldMsg != mMsg ) {
00583          // Should never happen!
00584          kdWarning ( 5006 ) << "Messagepointer in cachedImapJob has been modified during operation!"
00585                     << endl << "Should be: " << m_dbgCurrentSerNum << endl
00586                     << "Actually: " << mMsg->getMsgSerNum() << endl;
00587          Q_ASSERT( false );
00588          return;
00589        }
00590       }
00591 
00592       kdDebug( 5006 ) << k_funcinfo << "Server told us uid is-: " << uid << "-" << mMsg->getMsgSerNum() << mSerNumMsgList << endl;
00593       mMsg->setUID( uid );
00594     }
00595   }
00596 }
00597 
00598 
00599 //-----------------------------------------------------------------------------
00600 void CachedImapJob::slotPutMessageResult(KIO::Job *job)
00601 {
00602   KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
00603   if ( it == mAccount->jobsEnd() ) { // Shouldn't happen
00604     //kdDebug() << "DEBUG slotPutMessageResult() DOESNT HAPPEN2" << endl;
00605     delete this;
00606     return;
00607   }
00608 
00609   if ( job->error() ) {
00610     //kdDebug() << "DEBUG slotPutMessageResult() DOESNT HAPPEN2" << endl;
00611     bool cont = mAccount->handlePutError( job, *it, mFolder->folder() );
00612     if ( !cont ) {
00613       delete this;
00614     } else {
00615       mMsg = 0;
00616       slotPutNextMessage();
00617     }
00618     return;
00619   }
00620 
00621   emit messageStored( mMsg );
00622 
00623   // we abuse those fields, the unit is the number of messages, here
00624   ++mSentBytes;
00625   emit progress( mSentBytes, mTotalBytes );
00626 
00627   int i;
00628   if( ( i = mFolder->find(mMsg) ) != -1 ) {
00629      /*
00630       * If we have aquired a uid during upload the server supports the uidnext
00631       * extension and there is no need to redownload this mail, we already have
00632       * it. Otherwise remove it, it will be redownloaded.
00633       */
00634      if ( mMsg->UID() == 0 ) {
00635         //kdDebug() << "DEBUG DOESNT HAPPEN" << endl;
00636         mFolder->removeMsg(i);
00637      } else {
00638         // When removing+readding, no point in telling the imap resources about it
00639         bool b = kmkernel->iCalIface().isResourceQuiet();
00640         //kdDebug(5006) << "DEBUG slotPutMessageResult() START. oldQuiet=" << b <<" "<< this << " sernum: " << mMsg->getMsgSerNum() <<  endl;
00641         kmkernel->iCalIface().setResourceQuiet( true );
00642 
00643         mFolder->takeTemporarily( i );
00644         mFolder->addMsgKeepUID( mMsg );
00645         mMsg->setTransferInProgress( false );
00646         kmkernel->iCalIface().setResourceQuiet( b );
00647      }
00648   }
00649   mMsg = NULL;
00650   mAccount->removeJob( it );
00651   slotPutNextMessage();
00652 }
00653 
00654 
00655 void CachedImapJob::slotAddNextSubfolder( KIO::Job * job )
00656 {
00657   if (job) {
00658     KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
00659     if ( it == mAccount->jobsEnd() ) { // Shouldn't happen
00660       delete this;
00661       return;
00662     }
00663 
00664     // make copy of setting, to reset it before potentially destroying 'it'
00665     bool silentUpload = static_cast<KMFolderCachedImap*>((*it).parent->storage())->silentUpload();
00666     static_cast<KMFolderCachedImap*>((*it).parent->storage())->setSilentUpload( false );
00667 
00668     if ( job->error() && !silentUpload ) {
00669       QString myError = "<p><b>" + i18n("Error while uploading folder")
00670         + "</b></p><p>" + i18n("Could not make the folder <b>%1</b> on the server.").arg((*it).items[0])
00671         + "</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>";
00672       mAccount->handleJobError( job, myError );
00673     }
00674 
00675     if( job->error() ) {
00676       delete this;
00677       return;
00678     } else {
00679       KMFolderCachedImap* storage = static_cast<KMFolderCachedImap*>( (*it).current->storage() );
00680       KMFolderCachedImap* parentStorage = static_cast<KMFolderCachedImap*>( (*it).parent->storage() );
00681       Q_ASSERT( storage );
00682       Q_ASSERT( parentStorage );
00683       if ( storage->imapPath().isEmpty() ) {
00684         QString path = mAccount->createImapPath( parentStorage->imapPath(), storage->folder()->name() );
00685         if ( !storage->imapPathForCreation().isEmpty() )
00686           path = storage->imapPathForCreation();
00687         storage->setImapPath( path );
00688         storage->writeConfig();
00689       }
00690     }
00691     mAccount->removeJob( it );
00692   }
00693 
00694   if (mFolderList.isEmpty()) {
00695     // No more folders to add
00696     delete this;
00697     return;
00698   }
00699 
00700   KMFolderCachedImap *folder = mFolderList.front();
00701   mFolderList.pop_front();
00702   KURL url = mAccount->getUrl();
00703   QString path = mAccount->createImapPath( mFolder->imapPath(),
00704       folder->folder()->name() );
00705   if ( !folder->imapPathForCreation().isEmpty() ) {
00706     // the folder knows it's namespace
00707     path = folder->imapPathForCreation();
00708   }
00709   url.setPath( path );
00710 
00711   if ( mAccount->groupwareType() != KMAcctCachedImap::GroupwareScalix ) {
00712     // Associate the jobData with the parent folder, not with the child
00713     // This is necessary in case of an error while creating the subfolder,
00714     // so that folderComplete is called on the parent (and the sync resetted).
00715     ImapAccountBase::jobData jd( url.url(), mFolder->folder() );
00716     jd.items << folder->label(); // for the err msg
00717     jd.current = folder->folder();
00718     KIO::SimpleJob *simpleJob = KIO::mkdir(url);
00719     KIO::Scheduler::assignJobToSlave(mAccount->slave(), simpleJob);
00720     mAccount->insertJob(simpleJob, jd);
00721     connect( simpleJob, SIGNAL(result(KIO::Job *)),
00722              this, SLOT(slotAddNextSubfolder(KIO::Job *)) );
00723   } else {
00724     QByteArray packedArgs;
00725     QDataStream stream( packedArgs, IO_WriteOnly );
00726 
00727     const QString command = QString( "X-CREATE-SPECIAL" );
00728     const QString argument = QString( "%1 %2" ).arg( Scalix::Utils::contentsTypeToScalixId( folder->contentsType() ) )
00729                                                .arg( path );
00730 
00731     stream << (int) 'X' << 'N' << command << argument;
00732 
00733     ImapAccountBase::jobData jd( url.url(), mFolder->folder() );
00734     jd.items << folder->label(); // for the err msg
00735     jd.current = folder->folder();
00736     KIO::SimpleJob *simpleJob = KIO::special( url.url(), packedArgs, false );
00737     KIO::Scheduler::assignJobToSlave(mAccount->slave(), simpleJob);
00738     mAccount->insertJob(simpleJob, jd);
00739     connect( simpleJob, SIGNAL(result(KIO::Job *)),
00740              this, SLOT(slotAddNextSubfolder(KIO::Job *)) );
00741   }
00742 }
00743 
00744 
00745 void CachedImapJob::slotDeleteNextFolder( KIO::Job *job )
00746 {
00747   if (job) {
00748     KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
00749     if ( it == mAccount->jobsEnd() ) { // Shouldn't happen
00750       delete this;
00751       return;
00752     }
00753 
00754     mAccount->removeDeletedFolder( (*it).path );
00755 
00756     if( job->error() ) {
00757       mAccount->handleJobError( job, i18n( "Error while deleting folder %1 on the server: " ).arg( (*it).path ) + '\n' );
00758       delete this;
00759       return;
00760     }
00761     mAccount->removeJob(it);
00762   }
00763 
00764   if( mFoldersOrMessages.isEmpty() ) {
00765     // No more folders to delete
00766     delete this;
00767     return;
00768   }
00769 
00770   QString folderPath = mFoldersOrMessages.front();
00771   mFoldersOrMessages.pop_front();
00772   KURL url = mAccount->getUrl();
00773   url.setPath(folderPath);
00774   ImapAccountBase::jobData jd( url.url(), mFolder->folder() );
00775   jd.path = url.path();
00776   KIO::SimpleJob *simpleJob = KIO::file_delete(url, false);
00777   KIO::Scheduler::assignJobToSlave(mAccount->slave(), simpleJob);
00778   mAccount->insertJob(simpleJob, jd);
00779   connect( simpleJob, SIGNAL( result(KIO::Job *) ),
00780            SLOT( slotDeleteNextFolder(KIO::Job *) ) );
00781 }
00782 
00783 void CachedImapJob::checkUidValidity()
00784 {
00785   KURL url = mAccount->getUrl();
00786   url.setPath( mFolder->imapPath() + ";UID=0:0" );
00787 
00788   ImapAccountBase::jobData jd( url.url(), mFolder->folder() );
00789   jd.cancellable = true;
00790 
00791   KIO::SimpleJob *job = KIO::get( url, false, false );
00792   KIO::Scheduler::assignJobToSlave( mAccount->slave(), job );
00793   mAccount->insertJob( job, jd );
00794   connect( job, SIGNAL(result(KIO::Job *)),
00795            SLOT(slotCheckUidValidityResult(KIO::Job *)) );
00796   connect( job, SIGNAL(data(KIO::Job *, const QByteArray &)),
00797            mFolder, SLOT(slotSimpleData(KIO::Job *, const QByteArray &)));
00798 }
00799 
00800 void CachedImapJob::slotCheckUidValidityResult(KIO::Job * job)
00801 {
00802   KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
00803   if ( it == mAccount->jobsEnd() ) { // Shouldn't happen
00804     delete this;
00805     return;
00806   }
00807 
00808   if( job->error() ) {
00809     mErrorCode = job->error();
00810     mAccount->handleJobError( job, i18n( "Error while reading folder %1 on the server: " ).arg( (*it).parent->label() ) + '\n' );
00811     delete this;
00812     return;
00813   }
00814 
00815   // Check the uidValidity
00816   QCString cstr((*it).data.data(), (*it).data.size() + 1);
00817   int a = cstr.find("X-uidValidity: ");
00818   if (a < 0) {
00819     // Something is seriously rotten here!
00820     // TODO: Tell the user that he has a problem
00821     kdDebug(5006) << "No uidvalidity available for folder "
00822                   << mFolder->name() << endl;
00823   }
00824   else {
00825     int b = cstr.find("\r\n", a);
00826     if ( (b - a - 15) >= 0 ) {
00827       QString uidv = cstr.mid(a + 15, b - a - 15);
00828       // kdDebug(5006) << "New uidv = " << uidv << ", old uidv = "
00829       //               << mFolder->uidValidity() << endl;
00830       if( !mFolder->uidValidity().isEmpty() && mFolder->uidValidity() != uidv ) {
00831         // kdDebug(5006) << "Expunging the mailbox " << mFolder->name()
00832         //               << "!" << endl;
00833         mFolder->expunge();
00834         mFolder->setLastUid( 0 );
00835         mFolder->clearUidMap();
00836       }
00837     } else
00838       kdDebug(5006) << "No uidvalidity available for folder "
00839                     << mFolder->name() << endl;
00840   }
00841 
00842   a = cstr.find( "X-PermanentFlags: " );
00843   if ( a < 0 ) {
00844     kdDebug(5006) << "no PERMANENTFLAGS response? assumming custom flags are not available" << endl;
00845   } else {
00846     int b = cstr.find( "\r\n", a );
00847     if ( (b - a - 18) >= 0 ) {
00848       int flags = cstr.mid( a + 18, b - a - 18 ).toInt();
00849       emit permanentFlags( flags );
00850     } else {
00851       kdDebug(5006) << "PERMANENTFLAGS response broken, assumming custom flags are not available" << endl;
00852     }
00853   }
00854 
00855   mAccount->removeJob(it);
00856   delete this;
00857 }
00858 
00859 
00860 void CachedImapJob::renameFolder( const QString &newName )
00861 {
00862   mNewName = newName;
00863 
00864   // Set the source URL
00865   KURL urlSrc = mAccount->getUrl();
00866   mOldImapPath = mFolder->imapPath();
00867   urlSrc.setPath( mOldImapPath );
00868 
00869   // Set the destination URL - this is a bit trickier
00870   KURL urlDst = mAccount->getUrl();
00871   mNewImapPath = mFolder->imapPath();
00872   // Destination url = old imappath - oldname + new name
00873   mNewImapPath.truncate( mNewImapPath.length() - mFolder->folder()->name().length() - 1);
00874   mNewImapPath += newName + '/';
00875   urlDst.setPath( mNewImapPath );
00876 
00877   ImapAccountBase::jobData jd( newName, mFolder->folder() );
00878   jd.path = mNewImapPath;
00879 
00880   KIO::SimpleJob *simpleJob = KIO::rename( urlSrc, urlDst, false );
00881   KIO::Scheduler::assignJobToSlave( mAccount->slave(), simpleJob );
00882   mAccount->insertJob( simpleJob, jd );
00883   connect( simpleJob, SIGNAL(result(KIO::Job *)),
00884            SLOT(slotRenameFolderResult(KIO::Job *)) );
00885 }
00886 
00887 static void renameChildFolders( KMFolderDir* dir, const QString& oldPath,
00888                                 const QString& newPath )
00889 {
00890   if( dir ) {
00891     KMFolderNode *node = dir->first();
00892     while( node ) {
00893       if( !node->isDir() ) {
00894         KMFolderCachedImap* imapFolder =
00895           static_cast<KMFolderCachedImap*>(static_cast<KMFolder*>(node)->storage());
00896         if ( !imapFolder->imapPath().isEmpty() )
00897           // Only rename folders that have been accepted by the server
00898           if( imapFolder->imapPath().find( oldPath ) == 0 ) {
00899             QString p = imapFolder->imapPath();
00900             p = p.mid( oldPath.length() );
00901             p.prepend( newPath );
00902             imapFolder->setImapPath( p );
00903             renameChildFolders( imapFolder->folder()->child(), oldPath, newPath );
00904           }
00905       }
00906       node = dir->next();
00907     }
00908   }
00909 }
00910 
00911 void CachedImapJob::revertLabelChange()
00912 {
00913   QMap<QString, KMAcctCachedImap::RenamedFolder>::ConstIterator renit = mAccount->renamedFolders().find( mFolder->imapPath() );
00914   Q_ASSERT( renit != mAccount->renamedFolders().end() );
00915   if ( renit != mAccount->renamedFolders().end() ) {
00916     mFolder->folder()->setLabel( (*renit).mOldLabel );
00917     mAccount->removeRenamedFolder( mFolder->imapPath() );
00918     kmkernel->dimapFolderMgr()->contentsChanged();
00919   }
00920 }
00921 
00922 void CachedImapJob::renameOnDisk()
00923 {
00924   QString oldName = mFolder->name();
00925   QString oldPath = mFolder->imapPath();
00926   mAccount->removeRenamedFolder( oldPath );
00927   mFolder->setImapPath( mNewImapPath );
00928   mFolder->FolderStorage::rename( mNewName );
00929 
00930   if( oldPath.endsWith( "/" ) ) oldPath.truncate( oldPath.length() -1 );
00931   QString newPath = mFolder->imapPath();
00932   if( newPath.endsWith( "/" ) ) newPath.truncate( newPath.length() -1 );
00933   renameChildFolders( mFolder->folder()->child(), oldPath, newPath );
00934   kmkernel->dimapFolderMgr()->contentsChanged();
00935 }
00936 
00937 void CachedImapJob::slotSubscribtionChange1Failed( const QString &errorMessage )
00938 {
00939   KMessageBox::sorry( 0, i18n( "Error while trying to subscribe to the renamed folder %1.\n"
00940                                "Renaming itself was successful, but the renamed folder might disappear "
00941                                "from the folder list after the next sync since it is unsubscribed on the server.\n"
00942                                "You can try to manually subscribe to the folder yourself.\n\n"
00943                                "%2" )
00944       .arg( mFolder->label() ).arg( errorMessage ) );
00945   delete this;
00946 }
00947 
00948 void CachedImapJob::slotSubscribtionChange2Failed( const QString &errorMessage )
00949 {
00950   kdWarning(5006) << k_funcinfo << errorMessage << endl;
00951   // Ignore this error, not something user-visible anyway
00952   delete this;
00953 }
00954 
00955 void CachedImapJob::slotSubscribtionChange1Done( const QString&, bool )
00956 {
00957   disconnect( mAccount, SIGNAL( subscriptionChanged( const QString&, bool ) ),
00958               this, SLOT( slotSubscribtionChange1Done( const QString&, bool ) ) );
00959   connect( mAccount, SIGNAL( subscriptionChanged( const QString&, bool ) ),
00960            this, SLOT( slotSubscribtionChange2Done( const QString&, bool ) ) );
00961   disconnect( mAccount, SIGNAL( subscriptionChangeFailed( const QString& ) ),
00962               this, SLOT( slotSubscribtionChange1Failed( const QString& ) ) );
00963   connect( mAccount, SIGNAL( subscriptionChangeFailed( const QString& ) ),
00964            this, SLOT( slotSubscribtionChange2Failed( const QString& ) ) );
00965 
00966   mAccount->changeSubscription( false, mOldImapPath, true /* quiet */ );
00967 }
00968 
00969 void CachedImapJob::slotSubscribtionChange2Done( const QString&, bool )
00970 {
00971   // Finally done with everything!
00972   delete this;
00973 }
00974 
00975 void CachedImapJob::slotRenameFolderResult( KIO::Job *job )
00976 {
00977   KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
00978   if ( it == mAccount->jobsEnd() ) { // Shouldn't happen
00979     delete this;
00980     return;
00981   }
00982 
00983   if( job->error() ) {
00984     revertLabelChange();
00985     const QString errorMessage = i18n( "Error while trying to rename folder %1" ).arg( mFolder->label() );
00986     mAccount->handleJobError( job, errorMessage );
00987     delete this;
00988   } else {
00989 
00990     mAccount->removeJob( it );
00991     renameOnDisk();
00992 
00993     // Okay, the folder seems to be renamed on the server and on disk.
00994     // Now unsubscribe from the old folder name and subscribe to the new folder name,
00995     // so that the folder doesn't suddenly disappear after renaming it
00996     connect( mAccount, SIGNAL( subscriptionChangeFailed( const QString& ) ),
00997              this, SLOT( slotSubscribtionChange1Failed( const QString& ) ) );
00998     connect( mAccount, SIGNAL( subscriptionChanged( const QString&, bool ) ),
00999              this, SLOT( slotSubscribtionChange1Done( const QString&, bool ) ) );
01000     mAccount->changeSubscription( true, mNewImapPath, true /* quiet */ );
01001   }
01002 }
01003 
01004 void CachedImapJob::slotListMessagesResult( KIO::Job * job )
01005 {
01006   KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
01007   if ( it == mAccount->jobsEnd() ) { // Shouldn't happen
01008     delete this;
01009     return;
01010   }
01011 
01012   if (job->error()) {
01013     mErrorCode = job->error();
01014     mAccount->handleJobError( job, i18n( "Error while deleting messages on the server: " ) + '\n' );
01015   }
01016   else
01017     mAccount->removeJob(it);
01018 
01019   delete this;
01020 }
01021 
01022 //-----------------------------------------------------------------------------
01023 void CachedImapJob::setParentFolder( const KMFolderCachedImap* parent )
01024 {
01025   mParentFolder = const_cast<KMFolderCachedImap*>( parent );
01026 }
01027 
01028 }
01029 
01030 #include "cachedimapjob.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys