mirror of
https://bitbucket.org/smil3y/kde-playground.git
synced 2025-02-24 02:42:51 +00:00
303 lines
8.3 KiB
C++
303 lines
8.3 KiB
C++
/*
|
|
Copyright (c) 2010 Klarälvdalens Datakonsult AB,
|
|
a KDAB Group company <info@kdab.com>
|
|
Author: Kevin Ottens <kevin@kdab.com>
|
|
|
|
This library is free software; you can redistribute it and/or modify it
|
|
under the terms of the GNU Library General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or (at your
|
|
option) any later version.
|
|
|
|
This library 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 Library General Public
|
|
License for more details.
|
|
|
|
You should have received a copy of the GNU Library General Public License
|
|
along with this library; see the file COPYING.LIB. If not, write to the
|
|
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
|
02110-1301, USA.
|
|
*/
|
|
|
|
#include "changeitemtask.h"
|
|
|
|
#include <KDE/KDebug>
|
|
#include <KDE/KLocale>
|
|
|
|
#include <kimap/appendjob.h>
|
|
#include <kimap/searchjob.h>
|
|
#include <kimap/selectjob.h>
|
|
#include <kimap/session.h>
|
|
#include <kimap/storejob.h>
|
|
|
|
#include <kmime/kmime_message.h>
|
|
|
|
#include "imapflags.h"
|
|
#include "uidnextattribute.h"
|
|
|
|
ChangeItemTask::ChangeItemTask( ResourceStateInterface::Ptr resource, QObject *parent )
|
|
: ResourceTask( DeferIfNoSession, resource, parent ), m_session( 0 ), m_oldUid( 0 ), m_newUid( 0 )
|
|
{
|
|
|
|
}
|
|
|
|
ChangeItemTask::~ChangeItemTask()
|
|
{
|
|
}
|
|
|
|
void ChangeItemTask::doStart( KIMAP::Session *session )
|
|
{
|
|
m_session = session;
|
|
|
|
const QString mailBox = mailBoxForCollection( item().parentCollection() );
|
|
m_oldUid = item().remoteId().toLongLong();
|
|
kDebug(5327) << mailBox << m_oldUid << parts();
|
|
|
|
if ( parts().contains( "PLD:RFC822" ) ) {
|
|
if ( !item().hasPayload<KMime::Message::Ptr>() ) {
|
|
kWarning() << "Payload changed, no payload available.";
|
|
changeProcessed();
|
|
return;
|
|
}
|
|
|
|
// save message to the server.
|
|
KMime::Message::Ptr msg = item().payload<KMime::Message::Ptr>();
|
|
m_messageId = msg->messageID()->asUnicodeString().toUtf8();
|
|
|
|
KIMAP::AppendJob *job = new KIMAP::AppendJob( session );
|
|
|
|
job->setMailBox( mailBox );
|
|
job->setContent( msg->encodedContent( true ) );
|
|
const QList<QByteArray> flags = fromAkonadiToSupportedImapFlags( item().flags().toList(), item().parentCollection() );
|
|
job->setFlags( flags );
|
|
kDebug(5327) << "Appending new message: " << flags;
|
|
|
|
connect( job, SIGNAL(result(KJob*)),
|
|
this, SLOT(onAppendMessageDone(KJob*)) );
|
|
|
|
job->start();
|
|
|
|
} else if ( parts().contains( "FLAGS" ) ) {
|
|
|
|
if ( session->selectedMailBox() != mailBox ) {
|
|
KIMAP::SelectJob *select = new KIMAP::SelectJob( session );
|
|
select->setMailBox( mailBox );
|
|
|
|
connect( select, SIGNAL(result(KJob*)),
|
|
this, SLOT(onPreStoreSelectDone(KJob*)) );
|
|
|
|
select->start();
|
|
|
|
} else {
|
|
triggerStoreJob();
|
|
}
|
|
|
|
} else {
|
|
kDebug(5327) << "Nothing to do";
|
|
changeProcessed();
|
|
}
|
|
}
|
|
|
|
void ChangeItemTask::onPreStoreSelectDone( KJob *job )
|
|
{
|
|
if ( job->error() ) {
|
|
kWarning() << "Select failed: " << job->errorString();
|
|
cancelTask( job->errorString() );
|
|
} else {
|
|
triggerStoreJob();
|
|
}
|
|
}
|
|
|
|
void ChangeItemTask::triggerStoreJob()
|
|
{
|
|
QList<QByteArray> flags = fromAkonadiToSupportedImapFlags( item().flags().toList(), item().parentCollection() );
|
|
kDebug(5327) << flags;
|
|
|
|
KIMAP::StoreJob *store = new KIMAP::StoreJob( m_session );
|
|
|
|
store->setUidBased( true );
|
|
store->setSequenceSet( KIMAP::ImapSet( m_oldUid ) );
|
|
store->setFlags( flags );
|
|
store->setMode( KIMAP::StoreJob::SetFlags );
|
|
|
|
connect( store, SIGNAL(result(KJob*)),
|
|
this, SLOT(onStoreFlagsDone(KJob*)) );
|
|
|
|
store->start();
|
|
}
|
|
|
|
void ChangeItemTask::onStoreFlagsDone( KJob *job )
|
|
{
|
|
if ( job->error() ) {
|
|
kWarning() << "Flag store failed: " << job->errorString();
|
|
cancelTask( job->errorString() );
|
|
} else {
|
|
changeProcessed();
|
|
}
|
|
}
|
|
|
|
void ChangeItemTask::onAppendMessageDone( KJob *job )
|
|
{
|
|
if ( job->error() ) {
|
|
kWarning() << "Append failed: " << job->errorString();
|
|
cancelTask( job->errorString() );
|
|
return;
|
|
}
|
|
|
|
KIMAP::AppendJob *append = qobject_cast<KIMAP::AppendJob*>( job );
|
|
|
|
m_newUid = append->uid();
|
|
|
|
// OK it's a content change, so we've to mark the old version as deleted
|
|
// remember, you can't modify messages in IMAP mailboxes so that's really
|
|
// add+remove all the time.
|
|
|
|
// APPEND does not require a SELECT, so we could be anywhere right now
|
|
if ( m_session->selectedMailBox() != append->mailBox() ) {
|
|
KIMAP::SelectJob *select = new KIMAP::SelectJob( m_session );
|
|
select->setMailBox( append->mailBox() );
|
|
|
|
connect( select, SIGNAL(result(KJob*)),
|
|
this, SLOT(onPreDeleteSelectDone(KJob*)) );
|
|
|
|
select->start();
|
|
|
|
} else {
|
|
if ( m_newUid > 0 ) {
|
|
triggerDeleteJob();
|
|
} else {
|
|
triggerSearchJob();
|
|
}
|
|
}
|
|
}
|
|
|
|
void ChangeItemTask::onPreDeleteSelectDone( KJob *job )
|
|
{
|
|
if ( job->error() ) {
|
|
kWarning() << "PreDelete select failed: " << job->errorString();
|
|
if ( m_newUid > 0 ) {
|
|
recordNewUid();
|
|
} else {
|
|
cancelTask( job->errorString() );
|
|
}
|
|
} else {
|
|
if ( m_newUid > 0 ) {
|
|
triggerDeleteJob();
|
|
} else {
|
|
triggerSearchJob();
|
|
}
|
|
}
|
|
}
|
|
|
|
void ChangeItemTask::triggerSearchJob()
|
|
{
|
|
KIMAP::SearchJob *search = new KIMAP::SearchJob( m_session );
|
|
|
|
search->setUidBased( true );
|
|
search->setSearchLogic( KIMAP::SearchJob::And );
|
|
|
|
if ( !m_messageId.isEmpty() ) {
|
|
QByteArray header = "Message-ID ";
|
|
header+= m_messageId;
|
|
|
|
search->addSearchCriteria( KIMAP::SearchJob::Header, header );
|
|
} else {
|
|
search->addSearchCriteria( KIMAP::SearchJob::New );
|
|
|
|
UidNextAttribute *uidNext = item().parentCollection().attribute<UidNextAttribute>();
|
|
if ( !uidNext ) {
|
|
kWarning() << "Failed to determine new uid.";
|
|
cancelTask( i18n( "Could not determine the UID for the newly created message on the server" ) );
|
|
search->deleteLater();
|
|
return;
|
|
}
|
|
KIMAP::ImapInterval interval( uidNext->uidNext() );
|
|
|
|
search->addSearchCriteria( KIMAP::SearchJob::Uid, interval.toImapSequence() );
|
|
}
|
|
|
|
connect( search, SIGNAL(result(KJob*)),
|
|
this, SLOT(onSearchDone(KJob*)) );
|
|
|
|
search->start();
|
|
}
|
|
|
|
void ChangeItemTask::onSearchDone( KJob *job )
|
|
{
|
|
if ( job->error() ) {
|
|
kWarning() << "Search failed: " << job->errorString();
|
|
cancelTask( job->errorString() );
|
|
return;
|
|
}
|
|
|
|
KIMAP::SearchJob *search = static_cast<KIMAP::SearchJob*>( job );
|
|
|
|
if ( search->results().count()!=1 ) {
|
|
kWarning() << "Failed to determine new uid.";
|
|
cancelTask( i18n( "Could not determine the UID for the newly created message on the server" ) );
|
|
return;
|
|
}
|
|
|
|
m_newUid = search->results().first();
|
|
triggerDeleteJob();
|
|
}
|
|
|
|
void ChangeItemTask::triggerDeleteJob()
|
|
{
|
|
KIMAP::StoreJob *store = new KIMAP::StoreJob( m_session );
|
|
|
|
store->setUidBased( true );
|
|
store->setSequenceSet( KIMAP::ImapSet( m_oldUid ) );
|
|
store->setFlags( QList<QByteArray>() << ImapFlags::Deleted );
|
|
store->setMode( KIMAP::StoreJob::AppendFlags );
|
|
|
|
connect( store, SIGNAL(result(KJob*)),
|
|
this, SLOT(onDeleteDone(KJob*)) );
|
|
|
|
store->start();
|
|
}
|
|
|
|
void ChangeItemTask::onDeleteDone( KJob */*job*/ )
|
|
{
|
|
recordNewUid();
|
|
}
|
|
|
|
void ChangeItemTask::recordNewUid()
|
|
{
|
|
Q_ASSERT( m_newUid > 0 );
|
|
|
|
Akonadi::Item i = item();
|
|
Akonadi::Collection c = i.parentCollection();
|
|
|
|
// Get the current uid next value and store it
|
|
UidNextAttribute *uidAttr = 0;
|
|
int oldNextUid = 0;
|
|
if ( c.hasAttribute( "uidnext" ) ) {
|
|
uidAttr = static_cast<UidNextAttribute*>( c.attribute( "uidnext" ) );
|
|
oldNextUid = uidAttr->uidNext();
|
|
}
|
|
|
|
// If the uid we just got back is the expected next one of the box
|
|
// then update the property to the probable next uid to keep the cache in sync.
|
|
// If not something happened in our back, so we don't update and a refetch will
|
|
// happen at some point.
|
|
if ( m_newUid==oldNextUid ) {
|
|
if ( uidAttr==0 ) {
|
|
uidAttr = new UidNextAttribute( m_newUid+1 );
|
|
c.addAttribute( uidAttr );
|
|
} else {
|
|
uidAttr->setUidNext( m_newUid+1 );
|
|
}
|
|
|
|
applyCollectionChanges( c );
|
|
}
|
|
|
|
const QString remoteId = QString::number( m_newUid );
|
|
kDebug( 5327 ) << "Setting remote ID to " << remoteId << " for item with local id " << i.id();
|
|
i.setRemoteId( remoteId );
|
|
|
|
changeCommitted( i );
|
|
}
|
|
|
|
|
|
|