mirror of https://github.com/SeanOMik/znc-push.git
Implemented custom expression evaluation options
This option allows customization of the boolean logic used to determine how conditional values are used to filter notifications for channel messages. It evaluates as a full boolean logic expression, including the use of sub-expressions. The default value of "all" will bypass this evaluation and simply require all conditions to be true. The expression consists of space-separated tokens in the following grammar: * expression = expression operator expression | "(" expression ")" | value * operator = "and" | "or" * value = "true" | "false" | condition * condition = <any condition option> Also implemented EVAL command for testing purposes.
This commit is contained in:
parent
c462f15201
commit
33b381eb87
38
README.md
38
README.md
|
@ -97,6 +97,11 @@ Commands
|
||||||
Manually trigger a notification with the given message. Useful for testing to validate
|
Manually trigger a notification with the given message. Useful for testing to validate
|
||||||
credentials, etc.
|
credentials, etc.
|
||||||
|
|
||||||
|
* `eval <expression>`
|
||||||
|
|
||||||
|
Evaluate the given expression in an empty context. Useful for testing to validate that
|
||||||
|
a given expression is properly formatted and does not contain invalid tokens.
|
||||||
|
|
||||||
|
|
||||||
Configuration
|
Configuration
|
||||||
-------------
|
-------------
|
||||||
|
@ -196,6 +201,39 @@ Configuration
|
||||||
URI that will be sent with the notification to Notifo. This could be a web address or a
|
URI that will be sent with the notification to Notifo. This could be a web address or a
|
||||||
local scheme to access a mobile application.
|
local scheme to access a mobile application.
|
||||||
|
|
||||||
|
### Advanced
|
||||||
|
|
||||||
|
* `channel_conditions = "all"`
|
||||||
|
|
||||||
|
This option allows customization of the boolean logic used to determine how conditional
|
||||||
|
values are used to filter notifications for channel messages. It evaluates as a full
|
||||||
|
boolean logic expression, including the use of sub-expressions. The default value of
|
||||||
|
"all" will bypass this evaluation and simply require all conditions to be true.
|
||||||
|
|
||||||
|
The expression consists of space-separated tokens in the following grammar:
|
||||||
|
|
||||||
|
* `expression = expression operator expression | "(" expression ")" | value`
|
||||||
|
* `operator = "and" | "or"`
|
||||||
|
* `value = "true" | "false" | condition`
|
||||||
|
* `condition = <any condition option>`
|
||||||
|
|
||||||
|
As a simple example, to replicate the default "all" value, would be the value of
|
||||||
|
`away_only and client_count_less_than and highlight and idle and last_active and
|
||||||
|
last_notification and nick_blacklist and replied`.
|
||||||
|
|
||||||
|
Alternately, setting a value of `true` would send a notification for *every* message,
|
||||||
|
while a value of `false` would *never* send a notification.
|
||||||
|
|
||||||
|
For a more complicated example, the value of `client_count_less_than and highlight and
|
||||||
|
(last_active or last_notification or replied) and nick_blacklist` would send a
|
||||||
|
notification if any of the three conditions in the sub-expression are met, while still
|
||||||
|
requiring all of the conditions outside of the parentheses to also be met.
|
||||||
|
|
||||||
|
* `query_conditions = "all"`
|
||||||
|
|
||||||
|
This option is more or less identical to `channel_conditions`, except that it is used
|
||||||
|
to filter notifications for private messages.
|
||||||
|
|
||||||
|
|
||||||
Roadmap
|
Roadmap
|
||||||
-------
|
-------
|
||||||
|
|
123
notifo.cpp
123
notifo.cpp
|
@ -83,6 +83,10 @@ class CNotifoMod : public CModule
|
||||||
defaults["username"] = "";
|
defaults["username"] = "";
|
||||||
defaults["secret"] = "";
|
defaults["secret"] = "";
|
||||||
|
|
||||||
|
// Condition strings
|
||||||
|
defaults["channel_conditions"] = "all";
|
||||||
|
defaults["query_conditions"] = "all";
|
||||||
|
|
||||||
// Notification conditions
|
// Notification conditions
|
||||||
#ifdef NOTIFO_AWAY
|
#ifdef NOTIFO_AWAY
|
||||||
defaults["away_only"] = "no";
|
defaults["away_only"] = "no";
|
||||||
|
@ -171,6 +175,91 @@ class CNotifoMod : public CModule
|
||||||
AddSocket(sock);
|
AddSocket(sock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Evaluate a boolean expression using condition values.
|
||||||
|
* All tokens must be separated by spaces, using "and" and "or" for
|
||||||
|
* boolean operators, "(" and ")" to enclose sub-expressions, and
|
||||||
|
* condition option names to evaluate each condition.
|
||||||
|
*
|
||||||
|
* @param expression Boolean expression string
|
||||||
|
* @param context Notification context
|
||||||
|
* @param nick Sender nick
|
||||||
|
* @param message Message contents
|
||||||
|
* @return Result of boolean evaluation
|
||||||
|
*/
|
||||||
|
bool eval(const CString& expression, const CString& context=CString(""), const CNick& nick=CNick(""), const CString& message=" ")
|
||||||
|
{
|
||||||
|
CString padded = expression.Replace_n("(", " ( ");
|
||||||
|
padded.Replace(")", " ) ");
|
||||||
|
|
||||||
|
VCString tokens;
|
||||||
|
padded.Split(" ", tokens, false);
|
||||||
|
|
||||||
|
return eval_tokens(tokens.begin(), tokens.end(), context, nick, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define expr(x, y) else if (token == x) { value = oper ? value && y : value || y; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Evaluate a tokenized boolean expression, or sub-expression.
|
||||||
|
*
|
||||||
|
* @param pos Token vector iterator current position
|
||||||
|
* @param end Token vector iterator end position
|
||||||
|
* @param context Notification context
|
||||||
|
* @param nick Sender nick
|
||||||
|
* @param message Message contents
|
||||||
|
* @return Result of boolean expression
|
||||||
|
*/
|
||||||
|
bool eval_tokens(VCString::iterator pos, VCString::iterator end, const CString& context, const CNick& nick, const CString& message)
|
||||||
|
{
|
||||||
|
bool oper = true;
|
||||||
|
bool value = true;
|
||||||
|
|
||||||
|
for(; pos != end; pos++)
|
||||||
|
{
|
||||||
|
CString token = pos->AsLower();
|
||||||
|
|
||||||
|
if (token == "(")
|
||||||
|
{
|
||||||
|
bool inner = eval_tokens(++pos, end, context, nick, message);
|
||||||
|
value = oper ? value && inner : value || inner;
|
||||||
|
}
|
||||||
|
else if (token == ")")
|
||||||
|
{
|
||||||
|
pos++;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
else if (token == "and")
|
||||||
|
{
|
||||||
|
oper = true;
|
||||||
|
}
|
||||||
|
else if (token == "or")
|
||||||
|
{
|
||||||
|
oper = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
expr("true", true)
|
||||||
|
expr("false", false)
|
||||||
|
expr("away_only", away_only())
|
||||||
|
expr("client_count_less_than", client_count_less_than())
|
||||||
|
expr("highlight", highlight(message))
|
||||||
|
expr("idle", idle())
|
||||||
|
expr("last_active", last_active(context))
|
||||||
|
expr("last_notification", last_notification(context))
|
||||||
|
expr("nick_blacklist", nick_blacklist(nick))
|
||||||
|
expr("replied", replied(context))
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
PutModule("Error: Unexpected token \"" + token + "\"");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef expr
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -348,6 +437,13 @@ class CNotifoMod : public CModule
|
||||||
bool notify_channel(const CNick& nick, const CChan& channel, const CString& message)
|
bool notify_channel(const CNick& nick, const CChan& channel, const CString& message)
|
||||||
{
|
{
|
||||||
CString context = channel.GetName();
|
CString context = channel.GetName();
|
||||||
|
|
||||||
|
CString expression = options["channel_conditions"].AsLower();
|
||||||
|
if (expression != "all")
|
||||||
|
{
|
||||||
|
return eval(expression, context, nick, message);
|
||||||
|
}
|
||||||
|
|
||||||
return away_only()
|
return away_only()
|
||||||
&& client_count_less_than()
|
&& client_count_less_than()
|
||||||
&& highlight(message)
|
&& highlight(message)
|
||||||
|
@ -365,9 +461,16 @@ class CNotifoMod : public CModule
|
||||||
* @param nick Nick that sent the message
|
* @param nick Nick that sent the message
|
||||||
* @return Notification should be sent
|
* @return Notification should be sent
|
||||||
*/
|
*/
|
||||||
bool notify_pm(const CNick& nick)
|
bool notify_pm(const CNick& nick, const CString& message)
|
||||||
{
|
{
|
||||||
CString context = nick.GetNick();
|
CString context = nick.GetNick();
|
||||||
|
|
||||||
|
CString expression = options["query_conditions"].AsLower();
|
||||||
|
if (expression != "all")
|
||||||
|
{
|
||||||
|
return eval(expression, context, nick, message);
|
||||||
|
}
|
||||||
|
|
||||||
return away_only()
|
return away_only()
|
||||||
&& client_count_less_than()
|
&& client_count_less_than()
|
||||||
&& idle()
|
&& idle()
|
||||||
|
@ -458,7 +561,7 @@ class CNotifoMod : public CModule
|
||||||
*/
|
*/
|
||||||
EModRet OnPrivMsg(CNick& nick, CString& message)
|
EModRet OnPrivMsg(CNick& nick, CString& message)
|
||||||
{
|
{
|
||||||
if (notify_pm(nick))
|
if (notify_pm(nick, message))
|
||||||
{
|
{
|
||||||
CString title = "Private Message";
|
CString title = "Private Message";
|
||||||
CString msg = "From " + nick.GetNick();
|
CString msg = "From " + nick.GetNick();
|
||||||
|
@ -478,7 +581,7 @@ class CNotifoMod : public CModule
|
||||||
*/
|
*/
|
||||||
EModRet OnPrivAction(CNick& nick, CString& message)
|
EModRet OnPrivAction(CNick& nick, CString& message)
|
||||||
{
|
{
|
||||||
if (notify_pm(nick))
|
if (notify_pm(nick, message))
|
||||||
{
|
{
|
||||||
CString title = "Private Message";
|
CString title = "Private Message";
|
||||||
CString msg = "* " + nick.GetNick();
|
CString msg = "* " + nick.GetNick();
|
||||||
|
@ -597,6 +700,14 @@ class CNotifoMod : public CModule
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
if (option == "channel_conditions" || option == "query_conditions")
|
||||||
|
{
|
||||||
|
if (value != "all")
|
||||||
|
{
|
||||||
|
eval(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
options[option] = value;
|
options[option] = value;
|
||||||
options[option].Trim();
|
options[option].Trim();
|
||||||
SetNV(option, options[option]);
|
SetNV(option, options[option]);
|
||||||
|
@ -792,6 +903,12 @@ class CNotifoMod : public CModule
|
||||||
{
|
{
|
||||||
PutModule("View the detailed documentation at https://github.com/jreese/znc-notifo/blob/master/README.md");
|
PutModule("View the detailed documentation at https://github.com/jreese/znc-notifo/blob/master/README.md");
|
||||||
}
|
}
|
||||||
|
// EVAL command
|
||||||
|
else if (action == "eval")
|
||||||
|
{
|
||||||
|
CString value = command.Token(1, true, " ");
|
||||||
|
PutModule(eval(value) ? "true" : "false");
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
PutModule("Error: invalid command, try `help`");
|
PutModule("Error: invalid command, try `help`");
|
||||||
|
|
Loading…
Reference in New Issue