Пример #1
0
 def invoke(firstarg='0.0.0.0',
            sport='8787',
            upnp_str=None,
            addr_str=None):
     bindhost, *extrahosts = firstarg.split(',')
     if len(extrahosts) > 1:
         raise Exception("too many hosts")
     elif len(extrahosts) == 1:
         [
             announcehost,
         ] = extrahosts
     else:
         announcehost = None
     port = int(sport)
     pnp = get_upnp() if upnp_str == 'upnp' else None
     if not pnp and not addr_str:
         # third arg may be addr_str, so swap the args
         addr_str = upnp_str
         upnp_str = None
     addr = None
     if addr_str:
         assert Address.is_valid(
             addr_str), "Invalid donation address specified"
         addr = Address.from_string(addr_str)
     return self.start_fusion_server(network,
                                     bindhost,
                                     port,
                                     upnp=pnp,
                                     announcehost=announcehost,
                                     donation_address=addr)
Пример #2
0
    def doVerify(self) -> None:
        addrtf = self.tf
        address_str = str(addrtf.text).strip()
        message = str(self.topTvDel.text)
        signature = str(self.botTvDel.text).strip()

        if not signature:
            parent().show_message(
                _("Please provide both a signature and a message to verify"))
            return

        try:
            address = Address.from_string(address_str)
        except:
            parent().show_error(_('Invalid Ergon address.'))
            return
        message = message.encode('utf-8')
        try:
            # This can raise on invalid base64
            sig = base64.b64decode(signature)
            verified = bitcoin.verify_message(
                address, sig, message)  # this raises too on failure
        except:
            verified = False

        if verified:
            parent().show_message(_("Signature verified"), title=_("Success"))
        else:
            parent().show_error(_("Wrong signature"))
Пример #3
0
    def on_edited(self, item, column, prior_value):
        contact = item.data(0, self.DataRoles.Contact)
        if column == 2:  # Label
            label_key = contact.address
            try:
                label_key = Address.from_string(label_key).to_storage_string()
            except:
                pass
            self.wallet.set_label(label_key, item.text(2))
            self.update(
            )  # force refresh in case 2 contacts use the same address
            return
        # else.. Name
        typ = contact.type
        was_cur, was_sel = bool(self.currentItem()), item.isSelected()
        name, value = item.text(1), item.text(3)
        del item  # paranoia

        # On success, parent.set_contact returns the new key (address text)
        # if 'cashacct'.. or always the same key for all other types.
        key = self.parent.set_contact(name, value, typ=typ, replace=contact)

        if key:
            # Due to deferred updates, on_update will actually be called later.
            # So, we have to save the edited item's "current" and "selected"
            # status here. 'on_update' will look at this tuple and clear it
            # after updating.
            self._edited_item_cur_sel = (key, was_cur, was_sel)
Пример #4
0
    def doConversion_(self, text) -> bool:
        self.cash.text = ""
        self.legacy.text = ""
        self.cpyCashBut.enabled = False
        self.cpyLegBut.enabled = False
        self.qrButShowCash.enabled = False
        self.qrButShowLegacy.enabled = False
        text = text.strip()

        addy = None

        try:
            addy = Address.from_string(text)
        except:
            pass

        if addy:
            self.cash.text = addy.to_full_string(Address.FMT_CASHADDR)
            self.legacy.text = addy.to_full_string(Address.FMT_LEGACY)
            self.cpyCashBut.enabled = True
            self.cpyLegBut.enabled = True
            self.qrButShowCash.enabled = True
            self.qrButShowLegacy.enabled = True

            return True
        return False
Пример #5
0
 def make_unsigned_transaction(self, amount, fee, all_inputs, outputs,
                               changes):
     ''' make unsigned transaction '''
     dust = self.dust_threshold(
     )  # always 546 for now, but this call is here in case something more sophisticated happens in the future
     coins = {}
     tx_inputs = []
     amounts = {}
     try:
         for player in all_inputs:
             inputs_coins = self.get_coins(all_inputs[player])
             # if there are no coins on input it terminates the process
             if inputs_coins:
                 coins[player] = inputs_coins
             else:
                 return None
     except BaseException as e:
         self.print_error('make_unsigned_transaction:', repr(e))
         return None
     for player, pubkey_utxos in coins.items():
         amounts[player] = 0
         for pubkey, utxos in pubkey_utxos.items():
             for utxo in utxos:
                 utxo['type'] = 'p2pkh'
                 utxo['address'] = Address.from_pubkey(pubkey)
                 utxo['pubkeys'] = [pubkey]
                 utxo['x_pubkeys'] = [pubkey]
                 utxo['prevout_hash'] = utxo['tx_hash']
                 utxo['prevout_n'] = utxo['tx_pos']
                 utxo['signatures'] = [None]
                 utxo['num_sig'] = 1
                 tx_inputs.append(utxo)
                 amounts[player] += utxo['value']
     tx_inputs.sort(key=lambda x: x['prevout_hash'] + str(x["tx_pos"]))
     tx_outputs = [(TYPE_ADDRESS, Address.from_string(output), int(amount))
                   for output in outputs]
     transaction = Transaction.from_io(tx_inputs,
                                       tx_outputs,
                                       sign_schnorr=False)
     tx_changes = [
         (TYPE_ADDRESS, Address.from_string(changes[player]),
          int(amounts[player] - amount - fee)) for player in sorted(changes)
         if Address.is_valid(changes[player]) and int(amounts[player] -
                                                      amount - fee) >= dust
     ]
     transaction.add_outputs(tx_changes)
     return transaction
Пример #6
0
 def view_addr_link_activated(addr):
     if isinstance(parent, ElectrumWindow):
         try:
             address = Address.from_string(addr)
             parent.show_address(address,
                                 parent=parent.top_level_window())
         except Exception as e:
             parent.print_error(repr(e))
Пример #7
0
 def donation_address(self, window) -> Optional[Tuple[str, Address]]:
     ''' Plugin API: Returns a tuple of (description, Address) or None. This
     is the donation address that we as a client got from the remote server
     (as opposed to the donation address we announce if we are a server). '''
     if self.remote_donation_address and Address.is_valid(
             self.remote_donation_address):
         return (self.fullname() + " " + _("Server") + ": " +
                 self.get_server()[0],
                 Address.from_string(self.remote_donation_address))
Пример #8
0
 def delete_history(self, address: Address) -> None:
     if isinstance(address, str) and Address.is_valid(address):
         address = Address.from_string(address)
     storage = self.parent.wallet.storage if self.parent.wallet else None
     if storage:
         if True:  #with self.lock:
             addrstr = address.to_storage_string()
             k = 'contact_history_%s' % (addrstr)
             storage.put(k, None)
             self.print_error("Deleted %s" % addrstr)
Пример #9
0
def decodeAddress(addr: str) -> Address:
    ret = None
    if addr:
        try:
            # re-encode addr in case they went to/from cashaddr
            ret = Address.from_string(addr)
        except BaseException as e:
            utils.NSLog("Caught exception decoding address %s: %s", addr,
                        str(e))
    return ret
Пример #10
0
 def getaddressunspent(self, address):
     """Returns the UTXO list of any address. Note: This
     is a walletless server query, results are not checked by SPV.
     """
     if not isinstance(address, Address):
         try:
             address = Address.from_string(address)
         except AddressError:
             return None
     sh = address.to_scripthash_hex()
     return self.network.synchronous_get(
         ('blockchain.scripthash.listunspent', [sh]))
Пример #11
0
 def get_history(self, address: Address) -> list:
     ret = list()
     if isinstance(address, str) and Address.is_valid(address):
         address = Address.from_string(address)
     storage = self.parent.wallet.storage if self.parent.wallet else None
     if storage:
         addrstr = address.to_storage_string()
         k = 'contact_history_%s' % (addrstr)
         hdict = storage.get(k)
         if hdict:
             ret = list(hdict.values())
             ret.sort(key=lambda x: x[1], reverse=True)
     return ret
Пример #12
0
 def _open_internal_link(self, target):
     ''' accepts either a str txid, str address, or a QUrl which should be
     of the bare form "txid" and/or "address" -- used by the clickable
     links in the inputs/outputs QTextBrowsers'''
     if isinstance(target, QUrl):
         target = target.toString(QUrl.None_)
     assert target
     if Address.is_valid(target):
         # target was an address, open address dialog
         self.main_window.show_address(Address.from_string(target), parent=self)
     else:
         # target was a txid, open new tx dialog
         self.main_window.do_process_from_txid(txid=target, parent=self)
Пример #13
0
 def doReloadForKey(self, key: Any) -> Any:
     t0 = time.time()
     hist = list()
     unk = False
     duped = ''
     if isinstance(key, (type(None), list)):
         # the common case, 'None' or [Address]
         hist = get_history(domain=key)
     # contacts entires
     elif isinstance(key, contacts.ContactsEntry):
         hist = get_contact_history(key.address)
     elif isinstance(key, Address):
         # support for list-less single Address.. call self again with the proper format
         hist = self.get([key])
         duped = ' (duped) '
     elif isinstance(key, str):
         # support for string addresses or tx_hashes.. detect which and act accordingly
         if Address.is_valid(key):
             hist = self.get(
                 [Address.from_string(key)]
             )  # recursively call self with propery list data type, which will end up calling get_history (it's ok -- this is to cache results uniformly!)
             duped = ' (duped) '
         elif gui.ElectrumGui.gui.wallet and gui.ElectrumGui.gui.wallet.transactions.get(
                 key, None):
             fullHist = self.get(
                 None
             )  # recursively call self to get a full history (will be cached so it's ok!)
             try:
                 hentry = fullHist.get_by_txid(key)
                 hist.append(hentry)
             except KeyError:
                 pass
         else:
             unk = True
     else:
         unk = True
     dstr = str(key) if not isinstance(
         key, contacts.ContactsEntry
     ) else '[ContactsEntry: ' + key.address_str + ']'
     if unk:
         utils.NSLog(
             "HistoryMgr: failed to retrieve any data for unknown domain=%s, returning empty list",
             dstr[:80])
     else:
         time_taken = time.time() - t0
         utils.NSLog(
             "HistoryMgr: refresh %d entries for domain=%s in %f ms%s (hist result type=%s)",
             len(hist), dstr[:80], time_taken * 1e3, duped,
             ''.join(list(str(type(hist)))[-19:-2]))
         gui.ElectrumGui.gui.refresh_cost('history', time_taken)
     return hist
Пример #14
0
 def load_shuffle_change_shared_with_others(wallet):
     ''' Modifies wallet instance and adds _shuffle_change_shared_with_others
     retrieving it from storage. _shuffle_patched_ need not be set. '''
     wallet._shuffle_change_shared_with_others = set()
     tmpadrs = wallet.storage.get(
         ConfKeys.PerWallet.CHANGE_SHARED_WITH_OTHERS, [])
     if isinstance(tmpadrs, (list, tuple, set)):
         for a in tmpadrs:
             try:
                 a = Address.from_string(a)
                 if not wallet.get_address_history(
                         a
                 ):  # no need to re-add to set if it has a history since it won't be shared anyway with the network if it's been used. This set is used only to not cross over shuffled out addresses with change addresses for unused addrs when shuffling
                     wallet._shuffle_change_shared_with_others.add(a)
             except (AddressError, TypeError):
                 pass
Пример #15
0
    def _make_wallet_cashacct_pseudo_contacts(self,
                                              exclude_contacts=[]
                                              ) -> List[Contact]:
        ''' Returns a list of 'fake' contacts that come from the wallet's
        own registered Cash Accounts.  These contacts do not exist in the
        wallet.contacts object but are created on-the-fly from the
        wallet.cashacct list of registered & verified Cash Accounts.

        The creation of this list is relatively cheap and scales as the lookups
        are O(logN) in the cashaccts caches.

        This is a convenience so that the Contacts tab shows "my" cash accounts
        after registration as well as external Cash Accounts. Note that the
        "mine" entries won't be shown if the user explicitly added his own as
        "external"... '''
        try:
            excl_chk = set((c.name, Address.from_string(c.address))
                           for c in exclude_contacts if c.type == 'cashacct')
        except:
            # Hmm.. invalid address?
            excl_chk = set()
        wallet_cashaccts = []
        v_txids = set()
        # Add the [Mine] pseudo-contacts
        for ca_info in self.wallet.cashacct.get_wallet_cashaccounts():
            v_txids.add(ca_info.txid)
            name = self.wallet.cashacct.fmt_info(ca_info, emoji=False)
            if (name, ca_info.address) in excl_chk:
                continue
            wallet_cashaccts.append(
                Contact(name=name,
                        address=ca_info.address.to_ui_string(),
                        type='cashacct_W'))
        # Add the [Pend] pseudo-contacts
        for txid, tup in self._ca_pending_conf.copy().items():
            if txid in v_txids or self.wallet.cashacct.is_verified(txid):
                self._ca_pending_conf.pop(txid, None)
                continue
            if tup in excl_chk:
                continue
            name, address = tup
            wallet_cashaccts.append(
                Contact(name=name,
                        address=address.to_ui_string(),
                        type='cashacct_T'))
        return wallet_cashaccts
Пример #16
0
 def doReloadForKey(self, key: Any) -> Any:
     if key is None:
         a = AddressData(gui.ElectrumGui.gui)
         a.refresh()
         utils.NSLog("AddressMgr refresh (full)")
         return a
     elif key and isinstance(key, (str, Address)):
         if isinstance(key, str):
             key = Address.from_string(key)
         a = self.get(
             None
         )  # recursive call to self to get cached 'all' or rebuild 'all' if not cached
         if a:
             entries = a.master[0][0]
             for entry in entries:
                 if entry.address == key:
                     return entry
     return None
Пример #17
0
    def doSign(self) -> None:
        addrtf = self.tf
        address = str(addrtf.text).strip()
        message = str(self.topTvDel.text)
        signatureTvDel = self.botTvDel
        try:
            print("address = ", address)
            addr = Address.from_string(address)
        except:
            parent().show_error(_('Invalid Ergon address.'))
            return
        if addr.kind != addr.ADDR_P2PKH:
            msg_sign = _("Signing with an address actually means signing with the corresponding "
                        "private key, and verifying with the corresponding public key. The "
                        "address you have entered does not have a unique public key, so these "
                        "operations cannot be performed.") + '\n\n' + \
                       _('The operation is undefined. Not just in Oregano, but in general.')
            parent().show_message(
                _('Cannot sign messages with this type of address.') + '\n\n' +
                msg_sign)
            return
        if not parent().wallet:
            return
        if parent().wallet.is_watching_only():
            parent().show_message(_('This is a watching-only wallet.'))
            return
        if not parent().wallet.is_mine(addr):
            parent().show_message(_('Address not in wallet.'))
            return

        def onPw(password: str) -> None:
            try:
                signed = parent().wallet.sign_message(addr, message, password)
            except:
                parent().show_error(str(sys.exc_info()[1]))
                return
            signatureTvDel.text = base64.b64encode(signed).decode('ascii')
            parent().show_message(_(
                "The signature for the provided message has been pasted into the signature text box."
            ),
                                  title=_("Success"))

        parent().prompt_password_if_needed_asynch(onPw, vc=self)
Пример #18
0
    def on_update(self):
        self.chkVisible()

        # update the receive address if necessary
        current_address_string = self.parent.receive_address_e.text().strip()
        current_address = Address.from_string(current_address_string) if len(
            current_address_string) else None
        domain = self.wallet.get_receiving_addresses()
        addr = self.wallet.get_unused_address()
        if current_address not in domain and addr:
            self.parent.set_receive_address(addr)

        # clear the list and fill it again
        item = self.currentItem()
        prev_sel = item.data(0, Qt.UserRole) if item else None
        self.clear()
        for req in self.wallet.get_sorted_requests(self.config):
            address = req['address']
            if address not in domain:
                continue
            timestamp = req.get('time', 0)
            amount = req.get('amount')
            expiration = req.get('exp', None)
            message = req.get('memo', '')
            date = format_time(timestamp)
            status = req.get('status')
            signature = req.get('sig')
            requestor = req.get('name', '')
            amount_str = self.parent.format_amount(amount) if amount else ""
            item = QTreeWidgetItem([
                date,
                address.to_ui_string(), '', message, amount_str,
                _(pr_tooltips.get(status, ''))
            ])
            item.setData(0, Qt.UserRole, address)
            if signature is not None:
                item.setIcon(2, QIcon(":icons/seal.svg"))
                item.setToolTip(2, 'signed by ' + requestor)
            if status is not PR_UNKNOWN:
                item.setIcon(6, QIcon(pr_icons.get(status)))
            self.addTopLevelItem(item)
            if prev_sel == address:
                self.setCurrentItem(item)
Пример #19
0
    def getUnusedAddress(self) -> None:
        wallet = parent().wallet
        if not wallet: return
        # hide receive tab if no receive requests available
        b = len(wallet.receive_requests) > 0
        #self.setVisible(b)
        #self.parent.receive_requests_label.setVisible(b)
        #if not b:
        #    self.parent.expires_label.hide()
        #    self.parent.expires_combo.show()

        domain = wallet.get_addresses()
        if self.addrStr:
            # update the receive address if necessary
            current_address = Address.from_string(self.addrStr)
            addr = wallet.get_unused_address()
            if not current_address in domain and addr:
                self.setReceiveAddress_(addr.to_ui_string())
                current_address = addr.to_ui_string()
Пример #20
0
 def open_link(link):
     if Address.is_valid(link):
         addr = Address.from_string(link)
         if wallet.is_mine(addr):
             parent.show_address(addr)
         else:
             addr_URL = web.BE_URL(parent.config, 'addr', addr)
             if addr_URL:
                 webopen(addr_URL)
         return
     if link.startswith('http'):
         webopen(link)
     elif len(link) == 64:  # 64 character txid
         tx = wallet.transactions.get(link)
         if tx:
             parent.show_transaction(tx, tx_desc=wallet.get_label(link))
         else:
             parent.do_process_from_txid(txid=link,
                                         tx_desc=wallet.get_label(link))
         return
Пример #21
0
 def get_full_contacts(self, include_pseudo: bool = True) -> List[Contact]:
     ''' Returns all the contacts, with the "My CashAcct" pseudo-contacts
     clobbering dupes of the same type that were manually added.
     Client code should scan for type == 'cashacct' and type == 'cashacct_W' '''
     if include_pseudo:
         # filter out cachaccts that are "Wallet", as they will be added
         # at the end as pseudo contacts if they also appear in real contacts
         real_contacts = [
             contact
             for contact in self.parent.contacts.get_all(nocopy=True)
             if contact.type !=
             'cashacct'  # accept anything that's not cashacct
             or not Address.is_valid(
                 contact.address
             )  # or if it is, it can have invalid address as it's clearly 'not mine"
             or not self.wallet.is_mine(  # or if it's not mine
                 Address.from_string(contact.address))
         ]
         return real_contacts + self._make_wallet_cashacct_pseudo_contacts()
     else:
         return self.parent.contacts.get_all(nocopy=True)
Пример #22
0
 def viewWillDisappear_(self, animated: bool) -> None:
     send_super(__class__,
                self,
                'viewWillDisappear:',
                animated,
                argtypes=[c_bool])
     parent().cash_addr_sig.disconnect(self)
     data = utils.nspy_get_byname(self, 'data')
     if not data: data = DialogData(None, None)
     text = self.tf.text.strip()
     if self.mode == SignVerify:
         try:
             address = Address.from_string(text)
             data = utils.set_namedtuple_field(data, 'address', address)
         except:
             pass
     elif self.mode == EncryptDecrypt:
         data = utils.set_namedtuple_field(data, 'pubkey', text)
     utils.nspy_put_byname(self, data, 'data')
     if self.kbas:
         utils.unregister_keyboard_autoscroll(self.kbas)
         self.kbas = None
Пример #23
0
    def create_menu(self, position):
        menu = QMenu()
        selected = self.selectedItems()
        i2c = self._i2c
        ca_unverified = self._get_ca_unverified(include_temp=False)
        if selected:
            names = [item.text(1) for item in selected]
            keys = [i2c(item) for item in selected]
            payable_keys = [k for k in keys if k.type != 'cashacct_T']
            deletable_keys = [k for k in keys if k.type in contact_types]
            needs_verif_keys = [k for k in keys if k in ca_unverified]
            column = self.currentColumn()
            column_title = self.headerItem().text(column)
            column_data = '\n'.join([item.text(column) for item in selected])
            item = self.currentItem()
            typ = i2c(item).type if item else 'unknown'
            ca_info = None
            if item and typ in ('cashacct', 'cashacct_W'):
                ca_info = self.wallet.cashacct.get_verified(i2c(item).name)
                if column == 1 and len(selected) == 1:
                    # hack .. for Cash Accounts just say "Copy Cash Account"
                    column_title = _('Cash Account')
                    if ca_info:
                        column_data = self.wallet.cashacct.fmt_info(ca_info,
                                                                    emoji=True)
            if len(selected) > 1:
                column_title += f" ({len(selected)})"
            menu.addAction(
                _("Copy {}").format(column_title),
                lambda: self.parent.app.clipboard().setText(column_data))
            if item and column in self.editable_columns and self.on_permit_edit(
                    item, column):
                key = item.data(0, self.DataRoles.Contact)
                # this key & find_item business is so we don't hold a reference
                # to the ephemeral item, which may be deleted while the
                # context menu is up.  Accessing the item after on_update runs
                # means the item is deleted and you get a C++ object deleted
                # runtime error.
                menu.addAction(
                    _("Edit {}").format(column_title),
                    lambda: self._on_edit_item(key, column))
            a = menu.addAction(
                _("Pay to"), lambda: self.parent.payto_contacts(payable_keys))
            if needs_verif_keys or not payable_keys:
                a.setDisabled(True)
            a = menu.addAction(
                _("Delete"),
                lambda: self.parent.delete_contacts(deletable_keys))
            if not deletable_keys:
                a.setDisabled(True)
            # Add sign/verify and encrypt/decrypt menu - but only if just 1 thing selected
            if len(keys) == 1 and Address.is_valid(keys[0].address):
                signAddr = Address.from_string(keys[0].address)
                a = menu.addAction(
                    _("Sign/verify message") + "...",
                    lambda: self.parent.sign_verify_message(signAddr))
                if signAddr.kind != Address.ADDR_P2PKH:
                    a.setDisabled(
                        True
                    )  # We only allow this for P2PKH since it makes no sense for P2SH (ambiguous public key)
            URLs = [
                web.BE_URL(self.config, 'addr',
                           Address.from_string(key.address)) for key in keys
                if Address.is_valid(key.address)
            ]
            a = menu.addAction(_("View on block explorer"),
                               lambda: [URL and webopen(URL) for URL in URLs])
            if not any(URLs):
                a.setDisabled(True)
            if ca_info:
                menu.addAction(
                    _("View registration tx..."),
                    lambda: self.parent.do_process_from_txid(
                        txid=ca_info.txid,
                        tx_desc=self.wallet.get_label(ca_info.txid)))
                if typ in ('cashacct_W', 'cashacct'):
                    _contact_d = i2c(item)
                    menu.addAction(
                        _("Details..."),
                        lambda: cashacctqt.cash_account_detail_dialog(
                            self.parent, _contact_d.name))
            menu.addSeparator()

        menu.addAction(self.icon_cashacct,
                       _("Add Contact") + " - " + _("Cash Account"),
                       self.new_cash_account_contact_dialog)
        menu.addAction(self.icon_contacts,
                       _("Add Contact") + " - " + _("Address"),
                       self.parent.new_contact_dialog)
        menu.addSeparator()
        menu.addAction(self.icon_cashacct, _("Register Cash Account..."),
                       self.parent.register_new_cash_account)
        menu.addSeparator()
        menu.addAction(
            QIcon(":icons/import.svg" if not ColorScheme.dark_scheme else
                  ":icons/import_dark_theme.svg"), _("Import file"),
            self.import_contacts)
        if not self.parent.contacts.empty:
            menu.addAction(
                QIcon(":icons/save.svg" if not ColorScheme.dark_scheme else
                      ":icons/save_dark_theme.svg"), _("Export file"),
                self.export_contacts)

        menu.addSeparator()
        a = menu.addAction(_("Show My Cash Accounts"),
                           self.toggle_show_my_cashaccts)
        a.setCheckable(True)
        a.setChecked(self.show_my_cashaccts)

        if ca_unverified:

            def kick_off_verify():
                bnums = set()
                for contact in ca_unverified:
                    tup = self.wallet.cashacct.parse_string(contact.name)
                    if not tup:
                        continue
                    bnums.add(tup[1])  # number
                ret = cashacctqt.verify_multiple_blocks(
                    bnums, self.parent, self.wallet)
                if ret is None:
                    # user cancel
                    return
                verified = ca_unverified - self._get_ca_unverified()
                if not verified:
                    self.parent.show_error(
                        _("Cash Account verification failure"))

            menu.addSeparator()
            num = len(ca_unverified)
            a = menu.addAction(
                self.icon_unverif,
                ngettext("Verify {count} Cash Account",
                         "Verify {count} Cash Accounts",
                         num).format(count=num), kick_off_verify)
            if not self.wallet.network:
                a.setDisabled(True)

        run_hook('create_contact_menu', menu, selected)
        menu.exec_(self.viewport().mapToGlobal(position))
Пример #24
0
 def parse_address(self, line):
     r = line.strip()
     m = re.match(RE_ALIAS, r)
     address = m.group(2) if m else r
     return Address.from_string(address)
Пример #25
0
    def on_update(self):
        if self.cleaned_up:
            return
        item = self.currentItem()
        current_contact = item.data(0,
                                    self.DataRoles.Contact) if item else None
        selected = self.selectedItems() or []
        selected_contacts = set(
            item.data(0, self.DataRoles.Contact) for item in selected)
        del item, selected  # must not hold a reference to a C++ object that will soon be deleted in self.clear()..
        self.clear()
        type_names = defaultdict(lambda: _("Unknown"))
        type_names.update({
            'openalias': _('OpenAlias'),
            'cashacct': _('Cash Account'),
            'cashacct_W': _('Cash Account') + ' [' + _('Mine') + ']',
            'cashacct_T': _('Cash Account') + ' [' + _('Pend') + ']',
            'address': _('Address'),
        })
        type_icons = {
            'openalias': self.icon_openalias,
            'cashacct': self.icon_cashacct,
            'cashacct_W': self.icon_cashacct,
            'cashacct_T': self.icon_unverif,
            'address': self.icon_contacts,
        }
        selected_items, current_item = [], None
        edited = self._edited_item_cur_sel
        for contact in self.get_full_contacts(
                include_pseudo=self.show_my_cashaccts):
            _type, name, address = contact.type, contact.name, contact.address
            label_key = address
            if _type in ('cashacct', 'cashacct_W', 'cashacct_T', 'address'):
                try:
                    # try and re-parse and re-display the address based on current UI string settings
                    addy = Address.from_string(address)
                    address = addy.to_ui_string()
                    label_key = addy.to_storage_string()
                    del addy
                except:
                    ''' This may happen because we may not have always enforced this as strictly as we could have in legacy code. Just move on.. '''
            label = self.wallet.get_label(label_key)
            item = QTreeWidgetItem(
                ["", name, label, address, type_names[_type]])
            item.setData(0, self.DataRoles.Contact, contact)
            item.DataRole = self.DataRoles.Contact
            if _type in ('cashacct', 'cashacct_W', 'cashacct_T'):
                ca_info = self.wallet.cashacct.get_verified(name)
                tt_warn = None
                if ca_info:
                    if self.wallet.is_mine(
                            ca_info.address) and not self.show_my_cashaccts:
                        # user may have added the contact to "self" manually
                        # but since they asked to not see their own cashaccts,
                        # we must do this to suppress it from being shown regardless
                        continue
                    item.setText(0, ca_info.emoji)
                    tt = _(
                        'Validated Cash Account: <b><pre>{emoji} {account_string}</pre></b>'
                    ).format(
                        emoji=ca_info.emoji,
                        account_string=
                        f'{ca_info.name}#{ca_info.number}.{ca_info.collision_hash};'
                    )
                else:
                    item.setIcon(0, self.icon_unverif)
                    if _type == 'cashacct_T':
                        tt_warn = tt = _(
                            'Cash Account pending confirmation and/or verification'
                        )
                    else:
                        tt_warn = tt = _(
                            'Warning: This Cash Account is not verified')
                item.setToolTip(0, tt)
                if tt_warn: item.setToolTip(1, tt_warn)
            if _type in type_icons:
                item.setIcon(4, type_icons[_type])
            # always give the "Address" field a monospace font even if it's
            # not strictly an address such as openalias...
            item.setFont(3, self.monospace_font)
            self.addTopLevelItem(item)
            if contact == current_contact or (contact == edited[0]
                                              and edited[1]):
                current_item = item  # this key was the current item before and it hasn't gone away
            if contact in selected_contacts or (contact == edited[0]
                                                and edited[2]):
                selected_items.append(
                    item
                )  # this key was selected before and it hasn't gone away

        if selected_items:  # sometimes currentItem is set even if nothing actually selected. grr..
            # restore current item & selections
            if current_item:
                # set the current item. this may also implicitly select it
                self.setCurrentItem(current_item)
            for item in selected_items:
                # restore the previous selection
                item.setSelected(True)
        self._edited_item_cur_sel = (None, ) * 3
        run_hook('update_contacts_tab', self)