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*
create_event(Event * parent,const char * name,const BMessenger * target,const BMessage & args)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
Event(Event * parent)187 Event::Event(Event* parent)
188 :
189 fParent(parent),
190 fTriggered(false)
191 {
192 }
193
194
~Event()195 Event::~Event()
196 {
197 }
198
199
200 bool
Triggered() const201 Event::Triggered() const
202 {
203 return fTriggered;
204 }
205
206
207 void
Trigger(Event * origin)208 Event::Trigger(Event* origin)
209 {
210 fTriggered = true;
211 if (fParent != NULL)
212 fParent->Trigger(origin);
213 }
214
215
216 void
ResetTrigger()217 Event::ResetTrigger()
218 {
219 fTriggered = false;
220 }
221
222
223 BaseJob*
Owner() const224 Event::Owner() const
225 {
226 if (fParent != NULL)
227 return fParent->Owner();
228
229 return NULL;
230 }
231
232
233 void
SetOwner(BaseJob * owner)234 Event::SetOwner(BaseJob* owner)
235 {
236 if (fParent != NULL)
237 fParent->SetOwner(owner);
238 }
239
240
241 Event*
Parent() const242 Event::Parent() const
243 {
244 return fParent;
245 }
246
247
248 // #pragma mark -
249
250
EventContainer(Event * parent,const BMessenger * target,const BMessage & args)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
EventContainer(BaseJob * owner,const BMessenger & target)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
AddEvent(Event * event)287 EventContainer::AddEvent(Event* event)
288 {
289 if (event != NULL)
290 fEvents.AddItem(event);
291 }
292
293
294 BObjectList<Event>&
Events()295 EventContainer::Events()
296 {
297 return fEvents;
298 }
299
300
301 const BMessenger&
Target() const302 EventContainer::Target() const
303 {
304 return fTarget;
305 }
306
307
308 status_t
Register(EventRegistrator & registrator)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
Unregister(EventRegistrator & registrator)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
Trigger(Event * origin)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*
Owner() const353 EventContainer::Owner() const
354 {
355 return fOwner;
356 }
357
358
359 void
SetOwner(BaseJob * owner)360 EventContainer::SetOwner(BaseJob* owner)
361 {
362 Event::SetOwner(owner);
363 fOwner = owner;
364 }
365
366
367 void
AddEventsToString(BString & string) const368 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
OrEvent(Event * parent,const BMessenger * target,const BMessage & args)384 OrEvent::OrEvent(Event* parent, const BMessenger* target, const BMessage& args)
385 :
386 EventContainer(parent, target, args)
387 {
388 }
389
390
OrEvent(BaseJob * owner,const BMessenger & target)391 OrEvent::OrEvent(BaseJob* owner, const BMessenger& target)
392 :
393 EventContainer(owner, target)
394 {
395 }
396
397
398 void
ResetTrigger()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
ToString() const413 OrEvent::ToString() const
414 {
415 BString string = "or ";
416 EventContainer::AddEventsToString(string);
417 return string;
418 }
419
420
421 // #pragma mark - StickyEvent
422
423
StickyEvent(Event * parent)424 StickyEvent::StickyEvent(Event* parent)
425 :
426 Event(parent)
427 {
428 }
429
430
~StickyEvent()431 StickyEvent::~StickyEvent()
432 {
433 }
434
435
436 void
ResetSticky()437 StickyEvent::ResetSticky()
438 {
439 Event::ResetTrigger();
440 }
441
442
443 void
ResetTrigger()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
DemandEvent(Event * parent)453 DemandEvent::DemandEvent(Event* parent)
454 :
455 Event(parent)
456 {
457 }
458
459
460 status_t
Register(EventRegistrator & registrator)461 DemandEvent::Register(EventRegistrator& registrator)
462 {
463 return B_OK;
464 }
465
466
467 void
Unregister(EventRegistrator & registrator)468 DemandEvent::Unregister(EventRegistrator& registrator)
469 {
470 }
471
472
473 BString
ToString() const474 DemandEvent::ToString() const
475 {
476 return "demand";
477 }
478
479
480 // #pragma mark - External event
481
482
ExternalEvent(Event * parent,const char * name,const BMessage & args)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&
Name() const500 ExternalEvent::Name() const
501 {
502 return fName;
503 }
504
505
506 bool
Resolve(uint32 flags)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
ResetSticky()519 ExternalEvent::ResetSticky()
520 {
521 if ((fFlags & B_STICKY_EVENT) != 0)
522 Event::ResetTrigger();
523 }
524
525
526 void
ResetTrigger()527 ExternalEvent::ResetTrigger()
528 {
529 if ((fFlags & B_STICKY_EVENT) == 0)
530 Event::ResetTrigger();
531 }
532
533
534 status_t
Register(EventRegistrator & registrator)535 ExternalEvent::Register(EventRegistrator& registrator)
536 {
537 return registrator.RegisterExternalEvent(this, Name().String(), fArguments);
538 }
539
540
541 void
Unregister(EventRegistrator & registrator)542 ExternalEvent::Unregister(EventRegistrator& registrator)
543 {
544 registrator.UnregisterExternalEvent(this, Name().String());
545 }
546
547
548 BString
ToString() const549 ExternalEvent::ToString() const
550 {
551 return fName;
552 }
553
554
555 // #pragma mark - file_created
556
557
FileCreatedEvent(Event * parent,const BMessage & args)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
Register(EventRegistrator & registrator)567 FileCreatedEvent::Register(EventRegistrator& registrator)
568 {
569 // TODO: implement!
570 return B_ERROR;
571 }
572
573
574 void
Unregister(EventRegistrator & registrator)575 FileCreatedEvent::Unregister(EventRegistrator& registrator)
576 {
577 }
578
579
580 BString
ToString() const581 FileCreatedEvent::ToString() const
582 {
583 BString string = "file_created ";
584 string << fPath.Path();
585 return string;
586 }
587
588
589 // #pragma mark -
590
591
VolumeMountedEvent(Event * parent,const BMessage & args)592 VolumeMountedEvent::VolumeMountedEvent(Event* parent, const BMessage& args)
593 :
594 Event(parent)
595 {
596 }
597
598
599 status_t
Register(EventRegistrator & registrator)600 VolumeMountedEvent::Register(EventRegistrator& registrator)
601 {
602 VolumeWatcher::Register(this);
603 return B_OK;
604 }
605
606
607 void
Unregister(EventRegistrator & registrator)608 VolumeMountedEvent::Unregister(EventRegistrator& registrator)
609 {
610 VolumeWatcher::Unregister(this);
611 }
612
613
614 BString
ToString() const615 VolumeMountedEvent::ToString() const
616 {
617 return "volume_mounted";
618 }
619
620
621 void
VolumeMounted(dev_t device)622 VolumeMountedEvent::VolumeMounted(dev_t device)
623 {
624 Trigger(this);
625 }
626
627
628 void
VolumeUnmounted(dev_t device)629 VolumeMountedEvent::VolumeUnmounted(dev_t device)
630 {
631 }
632
633
634 // #pragma mark -
635
636
NetworkAvailableEvent(Event * parent,const BMessage & args)637 NetworkAvailableEvent::NetworkAvailableEvent(Event* parent,
638 const BMessage& args)
639 :
640 StickyEvent(parent)
641 {
642 }
643
644
645 status_t
Register(EventRegistrator & registrator)646 NetworkAvailableEvent::Register(EventRegistrator& registrator)
647 {
648 NetworkWatcher::Register(this);
649 return B_OK;
650 }
651
652
653 void
Unregister(EventRegistrator & registrator)654 NetworkAvailableEvent::Unregister(EventRegistrator& registrator)
655 {
656 NetworkWatcher::Unregister(this);
657 }
658
659
660 BString
ToString() const661 NetworkAvailableEvent::ToString() const
662 {
663 return "network_available";
664 }
665
666
667 void
NetworkAvailabilityChanged(bool available)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*
FromMessage(const BMessenger & target,const BMessage & message)681 Events::FromMessage(const BMessenger& target, const BMessage& message)
682 {
683 return create_event(NULL, "or", &target, message);
684 }
685
686
687 /*static*/ Event*
AddOnDemand(const BMessenger & target,Event * 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*
ResolveExternalEvent(Event * event,const char * name,uint32 flags)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
TriggerExternalEvent(Event * event)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
ResetStickyExternalEvent(Event * event)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
TriggerDemand(Event * event,bool testOnly)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