kmail

imapaccountbase.cpp
1/*
2 * imapaccountbase.cpp
3 *
4 * Copyright (c) 2000-2002 Michael Haeckel <haeckel@kde.org>
5 * Copyright (c) 2002 Marc Mutz <mutz@kde.org>
6 *
7 * This file is based on work on pop3 and imap account implementations
8 * by Don Sanders <sanders@kde.org> and Michael Haeckel <haeckel@kde.org>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; version 2 of the License
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 */
23
24#ifdef HAVE_CONFIG_H
25#include <config.h>
26#endif
27
28#include "imapaccountbase.h"
29using KMail::SieveConfig;
30
31#include "accountmanager.h"
33#include "kmfolder.h"
34#include "broadcaststatus.h"
35using KPIM::BroadcastStatus;
36#include "kmmainwin.h"
37#include "kmfolderimap.h"
38#include "kmmainwidget.h"
39#include "kmmainwin.h"
40#include "kmmsgpart.h"
41#include "acljobs.h"
42#include "kmfoldercachedimap.h"
43#include "bodyvisitor.h"
44using KMail::BodyVisitor;
45#include "imapjob.h"
46using KMail::ImapJob;
47#include "protocols.h"
48#include "progressmanager.h"
49using KPIM::ProgressManager;
50#include "kmfoldermgr.h"
51#include "listjob.h"
52
53#include <tdeapplication.h>
54#include <kdebug.h>
55#include <tdeconfig.h>
56#include <tdelocale.h>
57#include <tdemessagebox.h>
58using TDEIO::MetaData;
59#include <tdeio/passdlg.h>
60using TDEIO::PasswordDialog;
61#include <tdeio/scheduler.h>
62#include <tdeio/slave.h>
63#include <mimelib/bodypart.h>
64#include <mimelib/body.h>
65#include <mimelib/headers.h>
66#include <mimelib/message.h>
67//using TDEIO::Scheduler; // use FQN below
68
69#include <tqregexp.h>
70#include <tqstylesheet.h>
71
72namespace KMail {
73
74 static const unsigned short int imapDefaultPort = 143;
75
76 //
77 //
78 // Ctor and Dtor
79 //
80 //
81
82 ImapAccountBase::ImapAccountBase( AccountManager * parent, const TQString & name, uint id )
83 : NetworkAccount( parent, name, id ),
84 mIdleTimer( 0, "mIdleTimer" ),
85 mNoopTimer( 0, "mNoopTimer" ),
86 mTotal( 0 ),
87 mCountUnread( 0 ),
88 mCountLastUnread( 0 ),
89 mAutoExpunge( true ),
90 mHiddenFolders( false ),
91 mOnlySubscribedFolders( false ),
92 mOnlyLocallySubscribedFolders( false ),
93 mLoadOnDemand( true ),
94 mListOnlyOpenFolders( false ),
95 mProgressEnabled( false ),
96 mErrorDialogIsActive( false ),
97 mPasswordDialogIsActive( false ),
98 mACLSupport( true ),
99 mAnnotationSupport( true ),
100 mQuotaSupport( true ),
101 mSlaveConnected( false ),
102 mSlaveConnectionError( false ),
103 mCheckingSingleFolder( false ),
104 mListDirProgressItem( 0 )
105 {
106 mPort = imapDefaultPort;
107 mBodyPartList.setAutoDelete(true);
108 TDEIO::Scheduler::connect(TQ_SIGNAL(slaveError(TDEIO::Slave *, int, const TQString &)),
109 this, TQ_SLOT(slotSchedulerSlaveError(TDEIO::Slave *, int, const TQString &)));
110 TDEIO::Scheduler::connect(TQ_SIGNAL(slaveConnected(TDEIO::Slave *)),
111 this, TQ_SLOT(slotSchedulerSlaveConnected(TDEIO::Slave *)));
112 connect(&mNoopTimer, TQ_SIGNAL(timeout()), TQ_SLOT(slotNoopTimeout()));
113 connect(&mIdleTimer, TQ_SIGNAL(timeout()), TQ_SLOT(slotIdleTimeout()));
114 }
115
116 ImapAccountBase::~ImapAccountBase() {
117 kdWarning( mSlave, 5006 )
118 << "slave should have been destroyed by subclass!" << endl;
119 }
120
121 void ImapAccountBase::init() {
122 mAutoExpunge = true;
123 mHiddenFolders = false;
124 mOnlySubscribedFolders = false;
125 mOnlyLocallySubscribedFolders = false;
126 mLoadOnDemand = true;
127 mListOnlyOpenFolders = false;
128 mProgressEnabled = false;
129 }
130
131 void ImapAccountBase::pseudoAssign( const KMAccount * a ) {
132 NetworkAccount::pseudoAssign( a );
133
134 const ImapAccountBase * i = dynamic_cast<const ImapAccountBase*>( a );
135 if ( !i ) return;
136
137 setAutoExpunge( i->autoExpunge() );
138 setHiddenFolders( i->hiddenFolders() );
139 setOnlySubscribedFolders( i->onlySubscribedFolders() );
140 setOnlyLocallySubscribedFolders( i->onlyLocallySubscribedFolders() );
141 setLoadOnDemand( i->loadOnDemand() );
142 setListOnlyOpenFolders( i->listOnlyOpenFolders() );
143 setNamespaces( i->namespaces() );
144 setNamespaceToDelimiter( i->namespaceToDelimiter() );
145 localBlacklistFromStringList( i->locallyBlacklistedFolders() );
146 }
147
148 unsigned short int ImapAccountBase::defaultPort() const {
149 return imapDefaultPort;
150 }
151
152 TQString ImapAccountBase::protocol() const {
153 return useSSL() ? IMAP_SSL_PROTOCOL : IMAP_PROTOCOL;
154 }
155
156 //
157 //
158 // Getters and Setters
159 //
160 //
161
162 void ImapAccountBase::setAutoExpunge( bool expunge ) {
163 mAutoExpunge = expunge;
164 }
165
166 void ImapAccountBase::setHiddenFolders( bool show ) {
167 mHiddenFolders = show;
168 }
169
170 void ImapAccountBase::setOnlySubscribedFolders( bool show ) {
171 mOnlySubscribedFolders = show;
172 }
173
174 void ImapAccountBase::setOnlyLocallySubscribedFolders( bool show ) {
175 mOnlyLocallySubscribedFolders = show;
176 }
177
178 void ImapAccountBase::setLoadOnDemand( bool load ) {
179 mLoadOnDemand = load;
180 }
181
182 void ImapAccountBase::setListOnlyOpenFolders( bool only ) {
183 mListOnlyOpenFolders = only;
184 }
185
186 //
187 //
188 // read/write config
189 //
190 //
191
192 void ImapAccountBase::readConfig( /*const*/ TDEConfig/*Base*/ & config ) {
193 NetworkAccount::readConfig( config );
194
195 setAutoExpunge( config.readBoolEntry( "auto-expunge", false ) );
196 setHiddenFolders( config.readBoolEntry( "hidden-folders", false ) );
197 setOnlySubscribedFolders( config.readBoolEntry( "subscribed-folders", false ) );
198 setOnlyLocallySubscribedFolders( config.readBoolEntry( "locally-subscribed-folders", false ) );
199 setLoadOnDemand( config.readBoolEntry( "loadondemand", false ) );
200 setListOnlyOpenFolders( config.readBoolEntry( "listOnlyOpenFolders", false ) );
201 mCapabilities = config.readListEntry( "capabilities", TQStringList() );
202 // read namespaces
203 nsMap map;
204 TQStringList list = config.readListEntry( TQString::number( PersonalNS ) );
205 if ( !list.isEmpty() )
206 map[PersonalNS] = list.gres( "\"", "" );
207 list = config.readListEntry( TQString::number( OtherUsersNS ) );
208 if ( !list.isEmpty() )
209 map[OtherUsersNS] = list.gres( "\"", "" );
210 list = config.readListEntry( TQString::number( SharedNS ) );
211 if ( !list.isEmpty() )
212 map[SharedNS] = list.gres( "\"", "" );
213 setNamespaces( map );
214 // read namespace - delimiter
215 namespaceDelim entries = config.entryMap( config.group() );
216 namespaceDelim namespaceToDelimiter;
217 for ( namespaceDelim::ConstIterator it = entries.begin();
218 it != entries.end(); ++it ) {
219 if ( it.key().startsWith( "Namespace:" ) ) {
220 TQString key = it.key().right( it.key().length() - 10 );
221 namespaceToDelimiter[key] = it.data();
222 }
223 }
224 setNamespaceToDelimiter( namespaceToDelimiter );
225 mOldPrefix = config.readEntry( "prefix" );
226 if ( !mOldPrefix.isEmpty() ) {
227 makeConnection();
228 }
229 localBlacklistFromStringList( config.readListEntry( "locallyUnsubscribedFolders" ) );
230 }
231
232 void ImapAccountBase::writeConfig( TDEConfig/*Base*/ & config ) /*const*/ {
233 NetworkAccount::writeConfig( config );
234
235 config.writeEntry( "auto-expunge", autoExpunge() );
236 config.writeEntry( "hidden-folders", hiddenFolders() );
237 config.writeEntry( "subscribed-folders", onlySubscribedFolders() );
238 config.writeEntry( "locally-subscribed-folders", onlyLocallySubscribedFolders() );
239 config.writeEntry( "loadondemand", loadOnDemand() );
240 config.writeEntry( "listOnlyOpenFolders", listOnlyOpenFolders() );
241 config.writeEntry( "capabilities", mCapabilities );
242 TQString data;
243 for ( nsMap::Iterator it = mNamespaces.begin(); it != mNamespaces.end(); ++it ) {
244 if ( !it.data().isEmpty() ) {
245 data = "\"" + it.data().join("\",\"") + "\"";
246 config.writeEntry( TQString::number( it.key() ), data );
247 }
248 }
249 TQString key;
250 for ( namespaceDelim::ConstIterator it = mNamespaceToDelimiter.begin();
251 it != mNamespaceToDelimiter.end(); ++it ) {
252 key = "Namespace:" + it.key();
253 config.writeEntry( key, it.data() );
254 }
255 config.writeEntry( "locallyUnsubscribedFolders", locallyBlacklistedFolders() );
256 }
257
258 //
259 //
260 // Network processing
261 //
262 //
263
264 MetaData ImapAccountBase::slaveConfig() const {
265 MetaData m = NetworkAccount::slaveConfig();
266
267 m.insert( "auth", auth() );
268 if ( autoExpunge() )
269 m.insert( "expunge", "auto" );
270
271 return m;
272 }
273
274 ImapAccountBase::ConnectionState ImapAccountBase::makeConnection()
275 {
276 if ( mSlave && mSlaveConnected ) {
277 return Connected;
278 }
279 if ( mPasswordDialogIsActive ) return Connecting;
280
281 if( mAskAgain || ( ( passwd().isEmpty() || login().isEmpty() ) &&
282 auth() != "GSSAPI" ) ) {
283
284 Q_ASSERT( !mSlave ); // disconnected on 'wrong login' error already, or first try
285 TQString log = login();
286 TQString pass = passwd();
287 // We init "store" to true to indicate that we want to have the
288 // "keep password" checkbox. Then, we set [Passwords]Keep to
289 // storePasswd(), so that the checkbox in the dialog will be
290 // init'ed correctly:
291 TDEConfigGroup passwords( TDEGlobal::config(), "Passwords" );
292 passwords.writeEntry( "Keep", storePasswd() );
293 TQString msg = i18n("You need to supply a username and a password to "
294 "access this mailbox.");
295 mPasswordDialogIsActive = true;
296
297 PasswordDialog dlg( msg, log, true /* store pw */, true, KMKernel::self()->mainWin() );
298 dlg.setPlainCaption( i18n("Authorization Dialog") );
299 dlg.addCommentLine( i18n("Account:"), name() );
300 int ret = dlg.exec();
301 if (ret != TQDialog::Accepted ) {
302 mPasswordDialogIsActive = false;
303 mAskAgain = false;
304 emit connectionResult( TDEIO::ERR_USER_CANCELED, TQString() );
305 return Error;
306 }
307 mPasswordDialogIsActive = false;
308 // The user has been given the chance to change login and
309 // password, so copy both from the dialog:
310 setPasswd( dlg.password(), dlg.keepPassword() );
311 setLogin( dlg.username() );
312 mAskAgain = false;
313 }
314 // already waiting for a connection?
315 if ( mSlave && !mSlaveConnected ) return Connecting;
316
317 mSlaveConnected = false;
318 mSlave = TDEIO::Scheduler::getConnectedSlave( getUrl(), slaveConfig() );
319 if ( !mSlave ) {
320 KMessageBox::error(0, i18n("Could not start process for %1.")
321 .arg( getUrl().protocol() ) );
322 return Error;
323 }
324 if ( mSlave->isConnected() ) {
325 slotSchedulerSlaveConnected( mSlave );
326 return Connected;
327 }
328
329 return Connecting;
330 }
331
332 bool ImapAccountBase::handleJobError( TDEIO::Job *job, const TQString& context, bool abortSync )
333 {
334 JobIterator it = findJob( job );
335 if ( it != jobsEnd() && (*it).progressItem )
336 {
337 (*it).progressItem->setComplete();
338 (*it).progressItem = 0;
339 }
340 return handleError( job->error(), job->errorText(), job, context, abortSync );
341 }
342
343 // Called when we're really all done.
344 void ImapAccountBase::postProcessNewMail( bool showStatusMsg ) {
345 setCheckingMail(false);
346 int newMails = 0;
347 if ( mCountUnread > 0 && mCountUnread > mCountLastUnread ) {
348 newMails = mCountUnread - mCountLastUnread;
349 mCountLastUnread = mCountUnread;
350 mCountUnread = 0;
351 checkDone( true, CheckOK );
352 } else {
353 mCountUnread = 0;
354 checkDone( false, CheckOK );
355 }
356 if ( showStatusMsg )
357 BroadcastStatus::instance()->setStatusMsgTransmissionCompleted(
358 name(), newMails);
359 }
360
361 //-----------------------------------------------------------------------------
362 void ImapAccountBase::changeSubscription( bool subscribe, const TQString& imapPath, bool quiet )
363 {
364 // change the subscription of the folder
365 KURL url = getUrl();
366 url.setPath(imapPath);
367
368 TQByteArray packedArgs;
369 TQDataStream stream( packedArgs, IO_WriteOnly);
370
371 if (subscribe)
372 stream << (int) 'u' << url;
373 else
374 stream << (int) 'U' << url;
375
376 // create the TDEIO-job
377 if ( makeConnection() != Connected )
378 return;// ## doesn't handle Connecting
379 TDEIO::SimpleJob *job = TDEIO::special(url, packedArgs, false);
380 TDEIO::Scheduler::assignJobToSlave(mSlave, job);
381 jobData jd( url.url(), NULL );
382 // a bit of a hack to save one slot
383 if (subscribe) jd.onlySubscribed = true;
384 else jd.onlySubscribed = false;
385 jd.quiet = quiet;
386 insertJob(job, jd);
387
388 connect(job, TQ_SIGNAL(result(TDEIO::Job *)),
389 TQ_SLOT(slotSubscriptionResult(TDEIO::Job *)));
390 }
391
392 //-----------------------------------------------------------------------------
393 void ImapAccountBase::slotSubscriptionResult( TDEIO::Job * job )
394 {
395 // result of a subscription-job
396 JobIterator it = findJob( job );
397 if ( it == jobsEnd() ) return;
398 bool onlySubscribed = (*it).onlySubscribed;
399 TQString path = static_cast<TDEIO::SimpleJob*>(job)->url().path();
400 if (job->error())
401 {
402 if ( !(*it).quiet )
403 handleJobError( job, i18n( "Error while trying to subscribe to %1:" ).arg( path ) + '\n' );
404 emit subscriptionChangeFailed( job->errorString() );
405 // ## emit subscriptionChanged here in case anyone needs it to support continue/cancel
406 }
407 else
408 {
409 emit subscriptionChanged( path, onlySubscribed );
410 if (mSlave) removeJob(job);
411 }
412 }
413
414 //-----------------------------------------------------------------------------
415 // TODO imapPath can be removed once parent can be a KMFolderImapBase or whatever
416 void ImapAccountBase::getUserRights( KMFolder* parent, const TQString& imapPath )
417 {
418 // There isn't much point in asking the server about a user's rights on his own inbox,
419 // it might not be the effective permissions (at least with Cyrus, one can admin his own inbox,
420 // even after a SETACL that removes the admin permissions. Other imap servers apparently
421 // don't even allow removing one's own admin permission, so this code won't hurt either).
422 if ( imapPath == "/INBOX/" ) {
423 if ( parent->folderType() == KMFolderTypeImap )
424 static_cast<KMFolderImap*>( parent->storage() )->setUserRights( ACLJobs::All, ACLJobs::Ok );
425 else if ( parent->folderType() == KMFolderTypeCachedImap )
426 static_cast<KMFolderCachedImap*>( parent->storage() )->setUserRights( ACLJobs::All, ACLJobs::Ok );
427 emit receivedUserRights( parent ); // warning, you need to connect first to get that one
428 return;
429 }
430
431 KURL url = getUrl();
432 url.setPath(imapPath);
433
434 ACLJobs::GetUserRightsJob* job = ACLJobs::getUserRights( mSlave, url );
435
436 jobData jd( url.url(), parent );
437 jd.cancellable = true;
438 insertJob(job, jd);
439
440 connect(job, TQ_SIGNAL(result(TDEIO::Job *)),
441 TQ_SLOT(slotGetUserRightsResult(TDEIO::Job *)));
442 }
443
444 void ImapAccountBase::slotGetUserRightsResult( TDEIO::Job* _job )
445 {
446 ACLJobs::GetUserRightsJob* job = static_cast<ACLJobs::GetUserRightsJob *>( _job );
447 JobIterator it = findJob( job );
448 if ( it == jobsEnd() ) return;
449
450 KMFolder* folder = (*it).parent;
451 if ( job->error() ) {
452 if ( job->error() == TDEIO::ERR_UNSUPPORTED_ACTION ) // that's when the imap server doesn't support ACLs
453 mACLSupport = false;
454 else
455 kdWarning(5006) << "slotGetUserRightsResult: " << job->errorString() << endl;
456 } else {
457#ifndef NDEBUG
458 //kdDebug(5006) << "User Rights: " << ACLJobs::permissionsToString( job->permissions() ) << endl;
459#endif
460 }
461 // Store the permissions
462 if ( folder->folderType() == KMFolderTypeImap )
463 static_cast<KMFolderImap*>( folder->storage() )->setUserRights( job->permissions(),
465 else if ( folder->folderType() == KMFolderTypeCachedImap )
466 static_cast<KMFolderCachedImap*>( folder->storage() )->setUserRights( job->permissions(),
468
469 if (mSlave) removeJob(job);
470 emit receivedUserRights( folder );
471 }
472
473 //-----------------------------------------------------------------------------
474 void ImapAccountBase::getACL( KMFolder* parent, const TQString& imapPath )
475 {
476 KURL url = getUrl();
477 url.setPath(imapPath);
478
479 ACLJobs::GetACLJob* job = ACLJobs::getACL( mSlave, url );
480 jobData jd( url.url(), parent );
481 jd.cancellable = true;
482 insertJob(job, jd);
483
484 connect(job, TQ_SIGNAL(result(TDEIO::Job *)),
485 TQ_SLOT(slotGetACLResult(TDEIO::Job *)));
486 }
487
488 void ImapAccountBase::slotGetACLResult( TDEIO::Job* _job )
489 {
490 ACLJobs::GetACLJob* job = static_cast<ACLJobs::GetACLJob *>( _job );
491 JobIterator it = findJob( job );
492 if ( it == jobsEnd() ) return;
493
494 KMFolder* folder = (*it).parent;
495 emit receivedACL( folder, job, job->entries() );
496 if (mSlave) removeJob(job);
497 }
498
499 //-----------------------------------------------------------------------------
500 // Do not remove imapPath, FolderDiaQuotaTab needs to call this with parent==0.
501 void ImapAccountBase::getStorageQuotaInfo( KMFolder* parent, const TQString& imapPath )
502 {
503 if ( !mSlave ) return;
504 KURL url = getUrl();
505 url.setPath(imapPath);
506
507 QuotaJobs::GetStorageQuotaJob* job = QuotaJobs::getStorageQuota( mSlave, url );
508 jobData jd( url.url(), parent );
509 jd.cancellable = true;
510 insertJob(job, jd);
511
512 connect(job, TQ_SIGNAL(result(TDEIO::Job *)),
513 TQ_SLOT(slotGetStorageQuotaInfoResult(TDEIO::Job *)));
514 }
515
516 void ImapAccountBase::slotGetStorageQuotaInfoResult( TDEIO::Job* _job )
517 {
518 QuotaJobs::GetStorageQuotaJob* job = static_cast<QuotaJobs::GetStorageQuotaJob *>( _job );
519 JobIterator it = findJob( job );
520 if ( it == jobsEnd() ) return;
521 if ( job->error() && job->error() == TDEIO::ERR_UNSUPPORTED_ACTION )
522 setHasNoQuotaSupport();
523
524 KMFolder* folder = (*it).parent; // can be 0
525 emit receivedStorageQuotaInfo( folder, job, job->storageQuotaInfo() );
526 if (mSlave) removeJob(job);
527 }
528
529 void ImapAccountBase::slotNoopTimeout()
530 {
531 if ( mSlave ) {
532 TQByteArray packedArgs;
533 TQDataStream stream( packedArgs, IO_WriteOnly );
534
535 stream << ( int ) 'N';
536
537 TDEIO::SimpleJob *job = TDEIO::special( getUrl(), packedArgs, false );
538 TDEIO::Scheduler::assignJobToSlave(mSlave, job);
539 connect( job, TQ_SIGNAL(result( TDEIO::Job * ) ),
540 this, TQ_SLOT( slotSimpleResult( TDEIO::Job * ) ) );
541 } else {
542 /* Stop the timer, we have disconnected. We have to make sure it is
543 started again when a new slave appears. */
544 mNoopTimer.stop();
545 }
546 }
547
548 void ImapAccountBase::slotIdleTimeout()
549 {
550 if ( mSlave ) {
551 TDEIO::Scheduler::disconnectSlave(mSlave);
552 mSlave = 0;
553 mSlaveConnected = false;
554 /* As for the noop timer, we need to make sure this one is started
555 again when a new slave goes up. */
556 mIdleTimer.stop();
557 }
558 }
559
560 void ImapAccountBase::slotAbortRequested( KPIM::ProgressItem* item )
561 {
562 if ( item )
563 item->setComplete();
564 killAllJobs();
565 }
566
567
568 //-----------------------------------------------------------------------------
569 void ImapAccountBase::slotSchedulerSlaveError(TDEIO::Slave *aSlave, int errorCode,
570 const TQString &errorMsg)
571 {
572 if (aSlave != mSlave) return;
573 handleError( errorCode, errorMsg, 0, TQString(), true );
574 if ( mAskAgain )
575 if ( makeConnection() != ImapAccountBase::Error )
576 return;
577
578 if ( !mSlaveConnected ) {
579 mSlaveConnectionError = true;
580 resetConnectionList( this );
581 if ( mSlave )
582 {
583 TDEIO::Scheduler::disconnectSlave( slave() );
584 mSlave = 0;
585 }
586 }
587 emit connectionResult( errorCode, errorMsg );
588 }
589
590 //-----------------------------------------------------------------------------
591 void ImapAccountBase::slotSchedulerSlaveConnected(TDEIO::Slave *aSlave)
592 {
593 if (aSlave != mSlave) return;
594 mSlaveConnected = true;
595 mNoopTimer.start( 60000 ); // make sure we start sending noops
596 emit connectionResult( 0, TQString() ); // success
597
598 if ( mNamespaces.isEmpty() || mNamespaceToDelimiter.isEmpty() ) {
599 connect( this, TQ_SIGNAL( namespacesFetched( const ImapAccountBase::nsDelimMap& ) ),
600 this, TQ_SLOT( slotSaveNamespaces( const ImapAccountBase::nsDelimMap& ) ) );
601 getNamespaces();
602 }
603
604 // get capabilities
605 TQByteArray packedArgs;
606 TQDataStream stream( packedArgs, IO_WriteOnly);
607 stream << (int) 'c';
608 TDEIO::SimpleJob *job = TDEIO::special( getUrl(), packedArgs, false );
609 TDEIO::Scheduler::assignJobToSlave( mSlave, job );
610 connect( job, TQ_SIGNAL(infoMessage(TDEIO::Job*, const TQString&)),
611 TQ_SLOT(slotCapabilitiesResult(TDEIO::Job*, const TQString&)) );
612 }
613
614 //-----------------------------------------------------------------------------
615 void ImapAccountBase::slotCapabilitiesResult( TDEIO::Job*, const TQString& result )
616 {
617 mCapabilities = TQStringList::split(' ', result.lower() );
618 kdDebug(5006) << "capabilities:" << mCapabilities << endl;
619 }
620
621 //-----------------------------------------------------------------------------
622 void ImapAccountBase::getNamespaces()
623 {
624 disconnect( this, TQ_SIGNAL( connectionResult(int, const TQString&) ),
625 this, TQ_SLOT( getNamespaces() ) );
626 if ( makeConnection() != Connected || !mSlave ) {
627 kdDebug(5006) << "getNamespaces - wait for connection" << endl;
628 if ( mNamespaces.isEmpty() || mNamespaceToDelimiter.isEmpty() ) {
629 // when the connection is established slotSchedulerSlaveConnected notifies us
630 } else {
631 // getNamespaces was called by someone else
632 connect( this, TQ_SIGNAL( connectionResult(int, const TQString&) ),
633 this, TQ_SLOT( getNamespaces() ) );
634 }
635 return;
636 }
637
638 TQByteArray packedArgs;
639 TQDataStream stream( packedArgs, IO_WriteOnly);
640 stream << (int) 'n';
641 jobData jd;
642 jd.total = 1; jd.done = 0; jd.cancellable = true;
643 jd.progressItem = ProgressManager::createProgressItem(
644 ProgressManager::getUniqueID(),
645 i18n("Retrieving Namespaces"),
646 TQString(), true, useSSL() || useTLS() );
647 jd.progressItem->setTotalItems( 1 );
648 connect ( jd.progressItem,
649 TQ_SIGNAL( progressItemCanceled( KPIM::ProgressItem* ) ),
650 this,
651 TQ_SLOT( slotAbortRequested( KPIM::ProgressItem* ) ) );
652 TDEIO::SimpleJob *job = TDEIO::special( getUrl(), packedArgs, false );
653 TDEIO::Scheduler::assignJobToSlave( mSlave, job );
654 insertJob( job, jd );
655 connect( job, TQ_SIGNAL( infoMessage(TDEIO::Job*, const TQString&) ),
656 TQ_SLOT( slotNamespaceResult(TDEIO::Job*, const TQString&) ) );
657 }
658
659 //-----------------------------------------------------------------------------
660 void ImapAccountBase::slotNamespaceResult( TDEIO::Job* job, const TQString& str )
661 {
662 JobIterator it = findJob( job );
663 if ( it == jobsEnd() ) return;
664
665 nsDelimMap map;
666 namespaceDelim nsDelim;
667 TQStringList ns = TQStringList::split( ",", str );
668 for ( TQStringList::Iterator it = ns.begin(); it != ns.end(); ++it ) {
669 // split, allow empty parts as we can get empty namespaces
670 TQStringList parts = TQStringList::split( "=", *it, true );
671 imapNamespace section = imapNamespace( parts[0].toInt() );
672 if ( map.contains( section ) ) {
673 nsDelim = map[section];
674 } else {
675 nsDelim.clear();
676 }
677 // map namespace to delimiter
678 nsDelim[parts[1]] = parts[2];
679 map[section] = nsDelim;
680 }
681 removeJob(it);
682
683 kdDebug(5006) << "namespaces fetched" << endl;
684 emit namespacesFetched( map );
685 }
686
687 //-----------------------------------------------------------------------------
688 void ImapAccountBase::slotSaveNamespaces( const ImapAccountBase::nsDelimMap& map )
689 {
690 kdDebug(5006) << "slotSaveNamespaces " << name() << endl;
691 // extract the needed information
692 mNamespaces.clear();
693 mNamespaceToDelimiter.clear();
694 for ( uint i = 0; i < 3; ++i ) {
695 imapNamespace section = imapNamespace( i );
696 namespaceDelim ns = map[ section ];
697 namespaceDelim::ConstIterator it;
698 TQStringList list;
699 for ( it = ns.begin(); it != ns.end(); ++it ) {
700 list += it.key();
701 mNamespaceToDelimiter[ it.key() ] = it.data();
702 }
703 if ( !list.isEmpty() ) {
704 mNamespaces[section] = list;
705 }
706 }
707 // see if we need to migrate an old prefix
708 if ( !mOldPrefix.isEmpty() ) {
709 migratePrefix();
710 }
711 emit namespacesFetched();
712 }
713
714 //-----------------------------------------------------------------------------
715 void ImapAccountBase::migratePrefix()
716 {
717 if ( !mOldPrefix.isEmpty() && mOldPrefix != "/" ) {
718 // strip /
719 if ( mOldPrefix.startsWith("/") ) {
720 mOldPrefix = mOldPrefix.right( mOldPrefix.length()-1 );
721 }
722 if ( mOldPrefix.endsWith("/") ) {
723 mOldPrefix = mOldPrefix.left( mOldPrefix.length()-1 );
724 }
725 TQStringList list = mNamespaces[PersonalNS];
726 bool done = false;
727 for ( TQStringList::Iterator it = list.begin(); it != list.end(); ++it ) {
728 if ( (*it).startsWith( mOldPrefix ) ) {
729 // should be ok
730 done = true;
731 kdDebug(5006) << "migratePrefix - no migration needed" << endl;
732 break;
733 }
734 }
735 if ( !done ) {
736 TQString msg = i18n("KMail has detected a prefix entry in the "
737 "configuration of the account \"%1\" which is obsolete with the "
738 "support of IMAP namespaces.").arg( name() );
739 if ( list.contains( "" ) ) {
740 // replace empty entry with the old prefix
741 list.remove( "" );
742 list += mOldPrefix;
743 mNamespaces[PersonalNS] = list;
744 if ( mNamespaceToDelimiter.contains( "" ) ) {
745 TQString delim = mNamespaceToDelimiter[""];
746 mNamespaceToDelimiter.remove( "" );
747 mNamespaceToDelimiter[mOldPrefix] = delim;
748 }
749 kdDebug(5006) << "migratePrefix - replaced empty with " << mOldPrefix << endl;
750 msg += i18n("The configuration was automatically migrated but you should check "
751 "your account configuration.");
752 } else if ( list.count() == 1 ) {
753 // only one entry in the personal namespace so replace it
754 TQString old = list.first();
755 list.clear();
756 list += mOldPrefix;
757 mNamespaces[PersonalNS] = list;
758 if ( mNamespaceToDelimiter.contains( old ) ) {
759 TQString delim = mNamespaceToDelimiter[old];
760 mNamespaceToDelimiter.remove( old );
761 mNamespaceToDelimiter[mOldPrefix] = delim;
762 }
763 kdDebug(5006) << "migratePrefix - replaced single with " << mOldPrefix << endl;
764 msg += i18n("The configuration was automatically migrated but you should check "
765 "your account configuration.");
766 } else {
767 kdDebug(5006) << "migratePrefix - migration failed" << endl;
768 msg += i18n("It was not possible to migrate your configuration automatically "
769 "so please check your account configuration.");
770 }
771 KMessageBox::information( kmkernel->getKMMainWidget(), msg );
772 }
773 } else
774 {
775 kdDebug(5006) << "migratePrefix - no migration needed" << endl;
776 }
777 mOldPrefix = "";
778 }
779
780 //-----------------------------------------------------------------------------
781 TQString ImapAccountBase::namespaceForFolder( FolderStorage* storage )
782 {
783 TQString path;
784 if ( storage->folderType() == KMFolderTypeImap ) {
785 path = static_cast<KMFolderImap*>( storage )->imapPath();
786 } else if ( storage->folderType() == KMFolderTypeCachedImap ) {
787 path = static_cast<KMFolderCachedImap*>( storage )->imapPath();
788 }
789
790 nsMap::Iterator it;
791 for ( it = mNamespaces.begin(); it != mNamespaces.end(); ++it )
792 {
793 TQStringList::Iterator strit;
794 for ( strit = it.data().begin(); strit != it.data().end(); ++strit )
795 {
796 TQString ns = *strit;
797 if ( ns.endsWith("/") || ns.endsWith(".") ) {
798 // strip delimiter for the comparison
799 ns = ns.left( ns.length()-1 );
800 }
801 // first ignore an empty prefix as it would match always
802 if ( !ns.isEmpty() && path.find( ns ) != -1 ) {
803 return (*strit);
804 }
805 }
806 }
807 return TQString();
808 }
809
810 //-----------------------------------------------------------------------------
811 TQString ImapAccountBase::delimiterForNamespace( const TQString& prefix )
812 {
813 //kdDebug(5006) << "delimiterForNamespace " << prefix << endl;
814 // try to match exactly
815 if ( mNamespaceToDelimiter.contains(prefix) ) {
816 return mNamespaceToDelimiter[prefix];
817 }
818
819 // then try if the prefix is part of a namespace
820 // exclude empty namespace
821 for ( namespaceDelim::ConstIterator it = mNamespaceToDelimiter.begin();
822 it != mNamespaceToDelimiter.end(); ++it ) {
823 // the namespace definition sometimes contains the delimiter
824 // make sure we also match this version
825 TQString stripped = it.key().left( it.key().length() - 1 );
826 if ( !it.key().isEmpty() &&
827 ( prefix.contains( it.key() ) || prefix.contains( stripped ) ) ) {
828 return it.data();
829 }
830 }
831 // see if we have an empty namespace
832 // this should always be the case
833 if ( mNamespaceToDelimiter.contains( "" ) ) {
834 return mNamespaceToDelimiter[""];
835 }
836 // well, we tried
837 //kdDebug(5006) << "delimiterForNamespace - not found" << endl;
838 return TQString();
839 }
840
841 //-----------------------------------------------------------------------------
842 TQString ImapAccountBase::delimiterForFolder( FolderStorage* storage )
843 {
844 TQString prefix = namespaceForFolder( storage );
845 TQString delim = delimiterForNamespace( prefix );
846 return delim;
847 }
848
849 //-----------------------------------------------------------------------------
850 void ImapAccountBase::slotSimpleResult(TDEIO::Job * job)
851 {
852 JobIterator it = findJob( job );
853 bool quiet = false;
854 if (it != mapJobData.end()) {
855 quiet = (*it).quiet;
856 if ( !(job->error() && !quiet) ) // the error handler removes in that case
857 removeJob(it);
858 }
859 if (job->error()) {
860 if (!quiet)
861 handleJobError(job, TQString() );
862 else {
863 if ( job->error() == TDEIO::ERR_CONNECTION_BROKEN && slave() ) {
864 // make sure ERR_CONNECTION_BROKEN is properly handled and the slave
865 // disconnected even when quiet()
866 TDEIO::Scheduler::disconnectSlave( slave() );
867 mSlave = 0;
868 }
869 if (job->error() == TDEIO::ERR_SLAVE_DIED)
870 slaveDied();
871 }
872 }
873 }
874
875 //-----------------------------------------------------------------------------
876 bool ImapAccountBase::handlePutError( TDEIO::Job* job, jobData& jd, KMFolder* folder )
877 {
878 Q_ASSERT( !jd.msgList.isEmpty() );
879 KMMessage* msg = jd.msgList.first();
880 // Use double-quotes around the subject to keep the sentence readable,
881 // but don't use double quotes around the sender since from() might return a double-quoted name already
882 const TQString subject = msg->subject().isEmpty() ? i18n( "<unknown>" ) : TQString("\"%1\"").arg( msg->subject() );
883 const TQString from = msg->from().isEmpty() ? i18n( "<unknown>" ) : msg->from();
884 TQString myError = "<p><b>" + i18n("Error while uploading message")
885 + "</b></p><p>"
886 + i18n("Could not upload the message dated %1 from <i>%2</i> with subject <i>%3</i> to the server.").arg( msg->dateStr(), TQStyleSheet::escape( from ), TQStyleSheet::escape( subject ) )
887 + "</p><p>"
888 + i18n("The destination folder was: <b>%1</b>.").arg( TQStyleSheet::escape( folder->prettyURL() ) )
889 + "</p><p>"
890 + i18n("The server reported:") + "</p>";
891 return handleJobError( job, myError );
892 }
893
894 TQString ImapAccountBase::prettifyQuotaError( const TQString& _error, TDEIO::Job * job )
895 {
896 TQString error = _error;
897 if ( error.find( "quota", 0, false ) == -1 ) return error;
898 // this is a quota error, prettify it a bit
899 JobIterator it = findJob( job );
900 TQString quotaAsString( i18n("No detailed quota information available.") );
901 bool readOnly = false;
902 if (it != mapJobData.end()) {
903 const KMFolder * const folder = (*it).parent;
904 if( !folder ) return _error;
905 const KMFolderCachedImap * const imap = dynamic_cast<const KMFolderCachedImap*>( folder->storage() );
906 if ( imap ) {
907 quotaAsString = imap->quotaInfo().toString();
908 }
909 readOnly = folder->isReadOnly();
910 }
911 error = i18n("The folder is too close to its quota limit. (%1)").arg( quotaAsString );
912 if ( readOnly ) {
913 error += i18n("\nSince you do not have write privileges on this folder, "
914 "please ask the owner of the folder to free up some space in it.");
915 }
916 return error;
917 }
918
919 //-----------------------------------------------------------------------------
920 bool ImapAccountBase::handleError( int errorCode, const TQString &errorMsg, TDEIO::Job* job, const TQString& context, bool abortSync )
921 {
922 // Copy job's data before a possible killAllJobs
923 TQStringList errors;
924 if ( job && job->error() != TDEIO::ERR_SLAVE_DEFINED /*workaround for tdelibs-3.2*/)
925 errors = job->detailedErrorStrings();
926
927 bool jobsKilled = true;
928 switch( errorCode ) {
929 case TDEIO::ERR_SLAVE_DIED: slaveDied(); killAllJobs( true ); break;
930 case TDEIO::ERR_COULD_NOT_AUTHENTICATE: // bad password
931 mAskAgain = true;
932 // fallthrough intended
933 case TDEIO::ERR_CONNECTION_BROKEN:
934 case TDEIO::ERR_COULD_NOT_CONNECT:
935 case TDEIO::ERR_SERVER_TIMEOUT:
936 // These mean that we'll have to reconnect on the next attempt, so disconnect and set mSlave to 0.
937 killAllJobs( true );
938 break;
939 case TDEIO::ERR_COULD_NOT_LOGIN:
940 case TDEIO::ERR_USER_CANCELED:
941 killAllJobs( false );
942 break;
943 default:
944 if ( abortSync )
945 killAllJobs( false );
946 else
947 jobsKilled = false;
948 break;
949 }
950
951 // check if we still display an error
952 if ( !mErrorDialogIsActive && errorCode != TDEIO::ERR_USER_CANCELED ) {
953 mErrorDialogIsActive = true;
954 TQString msg = context + '\n' + prettifyQuotaError( TDEIO::buildErrorString( errorCode, errorMsg ), job );
955 TQString caption = i18n("Error");
956
957 if ( jobsKilled || errorCode == TDEIO::ERR_COULD_NOT_LOGIN ) {
958 if ( errorCode == TDEIO::ERR_SERVER_TIMEOUT || errorCode == TDEIO::ERR_CONNECTION_BROKEN ) {
959 msg = i18n("The connection to the server %1 was unexpectedly closed or timed out. It will be re-established automatically if possible.").
960 arg( name() );
961 KMessageBox::information( tdeApp->activeWindow(), msg, caption, "kmailConnectionBrokenErrorDialog" );
962 // Show it in the status bar, in case the user has ticked "don't show again"
963 if ( errorCode == TDEIO::ERR_CONNECTION_BROKEN )
964 KPIM::BroadcastStatus::instance()->setStatusMsg(
965 i18n( "The connection to account %1 was broken." ).arg( name() ) );
966 else if ( errorCode == TDEIO::ERR_SERVER_TIMEOUT )
967 KPIM::BroadcastStatus::instance()->setStatusMsg(
968 i18n( "The connection to account %1 timed out." ).arg( name() ) );
969 } else {
970 if ( !errors.isEmpty() )
971 KMessageBox::detailedError( tdeApp->activeWindow(), msg, errors.join("\n").prepend("<qt>"), caption );
972 else
973 KMessageBox::error( tdeApp->activeWindow(), msg, caption );
974 }
975 } else { // i.e. we have a chance to continue, ask the user about it
976 if ( errors.count() >= 3 ) { // there is no detailedWarningContinueCancel... (#86517)
977 TQString error = prettifyQuotaError( errors[1], job );
978 msg = TQString( "<qt>") + context + error + '\n' + errors[2];
979 caption = errors[0];
980 }
981 int ret = KMessageBox::warningContinueCancel( tdeApp->activeWindow(), msg, caption );
982 if ( ret == KMessageBox::Cancel ) {
983 jobsKilled = true;
984 killAllJobs( false );
985 }
986 }
987 mErrorDialogIsActive = false;
988 } else {
989 if ( mErrorDialogIsActive )
990 kdDebug(5006) << "suppressing error:" << errorMsg << endl;
991 }
992 if ( job && !jobsKilled )
993 removeJob( job );
994 return !jobsKilled; // jobsKilled==false -> continue==true
995 }
996
997 //-----------------------------------------------------------------------------
998 void ImapAccountBase::cancelMailCheck()
999 {
1000 TQMap<TDEIO::Job*, jobData>::Iterator it = mapJobData.begin();
1001 while ( it != mapJobData.end() ) {
1002 kdDebug(5006) << "cancelMailCheck: job is cancellable: " << (*it).cancellable << endl;
1003 if ( (*it).cancellable ) {
1004 it.key()->kill();
1005 TQMap<TDEIO::Job*, jobData>::Iterator rmit = it;
1006 ++it;
1007 mapJobData.remove( rmit );
1008 // We killed a job -> this kills the slave
1009 mSlave = 0;
1010 } else
1011 ++it;
1012 }
1013
1014 for( TQPtrListIterator<FolderJob> it( mJobList ); it.current(); ++it ) {
1015 if ( it.current()->isCancellable() ) {
1016 FolderJob* job = it.current();
1017 job->setPassiveDestructor( true );
1018 mJobList.remove( job );
1019 delete job;
1020 } else
1021 ++it;
1022 }
1023 }
1024
1025 //-----------------------------------------------------------------------------
1026 void ImapAccountBase::processNewMailInFolder( KMFolder* folder, FolderListType type /*= Single*/ )
1027 {
1028 if ( mFoldersQueuedForChecking.contains( folder ) )
1029 return;
1030 mFoldersQueuedForChecking.append( folder );
1031 mCheckingSingleFolder = ( type == Single );
1032 if ( checkingMail() )
1033 {
1034 disconnect( this, TQ_SIGNAL( finishedCheck( bool, CheckStatus ) ),
1035 this, TQ_SLOT( slotCheckQueuedFolders() ) );
1036 connect( this, TQ_SIGNAL( finishedCheck( bool, CheckStatus ) ),
1037 this, TQ_SLOT( slotCheckQueuedFolders() ) );
1038 } else {
1039 slotCheckQueuedFolders();
1040 }
1041 }
1042
1043 //-----------------------------------------------------------------------------
1044 void ImapAccountBase::slotCheckQueuedFolders()
1045 {
1046 disconnect( this, TQ_SIGNAL( finishedCheck( bool, CheckStatus ) ),
1047 this, TQ_SLOT( slotCheckQueuedFolders() ) );
1048
1049 TQValueList<TQGuardedPtr<KMFolder> > mSaveList = mMailCheckFolders;
1050 mMailCheckFolders = mFoldersQueuedForChecking;
1051 if ( kmkernel->acctMgr() )
1052 kmkernel->acctMgr()->singleCheckMail(this, true);
1053 mMailCheckFolders = mSaveList;
1054 mFoldersQueuedForChecking.clear();
1055 }
1056
1057 //-----------------------------------------------------------------------------
1058 bool ImapAccountBase::checkingMail( KMFolder *folder )
1059 {
1060 if (checkingMail() && mFoldersQueuedForChecking.contains(folder))
1061 return true;
1062 return false;
1063 }
1064
1065 //-----------------------------------------------------------------------------
1066 void ImapAccountBase::handleBodyStructure( TQDataStream & stream, KMMessage * msg,
1067 const AttachmentStrategy *as )
1068 {
1069 mBodyPartList.clear();
1070 mCurrentMsg = msg;
1071 // first delete old parts as we construct our own
1072 msg->deleteBodyParts();
1073 // make the parts and fill the mBodyPartList
1074 constructParts( stream, 1, 0, 0, msg->asDwMessage() );
1075 if ( mBodyPartList.count() == 1 ) // we directly set the body later, at partsToLoad below
1076 msg->deleteBodyParts();
1077
1078 if ( !as )
1079 {
1080 kdWarning(5006) << k_funcinfo << " - found no attachment strategy!" << endl;
1081 return;
1082 }
1083
1084 // see what parts have to loaded according to attachmentstrategy
1085 BodyVisitor *visitor = BodyVisitorFactory::getVisitor( as );
1086 visitor->visit( mBodyPartList );
1087 TQPtrList<KMMessagePart> parts = visitor->partsToLoad();
1088 delete visitor;
1089 TQPtrListIterator<KMMessagePart> it( parts );
1090 KMMessagePart *part;
1091 int partsToLoad = 0;
1092 // check how many parts we have to load
1093 while ( (part = it.current()) != 0 )
1094 {
1095 ++it;
1096 if ( part->loadPart() )
1097 {
1098 ++partsToLoad;
1099 }
1100 }
1101 // if the only body part is not text, part->loadPart() would return false
1102 // and that part is never loaded, so make sure it loads.
1103 // it seems that TEXT does load the single body part even if it is not text/*
1104 if ( mBodyPartList.count() == 1 && partsToLoad == 0 )
1105 partsToLoad = 1; // this causes the next test to succeed, and loads the whole message
1106
1107 if ( (mBodyPartList.count() * 0.5) < partsToLoad )
1108 {
1109 // more than 50% of the parts have to be loaded anyway so it is faster
1110 // to load the message completely
1111 kdDebug(5006) << "Falling back to normal mode" << endl;
1112 FolderJob *job = msg->parent()->createJob(
1113 msg, FolderJob::tGetMessage, 0, "TEXT" );
1114 job->start();
1115 return;
1116 }
1117 it.toFirst();
1118 while ( (part = it.current()) != 0 )
1119 {
1120 ++it;
1121 kdDebug(5006) << "ImapAccountBase::handleBodyStructure - load " << part->partSpecifier()
1122 << " (" << part->originalContentTypeStr() << ")" << endl;
1123 if ( part->loadHeaders() )
1124 {
1125 kdDebug(5006) << "load HEADER" << endl;
1126 FolderJob *job = msg->parent()->createJob(
1127 msg, FolderJob::tGetMessage, 0, part->partSpecifier()+".MIME" );
1128 job->start();
1129 }
1130 if ( part->loadPart() )
1131 {
1132 kdDebug(5006) << "load Part" << endl;
1133 FolderJob *job = msg->parent()->createJob(
1134 msg, FolderJob::tGetMessage, 0, part->partSpecifier() );
1135 job->start();
1136 }
1137 }
1138 }
1139
1140 //-----------------------------------------------------------------------------
1141 void ImapAccountBase::constructParts( TQDataStream & stream, int count, KMMessagePart* parentKMPart,
1142 DwBodyPart * parent, const DwMessage * dwmsg )
1143 {
1144 int children;
1145 for (int i = 0; i < count; i++)
1146 {
1147 stream >> children;
1148 KMMessagePart* part = new KMMessagePart( stream );
1149 part->setParent( parentKMPart );
1150 mBodyPartList.append( part );
1151 kdDebug(5006) << "ImapAccountBase::constructParts - created id " << part->partSpecifier()
1152 << " of type " << part->originalContentTypeStr() << endl;
1153 DwBodyPart *dwpart = mCurrentMsg->createDWBodyPart( part );
1154
1155 if ( parent )
1156 {
1157 // add to parent body
1158 parent->Body().AddBodyPart( dwpart );
1159 dwpart->Parse();
1160// kdDebug(5006) << "constructed dwpart " << dwpart << ",dwmsg " << dwmsg << ",parent " << parent
1161// << ",dwparts msg " << dwpart->Body().Message() <<",id "<<dwpart->ObjectId() << endl;
1162 } else if ( part->partSpecifier() != "0" &&
1163 !part->partSpecifier().endsWith(".HEADER") )
1164 {
1165 // add to message
1166 dwmsg->Body().AddBodyPart( dwpart );
1167 dwpart->Parse();
1168// kdDebug(5006) << "constructed dwpart " << dwpart << ",dwmsg " << dwmsg << ",parent " << parent
1169// << ",dwparts msg " << dwpart->Body().Message() <<",id "<<dwpart->ObjectId() << endl;
1170 } else
1171 dwpart = 0;
1172
1173 if ( !parentKMPart )
1174 parentKMPart = part;
1175
1176 if (children > 0)
1177 {
1178 DwBodyPart* newparent = dwpart;
1179 const DwMessage* newmsg = dwmsg;
1180 if ( part->originalContentTypeStr() == "MESSAGE/RFC822" && dwpart &&
1181 dwpart->Body().Message() )
1182 {
1183 // set the encapsulated message as the new message
1184 newparent = 0;
1185 newmsg = dwpart->Body().Message();
1186 }
1187 KMMessagePart* newParentKMPart = part;
1188 if ( part->partSpecifier().endsWith(".HEADER") ) // we don't want headers as parent
1189 newParentKMPart = parentKMPart;
1190
1191 constructParts( stream, children, newParentKMPart, newparent, newmsg );
1192 }
1193 }
1194 }
1195
1196 //-----------------------------------------------------------------------------
1197 void ImapAccountBase::setImapStatus( KMFolder* folder, const TQString& path, const TQCString& flags )
1198 {
1199 // set the status on the server, the uids are integrated in the path
1200 kdDebug(5006) << "setImapStatus path=" << path << " to: " << flags << endl;
1201 KURL url = getUrl();
1202 url.setPath(path);
1203
1204 TQByteArray packedArgs;
1205 TQDataStream stream( packedArgs, IO_WriteOnly);
1206
1207 stream << (int) 'S' << url << flags;
1208
1209 if ( makeConnection() != Connected )
1210 return; // can't happen with dimap
1211
1212 TDEIO::SimpleJob *job = TDEIO::special(url, packedArgs, false);
1213 TDEIO::Scheduler::assignJobToSlave(slave(), job);
1214 ImapAccountBase::jobData jd( url.url(), folder );
1215 jd.path = path;
1216 insertJob(job, jd);
1217 connect(job, TQ_SIGNAL(result(TDEIO::Job *)),
1218 TQ_SLOT(slotSetStatusResult(TDEIO::Job *)));
1219 }
1220
1221 void ImapAccountBase::setImapSeenStatus(KMFolder * folder, const TQString & path, bool seen)
1222 {
1223 KURL url = getUrl();
1224 url.setPath(path);
1225
1226 TQByteArray packedArgs;
1227 TQDataStream stream( packedArgs, IO_WriteOnly);
1228
1229 stream << (int) 's' << url << seen;
1230
1231 if ( makeConnection() != Connected )
1232 return; // can't happen with dimap
1233
1234 TDEIO::SimpleJob *job = TDEIO::special(url, packedArgs, false);
1235 TDEIO::Scheduler::assignJobToSlave(slave(), job);
1236 ImapAccountBase::jobData jd( url.url(), folder );
1237 jd.path = path;
1238 insertJob(job, jd);
1239 connect(job, TQ_SIGNAL(result(TDEIO::Job *)),
1240 TQ_SLOT(slotSetStatusResult(TDEIO::Job *)));
1241 }
1242
1243 //-----------------------------------------------------------------------------
1244 void ImapAccountBase::slotSetStatusResult(TDEIO::Job * job)
1245 {
1246 ImapAccountBase::JobIterator it = findJob(job);
1247 if ( it == jobsEnd() ) return;
1248 int errorCode = job->error();
1249 KMFolder * const parent = (*it).parent;
1250 const TQString path = (*it).path;
1251 if (errorCode && errorCode != TDEIO::ERR_CANNOT_OPEN_FOR_WRITING)
1252 {
1253 bool cont = handleJobError( job, i18n( "Error while uploading status of messages to server: " ) + '\n' );
1254 emit imapStatusChanged( parent, path, cont );
1255 }
1256 else
1257 {
1258 emit imapStatusChanged( parent, path, true );
1259 removeJob(it);
1260 }
1261 }
1262
1263 //-----------------------------------------------------------------------------
1264 void ImapAccountBase::setFolder(KMFolder* folder, bool addAccount)
1265 {
1266 if (folder)
1267 {
1268 folder->setSystemLabel(name());
1269 folder->setId(id());
1270 }
1271 NetworkAccount::setFolder(folder, addAccount);
1272 }
1273
1274 //-----------------------------------------------------------------------------
1275 void ImapAccountBase::removeJob( JobIterator& it )
1276 {
1277 if( (*it).progressItem ) {
1278 (*it).progressItem->setComplete();
1279 (*it).progressItem = 0;
1280 }
1281 mapJobData.remove( it );
1282 }
1283
1284 //-----------------------------------------------------------------------------
1285 void KMail::ImapAccountBase::removeJob( TDEIO::Job* job )
1286 {
1287 mapJobData.remove( job );
1288 }
1289
1290 //-----------------------------------------------------------------------------
1291 KPIM::ProgressItem* ImapAccountBase::listDirProgressItem()
1292 {
1293 if ( !mListDirProgressItem )
1294 {
1295 mListDirProgressItem = ProgressManager::createProgressItem(
1296 "ListDir" + name(),
1297 TQStyleSheet::escape( name() ),
1298 i18n("retrieving folders"),
1299 true,
1300 useSSL() || useTLS() );
1301 connect ( mListDirProgressItem,
1302 TQ_SIGNAL( progressItemCanceled( KPIM::ProgressItem* ) ),
1303 this,
1304 TQ_SLOT( slotAbortRequested( KPIM::ProgressItem* ) ) );
1305 // Start with a guessed value of the old folder count plus 5%. As long
1306 // as the list of folders doesn't constantly change, that should be good
1307 // enough.
1308 unsigned int count = folderCount();
1309 mListDirProgressItem->setTotalItems( count + (unsigned int)(count*0.05) );
1310 }
1311 return mListDirProgressItem;
1312 }
1313
1314 //-----------------------------------------------------------------------------
1315 unsigned int ImapAccountBase::folderCount() const
1316 {
1317 if ( !rootFolder() || !rootFolder()->folder() || !rootFolder()->folder()->child() )
1318 return 0;
1319 return kmkernel->imapFolderMgr()->folderCount( rootFolder()->folder()->child() );
1320 }
1321
1322 //------------------------------------------------------------------------------
1323 TQString ImapAccountBase::addPathToNamespace( const TQString& prefix )
1324 {
1325 TQString myPrefix = prefix;
1326 if ( !myPrefix.startsWith( "/" ) ) {
1327 myPrefix = "/" + myPrefix;
1328 }
1329 if ( !myPrefix.endsWith( "/" ) ) {
1330 myPrefix += "/";
1331 }
1332
1333 return myPrefix;
1334 }
1335
1336 //------------------------------------------------------------------------------
1337 bool ImapAccountBase::isNamespaceFolder( TQString& name )
1338 {
1339 TQStringList ns = mNamespaces[OtherUsersNS];
1340 ns += mNamespaces[SharedNS];
1341 ns += mNamespaces[PersonalNS];
1342 TQString nameWithDelimiter;
1343 for ( TQStringList::Iterator it = ns.begin(); it != ns.end(); ++it )
1344 {
1345 nameWithDelimiter = name + delimiterForNamespace( *it );
1346 if ( *it == name || *it == nameWithDelimiter )
1347 return true;
1348 }
1349 return false;
1350 }
1351
1352 //------------------------------------------------------------------------------
1353 ImapAccountBase::nsDelimMap ImapAccountBase::namespacesWithDelimiter()
1354 {
1355 nsDelimMap map;
1356 nsMap::ConstIterator it;
1357 for ( uint i = 0; i < 3; ++i )
1358 {
1359 imapNamespace section = imapNamespace( i );
1360 TQStringList namespaces = mNamespaces[section];
1361 namespaceDelim nsDelim;
1362 TQStringList::Iterator lit;
1363 for ( lit = namespaces.begin(); lit != namespaces.end(); ++lit )
1364 {
1365 nsDelim[*lit] = delimiterForNamespace( *lit );
1366 }
1367 map[section] = nsDelim;
1368 }
1369 return map;
1370 }
1371
1372 //------------------------------------------------------------------------------
1373 TQString ImapAccountBase::createImapPath( const TQString& parent,
1374 const TQString& folderName )
1375 {
1376 kdDebug(5006) << "createImapPath parent="<<parent<<", folderName="<<folderName<<endl;
1377 TQString newName = parent;
1378 // strip / at the end
1379 if ( newName.endsWith("/") ) {
1380 newName = newName.left( newName.length() - 1 );
1381 }
1382 // add correct delimiter
1383 TQString delim = delimiterForNamespace( newName );
1384 // should not happen...
1385 if ( delim.isEmpty() ) {
1386 delim = "/";
1387 }
1388 if ( !newName.isEmpty() &&
1389 !newName.endsWith( delim ) && !folderName.startsWith( delim ) ) {
1390 newName = newName + delim;
1391 }
1392 newName = newName + folderName;
1393 // add / at the end
1394 if ( !newName.endsWith("/") ) {
1395 newName = newName + "/";
1396 }
1397
1398 return newName;
1399 }
1400
1401 //------------------------------------------------------------------------------
1402 TQString ImapAccountBase::createImapPath( FolderStorage* parent,
1403 const TQString& folderName )
1404 {
1405 TQString path;
1406 if ( parent->folderType() == KMFolderTypeImap ) {
1407 path = static_cast<KMFolderImap*>( parent )->imapPath();
1408 } else if ( parent->folderType() == KMFolderTypeCachedImap ) {
1409 path = static_cast<KMFolderCachedImap*>( parent )->imapPath();
1410 } else {
1411 // error
1412 return path;
1413 }
1414
1415 return createImapPath( path, folderName );
1416 }
1417
1418
1419 bool ImapAccountBase::locallySubscribedTo( const TQString& imapPath )
1420 {
1421 return mLocalSubscriptionBlackList.find( imapPath ) == mLocalSubscriptionBlackList.end();
1422 }
1423
1424 void ImapAccountBase::changeLocalSubscription( const TQString& imapPath, bool subscribe )
1425 {
1426 if ( subscribe ) {
1427 // find in blacklist and remove from it
1428 mLocalSubscriptionBlackList.erase( imapPath );
1429 } else {
1430 // blacklist
1431 mLocalSubscriptionBlackList.insert( imapPath );
1432 }
1433 }
1434
1435
1436 TQStringList ImapAccountBase::locallyBlacklistedFolders() const
1437 {
1438 TQStringList list;
1439 std::set<TQString>::const_iterator it = mLocalSubscriptionBlackList.begin();
1440 std::set<TQString>::const_iterator end = mLocalSubscriptionBlackList.end();
1441 for ( ; it != end ; ++it )
1442 list.append( *it );
1443 return list;
1444 }
1445
1446 void ImapAccountBase::localBlacklistFromStringList( const TQStringList &list )
1447 {
1448 for( TQStringList::ConstIterator it = list.constBegin( ); it != list.constEnd( ); ++it )
1449 mLocalSubscriptionBlackList.insert( *it );
1450 }
1451
1452} // namespace KMail
1453
1454#include "imapaccountbase.moc"
The FolderStorage class is the bass class for the storage related aspects of a collection of mail (a ...
Definition: folderstorage.h:80
virtual KMFolderType folderType() const
Returns the type of this folder.
Definition: folderstorage.h:96
Mail folder.
Definition: kmfolder.h:69
virtual TQString prettyURL() const
URL of the node for visualization purposes.
Definition: kmfolder.cpp:593
KMFolderType folderType() const
Returns the type of this folder.
Definition: kmfolder.cpp:233
bool isReadOnly() const
Is the folder read-only?
Definition: kmfolder.cpp:561
static KMKernel * self()
normal control stuff
Definition: kmkernel.h:259
This is a Mime Message.
Definition: kmmessage.h:68
TQString from() const
Get or set the 'From' header field.
Definition: kmmessage.cpp:2015
TQString subject() const
Get or set the 'Subject' header field.
Definition: kmmessage.cpp:2049
void deleteBodyParts()
Delete all body parts.
Definition: kmmessage.cpp:3174
TQString dateStr() const
Get or set the 'Date' header field.
Definition: kmmessage.cpp:1797
The account manager is responsible for creating accounts of various types via the factory method crea...
@ Ok
The user rights/ACL have been fetched from the server sucessfully.
Definition: acljobs.h:66
@ FetchFailed
The attempt to fetch the user rights/ACL from the server failed.
Definition: acljobs.h:67
folderdiaquotatab.h
Definition: aboutdata.cpp:40