diff --git a/LICENSE b/LICENSE index d2afc3c4..06576583 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) Copyright (c) 2012-2016 Jonathan Warren -Copyright (c) 2013-2016 The Bitmessage Developers +Copyright (c) 2013-2018 The Bitmessage Developers Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in diff --git a/setup.py b/setup.py index 12670ed6..ba34f6df 100644 --- a/setup.py +++ b/setup.py @@ -112,7 +112,8 @@ if __name__ == "__main__": zip_safe=False, entry_points={ 'bitmessage.gui.menu': [ - 'address.qrcode = pybitmessage.plugins.menu_qrcode [qrcode]' + 'popMenuYourIdentities.qrcode = ' + 'pybitmessage.plugins.qrcodeui [qrcode]' ], 'bitmessage.notification.message': [ 'notify2 = pybitmessage.plugins.notification_notify2' diff --git a/src/bitmessagecli.py b/src/bitmessagecli.py index 05f4506e..d7f4e5a9 100644 --- a/src/bitmessagecli.py +++ b/src/bitmessagecli.py @@ -375,9 +375,10 @@ def bmSettings(): #Allows the viewing and modification of keys.dat settings. main() def validAddress(address): - address_information = json.loads(api.decodeAddress(address)) + address_information = api.decodeAddress(address) + address_information = eval(address_information) - if 'success' in str(address_information['status']).lower(): + if 'success' in str(address_information.get('status')).lower(): return True else: return False @@ -1345,14 +1346,15 @@ def UI(usrInput): #Main user menu elif usrInput == "addinfo": tmp_address = userInput('\nEnter the Bitmessage Address.') - address_information = json.loads(api.decodeAddress(tmp_address)) + address_information = api.decodeAddress(tmp_address) + address_information = eval(address_information) print '\n------------------------------' - if 'success' in str(address_information['status']).lower(): + if 'success' in str(address_information.get('status')).lower(): print ' Valid Address' - print ' Address Version: %s' % str(address_information['addressVersion']) - print ' Stream Number: %s' % str(address_information['streamNumber']) + print ' Address Version: %s' % str(address_information.get('addressVersion')) + print ' Stream Number: %s' % str(address_information.get('streamNumber')) else: print ' Invalid Address !' diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 001dc053..7bbd7dd9 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -47,7 +47,9 @@ from account import ( GatewayAccount, MailchuckAccount, AccountColor) import dialogs from helper_generic import powQueueSize -from network.stats import pendingDownload, pendingUpload +from inventory import ( + PendingDownloadQueue, PendingUpload, + PendingUploadDeadlineException) from uisignaler import UISignaler import knownnodes import paths @@ -255,18 +257,6 @@ class MyForm(settingsmixin.SMainWindow): 'customContextMenuRequested(const QPoint&)'), self.on_context_menuYourIdentities) - # load all gui.menu plugins with prefix 'address' - self.menu_plugins = {'address': []} - for plugin in get_plugins('gui.menu', 'address'): - try: - handler, title = plugin(self) - except TypeError: - continue - self.menu_plugins['address'].append( - self.ui.addressContextMenuToolbarYourIdentities.addAction( - title, handler - )) - def init_chan_popup_menu(self, connectSignal=True): # Popup menu for the Channels tab self.ui.addressContextMenuToolbar = QtGui.QToolBar() @@ -1739,8 +1729,6 @@ class MyForm(settingsmixin.SMainWindow): sent.item(i, 3).setText(textToDisplay) def updateSentItemStatusByAckdata(self, ackdata, textToDisplay): - if type(ackdata) is str: - ackdata = QtCore.QByteArray(ackdata) for sent in [self.ui.tableWidgetInbox, self.ui.tableWidgetInboxSubscriptions, self.ui.tableWidgetInboxChans]: treeWidget = self.widgetConvert(sent) if self.getCurrentFolder(treeWidget) != "sent": @@ -2244,7 +2232,7 @@ class MyForm(settingsmixin.SMainWindow): treeWidget = self.widgetConvert(sent) if self.getCurrentFolder(treeWidget) != "sent": continue - if treeWidget == self.ui.treeWidgetYourIdentities and self.getCurrentAccount(treeWidget) not in (fromAddress, None, False): + if treeWidget == self.ui.treeWidgetYourIdentities and self.getCurrentAccount(treeWidget) != fromAddress: continue elif treeWidget in [self.ui.treeWidgetSubscriptions, self.ui.treeWidgetChans] and self.getCurrentAccount(treeWidget) != toAddress: continue @@ -2252,7 +2240,7 @@ class MyForm(settingsmixin.SMainWindow): continue self.addMessageListItemSent(sent, toAddress, fromAddress, subject, "msgqueued", ackdata, time.time()) - self.getAccountTextedit(acct).setPlainText(unicode(message, 'utf-8', 'replace')) + self.getAccountTextedit(acct).setPlainText(unicode(message, 'utf-8)', 'replace')) sent.setCurrentCell(0, 0) def displayNewInboxMessage(self, inventoryHash, toAddress, fromAddress, subject, message): @@ -2711,10 +2699,10 @@ class MyForm(settingsmixin.SMainWindow): waitForSync = False # C PoW currently doesn't support interrupting and OpenCL is untested - if getPowType() == "python" and (powQueueSize() > 0 or pendingUpload() > 0): + if getPowType() == "python" and (powQueueSize() > 0 or PendingUpload().len() > 0): reply = QtGui.QMessageBox.question(self, _translate("MainWindow", "Proof of work pending"), _translate("MainWindow", "%n object(s) pending proof of work", None, QtCore.QCoreApplication.CodecForTr, powQueueSize()) + ", " + - _translate("MainWindow", "%n object(s) waiting to be distributed", None, QtCore.QCoreApplication.CodecForTr, pendingUpload()) + "\n\n" + + _translate("MainWindow", "%n object(s) waiting to be distributed", None, QtCore.QCoreApplication.CodecForTr, PendingUpload().len()) + "\n\n" + _translate("MainWindow", "Wait until these tasks finish?"), QtGui.QMessageBox.Yes|QtGui.QMessageBox.No|QtGui.QMessageBox.Cancel, QtGui.QMessageBox.Cancel) if reply == QtGui.QMessageBox.No: @@ -2722,14 +2710,16 @@ class MyForm(settingsmixin.SMainWindow): elif reply == QtGui.QMessageBox.Cancel: return - if pendingDownload() > 0: + if PendingDownloadQueue.totalSize() > 0: reply = QtGui.QMessageBox.question(self, _translate("MainWindow", "Synchronisation pending"), - _translate("MainWindow", "Bitmessage hasn't synchronised with the network, %n object(s) to be downloaded. If you quit now, it may cause delivery delays. Wait until the synchronisation finishes?", None, QtCore.QCoreApplication.CodecForTr, pendingDownload()), + _translate("MainWindow", "Bitmessage hasn't synchronised with the network, %n object(s) to be downloaded. If you quit now, it may cause delivery delays. Wait until the synchronisation finishes?", None, QtCore.QCoreApplication.CodecForTr, PendingDownloadQueue.totalSize()), QtGui.QMessageBox.Yes|QtGui.QMessageBox.No|QtGui.QMessageBox.Cancel, QtGui.QMessageBox.Cancel) if reply == QtGui.QMessageBox.Yes: waitForSync = True elif reply == QtGui.QMessageBox.Cancel: return + else: + PendingDownloadQueue.stop() if shared.statusIconColor == 'red' and not BMConfigParser().safeGetBoolean( 'bitmessagesettings', 'dontconnect'): @@ -2760,7 +2750,7 @@ class MyForm(settingsmixin.SMainWindow): if waitForSync: self.updateStatusBar(_translate( "MainWindow", "Waiting for finishing synchronisation...")) - while pendingDownload() > 0: + while PendingDownloadQueue.totalSize() > 0: time.sleep(0.5) QtCore.QCoreApplication.processEvents( QtCore.QEventLoop.AllEvents, 1000 @@ -2802,18 +2792,19 @@ class MyForm(settingsmixin.SMainWindow): # check if upload (of objects created locally) pending self.updateStatusBar(_translate( "MainWindow", "Waiting for objects to be sent... %1%").arg(50)) - maxPendingUpload = max(1, pendingUpload()) - - while pendingUpload() > 1: - self.updateStatusBar(_translate( - "MainWindow", - "Waiting for objects to be sent... %1%" - ).arg(int(50 + 20 * (pendingUpload()/maxPendingUpload))) - ) - time.sleep(0.5) - QtCore.QCoreApplication.processEvents( - QtCore.QEventLoop.AllEvents, 1000 - ) + try: + while PendingUpload().progress() < 1: + self.updateStatusBar(_translate( + "MainWindow", + "Waiting for objects to be sent... %1%" + ).arg(int(50 + 20 * PendingUpload().progress())) + ) + time.sleep(0.5) + QtCore.QCoreApplication.processEvents( + QtCore.QEventLoop.AllEvents, 1000 + ) + except PendingUploadDeadlineException: + pass QtCore.QCoreApplication.processEvents( QtCore.QEventLoop.AllEvents, 1000 @@ -3433,10 +3424,6 @@ class MyForm(settingsmixin.SMainWindow): self.popMenuSubscriptions.addSeparator() self.popMenuSubscriptions.addAction(self.actionsubscriptionsClipboard) self.popMenuSubscriptions.addSeparator() - # preloaded gui.menu plugins with prefix 'address' - for plugin in self.menu_plugins['address']: - self.popMenuSubscriptions.addAction(plugin) - self.popMenuSubscriptions.addSeparator() self.popMenuSubscriptions.addAction(self.actionMarkAllRead) self.popMenuSubscriptions.exec_( self.ui.treeWidgetSubscriptions.mapToGlobal(point)) @@ -3847,13 +3834,13 @@ class MyForm(settingsmixin.SMainWindow): self.popMenuYourIdentities.addAction(self.actionSpecialAddressBehaviorYourIdentities) self.popMenuYourIdentities.addAction(self.actionEmailGateway) self.popMenuYourIdentities.addSeparator() - if currentItem.type != AccountMixin.ALL: - # preloaded gui.menu plugins with prefix 'address' - for plugin in self.menu_plugins['address']: - self.popMenuYourIdentities.addAction(plugin) - self.popMenuYourIdentities.addSeparator() self.popMenuYourIdentities.addAction(self.actionMarkAllRead) + if get_plugins: + for plugin in get_plugins( + 'gui.menu', 'popMenuYourIdentities'): + plugin(self) + self.popMenuYourIdentities.exec_( self.ui.treeWidgetYourIdentities.mapToGlobal(point)) @@ -3873,10 +3860,6 @@ class MyForm(settingsmixin.SMainWindow): self.popMenu.addAction(self.actionEnable) self.popMenu.addAction(self.actionSetAvatar) self.popMenu.addSeparator() - # preloaded gui.menu plugins with prefix 'address' - for plugin in self.menu_plugins['address']: - self.popMenu.addAction(plugin) - self.popMenu.addSeparator() self.popMenu.addAction(self.actionMarkAllRead) self.popMenu.exec_( self.ui.treeWidgetChans.mapToGlobal(point)) diff --git a/src/bitmessageqt/blacklist.py b/src/bitmessageqt/blacklist.py index 64413ebb..e07f9469 100644 --- a/src/bitmessageqt/blacklist.py +++ b/src/bitmessageqt/blacklist.py @@ -56,10 +56,9 @@ class Blacklist(QtGui.QWidget, RetranslateMixin): def click_pushButtonAddBlacklist(self): self.NewBlacklistDialogInstance = AddAddressDialog(self) if self.NewBlacklistDialogInstance.exec_(): - if self.NewBlacklistDialogInstance.labelAddressCheck.text() == \ - _translate("MainWindow", "Address is valid."): + if self.NewBlacklistDialogInstance.ui.labelAddressCheck.text() == _translate("MainWindow", "Address is valid."): address = addBMIfNotPresent(str( - self.NewBlacklistDialogInstance.lineEditAddress.text())) + self.NewBlacklistDialogInstance.ui.lineEditAddress.text())) # First we must check to see if the address is already in the # address book. The user cannot add it again or else it will # cause problems when updating and deleting the entry. @@ -73,7 +72,7 @@ class Blacklist(QtGui.QWidget, RetranslateMixin): self.tableWidgetBlacklist.setSortingEnabled(False) self.tableWidgetBlacklist.insertRow(0) newItem = QtGui.QTableWidgetItem(unicode( - self.NewBlacklistDialogInstance.lineEditLabel.text().toUtf8(), 'utf-8')) + self.NewBlacklistDialogInstance.ui.newAddressLabel.text().toUtf8(), 'utf-8')) newItem.setIcon(avatarize(address)) self.tableWidgetBlacklist.setItem(0, 0, newItem) newItem = QtGui.QTableWidgetItem(address) @@ -81,7 +80,7 @@ class Blacklist(QtGui.QWidget, RetranslateMixin): QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) self.tableWidgetBlacklist.setItem(0, 1, newItem) self.tableWidgetBlacklist.setSortingEnabled(True) - t = (str(self.NewBlacklistDialogInstance.lineEditLabel.text().toUtf8()), address, True) + t = (str(self.NewBlacklistDialogInstance.ui.newAddressLabel.text().toUtf8()), address, True) if BMConfigParser().get('bitmessagesettings', 'blackwhitelist') == 'black': sql = '''INSERT INTO blacklist VALUES (?,?,?)''' else: diff --git a/src/bitmessageqt/networkstatus.py b/src/bitmessageqt/networkstatus.py index 3691d5b3..06b1e0ce 100644 --- a/src/bitmessageqt/networkstatus.py +++ b/src/bitmessageqt/networkstatus.py @@ -3,7 +3,7 @@ import time import shared from tr import _translate -from inventory import Inventory +from inventory import Inventory, PendingDownloadQueue, PendingUpload import knownnodes import l10n import network.stats diff --git a/src/class_objectHashHolder.py b/src/class_objectHashHolder.py new file mode 100644 index 00000000..2e456d8c --- /dev/null +++ b/src/class_objectHashHolder.py @@ -0,0 +1,54 @@ +# objectHashHolder is a timer-driven thread. One objectHashHolder thread is used +# by each sendDataThread. The sendDataThread uses it whenever it needs to +# advertise an object to peers in an inv message, or advertise a peer to other +# peers in an addr message. Instead of sending them out immediately, it must +# wait a random number of seconds for each connection so that different peers +# get different objects at different times. Thus an attacker who is +# connecting to many network nodes who receives a message first from Alice +# cannot be sure if Alice is the node who originated the message. + +import random +import time +import threading + +class objectHashHolder(threading.Thread): + size = 10 + def __init__(self, sendDataThreadMailbox): + threading.Thread.__init__(self, name="objectHashHolder") + self.shutdown = False + self.sendDataThreadMailbox = sendDataThreadMailbox # This queue is used to submit data back to our associated sendDataThread. + self.collectionOfHashLists = [] + self.collectionOfPeerLists = [] + for i in range(objectHashHolder.size): + self.collectionOfHashLists.append([]) + self.collectionOfPeerLists.append([]) + + def run(self): + iterator = 0 + while not self.shutdown: + if len(self.collectionOfHashLists[iterator]) > 0: + self.sendDataThreadMailbox.put((0, 'sendinv', self.collectionOfHashLists[iterator])) + self.collectionOfHashLists[iterator] = [] + if len(self.collectionOfPeerLists[iterator]) > 0: + self.sendDataThreadMailbox.put((0, 'sendaddr', self.collectionOfPeerLists[iterator])) + self.collectionOfPeerLists[iterator] = [] + iterator += 1 + iterator %= objectHashHolder.size + time.sleep(1) + + def holdHash(self,hash): + self.collectionOfHashLists[random.randrange(0, objectHashHolder.size)].append(hash) + + def hasHash(self, hash): + if hash in (hashlist for hashlist in self.collectionOfHashLists): + return True + return False + + def holdPeer(self,peerDetails): + self.collectionOfPeerLists[random.randrange(0, objectHashHolder.size)].append(peerDetails) + + def hashCount(self): + return sum([len(x) for x in self.collectionOfHashLists if type(x) is list]) + + def close(self): + self.shutdown = True diff --git a/src/class_outgoingSynSender.py b/src/class_outgoingSynSender.py new file mode 100644 index 00000000..9b3eac14 --- /dev/null +++ b/src/class_outgoingSynSender.py @@ -0,0 +1,283 @@ +import errno +import threading +import time +import random +import shared +import select +import socks +import socket +import sys +import tr + +from class_sendDataThread import * +from class_receiveDataThread import * +from bmconfigparser import BMConfigParser +from helper_threading import * +import knownnodes +import queues +import state + +# For each stream to which we connect, several outgoingSynSender threads +# will exist and will collectively create 8 connections with peers. + +class outgoingSynSender(threading.Thread, StoppableThread): + + def __init__(self): + threading.Thread.__init__(self, name="outgoingSynSender") + self.initStop() + random.seed() + + def setup(self, streamNumber, selfInitiatedConnections): + self.streamNumber = streamNumber + self.selfInitiatedConnections = selfInitiatedConnections + + def _getPeer(self): + # If the user has specified a trusted peer then we'll only + # ever connect to that. Otherwise we'll pick a random one from + # the known nodes + if state.trustedPeer: + with knownnodes.knownNodesLock: + peer = state.trustedPeer + knownnodes.knownNodes[self.streamNumber][peer] = time.time() + else: + while not self._stopped: + try: + with knownnodes.knownNodesLock: + peer, = random.sample(knownnodes.knownNodes[self.streamNumber], 1) + priority = (183600 - (time.time() - knownnodes.knownNodes[self.streamNumber][peer])) / 183600 # 2 days and 3 hours + except ValueError: # no known nodes + self.stop.wait(1) + continue + if BMConfigParser().get('bitmessagesettings', 'socksproxytype') != 'none': + if peer.host.find(".onion") == -1: + priority /= 10 # hidden services have 10x priority over plain net + else: + # don't connect to self + if peer.host == BMConfigParser().get('bitmessagesettings', 'onionhostname') and peer.port == BMConfigParser().getint("bitmessagesettings", "onionport"): + continue + elif peer.host.find(".onion") != -1: # onion address and so proxy + continue + if priority <= 0.001: # everyone has at least this much priority + priority = 0.001 + if (random.random() <= priority): + break + self.stop.wait(0.01) # prevent CPU hogging if something is broken + try: + return peer + except NameError: + return state.Peer('127.0.0.1', 8444) + + def stopThread(self): + super(outgoingSynSender, self).stopThread() + try: + self.sock.shutdown(socket.SHUT_RDWR) + except: + pass + + def run(self): + while BMConfigParser().safeGetBoolean('bitmessagesettings', 'dontconnect') and not self._stopped: + self.stop.wait(2) + while BMConfigParser().safeGetBoolean('bitmessagesettings', 'sendoutgoingconnections') and not self._stopped: + self.name = "outgoingSynSender" + maximumConnections = 1 if state.trustedPeer else BMConfigParser().safeGetInt('bitmessagesettings', 'maxoutboundconnections') + while len(self.selfInitiatedConnections[self.streamNumber]) >= maximumConnections and not self._stopped: + self.stop.wait(10) + if state.shutdown: + break + peer = self._getPeer() + while peer in shared.alreadyAttemptedConnectionsList or peer.host in shared.connectedHostsList: + # print 'choosing new sample' + peer = self._getPeer() + self.stop.wait(1) + if self._stopped: + break + # Clear out the shared.alreadyAttemptedConnectionsList every half + # hour so that this program will again attempt a connection + # to any nodes, even ones it has already tried. + with shared.alreadyAttemptedConnectionsListLock: + if (time.time() - shared.alreadyAttemptedConnectionsListResetTime) > 1800: + shared.alreadyAttemptedConnectionsList.clear() + shared.alreadyAttemptedConnectionsListResetTime = int( + time.time()) + shared.alreadyAttemptedConnectionsList[peer] = 0 + if self._stopped: + break + self.name = "outgoingSynSender-" + peer.host.replace(":", ".") # log parser field separator + address_family = socket.AF_INET + # Proxy IP is IPv6. Unlikely but possible + if BMConfigParser().get('bitmessagesettings', 'socksproxytype') != 'none': + if ":" in BMConfigParser().get('bitmessagesettings', 'sockshostname'): + address_family = socket.AF_INET6 + # No proxy, and destination is IPv6 + elif peer.host.find(':') >= 0 : + address_family = socket.AF_INET6 + try: + self.sock = socks.socksocket(address_family, socket.SOCK_STREAM) + except: + """ + The line can fail on Windows systems which aren't + 64-bit compatiable: + File "C:\Python27\lib\socket.py", line 187, in __init__ + _sock = _realsocket(family, type, proto) + error: [Errno 10047] An address incompatible with the requested protocol was used + + So let us remove the offending address from our knownNodes file. + """ + with knownnodes.knownNodesLock: + try: + del knownnodes.knownNodes[self.streamNumber][peer] + except KeyError: + pass + logger.debug('deleting ' + str(peer) + ' from knownnodes.knownNodes because it caused a socks.socksocket exception. We must not be 64-bit compatible.') + continue + # This option apparently avoids the TIME_WAIT state so that we + # can rebind faster + self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + self.sock.settimeout(20) + if BMConfigParser().get('bitmessagesettings', 'socksproxytype') == 'none' and shared.verbose >= 2: + logger.debug('Trying an outgoing connection to ' + str(peer)) + + # sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + elif BMConfigParser().get('bitmessagesettings', 'socksproxytype') == 'SOCKS4a': + if shared.verbose >= 2: + logger.debug ('(Using SOCKS4a) Trying an outgoing connection to ' + str(peer)) + + proxytype = socks.PROXY_TYPE_SOCKS4 + sockshostname = BMConfigParser().get( + 'bitmessagesettings', 'sockshostname') + socksport = BMConfigParser().getint( + 'bitmessagesettings', 'socksport') + rdns = True # Do domain name lookups through the proxy; though this setting doesn't really matter since we won't be doing any domain name lookups anyway. + if BMConfigParser().getboolean('bitmessagesettings', 'socksauthentication'): + socksusername = BMConfigParser().get( + 'bitmessagesettings', 'socksusername') + sockspassword = BMConfigParser().get( + 'bitmessagesettings', 'sockspassword') + self.sock.setproxy( + proxytype, sockshostname, socksport, rdns, socksusername, sockspassword) + else: + self.sock.setproxy( + proxytype, sockshostname, socksport, rdns) + elif BMConfigParser().get('bitmessagesettings', 'socksproxytype') == 'SOCKS5': + if shared.verbose >= 2: + logger.debug ('(Using SOCKS5) Trying an outgoing connection to ' + str(peer)) + + proxytype = socks.PROXY_TYPE_SOCKS5 + sockshostname = BMConfigParser().get( + 'bitmessagesettings', 'sockshostname') + socksport = BMConfigParser().getint( + 'bitmessagesettings', 'socksport') + rdns = True # Do domain name lookups through the proxy; though this setting doesn't really matter since we won't be doing any domain name lookups anyway. + if BMConfigParser().getboolean('bitmessagesettings', 'socksauthentication'): + socksusername = BMConfigParser().get( + 'bitmessagesettings', 'socksusername') + sockspassword = BMConfigParser().get( + 'bitmessagesettings', 'sockspassword') + self.sock.setproxy( + proxytype, sockshostname, socksport, rdns, socksusername, sockspassword) + else: + self.sock.setproxy( + proxytype, sockshostname, socksport, rdns) + + try: + self.sock.connect((peer.host, peer.port)) + if self._stopped: + self.sock.shutdown(socket.SHUT_RDWR) + self.sock.close() + return + sendDataThreadQueue = Queue.Queue() # Used to submit information to the send data thread for this connection. + + sd = sendDataThread(sendDataThreadQueue) + sd.setup(self.sock, peer.host, peer.port, self.streamNumber) + sd.start() + + rd = receiveDataThread() + rd.daemon = True # close the main program even if there are threads left + rd.setup(self.sock, + peer.host, + peer.port, + self.streamNumber, + self.selfInitiatedConnections, + sendDataThreadQueue, + sd.objectHashHolderInstance) + rd.start() + + sd.sendVersionMessage() + + logger.debug(str(self) + ' connected to ' + str(peer) + ' during an outgoing attempt.') + except socks.GeneralProxyError as err: + if err[0][0] in [7, 8, 9]: + logger.error('Error communicating with proxy: %s', str(err)) + queues.UISignalQueue.put(( + 'updateStatusBar', + tr._translate( + "MainWindow", "Problem communicating with proxy: %1. Please check your network settings.").arg(str(err[0][1])) + )) + self.stop.wait(1) + continue + elif shared.verbose >= 2: + logger.debug('Could NOT connect to ' + str(peer) + ' during outgoing attempt. ' + str(err)) + + deletedPeer = None + with knownnodes.knownNodesLock: + """ + It is remotely possible that peer is no longer in knownnodes.knownNodes. + This could happen if two outgoingSynSender threads both try to + connect to the same peer, both fail, and then both try to remove + it from knownnodes.knownNodes. This is unlikely because of the + alreadyAttemptedConnectionsList but because we clear that list once + every half hour, it can happen. + """ + if peer in knownnodes.knownNodes[self.streamNumber]: + timeLastSeen = knownnodes.knownNodes[self.streamNumber][peer] + if (int(time.time()) - timeLastSeen) > 172800 and len(knownnodes.knownNodes[self.streamNumber]) > 1000: # for nodes older than 48 hours old if we have more than 1000 hosts in our list, delete from the knownnodes.knownNodes data-structure. + del knownnodes.knownNodes[self.streamNumber][peer] + deletedPeer = peer + if deletedPeer: + str ('deleting ' + str(peer) + ' from knownnodes.knownNodes because it is more than 48 hours old and we could not connect to it.') + + except socks.Socks5AuthError as err: + queues.UISignalQueue.put(( + 'updateStatusBar', tr._translate( + "MainWindow", "SOCKS5 Authentication problem: %1. Please check your SOCKS5 settings.").arg(str(err)))) + except socks.Socks5Error as err: + if err[0][0] in [3, 4, 5, 6]: + # this is a more bening "error": host unreachable, network unreachable, connection refused, TTL expired + logger.debug('SOCKS5 error: %s', str(err)) + else: + logger.error('SOCKS5 error: %s', str(err)) + if err[0][0] == 4 or err[0][0] == 2: + state.networkProtocolAvailability[protocol.networkType(peer.host)] = False + except socks.Socks4Error as err: + logger.error('Socks4Error: ' + str(err)) + except socket.error as err: + if BMConfigParser().get('bitmessagesettings', 'socksproxytype')[0:5] == 'SOCKS': + logger.error('Bitmessage MIGHT be having trouble connecting to the SOCKS server. ' + str(err)) + else: + if err[0] == errno.ENETUNREACH: + state.networkProtocolAvailability[protocol.networkType(peer.host)] = False + if shared.verbose >= 1: + logger.debug('Could NOT connect to ' + str(peer) + 'during outgoing attempt. ' + str(err)) + + deletedPeer = None + with knownnodes.knownNodesLock: + """ + It is remotely possible that peer is no longer in knownnodes.knownNodes. + This could happen if two outgoingSynSender threads both try to + connect to the same peer, both fail, and then both try to remove + it from knownnodes.knownNodes. This is unlikely because of the + alreadyAttemptedConnectionsList but because we clear that list once + every half hour, it can happen. + """ + if peer in knownnodes.knownNodes[self.streamNumber]: + timeLastSeen = knownnodes.knownNodes[self.streamNumber][peer] + if (int(time.time()) - timeLastSeen) > 172800 and len(knownnodes.knownNodes[self.streamNumber]) > 1000: # for nodes older than 48 hours old if we have more than 1000 hosts in our list, delete from the knownnodes.knownNodes data-structure. + del knownnodes.knownNodes[self.streamNumber][peer] + deletedPeer = peer + if deletedPeer: + logger.debug('deleting ' + str(peer) + ' from knownnodes.knownNodes because it is more than 48 hours old and we could not connect to it.') + + except Exception as err: + import traceback + logger.exception('An exception has occurred in the outgoingSynSender thread that was not caught by other exception types:') + self.stop.wait(0.1) diff --git a/src/class_receiveDataThread.py b/src/class_receiveDataThread.py new file mode 100644 index 00000000..4e86196c --- /dev/null +++ b/src/class_receiveDataThread.py @@ -0,0 +1,879 @@ +doTimingAttackMitigation = False + +import base64 +import datetime +import errno +import math +import time +import threading +import shared +import hashlib +import os +import Queue +import select +import socket +import random +import ssl +from struct import unpack, pack +import sys +import traceback +from binascii import hexlify +#import string +#from subprocess import call # used when the API must execute an outside program +#from pyelliptic.openssl import OpenSSL + +#import highlevelcrypto +from addresses import * +from bmconfigparser import BMConfigParser +from class_objectHashHolder import objectHashHolder +from helper_generic import addDataPadding, isHostInPrivateIPRange +from helper_sql import sqlQuery +import knownnodes +from debug import logger +import paths +import protocol +from inventory import Inventory, PendingDownloadQueue, PendingUpload +import queues +import state +import throttle +import tr +from version import softwareVersion + +# This thread is created either by the synSenderThread(for outgoing +# connections) or the singleListenerThread(for incoming connections). + +class receiveDataThread(threading.Thread): + + def __init__(self): + threading.Thread.__init__(self, name="receiveData") + self.data = '' + self.verackSent = False + self.verackReceived = False + + def setup( + self, + sock, + HOST, + port, + streamNumber, + selfInitiatedConnections, + sendDataThreadQueue, + objectHashHolderInstance): + + self.sock = sock + self.peer = state.Peer(HOST, port) + self.name = "receiveData-" + self.peer.host.replace(":", ".") # ":" log parser field separator + self.streamNumber = state.streamsInWhichIAmParticipating + self.remoteStreams = [] + self.selfInitiatedConnections = selfInitiatedConnections + self.sendDataThreadQueue = sendDataThreadQueue # used to send commands and data to the sendDataThread + self.hostIdent = self.peer.port if ".onion" in BMConfigParser().get('bitmessagesettings', 'onionhostname') and protocol.checkSocksIP(self.peer.host) else self.peer.host + shared.connectedHostsList[ + self.hostIdent] = 0 # The very fact that this receiveData thread exists shows that we are connected to the remote host. Let's add it to this list so that an outgoingSynSender thread doesn't try to connect to it. + self.connectionIsOrWasFullyEstablished = False # set to true after the remote node and I accept each other's version messages. This is needed to allow the user interface to accurately reflect the current number of connections. + self.services = 0 + if streamNumber == -1: # This was an incoming connection. Send out a version message if we accept the other node's version message. + self.initiatedConnection = False + else: + self.initiatedConnection = True + for stream in self.streamNumber: + self.selfInitiatedConnections[stream][self] = 0 + self.objectHashHolderInstance = objectHashHolderInstance + self.downloadQueue = PendingDownloadQueue() + self.startTime = time.time() + + def run(self): + logger.debug('receiveDataThread starting. ID ' + str(id(self)) + '. The size of the shared.connectedHostsList is now ' + str(len(shared.connectedHostsList))) + + while state.shutdown == 0: + dataLen = len(self.data) + try: + isSSL = False + if ((self.services & protocol.NODE_SSL == protocol.NODE_SSL) and + self.connectionIsOrWasFullyEstablished and + protocol.haveSSL(not self.initiatedConnection)): + isSSL = True + dataRecv = self.sslSock.recv(throttle.ReceiveThrottle().chunkSize) + else: + dataRecv = self.sock.recv(throttle.ReceiveThrottle().chunkSize) + self.data += dataRecv + throttle.ReceiveThrottle().wait(len(dataRecv)) + except socket.timeout: + if self.connectionIsOrWasFullyEstablished: + self.sendping("Still around!") + continue + logger.error("Timeout during protocol initialisation") + break + except ssl.SSLError as err: + if err.errno == ssl.SSL_ERROR_WANT_READ: + select.select([self.sslSock], [], [], 10) + logger.debug('sock.recv retriable SSL error') + continue + if err.errno is None and 'timed out' in str(err): + if self.connectionIsOrWasFullyEstablished: + self.sendping("Still around!") + continue + logger.error ('SSL error: %i/%s', err.errno if err.errno else 0, str(err)) + break + except socket.error as err: + if err.errno in (errno.EAGAIN, errno.EWOULDBLOCK) or \ + (sys.platform.startswith('win') and \ + err.errno == errno.WSAEWOULDBLOCK): + select.select([self.sslSock if isSSL else self.sock], [], [], 10) + logger.debug('sock.recv retriable error') + continue + logger.error('sock.recv error. Closing receiveData thread, %s', str(err)) + break + # print 'Received', repr(self.data) + if len(self.data) == dataLen: # If self.sock.recv returned no data: + logger.debug('Connection to ' + str(self.peer) + ' closed. Closing receiveData thread') + break + else: + self.processData() + + try: + for stream in self.streamNumber: + try: + del self.selfInitiatedConnections[stream][self] + except KeyError: + pass + logger.debug('removed self (a receiveDataThread) from selfInitiatedConnections') + except: + pass + self.sendDataThreadQueue.put((0, 'shutdown','no data')) # commands the corresponding sendDataThread to shut itself down. + try: + del shared.connectedHostsList[self.hostIdent] + except Exception as err: + logger.error('Could not delete ' + str(self.hostIdent) + ' from shared.connectedHostsList.' + str(err)) + + queues.UISignalQueue.put(('updateNetworkStatusTab', 'no data')) + self.checkTimeOffsetNotification() + logger.debug('receiveDataThread ending. ID ' + str(id(self)) + '. The size of the shared.connectedHostsList is now ' + str(len(shared.connectedHostsList))) + + def antiIntersectionDelay(self, initial = False): + # estimated time for a small object to propagate across the whole network + delay = math.ceil(math.log(max(len(knownnodes.knownNodes[x]) for x in knownnodes.knownNodes) + 2, 20)) * (0.2 + objectHashHolder.size/2) + # take the stream with maximum amount of nodes + # +2 is to avoid problems with log(0) and log(1) + # 20 is avg connected nodes count + # 0.2 is avg message transmission time + now = time.time() + if initial and now - delay < self.startTime: + logger.debug("Initial sleeping for %.2fs", delay - (now - self.startTime)) + time.sleep(delay - (now - self.startTime)) + elif not initial: + logger.debug("Sleeping due to missing object for %.2fs", delay) + time.sleep(delay) + + def checkTimeOffsetNotification(self): + if shared.timeOffsetWrongCount >= 4 and not self.connectionIsOrWasFullyEstablished: + queues.UISignalQueue.put(('updateStatusBar', tr._translate("MainWindow", "The time on your computer, %1, may be wrong. Please verify your settings.").arg(datetime.datetime.now().strftime("%H:%M:%S")))) + + def processData(self): + if len(self.data) < protocol.Header.size: # if so little of the data has arrived that we can't even read the checksum then wait for more data. + return + + magic,command,payloadLength,checksum = protocol.Header.unpack(self.data[:protocol.Header.size]) + if magic != 0xE9BEB4D9: + self.data = "" + return + if payloadLength > 1600100: # ~1.6 MB which is the maximum possible size of an inv message. + logger.info('The incoming message, which we have not yet download, is too large. Ignoring it. (unfortunately there is no way to tell the other node to stop sending it except to disconnect.) Message size: %s' % payloadLength) + self.data = self.data[payloadLength + protocol.Header.size:] + del magic,command,payloadLength,checksum # we don't need these anymore and better to clean them now before the recursive call rather than after + self.processData() + return + if len(self.data) < payloadLength + protocol.Header.size: # check if the whole message has arrived yet. + return + payload = self.data[protocol.Header.size:payloadLength + protocol.Header.size] + if checksum != hashlib.sha512(payload).digest()[0:4]: # test the checksum in the message. + logger.error('Checksum incorrect. Clearing this message.') + self.data = self.data[payloadLength + protocol.Header.size:] + del magic,command,payloadLength,checksum,payload # better to clean up before the recursive call + self.processData() + return + + # The time we've last seen this node is obviously right now since we + # just received valid data from it. So update the knownNodes list so + # that other peers can be made aware of its existance. + if self.initiatedConnection and self.connectionIsOrWasFullyEstablished: # The remote port is only something we should share with others if it is the remote node's incoming port (rather than some random operating-system-assigned outgoing port). + with knownnodes.knownNodesLock: + for stream in self.streamNumber: + knownnodes.knownNodes[stream][self.peer] = int(time.time()) + + #Strip the nulls + command = command.rstrip('\x00') + logger.debug('remoteCommand ' + repr(command) + ' from ' + str(self.peer)) + + try: + #TODO: Use a dispatcher here + if command == 'error': + self.recerror(payload) + elif not self.connectionIsOrWasFullyEstablished: + if command == 'version': + self.recversion(payload) + elif command == 'verack': + self.recverack() + else: + if command == 'addr': + self.recaddr(payload) + elif command == 'inv': + self.recinv(payload) + elif command == 'getdata': + self.recgetdata(payload) + elif command == 'object': + self.recobject(payload) + elif command == 'ping': + self.sendpong(payload) + elif command == 'pong': + pass + else: + logger.info("Unknown command %s, ignoring", command) + except varintDecodeError as e: + logger.debug("There was a problem with a varint while processing a message from the wire. Some details: %s" % e) + except Exception as e: + logger.critical("Critical error in a receiveDataThread: \n%s" % traceback.format_exc()) + + del payload + self.data = self.data[payloadLength + protocol.Header.size:] # take this message out and then process the next message + + if self.data == '': # if there are no more messages + toRequest = [] + try: + for i in range(len(self.downloadQueue.pending), 100): + while True: + hashId = self.downloadQueue.get(False) + if not hashId in Inventory(): + toRequest.append(hashId) + break + # don't track download for duplicates + self.downloadQueue.task_done(hashId) + except Queue.Empty: + pass + if len(toRequest) > 0: + self.sendgetdata(toRequest) + self.processData() + + def sendpong(self, payload): + logger.debug('Sending pong') + self.sendDataThreadQueue.put((0, 'sendRawData', protocol.CreatePacket('pong', payload))) + + def sendping(self, payload): + logger.debug('Sending ping') + self.sendDataThreadQueue.put((0, 'sendRawData', protocol.CreatePacket('ping', payload))) + + def recverack(self): + logger.debug('verack received') + self.verackReceived = True + if self.verackSent: + # We have thus both sent and received a verack. + self.connectionFullyEstablished() + + def sslHandshake(self): + self.sslSock = self.sock + if ((self.services & protocol.NODE_SSL == protocol.NODE_SSL) and + protocol.haveSSL(not self.initiatedConnection)): + logger.debug("Initialising TLS") + if sys.version_info >= (2,7,9): + context = ssl.SSLContext(protocol.sslProtocolVersion) + context.set_ciphers(protocol.sslProtocolCiphers) + context.set_ecdh_curve("secp256k1") + context.check_hostname = False + context.verify_mode = ssl.CERT_NONE + # also exclude TLSv1 and TLSv1.1 in the future + context.options = ssl.OP_ALL | ssl.OP_NO_SSLv2 | ssl.OP_NO_SSLv3 | ssl.OP_SINGLE_ECDH_USE | ssl.OP_CIPHER_SERVER_PREFERENCE + self.sslSock = context.wrap_socket(self.sock, server_side = not self.initiatedConnection, do_handshake_on_connect=False) + else: + self.sslSock = ssl.wrap_socket(self.sock, keyfile = os.path.join(paths.codePath(), 'sslkeys', 'key.pem'), certfile = os.path.join(paths.codePath(), 'sslkeys', 'cert.pem'), server_side = not self.initiatedConnection, ssl_version=protocol.sslProtocolVersion, do_handshake_on_connect=False, ciphers=protocol.sslProtocolCiphers) + self.sendDataThreadQueue.join() + while True: + try: + self.sslSock.do_handshake() + logger.debug("TLS handshake success") + if sys.version_info >= (2, 7, 9): + logger.debug("TLS protocol version: %s", self.sslSock.version()) + break + except ssl.SSLError as e: + if sys.hexversion >= 0x02070900: + if isinstance (e, ssl.SSLWantReadError): + logger.debug("Waiting for SSL socket handhake read") + select.select([self.sslSock], [], [], 10) + continue + elif isinstance (e, ssl.SSLWantWriteError): + logger.debug("Waiting for SSL socket handhake write") + select.select([], [self.sslSock], [], 10) + continue + else: + if e.args[0] == ssl.SSL_ERROR_WANT_READ: + logger.debug("Waiting for SSL socket handhake read") + select.select([self.sslSock], [], [], 10) + continue + elif e.args[0] == ssl.SSL_ERROR_WANT_WRITE: + logger.debug("Waiting for SSL socket handhake write") + select.select([], [self.sslSock], [], 10) + continue + logger.error("SSL socket handhake failed: shutting down connection, %s", str(e)) + self.sendDataThreadQueue.put((0, 'shutdown','tls handshake fail %s' % (str(e)))) + return False + except socket.error as err: + logger.debug('SSL socket handshake failed, shutting down connection, %s', str(err)) + self.sendDataThreadQueue.put((0, 'shutdown','tls handshake fail')) + return False + except Exception: + logger.error("SSL socket handhake failed, shutting down connection", exc_info=True) + self.sendDataThreadQueue.put((0, 'shutdown','tls handshake fail')) + return False + # SSL in the background should be blocking, otherwise the error handling is difficult + self.sslSock.settimeout(None) + return True + # no SSL + return True + + def peerValidityChecks(self): + if self.remoteProtocolVersion < 3: + self.sendDataThreadQueue.put((0, 'sendRawData',protocol.assembleErrorMessage( + fatal=2, errorText="Your is using an old protocol. Closing connection."))) + logger.debug ('Closing connection to old protocol version ' + str(self.remoteProtocolVersion) + ' node: ' + str(self.peer)) + return False + if self.timeOffset > 3600: + self.sendDataThreadQueue.put((0, 'sendRawData', protocol.assembleErrorMessage( + fatal=2, errorText="Your time is too far in the future compared to mine. Closing connection."))) + logger.info("%s's time is too far in the future (%s seconds). Closing connection to it.", self.peer, self.timeOffset) + shared.timeOffsetWrongCount += 1 + time.sleep(2) + return False + elif self.timeOffset < -3600: + self.sendDataThreadQueue.put((0, 'sendRawData', protocol.assembleErrorMessage( + fatal=2, errorText="Your time is too far in the past compared to mine. Closing connection."))) + logger.info("%s's time is too far in the past (timeOffset %s seconds). Closing connection to it.", self.peer, self.timeOffset) + shared.timeOffsetWrongCount += 1 + return False + else: + shared.timeOffsetWrongCount = 0 + if len(self.streamNumber) == 0: + self.sendDataThreadQueue.put((0, 'sendRawData', protocol.assembleErrorMessage( + fatal=2, errorText="We don't have shared stream interests. Closing connection."))) + logger.debug ('Closed connection to ' + str(self.peer) + ' because there is no overlapping interest in streams.') + return False + return True + + def connectionFullyEstablished(self): + if self.connectionIsOrWasFullyEstablished: + # there is no reason to run this function a second time + return + + if not self.sslHandshake(): + return + + if self.peerValidityChecks() == False: + time.sleep(2) + self.sendDataThreadQueue.put((0, 'shutdown','no data')) + self.checkTimeOffsetNotification() + return + + self.connectionIsOrWasFullyEstablished = True + shared.timeOffsetWrongCount = 0 + + # Command the corresponding sendDataThread to set its own connectionIsOrWasFullyEstablished variable to True also + self.sendDataThreadQueue.put((0, 'connectionIsOrWasFullyEstablished', (self.services, self.sslSock))) + + if not self.initiatedConnection: + shared.clientHasReceivedIncomingConnections = True + queues.UISignalQueue.put(('setStatusIcon', 'green')) + self.sock.settimeout( + 600) # We'll send out a ping every 5 minutes to make sure the connection stays alive if there has been no other traffic to send lately. + queues.UISignalQueue.put(('updateNetworkStatusTab', 'no data')) + logger.debug('Connection fully established with ' + str(self.peer) + "\n" + \ + 'The size of the connectedHostsList is now ' + str(len(shared.connectedHostsList)) + "\n" + \ + 'The length of sendDataQueues is now: ' + str(len(state.sendDataQueues)) + "\n" + \ + 'broadcasting addr from within connectionFullyEstablished function.') + + if self.initiatedConnection: + state.networkProtocolAvailability[protocol.networkType(self.peer.host)] = True + + # we need to send our own objects to this node + PendingUpload().add() + + # Let all of our peers know about this new node. + for stream in self.remoteStreams: + dataToSend = (int(time.time()), stream, self.services, self.peer.host, self.remoteNodeIncomingPort) + protocol.broadcastToSendDataQueues(( + stream, 'advertisepeer', dataToSend)) + + self.sendaddr() # This is one large addr message to this one peer. + if len(shared.connectedHostsList) > \ + BMConfigParser().safeGetInt("bitmessagesettings", "maxtotalconnections", 200): + logger.info ('We are connected to too many people. Closing connection.') + if self.initiatedConnection: + self.sendDataThreadQueue.put((0, 'sendRawData', protocol.assembleErrorMessage(fatal=2, errorText="Thank you for providing a listening node."))) + else: + self.sendDataThreadQueue.put((0, 'sendRawData', protocol.assembleErrorMessage(fatal=2, errorText="Server full, please try again later."))) + self.sendDataThreadQueue.put((0, 'shutdown','no data')) + return + self.sendBigInv() + + def sendBigInv(self): + # Select all hashes for objects in this stream. + bigInvList = {} + for stream in self.streamNumber: + for hash in Inventory().unexpired_hashes_by_stream(stream): + if not self.objectHashHolderInstance.hasHash(hash): + bigInvList[hash] = 0 + numberOfObjectsInInvMessage = 0 + payload = '' + # Now let us start appending all of these hashes together. They will be + # sent out in a big inv message to our new peer. + for hash, storedValue in bigInvList.items(): + payload += hash + numberOfObjectsInInvMessage += 1 + if numberOfObjectsInInvMessage == 50000: # We can only send a max of 50000 items per inv message but we may have more objects to advertise. They must be split up into multiple inv messages. + self.sendinvMessageToJustThisOnePeer( + numberOfObjectsInInvMessage, payload) + payload = '' + numberOfObjectsInInvMessage = 0 + if numberOfObjectsInInvMessage > 0: + self.sendinvMessageToJustThisOnePeer( + numberOfObjectsInInvMessage, payload) + + # Used to send a big inv message when the connection with a node is + # first fully established. Notice that there is also a broadcastinv + # function for broadcasting invs to everyone in our stream. + def sendinvMessageToJustThisOnePeer(self, numberOfObjects, payload): + payload = encodeVarint(numberOfObjects) + payload + logger.debug('Sending huge inv message with ' + str(numberOfObjects) + ' objects to just this one peer') + self.sendDataThreadQueue.put((0, 'sendRawData', protocol.CreatePacket('inv', payload))) + + def _sleepForTimingAttackMitigation(self, sleepTime): + # We don't need to do the timing attack mitigation if we are + # only connected to the trusted peer because we can trust the + # peer not to attack + if sleepTime > 0 and doTimingAttackMitigation and state.trustedPeer == None: + logger.debug('Timing attack mitigation: Sleeping for ' + str(sleepTime) + ' seconds.') + time.sleep(sleepTime) + + def recerror(self, data): + """ + The remote node has been polite enough to send you an error message. + """ + fatalStatus, readPosition = decodeVarint(data[:10]) + banTime, banTimeLength = decodeVarint(data[readPosition:readPosition+10]) + readPosition += banTimeLength + inventoryVectorLength, inventoryVectorLengthLength = decodeVarint(data[readPosition:readPosition+10]) + if inventoryVectorLength > 100: + return + readPosition += inventoryVectorLengthLength + inventoryVector = data[readPosition:readPosition+inventoryVectorLength] + readPosition += inventoryVectorLength + errorTextLength, errorTextLengthLength = decodeVarint(data[readPosition:readPosition+10]) + if errorTextLength > 1000: + return + readPosition += errorTextLengthLength + errorText = data[readPosition:readPosition+errorTextLength] + if fatalStatus == 0: + fatalHumanFriendly = 'Warning' + elif fatalStatus == 1: + fatalHumanFriendly = 'Error' + elif fatalStatus == 2: + fatalHumanFriendly = 'Fatal' + message = '%s message received from %s: %s.' % (fatalHumanFriendly, self.peer, errorText) + if inventoryVector: + message += " This concerns object %s" % hexlify(inventoryVector) + if banTime > 0: + message += " Remote node says that the ban time is %s" % banTime + logger.error(message) + + + def recobject(self, data): + self.messageProcessingStartTime = time.time() + lengthOfTimeWeShouldUseToProcessThisMessage = shared.checkAndShareObjectWithPeers(data) + self.downloadQueue.task_done(calculateInventoryHash(data)) + + """ + Sleeping will help guarantee that we can process messages faster than a + remote node can send them. If we fall behind, the attacker could observe + that we are are slowing down the rate at which we request objects from the + network which would indicate that we own a particular address (whichever + one to which they are sending all of their attack messages). Note + that if an attacker connects to a target with many connections, this + mitigation mechanism might not be sufficient. + """ + sleepTime = lengthOfTimeWeShouldUseToProcessThisMessage - (time.time() - self.messageProcessingStartTime) + self._sleepForTimingAttackMitigation(sleepTime) + + + # We have received an inv message + def recinv(self, data): + numberOfItemsInInv, lengthOfVarint = decodeVarint(data[:10]) + if numberOfItemsInInv > 50000: + sys.stderr.write('Too many items in inv message!') + return + if len(data) < lengthOfVarint + (numberOfItemsInInv * 32): + logger.info('inv message doesn\'t contain enough data. Ignoring.') + return + + startTime = time.time() + advertisedSet = set() + for i in range(numberOfItemsInInv): + advertisedSet.add(data[lengthOfVarint + (32 * i):32 + lengthOfVarint + (32 * i)]) + objectsNewToMe = advertisedSet + for stream in self.streamNumber: + objectsNewToMe -= Inventory().hashes_by_stream(stream) + logger.info('inv message lists %s objects. Of those %s are new to me. It took %s seconds to figure that out.', numberOfItemsInInv, len(objectsNewToMe), time.time()-startTime) + for item in random.sample(objectsNewToMe, len(objectsNewToMe)): + self.downloadQueue.put(item) + + # Send a getdata message to our peer to request the object with the given + # hash + def sendgetdata(self, hashes): + if len(hashes) == 0: + return + logger.debug('sending getdata to retrieve %i objects', len(hashes)) + payload = encodeVarint(len(hashes)) + ''.join(hashes) + self.sendDataThreadQueue.put((0, 'sendRawData', protocol.CreatePacket('getdata', payload)), False) + + + # We have received a getdata request from our peer + def recgetdata(self, data): + numberOfRequestedInventoryItems, lengthOfVarint = decodeVarint( + data[:10]) + if len(data) < lengthOfVarint + (32 * numberOfRequestedInventoryItems): + logger.debug('getdata message does not contain enough data. Ignoring.') + return + self.antiIntersectionDelay(True) # only handle getdata requests if we have been connected long enough + for i in xrange(numberOfRequestedInventoryItems): + hash = data[lengthOfVarint + ( + i * 32):32 + lengthOfVarint + (i * 32)] + logger.debug('received getdata request for item:' + hexlify(hash)) + + if self.objectHashHolderInstance.hasHash(hash): + self.antiIntersectionDelay() + else: + if hash in Inventory(): + self.sendObject(hash, Inventory()[hash].payload) + else: + self.antiIntersectionDelay() + logger.warning('%s asked for an object with a getdata which is not in either our memory inventory or our SQL inventory. We probably cleaned it out after advertising it but before they got around to asking for it.' % (self.peer,)) + + # Our peer has requested (in a getdata message) that we send an object. + def sendObject(self, hash, payload): + logger.debug('sending an object.') + self.sendDataThreadQueue.put((0, 'sendRawData', (hash, protocol.CreatePacket('object',payload)))) + + def _checkIPAddress(self, host): + if host[0:12] == '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF': + hostStandardFormat = socket.inet_ntop(socket.AF_INET, host[12:]) + return self._checkIPv4Address(host[12:], hostStandardFormat) + elif host[0:6] == '\xfd\x87\xd8\x7e\xeb\x43': + # Onion, based on BMD/bitcoind + hostStandardFormat = base64.b32encode(host[6:]).lower() + ".onion" + return hostStandardFormat + else: + hostStandardFormat = socket.inet_ntop(socket.AF_INET6, host) + if hostStandardFormat == "": + # This can happen on Windows systems which are not 64-bit compatible + # so let us drop the IPv6 address. + return False + return self._checkIPv6Address(host, hostStandardFormat) + + def _checkIPv4Address(self, host, hostStandardFormat): + if host[0] == '\x7F': # 127/8 + logger.debug('Ignoring IP address in loopback range: ' + hostStandardFormat) + return False + if host[0] == '\x0A': # 10/8 + logger.debug('Ignoring IP address in private range: ' + hostStandardFormat) + return False + if host[0:2] == '\xC0\xA8': # 192.168/16 + logger.debug('Ignoring IP address in private range: ' + hostStandardFormat) + return False + if host[0:2] >= '\xAC\x10' and host[0:2] < '\xAC\x20': # 172.16/12 + logger.debug('Ignoring IP address in private range:' + hostStandardFormat) + return False + return hostStandardFormat + + def _checkIPv6Address(self, host, hostStandardFormat): + if host == ('\x00' * 15) + '\x01': + logger.debug('Ignoring loopback address: ' + hostStandardFormat) + return False + if host[0] == '\xFE' and (ord(host[1]) & 0xc0) == 0x80: + logger.debug ('Ignoring local address: ' + hostStandardFormat) + return False + if (ord(host[0]) & 0xfe) == 0xfc: + logger.debug ('Ignoring unique local address: ' + hostStandardFormat) + return False + return hostStandardFormat + + # We have received an addr message. + def recaddr(self, data): + numberOfAddressesIncluded, lengthOfNumberOfAddresses = decodeVarint( + data[:10]) + + if shared.verbose >= 1: + logger.debug('addr message contains ' + str(numberOfAddressesIncluded) + ' IP addresses.') + + if numberOfAddressesIncluded > 1000 or numberOfAddressesIncluded == 0: + return + if len(data) != lengthOfNumberOfAddresses + (38 * numberOfAddressesIncluded): + logger.debug('addr message does not contain the correct amount of data. Ignoring.') + return + + for i in range(0, numberOfAddressesIncluded): + fullHost = data[20 + lengthOfNumberOfAddresses + (38 * i):36 + lengthOfNumberOfAddresses + (38 * i)] + recaddrStream, = unpack('>I', data[8 + lengthOfNumberOfAddresses + ( + 38 * i):12 + lengthOfNumberOfAddresses + (38 * i)]) + if recaddrStream == 0: + continue + if recaddrStream not in self.streamNumber and (recaddrStream / 2) not in self.streamNumber: # if the embedded stream number and its parent are not in my streams then ignore it. Someone might be trying funny business. + continue + recaddrServices, = unpack('>Q', data[12 + lengthOfNumberOfAddresses + ( + 38 * i):20 + lengthOfNumberOfAddresses + (38 * i)]) + recaddrPort, = unpack('>H', data[36 + lengthOfNumberOfAddresses + ( + 38 * i):38 + lengthOfNumberOfAddresses + (38 * i)]) + hostStandardFormat = self._checkIPAddress(fullHost) + if hostStandardFormat is False: + continue + if recaddrPort == 0: + continue + timeSomeoneElseReceivedMessageFromThisNode, = unpack('>Q', data[lengthOfNumberOfAddresses + ( + 38 * i):8 + lengthOfNumberOfAddresses + (38 * i)]) # This is the 'time' value in the received addr message. 64-bit. + if recaddrStream not in knownnodes.knownNodes: # knownNodes is a dictionary of dictionaries with one outer dictionary for each stream. If the outer stream dictionary doesn't exist yet then we must make it. + with knownnodes.knownNodesLock: + knownnodes.knownNodes[recaddrStream] = {} + peerFromAddrMessage = state.Peer(hostStandardFormat, recaddrPort) + if peerFromAddrMessage not in knownnodes.knownNodes[recaddrStream]: + # only if recent + if timeSomeoneElseReceivedMessageFromThisNode > (int(time.time()) - 10800) and timeSomeoneElseReceivedMessageFromThisNode < (int(time.time()) + 10800): + # bootstrap provider? + if BMConfigParser().safeGetInt('bitmessagesettings', 'maxoutboundconnections') >= \ + BMConfigParser().safeGetInt('bitmessagesettings', 'maxtotalconnections', 200): + knownnodes.trimKnownNodes(recaddrStream) + with knownnodes.knownNodesLock: + knownnodes.knownNodes[recaddrStream][peerFromAddrMessage] = int(time.time()) - 86400 # penalise initially by 1 day + logger.debug('added new node ' + str(peerFromAddrMessage) + ' to knownNodes in stream ' + str(recaddrStream)) + shared.needToWriteKnownNodesToDisk = True + # normal mode + elif len(knownnodes.knownNodes[recaddrStream]) < 20000: + with knownnodes.knownNodesLock: + knownnodes.knownNodes[recaddrStream][peerFromAddrMessage] = timeSomeoneElseReceivedMessageFromThisNode + hostDetails = ( + timeSomeoneElseReceivedMessageFromThisNode, + recaddrStream, recaddrServices, hostStandardFormat, recaddrPort) + protocol.broadcastToSendDataQueues(( + recaddrStream, 'advertisepeer', hostDetails)) + logger.debug('added new node ' + str(peerFromAddrMessage) + ' to knownNodes in stream ' + str(recaddrStream)) + shared.needToWriteKnownNodesToDisk = True + # only update if normal mode + elif BMConfigParser().safeGetInt('bitmessagesettings', 'maxoutboundconnections') < \ + BMConfigParser().safeGetInt('bitmessagesettings', 'maxtotalconnections', 200): + timeLastReceivedMessageFromThisNode = knownnodes.knownNodes[recaddrStream][ + peerFromAddrMessage] + if (timeLastReceivedMessageFromThisNode < timeSomeoneElseReceivedMessageFromThisNode) and (timeSomeoneElseReceivedMessageFromThisNode < int(time.time())+900): # 900 seconds for wiggle-room in case other nodes' clocks aren't quite right. + with knownnodes.knownNodesLock: + knownnodes.knownNodes[recaddrStream][peerFromAddrMessage] = timeSomeoneElseReceivedMessageFromThisNode + + for stream in self.streamNumber: + logger.debug('knownNodes currently has %i nodes for stream %i', len(knownnodes.knownNodes[stream]), stream) + + + # Send a huge addr message to our peer. This is only used + # when we fully establish a connection with a + # peer (with the full exchange of version and verack + # messages). + def sendaddr(self): + def sendChunk(): + if numberOfAddressesInAddrMessage == 0: + return + self.sendDataThreadQueue.put((0, 'sendRawData', \ + protocol.CreatePacket('addr', \ + encodeVarint(numberOfAddressesInAddrMessage) + payload))) + + # We are going to share a maximum number of 1000 addrs (per overlapping + # stream) with our peer. 500 from overlapping streams, 250 from the + # left child stream, and 250 from the right child stream. + maxAddrCount = BMConfigParser().safeGetInt("bitmessagesettings", "maxaddrperstreamsend", 500) + + # protocol defines this as a maximum in one chunk + protocolAddrLimit = 1000 + + # init + numberOfAddressesInAddrMessage = 0 + payload = '' + + for stream in self.streamNumber: + addrsInMyStream = {} + addrsInChildStreamLeft = {} + addrsInChildStreamRight = {} + + with knownnodes.knownNodesLock: + if len(knownnodes.knownNodes[stream]) > 0: + filtered = {k: v for k, v in knownnodes.knownNodes[stream].items() + if v > (int(time.time()) - shared.maximumAgeOfNodesThatIAdvertiseToOthers)} + elemCount = len(filtered) + if elemCount > maxAddrCount: + elemCount = maxAddrCount + # only if more recent than 3 hours + addrsInMyStream = random.sample(filtered.items(), elemCount) + # sent 250 only if the remote isn't interested in it + if len(knownnodes.knownNodes[stream * 2]) > 0 and stream not in self.streamNumber: + filtered = {k: v for k, v in knownnodes.knownNodes[stream*2].items() + if v > (int(time.time()) - shared.maximumAgeOfNodesThatIAdvertiseToOthers)} + elemCount = len(filtered) + if elemCount > maxAddrCount / 2: + elemCount = int(maxAddrCount / 2) + addrsInChildStreamLeft = random.sample(filtered.items(), elemCount) + if len(knownnodes.knownNodes[(stream * 2) + 1]) > 0 and stream not in self.streamNumber: + filtered = {k: v for k, v in knownnodes.knownNodes[stream*2+1].items() + if v > (int(time.time()) - shared.maximumAgeOfNodesThatIAdvertiseToOthers)} + elemCount = len(filtered) + if elemCount > maxAddrCount / 2: + elemCount = int(maxAddrCount / 2) + addrsInChildStreamRight = random.sample(filtered.items(), elemCount) + for (HOST, PORT), timeLastReceivedMessageFromThisNode in addrsInMyStream: + numberOfAddressesInAddrMessage += 1 + payload += pack( + '>Q', timeLastReceivedMessageFromThisNode) # 64-bit time + payload += pack('>I', stream) + payload += pack( + '>q', 1) # service bit flags offered by this node + payload += protocol.encodeHost(HOST) + payload += pack('>H', PORT) # remote port + if numberOfAddressesInAddrMessage >= protocolAddrLimit: + sendChunk() + payload = '' + numberOfAddressesInAddrMessage = 0 + for (HOST, PORT), timeLastReceivedMessageFromThisNode in addrsInChildStreamLeft: + numberOfAddressesInAddrMessage += 1 + payload += pack( + '>Q', timeLastReceivedMessageFromThisNode) # 64-bit time + payload += pack('>I', stream * 2) + payload += pack( + '>q', 1) # service bit flags offered by this node + payload += protocol.encodeHost(HOST) + payload += pack('>H', PORT) # remote port + if numberOfAddressesInAddrMessage >= protocolAddrLimit: + sendChunk() + payload = '' + numberOfAddressesInAddrMessage = 0 + for (HOST, PORT), timeLastReceivedMessageFromThisNode in addrsInChildStreamRight: + numberOfAddressesInAddrMessage += 1 + payload += pack( + '>Q', timeLastReceivedMessageFromThisNode) # 64-bit time + payload += pack('>I', (stream * 2) + 1) + payload += pack( + '>q', 1) # service bit flags offered by this node + payload += protocol.encodeHost(HOST) + payload += pack('>H', PORT) # remote port + if numberOfAddressesInAddrMessage >= protocolAddrLimit: + sendChunk() + payload = '' + numberOfAddressesInAddrMessage = 0 + + # flush + sendChunk() + + # We have received a version message + def recversion(self, data): + if len(data) < 83: + # This version message is unreasonably short. Forget it. + return + if self.verackSent: + """ + We must have already processed the remote node's version message. + There might be a time in the future when we Do want to process + a new version message, like if the remote node wants to update + the streams in which they are interested. But for now we'll + ignore this version message + """ + return + + self.remoteProtocolVersion, = unpack('>L', data[:4]) + self.services, = unpack('>q', data[4:12]) + + timestamp, = unpack('>Q', data[12:20]) + self.timeOffset = timestamp - int(time.time()) + + self.myExternalIP = socket.inet_ntoa(data[40:44]) + # print 'myExternalIP', self.myExternalIP + self.remoteNodeIncomingPort, = unpack('>H', data[70:72]) + # print 'remoteNodeIncomingPort', self.remoteNodeIncomingPort + useragentLength, lengthOfUseragentVarint = decodeVarint( + data[80:84]) + readPosition = 80 + lengthOfUseragentVarint + self.userAgent = data[readPosition:readPosition + useragentLength] + + # version check + try: + userAgentName, userAgentVersion = self.userAgent[1:-1].split(":", 2) + except: + userAgentName = self.userAgent + userAgentVersion = "0.0.0" + if userAgentName == "PyBitmessage": + myVersion = [int(n) for n in softwareVersion.split(".")] + try: + remoteVersion = [int(n) for n in userAgentVersion.split(".")] + except: + remoteVersion = 0 + # remote is newer, but do not cross between stable and unstable + try: + if cmp(remoteVersion, myVersion) > 0 and \ + (myVersion[1] % 2 == remoteVersion[1] % 2): + queues.UISignalQueue.put(('newVersionAvailable', remoteVersion)) + except: + pass + + readPosition += useragentLength + numberOfStreamsInVersionMessage, lengthOfNumberOfStreamsInVersionMessage = decodeVarint( + data[readPosition:]) + readPosition += lengthOfNumberOfStreamsInVersionMessage + self.remoteStreams = [] + for i in range(numberOfStreamsInVersionMessage): + newStreamNumber, lengthOfRemoteStreamNumber = decodeVarint(data[readPosition:]) + readPosition += lengthOfRemoteStreamNumber + self.remoteStreams.append(newStreamNumber) + logger.debug('Remote node useragent: %s, streams: (%s), time offset: %is.', + self.userAgent, ', '.join(str(x) for x in self.remoteStreams), self.timeOffset) + + # find shared streams + self.streamNumber = sorted(set(state.streamsInWhichIAmParticipating).intersection(self.remoteStreams)) + + shared.connectedHostsList[ + self.hostIdent] = 1 # We use this data structure to not only keep track of what hosts we are connected to so that we don't try to connect to them again, but also to list the connections count on the Network Status tab. + self.sendDataThreadQueue.put((0, 'setStreamNumber', self.remoteStreams)) + if data[72:80] == protocol.eightBytesOfRandomDataUsedToDetectConnectionsToSelf: + self.sendDataThreadQueue.put((0, 'shutdown','no data')) + logger.debug('Closing connection to myself: ' + str(self.peer)) + return + + # The other peer's protocol version is of interest to the sendDataThread but we learn of it + # in this version message. Let us inform the sendDataThread. + self.sendDataThreadQueue.put((0, 'setRemoteProtocolVersion', self.remoteProtocolVersion)) + + if not isHostInPrivateIPRange(self.peer.host): + with knownnodes.knownNodesLock: + for stream in self.remoteStreams: + knownnodes.knownNodes[stream][state.Peer(self.peer.host, self.remoteNodeIncomingPort)] = int(time.time()) + if not self.initiatedConnection: + # bootstrap provider? + if BMConfigParser().safeGetInt('bitmessagesettings', 'maxoutboundconnections') >= \ + BMConfigParser().safeGetInt('bitmessagesettings', 'maxtotalconnections', 200): + knownnodes.knownNodes[stream][state.Peer(self.peer.host, self.remoteNodeIncomingPort)] -= 10800 # penalise inbound, 3 hours + else: + knownnodes.knownNodes[stream][state.Peer(self.peer.host, self.remoteNodeIncomingPort)] -= 7200 # penalise inbound, 2 hours + shared.needToWriteKnownNodesToDisk = True + + self.sendverack() + if self.initiatedConnection == False: + self.sendversion() + + # Sends a version message + def sendversion(self): + logger.debug('Sending version message') + self.sendDataThreadQueue.put((0, 'sendRawData', protocol.assembleVersionMessage( + self.peer.host, self.peer.port, state.streamsInWhichIAmParticipating, not self.initiatedConnection))) + + # Sends a verack message + def sendverack(self): + logger.debug('Sending verack') + self.sendDataThreadQueue.put((0, 'sendRawData', protocol.CreatePacket('verack'))) + self.verackSent = True + if self.verackReceived: + self.connectionFullyEstablished() diff --git a/src/class_sendDataThread.py b/src/class_sendDataThread.py new file mode 100644 index 00000000..792fedd0 --- /dev/null +++ b/src/class_sendDataThread.py @@ -0,0 +1,216 @@ +import errno +import time +import threading +import Queue +from struct import unpack, pack +import hashlib +import random +import select +import socket +from ssl import SSLError, SSL_ERROR_WANT_WRITE +import sys + +from helper_generic import addDataPadding +from class_objectHashHolder import * +from addresses import * +from debug import logger +from inventory import PendingUpload +import protocol +import state +import throttle + +# Every connection to a peer has a sendDataThread (and also a +# receiveDataThread). +class sendDataThread(threading.Thread): + + def __init__(self, sendDataThreadQueue): + threading.Thread.__init__(self, name="sendData") + self.sendDataThreadQueue = sendDataThreadQueue + state.sendDataQueues.append(self.sendDataThreadQueue) + self.data = '' + self.objectHashHolderInstance = objectHashHolder(self.sendDataThreadQueue) + self.objectHashHolderInstance.daemon = True + self.objectHashHolderInstance.start() + self.connectionIsOrWasFullyEstablished = False + + + def setup( + self, + sock, + HOST, + PORT, + streamNumber + ): + self.sock = sock + self.peer = state.Peer(HOST, PORT) + self.name = "sendData-" + self.peer.host.replace(":", ".") # log parser field separator + self.streamNumber = [] + self.services = 0 + self.buffer = "" + self.initiatedConnection = False + self.remoteProtocolVersion = - \ + 1 # This must be set using setRemoteProtocolVersion command which is sent through the self.sendDataThreadQueue queue. + self.lastTimeISentData = int( + time.time()) # If this value increases beyond five minutes ago, we'll send a pong message to keep the connection alive. + if streamNumber == -1: # This was an incoming connection. + self.initiatedConnection = False + else: + self.initiatedConnection = True + #logger.debug('The streamNumber of this sendDataThread (ID: ' + str(id(self)) + ') at setup() is' + str(self.streamNumber)) + + + def sendVersionMessage(self): + datatosend = protocol.assembleVersionMessage( + self.peer.host, self.peer.port, state.streamsInWhichIAmParticipating, not self.initiatedConnection) # the IP and port of the remote host, and my streamNumber. + + logger.debug('Sending version packet: ' + repr(datatosend)) + + try: + self.sendBytes(datatosend) + except Exception as err: + # if not 'Bad file descriptor' in err: + logger.error('sock.sendall error: %s\n' % err) + + self.versionSent = 1 + + def sendBytes(self, data = ""): + self.buffer += data + if len(self.buffer) < throttle.SendThrottle().chunkSize and self.sendDataThreadQueue.qsize() > 1: + return True + + while self.buffer and state.shutdown == 0: + isSSL = False + try: + if ((self.services & protocol.NODE_SSL == protocol.NODE_SSL) and + self.connectionIsOrWasFullyEstablished and + protocol.haveSSL(not self.initiatedConnection)): + isSSL = True + amountSent = self.sslSock.send(self.buffer[:throttle.SendThrottle().chunkSize]) + else: + amountSent = self.sock.send(self.buffer[:throttle.SendThrottle().chunkSize]) + except socket.timeout: + continue + except SSLError as e: + if e.errno == SSL_ERROR_WANT_WRITE: + select.select([], [self.sslSock], [], 10) + logger.debug('sock.recv retriable SSL error') + continue + logger.debug('Connection error (SSL)') + return False + except socket.error as e: + if e.errno in (errno.EAGAIN, errno.EWOULDBLOCK) or \ + (sys.platform.startswith('win') and \ + e.errno == errno.WSAEWOULDBLOCK): + select.select([], [self.sslSock if isSSL else self.sock], [], 10) + logger.debug('sock.recv retriable error') + continue + if e.errno in (errno.EPIPE, errno.ECONNRESET, errno.EHOSTUNREACH, errno.ETIMEDOUT, errno.ECONNREFUSED): + logger.debug('Connection error: %s', str(e)) + return False + raise + throttle.SendThrottle().wait(amountSent) + self.lastTimeISentData = int(time.time()) + self.buffer = self.buffer[amountSent:] + return True + + def run(self): + logger.debug('sendDataThread starting. ID: ' + str(id(self)) + '. Number of queues in sendDataQueues: ' + str(len(state.sendDataQueues))) + while self.sendBytes(): + deststream, command, data = self.sendDataThreadQueue.get() + + if deststream == 0 or deststream in self.streamNumber: + if command == 'shutdown': + logger.debug('sendDataThread (associated with ' + str(self.peer) + ') ID: ' + str(id(self)) + ' shutting down now.') + break + # When you receive an incoming connection, a sendDataThread is + # created even though you don't yet know what stream number the + # remote peer is interested in. They will tell you in a version + # message and if you too are interested in that stream then you + # will continue on with the connection and will set the + # streamNumber of this send data thread here: + elif command == 'setStreamNumber': + self.streamNumber = data + logger.debug('setting the stream number to %s', ', '.join(str(x) for x in self.streamNumber)) + elif command == 'setRemoteProtocolVersion': + specifiedRemoteProtocolVersion = data + logger.debug('setting the remote node\'s protocol version in the sendDataThread (ID: ' + str(id(self)) + ') to ' + str(specifiedRemoteProtocolVersion)) + self.remoteProtocolVersion = specifiedRemoteProtocolVersion + elif command == 'advertisepeer': + self.objectHashHolderInstance.holdPeer(data) + elif command == 'sendaddr': + if self.connectionIsOrWasFullyEstablished: # only send addr messages if we have sent and heard a verack from the remote node + numberOfAddressesInAddrMessage = len(data) + payload = '' + for hostDetails in data: + timeLastReceivedMessageFromThisNode, streamNumber, services, host, port = hostDetails + payload += pack( + '>Q', timeLastReceivedMessageFromThisNode) # now uses 64-bit time + payload += pack('>I', streamNumber) + payload += pack( + '>q', services) # service bit flags offered by this node + payload += protocol.encodeHost(host) + payload += pack('>H', port) + + payload = encodeVarint(numberOfAddressesInAddrMessage) + payload + packet = protocol.CreatePacket('addr', payload) + try: + self.sendBytes(packet) + except: + logger.error('sendaddr: self.sock.sendall failed') + break + elif command == 'advertiseobject': + self.objectHashHolderInstance.holdHash(data) + elif command == 'sendinv': + if self.connectionIsOrWasFullyEstablished: # only send inv messages if we have send and heard a verack from the remote node + payload = '' + for hash in data: + payload += hash + if payload != '': + payload = encodeVarint(len(payload)/32) + payload + packet = protocol.CreatePacket('inv', payload) + try: + self.sendBytes(packet) + except: + logger.error('sendinv: self.sock.sendall failed') + break + elif command == 'pong': + if self.lastTimeISentData < (int(time.time()) - 298): + # Send out a pong message to keep the connection alive. + logger.debug('Sending pong to ' + str(self.peer) + ' to keep connection alive.') + packet = protocol.CreatePacket('pong') + try: + self.sendBytes(packet) + except: + logger.error('send pong failed') + break + elif command == 'sendRawData': + objectHash = None + if type(data) in [list, tuple]: + objectHash, data = data + try: + self.sendBytes(data) + PendingUpload().delete(objectHash) + except: + logger.error('Sending of data to ' + str(self.peer) + ' failed. sendDataThread thread ' + str(self) + ' ending now.', exc_info=True) + break + elif command == 'connectionIsOrWasFullyEstablished': + self.connectionIsOrWasFullyEstablished = True + self.services, self.sslSock = data + elif self.connectionIsOrWasFullyEstablished: + logger.error('sendDataThread ID: ' + str(id(self)) + ' ignoring command ' + command + ' because the thread is not in stream ' + str(deststream) + ' but in streams ' + ', '.join(str(x) for x in self.streamNumber)) + self.sendDataThreadQueue.task_done() + # Flush if the cycle ended with break + try: + self.sendDataThreadQueue.task_done() + except ValueError: + pass + + try: + self.sock.shutdown(socket.SHUT_RDWR) + self.sock.close() + except: + pass + state.sendDataQueues.remove(self.sendDataThreadQueue) + PendingUpload().threadEnd() + logger.info('sendDataThread ending. ID: ' + str(id(self)) + '. Number of queues in sendDataQueues: ' + str(len(state.sendDataQueues))) + self.objectHashHolderInstance.close() diff --git a/src/class_singleListener.py b/src/class_singleListener.py new file mode 100644 index 00000000..7626542d --- /dev/null +++ b/src/class_singleListener.py @@ -0,0 +1,168 @@ +import threading +import shared +import socket +from bmconfigparser import BMConfigParser +from class_sendDataThread import * +from class_receiveDataThread import * +import helper_bootstrap +from helper_threading import * +import protocol +import errno +import re + +import state + +# Only one singleListener thread will ever exist. It creates the +# receiveDataThread and sendDataThread for each incoming connection. Note +# that it cannot set the stream number because it is not known yet- the +# other node will have to tell us its stream number in a version message. +# If we don't care about their stream, we will close the connection +# (within the recversion function of the recieveData thread) + + +class singleListener(threading.Thread, StoppableThread): + + def __init__(self): + threading.Thread.__init__(self, name="singleListener") + self.initStop() + + def setup(self, selfInitiatedConnections): + self.selfInitiatedConnections = selfInitiatedConnections + + def _createListenSocket(self, family): + HOST = '' # Symbolic name meaning all available interfaces + # If not sockslisten, but onionhostname defined, only listen on localhost + if not BMConfigParser().safeGetBoolean('bitmessagesettings', 'sockslisten') and ".onion" in BMConfigParser().get('bitmessagesettings', 'onionhostname'): + if family == socket.AF_INET6 and "." in BMConfigParser().get('bitmessagesettings', 'onionbindip'): + raise socket.error(errno.EINVAL, "Invalid mix of IPv4 and IPv6") + elif family == socket.AF_INET and ":" in BMConfigParser().get('bitmessagesettings', 'onionbindip'): + raise socket.error(errno.EINVAL, "Invalid mix of IPv4 and IPv6") + HOST = BMConfigParser().get('bitmessagesettings', 'onionbindip') + PORT = BMConfigParser().getint('bitmessagesettings', 'port') + sock = socket.socket(family, socket.SOCK_STREAM) + if family == socket.AF_INET6: + # Make sure we can accept both IPv4 and IPv6 connections. + # This is the default on everything apart from Windows + sock.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, 0) + # This option apparently avoids the TIME_WAIT state so that we can + # rebind faster + sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + sock.bind((HOST, PORT)) + sock.listen(2) + return sock + + def stopThread(self): + super(singleListener, self).stopThread() + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + for ip in ('127.0.0.1', BMConfigParser().get('bitmessagesettings', 'onionbindip')): + try: + s.connect((ip, BMConfigParser().getint('bitmessagesettings', 'port'))) + s.shutdown(socket.SHUT_RDWR) + s.close() + break + except: + pass + + def run(self): + # If there is a trusted peer then we don't want to accept + # incoming connections so we'll just abandon the thread + if state.trustedPeer: + return + + while BMConfigParser().safeGetBoolean('bitmessagesettings', 'dontconnect') and state.shutdown == 0: + self.stop.wait(1) + helper_bootstrap.dns() + # We typically don't want to accept incoming connections if the user is using a + # SOCKS proxy, unless they have configured otherwise. If they eventually select + # proxy 'none' or configure SOCKS listening then this will start listening for + # connections. But if on SOCKS and have an onionhostname, listen + # (socket is then only opened for localhost) + while BMConfigParser().get('bitmessagesettings', 'socksproxytype')[0:5] == 'SOCKS' and \ + (not BMConfigParser().getboolean('bitmessagesettings', 'sockslisten') and \ + ".onion" not in BMConfigParser().get('bitmessagesettings', 'onionhostname')) and \ + state.shutdown == 0: + self.stop.wait(5) + + logger.info('Listening for incoming connections.') + + # First try listening on an IPv6 socket. This should also be + # able to accept connections on IPv4. If that's not available + # we'll fall back to IPv4-only. + try: + sock = self._createListenSocket(socket.AF_INET6) + except socket.error as e: + if (isinstance(e.args, tuple) and + e.args[0] in (errno.EAFNOSUPPORT, + errno.EPFNOSUPPORT, + errno.EADDRNOTAVAIL, + errno.ENOPROTOOPT, + errno.EINVAL)): + sock = self._createListenSocket(socket.AF_INET) + else: + raise + + # regexp to match an IPv4-mapped IPv6 address + mappedAddressRegexp = re.compile(r'^::ffff:([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)$') + + while state.shutdown == 0: + # We typically don't want to accept incoming connections if the user is using a + # SOCKS proxy, unless they have configured otherwise. If they eventually select + # proxy 'none' or configure SOCKS listening then this will start listening for + # connections. + while BMConfigParser().get('bitmessagesettings', 'socksproxytype')[0:5] == 'SOCKS' and not BMConfigParser().getboolean('bitmessagesettings', 'sockslisten') and ".onion" not in BMConfigParser().get('bitmessagesettings', 'onionhostname') and state.shutdown == 0: + self.stop.wait(10) + while len(shared.connectedHostsList) > \ + BMConfigParser().safeGetInt("bitmessagesettings", "maxtotalconnections", 200) + \ + BMConfigParser().safeGetInt("bitmessagesettings", "maxbootstrapconnections", 20) \ + and state.shutdown == 0: + logger.info('We are connected to too many people. Not accepting further incoming connections for ten seconds.') + + self.stop.wait(10) + + while state.shutdown == 0: + try: + socketObject, sockaddr = sock.accept() + except socket.error as e: + if isinstance(e.args, tuple) and \ + e.args[0] in (errno.EINTR,): + continue + time.wait(1) + continue + + (HOST, PORT) = sockaddr[0:2] + + # If the address is an IPv4-mapped IPv6 address then + # convert it to just the IPv4 representation + md = mappedAddressRegexp.match(HOST) + if md != None: + HOST = md.group(1) + + # The following code will, unfortunately, block an + # incoming connection if someone else on the same LAN + # is already connected because the two computers will + # share the same external IP. This is here to prevent + # connection flooding. + # permit repeated connections from Tor + if HOST in shared.connectedHostsList and \ + (".onion" not in BMConfigParser().get('bitmessagesettings', 'onionhostname') or not protocol.checkSocksIP(HOST)): + socketObject.close() + logger.info('We are already connected to ' + str(HOST) + '. Ignoring connection.') + else: + break + + sendDataThreadQueue = Queue.Queue() # Used to submit information to the send data thread for this connection. + socketObject.settimeout(20) + + sd = sendDataThread(sendDataThreadQueue) + sd.setup( + socketObject, HOST, PORT, -1) + sd.start() + + rd = receiveDataThread() + rd.daemon = True # close the main program even if there are threads left + rd.setup( + socketObject, HOST, PORT, -1, self.selfInitiatedConnections, sendDataThreadQueue, sd.objectHashHolderInstance) + rd.start() + + logger.info('connected to ' + HOST + ' during INCOMING request.') + diff --git a/src/class_singleWorker.py b/src/class_singleWorker.py index 90db23c3..322bb20e 100644 --- a/src/class_singleWorker.py +++ b/src/class_singleWorker.py @@ -19,7 +19,7 @@ import helper_inbox from helper_generic import addDataPadding import helper_msgcoding from helper_threading import * -from inventory import Inventory +from inventory import Inventory, PendingUpload import l10n import protocol import queues @@ -199,6 +199,7 @@ class singleWorker(threading.Thread, StoppableThread): objectType = 1 Inventory()[inventoryHash] = ( objectType, streamNumber, payload, embeddedTime,'') + PendingUpload().add(inventoryHash) logger.info('broadcasting inv with hash: ' + hexlify(inventoryHash)) @@ -288,6 +289,7 @@ class singleWorker(threading.Thread, StoppableThread): objectType = 1 Inventory()[inventoryHash] = ( objectType, streamNumber, payload, embeddedTime,'') + PendingUpload().add(inventoryHash) logger.info('broadcasting inv with hash: ' + hexlify(inventoryHash)) @@ -377,6 +379,7 @@ class singleWorker(threading.Thread, StoppableThread): objectType = 1 Inventory()[inventoryHash] = ( objectType, streamNumber, payload, embeddedTime, doubleHashOfAddressData[32:]) + PendingUpload().add(inventoryHash) logger.info('broadcasting inv with hash: ' + hexlify(inventoryHash)) @@ -507,6 +510,7 @@ class singleWorker(threading.Thread, StoppableThread): objectType = 3 Inventory()[inventoryHash] = ( objectType, streamNumber, payload, embeddedTime, tag) + PendingUpload().add(inventoryHash) logger.info('sending inv (within sendBroadcast function) for object: ' + hexlify(inventoryHash)) queues.invQueue.put((streamNumber, inventoryHash)) @@ -830,6 +834,7 @@ class singleWorker(threading.Thread, StoppableThread): objectType = 2 Inventory()[inventoryHash] = ( objectType, toStreamNumber, encryptedPayload, embeddedTime, '') + PendingUpload().add(inventoryHash) if BMConfigParser().has_section(toaddress) or not protocol.checkBitfield(behaviorBitfield, protocol.BITFIELD_DOESACK): queues.UISignalQueue.put(('updateSentItemStatusByAckdata', (ackdata, tr._translate("MainWindow", "Message sent. Sent at %1").arg(l10n.formatTimestamp())))) else: @@ -936,6 +941,7 @@ class singleWorker(threading.Thread, StoppableThread): objectType = 1 Inventory()[inventoryHash] = ( objectType, streamNumber, payload, embeddedTime, '') + PendingUpload().add(inventoryHash) logger.info('sending inv (for the getpubkey message)') queues.invQueue.put((streamNumber, inventoryHash)) diff --git a/src/depends.py b/src/depends.py index 04656530..d66663b1 100755 --- a/src/depends.py +++ b/src/depends.py @@ -93,7 +93,7 @@ def check_openssl(): import os.path paths.insert(0, os.path.join(sys._MEIPASS, 'libeay32.dll')) else: - paths = ['libcrypto.so', 'libcrypto.so.1.0.0'] + paths = ['libcrypto.so'] if sys.platform == 'darwin': paths.extend([ 'libcrypto.dylib', diff --git a/src/inventory.py b/src/inventory.py index 7432b0f1..598021fb 100644 --- a/src/inventory.py +++ b/src/inventory.py @@ -1,4 +1,12 @@ +import collections +from importlib import import_module +from threading import current_thread, enumerate as threadingEnumerate, RLock +import Queue +import time +import sys + from bmconfigparser import BMConfigParser +from helper_sql import * from singleton import Singleton # TODO make this dynamic, and watch out for frozen, like with messagetypes @@ -10,7 +18,10 @@ class Inventory(): def __init__(self): #super(self.__class__, self).__init__() self._moduleName = BMConfigParser().safeGet("inventory", "storage") - self._inventoryClass = getattr(getattr(storage, self._moduleName), "{}Inventory".format(self._moduleName.title())) + #import_module("." + self._moduleName, "storage") + #import_module("storage." + self._moduleName) + self._className = "storage." + self._moduleName + "." + self._moduleName.title() + "Inventory" + self._inventoryClass = eval(self._className) self._realInventory = self._inventoryClass() self.numberOfInventoryLookupsPerformed = 0 @@ -24,3 +35,164 @@ class Inventory(): raise AttributeError("%s instance has no attribute '%s'" %(self.__class__.__name__, attr)) else: return realRet + + +class PendingDownloadQueue(Queue.Queue): +# keep a track of objects that have been advertised to us but we haven't downloaded them yet + maxWait = 300 + + def __init__(self, maxsize=0): + Queue.Queue.__init__(self, maxsize) + self.stopped = False + self.pending = {} + self.lock = RLock() + + def task_done(self, hashId): + Queue.Queue.task_done(self) + try: + with self.lock: + del self.pending[hashId] + except KeyError: + pass + + def get(self, block=True, timeout=None): + retval = Queue.Queue.get(self, block, timeout) + # no exception was raised + if not self.stopped: + with self.lock: + self.pending[retval] = time.time() + return retval + + def clear(self): + with self.lock: + newPending = {} + for hashId in self.pending: + if self.pending[hashId] + PendingDownloadQueue.maxWait > time.time(): + newPending[hashId] = self.pending[hashId] + self.pending = newPending + + @staticmethod + def totalSize(): + size = 0 + for thread in threadingEnumerate(): + if thread.isAlive() and hasattr(thread, 'downloadQueue'): + size += thread.downloadQueue.qsize() + len(thread.downloadQueue.pending) + return size + + @staticmethod + def stop(): + for thread in threadingEnumerate(): + if thread.isAlive() and hasattr(thread, 'downloadQueue'): + thread.downloadQueue.stopped = True + with thread.downloadQueue.lock: + thread.downloadQueue.pending = {} + + +class PendingUploadDeadlineException(Exception): + pass + + +@Singleton +class PendingUpload(object): +# keep a track of objects that we have created but haven't distributed yet + def __init__(self): + super(self.__class__, self).__init__() + self.lock = RLock() + self.hashes = {} + # end by this time in any case + self.deadline = 0 + self.maxLen = 0 + # during shutdown, wait up to 20 seconds to finish uploading + self.shutdownWait = 20 + # forget tracking objects after 60 seconds + self.objectWait = 60 + # wait 10 seconds between clears + self.clearDelay = 10 + self.lastCleared = time.time() + + def add(self, objectHash = None): + with self.lock: + # add a new object into existing thread lists + if objectHash: + if objectHash not in self.hashes: + self.hashes[objectHash] = {'created': time.time(), 'sendCount': 0, 'peers': []} + for thread in threadingEnumerate(): + if thread.isAlive() and hasattr(thread, 'peer') and \ + thread.peer not in self.hashes[objectHash]['peers']: + self.hashes[objectHash]['peers'].append(thread.peer) + # add all objects into the current thread + else: + for objectHash in self.hashes: + if current_thread().peer not in self.hashes[objectHash]['peers']: + self.hashes[objectHash]['peers'].append(current_thread().peer) + + def len(self): + self.clearHashes() + with self.lock: + return sum(1 + for x in self.hashes if (self.hashes[x]['created'] + self.objectWait < time.time() or + self.hashes[x]['sendCount'] == 0)) + + def _progress(self): + with self.lock: + return float(sum(len(self.hashes[x]['peers']) + for x in self.hashes if (self.hashes[x]['created'] + self.objectWait < time.time()) or + self.hashes[x]['sendCount'] == 0)) + + def progress(self, raiseDeadline=True): + if self.maxLen < self._progress(): + self.maxLen = self._progress() + if self.deadline < time.time(): + if self.deadline > 0 and raiseDeadline: + raise PendingUploadDeadlineException + self.deadline = time.time() + 20 + try: + return 1.0 - self._progress() / self.maxLen + except ZeroDivisionError: + return 1.0 + + def clearHashes(self, objectHash=None): + if objectHash is None: + if self.lastCleared > time.time() - self.clearDelay: + return + objects = self.hashes.keys() + else: + objects = objectHash, + with self.lock: + for i in objects: + try: + if self.hashes[i]['sendCount'] > 0 and ( + len(self.hashes[i]['peers']) == 0 or + self.hashes[i]['created'] + self.objectWait < time.time()): + del self.hashes[i] + except KeyError: + pass + self.lastCleared = time.time() + + def delete(self, objectHash=None): + if not hasattr(current_thread(), 'peer'): + return + if objectHash is None: + return + with self.lock: + try: + if objectHash in self.hashes and current_thread().peer in self.hashes[objectHash]['peers']: + self.hashes[objectHash]['sendCount'] += 1 + self.hashes[objectHash]['peers'].remove(current_thread().peer) + except KeyError: + pass + self.clearHashes(objectHash) + + def stop(self): + with self.lock: + self.hashes = {} + + def threadEnd(self): + with self.lock: + for objectHash in self.hashes: + try: + if current_thread().peer in self.hashes[objectHash]['peers']: + self.hashes[objectHash]['peers'].remove(current_thread().peer) + except KeyError: + pass + self.clearHashes() diff --git a/src/messagetypes/__init__.py b/src/messagetypes/__init__.py index 06783eac..1a5223df 100644 --- a/src/messagetypes/__init__.py +++ b/src/messagetypes/__init__.py @@ -3,7 +3,6 @@ from os import path, listdir from string import lower from debug import logger -import messagetypes import paths class MsgBase(object): @@ -16,8 +15,9 @@ def constructObject(data): if data[""] not in whitelist: return None try: - classBase = getattr(getattr(messagetypes, data[""]), data[""].title()) - except (NameError, AttributeError): + m = import_module("messagetypes." + data[""]) + classBase = getattr(m, data[""].title()) + except (NameError, ImportError): logger.error("Don't know how to handle message type: \"%s\"", data[""], exc_info=True) return None try: @@ -43,7 +43,7 @@ else: if splitted[1] != ".py": continue try: - import_module(".{}".format(splitted[0]), "messagetypes") + import_module("." + splitted[0], "messagetypes") except ImportError: logger.error("Error importing %s", mod, exc_info=True) else: diff --git a/src/network/advanceddispatcher.py b/src/network/advanceddispatcher.py index d426dbe8..6f857398 100644 --- a/src/network/advanceddispatcher.py +++ b/src/network/advanceddispatcher.py @@ -7,12 +7,6 @@ from debug import logger from helper_threading import BusyError, nonBlocking import state -class ProcessingError(Exception): - pass - -class UnknownStateError(ProcessingError): - pass - class AdvancedDispatcher(asyncore.dispatcher): _buf_len = 131072 # 128kB @@ -64,13 +58,11 @@ class AdvancedDispatcher(asyncore.dispatcher): break if len(self.read_buf) < self.expectBytes: return False - try: - cmd = getattr(self, "state_" + str(self.state)) - except AttributeError: - logger.error("Unknown state %s", self.state, exc_info=True) - raise UnknownState(self.state) - if not cmd(): + if not getattr(self, "state_" + str(self.state))(): break + except AttributeError: + logger.error("Unknown state %s", self.state, exc_info=True) + raise except BusyError: return False return False diff --git a/src/network/objectracker.py b/src/network/objectracker.py index ff2a9036..66b0685b 100644 --- a/src/network/objectracker.py +++ b/src/network/objectracker.py @@ -54,7 +54,8 @@ class ObjectTracker(object): def clean(self): if self.lastCleaned < time.time() - ObjectTracker.invCleanPeriod: if haveBloom: - if len(missingObjects) == 0: + # FIXME + if PendingDownloadQueue().size() == 0: self.initInvBloom() self.initAddrBloom() else: diff --git a/src/network/proxy.py b/src/network/proxy.py index 1d7ca357..43298f63 100644 --- a/src/network/proxy.py +++ b/src/network/proxy.py @@ -3,7 +3,6 @@ import time from advanceddispatcher import AdvancedDispatcher import asyncore_pollchoose as asyncore -from bmconfigparser import BMConfigParser from debug import logger import network.connectionpool import state @@ -88,11 +87,6 @@ class Proxy(AdvancedDispatcher): self.isOutbound = True self.fullyEstablished = False self.create_socket(socket.AF_INET, socket.SOCK_STREAM) - if BMConfigParser().safeGetBoolean("bitmessagesettings", "socksauthentication"): - self.auth = (BMConfigParser().safeGet("bitmessagesettings", "socksusername"), - BMConfigParser().safeGet("bitmessagesettings", "sockspassword")) - else: - self.auth = None if address.host.endswith(".onion") and self.onion_proxy is not None: self.connect(self.onion_proxy) else: diff --git a/src/network/receivequeuethread.py b/src/network/receivequeuethread.py index 0a7562cb..5399b972 100644 --- a/src/network/receivequeuethread.py +++ b/src/network/receivequeuethread.py @@ -12,7 +12,6 @@ from helper_threading import StoppableThread from inventory import Inventory from network.connectionpool import BMConnectionPool from network.bmproto import BMProto -from network.advanceddispatcher import UnknownStateError from queues import receiveDataQueue import protocol import state @@ -41,21 +40,14 @@ class ReceiveQueueThread(threading.Thread, StoppableThread): # or the connection is to be aborted try: - connection = BMConnectionPool().getConnectionByAddr(dest) + BMConnectionPool().getConnectionByAddr(dest).process() # KeyError = connection object not found - except KeyError: - receiveDataQueue.task_done() - continue - try: - connection.process() - # UnknownStateError = state isn't implemented - except (UnknownStateError): + # AttributeError = state isn't implemented + except (KeyError, AttributeError): pass except socket.error as err: if err.errno == errno.EBADF: - connection.set_state("close", 0) + BMConnectionPool().getConnectionByAddr(dest).set_state("close", 0) else: logger.error("Socket error: %s", str(err)) - except: - logger.error("Error processing", exc_info=True) receiveDataQueue.task_done() diff --git a/src/network/socks5.py b/src/network/socks5.py index 52136bdc..52050ec9 100644 --- a/src/network/socks5.py +++ b/src/network/socks5.py @@ -39,7 +39,7 @@ class Socks5(Proxy): return True def state_auth_1(self): - ret = struct.unpack('BB', self.read_buf[:2]) + ret = struct.unpack('BB', self.read_buf) if ret[0] != 5: # general error raise GeneralProxyError(1) diff --git a/src/plugins/menu_qrcode.py b/src/plugins/menu_qrcode.py deleted file mode 100644 index 3831e89b..00000000 --- a/src/plugins/menu_qrcode.py +++ /dev/null @@ -1,83 +0,0 @@ -# -*- coding: utf-8 -*- -""" -A menu plugin showing QR-Code for bitmessage address in modal dialog. -""" - -from PyQt4 import QtGui, QtCore -import qrcode - -from pybitmessage.tr import _translate - - -# http://stackoverflow.com/questions/20452486 -class Image(qrcode.image.base.BaseImage): - """Image output class for qrcode using QPainter""" - def __init__(self, border, width, box_size): - self.border = border - self.width = width - self.box_size = box_size - size = (width + border * 2) * box_size - self._image = QtGui.QImage( - size, size, QtGui.QImage.Format_RGB16) - self._image.fill(QtCore.Qt.white) - - def pixmap(self): - """Get image pixmap""" - return QtGui.QPixmap.fromImage(self._image) - - def drawrect(self, row, col): - """Draw a single rectangle - implementation""" - painter = QtGui.QPainter(self._image) - painter.fillRect( - (col + self.border) * self.box_size, - (row + self.border) * self.box_size, - self.box_size, self.box_size, - QtCore.Qt.black) - - -class QRCodeDialog(QtGui.QDialog): - """The dialog""" - def __init__(self, parent): - super(QRCodeDialog, self).__init__(parent) - self.image = QtGui.QLabel(self) - self.label = QtGui.QLabel(self) - font = QtGui.QFont() - font.setBold(True) - font.setWeight(75) - self.label.setFont(font) - self.label.setAlignment( - QtCore.Qt.AlignCenter | QtCore.Qt.AlignVCenter) - buttonBox = QtGui.QDialogButtonBox(self) - buttonBox.setOrientation(QtCore.Qt.Horizontal) - buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Ok) - buttonBox.accepted.connect(self.accept) - layout = QtGui.QVBoxLayout(self) - layout.addWidget(self.image) - layout.addWidget(self.label) - layout.addWidget(buttonBox) - self.retranslateUi() - - def retranslateUi(self): - """A conventional Qt Designer method for dynamic l10n""" - self.setWindowTitle(_translate("QRCodeDialog", "QR-code")) - - def render(self, text): - """Draw QR-code and address in labels""" - self.label.setText(text) - self.image.setPixmap( - qrcode.make(text, image_factory=Image).pixmap()) - self.setFixedSize(QtGui.QWidget.sizeHint(self)) - - -def connect_plugin(form): - """Plugin entry point""" - def on_action_ShowQR(): - """A slot for popup menu action""" - try: - dialog = form.qrcode_dialog - except AttributeError: - form.qrcode_dialog = dialog = QRCodeDialog(form) - dialog.render('bitmessage:' + str(form.getCurrentAccount())) - dialog.exec_() - - return on_action_ShowQR, _translate("MainWindow", "Show QR-code") diff --git a/src/plugins/qrcodeui.py b/src/plugins/qrcodeui.py new file mode 100644 index 00000000..25b1e0b1 --- /dev/null +++ b/src/plugins/qrcodeui.py @@ -0,0 +1,101 @@ +# -*- coding: utf-8 -*- + +from PyQt4 import QtGui, QtCore +import qrcode + +from pybitmessage.tr import translateText + +try: + _fromUtf8 = QtCore.QString.fromUtf8 +except AttributeError: + _fromUtf8 = lambda s: s + + +# http://stackoverflow.com/questions/20452486 +class Image(qrcode.image.base.BaseImage): + def __init__(self, border, width, box_size): + self.border = border + self.width = width + self.box_size = box_size + size = (width + border * 2) * box_size + self._image = QtGui.QImage( + size, size, QtGui.QImage.Format_RGB16) + self._image.fill(QtCore.Qt.white) + + def pixmap(self): + return QtGui.QPixmap.fromImage(self._image) + + def drawrect(self, row, col): + painter = QtGui.QPainter(self._image) + painter.fillRect( + (col + self.border) * self.box_size, + (row + self.border) * self.box_size, + self.box_size, self.box_size, + QtCore.Qt.black) + + def save(self, stream, kind=None): + pass + + +class Ui_qrcodeDialog(object): + def setupUi(self, qrcodeDialog): + qrcodeDialog.setObjectName(_fromUtf8("qrcodeDialog")) + self.image = QtGui.QLabel(qrcodeDialog) + self.label = QtGui.QLabel(qrcodeDialog) + font = QtGui.QFont() + font.setBold(True) + font.setWeight(75) + self.label.setFont(font) + self.label.setAlignment( + QtCore.Qt.AlignCenter | QtCore.Qt.AlignVCenter) + self.buttonBox = QtGui.QDialogButtonBox(qrcodeDialog) + self.buttonBox.setOrientation(QtCore.Qt.Horizontal) + self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Ok) + layout = QtGui.QVBoxLayout(qrcodeDialog) + layout.addWidget(self.image) + layout.addWidget(self.label) + layout.addWidget(self.buttonBox) + + self.retranslateUi(qrcodeDialog) + QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL( + _fromUtf8("accepted()")), qrcodeDialog.accept) + QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL( + _fromUtf8("rejected()")), qrcodeDialog.reject) + QtCore.QMetaObject.connectSlotsByName(qrcodeDialog) + + def retranslateUi(self, qrcodeDialog): + qrcodeDialog.setWindowTitle(QtGui.QApplication.translate( + "qrcodeDialog", "QR-code", + None, QtGui.QApplication.UnicodeUTF8 + )) + + def render(self, text): + self.label.setText(text) + self.image.setPixmap( + qrcode.make(text, image_factory=Image).pixmap()) + + +class qrcodeDialog(QtGui.QDialog): + + def __init__(self, parent): + QtGui.QWidget.__init__(self, parent) + self.ui = Ui_qrcodeDialog() + self.ui.setupUi(self) + self.parent = parent + QtGui.QWidget.resize(self, QtGui.QWidget.sizeHint(self)) + + +def connect_plugin(form): + def on_action_ShowQR(): + form.qrcodeDialogInstance = qrcodeDialog(form) + form.qrcodeDialogInstance.ui.render( + str(form.getCurrentAccount()) + ) + form.qrcodeDialogInstance.exec_() + + form.actionShowQRCode = \ + form.ui.addressContextMenuToolbarYourIdentities.addAction( + translateText("MainWindow", "Show QR-code"), + on_action_ShowQR + ) + form.popMenuYourIdentities.addAction(form.actionShowQRCode) diff --git a/src/pyelliptic/openssl.py b/src/pyelliptic/openssl.py index 115bdc08..7af4fd18 100644 --- a/src/pyelliptic/openssl.py +++ b/src/pyelliptic/openssl.py @@ -534,8 +534,6 @@ def loadOpenSSL(): else: libdir.append('libcrypto.so') libdir.append('libssl.so') - libdir.append('libcrypto.so.1.0.0') - libdir.append('libssl.so.1.0.0') if 'linux' in sys.platform or 'darwin' in sys.platform or 'bsd' in sys.platform: libdir.append(find_library('ssl')) elif 'win32' in sys.platform or 'win64' in sys.platform: diff --git a/src/throttle.py b/src/throttle.py new file mode 100644 index 00000000..6e53f217 --- /dev/null +++ b/src/throttle.py @@ -0,0 +1,81 @@ +import math +import threading +import time + +from bmconfigparser import BMConfigParser +from singleton import Singleton +import state + +class Throttle(object): + minChunkSize = 4096 + maxChunkSize = 131072 + + def __init__(self, limit=0): + self.limit = limit + self.speed = 0 + self.chunkSize = Throttle.maxChunkSize + self.txTime = int(time.time()) + self.txLen = 0 + self.total = 0 + self.timer = threading.Event() + self.lock = threading.RLock() + self.resetChunkSize() + + def recalculate(self): + with self.lock: + now = int(time.time()) + if now > self.txTime: + self.speed = self.txLen / (now - self.txTime) + self.txLen -= self.limit * (now - self.txTime) + self.txTime = now + if self.txLen < 0 or self.limit == 0: + self.txLen = 0 + + def wait(self, dataLen): + with self.lock: + self.txLen += dataLen + self.total += dataLen + while state.shutdown == 0: + self.recalculate() + if self.limit == 0: + break + if self.txLen < self.limit: + break + self.timer.wait(0.2) + + def getSpeed(self): + self.recalculate() + return self.speed + + def resetChunkSize(self): + with self.lock: + # power of two smaller or equal to speed limit + try: + self.chunkSize = int(math.pow(2, int(math.log(self.limit,2)))) + except ValueError: + self.chunkSize = Throttle.maxChunkSize + # range check + if self.chunkSize < Throttle.minChunkSize: + self.chunkSize = Throttle.minChunkSize + elif self.chunkSize > Throttle.maxChunkSize: + self.chunkSize = Throttle.maxChunkSize + +@Singleton +class SendThrottle(Throttle): + def __init__(self): + Throttle.__init__(self, BMConfigParser().safeGetInt('bitmessagesettings', 'maxuploadrate')*1024) + + def resetLimit(self): + with self.lock: + self.limit = BMConfigParser().safeGetInt('bitmessagesettings', 'maxuploadrate')*1024 + Throttle.resetChunkSize(self) + +@Singleton +class ReceiveThrottle(Throttle): + def __init__(self): + Throttle.__init__(self, BMConfigParser().safeGetInt('bitmessagesettings', 'maxdownloadrate')*1024) + + def resetLimit(self): + with self.lock: + self.limit = BMConfigParser().safeGetInt('bitmessagesettings', 'maxdownloadrate')*1024 + Throttle.resetChunkSize(self) diff --git a/src/translations/bitmessage.pro b/src/translations/bitmessage.pro index ed491b3d..f5d6b946 100644 --- a/src/translations/bitmessage.pro +++ b/src/translations/bitmessage.pro @@ -1,8 +1,12 @@ SOURCES = ../addresses.py\ ../bitmessagemain.py\ ../class_addressGenerator.py\ + ../class_outgoingSynSender.py\ ../class_objectProcessor.py\ + ../class_receiveDataThread.py\ + ../class_sendDataThread.py\ ../class_singleCleaner.py\ + ../class_singleListener.py\ ../class_singleWorker.py\ ../class_sqlThread.py\ ../helper_bitcoin.py\ diff --git a/src/translations/bitmessage_eo.qm b/src/translations/bitmessage_eo.qm index fa6a1a96..ea03b1b5 100644 Binary files a/src/translations/bitmessage_eo.qm and b/src/translations/bitmessage_eo.qm differ diff --git a/src/translations/bitmessage_eo.ts b/src/translations/bitmessage_eo.ts index de853696..beff4aca 100644 --- a/src/translations/bitmessage_eo.ts +++ b/src/translations/bitmessage_eo.ts @@ -60,27 +60,27 @@ @mailchuck.com - + Registration failed: Registrado malsukcesis: - + The requested email address is not available, please try a new one. La dezirata retpoŝtadreso ne estas disponebla, bonvolu provi alian. - + Sending email gateway registration request Sendado de peto pri registrado ĉe retpoŝta kluzo - + Sending email gateway unregistration request Sendado de peto pri malregistrado de retpoŝta kluzo - + Sending email gateway status request Sendado de peto pri stato de retpoŝta kluzo @@ -195,52 +195,52 @@ Please type the desired email address (including @mailchuck.com) below: MainWindow - + Reply to sender Respondi al sendinto - + Reply to channel Respondi al kanalo - + Add sender to your Address Book Aldoni sendinton al via adresaro - + Add sender to your Blacklist Aldoni sendinton al via nigra listo - + Move to Trash Movi al rubujo - + Undelete Malforigi - + View HTML code as formatted text Montri HTML-n kiel aranĝitan tekston - + Save message as... Konservi mesaĝon kiel… - + Mark Unread Marki kiel nelegitan - + New Nova @@ -265,12 +265,12 @@ Please type the desired email address (including @mailchuck.com) below: Kopii adreson al tondejo - + Special address behavior... Speciala sinteno de adreso… - + Email gateway Retpoŝta kluzo @@ -280,37 +280,37 @@ Please type the desired email address (including @mailchuck.com) below: Forigi - + Send message to this address Sendi mesaĝon al tiu adreso - + Subscribe to this address Aboni tiun adreson - + Add New Address Aldoni novan adreson - + Copy destination address to clipboard Kopii cel-adreson al tondejo - + Force send Devigi sendadon - + One of your addresses, %1, is an old version 1 address. Version 1 addresses are no longer supported. May we delete it now? Iu de viaj adresoj, %1, estas malnova versio 1 adreso. Versioj 1 adresoj ne estas jam subtenataj. Ĉu ni povas forigi ĝin? - + Waiting for their encryption key. Will request it again soon. Atendado je ilia ĉifroŝlosilo. Baldaŭ petos ĝin denove. @@ -320,17 +320,17 @@ Please type the desired email address (including @mailchuck.com) below: - + Queued. En atendovico. - + Message sent. Waiting for acknowledgement. Sent at %1 Mesaĝo sendita. Atendado je konfirmo. Sendita je %1 - + Message sent. Sent at %1 Mesaĝo sendita. Sendita je %1 @@ -340,77 +340,77 @@ Please type the desired email address (including @mailchuck.com) below: - + Acknowledgement of the message received %1 Ricevis konfirmon de la mesaĝo je %1 - + Broadcast queued. Elsendo en atendovico. - + Broadcast on %1 Elsendo je %1 - + Problem: The work demanded by the recipient is more difficult than you are willing to do. %1 Problemo: la demandita laboro de la ricevonto estas pli malfacila ol vi pretas fari. %1 - + Problem: The recipient's encryption key is no good. Could not encrypt message. %1 Problemo: la ĉifroŝlosilo de la ricevonto estas rompita. Ne povis ĉifri la mesaĝon. %1 - + Forced difficulty override. Send should start soon. Devigita superado de limito de malfacilaĵo. Sendado devus baldaŭ komenci. - + Unknown status: %1 %2 Nekonata stato: %1 %2 - + Not Connected Ne konektita - + Show Bitmessage Montri Bitmesaĝon - + Send Sendi - + Subscribe Aboni - + Channel Kanalo - + Quit Eliri - + You may manage your keys by editing the keys.dat file stored in the same directory as this program. It is important that you back up this file. Vi povas administri viajn ŝlosilojn per redakti la dosieron keys.dat en la sama dosierujo kiel tiu programo. Estas grava, ke vi faru sekurkopion de tiu dosiero. - + You may manage your keys by editing the keys.dat file stored in %1 It is important that you back up this file. @@ -419,17 +419,17 @@ It is important that you back up this file. Estas grava, ke vi faru sekurkopion de tiu dosiero. - + Open keys.dat? Ĉu malfermi keys.dat? - + You may manage your keys by editing the keys.dat file stored in the same directory as this program. It is important that you back up this file. Would you like to open the file now? (Be sure to close Bitmessage before making any changes.) Vi povas administri viajn ŝlosilojn per redakti la dosieron keys.dat en la sama dosierujo kiel tiu programo. Estas grava ke vi faru sekurkopion de tiu dosiero. Ĉu vi volas malfermi la dosieron nun? (Bonvolu certigi ke Bitmesaĝo estas fermita antaŭ fari ŝanĝojn.) - + You may manage your keys by editing the keys.dat file stored in %1 It is important that you back up this file. Would you like to open the file now? (Be sure to close Bitmessage before making any changes.) @@ -438,37 +438,37 @@ It is important that you back up this file. Would you like to open the file now? Estas grava, ke vi faru sekurkopion de tiu dosiero. Ĉu vi volas malfermi la dosieron nun? (Bonvolu certigi ke Bitmesaĝo estas fermita antaŭ fari ŝanĝojn.) - + Delete trash? Ĉu malplenigi rubujon? - + Are you sure you want to delete all trashed messages? Ĉu vi certe volas forviŝi ĉiujn mesaĝojn el la rubujo? - + bad passphrase malprava pasvorto - + You must type your passphrase. If you don't have one then this is not the form for you. Vi devas tajpi vian pasvorton. Se vi ne havas pasvorton, tiu ĉi ne estas la prava formularo por vi. - + Bad address version number Erara numero de adresversio - + Your address version number must be a number: either 3 or 4. Via numero de adresversio devas esti: aŭ 3 aŭ 4. - + Your address version number must be either 3 or 4. Via numero de adresversio devas esti: aŭ 3 aŭ 4. @@ -538,22 +538,22 @@ Estas grava, ke vi faru sekurkopion de tiu dosiero. Ĉu vi volas malfermi la dos - + Connection lost Perdis konekton - + Connected Konektita - + Message trashed Movis mesaĝon al rubujo - + The TTL, or Time-To-Live is the length of time that the network will hold the message. The recipient must get it during this time. If your Bitmessage client does not hear an acknowledgement, it will resend the message automatically. The longer the Time-To-Live, the @@ -561,17 +561,17 @@ Estas grava, ke vi faru sekurkopion de tiu dosiero. Ĉu vi volas malfermi la dos La vivdaŭro signifas ĝis kiam la reto tenos la mesaĝon. La ricevonto devos elŝuti ĝin dum tiu tempo. Se via bitmesaĝa kliento ne ricevos konfirmon, ĝi resendos mesaĝon aŭtomate. Ju pli longa vivdaŭro, des pli laboron via komputilo bezonos fari por sendi mesaĝon. Vivdaŭro proksimume kvin aŭ kvar horoj estas ofte konvena. - + Message too long Mesaĝo tro longa - + The message that you are trying to send is too long by %1 bytes. (The maximum is 261644 bytes). Please cut it down before sending. La mesaĝon kiun vi provis sendi estas tro longa je %1 bitokoj. (La maksimumo estas 261644 bitokoj.) Bonvolu mallongigi ĝin antaŭ sendado. - + Error: Your account wasn't registered at an email gateway. Sending registration now as %1, please wait for the registration to be processed before retrying sending. Eraro: Via konto ne estas registrita je retpoŝta kluzo. Registranta nun kiel %1, bonvolu atendi ĝis la registrado finos antaŭ vi reprovos sendi iun ajn. @@ -616,57 +616,57 @@ Estas grava, ke vi faru sekurkopion de tiu dosiero. Ĉu vi volas malfermi la dos - + Error: You must specify a From address. If you don't have one, go to the 'Your Identities' tab. Eraro: Vi devas elekti sendontan adreson. Se vi ne havas iun, iru al langeto 'Viaj identigoj'. - + Address version number Numero de adresversio - + Concerning the address %1, Bitmessage cannot understand address version numbers of %2. Perhaps upgrade Bitmessage to the latest version. Dum prilaborado de adreso adreso %1, Bitmesaĝo ne povas kompreni numerojn %2 de adresversioj. Eble ĝisdatigu Bitmesaĝon al la plej nova versio. - + Stream number Fluo numero - + Concerning the address %1, Bitmessage cannot handle stream numbers of %2. Perhaps upgrade Bitmessage to the latest version. Dum prilaborado de adreso %1, Bitmesaĝo ne povas priservi %2 fluojn numerojn. Eble ĝisdatigu Bitmesaĝon al la plej nova versio. - + Warning: You are currently not connected. Bitmessage will do the work necessary to send the message but it won't send until you connect. Atentu: Vi ne estas nun konektita. Bitmesaĝo faros necesan laboron por sendi mesaĝon, tamen ĝi ne sendos ĝin antaŭ vi konektos. - + Message queued. Mesaĝo envicigita. - + Your 'To' field is empty. Via "Ricevonto"-kampo malplenas. - + Right click one or more entries in your address book and select 'Send message to this address'. Dekstre alklaku kelka(j)n elemento(j)n en via adresaro kaj elektu 'Sendi mesaĝon al tiu adreso'. - + Fetched address from namecoin identity. Venigis adreson de namecoin-a identigo. - + New Message Nova mesaĝo @@ -691,47 +691,47 @@ Estas grava, ke vi faru sekurkopion de tiu dosiero. Ĉu vi volas malfermi la dos La adreso kiun vi enmetis estas malĝusta. Ignoras ĝin. - + Error: You cannot add the same address to your address book twice. Try renaming the existing one if you want. Eraro: Vi ne povas duoble aldoni la saman adreson al via adresaro. Provu renomi la ekzistan se vi volas. - + Error: You cannot add the same address to your subscriptions twice. Perhaps rename the existing one if you want. Eraro: Vi ne povas aldoni duoble la saman adreson al viaj abonoj. Eble renomi la ekzistan se vi volas. - + Restart Restartigi - + You must restart Bitmessage for the port number change to take effect. Vi devas restartigi Bitmesaĝon por ke la ŝanĝo de la numero de pordo (Port Number) efektivigu. - + Bitmessage will use your proxy from now on but you may want to manually restart Bitmessage now to close existing connections (if any). Bitmesaĝo uzos retperanton (proxy) ekde nun, sed eble vi volas permane restartigi Bitmesaĝon nun, por ke ĝi fermu eblajn ekzistajn konektojn. - + Number needed Numero bezonata - + Your maximum download and upload rate must be numbers. Ignoring what you typed. Maksimumaj elŝutrapido kaj alŝutrapido devas esti numeroj. Ignoras kion vi enmetis. - + Will not resend ever Resendos neniam - + Note that the time limit you entered is less than the amount of time Bitmessage waits for the first resend attempt therefore your messages will never be resent. Rigardu, ke la templimon vi enmetis estas pli malgrandan ol tempo dum kiu Bitmesaĝo atendas por resendi unuafoje, do viaj mesaĝoj estos senditaj neniam. @@ -766,22 +766,22 @@ Estas grava, ke vi faru sekurkopion de tiu dosiero. Ĉu vi volas malfermi la dos Vi ja vere bezonas pasfrazon. - + Address is gone Adreso foriris - + Bitmessage cannot find your address %1. Perhaps you removed it? Bitmesaĝo ne povas trovi vian adreson %1. Ĉu eble vi forviŝis ĝin? - + Address disabled Adreso malŝaltita - + Error: The address from which you are trying to send is disabled. You'll have to enable it on the 'Your Identities' tab before using it. Eraro: La adreso kun kiu vi provas sendi estas malŝaltita. Vi devos ĝin ŝalti en la langeto 'Viaj identigoj' antaŭ uzi ĝin. @@ -791,42 +791,42 @@ Estas grava, ke vi faru sekurkopion de tiu dosiero. Ĉu vi volas malfermi la dos - + Entry added to the blacklist. Edit the label to your liking. Aldonis elementon al la nigra listo. Redaktu la etikedon laŭvole. - + Error: You cannot add the same address to your blacklist twice. Try renaming the existing one if you want. Eraro: Vi ne povas duoble aldoni la saman adreson al via nigra listo. Provu renomi la jaman se vi volas. - + Moved items to trash. Movis elementojn al rubujo. - + Undeleted item. Malforigis elementon. - + Save As... Konservi kiel… - + Write error. Skriberaro. - + No addresses selected. Neniu adreso elektita. - + If you delete the subscription, messages that you already received will become inaccessible. Maybe you can consider disabling the subscription instead. Disabled subscriptions will not receive new messages, but you can still view messages you already received. Are you sure you want to delete the subscription? @@ -835,7 +835,7 @@ Are you sure you want to delete the subscription? Ĉu vi certe volas forigi la abonon? - + If you delete the channel, messages that you already received will become inaccessible. Maybe you can consider disabling the channel instead. Disabled channels will not receive new messages, but you can still view messages you already received. Are you sure you want to delete the channel? @@ -844,32 +844,32 @@ Are you sure you want to delete the channel? Ĉu vi certe volas forigi la kanalon? - + Do you really want to remove this avatar? Ĉu vi certe volas forviŝi tiun ĉi avataron? - + You have already set an avatar for this address. Do you really want to overwrite it? Vi jam agordis avataron por tiu ĉi adreso. Ĉu vi vere volas superskribi ĝin? - + Start-on-login not yet supported on your OS. Starto-dum-ensaluto ne estas ankoraŭ ebla en via operaciumo. - + Minimize-to-tray not yet supported on your OS. Plejetigo al taskopleto ne estas ankoraŭ ebla en via operaciumo. - + Tray notifications not yet supported on your OS. Taskopletaj sciigoj ne estas ankoraŭ eblaj en via operaciumo. - + Testing... Testado… @@ -934,192 +934,192 @@ Are you sure you want to delete the channel? - + Bitmessage Bitmesaĝo - + Identities Identigoj - + New Identity Nova identigo - + Search Serĉi - + All Ĉio - + To Al - + From De - + Subject Temo - + Message Mesaĝo - + Received Ricevita je - + Messages Mesaĝoj - + Address book Etikedo - + Address Adreso - + Add Contact Aldoni kontakton - + Fetch Namecoin ID Venigi Namecoin ID - + Subject: Temo: - + From: De: - + To: Al: - + Send ordinary Message Sendi ordinaran mesaĝon - + Send Message to your Subscribers Sendi mesaĝon al viaj abonantoj - + TTL: Vivdaŭro: - + Subscriptions Abonoj - + Add new Subscription Aldoni novan abonon - + Chans Kanaloj - + Add Chan Aldoni kanalon - + File Dosiero - + Settings Agordoj - + Help Helpo - + Import keys Enporti ŝlosilojn - + Manage keys Administri ŝlosilojn - + Ctrl+Q Stir+Q - + F1 F1 - + Contact support Peti pri helpo - + About Pri - + Regenerate deterministic addresses Regeneri antaŭkalkuleblan adreson - + Delete all trashed messages Forviŝi ĉiujn mesaĝojn el rubujo - + Join / Create chan - Anigi / krei kanalon + Aniĝi / Krei kanalon - + All accounts Ĉiuj kontoj @@ -1139,67 +1139,67 @@ Are you sure you want to delete the channel? Aldoni novan elementon - + Display the %1 recent broadcast(s) from this address. - + Montri %1 lasta(j)n elsendo(j)n de tiu ĉi adreso. - + New version of PyBitmessage is available: %1. Download it from https://github.com/Bitmessage/PyBitmessage/releases/latest La nova versio de PyBitmessage estas disponebla: %1. Elŝutu ĝin de https://github.com/Bitmessage/PyBitmessage/releases/latest - + Waiting for PoW to finish... %1% Atendado ĝis laborpruvo finiĝos… %1% - + Shutting down Pybitmessage... %1% Fermado de PyBitmessage… %1% - + Waiting for objects to be sent... %1% Atendado ĝis objektoj estos senditaj… %1% - + Saving settings... %1% Konservado de agordoj… %1% - + Shutting down core... %1% Fermado de kerno… %1% - + Stopping notifications... %1% Haltigado de sciigoj… %1% - + Shutdown imminent... %1% Fermado tuj… %1% - + %n hour(s) %n horo%n horoj - + %n day(s) %n tago%n tagoj - + Shutting down PyBitmessage... %1% Fermado de PyBitmessage… %1% - + Sent Senditaj @@ -1303,7 +1303,7 @@ Ricevonto postulas malfacilaĵon: %1 kaj %2 Eraro: Vi provis sendi mesaĝon al vi mem aŭ al kanalo, tamen via ĉifroŝlosilo ne estas trovebla en la dosiero keys.dat. Mesaĝo ne povis esti ĉifrita. %1 - + Doing work necessary to send message. Kalkulado de laborpruvo, kiu endas por sendi mesaĝon. @@ -1313,7 +1313,7 @@ Ricevonto postulas malfacilaĵon: %1 kaj %2 Mesaĝo sendita. Atendado je konfirmo. Sendita je %1 - + Doing work necessary to request encryption key. Kalkulado de laborpruvo, kiu endas por peti pri ĉifroŝlosilo. @@ -1338,37 +1338,37 @@ Ricevonto postulas malfacilaĵon: %1 kaj %2 UPnP pord-mapigo forigita - + Mark all messages as read Marki ĉiujn mesaĝojn kiel legitajn - + Are you sure you would like to mark all messages read? Ĉu vi certe volas marki ĉiujn mesaĝojn kiel legitajn? - + Doing work necessary to send broadcast. Kalkulado de laborpruvo, kiu endas por sendi elsendon. - + Proof of work pending Laborpruvo haltigita - + %n object(s) pending proof of work Haltigis laborpruvon por %n objektoHaltigis laborpruvon por %n objektoj - + %n object(s) waiting to be distributed %n objekto atendas je sendato%n objektoj atendas je sendato - + Wait until these tasks finish? Ĉu atendi ĝis tiujn taskojn finos? @@ -1413,37 +1413,32 @@ Ricevonto postulas malfacilaĵon: %1 kaj %2 La nomo %1 ne estas atribuita kun bitmesaĝa adreso. - + Success! Namecoind version %1 running. Sukceso! Namecoind versio %1 funkcias. - + Success! NMControll is up and running. Sukceso! NMControl funkcias ĝuste. - + Couldn't understand NMControl. Ne povis kompreni NMControl. - - - The connection to namecoin failed. - Malsukcesis konekti al namecoin. - Your GPU(s) did not calculate correctly, disabling OpenCL. Please report to the developers. Via(j) vidprocesoro(j) ne kalkulis senerare, malaktiviganta OpenCL. Bonvolu raporti tion al programistoj. - + Set notification sound... Agordi sciigan sonon… - + Welcome to easy and secure Bitmessage * send messages to other people @@ -1457,155 +1452,120 @@ Bonvenon al facila kaj sekura Bitmesaĝo * babili kun aliaj uloj en mesaĝ-kanaloj - + not recommended for chans malkonsilinda por kanaloj - + Quiet Mode Silenta reĝimo - + Problems connecting? Try enabling UPnP in the Network Settings Ĉu problemo kun konektado? Provu aktivigi UPnP en retaj agordoj. - + You are trying to send an email instead of a bitmessage. This requires registering with a gateway. Attempt to register? Vi provas sendi retmesaĝon anstataŭ bitmesaĝ-mesaĝon. Tio ĉi postulas registri ĉe retpoŝta kluzo. Ĉu provi registri? - + Error: Bitmessage addresses start with BM- Please check the recipient address %1 Eraro: bitmesaĝaj adresoj komenciĝas kun BM-. Bonvolu kontroli la adreson de ricevonto %1 - + Error: The recipient address %1 is not typed or copied correctly. Please check it. Eraro: la adreso de ricevonto %1 estas malprave tajpita aŭ kopiita. Bonvolu kontroli ĝin. - + Error: The recipient address %1 contains invalid characters. Please check it. Eraro: la adreso de ricevonto %1 enhavas malpermesatajn simbolojn. Bonvolu kontroli ĝin. - + Error: The version of the recipient address %1 is too high. Either you need to upgrade your Bitmessage software or your acquaintance is being clever. Eraro: la versio de adreso de ricevonto %1 estas tro alta. Eble vi devas ĝisdatigi vian bitmesaĝan programon aŭ via sagaca konato uzas alian programon. - + Error: Some data encoded in the recipient address %1 is too short. There might be something wrong with the software of your acquaintance. Eraro: kelkaj datumoj koditaj en la adreso de ricevonto %1 estas tro mallongaj. Povus esti ke io en la programo de via konato malfunkcias. - + Error: Some data encoded in the recipient address %1 is too long. There might be something wrong with the software of your acquaintance. Eraro: kelkaj datumoj koditaj en la adreso de ricevonto %1 estas tro longaj. Povus esti ke io en la programo de via konato malfunkcias. - + Error: Some data encoded in the recipient address %1 is malformed. There might be something wrong with the software of your acquaintance. Eraro: kelkaj datumoj koditaj en la adreso de ricevonto %1 estas misformitaj. Povus esti ke io en la programo de via konato malfunkcias. - + Error: Something is wrong with the recipient address %1. Eraro: io malĝustas kun la adreso de ricevonto %1. - + Error: %1 Eraro: %1 - + From %1 De %1 - + Synchronisation pending Samtempigado haltigita - + Bitmessage hasn't synchronised with the network, %n object(s) to be downloaded. If you quit now, it may cause delivery delays. Wait until the synchronisation finishes? Bitmesaĝo ne estas samtempigita kun la reto, %n objekto elŝutendas. Se vi eliros nun, tio povas igi malfruiĝojn de liveradoj. Ĉu atendi ĝis la samtempigado finiĝos?Bitmesaĝo ne estas samtempigita kun la reto, %n objektoj elŝutendas. Se vi eliros nun, tio povas igi malfruiĝojn de liveradoj. Ĉu atendi ĝis la samtempigado finiĝos? - + Not connected Nekonektita - + Bitmessage isn't connected to the network. If you quit now, it may cause delivery delays. Wait until connected and the synchronisation finishes? Bitmesaĝo ne estas konektita al la reto. Se vi eliros nun, tio povas igi malfruiĝojn de liveradoj. Ĉu atendi ĝis ĝi konektos kaj la samtempigado finiĝos? - + Waiting for network connection... Atendado je retkonekto… - + Waiting for finishing synchronisation... Atendado ĝis samtempigado finiĝos… - + You have already set a notification sound for this address book entry. Do you really want to overwrite it? Vi jam agordis sciigan sonon por tiu ĉi adreso. Ĉu vi volas anstataŭigi ĝin? - - Error occurred: could not load message from disk. - Eraro okazis: ne povis legi mesaĝon el la disko. - - - - Display the %n recent broadcast(s) from this address. - Montri %n lastan elsendon de tiu ĉi adreso.Montri %n lastajn elsendojn de tiu ĉi adreso. - - - + Go online Konekti - + Go offline Malkonekti - - - Clear - Forviŝi - - - - inbox - Ricevujo - - - - new - novaj - - - - sent - senditaj - - - - trash - rubujo - MessageView @@ -1633,14 +1593,14 @@ Bonvenon al facila kaj sekura Bitmesaĝo MsgDecode - + The message has an unknown encoding. Perhaps you should upgrade Bitmessage. La mesaĝo enhavas nekonatan kodoprezenton. Eble vi devas ĝisdatigi Bitmesaĝon. - + Unknown encoding Nekonata kodoprezento @@ -1796,7 +1756,7 @@ La “hazardnombra” adreso estas antaŭagordita, sed antaŭkalkuleblaj adresoj Nomo de kvazaŭ-dissendlisto: - + This is a chan address. You cannot use it as a pseudo-mailing list. Tio ĉi estas kanaladreso. Vi ne povas ĝin uzi kiel kvazaŭ-dissendolisto. @@ -1819,12 +1779,12 @@ La “hazardnombra” adreso estas antaŭagordita, sed antaŭkalkuleblaj adresoj - + <html><head/><body><p>Distributed under the MIT/X11 software license; see <a href="http://www.opensource.org/licenses/mit-license.php"><span style=" text-decoration: underline; color:#0000ff;">http://www.opensource.org/licenses/mit-license.php</span></a></p></body></html> <html><head/><body><p>Distribuata laŭ la permesilo “MIT/X11 software license”; legu <a href="http://www.opensource.org/licenses/mit-license.php"><span style=" text-decoration: underline; color:#0000ff;">http://www.opensource.org/licenses/mit-license.php</span></a></p></body></html> - + This is Beta software. Tio ĉi estas beta-eldono. @@ -1834,7 +1794,7 @@ La “hazardnombra” adreso estas antaŭagordita, sed antaŭkalkuleblaj adresoj - + <html><head/><body><p>Copyright © 2012-2016 Jonathan Warren<br/>Copyright © 2013-2017 The Bitmessage Developers</p></body></html> <html><head/><body><p>Kopirajto © 2012-2016 Jonathan WARREN<br/>Kopirajto © 2013-2017 La Programistoj de Bitmesaĝo</p></body></html> @@ -2004,27 +1964,27 @@ La “hazardnombra” adreso estas antaŭagordita, sed antaŭkalkuleblaj adresoj - + Since startup on %1 Ekde lanĉo de la programo je %1 - + Down: %1/s Total: %2 Elŝuto: %1/s Sume: %2 - + Up: %1/s Total: %2 Alŝuto: %1/s Sume: %2 - + Total Connections: %1 Ĉiuj konektoj: %1 - + Inventory lookups per second: %1 Petoj pri inventaro en sekundo: %1 @@ -2039,32 +1999,32 @@ La “hazardnombra” adreso estas antaŭagordita, sed antaŭkalkuleblaj adresoj Elŝuto: 0 kB/s - + Network Status - Reto + Reta stato - + byte(s) bitokobitokoj - + Object(s) to be synced: %n Objekto por samtempigi: %nObjektoj por samtempigi: %n - + Processed %n person-to-person message(s). Pritraktis %n inter-personan mesaĝon.Pritraktis %n inter-personajn mesaĝojn. - + Processed %n broadcast message(s). Pritraktis %n elsendon.Pritraktis %n elsendojn. - + Processed %n public key(s). Pritraktis %n publikan ŝlosilon.Pritraktis %n publikajn ŝlosilojn. @@ -2159,7 +2119,7 @@ La “hazardnombra” adreso estas antaŭagordita, sed antaŭkalkuleblaj adresoj Create or join a chan - Krei aŭ anigi kanalon + Krei aŭ aniĝi kanalon @@ -2192,7 +2152,7 @@ La “hazardnombra” adreso estas antaŭagordita, sed antaŭkalkuleblaj adresoj Successfully created / joined chan %1 - Sukcese kreis / anigis al la kanalo %1 + Sukcese kreis / aniĝis al la kanalo %1 @@ -2450,7 +2410,7 @@ La “hazardnombra” adreso estas antaŭagordita, sed antaŭkalkuleblaj adresoj Network Settings - Agordoj de reto + Retaj agordoj diff --git a/src/translations/bitmessage_fr.qm b/src/translations/bitmessage_fr.qm index e544a1c3..742e62d8 100644 Binary files a/src/translations/bitmessage_fr.qm and b/src/translations/bitmessage_fr.qm differ diff --git a/src/translations/bitmessage_fr.ts b/src/translations/bitmessage_fr.ts index becfcbf8..3e64d657 100644 --- a/src/translations/bitmessage_fr.ts +++ b/src/translations/bitmessage_fr.ts @@ -2,17 +2,17 @@ AddAddressDialog - + Add new entry Ajouter une nouvelle entrée - + Label Étiquette - + Address Adresse @@ -20,99 +20,70 @@ EmailGatewayDialog - + Email gateway Passerelle de courriel - + Register on email gateway S’inscrire sur la passerelle de courriel - + Account status at email gateway Statut du compte sur la passerelle de courriel - + Change account settings at email gateway Changer les paramètres de compte sur la passerelle de courriel - + Unregister from email gateway Se désabonner de la passerelle de courriel - + Email gateway allows you to communicate with email users. Currently, only the Mailchuck email gateway (@mailchuck.com) is available. La passerelle de courriel vous permet de communiquer avec des utilisateurs de courriel. Actuellement, seulement la passerelle de courriel de Mailchuck (@mailchuck.com) est disponible. - + Desired email address (including @mailchuck.com): Adresse de courriel désirée (incluant @mailchuck.com) : - - - @mailchuck.com - @mailchuck.com - - - - Registration failed: - L’inscription a échoué : - - - - The requested email address is not available, please try a new one. - L'adresse électronique demandée n'est pas disponible, veuillez essayer une nouvelle. - - - - Sending email gateway registration request - Envoi de la demande d’inscription de la passerelle de courriel - - - - Sending email gateway unregistration request - Envoi de la demande de désinscription de la passerelle de courriel - - - - Sending email gateway status request - Envoi à la passerelle de courriel d’une demande de statut - EmailGatewayRegistrationDialog - + Registration failed: - + L’inscription a échoué : - + The requested email address is not available, please try a new one. Fill out the new desired email address (including @mailchuck.com) below: - + L’adresse de courriel demandée n’est pas disponible, veuillez en essayer une nouvelle. Saisissez ci-dessous la nouvelle adresse de courriel désirée (incluant @mailchuck.com) : Email gateway registration - + Inscription à la passerelle de courriel Email gateway allows you to communicate with email users. Currently, only the Mailchuck email gateway (@mailchuck.com) is available. Please type the desired email address (including @mailchuck.com) below: - + La passerelle de courriel vous permet de communiquer avec des utilisateurs de courriels. Actuellement, seule la passerelle de courriel de Mailchuck (@mailchuck.com) est disponible. +Veuillez taper l’adresse de courriel désirée (incluant @mailchuck.com) : Mailchuck - + # You can use this to configure your email gateway account # Uncomment the setting you want to use # Here are the options: @@ -202,122 +173,122 @@ Please type the desired email address (including @mailchuck.com) below: MainWindow - + Reply to sender Répondre à l’expéditeur - + Reply to channel Répondre au canal - + Add sender to your Address Book Ajouter l’expéditeur au carnet d’adresses - + Add sender to your Blacklist Ajouter l’expéditeur à votre liste noire - + Move to Trash Envoyer à la Corbeille - + Undelete Restaurer - + View HTML code as formatted text Voir le code HTML comme du texte formaté - + Save message as... Enregistrer le message sous… - + Mark Unread Marquer comme non-lu - + New Nouvelle - + Enable Activer - + Disable Désactiver - + Set avatar... Configurer l’avatar - + Copy address to clipboard Copier l’adresse dans le presse-papier - + Special address behavior... Comportement spécial de l’adresse… - + Email gateway Passerelle de courriel - + Delete Effacer - + Send message to this address Envoyer un message à cette adresse - + Subscribe to this address S’abonner à cette adresse - + Add New Address Ajouter une nouvelle adresse - + Copy destination address to clipboard Copier l’adresse de destination dans le presse-papier - + Force send Forcer l’envoi - + One of your addresses, %1, is an old version 1 address. Version 1 addresses are no longer supported. May we delete it now? Une de vos adresses, %1, est une vieille adresse de la version 1. Les adresses de la version 1 ne sont plus supportées. Nous pourrions la supprimer maintenant? - + Waiting for their encryption key. Will request it again soon. En attente de la clé de chiffrement. Une nouvelle requête sera bientôt lancée. @@ -327,17 +298,17 @@ Please type the desired email address (including @mailchuck.com) below: - + Queued. En attente. - + Message sent. Waiting for acknowledgement. Sent at %1 Message envoyé. En attente de l’accusé de réception. Envoyé %1 - + Message sent. Sent at %1 Message envoyé. Envoyé %1 @@ -347,77 +318,77 @@ Please type the desired email address (including @mailchuck.com) below: - + Acknowledgement of the message received %1 Accusé de réception reçu %1 - + Broadcast queued. Message de diffusion en attente. - + Broadcast on %1 Message de diffusion du %1 - + Problem: The work demanded by the recipient is more difficult than you are willing to do. %1 Problème : Le travail demandé par le destinataire est plus difficile que ce que vous avez paramétré. %1 - + Problem: The recipient's encryption key is no good. Could not encrypt message. %1 Problème : la clé de chiffrement du destinataire n’est pas bonne. Il n’a pas été possible de chiffrer le message. %1 - + Forced difficulty override. Send should start soon. Neutralisation forcée de la difficulté. L’envoi devrait bientôt commencer. - + Unknown status: %1 %2 Statut inconnu : %1 %2 - + Not Connected Déconnecté - + Show Bitmessage Afficher Bitmessage - + Send Envoyer - + Subscribe S’abonner - + Channel Canal - + Quit Quitter - + You may manage your keys by editing the keys.dat file stored in the same directory as this program. It is important that you back up this file. Vous pouvez éditer vos clés en éditant le fichier keys.dat stocké dans le même répertoire que ce programme. Il est important de faire des sauvegardes de ce fichier. - + You may manage your keys by editing the keys.dat file stored in %1 It is important that you back up this file. @@ -425,54 +396,54 @@ It is important that you back up this file. Il est important de faire des sauvegardes de ce fichier. - + Open keys.dat? Ouvrir keys.dat ? - + You may manage your keys by editing the keys.dat file stored in the same directory as this program. It is important that you back up this file. Would you like to open the file now? (Be sure to close Bitmessage before making any changes.) Vous pouvez éditer vos clés en éditant le fichier keys.dat stocké dans le même répertoire que ce programme. Il est important de faire des sauvegardes de ce fichier. Souhaitez-vous l’ouvrir maintenant ? (Assurez-vous de fermer Bitmessage avant d’effectuer des changements.) - + You may manage your keys by editing the keys.dat file stored in %1 It is important that you back up this file. Would you like to open the file now? (Be sure to close Bitmessage before making any changes.) Vous pouvez éditer vos clés en éditant le fichier keys.dat stocké dans le répertoire %1. Il est important de faire des sauvegardes de ce fichier. Souhaitez-vous l’ouvrir maintenant? (Assurez-vous de fermer Bitmessage avant d’effectuer des changements.) - + Delete trash? Supprimer la corbeille ? - + Are you sure you want to delete all trashed messages? Êtes-vous sûr de vouloir supprimer tous les messages dans la corbeille ? - + bad passphrase Mauvaise phrase secrète - + You must type your passphrase. If you don't have one then this is not the form for you. Vous devez taper votre phrase secrète. Si vous n’en avez pas, ce formulaire n’est pas pour vous. - + Bad address version number Mauvais numéro de version d’adresse - + Your address version number must be a number: either 3 or 4. Votre numéro de version d’adresse doit être un nombre : soit 3 soit 4. - + Your address version number must be either 3 or 4. Votre numéro de version d’adresse doit être soit 3 soit 4. @@ -542,22 +513,22 @@ It is important that you back up this file. Would you like to open the file now? - + Connection lost Connexion perdue - + Connected Connecté - + Message trashed Message envoyé à la corbeille - + The TTL, or Time-To-Live is the length of time that the network will hold the message. The recipient must get it during this time. If your Bitmessage client does not hear an acknowledgement, it will resend the message automatically. The longer the Time-To-Live, the @@ -566,17 +537,17 @@ It is important that you back up this file. Would you like to open the file now? Le destinataire doit l’obtenir avant ce temps. Si votre client Bitmessage ne reçoit pas de confirmation de réception, il va le ré-envoyer automatiquement. Plus le Time-To-Live est long, plus grand est le travail que votre ordinateur doit effectuer pour envoyer le message. Un Time-To-Live de quatre ou cinq jours est souvent approprié. - + Message too long Message trop long - + The message that you are trying to send is too long by %1 bytes. (The maximum is 261644 bytes). Please cut it down before sending. Le message que vous essayez d’envoyer est trop long de %1 octets (le maximum est 261644 octets). Veuillez le réduire avant de l’envoyer. - + Error: Your account wasn't registered at an email gateway. Sending registration now as %1, please wait for the registration to be processed before retrying sending. Erreur : votre compte n’a pas été inscrit à une passerelle de courrier électronique. Envoi de l’inscription maintenant en tant que %1, veuillez patienter tandis que l’inscription est en cours de traitement, avant de retenter l’envoi. @@ -621,57 +592,57 @@ Le destinataire doit l’obtenir avant ce temps. Si votre client Bitmessage ne r - + Error: You must specify a From address. If you don't have one, go to the 'Your Identities' tab. Erreur : Vous devez spécifier une adresse d’expéditeur. Si vous n’en avez pas, rendez-vous dans l’onglet 'Vos identités'. - + Address version number Numéro de version de l’adresse - + Concerning the address %1, Bitmessage cannot understand address version numbers of %2. Perhaps upgrade Bitmessage to the latest version. Concernant l’adresse %1, Bitmessage ne peut pas comprendre les numéros de version de %2. Essayez de mettre à jour Bitmessage vers la dernière version. - + Stream number Numéro de flux - + Concerning the address %1, Bitmessage cannot handle stream numbers of %2. Perhaps upgrade Bitmessage to the latest version. Concernant l’adresse %1, Bitmessage ne peut pas supporter les nombres de flux de %2. Essayez de mettre à jour Bitmessage vers la dernière version. - + Warning: You are currently not connected. Bitmessage will do the work necessary to send the message but it won't send until you connect. Avertissement : Vous êtes actuellement déconnecté. Bitmessage fera le travail nécessaire pour envoyer le message mais il ne sera pas envoyé tant que vous ne vous connecterez pas. - + Message queued. Message mis en file d’attente. - + Your 'To' field is empty. Votre champ 'Vers' est vide. - + Right click one or more entries in your address book and select 'Send message to this address'. Cliquez droit sur une ou plusieurs entrées dans votre carnet d’adresses et sélectionnez 'Envoyer un message à ces adresses'. - + Fetched address from namecoin identity. Récupération avec succès de l’adresse de l’identité Namecoin. - + New Message Nouveau message @@ -681,157 +652,157 @@ Le destinataire doit l’obtenir avant ce temps. Si votre client Bitmessage ne r - + Sending email gateway registration request - + Envoi de la demande d’inscription de la passerelle de courriel - + Address is valid. L’adresse est valide. - + The address you entered was invalid. Ignoring it. L’adresse que vous avez entrée est invalide. Adresse ignorée. - + Error: You cannot add the same address to your address book twice. Try renaming the existing one if you want. Erreur : Vous ne pouvez pas ajouter une adresse déjà présente dans votre carnet d’adresses. Essayez de renommer l’adresse existante. - + Error: You cannot add the same address to your subscriptions twice. Perhaps rename the existing one if you want. Erreur : vous ne pouvez pas ajouter la même adresse deux fois à vos abonnements. Peut-être que vous pouvez renommer celle qui existe si vous le souhaitez. - + Restart Redémarrer - + You must restart Bitmessage for the port number change to take effect. Vous devez redémarrer Bitmessage pour que le changement de port prenne effet. - + Bitmessage will use your proxy from now on but you may want to manually restart Bitmessage now to close existing connections (if any). Bitmessage utilisera votre proxy dorénavant, mais vous pouvez redémarrer manuellement Bitmessage maintenant afin de fermer des connexions existantes (si il y en existe). - + Number needed Nombre requis - + Your maximum download and upload rate must be numbers. Ignoring what you typed. Vos taux maximum de téléchargement et de téléversement doivent être des nombres. Ce que vous avez tapé est ignoré. - + Will not resend ever Ne renverra jamais - + Note that the time limit you entered is less than the amount of time Bitmessage waits for the first resend attempt therefore your messages will never be resent. Notez que la limite de temps que vous avez entrée est plus courte que le temps d’attente respecté par Bitmessage avant le premier essai de renvoi, par conséquent votre message ne sera jamais renvoyé. - + Sending email gateway unregistration request - + Envoi de la demande de désinscription de la passerelle de courriel - + Sending email gateway status request - + Envoi à la passerelle de courriel d’une demande de statut - + Passphrase mismatch Phrases secrètes différentes - + The passphrase you entered twice doesn't match. Try again. Les phrases secrètes entrées sont différentes. Réessayez. - + Choose a passphrase Choisissez une phrase secrète - + You really do need a passphrase. Vous devez vraiment utiliser une phrase secrète. - + Address is gone L’adresse a disparu - + Bitmessage cannot find your address %1. Perhaps you removed it? Bitmessage ne peut pas trouver votre adresse %1. Peut-être l’avez-vous supprimée? - + Address disabled Adresse désactivée - + Error: The address from which you are trying to send is disabled. You'll have to enable it on the 'Your Identities' tab before using it. Erreur : L’adresse avec laquelle vous essayez de communiquer est désactivée. Vous devez d’abord l’activer dans l’onglet 'Vos identités' avant de l’utiliser. - + Entry added to the Address Book. Edit the label to your liking. - + Entrée ajoutée au carnet d’adresse. Éditez l’étiquette à votre convenance. - + Entry added to the blacklist. Edit the label to your liking. Entrée ajoutée à la liste noire. Éditez l’étiquette à votre convenance. - + Error: You cannot add the same address to your blacklist twice. Try renaming the existing one if you want. Erreur : vous ne pouvez pas ajouter la même adresse deux fois à votre liste noire. Essayez de renommer celle qui existe si vous le souhaitez. - + Moved items to trash. Messages déplacés dans la corbeille. - + Undeleted item. Articles restaurés. - + Save As... Enregistrer sous… - + Write error. Erreur d’écriture. - + No addresses selected. Aucune adresse sélectionnée. - + If you delete the subscription, messages that you already received will become inaccessible. Maybe you can consider disabling the subscription instead. Disabled subscriptions will not receive new messages, but you can still view messages you already received. Are you sure you want to delete the subscription? @@ -840,7 +811,7 @@ Are you sure you want to delete the subscription? Êtes-vous sur de vouloir supprimer cet abonnement ? - + If you delete the channel, messages that you already received will become inaccessible. Maybe you can consider disabling the channel instead. Disabled channels will not receive new messages, but you can still view messages you already received. Are you sure you want to delete the channel? @@ -849,282 +820,282 @@ Are you sure you want to delete the channel? Êtes-vous sûr de vouloir supprimer ce canal ? - + Do you really want to remove this avatar? Voulez-vous vraiment enlever cet avatar ? - + You have already set an avatar for this address. Do you really want to overwrite it? Vous avez déjà mis un avatar pour cette adresse. Voulez-vous vraiment l’écraser ? - + Start-on-login not yet supported on your OS. Le démarrage dès l’ouverture de session n’est pas encore supporté sur votre OS. - + Minimize-to-tray not yet supported on your OS. La minimisation en zone système n’est pas encore supportée sur votre OS. - + Tray notifications not yet supported on your OS. Les notifications en zone système ne sont pas encore supportées sur votre OS. - + Testing... Tester… - + This is a chan address. You cannot use it as a pseudo-mailing list. - + Ceci est une adresse de canal. Vous ne pouvez pas l’utiliser en tant que pseudo liste de diffusion. - + The address should start with ''BM-'' L’adresse devrait commencer avec "BM-" - + The address is not typed or copied correctly (the checksum failed). L’adresse n’est pas correcte (la somme de contrôle a échoué). - + The version number of this address is higher than this software can support. Please upgrade Bitmessage. Le numéro de version de cette adresse est supérieur à celui que le programme peut supporter. Veuiller mettre Bitmessage à jour. - + The address contains invalid characters. L’adresse contient des caractères invalides. - + Some data encoded in the address is too short. Certaines données encodées dans l’adresse sont trop courtes. - + Some data encoded in the address is too long. Certaines données encodées dans l’adresse sont trop longues. - + Some data encoded in the address is malformed. Quelques données codées dans l’adresse sont mal formées. - + Enter an address above. - + Entrez ci-dessus une adresse. - + Address is an old type. We cannot display its past broadcasts. L’adresse est d’ancien type. Nous ne pouvons pas montrer ses messages de diffusion passés. - + There are no recent broadcasts from this address to display. Il n’y a aucun message de diffusion récent de cette adresse à afficher. - + You are using TCP port %1. (This can be changed in the settings). - + Vous utilisez le port TCP %1. (Ceci peut être changé dans les paramètres). - + Bitmessage Bitmessage - + Identities Identités - + New Identity Nouvelle identité - + Search Chercher - + All Tous - + To Vers - + From De - + Subject Sujet - + Message Message - + Received Reçu - + Messages Messages - + Address book Carnet d’adresses - + Address Adresse - + Add Contact Ajouter un contact - + Fetch Namecoin ID Récupère l’ID Namecoin - + Subject: Sujet : - + From: De : - + To: Vers : - + Send ordinary Message Envoyer un message ordinaire - + Send Message to your Subscribers Envoyer un message à vos abonnés - + TTL: TTL : - + Subscriptions Abonnements - + Add new Subscription Ajouter un nouvel abonnement - + Chans Canaux - + Add Chan Ajouter un canal - + File Fichier - + Settings Paramètres - + Help Aide - + Import keys Importer les clés - + Manage keys Gérer les clés - + Ctrl+Q Ctrl+Q - + F1 F1 - + Contact support Contacter le support - + About À propos - + Regenerate deterministic addresses Regénérer les clés déterministes - + Delete all trashed messages Supprimer tous les messages dans la corbeille - + Join / Create chan Rejoindre / créer un canal - + All accounts Tous les comptes @@ -1134,77 +1105,77 @@ Are you sure you want to delete the channel? Niveau de zoom %1% - + Error: You cannot add the same address to your list twice. Perhaps rename the existing one if you want. Erreur : vous ne pouvez pas ajouter la même adresse deux fois à votre liste. Vous pouvez peut-être, si vous le souhaitez, renommer celle qui existe déjà. - + Add new entry Ajouter une nouvelle entrée - + Display the %1 recent broadcast(s) from this address. - + Montre le(s) %1 plus récent(s) message(s) de diffusion issu(s) de cette adresse. - + New version of PyBitmessage is available: %1. Download it from https://github.com/Bitmessage/PyBitmessage/releases/latest Une nouvelle version de PyBitmessage est disponible : %1. Veuillez la télécharger depuis https://github.com/Bitmessage/PyBitmessage/releases/latest - + Waiting for PoW to finish... %1% En attente de la fin de la PoW… %1% - + Shutting down Pybitmessage... %1% Pybitmessage en cours d’arrêt… %1% - + Waiting for objects to be sent... %1% En attente de l’envoi des objets… %1% - + Saving settings... %1% Enregistrement des paramètres… %1% - + Shutting down core... %1% Cœur en cours d’arrêt… %1% - + Stopping notifications... %1% Arrêt des notifications… %1% - + Shutdown imminent... %1% Arrêt imminent… %1% - + %n hour(s) %n heure%n heures - + %n day(s) %n jour%n jours - + Shutting down PyBitmessage... %1% PyBitmessage en cours d’arrêt… %1% - + Sent Envoyé @@ -1249,86 +1220,86 @@ Are you sure you want to delete the channel? Alerte : votre disque ou le volume de stockage de données est plein. Bitmessage va maintenant se fermer. - + Error! Could not find sender address (your address) in the keys.dat file. Erreur ! Il n’a pas été possible de trouver l’adresse d’expéditeur (votre adresse) dans le fichier keys.dat. - + Doing work necessary to send broadcast... Travail en cours afin d’envoyer le message de diffusion… - + Broadcast sent on %1 Message de diffusion envoyé %1 - + Encryption key was requested earlier. La clé de chiffrement a été demandée plus tôt. - + Sending a request for the recipient's encryption key. Envoi d’une demande de la clé de chiffrement du destinataire. - + Looking up the receiver's public key Recherche de la clé publique du récepteur - + Problem: Destination is a mobile device who requests that the destination be included in the message but this is disallowed in your settings. %1 Problème : la destination est un dispositif mobile qui nécessite que la destination soit incluse dans le message mais ceci n’est pas autorisé dans vos paramètres. %1 - + Doing work necessary to send message. There is no required difficulty for version 2 addresses like this. Travail en cours afin d’envoyer le message. Il n’y a pas de difficulté requise pour les adresses version 2 comme celle-ci. - + Doing work necessary to send message. Receiver's required difficulty: %1 and %2 Travail en cours afin d’envoyer le message. Difficulté requise du destinataire : %1 et %2 - + Problem: The work demanded by the recipient (%1 and %2) is more difficult than you are willing to do. %3 Problème : Le travail demandé par le destinataire (%1 and %2) est plus difficile que ce que vous avez paramétré. %3 - + Problem: You are trying to send a message to yourself or a chan but your encryption key could not be found in the keys.dat file. Could not encrypt message. %1 Problème : Vous essayez d’envoyer un message à un canal ou à vous-même mais votre clef de chiffrement n’a pas été trouvée dans le fichier keys.dat. Le message ne peut pas être chiffré. %1 - + Doing work necessary to send message. Travail en cours afin d’envoyer le message. - + Message sent. Waiting for acknowledgement. Sent on %1 Message envoyé. En attente de l’accusé de réception. Envoyé %1 - + Doing work necessary to request encryption key. Travail en cours afin d’obtenir la clé de chiffrement. - + Broadcasting the public key request. This program will auto-retry if they are offline. Diffusion de la demande de clef publique. Ce programme réessaiera automatiquement si ils sont déconnectés. - + Sending public key request. Waiting for reply. Requested at %1 Envoi d’une demande de clef publique. En attente d’une réponse. Demandée à %1 @@ -1343,37 +1314,37 @@ Difficulté requise du destinataire : %1 et %2 Transfert de port UPnP retiré - + Mark all messages as read Marquer tous les messages comme lus - + Are you sure you would like to mark all messages read? Êtes-vous sûr(e) de vouloir marquer tous les messages comme lus ? - + Doing work necessary to send broadcast. Travail en cours afin d’envoyer la diffusion. - + Proof of work pending En attente de preuve de fonctionnement - + %n object(s) pending proof of work %n objet en attente de preuve de fonctionnement%n objet(s) en attente de preuve de fonctionnement - + %n object(s) waiting to be distributed %n objet en attente d'être distribué%n objet(s) en attente d'être distribués - + Wait until these tasks finish? Attendre jusqu'à ce que ces tâches se terminent ? @@ -1418,37 +1389,32 @@ Difficulté requise du destinataire : %1 et %2 Le nom %1 n'a aucune adresse Bitmessage d'associée. - + Success! Namecoind version %1 running. Succès ! Namecoind version %1 en cours d'exécution. - + Success! NMControll is up and running. Succès ! NMControll est debout et en cours d'exécution. - + Couldn't understand NMControl. Ne pouvait pas comprendre NMControl. - - - The connection to namecoin failed. - La connexion à Namecoin a échouée. - Your GPU(s) did not calculate correctly, disabling OpenCL. Please report to the developers. Votre GPU(s) n'a pas calculé correctement, mettant OpenCL hors service. Veuillez remonter ceci aux développeurs s'il vous plaît. - + Set notification sound... Mettre un son de notification ... - + Welcome to easy and secure Bitmessage * send messages to other people @@ -1463,175 +1429,120 @@ Bienvenue dans le facile et sécurisé Bitmessage - + not recommended for chans pas recommandé pour les canaux - - Quiet Mode - Mode tranquille - - - + Problems connecting? Try enabling UPnP in the Network Settings Des difficultés à se connecter ? Essayez de permettre UPnP dans les "Paramètres réseau" - + You are trying to send an email instead of a bitmessage. This requires registering with a gateway. Attempt to register? Vous essayez d'envoyer un courrier électronique au lieu d'un bitmessage. Ceci exige votre inscription à une passerelle. Essayer de vous inscrire ? - + Error: Bitmessage addresses start with BM- Please check the recipient address %1 Erreur : Les adresses Bitmessage commencent par BM- Veuillez vérifier l'adresse du destinataire %1 - + Error: The recipient address %1 is not typed or copied correctly. Please check it. Erreur : L’adresse du destinataire %1 n’est pas correctement tapée ou recopiée. Veuillez la vérifier. - + Error: The recipient address %1 contains invalid characters. Please check it. Erreur : L’adresse du destinataire %1 contient des caractères invalides. Veuillez la vérifier. - + Error: The version of the recipient address %1 is too high. Either you need to upgrade your Bitmessage software or your acquaintance is being clever. Erreur : la version de l’adresse destinataire %1 est trop élevée. Vous devez mettre à niveau votre logiciel Bitmessage ou alors celui de votre connaissance est plus intelligent. - + Error: Some data encoded in the recipient address %1 is too short. There might be something wrong with the software of your acquaintance. Erreur : quelques données codées dans l’adresse destinataire %1 sont trop courtes. Il pourrait y avoir un soucis avec le logiciel de votre connaissance. - + Error: Some data encoded in the recipient address %1 is too long. There might be something wrong with the software of your acquaintance. Erreur : quelques données codées dans l’adresse destinataire %1 sont trop longues. Il pourrait y avoir un soucis avec le logiciel de votre connaissance. - + Error: Some data encoded in the recipient address %1 is malformed. There might be something wrong with the software of your acquaintance. Erreur : quelques données codées dans l’adresse destinataire %1 sont mal formées. Il pourrait y avoir un soucis avec le logiciel de votre connaissance. - + Error: Something is wrong with the recipient address %1. Erreur : quelque chose ne va pas avec l'adresse de destinataire %1. - - Error: %1 - Erreur : %1 - - - + From %1 De %1 - + Synchronisation pending En attente de synchronisation - + Bitmessage hasn't synchronised with the network, %n object(s) to be downloaded. If you quit now, it may cause delivery delays. Wait until the synchronisation finishes? Bitmessage ne s'est pas synchronisé avec le réseau, %n objet(s) à télécharger. Si vous quittez maintenant, cela pourrait causer des retards de livraison. Attendre jusqu'à ce que la synchronisation aboutisse ?Bitmessage ne s'est pas synchronisé avec le réseau, %n objet(s) à télécharger. Si vous quittez maintenant, cela pourrait causer des retards de livraison. Attendre jusqu'à ce que la synchronisation aboutisse ? - + Not connected Non connecté - + Bitmessage isn't connected to the network. If you quit now, it may cause delivery delays. Wait until connected and the synchronisation finishes? Bitmessage n'est pas connecté au réseau. Si vous quittez maintenant, cela pourrait causer des retards de livraison. Attendre jusqu'à ce qu'il soit connecté et que la synchronisation se termine ? - + Waiting for network connection... En attente de connexion réseau... - + Waiting for finishing synchronisation... En attente d'achèvement de la synchronisation... - + You have already set a notification sound for this address book entry. Do you really want to overwrite it? Vous avez déjà mis un son de notification pour cette adresse. Voulez-vous vraiment l’écraser ? - - - Error occurred: could not load message from disk. - Une erreur a eu lieu : ne peut pas charger de message depuis le disque. - - - - Display the %n recent broadcast(s) from this address. - - - - - Go online - Passer en-ligne - - - - Go offline - Passer hors-ligne - - - - Clear - Vider - - - - inbox - entrant - - - - new - nouveau - - - - sent - envoyé - - - - trash - corbeille - MessageView - + Follow external link Suivre lien externe - + The link "%1" will open in a browser. It may be a security risk, it could de-anonymise you or download malicious data. Are you sure? Le lien "%1" s'ouvrira dans un navigateur. Cela pourrait être un risque de sécurité, cela pourrait vous désanonymiser ou télécharger des données malveillantes. Êtes-vous sûr(e) ? - + HTML detected, click here to display HTML détecté, cliquer ici pour l'afficher - + Click here to disable HTML Cliquer ici pour mettre hors de service le HTML @@ -1639,14 +1550,14 @@ Bienvenue dans le facile et sécurisé Bitmessage MsgDecode - + The message has an unknown encoding. Perhaps you should upgrade Bitmessage. Le message est codé de façon inconnue. Peut-être que vous devriez mettre à niveau Bitmessage. - + Unknown encoding Encodage inconnu @@ -1654,98 +1565,98 @@ Peut-être que vous devriez mettre à niveau Bitmessage. NewAddressDialog - + Create new Address Créer une nouvelle adresse - + Here you may generate as many addresses as you like. Indeed, creating and abandoning addresses is encouraged. You may generate addresses by using either random numbers or by using a passphrase. If you use a passphrase, the address is called a "deterministic" address. The 'Random Number' option is selected by default but deterministic addresses have several pros and cons: Vous pouvez générer autant d’adresses que vous le souhaitez. En effet, nous vous encourageons à créer et à délaisser vos adresses. Vous pouvez générer des adresses en utilisant des nombres aléatoires ou en utilisant une phrase secrète. Si vous utilisez une phrase secrète, l’adresse sera une adresse "déterministe". L’option 'Nombre Aléatoire' est sélectionnée par défaut mais les adresses déterministes ont certains avantages et inconvénients : - + <html><head/><body><p><span style=" font-weight:600;">Pros:<br/></span>You can recreate your addresses on any computer from memory. <br/>You need-not worry about backing up your keys.dat file as long as you can remember your passphrase. <br/><span style=" font-weight:600;">Cons:<br/></span>You must remember (or write down) your passphrase if you expect to be able to recreate your keys if they are lost. <br/>You must remember the address version number and the stream number along with your passphrase. <br/>If you choose a weak passphrase and someone on the Internet can brute-force it, they can read your messages and send messages as you.</p></body></html> <html><head/><body><p><span style=" font-weight:600;">Avantages :<br/></span>Vous pouvez recréer vos adresses sur n’importe quel ordinateur. <br/>Vous n’avez pas à vous inquiéter à propos de la sauvegarde de votre fichier keys.dat tant que vous vous rappelez de votre phrase secrète. <br/><span style=" font-weight:600;">Inconvénients :<br/></span>Vous devez vous rappeler (ou noter) votre phrase secrète si vous souhaitez être capable de récréer vos clés si vous les perdez. <br/>Vous devez vous rappeler du numéro de version de l’adresse et du numéro de flux en plus de votre phrase secrète. <br/>Si vous choisissez une phrase secrète faible et que quelqu’un sur Internet parvient à la brute-forcer, il pourra lire vos messages et vous en envoyer.</p></body></html> - + Use a random number generator to make an address Utiliser un générateur de nombres aléatoires pour créer une adresse - + Use a passphrase to make addresses Utiliser une phrase secrète pour créer une adresse - + Spend several minutes of extra computing time to make the address(es) 1 or 2 characters shorter Créer une adresse plus courte d’un ou deux caractères (nécessite plusieurs minutes de temps de calcul supplémentaires) - + Make deterministic addresses Créer une adresse déterministe - + Address version number: 4 Numéro de version de l’adresse : 4 - + In addition to your passphrase, you must remember these numbers: En plus de votre phrase secrète, vous devez vous rappeler ces numéros: - + Passphrase Phrase secrète - + Number of addresses to make based on your passphrase: - Nombre d’adresses basées sur votre phrase secrète à créer : + Nombre d’adresses à créer sur base de votre phrase secrète: - + Stream number: 1 Nombre de flux : 1 - + Retype passphrase Retapez la phrase secrète - + Randomly generate address Générer une adresse de manière aléatoire - + Label (not shown to anyone except you) Étiquette (seulement visible par vous) - + Use the most available stream Utiliser le flux le plus disponible - + (best if this is the first of many addresses you will create) (préférable si vous générez votre première adresse) - + Use the same stream as an existing address Utiliser le même flux qu’une adresse existante - + (saves you some bandwidth and processing power) (économise de la bande passante et de la puissance de calcul) @@ -1753,22 +1664,22 @@ The 'Random Number' option is selected by default but deterministic ad NewSubscriptionDialog - + Add new entry Ajouter une nouvelle entrée - + Label Étiquette - + Address Adresse - + Enter an address above. Entrez ci-dessus une adresse. @@ -1776,60 +1687,55 @@ The 'Random Number' option is selected by default but deterministic ad SpecialAddressBehaviorDialog - + Special Address Behavior Comportement spécial de l’adresse - + Behave as a normal address Se comporter comme une adresse normale - + Behave as a pseudo-mailing-list address Se comporter comme une adresse d’une pseudo liste de diffusion - + Mail received to a pseudo-mailing-list address will be automatically broadcast to subscribers (and thus will be public). Un mail reçu sur une adresse d’une pseudo liste de diffusion sera automatiquement diffusé aux abonnés (et sera donc public). - + Name of the pseudo-mailing-list: Nom de la pseudo liste de diffusion : - - - This is a chan address. You cannot use it as a pseudo-mailing list. - Ceci est une adresse de canal. Vous ne pouvez pas l’utiliser en tant que pseudo liste de diffusion. - aboutDialog - + About À propos - - - PyBitmessage - - - version ? - + PyBitmessage + PyBitmessage - + + version ? + version ? + + + <html><head/><body><p>Distributed under the MIT/X11 software license; see <a href="http://www.opensource.org/licenses/mit-license.php"><span style=" text-decoration: underline; color:#0000ff;">http://www.opensource.org/licenses/mit-license.php</span></a></p></body></html> <html><head/><body><p>Distribué sous la licence logicielle MIT/X11; voir <a href="http://www.opensource.org/licenses/mit-license.php"><span style=" text-decoration: underline; color:#0000ff;">http://www.opensource.org/licenses/mit-license.php</span></a></p></body></html> - + This is Beta software. Version bêta. @@ -1838,10 +1744,10 @@ The 'Random Number' option is selected by default but deterministic ad <html><head/><body><p>Copyright © 2012-2016 Jonathan Warren<br/>Copyright © 2013-2016 The Bitmessage Developers</p></body></html> - - - <html><head/><body><p>Copyright © 2012-2016 Jonathan Warren<br/>Copyright © 2013-2017 The Bitmessage Developers</p></body></html> - <html><head/><body><p>Copyright © 2012-2016 Jonathan Warren<br/>Copyright © 2013-2017 Les développeurs de Bitmessage</p></body></html> + + + <html><head/><body><p>Copyright &copy; 2012-2016 Jonathan Warren<br/>Copyright &copy; 2013-2016 The Bitmessage Developers</p></body></html> + <html><head/><body><p>Copyright &copy; 2012-2016 Jonathan Warren<br/>Copyright &copy; 2013-2016 Les développeurs de Bitmessage</p></body></html> @@ -1872,12 +1778,12 @@ The 'Random Number' option is selected by default but deterministic ad Adresse - + Blacklist Liste noire - + Whitelist Liste blanche @@ -1885,45 +1791,40 @@ The 'Random Number' option is selected by default but deterministic ad connectDialog - + Bitmessage Bitmessage - + Bitmessage won't connect to anyone until you let it. Bitmessage ne connectera à personne avant que vous ne le laissiez faire. - + Connect now Connexion maintenant - + Let me configure special network settings first Me laisser d’abord configurer des paramètres spéciaux de réseau - - - Work offline - Travailler hors-ligne - helpDialog - + Help Aide - + <a href="https://bitmessage.org/wiki/PyBitmessage_Help">https://bitmessage.org/wiki/PyBitmessage_Help</a> <a href="https://bitmessage.org/wiki/PyBitmessage_Help">https://bitmessage.org/wiki/PyBitmessage_Help</a> - + As Bitmessage is a collaborative project, help can be found online in the Bitmessage Wiki: Bitmessage étant un projet collaboratif, une aide peut être trouvée en ligne sur le Wiki de Bitmessage: @@ -1931,35 +1832,30 @@ The 'Random Number' option is selected by default but deterministic ad iconGlossaryDialog - + Icon Glossary Glossaire des icônes - + You have no connections with other peers. Vous n’avez aucune connexion avec d’autres pairs. - + You have made at least one connection to a peer using an outgoing connection but you have not yet received any incoming connections. Your firewall or home router probably isn't configured to forward incoming TCP connections to your computer. Bitmessage will work just fine but it would help the Bitmessage network if you allowed for incoming connections and will help you be a better-connected node. Vous avez au moins une connexion sortante avec un pair mais vous n’avez encore reçu aucune connexion entrante. Votre pare-feu ou routeur n’est probablement pas configuré pour transmettre les connexions TCP vers votre ordinateur. Bitmessage fonctionnera correctement, mais le réseau Bitmessage se portera mieux si vous autorisez les connexions entrantes. Cela vous permettra d’être un nœud mieux connecté. You are using TCP port ?. (This can be changed in the settings). - + Vous utilisez le port TCP ?. (Peut être changé dans les paramètres). - + You do have connections with other peers and your firewall is correctly configured. Vous avez des connexions avec d’autres pairs et votre pare-feu est configuré correctement. - - - You are using TCP port %1. (This can be changed in the settings). - Vous utilisez le port TCP %1. (Ceci peut être changé dans les paramètres). - networkstatus @@ -1969,37 +1865,37 @@ The 'Random Number' option is selected by default but deterministic ad Total de connexions: - + Since startup: Depuis le démarrage : - + Processed 0 person-to-person messages. Traité 0 messages de personne à personne. - + Processed 0 public keys. Traité 0 clés publiques. - + Processed 0 broadcasts. Traité 0 message de diffusion. - + Inventory lookups per second: 0 Consultations d’inventaire par seconde : 0 - + Objects to be synced: Objets à synchroniser : - + Stream # Flux N° @@ -2009,114 +1905,114 @@ The 'Random Number' option is selected by default but deterministic ad - + Since startup on %1 Démarré depuis le %1 - + Down: %1/s Total: %2 Téléchargées : %1/s Total : %2 - + Up: %1/s Total: %2 Téléversées : %1/s Total : %2 - + Total Connections: %1 Total des connexions : %1 - + Inventory lookups per second: %1 Consultations d’inventaire par seconde : %1 - + Up: 0 kB/s Téléversement : 0 kO/s - + Down: 0 kB/s Téléchargement : 0 kO/s - + Network Status Statut du réseau - + byte(s) octetoctets - + Object(s) to be synced: %n Objet à synchroniser : %nObjets à synchroniser : %n - + Processed %n person-to-person message(s). Traité %n message de personne à personne.Traité %n messages de personne à personne. - + Processed %n broadcast message(s). Traité %n message de diffusion.Traité %n messages de diffusion. - + Processed %n public key(s). Traité %n clé publique.Traité %n clés publiques. - + Peer Pair - + IP address or hostname Adresse IP ou nom d'hôte - + Rating Évaluation - + PyBitmessage tracks the success rate of connection attempts to individual nodes. The rating ranges from -1 to 1 and affects the likelihood of selecting the node in the future PyBitmessage suit à la trace le taux de réussites de connexions tentées vers les noeuds individuels. L'évaluation s'étend de -1 à 1 et affecte la probabilité de choisir ce noeud dans l'avenir - + User agent Agent utilisateur - + Peer's self-reported software Logiciel, auto-rapporté par le pair - + TLS TLS - + Connection encryption - Chiffrement de la connexion + - + List of streams negotiated between you and the peer - Liste de flux négociés entre vous et le pair + @@ -2173,8 +2069,8 @@ The 'Random Number' option is selected by default but deterministic ad - Chan passphrase/name: - + Chan passhphrase/name: + Nom ou phrase mot de passe du canal : @@ -2195,7 +2091,7 @@ The 'Random Number' option is selected by default but deterministic ad newchandialog - + Successfully created / joined chan %1 Le canal %1 a été rejoint ou créé avec succès. @@ -2239,52 +2135,52 @@ The 'Random Number' option is selected by default but deterministic ad regenerateAddressesDialog - + Regenerate Existing Addresses Regénérer des adresses existantes - + Regenerate existing addresses - Adresses existantes régénérées + Regénérer des adresses existantes - + Passphrase Phrase secrète - + Number of addresses to make based on your passphrase: Nombre d’adresses basées sur votre phrase secrète à créer : - + Address version number: Numéro de version de l’adresse : - + Stream number: Numéro du flux : - + 1 1 - + Spend several minutes of extra computing time to make the address(es) 1 or 2 characters shorter Créer une adresse plus courte d’un ou deux caractères (nécessite plusieurs minutes de temps de calcul supplémentaires) - + You must check (or not check) this box just like you did (or didn't) when you made your addresses the first time. Vous devez cocher (ou décocher) cette case comme vous l’aviez fait (ou non) lors de la création de vos adresses la première fois. - + If you have previously made deterministic addresses but lost them due to an accident (like hard drive failure), you can regenerate them here. If you used the random number generator to make your addresses then this form will be of no use to you. Si vous aviez généré des adresses déterministes mais les avez perdues à cause d’un accident (comme une panne de disque dur), vous pouvez les régénérer ici. Si vous aviez utilisé le générateur de nombres aléatoires pour créer vos adresses, ce formulaire ne vous sera d’aucune utilité. diff --git a/src/translations/bitmessage_ja.qm b/src/translations/bitmessage_ja.qm index 9135be1a..3756d6d3 100644 Binary files a/src/translations/bitmessage_ja.qm and b/src/translations/bitmessage_ja.qm differ diff --git a/src/translations/bitmessage_ja.ts b/src/translations/bitmessage_ja.ts index 7f1e4515..90e49dc2 100644 --- a/src/translations/bitmessage_ja.ts +++ b/src/translations/bitmessage_ja.ts @@ -2,17 +2,17 @@ AddAddressDialog - + Add new entry 新しい項目を追加 - + Label ラベル - + Address アドレス @@ -20,99 +20,70 @@ EmailGatewayDialog - + Email gateway メールゲートウェイ - + Register on email gateway メールゲートウェイで登録 - + Account status at email gateway メールゲートウェイのアカウント状態 - + Change account settings at email gateway メールゲートウェイでアカウントの設定を変更 - + Unregister from email gateway メールゲートウェイから登録抹消 - + Email gateway allows you to communicate with email users. Currently, only the Mailchuck email gateway (@mailchuck.com) is available. メールゲートウェイを使用すると、メールユーザーと通信できます。 現在、Mailchuck メールゲートウェイ (@mailchuck.com) のみが利用可能です。 - + Desired email address (including @mailchuck.com): 希望のメールアドレス (@mailchuck.com を含む): - - - @mailchuck.com - @mailchuck.com - - - - Registration failed: - 登録に失敗しました: - - - - The requested email address is not available, please try a new one. - リクエストしたメールアドレスは利用できません。新しいメールアドレスを試してください。 - - - - Sending email gateway registration request - メールゲートウェイの登録リクエストを送信しています - - - - Sending email gateway unregistration request - メールゲートウェイの登録抹消リクエストを送信しています - - - - Sending email gateway status request - メールゲートウェイの状態リクエストを送信しています - EmailGatewayRegistrationDialog - + Registration failed: - + 登録に失敗しました: - + The requested email address is not available, please try a new one. Fill out the new desired email address (including @mailchuck.com) below: - + リクエストしたメールアドレスは利用できません。新しいメールアドレスをお試しください。 新しい希望メールアドレス (@mailchuck.com を含む) を次のように記入してください: Email gateway registration - + メールゲートウェイの登録 Email gateway allows you to communicate with email users. Currently, only the Mailchuck email gateway (@mailchuck.com) is available. Please type the desired email address (including @mailchuck.com) below: - + メールゲートウェイを使用すると、メールユーザーと通信できます。 現在、Mailchuck メールゲートウェイ (@mailchuck.com) のみが利用可能です。 +希望のメールアドレス (@mailchuck.com を含む) を以下に入力してください: Mailchuck - + # You can use this to configure your email gateway account # Uncomment the setting you want to use # Here are the options: @@ -197,122 +168,122 @@ Please type the desired email address (including @mailchuck.com) below: MainWindow - + Reply to sender 送信元に返信 - + Reply to channel チャンネルに返信 - + Add sender to your Address Book 送信元をアドレス帳に追加 - + Add sender to your Blacklist 送信元をブラックリストに追加 - + Move to Trash ゴミ箱へ移動 - + Undelete 削除を元に戻す - + View HTML code as formatted text HTMLコードを整形したテキストで表示 - + Save message as... 形式を選択してメッセージを保存 - + Mark Unread 未読にする - + New 新規 - + Enable 有効 - + Disable 無効 - + Set avatar... アバターを設定... - + Copy address to clipboard アドレスをコピー - + Special address behavior... アドレスの特別な動作 - + Email gateway メールゲートウェイ - + Delete 削除 - + Send message to this address このアドレスへ送信 - + Subscribe to this address このアドレスを購読 - + Add New Address アドレスを追加 - + Copy destination address to clipboard 宛先アドレスをコピー - + Force send 強制的に送信 - + One of your addresses, %1, is an old version 1 address. Version 1 addresses are no longer supported. May we delete it now? %1は古いバージョン1のアドレスです。バージョン1のアドレスはサポートが終了しています。すぐに削除しますか? - + Waiting for their encryption key. Will request it again soon. 暗号鍵を待っています。 すぐにもう一度リクエストします。 @@ -322,17 +293,17 @@ Please type the desired email address (including @mailchuck.com) below: - + Queued. キューに入りました。 - + Message sent. Waiting for acknowledgement. Sent at %1 メッセージを送信しました。 確認応答を待っています。 %1 で送信されました - + Message sent. Sent at %1 メッセージは送信されました。送信先: %1 @@ -342,131 +313,131 @@ Please type the desired email address (including @mailchuck.com) below: - + Acknowledgement of the message received %1 メッセージの確認を受け取りました %1 - + Broadcast queued. 配信がキューに入りました。 - + Broadcast on %1 配信: %1 - + Problem: The work demanded by the recipient is more difficult than you are willing to do. %1 問題: 受信者が要求している処理は現在あなたが設定しているよりも高い難易度です。 %1 - + Problem: The recipient's encryption key is no good. Could not encrypt message. %1 問題: 受信者の暗号鍵は正当でない物です。メッセージを暗号化できません。 %1 - + Forced difficulty override. Send should start soon. 難易度を強制上書きしました。まもなく送信されます。 - + Unknown status: %1 %2 不明なステータス: %1 %2 - + Not Connected 未接続 - + Show Bitmessage Bitmessageを表示 - + Send 送る - + Subscribe 購読 - + Channel チャンネル - + Quit 終了 - + You may manage your keys by editing the keys.dat file stored in the same directory as this program. It is important that you back up this file. プログラムを同じディレクトリに保存されているkeys.datファイルを編集することで鍵を管理できます。ファイルをバックアップしておくことも重要です。 - + You may manage your keys by editing the keys.dat file stored in %1 It is important that you back up this file. %1に保存されているkeys.datファイルを編集することで鍵を管理できます。ファイルをバックアップしておくことも重要です。 - + Open keys.dat? keys.datを開きますか? - + You may manage your keys by editing the keys.dat file stored in the same directory as this program. It is important that you back up this file. Would you like to open the file now? (Be sure to close Bitmessage before making any changes.) プログラムを同じディレクトリに保存されているkeys.datファイルを編集することで鍵を管理できます。ファイルをバックアップしておくことも重要です。すぐにファイルを開きますか?(必ず編集する前にBitmessageを終了してください) - + You may manage your keys by editing the keys.dat file stored in %1 It is important that you back up this file. Would you like to open the file now? (Be sure to close Bitmessage before making any changes.) %1に保存されているkeys.datファイルを編集することで鍵を管理できます。ファイルをバックアップしておくことも重要です。すぐにファイルを開きますか?(必ず編集する前にBitmessageを終了してください) - + Delete trash? ゴミ箱を空にしますか? - + Are you sure you want to delete all trashed messages? ゴミ箱内のメッセージを全て削除してもよろしいですか? - + bad passphrase 不正なパスフレーズ - + You must type your passphrase. If you don't have one then this is not the form for you. パスフレーズを入力してください。パスフレーズがない場合は入力する必要はありません。 - + Bad address version number 不正なアドレスのバージョン番号 - + Your address version number must be a number: either 3 or 4. アドレスのバージョン番号は数字にする必要があります: 3 または 4。 - + Your address version number must be either 3 or 4. アドレスのバージョン番号は、3 または 4 のどちらかにする必要があります。 @@ -536,22 +507,22 @@ It is important that you back up this file. Would you like to open the file now? - + Connection lost 接続が切断されました - + Connected 接続済み - + Message trashed メッセージが削除されました - + The TTL, or Time-To-Live is the length of time that the network will hold the message. The recipient must get it during this time. If your Bitmessage client does not hear an acknowledgement, it will resend the message automatically. The longer the Time-To-Live, the @@ -562,17 +533,17 @@ It is important that you back up this file. Would you like to open the file now? コンピュータがメッセージを送信するために必要な処理が増えます。 多くの場合 4〜5 日のTTL(Time-To-Live)が適切です。 - + Message too long メッセージが長すぎます - + The message that you are trying to send is too long by %1 bytes. (The maximum is 261644 bytes). Please cut it down before sending. 送信しようとしているメッセージが %1 バイト長すぎます。 (最大は261644バイトです)。 送信する前に短くしてください。 - + Error: Your account wasn't registered at an email gateway. Sending registration now as %1, please wait for the registration to be processed before retrying sending. エラー: アカウントがメールゲートウェイに登録されていません。 今 %1 として登録を送信しています。送信を再試行する前に、登録が処理されるまでお待ちください。 @@ -617,57 +588,57 @@ It is important that you back up this file. Would you like to open the file now? - + Error: You must specify a From address. If you don't have one, go to the 'Your Identities' tab. エラー: 送信元アドレスを指定してください。まだ作成していない場合には「アドレス一覧」のタブを開いてください。 - + Address version number アドレスのバージョン番号 - + Concerning the address %1, Bitmessage cannot understand address version numbers of %2. Perhaps upgrade Bitmessage to the latest version. アドレス %1 に接続。%2 のバージョン番号は処理できません。Bitmessageを最新のバージョンへアップデートしてください。 - + Stream number ストリーム番号 - + Concerning the address %1, Bitmessage cannot handle stream numbers of %2. Perhaps upgrade Bitmessage to the latest version. アドレス %1 に接続。%2 のストリーム番号は処理できません。Bitmessageを最新のバージョンへアップデートしてください。 - + Warning: You are currently not connected. Bitmessage will do the work necessary to send the message but it won't send until you connect. 警告: 接続されていません。Bitmessageはメッセージの処理を行いますが、ネットワークに接続するまで送信はされません。 - + Message queued. メッセージがキューに入りました。 - + Your 'To' field is empty. 宛先が指定されていません。 - + Right click one or more entries in your address book and select 'Send message to this address'. アドレス帳から一つ、または複数のアドレスを右クリックして「このアドレスへ送信」を選んでください。 - + Fetched address from namecoin identity. namecoin IDからアドレスを取得。 - + New Message 新規メッセージ @@ -677,157 +648,157 @@ It is important that you back up this file. Would you like to open the file now? - + Sending email gateway registration request - + メールゲートウェイの登録リクエストを送信しています - + Address is valid. アドレスが不正です。 - + The address you entered was invalid. Ignoring it. 入力されたアドレスは不正です。無視されました。 - + Error: You cannot add the same address to your address book twice. Try renaming the existing one if you want. エラー: 同じアドレスを複数アドレス帳に追加する事はできません。既存の項目をリネームしてください。 - + Error: You cannot add the same address to your subscriptions twice. Perhaps rename the existing one if you want. エラー: 購読に、同じアドレスを2回追加することはできません。 必要に応じて、既存の名前を変更してください。 - + Restart 再開 - + You must restart Bitmessage for the port number change to take effect. ポート番号の変更を有効にするにはBitmessageを再起動してください。 - + Bitmessage will use your proxy from now on but you may want to manually restart Bitmessage now to close existing connections (if any). プロキシの設定を有効にするには手動でBitmessageを再起動してください。既に接続がある場合は切断されます。 - + Number needed 数字が必要です - + Your maximum download and upload rate must be numbers. Ignoring what you typed. 最大ダウンロード数とアップロード数は数字にする必要があります。 入力されたものを無視します。 - + Will not resend ever 今後再送信されません - + Note that the time limit you entered is less than the amount of time Bitmessage waits for the first resend attempt therefore your messages will never be resent. 入力した時間制限は、Bitmessageが最初の再送試行を待つ時間よりも短いため、メッセージは再送信されないことにご注意ください。 - + Sending email gateway unregistration request - + メールゲートウェイの登録抹消リクエストを送信しています - + Sending email gateway status request - + メールゲートウェイの状態リクエストを送信しています - + Passphrase mismatch パスフレーズが一致しません - + The passphrase you entered twice doesn't match. Try again. 再度入力されたパスフレーズが一致しません。再入力してください。 - + Choose a passphrase パスフレーズを選択してください - + You really do need a passphrase. パスフレーズが必要です。 - + Address is gone アドレスが無効になりました - + Bitmessage cannot find your address %1. Perhaps you removed it? アドレス %1 が見つかりません。既に削除していませんか? - + Address disabled アドレスが無効になりました - + Error: The address from which you are trying to send is disabled. You'll have to enable it on the 'Your Identities' tab before using it. エラー: 送信しようとしたアドレスは無効になっています。使用する前に「アドレス一覧」で有効にしてください。 - + Entry added to the Address Book. Edit the label to your liking. - + アドレス帳に項目が追加されました。ラベルは自由に編集できます。 - + Entry added to the blacklist. Edit the label to your liking. ブラックリストに項目が追加されました。ラベルは自由に編集できます。 - + Error: You cannot add the same address to your blacklist twice. Try renaming the existing one if you want. エラー: ブラックリストに同じアドレスを2回追加することはできません。 必要に応じて既存の名前を変更してみてください。 - + Moved items to trash. アイテムをゴミ箱へ移動。 - + Undeleted item. アイテムの削除を元に戻します。 - + Save As... 形式を選択して保存 - + Write error. 書き込みエラー。 - + No addresses selected. アドレスが未選択です。 - + If you delete the subscription, messages that you already received will become inaccessible. Maybe you can consider disabling the subscription instead. Disabled subscriptions will not receive new messages, but you can still view messages you already received. Are you sure you want to delete the subscription? @@ -836,7 +807,7 @@ Are you sure you want to delete the subscription? 購読を削除してもよろしいですか? - + If you delete the channel, messages that you already received will become inaccessible. Maybe you can consider disabling the channel instead. Disabled channels will not receive new messages, but you can still view messages you already received. Are you sure you want to delete the channel? @@ -845,282 +816,282 @@ Are you sure you want to delete the channel? チャンネルを削除してもよろしいですか? - + Do you really want to remove this avatar? このアバターを削除してもよろしいですか? - + You have already set an avatar for this address. Do you really want to overwrite it? すでにこのアドレスのアバターを設定しています。 上書きしてもよろしいですか? - + Start-on-login not yet supported on your OS. ログイン時に開始は、まだお使いのOSでサポートされていません。 - + Minimize-to-tray not yet supported on your OS. トレイに最小化は、まだお使いのOSでサポートされていません。 - + Tray notifications not yet supported on your OS. トレイ通知は、まだお使いのOSでサポートされていません。 - + Testing... テスト中 - + This is a chan address. You cannot use it as a pseudo-mailing list. - + chanアドレスは仮想メーリングリストのアドレスには使用できません。 - + The address should start with ''BM-'' アドレスは「BM-」から始まります - + The address is not typed or copied correctly (the checksum failed). このアドレスは正しく入力、またはコピーされていません。(チェックサムが一致しません)。 - + The version number of this address is higher than this software can support. Please upgrade Bitmessage. このアドレスのバージョン番号はこのプログラムのサポート範囲外です。Bitmessageをアップデートしてください。 - + The address contains invalid characters. 入力されたアドレスは不正な文字を含んでいます。 - + Some data encoded in the address is too short. このアドレスでエンコードされたデータが短すぎます。 - + Some data encoded in the address is too long. このアドレスでエンコードされたデータが長過ぎます。 - + Some data encoded in the address is malformed. このアドレスでエンコードされた一部のデータが不正です。 - + Enter an address above. - + 上にアドレスを入力してください。 - + Address is an old type. We cannot display its past broadcasts. アドレスが古い形式です。 過去の配信は表示できません。 - + There are no recent broadcasts from this address to display. このアドレスから表示する最近の配信はありません。 - + You are using TCP port %1. (This can be changed in the settings). - + 使用中のポート %1 (設定で変更できます)。 - + Bitmessage Bitmessage - + Identities アドレス一覧 - + New Identity 新しいアドレス - + Search 検索 - + All 全て - + To 宛先 - + From 送信元 - + Subject 題名 - + Message メッセージ - + Received 受信日時 - + Messages メッセージ - + Address book アドレス帳 - + Address アドレス - + Add Contact 連絡先を追加 - + Fetch Namecoin ID namecoin IDを取得 - + Subject: 題名: - + From: 送信元: - + To: 宛先: - + Send ordinary Message 通常のメッセージを送信 - + Send Message to your Subscribers 購読者にメッセージを送信 - + TTL: TTL: - + Subscriptions 購読リスト - + Add new Subscription 購読先を追加 - + Chans チャンネル - + Add Chan チャンネルを追加 - + File ファイル - + Settings 設定 - + Help ヘルプ - + Import keys 鍵をインポート - + Manage keys 鍵を管理 - + Ctrl+Q Ctrrl+Q - + F1 F1 - + Contact support お問い合わせサポート - + About 概要 - + Regenerate deterministic addresses deterministicアドレスを再生成 - + Delete all trashed messages ゴミ箱のメッセージを全て削除する - + Join / Create chan チャンネルに参加 / 作成 - + All accounts すべてのアカウント @@ -1130,77 +1101,77 @@ Are you sure you want to delete the channel? ズーム レベル %1% - + Error: You cannot add the same address to your list twice. Perhaps rename the existing one if you want. エラー: 同じアドレスを複数リストに追加する事はできません。既存の項目をリネームしてください。 - + Add new entry 新しい項目を追加 - + Display the %1 recent broadcast(s) from this address. - + このアドレスから%1の最新の配信を表示します。 - + New version of PyBitmessage is available: %1. Download it from https://github.com/Bitmessage/PyBitmessage/releases/latest 新しいバージョンの PyBitmessage が利用可能です: %1。 https://github.com/Bitmessage/PyBitmessage/releases/latest からダウンロードしてください - + Waiting for PoW to finish... %1% PoW(証明)が完了するのを待っています... %1% - + Shutting down Pybitmessage... %1% Pybitmessageをシャットダウンしています... %1% - + Waiting for objects to be sent... %1% オブジェクトの送信待ち... %1% - + Saving settings... %1% 設定を保存しています... %1% - + Shutting down core... %1% コアをシャットダウンしています... %1% - + Stopping notifications... %1% 通知を停止しています... %1% - + Shutdown imminent... %1% すぐにシャットダウンします... %1% - + %n hour(s) %n 時間 - + %n day(s) %n 日 - + Shutting down PyBitmessage... %1% PyBitmessageをシャットダウンしています... %1% - + Sent 送信済 @@ -1245,86 +1216,86 @@ Are you sure you want to delete the channel? アラート: ディスクまたはデータストレージのボリュームがいっぱいです。 Bitmessageが終了します。 - + Error! Could not find sender address (your address) in the keys.dat file. エラー! keys.datファイルで送信元アドレス (あなたのアドレス) を見つけることができませんでした。 - + Doing work necessary to send broadcast... 配信に必要な処理を行っています... - + Broadcast sent on %1 配信が送信されました %1 - + Encryption key was requested earlier. 暗号鍵は以前にリクエストされました。 - + Sending a request for the recipient's encryption key. 受信者の暗号鍵のリクエストを送信します。 - + Looking up the receiver's public key 受信者の公開鍵を探しています - + Problem: Destination is a mobile device who requests that the destination be included in the message but this is disallowed in your settings. %1 問題: メッセージに含まれた宛先のリクエストはモバイルデバイスですが、設定では許可されていません。 %1 - + Doing work necessary to send message. There is no required difficulty for version 2 addresses like this. メッセージの送信に必要な処理を行っています。 このようなバージョン2のアドレスには、必要な難易度はありません。 - + Doing work necessary to send message. Receiver's required difficulty: %1 and %2 メッセージの送信に必要な処理を行っています。 受信者の必要な難易度: %1 および %2 - + Problem: The work demanded by the recipient (%1 and %2) is more difficult than you are willing to do. %3 問題: 受信者が要求している処理 (%1 および %2) は、現在あなたが設定しているよりも高い難易度です。 %3 - + Problem: You are trying to send a message to yourself or a chan but your encryption key could not be found in the keys.dat file. Could not encrypt message. %1 問題: あなた自身またはチャンネルにメッセージを送信しようとしていますが、暗号鍵がkeys.datファイルに見つかりませんでした。 メッセージを暗号化できませんでした。 %1 - + Doing work necessary to send message. メッセージの送信に必要な処理を行っています。 - + Message sent. Waiting for acknowledgement. Sent on %1 メッセージを送信しました。 確認応答を待っています。 %1 で送信しました - + Doing work necessary to request encryption key. 暗号鍵のリクエストに必要な処理を行っています。 - + Broadcasting the public key request. This program will auto-retry if they are offline. 公開鍵のリクエストを配信しています。 このプログラムがオフラインの場合、自動的に再試行されます。 - + Sending public key request. Waiting for reply. Requested at %1 公開鍵のリクエストを送信しています。 返信を待っています。 %1 でリクエストしました @@ -1339,40 +1310,55 @@ Receiver's required difficulty: %1 and %2 UPnPポートマッピングを削除しました - + Mark all messages as read すべてのメッセージを既読にする - + Are you sure you would like to mark all messages read? すべてのメッセージを既読にしてもよろしいですか? - + Doing work necessary to send broadcast. 配信に必要な処理を行っています。 - + Proof of work pending PoW(証明)を待っています - + %n object(s) pending proof of work %n オブジェクトが証明待ち (PoW) - + %n object(s) waiting to be distributed %n オブジェクトが配布待ち - + Wait until these tasks finish? これらのタスクが完了するまで待ちますか? + + + Problem communicating with proxy: %1. Please check your network settings. + プロキシとの通信に問題があります: %1。 ネットワーク設定を確認してください。 + + + + SOCKS5 Authentication problem: %1. Please check your SOCKS5 settings. + SOCKS5認証に問題があります: %1。 SOCKS5の設定を確認してください。 + + + + The time on your computer, %1, may be wrong. Please verify your settings. + お使いのコンピュータの時間 %1 は間違っている可能性があります。 設定を確認してください。 + The name %1 was not found. @@ -1399,37 +1385,32 @@ Receiver's required difficulty: %1 and %2 名前 %1 は関連付けられた Bitmessage アドレスがありません。 - + Success! Namecoind version %1 running. 成功! Namecoind バージョン %1 が実行中。 - + Success! NMControll is up and running. 成功! NMControll が開始して実行中です。 - + Couldn't understand NMControl. NMControl を理解できませんでした。 - - - The connection to namecoin failed. - namecoin への接続に失敗しました。 - Your GPU(s) did not calculate correctly, disabling OpenCL. Please report to the developers. GPUが正しく求められないため、OpenCLが無効になりました。 開発者に報告してください。 - + Set notification sound... 通知音を設定... - + Welcome to easy and secure Bitmessage * send messages to other people @@ -1444,175 +1425,130 @@ Receiver's required difficulty: %1 and %2 - + not recommended for chans チャンネルにはお勧めしません - + Quiet Mode マナーモード - + Problems connecting? Try enabling UPnP in the Network Settings 接続に問題がありますか? ネットワーク設定でUPnPを有効にしてみてください - + You are trying to send an email instead of a bitmessage. This requires registering with a gateway. Attempt to register? Bitmessage の代わりにメールを送信しようとしています。 これは、ゲートウェイに登録する必要があります。 登録しますか? - + Error: Bitmessage addresses start with BM- Please check the recipient address %1 エラー: BitmessageのアドレスはBM-で始まります。 受信者のアドレス %1 を確認してください - + Error: The recipient address %1 is not typed or copied correctly. Please check it. エラー: 受信者のアドレス %1 は正しく入力、またはコピーされていません。確認して下さい。 - + Error: The recipient address %1 contains invalid characters. Please check it. エラー: 受信者のアドレス %1 は不正な文字を含んでいます。確認して下さい。 - + Error: The version of the recipient address %1 is too high. Either you need to upgrade your Bitmessage software or your acquaintance is being clever. エラー: 受信者アドレスのバージョン %1 は高すぎます。 Bitmessageソフトウェアをアップグレードする必要があるか、連絡先が賢明になっているかのいずれかです。 - + Error: Some data encoded in the recipient address %1 is too short. There might be something wrong with the software of your acquaintance. エラー: アドレス %1 でエンコードされたデータが短すぎます。連絡先のソフトウェアが何かしら誤っている可能性があります。 - + Error: Some data encoded in the recipient address %1 is too long. There might be something wrong with the software of your acquaintance. エラー: 受信者のアドレス %1 でエンコードされたデータが短すぎます。連絡先のソフトウェアが何かしら誤っている可能性があります。 - + Error: Some data encoded in the recipient address %1 is malformed. There might be something wrong with the software of your acquaintance. エラー: 受信者のアドレス %1 でエンコードされたデータの一部が不正です。連絡先のソフトウェアが何かしら誤っている可能性があります。 - + Error: Something is wrong with the recipient address %1. エラー: 受信者のアドレス %1 には何かしら誤りがあります。 - + Error: %1 - エラー: %1 + - + From %1 送信元 %1 - + Synchronisation pending 同期を保留しています - + Bitmessage hasn't synchronised with the network, %n object(s) to be downloaded. If you quit now, it may cause delivery delays. Wait until the synchronisation finishes? Bitmessageはネットワークと同期していません。%n のオブジェクトをダウンロードする必要があります。 今、終了すると、配送が遅れることがあります。 同期が完了するまで待ちますか? - + Not connected 未接続 - + Bitmessage isn't connected to the network. If you quit now, it may cause delivery delays. Wait until connected and the synchronisation finishes? Bitmessageはネットワークに接続していません。 今、終了すると、配送が遅れることがあります。 接続して、同期が完了するまで待ちますか? - + Waiting for network connection... ネットワーク接続を待っています... - + Waiting for finishing synchronisation... 同期の完了を待っています... - + You have already set a notification sound for this address book entry. Do you really want to overwrite it? すでにこのアドレス帳エントリの通知音を設定しています。 上書きしてもよろしいですか? - - - Error occurred: could not load message from disk. - エラーが発生しました: ディスクからメッセージを読み込みできません。 - - - - Display the %n recent broadcast(s) from this address. - このアドレスから%nの最新の配信を表示します。 - - - - Go online - オンラインにする - - - - Go offline - オフラインにする - - - - Clear - クリア - - - - inbox - 受信トレイ - - - - new - 新規 - - - - sent - 送信済 - - - - trash - ゴミ箱 - MessageView - + Follow external link 外部リンクをフォロー - + The link "%1" will open in a browser. It may be a security risk, it could de-anonymise you or download malicious data. Are you sure? リンク "%1" はブラウザで開きます。 セキュリティリスクの可能性があります。匿名性がなくなったり、悪意のあるデータをダウンロードする可能性があります。 よろしいですか? - + HTML detected, click here to display HTMLが検出されました。ここをクリックすると表示します - + Click here to disable HTML ここをクリックするとHTMLを無効にします @@ -1620,14 +1556,14 @@ Receiver's required difficulty: %1 and %2 MsgDecode - + The message has an unknown encoding. Perhaps you should upgrade Bitmessage. メッセージのエンコードが不明です。 Bitmessageをアップグレードする必要があるかもしれません。 - + Unknown encoding 不明なエンコード @@ -1635,98 +1571,98 @@ Bitmessageをアップグレードする必要があるかもしれません。< NewAddressDialog - + Create new Address 新しいアドレスを作成 - + Here you may generate as many addresses as you like. Indeed, creating and abandoning addresses is encouraged. You may generate addresses by using either random numbers or by using a passphrase. If you use a passphrase, the address is called a "deterministic" address. The 'Random Number' option is selected by default but deterministic addresses have several pros and cons: 複数のアドレスを生成できます。アドレスを自由に生成、破棄することができます。アドレスは乱数かパスフレーズを使って生成できます。もしパスフレーズを使う場合、アドレスはdeterministicアドレスになります。デフォルトでは乱数による生成が選択されますが、deterministicアドレスにも長所と短所があります: - + <html><head/><body><p><span style=" font-weight:600;">Pros:<br/></span>You can recreate your addresses on any computer from memory. <br/>You need-not worry about backing up your keys.dat file as long as you can remember your passphrase. <br/><span style=" font-weight:600;">Cons:<br/></span>You must remember (or write down) your passphrase if you expect to be able to recreate your keys if they are lost. <br/>You must remember the address version number and the stream number along with your passphrase. <br/>If you choose a weak passphrase and someone on the Internet can brute-force it, they can read your messages and send messages as you.</p></body></html> <html><head/><body><p><span style=" font-weight:600;">長所:<br/></span>記憶を頼りにアドレスを再生成できます。<br/>keys.datファイルのバックアップの心配をしないでも、パスフレーズを覚えておけばよくなります。<br/><span style=" font-weight:600;">短所:<br/></span>アドレスの暗号鍵を紛失した場合に備えてアドレスを再生成出来るようにしたい場合、パスフレーズを覚えて(もしくは書き留めて)必要があります。<br/>パスフレーズを覚えておくのに加えて、アドレスのバージョン番号とストリーム番号も覚えておく必要があります。<br/>弱いパスフレーズを設定すると、ネット上の誰かがブルートフォース攻撃を行ってあなたの送信メッセージ、受信メッセージを読んでしまう可能性があります。</p></body></html> - + Use a random number generator to make an address アドレスの生成に乱数ジェネレーターを使う - + Use a passphrase to make addresses アドレスの作成にパスフレーズを使う - + Spend several minutes of extra computing time to make the address(es) 1 or 2 characters shorter アドレスを1、2文字短くするために数分間追加の計算処理を行う - + Make deterministic addresses deterministicアドレスを作る - + Address version number: 4 アドレスのバージョン番号: 4 - + In addition to your passphrase, you must remember these numbers: パスフレーズに加えて、これらの値を覚えておいてください: - + Passphrase パスフレーズ - + Number of addresses to make based on your passphrase: パスフレーズから生成されたアドレスの数: - + Stream number: 1 ストリーム数: 1 - + Retype passphrase パスフレーズを再入力 - + Randomly generate address ランダムなアドレスを生成する - + Label (not shown to anyone except you) ラベル(他の人からは見えません) - + Use the most available stream 最も有効なストリームを使う - + (best if this is the first of many addresses you will create) (もしこれから複数のアドレスを生成するのであれば、最初の一つに最適です。) - + Use the same stream as an existing address 既存のアドレスと同じストリームを利用する - + (saves you some bandwidth and processing power) (帯域と処理能力を節約する) @@ -1734,22 +1670,22 @@ The 'Random Number' option is selected by default but deterministic ad NewSubscriptionDialog - + Add new entry 新しい項目を追加 - + Label ラベル - + Address アドレス - + Enter an address above. 上にアドレスを入力してください。 @@ -1757,60 +1693,55 @@ The 'Random Number' option is selected by default but deterministic ad SpecialAddressBehaviorDialog - + Special Address Behavior アドレスの特別な動作 - + Behave as a normal address 通常のアドレスにする - + Behave as a pseudo-mailing-list address 仮想メーリングリストとして使用する - + Mail received to a pseudo-mailing-list address will be automatically broadcast to subscribers (and thus will be public). 仮想メーリングリストのアドレスが受信したアドレスは自動的に購読するユーザーに配信(公開)されます。 - + Name of the pseudo-mailing-list: 仮想メーリングリストの名前: - - - This is a chan address. You cannot use it as a pseudo-mailing list. - chanアドレスは仮想メーリングリストのアドレスには使用できません。 - aboutDialog - + About 概要 - - - PyBitmessage - - - version ? - + PyBitmessage + PyBitmessage - + + version ? + バージョン? + + + <html><head/><body><p>Distributed under the MIT/X11 software license; see <a href="http://www.opensource.org/licenses/mit-license.php"><span style=" text-decoration: underline; color:#0000ff;">http://www.opensource.org/licenses/mit-license.php</span></a></p></body></html> <html><head/><body><p>MIT/X11 ソフトウェアライセンスに基づいて配布されます。 <a href="http://www.opensource.org/licenses/mit-license.php"><span style=" text-decoration: underline; color:#0000ff;">http://www.opensource.org/licenses/mit-license.php</span></a> をご覧ください</p></body></html> - + This is Beta software. このソフトウェアはベータ版です。 @@ -1819,10 +1750,10 @@ The 'Random Number' option is selected by default but deterministic ad <html><head/><body><p>Copyright © 2012-2016 Jonathan Warren<br/>Copyright © 2013-2016 The Bitmessage Developers</p></body></html> - - - <html><head/><body><p>Copyright © 2012-2016 Jonathan Warren<br/>Copyright © 2013-2017 The Bitmessage Developers</p></body></html> - <html><head/><body><p>Copyright © 2012-2016 Jonathan Warren<br/>Copyright © 2013-2017 The Bitmessage Developers</p></body></html> + + + <html><head/><body><p>Copyright &copy; 2012-2016 Jonathan Warren<br/>Copyright &copy; 2013-2016 The Bitmessage Developers</p></body></html> + <html><head/><body><p>Copyright &copy; 2012-2016 Jonathan Warren<br/>Copyright &copy; 2013-2016 The Bitmessage 開発者</p></body></html> @@ -1853,12 +1784,12 @@ The 'Random Number' option is selected by default but deterministic ad アドレス - + Blacklist ブラックリスト - + Whitelist ホワイトリスト @@ -1866,45 +1797,40 @@ The 'Random Number' option is selected by default but deterministic ad connectDialog - + Bitmessage Bitmessage - + Bitmessage won't connect to anyone until you let it. Bitmessageはあなたが操作しない限りどこへも接続しません。 - + Connect now 接続 - + Let me configure special network settings first 最初に特別なネットワークの設定を行ってください - - - Work offline - - helpDialog - + Help ヘルプ - + <a href="https://bitmessage.org/wiki/PyBitmessage_Help">https://bitmessage.org/wiki/PyBitmessage_Help</a> <a href="https://bitmessage.org/wiki/PyBitmessage_Help">https://bitmessage.org/wiki/PyBitmessage_Help</a> - + As Bitmessage is a collaborative project, help can be found online in the Bitmessage Wiki: Bitmessageは協働プロジェクトです。ヘルプはBitmessage Wikiを参照してください: @@ -1912,35 +1838,30 @@ The 'Random Number' option is selected by default but deterministic ad iconGlossaryDialog - + Icon Glossary アイコン一覧 - + You have no connections with other peers. 他のpeerへ接続されていません。 - + You have made at least one connection to a peer using an outgoing connection but you have not yet received any incoming connections. Your firewall or home router probably isn't configured to forward incoming TCP connections to your computer. Bitmessage will work just fine but it would help the Bitmessage network if you allowed for incoming connections and will help you be a better-connected node. 発信接続のために1つ以上のピアへ接続を行っていますが、まだ着信接続を受け取っていません。ファイアーウォールかホームルーターが外部からこのコンピューターへのTCP接続を受け取れるように設定されていないかも知れません。Bitmessageは正常に動作しますが、外部からの接続を許可してより良く接続されたノードになることはBitmessageネットワークへの助けになります。 You are using TCP port ?. (This can be changed in the settings). - + 使用中のポート ? (設定で変更できます)。 - + You do have connections with other peers and your firewall is correctly configured. ファイアーウォールを適切に設定し、他のpeerへ接続してください。 - - - You are using TCP port %1. (This can be changed in the settings). - 使用中のポート %1 (設定で変更できます)。 - networkstatus @@ -1950,37 +1871,37 @@ The 'Random Number' option is selected by default but deterministic ad 接続数: - + Since startup: 起動日時: - + Processed 0 person-to-person messages. 0 通の1対1のメッセージを処理しました。 - + Processed 0 public keys. 0 件の公開鍵を処理しました。 - + Processed 0 broadcasts. 0 件の配信を処理しました。 - + Inventory lookups per second: 0 毎秒のインベントリ検索: 0 - + Objects to be synced: 同期する必要のあるオブジェクト: - + Stream # ストリーム # @@ -1990,112 +1911,112 @@ The 'Random Number' option is selected by default but deterministic ad - + Since startup on %1 起動日時 %1 - + Down: %1/s Total: %2 ダウン: %1/秒 合計: %2 - + Up: %1/s Total: %2 アップ: %1/秒 合計: %2 - + Total Connections: %1 接続数: %1 - + Inventory lookups per second: %1 毎秒のインベントリ検索: %1 - + Up: 0 kB/s アップ: 0 kB/秒 - + Down: 0 kB/s ダウン: 0 kB/秒 - + Network Status ネットワークの状態 - + byte(s) バイト - + Object(s) to be synced: %n 同期する必要のあるオブジェクト: %n - + Processed %n person-to-person message(s). %n 通の1対1のメッセージを処理しました。 - + Processed %n broadcast message(s). %n 件の配信を処理しました。 - + Processed %n public key(s). %n 件の公開鍵を処理しました。 - + Peer ピア - + IP address or hostname IP アドレスまたはホスト名 - + Rating 評価 - + PyBitmessage tracks the success rate of connection attempts to individual nodes. The rating ranges from -1 to 1 and affects the likelihood of selecting the node in the future PyBitmessage は、個々のノードへの接続試行の成功率を追跡します。 率は -1 から 1 の範囲で、将来ノードを選択する可能性に影響します - + User agent ユーザーエージェント - + Peer's self-reported software ピアの自己報告ソフトウェア - + TLS TLS - + Connection encryption 接続暗号化 - + List of streams negotiated between you and the peer あなたとピアの間でネゴシエーションしたストリームのリスト @@ -2155,7 +2076,7 @@ The 'Random Number' option is selected by default but deterministic ad Chan passphrase/name: - チャンネルのパスフレーズ/名前: + @@ -2181,12 +2102,12 @@ The 'Random Number' option is selected by default but deterministic ad チャンネル %1 を正常に作成 / 参加しました - + Chan creation / joining failed チャンネルの作成 / 参加に失敗しました - + Chan creation / joining cancelled チャンネルの作成 / 参加をキャンセルしました @@ -2220,52 +2141,52 @@ The 'Random Number' option is selected by default but deterministic ad regenerateAddressesDialog - + Regenerate Existing Addresses 既存のアドレスを再生成する - + Regenerate existing addresses - + 既存のアドレスを再生成する - + Passphrase パスフレーズ - + Number of addresses to make based on your passphrase: パスフレーズから生成されたアドレスの数: - + Address version number: アドレスのバージョン番号: - + Stream number: ストリーム数: - + 1 1 - + Spend several minutes of extra computing time to make the address(es) 1 or 2 characters shorter アドレスを1、2文字短くするために数分間追加の計算処理を行う - + You must check (or not check) this box just like you did (or didn't) when you made your addresses the first time. もしあなたが初めてアドレスを作ったのであればこのボックスをチェックする必要があります。(そうでない場合はしないでください)。 - + If you have previously made deterministic addresses but lost them due to an accident (like hard drive failure), you can regenerate them here. If you used the random number generator to make your addresses then this form will be of no use to you. もし以前にdeterministicアドレスを作ったことがあり、何かしらのトラブル(ハードディスクの故障のような)でそれを紛失していた場合、ここで再生成することができます。もし乱数でアドレスを作っていたのであればこのフォームは再生成には使えません。 diff --git a/src/translations/bitmessage_pl.qm b/src/translations/bitmessage_pl.qm index 94e7b8ca..3b9a0dcc 100644 Binary files a/src/translations/bitmessage_pl.qm and b/src/translations/bitmessage_pl.qm differ diff --git a/src/translations/bitmessage_pl.ts b/src/translations/bitmessage_pl.ts index c10259d7..c97cb4bb 100644 --- a/src/translations/bitmessage_pl.ts +++ b/src/translations/bitmessage_pl.ts @@ -60,27 +60,27 @@ @mailchuck.com - + Registration failed: Rejestracja nie powiodła się: - + The requested email address is not available, please try a new one. Wybrany adres e-mail nie jest dostępny, proszę spróbować inny. - + Sending email gateway registration request Wysyłanie zapytania o rejestrację na bramce poczty - + Sending email gateway unregistration request Wysyłanie zapytania o wyrejestrowanie z bramki poczty - + Sending email gateway status request Wysyłanie zapytania o stan bramki poczty @@ -199,52 +199,52 @@ Please type the desired email address (including @mailchuck.com) below: MainWindow - + Reply to sender Odpowiedz do nadawcy - + Reply to channel Odpowiedz do kanału - + Add sender to your Address Book Dodaj nadawcę do Książki Adresowej - + Add sender to your Blacklist Dodaj nadawcę do Listy Blokowanych - + Move to Trash Przenieś do kosza - + Undelete Przywróć - + View HTML code as formatted text Wyświetl kod HTML w postaci sformatowanej - + Save message as... Zapisz wiadomość jako… - + Mark Unread Oznacz jako nieprzeczytane - + New Nowe @@ -269,12 +269,12 @@ Please type the desired email address (including @mailchuck.com) below: Kopiuj adres do schowka - + Special address behavior... Specjalne zachowanie adresu… - + Email gateway Przekaźnik e-mail @@ -284,37 +284,37 @@ Please type the desired email address (including @mailchuck.com) below: Usuń - + Send message to this address Wyślij wiadomość pod ten adres - + Subscribe to this address Subskrybuj ten adres - + Add New Address Dodaj nowy adres - + Copy destination address to clipboard Kopiuj adres odbiorcy do schowka - + Force send Wymuś wysłanie - + One of your addresses, %1, is an old version 1 address. Version 1 addresses are no longer supported. May we delete it now? Jeden z adresów, %1, jest starym adresem wersji 1. Adresy tej wersji nie są już wspierane. Usunąć go? - + Waiting for their encryption key. Will request it again soon. Oczekiwanie na klucz szyfrujący odbiorcy. Niedługo nastąpi ponowne wysłanie o niego prośby. @@ -324,17 +324,17 @@ Please type the desired email address (including @mailchuck.com) below: - + Queued. W kolejce do wysłania. - + Message sent. Waiting for acknowledgement. Sent at %1 Wiadomość wysłana. Oczekiwanie na potwierdzenie odbioru. Wysłano o %1 - + Message sent. Sent at %1 Wiadomość wysłana. Wysłano o %1 @@ -344,77 +344,77 @@ Please type the desired email address (including @mailchuck.com) below: - + Acknowledgement of the message received %1 Otrzymano potwierdzenie odbioru wiadomości %1 - + Broadcast queued. Przekaz w kolejce do wysłania. - + Broadcast on %1 Wysłana o %1 - + Problem: The work demanded by the recipient is more difficult than you are willing to do. %1 Problem: dowód pracy wymagany przez odbiorcę jest trudniejszy niż zaakceptowany przez Ciebie. %1 - + Problem: The recipient's encryption key is no good. Could not encrypt message. %1 Problem: klucz szyfrujący odbiorcy jest nieprawidłowy. Nie można zaszyfrować wiadomości. %1 - + Forced difficulty override. Send should start soon. Wymuszono ominięcie trudności. Wysłanie zostanie wkrótce rozpoczęte. - + Unknown status: %1 %2 Nieznany status: %1 %2 - + Not Connected Brak połączenia - + Show Bitmessage Pokaż Bitmessage - + Send Wyślij - + Subscribe Subskrybuj - + Channel Kanał - + Quit Zamknij - + You may manage your keys by editing the keys.dat file stored in the same directory as this program. It is important that you back up this file. Możesz zarządzać swoimi kluczami edytując plik keys.dat znajdujący się w tym samym katalogu co program. Zaleca się zrobienie kopii zapasowej tego pliku. - + You may manage your keys by editing the keys.dat file stored in %1 It is important that you back up this file. @@ -423,17 +423,17 @@ It is important that you back up this file. Zaleca się zrobienie kopii zapasowej tego pliku. - + Open keys.dat? Otworzyć plik keys.dat? - + You may manage your keys by editing the keys.dat file stored in the same directory as this program. It is important that you back up this file. Would you like to open the file now? (Be sure to close Bitmessage before making any changes.) Możesz zarządzać swoimi kluczami edytując plik keys.dat znajdujący się w tym samym katalogu co program. Zaleca się zrobienie kopii zapasowej tego pliku. Czy chcesz otworzyć ten plik teraz? (Zamknij Bitmessage, przed wprowadzeniem jakichkolwiek zmian.) - + You may manage your keys by editing the keys.dat file stored in %1 It is important that you back up this file. Would you like to open the file now? (Be sure to close Bitmessage before making any changes.) @@ -442,37 +442,37 @@ It is important that you back up this file. Would you like to open the file now? Zaleca się zrobienie kopii zapasowej tego pliku. Czy chcesz otworzyć ten plik teraz? (Zamknij Bitmessage przed wprowadzeniem jakichkolwiek zmian.) - + Delete trash? Opróżnić kosz? - + Are you sure you want to delete all trashed messages? Czy na pewno usunąć wszystkie wiadomości z kosza? - + bad passphrase nieprawidłowe hasło - + You must type your passphrase. If you don't have one then this is not the form for you. Musisz wpisać swoje hasło. Jeżeli go nie posiadasz, to ten formularz nie jest dla Ciebie. - + Bad address version number Nieprawidłowy numer wersji adresu - + Your address version number must be a number: either 3 or 4. Twój numer wersji adresu powinien wynosić: 3 lub 4. - + Your address version number must be either 3 or 4. Twój numer wersji adresu powinien wynosić: 3 lub 4. @@ -542,22 +542,22 @@ Zaleca się zrobienie kopii zapasowej tego pliku. Czy chcesz otworzyć ten plik - + Connection lost Połączenie utracone - + Connected Połączono - + Message trashed Wiadomość usunięta - + The TTL, or Time-To-Live is the length of time that the network will hold the message. The recipient must get it during this time. If your Bitmessage client does not hear an acknowledgement, it will resend the message automatically. The longer the Time-To-Live, the @@ -568,17 +568,17 @@ Im dłuższy TTL, tym więcej pracy będzie musiał wykonac komputer wysyłając Zwykle 4-5 dniowy TTL jest odpowiedni. - + Message too long Wiadomość zbyt długa - + The message that you are trying to send is too long by %1 bytes. (The maximum is 261644 bytes). Please cut it down before sending. Wiadomość jest za długa o %1 bajtów (maksymalna długość wynosi 261644 bajty). Przed wysłaniem należy ją skrócić. - + Error: Your account wasn't registered at an email gateway. Sending registration now as %1, please wait for the registration to be processed before retrying sending. Błąd: Twoje konto nie było zarejestrowane w bramce poczty. Rejestrowanie jako %1, proszę poczekać na zakończenie procesu przed ponowną próbą wysłania wiadomości. @@ -623,57 +623,57 @@ Zwykle 4-5 dniowy TTL jest odpowiedni. - + Error: You must specify a From address. If you don't have one, go to the 'Your Identities' tab. Błąd: musisz wybrać adres wysyłania. Jeżeli go nie posiadasz, przejdź do zakładki 'Twoje tożsamości'. - + Address version number Numer wersji adresu - + Concerning the address %1, Bitmessage cannot understand address version numbers of %2. Perhaps upgrade Bitmessage to the latest version. Odnośnie adresu %1, Bitmessage nie potrafi odczytać wersji adresu %2. Może uaktualnij Bitmessage do najnowszej wersji. - + Stream number Numer strumienia - + Concerning the address %1, Bitmessage cannot handle stream numbers of %2. Perhaps upgrade Bitmessage to the latest version. Odnośnie adresu %1, Bitmessage nie potrafi operować na strumieniu adresu %2. Może uaktualnij Bitmessage do najnowszej wersji. - + Warning: You are currently not connected. Bitmessage will do the work necessary to send the message but it won't send until you connect. Uwaga: nie jesteś obecnie połączony. Bitmessage wykona niezbędną pracę do wysłania wiadomości, ale nie wyśle jej póki się nie połączysz. - + Message queued. W kolejce do wysłania - + Your 'To' field is empty. Pole 'Do' jest puste - + Right click one or more entries in your address book and select 'Send message to this address'. Użyj prawego przycisku myszy na adresie z książki adresowej i wybierz opcję "Wyślij wiadomość do tego adresu". - + Fetched address from namecoin identity. Pobrano adres z identyfikatora Namecoin. - + New Message Nowa wiadomość @@ -698,47 +698,47 @@ Zwykle 4-5 dniowy TTL jest odpowiedni. Wprowadzono niewłaściwy adres, który został zignorowany. - + Error: You cannot add the same address to your address book twice. Try renaming the existing one if you want. Błąd: Adres znajduje się już w książce adresowej. - + Error: You cannot add the same address to your subscriptions twice. Perhaps rename the existing one if you want. Błąd: Adres znajduje się już na liście subskrybcji. - + Restart Uruchom ponownie - + You must restart Bitmessage for the port number change to take effect. Musisz zrestartować Bitmessage, aby zmiana numeru portu weszła w życie. - + Bitmessage will use your proxy from now on but you may want to manually restart Bitmessage now to close existing connections (if any). Bitmessage będzie of teraz korzystał z serwera proxy, ale możesz ręcznie zrestartować Bitmessage, aby zamknąć obecne połączenia (jeżeli występują). - + Number needed Wymagany numer - + Your maximum download and upload rate must be numbers. Ignoring what you typed. Maksymalne prędkości wysyłania i pobierania powinny być liczbami. Zignorowano zmiany. - + Will not resend ever Nigdy nie wysyłaj ponownie - + Note that the time limit you entered is less than the amount of time Bitmessage waits for the first resend attempt therefore your messages will never be resent. Zauważ, że wpisany limit czasu wynosi mniej niż czas, który Bitmessage czeka przed pierwszą ponowną próbą wysłania wiadomości, więc Twoje wiadomości nie zostaną nigdy wysłane ponownie. @@ -773,22 +773,22 @@ Zwykle 4-5 dniowy TTL jest odpowiedni. Naprawdę musisz wpisać hasło. - + Address is gone Adres zniknął - + Bitmessage cannot find your address %1. Perhaps you removed it? Bitmessage nie może odnaleźć Twojego adresu %1. Może go usunąłeś? - + Address disabled Adres nieaktywny - + Error: The address from which you are trying to send is disabled. You'll have to enable it on the 'Your Identities' tab before using it. Błąd: adres, z którego próbowałeś wysłać wiadomość jest nieaktywny. Włącz go w zakładce 'Twoje tożsamości' zanim go użyjesz. @@ -798,42 +798,42 @@ Zwykle 4-5 dniowy TTL jest odpowiedni. - + Entry added to the blacklist. Edit the label to your liking. Dodano wpis do listy blokowanych. Można teraz zmienić jego nazwę. - + Error: You cannot add the same address to your blacklist twice. Try renaming the existing one if you want. Błąd: Adres znajduje się już na liście blokowanych. - + Moved items to trash. Przeniesiono wiadomości do kosza. - + Undeleted item. Przywrócono wiadomość. - + Save As... Zapisz jako… - + Write error. Błąd zapisu. - + No addresses selected. Nie wybrano adresu. - + If you delete the subscription, messages that you already received will become inaccessible. Maybe you can consider disabling the subscription instead. Disabled subscriptions will not receive new messages, but you can still view messages you already received. Are you sure you want to delete the subscription? @@ -842,7 +842,7 @@ Are you sure you want to delete the subscription? Czy na pewno chcesz usunąć tę subskrypcję? - + If you delete the channel, messages that you already received will become inaccessible. Maybe you can consider disabling the channel instead. Disabled channels will not receive new messages, but you can still view messages you already received. Are you sure you want to delete the channel? @@ -851,32 +851,32 @@ Are you sure you want to delete the channel? Czy na pewno chcesz usunąć ten kanał? - + Do you really want to remove this avatar? Czy na pewno chcesz usunąć ten awatar? - + You have already set an avatar for this address. Do you really want to overwrite it? Już ustawiłeś awatar dla tego adresu. Czy na pewno chcesz go nadpisać? - + Start-on-login not yet supported on your OS. Start po zalogowaniu jeszcze nie jest wspierany pod Twoim systemem. - + Minimize-to-tray not yet supported on your OS. Minimalizacja do zasobnika nie jest jeszcze wspierana pod Twoim systemem. - + Tray notifications not yet supported on your OS. Powiadomienia w zasobniku nie są jeszcze wspierane pod Twoim systemem. - + Testing... Testowanie… @@ -941,192 +941,192 @@ Czy na pewno chcesz usunąć ten kanał? - + Bitmessage Bitmessage - + Identities Tożsamości - + New Identity Nowa tożsamość - + Search Szukaj - + All Wszystkie - + To Do - + From Od - + Subject Temat - + Message Wiadomość - + Received Odebrana - + Messages Wiadomości - + Address book Książka adresowa - + Address Adres - + Add Contact Dodaj kontakt - + Fetch Namecoin ID Pobierz Namecoin ID - + Subject: Temat: - + From: Od: - + To: Do: - + Send ordinary Message Wyślij zwykłą wiadomość - + Send Message to your Subscribers Wyślij wiadomość broadcast - + TTL: Czas życia: - + Subscriptions Subskrypcje - + Add new Subscription Dodaj subskrypcję - + Chans Kanały - + Add Chan Dodaj kanał - + File Plik - + Settings Ustawienia - + Help Pomoc - + Import keys Importuj klucze - + Manage keys Zarządzaj kluczami - + Ctrl+Q Ctrl+Q - + F1 F1 - + Contact support Kontakt z twórcami - + About O programie - + Regenerate deterministic addresses Odtwórz adres deterministyczny - + Delete all trashed messages Usuń wiadomości z kosza - + Join / Create chan Dołącz / Utwórz kanał - + All accounts Wszystkie konta @@ -1146,67 +1146,67 @@ Czy na pewno chcesz usunąć ten kanał? Dodaj nowy wpis - + Display the %1 recent broadcast(s) from this address. - + Wyświetl %1 ostatnich wiadomości subskrypcji z tego adresu. - + New version of PyBitmessage is available: %1. Download it from https://github.com/Bitmessage/PyBitmessage/releases/latest Nowa wersja Bitmessage jest dostępna: %1. Pobierz ją z https://github.com/Bitmessage/PyBitmessage/releases/latest - + Waiting for PoW to finish... %1% Oczekiwanie na wykonanie dowodu pracy… %1% - + Shutting down Pybitmessage... %1% Zamykanie PyBitmessage… %1% - + Waiting for objects to be sent... %1% Oczekiwanie na wysłanie obiektów… %1% - + Saving settings... %1% Zapisywanie ustawień… %1% - + Shutting down core... %1% Zamykanie rdzenia programu… %1% - + Stopping notifications... %1% Zatrzymywanie powiadomień… %1% - + Shutdown imminent... %1% Zaraz zamknę… %1% - + %n hour(s) %n godzina%n godziny%n godzin%n godzin - + %n day(s) %n dzień%n dni%n dni%n dni - + Shutting down PyBitmessage... %1% Zamykanie PyBitmessage… %1% - + Sent Wysłane @@ -1310,7 +1310,7 @@ Odbiorca wymaga trudności: %1 i %2 Problem: próbujesz wysłać wiadomość do siebie lub na kanał, ale Twój klucz szyfrujący nie został znaleziony w pliku keys.dat. Nie można zaszyfrować wiadomości. %1 - + Doing work necessary to send message. Wykonywanie pracy potrzebnej do wysłania wiadomości. @@ -1320,7 +1320,7 @@ Odbiorca wymaga trudności: %1 i %2 Wiadomość wysłana. Oczekiwanie na potwierdzenie odbioru. Wysłano o %1 - + Doing work necessary to request encryption key. Wykonywanie pracy niezbędnej do prośby o klucz szyfrujący. @@ -1345,37 +1345,37 @@ Odbiorca wymaga trudności: %1 i %2 Usunięto mapowanie portów UPnP - + Mark all messages as read Oznacz wszystkie jako przeczytane - + Are you sure you would like to mark all messages read? Czy na pewno chcesz oznaczyć wszystkie wiadomości jako przeczytane? - + Doing work necessary to send broadcast. Wykonywanie dowodu pracy niezbędnego do wysłania przekazu. - + Proof of work pending Dowód pracy zawieszony - + %n object(s) pending proof of work Zawieszony dowód pracy %n obiektuZawieszony dowód pracy %n obiektówZawieszony dowód pracy %n obiektówZawieszony dowód pracy %n obiektów - + %n object(s) waiting to be distributed %n obiekt oczekuje na wysłanie%n obiektów oczekuje na wysłanie%n obiektów oczekuje na wysłanie%n obiektów oczekuje na wysłanie - + Wait until these tasks finish? Czy poczekać aż te zadania zostaną zakończone? @@ -1420,37 +1420,32 @@ Odbiorca wymaga trudności: %1 i %2 Ksywka %1 nie ma powiązanego adresu Bitmessage. - + Success! Namecoind version %1 running. Namecoind wersja %1 działa poprawnie! - + Success! NMControll is up and running. NMControl działa poprawnie! - + Couldn't understand NMControl. Nie można zrozumieć NMControl. - - - The connection to namecoin failed. - Nie udało się połączyć z namecoin. - Your GPU(s) did not calculate correctly, disabling OpenCL. Please report to the developers. Twoje procesory graficzne nie obliczyły poprawnie, wyłączam OpenCL. Prosimy zaraportować przypadek twórcom programu. - + Set notification sound... Ustaw dźwięk powiadomień… - + Welcome to easy and secure Bitmessage * send messages to other people @@ -1464,155 +1459,120 @@ Witamy w przyjaznym i bezpiecznym Bitmessage * dyskutuj na kanałach (chany) z innymi ludźmi - + not recommended for chans niezalecany dla kanałów - + Quiet Mode Tryb cichy - + Problems connecting? Try enabling UPnP in the Network Settings Problem z połączeniem? Spróbuj włączyć UPnP w ustawieniach sieci. - + You are trying to send an email instead of a bitmessage. This requires registering with a gateway. Attempt to register? Próbujesz wysłać e-mail zamiast wiadomość bitmessage. To wymaga zarejestrowania się na bramce. Czy zarejestrować? - + Error: Bitmessage addresses start with BM- Please check the recipient address %1 Błąd: adresy Bitmessage zaczynają się od BM-. Proszę sprawdzić adres odbiorcy %1. - + Error: The recipient address %1 is not typed or copied correctly. Please check it. Błąd: adres odbiorcy %1 nie został skopiowany lub przepisany poprawnie. Proszę go sprawdzić. - + Error: The recipient address %1 contains invalid characters. Please check it. Błąd: adres odbiorcy %1 zawiera nieprawidłowe znaki. Proszę go sprawdzić. - + Error: The version of the recipient address %1 is too high. Either you need to upgrade your Bitmessage software or your acquaintance is being clever. Błąd: wersja adresu odbiorcy %1 jest za wysoka. Musisz albo zaktualizować Twoje oprogramowanie Bitmessage, albo twój znajomy Cię trolluje. - + Error: Some data encoded in the recipient address %1 is too short. There might be something wrong with the software of your acquaintance. Błąd: niektóre dane zakodowane w adresie odbiorcy %1 są zbyt krótkie. Być może coś nie działa należycie w programie Twojego znajomego. - + Error: Some data encoded in the recipient address %1 is too long. There might be something wrong with the software of your acquaintance. Błąd: niektóre dane zakodowane w adresie odbiorcy %1 są zbyt długie. Być może coś nie działa należycie w programie Twojego znajomego. - + Error: Some data encoded in the recipient address %1 is malformed. There might be something wrong with the software of your acquaintance. Błąd: niektóre dane zakodowane w adresie odbiorcy %1 są uszkodzone. Być może coś nie działa należycie w programie Twojego znajomego. - + Error: Something is wrong with the recipient address %1. Błąd: coś jest nie tak z adresem odbiorcy %1. - + Error: %1 Błąd: %1 - + From %1 Od %1 - + Synchronisation pending Synchronizacja zawieszona - + Bitmessage hasn't synchronised with the network, %n object(s) to be downloaded. If you quit now, it may cause delivery delays. Wait until the synchronisation finishes? Bitmessage nie zsynchronizował się z siecią, %n obiekt oczekuje na pobranie. Jeżeli zamkniesz go teraz, może to spowodować opóźnienia dostarczeń. Czy poczekać na zakończenie synchronizacji?Bitmessage nie zsynchronizował się z siecią, %n obiekty oczekują na pobranie. Jeżeli zamkniesz go teraz, może to spowodować opóźnienia dostarczeń. Czy poczekać na zakończenie synchronizacji?Bitmessage nie zsynchronizował się z siecią, %n obiektów oczekuje na pobranie. Jeżeli zamkniesz go teraz, może to spowodować opóźnienia dostarczeń. Czy poczekać na zakończenie synchronizacji?Bitmessage nie zsynchronizował się z siecią, %n obiektów oczekuje na pobranie. Jeżeli zamkniesz go teraz, może to spowodować opóźnienia dostarczeń. Czy poczekać na zakończenie synchronizacji? - + Not connected Niepołączony - + Bitmessage isn't connected to the network. If you quit now, it may cause delivery delays. Wait until connected and the synchronisation finishes? Bitmessage nie połączył się z siecią. Jeżeli zamkniesz go teraz, może to spowodować opóźnienia dostarczeń. Czy poczekać na połączenie i zakończenie synchronizacji? - + Waiting for network connection... Oczekiwanie na połączenie sieciowe… - + Waiting for finishing synchronisation... Oczekiwanie na zakończenie synchronizacji… - + You have already set a notification sound for this address book entry. Do you really want to overwrite it? Już ustawiłeś dźwięk powiadomienia dla tego kontaktu. Czy chcesz go zastąpić? - - Error occurred: could not load message from disk. - Wystąpił błąd: nie można załadować wiadomości z dysku. - - - - Display the %n recent broadcast(s) from this address. - Wyświetl %n ostatnią wiadomość przekazu z tego adresu.Wyświetl %n ostatnią wiadomość przekazu z tego adresu.Wyświetl %n ostatnich wiadomości przekazu z tego adresu.Wyświetl %n ostatnich wiadomości przekazu z tego adresu. - - - + Go online Połącz - + Go offline Rozłącz - - - Clear - Wymaż - - - - inbox - odebrane - - - - new - nowe - - - - sent - wysłane - - - - trash - kosz - MessageView @@ -1640,14 +1600,14 @@ Witamy w przyjaznym i bezpiecznym Bitmessage MsgDecode - + The message has an unknown encoding. Perhaps you should upgrade Bitmessage. Wiadomość zawiera nierozpoznane kodowanie. Prawdopodobnie powinieneś zaktualizować Bitmessage. - + Unknown encoding Nierozpoznane kodowanie @@ -1803,7 +1763,7 @@ Generowanie adresów „losowych” jest wybrane domyślnie, jednak deterministy Nazwa pseudo-listy-dyskusyjnej: - + This is a chan address. You cannot use it as a pseudo-mailing list. To jest adres kanału. Nie możesz go użyć jako pseudo-listy-dyskusyjnej. @@ -1826,12 +1786,12 @@ Generowanie adresów „losowych” jest wybrane domyślnie, jednak deterministy - + <html><head/><body><p>Distributed under the MIT/X11 software license; see <a href="http://www.opensource.org/licenses/mit-license.php"><span style=" text-decoration: underline; color:#0000ff;">http://www.opensource.org/licenses/mit-license.php</span></a></p></body></html> <html><head/><body><p>Rozpowszechniane na licencji MIT/X11 software license; zobacz <a href="http://www.opensource.org/licenses/mit-license.php"><span style=" text-decoration: underline; color:#0000ff;">http://www.opensource.org/licenses/mit-license.php</span></a></p></body></html> - + This is Beta software. To jest wersja Beta. @@ -1841,7 +1801,7 @@ Generowanie adresów „losowych” jest wybrane domyślnie, jednak deterministy - + <html><head/><body><p>Copyright © 2012-2016 Jonathan Warren<br/>Copyright © 2013-2017 The Bitmessage Developers</p></body></html> <html><head/><body><p>Prawa autorskie © 2012-2016 Jonathan Warren<br/>Prawa autorskie © 2013-2017 Programiści Bitmessage</p></body></html> @@ -2011,27 +1971,27 @@ Generowanie adresów „losowych” jest wybrane domyślnie, jednak deterministy - + Since startup on %1 Od startu programu o %1 - + Down: %1/s Total: %2 Pobieranie: %1/s W całości: %2 - + Up: %1/s Total: %2 Wysyłanie: %1/s W całości: %2 - + Total Connections: %1 Wszystkich połączeń: %1 - + Inventory lookups per second: %1 Zapytań o elementy na sekundę: %1 @@ -2046,32 +2006,32 @@ Generowanie adresów „losowych” jest wybrane domyślnie, jednak deterministy Pobieranie: 0 kB/s - + Network Status Stan sieci - + byte(s) bajtbajtówbajtówbajtów - + Object(s) to be synced: %n Jeden obiekt do zsynchronizowaniaObieków do zsynchronizowania: %nObieków do zsynchronizowania: %nObieków do zsynchronizowania: %n - + Processed %n person-to-person message(s). Przetworzono %n wiadomość zwykłą.Przetworzono %n wiadomości zwykłych.Przetworzono %n wiadomości zwykłych.Przetworzono %n wiadomości zwykłych. - + Processed %n broadcast message(s). Przetworzono %n wiadomość subskrypcji.Przetworzono %n wiadomości subskrypcji.Przetworzono %n wiadomości subskrypcji.Przetworzono %n wiadomości subskrypcji. - + Processed %n public key(s). Przetworzono %n klucz publiczny.Przetworzono %n kluczy publicznych.Przetworzono %n kluczy publicznych.Przetworzono %n kluczy publicznych. diff --git a/src/translations/bitmessage_zh_cn.qm b/src/translations/bitmessage_zh_cn.qm index 204047e1..cc37b146 100644 Binary files a/src/translations/bitmessage_zh_cn.qm and b/src/translations/bitmessage_zh_cn.qm differ diff --git a/src/translations/bitmessage_zh_cn.ts b/src/translations/bitmessage_zh_cn.ts index 3a5c4aab..58e16cb8 100644 --- a/src/translations/bitmessage_zh_cn.ts +++ b/src/translations/bitmessage_zh_cn.ts @@ -2,17 +2,17 @@ AddAddressDialog - + Add new entry 添加新条目 - + Label 标签 - + Address 地址 @@ -20,99 +20,69 @@ EmailGatewayDialog - + Email gateway 电子邮件网关 - + Register on email gateway 注册电子邮件网关 - + Account status at email gateway 电子邮件网关帐户状态 - + Change account settings at email gateway 更改电子邮件网关帐户设置 - + Unregister from email gateway 取消电子邮件网关注册 - + Email gateway allows you to communicate with email users. Currently, only the Mailchuck email gateway (@mailchuck.com) is available. 电子邮件网关允许您与电子邮件用户通信。目前,只有Mailchuck电子邮件网关(@mailchuck.com)可用。 - + Desired email address (including @mailchuck.com): 所需的电子邮件地址(包括 @mailchuck.com): - - - @mailchuck.com - @mailchuck.com - - - - Registration failed: - 注册失败: - - - - The requested email address is not available, please try a new one. - 请求的电子邮件地址不可用,请换一个新的试试。 - - - - Sending email gateway registration request - 发送电​​子邮件网关注册请求 - - - - Sending email gateway unregistration request - 发送电​​子邮件网关注销请求 - - - - Sending email gateway status request - 发送电​​子邮件网关状态请求 - EmailGatewayRegistrationDialog - + Registration failed: - + 注册失败: - + The requested email address is not available, please try a new one. Fill out the new desired email address (including @mailchuck.com) below: - + 要求的电子邮件地址不详,请尝试一个新的。填写新的所需电子邮件地址(包括 @mailchuck.com)如下: Email gateway registration - + 电子邮件网关注册 Email gateway allows you to communicate with email users. Currently, only the Mailchuck email gateway (@mailchuck.com) is available. Please type the desired email address (including @mailchuck.com) below: - + 电子邮件网关允许您与电子邮件用户通信。目前,只有Mailchuck电子邮件网关(@mailchuck.com)可用。请键入所需的电子邮件地址(包括 @mailchuck.com)如下: Mailchuck - + # You can use this to configure your email gateway account # Uncomment the setting you want to use # Here are the options: @@ -196,52 +166,52 @@ Please type the desired email address (including @mailchuck.com) below: MainWindow - + Reply to sender 回复发件人 - + Reply to channel 回复通道 - + Add sender to your Address Book 将发送者添加到您的通讯簿 - + Add sender to your Blacklist 将发件人添加到您的黑名单 - + Move to Trash 移入回收站 - + Undelete 取消删除 - + View HTML code as formatted text 作为HTML查看 - + Save message as... 将消息保存为... - + Mark Unread 标记为未读 - + New 新建 @@ -266,12 +236,12 @@ Please type the desired email address (including @mailchuck.com) below: 将地址复制到剪贴板 - + Special address behavior... 特别的地址行为... - + Email gateway 电子邮件网关 @@ -281,37 +251,37 @@ Please type the desired email address (including @mailchuck.com) below: 删除 - + Send message to this address 发送消息到这个地址 - + Subscribe to this address 订阅到这个地址 - + Add New Address 创建新地址 - + Copy destination address to clipboard 复制目标地址到剪贴板 - + Force send 强制发送 - + One of your addresses, %1, is an old version 1 address. Version 1 addresses are no longer supported. May we delete it now? 您的地址中的一个, %1,是一个过时的版本1地址. 版本1地址已经不再受到支持了. 我们可以将它删除掉么? - + Waiting for their encryption key. Will request it again soon. 正在等待他们的加密密钥,我们会在稍后再次请求。 @@ -321,17 +291,17 @@ Please type the desired email address (including @mailchuck.com) below: - + Queued. 已经添加到队列。 - + Message sent. Waiting for acknowledgement. Sent at %1 消息已经发送. 正在等待回执. 发送于 %1 - + Message sent. Sent at %1 消息已经发送. 发送于 %1 @@ -341,131 +311,131 @@ Please type the desired email address (including @mailchuck.com) below: - + Acknowledgement of the message received %1 消息的回执已经收到于 %1 - + Broadcast queued. 广播已经添加到队列中。 - + Broadcast on %1 已经广播于 %1 - + Problem: The work demanded by the recipient is more difficult than you are willing to do. %1 错误: 收件人要求的做工量大于我们的最大接受做工量。 %1 - + Problem: The recipient's encryption key is no good. Could not encrypt message. %1 错误: 收件人的加密密钥是无效的。不能加密消息。 %1 - + Forced difficulty override. Send should start soon. 已经忽略最大做工量限制。发送很快就会开始。 - + Unknown status: %1 %2 未知状态: %1 %2 - + Not Connected 未连接 - + Show Bitmessage 显示比特信 - + Send 发送 - + Subscribe 订阅 - + Channel 频道 - + Quit 退出 - + You may manage your keys by editing the keys.dat file stored in the same directory as this program. It is important that you back up this file. 您可以通过编辑和程序储存在同一个目录的 keys.dat 来编辑密钥。备份这个文件十分重要。 - + You may manage your keys by editing the keys.dat file stored in %1 It is important that you back up this file. 您可以通过编辑储存在 %1 的 keys.dat 来编辑密钥。备份这个文件十分重要。 - + Open keys.dat? 打开 keys.dat ? - + You may manage your keys by editing the keys.dat file stored in the same directory as this program. It is important that you back up this file. Would you like to open the file now? (Be sure to close Bitmessage before making any changes.) 您可以通过编辑和程序储存在同一个目录的 keys.dat 来编辑密钥。备份这个文件十分重要。您现在想打开这个文件么?(请在进行任何修改前关闭比特信) - + You may manage your keys by editing the keys.dat file stored in %1 It is important that you back up this file. Would you like to open the file now? (Be sure to close Bitmessage before making any changes.) 您可以通过编辑储存在 %1 的 keys.dat 来编辑密钥。备份这个文件十分重要。您现在想打开这个文件么?(请在进行任何修改前关闭比特信) - + Delete trash? 清空回收站? - + Are you sure you want to delete all trashed messages? 您确定要删除全部被回收的消息么? - + bad passphrase 错误的密钥 - + You must type your passphrase. If you don't have one then this is not the form for you. 您必须输入您的密钥。如果您没有的话,这个表单不适用于您。 - + Bad address version number 地址的版本号无效 - + Your address version number must be a number: either 3 or 4. 您的地址的版本号必须是一个数字: 3 或 4. - + Your address version number must be either 3 or 4. 您的地址的版本号必须是 3 或 4. @@ -535,22 +505,22 @@ It is important that you back up this file. Would you like to open the file now? - + Connection lost 连接已丢失 - + Connected 已经连接 - + Message trashed 消息已经移入回收站 - + The TTL, or Time-To-Live is the length of time that the network will hold the message. The recipient must get it during this time. If your Bitmessage client does not hear an acknowledgement, it will resend the message automatically. The longer the Time-To-Live, the @@ -559,17 +529,17 @@ It is important that you back up this file. Would you like to open the file now? 收件人必须在此期间得到它. 如果您的Bitmessage客户沒有听到确认, 它会自动重新发送信息. Time-To-Live的时间越长, 您的电脑必须要做更多工作來发送信息. 四天或五天的 Time-To-Time, 经常是合适的. - + Message too long 信息太长 - + The message that you are trying to send is too long by %1 bytes. (The maximum is 261644 bytes). Please cut it down before sending. 你正在尝试发送的信息已超过%1个字节太长, (最大为261644个字节). 发送前请剪下来。 - + Error: Your account wasn't registered at an email gateway. Sending registration now as %1, please wait for the registration to be processed before retrying sending. 错误: 您的帐户没有在电子邮件网关注册。现在发送注册为%1​​, 注册正在处理请稍候重试发送. @@ -614,57 +584,57 @@ It is important that you back up this file. Would you like to open the file now? - + Error: You must specify a From address. If you don't have one, go to the 'Your Identities' tab. 错误: 您必须指出一个表单地址, 如果您没有,请到“您的身份”标签页。 - + Address version number 地址版本号 - + Concerning the address %1, Bitmessage cannot understand address version numbers of %2. Perhaps upgrade Bitmessage to the latest version. 地址 %1 的地址版本号 %2 无法被比特信理解。也许你应该升级你的比特信到最新版本。 - + Stream number 节点流序号 - + Concerning the address %1, Bitmessage cannot handle stream numbers of %2. Perhaps upgrade Bitmessage to the latest version. 地址 %1 的节点流序号 %2 无法被比特信理解。也许你应该升级你的比特信到最新版本。 - + Warning: You are currently not connected. Bitmessage will do the work necessary to send the message but it won't send until you connect. 警告: 您尚未连接。 比特信将做足够的功来发送消息,但是消息不会被发出直到您连接。 - + Message queued. 信息排队。 - + Your 'To' field is empty. “收件人"是空的。 - + Right click one or more entries in your address book and select 'Send message to this address'. 在您的地址本的一个条目上右击,之后选择”发送消息到这个地址“。 - + Fetched address from namecoin identity. 已经自namecoin接收了地址。 - + New Message 新消息 @@ -674,9 +644,9 @@ It is important that you back up this file. Would you like to open the file now? - + Sending email gateway registration request - + 发送电​​子邮件网关注册请求 @@ -689,142 +659,142 @@ It is important that you back up this file. Would you like to open the file now? 您输入的地址是无效的,将被忽略。 - + Error: You cannot add the same address to your address book twice. Try renaming the existing one if you want. 错误:您无法将一个地址添加到您的地址本两次,请尝试重命名已经存在的那个。 - + Error: You cannot add the same address to your subscriptions twice. Perhaps rename the existing one if you want. 错误: 您不能在同一地址添加到您的订阅两次. 也许您可重命名现有之一. - + Restart 重启 - + You must restart Bitmessage for the port number change to take effect. 您必须重启以便使比特信对于使用的端口的改变生效。 - + Bitmessage will use your proxy from now on but you may want to manually restart Bitmessage now to close existing connections (if any). 比特信将会从现在开始使用代理,但是您可能想手动重启比特信以便使之前的连接关闭(如果有的话)。 - + Number needed 需求数字 - + Your maximum download and upload rate must be numbers. Ignoring what you typed. 您最大的下载和上传速率必须是数字. 忽略您键入的内容. - + Will not resend ever 不尝试再次发送 - + Note that the time limit you entered is less than the amount of time Bitmessage waits for the first resend attempt therefore your messages will never be resent. 请注意,您所输入的时间限制小于比特信的最小重试时间,因此您将永远不会重发消息。 - + Sending email gateway unregistration request - + 发送电​​子邮件网关注销请求 - + Sending email gateway status request - + 发送电​​子邮件网关状态请求 - + Passphrase mismatch 密钥不匹配 - + The passphrase you entered twice doesn't match. Try again. 您两次输入的密码并不匹配,请再试一次。 - + Choose a passphrase 选择一个密钥 - + You really do need a passphrase. 您真的需要一个密码。 - + Address is gone 已经失去了地址 - + Bitmessage cannot find your address %1. Perhaps you removed it? 比特信无法找到你的地址 %1。 也许你已经把它删掉了? - + Address disabled 地址已经禁用 - + Error: The address from which you are trying to send is disabled. You'll have to enable it on the 'Your Identities' tab before using it. 错误: 您想以一个您已经禁用的地址发出消息。在使用之前您需要在“您的身份”处再次启用。 - + Entry added to the Address Book. Edit the label to your liking. - + 条目已经添加到地址本。您可以去修改您的标签。 - + Entry added to the blacklist. Edit the label to your liking. 条目添加到黑名单. 根据自己的喜好编辑标签. - + Error: You cannot add the same address to your blacklist twice. Try renaming the existing one if you want. 错误: 您不能在同一地址添加到您的黑名单两次. 也许您可重命名现有之一. - + Moved items to trash. 已经移动项目到回收站。 - + Undeleted item. 未删除的项目。 - + Save As... 另存为... - + Write error. 写入失败。 - + No addresses selected. 没有选择地址。 - + If you delete the subscription, messages that you already received will become inaccessible. Maybe you can consider disabling the subscription instead. Disabled subscriptions will not receive new messages, but you can still view messages you already received. Are you sure you want to delete the subscription? @@ -833,7 +803,7 @@ Are you sure you want to delete the subscription? 你确定要删除订阅? - + If you delete the channel, messages that you already received will become inaccessible. Maybe you can consider disabling the channel instead. Disabled channels will not receive new messages, but you can still view messages you already received. Are you sure you want to delete the channel? @@ -842,282 +812,282 @@ Are you sure you want to delete the channel? 你确定要删除频道? - + Do you really want to remove this avatar? 您真的想移除这个头像么? - + You have already set an avatar for this address. Do you really want to overwrite it? 您已经为这个地址设置了头像了。您真的想移除么? - + Start-on-login not yet supported on your OS. 登录时启动尚未支持您在使用的操作系统。 - + Minimize-to-tray not yet supported on your OS. 最小化到托盘尚未支持您的操作系统。 - + Tray notifications not yet supported on your OS. 托盘提醒尚未支持您所使用的操作系统。 - + Testing... 正在测试... - + This is a chan address. You cannot use it as a pseudo-mailing list. - + 这是一个频道地址,您无法把它作为伪邮件列表。 - + The address should start with ''BM-'' 地址应该以"BM-"开始 - + The address is not typed or copied correctly (the checksum failed). 地址没有被正确的键入或复制(校验码校验失败)。 - + The version number of this address is higher than this software can support. Please upgrade Bitmessage. 这个地址的版本号大于此软件的最大支持。 请升级比特信。 - + The address contains invalid characters. 这个地址中包含无效字符。 - + Some data encoded in the address is too short. 在这个地址中编码的部分信息过少。 - + Some data encoded in the address is too long. 在这个地址中编码的部分信息过长。 - + Some data encoded in the address is malformed. 在地址编码的某些数据格式不正确. - + Enter an address above. - + 请在上方键入地址。 - + Address is an old type. We cannot display its past broadcasts. 地址没有近期的广播。我们无法显示之间的广播。 - + There are no recent broadcasts from this address to display. 没有可以显示的近期广播。 - + You are using TCP port %1. (This can be changed in the settings). - + 您正在使用TCP端口 %1 。(可以在设置中修改)。 - + Bitmessage 比特信 - + Identities 身份标识 - + New Identity 新身份标识 - + Search 搜索 - + All 全部 - + To - + From 来自 - + Subject 标题 - + Message 消息 - + Received 接收时间 - + Messages 信息 - + Address book 地址簿 - + Address 地址 - + Add Contact 增加联系人 - + Fetch Namecoin ID 接收Namecoin ID - + Subject: 标题: - + From: 来自: - + To: 至: - + Send ordinary Message 发送普通信息 - + Send Message to your Subscribers 发送信息给您的订户 - + TTL: TTL: - + Subscriptions 订阅 - + Add new Subscription 添加新的订阅 - + Chans Chans - + Add Chan 添加 Chans - + File 文件 - + Settings 设置 - + Help 帮助 - + Import keys 导入密钥 - + Manage keys 管理密钥 - + Ctrl+Q Ctrl+Q - + F1 F1 - + Contact support 联系支持 - + About 关于 - + Regenerate deterministic addresses 重新生成静态地址 - + Delete all trashed messages 彻底删除全部回收站中的消息 - + Join / Create chan 加入或创建一个频道 - + All accounts 所有帐户 @@ -1137,67 +1107,67 @@ Are you sure you want to delete the channel? 添加新条目 - + Display the %1 recent broadcast(s) from this address. - + 显示从这个地址%1的最近广播 - + New version of PyBitmessage is available: %1. Download it from https://github.com/Bitmessage/PyBitmessage/releases/latest PyBitmessage的新版本可用: %1. 从https://github.com/Bitmessage/PyBitmessage/releases/latest下载 - + Waiting for PoW to finish... %1% 等待PoW完成...%1% - + Shutting down Pybitmessage... %1% 关闭Pybitmessage ...%1% - + Waiting for objects to be sent... %1% 等待要发送对象...%1% - + Saving settings... %1% 保存设置...%1% - + Shutting down core... %1% 关闭核心...%1% - + Stopping notifications... %1% 停止通知...%1% - + Shutdown imminent... %1% 关闭即将来临...%1% - + %n hour(s) %n 小时 - + %n day(s) %n 天 - + Shutting down PyBitmessage... %1% 关闭PyBitmessage...%1% - + Sent 发送 @@ -1242,86 +1212,86 @@ Are you sure you want to delete the channel? 警告: 您的磁盘或数据存储量已满. 比特信将立即退出. - + Error! Could not find sender address (your address) in the keys.dat file. 错误! 找不到在keys.dat 件发件人的地址 ( 您的地址). - + Doing work necessary to send broadcast... 做必要的工作, 以发送广播... - + Broadcast sent on %1 广播发送%1 - + Encryption key was requested earlier. 加密密钥已请求. - + Sending a request for the recipient's encryption key. 发送收件人的加密密钥的请求. - + Looking up the receiver's public key 展望接收方的公钥 - + Problem: Destination is a mobile device who requests that the destination be included in the message but this is disallowed in your settings. %1 问题: 目标是移动电话设备所请求的目的地包括在消息中, 但是这是在你的设置禁止. %1 - + Doing work necessary to send message. There is no required difficulty for version 2 addresses like this. 做必要的工作, 以发送信息. 这样第2版的地址没有难度. - + Doing work necessary to send message. Receiver's required difficulty: %1 and %2 做必要的工作, 以发送短信. 接收者的要求难度: %1与%2 - + Problem: The work demanded by the recipient (%1 and %2) is more difficult than you are willing to do. %3 问题: 由接收者(%1%2)要求的工作量比您愿意做的工作量來得更困难. %3 - + Problem: You are trying to send a message to yourself or a chan but your encryption key could not be found in the keys.dat file. Could not encrypt message. %1 问题: 您正在尝试将信息发送给自己或频道, 但您的加密密钥无法在keys.dat文件中找到. 无法加密信息. %1 - + Doing work necessary to send message. 做必要的工作, 以发送信息. - + Message sent. Waiting for acknowledgement. Sent on %1 信息发送. 等待确认. 已发送%1 - + Doing work necessary to request encryption key. 做必要的工作以要求加密密钥. - + Broadcasting the public key request. This program will auto-retry if they are offline. 广播公钥请求. 这个程序将自动重试, 如果他们处于离线状态. - + Sending public key request. Waiting for reply. Requested at %1 发送公钥的请求. 等待回复. 请求在%1 @@ -1336,37 +1306,37 @@ Receiver's required difficulty: %1 and %2 UPnP端口映射被删除 - + Mark all messages as read 标记全部信息为已读 - + Are you sure you would like to mark all messages read? 确定将所有信息标记为已读吗? - + Doing work necessary to send broadcast. 持续进行必要的工作,以发送广播。 - + Proof of work pending 待传输内容的校验 - + %n object(s) pending proof of work %n 待传输内容校验任务 - + %n object(s) waiting to be distributed %n 任务等待分配 - + Wait until these tasks finish? 等待所有任务执行完? @@ -1411,37 +1381,32 @@ Receiver's required difficulty: %1 and %2 名字%1没有关联比特信地址。 - + Success! Namecoind version %1 running. 成功!域名币系统%1运行中。 - + Success! NMControll is up and running. 成功!域名币控制上线运行! - + Couldn't understand NMControl. 不能理解 NMControl。 - - - The connection to namecoin failed. - 连接到 Namecoin 失败。 - Your GPU(s) did not calculate correctly, disabling OpenCL. Please report to the developers. - 你的GPU不能够正确计算,正在关闭OpenGL。请报告给开发者。 + 你的GPU(s)不能够正确计算,关闭OpenGL。请报告给开发者。 - + Set notification sound... 设置通知提示音... - + Welcome to easy and secure Bitmessage * send messages to other people @@ -1452,178 +1417,133 @@ Receiver's required difficulty: %1 and %2 欢迎使用简便安全的比特信 *发送信息给其他人 *像推特那样发送广播信息 -*在频道里和其他人讨论 +*在频道(s)里和其他人讨论 - + not recommended for chans 频道内不建议的内容 - + Quiet Mode 静默模式 - + Problems connecting? Try enabling UPnP in the Network Settings 连接问题?请尝试在网络设置里打开UPnP - + You are trying to send an email instead of a bitmessage. This requires registering with a gateway. Attempt to register? 您将要尝试经由 Bitmessage 发送一封电子邮件。该操作需要在一个网关上注册。尝试注册? - + Error: Bitmessage addresses start with BM- Please check the recipient address %1 错误:Bitmessage地址是以BM-开头的,请检查收信地址%1. - + Error: The recipient address %1 is not typed or copied correctly. Please check it. 错误:收信地址%1未填写或复制错误。请检查。 - + Error: The recipient address %1 contains invalid characters. Please check it. 错误:收信地址%1还有非法字符。请检查。 - + Error: The version of the recipient address %1 is too high. Either you need to upgrade your Bitmessage software or your acquaintance is being clever. 错误:收信地址%1版本太高。要么你需要更新你的软件,要么对方需要降级 。 - + Error: Some data encoded in the recipient address %1 is too short. There might be something wrong with the software of your acquaintance. 错误:收信地址%1编码数据太短。可能对方使用的软件有问题。 - + Error: Some data encoded in the recipient address %1 is too long. There might be something wrong with the software of your acquaintance. 错误: - + Error: Some data encoded in the recipient address %1 is malformed. There might be something wrong with the software of your acquaintance. 错误:收信地址%1编码数据太长。可能对方使用的软件有问题。 - + Error: Something is wrong with the recipient address %1. 错误:收信地址%1有问题。 - + Error: %1 错误:%1 - + From %1 来自 %1 - + Synchronisation pending 待同步 - + Bitmessage hasn't synchronised with the network, %n object(s) to be downloaded. If you quit now, it may cause delivery delays. Wait until the synchronisation finishes? Bitmessage还没有与网络同步,%n 件任务需要下载。如果你现在退出软件,可能会造成传输延时。是否等同步完成? - + Not connected 未连接成功。 - + Bitmessage isn't connected to the network. If you quit now, it may cause delivery delays. Wait until connected and the synchronisation finishes? Bitmessage未连接到网络。如果现在退出软件,可能会造成传输延时。是否等待同步完成? - + Waiting for network connection... 等待网络连接…… - + Waiting for finishing synchronisation... 等待同步完成…… - + You have already set a notification sound for this address book entry. Do you really want to overwrite it? - 您已经为该地址簿条目设置了通知提示音。您想要覆盖它吗? - - - - Error occurred: could not load message from disk. - 发生错误:无法从磁盘读取消息。 - - - - Display the %n recent broadcast(s) from this address. - 显示从此地址最近 %n 的广播。 - - - - Go online - 上线 - - - - Go offline - 下线 - - - - Clear - 清除 - - - - inbox - 收件箱 - - - - new - 新信息 - - - - sent - 已发送 - - - - trash - 垃圾箱 + MessageView - + Follow external link 查看外部链接 - + The link "%1" will open in a browser. It may be a security risk, it could de-anonymise you or download malicious data. Are you sure? 此链接“%1”将在浏览器中打开。可能会有安全风险,可能会暴露你或下载恶意数据。确定吗? - + HTML detected, click here to display 检测到HTML,单击此处来显示内容。 - + Click here to disable HTML 单击此处以禁止HTML。 @@ -1631,14 +1551,14 @@ Receiver's required difficulty: %1 and %2 MsgDecode - + The message has an unknown encoding. Perhaps you should upgrade Bitmessage. 这些消息使用了未知编码方式。 你可能需要更新Bitmessage软件。 - + Unknown encoding 未知编码 @@ -1646,98 +1566,98 @@ Perhaps you should upgrade Bitmessage. NewAddressDialog - + Create new Address 创建新地址 - + Here you may generate as many addresses as you like. Indeed, creating and abandoning addresses is encouraged. You may generate addresses by using either random numbers or by using a passphrase. If you use a passphrase, the address is called a "deterministic" address. The 'Random Number' option is selected by default but deterministic addresses have several pros and cons: 在这里,您想创建多少地址就创建多少。诚然,创建和丢弃地址受到鼓励。你既可以使用随机数来创建地址,也可以使用密钥。如果您使用密钥的话,生成的地址叫“静态地址”。随机数选项默认为选择,不过相比而言静态地址既有缺点也有优点: - + <html><head/><body><p><span style=" font-weight:600;">Pros:<br/></span>You can recreate your addresses on any computer from memory. <br/>You need-not worry about backing up your keys.dat file as long as you can remember your passphrase. <br/><span style=" font-weight:600;">Cons:<br/></span>You must remember (or write down) your passphrase if you expect to be able to recreate your keys if they are lost. <br/>You must remember the address version number and the stream number along with your passphrase. <br/>If you choose a weak passphrase and someone on the Internet can brute-force it, they can read your messages and send messages as you.</p></body></html> <html><head/><body><p><span style=" font-weight:600;">优点:<br/></span>您可以通过记忆在任何电脑再次得到您的地址. <br/>您不需要注意备份您的 keys.dat 只要您能记住您的密钥。 <br/><span style=" font-weight:600;">缺点:<br/></span>您若要再次得到您的地址,您必须牢记(或写下您的密钥)。 <br/>您必须牢记密钥的同时也牢记地址版本号和the stream number . <br/>如果您选择了一个弱的密钥的话,一些在互联网我那个的人可能有机会暴力破解, 他们将可以阅读您的消息并且以您的身份发送消息.</p></body></html> - + Use a random number generator to make an address 使用随机数生成地址 - + Use a passphrase to make addresses 使用密钥生成地址 - + Spend several minutes of extra computing time to make the address(es) 1 or 2 characters shorter 花费数分钟的计算使地址短1-2个字母 - + Make deterministic addresses 创建静态地址 - + Address version number: 4 地址版本号:4 - + In addition to your passphrase, you must remember these numbers: 在记住您的密钥的同时,您还需要记住以下数字: - + Passphrase 密钥 - + Number of addresses to make based on your passphrase: 使用该密钥生成的地址数: - + Stream number: 1 节点流序号:1 - + Retype passphrase 再次输入密钥 - + Randomly generate address 随机生成地址 - + Label (not shown to anyone except you) 标签(只有您看的到) - + Use the most available stream 使用最可用的节点流 - + (best if this is the first of many addresses you will create) 如果这是您创建的数个地址中的第一个时最佳 - + Use the same stream as an existing address 使用和如下地址一样的节点流 - + (saves you some bandwidth and processing power) (节省你的带宽和处理能力) @@ -1745,83 +1665,78 @@ The 'Random Number' option is selected by default but deterministic ad NewSubscriptionDialog - + Add new entry 添加新条目 - + Label 标签 - + Address 地址 - + Enter an address above. - 请在上方键入地址。 + 输入上述地址. SpecialAddressBehaviorDialog - + Special Address Behavior 特别的地址行为 - + Behave as a normal address 作为普通地址 - + Behave as a pseudo-mailing-list address 作为伪邮件列表地址 - + Mail received to a pseudo-mailing-list address will be automatically broadcast to subscribers (and thus will be public). 伪邮件列表收到消息时会自动将其公开的广播给订阅者。 - + Name of the pseudo-mailing-list: 伪邮件列表名称: - - - This is a chan address. You cannot use it as a pseudo-mailing list. - 这是一个频道地址,您无法把它作为伪邮件列表。 - aboutDialog - + About 关于 - - - PyBitmessage - - - version ? - + PyBitmessage + PyBitmessage - + + version ? + 版本 ? + + + <html><head/><body><p>Distributed under the MIT/X11 software license; see <a href="http://www.opensource.org/licenses/mit-license.php"><span style=" text-decoration: underline; color:#0000ff;">http://www.opensource.org/licenses/mit-license.php</span></a></p></body></html> <html><head/><body><p>以 MIT/X11 软件授权发布; 详情参见 <a href="http://www.opensource.org/licenses/mit-license.php"><span style=" text-decoration: underline; color:#0000ff;">http://www.opensource.org/licenses/mit-license.php</span></a></p></body></html> - + This is Beta software. 本软件处于Beta阶段。 @@ -1830,10 +1745,10 @@ The 'Random Number' option is selected by default but deterministic ad <html><head/><body><p>Copyright © 2012-2016 Jonathan Warren<br/>Copyright © 2013-2016 The Bitmessage Developers</p></body></html> - - - <html><head/><body><p>Copyright © 2012-2016 Jonathan Warren<br/>Copyright © 2013-2017 The Bitmessage Developers</p></body></html> - <html><head/><body><p>Copyright © 2012-2016 Jonathan Warren<br/>Copyright © 2013-2017 The Bitmessage Developers</p></body></html> + + + <html><head/><body><p>Copyright &copy; 2012-2016 Jonathan Warren<br/>Copyright &copy; 2013-2016 The Bitmessage Developers</p></body></html> + <html><head/><body><p>版权:2012-2016 Jonathan Warren<br/>版权: 2013-2016 The Bitmessage Developers</p></body></html> @@ -1877,45 +1792,40 @@ The 'Random Number' option is selected by default but deterministic ad connectDialog - + Bitmessage 比特信 - + Bitmessage won't connect to anyone until you let it. 除非您允许,比特信不会连接到任何人。 - + Connect now 现在连接 - + Let me configure special network settings first 请先让我进行特别的网络设置 - - - Work offline - 离线模式下工作 - helpDialog - + Help 帮助 - + <a href="https://bitmessage.org/wiki/PyBitmessage_Help">https://bitmessage.org/wiki/PyBitmessage_Help</a> <a href="https://bitmessage.org/wiki/PyBitmessage_Help">https://bitmessage.org/wiki/PyBitmessage_Help</a> - + As Bitmessage is a collaborative project, help can be found online in the Bitmessage Wiki: 鉴于比特信是一个共同完成的项目,您可以在比特信的Wiki上了解如何帮助比特信: @@ -1923,35 +1833,30 @@ The 'Random Number' option is selected by default but deterministic ad iconGlossaryDialog - + Icon Glossary 图标含义 - + You have no connections with other peers. 您没有和其他节点的连接. - + You have made at least one connection to a peer using an outgoing connection but you have not yet received any incoming connections. Your firewall or home router probably isn't configured to forward incoming TCP connections to your computer. Bitmessage will work just fine but it would help the Bitmessage network if you allowed for incoming connections and will help you be a better-connected node. 你有至少一个到其他节点的出站连接,但是尚未收到入站连接。您的防火墙或路由器可能尚未设置转发入站TCP连接到您的电脑。比特信将正常运行,不过如果您允许入站连接的话将帮助比特信网络并成为一个通信状态更好的节点。 You are using TCP port ?. (This can be changed in the settings). - + 您正在使用TCP端口 ? 。(可以在设置中更改). - + You do have connections with other peers and your firewall is correctly configured. 您有和其他节点的连接且您的防火墙已经正确配置。 - - - You are using TCP port %1. (This can be changed in the settings). - 您正在使用TCP端口 %1 。(可以在设置中修改)。 - networkstatus @@ -2001,27 +1906,27 @@ The 'Random Number' option is selected by default but deterministic ad - + Since startup on %1 自从%1启动 - + Down: %1/s Total: %2 下: %1/秒 总计: %2 - + Up: %1/s Total: %2 上: %1/秒 总计: %2 - + Total Connections: %1 总的连接数: %1 - + Inventory lookups per second: %1 每秒库存查询: %1 @@ -2036,32 +1941,32 @@ The 'Random Number' option is selected by default but deterministic ad 下载: 0 kB /秒 - + Network Status 网络状态 - + byte(s) 字节 - + Object(s) to be synced: %n 要同步的对象: %n - + Processed %n person-to-person message(s). 处理%n人对人的信息. - + Processed %n broadcast message(s). 处理%n广播信息. - + Processed %n public key(s). 处理%n公钥. @@ -2166,7 +2071,7 @@ The 'Random Number' option is selected by default but deterministic ad Chan passphrase/name: - 通道密码/名称: + @@ -2192,12 +2097,12 @@ The 'Random Number' option is selected by default but deterministic ad 成功创建或加入频道%1 - + Chan creation / joining failed 频道创建或加入失败 - + Chan creation / joining cancelled 频道创建或加入已取消 @@ -2231,52 +2136,52 @@ The 'Random Number' option is selected by default but deterministic ad regenerateAddressesDialog - + Regenerate Existing Addresses 重新生成已经存在的地址 - + Regenerate existing addresses 重新生成已经存在的地址 - + Passphrase 密钥 - + Number of addresses to make based on your passphrase: - 使用该密钥生成的地址数: + 您想要要使用这个密钥生成的地址数: - + Address version number: 地址版本号: - + Stream number: 节点流序号: - + 1 1 - + Spend several minutes of extra computing time to make the address(es) 1 or 2 characters shorter 花费数分钟的计算使地址短1-2个字母 - + You must check (or not check) this box just like you did (or didn't) when you made your addresses the first time. 这个选项需要和您第一次生成的时候相同。 - + If you have previously made deterministic addresses but lost them due to an accident (like hard drive failure), you can regenerate them here. If you used the random number generator to make your addresses then this form will be of no use to you. 如果您之前创建了静态地址,但是因为一些意外失去了它们(比如硬盘坏了),您可以在这里将他们再次生成。如果您使用随机数来生成的地址的话,那么这个表格对您没有帮助。 diff --git a/src/upnp.py b/src/upnp.py index 46d55956..ad72560c 100644 --- a/src/upnp.py +++ b/src/upnp.py @@ -224,7 +224,7 @@ class uPnPThread(threading.Thread, StoppableThread): continue newRouter = Router(resp, ip) for router in self.routers: - if router.routerPath == newRouter.routerPath: + if router.location == newRouter.location: break else: logger.debug("Found UPnP router at %s", ip)