<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>