1 /* 2 * Copyright 2011, Haiku, Inc. All rights reserved. 3 * Copyright 2001-2003 Dr. Zoidberg Enterprises. All rights reserved. 4 */ 5 6 7 #include <stdio.h> 8 #include <fs_attr.h> 9 #include <stdlib.h> 10 #include <assert.h> 11 12 #include <Alert.h> 13 #include <Directory.h> 14 #include <FindDirectory.h> 15 #include <Query.h> 16 #include <E-mail.h> 17 #include <Node.h> 18 #include <NodeInfo.h> 19 #include <NodeMonitor.h> 20 #include <Path.h> 21 #include <Roster.h> 22 #include <String.h> 23 #include <StringList.h> 24 #include <VolumeRoster.h> 25 26 #include <mail_util.h> 27 #include <MailAddon.h> 28 #include <MailDaemon.h> 29 #include <MailProtocol.h> 30 #include <MailSettings.h> 31 32 #include "HaikuMailFormatFilter.h" 33 34 35 using std::map; 36 37 38 const uint32 kMsgSyncMessages = '&SyM'; 39 const uint32 kMsgDeleteMessage = '&DeM'; 40 const uint32 kMsgAppendMessage = '&ApM'; 41 42 const uint32 kMsgMoveFile = '&MoF'; 43 const uint32 kMsgDeleteFile = '&DeF'; 44 const uint32 kMsgFileRenamed = '&FiR'; 45 const uint32 kMsgFileDeleted = '&FDe'; 46 const uint32 kMsgInit = '&Ini'; 47 48 const uint32 kMsgSendMessage = '&SeM'; 49 50 51 MailFilter::MailFilter(MailProtocol& protocol, AddonSettings* settings) 52 : 53 fMailProtocol(protocol), 54 fAddonSettings(settings) 55 { 56 } 57 58 59 MailFilter::~MailFilter() 60 { 61 } 62 63 64 void 65 MailFilter::HeaderFetched(const entry_ref& ref, BFile* file) 66 { 67 } 68 69 70 void 71 MailFilter::BodyFetched(const entry_ref& ref, BFile* file) 72 { 73 } 74 75 76 void 77 MailFilter::MailboxSynced(status_t status) 78 { 79 } 80 81 82 void 83 MailFilter::MessageReadyToSend(const entry_ref& ref, BFile* file) 84 { 85 } 86 87 88 void 89 MailFilter::MessageSent(const entry_ref& ref, BFile* file) 90 { 91 } 92 93 94 // #pragma mark - 95 96 97 MailProtocol::MailProtocol(BMailAccountSettings* settings) 98 : 99 fMailNotifier(NULL), 100 fProtocolThread(NULL) 101 { 102 fAccountSettings = *settings; 103 104 AddFilter(new HaikuMailFormatFilter(*this, settings)); 105 } 106 107 108 MailProtocol::~MailProtocol() 109 { 110 delete fMailNotifier; 111 112 for (int i = 0; i < fFilterList.CountItems(); i++) 113 delete fFilterList.ItemAt(i); 114 115 map<entry_ref, image_id>::iterator it = fFilterImages.begin(); 116 for (; it != fFilterImages.end(); it++) 117 unload_add_on(it->second); 118 } 119 120 121 BMailAccountSettings& 122 MailProtocol::AccountSettings() 123 { 124 return fAccountSettings; 125 } 126 127 128 void 129 MailProtocol::SetProtocolThread(MailProtocolThread* protocolThread) 130 { 131 if (fProtocolThread) { 132 fProtocolThread->Lock(); 133 for (int i = 0; i < fHandlerList.CountItems(); i++) 134 fProtocolThread->RemoveHandler(fHandlerList.ItemAt(i)); 135 fProtocolThread->Unlock(); 136 } 137 138 fProtocolThread = protocolThread; 139 140 if (!fProtocolThread) 141 return; 142 143 fProtocolThread->Lock(); 144 for (int i = 0; i < fHandlerList.CountItems(); i++) 145 fProtocolThread->AddHandler(fHandlerList.ItemAt(i)); 146 fProtocolThread->Unlock(); 147 148 AddedToLooper(); 149 } 150 151 152 MailProtocolThread* 153 MailProtocol::Looper() 154 { 155 return fProtocolThread; 156 } 157 158 159 bool 160 MailProtocol::AddHandler(BHandler* handler) 161 { 162 if (!fHandlerList.AddItem(handler)) 163 return false; 164 if (fProtocolThread) { 165 fProtocolThread->Lock(); 166 fProtocolThread->AddHandler(handler); 167 fProtocolThread->Unlock(); 168 } 169 return true; 170 } 171 172 173 bool 174 MailProtocol::RemoveHandler(BHandler* handler) 175 { 176 if (!fHandlerList.RemoveItem(handler)) 177 return false; 178 if (fProtocolThread) { 179 fProtocolThread->Lock(); 180 fProtocolThread->RemoveHandler(handler); 181 fProtocolThread->Unlock(); 182 } 183 return true; 184 } 185 186 187 void 188 MailProtocol::SetMailNotifier(MailNotifier* mailNotifier) 189 { 190 delete fMailNotifier; 191 fMailNotifier = mailNotifier; 192 } 193 194 195 void 196 MailProtocol::ShowError(const char* error) 197 { 198 if (fMailNotifier) 199 fMailNotifier->ShowError(error); 200 } 201 202 203 void 204 MailProtocol::ShowMessage(const char* message) 205 { 206 if (fMailNotifier) 207 fMailNotifier->ShowMessage(message); 208 } 209 210 211 void 212 MailProtocol::SetTotalItems(int32 items) 213 { 214 if (fMailNotifier) 215 fMailNotifier->SetTotalItems(items); 216 } 217 218 219 void 220 MailProtocol::SetTotalItemsSize(int32 size) 221 { 222 if (fMailNotifier) 223 fMailNotifier->SetTotalItemsSize(size); 224 } 225 226 227 void 228 MailProtocol::ReportProgress(int bytes, int messages, const char* message) 229 { 230 if (fMailNotifier) 231 fMailNotifier->ReportProgress(bytes, messages, message); 232 } 233 234 235 void 236 MailProtocol::ResetProgress(const char* message) 237 { 238 if (fMailNotifier) 239 fMailNotifier->ResetProgress(message); 240 } 241 242 243 bool 244 MailProtocol::AddFilter(MailFilter* filter) 245 { 246 return fFilterList.AddItem(filter); 247 } 248 249 250 int32 251 MailProtocol::CountFilter() 252 { 253 return fFilterList.CountItems(); 254 } 255 256 257 MailFilter* 258 MailProtocol::FilterAt(int32 index) 259 { 260 return fFilterList.ItemAt(index); 261 } 262 263 264 MailFilter* 265 MailProtocol::RemoveFilter(int32 index) 266 { 267 return fFilterList.RemoveItemAt(index); 268 } 269 270 271 bool 272 MailProtocol::RemoveFilter(MailFilter* filter) 273 { 274 return fFilterList.RemoveItem(filter); 275 } 276 277 278 void 279 MailProtocol::NotifyNewMessagesToFetch(int32 nMessages) 280 { 281 ResetProgress(); 282 SetTotalItems(nMessages); 283 } 284 285 286 void 287 MailProtocol::NotifyHeaderFetched(const entry_ref& ref, BFile* data) 288 { 289 for (int i = 0; i < fFilterList.CountItems(); i++) 290 fFilterList.ItemAt(i)->HeaderFetched(ref, data); 291 } 292 293 294 void 295 MailProtocol::NotifyBodyFetched(const entry_ref& ref, BFile* data) 296 { 297 for (int i = 0; i < fFilterList.CountItems(); i++) 298 fFilterList.ItemAt(i)->BodyFetched(ref, data); 299 } 300 301 302 void 303 MailProtocol::NotifyMessageReadyToSend(const entry_ref& ref, BFile* data) 304 { 305 for (int i = 0; i < fFilterList.CountItems(); i++) 306 fFilterList.ItemAt(i)->MessageReadyToSend(ref, data); 307 } 308 309 310 void 311 MailProtocol::NotifyMessageSent(const entry_ref& ref, BFile* data) 312 { 313 for (int i = 0; i < fFilterList.CountItems(); i++) 314 fFilterList.ItemAt(i)->MessageSent(ref, data); 315 } 316 317 318 status_t 319 MailProtocol::MoveMessage(const entry_ref& ref, BDirectory& dir) 320 { 321 BEntry entry(&ref); 322 return entry.MoveTo(&dir); 323 } 324 325 326 status_t 327 MailProtocol::DeleteMessage(const entry_ref& ref) 328 { 329 BEntry entry(&ref); 330 return entry.Remove(); 331 } 332 333 334 void 335 MailProtocol::FileRenamed(const entry_ref& from, const entry_ref& to) 336 { 337 338 } 339 340 341 void 342 MailProtocol::FileDeleted(const node_ref& node) 343 { 344 345 } 346 347 348 void 349 MailProtocol::LoadFilters(MailAddonSettings& settings) 350 { 351 for (int i = 0; i < settings.CountFilterSettings(); i++) { 352 AddonSettings* filterSettings = settings.FilterSettingsAt(i); 353 MailFilter* filter = _LoadFilter(filterSettings); 354 if (!filter) 355 continue; 356 AddFilter(filter); 357 } 358 } 359 360 361 MailFilter* 362 MailProtocol::_LoadFilter(AddonSettings* filterSettings) 363 { 364 const entry_ref& ref = filterSettings->AddonRef(); 365 map<entry_ref, image_id>::iterator it = fFilterImages.find(ref); 366 image_id image; 367 if (it != fFilterImages.end()) 368 image = it->second; 369 else { 370 BEntry entry(&ref); 371 BPath path(&entry); 372 image = load_add_on(path.Path()); 373 } 374 if (image < 0) 375 return NULL; 376 377 MailFilter* (*instantiate_mailfilter)(MailProtocol& protocol, 378 AddonSettings* settings); 379 if (get_image_symbol(image, "instantiate_mailfilter", 380 B_SYMBOL_TYPE_TEXT, (void **)&instantiate_mailfilter) 381 != B_OK) { 382 unload_add_on(image); 383 return NULL; 384 } 385 386 fFilterImages[ref] = image; 387 return (*instantiate_mailfilter)(*this, filterSettings); 388 } 389 390 391 // #pragma mark - 392 393 394 InboundProtocol::InboundProtocol(BMailAccountSettings* settings) 395 : 396 MailProtocol(settings) 397 { 398 LoadFilters(fAccountSettings.InboundSettings()); 399 } 400 401 402 InboundProtocol::~InboundProtocol() 403 { 404 405 } 406 407 408 status_t 409 InboundProtocol::AppendMessage(const entry_ref& ref) 410 { 411 return false; 412 } 413 414 415 status_t 416 InboundProtocol::MarkMessageAsRead(const entry_ref& ref, read_flags flag) 417 { 418 BNode node(&ref); 419 return write_read_attr(node, flag); 420 } 421 422 423 // #pragma mark - 424 425 426 OutboundProtocol::OutboundProtocol(BMailAccountSettings* settings) 427 : 428 MailProtocol(settings) 429 { 430 LoadFilters(fAccountSettings.OutboundSettings()); 431 } 432 433 434 OutboundProtocol::~OutboundProtocol() 435 { 436 437 } 438 439 440 // #pragma mark - 441 442 443 MailProtocolThread::MailProtocolThread(MailProtocol* protocol) 444 : 445 fMailProtocol(protocol) 446 { 447 PostMessage(kMsgInit); 448 } 449 450 451 void 452 MailProtocolThread::SetStopNow() 453 { 454 fMailProtocol->SetStopNow(); 455 } 456 457 458 void 459 MailProtocolThread::MessageReceived(BMessage* message) 460 { 461 switch (message->what) { 462 case kMsgInit: 463 fMailProtocol->SetProtocolThread(this); 464 break; 465 466 case kMsgMoveFile: 467 { 468 entry_ref file; 469 message->FindRef("file", &file); 470 entry_ref dir; 471 message->FindRef("directory", &dir); 472 BDirectory directory(&dir); 473 fMailProtocol->MoveMessage(file, directory); 474 break; 475 } 476 477 case kMsgDeleteFile: 478 { 479 entry_ref file; 480 message->FindRef("file", &file); 481 fMailProtocol->DeleteMessage(file); 482 break; 483 } 484 485 case kMsgFileRenamed: 486 { 487 entry_ref from; 488 message->FindRef("from", &from); 489 entry_ref to; 490 message->FindRef("to", &to); 491 fMailProtocol->FileRenamed(from, to); 492 break; 493 } 494 495 case kMsgFileDeleted: 496 { 497 node_ref node; 498 message->FindInt32("device",&node.device); 499 message->FindInt64("node", &node.node); 500 fMailProtocol->FileDeleted(node); 501 break; 502 } 503 504 default: 505 BLooper::MessageReceived(message); 506 } 507 } 508 509 510 void 511 MailProtocolThread::TriggerFileMove(const entry_ref& ref, BDirectory& dir) 512 { 513 BMessage message(kMsgMoveFile); 514 message.AddRef("file", &ref); 515 BEntry entry; 516 dir.GetEntry(&entry); 517 entry_ref dirRef; 518 entry.GetRef(&dirRef); 519 message.AddRef("directory", &dirRef); 520 PostMessage(&message); 521 } 522 523 524 void 525 MailProtocolThread::TriggerFileDeletion(const entry_ref& ref) 526 { 527 BMessage message(kMsgDeleteFile); 528 message.AddRef("file", &ref); 529 PostMessage(&message); 530 } 531 532 533 void 534 MailProtocolThread::TriggerFileRenamed(const entry_ref& from, 535 const entry_ref& to) 536 { 537 BMessage message(kMsgFileRenamed); 538 message.AddRef("from", &from); 539 message.AddRef("to", &to); 540 PostMessage(&message); 541 } 542 543 544 void 545 MailProtocolThread::TriggerFileDeleted(const node_ref& node) 546 { 547 BMessage message(kMsgFileDeleted); 548 message.AddInt32("device", node.device); 549 message.AddInt64("node", node.node); 550 PostMessage(&message); 551 } 552 553 554 // #pragma mark - 555 556 557 InboundProtocolThread::InboundProtocolThread(InboundProtocol* protocol) 558 : 559 MailProtocolThread(protocol), 560 fProtocol(protocol) 561 { 562 563 } 564 565 566 InboundProtocolThread::~InboundProtocolThread() 567 { 568 fProtocol->SetProtocolThread(NULL); 569 } 570 571 572 void 573 InboundProtocolThread::MessageReceived(BMessage* message) 574 { 575 switch (message->what) { 576 case kMsgSyncMessages: 577 { 578 status_t status = fProtocol->SyncMessages(); 579 _NotiyMailboxSynced(status); 580 break; 581 } 582 583 case kMsgFetchBody: 584 { 585 entry_ref ref; 586 message->FindRef("ref", &ref); 587 status_t status = fProtocol->FetchBody(ref); 588 589 BMessenger target; 590 if (message->FindMessenger("target", &target) != B_OK) 591 break; 592 593 BMessage message(kMsgBodyFetched); 594 message.AddInt32("status", status); 595 message.AddRef("ref", &ref); 596 target.SendMessage(&message); 597 break; 598 } 599 600 case kMsgMarkMessageAsRead: 601 { 602 entry_ref ref; 603 message->FindRef("ref", &ref); 604 read_flags read = (read_flags)message->FindInt32("read"); 605 fProtocol->MarkMessageAsRead(ref, read); 606 break; 607 } 608 609 case kMsgDeleteMessage: 610 { 611 entry_ref ref; 612 message->FindRef("ref", &ref); 613 fProtocol->DeleteMessage(ref); 614 break; 615 } 616 617 case kMsgAppendMessage: 618 { 619 entry_ref ref; 620 message->FindRef("ref", &ref); 621 fProtocol->AppendMessage(ref); 622 break; 623 } 624 625 default: 626 MailProtocolThread::MessageReceived(message); 627 break; 628 } 629 } 630 631 632 void 633 InboundProtocolThread::SyncMessages() 634 { 635 PostMessage(kMsgSyncMessages); 636 } 637 638 639 void 640 InboundProtocolThread::FetchBody(const entry_ref& ref, BMessenger* listener) 641 { 642 BMessage message(kMsgFetchBody); 643 message.AddRef("ref", &ref); 644 if (listener) 645 message.AddMessenger("target", *listener); 646 PostMessage(&message); 647 } 648 649 650 void 651 InboundProtocolThread::MarkMessageAsRead(const entry_ref& ref, read_flags flag) 652 { 653 BMessage message(kMsgMarkMessageAsRead); 654 message.AddRef("ref", &ref); 655 message.AddInt32("read", flag); 656 PostMessage(&message); 657 } 658 659 660 void 661 InboundProtocolThread::DeleteMessage(const entry_ref& ref) 662 { 663 BMessage message(kMsgDeleteMessage); 664 message.AddRef("ref", &ref); 665 PostMessage(&message); 666 } 667 668 669 void 670 InboundProtocolThread::AppendMessage(const entry_ref& ref) 671 { 672 BMessage message(kMsgAppendMessage); 673 message.AddRef("ref", &ref); 674 PostMessage(&message); 675 } 676 677 678 void 679 InboundProtocolThread::_NotiyMailboxSynced(status_t status) 680 { 681 for (int i = 0; i < fProtocol->CountFilter(); i++) 682 fProtocol->FilterAt(i)->MailboxSynced(status); 683 } 684 685 686 // #pragma mark - 687 688 689 OutboundProtocolThread::OutboundProtocolThread(OutboundProtocol* protocol) 690 : 691 MailProtocolThread(protocol), 692 fProtocol(protocol) 693 { 694 695 } 696 697 698 OutboundProtocolThread::~OutboundProtocolThread() 699 { 700 fProtocol->SetProtocolThread(NULL); 701 } 702 703 704 void 705 OutboundProtocolThread::MessageReceived(BMessage* message) 706 { 707 switch (message->what) { 708 case kMsgSendMessage: 709 { 710 std::vector<entry_ref> mails; 711 for (int32 i = 0; ;i++) { 712 entry_ref ref; 713 if (message->FindRef("ref", i, &ref) != B_OK) 714 break; 715 mails.push_back(ref); 716 } 717 size_t size = message->FindInt32("size"); 718 fProtocol->SendMessages(mails, size); 719 break; 720 } 721 722 default: 723 MailProtocolThread::MessageReceived(message); 724 } 725 } 726 727 728 void 729 OutboundProtocolThread::SendMessages(const std::vector<entry_ref>& mails, 730 size_t totalBytes) 731 { 732 BMessage message(kMsgSendMessage); 733 for (unsigned int i = 0; i < mails.size(); i++) 734 message.AddRef("ref", &mails[i]); 735 message.AddInt32("size", totalBytes); 736 PostMessage(&message); 737 } 738