29 #include "searchjob.h"
30 #include "kmfolderimap.h"
31 #include "imapaccountbase.h"
32 #include "kmsearchpattern.h"
35 #include "kmmsgdict.h"
37 #include <progressmanager.h>
38 using KPIM::ProgressItem;
39 using KPIM::ProgressManager;
43 #include <tdeio/scheduler.h>
44 #include <tdeio/job.h>
45 #include <tdeio/global.h>
46 #include <tdelocale.h>
47 #include <tdemessagebox.h>
49 #include <tqstylesheet.h>
55 : FolderJob( 0, tOther, (folder ? folder->folder() : 0) ),
56 mFolder( folder ), mAccount( account ), mSearchPattern( pattern ),
57 mSerNum( serNum ), mRemainingMsgs( 0 ), mProgress( 0 ),
58 mUngetCurrentMsg( false )
62 SearchJob::~SearchJob()
66 void SearchJob::execute()
70 searchCompleteFolder();
72 searchSingleMessage();
77 void SearchJob::searchCompleteFolder()
80 TQString searchString = searchStringFromPattern( mSearchPattern );
82 if ( searchString.isEmpty() )
83 return slotSearchData( 0, TQString() );
86 KURL url = mAccount->getUrl();
87 url.setPath( mFolder->imapPath() +
";SECTION=" + searchString );
88 TQByteArray packedArgs;
89 TQDataStream stream( packedArgs, IO_WriteOnly );
90 stream << (int)
'E' << url;
91 TDEIO::SimpleJob *job = TDEIO::special( url, packedArgs,
false );
92 if ( mFolder->imapPath() != TQString(
"/" ) )
94 TDEIO::Scheduler::assignJobToSlave( mAccount->slave(), job );
95 connect( job, TQ_SIGNAL( infoMessage( TDEIO::Job*,
const TQString& ) ),
96 TQ_SLOT( slotSearchData( TDEIO::Job*,
const TQString& ) ) );
97 connect( job, TQ_SIGNAL( result( TDEIO::Job * ) ),
98 TQ_SLOT( slotSearchResult( TDEIO::Job * ) ) );
102 slotSearchData( job, TQString() );
103 slotSearchResult( job );
108 TQString SearchJob::searchStringFromPattern(
const KMSearchPattern* pattern )
113 mLocalSearchPattern->
setOp( pattern->
op() );
115 for ( TQPtrListIterator<KMSearchRule> it( *pattern ) ; it.current() ; ++it )
120 TQString field = (*it)->field();
122 if ( (*it)->function() == KMSearchRule::FuncContainsNot ) {
124 }
else if ( (*it)->function() == KMSearchRule::FuncIsGreater &&
125 (*it)->field() ==
"<size>" ) {
127 }
else if ( (*it)->function() == KMSearchRule::FuncIsLess &&
128 (*it)->field() ==
"<size>" ) {
130 }
else if ( (*it)->function() != KMSearchRule::FuncContains ) {
136 if ( (*it)->field() ==
"<message>" ) {
137 result +=
"TEXT \"" + (*it)->contents() +
"\"";
138 }
else if ( (*it)->field() ==
"<body>" ) {
139 result +=
"BODY \"" + (*it)->contents() +
"\"";
140 }
else if ( (*it)->field() ==
"<recipients>" ) {
141 result +=
" (OR HEADER To \"" + (*it)->contents() +
"\" HEADER Cc \"" +
142 (*it)->contents() +
"\" HEADER Bcc \"" + (*it)->contents() +
"\")";
143 }
else if ( (*it)->field() ==
"<size>" ) {
144 result += (*it)->contents();
145 }
else if ( (*it)->field() ==
"<age in days>" ||
146 (*it)->field() ==
"<status>" ||
147 (*it)->field() ==
"<any header>" ) {
150 result +=
"HEADER "+ field +
" \"" + (*it)->contents() +
"\"";
153 if ( result.isEmpty() ) {
160 mLocalSearchPattern->append( *it );
165 if ( !parts.isEmpty() ) {
166 if ( pattern->
op() == KMSearchPattern::OpOr && parts.size() > 1 ) {
167 search =
"(OR " + parts.join(
" ") +
")";
170 search = parts.join(
" ");
174 kdDebug(5006) << k_funcinfo << search <<
";localSearch=" << mLocalSearchPattern->
asString() << endl;
179 void SearchJob::slotSearchData( TDEIO::Job* job,
const TQString& data )
181 if ( job && job->error() ) {
186 if ( mLocalSearchPattern->isEmpty() && data.isEmpty() )
189 TQValueList<TQ_UINT32> serNums;
190 emit searchDone( serNums, mSearchPattern,
true );
194 mImapSearchHits = TQStringList::split(
" ", data );
196 if ( canMapAllUIDs() )
202 connect ( mFolder, TQ_SIGNAL( folderComplete( KMFolderImap*,
bool ) ),
203 this, TQ_SLOT( slotSearchFolder()) );
204 mFolder->getFolder();
210 bool SearchJob::canMapAllUIDs()
212 for ( TQStringList::Iterator it = mImapSearchHits.begin();
213 it != mImapSearchHits.end(); ++it )
215 if ( mFolder->serNumForUID( (*it).toULong() ) == 0 )
222 void SearchJob::slotSearchFolder()
224 disconnect ( mFolder, TQ_SIGNAL( folderComplete( KMFolderImap*,
bool ) ),
225 this, TQ_SLOT( slotSearchFolder()) );
227 if ( mLocalSearchPattern->isEmpty() ) {
229 TQValueList<TQ_UINT32> serNums;
230 for ( TQStringList::Iterator it = mImapSearchHits.begin();
231 it != mImapSearchHits.end(); ++it )
233 ulong serNum = mFolder->serNumForUID( (*it).toULong() );
238 serNums.append( serNum );
240 emit searchDone( serNums, mSearchPattern,
true );
243 mRemainingMsgs = mFolder->count();
244 if ( mRemainingMsgs == 0 ) {
245 emit searchDone( mSearchSerNums, mSearchPattern,
true );
250 bool needToDownload = needsDownload();
251 if ( needToDownload ) {
253 TQString question = i18n(
"To execute your search all messages of the folder %1 "
254 "have to be downloaded from the server. This may take some time. "
255 "Do you want to continue your search?").arg( mFolder->label() );
256 if ( KMessageBox::warningContinueCancel( 0, question,
257 i18n(
"Continue Search"), i18n(
"&Search"),
258 "continuedownloadingforsearch" ) != KMessageBox::Continue )
260 TQValueList<TQ_UINT32> serNums;
261 emit searchDone( serNums, mSearchPattern,
true );
265 unsigned int numMsgs = mRemainingMsgs;
267 mProgress = ProgressManager::createProgressItem(
268 "ImapSearchDownload" + ProgressManager::getUniqueID(),
269 i18n(
"Downloading emails from IMAP server"),
270 i18n(
"URL: %1" ).arg( TQStyleSheet::escape( mFolder->folder()->prettyURL() ) ),
272 mAccount->useSSL() || mAccount->useTLS() );
273 mProgress->setTotalItems( numMsgs );
274 connect ( mProgress, TQ_SIGNAL( progressItemCanceled( KPIM::ProgressItem*)),
275 this, TQ_SLOT( slotAbortSearch( KPIM::ProgressItem* ) ) );
277 for (
unsigned int i = 0; i < numMsgs ; ++i ) {
279 if ( needToDownload ) {
280 ImapJob *job =
new ImapJob( msg );
281 job->setParentFolder( mFolder );
282 job->setParentProgressItem( mProgress );
283 connect( job, TQ_SIGNAL(messageRetrieved(
KMMessage*)),
284 this, TQ_SLOT(slotSearchMessageArrived(
KMMessage*)) );
287 slotSearchMessageArrived( msg );
294 void SearchJob::slotSearchMessageArrived(
KMMessage* msg )
298 mProgress->incCompletedItems();
299 mProgress->updateProgress();
302 bool matches =
false;
304 if ( mLocalSearchPattern->
op() == KMSearchPattern::OpAnd ) {
306 if ( mLocalSearchPattern->
matches( msg ) &&
307 ( mImapSearchHits.isEmpty() ||
308 mImapSearchHits.find( TQString::number(msg->
UID() ) ) != mImapSearchHits.end() ) ) {
309 TQ_UINT32 serNum = msg->getMsgSerNum();
310 mSearchSerNums.append( serNum );
313 }
else if ( mLocalSearchPattern->
op() == KMSearchPattern::OpOr ) {
315 if ( mLocalSearchPattern->
matches( msg ) ||
316 mImapSearchHits.find( TQString::number(msg->
UID()) ) != mImapSearchHits.end() ) {
317 TQ_UINT32 serNum = msg->getMsgSerNum();
318 mSearchSerNums.append( serNum );
325 if ( idx != -1 && mUngetCurrentMsg )
326 mFolder->unGetMsg( idx );
330 emit searchDone( mSerNum, mSearchPattern, matches );
332 bool complete = ( mRemainingMsgs == 0 );
333 if ( complete && mProgress )
335 mProgress->setComplete();
338 if ( matches || complete )
340 emit searchDone( mSearchSerNums, mSearchPattern, complete );
341 mSearchSerNums.clear();
347 void SearchJob::slotSearchResult( TDEIO::Job *job )
351 mAccount->handleJobError( job, i18n(
"Error while searching.") );
355 TQValueList<TQ_UINT32> serNums;
356 emit searchDone( serNums, mSearchPattern,
true );
359 emit searchDone( mSerNum, mSearchPattern,
false );
365 void SearchJob::searchSingleMessage()
367 TQString searchString = searchStringFromPattern( mSearchPattern );
368 if ( searchString.isEmpty() )
371 slotSearchDataSingleMessage( 0, TQString() );
378 assert(aFolder && (idx != -1));
379 KMMsgBase *mb = mFolder->getMsgBase( idx );
382 searchString +=
" UID " + TQString::number( mb->UID() );
383 KURL url = mAccount->getUrl();
384 url.setPath( mFolder->imapPath() +
";SECTION=" + searchString );
385 TQByteArray packedArgs;
386 TQDataStream stream( packedArgs, IO_WriteOnly );
387 stream << (int)
'E' << url;
388 TDEIO::SimpleJob *job = TDEIO::special( url, packedArgs,
false );
389 TDEIO::Scheduler::assignJobToSlave(mAccount->slave(), job);
390 connect( job, TQ_SIGNAL(infoMessage(TDEIO::Job*,
const TQString&)),
391 TQ_SLOT(slotSearchDataSingleMessage(TDEIO::Job*,
const TQString&)) );
392 connect( job, TQ_SIGNAL(result(TDEIO::Job *)),
393 TQ_SLOT(slotSearchResult(TDEIO::Job *)) );
398 void SearchJob::slotSearchDataSingleMessage( TDEIO::Job* job,
const TQString& data )
400 if ( job && job->error() ) {
405 if ( mLocalSearchPattern->isEmpty() ) {
407 emit searchDone( mSerNum, mSearchPattern, !data.isEmpty() );
411 mImapSearchHits = TQStringList::split(
" ", data );
417 assert(aFolder && (idx != -1));
418 mUngetCurrentMsg = !mFolder->getMsgBase( idx )->isMessage();
419 KMMessage * msg = mFolder->getMsg( idx );
420 if ( needsDownload() ) {
421 ImapJob *job =
new ImapJob( msg );
422 job->setParentFolder( mFolder );
423 connect( job, TQ_SIGNAL(messageRetrieved(
KMMessage*)),
424 this, TQ_SLOT(slotSearchMessageArrived(
KMMessage*)) );
427 slotSearchMessageArrived( msg );
432 void SearchJob::slotAbortSearch( KPIM::ProgressItem* item )
436 mAccount->killAllJobs();
437 TQValueList<TQ_UINT32> serNums;
438 emit searchDone( serNums, mSearchPattern,
true );
442 bool SearchJob::needsDownload()
444 for ( TQPtrListIterator<KMSearchRule> it( *mLocalSearchPattern ) ; it.current() ; ++it ) {
445 if ( (*it)->field() !=
"<status>" ) {
454 #include "searchjob.moc"
ulong UID() const
Get/set UID.
void getLocation(unsigned long key, KMFolder **retFolder, int *retIndex) const
Returns the folder the message represented by the serial number key is in and the index in that folde...
static const KMMsgDict * instance()
Access the globally unique MessageDict.
This class is an abstraction of a search over messages.
KMSearchPattern::Operator op() const
Get the filter operator.
bool matches(const KMMessage *msg, bool ignoreBody=false) const
The central function of this class.
void setOp(KMSearchPattern::Operator aOp)
Set the filter operator.
TQString asString() const
Returns the pattern as string.
SearchJob(KMFolderImap *folder, ImapAccountBase *account, const KMSearchPattern *pattern, TQ_UINT32 serNum=0)
Creates a new job.