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