You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
876 lines
29 KiB
876 lines
29 KiB
/** -*- c++ -*- |
|
* imapaccountbase.cpp |
|
* |
|
* Copyright (c) 2000-2002 Michael Haeckel <haeckel@kde.org> |
|
* Copyright (c) 2002 Marc Mutz <mutz@kde.org> |
|
* |
|
* This file is based on work on pop3 and imap account implementations |
|
* by Don Sanders <sanders@kde.org> and Michael Haeckel <haeckel@kde.org> |
|
* |
|
* This program is free software; you can redistribute it and/or modify |
|
* it under the terms of the GNU General Public License as published by |
|
* the Free Software Foundation; version 2 of the License |
|
* |
|
* This program is distributed in the hope that it will be useful, |
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
* GNU General Public License for more details. |
|
* |
|
* You should have received a copy of the GNU General Public License |
|
* along with this program; if not, write to the Free Software |
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
|
*/ |
|
|
|
#ifdef HAVE_CONFIG_H |
|
#include <config.h> |
|
#endif |
|
|
|
#include "imapaccountbase.h" |
|
using KMail::SieveConfig; |
|
|
|
#include "kmacctmgr.h" |
|
#include "kmfolder.h" |
|
#include "broadcaststatus.h" |
|
using KPIM::BroadcastStatus; |
|
#include "kmmainwin.h" |
|
#include "kmfolderimap.h" |
|
#include "kmmainwidget.h" |
|
#include "kmmainwin.h" |
|
#include "kmmsgpart.h" |
|
#include "acljobs.h" |
|
#include "kmfoldercachedimap.h" |
|
#include "bodyvisitor.h" |
|
using KMail::BodyVisitor; |
|
#include "imapjob.h" |
|
using KMail::ImapJob; |
|
#include "protocols.h" |
|
#include "progressmanager.h" |
|
using KPIM::ProgressManager; |
|
#include "kmfoldermgr.h" |
|
|
|
#include <kapplication.h> |
|
#include <kdebug.h> |
|
#include <kconfig.h> |
|
#include <klocale.h> |
|
#include <kmessagebox.h> |
|
using KIO::MetaData; |
|
#include <kio/passdlg.h> |
|
using KIO::PasswordDialog; |
|
#include <kio/scheduler.h> |
|
#include <kio/slave.h> |
|
#include <mimelib/bodypart.h> |
|
#include <mimelib/body.h> |
|
#include <mimelib/headers.h> |
|
#include <mimelib/message.h> |
|
//using KIO::Scheduler; // use FQN below |
|
|
|
#include <qregexp.h> |
|
#include <qstylesheet.h> |
|
|
|
namespace KMail { |
|
|
|
static const unsigned short int imapDefaultPort = 143; |
|
|
|
// |
|
// |
|
// Ctor and Dtor |
|
// |
|
// |
|
|
|
ImapAccountBase::ImapAccountBase( KMAcctMgr * parent, const QString & name, uint id ) |
|
: NetworkAccount( parent, name, id ), |
|
mPrefix( "/" ), |
|
mTotal( 0 ), |
|
mCountUnread( 0 ), |
|
mCountLastUnread( 0 ), |
|
mAutoExpunge( true ), |
|
mHiddenFolders( false ), |
|
mOnlySubscribedFolders( false ), |
|
mLoadOnDemand( true ), |
|
mListOnlyOpenFolders( false ), |
|
mProgressEnabled( false ), |
|
mErrorDialogIsActive( false ), |
|
mPasswordDialogIsActive( false ), |
|
mACLSupport( true ), |
|
mSlaveConnected( false ), |
|
mSlaveConnectionError( false ), |
|
mListDirProgressItem( 0 ) |
|
{ |
|
mPort = imapDefaultPort; |
|
mBodyPartList.setAutoDelete(true); |
|
KIO::Scheduler::connect(SIGNAL(slaveError(KIO::Slave *, int, const QString &)), |
|
this, SLOT(slotSchedulerSlaveError(KIO::Slave *, int, const QString &))); |
|
KIO::Scheduler::connect(SIGNAL(slaveConnected(KIO::Slave *)), |
|
this, SLOT(slotSchedulerSlaveConnected(KIO::Slave *))); |
|
connect(&mNoopTimer, SIGNAL(timeout()), SLOT(slotNoopTimeout())); |
|
connect(&mIdleTimer, SIGNAL(timeout()), SLOT(slotIdleTimeout())); |
|
} |
|
|
|
ImapAccountBase::~ImapAccountBase() { |
|
kdWarning( mSlave, 5006 ) |
|
<< "slave should have been destroyed by subclass!" << endl; |
|
} |
|
|
|
void ImapAccountBase::init() { |
|
mPrefix = '/'; |
|
mAutoExpunge = true; |
|
mHiddenFolders = false; |
|
mOnlySubscribedFolders = false; |
|
mLoadOnDemand = true; |
|
mListOnlyOpenFolders = false; |
|
mProgressEnabled = false; |
|
} |
|
|
|
void ImapAccountBase::pseudoAssign( const KMAccount * a ) { |
|
NetworkAccount::pseudoAssign( a ); |
|
|
|
const ImapAccountBase * i = dynamic_cast<const ImapAccountBase*>( a ); |
|
if ( !i ) return; |
|
|
|
setPrefix( i->prefix() ); |
|
setAutoExpunge( i->autoExpunge() ); |
|
setHiddenFolders( i->hiddenFolders() ); |
|
setOnlySubscribedFolders( i->onlySubscribedFolders() ); |
|
setLoadOnDemand( i->loadOnDemand() ); |
|
setListOnlyOpenFolders( i->listOnlyOpenFolders() ); |
|
} |
|
|
|
unsigned short int ImapAccountBase::defaultPort() const { |
|
return imapDefaultPort; |
|
} |
|
|
|
QString ImapAccountBase::protocol() const { |
|
return useSSL() ? IMAP_SSL_PROTOCOL : IMAP_PROTOCOL; |
|
} |
|
|
|
// |
|
// |
|
// Getters and Setters |
|
// |
|
// |
|
|
|
void ImapAccountBase::setPrefix( const QString & prefix ) { |
|
mPrefix = prefix; |
|
mPrefix.remove( QRegExp( "[%*\"]" ) ); |
|
if ( mPrefix.isEmpty() || mPrefix[0] != '/' ) |
|
mPrefix.prepend( '/' ); |
|
if ( mPrefix[ mPrefix.length() - 1 ] != '/' ) |
|
mPrefix += '/'; |
|
#if 1 |
|
setPrefixHook(); // ### needed while KMFolderCachedImap exists |
|
#else |
|
if ( mFolder ) mFolder->setImapPath( mPrefix ); |
|
#endif |
|
} |
|
|
|
void ImapAccountBase::setAutoExpunge( bool expunge ) { |
|
mAutoExpunge = expunge; |
|
} |
|
|
|
void ImapAccountBase::setHiddenFolders( bool show ) { |
|
mHiddenFolders = show; |
|
} |
|
|
|
void ImapAccountBase::setOnlySubscribedFolders( bool show ) { |
|
mOnlySubscribedFolders = show; |
|
} |
|
|
|
void ImapAccountBase::setLoadOnDemand( bool load ) { |
|
mLoadOnDemand = load; |
|
} |
|
|
|
void ImapAccountBase::setListOnlyOpenFolders( bool only ) { |
|
mListOnlyOpenFolders = only; |
|
} |
|
|
|
// |
|
// |
|
// read/write config |
|
// |
|
// |
|
|
|
void ImapAccountBase::readConfig( /*const*/ KConfig/*Base*/ & config ) { |
|
NetworkAccount::readConfig( config ); |
|
|
|
setPrefix( config.readEntry( "prefix", "/" ) ); |
|
setAutoExpunge( config.readBoolEntry( "auto-expunge", false ) ); |
|
setHiddenFolders( config.readBoolEntry( "hidden-folders", false ) ); |
|
setOnlySubscribedFolders( config.readBoolEntry( "subscribed-folders", false ) ); |
|
setLoadOnDemand( config.readBoolEntry( "loadondemand", false ) ); |
|
setListOnlyOpenFolders( config.readBoolEntry( "listOnlyOpenFolders", false ) ); |
|
} |
|
|
|
void ImapAccountBase::writeConfig( KConfig/*Base*/ & config ) /*const*/ { |
|
NetworkAccount::writeConfig( config ); |
|
|
|
config.writeEntry( "prefix", prefix() ); |
|
config.writeEntry( "auto-expunge", autoExpunge() ); |
|
config.writeEntry( "hidden-folders", hiddenFolders() ); |
|
config.writeEntry( "subscribed-folders", onlySubscribedFolders() ); |
|
config.writeEntry( "loadondemand", loadOnDemand() ); |
|
config.writeEntry( "listOnlyOpenFolders", listOnlyOpenFolders() ); |
|
} |
|
|
|
// |
|
// |
|
// Network processing |
|
// |
|
// |
|
|
|
MetaData ImapAccountBase::slaveConfig() const { |
|
MetaData m = NetworkAccount::slaveConfig(); |
|
|
|
m.insert( "auth", auth() ); |
|
if ( autoExpunge() ) |
|
m.insert( "expunge", "auto" ); |
|
|
|
return m; |
|
} |
|
|
|
ImapAccountBase::ConnectionState ImapAccountBase::makeConnection() { |
|
|
|
if ( mSlave && mSlaveConnected ) return Connected; |
|
if ( mPasswordDialogIsActive ) return Connecting; |
|
|
|
if( mAskAgain || passwd().isEmpty() || login().isEmpty() ) { |
|
Q_ASSERT( !mSlave ); // disconnected on 'wrong login' error already, or first try |
|
QString log = login(); |
|
QString pass = passwd(); |
|
// We init "store" to true to indicate that we want to have the |
|
// "keep password" checkbox. Then, we set [Passwords]Keep to |
|
// storePasswd(), so that the checkbox in the dialog will be |
|
// init'ed correctly: |
|
bool store = true; |
|
KConfigGroup passwords( KGlobal::config(), "Passwords" ); |
|
passwords.writeEntry( "Keep", storePasswd() ); |
|
QString msg = i18n("You need to supply a username and a password to " |
|
"access this mailbox."); |
|
mPasswordDialogIsActive = true; |
|
if ( PasswordDialog::getNameAndPassword( log, pass, &store, msg, false, |
|
QString::null, name(), |
|
i18n("Account:") ) |
|
!= QDialog::Accepted ) { |
|
mPasswordDialogIsActive = false; |
|
mAskAgain = false; |
|
emit connectionResult( KIO::ERR_USER_CANCELED, QString::null ); |
|
return Error; |
|
} |
|
mPasswordDialogIsActive = false; |
|
// The user has been given the chance to change login and |
|
// password, so copy both from the dialog: |
|
setPasswd( pass, store ); |
|
setLogin( log ); |
|
mAskAgain = false; |
|
} |
|
// already waiting for a connection? |
|
if ( mSlave && !mSlaveConnected ) return Connecting; |
|
|
|
mSlaveConnected = false; |
|
mSlave = KIO::Scheduler::getConnectedSlave( getUrl(), slaveConfig() ); |
|
if ( !mSlave ) { |
|
KMessageBox::error(0, i18n("Could not start process for %1.") |
|
.arg( getUrl().protocol() ) ); |
|
return Error; |
|
} |
|
if ( mSlave->isConnected() ) { |
|
mSlaveConnected = true; |
|
return Connected; |
|
} |
|
|
|
return Connecting; |
|
} |
|
|
|
bool ImapAccountBase::handleJobError( KIO::Job *job, const QString& context, bool abortSync ) |
|
{ |
|
return handleError( job->error(), job->errorText(), job, context, abortSync ); |
|
} |
|
|
|
// Called when we're really all done. |
|
void ImapAccountBase::postProcessNewMail() { |
|
setCheckingMail(false); |
|
int newMails = 0; |
|
if ( mCountUnread > 0 && mCountUnread > mCountLastUnread ) { |
|
newMails = mCountUnread - mCountLastUnread; |
|
mCountLastUnread = mCountUnread; |
|
mCountUnread = 0; |
|
checkDone( true, CheckOK ); |
|
} else { |
|
mCountUnread = 0; |
|
checkDone( false, CheckOK ); |
|
} |
|
BroadcastStatus::instance()->setStatusMsgTransmissionCompleted( |
|
name(), newMails); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
void ImapAccountBase::changeSubscription( bool subscribe, QString imapPath ) |
|
{ |
|
// change the subscription of the folder |
|
KURL url = getUrl(); |
|
url.setPath(imapPath); |
|
|
|
QByteArray packedArgs; |
|
QDataStream stream( packedArgs, IO_WriteOnly); |
|
|
|
if (subscribe) |
|
stream << (int) 'u' << url; |
|
else |
|
stream << (int) 'U' << url; |
|
|
|
// create the KIO-job |
|
if (makeConnection() != Connected) // ## doesn't handle Connecting |
|
return; |
|
KIO::SimpleJob *job = KIO::special(url, packedArgs, FALSE); |
|
KIO::Scheduler::assignJobToSlave(mSlave, job); |
|
jobData jd( url.url(), NULL ); |
|
// a bit of a hack to save one slot |
|
if (subscribe) jd.onlySubscribed = true; |
|
else jd.onlySubscribed = false; |
|
insertJob(job, jd); |
|
|
|
connect(job, SIGNAL(result(KIO::Job *)), |
|
SLOT(slotSubscriptionResult(KIO::Job *))); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
void ImapAccountBase::slotSubscriptionResult( KIO::Job * job ) |
|
{ |
|
// result of a subscription-job |
|
JobIterator it = findJob( job ); |
|
if ( it == jobsEnd() ) return; |
|
bool onlySubscribed = (*it).onlySubscribed; |
|
QString path = static_cast<KIO::SimpleJob*>(job)->url().path(); |
|
if (job->error()) |
|
{ |
|
handleJobError( job, i18n( "Error while trying to subscribe to %1:" ).arg( path ) + '\n' ); |
|
// ## emit subscriptionChanged here in case anyone needs it to support continue/cancel |
|
} |
|
else |
|
{ |
|
emit subscriptionChanged( path, onlySubscribed ); |
|
if (mSlave) removeJob(job); |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// TODO imapPath can be removed once parent can be a KMFolderImapBase or whatever |
|
void ImapAccountBase::getUserRights( KMFolder* parent, const QString& imapPath ) |
|
{ |
|
// There isn't much point in asking the server about a user's rights on his own inbox, |
|
// it might not be the effective permissions (at least with Cyrus, one can admin his own inbox, |
|
// even after a SETACL that removes the admin permissions. Other imap servers apparently |
|
// don't even allow removing one's own admin permission, so this code won't hurt either). |
|
if ( imapPath == "/INBOX/" ) { |
|
if ( parent->folderType() == KMFolderTypeImap ) |
|
static_cast<KMFolderImap*>( parent->storage() )->setUserRights( ACLJobs::All ); |
|
else if ( parent->folderType() == KMFolderTypeCachedImap ) |
|
static_cast<KMFolderCachedImap*>( parent->storage() )->setUserRights( ACLJobs::All ); |
|
emit receivedUserRights( parent ); // warning, you need to connect first to get that one |
|
return; |
|
} |
|
|
|
KURL url = getUrl(); |
|
url.setPath(imapPath); |
|
|
|
ACLJobs::GetUserRightsJob* job = ACLJobs::getUserRights( mSlave, url ); |
|
|
|
jobData jd( url.url(), parent ); |
|
jd.cancellable = true; |
|
insertJob(job, jd); |
|
|
|
connect(job, SIGNAL(result(KIO::Job *)), |
|
SLOT(slotGetUserRightsResult(KIO::Job *))); |
|
} |
|
|
|
void ImapAccountBase::slotGetUserRightsResult( KIO::Job* _job ) |
|
{ |
|
ACLJobs::GetUserRightsJob* job = static_cast<ACLJobs::GetUserRightsJob *>( _job ); |
|
JobIterator it = findJob( job ); |
|
if ( it == jobsEnd() ) return; |
|
|
|
KMFolder* folder = (*it).parent; |
|
if ( job->error() ) { |
|
if ( job->error() == KIO::ERR_UNSUPPORTED_ACTION ) // that's when the imap server doesn't support ACLs |
|
mACLSupport = false; |
|
else |
|
kdWarning(5006) << "slotGetUserRightsResult: " << job->errorString() << endl; |
|
} else { |
|
#ifndef NDEBUG |
|
//kdDebug(5006) << "User Rights: " << ACLJobs::permissionsToString( job->permissions() ) << endl; |
|
#endif |
|
// Store the permissions |
|
if ( folder->folderType() == KMFolderTypeImap ) |
|
static_cast<KMFolderImap*>( folder->storage() )->setUserRights( job->permissions() ); |
|
else if ( folder->folderType() == KMFolderTypeCachedImap ) |
|
static_cast<KMFolderCachedImap*>( folder->storage() )->setUserRights( job->permissions() ); |
|
} |
|
if (mSlave) removeJob(job); |
|
emit receivedUserRights( folder ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
void ImapAccountBase::getACL( KMFolder* parent, const QString& imapPath ) |
|
{ |
|
KURL url = getUrl(); |
|
url.setPath(imapPath); |
|
|
|
ACLJobs::GetACLJob* job = ACLJobs::getACL( mSlave, url ); |
|
jobData jd( url.url(), parent ); |
|
jd.cancellable = true; |
|
insertJob(job, jd); |
|
|
|
connect(job, SIGNAL(result(KIO::Job *)), |
|
SLOT(slotGetACLResult(KIO::Job *))); |
|
} |
|
|
|
void ImapAccountBase::slotGetACLResult( KIO::Job* _job ) |
|
{ |
|
ACLJobs::GetACLJob* job = static_cast<ACLJobs::GetACLJob *>( _job ); |
|
JobIterator it = findJob( job ); |
|
if ( it == jobsEnd() ) return; |
|
|
|
KMFolder* folder = (*it).parent; |
|
emit receivedACL( folder, job, job->entries() ); |
|
if (mSlave) removeJob(job); |
|
} |
|
|
|
|
|
void ImapAccountBase::slotNoopTimeout() |
|
{ |
|
if ( mSlave ) { |
|
QByteArray packedArgs; |
|
QDataStream stream( packedArgs, IO_WriteOnly ); |
|
|
|
stream << ( int ) 'N'; |
|
|
|
KIO::SimpleJob *job = KIO::special( getUrl(), packedArgs, false ); |
|
KIO::Scheduler::assignJobToSlave(mSlave, job); |
|
connect( job, SIGNAL(result( KIO::Job * ) ), |
|
this, SLOT( slotSimpleResult( KIO::Job * ) ) ); |
|
} else { |
|
/* Stop the timer, we have disconnected. We have to make sure it is |
|
started again when a new slave appears. */ |
|
mNoopTimer.stop(); |
|
} |
|
} |
|
|
|
void ImapAccountBase::slotIdleTimeout() |
|
{ |
|
if ( mSlave ) { |
|
KIO::Scheduler::disconnectSlave(mSlave); |
|
mSlave = 0; |
|
mSlaveConnected = false; |
|
/* As for the noop timer, we need to make sure this one is started |
|
again when a new slave goes up. */ |
|
mIdleTimer.stop(); |
|
} |
|
} |
|
|
|
void ImapAccountBase::slotAbortRequested( KPIM::ProgressItem* item ) |
|
{ |
|
if ( item ) |
|
item->setComplete(); |
|
killAllJobs(); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
void ImapAccountBase::slotSchedulerSlaveError(KIO::Slave *aSlave, int errorCode, |
|
const QString &errorMsg) |
|
{ |
|
if (aSlave != mSlave) return; |
|
handleError( errorCode, errorMsg, 0, QString::null, true ); |
|
if ( mAskAgain ) |
|
makeConnection(); |
|
else { |
|
if ( !mSlaveConnected ) |
|
mSlaveConnectionError = true; |
|
emit connectionResult( errorCode, errorMsg ); |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
void ImapAccountBase::slotSchedulerSlaveConnected(KIO::Slave *aSlave) |
|
{ |
|
if (aSlave != mSlave) return; |
|
mSlaveConnected = true; |
|
emit connectionResult( 0, QString::null ); // success |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
void ImapAccountBase::slotSimpleResult(KIO::Job * job) |
|
{ |
|
JobIterator it = findJob( job ); |
|
bool quiet = false; |
|
if (it != mapJobData.end()) { |
|
quiet = (*it).quiet; |
|
if ( !(job->error() && !quiet) ) // the error handler removes in that case |
|
removeJob(it); |
|
} |
|
if (job->error()) { |
|
if (!quiet) |
|
handleJobError(job, QString::null ); |
|
else { |
|
if ( job->error() == KIO::ERR_CONNECTION_BROKEN && slave() ) { |
|
// make sure ERR_CONNECTION_BROKEN is properly handled and the slave |
|
// disconnected even when quiet() |
|
KIO::Scheduler::disconnectSlave( slave() ); |
|
mSlave = 0; |
|
} |
|
if (job->error() == KIO::ERR_SLAVE_DIED) |
|
slaveDied(); |
|
} |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
bool ImapAccountBase::handlePutError( KIO::Job* job, jobData& jd, KMFolder* folder ) |
|
{ |
|
Q_ASSERT( !jd.msgList.isEmpty() ); |
|
KMMessage* msg = jd.msgList.first(); |
|
// Use double-quotes around the subject to keep the sentence readable, |
|
// but don't use double quotes around the sender since from() might return a double-quoted name already |
|
const QString subject = msg->subject().isEmpty() ? i18n( "<unknown>" ) : QString("\"%1\"").arg( msg->subject() ); |
|
const QString from = msg->from().isEmpty() ? i18n( "<unknown>" ) : msg->from(); |
|
QString myError = "<p><b>" + i18n("Error while uploading message") |
|
+ "</b></p><p>" |
|
+ i18n("Could not upload the message dated %1 from %2 with subject %3 on the server.").arg( msg->dateStr(), QStyleSheet::escape( from ), QStyleSheet::escape( subject ) ) |
|
+ "</p><p>" |
|
+ i18n("The destination folder was %1, which has the URL %2.").arg( QStyleSheet::escape( folder->label() ), QStyleSheet::escape( jd.htmlURL() ) ) |
|
+ "</p><p>" |
|
+ i18n("The error message from the server communication is here:") + "</p>"; |
|
return handleJobError( job, myError ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
bool ImapAccountBase::handleError( int errorCode, const QString &errorMsg, KIO::Job* job, const QString& context, bool abortSync ) |
|
{ |
|
// Copy job's data before a possible killAllJobs |
|
QStringList errors; |
|
if ( job && job->error() != KIO::ERR_SLAVE_DEFINED /*workaround for kdelibs-3.2*/) |
|
errors = job->detailedErrorStrings(); |
|
|
|
bool jobsKilled = true; |
|
switch( errorCode ) { |
|
case KIO::ERR_SLAVE_DIED: slaveDied(); killAllJobs( true ); break; |
|
case KIO::ERR_COULD_NOT_LOGIN: // bad password |
|
mAskAgain = true; |
|
// fallthrough intended |
|
case KIO::ERR_CONNECTION_BROKEN: |
|
case KIO::ERR_COULD_NOT_CONNECT: |
|
// These mean that we'll have to reconnect on the next attempt, so disconnect and set mSlave to 0. |
|
killAllJobs( true ); |
|
break; |
|
case KIO::ERR_USER_CANCELED: |
|
killAllJobs( false ); |
|
break; |
|
default: |
|
if ( abortSync ) |
|
killAllJobs( false ); |
|
else |
|
jobsKilled = false; |
|
break; |
|
} |
|
|
|
// check if we still display an error |
|
if ( !mErrorDialogIsActive && errorCode != KIO::ERR_USER_CANCELED ) |
|
{ |
|
mErrorDialogIsActive = true; |
|
QString msg; |
|
QString caption; |
|
if ( errors.count() >= 3 ) { |
|
msg = QString( "<qt>") + context + errors[1] + '\n' + errors[2]; |
|
caption = errors[0]; |
|
} else { |
|
msg = context + '\n' + KIO::buildErrorString( errorCode, errorMsg ); |
|
caption = i18n("Error"); |
|
} |
|
|
|
if ( jobsKilled || errorCode == KIO::ERR_COULD_NOT_LOGIN ) |
|
KMessageBox::error( kapp->activeWindow(), msg, caption ); |
|
else // i.e. we have a chance to continue, ask the user about it |
|
{ |
|
int ret = KMessageBox::warningContinueCancel( kapp->activeWindow(), msg, caption ); |
|
if ( ret == KMessageBox::Cancel ) { |
|
jobsKilled = true; |
|
killAllJobs( false ); |
|
} |
|
} |
|
mErrorDialogIsActive = false; |
|
} else |
|
kdDebug(5006) << "suppressing error:" << errorMsg << endl; |
|
|
|
if ( job && !jobsKilled ) |
|
removeJob( job ); |
|
return !jobsKilled; // jobsKilled==false -> continue==true |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
void ImapAccountBase::cancelMailCheck() |
|
{ |
|
QMap<KIO::Job*, jobData>::Iterator it = mapJobData.begin(); |
|
while ( it != mapJobData.end() ) { |
|
kdDebug(5006) << "cancelMailCheck: job is cancellable: " << (*it).cancellable << endl; |
|
if ( (*it).cancellable ) { |
|
it.key()->kill(); |
|
QMap<KIO::Job*, jobData>::Iterator rmit = it; |
|
++it; |
|
mapJobData.remove( rmit ); |
|
// We killed a job -> this kills the slave |
|
mSlave = 0; |
|
} else |
|
++it; |
|
} |
|
|
|
for( QPtrListIterator<FolderJob> it( mJobList ); it.current(); ++it ) { |
|
if ( it.current()->isCancellable() ) { |
|
FolderJob* job = it.current(); |
|
job->setPassiveDestructor( true ); |
|
mJobList.remove( job ); |
|
delete job; |
|
} else |
|
++it; |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
QString ImapAccountBase::jobData::htmlURL() const |
|
{ |
|
KURL u( url ); |
|
return u.htmlURL(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
void ImapAccountBase::processNewMailSingleFolder(KMFolder* folder) |
|
{ |
|
mFoldersQueuedForChecking.append(folder); |
|
if ( checkingMail() ) |
|
{ |
|
disconnect( this, SIGNAL( finishedCheck( bool, CheckStatus ) ), |
|
this, SLOT( slotCheckQueuedFolders() ) ); |
|
connect( this, SIGNAL( finishedCheck( bool, CheckStatus ) ), |
|
this, SLOT( slotCheckQueuedFolders() ) ); |
|
} else { |
|
slotCheckQueuedFolders(); |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
void ImapAccountBase::slotCheckQueuedFolders() |
|
{ |
|
disconnect( this, SIGNAL( finishedCheck( bool, CheckStatus ) ), |
|
this, SLOT( slotCheckQueuedFolders() ) ); |
|
|
|
QValueList<QGuardedPtr<KMFolder> > mSaveList = mMailCheckFolders; |
|
mMailCheckFolders = mFoldersQueuedForChecking; |
|
kmkernel->acctMgr()->singleCheckMail(this, true); |
|
mMailCheckFolders = mSaveList; |
|
mFoldersQueuedForChecking.clear(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
bool ImapAccountBase::checkingMail( KMFolder *folder ) |
|
{ |
|
if (checkingMail() && mFoldersQueuedForChecking.contains(folder)) |
|
return true; |
|
return false; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
void ImapAccountBase::handleBodyStructure( QDataStream & stream, KMMessage * msg, |
|
const AttachmentStrategy *as ) |
|
{ |
|
mBodyPartList.clear(); |
|
mCurrentMsg = msg; |
|
// make the parts and fill the mBodyPartList |
|
constructParts( stream, 1, 0, 0, msg->asDwMessage() ); |
|
if ( mBodyPartList.count() == 1 ) // we directly set the body later |
|
msg->deleteBodyParts(); |
|
|
|
if ( !as ) |
|
{ |
|
kdWarning(5006) << "ImapAccountBase::handleBodyStructure - found no attachment strategy!" << endl; |
|
return; |
|
} |
|
|
|
// download parts according to attachmentstrategy |
|
BodyVisitor *visitor = BodyVisitorFactory::getVisitor( as ); |
|
visitor->visit( mBodyPartList ); |
|
QPtrList<KMMessagePart> parts = visitor->partsToLoad(); |
|
QPtrListIterator<KMMessagePart> it( parts ); |
|
KMMessagePart *part; |
|
while ( (part = it.current()) != 0 ) |
|
{ |
|
++it; |
|
kdDebug(5006) << "ImapAccountBase::handleBodyStructure - load " << part->partSpecifier() |
|
<< " (" << part->originalContentTypeStr() << ")" << endl; |
|
if ( part->loadHeaders() ) |
|
{ |
|
kdDebug(5006) << "load HEADER" << endl; |
|
FolderJob *job = msg->parent()->createJob( |
|
msg, FolderJob::tGetMessage, 0, part->partSpecifier()+".MIME" ); |
|
job->start(); |
|
} |
|
if ( part->loadPart() ) |
|
{ |
|
kdDebug(5006) << "load Part" << endl; |
|
FolderJob *job = msg->parent()->createJob( |
|
msg, FolderJob::tGetMessage, 0, part->partSpecifier() ); |
|
job->start(); |
|
} |
|
} |
|
delete visitor; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
void ImapAccountBase::constructParts( QDataStream & stream, int count, KMMessagePart* parentKMPart, |
|
DwBodyPart * parent, const DwMessage * dwmsg ) |
|
{ |
|
int children; |
|
for (int i = 0; i < count; i++) |
|
{ |
|
stream >> children; |
|
KMMessagePart* part = new KMMessagePart( stream ); |
|
part->setParent( parentKMPart ); |
|
mBodyPartList.append( part ); |
|
kdDebug(5006) << "ImapAccountBase::constructParts - created id " << part->partSpecifier() |
|
<< " of type " << part->originalContentTypeStr() << endl; |
|
DwBodyPart *dwpart = mCurrentMsg->createDWBodyPart( part ); |
|
dwpart->Parse(); // also creates an encapsulated DwMessage if necessary |
|
|
|
// kdDebug(5006) << "constructed dwpart " << dwpart << ",dwmsg " << dwmsg << ",parent " << parent |
|
// << ",dwparts msg " << dwpart->Body().Message() << endl; |
|
|
|
if ( parent ) |
|
{ |
|
// add to parent body |
|
parent->Body().AddBodyPart( dwpart ); |
|
} else if ( part->partSpecifier() != "0" && |
|
!part->partSpecifier().endsWith(".HEADER") ) |
|
{ |
|
// add to message |
|
dwmsg->Body().AddBodyPart( dwpart ); |
|
} else |
|
dwpart = 0; |
|
|
|
if ( !parentKMPart ) |
|
parentKMPart = part; |
|
|
|
if (children > 0) |
|
{ |
|
DwBodyPart* newparent = dwpart; |
|
const DwMessage* newmsg = dwmsg; |
|
if ( part->originalContentTypeStr() == "MESSAGE/RFC822" && |
|
dwpart->Body().Message() ) |
|
{ |
|
// set the encapsulated message as new parent message |
|
newparent = 0; |
|
newmsg = dwpart->Body().Message(); |
|
} |
|
KMMessagePart* newParentKMPart = part; |
|
if ( part->partSpecifier().endsWith(".HEADER") ) // we don't want headers as parent |
|
newParentKMPart = parentKMPart; |
|
|
|
constructParts( stream, children, newParentKMPart, newparent, newmsg ); |
|
} |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
void ImapAccountBase::setImapStatus( KMFolder* folder, const QString& path, const QCString& flags ) |
|
{ |
|
// set the status on the server, the uids are integrated in the path |
|
kdDebug(5006) << "setImapStatus path=" << path << " to: " << flags << endl; |
|
KURL url = getUrl(); |
|
url.setPath(path); |
|
|
|
QByteArray packedArgs; |
|
QDataStream stream( packedArgs, IO_WriteOnly); |
|
|
|
stream << (int) 'S' << url << flags; |
|
|
|
if ( makeConnection() != ImapAccountBase::Connected ) |
|
return; // can't happen with dimap |
|
|
|
KIO::SimpleJob *job = KIO::special(url, packedArgs, FALSE); |
|
KIO::Scheduler::assignJobToSlave(slave(), job); |
|
ImapAccountBase::jobData jd( url.url(), folder ); |
|
jd.path = path; |
|
insertJob(job, jd); |
|
connect(job, SIGNAL(result(KIO::Job *)), |
|
SLOT(slotSetStatusResult(KIO::Job *))); |
|
} |
|
//----------------------------------------------------------------------------- |
|
void ImapAccountBase::slotSetStatusResult(KIO::Job * job) |
|
{ |
|
ImapAccountBase::JobIterator it = findJob(job); |
|
if ( it == jobsEnd() ) return; |
|
int errorCode = job->error(); |
|
if (errorCode && errorCode != KIO::ERR_CANNOT_OPEN_FOR_WRITING) |
|
{ |
|
bool cont = handleJobError( job, i18n( "Error while uploading status of messages to server: " ) + '\n' ); |
|
emit imapStatusChanged( (*it).parent, (*it).path, cont ); |
|
} |
|
else |
|
{ |
|
emit imapStatusChanged( (*it).parent, (*it).path, true ); |
|
removeJob(it); |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
void ImapAccountBase::setFolder(KMFolder* folder, bool addAccount) |
|
{ |
|
if (folder) |
|
{ |
|
folder->setSystemLabel(name()); |
|
folder->setId(id()); |
|
} |
|
NetworkAccount::setFolder(folder, addAccount); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
void ImapAccountBase::removeJob( JobIterator& it ) |
|
{ |
|
if( (*it).progressItem ) { |
|
(*it).progressItem->setComplete(); |
|
(*it).progressItem = 0; |
|
} |
|
mapJobData.remove( it ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
KPIM::ProgressItem* ImapAccountBase::listDirProgressItem() |
|
{ |
|
if ( !mListDirProgressItem ) |
|
{ |
|
mListDirProgressItem = ProgressManager::createProgressItem( |
|
"ListDir" + name(), |
|
name(), |
|
i18n("retrieving folders"), |
|
true, |
|
useSSL() || useTLS() ); |
|
connect ( mListDirProgressItem, |
|
SIGNAL( progressItemCanceled( ProgressItem* ) ), |
|
this, |
|
SLOT( slotAbortRequested( ProgressItem* ) ) ); |
|
// Start with a guessed value of the old folder count plus 5%. As long |
|
// as the list of folders doesn't constantly change, that should be good |
|
// enough. |
|
unsigned int count = folderCount(); |
|
mListDirProgressItem->setTotalItems( count + (unsigned int)(count*0.05) ); |
|
} |
|
return mListDirProgressItem; |
|
} |
|
|
|
unsigned int ImapAccountBase::folderCount() const |
|
{ |
|
if ( !rootFolder() || !rootFolder()->folder() || !rootFolder()->folder()->child() ) |
|
return 0; |
|
return kmkernel->imapFolderMgr()->folderCount( rootFolder()->folder()->child() ); |
|
} |
|
|
|
} // namespace KMail |
|
|
|
#include "imapaccountbase.moc"
|
|
|