maildirmessage.cc (27315B)
1 /* -*- Mode: c++; -*- */ 2 /* -------------------------------------------------------------------- 3 * Filename: 4 * maildirmessage.cc 5 * 6 * Description: 7 * Implementation of the MaildirMessage class. 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 40 #include <stack> 41 #include <fcntl.h> 42 #include <unistd.h> 43 #include <ctype.h> 44 #include <time.h> 45 #include <utime.h> 46 47 #include "maildir.h" 48 #include "maildirmessage.h" 49 #include "convert.h" 50 #include "mime.h" 51 #include "io.h" 52 #include "mime-utils.h" 53 54 using namespace ::std; 55 using namespace Binc; 56 57 string Message::lastError; 58 string MaildirMessage::storage; 59 60 namespace { 61 //---------------------------------------------------------------------- 62 void printOneHeader(IO &io, const MimePart *message, const string &s_in, 63 bool removecomments = true) 64 { 65 string tmp = ""; 66 HeaderItem hitem; 67 68 if (message->h.getFirstHeader(s_in, hitem)) { 69 tmp = hitem.getValue(); 70 io << toImapString(unfold(tmp, removecomments)); 71 } else 72 io << "NIL"; 73 } 74 75 //---------------------------------------------------------------------- 76 void printOneAddressList(IO &io, const MimePart *message, 77 const string &s_in, bool removecomments = true) 78 { 79 string tmp = ""; 80 HeaderItem hitem; 81 82 if (message->h.getFirstHeader(s_in, hitem)) { 83 tmp = hitem.getValue(); 84 vector<string> addr; 85 splitAddr(unfold(tmp, removecomments), addr); 86 if (addr.size() != 0) { 87 io << "("; 88 for (vector<string>::const_iterator i = addr.begin(); 89 i != addr.end(); ++i) 90 io << Address(*i).toParenList(); 91 io << ")"; 92 } else io << "NIL"; 93 } else 94 io << "NIL"; 95 } 96 97 //---------------------------------------------------------------------- 98 void envelope(IO &io, const MimePart *message) 99 { 100 HeaderItem hitem; 101 io << "("; 102 printOneHeader(io, message, "date"); 103 io << " "; 104 printOneHeader(io, message, "subject", false); 105 io << " "; 106 printOneAddressList(io, message, "from", false); 107 io << " "; 108 printOneAddressList(io, message, 109 message->h.getFirstHeader("sender", hitem) 110 ? "sender" : "from", false); 111 io << " "; 112 printOneAddressList(io, message, 113 message->h.getFirstHeader("reply-to", hitem) 114 ? "reply-to" : "from", false); 115 io << " "; 116 printOneAddressList(io, message, "to", false); 117 io << " "; 118 printOneAddressList(io, message, "cc", false); 119 io << " "; 120 printOneAddressList(io, message, "bcc", false); 121 io << " "; 122 printOneHeader(io, message, "in-reply-to"); 123 io << " "; 124 printOneHeader(io, message, "message-id"); 125 io << ")"; 126 } 127 128 //---------------------------------------------------------------------- 129 void bodyStructure(IO &io, const MimePart *message, bool extended) 130 { 131 HeaderItem hitem; 132 if (message->isMultipart() && message->members.size() > 0) { 133 io << "("; 134 135 for (vector<MimePart>::const_iterator i = message->members.begin(); 136 i != message->members.end(); ++i) 137 bodyStructure(io, &(*i), extended); 138 139 io << " "; 140 io << toImapString(message->getSubType()); 141 142 if (extended) { 143 io << " "; 144 145 vector<string> parameters; 146 vector<string> headers; 147 string tmp; 148 149 string type, subtype; 150 151 tmp = ""; 152 if (message->h.getFirstHeader("content-type", hitem)) { 153 tmp = unfold(hitem.getValue()); 154 trim(tmp); 155 156 vector<string> v; 157 split(tmp, ";", v); 158 159 for (vector<string>::const_iterator i = v.begin(); i != v.end(); ++i) { 160 string element = *i; 161 trim(element); 162 if (element.find('=') != string::npos) { 163 string::size_type pos = element.find('='); 164 string s = element.substr(0, pos); 165 string t = element.substr(pos + 1); 166 trim(s, " \""); 167 trim(t, " \""); 168 parameters.push_back(s); 169 parameters.push_back(t); 170 } 171 } 172 173 if (parameters.size() != 0) { 174 io << "("; 175 for (vector<string>::const_iterator i = parameters.begin(); 176 i != parameters.end(); ++i) { 177 if (i != parameters.begin()) 178 io << " "; 179 io << toImapString(*i); 180 } 181 io << ")"; 182 } else 183 io << "NIL"; 184 } else 185 io << "NIL"; 186 187 // CONTENT-DISPOSITION 188 io << " "; 189 tmp = ""; 190 if (message->h.getFirstHeader("content-disposition", hitem)) { 191 tmp = hitem.getValue(); 192 trim(tmp); 193 194 vector<string> v; 195 split(tmp, ";", v); 196 if (v.size() > 0) { 197 string disp = v[0]; 198 trim(disp); 199 io << "(" << toImapString(disp); 200 io << " "; 201 if (v.size() > 1) { 202 io << "("; 203 vector<string>::const_iterator i = v.begin(); 204 ++i; 205 bool wrote = false; 206 while (i != v.end()) { 207 string s = *i; 208 trim(s); 209 210 string::size_type pos = s.find('='); 211 string key = s.substr(0, pos); 212 string value = s.substr(pos + 1); 213 trim(key); 214 trim(value); 215 216 trim(key, " \""); 217 trim(value, " \""); 218 219 if (!wrote) wrote = true; 220 else io << " "; 221 io << toImapString(key); 222 223 io << " "; 224 io << toImapString(value); 225 226 ++i; 227 } 228 io << ")"; 229 } else 230 io << "NIL"; 231 io << ")"; 232 } else 233 io << "NIL"; 234 } else 235 io << "NIL"; 236 237 // CONTENT-LANGUAGE 238 io << " "; 239 printOneHeader(io, message, "content-language"); 240 } 241 242 io << ")"; 243 } else { 244 io << "("; 245 246 vector<string> parameters; 247 vector<string> headers; 248 string tmp; 249 tmp = ""; 250 string type, subtype; 251 252 tmp = ""; 253 if (message->h.getFirstHeader("content-type", hitem)) { 254 tmp = unfold(hitem.getValue()); 255 256 vector<string> v; 257 split(tmp, ";", v); 258 259 if (v.size() > 0) { 260 vector<string> b; 261 split(v[0], "/", b); 262 263 if (b.size() > 0) 264 type = b[0]; 265 else 266 type = "text"; 267 268 if (b.size() > 1) 269 subtype = b[1]; 270 else 271 subtype = "plain"; 272 } 273 274 for (vector<string>::const_iterator i = v.begin(); i != v.end(); ++i) { 275 if (i == v.begin()) continue; 276 277 string element = *i; 278 trim(element); 279 280 if (element.find('=') != string::npos) { 281 string::size_type pos = element.find('='); 282 string s = element.substr(0, pos); 283 string t = element.substr(pos + 1); 284 trim(s, " \""); 285 trim(t, " \""); 286 parameters.push_back(s); 287 parameters.push_back(t); 288 } 289 } 290 } else { 291 type = "text"; 292 subtype = "plain"; 293 } 294 295 io << toImapString(type); 296 io << " "; 297 io << toImapString(subtype); 298 299 io << " "; 300 if (parameters.size() != 0) { 301 io << "("; 302 for (vector<string>::const_iterator i = parameters.begin(); 303 i != parameters.end(); ++i) { 304 if (i != parameters.begin()) 305 io << " "; 306 io << toImapString(*i); 307 } 308 io << ")"; 309 } else 310 io << "NIL"; 311 312 // CONTENT-ID 313 io << " "; 314 printOneHeader(io, message, "content-id"); 315 316 // CONTENT-DESCRIPTION 317 io << " "; 318 printOneHeader(io, message, "content-description"); 319 320 // CONTENT-TRANSFER-ENCODING 321 io << " "; 322 tmp = ""; 323 if (message->h.getFirstHeader("content-transfer-encoding", hitem)) { 324 tmp = hitem.getValue(); 325 trim(tmp); 326 io << toImapString(tmp); 327 } else 328 io << "\"7bit\""; 329 io << " "; 330 331 // Size of body in octets 332 io << message->getBodyLength(); 333 334 lowercase(type); 335 if (type == "text") { 336 io << " "; 337 io << message->getNofBodyLines(); 338 } else if (message->isMessageRFC822()) { 339 io << " "; 340 envelope(io, &message->members[0]); 341 io << " "; 342 bodyStructure(io, &message->members[0], extended); 343 io << " "; 344 io << message->getNofBodyLines(); 345 } 346 347 // Extension data follows 348 349 if (extended) { 350 351 // CONTENT-MD5 352 io << " "; 353 printOneHeader(io, message, "content-md5"); 354 355 // CONTENT-DISPOSITION 356 io << " "; 357 tmp = ""; 358 if (message->h.getFirstHeader("content-disposition", hitem)) { 359 tmp = hitem.getValue(); 360 trim(tmp); 361 362 vector<string> v; 363 split(tmp, ";", v); 364 if (v.size() > 0) { 365 string disp = v[0]; 366 trim(disp); 367 io << "(" << toImapString(disp); 368 io << " "; 369 if (v.size() > 1) { 370 io << "("; 371 vector<string>::const_iterator i = v.begin(); 372 ++i; 373 bool wrote = false; 374 while (i != v.end()) { 375 string s = *i; 376 trim(s); 377 378 string::size_type pos = s.find('='); 379 string key = s.substr(0, pos); 380 string value = s.substr(pos + 1); 381 trim(key); 382 trim(value); 383 384 trim(key, " \""); 385 trim(value, " \""); 386 387 if (!wrote) wrote = true; 388 else io << " "; 389 io << toImapString(key); 390 391 io << " "; 392 io << toImapString(value); 393 394 ++i; 395 } 396 io << ")"; 397 } else 398 io << "NIL"; 399 io << ")"; 400 } else 401 io << "NIL"; 402 } else 403 io << "NIL"; 404 405 // CONTENT-LANGUAGE 406 io << " "; 407 printOneHeader(io, message, "content-language"); 408 409 // CONTENT-LOCATION 410 io << " "; 411 printOneHeader(io, message, "content-location"); 412 } 413 414 io << ")"; 415 } 416 } 417 } 418 419 //------------------------------------------------------------------------ 420 MaildirMessage::MaildirMessage(Maildir &hom) 421 : fd(-1), doc(0), internalFlags(None), stdflags(F_NONE), 422 uid(0), size(0), unique(""), safeName(""), internaldate(0), 423 home(hom) 424 { 425 } 426 427 //------------------------------------------------------------------------ 428 MaildirMessage::MaildirMessage(const MaildirMessage ©) 429 : fd(copy.fd), doc(copy.doc), internalFlags(copy.internalFlags), 430 stdflags(copy.stdflags), uid(copy.uid), size(copy.size), 431 unique(copy.unique), safeName(copy.safeName), 432 internaldate(copy.internaldate), home(copy.home) 433 { 434 } 435 436 //------------------------------------------------------------------------ 437 MaildirMessage::~MaildirMessage(void) 438 { 439 } 440 441 //------------------------------------------------------------------------ 442 MaildirMessage &MaildirMessage::operator =(const MaildirMessage ©) 443 { 444 fd = copy.fd; 445 doc = copy.doc; 446 internalFlags = copy.internalFlags; 447 stdflags = copy.stdflags; 448 uid = copy.uid; 449 size = copy.size; 450 unique = copy.unique; 451 safeName = copy.safeName; 452 internaldate = copy.internaldate; 453 home = copy.home; 454 455 return *this; 456 } 457 458 //------------------------------------------------------------------------ 459 bool MaildirMessage::operator <(const MaildirMessage &a) const 460 { 461 return uid < a.uid; 462 } 463 //------------------------------------------------------------------------ 464 void MaildirMessage::close(void) 465 { 466 if (fd != -1) { 467 if ((internalFlags & WasWrittenTo) && fsync(fd) != 0 468 && errno != EINVAL && errno != EROFS) { 469 // FIXME: report this error 470 } 471 472 if (::close(fd) != 0) { 473 // FIXME: report this error 474 } 475 476 fd = -1; 477 } 478 479 // The file will not be moved from tmp/ before this function has 480 // finished. So it's safe to assume that safeName is still valid. 481 if (internalFlags & WasWrittenTo) { 482 if (internaldate != 0) { 483 struct utimbuf tim = {internaldate, internaldate}; 484 utime(safeName.c_str(), &tim); 485 } else { 486 time_t t = time(0); 487 struct utimbuf tim = {t, t}; 488 utime(safeName.c_str(), &tim); 489 } 490 491 internalFlags &= ~WasWrittenTo; 492 } 493 494 495 if (doc) { 496 doc->clear(); 497 delete doc; 498 doc = 0; 499 } 500 } 501 502 //------------------------------------------------------------------------ 503 void MaildirMessage::setExpunged(void) 504 { 505 internalFlags |= Expunged; 506 } 507 508 //------------------------------------------------------------------------ 509 void MaildirMessage::setUnExpunged(void) 510 { 511 internalFlags &= ~Expunged; 512 } 513 514 //------------------------------------------------------------------------ 515 void MaildirMessage::setFlagsUnchanged(void) 516 { 517 internalFlags &= ~FlagsChanged; 518 } 519 520 //------------------------------------------------------------------------ 521 bool MaildirMessage::hasFlagsChanged(void) const 522 { 523 return (internalFlags & FlagsChanged) != 0; 524 } 525 526 //------------------------------------------------------------------------ 527 unsigned char MaildirMessage::getStdFlags(void) const 528 { 529 return stdflags; 530 } 531 532 //------------------------------------------------------------------------ 533 bool MaildirMessage::isExpunged(void) const 534 { 535 return (internalFlags & Expunged) != 0; 536 } 537 538 //------------------------------------------------------------------------ 539 unsigned int MaildirMessage::getUID(void) const 540 { 541 return uid; 542 } 543 544 //------------------------------------------------------------------------ 545 unsigned int MaildirMessage::getSize(bool render) const 546 { 547 if (size == 0 && render) { 548 size = getDocSize(); 549 home.mailboxchanged = true; 550 } 551 552 return size; 553 } 554 555 //------------------------------------------------------------------------ 556 const string &MaildirMessage::getUnique(void) const 557 { 558 return unique; 559 } 560 561 //------------------------------------------------------------------------ 562 time_t MaildirMessage::getInternalDate(void) const 563 { 564 return internaldate; 565 } 566 567 //------------------------------------------------------------------------ 568 void MaildirMessage::setInternalDate(time_t t) 569 { 570 internaldate = t; 571 } 572 573 //------------------------------------------------------------------------ 574 void MaildirMessage::setStdFlag(unsigned char f_in) 575 { 576 internalFlags |= FlagsChanged; 577 stdflags |= f_in; 578 } 579 580 //------------------------------------------------------------------------ 581 void MaildirMessage::resetStdFlags(void) 582 { 583 internalFlags |= FlagsChanged; 584 stdflags = F_NONE; 585 } 586 587 //------------------------------------------------------------------------ 588 void MaildirMessage::setUID(unsigned int i_in) 589 { 590 uid = i_in; 591 } 592 593 //------------------------------------------------------------------------ 594 void MaildirMessage::setSize(unsigned int i_in) 595 { 596 size = i_in; 597 } 598 599 //------------------------------------------------------------------------ 600 void MaildirMessage::setUnique(const string &s_in) 601 { 602 unique = s_in; 603 } 604 605 //------------------------------------------------------------------------ 606 int MaildirMessage::getFile(void) const 607 { 608 if (fd != -1) 609 return fd; 610 611 const string &id = getUnique(); 612 MaildirIndexItem *item = home.index.find(id); 613 if (item) { 614 string fpath = home.path + "/cur/" + item->fileName; 615 616 unsigned int oflags = O_RDONLY; 617 #ifdef HAVE_OLARGEFILE 618 oflags |= O_LARGEFILE; 619 #endif 620 while ((fd = open(fpath.c_str(), oflags)) == -1) { 621 if (errno == ENOENT) { 622 struct stat st; 623 if (lstat(fpath.c_str(), &st) != -1) { 624 IO &logger = IOFactory::getInstance().get(2); 625 logger << "dangling symlink: " << fpath << endl; 626 return -1; 627 } 628 } else { 629 IO &logger = IOFactory::getInstance().get(2); 630 logger << "unable to open " << fpath << ": " 631 << strerror(errno) << endl; 632 return -1; 633 } 634 635 home.scanFileNames(); 636 if ((item = home.index.find(id)) == 0) 637 break; 638 else 639 fpath = home.path + "/cur/" + item->fileName; 640 } 641 642 MaildirMessageCache &cache = MaildirMessageCache::getInstance(); 643 cache.addStatus(this, MaildirMessageCache::NotParsed); 644 645 return fd; 646 } 647 648 return -1; 649 } 650 651 //------------------------------------------------------------------------ 652 void MaildirMessage::setFile(int fd) 653 { 654 this->fd = fd; 655 } 656 657 //------------------------------------------------------------------------ 658 void MaildirMessage::setSafeName(const string &name) 659 { 660 safeName = name; 661 } 662 663 //------------------------------------------------------------------------ 664 const string &MaildirMessage::getSafeName(void) const 665 { 666 return safeName; 667 } 668 669 //------------------------------------------------------------------------ 670 string MaildirMessage::getFileName(void) const 671 { 672 MaildirIndexItem *item = home.index.find(getUnique()); 673 if (!item) { 674 home.scanFileNames(); 675 676 if ((item = home.index.find(getUnique())) == 0) 677 return ""; 678 } 679 680 return item->fileName; 681 } 682 683 //------------------------------------------------------------------------ 684 void MaildirMessage::rewind(void) 685 { 686 if (fd == -1) { 687 if ((fd == getFile()) == -1) 688 return; 689 } 690 691 lseek(fd, 0, SEEK_SET); 692 } 693 694 //------------------------------------------------------------------------ 695 int MaildirMessage::readChunk(string &chunk) 696 { 697 if (fd == -1) { 698 if ((fd == getFile()) == -1) 699 return -1; 700 } 701 702 char buffer[1024]; 703 ssize_t readBytes = read(fd, buffer, (size_t) sizeof(buffer)); 704 if (readBytes == -1) { 705 setLastError("Error reading from " + getFileName() 706 + ": " + string(strerror(errno))); 707 return -1; 708 } 709 710 chunk = string(buffer, readBytes); 711 return readBytes; 712 } 713 714 //------------------------------------------------------------------------ 715 bool MaildirMessage::appendChunk(const string &chunk) 716 { 717 if (fd == -1) { 718 setLastError("Error writing to " + getSafeName() 719 + ": File is not open"); 720 return false; 721 } 722 723 internalFlags |= WasWrittenTo; 724 725 string out; 726 for (string::const_iterator i = chunk.begin(); i != chunk.end(); ++i) { 727 const char c = *i; 728 if (c != '\r') 729 out += c; 730 } 731 732 ssize_t wroteBytes = 0; 733 for (;;) { 734 wroteBytes = write(fd, out.c_str(), (size_t) out.length()); 735 if (wroteBytes == -1) { 736 if (errno == EINTR) 737 continue; 738 wroteBytes = 0; 739 } 740 741 break; 742 } 743 744 if (wroteBytes == (ssize_t) out.length()) 745 return true; 746 747 setLastError("Error writing to " + getSafeName() 748 + ": " + string(strerror(errno))); 749 return false; 750 } 751 752 //------------------------------------------------------------------------ 753 bool MaildirMessage::parseFull(void) const 754 { 755 MaildirMessageCache &cache = MaildirMessageCache::getInstance(); 756 MaildirMessageCache::ParseStatus ps = cache.getStatus(this); 757 if (ps == MaildirMessageCache::AllParsed && doc) 758 return true; 759 760 int fd = getFile(); 761 if (fd == -1) 762 return false; 763 764 // FIXME: parse errors 765 if (!doc) 766 doc = new MimeDocument; 767 doc->parseFull(fd); 768 769 cache.addStatus(this, MaildirMessageCache::AllParsed); 770 771 return true; 772 } 773 774 //------------------------------------------------------------------------ 775 bool MaildirMessage::parseHeaders(void) const 776 { 777 MaildirMessageCache &cache = MaildirMessageCache::getInstance(); 778 MaildirMessageCache::ParseStatus ps = cache.getStatus(this); 779 if ((ps == MaildirMessageCache::AllParsed 780 || ps == MaildirMessageCache::HeaderParsed) && doc) 781 return true; 782 783 int fd = getFile(); 784 if (fd == -1) 785 return false; 786 787 // FIXME: parse errors 788 if (!doc) 789 doc = new MimeDocument; 790 doc->parseOnlyHeader(fd); 791 792 cache.addStatus(this, MaildirMessageCache::HeaderParsed); 793 794 return true; 795 } 796 797 //------------------------------------------------------------------------ 798 bool MaildirMessage::printBodyStructure(bool extended) const 799 { 800 if (!parseFull()) 801 return false; 802 803 IO &com = IOFactory::getInstance().get(1); 804 bodyStructure(com, doc, extended); 805 return true; 806 } 807 808 //------------------------------------------------------------------------ 809 bool MaildirMessage::printEnvelope(void) const 810 { 811 if (!parseFull()) 812 return false; 813 814 IO &com = IOFactory::getInstance().get(1); 815 envelope(com, doc); 816 return true; 817 } 818 819 //------------------------------------------------------------------------ 820 bool MaildirMessage::printHeader(const std::string §ion, 821 std::vector<std::string> headers, 822 bool includeHeaders, 823 unsigned int startOffset, 824 unsigned int length, 825 bool mime) const 826 { 827 IO &com = IOFactory::getInstance().get(1); 828 com << storage; 829 storage = ""; 830 return true; 831 } 832 833 //------------------------------------------------------------------------ 834 unsigned int MaildirMessage::getHeaderSize(const std::string §ion, 835 std::vector<std::string> headers, 836 bool includeHeaders, 837 unsigned int startOffset, 838 unsigned int length, 839 bool mime) const 840 { 841 IO &com = IOFactory::getInstance().get(1); 842 843 if (section == "") { 844 if (!parseHeaders()) 845 return 0; 846 } else if (!parseFull()) 847 return 0; 848 849 const MimePart *part = doc->getPart(section, "", mime ? MimePart::FetchMime : MimePart::FetchHeader); 850 if (!part) { 851 storage = ""; 852 return 0; 853 } 854 855 int fd = getFile(); 856 if (fd == -1) 857 return 0; 858 859 storage = ""; 860 part->printHeader(fd, com, headers, 861 includeHeaders, startOffset, 862 length, storage); 863 864 return storage.size(); 865 } 866 867 //------------------------------------------------------------------------ 868 bool MaildirMessage::printBody(const std::string §ion, 869 unsigned int startOffset, 870 unsigned int length) const 871 { 872 IO &com = IOFactory::getInstance().get(1); 873 if (!parseFull()) 874 return false; 875 876 const MimePart *part = doc->getPart(section, ""); 877 if (!part) { 878 storage = ""; 879 return 0; 880 } 881 882 int fd = getFile(); 883 if (fd == -1) 884 return false; 885 886 storage = ""; 887 part->printBody(fd, com, startOffset, length); 888 return true; 889 } 890 891 //------------------------------------------------------------------------ 892 unsigned int MaildirMessage::getBodySize(const std::string §ion, 893 unsigned int startOffset, 894 unsigned int length) const 895 { 896 if (!parseFull()) 897 return false; 898 899 const MimePart *part = doc->getPart(section, ""); 900 if (!part) { 901 storage = ""; 902 return 0; 903 } 904 905 if (startOffset > part->bodylength) 906 return 0; 907 908 unsigned int s = part->bodylength - startOffset; 909 return s < length ? s : length; 910 } 911 912 //------------------------------------------------------------------------ 913 bool MaildirMessage::printDoc(unsigned int startOffset, 914 unsigned int length, bool onlyText) const 915 { 916 IO &com = IOFactory::getInstance().get(1); 917 if (!parseFull()) 918 return false; 919 920 int fd = getFile(); 921 if (fd == -1) 922 return false; 923 924 if (onlyText) 925 startOffset += doc->bodystartoffsetcrlf; 926 927 storage = ""; 928 doc->printDoc(fd, com, startOffset, length); 929 return true; 930 } 931 932 //------------------------------------------------------------------------ 933 unsigned int MaildirMessage::getDocSize(unsigned int startOffset, 934 unsigned int length, 935 bool onlyText) const 936 { 937 if (!parseFull()) 938 return false; 939 940 unsigned int s = doc->size; 941 if (onlyText) s -= doc->bodystartoffsetcrlf; 942 943 if (startOffset > s) 944 return 0; 945 946 s -= startOffset; 947 return s < length ? s : length; 948 } 949 950 //------------------------------------------------------------------------ 951 bool MaildirMessage::headerContains(const std::string &header, 952 const std::string &text) 953 { 954 if (!parseHeaders()) 955 return false; 956 957 HeaderItem hitem; 958 if (!doc->h.getFirstHeader(header, hitem)) 959 return false; 960 961 string tmp = hitem.getValue(); 962 uppercase(tmp); 963 string tmp2 = text; 964 uppercase(tmp2); 965 return (tmp.find(tmp2) != string::npos); 966 } 967 968 //------------------------------------------------------------------------ 969 bool MaildirMessage::bodyContains(const std::string &text) 970 { 971 if (!parseFull()) 972 return false; 973 974 // search the body part of the message.. 975 int fd = getFile(); 976 if (fd == -1) 977 return false; 978 979 crlffile = fd; 980 crlfReset(); 981 982 char c; 983 for (unsigned int i = 0; i < doc->getBodyStartOffset(); ++i) 984 if (!crlfGetChar(c)) 985 break; 986 987 char *ring = new char[text.length()]; 988 int pos = 0; 989 int length = doc->getBodyLength(); 990 while (crlfGetChar(c) && length--) { 991 ring[pos % text.length()] = toupper(c); 992 993 if (compareStringToQueue(text, ring, pos + 1, text.length())) { 994 delete ring; 995 return true; 996 } 997 998 ++pos; 999 } 1000 1001 delete ring; 1002 return false; 1003 } 1004 1005 //------------------------------------------------------------------------ 1006 bool MaildirMessage::textContains(const std::string &text) 1007 { 1008 // search the body part of the message.. 1009 int fd = getFile(); 1010 if (fd == -1) 1011 return false; 1012 1013 crlffile = fd; 1014 crlfReset(); 1015 1016 char c; 1017 char *ring = new char[text.length()]; 1018 int pos = 0; 1019 while (crlfGetChar(c)) { 1020 ring[pos % text.length()] = toupper(c); 1021 1022 if (compareStringToQueue(text, ring, pos + 1, text.length())) { 1023 delete ring; 1024 return true; 1025 } 1026 1027 ++pos; 1028 } 1029 1030 delete ring; 1031 return false; 1032 } 1033 1034 //------------------------------------------------------------------------ 1035 const std::string &MaildirMessage::getHeader(const std::string &header) 1036 { 1037 static string NIL = ""; 1038 1039 if (!parseHeaders()) 1040 return NIL; 1041 1042 HeaderItem hitem; 1043 if (!doc->h.getFirstHeader(header, hitem)) 1044 return NIL; 1045 1046 return hitem.getValue(); 1047 } 1048 1049 //------------------------------------------------------------------------ 1050 MaildirMessageCache::MaildirMessageCache(void) 1051 { 1052 } 1053 1054 //------------------------------------------------------------------------ 1055 MaildirMessageCache::~MaildirMessageCache(void) 1056 { 1057 clear(); 1058 } 1059 1060 //------------------------------------------------------------------------ 1061 MaildirMessageCache &MaildirMessageCache::getInstance(void) 1062 { 1063 static MaildirMessageCache cache; 1064 return cache; 1065 } 1066 1067 //------------------------------------------------------------------------ 1068 void MaildirMessageCache::addStatus(const MaildirMessage *m, 1069 ParseStatus s) 1070 { 1071 if (statuses.find(m) == statuses.end()) { 1072 // Insert status. Perhaps remove oldest status. 1073 if (statuses.size() > 2) { 1074 MaildirMessage *message = const_cast<MaildirMessage *>(parsed.front()); 1075 1076 removeStatus(message); 1077 } 1078 1079 parsed.push_back(m); 1080 } 1081 1082 statuses[m] = s; 1083 } 1084 1085 //------------------------------------------------------------------------ 1086 MaildirMessageCache::ParseStatus 1087 MaildirMessageCache::getStatus(const MaildirMessage *m) const 1088 { 1089 if (statuses.find(m) == statuses.end()) 1090 return NotParsed; 1091 1092 return statuses[m]; 1093 } 1094 1095 //------------------------------------------------------------------------ 1096 void MaildirMessageCache::clear(void) 1097 { 1098 for (deque<const MaildirMessage *>::iterator i = parsed.begin(); 1099 i != parsed.end(); ++i) 1100 const_cast<MaildirMessage *>(*i)->close(); 1101 1102 parsed.clear(); 1103 statuses.clear(); 1104 } 1105 1106 //------------------------------------------------------------------------ 1107 void MaildirMessageCache::removeStatus(const MaildirMessage *m) 1108 { 1109 if (statuses.find(m) == statuses.end()) 1110 return; 1111 1112 statuses.erase(statuses.find(m)); 1113 1114 for (deque<const MaildirMessage *>::iterator i = parsed.begin(); 1115 i != parsed.end(); ++i) { 1116 if (*i == m) { 1117 const_cast<MaildirMessage *>(*i)->close(); 1118 parsed.erase(i); 1119 break; 1120 } 1121 } 1122 } 1123 1124 //------------------------------------------------------------------------ 1125 void MaildirMessage::setInternalFlag(unsigned char f) 1126 { 1127 internalFlags |= f; 1128 } 1129 1130 //------------------------------------------------------------------------ 1131 unsigned char MaildirMessage::getInternalFlags(void) const 1132 { 1133 return internalFlags; 1134 } 1135 1136 //------------------------------------------------------------------------ 1137 void MaildirMessage::clearInternalFlag(unsigned char f) 1138 { 1139 internalFlags &= ~f; 1140 }