kmail

renamejob.cpp

00001 /*
00002  * Copyright (c) 2004 Carsten Burghardt <burghardt@kde.org>
00003  *
00004  *  This program is free software; you can redistribute it and/or modify
00005  *  it under the terms of the GNU General Public License as published by
00006  *  the Free Software Foundation; version 2 of the License
00007  *
00008  *  This program is distributed in the hope that it will be useful,
00009  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00010  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00011  *  GNU General Public License for more details.
00012  *
00013  *  You should have received a copy of the GNU General Public License
00014  *  along with this program; if not, write to the Free Software
00015  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00016  *
00017  *  In addition, as a special exception, the copyright holders give
00018  *  permission to link the code of this program with any edition of
00019  *  the Qt library by Trolltech AS, Norway (or with modified versions
00020  *  of Qt that use the same license as Qt), and distribute linked
00021  *  combinations including the two.  You must obey the GNU General
00022  *  Public License in all respects for all of the code used other than
00023  *  Qt.  If you modify this file, you may extend this exception to
00024  *  your version of the file, but you are not obligated to do so.  If
00025  *  you do not wish to do so, delete this exception statement from
00026  *  your version.
00027  */
00028 
00029 #include "renamejob.h"
00030 #include "kmfolderimap.h"
00031 #include "kmfoldercachedimap.h"
00032 #include "folderstorage.h"
00033 #include "kmfolder.h"
00034 #include "kmfolderdir.h"
00035 #include "kmfoldermgr.h"
00036 #include "imapaccountbase.h"
00037 #include "kmacctimap.h"
00038 #include "kmacctcachedimap.h"
00039 #include "kmcommands.h"
00040 #include "kmmsgbase.h"
00041 #include "undostack.h"
00042 
00043 #include <kdebug.h>
00044 #include <kurl.h>
00045 #include <kio/scheduler.h>
00046 #include <kio/job.h>
00047 #include <kio/global.h>
00048 #include <klocale.h>
00049 #include <config.h>
00050 
00051 #include <qmap.h>
00052 
00053 using namespace KMail;
00054 
00055 RenameJob::RenameJob( FolderStorage* storage, const QString& newName,
00056     KMFolderDir* newParent )
00057  : FolderJob( 0, tOther, (storage ? storage->folder() : 0) ),
00058    mStorage( storage ), mNewParent( newParent ),
00059    mNewName( newName ), mNewFolder( 0 )
00060 {
00061   mStorageTempOpened = 0;
00062   mOldName = storage->name();
00063   if ( storage->folderType() == KMFolderTypeImap ) {
00064     mOldImapPath = static_cast<KMFolderImap*>(storage)->imapPath();
00065   } else if ( storage->folderType() == KMFolderTypeCachedImap ) {
00066     mOldImapPath = static_cast<KMFolderCachedImap*>(storage)->imapPath();
00067   }
00068 }
00069 
00070 RenameJob::~RenameJob()
00071 {
00072 }
00073 
00074 void RenameJob::execute()
00075 {
00076   if ( mNewParent )
00077   {
00078     // move the folder to a different parent
00079     KMFolderType type = mStorage->folderType();
00080     if ( ( type == KMFolderTypeMbox || type == KMFolderTypeMaildir ) &&
00081          mNewParent->type() == KMStandardDir &&
00082          mStorage->folderType() != KMFolderTypeCachedImap )
00083     {
00084       // local folders can handle this on their own
00085       mStorage->rename( mNewName, mNewParent );
00086       emit renameDone( mNewName, true );
00087       deleteLater();
00088       return;
00089     }
00090     // first create the new folder
00091     KMFolderMgr* folderMgr = kmkernel->folderMgr();
00092     if ( mNewParent->type() == KMImapDir ) {
00093       folderMgr = kmkernel->imapFolderMgr();
00094     } else if ( mNewParent->type() == KMDImapDir ) {
00095       folderMgr = kmkernel->dimapFolderMgr();
00096     }
00097 
00098     // get the default mailbox type
00099     KConfig *config = KMKernel::config();
00100     KConfigGroupSaver saver(config, "General");
00101     int deftype = config->readNumEntry("default-mailbox-format", 1);
00102     if ( deftype < 0 || deftype > 1 ) deftype = 1;
00103 
00104     // the type of the new folder
00105     KMFolderType typenew =
00106       ( deftype == 0 ) ? KMFolderTypeMbox : KMFolderTypeMaildir;
00107     if ( mNewParent->owner() )
00108       typenew = mNewParent->owner()->folderType();
00109 
00110     mNewFolder = folderMgr->createFolder( mNewName, false, typenew, mNewParent );
00111     if ( !mNewFolder )
00112     {
00113       kdWarning(5006) << k_funcinfo << "could not create folder" << endl;
00114       emit renameDone( mNewName, false );
00115       deleteLater();
00116       return;
00117     }
00118     kdDebug(5006)<< "RenameJob::rename - " << mStorage->folder()->idString()
00119       << " |=> " << mNewFolder->idString() << endl;
00120 
00121     if ( mNewParent->type() == KMImapDir )
00122     {
00123       // online imap
00124       // create it on the server and wait for the folderAdded signal
00125       // do not ask the user what kind of folder should be created
00126       connect( kmkernel->imapFolderMgr(), SIGNAL( changed() ),
00127           this, SLOT( slotMoveMessages() ) );
00128       KMFolderImap* imapFolder =
00129         static_cast<KMFolderImap*>(mNewParent->owner()->storage());
00130       imapFolder->createFolder( mNewName, QString::null, false ); 
00131     } else if ( mNewParent->type() == KMDImapDir )
00132     {
00133       KMFolderCachedImap* newStorage = static_cast<KMFolderCachedImap*>(mNewFolder->storage());
00134       KMFolderCachedImap* owner = static_cast<KMFolderCachedImap*>(mNewParent->owner()->storage());
00135       newStorage->initializeFrom( owner );
00136       moveSubFoldersBeforeMessages();
00137     } else if ( mStorage->folderType() == KMFolderTypeCachedImap )
00138     {
00139       // from (d)IMAP to local account
00140       moveSubFoldersBeforeMessages();
00141     } else
00142     {
00143       // local
00144       slotMoveMessages();
00145     }
00146   } else
00147   {
00148     // only rename the folder
00149     if ( mStorage->folderType() != KMFolderTypeImap )
00150     {
00151       // local and dimap folder handle this directly
00152       mStorage->rename( mNewName );
00153       emit renameDone( mNewName, true );
00154       deleteLater();
00155       return;
00156     }
00157     if ( mOldImapPath.isEmpty() )
00158     {
00159       // sanity
00160       emit renameDone( mNewName, false );
00161       deleteLater();
00162       return;
00163     } else if ( mOldName == mNewName || mOldImapPath == "/INBOX/" ) {
00164       emit renameDone( mNewName, true ); // noop
00165       deleteLater();
00166       return;
00167     }
00168     ImapAccountBase* account = static_cast<KMFolderImap*>(mStorage)->account();
00169     // first rename it on the server
00170     mNewImapPath = mOldImapPath;
00171     mNewImapPath = mNewImapPath.replace( mOldName, mNewName );
00172     KURL src( account->getUrl() );
00173     src.setPath( mOldImapPath );
00174     KURL dst( account->getUrl() );
00175     dst.setPath( mNewImapPath );
00176     KIO::SimpleJob *job = KIO::rename( src, dst, true );
00177     kdDebug(5006)<< "RenameJob::rename - " << src.prettyURL()
00178       << " |=> " << dst.prettyURL() << endl;
00179     ImapAccountBase::jobData jd( src.url() );
00180     account->insertJob( job, jd );
00181     KIO::Scheduler::assignJobToSlave( account->slave(), job );
00182     connect( job, SIGNAL(result(KIO::Job*)),
00183         SLOT(slotRenameResult(KIO::Job*)) );
00184   }
00185 }
00186 
00187 void RenameJob::slotRenameResult( KIO::Job *job )
00188 {
00189   ImapAccountBase* account = static_cast<KMFolderImap*>(mStorage)->account();
00190   ImapAccountBase::JobIterator it = account->findJob(job);
00191   if ( it == account->jobsEnd() )
00192   {
00193     emit renameDone( mNewName, false );
00194     deleteLater();
00195     return;
00196   }
00197   if ( job->error() )
00198   {
00199     account->handleJobError( job, i18n("Error while renaming a folder.") );
00200     emit renameDone( mNewName, false );
00201     deleteLater();
00202     return;
00203   }
00204   account->removeJob(it);
00205   // set the new path
00206   if ( mStorage->folderType() == KMFolderTypeImap )
00207     static_cast<KMFolderImap*>(mStorage)->setImapPath( mNewImapPath );
00208   // unsubscribe old (we don't want ghosts)
00209   account->changeSubscription( false, mOldImapPath );
00210   // subscribe new
00211   account->changeSubscription( true, mNewImapPath );
00212 
00213   // local part (will set the new name)
00214   mStorage->rename( mNewName );
00215 
00216   emit renameDone( mNewName, true );
00217   deleteLater();
00218 }
00219 
00220 void RenameJob::slotMoveMessages()
00221 {
00222   kdDebug(5006) << k_funcinfo << endl;
00223   disconnect( kmkernel->imapFolderMgr(), SIGNAL( changed() ),
00224       this, SLOT( slotMoveMessages() ) );
00225   mStorage->blockSignals( true );
00226   // move all messages to the new folder
00227   QPtrList<KMMsgBase> msgList;
00228   if ( !mStorage->isOpened() )
00229     mStorageTempOpened = mStorage->open() ? mStorage : 0;
00230   for ( int i = 0; i < mStorage->count(); i++ )
00231   {
00232     KMMsgBase* msgBase = mStorage->getMsgBase( i );
00233     assert( msgBase );
00234     msgList.append( msgBase );
00235   }
00236   if ( msgList.count() == 0 )
00237   {
00238     slotMoveCompleted( 0 );
00239   } else
00240   {
00241     KMCommand *command = new KMMoveCommand( mNewFolder, msgList );
00242     connect( command, SIGNAL( completed( KMCommand * ) ),
00243         this, SLOT( slotMoveCompleted( KMCommand * ) ) );
00244     command->start();
00245   }
00246 }
00247 
00248 void RenameJob::slotMoveCompleted( KMCommand* command )
00249 {
00250   kdDebug(5006) << k_funcinfo << (command?command->result():0) << endl;
00251   if ( mStorageTempOpened ) {
00252     mStorageTempOpened->close();
00253     mStorageTempOpened = 0;
00254   }
00255   if ( command ) {
00256     // just make sure nothing bounces
00257     disconnect( command, SIGNAL( completed( KMCommand * ) ),
00258         this, SLOT( slotMoveCompleted( KMCommand * ) ) );
00259   }
00260   if ( !command || command->result() == KMCommand::OK )
00261   {
00262     kdDebug(5006) << "deleting old folder" << endl;
00263     // move complete or not necessary
00264     // save our settings
00265     QString oldconfig = "Folder-" + mStorage->folder()->idString();
00266     KConfig* config = KMKernel::config();
00267     QMap<QString, QString> entries = config->entryMap( oldconfig );
00268     KConfigGroupSaver saver(config, "Folder-" + mNewFolder->idString());
00269     for ( QMap<QString, QString>::Iterator it = entries.begin();
00270           it != entries.end(); ++it )
00271     {
00272       if ( it.key() == "Id" || it.key() == "ImapPath" ||
00273            it.key() == "UidValidity" )
00274         continue;
00275       config->writeEntry( it.key(), it.data() );
00276     }
00277     mNewFolder->readConfig( config );
00278     // make sure the children state is correct
00279     if ( mNewFolder->child() &&
00280          ( mNewFolder->storage()->hasChildren() == FolderStorage::HasNoChildren ) )
00281       mNewFolder->storage()->updateChildrenState();
00282 
00283     // delete the old folder
00284     mStorage->blockSignals( false );
00285     if ( mStorage->folderType() == KMFolderTypeImap )
00286     {
00287       kmkernel->imapFolderMgr()->remove( mStorage->folder() );
00288     } else if ( mStorage->folderType() == KMFolderTypeCachedImap )
00289     {
00290       // tell the account (see KMFolderCachedImap::listDirectory2)
00291       KMAcctCachedImap* acct = static_cast<KMFolderCachedImap*>(mStorage)->account();
00292       if ( acct )
00293         acct->addDeletedFolder( mOldImapPath );
00294       kmkernel->dimapFolderMgr()->remove( mStorage->folder() );
00295     } else if ( mStorage->folderType() == KMFolderTypeSearch )
00296     {
00297       // invalid
00298       kdWarning(5006) << k_funcinfo << "cannot remove a search folder" << endl;
00299     } else {
00300       kmkernel->folderMgr()->remove( mStorage->folder() );
00301     }
00302 
00303     emit renameDone( mNewName, true );
00304   } else
00305   {
00306     kdDebug(5006) << "rollback - deleting folder" << endl;
00307     // move failed - rollback the last transaction
00308     kmkernel->undoStack()->undo();
00309     // .. and delete the new folder
00310     if ( mNewFolder->folderType() == KMFolderTypeImap )
00311     {
00312       kmkernel->imapFolderMgr()->remove( mNewFolder );
00313     } else if ( mNewFolder->folderType() == KMFolderTypeCachedImap )
00314     {
00315       // tell the account (see KMFolderCachedImap::listDirectory2)
00316       KMFolderCachedImap* folder = static_cast<KMFolderCachedImap*>(mNewFolder->storage());
00317       KMAcctCachedImap* acct = folder->account();
00318       if ( acct )
00319         acct->addDeletedFolder( folder->imapPath() );
00320       kmkernel->dimapFolderMgr()->remove( mNewFolder );
00321     } else if ( mNewFolder->folderType() == KMFolderTypeSearch )
00322     {
00323       // invalid
00324       kdWarning(5006) << k_funcinfo << "cannot remove a search folder" << endl;
00325     } else {
00326       kmkernel->folderMgr()->remove( mNewFolder );
00327     }
00328 
00329     emit renameDone( mNewName, false );
00330   }
00331   delete this;
00332 }
00333 
00334 void RenameJob::slotMoveSubFolders( QString newName, bool success )
00335 {
00336   if ( !success ) {
00337       emit renameDone( newName, false );
00338   } else {
00339     KMFolderDir* child = mStorage->folder()->child();
00340     if ( child && child->first() )
00341     {
00342       KMFolderNode* node = child->first();
00343       {
00344         FolderStorage* childStorage = static_cast<KMFolder*>(node)->storage();
00345         if ( !mNewFolder->child() )
00346           mNewFolder->createChildFolder();
00347         RenameJob* job = new RenameJob( childStorage, childStorage->name(),
00348                                         mNewFolder->child() );
00349         connect( job, SIGNAL( renameDone( QString, bool ) ),
00350             this, SLOT( slotMoveSubFolders( QString, bool ) ) );
00351         job->start();
00352       }
00353     }
00354     else slotMoveMessages();
00355   }
00356 }
00357 
00358 void RenameJob::moveSubFoldersBeforeMessages()
00359 {
00360   // move child folders recursive if present - else simply move the messages
00361   KMFolderDir* child = mStorage->folder()->child();
00362   if ( child )
00363     slotMoveSubFolders( "", true );
00364   else slotMoveMessages();
00365 }
00366 
00367 #include "renamejob.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys