SVN_SILENT made messages (.desktop file)
[kdepim.git] / mailimporter / filter_kmail_archive.cpp
blobeb3a76916d7eeef00a58ec52231e2b62be652f13
1 /* Copyright 2009,2010 Klarälvdalens Datakonsult AB
3 This program is free software; you can redistribute it and/or
4 modify it under the terms of the GNU General Public License as
5 published by the Free Software Foundation; either version 2 of
6 the License or (at your option) version 3 or any later version
7 accepted by the membership of KDE e.V. (or its successor approved
8 by the membership of KDE e.V.), which shall act as a proxy
9 defined in Section 14 of version 3 of the license.
11 This program 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
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
19 #include "filter_kmail_archive.h"
22 #include <KLocalizedString>
23 #include <KFileDialog>
24 #include <KZip>
25 #include <KTar>
27 #include <QApplication>
29 #include <QSharedPointer>
31 #include <boost/shared_ptr.hpp>
33 using namespace MailImporter;
35 FilterKMailArchive::FilterKMailArchive()
36 : Filter( i18n( "Import KMail Archive File" ),
37 "Klar\xE4lvdalens Datakonsult AB",
38 i18n( "<p><b>KMail Archive File Import Filter</b></p>"
39 "<p>This filter will import archives files previously exported by KMail.</p>"
40 "<p>Archive files contain a complete folder subtree compressed into a single file.</p>" ) ),
41 mTotalFiles( 0 ),
42 mFilesDone( 0 )
46 FilterKMailArchive::~FilterKMailArchive()
50 // Input: .inbox.directory
51 // Output: inbox
52 // Can also return an empty string if this is no valid dir name
53 static QString folderNameForDirectoryName( const QString &dirName )
55 Q_ASSERT( dirName.startsWith( QLatin1String( "." ) ) );
56 const QString end = ".directory";
57 const int expectedIndex = dirName.length() - end.length();
58 if ( dirName.toLower().indexOf( end ) != expectedIndex )
59 return QString();
60 QString returnName = dirName.left( dirName.length() - end.length() );
61 returnName = returnName.right( returnName.length() - 1 );
62 return returnName;
65 bool FilterKMailArchive::importMessage( const KArchiveFile *file, const QString &folderPath )
67 if ( filterInfo()->shouldTerminate() )
68 return false;
70 qApp->processEvents();
72 KMime::Message::Ptr newMessage( new KMime::Message() );
73 newMessage->setContent( file->data() );
74 newMessage->parse();
76 Akonadi::Collection collection = parseFolderString( folderPath );
77 if ( !collection.isValid() ) {
78 filterInfo()->addErrorLogEntry( i18n( "Unable to retrieve folder for folder path %1.", folderPath ) );
79 return false;
82 if ( filterInfo()->removeDupMessage() ) {
83 KMime::Headers::MessageID *messageId = newMessage->messageID( false );
84 if ( messageId &&!messageId->asUnicodeString().isEmpty() ) {
85 if ( checkForDuplicates( messageId->asUnicodeString(), collection, folderPath ) ) {
86 mTotalFiles--;
87 return true;
92 const bool result = addAkonadiMessage( collection, newMessage );
93 if ( result ) {
94 mFilesDone++;
96 return result;
99 bool FilterKMailArchive::importFolder( const KArchiveDirectory *folder, const QString &folderPath )
101 kDebug() << "Importing folder" << folder->name();
102 filterInfo()->addInfoLogEntry( i18n( "Importing folder '%1'...", folderPath ) );
103 filterInfo()->setTo( filterInfo()->rootCollection().name() + folderPath );
104 const KArchiveDirectory * const messageDir =
105 dynamic_cast<const KArchiveDirectory*>( folder->entry( "cur" ) );
106 if ( messageDir ) {
108 int total = messageDir->entries().count();
109 int cur = 1;
111 foreach( const QString &entryName, messageDir->entries() ) {
112 filterInfo()->setCurrent( cur * 100 / total );
113 filterInfo()->setOverall( mFilesDone * 100 / mTotalFiles );
114 const KArchiveEntry * const entry = messageDir->entry( entryName );
116 if ( entry->isFile() ) {
117 const int oldCount = mFilesDone;
118 if ( !importMessage( static_cast<const KArchiveFile*>( entry ), folderPath ) )
119 return false;
121 // Adjust the counter. Total count can decrease because importMessage() detects a duplicate
122 if ( oldCount != mFilesDone )
123 cur++;
124 else
125 total--;
127 else {
128 filterInfo()->addErrorLogEntry( i18n( "Unexpected subfolder %1 in folder %2.", entryName, folder->name() ) );
132 else {
133 filterInfo()->addErrorLogEntry( i18n( "No subfolder named 'cur' in folder %1.", folder->name() ) );
135 return true;
138 bool FilterKMailArchive::importDirectory( const KArchiveDirectory *directory, const QString &folderPath )
140 kDebug() << "Importing directory" << directory->name();
141 foreach( const QString &entryName, directory->entries() ) {
142 const KArchiveEntry * const entry = directory->entry( entryName );
144 if ( entry->isDirectory() ) {
146 const KArchiveDirectory *dir = static_cast<const KArchiveDirectory*>( entry );
148 if ( !dir->name().startsWith( QLatin1String( "." ) ) ) {
149 if ( !importFolder( dir, folderPath + QLatin1Char('/') + dir->name() ) )
150 return false;
153 // Entry starts with a dot, so we assume it is a subdirectory
154 else {
156 const QString folderName = folderNameForDirectoryName( entry->name() );
157 if ( folderName.isEmpty() ) {
158 filterInfo()->addErrorLogEntry( i18n( "Unexpected subdirectory named '%1'.", entry->name() ) );
160 else {
162 if ( !importDirectory( dir, folderPath + QLatin1Char('/') + folderName ) )
163 return false;
169 return true;
172 int FilterKMailArchive::countFiles( const KArchiveDirectory *directory ) const
174 int count = 0;
175 foreach( const QString &entryName, directory->entries() ) {
176 const KArchiveEntry * const entry = directory->entry( entryName );
177 if ( entry->isFile() )
178 count++;
179 else
180 count += countFiles( static_cast<const KArchiveDirectory*>( entry ) );
182 return count;
185 void FilterKMailArchive::import()
187 Q_ASSERT( filterInfo()->rootCollection().isValid() );
189 KFileDialog fileDialog( KUrl(), QString(), filterInfo()->parent() );
190 fileDialog.setMode( KFile::File | KFile::LocalOnly );
191 fileDialog.setCaption( i18n( "Select KMail Archive File to Import" ) );
192 fileDialog.setFilter( "*.tar.bz2 *.tar.gz *.tar *.zip|" +
193 i18n( "KMail Archive Files (*.tar, *.tar.gz, *.tar.bz2, *.zip)" ) );
194 if ( !fileDialog.exec() ) {
195 filterInfo()->alert( i18n( "Please select an archive file that should be imported." ) );
196 return;
198 const QString archiveFile = fileDialog.selectedFile();
199 importMails( archiveFile );
202 void FilterKMailArchive::importMails( const QString &archiveFile )
204 filterInfo()->setFrom( archiveFile );
206 KMimeType::Ptr mimeType = KMimeType::findByUrl( archiveFile, 0, true /* local file */ );
207 typedef QSharedPointer<KArchive> KArchivePtr;
208 KArchivePtr archive;
209 if ( !mimeType->patterns().filter( "tar", Qt::CaseInsensitive ).isEmpty() )
210 archive = KArchivePtr( new KTar( archiveFile ) );
211 else if ( !mimeType->patterns().filter( "zip", Qt::CaseInsensitive ).isEmpty() )
212 archive = KArchivePtr( new KZip( archiveFile ) );
213 else {
214 filterInfo()->alert( i18n( "The file '%1' does not appear to be a valid archive.", archiveFile ) );
215 return;
218 if ( !archive->open( QIODevice::ReadOnly ) ) {
219 filterInfo()->alert( i18n( "Unable to open archive file '%1'", archiveFile ) );
220 return;
223 filterInfo()->setOverall( 0 );
224 filterInfo()->addInfoLogEntry( i18n( "Counting files in archive..." ) );
225 mTotalFiles = countFiles( archive->directory() );
227 if ( importDirectory( archive->directory(), QString() ) ) {
228 filterInfo()->setOverall( 100 );
229 filterInfo()->setCurrent( 100 );
230 filterInfo()->addInfoLogEntry( i18n( "Importing the archive file '%1' into the folder '%2' succeeded.",
231 archiveFile, filterInfo()->rootCollection().name() ) );
232 filterInfo()->addInfoLogEntry( i18np( "1 message was imported.", "%1 messages were imported.",
233 mFilesDone ) );
235 else {
236 filterInfo()->addInfoLogEntry( i18n( "Importing the archive failed." ) );
238 archive->close();