operator-search.cc (29688B)
1 /* -*- Mode: c++; -*- */ 2 /* -------------------------------------------------------------------- 3 * Filename: 4 * operator-search.cc 5 * 6 * Description: 7 * Implementation of the SEARCH command. 8 * 9 * Authors: 10 * Andreas Aardal Hanssen <andreas-binc curly bincimap spot org> 11 * 12 * Bugs: 13 * 14 * ChangeLog: 15 * 16 * -------------------------------------------------------------------- 17 * Copyright 2002-2005 Andreas Aardal Hanssen 18 * 19 * This program is free software; you can redistribute it and/or modify 20 * it under the terms of the GNU General Public License as published by 21 * the Free Software Foundation; either version 2 of the License, or 22 * (at your option) any later version. 23 * 24 * This program is distributed in the hope that it will be useful, 25 * but WITHOUT ANY WARRANTY; without even the implied warranty of 26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 27 * GNU General Public License for more details. 28 * 29 * You should have received a copy of the GNU General Public License 30 * along with this program; if not, write to the Free Software 31 * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA. 32 * -------------------------------------------------------------------- 33 */ 34 #ifdef HAVE_CONFIG_H 35 #include <config.h> 36 #endif 37 38 #include <string> 39 #include <iostream> 40 #include <algorithm> 41 42 #include <ctype.h> 43 44 #include "imapparser.h" 45 #include "mailbox.h" 46 #include "mime.h" 47 #include "io.h" 48 #include "convert.h" 49 50 #include "recursivedescent.h" 51 52 #include "session.h" 53 #include "depot.h" 54 #include "operators.h" 55 56 using namespace ::std; 57 using namespace Binc; 58 59 //---------------------------------------------------------------------- 60 bool SearchOperator::SearchNode::convertDate(const string &date, 61 time_t &t, 62 const string &delim) 63 { 64 vector<string> parts; 65 split(date, delim, parts); 66 if (parts.size() < 3) return false; 67 68 struct tm mold; 69 memset((char *) &mold, 0, sizeof(struct tm)); 70 mold.tm_mday = atoi(parts[0].c_str()); 71 mold.tm_year = atoi(parts[2].c_str()) - 1900; 72 73 // accept mixed case months. this is more than the standard 74 // accepts. 75 string month = parts[1]; 76 lowercase(month); 77 78 if (month == "jan") mold.tm_mon = 0; 79 else if (month == "feb") mold.tm_mon = 1; 80 else if (month == "mar") mold.tm_mon = 2; 81 else if (month == "apr") mold.tm_mon = 3; 82 else if (month == "may") mold.tm_mon = 4; 83 else if (month == "jun") mold.tm_mon = 5; 84 else if (month == "jul") mold.tm_mon = 6; 85 else if (month == "aug") mold.tm_mon = 7; 86 else if (month == "sep") mold.tm_mon = 8; 87 else if (month == "oct") mold.tm_mon = 9; 88 else if (month == "nov") mold.tm_mon = 10; 89 else if (month == "dec") mold.tm_mon = 11; 90 91 t = mktime(&mold); 92 return true; 93 } 94 95 //---------------------------------------------------------------------- 96 bool SearchOperator::SearchNode::convertDateHeader(const string &d_in, 97 time_t &t) 98 { 99 string date = d_in; 100 string::size_type n = date.find(','); 101 if (n != string::npos) 102 date = date.substr(n + 1); 103 trim(date); 104 105 bool result = convertDate(date, t, " "); 106 return result; 107 } 108 109 //---------------------------------------------------------------------- 110 SearchOperator::SearchNode::SearchNode(void) 111 { 112 } 113 114 //---------------------------------------------------------------------- 115 SearchOperator::SearchNode::SearchNode(const BincImapParserSearchKey &a) 116 { 117 init(a); 118 } 119 120 //---------------------------------------------------------------------- 121 int SearchOperator::SearchNode::getType(void) const 122 { 123 return type; 124 } 125 126 //---------------------------------------------------------------------- 127 bool SearchOperator::SearchNode::match(Mailbox *mailbox, 128 Message *m, 129 unsigned int seqnr, 130 unsigned int lastmessage, 131 unsigned int lastuid) const 132 { 133 HeaderItem hitem; 134 string tmp; 135 136 switch (type) { 137 //-------------------------------------------------------------------- 138 case S_ALL: 139 return true; 140 //-------------------------------------------------------------------- 141 case S_ANSWERED: 142 return (m->getStdFlags() & Message::F_ANSWERED); 143 //-------------------------------------------------------------------- 144 case S_BCC: 145 return m->headerContains("bcc", astring); 146 //-------------------------------------------------------------------- 147 case S_BEFORE: { 148 time_t mtime = m->getInternalDate(); 149 struct tm *mtime_ = localtime(&mtime); 150 mtime_->tm_sec = 0; 151 mtime_->tm_min = 0; 152 mtime_->tm_hour = 0; 153 mtime_->tm_wday = 0; 154 mtime_->tm_yday = 0; 155 mtime_->tm_isdst = 0; 156 mtime = mktime(mtime_); 157 158 time_t atime; 159 if (!convertDate(date, atime)) { 160 IO &logger = IOFactory::getInstance().get(2); 161 162 logger << "warning, unable to convert " << date << 163 " to a time_t" << endl; 164 return false; 165 } 166 167 return mtime < atime; 168 } //-------------------------------------------------------------------- 169 case S_BODY: 170 return m->bodyContains(astring); 171 //-------------------------------------------------------------------- 172 case S_CC: 173 return m->headerContains("cc", astring); 174 //-------------------------------------------------------------------- 175 case S_DELETED: 176 return (m->getStdFlags() & Message::F_DELETED); 177 //-------------------------------------------------------------------- 178 case S_FLAGGED: 179 return (m->getStdFlags() & Message::F_FLAGGED); 180 //-------------------------------------------------------------------- 181 case S_FROM: 182 return m->headerContains("from", astring); 183 //-------------------------------------------------------------------- 184 case S_KEYWORD: 185 // the server does not support keywords 186 return false; 187 //-------------------------------------------------------------------- 188 case S_NEW: 189 return (m->getStdFlags() & Message::F_RECENT) 190 && !(m->getStdFlags() & Message::F_SEEN); 191 //-------------------------------------------------------------------- 192 case S_OLD: 193 return !(m->getStdFlags() & Message::F_RECENT); 194 //-------------------------------------------------------------------- 195 case S_ON: { 196 time_t mtime = m->getInternalDate(); 197 struct tm *mtime_ = localtime(&mtime); 198 mtime_->tm_sec = 0; 199 mtime_->tm_min = 0; 200 mtime_->tm_hour = 0; 201 mtime_->tm_wday = 0; 202 mtime_->tm_yday = 0; 203 mtime_->tm_isdst = 0; 204 mtime = mktime(mtime_); 205 206 time_t atime; 207 if (!convertDate(date, atime)) { 208 IO &logger = IOFactory::getInstance().get(2); 209 210 logger << "warning, unable to convert " << date << 211 " to a time_t" << endl; 212 return false; 213 } 214 215 return mtime == atime; 216 } //-------------------------------------------------------------------- 217 case S_RECENT: 218 return (m->getStdFlags() & Message::F_RECENT); 219 //-------------------------------------------------------------------- 220 case S_SEEN: 221 return (m->getStdFlags() & Message::F_SEEN); 222 //-------------------------------------------------------------------- 223 case S_SINCE: { 224 time_t mtime = m->getInternalDate(); 225 struct tm *mtime_ = localtime(&mtime); 226 mtime_->tm_sec = 0; 227 mtime_->tm_min = 0; 228 mtime_->tm_hour = 0; 229 mtime_->tm_wday = 0; 230 mtime_->tm_yday = 0; 231 mtime_->tm_isdst = 0; 232 mtime = mktime(mtime_); 233 234 time_t atime; 235 if (!convertDate(date, atime)) { 236 IO &logger = IOFactory::getInstance().get(2); 237 238 logger << "warning, unable to convert " << date << 239 " to a time_t" << endl; 240 return false; 241 } 242 243 return mtime >= atime; 244 } //-------------------------------------------------------------------- 245 case S_SUBJECT: 246 return m->headerContains("subject", astring); 247 //-------------------------------------------------------------------- 248 case S_TEXT: 249 return m->textContains(astring); 250 //-------------------------------------------------------------------- 251 case S_TO: 252 return m->headerContains("to", astring); 253 //-------------------------------------------------------------------- 254 case S_UNANSWERED: 255 return !(m->getStdFlags() & Message::F_ANSWERED); 256 //-------------------------------------------------------------------- 257 case S_UNDELETED: 258 return !(m->getStdFlags() & Message::F_DELETED); 259 //-------------------------------------------------------------------- 260 case S_UNFLAGGED: 261 return !(m->getStdFlags() & Message::F_FLAGGED); 262 //-------------------------------------------------------------------- 263 case S_UNKEYWORD: 264 // the server does not support keywords 265 return true; 266 //-------------------------------------------------------------------- 267 case S_UNSEEN: 268 return !(m->getStdFlags() & Message::F_SEEN); 269 //-------------------------------------------------------------------- 270 case S_DRAFT: 271 return (m->getStdFlags() & Message::F_DRAFT); 272 //-------------------------------------------------------------------- 273 case S_HEADER: 274 return m->headerContains(astring, bstring); 275 //-------------------------------------------------------------------- 276 case S_LARGER: { 277 return (m->getSize(true) > number); 278 } 279 //-------------------------------------------------------------------- 280 case S_NOT: 281 for (vector<SearchNode>::const_iterator i = children.begin(); 282 i != children.end(); ++i) 283 if ((*i).match(mailbox, m, seqnr, lastmessage, lastuid)) 284 return false; 285 return true; 286 //-------------------------------------------------------------------- 287 case S_OR: 288 for (vector<SearchNode>::const_iterator i = children.begin(); 289 i != children.end(); ++i) 290 if ((*i).match(mailbox, m, seqnr, lastmessage, lastuid)) 291 return true; 292 return false; 293 //-------------------------------------------------------------------- 294 case S_SENTBEFORE: { 295 string tmp = m->getHeader("date"); 296 if (tmp == "") 297 return false; 298 299 lowercase(tmp); 300 301 time_t mtime; 302 if (!convertDateHeader(tmp, mtime)) 303 return false; 304 305 if (mtime == (time_t) -1) 306 return false; 307 308 time_t atime; 309 if (!convertDate(date, atime)) { 310 IO &logger = IOFactory::getInstance().get(2); 311 312 logger << "warning, unable to convert " << date << 313 " to a time_t" << endl; 314 return false; 315 } 316 317 return mtime < atime; 318 } //-------------------------------------------------------------------- 319 case S_SENTON: { 320 string tmp = m->getHeader("date"); 321 if (tmp == "") 322 return false; 323 324 lowercase(tmp); 325 326 time_t mtime; 327 if (!convertDateHeader(tmp, mtime)) 328 return false; 329 330 if (mtime == (time_t) -1) 331 return false; 332 333 time_t atime; 334 if (!convertDate(date, atime)) { 335 IO &logger = IOFactory::getInstance().get(2); 336 337 logger << "warning, unable to convert " << date << 338 " to a time_t" << endl; 339 return false; 340 } 341 342 return mtime == atime; 343 } //-------------------------------------------------------------------- 344 case S_SENTSINCE: { 345 string tmp = m->getHeader("date"); 346 if (tmp == "") 347 return false; 348 349 lowercase(tmp); 350 351 time_t mtime; 352 if (!convertDateHeader(tmp, mtime)) 353 return false; 354 355 if (mtime == (time_t) -1) 356 return false; 357 358 time_t atime; 359 if (!convertDate(date, atime)) { 360 IO &logger = IOFactory::getInstance().get(2); 361 362 logger << "warning, unable to convert " << date << 363 " to a time_t" << endl; 364 return false; 365 } 366 367 return mtime >= atime; 368 } //-------------------------------------------------------------------- 369 case S_SMALLER: 370 return (m->getSize(true) < number); 371 //-------------------------------------------------------------------- 372 case S_UID: 373 if (!bset->isInSet(m->getUID())) 374 if (!(m->getUID() == lastuid && !bset->isLimited())) 375 return false; 376 return true; 377 //-------------------------------------------------------------------- 378 case S_UNDRAFT: 379 return !(m->getStdFlags() & Message::F_DRAFT); 380 //-------------------------------------------------------------------- 381 case S_SET: 382 if (!bset->isInSet(seqnr)) 383 if (!(seqnr == lastmessage && !bset->isLimited())) 384 return false; 385 return true; 386 //-------------------------------------------------------------------- 387 case S_AND: 388 for (vector<SearchNode>::const_iterator i = children.begin(); 389 i != children.end(); ++i) 390 if (!(*i).match(mailbox, m, seqnr, lastmessage, lastuid)) 391 return false; 392 return true; 393 } 394 395 return false; 396 } 397 398 //---------------------------------------------------------------------- 399 void SearchOperator::SearchNode::init(const BincImapParserSearchKey &a) 400 { 401 astring = a.astring; 402 bstring = a.bstring; 403 date = a.date; 404 number = a.number; 405 uppercase(astring); 406 uppercase(bstring); 407 uppercase(date); 408 409 if (a.name == "ALL") { type = S_ALL; weight = 1; } 410 else if (a.name == "ANSWERED") { type = S_ANSWERED; weight = 1; } 411 else if (a.name == "BCC") { type = S_BCC; weight = 2; } 412 else if (a.name == "BEFORE") { type = S_BEFORE; weight = 2; } 413 else if (a.name == "BODY") { type = S_BODY; weight = 1; } 414 else if (a.name == "CC") { type = S_CC; weight = 2; } 415 else if (a.name == "DELETED") { type = S_DELETED; weight = 1; } 416 else if (a.name == "FLAGGED") { type = S_FLAGGED; weight = 1; } 417 else if (a.name == "FROM") { type = S_FROM; weight = 2; } 418 else if (a.name == "KEYWORD") { type = S_KEYWORD; weight = 3; } 419 else if (a.name == "NEW") { type = S_NEW; weight = 1; } 420 else if (a.name == "OLD") { type = S_OLD; weight = 1; } 421 else if (a.name == "ON") { type = S_ON; weight = 1; } 422 else if (a.name == "RECENT") { type = S_RECENT; weight = 1; } 423 else if (a.name == "SEEN") { type = S_SEEN; weight = 1; } 424 else if (a.name == "SINCE") { type = S_SINCE; weight = 1; } 425 else if (a.name == "SUBJECT") { type = S_SUBJECT; weight = 2; } 426 else if (a.name == "TEXT") { type = S_TEXT; weight = 4; } 427 else if (a.name == "TO") { type = S_TO; weight = 2; } 428 else if (a.name == "UNANSWERED") { type = S_UNANSWERED; weight = 1; } 429 else if (a.name == "UNDELETED") { type = S_UNDELETED; weight = 1; } 430 else if (a.name == "UNFLAGGED") { type = S_UNFLAGGED; weight = 1; } 431 else if (a.name == "UNKEYWORD") { type = S_UNKEYWORD; weight = 1; } 432 else if (a.name == "UNSEEN") { type = S_UNSEEN; weight = 1; } 433 else if (a.name == "DRAFT") { type = S_DRAFT; weight = 1; } 434 else if (a.name == "HEADER") { type = S_HEADER; weight = 3; } 435 else if (a.name == "LARGER") { type = S_LARGER; weight = 4; } 436 else if (a.name == "NOT") { 437 // ******* NOT 438 type = S_NOT; 439 weight = 1; 440 441 vector<BincImapParserSearchKey>::const_iterator i = a.children.begin(); 442 while (i != a.children.end()) { 443 SearchNode b(*i); 444 weight += b.getWeight(); 445 children.push_back(b); 446 ++i; 447 } 448 449 } else if (a.name == "OR") { 450 // ******* OR 451 type = S_OR; 452 weight = 0; 453 454 vector<BincImapParserSearchKey>::const_iterator i = a.children.begin(); 455 while (i != a.children.end()) { 456 SearchNode b(*i); 457 weight += b.getWeight(); 458 459 children.push_back(b); 460 ++i; 461 } 462 463 } else if (a.name == "SENTBEFORE") { type = S_SENTBEFORE; weight = 1; } 464 else if (a.name == "SENTON") { type = S_SENTON; weight = 1; } 465 else if (a.name == "SENTSINCE") { type = S_SENTSINCE; weight = 1; } 466 else if (a.name == "SMALLER") { type = S_SMALLER; weight = 4; } 467 else if (a.name == "UID") { 468 bset = &a.getSet(); 469 type = S_UID; 470 weight = 1; 471 } else if (a.name == "UNDRAFT") { type = S_UNDRAFT; weight = 1; } 472 else if (a.type == BincImapParserSearchKey::KEY_SET) { 473 bset = &a.getSet(); 474 type = S_SET; 475 weight = 1; 476 } else if (a.type == BincImapParserSearchKey::KEY_AND) { 477 // ******* AND 478 type = S_AND; 479 weight = 0; 480 481 vector<BincImapParserSearchKey>::const_iterator i = a.children.begin(); 482 while (i != a.children.end()) { 483 SearchNode b(*i); 484 weight += b.getWeight(); 485 children.push_back(b); 486 ++i; 487 } 488 } 489 } 490 491 //---------------------------------------------------------------------- 492 int SearchOperator::SearchNode::getWeight(void) const 493 { 494 return weight; 495 } 496 497 //---------------------------------------------------------------------- 498 void SearchOperator::SearchNode::setWeight(int i) 499 { 500 weight = i; 501 } 502 503 //---------------------------------------------------------------------- 504 void SearchOperator::SearchNode::order(void) 505 { 506 for (vector<SearchNode>::iterator i = children.begin(); 507 i != children.end(); ++i) 508 (*i).order(); 509 ::stable_sort(children.begin(), children.end(), compareNodes); 510 } 511 512 //---------------------------------------------------------------------- 513 SearchOperator::SearchOperator(void) 514 { 515 } 516 517 //---------------------------------------------------------------------- 518 SearchOperator::~SearchOperator(void) 519 { 520 } 521 522 //---------------------------------------------------------------------- 523 const string SearchOperator::getName(void) const 524 { 525 return "SEARCH"; 526 } 527 528 //---------------------------------------------------------------------- 529 int SearchOperator::getState(void) const 530 { 531 return Session::SELECTED; 532 } 533 534 //------------------------------------------------------------------------ 535 Operator::ProcessResult SearchOperator::process(Depot &depot, 536 Request &command) 537 { 538 IO &com = IOFactory::getInstance().get(1); 539 Session &session = Session::getInstance(); 540 541 Mailbox *mailbox = depot.getSelected(); 542 543 if (command.getCharSet() != "" && command.getCharSet() != "US-ASCII") { 544 session.setResponseCode("BADCHARSET (\"US-ASCII\")"); 545 return NO; 546 } 547 548 com << "* SEARCH"; 549 550 SearchNode s(command.searchkey); 551 s.order(); 552 553 const unsigned int maxsqnr = mailbox->getMaxSqnr(); 554 const unsigned int maxuid = mailbox->getMaxUid(); 555 556 Mailbox::iterator i 557 = mailbox->begin(SequenceSet::all(), Mailbox::SKIP_EXPUNGED); 558 for (; i != mailbox->end(); ++i) { 559 Message &message = *i; 560 561 if (s.match(mailbox, &message, i.getSqnr(), maxsqnr, maxuid)) { 562 com << " " << (command.getUidMode() ? message.getUID() : i.getSqnr()); 563 com.flushContent(); 564 } 565 566 message.close(); 567 } 568 569 com << endl; 570 return OK; 571 } 572 573 //------------------------------------------------------------------------ 574 Operator::ParseResult SearchOperator::parse(Request & c_in) const 575 { 576 Session &session = Session::getInstance(); 577 578 Operator::ParseResult res; 579 if ((res = expectSPACE()) != ACCEPT) { 580 session.setLastError("Expected SPACE"); 581 return res; 582 } 583 584 if ((res = expectThisString("CHARSET")) == ACCEPT) { 585 if ((res = expectSPACE()) != ACCEPT) { 586 session.setLastError("Expected SPACE after CHARSET"); 587 return res; 588 } 589 590 string charset; 591 if ((res = expectAstring(charset)) != ACCEPT) { 592 session.setLastError("Expected astring after CHARSET SPACE"); 593 return res; 594 } 595 596 c_in.setCharSet(charset); 597 598 if ((res = expectSPACE()) != ACCEPT) { 599 session.setLastError("Expected SPACE after CHARSET SPACE astring"); 600 return res; 601 } 602 } 603 604 BincImapParserSearchKey b; 605 if ((res = expectSearchKey(b)) != ACCEPT) { 606 session.setLastError("Expected search_key"); 607 return res; 608 } 609 610 c_in.searchkey.type = BincImapParserSearchKey::KEY_AND; 611 c_in.searchkey.children.push_back(b); 612 613 while (1) { 614 if ((res = expectSPACE()) != ACCEPT) 615 break; 616 617 BincImapParserSearchKey c; 618 if ((res = expectSearchKey(c)) != ACCEPT) { 619 session.setLastError("Expected search_key after search_key SPACE"); 620 return res; 621 } 622 623 c_in.searchkey.children.push_back(c); 624 } 625 626 if ((res = expectCRLF()) != ACCEPT) { 627 session.setLastError("Expected CRLF after search_key"); 628 return res; 629 } 630 631 c_in.setName("SEARCH"); 632 return ACCEPT; 633 } 634 635 //---------------------------------------------------------------------- 636 Operator::ParseResult 637 SearchOperator::expectSearchKey(BincImapParserSearchKey &s_in) const 638 { 639 Session &session = Session::getInstance(); 640 Operator::ParseResult res; 641 642 s_in.type = BincImapParserSearchKey::KEY_OTHER; 643 if ((res = expectThisString("ALL")) == ACCEPT) s_in.name = "ALL"; 644 else if ((res = expectThisString("ANSWERED")) == ACCEPT) s_in.name = "ANSWERED"; 645 else if ((res = expectThisString("BCC")) == ACCEPT) { 646 s_in.name = "BCC"; 647 if ((res = expectSPACE()) != ACCEPT) { 648 session.setLastError("Expected SPACE"); 649 return res; 650 } 651 652 if ((res = expectAstring(s_in.astring)) != ACCEPT) { 653 session.setLastError("Expected astring"); 654 return res; 655 } 656 } else if ((res = expectThisString("BEFORE")) == ACCEPT) { 657 s_in.name = "BEFORE"; 658 659 if ((res = expectSPACE()) != ACCEPT) { 660 session.setLastError("Expected SPACE"); 661 return res; 662 } 663 664 if ((res = expectDate(s_in.date)) != ACCEPT) { 665 session.setLastError("Expected date"); 666 return res; 667 } 668 } else if ((res = expectThisString("BODY")) == ACCEPT) { 669 s_in.name = "BODY"; 670 if ((res = expectSPACE()) != ACCEPT) { 671 session.setLastError("Expected SPACE"); 672 return res; 673 } 674 675 if ((res = expectAstring(s_in.astring)) != ACCEPT) { 676 session.setLastError("Expected astring"); 677 return res; 678 } 679 } else if ((res = expectThisString("CC")) == ACCEPT) { 680 s_in.name = "CC"; 681 if ((res = expectSPACE()) != ACCEPT) { 682 session.setLastError("Expected SPACE"); 683 return res; 684 } 685 686 if ((res = expectAstring(s_in.astring)) != ACCEPT) { 687 session.setLastError("Expected astring"); 688 return res; 689 } 690 } else if ((res = expectThisString("DELETED")) == ACCEPT) s_in.name = "DELETED"; 691 else if ((res = expectThisString("FLAGGED")) == ACCEPT) s_in.name = "FLAGGED"; 692 else if ((res = expectThisString("FROM")) == ACCEPT) { 693 s_in.name = "FROM"; 694 if ((res = expectSPACE()) != ACCEPT) { 695 session.setLastError("Expected SPACE"); 696 return res; 697 } 698 699 if ((res = expectAstring(s_in.astring)) != ACCEPT) { 700 session.setLastError("Expected astring"); 701 return res; 702 } 703 } else if ((res = expectThisString("KEYWORD")) == ACCEPT) { 704 s_in.name = "KEYWORD"; 705 if ((res = expectSPACE()) != ACCEPT) { 706 session.setLastError("Expected SPACE"); 707 return res; 708 } 709 710 if ((res = expectAtom(s_in.astring)) != ACCEPT) { 711 session.setLastError("Expected flag_keyword"); 712 return res; 713 } 714 } else if ((res = expectThisString("NEW")) == ACCEPT) s_in.name = "NEW"; 715 else if ((res = expectThisString("OLD")) == ACCEPT) s_in.name = "OLD"; 716 else if ((res = expectThisString("ON")) == ACCEPT) { 717 s_in.name = "ON"; 718 719 if ((res = expectSPACE()) != ACCEPT) { 720 session.setLastError("Expected SPACE"); 721 return res; 722 } 723 724 if ((res = expectDate(s_in.date)) != ACCEPT) { 725 session.setLastError("Expected date"); 726 return res; 727 } 728 } else if ((res = expectThisString("RECENT")) == ACCEPT) s_in.name = "RECENT"; 729 else if ((res = expectThisString("SEEN")) == ACCEPT) s_in.name = "SEEN"; 730 else if ((res = expectThisString("SINCE")) == ACCEPT) { 731 s_in.name = "SINCE"; 732 733 if ((res = expectSPACE()) != ACCEPT) { 734 session.setLastError("Expected SPACE"); 735 return res; 736 } 737 738 if ((res = expectDate(s_in.date)) != ACCEPT) { 739 session.setLastError("Expected date"); 740 return res; 741 } 742 } else if ((res = expectThisString("SUBJECT")) == ACCEPT) { 743 s_in.name = "SUBJECT"; 744 if ((res = expectSPACE()) != ACCEPT) { 745 session.setLastError("Expected SPACE"); 746 return res; 747 } 748 749 if ((res = expectAstring(s_in.astring)) != ACCEPT) { 750 session.setLastError("Expected astring"); 751 return res; 752 } 753 } else if ((res = expectThisString("TEXT")) == ACCEPT) { 754 s_in.name = "TEXT"; 755 if ((res = expectSPACE()) != ACCEPT) { 756 session.setLastError("Expected SPACE"); 757 return res; 758 } 759 760 if ((res = expectAstring(s_in.astring)) != ACCEPT) { 761 session.setLastError("Expected astring"); 762 return res; 763 } 764 } else if ((res = expectThisString("TO")) == ACCEPT) { 765 s_in.name = "TO"; 766 if ((res = expectSPACE()) != ACCEPT) { 767 session.setLastError("Expected SPACE"); 768 return res; 769 } 770 771 if ((res = expectAstring(s_in.astring)) != ACCEPT) { 772 session.setLastError("Expected astring"); 773 return res; 774 } 775 } else if ((res = expectThisString("UNANSWERED")) == ACCEPT) 776 s_in.name = "UNANSWERED"; 777 else if ((res = expectThisString("UNDELETED")) == ACCEPT) s_in.name = "UNDELETED"; 778 else if ((res = expectThisString("UNFLAGGED")) == ACCEPT) s_in.name = "UNFLAGGED"; 779 else if ((res = expectThisString("UNKEYWORD")) == ACCEPT) { 780 s_in.name = "UNKEYWORD"; 781 if ((res = expectSPACE()) != ACCEPT) { 782 session.setLastError("Expected SPACE"); 783 return res; 784 } 785 786 if ((res = expectAtom(s_in.astring)) != ACCEPT) { 787 session.setLastError("Expected flag_keyword"); 788 return res; 789 } 790 } else if ((res = expectThisString("UNSEEN")) == ACCEPT) s_in.name = "UNSEEN"; 791 else if ((res = expectThisString("DRAFT")) == ACCEPT) s_in.name = "DRAFT"; 792 else if ((res = expectThisString("HEADER")) == ACCEPT) { 793 s_in.name = "HEADER"; 794 795 if ((res = expectSPACE()) != ACCEPT) { 796 session.setLastError("Expected SPACE"); 797 return res; 798 } 799 800 if ((res = expectAstring(s_in.astring)) != ACCEPT) { 801 session.setLastError("Expected astring"); 802 return res; 803 } 804 805 if ((res = expectSPACE()) != ACCEPT) { 806 session.setLastError("Expected SPACE"); 807 return res; 808 } 809 810 if ((res = expectAstring(s_in.bstring)) != ACCEPT) { 811 session.setLastError("Expected astring"); 812 return res; 813 } 814 } else if ((res = expectThisString("LARGER")) == ACCEPT) { 815 s_in.name = "LARGER"; 816 if ((res = expectSPACE()) != ACCEPT) { 817 session.setLastError("Expected SPACE"); 818 return res; 819 } 820 821 if ((res = expectNumber(s_in.number)) != ACCEPT) { 822 session.setLastError("Expected number"); 823 return res; 824 } 825 } else if ((res = expectThisString("NOT")) == ACCEPT) { 826 s_in.name = "NOT"; 827 s_in.type = BincImapParserSearchKey::KEY_NOT; 828 829 if ((res = expectSPACE()) != ACCEPT) { 830 session.setLastError("Expected SPACE"); 831 return res; 832 } 833 834 BincImapParserSearchKey s; 835 if ((res = expectSearchKey(s)) != ACCEPT) { 836 session.setLastError("Expected search_key"); 837 return res; 838 } 839 s_in.children.push_back(s); 840 } else if ((res = expectThisString("OR")) == ACCEPT) { 841 s_in.name = "OR"; 842 s_in.type = BincImapParserSearchKey::KEY_OR; 843 844 if ((res = expectSPACE()) != ACCEPT) { 845 session.setLastError("Expected SPACE"); 846 return res; 847 } 848 849 BincImapParserSearchKey s; 850 if ((res = expectSearchKey(s)) != ACCEPT) { 851 session.setLastError("Expected search_key"); 852 return res; 853 } 854 s_in.children.push_back(s); 855 856 if ((res = expectSPACE()) != ACCEPT) { 857 session.setLastError("Expected SPACE"); 858 return res; 859 } 860 861 BincImapParserSearchKey t; 862 if ((res = expectSearchKey(t)) != ACCEPT) { 863 session.setLastError("Expected search_key"); 864 return res; 865 } 866 s_in.children.push_back(t); 867 } else if ((res = expectThisString("SENTBEFORE")) == ACCEPT) { 868 s_in.name = "SENTBEFORE"; 869 870 if ((res = expectSPACE()) != ACCEPT) { 871 session.setLastError("Expected SPACE"); 872 return res; 873 } 874 875 if ((res = expectDate(s_in.date)) != ACCEPT) { 876 session.setLastError("Expected date"); 877 return res; 878 } 879 } else if ((res = expectThisString("SENTON")) == ACCEPT) { 880 s_in.name = "SENTON"; 881 882 if ((res = expectSPACE()) != ACCEPT) { 883 session.setLastError("Expected SPACE"); 884 return res; 885 } 886 887 if ((res = expectDate(s_in.date)) != ACCEPT) { 888 session.setLastError("Expected date"); 889 return res; 890 } 891 892 } else if ((res = expectThisString("SENTSINCE")) == ACCEPT) { 893 s_in.name = "SENTSINCE"; 894 895 if ((res = expectSPACE()) != ACCEPT) { 896 session.setLastError("Expected SPACE"); 897 return res; 898 } 899 900 if ((res = expectDate(s_in.date)) != ACCEPT) { 901 session.setLastError("Expected date"); 902 return res; 903 } 904 } else if ((res = expectThisString("SMALLER")) == ACCEPT) { 905 s_in.name = "SMALLER"; 906 if ((res = expectSPACE()) != ACCEPT) { 907 session.setLastError("Expected SPACE"); 908 return res; 909 } 910 911 if ((res = expectNumber(s_in.number)) != ACCEPT) { 912 session.setLastError("Expected number"); 913 return res; 914 } 915 } else if ((res = expectThisString("UID")) == ACCEPT) { 916 s_in.name = "UID"; 917 if ((res = expectSPACE()) != ACCEPT) { 918 session.setLastError("Expected SPACE"); 919 return res; 920 } 921 922 if ((res = expectSet(s_in.bset)) != ACCEPT) { 923 session.setLastError("Expected number"); 924 return res; 925 } 926 } else if ((res = expectThisString("UNDRAFT")) == ACCEPT) s_in.name = "UNDRAFT"; 927 else if ((res = expectSet(s_in.bset)) == ACCEPT) { 928 s_in.name = ""; 929 s_in.type = BincImapParserSearchKey::KEY_SET; 930 } else if ((res = expectThisString("(")) == ACCEPT) { 931 s_in.type = BincImapParserSearchKey::KEY_AND; 932 933 while (1) { 934 BincImapParserSearchKey c; 935 if ((res = expectSearchKey(c)) != ACCEPT) { 936 session.setLastError("Expected search_key"); 937 return res; 938 } 939 940 s_in.children.push_back(c); 941 942 if ((res = expectSPACE()) != ACCEPT) 943 break; 944 } 945 946 if ((res = expectThisString(")")) != ACCEPT) { 947 session.setLastError("Expected )"); 948 return res; 949 } 950 } else 951 return REJECT; 952 953 return ACCEPT; 954 }