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 fTriggered(false) 191 { 192 } 193 194 195 Event::~Event() 196 { 197 } 198 199 200 bool 201 Event::Triggered() const 202 { 203 return fTriggered; 204 } 205 206 207 void 208 Event::Trigger() 209 { 210 fTriggered = true; 211 if (fParent != NULL) 212 fParent->Trigger(); 213 } 214 215 216 void 217 Event::ResetTrigger() 218 { 219 fTriggered = false; 220 } 221 222 223 BaseJob* 224 Event::Owner() const 225 { 226 if (fParent != NULL) 227 return fParent->Owner(); 228 229 return NULL; 230 } 231 232 233 void 234 Event::SetOwner(BaseJob* owner) 235 { 236 if (fParent != NULL) 237 fParent->SetOwner(owner); 238 } 239 240 241 Event* 242 Event::Parent() const 243 { 244 return fParent; 245 } 246 247 248 // #pragma mark - 249 250 251 EventContainer::EventContainer(Event* parent, const BMessenger* target, 252 const BMessage& args) 253 : 254 Event(parent), 255 fEvents(5, true), 256 fRegistered(false) 257 { 258 if (target != NULL) 259 fTarget = *target; 260 261 char* name; 262 type_code type; 263 int32 count; 264 for (int32 index = 0; args.GetInfo(B_MESSAGE_TYPE, index, &name, &type, 265 &count) == B_OK; index++) { 266 BMessage message; 267 for (int32 messageIndex = 0; args.FindMessage(name, messageIndex, 268 &message) == B_OK; messageIndex++) { 269 AddEvent(create_event(this, name, target, message)); 270 } 271 } 272 } 273 274 275 EventContainer::EventContainer(BaseJob* owner, const BMessenger& target) 276 : 277 Event(NULL), 278 fOwner(owner), 279 fTarget(target), 280 fEvents(5, true), 281 fRegistered(false) 282 { 283 } 284 285 286 void 287 EventContainer::AddEvent(Event* event) 288 { 289 if (event != NULL) 290 fEvents.AddItem(event); 291 } 292 293 294 BObjectList<Event>& 295 EventContainer::Events() 296 { 297 return fEvents; 298 } 299 300 301 const BMessenger& 302 EventContainer::Target() const 303 { 304 return fTarget; 305 } 306 307 308 status_t 309 EventContainer::Register(EventRegistrator& registrator) 310 { 311 if (fRegistered) 312 return B_OK; 313 314 int32 count = fEvents.CountItems(); 315 for (int32 index = 0; index < count; index++) { 316 Event* event = fEvents.ItemAt(index); 317 status_t status = event->Register(registrator); 318 if (status != B_OK) 319 return status; 320 } 321 322 fRegistered = true; 323 return B_OK; 324 } 325 326 327 void 328 EventContainer::Unregister(EventRegistrator& registrator) 329 { 330 int32 count = fEvents.CountItems(); 331 for (int32 index = 0; index < count; index++) { 332 Event* event = fEvents.ItemAt(index); 333 event->Unregister(registrator); 334 } 335 } 336 337 338 void 339 EventContainer::Trigger() 340 { 341 Event::Trigger(); 342 343 if (Parent() == NULL && Owner() != NULL) { 344 BMessage message(kMsgEventTriggered); 345 message.AddString("owner", Owner()->Name()); 346 fTarget.SendMessage(&message); 347 } 348 } 349 350 351 BaseJob* 352 EventContainer::Owner() const 353 { 354 return fOwner; 355 } 356 357 358 void 359 EventContainer::SetOwner(BaseJob* owner) 360 { 361 Event::SetOwner(owner); 362 fOwner = owner; 363 } 364 365 366 void 367 EventContainer::AddEventsToString(BString& string) const 368 { 369 string += "["; 370 371 for (int32 index = 0; index < fEvents.CountItems(); index++) { 372 if (index != 0) 373 string += ", "; 374 string += fEvents.ItemAt(index)->ToString(); 375 } 376 string += "]"; 377 } 378 379 380 // #pragma mark - or 381 382 383 OrEvent::OrEvent(Event* parent, const BMessenger* target, const BMessage& args) 384 : 385 EventContainer(parent, target, args) 386 { 387 } 388 389 390 OrEvent::OrEvent(BaseJob* owner, const BMessenger& target) 391 : 392 EventContainer(owner, target) 393 { 394 } 395 396 397 void 398 OrEvent::ResetTrigger() 399 { 400 fTriggered = false; 401 402 int32 count = fEvents.CountItems(); 403 for (int32 index = 0; index < count; index++) { 404 Event* event = fEvents.ItemAt(index); 405 event->ResetTrigger(); 406 fTriggered |= event->Triggered(); 407 } 408 } 409 410 411 BString 412 OrEvent::ToString() const 413 { 414 BString string = "or "; 415 EventContainer::AddEventsToString(string); 416 return string; 417 } 418 419 420 // #pragma mark - StickyEvent 421 422 423 StickyEvent::StickyEvent(Event* parent) 424 : 425 Event(parent) 426 { 427 } 428 429 430 StickyEvent::~StickyEvent() 431 { 432 } 433 434 435 void 436 StickyEvent::ResetSticky() 437 { 438 Event::ResetTrigger(); 439 } 440 441 442 void 443 StickyEvent::ResetTrigger() 444 { 445 // This is a sticky event; we don't reset the trigger here 446 } 447 448 449 // #pragma mark - demand 450 451 452 DemandEvent::DemandEvent(Event* parent) 453 : 454 Event(parent) 455 { 456 } 457 458 459 status_t 460 DemandEvent::Register(EventRegistrator& registrator) 461 { 462 return B_OK; 463 } 464 465 466 void 467 DemandEvent::Unregister(EventRegistrator& registrator) 468 { 469 } 470 471 472 BString 473 DemandEvent::ToString() const 474 { 475 return "demand"; 476 } 477 478 479 // #pragma mark - External event 480 481 482 ExternalEvent::ExternalEvent(Event* parent, const char* name, 483 const BMessage& args) 484 : 485 Event(parent), 486 fName(name), 487 fFlags(0), 488 fResolved(false) 489 { 490 const char* argument; 491 for (int32 index = 0; args.FindString("args", index, &argument) == B_OK; 492 index++) { 493 fArguments.Add(argument); 494 } 495 } 496 497 498 const BString& 499 ExternalEvent::Name() const 500 { 501 return fName; 502 } 503 504 505 bool 506 ExternalEvent::Resolve(uint32 flags) 507 { 508 if (fResolved) 509 return false; 510 511 fResolved = true; 512 fFlags = flags; 513 return true; 514 } 515 516 517 void 518 ExternalEvent::ResetSticky() 519 { 520 if ((fFlags & B_STICKY_EVENT) != 0) 521 Event::ResetTrigger(); 522 } 523 524 525 void 526 ExternalEvent::ResetTrigger() 527 { 528 if ((fFlags & B_STICKY_EVENT) == 0) 529 Event::ResetTrigger(); 530 } 531 532 533 status_t 534 ExternalEvent::Register(EventRegistrator& registrator) 535 { 536 return registrator.RegisterExternalEvent(this, Name().String(), fArguments); 537 } 538 539 540 void 541 ExternalEvent::Unregister(EventRegistrator& registrator) 542 { 543 registrator.UnregisterExternalEvent(this, Name().String()); 544 } 545 546 547 BString 548 ExternalEvent::ToString() const 549 { 550 return fName; 551 } 552 553 554 // #pragma mark - file_created 555 556 557 FileCreatedEvent::FileCreatedEvent(Event* parent, const BMessage& args) 558 : 559 Event(parent) 560 { 561 fPath.SetTo(args.GetString("args", NULL)); 562 } 563 564 565 status_t 566 FileCreatedEvent::Register(EventRegistrator& registrator) 567 { 568 // TODO: implement! 569 return B_ERROR; 570 } 571 572 573 void 574 FileCreatedEvent::Unregister(EventRegistrator& registrator) 575 { 576 } 577 578 579 BString 580 FileCreatedEvent::ToString() const 581 { 582 BString string = "file_created "; 583 string << fPath.Path(); 584 return string; 585 } 586 587 588 // #pragma mark - 589 590 591 VolumeMountedEvent::VolumeMountedEvent(Event* parent, const BMessage& args) 592 : 593 Event(parent) 594 { 595 } 596 597 598 status_t 599 VolumeMountedEvent::Register(EventRegistrator& registrator) 600 { 601 VolumeWatcher::Register(this); 602 return B_OK; 603 } 604 605 606 void 607 VolumeMountedEvent::Unregister(EventRegistrator& registrator) 608 { 609 VolumeWatcher::Unregister(this); 610 } 611 612 613 BString 614 VolumeMountedEvent::ToString() const 615 { 616 return "volume_mounted"; 617 } 618 619 620 void 621 VolumeMountedEvent::VolumeMounted(dev_t device) 622 { 623 Trigger(); 624 } 625 626 627 void 628 VolumeMountedEvent::VolumeUnmounted(dev_t device) 629 { 630 } 631 632 633 // #pragma mark - 634 635 636 NetworkAvailableEvent::NetworkAvailableEvent(Event* parent, 637 const BMessage& args) 638 : 639 StickyEvent(parent) 640 { 641 } 642 643 644 status_t 645 NetworkAvailableEvent::Register(EventRegistrator& registrator) 646 { 647 NetworkWatcher::Register(this); 648 return B_OK; 649 } 650 651 652 void 653 NetworkAvailableEvent::Unregister(EventRegistrator& registrator) 654 { 655 NetworkWatcher::Unregister(this); 656 } 657 658 659 BString 660 NetworkAvailableEvent::ToString() const 661 { 662 return "network_available"; 663 } 664 665 666 void 667 NetworkAvailableEvent::NetworkAvailabilityChanged(bool available) 668 { 669 if (available) 670 Trigger(); 671 else 672 ResetSticky(); 673 } 674 675 676 // #pragma mark - 677 678 679 /*static*/ Event* 680 Events::FromMessage(const BMessenger& target, const BMessage& message) 681 { 682 return create_event(NULL, "or", &target, message); 683 } 684 685 686 /*static*/ Event* 687 Events::AddOnDemand(const BMessenger& target, Event* event) 688 { 689 OrEvent* orEvent = dynamic_cast<OrEvent*>(event); 690 if (orEvent == NULL) { 691 EventContainer* container = dynamic_cast<EventContainer*>(event); 692 if (container != NULL) 693 orEvent = new OrEvent(container->Owner(), container->Target()); 694 else 695 orEvent = new OrEvent(NULL, target); 696 } 697 if (orEvent != event && event != NULL) 698 orEvent->AddEvent(event); 699 700 orEvent->AddEvent(new DemandEvent(orEvent)); 701 return orEvent; 702 } 703 704 705 /*static*/ bool 706 Events::ResolveExternalEvent(Event* event, const char* name, uint32 flags) 707 { 708 if (event == NULL) 709 return false; 710 711 if (EventContainer* container = dynamic_cast<EventContainer*>(event)) { 712 for (int32 index = 0; index < container->Events().CountItems(); 713 index++) { 714 Event* event = container->Events().ItemAt(index); 715 if (ExternalEvent* external = dynamic_cast<ExternalEvent*>(event)) { 716 if (external->Name() == name && external->Resolve(flags)) 717 return true; 718 } else if (dynamic_cast<EventContainer*>(event) != NULL) { 719 if (ResolveExternalEvent(event, name, flags)) 720 return true; 721 } 722 } 723 } 724 return false; 725 } 726 727 728 /*static*/ void 729 Events::TriggerExternalEvent(Event* event, const char* name) 730 { 731 if (event == NULL) 732 return; 733 734 if (EventContainer* container = dynamic_cast<EventContainer*>(event)) { 735 for (int32 index = 0; index < container->Events().CountItems(); 736 index++) { 737 Event* event = container->Events().ItemAt(index); 738 if (ExternalEvent* external = dynamic_cast<ExternalEvent*>(event)) { 739 if (external->Name() == name) { 740 external->Trigger(); 741 return; 742 } 743 } else if (dynamic_cast<EventContainer*>(event) != NULL) { 744 TriggerExternalEvent(event, name); 745 } 746 } 747 } 748 return; 749 } 750 751 752 /*static*/ void 753 Events::ResetStickyExternalEvent(Event* event, const char* name) 754 { 755 if (event == NULL) 756 return; 757 758 if (EventContainer* container = dynamic_cast<EventContainer*>(event)) { 759 for (int32 index = 0; index < container->Events().CountItems(); 760 index++) { 761 Event* event = container->Events().ItemAt(index); 762 if (ExternalEvent* external = dynamic_cast<ExternalEvent*>(event)) { 763 if (external->Name() == name) { 764 external->ResetSticky(); 765 return; 766 } 767 } else if (dynamic_cast<EventContainer*>(event) != NULL) { 768 ResetStickyExternalEvent(event, name); 769 } 770 } 771 } 772 return; 773 } 774 775 776 /*! This will trigger a demand event, if it exists. 777 778 \param testOnly If \c true, the deman will not actually be triggered, 779 it will only be checked if it could. 780 \return \c true, if there is a demand event, and it has been 781 triggered by this call. \c false if not. 782 */ 783 /*static*/ bool 784 Events::TriggerDemand(Event* event, bool testOnly) 785 { 786 if (event == NULL || event->Triggered()) 787 return false; 788 789 if (EventContainer* container = dynamic_cast<EventContainer*>(event)) { 790 for (int32 index = 0; index < container->Events().CountItems(); 791 index++) { 792 Event* childEvent = container->Events().ItemAt(index); 793 if (dynamic_cast<DemandEvent*>(childEvent) != NULL) { 794 if (testOnly) 795 return true; 796 797 childEvent->Trigger(); 798 break; 799 } 800 if (dynamic_cast<EventContainer*>(childEvent) != NULL) { 801 if (TriggerDemand(childEvent, testOnly)) 802 break; 803 } 804 } 805 } 806 807 return event->Triggered(); 808 } 809