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)
|
### [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
|
### 1.1784 - 2021-12-08
|
||||||
|
|
||||||
* Added display option to override widths in original message view
|
* Added display option to override widths in original message view
|
||||||
|
|
|
@ -4,6 +4,12 @@
|
||||||
|
|
||||||
### [Caudipteryx](https://en.wikipedia.org/wiki/Caudipteryx)
|
### [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
|
### 1.1784 - 2021-12-08
|
||||||
|
|
||||||
* Added display option to override widths in original message view
|
* 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));
|
condition.add(context.getString(R.string.title_rule_subject));
|
||||||
if (jcondition.has("header"))
|
if (jcondition.has("header"))
|
||||||
condition.add(context.getString(R.string.title_rule_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"))
|
if (jcondition.has("date"))
|
||||||
condition.add(context.getString(R.string.title_rule_time_abs));
|
condition.add(context.getString(R.string.title_rule_time_abs));
|
||||||
if (jcondition.has("schedule"))
|
if (jcondition.has("schedule"))
|
||||||
|
@ -319,7 +321,7 @@ public class AdapterRule extends RecyclerView.Adapter<AdapterRule.ViewHolder> {
|
||||||
if (message == null)
|
if (message == null)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (rule.matches(context, message, null))
|
if (rule.matches(context, message, null, null))
|
||||||
if (rule.execute(context, message))
|
if (rule.execute(context, message))
|
||||||
applied++;
|
applied++;
|
||||||
|
|
||||||
|
|
|
@ -2800,6 +2800,7 @@ class Core {
|
||||||
|
|
||||||
List<Header> headers =
|
List<Header> headers =
|
||||||
(EntityRule.needsHeaders(rules) ? helper.getAllHeaders() : null);
|
(EntityRule.needsHeaders(rules) ? helper.getAllHeaders() : null);
|
||||||
|
String body = parts.getHtml(context);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
db.beginTransaction();
|
db.beginTransaction();
|
||||||
|
@ -2819,7 +2820,7 @@ class Core {
|
||||||
attachment.id = db.attachment().insertAttachment(attachment);
|
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);
|
reportNewMessage(context, account, folder, message);
|
||||||
|
|
||||||
db.setTransactionSuccessful();
|
db.setTransactionSuccessful();
|
||||||
|
@ -2827,7 +2828,6 @@ class Core {
|
||||||
db.endTransaction();
|
db.endTransaction();
|
||||||
}
|
}
|
||||||
|
|
||||||
String body = parts.getHtml(context);
|
|
||||||
File file = message.getFile(context);
|
File file = message.getFile(context);
|
||||||
Helper.writeText(file, body);
|
Helper.writeText(file, body);
|
||||||
String text = HtmlHelper.getFullText(body);
|
String text = HtmlHelper.getFullText(body);
|
||||||
|
@ -3656,6 +3656,8 @@ class Core {
|
||||||
|
|
||||||
List<Header> headers =
|
List<Header> headers =
|
||||||
(EntityRule.needsHeaders(rules) ? helper.getAllHeaders() : null);
|
(EntityRule.needsHeaders(rules) ? helper.getAllHeaders() : null);
|
||||||
|
String body =
|
||||||
|
(EntityRule.needsBody(rules) ? helper.getMessageParts().getHtml(context) : null);
|
||||||
|
|
||||||
if (message == null) {
|
if (message == null) {
|
||||||
Long sent = helper.getSent();
|
Long sent = helper.getSent();
|
||||||
|
@ -3868,7 +3870,7 @@ class Core {
|
||||||
attachment.id = db.attachment().insertAttachment(attachment);
|
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) {
|
if (message.blocklist != null && message.blocklist) {
|
||||||
boolean use_blocklist = prefs.getBoolean("use_blocklist", false);
|
boolean use_blocklist = prefs.getBoolean("use_blocklist", false);
|
||||||
|
@ -3910,7 +3912,7 @@ class Core {
|
||||||
EntityContact.received(context, account, folder, message);
|
EntityContact.received(context, account, folder, message);
|
||||||
|
|
||||||
// Download small messages inline
|
// Download small messages inline
|
||||||
if (download && !message.ui_hide) {
|
if (body != null || (download && !message.ui_hide)) {
|
||||||
long maxSize;
|
long maxSize;
|
||||||
if (state == null || state.networkState.isUnmetered())
|
if (state == null || state.networkState.isUnmetered())
|
||||||
maxSize = MessageHelper.SMALL_MESSAGE_SIZE;
|
maxSize = MessageHelper.SMALL_MESSAGE_SIZE;
|
||||||
|
@ -3920,10 +3922,12 @@ class Core {
|
||||||
maxSize = MessageHelper.SMALL_MESSAGE_SIZE;
|
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)
|
(MessageClassifier.isEnabled(context)) && folder.auto_classify_source)
|
||||||
try {
|
try {
|
||||||
String body = parts.getHtml(context);
|
if (body == null)
|
||||||
|
body = parts.getHtml(context);
|
||||||
File file = message.getFile(context);
|
File file = message.getFile(context);
|
||||||
Helper.writeText(file, body);
|
Helper.writeText(file, body);
|
||||||
String text = HtmlHelper.getFullText(body);
|
String text = HtmlHelper.getFullText(body);
|
||||||
|
@ -4078,7 +4082,7 @@ class Core {
|
||||||
db.message().updateMessage(message);
|
db.message().updateMessage(message);
|
||||||
|
|
||||||
if (process)
|
if (process)
|
||||||
runRules(context, headers, account, folder, message, rules);
|
runRules(context, headers, body, account, folder, message, rules);
|
||||||
|
|
||||||
db.setTransactionSuccessful();
|
db.setTransactionSuccessful();
|
||||||
} finally {
|
} finally {
|
||||||
|
@ -4241,7 +4245,7 @@ class Core {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void runRules(
|
private static void runRules(
|
||||||
Context context, List<Header> headers,
|
Context context, List<Header> headers, String html,
|
||||||
EntityAccount account, EntityFolder folder, EntityMessage message,
|
EntityAccount account, EntityFolder folder, EntityMessage message,
|
||||||
List<EntityRule> rules) {
|
List<EntityRule> rules) {
|
||||||
|
|
||||||
|
@ -4254,7 +4258,7 @@ class Core {
|
||||||
try {
|
try {
|
||||||
boolean executed = false;
|
boolean executed = false;
|
||||||
for (EntityRule rule : rules)
|
for (EntityRule rule : rules)
|
||||||
if (rule.matches(context, message, headers)) {
|
if (rule.matches(context, message, headers, html)) {
|
||||||
rule.execute(context, message);
|
rule.execute(context, message);
|
||||||
executed = true;
|
executed = true;
|
||||||
if (rule.stop)
|
if (rule.stop)
|
||||||
|
|
|
@ -128,6 +128,10 @@ public class EntityRule {
|
||||||
return needs(rules, "header");
|
return needs(rules, "header");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static boolean needsBody(List<EntityRule> rules) {
|
||||||
|
return needs(rules, "body");
|
||||||
|
}
|
||||||
|
|
||||||
private static boolean needs(List<EntityRule> rules, String what) {
|
private static boolean needs(List<EntityRule> rules, String what) {
|
||||||
for (EntityRule rule : rules)
|
for (EntityRule rule : rules)
|
||||||
try {
|
try {
|
||||||
|
@ -141,7 +145,7 @@ public class EntityRule {
|
||||||
return false;
|
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 {
|
try {
|
||||||
JSONObject jcondition = new JSONObject(condition);
|
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
|
// Date
|
||||||
JSONObject jdate = jcondition.optJSONObject("date");
|
JSONObject jdate = jcondition.optJSONObject("date");
|
||||||
if (jdate != null) {
|
if (jdate != null) {
|
||||||
|
@ -329,6 +356,7 @@ public class EntityRule {
|
||||||
jsubject == null &&
|
jsubject == null &&
|
||||||
!jcondition.optBoolean("attachments") &&
|
!jcondition.optBoolean("attachments") &&
|
||||||
jheader == null &&
|
jheader == null &&
|
||||||
|
jbody == null &&
|
||||||
jdate == null &&
|
jdate == null &&
|
||||||
jschedule == null)
|
jschedule == null)
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -1070,7 +1070,7 @@ public class FragmentFolders extends FragmentBase {
|
||||||
|
|
||||||
for (EntityRule rule : rules) {
|
for (EntityRule rule : rules) {
|
||||||
EntityLog.log(context, "Executing rules evaluating=" + rule.name);
|
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);
|
EntityLog.log(context, "Executing rules matches=" + rule.name);
|
||||||
if (rule.execute(context, message)) {
|
if (rule.execute(context, message)) {
|
||||||
EntityLog.log(context, "Executing rules applied=" + rule.name);
|
EntityLog.log(context, "Executing rules applied=" + rule.name);
|
||||||
|
|
|
@ -105,6 +105,9 @@ public class FragmentRule extends FragmentBase {
|
||||||
private EditText etHeader;
|
private EditText etHeader;
|
||||||
private CheckBox cbHeader;
|
private CheckBox cbHeader;
|
||||||
|
|
||||||
|
private EditText etBody;
|
||||||
|
private CheckBox cbBody;
|
||||||
|
|
||||||
private TextView tvDateAfter;
|
private TextView tvDateAfter;
|
||||||
private TextView tvDateBefore;
|
private TextView tvDateBefore;
|
||||||
private Button btnDateAfter;
|
private Button btnDateAfter;
|
||||||
|
@ -240,6 +243,9 @@ public class FragmentRule extends FragmentBase {
|
||||||
etHeader = view.findViewById(R.id.etHeader);
|
etHeader = view.findViewById(R.id.etHeader);
|
||||||
cbHeader = view.findViewById(R.id.cbHeader);
|
cbHeader = view.findViewById(R.id.cbHeader);
|
||||||
|
|
||||||
|
etBody = view.findViewById(R.id.etBody);
|
||||||
|
cbBody = view.findViewById(R.id.cbBody);
|
||||||
|
|
||||||
tvDateAfter = view.findViewById(R.id.tvDateAfter);
|
tvDateAfter = view.findViewById(R.id.tvDateAfter);
|
||||||
tvDateBefore = view.findViewById(R.id.tvDateBefore);
|
tvDateBefore = view.findViewById(R.id.tvDateBefore);
|
||||||
btnDateAfter = view.findViewById(R.id.btnDateAfter);
|
btnDateAfter = view.findViewById(R.id.btnDateAfter);
|
||||||
|
@ -877,6 +883,7 @@ public class FragmentRule extends FragmentBase {
|
||||||
JSONObject jrecipient = jcondition.optJSONObject("recipient");
|
JSONObject jrecipient = jcondition.optJSONObject("recipient");
|
||||||
JSONObject jsubject = jcondition.optJSONObject("subject");
|
JSONObject jsubject = jcondition.optJSONObject("subject");
|
||||||
JSONObject jheader = jcondition.optJSONObject("header");
|
JSONObject jheader = jcondition.optJSONObject("header");
|
||||||
|
JSONObject jbody = jcondition.optJSONObject("body");
|
||||||
JSONObject jdate = jcondition.optJSONObject("date");
|
JSONObject jdate = jcondition.optJSONObject("date");
|
||||||
JSONObject jschedule = jcondition.optJSONObject("schedule");
|
JSONObject jschedule = jcondition.optJSONObject("schedule");
|
||||||
|
|
||||||
|
@ -905,6 +912,9 @@ public class FragmentRule extends FragmentBase {
|
||||||
etHeader.setText(jheader == null ? null : jheader.getString("value"));
|
etHeader.setText(jheader == null ? null : jheader.getString("value"));
|
||||||
cbHeader.setChecked(jheader != null && jheader.getBoolean("regex"));
|
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 after = (jdate != null && jdate.has("after") ? jdate.getLong("after") : 0);
|
||||||
long before = (jdate != null && jdate.has("before") ? jdate.getLong("before") : 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 jrecipient = jcondition.optJSONObject("recipient");
|
||||||
JSONObject jsubject = jcondition.optJSONObject("subject");
|
JSONObject jsubject = jcondition.optJSONObject("subject");
|
||||||
JSONObject jheader = jcondition.optJSONObject("header");
|
JSONObject jheader = jcondition.optJSONObject("header");
|
||||||
|
JSONObject jbody = jcondition.optJSONObject("body");
|
||||||
JSONObject jdate = jcondition.optJSONObject("date");
|
JSONObject jdate = jcondition.optJSONObject("date");
|
||||||
JSONObject jschedule = jcondition.optJSONObject("schedule");
|
JSONObject jschedule = jcondition.optJSONObject("schedule");
|
||||||
|
|
||||||
|
@ -1126,6 +1137,7 @@ public class FragmentRule extends FragmentBase {
|
||||||
jsubject == null &&
|
jsubject == null &&
|
||||||
!jcondition.optBoolean("attachments") &&
|
!jcondition.optBoolean("attachments") &&
|
||||||
jheader == null &&
|
jheader == null &&
|
||||||
|
jbody == null &&
|
||||||
jdate == null &&
|
jdate == null &&
|
||||||
jschedule == null)
|
jschedule == null)
|
||||||
throw new IllegalArgumentException(context.getString(R.string.title_rule_condition_missing));
|
throw new IllegalArgumentException(context.getString(R.string.title_rule_condition_missing));
|
||||||
|
@ -1220,6 +1232,14 @@ public class FragmentRule extends FragmentBase {
|
||||||
jcondition.put("header", jheader);
|
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 hafter = tvDateAfter.getTag();
|
||||||
Object hbefore = tvDateBefore.getTag();
|
Object hbefore = tvDateBefore.getTag();
|
||||||
|
|
||||||
|
@ -1441,7 +1461,7 @@ public class FragmentRule extends FragmentBase {
|
||||||
if (message == null)
|
if (message == null)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (rule.matches(context, message, null))
|
if (rule.matches(context, message, null, null))
|
||||||
if (rule.execute(context, message))
|
if (rule.execute(context, message))
|
||||||
applied++;
|
applied++;
|
||||||
|
|
||||||
|
@ -1501,7 +1521,7 @@ public class FragmentRule extends FragmentBase {
|
||||||
if (message == null)
|
if (message == null)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (rule.matches(context, message, null))
|
if (rule.matches(context, message, null, null))
|
||||||
matching.add(message);
|
matching.add(message);
|
||||||
|
|
||||||
if (matching.size() >= MAX_CHECK)
|
if (matching.size() >= MAX_CHECK)
|
||||||
|
|
|
@ -408,13 +408,65 @@
|
||||||
app:layout_constraintTop_toBottomOf="@+id/etHeader" />
|
app:layout_constraintTop_toBottomOf="@+id/etHeader" />
|
||||||
|
|
||||||
<View
|
<View
|
||||||
android:id="@+id/vSeparatorDate"
|
android:id="@+id/vSeparatorBody"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="1dp"
|
android:layout_height="1dp"
|
||||||
android:background="?attr/colorSeparator"
|
android:background="?attr/colorSeparator"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@id/tvAndHeader" />
|
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
|
<eu.faircode.email.FixedTextView
|
||||||
android:id="@+id/tvDate"
|
android:id="@+id/tvDate"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
|
|
|
@ -1474,6 +1474,7 @@
|
||||||
<string name="title_rule_attachments">Has attachments</string>
|
<string name="title_rule_attachments">Has attachments</string>
|
||||||
<string name="title_rule_mime_type" translatable="false">Mime type</string>
|
<string name="title_rule_mime_type" translatable="false">Mime type</string>
|
||||||
<string name="title_rule_header">Header contains</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_abs">Absolute time (received) between</string>
|
||||||
<string name="title_rule_time_after">Received after</string>
|
<string name="title_rule_time_after">Received after</string>
|
||||||
<string name="title_rule_time_before">Received before</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_check">Check</string>
|
||||||
<string name="title_rule_no_headers">Header conditions cannot be checked</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_matched">Matching messages</string>
|
||||||
<string name="title_rule_no_matches">No matching messages</string>
|
<string name="title_rule_no_matches">No matching messages</string>
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,12 @@
|
||||||
|
|
||||||
### [Caudipteryx](https://en.wikipedia.org/wiki/Caudipteryx)
|
### [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
|
### 1.1784 - 2021-12-08
|
||||||
|
|
||||||
* Added display option to override widths in original message view
|
* Added display option to override widths in original message view
|
||||||
|
|
Loading…
Reference in New Issue