Added IMAP search expressions (AND, NOT, OR)

pull/184/head
M66B 4 years ago
parent 049e11b993
commit f0b792f9e1

@ -42,6 +42,7 @@ import com.sun.mail.imap.protocol.SearchSequence;
import java.io.File;
import java.io.IOException;
import java.io.Serializable;
import java.lang.reflect.Constructor;
import java.nio.charset.StandardCharsets;
import java.text.Normalizer;
import java.util.ArrayList;
@ -66,6 +67,7 @@ import javax.mail.search.BodyTerm;
import javax.mail.search.ComparisonTerm;
import javax.mail.search.FlagTerm;
import javax.mail.search.FromStringTerm;
import javax.mail.search.NotTerm;
import javax.mail.search.OrTerm;
import javax.mail.search.ReceivedDateTerm;
import javax.mail.search.RecipientStringTerm;
@ -192,6 +194,8 @@ public class BoundaryCallbackMessages extends PagedList.BoundaryCallback<TupleMe
DB db = DB.getInstance(context);
int found = 0;
if (criteria.isExpression())
return found;
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
boolean fts = prefs.getBoolean("fts", false);
@ -677,6 +681,17 @@ public class BoundaryCallbackMessages extends PagedList.BoundaryCallback<TupleMe
with_size != null);
}
boolean isExpression() {
if (this.query == null)
return false;
for (String w : this.query.trim().split("\\s+"))
if (w.length() > 1 && "+-?".indexOf(w.charAt(0)) >= 0)
return true;
return false;
}
SearchTerm getTerms(boolean utf8, Flags flags, String[] keywords) {
List<SearchTerm> or = new ArrayList<>();
List<SearchTerm> and = new ArrayList<>();
@ -689,6 +704,39 @@ public class BoundaryCallbackMessages extends PagedList.BoundaryCallback<TupleMe
.replaceAll("[^\\p{ASCII}]", "");
}
List<String> word = new ArrayList<>();
List<String> plus = new ArrayList<>();
List<String> minus = new ArrayList<>();
List<String> opt = new ArrayList<>();
StringBuilder sb = new StringBuilder();
for (String w : search.trim().split("\\s+")) {
if (sb.length() > 0)
sb.append(' ');
if (w.length() > 1 && w.startsWith("+")) {
plus.add(w.substring(1));
sb.append(w.substring(1));
} else if (w.length() > 1 && w.startsWith("-")) {
minus.add(w.substring(1));
sb.append(w.substring(1));
} else if (w.length() > 1 && w.startsWith("?")) {
opt.add(w.substring(1));
sb.append(w.substring(1));
} else {
word.add(w);
sb.append(w);
}
}
if (plus.size() + minus.size() + opt.size() > 0) {
search = sb.toString();
Log.i("SEARCH word=" + TextUtils.join(",", word));
Log.i("SEARCH plus=" + TextUtils.join(",", plus));
Log.i("SEARCH minus=" + TextUtils.join(",", minus));
Log.i("SEARCH opt=" + TextUtils.join(",", opt));
Log.i("SEARCH full=" + search);
}
// Yahoo! does not support keyword search, but uses the flags $Forwarded $Junk $NotJunk
boolean hasKeywords = false;
for (String keyword : keywords)
@ -704,12 +752,31 @@ public class BoundaryCallbackMessages extends PagedList.BoundaryCallback<TupleMe
or.add(new RecipientStringTerm(Message.RecipientType.CC, search));
or.add(new RecipientStringTerm(Message.RecipientType.BCC, search));
}
if (in_subject)
or.add(new SubjectTerm(search));
if (plus.size() + minus.size() + opt.size() == 0)
or.add(new SubjectTerm(search));
else
try {
or.add(construct(word, plus, minus, opt, SubjectTerm.class));
} catch (Throwable ex) {
Log.e(ex);
or.add(new SubjectTerm(search));
}
if (in_keywords && hasKeywords)
or.add(new FlagTerm(new Flags(MessageHelper.sanitizeKeyword(search)), true));
if (in_message)
or.add(new BodyTerm(search));
if (plus.size() + minus.size() + opt.size() == 0)
or.add(new BodyTerm(search));
else
try {
or.add(construct(word, plus, minus, opt, BodyTerm.class));
} catch (Throwable ex) {
Log.e(ex);
or.add(new BodyTerm(search));
}
}
if (with_unseen && flags.contains(Flags.Flag.SEEN))
@ -739,6 +806,39 @@ public class BoundaryCallbackMessages extends PagedList.BoundaryCallback<TupleMe
return term;
}
private SearchTerm construct(
List<String> word,
List<String> plus,
List<String> minus,
List<String> opt,
Class<?> clazz) throws ReflectiveOperationException {
SearchTerm term = null;
Constructor<?> ctor = clazz.getConstructor(String.class);
if (word.size() > 0)
term = (SearchTerm) ctor.newInstance(TextUtils.join(" ", word));
for (String p : plus)
if (term == null)
term = (SearchTerm) ctor.newInstance(p);
else
term = new AndTerm(term, (SearchTerm) ctor.newInstance(p));
for (String m : minus)
if (term == null)
term = new NotTerm((SearchTerm) ctor.newInstance(m));
else
term = new AndTerm(term, new NotTerm((SearchTerm) ctor.newInstance(m)));
for (String o : opt)
if (term == null)
term = (SearchTerm) ctor.newInstance(o);
else
term = new OrTerm(term, (SearchTerm) ctor.newInstance(o));
return term;
}
String getTitle(Context context) {
List<String> flags = new ArrayList<>();
if (with_unseen)

@ -295,7 +295,7 @@ public class FragmentDialogSearch extends FragmentDialogBase {
if (criteria.query != null && criteria.query.startsWith("raw:"))
new SimpleTask<EntityFolder>() {
@Override
protected EntityFolder onExecute(Context context, Bundle args) throws Throwable {
protected EntityFolder onExecute(Context context, Bundle args) {
long aid = args.getLong("account", -1);
DB db = DB.getInstance(context);
@ -334,6 +334,10 @@ public class FragmentDialogSearch extends FragmentDialogBase {
Log.unexpectedError(getParentFragmentManager(), ex);
}
}.execute(getContext(), getViewLifecycleOwner(), getArguments(), "search:raw");
else if (criteria.isExpression() && folder > 0)
FragmentMessages.search(
getContext(), getViewLifecycleOwner(), getParentFragmentManager(),
account, folder, true, criteria);
else
FragmentMessages.search(
getContext(), getViewLifecycleOwner(), getParentFragmentManager(),

Loading…
Cancel
Save