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   if ( storage ) {
00063     mOldName = storage->name();
00064     if ( storage->folderType() == KMFolderTypeImap ) {
00065       mOldImapPath = static_cast<KMFolderImap*>(storage)->imapPath();
00066     } else if ( storage->folderType() == KMFolderTypeCachedImap ) {
00067       mOldImapPath = static_cast<KMFolderCachedImap*>(storage)->imapPath();
00068     }
00069   }
00070 }
00071 
00072 RenameJob::~RenameJob()
00073 {
00074 }
00075 
00076 void RenameJob::execute()
00077 {
00078   if ( mNewParent )
00079   {
00080     // move the folder to a different parent
00081     KMFolderType type = mStorage->folderType();
00082     if ( ( type == KMFolderTypeMbox || type == KMFolderTypeMaildir ) &&
00083          mNewParent->type() == KMStandardDir &&
00084          mStorage->folderType() != KMFolderTypeCachedImap )
00085     {
00086       // local folders can handle this on their own
00087       mStorage->rename( mNewName, mNewParent );
00088       emit renameDone( mNewName, true );
00089       deleteLater();
00090       return;
00091     }
00092     // first create the new folder
00093     KMFolderMgr* folderMgr = kmkernel->folderMgr();
00094     if ( mNewParent->type() == KMImapDir ) {
00095       folderMgr = kmkernel->imapFolderMgr();
00096     } else if ( mNewParent->type() == KMDImapDir ) {
00097       folderMgr = kmkernel->dimapFolderMgr();
00098     }
00099 
00100     // get the default mailbox type
00101     KConfig *config = KMKernel::config();
00102     KConfigGroupSaver saver(config, "General");
00103     int deftype = config->readNumEntry("default-mailbox-format", 1);
00104     if ( deftype < 0 || deftype > 1 ) deftype = 1;
00105 
00106     // the type of the new folder
00107     KMFolderType typenew =
00108       ( deftype == 0 ) ? KMFolderTypeMbox : KMFolderTypeMaildir;
00109     if ( mNewParent->owner() )
00110       typenew = mNewParent->owner()->folderType();
00111 
00112     mNewFolder = folderMgr->createFolder( mNewName, false, typenew, mNewParent );
00113     if ( !mNewFolder )
00114     {
00115       kdWarning(5006) << k_funcinfo << "could not create folder" << endl;
00116       emit renameDone( mNewName, false );
00117       deleteLater();
00118       return;
00119     }
00120     kdDebug(5006)<< "RenameJob::rename - " << mStorage->folder()->idString()
00121       << " |=> " << mNewFolder->idString() << endl;
00122 
00123     if ( mNewParent->type() == KMImapDir )
00124     {
00125       // online imap
00126       // create it on the server and wait for the folderAdded signal
00127       // do not ask the user what kind of folder should be created
00128       connect( kmkernel->imapFolderMgr(), SIGNAL( changed() ),
00129           this, SLOT( slotMoveMessages() ) );
00130       KMFolderImap* imapFolder =
00131         static_cast<KMFolderImap*>(mNewParent->owner()->storage());
00132       imapFolder->createFolder( mNewName, QString::null, false ); 
00133     } else if ( mNewParent->type() == KMDImapDir )
00134     {
00135       KMFolderCachedImap* newStorage = static_cast<KMFolderCachedImap*>(mNewFolder->storage());
00136       KMFolderCachedImap* owner = static_cast<KMFolderCachedImap*>(mNewParent->owner()->storage());
00137       newStorage->initializeFrom( owner );
00138       moveSubFoldersBeforeMessages();
00139     } else if ( mStorage->folderType() == KMFolderTypeCachedImap )
00140     {
00141       // from (d)IMAP to local account
00142       moveSubFoldersBeforeMessages();
00143     } else
00144     {
00145       // local
00146       slotMoveMessages();
00147     }
00148   } else
00149   {
00150     // only rename the folder
00151     if ( mStorage->folderType() != KMFolderTypeImap )
00152     {
00153       // local and dimap folder handle this directly
00154       mStorage->rename( mNewName );
00155       emit renameDone( mNewName, true );
00156       deleteLater();
00157       return;
00158     }
00159     if ( mOldImapPath.isEmpty() )
00160     {
00161       // sanity
00162       emit renameDone( mNewName, false );
00163       deleteLater();
00164       return;
00165     } else if ( mOldName == mNewName || mOldImapPath == "/INBOX/" ) {
00166       emit renameDone( mNewName, true ); // noop
00167       deleteLater();
00168       return;
00169     }
00170     ImapAccountBase* account = static_cast<KMFolderImap*>(mStorage)->account();
00171     // first rename it on the server
00172     mNewImapPath = mOldImapPath;
00173     mNewImapPath = mNewImapPath.replace( mOldName, mNewName );
00174     KURL src( account->getUrl() );
00175     src.setPath( mOldImapPath );
00176     KURL dst( account->getUrl() );
00177     dst.setPath( mNewImapPath );
00178     KIO::SimpleJob *job = KIO::rename( src, dst, true );
00179     kdDebug(5006)<< "RenameJob::rename - " << src.prettyURL()
00180       << " |=> " << dst.prettyURL() << endl;
00181     ImapAccountBase::jobData jd( src.url() );
00182     account->insertJob( job, jd );
00183     KIO::Scheduler::assignJobToSlave( account->slave(), job );
00184     connect( job, SIGNAL(result(KIO::Job*)),
00185         SLOT(slotRenameResult(KIO::Job*)) );
00186   }
00187 }
00188 
00189 void RenameJob::slotRenameResult( KIO::Job *job )
00190 {
00191   ImapAccountBase* account = static_cast<KMFolderImap*>(mStorage)->account();
00192   ImapAccountBase::JobIterator it = account->findJob(job);
00193   if ( it == account->jobsEnd() )
00194   {
00195     emit renameDone( mNewName, false );
00196     deleteLater();
00197     return;
00198   }
00199   if ( job->error() )
00200   {
00201     account->handleJobError( job, i18n("Error while renaming a folder.") );
00202     emit renameDone( mNewName, false );
00203     deleteLater();
00204     return;
00205   }
00206   account->removeJob(it);
00207   // set the new path
00208   if ( mStorage->folderType() == KMFolderTypeImap )
00209     static_cast<KMFolderImap*>(mStorage)->setImapPath( mNewImapPath );
00210   // unsubscribe old (we don't want ghosts)
00211   account->changeSubscription( false, mOldImapPath );
00212   // subscribe new
00213   account->changeSubscription( true, mNewImapPath );
00214 
00215   // local part (will set the new name)
00216   mStorage->rename( mNewName );
00217 
00218   emit renameDone( mNewName, true );
00219   deleteLater();
00220 }
00221 
00222 void RenameJob::slotMoveMessages()
00223 {
00224   kdDebug(5006) << k_funcinfo << endl;
00225   disconnect( kmkernel->imapFolderMgr(), SIGNAL( changed() ),
00226       this, SLOT( slotMoveMessages() ) );
00227   mStorage->blockSignals( true );
00228   // move all messages to the new folder
00229   QPtrList<KMMsgBase> msgList;
00230   if ( !mStorage->isOpened() )
00231     mStorageTempOpened = mStorage->open() ? mStorage : 0;
00232   for ( int i = 0; i < mStorage->count(); i++ )
00233   {
00234     KMMsgBase* msgBase = mStorage->getMsgBase( i );
00235     assert( msgBase );
00236     msgList.append( msgBase );
00237   }
00238   if ( msgList.count() == 0 )
00239   {
00240     slotMoveCompleted( 0 );
00241   } else
00242   {
00243     KMCommand *command = new KMMoveCommand( mNewFolder, msgList );
00244     connect( command, SIGNAL( completed( KMCommand * ) ),
00245         this, SLOT( slotMoveCompleted( KMCommand * ) ) );
00246     command->start();
00247   }
00248 }
00249 
00250 void RenameJob::slotMoveCompleted( KMCommand* command )
00251 {
00252   kdDebug(5006) << k_funcinfo << (command?command->result():0) << endl;
00253   if ( mStorageTempOpened ) {
00254     mStorageTempOpened->close();
00255     mStorageTempOpened = 0;
00256   }
00257   if ( command ) {
00258     // just make sure nothing bounces
00259     disconnect( command, SIGNAL( completed( KMCommand * ) ),
00260         this, SLOT( slotMoveCompleted( KMCommand * ) ) );
00261   }
00262   if ( !command || command->result() == KMCommand::OK )
00263   {
00264     kdDebug(5006) << "deleting old folder" << endl;
00265     // move complete or not necessary
00266     // save our settings
00267     QString oldconfig = "Folder-" + mStorage->folder()->idString();
00268     KConfig* config = KMKernel::config();
00269     QMap<QString, QString> entries = config->entryMap( oldconfig );
00270     KConfigGroupSaver saver(config, "Folder-" + mNewFolder->idString());
00271     for ( QMap<QString, QString>::Iterator it = entries.begin();
00272           it != entries.end(); ++it )
00273     {
00274       if ( it.key() == "Id" || it.key() == "ImapPath" ||
00275            it.key() == "UidValidity" )
00276         continue;
00277       config->writeEntry( it.key(), it.data() );
00278     }
00279     mNewFolder->readConfig( config );
00280     // make sure the children state is correct
00281     if ( mNewFolder->child() &&
00282          ( mNewFolder->storage()->hasChildren() == FolderStorage::HasNoChildren ) )
00283       mNewFolder->storage()->updateChildrenState();
00284 
00285     // delete the old folder
00286     mStorage->blockSignals( false );
00287     if ( mStorage->folderType() == KMFolderTypeImap )
00288     {
00289       kmkernel->imapFolderMgr()->remove( mStorage->folder() );
00290     } else if ( mStorage->folderType() == KMFolderTypeCachedImap )
00291     {
00292       // tell the account (see KMFolderCachedImap::listDirectory2)
00293       KMAcctCachedImap* acct = static_cast<KMFolderCachedImap*>(mStorage)->account();
00294       if ( acct )
00295         acct->addDeletedFolder( mOldImapPath );
00296       kmkernel->dimapFolderMgr()->remove( mStorage->folder() );
00297     } else if ( mStorage->folderType() == KMFolderTypeSearch )
00298     {
00299       // invalid
00300       kdWarning(5006) << k_funcinfo << "cannot remove a search folder" << endl;
00301     } else {
00302       kmkernel->folderMgr()->remove( mStorage->folder() );
00303     }
00304 
00305     emit renameDone( mNewName, true );
00306   } else
00307   {
00308     // move failed - rollback the last transaction
00309     kmkernel->undoStack()->undo();
00310 
00311     emit renameDone( mNewName, false );
00312   }
00313   delete this;
00314 }
00315 
00316 void RenameJob::slotMoveSubFolders( QString newName, bool success )
00317 {
00318   if ( !success ) {
00319       emit renameDone( newName, false );
00320   } else {
00321     KMFolderDir* child = mStorage->folder()->child();
00322     if ( child && child->first() )
00323     {
00324       KMFolderNode* node = child->first();
00325       {
00326         FolderStorage* childStorage = static_cast<KMFolder*>(node)->storage();
00327         if ( !mNewFolder->child() )
00328           mNewFolder->createChildFolder();
00329         RenameJob* job = new RenameJob( childStorage, childStorage->name(),
00330                                         mNewFolder->child() );
00331         connect( job, SIGNAL( renameDone( QString, bool ) ),
00332             this, SLOT( slotMoveSubFolders( QString, bool ) ) );
00333         job->start();
00334       }
00335     }
00336     else slotMoveMessages();
00337   }
00338 }
00339 
00340 void RenameJob::moveSubFoldersBeforeMessages()
00341 {
00342   // move child folders recursive if present - else simply move the messages
00343   KMFolderDir* child = mStorage->folder()->child();
00344   if ( child )
00345     slotMoveSubFolders( "", true );
00346   else slotMoveMessages();
00347 }
00348 
00349 #include "renamejob.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys