• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdepimlibs-4.10.5 API Reference
  • KDE Home
  • Contact Us
 

akonadi

  • akonadi
job.cpp
1 /*
2  Copyright (c) 2006 Tobias Koenig <tokoe@kde.org>
3  2006 Marc Mutz <mutz@kde.org>
4  2006 - 2007 Volker Krause <vkrause@kde.org>
5 
6  This library is free software; you can redistribute it and/or modify it
7  under the terms of the GNU Library General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or (at your
9  option) any later version.
10 
11  This library is distributed in the hope that it will be useful, but WITHOUT
12  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
14  License for more details.
15 
16  You should have received a copy of the GNU Library General Public License
17  along with this library; see the file COPYING.LIB. If not, write to the
18  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19  02110-1301, USA.
20 */
21 
22 #include "job.h"
23 #include "job_p.h"
24 #include "dbusconnectionpool.h"
25 #include <QTime>
26 #include "imapparser_p.h"
27 #include "session.h"
28 #include "session_p.h"
29 
30 #include <kdebug.h>
31 #include <klocale.h>
32 
33 #include <QtCore/QEventLoop>
34 #include <QtCore/QTimer>
35 #include <QtCore/QTextStream>
36 #include <QtNetwork/QHostAddress>
37 #include <QtNetwork/QTcpSocket>
38 #include <QtDBus/QDBusInterface>
39 #include <QtDBus/QDBusConnectionInterface>
40 
41 using namespace Akonadi;
42 
43 static QDBusAbstractInterface *s_jobtracker = 0;
44 
45 //@cond PRIVATE
46 void JobPrivate::handleResponse( const QByteArray & tag, const QByteArray & data )
47 {
48  Q_Q( Job );
49 
50  if ( mCurrentSubJob ) {
51  mCurrentSubJob->d_ptr->handleResponse( tag, data );
52  return;
53  }
54 
55  if ( tag == mTag ) {
56  if ( data.startsWith( "NO " ) || data.startsWith( "BAD " ) ) { //krazy:exclude=strings
57  QString msg = QString::fromUtf8( data );
58 
59  msg.remove( 0, msg.startsWith( QLatin1String( "NO " ) ) ? 3 : 4 );
60 
61  if ( msg.endsWith( QLatin1String( "\r\n" ) ) )
62  msg.chop( 2 );
63 
64  q->setError( Job::Unknown );
65  q->setErrorText( msg );
66  q->emitResult();
67  return;
68  } else if ( data.startsWith( "OK" ) ) { //krazy:exclude=strings
69 
70  // We can't use emitResult() here: The slot connected to the result signal might exec()
71  // another job, and therefore this method would never return. That causes the session
72  // to deadlock, since it calls this method and does not continue starting new jobs until
73  // this method finishes. Which would also mean the exec()'d job is never started,, and there-
74  // fore everything deadlocks.
75  QTimer::singleShot( 0, q, SLOT(delayedEmitResult()) );
76  return;
77  }
78  }
79 
80  q->doHandleResponse( tag, data );
81 }
82 
83 void JobPrivate::init( QObject *parent )
84 {
85  Q_Q( Job );
86 
87  mParentJob = dynamic_cast<Job*>( parent );
88  mSession = dynamic_cast<Session*>( parent );
89 
90  if ( !mSession ) {
91  if ( !mParentJob )
92  mSession = Session::defaultSession();
93  else
94  mSession = mParentJob->d_ptr->mSession;
95  }
96 
97  if ( !mParentJob )
98  mSession->d->addJob( q );
99  else
100  mParentJob->addSubjob( q );
101 
102  // if there's a job tracker running, tell it about the new job
103  if ( !s_jobtracker ) {
104  // Let's only check for the debugging console every 3 seconds, otherwise every single job
105  // makes a dbus call to the dbus daemon, doesn't help performance.
106  static QTime s_lastTime;
107  if ( s_lastTime.isNull() || s_lastTime.elapsed() > 3000 ) {
108  if ( s_lastTime.isNull() )
109  s_lastTime.start();
110  if ( DBusConnectionPool::threadConnection().interface()->isServiceRegistered(QLatin1String( "org.kde.akonadiconsole" ) ) ) {
111  s_jobtracker = new QDBusInterface( QLatin1String( "org.kde.akonadiconsole" ),
112  QLatin1String( "/jobtracker" ),
113  QLatin1String( "org.freedesktop.Akonadi.JobTracker" ),
114  DBusConnectionPool::threadConnection(), 0 );
115  } else {
116  s_lastTime.restart();
117  }
118  }
119  // Note: we never reset s_jobtracker to 0 when a call fails; but if we did
120  // then we should restart s_lastTime.
121  }
122  QMetaObject::invokeMethod( q, "signalCreationToJobTracker", Qt::QueuedConnection );
123 }
124 
125 void JobPrivate::signalCreationToJobTracker()
126 {
127  Q_Q( Job );
128  if ( s_jobtracker ) {
129  // We do these dbus calls manually, so as to avoid having to install (or copy) the console's
130  // xml interface document. Since this is purely a debugging aid, that seems preferable to
131  // publishing something not intended for public consumption.
132  QList<QVariant> argumentList;
133  argumentList << QLatin1String( mSession->sessionId() )
134  << QString::number(reinterpret_cast<quintptr>( q ), 16)
135  << ( mParentJob ? QString::number( reinterpret_cast<quintptr>( mParentJob ), 16) : QString() )
136  << QString::fromLatin1( q->metaObject()->className() );
137  s_jobtracker->callWithArgumentList(QDBus::NoBlock, QLatin1String( "jobCreated" ), argumentList);
138  }
139 }
140 
141 void JobPrivate::delayedEmitResult()
142 {
143  Q_Q( Job );
144  q->emitResult();
145 }
146 
147 void JobPrivate::startQueued()
148 {
149  Q_Q( Job );
150  mStarted = true;
151 
152  emit q->aboutToStart( q );
153  q->doStart();
154  QTimer::singleShot( 0, q, SLOT(startNext()) );
155 
156  // if there's a job tracker running, tell it a job started
157  if ( s_jobtracker ) {
158  QList<QVariant> argumentList;
159  argumentList << QString::number(reinterpret_cast<quintptr>( q ), 16);
160  s_jobtracker->callWithArgumentList(QDBus::NoBlock, QLatin1String( "jobStarted" ), argumentList);
161  }
162 }
163 
164 void JobPrivate::lostConnection()
165 {
166  Q_Q( Job );
167 
168  if ( mCurrentSubJob ) {
169  mCurrentSubJob->d_ptr->lostConnection();
170  } else {
171  q->setError( Job::ConnectionFailed );
172  q->emitResult();
173  }
174 }
175 
176 void JobPrivate::slotSubJobAboutToStart( Job * job )
177 {
178  Q_ASSERT( mCurrentSubJob == 0 );
179  mCurrentSubJob = job;
180 }
181 
182 void JobPrivate::startNext()
183 {
184  Q_Q( Job );
185 
186  if ( mStarted && !mCurrentSubJob && q->hasSubjobs() ) {
187  Job *job = dynamic_cast<Akonadi::Job*>( q->subjobs().first() );
188  Q_ASSERT( job );
189  job->d_ptr->startQueued();
190  }
191 }
192 
193 QByteArray JobPrivate::newTag( )
194 {
195  if ( mParentJob )
196  mTag = mParentJob->d_ptr->newTag();
197  else
198  mTag = QByteArray::number( mSession->d->nextTag() );
199  return mTag;
200 }
201 
202 QByteArray JobPrivate::tag() const
203 {
204  return mTag;
205 }
206 
207 void JobPrivate::writeData( const QByteArray & data )
208 {
209  Q_ASSERT_X( !mWriteFinished, "Job::writeData()", "Calling writeData() after emitting writeFinished()" );
210  mSession->d->writeData( data );
211 }
212 
213 void JobPrivate::itemRevisionChanged( Akonadi::Item::Id itemId, int oldRevision, int newRevision )
214 {
215  mSession->d->itemRevisionChanged( itemId, oldRevision, newRevision );
216 }
217 
218 void JobPrivate::updateItemRevision( Akonadi::Item::Id itemId, int oldRevision, int newRevision )
219 {
220  Q_Q( Job );
221  foreach ( KJob *j, q->subjobs() ) {
222  Akonadi::Job *job = qobject_cast<Akonadi::Job*>( j );
223  if ( job )
224  job->d_ptr->updateItemRevision( itemId, oldRevision, newRevision );
225  }
226  doUpdateItemRevision( itemId, oldRevision, newRevision );
227 }
228 
229 void JobPrivate::doUpdateItemRevision( Akonadi::Item::Id itemId, int oldRevision, int newRevision )
230 {
231  Q_UNUSED( itemId );
232  Q_UNUSED( oldRevision );
233  Q_UNUSED( newRevision );
234 }
235 
236 int JobPrivate::protocolVersion() const
237 {
238  return mSession->d->protocolVersion;
239 }
240 //@endcond
241 
242 
243 Job::Job( QObject *parent )
244  : KCompositeJob( parent ),
245  d_ptr( new JobPrivate( this ) )
246 {
247  d_ptr->init( parent );
248 }
249 
250 Job::Job( JobPrivate *dd, QObject *parent )
251  : KCompositeJob( parent ),
252  d_ptr( dd )
253 {
254  d_ptr->init( parent );
255 }
256 
257 Job::~Job()
258 {
259  delete d_ptr;
260 
261  // if there is a job tracer listening, tell it the job is done now
262  if ( s_jobtracker ) {
263  QList<QVariant> argumentList;
264  argumentList << QString::number(reinterpret_cast<quintptr>( this ), 16)
265  << errorString();
266  s_jobtracker->callWithArgumentList(QDBus::NoBlock, QLatin1String( "jobEnded" ), argumentList);
267  }
268 }
269 
270 void Job::start()
271 {
272 }
273 
274 bool Job::doKill()
275 {
276  Q_D( Job );
277  if ( d->mStarted ) {
278  // the only way to cancel an already started job is reconnecting to the server
279  d->mSession->d->forceReconnect();
280  }
281  d->mStarted = false;
282  return true;
283 }
284 
285 QString Job::errorString() const
286 {
287  QString str;
288  switch ( error() ) {
289  case NoError:
290  break;
291  case ConnectionFailed:
292  str = i18n( "Cannot connect to the Akonadi service." );
293  break;
294  case ProtocolVersionMismatch:
295  str = i18n( "The protocol version of the Akonadi server is incompatible. Make sure you have a compatible version installed." );
296  break;
297  case UserCanceled:
298  str = i18n( "User canceled operation." );
299  break;
300  case Unknown:
301  return errorText();
302  default:
303  str = i18n( "Unknown error." );
304  break;
305  }
306  if ( !errorText().isEmpty() ) {
307  str += QString::fromLatin1( " (%1)" ).arg( errorText() );
308  }
309  return str;
310 }
311 
312 bool Job::addSubjob( KJob * job )
313 {
314  bool rv = KCompositeJob::addSubjob( job );
315  if ( rv ) {
316  connect( job, SIGNAL(aboutToStart(Akonadi::Job*)), SLOT(slotSubJobAboutToStart(Akonadi::Job*)) );
317  QTimer::singleShot( 0, this, SLOT(startNext()) );
318  }
319  return rv;
320 }
321 
322 bool Job::removeSubjob(KJob * job)
323 {
324  bool rv = KCompositeJob::removeSubjob( job );
325  if ( job == d_ptr->mCurrentSubJob ) {
326  d_ptr->mCurrentSubJob = 0;
327  QTimer::singleShot( 0, this, SLOT(startNext()) );
328  }
329  return rv;
330 }
331 
332 void Job::doHandleResponse(const QByteArray & tag, const QByteArray & data)
333 {
334  kDebug() << "Unhandled response: " << tag << data;
335 }
336 
337 void Job::slotResult(KJob * job)
338 {
339  if ( d_ptr->mCurrentSubJob == job ) {
340  // current job finished, start the next one
341  d_ptr->mCurrentSubJob = 0;
342  KCompositeJob::slotResult( job );
343  if ( !job->error() )
344  QTimer::singleShot( 0, this, SLOT(startNext()) );
345  } else {
346  // job that was still waiting for execution finished, probably canceled,
347  // so just remove it from the queue and move on without caring about
348  // its error code
349  KCompositeJob::removeSubjob( job );
350  }
351 }
352 
353 void Job::emitWriteFinished()
354 {
355  d_ptr->mWriteFinished = true;
356  emit writeFinished( this );
357 }
358 
359 #include "moc_job.cpp"
This file is part of the KDE documentation.
Documentation copyright © 1996-2013 The KDE developers.
Generated on Sat Jul 13 2013 01:27:38 by doxygen 1.8.3.1 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

akonadi

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

kdepimlibs-4.10.5 API Reference

Skip menu "kdepimlibs-4.10.5 API Reference"
  • akonadi
  •   contact
  •   kmime
  •   socialutils
  • kabc
  • kalarmcal
  • kblog
  • kcal
  • kcalcore
  • kcalutils
  • kholidays
  • kimap
  • kioslave
  •   imap4
  •   mbox
  •   nntp
  • kldap
  • kmbox
  • kmime
  • kontactinterface
  • kpimidentities
  • kpimtextedit
  • kpimutils
  • kresources
  • ktnef
  • kxmlrpcclient
  • mailtransport
  • microblog
  • qgpgme
  • syndication
  •   atom
  •   rdf
  •   rss2
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal