akonadi
job.cpp
00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "job.h"
00023 #include "job_p.h"
00024 #include "imapparser_p.h"
00025 #include "session.h"
00026 #include "session_p.h"
00027
00028 #include <kdebug.h>
00029 #include <klocale.h>
00030
00031 #include <QtCore/QEventLoop>
00032 #include <QtCore/QTimer>
00033 #include <QtCore/QTextStream>
00034 #include <QtNetwork/QHostAddress>
00035 #include <QtNetwork/QTcpSocket>
00036 #include <QtDBus/QDBusInterface>
00037 #include <QtDBus/QDBusConnectionInterface>
00038
00039 using namespace Akonadi;
00040
00041 static QDBusAbstractInterface *s_jobtracker = 0;
00042
00043
00044 void JobPrivate::handleResponse( const QByteArray & tag, const QByteArray & data )
00045 {
00046 Q_Q( Job );
00047
00048 if ( mCurrentSubJob ) {
00049 mCurrentSubJob->d_ptr->handleResponse( tag, data );
00050 return;
00051 }
00052
00053 if ( tag == mTag ) {
00054 if ( data.startsWith( "NO " ) || data.startsWith( "BAD " ) ) {
00055 QString msg = QString::fromUtf8( data );
00056
00057 msg.remove( 0, msg.startsWith( QLatin1String( "NO " ) ) ? 3 : 4 );
00058
00059 if ( msg.endsWith( QLatin1String( "\r\n" ) ) )
00060 msg.chop( 2 );
00061
00062 q->setError( Job::Unknown );
00063 q->setErrorText( msg );
00064 q->emitResult();
00065 return;
00066 } else if ( data.startsWith( "OK" ) ) {
00067 q->emitResult();
00068 return;
00069 }
00070 }
00071
00072 q->doHandleResponse( tag, data );
00073 }
00074
00075 void JobPrivate::init( QObject *parent )
00076 {
00077 Q_Q( Job );
00078
00079 mParentJob = dynamic_cast<Job*>( parent );
00080 mSession = dynamic_cast<Session*>( parent );
00081
00082 if ( !mSession ) {
00083 if ( !mParentJob )
00084 mSession = Session::defaultSession();
00085 else
00086 mSession = mParentJob->d_ptr->mSession;
00087 }
00088
00089 if ( !mParentJob )
00090 mSession->d->addJob( q );
00091 else
00092 mParentJob->addSubjob( q );
00093
00094
00095 if ( !s_jobtracker && QDBusConnection::sessionBus().interface()->isServiceRegistered(QLatin1String("org.kde.akonadiconsole") ) ) {
00096 s_jobtracker = new QDBusInterface( QLatin1String("org.kde.akonadiconsole"),
00097 QLatin1String("/jobtracker"),
00098 QLatin1String("org.freedesktop.Akonadi.JobTracker"),
00099 QDBusConnection::sessionBus(), 0 );
00100 }
00101 QMetaObject::invokeMethod( q, "signalCreationToJobTracker", Qt::QueuedConnection );
00102 }
00103
00104 void JobPrivate::signalCreationToJobTracker()
00105 {
00106 Q_Q( Job );
00107 if ( s_jobtracker ) {
00108
00109
00110
00111 QList<QVariant> argumentList;
00112 argumentList << QLatin1String( mSession->sessionId() )
00113 << QString::number(reinterpret_cast<unsigned long>( q ), 16)
00114 << ( mParentJob ? QString::number( reinterpret_cast<unsigned long>( mParentJob ), 16) : QString() )
00115 << QString::fromLatin1( q->metaObject()->className() );
00116 s_jobtracker->asyncCallWithArgumentList(QLatin1String("jobCreated"), argumentList);
00117 }
00118 }
00119
00120 void JobPrivate::startQueued()
00121 {
00122 Q_Q( Job );
00123 mStarted = true;
00124
00125 emit q->aboutToStart( q );
00126 q->doStart();
00127 QTimer::singleShot( 0, q, SLOT(startNext()) );
00128
00129
00130 if ( s_jobtracker ) {
00131 QList<QVariant> argumentList;
00132 argumentList << QString::number(reinterpret_cast<unsigned long>( q ), 16);
00133 s_jobtracker->asyncCallWithArgumentList(QLatin1String("jobStarted"), argumentList);
00134 }
00135 }
00136
00137 void JobPrivate::lostConnection()
00138 {
00139 Q_Q( Job );
00140
00141 if ( mCurrentSubJob ) {
00142 mCurrentSubJob->d_ptr->lostConnection();
00143 } else {
00144 q->setError( Job::ConnectionFailed );
00145 q->kill( KJob::EmitResult );
00146 }
00147 }
00148
00149 void JobPrivate::slotSubJobAboutToStart( Job * job )
00150 {
00151 Q_ASSERT( mCurrentSubJob == 0 );
00152 mCurrentSubJob = job;
00153 }
00154
00155 void JobPrivate::startNext()
00156 {
00157 Q_Q( Job );
00158
00159 if ( mStarted && !mCurrentSubJob && q->hasSubjobs() ) {
00160 Job *job = dynamic_cast<Akonadi::Job*>( q->subjobs().first() );
00161 Q_ASSERT( job );
00162 job->d_ptr->startQueued();
00163 }
00164 }
00165
00166 QByteArray JobPrivate::newTag( )
00167 {
00168 if ( mParentJob )
00169 mTag = mParentJob->d_ptr->newTag();
00170 else
00171 mTag = QByteArray::number( mSession->d->nextTag() );
00172 return mTag;
00173 }
00174
00175 QByteArray JobPrivate::tag() const
00176 {
00177 return mTag;
00178 }
00179
00180 void JobPrivate::writeData( const QByteArray & data )
00181 {
00182 Q_ASSERT_X( !mWriteFinished, "Job::writeData()", "Calling writeData() after emitting writeFinished()" );
00183 mSession->d->writeData( data );
00184 }
00185
00186
00187
00188 Job::Job( QObject *parent )
00189 : KCompositeJob( parent ),
00190 d_ptr( new JobPrivate( this ) )
00191 {
00192 d_ptr->init( parent );
00193 }
00194
00195 Job::Job( JobPrivate *dd, QObject *parent )
00196 : KCompositeJob( parent ),
00197 d_ptr( dd )
00198 {
00199 d_ptr->init( parent );
00200 }
00201
00202 Job::~Job()
00203 {
00204 delete d_ptr;
00205
00206
00207 if ( s_jobtracker ) {
00208 QList<QVariant> argumentList;
00209 argumentList << QString::number(reinterpret_cast<unsigned long>( this ), 16)
00210 << errorString();
00211 s_jobtracker->asyncCallWithArgumentList(QLatin1String("jobEnded"), argumentList);
00212 }
00213 }
00214
00215 void Job::start()
00216 {
00217 }
00218
00219 bool Job::doKill()
00220 {
00221 return true;
00222 }
00223
00224 QString Job::errorString() const
00225 {
00226 QString str;
00227 switch ( error() ) {
00228 case NoError:
00229 break;
00230 case ConnectionFailed:
00231 str = i18n( "Cannot connect to the Akonadi service." );
00232 break;
00233 case ProtocolVersionMismatch:
00234 str = i18n( "The protocol version of the Akonadi server is incompatible. Make sure you have a compatible version installed." );
00235 break;
00236 case UserCanceled:
00237 str = i18n( "User canceled operation." );
00238 break;
00239 case Unknown:
00240 default:
00241 str = i18n( "Unknown error." );
00242 break;
00243 }
00244 if ( !errorText().isEmpty() ) {
00245 str += QString::fromLatin1( " (%1)" ).arg( errorText() );
00246 }
00247 return str;
00248 }
00249
00250 bool Job::addSubjob( KJob * job )
00251 {
00252 bool rv = KCompositeJob::addSubjob( job );
00253 if ( rv ) {
00254 connect( job, SIGNAL(aboutToStart(Akonadi::Job*)), SLOT(slotSubJobAboutToStart(Akonadi::Job*)) );
00255 QTimer::singleShot( 0, this, SLOT(startNext()) );
00256 }
00257 return rv;
00258 }
00259
00260 bool Job::removeSubjob(KJob * job)
00261 {
00262 bool rv = KCompositeJob::removeSubjob( job );
00263 if ( job == d_ptr->mCurrentSubJob ) {
00264 d_ptr->mCurrentSubJob = 0;
00265 QTimer::singleShot( 0, this, SLOT(startNext()) );
00266 }
00267 return rv;
00268 }
00269
00270 void Job::doHandleResponse(const QByteArray & tag, const QByteArray & data)
00271 {
00272 kDebug( 5250 ) << "Unhandled response: " << tag << data;
00273 }
00274
00275 void Job::slotResult(KJob * job)
00276 {
00277 Q_ASSERT( job == d_ptr->mCurrentSubJob );
00278 d_ptr->mCurrentSubJob = 0;
00279 KCompositeJob::slotResult( job );
00280 if ( !job->error() )
00281 QTimer::singleShot( 0, this, SLOT(startNext()) );
00282 }
00283
00284 void Job::emitWriteFinished()
00285 {
00286 d_ptr->mWriteFinished = true;
00287 emit writeFinished( this );
00288 }
00289
00290 #include "job.moc"