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 35using std::map; 36 37 38const uint32 kMsgSyncMessages = '&SyM'; 39const uint32 kMsgDeleteMessage = '&DeM'; 40const uint32 kMsgAppendMessage = '&ApM'; 41 42const uint32 kMsgMoveFile = '&MoF'; 43const uint32 kMsgDeleteFile = '&DeF'; 44const uint32 kMsgFileRenamed = '&FiR'; 45const uint32 kMsgFileDeleted = '&FDe'; 46const uint32 kMsgInit = '&Ini'; 47 48const uint32 kMsgSendMessage = '&SeM'; 49 50 51MailFilter::MailFilter(MailProtocol& protocol, AddonSettings* settings) 52 : 53 fMailProtocol(protocol), 54 fAddonSettings(settings) 55{ 56} 57 58 59MailFilter::~MailFilter() 60{ 61} 62 63 64void 65MailFilter::HeaderFetched(const entry_ref& ref, BFile* file) 66{ 67} 68 69 70void 71MailFilter::BodyFetched(const entry_ref& ref, BFile* file) 72{ 73} 74 75 76void 77MailFilter::MailboxSynced(status_t status) 78{ 79} 80 81 82void 83MailFilter::MessageReadyToSend(const entry_ref& ref, BFile* file) 84{ 85} 86 87 88void 89MailFilter::MessageSent(const entry_ref& ref, BFile* file) 90{ 91} 92 93 94// #pragma mark - 95 96 97MailProtocol::MailProtocol(BMailAccountSettings* settings) 98 : 99 fMailNotifier(NULL), 100 fProtocolThread(NULL) 101{ 102 fAccountSettings = *settings; 103 104 AddFilter(new HaikuMailFormatFilter(*this, settings)); 105} 106 107 108MailProtocol::~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 121BMailAccountSettings& 122MailProtocol::AccountSettings() 123{ 124 return fAccountSettings; 125} 126 127 128void 129MailProtocol::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 152MailProtocolThread* 153MailProtocol::Looper() 154{ 155 return fProtocolThread; 156} 157 158 159bool 160MailProtocol::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 173bool 174MailProtocol::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 187void 188MailProtocol::SetMailNotifier(MailNotifier* mailNotifier) 189{ 190 delete fMailNotifier; 191 fMailNotifier = mailNotifier; 192} 193 194 195void 196MailProtocol::ShowError(const char* error) 197{ 198 if (fMailNotifier) 199 fMailNotifier->ShowError(error); 200} 201 202 203void 204MailProtocol::ShowMessage(const char* message) 205{ 206 if (fMailNotifier) 207 fMailNotifier->ShowMessage(message); 208} 209 210 211void 212MailProtocol::SetTotalItems(int32 items) 213{ 214 if (fMailNotifier) 215 fMailNotifier->SetTotalItems(items); 216} 217 218 219void 220MailProtocol::SetTotalItemsSize(int32 size) 221{ 222 if (fMailNotifier) 223 fMailNotifier->SetTotalItemsSize(size); 224} 225 226 227void 228MailProtocol::ReportProgress(int bytes, int messages, const char* message) 229{ 230 if (fMailNotifier) 231 fMailNotifier->ReportProgress(bytes, messages, message); 232} 233 234 235void 236MailProtocol::ResetProgress(const char* message) 237{ 238 if (fMailNotifier) 239 fMailNotifier->ResetProgress(message); 240} 241 242 243bool 244MailProtocol::AddFilter(MailFilter* filter) 245{ 246 return fFilterList.AddItem(filter); 247} 248 249 250int32 251MailProtocol::CountFilter() 252{ 253 return fFilterList.CountItems(); 254} 255 256 257MailFilter* 258MailProtocol::FilterAt(int32 index) 259{ 260 return fFilterList.ItemAt(index); 261} 262 263 264MailFilter* 265MailProtocol::RemoveFilter(int32 index) 266{ 267 return fFilterList.RemoveItemAt(index); 268} 269 270 271bool 272MailProtocol::RemoveFilter(MailFilter* filter) 273{ 274 return fFilterList.RemoveItem(filter); 275} 276 277 278void 279MailProtocol::NotifyNewMessagesToFetch(int32 nMessages) 280{ 281 ResetProgress(); 282 SetTotalItems(nMessages); 283} 284 285 286void 287MailProtocol::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 294void 295MailProtocol::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 302void 303MailProtocol::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 310void 311MailProtocol::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 318status_t 319MailProtocol::MoveMessage(const entry_ref& ref, BDirectory& dir) 320{ 321 BEntry entry(&ref); 322 return entry.MoveTo(&dir); 323} 324 325 326status_t 327MailProtocol::DeleteMessage(const entry_ref& ref) 328{ 329 BEntry entry(&ref); 330 return entry.Remove(); 331} 332 333 334void 335MailProtocol::FileRenamed(const entry_ref& from, const entry_ref& to) 336{ 337 338} 339 340 341void 342MailProtocol::FileDeleted(const node_ref& node) 343{ 344 345} 346 347 348void 349MailProtocol::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 361MailFilter* 362MailProtocol::_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 394InboundProtocol::InboundProtocol(BMailAccountSettings* settings) 395 : 396 MailProtocol(settings) 397{ 398 LoadFilters(fAccountSettings.InboundSettings()); 399} 400 401 402InboundProtocol::~InboundProtocol() 403{ 404 405} 406 407 408status_t 409InboundProtocol::AppendMessage(const entry_ref& ref) 410{ 411 return false; 412} 413 414 415status_t 416InboundProtocol::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 426OutboundProtocol::OutboundProtocol(BMailAccountSettings* settings) 427 : 428 MailProtocol(settings) 429{ 430 LoadFilters(fAccountSettings.OutboundSettings()); 431} 432 433 434OutboundProtocol::~OutboundProtocol() 435{ 436 437} 438 439 440// #pragma mark - 441 442 443MailProtocolThread::MailProtocolThread(MailProtocol* protocol) 444 : 445 fMailProtocol(protocol) 446{ 447 PostMessage(kMsgInit); 448} 449 450 451void 452MailProtocolThread::SetStopNow() 453{ 454 fMailProtocol->SetStopNow(); 455} 456 457 458void 459MailProtocolThread::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 510void 511MailProtocolThread::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 524void 525MailProtocolThread::TriggerFileDeletion(const entry_ref& ref) 526{ 527 BMessage message(kMsgDeleteFile); 528 message.AddRef("file", &ref); 529 PostMessage(&message); 530} 531 532 533void 534MailProtocolThread::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 544void 545MailProtocolThread::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 557InboundProtocolThread::InboundProtocolThread(InboundProtocol* protocol) 558 : 559 MailProtocolThread(protocol), 560 fProtocol(protocol) 561{ 562 563} 564 565 566InboundProtocolThread::~InboundProtocolThread() 567{ 568 fProtocol->SetProtocolThread(NULL); 569} 570 571 572void 573InboundProtocolThread::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 632void 633InboundProtocolThread::SyncMessages() 634{ 635 PostMessage(kMsgSyncMessages); 636} 637 638 639void 640InboundProtocolThread::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 650void 651InboundProtocolThread::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 660void 661InboundProtocolThread::DeleteMessage(const entry_ref& ref) 662{ 663 BMessage message(kMsgDeleteMessage); 664 message.AddRef("ref", &ref); 665 PostMessage(&message); 666} 667 668 669void 670InboundProtocolThread::AppendMessage(const entry_ref& ref) 671{ 672 BMessage message(kMsgAppendMessage); 673 message.AddRef("ref", &ref); 674 PostMessage(&message); 675} 676 677 678void 679InboundProtocolThread::_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 689OutboundProtocolThread::OutboundProtocolThread(OutboundProtocol* protocol) 690 : 691 MailProtocolThread(protocol), 692 fProtocol(protocol) 693{ 694 695} 696 697 698OutboundProtocolThread::~OutboundProtocolThread() 699{ 700 fProtocol->SetProtocolThread(NULL); 701} 702 703 704void 705OutboundProtocolThread::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 728void 729OutboundProtocolThread::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