diff --git a/app/src/main/java/com/termux/api/App.java b/app/src/main/java/com/termux/api/App.java deleted file mode 100644 index 82b85b0be..000000000 --- a/app/src/main/java/com/termux/api/App.java +++ /dev/null @@ -1,223 +0,0 @@ -package com.termux.api; - -import android.app.Application; -import android.content.Intent; -import android.net.LocalServerSocket; -import android.net.LocalSocket; - -import com.termux.api.util.TermuxApiLogger; - -import java.io.BufferedWriter; -import java.io.DataInputStream; -import java.io.OutputStreamWriter; -import java.nio.charset.StandardCharsets; -import java.util.HashMap; -import java.util.Map; -import java.util.Objects; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -public class App extends Application -{ - public static final String LISTEN_ADDRESS = "com.termux.api://listen"; - private static final Pattern EXTRA_STRING = Pattern.compile("(-e|--es|--esa) +([^ ]+) +\"(.*?)(? { - try (LocalServerSocket listen = new LocalServerSocket(LISTEN_ADDRESS)) { - while (true) { - try (LocalSocket con = listen.accept(); - DataInputStream in = new DataInputStream(con.getInputStream()); - BufferedWriter out = new BufferedWriter(new OutputStreamWriter(con.getOutputStream()))) { - // only accept connections from Termux programs - if (con.getPeerCredentials().getUid() != getApplicationInfo().uid) { - continue; - } - try { - //System.out.println("connection"); - int length = in.readUnsignedShort(); - byte[] b = new byte[length]; - in.readFully(b); - String cmdline = new String(b, StandardCharsets.UTF_8); - - Intent intent = new Intent(getApplicationContext(), TermuxApiReceiver.class); - //System.out.println(cmdline.replaceAll("--es socket_input \".*?\"","").replaceAll("--es socket_output \".*?\"","")); - HashMap stringExtras = new HashMap<>(); - HashMap stringArrayExtras = new HashMap<>(); - HashMap booleanExtras = new HashMap<>(); - HashMap intExtras = new HashMap<>(); - HashMap floatExtras = new HashMap<>(); - HashMap intArrayExtras = new HashMap<>(); - HashMap longArrayExtras = new HashMap<>(); - boolean err = false; - - // extract and remove the string extras first, so another argument embedded in a string isn't counted as an argument - Matcher m = EXTRA_STRING.matcher(cmdline); - while (m.find()) { - String option = m.group(1); - if ("-e".equals(option) || "--es".equals(option)) { - // unescape " - stringExtras.put(m.group(2), Objects.requireNonNull(m.group(3)).replaceAll("\\\\\"","\"")); - } else { - // split the list - String[] list = Objects.requireNonNull(m.group(3)).split("(? e : stringExtras.entrySet()) { - intent.putExtra(e.getKey(), e.getValue()); - } - for (Map.Entry e : stringArrayExtras.entrySet()) { - intent.putExtra(e.getKey(), e.getValue()); - } - for (Map.Entry e : intExtras.entrySet()) { - intent.putExtra(e.getKey(), e.getValue()); - } - for (Map.Entry e : booleanExtras.entrySet()) { - intent.putExtra(e.getKey(), e.getValue()); - } - for (Map.Entry e : floatExtras.entrySet()) { - intent.putExtra(e.getKey(), e.getValue()); - } - for (Map.Entry e : intArrayExtras.entrySet()) { - intent.putExtra(e.getKey(), e.getValue()); - } - for (Map.Entry e : longArrayExtras.entrySet()) { - intent.putExtra(e.getKey(), e.getValue()); - } - getApplicationContext().sendOrderedBroadcast(intent, null); - // send a null byte as a sign that the arguments have been successfully received, parsed and the broadcast receiver is called - con.getOutputStream().write(0); - con.getOutputStream().flush(); - } catch (Exception e) { - TermuxApiLogger.error("Error parsing arguments", e); - out.write("Exception in the plugin\n"); - out.flush(); - } - } - } - } catch (Exception e) { - TermuxApiLogger.error("Error listening for connections", e); - } - }).start(); - } - -} diff --git a/app/src/main/java/com/termux/api/SocketListener.java b/app/src/main/java/com/termux/api/SocketListener.java new file mode 100644 index 000000000..3da329a73 --- /dev/null +++ b/app/src/main/java/com/termux/api/SocketListener.java @@ -0,0 +1,233 @@ +package com.termux.api; + +import android.app.Application; +import android.content.Intent; +import android.net.LocalServerSocket; +import android.net.LocalSocket; + +import com.termux.api.util.TermuxApiLogger; + +import java.io.BufferedWriter; +import java.io.DataInputStream; +import java.io.OutputStreamWriter; +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class SocketListener +{ + public static final String LISTEN_ADDRESS = "com.termux.api://listen"; + private static final Pattern EXTRA_STRING = Pattern.compile("(-e|--es|--esa) +([^ ]+) +\"(.*?)(? { + try (LocalServerSocket listen = new LocalServerSocket(LISTEN_ADDRESS)) { + while (true) { + try (LocalSocket con = listen.accept(); + DataInputStream in = new DataInputStream(con.getInputStream()); + BufferedWriter out = new BufferedWriter(new OutputStreamWriter(con.getOutputStream()))) { + // only accept connections from Termux programs + if (con.getPeerCredentials().getUid() != app.getApplicationInfo().uid) { + continue; + } + try { + //System.out.println("connection"); + int length = in.readUnsignedShort(); + byte[] b = new byte[length]; + in.readFully(b); + String cmdline = new String(b, StandardCharsets.UTF_8); + + Intent intent = new Intent(app.getApplicationContext(), TermuxApiReceiver.class); + //System.out.println(cmdline.replaceAll("--es socket_input \".*?\"","").replaceAll("--es socket_output \".*?\"","")); + HashMap stringExtras = new HashMap<>(); + HashMap stringArrayExtras = new HashMap<>(); + HashMap booleanExtras = new HashMap<>(); + HashMap intExtras = new HashMap<>(); + HashMap floatExtras = new HashMap<>(); + HashMap intArrayExtras = new HashMap<>(); + HashMap longArrayExtras = new HashMap<>(); + boolean err = false; + + // extract and remove the string extras first, so another argument embedded in a string isn't counted as an argument + Matcher m = EXTRA_STRING.matcher(cmdline); + while (m.find()) { + String option = m.group(1); + if ("-e".equals(option) || "--es".equals(option)) { + // unescape " + stringExtras.put(m.group(2), Objects.requireNonNull(m.group(3)).replaceAll("\\\\\"", "\"")); + } + else { + // split the list + String[] list = Objects.requireNonNull(m.group(3)).split("(? e : stringExtras.entrySet()) { + intent.putExtra(e.getKey(), e.getValue()); + } + for (Map.Entry e : stringArrayExtras.entrySet()) { + intent.putExtra(e.getKey(), e.getValue()); + } + for (Map.Entry e : intExtras.entrySet()) { + intent.putExtra(e.getKey(), e.getValue()); + } + for (Map.Entry e : booleanExtras.entrySet()) { + intent.putExtra(e.getKey(), e.getValue()); + } + for (Map.Entry e : floatExtras.entrySet()) { + intent.putExtra(e.getKey(), e.getValue()); + } + for (Map.Entry e : intArrayExtras.entrySet()) { + intent.putExtra(e.getKey(), e.getValue()); + } + for (Map.Entry e : longArrayExtras.entrySet()) { + intent.putExtra(e.getKey(), e.getValue()); + } + app.getApplicationContext().sendOrderedBroadcast(intent, null); + // send a null byte as a sign that the arguments have been successfully received, parsed and the broadcast receiver is called + con.getOutputStream().write(0); + con.getOutputStream().flush(); + } + catch (Exception e) { + TermuxApiLogger.error("Error parsing arguments", e); + out.write("Exception in the plugin\n"); + out.flush(); + } + } + } + } + catch (Exception e) { + TermuxApiLogger.error("Error listening for connections", e); + } + }); + listener.start(); + } + } + +} diff --git a/app/src/main/java/com/termux/api/TermuxAPIApplication.java b/app/src/main/java/com/termux/api/TermuxAPIApplication.java index 2184070eb..29e0e0dea 100644 --- a/app/src/main/java/com/termux/api/TermuxAPIApplication.java +++ b/app/src/main/java/com/termux/api/TermuxAPIApplication.java @@ -19,6 +19,8 @@ public void onCreate() { // Set log config for the app setLogLevel(getApplicationContext(), true); + SocketListener.createSocketListener(this); + Logger.logDebug("Starting Application"); }