diff --git a/FAQ.md b/FAQ.md
index 719201e5f1..7086a1a71a 100644
--- a/FAQ.md
+++ b/FAQ.md
@@ -3028,6 +3028,7 @@ The following extra operators are available:
The following extra functions are available:
* *header("name")* (returns an array of header values for the named header)
+* *message("language")* returns the two letter [ISO language code](https://en.wikipedia.org/wiki/List_of_ISO_639_language_codes) of a message; note that it cannot always be determined and that it can be incorrect (since version 1.2330)
* *blocklist()* (version 1.2176-1.2178; deprecated, use *onBlocklist()* instead)
* *onBlocklist()* (returns a boolean indicating if the sender/server is on a DNS blocklist; since version 1.2179)
* *hasMx()* (returns a boolean indicating if the from/reply-to address has an associated MX record; since version 1.2179)
@@ -3050,6 +3051,8 @@ Example conditions:
```AI("Is the message below a scam? Answer in English with just yes or no.") contains "yes"```
+```COALESCE(message("language")) == "en"```
+
**Actions**
diff --git a/app/src/main/java/eu/faircode/email/ExpressionHelper.java b/app/src/main/java/eu/faircode/email/ExpressionHelper.java
index 0010963f0e..94da36c977 100644
--- a/app/src/main/java/eu/faircode/email/ExpressionHelper.java
+++ b/app/src/main/java/eu/faircode/email/ExpressionHelper.java
@@ -108,7 +108,7 @@ public class ExpressionHelper {
}
HeaderFunction fHeader = new HeaderFunction(headers);
- MessageFunction fMessage = new MessageFunction(message);
+ MessageFunction fMessage = new MessageFunction(context, message, doc);
BlocklistFunction fBlocklist = new BlocklistFunction(context, message, headers);
MxFunction fMx = new MxFunction(context, message);
AttachmentsFunction fAttachments = new AttachmentsFunction(context, message);
@@ -189,7 +189,7 @@ public class ExpressionHelper {
Token token = node.getToken();
Log.i("EXPR token=" + token.getType() + ":" + token.getValue());
if (token.getType() == Token.TokenType.FUNCTION &&
- "AI".equalsIgnoreCase(token.getValue())) {
+ ("AI".equalsIgnoreCase(token.getValue()) || "message".equalsIgnoreCase(token.getValue()))) {
Log.i("EXPR needs body");
return true;
}
@@ -232,10 +232,14 @@ public class ExpressionHelper {
@FunctionParameter(name = "value")
public static class MessageFunction extends AbstractFunction {
+ private Context context;
private final EntityMessage message;
+ private final Document doc;
- MessageFunction(EntityMessage message) {
+ MessageFunction(Context context, EntityMessage message, Document doc) {
+ this.context = context;
this.message = message;
+ this.doc = doc;
}
@Override
@@ -246,20 +250,32 @@ public class ExpressionHelper {
try {
if (parameterValues.length == 1) {
String name = parameterValues[0].getStringValue();
- if (name != null && message != null) {
- Field field = message.getClass().getField(name);
- field.setAccessible(true);
- Object value = field.get(message);
- if (value != null)
- result.add(value);
+ if ("language".equalsIgnoreCase(name)) {
+ String language;
+ if (message.language == null)
+ language = (doc == null ? null : HtmlHelper.getLanguage(context, message.subject, doc.text()));
+ else
+ language = message.language;
+ Log.i("EXPR language=" + language);
+ if (language != null)
+ result.add(language);
+ } else {
+ if (name != null && message != null) {
+ Field field = message.getClass().getField(name);
+ field.setAccessible(true);
+ Object value = field.get(message);
+ if (value != null)
+ result.add(value);
+ }
}
}
} catch (Throwable ex) {
Log.e("EXPR", ex);
}
- Log.i("EXPR message(" + parameterValues[0] + ")=" + TextUtils.join(", ", result));
- return EvaluationValue.of(result, ExpressionConfiguration.defaultConfiguration());
+ EvaluationValue val = EvaluationValue.of(result, ExpressionConfiguration.defaultConfiguration());
+ Log.i("EXPR message(" + parameterValues[0] + ")=" + TextUtils.join(", ", result) + " val=" + val);
+ return val;
}
}
diff --git a/index.html b/index.html
index e54f542dd8..70ff44ec89 100644
--- a/index.html
+++ b/index.html
@@ -1658,6 +1658,7 @@ X-Google-Original-From: Somebody <somebody+extra@example.org>
The following extra functions are available:
!onBlocklist() && hasMx() && attachments() > 0
(received + 7*24*60*60*1000) < DT_DATE_TO_EPOCH(DT_NOW())
AI("Is the message below a scam? Answer in English with just yes or no.") contains "yes"
COALESCE(message("language")) == "en"
Actions
You can select one of these actions to apply to matching messages: