~ubuntu-branches/ubuntu/karmic/kdepim/karmic-backports

« back to all changes in this revision

Viewing changes to akonadi/resources/imap/imapresource.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Christian Mangold
  • Date: 2009-07-10 06:34:50 UTC
  • mfrom: (1.1.40 upstream)
  • Revision ID: james.westby@ubuntu.com-20090710063450-neojgew2fh0n3y0u
Tags: 4:4.2.96-0ubuntu1
* New upstream release
* Bump kde build-deps to 4.2.96

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
    Copyright (c) 2007 Till Adam <adam@kde.org>
3
 
    Copyright (C) 2008 Omat Holding B.V. <info@omat.nl>
4
 
    Copyright (C) 2009 Kevin Ottens <ervin@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 "imapresource.h"
23
 
#include <qglobal.h>
24
 
#include "setupserver.h"
25
 
#include "settings.h"
26
 
#include "uidvalidityattribute.h"
27
 
#include "uidnextattribute.h"
28
 
#include "noselectattribute.h"
29
 
 
30
 
#include <QtCore/QDebug>
31
 
#include <QtDBus/QDBusConnection>
32
 
#include <QtNetwork/QSslSocket>
33
 
 
34
 
#include <kdebug.h>
35
 
#include <klocale.h>
36
 
#include <kpassworddialog.h>
37
 
#include <kmessagebox.h>
38
 
#include <KWindowSystem>
39
 
#include <KAboutData>
40
 
 
41
 
#include <kimap/session.h>
42
 
#include <kimap/sessionuiproxy.h>
43
 
 
44
 
#include <kimap/appendjob.h>
45
 
#include <kimap/capabilitiesjob.h>
46
 
#include <kimap/createjob.h>
47
 
#include <kimap/deletejob.h>
48
 
#include <kimap/expungejob.h>
49
 
#include <kimap/fetchjob.h>
50
 
#include <kimap/getacljob.h>
51
 
#include <kimap/getmetadatajob.h>
52
 
#include <kimap/getquotarootjob.h>
53
 
#include <kimap/listjob.h>
54
 
#include <kimap/loginjob.h>
55
 
#include <kimap/logoutjob.h>
56
 
#include <kimap/myrightsjob.h>
57
 
#include <kimap/renamejob.h>
58
 
#include <kimap/selectjob.h>
59
 
#include <kimap/storejob.h>
60
 
 
61
 
#include <kmime/kmime_message.h>
62
 
 
63
 
typedef boost::shared_ptr<KMime::Message> MessagePtr;
64
 
 
65
 
#include <akonadi/attributefactory.h>
66
 
#include <akonadi/cachepolicy.h>
67
 
#include <akonadi/collectionfetchjob.h>
68
 
#include <akonadi/collectionmodifyjob.h>
69
 
#include <akonadi/collectionstatisticsjob.h>
70
 
#include <akonadi/collectionstatistics.h>
71
 
#include <akonadi/monitor.h>
72
 
#include <akonadi/changerecorder.h>
73
 
#include <akonadi/collectiondeletejob.h>
74
 
#include <akonadi/itemdeletejob.h>
75
 
#include <akonadi/itemfetchjob.h>
76
 
#include <akonadi/itemfetchscope.h>
77
 
#include <akonadi/session.h>
78
 
#include <akonadi/transactionsequence.h>
79
 
 
80
 
#include "collectionflagsattribute.h"
81
 
#include "collectionannotationsattribute.h"
82
 
#include "imapaclattribute.h"
83
 
#include "imapquotaattribute.h"
84
 
 
85
 
#include "imapaccount.h"
86
 
 
87
 
using namespace Akonadi;
88
 
 
89
 
ImapResource::ImapResource( const QString &id )
90
 
        :ResourceBase( id ), m_account( 0 )
91
 
{
92
 
  Akonadi::AttributeFactory::registerAttribute<UidValidityAttribute>();
93
 
  Akonadi::AttributeFactory::registerAttribute<UidNextAttribute>();
94
 
  Akonadi::AttributeFactory::registerAttribute<NoSelectAttribute>();
95
 
  Akonadi::AttributeFactory::registerAttribute<CollectionFlagsAttribute>();
96
 
  Akonadi::AttributeFactory::registerAttribute<CollectionAnnotationsAttribute>();
97
 
  Akonadi::AttributeFactory::registerAttribute<ImapAclAttribute>();
98
 
  Akonadi::AttributeFactory::registerAttribute<ImapQuotaAttribute>();
99
 
 
100
 
  changeRecorder()->fetchCollection( true );
101
 
  changeRecorder()->itemFetchScope().fetchFullPayload( true );
102
 
 
103
 
  connect( this, SIGNAL(reloadConfiguration()), SLOT(startConnect()) );
104
 
  startConnect();
105
 
}
106
 
 
107
 
ImapResource::~ImapResource()
108
 
{
109
 
}
110
 
 
111
 
bool ImapResource::retrieveItem( const Akonadi::Item &item, const QSet<QByteArray> &parts )
112
 
{
113
 
    const QString remoteId = item.remoteId();
114
 
    const QStringList temp = remoteId.split( "-+-" );
115
 
    const QString mailBox = mailBoxForRemoteId( temp[0] );
116
 
    const qint64 uid = temp[1].toLongLong();
117
 
 
118
 
    KIMAP::SelectJob *select = new KIMAP::SelectJob( m_account->session() );
119
 
    select->setMailBox( mailBox );
120
 
    select->start();
121
 
    KIMAP::FetchJob *fetch = new KIMAP::FetchJob( m_account->session() );
122
 
    fetch->setProperty( "akonadiItem", QVariant::fromValue( item ) );
123
 
    KIMAP::FetchJob::FetchScope scope;
124
 
    fetch->setUidBased( true );
125
 
    fetch->setSequenceSet( KIMAP::ImapSet( uid ) );
126
 
    scope.parts.clear();// = parts.toList();
127
 
    scope.mode = KIMAP::FetchJob::FetchScope::Content;
128
 
    fetch->setScope( scope );
129
 
    connect( fetch, SIGNAL( messagesReceived( QString, QMap<qint64, qint64>, QMap<qint64, KIMAP::MessagePtr> ) ),
130
 
             this, SLOT( onMessagesReceived( QString, QMap<qint64, qint64>, QMap<qint64, KIMAP::MessagePtr> ) ) );
131
 
    connect( fetch, SIGNAL( partsReceived( QString, QMap<qint64, qint64>, QMap<qint64, KIMAP::MessageParts> ) ),
132
 
             this, SLOT( onPartsReceived( QString, QMap<qint64, qint64>, QMap<qint64, KIMAP::MessageParts> ) ) );
133
 
    connect( fetch, SIGNAL( result( KJob* ) ),
134
 
             this, SLOT( onContentFetchDone( KJob* ) ) );
135
 
    fetch->start();
136
 
    return true;
137
 
}
138
 
 
139
 
void ImapResource::onMessagesReceived( const QString &mailBox, const QMap<qint64, qint64> &uids,
140
 
                                       const QMap<qint64, KIMAP::MessagePtr> &messages )
141
 
{
142
 
  KIMAP::FetchJob *fetch = qobject_cast<KIMAP::FetchJob*>( sender() );
143
 
  Q_ASSERT( fetch!=0 );
144
 
  Q_ASSERT( uids.size()==1 );
145
 
  Q_ASSERT( messages.size()==1 );
146
 
 
147
 
  Item i = fetch->property( "akonadiItem" ).value<Item>();
148
 
 
149
 
  kDebug() << "MESSAGE from Imap server" << i.remoteId();
150
 
  Q_ASSERT( i.isValid() );
151
 
 
152
 
  KIMAP::MessagePtr message = messages[messages.keys().first()];
153
 
 
154
 
  i.setMimeType( "message/rfc822" );
155
 
  i.setPayload( MessagePtr( message ) );
156
 
 
157
 
  kDebug() << "Has Payload: " << i.hasPayload();
158
 
  kDebug() << message->head().isEmpty() << message->body().isEmpty() << message->contents().isEmpty() << message->hasContent() << message->hasHeader("Message-ID");
159
 
 
160
 
  itemRetrieved( i );
161
 
}
162
 
 
163
 
void ImapResource::onContentFetchDone( KJob *job )
164
 
{
165
 
  if ( job->error() ) {
166
 
    cancelTask( job->errorString() );
167
 
  } else {
168
 
    KIMAP::FetchJob *fetch = qobject_cast<KIMAP::FetchJob*>( job );
169
 
    if ( fetch->messages().isEmpty() && fetch->parts().isEmpty() ) {
170
 
      cancelTask( i18n("No message retrieved, server reply was empty.") );
171
 
    }
172
 
  }
173
 
}
174
 
 
175
 
void ImapResource::configure( WId windowId )
176
 
{
177
 
  SetupServer dlg( windowId );
178
 
  KWindowSystem::setMainWindow( &dlg, windowId );
179
 
 
180
 
  dlg.exec();
181
 
  if ( dlg.shouldClearCache() ) {
182
 
    clearCache();
183
 
  }
184
 
 
185
 
  if ( !Settings::self()->imapServer().isEmpty() && !Settings::self()->userName().isEmpty() ) {
186
 
    setName( Settings::self()->imapServer() + '/' + Settings::self()->userName() );
187
 
  } else {
188
 
    setName( KGlobal::mainComponent().aboutData()->appName() );
189
 
  }
190
 
 
191
 
  startConnect();
192
 
}
193
 
 
194
 
void ImapResource::startConnect( bool forceManualAuth )
195
 
{
196
 
  if ( Settings::self()->imapServer().isEmpty() ) {
197
 
    return;
198
 
  }
199
 
 
200
 
  QString password = Settings::self()->password();
201
 
 
202
 
  if ( password.isEmpty() || forceManualAuth ) {
203
 
    if ( !manualAuth( Settings::self()->userName(), password ) ) {
204
 
      return;
205
 
    }
206
 
  }
207
 
 
208
 
  delete m_account;
209
 
  m_account = new ImapAccount( Settings::self(), this );
210
 
 
211
 
  connect( m_account, SIGNAL( success() ),
212
 
           this, SLOT( onConnectSuccess() ) );
213
 
  connect( m_account, SIGNAL( error( int, const QString& ) ),
214
 
           this, SLOT( onConnectError( int, const QString& ) ) );
215
 
 
216
 
  m_account->connect( password );
217
 
}
218
 
 
219
 
void ImapResource::itemAdded( const Item &item, const Collection &collection )
220
 
{
221
 
  const QString mailBox = mailBoxForRemoteId( collection.remoteId() );
222
 
 
223
 
  // save message to the server.
224
 
  MessagePtr msg = item.payload<MessagePtr>();
225
 
 
226
 
  KIMAP::AppendJob *job = new KIMAP::AppendJob( m_account->session() );
227
 
  job->setProperty( "akonadiCollection", QVariant::fromValue( collection ) );
228
 
  job->setProperty( "akonadiItem", QVariant::fromValue( item ) );
229
 
  job->setMailBox( mailBox );
230
 
  job->setContent( msg->encodedContent( true ) );
231
 
  connect( job, SIGNAL( result( KJob* ) ), SLOT( onAppendMessageDone( KJob* ) ) );
232
 
  job->start();
233
 
}
234
 
 
235
 
void ImapResource::onAppendMessageDone( KJob *job )
236
 
{
237
 
  KIMAP::AppendJob *append = qobject_cast<KIMAP::AppendJob*>( job );
238
 
 
239
 
  const QString collectionRemoteId = remoteIdForMailBox( append->mailBox() );
240
 
  Item item = job->property( "akonadiItem" ).value<Item>();
241
 
 
242
 
  if ( append->error() ) {
243
 
    deferTask();
244
 
  }
245
 
 
246
 
  qint64 uid = append->uid();
247
 
  Q_ASSERT( uid > 0 );
248
 
 
249
 
  const QString remoteId =  collectionRemoteId + "-+-" + QString::number( uid );
250
 
  kDebug() << "Setting remote ID to " << remoteId;
251
 
  item.setRemoteId( remoteId );
252
 
 
253
 
  changeCommitted( item );
254
 
 
255
 
  // Check if it we got here because an itemChanged() call
256
 
  // (since in IMAP you're forced to append+remove in this case)
257
 
  qint64 oldUid = job->property( "oldUid" ).toLongLong();
258
 
  if ( oldUid ) {
259
 
    // OK it's indeed a content change, so we've to mark the old version as deleted
260
 
    KIMAP::StoreJob *store = new KIMAP::StoreJob( m_account->session() );
261
 
    store->setUidBased( true );
262
 
    store->setSequenceSet( KIMAP::ImapSet( oldUid ) );
263
 
    store->setFlags( QList<QByteArray>() << "\\Deleted" );
264
 
    store->setMode( KIMAP::StoreJob::AppendFlags );
265
 
    store->start();
266
 
  }
267
 
 
268
 
  Collection collection = job->property( "akonadiCollection" ).value<Collection>();
269
 
  if ( !collection.isValid() ) {
270
 
    collection = collectionFromRemoteId( collectionRemoteId );
271
 
  }
272
 
 
273
 
  // Get the current uid next value and store it
274
 
  UidNextAttribute *uidAttr = 0;
275
 
  int oldNextUid = 0;
276
 
  if ( collection.hasAttribute( "uidnext" ) ) {
277
 
    uidAttr = static_cast<UidNextAttribute*>( collection.attribute( "uidnext" ) );
278
 
    oldNextUid = uidAttr->uidNext();
279
 
  }
280
 
 
281
 
  // If the uid we just got back is the expected next one of the box
282
 
  // then update the property to the probable next uid to keep the cache in sync.
283
 
  // If not something happened in our back, so we don't update and a refetch will
284
 
  // happen at some point.
285
 
  if ( uid==oldNextUid ) {
286
 
    if ( uidAttr==0 ) {
287
 
      uidAttr = new UidNextAttribute( uid+1 );
288
 
      collection.addAttribute( uidAttr );
289
 
    } else {
290
 
      uidAttr->setUidNext( uid+1 );
291
 
    }
292
 
 
293
 
    CollectionModifyJob *modify = new CollectionModifyJob( collection );
294
 
  }
295
 
}
296
 
 
297
 
void ImapResource::itemChanged( const Item &item, const QSet<QByteArray> &parts )
298
 
{
299
 
  kDebug() << item.remoteId() << parts;
300
 
 
301
 
  const QString remoteId = item.remoteId();
302
 
  const QStringList temp = remoteId.split( "-+-" );
303
 
  const QString mailBox = mailBoxForRemoteId( temp[0] );
304
 
  const qint64 uid = temp[1].toLongLong();
305
 
 
306
 
  if ( parts.contains( "PLD:RFC822" ) ) {
307
 
    // save message to the server.
308
 
    MessagePtr msg = item.payload<MessagePtr>();
309
 
 
310
 
    KIMAP::AppendJob *job = new KIMAP::AppendJob( m_account->session() );
311
 
    job->setProperty( "akonadiItem", QVariant::fromValue( item ) );
312
 
    job->setProperty( "oldUid", uid ); // Will be used in onAppendMessageDone
313
 
    job->setMailBox( mailBox );
314
 
    job->setContent( msg->encodedContent( true ) );
315
 
    job->setFlags( item.flags().toList() );
316
 
    connect( job, SIGNAL( result( KJob* ) ), SLOT( onAppendMessageDone( KJob* ) ) );
317
 
    job->start();
318
 
 
319
 
  } else if ( parts.contains( "FLAGS" ) ) {
320
 
    KIMAP::SelectJob *select = new KIMAP::SelectJob( m_account->session() );
321
 
    select->setMailBox( mailBox );
322
 
    select->start();
323
 
    KIMAP::StoreJob *store = new KIMAP::StoreJob( m_account->session() );
324
 
    store->setProperty( "akonadiItem", QVariant::fromValue( item ) );
325
 
    store->setProperty( "itemUid", uid );
326
 
    store->setUidBased( true );
327
 
    store->setSequenceSet( KIMAP::ImapSet( uid ) );
328
 
    store->setFlags( item.flags().toList() );
329
 
    store->setMode( KIMAP::StoreJob::SetFlags );
330
 
    connect( store, SIGNAL( result( KJob* ) ), SLOT( onStoreFlagsDone( KJob* ) ) );
331
 
    store->start();
332
 
  }
333
 
}
334
 
 
335
 
void ImapResource::onStoreFlagsDone( KJob *job )
336
 
{
337
 
  KIMAP::StoreJob *store = qobject_cast<KIMAP::StoreJob*>( job );
338
 
 
339
 
  if ( store->error() ) {
340
 
    deferTask();
341
 
  }
342
 
 
343
 
  Item item = job->property( "akonadiItem" ).value<Item>();
344
 
  qint64 uid = job->property( "itemUid" ).toLongLong();
345
 
  bool itemRemoval = job->property( "itemRemoval" ).toBool();
346
 
 
347
 
  if ( !itemRemoval ) {
348
 
    item.setFlags( store->resultingFlags()[uid].toSet() );
349
 
    changeCommitted( item );
350
 
  } else {
351
 
    changeProcessed();
352
 
  }
353
 
}
354
 
 
355
 
void ImapResource::itemRemoved( const Akonadi::Item &item )
356
 
{
357
 
  // The imap specs do not allow for a single message to be deleted. We can only
358
 
  // set the \Deleted flag. The message will actually be deleted when EXPUNGE will
359
 
  // be issued on the next retrieveItems().
360
 
 
361
 
  const QString remoteId = item.remoteId();
362
 
  const QStringList temp = remoteId.split( "-+-" );
363
 
  const QString mailBox = mailBoxForRemoteId( temp[0] );
364
 
  const qint64 uid = temp[1].toLongLong();
365
 
 
366
 
  KIMAP::SelectJob *select = new KIMAP::SelectJob( m_account->session() );
367
 
  select->setMailBox( mailBox );
368
 
  select->start();
369
 
  KIMAP::StoreJob *store = new KIMAP::StoreJob( m_account->session() );
370
 
  store->setProperty( "akonadiItem", QVariant::fromValue( item ) );
371
 
  store->setProperty( "itemRemoval", true );
372
 
  store->setUidBased( true );
373
 
  store->setSequenceSet( KIMAP::ImapSet( uid ) );
374
 
  store->setFlags( QList<QByteArray>() << "\\Deleted" );
375
 
  store->setMode( KIMAP::StoreJob::AppendFlags );
376
 
  connect( store, SIGNAL( result( KJob* ) ), SLOT( onStoreFlagsDone( KJob* ) ) );
377
 
  store->start();
378
 
}
379
 
 
380
 
void ImapResource::retrieveCollections()
381
 
{
382
 
  if ( !m_account || !m_account->session() ) {
383
 
    kDebug() << "Ignoring this request. Probably there is no connection.";
384
 
    cancelTask();
385
 
    return;
386
 
  }
387
 
 
388
 
  Collection root;
389
 
  root.setName( m_account->server() + '/' + m_account->userName() );
390
 
  root.setRemoteId( rootRemoteId() );
391
 
  root.setContentMimeTypes( QStringList( Collection::mimeType() ) );
392
 
 
393
 
  CachePolicy policy;
394
 
  policy.setInheritFromParent( false );
395
 
  policy.setSyncOnDemand( true );
396
 
  root.setCachePolicy( policy );
397
 
 
398
 
  setCollectionStreamingEnabled( true );
399
 
  collectionsRetrievedIncremental( Collection::List() << root, Collection::List() );
400
 
 
401
 
  KIMAP::ListJob *listJob = new KIMAP::ListJob( m_account->session() );
402
 
  listJob->setIncludeUnsubscribed( !m_account->isSubscriptionEnabled() );
403
 
  connect( listJob, SIGNAL( mailBoxesReceived(QList<KIMAP::MailBoxDescriptor>, QList< QList<QByteArray> >) ),
404
 
           this, SLOT( onMailBoxesReceived(QList<KIMAP::MailBoxDescriptor>, QList< QList<QByteArray> >) ) );
405
 
  connect( listJob, SIGNAL(result(KJob*)), SLOT(onMailBoxesReceiveDone(KJob*)) );
406
 
  listJob->start();
407
 
}
408
 
 
409
 
void ImapResource::onMailBoxesReceived( const QList< KIMAP::MailBoxDescriptor > &descriptors,
410
 
                                        const QList< QList<QByteArray> > &flags )
411
 
{
412
 
  QStringList reportedPaths = sender()->property("reportedPaths").toStringList();
413
 
 
414
 
  Collection::List collections;
415
 
  QStringList contentTypes;
416
 
  contentTypes << "message/rfc822" << Collection::mimeType();
417
 
 
418
 
  for ( int i=0; i<descriptors.size(); ++i ) {
419
 
    KIMAP::MailBoxDescriptor descriptor = descriptors[i];
420
 
 
421
 
    QStringList pathParts = descriptor.name.split(descriptor.separator);
422
 
    QString separator = descriptor.separator;
423
 
 
424
 
    QString parentPath;
425
 
    QString currentPath;
426
 
 
427
 
    foreach ( const QString &pathPart, pathParts ) {
428
 
      currentPath+='/'+pathPart;
429
 
      if ( currentPath.startsWith( '/' ) ) {
430
 
        currentPath.remove( 0, 1 );
431
 
      }
432
 
 
433
 
      if ( reportedPaths.contains( currentPath ) ) {
434
 
        parentPath = currentPath;
435
 
        continue;
436
 
      } else {
437
 
        reportedPaths << currentPath;
438
 
      }
439
 
 
440
 
      Collection c;
441
 
      c.setName( pathPart );
442
 
      c.setRemoteId( remoteIdForMailBox( currentPath ) );
443
 
      c.setParentRemoteId( remoteIdForMailBox( parentPath ) );
444
 
      c.setRights( Collection::AllRights );
445
 
      c.setContentMimeTypes( contentTypes );
446
 
 
447
 
      CachePolicy cachePolicy;
448
 
      cachePolicy.setInheritFromParent( false );
449
 
      cachePolicy.setIntervalCheckTime( -1 );
450
 
      cachePolicy.setSyncOnDemand( true );
451
 
 
452
 
      // If the folder is the Inbox, make some special settings.
453
 
      if ( currentPath.compare( QLatin1String("INBOX") , Qt::CaseInsensitive ) == 0 ) {
454
 
        cachePolicy.setIntervalCheckTime( 1 );
455
 
        c.setName( "Inbox" );
456
 
      }
457
 
 
458
 
      // If this folder is a noselect folder, make some special settings.
459
 
      if ( flags[i].contains( "\\NoSelect" ) ) {
460
 
        cachePolicy.setSyncOnDemand( false );
461
 
        c.addAttribute( new NoSelectAttribute( true ) );
462
 
      }
463
 
 
464
 
      c.setCachePolicy( cachePolicy );
465
 
 
466
 
      collections << c;
467
 
      parentPath = currentPath;
468
 
    }
469
 
  }
470
 
 
471
 
  sender()->setProperty("reportedPaths", reportedPaths);
472
 
  collectionsRetrievedIncremental( collections, Collection::List() );
473
 
}
474
 
 
475
 
void ImapResource::onMailBoxesReceiveDone(KJob* job)
476
 
{
477
 
  // TODO error handling
478
 
  collectionsRetrievalDone();
479
 
}
480
 
 
481
 
// ----------------------------------------------------------------------------------
482
 
 
483
 
void ImapResource::retrieveItems( const Collection &col )
484
 
{
485
 
  kDebug( ) << col.remoteId();
486
 
 
487
 
  // Prevent fetching items from noselect folders.
488
 
  if ( col.hasAttribute( "noselect" ) ) {
489
 
    NoSelectAttribute* noselect = static_cast<NoSelectAttribute*>( col.attribute( "noselect" ) );
490
 
    if ( noselect->noSelect() ) {
491
 
      kDebug() << "No Select folder";
492
 
      itemsRetrievalDone();
493
 
      return;
494
 
    }
495
 
  }
496
 
 
497
 
  const QString mailBox = mailBoxForRemoteId( col.remoteId() );
498
 
  const QStringList capabilities = m_account->capabilities();
499
 
 
500
 
  // First get the annotations from the mailbox if it's supported
501
 
  if ( capabilities.contains( "METADATA" ) || capabilities.contains( "ANNOTATEMORE" ) ) {
502
 
    KIMAP::GetMetaDataJob *meta = new KIMAP::GetMetaDataJob( m_account->session() );
503
 
    meta->setProperty( "akonadiCollection", QVariant::fromValue( col ) );
504
 
    meta->setMailBox( mailBox );
505
 
    if ( capabilities.contains( "METADATA" ) ) {
506
 
      meta->setServerCapability( KIMAP::MetaDataJobBase::Metadata );
507
 
      meta->addEntry( "*" );
508
 
    } else {
509
 
      meta->setServerCapability( KIMAP::MetaDataJobBase::Annotatemore );
510
 
      meta->addEntry( "*", "value.shared" );
511
 
    }
512
 
    connect( meta, SIGNAL( result( KJob* ) ), SLOT( onGetMetaDataDone( KJob* ) ) );
513
 
    meta->start();
514
 
  }
515
 
 
516
 
  // Get the ACLs from the mailbox if it's supported
517
 
  if ( capabilities.contains( "ACL" ) ) {
518
 
    KIMAP::GetAclJob *acl = new KIMAP::GetAclJob( m_account->session() );
519
 
    acl->setProperty( "akonadiCollection", QVariant::fromValue( col ) );
520
 
    acl->setMailBox( mailBox );
521
 
    connect( acl, SIGNAL( result( KJob* ) ), SLOT( onGetAclDone( KJob* ) ) );
522
 
    acl->start();
523
 
 
524
 
    KIMAP::MyRightsJob *rights = new KIMAP::MyRightsJob( m_account->session() );
525
 
    rights->setProperty( "akonadiCollection", QVariant::fromValue( col ) );
526
 
    rights->setMailBox( mailBox );
527
 
    connect( rights, SIGNAL( result( KJob* ) ), SLOT( onRightsReceived( KJob* ) ) );
528
 
    rights->start();
529
 
  }
530
 
 
531
 
  // Get the QUOTA info from the mailbox if it's supported
532
 
  if ( capabilities.contains( "QUOTA" ) ) {
533
 
    KIMAP::GetQuotaRootJob *quota = new KIMAP::GetQuotaRootJob( m_account->session() );
534
 
    quota->setProperty( "akonadiCollection", QVariant::fromValue( col ) );
535
 
    quota->setMailBox( mailBox );
536
 
    connect( quota, SIGNAL( result( KJob* ) ), SLOT( onQuotasReceived( KJob* ) ) );
537
 
    quota->start();
538
 
  }
539
 
 
540
 
  // Now is the right time to expunge the messages marked \\Deleted from this mailbox.
541
 
  KIMAP::SelectJob *select = new KIMAP::SelectJob( m_account->session() );
542
 
  select->setMailBox( mailBox );
543
 
  select->start();
544
 
  KIMAP::ExpungeJob *expunge = new KIMAP::ExpungeJob( m_account->session() );
545
 
  expunge->start();
546
 
 
547
 
  // Issue another select to get the updated info from the mailbox
548
 
  select = new KIMAP::SelectJob( m_account->session() );
549
 
  select->setMailBox( mailBox );
550
 
  connect( select, SIGNAL( result( KJob* ) ),
551
 
           this, SLOT( onSelectDone( KJob* ) ) );
552
 
  select->start();
553
 
}
554
 
 
555
 
void ImapResource::onHeadersReceived( const QString &mailBox, const QMap<qint64, qint64> &uids,
556
 
                                      const QMap<qint64, qint64> &sizes,
557
 
                                      const QMap<qint64, KIMAP::MessageFlags> &flags,
558
 
                                      const QMap<qint64, KIMAP::MessagePtr> &messages )
559
 
{
560
 
  Item::List addedItems;
561
 
 
562
 
  foreach ( qint64 number, uids.keys() ) {
563
 
    Akonadi::Item i;
564
 
    i.setRemoteId( remoteIdForMailBox( mailBox ) + "-+-" + QString::number( uids[number] ) );
565
 
    i.setMimeType( "message/rfc822" );
566
 
    i.setPayload( MessagePtr( messages[number] ) );
567
 
    i.setSize( sizes[number] );
568
 
 
569
 
    foreach( const QByteArray &flag, flags[number] ) {
570
 
      i.setFlag( flag );
571
 
    }
572
 
    kDebug() << "Flags: " << i.flags();
573
 
    addedItems << i;
574
 
  }
575
 
 
576
 
  itemsRetrievedIncremental( addedItems, Item::List() );
577
 
}
578
 
 
579
 
void ImapResource::onHeadersFetchDone( KJob */*job*/ )
580
 
{
581
 
  itemsRetrievalDone();
582
 
}
583
 
 
584
 
 
585
 
// ----------------------------------------------------------------------------------
586
 
 
587
 
void ImapResource::collectionAdded( const Collection & collection, const Collection &parent )
588
 
{
589
 
  const QString remoteName = parent.remoteId() + '/' + collection.name();
590
 
 
591
 
  kDebug( ) << "New folder: " << remoteName;
592
 
 
593
 
  Collection c = collection;
594
 
  c.setRemoteId( remoteName );
595
 
 
596
 
  const QString mailBox = mailBoxForRemoteId( remoteName );
597
 
 
598
 
  KIMAP::CreateJob *job = new KIMAP::CreateJob( m_account->session() );
599
 
  job->setProperty( "akonadiCollection", QVariant::fromValue( c ) );
600
 
  job->setMailBox( mailBox );
601
 
  connect( job, SIGNAL( result( KJob* ) ), SLOT( onCreateMailBoxDone( KJob* ) ) );
602
 
  job->start();
603
 
}
604
 
 
605
 
void ImapResource::onCreateMailBoxDone( KJob *job )
606
 
{
607
 
  Collection collection = job->property( "akonadiCollection" ).value<Collection>();
608
 
 
609
 
  if ( !job->error() ) {
610
 
    changeCommitted( collection );
611
 
  } else {
612
 
    // remove the collection again.
613
 
    kDebug() << "Failed to create the folder, deleting it in akonadi again";
614
 
    emit warning( i18n( "Failed to create the folder, restoring folder list." ) );
615
 
    new CollectionDeleteJob( collection, this );
616
 
  }
617
 
}
618
 
 
619
 
void ImapResource::collectionChanged( const Collection & collection )
620
 
{
621
 
  QString oldRemoteId = collection.remoteId();
622
 
  QString parentRemoteId = oldRemoteId.mid( 0, oldRemoteId.lastIndexOf('/') );
623
 
 
624
 
  QString newRemoteId = parentRemoteId + '/' + collection.name();
625
 
 
626
 
  Collection c = collection;
627
 
  c.setRemoteId( newRemoteId );
628
 
 
629
 
  const QString oldMailBox = mailBoxForRemoteId( oldRemoteId );
630
 
  const QString newMailBox = mailBoxForRemoteId( newRemoteId );
631
 
 
632
 
  KIMAP::RenameJob *job = new KIMAP::RenameJob( m_account->session() );
633
 
  job->setProperty( "akonadiCollection", QVariant::fromValue( c ) );
634
 
  job->setSourceMailBox( oldMailBox );
635
 
  job->setDestinationMailBox( newMailBox );
636
 
  connect( job, SIGNAL( result( KJob* ) ), SLOT( onRenameMailBoxDone( KJob* ) ) );
637
 
  job->start();
638
 
}
639
 
 
640
 
void ImapResource::onRenameMailBoxDone( KJob *job )
641
 
{
642
 
  Collection collection = job->property( "akonadiCollection" ).value<Collection>();
643
 
 
644
 
  if ( !job->error() ) {
645
 
    changeCommitted( collection );
646
 
  } else {
647
 
    KIMAP::RenameJob *rename = qobject_cast<KIMAP::RenameJob*>( job );
648
 
 
649
 
    // rename the collection again.
650
 
    kDebug() << "Failed to rename the folder, resetting it in akonadi again";
651
 
    collection.setName( rename->sourceMailBox().split('/').last() );
652
 
    collection.setRemoteId( remoteIdForMailBox( rename->sourceMailBox() ) );
653
 
    emit warning( i18n( "Failed to rename the folder, restoring folder list." ) );
654
 
    changeCommitted( collection );
655
 
  }
656
 
}
657
 
 
658
 
void ImapResource::collectionRemoved( const Collection &collection )
659
 
{
660
 
  const QString mailBox = mailBoxForRemoteId( collection.remoteId() );
661
 
 
662
 
  KIMAP::DeleteJob *job = new KIMAP::DeleteJob( m_account->session() );
663
 
  job->setProperty( "akonadiCollection", QVariant::fromValue( collection ) );
664
 
  job->setMailBox( mailBox );
665
 
  connect( job, SIGNAL( result( KJob* ) ), SLOT( onDeleteMailBoxDone( KJob* ) ) );
666
 
  job->start();
667
 
}
668
 
 
669
 
void ImapResource::onDeleteMailBoxDone( KJob *job )
670
 
{
671
 
  // finish the task.
672
 
  changeProcessed();
673
 
 
674
 
    if ( !job->error() ) {
675
 
        kDebug() << "Failed to delete the folder, resync the folder tree";
676
 
        emit warning( i18n( "Failed to delete the folder, restoring folder list." ) );
677
 
        synchronizeCollectionTree();
678
 
    }
679
 
}
680
 
 
681
 
/******************* Slots  ***********************************************/
682
 
 
683
 
void ImapResource::onConnectError( int code, const QString &message )
684
 
{
685
 
  if ( code==ImapAccount::LoginFailError ) {
686
 
    // the credentials where not ok....
687
 
    int i = KMessageBox::questionYesNoCancelWId( winIdForDialogs(),
688
 
                                                 i18n( "The server refused the supplied username and password. "
689
 
                                                       "Do you want to go to the settings, have another attempt "
690
 
                                                       "at logging in, or do nothing?" ),
691
 
                                                 i18n( "Could Not Authenticate" ),
692
 
                                                 KGuiItem( i18n( "Settings" ) ),
693
 
                                                 KGuiItem( i18nc( "Input username/password manually and not store them", "Single Input" ) ) );
694
 
    if ( i == KMessageBox::Yes ) {
695
 
      configure( winIdForDialogs() );
696
 
      return;
697
 
    } else if ( i == KMessageBox::No ) {
698
 
      startConnect( true );
699
 
      return;
700
 
    } else {
701
 
      KIMAP::LogoutJob *logout = new KIMAP::LogoutJob( m_account->session() );
702
 
      logout->start();
703
 
      emit warning( i18n( "Could not connect to the IMAP-server %1.", m_account->server() ) );
704
 
    }
705
 
  }
706
 
 
707
 
  m_account->disconnect();
708
 
  emit error( message );
709
 
}
710
 
 
711
 
void ImapResource::onConnectSuccess()
712
 
{
713
 
  synchronizeCollectionTree();
714
 
}
715
 
 
716
 
void ImapResource::onGetAclDone( KJob *job )
717
 
{
718
 
  if ( job->error() ) {
719
 
    return; // Well, no metadata for us then...
720
 
  }
721
 
 
722
 
  KIMAP::GetAclJob *acl = qobject_cast<KIMAP::GetAclJob*>( job );
723
 
  Collection collection = job->property( "akonadiCollection" ).value<Collection>();
724
 
 
725
 
  // Store the mailbox ACLs
726
 
  if ( !collection.hasAttribute( "imapacl" ) ) {
727
 
    ImapAclAttribute *aclAttribute  = new ImapAclAttribute( acl->allRights() );
728
 
    collection.addAttribute( aclAttribute );
729
 
  } else {
730
 
    ImapAclAttribute *aclAttribute =
731
 
      static_cast<ImapAclAttribute*>( collection.attribute( "imapacl" ) );
732
 
    const QMap<QByteArray, KIMAP::Acl::Rights> oldRights = aclAttribute->rights();
733
 
    if ( oldRights != acl->allRights() ) {
734
 
      aclAttribute->setRights( acl->allRights() );
735
 
    }
736
 
  }
737
 
 
738
 
  CollectionModifyJob *modify = new CollectionModifyJob( collection );
739
 
}
740
 
 
741
 
void ImapResource::onRightsReceived( KJob *job )
742
 
{
743
 
  if ( job->error() ) {
744
 
    return; // Well, no metadata for us then...
745
 
  }
746
 
 
747
 
  KIMAP::MyRightsJob *rightsJob = qobject_cast<KIMAP::MyRightsJob*>( job );
748
 
  Collection collection = job->property( "akonadiCollection" ).value<Collection>();
749
 
 
750
 
  KIMAP::Acl::Rights imapRights = rightsJob->rights();
751
 
  Collection::Rights newRights = Collection::ReadOnly;
752
 
 
753
 
  if ( imapRights & KIMAP::Acl::Write ) {
754
 
    newRights|= Collection::CanChangeItem;
755
 
  }
756
 
 
757
 
  if ( imapRights & KIMAP::Acl::Insert ) {
758
 
    newRights|= Collection::CanCreateItem;
759
 
  }
760
 
 
761
 
  if ( imapRights & KIMAP::Acl::DeleteMessage ) {
762
 
    newRights|= Collection::CanDeleteItem;
763
 
  }
764
 
 
765
 
  if ( imapRights & KIMAP::Acl::CreateMailbox ) {
766
 
    newRights|= Collection::CanChangeCollection;
767
 
    newRights|= Collection::CanCreateCollection;
768
 
  }
769
 
 
770
 
  if ( imapRights & KIMAP::Acl::DeleteMailbox ) {
771
 
    newRights|= Collection::CanDeleteCollection;
772
 
  }
773
 
 
774
 
  if ( newRights != collection.rights() ) {
775
 
    collection.setRights( newRights );
776
 
 
777
 
    CollectionModifyJob *modify = new CollectionModifyJob( collection );
778
 
  }
779
 
}
780
 
 
781
 
void ImapResource::onQuotasReceived( KJob *job )
782
 
{
783
 
  if ( job->error() ) {
784
 
    return; // Well, no metadata for us then...
785
 
  }
786
 
 
787
 
  KIMAP::GetQuotaRootJob *quotaJob = qobject_cast<KIMAP::GetQuotaRootJob*>( job );
788
 
  Collection collection = job->property( "akonadiCollection" ).value<Collection>();
789
 
 
790
 
  QList<QByteArray> newRoots = quotaJob->roots();
791
 
  QList< QMap<QByteArray, qint64> > newLimits;
792
 
  QList< QMap<QByteArray, qint64> > newUsages;
793
 
 
794
 
  foreach ( const QByteArray &root, newRoots ) {
795
 
    newLimits << quotaJob->allLimits( root );
796
 
    newUsages << quotaJob->allUsages( root );
797
 
  }
798
 
 
799
 
  // Store the mailbox Quotas
800
 
  if ( !collection.hasAttribute( "imapquota" ) ) {
801
 
    ImapQuotaAttribute *quotaAttribute  = new ImapQuotaAttribute( newRoots, newLimits, newUsages );
802
 
    collection.addAttribute( quotaAttribute );
803
 
  } else {
804
 
    ImapQuotaAttribute *quotaAttribute =
805
 
      static_cast<ImapQuotaAttribute*>( collection.attribute( "imapquota" ) );
806
 
    const QList<QByteArray> oldRoots = quotaAttribute->roots();
807
 
    const QList< QMap<QByteArray, qint64> > oldLimits = quotaAttribute->limits();
808
 
    const QList< QMap<QByteArray, qint64> > oldUsages = quotaAttribute->usages();
809
 
 
810
 
    if ( oldRoots != newRoots
811
 
      || oldLimits != newLimits
812
 
      || oldUsages != newUsages ) {
813
 
      quotaAttribute->setQuotas( newRoots, newLimits, newUsages );
814
 
    }
815
 
  }
816
 
 
817
 
  CollectionModifyJob *modify = new CollectionModifyJob( collection );
818
 
}
819
 
 
820
 
void ImapResource::onGetMetaDataDone( KJob *job )
821
 
{
822
 
  if ( job->error() ) {
823
 
    return; // Well, no metadata for us then...
824
 
  }
825
 
 
826
 
  KIMAP::GetMetaDataJob *meta = qobject_cast<KIMAP::GetMetaDataJob*>( job );
827
 
  QMap<QByteArray, QMap<QByteArray, QByteArray> > rawAnnotations = meta->allMetaData( meta->mailBox() );
828
 
 
829
 
  QMap<QByteArray, QByteArray> annotations;
830
 
  QByteArray attribute = "";
831
 
  if ( meta->serverCapability()==KIMAP::MetaDataJobBase::Annotatemore ) {
832
 
    attribute = "value.shared";
833
 
  }
834
 
 
835
 
  foreach ( const QByteArray &entry, rawAnnotations.keys() ) {
836
 
    annotations[entry] = rawAnnotations[entry][attribute];
837
 
  }
838
 
 
839
 
  Collection collection = job->property( "akonadiCollection" ).value<Collection>();
840
 
 
841
 
  // Store the mailbox metadata
842
 
  CollectionAnnotationsAttribute *annotationsAttribute =
843
 
    collection.attribute<CollectionAnnotationsAttribute>( Collection::AddIfMissing );
844
 
  const QMap<QByteArray, QByteArray> oldAnnotations = annotationsAttribute->annotations();
845
 
  if ( oldAnnotations != annotations ) {
846
 
    annotationsAttribute->setAnnotations( annotations );
847
 
  }
848
 
 
849
 
  CollectionModifyJob *modify = new CollectionModifyJob( collection );
850
 
}
851
 
 
852
 
void ImapResource::onSelectDone( KJob *job )
853
 
{
854
 
  if ( job->error() ) {
855
 
    itemsRetrievalDone();
856
 
    return;
857
 
  }
858
 
 
859
 
  KIMAP::SelectJob *select = qobject_cast<KIMAP::SelectJob*>( job );
860
 
 
861
 
  const QString mailBox = select->mailBox();
862
 
  const int messageCount = select->messageCount();
863
 
  const qint64 uidValidity = select->uidValidity();
864
 
  const qint64 nextUid = select->nextUid();
865
 
  const QList<QByteArray> flags = select->flags();
866
 
 
867
 
  // uidvalidity can change between sessions, we don't want to refetch
868
 
  // folders in that case. Keep track of what is processed and what not.
869
 
  static QStringList processed;
870
 
  bool firstTime = false;
871
 
  if ( processed.indexOf( mailBox ) == -1 ) {
872
 
    firstTime = true;
873
 
    processed.append( mailBox );
874
 
  }
875
 
 
876
 
  Collection collection = collectionFromRemoteId( remoteIdForMailBox( mailBox ) );
877
 
  Q_ASSERT( collection.isValid() );
878
 
 
879
 
  // Get the current uid validity value and store it
880
 
  int oldUidValidity = 0;
881
 
  if ( !collection.hasAttribute( "uidvalidity" ) ) {
882
 
    UidValidityAttribute* currentUidValidity  = new UidValidityAttribute( uidValidity );
883
 
    collection.addAttribute( currentUidValidity );
884
 
  } else {
885
 
    UidValidityAttribute* currentUidValidity =
886
 
      static_cast<UidValidityAttribute*>( collection.attribute( "uidvalidity" ) );
887
 
    oldUidValidity = currentUidValidity->uidValidity();
888
 
    if ( oldUidValidity != uidValidity ) {
889
 
      currentUidValidity->setUidValidity( uidValidity );
890
 
    }
891
 
  }
892
 
 
893
 
  // Get the current uid next value and store it
894
 
  int oldNextUid = 0;
895
 
  if ( !collection.hasAttribute( "uidnext" ) ) {
896
 
    UidNextAttribute* currentNextUid  = new UidNextAttribute( nextUid );
897
 
    collection.addAttribute( currentNextUid );
898
 
  } else {
899
 
    UidNextAttribute* currentNextUid =
900
 
      static_cast<UidNextAttribute*>( collection.attribute( "uidnext" ) );
901
 
    oldNextUid = currentNextUid->uidNext();
902
 
    if ( oldNextUid != nextUid ) {
903
 
      currentNextUid->setUidNext( nextUid );
904
 
    }
905
 
  }
906
 
 
907
 
  // Store the mailbox flags
908
 
  if ( !collection.hasAttribute( "collectionflags" ) ) {
909
 
    CollectionFlagsAttribute *flagsAttribute  = new CollectionFlagsAttribute( flags );
910
 
    collection.addAttribute( flagsAttribute );
911
 
  } else {
912
 
    CollectionFlagsAttribute *flagsAttribute =
913
 
      static_cast<CollectionFlagsAttribute*>( collection.attribute( "collectionflags" ) );
914
 
    const QList<QByteArray> oldFlags = flagsAttribute->flags();
915
 
    if ( oldFlags != flags ) {
916
 
      flagsAttribute->setFlags( flags );
917
 
    }
918
 
  }
919
 
 
920
 
  CollectionModifyJob *modify = new CollectionModifyJob( collection );
921
 
 
922
 
  // First check the uidvalidity, if this has changed, it means the folder
923
 
  // has been deleted and recreated. So we wipe out the messages and
924
 
  // retrieve all.
925
 
  if ( oldUidValidity != uidValidity && !firstTime
926
 
    && oldUidValidity != 0 ) {
927
 
    kDebug() << "UIDVALIDITY check failed (" << oldUidValidity << "|"
928
 
             << uidValidity <<") refetching "<< mailBox;
929
 
 
930
 
    setItemStreamingEnabled( true );
931
 
 
932
 
    KIMAP::FetchJob *fetch = new KIMAP::FetchJob( m_account->session() );
933
 
    KIMAP::FetchJob::FetchScope scope;
934
 
    fetch->setSequenceSet( KIMAP::ImapSet( 1, messageCount ) );
935
 
    scope.parts.clear();
936
 
    scope.mode = KIMAP::FetchJob::FetchScope::Headers;
937
 
    fetch->setScope( scope );
938
 
    connect( fetch, SIGNAL( headersReceived( QString, QMap<qint64, qint64>, QMap<qint64, qint64>,
939
 
                                             QMap<qint64, KIMAP::MessageFlags>, QMap<qint64, KIMAP::MessagePtr> ) ),
940
 
             this, SLOT( onHeadersReceived( QString, QMap<qint64, qint64>, QMap<qint64, qint64>,
941
 
                                            QMap<qint64, KIMAP::MessageFlags>, QMap<qint64, KIMAP::MessagePtr> ) ) );
942
 
    connect( fetch, SIGNAL( result( KJob* ) ),
943
 
             this, SLOT( onHeadersFetchDone( KJob* ) ) );
944
 
    fetch->start();
945
 
    return;
946
 
  }
947
 
 
948
 
  // See how many messages are in the folder currently
949
 
  qint64 realMessageCount = collection.statistics().count();
950
 
  if ( realMessageCount == -1 ) {
951
 
    Akonadi::CollectionStatisticsJob *job = new Akonadi::CollectionStatisticsJob( collection );
952
 
    if ( job->exec() ) {
953
 
      Akonadi::CollectionStatistics statistics = job->statistics();
954
 
      realMessageCount = statistics.count();
955
 
    }
956
 
  }
957
 
 
958
 
  kDebug() << "integrity: " << mailBox << " should be: " << messageCount << " current: " << realMessageCount;
959
 
 
960
 
  if ( messageCount > realMessageCount ) {
961
 
    // The amount on the server is bigger than that we have in the cache
962
 
    // that probably means that there is new mail. Fetch missing.
963
 
    kDebug() << "Fetch missing: " << messageCount << " But: " << realMessageCount;
964
 
 
965
 
    setItemStreamingEnabled( true );
966
 
 
967
 
    KIMAP::FetchJob *fetch = new KIMAP::FetchJob( m_account->session() );
968
 
    KIMAP::FetchJob::FetchScope scope;
969
 
    fetch->setSequenceSet( KIMAP::ImapSet( realMessageCount+1, messageCount ) );
970
 
    scope.parts.clear();
971
 
    scope.mode = KIMAP::FetchJob::FetchScope::Headers;
972
 
    fetch->setScope( scope );
973
 
    connect( fetch, SIGNAL( headersReceived( QString, QMap<qint64, qint64>, QMap<qint64, qint64>,
974
 
                                             QMap<qint64, KIMAP::MessageFlags>, QMap<qint64, KIMAP::MessagePtr> ) ),
975
 
             this, SLOT( onHeadersReceived( QString, QMap<qint64, qint64>, QMap<qint64, qint64>,
976
 
                                            QMap<qint64, KIMAP::MessageFlags>, QMap<qint64, KIMAP::MessagePtr> ) ) );
977
 
    connect( fetch, SIGNAL( result( KJob* ) ),
978
 
             this, SLOT( onHeadersFetchDone( KJob* ) ) );
979
 
    fetch->start();
980
 
    return;
981
 
  } else if ( messageCount != realMessageCount ) {
982
 
    // The amount on the server does not match the amount in the cache.
983
 
    // that means we need reget the catch completely.
984
 
    kDebug() << "O OH: " << messageCount << " But: " << realMessageCount;
985
 
 
986
 
    itemsClear( collection );
987
 
    setItemStreamingEnabled( true );
988
 
 
989
 
    KIMAP::FetchJob *fetch = new KIMAP::FetchJob( m_account->session() );
990
 
    KIMAP::FetchJob::FetchScope scope;
991
 
    fetch->setSequenceSet( KIMAP::ImapSet( 1, messageCount ) );
992
 
    scope.parts.clear();
993
 
    scope.mode = KIMAP::FetchJob::FetchScope::Headers;
994
 
    fetch->setScope( scope );
995
 
    connect( fetch, SIGNAL( headersReceived( QString, QMap<qint64, qint64>, QMap<qint64, qint64>,
996
 
                                             QMap<qint64, KIMAP::MessageFlags>, QMap<qint64, KIMAP::MessagePtr> ) ),
997
 
             this, SLOT( onHeadersReceived( QString, QMap<qint64, qint64>, QMap<qint64, qint64>,
998
 
                                            QMap<qint64, KIMAP::MessageFlags>, QMap<qint64, KIMAP::MessagePtr> ) ) );
999
 
    connect( fetch, SIGNAL( result( KJob* ) ),
1000
 
             this, SLOT( onHeadersFetchDone( KJob* ) ) );
1001
 
    fetch->start();
1002
 
    return;
1003
 
  } else if ( messageCount == realMessageCount && oldNextUid != nextUid
1004
 
           && oldNextUid != 0 && !firstTime ) {
1005
 
    // amount is right but uidnext is different.... something happened
1006
 
    // behind our back...
1007
 
    kDebug() << "UIDNEXT check failed, refetching mailbox";
1008
 
 
1009
 
    itemsClear( collection );
1010
 
    setItemStreamingEnabled( true );
1011
 
 
1012
 
    KIMAP::FetchJob *fetch = new KIMAP::FetchJob( m_account->session() );
1013
 
    KIMAP::FetchJob::FetchScope scope;
1014
 
    fetch->setSequenceSet( KIMAP::ImapSet( 1, messageCount ) );
1015
 
    scope.parts.clear();
1016
 
    scope.mode = KIMAP::FetchJob::FetchScope::Headers;
1017
 
    fetch->setScope( scope );
1018
 
    connect( fetch, SIGNAL( headersReceived( QString, QMap<qint64, qint64>, QMap<qint64, qint64>,
1019
 
                                             QMap<qint64, KIMAP::MessageFlags>, QMap<qint64, KIMAP::MessagePtr> ) ),
1020
 
             this, SLOT( onHeadersReceived( QString, QMap<qint64, qint64>, QMap<qint64, qint64>,
1021
 
                                            QMap<qint64, KIMAP::MessageFlags>, QMap<qint64, KIMAP::MessagePtr> ) ) );
1022
 
    connect( fetch, SIGNAL( result( KJob* ) ),
1023
 
             this, SLOT( onHeadersFetchDone( KJob* ) ) );
1024
 
    fetch->start();
1025
 
    return;
1026
 
  }
1027
 
 
1028
 
  kDebug() << "All fine, nothing to do";
1029
 
  itemsRetrievalDone();
1030
 
}
1031
 
 
1032
 
 
1033
 
/******************* Private ***********************************************/
1034
 
 
1035
 
bool ImapResource::manualAuth( const QString& username, QString &password )
1036
 
{
1037
 
  KPasswordDialog dlg( 0 );
1038
 
  dlg.setPrompt( i18n( "Could not find a valid password, please enter it here." ) );
1039
 
  if ( dlg.exec() == QDialog::Accepted ) {
1040
 
    password = dlg.password();
1041
 
    return true;
1042
 
  } else {
1043
 
    password = QString();
1044
 
    return false;
1045
 
  }
1046
 
}
1047
 
 
1048
 
QString ImapResource::rootRemoteId() const
1049
 
{
1050
 
  return "imap://"+m_account->userName()+'@'+m_account->server()+'/';
1051
 
}
1052
 
 
1053
 
QString ImapResource::remoteIdForMailBox( const QString &path ) const
1054
 
{
1055
 
  return rootRemoteId()+path;
1056
 
}
1057
 
 
1058
 
QString ImapResource::mailBoxForRemoteId( const QString &remoteId ) const
1059
 
{
1060
 
  QString path = remoteId;
1061
 
  path.replace( rootRemoteId(), "" );
1062
 
  return path;
1063
 
}
1064
 
 
1065
 
Collection ImapResource::collectionFromRemoteId( const QString &remoteId )
1066
 
{
1067
 
  CollectionFetchJob *fetch = new CollectionFetchJob( Collection::root(), CollectionFetchJob::Recursive );
1068
 
  fetch->setResource( identifier() );
1069
 
  fetch->exec();
1070
 
 
1071
 
  Collection::List collections = fetch->collections();
1072
 
  foreach ( const Collection &collection, collections ) {
1073
 
    if ( collection.remoteId()==remoteId ) {
1074
 
      return collection;
1075
 
    }
1076
 
  }
1077
 
 
1078
 
  return Collection();
1079
 
}
1080
 
 
1081
 
Item ImapResource::itemFromRemoteId( const Akonadi::Collection &collection, const QString &remoteId )
1082
 
{
1083
 
  ItemFetchJob *fetch = new ItemFetchJob( collection );
1084
 
  fetch->exec();
1085
 
 
1086
 
  Item::List items = fetch->items();
1087
 
  foreach ( const Item &item, items ) {
1088
 
    if ( item.remoteId()==remoteId ) {
1089
 
      return item;
1090
 
    }
1091
 
  }
1092
 
 
1093
 
  return Item();
1094
 
}
1095
 
 
1096
 
void ImapResource::itemsClear( const Collection &collection )
1097
 
{
1098
 
  ItemFetchJob *fetch = new ItemFetchJob( collection );
1099
 
  fetch->exec();
1100
 
 
1101
 
  TransactionSequence *transaction = new TransactionSequence;
1102
 
 
1103
 
  Item::List items = fetch->items();
1104
 
  foreach ( const Item &item, items ) {
1105
 
    new ItemDeleteJob( item, transaction );
1106
 
  }
1107
 
 
1108
 
  transaction->exec();
1109
 
}
1110
 
 
1111
 
AKONADI_RESOURCE_MAIN( ImapResource )
1112
 
 
1113
 
#include "imapresource.moc"
1114
 
 
1115