docs/ikteam: Delete most files.
[haiku.git] / src / servers / launch / Events.cpp
blobc5d9aab96c4fabd584176c7f4e8e79e82b98ec35
1 /*
2 * Copyright 2015, Axel Dörfler, axeld@pinc-software.de.
3 * Distributed under the terms of the MIT License.
4 */
7 #include "Events.h"
9 #include <stdio.h>
11 #include <Entry.h>
12 #include <LaunchRoster.h>
13 #include <Message.h>
14 #include <ObjectList.h>
15 #include <Path.h>
16 #include <StringList.h>
18 #include "BaseJob.h"
19 #include "LaunchDaemon.h"
20 #include "NetworkWatcher.h"
21 #include "Utility.h"
22 #include "VolumeWatcher.h"
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);
33 public:
34 void AddEvent(Event* event);
35 BObjectList<Event>& Events();
37 const BMessenger& Target() const;
39 virtual status_t Register(EventRegistrator& registrator);
40 virtual void Unregister(EventRegistrator& registrator);
42 virtual void Trigger();
44 virtual BaseJob* Owner() const;
45 virtual void SetOwner(BaseJob* owner);
47 protected:
48 void AddEventsToString(BString& string) const;
50 protected:
51 BaseJob* fOwner;
52 BMessenger fTarget;
53 BObjectList<Event> fEvents;
54 bool fRegistered;
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);
65 virtual void ResetTrigger();
67 virtual BString ToString() const;
71 class StickyEvent : public Event {
72 public:
73 StickyEvent(Event* parent);
74 virtual ~StickyEvent();
76 virtual void ResetSticky();
77 virtual void ResetTrigger();
81 class DemandEvent : public Event {
82 public:
83 DemandEvent(Event* parent);
85 virtual status_t Register(EventRegistrator& registrator);
86 virtual void Unregister(EventRegistrator& registrator);
88 virtual BString ToString() const;
92 class ExternalEvent : public Event {
93 public:
94 ExternalEvent(Event* parent, const char* name,
95 const BMessage& args);
97 const BString& Name() const;
98 bool Resolve(uint32 flags);
100 void ResetSticky();
101 virtual void ResetTrigger();
103 virtual status_t Register(EventRegistrator& registrator);
104 virtual void Unregister(EventRegistrator& registrator);
106 virtual BString ToString() const;
108 private:
109 BString fName;
110 BStringList fArguments;
111 uint32 fFlags;
112 bool fResolved;
116 class FileCreatedEvent : public Event {
117 public:
118 FileCreatedEvent(Event* parent,
119 const BMessage& args);
121 virtual status_t Register(EventRegistrator& registrator);
122 virtual void Unregister(EventRegistrator& registrator);
124 virtual BString ToString() const;
126 private:
127 BPath fPath;
131 class VolumeMountedEvent : public Event, public VolumeListener {
132 public:
133 VolumeMountedEvent(Event* parent,
134 const BMessage& args);
136 virtual status_t Register(EventRegistrator& registrator);
137 virtual void Unregister(EventRegistrator& registrator);
139 virtual BString ToString() const;
141 virtual void VolumeMounted(dev_t device);
142 virtual void VolumeUnmounted(dev_t device);
146 class NetworkAvailableEvent : public StickyEvent, public NetworkListener {
147 public:
148 NetworkAvailableEvent(Event* parent,
149 const BMessage& args);
151 virtual status_t Register(EventRegistrator& registrator);
152 virtual void Unregister(EventRegistrator& registrator);
154 virtual BString ToString() const;
156 virtual void NetworkAvailabilityChanged(bool available);
160 static Event*
161 create_event(Event* parent, const char* name, const BMessenger* target,
162 const BMessage& args)
164 if (strcmp(name, "or") == 0) {
165 if (args.IsEmpty())
166 return NULL;
168 return new OrEvent(parent, target, args);
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);
180 return new ExternalEvent(parent, name, args);
184 // #pragma mark -
187 Event::Event(Event* parent)
189 fParent(parent),
190 fTriggered(false)
195 Event::~Event()
200 bool
201 Event::Triggered() const
203 return fTriggered;
207 void
208 Event::Trigger()
210 fTriggered = true;
211 if (fParent != NULL)
212 fParent->Trigger();
216 void
217 Event::ResetTrigger()
219 fTriggered = false;
223 BaseJob*
224 Event::Owner() const
226 if (fParent != NULL)
227 return fParent->Owner();
229 return NULL;
233 void
234 Event::SetOwner(BaseJob* owner)
236 if (fParent != NULL)
237 fParent->SetOwner(owner);
241 Event*
242 Event::Parent() const
244 return fParent;
248 // #pragma mark -
251 EventContainer::EventContainer(Event* parent, const BMessenger* target,
252 const BMessage& args)
254 Event(parent),
255 fEvents(5, true),
256 fRegistered(false)
258 if (target != NULL)
259 fTarget = *target;
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));
275 EventContainer::EventContainer(BaseJob* owner, const BMessenger& target)
277 Event(NULL),
278 fOwner(owner),
279 fTarget(target),
280 fEvents(5, true),
281 fRegistered(false)
286 void
287 EventContainer::AddEvent(Event* event)
289 if (event != NULL)
290 fEvents.AddItem(event);
294 BObjectList<Event>&
295 EventContainer::Events()
297 return fEvents;
301 const BMessenger&
302 EventContainer::Target() const
304 return fTarget;
308 status_t
309 EventContainer::Register(EventRegistrator& registrator)
311 if (fRegistered)
312 return B_OK;
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;
322 fRegistered = true;
323 return B_OK;
327 void
328 EventContainer::Unregister(EventRegistrator& registrator)
330 int32 count = fEvents.CountItems();
331 for (int32 index = 0; index < count; index++) {
332 Event* event = fEvents.ItemAt(index);
333 event->Unregister(registrator);
338 void
339 EventContainer::Trigger()
341 Event::Trigger();
343 if (Parent() == NULL && Owner() != NULL) {
344 BMessage message(kMsgEventTriggered);
345 message.AddString("owner", Owner()->Name());
346 fTarget.SendMessage(&message);
351 BaseJob*
352 EventContainer::Owner() const
354 return fOwner;
358 void
359 EventContainer::SetOwner(BaseJob* owner)
361 Event::SetOwner(owner);
362 fOwner = owner;
366 void
367 EventContainer::AddEventsToString(BString& string) const
369 string += "[";
371 for (int32 index = 0; index < fEvents.CountItems(); index++) {
372 if (index != 0)
373 string += ", ";
374 string += fEvents.ItemAt(index)->ToString();
376 string += "]";
380 // #pragma mark - or
383 OrEvent::OrEvent(Event* parent, const BMessenger* target, const BMessage& args)
385 EventContainer(parent, target, args)
390 OrEvent::OrEvent(BaseJob* owner, const BMessenger& target)
392 EventContainer(owner, target)
397 void
398 OrEvent::ResetTrigger()
400 fTriggered = false;
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();
411 BString
412 OrEvent::ToString() const
414 BString string = "or ";
415 EventContainer::AddEventsToString(string);
416 return string;
420 // #pragma mark - StickyEvent
423 StickyEvent::StickyEvent(Event* parent)
425 Event(parent)
430 StickyEvent::~StickyEvent()
435 void
436 StickyEvent::ResetSticky()
438 Event::ResetTrigger();
442 void
443 StickyEvent::ResetTrigger()
445 // This is a sticky event; we don't reset the trigger here
449 // #pragma mark - demand
452 DemandEvent::DemandEvent(Event* parent)
454 Event(parent)
459 status_t
460 DemandEvent::Register(EventRegistrator& registrator)
462 return B_OK;
466 void
467 DemandEvent::Unregister(EventRegistrator& registrator)
472 BString
473 DemandEvent::ToString() const
475 return "demand";
479 // #pragma mark - External event
482 ExternalEvent::ExternalEvent(Event* parent, const char* name,
483 const BMessage& args)
485 Event(parent),
486 fName(name),
487 fFlags(0),
488 fResolved(false)
490 const char* argument;
491 for (int32 index = 0; args.FindString("args", index, &argument) == B_OK;
492 index++) {
493 fArguments.Add(argument);
498 const BString&
499 ExternalEvent::Name() const
501 return fName;
505 bool
506 ExternalEvent::Resolve(uint32 flags)
508 if (fResolved)
509 return false;
511 fResolved = true;
512 fFlags = flags;
513 return true;
517 void
518 ExternalEvent::ResetSticky()
520 if ((fFlags & B_STICKY_EVENT) != 0)
521 Event::ResetTrigger();
525 void
526 ExternalEvent::ResetTrigger()
528 if ((fFlags & B_STICKY_EVENT) == 0)
529 Event::ResetTrigger();
533 status_t
534 ExternalEvent::Register(EventRegistrator& registrator)
536 return registrator.RegisterExternalEvent(this, Name().String(), fArguments);
540 void
541 ExternalEvent::Unregister(EventRegistrator& registrator)
543 registrator.UnregisterExternalEvent(this, Name().String());
547 BString
548 ExternalEvent::ToString() const
550 return fName;
554 // #pragma mark - file_created
557 FileCreatedEvent::FileCreatedEvent(Event* parent, const BMessage& args)
559 Event(parent)
561 fPath.SetTo(args.GetString("args", NULL));
565 status_t
566 FileCreatedEvent::Register(EventRegistrator& registrator)
568 // TODO: implement!
569 return B_ERROR;
573 void
574 FileCreatedEvent::Unregister(EventRegistrator& registrator)
579 BString
580 FileCreatedEvent::ToString() const
582 BString string = "file_created ";
583 string << fPath.Path();
584 return string;
588 // #pragma mark -
591 VolumeMountedEvent::VolumeMountedEvent(Event* parent, const BMessage& args)
593 Event(parent)
598 status_t
599 VolumeMountedEvent::Register(EventRegistrator& registrator)
601 VolumeWatcher::Register(this);
602 return B_OK;
606 void
607 VolumeMountedEvent::Unregister(EventRegistrator& registrator)
609 VolumeWatcher::Unregister(this);
613 BString
614 VolumeMountedEvent::ToString() const
616 return "volume_mounted";
620 void
621 VolumeMountedEvent::VolumeMounted(dev_t device)
623 Trigger();
627 void
628 VolumeMountedEvent::VolumeUnmounted(dev_t device)
633 // #pragma mark -
636 NetworkAvailableEvent::NetworkAvailableEvent(Event* parent,
637 const BMessage& args)
639 StickyEvent(parent)
644 status_t
645 NetworkAvailableEvent::Register(EventRegistrator& registrator)
647 NetworkWatcher::Register(this);
648 return B_OK;
652 void
653 NetworkAvailableEvent::Unregister(EventRegistrator& registrator)
655 NetworkWatcher::Unregister(this);
659 BString
660 NetworkAvailableEvent::ToString() const
662 return "network_available";
666 void
667 NetworkAvailableEvent::NetworkAvailabilityChanged(bool available)
669 if (available)
670 Trigger();
671 else
672 ResetSticky();
676 // #pragma mark -
679 /*static*/ Event*
680 Events::FromMessage(const BMessenger& target, const BMessage& message)
682 return create_event(NULL, "or", &target, message);
686 /*static*/ Event*
687 Events::AddOnDemand(const BMessenger& target, Event* event)
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);
697 if (orEvent != event && event != NULL)
698 orEvent->AddEvent(event);
700 orEvent->AddEvent(new DemandEvent(orEvent));
701 return orEvent;
705 /*static*/ bool
706 Events::ResolveExternalEvent(Event* event, const char* name, uint32 flags)
708 if (event == NULL)
709 return false;
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;
724 return false;
728 /*static*/ void
729 Events::TriggerExternalEvent(Event* event, const char* name)
731 if (event == NULL)
732 return;
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;
743 } else if (dynamic_cast<EventContainer*>(event) != NULL) {
744 TriggerExternalEvent(event, name);
748 return;
752 /*static*/ void
753 Events::ResetStickyExternalEvent(Event* event, const char* name)
755 if (event == NULL)
756 return;
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;
767 } else if (dynamic_cast<EventContainer*>(event) != NULL) {
768 ResetStickyExternalEvent(event, name);
772 return;
776 /*! This will trigger a demand event, if it exists.
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.
783 /*static*/ bool
784 Events::TriggerDemand(Event* event, bool testOnly)
786 if (event == NULL || event->Triggered())
787 return false;
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;
797 childEvent->Trigger();
798 break;
800 if (dynamic_cast<EventContainer*>(childEvent) != NULL) {
801 if (TriggerDemand(childEvent, testOnly))
802 break;
807 return event->Triggered();