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.
2435 lines
80 KiB
2435 lines
80 KiB
/**
|
|
* kmfolderimap.cpp
|
|
*
|
|
* Copyright (c) 2001 Kurt Granroth <granroth@kde.org>
|
|
* Copyright (c) 2000-2002 Michael Haeckel <haeckel@kde.org>
|
|
*
|
|
* This file is based on kmacctimap.coo by Michael Haeckel which was
|
|
* based on popaccount.cpp by Don Sanders
|
|
*
|
|
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*/
|
|
#ifdef HAVE_CONFIG_H
|
|
#include <config.h>
|
|
#endif
|
|
|
|
#include "kmfolder.h"
|
|
#include "kmfolderimap.h"
|
|
#include "kmfoldermbox.h"
|
|
#include "kmfoldertree.h"
|
|
#include "kmmsgdict.h"
|
|
#include "undostack.h"
|
|
#include "kmfoldermgr.h"
|
|
#include "kmfiltermgr.h"
|
|
#include "kmmsgdict.h"
|
|
#include "imapaccountbase.h"
|
|
using KMail::ImapAccountBase;
|
|
#include "imapjob.h"
|
|
using KMail::ImapJob;
|
|
#include "attachmentstrategy.h"
|
|
using KMail::AttachmentStrategy;
|
|
#include "progressmanager.h"
|
|
using KPIM::ProgressItem;
|
|
using KPIM::ProgressManager;
|
|
#include "listjob.h"
|
|
using KMail::ListJob;
|
|
#include "kmsearchpattern.h"
|
|
#include "searchjob.h"
|
|
using KMail::SearchJob;
|
|
#include "renamejob.h"
|
|
using KMail::RenameJob;
|
|
|
|
#include <kdebug.h>
|
|
#include <kio/scheduler.h>
|
|
#include <kconfig.h>
|
|
|
|
#include <qbuffer.h>
|
|
#include <qtextcodec.h>
|
|
#include <qstylesheet.h>
|
|
|
|
#include <assert.h>
|
|
|
|
KMFolderImap::KMFolderImap(KMFolder* folder, const char* aName)
|
|
: KMFolderMbox(folder, aName),
|
|
mUploadAllFlags( false )
|
|
{
|
|
mContentState = imapNoInformation;
|
|
mSubfolderState = imapNoInformation;
|
|
mAccount = 0;
|
|
mIsSelected = false;
|
|
mLastUid = 0;
|
|
mCheckFlags = true;
|
|
mCheckMail = true;
|
|
mCheckingValidity = false;
|
|
mUserRights = 0;
|
|
mAlreadyRemoved = false;
|
|
mHasChildren = ChildrenUnknown;
|
|
mMailCheckProgressItem = 0;
|
|
mListDirProgressItem = 0;
|
|
mAddMessageProgressItem = 0;
|
|
mReadOnly = false;
|
|
|
|
connect (this, SIGNAL( folderComplete( KMFolderImap*, bool ) ),
|
|
this, SLOT( slotCompleteMailCheckProgress()) );
|
|
}
|
|
|
|
KMFolderImap::~KMFolderImap()
|
|
{
|
|
if (mAccount) {
|
|
mAccount->removeSlaveJobsForFolder( folder() );
|
|
/* Now that we've removed ourselves from the accounts jobs map, kill all
|
|
ongoing operations and reset mailcheck if we were deleted during an
|
|
ongoing mailcheck of our account. Not very gracefull, but safe, and the
|
|
only way I can see to reset the account state cleanly. */
|
|
if ( mAccount->checkingMail( folder() ) ) {
|
|
mAccount->killAllJobs();
|
|
}
|
|
}
|
|
writeConfig();
|
|
if (kmkernel->undoStack()) kmkernel->undoStack()->folderDestroyed( folder() );
|
|
mMetaDataMap.setAutoDelete( true );
|
|
mMetaDataMap.clear();
|
|
mUidMetaDataMap.setAutoDelete( true );
|
|
mUidMetaDataMap.clear();
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void KMFolderImap::reallyDoClose(const char* owner)
|
|
{
|
|
if (isSelected()) {
|
|
kdWarning(5006) << "Trying to close the selected folder " << label() <<
|
|
" - ignoring!" << endl;
|
|
return;
|
|
}
|
|
|
|
// FIXME is this still needed?
|
|
if (account())
|
|
account()->ignoreJobsForFolder( folder() );
|
|
int idx = count();
|
|
while (--idx >= 0) {
|
|
if ( mMsgList[idx]->isMessage() ) {
|
|
KMMessage *msg = static_cast<KMMessage*>(mMsgList[idx]);
|
|
if (msg->transferInProgress())
|
|
msg->setTransferInProgress( false );
|
|
}
|
|
}
|
|
KMFolderMbox::reallyDoClose( owner );
|
|
}
|
|
|
|
KMFolder* KMFolderImap::trashFolder() const
|
|
{
|
|
QString trashStr = account()->trash();
|
|
return kmkernel->imapFolderMgr()->findIdString( trashStr );
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
KMMessage* KMFolderImap::getMsg(int idx)
|
|
{
|
|
if(!(idx >= 0 && idx <= count()))
|
|
return 0;
|
|
|
|
KMMsgBase* mb = getMsgBase(idx);
|
|
if (!mb) return 0;
|
|
if (mb->isMessage())
|
|
{
|
|
return ((KMMessage*)mb);
|
|
} else {
|
|
KMMessage* msg = FolderStorage::getMsg( idx );
|
|
if ( msg ) // set it incomplete as the msg was not transferred from the server
|
|
msg->setComplete( false );
|
|
return msg;
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
KMAcctImap* KMFolderImap::account() const
|
|
{
|
|
if ( !mAccount ) {
|
|
KMFolderDir *parentFolderDir = dynamic_cast<KMFolderDir*>( folder()->parent() );
|
|
if ( !parentFolderDir ) {
|
|
kdWarning() << k_funcinfo << "No parent folder dir found for " << name() << endl;
|
|
return 0;
|
|
}
|
|
KMFolder *parentFolder = parentFolderDir->owner();
|
|
if ( !parentFolder ) {
|
|
kdWarning() << k_funcinfo << "No parent folder found for " << name() << endl;
|
|
return 0;
|
|
}
|
|
KMFolderImap *parentStorage = dynamic_cast<KMFolderImap*>( parentFolder->storage() );
|
|
if ( parentStorage )
|
|
mAccount = parentStorage->account();
|
|
}
|
|
return mAccount;
|
|
}
|
|
|
|
void KMFolderImap::setAccount(KMAcctImap *aAccount)
|
|
{
|
|
mAccount = aAccount;
|
|
if( !folder() || !folder()->child() ) return;
|
|
KMFolderNode* node;
|
|
for (node = folder()->child()->first(); node;
|
|
node = folder()->child()->next())
|
|
{
|
|
if (!node->isDir())
|
|
static_cast<KMFolderImap*>(static_cast<KMFolder*>(node)->storage())->setAccount(aAccount);
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void KMFolderImap::readConfig()
|
|
{
|
|
KConfig* config = KMKernel::config();
|
|
KConfigGroupSaver saver(config, "Folder-" + folder()->idString());
|
|
mCheckMail = config->readBoolEntry("checkmail", true);
|
|
|
|
mUidValidity = config->readEntry("UidValidity");
|
|
if ( mImapPath.isEmpty() ) {
|
|
setImapPath( config->readEntry("ImapPath") );
|
|
}
|
|
if (QString(name()).upper() == "INBOX" && mImapPath == "/INBOX/")
|
|
{
|
|
folder()->setSystemFolder( true );
|
|
folder()->setLabel( i18n("inbox") );
|
|
}
|
|
mNoContent = config->readBoolEntry("NoContent", false);
|
|
mReadOnly = config->readBoolEntry("ReadOnly", false);
|
|
mUploadAllFlags = config->readBoolEntry( "UploadAllFlags", true );
|
|
mPermanentFlags = config->readNumEntry( "PermanentFlags", 31 /* default flags */ );
|
|
|
|
KMFolderMbox::readConfig();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void KMFolderImap::writeConfig()
|
|
{
|
|
KConfig* config = KMKernel::config();
|
|
KConfigGroupSaver saver(config, "Folder-" + folder()->idString());
|
|
config->writeEntry("checkmail", mCheckMail);
|
|
config->writeEntry("UidValidity", mUidValidity);
|
|
config->writeEntry("ImapPath", mImapPath);
|
|
config->writeEntry("NoContent", mNoContent);
|
|
config->writeEntry("ReadOnly", mReadOnly);
|
|
config->writeEntry( "UploadAllFlags", mUploadAllFlags );
|
|
config->writeEntry( "PermanentFlags", mPermanentFlags );
|
|
KMFolderMbox::writeConfig();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void KMFolderImap::remove()
|
|
{
|
|
if ( mAlreadyRemoved || !account() )
|
|
{
|
|
// override
|
|
FolderStorage::remove();
|
|
return;
|
|
}
|
|
KURL url = account()->getUrl();
|
|
url.setPath(imapPath());
|
|
if ( account()->makeConnection() == ImapAccountBase::Error ||
|
|
imapPath().isEmpty() )
|
|
{
|
|
emit removed(folder(), false);
|
|
return;
|
|
}
|
|
KIO::SimpleJob *job = KIO::file_delete(url, false);
|
|
KIO::Scheduler::assignJobToSlave(account()->slave(), job);
|
|
ImapAccountBase::jobData jd(url.url());
|
|
jd.progressItem = ProgressManager::createProgressItem(
|
|
"ImapFolderRemove" + ProgressManager::getUniqueID(),
|
|
i18n("Removing folder"),
|
|
i18n( "URL: %1" ).arg( QStyleSheet::escape( folder()->prettyURL() ) ),
|
|
false,
|
|
account()->useSSL() || account()->useTLS() );
|
|
account()->insertJob(job, jd);
|
|
connect(job, SIGNAL(result(KIO::Job *)),
|
|
this, SLOT(slotRemoveFolderResult(KIO::Job *)));
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void KMFolderImap::slotRemoveFolderResult(KIO::Job *job)
|
|
{
|
|
ImapAccountBase::JobIterator it = account()->findJob(job);
|
|
if ( it == account()->jobsEnd() ) return;
|
|
if (job->error())
|
|
{
|
|
account()->handleJobError( job, i18n("Error while removing a folder.") );
|
|
emit removed(folder(), false);
|
|
} else {
|
|
account()->removeJob(it);
|
|
FolderStorage::remove();
|
|
}
|
|
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void KMFolderImap::removeMsg(int idx, bool quiet)
|
|
{
|
|
if (idx < 0)
|
|
return;
|
|
|
|
if (!quiet)
|
|
{
|
|
KMMessage *msg = getMsg(idx);
|
|
deleteMessage(msg);
|
|
}
|
|
|
|
mLastUid = 0;
|
|
KMFolderMbox::removeMsg(idx);
|
|
}
|
|
|
|
void KMFolderImap::removeMsg( const QPtrList<KMMessage>& msgList, bool quiet )
|
|
{
|
|
if ( msgList.isEmpty() ) return;
|
|
if (!quiet)
|
|
deleteMessage(msgList);
|
|
|
|
mLastUid = 0;
|
|
|
|
/* Remove the messages from the local store as well.
|
|
We don't call KMFolderInherited::removeMsg(QPtrList<KMMessage>) but
|
|
iterate ourselves, as that would call KMFolderImap::removeMsg(int)
|
|
and not the one from the store we want to be used. */
|
|
|
|
QPtrListIterator<KMMessage> it( msgList );
|
|
KMMessage *msg;
|
|
while ( (msg = it.current()) != 0 ) {
|
|
++it;
|
|
int idx = find(msg);
|
|
assert( idx != -1);
|
|
// ATTENTION port me to maildir
|
|
KMFolderMbox::removeMsg(idx, quiet);
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
int KMFolderImap::rename( const QString& newName, KMFolderDir *aParent )
|
|
{
|
|
if ( !aParent )
|
|
KMFolderMbox::rename( newName );
|
|
kmkernel->folderMgr()->contentsChanged();
|
|
return 0;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void KMFolderImap::addMsgQuiet(KMMessage* aMsg)
|
|
{
|
|
KMFolder *aFolder = aMsg->parent();
|
|
Q_UINT32 serNum = 0;
|
|
aMsg->setTransferInProgress( false );
|
|
if (aFolder) {
|
|
serNum = aMsg->getMsgSerNum();
|
|
kmkernel->undoStack()->pushSingleAction( serNum, aFolder, folder() );
|
|
int idx = aFolder->find( aMsg );
|
|
assert( idx != -1 );
|
|
aFolder->take( idx );
|
|
} else {
|
|
kdDebug(5006) << k_funcinfo << "no parent" << endl;
|
|
}
|
|
if ( !account()->hasCapability("uidplus") ) {
|
|
// Remember the status with the MD5 as key
|
|
// so it can be transfered to the new message
|
|
mMetaDataMap.insert( aMsg->msgIdMD5(),
|
|
new KMMsgMetaData(aMsg->status(), serNum) );
|
|
}
|
|
|
|
delete aMsg;
|
|
aMsg = 0;
|
|
getFolder();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void KMFolderImap::addMsgQuiet(QPtrList<KMMessage> msgList)
|
|
{
|
|
if ( mAddMessageProgressItem )
|
|
{
|
|
mAddMessageProgressItem->setComplete();
|
|
mAddMessageProgressItem = 0;
|
|
}
|
|
KMFolder *aFolder = msgList.first()->parent();
|
|
int undoId = -1;
|
|
bool uidplus = account()->hasCapability("uidplus");
|
|
for ( KMMessage* msg = msgList.first(); msg; msg = msgList.next() )
|
|
{
|
|
if ( undoId == -1 )
|
|
undoId = kmkernel->undoStack()->newUndoAction( aFolder, folder() );
|
|
if ( msg->getMsgSerNum() > 0 )
|
|
kmkernel->undoStack()->addMsgToAction( undoId, msg->getMsgSerNum() );
|
|
if ( !uidplus ) {
|
|
// Remember the status with the MD5 as key
|
|
// so it can be transfered to the new message
|
|
mMetaDataMap.insert( msg->msgIdMD5(),
|
|
new KMMsgMetaData(msg->status(), msg->getMsgSerNum()) );
|
|
}
|
|
msg->setTransferInProgress( false );
|
|
}
|
|
if ( aFolder ) {
|
|
aFolder->take( msgList );
|
|
} else {
|
|
kdDebug(5006) << k_funcinfo << "no parent" << endl;
|
|
}
|
|
msgList.setAutoDelete(true);
|
|
msgList.clear();
|
|
getFolder();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
int KMFolderImap::addMsg(KMMessage* aMsg, int* aIndex_ret)
|
|
{
|
|
QPtrList<KMMessage> list;
|
|
list.append(aMsg);
|
|
QValueList<int> index;
|
|
int ret = addMsg(list, index);
|
|
aIndex_ret = &index.first();
|
|
return ret;
|
|
}
|
|
|
|
int KMFolderImap::addMsg(QPtrList<KMMessage>& msgList, QValueList<int>& aIndex_ret)
|
|
{
|
|
KMMessage *aMsg = msgList.getFirst();
|
|
KMFolder *msgParent = aMsg->parent();
|
|
|
|
ImapJob *imapJob = 0;
|
|
if (msgParent)
|
|
{
|
|
if (msgParent->folderType() == KMFolderTypeImap)
|
|
{
|
|
if (static_cast<KMFolderImap*>(msgParent->storage())->account() == account())
|
|
{
|
|
// make sure the messages won't be deleted while we work with them
|
|
for ( KMMessage* msg = msgList.first(); msg; msg = msgList.next() )
|
|
msg->setTransferInProgress(true);
|
|
|
|
if (folder() == msgParent)
|
|
{
|
|
// transfer the whole message, e.g. a draft-message is canceled and re-added to the drafts-folder
|
|
for ( KMMessage* msg = msgList.first(); msg; msg = msgList.next() )
|
|
{
|
|
if (!msg->isComplete())
|
|
{
|
|
int idx = msgParent->find(msg);
|
|
assert(idx != -1);
|
|
msg = msgParent->getMsg(idx);
|
|
}
|
|
imapJob = new ImapJob(msg, ImapJob::tPutMessage, this);
|
|
connect(imapJob, SIGNAL(messageStored(KMMessage*)),
|
|
SLOT(addMsgQuiet(KMMessage*)));
|
|
connect(imapJob, SIGNAL(result(KMail::FolderJob*)),
|
|
SLOT(slotCopyMsgResult(KMail::FolderJob*)));
|
|
imapJob->start();
|
|
}
|
|
|
|
} else {
|
|
|
|
// get the messages and the uids
|
|
QValueList<ulong> uids;
|
|
getUids(msgList, uids);
|
|
|
|
// get the sets (do not sort the uids)
|
|
QStringList sets = makeSets(uids, false);
|
|
|
|
for ( QStringList::Iterator it = sets.begin(); it != sets.end(); ++it )
|
|
{
|
|
// we need the messages that belong to the current set to pass them to the ImapJob
|
|
QPtrList<KMMessage> temp_msgs = splitMessageList(*it, msgList);
|
|
if ( temp_msgs.isEmpty() ) kdDebug(5006) << "Wow! KMFolderImap::splitMessageList() returned an empty list!" << endl;
|
|
imapJob = new ImapJob(temp_msgs, *it, ImapJob::tMoveMessage, this);
|
|
connect(imapJob, SIGNAL(messageCopied(QPtrList<KMMessage>)),
|
|
SLOT(addMsgQuiet(QPtrList<KMMessage>)));
|
|
connect(imapJob, SIGNAL(result(KMail::FolderJob*)),
|
|
SLOT(slotCopyMsgResult(KMail::FolderJob*)));
|
|
imapJob->start();
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
// different account, check if messages can be added
|
|
QPtrListIterator<KMMessage> it( msgList );
|
|
KMMessage *msg;
|
|
while ( (msg = it.current()) != 0 )
|
|
{
|
|
++it;
|
|
int index;
|
|
if (!canAddMsgNow(msg, &index)) {
|
|
aIndex_ret << index;
|
|
msgList.remove(msg);
|
|
} else {
|
|
if (!msg->transferInProgress())
|
|
msg->setTransferInProgress(true);
|
|
}
|
|
}
|
|
}
|
|
} // if imap
|
|
}
|
|
|
|
if ( !msgList.isEmpty() )
|
|
{
|
|
// transfer from local folders or other accounts
|
|
QPtrListIterator<KMMessage> it( msgList );
|
|
KMMessage* msg;
|
|
while ( ( msg = it.current() ) != 0 )
|
|
{
|
|
++it;
|
|
if ( !msg->transferInProgress() )
|
|
msg->setTransferInProgress( true );
|
|
}
|
|
imapJob = new ImapJob( msgList, QString::null, ImapJob::tPutMessage, this );
|
|
if ( !mAddMessageProgressItem && msgList.count() > 1 )
|
|
{
|
|
// use a parent progress if we have more than 1 message
|
|
// otherwise the normal progress is more accurate
|
|
mAddMessageProgressItem = ProgressManager::createProgressItem(
|
|
"Uploading"+ProgressManager::getUniqueID(),
|
|
i18n("Uploading message data"),
|
|
i18n("Destination folder: %1").arg( QStyleSheet::escape( folder()->prettyURL() ) ),
|
|
true,
|
|
account()->useSSL() || account()->useTLS() );
|
|
mAddMessageProgressItem->setTotalItems( msgList.count() );
|
|
connect ( mAddMessageProgressItem, SIGNAL( progressItemCanceled( KPIM::ProgressItem*)),
|
|
account(), SLOT( slotAbortRequested( KPIM::ProgressItem* ) ) );
|
|
imapJob->setParentProgressItem( mAddMessageProgressItem );
|
|
}
|
|
connect( imapJob, SIGNAL( messageCopied(QPtrList<KMMessage>) ),
|
|
SLOT( addMsgQuiet(QPtrList<KMMessage>) ) );
|
|
connect( imapJob, SIGNAL(result(KMail::FolderJob*)),
|
|
SLOT(slotCopyMsgResult(KMail::FolderJob*)) );
|
|
imapJob->start();
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void KMFolderImap::slotCopyMsgResult( KMail::FolderJob* job )
|
|
{
|
|
kdDebug(5006) << k_funcinfo << job->error() << endl;
|
|
if ( job->error() ) // getFolder() will not be called in this case
|
|
emit folderComplete( this, false );
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void KMFolderImap::copyMsg(QPtrList<KMMessage>& msgList)
|
|
{
|
|
if ( !account()->hasCapability("uidplus") ) {
|
|
for ( KMMessage *msg = msgList.first(); msg; msg = msgList.next() ) {
|
|
// Remember the status with the MD5 as key
|
|
// so it can be transfered to the new message
|
|
mMetaDataMap.insert( msg->msgIdMD5(), new KMMsgMetaData(msg->status()) );
|
|
}
|
|
}
|
|
|
|
QValueList<ulong> uids;
|
|
getUids(msgList, uids);
|
|
QStringList sets = makeSets(uids, false);
|
|
for ( QStringList::Iterator it = sets.begin(); it != sets.end(); ++it )
|
|
{
|
|
// we need the messages that belong to the current set to pass them to the ImapJob
|
|
QPtrList<KMMessage> temp_msgs = splitMessageList(*it, msgList);
|
|
|
|
ImapJob *job = new ImapJob(temp_msgs, *it, ImapJob::tCopyMessage, this);
|
|
connect(job, SIGNAL(result(KMail::FolderJob*)),
|
|
SLOT(slotCopyMsgResult(KMail::FolderJob*)));
|
|
job->start();
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
QPtrList<KMMessage> KMFolderImap::splitMessageList(const QString& set,
|
|
QPtrList<KMMessage>& msgList)
|
|
{
|
|
int lastcomma = set.findRev(",");
|
|
int lastdub = set.findRev(":");
|
|
int last = 0;
|
|
if (lastdub > lastcomma) last = lastdub;
|
|
else last = lastcomma;
|
|
last++;
|
|
if (last < 0) last = set.length();
|
|
// the last uid of the current set
|
|
const QString last_uid = set.right(set.length() - last);
|
|
QPtrList<KMMessage> temp_msgs;
|
|
QString uid;
|
|
if (!last_uid.isEmpty())
|
|
{
|
|
QPtrListIterator<KMMessage> it( msgList );
|
|
KMMessage* msg = 0;
|
|
while ( (msg = it.current()) != 0 )
|
|
{
|
|
// append the msg to the new list and delete it from the old
|
|
temp_msgs.append(msg);
|
|
uid.setNum( msg->UID() );
|
|
// remove modifies the current
|
|
msgList.remove(msg);
|
|
if (uid == last_uid) break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// probably only one element
|
|
temp_msgs = msgList;
|
|
}
|
|
|
|
return temp_msgs;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
KMMessage* KMFolderImap::take(int idx)
|
|
{
|
|
KMMsgBase* mb(mMsgList[idx]);
|
|
if (!mb) return 0;
|
|
if (!mb->isMessage()) readMsg(idx);
|
|
|
|
KMMessage *msg = static_cast<KMMessage*>(mb);
|
|
deleteMessage(msg);
|
|
|
|
mLastUid = 0;
|
|
return KMFolderMbox::take(idx);
|
|
}
|
|
|
|
void KMFolderImap::take(QPtrList<KMMessage> msgList)
|
|
{
|
|
deleteMessage(msgList);
|
|
|
|
mLastUid = 0;
|
|
KMFolderMbox::take(msgList);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void KMFolderImap::slotListNamespaces()
|
|
{
|
|
disconnect( account(), SIGNAL( connectionResult(int, const QString&) ),
|
|
this, SLOT( slotListNamespaces() ) );
|
|
if ( account()->makeConnection() == ImapAccountBase::Error )
|
|
{
|
|
kdWarning(5006) << "slotListNamespaces - got no connection" << endl;
|
|
return;
|
|
} else if ( account()->makeConnection() == ImapAccountBase::Connecting )
|
|
{
|
|
// wait for the connectionResult
|
|
kdDebug(5006) << "slotListNamespaces - waiting for connection" << endl;
|
|
connect( account(), SIGNAL( connectionResult(int, const QString&) ),
|
|
this, SLOT( slotListNamespaces() ) );
|
|
return;
|
|
}
|
|
kdDebug(5006) << "slotListNamespaces" << endl;
|
|
// reset subfolder states recursively
|
|
setSubfolderState( imapNoInformation );
|
|
mSubfolderState = imapListingInProgress;
|
|
account()->setHasInbox( false );
|
|
|
|
ImapAccountBase::ListType type = ImapAccountBase::List;
|
|
if ( account()->onlySubscribedFolders() )
|
|
type = ImapAccountBase::ListSubscribed;
|
|
|
|
ImapAccountBase::nsMap map = account()->namespaces();
|
|
QStringList personal = map[ImapAccountBase::PersonalNS];
|
|
// start personal namespace listing and send it directly to slotListResult
|
|
for ( QStringList::Iterator it = personal.begin(); it != personal.end(); ++it )
|
|
{
|
|
KMail::ListJob* job = new KMail::ListJob( account(), type, this,
|
|
account()->addPathToNamespace( *it ) );
|
|
job->setNamespace( *it );
|
|
job->setHonorLocalSubscription( true );
|
|
connect( job, SIGNAL(receivedFolders(const QStringList&, const QStringList&,
|
|
const QStringList&, const QStringList&, const ImapAccountBase::jobData&)),
|
|
this, SLOT(slotListResult(const QStringList&, const QStringList&,
|
|
const QStringList&, const QStringList&, const ImapAccountBase::jobData&)));
|
|
job->start();
|
|
}
|
|
|
|
// and now we list all other namespaces and check them ourself
|
|
QStringList ns = map[ImapAccountBase::OtherUsersNS];
|
|
ns += map[ImapAccountBase::SharedNS];
|
|
for ( QStringList::Iterator it = ns.begin(); it != ns.end(); ++it )
|
|
{
|
|
KMail::ListJob* job = new KMail::ListJob( account(), type, this, account()->addPathToNamespace( *it ) );
|
|
job->setHonorLocalSubscription( true );
|
|
connect( job, SIGNAL(receivedFolders(const QStringList&, const QStringList&,
|
|
const QStringList&, const QStringList&, const ImapAccountBase::jobData&)),
|
|
this, SLOT(slotCheckNamespace(const QStringList&, const QStringList&,
|
|
const QStringList&, const QStringList&, const ImapAccountBase::jobData&)));
|
|
job->start();
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void KMFolderImap::slotCheckNamespace( const QStringList& subfolderNames,
|
|
const QStringList& subfolderPaths,
|
|
const QStringList& subfolderMimeTypes,
|
|
const QStringList& subfolderAttributes,
|
|
const ImapAccountBase::jobData& jobData )
|
|
{
|
|
kdDebug(5006) << "slotCheckNamespace - " << subfolderNames.join(",") << endl;
|
|
|
|
// get a correct foldername:
|
|
// strip / and make sure it does not contain the delimiter
|
|
QString name = jobData.path.mid( 1, jobData.path.length()-2 );
|
|
name.remove( account()->delimiterForNamespace( name ) );
|
|
if ( name.isEmpty() ) {
|
|
// happens when an empty namespace is defined
|
|
slotListResult( subfolderNames, subfolderPaths,
|
|
subfolderMimeTypes, subfolderAttributes, jobData );
|
|
return;
|
|
}
|
|
|
|
folder()->createChildFolder();
|
|
KMFolderNode *node = 0;
|
|
for ( node = folder()->child()->first(); node;
|
|
node = folder()->child()->next())
|
|
{
|
|
if ( !node->isDir() && node->name() == name )
|
|
break;
|
|
}
|
|
if ( subfolderNames.isEmpty() )
|
|
{
|
|
if ( node )
|
|
{
|
|
kdDebug(5006) << "delete namespace folder " << name << endl;
|
|
KMFolder *fld = static_cast<KMFolder*>(node);
|
|
KMFolderImap* nsFolder = static_cast<KMFolderImap*>(fld->storage());
|
|
nsFolder->setAlreadyRemoved( true );
|
|
kmkernel->imapFolderMgr()->remove( fld );
|
|
}
|
|
} else {
|
|
if ( node )
|
|
{
|
|
// folder exists so pass on the attributes
|
|
kdDebug(5006) << "found namespace folder " << name << endl;
|
|
if ( !account()->listOnlyOpenFolders() )
|
|
{
|
|
KMFolderImap* nsFolder =
|
|
static_cast<KMFolderImap*>(static_cast<KMFolder*>(node)->storage());
|
|
nsFolder->slotListResult( subfolderNames, subfolderPaths,
|
|
subfolderMimeTypes, subfolderAttributes, jobData );
|
|
}
|
|
} else
|
|
{
|
|
// create folder
|
|
kdDebug(5006) << "create namespace folder " << name << endl;
|
|
KMFolder *fld = folder()->child()->createFolder( name );
|
|
if ( fld ) {
|
|
KMFolderImap* f = static_cast<KMFolderImap*> ( fld->storage() );
|
|
f->initializeFrom( this, account()->addPathToNamespace( name ),
|
|
"inode/directory" );
|
|
f->close( "kmfolderimap_create" );
|
|
if ( !account()->listOnlyOpenFolders() )
|
|
{
|
|
f->slotListResult( subfolderNames, subfolderPaths,
|
|
subfolderMimeTypes, subfolderAttributes, jobData );
|
|
}
|
|
}
|
|
kmkernel->imapFolderMgr()->contentsChanged();
|
|
}
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
bool KMFolderImap::listDirectory()
|
|
{
|
|
if ( !account() ||
|
|
( account() && account()->makeConnection() == ImapAccountBase::Error ) )
|
|
{
|
|
kdDebug(5006) << "KMFolderImap::listDirectory - got no connection" << endl;
|
|
return false;
|
|
}
|
|
|
|
if ( this == account()->rootFolder() )
|
|
{
|
|
// a new listing started
|
|
slotListNamespaces();
|
|
return true;
|
|
}
|
|
mSubfolderState = imapListingInProgress;
|
|
|
|
// get the folders
|
|
ImapAccountBase::ListType type = ImapAccountBase::List;
|
|
if ( account()->onlySubscribedFolders() )
|
|
type = ImapAccountBase::ListSubscribed;
|
|
KMail::ListJob* job = new KMail::ListJob( account(), type, this );
|
|
job->setParentProgressItem( account()->listDirProgressItem() );
|
|
job->setHonorLocalSubscription( true );
|
|
connect( job, SIGNAL(receivedFolders(const QStringList&, const QStringList&,
|
|
const QStringList&, const QStringList&, const ImapAccountBase::jobData&)),
|
|
this, SLOT(slotListResult(const QStringList&, const QStringList&,
|
|
const QStringList&, const QStringList&, const ImapAccountBase::jobData&)));
|
|
job->start();
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void KMFolderImap::slotListResult( const QStringList& subfolderNames,
|
|
const QStringList& subfolderPaths,
|
|
const QStringList& subfolderMimeTypes,
|
|
const QStringList& subfolderAttributes,
|
|
const ImapAccountBase::jobData& jobData )
|
|
{
|
|
mSubfolderState = imapFinished;
|
|
//kdDebug(5006) << label() << ": folderNames=" << subfolderNames << " folderPaths="
|
|
//<< subfolderPaths << " mimeTypes=" << subfolderMimeTypes << endl;
|
|
|
|
// don't react on changes
|
|
kmkernel->imapFolderMgr()->quiet(true);
|
|
|
|
bool root = ( this == account()->rootFolder() );
|
|
folder()->createChildFolder();
|
|
if ( root && !account()->hasInbox() )
|
|
{
|
|
// create the INBOX
|
|
initInbox();
|
|
}
|
|
|
|
// see if we have a better parent
|
|
// if you have a prefix that contains a folder (e.g "INBOX.") the folders
|
|
// need to be created underneath it
|
|
if ( root && !subfolderNames.empty() )
|
|
{
|
|
KMFolderImap* parent = findParent( subfolderPaths.first(), subfolderNames.first() );
|
|
if ( parent )
|
|
{
|
|
kdDebug(5006) << "KMFolderImap::slotListResult - pass listing to "
|
|
<< parent->label() << endl;
|
|
parent->slotListResult( subfolderNames, subfolderPaths,
|
|
subfolderMimeTypes, subfolderAttributes, jobData );
|
|
// cleanup
|
|
QStringList list;
|
|
checkFolders( list, jobData.curNamespace );
|
|
// finish
|
|
emit directoryListingFinished( this );
|
|
kmkernel->imapFolderMgr()->quiet( false );
|
|
return;
|
|
}
|
|
}
|
|
|
|
bool emptyList = ( root && subfolderNames.empty() );
|
|
if ( !emptyList )
|
|
{
|
|
checkFolders( subfolderNames, jobData.curNamespace );
|
|
}
|
|
|
|
KMFolderImap *f = 0;
|
|
KMFolderNode *node = 0;
|
|
for ( uint i = 0; i < subfolderNames.count(); i++ )
|
|
{
|
|
bool settingsChanged = false;
|
|
// create folders if necessary
|
|
for ( node = folder()->child()->first(); node;
|
|
node = folder()->child()->next() ) {
|
|
if ( !node->isDir() && node->name() == subfolderNames[i] )
|
|
break;
|
|
}
|
|
if ( node ) {
|
|
f = static_cast<KMFolderImap*>(static_cast<KMFolder*>(node)->storage());
|
|
}
|
|
else if ( subfolderPaths[i].upper() != "/INBOX/" )
|
|
{
|
|
kdDebug(5006) << "create folder " << subfolderNames[i] << endl;
|
|
KMFolder *fld = folder()->child()->createFolder(subfolderNames[i]);
|
|
if ( fld ) {
|
|
f = static_cast<KMFolderImap*> ( fld->storage() );
|
|
f->close( "kmfolderimap_create" );
|
|
settingsChanged = true;
|
|
} else {
|
|
kdWarning(5006) << "can't create folder " << subfolderNames[i] << endl;
|
|
}
|
|
}
|
|
if ( f )
|
|
{
|
|
// sanity check
|
|
if ( f->imapPath().isEmpty() ) {
|
|
settingsChanged = true;
|
|
}
|
|
// update progress
|
|
account()->listDirProgressItem()->incCompletedItems();
|
|
account()->listDirProgressItem()->updateProgress();
|
|
account()->listDirProgressItem()->setStatus( folder()->prettyURL() + i18n(" completed") );
|
|
|
|
f->initializeFrom( this, subfolderPaths[i], subfolderMimeTypes[i] );
|
|
f->setChildrenState( subfolderAttributes[i] );
|
|
if ( account()->listOnlyOpenFolders() &&
|
|
f->hasChildren() != FolderStorage::ChildrenUnknown )
|
|
{
|
|
settingsChanged = true;
|
|
}
|
|
|
|
if ( settingsChanged )
|
|
{
|
|
// tell the tree our information changed
|
|
kmkernel->imapFolderMgr()->contentsChanged();
|
|
}
|
|
if ( ( subfolderMimeTypes[i] == "message/directory" ||
|
|
subfolderMimeTypes[i] == "inode/directory" ) &&
|
|
!account()->listOnlyOpenFolders() )
|
|
{
|
|
f->listDirectory();
|
|
}
|
|
} else {
|
|
kdWarning(5006) << "can't find folder " << subfolderNames[i] << endl;
|
|
}
|
|
} // for subfolders
|
|
|
|
// now others should react on the changes
|
|
kmkernel->imapFolderMgr()->quiet( false );
|
|
emit directoryListingFinished( this );
|
|
account()->listDirProgressItem()->setComplete();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void KMFolderImap::initInbox()
|
|
{
|
|
KMFolderImap *f = 0;
|
|
KMFolderNode *node = 0;
|
|
|
|
for (node = folder()->child()->first(); node;
|
|
node = folder()->child()->next()) {
|
|
if (!node->isDir() && node->name() == "INBOX") break;
|
|
}
|
|
if (node) {
|
|
f = static_cast<KMFolderImap*>(static_cast<KMFolder*>(node)->storage());
|
|
} else {
|
|
f = static_cast<KMFolderImap*>
|
|
(folder()->child()->createFolder("INBOX", true)->storage());
|
|
if ( f )
|
|
{
|
|
f->folder()->setLabel( i18n("inbox") );
|
|
f->close( "kmfolderimap" );
|
|
}
|
|
kmkernel->imapFolderMgr()->contentsChanged();
|
|
}
|
|
if ( f ) {
|
|
f->initializeFrom( this, "/INBOX/", "message/directory" );
|
|
f->setChildrenState( QString::null );
|
|
}
|
|
// so we have an INBOX
|
|
account()->setHasInbox( true );
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
KMFolderImap* KMFolderImap::findParent( const QString& path, const QString& name )
|
|
{
|
|
QString parent = path.left( path.length() - name.length() - 2 );
|
|
if ( parent.length() > 1 )
|
|
{
|
|
// extract name of the parent
|
|
parent = parent.right( parent.length() - 1 );
|
|
if ( parent != label() )
|
|
{
|
|
KMFolderNode *node = folder()->child()->first();
|
|
// look for a better parent
|
|
while ( node )
|
|
{
|
|
if ( node->name() == parent )
|
|
{
|
|
KMFolder* fld = static_cast<KMFolder*>(node);
|
|
KMFolderImap* imapFld = static_cast<KMFolderImap*>( fld->storage() );
|
|
return imapFld;
|
|
}
|
|
node = folder()->child()->next();
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void KMFolderImap::checkFolders( const QStringList& subfolderNames,
|
|
const QString& myNamespace )
|
|
{
|
|
QPtrList<KMFolder> toRemove;
|
|
KMFolderNode *node = folder()->child()->first();
|
|
while ( node )
|
|
{
|
|
if ( !node->isDir() && subfolderNames.findIndex(node->name()) == -1 )
|
|
{
|
|
KMFolder* fld = static_cast<KMFolder*>(node);
|
|
KMFolderImap* imapFld = static_cast<KMFolderImap*>( fld->storage() );
|
|
// as more than one namespace can be listed in the root folder we need to make sure
|
|
// that the folder is within the current namespace
|
|
bool isInNamespace = ( myNamespace.isEmpty() ||
|
|
myNamespace == account()->namespaceForFolder( imapFld ) );
|
|
kdDebug(5006) << node->name() << " in namespace " << myNamespace << ":" <<
|
|
isInNamespace << endl;
|
|
// ignore some cases
|
|
QString name = node->name();
|
|
bool ignore = ( ( this == account()->rootFolder() ) &&
|
|
( imapFld->imapPath() == "/INBOX/" ||
|
|
account()->isNamespaceFolder( name ) ||
|
|
!isInNamespace ) );
|
|
// additional sanity check for broken folders
|
|
if ( imapFld->imapPath().isEmpty() ) {
|
|
ignore = false;
|
|
}
|
|
if ( !ignore )
|
|
{
|
|
// remove the folder without server round trip
|
|
kdDebug(5006) << "checkFolders - " << node->name() << " disappeared" << endl;
|
|
imapFld->setAlreadyRemoved( true );
|
|
toRemove.append( fld );
|
|
} else {
|
|
kdDebug(5006) << "checkFolders - " << node->name() << " ignored" << endl;
|
|
}
|
|
}
|
|
node = folder()->child()->next();
|
|
}
|
|
// remove folders
|
|
for ( KMFolder* doomed=toRemove.first(); doomed; doomed = toRemove.next() )
|
|
kmkernel->imapFolderMgr()->remove( doomed );
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void KMFolderImap::initializeFrom( KMFolderImap* parent, QString folderPath,
|
|
QString mimeType )
|
|
{
|
|
setAccount( parent->account() );
|
|
setImapPath( folderPath );
|
|
setNoContent( mimeType == "inode/directory" );
|
|
setNoChildren( mimeType == "message/digest" );
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void KMFolderImap::setChildrenState( QString attributes )
|
|
{
|
|
// update children state
|
|
if ( attributes.find( "haschildren", 0, false ) != -1 )
|
|
{
|
|
setHasChildren( FolderStorage::HasChildren );
|
|
} else if ( attributes.find( "hasnochildren", 0, false ) != -1 ||
|
|
attributes.find( "noinferiors", 0, false ) != -1 )
|
|
{
|
|
setHasChildren( FolderStorage::HasNoChildren );
|
|
} else
|
|
{
|
|
if ( account()->listOnlyOpenFolders() ) {
|
|
setHasChildren( FolderStorage::HasChildren );
|
|
} else {
|
|
setHasChildren( FolderStorage::ChildrenUnknown );
|
|
}
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void KMFolderImap::checkValidity()
|
|
{
|
|
if (!account()) {
|
|
emit folderComplete(this, false);
|
|
close("checkvalidity");
|
|
return;
|
|
}
|
|
KURL url = account()->getUrl();
|
|
url.setPath(imapPath() + ";UID=0:0");
|
|
kdDebug(5006) << "KMFolderImap::checkValidity of: " << imapPath() << endl;
|
|
|
|
// Start with a clean slate
|
|
disconnect( account(), SIGNAL( connectionResult(int, const QString&) ),
|
|
this, SLOT( checkValidity() ) );
|
|
|
|
KMAcctImap::ConnectionState connectionState = account()->makeConnection();
|
|
if ( connectionState == ImapAccountBase::Error ) {
|
|
kdDebug(5006) << "KMFolderImap::checkValidity - got no connection" << endl;
|
|
emit folderComplete(this, false);
|
|
mContentState = imapNoInformation;
|
|
close("checkvalidity");
|
|
return;
|
|
} else if ( connectionState == ImapAccountBase::Connecting ) {
|
|
// We'll wait for the connectionResult signal from the account. If it
|
|
// errors, the above will catch it.
|
|
kdDebug(5006) << "CheckValidity - waiting for connection" << endl;
|
|
connect( account(), SIGNAL( connectionResult(int, const QString&) ),
|
|
this, SLOT( checkValidity() ) );
|
|
return;
|
|
}
|
|
// Only check once at a time.
|
|
if (mCheckingValidity) {
|
|
kdDebug(5006) << "KMFolderImap::checkValidity - already checking" << endl;
|
|
close("checkvalidity");
|
|
return;
|
|
}
|
|
// otherwise we already are inside a mailcheck
|
|
if ( !mMailCheckProgressItem ) {
|
|
ProgressItem* parent = ( account()->checkingSingleFolder() ? 0 :
|
|
account()->mailCheckProgressItem() );
|
|
mMailCheckProgressItem = ProgressManager::createProgressItem(
|
|
parent,
|
|
"MailCheck" + folder()->prettyURL(),
|
|
QStyleSheet::escape( folder()->prettyURL() ),
|
|
i18n("checking"),
|
|
false,
|
|
account()->useSSL() || account()->useTLS() );
|
|
} else {
|
|
mMailCheckProgressItem->setProgress(0);
|
|
}
|
|
if ( account()->mailCheckProgressItem() ) {
|
|
account()->mailCheckProgressItem()->setStatus( folder()->prettyURL() );
|
|
}
|
|
ImapAccountBase::jobData jd( url.url() );
|
|
KIO::SimpleJob *job = KIO::get(url, false, false);
|
|
KIO::Scheduler::assignJobToSlave(account()->slave(), job);
|
|
account()->insertJob(job, jd);
|
|
connect(job, SIGNAL(result(KIO::Job *)),
|
|
SLOT(slotCheckValidityResult(KIO::Job *)));
|
|
connect(job, SIGNAL(data(KIO::Job *, const QByteArray &)),
|
|
SLOT(slotSimpleData(KIO::Job *, const QByteArray &)));
|
|
// Only check once at a time.
|
|
mCheckingValidity = true;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
ulong KMFolderImap::lastUid()
|
|
{
|
|
if ( mLastUid > 0 )
|
|
return mLastUid;
|
|
open("lastuid");
|
|
if (count() > 0)
|
|
{
|
|
KMMsgBase * base = getMsgBase(count()-1);
|
|
mLastUid = base->UID();
|
|
}
|
|
close("lastuid");
|
|
return mLastUid;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void KMFolderImap::slotCheckValidityResult(KIO::Job * job)
|
|
{
|
|
kdDebug(5006) << "KMFolderImap::slotCheckValidityResult of: " << fileName() << endl;
|
|
mCheckingValidity = false;
|
|
ImapAccountBase::JobIterator it = account()->findJob(job);
|
|
if ( it == account()->jobsEnd() ) return;
|
|
if (job->error()) {
|
|
if ( job->error() != KIO::ERR_ACCESS_DENIED ) {
|
|
// we suppress access denied messages because they are normally a result of
|
|
// explicitely set ACLs. Do not save this information (e.g. setNoContent) so that
|
|
// we notice when this changes
|
|
account()->handleJobError( job, i18n("Error while querying the server status.") );
|
|
}
|
|
mContentState = imapNoInformation;
|
|
emit folderComplete(this, false);
|
|
close("checkvalidity");
|
|
} else {
|
|
QCString cstr((*it).data.data(), (*it).data.size() + 1);
|
|
int a = cstr.find("X-uidValidity: ");
|
|
int b = cstr.find("\r\n", a);
|
|
QString uidv;
|
|
if ( (b - a - 15) >= 0 )
|
|
uidv = cstr.mid(a + 15, b - a - 15);
|
|
a = cstr.find("X-Access: ");
|
|
b = cstr.find("\r\n", a);
|
|
QString access;
|
|
if ( (b - a - 10) >= 0 )
|
|
access = cstr.mid(a + 10, b - a - 10);
|
|
mReadOnly = access == "Read only";
|
|
a = cstr.find("X-Count: ");
|
|
b = cstr.find("\r\n", a);
|
|
int exists = -1;
|
|
bool ok = false;
|
|
if ( (b - a - 9) >= 0 )
|
|
exists = cstr.mid(a + 9, b - a - 9).toInt(&ok);
|
|
if ( !ok ) exists = -1;
|
|
a = cstr.find( "X-PermanentFlags: " );
|
|
b = cstr.find( "\r\n", a );
|
|
if ( a >= 0 && (b - a - 18) >= 0 )
|
|
mPermanentFlags = cstr.mid( a + 18, b - a - 18 ).toInt(&ok);
|
|
if ( !ok ) mPermanentFlags = 0;
|
|
QString startUid;
|
|
if (uidValidity() != uidv)
|
|
{
|
|
// uidValidity changed
|
|
kdDebug(5006) << k_funcinfo << "uidValidty changed from "
|
|
<< uidValidity() << " to " << uidv << endl;
|
|
if ( !uidValidity().isEmpty() )
|
|
{
|
|
account()->ignoreJobsForFolder( folder() );
|
|
mUidMetaDataMap.clear();
|
|
}
|
|
mLastUid = 0;
|
|
setUidValidity(uidv);
|
|
writeConfig();
|
|
} else {
|
|
if (!mCheckFlags)
|
|
startUid = QString::number(lastUid() + 1);
|
|
}
|
|
account()->removeJob(it);
|
|
if ( mMailCheckProgressItem )
|
|
{
|
|
if ( startUid.isEmpty() ) {
|
|
// flags for all messages are loaded
|
|
mMailCheckProgressItem->setTotalItems( exists );
|
|
} else {
|
|
// only an approximation but doesn't hurt
|
|
int remain = exists - count();
|
|
if ( remain < 0 ) remain = 1;
|
|
mMailCheckProgressItem->setTotalItems( remain );
|
|
}
|
|
mMailCheckProgressItem->setCompletedItems( 0 );
|
|
}
|
|
reallyGetFolder(startUid);
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void KMFolderImap::getAndCheckFolder(bool force)
|
|
{
|
|
if (mNoContent)
|
|
return getFolder(force);
|
|
|
|
if ( account() )
|
|
account()->processNewMailSingleFolder( folder() );
|
|
if (force) {
|
|
// force an update
|
|
mCheckFlags = true;
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void KMFolderImap::getFolder(bool force)
|
|
{
|
|
mGuessedUnreadMsgs = -1;
|
|
if (mNoContent)
|
|
{
|
|
mContentState = imapFinished;
|
|
emit folderComplete(this, true);
|
|
return;
|
|
}
|
|
open("getfolder");
|
|
mContentState = imapListingInProgress;
|
|
if (force) {
|
|
// force an update
|
|
mCheckFlags = true;
|
|
}
|
|
checkValidity();
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void KMFolderImap::reallyGetFolder(const QString &startUid)
|
|
{
|
|
KURL url = account()->getUrl();
|
|
if ( account()->makeConnection() != ImapAccountBase::Connected )
|
|
{
|
|
mContentState = imapNoInformation;
|
|
emit folderComplete(this, false);
|
|
close("listfolder");
|
|
return;
|
|
}
|
|
quiet(true);
|
|
if (startUid.isEmpty())
|
|
{
|
|
if ( mMailCheckProgressItem )
|
|
mMailCheckProgressItem->setStatus( i18n("Retrieving message status") );
|
|
url.setPath(imapPath() + ";SECTION=UID FLAGS");
|
|
KIO::SimpleJob *job = KIO::listDir(url, false);
|
|
KIO::Scheduler::assignJobToSlave(account()->slave(), job);
|
|
ImapAccountBase::jobData jd( url.url(), folder() );
|
|
jd.cancellable = true;
|
|
account()->insertJob(job, jd);
|
|
connect(job, SIGNAL(result(KIO::Job *)),
|
|
this, SLOT(slotListFolderResult(KIO::Job *)));
|
|
connect(job, SIGNAL(entries(KIO::Job *, const KIO::UDSEntryList &)),
|
|
this, SLOT(slotListFolderEntries(KIO::Job *,
|
|
const KIO::UDSEntryList &)));
|
|
} else {
|
|
mContentState = imapDownloadInProgress;
|
|
if ( mMailCheckProgressItem )
|
|
mMailCheckProgressItem->setStatus( i18n("Retrieving messages") );
|
|
url.setPath(imapPath() + ";UID=" + startUid
|
|
+ ":*;SECTION=ENVELOPE");
|
|
KIO::SimpleJob *newJob = KIO::get(url, false, false);
|
|
KIO::Scheduler::assignJobToSlave(account()->slave(), newJob);
|
|
ImapAccountBase::jobData jd( url.url(), folder() );
|
|
jd.cancellable = true;
|
|
account()->insertJob(newJob, jd);
|
|
connect(newJob, SIGNAL(result(KIO::Job *)),
|
|
this, SLOT(slotGetLastMessagesResult(KIO::Job *)));
|
|
connect(newJob, SIGNAL(data(KIO::Job *, const QByteArray &)),
|
|
this, SLOT(slotGetMessagesData(KIO::Job *, const QByteArray &)));
|
|
}
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void KMFolderImap::slotListFolderResult(KIO::Job * job)
|
|
{
|
|
ImapAccountBase::JobIterator it = account()->findJob(job);
|
|
if ( it == account()->jobsEnd() ) return;
|
|
QString uids;
|
|
if (job->error())
|
|
{
|
|
account()->handleJobError( job,
|
|
i18n("Error while listing the contents of the folder %1.").arg( label() ) );
|
|
account()->removeJob(it);
|
|
finishMailCheck( "listfolder", imapNoInformation );
|
|
return;
|
|
}
|
|
mCheckFlags = false;
|
|
QStringList::Iterator uid;
|
|
/*
|
|
The code below does the following:
|
|
- for each mail in the local store and each entry we got from the server,
|
|
compare the local uid with the one from the server and update the status
|
|
flags of the mails
|
|
- for all mails that are not already locally present, start a job which
|
|
gets the envelope of each
|
|
- remove all locally present mails if the server does not list them anymore
|
|
*/
|
|
if ( count() ) {
|
|
int idx = 0, c, serverFlags;
|
|
ulong mailUid, serverUid;
|
|
uid = (*it).items.begin();
|
|
while ( idx < count() && uid != (*it).items.end() ) {
|
|
KMMsgBase *msgBase = getMsgBase( idx );
|
|
mailUid = msgBase->UID();
|
|
// parse the uid from the server and the flags out of the list from
|
|
// the server. Format: 1234, 1
|
|
c = (*uid).find(",");
|
|
serverUid = (*uid).left( c ).toLong();
|
|
serverFlags = (*uid).mid( c+1 ).toInt();
|
|
if ( mailUid < serverUid ) {
|
|
removeMsg( idx, true );
|
|
} else if ( mailUid == serverUid ) {
|
|
// if this is a read only folder, ignore status updates from the server
|
|
// since we can't write our status back our local version is what has to
|
|
// be considered correct.
|
|
if ( !mReadOnly || !GlobalSettings::allowLocalFlags() ) {
|
|
int supportedFlags = mUploadAllFlags ? 31 : mPermanentFlags;
|
|
if ( mReadOnly )
|
|
supportedFlags = INT_MAX;
|
|
flagsToStatus( msgBase, serverFlags, false, supportedFlags );
|
|
} else
|
|
seenFlagToStatus( msgBase, serverFlags, false );
|
|
idx++;
|
|
uid = (*it).items.remove(uid);
|
|
if ( msgBase->getMsgSerNum() > 0 ) {
|
|
saveMsgMetaData( static_cast<KMMessage*>(msgBase) );
|
|
}
|
|
}
|
|
else break; // happens only, if deleted mails reappear on the server
|
|
}
|
|
// remove all remaining entries in the local cache, they are no longer
|
|
// present on the server
|
|
while (idx < count()) removeMsg(idx, true);
|
|
}
|
|
// strip the flags from the list of uids, so it can be reused
|
|
for (uid = (*it).items.begin(); uid != (*it).items.end(); ++uid)
|
|
(*uid).truncate((*uid).find(","));
|
|
ImapAccountBase::jobData jd( QString::null, (*it).parent );
|
|
jd.total = (*it).items.count();
|
|
if (jd.total == 0)
|
|
{
|
|
finishMailCheck( "listfolder", imapFinished );
|
|
account()->removeJob(it);
|
|
return;
|
|
}
|
|
if ( mMailCheckProgressItem )
|
|
{
|
|
// next step for the progressitem
|
|
mMailCheckProgressItem->setCompletedItems( 0 );
|
|
mMailCheckProgressItem->setTotalItems( jd.total );
|
|
mMailCheckProgressItem->setProgress( 0 );
|
|
mMailCheckProgressItem->setStatus( i18n("Retrieving messages") );
|
|
}
|
|
|
|
QStringList sets;
|
|
uid = (*it).items.begin();
|
|
if (jd.total == 1) sets.append(*uid + ":" + *uid);
|
|
else sets = makeSets( (*it).items );
|
|
account()->removeJob(it); // don't use *it below
|
|
|
|
// Now kick off the getting of envelopes for the new mails in the folder
|
|
for (QStringList::Iterator i = sets.begin(); i != sets.end(); ++i)
|
|
{
|
|
mContentState = imapDownloadInProgress;
|
|
KURL url = account()->getUrl();
|
|
url.setPath(imapPath() + ";UID=" + *i + ";SECTION=ENVELOPE");
|
|
KIO::SimpleJob *newJob = KIO::get(url, false, false);
|
|
jd.url = url.url();
|
|
KIO::Scheduler::assignJobToSlave(account()->slave(), newJob);
|
|
account()->insertJob(newJob, jd);
|
|
connect(newJob, SIGNAL(result(KIO::Job *)),
|
|
this, (i == sets.at(sets.count() - 1))
|
|
? SLOT(slotGetLastMessagesResult(KIO::Job *))
|
|
: SLOT(slotGetMessagesResult(KIO::Job *)));
|
|
connect(newJob, SIGNAL(data(KIO::Job *, const QByteArray &)),
|
|
this, SLOT(slotGetMessagesData(KIO::Job *, const QByteArray &)));
|
|
}
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void KMFolderImap::slotListFolderEntries(KIO::Job * job,
|
|
const KIO::UDSEntryList & uds)
|
|
{
|
|
ImapAccountBase::JobIterator it = account()->findJob(job);
|
|
if ( it == account()->jobsEnd() ) return;
|
|
QString mimeType, name;
|
|
long int flags = 0;
|
|
for (KIO::UDSEntryList::ConstIterator udsIt = uds.begin();
|
|
udsIt != uds.end(); udsIt++)
|
|
{
|
|
for (KIO::UDSEntry::ConstIterator eIt = (*udsIt).begin();
|
|
eIt != (*udsIt).end(); eIt++)
|
|
{
|
|
if ((*eIt).m_uds == KIO::UDS_NAME)
|
|
name = (*eIt).m_str;
|
|
else if ((*eIt).m_uds == KIO::UDS_MIME_TYPE)
|
|
mimeType = (*eIt).m_str;
|
|
else if ((*eIt).m_uds == KIO::UDS_ACCESS)
|
|
flags = (*eIt).m_long;
|
|
}
|
|
if ((mimeType == "message/rfc822-imap" || mimeType == "message/rfc822") &&
|
|
!(flags & 8)) {
|
|
(*it).items.append(name + "," + QString::number(flags));
|
|
if ( mMailCheckProgressItem ) {
|
|
mMailCheckProgressItem->incCompletedItems();
|
|
mMailCheckProgressItem->updateProgress();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// debugging helper
|
|
//X static QString flagsToString( int flags )
|
|
//X {
|
|
//X QString str("(");
|
|
//X if ( flags & 4 ) {
|
|
//X str += "\\Flagged ";
|
|
//X }
|
|
//X if ( flags & 2 ) {
|
|
//X str += "\\Answered ";
|
|
//X }
|
|
//X if ( flags & 1 ) {
|
|
//X str += "\\Seen";
|
|
//X }
|
|
//X str += ")";
|
|
//X return str;
|
|
//X }
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void KMFolderImap::flagsToStatus(KMMsgBase *msg, int flags, bool newMsg, int supportedFlags )
|
|
{
|
|
if ( !msg ) return;
|
|
|
|
// see imap4/imapinfo.h for the magic numbers
|
|
static const struct {
|
|
const int imapFlag;
|
|
const int kmFlag;
|
|
const bool standardFlag;
|
|
} imapFlagMap[] = {
|
|
{ 2, KMMsgStatusReplied, true },
|
|
{ 4, KMMsgStatusFlag, true },
|
|
{ 128, KMMsgStatusForwarded, false },
|
|
{ 256, KMMsgStatusTodo, false },
|
|
{ 512, KMMsgStatusWatched, false },
|
|
{ 1024, KMMsgStatusIgnored, false }
|
|
};
|
|
static const int numFlags = sizeof imapFlagMap / sizeof *imapFlagMap;
|
|
|
|
const KMMsgStatus oldStatus = msg->status();
|
|
for ( int i = 0; i < numFlags; ++i ) {
|
|
if ( ( (supportedFlags & imapFlagMap[i].imapFlag) == 0 && (supportedFlags & 64) == 0 )
|
|
&& !imapFlagMap[i].standardFlag ) {
|
|
continue;
|
|
}
|
|
if ( ((flags & imapFlagMap[i].imapFlag) > 0) != ((oldStatus & imapFlagMap[i].kmFlag) > 0) ) {
|
|
msg->toggleStatus( imapFlagMap[i].kmFlag );
|
|
}
|
|
}
|
|
|
|
seenFlagToStatus( msg, flags, newMsg );
|
|
}
|
|
|
|
void KMFolderImap::seenFlagToStatus(KMMsgBase * msg, int flags, bool newMsg)
|
|
{
|
|
if ( !msg ) return;
|
|
|
|
const KMMsgStatus oldStatus = msg->status();
|
|
if ( (flags & 1) && (oldStatus & KMMsgStatusOld) == 0 )
|
|
msg->setStatus( KMMsgStatusOld );
|
|
|
|
// In case the message does not have the seen flag set, override our local
|
|
// notion that it is read. Otherwise the count of unread messages and the
|
|
// number of messages which actually show up as read can go out of sync.
|
|
if ( msg->isOfUnknownStatus() || (!(flags&1) && !(oldStatus&(KMMsgStatusNew|KMMsgStatusUnread)) ) ) {
|
|
if (newMsg) {
|
|
if ( (oldStatus & KMMsgStatusNew) == 0 )
|
|
msg->setStatus( KMMsgStatusNew );
|
|
} else {
|
|
if ( (oldStatus & KMMsgStatusUnread) == 0 )
|
|
msg->setStatus( KMMsgStatusUnread );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
QString KMFolderImap::statusToFlags(KMMsgStatus status, int supportedFlags)
|
|
{
|
|
QString flags;
|
|
if (status & KMMsgStatusDeleted)
|
|
flags = "\\DELETED";
|
|
else {
|
|
if (status & KMMsgStatusOld || status & KMMsgStatusRead)
|
|
flags = "\\SEEN ";
|
|
if (status & KMMsgStatusReplied)
|
|
flags += "\\ANSWERED ";
|
|
if (status & KMMsgStatusFlag)
|
|
flags += "\\FLAGGED ";
|
|
// non standard flags
|
|
if ( (status & KMMsgStatusForwarded) && ((supportedFlags & 64) || (supportedFlags & 128)) )
|
|
flags += "$FORWARDED ";
|
|
if ( (status & KMMsgStatusTodo) && ((supportedFlags & 64) || (supportedFlags & 256)) )
|
|
flags += "$TODO ";
|
|
if ( (status & KMMsgStatusWatched) && ((supportedFlags & 64) || (supportedFlags & 512)) )
|
|
flags += "$WATCHED ";
|
|
if ( (status & KMMsgStatusIgnored) && ((supportedFlags & 64) || (supportedFlags & 1024)) )
|
|
flags += "$IGNORED ";
|
|
}
|
|
|
|
return flags.simplifyWhiteSpace();
|
|
}
|
|
|
|
//-------------------------------------------------------------
|
|
void
|
|
KMFolderImap::ignoreJobsForMessage( KMMessage* msg )
|
|
{
|
|
if ( !msg || msg->transferInProgress() ||
|
|
!msg->parent() || msg->parent()->folderType() != KMFolderTypeImap )
|
|
return;
|
|
KMAcctImap *account;
|
|
if ( !(account = static_cast<KMFolderImap*>(msg->storage())->account()) )
|
|
return;
|
|
|
|
account->ignoreJobsForMessage( msg );
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void KMFolderImap::slotGetMessagesData(KIO::Job * job, const QByteArray & data)
|
|
{
|
|
if ( data.isEmpty() ) return; // optimization
|
|
ImapAccountBase::JobIterator it = account()->findJob(job);
|
|
if ( it == account()->jobsEnd() ) return;
|
|
(*it).cdata += QCString(data, data.size() + 1);
|
|
int pos = (*it).cdata.find("\r\n--IMAPDIGEST");
|
|
if ( pos == -1 ) {
|
|
// if we do not find the pattern in the complete string we will not find
|
|
// it in a substring.
|
|
return;
|
|
}
|
|
if (pos > 0)
|
|
{
|
|
int p = (*it).cdata.find("\r\nX-uidValidity:");
|
|
if (p != -1) setUidValidity((*it).cdata
|
|
.mid(p + 17, (*it).cdata.find("\r\n", p+1) - p - 17));
|
|
int c = (*it).cdata.find("\r\nX-Count:");
|
|
if ( c != -1 )
|
|
{
|
|
bool ok;
|
|
int exists = (*it).cdata.mid( c+10,
|
|
(*it).cdata.find("\r\n", c+1) - c-10 ).toInt(&ok);
|
|
if ( ok && exists < count() ) {
|
|
kdDebug(5006) << "KMFolderImap::slotGetMessagesData - server has less messages (" <<
|
|
exists << ") then folder (" << count() << "), so reload" << endl;
|
|
open("getMessage");
|
|
reallyGetFolder( QString::null );
|
|
(*it).cdata.remove(0, pos);
|
|
return;
|
|
} else if ( ok ) {
|
|
int delta = exists - count();
|
|
if ( mMailCheckProgressItem ) {
|
|
mMailCheckProgressItem->setTotalItems( delta );
|
|
}
|
|
}
|
|
}
|
|
(*it).cdata.remove(0, pos);
|
|
}
|
|
pos = (*it).cdata.find("\r\n--IMAPDIGEST", 1);
|
|
int flags;
|
|
while (pos >= 0)
|
|
{
|
|
KMMessage *msg = new KMMessage;
|
|
msg->setComplete( false );
|
|
msg->setReadyToShow( false );
|
|
// nothing between the boundaries, older UWs do that
|
|
if ( pos != 14 ) {
|
|
msg->fromString( (*it).cdata.mid(16, pos - 16) );
|
|
flags = msg->headerField("X-Flags").toInt();
|
|
ulong uid = msg->UID();
|
|
KMMsgMetaData *md = 0;
|
|
if ( mUidMetaDataMap.find( uid ) ) {
|
|
md = mUidMetaDataMap[uid];
|
|
}
|
|
ulong serNum = 0;
|
|
if ( md ) {
|
|
serNum = md->serNum();
|
|
}
|
|
bool ok = true;
|
|
if ( uid <= lastUid() && serNum > 0 ) {
|
|
// the UID is already known so no need to create it
|
|
ok = false;
|
|
}
|
|
// deleted flag
|
|
if ( flags & 8 )
|
|
ok = false;
|
|
if ( !ok ) {
|
|
delete msg;
|
|
msg = 0;
|
|
} else {
|
|
if ( serNum > 0 ) {
|
|
// assign the sernum from the cache
|
|
msg->setMsgSerNum( serNum );
|
|
}
|
|
// Transfer the status, if it is cached.
|
|
if ( md ) {
|
|
msg->setStatus( md->status() );
|
|
} else if ( !account()->hasCapability("uidplus") ) {
|
|
// see if we have cached the msgIdMD5 and get the status +
|
|
// serial number from there
|
|
QString id = msg->msgIdMD5();
|
|
if ( mMetaDataMap.find( id ) ) {
|
|
md = mMetaDataMap[id];
|
|
msg->setStatus( md->status() );
|
|
if ( md->serNum() != 0 && serNum == 0 ) {
|
|
msg->setMsgSerNum( md->serNum() );
|
|
}
|
|
mMetaDataMap.remove( id );
|
|
delete md;
|
|
}
|
|
}
|
|
KMFolderMbox::addMsg(msg, 0);
|
|
// Merge with the flags from the server.
|
|
flagsToStatus((KMMsgBase*)msg, flags, true, mUploadAllFlags ? 31 : mPermanentFlags);
|
|
// set the correct size
|
|
msg->setMsgSizeServer( msg->headerField("X-Length").toUInt() );
|
|
msg->setUID(uid);
|
|
if ( msg->getMsgSerNum() > 0 ) {
|
|
saveMsgMetaData( msg );
|
|
}
|
|
// Filter messages that have arrived in the inbox folder
|
|
if ( folder()->isSystemFolder() && imapPath() == "/INBOX/"
|
|
&& kmkernel->filterMgr()->atLeastOneIncomingFilterAppliesTo( account()->id() ) )
|
|
account()->execFilters( msg->getMsgSerNum() );
|
|
|
|
if ( count() > 1 ) {
|
|
unGetMsg(count() - 1);
|
|
}
|
|
mLastUid = uid;
|
|
if ( mMailCheckProgressItem ) {
|
|
mMailCheckProgressItem->incCompletedItems();
|
|
mMailCheckProgressItem->updateProgress();
|
|
}
|
|
}
|
|
}
|
|
(*it).cdata.remove(0, pos);
|
|
(*it).done++;
|
|
pos = (*it).cdata.find("\r\n--IMAPDIGEST", 1);
|
|
} // while
|
|
}
|
|
|
|
//-------------------------------------------------------------
|
|
FolderJob*
|
|
KMFolderImap::doCreateJob( KMMessage *msg, FolderJob::JobType jt,
|
|
KMFolder *folder, QString partSpecifier,
|
|
const AttachmentStrategy *as ) const
|
|
{
|
|
KMFolderImap* kmfi = folder? dynamic_cast<KMFolderImap*>(folder->storage()) : 0;
|
|
if ( jt == FolderJob::tGetMessage && partSpecifier == "STRUCTURE" &&
|
|
account() && account()->loadOnDemand() &&
|
|
( msg->msgSizeServer() > 5000 || msg->msgSizeServer() == 0 ) &&
|
|
( msg->signatureState() == KMMsgNotSigned ||
|
|
msg->signatureState() == KMMsgSignatureStateUnknown ) &&
|
|
( msg->encryptionState() == KMMsgNotEncrypted ||
|
|
msg->encryptionState() == KMMsgEncryptionStateUnknown ) )
|
|
{
|
|
// load-on-demand: retrieve the BODYSTRUCTURE and to speed things up also the headers
|
|
// this is not activated for small or signed messages
|
|
ImapJob *job = new ImapJob( msg, jt, kmfi, "HEADER" );
|
|
job->start();
|
|
ImapJob *job2 = new ImapJob( msg, jt, kmfi, "STRUCTURE", as );
|
|
job2->start();
|
|
job->setParentFolder( this );
|
|
return job;
|
|
} else {
|
|
// download complete message or part (attachment)
|
|
if ( partSpecifier == "STRUCTURE" ) // hide from outside
|
|
partSpecifier = QString::null;
|
|
|
|
ImapJob *job = new ImapJob( msg, jt, kmfi, partSpecifier );
|
|
job->setParentFolder( this );
|
|
return job;
|
|
}
|
|
}
|
|
|
|
//-------------------------------------------------------------
|
|
FolderJob*
|
|
KMFolderImap::doCreateJob( QPtrList<KMMessage>& msgList, const QString& sets,
|
|
FolderJob::JobType jt, KMFolder *folder ) const
|
|
{
|
|
KMFolderImap* kmfi = dynamic_cast<KMFolderImap*>(folder->storage());
|
|
ImapJob *job = new ImapJob( msgList, sets, jt, kmfi );
|
|
job->setParentFolder( this );
|
|
return job;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void KMFolderImap::getMessagesResult(KIO::Job * job, bool lastSet)
|
|
{
|
|
ImapAccountBase::JobIterator it = account()->findJob(job);
|
|
if ( it == account()->jobsEnd() ) return;
|
|
if (job->error()) {
|
|
account()->handleJobError( job, i18n("Error while retrieving messages.") );
|
|
finishMailCheck( "getMessage", imapNoInformation );
|
|
return;
|
|
}
|
|
if (lastSet) {
|
|
finishMailCheck( "getMessage", imapFinished );
|
|
account()->removeJob(it);
|
|
}
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void KMFolderImap::slotGetLastMessagesResult(KIO::Job * job)
|
|
{
|
|
getMessagesResult(job, true);
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void KMFolderImap::slotGetMessagesResult(KIO::Job * job)
|
|
{
|
|
getMessagesResult(job, false);
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void KMFolderImap::createFolder(const QString &name, const QString& parentPath,
|
|
bool askUser)
|
|
{
|
|
kdDebug(5006) << "KMFolderImap::createFolder - name=" << name << ",parent=" <<
|
|
parentPath << ",askUser=" << askUser << endl;
|
|
if ( account()->makeConnection() != ImapAccountBase::Connected ) {
|
|
kdWarning(5006) << "KMFolderImap::createFolder - got no connection" << endl;
|
|
return;
|
|
}
|
|
KURL url = account()->getUrl();
|
|
QString parent = ( parentPath.isEmpty() ? imapPath() : parentPath );
|
|
QString path = account()->createImapPath( parent, name );
|
|
if ( askUser ) {
|
|
path += "/;INFO=ASKUSER";
|
|
}
|
|
url.setPath( path );
|
|
|
|
KIO::SimpleJob *job = KIO::mkdir(url);
|
|
KIO::Scheduler::assignJobToSlave(account()->slave(), job);
|
|
ImapAccountBase::jobData jd( url.url(), folder() );
|
|
jd.items = name;
|
|
account()->insertJob(job, jd);
|
|
connect(job, SIGNAL(result(KIO::Job *)),
|
|
this, SLOT(slotCreateFolderResult(KIO::Job *)));
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void KMFolderImap::slotCreateFolderResult(KIO::Job * job)
|
|
{
|
|
ImapAccountBase::JobIterator it = account()->findJob(job);
|
|
if ( it == account()->jobsEnd() ) return;
|
|
|
|
QString name;
|
|
if ( it.data().items.count() > 0 )
|
|
name = it.data().items.first();
|
|
|
|
if (job->error())
|
|
{
|
|
if ( job->error() == KIO::ERR_COULD_NOT_MKDIR ) {
|
|
// Creating a folder failed, remove it from the tree.
|
|
account()->listDirectory( );
|
|
}
|
|
account()->handleJobError( job, i18n("Error while creating a folder.") );
|
|
emit folderCreationResult( name, false );
|
|
} else {
|
|
listDirectory();
|
|
account()->removeJob(job);
|
|
emit folderCreationResult( name, true );
|
|
}
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
static QTextCodec *sUtf7Codec = 0;
|
|
|
|
QTextCodec * KMFolderImap::utf7Codec()
|
|
{
|
|
if (!sUtf7Codec) sUtf7Codec = QTextCodec::codecForName("utf-7");
|
|
return sUtf7Codec;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
QString KMFolderImap::encodeFileName(const QString &name)
|
|
{
|
|
QString result = utf7Codec()->fromUnicode(name);
|
|
return KURL::encode_string_no_slash(result);
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
QString KMFolderImap::decodeFileName(const QString &name)
|
|
{
|
|
QString result = KURL::decode_string(name);
|
|
return utf7Codec()->toUnicode(result.latin1());
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
bool KMFolderImap::autoExpunge()
|
|
{
|
|
if (account())
|
|
return account()->autoExpunge();
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void KMFolderImap::slotSimpleData(KIO::Job * job, const QByteArray & data)
|
|
{
|
|
if ( data.isEmpty() ) return; // optimization
|
|
ImapAccountBase::JobIterator it = account()->findJob(job);
|
|
if ( it == account()->jobsEnd() ) return;
|
|
QBuffer buff((*it).data);
|
|
buff.open(IO_WriteOnly | IO_Append);
|
|
buff.writeBlock(data.data(), data.size());
|
|
buff.close();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void KMFolderImap::deleteMessage(KMMessage * msg)
|
|
{
|
|
mUidMetaDataMap.remove( msg->UID() );
|
|
mMetaDataMap.remove( msg->msgIdMD5() );
|
|
KURL url = account()->getUrl();
|
|
KMFolderImap *msg_parent = static_cast<KMFolderImap*>(msg->storage());
|
|
ulong uid = msg->UID();
|
|
/* If the uid is empty the delete job below will nuke all mail in the
|
|
folder, so we better safeguard against that. See ::expungeFolder, as
|
|
to why. :( */
|
|
if ( uid == 0 ) {
|
|
kdDebug( 5006 ) << "KMFolderImap::deleteMessage: Attempt to delete "
|
|
"an empty UID. Aborting." << endl;
|
|
return;
|
|
}
|
|
url.setPath(msg_parent->imapPath() + ";UID=" + QString::number(uid) );
|
|
if ( account()->makeConnection() != ImapAccountBase::Connected )
|
|
return;
|
|
KIO::SimpleJob *job = KIO::file_delete(url, false);
|
|
KIO::Scheduler::assignJobToSlave(account()->slave(), job);
|
|
ImapAccountBase::jobData jd( url.url(), 0 );
|
|
account()->insertJob(job, jd);
|
|
connect(job, SIGNAL(result(KIO::Job *)),
|
|
account(), SLOT(slotSimpleResult(KIO::Job *)));
|
|
}
|
|
|
|
void KMFolderImap::deleteMessage(const QPtrList<KMMessage>& msgList)
|
|
{
|
|
QPtrListIterator<KMMessage> it( msgList );
|
|
KMMessage *msg;
|
|
while ( (msg = it.current()) != 0 ) {
|
|
++it;
|
|
mUidMetaDataMap.remove( msg->UID() );
|
|
mMetaDataMap.remove( msg->msgIdMD5() );
|
|
}
|
|
|
|
QValueList<ulong> uids;
|
|
getUids(msgList, uids);
|
|
QStringList sets = makeSets(uids);
|
|
|
|
KURL url = account()->getUrl();
|
|
KMFolderImap *msg_parent = static_cast<KMFolderImap*>(msgList.getFirst()->storage());
|
|
for ( QStringList::Iterator it = sets.begin(); it != sets.end(); ++it )
|
|
{
|
|
QString uid = *it;
|
|
// Don't delete with no uid, that nukes the folder. Should not happen, but
|
|
// better safe than sorry.
|
|
if ( uid.isEmpty() ) continue;
|
|
url.setPath(msg_parent->imapPath() + ";UID=" + uid);
|
|
if ( account()->makeConnection() != ImapAccountBase::Connected )
|
|
return;
|
|
KIO::SimpleJob *job = KIO::file_delete(url, false);
|
|
KIO::Scheduler::assignJobToSlave(account()->slave(), job);
|
|
ImapAccountBase::jobData jd( url.url(), 0 );
|
|
account()->insertJob(job, jd);
|
|
connect(job, SIGNAL(result(KIO::Job *)),
|
|
account(), SLOT(slotSimpleResult(KIO::Job *)));
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void KMFolderImap::setStatus(int idx, KMMsgStatus status, bool toggle)
|
|
{
|
|
QValueList<int> ids; ids.append(idx);
|
|
setStatus(ids, status, toggle);
|
|
}
|
|
|
|
void KMFolderImap::setStatus(QValueList<int>& _ids, KMMsgStatus status, bool toggle)
|
|
{
|
|
FolderStorage::setStatus(_ids, status, toggle);
|
|
QValueList<int> ids;
|
|
if ( mUploadAllFlags ) {
|
|
kdDebug(5006) << k_funcinfo << "Migrating all flags to the server" << endl;
|
|
ids.clear();
|
|
for ( int i = 0; i < count(); ++i )
|
|
ids << i;
|
|
mUploadAllFlags = false;
|
|
} else {
|
|
ids = _ids;
|
|
}
|
|
|
|
/* The status has been already set in the local index. Update the flags on
|
|
* the server. To avoid doing that for each message individually, group them
|
|
* by the status string they will be assigned and make sets for each of those
|
|
* groups of mails. This is necessary because the imap kio_slave status job
|
|
* does not append flags but overwrites them. Example:
|
|
*
|
|
* 2 important mails and 3 unimportant mail, all unread. Mark all as read calls
|
|
* this method with a list of uids. The 2 important mails need to get the string
|
|
* \SEEN \FLAGGED while the others need to get just \SEEN. Build sets for each
|
|
* of those and sort them, so the server can handle them efficiently. */
|
|
|
|
if ( mReadOnly ) { // mUserRights is not available here
|
|
// FIXME duplicated code in KMFolderCachedImap
|
|
QValueList<ulong> seenUids, unseenUids;
|
|
for ( QValueList<int>::ConstIterator it = ids.constBegin(); it != ids.constEnd(); ++it ) {
|
|
KMMessage *msg = 0;
|
|
bool unget = !isMessage(*it);
|
|
msg = getMsg(*it);
|
|
if (!msg) continue;
|
|
if ( msg->status() & KMMsgStatusOld || msg->status() & KMMsgStatusRead )
|
|
seenUids.append( msg->UID() );
|
|
else
|
|
unseenUids.append( msg->UID() );
|
|
if (unget) unGetMsg(*it);
|
|
}
|
|
if ( !seenUids.isEmpty() ) {
|
|
QStringList sets = KMFolderImap::makeSets( seenUids, true );
|
|
for( QStringList::Iterator it = sets.begin(); it != sets.end(); ++it ) {
|
|
QString imappath = imapPath() + ";UID=" + ( *it );
|
|
account()->setImapSeenStatus( folder(), imappath, true );
|
|
}
|
|
}
|
|
if ( !unseenUids.isEmpty() ) {
|
|
QStringList sets = KMFolderImap::makeSets( unseenUids, true );
|
|
for( QStringList::Iterator it = sets.begin(); it != sets.end(); ++it ) {
|
|
QString imappath = imapPath() + ";UID=" + ( *it );
|
|
account()->setImapSeenStatus( folder(), imappath, false );
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
QMap< QString, QStringList > groups;
|
|
for ( QValueList<int>::Iterator it = ids.begin(); it != ids.end(); ++it ) {
|
|
KMMessage *msg = 0;
|
|
bool unget = !isMessage(*it);
|
|
msg = getMsg(*it);
|
|
if (!msg) continue;
|
|
QString flags = statusToFlags(msg->status(), mPermanentFlags);
|
|
// Collect uids for each type of flags.
|
|
groups[flags].append(QString::number(msg->UID()));
|
|
if (unget) unGetMsg(*it);
|
|
}
|
|
QMapIterator< QString, QStringList > dit;
|
|
for ( dit = groups.begin(); dit != groups.end(); ++dit ) {
|
|
QCString flags = dit.key().latin1();
|
|
QStringList sets = makeSets( (*dit), true );
|
|
// Send off a status setting job for each set.
|
|
for ( QStringList::Iterator slit = sets.begin(); slit != sets.end(); ++slit ) {
|
|
QString imappath = imapPath() + ";UID=" + ( *slit );
|
|
account()->setImapStatus(folder(), imappath, flags);
|
|
}
|
|
}
|
|
if ( mContentState == imapListingInProgress ) {
|
|
// we're currently get'ing this folder
|
|
// to make sure that we get the latest flags abort the current listing and
|
|
// create a new one
|
|
kdDebug(5006) << "Set status during folder listing, restarting listing." << endl;
|
|
disconnect(this, SLOT(slotListFolderResult(KIO::Job *)));
|
|
quiet( false );
|
|
reallyGetFolder( QString::null );
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
QStringList KMFolderImap::makeSets(const QStringList& uids, bool sort)
|
|
{
|
|
QValueList<ulong> tmp;
|
|
for ( QStringList::ConstIterator it = uids.begin(); it != uids.end(); ++it )
|
|
tmp.append( (*it).toInt() );
|
|
return makeSets(tmp, sort);
|
|
}
|
|
|
|
QStringList KMFolderImap::makeSets( QValueList<ulong>& uids, bool sort )
|
|
{
|
|
QStringList sets;
|
|
QString set;
|
|
|
|
if (uids.size() == 1)
|
|
{
|
|
sets.append(QString::number(uids.first()));
|
|
return sets;
|
|
}
|
|
|
|
if (sort) qHeapSort(uids);
|
|
|
|
ulong last = 0;
|
|
// needed to make a uid like 124 instead of 124:124
|
|
bool inserted = false;
|
|
/* iterate over uids and build sets like 120:122,124,126:150 */
|
|
for ( QValueList<ulong>::Iterator it = uids.begin(); it != uids.end(); ++it )
|
|
{
|
|
if (it == uids.begin() || set.isEmpty()) {
|
|
set = QString::number(*it);
|
|
inserted = true;
|
|
} else
|
|
{
|
|
if (last+1 != *it)
|
|
{
|
|
// end this range
|
|
if (inserted)
|
|
set += ',' + QString::number(*it);
|
|
else
|
|
set += ':' + QString::number(last) + ',' + QString::number(*it);
|
|
inserted = true;
|
|
if (set.length() > 100)
|
|
{
|
|
// just in case the server has a problem with longer lines..
|
|
sets.append(set);
|
|
set = "";
|
|
}
|
|
} else {
|
|
inserted = false;
|
|
}
|
|
}
|
|
last = *it;
|
|
}
|
|
// last element
|
|
if (!inserted)
|
|
set += ':' + QString::number(uids.last());
|
|
|
|
if (!set.isEmpty()) sets.append(set);
|
|
|
|
return sets;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void KMFolderImap::getUids(QValueList<int>& ids, QValueList<ulong>& uids)
|
|
{
|
|
KMMsgBase *msg = 0;
|
|
// get the uids
|
|
for ( QValueList<int>::Iterator it = ids.begin(); it != ids.end(); ++it )
|
|
{
|
|
msg = getMsgBase(*it);
|
|
if (!msg) continue;
|
|
uids.append(msg->UID());
|
|
}
|
|
}
|
|
|
|
void KMFolderImap::getUids(const QPtrList<KMMessage>& msgList, QValueList<ulong>& uids)
|
|
{
|
|
KMMessage *msg = 0;
|
|
|
|
QPtrListIterator<KMMessage> it( msgList );
|
|
while ( (msg = it.current()) != 0 ) {
|
|
++it;
|
|
if ( msg->UID() > 0 ) {
|
|
uids.append( msg->UID() );
|
|
}
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void KMFolderImap::expungeFolder(KMFolderImap * aFolder, bool quiet)
|
|
{
|
|
aFolder->setNeedsCompacting(false);
|
|
KURL url = account()->getUrl();
|
|
url.setPath(aFolder->imapPath() + ";UID=*");
|
|
if ( account()->makeConnection() != ImapAccountBase::Connected )
|
|
return;
|
|
KIO::SimpleJob *job = KIO::file_delete(url, false);
|
|
KIO::Scheduler::assignJobToSlave(account()->slave(), job);
|
|
ImapAccountBase::jobData jd( url.url(), 0 );
|
|
jd.quiet = quiet;
|
|
account()->insertJob(job, jd);
|
|
connect(job, SIGNAL(result(KIO::Job *)),
|
|
account(), SLOT(slotSimpleResult(KIO::Job *)));
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void KMFolderImap::slotProcessNewMail( int errorCode, const QString &errorMsg )
|
|
{
|
|
Q_UNUSED( errorMsg );
|
|
disconnect( account(), SIGNAL( connectionResult(int, const QString&) ),
|
|
this, SLOT( slotProcessNewMail(int, const QString&) ) );
|
|
if ( !errorCode )
|
|
processNewMail( false );
|
|
else
|
|
emit numUnreadMsgsChanged( folder() );
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
bool KMFolderImap::processNewMail(bool)
|
|
{
|
|
// a little safety
|
|
if ( !account() ) {
|
|
kdDebug(5006) << "KMFolderImap::processNewMail - account is null!" << endl;
|
|
return false;
|
|
}
|
|
if ( imapPath().isEmpty() ) {
|
|
kdDebug(5006) << "KMFolderImap::processNewMail - imapPath of " << name() << " is empty!" << endl;
|
|
// remove it locally
|
|
setAlreadyRemoved( true );
|
|
kmkernel->imapFolderMgr()->remove( folder() );
|
|
return false;
|
|
}
|
|
// check the connection
|
|
if ( account()->makeConnection() == ImapAccountBase::Error ) {
|
|
kdDebug(5006) << "KMFolderImap::processNewMail - got no connection!" << endl;
|
|
return false;
|
|
} else if ( account()->makeConnection() == ImapAccountBase::Connecting )
|
|
{
|
|
// wait
|
|
kdDebug(5006) << "KMFolderImap::processNewMail - waiting for connection: " << label() << endl;
|
|
connect( account(), SIGNAL( connectionResult(int, const QString&) ),
|
|
this, SLOT( slotProcessNewMail(int, const QString&) ) );
|
|
return true;
|
|
}
|
|
KURL url = account()->getUrl();
|
|
if (mReadOnly)
|
|
url.setPath(imapPath() + ";SECTION=UIDNEXT");
|
|
else
|
|
url.setPath(imapPath() + ";SECTION=UNSEEN");
|
|
|
|
mMailCheckProgressItem = ProgressManager::createProgressItem(
|
|
"MailCheckAccount" + account()->name(),
|
|
"MailCheck" + folder()->prettyURL(),
|
|
QStyleSheet::escape( folder()->prettyURL() ),
|
|
i18n("updating message counts"),
|
|
false,
|
|
account()->useSSL() || account()->useTLS() );
|
|
|
|
KIO::SimpleJob *job = KIO::stat(url, false);
|
|
KIO::Scheduler::assignJobToSlave(account()->slave(), job);
|
|
ImapAccountBase::jobData jd(url.url(), folder() );
|
|
jd.cancellable = true;
|
|
account()->insertJob(job, jd);
|
|
connect(job, SIGNAL(result(KIO::Job *)),
|
|
SLOT(slotStatResult(KIO::Job *)));
|
|
return true;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void KMFolderImap::slotStatResult(KIO::Job * job)
|
|
{
|
|
slotCompleteMailCheckProgress();
|
|
ImapAccountBase::JobIterator it = account()->findJob(job);
|
|
if ( it == account()->jobsEnd() ) return;
|
|
account()->removeJob(it);
|
|
if (job->error())
|
|
{
|
|
account()->handleJobError( job, i18n("Error while getting folder information.") );
|
|
} else {
|
|
KIO::UDSEntry uds = static_cast<KIO::StatJob*>(job)->statResult();
|
|
for (KIO::UDSEntry::ConstIterator it = uds.begin(); it != uds.end(); it++)
|
|
{
|
|
if ((*it).m_uds == KIO::UDS_SIZE)
|
|
{
|
|
if (mReadOnly)
|
|
{
|
|
mGuessedUnreadMsgs = -1;
|
|
mGuessedUnreadMsgs = countUnread() + (*it).m_long - lastUid() - 1;
|
|
if (mGuessedUnreadMsgs < 0) mGuessedUnreadMsgs = 0;
|
|
} else {
|
|
mGuessedUnreadMsgs = (*it).m_long;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
int KMFolderImap::create()
|
|
{
|
|
readConfig();
|
|
mUnreadMsgs = -1;
|
|
return KMFolderMbox::create();
|
|
}
|
|
|
|
QValueList<ulong> KMFolderImap::splitSets(const QString uids)
|
|
{
|
|
QValueList<ulong> uidlist;
|
|
|
|
// ex: 1205,1204,1203,1202,1236:1238
|
|
QString buffer = QString::null;
|
|
int setstart = -1;
|
|
// iterate over the uids
|
|
for (uint i = 0; i < uids.length(); i++)
|
|
{
|
|
QChar chr = uids[i];
|
|
if (chr == ',')
|
|
{
|
|
if (setstart > -1)
|
|
{
|
|
// a range (uid:uid) was before
|
|
for (int j = setstart; j <= buffer.toInt(); j++)
|
|
{
|
|
uidlist.append(j);
|
|
}
|
|
setstart = -1;
|
|
} else {
|
|
// single uid
|
|
uidlist.append(buffer.toInt());
|
|
}
|
|
buffer = "";
|
|
} else if (chr == ':') {
|
|
// remember the start of the range
|
|
setstart = buffer.toInt();
|
|
buffer = "";
|
|
} else if (chr.category() == QChar::Number_DecimalDigit) {
|
|
// digit
|
|
buffer += chr;
|
|
} else {
|
|
// ignore
|
|
}
|
|
}
|
|
// process the last data
|
|
if (setstart > -1)
|
|
{
|
|
for (int j = setstart; j <= buffer.toInt(); j++)
|
|
{
|
|
uidlist.append(j);
|
|
}
|
|
} else {
|
|
uidlist.append(buffer.toInt());
|
|
}
|
|
|
|
return uidlist;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
int KMFolderImap::expungeContents()
|
|
{
|
|
// nuke the local cache
|
|
int rc = KMFolderMbox::expungeContents();
|
|
|
|
// set the deleted flag for all messages in the folder
|
|
KURL url = account()->getUrl();
|
|
url.setPath( imapPath() + ";UID=1:*");
|
|
if ( account()->makeConnection() == ImapAccountBase::Connected )
|
|
{
|
|
KIO::SimpleJob *job = KIO::file_delete(url, false);
|
|
KIO::Scheduler::assignJobToSlave(account()->slave(), job);
|
|
ImapAccountBase::jobData jd( url.url(), 0 );
|
|
jd.quiet = true;
|
|
account()->insertJob(job, jd);
|
|
connect(job, SIGNAL(result(KIO::Job *)),
|
|
account(), SLOT(slotSimpleResult(KIO::Job *)));
|
|
}
|
|
/* Is the below correct? If we are expunging (in the folder sense, not the imap sense),
|
|
why delete but not (imap-)expunge? Since the folder is not active there is no concept
|
|
of "leaving the folder", so the setting really has little to do with it. */
|
|
// if ( autoExpunge() )
|
|
expungeFolder(this, true);
|
|
getFolder();
|
|
|
|
return rc;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void
|
|
KMFolderImap::setUserRights( unsigned int userRights )
|
|
{
|
|
mUserRights = userRights;
|
|
kdDebug(5006) << imapPath() << " setUserRights: " << userRights << endl;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void KMFolderImap::slotCompleteMailCheckProgress()
|
|
{
|
|
if ( mMailCheckProgressItem ) {
|
|
mMailCheckProgressItem->setComplete();
|
|
mMailCheckProgressItem = 0;
|
|
emit numUnreadMsgsChanged( folder() );
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void KMFolderImap::setSubfolderState( imapState state )
|
|
{
|
|
mSubfolderState = state;
|
|
if ( state == imapNoInformation && folder()->child() )
|
|
{
|
|
// pass through to children
|
|
KMFolderNode* node;
|
|
QPtrListIterator<KMFolderNode> it( *folder()->child() );
|
|
for ( ; (node = it.current()); )
|
|
{
|
|
++it;
|
|
if (node->isDir()) continue;
|
|
KMFolder *folder = static_cast<KMFolder*>(node);
|
|
static_cast<KMFolderImap*>(folder->storage())->setSubfolderState( state );
|
|
}
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void KMFolderImap::setIncludeInMailCheck( bool check )
|
|
{
|
|
bool changed = ( mCheckMail != check );
|
|
mCheckMail = check;
|
|
if ( changed )
|
|
account()->slotUpdateFolderList();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void KMFolderImap::setAlreadyRemoved( bool removed )
|
|
{
|
|
mAlreadyRemoved = removed;
|
|
if ( folder()->child() )
|
|
{
|
|
// pass through to childs
|
|
KMFolderNode* node;
|
|
QPtrListIterator<KMFolderNode> it( *folder()->child() );
|
|
for ( ; (node = it.current()); )
|
|
{
|
|
++it;
|
|
if (node->isDir()) continue;
|
|
KMFolder *folder = static_cast<KMFolder*>(node);
|
|
static_cast<KMFolderImap*>(folder->storage())->setAlreadyRemoved( removed );
|
|
}
|
|
}
|
|
}
|
|
|
|
void KMFolderImap::slotCreatePendingFolders( int errorCode, const QString& errorMsg )
|
|
{
|
|
Q_UNUSED( errorMsg );
|
|
disconnect( account(), SIGNAL( connectionResult( int, const QString& ) ),
|
|
this, SLOT( slotCreatePendingFolders( int, const QString& ) ) );
|
|
if ( !errorCode ) {
|
|
QStringList::Iterator it = mFoldersPendingCreation.begin();
|
|
for ( ; it != mFoldersPendingCreation.end(); ++it ) {
|
|
createFolder( *it );
|
|
}
|
|
}
|
|
mFoldersPendingCreation.clear();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void KMFolderImap::search( const KMSearchPattern* pattern )
|
|
{
|
|
if ( !pattern || pattern->isEmpty() )
|
|
{
|
|
// not much to do here
|
|
QValueList<Q_UINT32> serNums;
|
|
emit searchResult( folder(), serNums, pattern, true );
|
|
return;
|
|
}
|
|
SearchJob* job = new SearchJob( this, account(), pattern );
|
|
connect( job, SIGNAL( searchDone( QValueList<Q_UINT32>, const KMSearchPattern*, bool ) ),
|
|
this, SLOT( slotSearchDone( QValueList<Q_UINT32>, const KMSearchPattern*, bool ) ) );
|
|
job->start();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void KMFolderImap::slotSearchDone( QValueList<Q_UINT32> serNums,
|
|
const KMSearchPattern* pattern,
|
|
bool complete )
|
|
{
|
|
emit searchResult( folder(), serNums, pattern, complete );
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void KMFolderImap::search( const KMSearchPattern* pattern, Q_UINT32 serNum )
|
|
{
|
|
if ( !pattern || pattern->isEmpty() )
|
|
{
|
|
// not much to do here
|
|
emit searchDone( folder(), serNum, pattern, false );
|
|
return;
|
|
}
|
|
SearchJob* job = new SearchJob( this, account(), pattern, serNum );
|
|
connect( job, SIGNAL( searchDone( Q_UINT32, const KMSearchPattern*, bool ) ),
|
|
this, SLOT( slotSearchDone( Q_UINT32, const KMSearchPattern*, bool ) ) );
|
|
job->start();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void KMFolderImap::slotSearchDone( Q_UINT32 serNum, const KMSearchPattern* pattern,
|
|
bool matches )
|
|
{
|
|
emit searchDone( folder(), serNum, pattern, matches );
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
bool KMFolderImap::isMoveable() const
|
|
{
|
|
return ( hasChildren() == HasNoChildren &&
|
|
!folder()->isSystemFolder() ) ? true : false;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
const ulong KMFolderImap::serNumForUID( ulong uid )
|
|
{
|
|
if ( mUidMetaDataMap.find( uid ) ) {
|
|
KMMsgMetaData *md = mUidMetaDataMap[uid];
|
|
return md->serNum();
|
|
} else {
|
|
kdDebug(5006) << "serNumForUID: unknown uid " << uid << endl;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void KMFolderImap::saveMsgMetaData( KMMessage* msg, ulong uid )
|
|
{
|
|
if ( uid == 0 ) {
|
|
uid = msg->UID();
|
|
}
|
|
ulong serNum = msg->getMsgSerNum();
|
|
mUidMetaDataMap.replace( uid, new KMMsgMetaData(msg->status(), serNum) );
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void KMFolderImap::setImapPath( const QString& path )
|
|
{
|
|
if ( path.isEmpty() ) {
|
|
kdWarning(5006) << k_funcinfo << "ignoring empty path" << endl;
|
|
} else {
|
|
mImapPath = path;
|
|
}
|
|
}
|
|
|
|
void KMFolderImap::finishMailCheck( const char *dbg, imapState state )
|
|
{
|
|
quiet( false );
|
|
mContentState = state;
|
|
emit folderComplete( this, mContentState == imapFinished );
|
|
close(dbg);
|
|
}
|
|
|
|
#include "kmfolderimap.moc"
|