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

akonadi/kmime

  • akonadi
  • kmime
removeduplicatesjob.cpp
1 /*
2  Copyright (c) 2010 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com
3  Copyright (c) 2010 Andras Mantia <andras@kdab.com>
4  Copyright (c) 2012 Dan Vrátil <dvratil@redhat.com>
5 
6  This library is free software; you can redistribute it and/or
7  modify it under the terms of the GNU Lesser General Public
8  License as published by the Free Software Foundation; either
9  version 2.1 of the License, or (at your option) any later version.
10 
11  This library is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  Lesser General Public License for more details.
15 
16  You should have received a copy of the GNU Lesser General Public
17  License along with this library; if not, write to the Free Software
18  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20 
21 #include "removeduplicatesjob.h"
22 
23 #include <QAbstractItemModel>
24 
25 #include <akonadi/itemfetchjob.h>
26 #include <akonadi/itemdeletejob.h>
27 #include <akonadi/itemfetchscope.h>
28 #include <kmime/kmime_message.h>
29 
30 #include <KLocalizedString>
31 
32 
33 class Akonadi::RemoveDuplicatesJob::Private {
34 
35  public:
36  Private( RemoveDuplicatesJob *parent )
37  : mJobCount( 0 )
38  , mKilled( false )
39  , mCurrentJob( 0 )
40  , mParent( parent )
41  {
42 
43  }
44 
45  void fetchItem()
46  {
47  Akonadi::Collection collection = mFolders.value( mJobCount - 1);
48  kDebug() << "Processing collection" << collection.name() << "(" << collection.id() << ")";
49 
50  Akonadi::ItemFetchJob *job = new Akonadi::ItemFetchJob( collection, mParent );
51  job->fetchScope().setAncestorRetrieval( Akonadi::ItemFetchScope::Parent );
52  job->fetchScope().fetchFullPayload();
53  mParent->connect( job, SIGNAL(result(KJob*)), mParent, SLOT(slotFetchDone(KJob*)) );
54  mCurrentJob = job;
55 
56  emit mParent->description( mParent, i18n( "Retrieving items..." ) );
57  }
58 
59  void slotFetchDone( KJob *job )
60  {
61  mJobCount--;
62  if ( job->error() ) {
63  mParent->setError( job->error() );
64  mParent->setErrorText( job->errorText() );
65  mParent->emitResult();
66  return;
67  }
68 
69  if ( mKilled ) {
70  mParent->emitResult();
71  return;
72  }
73 
74  emit mParent->description( mParent, i18n( "Searching for duplicates..." ) );
75 
76  Akonadi::ItemFetchJob *fjob = dynamic_cast<Akonadi::ItemFetchJob*>( job );
77  Q_ASSERT( fjob );
78  Akonadi::Item::List items = fjob->items();
79 
80  //find duplicate mails with the same messageid
81  //if duplicates are found, check the content as well to be sure they are the same
82  QMap<QByteArray, uint> messageIds;
83  QMap<uint, QList<uint> > duplicates;
84  QMap<uint, uint> bodyHashes;
85  const int numberOfItems( items.size() );
86  for ( int i = 0; i < numberOfItems; ++i ) {
87  Akonadi::Item item = items.at( i );
88  if ( item.hasPayload<KMime::Message::Ptr>() ) {
89  KMime::Message::Ptr message = item.payload<KMime::Message::Ptr>();
90  QByteArray idStr = message->messageID()->as7BitString( false );
91  //TODO: Maybe do some more check in case of idStr.isEmpty()
92  //like when the first message's body is different from the 2nd,
93  //but the 2nd is the same as the 3rd, etc.
94  //if ( !idStr.isEmpty() )
95  {
96  if ( messageIds.contains( idStr ) ) {
97  uint mainId = messageIds.value( idStr );
98  if ( !bodyHashes.contains( mainId ) ) {
99  bodyHashes.insert( mainId, qHash( items.value( mainId ).payload<KMime::Message::Ptr>()->encodedContent() ) );
100  }
101  uint hash = qHash( message->encodedContent() );
102  kDebug() << idStr << bodyHashes.value( mainId ) << hash;
103  if ( bodyHashes.value( mainId ) == hash ) {
104  duplicates[ mainId ].append( i );
105  }
106  } else {
107  messageIds.insert( idStr, i );
108  }
109  }
110  }
111  }
112 
113  QMap<uint, QList<uint> >::ConstIterator end( duplicates.constEnd() );
114  for( QMap<uint, QList<uint> >::ConstIterator it = duplicates.constBegin(); it != end; ++it ) {
115  QList<uint>::ConstIterator dupEnd( it.value().constEnd() );
116  for ( QList<uint>::ConstIterator dupIt = it.value().constBegin(); dupIt != dupEnd; ++dupIt ) {
117  mDuplicateItems.append( items.value( *dupIt ) );
118  }
119  }
120 
121  if ( mKilled ) {
122  mParent->emitResult();
123  return;
124  }
125 
126  if ( mJobCount > 0 ) {
127  fetchItem();
128  } else {
129  if ( mDuplicateItems.isEmpty() ) {
130  kDebug() << "No duplicates, I'm done here";
131  mParent->emitResult();
132  return;
133  } else {
134  emit mParent->description( mParent, i18n( "Removing duplicates..." ) );
135  Akonadi::ItemDeleteJob *delCmd = new Akonadi::ItemDeleteJob( mDuplicateItems, mParent );
136  mParent->connect( delCmd, SIGNAL(result(KJob*)), mParent, SLOT(slotDeleteDone(KJob*)) );
137  }
138  }
139  }
140 
141  void slotDeleteDone( KJob *job )
142  {
143  kDebug() << "Job done";
144 
145  mParent->setError( job->error() );
146  mParent->setErrorText( job->errorText() );
147  mParent->emitResult();
148  }
149 
150  Akonadi::Collection::List mFolders;
151  int mJobCount;
152  Akonadi::Item::List mDuplicateItems;
153  bool mKilled;
154  Akonadi::Job *mCurrentJob;
155 
156  private:
157  RemoveDuplicatesJob *mParent;
158 
159 };
160 
161 using namespace Akonadi;
162 
163 RemoveDuplicatesJob::RemoveDuplicatesJob( const Akonadi::Collection &folder, QObject* parent )
164  : Job( parent )
165  , d( new Private( this ) )
166 {
167  d->mFolders << folder;
168 }
169 
170 RemoveDuplicatesJob::RemoveDuplicatesJob( const Akonadi::Collection::List &folders, QObject* parent)
171  : Job(parent)
172  , d( new Private( this ) )
173 {
174  d->mFolders = folders;
175  d->mJobCount = d->mFolders.length();
176 }
177 
178 RemoveDuplicatesJob::~RemoveDuplicatesJob()
179 {
180  delete d;
181 }
182 
183 void RemoveDuplicatesJob::doStart()
184 {
185  kDebug();
186 
187  if ( d->mFolders.isEmpty() ) {
188  kWarning() << "No collections to process";
189  emitResult();
190  return;
191  }
192 
193  d->fetchItem();
194 }
195 
196 bool RemoveDuplicatesJob::doKill()
197 {
198  kDebug() << "Killed!";
199 
200  d->mKilled = true;
201  if ( d->mCurrentJob ) {
202  d->mCurrentJob->kill( EmitResult );
203  }
204 
205  return true;
206 }
207 
208 #include "removeduplicatesjob.moc"
This file is part of the KDE documentation.
Documentation copyright © 1996-2013 The KDE developers.
Generated on Sat Jul 13 2013 01:28:59 by doxygen 1.8.3.1 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

akonadi/kmime

Skip menu "akonadi/kmime"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Members
  • File List
  • 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