From 0f126fc0f81760a4b5244d48a73c4d7c30e2451c Mon Sep 17 00:00:00 2001
From: Matt Corallo <git@bluematt.me>
Date: Thu, 5 Jun 2014 21:05:42 -0400
Subject: [PATCH] Keep track of number->groups, add TODO to refresh, other
 tweaks

---
 js/helpers.js     | 33 +++++++++++++++++++++++++++++++--
 js/sendmessage.js | 15 +++++----------
 2 files changed, 36 insertions(+), 12 deletions(-)

diff --git a/js/helpers.js b/js/helpers.js
index 5bef94019..2589182ac 100644
--- a/js/helpers.js
+++ b/js/helpers.js
@@ -215,6 +215,8 @@ window.textsecure.utils = function() {
 		return isNumeric(countryCode) && countryCode.length < 4 && countryCode.length > 0;
 	}
 
+	// Verifies a number (possibly tweaking its format)
+	// This should be used ONLY to verify numbers provided by the user
 	self.verifyNumber = function(number, countryCode) {
 		//XXX: All verifyNumber stuff needs to match the server-side verification
 		var countryCodeValid = true;
@@ -412,11 +414,28 @@ window.textsecure.storage = function() {
 	self.groups = function() {
 		var self = {};
 
+		var addGroupToNumber = function(groupId, number) {
+			var membership = textsecure.storage.getEncrypted("groupMembership" + number, [groupId]);
+			if (membership.indexOf(groupId) < 0)
+				membership.push(groupId);
+			textsecure.storage.putEncrypted("groupMembership" + number, membership);
+		}
+
+		var removeGroupFromNumber = function(groupId, number) {
+			var membership = textsecure.storage.getEncrypted("groupMembership" + number, [groupId]);
+			membership = membership.filter(function(group) { return group != groupId; });
+			if (membership.length == 0)
+				textsecure.storage.removeEncrypted("groupMembership" + number);
+			else
+				textsecure.storage.putEncrypted("groupMembership" + number, membership);
+		}
+
 		self.createNewGroup = function(numbers, groupId) {
 			if (groupId === undefined) {
 				while (textsecure.storage.getEncrypted("group" + groupId) !== undefined)
 					groupId = new Uint32Array(textsecure.crypto.getRandomBytes(4))[0];
-			}
+			} else if (textsecure.storage.getEncrypted("group" + groupId) !== undefined)
+				throw new Error("Tried to recreate group");
 
 			var me = textsecure.utils.unencodeNumber(textsecure.storage.getUnencrypted("number_id"))[0];
 			var haveMe = false;
@@ -425,8 +444,10 @@ window.textsecure.storage = function() {
 				var number = textsecure.utils.verifyNumber(numbers[i]);
 				if (number == me)
 					haveMe = true;
-				if (finalNumbers.indexOf(number) < 0)
+				if (finalNumbers.indexOf(number) < 0) {
 					finalNumbers.push(number);
+					addGroupToNumber(groupId, number);
+				}
 			}
 
 			if (!haveMe)
@@ -464,6 +485,7 @@ window.textsecure.storage = function() {
 			if (i > -1) {
 				group.numbers.slice(i, 1);
 				textsecure.storage.putEncrypted("group" + groupId, group);
+				removeGroupFromNumber(groupId, number);
 			}
 
 			return group.numbers;
@@ -479,6 +501,7 @@ window.textsecure.storage = function() {
 
 			number = textsecure.utils.verifyNumber(number);
 			group.numbers.push(number);
+			addGroupToNumber(groupId, number);
 			textsecure.storage.putEncrypted("group" + groupId, group);
 
 			return group.numbers;
@@ -688,6 +711,12 @@ window.textsecure.subscribeToPush = function() {
 												newGroup.filter(function(number) { return decrypted.group.members.indexOf(number) < 0; }).length != 0)
 										throw new Error("Error calculating group member difference");
 
+									//TODO: Also follow this path if avatar + name haven't changed (ie we should start storing those)
+									if (decrypted.group.avatar === null && decrypted.group.added.length == 0 && decrypted.group.name === null)
+										return;
+
+									//TODO: Strictly verify all numbers (ie dont let verifyNumber do any user-magic tweaking)
+
 									decrypted.body = null;
 									decrypted.attachments = [];
 
diff --git a/js/sendmessage.js b/js/sendmessage.js
index 50b680e01..5e1a48674 100644
--- a/js/sendmessage.js
+++ b/js/sendmessage.js
@@ -10,13 +10,7 @@ window.textsecure.messaging = function() {
 					throw new Error("Identity key not consistent");
 
 			for (i in response) {
-				var updateDevice = (updateDevices === undefined);
-				if (!updateDevice)
-					for (j in updateDevices)
-						if (updateDevices[j] == response[i].deviceId)
-							updateDevice = true;
-
-				if (updateDevice)
+				if (updateDevices === undefined || updateDevices.indexOf(response[i].deviceId) > -1)
 					textsecure.storage.devices.saveDeviceObject({
 						encodedNumber: number + "." + response[i].deviceId,
 						identityKey: response[i].identityKey,
@@ -71,6 +65,7 @@ window.textsecure.messaging = function() {
 
 	var tryMessageAgain = function(number, encodedMessage, callback) {
 		//TODO: Wipe identity key!
+		//TODO: refresh groups
 		var message = textsecure.protos.decodePushMessageContentProtobuf(encodedMessage);
 		textsecure.sendMessage([number], message, callback);
 	}
@@ -99,9 +94,9 @@ window.textsecure.messaging = function() {
 			return function() {
 				var devicesForNumber = textsecure.storage.devices.getDeviceObjectsForNumber(number);
 				if (devicesForNumber.length == 0)
-					registerError(number, "Go empty device list when loading device keys", null);
-				else
-					doSendMessage(number, devicesForNumber, recurse);
+					return registerError(number, "Go empty device list when loading device keys", null);
+				//TODO: Refresh groups
+				doSendMessage(number, devicesForNumber, recurse);
 			}
 		}