21#include "removeduplicatesjob.h"
23#include <QAbstractItemModel>
25#include <akonadi/itemfetchjob.h>
26#include <akonadi/itemdeletejob.h>
27#include <akonadi/itemfetchscope.h>
28#include <kmime/kmime_message.h>
30#include <KLocalizedString>
32class Akonadi::RemoveDuplicatesJob::Private {
45 Akonadi::Collection collection = mFolders.value(mJobCount - 1);
46 kDebug() <<
"Processing collection" << collection.name() <<
"(" << collection.id() <<
")";
48 Akonadi::ItemFetchJob *job =
new Akonadi::ItemFetchJob(collection, mParent);
49 job->fetchScope().setAncestorRetrieval(Akonadi::ItemFetchScope::Parent);
50 job->fetchScope().fetchFullPayload();
51 mParent->connect(job, SIGNAL(result(KJob*)), mParent, SLOT(slotFetchDone(KJob*)));
54 emit mParent->description(mParent, i18n(
"Retrieving items..."));
57 void slotFetchDone(KJob *job)
61 mParent->setError(job->error());
62 mParent->setErrorText(job->errorText());
63 mParent->emitResult();
68 mParent->emitResult();
72 emit mParent->description(mParent, i18n(
"Searching for duplicates..."));
74 Akonadi::ItemFetchJob *fjob =
static_cast<Akonadi::ItemFetchJob *
>(job);
75 Akonadi::Item::List items = fjob->items();
79 QMap<QByteArray, uint> messageIds;
80 QMap<uint, QList<uint> > duplicates;
81 QMap<uint, uint> bodyHashes;
82 const int numberOfItems(items.size());
83 for (
int i = 0; i < numberOfItems; ++i) {
84 Akonadi::Item item = items.at(i);
85 if (item.hasPayload<KMime::Message::Ptr>()) {
86 KMime::Message::Ptr message = item.payload<KMime::Message::Ptr>();
87 QByteArray idStr = message->messageID()->as7BitString(
false);
93 if (messageIds.contains(idStr)) {
94 uint mainId = messageIds.value(idStr);
95 if (!bodyHashes.contains(mainId)) {
96 bodyHashes.insert(mainId, qHash(items.value(mainId).payload<KMime::Message::Ptr>()->encodedContent()));
98 uint hash = qHash(message->encodedContent());
99 kDebug() << idStr << bodyHashes.value(mainId) << hash;
100 if (bodyHashes.value(mainId) == hash) {
101 duplicates[mainId].append(i);
104 messageIds.insert(idStr, i);
110 QMap<uint, QList<uint> >::ConstIterator end(duplicates.constEnd());
111 for (QMap<uint, QList<uint> >::ConstIterator it = duplicates.constBegin(); it != end; ++it) {
112 QList<uint>::ConstIterator dupEnd(it.value().constEnd());
113 for (QList<uint>::ConstIterator dupIt = it.value().constBegin(); dupIt != dupEnd; ++dupIt) {
114 mDuplicateItems.append(items.value(*dupIt));
119 mParent->emitResult();
126 if (mDuplicateItems.isEmpty()) {
127 kDebug() <<
"No duplicates, I'm done here";
128 mParent->emitResult();
131 emit mParent->description(mParent, i18n(
"Removing duplicates..."));
132 Akonadi::ItemDeleteJob *delCmd =
new Akonadi::ItemDeleteJob(mDuplicateItems, mParent);
133 mParent->connect(delCmd, SIGNAL(result(KJob*)), mParent, SLOT(slotDeleteDone(KJob*)));
138 void slotDeleteDone(KJob *job)
140 kDebug() <<
"Job done";
142 mParent->setError(job->error());
143 mParent->setErrorText(job->errorText());
144 mParent->emitResult();
147 Akonadi::Collection::List mFolders;
149 Akonadi::Item::List mDuplicateItems;
151 Akonadi::Job *mCurrentJob;
158using namespace Akonadi;
162 , d(new Private(this))
165 d->mFolders << folder;
170 , d(new Private(this))
172 d->mFolders = folders;
173 d->mJobCount = d->mFolders.length();
181void RemoveDuplicatesJob::doStart()
185 if (d->mFolders.isEmpty()) {
186 kWarning() <<
"No collections to process";
194bool RemoveDuplicatesJob::doKill()
196 kDebug() <<
"Killed!";
199 if (d->mCurrentJob) {
200 d->mCurrentJob->kill(EmitResult);
206#include "moc_removeduplicatesjob.cpp"
Job that finds and removes duplicate messages in given collection.
RemoveDuplicatesJob(const Akonadi::Collection &folder, QObject *parent=0)
Creates a new job that will remove duplicates in folder.
virtual ~RemoveDuplicatesJob()
Destroys the job.