kmail

cachedimapjob.cpp
1/*
2 *
3 * This file is part of KMail, the KDE mail client.
4 * Copyright (c) 2002-2004 Bo Thorsen <bo@sonofthor.dk>
5 * 2002-2003 Steffen Hansen <hansen@kde.org>
6 * 2002-2003 Zack Rusin <zack@kde.org>
7 *
8 * KMail is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License, version 2, as
10 * published by the Free Software Foundation.
11 *
12 * KMail is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 *
21 * In addition, as a special exception, the copyright holders give
22 * permission to link the code of this program with any edition of
23 * the TQt library by Trolltech AS, Norway (or with modified versions
24 * of TQt that use the same license as TQt), and distribute linked
25 * combinations including the two. You must obey the GNU General
26 * Public License in all respects for all of the code used other than
27 * TQt. If you modify this file, you may extend this exception to
28 * your version of the file, but you are not obligated to do so. If
29 * you do not wish to do so, delete this exception statement from
30 * your version.
31 */
32
33#ifdef HAVE_CONFIG_H
34#include <config.h>
35#endif
36
37#include "cachedimapjob.h"
38#include "imapaccountbase.h"
39
40#include "kmfoldermgr.h"
41#include "kmfolder.h"
42#include "kmfoldercachedimap.h"
43#include "kmailicalifaceimpl.h"
44#include "kmacctcachedimap.h"
45#include "kmmsgdict.h"
46#include "maildirjob.h"
47#include "scalix.h"
48#include "util.h"
49
50#include <tdeio/scheduler.h>
51#include <tdeio/job.h>
52
53#include <tdelocale.h>
54#include <kdebug.h>
55
56
57namespace KMail {
58
59// Get messages
60CachedImapJob::CachedImapJob( const TQValueList<MsgForDownload>& msgs,
61 JobType type, KMFolderCachedImap* folder )
62 : FolderJob( type ), mFolder( folder ), mMsgsForDownload( msgs ),
63 mTotalBytes(0), mMsg(0), mParentFolder( 0 )
64{
65 TQValueList<MsgForDownload>::ConstIterator it = msgs.begin();
66 for ( ; it != msgs.end() ; ++it )
67 mTotalBytes += (*it).size;
68}
69
70// Put messages
71CachedImapJob::CachedImapJob( const TQPtrList<KMMessage>& msgs, JobType type,
72 KMFolderCachedImap* folder )
73 : FolderJob( msgs, TQString(), type, folder?folder->folder():0 ), mFolder( folder ),
74 mTotalBytes( msgs.count() ), // we abuse it as "total number of messages"
75 mMsg( 0 ), mParentFolder( 0 )
76{
77}
78
79CachedImapJob::CachedImapJob( const TQValueList<unsigned long>& msgs,
80 JobType type, KMFolderCachedImap* folder )
81 : FolderJob( TQPtrList<KMMessage>(), TQString(), type, folder?folder->folder():0 ),
82 mFolder( folder ), mSerNumMsgList( msgs ), mTotalBytes( msgs.count() ), mMsg( 0 ),
83 mParentFolder ( 0 )
84{
85}
86
87// Add sub folders
88CachedImapJob::CachedImapJob( const TQValueList<KMFolderCachedImap*>& fList,
89 JobType type, KMFolderCachedImap* folder )
90 : FolderJob( type ), mFolder( folder ), mFolderList( fList ), mMsg( 0 ),
91 mParentFolder ( 0 )
92{
93}
94
95// Rename folder
96CachedImapJob::CachedImapJob( const TQString& string1, JobType type,
97 KMFolderCachedImap* folder )
98 : FolderJob( type ), mFolder(folder), mMsg( 0 ), mString( string1 ),
99 mParentFolder ( 0 )
100{
101 assert( folder );
102 assert( type != tDeleteMessage ); // moved to another ctor
103}
104
105// Delete folders or messages
106CachedImapJob::CachedImapJob( const TQStringList& foldersOrMsgs, JobType type,
107 KMFolderCachedImap* folder )
108 : FolderJob( type ), mFolder( folder ), mFoldersOrMessages( foldersOrMsgs ),
109 mMsg( 0 ), mParentFolder( 0 )
110{
111 assert( folder );
112}
113
114// Other jobs (list messages,expunge folder, check uid validity)
115CachedImapJob::CachedImapJob( JobType type, KMFolderCachedImap* folder )
116 : FolderJob( type ), mFolder( folder ), mMsg( 0 ), mParentFolder ( 0 )
117{
118 assert( folder );
119}
120
121CachedImapJob::~CachedImapJob()
122{
123 mAccount->mJobList.remove(this);
124}
125
126void CachedImapJob::execute()
127{
128 mSentBytes = 0;
129
130 if( !mFolder ) {
131 if( !mMsgList.isEmpty() ) {
132 mFolder = static_cast<KMFolderCachedImap*>(mMsgList.first()->storage());
133 }
134 }
135 assert( mFolder );
136 mAccount = mFolder->account();
137 assert( mAccount != 0 );
138 if( mAccount->makeConnection() != ImapAccountBase::Connected ) {
139 // No connection to the IMAP server
140 kdDebug(5006) << "mAccount->makeConnection() failed" << endl;
141 mPassiveDestructor = true;
142 delete this;
143 return;
144 } else
145 mPassiveDestructor = false;
146
147 // All necessary conditions have been met. Register this job
148 mAccount->mJobList.append(this);
149
156 if ( mAccount->groupwareType() == KMAcctCachedImap::GroupwareScalix ) {
157 if ( !mAccount->sentCustomLoginCommand() ) {
158 TQByteArray packedArgs;
159 TQDataStream stream( packedArgs, IO_WriteOnly );
160
161 const TQString command = TQString( "X-SCALIX-ID " );
162 const TQString argument = TQString( "(\"name\" \"Evolution\" \"version\" \"2.10.0\")" );
163
164 stream << (int) 'X' << 'N' << command << argument;
165
166 const KURL url = mAccount->getUrl();
167
168 ImapAccountBase::jobData jd( url.url(), mFolder->folder() );
169 jd.items << mFolder->label(); // for the err msg
170 TDEIO::SimpleJob *simpleJob = TDEIO::special( url.url(), packedArgs, false );
171 TDEIO::Scheduler::assignJobToSlave(mAccount->slave(), simpleJob);
172 mAccount->insertJob(simpleJob, jd);
173
174 mAccount->setSentCustomLoginCommand( true );
175 }
176 }
177
178 switch( mType ) {
179 case tGetMessage: slotGetNextMessage(); break;
180 case tPutMessage: slotPutNextMessage(); break;
181 case tDeleteMessage: slotDeleteNextMessages(); break;
182 case tExpungeFolder: expungeFolder(); break;
183 case tAddSubfolders: slotAddNextSubfolder(); break;
184 case tDeleteFolders: slotDeleteNextFolder(); break;
185 case tCheckUidValidity: checkUidValidity(); break;
186 case tRenameFolder: renameFolder(mString); break;
187 case tListMessages: listMessages(); break;
188 default:
189 assert( 0 );
190 }
191}
192
193void CachedImapJob::listMessages()
194{
195 KURL url = mAccount->getUrl();
196 url.setPath( mFolder->imapPath() + ";UID=1:*;SECTION=FLAGS RFC822.SIZE");
197
198 TDEIO::SimpleJob *job = TDEIO::get(url, false, false);
199 TDEIO::Scheduler::assignJobToSlave( mAccount->slave(), job );
200 ImapAccountBase::jobData jd( url.url(), mFolder->folder() );
201 jd.cancellable = true;
202 mAccount->insertJob( job, jd );
203 connect( job, TQ_SIGNAL( result(TDEIO::Job *) ),
204 this, TQ_SLOT( slotListMessagesResult( TDEIO::Job* ) ) );
205 // send the data directly for KMFolderCachedImap
206 connect( job, TQ_SIGNAL( data( TDEIO::Job*, const TQByteArray& ) ),
207 mFolder, TQ_SLOT( slotGetMessagesData( TDEIO::Job* , const TQByteArray& ) ) );
208}
209
210void CachedImapJob::slotDeleteNextMessages( TDEIO::Job* job )
211{
212 if (job) {
213 KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
214 if ( it == mAccount->jobsEnd() ) { // Shouldn't happen
215 delete this;
216 return;
217 }
218
219 if( job->error() ) {
220 mAccount->handleJobError( job, i18n( "Error while deleting messages on the server: " ) + '\n' );
221 delete this;
222 return;
223 }
224 mAccount->removeJob(it);
225 }
226
227 if( mFoldersOrMessages.isEmpty() ) {
228 // No more messages to delete
229 delete this;
230 return;
231 }
232
233 TQString uids = mFoldersOrMessages.front(); mFoldersOrMessages.pop_front();
234
235 KURL url = mAccount->getUrl();
236 url.setPath( mFolder->imapPath() +
237 TQString::fromLatin1(";UID=%1").arg(uids) );
238
239 TDEIO::SimpleJob *simpleJob = TDEIO::file_delete( url, false );
240 TDEIO::Scheduler::assignJobToSlave( mAccount->slave(), simpleJob );
241 ImapAccountBase::jobData jd( url.url(), mFolder->folder() );
242 mAccount->insertJob( simpleJob, jd );
243 connect( simpleJob, TQ_SIGNAL( result(TDEIO::Job *) ),
244 this, TQ_SLOT( slotDeleteNextMessages(TDEIO::Job *) ) );
245}
246
247void CachedImapJob::expungeFolder()
248{
249 KURL url = mAccount->getUrl();
250 // Special URL that means EXPUNGE
251 url.setPath( mFolder->imapPath() + TQString::fromLatin1(";UID=*") );
252
253 TDEIO::SimpleJob *job = TDEIO::file_delete( url, false );
254 TDEIO::Scheduler::assignJobToSlave( mAccount->slave(), job );
255 ImapAccountBase::jobData jd( url.url(), mFolder->folder() );
256 mAccount->insertJob( job, jd );
257 connect( job, TQ_SIGNAL( result(TDEIO::Job *) ),
258 this, TQ_SLOT( slotExpungeResult(TDEIO::Job *) ) );
259}
260
261void CachedImapJob::slotExpungeResult( TDEIO::Job * job )
262{
263 KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
264 if ( it == mAccount->jobsEnd() ) { // Shouldn't happen
265 delete this;
266 return;
267 }
268
269 if (job->error()) {
270 mErrorCode = job->error();
271 mAccount->handleJobError( job, i18n( "Error while deleting messages on the server: " ) + '\n' );
272 }
273 else
274 mAccount->removeJob(it);
275
276 delete this;
277}
278
279void CachedImapJob::slotGetNextMessage(TDEIO::Job * job)
280{
281 if (job) {
282 KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
283 if ( it == mAccount->jobsEnd() ) { // Shouldn't happen
284 delete this;
285 return;
286 }
287
288 if (job->error()) {
289 mErrorCode = job->error();
290 mAccount->handleJobError( job, i18n( "Error while retrieving message on the server: " ) + '\n' );
291 delete this;
292 return;
293 }
294
295 ulong size = 0;
296 if ((*it).data.size() > 0) {
297 ulong uid = mMsg->UID();
298 size = mMsg->msgSizeServer();
299
300 // Convert CR/LF to LF.
301 size_t dataSize = (*it).data.size();
302 dataSize = Util::crlf2lf( (*it).data.data(), dataSize ); // always <=
303 (*it).data.resize( dataSize );
304
305 mMsg->setComplete( true );
306 mMsg->fromByteArray( (*it).data );
307 mMsg->setUID(uid);
308 mMsg->setMsgSizeServer(size);
309 mMsg->setTransferInProgress( false );
310 int index = 0;
311 mFolder->addMsgInternal( mMsg, true, &index );
312
313 if ( kmkernel->iCalIface().isResourceFolder( mFolder->folder() ) ) {
314 mFolder->setStatus( index, KMMsgStatusRead, false );
315 }
316
317 emit messageRetrieved( mMsg );
318 if ( index > 0 ) mFolder->unGetMsg( index );
319 } else {
320 emit messageRetrieved( 0 );
321 }
322 mMsg = 0;
323
324 mSentBytes += size;
325 emit progress( mSentBytes, mTotalBytes );
326 mAccount->removeJob(it);
327 } else
328 mFolder->quiet( true );
329
330 if( mMsgsForDownload.isEmpty() ) {
331 mFolder->quiet( false );
332 delete this;
333 return;
334 }
335
336 MsgForDownload mfd = mMsgsForDownload.front(); mMsgsForDownload.pop_front();
337
338 mMsg = new KMMessage;
339 mMsg->setUID(mfd.uid);
340 mMsg->setMsgSizeServer(mfd.size);
341 if( mfd.flags > 0 )
342 KMFolderImap::flagsToStatus(mMsg, mfd.flags, true, GlobalSettings::allowLocalFlags() ? mFolder->permanentFlags() : INT_MAX);
343 KURL url = mAccount->getUrl();
344 url.setPath(mFolder->imapPath() + TQString(";UID=%1;SECTION=BODY.PEEK[]").arg(mfd.uid));
345
346 ImapAccountBase::jobData jd( url.url(), mFolder->folder() );
347 jd.cancellable = true;
348 mMsg->setTransferInProgress(true);
349 TDEIO::SimpleJob *simpleJob = TDEIO::get(url, false, false);
350 TDEIO::Scheduler::assignJobToSlave(mAccount->slave(), simpleJob);
351 mAccount->insertJob(simpleJob, jd);
352 connect(simpleJob, TQ_SIGNAL(processedSize(TDEIO::Job *, TDEIO::filesize_t)),
353 this, TQ_SLOT(slotProcessedSize(TDEIO::Job *, TDEIO::filesize_t)));
354 connect(simpleJob, TQ_SIGNAL(result(TDEIO::Job *)),
355 this, TQ_SLOT(slotGetNextMessage(TDEIO::Job *)));
356 connect(simpleJob, TQ_SIGNAL(data(TDEIO::Job *, const TQByteArray &)),
357 mFolder, TQ_SLOT(slotSimpleData(TDEIO::Job *, const TQByteArray &)));
358}
359
360void CachedImapJob::slotProcessedSize(TDEIO::Job *, TDEIO::filesize_t processed)
361{
362 emit progress( mSentBytes + processed, mTotalBytes );
363}
364
365void CachedImapJob::slotPutNextMessage()
366{
367 mMsg = 0;
368
369 // First try the message list
370 if( !mMsgList.isEmpty() ) {
371 mMsg = mMsgList.first();
372 mMsgList.removeFirst();
373 }
374
375 // Now try the serial number list
376 while( mMsg == 0 && !mSerNumMsgList.isEmpty() ) {
377 unsigned long serNum = mSerNumMsgList.first();
378 mSerNumMsgList.pop_front();
379
380 // Find the message with this serial number
381 int i = 0;
382 KMFolder* aFolder = 0;
383 KMMsgDict::instance()->getLocation( serNum, &aFolder, &i );
384 if( mFolder->folder() != aFolder )
385 // This message was moved or something
386 continue;
387 mMsg = mFolder->getMsg( i );
388 }
389
390 if( !mMsg ) {
391 // No message found for upload
392 delete this;
393 return;
394 }
395
396 KURL url = mAccount->getUrl();
397 TQString flags = KMFolderImap::statusToFlags( mMsg->status(), mFolder->permanentFlags() );
398 url.setPath( mFolder->imapPath() + ";SECTION=" + flags );
399
400 ImapAccountBase::jobData jd( url.url(), mFolder->folder() );
401
402 mMsg->setUID( 0 ); // for the index
403 TQCString cstr(mMsg->asString());
404 int a = cstr.find("\nX-UID: ");
405 int b = cstr.find('\n', a);
406 if (a != -1 && b != -1 && cstr.find("\n\n") > a) cstr.remove(a, b-a);
407 TQCString mData(cstr.length() + cstr.contains('\n'));
408 unsigned int i = 0;
409 for( char *ch = cstr.data(); *ch; ch++ ) {
410 if ( *ch == '\n' ) {
411 mData.at(i) = '\r';
412 i++;
413 }
414 mData.at(i) = *ch; i++;
415 }
416 jd.data = mData;
417 jd.msgList.append( mMsg );
418
419 mMsg->setTransferInProgress(true);
420 TDEIO::SimpleJob *simpleJob = TDEIO::put(url, 0, false, false, false);
421 TDEIO::Scheduler::assignJobToSlave(mAccount->slave(), simpleJob);
422 mAccount->insertJob(simpleJob, jd);
423 connect( simpleJob, TQ_SIGNAL( result(TDEIO::Job *) ),
424 TQ_SLOT( slotPutMessageResult(TDEIO::Job *) ) );
425 connect( simpleJob, TQ_SIGNAL( dataReq(TDEIO::Job *, TQByteArray &) ),
426 TQ_SLOT( slotPutMessageDataReq(TDEIO::Job *, TQByteArray &) ) );
427 connect( simpleJob, TQ_SIGNAL( data(TDEIO::Job *, const TQByteArray &) ),
428 mFolder, TQ_SLOT( slotSimpleData(TDEIO::Job *, const TQByteArray &) ) );
429 connect( simpleJob, TQ_SIGNAL(infoMessage(TDEIO::Job *, const TQString &)),
430 TQ_SLOT(slotPutMessageInfoData(TDEIO::Job *, const TQString &)) );
431
432}
433
434//-----------------------------------------------------------------------------
435// TODO: port to TDEIO::StoredTransferJob once it's ok to require tdelibs-3.3
436void CachedImapJob::slotPutMessageDataReq(TDEIO::Job *job, TQByteArray &data)
437{
438 KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
439 if ( it == mAccount->jobsEnd() ) { // Shouldn't happen
440 delete this;
441 return;
442 }
443 if ((*it).data.size() - (*it).offset > 0x8000) {
444 data.duplicate((*it).data.data() + (*it).offset, 0x8000);
445 (*it).offset += 0x8000;
446 } else if ((*it).data.size() - (*it).offset > 0) {
447 data.duplicate((*it).data.data() + (*it).offset,
448 (*it).data.size() - (*it).offset);
449 (*it).offset = (*it).data.size();
450 } else
451 data.resize(0);
452}
453
454//----------------------------------------------------------------------------
455void CachedImapJob::slotPutMessageInfoData( TDEIO::Job *job, const TQString &data )
456{
457 KMFolderCachedImap *imapFolder = static_cast<KMFolderCachedImap*>( mDestFolder->storage() );
458 if ( imapFolder ) {
459 KMAcctCachedImap *account = imapFolder->account();
460 ImapAccountBase::JobIterator it = account->findJob( job );
461 if ( it == account->jobsEnd() ) {
462 return;
463 }
464
465 if ( data.find( "UID" ) != -1 && mMsg ) {
466 int uid = ( data.right( data.length() - 4 ) ).toInt();
467 kdDebug( 5006 ) << k_funcinfo << "Server told us uid is: " << uid << endl;
468 mMsg->setUID( uid );
469 }
470 }
471}
472
473
474//-----------------------------------------------------------------------------
475void CachedImapJob::slotPutMessageResult(TDEIO::Job *job)
476{
477 KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
478 if ( it == mAccount->jobsEnd() ) { // Shouldn't happen
479 delete this;
480 return;
481 }
482
483 if ( job->error() ) {
484 bool cont = mAccount->handlePutError( job, *it, mFolder->folder() );
485 if ( !cont ) {
486 delete this;
487 } else {
488 mMsg = 0;
489 slotPutNextMessage();
490 }
491 return;
492 }
493
494 emit messageStored( mMsg );
495
496 // we abuse those fields, the unit is the number of messages, here
497 ++mSentBytes;
498 emit progress( mSentBytes, mTotalBytes );
499
500 int i;
501 if( ( i = mFolder->find(mMsg) ) != -1 ) {
502 /*
503 * If we have acquired a uid during upload the server supports the uidnext
504 * extension and there is no need to redownload this mail, we already have
505 * it. Otherwise remove it, it will be redownloaded.
506 */
507 if ( mMsg->UID() == 0 ) {
508 mFolder->removeMsg(i);
509 } else {
510 // When removing+readding, no point in telling the imap resources about it
511 bool b = kmkernel->iCalIface().isResourceQuiet();
512 kmkernel->iCalIface().setResourceQuiet( true );
513
514 mFolder->takeTemporarily( i );
515 mFolder->addMsgKeepUID( mMsg );
516 mMsg->setTransferInProgress( false );
517
518 kmkernel->iCalIface().setResourceQuiet( b );
519 }
520 }
521 mMsg = NULL;
522 mAccount->removeJob( it );
523 slotPutNextMessage();
524}
525
526
527void CachedImapJob::slotAddNextSubfolder( TDEIO::Job * job )
528{
529 if (job) {
530 KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
531 if ( it == mAccount->jobsEnd() ) { // Shouldn't happen
532 delete this;
533 return;
534 }
535
536 // make copy of setting, to reset it before potentially destroying 'it'
537 bool silentUpload = static_cast<KMFolderCachedImap*>((*it).parent->storage())->silentUpload();
538 static_cast<KMFolderCachedImap*>((*it).parent->storage())->setSilentUpload( false );
539
540 if ( job->error() && !silentUpload ) {
541 TQString myError = "<p><b>" + i18n("Error while uploading folder")
542 + "</b></p><p>" + i18n("Could not make the folder <b>%1</b> on the server.").arg((*it).items[0])
543 + "</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>";
544 mAccount->handleJobError( job, myError );
545 }
546
547 if( job->error() ) {
548 delete this;
549 return;
550 } else {
551 KMFolderCachedImap* storage = static_cast<KMFolderCachedImap*>( (*it).current->storage() );
552 KMFolderCachedImap* parentStorage = static_cast<KMFolderCachedImap*>( (*it).parent->storage() );
553 Q_ASSERT( storage );
554 Q_ASSERT( parentStorage );
555 if ( storage->imapPath().isEmpty() ) {
556 TQString path = mAccount->createImapPath( parentStorage->imapPath(), storage->folder()->name() );
557 if ( !storage->imapPathForCreation().isEmpty() )
558 path = storage->imapPathForCreation();
559 storage->setImapPath( path );
560 storage->writeConfig();
561 }
562 }
563 mAccount->removeJob( it );
564 }
565
566 if (mFolderList.isEmpty()) {
567 // No more folders to add
568 delete this;
569 return;
570 }
571
572 KMFolderCachedImap *folder = mFolderList.front();
573 mFolderList.pop_front();
574 KURL url = mAccount->getUrl();
575 TQString path = mAccount->createImapPath( mFolder->imapPath(),
576 folder->folder()->name() );
577 if ( !folder->imapPathForCreation().isEmpty() ) {
578 // the folder knows it's namespace
579 path = folder->imapPathForCreation();
580 }
581 url.setPath( path );
582
583 if ( mAccount->groupwareType() != KMAcctCachedImap::GroupwareScalix ) {
584 // Associate the jobData with the parent folder, not with the child
585 // This is necessary in case of an error while creating the subfolder,
586 // so that folderComplete is called on the parent (and the sync resetted).
587 ImapAccountBase::jobData jd( url.url(), mFolder->folder() );
588 jd.items << folder->label(); // for the err msg
589 jd.current = folder->folder();
590 TDEIO::SimpleJob *simpleJob = TDEIO::mkdir(url);
591 TDEIO::Scheduler::assignJobToSlave(mAccount->slave(), simpleJob);
592 mAccount->insertJob(simpleJob, jd);
593 connect( simpleJob, TQ_SIGNAL(result(TDEIO::Job *)),
594 this, TQ_SLOT(slotAddNextSubfolder(TDEIO::Job *)) );
595 } else {
596 TQByteArray packedArgs;
597 TQDataStream stream( packedArgs, IO_WriteOnly );
598
599 const TQString command = TQString( "X-CREATE-SPECIAL" );
600 const TQString argument = TQString( "%1 %2" ).arg( Scalix::Utils::contentsTypeToScalixId( folder->contentsType() ) )
601 .arg( path );
602
603 stream << (int) 'X' << 'N' << command << argument;
604
605 ImapAccountBase::jobData jd( url.url(), mFolder->folder() );
606 jd.items << folder->label(); // for the err msg
607 jd.current = folder->folder();
608 TDEIO::SimpleJob *simpleJob = TDEIO::special( url.url(), packedArgs, false );
609 TDEIO::Scheduler::assignJobToSlave(mAccount->slave(), simpleJob);
610 mAccount->insertJob(simpleJob, jd);
611 connect( simpleJob, TQ_SIGNAL(result(TDEIO::Job *)),
612 this, TQ_SLOT(slotAddNextSubfolder(TDEIO::Job *)) );
613 }
614}
615
616
617void CachedImapJob::slotDeleteNextFolder( TDEIO::Job *job )
618{
619 if (job) {
620 KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
621 if ( it == mAccount->jobsEnd() ) { // Shouldn't happen
622 delete this;
623 return;
624 }
625
626 mAccount->removeDeletedFolder( (*it).path );
627
628 if( job->error() ) {
629 mAccount->handleJobError( job, i18n( "Error while deleting folder %1 on the server: " ).arg( (*it).path ) + '\n' );
630 delete this;
631 return;
632 }
633 mAccount->removeJob(it);
634 }
635
636 if( mFoldersOrMessages.isEmpty() ) {
637 // No more folders to delete
638 delete this;
639 return;
640 }
641
642 TQString folderPath = mFoldersOrMessages.front();
643 mFoldersOrMessages.pop_front();
644 KURL url = mAccount->getUrl();
645 url.setPath(folderPath);
646 ImapAccountBase::jobData jd( url.url(), mFolder->folder() );
647 jd.path = url.path();
648 TDEIO::SimpleJob *simpleJob = TDEIO::file_delete(url, false);
649 TDEIO::Scheduler::assignJobToSlave(mAccount->slave(), simpleJob);
650 mAccount->insertJob(simpleJob, jd);
651 connect( simpleJob, TQ_SIGNAL( result(TDEIO::Job *) ),
652 TQ_SLOT( slotDeleteNextFolder(TDEIO::Job *) ) );
653}
654
655void CachedImapJob::checkUidValidity()
656{
657 KURL url = mAccount->getUrl();
658 url.setPath( mFolder->imapPath() + ";UID=0:0" );
659
660 ImapAccountBase::jobData jd( url.url(), mFolder->folder() );
661 jd.cancellable = true;
662
663 TDEIO::SimpleJob *job = TDEIO::get( url, false, false );
664 TDEIO::Scheduler::assignJobToSlave( mAccount->slave(), job );
665 mAccount->insertJob( job, jd );
666 connect( job, TQ_SIGNAL(result(TDEIO::Job *)),
667 TQ_SLOT(slotCheckUidValidityResult(TDEIO::Job *)) );
668 connect( job, TQ_SIGNAL(data(TDEIO::Job *, const TQByteArray &)),
669 mFolder, TQ_SLOT(slotSimpleData(TDEIO::Job *, const TQByteArray &)));
670}
671
672void CachedImapJob::slotCheckUidValidityResult(TDEIO::Job * job)
673{
674 KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
675 if ( it == mAccount->jobsEnd() ) { // Shouldn't happen
676 delete this;
677 return;
678 }
679
680 if( job->error() ) {
681 mErrorCode = job->error();
682 mAccount->handleJobError( job, i18n( "Error while reading folder %1 on the server: " ).arg( (*it).parent->label() ) + '\n' );
683 delete this;
684 return;
685 }
686
687 // Check the uidValidity
688 TQCString cstr((*it).data.data(), (*it).data.size() + 1);
689 int a = cstr.find("X-uidValidity: ");
690 if (a < 0) {
691 // Something is seriously rotten here!
692 // TODO: Tell the user that he has a problem
693 kdDebug(5006) << "No uidvalidity available for folder "
694 << mFolder->name() << endl;
695 }
696 else {
697 int b = cstr.find("\r\n", a);
698 if ( (b - a - 15) >= 0 ) {
699 TQString uidv = cstr.mid(a + 15, b - a - 15);
700 // kdDebug(5006) << "New uidv = " << uidv << ", old uidv = "
701 // << mFolder->uidValidity() << endl;
702 if( !mFolder->uidValidity().isEmpty() && mFolder->uidValidity() != uidv ) {
703 // kdDebug(5006) << "Expunging the mailbox " << mFolder->name()
704 // << "!" << endl;
705 mFolder->expunge();
706 mFolder->setLastUid( 0 );
707 mFolder->clearUidMap();
708 }
709 } else
710 kdDebug(5006) << "No uidvalidity available for folder "
711 << mFolder->name() << endl;
712 }
713
714 a = cstr.find( "X-PermanentFlags: " );
715 if ( a < 0 ) {
716 kdDebug(5006) << "no PERMANENTFLAGS response? assumming custom flags are not available" << endl;
717 } else {
718 int b = cstr.find( "\r\n", a );
719 if ( (b - a - 18) >= 0 ) {
720 int flags = cstr.mid( a + 18, b - a - 18 ).toInt();
721 emit permanentFlags( flags );
722 } else {
723 kdDebug(5006) << "PERMANENTFLAGS response broken, assumming custom flags are not available" << endl;
724 }
725 }
726
727 mAccount->removeJob(it);
728 delete this;
729}
730
731
732void CachedImapJob::renameFolder( const TQString &newName )
733{
734 mNewName = newName;
735
736 // Set the source URL
737 KURL urlSrc = mAccount->getUrl();
738 mOldImapPath = mFolder->imapPath();
739 urlSrc.setPath( mOldImapPath );
740
741 // Set the destination URL - this is a bit trickier
742 KURL urlDst = mAccount->getUrl();
743 mNewImapPath = mFolder->imapPath();
744 // Destination url = old imappath - oldname + new name
745 mNewImapPath.truncate( mNewImapPath.length() - mFolder->folder()->name().length() - 1);
746 mNewImapPath += newName + '/';
747 urlDst.setPath( mNewImapPath );
748
749 ImapAccountBase::jobData jd( newName, mFolder->folder() );
750 jd.path = mNewImapPath;
751
752 TDEIO::SimpleJob *simpleJob = TDEIO::rename( urlSrc, urlDst, false );
753 TDEIO::Scheduler::assignJobToSlave( mAccount->slave(), simpleJob );
754 mAccount->insertJob( simpleJob, jd );
755 connect( simpleJob, TQ_SIGNAL(result(TDEIO::Job *)),
756 TQ_SLOT(slotRenameFolderResult(TDEIO::Job *)) );
757}
758
759static void renameChildFolders( KMFolderDir* dir, const TQString& oldPath,
760 const TQString& newPath )
761{
762 if( dir ) {
763 KMFolderNode *node = dir->first();
764 while( node ) {
765 if( !node->isDir() ) {
766 KMFolderCachedImap* imapFolder =
767 static_cast<KMFolderCachedImap*>(static_cast<KMFolder*>(node)->storage());
768 if ( !imapFolder->imapPath().isEmpty() )
769 // Only rename folders that have been accepted by the server
770 if( imapFolder->imapPath().find( oldPath ) == 0 ) {
771 TQString p = imapFolder->imapPath();
772 p = p.mid( oldPath.length() );
773 p.prepend( newPath );
774 imapFolder->setImapPath( p );
775 renameChildFolders( imapFolder->folder()->child(), oldPath, newPath );
776 }
777 }
778 node = dir->next();
779 }
780 }
781}
782
783void CachedImapJob::revertLabelChange()
784{
785 TQMap<TQString, KMAcctCachedImap::RenamedFolder>::ConstIterator renit = mAccount->renamedFolders().find( mFolder->imapPath() );
786 Q_ASSERT( renit != mAccount->renamedFolders().end() );
787 if ( renit != mAccount->renamedFolders().end() ) {
788 mFolder->folder()->setLabel( (*renit).mOldLabel );
789 mAccount->removeRenamedFolder( mFolder->imapPath() );
790 kmkernel->dimapFolderMgr()->contentsChanged();
791 }
792}
793
794void CachedImapJob::renameOnDisk()
795{
796 TQString oldName = mFolder->name();
797 TQString oldPath = mFolder->imapPath();
798 mAccount->removeRenamedFolder( oldPath );
799 mFolder->setImapPath( mNewImapPath );
800 mFolder->FolderStorage::rename( mNewName );
801
802 if( oldPath.endsWith( "/" ) ) oldPath.truncate( oldPath.length() -1 );
803 TQString newPath = mFolder->imapPath();
804 if( newPath.endsWith( "/" ) ) newPath.truncate( newPath.length() -1 );
805 renameChildFolders( mFolder->folder()->child(), oldPath, newPath );
806 kmkernel->dimapFolderMgr()->contentsChanged();
807}
808
809void CachedImapJob::slotSubscribtionChange1Failed( const TQString &errorMessage )
810{
811 KMessageBox::sorry( 0, i18n( "Error while trying to subscribe to the renamed folder %1.\n"
812 "Renaming itself was successful, but the renamed folder might disappear "
813 "from the folder list after the next sync since it is unsubscribed on the server.\n"
814 "You can try to manually subscribe to the folder yourself.\n\n"
815 "%2" )
816 .arg( mFolder->label() ).arg( errorMessage ) );
817 delete this;
818}
819
820void CachedImapJob::slotSubscribtionChange2Failed( const TQString &errorMessage )
821{
822 kdWarning(5006) << k_funcinfo << errorMessage << endl;
823 // Ignore this error, not something user-visible anyway
824 delete this;
825}
826
827void CachedImapJob::slotSubscribtionChange1Done( const TQString&, bool )
828{
829 disconnect( mAccount, TQ_SIGNAL( subscriptionChanged( const TQString&, bool ) ),
830 this, TQ_SLOT( slotSubscribtionChange1Done( const TQString&, bool ) ) );
831 connect( mAccount, TQ_SIGNAL( subscriptionChanged( const TQString&, bool ) ),
832 this, TQ_SLOT( slotSubscribtionChange2Done( const TQString&, bool ) ) );
833 disconnect( mAccount, TQ_SIGNAL( subscriptionChangeFailed( const TQString& ) ),
834 this, TQ_SLOT( slotSubscribtionChange1Failed( const TQString& ) ) );
835 connect( mAccount, TQ_SIGNAL( subscriptionChangeFailed( const TQString& ) ),
836 this, TQ_SLOT( slotSubscribtionChange2Failed( const TQString& ) ) );
837
838 mAccount->changeSubscription( false, mOldImapPath, true /* quiet */ );
839}
840
841void CachedImapJob::slotSubscribtionChange2Done( const TQString&, bool )
842{
843 // Finally done with everything!
844 delete this;
845}
846
847void CachedImapJob::slotRenameFolderResult( TDEIO::Job *job )
848{
849 KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
850 if ( it == mAccount->jobsEnd() ) { // Shouldn't happen
851 delete this;
852 return;
853 }
854
855 if( job->error() ) {
856 revertLabelChange();
857 const TQString errorMessage = i18n( "Error while trying to rename folder %1" ).arg( mFolder->label() );
858 mAccount->handleJobError( job, errorMessage );
859 delete this;
860 } else {
861
862 mAccount->removeJob( it );
863 renameOnDisk();
864
865 // Okay, the folder seems to be renamed on the server and on disk.
866 // Now unsubscribe from the old folder name and subscribe to the new folder name,
867 // so that the folder doesn't suddenly disappear after renaming it
868 connect( mAccount, TQ_SIGNAL( subscriptionChangeFailed( const TQString& ) ),
869 this, TQ_SLOT( slotSubscribtionChange1Failed( const TQString& ) ) );
870 connect( mAccount, TQ_SIGNAL( subscriptionChanged( const TQString&, bool ) ),
871 this, TQ_SLOT( slotSubscribtionChange1Done( const TQString&, bool ) ) );
872 mAccount->changeSubscription( true, mNewImapPath, true /* quiet */ );
873 }
874}
875
876void CachedImapJob::slotListMessagesResult( TDEIO::Job * job )
877{
878 KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
879 if ( it == mAccount->jobsEnd() ) { // Shouldn't happen
880 delete this;
881 return;
882 }
883
884 if (job->error()) {
885 mErrorCode = job->error();
886 mAccount->handleJobError( job, i18n( "Error while deleting messages on the server: " ) + '\n' );
887 }
888 else
889 mAccount->removeJob(it);
890
891 delete this;
892}
893
894//-----------------------------------------------------------------------------
895void CachedImapJob::setParentFolder( const KMFolderCachedImap* parent )
896{
897 mParentFolder = const_cast<KMFolderCachedImap*>( parent );
898}
899
900}
901
902#include "cachedimapjob.moc"
KMail list that manages the contents of one directory that may contain folders and/or other directori...
Definition: kmfolderdir.h:16
Mail folder.
Definition: kmfolder.h:69
This is a Mime Message.
Definition: kmmessage.h:68
void getLocation(unsigned long key, KMFolder **retFolder, int *retIndex) const
Returns the folder the message represented by the serial number key is in and the index in that folde...
Definition: kmmsgdict.cpp:319
static const KMMsgDict * instance()
Access the globally unique MessageDict.
Definition: kmmsgdict.cpp:167
folderdiaquotatab.h
Definition: aboutdata.cpp:40