1import os 2import sys 3import re 4import platform 5import shutil 6from datetime import datetime 7from decimal import Decimal 8 9is_verbose = True 10 11btc = Decimal('1'+'0'*8) 12 13 14def to_btc(value): 15 return Decimal(value)/btc 16 17 18def set_verbosity(b): 19 global is_verbose 20 is_verbose = b 21 22 23def print_error(*args): 24 if not is_verbose: 25 return 26 args = [str(item) for item in args] 27 sys.stderr.write(" ".join(args) + "\n") 28 sys.stderr.flush() 29 30 31def print_msg(*args): 32 # Stringify args 33 args = [str(item) for item in args] 34 sys.stdout.write(" ".join(args) + "\n") 35 sys.stdout.flush() 36 37 38def print_json(obj): 39 import json 40 s = json.dumps(obj, sort_keys=True, indent=4) 41 sys.stdout.write(s + "\n") 42 sys.stdout.flush() 43 44 45def check_windows_wallet_migration(): 46 if platform.release() != "XP": 47 path = os.path.join(os.environ["LOCALAPPDATA"], "Electrum") 48 if os.path.exists(path): 49 if os.path.exists(os.path.join(os.environ["APPDATA"], "Electrum")): 50 print_msg("Two Electrum folders have been found, the " + 51 "default Electrum location for Windows has " + 52 "changed from %s to %s since Electrum 1.7, " + 53 "please check your wallets and fix the problem " + 54 "manually." % 55 (os.environ["LOCALAPPDATA"], os.environ["APPDATA"])) 56 sys.exit() 57 try: 58 shutil.move(path, os.path.join(os.environ["APPDATA"])) 59 print_msg("Your wallet has been moved from %s to %s." % 60 (os.environ["LOCALAPPDATA"], os.environ["APPDATA"])) 61 except: 62 print_msg("Failed to move your wallet.") 63 64 65def user_dir(): 66 if "HOME" in os.environ: 67 return os.path.join(os.environ["HOME"], ".electrum") 68 elif "APPDATA" in os.environ: 69 return os.path.join(os.environ["APPDATA"], "Electrum") 70 elif "LOCALAPPDATA" in os.environ: 71 return os.path.join(os.environ["LOCALAPPDATA"], "Electrum") 72 else: 73 return 74 75 76def appdata_dir(): 77 """Find the path to the application data directory; 78 add an electrum folder and return path.""" 79 if platform.system() == "Windows": 80 return os.path.join(os.environ["APPDATA"], "Electrum") 81 elif platform.system() == "Linux": 82 return os.path.join(sys.prefix, "share", "electrum") 83 elif (platform.system() == "Darwin" or 84 platform.system() == "DragonFly" or 85 platform.system() == "NetBSD"): 86 return "/Library/Application Support/Electrum" 87 else: 88 raise Exception("Unknown system") 89 90 91def get_resource_path(*args): 92 return os.path.join(".", *args) 93 94 95def local_data_dir(): 96 """Return path to the data folder.""" 97 assert sys.argv 98 prefix_path = os.path.dirname(sys.argv[0]) 99 local_data = os.path.join(prefix_path, "data") 100 return local_data 101 102 103def format_satoshis(x, is_diff=False, 104 num_zeros=0, decimal_point=8, 105 whitespaces=False): 106 from decimal import Decimal 107 s = Decimal(x) 108 sign, digits, exp = s.as_tuple() 109 digits = map(str, digits) 110 while len(digits) < decimal_point + 1: 111 digits.insert(0, '0') 112 digits.insert(-decimal_point, '.') 113 s = ''.join(digits).rstrip('0') 114 if sign: 115 s = '-' + s 116 elif is_diff: 117 s = "+" + s 118 119 p = s.find('.') 120 s += "0" * (1 + num_zeros - (len(s) - p)) 121 if whitespaces: 122 s += " " * (1 + decimal_point - (len(s) - p)) 123 s = " " * (13 - decimal_point - (p)) + s 124 return s 125 126 127# Takes a timestamp and returns a string with the approximation of the age 128def age(from_date, since_date=None, target_tz=None, include_seconds=False): 129 if from_date is None: 130 return "Unknown" 131 132 from_date = datetime.fromtimestamp(from_date) 133 if since_date is None: 134 since_date = datetime.now(target_tz) 135 136 distance_in_time = since_date - from_date 137 distance_in_seconds = distance_in_time.days * 86400 138 distance_in_seconds += distance_in_time.seconds 139 distance_in_seconds = int(round(abs(distance_in_seconds))) 140 distance_in_minutes = int(round(distance_in_seconds/60)) 141 142 if distance_in_minutes <= 1: 143 if include_seconds: 144 for remainder in [5, 10, 20]: 145 if distance_in_seconds < remainder: 146 return "less than %s seconds ago" % remainder 147 if distance_in_seconds < 40: 148 return "half a minute ago" 149 elif distance_in_seconds < 60: 150 return "less than a minute ago" 151 else: 152 return "1 minute ago" 153 else: 154 if distance_in_minutes == 0: 155 return "less than a minute ago" 156 else: 157 return "1 minute ago" 158 elif distance_in_minutes < 45: 159 return "%s minutes ago" % distance_in_minutes 160 elif distance_in_minutes < 90: 161 return "about 1 hour ago" 162 elif distance_in_minutes < 1440: 163 return "about %d hours ago" % (round(distance_in_minutes / 60.0)) 164 elif distance_in_minutes < 2880: 165 return "1 day ago" 166 elif distance_in_minutes < 43220: 167 return "%d days ago" % (round(distance_in_minutes / 1440)) 168 elif distance_in_minutes < 86400: 169 return "about 1 month ago" 170 elif distance_in_minutes < 525600: 171 return "%d months ago" % (round(distance_in_minutes / 43200)) 172 elif distance_in_minutes < 1051200: 173 return "about 1 year ago" 174 else: 175 return "over %d years ago" % (round(distance_in_minutes / 525600)) 176 177# URL decode 178_ud = re.compile('%([0-9a-hA-H]{2})', re.MULTILINE) 179urldecode = lambda x: _ud.sub(lambda m: chr(int(m.group(1), 16)), x) 180 181 182def parse_url(url): 183 o = url[8:].split('?') 184 address = o[0] 185 if len(o) > 1: 186 params = o[1].split('&') 187 else: 188 params = [] 189 190 amount = label = message = signature = identity = '' 191 for p in params: 192 k, v = p.split('=') 193 uv = urldecode(v) 194 if k == 'amount': 195 amount = uv 196 elif k == 'message': 197 message = uv 198 elif k == 'label': 199 label = uv 200 elif k == 'signature': 201 identity, signature = uv.split(':') 202 url = url.replace('&%s=%s' % (k, v), '') 203 else: 204 print k, v 205 206 return address, amount, label, message, signature, identity, url 207