refactor the menu, the mi2str() implementation, and tests

Instead of a sub-menu for changing the IMSI, just offer a dialog with the
current IMSI pre-filled in an edit field.
"Show IMSI" becomes just "Change IMSI" without changing anything.

Change mi2str() so that it simply returns a byte[] of the right size.

Test new mi2str()
diff --git a/sim-applet/src/org/osmocom/IMSIPseudo/IMSIPseudo.java b/sim-applet/src/org/osmocom/IMSIPseudo/IMSIPseudo.java
index 32bbe99..1482d46 100755
--- a/sim-applet/src/org/osmocom/IMSIPseudo/IMSIPseudo.java
+++ b/sim-applet/src/org/osmocom/IMSIPseudo/IMSIPseudo.java
@@ -19,17 +19,12 @@
 	private static final byte[] title = { 'I', 'M', 'S', 'I', ' ', 'P', 's', 'e', 'u', 'd', 'o', 'n', 'y', 'm',
 					   'i', 'z', 'a', 't', 'i', 'o', 'n'};
 	private static final byte[] showLU = {'S', 'h', 'o', 'w', ' ', 'L', 'U', ' ', 'c', 'o', 'u', 'n', 't', 'e', 'r'};
-	private static final byte[] showIMSI = {'S', 'h', 'o', 'w', ' ', 'I', 'M', 'S', 'I'};
-	private static final byte[] changeIMSI = {'C', 'h', 'a', 'n', 'g', 'e', ' ', 'I', 'M', 'S', 'I', ' '};
-	private final Object[] itemListMain = {title, showLU, showIMSI, changeIMSI};
-
-	/* Change IMSI menu */
-	private static final byte[] enterIMSI = {'E', 'n', 't', 'e', 'r', ' ', 'I', 'M', 'S', 'I' };
-	private static final byte[] setDigit1 = {'S', 'e', 't', ' ', '1', ' ', 'a', 's', ' ', 'l', 'a', 's', 't', ' ',
-						  'd', 'i', 'g', 'i', 't'};
-	private static final byte[] setDigit2 = {'S', 'e', 't', ' ', '2', ' ', 'a', 's', ' ', 'l', 'a', 's', 't', ' ',
-						  'd', 'i', 'g', 'i', 't'};
-	private final Object[] itemListChangeIMSI = {changeIMSI, enterIMSI, setDigit1, setDigit2};
+	private static final byte[] changeIMSI = {'C', 'h', 'a', 'n', 'g', 'e', ' ', 'I', 'M', 'S', 'I'};
+	private static final byte[] invalidIMSI = {'I', 'n', 'v', 'a', 'l', 'i', 'd', ' ', 'I', 'M', 'S', 'I'};
+	private static final byte[] noChange = {'N', 'o', ' ', 'c', 'h', 'a', 'n', 'g', 'e'};
+	private static final byte[] changed = {'I', 'M', 'S', 'I', ' ', 'c', 'h', 'a', 'n', 'g', 'e', 'd', '!'};
+	private static final byte error[] = {'E', 'R', 'R', 'O', 'R' };
+	private final Object[] itemListMain = {title, showLU, changeIMSI};
 
 	private IMSIPseudo() {
 		gsmFile = SIMSystem.getTheSIMView();
@@ -172,21 +167,6 @@
 		showMsg(msg);
 	}
 
-
-	private void showIMSI() {
-		/* 3GPP TS 31.102 4.2.2: IMSI */
-		byte[] msg = {'C', 'u', 'r', 'r', 'e', 'n', 't', ' ', 'I', 'M', 'S', 'I', ':', ' ',
-			      ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '};
-
-		try {
-			byte IMSI[] = readIMSI();
-			MobileIdentity.mi2str(msg, (byte)14, (byte)16, IMSI, false);
-			showMsgAndWaitKey(msg);
-		} catch (SIMViewException e) {
-			showError(e.getReason());
-		}
-	}
-
 	private void handleMenuResponseMain() {
 		ProactiveResponseHandler rspHdlr = ProactiveResponseHandler.getTheHandler();
 
@@ -194,43 +174,44 @@
 		case 1: /* Show LU counter */
 			showMsg(LUCounter);
 			break;
-		case 2: /* Show IMSI */
-			showIMSI();
-			break;
-		case 3: /* Change IMSI */
-			showMenu(itemListChangeIMSI);
-			handleMenuResponseChangeIMSI();
+		case 2: /* Change IMSI */
+			byte prevIMSI_mi[] = readIMSI();
+			byte prevIMSI_str[] = MobileIdentity.mi2str(prevIMSI_mi);
+			promptIMSI(prevIMSI_str);
 			break;
 		}
 	}
 
-	private void handleMenuResponseChangeIMSI() {
-		ProactiveResponseHandler rspHdlr = ProactiveResponseHandler.getTheHandler();
-		switch (rspHdlr.getItemIdentifier()) {
-		case 1: /* enter IMSI */
-			promptIMSI();
-			break;
-		case 2: /* set last digit to 1 */
-			promptIMSI();
-			break;
-		case 3: /* set last digit to 2 */
-			promptIMSI();
-			break;
-		}
-	}
-
-	private void promptIMSI()
+	private void promptIMSI(byte prevIMSI_str[])
 	{
-		byte[] msg = {'N', 'e', 'w', ' ', 'I', 'M', 'S', 'I', '?'};
-		byte imsi[] = prompt(msg, (short)0, (short)15);
-		/* The IMSI file should be 9 bytes long, even if the IMSI is shorter */
+		byte newIMSI_str[] = prevIMSI_str;
+
+		try {
+			newIMSI_str = prompt(changeIMSI, newIMSI_str, (short)0, (short)15);
+		} catch (Exception e) {
+			showError((short)40);
+			return;
+		}
+
+		if (newIMSI_str.length < 6 || newIMSI_str.length > 15
+		    || !Bytes.isDigit(newIMSI_str)) {
+			showMsg(invalidIMSI);
+			return;
+		}
+
+		if (Bytes.equals(newIMSI_str, prevIMSI_str)) {
+			showMsg(noChange);
+			return;
+		}
+
 		byte mi[];
 		try {
-			mi = MobileIdentity.str2mi(imsi, MobileIdentity.MI_IMSI, (byte)9);
+			/* The IMSI file should be 9 bytes long, even if the IMSI is shorter */
+			mi = MobileIdentity.str2mi(newIMSI_str, MobileIdentity.MI_IMSI, (byte)9);
 			writeIMSI(mi);
+			showMsg(changed);
 		} catch (Exception e) {
-			byte err[] = {'E', 'R', 'R' };
-			showMsgAndWaitKey(err);
+			showError((short)42);
 		}
 	}
 
diff --git a/sim-applet/src/org/osmocom/IMSIPseudo/MobileIdentity.java b/sim-applet/src/org/osmocom/IMSIPseudo/MobileIdentity.java
index e363932..7ddfb50 100644
--- a/sim-applet/src/org/osmocom/IMSIPseudo/MobileIdentity.java
+++ b/sim-applet/src/org/osmocom/IMSIPseudo/MobileIdentity.java
@@ -52,8 +52,7 @@
 		return rc;
 	}
 
-	public static byte mi2str(byte dst[], byte dst_ofs, byte dst_len,
-				  byte mi[], boolean allow_hex)
+	public static byte[] mi2str(byte mi[])
 	{
 		/* The IMSI byte array by example:
 		 * 08 99 10 07 00 00 10 74 90
@@ -92,8 +91,9 @@
 		boolean odd_nr_of_digits = ((mi_type & 0x08) != 0);
 		byte start_nibble = 2 + 1; // 2 to skip the bytelen, 1 to skip the mi_type
 		byte end_nibble = (byte)(2 + bytelen * 2 - (odd_nr_of_digits ? 0 : 1));
-		bcd2str(dst, dst_ofs, dst_len, mi, start_nibble, end_nibble, allow_hex);
-		return (byte)(end_nibble - start_nibble);
+		byte str[] = new byte[end_nibble - start_nibble];
+		bcd2str(str, (byte)0, (byte)str.length, mi, start_nibble, end_nibble, true);
+		return str;
 	}
 
 	public static byte char2bcd(byte c)
diff --git a/sim-applet/src/org/osmocom/IMSIPseudo/Test.java b/sim-applet/src/org/osmocom/IMSIPseudo/Test.java
index 3b37f26..5293afe 100644
--- a/sim-applet/src/org/osmocom/IMSIPseudo/Test.java
+++ b/sim-applet/src/org/osmocom/IMSIPseudo/Test.java
@@ -28,17 +28,36 @@
 		return new String(hexdump(data));
 	}
 
+	private static final String[] imsis = {
+		"123456",
+		"1234567",
+		"12345678",
+		"123456789",
+		"1234567890",
+		"12345678901",
+		"123456789012",
+		"1234567890123",
+		"12345678901234",
+		"123456789012345",
+		"1234567890123456",
+	};
+
+	private static void test_str2mi2str()
+	{
+		for (int i = 0; i < imsis.length; i++) {
+			byte str[] = imsis[i].getBytes();
+			byte mi[] = MobileIdentity.str2mi(str, MobileIdentity.MI_IMSI, (byte)9);
+			byte str_from_mi[] = MobileIdentity.mi2str(mi);
+			System.out.print("IMSI " + new String(str) + " --> MI " + hexdumpStr(mi) + " --> IMSI "
+					   + new String(str_from_mi));
+			if (Bytes.equals(str, str_from_mi))
+				System.out.println(" (ok)");
+			else
+				System.out.println(" ERROR!");
+		}
+	}
+
 	public static void main(String args[]){
-		System.out.println(hexdumpStr(MobileIdentity.str2mi("123456".getBytes(), (byte)1, (byte)9)));
-		System.out.println(hexdumpStr(MobileIdentity.str2mi("1234567".getBytes(), (byte)1, (byte)9)));
-		System.out.println(hexdumpStr(MobileIdentity.str2mi("12345678".getBytes(), (byte)1, (byte)9)));
-		System.out.println(hexdumpStr(MobileIdentity.str2mi("123456789".getBytes(), (byte)1, (byte)9)));
-		System.out.println(hexdumpStr(MobileIdentity.str2mi("1234567890".getBytes(), (byte)1, (byte)9)));
-		System.out.println(hexdumpStr(MobileIdentity.str2mi("12345678901".getBytes(), (byte)1, (byte)9)));
-		System.out.println(hexdumpStr(MobileIdentity.str2mi("123456789012".getBytes(), (byte)1, (byte)9)));
-		System.out.println(hexdumpStr(MobileIdentity.str2mi("1234567890123".getBytes(), (byte)1, (byte)9)));
-		System.out.println(hexdumpStr(MobileIdentity.str2mi("12345678901234".getBytes(), (byte)1, (byte)9)));
-		System.out.println(hexdumpStr(MobileIdentity.str2mi("123456789012345".getBytes(), (byte)1, (byte)9)));
-		System.out.println(hexdumpStr(MobileIdentity.str2mi("1234567890123456".getBytes(), (byte)1, (byte)9)));
+		test_str2mi2str();
 	}
 }