2 * Copyright 2015, Axel Dörfler, axeld@pinc-software.de.
3 * Distributed under the terms of the MIT License.
7 #include "Conditions.h"
13 #include <ObjectList.h>
16 #include <StringList.h>
18 #include "NetworkWatcher.h"
22 class ConditionContainer
: public Condition
{
24 ConditionContainer(const BMessage
& args
);
28 void AddCondition(Condition
* condition
);
30 virtual bool IsConstant(ConditionContext
& context
) const;
33 void AddConditionsToString(BString
& string
) const;
36 BObjectList
<Condition
> fConditions
;
40 class AndCondition
: public ConditionContainer
{
42 AndCondition(const BMessage
& args
);
45 virtual bool Test(ConditionContext
& context
) const;
46 virtual BString
ToString() const;
50 class OrCondition
: public ConditionContainer
{
52 OrCondition(const BMessage
& args
);
54 virtual bool Test(ConditionContext
& context
) const;
55 virtual bool IsConstant(ConditionContext
& context
) const;
57 virtual BString
ToString() const;
61 class NotCondition
: public ConditionContainer
{
63 NotCondition(const BMessage
& args
);
66 virtual bool Test(ConditionContext
& context
) const;
67 virtual BString
ToString() const;
71 class SafeModeCondition
: public Condition
{
73 virtual bool Test(ConditionContext
& context
) const;
74 virtual bool IsConstant(ConditionContext
& context
) const;
76 virtual BString
ToString() const;
80 class ReadOnlyCondition
: public Condition
{
82 ReadOnlyCondition(const BMessage
& args
);
84 virtual bool Test(ConditionContext
& context
) const;
85 virtual bool IsConstant(ConditionContext
& context
) const;
87 virtual BString
ToString() const;
91 mutable bool fIsReadOnly
;
92 mutable bool fTestPerformed
;
96 class FileExistsCondition
: public Condition
{
98 FileExistsCondition(const BMessage
& args
);
100 virtual bool Test(ConditionContext
& context
) const;
101 virtual BString
ToString() const;
108 class NetworkAvailableCondition
: public Condition
{
110 virtual bool Test(ConditionContext
& context
) const;
111 virtual bool IsConstant(ConditionContext
& context
) const;
113 virtual BString
ToString() const;
117 class SettingCondition
: public Condition
{
119 SettingCondition(const BMessage
& args
);
121 virtual bool Test(ConditionContext
& context
) const;
123 virtual BString
ToString() const;
133 create_condition(const char* name
, const BMessage
& args
)
135 if (strcmp(name
, "and") == 0 && !args
.IsEmpty())
136 return new AndCondition(args
);
137 if (strcmp(name
, "or") == 0 && !args
.IsEmpty())
138 return new OrCondition(args
);
139 if (strcmp(name
, "not") == 0 && !args
.IsEmpty())
140 return new NotCondition(args
);
142 if (strcmp(name
, "safemode") == 0)
143 return new SafeModeCondition();
144 if (strcmp(name
, "read_only") == 0)
145 return new ReadOnlyCondition(args
);
146 if (strcmp(name
, "file_exists") == 0)
147 return new FileExistsCondition(args
);
148 if (strcmp(name
, "network_available") == 0)
149 return new NetworkAvailableCondition();
150 if (strcmp(name
, "setting") == 0)
151 return new SettingCondition(args
);
160 Condition::Condition()
165 Condition::~Condition()
171 Condition::IsConstant(ConditionContext
& context
) const
180 ConditionContainer::ConditionContainer(const BMessage
& args
)
182 fConditions(10, true)
187 for (int32 index
= 0; args
.GetInfo(B_MESSAGE_TYPE
, index
, &name
, &type
,
188 &count
) == B_OK
; index
++) {
190 for (int32 messageIndex
= 0; args
.FindMessage(name
, messageIndex
,
191 &message
) == B_OK
; messageIndex
++) {
192 AddCondition(create_condition(name
, message
));
198 ConditionContainer::ConditionContainer()
200 fConditions(10, true)
206 ConditionContainer::AddCondition(Condition
* condition
)
208 if (condition
!= NULL
)
209 fConditions
.AddItem(condition
);
213 /*! A single constant failing condition makes this constant, too, otherwise,
214 a single non-constant condition makes this non-constant as well.
217 ConditionContainer::IsConstant(ConditionContext
& context
) const
220 for (int32 index
= 0; index
< fConditions
.CountItems(); index
++) {
221 const Condition
* condition
= fConditions
.ItemAt(index
);
222 if (condition
->IsConstant(context
)) {
223 if (!condition
->Test(context
))
233 ConditionContainer::AddConditionsToString(BString
& string
) const
237 for (int32 index
= 0; index
< fConditions
.CountItems(); index
++) {
240 string
+= fConditions
.ItemAt(index
)->ToString();
246 // #pragma mark - and
249 AndCondition::AndCondition(const BMessage
& args
)
251 ConditionContainer(args
)
256 AndCondition::AndCondition()
262 AndCondition::Test(ConditionContext
& context
) const
264 for (int32 index
= 0; index
< fConditions
.CountItems(); index
++) {
265 Condition
* condition
= fConditions
.ItemAt(index
);
266 if (!condition
->Test(context
))
274 AndCondition::ToString() const
276 BString string
= "and ";
277 ConditionContainer::AddConditionsToString(string
);
285 OrCondition::OrCondition(const BMessage
& args
)
287 ConditionContainer(args
)
293 OrCondition::Test(ConditionContext
& context
) const
295 if (fConditions
.IsEmpty())
298 for (int32 index
= 0; index
< fConditions
.CountItems(); index
++) {
299 Condition
* condition
= fConditions
.ItemAt(index
);
300 if (condition
->Test(context
))
307 /*! If there is a single succeeding constant condition, this is constant, too.
308 Otherwise, it is non-constant if there is a single non-constant condition.
311 OrCondition::IsConstant(ConditionContext
& context
) const
314 for (int32 index
= 0; index
< fConditions
.CountItems(); index
++) {
315 const Condition
* condition
= fConditions
.ItemAt(index
);
316 if (condition
->IsConstant(context
)) {
317 if (condition
->Test(context
))
327 OrCondition::ToString() const
329 BString string
= "or ";
330 ConditionContainer::AddConditionsToString(string
);
338 NotCondition::NotCondition(const BMessage
& args
)
340 ConditionContainer(args
)
345 NotCondition::NotCondition()
351 NotCondition::Test(ConditionContext
& context
) const
353 for (int32 index
= 0; index
< fConditions
.CountItems(); index
++) {
354 Condition
* condition
= fConditions
.ItemAt(index
);
355 if (condition
->Test(context
))
363 NotCondition::ToString() const
365 BString string
= "not ";
366 ConditionContainer::AddConditionsToString(string
);
371 // #pragma mark - safemode
375 SafeModeCondition::Test(ConditionContext
& context
) const
377 return context
.IsSafeMode();
382 SafeModeCondition::IsConstant(ConditionContext
& context
) const
389 SafeModeCondition::ToString() const
395 // #pragma mark - read_only
398 ReadOnlyCondition::ReadOnlyCondition(const BMessage
& args
)
400 fPath(args
.GetString("args")),
402 fTestPerformed(false)
408 ReadOnlyCondition::Test(ConditionContext
& context
) const
413 if (fPath
.IsEmpty() || fPath
== "/boot")
414 fIsReadOnly
= context
.BootVolumeIsReadOnly();
416 fIsReadOnly
= Utility::IsReadOnlyVolume(fPath
);
418 fTestPerformed
= true;
425 ReadOnlyCondition::IsConstant(ConditionContext
& context
) const
432 ReadOnlyCondition::ToString() const
434 BString string
= "readonly ";
440 // #pragma mark - file_exists
443 FileExistsCondition::FileExistsCondition(const BMessage
& args
)
445 for (int32 index
= 0;
446 const char* path
= args
.GetString("args", index
, NULL
); index
++) {
447 fPaths
.Add(Utility::TranslatePath(path
));
453 FileExistsCondition::Test(ConditionContext
& context
) const
455 for (int32 index
= 0; index
< fPaths
.CountStrings(); index
++) {
457 if (entry
.SetTo(fPaths
.StringAt(index
)) != B_OK
466 FileExistsCondition::ToString() const
468 BString string
= "file_exists [";
469 for (int32 index
= 0; index
< fPaths
.CountStrings(); index
++) {
472 string
<< fPaths
.StringAt(index
);
479 // #pragma mark - network_available
483 NetworkAvailableCondition::Test(ConditionContext
& context
) const
485 return NetworkWatcher::NetworkAvailable(false);
490 NetworkAvailableCondition::IsConstant(ConditionContext
& context
) const
497 NetworkAvailableCondition::ToString() const
499 return "network_available";
503 // #pragma mark - setting
506 SettingCondition::SettingCondition(const BMessage
& args
)
508 fPath
.SetTo(Utility::TranslatePath(args
.GetString("args", 0, NULL
)));
509 fField
= args
.GetString("args", 1, NULL
);
510 fValue
= args
.GetString("args", 2, NULL
);
515 SettingCondition::Test(ConditionContext
& context
) const
517 BFile
file(fPath
.Path(), B_READ_ONLY
);
518 if (file
.InitCheck() != B_OK
)
522 if (settings
.Unflatten(&file
) == B_OK
) {
525 if (settings
.GetInfo(fField
, &type
, &count
) == B_OK
) {
529 bool value
= settings
.GetBool(fField
);
530 bool expect
= fValue
.IsEmpty();
532 expect
= fValue
== "true" || fValue
== "yes"
533 || fValue
== "on" || fValue
== "1";
535 return value
== expect
;
539 BString value
= settings
.GetString(fField
);
540 if (fValue
.IsEmpty() && !value
.IsEmpty())
543 return fValue
== value
;
548 // TODO: check for driver settings, too?
555 SettingCondition::ToString() const
557 BString string
= "setting file ";
558 string
<< fPath
.Path() << ", field " << fField
;
559 if (!fValue
.IsEmpty())
560 string
<< ", value " << fValue
;
569 /*static*/ Condition
*
570 Conditions::FromMessage(const BMessage
& message
)
572 return create_condition("and", message
);
576 /*static*/ Condition
*
577 Conditions::AddNotSafeMode(Condition
* condition
)
579 AndCondition
* andCondition
= dynamic_cast<AndCondition
*>(condition
);
580 if (andCondition
== NULL
)
581 andCondition
= new AndCondition();
582 if (andCondition
!= condition
&& condition
!= NULL
)
583 andCondition
->AddCondition(condition
);
585 NotCondition
* notCondition
= new NotCondition();
586 notCondition
->AddCondition(new SafeModeCondition());
588 andCondition
->AddCondition(notCondition
);