20 #include "searchjob.h"
22 #include <KDE/KLocalizedString>
25 #include <QtCore/QDate>
28 #include "message_p.h"
29 #include "session_p.h"
38 Private(): isFuzzy(false), isNegated(false), isNull(false) {};
46 : d(new
Term::Private)
51 Term::Term(Term::Relation relation,
const QVector<Term> &subterms)
52 : d(new
Term::Private)
54 if (subterms.
size() >= 2) {
56 if (relation == KIMAP::Term::Or) {
58 d->command += subterms.
at(0).serialize() +
' ';
59 if (subterms.
size() >= 3) {
60 Term t(relation, subterms.
mid(1));
61 d->command += t.serialize();
62 }
else if (subterms.
size() == 2) {
63 d->command += subterms.
at(1).serialize();
66 Q_FOREACH (
const Term &t, subterms) {
67 d->command += t.serialize() +
' ';
74 }
else if (subterms.
size() == 1) {
75 d->command += subterms.
first().serialize();
81 Term::Term(Term::SearchKey key,
const QString& value)
82 : d(new
Term::Private)
101 d->command +=
"KEYWORD";
104 d->command +=
"SUBJECT";
107 d->command +=
"TEXT";
119 : d(new
Term::Private)
121 d->command +=
"HEADER";
126 Term::Term(Term::BooleanSearchKey key)
127 : d(new
Term::Private)
131 d->command =
"ANSWERED";
134 d->command =
"DELETED";
137 d->command =
"DRAFT";
140 d->command =
"FLAGGED";
149 d->command =
"RECENT";
178 Term::Term(Term::DateSearchKey key,
const QDate &date)
179 : d(new
Term::Private)
183 d->command =
"BEFORE";
189 d->command =
"SENTBEFORE";
192 d->command =
"SENTON";
195 d->command =
"SENTSINCE";
198 d->command =
"SINCE";
203 d->command += months[date.
month()] +
'-';
208 Term::Term(Term::NumberSearchKey key,
int value)
209 : d(new
Term::Private)
213 d->command =
"LARGER";
216 d->command =
"SMALLER";
222 Term::Term(Term::SequenceSearchKey key,
const ImapSet &set)
223 : d(new
Term::Private)
235 Term::Term(
const Term& other)
236 : d(new
Term::Private)
241 Term& Term::operator=(
const Term& other)
247 bool Term::operator==(
const Term& other)
const
249 return d->command == other.d->command &&
250 d->isNegated == other.d->isNegated &&
251 d->isFuzzy == other.d->isFuzzy;
263 return command + d->command;
266 Term &Term::setFuzzy(
bool fuzzy)
272 Term &Term::setNegated(
bool negated)
274 d->isNegated = negated;
278 bool Term::isNull()
const
285 class SearchJobPrivate :
public JobPrivate
288 SearchJobPrivate( Session *session,
const QString& name ) : JobPrivate( session, name ), logic( SearchJob::And ) {
289 criteriaMap[SearchJob::All] =
"ALL";
290 criteriaMap[SearchJob::Answered] =
"ANSWERED";
291 criteriaMap[SearchJob::BCC] =
"BCC";
292 criteriaMap[SearchJob::Before] =
"BEFORE";
293 criteriaMap[SearchJob::Body] =
"BODY";
294 criteriaMap[SearchJob::CC] =
"CC";
295 criteriaMap[SearchJob::Deleted] =
"DELETED";
296 criteriaMap[SearchJob::Draft] =
"DRAFT";
297 criteriaMap[SearchJob::Flagged] =
"FLAGGED";
298 criteriaMap[SearchJob::From] =
"FROM";
299 criteriaMap[SearchJob::Header] =
"HEADER";
300 criteriaMap[SearchJob::Keyword] =
"KEYWORD";
301 criteriaMap[SearchJob::Larger] =
"LARGER";
302 criteriaMap[SearchJob::New] =
"NEW";
303 criteriaMap[SearchJob::Old] =
"OLD";
304 criteriaMap[SearchJob::On] =
"ON";
305 criteriaMap[SearchJob::Recent] =
"RECENT";
306 criteriaMap[SearchJob::Seen] =
"SEEN";
307 criteriaMap[SearchJob::SentBefore] =
"SENTBEFORE";
308 criteriaMap[SearchJob::SentOn] =
"SENTON";
309 criteriaMap[SearchJob::SentSince] =
"SENTSINCE";
310 criteriaMap[SearchJob::Since] =
"SINCE";
311 criteriaMap[SearchJob::Smaller] =
"SMALLER";
312 criteriaMap[SearchJob::Subject] =
"SUBJECT";
313 criteriaMap[SearchJob::Text] =
"TEXT";
314 criteriaMap[SearchJob::To] =
"TO";
315 criteriaMap[SearchJob::Uid] =
"UID";
316 criteriaMap[SearchJob::Unanswered] =
"UNANSWERED";
317 criteriaMap[SearchJob::Undeleted] =
"UNDELETED";
318 criteriaMap[SearchJob::Undraft] =
"UNDRAFT";
319 criteriaMap[SearchJob::Unflagged] =
"UNFLAGGED";
320 criteriaMap[SearchJob::Unkeyword] =
"UNKEYWORD";
321 criteriaMap[SearchJob::Unseen] =
"UNSEEN";
340 ~SearchJobPrivate() { }
346 SearchJob::SearchLogic logic;
355 using namespace KIMAP;
357 SearchJob::SearchJob( Session *session )
358 : Job( *new SearchJobPrivate( session, i18nc(
"Name of the search job",
"Search" ) ) )
362 SearchJob::~SearchJob()
366 void SearchJob::setTerm(
const Term &term)
372 void SearchJob::doStart()
378 if ( !d->charset.isEmpty() ) {
379 searchKey =
"CHARSET " + d->charset;
382 if (!d->term.isNull()) {
385 searchKey += term.
mid(1, term.
size() - 2);
391 if ( d->logic == SearchJob::Not ) {
393 }
else if ( d->logic == SearchJob::Or && d->criterias.size() > 1 ) {
397 if ( d->logic == SearchJob::And ) {
398 for (
int i = 0; i < d->criterias.size(); i++ ) {
406 for (
int i = 0; i < d->criterias.size(); i++ ) {
411 searchKey +=
'(' + key +
')';
418 command =
"UID " + command;
421 d->tags << d->sessionInternal()->sendCommand( command, searchKey );
424 void SearchJob::handleResponse(
const Message &response )
428 if ( handleErrorReplies( response ) == NotHandled ) {
429 if ( response.content.size() >= 1 && response.content[0].toString() ==
"+" ) {
430 if (d->term.isNull()) {
431 d->sessionInternal()->sendData( d->contents[d->nextContent] );
433 kWarning() <<
"The term API only supports inline strings.";
436 }
else if ( response.content.size() >= 2 && response.content[1].toString() ==
"SEARCH" ) {
437 for (
int i = 2; i < response.content.size(); i++ ) {
438 d->results.append( response.content[i].toString().toInt() );
444 void SearchJob::setCharset(
const QByteArray &charset )
447 d->charset = charset;
452 Q_D(
const SearchJob );
456 void SearchJob::setSearchLogic( SearchLogic logic )
462 void SearchJob::addSearchCriteria( SearchCriteria criteria )
466 switch ( criteria ) {
481 d->criterias.append( d->criteriaMap[criteria] );
485 kDebug() <<
"Criteria " << d->criteriaMap[criteria] <<
" needs an argument, but none was specified.";
490 void SearchJob::addSearchCriteria( SearchCriteria criteria,
int argument )
493 switch ( criteria ) {
496 d->criterias.append( d->criteriaMap[criteria] +
' ' +
QByteArray::number( argument ) );
500 kDebug() <<
"Criteria " << d->criteriaMap[criteria] <<
" doesn't accept an integer as an argument.";
505 void SearchJob::addSearchCriteria( SearchCriteria criteria,
const QByteArray &argument )
508 switch ( criteria ) {
516 d->contents.append( argument );
523 d->criterias.append( d->criteriaMap[criteria] +
' ' + argument );
527 kDebug() <<
"Criteria " << d->criteriaMap[criteria] <<
" doesn't accept any argument.";
532 void SearchJob::addSearchCriteria( SearchCriteria criteria,
const QDate &argument )
535 switch ( criteria ) {
542 date += d->months[argument.
month()] +
'-';
544 d->criterias.
append( d->criteriaMap[criteria] +
" \"" + date +
'\"' );
549 kDebug() <<
"Criteria " << d->criteriaMap[criteria] <<
" doesn't accept a date as argument.";
554 void SearchJob::addSearchCriteria(
const QByteArray &searchCriteria )
557 d->criterias.append( searchCriteria );
560 void SearchJob::setUidBased(
bool uidBased)
563 d->uidBased = uidBased;
566 bool SearchJob::isUidBased()
const
568 Q_D(
const SearchJob );
574 Q_D(
const SearchJob );
580 Q_D(
const SearchJob );
583 qCopy( d->results.begin(), d->results.end(), results.
begin() );
bool startsWith(const QByteArray &ba) const
QByteArray number(int n, int base)
const char * constData() const
QVector< T > mid(int pos, int length) const
QByteArray mid(int pos, int len) const
QByteArray & append(char ch)
Represents a set of natural numbers (1-> ) in a as compact as possible form.
const T & at(int i) const
QByteArray toImapSequenceSet() const
Returns a IMAP-compatible QByteArray representation of this set.
QByteArray toUtf8() const