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);