Fix clipping/eliding of multi-line task descriptions.
[kdepim.git] / kmailcvt / filters.cxx
blobc62581b211a8ff8bf5b97e0eafa225f63184907d
1 /***************************************************************************
2 filters.cxx - description
3 -------------------
4 begin : Fri Jun 30 2000
5 copyright : (C) 2000 by Hans Dijkema
6 email : kmailcvt@hum.org
7 ***************************************************************************/
9 /***************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 ***************************************************************************/
17 // Local Includes
18 #include "filters.hxx"
19 #include "kmailcvt.h"
21 // KDEPIM Includes
22 #include <KPIMUtils/KFileIO>
24 // Akonadi Includes
25 #include <Akonadi/CollectionFetchJob>
26 #include <Akonadi/Item>
27 #include <Akonadi/ItemCreateJob>
28 #include <Akonadi/ItemFetchJob>
29 #include <Akonadi/ItemFetchScope>
30 #include <Akonadi/CollectionCreateJob>
31 #include <akonadi/kmime/messageparts.h>
32 #include <akonadi/kmime/messagestatus.h>
34 // KDE Includes
35 #include <KUrl>
36 #include <KLocale>
37 #include <KDebug>
38 #include <KMessageBox>
40 // Qt Includes
42 //////////////////////////////////////////////////////////////////////////////////
44 // The API to the kmailcvt dialog --> Gives the import filter access to
45 // put information on the dialog.
47 //////////////////////////////////////////////////////////////////////////////////
49 bool FilterInfo::s_terminateASAP = false;
51 FilterInfo::FilterInfo( KImportPageDlg* dlg, QWidget* parent , bool _removeDupMsg)
52 : m_dlg( dlg ),
53 m_parent( parent )
55 removeDupMsg = _removeDupMsg;
56 s_terminateASAP = false;
59 FilterInfo::~FilterInfo()
63 void FilterInfo::setStatusMsg( const QString& status )
65 m_dlg->_textStatus->setText( status );
68 void FilterInfo::setFrom( const QString& from )
70 m_dlg->_from->setText( from );
73 void FilterInfo::setTo( const QString& to )
75 m_dlg->_to->setText( to );
78 void FilterInfo::setCurrent( const QString& current )
80 m_dlg->_current->setText( current );
81 kapp->processEvents();
84 void FilterInfo::setCurrent( int percent )
86 m_dlg->_done_current->setValue( percent );
87 kapp->processEvents(); // Be careful - back & finish buttons disabled, so only user event that can happen is cancel/close button
90 void FilterInfo::setOverall( int percent )
92 m_dlg->_done_overall->setValue( percent );
95 void FilterInfo::addLog( const QString& log )
97 m_dlg->_log->addItem( log );
98 m_dlg->_log->setCurrentItem( m_dlg->_log->item(m_dlg->_log->count() - 1 ));
99 kapp->processEvents();
102 void FilterInfo::clear()
104 m_dlg->_log->clear();
105 setCurrent();
106 setOverall();
107 setCurrent( QString() );
108 setFrom( QString() );
109 setTo( QString() );
112 void FilterInfo::alert( const QString& message )
114 KMessageBox::information( m_parent, message );
117 void FilterInfo::terminateASAP()
119 s_terminateASAP = true;
122 bool FilterInfo::shouldTerminate()
124 return s_terminateASAP;
127 Akonadi::Collection FilterInfo::rootCollection() const
129 return m_rootCollection;
132 void FilterInfo::setRootCollection( const Akonadi::Collection &collection )
134 m_rootCollection = collection;
138 //////////////////////////////////////////////////////////////////////////////////
140 // The generic filter class
142 //////////////////////////////////////////////////////////////////////////////////
145 Filter::Filter( const QString& name, const QString& author,
146 const QString& info )
147 : m_name( name ),
148 m_author( author ),
149 m_info( info )
151 //public
152 count_duplicates = 0;
155 bool Filter::addAkonadiMessage( FilterInfo* info, const Akonadi::Collection &collection,
156 const KMime::Message::Ptr& message )
158 Akonadi::Item item;
159 Akonadi::MessageStatus status;
161 item.setMimeType( "message/rfc822" );
163 KMime::Headers::Base *statusHeaders = message->headerByType( "X-Status" );
164 if( statusHeaders ) {
165 if( !statusHeaders->isEmpty() ) {
166 status.setStatusFromStr( statusHeaders->asUnicodeString() );
167 item.setFlags( status.statusFlags() );
170 item.setPayload<KMime::Message::Ptr>( message );
171 Akonadi::ItemCreateJob* job = new Akonadi::ItemCreateJob( item, collection );
172 if( !job->exec() ) {
173 info->alert( i18n( "<b>Error:</b> Could not add message to folder %1. Reason: %2",
174 collection.name(), job->errorString() ) );
175 return false;
177 return true;
180 Akonadi::Collection Filter::parseFolderString(FilterInfo* info, const QString& folderParseString)
182 // Return an already created collection:
183 for( QMap<QString, Akonadi::Collection>::const_iterator it =
184 m_messageFolderCollectionMap.constBegin(); it != m_messageFolderCollectionMap.constEnd(); it ++ ) {
185 if( it.key() == folderParseString )
186 return it.value();
189 // The folder hasn't yet been created, create it now.
190 const QStringList folderList = folderParseString.split( '/', QString::SkipEmptyParts );
191 bool isFirst = true;
192 QString folderBuilder;
193 Akonadi::Collection lastCollection;
195 // Create each folder on the folder list and add it the map.
196 foreach( const QString &folder, folderList ) {
197 if( isFirst ) {
198 m_messageFolderCollectionMap[folder] = addSubCollection( info, info->rootCollection(), folder );
199 folderBuilder = folder;
200 lastCollection = m_messageFolderCollectionMap[folder];
201 isFirst = false;
202 } else {
203 folderBuilder += '/' + folder;
204 m_messageFolderCollectionMap[folderBuilder] = addSubCollection( info, lastCollection, folder );
205 lastCollection = m_messageFolderCollectionMap[folderBuilder];
209 return lastCollection;
212 Akonadi::Collection Filter::addSubCollection( FilterInfo* info,
213 const Akonadi::Collection &baseCollection,
214 const QString& newCollectionPathName )
216 // Ensure that the collection doesn't already exsit, if it does just return it.
217 Akonadi::CollectionFetchJob *fetchJob = new Akonadi::CollectionFetchJob( baseCollection,
218 Akonadi::CollectionFetchJob::FirstLevel);
219 if( !fetchJob->exec() ) {
220 info->alert( i18n( "<b>Warning:</b> Could not check that the folder already exists. Reason: %1",
221 fetchJob->errorString() ) );
222 return Akonadi::Collection();
225 foreach( const Akonadi::Collection &subCollection, fetchJob->collections() ) {
226 if( subCollection.name() == newCollectionPathName ) {
227 return subCollection;
231 // The subCollection doesn't exsit, create a new one
232 Akonadi::Collection newSubCollection;
233 newSubCollection.setParentCollection( baseCollection );
234 newSubCollection.setName( newCollectionPathName );
236 Akonadi::CollectionCreateJob * job = new Akonadi::CollectionCreateJob( newSubCollection );
237 if( !job->exec() ) {
238 info->alert( i18n("<b>Error:</b> Could not create folder. Reason: %1",
239 job->errorString() ) );
240 return Akonadi::Collection();
242 // Return the newly created collection
243 return job->collection();
246 bool Filter::checkForDuplicates ( FilterInfo* info, const QString& msgID,
247 const Akonadi::Collection& msgCollection,
248 const QString& messageFolder )
250 bool folderFound = false;
252 // Check if the contents of this collection have already been found.
253 for( QMultiMap<QString, QString>::const_iterator it = m_messageFolderMessageIDMap.constBegin();
254 it != m_messageFolderMessageIDMap.constEnd(); it++ ) {
255 if( it.key() == messageFolder ) {
256 folderFound = true;
257 break;
261 if( !folderFound ) {
262 // Populate the map with message IDs that are in that collection.
263 if( msgCollection.isValid() ) {
264 Akonadi::ItemFetchJob job( msgCollection );
265 job.fetchScope().fetchPayloadPart( Akonadi::MessagePart::Header );
266 if( !job.exec() ) {
267 info->addLog( i18n( "<b>Warning:</b> Could not fetch mail in folder %1. Reason: %2"
268 " You may have duplicate messages.", messageFolder, job.errorString() ) );
269 } else {
270 foreach( const Akonadi::Item& messageItem, job.items() ) {
271 if( !messageItem.isValid() ) {
272 info->addLog( i18n( "<b>Warning:</b> Got an invalid message in folder %1.", messageFolder ) );
273 } else {
274 if( !messageItem.hasPayload<KMime::Message::Ptr>() )
275 continue;
276 const KMime::Message::Ptr message = messageItem.payload<KMime::Message::Ptr>();
277 const KMime::Headers::Base* messageID = message->messageID( false );
278 if( messageID ) {
279 if( !messageID->isEmpty() ) {
280 m_messageFolderMessageIDMap.insert( messageFolder, messageID->asUnicodeString() );
289 // Check if this message has a duplicate
290 for( QMultiMap<QString, QString>::const_iterator it = m_messageFolderMessageIDMap.constBegin();
291 it != m_messageFolderMessageIDMap.constEnd(); it++ ) {
292 if( it.key() == messageFolder &&
293 it.value() == msgID )
294 return true;
297 // The message isn't a duplicate, but add it to the map for checking in the future.
298 m_messageFolderMessageIDMap.insert( messageFolder, msgID );
299 return false;
303 bool Filter::addMessage( FilterInfo* info, const QString& folderName,
304 const QString& msgPath,
305 const QString& msgStatusFlags // Defunct - KMime will now handle the MessageStatus flags.
308 Q_UNUSED( msgStatusFlags );
310 // Add the message.
311 return doAddMessage( info, folderName, msgPath, true );
314 bool Filter::addMessage_fastImport( FilterInfo* info, const QString& folderName,
315 const QString& msgPath,
316 const QString& msgStatusFlags // Defunct - KMime will now handle the MessageStatus flags.
319 Q_UNUSED( msgStatusFlags );
321 // Add the message.
322 return doAddMessage( info, folderName, msgPath );
325 bool Filter::doAddMessage( FilterInfo* info, const QString& folderName,
326 const QString& msgPath,
327 bool duplicateCheck )
329 QString messageID;
330 // Create the mail folder (if not already created).
331 Akonadi::Collection mailFolder = parseFolderString( info, folderName );
333 KUrl msgUrl( msgPath );
334 if( !msgUrl.isEmpty() && msgUrl.isLocalFile() ) {
336 // Read in the temporary file.
337 const QByteArray msgText =
338 KPIMUtils::kFileToByteArray( msgUrl.toLocalFile(), true, false );
339 if( msgText.isEmpty() ) {
340 info->addLog( i18n( "Error: failed to read temporary file at %1", msgPath ) );
341 return false;
344 // Construct a message.
345 KMime::Message::Ptr newMessage( new KMime::Message() );
346 newMessage->setContent( msgText );
347 newMessage->parse();
349 if( duplicateCheck ) {
350 // Get the messageID.
351 const KMime::Headers::Base* messageIDHeader = newMessage->messageID( false );
352 if( messageIDHeader )
353 messageID = messageIDHeader->asUnicodeString();
355 if( !messageID.isEmpty() ) {
356 // Check for duplicate.
357 if( checkForDuplicates( info, messageID, mailFolder, folderName ) ) {
358 count_duplicates++;
359 return false;
364 // Add it to the collection.
365 if( mailFolder.isValid() ) {
366 addAkonadiMessage( info, mailFolder, newMessage );
367 } else {
368 info->alert( i18n( "<b>Warning:</b> Got a bad message folder, adding to root folder." ) );
369 addAkonadiMessage( info, info->rootCollection(), newMessage );
372 return true;
376 bool Filter::needsSecondPage()
378 return true;
381 // vim: ts=2 sw=2 et