/* Copyright (c) 2007 Till Adam Copyright (C) 2008 Omat Holding B.V. Copyright (C) 2009 Kevin Ottens Copyright (c) 2010 Klarälvdalens Datakonsult AB, a KDAB Group company Author: Kevin Ottens 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 "imapidlemanager.h" #include #include #include #include #include #include "imapresource.h" #include "sessionpool.h" ImapIdleManager::ImapIdleManager( ResourceStateInterface::Ptr state, SessionPool *pool, ImapResourceBase *parent ) : QObject( parent ), m_sessionRequestId( 0 ), m_pool( pool ), m_session( 0 ), m_idle( 0 ), m_resource( parent ), m_state( state ), m_lastMessageCount( -1 ), m_lastRecentCount( -1 ) { connect( pool, SIGNAL(sessionRequestDone(qint64,KIMAP::Session*,int,QString)), this, SLOT(onSessionRequestDone(qint64,KIMAP::Session*,int,QString)) ); m_sessionRequestId = m_pool->requestSession(); } ImapIdleManager::~ImapIdleManager() { stop(); if ( m_pool ) { if ( m_sessionRequestId ) { m_pool->cancelSessionRequest( m_sessionRequestId ); } if ( m_session ) { m_pool->releaseSession( m_session ); } } } void ImapIdleManager::stop() { if ( m_idle ) { m_idle->stop(); disconnect(m_idle, 0, this, 0); m_idle = 0; } if ( m_pool ) { disconnect(m_pool, 0, this, 0); } } KIMAP::Session *ImapIdleManager::session() const { return m_session; } void ImapIdleManager::reconnect() { kDebug() << "attempting to reconnect IDLE session"; if ( m_session == 0 && m_pool->isConnected() && m_sessionRequestId == 0 ) m_sessionRequestId = m_pool->requestSession(); } void ImapIdleManager::onSessionRequestDone( qint64 requestId, KIMAP::Session *session, int errorCode, const QString &/*errorString*/ ) { if ( requestId!=m_sessionRequestId || session==0 || errorCode!=SessionPool::NoError ) { return; } m_session = session; m_sessionRequestId = 0; connect( m_pool, SIGNAL(connectionLost(KIMAP::Session*)), this, SLOT(onConnectionLost(KIMAP::Session*)) ); connect( m_pool, SIGNAL(disconnectDone()), this, SLOT(onPoolDisconnect()) ); KIMAP::SelectJob *select = new KIMAP::SelectJob( m_session ); select->setMailBox( m_state->mailBoxForCollection( m_state->collection() ) ); connect( select, SIGNAL(result(KJob*)), this, SLOT(onSelectDone(KJob*)) ); select->start(); m_idle = new KIMAP::IdleJob( m_session ); connect( m_idle, SIGNAL(mailBoxStats(KIMAP::IdleJob*,QString,int,int)), this, SLOT(onStatsReceived(KIMAP::IdleJob*,QString,int,int)) ); connect( m_idle, SIGNAL(mailBoxMessageFlagsChanged(KIMAP::IdleJob*,qint64)), this, SLOT(onFlagsChanged(KIMAP::IdleJob*)) ); connect( m_idle, SIGNAL(result(KJob*)), this, SLOT(onIdleStopped()) ); m_idle->start(); } void ImapIdleManager::onConnectionLost( KIMAP::Session *session ) { if ( session == m_session ) { // Our session becomes invalid, so get ride of // the pointer, we don't need to release it once the // task is done m_session = 0; QMetaObject::invokeMethod( this, "reconnect", Qt::QueuedConnection ); } } void ImapIdleManager::onPoolDisconnect() { // All the sessions in the pool we used changed, // so get ride of the pointer, we don't need to // release our session anymore m_pool = 0; } void ImapIdleManager::onSelectDone( KJob *job ) { KIMAP::SelectJob *select = static_cast( job ); m_lastMessageCount = select->messageCount(); m_lastRecentCount = select->recentCount(); } void ImapIdleManager::onIdleStopped() { kDebug( 5327 ) << "IDLE dropped maybe we should reconnect?"; m_idle = 0; if ( m_session ) { kDebug( 5327 ) << "Restarting the IDLE session!"; m_idle = new KIMAP::IdleJob( m_session ); connect( m_idle, SIGNAL(mailBoxStats(KIMAP::IdleJob*,QString,int,int)), this, SLOT(onStatsReceived(KIMAP::IdleJob*,QString,int,int)) ); connect( m_idle, SIGNAL(result(KJob*)), this, SLOT(onIdleStopped()) ); m_idle->start(); } } void ImapIdleManager::onStatsReceived(KIMAP::IdleJob *job, const QString &mailBox, int messageCount, int recentCount) { kDebug( 5327 ) << "IDLE stats received:" << job << mailBox << messageCount << recentCount; kDebug( 5327 ) << "Cached information:" << m_state->collection().remoteId() << m_state->collection().id() << m_lastMessageCount << m_lastRecentCount; // It seems we're not in sync with the cache, resync is needed if ( messageCount!=m_lastMessageCount || recentCount!=m_lastRecentCount ) { m_lastMessageCount = messageCount; m_lastRecentCount = recentCount; kDebug( 5327 ) << "Resync needed for" << mailBox << m_state->collection().id(); m_resource->synchronizeCollection( m_state->collection().id() ); } } void ImapIdleManager::onFlagsChanged( KIMAP::IdleJob *job ) { kDebug( 5327 ) << "IDLE flags changed in" << m_session->selectedMailBox(); m_resource->synchronizeCollection( m_state->collection().id() ); }