mirror of https://github.com/M66B/FairEmail.git
Added text contains filter rule condition
This commit is contained in:
parent
1190111069
commit
394134c1e5
|
@ -4,6 +4,12 @@
|
|||
|
||||
### [Caudipteryx](https://en.wikipedia.org/wiki/Caudipteryx)
|
||||
|
||||
### Next version
|
||||
|
||||
* Added text contains filter rule condition
|
||||
* Small improvements and minor bug fixes
|
||||
* Updated translations
|
||||
|
||||
### 1.1784 - 2021-12-08
|
||||
|
||||
* Added display option to override widths in original message view
|
||||
|
|
|
@ -4,6 +4,12 @@
|
|||
|
||||
### [Caudipteryx](https://en.wikipedia.org/wiki/Caudipteryx)
|
||||
|
||||
### Next version
|
||||
|
||||
* Added text contains filter rule condition
|
||||
* Small improvements and minor bug fixes
|
||||
* Updated translations
|
||||
|
||||
### 1.1784 - 2021-12-08
|
||||
|
||||
* Added display option to override widths in original message view
|
||||
|
|
|
@ -126,6 +126,8 @@ public class AdapterRule extends RecyclerView.Adapter<AdapterRule.ViewHolder> {
|
|||
condition.add(context.getString(R.string.title_rule_subject));
|
||||
if (jcondition.has("header"))
|
||||
condition.add(context.getString(R.string.title_rule_header));
|
||||
if (jcondition.has("body"))
|
||||
condition.add(context.getString(R.string.title_rule_body));
|
||||
if (jcondition.has("date"))
|
||||
condition.add(context.getString(R.string.title_rule_time_abs));
|
||||
if (jcondition.has("schedule"))
|
||||
|
@ -319,7 +321,7 @@ public class AdapterRule extends RecyclerView.Adapter<AdapterRule.ViewHolder> {
|
|||
if (message == null)
|
||||
continue;
|
||||
|
||||
if (rule.matches(context, message, null))
|
||||
if (rule.matches(context, message, null, null))
|
||||
if (rule.execute(context, message))
|
||||
applied++;
|
||||
|
||||
|
|
|
@ -2800,6 +2800,7 @@ class Core {
|
|||
|
||||
List<Header> headers =
|
||||
(EntityRule.needsHeaders(rules) ? helper.getAllHeaders() : null);
|
||||
String body = parts.getHtml(context);
|
||||
|
||||
try {
|
||||
db.beginTransaction();
|
||||
|
@ -2819,7 +2820,7 @@ class Core {
|
|||
attachment.id = db.attachment().insertAttachment(attachment);
|
||||
}
|
||||
|
||||
runRules(context, headers, account, folder, message, rules);
|
||||
runRules(context, headers, body, account, folder, message, rules);
|
||||
reportNewMessage(context, account, folder, message);
|
||||
|
||||
db.setTransactionSuccessful();
|
||||
|
@ -2827,7 +2828,6 @@ class Core {
|
|||
db.endTransaction();
|
||||
}
|
||||
|
||||
String body = parts.getHtml(context);
|
||||
File file = message.getFile(context);
|
||||
Helper.writeText(file, body);
|
||||
String text = HtmlHelper.getFullText(body);
|
||||
|
@ -3656,6 +3656,8 @@ class Core {
|
|||
|
||||
List<Header> headers =
|
||||
(EntityRule.needsHeaders(rules) ? helper.getAllHeaders() : null);
|
||||
String body =
|
||||
(EntityRule.needsBody(rules) ? helper.getMessageParts().getHtml(context) : null);
|
||||
|
||||
if (message == null) {
|
||||
Long sent = helper.getSent();
|
||||
|
@ -3868,7 +3870,7 @@ class Core {
|
|||
attachment.id = db.attachment().insertAttachment(attachment);
|
||||
}
|
||||
|
||||
runRules(context, headers, account, folder, message, rules);
|
||||
runRules(context, headers, body, account, folder, message, rules);
|
||||
|
||||
if (message.blocklist != null && message.blocklist) {
|
||||
boolean use_blocklist = prefs.getBoolean("use_blocklist", false);
|
||||
|
@ -3910,7 +3912,7 @@ class Core {
|
|||
EntityContact.received(context, account, folder, message);
|
||||
|
||||
// Download small messages inline
|
||||
if (download && !message.ui_hide) {
|
||||
if (body != null || (download && !message.ui_hide)) {
|
||||
long maxSize;
|
||||
if (state == null || state.networkState.isUnmetered())
|
||||
maxSize = MessageHelper.SMALL_MESSAGE_SIZE;
|
||||
|
@ -3920,10 +3922,12 @@ class Core {
|
|||
maxSize = MessageHelper.SMALL_MESSAGE_SIZE;
|
||||
}
|
||||
|
||||
if ((message.size != null && message.size < maxSize) ||
|
||||
if (body != null ||
|
||||
(message.size != null && message.size < maxSize) ||
|
||||
(MessageClassifier.isEnabled(context)) && folder.auto_classify_source)
|
||||
try {
|
||||
String body = parts.getHtml(context);
|
||||
if (body == null)
|
||||
body = parts.getHtml(context);
|
||||
File file = message.getFile(context);
|
||||
Helper.writeText(file, body);
|
||||
String text = HtmlHelper.getFullText(body);
|
||||
|
@ -4078,7 +4082,7 @@ class Core {
|
|||
db.message().updateMessage(message);
|
||||
|
||||
if (process)
|
||||
runRules(context, headers, account, folder, message, rules);
|
||||
runRules(context, headers, body, account, folder, message, rules);
|
||||
|
||||
db.setTransactionSuccessful();
|
||||
} finally {
|
||||
|
@ -4241,7 +4245,7 @@ class Core {
|
|||
}
|
||||
|
||||
private static void runRules(
|
||||
Context context, List<Header> headers,
|
||||
Context context, List<Header> headers, String html,
|
||||
EntityAccount account, EntityFolder folder, EntityMessage message,
|
||||
List<EntityRule> rules) {
|
||||
|
||||
|
@ -4254,7 +4258,7 @@ class Core {
|
|||
try {
|
||||
boolean executed = false;
|
||||
for (EntityRule rule : rules)
|
||||
if (rule.matches(context, message, headers)) {
|
||||
if (rule.matches(context, message, headers, html)) {
|
||||
rule.execute(context, message);
|
||||
executed = true;
|
||||
if (rule.stop)
|
||||
|
|
|
@ -128,6 +128,10 @@ public class EntityRule {
|
|||
return needs(rules, "header");
|
||||
}
|
||||
|
||||
static boolean needsBody(List<EntityRule> rules) {
|
||||
return needs(rules, "body");
|
||||
}
|
||||
|
||||
private static boolean needs(List<EntityRule> rules, String what) {
|
||||
for (EntityRule rule : rules)
|
||||
try {
|
||||
|
@ -141,7 +145,7 @@ public class EntityRule {
|
|||
return false;
|
||||
}
|
||||
|
||||
boolean matches(Context context, EntityMessage message, List<Header> headers) throws MessagingException {
|
||||
boolean matches(Context context, EntityMessage message, List<Header> headers, String html) throws MessagingException {
|
||||
try {
|
||||
JSONObject jcondition = new JSONObject(condition);
|
||||
|
||||
|
@ -297,6 +301,29 @@ public class EntityRule {
|
|||
}
|
||||
}
|
||||
|
||||
// Body
|
||||
JSONObject jbody = jcondition.optJSONObject("body");
|
||||
if (jbody != null) {
|
||||
String value = jbody.getString("value");
|
||||
boolean regex = jbody.getBoolean("regex");
|
||||
|
||||
if (html == null && message.content) {
|
||||
File file = message.getFile(context);
|
||||
try {
|
||||
html = Helper.readText(file);
|
||||
} catch (IOException ex) {
|
||||
Log.e(ex);
|
||||
}
|
||||
}
|
||||
|
||||
if (html == null)
|
||||
throw new IllegalArgumentException(context.getString(R.string.title_rule_no_body));
|
||||
|
||||
String text = HtmlHelper.getFullText(html);
|
||||
if (!matches(context, message, value, text, regex))
|
||||
return false;
|
||||
}
|
||||
|
||||
// Date
|
||||
JSONObject jdate = jcondition.optJSONObject("date");
|
||||
if (jdate != null) {
|
||||
|
@ -329,6 +356,7 @@ public class EntityRule {
|
|||
jsubject == null &&
|
||||
!jcondition.optBoolean("attachments") &&
|
||||
jheader == null &&
|
||||
jbody == null &&
|
||||
jdate == null &&
|
||||
jschedule == null)
|
||||
return false;
|
||||
|
|
|
@ -1070,7 +1070,7 @@ public class FragmentFolders extends FragmentBase {
|
|||
|
||||
for (EntityRule rule : rules) {
|
||||
EntityLog.log(context, "Executing rules evaluating=" + rule.name);
|
||||
if (rule.matches(context, message, null)) {
|
||||
if (rule.matches(context, message, null, null)) {
|
||||
EntityLog.log(context, "Executing rules matches=" + rule.name);
|
||||
if (rule.execute(context, message)) {
|
||||
EntityLog.log(context, "Executing rules applied=" + rule.name);
|
||||
|
|
|
@ -105,6 +105,9 @@ public class FragmentRule extends FragmentBase {
|
|||
private EditText etHeader;
|
||||
private CheckBox cbHeader;
|
||||
|
||||
private EditText etBody;
|
||||
private CheckBox cbBody;
|
||||
|
||||
private TextView tvDateAfter;
|
||||
private TextView tvDateBefore;
|
||||
private Button btnDateAfter;
|
||||
|
@ -240,6 +243,9 @@ public class FragmentRule extends FragmentBase {
|
|||
etHeader = view.findViewById(R.id.etHeader);
|
||||
cbHeader = view.findViewById(R.id.cbHeader);
|
||||
|
||||
etBody = view.findViewById(R.id.etBody);
|
||||
cbBody = view.findViewById(R.id.cbBody);
|
||||
|
||||
tvDateAfter = view.findViewById(R.id.tvDateAfter);
|
||||
tvDateBefore = view.findViewById(R.id.tvDateBefore);
|
||||
btnDateAfter = view.findViewById(R.id.btnDateAfter);
|
||||
|
@ -877,6 +883,7 @@ public class FragmentRule extends FragmentBase {
|
|||
JSONObject jrecipient = jcondition.optJSONObject("recipient");
|
||||
JSONObject jsubject = jcondition.optJSONObject("subject");
|
||||
JSONObject jheader = jcondition.optJSONObject("header");
|
||||
JSONObject jbody = jcondition.optJSONObject("body");
|
||||
JSONObject jdate = jcondition.optJSONObject("date");
|
||||
JSONObject jschedule = jcondition.optJSONObject("schedule");
|
||||
|
||||
|
@ -905,6 +912,9 @@ public class FragmentRule extends FragmentBase {
|
|||
etHeader.setText(jheader == null ? null : jheader.getString("value"));
|
||||
cbHeader.setChecked(jheader != null && jheader.getBoolean("regex"));
|
||||
|
||||
etBody.setText(jbody == null ? null : jbody.getString("value"));
|
||||
cbBody.setChecked(jbody != null && jbody.getBoolean("regex"));
|
||||
|
||||
long after = (jdate != null && jdate.has("after") ? jdate.getLong("after") : 0);
|
||||
long before = (jdate != null && jdate.has("before") ? jdate.getLong("before") : 0);
|
||||
|
||||
|
@ -1118,6 +1128,7 @@ public class FragmentRule extends FragmentBase {
|
|||
JSONObject jrecipient = jcondition.optJSONObject("recipient");
|
||||
JSONObject jsubject = jcondition.optJSONObject("subject");
|
||||
JSONObject jheader = jcondition.optJSONObject("header");
|
||||
JSONObject jbody = jcondition.optJSONObject("body");
|
||||
JSONObject jdate = jcondition.optJSONObject("date");
|
||||
JSONObject jschedule = jcondition.optJSONObject("schedule");
|
||||
|
||||
|
@ -1126,6 +1137,7 @@ public class FragmentRule extends FragmentBase {
|
|||
jsubject == null &&
|
||||
!jcondition.optBoolean("attachments") &&
|
||||
jheader == null &&
|
||||
jbody == null &&
|
||||
jdate == null &&
|
||||
jschedule == null)
|
||||
throw new IllegalArgumentException(context.getString(R.string.title_rule_condition_missing));
|
||||
|
@ -1220,6 +1232,14 @@ public class FragmentRule extends FragmentBase {
|
|||
jcondition.put("header", jheader);
|
||||
}
|
||||
|
||||
String body = etBody.getText().toString();
|
||||
if (!TextUtils.isEmpty(body)) {
|
||||
JSONObject jbody = new JSONObject();
|
||||
jbody.put("value", body);
|
||||
jbody.put("regex", cbBody.isChecked());
|
||||
jcondition.put("body", jbody);
|
||||
}
|
||||
|
||||
Object hafter = tvDateAfter.getTag();
|
||||
Object hbefore = tvDateBefore.getTag();
|
||||
|
||||
|
@ -1441,7 +1461,7 @@ public class FragmentRule extends FragmentBase {
|
|||
if (message == null)
|
||||
continue;
|
||||
|
||||
if (rule.matches(context, message, null))
|
||||
if (rule.matches(context, message, null, null))
|
||||
if (rule.execute(context, message))
|
||||
applied++;
|
||||
|
||||
|
@ -1501,7 +1521,7 @@ public class FragmentRule extends FragmentBase {
|
|||
if (message == null)
|
||||
continue;
|
||||
|
||||
if (rule.matches(context, message, null))
|
||||
if (rule.matches(context, message, null, null))
|
||||
matching.add(message);
|
||||
|
||||
if (matching.size() >= MAX_CHECK)
|
||||
|
|
|
@ -408,13 +408,65 @@
|
|||
app:layout_constraintTop_toBottomOf="@+id/etHeader" />
|
||||
|
||||
<View
|
||||
android:id="@+id/vSeparatorDate"
|
||||
android:id="@+id/vSeparatorBody"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:background="?attr/colorSeparator"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/tvAndHeader" />
|
||||
|
||||
<eu.faircode.email.FixedTextView
|
||||
android:id="@+id/tvBody"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="end"
|
||||
android:singleLine="true"
|
||||
android:text="@string/title_rule_body"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/cbBody"
|
||||
app:layout_constraintEnd_toStartOf="@+id/cbBody"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@+id/cbBody" />
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/cbBody"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/title_rule_regex"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/vSeparatorBody" />
|
||||
|
||||
<eu.faircode.email.EditTextPlain
|
||||
android:id="@+id/etBody"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/title_optional"
|
||||
android:inputType="text|textNoSuggestions"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/cbBody" />
|
||||
|
||||
<eu.faircode.email.FixedTextView
|
||||
android:id="@+id/tvAndBody"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="12dp"
|
||||
android:text="@string/title_rule_and"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
|
||||
android:textColor="?android:attr/textColorPrimary"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/etBody" />
|
||||
|
||||
<View
|
||||
android:id="@+id/vSeparatorDate"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:background="?attr/colorSeparator"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/tvAndBody" />
|
||||
|
||||
<eu.faircode.email.FixedTextView
|
||||
android:id="@+id/tvDate"
|
||||
android:layout_width="0dp"
|
||||
|
|
|
@ -1474,6 +1474,7 @@
|
|||
<string name="title_rule_attachments">Has attachments</string>
|
||||
<string name="title_rule_mime_type" translatable="false">Mime type</string>
|
||||
<string name="title_rule_header">Header contains</string>
|
||||
<string name="title_rule_body">Text contains</string>
|
||||
<string name="title_rule_time_abs">Absolute time (received) between</string>
|
||||
<string name="title_rule_time_after">Received after</string>
|
||||
<string name="title_rule_time_before">Received before</string>
|
||||
|
@ -1505,6 +1506,7 @@
|
|||
|
||||
<string name="title_rule_check">Check</string>
|
||||
<string name="title_rule_no_headers">Header conditions cannot be checked</string>
|
||||
<string name="title_rule_no_body">Message text not available</string>
|
||||
<string name="title_rule_matched">Matching messages</string>
|
||||
<string name="title_rule_no_matches">No matching messages</string>
|
||||
|
||||
|
|
|
@ -4,6 +4,12 @@
|
|||
|
||||
### [Caudipteryx](https://en.wikipedia.org/wiki/Caudipteryx)
|
||||
|
||||
### Next version
|
||||
|
||||
* Added text contains filter rule condition
|
||||
* Small improvements and minor bug fixes
|
||||
* Updated translations
|
||||
|
||||
### 1.1784 - 2021-12-08
|
||||
|
||||
* Added display option to override widths in original message view
|
||||
|
|
Loading…
Reference in New Issue