Example #1
0
    def __init__(self, config, network):

        self.config = config
        self.network = network
        storage = WalletStorage(config)
        if not storage.file_exists:
            print "Wallet not found. try 'electrum-vior create'"
            exit()

        self.wallet = Wallet(storage)
        self.wallet.start_threads(self.network)

        locale.setlocale(locale.LC_ALL, '')
        self.encoding = locale.getpreferredencoding()

        self.stdscr = curses.initscr()
        curses.noecho()
        curses.cbreak()
        curses.start_color()
        curses.use_default_colors()
        curses.init_pair(1, curses.COLOR_WHITE, curses.COLOR_BLUE)
        curses.init_pair(2, curses.COLOR_WHITE, curses.COLOR_CYAN)
        self.stdscr.keypad(1)
        self.stdscr.border(0)
        self.maxy, self.maxx = self.stdscr.getmaxyx()
        self.set_cursor(0)
        self.w = curses.newwin(10, 50, 5, 5)

        set_verbosity(False)
        self.tab = 0
        self.pos = 0
        self.popup_pos = 0

        self.str_recipient = ""
        self.str_description = ""
        self.str_amount = ""
        self.str_fee = ""
        self.history = None

        if self.network:
            self.network.register_callback('updated', self.update)
            self.network.register_callback('connected', self.refresh)
            self.network.register_callback('disconnected', self.refresh)
            self.network.register_callback('disconnecting', self.refresh)

        self.tab_names = [
            _("History"),
            _("Send"),
            _("Receive"),
            _("Contacts"),
            _("Wall")
        ]
        self.num_tabs = len(self.tab_names)
    def main(self, url):

        storage = WalletStorage(self.config)
        if storage.file_exists:
            wallet = Wallet(storage)
            action = wallet.get_action()
        else:
            action = "new"

        if action is not None:
            import installwizard

            wizard = installwizard.InstallWizard(self.config, self.network, storage)
            wallet = wizard.run(action)
            if not wallet:
                exit()
        else:
            wallet.start_threads(self.network)

        # init tray
        self.dark_icon = self.config.get("dark_icon", False)
        icon = QIcon(":icons/electrum_dark_icon.png") if self.dark_icon else QIcon(":icons/electrum_light_icon.png")
        self.tray = QSystemTrayIcon(icon, None)
        self.tray.setToolTip("Electrum-VIOR")
        self.tray.activated.connect(self.tray_activated)
        self.build_tray_menu()
        self.tray.show()

        # main window
        self.main_window = w = ElectrumWindow(self.config, self.network, self)
        self.current_window = self.main_window

        # lite window
        self.init_lite()

        # plugins that need to change the GUI do it here
        run_hook("init")

        w.load_wallet(wallet)

        s = Timer()
        s.start()

        self.windows.append(w)
        if url:
            self.set_url(url)

        w.app = self.app
        w.connect_slots(s)
        w.update_wallet()

        self.app.exec_()

        # clipboard persistence
        # see http://www.mail-archive.com/[email protected]/msg17328.html
        event = QtCore.QEvent(QtCore.QEvent.Clipboard)
        self.app.sendEvent(self.app.clipboard(), event)

        wallet.stop_threads()
Example #3
0
    def __init__(self, config, network):
        self.network = network
        self.config = config
        storage = WalletStorage(config)
        if not storage.file_exists:
            print "Wallet not found. try 'electrum-vior create'"
            exit()

	self.done = 0
        self.last_balance = ""

        set_verbosity(False)

        self.str_recipient = ""
        self.str_description = ""
        self.str_amount = ""
        self.str_fee = ""

        self.wallet = Wallet(storage)
        self.wallet.start_threads(network)
        
        self.wallet.network.register_callback('updated', self.updated)
        self.wallet.network.register_callback('connected', self.connected)
        self.wallet.network.register_callback('disconnected', self.disconnected)
        self.wallet.network.register_callback('disconnecting', self.disconnecting)
        self.wallet.network.register_callback('peers', self.peers)
        self.wallet.network.register_callback('banner', self.print_banner)
        self.commands = [_("[h] - displays this help text"), \
                         _("[i] - display transaction history"), \
                         _("[o] - enter payment order"), \
                         _("[p] - print stored payment order"), \
                         _("[s] - send stored payment order"), \
                         _("[r] - show own receipt addresses"), \
                         _("[c] - display contacts"), \
                         _("[b] - print server banner"), \
                         _("[q] - quit") ]
        self.num_commands = len(self.commands)
Example #4
0
    def __init__(self, config, network):

        self.config = config
        self.network = network
        storage = WalletStorage(config)
        if not storage.file_exists:
            print "Wallet not found. try 'electrum-vior create'"
            exit()

        self.wallet = Wallet(storage)
        self.wallet.start_threads(self.network)

        locale.setlocale(locale.LC_ALL, '')
        self.encoding = locale.getpreferredencoding()

        self.stdscr = curses.initscr()
        curses.noecho()
        curses.cbreak()
        curses.start_color()
        curses.use_default_colors()
        curses.init_pair(1, curses.COLOR_WHITE, curses.COLOR_BLUE)
        curses.init_pair(2, curses.COLOR_WHITE, curses.COLOR_CYAN)
        self.stdscr.keypad(1)
        self.stdscr.border(0)
        self.maxy, self.maxx = self.stdscr.getmaxyx()
        self.set_cursor(0)
        self.w = curses.newwin(10, 50, 5, 5)

        set_verbosity(False)
        self.tab = 0
        self.pos = 0
        self.popup_pos = 0

        self.str_recipient = ""
        self.str_description = ""
        self.str_amount = ""
        self.str_fee = ""
        self.history = None
       
        if self.network: 
            self.network.register_callback('updated', self.update)
            self.network.register_callback('connected', self.refresh)
            self.network.register_callback('disconnected', self.refresh)
            self.network.register_callback('disconnecting', self.refresh)

        self.tab_names = [_("History"), _("Send"), _("Receive"), _("Contacts"), _("Wall")]
        self.num_tabs = len(self.tab_names)
Example #5
0
    def main(self, url=None):

        storage = WalletStorage(self.config)
        if not storage.file_exists:
            action = self.restore_or_create()
            if not action:
                exit()
            self.wallet = wallet = Wallet(storage)
            gap = self.config.get('gap_limit', 5)
            if gap != 5:
                wallet.gap_limit = gap
                wallet.storage.put('gap_limit', gap, True)

            if action == 'create':
                seed = wallet.make_seed()
                show_seed_dialog(seed, None)
                r = change_password_dialog(False, None)
                password = r[2] if r else None
                wallet.add_seed(seed, password)
                wallet.create_accounts(password)
                wallet.synchronize()  # generate first addresses offline

            elif action == 'restore':
                seed = self.seed_dialog()
                if not seed:
                    exit()
                r = change_password_dialog(False, None)
                password = r[2] if r else None
                wallet.add_seed(seed, password)
                wallet.create_accounts(password)
                
            else:
                exit()
        else:
            self.wallet = Wallet(storage)
            action = None

        self.wallet.start_threads(self.network)

        if action == 'restore':
            self.restore_wallet(wallet)

        w = ElectrumWindow(self.wallet, self.config, self.network)
        if url: w.set_url(url)
        Gtk.main()
Example #6
0
def run_recovery_dialog():
    message = "Please enter your wallet seed or the corresponding mnemonic list of words, and the gap limit of your wallet."
    dialog = Gtk.MessageDialog(
        parent = None,
        flags = Gtk.DialogFlags.MODAL, 
        buttons = Gtk.ButtonsType.OK_CANCEL,
        message_format = message)

    vbox = dialog.vbox
    dialog.set_default_response(Gtk.ResponseType.OK)

    # ask seed, server and gap in the same dialog
    seed_box = Gtk.HBox()
    seed_label = Gtk.Label(label='Seed or mnemonic:')
    seed_label.set_size_request(150,-1)
    seed_box.pack_start(seed_label, False, False, 10)
    seed_label.show()
    seed_entry = Gtk.Entry()
    seed_entry.show()
    seed_entry.set_size_request(450,-1)
    seed_box.pack_start(seed_entry, False, False, 10)
    add_help_button(seed_box, '.')
    seed_box.show()
    vbox.pack_start(seed_box, False, False, 5)    

    dialog.show()
    r = dialog.run()
    seed = seed_entry.get_text()
    dialog.destroy()

    if r==Gtk.ResponseType.CANCEL:
        return False

    if Wallet.is_seed(seed):
        return seed

    show_message("no seed")
    return False
        params = sys.argv[2:] + [my_password]
        ret = send_command(cmd, params)
        sys.exit(ret)

    conn = sqlite3.connect(database)
    # create table if needed
    check_create_table(conn)

    # init network
    config = SimpleConfig({'wallet_path': wallet_path})
    network = Network(config)
    network.start(wait=True)

    # create watching_only wallet
    storage = WalletStorage(config)
    wallet = Wallet(storage)
    if not storage.file_exists:
        wallet.seed = ''
        wallet.create_watching_only_wallet(master_public_key, master_chain)

    wallet.synchronize = lambda: None  # prevent address creation by the wallet
    wallet.start_threads(network)
    network.register_callback('updated', on_wallet_update)

    out_queue = Queue.Queue()
    thread.start_new_thread(server_thread, (conn, ))

    while not stopping:
        cur = conn.cursor()

        # read pending requests from table
    def __init__(self, config, _network):
        global wallet, network
        network = _network
        network.register_callback('updated', update_callback)
        network.register_callback('connected', update_callback)
        network.register_callback('disconnected', update_callback)
        network.register_callback('disconnecting', update_callback)

        storage = WalletStorage(config)
        if not storage.file_exists:
            action = self.restore_or_create()
            if not action: exit()

            wallet = Wallet(storage)
            if action == 'create':
                wallet.init_seed(None)
                self.show_seed()
                wallet.save_seed(None)
                wallet.synchronize()  # generate first addresses offline

            elif action == 'restore':
                seed = self.seed_dialog()
                if not seed:
                    exit()
                wallet.init_seed(str(seed))
                wallet.save_seed(None)
            else:
                exit()

            wallet.start_threads(network)

            if action == 'restore':
                if not self.restore_wallet():
                    exit()

            self.password_dialog()

        else:
            wallet = Wallet(storage)
            wallet.start_threads(network)
    def main(self, url):

        storage = WalletStorage(self.config)
        if storage.file_exists:
            wallet = Wallet(storage)
            action = wallet.get_action()
        else:
            action = 'new'

        if action is not None:
            import installwizard
            wizard = installwizard.InstallWizard(self.config, self.network,
                                                 storage)
            wallet = wizard.run(action)
            if not wallet:
                exit()
        else:
            wallet.start_threads(self.network)

        # init tray
        self.dark_icon = self.config.get("dark_icon", False)
        icon = QIcon(
            ":icons/electrum_dark_icon.png") if self.dark_icon else QIcon(
                ':icons/electrum_light_icon.png')
        self.tray = QSystemTrayIcon(icon, None)
        self.tray.setToolTip('Electrum-VIOR')
        self.tray.activated.connect(self.tray_activated)
        self.build_tray_menu()
        self.tray.show()

        # main window
        self.main_window = w = ElectrumWindow(self.config, self.network, self)
        self.current_window = self.main_window

        #lite window
        self.init_lite()

        # plugins that need to change the GUI do it here
        run_hook('init')

        w.load_wallet(wallet)

        s = Timer()
        s.start()

        self.windows.append(w)
        if url:
            self.set_url(url)

        w.app = self.app
        w.connect_slots(s)
        w.update_wallet()

        self.app.exec_()

        # clipboard persistence
        # see http://www.mail-archive.com/[email protected]/msg17328.html
        event = QtCore.QEvent(QtCore.QEvent.Clipboard)
        self.app.sendEvent(self.app.clipboard(), event)

        wallet.stop_threads()
Example #10
0
class ElectrumGui:

    def __init__(self, config, network):

        self.config = config
        self.network = network
        storage = WalletStorage(config)
        if not storage.file_exists:
            print "Wallet not found. try 'electrum-vior create'"
            exit()

        self.wallet = Wallet(storage)
        self.wallet.start_threads(self.network)

        locale.setlocale(locale.LC_ALL, '')
        self.encoding = locale.getpreferredencoding()

        self.stdscr = curses.initscr()
        curses.noecho()
        curses.cbreak()
        curses.start_color()
        curses.use_default_colors()
        curses.init_pair(1, curses.COLOR_WHITE, curses.COLOR_BLUE)
        curses.init_pair(2, curses.COLOR_WHITE, curses.COLOR_CYAN)
        self.stdscr.keypad(1)
        self.stdscr.border(0)
        self.maxy, self.maxx = self.stdscr.getmaxyx()
        self.set_cursor(0)
        self.w = curses.newwin(10, 50, 5, 5)

        set_verbosity(False)
        self.tab = 0
        self.pos = 0
        self.popup_pos = 0

        self.str_recipient = ""
        self.str_description = ""
        self.str_amount = ""
        self.str_fee = ""
        self.history = None
       
        if self.network: 
            self.network.register_callback('updated', self.update)
            self.network.register_callback('connected', self.refresh)
            self.network.register_callback('disconnected', self.refresh)
            self.network.register_callback('disconnecting', self.refresh)

        self.tab_names = [_("History"), _("Send"), _("Receive"), _("Contacts"), _("Wall")]
        self.num_tabs = len(self.tab_names)


    def set_cursor(self, x):
        try:
            curses.curs_set(x)
        except Exception:
            pass

    def restore_or_create(self):
        pass

    def verify_seed(self):
        pass
    
    def get_string(self, y, x):
        self.set_cursor(1)
        curses.echo()
        self.stdscr.addstr( y, x, " "*20, curses.A_REVERSE)
        s = self.stdscr.getstr(y,x)
        curses.noecho()
        self.set_cursor(0)
        return s

    def update(self):
        self.update_history()
        if self.tab == 0: 
            self.print_history()
        self.refresh()

    def print_history(self):

        width = [20, 40, 14, 14]
        delta = (self.maxx - sum(width) - 4)/3
        format_str = "%"+"%d"%width[0]+"s"+"%"+"%d"%(width[1]+delta)+"s"+"%"+"%d"%(width[2]+delta)+"s"+"%"+"%d"%(width[3]+delta)+"s"

        if self.history is None:
            self.update_history()

        self.print_list(self.history[::-1], format_str%( _("Date"), _("Description"), _("Amount"), _("Balance")))

    def update_history(self):
        width = [20, 40, 14, 14]
        delta = (self.maxx - sum(width) - 4)/3
        format_str = "%"+"%d"%width[0]+"s"+"%"+"%d"%(width[1]+delta)+"s"+"%"+"%d"%(width[2]+delta)+"s"+"%"+"%d"%(width[3]+delta)+"s"

        b = 0 
        self.history = []

        for item in self.wallet.get_tx_history():
            tx_hash, conf, is_mine, value, fee, balance, timestamp = item
            if conf:
                try:
                    time_str = datetime.datetime.fromtimestamp( timestamp).isoformat(' ')[:-3]
                except Exception:
                    time_str = "------"
            else:
                time_str = 'pending'

            label, is_default_label = self.wallet.get_label(tx_hash)
            self.history.append( format_str%( time_str, label, format_satoshis(value, whitespaces=True), format_satoshis(balance, whitespaces=True) ) )


    def print_balance(self):
        if not self.network:
            msg = _("Offline")
        elif self.network.interface and self.network.interface.is_connected:
            if not self.wallet.up_to_date:
                msg = _("Synchronizing...")
            else: 
                c, u =  self.wallet.get_balance()
                msg = _("Balance")+": %f  "%(Decimal( c ) / 100000000)
                if u: msg += "  [%f unconfirmed]"%(Decimal( u ) / 100000000)
        else:
            msg = _("Not connected")
            
        self.stdscr.addstr( self.maxy -1, 3, msg)

        for i in range(self.num_tabs):
            self.stdscr.addstr( 0, 2 + 2*i + len(''.join(self.tab_names[0:i])), ' '+self.tab_names[i]+' ', curses.A_BOLD if self.tab == i else 0)
            
        self.stdscr.addstr( self.maxy -1, self.maxx-30, ' '.join([_("Settings"), _("Network"), _("Quit")]))


    def print_contacts(self):
        messages = map(lambda addr: "%30s    %30s       "%(addr, self.wallet.labels.get(addr,"")), self.wallet.addressbook)
        self.print_list(messages, "%19s  %25s "%("Address", "Label"))

    def print_receive(self):
        fmt = "%-35s  %-30s"
        messages = map(lambda addr: fmt % (addr, self.wallet.labels.get(addr,"")), self.wallet.addresses())
        self.print_list(messages,   fmt % ("Address", "Label"))

    def print_edit_line(self, y, label, text, index, size):
        text += " "*(size - len(text) )
        self.stdscr.addstr( y, 2, label)
        self.stdscr.addstr( y, 15, text, curses.A_REVERSE if self.pos%6==index else curses.color_pair(1))

    def print_send_tab(self):
        self.stdscr.clear()
        self.print_edit_line(3, _("Pay to"), self.str_recipient, 0, 40)
        self.print_edit_line(5, _("Description"), self.str_description, 1, 40)
        self.print_edit_line(7, _("Amount"), self.str_amount, 2, 15)
        self.print_edit_line(9, _("Fee"), self.str_fee, 3, 15)
        self.stdscr.addstr( 12, 15, _("[Send]"), curses.A_REVERSE if self.pos%6==4 else curses.color_pair(2))
        self.stdscr.addstr( 12, 25, _("[Clear]"), curses.A_REVERSE if self.pos%6==5 else curses.color_pair(2))

    def print_banner(self):
        if self.network:
            self.print_list( self.network.banner.split('\n'))

    def print_list(self, list, firstline = None):
        self.maxpos = len(list)
        if not self.maxpos: return
        if firstline:
            firstline += " "*(self.maxx -2 - len(firstline))
            self.stdscr.addstr( 1, 1, firstline )
        for i in range(self.maxy-4):
            msg = list[i] if i < len(list) else ""
            msg += " "*(self.maxx - 2 - len(msg))
            m = msg[0:self.maxx - 2]
            m = m.encode(self.encoding)
            self.stdscr.addstr( i+2, 1, m, curses.A_REVERSE if i == (self.pos % self.maxpos) else 0)

    def refresh(self):
        if self.tab == -1: return
        self.stdscr.border(0)
        self.print_balance()
        self.stdscr.refresh()

    def main_command(self):
        c = self.stdscr.getch()
        print c
        if   c == curses.KEY_RIGHT: self.tab = (self.tab + 1)%self.num_tabs
        elif c == curses.KEY_LEFT: self.tab = (self.tab - 1)%self.num_tabs
        elif c == curses.KEY_DOWN: self.pos +=1
        elif c == curses.KEY_UP: self.pos -= 1
        elif c == 9: self.pos +=1 # tab
        elif curses.unctrl(c) in ['^W', '^C', '^X', '^Q']: self.tab = -1
        elif curses.unctrl(c) in ['^N']: self.network_dialog()
        elif curses.unctrl(c) == '^S': self.settings_dialog()
        else: return c
        if self.pos<0: self.pos=0
        if self.pos>=self.maxpos: self.pos=self.maxpos - 1

    def run_tab(self, i, print_func, exec_func):
        while self.tab == i:
            self.stdscr.clear()
            print_func()
            self.refresh()
            c = self.main_command()
            if c: exec_func(c)


    def run_history_tab(self, c):
        if c == 10:
            out = self.run_popup('',["blah","foo"])
            

    def edit_str(self, target, c, is_num=False):
        # detect backspace
        if c in [8, 127, 263] and target:
            target = target[:-1]
        elif not is_num or curses.unctrl(c) in '0123456789.':
            target += curses.unctrl(c)
        return target


    def run_send_tab(self, c):
        if self.pos%6 == 0:
            self.str_recipient = self.edit_str(self.str_recipient, c)
        if self.pos%6 == 1:
            self.str_description = self.edit_str(self.str_description, c)
        if self.pos%6 == 2:
            self.str_amount = self.edit_str(self.str_amount, c, True)
        elif self.pos%6 == 3:
            self.str_fee = self.edit_str(self.str_fee, c, True)
        elif self.pos%6==4:
            if c == 10: self.do_send()
        elif self.pos%6==5:
            if c == 10: self.do_clear()

            
    def run_receive_tab(self, c):
        if c == 10:
            out = self.run_popup('Address', ["Edit label", "Freeze", "Prioritize"])
            
    def run_contacts_tab(self, c):
        if c == 10 and self.wallet.addressbook:
            out = self.run_popup('Adress', ["Copy", "Pay to", "Edit label", "Delete"]).get('button')
            address = self.wallet.addressbook[self.pos%len(self.wallet.addressbook)]
            if out == "Pay to":
                self.tab = 1
                self.str_recipient = address 
                self.pos = 2
            elif out == "Edit label":
                s = self.get_string(6 + self.pos, 18)
                if s:
                    self.wallet.labels[address] = s
            
    def run_banner_tab(self, c):
        self.show_message(repr(c))
        pass

    def main(self,url):

        tty.setraw(sys.stdin)
        while self.tab != -1:
            self.run_tab(0, self.print_history, self.run_history_tab)
            self.run_tab(1, self.print_send_tab, self.run_send_tab)
            self.run_tab(2, self.print_receive, self.run_receive_tab)
            self.run_tab(3, self.print_contacts, self.run_contacts_tab)
            self.run_tab(4, self.print_banner, self.run_banner_tab)

        tty.setcbreak(sys.stdin)
        curses.nocbreak()
        self.stdscr.keypad(0)
        curses.echo()
        curses.endwin()


    def do_clear(self):
        self.str_amount = ''
        self.str_recipient = ''
        self.str_fee = ''
        self.str_description = ''

    def do_send(self):
        if not is_valid(self.str_recipient):
            self.show_message(_('Invalid ViorCoin address'))
            return
        try:
            amount = int( Decimal( self.str_amount) * 100000000 )
        except Exception:
            self.show_message(_('Invalid Amount'))
            return
        try:
            fee = int( Decimal( self.str_fee) * 100000000 )
        except Exception:
            self.show_message(_('Invalid Fee'))
            return

        if self.wallet.use_encryption:
            password = self.password_dialog()
            if not password:
                return
        else:
            password = None

        try:
            tx = self.wallet.mktx( [(self.str_recipient, amount)], password, fee)
        except Exception as e:
            self.show_message(str(e))
            return
            
        if self.str_description: 
            self.wallet.labels[tx.hash()] = self.str_description

        h = self.wallet.send_tx(tx)
        self.show_message(_("Please wait..."), getchar=False)
        self.wallet.tx_event.wait()
        status, msg = self.wallet.receive_tx( h, tx )

        if status:
            self.show_message(_('Payment sent.'))
            self.do_clear()
            #self.update_contacts_tab()
        else:
            self.show_message(_('Error'))


    def show_message(self, message, getchar = True):
        w = self.w
        w.clear()
        w.border(0)
        for i, line in enumerate(message.split('\n')):
            w.addstr(2+i,2,line)
        w.refresh()
        if getchar: c = self.stdscr.getch()


    def run_popup(self, title, items):
        return self.run_dialog(title, map(lambda x: {'type':'button','label':x}, items), interval=1, y_pos = self.pos+3)


    def network_dialog(self):
        if not self.network: return
        auto_connect = self.network.config.get('auto_cycle')
        host, port, protocol = self.network.default_server.split(':')
        srv = 'auto-connect' if auto_connect else self.network.default_server

        out = self.run_dialog('Network', [
            {'label':'server', 'type':'str', 'value':srv},
            {'label':'proxy', 'type':'str', 'value':self.config.get('proxy', '')},
            ], buttons = 1)
        if out:
            if out.get('server'):
                server = out.get('server')
                auto_connect = server == 'auto-connect'
                if not auto_connect:
                    try:
                        host, port, protocol = server.split(':')
                    except Exception:
                        self.show_message("Error:" + server + "\nIn doubt, type \"auto-connect\"")
                        return False

                if out.get('proxy'):
                    proxy = self.parse_proxy_options(out.get('proxy'))
                else:
                    proxy = None

                self.network.set_parameters(host, port, protocol, proxy, auto_connect)
                


    def settings_dialog(self):
        out = self.run_dialog('Settings', [
            {'label':'Default GUI', 'type':'list', 'choices':['classic','lite','gtk','text'], 'value':self.config.get('gui')},
            {'label':'Default fee', 'type':'satoshis', 'value': format_satoshis(self.wallet.fee).strip() }
            ], buttons = 1)
        if out:
            if out.get('Default GUI'):
                self.config.set_key('gui', out['Default GUI'], True)
            if out.get('Default fee'):
                fee = int ( Decimal( out['Default fee']) *10000000 )
                self.config.set_key('fee_per_kb', fee, True)


    def password_dialog(self):
        out = self.run_dialog('Password', [
            {'label':'Password', 'type':'password', 'value':''}
            ], buttons = 1)
        return out.get('Password')
        

    def run_dialog(self, title, items, interval=2, buttons=None, y_pos=3):
        self.popup_pos = 0
        
        self.w = curses.newwin( 5 + len(items)*interval + (2 if buttons else 0), 50, y_pos, 5)
        w = self.w
        out = {}
        while True:
            w.clear()
            w.border(0)
            w.addstr( 0, 2, title)

            num = len(items)

            numpos = num
            if buttons: numpos += 2

            for i in range(num):
                item = items[i]
                label = item.get('label')
                if item.get('type') == 'list':
                    value = item.get('value','')
                elif item.get('type') == 'satoshis':
                    value = item.get('value','')
                elif item.get('type') == 'str':
                    value = item.get('value','')
                elif item.get('type') == 'password':
                    value = '*'*len(item.get('value',''))
                else:
                    value = ''

                if len(value)<20: value += ' '*(20-len(value))

                if item.has_key('value'):
                    w.addstr( 2+interval*i, 2, label)
                    w.addstr( 2+interval*i, 15, value, curses.A_REVERSE if self.popup_pos%numpos==i else curses.color_pair(1) )
                else:
                    w.addstr( 2+interval*i, 2, label, curses.A_REVERSE if self.popup_pos%numpos==i else 0)

            if buttons:
                w.addstr( 5+interval*i, 10, "[  ok  ]",     curses.A_REVERSE if self.popup_pos%numpos==(numpos-2) else curses.color_pair(2))
                w.addstr( 5+interval*i, 25, "[cancel]", curses.A_REVERSE if self.popup_pos%numpos==(numpos-1) else curses.color_pair(2))
                
            w.refresh()

            c = self.stdscr.getch()
            if c in [ord('q'), 27]: break
            elif c in [curses.KEY_LEFT, curses.KEY_UP]: self.popup_pos -= 1
            elif c in [curses.KEY_RIGHT, curses.KEY_DOWN]: self.popup_pos +=1
            else:
                i = self.popup_pos%numpos
                if buttons and c==10:
                    if i == numpos-2:
                        return out
                    elif i == numpos -1:
                        return {}

                item = items[i]
                _type = item.get('type')

                if _type == 'str':
                    item['value'] = self.edit_str(item['value'], c)
                    out[item.get('label')] = item.get('value')

                elif _type == 'password':
                    item['value'] = self.edit_str(item['value'], c)
                    out[item.get('label')] = item ['value']

                elif _type == 'satoshis':
                    item['value'] = self.edit_str(item['value'], c, True)
                    out[item.get('label')] = item.get('value')

                elif _type == 'list':
                    choices = item.get('choices')
                    try:
                        j = choices.index(item.get('value'))
                    except Exception:
                        j = 0
                    new_choice = choices[(j + 1)% len(choices)]
                    item['value'] = new_choice
                    out[item.get('label')] = item.get('value')
                    
                elif _type == 'button':
                    out['button'] = item.get('label')
                    break

        return out
Example #11
0
class ElectrumGui:

    def __init__(self, config, network):
        self.network = network
        self.config = config
        storage = WalletStorage(config)
        if not storage.file_exists:
            print "Wallet not found. try 'electrum-vior create'"
            exit()

	self.done = 0
        self.last_balance = ""

        set_verbosity(False)

        self.str_recipient = ""
        self.str_description = ""
        self.str_amount = ""
        self.str_fee = ""

        self.wallet = Wallet(storage)
        self.wallet.start_threads(network)
        
        self.wallet.network.register_callback('updated', self.updated)
        self.wallet.network.register_callback('connected', self.connected)
        self.wallet.network.register_callback('disconnected', self.disconnected)
        self.wallet.network.register_callback('disconnecting', self.disconnecting)
        self.wallet.network.register_callback('peers', self.peers)
        self.wallet.network.register_callback('banner', self.print_banner)
        self.commands = [_("[h] - displays this help text"), \
                         _("[i] - display transaction history"), \
                         _("[o] - enter payment order"), \
                         _("[p] - print stored payment order"), \
                         _("[s] - send stored payment order"), \
                         _("[r] - show own receipt addresses"), \
                         _("[c] - display contacts"), \
                         _("[b] - print server banner"), \
                         _("[q] - quit") ]
        self.num_commands = len(self.commands)

    def main_command(self):
        self.print_balance()
        c = raw_input("enter command: ")
        if   c == "h" : self.print_commands()
        elif c == "i" : self.print_history()
        elif c == "o" : self.enter_order()
        elif c == "p" : self.print_order()
        elif c == "s" : self.send_order()
        elif c == "r" : self.print_addresses()
        elif c == "c" : self.print_contacts()
        elif c == "b" : self.print_banner()
        elif c == "n" : self.network_dialog()
        elif c == "e" : self.settings_dialog()
        elif c == "q" : self.done = 1
        else: self.print_commands()

    def peers(self):
        print("got peers list:")
        l = filter_protocol(self.wallet.network.get_servers(), 's')
        for s in l:
            print (s)

    def connected(self):
        print ("connected")

    def disconnected(self):
        print ("disconnected")

    def disconnecting(self):
        print ("disconnecting")

    def updated(self):
        s = self.get_balance()
        if s != self.last_balance:
            print(s)
        self.last_balance = s
        return True

    def print_commands(self):
        self.print_list(self.commands, "Available commands")

    def print_history(self):
        width = [20, 40, 14, 14]
        delta = (80 - sum(width) - 4)/3
        format_str = "%"+"%d"%width[0]+"s"+"%"+"%d"%(width[1]+delta)+"s"+"%" \
        + "%d"%(width[2]+delta)+"s"+"%"+"%d"%(width[3]+delta)+"s"
        b = 0 
        messages = []

        for item in self.wallet.get_tx_history():
            tx_hash, confirmations, is_mine, value, fee, balance, timestamp = item
            if confirmations:
                try:
                    time_str = datetime.datetime.fromtimestamp( timestamp).isoformat(' ')[:-3]
                except Exception:
                    time_str = "unknown"
            else:
                time_str = 'pending'

            label, is_default_label = self.wallet.get_label(tx_hash)
            messages.append( format_str%( time_str, label, format_satoshis(value, whitespaces=True), format_satoshis(balance, whitespaces=True) ) )

        self.print_list(messages[::-1], format_str%( _("Date"), _("Description"), _("Amount"), _("Balance")))


    def print_balance(self):
        print(self.get_balance())

    def get_balance(self):
        if self.wallet.network.interface and self.wallet.network.interface.is_connected:
            if not self.wallet.up_to_date:
                msg = _( "Synchronizing..." )
            else: 
                c, u =  self.wallet.get_balance()
                msg = _("Balance")+": %f  "%(Decimal( c ) / 100000000)
                if u: msg += "  [%f unconfirmed]"%(Decimal( u ) / 100000000)
        else:
                msg = _( "Not connected" )
            
        return(msg)


    def print_contacts(self):
        messages = map(lambda addr: "%30s    %30s       "%(addr, self.wallet.labels.get(addr,"")), self.wallet.addressbook)
        self.print_list(messages, "%19s  %25s "%("Address", "Label"))

    def print_addresses(self):
        messages = map(lambda addr: "%30s    %30s       "%(addr, self.wallet.labels.get(addr,"")), self.wallet.addresses())
        self.print_list(messages, "%19s  %25s "%("Address", "Label"))

    def print_order(self):
        print("send order to " + self.str_recipient + ", amount: " + self.str_amount \
              + "\nfee: " + self.str_fee + ", desc: " + self.str_description)

    def enter_order(self):
        self.str_recipient = raw_input("Pay to: ")
        self.str_description = raw_input("Description : ")
        self.str_amount = raw_input("Amount: ")
        self.str_fee = raw_input("Fee: ")

    def send_order(self):
        self.do_send()

    def print_banner(self):
        for i, x in enumerate( self.wallet.network.banner.split('\n') ):
            print( x )

    def print_list(self, list, firstline):
        self.maxpos = len(list)
        if not self.maxpos: return
        print(firstline)
        for i in range(self.maxpos):
            msg = list[i] if i < len(list) else ""
            print(msg)

           
    def main(self,url):
        while self.done == 0: self.main_command()

    def do_send(self):
        if not is_valid(self.str_recipient):
            print(_('Invalid ViorCoin address'))
            return
        try:
            amount = int( Decimal( self.str_amount) * 100000000 )
        except Exception:
            print(_('Invalid Amount'))
            return
        try:
            fee = int( Decimal( self.str_fee) * 100000000 )
        except Exception:
            print(_('Invalid Fee'))
            return

        if self.wallet.use_encryption:
            password = self.password_dialog()
            if not password:
                return
        else:
            password = None

        c = ""
        while c != "y":
            c = raw_input("ok to send (y/n)?")
            if c == "n": return

        try:
            tx = self.wallet.mktx( [(self.str_recipient, amount)], password, fee)
        except Exception as e:
            print(str(e))
            return
            
        if self.str_description: 
            self.wallet.labels[tx.hash()] = self.str_description

        h = self.wallet.send_tx(tx)
        print(_("Please wait..."))
        self.wallet.tx_event.wait()
        status, msg = self.wallet.receive_tx( h, tx )

        if status:
            print(_('Payment sent.'))
            #self.do_clear()
            #self.update_contacts_tab()
        else:
            print(_('Error'))

    def network_dialog(self):
        print("use 'electrum-vior setconfig server/proxy' to change your network settings")
        return True


    def settings_dialog(self):
        print("use 'electrum-vior setconfig' to change your settings")
        return True

    def password_dialog(self):
        return getpass.getpass()
        

#   XXX unused

    def run_receive_tab(self, c):
        #if c == 10:
        #    out = self.run_popup('Address', ["Edit label", "Freeze", "Prioritize"])
        return
            
    def run_contacts_tab(self, c):
        pass
Example #12
0
        params = sys.argv[2:] + [my_password]
        ret = send_command(cmd, params)
        sys.exit(ret)

    conn = sqlite3.connect(database);
    # create table if needed
    check_create_table(conn)

    # init network
    config = SimpleConfig({'wallet_path':wallet_path})
    network = Network(config)
    network.start(wait=True)

    # create watching_only wallet
    storage = WalletStorage(config)
    wallet = Wallet(storage)
    if not storage.file_exists:
        wallet.seed = ''
        wallet.create_watching_only_wallet(master_public_key,master_chain)

    wallet.synchronize = lambda: None # prevent address creation by the wallet
    wallet.start_threads(network)
    network.register_callback('updated', on_wallet_update)
    
    out_queue = Queue.Queue()
    thread.start_new_thread(server_thread, (conn,))

    while not stopping:
        cur = conn.cursor()

        # read pending requests from table
    def run(self, action):

        if action == 'new':
            action, t = self.restore_or_create()

        if action is None: 
            return
            
        if action == 'create':
            if t == 'standard':
                wallet = Wallet(self.storage)

            elif t == '2fa':
                wallet = Wallet_2of3(self.storage)
                run_hook('create_cold_seed', wallet, self)
                self.create_cold_seed(wallet)
                return

            elif t == '2of2':
                wallet = Wallet_2of2(self.storage)
                action = 'create_2of2_1'

            elif t == '2of3':
                wallet = Wallet_2of3(self.storage)
                action = 'create_2of3_1'


        if action == 'create_2fa_2':
            wallet = Wallet_2of3(self.storage)

        if action in ['create', 'create_2of2_1', 'create_2fa_2', 'create_2of3_1']:
            seed = wallet.make_seed()
            sid = None if action == 'create' else 'hot'
            if not self.show_seed(seed, sid):
                return
            if not self.verify_seed(seed, sid):
                return
            password = self.password_dialog()
            wallet.add_seed(seed, password)
            if action == 'create':
                wallet.create_accounts(password)
                self.waiting_dialog(wallet.synchronize)
            elif action == 'create_2of2_1':
                action = 'create_2of2_2'
            elif action == 'create_2of3_1':
                action = 'create_2of3_2'
            elif action == 'create_2fa_2':
                action = 'create_2fa_3'

        if action == 'create_2of2_2':
            xpub_hot = wallet.master_public_keys.get("m/")
            xpub = self.cold_mpk_dialog(xpub_hot)
            wallet.add_master_public_key("cold/", xpub)
            wallet.create_account()
            self.waiting_dialog(wallet.synchronize)


        if action == 'create_2of3_2':
            xpub_hot = wallet.master_public_keys.get("m/")
            xpub1, xpub2 = self.cold_mpk2_dialog(xpub_hot)
            wallet.add_master_public_key("cold/", xpub1)
            wallet.add_master_public_key("remote/", xpub2)
            wallet.create_account()
            self.waiting_dialog(wallet.synchronize)


        if action == 'create_2fa_3':
            run_hook('create_remote_key', wallet, self)
            if not wallet.master_public_keys.get("remote/"):
                return
            wallet.create_account()
            self.waiting_dialog(wallet.synchronize)


        if action == 'restore':

            if t == 'standard':
                text = self.enter_seed_dialog(MSG_ENTER_ANYTHING, None)
                if not text:
                    return
                if Wallet.is_seed(text):
                    password = self.password_dialog()
                    wallet = Wallet.from_seed(text, self.storage)
                    wallet.add_seed(text, password)
                    wallet.create_accounts(password)
                elif Wallet.is_mpk(text):
                    wallet = Wallet.from_mpk(text, self.storage)
                elif Wallet.is_address(text):
                    wallet = Wallet.from_address(text, self.storage)
                elif Wallet.is_private_key(text):
                    wallet = Wallet.from_private_key(text, self.storage)
                else:
                    raise

            elif t in ['2fa', '2of2','2of3']:
                r = self.double_seed_dialog()
                if not r: 
                    return
                text1, text2 = r
                password = self.password_dialog()
                if t == '2of2':
                    wallet = Wallet_2of2(self.storage)
                elif t == '2of3':
                    wallet = Wallet_2of3(self.storage)
                elif t == '2fa':
                    wallet = Wallet_2of3(self.storage)

                if Wallet.is_seed(text1):
                    wallet.add_seed(text1, password)
                    if Wallet.is_seed(text2):
                        wallet.add_cold_seed(text2, password)
                    else:
                        wallet.add_master_public_key("cold/", text2)

                elif Wallet.is_mpk(text1):
                    if Wallet.is_seed(text2):
                        wallet.add_seed(text2, password)
                        wallet.add_master_public_key("cold/", text1)
                    else:
                        wallet.add_master_public_key("m/", text1)
                        wallet.add_master_public_key("cold/", text2)

                if t == '2of3':
                    run_hook('restore_third_key', wallet, self)

                wallet.create_account()

            else:
                raise


                
        #if not self.config.get('server'):
        if self.network:
            if self.network.interfaces:
                self.network_dialog()
            else:
                QMessageBox.information(None, _('Warning'), _('You are offline'), _('OK'))
                self.network.stop()
                self.network = None

        # start wallet threads
        wallet.start_threads(self.network)

        if action == 'restore':

            self.waiting_dialog(lambda: wallet.restore(self.waiting_label.setText))

            if self.network:
                if wallet.is_found():
                    QMessageBox.information(None, _('Information'), _("Recovery successful"), _('OK'))
                else:
                    QMessageBox.information(None, _('Information'), _("No transactions found for this seed"), _('OK'))
            else:
                QMessageBox.information(None, _('Information'), _("This wallet was restored offline. It may contain more addresses than displayed."), _('OK'))

        return wallet
 def is_mpk(self, seed_e):
     text = self.get_seed_text(seed_e)
     return Wallet.is_mpk(text)
 def is_any(self, seed_e):
     text = self.get_seed_text(seed_e)
     return Wallet.is_seed(text) or Wallet.is_mpk(text) or Wallet.is_address(text) or Wallet.is_private_key(text)
Example #16
0
    def __init__(self, config, _network):
        global wallet, network
        network = _network
        network.register_callback('updated', update_callback)
        network.register_callback('connected', update_callback)
        network.register_callback('disconnected', update_callback)
        network.register_callback('disconnecting', update_callback)
        
        storage = WalletStorage(config)
        if not storage.file_exists:
            action = self.restore_or_create()
            if not action: exit()

            wallet = Wallet(storage)
            if action == 'create':
                wallet.init_seed(None)
                self.show_seed()
                wallet.save_seed(None)
                wallet.synchronize()  # generate first addresses offline
                
            elif action == 'restore':
                seed = self.seed_dialog()
                if not seed:
                    exit()
                wallet.init_seed(str(seed))
                wallet.save_seed(None)
            else:
                exit()

            wallet.start_threads(network)

            if action == 'restore':
                if not self.restore_wallet():
                    exit()

            self.password_dialog()

        else:
            wallet = Wallet(storage)
            wallet.start_threads(network)
Example #17
0
class ElectrumGui():

    def __init__(self, config, network):
        self.network = network
        self.config = config


    def main(self, url=None):

        storage = WalletStorage(self.config)
        if not storage.file_exists:
            action = self.restore_or_create()
            if not action:
                exit()
            self.wallet = wallet = Wallet(storage)
            gap = self.config.get('gap_limit', 5)
            if gap != 5:
                wallet.gap_limit = gap
                wallet.storage.put('gap_limit', gap, True)

            if action == 'create':
                seed = wallet.make_seed()
                show_seed_dialog(seed, None)
                r = change_password_dialog(False, None)
                password = r[2] if r else None
                wallet.add_seed(seed, password)
                wallet.create_accounts(password)
                wallet.synchronize()  # generate first addresses offline

            elif action == 'restore':
                seed = self.seed_dialog()
                if not seed:
                    exit()
                r = change_password_dialog(False, None)
                password = r[2] if r else None
                wallet.add_seed(seed, password)
                wallet.create_accounts(password)
                
            else:
                exit()
        else:
            self.wallet = Wallet(storage)
            action = None

        self.wallet.start_threads(self.network)

        if action == 'restore':
            self.restore_wallet(wallet)

        w = ElectrumWindow(self.wallet, self.config, self.network)
        if url: w.set_url(url)
        Gtk.main()

    def restore_or_create(self):
        return restore_create_dialog()

    def seed_dialog(self):
        return run_recovery_dialog()

    def network_dialog(self):
        return run_network_dialog( self.network, parent=None )


    def restore_wallet(self, wallet):

        dialog = Gtk.MessageDialog(
            parent = None,
            flags = Gtk.DialogFlags.MODAL, 
            buttons = Gtk.ButtonsType.CANCEL, 
            message_format = "Please wait..."  )
        dialog.show()

        def recover_thread( wallet, dialog ):
            wallet.restore(lambda x:x)
            GObject.idle_add( dialog.destroy )

        thread.start_new_thread( recover_thread, ( wallet, dialog ) )
        r = dialog.run()
        dialog.destroy()
        if r==Gtk.ResponseType.CANCEL: return False
        if not wallet.is_found():
            show_message("No transactions found for this seed")

        return True
Example #18
0
class ElectrumGui:
    def __init__(self, config, network):

        self.config = config
        self.network = network
        storage = WalletStorage(config)
        if not storage.file_exists:
            print "Wallet not found. try 'electrum-vior create'"
            exit()

        self.wallet = Wallet(storage)
        self.wallet.start_threads(self.network)

        locale.setlocale(locale.LC_ALL, '')
        self.encoding = locale.getpreferredencoding()

        self.stdscr = curses.initscr()
        curses.noecho()
        curses.cbreak()
        curses.start_color()
        curses.use_default_colors()
        curses.init_pair(1, curses.COLOR_WHITE, curses.COLOR_BLUE)
        curses.init_pair(2, curses.COLOR_WHITE, curses.COLOR_CYAN)
        self.stdscr.keypad(1)
        self.stdscr.border(0)
        self.maxy, self.maxx = self.stdscr.getmaxyx()
        self.set_cursor(0)
        self.w = curses.newwin(10, 50, 5, 5)

        set_verbosity(False)
        self.tab = 0
        self.pos = 0
        self.popup_pos = 0

        self.str_recipient = ""
        self.str_description = ""
        self.str_amount = ""
        self.str_fee = ""
        self.history = None

        if self.network:
            self.network.register_callback('updated', self.update)
            self.network.register_callback('connected', self.refresh)
            self.network.register_callback('disconnected', self.refresh)
            self.network.register_callback('disconnecting', self.refresh)

        self.tab_names = [
            _("History"),
            _("Send"),
            _("Receive"),
            _("Contacts"),
            _("Wall")
        ]
        self.num_tabs = len(self.tab_names)

    def set_cursor(self, x):
        try:
            curses.curs_set(x)
        except Exception:
            pass

    def restore_or_create(self):
        pass

    def verify_seed(self):
        pass

    def get_string(self, y, x):
        self.set_cursor(1)
        curses.echo()
        self.stdscr.addstr(y, x, " " * 20, curses.A_REVERSE)
        s = self.stdscr.getstr(y, x)
        curses.noecho()
        self.set_cursor(0)
        return s

    def update(self):
        self.update_history()
        if self.tab == 0:
            self.print_history()
        self.refresh()

    def print_history(self):

        width = [20, 40, 14, 14]
        delta = (self.maxx - sum(width) - 4) / 3
        format_str = "%" + "%d" % width[0] + "s" + "%" + "%d" % (
            width[1] + delta) + "s" + "%" + "%d" % (
                width[2] + delta) + "s" + "%" + "%d" % (width[3] + delta) + "s"

        if self.history is None:
            self.update_history()

        self.print_list(
            self.history[::-1], format_str %
            (_("Date"), _("Description"), _("Amount"), _("Balance")))

    def update_history(self):
        width = [20, 40, 14, 14]
        delta = (self.maxx - sum(width) - 4) / 3
        format_str = "%" + "%d" % width[0] + "s" + "%" + "%d" % (
            width[1] + delta) + "s" + "%" + "%d" % (
                width[2] + delta) + "s" + "%" + "%d" % (width[3] + delta) + "s"

        b = 0
        self.history = []

        for item in self.wallet.get_tx_history():
            tx_hash, conf, is_mine, value, fee, balance, timestamp = item
            if conf:
                try:
                    time_str = datetime.datetime.fromtimestamp(
                        timestamp).isoformat(' ')[:-3]
                except Exception:
                    time_str = "------"
            else:
                time_str = 'pending'

            label, is_default_label = self.wallet.get_label(tx_hash)
            self.history.append(
                format_str %
                (time_str, label, format_satoshis(value, whitespaces=True),
                 format_satoshis(balance, whitespaces=True)))

    def print_balance(self):
        if not self.network:
            msg = _("Offline")
        elif self.network.interface and self.network.interface.is_connected:
            if not self.wallet.up_to_date:
                msg = _("Synchronizing...")
            else:
                c, u = self.wallet.get_balance()
                msg = _("Balance") + ": %f  " % (Decimal(c) / 100000000)
                if u: msg += "  [%f unconfirmed]" % (Decimal(u) / 100000000)
        else:
            msg = _("Not connected")

        self.stdscr.addstr(self.maxy - 1, 3, msg)

        for i in range(self.num_tabs):
            self.stdscr.addstr(0,
                               2 + 2 * i + len(''.join(self.tab_names[0:i])),
                               ' ' + self.tab_names[i] + ' ',
                               curses.A_BOLD if self.tab == i else 0)

        self.stdscr.addstr(self.maxy - 1, self.maxx - 30,
                           ' '.join([_("Settings"),
                                     _("Network"),
                                     _("Quit")]))

    def print_contacts(self):
        messages = map(
            lambda addr: "%30s    %30s       " %
            (addr, self.wallet.labels.get(addr, "")), self.wallet.addressbook)
        self.print_list(messages, "%19s  %25s " % ("Address", "Label"))

    def print_receive(self):
        fmt = "%-35s  %-30s"
        messages = map(
            lambda addr: fmt % (addr, self.wallet.labels.get(addr, "")),
            self.wallet.addresses())
        self.print_list(messages, fmt % ("Address", "Label"))

    def print_edit_line(self, y, label, text, index, size):
        text += " " * (size - len(text))
        self.stdscr.addstr(y, 2, label)
        self.stdscr.addstr(
            y, 15, text, curses.A_REVERSE if self.pos %
            6 == index else curses.color_pair(1))

    def print_send_tab(self):
        self.stdscr.clear()
        self.print_edit_line(3, _("Pay to"), self.str_recipient, 0, 40)
        self.print_edit_line(5, _("Description"), self.str_description, 1, 40)
        self.print_edit_line(7, _("Amount"), self.str_amount, 2, 15)
        self.print_edit_line(9, _("Fee"), self.str_fee, 3, 15)
        self.stdscr.addstr(
            12, 15, _("[Send]"),
            curses.A_REVERSE if self.pos % 6 == 4 else curses.color_pair(2))
        self.stdscr.addstr(
            12, 25, _("[Clear]"),
            curses.A_REVERSE if self.pos % 6 == 5 else curses.color_pair(2))

    def print_banner(self):
        if self.network:
            self.print_list(self.network.banner.split('\n'))

    def print_list(self, list, firstline=None):
        self.maxpos = len(list)
        if not self.maxpos: return
        if firstline:
            firstline += " " * (self.maxx - 2 - len(firstline))
            self.stdscr.addstr(1, 1, firstline)
        for i in range(self.maxy - 4):
            msg = list[i] if i < len(list) else ""
            msg += " " * (self.maxx - 2 - len(msg))
            m = msg[0:self.maxx - 2]
            m = m.encode(self.encoding)
            self.stdscr.addstr(
                i + 2, 1, m,
                curses.A_REVERSE if i == (self.pos % self.maxpos) else 0)

    def refresh(self):
        if self.tab == -1: return
        self.stdscr.border(0)
        self.print_balance()
        self.stdscr.refresh()

    def main_command(self):
        c = self.stdscr.getch()
        print c
        if c == curses.KEY_RIGHT: self.tab = (self.tab + 1) % self.num_tabs
        elif c == curses.KEY_LEFT: self.tab = (self.tab - 1) % self.num_tabs
        elif c == curses.KEY_DOWN: self.pos += 1
        elif c == curses.KEY_UP: self.pos -= 1
        elif c == 9: self.pos += 1  # tab
        elif curses.unctrl(c) in ['^W', '^C', '^X', '^Q']: self.tab = -1
        elif curses.unctrl(c) in ['^N']: self.network_dialog()
        elif curses.unctrl(c) == '^S': self.settings_dialog()
        else: return c
        if self.pos < 0: self.pos = 0
        if self.pos >= self.maxpos: self.pos = self.maxpos - 1

    def run_tab(self, i, print_func, exec_func):
        while self.tab == i:
            self.stdscr.clear()
            print_func()
            self.refresh()
            c = self.main_command()
            if c: exec_func(c)

    def run_history_tab(self, c):
        if c == 10:
            out = self.run_popup('', ["blah", "foo"])

    def edit_str(self, target, c, is_num=False):
        # detect backspace
        if c in [8, 127, 263] and target:
            target = target[:-1]
        elif not is_num or curses.unctrl(c) in '0123456789.':
            target += curses.unctrl(c)
        return target

    def run_send_tab(self, c):
        if self.pos % 6 == 0:
            self.str_recipient = self.edit_str(self.str_recipient, c)
        if self.pos % 6 == 1:
            self.str_description = self.edit_str(self.str_description, c)
        if self.pos % 6 == 2:
            self.str_amount = self.edit_str(self.str_amount, c, True)
        elif self.pos % 6 == 3:
            self.str_fee = self.edit_str(self.str_fee, c, True)
        elif self.pos % 6 == 4:
            if c == 10: self.do_send()
        elif self.pos % 6 == 5:
            if c == 10: self.do_clear()

    def run_receive_tab(self, c):
        if c == 10:
            out = self.run_popup('Address',
                                 ["Edit label", "Freeze", "Prioritize"])

    def run_contacts_tab(self, c):
        if c == 10 and self.wallet.addressbook:
            out = self.run_popup(
                'Adress',
                ["Copy", "Pay to", "Edit label", "Delete"]).get('button')
            address = self.wallet.addressbook[self.pos %
                                              len(self.wallet.addressbook)]
            if out == "Pay to":
                self.tab = 1
                self.str_recipient = address
                self.pos = 2
            elif out == "Edit label":
                s = self.get_string(6 + self.pos, 18)
                if s:
                    self.wallet.labels[address] = s

    def run_banner_tab(self, c):
        self.show_message(repr(c))
        pass

    def main(self, url):

        tty.setraw(sys.stdin)
        while self.tab != -1:
            self.run_tab(0, self.print_history, self.run_history_tab)
            self.run_tab(1, self.print_send_tab, self.run_send_tab)
            self.run_tab(2, self.print_receive, self.run_receive_tab)
            self.run_tab(3, self.print_contacts, self.run_contacts_tab)
            self.run_tab(4, self.print_banner, self.run_banner_tab)

        tty.setcbreak(sys.stdin)
        curses.nocbreak()
        self.stdscr.keypad(0)
        curses.echo()
        curses.endwin()

    def do_clear(self):
        self.str_amount = ''
        self.str_recipient = ''
        self.str_fee = ''
        self.str_description = ''

    def do_send(self):
        if not is_valid(self.str_recipient):
            self.show_message(_('Invalid ViorCoin address'))
            return
        try:
            amount = int(Decimal(self.str_amount) * 100000000)
        except Exception:
            self.show_message(_('Invalid Amount'))
            return
        try:
            fee = int(Decimal(self.str_fee) * 100000000)
        except Exception:
            self.show_message(_('Invalid Fee'))
            return

        if self.wallet.use_encryption:
            password = self.password_dialog()
            if not password:
                return
        else:
            password = None

        try:
            tx = self.wallet.mktx([(self.str_recipient, amount)], password,
                                  fee)
        except Exception as e:
            self.show_message(str(e))
            return

        if self.str_description:
            self.wallet.labels[tx.hash()] = self.str_description

        h = self.wallet.send_tx(tx)
        self.show_message(_("Please wait..."), getchar=False)
        self.wallet.tx_event.wait()
        status, msg = self.wallet.receive_tx(h, tx)

        if status:
            self.show_message(_('Payment sent.'))
            self.do_clear()
            #self.update_contacts_tab()
        else:
            self.show_message(_('Error'))

    def show_message(self, message, getchar=True):
        w = self.w
        w.clear()
        w.border(0)
        for i, line in enumerate(message.split('\n')):
            w.addstr(2 + i, 2, line)
        w.refresh()
        if getchar: c = self.stdscr.getch()

    def run_popup(self, title, items):
        return self.run_dialog(title,
                               map(lambda x: {
                                   'type': 'button',
                                   'label': x
                               }, items),
                               interval=1,
                               y_pos=self.pos + 3)

    def network_dialog(self):
        if not self.network: return
        auto_connect = self.network.config.get('auto_cycle')
        host, port, protocol = self.network.default_server.split(':')
        srv = 'auto-connect' if auto_connect else self.network.default_server

        out = self.run_dialog('Network', [
            {
                'label': 'server',
                'type': 'str',
                'value': srv
            },
            {
                'label': 'proxy',
                'type': 'str',
                'value': self.config.get('proxy', '')
            },
        ],
                              buttons=1)
        if out:
            if out.get('server'):
                server = out.get('server')
                auto_connect = server == 'auto-connect'
                if not auto_connect:
                    try:
                        host, port, protocol = server.split(':')
                    except Exception:
                        self.show_message("Error:" + server +
                                          "\nIn doubt, type \"auto-connect\"")
                        return False

                if out.get('proxy'):
                    proxy = self.parse_proxy_options(out.get('proxy'))
                else:
                    proxy = None

                self.network.set_parameters(host, port, protocol, proxy,
                                            auto_connect)

    def settings_dialog(self):
        out = self.run_dialog(
            'Settings', [{
                'label': 'Default GUI',
                'type': 'list',
                'choices': ['classic', 'lite', 'gtk', 'text'],
                'value': self.config.get('gui')
            }, {
                'label': 'Default fee',
                'type': 'satoshis',
                'value': format_satoshis(self.wallet.fee).strip()
            }],
            buttons=1)
        if out:
            if out.get('Default GUI'):
                self.config.set_key('gui', out['Default GUI'], True)
            if out.get('Default fee'):
                fee = int(Decimal(out['Default fee']) * 10000000)
                self.config.set_key('fee_per_kb', fee, True)

    def password_dialog(self):
        out = self.run_dialog('Password', [{
            'label': 'Password',
            'type': 'password',
            'value': ''
        }],
                              buttons=1)
        return out.get('Password')

    def run_dialog(self, title, items, interval=2, buttons=None, y_pos=3):
        self.popup_pos = 0

        self.w = curses.newwin(
            5 + len(items) * interval + (2 if buttons else 0), 50, y_pos, 5)
        w = self.w
        out = {}
        while True:
            w.clear()
            w.border(0)
            w.addstr(0, 2, title)

            num = len(items)

            numpos = num
            if buttons: numpos += 2

            for i in range(num):
                item = items[i]
                label = item.get('label')
                if item.get('type') == 'list':
                    value = item.get('value', '')
                elif item.get('type') == 'satoshis':
                    value = item.get('value', '')
                elif item.get('type') == 'str':
                    value = item.get('value', '')
                elif item.get('type') == 'password':
                    value = '*' * len(item.get('value', ''))
                else:
                    value = ''

                if len(value) < 20: value += ' ' * (20 - len(value))

                if item.has_key('value'):
                    w.addstr(2 + interval * i, 2, label)
                    w.addstr(
                        2 + interval * i, 15, value,
                        curses.A_REVERSE if self.popup_pos %
                        numpos == i else curses.color_pair(1))
                else:
                    w.addstr(
                        2 + interval * i, 2, label,
                        curses.A_REVERSE if self.popup_pos %
                        numpos == i else 0)

            if buttons:
                w.addstr(
                    5 + interval * i, 10, "[  ok  ]",
                    curses.A_REVERSE if self.popup_pos %
                    numpos == (numpos - 2) else curses.color_pair(2))
                w.addstr(
                    5 + interval * i, 25, "[cancel]",
                    curses.A_REVERSE if self.popup_pos %
                    numpos == (numpos - 1) else curses.color_pair(2))

            w.refresh()

            c = self.stdscr.getch()
            if c in [ord('q'), 27]: break
            elif c in [curses.KEY_LEFT, curses.KEY_UP]: self.popup_pos -= 1
            elif c in [curses.KEY_RIGHT, curses.KEY_DOWN]: self.popup_pos += 1
            else:
                i = self.popup_pos % numpos
                if buttons and c == 10:
                    if i == numpos - 2:
                        return out
                    elif i == numpos - 1:
                        return {}

                item = items[i]
                _type = item.get('type')

                if _type == 'str':
                    item['value'] = self.edit_str(item['value'], c)
                    out[item.get('label')] = item.get('value')

                elif _type == 'password':
                    item['value'] = self.edit_str(item['value'], c)
                    out[item.get('label')] = item['value']

                elif _type == 'satoshis':
                    item['value'] = self.edit_str(item['value'], c, True)
                    out[item.get('label')] = item.get('value')

                elif _type == 'list':
                    choices = item.get('choices')
                    try:
                        j = choices.index(item.get('value'))
                    except Exception:
                        j = 0
                    new_choice = choices[(j + 1) % len(choices)]
                    item['value'] = new_choice
                    out[item.get('label')] = item.get('value')

                elif _type == 'button':
                    out['button'] = item.get('label')
                    break

        return out