22#include <KDE/KLocalizedString>
25#include <QtCore/QDate>
38 Private(): isFuzzy(false), isNegated(false), isNull(false) {};
51Term::Term(Term::Relation relation,
const QVector<Term> &subterms)
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() +
' ';
69 if (!subterms.isEmpty()) {
74 }
else if (subterms.size() == 1) {
75 d->command += subterms.first().serialize();
81Term::Term(Term::SearchKey key,
const QString& value)
101 d->command +=
"KEYWORD";
104 d->command +=
"SUBJECT";
107 d->command +=
"TEXT";
114 d->command +=
" \"" + QByteArray(value.toUtf8().constData()) +
"\"";
118Term::Term(
const QString &header,
const QString &value )
119: d(new
Term::Private)
121 d->command +=
"HEADER";
122 d->command +=
' ' + QByteArray(header.toUtf8().constData());
123 d->command +=
" \"" + QByteArray(value.toUtf8().constData()) +
"\"";
126Term::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";
157QMap<int, QByteArray> initializeMonths()
159 QMap<int, QByteArray> months;
176static QMap<int, QByteArray> months = initializeMonths();
178Term::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";
202 d->command += QByteArray::number( date.day() ) +
'-';
203 d->command += months[date.month()] +
'-';
204 d->command += QByteArray::number( date.year() );
208Term::Term(Term::NumberSearchKey key,
int value)
209: d(new
Term::Private)
213 d->command =
"LARGER";
216 d->command =
"SMALLER";
219 d->command +=
" " + QByteArray::number(value);
222Term::Term(Term::SequenceSearchKey key,
const ImapSet &set)
223: d(new
Term::Private)
235Term::Term(
const Term& other)
236: d(new
Term::Private)
241Term& Term::operator=(
const Term& other)
247bool 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;
254QByteArray Term::serialize()
const
263 return command + d->command;
266Term &Term::setFuzzy(
bool fuzzy)
272Term &Term::setNegated(
bool negated)
274 d->isNegated = negated;
278bool 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() { }
343 QList<QByteArray> criterias;
344 QMap<SearchJob::SearchCriteria, QByteArray > criteriaMap;
345 QMap<int, QByteArray> months;
346 SearchJob::SearchLogic logic;
347 QList<QByteArray> contents;
348 QList<qint64> results;
355using namespace KIMAP;
357SearchJob::SearchJob( Session *session )
358 : Job( *new SearchJobPrivate( session, i18nc(
"Name of the search job",
"Search" ) ) )
362SearchJob::~SearchJob()
366void SearchJob::setTerm(
const Term &term)
372void SearchJob::doStart()
376 QByteArray searchKey;
378 if ( !d->charset.isEmpty() ) {
379 searchKey =
"CHARSET " + d->charset;
382 if (!d->term.isNull()) {
383 const QByteArray term = d->term.serialize();
384 if (term.startsWith(
'(')) {
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++ ) {
399 const QByteArray key = d->criterias.at( i );
406 for (
int i = 0; i < d->criterias.size(); i++ ) {
407 const QByteArray key = d->criterias.at( i );
411 searchKey +=
'(' + key +
')';
416 QByteArray command =
"SEARCH";
418 command =
"UID " + command;
421 d->tags << d->sessionInternal()->sendCommand( command, searchKey );
424void 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() );
444void SearchJob::setCharset(
const QByteArray &charset )
447 d->charset = charset;
450QByteArray SearchJob::charset()
const
452 Q_D(
const SearchJob );
456void SearchJob::setSearchLogic( SearchLogic logic )
462void 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.";
490void 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.";
505void SearchJob::addSearchCriteria( SearchCriteria criteria,
const QByteArray &argument )
508 switch ( criteria ) {
516 d->contents.append( argument );
517 d->criterias.append( d->criteriaMap[criteria] +
" {" + QByteArray::number( argument.size() ) +
'}' );
523 d->criterias.append( d->criteriaMap[criteria] +
' ' + argument );
527 kDebug() <<
"Criteria " << d->criteriaMap[criteria] <<
" doesn't accept any argument.";
532void SearchJob::addSearchCriteria( SearchCriteria criteria,
const QDate &argument )
535 switch ( criteria ) {
541 QByteArray date = QByteArray::number( argument.day() ) +
'-';
542 date += d->months[argument.month()] +
'-';
543 date += QByteArray::number( argument.year() );
544 d->criterias.append( d->criteriaMap[criteria] +
" \"" + date +
'\"' );
549 kDebug() <<
"Criteria " << d->criteriaMap[criteria] <<
" doesn't accept a date as argument.";
554void SearchJob::addSearchCriteria(
const QByteArray &searchCriteria )
557 d->criterias.append( searchCriteria );
560void SearchJob::setUidBased(
bool uidBased)
563 d->uidBased = uidBased;
566bool SearchJob::isUidBased()
const
568 Q_D(
const SearchJob );
572QList<qint64> SearchJob::results()
const
574 Q_D(
const SearchJob );
578QList<int> SearchJob::foundItems()
580 Q_D(
const SearchJob );
583 qCopy( d->results.begin(), d->results.end(), results.begin() );
Represents a set of natural numbers (1-> ) in a as compact as possible form.
QByteArray toImapSequenceSet() const
Returns a IMAP-compatible QByteArray representation of this set.