00001
00024
#ifdef HAVE_CONFIG_H
00025
#include <config.h>
00026
#endif
00027
00028
#include "imapaccountbase.h"
00029
using KMail::SieveConfig;
00030
00031
#include "kmacctmgr.h"
00032
#include "kmfolder.h"
00033
#include "kmbroadcaststatus.h"
00034
#include "kmmainwin.h"
00035
#include "kmfolderimap.h"
00036
#include "kmmainwidget.h"
00037
#include "kmmainwin.h"
00038
#include "kmmsgpart.h"
00039
#include "bodyvisitor.h"
00040
using KMail::BodyVisitor;
00041
#include "imapjob.h"
00042
using KMail::ImapJob;
00043
00044
#include <kdebug.h>
00045
#include <kconfig.h>
00046
#include <klocale.h>
00047
#include <kmessagebox.h>
00048
using KIO::MetaData;
00049
#include <kio/passdlg.h>
00050
using KIO::PasswordDialog;
00051
#include <kio/scheduler.h>
00052
#include <mimelib/bodypart.h>
00053
#include <mimelib/body.h>
00054
#include <mimelib/headers.h>
00055
#include <mimelib/message.h>
00056
00057
00058
#include <qregexp.h>
00059
00060
namespace KMail {
00061
00062
static const unsigned short int imapDefaultPort = 143;
00063
00064
00065
00066
00067
00068
00069
00070 ImapAccountBase::ImapAccountBase( KMAcctMgr * parent,
const QString & name )
00071 : NetworkAccount( parent, name ),
00072 mPrefix( "/" ),
00073 mTotal( 0 ),
00074 mCountUnread( 0 ),
00075 mCountLastUnread( 0 ),
00076 mCountRemainChecks( 0 ),
00077 mAutoExpunge( true ),
00078 mHiddenFolders( false ),
00079 mOnlySubscribedFolders( false ),
00080 mLoadOnDemand( true ),
00081 mProgressEnabled( false ),
00082 mIdle( true ),
00083 mErrorDialogIsActive( false ),
00084 mPasswordDialogIsActive( false ),
00085 mCreateInbox( false )
00086 {
00087 mPort = imapDefaultPort;
00088 mBodyPartList.setAutoDelete(
true);
00089 KIO::Scheduler::connect(SIGNAL(slaveError(KIO::Slave *,
int,
const QString &)),
00090
this, SLOT(slotSchedulerSlaveError(KIO::Slave *,
int,
const QString &)));
00091 KIO::Scheduler::connect(SIGNAL(slaveConnected(KIO::Slave *)),
00092
this, SLOT(slotSchedulerSlaveConnected(KIO::Slave *)));
00093 }
00094
00095 ImapAccountBase::~ImapAccountBase() {
00096 kdWarning( mSlave, 5006 )
00097 <<
"slave should have been destroyed by subclass!" << endl;
00098 }
00099
00100
void ImapAccountBase::init() {
00101 mPrefix =
'/';
00102 mAutoExpunge =
true;
00103 mHiddenFolders =
false;
00104 mOnlySubscribedFolders =
false;
00105 mLoadOnDemand =
true;
00106 mProgressEnabled =
false;
00107 }
00108
00109
void ImapAccountBase::pseudoAssign(
const KMAccount * a ) {
00110 NetworkAccount::pseudoAssign( a );
00111
00112
const ImapAccountBase * i = dynamic_cast<const ImapAccountBase*>( a );
00113
if ( !i )
return;
00114
00115 setPrefix( i->prefix() );
00116 setAutoExpunge( i->autoExpunge() );
00117 setHiddenFolders( i->hiddenFolders() );
00118 setOnlySubscribedFolders( i->onlySubscribedFolders() );
00119 setLoadOnDemand( i->loadOnDemand() );
00120 }
00121
00122
unsigned short int ImapAccountBase::defaultPort()
const {
00123
return imapDefaultPort;
00124 }
00125
00126 QString ImapAccountBase::protocol()
const {
00127
return useSSL() ?
"imaps" :
"imap";
00128 }
00129
00130
00131
00132
00133
00134
00135
00136
void ImapAccountBase::setPrefix(
const QString & prefix ) {
00137 mPrefix = prefix;
00138 mPrefix.remove( QRegExp(
"[%*\"]" ) );
00139
if ( mPrefix.isEmpty() || mPrefix[0] !=
'/' )
00140 mPrefix.prepend(
'/' );
00141
if ( mPrefix[ mPrefix.length() - 1 ] !=
'/' )
00142 mPrefix +=
'/';
00143
#if 1
00144
setPrefixHook();
00145
#else
00146
if ( mFolder ) mFolder->setImapPath( mPrefix );
00147
#endif
00148
}
00149
00150
void ImapAccountBase::setAutoExpunge(
bool expunge ) {
00151 mAutoExpunge = expunge;
00152 }
00153
00154
void ImapAccountBase::setHiddenFolders(
bool show ) {
00155 mHiddenFolders = show;
00156 }
00157
00158
void ImapAccountBase::setOnlySubscribedFolders(
bool show ) {
00159 mOnlySubscribedFolders = show;
00160 }
00161
00162
void ImapAccountBase::setLoadOnDemand(
bool load ) {
00163 mLoadOnDemand = load;
00164 }
00165
00166
00167
00168
00169
00170
00171
00172
void ImapAccountBase::readConfig( KConfig & config ) {
00173 NetworkAccount::readConfig( config );
00174
00175 setPrefix( config.readEntry(
"prefix",
"/" ) );
00176 setAutoExpunge( config.readBoolEntry(
"auto-expunge",
false ) );
00177 setHiddenFolders( config.readBoolEntry(
"hidden-folders",
false ) );
00178 setOnlySubscribedFolders( config.readBoolEntry(
"subscribed-folders",
false ) );
00179 setLoadOnDemand( config.readBoolEntry(
"loadondemand",
false ) );
00180 }
00181
00182
void ImapAccountBase::writeConfig( KConfig & config ) {
00183 NetworkAccount::writeConfig( config );
00184
00185 config.writeEntry(
"prefix", prefix() );
00186 config.writeEntry(
"auto-expunge", autoExpunge() );
00187 config.writeEntry(
"hidden-folders", hiddenFolders() );
00188 config.writeEntry(
"subscribed-folders", onlySubscribedFolders() );
00189 config.writeEntry(
"loadondemand", loadOnDemand() );
00190 }
00191
00192
00193
00194
00195
00196
00197
00198 MetaData ImapAccountBase::slaveConfig()
const {
00199 MetaData m = NetworkAccount::slaveConfig();
00200
00201 m.insert(
"auth", auth() );
00202
if ( autoExpunge() )
00203 m.insert(
"expunge",
"auto" );
00204
00205
return m;
00206 }
00207
00208 ImapAccountBase::ConnectionState ImapAccountBase::makeConnection() {
00209
if ( mSlave )
return Connected;
00210
00211
if ( mPasswordDialogIsActive )
return Connecting;
00212
if( mAskAgain || passwd().isEmpty() || login().isEmpty() ) {
00213 QString log = login();
00214 QString pass = passwd();
00215
00216
00217
00218
00219
bool store =
true;
00220 KConfigGroup passwords( KGlobal::config(),
"Passwords" );
00221 passwords.writeEntry(
"Keep", storePasswd() );
00222 QString msg = i18n(
"You need to supply a username and a password to "
00223
"access this mailbox.");
00224 mPasswordDialogIsActive =
true;
00225
if ( PasswordDialog::getNameAndPassword( log, pass, &store, msg,
false,
00226 QString::null, name(),
00227 i18n(
"Account:") )
00228 != QDialog::Accepted ) {
00229 checkDone(
false, 0);
00230 mPasswordDialogIsActive =
false;
00231
return Error;
00232 }
00233 mPasswordDialogIsActive =
false;
00234
00235
00236 setPasswd( pass, store );
00237 setLogin( log );
00238 mAskAgain =
false;
00239 }
00240
00241 mSlave = KIO::Scheduler::getConnectedSlave( getUrl(), slaveConfig() );
00242
if ( !mSlave ) {
00243 KMessageBox::error(0, i18n(
"Could not start process for %1.")
00244 .arg( getUrl().protocol() ) );
00245
return Error;
00246 }
00247
00248
return Connecting;
00249 }
00250
00251
void ImapAccountBase::postProcessNewMail(
KMFolder * folder ) {
00252
00253 disconnect( folder, SIGNAL(numUnreadMsgsChanged(
KMFolder*)),
00254
this, SLOT(postProcessNewMail(
KMFolder*)) );
00255
00256 mCountRemainChecks--;
00257
00258
00259 mCountUnread += folder->
countUnread();
00260
if (mCountRemainChecks == 0)
00261 {
00262
00263
KMBroadcastStatus::instance()->
setStatusMsgTransmissionCompleted(
00264 name(), mCountUnread );
00265
if (mCountUnread > 0 && mCountUnread > mCountLastUnread) {
00266 checkDone(
true, mCountUnread);
00267 mCountLastUnread = mCountUnread;
00268 }
else {
00269 checkDone(
false, 0);
00270 }
00271 setCheckingMail(
false);
00272 mCountUnread = 0;
00273 }
00274 }
00275
00276
00277
void ImapAccountBase::displayProgress()
00278 {
00279
if (mProgressEnabled == mapJobData.isEmpty())
00280 {
00281 mProgressEnabled = !mapJobData.isEmpty();
00282
KMBroadcastStatus::instance()->
setStatusProgressEnable(
"I" + mName,
00283 mProgressEnabled );
00284 }
00285 mIdle = FALSE;
00286
if (mapJobData.isEmpty())
00287 mIdleTimer.start(15000);
00288
else
00289 mIdleTimer.stop();
00290
int total = 0, done = 0;
00291
for (QMap<KIO::Job*, jobData>::Iterator it = mapJobData.begin();
00292 it != mapJobData.end(); ++it)
00293 {
00294 total += (*it).total;
00295 done += (*it).done;
00296 }
00297
if (total == 0)
00298 {
00299 mTotal = 0;
00300
return;
00301 }
00302
if (total > mTotal) mTotal = total;
00303 done += mTotal - total;
00304
KMBroadcastStatus::instance()->
setStatusProgressPercent(
"I" + mName,
00305 100*done / mTotal );
00306 }
00307
00308
00309
void ImapAccountBase::listDirectory(QString path,
bool onlySubscribed,
00310
bool secondStep,
KMFolder* parent,
bool reset)
00311 {
00312
if (makeConnection() == Error)
00313
return;
00314
00315 jobData jd;
00316 jd.total = 1; jd.done = 0;
00317
00318
if (reset)
00319 mHasInbox =
false;
00320
00321 jd.inboxOnly = !secondStep && prefix() !=
"/"
00322 && path == prefix() && !mHasInbox;
00323 jd.onlySubscribed = onlySubscribed;
00324
if (parent) jd.parent = parent;
00325
if (!secondStep) mCreateInbox = FALSE;
00326
00327 KURL url = getUrl();
00328 url.setPath(((jd.inboxOnly) ? QString(
"/") : path)
00329 +
";TYPE=" + ((onlySubscribed) ?
"LSUB" :
"LIST"));
00330 mSubfolderNames.clear();
00331 mSubfolderPaths.clear();
00332 mSubfolderMimeTypes.clear();
00333
00334 KIO::SimpleJob *job = KIO::listDir(url, FALSE);
00335 KIO::Scheduler::assignJobToSlave(mSlave, job);
00336 insertJob(job, jd);
00337 connect(job, SIGNAL(result(KIO::Job *)),
00338
this, SLOT(slotListResult(KIO::Job *)));
00339 connect(job, SIGNAL(entries(KIO::Job *,
const KIO::UDSEntryList &)),
00340
this, SLOT(slotListEntries(KIO::Job *,
const KIO::UDSEntryList &)));
00341 }
00342
00343
00344
void ImapAccountBase::slotListEntries(KIO::Job * job,
const KIO::UDSEntryList & uds)
00345 {
00346 JobIterator it = findJob( job );
00347
if ( it == jobsEnd() )
return;
00348 QString name;
00349 KURL url;
00350 QString mimeType;
00351
for (KIO::UDSEntryList::ConstIterator udsIt = uds.begin();
00352 udsIt != uds.end(); udsIt++)
00353 {
00354 mimeType = QString::null;
00355
for (KIO::UDSEntry::ConstIterator eIt = (*udsIt).begin();
00356 eIt != (*udsIt).end(); eIt++)
00357 {
00358
00359
if ((*eIt).m_uds == KIO::UDS_NAME)
00360 name = (*eIt).m_str;
00361
else if ((*eIt).m_uds == KIO::UDS_URL)
00362 url = KURL((*eIt).m_str, 106);
00363
else if ((*eIt).m_uds == KIO::UDS_MIME_TYPE)
00364 mimeType = (*eIt).m_str;
00365 }
00366
if ((mimeType ==
"inode/directory" || mimeType ==
"message/digest"
00367 || mimeType ==
"message/directory")
00368 && name !=
".." && (hiddenFolders() || name.at(0) !=
'.')
00369 && (!(*it).inboxOnly || name.upper() ==
"INBOX"))
00370 {
00371
if (((*it).inboxOnly ||
00372 url.path() ==
"/INBOX/") && name.upper() ==
"INBOX" &&
00373 !mHasInbox)
00374 {
00375
00376 mCreateInbox = TRUE;
00377 }
00378
00379
00380
if (mSubfolderNames.findIndex(name) == -1)
00381 {
00382 mSubfolderNames.append(name);
00383 mSubfolderPaths.append(url.path());
00384 mSubfolderMimeTypes.append(mimeType);
00385 }
00386 }
00387 }
00388 }
00389
00390
00391
void ImapAccountBase::slotListResult(KIO::Job * job)
00392 {
00393 JobIterator it = findJob( job );
00394
if ( it == jobsEnd() )
return;
00395
if (job->error())
00396 {
00397 slotSlaveError( mSlave, job->error(),
00398 job->errorText() );
00399 }
00400
if (!job->error())
00401 {
00402
00403 emit receivedFolders(mSubfolderNames, mSubfolderPaths,
00404 mSubfolderMimeTypes, *it);
00405 }
00406
if (mSlave) removeJob(job);
00407 mSubfolderNames.clear();
00408 mSubfolderPaths.clear();
00409 mSubfolderMimeTypes.clear();
00410 }
00411
00412
00413
void ImapAccountBase::changeSubscription(
bool subscribe, QString imapPath )
00414 {
00415
00416 KURL url = getUrl();
00417 url.setPath(imapPath);
00418
00419 QByteArray packedArgs;
00420 QDataStream stream( packedArgs, IO_WriteOnly);
00421
00422
if (subscribe)
00423 stream << (
int)
'u' << url;
00424
else
00425 stream << (
int)
'U' << url;
00426
00427
00428
if (makeConnection() != Connected)
00429
return;
00430 KIO::SimpleJob *job = KIO::special(url, packedArgs, FALSE);
00431 KIO::Scheduler::assignJobToSlave(mSlave, job);
00432 jobData jd;
00433 jd.total = 1; jd.done = 0; jd.parent = NULL;
00434
00435
if (subscribe) jd.onlySubscribed =
true;
00436
else jd.onlySubscribed =
false;
00437 insertJob(job, jd);
00438
00439 connect(job, SIGNAL(result(KIO::Job *)),
00440 SLOT(slotSubscriptionResult(KIO::Job *)));
00441 }
00442
00443
00444
void ImapAccountBase::slotSubscriptionResult( KIO::Job * job )
00445 {
00446
00447 JobIterator it = findJob( job );
00448
if ( it == jobsEnd() )
return;
00449
if (job->error())
00450 {
00451 slotSlaveError( mSlave, job->error(),
00452 job->errorText() );
00453 }
else {
00454 emit subscriptionChanged(
00455 static_cast<KIO::SimpleJob*>(job)->url().path(), (*it).onlySubscribed );
00456 }
00457
if (mSlave) removeJob(job);
00458 }
00459
00460
00461
void ImapAccountBase::slotSchedulerSlaveError(KIO::Slave *aSlave,
int errorCode,
00462
const QString &errorMsg)
00463 {
00464
if (aSlave != mSlave)
return;
00465 slotSlaveError( aSlave, errorCode, errorMsg );
00466 emit connectionResult( errorCode );
00467 }
00468
00469
00470
void ImapAccountBase::slotSchedulerSlaveConnected(KIO::Slave *aSlave)
00471 {
00472
if (aSlave != mSlave)
return;
00473 emit connectionResult( 0 );
00474 }
00475
00476
00477
void ImapAccountBase::slotSlaveError(KIO::Slave *aSlave,
int errorCode,
00478
const QString &errorMsg)
00479 {
00480
if (aSlave != mSlave)
return;
00481
if (errorCode == KIO::ERR_SLAVE_DIED) slaveDied();
00482
if (errorCode == KIO::ERR_COULD_NOT_LOGIN && !mStorePasswd) mAskAgain = TRUE;
00483 killAllJobs();
00484
00485
if ( !mErrorDialogIsActive )
00486 {
00487 mErrorDialogIsActive =
true;
00488 KMessageBox::messageBox(kmkernel->mainWin(), KMessageBox::Error,
00489 KIO::buildErrorString(errorCode, errorMsg),
00490 i18n(
"Error"));
00491 mErrorDialogIsActive =
false;
00492 }
else
00493 kdDebug(5006) <<
"suppressing error:" << errorMsg << endl;
00494 }
00495
00496
00497 QString ImapAccountBase::jobData::htmlURL()
const
00498
{
00499 KURL u( url );
00500
return u.htmlURL();
00501 }
00502
00503
00504
void ImapAccountBase::processNewMailSingleFolder(
KMFolder* folder)
00505 {
00506 mFoldersQueuedForChecking.append(folder);
00507
if (checkingMail())
00508 {
00509 disconnect (
this, SIGNAL(finishedCheck(
bool)),
00510
this, SLOT(slotCheckQueuedFolders()));
00511 connect (
this, SIGNAL(finishedCheck(
bool)),
00512
this, SLOT(slotCheckQueuedFolders()));
00513 }
else {
00514 slotCheckQueuedFolders();
00515 }
00516 }
00517
00518
00519
void ImapAccountBase::slotCheckQueuedFolders()
00520 {
00521 disconnect (
this, SIGNAL(finishedCheck(
bool)),
00522
this, SLOT(slotCheckQueuedFolders()));
00523
00524 QValueList<QGuardedPtr<KMFolder> > mSaveList = mMailCheckFolders;
00525 mMailCheckFolders = mFoldersQueuedForChecking;
00526 kmkernel->acctMgr()->singleCheckMail(
this,
true);
00527 mMailCheckFolders = mSaveList;
00528 mFoldersQueuedForChecking.clear();
00529 }
00530
00531
00532
void ImapAccountBase::handleBodyStructure( QDataStream & stream, KMMessage * msg,
00533
const AttachmentStrategy *as )
00534 {
00535 mBodyPartList.clear();
00536 mCurrentMsg = msg;
00537
00538 constructParts( stream, 1, 0, 0, msg->asDwMessage() );
00539
if ( mBodyPartList.count() == 1 )
00540 msg->deleteBodyParts();
00541
00542
if ( !as )
00543 {
00544 kdWarning(5006) <<
"ImapAccountBase::handleBodyStructure - found no attachment strategy!" << endl;
00545
return;
00546 }
00547
00548
if ( msg->msgLength() < 5000 )
00549 {
00550 FolderJob *job = msg->parent()->createJob(
00551 msg, FolderJob::tGetMessage, 0,
"TEXT" );
00552 job->start();
00553
return;
00554 }
00555
00556
00557 BodyVisitor *visitor = BodyVisitorFactory::getVisitor( as );
00558 visitor->visit( mBodyPartList );
00559 QPtrList<KMMessagePart> parts = visitor->partsToLoad();
00560 QPtrListIterator<KMMessagePart> it( parts );
00561 KMMessagePart *part;
00562
while ( (part = it.current()) != 0 )
00563 {
00564 ++it;
00565 kdDebug(5006) <<
"ImapAccountBase::handleBodyStructure - load " << part->partSpecifier()
00566 <<
" (" << part->originalContentTypeStr() <<
")" << endl;
00567
if ( part->loadHeaders() )
00568 {
00569 kdDebug(5006) <<
"load HEADER" << endl;
00570 FolderJob *job = msg->parent()->createJob(
00571 msg, FolderJob::tGetMessage, 0, part->partSpecifier()+
".MIME" );
00572 job->start();
00573 }
00574
if ( part->loadPart() )
00575 {
00576 kdDebug(5006) <<
"load Part" << endl;
00577 FolderJob *job = msg->parent()->createJob(
00578 msg, FolderJob::tGetMessage, 0, part->partSpecifier() );
00579 job->start();
00580 }
00581 }
00582
delete visitor;
00583 }
00584
00585
00586
void ImapAccountBase::constructParts( QDataStream & stream,
int count, KMMessagePart* parentKMPart,
00587 DwBodyPart * parent,
const DwMessage * dwmsg )
00588 {
00589
int children;
00590
for (
int i = 0; i < count; i++)
00591 {
00592 stream >> children;
00593 KMMessagePart* part =
new KMMessagePart( stream );
00594 part->setParent( parentKMPart );
00595 mBodyPartList.append( part );
00596 kdDebug(5006) <<
"ImapAccountBase::constructParts - created id " << part->partSpecifier()
00597 <<
" of type " << part->originalContentTypeStr() << endl;
00598 DwBodyPart *dwpart = mCurrentMsg->createDWBodyPart( part );
00599 dwpart->Parse();
00600
00601
00602
00603
00604
if ( parent )
00605 {
00606
00607 parent->Body().AddBodyPart( dwpart );
00608 }
else if ( part->partSpecifier() !=
"0" &&
00609 !part->partSpecifier().endsWith(
".HEADER") )
00610 {
00611
00612 dwmsg->Body().AddBodyPart( dwpart );
00613 }
else
00614 dwpart = 0;
00615
00616
if ( !parentKMPart )
00617 parentKMPart = part;
00618
00619
if (children > 0)
00620 {
00621 DwBodyPart* newparent = dwpart;
00622
const DwMessage* newmsg = dwmsg;
00623
if ( part->originalContentTypeStr() ==
"MESSAGE/RFC822" &&
00624 dwpart->Body().Message() )
00625 {
00626
00627 newparent = 0;
00628 newmsg = dwpart->Body().Message();
00629 }
00630 KMMessagePart* newParentKMPart = part;
00631
if ( part->partSpecifier().endsWith(
".HEADER") )
00632 newParentKMPart = parentKMPart;
00633
00634 constructParts( stream, children, newParentKMPart, newparent, newmsg );
00635 }
00636 }
00637 }
00638
00639 }
00640
00641
#include "imapaccountbase.moc"