Added rule action GET URL

pull/214/head
M66B 1 year ago
parent 2d07650db8
commit 97be480046

@ -225,6 +225,9 @@ public class AdapterRule extends RecyclerView.Adapter<AdapterRule.ViewHolder> {
} else if (type == EntityRule.TYPE_NOTES) { } else if (type == EntityRule.TYPE_NOTES) {
String notes = jaction.getString("notes"); String notes = jaction.getString("notes");
setAction(getAction(type), notes); setAction(getAction(type), notes);
} else if (type == EntityRule.TYPE_URL) {
String url = jaction.getString("url");
setAction(getAction(type), url);
} else } else
setAction(getAction(type), null); setAction(getAction(type), null);
@ -577,6 +580,8 @@ public class AdapterRule extends RecyclerView.Adapter<AdapterRule.ViewHolder> {
return R.string.title_rule_local_only; return R.string.title_rule_local_only;
case EntityRule.TYPE_NOTES: case EntityRule.TYPE_NOTES:
return R.string.title_rule_notes; return R.string.title_rule_notes;
case EntityRule.TYPE_URL:
return R.string.title_rule_url;
default: default:
throw new IllegalArgumentException("Unknown action type=" + type); throw new IllegalArgumentException("Unknown action type=" + type);
} }

@ -3100,7 +3100,7 @@ class Core {
} while (count > 0); } while (count > 0);
} }
private static void onRule(Context context, JSONArray jargs, EntityMessage message) throws JSONException, MessagingException { private static void onRule(Context context, JSONArray jargs, EntityMessage message) throws JSONException, MessagingException, IOException {
// Deferred rule (download headers, body, etc) // Deferred rule (download headers, body, etc)
DB db = DB.getInstance(context); DB db = DB.getInstance(context);

@ -32,6 +32,7 @@ import android.database.Cursor;
import android.net.Uri; import android.net.Uri;
import android.provider.ContactsContract; import android.provider.ContactsContract;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Patterns;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.preference.PreferenceManager; import androidx.preference.PreferenceManager;
@ -48,6 +49,9 @@ import org.jsoup.nodes.Element;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.text.DateFormat; import java.text.DateFormat;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
@ -128,6 +132,7 @@ public class EntityRule {
static final int TYPE_SOUND = 16; static final int TYPE_SOUND = 16;
static final int TYPE_LOCAL_ONLY = 17; static final int TYPE_LOCAL_ONLY = 17;
static final int TYPE_NOTES = 18; static final int TYPE_NOTES = 18;
static final int TYPE_URL = 19;
static final String ACTION_AUTOMATION = BuildConfig.APPLICATION_ID + ".AUTOMATION"; static final String ACTION_AUTOMATION = BuildConfig.APPLICATION_ID + ".AUTOMATION";
static final String EXTRA_RULE = "rule"; static final String EXTRA_RULE = "rule";
@ -139,6 +144,7 @@ public class EntityRule {
static final String JSOUP_PREFIX = "jsoup:"; static final String JSOUP_PREFIX = "jsoup:";
private static final long SEND_DELAY = 5000L; // milliseconds private static final long SEND_DELAY = 5000L; // milliseconds
private static final int MAX_NOTES_LENGTH = 512; // characters private static final int MAX_NOTES_LENGTH = 512; // characters
private static final int URL_TIMEOUT = 15 * 1000; // milliseconds
static boolean needsHeaders(EntityMessage message, List<EntityRule> rules) { static boolean needsHeaders(EntityMessage message, List<EntityRule> rules) {
return needsHeaders(rules); return needsHeaders(rules);
@ -181,7 +187,7 @@ public class EntityRule {
static int run(Context context, List<EntityRule> rules, static int run(Context context, List<EntityRule> rules,
EntityMessage message, List<Header> headers, String html) EntityMessage message, List<Header> headers, String html)
throws JSONException, MessagingException { throws JSONException, MessagingException, IOException {
int applied = 0; int applied = 0;
List<String> stopped = new ArrayList<>(); List<String> stopped = new ArrayList<>();
@ -564,7 +570,7 @@ public class EntityRule {
return matched; return matched;
} }
boolean execute(Context context, EntityMessage message, String html) throws JSONException { boolean execute(Context context, EntityMessage message, String html) throws JSONException, IOException {
boolean executed = _execute(context, message, html); boolean executed = _execute(context, message, html);
if (this.id != null && executed) { if (this.id != null && executed) {
DB db = DB.getInstance(context); DB db = DB.getInstance(context);
@ -573,7 +579,7 @@ public class EntityRule {
return executed; return executed;
} }
private boolean _execute(Context context, EntityMessage message, String html) throws JSONException, IllegalArgumentException { private boolean _execute(Context context, EntityMessage message, String html) throws JSONException, IllegalArgumentException, IOException {
JSONObject jaction = new JSONObject(action); JSONObject jaction = new JSONObject(action);
int type = jaction.getInt("type"); int type = jaction.getInt("type");
EntityLog.log(context, EntityLog.Type.Rules, message, EntityLog.log(context, EntityLog.Type.Rules, message,
@ -616,6 +622,8 @@ public class EntityRule {
return onActionLocalOnly(context, message, jaction); return onActionLocalOnly(context, message, jaction);
case TYPE_NOTES: case TYPE_NOTES:
return onActionNotes(context, message, jaction, html); return onActionNotes(context, message, jaction, html);
case TYPE_URL:
return onActionUrl(context, message, jaction, html);
default: default:
throw new IllegalArgumentException("Unknown rule type=" + type + " name=" + name); throw new IllegalArgumentException("Unknown rule type=" + type + " name=" + name);
} }
@ -699,6 +707,11 @@ public class EntityRule {
if (TextUtils.isEmpty(notes)) if (TextUtils.isEmpty(notes))
throw new IllegalArgumentException(context.getString(R.string.title_rule_notes_missing)); throw new IllegalArgumentException(context.getString(R.string.title_rule_notes_missing));
return; return;
case TYPE_URL:
String url = jargs.optString("url");
if (TextUtils.isEmpty(url) || !Patterns.WEB_URL.matcher(url).matches())
throw new IllegalArgumentException(context.getString(R.string.title_rule_url_missing));
return;
default: default:
throw new IllegalArgumentException("Unknown rule type=" + type); throw new IllegalArgumentException("Unknown rule type=" + type);
} }
@ -1386,6 +1399,29 @@ public class EntityRule {
return true; return true;
} }
private boolean onActionUrl(Context context, EntityMessage message, JSONObject jargs, String html) throws JSONException, IOException {
String url = jargs.getString("url");
Log.i("GET " + url);
HttpURLConnection connection = null;
try {
connection = (HttpURLConnection) new URL(url).openConnection();
connection.setRequestMethod("GET");
connection.setDoOutput(false);
connection.setReadTimeout(URL_TIMEOUT);
connection.setConnectTimeout(URL_TIMEOUT);
connection.setInstanceFollowRedirects(true);
ConnectionHelper.setUserAgent(context, connection);
connection.connect();
} finally {
if (connection != null)
connection.disconnect();
}
return true;
}
private static Calendar getRelativeCalendar(boolean all, int minutes, long reference) { private static Calendar getRelativeCalendar(boolean all, int minutes, long reference) {
int d = minutes / (24 * 60); int d = minutes / (24 * 60);
int h = minutes / 60 % 24; int h = minutes / 60 % 24;

@ -172,6 +172,8 @@ public class FragmentRule extends FragmentBase {
private EditText etNotes; private EditText etNotes;
private ViewButtonColor btnColorNotes; private ViewButtonColor btnColorNotes;
private EditText etUrl;
private BottomNavigationView bottom_navigation; private BottomNavigationView bottom_navigation;
private ContentLoadingProgressBar pbWait; private ContentLoadingProgressBar pbWait;
@ -190,6 +192,7 @@ public class FragmentRule extends FragmentBase {
private Group grpDelete; private Group grpDelete;
private Group grpLocalOnly; private Group grpLocalOnly;
private Group grpNotes; private Group grpNotes;
private Group grpUrl;
private ArrayAdapter<String> adapterGroup; private ArrayAdapter<String> adapterGroup;
private ArrayAdapter<String> adapterDay; private ArrayAdapter<String> adapterDay;
@ -362,6 +365,8 @@ public class FragmentRule extends FragmentBase {
etNotes = view.findViewById(R.id.etNotes); etNotes = view.findViewById(R.id.etNotes);
btnColorNotes = view.findViewById(R.id.btnColorNotes); btnColorNotes = view.findViewById(R.id.btnColorNotes);
etUrl = view.findViewById(R.id.etUrl);
bottom_navigation = view.findViewById(R.id.bottom_navigation); bottom_navigation = view.findViewById(R.id.bottom_navigation);
pbWait = view.findViewById(R.id.pbWait); pbWait = view.findViewById(R.id.pbWait);
@ -381,6 +386,7 @@ public class FragmentRule extends FragmentBase {
grpDelete = view.findViewById(R.id.grpDelete); grpDelete = view.findViewById(R.id.grpDelete);
grpLocalOnly = view.findViewById(R.id.grpLocalOnly); grpLocalOnly = view.findViewById(R.id.grpLocalOnly);
grpNotes = view.findViewById(R.id.grpNotes); grpNotes = view.findViewById(R.id.grpNotes);
grpUrl = view.findViewById(R.id.grpUrl);
adapterGroup = new ArrayAdapter<>(getContext(), R.layout.spinner_item1_dropdown, android.R.id.text1); adapterGroup = new ArrayAdapter<>(getContext(), R.layout.spinner_item1_dropdown, android.R.id.text1);
etGroup.setThreshold(1); etGroup.setThreshold(1);
@ -646,6 +652,7 @@ public class FragmentRule extends FragmentBase {
actions.add(new Action(EntityRule.TYPE_TTS, getString(R.string.title_rule_tts))); actions.add(new Action(EntityRule.TYPE_TTS, getString(R.string.title_rule_tts)));
actions.add(new Action(EntityRule.TYPE_SOUND, getString(R.string.title_rule_sound))); actions.add(new Action(EntityRule.TYPE_SOUND, getString(R.string.title_rule_sound)));
actions.add(new Action(EntityRule.TYPE_AUTOMATION, getString(R.string.title_rule_automation))); actions.add(new Action(EntityRule.TYPE_AUTOMATION, getString(R.string.title_rule_automation)));
actions.add(new Action(EntityRule.TYPE_URL, getString(R.string.title_rule_url)));
adapterAction.addAll(actions); adapterAction.addAll(actions);
spAction.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { spAction.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@ -849,6 +856,7 @@ public class FragmentRule extends FragmentBase {
grpDelete.setVisibility(View.GONE); grpDelete.setVisibility(View.GONE);
grpLocalOnly.setVisibility(View.GONE); grpLocalOnly.setVisibility(View.GONE);
grpNotes.setVisibility(View.GONE); grpNotes.setVisibility(View.GONE);
grpUrl.setVisibility(View.GONE);
pbWait.setVisibility(View.VISIBLE); pbWait.setVisibility(View.VISIBLE);
@ -1300,7 +1308,6 @@ public class FragmentRule extends FragmentBase {
etKeyword.setText(jaction.getString("keyword")); etKeyword.setText(jaction.getString("keyword"));
rgKeyword.check(jaction.optBoolean("set", true) rgKeyword.check(jaction.optBoolean("set", true)
? R.id.keyword_add : R.id.keyword_delete); ? R.id.keyword_add : R.id.keyword_delete);
break; break;
case EntityRule.TYPE_MOVE: case EntityRule.TYPE_MOVE:
@ -1359,6 +1366,10 @@ public class FragmentRule extends FragmentBase {
!jaction.has("color") || jaction.isNull("color") !jaction.has("color") || jaction.isNull("color")
? null : jaction.getInt("color")); ? null : jaction.getInt("color"));
break; break;
case EntityRule.TYPE_URL:
etUrl.setText(jaction.getString("url"));
break;
} }
for (int pos = 0; pos < adapterAction.getCount(); pos++) for (int pos = 0; pos < adapterAction.getCount(); pos++)
@ -1417,6 +1428,7 @@ public class FragmentRule extends FragmentBase {
grpDelete.setVisibility(type == EntityRule.TYPE_DELETE ? View.VISIBLE : View.GONE); grpDelete.setVisibility(type == EntityRule.TYPE_DELETE ? View.VISIBLE : View.GONE);
grpLocalOnly.setVisibility(type == EntityRule.TYPE_LOCAL_ONLY ? View.VISIBLE : View.GONE); grpLocalOnly.setVisibility(type == EntityRule.TYPE_LOCAL_ONLY ? View.VISIBLE : View.GONE);
grpNotes.setVisibility(type == EntityRule.TYPE_NOTES ? View.VISIBLE : View.GONE); grpNotes.setVisibility(type == EntityRule.TYPE_NOTES ? View.VISIBLE : View.GONE);
grpUrl.setVisibility(type == EntityRule.TYPE_URL ? View.VISIBLE : View.GONE);
} }
private void onActionDelete() { private void onActionDelete() {
@ -1764,6 +1776,10 @@ public class FragmentRule extends FragmentBase {
if (ncolor != Color.TRANSPARENT) if (ncolor != Color.TRANSPARENT)
jaction.put("color", ncolor); jaction.put("color", ncolor);
break; break;
case EntityRule.TYPE_URL:
jaction.put("url", etUrl.getText().toString().trim());
break;
} }
} }

@ -1281,6 +1281,26 @@
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tvColorNotes" /> app:layout_constraintTop_toBottomOf="@id/tvColorNotes" />
<TextView
android:id="@+id/tvUrl"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:text="@string/title_rule_url"
android:textAppearance="@style/TextAppearance.AppCompat.Small"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/btnColorNotes" />
<eu.faircode.email.EditTextPlain
android:id="@+id/etUrl"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:inputType="textUri"
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tvUrl" />
<androidx.constraintlayout.widget.Group <androidx.constraintlayout.widget.Group
android:id="@+id/grpReady" android:id="@+id/grpReady"
android:layout_width="0dp" android:layout_width="0dp"
@ -1382,6 +1402,12 @@
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="0dp" android:layout_height="0dp"
app:constraint_referenced_ids="tvNotes,etNotes,tvColorNotes,btnColorNotes" /> app:constraint_referenced_ids="tvNotes,etNotes,tvColorNotes,btnColorNotes" />
<androidx.constraintlayout.widget.Group
android:id="@+id/grpUrl"
android:layout_width="0dp"
android:layout_height="0dp"
app:constraint_referenced_ids="tvUrl,etUrl" />
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>
</eu.faircode.email.ScrollViewEx> </eu.faircode.email.ScrollViewEx>

@ -1920,6 +1920,7 @@
<string name="title_rule_keyword_add">Add</string> <string name="title_rule_keyword_add">Add</string>
<string name="title_rule_keyword_delete">Delete</string> <string name="title_rule_keyword_delete">Delete</string>
<string name="title_rule_notes">Local notes</string> <string name="title_rule_notes">Local notes</string>
<string name="title_rule_url" translatable="false">URL</string>
<string name="title_rule_move">Move</string> <string name="title_rule_move">Move</string>
<string name="title_rule_copy">Copy (label)</string> <string name="title_rule_copy">Copy (label)</string>
<string name="title_rule_answer">Reply/forward</string> <string name="title_rule_answer">Reply/forward</string>
@ -1981,6 +1982,7 @@
<string name="title_rule_keyword_missing">Keyword missing</string> <string name="title_rule_keyword_missing">Keyword missing</string>
<string name="title_rule_automation_hint">This will send the intent \'%1$s\' with the extras \'%2$s\'</string> <string name="title_rule_automation_hint">This will send the intent \'%1$s\' with the extras \'%2$s\'</string>
<string name="title_rule_notes_missing">Local notes missing</string> <string name="title_rule_notes_missing">Local notes missing</string>
<string name="title_rule_url_missing" translatable="false">URL missing or invalid</string>
<string name="title_rule_delete_hint">Permanent deletion is irreversible, so make sure the rule conditions are correct!</string> <string name="title_rule_delete_hint">Permanent deletion is irreversible, so make sure the rule conditions are correct!</string>
<string name="title_rule_local_only_hint" translatable="false">Try to avoid bridging notifications to other devices, such as smartwatches. Not all devices support this.</string> <string name="title_rule_local_only_hint" translatable="false">Try to avoid bridging notifications to other devices, such as smartwatches. Not all devices support this.</string>
<string name="title_rule_edit_group">Edit group &#8230;</string> <string name="title_rule_edit_group">Edit group &#8230;</string>

Loading…
Cancel
Save