• Skip to content
  • Skip to link menu
KDE 4.5 API Reference
  • KDE API Reference
  • KDE-PIM Libraries
  • Sitemap
  • Contact Us
 

akonadi

job.cpp

00001 /*
00002     Copyright (c) 2006 Tobias Koenig <tokoe@kde.org>
00003                   2006 Marc Mutz <mutz@kde.org>
00004                   2006 - 2007 Volker Krause <vkrause@kde.org>
00005 
00006     This library is free software; you can redistribute it and/or modify it
00007     under the terms of the GNU Library General Public License as published by
00008     the Free Software Foundation; either version 2 of the License, or (at your
00009     option) any later version.
00010 
00011     This library is distributed in the hope that it will be useful, but WITHOUT
00012     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00013     FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
00014     License for more details.
00015 
00016     You should have received a copy of the GNU Library General Public License
00017     along with this library; see the file COPYING.LIB.  If not, write to the
00018     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
00019     02110-1301, USA.
00020 */
00021 
00022 #include "job.h"
00023 #include "job_p.h"
00024 #include <QTime>
00025 #include "imapparser_p.h"
00026 #include "session.h"
00027 #include "session_p.h"
00028 
00029 #include <kdebug.h>
00030 #include <klocale.h>
00031 
00032 #include <QtCore/QEventLoop>
00033 #include <QtCore/QTimer>
00034 #include <QtCore/QTextStream>
00035 #include <QtNetwork/QHostAddress>
00036 #include <QtNetwork/QTcpSocket>
00037 #include <QtDBus/QDBusInterface>
00038 #include <QtDBus/QDBusConnectionInterface>
00039 
00040 using namespace Akonadi;
00041 
00042 static QDBusAbstractInterface *s_jobtracker = 0;
00043 
00044 //@cond PRIVATE
00045 void JobPrivate::handleResponse( const QByteArray & tag, const QByteArray & data )
00046 {
00047   Q_Q( Job );
00048 
00049   if ( mCurrentSubJob ) {
00050     mCurrentSubJob->d_ptr->handleResponse( tag, data );
00051     return;
00052   }
00053 
00054   if ( tag == mTag ) {
00055     if ( data.startsWith( "NO " ) || data.startsWith( "BAD " ) ) { //krazy:exclude=strings
00056       QString msg = QString::fromUtf8( data );
00057 
00058       msg.remove( 0, msg.startsWith( QLatin1String( "NO " ) ) ? 3 : 4 );
00059 
00060       if ( msg.endsWith( QLatin1String( "\r\n" ) ) )
00061         msg.chop( 2 );
00062 
00063       q->setError( Job::Unknown );
00064       q->setErrorText( msg );
00065       q->emitResult();
00066       return;
00067     } else if ( data.startsWith( "OK" ) ) { //krazy:exclude=strings
00068 
00069       // We can't use emitResult() here: The slot connected to the result signal might exec()
00070       // another job, and therefore this method would never return. That causes the session
00071       // to deadlock, since it calls this method and does not continue starting new jobs until
00072       // this method finishes. Which would also mean the exec()'d job is never started,, and there-
00073       // fore everything deadlocks.
00074       QTimer::singleShot( 0, q, SLOT( delayedEmitResult() ) );
00075       return;
00076     }
00077   }
00078 
00079   q->doHandleResponse( tag, data );
00080 }
00081 
00082 void JobPrivate::init( QObject *parent )
00083 {
00084   Q_Q( Job );
00085 
00086   mParentJob = dynamic_cast<Job*>( parent );
00087   mSession = dynamic_cast<Session*>( parent );
00088 
00089   if ( !mSession ) {
00090     if ( !mParentJob )
00091       mSession = Session::defaultSession();
00092     else
00093       mSession = mParentJob->d_ptr->mSession;
00094   }
00095 
00096   if ( !mParentJob )
00097     mSession->d->addJob( q );
00098   else
00099     mParentJob->addSubjob( q );
00100 
00101   // if there's a job tracker running, tell it about the new job
00102   if ( !s_jobtracker ) {
00103     // Let's only check for the debugging console every 3 seconds, otherwise every single job
00104     // makes a dbus call to the dbus daemon, doesn't help performance.
00105     static QTime s_lastTime;
00106     if ( s_lastTime.isNull() )
00107       s_lastTime.start();
00108     if ( s_lastTime.elapsed() > 3000 ) {
00109       if ( QDBusConnection::sessionBus().interface()->isServiceRegistered(QLatin1String( "org.kde.akonadiconsole" ) ) ) {
00110         s_jobtracker = new QDBusInterface( QLatin1String( "org.kde.akonadiconsole" ),
00111                                            QLatin1String( "/jobtracker" ),
00112                                            QLatin1String( "org.freedesktop.Akonadi.JobTracker" ),
00113                                            QDBusConnection::sessionBus(), 0 );
00114       } else {
00115         s_lastTime.restart();
00116       }
00117     }
00118     // Note: we never reset s_jobtracker to 0 when a call fails; but if we did
00119     // then we should restart s_lastTime.
00120   }
00121   QMetaObject::invokeMethod( q, "signalCreationToJobTracker", Qt::QueuedConnection );
00122 }
00123 
00124 void JobPrivate::signalCreationToJobTracker()
00125 {
00126   Q_Q( Job );
00127   if ( s_jobtracker ) {
00128       // We do these dbus calls manually, so as to avoid having to install (or copy) the console's
00129       // xml interface document. Since this is purely a debugging aid, that seems preferable to
00130       // publishing something not intended for public consumption.
00131       QList<QVariant> argumentList;
00132       argumentList << QLatin1String( mSession->sessionId() )
00133                    << QString::number(reinterpret_cast<unsigned long>( q ), 16)
00134                    << ( mParentJob ? QString::number( reinterpret_cast<unsigned long>( mParentJob ), 16) : QString() )
00135                    << QString::fromLatin1( q->metaObject()->className() );
00136       s_jobtracker->callWithArgumentList(QDBus::NoBlock, QLatin1String( "jobCreated" ), argumentList);
00137   }
00138 }
00139 
00140 void JobPrivate::delayedEmitResult()
00141 {
00142   Q_Q( Job );
00143   q->emitResult();
00144 }
00145 
00146 void JobPrivate::startQueued()
00147 {
00148   Q_Q( Job );
00149   mStarted = true;
00150 
00151   emit q->aboutToStart( q );
00152   q->doStart();
00153   QTimer::singleShot( 0, q, SLOT( startNext() ) );
00154 
00155   // if there's a job tracker running, tell it a job started
00156   if ( s_jobtracker ) {
00157       QList<QVariant> argumentList;
00158       argumentList << QString::number(reinterpret_cast<unsigned long>( q ), 16);
00159       s_jobtracker->callWithArgumentList(QDBus::NoBlock, QLatin1String( "jobStarted" ), argumentList);
00160   }
00161 }
00162 
00163 void JobPrivate::lostConnection()
00164 {
00165   Q_Q( Job );
00166 
00167   if ( mCurrentSubJob ) {
00168     mCurrentSubJob->d_ptr->lostConnection();
00169   } else {
00170     q->setError( Job::ConnectionFailed );
00171     q->kill( KJob::EmitResult );
00172   }
00173 }
00174 
00175 void JobPrivate::slotSubJobAboutToStart( Job * job )
00176 {
00177   Q_ASSERT( mCurrentSubJob == 0 );
00178   mCurrentSubJob = job;
00179 }
00180 
00181 void JobPrivate::startNext()
00182 {
00183   Q_Q( Job );
00184 
00185   if ( mStarted && !mCurrentSubJob && q->hasSubjobs() ) {
00186     Job *job = dynamic_cast<Akonadi::Job*>( q->subjobs().first() );
00187     Q_ASSERT( job );
00188     job->d_ptr->startQueued();
00189   }
00190 }
00191 
00192 QByteArray JobPrivate::newTag( )
00193 {
00194   if ( mParentJob )
00195     mTag = mParentJob->d_ptr->newTag();
00196   else
00197     mTag = QByteArray::number( mSession->d->nextTag() );
00198   return mTag;
00199 }
00200 
00201 QByteArray JobPrivate::tag() const
00202 {
00203   return mTag;
00204 }
00205 
00206 void JobPrivate::writeData( const QByteArray & data )
00207 {
00208   Q_ASSERT_X( !mWriteFinished, "Job::writeData()", "Calling writeData() after emitting writeFinished()" );
00209   mSession->d->writeData( data );
00210 }
00211 //@endcond
00212 
00213 
00214 Job::Job( QObject *parent )
00215   : KCompositeJob( parent ),
00216     d_ptr( new JobPrivate( this ) )
00217 {
00218   d_ptr->init( parent );
00219 }
00220 
00221 Job::Job( JobPrivate *dd, QObject *parent )
00222   : KCompositeJob( parent ),
00223     d_ptr( dd )
00224 {
00225   d_ptr->init( parent );
00226 }
00227 
00228 Job::~Job()
00229 {
00230   delete d_ptr;
00231 
00232   // if there is a job tracer listening, tell it the job is done now
00233   if ( s_jobtracker ) {
00234       QList<QVariant> argumentList;
00235       argumentList << QString::number(reinterpret_cast<unsigned long>( this ), 16)
00236                    << errorString();
00237       s_jobtracker->callWithArgumentList(QDBus::NoBlock, QLatin1String( "jobEnded" ), argumentList);
00238   }
00239 }
00240 
00241 void Job::start()
00242 {
00243 }
00244 
00245 bool Job::doKill()
00246 {
00247   Q_D( Job );
00248   d->mStarted = false;
00249   return true;
00250 }
00251 
00252 QString Job::errorString() const
00253 {
00254   QString str;
00255   switch ( error() ) {
00256     case NoError:
00257       break;
00258     case ConnectionFailed:
00259       str = i18n( "Cannot connect to the Akonadi service." );
00260       break;
00261     case ProtocolVersionMismatch:
00262       str = i18n( "The protocol version of the Akonadi server is incompatible. Make sure you have a compatible version installed." );
00263       break;
00264     case UserCanceled:
00265       str = i18n( "User canceled operation." );
00266       break;
00267     case Unknown:
00268     default:
00269       str = i18n( "Unknown error." );
00270       break;
00271   }
00272   if ( !errorText().isEmpty() ) {
00273     str += QString::fromLatin1( " (%1)" ).arg( errorText() );
00274   }
00275   return str;
00276 }
00277 
00278 bool Job::addSubjob( KJob * job )
00279 {
00280   bool rv = KCompositeJob::addSubjob( job );
00281   if ( rv ) {
00282     connect( job, SIGNAL( aboutToStart( Akonadi::Job* ) ), SLOT( slotSubJobAboutToStart( Akonadi::Job* ) ) );
00283     QTimer::singleShot( 0, this, SLOT( startNext() ) );
00284   }
00285   return rv;
00286 }
00287 
00288 bool Job::removeSubjob(KJob * job)
00289 {
00290   bool rv = KCompositeJob::removeSubjob( job );
00291   if ( job == d_ptr->mCurrentSubJob ) {
00292     d_ptr->mCurrentSubJob = 0;
00293     QTimer::singleShot( 0, this, SLOT( startNext() ) );
00294   }
00295   return rv;
00296 }
00297 
00298 void Job::doHandleResponse(const QByteArray & tag, const QByteArray & data)
00299 {
00300   kDebug() << "Unhandled response: " << tag << data;
00301 }
00302 
00303 void Job::slotResult(KJob * job)
00304 {
00305   if ( d_ptr->mCurrentSubJob == job ) {
00306     // current job finished, start the next one
00307     d_ptr->mCurrentSubJob = 0;
00308     KCompositeJob::slotResult( job );
00309     if ( !job->error() )
00310       QTimer::singleShot( 0, this, SLOT( startNext() ) );
00311   } else {
00312     // job that was still waiting for execution finished, probably canceled,
00313     // so just remove it from the queue and move on without caring about
00314     // its error code
00315     KCompositeJob::removeSubjob( job );
00316   }
00317 }
00318 
00319 void Job::emitWriteFinished()
00320 {
00321   d_ptr->mWriteFinished = true;
00322   emit writeFinished( this );
00323 }
00324 
00325 #include "job.moc"

akonadi

Skip menu "akonadi"
  • Main Page
  • Modules
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

KDE-PIM Libraries

Skip menu "KDE-PIM Libraries"
  • akonadi
  •   contact
  •   kmime
  • kabc
  • kblog
  • kcal
  • kholidays
  • kimap
  • kioslave
  •   imap4
  •   mbox
  •   nntp
  • kldap
  • kmime
  • kontactinterface
  • kpimidentities
  • kpimtextedit
  •   richtextbuilders
  • kpimutils
  • kresources
  • ktnef
  • kxmlrpcclient
  • mailtransport
  • microblog
  • qgpgme
  • syndication
  •   atom
  •   rdf
  •   rss2
Generated for KDE-PIM Libraries by doxygen 1.7.1
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal