Bincimap 2.0.16
Easy Imapping
Loading...
Searching...
No Matches
operator-fetch.cc
Go to the documentation of this file.
1
7#include <string>
8
9#include "depot.h"
10#include "iodevice.h"
11#include "iofactory.h"
12#include "mailbox.h"
13#include "operators.h"
14#include "imapparser.h"
15#include "pendingupdates.h"
16#include "recursivedescent.h"
17#include "session.h"
18#include "convert.h"
19
20using namespace ::std;
21using namespace Binc;
22
23namespace {
24 void outputFlags(const Message & message)
25 {
26 bincClient << "FLAGS ";
27
28 bincClient << "(";
29 int flags = message.getStdFlags();
30 vector<string> flagv;
31 if (flags & Message::F_SEEN) flagv.push_back("\\Seen");
32 if (flags & Message::F_ANSWERED) flagv.push_back("\\Answered");
33 if (flags & Message::F_DELETED) flagv.push_back("\\Deleted");
34 if (flags & Message::F_DRAFT) flagv.push_back("\\Draft");
35 if (flags & Message::F_RECENT) flagv.push_back("\\Recent");
36 if (flags & Message::F_FLAGGED) flagv.push_back("\\Flagged");
37
38 for (vector<string>::const_iterator k
39 = flagv.begin(); k != flagv.end(); ++k) {
40 if (k != flagv.begin()) bincClient << " ";
41 bincClient << *k;
42 }
43
44 vector<string> customFlags = message.getCustomFlags();
45 for (vector<string>::const_iterator it = customFlags.begin();
46 it != customFlags.end(); ++it) {
47 if (flagv.size() > 0 || it != customFlags.begin()) bincClient << " ";
48 bincClient << *it;
49 }
50
51 bincClient << ")";
52 }
53
54}
55
56//----------------------------------------------------------------------
58{
59}
60
61//----------------------------------------------------------------------
63{
64}
65
66//----------------------------------------------------------------------
67const string FetchOperator::getName(void) const
68{
69 return "FETCH";
70}
71
72//----------------------------------------------------------------------
74{
75 return Session::SELECTED;
76}
77
78//------------------------------------------------------------------------
80 Request &request)
81{
82 Session &session = Session::getInstance();
83
84 bool updateFlags = false;
85 Request req = request;
86
87 Mailbox *mailbox = depot.getSelected();
88
89 // If this is a UID FETCH, check if the UID attribute is fetched. If
90 // it is not, then add it to the list of fetch attributes.
91 vector<BincImapParserFetchAtt>::const_iterator f_i;
92 bool uidfetched = false;
93 if (request.getUidMode()) {
94 f_i = request.fatt.begin();
95 while (f_i != request.fatt.end()) {
96 if ((*f_i).type == "UID") {
97 uidfetched = true;
98 break;
99 }
100 f_i++;
101 }
102
103 if (!uidfetched) {
105 b.type = "UID";
106 req.fatt.push_back(b);
107 }
108 }
109
110 // Convert macros ALL, FULL and FAST
111 f_i = request.fatt.begin();
112 while (f_i != request.fatt.end()) {
113 const string &type = (*f_i).type;
114 if (type == "ALL") {
115 req.fatt.push_back(BincImapParserFetchAtt("FLAGS"));
116 req.fatt.push_back(BincImapParserFetchAtt("INTERNALDATE"));
117 req.fatt.push_back(BincImapParserFetchAtt("RFC822.SIZE"));
118 req.fatt.push_back(BincImapParserFetchAtt("ENVELOPE"));
119 } else if (type == "FULL") {
120 req.fatt.push_back(BincImapParserFetchAtt("FLAGS"));
121 req.fatt.push_back(BincImapParserFetchAtt("INTERNALDATE"));
122 req.fatt.push_back(BincImapParserFetchAtt("RFC822.SIZE"));
123 req.fatt.push_back(BincImapParserFetchAtt("ENVELOPE"));
124 req.fatt.push_back(BincImapParserFetchAtt("BODY"));
125 } else if (type == "FAST") {
126 req.fatt.push_back(BincImapParserFetchAtt("FLAGS"));
127 req.fatt.push_back(BincImapParserFetchAtt("INTERNALDATE"));
128 req.fatt.push_back(BincImapParserFetchAtt("RFC822.SIZE"));
129 }
130
131 ++f_i;
132 }
133
134 int mode;
135 if (req.getUidMode())
136 mode = Mailbox::UID_MODE;
137 else
138 mode = Mailbox::SQNR_MODE;
139
141 = mailbox->begin(req.bset, Mailbox::SKIP_EXPUNGED | mode);
142
143 for (; i != mailbox->end(); ++i) {
144 Message &message = *i;
145
146 bincClient << "* " << i.getSqnr() << " FETCH (";
147 bool hasprinted = false;
148 f_i = req.fatt.begin();
149 while (f_i != req.fatt.end()) {
150 BincImapParserFetchAtt fatt = *f_i;
151
152 string prefix = "";
153 if (hasprinted) prefix = " ";
154
155 if (fatt.type == "FLAGS") {
156 // FLAGS
157 hasprinted = true;
158 bincClient << prefix;
159
160 outputFlags(message);
161 } else if (fatt.type == "UID") {
162 // UID
163 hasprinted = true;
164 bincClient << prefix << "UID " << message.getUID();
165 } else if (fatt.type == "RFC822.SIZE") {
166 // RFC822.SIZE
167 hasprinted = true;
168 bincClient << prefix << "RFC822.SIZE " << message.getSize(true);
169 } else if (fatt.type == "ENVELOPE") {
170 // ENVELOPE
171 hasprinted = true;
172 bincClient << prefix << "ENVELOPE ";
173 message.printEnvelope();
174 } else if (fatt.type == "BODYSTRUCTURE") {
175 // BODYSTRUCTURE
176 hasprinted = true;
177 bincClient << prefix << "BODYSTRUCTURE ";
178 message.printBodyStructure(true);
179 } else if (fatt.type == "BODY" && !fatt.hassection) {
180 // BODY with no section
181 hasprinted = true;
182 session.addBody();
183 bincClient << prefix << "BODY ";
184 message.printBodyStructure(false);
185 } else if (fatt.type == "INTERNALDATE") {
186 // INTERNALDATE
187 hasprinted = true;
188 bincClient << prefix << "INTERNALDATE ";
189
190 time_t iDate = message.getInternalDate();
191 struct tm *_tm = gmtime(&iDate);
192 char internal[64];
193 string iDateStr;
194 if (strftime(internal, sizeof(internal),
195 "%d-%b-%Y %H:%M:%S %z", _tm) != 0) {
196 if (internal[0] == '0') internal[0] = ' ';
197 iDateStr = internal;
198 } else
199 iDateStr = "NIL";
200
201 bincClient << toImapString(iDateStr);
202 } else if (fatt.type == "BODY" || fatt.type == "BODY.PEEK") {
203 // BODY & BODY.PEEK
204 hasprinted = true;
205 session.addBody();
206
207 bincClient << prefix;
208 bool peek = (fatt.type == "BODY.PEEK");
209 bincClient << fatt.toString();
210
211 bool includeheaders = true;
212 bool fullheader = false;
213 bool bodyfetch = false;
214
215 if (fatt.section != "" || fatt.sectiontext == ""
216 || fatt.sectiontext == "TEXT") {
217 bodyfetch = true;
218 fullheader = true;
219 }
220
221 if (fatt.sectiontext == "HEADER.FIELDS.NOT")
222 includeheaders = false;
223
224 if (fatt.sectiontext == "HEADER"
225 || fatt.sectiontext == "HEADER.FIELDS"
226 || fatt.sectiontext == "HEADER.FIELDS.NOT"
227 || fatt.sectiontext == "MIME") {
228 vector<string> v;
229
230 if (fatt.sectiontext == "MIME") {
231 v.push_back("content-type");
232 v.push_back("content-transfer-encoding");
233 v.push_back("content-disposition");
234 v.push_back("content-description");
235 } else
236 v = fatt.headerlist;
237
238 string dummy;
239 unsigned int size = fullheader
240 ? message.getHeaderSize(fatt.section, v, true,
241 fatt.offsetstart,
242 fatt.offsetlength,
243 fatt.sectiontext == "MIME")
244 : message.getHeaderSize(fatt.section, fatt.headerlist,
245 includeheaders,
246 fatt.offsetstart,
247 fatt.offsetlength,
248 fatt.sectiontext == "MIME");
249
250 bincClient << "{" << size << "}\r\n";
251
252 if (fullheader) {
253 message.printHeader(fatt.section, v, true,
254 fatt.offsetstart,
255 fatt.offsetlength,
256 fatt.sectiontext == "MIME");
257 } else {
258 message.printHeader(fatt.section, fatt.headerlist,
259 includeheaders,
260 fatt.offsetstart,
261 fatt.offsetlength,
262 fatt.sectiontext == "MIME");
263 }
264 } else {
265 unsigned int size;
266 if ((fatt.sectiontext == "" || fatt.sectiontext == "TEXT")
267 && fatt.section == "")
268 size = message.getDocSize(fatt.offsetstart,
269 fatt.offsetlength,
270 fatt.sectiontext == "TEXT");
271 else
272 size = message.getBodySize(fatt.section,
273 fatt.offsetstart,
274 fatt.offsetlength);
275
276 bincClient << "{" << size << "}\r\n";
277
278 if ((fatt.sectiontext == "" || fatt.sectiontext == "TEXT")
279 && fatt.section == "")
280 message.printDoc(fatt.offsetstart,
281 fatt.offsetlength,
282 fatt.sectiontext == "TEXT");
283 else
284 message.printBody(fatt.section, fatt.offsetstart,
285 fatt.offsetlength);
286 }
287
288 // set the \Seen flag if .PEEK is not used.
289 if (!peek)
290 if ((message.getStdFlags() & Message::F_SEEN) == 0)
292 } else if (fatt.type == "RFC822") {
293 bincClient << prefix;
294 hasprinted = true;
295 session.addBody();
296 bincClient << fatt.toString();
297 unsigned int size = message.getDocSize(fatt.offsetstart,
298 fatt.offsetlength);
299 bincClient << " {" << size << "}\r\n";
300 message.printDoc(fatt.offsetstart, fatt.offsetlength);
301
302 // set the \Seen flag
303 if ((message.getStdFlags() & Message::F_SEEN) == 0)
305
306 } else if (fatt.type == "RFC822.HEADER") {
307 bincClient << prefix;
308 hasprinted = true;
309 bincClient << fatt.toString();
310 vector<string> v;
311 string dummy;
312 unsigned int size = message.getHeaderSize("", v, true,
313 fatt.offsetstart,
314 fatt.offsetlength);
315 bincClient << " {" << size << "}\r\n";
316 message.printHeader("", v, true, fatt.offsetstart,
317 fatt.offsetlength);
318 } else if (fatt.type == "RFC822.TEXT") {
319 // RFC822.TEXT
320 bincClient << prefix;
321 hasprinted = true;
322 session.addBody();
323
324 bincClient << fatt.toString();
325
326 bool bodyfetch = false;
327 bodyfetch = true;
328
329 unsigned int size;
330 if (fatt.sectiontext == "" && fatt.section == "")
331 size = message.getDocSize(fatt.offsetstart,
332 fatt.offsetlength, true);
333 else
334 size = message.getBodySize(fatt.section, fatt.offsetstart,
335 fatt.offsetlength);
336
337 bincClient << " {" << size << "}\r\n";
338
339 if (fatt.sectiontext == "" && fatt.section == "")
340 message.printDoc(fatt.offsetstart,
341 fatt.offsetlength, true);
342 else
343 message.printBody(fatt.section, fatt.offsetstart,
344 fatt.offsetlength);
345
346 // set the \Seen flag
347 if ((message.getStdFlags() & Message::F_SEEN) == 0)
349
350 } else {
351 // Unrecognized fetch_att, this is stopped by the parser
352 // so we never get here.
353 }
354
355 f_i++;
356 }
357
358 // FIXME: how are parse error passed back?
359
360 bincClient << ")" << endl;
361
362 if (message.hasFlagsChanged()) {
363 updateFlags = true;
364 bincClient << "* " << i.getSqnr() << " FETCH (";
365 outputFlags(message);
366 bincClient << ")" << endl;
367 message.setFlagsUnchanged();
368 }
369 }
370
371 if (updateFlags) mailbox->updateFlags();
372
373 pendingUpdates(mailbox,
377 | PendingUpdates::RECENT, true);
378
379 return OK;
380}
381
382//----------------------------------------------------------------------
384{
385 Session &session = Session::getInstance();
386
388 if ((res = expectSPACE()) != ACCEPT) {
389 session.setLastError("Expected SPACE after FETCH");
390 return res;
391 }
392
393 if ((res = expectSet(c_in.getSet())) != ACCEPT) {
394 session.setLastError("Expected sequence set after FETCH SPACE");
395 return res;
396 }
397
398 if ((res = expectSPACE()) != ACCEPT) {
399 session.setLastError("Expected SPACE after FETCH SPACE set");
400 return res;
401 }
402
404
405 if ((res = expectThisString("ALL")) == ACCEPT) {
406 f.type = "ALL";
407 c_in.fatt.push_back(f);
408 } else if ((res = expectThisString("FULL")) == ACCEPT) {
409 f.type = "FULL";
410 c_in.fatt.push_back(f);
411 } else if ((res = expectThisString("FAST")) == ACCEPT) {
412 f.type = "FAST";
413 c_in.fatt.push_back(f);
414 } else if ((res = expectFetchAtt(f)) == ACCEPT) {
415 c_in.fatt.push_back(f);
416 } else if ((res = expectThisString("(")) == ACCEPT) {
417 while (1) {
419 if ((res = expectFetchAtt(ftmp)) != ACCEPT) {
420 session.setLastError("Expected fetch_att");
421 return res;
422 }
423
424 c_in.fatt.push_back(ftmp);
425
426 if ((res = expectSPACE()) == REJECT) break;
427 else if (res == ERROR) return ERROR;
428 }
429
430 if ((res = expectThisString(")")) != ACCEPT) {
431 session.setLastError("Expected )");
432 return res;
433 }
434 } else {
435 session.setLastError("Expected ALL, FULL, FAST, fetch_att or (");
436 return res;
437 }
438
439 if ((res = expectCRLF()) != ACCEPT) {
440 session.setLastError("Expected CRLF");
441 return res;
442 }
443
444 c_in.setName("FETCH");
445 return ACCEPT;
446}
447
448//----------------------------------------------------------------------
451{
452 Session &session = Session::getInstance();
453
455 if ((res = expectThisString("HEADER")) == ACCEPT) {
456 f_in.sectiontext = "HEADER";
457
458 if ((res = expectThisString(".FIELDS")) == ACCEPT) {
459 f_in.sectiontext += ".FIELDS";
460
461 if ((res = expectThisString(".NOT")) == ACCEPT)
462 f_in.sectiontext += ".NOT";
463
464 if ((res = expectSPACE()) != ACCEPT) {
465 session.setLastError("expected SPACE");
466 return res;
467 }
468
469 if ((res = expectHeaderList(f_in)) != ACCEPT) {
470 session.setLastError("Expected header_list");
471 return res;
472 }
473 }
474 } else if ((res = expectThisString("TEXT")) == ACCEPT)
475 f_in.sectiontext = "TEXT";
476 else
477 return REJECT;
478
479 return ACCEPT;
480
481}
482
483//----------------------------------------------------------------------
486{
487 Session &session = Session::getInstance();
488
490 if ((res = expectThisString("[")) != ACCEPT)
491 return REJECT;
492
493 if ((res = expectSectionText(f_in)) != ACCEPT) {
494 unsigned int n;
495 if ((res = expectNZNumber(n)) == ACCEPT) {
496 BincStream nstr;
497 nstr << n;
498 f_in.section = nstr.str();
499
500 bool gotadotalready = false;
501 while (1) {
502 if ((res = expectThisString(".")) != ACCEPT) break;
503
504 if ((res = expectNZNumber(n)) != ACCEPT) {
505 gotadotalready = true;
506 break;
507 }
508
509 f_in.section += ".";
510 BincStream nstr;
511 nstr << n;
512 f_in.section += nstr.str();
513 }
514
515 if (gotadotalready || (res = expectThisString(".")) == ACCEPT) {
516 if ((res = expectThisString("MIME")) == ACCEPT) {
517 f_in.sectiontext = "MIME";
518 } else if ((res = expectSectionText(f_in)) != ACCEPT) {
519 session.setLastError("Expected MIME or section_text");
520 return res;
521 }
522 }
523 }
524 }
525
526 if ((res = expectThisString("]")) != ACCEPT) {
527 session.setLastError("Expected ]");
528 return res;
529 }
530
531 return ACCEPT;
532}
533
534//----------------------------------------------------------------------
537{
538 Session &session = Session::getInstance();
539
541 if ((res = expectThisString("(")) != ACCEPT)
542 return REJECT;
543
544 string header_fld_name;
545 while (1) {
546 if ((res = expectAstring(header_fld_name)) != ACCEPT) {
547 session.setLastError("Expected header_fld_name");
548 return res;
549 }
550
551 f_in.headerlist.push_back(header_fld_name);
552
553 if ((res = expectSPACE()) == ACCEPT) continue;
554 else break;
555 }
556
557 if ((res = expectThisString(")")) != ACCEPT) {
558 session.setLastError("Expected )");
559 return res;
560 }
561
562 return ACCEPT;
563}
564
565//----------------------------------------------------------------------
568{
569 Session &session = Session::getInstance();
571
572 if ((res = expectThisString("<")) != ACCEPT) return REJECT;
573
574 unsigned int i;
575 if ((res = expectNumber(i)) != ACCEPT) {
576 session.setLastError("Expected number");
577 return res;
578 }
579
580 if ((res = expectThisString(".")) != ACCEPT) {
581 session.setLastError("Expected .");
582 return res;
583 }
584
585 unsigned int j;
586 if ((res = expectNZNumber(j)) != ACCEPT) {
587 session.setLastError("expected nz_number");
588 return res;
589 }
590
591 if ((res = expectThisString(">")) != ACCEPT) {
592 session.setLastError("Expected >");
593 return res;
594 }
595
596 f_in.offsetstart = i;
597 f_in.offsetlength = j;
598 return ACCEPT;
599}
600
601//----------------------------------------------------------------------
604{
606
607 Session &session = Session::getInstance();
608
609 if ((res = expectThisString("ENVELOPE")) == ACCEPT) f_in.type = "ENVELOPE";
610 else if ((res = expectThisString("FLAGS")) == ACCEPT) f_in.type = "FLAGS";
611 else if ((res = expectThisString("INTERNALDATE")) == ACCEPT)
612 f_in.type = "INTERNALDATE";
613 else if ((res = expectThisString("UID")) == ACCEPT) f_in.type = "UID";
614 else if ((res = expectThisString("RFC822")) == ACCEPT) {
615 f_in.type = "RFC822";
616 if ((res = expectThisString(".HEADER")) == ACCEPT) f_in.type += ".HEADER";
617 else if ((res = expectThisString(".SIZE")) == ACCEPT) f_in.type += ".SIZE";
618 else if ((res = expectThisString(".TEXT")) == ACCEPT) f_in.type += ".TEXT";
619 else if ((res = expectThisString(".")) == ACCEPT) {
620 session.setLastError("Expected RFC822, RFC822.HEADER,"
621 " RFC822.SIZE or RFC822.TEXT");
622 return ERROR;
623 }
624
625 } else if ((res = expectThisString("BODY")) == ACCEPT) {
626 f_in.type = "BODY";
627
628 if ((res = expectThisString("STRUCTURE")) == ACCEPT) f_in.type += "STRUCTURE";
629 else if ((res = expectThisString(".PEEK")) == ACCEPT) f_in.type += ".PEEK";
630
631 if ((res = expectSection(f_in)) != ACCEPT)
632 f_in.hassection = false;
633 else {
634 f_in.hassection = true;
635 if ((res = expectOffset(f_in)) == ERROR) return ERROR;
636 }
637 } else
638 return REJECT;
639
640 return ACCEPT;
641}
std::vector< std::string > headerlist
Definition: imapparser.h:57
std::string toString(void)
Definition: imapparser.cc:328
const std::string & str(void) const
Definition: convert.cc:58
virtual Mailbox * getSelected(void) const
Definition: depot.cc:183
virtual ParseResult parse(Request &) const
ParseResult expectFetchAtt(BincImapParserFetchAtt &f_in) const
ParseResult expectSectionText(BincImapParserFetchAtt &f_in) const
int getState(void) const
ParseResult expectHeaderList(BincImapParserFetchAtt &f_in) const
ParseResult expectOffset(BincImapParserFetchAtt &f_in) const
ProcessResult process(Depot &, Request &)
ParseResult expectSection(BincImapParserFetchAtt &f_in) const
const std::string getName(void) const
unsigned int getSqnr() const
Definition: mailbox.cc:85
virtual void updateFlags(void)=0
virtual iterator begin(const SequenceSet &bset, unsigned int mod=INCLUDE_EXPUNGED|SQNR_MODE) const =0
virtual iterator end(void) const =0
@ SKIP_EXPUNGED
Definition: mailbox.h:69
The Message class provides an interface for IMAP messages.
Definition: message.h:31
virtual bool printEnvelope(void) const =0
virtual time_t getInternalDate(void) const =0
virtual unsigned int getUID(void) const =0
virtual unsigned int getBodySize(const std::string &section, unsigned int startOffset=0, unsigned int length=UINTMAX) const =0
virtual void setFlagsUnchanged(void)=0
virtual bool printDoc(unsigned int startOffset=0, unsigned int length=UINTMAX, bool onlyText=false) const =0
virtual bool printBody(const std::string &section, unsigned int startOffset=0, unsigned int length=UINTMAX) const =0
virtual bool printHeader(const std::string &section, std::vector< std::string > headers, bool includeHeaders=false, unsigned int startOffset=0, unsigned int length=UINTMAX, bool mime=false) const =0
virtual unsigned int getSize(bool render=false) const =0
virtual void setStdFlag(unsigned char)=0
virtual unsigned int getHeaderSize(const std::string &section, std::vector< std::string > headers, bool includeHeaders=false, unsigned int startOffset=0, unsigned int length=UINTMAX, bool mime=false) const =0
virtual unsigned char getStdFlags(void) const =0
virtual bool printBodyStructure(bool extended=true) const =0
virtual std::vector< std::string > getCustomFlags(void) const =0
virtual unsigned int getDocSize(unsigned int startOffset=0, unsigned int length=UINTMAX, bool onlyText=false) const =0
virtual bool hasFlagsChanged(void) const =0
std::vector< BincImapParserFetchAtt > fatt
Definition: imapparser.h:117
SequenceSet bset
Definition: imapparser.h:115
void setName(const std::string &s_in)
Definition: imapparser.cc:70
bool getUidMode(void) const
Definition: imapparser.cc:40
SequenceSet & getSet(void)
Definition: imapparser.cc:203
void setLastError(const std::string &error) const
Definition: session.cc:185
void addBody(void)
Definition: session.cc:88
static Session & getInstance(void)
Definition: session.cc:33
Declaration of miscellaneous convertion functions.
Declaration of the common items for parsing IMAP input.
Declaration of the IODevice class.
Declaration of the IOFactory class.
#define bincClient
Definition: iofactory.h:31
Declaration of the Mailbox class (Mailbox is logical container)
Definition: bincimapd.cc:9
Operator::ParseResult expectNumber(unsigned int &i_in)
std::string toImapString(const std::string &s_in)
Definition: convert.h:103
Operator::ParseResult expectAstring(std::string &s_in)
Operator::ParseResult expectSPACE(void)
Operator::ParseResult expectThisString(const std::string &s_in)
bool pendingUpdates(Mailbox *, int type, bool rescan, bool showAll=false, bool forceScan=false, bool uidfetchflags=false)
Operator::ParseResult expectNZNumber(unsigned int &i_in)
Operator::ParseResult expectSet(SequenceSet &s_in)
Operator::ParseResult expectCRLF(void)
Declaration of all operators.
Declaration of a recursive descent IMAP command parser.