diff --git a/mmgen/addr.py b/mmgen/addr.py index a524f1aa..fce78ac0 100755 --- a/mmgen/addr.py +++ b/mmgen/addr.py @@ -857,8 +857,8 @@ Record this checksum: it will be used to verify the password file in the future return True def scramble_seed(self,seed): - # Changing either pw_fmt, pw_len or scramble_key will cause a different, - # unrelated set of passwords to be generated: this is what we want. + # Changing either pw_fmt or pw_len will cause a different, unrelated + # set of passwords to be generated: this is what we want. # NB: In original implementation, pw_id_str was 'baseN', not 'bN' scramble_key = '{}:{}:{}'.format(self.pw_fmt,self.pw_len,self.pw_id_str) from mmgen.crypto import scramble_seed diff --git a/mmgen/altcoin.py b/mmgen/altcoin.py index c34b8f64..7d0a8c93 100755 --- a/mmgen/altcoin.py +++ b/mmgen/altcoin.py @@ -432,8 +432,6 @@ class CoinInfo(object): line[n] = re.sub(r' ',r'',line[n]) + ('',',')[n != len(line)-1] from mmgen.util import pmsg,pdie -# pmsg(sym) -# pdie(tt) if trust != -1: if sym in tt: src = tt[sym] @@ -501,7 +499,7 @@ class CoinInfo(object): 'mainnet': { 'pycoin': ( # broken: DASH - only compressed, LTC segwit old fmt - 'BTC','LTC','VIA','FTC','DOGE','MEC','MYR','UNO', + 'BTC','LTC','VIA','FTC','DOGE','MEC', 'JBS','MZC','RIC','DFC','FAI','ARG','ZEC','DCR'), 'pyethereum': ('ETH','ETC'), 'zcash_mini': ('ZEC',), diff --git a/mmgen/globalvars.py b/mmgen/globalvars.py index 7cf6aaa9..216d5f50 100755 --- a/mmgen/globalvars.py +++ b/mmgen/globalvars.py @@ -122,7 +122,8 @@ class g(object): required_opts = ( 'quiet','verbose','debug','outdir','echo_passphrase','passwd_file','stdout', 'show_hash_presets','label','keep_passphrase','keep_hash_preset','yes', - 'brain_params','b16','usr_randchars','coin','bob','alice','key_generator' + 'brain_params','b16','usr_randchars','coin','bob','alice','key_generator', + 'hidden_incog_input_params','in_fmt' ) incompatible_opts = ( ('base32','hex'), # mmgen-passgen diff --git a/mmgen/main.py b/mmgen/main.py index 9671dedf..f7163c49 100755 --- a/mmgen/main.py +++ b/mmgen/main.py @@ -26,6 +26,8 @@ def launch(what): what = 'wallet' if what == 'keygen': what = 'addrgen' + import sys + try: import termios except: # Windows __import__('mmgen.main_' + what) diff --git a/mmgen/main_autosign.py b/mmgen/main_autosign.py index 98be4d00..8f2b2d25 100755 --- a/mmgen/main_autosign.py +++ b/mmgen/main_autosign.py @@ -161,6 +161,7 @@ def do_umount(): subprocess.call(['umount',mountpoint]) def sign_tx_file(txfile): + from importlib import reload try: g.testnet = False g.coin = 'BTC' @@ -360,7 +361,7 @@ def do_loop(): while True: status = get_insert_status() if status and not prev_status: - msg('Device insert detected') + msg('Device insertion detected') do_sign() prev_status = status if not n % 10: diff --git a/mmgen/obj.py b/mmgen/obj.py index 3d4594f9..1ca0d82f 100755 --- a/mmgen/obj.py +++ b/mmgen/obj.py @@ -139,13 +139,14 @@ class Hilite(object): color_always = False width = 0 trunc_ok = True + dtype = str @classmethod # 'width' is screen width (greater than len(s) for CJK strings) # 'append_chars' and 'encl' must consist of single-width chars only def fmtc(cls,s,width=None,color=False,encl='',trunc_ok=None, center=False,nullrepl='',append_chars='',append_color=False): - s = str(s) + if cls.dtype == bytes: s = s.decode() s_wide_count = len([1 for ch in s if unicodedata.east_asian_width(ch) in ('F','W')]) assert type(encl) is str and len(encl) in (0,2),"'encl' must be 2-character str" a,b = list(encl) if encl else ('','') @@ -168,6 +169,12 @@ class Hilite(object): else: return cls.colorize(s.ljust(width-s_wide_count),color=color) + @classmethod + def colorize(cls,s,color=True): + if cls.dtype == bytes: s = s.decode() + k = color if type(color) is str else cls.color # hack: override color with str value + return globals()[k](s) if (color or cls.color_always) else s + def fmt(self,*args,**kwargs): assert args == () # forbid invocation w/o keywords return self.fmtc(self,*args,**kwargs) @@ -182,11 +189,6 @@ class Hilite(object): def __str__(self): return self.colorize(self,color=False) - @classmethod - def colorize(cls,s,color=True): - k = color if type(color) is str else cls.color # hack: override color with str value - return globals()[k](s) if (color or cls.color_always) else s - # For attrs that are always present in the data instance # Reassignment and deletion forbidden class MMGenImmutableAttr(object): # Descriptor @@ -202,7 +204,8 @@ class MMGenImmutableAttr(object): # Descriptor # forbid all reassignment def set_attr_ok(self,instance): - return not hasattr(instance,self.name) + return not self.name in instance.__dict__ +# return not hasattr(instance,self.name) def __set__(self,instance,value): if not self.set_attr_ok(instance): @@ -624,7 +627,7 @@ class WifKey(str,Hilite,InitErrors): if type(s) == cls: return s cls.arg_chk(cls,on_fail) try: - assert set(s) <= set(ascii_letters+digits),'not an ascii string' + assert set(s) <= set(ascii_letters+digits),'not an ascii alphanumeric string' from mmgen.globalvars import g g.proto.wif2hex(s) # raises exception on error return str.__new__(cls,s) @@ -643,7 +646,7 @@ class PubKey(HexBytes,MMGenObject): # TODO: add some real checks m = '{!r}: invalid value for pubkey ({})'.format(s,e.args[0]) return cls.init_fail(m,on_fail) -class PrivKey(str,Hilite,InitErrors,MMGenObject): +class PrivKey(bytes,Hilite,InitErrors,MMGenObject): color = 'red' width = 64 @@ -662,9 +665,9 @@ class PrivKey(str,Hilite,InitErrors,MMGenObject): if wif: try: assert s == None - assert set(wif) <= set(ascii_letters+digits),'not an ascii string' + assert set(wif) <= set(ascii_letters+digits),'not an ascii alphanumeric string' w2h = g.proto.wif2hex(wif) # raises exception on error - me = str.__new__(cls,w2h['hex']) + me = bytes.__new__(cls,w2h['hex']) me.compressed = w2h['compressed'] me.pubkey_type = w2h['pubkey_type'] me.wif = str.__new__(WifKey,wif) # check has been done @@ -678,9 +681,9 @@ class PrivKey(str,Hilite,InitErrors,MMGenObject): assert s and type(compressed) == bool and pubkey_type,'Incorrect args for PrivKey()' assert len(s) == cls.width // 2,'Key length must be {}'.format(cls.width/2) if pubkey_type == 'password': # skip WIF creation and pre-processing for passwds - me = str.__new__(cls,hexlify(s)) + me = bytes.__new__(cls,hexlify(s)) else: - me = str.__new__(cls,g.proto.preprocess_key(hexlify(s),pubkey_type)) + me = bytes.__new__(cls,g.proto.preprocess_key(hexlify(s),pubkey_type)) me.wif = WifKey(g.proto.hex2wif(me,pubkey_type,compressed),on_fail='raise') me.compressed = compressed me.pubkey_type = pubkey_type diff --git a/mmgen/opts.py b/mmgen/opts.py index 74191a06..51a374d6 100755 --- a/mmgen/opts.py +++ b/mmgen/opts.py @@ -20,7 +20,7 @@ """ opts.py: MMGen-specific options processing after generic processing by share.Opts """ -import sys,os +import sys,os,stat class opt(object): pass @@ -161,10 +161,8 @@ def override_from_cfg_file(cfg_data): else: cls,attr = g,name setattr(cls,attr,set_for_type(val,getattr(cls,attr),attr,src=g.cfg_file)) - # pmsg(cls,attr,getattr(cls,attr)) else: die(2,"'{}': unrecognized option in '{}'".format(name,g.cfg_file)) -# pdie('xxx') def override_from_env(): from mmgen.util import set_for_type diff --git a/mmgen/protocol.py b/mmgen/protocol.py index f8c207b0..2930f0aa 100755 --- a/mmgen/protocol.py +++ b/mmgen/protocol.py @@ -122,7 +122,7 @@ class BitcoinProtocol(MMGenObject): return '{:064x}'.format(pk % cls.secp256k1_ge).encode() @classmethod - def hex2wif(cls,hexpriv,pubkey_type,compressed): + def hex2wif(cls,hexpriv,pubkey_type,compressed): # PrivKey return _b58chk_encode(cls.wif_ver_num[pubkey_type] + hexpriv + (b'',b'01')[bool(compressed)]) @classmethod @@ -153,7 +153,7 @@ class BitcoinProtocol(MMGenObject): msg('{}: Invalid witness version number'.format(ret[0])) elif ret[1]: return { - 'hex': hexlify(''.join(map(chr,ret[1]))), + 'hex': hexlify(bytes(ret[1])), 'format': 'bech32' } if return_dict else True return False @@ -168,7 +168,6 @@ class BitcoinProtocol(MMGenObject): if g.debug: Msg('Address cannot be converted to base 58') break addr_hex = '{:0{}x}'.format(num,len(ver_num)+hex_width+8).encode() -# pmsg(hex_width,len(addr_hex),addr_hex[:len(ver_num)],ver_num) if addr_hex[:len(ver_num)] != ver_num: continue if hash256(addr_hex[:-8])[:8] == addr_hex[-8:]: return { diff --git a/mmgen/rpc.py b/mmgen/rpc.py index 637fee03..65777112 100755 --- a/mmgen/rpc.py +++ b/mmgen/rpc.py @@ -91,7 +91,7 @@ class CoinDaemonRPCConnection(object): for k in cf: if k in kwargs and kwargs[k]: cf[k] = kwargs[k] - hc = http.client.HTTPConnection(self.host, self.port, False, cf['timeout']) + hc = http.client.HTTPConnection(self.host,self.port,cf['timeout']) if cf['batch']: p = [{'method':cmd,'params':r,'id':n,'jsonrpc':'2.0'} for n,r in enumerate(args[0],1)] diff --git a/mmgen/seed.py b/mmgen/seed.py index 25c3be31..b294eb36 100755 --- a/mmgen/seed.py +++ b/mmgen/seed.py @@ -196,7 +196,7 @@ class SeedSource(MMGenObject): @classmethod def format_fmt_codes(cls): - d = [(c.__name__,('.'+c.ext if c.ext else c.ext),','.join(c.fmt_codes)) + d = [(c.__name__,('.'+c.ext if c.ext else str(c.ext)),','.join(c.fmt_codes)) for c in cls.get_subclasses() if hasattr(c,'fmt_codes')] w = max(len(i[0]) for i in d) @@ -414,16 +414,15 @@ class Mnemonic (SeedSourceUnenc): idx = bisect_left(wl,w) return(True,False)[idx == len(wl) or w != wl[idx]] - words,i,p = [],0,('Enter word #{}: ','Incorrect entry. Repeat word #{}: ') + p = ('Enter word #{}: ','Incorrect entry. Repeat word #{}: ') + words,err = [],0 while len(words) < mn_len: msg_r('{r}{s}{r}'.format(r='\r',s=' '*40)) - if i == 1: time.sleep(0.1) - msg_r(p[i].format(len(words)+1)) + if err == 1: time.sleep(0.1) + msg_r(p[err].format(len(words)+1)) s = get_word() - if in_list(s): - words.append(s); i = 0 - else: - i = 1 + if in_list(s): words.append(s) + err = (1,0)[in_list(s)] msg('') qmsg('Mnemonic successfully entered') return ' '.join(words) diff --git a/mmgen/share/Opts.py b/mmgen/share/Opts.py index ebb32291..b78219eb 100755 --- a/mmgen/share/Opts.py +++ b/mmgen/share/Opts.py @@ -22,7 +22,6 @@ Opts.py: Generic options handling import sys,getopt import collections -# from mmgen.util import mdie,die,pdie,pmsg # DEBUG def usage(opts_data): print(('USAGE: {} {}'.format(opts_data['prog_name'], opts_data['usage']))) @@ -56,7 +55,8 @@ def process_opts(argv,opts_data,short_opts,long_opts,skip_help=False): so_str = short_opts.replace('-:','').replace('-','') try: cl_opts,args = getopt.getopt(argv[1:], so_str, long_opts) except getopt.GetoptError as err: - print((str(err))); sys.exit(2) + print(str(err)) + sys.exit(2) sopts_list = ':_'.join(['_'.join(list(i)) for i in short_opts.split(':')]).split('_') opts,skipped_help = {},False diff --git a/mmgen/tool.py b/mmgen/tool.py index 1e0302d5..0e0c238d 100755 --- a/mmgen/tool.py +++ b/mmgen/tool.py @@ -22,17 +22,16 @@ tool.py: Routines and data for the 'mmgen-tool' utility """ import binascii +from collections import OrderedDict from mmgen.protocol import hash160 from mmgen.common import * from mmgen.crypto import * from mmgen.tx import * from mmgen.addr import * -from decimal import Decimal pnm = g.proj_name -from collections import OrderedDict cmd_data = OrderedDict([ ('Help', [' [str]']), ('Usage', [' [str]']), @@ -194,7 +193,7 @@ def process_args(command,cmd_args): usage(command) def conv_type(arg,arg_name,arg_type): - if arg_type == 'str': arg_type = 'unicode' + if arg_type == 'bytes': pdie(arg,arg_name,arg_type) if arg_type == 'bool': if arg.lower() in ('true','yes','1','on'): arg = True elif arg.lower() in ('false','no','0','off'): arg = False @@ -246,8 +245,9 @@ def Unhexdump(infile): if g.platform == 'win': import msvcrt msvcrt.setmode(sys.stdout.fileno(),os.O_BINARY) - sys.stdout.write(decode_pretty_hexdump( - get_data_from_file(infile,dash=True,silent=True))) + hexdata = get_data_from_file(infile,dash=True,silent=True) + ret = decode_pretty_hexdump(hexdata) + os.write(g.stdout_fileno,ret) def B58randenc(): r = get_random(32) @@ -594,7 +594,8 @@ def monero_wallet_ops(infile,op,blockheight=None,addrs=None): msg(' Wallet in sync') b = [l for l in p.before.decode().splitlines() if len(l) > 7 and l[:8] == 'Balance:'][0].split() msg(' Balance: {} Unlocked balance: {}'.format(b[1],b[4])) - bals[fn] = ( Decimal(b[1][:-1]), Decimal(b[4]) ) + from mmgen.obj import XMRAmt + bals[fn] = ( XMRAmt(b[1][:-1]), XMRAmt(b[4]) ) my_sendline(p,'Exiting','exit',5) p.read() break @@ -626,8 +627,8 @@ def monero_wallet_ops(infile,op,blockheight=None,addrs=None): col1_w = max(list(map(len,bals))) + 1 fs = '{:%s} {} {}' % col1_w msg('\n'+fs.format('Wallet','Balance ','Unlocked Balance ')) - tbals = [Decimal('0'),Decimal('0')] from mmgen.obj import XMRAmt + tbals = [XMRAmt('0'),XMRAmt('0')] for bal in bals: for i in (0,1): tbals[i] += bals[bal][i] msg(fs.format(bal+':',*[XMRAmt(b).fmt(fs='5.12',color=True) for b in bals[bal]])) @@ -655,7 +656,7 @@ def monero_wallet_ops(infile,op,blockheight=None,addrs=None): # ================ RPC commands ================== # -def Gen_addr(addr,wallet='',target='addr'): +def Gen_addr(addr,wallet='',target='addr',return_result=False): addr = MMGenID(addr) sf = get_seed_file([wallet] if wallet else [],1) opt.quiet = True @@ -666,7 +667,9 @@ def Gen_addr(addr,wallet='',target='addr'): die(1,m.format(addr.sid,ss.seed.sid)) al = AddrList(seed=ss.seed,addr_idxs=AddrIdxList(str(addr.idx)),mmtype=addr.mmtype,do_chksum=False) d = al.data[0] - Msg(d.sec.wif if target=='wif' else d.addr) + ret = d.sec.wif if target=='wif' else d.addr + if return_result: return ret + else: Msg(ret) def Gen_key(addr,wallet=''): return Gen_addr(addr,wallet,target='wif') diff --git a/mmgen/tx.py b/mmgen/tx.py index 107c6c03..81cd4a48 100755 --- a/mmgen/tx.py +++ b/mmgen/tx.py @@ -55,12 +55,12 @@ def strfmt_locktime(num,terse=False): # If greater than or equal to 500 million, locktime is parsed using the Unix epoch time # format (the number of seconds elapsed since 1970-01-01T00:00 UTC). The transaction can be # added to any block whose block time is greater than the locktime. - if num >= 5 * 10**6: + if num == None: + return '(None)' + elif num >= 5 * 10**6: return ' '.join(time.strftime('%c',time.gmtime(num)).split()[1:]) elif num > 0: return '{}{}'.format(('block height ','')[terse],num) - elif num == None: - return '(None)' else: die(2,"'{}': invalid locktime value!".format(num)) @@ -98,7 +98,7 @@ def segwit_is_active(exit_on_error=False): def bytes2int(hex_bytes): r = hexlify(unhexlify(hex_bytes)[::-1]) - if r[0] in b'89abcdef': + if hexlify(bytes([r[0]])) in b'89abcdef': die(3,"{}: Negative values not permitted in transaction!".format(hex_bytes)) return int(r,16) @@ -120,35 +120,36 @@ class DeserializedTX(OrderedDict,MMGenObject): # need to add MMGen types def __init__(self,txhex): tx = list(unhexlify(txhex)) tx_copy = tx[:] - d = { 'raw_tx':'' } + d = { 'raw_tx': [] } def hshift(l,n,reverse=False,skip=False): ret = l[:n] - if not skip: d['raw_tx'] += ''.join(ret) + if not skip: d['raw_tx'] += ret del l[:n] - return hexlify(''.join(ret[::-1] if reverse else ret)) + return hexlify(bytes(ret[::-1] if reverse else ret)) # https://bitcoin.org/en/developer-reference#compactsize-unsigned-integers # For example, the number 515 is encoded as 0xfd0302. def readVInt(l,skip=False,sub_null=False): - s = int(hexlify(l[0]),16) + s = l[0] bytes_len = 1 if s < 0xfd else 2 if s == 0xfd else 4 if s == 0xfe else 8 if bytes_len != 1: del l[0] - ret = int(hexlify(''.join(l[:bytes_len][::-1])),16) + ret = int(hexlify(bytes(l[:bytes_len][::-1])),16) if sub_null: d['raw_tx'] += b'\0' - elif not skip: d['raw_tx'] += ''.join(l[:bytes_len]) + elif not skip: d['raw_tx'] += l[:bytes_len] del l[:bytes_len] return ret d['version'] = bytes2int(hshift(tx,4)) - has_witness = tx[0] == '\x00' + has_witness = tx[0] == 0 if has_witness: - u = hshift(tx,2,skip=True)[2:] - if u != '01': + u = hshift(tx,2,skip=True) + if u != b'0001': raise IllegalWitnessFlagValue("'{}': Illegal value for flag in transaction!".format(u)) del tx_copy[-len(tx)-2:-len(tx)] d['num_txins'] = readVInt(tx) + d['txins'] = MMGenList([OrderedDict(( ('txid', hshift(tx,32,reverse=True)), ('vout', bytes2int(hshift(tx,4))), @@ -174,7 +175,7 @@ class DeserializedTX(OrderedDict,MMGenObject): # need to add MMGen types wd,tx = tx[:-4],tx[-4:] d['witness_size'] = len(wd) + 2 # add marker and flag for i in range(len(d['txins'])): - if hexlify(wd[0]) == '00': + if wd[0] == 0: hshift(wd,1,skip=True) continue d['txins'][i]['witness'] = [ @@ -184,12 +185,12 @@ class DeserializedTX(OrderedDict,MMGenObject): # need to add MMGen types raise WitnessSizeMismatch('More witness data than inputs with witnesses!') d['lock_time'] = bytes2int(hshift(tx,4)) - d['txid'] = hexlify(sha256(sha256(''.join(tx_copy)).digest()).digest()[::-1]) - d['unsigned_hex'] = hexlify(d['raw_tx']) + d['txid'] = hexlify(sha256(sha256(bytes(tx_copy)).digest()).digest()[::-1]) + d['unsigned_hex'] = hexlify(bytes(d['raw_tx'])) del d['raw_tx'] keys = 'txid','version','lock_time','witness_size','num_txins','txins','num_txouts','txouts','unsigned_hex' - return OrderedDict.__init__(self, ((k,d[k]) for k in keys)) + OrderedDict.__init__(self, ((k,d[k]) for k in keys)) txio_attrs = { 'vout': MMGenListItemAttr('vout',int,typeconv=False), @@ -315,8 +316,11 @@ Selected non-{pnm} inputs: {{}}""".strip().format(pnm=g.proj_name,pnl=g.proj_nam self.outputs.append(MMGenTX.MMGenTxOutput(addr=coinaddr,amt=amt,is_chg=is_chg)) def get_chg_output_idx(self): - try: return map(lambda x: x.is_chg,self.outputs).index(True) - except ValueError: return None + ch_ops = [x.is_chg for x in self.outputs] + try: + return ch_ops.index(True) + except ValueError: + return None def update_output_amt(self,idx,amt): o = self.outputs[idx].__dict__ @@ -352,13 +356,9 @@ Selected non-{pnm} inputs: {{}}""".strip().format(pnm=g.proj_name,pnl=g.proj_nam def check_dup_addrs(self,io_str): assert io_str in ('inputs','outputs') - io = getattr(self,io_str) - for k in ('mmid','addr'): - old_attr = None - for attr in sorted(getattr(e,k) for e in io): - if attr != None and attr == old_attr: - die(2,'{}: duplicate address in transaction {}'.format(attr,io_str)) - old_attr = attr + addrs = [e.addr for e in getattr(self,io_str)] + if len(addrs) != len(set(addrs)): + die(2,'{}: duplicate address in transaction {}'.format(attr,io_str)) def update_txid(self): self.txid = MMGenTxID(make_chksum_6(unhexlify(self.hex)).upper()) @@ -740,6 +740,9 @@ Selected non-{pnm} inputs: {{}}""".strip().format(pnm=g.proj_name,pnl=g.proj_nam msg('OK') return True except Exception as e: + if os.getenv('MMGEN_TRACEBACK'): + import traceback + ymsg('\n'+''.join(traceback.format_exception(*sys.exc_info()))) try: m = '{}'.format(e.args[0]) except: m = repr(e.args[0]) msg('\n'+yellow(m)) diff --git a/mmgen/util.py b/mmgen/util.py index 2f427be4..746e58db 100755 --- a/mmgen/util.py +++ b/mmgen/util.py @@ -23,7 +23,7 @@ util.py: Low-level routines imported by other modules in the MMGen suite import sys,os,time,stat,re,unicodedata from hashlib import sha256 from binascii import hexlify,unhexlify -from string import hexdigits +from string import hexdigits,digits from mmgen.color import * from mmgen.exception import * @@ -67,7 +67,7 @@ def Die(ev=0,s=''): def rdie(ev=0,s=''): die(ev,red(s)) def ydie(ev=0,s=''): die(ev,yellow(s)) -def hi(): sys.stdout.write(yellow('hi')) +def hi(): ymsg('hi') def pformat(d): import pprint @@ -122,7 +122,7 @@ def check_or_create_dir(path): os.listdir(path) except: try: - os.makedirs(path,0o700) + os.makedirs(path,stat.S_IRUSR|stat.S_IWUSR|stat.S_IXUSR) except: die(2,"ERROR: unable to read or create path '{}'".format(path)) @@ -232,6 +232,7 @@ def secs_to_hms(secs): def secs_to_ms(secs): return '{:02d}:{:02d}'.format(secs//60, secs % 60) +def is_digits(s): return set(list(s)) <= set(list(digits)) def is_int(s): try: int(str(s)) @@ -431,7 +432,7 @@ def compare_chksums(chk1,desc1,chk2,desc2,hdr='',die_on_fail=False,verbose=False return True def compare_or_die(val1, desc1, val2, desc2, e='Error'): - if cmp(val1,val2): + if val1 != val2: die(3,"{}: {} ({}) doesn't match {} ({})".format(e,desc2,val2,desc1,val1)) dmsg('{} OK ({})'.format(capfirst(desc2),val2)) return True @@ -740,8 +741,8 @@ def keypress_confirm(prompt,default_yes=False,verbose=False,no_nl=False): return (False,True)[default_yes] while True: - reply = get_char(p).strip(b'\n\r') - if not reply: + r = get_char(p).strip(b'\n\r') + if not r: if default_yes: msg_r(nl); return True else: msg_r(nl); return False elif r in b'yY': msg_r(nl); return True @@ -812,7 +813,7 @@ def get_daemon_cfg_options(cfg_keys): cfg_file = os.path.join(g.proto.daemon_data_dir,g.proto.name+'.conf') try: lines = get_lines_from_file(cfg_file,'',silent=bool(opt.quiet)) - kv_pairs = [split2(str(line).translate(None,'\t '),'=') for line in lines] + kv_pairs = [l.split('=') for l in lines] cfg = dict([(k,v) for k,v in kv_pairs if k in cfg_keys]) except: vmsg("Warning: '{}' does not exist or is unreadable".format(cfg_file))