Add support for multi-user decryption

* Add CLI support using the command "twrp decrypt <PASSWORD> [USER ID]"
* Add GUI support using the menu Advanced --> Decrypt User

multiuser: Parse users only when Decrypt_DE runs successfully

multiuser: Warn when not all users are decrypted

Change-Id: Ia5e943b13c2d5ec5c34ae97661133c19ff471e6d
diff --git a/gui/listbox.cpp b/gui/listbox.cpp
index 9fbe092..3386465 100644
--- a/gui/listbox.cpp
+++ b/gui/listbox.cpp
@@ -26,6 +26,7 @@
 #include "rapidxml.hpp"
 #include "objects.hpp"
 #include "../data.hpp"
+#include "../partitions.hpp"
 #include "pages.hpp"
 
 extern std::vector<language_struct> Language_List;
@@ -82,10 +83,28 @@
 					data.selected = 0;
 				mListItems.push_back(data);
 			}
+		} else if (mVariable == "tw_crypto_user_id") {
+			std::vector<users_struct>::iterator iter;
+			std::vector<users_struct>* Users_List = PartitionManager.Get_Users_List();
+			for (iter = Users_List->begin(); iter != Users_List->end(); iter++) {
+				if (!(*iter).isDecrypted) {
+					ListItem data;
+					data.displayName = (*iter).userName;
+					data.variableValue = (*iter).userId;
+					data.action = NULL;
+					DataManager::GetValue("tw_crypto_user_id", currentValue);
+					if (currentValue == (*iter).userId || currentValue == "") {
+						data.selected = 1;
+						DataManager::SetValue("tw_crypto_user_id", (*iter).userId);
+						DataManager::SetValue("tw_crypto_pwtype", (*iter).type);
+					} else
+						data.selected = 0;
+					mListItems.push_back(data);
+				}
+			}
 		}
-	}
-	else
-		allowSelection = false;		// allows using listbox as a read-only list or menu
+	} else
+		allowSelection = false;  // allows using listbox as a read-only list or menu
 
 	// Get the data for the list
 	child = FindNode(node, "listitem");
@@ -94,16 +113,14 @@
 		ListItem item;
 
 		attr = child->first_attribute("name");
-		if (!attr)
-			continue;
+		if (!attr) continue;
 		// We will parse display names when we get page focus to ensure that translating takes place
 		item.displayName = attr->value();
 		item.variableValue = gui_parse_text(child->value());
 		item.selected = (child->value() == currentValue);
 		item.action = NULL;
 		xml_node<>* action = child->first_node("action");
-		if (!action)
-			action = child->first_node("actions");
+		if (!action) action = child->first_node("actions");
 		if (action) {
 			item.action = new GUIAction(child);
 			allowSelection = true;
@@ -122,7 +139,7 @@
 		LoadConditions(child, item.mConditions);
 
 		mListItems.push_back(item);
-		mVisibleItems.push_back(mListItems.size()-1);
+		mVisibleItems.push_back(mListItems.size() - 1);
 
 		child = child->next_sibling("listitem");
 	}
@@ -137,6 +154,33 @@
 	if (!isConditionTrue())
 		return 0;
 
+	if (mVariable == "tw_crypto_user_id") {
+		mListItems.clear();
+		std::vector<users_struct>::iterator iter;
+		std::vector<users_struct>* Users_List = PartitionManager.Get_Users_List();
+		for (iter = Users_List->begin(); iter != Users_List->end(); iter++) {
+			if (!(*iter).isDecrypted) {
+				ListItem data;
+				data.displayName = (*iter).userName;
+				data.variableValue = (*iter).userId;
+				data.action = NULL;
+				DataManager::GetValue("tw_crypto_user_id", currentValue);
+				if (currentValue == (*iter).userId || currentValue == "") {
+					data.selected = 1;
+					DataManager::SetValue("tw_crypto_user_id", (*iter).userId);
+					DataManager::SetValue("tw_crypto_pwtype", (*iter).type);
+				} else
+				data.selected = 0;
+				mListItems.push_back(data);
+			}
+		}
+		mVisibleItems.clear();
+		for (size_t i = 0; i < mListItems.size(); i++) {
+			mVisibleItems.push_back(i);
+		}
+		mUpdate = 1;
+	}
+
 	GUIScrollList::Update();
 
 	if (mUpdate) {