9#include "kimap_debug.h"
10#include <KLocalizedString>
16#include "response_p.h"
31 Private(
const Private &other)
33 , command(other.command)
34 , isFuzzy(other.isFuzzy)
35 , isNegated(other.isNegated)
36 , isNull(other.isNull)
40 Private &operator=(
const Private &other)
42 command = other.command;
43 isFuzzy = other.isFuzzy;
44 isNegated = other.isNegated;
45 isNull = other.isNull;
56 : d(new
Term::Private)
61Term::Term(Term::Relation relation,
const QList<Term> &subterms)
62 : d(new
Term::Private)
64 if (subterms.
size() >= 2) {
65 if (relation == KIMAP::Term::Or) {
66 for (int i = 0; i < subterms.size() - 1; ++i) {
67 d->command +=
"(OR " + subterms[i].serialize() +
" ";
69 d->command += subterms.back().serialize();
70 for (int i = 0; i < subterms.size() - 1; ++i) {
75 for (const Term &t : subterms) {
76 d->command += t.serialize() +
' ';
83 }
else if (subterms.
size() == 1) {
84 d->command += subterms.first().serialize();
90Term::Term(Term::SearchKey key,
const QString &value)
91 : d(new
Term::Private)
104 d->command +=
"BODY";
107 d->command +=
"FROM";
110 d->command +=
"KEYWORD";
113 d->command +=
"SUBJECT";
116 d->command +=
"TEXT";
128 : d(new
Term::Private)
130 d->command +=
"HEADER";
135Term::Term(Term::BooleanSearchKey key)
136 : d(new
Term::Private)
140 d->command =
"ANSWERED";
143 d->command =
"DELETED";
146 d->command =
"DRAFT";
149 d->command =
"FLAGGED";
158 d->command =
"RECENT";
168 static const char *names[12] = {
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec"};
172Term::Term(Term::DateSearchKey key,
const QDate &date)
173 : d(new
Term::Private)
177 d->command =
"BEFORE";
183 d->command =
"SENTBEFORE";
186 d->command =
"SENTON";
189 d->command =
"SENTSINCE";
192 d->command =
"SINCE";
197 d->command += monthName(date.
month()) +
'-';
202Term::Term(Term::NumberSearchKey key,
int value)
203 : d(new
Term::Private)
207 d->command =
"LARGER";
210 d->command =
"SMALLER";
216Term::Term(Term::SequenceSearchKey key,
const ImapSet &set)
217 : d(new
Term::Private)
226 auto optimizedSet = set;
228 d->command +=
" " + optimizedSet.toImapSequenceSet();
231Term::Term(
const Term &other)
232 : d(new
Term::Private)
241Term &Term::operator=(
const Term &other)
247bool Term::operator==(
const Term &other)
const
249 return d->command == other.d->command && d->isNegated == other.d->isNegated && d->isFuzzy == other.d->isFuzzy;
261 return command + d->command;
264Term &Term::setFuzzy(
bool fuzzy)
270Term &Term::setNegated(
bool negated)
272 d->isNegated = negated;
276bool Term::isNull()
const
283class SearchJobPrivate :
public JobPrivate
287 : JobPrivate(session,
name)
288 , logic(SearchJob::And)
290 criteriaMap[SearchJob::All] =
"ALL";
291 criteriaMap[SearchJob::Answered] =
"ANSWERED";
292 criteriaMap[SearchJob::BCC] =
"BCC";
293 criteriaMap[SearchJob::Before] =
"BEFORE";
294 criteriaMap[SearchJob::Body] =
"BODY";
295 criteriaMap[SearchJob::CC] =
"CC";
296 criteriaMap[SearchJob::Deleted] =
"DELETED";
297 criteriaMap[SearchJob::Draft] =
"DRAFT";
298 criteriaMap[SearchJob::Flagged] =
"FLAGGED";
299 criteriaMap[SearchJob::From] =
"FROM";
300 criteriaMap[SearchJob::Header] =
"HEADER";
301 criteriaMap[SearchJob::Keyword] =
"KEYWORD";
302 criteriaMap[SearchJob::Larger] =
"LARGER";
303 criteriaMap[SearchJob::New] =
"NEW";
304 criteriaMap[SearchJob::Old] =
"OLD";
305 criteriaMap[SearchJob::On] =
"ON";
306 criteriaMap[SearchJob::Recent] =
"RECENT";
307 criteriaMap[SearchJob::Seen] =
"SEEN";
308 criteriaMap[SearchJob::SentBefore] =
"SENTBEFORE";
309 criteriaMap[SearchJob::SentOn] =
"SENTON";
310 criteriaMap[SearchJob::SentSince] =
"SENTSINCE";
311 criteriaMap[SearchJob::Since] =
"SINCE";
312 criteriaMap[SearchJob::Smaller] =
"SMALLER";
313 criteriaMap[SearchJob::Subject] =
"SUBJECT";
314 criteriaMap[SearchJob::Text] =
"TEXT";
315 criteriaMap[SearchJob::To] =
"TO";
316 criteriaMap[SearchJob::Uid] =
"UID";
317 criteriaMap[SearchJob::Unanswered] =
"UNANSWERED";
318 criteriaMap[SearchJob::Undeleted] =
"UNDELETED";
319 criteriaMap[SearchJob::Undraft] =
"UNDRAFT";
320 criteriaMap[SearchJob::Unflagged] =
"UNFLAGGED";
321 criteriaMap[SearchJob::Unkeyword] =
"UNKEYWORD";
322 criteriaMap[SearchJob::Unseen] =
"UNSEEN";
349 SearchJob::SearchLogic logic;
358using namespace KIMAP;
360SearchJob::SearchJob(
Session *session)
361 : Job(*new SearchJobPrivate(session,
i18nc(
"Name of the search job",
"Search")))
365SearchJob::~SearchJob()
369void SearchJob::setTerm(
const Term &term)
375void SearchJob::doStart()
381 if (!d->charset.isEmpty()) {
382 searchKey =
"CHARSET " + d->charset;
385 if (!d->term.isNull()) {
388 searchKey += term.
mid(1, term.
size() - 2);
393 if (d->logic == SearchJob::Not) {
395 }
else if (d->logic == SearchJob::Or && d->criterias.size() > 1) {
399 if (d->logic == SearchJob::And) {
400 const int numberCriterias(d->criterias.size());
401 for (
int i = 0; i < numberCriterias; i++) {
409 const int numberCriterias(d->criterias.size());
410 for (
int i = 0; i < numberCriterias; i++) {
415 searchKey +=
'(' + key +
')';
422 command =
"UID " + command;
425 d->tags << d->sessionInternal()->sendCommand(command, searchKey);
428void SearchJob::handleResponse(
const Response &response)
432 if (handleErrorReplies(response) == NotHandled) {
433 if (response.content.size() >= 1 && response.content[0].toString() ==
"+") {
434 if (d->term.isNull()) {
435 d->sessionInternal()->sendData(d->contents[d->nextContent]);
437 qCWarning(KIMAP_LOG) <<
"The term API only supports inline strings.";
440 }
else if (response.content.size() >= 2 && response.content[1].toString() ==
"SEARCH") {
441 for (
int i = 2; i < response.content.size(); i++) {
442 d->results.append(response.content[i].toString().toInt());
448void SearchJob::setCharset(
const QByteArray &charset)
451 d->charset = charset;
456 Q_D(
const SearchJob);
460void SearchJob::setSearchLogic(SearchLogic logic)
466void SearchJob::addSearchCriteria(SearchCriteria criteria)
485 d->criterias.append(d->criteriaMap[criteria]);
489 qCDebug(KIMAP_LOG) <<
"Criteria " << d->criteriaMap[criteria] <<
" needs an argument, but none was specified.";
494void SearchJob::addSearchCriteria(SearchCriteria criteria,
int argument)
504 qCDebug(KIMAP_LOG) <<
"Criteria " << d->criteriaMap[criteria] <<
" doesn't accept an integer as an argument.";
509void SearchJob::addSearchCriteria(SearchCriteria criteria,
const QByteArray &argument)
520 d->contents.append(argument);
527 d->criterias.append(d->criteriaMap[criteria] +
' ' + argument);
531 qCDebug(KIMAP_LOG) <<
"Criteria " << d->criteriaMap[criteria] <<
" doesn't accept any argument.";
536void SearchJob::addSearchCriteria(SearchCriteria criteria,
const QDate &argument)
546 date += d->months[argument.
month()] +
'-';
548 d->criterias.append(d->criteriaMap[criteria] +
" \"" + date +
'\"');
553 qCDebug(KIMAP_LOG) <<
"Criteria " << d->criteriaMap[criteria] <<
" doesn't accept a date as argument.";
558void SearchJob::addSearchCriteria(
const QByteArray &searchCriteria)
561 d->criterias.append(searchCriteria);
564void SearchJob::setUidBased(
bool uidBased)
567 d->uidBased = uidBased;
570bool SearchJob::isUidBased()
const
572 Q_D(
const SearchJob);
578 Q_D(
const SearchJob);
582#include "moc_searchjob.cpp"
Represents a set of natural numbers (1->∞) in a as compact as possible form.
void optimize()
Optimizes the ImapSet by sorting and merging overlapping intervals.
QString i18nc(const char *context, const char *text, const TYPE &arg...)
AKONADI_MIME_EXPORT const char Answered[]
AKONADI_MIME_EXPORT const char Seen[]
AKONADI_MIME_EXPORT const char Deleted[]
AKONADI_MIME_EXPORT const char Flagged[]
AKONADI_MIME_EXPORT const char Body[]
QString name(StandardAction id)
char at(qsizetype i) const const
const char * constData() const const
QByteArray mid(qsizetype pos, qsizetype len) const const
QByteArray number(double n, char format, int precision)
qsizetype size() const const
bool startsWith(QByteArrayView bv) const const
bool isEmpty() const const
qsizetype size() const const
QByteArray toUtf8() const const