1 /* 2 * Copyright 2015, Axel Dörfler, axeld@pinc-software.de. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7 #include "Events.h" 8 9 #include <stdio.h> 10 11 #include <Entry.h> 12 #include <LaunchRoster.h> 13 #include <Message.h> 14 #include <ObjectList.h> 15 #include <Path.h> 16 #include <StringList.h> 17 18 #include "BaseJob.h" 19 #include "LaunchDaemon.h" 20 #include "NetworkWatcher.h" 21 #include "Utility.h" 22 #include "VolumeWatcher.h" 23 24 25 class EventContainer : public Event { 26 protected: 27 EventContainer(Event* parent, 28 const BMessenger* target, 29 const BMessage& args); 30 EventContainer(BaseJob* owner, 31 const BMessenger& target); 32 33 public: 34 void AddEvent(Event* event); 35 BObjectList<Event>& Events(); 36 37 const BMessenger& Target() const; 38 39 virtual status_t Register(EventRegistrator& registrator); 40 virtual void Unregister(EventRegistrator& registrator); 41 42 virtual void Trigger(); 43 44 virtual BaseJob* Owner() const; 45 virtual void SetOwner(BaseJob* owner); 46 47 protected: 48 void AddEventsToString(BString& string) const; 49 50 protected: 51 BaseJob* fOwner; 52 BMessenger fTarget; 53 BObjectList<Event> fEvents; 54 bool fRegistered; 55 }; 56 57 58 class OrEvent : public EventContainer { 59 public: 60 OrEvent(Event* parent, const BMessenger* target, 61 const BMessage& args); 62 OrEvent(BaseJob* owner, 63 const BMessenger& target); 64 65 virtual void ResetTrigger(); 66 67 virtual BString ToString() const; 68 }; 69 70 71 class StickyEvent : public Event { 72 public: 73 StickyEvent(Event* parent); 74 virtual ~StickyEvent(); 75 76 virtual void ResetSticky(); 77 virtual void ResetTrigger(); 78 }; 79 80 81 class DemandEvent : public Event { 82 public: 83 DemandEvent(Event* parent); 84 85 virtual status_t Register(EventRegistrator& registrator); 86 virtual void Unregister(EventRegistrator& registrator); 87 88 virtual BString ToString() const; 89 }; 90 91 92 class ExternalEvent : public Event { 93 public: 94 ExternalEvent(Event* parent, const char* name, 95 const BMessage& args); 96 97 const BString& Name() const; 98 bool Resolve(uint32 flags); 99 100 void ResetSticky(); 101 virtual void ResetTrigger(); 102 103 virtual status_t Register(EventRegistrator& registrator); 104 virtual void Unregister(EventRegistrator& registrator); 105 106 virtual BString ToString() const; 107 108 private: 109 BString fName; 110 BStringList fArguments; 111 uint32 fFlags; 112 bool fResolved; 113 }; 114 115 116 class FileCreatedEvent : public Event { 117 public: 118 FileCreatedEvent(Event* parent, 119 const BMessage& args); 120 121 virtual status_t Register(EventRegistrator& registrator); 122 virtual void Unregister(EventRegistrator& registrator); 123 124 virtual BString ToString() const; 125 126 private: 127 BPath fPath; 128 }; 129 130 131 class VolumeMountedEvent : public Event, public VolumeListener { 132 public: 133 VolumeMountedEvent(Event* parent, 134 const BMessage& args); 135 136 virtual status_t Register(EventRegistrator& registrator); 137 virtual void Unregister(EventRegistrator& registrator); 138 139 virtual BString ToString() const; 140 141 virtual void VolumeMounted(dev_t device); 142 virtual void VolumeUnmounted(dev_t device); 143 }; 144 145 146 class NetworkAvailableEvent : public StickyEvent, public NetworkListener { 147 public: 148 NetworkAvailableEvent(Event* parent, 149 const BMessage& args); 150 151 virtual status_t Register(EventRegistrator& registrator); 152 virtual void Unregister(EventRegistrator& registrator); 153 154 virtual BString ToString() const; 155 156 virtual void NetworkAvailabilityChanged(bool available); 157 }; 158 159 160 static Event* 161 create_event(Event* parent, const char* name, const BMessenger* target, 162 const BMessage& args) 163 { 164 if (strcmp(name, "or") == 0) { 165 if (args.IsEmpty()) 166 return NULL; 167 168 return new OrEvent(parent, target, args); 169 } 170 171 if (strcmp(name, "demand") == 0) 172 return new DemandEvent(parent); 173 if (strcmp(name, "file_created") == 0) 174 return new FileCreatedEvent(parent, args); 175 if (strcmp(name, "volume_mounted") == 0) 176 return new VolumeMountedEvent(parent, args); 177 if (strcmp(name, "network_available") == 0) 178 return new NetworkAvailableEvent(parent, args); 179 180 return new ExternalEvent(parent, name, args); 181 } 182 183 184 // #pragma mark - 185 186 187 Event::Event(Event* parent) 188 : 189 fParent(parent) 190 { 191 } 192 193 194 Event::~Event() 195 { 196 } 197 198 199 bool 200 Event::Triggered() const 201 { 202 return fTriggered; 203 } 204 205 206 void 207 Event::Trigger() 208 { 209 fTriggered = true; 210 if (fParent != NULL) 211 fParent->Trigger(); 212 } 213 214 215 void 216 Event::ResetTrigger() 217 { 218 fTriggered = false; 219 } 220 221 222 BaseJob* 223 Event::Owner() const 224 { 225 if (fParent != NULL) 226 return fParent->Owner(); 227 228 return NULL; 229 } 230 231 232 void 233 Event::SetOwner(BaseJob* owner) 234 { 235 if (fParent != NULL) 236 fParent->SetOwner(owner); 237 } 238 239 240 Event* 241 Event::Parent() const 242 { 243 return fParent; 244 } 245 246 247 // #pragma mark - 248 249 250 EventContainer::EventContainer(Event* parent, const BMessenger* target, 251 const BMessage& args) 252 : 253 Event(parent), 254 fEvents(5, true), 255 fRegistered(false) 256 { 257 if (target != NULL) 258 fTarget = *target; 259 260 char* name; 261 type_code type; 262 int32 count; 263 for (int32 index = 0; args.GetInfo(B_MESSAGE_TYPE, index, &name, &type, 264 &count) == B_OK; index++) { 265 BMessage message; 266 for (int32 messageIndex = 0; args.FindMessage(name, messageIndex, 267 &message) == B_OK; messageIndex++) { 268 AddEvent(create_event(this, name, target, message)); 269 } 270 } 271 } 272 273 274 EventContainer::EventContainer(BaseJob* owner, const BMessenger& target) 275 : 276 Event(NULL), 277 fOwner(owner), 278 fTarget(target), 279 fEvents(5, true), 280 fRegistered(false) 281 { 282 } 283 284 285 void 286 EventContainer::AddEvent(Event* event) 287 { 288 if (event != NULL) 289 fEvents.AddItem(event); 290 } 291 292 293 BObjectList<Event>& 294 EventContainer::Events() 295 { 296 return fEvents; 297 } 298 299 300 const BMessenger& 301 EventContainer::Target() const 302 { 303 return fTarget; 304 } 305 306 307 status_t 308 EventContainer::Register(EventRegistrator& registrator) 309 { 310 if (fRegistered) 311 return B_OK; 312 313 int32 count = fEvents.CountItems(); 314 for (int32 index = 0; index < count; index++) { 315 Event* event = fEvents.ItemAt(index); 316 status_t status = event->Register(registrator); 317 if (status != B_OK) 318 return status; 319 } 320 321 fRegistered = true; 322 return B_OK; 323 } 324 325 326 void 327 EventContainer::Unregister(EventRegistrator& registrator) 328 { 329 int32 count = fEvents.CountItems(); 330 for (int32 index = 0; index < count; index++) { 331 Event* event = fEvents.ItemAt(index); 332 event->Unregister(registrator); 333 } 334 } 335 336 337 void 338 EventContainer::Trigger() 339 { 340 Event::Trigger(); 341 342 if (Parent() == NULL && Owner() != NULL) { 343 BMessage message(kMsgEventTriggered); 344 message.AddString("owner", Owner()->Name()); 345 fTarget.SendMessage(&message); 346 } 347 } 348 349 350 BaseJob* 351 EventContainer::Owner() const 352 { 353 return fOwner; 354 } 355 356 357 void 358 EventContainer::SetOwner(BaseJob* owner) 359 { 360 Event::SetOwner(owner); 361 fOwner = owner; 362 } 363 364 365 void 366 EventContainer::AddEventsToString(BString& string) const 367 { 368 string += "["; 369 370 for (int32 index = 0; index < fEvents.CountItems(); index++) { 371 if (index != 0) 372 string += ", "; 373 string += fEvents.ItemAt(index)->ToString(); 374 } 375 string += "]"; 376 } 377 378 379 // #pragma mark - or 380 381 382 OrEvent::OrEvent(Event* parent, const BMessenger* target, const BMessage& args) 383 : 384 EventContainer(parent, target, args) 385 { 386 } 387 388 389 OrEvent::OrEvent(BaseJob* owner, const BMessenger& target) 390 : 391 EventContainer(owner, target) 392 { 393 } 394 395 396 void 397 OrEvent::ResetTrigger() 398 { 399 fTriggered = false; 400 401 int32 count = fEvents.CountItems(); 402 for (int32 index = 0; index < count; index++) { 403 Event* event = fEvents.ItemAt(index); 404 event->ResetTrigger(); 405 fTriggered |= event->Triggered(); 406 } 407 } 408 409 410 BString 411 OrEvent::ToString() const 412 { 413 BString string = "or "; 414 EventContainer::AddEventsToString(string); 415 return string; 416 } 417 418 419 // #pragma mark - StickyEvent 420 421 422 StickyEvent::StickyEvent(Event* parent) 423 : 424 Event(parent) 425 { 426 } 427 428 429 StickyEvent::~StickyEvent() 430 { 431 } 432 433 434 void 435 StickyEvent::ResetSticky() 436 { 437 Event::ResetTrigger(); 438 } 439 440 441 void 442 StickyEvent::ResetTrigger() 443 { 444 // This is a sticky event; we don't reset the trigger here 445 } 446 447 448 // #pragma mark - demand 449 450 451 DemandEvent::DemandEvent(Event* parent) 452 : 453 Event(parent) 454 { 455 } 456 457 458 status_t 459 DemandEvent::Register(EventRegistrator& registrator) 460 { 461 return B_OK; 462 } 463 464 465 void 466 DemandEvent::Unregister(EventRegistrator& registrator) 467 { 468 } 469 470 471 BString 472 DemandEvent::ToString() const 473 { 474 return "event"; 475 } 476 477 478 // #pragma mark - External event 479 480 481 ExternalEvent::ExternalEvent(Event* parent, const char* name, 482 const BMessage& args) 483 : 484 Event(parent), 485 fName(name), 486 fFlags(0), 487 fResolved(false) 488 { 489 const char* argument; 490 for (int32 index = 0; args.FindString("args", index, &argument) == B_OK; 491 index++) { 492 fArguments.Add(argument); 493 } 494 } 495 496 497 const BString& 498 ExternalEvent::Name() const 499 { 500 return fName; 501 } 502 503 504 bool 505 ExternalEvent::Resolve(uint32 flags) 506 { 507 if (fResolved) 508 return false; 509 510 fResolved = true; 511 fFlags = flags; 512 return true; 513 } 514 515 516 void 517 ExternalEvent::ResetSticky() 518 { 519 if ((fFlags & B_STICKY_EVENT) != 0) 520 Event::ResetTrigger(); 521 } 522 523 524 void 525 ExternalEvent::ResetTrigger() 526 { 527 if ((fFlags & B_STICKY_EVENT) == 0) 528 Event::ResetTrigger(); 529 } 530 531 532 status_t 533 ExternalEvent::Register(EventRegistrator& registrator) 534 { 535 return registrator.RegisterExternalEvent(this, Name().String(), fArguments); 536 } 537 538 539 void 540 ExternalEvent::Unregister(EventRegistrator& registrator) 541 { 542 registrator.UnregisterExternalEvent(this, Name().String()); 543 } 544 545 546 BString 547 ExternalEvent::ToString() const 548 { 549 return fName; 550 } 551 552 553 // #pragma mark - file_created 554 555 556 FileCreatedEvent::FileCreatedEvent(Event* parent, const BMessage& args) 557 : 558 Event(parent) 559 { 560 fPath.SetTo(args.GetString("args", NULL)); 561 } 562 563 564 status_t 565 FileCreatedEvent::Register(EventRegistrator& registrator) 566 { 567 // TODO: implement! 568 return B_ERROR; 569 } 570 571 572 void 573 FileCreatedEvent::Unregister(EventRegistrator& registrator) 574 { 575 } 576 577 578 BString 579 FileCreatedEvent::ToString() const 580 { 581 BString string = "file_created "; 582 string << fPath.Path(); 583 return string; 584 } 585 586 587 // #pragma mark - 588 589 590 VolumeMountedEvent::VolumeMountedEvent(Event* parent, const BMessage& args) 591 : 592 Event(parent) 593 { 594 } 595 596 597 status_t 598 VolumeMountedEvent::Register(EventRegistrator& registrator) 599 { 600 VolumeWatcher::Register(this); 601 return B_OK; 602 } 603 604 605 void 606 VolumeMountedEvent::Unregister(EventRegistrator& registrator) 607 { 608 VolumeWatcher::Unregister(this); 609 } 610 611 612 BString 613 VolumeMountedEvent::ToString() const 614 { 615 return "volume_mounted"; 616 } 617 618 619 void 620 VolumeMountedEvent::VolumeMounted(dev_t device) 621 { 622 Trigger(); 623 } 624 625 626 void 627 VolumeMountedEvent::VolumeUnmounted(dev_t device) 628 { 629 } 630 631 632 // #pragma mark - 633 634 635 NetworkAvailableEvent::NetworkAvailableEvent(Event* parent, 636 const BMessage& args) 637 : 638 StickyEvent(parent) 639 { 640 } 641 642 643 status_t 644 NetworkAvailableEvent::Register(EventRegistrator& registrator) 645 { 646 NetworkWatcher::Register(this); 647 return B_OK; 648 } 649 650 651 void 652 NetworkAvailableEvent::Unregister(EventRegistrator& registrator) 653 { 654 NetworkWatcher::Unregister(this); 655 } 656 657 658 BString 659 NetworkAvailableEvent::ToString() const 660 { 661 return "network_available"; 662 } 663 664 665 void 666 NetworkAvailableEvent::NetworkAvailabilityChanged(bool available) 667 { 668 if (available) 669 Trigger(); 670 else 671 ResetSticky(); 672 } 673 674 675 // #pragma mark - 676 677 678 /*static*/ Event* 679 Events::FromMessage(const BMessenger& target, const BMessage& message) 680 { 681 return create_event(NULL, "or", &target, message); 682 } 683 684 685 /*static*/ Event* 686 Events::AddOnDemand(const BMessenger& target, Event* event) 687 { 688 OrEvent* orEvent = dynamic_cast<OrEvent*>(event); 689 if (orEvent == NULL) { 690 EventContainer* container = dynamic_cast<EventContainer*>(event); 691 if (container != NULL) 692 orEvent = new OrEvent(container->Owner(), container->Target()); 693 else 694 orEvent = new OrEvent(NULL, target); 695 } 696 if (orEvent != event && event != NULL) 697 orEvent->AddEvent(event); 698 699 orEvent->AddEvent(new DemandEvent(orEvent)); 700 return orEvent; 701 } 702 703 704 /*static*/ bool 705 Events::ResolveExternalEvent(Event* event, const char* name, uint32 flags) 706 { 707 if (event == NULL) 708 return false; 709 710 if (EventContainer* container = dynamic_cast<EventContainer*>(event)) { 711 for (int32 index = 0; index < container->Events().CountItems(); 712 index++) { 713 Event* event = container->Events().ItemAt(index); 714 if (ExternalEvent* external = dynamic_cast<ExternalEvent*>(event)) { 715 if (external->Name() == name && external->Resolve(flags)) 716 return true; 717 } else if (dynamic_cast<EventContainer*>(event) != NULL) { 718 if (ResolveExternalEvent(event, name, flags)) 719 return true; 720 } 721 } 722 } 723 return false; 724 } 725 726 727 /*static*/ void 728 Events::TriggerExternalEvent(Event* event, const char* name) 729 { 730 if (event == NULL) 731 return; 732 733 if (EventContainer* container = dynamic_cast<EventContainer*>(event)) { 734 for (int32 index = 0; index < container->Events().CountItems(); 735 index++) { 736 Event* event = container->Events().ItemAt(index); 737 if (ExternalEvent* external = dynamic_cast<ExternalEvent*>(event)) { 738 if (external->Name() == name) { 739 external->Trigger(); 740 return; 741 } 742 } else if (dynamic_cast<EventContainer*>(event) != NULL) { 743 TriggerExternalEvent(event, name); 744 } 745 } 746 } 747 return; 748 } 749 750 751 /*static*/ void 752 Events::ResetStickyExternalEvent(Event* event, const char* name) 753 { 754 if (event == NULL) 755 return; 756 757 if (EventContainer* container = dynamic_cast<EventContainer*>(event)) { 758 for (int32 index = 0; index < container->Events().CountItems(); 759 index++) { 760 Event* event = container->Events().ItemAt(index); 761 if (ExternalEvent* external = dynamic_cast<ExternalEvent*>(event)) { 762 if (external->Name() == name) { 763 external->ResetSticky(); 764 return; 765 } 766 } else if (dynamic_cast<EventContainer*>(event) != NULL) { 767 ResetStickyExternalEvent(event, name); 768 } 769 } 770 } 771 return; 772 } 773 774 775 /*! This will trigger a demand event, if it exists. 776 777 \return \c true, if there is a demand event, and it has been 778 triggered by this call. \c false if not. 779 */ 780 /*static*/ bool 781 Events::TriggerDemand(Event* event) 782 { 783 if (event == NULL || event->Triggered()) 784 return false; 785 786 if (EventContainer* container = dynamic_cast<EventContainer*>(event)) { 787 for (int32 index = 0; index < container->Events().CountItems(); 788 index++) { 789 Event* childEvent = container->Events().ItemAt(index); 790 if (dynamic_cast<DemandEvent*>(childEvent) != NULL) { 791 childEvent->Trigger(); 792 break; 793 } 794 if (dynamic_cast<EventContainer*>(childEvent) != NULL) { 795 if (TriggerDemand(childEvent)) 796 break; 797 } 798 } 799 } 800 801 return event->Triggered(); 802 } 803