Fixed: Style and lint violations for ten more of the worst violating files #1265
|
@ -1,9 +1,11 @@
|
||||||
[pycodestyle]
|
[pycodestyle]
|
||||||
max-line-length = 119
|
max-line-length = 119
|
||||||
|
ignore = E722,E402
|
||||||
|
|
||||||
[flake8]
|
[flake8]
|
||||||
max-line-length = 119
|
max-line-length = 119
|
||||||
ignore = E722
|
ignore = E722,E402
|
||||||
|
# E402: pylint is preferred for wrong-import-position
|
||||||
|
|
||||||
# pylint
|
# pylint
|
||||||
[MESSAGES CONTROL]
|
[MESSAGES CONTROL]
|
||||||
|
|
294
src/api.py
294
src/api.py
|
@ -1,19 +1,24 @@
|
||||||
|
# pylint: disable=too-many-locals,too-many-lines,no-self-use,too-many-public-methods,too-many-branches
|
||||||
|
# pylint: disable=too-many-statements
|
||||||
|
"""
|
||||||
# Copyright (c) 2012-2016 Jonathan Warren
|
# Copyright (c) 2012-2016 Jonathan Warren
|
||||||
# Copyright (c) 2012-2018 The Bitmessage developers
|
# Copyright (c) 2012-2018 The Bitmessage developers
|
||||||
|
|
||||||
"""
|
|
||||||
This is not what you run to run the Bitmessage API. Instead, enable the API
|
This is not what you run to run the Bitmessage API. Instead, enable the API
|
||||||
( https://bitmessage.org/wiki/API ) and optionally enable daemon mode
|
( https://bitmessage.org/wiki/API ) and optionally enable daemon mode
|
||||||
( https://bitmessage.org/wiki/Daemon ) then run bitmessagemain.py.
|
( https://bitmessage.org/wiki/Daemon ) then run bitmessagemain.py.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
from __future__ import absolute_import
|
||||||
|
|
||||||
import base64
|
import base64
|
||||||
import hashlib
|
import hashlib
|
||||||
import json
|
import json
|
||||||
|
from struct import pack
|
||||||
import time
|
import time
|
||||||
|
|||||||
from binascii import hexlify, unhexlify
|
from binascii import hexlify, unhexlify
|
||||||
|
|
||||||
from SimpleXMLRPCServer import SimpleXMLRPCRequestHandler, SimpleXMLRPCServer
|
from SimpleXMLRPCServer import SimpleXMLRPCRequestHandler, SimpleXMLRPCServer
|
||||||
from struct import pack
|
|
||||||
|
|
||||||
import shared
|
import shared
|
||||||
from addresses import (
|
from addresses import (
|
||||||
|
@ -43,6 +48,8 @@ str_chan = '[chan]'
|
||||||
|
|
||||||
|
|
||||||
class APIError(Exception):
|
class APIError(Exception):
|
||||||
|
"""APIError exception class"""
|
||||||
|
|
||||||
def __init__(self, error_number, error_message):
|
def __init__(self, error_number, error_message):
|
||||||
super(APIError, self).__init__()
|
super(APIError, self).__init__()
|
||||||
self.error_number = error_number
|
self.error_number = error_number
|
||||||
|
@ -53,26 +60,34 @@ class APIError(Exception):
|
||||||
|
|
||||||
|
|
||||||
class StoppableXMLRPCServer(SimpleXMLRPCServer):
|
class StoppableXMLRPCServer(SimpleXMLRPCServer):
|
||||||
|
"""A SimpleXMLRPCServer that honours state.shutdown"""
|
||||||
allow_reuse_address = True
|
allow_reuse_address = True
|
||||||
|
|
||||||
def serve_forever(self):
|
def serve_forever(self):
|
||||||
|
"""Start the SimpleXMLRPCServer"""
|
||||||
|
# pylint: disable=arguments-differ
|
||||||
while state.shutdown == 0:
|
while state.shutdown == 0:
|
||||||
self.handle_request()
|
self.handle_request()
|
||||||
|
|
||||||
|
|
||||||
# This is one of several classes that constitute the API
|
|
||||||
# This class was written by Vaibhav Bhatia.
|
|
||||||
# Modified by Jonathan Warren (Atheros).
|
|
||||||
# http://code.activestate.com/recipes/501148-xmlrpc-serverclient-which-does-cookie-handling-and/
|
|
||||||
class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
|
class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
|
||||||
|
"""
|
||||||
|
This is one of several classes that constitute the API
|
||||||
|
|
||||||
|
This class was written by Vaibhav Bhatia. Modified by Jonathan Warren (Atheros).
|
||||||
|
http://code.activestate.com/recipes/501148-xmlrpc-serverclient-which-does-cookie-handling-and/
|
||||||
|
"""
|
||||||
|
|
||||||
def do_POST(self):
|
def do_POST(self):
|
||||||
# Handles the HTTP POST request.
|
"""
|
||||||
# Attempts to interpret all HTTP POST requests as XML-RPC calls,
|
Handles the HTTP POST request.
|
||||||
# which are forwarded to the server's _dispatch method for handling.
|
|
||||||
|
|
||||||
# Note: this method is the same as in SimpleXMLRPCRequestHandler,
|
Attempts to interpret all HTTP POST requests as XML-RPC calls,
|
||||||
# just hacked to handle cookies
|
which are forwarded to the server's _dispatch method for handling.
|
||||||
|
|
||||||
|
Note: this method is the same as in SimpleXMLRPCRequestHandler,
|
||||||
|
just hacked to handle cookies
|
||||||
|
"""
|
||||||
|
|
||||||
# Check that the path is legal
|
# Check that the path is legal
|
||||||
if not self.is_rpc_path_valid():
|
if not self.is_rpc_path_valid():
|
||||||
|
@ -98,7 +113,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
|
||||||
# SimpleXMLRPCDispatcher. To maintain backwards compatibility,
|
# SimpleXMLRPCDispatcher. To maintain backwards compatibility,
|
||||||
# check to see if a subclass implements _dispatch and dispatch
|
# check to see if a subclass implements _dispatch and dispatch
|
||||||
# using that method if present.
|
# using that method if present.
|
||||||
response = self.server._marshaled_dispatch(
|
response = self.server._marshaled_dispatch( # pylint: disable=protected-access
|
||||||
data, getattr(self, '_dispatch', None)
|
data, getattr(self, '_dispatch', None)
|
||||||
)
|
)
|
||||||
except: # This should only happen if the module is buggy
|
except: # This should only happen if the module is buggy
|
||||||
|
@ -125,22 +140,21 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
|
||||||
self.connection.shutdown(1)
|
self.connection.shutdown(1)
|
||||||
|
|
||||||
def APIAuthenticateClient(self):
|
def APIAuthenticateClient(self):
|
||||||
|
"""Predicate to check for valid API credentials in the request header"""
|
||||||
|
|
||||||
if 'Authorization' in self.headers:
|
if 'Authorization' in self.headers:
|
||||||
# handle Basic authentication
|
# handle Basic authentication
|
||||||
enctype, encstr = self.headers.get('Authorization').split()
|
_, encstr = self.headers.get('Authorization').split()
|
||||||
emailid, password = encstr.decode('base64').split(':')
|
emailid, password = encstr.decode('base64').split(':')
|
||||||
return (
|
return (
|
||||||
emailid ==
|
emailid == BMConfigParser().get('bitmessagesettings', 'apiusername') and
|
||||||
BMConfigParser().get('bitmessagesettings', 'apiusername')
|
password == BMConfigParser().get('bitmessagesettings', 'apipassword')
|
||||||
and password ==
|
|
||||||
BMConfigParser().get('bitmessagesettings', 'apipassword')
|
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
logger.warning(
|
logger.warning(
|
||||||
'Authentication failed because header lacks'
|
'Authentication failed because header lacks'
|
||||||
' Authentication field')
|
' Authentication field')
|
||||||
time.sleep(2)
|
time.sleep(2)
|
||||||
return False
|
|
||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
@ -155,6 +169,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
|
||||||
22, "Decode error - %s. Had trouble while decoding string: %r"
|
22, "Decode error - %s. Had trouble while decoding string: %r"
|
||||||
% (e, text)
|
% (e, text)
|
||||||
)
|
)
|
||||||
|
return None
|
||||||
|
|
||||||
def _verifyAddress(self, address):
|
def _verifyAddress(self, address):
|
||||||
status, addressVersionNumber, streamNumber, ripe = \
|
status, addressVersionNumber, streamNumber, ripe = \
|
||||||
|
@ -170,15 +185,10 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
|
||||||
if status == 'invalidcharacters':
|
if status == 'invalidcharacters':
|
||||||
raise APIError(9, 'Invalid characters in address: ' + address)
|
raise APIError(9, 'Invalid characters in address: ' + address)
|
||||||
if status == 'versiontoohigh':
|
if status == 'versiontoohigh':
|
||||||
raise APIError(
|
raise APIError(10, 'Address version number too high (or zero) in address: ' + address)
|
||||||
10,
|
|
||||||
'Address version number too high (or zero) in address: '
|
|
||||||
+ address
|
|
||||||
)
|
|
||||||
if status == 'varintmalformed':
|
if status == 'varintmalformed':
|
||||||
raise APIError(26, 'Malformed varint in address: ' + address)
|
raise APIError(26, 'Malformed varint in address: ' + address)
|
||||||
raise APIError(
|
raise APIError(7, 'Could not decode address: %s : %s' % (address, status))
|
||||||
7, 'Could not decode address: %s : %s' % (address, status))
|
|
||||||
if addressVersionNumber < 2 or addressVersionNumber > 4:
|
if addressVersionNumber < 2 or addressVersionNumber > 4:
|
||||||
raise APIError(
|
raise APIError(
|
||||||
11, 'The address version number currently must be 2, 3 or 4.'
|
11, 'The address version number currently must be 2, 3 or 4.'
|
||||||
|
@ -195,9 +205,11 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
|
||||||
# Request Handlers
|
# Request Handlers
|
||||||
|
|
||||||
def HandleListAddresses(self, method):
|
def HandleListAddresses(self, method):
|
||||||
|
"""Handle a request to list addresses"""
|
||||||
|
|
||||||
data = '{"addresses":['
|
data = '{"addresses":['
|
||||||
for addressInKeysFile in BMConfigParser().addresses():
|
for addressInKeysFile in BMConfigParser().addresses():
|
||||||
status, addressVersionNumber, streamNumber, hash01 = decodeAddress(
|
status, addressVersionNumber, streamNumber, hash01 = decodeAddress( # pylint: disable=unused-variable
|
||||||
addressInKeysFile)
|
addressInKeysFile)
|
||||||
if len(data) > 20:
|
if len(data) > 20:
|
||||||
data += ','
|
data += ','
|
||||||
|
@ -220,6 +232,8 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def HandleListAddressBookEntries(self, params):
|
def HandleListAddressBookEntries(self, params):
|
||||||
|
"""Handle a request to list address book entries"""
|
||||||
|
|
||||||
if len(params) == 1:
|
if len(params) == 1:
|
||||||
label, = params
|
label, = params
|
||||||
label = self._decode(label, "base64")
|
label = self._decode(label, "base64")
|
||||||
|
@ -243,6 +257,8 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def HandleAddAddressBookEntry(self, params):
|
def HandleAddAddressBookEntry(self, params):
|
||||||
|
"""Handle a request to add an address book entry"""
|
||||||
|
|
||||||
if len(params) != 2:
|
if len(params) != 2:
|
||||||
raise APIError(0, "I need label and address")
|
raise APIError(0, "I need label and address")
|
||||||
address, label = params
|
address, label = params
|
||||||
|
@ -262,6 +278,8 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
|
||||||
return "Added address %s to address book" % address
|
return "Added address %s to address book" % address
|
||||||
|
|
||||||
def HandleDeleteAddressBookEntry(self, params):
|
def HandleDeleteAddressBookEntry(self, params):
|
||||||
|
"""Handle a request to delete an address book entry"""
|
||||||
|
|
||||||
if len(params) != 1:
|
if len(params) != 1:
|
||||||
raise APIError(0, "I need an address")
|
raise APIError(0, "I need an address")
|
||||||
address, = params
|
address, = params
|
||||||
|
@ -274,8 +292,11 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
|
||||||
return "Deleted address book entry for %s if it existed" % address
|
return "Deleted address book entry for %s if it existed" % address
|
||||||
|
|
||||||
def HandleCreateRandomAddress(self, params):
|
def HandleCreateRandomAddress(self, params):
|
||||||
if len(params) == 0:
|
"""Handle a request to create a random address"""
|
||||||
|
|
||||||
|
if not params:
|
||||||
raise APIError(0, 'I need parameters!')
|
raise APIError(0, 'I need parameters!')
|
||||||
|
|
||||||
elif len(params) == 1:
|
elif len(params) == 1:
|
||||||
label, = params
|
label, = params
|
||||||
eighteenByteRipe = False
|
eighteenByteRipe = False
|
||||||
|
@ -292,19 +313,16 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
|
||||||
elif len(params) == 3:
|
elif len(params) == 3:
|
||||||
label, eighteenByteRipe, totalDifficulty = params
|
label, eighteenByteRipe, totalDifficulty = params
|
||||||
nonceTrialsPerByte = int(
|
nonceTrialsPerByte = int(
|
||||||
defaults.networkDefaultProofOfWorkNonceTrialsPerByte
|
defaults.networkDefaultProofOfWorkNonceTrialsPerByte * totalDifficulty)
|
||||||
* totalDifficulty)
|
|
||||||
payloadLengthExtraBytes = BMConfigParser().get(
|
payloadLengthExtraBytes = BMConfigParser().get(
|
||||||
'bitmessagesettings', 'defaultpayloadlengthextrabytes')
|
'bitmessagesettings', 'defaultpayloadlengthextrabytes')
|
||||||
elif len(params) == 4:
|
elif len(params) == 4:
|
||||||
label, eighteenByteRipe, totalDifficulty, \
|
label, eighteenByteRipe, totalDifficulty, \
|
||||||
smallMessageDifficulty = params
|
smallMessageDifficulty = params
|
||||||
nonceTrialsPerByte = int(
|
nonceTrialsPerByte = int(
|
||||||
defaults.networkDefaultProofOfWorkNonceTrialsPerByte
|
defaults.networkDefaultProofOfWorkNonceTrialsPerByte * totalDifficulty)
|
||||||
* totalDifficulty)
|
|
||||||
payloadLengthExtraBytes = int(
|
payloadLengthExtraBytes = int(
|
||||||
defaults.networkDefaultPayloadLengthExtraBytes
|
defaults.networkDefaultPayloadLengthExtraBytes * smallMessageDifficulty)
|
||||||
* smallMessageDifficulty)
|
|
||||||
else:
|
else:
|
||||||
raise APIError(0, 'Too many parameters!')
|
raise APIError(0, 'Too many parameters!')
|
||||||
label = self._decode(label, "base64")
|
label = self._decode(label, "base64")
|
||||||
|
@ -321,8 +339,11 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
|
||||||
return queues.apiAddressGeneratorReturnQueue.get()
|
return queues.apiAddressGeneratorReturnQueue.get()
|
||||||
|
|
||||||
def HandleCreateDeterministicAddresses(self, params):
|
def HandleCreateDeterministicAddresses(self, params):
|
||||||
if len(params) == 0:
|
"""Handle a request to create a deterministic address"""
|
||||||
|
|
||||||
|
if not params:
|
||||||
raise APIError(0, 'I need parameters!')
|
raise APIError(0, 'I need parameters!')
|
||||||
|
|
||||||
elif len(params) == 1:
|
elif len(params) == 1:
|
||||||
passphrase, = params
|
passphrase, = params
|
||||||
numberOfAddresses = 1
|
numberOfAddresses = 1
|
||||||
|
@ -333,6 +354,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
|
||||||
'bitmessagesettings', 'defaultnoncetrialsperbyte')
|
'bitmessagesettings', 'defaultnoncetrialsperbyte')
|
||||||
payloadLengthExtraBytes = BMConfigParser().get(
|
payloadLengthExtraBytes = BMConfigParser().get(
|
||||||
'bitmessagesettings', 'defaultpayloadlengthextrabytes')
|
'bitmessagesettings', 'defaultpayloadlengthextrabytes')
|
||||||
|
|
||||||
elif len(params) == 2:
|
elif len(params) == 2:
|
||||||
passphrase, numberOfAddresses = params
|
passphrase, numberOfAddresses = params
|
||||||
addressVersionNumber = 0
|
addressVersionNumber = 0
|
||||||
|
@ -342,6 +364,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
|
||||||
'bitmessagesettings', 'defaultnoncetrialsperbyte')
|
'bitmessagesettings', 'defaultnoncetrialsperbyte')
|
||||||
payloadLengthExtraBytes = BMConfigParser().get(
|
payloadLengthExtraBytes = BMConfigParser().get(
|
||||||
'bitmessagesettings', 'defaultpayloadlengthextrabytes')
|
'bitmessagesettings', 'defaultpayloadlengthextrabytes')
|
||||||
|
|
||||||
elif len(params) == 3:
|
elif len(params) == 3:
|
||||||
passphrase, numberOfAddresses, addressVersionNumber = params
|
passphrase, numberOfAddresses, addressVersionNumber = params
|
||||||
streamNumber = 0
|
streamNumber = 0
|
||||||
|
@ -350,6 +373,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
|
||||||
'bitmessagesettings', 'defaultnoncetrialsperbyte')
|
'bitmessagesettings', 'defaultnoncetrialsperbyte')
|
||||||
payloadLengthExtraBytes = BMConfigParser().get(
|
payloadLengthExtraBytes = BMConfigParser().get(
|
||||||
'bitmessagesettings', 'defaultpayloadlengthextrabytes')
|
'bitmessagesettings', 'defaultpayloadlengthextrabytes')
|
||||||
|
|
||||||
elif len(params) == 4:
|
elif len(params) == 4:
|
||||||
passphrase, numberOfAddresses, addressVersionNumber, \
|
passphrase, numberOfAddresses, addressVersionNumber, \
|
||||||
streamNumber = params
|
streamNumber = params
|
||||||
|
@ -358,6 +382,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
|
||||||
'bitmessagesettings', 'defaultnoncetrialsperbyte')
|
'bitmessagesettings', 'defaultnoncetrialsperbyte')
|
||||||
payloadLengthExtraBytes = BMConfigParser().get(
|
payloadLengthExtraBytes = BMConfigParser().get(
|
||||||
'bitmessagesettings', 'defaultpayloadlengthextrabytes')
|
'bitmessagesettings', 'defaultpayloadlengthextrabytes')
|
||||||
|
|
||||||
elif len(params) == 5:
|
elif len(params) == 5:
|
||||||
passphrase, numberOfAddresses, addressVersionNumber, \
|
passphrase, numberOfAddresses, addressVersionNumber, \
|
||||||
streamNumber, eighteenByteRipe = params
|
streamNumber, eighteenByteRipe = params
|
||||||
|
@ -365,27 +390,26 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
|
||||||
'bitmessagesettings', 'defaultnoncetrialsperbyte')
|
'bitmessagesettings', 'defaultnoncetrialsperbyte')
|
||||||
payloadLengthExtraBytes = BMConfigParser().get(
|
payloadLengthExtraBytes = BMConfigParser().get(
|
||||||
'bitmessagesettings', 'defaultpayloadlengthextrabytes')
|
'bitmessagesettings', 'defaultpayloadlengthextrabytes')
|
||||||
|
|
||||||
elif len(params) == 6:
|
elif len(params) == 6:
|
||||||
passphrase, numberOfAddresses, addressVersionNumber, \
|
passphrase, numberOfAddresses, addressVersionNumber, \
|
||||||
streamNumber, eighteenByteRipe, totalDifficulty = params
|
streamNumber, eighteenByteRipe, totalDifficulty = params
|
||||||
nonceTrialsPerByte = int(
|
nonceTrialsPerByte = int(
|
||||||
defaults.networkDefaultProofOfWorkNonceTrialsPerByte
|
defaults.networkDefaultProofOfWorkNonceTrialsPerByte * totalDifficulty)
|
||||||
* totalDifficulty)
|
|
||||||
payloadLengthExtraBytes = BMConfigParser().get(
|
payloadLengthExtraBytes = BMConfigParser().get(
|
||||||
'bitmessagesettings', 'defaultpayloadlengthextrabytes')
|
'bitmessagesettings', 'defaultpayloadlengthextrabytes')
|
||||||
|
|
||||||
elif len(params) == 7:
|
elif len(params) == 7:
|
||||||
passphrase, numberOfAddresses, addressVersionNumber, \
|
passphrase, numberOfAddresses, addressVersionNumber, \
|
||||||
streamNumber, eighteenByteRipe, totalDifficulty, \
|
streamNumber, eighteenByteRipe, totalDifficulty, \
|
||||||
smallMessageDifficulty = params
|
smallMessageDifficulty = params
|
||||||
nonceTrialsPerByte = int(
|
nonceTrialsPerByte = int(
|
||||||
defaults.networkDefaultProofOfWorkNonceTrialsPerByte
|
defaults.networkDefaultProofOfWorkNonceTrialsPerByte * totalDifficulty)
|
||||||
* totalDifficulty)
|
|
||||||
payloadLengthExtraBytes = int(
|
payloadLengthExtraBytes = int(
|
||||||
defaults.networkDefaultPayloadLengthExtraBytes
|
defaults.networkDefaultPayloadLengthExtraBytes * smallMessageDifficulty)
|
||||||
* smallMessageDifficulty)
|
|
||||||
else:
|
else:
|
||||||
raise APIError(0, 'Too many parameters!')
|
raise APIError(0, 'Too many parameters!')
|
||||||
if len(passphrase) == 0:
|
if not passphrase:
|
||||||
raise APIError(1, 'The specified passphrase is blank.')
|
raise APIError(1, 'The specified passphrase is blank.')
|
||||||
if not isinstance(eighteenByteRipe, bool):
|
if not isinstance(eighteenByteRipe, bool):
|
||||||
raise APIError(
|
raise APIError(
|
||||||
|
@ -436,12 +460,14 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def HandleGetDeterministicAddress(self, params):
|
def HandleGetDeterministicAddress(self, params):
|
||||||
|
"""Handle a request to get a deterministic address"""
|
||||||
|
|
||||||
if len(params) != 3:
|
if len(params) != 3:
|
||||||
raise APIError(0, 'I need exactly 3 parameters.')
|
raise APIError(0, 'I need exactly 3 parameters.')
|
||||||
passphrase, addressVersionNumber, streamNumber = params
|
passphrase, addressVersionNumber, streamNumber = params
|
||||||
numberOfAddresses = 1
|
numberOfAddresses = 1
|
||||||
eighteenByteRipe = False
|
eighteenByteRipe = False
|
||||||
if len(passphrase) == 0:
|
if not passphrase:
|
||||||
raise APIError(1, 'The specified passphrase is blank.')
|
raise APIError(1, 'The specified passphrase is blank.')
|
||||||
passphrase = self._decode(passphrase, "base64")
|
passphrase = self._decode(passphrase, "base64")
|
||||||
if addressVersionNumber != 3 and addressVersionNumber != 4:
|
if addressVersionNumber != 3 and addressVersionNumber != 4:
|
||||||
|
@ -463,12 +489,16 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
|
||||||
return queues.apiAddressGeneratorReturnQueue.get()
|
return queues.apiAddressGeneratorReturnQueue.get()
|
||||||
|
|
||||||
def HandleCreateChan(self, params):
|
def HandleCreateChan(self, params):
|
||||||
if len(params) == 0:
|
"""Handle a request to create a chan"""
|
||||||
|
|
||||||
|
if not params:
|
||||||
raise APIError(0, 'I need parameters.')
|
raise APIError(0, 'I need parameters.')
|
||||||
|
|
||||||
elif len(params) == 1:
|
elif len(params) == 1:
|
||||||
passphrase, = params
|
passphrase, = params
|
||||||
passphrase = self._decode(passphrase, "base64")
|
passphrase = self._decode(passphrase, "base64")
|
||||||
if len(passphrase) == 0:
|
|
||||||
|
if not passphrase:
|
||||||
raise APIError(1, 'The specified passphrase is blank.')
|
raise APIError(1, 'The specified passphrase is blank.')
|
||||||
# It would be nice to make the label the passphrase but it is
|
# It would be nice to make the label the passphrase but it is
|
||||||
# possible that the passphrase contains non-utf-8 characters.
|
# possible that the passphrase contains non-utf-8 characters.
|
||||||
|
@ -488,18 +518,20 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
|
||||||
passphrase, True
|
passphrase, True
|
||||||
))
|
))
|
||||||
queueReturn = queues.apiAddressGeneratorReturnQueue.get()
|
queueReturn = queues.apiAddressGeneratorReturnQueue.get()
|
||||||
if len(queueReturn) == 0:
|
if not queueReturn:
|
||||||
raise APIError(24, 'Chan address is already present.')
|
raise APIError(24, 'Chan address is already present.')
|
||||||
address = queueReturn[0]
|
address = queueReturn[0]
|
||||||
return address
|
return address
|
||||||
|
|
||||||
def HandleJoinChan(self, params):
|
def HandleJoinChan(self, params):
|
||||||
|
"""Handle a request to join a chan"""
|
||||||
|
|
||||||
if len(params) < 2:
|
if len(params) < 2:
|
||||||
raise APIError(0, 'I need two parameters.')
|
raise APIError(0, 'I need two parameters.')
|
||||||
elif len(params) == 2:
|
elif len(params) == 2:
|
||||||
passphrase, suppliedAddress = params
|
passphrase, suppliedAddress = params
|
||||||
passphrase = self._decode(passphrase, "base64")
|
passphrase = self._decode(passphrase, "base64")
|
||||||
if len(passphrase) == 0:
|
if not passphrase:
|
||||||
raise APIError(1, 'The specified passphrase is blank.')
|
raise APIError(1, 'The specified passphrase is blank.')
|
||||||
# It would be nice to make the label the passphrase but it is
|
# It would be nice to make the label the passphrase but it is
|
||||||
# possible that the passphrase contains non-utf-8 characters.
|
# possible that the passphrase contains non-utf-8 characters.
|
||||||
|
@ -509,8 +541,8 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
|
||||||
except:
|
except:
|
||||||
label = str_chan + ' ' + repr(passphrase)
|
label = str_chan + ' ' + repr(passphrase)
|
||||||
|
|
||||||
status, addressVersionNumber, streamNumber, toRipe = \
|
status, addressVersionNumber, streamNumber, toRipe = self._verifyAddress( # pylint: disable=unused-variable
|
||||||
self._verifyAddress(suppliedAddress)
|
suppliedAddress)
|
||||||
suppliedAddress = addBMIfNotPresent(suppliedAddress)
|
suppliedAddress = addBMIfNotPresent(suppliedAddress)
|
||||||
queues.apiAddressGeneratorReturnQueue.queue.clear()
|
queues.apiAddressGeneratorReturnQueue.queue.clear()
|
||||||
queues.addressGeneratorQueue.put((
|
queues.addressGeneratorQueue.put((
|
||||||
|
@ -522,20 +554,19 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
|
||||||
if addressGeneratorReturnValue[0] == \
|
if addressGeneratorReturnValue[0] == \
|
||||||
'chan name does not match address':
|
'chan name does not match address':
|
||||||
raise APIError(18, 'Chan name does not match address.')
|
raise APIError(18, 'Chan name does not match address.')
|
||||||
if len(addressGeneratorReturnValue) == 0:
|
if not addressGeneratorReturnValue:
|
||||||
raise APIError(24, 'Chan address is already present.')
|
raise APIError(24, 'Chan address is already present.')
|
||||||
# TODO: this variable is not used to anything
|
|
||||||
# in case we ever want it for anything.
|
|
||||||
# createdAddress = addressGeneratorReturnValue[0]
|
|
||||||
return "success"
|
return "success"
|
||||||
|
|
||||||
def HandleLeaveChan(self, params):
|
def HandleLeaveChan(self, params):
|
||||||
if len(params) == 0:
|
"""Handle a request to leave a chan"""
|
||||||
|
|
||||||
|
if not params:
|
||||||
raise APIError(0, 'I need parameters.')
|
raise APIError(0, 'I need parameters.')
|
||||||
elif len(params) == 1:
|
elif len(params) == 1:
|
||||||
address, = params
|
address, = params
|
||||||
status, addressVersionNumber, streamNumber, toRipe = \
|
# pylint: disable=unused-variable
|
||||||
self._verifyAddress(address)
|
status, addressVersionNumber, streamNumber, toRipe = self._verifyAddress(address)
|
||||||
address = addBMIfNotPresent(address)
|
address = addBMIfNotPresent(address)
|
||||||
if not BMConfigParser().has_section(address):
|
if not BMConfigParser().has_section(address):
|
||||||
raise APIError(
|
raise APIError(
|
||||||
|
@ -550,12 +581,14 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
|
||||||
return 'success'
|
return 'success'
|
||||||
|
|
||||||
def HandleDeleteAddress(self, params):
|
def HandleDeleteAddress(self, params):
|
||||||
if len(params) == 0:
|
"""Handle a request to delete an address"""
|
||||||
|
|
||||||
|
if not params:
|
||||||
raise APIError(0, 'I need parameters.')
|
raise APIError(0, 'I need parameters.')
|
||||||
elif len(params) == 1:
|
elif len(params) == 1:
|
||||||
address, = params
|
address, = params
|
||||||
status, addressVersionNumber, streamNumber, toRipe = \
|
# pylint: disable=unused-variable
|
||||||
self._verifyAddress(address)
|
status, addressVersionNumber, streamNumber, toRipe = self._verifyAddress(address)
|
||||||
address = addBMIfNotPresent(address)
|
address = addBMIfNotPresent(address)
|
||||||
if not BMConfigParser().has_section(address):
|
if not BMConfigParser().has_section(address):
|
||||||
raise APIError(
|
raise APIError(
|
||||||
|
@ -568,7 +601,9 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
|
||||||
shared.reloadMyAddressHashes()
|
shared.reloadMyAddressHashes()
|
||||||
return 'success'
|
return 'success'
|
||||||
|
|
||||||
def HandleGetAllInboxMessages(self, params):
|
def HandleGetAllInboxMessages(self, params): # pylint: disable=unused-argument
|
||||||
|
"""Handle a request to get all inbox messages"""
|
||||||
|
|
||||||
queryreturn = sqlQuery(
|
queryreturn = sqlQuery(
|
||||||
"SELECT msgid, toaddress, fromaddress, subject, received, message,"
|
"SELECT msgid, toaddress, fromaddress, subject, received, message,"
|
||||||
" encodingtype, read FROM inbox where folder='inbox'"
|
" encodingtype, read FROM inbox where folder='inbox'"
|
||||||
|
@ -594,7 +629,9 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
|
||||||
data += ']}'
|
data += ']}'
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def HandleGetAllInboxMessageIds(self, params):
|
def HandleGetAllInboxMessageIds(self, params): # pylint: disable=unused-argument
|
||||||
|
"""Handle a request to get all inbox message IDs"""
|
||||||
|
|
||||||
queryreturn = sqlQuery(
|
queryreturn = sqlQuery(
|
||||||
"SELECT msgid FROM inbox where folder='inbox' ORDER BY received")
|
"SELECT msgid FROM inbox where folder='inbox' ORDER BY received")
|
||||||
data = '{"inboxMessageIds":['
|
data = '{"inboxMessageIds":['
|
||||||
|
@ -608,7 +645,9 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def HandleGetInboxMessageById(self, params):
|
def HandleGetInboxMessageById(self, params):
|
||||||
if len(params) == 0:
|
"""Handle a request to get an inbox messsage by ID"""
|
||||||
|
|
||||||
|
if not params:
|
||||||
raise APIError(0, 'I need parameters!')
|
raise APIError(0, 'I need parameters!')
|
||||||
elif len(params) == 1:
|
elif len(params) == 1:
|
||||||
msgid = self._decode(params[0], "hex")
|
msgid = self._decode(params[0], "hex")
|
||||||
|
@ -649,7 +688,9 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
|
||||||
data += ']}'
|
data += ']}'
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def HandleGetAllSentMessages(self, params):
|
def HandleGetAllSentMessages(self, params): # pylint: disable=unused-argument
|
||||||
|
"""Handle a request to get all sent messages"""
|
||||||
|
|
||||||
queryreturn = sqlQuery(
|
queryreturn = sqlQuery(
|
||||||
"SELECT msgid, toaddress, fromaddress, subject, lastactiontime,"
|
"SELECT msgid, toaddress, fromaddress, subject, lastactiontime,"
|
||||||
" message, encodingtype, status, ackdata FROM sent"
|
" message, encodingtype, status, ackdata FROM sent"
|
||||||
|
@ -676,7 +717,9 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
|
||||||
data += ']}'
|
data += ']}'
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def HandleGetAllSentMessageIds(self, params):
|
def HandleGetAllSentMessageIds(self, params): # pylint: disable=unused-argument
|
||||||
|
"""Handle a request to get all sent message IDs"""
|
||||||
|
|
||||||
queryreturn = sqlQuery(
|
queryreturn = sqlQuery(
|
||||||
"SELECT msgid FROM sent where folder='sent'"
|
"SELECT msgid FROM sent where folder='sent'"
|
||||||
" ORDER BY lastactiontime"
|
" ORDER BY lastactiontime"
|
||||||
|
@ -692,7 +735,9 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def HandleInboxMessagesByReceiver(self, params):
|
def HandleInboxMessagesByReceiver(self, params):
|
||||||
if len(params) == 0:
|
"""Handle a request to get inbox messages by receiver"""
|
||||||
|
|
||||||
|
if not params:
|
||||||
raise APIError(0, 'I need parameters!')
|
raise APIError(0, 'I need parameters!')
|
||||||
toAddress = params[0]
|
toAddress = params[0]
|
||||||
queryreturn = sqlQuery(
|
queryreturn = sqlQuery(
|
||||||
|
@ -719,7 +764,9 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def HandleGetSentMessageById(self, params):
|
def HandleGetSentMessageById(self, params):
|
||||||
if len(params) == 0:
|
"""Handle a request to get a sent message by ID"""
|
||||||
|
|
||||||
|
if not params:
|
||||||
raise APIError(0, 'I need parameters!')
|
raise APIError(0, 'I need parameters!')
|
||||||
msgid = self._decode(params[0], "hex")
|
msgid = self._decode(params[0], "hex")
|
||||||
queryreturn = sqlQuery(
|
queryreturn = sqlQuery(
|
||||||
|
@ -747,7 +794,9 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def HandleGetSentMessagesByAddress(self, params):
|
def HandleGetSentMessagesByAddress(self, params):
|
||||||
if len(params) == 0:
|
"""Handle a request to get sent messages by address"""
|
||||||
|
|
||||||
|
if not params:
|
||||||
raise APIError(0, 'I need parameters!')
|
raise APIError(0, 'I need parameters!')
|
||||||
fromAddress = params[0]
|
fromAddress = params[0]
|
||||||
queryreturn = sqlQuery(
|
queryreturn = sqlQuery(
|
||||||
|
@ -759,7 +808,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
|
||||||
data = '{"sentMessages":['
|
data = '{"sentMessages":['
|
||||||
for row in queryreturn:
|
for row in queryreturn:
|
||||||
msgid, toAddress, fromAddress, subject, lastactiontime, message, \
|
msgid, toAddress, fromAddress, subject, lastactiontime, message, \
|
||||||
encodingtype, status, ackdata = row
|
encodingtype, status, ackdata = row # pylint: disable=unused-variable
|
||||||
subject = shared.fixPotentiallyInvalidUTF8Data(subject)
|
subject = shared.fixPotentiallyInvalidUTF8Data(subject)
|
||||||
message = shared.fixPotentiallyInvalidUTF8Data(message)
|
message = shared.fixPotentiallyInvalidUTF8Data(message)
|
||||||
if len(data) > 25:
|
if len(data) > 25:
|
||||||
|
@ -778,7 +827,9 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def HandleGetSentMessagesByAckData(self, params):
|
def HandleGetSentMessagesByAckData(self, params):
|
||||||
if len(params) == 0:
|
"""Handle a request to get sent messages by ack data"""
|
||||||
|
|
||||||
|
if not params:
|
||||||
raise APIError(0, 'I need parameters!')
|
raise APIError(0, 'I need parameters!')
|
||||||
ackData = self._decode(params[0], "hex")
|
ackData = self._decode(params[0], "hex")
|
||||||
queryreturn = sqlQuery(
|
queryreturn = sqlQuery(
|
||||||
|
@ -806,7 +857,9 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def HandleTrashMessage(self, params):
|
def HandleTrashMessage(self, params):
|
||||||
if len(params) == 0:
|
"""Handle a request to trash a message by ID"""
|
||||||
|
|
||||||
|
if not params:
|
||||||
raise APIError(0, 'I need parameters!')
|
raise APIError(0, 'I need parameters!')
|
||||||
msgid = self._decode(params[0], "hex")
|
msgid = self._decode(params[0], "hex")
|
||||||
|
|
||||||
|
@ -817,32 +870,42 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
|
||||||
return 'Trashed message (assuming message existed).'
|
return 'Trashed message (assuming message existed).'
|
||||||
|
|
||||||
def HandleTrashInboxMessage(self, params):
|
def HandleTrashInboxMessage(self, params):
|
||||||
if len(params) == 0:
|
"""Handle a request to trash an inbox message by ID"""
|
||||||
|
|
||||||
|
if not params:
|
||||||
raise APIError(0, 'I need parameters!')
|
raise APIError(0, 'I need parameters!')
|
||||||
msgid = self._decode(params[0], "hex")
|
msgid = self._decode(params[0], "hex")
|
||||||
helper_inbox.trash(msgid)
|
helper_inbox.trash(msgid)
|
||||||
return 'Trashed inbox message (assuming message existed).'
|
return 'Trashed inbox message (assuming message existed).'
|
||||||
|
|
||||||
def HandleTrashSentMessage(self, params):
|
def HandleTrashSentMessage(self, params):
|
||||||
if len(params) == 0:
|
"""Handle a request to trash a sent message by ID"""
|
||||||
|
|
||||||
|
if not params:
|
||||||
raise APIError(0, 'I need parameters!')
|
raise APIError(0, 'I need parameters!')
|
||||||
msgid = self._decode(params[0], "hex")
|
msgid = self._decode(params[0], "hex")
|
||||||
sqlExecute('''UPDATE sent SET folder='trash' WHERE msgid=?''', msgid)
|
sqlExecute('''UPDATE sent SET folder='trash' WHERE msgid=?''', msgid)
|
||||||
return 'Trashed sent message (assuming message existed).'
|
return 'Trashed sent message (assuming message existed).'
|
||||||
|
|
||||||
def HandleSendMessage(self, params):
|
def HandleSendMessage(self, params):
|
||||||
if len(params) == 0:
|
"""Handle a request to send a message"""
|
||||||
|
|
||||||
|
if not params:
|
||||||
raise APIError(0, 'I need parameters!')
|
raise APIError(0, 'I need parameters!')
|
||||||
|
|
||||||
elif len(params) == 4:
|
elif len(params) == 4:
|
||||||
toAddress, fromAddress, subject, message = params
|
toAddress, fromAddress, subject, message = params
|
||||||
encodingType = 2
|
encodingType = 2
|
||||||
TTL = 4 * 24 * 60 * 60
|
TTL = 4 * 24 * 60 * 60
|
||||||
|
|
||||||
elif len(params) == 5:
|
elif len(params) == 5:
|
||||||
toAddress, fromAddress, subject, message, encodingType = params
|
toAddress, fromAddress, subject, message, encodingType = params
|
||||||
TTL = 4 * 24 * 60 * 60
|
TTL = 4 * 24 * 60 * 60
|
||||||
|
|
||||||
elif len(params) == 6:
|
elif len(params) == 6:
|
||||||
toAddress, fromAddress, subject, message, encodingType, TTL = \
|
toAddress, fromAddress, subject, message, encodingType, TTL = \
|
||||||
params
|
params
|
||||||
|
|
||||||
if encodingType not in [2, 3]:
|
if encodingType not in [2, 3]:
|
||||||
raise APIError(6, 'The encoding type must be 2 or 3.')
|
raise APIError(6, 'The encoding type must be 2 or 3.')
|
||||||
subject = self._decode(subject, "base64")
|
subject = self._decode(subject, "base64")
|
||||||
|
@ -855,6 +918,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
|
||||||
TTL = 28 * 24 * 60 * 60
|
TTL = 28 * 24 * 60 * 60
|
||||||
toAddress = addBMIfNotPresent(toAddress)
|
toAddress = addBMIfNotPresent(toAddress)
|
||||||
fromAddress = addBMIfNotPresent(fromAddress)
|
fromAddress = addBMIfNotPresent(fromAddress)
|
||||||
|
# pylint: disable=unused-variable
|
||||||
status, addressVersionNumber, streamNumber, toRipe = \
|
status, addressVersionNumber, streamNumber, toRipe = \
|
||||||
self._verifyAddress(toAddress)
|
self._verifyAddress(toAddress)
|
||||||
self._verifyAddress(fromAddress)
|
self._verifyAddress(fromAddress)
|
||||||
|
@ -894,7 +958,6 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
|
||||||
if queryreturn != []:
|
if queryreturn != []:
|
||||||
for row in queryreturn:
|
for row in queryreturn:
|
||||||
toLabel, = row
|
toLabel, = row
|
||||||
# apiSignalQueue.put(('displayNewSentMessage',(toAddress,toLabel,fromAddress,subject,message,ackdata)))
|
|
||||||
queues.UISignalQueue.put(('displayNewSentMessage', (
|
queues.UISignalQueue.put(('displayNewSentMessage', (
|
||||||
toAddress, toLabel, fromAddress, subject, message, ackdata)))
|
toAddress, toLabel, fromAddress, subject, message, ackdata)))
|
||||||
|
|
||||||
|
@ -903,19 +966,25 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
|
||||||
return hexlify(ackdata)
|
return hexlify(ackdata)
|
||||||
|
|
||||||
def HandleSendBroadcast(self, params):
|
def HandleSendBroadcast(self, params):
|
||||||
if len(params) == 0:
|
"""Handle a request to send a broadcast message"""
|
||||||
|
|
||||||
|
if not params:
|
||||||
raise APIError(0, 'I need parameters!')
|
raise APIError(0, 'I need parameters!')
|
||||||
|
|
||||||
if len(params) == 3:
|
if len(params) == 3:
|
||||||
fromAddress, subject, message = params
|
fromAddress, subject, message = params
|
||||||
encodingType = 2
|
encodingType = 2
|
||||||
TTL = 4 * 24 * 60 * 60
|
TTL = 4 * 24 * 60 * 60
|
||||||
|
|
||||||
elif len(params) == 4:
|
elif len(params) == 4:
|
||||||
fromAddress, subject, message, encodingType = params
|
fromAddress, subject, message, encodingType = params
|
||||||
TTL = 4 * 24 * 60 * 60
|
TTL = 4 * 24 * 60 * 60
|
||||||
elif len(params) == 5:
|
elif len(params) == 5:
|
||||||
fromAddress, subject, message, encodingType, TTL = params
|
fromAddress, subject, message, encodingType, TTL = params
|
||||||
|
|
||||||
if encodingType not in [2, 3]:
|
if encodingType not in [2, 3]:
|
||||||
raise APIError(6, 'The encoding type must be 2 or 3.')
|
raise APIError(6, 'The encoding type must be 2 or 3.')
|
||||||
|
|
||||||
subject = self._decode(subject, "base64")
|
subject = self._decode(subject, "base64")
|
||||||
message = self._decode(message, "base64")
|
message = self._decode(message, "base64")
|
||||||
if len(subject + message) > (2 ** 18 - 500):
|
if len(subject + message) > (2 ** 18 - 500):
|
||||||
|
@ -961,6 +1030,8 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
|
||||||
return hexlify(ackdata)
|
return hexlify(ackdata)
|
||||||
|
|
||||||
def HandleGetStatus(self, params):
|
def HandleGetStatus(self, params):
|
||||||
|
"""Handle a request to get the status of a sent message"""
|
||||||
|
|
||||||
if len(params) != 1:
|
if len(params) != 1:
|
||||||
raise APIError(0, 'I need one parameter!')
|
raise APIError(0, 'I need one parameter!')
|
||||||
ackdata, = params
|
ackdata, = params
|
||||||
|
@ -977,7 +1048,9 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
|
||||||
return status
|
return status
|
||||||
|
|
||||||
def HandleAddSubscription(self, params):
|
def HandleAddSubscription(self, params):
|
||||||
if len(params) == 0:
|
"""Handle a request to add a subscription"""
|
||||||
|
|
||||||
|
if not params:
|
||||||
raise APIError(0, 'I need parameters!')
|
raise APIError(0, 'I need parameters!')
|
||||||
if len(params) == 1:
|
if len(params) == 1:
|
||||||
address, = params
|
address, = params
|
||||||
|
@ -1007,6 +1080,8 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
|
||||||
return 'Added subscription.'
|
return 'Added subscription.'
|
||||||
|
|
||||||
def HandleDeleteSubscription(self, params):
|
def HandleDeleteSubscription(self, params):
|
||||||
|
"""Handle a request to delete a subscription"""
|
||||||
|
|
||||||
if len(params) != 1:
|
if len(params) != 1:
|
||||||
raise APIError(0, 'I need 1 parameter!')
|
raise APIError(0, 'I need 1 parameter!')
|
||||||
address, = params
|
address, = params
|
||||||
|
@ -1017,7 +1092,10 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
|
||||||
queues.UISignalQueue.put(('rerenderSubscriptions', ''))
|
queues.UISignalQueue.put(('rerenderSubscriptions', ''))
|
||||||
return 'Deleted subscription if it existed.'
|
return 'Deleted subscription if it existed.'
|
||||||
|
|
||||||
def ListSubscriptions(self, params):
|
def ListSubscriptions(self, params): # pylint: disable=unused-argument
|
||||||
|
"""Handle a request to list susbcriptions"""
|
||||||
|
|
||||||
|
# pylint: disable=unused-variable
|
||||||
queryreturn = sqlQuery(
|
queryreturn = sqlQuery(
|
||||||
"SELECT label, address, enabled FROM subscriptions")
|
"SELECT label, address, enabled FROM subscriptions")
|
||||||
data = {'subscriptions': []}
|
data = {'subscriptions': []}
|
||||||
|
@ -1032,6 +1110,8 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
|
||||||
return json.dumps(data, indent=4, separators=(',', ': '))
|
return json.dumps(data, indent=4, separators=(',', ': '))
|
||||||
|
|
||||||
def HandleDisseminatePreEncryptedMsg(self, params):
|
def HandleDisseminatePreEncryptedMsg(self, params):
|
||||||
|
"""Handle a request to disseminate an encrypted message"""
|
||||||
|
|
||||||
# The device issuing this command to PyBitmessage supplies a msg
|
# The device issuing this command to PyBitmessage supplies a msg
|
||||||
# object that has already been encrypted but which still needs the POW
|
# object that has already been encrypted but which still needs the POW
|
||||||
# to be done. PyBitmessage accepts this msg object and sends it out
|
# to be done. PyBitmessage accepts this msg object and sends it out
|
||||||
|
@ -1044,17 +1124,29 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
|
||||||
encryptedPayload = self._decode(encryptedPayload, "hex")
|
encryptedPayload = self._decode(encryptedPayload, "hex")
|
||||||
# Let us do the POW and attach it to the front
|
# Let us do the POW and attach it to the front
|
||||||
target = 2**64 / (
|
target = 2**64 / (
|
||||||
(len(encryptedPayload) + requiredPayloadLengthExtraBytes + 8)
|
(
|
||||||
* requiredAverageProofOfWorkNonceTrialsPerByte)
|
len(encryptedPayload) + requiredPayloadLengthExtraBytes + 8
|
||||||
|
) * requiredAverageProofOfWorkNonceTrialsPerByte
|
||||||
|
)
|
||||||
with shared.printLock:
|
with shared.printLock:
|
||||||
print '(For msg message via API) Doing proof of work. Total required difficulty:', float(requiredAverageProofOfWorkNonceTrialsPerByte) / defaults.networkDefaultProofOfWorkNonceTrialsPerByte, 'Required small message difficulty:', float(requiredPayloadLengthExtraBytes) / defaults.networkDefaultPayloadLengthExtraBytes
|
print(
|
||||||
|
'(For msg message via API) Doing proof of work. Total required difficulty:',
|
||||||
|
float(
|
||||||
|
requiredAverageProofOfWorkNonceTrialsPerByte
|
||||||
|
) / defaults.networkDefaultProofOfWorkNonceTrialsPerByte,
|
||||||
|
'Required small message difficulty:',
|
||||||
|
float(requiredPayloadLengthExtraBytes) / defaults.networkDefaultPayloadLengthExtraBytes,
|
||||||
|
)
|
||||||
powStartTime = time.time()
|
powStartTime = time.time()
|
||||||
initialHash = hashlib.sha512(encryptedPayload).digest()
|
initialHash = hashlib.sha512(encryptedPayload).digest()
|
||||||
trialValue, nonce = proofofwork.run(target, initialHash)
|
trialValue, nonce = proofofwork.run(target, initialHash)
|
||||||
with shared.printLock:
|
with shared.printLock:
|
||||||
print '(For msg message via API) Found proof of work', trialValue, 'Nonce:', nonce
|
print '(For msg message via API) Found proof of work', trialValue, 'Nonce:', nonce
|
||||||
try:
|
try:
|
||||||
print 'POW took', int(time.time() - powStartTime), 'seconds.', nonce / (time.time() - powStartTime), 'nonce trials per second.'
|
print(
|
||||||
|
'POW took', int(time.time() - powStartTime), 'seconds.',
|
||||||
|
nonce / (time.time() - powStartTime), 'nonce trials per second.',
|
||||||
|
)
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
encryptedPayload = pack('>Q', nonce) + encryptedPayload
|
encryptedPayload = pack('>Q', nonce) + encryptedPayload
|
||||||
|
@ -1071,14 +1163,18 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
|
||||||
queues.invQueue.put((toStreamNumber, inventoryHash))
|
queues.invQueue.put((toStreamNumber, inventoryHash))
|
||||||
|
|
||||||
def HandleTrashSentMessageByAckDAta(self, params):
|
def HandleTrashSentMessageByAckDAta(self, params):
|
||||||
|
"""Handle a request to trash a sent message by ackdata"""
|
||||||
|
|
||||||
# This API method should only be used when msgid is not available
|
# This API method should only be used when msgid is not available
|
||||||
if len(params) == 0:
|
if not params:
|
||||||
raise APIError(0, 'I need parameters!')
|
raise APIError(0, 'I need parameters!')
|
||||||
ackdata = self._decode(params[0], "hex")
|
ackdata = self._decode(params[0], "hex")
|
||||||
sqlExecute("UPDATE sent SET folder='trash' WHERE ackdata=?", ackdata)
|
sqlExecute("UPDATE sent SET folder='trash' WHERE ackdata=?", ackdata)
|
||||||
return 'Trashed sent message (assuming message existed).'
|
return 'Trashed sent message (assuming message existed).'
|
||||||
|
|
||||||
def HandleDissimatePubKey(self, params):
|
def HandleDissimatePubKey(self, params): # pylint: disable=unused-argument
|
||||||
|
"""Handle a request to disseminate a public key"""
|
||||||
|
|
||||||
# The device issuing this command to PyBitmessage supplies a pubkey
|
# The device issuing this command to PyBitmessage supplies a pubkey
|
||||||
# object to be disseminated to the rest of the Bitmessage network.
|
# object to be disseminated to the rest of the Bitmessage network.
|
||||||
# PyBitmessage accepts this pubkey object and sends it out to the rest
|
# PyBitmessage accepts this pubkey object and sends it out to the rest
|
||||||
|
@ -1090,9 +1186,9 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
|
||||||
payload = self._decode(payload, "hex")
|
payload = self._decode(payload, "hex")
|
||||||
|
|
||||||
# Let us do the POW
|
# Let us do the POW
|
||||||
target = 2 ** 64 / (
|
target = 2 ** 64 / ((
|
||||||
(len(payload) + defaults.networkDefaultPayloadLengthExtraBytes
|
len(payload) + defaults.networkDefaultPayloadLengthExtraBytes + 8
|
||||||
+ 8) * defaults.networkDefaultProofOfWorkNonceTrialsPerByte)
|
) * defaults.networkDefaultProofOfWorkNonceTrialsPerByte)
|
||||||
print '(For pubkey message via API) Doing proof of work...'
|
print '(For pubkey message via API) Doing proof of work...'
|
||||||
initialHash = hashlib.sha512(payload).digest()
|
initialHash = hashlib.sha512(payload).digest()
|
||||||
trialValue, nonce = proofofwork.run(target, initialHash)
|
trialValue, nonce = proofofwork.run(target, initialHash)
|
||||||
|
@ -1105,13 +1201,14 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
|
||||||
pubkeyReadPosition += 8
|
pubkeyReadPosition += 8
|
||||||
else:
|
else:
|
||||||
pubkeyReadPosition += 4
|
pubkeyReadPosition += 4
|
||||||
|
# pylint: disable=unused-variable
|
||||||
addressVersion, addressVersionLength = decodeVarint(
|
addressVersion, addressVersionLength = decodeVarint(
|
||||||
payload[pubkeyReadPosition:pubkeyReadPosition + 10])
|
payload[pubkeyReadPosition:pubkeyReadPosition + 10])
|
||||||
pubkeyReadPosition += addressVersionLength
|
pubkeyReadPosition += addressVersionLength
|
||||||
pubkeyStreamNumber = decodeVarint(
|
pubkeyStreamNumber = decodeVarint(
|
||||||
payload[pubkeyReadPosition:pubkeyReadPosition + 10])[0]
|
payload[pubkeyReadPosition:pubkeyReadPosition + 10])[0]
|
||||||
inventoryHash = calculateInventoryHash(payload)
|
inventoryHash = calculateInventoryHash(payload)
|
||||||
objectType = 1 # TODO: support v4 pubkeys
|
objectType = 1 # .. todo::: support v4 pubkeys
|
||||||
TTL = 28 * 24 * 60 * 60
|
TTL = 28 * 24 * 60 * 60
|
||||||
Inventory()[inventoryHash] = (
|
Inventory()[inventoryHash] = (
|
||||||
objectType, pubkeyStreamNumber, payload, int(time.time()) + TTL, ''
|
objectType, pubkeyStreamNumber, payload, int(time.time()) + TTL, ''
|
||||||
|
@ -1121,6 +1218,8 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
|
||||||
queues.invQueue.put((pubkeyStreamNumber, inventoryHash))
|
queues.invQueue.put((pubkeyStreamNumber, inventoryHash))
|
||||||
|
|
||||||
def HandleGetMessageDataByDestinationHash(self, params):
|
def HandleGetMessageDataByDestinationHash(self, params):
|
||||||
|
"""Handle a request to get message data by destination hash"""
|
||||||
|
|
||||||
# Method will eventually be used by a particular Android app to
|
# Method will eventually be used by a particular Android app to
|
||||||
# select relevant messages. Do not yet add this to the api
|
# select relevant messages. Do not yet add this to the api
|
||||||
# doc.
|
# doc.
|
||||||
|
@ -1161,10 +1260,12 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
|
||||||
data += ']}'
|
data += ']}'
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def HandleClientStatus(self, params):
|
def HandleClientStatus(self, params): # pylint: disable=unused-argument
|
||||||
if len(network.stats.connectedHostsList()) == 0:
|
"""Handle a request to get the status of the client"""
|
||||||
|
|
||||||
|
if not network.stats.connectedHostsList():
|
||||||
networkStatus = 'notConnected'
|
networkStatus = 'notConnected'
|
||||||
elif len(network.stats.connectedHostsList()) > 0 \
|
elif not network.stats.connectedHostsList() \
|
||||||
and not shared.clientHasReceivedIncomingConnections:
|
and not shared.clientHasReceivedIncomingConnections:
|
||||||
networkStatus = 'connectedButHaveNotReceivedIncomingConnections'
|
networkStatus = 'connectedButHaveNotReceivedIncomingConnections'
|
||||||
else:
|
else:
|
||||||
|
@ -1180,6 +1281,8 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
|
||||||
}, indent=4, separators=(',', ': '))
|
}, indent=4, separators=(',', ': '))
|
||||||
|
|
||||||
def HandleDecodeAddress(self, params):
|
def HandleDecodeAddress(self, params):
|
||||||
|
"""Handle a request to decode an address"""
|
||||||
|
|
||||||
# Return a meaningful decoding of an address.
|
# Return a meaningful decoding of an address.
|
||||||
if len(params) != 1:
|
if len(params) != 1:
|
||||||
raise APIError(0, 'I need 1 parameter!')
|
raise APIError(0, 'I need 1 parameter!')
|
||||||
|
@ -1193,26 +1296,38 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
|
||||||
}, indent=4, separators=(',', ': '))
|
}, indent=4, separators=(',', ': '))
|
||||||
|
|
||||||
def HandleHelloWorld(self, params):
|
def HandleHelloWorld(self, params):
|
||||||
|
"""Test two string params"""
|
||||||
|
|
||||||
a, b = params
|
a, b = params
|
||||||
return a + '-' + b
|
return a + '-' + b
|
||||||
|
|
||||||
def HandleAdd(self, params):
|
def HandleAdd(self, params):
|
||||||
|
"""Test two numeric params"""
|
||||||
|
|
||||||
a, b = params
|
a, b = params
|
||||||
return a + b
|
return a + b
|
||||||
|
|
||||||
def HandleStatusBar(self, params):
|
def HandleStatusBar(self, params):
|
||||||
|
"""Handle a request to update the status bar"""
|
||||||
|
|
||||||
message, = params
|
message, = params
|
||||||
queues.UISignalQueue.put(('updateStatusBar', message))
|
queues.UISignalQueue.put(('updateStatusBar', message))
|
||||||
|
|
||||||
def HandleDeleteAndVacuum(self, params):
|
def HandleDeleteAndVacuum(self, params):
|
||||||
|
"""Handle a request to run the deleteandvacuum stored procedure"""
|
||||||
|
|
||||||
if not params:
|
if not params:
|
||||||
sqlStoredProcedure('deleteandvacuume')
|
sqlStoredProcedure('deleteandvacuume')
|
||||||
return 'done'
|
return 'done'
|
||||||
|
return None
|
||||||
|
|
||||||
def HandleShutdown(self, params):
|
def HandleShutdown(self, params):
|
||||||
|
"""Handle a request to huutdown the client"""
|
||||||
|
|
||||||
if not params:
|
if not params:
|
||||||
shutdown.doCleanShutdown()
|
shutdown.doCleanShutdown()
|
||||||
return 'done'
|
return 'done'
|
||||||
|
return None
|
||||||
|
|
||||||
handlers = {}
|
handlers = {}
|
||||||
handlers['helloWorld'] = HandleHelloWorld
|
handlers['helloWorld'] = HandleHelloWorld
|
||||||
|
@ -1279,6 +1394,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
|
||||||
return self.handlers[method](self, params)
|
return self.handlers[method](self, params)
|
||||||
|
|
||||||
def _dispatch(self, method, params):
|
def _dispatch(self, method, params):
|
||||||
|
# pylint: disable=attribute-defined-outside-init
|
||||||
self.cookies = []
|
self.cookies = []
|
||||||
|
|
||||||
validuser = self.APIAuthenticateClient()
|
validuser = self.APIAuthenticateClient()
|
||||||
|
|
|
@ -1,37 +1,40 @@
|
||||||
#!/usr/bin/python2.7
|
#!/usr/bin/python2.7
|
||||||
# Copyright (c) 2012-2016 Jonathan Warren
|
# pylint: disable=no-self-use,too-many-branches,too-many-statements,too-many-locals
|
||||||
# Copyright (c) 2012-2018 The Bitmessage developers
|
"""
|
||||||
# Distributed under the MIT/X11 software license. See the accompanying
|
bitmessagemain.py
|
||||||
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
=================
|
||||||
|
|
||||||
# Right now, PyBitmessage only support connecting to stream 1. It doesn't
|
Copyright (c) 2012-2016 Jonathan Warren
|
||||||
# yet contain logic to expand into further streams.
|
Copyright (c) 2012-2018 The Bitmessage developers
|
||||||
|
Distributed under the MIT/X11 software license. See the accompanying
|
||||||
|
file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
# The software version variable is now held in shared.py
|
Right now, PyBitmessage only support connecting to stream 1. It doesn't
|
||||||
|
yet contain logic to expand into further streams.
|
||||||
|
|
||||||
import os
|
The software version variable is now held in shared.py
|
||||||
import sys
|
|
||||||
|
|
||||||
Why are you moving copyrights to docstring? Why are you moving copyrights to docstring?
Multi-line comments are better done with a triple quoted string. In particular, Sphinx (or rather effective rST comments) requires triple quoted strings. However a triple-quoted string is flagged by linters as 'string statement has no effect'. Perhaps a Sphinx section on copyright would be the best place to put these notices? Being part of a module docstring made more sense to me than loose in the top level in module, though I don't feel a Python file is the right place anyway. So continued in PR#1270. Multi-line comments are better done with a triple quoted string. In particular, Sphinx (or rather effective rST comments) requires triple quoted strings. However a triple-quoted string is flagged by linters as 'string statement has no effect'. Perhaps a Sphinx section on copyright would be the best place to put these notices? Being part of a module docstring made more sense to me than loose in the top level in module, though I don't feel a Python file is the right place anyway. So continued in PR#1270.
|
|||||||
app_dir = os.path.dirname(os.path.abspath(__file__))
|
"""
|
||||||
os.chdir(app_dir)
|
|
||||||
sys.path.insert(0, app_dir)
|
|
||||||
|
|
||||||
|
from __future__ import absolute_import
|
||||||
|
|
||||||
import depends
|
|
||||||
depends.check_dependencies()
|
|
||||||
|
|
||||||
# Used to capture a Ctrl-C keypress so that Bitmessage can shutdown gracefully.
|
|
||||||
import signal
|
|
||||||
# The next 3 are used for the API
|
|
||||||
from singleinstance import singleinstance
|
|
||||||
import errno
|
|
||||||
import socket
|
|
||||||
import ctypes
|
import ctypes
|
||||||
|
import errno
|
||||||
|
import getopt
|
||||||
|
import os
|
||||||
|
import signal
|
||||||
|
import socket
|
||||||
|
import sys
|
||||||
This will probably break script execution. This will probably break script execution.
|
|||||||
|
import threading
|
||||||
|
from random import randint
|
||||||
from struct import pack
|
from struct import pack
|
||||||
from subprocess import call
|
from subprocess import call
|
||||||
from time import sleep
|
from time import sleep
|
||||||
from random import randint
|
|
||||||
import getopt
|
|
||||||
|
# Used to capture a Ctrl-C keypress so that Bitmessage can shutdown gracefully.
|
||||||
|
# The next 3 are used for the API
|
||||||
|
from singleinstance import singleinstance
|
||||||
|
|
||||||
from api import MySimpleXMLRPCRequestHandler, StoppableXMLRPCServer
|
from api import MySimpleXMLRPCRequestHandler, StoppableXMLRPCServer
|
||||||
from helper_startup import (
|
from helper_startup import (
|
||||||
|
@ -39,11 +42,11 @@ from helper_startup import (
|
||||||
)
|
)
|
||||||
|
|
||||||
import defaults
|
import defaults
|
||||||
|
import depends
|
||||||
import shared
|
import shared
|
||||||
import knownnodes
|
import knownnodes
|
||||||
import state
|
import state
|
||||||
import shutdown
|
import shutdown
|
||||||
import threading
|
|
||||||
|
|
||||||
# Classes
|
# Classes
|
||||||
from class_sqlThread import sqlThread
|
from class_sqlThread import sqlThread
|
||||||
|
@ -72,7 +75,12 @@ import helper_generic
|
||||||
import helper_threading
|
import helper_threading
|
||||||
|
|
||||||
|
|
||||||
|
depends.check_dependencies()
|
||||||
|
|
||||||
|
|
||||||
def connectToStream(streamNumber):
|
def connectToStream(streamNumber):
|
||||||
|
"""Connect to a stream"""
|
||||||
|
|
||||||
state.streamsInWhichIAmParticipating.append(streamNumber)
|
state.streamsInWhichIAmParticipating.append(streamNumber)
|
||||||
selfInitiatedConnections[streamNumber] = {}
|
selfInitiatedConnections[streamNumber] = {}
|
||||||
|
|
||||||
|
@ -114,6 +122,8 @@ def _fixSocket():
|
||||||
addressToString = ctypes.windll.ws2_32.WSAAddressToStringA
|
addressToString = ctypes.windll.ws2_32.WSAAddressToStringA
|
||||||
|
|
||||||
def inet_ntop(family, host):
|
def inet_ntop(family, host):
|
||||||
|
"""Convert IPv4 and IPv6 addresses from binary to text form"""
|
||||||
|
|
||||||
if family == socket.AF_INET:
|
if family == socket.AF_INET:
|
||||||
if len(host) != 4:
|
if len(host) != 4:
|
||||||
raise ValueError("invalid IPv4 host")
|
raise ValueError("invalid IPv4 host")
|
||||||
|
@ -135,6 +145,8 @@ def _fixSocket():
|
||||||
stringToAddress = ctypes.windll.ws2_32.WSAStringToAddressA
|
stringToAddress = ctypes.windll.ws2_32.WSAStringToAddressA
|
||||||
|
|
||||||
def inet_pton(family, host):
|
def inet_pton(family, host):
|
||||||
|
"""Convert IPv4 and IPv6 addresses from text to binary form"""
|
||||||
|
|
||||||
buf = "\0" * 28
|
buf = "\0" * 28
|
||||||
lengthBuf = pack("I", len(buf))
|
lengthBuf = pack("I", len(buf))
|
||||||
if stringToAddress(str(host),
|
if stringToAddress(str(host),
|
||||||
|
@ -158,13 +170,15 @@ def _fixSocket():
|
||||||
socket.IPV6_V6ONLY = 27
|
socket.IPV6_V6ONLY = 27
|
||||||
|
|
||||||
|
|
||||||
# This thread, of which there is only one, runs the API.
|
|
||||||
class singleAPI(threading.Thread, helper_threading.StoppableThread):
|
class singleAPI(threading.Thread, helper_threading.StoppableThread):
|
||||||
|
"""This thread, of which there is only one, runs the API."""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
threading.Thread.__init__(self, name="singleAPI")
|
threading.Thread.__init__(self, name="singleAPI")
|
||||||
self.initStop()
|
self.initStop()
|
||||||
|
|
||||||
def stopThread(self):
|
def stopThread(self):
|
||||||
|
"""Stop the API thread"""
|
||||||
super(singleAPI, self).stopThread()
|
super(singleAPI, self).stopThread()
|
||||||
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
try:
|
try:
|
||||||
|
@ -178,9 +192,10 @@ class singleAPI(threading.Thread, helper_threading.StoppableThread):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
|
"""Run the API thread"""
|
||||||
port = BMConfigParser().getint('bitmessagesettings', 'apiport')
|
port = BMConfigParser().getint('bitmessagesettings', 'apiport')
|
||||||
try:
|
try:
|
||||||
from errno import WSAEADDRINUSE
|
from errno import WSAEADDRINUSE # pylint: disable=unused-variable
|
||||||
except (ImportError, AttributeError):
|
except (ImportError, AttributeError):
|
||||||
errno.WSAEADDRINUSE = errno.EADDRINUSE
|
errno.WSAEADDRINUSE = errno.EADDRINUSE
|
||||||
for attempt in range(50):
|
for attempt in range(50):
|
||||||
|
@ -215,15 +230,18 @@ if shared.useVeryEasyProofOfWorkForTesting:
|
||||||
defaults.networkDefaultPayloadLengthExtraBytes / 100)
|
defaults.networkDefaultPayloadLengthExtraBytes / 100)
|
||||||
|
|
||||||
|
|
||||||
class Main:
|
class Main(object):
|
||||||
|
"""The main app"""
|
||||||
|
|
||||||
def start(self):
|
def start(self):
|
||||||
|
"""Start the main app"""
|
||||||
_fixSocket()
|
_fixSocket()
|
||||||
|
|
||||||
daemon = BMConfigParser().safeGetBoolean(
|
daemon = BMConfigParser().safeGetBoolean(
|
||||||
'bitmessagesettings', 'daemon')
|
'bitmessagesettings', 'daemon')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
opts, args = getopt.getopt(
|
opts, _ = getopt.getopt(
|
||||||
sys.argv[1:], "hcdt",
|
sys.argv[1:], "hcdt",
|
||||||
["help", "curses", "daemon", "test"])
|
["help", "curses", "daemon", "test"])
|
||||||
|
|
||||||
|
@ -231,7 +249,7 @@ class Main:
|
||||||
self.usage()
|
self.usage()
|
||||||
sys.exit(2)
|
sys.exit(2)
|
||||||
|
|
||||||
for opt, arg in opts:
|
for opt, _ in opts:
|
||||||
if opt in ("-h", "--help"):
|
if opt in ("-h", "--help"):
|
||||||
self.usage()
|
self.usage()
|
||||||
sys.exit()
|
sys.exit()
|
||||||
|
@ -249,7 +267,7 @@ class Main:
|
||||||
|
|
||||||
if daemon and not state.testmode:
|
if daemon and not state.testmode:
|
||||||
with shared.printLock:
|
with shared.printLock:
|
||||||
print('Running as a daemon. Send TERM signal to end.')
|
print 'Running as a daemon. Send TERM signal to end.'
|
||||||
self.daemonize()
|
self.daemonize()
|
||||||
|
|
||||||
self.setSignalHandler()
|
self.setSignalHandler()
|
||||||
|
@ -381,8 +399,7 @@ class Main:
|
||||||
BMConfigParser().remove_option('bitmessagesettings', 'dontconnect')
|
BMConfigParser().remove_option('bitmessagesettings', 'dontconnect')
|
||||||
elif daemon is False:
|
elif daemon is False:
|
||||||
if state.curses:
|
if state.curses:
|
||||||
# if depends.check_curses():
|
print 'Running with curses'
|
||||||
print('Running with curses')
|
|
||||||
import bitmessagecurses
|
import bitmessagecurses
|
||||||
bitmessagecurses.runwrapper()
|
bitmessagecurses.runwrapper()
|
||||||
elif depends.check_pyqt():
|
elif depends.check_pyqt():
|
||||||
|
@ -411,6 +428,7 @@ class Main:
|
||||||
sleep(1)
|
sleep(1)
|
||||||
|
|
||||||
def daemonize(self):
|
def daemonize(self):
|
||||||
|
"""Daemonise"""
|
||||||
grandfatherPid = os.getpid()
|
grandfatherPid = os.getpid()
|
||||||
parentPid = None
|
parentPid = None
|
||||||
try:
|
try:
|
||||||
|
@ -420,7 +438,7 @@ class Main:
|
||||||
# wait until grandchild ready
|
# wait until grandchild ready
|
||||||
while True:
|
while True:
|
||||||
sleep(1)
|
sleep(1)
|
||||||
os._exit(0)
|
sys.exit(0)
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
# fork not implemented
|
# fork not implemented
|
||||||
pass
|
pass
|
||||||
|
@ -441,7 +459,7 @@ class Main:
|
||||||
# wait until child ready
|
# wait until child ready
|
||||||
while True:
|
while True:
|
||||||
sleep(1)
|
sleep(1)
|
||||||
os._exit(0)
|
sys.exit(0)
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
# fork not implemented
|
# fork not implemented
|
||||||
pass
|
pass
|
||||||
|
@ -463,11 +481,13 @@ class Main:
|
||||||
os.kill(grandfatherPid, signal.SIGTERM)
|
os.kill(grandfatherPid, signal.SIGTERM)
|
||||||
|
|
||||||
def setSignalHandler(self):
|
def setSignalHandler(self):
|
||||||
|
"""Register signal handlers"""
|
||||||
signal.signal(signal.SIGINT, helper_generic.signal_handler)
|
signal.signal(signal.SIGINT, helper_generic.signal_handler)
|
||||||
signal.signal(signal.SIGTERM, helper_generic.signal_handler)
|
signal.signal(signal.SIGTERM, helper_generic.signal_handler)
|
||||||
# signal.signal(signal.SIGINT, signal.SIG_DFL)
|
|
||||||
|
|
||||||
def usage(self):
|
def usage(self):
|
||||||
|
"""Print usage message"""
|
||||||
|
|
||||||
print 'Usage: ' + sys.argv[0] + ' [OPTIONS]'
|
print 'Usage: ' + sys.argv[0] + ' [OPTIONS]'
|
||||||
print '''
|
print '''
|
||||||
Options:
|
Options:
|
||||||
|
@ -480,12 +500,18 @@ All parameters are optional.
|
||||||
'''
|
'''
|
||||||
|
|
||||||
def stop(self):
|
def stop(self):
|
||||||
|
"""Stop the daemon"""
|
||||||
with shared.printLock:
|
with shared.printLock:
|
||||||
print('Stopping Bitmessage Deamon.')
|
print 'Stopping Bitmessage Daemon.'
|
||||||
shutdown.doCleanShutdown()
|
shutdown.doCleanShutdown()
|
||||||
|
|
||||||
# TODO: nice function but no one is using this
|
|
||||||
def getApiAddress(self):
|
def getApiAddress(self):
|
||||||
|
"""
|
||||||
|
Return the address and port the API is configured to use
|
||||||
|
|
||||||
|
.. todo:: nice function but no one is using this
|
||||||
|
"""
|
||||||
|
|
||||||
if not BMConfigParser().safeGetBoolean(
|
if not BMConfigParser().safeGetBoolean(
|
||||||
'bitmessagesettings', 'apienabled'):
|
'bitmessagesettings', 'apienabled'):
|
||||||
return None
|
return None
|
||||||
|
@ -495,14 +521,10 @@ All parameters are optional.
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
"""Create and start the main app"""
|
||||||
mainprogram = Main()
|
mainprogram = Main()
|
||||||
mainprogram.start()
|
mainprogram.start()
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
|
|
||||||
|
|
||||||
# So far, the creation of and management of the Bitmessage protocol and this
|
|
||||||
# client is a one-man operation. Bitcoin tips are quite appreciated.
|
|
||||||
# 1H5XaDA6fYENLbknwZyjiYXYPQaFjjLX2u
|
|
||||||
|
|
|
@ -1,20 +1,29 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
# pylint: disable=too-many-locals
|
||||||
|
"""
|
||||||
|
Form implementation generated from reading ui file 'bitmessageui.ui'
|
||||||
|
|
||||||
# Form implementation generated from reading ui file 'bitmessageui.ui'
|
Created: Mon Mar 23 22:18:07 2015
|
||||||
#
|
by: PyQt4 UI code generator 4.10.4
|
||||||
# Created: Mon Mar 23 22:18:07 2015
|
|
||||||
# by: PyQt4 UI code generator 4.10.4
|
WARNING! All changes made in this file will be lost!
|
||||||
#
|
"""
|
||||||
# WARNING! All changes made in this file will be lost!
|
|
||||||
|
from __future__ import absolute_import
|
||||||
|
|
||||||
|
import sys
|
||||||
|
|
||||||
from PyQt4 import QtCore, QtGui
|
from PyQt4 import QtCore, QtGui
|
||||||
|
|
||||||
from bmconfigparser import BMConfigParser
|
from bmconfigparser import BMConfigParser
|
||||||
from foldertree import AddressBookCompleter
|
from . import bitmessage_icons_rc # pylint: disable=unused-import
|
||||||
from messageview import MessageView
|
from . import settingsmixin
|
||||||
from messagecompose import MessageCompose
|
from .messageview import MessageView
|
||||||
import settingsmixin
|
from .messagecompose import MessageCompose
|
||||||
from networkstatus import NetworkStatus
|
from .networkstatus import NetworkStatus
|
||||||
from blacklist import Blacklist
|
from .blacklist import Blacklist
|
||||||
|
from .foldertree import AddressBookCompleter
|
||||||
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
_fromUtf8 = QtCore.QString.fromUtf8
|
_fromUtf8 = QtCore.QString.fromUtf8
|
||||||
|
@ -24,24 +33,38 @@ except AttributeError:
|
||||||
|
|
||||||
try:
|
try:
|
||||||
_encoding = QtGui.QApplication.UnicodeUTF8
|
_encoding = QtGui.QApplication.UnicodeUTF8
|
||||||
|
|
||||||
def _translate(context, text, disambig, encoding=QtCore.QCoreApplication.CodecForTr, n=None):
|
def _translate(context, text, disambig, encoding=QtCore.QCoreApplication.CodecForTr, n=None):
|
||||||
This changes break portable usage. This changes break portable usage.
Continued in PR#1271 Continued in PR#1271
|
|||||||
|
# pylint: disable=unused-argument
|
||||||
if n is None:
|
if n is None:
|
||||||
return QtGui.QApplication.translate(context, text, disambig, _encoding)
|
return QtGui.QApplication.translate(context, text, disambig, _encoding)
|
||||||
else:
|
|
||||||
return QtGui.QApplication.translate(context, text, disambig, _encoding, n)
|
return QtGui.QApplication.translate(context, text, disambig, _encoding, n)
|
||||||
|
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
|
|
||||||
def _translate(context, text, disambig, encoding=QtCore.QCoreApplication.CodecForTr, n=None):
|
def _translate(context, text, disambig, encoding=QtCore.QCoreApplication.CodecForTr, n=None):
|
||||||
|
# pylint: disable=unused-argument
|
||||||
if n is None:
|
if n is None:
|
||||||
return QtGui.QApplication.translate(context, text, disambig)
|
return QtGui.QApplication.translate(context, text, disambig)
|
||||||
else:
|
|
||||||
return QtGui.QApplication.translate(context, text, disambig, QtCore.QCoreApplication.CodecForTr, n)
|
return QtGui.QApplication.translate(context, text, disambig, QtCore.QCoreApplication.CodecForTr, n)
|
||||||
|
|
||||||
|
|
||||||
class Ui_MainWindow(object):
|
class Ui_MainWindow(object):
|
||||||
|
"""Encapsulate the main UI"""
|
||||||
|
# pylint: disable=too-many-instance-attributes,too-many-statements
|
||||||
|
|
||||||
def setupUi(self, MainWindow):
|
def setupUi(self, MainWindow):
|
||||||
|
"""Set up the UI"""
|
||||||
|
# pylint: disable=attribute-defined-outside-init
|
||||||
|
|
||||||
MainWindow.setObjectName(_fromUtf8("MainWindow"))
|
MainWindow.setObjectName(_fromUtf8("MainWindow"))
|
||||||
MainWindow.resize(885, 580)
|
MainWindow.resize(885, 580)
|
||||||
icon = QtGui.QIcon()
|
icon = QtGui.QIcon()
|
||||||
icon.addPixmap(QtGui.QPixmap(_fromUtf8(":/newPrefix/images/can-icon-24px.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
icon.addPixmap(
|
||||||
|
QtGui.QPixmap(
|
||||||
|
_fromUtf8(":/newPrefix/images/can-icon-24px.png")),
|
||||||
|
QtGui.QIcon.Normal,
|
||||||
|
QtGui.QIcon.Off)
|
||||||
MainWindow.setWindowIcon(icon)
|
MainWindow.setWindowIcon(icon)
|
||||||
MainWindow.setTabShape(QtGui.QTabWidget.Rounded)
|
MainWindow.setTabShape(QtGui.QTabWidget.Rounded)
|
||||||
self.centralwidget = QtGui.QWidget(MainWindow)
|
self.centralwidget = QtGui.QWidget(MainWindow)
|
||||||
|
@ -75,7 +98,11 @@ class Ui_MainWindow(object):
|
||||||
self.treeWidgetYourIdentities.setObjectName(_fromUtf8("treeWidgetYourIdentities"))
|
self.treeWidgetYourIdentities.setObjectName(_fromUtf8("treeWidgetYourIdentities"))
|
||||||
self.treeWidgetYourIdentities.resize(200, self.treeWidgetYourIdentities.height())
|
self.treeWidgetYourIdentities.resize(200, self.treeWidgetYourIdentities.height())
|
||||||
icon1 = QtGui.QIcon()
|
icon1 = QtGui.QIcon()
|
||||||
icon1.addPixmap(QtGui.QPixmap(_fromUtf8(":/newPrefix/images/identities.png")), QtGui.QIcon.Selected, QtGui.QIcon.Off)
|
icon1.addPixmap(
|
||||||
|
QtGui.QPixmap(
|
||||||
|
_fromUtf8(":/newPrefix/images/identities.png")),
|
||||||
|
QtGui.QIcon.Selected,
|
||||||
|
QtGui.QIcon.Off)
|
||||||
self.treeWidgetYourIdentities.headerItem().setIcon(0, icon1)
|
self.treeWidgetYourIdentities.headerItem().setIcon(0, icon1)
|
||||||
self.verticalSplitter_12.addWidget(self.treeWidgetYourIdentities)
|
self.verticalSplitter_12.addWidget(self.treeWidgetYourIdentities)
|
||||||
self.pushButtonNewAddress = QtGui.QPushButton(self.inbox)
|
self.pushButtonNewAddress = QtGui.QPushButton(self.inbox)
|
||||||
|
@ -175,7 +202,11 @@ class Ui_MainWindow(object):
|
||||||
self.tableWidgetAddressBook.resize(200, self.tableWidgetAddressBook.height())
|
self.tableWidgetAddressBook.resize(200, self.tableWidgetAddressBook.height())
|
||||||
item = QtGui.QTableWidgetItem()
|
item = QtGui.QTableWidgetItem()
|
||||||
icon3 = QtGui.QIcon()
|
icon3 = QtGui.QIcon()
|
||||||
icon3.addPixmap(QtGui.QPixmap(_fromUtf8(":/newPrefix/images/addressbook.png")), QtGui.QIcon.Selected, QtGui.QIcon.Off)
|
icon3.addPixmap(
|
||||||
|
QtGui.QPixmap(
|
||||||
|
_fromUtf8(":/newPrefix/images/addressbook.png")),
|
||||||
|
QtGui.QIcon.Selected,
|
||||||
|
QtGui.QIcon.Off)
|
||||||
item.setIcon(icon3)
|
item.setIcon(icon3)
|
||||||
self.tableWidgetAddressBook.setHorizontalHeaderItem(0, item)
|
self.tableWidgetAddressBook.setHorizontalHeaderItem(0, item)
|
||||||
item = QtGui.QTableWidgetItem()
|
item = QtGui.QTableWidgetItem()
|
||||||
|
@ -376,7 +407,11 @@ class Ui_MainWindow(object):
|
||||||
self.treeWidgetSubscriptions.setObjectName(_fromUtf8("treeWidgetSubscriptions"))
|
self.treeWidgetSubscriptions.setObjectName(_fromUtf8("treeWidgetSubscriptions"))
|
||||||
self.treeWidgetSubscriptions.resize(200, self.treeWidgetSubscriptions.height())
|
self.treeWidgetSubscriptions.resize(200, self.treeWidgetSubscriptions.height())
|
||||||
icon5 = QtGui.QIcon()
|
icon5 = QtGui.QIcon()
|
||||||
icon5.addPixmap(QtGui.QPixmap(_fromUtf8(":/newPrefix/images/subscriptions.png")), QtGui.QIcon.Selected, QtGui.QIcon.Off)
|
icon5.addPixmap(
|
||||||
|
QtGui.QPixmap(
|
||||||
|
_fromUtf8(":/newPrefix/images/subscriptions.png")),
|
||||||
|
QtGui.QIcon.Selected,
|
||||||
|
QtGui.QIcon.Off)
|
||||||
self.treeWidgetSubscriptions.headerItem().setIcon(0, icon5)
|
self.treeWidgetSubscriptions.headerItem().setIcon(0, icon5)
|
||||||
self.verticalSplitter_3.addWidget(self.treeWidgetSubscriptions)
|
self.verticalSplitter_3.addWidget(self.treeWidgetSubscriptions)
|
||||||
self.pushButtonAddSubscription = QtGui.QPushButton(self.subscriptions)
|
self.pushButtonAddSubscription = QtGui.QPushButton(self.subscriptions)
|
||||||
|
@ -455,7 +490,11 @@ class Ui_MainWindow(object):
|
||||||
self.horizontalSplitter_4.setCollapsible(1, False)
|
self.horizontalSplitter_4.setCollapsible(1, False)
|
||||||
self.gridLayout_3.addWidget(self.horizontalSplitter_4, 0, 0, 1, 1)
|
self.gridLayout_3.addWidget(self.horizontalSplitter_4, 0, 0, 1, 1)
|
||||||
icon6 = QtGui.QIcon()
|
icon6 = QtGui.QIcon()
|
||||||
icon6.addPixmap(QtGui.QPixmap(_fromUtf8(":/newPrefix/images/subscriptions.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
icon6.addPixmap(
|
||||||
|
QtGui.QPixmap(
|
||||||
|
_fromUtf8(":/newPrefix/images/subscriptions.png")),
|
||||||
|
QtGui.QIcon.Normal,
|
||||||
|
QtGui.QIcon.Off)
|
||||||
self.tabWidget.addTab(self.subscriptions, icon6, _fromUtf8(""))
|
self.tabWidget.addTab(self.subscriptions, icon6, _fromUtf8(""))
|
||||||
self.chans = QtGui.QWidget()
|
self.chans = QtGui.QWidget()
|
||||||
self.chans.setObjectName(_fromUtf8("chans"))
|
self.chans.setObjectName(_fromUtf8("chans"))
|
||||||
|
@ -475,7 +514,11 @@ class Ui_MainWindow(object):
|
||||||
self.treeWidgetChans.setObjectName(_fromUtf8("treeWidgetChans"))
|
self.treeWidgetChans.setObjectName(_fromUtf8("treeWidgetChans"))
|
||||||
self.treeWidgetChans.resize(200, self.treeWidgetChans.height())
|
self.treeWidgetChans.resize(200, self.treeWidgetChans.height())
|
||||||
icon7 = QtGui.QIcon()
|
icon7 = QtGui.QIcon()
|
||||||
icon7.addPixmap(QtGui.QPixmap(_fromUtf8(":/newPrefix/images/can-icon-16px.png")), QtGui.QIcon.Selected, QtGui.QIcon.Off)
|
icon7.addPixmap(
|
||||||
|
QtGui.QPixmap(
|
||||||
|
_fromUtf8(":/newPrefix/images/can-icon-16px.png")),
|
||||||
|
QtGui.QIcon.Selected,
|
||||||
|
QtGui.QIcon.Off)
|
||||||
self.treeWidgetChans.headerItem().setIcon(0, icon7)
|
self.treeWidgetChans.headerItem().setIcon(0, icon7)
|
||||||
self.verticalSplitter_17.addWidget(self.treeWidgetChans)
|
self.verticalSplitter_17.addWidget(self.treeWidgetChans)
|
||||||
self.pushButtonAddChan = QtGui.QPushButton(self.chans)
|
self.pushButtonAddChan = QtGui.QPushButton(self.chans)
|
||||||
|
@ -554,7 +597,11 @@ class Ui_MainWindow(object):
|
||||||
self.horizontalSplitter_7.setCollapsible(1, False)
|
self.horizontalSplitter_7.setCollapsible(1, False)
|
||||||
self.gridLayout_4.addWidget(self.horizontalSplitter_7, 0, 0, 1, 1)
|
self.gridLayout_4.addWidget(self.horizontalSplitter_7, 0, 0, 1, 1)
|
||||||
icon8 = QtGui.QIcon()
|
icon8 = QtGui.QIcon()
|
||||||
icon8.addPixmap(QtGui.QPixmap(_fromUtf8(":/newPrefix/images/can-icon-16px.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
icon8.addPixmap(
|
||||||
|
QtGui.QPixmap(
|
||||||
|
_fromUtf8(":/newPrefix/images/can-icon-16px.png")),
|
||||||
|
QtGui.QIcon.Normal,
|
||||||
|
QtGui.QIcon.Off)
|
||||||
self.tabWidget.addTab(self.chans, icon8, _fromUtf8(""))
|
self.tabWidget.addTab(self.chans, icon8, _fromUtf8(""))
|
||||||
self.blackwhitelist = Blacklist()
|
self.blackwhitelist = Blacklist()
|
||||||
self.tabWidget.addTab(self.blackwhitelist, QtGui.QIcon(":/newPrefix/images/blacklist.png"), "")
|
self.tabWidget.addTab(self.blackwhitelist, QtGui.QIcon(":/newPrefix/images/blacklist.png"), "")
|
||||||
|
@ -652,6 +699,8 @@ class Ui_MainWindow(object):
|
||||||
MainWindow.setTabOrder(self.textEditMessage, self.pushButtonAddSubscription)
|
MainWindow.setTabOrder(self.textEditMessage, self.pushButtonAddSubscription)
|
||||||
|
|
||||||
def updateNetworkSwitchMenuLabel(self, dontconnect=None):
|
def updateNetworkSwitchMenuLabel(self, dontconnect=None):
|
||||||
|
"""Restore last online/offline setting"""
|
||||||
|
|
||||||
if dontconnect is None:
|
if dontconnect is None:
|
||||||
dontconnect = BMConfigParser().safeGetBoolean(
|
dontconnect = BMConfigParser().safeGetBoolean(
|
||||||
'bitmessagesettings', 'dontconnect')
|
'bitmessagesettings', 'dontconnect')
|
||||||
|
@ -662,6 +711,8 @@ class Ui_MainWindow(object):
|
||||||
)
|
)
|
||||||
|
|
||||||
def retranslateUi(self, MainWindow):
|
def retranslateUi(self, MainWindow):
|
||||||
|
"""Re-translate the UI"""
|
||||||
|
|
||||||
MainWindow.setWindowTitle(_translate("MainWindow", "Bitmessage", None))
|
MainWindow.setWindowTitle(_translate("MainWindow", "Bitmessage", None))
|
||||||
self.treeWidgetYourIdentities.headerItem().setText(0, _translate("MainWindow", "Identities", None))
|
self.treeWidgetYourIdentities.headerItem().setText(0, _translate("MainWindow", "Identities", None))
|
||||||
self.pushButtonNewAddress.setText(_translate("MainWindow", "New Identity", None))
|
self.pushButtonNewAddress.setText(_translate("MainWindow", "New Identity", None))
|
||||||
|
@ -692,18 +743,32 @@ class Ui_MainWindow(object):
|
||||||
self.label_2.setText(_translate("MainWindow", "From:", None))
|
self.label_2.setText(_translate("MainWindow", "From:", None))
|
||||||
self.label.setText(_translate("MainWindow", "To:", None))
|
self.label.setText(_translate("MainWindow", "To:", None))
|
||||||
# self.textEditMessage.setHtml("")
|
# self.textEditMessage.setHtml("")
|
||||||
self.tabWidgetSend.setTabText(self.tabWidgetSend.indexOf(self.sendDirect), _translate("MainWindow", "Send ordinary Message", None))
|
self.tabWidgetSend.setTabText(
|
||||||
|
self.tabWidgetSend.indexOf(
|
||||||
|
self.sendDirect),
|
||||||
|
_translate(
|
||||||
|
"MainWindow", "Send ordinary Message", None))
|
||||||
self.label_8.setText(_translate("MainWindow", "From:", None))
|
self.label_8.setText(_translate("MainWindow", "From:", None))
|
||||||
self.label_7.setText(_translate("MainWindow", "Subject:", None))
|
self.label_7.setText(_translate("MainWindow", "Subject:", None))
|
||||||
# self.textEditMessageBroadcast.setHtml("")
|
# self.textEditMessageBroadcast.setHtml("")
|
||||||
self.tabWidgetSend.setTabText(self.tabWidgetSend.indexOf(self.sendBroadcast), _translate("MainWindow", "Send Message to your Subscribers", None))
|
self.tabWidgetSend.setTabText(
|
||||||
|
self.tabWidgetSend.indexOf(
|
||||||
|
self.sendBroadcast),
|
||||||
|
_translate(
|
||||||
|
"MainWindow", "Send Message to your Subscribers", None))
|
||||||
self.pushButtonTTL.setText(_translate("MainWindow", "TTL:", None))
|
self.pushButtonTTL.setText(_translate("MainWindow", "TTL:", None))
|
||||||
hours = 48
|
hours = 48
|
||||||
try:
|
try:
|
||||||
hours = int(BMConfigParser().getint('bitmessagesettings', 'ttl') / 60 / 60)
|
hours = int(BMConfigParser().getint('bitmessagesettings', 'ttl') / 60 / 60)
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
self.labelHumanFriendlyTTLDescription.setText(_translate("MainWindow", "%n hour(s)", None, QtCore.QCoreApplication.CodecForTr, hours))
|
self.labelHumanFriendlyTTLDescription.setText(
|
||||||
|
_translate(
|
||||||
|
"MainWindow",
|
||||||
|
"%n hour(s)",
|
||||||
|
None,
|
||||||
|
QtCore.QCoreApplication.CodecForTr,
|
||||||
|
hours))
|
||||||
self.pushButtonClear.setText(_translate("MainWindow", "Clear", None))
|
self.pushButtonClear.setText(_translate("MainWindow", "Clear", None))
|
||||||
self.pushButtonSend.setText(_translate("MainWindow", "Send", None))
|
self.pushButtonSend.setText(_translate("MainWindow", "Send", None))
|
||||||
self.tabWidget.setTabText(self.tabWidget.indexOf(self.send), _translate("MainWindow", "Send", None))
|
self.tabWidget.setTabText(self.tabWidget.indexOf(self.send), _translate("MainWindow", "Send", None))
|
||||||
|
@ -724,7 +789,11 @@ class Ui_MainWindow(object):
|
||||||
item.setText(_translate("MainWindow", "Subject", None))
|
item.setText(_translate("MainWindow", "Subject", None))
|
||||||
item = self.tableWidgetInboxSubscriptions.horizontalHeaderItem(3)
|
item = self.tableWidgetInboxSubscriptions.horizontalHeaderItem(3)
|
||||||
item.setText(_translate("MainWindow", "Received", None))
|
item.setText(_translate("MainWindow", "Received", None))
|
||||||
self.tabWidget.setTabText(self.tabWidget.indexOf(self.subscriptions), _translate("MainWindow", "Subscriptions", None))
|
self.tabWidget.setTabText(
|
||||||
|
self.tabWidget.indexOf(
|
||||||
|
self.subscriptions),
|
||||||
|
_translate(
|
||||||
|
"MainWindow", "Subscriptions", None))
|
||||||
self.treeWidgetChans.headerItem().setText(0, _translate("MainWindow", "Chans", None))
|
self.treeWidgetChans.headerItem().setText(0, _translate("MainWindow", "Chans", None))
|
||||||
self.pushButtonAddChan.setText(_translate("MainWindow", "Add Chan", None))
|
self.pushButtonAddChan.setText(_translate("MainWindow", "Add Chan", None))
|
||||||
self.inboxSearchLineEditChans.setPlaceholderText(_translate("MainWindow", "Search", None))
|
self.inboxSearchLineEditChans.setPlaceholderText(_translate("MainWindow", "Search", None))
|
||||||
|
@ -744,9 +813,17 @@ class Ui_MainWindow(object):
|
||||||
item.setText(_translate("MainWindow", "Received", None))
|
item.setText(_translate("MainWindow", "Received", None))
|
||||||
self.tabWidget.setTabText(self.tabWidget.indexOf(self.chans), _translate("MainWindow", "Chans", None))
|
self.tabWidget.setTabText(self.tabWidget.indexOf(self.chans), _translate("MainWindow", "Chans", None))
|
||||||
self.blackwhitelist.retranslateUi()
|
self.blackwhitelist.retranslateUi()
|
||||||
self.tabWidget.setTabText(self.tabWidget.indexOf(self.blackwhitelist), _translate("blacklist", "Blacklist", None))
|
self.tabWidget.setTabText(
|
||||||
|
self.tabWidget.indexOf(
|
||||||
|
self.blackwhitelist),
|
||||||
|
_translate(
|
||||||
|
"blacklist", "Blacklist", None))
|
||||||
self.networkstatus.retranslateUi()
|
self.networkstatus.retranslateUi()
|
||||||
self.tabWidget.setTabText(self.tabWidget.indexOf(self.networkstatus), _translate("networkstatus", "Network Status", None))
|
self.tabWidget.setTabText(
|
||||||
|
self.tabWidget.indexOf(
|
||||||
|
self.networkstatus),
|
||||||
|
_translate(
|
||||||
|
"networkstatus", "Network Status", None))
|
||||||
self.menuFile.setTitle(_translate("MainWindow", "File", None))
|
self.menuFile.setTitle(_translate("MainWindow", "File", None))
|
||||||
self.menuSettings.setTitle(_translate("MainWindow", "Settings", None))
|
self.menuSettings.setTitle(_translate("MainWindow", "Settings", None))
|
||||||
self.menuHelp.setTitle(_translate("MainWindow", "Help", None))
|
self.menuHelp.setTitle(_translate("MainWindow", "Help", None))
|
||||||
|
@ -759,19 +836,17 @@ class Ui_MainWindow(object):
|
||||||
self.actionSupport.setText(_translate("MainWindow", "Contact support", None))
|
self.actionSupport.setText(_translate("MainWindow", "Contact support", None))
|
||||||
self.actionAbout.setText(_translate("MainWindow", "About", None))
|
self.actionAbout.setText(_translate("MainWindow", "About", None))
|
||||||
self.actionSettings.setText(_translate("MainWindow", "Settings", None))
|
self.actionSettings.setText(_translate("MainWindow", "Settings", None))
|
||||||
self.actionRegenerateDeterministicAddresses.setText(_translate("MainWindow", "Regenerate deterministic addresses", None))
|
self.actionRegenerateDeterministicAddresses.setText(
|
||||||
|
_translate("MainWindow", "Regenerate deterministic addresses", None))
|
||||||
self.actionDeleteAllTrashedMessages.setText(_translate("MainWindow", "Delete all trashed messages", None))
|
self.actionDeleteAllTrashedMessages.setText(_translate("MainWindow", "Delete all trashed messages", None))
|
||||||
self.actionJoinChan.setText(_translate("MainWindow", "Join / Create chan", None))
|
self.actionJoinChan.setText(_translate("MainWindow", "Join / Create chan", None))
|
||||||
|
|
||||||
import bitmessage_icons_rc
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
import sys
|
|
||||||
|
|
||||||
app = QtGui.QApplication(sys.argv)
|
app = QtGui.QApplication(sys.argv)
|
||||||
MainWindow = settingsmixin.SMainWindow()
|
ThisMainWindow = settingsmixin.SMainWindow()
|
||||||
ui = Ui_MainWindow()
|
ui = Ui_MainWindow()
|
||||||
ui.setupUi(MainWindow)
|
ui.setupUi(ThisMainWindow)
|
||||||
MainWindow.show()
|
ThisMainWindow.show()
|
||||||
sys.exit(app.exec_())
|
sys.exit(app.exec_())
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,26 @@
|
||||||
#!/usr/bin/env python2.7
|
#!/usr/bin/env python2.7
|
||||||
This is unused module This is unused module
Removed in PR#1271 Removed in PR#1271
|
|||||||
|
# pylint: disable=no-self-use
|
||||||
|
"""
|
||||||
|
newaddresswizard.py
|
||||||
|
===================
|
||||||
|
"""
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
|
||||||
from PyQt4 import QtCore, QtGui
|
from PyQt4 import QtCore, QtGui
|
||||||
|
|
||||||
|
|
||||||
class NewAddressWizardIntroPage(QtGui.QWizardPage):
|
class NewAddressWizardIntroPage(QtGui.QWizardPage):
|
||||||
|
"""The introduction page for the new address wizard"""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super(QtGui.QWizardPage, self).__init__()
|
super(NewAddressWizardIntroPage, self).__init__()
|
||||||
self.setTitle("Creating a new address")
|
self.setTitle("Creating a new address")
|
||||||
|
|
||||||
label = QtGui.QLabel("This wizard will help you create as many addresses as you like. Indeed, creating and abandoning addresses is encouraged.\n\n"
|
label = QtGui.QLabel(
|
||||||
|
"This wizard will help you create as many addresses as you like."
|
||||||
|
" Indeed, creating and abandoning addresses is encouraged.\n\n"
|
||||||
"What type of address would you like? Would you like to send emails or not?\n"
|
"What type of address would you like? Would you like to send emails or not?\n"
|
||||||
"You can still change your mind later, and register/unregister with an email service provider.\n\n")
|
"You can still change your mind later, and register/unregister with an email service provider.\n\n")
|
||||||
label.setWordWrap(True)
|
label.setWordWrap(True)
|
||||||
|
@ -24,28 +38,33 @@ class NewAddressWizardIntroPage(QtGui.QWizardPage):
|
||||||
self.setLayout(layout)
|
self.setLayout(layout)
|
||||||
|
|
||||||
def nextId(self):
|
def nextId(self):
|
||||||
|
"""Page 1 or 4"""
|
||||||
|
|
||||||
if self.emailAsWell.isChecked():
|
if self.emailAsWell.isChecked():
|
||||||
return 4
|
return 4
|
||||||
else:
|
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
|
|
||||||
class NewAddressWizardRngPassphrasePage(QtGui.QWizardPage):
|
class NewAddressWizardRngPassphrasePage(QtGui.QWizardPage):
|
||||||
|
"""The user chose a random or passphrase-based address"""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super(QtGui.QWizardPage, self).__init__()
|
super(NewAddressWizardRngPassphrasePage, self).__init__()
|
||||||
self.setTitle("Random or Passphrase")
|
self.setTitle("Random or Passphrase")
|
||||||
|
|
||||||
label = QtGui.QLabel("<html><head/><body><p>You may generate addresses by using either random numbers or by using a passphrase. "
|
label = QtGui.QLabel(
|
||||||
|
"<html><head/><body><p>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."
|
" 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:</p>"
|
" The \'Random Number\' option is selected by default but deterministic addresses have several pros and"
|
||||||
"<table border=0><tr><td><span style=\" font-weight:600;\">Pros:</span></td><td><span style=\" font-weight:600;\">Cons:</span></td></tr>"
|
" cons:</p><table border=0><tr><td><span style=\" font-weight:600;\">Pros:</span></td>"
|
||||||
|
" <td><span style=\" font-weight:600;\">Cons:</span></td></tr>"
|
||||||
" <tr><td>You can recreate your addresses on any computer from memory."
|
" <tr><td>You can recreate your addresses on any computer from memory."
|
||||||
" You need-not worry about backing up your keys.dat file as long as you can remember your passphrase.</td>"
|
" You need-not worry about backing up your keys.dat file as long as you can remember your passphrase.</td>"
|
||||||
" <td>You must remember (or write down) your passphrase if you expect to be able"
|
" <td>You must remember (or write down) your passphrase if you expect to be able"
|
||||||
" to recreate your keys if they are lost."
|
" to recreate your keys if they are lost."
|
||||||
# "You must remember the address version number and the stream number along with your passphrase. "
|
# "You must remember the address version number and the stream number along with your passphrase. "
|
||||||
"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."
|
" If you choose a weak passphrase and someone on the Internet can brute-force it, they can read your"
|
||||||
"</p></body></html>")
|
" messages and send messages as you.</p></body></html>")
|
||||||
label.setWordWrap(True)
|
label.setWordWrap(True)
|
||||||
|
|
||||||
self.randomAddress = QtGui.QRadioButton("Use a random number generator to make an address")
|
self.randomAddress = QtGui.QRadioButton("Use a random number generator to make an address")
|
||||||
|
@ -59,14 +78,18 @@ class NewAddressWizardRngPassphrasePage(QtGui.QWizardPage):
|
||||||
self.setLayout(layout)
|
self.setLayout(layout)
|
||||||
|
|
||||||
def nextId(self):
|
def nextId(self):
|
||||||
|
"""Page 2"""
|
||||||
|
|
||||||
if self.randomAddress.isChecked():
|
if self.randomAddress.isChecked():
|
||||||
return 2
|
return 2
|
||||||
else:
|
|
||||||
return 3
|
return 3
|
||||||
|
|
||||||
|
|
||||||
class NewAddressWizardRandomPage(QtGui.QWizardPage):
|
class NewAddressWizardRandomPage(QtGui.QWizardPage):
|
||||||
|
"""The user chose a new random address"""
|
||||||
|
|
||||||
def __init__(self, addresses):
|
def __init__(self, addresses):
|
||||||
super(QtGui.QWizardPage, self).__init__()
|
super(NewAddressWizardRandomPage, self).__init__()
|
||||||
self.setTitle("Random")
|
self.setTitle("Random")
|
||||||
|
|
||||||
label = QtGui.QLabel("Random address.")
|
label = QtGui.QLabel("Random address.")
|
||||||
|
@ -75,7 +98,8 @@ class NewAddressWizardRandomPage(QtGui.QWizardPage):
|
||||||
labelLabel = QtGui.QLabel("Label (not shown to anyone except you):")
|
labelLabel = QtGui.QLabel("Label (not shown to anyone except you):")
|
||||||
self.labelLineEdit = QtGui.QLineEdit()
|
self.labelLineEdit = QtGui.QLineEdit()
|
||||||
|
|
||||||
self.radioButtonMostAvailable = QtGui.QRadioButton("Use the most available stream\n"
|
self.radioButtonMostAvailable = QtGui.QRadioButton(
|
||||||
|
"Use the most available stream\n"
|
||||||
"(best if this is the first of many addresses you will create)")
|
"(best if this is the first of many addresses you will create)")
|
||||||
self.radioButtonExisting = QtGui.QRadioButton("Use the same stream as an existing address\n"
|
self.radioButtonExisting = QtGui.QRadioButton("Use the same stream as an existing address\n"
|
||||||
"(saves you some bandwidth and processing power)")
|
"(saves you some bandwidth and processing power)")
|
||||||
|
@ -87,8 +111,8 @@ class NewAddressWizardRandomPage(QtGui.QWizardPage):
|
||||||
for address in addresses:
|
for address in addresses:
|
||||||
self.comboBoxExisting.addItem(address)
|
self.comboBoxExisting.addItem(address)
|
||||||
|
|
||||||
# self.comboBoxExisting.setObjectName(_fromUtf8("comboBoxExisting"))
|
self.checkBoxEighteenByteRipe = QtGui.QCheckBox(
|
||||||
self.checkBoxEighteenByteRipe = QtGui.QCheckBox("Spend several minutes of extra computing time to make the address(es) 1 or 2 characters shorter")
|
"Spend several minutes of extra computing time to make the address(es) 1 or 2 characters shorter")
|
||||||
|
|
||||||
layout = QtGui.QGridLayout()
|
layout = QtGui.QGridLayout()
|
||||||
layout.addWidget(label, 0, 0)
|
layout.addWidget(label, 0, 0)
|
||||||
|
@ -100,24 +124,27 @@ class NewAddressWizardRandomPage(QtGui.QWizardPage):
|
||||||
layout.addWidget(self.checkBoxEighteenByteRipe, 6, 0)
|
layout.addWidget(self.checkBoxEighteenByteRipe, 6, 0)
|
||||||
self.setLayout(layout)
|
self.setLayout(layout)
|
||||||
|
|
||||||
QtCore.QObject.connect(self.radioButtonExisting, QtCore.SIGNAL("toggled(bool)"), self.comboBoxExisting.setEnabled)
|
QtCore.QObject.connect( # pylint: disable=no-member
|
||||||
|
self.radioButtonExisting,
|
||||||
|
QtCore.SIGNAL("toggled(bool)"),
|
||||||
|
self.comboBoxExisting.setEnabled)
|
||||||
|
|
||||||
self.registerField("label", self.labelLineEdit)
|
self.registerField("label", self.labelLineEdit)
|
||||||
self.registerField("radioButtonMostAvailable", self.radioButtonMostAvailable)
|
self.registerField("radioButtonMostAvailable", self.radioButtonMostAvailable)
|
||||||
self.registerField("radioButtonExisting", self.radioButtonExisting)
|
self.registerField("radioButtonExisting", self.radioButtonExisting)
|
||||||
self.registerField("comboBoxExisting", self.comboBoxExisting)
|
self.registerField("comboBoxExisting", self.comboBoxExisting)
|
||||||
|
|
||||||
# self.emailAsWell = QtGui.QRadioButton("Combined email and bitmessage account")
|
|
||||||
# self.onlyBM = QtGui.QRadioButton("Bitmessage-only account (no email)")
|
|
||||||
# self.emailAsWell.setChecked(True)
|
|
||||||
|
|
||||||
def nextId(self):
|
def nextId(self):
|
||||||
|
"""Page 6"""
|
||||||
|
|
||||||
return 6
|
return 6
|
||||||
|
|
||||||
|
|
||||||
class NewAddressWizardPassphrasePage(QtGui.QWizardPage):
|
class NewAddressWizardPassphrasePage(QtGui.QWizardPage):
|
||||||
|
"""The user chose a passphrase-based address"""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super(QtGui.QWizardPage, self).__init__()
|
super(NewAddressWizardPassphrasePage, self).__init__()
|
||||||
self.setTitle("Passphrase")
|
self.setTitle("Passphrase")
|
||||||
|
|
||||||
label = QtGui.QLabel("Deterministric address.")
|
label = QtGui.QLabel("Deterministric address.")
|
||||||
|
@ -126,7 +153,8 @@ class NewAddressWizardPassphrasePage(QtGui.QWizardPage):
|
||||||
passphraseLabel = QtGui.QLabel("Passphrase")
|
passphraseLabel = QtGui.QLabel("Passphrase")
|
||||||
self.lineEditPassphrase = QtGui.QLineEdit()
|
self.lineEditPassphrase = QtGui.QLineEdit()
|
||||||
self.lineEditPassphrase.setEchoMode(QtGui.QLineEdit.Password)
|
self.lineEditPassphrase.setEchoMode(QtGui.QLineEdit.Password)
|
||||||
self.lineEditPassphrase.setInputMethodHints(QtCore.Qt.ImhHiddenText|QtCore.Qt.ImhNoAutoUppercase|QtCore.Qt.ImhNoPredictiveText)
|
self.lineEditPassphrase.setInputMethodHints(
|
||||||
|
QtCore.Qt.ImhHiddenText | QtCore.Qt.ImhNoAutoUppercase | QtCore.Qt.ImhNoPredictiveText)
|
||||||
retypePassphraseLabel = QtGui.QLabel("Retype passphrase")
|
retypePassphraseLabel = QtGui.QLabel("Retype passphrase")
|
||||||
self.lineEditPassphraseAgain = QtGui.QLineEdit()
|
self.lineEditPassphraseAgain = QtGui.QLineEdit()
|
||||||
self.lineEditPassphraseAgain.setEchoMode(QtGui.QLineEdit.Password)
|
self.lineEditPassphraseAgain.setEchoMode(QtGui.QLineEdit.Password)
|
||||||
|
@ -135,7 +163,7 @@ class NewAddressWizardPassphrasePage(QtGui.QWizardPage):
|
||||||
self.spinBoxNumberOfAddressesToMake = QtGui.QSpinBox()
|
self.spinBoxNumberOfAddressesToMake = QtGui.QSpinBox()
|
||||||
self.spinBoxNumberOfAddressesToMake.setMinimum(1)
|
self.spinBoxNumberOfAddressesToMake.setMinimum(1)
|
||||||
self.spinBoxNumberOfAddressesToMake.setProperty("value", 8)
|
self.spinBoxNumberOfAddressesToMake.setProperty("value", 8)
|
||||||
# self.spinBoxNumberOfAddressesToMake.setObjectName(_fromUtf8("spinBoxNumberOfAddressesToMake"))
|
|
||||||
label2 = QtGui.QLabel("In addition to your passphrase, you must remember these numbers:")
|
label2 = QtGui.QLabel("In addition to your passphrase, you must remember these numbers:")
|
||||||
label3 = QtGui.QLabel("Address version number: 4")
|
label3 = QtGui.QLabel("Address version number: 4")
|
||||||
label4 = QtGui.QLabel("Stream number: 1")
|
label4 = QtGui.QLabel("Stream number: 1")
|
||||||
|
@ -155,12 +183,16 @@ class NewAddressWizardPassphrasePage(QtGui.QWizardPage):
|
||||||
self.setLayout(layout)
|
self.setLayout(layout)
|
||||||
|
|
||||||
def nextId(self):
|
def nextId(self):
|
||||||
|
"""Page 6"""
|
||||||
|
|
||||||
return 6
|
return 6
|
||||||
|
|
||||||
|
|
||||||
class NewAddressWizardEmailProviderPage(QtGui.QWizardPage):
|
class NewAddressWizardEmailProviderPage(QtGui.QWizardPage):
|
||||||
|
"""The user choses the email gateway address type"""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super(QtGui.QWizardPage, self).__init__()
|
super(NewAddressWizardEmailProviderPage, self).__init__()
|
||||||
self.setTitle("Choose email provider")
|
self.setTitle("Choose email provider")
|
||||||
|
|
||||||
label = QtGui.QLabel("Currently only Mailchuck email gateway is available "
|
label = QtGui.QLabel("Currently only Mailchuck email gateway is available "
|
||||||
|
@ -168,21 +200,22 @@ class NewAddressWizardEmailProviderPage(QtGui.QWizardPage):
|
||||||
"Press Next.")
|
"Press Next.")
|
||||||
label.setWordWrap(True)
|
label.setWordWrap(True)
|
||||||
|
|
||||||
# self.mailchuck = QtGui.QRadioButton("Mailchuck email gateway (@mailchuck.com)")
|
|
||||||
# self.mailchuck.setChecked(True)
|
|
||||||
|
|
||||||
layout = QtGui.QVBoxLayout()
|
layout = QtGui.QVBoxLayout()
|
||||||
layout.addWidget(label)
|
layout.addWidget(label)
|
||||||
# layout.addWidget(self.mailchuck)
|
|
||||||
self.setLayout(layout)
|
self.setLayout(layout)
|
||||||
|
|
||||||
def nextId(self):
|
def nextId(self):
|
||||||
|
"""Page 5"""
|
||||||
|
|
||||||
return 5
|
return 5
|
||||||
|
|
||||||
|
|
||||||
class NewAddressWizardEmailAddressPage(QtGui.QWizardPage):
|
class NewAddressWizardEmailAddressPage(QtGui.QWizardPage):
|
||||||
|
"""The user provides their email gateway detauils"""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super(QtGui.QWizardPage, self).__init__()
|
super(NewAddressWizardEmailAddressPage, self).__init__()
|
||||||
self.setTitle("Email address")
|
self.setTitle("Email address")
|
||||||
|
|
||||||
label = QtGui.QLabel("Choosing an email address. Address must end with @mailchuck.com")
|
label = QtGui.QLabel("Choosing an email address. Address must end with @mailchuck.com")
|
||||||
|
@ -193,7 +226,8 @@ class NewAddressWizardEmailAddressPage(QtGui.QWizardPage):
|
||||||
self.emailLineEdit = QtGui.QLineEdit()
|
self.emailLineEdit = QtGui.QLineEdit()
|
||||||
self.randomEmail = QtGui.QRadioButton("Generate a random email address")
|
self.randomEmail = QtGui.QRadioButton("Generate a random email address")
|
||||||
|
|
||||||
QtCore.QObject.connect(self.specificEmail, QtCore.SIGNAL("toggled(bool)"), self.emailLineEdit.setEnabled)
|
QtCore.QObject.connect( # pylint: disable=no-member
|
||||||
|
self.specificEmail, QtCore.SIGNAL("toggled(bool)"), self.emailLineEdit.setEnabled)
|
||||||
|
|
||||||
layout = QtGui.QVBoxLayout()
|
layout = QtGui.QVBoxLayout()
|
||||||
layout.addWidget(label)
|
layout.addWidget(label)
|
||||||
|
@ -203,12 +237,16 @@ class NewAddressWizardEmailAddressPage(QtGui.QWizardPage):
|
||||||
self.setLayout(layout)
|
self.setLayout(layout)
|
||||||
|
|
||||||
def nextId(self):
|
def nextId(self):
|
||||||
|
"""Page 6"""
|
||||||
|
|
||||||
return 6
|
return 6
|
||||||
|
|
||||||
|
|
||||||
class NewAddressWizardWaitPage(QtGui.QWizardPage):
|
class NewAddressWizardWaitPage(QtGui.QWizardPage):
|
||||||
|
"""Wait for the address to be generated"""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super(QtGui.QWizardPage, self).__init__()
|
super(NewAddressWizardWaitPage, self).__init__()
|
||||||
self.setTitle("Wait")
|
self.setTitle("Wait")
|
||||||
|
|
||||||
self.label = QtGui.QLabel("Wait!")
|
self.label = QtGui.QLabel("Wait!")
|
||||||
|
@ -218,18 +256,18 @@ class NewAddressWizardWaitPage(QtGui.QWizardPage):
|
||||||
self.progressBar.setMaximum(100)
|
self.progressBar.setMaximum(100)
|
||||||
self.progressBar.setValue(0)
|
self.progressBar.setValue(0)
|
||||||
|
|
||||||
# self.emailAsWell = QtGui.QRadioButton("Combined email and bitmessage account")
|
|
||||||
# self.onlyBM = QtGui.QRadioButton("Bitmessage-only account (no email)")
|
|
||||||
# self.emailAsWell.setChecked(True)
|
|
||||||
|
|
||||||
layout = QtGui.QVBoxLayout()
|
layout = QtGui.QVBoxLayout()
|
||||||
layout.addWidget(self.label)
|
layout.addWidget(self.label)
|
||||||
layout.addWidget(self.progressBar)
|
layout.addWidget(self.progressBar)
|
||||||
# layout.addWidget(self.emailAsWell)
|
|
||||||
# layout.addWidget(self.onlyBM)
|
|
||||||
self.setLayout(layout)
|
self.setLayout(layout)
|
||||||
|
|
||||||
def update(self, i):
|
def update(self, i):
|
||||||
|
"""
|
||||||
|
Update the progress bar
|
||||||
|
|
||||||
|
.. todo:: remove print statement?
|
||||||
|
"""
|
||||||
if i == 101 and self.wizard().currentId() == 6:
|
if i == 101 and self.wizard().currentId() == 6:
|
||||||
self.wizard().button(QtGui.QWizard.NextButton).click()
|
self.wizard().button(QtGui.QWizard.NextButton).click()
|
||||||
return
|
return
|
||||||
|
@ -241,13 +279,15 @@ class NewAddressWizardWaitPage(QtGui.QWizardPage):
|
||||||
self.emit(QtCore.SIGNAL('completeChanged()'))
|
self.emit(QtCore.SIGNAL('completeChanged()'))
|
||||||
|
|
||||||
def isComplete(self):
|
def isComplete(self):
|
||||||
# print "val = " + str(self.progressBar.value())
|
"""Predicate to indicate progress is complete"""
|
||||||
|
|
||||||
if self.progressBar.value() >= 50:
|
if self.progressBar.value() >= 50:
|
||||||
return True
|
return True
|
||||||
else:
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def initializePage(self):
|
def initializePage(self):
|
||||||
|
"""Initialize the underlying QWizardPage"""
|
||||||
|
|
||||||
if self.field("emailAsWell").toBool():
|
if self.field("emailAsWell").toBool():
|
||||||
val = "yes/"
|
val = "yes/"
|
||||||
else:
|
else:
|
||||||
|
@ -258,19 +298,23 @@ class NewAddressWizardWaitPage(QtGui.QWizardPage):
|
||||||
val += "no"
|
val += "no"
|
||||||
|
|
||||||
self.label.setText("Wait! " + val)
|
self.label.setText("Wait! " + val)
|
||||||
# self.wizard().button(QtGui.QWizard.NextButton).setEnabled(False)
|
|
||||||
self.progressBar.setValue(0)
|
self.progressBar.setValue(0)
|
||||||
self.thread = NewAddressThread()
|
self.thread = NewAddressThread()
|
||||||
self.connect(self.thread, self.thread.signal, self.update)
|
self.connect(self.thread, self.thread.signal, self.update)
|
||||||
self.thread.start()
|
self.thread.start()
|
||||||
|
|
||||||
def nextId(self):
|
def nextId(self):
|
||||||
|
"""Page 10"""
|
||||||
|
|
||||||
return 10
|
return 10
|
||||||
|
|
||||||
|
|
||||||
class NewAddressWizardConclusionPage(QtGui.QWizardPage):
|
class NewAddressWizardConclusionPage(QtGui.QWizardPage):
|
||||||
|
"""The user is informed their address has been created"""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super(QtGui.QWizardPage, self).__init__()
|
super(NewAddressWizardConclusionPage, self).__init__()
|
||||||
self.setTitle("All done!")
|
self.setTitle("All done!")
|
||||||
|
|
||||||
label = QtGui.QLabel("You successfully created a new address.")
|
label = QtGui.QLabel("You successfully created a new address.")
|
||||||
|
@ -280,9 +324,12 @@ class NewAddressWizardConclusionPage(QtGui.QWizardPage):
|
||||||
layout.addWidget(label)
|
layout.addWidget(label)
|
||||||
self.setLayout(layout)
|
self.setLayout(layout)
|
||||||
|
|
||||||
|
|
||||||
class Ui_NewAddressWizard(QtGui.QWizard):
|
class Ui_NewAddressWizard(QtGui.QWizard):
|
||||||
|
"""The wizard is a collection of pages"""
|
||||||
|
|
||||||
def __init__(self, addresses):
|
def __init__(self, addresses):
|
||||||
super(QtGui.QWizard, self).__init__()
|
super(Ui_NewAddressWizard, self).__init__()
|
||||||
|
|
||||||
self.pages = {}
|
self.pages = {}
|
||||||
|
|
||||||
|
@ -308,7 +355,10 @@ class Ui_NewAddressWizard(QtGui.QWizard):
|
||||||
self.adjustSize()
|
self.adjustSize()
|
||||||
self.show()
|
self.show()
|
||||||
|
|
||||||
|
|
||||||
class NewAddressThread(QtCore.QThread):
|
class NewAddressThread(QtCore.QThread):
|
||||||
|
# pylint: disable=missing-docstring
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
QtCore.QThread.__init__(self)
|
QtCore.QThread.__init__(self)
|
||||||
self.signal = QtCore.SIGNAL("signal")
|
self.signal = QtCore.SIGNAL("signal")
|
||||||
|
@ -332,21 +382,18 @@ class NewAddressThread(QtCore.QThread):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
import time
|
|
||||||
for i in range(1, 101):
|
for i in range(1, 101):
|
||||||
time.sleep(0.1) # artificial time delay
|
time.sleep(0.1) # artificial time delay
|
||||||
self.emit(self.signal, i)
|
self.emit(self.signal, i)
|
||||||
self.emit(self.signal, 101)
|
self.emit(self.signal, 101)
|
||||||
# self.terminate()
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|
||||||
import sys
|
|
||||||
|
|
||||||
app = QtGui.QApplication(sys.argv)
|
app = QtGui.QApplication(sys.argv)
|
||||||
|
|
||||||
wizard = Ui_NewAddressWizard(["a", "b", "c", "d"])
|
wizard = Ui_NewAddressWizard(["a", "b", "c", "d"])
|
||||||
if (wizard.exec_()):
|
if wizard.exec_():
|
||||||
print "Email: " + ("yes" if wizard.field("emailAsWell").toBool() else "no")
|
print "Email: " + ("yes" if wizard.field("emailAsWell").toBool() else "no")
|
||||||
print "BM: " + ("yes" if wizard.field("onlyBM").toBool() else "no")
|
print "BM: " + ("yes" if wizard.field("onlyBM").toBool() else "no")
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
# -*- Mode: Python -*-
|
# -*- Mode: Python -*-
|
||||||
# Id: asyncore.py,v 2.51 2000/09/07 22:29:26 rushing Exp
|
# Id: asyncore.py,v 2.51 2000/09/07 22:29:26 rushing Exp
|
||||||
# Author: Sam Rushing <rushing@nightmare.com>
|
# Author: Sam Rushing <rushing@nightmare.com>
|
||||||
|
# pylint: disable=too-many-statements,too-many-branches,no-self-use,too-many-lines,attribute-defined-outside-init
|
||||||
|
# pylint: disable=global-statement
|
||||||
|
"""
|
||||||
# ======================================================================
|
# ======================================================================
|
||||||
# Copyright 1996 by Sam Rushing
|
# Copyright 1996 by Sam Rushing
|
||||||
#
|
#
|
||||||
|
@ -25,7 +27,7 @@
|
||||||
# CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
# CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
# ======================================================================
|
# ======================================================================
|
||||||
|
|
||||||
"""Basic infrastructure for asynchronous socket service clients and servers.
|
Basic infrastructure for asynchronous socket service clients and servers.
|
||||||
|
|
||||||
There are only two ways to have a program on a single processor do "more
|
There are only two ways to have a program on a single processor do "more
|
||||||
than one thing at a time". Multi-threaded programming is the simplest and
|
than one thing at a time". Multi-threaded programming is the simplest and
|
||||||
|
@ -46,17 +48,13 @@ many of the difficult problems for you, making the task of building
|
||||||
sophisticated high-performance network servers and clients a snap.
|
sophisticated high-performance network servers and clients a snap.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# randomise object order for bandwidth balancing
|
import os
|
||||||
import random
|
|
||||||
import select
|
import select
|
||||||
import socket
|
import socket
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
from threading import current_thread
|
from threading import current_thread
|
||||||
import warnings
|
import warnings
|
||||||
|
|
||||||
import os
|
|
||||||
import helper_random
|
|
||||||
from errno import EALREADY, EINPROGRESS, EWOULDBLOCK, ECONNRESET, EINVAL, \
|
from errno import EALREADY, EINPROGRESS, EWOULDBLOCK, ECONNRESET, EINVAL, \
|
||||||
ENOTCONN, ESHUTDOWN, EISCONN, EBADF, ECONNABORTED, EPIPE, EAGAIN, \
|
ENOTCONN, ESHUTDOWN, EISCONN, EBADF, ECONNABORTED, EPIPE, EAGAIN, \
|
||||||
ECONNREFUSED, EHOSTUNREACH, ENETUNREACH, ENOTSOCK, EINTR, ETIMEDOUT, \
|
ECONNREFUSED, EHOSTUNREACH, ENETUNREACH, ENOTSOCK, EINTR, ETIMEDOUT, \
|
||||||
|
@ -75,13 +73,16 @@ try:
|
||||||
except (ImportError, AttributeError):
|
except (ImportError, AttributeError):
|
||||||
WSAECONNRESET = ECONNRESET
|
WSAECONNRESET = ECONNRESET
|
||||||
try:
|
try:
|
||||||
from errno import WSAEADDRINUSE
|
# side-effects on Windows or cruft?
|
||||||
|
from errno import WSAEADDRINUSE # pylint: disable=unused-import
|
||||||
except (ImportError, AttributeError):
|
except (ImportError, AttributeError):
|
||||||
WSAEADDRINUSE = EADDRINUSE
|
WSAEADDRINUSE = EADDRINUSE
|
||||||
|
import helper_random
|
||||||
|
|
||||||
_DISCONNECTED = frozenset((ECONNRESET, ENOTCONN, ESHUTDOWN, ECONNABORTED, EPIPE,
|
|
||||||
EBADF, ECONNREFUSED, EHOSTUNREACH, ENETUNREACH, ETIMEDOUT,
|
_DISCONNECTED = frozenset((
|
||||||
WSAECONNRESET))
|
ECONNRESET, ENOTCONN, ESHUTDOWN, ECONNABORTED, EPIPE, EBADF, ECONNREFUSED,
|
||||||
|
EHOSTUNREACH, ENETUNREACH, ETIMEDOUT, WSAECONNRESET))
|
||||||
|
|
||||||
OP_READ = 1
|
OP_READ = 1
|
||||||
OP_WRITE = 2
|
OP_WRITE = 2
|
||||||
|
@ -91,6 +92,7 @@ try:
|
||||||
except NameError:
|
except NameError:
|
||||||
socket_map = {}
|
socket_map = {}
|
||||||
|
|
||||||
|
|
||||||
def _strerror(err):
|
def _strerror(err):
|
||||||
try:
|
try:
|
||||||
return os.strerror(err)
|
return os.strerror(err)
|
||||||
|
@ -99,9 +101,12 @@ def _strerror(err):
|
||||||
return errorcode[err]
|
return errorcode[err]
|
||||||
return "Unknown error %s" % err
|
return "Unknown error %s" % err
|
||||||
|
|
||||||
|
|
||||||
class ExitNow(Exception):
|
class ExitNow(Exception):
|
||||||
|
"""We don't use directly but may be necessary as we replace asyncore due to some library raising or expecting it"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
_reraised_exceptions = (ExitNow, KeyboardInterrupt, SystemExit)
|
_reraised_exceptions = (ExitNow, KeyboardInterrupt, SystemExit)
|
||||||
|
|
||||||
maxDownloadRate = 0
|
maxDownloadRate = 0
|
||||||
|
@ -113,7 +118,10 @@ uploadTimestamp = 0
|
||||||
uploadBucket = 0
|
uploadBucket = 0
|
||||||
sentBytes = 0
|
sentBytes = 0
|
||||||
|
|
||||||
|
|
||||||
def read(obj):
|
def read(obj):
|
||||||
|
"""Read an event from the object"""
|
||||||
|
|
||||||
if not can_receive():
|
if not can_receive():
|
||||||
return
|
return
|
||||||
try:
|
try:
|
||||||
|
@ -123,7 +131,10 @@ def read(obj):
|
||||||
except:
|
except:
|
||||||
obj.handle_error()
|
obj.handle_error()
|
||||||
|
|
||||||
|
|
||||||
def write(obj):
|
def write(obj):
|
||||||
|
"""Write an event to the object"""
|
||||||
|
|
||||||
if not can_send():
|
if not can_send():
|
||||||
return
|
return
|
||||||
try:
|
try:
|
||||||
|
@ -133,8 +144,12 @@ def write(obj):
|
||||||
except:
|
except:
|
||||||
obj.handle_error()
|
obj.handle_error()
|
||||||
|
|
||||||
|
|
||||||
def set_rates(download, upload):
|
def set_rates(download, upload):
|
||||||
|
"""Set throttling rates"""
|
||||||
|
|
||||||
global maxDownloadRate, maxUploadRate, downloadBucket, uploadBucket, downloadTimestamp, uploadTimestamp
|
global maxDownloadRate, maxUploadRate, downloadBucket, uploadBucket, downloadTimestamp, uploadTimestamp
|
||||||
|
|
||||||
maxDownloadRate = float(download) * 1024
|
maxDownloadRate = float(download) * 1024
|
||||||
maxUploadRate = float(upload) * 1024
|
maxUploadRate = float(upload) * 1024
|
||||||
downloadBucket = maxDownloadRate
|
downloadBucket = maxDownloadRate
|
||||||
|
@ -142,14 +157,24 @@ def set_rates(download, upload):
|
||||||
downloadTimestamp = time.time()
|
downloadTimestamp = time.time()
|
||||||
uploadTimestamp = time.time()
|
uploadTimestamp = time.time()
|
||||||
|
|
||||||
|
|
||||||
def can_receive():
|
def can_receive():
|
||||||
|
"""Predicate indicating whether the download throttle is in effect"""
|
||||||
|
|
||||||
return maxDownloadRate == 0 or downloadBucket > 0
|
return maxDownloadRate == 0 or downloadBucket > 0
|
||||||
|
|
||||||
|
|
||||||
def can_send():
|
def can_send():
|
||||||
|
"""Predicate indicating whether the upload throttle is in effect"""
|
||||||
|
|
||||||
return maxUploadRate == 0 or uploadBucket > 0
|
return maxUploadRate == 0 or uploadBucket > 0
|
||||||
|
|
||||||
|
|
||||||
def update_received(download=0):
|
def update_received(download=0):
|
||||||
|
"""Update the receiving throttle"""
|
||||||
|
|
||||||
global receivedBytes, downloadBucket, downloadTimestamp
|
global receivedBytes, downloadBucket, downloadTimestamp
|
||||||
|
|
||||||
currentTimestamp = time.time()
|
currentTimestamp = time.time()
|
||||||
receivedBytes += download
|
receivedBytes += download
|
||||||
if maxDownloadRate > 0:
|
if maxDownloadRate > 0:
|
||||||
|
@ -160,8 +185,12 @@ def update_received(download=0):
|
||||||
downloadBucket -= download
|
downloadBucket -= download
|
||||||
downloadTimestamp = currentTimestamp
|
downloadTimestamp = currentTimestamp
|
||||||
|
|
||||||
|
|
||||||
def update_sent(upload=0):
|
def update_sent(upload=0):
|
||||||
|
"""Update the sending throttle"""
|
||||||
|
|
||||||
global sentBytes, uploadBucket, uploadTimestamp
|
global sentBytes, uploadBucket, uploadTimestamp
|
||||||
|
|
||||||
currentTimestamp = time.time()
|
currentTimestamp = time.time()
|
||||||
sentBytes += upload
|
sentBytes += upload
|
||||||
if maxUploadRate > 0:
|
if maxUploadRate > 0:
|
||||||
|
@ -172,7 +201,10 @@ def update_sent(upload=0):
|
||||||
uploadBucket -= upload
|
uploadBucket -= upload
|
||||||
uploadTimestamp = currentTimestamp
|
uploadTimestamp = currentTimestamp
|
||||||
|
|
||||||
|
|
||||||
def _exception(obj):
|
def _exception(obj):
|
||||||
|
"""Handle exceptions as appropriate"""
|
||||||
|
|
||||||
try:
|
try:
|
||||||
obj.handle_expt_event()
|
obj.handle_expt_event()
|
||||||
except _reraised_exceptions:
|
except _reraised_exceptions:
|
||||||
|
@ -180,7 +212,10 @@ def _exception(obj):
|
||||||
except:
|
except:
|
||||||
obj.handle_error()
|
obj.handle_error()
|
||||||
|
|
||||||
|
|
||||||
def readwrite(obj, flags):
|
def readwrite(obj, flags):
|
||||||
|
"""Read and write any pending data to/from the object"""
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if flags & select.POLLIN and can_receive():
|
if flags & select.POLLIN and can_receive():
|
||||||
obj.handle_read_event()
|
obj.handle_read_event()
|
||||||
|
@ -200,12 +235,17 @@ def readwrite(obj, flags):
|
||||||
except:
|
except:
|
||||||
obj.handle_error()
|
obj.handle_error()
|
||||||
|
|
||||||
|
|
||||||
def select_poller(timeout=0.0, map=None):
|
def select_poller(timeout=0.0, map=None):
|
||||||
"""A poller which uses select(), available on most platforms."""
|
"""A poller which uses select(), available on most platforms."""
|
||||||
|
# pylint: disable=redefined-builtin
|
||||||
|
|
||||||
if map is None:
|
if map is None:
|
||||||
map = socket_map
|
map = socket_map
|
||||||
if map:
|
if map:
|
||||||
r = []; w = []; e = []
|
r = []
|
||||||
|
w = []
|
||||||
|
e = []
|
||||||
for fd, obj in list(map.items()):
|
for fd, obj in list(map.items()):
|
||||||
is_r = obj.readable()
|
is_r = obj.readable()
|
||||||
is_w = obj.writable()
|
is_w = obj.writable()
|
||||||
|
@ -251,8 +291,11 @@ def select_poller(timeout=0.0, map=None):
|
||||||
else:
|
else:
|
||||||
current_thread().stop.wait(timeout)
|
current_thread().stop.wait(timeout)
|
||||||
|
|
||||||
|
|
||||||
def poll_poller(timeout=0.0, map=None):
|
def poll_poller(timeout=0.0, map=None):
|
||||||
"""A poller which uses poll(), available on most UNIXen."""
|
"""A poller which uses poll(), available on most UNIXen."""
|
||||||
|
# pylint: disable=redefined-builtin
|
||||||
|
|
||||||
if map is None:
|
if map is None:
|
||||||
map = socket_map
|
map = socket_map
|
||||||
if timeout is not None:
|
if timeout is not None:
|
||||||
|
@ -301,12 +344,16 @@ def poll_poller(timeout=0.0, map=None):
|
||||||
else:
|
else:
|
||||||
current_thread().stop.wait(timeout)
|
current_thread().stop.wait(timeout)
|
||||||
|
|
||||||
|
|
||||||
# Aliases for backward compatibility
|
# Aliases for backward compatibility
|
||||||
poll = select_poller
|
poll = select_poller
|
||||||
poll2 = poll3 = poll_poller
|
poll2 = poll3 = poll_poller
|
||||||
|
|
||||||
|
|
||||||
def epoll_poller(timeout=0.0, map=None):
|
def epoll_poller(timeout=0.0, map=None):
|
||||||
"""A poller which uses epoll(), supported on Linux 2.5.44 and newer."""
|
"""A poller which uses epoll(), supported on Linux 2.5.44 and newer."""
|
||||||
|
# pylint: disable=redefined-builtin
|
||||||
|
|
||||||
if map is None:
|
if map is None:
|
||||||
map = socket_map
|
map = socket_map
|
||||||
try:
|
try:
|
||||||
|
@ -346,7 +393,7 @@ def epoll_poller(timeout=0.0, map=None):
|
||||||
if e.errno != EINTR:
|
if e.errno != EINTR:
|
||||||
raise
|
raise
|
||||||
r = []
|
r = []
|
||||||
except select.error, err:
|
except select.error as err:
|
||||||
if err.args[0] != EINTR:
|
if err.args[0] != EINTR:
|
||||||
raise
|
raise
|
||||||
r = []
|
r = []
|
||||||
|
@ -358,8 +405,11 @@ def epoll_poller(timeout=0.0, map=None):
|
||||||
else:
|
else:
|
||||||
current_thread().stop.wait(timeout)
|
current_thread().stop.wait(timeout)
|
||||||
|
|
||||||
|
|
||||||
def kqueue_poller(timeout=0.0, map=None):
|
def kqueue_poller(timeout=0.0, map=None):
|
||||||
"""A poller which uses kqueue(), BSD specific."""
|
"""A poller which uses kqueue(), BSD specific."""
|
||||||
|
# pylint: disable=redefined-builtin,no-member
|
||||||
|
|
||||||
if map is None:
|
if map is None:
|
||||||
map = socket_map
|
map = socket_map
|
||||||
try:
|
try:
|
||||||
|
@ -425,8 +475,10 @@ def kqueue_poller(timeout=0.0, map=None):
|
||||||
current_thread().stop.wait(timeout)
|
current_thread().stop.wait(timeout)
|
||||||
|
|
||||||
|
|
||||||
def loop(timeout=30.0, use_poll=False, map=None, count=None,
|
def loop(timeout=30.0, use_poll=False, map=None, count=None, poller=None):
|
||||||
poller=None):
|
"""Poll in a loop, forever if count is None"""
|
||||||
|
# pylint: disable=redefined-builtin
|
||||||
|
|
||||||
if map is None:
|
if map is None:
|
||||||
map = socket_map
|
map = socket_map
|
||||||
if count is None:
|
if count is None:
|
||||||
|
@ -460,10 +512,13 @@ def loop(timeout=30.0, use_poll=False, map=None, count=None,
|
||||||
break
|
break
|
||||||
# then poll
|
# then poll
|
||||||
poller(subtimeout, map)
|
poller(subtimeout, map)
|
||||||
if type(count) is int:
|
if isinstance(count, int):
|
||||||
count = count - 1
|
count = count - 1
|
||||||
|
|
||||||
|
|
||||||
class dispatcher:
|
class dispatcher:
|
||||||
|
"""Dispatcher for socket objects"""
|
||||||
|
# pylint: disable=too-many-public-methods,too-many-instance-attributes,old-style-class
|
||||||
|
|
||||||
debug = False
|
debug = False
|
||||||
connected = False
|
connected = False
|
||||||
|
@ -478,6 +533,7 @@ class dispatcher:
|
||||||
minTx = 1500
|
minTx = 1500
|
||||||
|
|
||||||
def __init__(self, sock=None, map=None):
|
def __init__(self, sock=None, map=None):
|
||||||
|
# pylint: disable=redefined-builtin
|
||||||
if map is None:
|
if map is None:
|
||||||
self._map = socket_map
|
self._map = socket_map
|
||||||
else:
|
else:
|
||||||
|
@ -525,7 +581,9 @@ class dispatcher:
|
||||||
__str__ = __repr__
|
__str__ = __repr__
|
||||||
|
|
||||||
def add_channel(self, map=None):
|
def add_channel(self, map=None):
|
||||||
#self.log_info('adding channel %s' % self)
|
"""Add a channel"""
|
||||||
|
# pylint: disable=redefined-builtin
|
||||||
|
|
||||||
if map is None:
|
if map is None:
|
||||||
map = self._map
|
map = self._map
|
||||||
map[self._fileno] = self
|
map[self._fileno] = self
|
||||||
|
@ -533,11 +591,13 @@ class dispatcher:
|
||||||
self.poller_filter = 0
|
self.poller_filter = 0
|
||||||
|
|
||||||
def del_channel(self, map=None):
|
def del_channel(self, map=None):
|
||||||
|
"""Delete a channel"""
|
||||||
|
# pylint: disable=redefined-builtin
|
||||||
|
|
||||||
fd = self._fileno
|
fd = self._fileno
|
||||||
if map is None:
|
if map is None:
|
||||||
map = self._map
|
map = self._map
|
||||||
if fd in map:
|
if fd in map:
|
||||||
#self.log_info('closing channel %d:%s' % (fd, self))
|
|
||||||
del map[fd]
|
del map[fd]
|
||||||
if self._fileno:
|
if self._fileno:
|
||||||
try:
|
try:
|
||||||
|
@ -564,19 +624,23 @@ class dispatcher:
|
||||||
self.poller_registered = False
|
self.poller_registered = False
|
||||||
|
|
||||||
def create_socket(self, family=socket.AF_INET, socket_type=socket.SOCK_STREAM):
|
def create_socket(self, family=socket.AF_INET, socket_type=socket.SOCK_STREAM):
|
||||||
|
"""Create a socket"""
|
||||||
self.family_and_type = family, socket_type
|
self.family_and_type = family, socket_type
|
||||||
sock = socket.socket(family, socket_type)
|
sock = socket.socket(family, socket_type)
|
||||||
sock.setblocking(0)
|
sock.setblocking(0)
|
||||||
self.set_socket(sock)
|
self.set_socket(sock)
|
||||||
|
|
||||||
def set_socket(self, sock, map=None):
|
def set_socket(self, sock, map=None):
|
||||||
|
"""Set socket"""
|
||||||
|
# pylint: disable=redefined-builtin
|
||||||
|
|
||||||
self.socket = sock
|
self.socket = sock
|
||||||
## self.__dict__['socket'] = sock
|
|
||||||
self._fileno = sock.fileno()
|
self._fileno = sock.fileno()
|
||||||
self.add_channel(map)
|
self.add_channel(map)
|
||||||
|
|
||||||
def set_reuse_addr(self):
|
def set_reuse_addr(self):
|
||||||
# try to re-use a server port if possible
|
"""try to re-use a server port if possible"""
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.socket.setsockopt(
|
self.socket.setsockopt(
|
||||||
socket.SOL_SOCKET, socket.SO_REUSEADDR,
|
socket.SOL_SOCKET, socket.SO_REUSEADDR,
|
||||||
|
@ -593,11 +657,13 @@ class dispatcher:
|
||||||
# ==================================================
|
# ==================================================
|
||||||
|
|
||||||
def readable(self):
|
def readable(self):
|
||||||
|
"""Predicate to indicate download throttle status"""
|
||||||
if maxDownloadRate > 0:
|
if maxDownloadRate > 0:
|
||||||
return downloadBucket > dispatcher.minTx
|
return downloadBucket > dispatcher.minTx
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def writable(self):
|
def writable(self):
|
||||||
|
"""Predicate to indicate upload throttle status"""
|
||||||
if maxUploadRate > 0:
|
if maxUploadRate > 0:
|
||||||
return uploadBucket > dispatcher.minTx
|
return uploadBucket > dispatcher.minTx
|
||||||
return True
|
return True
|
||||||
|
@ -607,16 +673,19 @@ class dispatcher:
|
||||||
# ==================================================
|
# ==================================================
|
||||||
|
|
||||||
def listen(self, num):
|
def listen(self, num):
|
||||||
|
"""Listen on a port"""
|
||||||
self.accepting = True
|
self.accepting = True
|
||||||
if os.name == 'nt' and num > 5:
|
if os.name == 'nt' and num > 5:
|
||||||
num = 5
|
num = 5
|
||||||
return self.socket.listen(num)
|
return self.socket.listen(num)
|
||||||
|
|
||||||
def bind(self, addr):
|
def bind(self, addr):
|
||||||
|
"""Bind to an address"""
|
||||||
self.addr = addr
|
self.addr = addr
|
||||||
return self.socket.bind(addr)
|
return self.socket.bind(addr)
|
||||||
|
|
||||||
def connect(self, address):
|
def connect(self, address):
|
||||||
|
"""Connect to an address"""
|
||||||
self.connected = False
|
self.connected = False
|
||||||
self.connecting = True
|
self.connecting = True
|
||||||
err = self.socket.connect_ex(address)
|
err = self.socket.connect_ex(address)
|
||||||
|
@ -631,7 +700,11 @@ class dispatcher:
|
||||||
raise socket.error(err, errorcode[err])
|
raise socket.error(err, errorcode[err])
|
||||||
|
|
||||||
def accept(self):
|
def accept(self):
|
||||||
# XXX can return either an address pair or None
|
"""
|
||||||
|
Accept incoming connections
|
||||||
|
|
||||||
|
.. todo:: FIXME: can return either an address pair or None
|
||||||
|
"""
|
||||||
try:
|
try:
|
||||||
conn, addr = self.socket.accept()
|
conn, addr = self.socket.accept()
|
||||||
except TypeError:
|
except TypeError:
|
||||||
|
@ -645,6 +718,7 @@ class dispatcher:
|
||||||
return conn, addr
|
return conn, addr
|
||||||
|
|
||||||
def send(self, data):
|
def send(self, data):
|
||||||
|
"""Send data"""
|
||||||
try:
|
try:
|
||||||
result = self.socket.send(data)
|
result = self.socket.send(data)
|
||||||
return result
|
return result
|
||||||
|
@ -658,6 +732,7 @@ class dispatcher:
|
||||||
raise
|
raise
|
||||||
|
|
||||||
def recv(self, buffer_size):
|
def recv(self, buffer_size):
|
||||||
|
"""Receive data"""
|
||||||
try:
|
try:
|
||||||
data = self.socket.recv(buffer_size)
|
data = self.socket.recv(buffer_size)
|
||||||
if not data:
|
if not data:
|
||||||
|
@ -665,7 +740,6 @@ class dispatcher:
|
||||||
# a read condition, and having recv() return 0.
|
# a read condition, and having recv() return 0.
|
||||||
self.handle_close()
|
self.handle_close()
|
||||||
return b''
|
return b''
|
||||||
else:
|
|
||||||
return data
|
return data
|
||||||
except socket.error as why:
|
except socket.error as why:
|
||||||
# winsock sometimes raises ENOTCONN
|
# winsock sometimes raises ENOTCONN
|
||||||
|
@ -678,6 +752,7 @@ class dispatcher:
|
||||||
raise
|
raise
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
|
"""Close connection"""
|
||||||
self.connected = False
|
self.connected = False
|
||||||
self.accepting = False
|
self.accepting = False
|
||||||
self.connecting = False
|
self.connecting = False
|
||||||
|
@ -707,13 +782,16 @@ class dispatcher:
|
||||||
# and 'log_info' is for informational, warning and error logging.
|
# and 'log_info' is for informational, warning and error logging.
|
||||||
|
|
||||||
def log(self, message):
|
def log(self, message):
|
||||||
|
"""Log a message to stderr"""
|
||||||
sys.stderr.write('log: %s\n' % str(message))
|
sys.stderr.write('log: %s\n' % str(message))
|
||||||
|
|
||||||
def log_info(self, message, log_type='info'):
|
def log_info(self, message, log_type='info'):
|
||||||
|
"""Conditionally print a message"""
|
||||||
if log_type not in self.ignore_log_types:
|
if log_type not in self.ignore_log_types:
|
||||||
print('%s: %s' % (log_type, message))
|
print '%s: %s' % log_type, message
|
||||||
|
|
||||||
def handle_read_event(self):
|
def handle_read_event(self):
|
||||||
|
"""Handle a read event"""
|
||||||
if self.accepting:
|
if self.accepting:
|
||||||
# accepting sockets are never connected, they "spawn" new
|
# accepting sockets are never connected, they "spawn" new
|
||||||
# sockets that are connected
|
# sockets that are connected
|
||||||
|
@ -726,6 +804,7 @@ class dispatcher:
|
||||||
self.handle_read()
|
self.handle_read()
|
||||||
|
|
||||||
def handle_connect_event(self):
|
def handle_connect_event(self):
|
||||||
|
"""Handle a connection event"""
|
||||||
err = self.socket.getsockopt(socket.SOL_SOCKET, socket.SO_ERROR)
|
err = self.socket.getsockopt(socket.SOL_SOCKET, socket.SO_ERROR)
|
||||||
if err != 0:
|
if err != 0:
|
||||||
raise socket.error(err, _strerror(err))
|
raise socket.error(err, _strerror(err))
|
||||||
|
@ -734,6 +813,7 @@ class dispatcher:
|
||||||
self.connecting = False
|
self.connecting = False
|
||||||
|
|
||||||
def handle_write_event(self):
|
def handle_write_event(self):
|
||||||
|
"""Handle a write event"""
|
||||||
if self.accepting:
|
if self.accepting:
|
||||||
# Accepting sockets shouldn't get a write event.
|
# Accepting sockets shouldn't get a write event.
|
||||||
# We will pretend it didn't happen.
|
# We will pretend it didn't happen.
|
||||||
|
@ -745,6 +825,7 @@ class dispatcher:
|
||||||
self.handle_write()
|
self.handle_write()
|
||||||
|
|
||||||
def handle_expt_event(self):
|
def handle_expt_event(self):
|
||||||
|
"""Handle expected exceptions"""
|
||||||
# handle_expt_event() is called if there might be an error on the
|
# handle_expt_event() is called if there might be an error on the
|
||||||
# socket, or if there is OOB data
|
# socket, or if there is OOB data
|
||||||
# check for the error condition first
|
# check for the error condition first
|
||||||
|
@ -763,7 +844,8 @@ class dispatcher:
|
||||||
self.handle_expt()
|
self.handle_expt()
|
||||||
|
|
||||||
def handle_error(self):
|
def handle_error(self):
|
||||||
nil, t, v, tbinfo = compact_traceback()
|
"""Handle unexpected exceptions"""
|
||||||
|
_, t, v, tbinfo = compact_traceback()
|
||||||
|
|
||||||
# sometimes a user repr method will crash.
|
# sometimes a user repr method will crash.
|
||||||
try:
|
try:
|
||||||
|
@ -782,64 +864,81 @@ class dispatcher:
|
||||||
)
|
)
|
||||||
self.handle_close()
|
self.handle_close()
|
||||||
|
|
||||||
def handle_expt(self):
|
|
||||||
self.log_info('unhandled incoming priority event', 'warning')
|
|
||||||
|
|
||||||
def handle_read(self):
|
|
||||||
self.log_info('unhandled read event', 'warning')
|
|
||||||
|
|
||||||
def handle_write(self):
|
|
||||||
self.log_info('unhandled write event', 'warning')
|
|
||||||
|
|
||||||
def handle_connect(self):
|
|
||||||
self.log_info('unhandled connect event', 'warning')
|
|
||||||
|
|
||||||
def handle_accept(self):
|
def handle_accept(self):
|
||||||
|
"""Handle an accept event"""
|
||||||
pair = self.accept()
|
pair = self.accept()
|
||||||
if pair is not None:
|
if pair is not None:
|
||||||
self.handle_accepted(*pair)
|
self.handle_accepted(*pair)
|
||||||
|
|
||||||
|
def handle_expt(self):
|
||||||
|
"""Log that the subclass does not implement handle_expt"""
|
||||||
|
self.log_info('unhandled incoming priority event', 'warning')
|
||||||
|
|
||||||
|
def handle_read(self):
|
||||||
|
"""Log that the subclass does not implement handle_read"""
|
||||||
|
self.log_info('unhandled read event', 'warning')
|
||||||
|
|
||||||
|
def handle_write(self):
|
||||||
|
"""Log that the subclass does not implement handle_write"""
|
||||||
|
self.log_info('unhandled write event', 'warning')
|
||||||
|
|
||||||
|
def handle_connect(self):
|
||||||
|
"""Log that the subclass does not implement handle_connect"""
|
||||||
|
self.log_info('unhandled connect event', 'warning')
|
||||||
|
|
||||||
def handle_accepted(self, sock, addr):
|
def handle_accepted(self, sock, addr):
|
||||||
|
"""Log that the subclass does not implement handle_accepted"""
|
||||||
sock.close()
|
sock.close()
|
||||||
self.log_info('unhandled accepted event on %s' % (addr), 'warning')
|
self.log_info('unhandled accepted event on %s' % (addr), 'warning')
|
||||||
|
|
||||||
def handle_close(self):
|
def handle_close(self):
|
||||||
|
"""Log that the subclass does not implement handle_close"""
|
||||||
self.log_info('unhandled close event', 'warning')
|
self.log_info('unhandled close event', 'warning')
|
||||||
self.close()
|
self.close()
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
|
||||||
# adds simple buffered output capability, useful for simple clients.
|
|
||||||
# [for more sophisticated usage use asynchat.async_chat]
|
|
||||||
# ---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
class dispatcher_with_send(dispatcher):
|
class dispatcher_with_send(dispatcher):
|
||||||
|
"""
|
||||||
|
adds simple buffered output capability, useful for simple clients.
|
||||||
|
[for more sophisticated usage use asynchat.async_chat]
|
||||||
|
"""
|
||||||
|
# pylint: disable=redefined-builtin
|
||||||
|
|
||||||
def __init__(self, sock=None, map=None):
|
def __init__(self, sock=None, map=None):
|
||||||
|
# pylint: disable=redefined-builtin
|
||||||
|
|
||||||
dispatcher.__init__(self, sock, map)
|
dispatcher.__init__(self, sock, map)
|
||||||
self.out_buffer = b''
|
self.out_buffer = b''
|
||||||
|
|
||||||
def initiate_send(self):
|
def initiate_send(self):
|
||||||
|
"""Initiate a send"""
|
||||||
num_sent = 0
|
num_sent = 0
|
||||||
num_sent = dispatcher.send(self, self.out_buffer[:512])
|
num_sent = dispatcher.send(self, self.out_buffer[:512])
|
||||||
self.out_buffer = self.out_buffer[num_sent:]
|
self.out_buffer = self.out_buffer[num_sent:]
|
||||||
|
|
||||||
def handle_write(self):
|
def handle_write(self):
|
||||||
|
"""Handle a write event"""
|
||||||
self.initiate_send()
|
self.initiate_send()
|
||||||
|
|
||||||
def writable(self):
|
def writable(self):
|
||||||
return (not self.connected) or len(self.out_buffer)
|
"""Predicate to indicate if the object is writable"""
|
||||||
|
return not self.connected or len(self.out_buffer)
|
||||||
|
|
||||||
def send(self, data):
|
def send(self, data):
|
||||||
|
"""Send data"""
|
||||||
if self.debug:
|
if self.debug:
|
||||||
self.log_info('sending %s' % repr(data))
|
self.log_info('sending %s' % repr(data))
|
||||||
self.out_buffer = self.out_buffer + data
|
self.out_buffer = self.out_buffer + data
|
||||||
self.initiate_send()
|
self.initiate_send()
|
||||||
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# used for debugging.
|
# used for debugging.
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
def compact_traceback():
|
def compact_traceback():
|
||||||
|
"""Return a compact traceback"""
|
||||||
t, v, tb = sys.exc_info()
|
t, v, tb = sys.exc_info()
|
||||||
tbinfo = []
|
tbinfo = []
|
||||||
if not tb: # Must have a traceback
|
if not tb: # Must have a traceback
|
||||||
|
@ -855,11 +954,15 @@ def compact_traceback():
|
||||||
# just to be safe
|
# just to be safe
|
||||||
del tb
|
del tb
|
||||||
|
|
||||||
file, function, line = tbinfo[-1]
|
filename, function, line = tbinfo[-1]
|
||||||
info = ' '.join(['[%s|%s|%s]' % x for x in tbinfo])
|
info = ' '.join(['[%s|%s|%s]' % x for x in tbinfo])
|
||||||
return (file, function, line), t, v, info
|
return (filename, function, line), t, v, info
|
||||||
|
|
||||||
|
|
||||||
def close_all(map=None, ignore_all=False):
|
def close_all(map=None, ignore_all=False):
|
||||||
|
"""Close all connections"""
|
||||||
|
# pylint: disable=redefined-builtin
|
||||||
|
|
||||||
if map is None:
|
if map is None:
|
||||||
map = socket_map
|
map = socket_map
|
||||||
for x in list(map.values()):
|
for x in list(map.values()):
|
||||||
|
@ -877,6 +980,7 @@ def close_all(map=None, ignore_all=False):
|
||||||
raise
|
raise
|
||||||
map.clear()
|
map.clear()
|
||||||
|
|
||||||
|
|
||||||
# Asynchronous File I/O:
|
# Asynchronous File I/O:
|
||||||
#
|
#
|
||||||
# After a little research (reading man pages on various unixen, and
|
# After a little research (reading man pages on various unixen, and
|
||||||
|
@ -890,24 +994,31 @@ def close_all(map=None, ignore_all=False):
|
||||||
#
|
#
|
||||||
# Regardless, this is useful for pipes, and stdin/stdout...
|
# Regardless, this is useful for pipes, and stdin/stdout...
|
||||||
|
|
||||||
|
|
||||||
if os.name == 'posix':
|
if os.name == 'posix':
|
||||||
import fcntl
|
import fcntl
|
||||||
|
|
||||||
class file_wrapper:
|
class file_wrapper:
|
||||||
# Here we override just enough to make a file
|
"""
|
||||||
# look like a socket for the purposes of asyncore.
|
Here we override just enough to make a file look like a socket for the purposes of asyncore.
|
||||||
# The passed fd is automatically os.dup()'d
|
|
||||||
|
The passed fd is automatically os.dup()'d
|
||||||
|
"""
|
||||||
|
# pylint: disable=old-style-class
|
||||||
|
|
||||||
def __init__(self, fd):
|
def __init__(self, fd):
|
||||||
self.fd = os.dup(fd)
|
self.fd = os.dup(fd)
|
||||||
|
|
||||||
def recv(self, *args):
|
def recv(self, *args):
|
||||||
|
"""Fake recv()"""
|
||||||
return os.read(self.fd, *args)
|
return os.read(self.fd, *args)
|
||||||
|
|
||||||
def send(self, *args):
|
def send(self, *args):
|
||||||
|
"""Fake send()"""
|
||||||
return os.write(self.fd, *args)
|
return os.write(self.fd, *args)
|
||||||
|
|
||||||
def getsockopt(self, level, optname, buflen=None):
|
def getsockopt(self, level, optname, buflen=None):
|
||||||
|
"""Fake getsockopt()"""
|
||||||
if (level == socket.SOL_SOCKET and
|
if (level == socket.SOL_SOCKET and
|
||||||
optname == socket.SO_ERROR and
|
optname == socket.SO_ERROR and
|
||||||
not buflen):
|
not buflen):
|
||||||
|
@ -919,14 +1030,19 @@ if os.name == 'posix':
|
||||||
write = send
|
write = send
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
|
"""Fake close()"""
|
||||||
os.close(self.fd)
|
os.close(self.fd)
|
||||||
|
|
||||||
def fileno(self):
|
def fileno(self):
|
||||||
|
"""Fake fileno()"""
|
||||||
return self.fd
|
return self.fd
|
||||||
|
|
||||||
class file_dispatcher(dispatcher):
|
class file_dispatcher(dispatcher):
|
||||||
|
"""A dispatcher for file_wrapper objects"""
|
||||||
|
|
||||||
def __init__(self, fd, map=None):
|
def __init__(self, fd, map=None):
|
||||||
|
# pylint: disable=redefined-builtin
|
||||||
|
|
||||||
dispatcher.__init__(self, None, map)
|
dispatcher.__init__(self, None, map)
|
||||||
self.connected = True
|
self.connected = True
|
||||||
try:
|
try:
|
||||||
|
@ -940,6 +1056,7 @@ if os.name == 'posix':
|
||||||
fcntl.fcntl(fd, fcntl.F_SETFL, flags)
|
fcntl.fcntl(fd, fcntl.F_SETFL, flags)
|
||||||
|
|
||||||
def set_file(self, fd):
|
def set_file(self, fd):
|
||||||
|
"""Set file"""
|
||||||
self.socket = file_wrapper(fd)
|
self.socket = file_wrapper(fd)
|
||||||
self._fileno = self.socket.fileno()
|
self._fileno = self.socket.fileno()
|
||||||
self.add_channel()
|
self.add_channel()
|
||||||
|
|
|
@ -1,6 +1,12 @@
|
||||||
|
# pylint: disable=too-many-return-statements,too-many-public-methods,attribute-defined-outside-init,too-many-branches
|
||||||
|
# pylint: disable=too-many-instance-attributes,too-many-statements
|
||||||
|
"""
|
||||||
|
The Bitmessage Protocol
|
||||||
|
=======================
|
||||||
|
"""
|
||||||
|
|
||||||
import base64
|
import base64
|
||||||
import hashlib
|
import hashlib
|
||||||
import random
|
|
||||||
import socket
|
import socket
|
||||||
import struct
|
import struct
|
||||||
import time
|
import time
|
||||||
|
@ -16,7 +22,7 @@ from network.bmobject import BMObject, BMObjectInsufficientPOWError, BMObjectInv
|
||||||
import network.connectionpool
|
import network.connectionpool
|
||||||
from network.node import Node
|
from network.node import Node
|
||||||
from network.objectracker import ObjectTracker
|
from network.objectracker import ObjectTracker
|
||||||
from network.proxy import Proxy, ProxyError, GeneralProxyError
|
from network.proxy import ProxyError
|
||||||
|
|
||||||
import addresses
|
import addresses
|
||||||
from queues import objectProcessorQueue, portCheckerQueue, invQueue, addrQueue
|
from queues import objectProcessorQueue, portCheckerQueue, invQueue, addrQueue
|
||||||
|
@ -25,19 +31,27 @@ import state
|
||||||
import protocol
|
import protocol
|
||||||
import helper_random
|
import helper_random
|
||||||
|
|
||||||
|
|
||||||
class BMProtoError(ProxyError):
|
class BMProtoError(ProxyError):
|
||||||
|
"""A Bitmessage Protocol Base Error"""
|
||||||
errorCodes = ("Protocol error")
|
errorCodes = ("Protocol error")
|
||||||
|
|
||||||
|
|
||||||
class BMProtoInsufficientDataError(BMProtoError):
|
class BMProtoInsufficientDataError(BMProtoError):
|
||||||
|
"""A Bitmessage Protocol Insufficient Data Error"""
|
||||||
|
|
||||||
errorCodes = ("Insufficient data")
|
errorCodes = ("Insufficient data")
|
||||||
|
|
||||||
|
|
||||||
class BMProtoExcessiveDataError(BMProtoError):
|
class BMProtoExcessiveDataError(BMProtoError):
|
||||||
|
"""A Bitmessage Protocol Excessive Data Error"""
|
||||||
|
|
||||||
errorCodes = ("Too much data")
|
errorCodes = ("Too much data")
|
||||||
|
|
||||||
|
|
||||||
class BMProto(AdvancedDispatcher, ObjectTracker):
|
class BMProto(AdvancedDispatcher, ObjectTracker):
|
||||||
|
"""A parser for the Bitmessage Protocol"""
|
||||||
|
|
||||||
# ~1.6 MB which is the maximum possible size of an inv message.
|
# ~1.6 MB which is the maximum possible size of an inv message.
|
||||||
maxMessageSize = 1600100
|
maxMessageSize = 1600100
|
||||||
# 2**18 = 256kB is the maximum size of an object payload
|
# 2**18 = 256kB is the maximum size of an object payload
|
||||||
|
@ -52,12 +66,15 @@ class BMProto(AdvancedDispatcher, ObjectTracker):
|
||||||
maxTimeOffset = 3600
|
maxTimeOffset = 3600
|
||||||
|
|
||||||
def __init__(self, address=None, sock=None):
|
def __init__(self, address=None, sock=None):
|
||||||
|
# pylint: disable=super-init-not-called,unused-argument
|
||||||
|
|
||||||
AdvancedDispatcher.__init__(self, sock)
|
AdvancedDispatcher.__init__(self, sock)
|
||||||
self.isOutbound = False
|
self.isOutbound = False
|
||||||
# packet/connection from a local IP
|
# packet/connection from a local IP
|
||||||
self.local = False
|
self.local = False
|
||||||
|
|
||||||
def bm_proto_reset(self):
|
def bm_proto_reset(self):
|
||||||
|
"""TBC"""
|
||||||
self.magic = None
|
self.magic = None
|
||||||
self.command = None
|
self.command = None
|
||||||
self.payloadLength = 0
|
self.payloadLength = 0
|
||||||
|
@ -69,7 +86,10 @@ class BMProto(AdvancedDispatcher, ObjectTracker):
|
||||||
self.object = None
|
self.object = None
|
||||||
|
|
||||||
def state_bm_header(self):
|
def state_bm_header(self):
|
||||||
self.magic, self.command, self.payloadLength, self.checksum = protocol.Header.unpack(self.read_buf[:protocol.Header.size])
|
"""Predicate to indicate the prescence of a header"""
|
||||||
|
|
||||||
|
self.magic, self.command, self.payloadLength, self.checksum = protocol.Header.unpack(
|
||||||
|
self.read_buf[:protocol.Header.size])
|
||||||
self.command = self.command.rstrip('\x00')
|
self.command = self.command.rstrip('\x00')
|
||||||
if self.magic != 0xE9BEB4D9:
|
if self.magic != 0xE9BEB4D9:
|
||||||
# skip 1 byte in order to sync
|
# skip 1 byte in order to sync
|
||||||
|
@ -86,6 +106,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def state_bm_command(self):
|
def state_bm_command(self):
|
||||||
|
"""TBC"""
|
||||||
self.payload = self.read_buf[:self.payloadLength]
|
self.payload = self.read_buf[:self.payloadLength]
|
||||||
if self.checksum != hashlib.sha512(self.payload).digest()[0:4]:
|
if self.checksum != hashlib.sha512(self.payload).digest()[0:4]:
|
||||||
logger.debug("Bad checksum, ignoring")
|
logger.debug("Bad checksum, ignoring")
|
||||||
|
@ -134,16 +155,21 @@ class BMProto(AdvancedDispatcher, ObjectTracker):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def decode_payload_string(self, length):
|
def decode_payload_string(self, length):
|
||||||
|
"""Read and return `length` bytes from payload"""
|
||||||
|
|
||||||
value = self.payload[self.payloadOffset:self.payloadOffset + length]
|
value = self.payload[self.payloadOffset:self.payloadOffset + length]
|
||||||
self.payloadOffset += length
|
self.payloadOffset += length
|
||||||
return value
|
return value
|
||||||
|
|
||||||
def decode_payload_varint(self):
|
def decode_payload_varint(self):
|
||||||
|
"""Decode a varint from the payload"""
|
||||||
|
|
||||||
value, offset = addresses.decodeVarint(self.payload[self.payloadOffset:])
|
value, offset = addresses.decodeVarint(self.payload[self.payloadOffset:])
|
||||||
self.payloadOffset += offset
|
self.payloadOffset += offset
|
||||||
return value
|
return value
|
||||||
|
|
||||||
def decode_payload_node(self):
|
def decode_payload_node(self):
|
||||||
|
"""Decode node details from the payload"""
|
||||||
services, host, port = self.decode_payload_content("Q16sH")
|
services, host, port = self.decode_payload_content("Q16sH")
|
||||||
if host[0:12] == '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF':
|
if host[0:12] == '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF':
|
||||||
host = socket.inet_ntop(socket.AF_INET, str(host[12:16]))
|
host = socket.inet_ntop(socket.AF_INET, str(host[12:16]))
|
||||||
|
@ -160,18 +186,24 @@ class BMProto(AdvancedDispatcher, ObjectTracker):
|
||||||
return Node(services, host, port)
|
return Node(services, host, port)
|
||||||
|
|
||||||
def decode_payload_content(self, pattern="v"):
|
def decode_payload_content(self, pattern="v"):
|
||||||
# L = varint indicating the length of the next array
|
"""
|
||||||
# l = varint indicating the length of the next item
|
Decode the payload
|
||||||
# v = varint (or array)
|
|
||||||
# H = uint16
|
L = varint indicating the length of the next array
|
||||||
# I = uint32
|
l = varint indicating the length of the next item
|
||||||
# Q = uint64
|
v = varint (or array)
|
||||||
# i = net_addr (without time and stream number)
|
H = uint16
|
||||||
# s = string
|
I = uint32
|
||||||
# 0-9 = length of the next item
|
Q = uint64
|
||||||
# , = end of array
|
i = net_addr (without time and stream number)
|
||||||
|
s = string
|
||||||
|
0-9 = length of the next item
|
||||||
|
, = end of array
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
def decode_simple(self, char="v"):
|
def decode_simple(self, char="v"):
|
||||||
|
"""Some expected objects can be decoded very straightforwardly"""
|
||||||
if char == "v":
|
if char == "v":
|
||||||
return self.decode_payload_varint()
|
return self.decode_payload_varint()
|
||||||
if char == "i":
|
if char == "i":
|
||||||
|
@ -185,6 +217,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker):
|
||||||
if char == "Q":
|
if char == "Q":
|
||||||
self.payloadOffset += 8
|
self.payloadOffset += 8
|
||||||
return struct.unpack(">Q", self.payload[self.payloadOffset - 8:self.payloadOffset])[0]
|
return struct.unpack(">Q", self.payload[self.payloadOffset - 8:self.payloadOffset])[0]
|
||||||
|
return None
|
||||||
|
|
||||||
size = None
|
size = None
|
||||||
isArray = False
|
isArray = False
|
||||||
|
@ -197,13 +230,6 @@ class BMProto(AdvancedDispatcher, ObjectTracker):
|
||||||
# retval (array)
|
# retval (array)
|
||||||
parserStack = [[1, 1, False, pattern, 0, []]]
|
parserStack = [[1, 1, False, pattern, 0, []]]
|
||||||
|
|
||||||
#try:
|
|
||||||
# sys._getframe(200)
|
|
||||||
# logger.error("Stack depth warning, pattern: %s", pattern)
|
|
||||||
# return
|
|
||||||
#except ValueError:
|
|
||||||
# pass
|
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
i = parserStack[-1][3][parserStack[-1][4]]
|
i = parserStack[-1][3][parserStack[-1][4]]
|
||||||
if i in "0123456789" and (size is None or parserStack[-1][3][parserStack[-1][4] - 1] not in "lL"):
|
if i in "0123456789" and (size is None or parserStack[-1][3][parserStack[-1][4] - 1] not in "lL"):
|
||||||
|
@ -212,12 +238,11 @@ class BMProto(AdvancedDispatcher, ObjectTracker):
|
||||||
except TypeError:
|
except TypeError:
|
||||||
size = int(i)
|
size = int(i)
|
||||||
isArray = False
|
isArray = False
|
||||||
|
|
||||||
elif i in "Ll" and size is None:
|
elif i in "Ll" and size is None:
|
||||||
size = self.decode_payload_varint()
|
size = self.decode_payload_varint()
|
||||||
if i == "L":
|
isArray = bool(i == "L")
|
||||||
isArray = True
|
|
||||||
else:
|
|
||||||
isArray = False
|
|
||||||
elif size is not None:
|
elif size is not None:
|
||||||
if isArray:
|
if isArray:
|
||||||
parserStack.append([size, size, isArray, parserStack[-1][3][parserStack[-1][4]:], 0, []])
|
parserStack.append([size, size, isArray, parserStack[-1][3][parserStack[-1][4]:], 0, []])
|
||||||
|
@ -226,25 +251,26 @@ class BMProto(AdvancedDispatcher, ObjectTracker):
|
||||||
for j in range(parserStack[-1][4], len(parserStack[-1][3])):
|
for j in range(parserStack[-1][4], len(parserStack[-1][3])):
|
||||||
if parserStack[-1][3][j] not in "lL0123456789":
|
if parserStack[-1][3][j] not in "lL0123456789":
|
||||||
break
|
break
|
||||||
|
# pylint: disable=undefined-loop-variable
|
||||||
parserStack.append([size, size, isArray, parserStack[-1][3][parserStack[-1][4]:j + 1], 0, []])
|
parserStack.append([size, size, isArray, parserStack[-1][3][parserStack[-1][4]:j + 1], 0, []])
|
||||||
parserStack[-2][4] += len(parserStack[-1][3]) - 1
|
parserStack[-2][4] += len(parserStack[-1][3]) - 1
|
||||||
size = None
|
size = None
|
||||||
continue
|
continue
|
||||||
|
|
||||||
elif i == "s":
|
elif i == "s":
|
||||||
#if parserStack[-2][2]:
|
|
||||||
# parserStack[-1][5].append(self.payload[self.payloadOffset:self.payloadOffset + parserStack[-1][0]])
|
|
||||||
#else:
|
|
||||||
parserStack[-1][5] = self.payload[self.payloadOffset:self.payloadOffset + parserStack[-1][0]]
|
parserStack[-1][5] = self.payload[self.payloadOffset:self.payloadOffset + parserStack[-1][0]]
|
||||||
self.payloadOffset += parserStack[-1][0]
|
self.payloadOffset += parserStack[-1][0]
|
||||||
parserStack[-1][1] = 0
|
parserStack[-1][1] = 0
|
||||||
parserStack[-1][2] = True
|
parserStack[-1][2] = True
|
||||||
#del parserStack[-1]
|
|
||||||
size = None
|
size = None
|
||||||
|
|
||||||
elif i in "viHIQ":
|
elif i in "viHIQ":
|
||||||
parserStack[-1][5].append(decode_simple(self, parserStack[-1][3][parserStack[-1][4]]))
|
parserStack[-1][5].append(decode_simple(self, parserStack[-1][3][parserStack[-1][4]]))
|
||||||
size = None
|
size = None
|
||||||
|
|
||||||
else:
|
else:
|
||||||
size = None
|
size = None
|
||||||
|
|
||||||
for depth in range(len(parserStack) - 1, -1, -1):
|
for depth in range(len(parserStack) - 1, -1, -1):
|
||||||
parserStack[depth][4] += 1
|
parserStack[depth][4] += 1
|
||||||
if parserStack[depth][4] >= len(parserStack[depth][3]):
|
if parserStack[depth][4] >= len(parserStack[depth][3]):
|
||||||
|
@ -269,16 +295,19 @@ class BMProto(AdvancedDispatcher, ObjectTracker):
|
||||||
raise BMProtoInsufficientDataError()
|
raise BMProtoInsufficientDataError()
|
||||||
|
|
||||||
def bm_command_error(self):
|
def bm_command_error(self):
|
||||||
|
"""TBC"""
|
||||||
|
# pylint: disable=unused-variable
|
||||||
fatalStatus, banTime, inventoryVector, errorText = self.decode_payload_content("vvlsls")
|
fatalStatus, banTime, inventoryVector, errorText = self.decode_payload_content("vvlsls")
|
||||||
logger.error("%s:%i error: %i, %s", self.destination.host, self.destination.port, fatalStatus, errorText)
|
logger.error("%s:%i error: %i, %s", self.destination.host, self.destination.port, fatalStatus, errorText)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def bm_command_getdata(self):
|
def bm_command_getdata(self):
|
||||||
|
"""TBC"""
|
||||||
items = self.decode_payload_content("l32s")
|
items = self.decode_payload_content("l32s")
|
||||||
# skip?
|
# ..todo:: skip?
|
||||||
if time.time() < self.skipUntil:
|
if time.time() < self.skipUntil:
|
||||||
return True
|
return True
|
||||||
#TODO make this more asynchronous
|
# .. todo:: make this more asynchronous
|
||||||
helper_random.randomshuffle(items)
|
helper_random.randomshuffle(items)
|
||||||
for i in map(str, items):
|
for i in map(str, items):
|
||||||
if Dandelion().hasHash(i) and \
|
if Dandelion().hasHash(i) and \
|
||||||
|
@ -320,6 +349,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def bm_command_inv(self):
|
def bm_command_inv(self):
|
||||||
|
"""TBC"""
|
||||||
return self._command_inv(False)
|
return self._command_inv(False)
|
||||||
|
|
||||||
def bm_command_dinv(self):
|
def bm_command_dinv(self):
|
||||||
|
@ -329,12 +359,16 @@ class BMProto(AdvancedDispatcher, ObjectTracker):
|
||||||
return self._command_inv(True)
|
return self._command_inv(True)
|
||||||
|
|
||||||
def bm_command_object(self):
|
def bm_command_object(self):
|
||||||
|
"""TBC"""
|
||||||
objectOffset = self.payloadOffset
|
objectOffset = self.payloadOffset
|
||||||
nonce, expiresTime, objectType, version, streamNumber = self.decode_payload_content("QQIvv")
|
nonce, expiresTime, objectType, version, streamNumber = self.decode_payload_content("QQIvv")
|
||||||
self.object = BMObject(nonce, expiresTime, objectType, version, streamNumber, self.payload, self.payloadOffset)
|
self.object = BMObject(nonce, expiresTime, objectType, version, streamNumber, self.payload, self.payloadOffset)
|
||||||
|
|
||||||
if len(self.payload) - self.payloadOffset > BMProto.maxObjectPayloadSize:
|
if len(self.payload) - self.payloadOffset > BMProto.maxObjectPayloadSize:
|
||||||
logger.info('The payload length of this object is too large (%d bytes). Ignoring it.' % (len(self.payload) - self.payloadOffset))
|
logger.info(
|
||||||
|
'The payload length of this object is too large (%d bytes). Ignoring it.',
|
||||||
|
len(self.payload) - self.payloadOffset
|
||||||
|
)
|
||||||
raise BMProtoExcessiveDataError()
|
raise BMProtoExcessiveDataError()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
@ -347,7 +381,9 @@ class BMProto(AdvancedDispatcher, ObjectTracker):
|
||||||
try:
|
try:
|
||||||
self.object.checkStream()
|
self.object.checkStream()
|
||||||
except (BMObjectUnwantedStreamError,) as e:
|
except (BMObjectUnwantedStreamError,) as e:
|
||||||
BMProto.stopDownloadingObject(self.object.inventoryHash, BMConfigParser().get("inventory", "acceptmismatch"))
|
BMProto.stopDownloadingObject(
|
||||||
|
self.object.inventoryHash, BMConfigParser().get(
|
||||||
|
"inventory", "acceptmismatch"))
|
||||||
if not BMConfigParser().get("inventory", "acceptmismatch"):
|
if not BMConfigParser().get("inventory", "acceptmismatch"):
|
||||||
raise e
|
raise e
|
||||||
|
|
||||||
|
@ -366,7 +402,10 @@ class BMProto(AdvancedDispatcher, ObjectTracker):
|
||||||
Dandelion().removeHash(self.object.inventoryHash, "cycle detection")
|
Dandelion().removeHash(self.object.inventoryHash, "cycle detection")
|
||||||
|
|
||||||
Inventory()[self.object.inventoryHash] = (
|
Inventory()[self.object.inventoryHash] = (
|
||||||
self.object.objectType, self.object.streamNumber, buffer(self.payload[objectOffset:]), self.object.expiresTime, buffer(self.object.tag))
|
self.object.objectType, self.object.streamNumber,
|
||||||
|
buffer(self.payload[objectOffset:]), self.object.expiresTime,
|
||||||
|
buffer(self.object.tag)
|
||||||
|
)
|
||||||
self.handleReceivedObject(self.object.streamNumber, self.object.inventoryHash)
|
self.handleReceivedObject(self.object.streamNumber, self.object.inventoryHash)
|
||||||
invQueue.put((self.object.streamNumber, self.object.inventoryHash, self.destination))
|
invQueue.put((self.object.streamNumber, self.object.inventoryHash, self.destination))
|
||||||
return True
|
return True
|
||||||
|
@ -375,9 +414,10 @@ class BMProto(AdvancedDispatcher, ObjectTracker):
|
||||||
return self.decode_payload_content("LQIQ16sH")
|
return self.decode_payload_content("LQIQ16sH")
|
||||||
|
|
||||||
def bm_command_addr(self):
|
def bm_command_addr(self):
|
||||||
addresses = self._decode_addr()
|
"""TBC"""
|
||||||
for i in addresses:
|
these_addresses = self._decode_addr()
|
||||||
seenTime, stream, services, ip, port = i
|
for i in these_addresses:
|
||||||
|
seenTime, stream, _, ip, port = i
|
||||||
decodedIP = protocol.checkIPAddress(str(ip))
|
decodedIP = protocol.checkIPAddress(str(ip))
|
||||||
if stream not in state.streamsInWhichIAmParticipating:
|
if stream not in state.streamsInWhichIAmParticipating:
|
||||||
continue
|
continue
|
||||||
|
@ -402,18 +442,23 @@ class BMProto(AdvancedDispatcher, ObjectTracker):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def bm_command_portcheck(self):
|
def bm_command_portcheck(self):
|
||||||
|
"""TBC"""
|
||||||
portCheckerQueue.put(state.Peer(self.destination, self.peerNode.port))
|
portCheckerQueue.put(state.Peer(self.destination, self.peerNode.port))
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def bm_command_ping(self):
|
def bm_command_ping(self):
|
||||||
|
"""TBC"""
|
||||||
self.append_write_buf(protocol.CreatePacket('pong'))
|
self.append_write_buf(protocol.CreatePacket('pong'))
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def bm_command_pong(self):
|
def bm_command_pong(self):
|
||||||
# nothing really
|
"""noop"""
|
||||||
|
# pylint: disable=no-self-use
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def bm_command_verack(self):
|
def bm_command_verack(self):
|
||||||
|
"""TBC"""
|
||||||
|
|
||||||
self.verackReceived = True
|
self.verackReceived = True
|
||||||
if self.verackSent:
|
if self.verackSent:
|
||||||
if self.isSSL:
|
if self.isSSL:
|
||||||
|
@ -424,6 +469,8 @@ class BMProto(AdvancedDispatcher, ObjectTracker):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def bm_command_version(self):
|
def bm_command_version(self):
|
||||||
|
"""TBC"""
|
||||||
|
|
||||||
self.remoteProtocolVersion, self.services, self.timestamp, self.sockNode, self.peerNode, self.nonce, \
|
self.remoteProtocolVersion, self.services, self.timestamp, self.sockNode, self.peerNode, self.nonce, \
|
||||||
self.userAgent, self.streams = self.decode_payload_content("IQQiiQlsLv")
|
self.userAgent, self.streams = self.decode_payload_content("IQQiiQlsLv")
|
||||||
self.nonce = struct.pack('>Q', self.nonce)
|
self.nonce = struct.pack('>Q', self.nonce)
|
||||||
|
@ -436,15 +483,18 @@ class BMProto(AdvancedDispatcher, ObjectTracker):
|
||||||
logger.debug("user agent: %s", self.userAgent)
|
logger.debug("user agent: %s", self.userAgent)
|
||||||
logger.debug("streams: [%s]", ",".join(map(str, self.streams)))
|
logger.debug("streams: [%s]", ",".join(map(str, self.streams)))
|
||||||
if not self.peerValidityChecks():
|
if not self.peerValidityChecks():
|
||||||
# TODO ABORT
|
# .. todo:: ABORT
|
||||||
return True
|
return True
|
||||||
#shared.connectedHostsList[self.destination] = self.streams[0]
|
|
||||||
self.append_write_buf(protocol.CreatePacket('verack'))
|
self.append_write_buf(protocol.CreatePacket('verack'))
|
||||||
self.verackSent = True
|
self.verackSent = True
|
||||||
if not self.isOutbound:
|
if not self.isOutbound:
|
||||||
self.append_write_buf(protocol.assembleVersionMessage(self.destination.host, self.destination.port, \
|
self.append_write_buf(
|
||||||
network.connectionpool.BMConnectionPool().streams, True, nodeid=self.nodeid))
|
protocol.assembleVersionMessage(
|
||||||
#print "%s:%i: Sending version" % (self.destination.host, self.destination.port)
|
self.destination.host,
|
||||||
|
self.destination.port,
|
||||||
|
network.connectionpool.BMConnectionPool().streams,
|
||||||
|
True,
|
||||||
|
nodeid=self.nodeid))
|
||||||
if ((self.services & protocol.NODE_SSL == protocol.NODE_SSL) and
|
if ((self.services & protocol.NODE_SSL == protocol.NODE_SSL) and
|
||||||
protocol.haveSSL(not self.isOutbound)):
|
protocol.haveSSL(not self.isOutbound)):
|
||||||
self.isSSL = True
|
self.isSSL = True
|
||||||
|
@ -457,22 +507,25 @@ class BMProto(AdvancedDispatcher, ObjectTracker):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def peerValidityChecks(self):
|
def peerValidityChecks(self):
|
||||||
|
"""Check the validity of peers"""
|
||||||
if self.remoteProtocolVersion < 3:
|
if self.remoteProtocolVersion < 3:
|
||||||
self.append_write_buf(protocol.assembleErrorMessage(fatal=2,
|
self.append_write_buf(protocol.assembleErrorMessage(
|
||||||
errorText="Your is using an old protocol. Closing connection."))
|
fatal=2, errorText="Your is using an old protocol. Closing connection."))
|
||||||
logger.debug('Closing connection to old protocol version %s, node: %s',
|
logger.debug('Closing connection to old protocol version %s, node: %s',
|
||||||
str(self.remoteProtocolVersion), str(self.destination))
|
str(self.remoteProtocolVersion), str(self.destination))
|
||||||
return False
|
return False
|
||||||
if self.timeOffset > BMProto.maxTimeOffset:
|
if self.timeOffset > BMProto.maxTimeOffset:
|
||||||
self.append_write_buf(protocol.assembleErrorMessage(fatal=2,
|
self.append_write_buf(
|
||||||
|
protocol.assembleErrorMessage(
|
||||||
|
fatal=2,
|
||||||
errorText="Your time is too far in the future compared to mine. Closing connection."))
|
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.",
|
logger.info("%s's time is too far in the future (%s seconds). Closing connection to it.",
|
||||||
self.destination, self.timeOffset)
|
self.destination, self.timeOffset)
|
||||||
shared.timeOffsetWrongCount += 1
|
shared.timeOffsetWrongCount += 1
|
||||||
return False
|
return False
|
||||||
elif self.timeOffset < -BMProto.maxTimeOffset:
|
elif self.timeOffset < -BMProto.maxTimeOffset:
|
||||||
self.append_write_buf(protocol.assembleErrorMessage(fatal=2,
|
self.append_write_buf(protocol.assembleErrorMessage(
|
||||||
errorText="Your time is too far in the past compared to mine. Closing connection."))
|
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.",
|
logger.info("%s's time is too far in the past (timeOffset %s seconds). Closing connection to it.",
|
||||||
self.destination, self.timeOffset)
|
self.destination, self.timeOffset)
|
||||||
shared.timeOffsetWrongCount += 1
|
shared.timeOffsetWrongCount += 1
|
||||||
|
@ -480,16 +533,17 @@ class BMProto(AdvancedDispatcher, ObjectTracker):
|
||||||
else:
|
else:
|
||||||
shared.timeOffsetWrongCount = 0
|
shared.timeOffsetWrongCount = 0
|
||||||
if not self.streams:
|
if not self.streams:
|
||||||
self.append_write_buf(protocol.assembleErrorMessage(fatal=2,
|
self.append_write_buf(protocol.assembleErrorMessage(
|
||||||
errorText="We don't have shared stream interests. Closing connection."))
|
fatal=2, errorText="We don't have shared stream interests. Closing connection."))
|
||||||
logger.debug('Closed connection to %s because there is no overlapping interest in streams.',
|
logger.debug('Closed connection to %s because there is no overlapping interest in streams.',
|
||||||
str(self.destination))
|
str(self.destination))
|
||||||
return False
|
return False
|
||||||
if self.destination in network.connectionpool.BMConnectionPool().inboundConnections:
|
if self.destination in network.connectionpool.BMConnectionPool().inboundConnections:
|
||||||
try:
|
try:
|
||||||
if not protocol.checkSocksIP(self.destination.host):
|
if not protocol.checkSocksIP(self.destination.host):
|
||||||
self.append_write_buf(protocol.assembleErrorMessage(fatal=2,
|
self.append_write_buf(
|
||||||
errorText="Too many connections from your IP. Closing connection."))
|
protocol.assembleErrorMessage(
|
||||||
|
fatal=2, errorText="Too many connections from your IP. Closing connection."))
|
||||||
logger.debug('Closed connection to %s because we are already connected to that IP.',
|
logger.debug('Closed connection to %s because we are already connected to that IP.',
|
||||||
str(self.destination))
|
str(self.destination))
|
||||||
return False
|
return False
|
||||||
|
@ -510,7 +564,9 @@ class BMProto(AdvancedDispatcher, ObjectTracker):
|
||||||
str(self.destination))
|
str(self.destination))
|
||||||
return False
|
return False
|
||||||
if network.connectionpool.BMConnectionPool().isAlreadyConnected(self.nonce):
|
if network.connectionpool.BMConnectionPool().isAlreadyConnected(self.nonce):
|
||||||
self.append_write_buf(protocol.assembleErrorMessage(fatal=2,
|
self.append_write_buf(
|
||||||
|
protocol.assembleErrorMessage(
|
||||||
|
fatal=2,
|
||||||
errorText="I'm connected to myself. Closing connection."))
|
errorText="I'm connected to myself. Closing connection."))
|
||||||
logger.debug("Closed connection to %s because I'm connected to myself.",
|
logger.debug("Closed connection to %s because I'm connected to myself.",
|
||||||
str(self.destination))
|
str(self.destination))
|
||||||
|
@ -520,6 +576,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker):
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def assembleAddr(peerList):
|
def assembleAddr(peerList):
|
||||||
|
"""iBuild up a packed address"""
|
||||||
if isinstance(peerList, state.Peer):
|
if isinstance(peerList, state.Peer):
|
||||||
peerList = (peerList)
|
peerList = (peerList)
|
||||||
if not peerList:
|
if not peerList:
|
||||||
|
@ -541,6 +598,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker):
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def stopDownloadingObject(hashId, forwardAnyway=False):
|
def stopDownloadingObject(hashId, forwardAnyway=False):
|
||||||
|
"""Stop downloading an object"""
|
||||||
for connection in network.connectionpool.BMConnectionPool().inboundConnections.values() + \
|
for connection in network.connectionpool.BMConnectionPool().inboundConnections.values() + \
|
||||||
network.connectionpool.BMConnectionPool().outboundConnections.values():
|
network.connectionpool.BMConnectionPool().outboundConnections.values():
|
||||||
try:
|
try:
|
||||||
|
@ -559,6 +617,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def handle_close(self):
|
def handle_close(self):
|
||||||
|
"""Handle close"""
|
||||||
self.set_state("close")
|
self.set_state("close")
|
||||||
if not (self.accepting or self.connecting or self.connected):
|
if not (self.accepting or self.connecting or self.connected):
|
||||||
# already disconnected
|
# already disconnected
|
||||||
|
|
|
@ -1,41 +1,45 @@
|
||||||
import base64
|
# pylint: disable=too-many-ancestors
|
||||||
from binascii import hexlify
|
"""
|
||||||
import hashlib
|
tcp.py
|
||||||
|
======
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import absolute_import
|
||||||
|
|
||||||
import math
|
import math
|
||||||
import time
|
import time
|
||||||
from pprint import pprint
|
|
||||||
import socket
|
import socket
|
||||||
import struct
|
|
||||||
import random
|
import random
|
||||||
import traceback
|
|
||||||
|
|
||||||
from addresses import calculateInventoryHash
|
|
||||||
from debug import logger
|
from debug import logger
|
||||||
from helper_random import randomBytes
|
from helper_random import randomBytes
|
||||||
import helper_random
|
import helper_random
|
||||||
from inventory import Inventory
|
from inventory import Inventory
|
||||||
import knownnodes
|
import knownnodes
|
||||||
from network.advanceddispatcher import AdvancedDispatcher
|
from network.advanceddispatcher import AdvancedDispatcher
|
||||||
from network.bmproto import BMProtoError, BMProtoInsufficientDataError, BMProtoExcessiveDataError, BMProto
|
|
||||||
from network.bmobject import BMObject, BMObjectInsufficientPOWError, BMObjectInvalidDataError, BMObjectExpiredError, BMObjectUnwantedStreamError, BMObjectInvalidError, BMObjectAlreadyHaveError
|
from network.bmproto import BMProto
|
||||||
import network.connectionpool
|
import network.connectionpool
|
||||||
from network.dandelion import Dandelion
|
from network.dandelion import Dandelion
|
||||||
from network.node import Node
|
|
||||||
import network.asyncore_pollchoose as asyncore
|
import network.asyncore_pollchoose as asyncore
|
||||||
from network.proxy import Proxy, ProxyError, GeneralProxyError
|
|
||||||
from network.objectracker import ObjectTracker
|
from network.objectracker import ObjectTracker
|
||||||
from network.socks5 import Socks5Connection, Socks5Resolver, Socks5AuthError, Socks5Error
|
from network.socks5 import Socks5Connection
|
||||||
from network.socks4a import Socks4aConnection, Socks4aResolver, Socks4aError
|
from network.socks4a import Socks4aConnection
|
||||||
from network.tls import TLSDispatcher
|
from network.tls import TLSDispatcher
|
||||||
|
|
||||||
import addresses
|
import addresses
|
||||||
from bmconfigparser import BMConfigParser
|
from bmconfigparser import BMConfigParser
|
||||||
from queues import invQueue, objectProcessorQueue, portCheckerQueue, UISignalQueue, receiveDataQueue
|
from queues import invQueue, UISignalQueue, receiveDataQueue
|
||||||
import shared
|
import shared
|
||||||
import state
|
import state
|
||||||
import protocol
|
import protocol
|
||||||
|
|
||||||
class TCPConnection(BMProto, TLSDispatcher):
|
|
||||||
|
class TCPConnection(BMProto, TLSDispatcher): # pylint: disable=too-many-instance-attributes
|
||||||
|
"""
|
||||||
|
|
||||||
|
.. todo:: Look to understand and/or fix the non-parent-init-called
|
||||||
|
"""
|
||||||
|
|
||||||
def __init__(self, address=None, sock=None):
|
def __init__(self, address=None, sock=None):
|
||||||
BMProto.__init__(self, address=address, sock=sock)
|
BMProto.__init__(self, address=address, sock=sock)
|
||||||
self.verackReceived = False
|
self.verackReceived = False
|
||||||
|
@ -67,18 +71,27 @@ class TCPConnection(BMProto, TLSDispatcher):
|
||||||
self.connect(self.destination)
|
self.connect(self.destination)
|
||||||
logger.debug("Connecting to %s:%i", self.destination.host, self.destination.port)
|
logger.debug("Connecting to %s:%i", self.destination.host, self.destination.port)
|
||||||
encodedAddr = protocol.encodeHost(self.destination.host)
|
encodedAddr = protocol.encodeHost(self.destination.host)
|
||||||
if protocol.checkIPAddress(encodedAddr, True) and not protocol.checkSocksIP(self.destination.host):
|
self.local = all([
|
||||||
self.local = True
|
protocol.checkIPAddress(encodedAddr, True),
|
||||||
else:
|
not protocol.checkSocksIP(self.destination.host)
|
||||||
self.local = False
|
])
|
||||||
#shared.connectedHostsList[self.destination] = 0
|
ObjectTracker.__init__(self) # pylint: disable=non-parent-init-called
|
||||||
ObjectTracker.__init__(self)
|
|
||||||
self.bm_proto_reset()
|
self.bm_proto_reset()
|
||||||
self.set_state("bm_header", expectBytes=protocol.Header.size)
|
self.set_state("bm_header", expectBytes=protocol.Header.size)
|
||||||
|
|
||||||
def antiIntersectionDelay(self, initial=False):
|
def antiIntersectionDelay(self, initial=False):
|
||||||
|
"""TBC"""
|
||||||
# estimated time for a small object to propagate across the whole network
|
# 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 + invQueue.queueCount/2.0)
|
|
||||||
|
delay = math.ceil(
|
||||||
|
math.log(
|
||||||
|
max(
|
||||||
|
len(knownnodes.knownNodes[x])
|
||||||
|
for x in knownnodes.knownNodes
|
||||||
|
) + 2,
|
||||||
|
20
|
||||||
|
)
|
||||||
|
) * (0.2 + invQueue.queueCount / 2.0)
|
||||||
# take the stream with maximum amount of nodes
|
# take the stream with maximum amount of nodes
|
||||||
# +2 is to avoid problems with log(0) and log(1)
|
# +2 is to avoid problems with log(0) and log(1)
|
||||||
# 20 is avg connected nodes count
|
# 20 is avg connected nodes count
|
||||||
|
@ -93,12 +106,14 @@ class TCPConnection(BMProto, TLSDispatcher):
|
||||||
self.skipUntil = time.time() + delay
|
self.skipUntil = time.time() + delay
|
||||||
|
|
||||||
def state_connection_fully_established(self):
|
def state_connection_fully_established(self):
|
||||||
|
"""TBC"""
|
||||||
self.set_connection_fully_established()
|
self.set_connection_fully_established()
|
||||||
self.set_state("bm_header")
|
self.set_state("bm_header")
|
||||||
self.bm_proto_reset()
|
self.bm_proto_reset()
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def set_connection_fully_established(self):
|
def set_connection_fully_established(self):
|
||||||
|
"""TBC"""
|
||||||
if not self.isOutbound and not self.local:
|
if not self.isOutbound and not self.local:
|
||||||
shared.clientHasReceivedIncomingConnections = True
|
shared.clientHasReceivedIncomingConnections = True
|
||||||
UISignalQueue.put(('setStatusIcon', 'green'))
|
UISignalQueue.put(('setStatusIcon', 'green'))
|
||||||
|
@ -113,20 +128,18 @@ class TCPConnection(BMProto, TLSDispatcher):
|
||||||
self.sendBigInv()
|
self.sendBigInv()
|
||||||
|
|
||||||
def sendAddr(self):
|
def sendAddr(self):
|
||||||
|
"""TBC"""
|
||||||
# We are going to share a maximum number of 1000 addrs (per overlapping
|
# We are going to share a maximum number of 1000 addrs (per overlapping
|
||||||
# stream) with our peer. 500 from overlapping streams, 250 from the
|
# stream) with our peer. 500 from overlapping streams, 250 from the
|
||||||
# left child stream, and 250 from the right child stream.
|
# left child stream, and 250 from the right child stream.
|
||||||
maxAddrCount = BMConfigParser().safeGetInt("bitmessagesettings", "maxaddrperstreamsend", 500)
|
maxAddrCount = BMConfigParser().safeGetInt("bitmessagesettings", "maxaddrperstreamsend", 500)
|
||||||
|
|
||||||
# init
|
# init
|
||||||
addressCount = 0
|
|
||||||
payload = b''
|
|
||||||
|
|
||||||
templist = []
|
templist = []
|
||||||
addrs = {}
|
addrs = {}
|
||||||
for stream in self.streams:
|
for stream in self.streams:
|
||||||
with knownnodes.knownNodesLock:
|
with knownnodes.knownNodesLock:
|
||||||
if len(knownnodes.knownNodes[stream]) > 0:
|
if knownnodes.knownNodes[stream]:
|
||||||
filtered = {k: v for k, v in knownnodes.knownNodes[stream].items()
|
filtered = {k: v for k, v in knownnodes.knownNodes[stream].items()
|
||||||
if v["lastseen"] > (int(time.time()) - shared.maximumAgeOfNodesThatIAdvertiseToOthers)}
|
if v["lastseen"] > (int(time.time()) - shared.maximumAgeOfNodesThatIAdvertiseToOthers)}
|
||||||
elemCount = len(filtered)
|
elemCount = len(filtered)
|
||||||
|
@ -135,28 +148,30 @@ class TCPConnection(BMProto, TLSDispatcher):
|
||||||
# only if more recent than 3 hours
|
# only if more recent than 3 hours
|
||||||
addrs[stream] = helper_random.randomsample(filtered.items(), elemCount)
|
addrs[stream] = helper_random.randomsample(filtered.items(), elemCount)
|
||||||
# sent 250 only if the remote isn't interested in it
|
# sent 250 only if the remote isn't interested in it
|
||||||
if len(knownnodes.knownNodes[stream * 2]) > 0 and stream not in self.streams:
|
if knownnodes.knownNodes[stream * 2] and stream not in self.streams:
|
||||||
filtered = {k: v for k, v in knownnodes.knownNodes[stream * 2].items()
|
filtered = {k: v for k, v in knownnodes.knownNodes[stream * 2].items()
|
||||||
if v["lastseen"] > (int(time.time()) - shared.maximumAgeOfNodesThatIAdvertiseToOthers)}
|
if v["lastseen"] > (int(time.time()) - shared.maximumAgeOfNodesThatIAdvertiseToOthers)}
|
||||||
elemCount = len(filtered)
|
elemCount = len(filtered)
|
||||||
if elemCount > maxAddrCount / 2:
|
if elemCount > maxAddrCount / 2:
|
||||||
elemCount = int(maxAddrCount / 2)
|
elemCount = int(maxAddrCount / 2)
|
||||||
addrs[stream * 2] = helper_random.randomsample(filtered.items(), elemCount)
|
addrs[stream * 2] = helper_random.randomsample(filtered.items(), elemCount)
|
||||||
if len(knownnodes.knownNodes[(stream * 2) + 1]) > 0 and stream not in self.streams:
|
if knownnodes.knownNodes[(stream * 2) + 1] and stream not in self.streams:
|
||||||
filtered = {k: v for k, v in knownnodes.knownNodes[stream * 2 + 1].items()
|
filtered = {k: v for k, v in knownnodes.knownNodes[stream * 2 + 1].items()
|
||||||
if v["lastseen"] > (int(time.time()) - shared.maximumAgeOfNodesThatIAdvertiseToOthers)}
|
if v["lastseen"] > (int(time.time()) - shared.maximumAgeOfNodesThatIAdvertiseToOthers)}
|
||||||
elemCount = len(filtered)
|
elemCount = len(filtered)
|
||||||
if elemCount > maxAddrCount / 2:
|
if elemCount > maxAddrCount / 2:
|
||||||
elemCount = int(maxAddrCount / 2)
|
elemCount = int(maxAddrCount / 2)
|
||||||
addrs[stream * 2 + 1] = helper_random.randomsample(filtered.items(), elemCount)
|
addrs[stream * 2 + 1] = helper_random.randomsample(filtered.items(), elemCount)
|
||||||
Oh my eyes Oh my eyes
Fixed in PR#1271 Fixed in PR#1271
|
|||||||
for substream in addrs.keys():
|
for substream in addrs:
|
||||||
for peer, params in addrs[substream]:
|
for peer, params in addrs[substream]:
|
||||||
templist.append((substream, peer, params["lastseen"]))
|
templist.append((substream, peer, params["lastseen"]))
|
||||||
if len(templist) > 0:
|
if templist:
|
||||||
self.append_write_buf(BMProto.assembleAddr(templist))
|
self.append_write_buf(BMProto.assembleAddr(templist))
|
||||||
|
|
||||||
def sendBigInv(self):
|
def sendBigInv(self):
|
||||||
|
"""TBC"""
|
||||||
def sendChunk():
|
def sendChunk():
|
||||||
|
"""TBC"""
|
||||||
if objectCount == 0:
|
if objectCount == 0:
|
||||||
return
|
return
|
||||||
logger.debug('Sending huge inv message with %i objects to just this one peer', objectCount)
|
logger.debug('Sending huge inv message with %i objects to just this one peer', objectCount)
|
||||||
|
@ -172,13 +187,12 @@ class TCPConnection(BMProto, TLSDispatcher):
|
||||||
if Dandelion().hasHash(objHash):
|
if Dandelion().hasHash(objHash):
|
||||||
continue
|
continue
|
||||||
bigInvList[objHash] = 0
|
bigInvList[objHash] = 0
|
||||||
#self.objectsNewToThem[objHash] = time.time()
|
|
||||||
objectCount = 0
|
objectCount = 0
|
||||||
payload = b''
|
payload = b''
|
||||||
# Now let us start appending all of these hashes together. They will be
|
# Now let us start appending all of these hashes together. They will be
|
||||||
# sent out in a big inv message to our new peer.
|
# sent out in a big inv message to our new peer.
|
||||||
for hash, storedValue in bigInvList.items():
|
for obj_hash, _ in bigInvList.items():
|
||||||
payload += hash
|
payload += obj_hash
|
||||||
objectCount += 1
|
objectCount += 1
|
||||||
if objectCount >= BMProto.maxObjectCount:
|
if objectCount >= BMProto.maxObjectCount:
|
||||||
sendChunk()
|
sendChunk()
|
||||||
|
@ -189,20 +203,26 @@ class TCPConnection(BMProto, TLSDispatcher):
|
||||||
sendChunk()
|
sendChunk()
|
||||||
|
|
||||||
def handle_connect(self):
|
def handle_connect(self):
|
||||||
|
"""TBC"""
|
||||||
try:
|
try:
|
||||||
AdvancedDispatcher.handle_connect(self)
|
AdvancedDispatcher.handle_connect(self)
|
||||||
except socket.error as e:
|
except socket.error as e:
|
||||||
if e.errno in asyncore._DISCONNECTED:
|
if e.errno in asyncore._DISCONNECTED: # pylint: disable=protected-access
|
||||||
logger.debug("%s:%i: Connection failed: %s" % (self.destination.host, self.destination.port, str(e)))
|
logger.debug("%s:%i: Connection failed: %s", self.destination.host, self.destination.port, str(e))
|
||||||
return
|
return
|
||||||
self.nodeid = randomBytes(8)
|
self.nodeid = randomBytes(8)
|
||||||
self.append_write_buf(protocol.assembleVersionMessage(self.destination.host, self.destination.port, \
|
self.append_write_buf(
|
||||||
network.connectionpool.BMConnectionPool().streams, False, nodeid=self.nodeid))
|
protocol.assembleVersionMessage(
|
||||||
#print "%s:%i: Sending version" % (self.destination.host, self.destination.port)
|
self.destination.host,
|
||||||
|
self.destination.port,
|
||||||
|
network.connectionpool.BMConnectionPool().streams,
|
||||||
|
False,
|
||||||
|
nodeid=self.nodeid))
|
||||||
self.connectedAt = time.time()
|
self.connectedAt = time.time()
|
||||||
receiveDataQueue.put(self.destination)
|
receiveDataQueue.put(self.destination)
|
||||||
|
|
||||||
def handle_read(self):
|
def handle_read(self):
|
||||||
|
"""TBC"""
|
||||||
TLSDispatcher.handle_read(self)
|
TLSDispatcher.handle_read(self)
|
||||||
if self.isOutbound and self.fullyEstablished:
|
if self.isOutbound and self.fullyEstablished:
|
||||||
for s in self.streams:
|
for s in self.streams:
|
||||||
|
@ -214,9 +234,11 @@ class TCPConnection(BMProto, TLSDispatcher):
|
||||||
receiveDataQueue.put(self.destination)
|
receiveDataQueue.put(self.destination)
|
||||||
|
|
||||||
def handle_write(self):
|
def handle_write(self):
|
||||||
|
"""TBC"""
|
||||||
TLSDispatcher.handle_write(self)
|
TLSDispatcher.handle_write(self)
|
||||||
|
|
||||||
def handle_close(self):
|
def handle_close(self):
|
||||||
|
"""TBC"""
|
||||||
if self.isOutbound and not self.fullyEstablished:
|
if self.isOutbound and not self.fullyEstablished:
|
||||||
knownnodes.decreaseRating(self.destination)
|
knownnodes.decreaseRating(self.destination)
|
||||||
if self.fullyEstablished:
|
if self.fullyEstablished:
|
||||||
|
@ -227,37 +249,55 @@ class TCPConnection(BMProto, TLSDispatcher):
|
||||||
|
|
||||||
|
|
||||||
class Socks5BMConnection(Socks5Connection, TCPConnection):
|
class Socks5BMConnection(Socks5Connection, TCPConnection):
|
||||||
|
"""TBC"""
|
||||||
|
|
||||||
def __init__(self, address):
|
def __init__(self, address):
|
||||||
Socks5Connection.__init__(self, address=address)
|
Socks5Connection.__init__(self, address=address)
|
||||||
TCPConnection.__init__(self, address=address, sock=self.socket)
|
TCPConnection.__init__(self, address=address, sock=self.socket)
|
||||||
self.set_state("init")
|
self.set_state("init")
|
||||||
|
|
||||||
def state_proxy_handshake_done(self):
|
def state_proxy_handshake_done(self):
|
||||||
|
"""TBC"""
|
||||||
Socks5Connection.state_proxy_handshake_done(self)
|
Socks5Connection.state_proxy_handshake_done(self)
|
||||||
self.nodeid = randomBytes(8)
|
self.nodeid = randomBytes(8)
|
||||||
self.append_write_buf(protocol.assembleVersionMessage(self.destination.host, self.destination.port, \
|
self.append_write_buf(
|
||||||
network.connectionpool.BMConnectionPool().streams, False, nodeid=self.nodeid))
|
protocol.assembleVersionMessage(
|
||||||
|
self.destination.host,
|
||||||
|
self.destination.port,
|
||||||
|
network.connectionpool.BMConnectionPool().streams,
|
||||||
|
False,
|
||||||
|
nodeid=self.nodeid))
|
||||||
self.set_state("bm_header", expectBytes=protocol.Header.size)
|
self.set_state("bm_header", expectBytes=protocol.Header.size)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
class Socks4aBMConnection(Socks4aConnection, TCPConnection):
|
class Socks4aBMConnection(Socks4aConnection, TCPConnection):
|
||||||
|
"""TBC"""
|
||||||
|
|
||||||
def __init__(self, address):
|
def __init__(self, address):
|
||||||
Socks4aConnection.__init__(self, address=address)
|
Socks4aConnection.__init__(self, address=address)
|
||||||
TCPConnection.__init__(self, address=address, sock=self.socket)
|
TCPConnection.__init__(self, address=address, sock=self.socket)
|
||||||
self.set_state("init")
|
self.set_state("init")
|
||||||
|
|
||||||
def state_proxy_handshake_done(self):
|
def state_proxy_handshake_done(self):
|
||||||
|
"""TBC"""
|
||||||
Socks4aConnection.state_proxy_handshake_done(self)
|
Socks4aConnection.state_proxy_handshake_done(self)
|
||||||
self.nodeid = randomBytes(8)
|
self.nodeid = randomBytes(8)
|
||||||
self.append_write_buf(protocol.assembleVersionMessage(self.destination.host, self.destination.port, \
|
self.append_write_buf(
|
||||||
network.connectionpool.BMConnectionPool().streams, False, nodeid=self.nodeid))
|
protocol.assembleVersionMessage(
|
||||||
|
self.destination.host,
|
||||||
|
self.destination.port,
|
||||||
|
network.connectionpool.BMConnectionPool().streams,
|
||||||
|
False,
|
||||||
|
nodeid=self.nodeid))
|
||||||
self.set_state("bm_header", expectBytes=protocol.Header.size)
|
self.set_state("bm_header", expectBytes=protocol.Header.size)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
class TCPServer(AdvancedDispatcher):
|
class TCPServer(AdvancedDispatcher):
|
||||||
def __init__(self, host='127.0.0.1', port=8444):
|
"""TBC"""
|
||||||
|
|
||||||
|
def __init__(self, host='127.0.0.1', port=8444): # pylint: disable=redefined-outer-name
|
||||||
if not hasattr(self, '_map'):
|
if not hasattr(self, '_map'):
|
||||||
AdvancedDispatcher.__init__(self)
|
AdvancedDispatcher.__init__(self)
|
||||||
self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
|
self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
|
@ -280,15 +320,17 @@ class TCPServer(AdvancedDispatcher):
|
||||||
self.listen(5)
|
self.listen(5)
|
||||||
|
|
||||||
def is_bound(self):
|
def is_bound(self):
|
||||||
|
"""TBC"""
|
||||||
try:
|
try:
|
||||||
return self.bound
|
return self.bound
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def handle_accept(self):
|
def handle_accept(self):
|
||||||
|
"""TBC"""
|
||||||
pair = self.accept()
|
pair = self.accept()
|
||||||
if pair is not None:
|
if pair is not None:
|
||||||
sock, addr = pair
|
sock, _ = pair
|
||||||
state.ownAddresses[state.Peer(sock.getsockname()[0], sock.getsockname()[1])] = True
|
state.ownAddresses[state.Peer(sock.getsockname()[0], sock.getsockname()[1])] = True
|
||||||
if len(network.connectionpool.BMConnectionPool().inboundConnections) + \
|
if len(network.connectionpool.BMConnectionPool().inboundConnections) + \
|
||||||
len(network.connectionpool.BMConnectionPool().outboundConnections) > \
|
len(network.connectionpool.BMConnectionPool().outboundConnections) > \
|
||||||
|
@ -310,17 +352,7 @@ if __name__ == "__main__":
|
||||||
|
|
||||||
for host in (("127.0.0.1", 8448),):
|
for host in (("127.0.0.1", 8448),):
|
||||||
direct = TCPConnection(host)
|
direct = TCPConnection(host)
|
||||||
while len(asyncore.socket_map) > 0:
|
while asyncore.socket_map:
|
||||||
print "loop, state = %s" % (direct.state)
|
print "loop, state = %s" % (direct.state)
|
||||||
asyncore.loop(timeout=10, count=1)
|
asyncore.loop(timeout=10, count=1)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
proxy = Socks5BMConnection(host)
|
|
||||||
while len(asyncore.socket_map) > 0:
|
|
||||||
# print "loop, state = %s" % (proxy.state)
|
|
||||||
asyncore.loop(timeout=10, count=1)
|
|
||||||
|
|
||||||
proxy = Socks4aBMConnection(host)
|
|
||||||
while len(asyncore.socket_map) > 0:
|
|
||||||
# print "loop, state = %s" % (proxy.state)
|
|
||||||
asyncore.loop(timeout=10, count=1)
|
|
||||||
|
|
|
@ -1,33 +1,42 @@
|
||||||
#import shared
|
# pylint: disable=too-many-branches,too-many-statements,protected-access
|
||||||
#import time
|
"""
|
||||||
#from multiprocessing import Pool, cpu_count
|
proofofwork.py
|
||||||
|
==============
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import absolute_import
|
||||||
|
|
||||||
|
import ctypes
|
||||||
import hashlib
|
import hashlib
|
||||||
from struct import unpack, pack
|
import os
|
||||||
from subprocess import call
|
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
from bmconfigparser import BMConfigParser
|
from struct import unpack, pack
|
||||||
from debug import logger
|
from subprocess import call
|
||||||
|
|
||||||
import paths
|
import paths
|
||||||
import openclpow
|
import openclpow
|
||||||
import queues
|
import queues
|
||||||
import tr
|
import tr
|
||||||
import os
|
|
||||||
import ctypes
|
|
||||||
|
|
||||||
import state
|
import state
|
||||||
|
from bmconfigparser import BMConfigParser
|
||||||
|
from debug import logger
|
||||||
|
|
||||||
|
|
||||||
bitmsglib = 'bitmsghash.so'
|
bitmsglib = 'bitmsghash.so'
|
||||||
|
|
||||||
bmpow = None
|
bmpow = None
|
||||||
|
|
||||||
|
|
||||||
def _set_idle():
|
def _set_idle():
|
||||||
if 'linux' in sys.platform:
|
if 'linux' in sys.platform:
|
||||||
os.nice(20)
|
os.nice(20)
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
|
# pylint: disable=no-member,import-error
|
||||||
sys.getwindowsversion()
|
sys.getwindowsversion()
|
||||||
import win32api,win32process,win32con # @UnresolvedImport
|
import win32api
|
||||||
|
import win32process
|
||||||
|
import win32con # @UnresolvedImport
|
||||||
pid = win32api.GetCurrentProcessId()
|
pid = win32api.GetCurrentProcessId()
|
||||||
handle = win32api.OpenProcess(win32con.PROCESS_ALL_ACCESS, True, pid)
|
handle = win32api.OpenProcess(win32con.PROCESS_ALL_ACCESS, True, pid)
|
||||||
win32process.SetPriorityClass(handle, win32process.IDLE_PRIORITY_CLASS)
|
win32process.SetPriorityClass(handle, win32process.IDLE_PRIORITY_CLASS)
|
||||||
|
@ -35,26 +44,31 @@ def _set_idle():
|
||||||
# Windows 64-bit
|
# Windows 64-bit
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
def _pool_worker(nonce, initialHash, target, pool_size):
|
def _pool_worker(nonce, initialHash, target, pool_size):
|
||||||
_set_idle()
|
_set_idle()
|
||||||
trialValue = float('inf')
|
trialValue = float('inf')
|
||||||
while trialValue > target:
|
while trialValue > target:
|
||||||
nonce += pool_size
|
nonce += pool_size
|
||||||
trialValue, = unpack('>Q',hashlib.sha512(hashlib.sha512(pack('>Q',nonce) + initialHash).digest()).digest()[0:8])
|
trialValue, = unpack('>Q', hashlib.sha512(hashlib.sha512(
|
||||||
|
pack('>Q', nonce) + initialHash).digest()).digest()[0:8])
|
||||||
return [trialValue, nonce]
|
return [trialValue, nonce]
|
||||||
|
|
||||||
|
|
||||||
def _doSafePoW(target, initialHash):
|
def _doSafePoW(target, initialHash):
|
||||||
logger.debug("Safe PoW start")
|
logger.debug("Safe PoW start")
|
||||||
nonce = 0
|
nonce = 0
|
||||||
trialValue = float('inf')
|
trialValue = float('inf')
|
||||||
while trialValue > target and state.shutdown == 0:
|
while trialValue > target and state.shutdown == 0:
|
||||||
nonce += 1
|
nonce += 1
|
||||||
trialValue, = unpack('>Q',hashlib.sha512(hashlib.sha512(pack('>Q',nonce) + initialHash).digest()).digest()[0:8])
|
trialValue, = unpack('>Q', hashlib.sha512(hashlib.sha512(
|
||||||
|
pack('>Q', nonce) + initialHash).digest()).digest()[0:8])
|
||||||
if state.shutdown != 0:
|
if state.shutdown != 0:
|
||||||
raise StopIteration("Interrupted")
|
raise StopIteration("Interrupted") # pylint: misplaced-bare-raise
|
||||||
logger.debug("Safe PoW done")
|
logger.debug("Safe PoW done")
|
||||||
return [trialValue, nonce]
|
return [trialValue, nonce]
|
||||||
|
|
||||||
|
|
||||||
def _doFastPoW(target, initialHash):
|
def _doFastPoW(target, initialHash):
|
||||||
logger.debug("Fast PoW start")
|
logger.debug("Fast PoW start")
|
||||||
from multiprocessing import Pool, cpu_count
|
from multiprocessing import Pool, cpu_count
|
||||||
|
@ -97,6 +111,7 @@ def _doFastPoW(target, initialHash):
|
||||||
return result[0], result[1]
|
return result[0], result[1]
|
||||||
time.sleep(0.2)
|
time.sleep(0.2)
|
||||||
|
|
||||||
|
|
||||||
def _doCPoW(target, initialHash):
|
def _doCPoW(target, initialHash):
|
||||||
h = initialHash
|
h = initialHash
|
||||||
m = target
|
m = target
|
||||||
|
@ -110,15 +125,28 @@ def _doCPoW(target, initialHash):
|
||||||
logger.debug("C PoW done")
|
logger.debug("C PoW done")
|
||||||
return [trialValue, nonce]
|
return [trialValue, nonce]
|
||||||
|
|
||||||
|
|
||||||
def _doGPUPoW(target, initialHash):
|
def _doGPUPoW(target, initialHash):
|
||||||
logger.debug("GPU PoW start")
|
logger.debug("GPU PoW start")
|
||||||
nonce = openclpow.do_opencl_pow(initialHash.encode("hex"), target)
|
nonce = openclpow.do_opencl_pow(initialHash.encode("hex"), target)
|
||||||
trialValue, = unpack('>Q', hashlib.sha512(hashlib.sha512(pack('>Q', nonce) + initialHash).digest()).digest()[0:8])
|
trialValue, = unpack('>Q', hashlib.sha512(hashlib.sha512(pack('>Q', nonce) + initialHash).digest()).digest()[0:8])
|
||||||
#print "{} - value {} < {}".format(nonce, trialValue, target)
|
|
||||||
if trialValue > target:
|
if trialValue > target:
|
||||||
deviceNames = ", ".join(gpu.name for gpu in openclpow.enabledGpus)
|
deviceNames = ", ".join(gpu.name for gpu in openclpow.enabledGpus)
|
||||||
queues.UISignalQueue.put(('updateStatusBar', (tr._translate("MainWindow",'Your GPU(s) did not calculate correctly, disabling OpenCL. Please report to the developers.'), 1)))
|
queues.UISignalQueue.put(
|
||||||
logger.error("Your GPUs (%s) did not calculate correctly, disabling OpenCL. Please report to the developers.", deviceNames)
|
(
|
||||||
|
'updateStatusBar',
|
||||||
|
(
|
||||||
|
tr._translate(
|
||||||
|
"MainWindow",
|
||||||
|
'Your GPU(s) did not calculate correctly, disabling OpenCL. Please report to the developers.'
|
||||||
|
),
|
||||||
|
1
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
logger.error(
|
||||||
|
"Your GPUs (%s) did not calculate correctly, disabling OpenCL. Please report to the developers.",
|
||||||
|
deviceNames)
|
||||||
openclpow.enabledGpus = []
|
openclpow.enabledGpus = []
|
||||||
raise Exception("GPU did not calculate correctly.")
|
raise Exception("GPU did not calculate correctly.")
|
||||||
if state.shutdown != 0:
|
if state.shutdown != 0:
|
||||||
|
@ -126,11 +154,17 @@ def _doGPUPoW(target, initialHash):
|
||||||
logger.debug("GPU PoW done")
|
logger.debug("GPU PoW done")
|
||||||
return [trialValue, nonce]
|
return [trialValue, nonce]
|
||||||
|
|
||||||
def estimate(difficulty, format = False):
|
|
||||||
|
def estimate(difficulty, format=False): # pylint: disable=redefined-builtin
|
||||||
|
"""
|
||||||
|
.. todo: fix unused variable
|
||||||
|
"""
|
||||||
ret = difficulty / 10
|
ret = difficulty / 10
|
||||||
if ret < 1:
|
if ret < 1:
|
||||||
ret = 1
|
ret = 1
|
||||||
|
|
||||||
if format:
|
if format:
|
||||||
|
# pylint: disable=unused-variable
|
||||||
out = str(int(ret)) + " seconds"
|
out = str(int(ret)) + " seconds"
|
||||||
if ret > 60:
|
if ret > 60:
|
||||||
ret /= 60
|
ret /= 60
|
||||||
|
@ -148,25 +182,46 @@ def estimate(difficulty, format = False):
|
||||||
if ret > 366:
|
if ret > 366:
|
||||||
ret /= 366
|
ret /= 366
|
||||||
out = str(int(ret)) + " years"
|
out = str(int(ret)) + " years"
|
||||||
else:
|
ret = None # Ensure legacy behaviour
|
||||||
|
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
||||||
def getPowType():
|
def getPowType():
|
||||||
|
"""Get the proof of work implementation"""
|
||||||
|
|
||||||
if openclpow.openclEnabled():
|
if openclpow.openclEnabled():
|
||||||
return "OpenCL"
|
return "OpenCL"
|
||||||
if bmpow:
|
if bmpow:
|
||||||
return "C"
|
return "C"
|
||||||
return "python"
|
return "python"
|
||||||
|
|
||||||
|
|
||||||
def notifyBuild(tried=False):
|
def notifyBuild(tried=False):
|
||||||
|
"""TBC"""
|
||||||
|
|
||||||
if bmpow:
|
if bmpow:
|
||||||
queues.UISignalQueue.put(('updateStatusBar', (tr._translate("proofofwork", "C PoW module built successfully."), 1)))
|
queues.UISignalQueue.put(('updateStatusBar', (tr._translate(
|
||||||
|
"proofofwork", "C PoW module built successfully."), 1)))
|
||||||
elif tried:
|
elif tried:
|
||||||
queues.UISignalQueue.put(('updateStatusBar', (tr._translate("proofofwork", "Failed to build C PoW module. Please build it manually."), 1)))
|
queues.UISignalQueue.put(
|
||||||
|
(
|
||||||
|
'updateStatusBar', (
|
||||||
|
tr._translate(
|
||||||
|
"proofofwork",
|
||||||
|
"Failed to build C PoW module. Please build it manually."
|
||||||
|
),
|
||||||
|
1
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
queues.UISignalQueue.put(('updateStatusBar', (tr._translate("proofofwork", "C PoW module unavailable. Please build it."), 1)))
|
queues.UISignalQueue.put(('updateStatusBar', (tr._translate(
|
||||||
|
"proofofwork", "C PoW module unavailable. Please build it."), 1)))
|
||||||
|
|
||||||
|
|
||||||
def buildCPoW():
|
def buildCPoW():
|
||||||
|
"""TBC"""
|
||||||
if bmpow is not None:
|
if bmpow is not None:
|
||||||
return
|
return
|
||||||
if paths.frozen is not None:
|
if paths.frozen is not None:
|
||||||
|
@ -190,16 +245,14 @@ def buildCPoW():
|
||||||
except:
|
except:
|
||||||
notifyBuild(True)
|
notifyBuild(True)
|
||||||
|
|
||||||
|
|
||||||
def run(target, initialHash):
|
def run(target, initialHash):
|
||||||
|
"""Run the proof of work thread"""
|
||||||
|
|
||||||
if state.shutdown != 0:
|
if state.shutdown != 0:
|
||||||
raise
|
raise
|
||||||
target = int(target)
|
target = int(target)
|
||||||
if openclpow.openclEnabled():
|
if openclpow.openclEnabled():
|
||||||
# trialvalue1, nonce1 = _doGPUPoW(target, initialHash)
|
|
||||||
# trialvalue, nonce = _doFastPoW(target, initialHash)
|
|
||||||
# print "GPU: %s, %s" % (trialvalue1, nonce1)
|
|
||||||
# print "Fast: %s, %s" % (trialvalue, nonce)
|
|
||||||
# return [trialvalue, nonce]
|
|
||||||
try:
|
try:
|
||||||
return _doGPUPoW(target, initialHash)
|
return _doGPUPoW(target, initialHash)
|
||||||
except StopIteration:
|
except StopIteration:
|
||||||
|
@ -225,7 +278,6 @@ def run(target, initialHash):
|
||||||
raise
|
raise
|
||||||
except:
|
except:
|
||||||
logger.error("Fast PoW got exception:", exc_info=True)
|
logger.error("Fast PoW got exception:", exc_info=True)
|
||||||
pass #fallback
|
|
||||||
try:
|
try:
|
||||||
return _doSafePoW(target, initialHash)
|
return _doSafePoW(target, initialHash)
|
||||||
except StopIteration:
|
except StopIteration:
|
||||||
|
@ -233,16 +285,23 @@ def run(target, initialHash):
|
||||||
except:
|
except:
|
||||||
pass # fallback
|
pass # fallback
|
||||||
|
|
||||||
|
|
||||||
def resetPoW():
|
def resetPoW():
|
||||||
|
"""TBC"""
|
||||||
openclpow.initCL()
|
openclpow.initCL()
|
||||||
|
|
||||||
|
|
||||||
# init
|
# init
|
||||||
|
|
||||||
|
|
||||||
def init():
|
def init():
|
||||||
global bitmsglib, bso, bmpow
|
"""TBC"""
|
||||||
|
# pylint: disable=global-statement
|
||||||
|
global bitmsglib, bmpow
|
||||||
|
|
||||||
openclpow.initCL()
|
openclpow.initCL()
|
||||||
|
|
||||||
if "win32" == sys.platform:
|
if sys.platform == "win32":
|
||||||
if ctypes.sizeof(ctypes.c_voidp) == 4:
|
if ctypes.sizeof(ctypes.c_voidp) == 4:
|
||||||
bitmsglib = 'bitmsghash32.dll'
|
bitmsglib = 'bitmsghash32.dll'
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
"""SocksiPy - Python SOCKS module.
|
# pylint: disable=too-many-arguments,global-statement,too-many-branches
|
||||||
|
"""
|
||||||
|
SocksiPy - Python SOCKS module.
|
||||||
Version 1.00
|
Version 1.00
|
||||||
|
|
||||||
Copyright 2006 Dan-Haim. All rights reserved.
|
Copyright 2006 Dan-Haim. All rights reserved.
|
||||||
|
@ -28,10 +30,6 @@ OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMANGE.
|
||||||
This module provides a standard socket-like interface for Python
|
This module provides a standard socket-like interface for Python
|
||||||
for tunneling connections through SOCKS proxies.
|
for tunneling connections through SOCKS proxies.
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
Minor modifications made by Christopher Gilbert (http://motomastyle.com/)
|
Minor modifications made by Christopher Gilbert (http://motomastyle.com/)
|
||||||
for use in PyLoris (http://pyloris.sourceforge.net/)
|
for use in PyLoris (http://pyloris.sourceforge.net/)
|
||||||
|
|
||||||
|
@ -42,7 +40,7 @@ mainly to merge bug fixes found in Sourceforge
|
||||||
|
|
||||||
import socket
|
import socket
|
||||||
import struct
|
import struct
|
||||||
import sys
|
|
||||||
|
|
||||||
PROXY_TYPE_SOCKS4 = 1
|
PROXY_TYPE_SOCKS4 = 1
|
||||||
PROXY_TYPE_SOCKS5 = 2
|
PROXY_TYPE_SOCKS5 = 2
|
||||||
|
@ -51,12 +49,36 @@ PROXY_TYPE_HTTP = 3
|
||||||
_defaultproxy = None
|
_defaultproxy = None
|
||||||
_orgsocket = socket.socket
|
_orgsocket = socket.socket
|
||||||
|
|
||||||
class ProxyError(Exception): pass
|
|
||||||
class GeneralProxyError(ProxyError): pass
|
class ProxyError(Exception):
|
||||||
class Socks5AuthError(ProxyError): pass
|
"""Base class for other ProxyErrors"""
|
||||||
class Socks5Error(ProxyError): pass
|
pass
|
||||||
class Socks4Error(ProxyError): pass
|
|
||||||
class HTTPError(ProxyError): pass
|
|
||||||
|
class GeneralProxyError(ProxyError):
|
||||||
|
"""Handle a general proxy error"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class Socks5AuthError(ProxyError):
|
||||||
|
"""Handle a SOCKS5 auth error"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class Socks5Error(ProxyError):
|
||||||
|
"""Handle a SOCKS5 non-auth error"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class Socks4Error(ProxyError):
|
||||||
|
"""Handle a SOCKS4 error"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class HTTPError(ProxyError):
|
||||||
|
"""Handle a HTTP error"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
_generalerrors = ("success",
|
_generalerrors = ("success",
|
||||||
"invalid data",
|
"invalid data",
|
||||||
|
@ -92,6 +114,7 @@ _socks4errors = ("request granted",
|
||||||
"request rejected because the client program and identd report different user-ids",
|
"request rejected because the client program and identd report different user-ids",
|
||||||
"unknown error")
|
"unknown error")
|
||||||
|
|
||||||
|
|
||||||
def setdefaultproxy(proxytype=None, addr=None, port=None, rdns=True, username=None, password=None):
|
def setdefaultproxy(proxytype=None, addr=None, port=None, rdns=True, username=None, password=None):
|
||||||
"""setdefaultproxy(proxytype, addr[, port[, rdns[, username[, password]]]])
|
"""setdefaultproxy(proxytype, addr[, port[, rdns[, username[, password]]]])
|
||||||
Sets a default proxy which all further socksocket objects will use,
|
Sets a default proxy which all further socksocket objects will use,
|
||||||
|
@ -100,6 +123,7 @@ def setdefaultproxy(proxytype=None, addr=None, port=None, rdns=True, username=No
|
||||||
global _defaultproxy
|
global _defaultproxy
|
||||||
_defaultproxy = (proxytype, addr, port, rdns, username, password)
|
_defaultproxy = (proxytype, addr, port, rdns, username, password)
|
||||||
|
|
||||||
|
|
||||||
def wrapmodule(module):
|
def wrapmodule(module):
|
||||||
"""wrapmodule(module)
|
"""wrapmodule(module)
|
||||||
Attempts to replace a module's socket library with a SOCKS socket. Must set
|
Attempts to replace a module's socket library with a SOCKS socket. Must set
|
||||||
|
@ -107,11 +131,12 @@ def wrapmodule(module):
|
||||||
This will only work on modules that import socket directly into the namespace;
|
This will only work on modules that import socket directly into the namespace;
|
||||||
most of the Python Standard Library falls into this category.
|
most of the Python Standard Library falls into this category.
|
||||||
"""
|
"""
|
||||||
if _defaultproxy != None:
|
if _defaultproxy is not None:
|
||||||
module.socket.socket = socksocket
|
module.socket.socket = socksocket
|
||||||
else:
|
else:
|
||||||
raise GeneralProxyError((4, "no proxy specified"))
|
raise GeneralProxyError((4, "no proxy specified"))
|
||||||
|
|
||||||
|
|
||||||
class socksocket(socket.socket):
|
class socksocket(socket.socket):
|
||||||
"""socksocket([family[, type[, proto]]]) -> socket object
|
"""socksocket([family[, type[, proto]]]) -> socket object
|
||||||
Open a SOCKS enabled socket. The parameters are the same as
|
Open a SOCKS enabled socket. The parameters are the same as
|
||||||
|
@ -120,8 +145,9 @@ class socksocket(socket.socket):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, family=socket.AF_INET, type=socket.SOCK_STREAM, proto=0, _sock=None):
|
def __init__(self, family=socket.AF_INET, type=socket.SOCK_STREAM, proto=0, _sock=None):
|
||||||
|
# pylint: disable=redefined-builtin
|
||||||
_orgsocket.__init__(self, family, type, proto, _sock)
|
_orgsocket.__init__(self, family, type, proto, _sock)
|
||||||
if _defaultproxy != None:
|
if _defaultproxy is not None:
|
||||||
self.__proxy = _defaultproxy
|
self.__proxy = _defaultproxy
|
||||||
else:
|
else:
|
||||||
self.__proxy = (None, None, None, None, None, None)
|
self.__proxy = (None, None, None, None, None, None)
|
||||||
|
@ -139,7 +165,8 @@ class socksocket(socket.socket):
|
||||||
raise GeneralProxyError((6, "timed out"))
|
raise GeneralProxyError((6, "timed out"))
|
||||||
while len(data) < count:
|
while len(data) < count:
|
||||||
d = self.recv(count - len(data))
|
d = self.recv(count - len(data))
|
||||||
if not d: raise GeneralProxyError((0, "connection closed unexpectedly"))
|
if not d:
|
||||||
|
raise GeneralProxyError((0, "connection closed unexpectedly"))
|
||||||
data = data + d
|
data = data + d
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
@ -167,7 +194,7 @@ class socksocket(socket.socket):
|
||||||
Negotiates a connection through a SOCKS5 server.
|
Negotiates a connection through a SOCKS5 server.
|
||||||
"""
|
"""
|
||||||
# First we'll send the authentication packages we support.
|
# First we'll send the authentication packages we support.
|
||||||
if (self.__proxy[4]!=None) and (self.__proxy[5]!=None):
|
if (self.__proxy[4] is not None) and (self.__proxy[5] is not None):
|
||||||
# The username/password details were supplied to the
|
# The username/password details were supplied to the
|
||||||
# setproxy method so we support the USERNAME/PASSWORD
|
# setproxy method so we support the USERNAME/PASSWORD
|
||||||
# authentication (in addition to the standard none).
|
# authentication (in addition to the standard none).
|
||||||
|
@ -189,7 +216,11 @@ class socksocket(socket.socket):
|
||||||
elif chosenauth[1:2] == chr(0x02).encode():
|
elif chosenauth[1:2] == chr(0x02).encode():
|
||||||
# Okay, we need to perform a basic username/password
|
# Okay, we need to perform a basic username/password
|
||||||
# authentication.
|
# authentication.
|
||||||
self.sendall(chr(0x01).encode() + chr(len(self.__proxy[4])) + self.__proxy[4] + chr(len(self.__proxy[5])) + self.__proxy[5])
|
self.sendall(chr(0x01).encode() +
|
||||||
|
chr(len(self.__proxy[4])) +
|
||||||
|
self.__proxy[4] +
|
||||||
|
chr(len(self.__proxy[5])) +
|
||||||
|
self.__proxy[5])
|
||||||
authstat = self.__recvall(2)
|
authstat = self.__recvall(2)
|
||||||
if authstat[0:1] != chr(0x01).encode():
|
if authstat[0:1] != chr(0x01).encode():
|
||||||
# Bad response
|
# Bad response
|
||||||
|
@ -251,7 +282,7 @@ class socksocket(socket.socket):
|
||||||
raise GeneralProxyError((1, _generalerrors[1]))
|
raise GeneralProxyError((1, _generalerrors[1]))
|
||||||
boundport = struct.unpack(">H", self.__recvall(2))[0]
|
boundport = struct.unpack(">H", self.__recvall(2))[0]
|
||||||
self.__proxysockname = (boundaddr, boundport)
|
self.__proxysockname = (boundaddr, boundport)
|
||||||
if ipaddr != None:
|
if ipaddr is not None:
|
||||||
self.__proxypeername = (socket.inet_ntoa(ipaddr), destport)
|
self.__proxypeername = (socket.inet_ntoa(ipaddr), destport)
|
||||||
else:
|
else:
|
||||||
self.__proxypeername = (destaddr, destport)
|
self.__proxypeername = (destaddr, destport)
|
||||||
|
@ -284,7 +315,7 @@ class socksocket(socket.socket):
|
||||||
else:
|
else:
|
||||||
self.close()
|
self.close()
|
||||||
raise GeneralProxyError((1, _generalerrors[1]))
|
raise GeneralProxyError((1, _generalerrors[1]))
|
||||||
boundport = struct.unpack(">H", self.__recvall(2))[0]
|
_ = struct.unpack(">H", self.__recvall(2))[0]
|
||||||
return ip
|
return ip
|
||||||
|
|
||||||
def getproxysockname(self):
|
def getproxysockname(self):
|
||||||
|
@ -307,6 +338,7 @@ class socksocket(socket.socket):
|
||||||
return self.__proxypeername
|
return self.__proxypeername
|
||||||
|
|
||||||
def getproxytype(self):
|
def getproxytype(self):
|
||||||
|
"""Get the proxy type"""
|
||||||
return self.__proxy[0]
|
return self.__proxy[0]
|
||||||
|
|
||||||
def __negotiatesocks4(self, destaddr, destport):
|
def __negotiatesocks4(self, destaddr, destport):
|
||||||
|
@ -327,7 +359,7 @@ class socksocket(socket.socket):
|
||||||
# Construct the request packet
|
# Construct the request packet
|
||||||
req = struct.pack(">BBH", 0x04, 0x01, destport) + ipaddr
|
req = struct.pack(">BBH", 0x04, 0x01, destport) + ipaddr
|
||||||
# The username parameter is considered userid for SOCKS4
|
# The username parameter is considered userid for SOCKS4
|
||||||
if self.__proxy[4] != None:
|
if self.__proxy[4] is not None:
|
||||||
req = req + self.__proxy[4]
|
req = req + self.__proxy[4]
|
||||||
req = req + chr(0x00).encode()
|
req = req + chr(0x00).encode()
|
||||||
# DNS name if remote resolving is required
|
# DNS name if remote resolving is required
|
||||||
|
@ -352,7 +384,7 @@ class socksocket(socket.socket):
|
||||||
raise Socks4Error((94, _socks4errors[4]))
|
raise Socks4Error((94, _socks4errors[4]))
|
||||||
# Get the bound address/port
|
# Get the bound address/port
|
||||||
self.__proxysockname = (socket.inet_ntoa(resp[4:]), struct.unpack(">H", resp[2:4])[0])
|
self.__proxysockname = (socket.inet_ntoa(resp[4:]), struct.unpack(">H", resp[2:4])[0])
|
||||||
if rmtrslv != None:
|
if rmtrslv is not None:
|
||||||
self.__proxypeername = (socket.inet_ntoa(ipaddr), destport)
|
self.__proxypeername = (socket.inet_ntoa(ipaddr), destport)
|
||||||
else:
|
else:
|
||||||
self.__proxypeername = (destaddr, destport)
|
self.__proxypeername = (destaddr, destport)
|
||||||
|
@ -366,7 +398,16 @@ class socksocket(socket.socket):
|
||||||
addr = socket.gethostbyname(destaddr)
|
addr = socket.gethostbyname(destaddr)
|
||||||
else:
|
else:
|
||||||
addr = destaddr
|
addr = destaddr
|
||||||
self.sendall(("CONNECT " + addr + ":" + str(destport) + " HTTP/1.1\r\n" + "Host: " + destaddr + "\r\n\r\n").encode())
|
self.sendall(''.join([
|
||||||
|
"CONNECT ",
|
||||||
|
addr,
|
||||||
|
":",
|
||||||
|
str(destport),
|
||||||
|
" HTTP/1.1\r\n",
|
||||||
|
"Host: ",
|
||||||
|
destaddr,
|
||||||
|
"\r\n\r\n",
|
||||||
|
]).encode())
|
||||||
# We read the response until we get the string "\r\n\r\n"
|
# We read the response until we get the string "\r\n\r\n"
|
||||||
resp = self.recv(1)
|
resp = self.recv(1)
|
||||||
while resp.find("\r\n\r\n".encode()) == -1:
|
while resp.find("\r\n\r\n".encode()) == -1:
|
||||||
|
@ -396,10 +437,15 @@ class socksocket(socket.socket):
|
||||||
To select the proxy server use setproxy().
|
To select the proxy server use setproxy().
|
||||||
"""
|
"""
|
||||||
# Do a minimal input check first
|
# Do a minimal input check first
|
||||||
if (not type(destpair) in (list,tuple)) or (len(destpair) < 2) or (type(destpair[0]) != type('')) or (type(destpair[1]) != int):
|
if any([
|
||||||
|
not isinstance(destpair, (list, tuple)),
|
||||||
|
len(destpair) < 2,
|
||||||
|
not isinstance(destpair[0], type('')),
|
||||||
|
not isinstance(destpair[1], int),
|
||||||
|
]):
|
||||||
raise GeneralProxyError((5, _generalerrors[5]))
|
raise GeneralProxyError((5, _generalerrors[5]))
|
||||||
if self.__proxy[0] == PROXY_TYPE_SOCKS5:
|
if self.__proxy[0] == PROXY_TYPE_SOCKS5:
|
||||||
if self.__proxy[2] != None:
|
if self.__proxy[2] is not None:
|
||||||
portnum = self.__proxy[2]
|
portnum = self.__proxy[2]
|
||||||
else:
|
else:
|
||||||
portnum = 1080
|
portnum = 1080
|
||||||
|
@ -419,14 +465,14 @@ class socksocket(socket.socket):
|
||||||
self.__negotiatesocks5()
|
self.__negotiatesocks5()
|
||||||
self.__connectsocks5(destpair[0], destpair[1])
|
self.__connectsocks5(destpair[0], destpair[1])
|
||||||
elif self.__proxy[0] == PROXY_TYPE_SOCKS4:
|
elif self.__proxy[0] == PROXY_TYPE_SOCKS4:
|
||||||
if self.__proxy[2] != None:
|
if self.__proxy[2] is not None:
|
||||||
portnum = self.__proxy[2]
|
portnum = self.__proxy[2]
|
||||||
else:
|
else:
|
||||||
portnum = 1080
|
portnum = 1080
|
||||||
_orgsocket.connect(self, (self.__proxy[1], portnum))
|
_orgsocket.connect(self, (self.__proxy[1], portnum))
|
||||||
self.__negotiatesocks4(destpair[0], destpair[1])
|
self.__negotiatesocks4(destpair[0], destpair[1])
|
||||||
elif self.__proxy[0] == PROXY_TYPE_HTTP:
|
elif self.__proxy[0] == PROXY_TYPE_HTTP:
|
||||||
if self.__proxy[2] != None:
|
if self.__proxy[2] is not None:
|
||||||
portnum = self.__proxy[2]
|
portnum = self.__proxy[2]
|
||||||
else:
|
else:
|
||||||
portnum = 8080
|
portnum = 8080
|
||||||
|
@ -444,14 +490,15 @@ class socksocket(socket.socket):
|
||||||
raise GeneralProxyError((9, _generalerrors[9]))
|
raise GeneralProxyError((9, _generalerrors[9]))
|
||||||
raise
|
raise
|
||||||
self.__negotiatehttp(destpair[0], destpair[1])
|
self.__negotiatehttp(destpair[0], destpair[1])
|
||||||
elif self.__proxy[0] == None:
|
elif self.__proxy[0] is None:
|
||||||
_orgsocket.connect(self, (destpair[0], destpair[1]))
|
_orgsocket.connect(self, (destpair[0], destpair[1]))
|
||||||
else:
|
else:
|
||||||
raise GeneralProxyError((4, _generalerrors[4]))
|
raise GeneralProxyError((4, _generalerrors[4]))
|
||||||
|
|
||||||
def resolve(self, host):
|
def resolve(self, host):
|
||||||
|
"""TBC"""
|
||||||
if self.__proxy[0] == PROXY_TYPE_SOCKS5:
|
if self.__proxy[0] == PROXY_TYPE_SOCKS5:
|
||||||
if self.__proxy[2] != None:
|
if self.__proxy[2] is not None:
|
||||||
portnum = self.__proxy[2]
|
portnum = self.__proxy[2]
|
||||||
else:
|
else:
|
||||||
portnum = 1080
|
portnum = 1080
|
||||||
|
|
106
src/upnp.py
106
src/upnp.py
|
@ -1,21 +1,33 @@
|
||||||
# A simple upnp module to forward port for BitMessage
|
# pylint: disable=too-many-statements,too-many-branches,protected-access,no-self-use
|
||||||
# Reference: http://mattscodecave.com/posts/using-python-and-upnp-to-forward-a-port
|
"""
|
||||||
|
A simple upnp module to forward port for BitMessage
|
||||||
|
Reference: http://mattscodecave.com/posts/using-python-and-upnp-to-forward-a-port
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import absolute_import
|
||||||
|
|
||||||
import httplib
|
import httplib
|
||||||
from random import randint
|
from random import randint
|
||||||
import socket
|
import socket
|
||||||
from struct import unpack, pack
|
from struct import unpack
|
||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
|
import urllib2
|
||||||
|
from urlparse import urlparse
|
||||||
|
from xml.dom.minidom import Document, parseString
|
||||||
|
|
||||||
from bmconfigparser import BMConfigParser
|
from bmconfigparser import BMConfigParser
|
||||||
|
from debug import logger
|
||||||
from network.connectionpool import BMConnectionPool
|
from network.connectionpool import BMConnectionPool
|
||||||
from helper_threading import *
|
from helper_threading import StoppableThread
|
||||||
import queues
|
import queues
|
||||||
import shared
|
import shared
|
||||||
import state
|
import state
|
||||||
import tr
|
import tr
|
||||||
|
|
||||||
|
|
||||||
def createRequestXML(service, action, arguments=None):
|
def createRequestXML(service, action, arguments=None):
|
||||||
from xml.dom.minidom import Document
|
"""Router UPnP requests are XML formatted"""
|
||||||
|
|
||||||
doc = Document()
|
doc = Document()
|
||||||
|
|
||||||
|
@ -63,11 +75,17 @@ def createRequestXML(service, action, arguments=None):
|
||||||
# our tree is ready, conver it to a string
|
# our tree is ready, conver it to a string
|
||||||
return doc.toxml()
|
return doc.toxml()
|
||||||
|
|
||||||
class UPnPError(Exception):
|
|
||||||
def __init__(self, message):
|
|
||||||
self.message
|
|
||||||
|
|
||||||
class Router:
|
class UPnPError(Exception):
|
||||||
|
"""Handle a UPnP error"""
|
||||||
|
|
||||||
|
def __init__(self, message):
|
||||||
|
super(UPnPError, self).__init__()
|
||||||
|
logger.error(message)
|
||||||
|
|
||||||
|
|
||||||
|
class Router: # pylint: disable=old-style-class
|
||||||
|
"""TBC"""
|
||||||
name = ""
|
name = ""
|
||||||
path = ""
|
path = ""
|
||||||
address = None
|
address = None
|
||||||
|
@ -75,10 +93,6 @@ class Router:
|
||||||
extPort = None
|
extPort = None
|
||||||
|
|
||||||
def __init__(self, ssdpResponse, address):
|
def __init__(self, ssdpResponse, address):
|
||||||
import urllib2
|
|
||||||
from xml.dom.minidom import parseString
|
|
||||||
from urlparse import urlparse
|
|
||||||
from debug import logger
|
|
||||||
|
|
||||||
self.address = address
|
self.address = address
|
||||||
|
|
||||||
|
@ -112,8 +126,18 @@ class Router:
|
||||||
self.path = service.parentNode.getElementsByTagName('controlURL')[0].childNodes[0].data
|
self.path = service.parentNode.getElementsByTagName('controlURL')[0].childNodes[0].data
|
||||||
self.upnp_schema = service.childNodes[0].data.split(':')[-2]
|
self.upnp_schema = service.childNodes[0].data.split(':')[-2]
|
||||||
|
|
||||||
def AddPortMapping(self, externalPort, internalPort, internalClient, protocol, description, leaseDuration = 0, enabled = 1):
|
def AddPortMapping(
|
||||||
from debug import logger
|
self,
|
||||||
|
externalPort,
|
||||||
|
internalPort,
|
||||||
|
internalClient,
|
||||||
|
protocol,
|
||||||
|
description,
|
||||||
|
leaseDuration=0,
|
||||||
|
enabled=1,
|
||||||
|
): # pylint: disable=too-many-arguments
|
||||||
|
"""Add UPnP port mapping"""
|
||||||
|
|
||||||
resp = self.soapRequest(self.upnp_schema + ':1', 'AddPortMapping', [
|
resp = self.soapRequest(self.upnp_schema + ':1', 'AddPortMapping', [
|
||||||
('NewRemoteHost', ''),
|
('NewRemoteHost', ''),
|
||||||
('NewExternalPort', str(externalPort)),
|
('NewExternalPort', str(externalPort)),
|
||||||
|
@ -125,11 +149,13 @@ class Router:
|
||||||
('NewLeaseDuration', str(leaseDuration))
|
('NewLeaseDuration', str(leaseDuration))
|
||||||
])
|
])
|
||||||
self.extPort = externalPort
|
self.extPort = externalPort
|
||||||
logger.info("Successfully established UPnP mapping for %s:%i on external port %i", internalClient, internalPort, externalPort)
|
logger.info("Successfully established UPnP mapping for %s:%i on external port %i",
|
||||||
|
internalClient, internalPort, externalPort)
|
||||||
return resp
|
return resp
|
||||||
|
|
||||||
def DeletePortMapping(self, externalPort, protocol):
|
def DeletePortMapping(self, externalPort, protocol):
|
||||||
from debug import logger
|
"""Delete UPnP port mapping"""
|
||||||
|
|
||||||
resp = self.soapRequest(self.upnp_schema + ':1', 'DeletePortMapping', [
|
resp = self.soapRequest(self.upnp_schema + ':1', 'DeletePortMapping', [
|
||||||
('NewRemoteHost', ''),
|
('NewRemoteHost', ''),
|
||||||
('NewExternalPort', str(externalPort)),
|
('NewExternalPort', str(externalPort)),
|
||||||
|
@ -139,14 +165,15 @@ class Router:
|
||||||
return resp
|
return resp
|
||||||
|
|
||||||
def GetExternalIPAddress(self):
|
def GetExternalIPAddress(self):
|
||||||
from xml.dom.minidom import parseString
|
"""Get the external address"""
|
||||||
|
|
||||||
resp = self.soapRequest(self.upnp_schema + ':1', 'GetExternalIPAddress')
|
resp = self.soapRequest(self.upnp_schema + ':1', 'GetExternalIPAddress')
|
||||||
dom = parseString(resp)
|
dom = parseString(resp)
|
||||||
return dom.getElementsByTagName('NewExternalIPAddress')[0].childNodes[0].data
|
return dom.getElementsByTagName('NewExternalIPAddress')[0].childNodes[0].data
|
||||||
|
|
||||||
def soapRequest(self, service, action, arguments=None):
|
def soapRequest(self, service, action, arguments=None):
|
||||||
from xml.dom.minidom import parseString
|
"""Make a request to a router"""
|
||||||
from debug import logger
|
|
||||||
conn = httplib.HTTPConnection(self.routerPath.hostname, self.routerPath.port)
|
conn = httplib.HTTPConnection(self.routerPath.hostname, self.routerPath.port)
|
||||||
conn.request(
|
conn.request(
|
||||||
'POST',
|
'POST',
|
||||||
|
@ -164,14 +191,17 @@ class Router:
|
||||||
try:
|
try:
|
||||||
dom = parseString(respData)
|
dom = parseString(respData)
|
||||||
errinfo = dom.getElementsByTagName('errorDescription')
|
errinfo = dom.getElementsByTagName('errorDescription')
|
||||||
if len(errinfo) > 0:
|
if errinfo:
|
||||||
logger.error("UPnP error: %s", respData)
|
logger.error("UPnP error: %s", respData)
|
||||||
raise UPnPError(errinfo[0].childNodes[0].data)
|
raise UPnPError(errinfo[0].childNodes[0].data)
|
||||||
except:
|
except:
|
||||||
raise UPnPError("Unable to parse SOAP error: %s" % (respData))
|
raise UPnPError("Unable to parse SOAP error: %s" % (respData))
|
||||||
return resp
|
return resp
|
||||||
|
|
||||||
|
|
||||||
class uPnPThread(threading.Thread, StoppableThread):
|
class uPnPThread(threading.Thread, StoppableThread):
|
||||||
|
"""Start a thread to handle UPnP activity"""
|
||||||
|
|
||||||
SSDP_ADDR = "239.255.255.250"
|
SSDP_ADDR = "239.255.255.250"
|
||||||
GOOGLE_DNS = "8.8.8.8"
|
GOOGLE_DNS = "8.8.8.8"
|
||||||
SSDP_PORT = 1900
|
SSDP_PORT = 1900
|
||||||
|
@ -194,7 +224,7 @@ class uPnPThread(threading.Thread, StoppableThread):
|
||||||
self.initStop()
|
self.initStop()
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
from debug import logger
|
"""Start the thread to manage UPnP activity"""
|
||||||
|
|
||||||
logger.debug("Starting UPnP thread")
|
logger.debug("Starting UPnP thread")
|
||||||
logger.debug("Local IP: %s", self.localIP)
|
logger.debug("Local IP: %s", self.localIP)
|
||||||
|
@ -209,9 +239,11 @@ class uPnPThread(threading.Thread, StoppableThread):
|
||||||
if not bound:
|
if not bound:
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
|
|
||||||
|
# pylint: disable=attribute-defined-outside-init
|
||||||
self.localPort = BMConfigParser().getint('bitmessagesettings', 'port')
|
self.localPort = BMConfigParser().getint('bitmessagesettings', 'port')
|
||||||
|
|
||||||
while state.shutdown == 0 and BMConfigParser().safeGetBoolean('bitmessagesettings', 'upnp'):
|
while state.shutdown == 0 and BMConfigParser().safeGetBoolean('bitmessagesettings', 'upnp'):
|
||||||
if time.time() - lastSent > self.sendSleep and len(self.routers) == 0:
|
if time.time() - lastSent > self.sendSleep and not self.routers:
|
||||||
try:
|
try:
|
||||||
self.sendSearchRouter()
|
self.sendSearchRouter()
|
||||||
except:
|
except:
|
||||||
|
@ -219,7 +251,7 @@ class uPnPThread(threading.Thread, StoppableThread):
|
||||||
lastSent = time.time()
|
lastSent = time.time()
|
||||||
try:
|
try:
|
||||||
while state.shutdown == 0 and BMConfigParser().safeGetBoolean('bitmessagesettings', 'upnp'):
|
while state.shutdown == 0 and BMConfigParser().safeGetBoolean('bitmessagesettings', 'upnp'):
|
||||||
resp,(ip,port) = self.sock.recvfrom(1000)
|
resp, (ip, _) = self.sock.recvfrom(1000)
|
||||||
if resp is None:
|
if resp is None:
|
||||||
continue
|
continue
|
||||||
newRouter = Router(resp, ip)
|
newRouter = Router(resp, ip)
|
||||||
|
@ -230,14 +262,16 @@ class uPnPThread(threading.Thread, StoppableThread):
|
||||||
logger.debug("Found UPnP router at %s", ip)
|
logger.debug("Found UPnP router at %s", ip)
|
||||||
self.routers.append(newRouter)
|
self.routers.append(newRouter)
|
||||||
self.createPortMapping(newRouter)
|
self.createPortMapping(newRouter)
|
||||||
queues.UISignalQueue.put(('updateStatusBar', tr._translate("MainWindow",'UPnP port mapping established on port %1').arg(str(self.extPort))))
|
queues.UISignalQueue.put(('updateStatusBar', tr._translate(
|
||||||
|
"MainWindow", 'UPnP port mapping established on port %1'
|
||||||
|
).arg(str(self.extPort))))
|
||||||
# retry connections so that the submitted port is refreshed
|
# retry connections so that the submitted port is refreshed
|
||||||
with shared.alreadyAttemptedConnectionsListLock:
|
with shared.alreadyAttemptedConnectionsListLock:
|
||||||
shared.alreadyAttemptedConnectionsList.clear()
|
shared.alreadyAttemptedConnectionsList.clear()
|
||||||
shared.alreadyAttemptedConnectionsListResetTime = int(
|
shared.alreadyAttemptedConnectionsListResetTime = int(
|
||||||
time.time())
|
time.time())
|
||||||
break
|
break
|
||||||
except socket.timeout as e:
|
except socket.timeout:
|
||||||
pass
|
pass
|
||||||
except:
|
except:
|
||||||
logger.error("Failure running UPnP router search.", exc_info=True)
|
logger.error("Failure running UPnP router search.", exc_info=True)
|
||||||
|
@ -263,13 +297,16 @@ class uPnPThread(threading.Thread, StoppableThread):
|
||||||
logger.debug("UPnP thread done")
|
logger.debug("UPnP thread done")
|
||||||
|
|
||||||
def getLocalIP(self):
|
def getLocalIP(self):
|
||||||
|
"""Get the local IP of the node"""
|
||||||
|
|
||||||
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||||
s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
|
s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
|
||||||
s.connect((uPnPThread.GOOGLE_DNS, 1))
|
s.connect((uPnPThread.GOOGLE_DNS, 1))
|
||||||
return s.getsockname()[0]
|
return s.getsockname()[0]
|
||||||
|
|
||||||
def sendSearchRouter(self):
|
def sendSearchRouter(self):
|
||||||
from debug import logger
|
"""Querying for UPnP services"""
|
||||||
|
|
||||||
ssdpRequest = "M-SEARCH * HTTP/1.1\r\n" + \
|
ssdpRequest = "M-SEARCH * HTTP/1.1\r\n" + \
|
||||||
"HOST: %s:%d\r\n" % (uPnPThread.SSDP_ADDR, uPnPThread.SSDP_PORT) + \
|
"HOST: %s:%d\r\n" % (uPnPThread.SSDP_ADDR, uPnPThread.SSDP_PORT) + \
|
||||||
"MAN: \"ssdp:discover\"\r\n" + \
|
"MAN: \"ssdp:discover\"\r\n" + \
|
||||||
|
@ -283,11 +320,11 @@ class uPnPThread(threading.Thread, StoppableThread):
|
||||||
logger.exception("UPnP send query failed")
|
logger.exception("UPnP send query failed")
|
||||||
|
|
||||||
def createPortMapping(self, router):
|
def createPortMapping(self, router):
|
||||||
from debug import logger
|
"""Add a port mapping"""
|
||||||
|
|
||||||
for i in range(50):
|
for i in range(50):
|
||||||
try:
|
try:
|
||||||
routerIP, = unpack('>I', socket.inet_aton(router.address))
|
_, = unpack('>I', socket.inet_aton(router.address))
|
||||||
localIP = self.localIP
|
localIP = self.localIP
|
||||||
if i == 0:
|
if i == 0:
|
||||||
extPort = self.localPort # try same port first
|
extPort = self.localPort # try same port first
|
||||||
|
@ -295,7 +332,12 @@ class uPnPThread(threading.Thread, StoppableThread):
|
||||||
extPort = self.extPort # try external port from last time next
|
extPort = self.extPort # try external port from last time next
|
||||||
else:
|
else:
|
||||||
extPort = randint(32767, 65535)
|
extPort = randint(32767, 65535)
|
||||||
logger.debug("Attempt %i, requesting UPnP mapping for %s:%i on external port %i", i, localIP, self.localPort, extPort)
|
logger.debug(
|
||||||
|
"Attempt %i, requesting UPnP mapping for %s:%i on external port %i",
|
||||||
|
i,
|
||||||
|
localIP,
|
||||||
|
self.localPort,
|
||||||
|
extPort)
|
||||||
router.AddPortMapping(extPort, self.localPort, localIP, 'TCP', 'BitMessage')
|
router.AddPortMapping(extPort, self.localPort, localIP, 'TCP', 'BitMessage')
|
||||||
shared.extPort = extPort
|
shared.extPort = extPort
|
||||||
self.extPort = extPort
|
self.extPort = extPort
|
||||||
|
@ -306,7 +348,5 @@ class uPnPThread(threading.Thread, StoppableThread):
|
||||||
logger.debug("UPnP error: ", exc_info=True)
|
logger.debug("UPnP error: ", exc_info=True)
|
||||||
|
|
||||||
def deletePortMapping(self, router):
|
def deletePortMapping(self, router):
|
||||||
|
"""Delete a port mapping"""
|
||||||
router.DeletePortMapping(router.extPort, 'TCP')
|
router.DeletePortMapping(router.extPort, 'TCP')
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
Reference in New Issue
Block a user
Why?
In the wrong order: Continued in PR#1271