diff --git a/FAQ.md b/FAQ.md
index 140ebccfee..2824b6004f 100644
--- a/FAQ.md
+++ b/FAQ.md
@@ -2768,6 +2768,15 @@ The filter rules will move the messages to a (sub) archive folder as a second st
The POP3 protocol does not support setting keywords and moving or copying messages.
+
+
+Since version 1.2061 it is possible to execute rules with an automation app, like for example Tasker.
+
+
+```
+(adb shell) am start-foreground-service -a eu.faircode.email.RULE --es account -e rule
+```
+
Using rules is a pro feature.
diff --git a/app/src/amazon/AndroidManifest.xml b/app/src/amazon/AndroidManifest.xml
index a440fa3242..d6193395ff 100644
--- a/app/src/amazon/AndroidManifest.xml
+++ b/app/src/amazon/AndroidManifest.xml
@@ -561,6 +561,7 @@
+
diff --git a/app/src/fdroid/AndroidManifest.xml b/app/src/fdroid/AndroidManifest.xml
index 55e66340ba..089d2c2c23 100644
--- a/app/src/fdroid/AndroidManifest.xml
+++ b/app/src/fdroid/AndroidManifest.xml
@@ -567,6 +567,7 @@
+
diff --git a/app/src/github/AndroidManifest.xml b/app/src/github/AndroidManifest.xml
index ab00db5a5a..819f0f9eae 100644
--- a/app/src/github/AndroidManifest.xml
+++ b/app/src/github/AndroidManifest.xml
@@ -567,6 +567,7 @@
+
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 3d7163a133..f50c7663ed 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -559,6 +559,7 @@
+
diff --git a/app/src/main/java/eu/faircode/email/DaoRule.java b/app/src/main/java/eu/faircode/email/DaoRule.java
index b3859c2998..7182622ccc 100644
--- a/app/src/main/java/eu/faircode/email/DaoRule.java
+++ b/app/src/main/java/eu/faircode/email/DaoRule.java
@@ -47,6 +47,12 @@ public interface DaoRule {
" WHERE rule.id = :id")
TupleRuleEx getRule(long id);
+ @Query("SELECT rule.* FROM rule" +
+ " JOIN folder ON folder.id = rule.folder" +
+ " WHERE folder.account = :account" +
+ " AND rule.name = :name")
+ List getRuleByName(long account, String name);
+
@Query("SELECT * FROM rule WHERE uuid = :uuid")
EntityRule getRuleByUUID(String uuid);
diff --git a/app/src/main/java/eu/faircode/email/ServiceExternal.java b/app/src/main/java/eu/faircode/email/ServiceExternal.java
index dfc82ae9af..dd39847040 100644
--- a/app/src/main/java/eu/faircode/email/ServiceExternal.java
+++ b/app/src/main/java/eu/faircode/email/ServiceExternal.java
@@ -37,17 +37,21 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+import javax.mail.MessagingException;
+
public class ServiceExternal extends Service {
private static final String ACTION_POLL = BuildConfig.APPLICATION_ID + ".POLL";
private static final String ACTION_ENABLE = BuildConfig.APPLICATION_ID + ".ENABLE";
private static final String ACTION_DISABLE = BuildConfig.APPLICATION_ID + ".DISABLE";
private static final String ACTION_INTERVAL = BuildConfig.APPLICATION_ID + ".INTERVAL";
+ private static final String ACTION_RULE = BuildConfig.APPLICATION_ID + ".RULE";
private static final String ACTION_DISCONNECT_ME = BuildConfig.APPLICATION_ID + ".DISCONNECT.ME";
// adb shell am start-foreground-service -a eu.faircode.email.POLL --es account Gmail
// adb shell am start-foreground-service -a eu.faircode.email.ENABLE --es account Gmail
// adb shell am start-foreground-service -a eu.faircode.email.DISABLE --es account Gmail
// adb shell am start-foreground-service -a eu.faircode.email.INTERVAL --ei minutes {0, 15, 30, 60, 120, 240, 480, 1440}
+ // adb shell am start-foreground-service -a eu.faircode.email.RULE --es account Gmail -e rule Test
// adb shell am start-foreground-service -a eu.faircode.email.DISCONNECT
@Override
@@ -96,6 +100,9 @@ public class ServiceExternal extends Service {
case ACTION_INTERVAL:
interval(context, intent);
break;
+ case ACTION_RULE:
+ rule(context, intent);
+ break;
case ACTION_DISCONNECT_ME:
disconnect(context, intent);
break;
@@ -196,6 +203,53 @@ public class ServiceExternal extends Service {
ServiceSynchronize.eval(context, "external account=" + accountName + " enabled=" + enabled);
}
+ private static void rule(Context context, Intent intent) throws IOException, JSONException, MessagingException {
+ String accountName = intent.getStringExtra("account");
+ String ruleName = intent.getStringExtra("rule");
+
+ DB db = DB.getInstance(context);
+ EntityAccount account = db.account().getAccount(accountName);
+ if (account == null)
+ throw new IllegalArgumentException("Account not found name=" + accountName);
+
+ List rules = db.rule().getRuleByName(account.id, ruleName);
+ if (rules == null || rules.size() == 0)
+ throw new IllegalArgumentException("Rule not found name=" + ruleName);
+ if (rules.size() != 1)
+ throw new IllegalArgumentException("Rule ambiguous name=" + ruleName);
+
+ EntityRule rule = rules.get(0);
+ List ids = db.message().getMessageIdsByFolder(rule.folder);
+ if (ids == null || ids.size() == 0)
+ return;
+
+ // Check header conditions
+ for (long mid : ids) {
+ EntityMessage message = db.message().getMessage(mid);
+ if (message == null || message.ui_hide)
+ continue;
+ rule.matches(context, message, null, null);
+ }
+
+ int applied = 0;
+ for (long mid : ids)
+ try {
+ db.beginTransaction();
+
+ EntityMessage message = db.message().getMessage(mid);
+ if (message == null || message.ui_hide)
+ continue;
+
+ EntityLog.log(context, "Executing rules message=" + message.id);
+ applied = EntityRule.run(context, rules, message, null, null);
+
+ db.setTransactionSuccessful();
+ } finally {
+ db.endTransaction();
+ }
+ EntityLog.log(context, "Executing rule=" + rule.name + " applied=" + applied);
+ }
+
private static void disconnect(Context context, Intent intent) throws IOException, JSONException {
DisconnectBlacklist.download(context);
}
diff --git a/app/src/play/AndroidManifest.xml b/app/src/play/AndroidManifest.xml
index 5e9b9d70a8..ccc256f35e 100644
--- a/app/src/play/AndroidManifest.xml
+++ b/app/src/play/AndroidManifest.xml
@@ -561,6 +561,7 @@
+