mirror of https://github.com/M66B/FairEmail.git
Header rules, improvements
This commit is contained in:
parent
2ac7976681
commit
d9528a3ca4
|
@ -24,10 +24,13 @@ import android.content.Context;
|
||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.util.Enumeration;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
import javax.mail.Address;
|
import javax.mail.Address;
|
||||||
|
import javax.mail.Header;
|
||||||
|
import javax.mail.Message;
|
||||||
|
import javax.mail.MessagingException;
|
||||||
import javax.mail.internet.InternetAddress;
|
import javax.mail.internet.InternetAddress;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
@ -72,13 +75,13 @@ public class EntityRule {
|
||||||
static final int TYPE_UNSEEN = 2;
|
static final int TYPE_UNSEEN = 2;
|
||||||
static final int TYPE_MOVE = 3;
|
static final int TYPE_MOVE = 3;
|
||||||
|
|
||||||
boolean matches(Context context, EntityMessage message) throws IOException {
|
boolean matches(Context context, EntityMessage message, Message imessage) throws MessagingException {
|
||||||
try {
|
try {
|
||||||
JSONObject jcondition = new JSONObject(condition);
|
JSONObject jcondition = new JSONObject(condition);
|
||||||
|
|
||||||
JSONObject jsender = jcondition.optJSONObject("sender");
|
JSONObject jsender = jcondition.optJSONObject("sender");
|
||||||
if (jsender != null) {
|
if (jsender != null) {
|
||||||
String sender = jsender.getString("value");
|
String value = jsender.getString("value");
|
||||||
boolean regex = jsender.getBoolean("regex");
|
boolean regex = jsender.getBoolean("regex");
|
||||||
|
|
||||||
boolean matches = false;
|
boolean matches = false;
|
||||||
|
@ -87,7 +90,7 @@ public class EntityRule {
|
||||||
InternetAddress ia = (InternetAddress) from;
|
InternetAddress ia = (InternetAddress) from;
|
||||||
String personal = ia.getPersonal();
|
String personal = ia.getPersonal();
|
||||||
String formatted = ((personal == null ? "" : personal + " ") + "<" + ia.getAddress() + ">");
|
String formatted = ((personal == null ? "" : personal + " ") + "<" + ia.getAddress() + ">");
|
||||||
if (matches(sender, formatted, regex)) {
|
if (matches(value, formatted, regex)) {
|
||||||
matches = true;
|
matches = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -99,15 +102,34 @@ public class EntityRule {
|
||||||
|
|
||||||
JSONObject jsubject = jcondition.optJSONObject("subject");
|
JSONObject jsubject = jcondition.optJSONObject("subject");
|
||||||
if (jsubject != null) {
|
if (jsubject != null) {
|
||||||
String subject = jsubject.getString("value");
|
String value = jsubject.getString("value");
|
||||||
boolean regex = jsubject.getBoolean("regex");
|
boolean regex = jsubject.getBoolean("regex");
|
||||||
|
|
||||||
if (!matches(subject, message.subject, regex))
|
if (!matches(value, message.subject, regex))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSONObject jheader = jcondition.optJSONObject("header");
|
||||||
|
if (jheader != null) {
|
||||||
|
String value = jheader.getString("value");
|
||||||
|
boolean regex = jheader.getBoolean("regex");
|
||||||
|
|
||||||
|
boolean matches = false;
|
||||||
|
Enumeration<Header> headers = imessage.getAllHeaders();
|
||||||
|
while (headers.hasMoreElements()) {
|
||||||
|
Header header = headers.nextElement();
|
||||||
|
String formatted = header.getName() + ": " + header.getValue();
|
||||||
|
if (matches(value, formatted, regex)) {
|
||||||
|
matches = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!matches)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Safeguard
|
// Safeguard
|
||||||
if (jsender == null && jsubject == null)
|
if (jsender == null && jsubject == null && jheader == null)
|
||||||
return false;
|
return false;
|
||||||
} catch (JSONException ex) {
|
} catch (JSONException ex) {
|
||||||
Log.e(ex);
|
Log.e(ex);
|
||||||
|
@ -127,7 +149,7 @@ public class EntityRule {
|
||||||
Pattern pattern = Pattern.compile(needle);
|
Pattern pattern = Pattern.compile(needle);
|
||||||
return pattern.matcher(haystack).matches();
|
return pattern.matcher(haystack).matches();
|
||||||
} else
|
} else
|
||||||
return haystack.contains(needle);
|
return haystack.toLowerCase().contains(needle.toLowerCase());
|
||||||
}
|
}
|
||||||
|
|
||||||
void execute(Context context, DB db, EntityMessage message) {
|
void execute(Context context, DB db, EntityMessage message) {
|
||||||
|
|
|
@ -56,6 +56,8 @@ public class FragmentRule extends FragmentBase {
|
||||||
private CheckBox cbSender;
|
private CheckBox cbSender;
|
||||||
private EditText etSubject;
|
private EditText etSubject;
|
||||||
private CheckBox cbSubject;
|
private CheckBox cbSubject;
|
||||||
|
private EditText etHeader;
|
||||||
|
private CheckBox cbHeader;
|
||||||
private Spinner spAction;
|
private Spinner spAction;
|
||||||
private Spinner spTarget;
|
private Spinner spTarget;
|
||||||
private BottomNavigationView bottom_navigation;
|
private BottomNavigationView bottom_navigation;
|
||||||
|
@ -95,6 +97,8 @@ public class FragmentRule extends FragmentBase {
|
||||||
cbSender = view.findViewById(R.id.cbSender);
|
cbSender = view.findViewById(R.id.cbSender);
|
||||||
etSubject = view.findViewById(R.id.etSubject);
|
etSubject = view.findViewById(R.id.etSubject);
|
||||||
cbSubject = view.findViewById(R.id.cbSubject);
|
cbSubject = view.findViewById(R.id.cbSubject);
|
||||||
|
etHeader = view.findViewById(R.id.etHeader);
|
||||||
|
cbHeader = view.findViewById(R.id.cbHeader);
|
||||||
spAction = view.findViewById(R.id.spAction);
|
spAction = view.findViewById(R.id.spAction);
|
||||||
spTarget = view.findViewById(R.id.spTarget);
|
spTarget = view.findViewById(R.id.spTarget);
|
||||||
bottom_navigation = view.findViewById(R.id.bottom_navigation);
|
bottom_navigation = view.findViewById(R.id.bottom_navigation);
|
||||||
|
@ -208,6 +212,7 @@ public class FragmentRule extends FragmentBase {
|
||||||
|
|
||||||
JSONObject jsender = jcondition.optJSONObject("sender");
|
JSONObject jsender = jcondition.optJSONObject("sender");
|
||||||
JSONObject jsubject = jcondition.optJSONObject("subject");
|
JSONObject jsubject = jcondition.optJSONObject("subject");
|
||||||
|
JSONObject jheader = jcondition.optJSONObject("header");
|
||||||
|
|
||||||
etName.setText(rule == null ? null : rule.name);
|
etName.setText(rule == null ? null : rule.name);
|
||||||
etOrder.setText(rule == null ? null : Integer.toString(rule.order));
|
etOrder.setText(rule == null ? null : Integer.toString(rule.order));
|
||||||
|
@ -217,6 +222,8 @@ public class FragmentRule extends FragmentBase {
|
||||||
cbSender.setChecked(jsender != null && jsender.optBoolean("regex", false));
|
cbSender.setChecked(jsender != null && jsender.optBoolean("regex", false));
|
||||||
etSubject.setText(jsubject == null ? null : jsubject.optString("value"));
|
etSubject.setText(jsubject == null ? null : jsubject.optString("value"));
|
||||||
cbSubject.setChecked(jsubject != null && jsubject.optBoolean("regex", false));
|
cbSubject.setChecked(jsubject != null && jsubject.optBoolean("regex", false));
|
||||||
|
etHeader.setText(jheader == null ? null : jheader.optString("value"));
|
||||||
|
cbHeader.setChecked(jheader != null && jheader.optBoolean("regex", false));
|
||||||
|
|
||||||
int type = jaction.optInt("type", -1);
|
int type = jaction.optInt("type", -1);
|
||||||
for (int pos = 0; pos < adapterAction.getCount(); pos++)
|
for (int pos = 0; pos < adapterAction.getCount(); pos++)
|
||||||
|
@ -329,6 +336,14 @@ public class FragmentRule extends FragmentBase {
|
||||||
jcondition.put("subject", jsubject);
|
jcondition.put("subject", jsubject);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String header = etHeader.getText().toString();
|
||||||
|
if (!TextUtils.isEmpty(header)) {
|
||||||
|
JSONObject jheader = new JSONObject();
|
||||||
|
jheader.put("value", header);
|
||||||
|
jheader.put("regex", cbHeader.isChecked());
|
||||||
|
jcondition.put("header", jheader);
|
||||||
|
}
|
||||||
|
|
||||||
JSONObject jaction = new JSONObject();
|
JSONObject jaction = new JSONObject();
|
||||||
|
|
||||||
Action action = (Action) spAction.getSelectedItem();
|
Action action = (Action) spAction.getSelectedItem();
|
||||||
|
@ -378,8 +393,9 @@ public class FragmentRule extends FragmentBase {
|
||||||
JSONObject jcondition = new JSONObject(condition);
|
JSONObject jcondition = new JSONObject(condition);
|
||||||
JSONObject jsender = jcondition.optJSONObject("sender");
|
JSONObject jsender = jcondition.optJSONObject("sender");
|
||||||
JSONObject jsubject = jcondition.optJSONObject("subject");
|
JSONObject jsubject = jcondition.optJSONObject("subject");
|
||||||
|
JSONObject jheader = jcondition.optJSONObject("header");
|
||||||
|
|
||||||
if (jsender == null && jsubject == null)
|
if (jsender == null && jsubject == null && jheader == null)
|
||||||
throw new IllegalArgumentException(context.getString(R.string.title_rule_condition_missing));
|
throw new IllegalArgumentException(context.getString(R.string.title_rule_condition_missing));
|
||||||
|
|
||||||
if (TextUtils.isEmpty(order))
|
if (TextUtils.isEmpty(order))
|
||||||
|
|
|
@ -2589,7 +2589,7 @@ public class ServiceSynchronize extends LifecycleService {
|
||||||
|
|
||||||
if (filter)
|
if (filter)
|
||||||
for (EntityRule rule : rules)
|
for (EntityRule rule : rules)
|
||||||
if (rule.matches(context, message)) {
|
if (rule.matches(context, message, imessage)) {
|
||||||
rule.execute(context, db, message);
|
rule.execute(context, db, message);
|
||||||
if (rule.stop)
|
if (rule.stop)
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -104,6 +104,7 @@
|
||||||
android:id="@+id/etSender"
|
android:id="@+id/etSender"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="@string/title_optional"
|
||||||
android:inputType="textEmailAddress"
|
android:inputType="textEmailAddress"
|
||||||
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
|
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
@ -148,12 +149,58 @@
|
||||||
android:id="@+id/etSubject"
|
android:id="@+id/etSubject"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:inputType="textEmailAddress"
|
android:hint="@string/title_optional"
|
||||||
|
android:inputType="text"
|
||||||
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
|
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@id/cbSubject" />
|
app:layout_constraintTop_toBottomOf="@id/cbSubject" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvAndSubject"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="12dp"
|
||||||
|
android:text="@string/title_rule_and"
|
||||||
|
android:textAppearance="@style/Base.TextAppearance.AppCompat.Medium"
|
||||||
|
android:textColor="?android:attr/textColorPrimary"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/etSubject" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvHeader"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:text="@string/title_rule_header"
|
||||||
|
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||||
|
app:layout_constraintBottom_toBottomOf="@+id/cbHeader"
|
||||||
|
app:layout_constraintEnd_toStartOf="@+id/cbHeader"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="@+id/cbHeader" />
|
||||||
|
|
||||||
|
<CheckBox
|
||||||
|
android:id="@+id/cbHeader"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="12dp"
|
||||||
|
android:text="@string/title_rule_regex"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/tvAndSubject" />
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/etHeader"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="@string/title_optional"
|
||||||
|
android:inputType="text"
|
||||||
|
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/cbHeader" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/tvAction"
|
android:id="@+id/tvAction"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
|
@ -162,7 +209,7 @@
|
||||||
android:text="@string/title_rule_action"
|
android:text="@string/title_rule_action"
|
||||||
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/etSubject" />
|
app:layout_constraintTop_toBottomOf="@+id/etHeader" />
|
||||||
|
|
||||||
<Spinner
|
<Spinner
|
||||||
android:id="@+id/spAction"
|
android:id="@+id/spAction"
|
||||||
|
@ -172,35 +219,26 @@
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@id/tvAction" />
|
app:layout_constraintTop_toBottomOf="@id/tvAction" />
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/tvTarget"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginTop="12dp"
|
|
||||||
android:text="@string/title_rule_target"
|
|
||||||
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/spAction" />
|
|
||||||
|
|
||||||
<Spinner
|
<Spinner
|
||||||
android:id="@+id/spTarget"
|
android:id="@+id/spTarget"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="12dp"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@id/tvTarget" />
|
app:layout_constraintTop_toBottomOf="@id/spAction" />
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.Group
|
<androidx.constraintlayout.widget.Group
|
||||||
android:id="@+id/grpReady"
|
android:id="@+id/grpReady"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="0dp"
|
android:layout_height="0dp"
|
||||||
app:constraint_referenced_ids="tvName,etName,tvOrder,etOrder,cbEnabled,cbStop,tvSender,etSender,cbSender,tvAndSender,tvSubject,etSubject,cbSubject,tvAction,spAction,tvTarget,spTarget" />
|
app:constraint_referenced_ids="tvName,etName,tvOrder,etOrder,cbEnabled,cbStop,tvSender,cbSender,etSender,tvAndSender,tvSubject,cbSubject,etSubject,tvAction,spAction" />
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.Group
|
<androidx.constraintlayout.widget.Group
|
||||||
android:id="@+id/grpMove"
|
android:id="@+id/grpMove"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="0dp"
|
android:layout_height="0dp"
|
||||||
app:constraint_referenced_ids="tvTarget,spTarget" />
|
app:constraint_referenced_ids="spTarget" />
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
|
|
||||||
|
|
|
@ -390,8 +390,6 @@
|
||||||
<string name="title_rule_regex">Regex</string>
|
<string name="title_rule_regex">Regex</string>
|
||||||
<string name="title_rule_and">AND</string>
|
<string name="title_rule_and">AND</string>
|
||||||
<string name="title_rule_action">Action</string>
|
<string name="title_rule_action">Action</string>
|
||||||
<string name="title_rule_target">To</string>
|
|
||||||
<string name="title_rule_seen">Mark as read</string>
|
|
||||||
<string name="title_rule_name_missing">Rule name missing</string>
|
<string name="title_rule_name_missing">Rule name missing</string>
|
||||||
<string name="title_rule_condition_missing">Condition missing</string>
|
<string name="title_rule_condition_missing">Condition missing</string>
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue