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