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 \return \c true, if there is a demand event, and it has been 779 triggered by this call. \c false if not. 780 */ 781 /*static*/ bool 782 Events::TriggerDemand(Event* event) 783 { 784 if (event == NULL || event->Triggered()) 785 return false; 786 787 if (EventContainer* container = dynamic_cast<EventContainer*>(event)) { 788 for (int32 index = 0; index < container->Events().CountItems(); 789 index++) { 790 Event* childEvent = container->Events().ItemAt(index); 791 if (dynamic_cast<DemandEvent*>(childEvent) != NULL) { 792 childEvent->Trigger(); 793 break; 794 } 795 if (dynamic_cast<EventContainer*>(childEvent) != NULL) { 796 if (TriggerDemand(childEvent)) 797 break; 798 } 799 } 800 } 801 802 return event->Triggered(); 803 } 804