23#include "kimap_debug.h"
31class FetchJobPrivate :
public JobPrivate
35 : JobPrivate(session,
name)
48 void skipLeadingSpaces(
const QByteArray &structure,
int &pos);
60using namespace KIMAP2;
62FetchJob::FetchScope::FetchScope():
63 mode(FetchScope::Content),
65 gmailExtensionsEnabled(false)
70FetchJob::FetchJob(
Session *session)
71 : Job(*new FetchJobPrivate(this, session,
"Fetch"))
82 d->avoidParsing = avoid;
101 d->uidBased = uidBased;
122void FetchJob::doStart()
127 QByteArray parameters = d->set.toImapSequenceSet() +
' ';
130 switch (d->scope.mode) {
132 if (d->scope.parts.isEmpty()) {
133 parameters +=
"(RFC822.SIZE INTERNALDATE BODY.PEEK[HEADER.FIELDS (TO FROM MESSAGE-ID REFERENCES IN-REPLY-TO SUBJECT DATE)] FLAGS UID";
136 foreach (
const QByteArray &part, d->scope.parts) {
137 parameters +=
"BODY.PEEK[" + part +
".MIME] ";
143 parameters +=
"(FLAGS UID";
146 parameters +=
"(BODYSTRUCTURE UID";
149 if (d->scope.parts.isEmpty()) {
150 parameters +=
"(BODY.PEEK[] UID";
153 foreach (
const QByteArray &part, d->scope.parts) {
154 parameters +=
"BODY.PEEK[" + part +
"] ";
160 parameters +=
"(RFC822.SIZE INTERNALDATE BODY.PEEK[] FLAGS UID";
163 if (d->scope.parts.isEmpty()) {
164 parameters +=
"(BODY.PEEK[] FLAGS UID";
166 parameters +=
"(BODY.PEEK[HEADER.FIELDS (TO FROM MESSAGE-ID REFERENCES IN-REPLY-TO SUBJECT DATE)]";
167 foreach (
const QByteArray &part, d->scope.parts) {
168 parameters +=
" BODY.PEEK[" + part +
".MIME] BODY.PEEK[" + part +
"]";
170 parameters +=
" FLAGS UID";
174 parameters +=
"(RFC822.SIZE INTERNALDATE BODY.PEEK[HEADER] FLAGS UID";
178 if (d->scope.gmailExtensionsEnabled) {
179 parameters +=
" X-GM-LABELS X-GM-MSGID X-GM-THRID";
183 if (d->scope.changedSince > 0) {
189 command =
"UID " + command;
192 d->selectedMailBox = d->m_session->selectedMailBox();
193 d->sendCommand(command, parameters);
196void FetchJob::handleResponse(
const Message &response)
200 if (handleErrorReplies(response) == NotHandled) {
201 if (response.content.size() == 4 &&
202 response.content[2].toString() ==
"FETCH" &&
203 response.content[3].type() == Message::Part::List) {
208 result.sequenceNumber = response.content[1].toString().toLongLong();
209 bool shouldParseMessage =
false;
215 qCWarning(KIMAP2_LOG) <<
"FETCH reply got truncated, skipping.";
216 qCWarning(KIMAP2_LOG) << response.toString();
217 qCWarning(KIMAP2_LOG) <<
result.sequenceNumber;
218 qCWarning(KIMAP2_LOG) << content;
219 qCWarning(KIMAP2_LOG) << str;
224 result.uid = it->toLongLong();
225 }
else if (str ==
"RFC822.SIZE") {
226 result.size = it->toLongLong();
227 }
else if (str ==
"INTERNALDATE") {
232 }
else if (str ==
"FLAGS") {
233 if ((*it).startsWith(
'(') && (*it).endsWith(
')')) {
241 }
else if (str ==
"X-GM-LABELS") {
242 result.attributes << qMakePair<QByteArray, QVariant>(
"X-GM-LABELS", *it);
243 }
else if (str ==
"X-GM-THRID") {
244 result.attributes << qMakePair<QByteArray, QVariant>(
"X-GM-THRID", *it);
245 }
else if (str ==
"X-GM-MSGID") {
246 result.attributes << qMakePair<QByteArray, QVariant>(
"X-GM-MSGID", *it);
247 }
else if (str ==
"BODYSTRUCTURE") {
252 d->parseBodyStructure(*it, pos,
result.message.data());
253 result.message->assemble();
256 while (it != content.
constEnd() && !(*it).endsWith(
']')) {
262 if ((index = str.
indexOf(
"HEADER")) > 0 || (index = str.
indexOf(
"MIME")) > 0) {
263 if (str[index - 1] ==
'.') {
265 if (!
result.parts.contains(partId)) {
268 result.parts[partId]->setHead(*it);
269 result.parts[partId]->parse();
274 shouldParseMessage =
true;
275 result.message->setHead(*it);
278 if (str ==
"BODY[]") {
282 shouldParseMessage =
true;
283 result.message->setContent(KMime::CRLFtoLF(*it));
286 if (!
result.parts.contains(partId)) {
289 result.parts[partId]->setBody(*it);
290 result.parts[partId]->parse();
296 if (
result.message && shouldParseMessage && !d->avoidParsing) {
299 emit resultReceived(
result);
306 skipLeadingSpaces(structure, pos);
308 if (structure[pos] !=
'(') {
314 if (structure[pos] !=
'(') {
316 parsePart(structure, pos, content);
319 while (pos < structure.
size() && structure[pos] ==
'(') {
321 content->addContent(child);
322 parseBodyStructure(structure, pos, child);
326 QByteArray subType = parseString(structure, pos);
329 QByteArray parameters = parseSentence(structure, pos);
330 if (parameters.
contains(
"BOUNDARY")) {
334 QByteArray disposition = parseSentence(structure, pos);
335 if (disposition.
contains(
"INLINE")) {
337 }
else if (disposition.
contains(
"ATTACHMENT")) {
341 parseSentence(structure, pos);
345 while (pos < structure.
size() && structure[pos] !=
')') {
346 skipLeadingSpaces(structure, pos);
347 parseSentence(structure, pos);
348 skipLeadingSpaces(structure, pos);
356 if (structure[pos] !=
'(') {
362 QByteArray mainType = parseString(structure, pos);
363 QByteArray subType = parseString(structure, pos);
367 parseSentence(structure, pos);
368 parseString(structure, pos);
372 parseString(structure, pos);
373 parseString(structure, pos);
374 parseString(structure, pos);
376 QByteArray disposition = parseSentence(structure, pos);
377 if (disposition.
contains(
"INLINE")) {
379 }
else if (disposition.
contains(
"ATTACHMENT")) {
390 while (pos < structure.
size() && structure[pos] !=
')') {
391 skipLeadingSpaces(structure, pos);
392 parseSentence(structure, pos);
393 skipLeadingSpaces(structure, pos);
402 skipLeadingSpaces(structure, pos);
404 if (structure[pos] !=
'(') {
405 return parseString(structure, pos);
411 switch (structure[pos]) {
429 skipLeadingSpaces(structure, pos);
430 parseString(structure, pos);
431 skipLeadingSpaces(structure, pos);
434 }
while (pos < structure.
size() && stack != 0);
445 skipLeadingSpaces(structure, pos);
448 bool foundSlash =
false;
451 if (structure[pos] ==
'"') {
454 if (structure[pos] ==
'\\')
460 if (structure[pos] ==
'"')
470 if (structure[pos] ==
' ' ||
471 structure[pos] ==
'(' ||
472 structure[pos] ==
')' ||
473 structure[pos] ==
'[' ||
474 structure[pos] ==
']' ||
475 structure[pos] ==
'\n' ||
476 structure[pos] ==
'\r' ||
477 structure[pos] ==
'"')
481 if (structure[pos] ==
'\\')
491 if (result ==
"NIL") {
509void FetchJobPrivate::skipLeadingSpaces(
const QByteArray &structure,
int &pos)
511 while (pos < structure.
size() && structure[pos] ==
' ') {
516#include "moc_fetchjob.cpp"
Used to indicate what message data should be fetched.
@ Full
Fetch the complete message.
@ Headers
Fetch RFC-2822 or MIME message headers.
@ Flags
Fetch the message flags (the UID is also fetched)
@ Content
Fetch the message content (the UID is also fetched)
@ FullHeaders
Fetch message size (in octets), internal date of the message, flags, UID and all RFC822 headers.
@ HeaderAndContent
Fetch the message MIME headers and the content of parts specified in the parts field.
@ Structure
Fetch the MIME message body structure (the UID is also fetched)
Fetch message data from the server.
void setUidBased(bool uidBased)
Set how the sequence set should be interpreted.
ImapSet sequenceSet() const
The messages that will be fetched.
FetchScope scope() const
Specifies what data will be fetched.
void setAvoidParsing(bool)
Avoid calling parse() on returned KMime::Messages.
void setSequenceSet(const ImapSet &set)
Set which messages to fetch data for.
void setScope(const FetchScope &scope)
Sets what data should be fetched.
bool isUidBased() const
How to interpret the sequence set.
Represents a set of natural numbers (1->∞) in a as compact as possible form.
bool isEmpty() const
Returns true if this set doesn't contains any values.
const Headers::ContentType * contentType() const
const Headers::ContentDisposition * contentDisposition() const
const Headers::ContentDescription * contentDescription() const
Q_SCRIPTABLE Q_NOREPLY void start()
QString name(StandardAction id)
bool contains(QByteArrayView bv) const const
bool endsWith(QByteArrayView bv) const const
qsizetype indexOf(QByteArrayView bv, qsizetype from) const const
bool isEmpty() const const
QByteArray mid(qsizetype pos, qsizetype len) const const
QByteArray number(double n, char format, int precision)
QByteArray & remove(qsizetype pos, qsizetype len)
QByteArray & replace(QByteArrayView before, QByteArrayView after)
qsizetype size() const const
QList< QByteArray > split(char sep) const const
bool startsWith(QByteArrayView bv) const const
QByteArray trimmed() const const
QDateTime fromString(QStringView string, QStringView format, QCalendar cal)
QList< T > toList() const const
const_iterator constBegin() const const
const_iterator constEnd() const const