From e70f499f13328009f1bc1794734e7202f50e36dd Mon Sep 17 00:00:00 2001
From: Daniel Xie <Daniel Xie>
Date: Wed, 31 May 2017 11:33:54 -0500
Subject: [PATCH] Added exec() command. Initial testing shows that its working
 ok

---
 src/Constants.js          |  7 ++++++-
 src/NetscriptEvaluator.js | 37 ++++++++++++++++++++++++++++++++++---
 src/Script.js             |  2 ++
 3 files changed, 42 insertions(+), 4 deletions(-)

diff --git a/src/Constants.js b/src/Constants.js
index 24234780f..1220bdd43 100644
--- a/src/Constants.js
+++ b/src/Constants.js
@@ -49,6 +49,7 @@ CONSTANTS = {
     ScriptHttpwormRamCost:          0.05,
     ScriptSqlinjectRamCost:         0.05,
     ScriptRunRamCost:               0.8,
+    ScriptExecRamCost:              1.0,
     ScriptScpRamCost:               0.5,
     ScriptHasRootAccessRamCost:     0.05,
     ScriptGetHostnameRamCost:       0.1,
@@ -267,7 +268,7 @@ CONSTANTS = {
                            "<i>hack(hostname/ip)</i><br>Core function that is used to try and hack servers to steal money and gain hacking experience. The argument passed in must be a string with " +
                            "either the IP or hostname of the server you want to hack. A script can hack a server from anywhere. It does not need to be running on the same server to hack that server. " +
                            "For example, you can create a script that hacks the 'foodnstuff' server and run it on your home computer. <br>" + 
-                          "Examples: hack('foodnstuff'); or hack('148.192.0.12');<br><br>" + 
+                           "Examples: hack('foodnstuff'); or hack('148.192.0.12');<br><br>" + 
                            "<i>sleep(n)</i><br>Suspends the script for n milliseconds. <br>Example: sleep(5000);<br><br>" + 
                            "<i>grow(hostname/ip)</i><br>Use your hacking skills to increase the amount of money available on a server. The argument passed in " + 
                            "must be a string with either the IP or hostname of the target server. The grow() command requires root access to the target server, but " +
@@ -284,6 +285,10 @@ CONSTANTS = {
                            "be used to run scripts located on the same server. Returns true if the script is successfully started, and false otherwise. Requires a significant amount " +
                            "of RAM to run this command. Does NOT work while offline <br>Example: run('hack-foodnstuff.script'); <br> The example above will try and launch the 'hack-foodnstuff.script' script on " + 
                            "the current server, if it exists. <br><br>" + 
+                           "<i>exec(script, hostname/ip)</i><br>Run a script as a separate process on another server. The first argument is the name of the script as a string. The " + 
+                           "second argument is a string with the hostname or IP of the 'target server' on which to run the script. The specified script must exist on the target server. Returns " + 
+                           "true if the script is successfully started, and false otherwise. Does NOT work while offline<br> " + 
+                           "Example: exec('generic-hack.script', 'foodnstuff'); <br> The example above will try to launch the script 'generic-hack.script' on the 'foodnstuff' server.<br><br>" + 
                            "<i>scp(script, hostname/ip)</i><br>Copies a script to another server. The first argument is a string with the filename of the script " + 
                            "to be copied. The second argument is a string with the hostname or IP of the destination server. Returns true if the script is successfully " + 
                            "copied over and false otherwise. <br> Example: scp('hack-template.script', 'foodnstuff');<br><br>" + 
diff --git a/src/NetscriptEvaluator.js b/src/NetscriptEvaluator.js
index b17124d0c..a26353e96 100644
--- a/src/NetscriptEvaluator.js
+++ b/src/NetscriptEvaluator.js
@@ -710,6 +710,35 @@ function evaluate(exp, workerScript) {
                         }, function(e) {
                             reject(e);
                         });
+                    } else if (exp.func.value == "exec") {
+                        if (exp.args.length != 2) {
+                            reject(makeRuntimeRejectMsg(workerScript, "exec() call has incorrect number of arguments. Takes 2 arguments"));
+                            return;
+                        }
+                        var scriptNamePromise = evaluate(exp.args[0], workerScript);
+                        scriptNamePromise.then(function(scriptname) {
+                            if (env.stopFlag) {reject(workerScript); return;}
+                            var ipPromise = evaluate(exp.args[1], workerScript);
+                            ipPromise.then(function(ip) {
+                                if (env.stopFlag) {reject(workerScript); return;}
+                                var server = getServer(ip);
+                                if (server == null) {
+                                    reject(makeRuntimeRejectMsg(workerScript, "Invalid hostname/ip passed into exec() command: " + ip));
+                                    return;
+                                }
+                                
+                                var runScriptPromise = runScriptFromScript(server, scriptname, workerScript); 
+                                runScriptPromise.then(function(res) {
+                                    resolve(res);
+                                }, function(e) {
+                                    reject(e);
+                                });
+                            }, function(e) {
+                                reject(e);
+                            });
+                        }, function(e) {
+                            reject(e);
+                        });
                     } else if (exp.func.value == "scp") {
                         if (exp.args.length != 2) {
                             reject(makeRuntimeRejectMsg(workerScript, "scp() call has incorrect number of arguments. Takes 2 arguments"));
@@ -717,8 +746,10 @@ function evaluate(exp, workerScript) {
                         }
                         var scriptNamePromise = evaluate(exp.args[0], workerScript);
                         scriptNamePromise.then(function(scriptname) {
+                            if (env.stopFlag) {reject(workerScript); return;}
                             var ipPromise = evaluate(exp.args[1], workerScript);
                             ipPromise.then(function(ip) {
+                                if (env.stopFlag) {reject(workerScript); return;}
                                 var destServer = getServer(ip);
                                 if (destServer == null) {
                                     reject(makeRuntimeRejectMsg(workerScript, "Invalid hostname/ip passed into scp() command: " + ip));
@@ -1203,16 +1234,16 @@ function runScriptFromScript(server, scriptname, workerScript) {
                     var ramAvailable = server.maxRam - server.ramUsed;
                     
                     if (server.hasAdminRights == false) {
-                        workerScript.scriptRef.log("Cannot run script " + scriptname + " because you do not have root access!");
+                        workerScript.scriptRef.log("Cannot run script " + scriptname + " on " + server.hostname + " because you do not have root access!");
                         resolve(false);
                         return;
                     } else if (ramUsage > ramAvailable){
-                        workerScript.scriptRef.log("Cannot run script " + scriptname + " because there is not enough available RAM!");
+                        workerScript.scriptRef.log("Cannot run script " + scriptname + " on " + server.hostname + " because there is not enough available RAM!");
                         resolve(false);
                         return;
                     } else {
                         //Able to run script
-                        workerScript.scriptRef.log("Running script: " + scriptname + ". May take a few seconds to start up...");
+                        workerScript.scriptRef.log("Running script: " + scriptname + " on " + server.hostname + ". May take a few seconds to start up...");
                         var script = server.scripts[i];
                         server.runningScripts.push(script.filename);	//Push onto runningScripts
                         addWorkerScript(script, server);
diff --git a/src/Script.js b/src/Script.js
index 14f793d87..3bdd42e1b 100644
--- a/src/Script.js
+++ b/src/Script.js
@@ -182,6 +182,7 @@ Script.prototype.updateRamUsage = function() {
     var httpwormCount = numOccurrences(codeCopy, "httpworm(");
     var sqlinjectCount = numOccurrences(codeCopy, "sqlinject(");
     var runCount = numOccurrences(codeCopy, "run(");
+    var execCount = numOccurrences(codeCopy, "exec(");
     var scpCount = numOccurrences(codeCopy, "scp(");
     var hasRootAccessCount = numOccurrences(codeCopy, "hasRootAccess(");
     var getHostnameCount = numOccurrences(codeCopy, "getHostname(");
@@ -207,6 +208,7 @@ Script.prototype.updateRamUsage = function() {
                     (httpwormCount * CONSTANTS.ScriptHttpwormRamCost) + 
                     (sqlinjectCount * CONSTANTS.ScriptSqlinjectRamCost) + 
                     (runCount * CONSTANTS.ScriptRunRamCost) + 
+                    (execCount * CONSTANTS.ScriptExecRamCost) + 
                     (scpCount * CONSTANTS.ScriptScpRamCost) + 
                     (hasRootAccessCount * CONSTANTS.ScriptHasRootAccessRamCost) + 
                     (getHostnameCount * CONSTANTS.ScriptGetHostnameRamCost) +