/* -*- mode: C++; c-file-style: "gnu" -*-
*
* This file is part of KMail , the KDE mail client .
* Copyright ( c ) 2002 - 2004 Bo Thorsen < bo @ sonofthor . dk >
* 2002 - 2003 Steffen Hansen < hansen @ kde . org >
* 2002 - 2003 Zack Rusin < zack @ kde . org >
*
* KMail is free software ; you can redistribute it and / or modify it
* under the terms of the GNU General Public License , version 2 , as
* published by the Free Software Foundation .
*
* KMail is distributed in the hope that it will be useful , but
* WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA
*
* In addition , as a special exception , the copyright holders give
* permission to link the code of this program with any edition of
* the TQt library by Trolltech AS , Norway ( or with modified versions
* of TQt that use the same license as TQt ) , and distribute linked
* combinations including the two . You must obey the GNU General
* Public License in all respects for all of the code used other than
* TQt . If you modify this file , you may extend this exception to
* your version of the file , but you are not obligated to do so . If
* you do not wish to do so , delete this exception statement from
* your version .
*/
# ifdef HAVE_CONFIG_H
# include <config.h>
# endif
# include "cachedimapjob.h"
# include "imapaccountbase.h"
# include "kmfoldermgr.h"
# include "kmfolder.h"
# include "kmfoldercachedimap.h"
# include "kmailicalifaceimpl.h"
# include "kmacctcachedimap.h"
# include "kmmsgdict.h"
# include "maildirjob.h"
# include "scalix.h"
# include "util.h"
# include <kio/scheduler.h>
# include <kio/job.h>
# include <klocale.h>
# include <kdebug.h>
namespace KMail {
// Get messages
CachedImapJob : : CachedImapJob ( const TQValueList < MsgForDownload > & msgs ,
JobType type , KMFolderCachedImap * folder )
: FolderJob ( type ) , mFolder ( folder ) , mMsgsForDownload ( msgs ) ,
mTotalBytes ( 0 ) , mMsg ( 0 ) , mParentFolder ( 0 )
{
TQValueList < MsgForDownload > : : ConstIterator it = msgs . begin ( ) ;
for ( ; it ! = msgs . end ( ) ; + + it )
mTotalBytes + = ( * it ) . size ;
}
// Put messages
CachedImapJob : : CachedImapJob ( const TQPtrList < KMMessage > & msgs , JobType type ,
KMFolderCachedImap * folder )
: FolderJob ( msgs , TQString ( ) , type , folder ? folder - > folder ( ) : 0 ) , mFolder ( folder ) ,
mTotalBytes ( msgs . count ( ) ) , // we abuse it as "total number of messages"
mMsg ( 0 ) , mParentFolder ( 0 )
{
}
CachedImapJob : : CachedImapJob ( const TQValueList < unsigned long > & msgs ,
JobType type , KMFolderCachedImap * folder )
: FolderJob ( TQPtrList < KMMessage > ( ) , TQString ( ) , type , folder ? folder - > folder ( ) : 0 ) ,
mFolder ( folder ) , mSerNumMsgList ( msgs ) , mTotalBytes ( msgs . count ( ) ) , mMsg ( 0 ) ,
mParentFolder ( 0 )
{
}
// Add sub folders
CachedImapJob : : CachedImapJob ( const TQValueList < KMFolderCachedImap * > & fList ,
JobType type , KMFolderCachedImap * folder )
: FolderJob ( type ) , mFolder ( folder ) , mFolderList ( fList ) , mMsg ( 0 ) ,
mParentFolder ( 0 )
{
}
// Rename folder
CachedImapJob : : CachedImapJob ( const TQString & string1 , JobType type ,
KMFolderCachedImap * folder )
: FolderJob ( type ) , mFolder ( folder ) , mMsg ( 0 ) , mString ( string1 ) ,
mParentFolder ( 0 )
{
assert ( folder ) ;
assert ( type ! = tDeleteMessage ) ; // moved to another ctor
}
// Delete folders or messages
CachedImapJob : : CachedImapJob ( const TQStringList & foldersOrMsgs , JobType type ,
KMFolderCachedImap * folder )
: FolderJob ( type ) , mFolder ( folder ) , mFoldersOrMessages ( foldersOrMsgs ) ,
mMsg ( 0 ) , mParentFolder ( 0 )
{
assert ( folder ) ;
}
// Other jobs (list messages,expunge folder, check uid validity)
CachedImapJob : : CachedImapJob ( JobType type , KMFolderCachedImap * folder )
: FolderJob ( type ) , mFolder ( folder ) , mMsg ( 0 ) , mParentFolder ( 0 )
{
assert ( folder ) ;
}
CachedImapJob : : ~ CachedImapJob ( )
{
mAccount - > mJobList . remove ( this ) ;
}
void CachedImapJob : : execute ( )
{
mSentBytes = 0 ;
if ( ! mFolder ) {
if ( ! mMsgList . isEmpty ( ) ) {
mFolder = static_cast < KMFolderCachedImap * > ( mMsgList . first ( ) - > storage ( ) ) ;
}
}
assert ( mFolder ) ;
mAccount = mFolder - > account ( ) ;
assert ( mAccount ! = 0 ) ;
if ( mAccount - > makeConnection ( ) ! = ImapAccountBase : : Connected ) {
// No connection to the IMAP server
kdDebug ( 5006 ) < < " mAccount->makeConnection() failed " < < endl ;
mPassiveDestructor = true ;
delete this ;
return ;
} else
mPassiveDestructor = false ;
// All necessary conditions have been met. Register this job
mAccount - > mJobList . append ( this ) ;
/**
* The Scalix server requires to send him a custom X - SCALIX - ID command
* to switch it into a special mode .
*
* This should be done once after the login and before the first command .
*/
if ( mAccount - > groupwareType ( ) = = KMAcctCachedImap : : GroupwareScalix ) {
if ( ! mAccount - > sentCustomLoginCommand ( ) ) {
TQByteArray packedArgs ;
TQDataStream stream ( packedArgs , IO_WriteOnly ) ;
const TQString command = TQString ( " X-SCALIX-ID " ) ;
const TQString argument = TQString ( " ( \" name \" \" Evolution \" \" version \" \" 2.10.0 \" ) " ) ;
stream < < ( int ) ' X ' < < ' N ' < < command < < argument ;
const KURL url = mAccount - > getUrl ( ) ;
ImapAccountBase : : jobData jd ( url . url ( ) , mFolder - > folder ( ) ) ;
jd . items < < mFolder - > label ( ) ; // for the err msg
TDEIO : : SimpleJob * simpleJob = TDEIO : : special ( url . url ( ) , packedArgs , false ) ;
TDEIO : : Scheduler : : assignJobToSlave ( mAccount - > slave ( ) , simpleJob ) ;
mAccount - > insertJob ( simpleJob , jd ) ;
mAccount - > setSentCustomLoginCommand ( true ) ;
}
}
switch ( mType ) {
case tGetMessage : slotGetNextMessage ( ) ; break ;
case tPutMessage : slotPutNextMessage ( ) ; break ;
case tDeleteMessage : slotDeleteNextMessages ( ) ; break ;
case tExpungeFolder : expungeFolder ( ) ; break ;
case tAddSubfolders : slotAddNextSubfolder ( ) ; break ;
case tDeleteFolders : slotDeleteNextFolder ( ) ; break ;
case tCheckUidValidity : checkUidValidity ( ) ; break ;
case tRenameFolder : renameFolder ( mString ) ; break ;
case tListMessages : listMessages ( ) ; break ;
default :
assert ( 0 ) ;
}
}
void CachedImapJob : : listMessages ( )
{
KURL url = mAccount - > getUrl ( ) ;
url . setPath ( mFolder - > imapPath ( ) + " ;UID=1:*;SECTION=FLAGS RFC822.SIZE " ) ;
TDEIO : : SimpleJob * job = TDEIO : : get ( url , false , false ) ;
TDEIO : : Scheduler : : assignJobToSlave ( mAccount - > slave ( ) , job ) ;
ImapAccountBase : : jobData jd ( url . url ( ) , mFolder - > folder ( ) ) ;
jd . cancellable = true ;
mAccount - > insertJob ( job , jd ) ;
connect ( job , TQT_SIGNAL ( result ( TDEIO : : Job * ) ) ,
this , TQT_SLOT ( slotListMessagesResult ( TDEIO : : Job * ) ) ) ;
// send the data directly for KMFolderCachedImap
connect ( job , TQT_SIGNAL ( data ( TDEIO : : Job * , const TQByteArray & ) ) ,
mFolder , TQT_SLOT ( slotGetMessagesData ( TDEIO : : Job * , const TQByteArray & ) ) ) ;
}
void CachedImapJob : : slotDeleteNextMessages ( TDEIO : : Job * job )
{
if ( job ) {
KMAcctCachedImap : : JobIterator it = mAccount - > findJob ( job ) ;
if ( it = = mAccount - > jobsEnd ( ) ) { // Shouldn't happen
delete this ;
return ;
}
if ( job - > error ( ) ) {
mAccount - > handleJobError ( job , i18n ( " Error while deleting messages on the server: " ) + ' \n ' ) ;
delete this ;
return ;
}
mAccount - > removeJob ( it ) ;
}
if ( mFoldersOrMessages . isEmpty ( ) ) {
// No more messages to delete
delete this ;
return ;
}
TQString uids = mFoldersOrMessages . front ( ) ; mFoldersOrMessages . pop_front ( ) ;
KURL url = mAccount - > getUrl ( ) ;
url . setPath ( mFolder - > imapPath ( ) +
TQString : : fromLatin1 ( " ;UID=%1 " ) . arg ( uids ) ) ;
TDEIO : : SimpleJob * simpleJob = TDEIO : : file_delete ( url , false ) ;
TDEIO : : Scheduler : : assignJobToSlave ( mAccount - > slave ( ) , simpleJob ) ;
ImapAccountBase : : jobData jd ( url . url ( ) , mFolder - > folder ( ) ) ;
mAccount - > insertJob ( simpleJob , jd ) ;
connect ( simpleJob , TQT_SIGNAL ( result ( TDEIO : : Job * ) ) ,
this , TQT_SLOT ( slotDeleteNextMessages ( TDEIO : : Job * ) ) ) ;
}
void CachedImapJob : : expungeFolder ( )
{
KURL url = mAccount - > getUrl ( ) ;
// Special URL that means EXPUNGE
url . setPath ( mFolder - > imapPath ( ) + TQString : : fromLatin1 ( " ;UID=* " ) ) ;
TDEIO : : SimpleJob * job = TDEIO : : file_delete ( url , false ) ;
TDEIO : : Scheduler : : assignJobToSlave ( mAccount - > slave ( ) , job ) ;
ImapAccountBase : : jobData jd ( url . url ( ) , mFolder - > folder ( ) ) ;
mAccount - > insertJob ( job , jd ) ;
connect ( job , TQT_SIGNAL ( result ( TDEIO : : Job * ) ) ,
this , TQT_SLOT ( slotExpungeResult ( TDEIO : : Job * ) ) ) ;
}
void CachedImapJob : : slotExpungeResult ( TDEIO : : Job * job )
{
KMAcctCachedImap : : JobIterator it = mAccount - > findJob ( job ) ;
if ( it = = mAccount - > jobsEnd ( ) ) { // Shouldn't happen
delete this ;
return ;
}
if ( job - > error ( ) ) {
mErrorCode = job - > error ( ) ;
mAccount - > handleJobError ( job , i18n ( " Error while deleting messages on the server: " ) + ' \n ' ) ;
}
else
mAccount - > removeJob ( it ) ;
delete this ;
}
void CachedImapJob : : slotGetNextMessage ( TDEIO : : Job * job )
{
if ( job ) {
KMAcctCachedImap : : JobIterator it = mAccount - > findJob ( job ) ;
if ( it = = mAccount - > jobsEnd ( ) ) { // Shouldn't happen
delete this ;
return ;
}
if ( job - > error ( ) ) {
mErrorCode = job - > error ( ) ;
mAccount - > handleJobError ( job , i18n ( " Error while retrieving message on the server: " ) + ' \n ' ) ;
delete this ;
return ;
}
ulong size = 0 ;
if ( ( * it ) . data . size ( ) > 0 ) {
ulong uid = mMsg - > UID ( ) ;
size = mMsg - > msgSizeServer ( ) ;
// Convert CR/LF to LF.
size_t dataSize = ( * it ) . data . size ( ) ;
dataSize = Util : : crlf2lf ( ( * it ) . data . data ( ) , dataSize ) ; // always <=
( * it ) . data . resize ( dataSize ) ;
mMsg - > setComplete ( true ) ;
mMsg - > fromByteArray ( ( * it ) . data ) ;
mMsg - > setUID ( uid ) ;
mMsg - > setMsgSizeServer ( size ) ;
mMsg - > setTransferInProgress ( false ) ;
int index = 0 ;
mFolder - > addMsgInternal ( mMsg , true , & index ) ;
if ( kmkernel - > iCalIface ( ) . isResourceFolder ( mFolder - > folder ( ) ) ) {
mFolder - > setStatus ( index , KMMsgStatusRead , false ) ;
}
emit messageRetrieved ( mMsg ) ;
if ( index > 0 ) mFolder - > unGetMsg ( index ) ;
} else {
emit messageRetrieved ( 0 ) ;
}
mMsg = 0 ;
mSentBytes + = size ;
emit progress ( mSentBytes , mTotalBytes ) ;
mAccount - > removeJob ( it ) ;
} else
mFolder - > quiet ( true ) ;
if ( mMsgsForDownload . isEmpty ( ) ) {
mFolder - > quiet ( false ) ;
delete this ;
return ;
}
MsgForDownload mfd = mMsgsForDownload . front ( ) ; mMsgsForDownload . pop_front ( ) ;
mMsg = new KMMessage ;
mMsg - > setUID ( mfd . uid ) ;
mMsg - > setMsgSizeServer ( mfd . size ) ;
if ( mfd . flags > 0 )
KMFolderImap : : flagsToStatus ( mMsg , mfd . flags , true , GlobalSettings : : allowLocalFlags ( ) ? mFolder - > permanentFlags ( ) : INT_MAX ) ;
KURL url = mAccount - > getUrl ( ) ;
url . setPath ( mFolder - > imapPath ( ) + TQString ( " ;UID=%1;SECTION=BODY.PEEK[] " ) . arg ( mfd . uid ) ) ;
ImapAccountBase : : jobData jd ( url . url ( ) , mFolder - > folder ( ) ) ;
jd . cancellable = true ;
mMsg - > setTransferInProgress ( true ) ;
TDEIO : : SimpleJob * simpleJob = TDEIO : : get ( url , false , false ) ;
TDEIO : : Scheduler : : assignJobToSlave ( mAccount - > slave ( ) , simpleJob ) ;
mAccount - > insertJob ( simpleJob , jd ) ;
connect ( simpleJob , TQT_SIGNAL ( processedSize ( TDEIO : : Job * , TDEIO : : filesize_t ) ) ,
this , TQT_SLOT ( slotProcessedSize ( TDEIO : : Job * , TDEIO : : filesize_t ) ) ) ;
connect ( simpleJob , TQT_SIGNAL ( result ( TDEIO : : Job * ) ) ,
this , TQT_SLOT ( slotGetNextMessage ( TDEIO : : Job * ) ) ) ;
connect ( simpleJob , TQT_SIGNAL ( data ( TDEIO : : Job * , const TQByteArray & ) ) ,
mFolder , TQT_SLOT ( slotSimpleData ( TDEIO : : Job * , const TQByteArray & ) ) ) ;
}
void CachedImapJob : : slotProcessedSize ( TDEIO : : Job * , TDEIO : : filesize_t processed )
{
emit progress ( mSentBytes + processed , mTotalBytes ) ;
}
void CachedImapJob : : slotPutNextMessage ( )
{
mMsg = 0 ;
// First try the message list
if ( ! mMsgList . isEmpty ( ) ) {
mMsg = mMsgList . first ( ) ;
mMsgList . removeFirst ( ) ;
}
// Now try the serial number list
while ( mMsg = = 0 & & ! mSerNumMsgList . isEmpty ( ) ) {
unsigned long serNum = mSerNumMsgList . first ( ) ;
mSerNumMsgList . pop_front ( ) ;
// Find the message with this serial number
int i = 0 ;
KMFolder * aFolder = 0 ;
KMMsgDict : : instance ( ) - > getLocation ( serNum , & aFolder , & i ) ;
if ( mFolder - > folder ( ) ! = aFolder )
// This message was moved or something
continue ;
mMsg = mFolder - > getMsg ( i ) ;
}
if ( ! mMsg ) {
// No message found for upload
delete this ;
return ;
}
KURL url = mAccount - > getUrl ( ) ;
TQString flags = KMFolderImap : : statusToFlags ( mMsg - > status ( ) , mFolder - > permanentFlags ( ) ) ;
url . setPath ( mFolder - > imapPath ( ) + " ;SECTION= " + flags ) ;
ImapAccountBase : : jobData jd ( url . url ( ) , mFolder - > folder ( ) ) ;
mMsg - > setUID ( 0 ) ; // for the index
TQCString cstr ( mMsg - > asString ( ) ) ;
int a = cstr . find ( " \n X-UID: " ) ;
int b = cstr . find ( ' \n ' , a ) ;
if ( a ! = - 1 & & b ! = - 1 & & cstr . find ( " \n \n " ) > a ) cstr . remove ( a , b - a ) ;
TQCString mData ( cstr . length ( ) + cstr . contains ( ' \n ' ) ) ;
unsigned int i = 0 ;
for ( char * ch = cstr . data ( ) ; * ch ; ch + + ) {
if ( * ch = = ' \n ' ) {
mData . at ( i ) = ' \r ' ;
i + + ;
}
mData . at ( i ) = * ch ; i + + ;
}
jd . data = mData ;
jd . msgList . append ( mMsg ) ;
mMsg - > setTransferInProgress ( true ) ;
TDEIO : : SimpleJob * simpleJob = TDEIO : : put ( url , 0 , false , false , false ) ;
TDEIO : : Scheduler : : assignJobToSlave ( mAccount - > slave ( ) , simpleJob ) ;
mAccount - > insertJob ( simpleJob , jd ) ;
connect ( simpleJob , TQT_SIGNAL ( result ( TDEIO : : Job * ) ) ,
TQT_SLOT ( slotPutMessageResult ( TDEIO : : Job * ) ) ) ;
connect ( simpleJob , TQT_SIGNAL ( dataReq ( TDEIO : : Job * , TQByteArray & ) ) ,
TQT_SLOT ( slotPutMessageDataReq ( TDEIO : : Job * , TQByteArray & ) ) ) ;
connect ( simpleJob , TQT_SIGNAL ( data ( TDEIO : : Job * , const TQByteArray & ) ) ,
mFolder , TQT_SLOT ( slotSimpleData ( TDEIO : : Job * , const TQByteArray & ) ) ) ;
connect ( simpleJob , TQT_SIGNAL ( infoMessage ( TDEIO : : Job * , const TQString & ) ) ,
TQT_SLOT ( slotPutMessageInfoData ( TDEIO : : Job * , const TQString & ) ) ) ;
}
//-----------------------------------------------------------------------------
// TODO: port to TDEIO::StoredTransferJob once it's ok to require tdelibs-3.3
void CachedImapJob : : slotPutMessageDataReq ( TDEIO : : Job * job , TQByteArray & data )
{
KMAcctCachedImap : : JobIterator it = mAccount - > findJob ( job ) ;
if ( it = = mAccount - > jobsEnd ( ) ) { // Shouldn't happen
delete this ;
return ;
}
if ( ( * it ) . data . size ( ) - ( * it ) . offset > 0x8000 ) {
data . duplicate ( ( * it ) . data . data ( ) + ( * it ) . offset , 0x8000 ) ;
( * it ) . offset + = 0x8000 ;
} else if ( ( * it ) . data . size ( ) - ( * it ) . offset > 0 ) {
data . duplicate ( ( * it ) . data . data ( ) + ( * it ) . offset ,
( * it ) . data . size ( ) - ( * it ) . offset ) ;
( * it ) . offset = ( * it ) . data . size ( ) ;
} else
data . resize ( 0 ) ;
}
//----------------------------------------------------------------------------
void CachedImapJob : : slotPutMessageInfoData ( TDEIO : : Job * job , const TQString & data )
{
KMFolderCachedImap * imapFolder = static_cast < KMFolderCachedImap * > ( mDestFolder - > storage ( ) ) ;
if ( imapFolder ) {
KMAcctCachedImap * account = imapFolder - > account ( ) ;
ImapAccountBase : : JobIterator it = account - > findJob ( job ) ;
if ( it = = account - > jobsEnd ( ) ) {
return ;
}
if ( data . find ( " UID " ) ! = - 1 & & mMsg ) {
int uid = ( data . right ( data . length ( ) - 4 ) ) . toInt ( ) ;
kdDebug ( 5006 ) < < k_funcinfo < < " Server told us uid is: " < < uid < < endl ;
mMsg - > setUID ( uid ) ;
}
}
}
//-----------------------------------------------------------------------------
void CachedImapJob : : slotPutMessageResult ( TDEIO : : Job * job )
{
KMAcctCachedImap : : JobIterator it = mAccount - > findJob ( job ) ;
if ( it = = mAccount - > jobsEnd ( ) ) { // Shouldn't happen
delete this ;
return ;
}
if ( job - > error ( ) ) {
bool cont = mAccount - > handlePutError ( job , * it , mFolder - > folder ( ) ) ;
if ( ! cont ) {
delete this ;
} else {
mMsg = 0 ;
slotPutNextMessage ( ) ;
}
return ;
}
emit messageStored ( mMsg ) ;
// we abuse those fields, the unit is the number of messages, here
+ + mSentBytes ;
emit progress ( mSentBytes , mTotalBytes ) ;
int i ;
if ( ( i = mFolder - > find ( mMsg ) ) ! = - 1 ) {
/*
* If we have aquired a uid during upload the server supports the uidnext
* extension and there is no need to redownload this mail , we already have
* it . Otherwise remove it , it will be redownloaded .
*/
if ( mMsg - > UID ( ) = = 0 ) {
mFolder - > removeMsg ( i ) ;
} else {
// When removing+readding, no point in telling the imap resources about it
bool b = kmkernel - > iCalIface ( ) . isResourceQuiet ( ) ;
kmkernel - > iCalIface ( ) . setResourceQuiet ( true ) ;
mFolder - > takeTemporarily ( i ) ;
mFolder - > addMsgKeepUID ( mMsg ) ;
mMsg - > setTransferInProgress ( false ) ;
kmkernel - > iCalIface ( ) . setResourceQuiet ( b ) ;
}
}
mMsg = NULL ;
mAccount - > removeJob ( it ) ;
slotPutNextMessage ( ) ;
}
void CachedImapJob : : slotAddNextSubfolder ( TDEIO : : Job * job )
{
if ( job ) {
KMAcctCachedImap : : JobIterator it = mAccount - > findJob ( job ) ;
if ( it = = mAccount - > jobsEnd ( ) ) { // Shouldn't happen
delete this ;
return ;
}
// make copy of setting, to reset it before potentially destroying 'it'
bool silentUpload = static_cast < KMFolderCachedImap * > ( ( * it ) . parent - > storage ( ) ) - > silentUpload ( ) ;
static_cast < KMFolderCachedImap * > ( ( * it ) . parent - > storage ( ) ) - > setSilentUpload ( false ) ;
if ( job - > error ( ) & & ! silentUpload ) {
TQString myError = " <p><b> " + i18n ( " Error while uploading folder " )
+ " </b></p><p> " + i18n ( " Could not make the folder <b>%1</b> on the server. " ) . arg ( ( * it ) . items [ 0 ] )
+ " </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> " ;
mAccount - > handleJobError ( job , myError ) ;
}
if ( job - > error ( ) ) {
delete this ;
return ;
} else {
KMFolderCachedImap * storage = static_cast < KMFolderCachedImap * > ( ( * it ) . current - > storage ( ) ) ;
KMFolderCachedImap * parentStorage = static_cast < KMFolderCachedImap * > ( ( * it ) . parent - > storage ( ) ) ;
Q_ASSERT ( storage ) ;
Q_ASSERT ( parentStorage ) ;
if ( storage - > imapPath ( ) . isEmpty ( ) ) {
TQString path = mAccount - > createImapPath ( parentStorage - > imapPath ( ) , storage - > folder ( ) - > name ( ) ) ;
if ( ! storage - > imapPathForCreation ( ) . isEmpty ( ) )
path = storage - > imapPathForCreation ( ) ;
storage - > setImapPath ( path ) ;
storage - > writeConfig ( ) ;
}
}
mAccount - > removeJob ( it ) ;
}
if ( mFolderList . isEmpty ( ) ) {
// No more folders to add
delete this ;
return ;
}
KMFolderCachedImap * folder = mFolderList . front ( ) ;
mFolderList . pop_front ( ) ;
KURL url = mAccount - > getUrl ( ) ;
TQString path = mAccount - > createImapPath ( mFolder - > imapPath ( ) ,
folder - > folder ( ) - > name ( ) ) ;
if ( ! folder - > imapPathForCreation ( ) . isEmpty ( ) ) {
// the folder knows it's namespace
path = folder - > imapPathForCreation ( ) ;
}
url . setPath ( path ) ;
if ( mAccount - > groupwareType ( ) ! = KMAcctCachedImap : : GroupwareScalix ) {
// Associate the jobData with the parent folder, not with the child
// This is necessary in case of an error while creating the subfolder,
// so that folderComplete is called on the parent (and the sync resetted).
ImapAccountBase : : jobData jd ( url . url ( ) , mFolder - > folder ( ) ) ;
jd . items < < folder - > label ( ) ; // for the err msg
jd . current = folder - > folder ( ) ;
TDEIO : : SimpleJob * simpleJob = TDEIO : : mkdir ( url ) ;
TDEIO : : Scheduler : : assignJobToSlave ( mAccount - > slave ( ) , simpleJob ) ;
mAccount - > insertJob ( simpleJob , jd ) ;
connect ( simpleJob , TQT_SIGNAL ( result ( TDEIO : : Job * ) ) ,
this , TQT_SLOT ( slotAddNextSubfolder ( TDEIO : : Job * ) ) ) ;
} else {
TQByteArray packedArgs ;
TQDataStream stream ( packedArgs , IO_WriteOnly ) ;
const TQString command = TQString ( " X-CREATE-SPECIAL " ) ;
const TQString argument = TQString ( " %1 %2 " ) . arg ( Scalix : : Utils : : contentsTypeToScalixId ( folder - > contentsType ( ) ) )
. arg ( path ) ;
stream < < ( int ) ' X ' < < ' N ' < < command < < argument ;
ImapAccountBase : : jobData jd ( url . url ( ) , mFolder - > folder ( ) ) ;
jd . items < < folder - > label ( ) ; // for the err msg
jd . current = folder - > folder ( ) ;
TDEIO : : SimpleJob * simpleJob = TDEIO : : special ( url . url ( ) , packedArgs , false ) ;
TDEIO : : Scheduler : : assignJobToSlave ( mAccount - > slave ( ) , simpleJob ) ;
mAccount - > insertJob ( simpleJob , jd ) ;
connect ( simpleJob , TQT_SIGNAL ( result ( TDEIO : : Job * ) ) ,
this , TQT_SLOT ( slotAddNextSubfolder ( TDEIO : : Job * ) ) ) ;
}
}
void CachedImapJob : : slotDeleteNextFolder ( TDEIO : : Job * job )
{
if ( job ) {
KMAcctCachedImap : : JobIterator it = mAccount - > findJob ( job ) ;
if ( it = = mAccount - > jobsEnd ( ) ) { // Shouldn't happen
delete this ;
return ;
}
mAccount - > removeDeletedFolder ( ( * it ) . path ) ;
if ( job - > error ( ) ) {
mAccount - > handleJobError ( job , i18n ( " Error while deleting folder %1 on the server: " ) . arg ( ( * it ) . path ) + ' \n ' ) ;
delete this ;
return ;
}
mAccount - > removeJob ( it ) ;
}
if ( mFoldersOrMessages . isEmpty ( ) ) {
// No more folders to delete
delete this ;
return ;
}
TQString folderPath = mFoldersOrMessages . front ( ) ;
mFoldersOrMessages . pop_front ( ) ;
KURL url = mAccount - > getUrl ( ) ;
url . setPath ( folderPath ) ;
ImapAccountBase : : jobData jd ( url . url ( ) , mFolder - > folder ( ) ) ;
jd . path = url . path ( ) ;
TDEIO : : SimpleJob * simpleJob = TDEIO : : file_delete ( url , false ) ;
TDEIO : : Scheduler : : assignJobToSlave ( mAccount - > slave ( ) , simpleJob ) ;
mAccount - > insertJob ( simpleJob , jd ) ;
connect ( simpleJob , TQT_SIGNAL ( result ( TDEIO : : Job * ) ) ,
TQT_SLOT ( slotDeleteNextFolder ( TDEIO : : Job * ) ) ) ;
}
void CachedImapJob : : checkUidValidity ( )
{
KURL url = mAccount - > getUrl ( ) ;
url . setPath ( mFolder - > imapPath ( ) + " ;UID=0:0 " ) ;
ImapAccountBase : : jobData jd ( url . url ( ) , mFolder - > folder ( ) ) ;
jd . cancellable = true ;
TDEIO : : SimpleJob * job = TDEIO : : get ( url , false , false ) ;
TDEIO : : Scheduler : : assignJobToSlave ( mAccount - > slave ( ) , job ) ;
mAccount - > insertJob ( job , jd ) ;
connect ( job , TQT_SIGNAL ( result ( TDEIO : : Job * ) ) ,
TQT_SLOT ( slotCheckUidValidityResult ( TDEIO : : Job * ) ) ) ;
connect ( job , TQT_SIGNAL ( data ( TDEIO : : Job * , const TQByteArray & ) ) ,
mFolder , TQT_SLOT ( slotSimpleData ( TDEIO : : Job * , const TQByteArray & ) ) ) ;
}
void CachedImapJob : : slotCheckUidValidityResult ( TDEIO : : Job * job )
{
KMAcctCachedImap : : JobIterator it = mAccount - > findJob ( job ) ;
if ( it = = mAccount - > jobsEnd ( ) ) { // Shouldn't happen
delete this ;
return ;
}
if ( job - > error ( ) ) {
mErrorCode = job - > error ( ) ;
mAccount - > handleJobError ( job , i18n ( " Error while reading folder %1 on the server: " ) . arg ( ( * it ) . parent - > label ( ) ) + ' \n ' ) ;
delete this ;
return ;
}
// Check the uidValidity
TQCString cstr ( ( * it ) . data . data ( ) , ( * it ) . data . size ( ) + 1 ) ;
int a = cstr . find ( " X-uidValidity: " ) ;
if ( a < 0 ) {
// Something is seriously rotten here!
// TODO: Tell the user that he has a problem
kdDebug ( 5006 ) < < " No uidvalidity available for folder "
< < mFolder - > name ( ) < < endl ;
}
else {
int b = cstr . find ( " \r \n " , a ) ;
if ( ( b - a - 15 ) > = 0 ) {
TQString uidv = cstr . mid ( a + 15 , b - a - 15 ) ;
// kdDebug(5006) << "New uidv = " << uidv << ", old uidv = "
// << mFolder->uidValidity() << endl;
if ( ! mFolder - > uidValidity ( ) . isEmpty ( ) & & mFolder - > uidValidity ( ) ! = uidv ) {
// kdDebug(5006) << "Expunging the mailbox " << mFolder->name()
// << "!" << endl;
mFolder - > expunge ( ) ;
mFolder - > setLastUid ( 0 ) ;
mFolder - > clearUidMap ( ) ;
}
} else
kdDebug ( 5006 ) < < " No uidvalidity available for folder "
< < mFolder - > name ( ) < < endl ;
}
a = cstr . find ( " X-PermanentFlags: " ) ;
if ( a < 0 ) {
kdDebug ( 5006 ) < < " no PERMANENTFLAGS response? assumming custom flags are not available " < < endl ;
} else {
int b = cstr . find ( " \r \n " , a ) ;
if ( ( b - a - 18 ) > = 0 ) {
int flags = cstr . mid ( a + 18 , b - a - 18 ) . toInt ( ) ;
emit permanentFlags ( flags ) ;
} else {
kdDebug ( 5006 ) < < " PERMANENTFLAGS response broken, assumming custom flags are not available " < < endl ;
}
}
mAccount - > removeJob ( it ) ;
delete this ;
}
void CachedImapJob : : renameFolder ( const TQString & newName )
{
mNewName = newName ;
// Set the source URL
KURL urlSrc = mAccount - > getUrl ( ) ;
mOldImapPath = mFolder - > imapPath ( ) ;
urlSrc . setPath ( mOldImapPath ) ;
// Set the destination URL - this is a bit trickier
KURL urlDst = mAccount - > getUrl ( ) ;
mNewImapPath = mFolder - > imapPath ( ) ;
// Destination url = old imappath - oldname + new name
mNewImapPath . truncate ( mNewImapPath . length ( ) - mFolder - > folder ( ) - > name ( ) . length ( ) - 1 ) ;
mNewImapPath + = newName + ' / ' ;
urlDst . setPath ( mNewImapPath ) ;
ImapAccountBase : : jobData jd ( newName , mFolder - > folder ( ) ) ;
jd . path = mNewImapPath ;
TDEIO : : SimpleJob * simpleJob = TDEIO : : rename ( urlSrc , urlDst , false ) ;
TDEIO : : Scheduler : : assignJobToSlave ( mAccount - > slave ( ) , simpleJob ) ;
mAccount - > insertJob ( simpleJob , jd ) ;
connect ( simpleJob , TQT_SIGNAL ( result ( TDEIO : : Job * ) ) ,
TQT_SLOT ( slotRenameFolderResult ( TDEIO : : Job * ) ) ) ;
}
static void renameChildFolders ( KMFolderDir * dir , const TQString & oldPath ,
const TQString & newPath )
{
if ( dir ) {
KMFolderNode * node = dir - > first ( ) ;
while ( node ) {
if ( ! node - > isDir ( ) ) {
KMFolderCachedImap * imapFolder =
static_cast < KMFolderCachedImap * > ( static_cast < KMFolder * > ( node ) - > storage ( ) ) ;
if ( ! imapFolder - > imapPath ( ) . isEmpty ( ) )
// Only rename folders that have been accepted by the server
if ( imapFolder - > imapPath ( ) . find ( oldPath ) = = 0 ) {
TQString p = imapFolder - > imapPath ( ) ;
p = p . mid ( oldPath . length ( ) ) ;
p . prepend ( newPath ) ;
imapFolder - > setImapPath ( p ) ;
renameChildFolders ( imapFolder - > folder ( ) - > child ( ) , oldPath , newPath ) ;
}
}
node = dir - > next ( ) ;
}
}
}
void CachedImapJob : : revertLabelChange ( )
{
TQMap < TQString , KMAcctCachedImap : : RenamedFolder > : : ConstIterator renit = mAccount - > renamedFolders ( ) . find ( mFolder - > imapPath ( ) ) ;
Q_ASSERT ( renit ! = mAccount - > renamedFolders ( ) . end ( ) ) ;
if ( renit ! = mAccount - > renamedFolders ( ) . end ( ) ) {
mFolder - > folder ( ) - > setLabel ( ( * renit ) . mOldLabel ) ;
mAccount - > removeRenamedFolder ( mFolder - > imapPath ( ) ) ;
kmkernel - > dimapFolderMgr ( ) - > contentsChanged ( ) ;
}
}
void CachedImapJob : : renameOnDisk ( )
{
TQString oldName = mFolder - > name ( ) ;
TQString oldPath = mFolder - > imapPath ( ) ;
mAccount - > removeRenamedFolder ( oldPath ) ;
mFolder - > setImapPath ( mNewImapPath ) ;
mFolder - > FolderStorage : : rename ( mNewName ) ;
if ( oldPath . endsWith ( " / " ) ) oldPath . truncate ( oldPath . length ( ) - 1 ) ;
TQString newPath = mFolder - > imapPath ( ) ;
if ( newPath . endsWith ( " / " ) ) newPath . truncate ( newPath . length ( ) - 1 ) ;
renameChildFolders ( mFolder - > folder ( ) - > child ( ) , oldPath , newPath ) ;
kmkernel - > dimapFolderMgr ( ) - > contentsChanged ( ) ;
}
void CachedImapJob : : slotSubscribtionChange1Failed ( const TQString & errorMessage )
{
KMessageBox : : sorry ( 0 , i18n ( " Error while trying to subscribe to the renamed folder %1. \n "
" Renaming itself was successful, but the renamed folder might disappear "
" from the folder list after the next sync since it is unsubscribed on the server. \n "
" You can try to manually subscribe to the folder yourself. \n \n "
" %2 " )
. arg ( mFolder - > label ( ) ) . arg ( errorMessage ) ) ;
delete this ;
}
void CachedImapJob : : slotSubscribtionChange2Failed ( const TQString & errorMessage )
{
kdWarning ( 5006 ) < < k_funcinfo < < errorMessage < < endl ;
// Ignore this error, not something user-visible anyway
delete this ;
}
void CachedImapJob : : slotSubscribtionChange1Done ( const TQString & , bool )
{
disconnect ( mAccount , TQT_SIGNAL ( subscriptionChanged ( const TQString & , bool ) ) ,
this , TQT_SLOT ( slotSubscribtionChange1Done ( const TQString & , bool ) ) ) ;
connect ( mAccount , TQT_SIGNAL ( subscriptionChanged ( const TQString & , bool ) ) ,
this , TQT_SLOT ( slotSubscribtionChange2Done ( const TQString & , bool ) ) ) ;
disconnect ( mAccount , TQT_SIGNAL ( subscriptionChangeFailed ( const TQString & ) ) ,
this , TQT_SLOT ( slotSubscribtionChange1Failed ( const TQString & ) ) ) ;
connect ( mAccount , TQT_SIGNAL ( subscriptionChangeFailed ( const TQString & ) ) ,
this , TQT_SLOT ( slotSubscribtionChange2Failed ( const TQString & ) ) ) ;
mAccount - > changeSubscription ( false , mOldImapPath , true /* quiet */ ) ;
}
void CachedImapJob : : slotSubscribtionChange2Done ( const TQString & , bool )
{
// Finally done with everything!
delete this ;
}
void CachedImapJob : : slotRenameFolderResult ( TDEIO : : Job * job )
{
KMAcctCachedImap : : JobIterator it = mAccount - > findJob ( job ) ;
if ( it = = mAccount - > jobsEnd ( ) ) { // Shouldn't happen
delete this ;
return ;
}
if ( job - > error ( ) ) {
revertLabelChange ( ) ;
const TQString errorMessage = i18n ( " Error while trying to rename folder %1 " ) . arg ( mFolder - > label ( ) ) ;
mAccount - > handleJobError ( job , errorMessage ) ;
delete this ;
} else {
mAccount - > removeJob ( it ) ;
renameOnDisk ( ) ;
// Okay, the folder seems to be renamed on the server and on disk.
// Now unsubscribe from the old folder name and subscribe to the new folder name,
// so that the folder doesn't suddenly disappear after renaming it
connect ( mAccount , TQT_SIGNAL ( subscriptionChangeFailed ( const TQString & ) ) ,
this , TQT_SLOT ( slotSubscribtionChange1Failed ( const TQString & ) ) ) ;
connect ( mAccount , TQT_SIGNAL ( subscriptionChanged ( const TQString & , bool ) ) ,
this , TQT_SLOT ( slotSubscribtionChange1Done ( const TQString & , bool ) ) ) ;
mAccount - > changeSubscription ( true , mNewImapPath , true /* quiet */ ) ;
}
}
void CachedImapJob : : slotListMessagesResult ( TDEIO : : Job * job )
{
KMAcctCachedImap : : JobIterator it = mAccount - > findJob ( job ) ;
if ( it = = mAccount - > jobsEnd ( ) ) { // Shouldn't happen
delete this ;
return ;
}
if ( job - > error ( ) ) {
mErrorCode = job - > error ( ) ;
mAccount - > handleJobError ( job , i18n ( " Error while deleting messages on the server: " ) + ' \n ' ) ;
}
else
mAccount - > removeJob ( it ) ;
delete this ;
}
//-----------------------------------------------------------------------------
void CachedImapJob : : setParentFolder ( const KMFolderCachedImap * parent )
{
mParentFolder = const_cast < KMFolderCachedImap * > ( parent ) ;
}
}
# include "cachedimapjob.moc"