solves problem with binaries being stored on external SDcard
This commit is contained in:
parent
649ca401e7
commit
c5959637af
|
@ -31,7 +31,6 @@ import org.torproject.android.TorConstants;
|
||||||
import org.torproject.android.Utils;
|
import org.torproject.android.Utils;
|
||||||
import org.torproject.android.settings.AppManager;
|
import org.torproject.android.settings.AppManager;
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
|
||||||
import android.app.Application;
|
import android.app.Application;
|
||||||
import android.app.Notification;
|
import android.app.Notification;
|
||||||
import android.app.NotificationManager;
|
import android.app.NotificationManager;
|
||||||
|
@ -46,13 +45,13 @@ import android.content.SharedPreferences.Editor;
|
||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
import android.net.ConnectivityManager;
|
import android.net.ConnectivityManager;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Handler;
|
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
import android.os.RemoteCallbackList;
|
import android.os.RemoteCallbackList;
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
import android.support.v4.app.NotificationCompat;
|
import android.support.v4.app.NotificationCompat;
|
||||||
import android.support.v4.app.NotificationCompat.Builder;
|
import android.support.v4.app.NotificationCompat.Builder;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
public class TorService extends Service implements TorServiceConstants, TorConstants, Runnable, EventHandler
|
public class TorService extends Service implements TorServiceConstants, TorConstants, Runnable, EventHandler
|
||||||
{
|
{
|
||||||
|
@ -104,6 +103,11 @@ public class TorService extends Service implements TorServiceConstants, TorConst
|
||||||
private NotificationManager mNotificationManager = null;
|
private NotificationManager mNotificationManager = null;
|
||||||
private Builder mNotifyBuilder;
|
private Builder mNotifyBuilder;
|
||||||
|
|
||||||
|
private boolean mHasRoot = false;
|
||||||
|
private boolean mEnableTransparentProxy = false;
|
||||||
|
private boolean mTransProxyAll = false;
|
||||||
|
private boolean mTransProxyTethering = false;
|
||||||
|
|
||||||
public void logMessage(String msg)
|
public void logMessage(String msg)
|
||||||
{
|
{
|
||||||
if (ENABLE_DEBUG_LOG)
|
if (ENABLE_DEBUG_LOG)
|
||||||
|
@ -126,38 +130,40 @@ public class TorService extends Service implements TorServiceConstants, TorConst
|
||||||
|
|
||||||
private boolean findExistingProc ()
|
private boolean findExistingProc ()
|
||||||
{
|
{
|
||||||
try
|
if (fileTorLink != null)
|
||||||
{
|
{
|
||||||
if (fileTorLink == null)
|
try
|
||||||
initTorPathLink();
|
{
|
||||||
|
int procId = TorServiceUtils.findProcessId(fileTorLink.getAbsolutePath());
|
||||||
|
|
||||||
int procId = TorServiceUtils.findProcessId(fileTorLink.getAbsolutePath());
|
if (procId != -1)
|
||||||
|
{
|
||||||
|
logNotice("Found existing Tor process");
|
||||||
|
|
||||||
if (procId != -1)
|
sendCallbackLogMessage (getString(R.string.found_existing_tor_process));
|
||||||
{
|
|
||||||
logNotice("Found existing Tor process");
|
|
||||||
|
|
||||||
sendCallbackLogMessage (getString(R.string.found_existing_tor_process));
|
currentStatus = STATUS_CONNECTING;
|
||||||
|
|
||||||
currentStatus = STATUS_CONNECTING;
|
initControlConnection();
|
||||||
|
|
||||||
initControlConnection();
|
processSettingsImpl();
|
||||||
|
|
||||||
processSettingsImpl();
|
currentStatus = STATUS_ON;
|
||||||
|
|
||||||
currentStatus = STATUS_ON;
|
return true;
|
||||||
|
|
||||||
return true;
|
}
|
||||||
|
|
||||||
}
|
return false;
|
||||||
|
}
|
||||||
return false;
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Log.e(TAG,"error finding proc",e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
else
|
||||||
{
|
|
||||||
Log.e(TAG,"error finding proc",e);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -252,8 +258,6 @@ public class TorService extends Service implements TorServiceConstants, TorConst
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
initTorPaths();
|
|
||||||
|
|
||||||
sendCallbackLogMessage("Welcome back, Carter!");
|
sendCallbackLogMessage("Welcome back, Carter!");
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
|
@ -271,15 +275,6 @@ public class TorService extends Service implements TorServiceConstants, TorConst
|
||||||
|
|
||||||
_torInstance = this;
|
_torInstance = this;
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
initTorPaths();
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
Log.e(TAG,"error setting up Tor",e);
|
|
||||||
throw new RuntimeException("Unable to start Tor",e);
|
|
||||||
}
|
|
||||||
|
|
||||||
IntentFilter mNetworkStateFilter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
|
IntentFilter mNetworkStateFilter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
|
||||||
registerReceiver(mNetworkStateReceiver , mNetworkStateFilter);
|
registerReceiver(mNetworkStateReceiver , mNetworkStateFilter);
|
||||||
|
@ -332,8 +327,10 @@ public class TorService extends Service implements TorServiceConstants, TorConst
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
logException("Unable to start Tor: " + e.getMessage(),e);
|
||||||
|
sendCallbackStatusMessage(getString(R.string.unable_to_start_tor) + ' ' + e.getMessage());
|
||||||
currentStatus = STATUS_OFF;
|
currentStatus = STATUS_OFF;
|
||||||
this.showToolbarNotification(getString(R.string.status_disabled), ERROR_NOTIFY_ID, R.drawable.ic_stat_notifyerr, -1, false);
|
this.showToolbarNotification(getString(R.string.unable_to_start_tor) + ": " + e.getMessage(), ERROR_NOTIFY_ID, R.drawable.ic_stat_notifyerr, -1, false);
|
||||||
Log.d(TAG,"Unable to start Tor: " + e.getMessage(),e);
|
Log.d(TAG,"Unable to start Tor: " + e.getMessage(),e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -455,19 +452,74 @@ public class TorService extends Service implements TorServiceConstants, TorConst
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initTorPathLink () throws Exception
|
private void initTorPathLinkAndPerms () throws Exception
|
||||||
{
|
{
|
||||||
|
|
||||||
fileTorLink = new File(appBinHome,"tor");
|
fileTorLink = new File(appBinHome,"tor");
|
||||||
|
fileTorLink.getParentFile().mkdirs();
|
||||||
|
|
||||||
StringBuilder log = new StringBuilder();
|
if (fileTorOrig.getAbsolutePath().startsWith("/mnt"))
|
||||||
|
{
|
||||||
|
logNotice("app installed on external storage - copying binaries to internal");
|
||||||
|
|
||||||
String[] cmdDel = { "rm " + fileTorLink.getAbsolutePath() };
|
//can't execute binaries off the external storage, so copy them internal
|
||||||
TorServiceUtils.doShellCommand(cmdDel,log, false, false);
|
StringBuilder log = new StringBuilder();
|
||||||
|
int errCode = -1;
|
||||||
|
|
||||||
|
if (!fileTorLink.exists()||(fileTorOrig.length()!=fileTorLink.length()))
|
||||||
|
{
|
||||||
|
String[] cmd = { SHELL_CMD_CP + ' ' + fileTorOrig.getAbsolutePath() + ' ' + fileTorLink.getAbsolutePath() };
|
||||||
|
errCode = TorServiceUtils.doShellCommand(cmd,log, false, true);
|
||||||
|
logNotice("link CP err=" + errCode + " out: " + log.toString());
|
||||||
|
}
|
||||||
|
enableBinExec(fileTorLink);
|
||||||
|
|
||||||
|
log = new StringBuilder();
|
||||||
|
File filePrivoxyLink = new File(appBinHome,"privoxy");
|
||||||
|
if (!filePrivoxyLink.exists()||(filePrivoxy.length()!=filePrivoxyLink.length()))
|
||||||
|
{
|
||||||
|
String[] cmd1 = { SHELL_CMD_CP + ' ' + filePrivoxy.getAbsolutePath() + ' ' + filePrivoxyLink.getAbsolutePath() };
|
||||||
|
errCode = TorServiceUtils.doShellCommand(cmd1,log, false, true);
|
||||||
|
logNotice("link CP err=" + errCode + " out: " + log.toString());
|
||||||
|
}
|
||||||
|
filePrivoxy = filePrivoxyLink;
|
||||||
|
enableBinExec(filePrivoxy);
|
||||||
|
|
||||||
|
log = new StringBuilder();
|
||||||
|
File fileObfsProxyLink = new File(appBinHome,"obfsproxy");
|
||||||
|
if (!fileObfsProxyLink.exists()||(fileObfsProxy.length()!=fileObfsProxyLink.length()))
|
||||||
|
{
|
||||||
|
String[] cmd2 = { SHELL_CMD_CP + ' ' + fileObfsProxy.getAbsolutePath() + ' ' + fileObfsProxyLink.getAbsolutePath() };
|
||||||
|
errCode = TorServiceUtils.doShellCommand(cmd2,log, false, true);
|
||||||
|
logNotice("link CP err=" + errCode + " out: " + log.toString());
|
||||||
|
}
|
||||||
|
fileObfsProxy = fileObfsProxyLink;
|
||||||
|
enableBinExec(fileObfsProxy);
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
if (fileTorLink.exists())
|
||||||
|
{
|
||||||
|
StringBuilder log = new StringBuilder();
|
||||||
|
String[] cmdDel = { "rm " + fileTorLink.getAbsolutePath() };
|
||||||
|
int errCode = TorServiceUtils.doShellCommand(cmdDel,log, false, true);
|
||||||
|
logNotice("link RM err=" + errCode + " out: " + log.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
StringBuilder log = new StringBuilder();
|
||||||
|
String[] cmd = { SHELL_CMD_LINK + ' ' + fileTorOrig.getAbsolutePath() + ' ' + fileTorLink.getAbsolutePath() };
|
||||||
|
int errCode = TorServiceUtils.doShellCommand(cmd,log, false, true);
|
||||||
|
logNotice("link LN err=" + errCode + " out: " + log.toString());
|
||||||
|
|
||||||
|
enableBinExec(fileTorOrig);
|
||||||
|
|
||||||
|
enableBinExec(filePrivoxy);
|
||||||
|
enableBinExec(fileObfsProxy);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
String[] cmd = { SHELL_CMD_LINK + ' ' + fileTorOrig.getAbsolutePath() + ' ' + fileTorLink.getAbsolutePath() };
|
|
||||||
TorServiceUtils.doShellCommand(cmd,log, false, false);
|
|
||||||
logNotice("link command output: " + log.toString());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void killTorProcess () throws Exception
|
private void killTorProcess () throws Exception
|
||||||
|
@ -493,40 +545,49 @@ public class TorService extends Service implements TorServiceConstants, TorConst
|
||||||
}
|
}
|
||||||
|
|
||||||
int killDelayMs = 300;
|
int killDelayMs = 300;
|
||||||
|
int maxTry = 5;
|
||||||
|
int currTry = 0;
|
||||||
|
|
||||||
while ((procId = TorServiceUtils.findProcessId(fileTorLink.getAbsolutePath())) != -1)
|
while ((procId = TorServiceUtils.findProcessId(fileTorLink.getAbsolutePath())) != -1 && currTry++ < maxTry)
|
||||||
{
|
{
|
||||||
|
sendCallbackStatusMessage ("Found existing orphan Tor process; Trying to shutdown now (device restart may be needed)...");
|
||||||
|
|
||||||
logNotice("Found Tor PID=" + procId + " - killing now...");
|
logNotice("Found Tor PID=" + procId + " - attempt to shutdown now...");
|
||||||
|
|
||||||
String[] cmd = { SHELL_CMD_KILL + ' ' + procId + "" };
|
String[] cmd = { SHELL_CMD_KILL + ' ' + procId + "" };
|
||||||
TorServiceUtils.doShellCommand(cmd,log, false, false);
|
TorServiceUtils.doShellCommand(cmd,log, mHasRoot, false);
|
||||||
try { Thread.sleep(killDelayMs); }
|
try { Thread.sleep(killDelayMs); }
|
||||||
catch (Exception e){}
|
catch (Exception e){}
|
||||||
}
|
}
|
||||||
|
|
||||||
while ((procId = TorServiceUtils.findProcessId(filePrivoxy.getAbsolutePath())) != -1)
|
if (procId == -1)
|
||||||
{
|
{
|
||||||
|
while ((procId = TorServiceUtils.findProcessId(filePrivoxy.getAbsolutePath())) != -1)
|
||||||
|
{
|
||||||
|
|
||||||
logNotice("Found Privoxy PID=" + procId + " - killing now...");
|
logNotice("Found Privoxy PID=" + procId + " - killing now...");
|
||||||
String[] cmd = { SHELL_CMD_KILL + ' ' + procId + "" };
|
String[] cmd = { SHELL_CMD_KILL + ' ' + procId + "" };
|
||||||
|
|
||||||
TorServiceUtils.doShellCommand(cmd,log, false, false);
|
TorServiceUtils.doShellCommand(cmd,log, mHasRoot, false);
|
||||||
try { Thread.sleep(killDelayMs); }
|
try { Thread.sleep(killDelayMs); }
|
||||||
catch (Exception e){}
|
catch (Exception e){}
|
||||||
|
}
|
||||||
|
|
||||||
|
while ((procId = TorServiceUtils.findProcessId(fileObfsProxy.getAbsolutePath())) != -1)
|
||||||
|
{
|
||||||
|
|
||||||
|
logNotice("Found ObfsProxy PID=" + procId + " - killing now...");
|
||||||
|
String[] cmd = { SHELL_CMD_KILL + ' ' + procId + "" };
|
||||||
|
|
||||||
|
TorServiceUtils.doShellCommand(cmd,log, mHasRoot, false);
|
||||||
|
try { Thread.sleep(killDelayMs); }
|
||||||
|
catch (Exception e){}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
while ((procId = TorServiceUtils.findProcessId(fileObfsProxy.getAbsolutePath())) != -1)
|
|
||||||
{
|
{
|
||||||
|
throw new Exception("*** Unable to kill existing Tor process. Please REBOOT your device. ***");
|
||||||
logNotice("Found ObfsProxy PID=" + procId + " - killing now...");
|
|
||||||
String[] cmd = { SHELL_CMD_KILL + ' ' + procId + "" };
|
|
||||||
|
|
||||||
TorServiceUtils.doShellCommand(cmd,log, false, false);
|
|
||||||
try { Thread.sleep(killDelayMs); }
|
|
||||||
catch (Exception e){}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void logNotice (String msg)
|
private void logNotice (String msg)
|
||||||
|
@ -540,9 +601,8 @@ public class TorService extends Service implements TorServiceConstants, TorConst
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initTorPaths () throws IOException
|
private void initTorPaths () throws Exception
|
||||||
{
|
{
|
||||||
|
|
||||||
appBinHome = getDir("bin",Application.MODE_PRIVATE);
|
appBinHome = getDir("bin",Application.MODE_PRIVATE);
|
||||||
appCacheHome = getDir("data",Application.MODE_PRIVATE);
|
appCacheHome = getDir("data",Application.MODE_PRIVATE);
|
||||||
appLibsHome = new File(getApplicationInfo().nativeLibraryDir);
|
appLibsHome = new File(getApplicationInfo().nativeLibraryDir);
|
||||||
|
@ -588,45 +648,26 @@ public class TorService extends Service implements TorServiceConstants, TorConst
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
initTorPathLinkAndPerms();
|
||||||
{
|
|
||||||
setBinaryPerms();
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
logNotice("Error setting binary permissions: " + e.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setBinaryPerms () throws Exception
|
private boolean enableBinExec (File fileBin) throws Exception
|
||||||
{
|
{
|
||||||
|
|
||||||
logNotice("Is Tor binary exec? " + fileTorOrig.canExecute());
|
logNotice(fileBin.getName() + ": PRE: Is binary exec? " + fileBin.canExecute());
|
||||||
logNotice("Is Tor binary exec? " + filePrivoxy.canExecute());
|
|
||||||
logNotice("Is Tor binary exec? " + fileObfsProxy.canExecute());
|
|
||||||
|
|
||||||
|
|
||||||
StringBuilder log = new StringBuilder ();
|
StringBuilder log = new StringBuilder ();
|
||||||
|
|
||||||
logNotice("(re)Setting permission on Tor binary");
|
logNotice("(re)Setting permission on binary: " + fileBin.getAbsolutePath());
|
||||||
String[] cmd1 = {SHELL_CMD_CHMOD + ' ' + CHMOD_EXE_VALUE + ' ' + fileTorOrig.getAbsolutePath()};
|
String[] cmd1 = {SHELL_CMD_CHMOD + ' ' + CHMOD_EXE_VALUE + ' ' + fileBin.getAbsolutePath()};
|
||||||
TorServiceUtils.doShellCommand(cmd1, log, false, true);
|
TorServiceUtils.doShellCommand(cmd1, log, false, true);
|
||||||
|
|
||||||
logNotice("(re)Setting permission on Privoxy binary");
|
logNotice(fileBin.getName() + ": POST: Is binary exec? " + fileBin.canExecute());
|
||||||
String[] cmd2 = {SHELL_CMD_CHMOD + ' ' + CHMOD_EXE_VALUE + ' ' + filePrivoxy.getAbsolutePath()};
|
|
||||||
TorServiceUtils.doShellCommand(cmd2, log, false, true);
|
|
||||||
|
|
||||||
logNotice("(re)Setting permission on Obfsproxy binary");
|
|
||||||
String[] cmd3 = {SHELL_CMD_CHMOD + ' ' + CHMOD_EXE_VALUE + ' ' + fileObfsProxy.getAbsolutePath()};
|
|
||||||
TorServiceUtils.doShellCommand(cmd3, log, false, true);
|
|
||||||
|
|
||||||
|
return fileBin.canExecute();
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean mHasRoot = false;
|
|
||||||
private boolean mEnableTransparentProxy = false;
|
|
||||||
private boolean mTransProxyAll = false;
|
|
||||||
private boolean mTransProxyTethering = false;
|
|
||||||
|
|
||||||
private void updateSettings ()
|
private void updateSettings ()
|
||||||
{
|
{
|
||||||
|
@ -646,6 +687,8 @@ public class TorService extends Service implements TorServiceConstants, TorConst
|
||||||
public void initTor () throws Exception
|
public void initTor () throws Exception
|
||||||
{
|
{
|
||||||
|
|
||||||
|
initTorPaths();
|
||||||
|
|
||||||
updateSettings ();
|
updateSettings ();
|
||||||
|
|
||||||
currentStatus = STATUS_CONNECTING;
|
currentStatus = STATUS_CONNECTING;
|
||||||
|
@ -654,26 +697,13 @@ public class TorService extends Service implements TorServiceConstants, TorConst
|
||||||
|
|
||||||
sendCallbackStatusMessage(getString(R.string.status_starting_up));
|
sendCallbackStatusMessage(getString(R.string.status_starting_up));
|
||||||
|
|
||||||
initTorPathLink ();
|
|
||||||
|
|
||||||
killTorProcess ();
|
killTorProcess ();
|
||||||
|
|
||||||
try {
|
runTorShellCmd();
|
||||||
|
runPrivoxyShellCmd();
|
||||||
|
|
||||||
//setBinaryPerms();
|
if (mHasRoot && mEnableTransparentProxy)
|
||||||
|
enableTransparentProxy(mTransProxyAll, mTransProxyTethering);
|
||||||
runTorShellCmd();
|
|
||||||
runPrivoxyShellCmd();
|
|
||||||
|
|
||||||
if (mHasRoot && mEnableTransparentProxy)
|
|
||||||
enableTransparentProxy(mTransProxyAll, mTransProxyTethering);
|
|
||||||
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
|
||||||
logException("Unable to start Tor: " + e.getMessage(),e);
|
|
||||||
sendCallbackStatusMessage(getString(R.string.unable_to_start_tor) + ' ' + e.getMessage());
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -758,6 +788,12 @@ public class TorService extends Service implements TorServiceConstants, TorConst
|
||||||
private void runTorShellCmd() throws Exception
|
private void runTorShellCmd() throws Exception
|
||||||
{
|
{
|
||||||
|
|
||||||
|
if (!fileTorLink.exists())
|
||||||
|
throw new RuntimeException("Sorry Tor binary not installed properly: " + fileTorLink.getAbsolutePath());
|
||||||
|
|
||||||
|
if (!fileTorLink.canExecute())
|
||||||
|
throw new RuntimeException("Sorry can't execute Tor: " + fileTorLink.getAbsolutePath());
|
||||||
|
|
||||||
SharedPreferences prefs =getSharedPrefs(getApplicationContext());
|
SharedPreferences prefs =getSharedPrefs(getApplicationContext());
|
||||||
|
|
||||||
StringBuilder log = new StringBuilder();
|
StringBuilder log = new StringBuilder();
|
||||||
|
@ -1248,7 +1284,6 @@ public class TorService extends Service implements TorServiceConstants, TorConst
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
initTorPaths();
|
|
||||||
findExistingProc ();
|
findExistingProc ();
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
|
|
|
@ -41,6 +41,7 @@ public interface TorServiceConstants {
|
||||||
public final static String SHELL_CMD_PS = "ps";
|
public final static String SHELL_CMD_PS = "ps";
|
||||||
public final static String SHELL_CMD_PIDOF = "pidof";
|
public final static String SHELL_CMD_PIDOF = "pidof";
|
||||||
public final static String SHELL_CMD_LINK = "ln -s";
|
public final static String SHELL_CMD_LINK = "ln -s";
|
||||||
|
public final static String SHELL_CMD_CP = "cp";
|
||||||
|
|
||||||
|
|
||||||
public final static String CHMOD_EXE_VALUE = "700";
|
public final static String CHMOD_EXE_VALUE = "700";
|
||||||
|
|
Loading…
Reference in New Issue