<p>laforge has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.osmocom.org/c/pysim/+/23599">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">shell: Move dir,tree,export from ISO7816 to pySim commands<br><br>pySim has the notion of command categories.  The ISO7816 category<br>should only contain commands such as SELECT or CHV management<br>which really is ISO7816.  Custom commands like 'tree' or 'export'<br>are pySim specific and hence go into a different category.<br><br>Change-Id: Id38c8190c6279d037fe266c586065f1507a02932<br>---<br>M pySim-shell.py<br>1 file changed, 101 insertions(+), 96 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.osmocom.org:29418/pysim refs/changes/99/23599/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/pySim-shell.py b/pySim-shell.py</span><br><span>index ef76cb2..ae8a5a2 100755</span><br><span>--- a/pySim-shell.py</span><br><span>+++ b/pySim-shell.py</span><br><span>@@ -55,7 +55,7 @@</span><br><span> class PysimApp(cmd2.Cmd):</span><br><span>  CUSTOM_CATEGORY = 'pySim Commands'</span><br><span>   def __init__(self, card, rs, script = None):</span><br><span style="color: hsl(0, 100%, 40%);">-            basic_commands = [Iso7816Commands()]</span><br><span style="color: hsl(120, 100%, 40%);">+          basic_commands = [Iso7816Commands(), PySimCommands()]</span><br><span>                super().__init__(persistent_history_file='~/.pysim_shell_history', allow_cli_args=False,</span><br><span>                              use_ipython=True, auto_load_commands=False, command_sets=basic_commands, startup_script=script)</span><br><span>             self.intro = style('Welcome to pySim-shell!', fg=fg.red)</span><br><span>@@ -118,104 +118,11 @@</span><br><span>            else:</span><br><span>                        self.poutput("no description available")</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-@with_default_category('ISO7816 Commands')</span><br><span style="color: hsl(0, 100%, 40%);">-class Iso7816Commands(CommandSet):</span><br><span style="color: hsl(120, 100%, 40%);">+@with_default_category('pySim Commands')</span><br><span style="color: hsl(120, 100%, 40%);">+class PySimCommands(CommandSet):</span><br><span>       def __init__(self):</span><br><span>          super().__init__()</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-  def do_select(self, opts):</span><br><span style="color: hsl(0, 100%, 40%);">-              """SELECT a File (ADF/DF/EF)"""</span><br><span style="color: hsl(0, 100%, 40%);">-           if len(opts.arg_list) == 0:</span><br><span style="color: hsl(0, 100%, 40%);">-                     path_list = self._cmd.rs.selected_file.fully_qualified_path(True)</span><br><span style="color: hsl(0, 100%, 40%);">-                       path_list_fid = self._cmd.rs.selected_file.fully_qualified_path(False)</span><br><span style="color: hsl(0, 100%, 40%);">-                  self._cmd.poutput("currently selected file: " + '/'.join(path_list) + " (" + '/'.join(path_list_fid) + ")")</span><br><span style="color: hsl(0, 100%, 40%);">-                       return</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-          path = opts.arg_list[0]</span><br><span style="color: hsl(0, 100%, 40%);">-         fcp_dec = self._cmd.rs.select(path, self._cmd)</span><br><span style="color: hsl(0, 100%, 40%);">-          self._cmd.update_prompt()</span><br><span style="color: hsl(0, 100%, 40%);">-               self._cmd.poutput(json.dumps(fcp_dec, indent=4))</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-        def complete_select(self, text, line, begidx, endidx) -> List[str]:</span><br><span style="color: hsl(0, 100%, 40%);">-          """Command Line tab completion for SELECT"""</span><br><span style="color: hsl(0, 100%, 40%);">-              index_dict = { 1: self._cmd.rs.selected_file.get_selectable_names() }</span><br><span style="color: hsl(0, 100%, 40%);">-           return self._cmd.index_based_complete(text, line, begidx, endidx, index_dict=index_dict)</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-        def get_code(self, code):</span><br><span style="color: hsl(0, 100%, 40%);">-               """Use code either directly or try to get it from external data source"""</span><br><span style="color: hsl(0, 100%, 40%);">-         auto = ('PIN1', 'PIN2', 'PUK1', 'PUK2')</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-         if str(code).upper() not in auto:</span><br><span style="color: hsl(0, 100%, 40%);">-                       return sanitize_pin_adm(code)</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-           result = card_key_provider_get_field(str(code), key='ICCID', value=self._cmd.iccid)</span><br><span style="color: hsl(0, 100%, 40%);">-             result = sanitize_pin_adm(result)</span><br><span style="color: hsl(0, 100%, 40%);">-               if result:</span><br><span style="color: hsl(0, 100%, 40%);">-                      self._cmd.poutput("found %s '%s' for ICCID '%s'" % (code.upper(), result, self._cmd.iccid))</span><br><span style="color: hsl(0, 100%, 40%);">-           else:</span><br><span style="color: hsl(0, 100%, 40%);">-                   self._cmd.poutput("cannot find %s for ICCID '%s'" % (code.upper(), self._cmd.iccid))</span><br><span style="color: hsl(0, 100%, 40%);">-          return result</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-   verify_chv_parser = argparse.ArgumentParser()</span><br><span style="color: hsl(0, 100%, 40%);">-   verify_chv_parser.add_argument('--pin-nr', type=int, default=1, help='PIN Number, 1=PIN1, 2=PIN2 or custom value (decimal)')</span><br><span style="color: hsl(0, 100%, 40%);">-    verify_chv_parser.add_argument('pin_code', type=str, help='PIN code digits, \"PIN1\" or \"PIN2\" to get PIN code from external data source')</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-        @cmd2.with_argparser(verify_chv_parser)</span><br><span style="color: hsl(0, 100%, 40%);">- def do_verify_chv(self, opts):</span><br><span style="color: hsl(0, 100%, 40%);">-          """Verify (authenticate) using specified PIN code"""</span><br><span style="color: hsl(0, 100%, 40%);">-              pin = self.get_code(opts.pin_code)</span><br><span style="color: hsl(0, 100%, 40%);">-              (data, sw) = self._cmd.card._scc.verify_chv(opts.pin_nr, h2b(pin))</span><br><span style="color: hsl(0, 100%, 40%);">-              self._cmd.poutput("CHV verfication successful")</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       unblock_chv_parser = argparse.ArgumentParser()</span><br><span style="color: hsl(0, 100%, 40%);">-  unblock_chv_parser.add_argument('--pin-nr', type=int, default=1, help='PUK Number, 1=PIN1, 2=PIN2 or custom value (decimal)')</span><br><span style="color: hsl(0, 100%, 40%);">-   unblock_chv_parser.add_argument('puk_code', type=str, help='PUK code digits \"PUK1\" or \"PUK2\" to get PUK code from external data source')</span><br><span style="color: hsl(0, 100%, 40%);">-        unblock_chv_parser.add_argument('new_pin_code', type=str, help='PIN code digits \"PIN1\" or \"PIN2\" to get PIN code from external data source')</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    @cmd2.with_argparser(unblock_chv_parser)</span><br><span style="color: hsl(0, 100%, 40%);">-        def do_unblock_chv(self, opts):</span><br><span style="color: hsl(0, 100%, 40%);">-         """Unblock PIN code using specified PUK code"""</span><br><span style="color: hsl(0, 100%, 40%);">-           new_pin = self.get_code(opts.new_pin_code)</span><br><span style="color: hsl(0, 100%, 40%);">-              puk = self.get_code(opts.puk_code)</span><br><span style="color: hsl(0, 100%, 40%);">-              (data, sw) = self._cmd.card._scc.unblock_chv(opts.pin_nr, h2b(puk), h2b(new_pin))</span><br><span style="color: hsl(0, 100%, 40%);">-               self._cmd.poutput("CHV unblock successful")</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-   change_chv_parser = argparse.ArgumentParser()</span><br><span style="color: hsl(0, 100%, 40%);">-   change_chv_parser.add_argument('--pin-nr', type=int, default=1, help='PUK Number, 1=PIN1, 2=PIN2 or custom value (decimal)')</span><br><span style="color: hsl(0, 100%, 40%);">-    change_chv_parser.add_argument('pin_code', type=str, help='PIN code digits \"PIN1\" or \"PIN2\" to get PIN code from external data source')</span><br><span style="color: hsl(0, 100%, 40%);">- change_chv_parser.add_argument('new_pin_code', type=str, help='PIN code digits \"PIN1\" or \"PIN2\" to get PIN code from external data source')</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-     @cmd2.with_argparser(change_chv_parser)</span><br><span style="color: hsl(0, 100%, 40%);">- def do_change_chv(self, opts):</span><br><span style="color: hsl(0, 100%, 40%);">-          """Change PIN code to a new PIN code"""</span><br><span style="color: hsl(0, 100%, 40%);">-           new_pin = self.get_code(opts.new_pin_code)</span><br><span style="color: hsl(0, 100%, 40%);">-              pin = self.get_code(opts.pin_code)</span><br><span style="color: hsl(0, 100%, 40%);">-              (data, sw) = self._cmd.card._scc.change_chv(opts.pin_nr, h2b(pin), h2b(new_pin))</span><br><span style="color: hsl(0, 100%, 40%);">-                self._cmd.poutput("CHV change successful")</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    disable_chv_parser = argparse.ArgumentParser()</span><br><span style="color: hsl(0, 100%, 40%);">-  disable_chv_parser.add_argument('--pin-nr', type=int, default=1, help='PIN Number, 1=PIN1, 2=PIN2 or custom value (decimal)')</span><br><span style="color: hsl(0, 100%, 40%);">-   disable_chv_parser.add_argument('pin_code', type=str, help='PIN code digits, \"PIN1\" or \"PIN2\" to get PIN code from external data source')</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       @cmd2.with_argparser(disable_chv_parser)</span><br><span style="color: hsl(0, 100%, 40%);">-        def do_disable_chv(self, opts):</span><br><span style="color: hsl(0, 100%, 40%);">-         """Disable PIN code using specified PIN code"""</span><br><span style="color: hsl(0, 100%, 40%);">-           pin = self.get_code(opts.pin_code)</span><br><span style="color: hsl(0, 100%, 40%);">-              (data, sw) = self._cmd.card._scc.disable_chv(opts.pin_nr, h2b(pin))</span><br><span style="color: hsl(0, 100%, 40%);">-             self._cmd.poutput("CHV disable successful")</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-   enable_chv_parser = argparse.ArgumentParser()</span><br><span style="color: hsl(0, 100%, 40%);">-   enable_chv_parser.add_argument('--pin-nr', type=int, default=1, help='PIN Number, 1=PIN1, 2=PIN2 or custom value (decimal)')</span><br><span style="color: hsl(0, 100%, 40%);">-    enable_chv_parser.add_argument('pin_code', type=str, help='PIN code digits, \"PIN1\" or \"PIN2\" to get PIN code from external data source')</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-        @cmd2.with_argparser(enable_chv_parser)</span><br><span style="color: hsl(0, 100%, 40%);">- def do_enable_chv(self, opts):</span><br><span style="color: hsl(0, 100%, 40%);">-          """Enable PIN code using specified PIN code"""</span><br><span style="color: hsl(0, 100%, 40%);">-            pin = self.get_code(opts.pin_code)</span><br><span style="color: hsl(0, 100%, 40%);">-              (data, sw) = self._cmd.card._scc.enable_chv(opts.pin_nr, h2b(pin))</span><br><span style="color: hsl(0, 100%, 40%);">-              self._cmd.poutput("CHV enable successful")</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span>         dir_parser = argparse.ArgumentParser()</span><br><span>       dir_parser.add_argument('--fids', help='Show file identifiers', action='store_true')</span><br><span>         dir_parser.add_argument('--names', help='Show file names', action='store_true')</span><br><span>@@ -347,6 +254,104 @@</span><br><span>                      raise RuntimeError("unable to export %i file(s)" % context['ERR'])</span><br><span> </span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+@with_default_category('ISO7816 Commands')</span><br><span style="color: hsl(120, 100%, 40%);">+class Iso7816Commands(CommandSet):</span><br><span style="color: hsl(120, 100%, 40%);">+  def __init__(self):</span><br><span style="color: hsl(120, 100%, 40%);">+           super().__init__()</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  def do_select(self, opts):</span><br><span style="color: hsl(120, 100%, 40%);">+            """SELECT a File (ADF/DF/EF)"""</span><br><span style="color: hsl(120, 100%, 40%);">+         if len(opts.arg_list) == 0:</span><br><span style="color: hsl(120, 100%, 40%);">+                   path_list = self._cmd.rs.selected_file.fully_qualified_path(True)</span><br><span style="color: hsl(120, 100%, 40%);">+                     path_list_fid = self._cmd.rs.selected_file.fully_qualified_path(False)</span><br><span style="color: hsl(120, 100%, 40%);">+                        self._cmd.poutput("currently selected file: " + '/'.join(path_list) + " (" + '/'.join(path_list_fid) + ")")</span><br><span style="color: hsl(120, 100%, 40%);">+                     return</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+              path = opts.arg_list[0]</span><br><span style="color: hsl(120, 100%, 40%);">+               fcp_dec = self._cmd.rs.select(path, self._cmd)</span><br><span style="color: hsl(120, 100%, 40%);">+                self._cmd.update_prompt()</span><br><span style="color: hsl(120, 100%, 40%);">+             self._cmd.poutput(json.dumps(fcp_dec, indent=4))</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    def complete_select(self, text, line, begidx, endidx) -> List[str]:</span><br><span style="color: hsl(120, 100%, 40%);">+                """Command Line tab completion for SELECT"""</span><br><span style="color: hsl(120, 100%, 40%);">+            index_dict = { 1: self._cmd.rs.selected_file.get_selectable_names() }</span><br><span style="color: hsl(120, 100%, 40%);">+         return self._cmd.index_based_complete(text, line, begidx, endidx, index_dict=index_dict)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    def get_code(self, code):</span><br><span style="color: hsl(120, 100%, 40%);">+             """Use code either directly or try to get it from external data source"""</span><br><span style="color: hsl(120, 100%, 40%);">+               auto = ('PIN1', 'PIN2', 'PUK1', 'PUK2')</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+             if str(code).upper() not in auto:</span><br><span style="color: hsl(120, 100%, 40%);">+                     return sanitize_pin_adm(code)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+               result = card_key_provider_get_field(str(code), key='ICCID', value=self._cmd.iccid)</span><br><span style="color: hsl(120, 100%, 40%);">+           result = sanitize_pin_adm(result)</span><br><span style="color: hsl(120, 100%, 40%);">+             if result:</span><br><span style="color: hsl(120, 100%, 40%);">+                    self._cmd.poutput("found %s '%s' for ICCID '%s'" % (code.upper(), result, self._cmd.iccid))</span><br><span style="color: hsl(120, 100%, 40%);">+         else:</span><br><span style="color: hsl(120, 100%, 40%);">+                 self._cmd.poutput("cannot find %s for ICCID '%s'" % (code.upper(), self._cmd.iccid))</span><br><span style="color: hsl(120, 100%, 40%);">+                return result</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       verify_chv_parser = argparse.ArgumentParser()</span><br><span style="color: hsl(120, 100%, 40%);">+ verify_chv_parser.add_argument('--pin-nr', type=int, default=1, help='PIN Number, 1=PIN1, 2=PIN2 or custom value (decimal)')</span><br><span style="color: hsl(120, 100%, 40%);">+  verify_chv_parser.add_argument('pin_code', type=str, help='PIN code digits, \"PIN1\" or \"PIN2\" to get PIN code from external data source')</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    @cmd2.with_argparser(verify_chv_parser)</span><br><span style="color: hsl(120, 100%, 40%);">+       def do_verify_chv(self, opts):</span><br><span style="color: hsl(120, 100%, 40%);">+                """Verify (authenticate) using specified PIN code"""</span><br><span style="color: hsl(120, 100%, 40%);">+            pin = self.get_code(opts.pin_code)</span><br><span style="color: hsl(120, 100%, 40%);">+            (data, sw) = self._cmd.card._scc.verify_chv(opts.pin_nr, h2b(pin))</span><br><span style="color: hsl(120, 100%, 40%);">+            self._cmd.poutput("CHV verfication successful")</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   unblock_chv_parser = argparse.ArgumentParser()</span><br><span style="color: hsl(120, 100%, 40%);">+        unblock_chv_parser.add_argument('--pin-nr', type=int, default=1, help='PUK Number, 1=PIN1, 2=PIN2 or custom value (decimal)')</span><br><span style="color: hsl(120, 100%, 40%);">+ unblock_chv_parser.add_argument('puk_code', type=str, help='PUK code digits \"PUK1\" or \"PUK2\" to get PUK code from external data source')</span><br><span style="color: hsl(120, 100%, 40%);">+      unblock_chv_parser.add_argument('new_pin_code', type=str, help='PIN code digits \"PIN1\" or \"PIN2\" to get PIN code from external data source')</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        @cmd2.with_argparser(unblock_chv_parser)</span><br><span style="color: hsl(120, 100%, 40%);">+      def do_unblock_chv(self, opts):</span><br><span style="color: hsl(120, 100%, 40%);">+               """Unblock PIN code using specified PUK code"""</span><br><span style="color: hsl(120, 100%, 40%);">+         new_pin = self.get_code(opts.new_pin_code)</span><br><span style="color: hsl(120, 100%, 40%);">+            puk = self.get_code(opts.puk_code)</span><br><span style="color: hsl(120, 100%, 40%);">+            (data, sw) = self._cmd.card._scc.unblock_chv(opts.pin_nr, h2b(puk), h2b(new_pin))</span><br><span style="color: hsl(120, 100%, 40%);">+             self._cmd.poutput("CHV unblock successful")</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       change_chv_parser = argparse.ArgumentParser()</span><br><span style="color: hsl(120, 100%, 40%);">+ change_chv_parser.add_argument('--pin-nr', type=int, default=1, help='PUK Number, 1=PIN1, 2=PIN2 or custom value (decimal)')</span><br><span style="color: hsl(120, 100%, 40%);">+  change_chv_parser.add_argument('pin_code', type=str, help='PIN code digits \"PIN1\" or \"PIN2\" to get PIN code from external data source')</span><br><span style="color: hsl(120, 100%, 40%);">+       change_chv_parser.add_argument('new_pin_code', type=str, help='PIN code digits \"PIN1\" or \"PIN2\" to get PIN code from external data source')</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ @cmd2.with_argparser(change_chv_parser)</span><br><span style="color: hsl(120, 100%, 40%);">+       def do_change_chv(self, opts):</span><br><span style="color: hsl(120, 100%, 40%);">+                """Change PIN code to a new PIN code"""</span><br><span style="color: hsl(120, 100%, 40%);">+         new_pin = self.get_code(opts.new_pin_code)</span><br><span style="color: hsl(120, 100%, 40%);">+            pin = self.get_code(opts.pin_code)</span><br><span style="color: hsl(120, 100%, 40%);">+            (data, sw) = self._cmd.card._scc.change_chv(opts.pin_nr, h2b(pin), h2b(new_pin))</span><br><span style="color: hsl(120, 100%, 40%);">+              self._cmd.poutput("CHV change successful")</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        disable_chv_parser = argparse.ArgumentParser()</span><br><span style="color: hsl(120, 100%, 40%);">+        disable_chv_parser.add_argument('--pin-nr', type=int, default=1, help='PIN Number, 1=PIN1, 2=PIN2 or custom value (decimal)')</span><br><span style="color: hsl(120, 100%, 40%);">+ disable_chv_parser.add_argument('pin_code', type=str, help='PIN code digits, \"PIN1\" or \"PIN2\" to get PIN code from external data source')</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   @cmd2.with_argparser(disable_chv_parser)</span><br><span style="color: hsl(120, 100%, 40%);">+      def do_disable_chv(self, opts):</span><br><span style="color: hsl(120, 100%, 40%);">+               """Disable PIN code using specified PIN code"""</span><br><span style="color: hsl(120, 100%, 40%);">+         pin = self.get_code(opts.pin_code)</span><br><span style="color: hsl(120, 100%, 40%);">+            (data, sw) = self._cmd.card._scc.disable_chv(opts.pin_nr, h2b(pin))</span><br><span style="color: hsl(120, 100%, 40%);">+           self._cmd.poutput("CHV disable successful")</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       enable_chv_parser = argparse.ArgumentParser()</span><br><span style="color: hsl(120, 100%, 40%);">+ enable_chv_parser.add_argument('--pin-nr', type=int, default=1, help='PIN Number, 1=PIN1, 2=PIN2 or custom value (decimal)')</span><br><span style="color: hsl(120, 100%, 40%);">+  enable_chv_parser.add_argument('pin_code', type=str, help='PIN code digits, \"PIN1\" or \"PIN2\" to get PIN code from external data source')</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    @cmd2.with_argparser(enable_chv_parser)</span><br><span style="color: hsl(120, 100%, 40%);">+       def do_enable_chv(self, opts):</span><br><span style="color: hsl(120, 100%, 40%);">+                """Enable PIN code using specified PIN code"""</span><br><span style="color: hsl(120, 100%, 40%);">+          pin = self.get_code(opts.pin_code)</span><br><span style="color: hsl(120, 100%, 40%);">+            (data, sw) = self._cmd.card._scc.enable_chv(opts.pin_nr, h2b(pin))</span><br><span style="color: hsl(120, 100%, 40%);">+            self._cmd.poutput("CHV enable successful")</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> def parse_options():</span><br><span> </span><br><span>         parser = OptionParser(usage="usage: %prog [options]")</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/c/pysim/+/23599">change 23599</a>. To unsubscribe, or for help writing mail filters, visit <a href="https://gerrit.osmocom.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.osmocom.org/c/pysim/+/23599"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: pysim </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-Change-Id: Id38c8190c6279d037fe266c586065f1507a02932 </div>
<div style="display:none"> Gerrit-Change-Number: 23599 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: laforge <laforge@osmocom.org> </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>