Introduce concept of CardProfileAddon

We have a strict "one CardProfile per card" rule.  For a modern UICC
without legacy SIM support, that works great, as all applications
have AID and ADF and can hence be enumerated/detected that way.

However, in reality there are mostly UICC that have legacy SIM, GSM-R
or even CDMA support, all of which are not proper UICC applications
for historical reasons.

So instead of having hard-coded hacks in various places, let's introduce
the new concept of a CardProfileAddon.  Every profile can have any
number of those.  When building up the RuntimeState, we iterate over the
CardProfile addons, and probe which of those are actually on the card.
For those discovered, we add their files to the filesystem hierarchy.

Change-Id: I5866590b6d48f85eb889c9b1b8ab27936d2378b9
diff --git a/pySim/ts_51_011.py b/pySim/ts_51_011.py
index 1f98e72..c81bfdf 100644
--- a/pySim/ts_51_011.py
+++ b/pySim/ts_51_011.py
@@ -30,9 +30,10 @@
 #
 
 from pySim.profile import match_sim
-from pySim.profile import CardProfile
+from pySim.profile import CardProfile, CardProfileAddon
 from pySim.filesystem import *
 from pySim.ts_31_102_telecom import DF_PHONEBOOK, DF_MULTIMEDIA, DF_MCS, DF_V2X
+from pySim.gsm_r import AddonGSMR
 import enum
 from pySim.construct import *
 from construct import Optional as COptional
@@ -1047,8 +1048,12 @@
             },
         }
 
+        addons = [
+            AddonGSMR,
+        ]
+
         super().__init__('SIM', desc='GSM SIM Card', cla="a0",
-                         sel_ctrl="0000", files_in_mf=[DF_TELECOM(), DF_GSM()], sw=sw)
+                         sel_ctrl="0000", files_in_mf=[DF_TELECOM(), DF_GSM()], sw=sw, addons = addons)
 
     @staticmethod
     def decode_select_response(resp_hex: str) -> object:
@@ -1104,3 +1109,17 @@
     @staticmethod
     def match_with_card(scc: SimCardCommands) -> bool:
         return match_sim(scc)
+
+
+class AddonSIM(CardProfileAddon):
+    """An add-on that can be found on a UICC in order to support classic GSM SIM."""
+    def __init__(self):
+        files = [
+            DF_GSM(),
+            DF_TELECOM(),
+        ]
+        super().__init__('SIM', desc='GSM SIM', files_in_mf=files)
+
+    def probe(self, card:'CardBase') -> bool:
+        # we assume the add-on to be present in case DF.GSM is found on the card
+        return card.file_exists(self.files_in_mf[0].fid)