1 /* 2 * Copyright 2015-2018, 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(Event* origin); 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(Event* origin) 209 { 210 fTriggered = true; 211 if (fParent != NULL) 212 fParent->Trigger(origin); 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(Event* origin) 340 { 341 Event::Trigger(origin); 342 343 if (Parent() == NULL && Owner() != NULL) { 344 BMessage message(kMsgEventTriggered); 345 message.AddPointer("event", origin); 346 message.AddString("owner", Owner()->Name()); 347 fTarget.SendMessage(&message); 348 } 349 } 350 351 352 BaseJob* 353 EventContainer::Owner() const 354 { 355 return fOwner; 356 } 357 358 359 void 360 EventContainer::SetOwner(BaseJob* owner) 361 { 362 Event::SetOwner(owner); 363 fOwner = owner; 364 } 365 366 367 void 368 EventContainer::AddEventsToString(BString& string) const 369 { 370 string += "["; 371 372 for (int32 index = 0; index < fEvents.CountItems(); index++) { 373 if (index != 0) 374 string += ", "; 375 string += fEvents.ItemAt(index)->ToString(); 376 } 377 string += "]"; 378 } 379 380 381 // #pragma mark - or 382 383 384 OrEvent::OrEvent(Event* parent, const BMessenger* target, const BMessage& args) 385 : 386 EventContainer(parent, target, args) 387 { 388 } 389 390 391 OrEvent::OrEvent(BaseJob* owner, const BMessenger& target) 392 : 393 EventContainer(owner, target) 394 { 395 } 396 397 398 void 399 OrEvent::ResetTrigger() 400 { 401 fTriggered = false; 402 403 int32 count = fEvents.CountItems(); 404 for (int32 index = 0; index < count; index++) { 405 Event* event = fEvents.ItemAt(index); 406 event->ResetTrigger(); 407 fTriggered |= event->Triggered(); 408 } 409 } 410 411 412 BString 413 OrEvent::ToString() const 414 { 415 BString string = "or "; 416 EventContainer::AddEventsToString(string); 417 return string; 418 } 419 420 421 // #pragma mark - StickyEvent 422 423 424 StickyEvent::StickyEvent(Event* parent) 425 : 426 Event(parent) 427 { 428 } 429 430 431 StickyEvent::~StickyEvent() 432 { 433 } 434 435 436 void 437 StickyEvent::ResetSticky() 438 { 439 Event::ResetTrigger(); 440 } 441 442 443 void 444 StickyEvent::ResetTrigger() 445 { 446 // This is a sticky event; we don't reset the trigger here 447 } 448 449 450 // #pragma mark - demand 451 452 453 DemandEvent::DemandEvent(Event* parent) 454 : 455 Event(parent) 456 { 457 } 458 459 460 status_t 461 DemandEvent::Register(EventRegistrator& registrator) 462 { 463 return B_OK; 464 } 465 466 467 void 468 DemandEvent::Unregister(EventRegistrator& registrator) 469 { 470 } 471 472 473 BString 474 DemandEvent::ToString() const 475 { 476 return "demand"; 477 } 478 479 480 // #pragma mark - External event 481 482 483 ExternalEvent::ExternalEvent(Event* parent, const char* name, 484 const BMessage& args) 485 : 486 Event(parent), 487 fName(name), 488 fFlags(0), 489 fResolved(false) 490 { 491 const char* argument; 492 for (int32 index = 0; args.FindString("args", index, &argument) == B_OK; 493 index++) { 494 fArguments.Add(argument); 495 } 496 } 497 498 499 const BString& 500 ExternalEvent::Name() const 501 { 502 return fName; 503 } 504 505 506 bool 507 ExternalEvent::Resolve(uint32 flags) 508 { 509 if (fResolved) 510 return false; 511 512 fResolved = true; 513 fFlags = flags; 514 return true; 515 } 516 517 518 void 519 ExternalEvent::ResetSticky() 520 { 521 if ((fFlags & B_STICKY_EVENT) != 0) 522 Event::ResetTrigger(); 523 } 524 525 526 void 527 ExternalEvent::ResetTrigger() 528 { 529 if ((fFlags & B_STICKY_EVENT) == 0) 530 Event::ResetTrigger(); 531 } 532 533 534 status_t 535 ExternalEvent::Register(EventRegistrator& registrator) 536 { 537 return registrator.RegisterExternalEvent(this, Name().String(), fArguments); 538 } 539 540 541 void 542 ExternalEvent::Unregister(EventRegistrator& registrator) 543 { 544 registrator.UnregisterExternalEvent(this, Name().String()); 545 } 546 547 548 BString 549 ExternalEvent::ToString() const 550 { 551 return fName; 552 } 553 554 555 // #pragma mark - file_created 556 557 558 FileCreatedEvent::FileCreatedEvent(Event* parent, const BMessage& args) 559 : 560 Event(parent) 561 { 562 fPath.SetTo(args.GetString("args", NULL)); 563 } 564 565 566 status_t 567 FileCreatedEvent::Register(EventRegistrator& registrator) 568 { 569 // TODO: implement! 570 return B_ERROR; 571 } 572 573 574 void 575 FileCreatedEvent::Unregister(EventRegistrator& registrator) 576 { 577 } 578 579 580 BString 581 FileCreatedEvent::ToString() const 582 { 583 BString string = "file_created "; 584 string << fPath.Path(); 585 return string; 586 } 587 588 589 // #pragma mark - 590 591 592 VolumeMountedEvent::VolumeMountedEvent(Event* parent, const BMessage& args) 593 : 594 Event(parent) 595 { 596 } 597 598 599 status_t 600 VolumeMountedEvent::Register(EventRegistrator& registrator) 601 { 602 VolumeWatcher::Register(this); 603 return B_OK; 604 } 605 606 607 void 608 VolumeMountedEvent::Unregister(EventRegistrator& registrator) 609 { 610 VolumeWatcher::Unregister(this); 611 } 612 613 614 BString 615 VolumeMountedEvent::ToString() const 616 { 617 return "volume_mounted"; 618 } 619 620 621 void 622 VolumeMountedEvent::VolumeMounted(dev_t device) 623 { 624 Trigger(this); 625 } 626 627 628 void 629 VolumeMountedEvent::VolumeUnmounted(dev_t device) 630 { 631 } 632 633 634 // #pragma mark - 635 636 637 NetworkAvailableEvent::NetworkAvailableEvent(Event* parent, 638 const BMessage& args) 639 : 640 StickyEvent(parent) 641 { 642 } 643 644 645 status_t 646 NetworkAvailableEvent::Register(EventRegistrator& registrator) 647 { 648 NetworkWatcher::Register(this); 649 return B_OK; 650 } 651 652 653 void 654 NetworkAvailableEvent::Unregister(EventRegistrator& registrator) 655 { 656 NetworkWatcher::Unregister(this); 657 } 658 659 660 BString 661 NetworkAvailableEvent::ToString() const 662 { 663 return "network_available"; 664 } 665 666 667 void 668 NetworkAvailableEvent::NetworkAvailabilityChanged(bool available) 669 { 670 if (available) 671 Trigger(this); 672 else 673 ResetSticky(); 674 } 675 676 677 // #pragma mark - 678 679 680 /*static*/ Event* 681 Events::FromMessage(const BMessenger& target, const BMessage& message) 682 { 683 return create_event(NULL, "or", &target, message); 684 } 685 686 687 /*static*/ Event* 688 Events::AddOnDemand(const BMessenger& target, Event* event) 689 { 690 OrEvent* orEvent = dynamic_cast<OrEvent*>(event); 691 if (orEvent == NULL) { 692 EventContainer* container = dynamic_cast<EventContainer*>(event); 693 if (container != NULL) 694 orEvent = new OrEvent(container->Owner(), container->Target()); 695 else 696 orEvent = new OrEvent(NULL, target); 697 } 698 if (orEvent != event && event != NULL) 699 orEvent->AddEvent(event); 700 701 orEvent->AddEvent(new DemandEvent(orEvent)); 702 return orEvent; 703 } 704 705 706 /*static*/ Event* 707 Events::ResolveExternalEvent(Event* event, const char* name, uint32 flags) 708 { 709 if (event == NULL) 710 return NULL; 711 712 if (EventContainer* container = dynamic_cast<EventContainer*>(event)) { 713 for (int32 index = 0; index < container->Events().CountItems(); 714 index++) { 715 Event* event = ResolveExternalEvent(container->Events().ItemAt(index), name, flags); 716 if (event != NULL) 717 return event; 718 } 719 } else if (ExternalEvent* external = dynamic_cast<ExternalEvent*>(event)) { 720 if (external->Name() == name && external->Resolve(flags)) 721 return external; 722 } 723 724 return NULL; 725 } 726 727 728 /*static*/ void 729 Events::TriggerExternalEvent(Event* event) 730 { 731 if (event == NULL) 732 return; 733 734 ExternalEvent* external = dynamic_cast<ExternalEvent*>(event); 735 if (external == NULL) 736 return; 737 738 external->Trigger(external); 739 } 740 741 742 /*static*/ void 743 Events::ResetStickyExternalEvent(Event* event) 744 { 745 if (event == NULL) 746 return; 747 748 ExternalEvent* external = dynamic_cast<ExternalEvent*>(event); 749 if (external == NULL) 750 return; 751 752 external->ResetSticky(); 753 } 754 755 756 /*! This will trigger a demand event, if it exists. 757 758 \param testOnly If \c true, the deman will not actually be triggered, 759 it will only be checked if it could. 760 \return \c true, if there is a demand event, and it has been 761 triggered by this call. \c false if not. 762 */ 763 /*static*/ bool 764 Events::TriggerDemand(Event* event, bool testOnly) 765 { 766 if (event == NULL || event->Triggered()) 767 return false; 768 769 if (EventContainer* container = dynamic_cast<EventContainer*>(event)) { 770 for (int32 index = 0; index < container->Events().CountItems(); 771 index++) { 772 Event* childEvent = container->Events().ItemAt(index); 773 if (dynamic_cast<DemandEvent*>(childEvent) != NULL) { 774 if (testOnly) 775 return true; 776 777 childEvent->Trigger(childEvent); 778 break; 779 } 780 if (dynamic_cast<EventContainer*>(childEvent) != NULL) { 781 if (TriggerDemand(childEvent, testOnly)) 782 break; 783 } 784 } 785 } 786 787 return event->Triggered(); 788 } 789