get rid of console thread for OpenRecoveryScript

- CLI commands run in a threaded action "twcmd"
- Console is displayed via "singleaction_page"
- move ORS execution code from GUI action to OpenRecoveryScript class
- remove unused function gui_changePackage
- don't change PageManager package in home action
- fix that /tmp/openrecoveryscript was not deleted after execution

Change-Id: Ic688c0b04647ce09e9db979b0bc5123f47cf4f70
diff --git a/gui/action.cpp b/gui/action.cpp
index 20944da..081e2d1 100644
--- a/gui/action.cpp
+++ b/gui/action.cpp
@@ -226,6 +226,7 @@
 		ADD_ACTION(resize);
 		ADD_ACTION(changefilesystem);
 		ADD_ACTION(flashimage);
+		ADD_ACTION(twcmd);
 	}
 
 	// First, get the action
@@ -522,7 +523,6 @@
 
 int GUIAction::home(std::string arg __unused)
 {
-	PageManager::SelectPackage("TWRP");
 	gui_changePage("main");
 	return 0;
 }
@@ -1536,41 +1536,12 @@
 
 int GUIAction::openrecoveryscript(std::string arg __unused)
 {
-	int op_status = 1;
-
 	operation_start("OpenRecoveryScript");
 	if (simulate) {
 		simulate_progress_bar();
 		operation_end(0);
 	} else {
-		// Check for the SCRIPT_FILE_TMP first as these are AOSP recovery commands
-		// that we converted to ORS commands during boot in recovery.cpp.
-		// Run those first.
-		int reboot = 0;
-		if (TWFunc::Path_Exists(SCRIPT_FILE_TMP)) {
-			gui_msg("running_recovery_commands=Running Recovery Commands");
-			if (OpenRecoveryScript::run_script_file() == 0) {
-				reboot = 1;
-				op_status = 0;
-			}
-		}
-		// Check for the ORS file in /cache and attempt to run those commands.
-		if (OpenRecoveryScript::check_for_script_file()) {
-			gui_msg("running_ors=Running OpenRecoveryScript");
-			if (OpenRecoveryScript::run_script_file() == 0) {
-				reboot = 1;
-				op_status = 0;
-			}
-		}
-		if (reboot) {
-			// Disable stock recovery reflashing
-			TWFunc::Disable_Stock_Recovery_Replace();
-			usleep(2000000); // Sleep for 2 seconds before rebooting
-			TWFunc::tw_reboot(rb_system);
-			usleep(5000000); // Sleep for 5 seconds to allow reboot to occur
-		} else {
-			DataManager::SetValue("tw_page_done", 1);
-		}
+		int op_status = OpenRecoveryScript::Run_OpenRecoveryScript_Action();
 		operation_end(op_status);
 	}
 	return 0;
@@ -1743,6 +1714,17 @@
 	return 0;
 }
 
+int GUIAction::twcmd(std::string arg)
+{
+	operation_start("TWRP CLI Command");
+	if (simulate)
+		simulate_progress_bar();
+	else
+		OpenRecoveryScript::Run_CLI_Command(arg.c_str());
+	operation_end(0);
+	return 0;
+}
+
 int GUIAction::getKeyByName(std::string key)
 {
 	if (key == "home")			return KEY_HOME;
diff --git a/gui/gui.cpp b/gui/gui.cpp
index 78e8a7e..63baeee 100644
--- a/gui/gui.cpp
+++ b/gui/gui.cpp
@@ -69,12 +69,11 @@
 // Global values
 static gr_surface gCurtain = NULL;
 static int gGuiInitialized = 0;
-static TWAtomicInt gGuiConsoleRunning;
-static TWAtomicInt gGuiConsoleTerminate;
 static TWAtomicInt gForceRender;
 const int gNoAnimation = 1;
 blanktimer blankTimer;
 int ors_read_fd = -1;
+static FILE* orsout = NULL;
 static float scale_theme_w = 1;
 static float scale_theme_h = 1;
 
@@ -493,13 +492,28 @@
 	}
 }
 
+// callback called after a CLI command was executed
+static void ors_command_done()
+{
+	gui_set_FILE(NULL);
+	fclose(orsout);
+	orsout = NULL;
+
+	if (DataManager::GetIntValue("tw_page_done") == 0) {
+		// The select function will return ready to read and the
+		// read function will return errno 19 no such device unless
+		// we set everything up all over again.
+		close(ors_read_fd);
+		setup_ors_command();
+	}
+}
+
 static void ors_command_read()
 {
-	FILE* orsout;
-	char command[1024], result[512];
-	int set_page_done = 0, read_ret = 0;
+	char command[1024];
+	int read_ret = read(ors_read_fd, &command, sizeof(command));
 
-	if ((read_ret = read(ors_read_fd, &command, sizeof(command))) > 0) {
+	if (read_ret > 0) {
 		command[1022] = '\n';
 		command[1023] = '\0';
 		LOGINFO("Command '%s' received\n", command);
@@ -513,61 +527,40 @@
 			return;
 		}
 		if (DataManager::GetIntValue("tw_busy") != 0) {
-			strcpy(result, "Failed, operation in progress\n");
-			fprintf(orsout, "%s", result);
+			fputs("Failed, operation in progress\n", orsout);
 			LOGINFO("Command cannot be performed, operation in progress.\n");
+			fclose(orsout);
 		} else {
 			if (strlen(command) == 11 && strncmp(command, "dumpstrings", 11) == 0) {
-				// This cannot be done safely with gui_console_only because gui_console_only updates mCurrentSet
-				// which makes the resources that we are trying to read unreachable.
 				gui_set_FILE(orsout);
 				PageManager::GetResources()->DumpStrings();
-				gui_set_FILE(NULL);
-			} else if (gui_console_only() == 0) {
-				LOGINFO("Console started successfully\n");
+				ors_command_done();
+			} else {
+				// mirror output messages
 				gui_set_FILE(orsout);
-				if (strlen(command) > 11 && strncmp(command, "runscript", 9) == 0) {
-					char* filename = command + 11;
-					if (OpenRecoveryScript::copy_script_file(filename) == 0) {
-						LOGINFO("Unable to copy script file\n");
-					} else {
-						OpenRecoveryScript::run_script_file();
-					}
-				} else if (strlen(command) > 5 && strncmp(command, "get", 3) == 0) {
-					char* varname = command + 4;
-					string temp;
-					DataManager::GetValue(varname, temp);
-					gui_print("%s = %s\n", varname, temp.c_str());
-				} else if (strlen(command) > 9 && strncmp(command, "decrypt", 7) == 0) {
-					char* pass = command + 8;
-					gui_msg("decrypt_cmd=Attempting to decrypt data partition via command line.");
-					if (PartitionManager.Decrypt_Device(pass) == 0) {
-						set_page_done = 1;
-					}
-				} else if (OpenRecoveryScript::Insert_ORS_Command(command)) {
-					OpenRecoveryScript::run_script_file();
-				}
-				gui_set_FILE(NULL);
-				gGuiConsoleTerminate.set_value(1);
+				// close orsout and restart listener after command is done
+				OpenRecoveryScript::Call_After_CLI_Command(ors_command_done);
+				// run the command in a threaded action...
+				DataManager::SetValue("tw_action", "twcmd");
+				DataManager::SetValue("tw_action_param", command);
+				// ...and switch back to the current page when finished
+				std::string currentPage = PageManager::GetCurrentPage();
+				DataManager::SetValue("tw_has_action2", "1");
+				DataManager::SetValue("tw_action2", "page");
+				DataManager::SetValue("tw_action2_param", currentPage);
+				DataManager::SetValue("tw_action_text1", gui_lookup("running_recovery_commands", "Running Recovery Commands"));
+				DataManager::SetValue("tw_action_text2", "");
+				gui_changePage("singleaction_page");
+				// now immediately return to the GUI main loop (the action runs in the background thread)
+				// put all things that need to be done after the command is finished into ors_command_done, not here
 			}
 		}
-		fclose(orsout);
-		LOGINFO("Done reading ORS command from command line\n");
-		if (set_page_done) {
-			DataManager::SetValue("tw_page_done", 1);
-		} else {
-			// The select function will return ready to read and the
-			// read function will return errno 19 no such device unless
-			// we set everything up all over again.
-			close(ors_read_fd);
-			setup_ors_command();
-		}
 	} else {
 		LOGINFO("ORS command line read returned an error: %i, %i, %s\n", read_ret, errno, strerror(errno));
 	}
-	return;
 }
 
+// Get and dispatch input events until it's time to draw the next frame
 // This special function will return immediately the first time, but then
 // always returns 1/30th of a second (or immediately if called later) from
 // the last time it was called
@@ -648,7 +641,7 @@
 	{
 		loopTimer(input_timeout_ms);
 #ifndef TW_OEM_BUILD
-		if (ors_read_fd > 0) {
+		if (ors_read_fd > 0 && !orsout) { // orsout is non-NULL if a command is still running
 			FD_ZERO(&fdset);
 			FD_SET(ors_read_fd, &fdset);
 			timeout.tv_sec = 0;
@@ -660,10 +653,6 @@
 		}
 #endif
 
-		if (gGuiConsoleRunning.get_value()) {
-			continue;
-		}
-
 		if (!gForceRender.get_value())
 		{
 			int ret = PageManager::Update();
@@ -748,13 +737,6 @@
 	return 0;
 }
 
-int gui_changePackage(std::string newPackage)
-{
-	PageManager::SelectPackage(newPackage);
-	gForceRender.set_value(1);
-	return 0;
-}
-
 std::string gui_parse_text(std::string str)
 {
 	// This function parses text for DataManager values encompassed by %value% in the XML
@@ -957,11 +939,6 @@
 	if (!gGuiInitialized)
 		return -1;
 
-	gGuiConsoleTerminate.set_value(1);
-
-	while (gGuiConsoleRunning.get_value())
-		usleep(10000);
-
 	// Set the default package
 	PageManager::SelectPackage("TWRP");
 
@@ -981,60 +958,6 @@
 	return runPages(page_name, stop_on_page_done);
 }
 
-static void * console_thread(void *cookie __unused)
-{
-	PageManager::SwitchToConsole();
-
-	while (!gGuiConsoleTerminate.get_value())
-	{
-		loopTimer(0);
-
-		if (!gForceRender.get_value())
-		{
-			int ret;
-
-			ret = PageManager::Update();
-			if (ret > 1)
-				PageManager::Render();
-
-			if (ret > 0)
-				flip();
-
-			if (ret < 0)
-				LOGERR("An update request has failed.\n");
-		}
-		else
-		{
-			gForceRender.set_value(0);
-			PageManager::Render();
-			flip();
-		}
-	}
-	gGuiConsoleRunning.set_value(0);
-	gForceRender.set_value(1); // this will kickstart the GUI to render again
-	PageManager::EndConsole();
-	LOGINFO("Console stopping\n");
-	return NULL;
-}
-
-extern "C" int gui_console_only(void)
-{
-	if (!gGuiInitialized)
-		return -1;
-
-	gGuiConsoleTerminate.set_value(0);
-
-	if (gGuiConsoleRunning.get_value())
-		return 0;
-
-	gGuiConsoleRunning.set_value(1);
-
-	// Start by spinning off an input handler.
-	pthread_t t;
-	pthread_create(&t, NULL, console_thread, NULL);
-
-	return 0;
-}
 
 extern "C" void set_scale_values(float w, float h)
 {
diff --git a/gui/gui.h b/gui/gui.h
index f6f0483..034f1cd 100644
--- a/gui/gui.h
+++ b/gui/gui.h
@@ -21,7 +21,6 @@
 
 #include <stdio.h>
 
-int gui_console_only();
 int gui_init();
 int gui_loadResources();
 int gui_loadCustomResources();
diff --git a/gui/objects.hpp b/gui/objects.hpp
index 438905b..ebf08a8 100644
--- a/gui/objects.hpp
+++ b/gui/objects.hpp
@@ -366,6 +366,7 @@
 	int checkpartitionlifetimewrites(std::string arg);
 	int mountsystemtoggle(std::string arg);
 	int setlanguage(std::string arg);
+	int twcmd(std::string arg);
 
 	int simulate;
 };
diff --git a/gui/pages.cpp b/gui/pages.cpp
index 13f3bd7..4a65c69 100644
--- a/gui/pages.cpp
+++ b/gui/pages.cpp
@@ -1098,6 +1098,11 @@
 	return ((mCurrentPage && mCurrentPage == page) ? 1 : 0);
 }
 
+std::string PageSet::GetCurrentPage() const
+{
+	return mCurrentPage ? mCurrentPage->GetName() : "";
+}
+
 int PageSet::Render(void)
 {
 	int ret;
@@ -1544,6 +1549,11 @@
 	return ret;
 }
 
+std::string PageManager::GetCurrentPage()
+{
+	return mCurrentSet ? mCurrentSet->GetCurrentPage() : "";
+}
+
 int PageManager::ChangeOverlay(std::string name)
 {
 	if (name.empty())
@@ -1560,24 +1570,6 @@
 	return (mCurrentSet ? mCurrentSet->GetResources() : NULL);
 }
 
-int PageManager::SwitchToConsole(void)
-{
-	PageSet* console = new PageSet(NULL);
-
-	mCurrentSet = console;
-	return 0;
-}
-
-int PageManager::EndConsole(void)
-{
-	if (mCurrentSet && mBaseSet) {
-		delete mCurrentSet;
-		mCurrentSet = mBaseSet;
-		return 0;
-	}
-	return -1;
-}
-
 int PageManager::IsCurrentPage(Page* page)
 {
 	return (mCurrentSet ? mCurrentSet->IsCurrentPage(page) : 0);
diff --git a/gui/pages.hpp b/gui/pages.hpp
index 5dcc9e0..e7ad55e 100644
--- a/gui/pages.hpp
+++ b/gui/pages.hpp
@@ -101,6 +101,7 @@
 
 	// Helper routine for identifing if we're the current page
 	int IsCurrentPage(Page* page);
+	std::string GetCurrentPage() const;
 
 	// These are routing routines
 	int Render(void);
@@ -144,10 +145,7 @@
 	static int ChangePage(std::string name);
 	static int ChangeOverlay(std::string name);
 	static const ResourceManager* GetResources();
-
-	// Used for console-only mode
-	static int SwitchToConsole(void);
-	static int EndConsole(void);
+	static std::string GetCurrentPage();
 
 	// Helper to identify if a particular page is the active page
 	static int IsCurrentPage(Page* page);
diff --git a/openrecoveryscript.cpp b/openrecoveryscript.cpp
index b31a760..30c03b1 100644
--- a/openrecoveryscript.cpp
+++ b/openrecoveryscript.cpp
@@ -48,6 +48,8 @@
 	int TWinstall_zip(const char* path, int* wipe_cache);
 }
 
+OpenRecoveryScript::VoidFunction OpenRecoveryScript::call_after_cli_command;
+
 #define SCRIPT_COMMAND_SIZE 512
 
 int OpenRecoveryScript::check_for_script_file(void) {
@@ -398,6 +400,7 @@
 			}
 		}
 		fclose(fp);
+		unlink(SCRIPT_FILE_TMP);
 		gui_msg("done_ors=Done processing script file");
 	} else {
 		gui_msg(Msg(msg::kError, "error_opening_strerr=Error opening: '{1}' ({2})")(SCRIPT_FILE_TMP)(strerror(errno)));
@@ -569,9 +572,11 @@
 	return 0;
 }
 
+// this is called by main()
 void OpenRecoveryScript::Run_OpenRecoveryScript(void) {
 	DataManager::SetValue("tw_back", "main");
 	DataManager::SetValue("tw_action", "openrecoveryscript");
+	DataManager::SetValue("tw_action_param", "");
 	DataManager::SetValue("tw_has_action2", "0");
 	DataManager::SetValue("tw_action2", "");
 	DataManager::SetValue("tw_action2_param", "");
@@ -589,3 +594,66 @@
 		LOGERR("Failed to load OpenRecoveryScript GUI page.\n");
 	}
 }
+
+// this is called by the "openrecoveryscript" GUI action called via action page from Run_OpenRecoveryScript
+int OpenRecoveryScript::Run_OpenRecoveryScript_Action() {
+	int op_status = 1;
+	// Check for the SCRIPT_FILE_TMP first as these are AOSP recovery commands
+	// that we converted to ORS commands during boot in recovery.cpp.
+	// Run those first.
+	int reboot = 0;
+	if (TWFunc::Path_Exists(SCRIPT_FILE_TMP)) {
+		gui_msg("running_recovery_commands=Running Recovery Commands");
+		if (OpenRecoveryScript::run_script_file() == 0) {
+			reboot = 1;
+			op_status = 0;
+		}
+	}
+	// Check for the ORS file in /cache and attempt to run those commands.
+	if (OpenRecoveryScript::check_for_script_file()) {
+		gui_msg("running_ors=Running OpenRecoveryScript");
+		if (OpenRecoveryScript::run_script_file() == 0) {
+			reboot = 1;
+			op_status = 0;
+		}
+	}
+	if (reboot) {
+		// Disable stock recovery reflashing
+		TWFunc::Disable_Stock_Recovery_Replace();
+		usleep(2000000); // Sleep for 2 seconds before rebooting
+		TWFunc::tw_reboot(rb_system);
+		usleep(5000000); // Sleep for 5 seconds to allow reboot to occur
+	} else {
+		DataManager::SetValue("tw_page_done", 1);
+	}
+	return op_status;
+}
+
+// this is called by the "twcmd" GUI action when a command is received via FIFO from the "twrp" command line tool
+void OpenRecoveryScript::Run_CLI_Command(const char* command) {
+	if (strlen(command) > 11 && strncmp(command, "runscript", 9) == 0) {
+		const char* filename = command + 10;
+		if (OpenRecoveryScript::copy_script_file(filename) == 0) {
+			LOGINFO("Unable to copy script file\n");
+		} else {
+			OpenRecoveryScript::run_script_file();
+		}
+	} else if (strlen(command) > 5 && strncmp(command, "get", 3) == 0) {
+		const char* varname = command + 4;
+		string value;
+		DataManager::GetValue(varname, value);
+		gui_print("%s = %s\n", varname, value.c_str());
+	} else if (strlen(command) > 9 && strncmp(command, "decrypt", 7) == 0) {
+		const char* pass = command + 8;
+		gui_msg("decrypt_cmd=Attempting to decrypt data partition via command line.");
+		if (PartitionManager.Decrypt_Device(pass) == 0) {
+			// set_page_done = 1;  // done by singleaction_page anyway
+		}
+	} else if (OpenRecoveryScript::Insert_ORS_Command(command)) {
+		OpenRecoveryScript::run_script_file();
+	}
+
+	// let the GUI close the output fd and restart the command listener
+	call_after_cli_command();
+	LOGINFO("Done reading ORS command from command line\n");
+}
diff --git a/openrecoveryscript.hpp b/openrecoveryscript.hpp
index c3eabf6..3831195 100644
--- a/openrecoveryscript.hpp
+++ b/openrecoveryscript.hpp
@@ -23,18 +23,23 @@
 
 using namespace std;
 
-// Partition class
 class OpenRecoveryScript
 {
-public:
+	typedef void (*VoidFunction)();
+	static VoidFunction call_after_cli_command;                                    // callback to GUI after Run_CLI_Command
+
 	static int check_for_script_file();                                            // Checks to see if the ORS file is present in /cache
 	static int copy_script_file(string filename);                                  // Copies a script file to the temp folder
 	static int run_script_file();                                                  // Executes the commands in the ORS file
-	static int Insert_ORS_Command(string Command);                                 // Inserts the Command into the SCRIPT_FILE_TMP file
 	static int Install_Command(string Zip);                                        // Installs a zip
 	static string Locate_Zip_File(string Path, string File);                       // Attempts to locate the zip file in storage
 	static int Backup_Command(string Options);                                     // Runs a backup
+public:
+	static int Insert_ORS_Command(string Command);                                 // Inserts the Command into the SCRIPT_FILE_TMP file
 	static void Run_OpenRecoveryScript();                                          // Starts the GUI Page for running OpenRecoveryScript
+	static int Run_OpenRecoveryScript_Action();                                    // Actually runs the ORS scripts for the GUI action
+	static void Call_After_CLI_Command(VoidFunction fn) { call_after_cli_command = fn; }
+	static void Run_CLI_Command(const char* command);                              // Runs a command for orscmd (twrp binary)
 };
 
 #endif // _OPENRECOVERYSCRIPT_HPP