allowing for max connection configuration #939

Closed
ghost wants to merge 6 commits from maxconnection-config into v0.6
51 changed files with 1886 additions and 1490 deletions
Showing only changes of commit 12f1e9f505 - Show all commits

3
build/compiletest.py Normal file → Executable file
View File

@ -16,5 +16,8 @@ for filename in matches:
try: try:
compile(source, filename, 'exec') compile(source, filename, 'exec')
except Exception as e: except Exception as e:
if 'win' in sys.platform:
ctypes.windll.user32.MessageBoxA(0, traceback.format_exc(), "Exception in " + filename, 1) ctypes.windll.user32.MessageBoxA(0, traceback.format_exc(), "Exception in " + filename, 1)
else:
print "Exception in %s: %s" % (filename, traceback.format_exc())
sys.exit(1) sys.exit(1)

View File

@ -19,16 +19,21 @@ from binascii import hexlify
import shared import shared
import time import time
from addresses import decodeAddress,addBMIfNotPresent,decodeVarint,calculateInventoryHash,varintDecodeError from addresses import decodeAddress,addBMIfNotPresent,decodeVarint,calculateInventoryHash,varintDecodeError
from configparser import BMConfigParser
import helper_inbox import helper_inbox
import helper_sent import helper_sent
import hashlib import hashlib
import protocol
import state
from pyelliptic.openssl import OpenSSL from pyelliptic.openssl import OpenSSL
from struct import pack from struct import pack
# Classes # Classes
from helper_sql import sqlQuery,sqlExecute,SqlBulkExecute,sqlStoredProcedure from helper_sql import sqlQuery,sqlExecute,SqlBulkExecute,sqlStoredProcedure
from debug import logger from debug import logger
from inventory import Inventory
from version import softwareVersion
# Helper Functions # Helper Functions
import proofofwork import proofofwork
@ -119,7 +124,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
# handle Basic authentication # handle Basic authentication
(enctype, encstr) = self.headers.get('Authorization').split() (enctype, encstr) = self.headers.get('Authorization').split()
(emailid, password) = encstr.decode('base64').split(':') (emailid, password) = encstr.decode('base64').split(':')
if emailid == shared.config.get('bitmessagesettings', 'apiusername') and password == shared.config.get('bitmessagesettings', 'apipassword'): if emailid == BMConfigParser().get('bitmessagesettings', 'apiusername') and password == BMConfigParser().get('bitmessagesettings', 'apipassword'):
return True return True
else: else:
return False return False
@ -162,22 +167,22 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
def HandleListAddresses(self, method): def HandleListAddresses(self, method):
data = '{"addresses":[' data = '{"addresses":['
configSections = shared.config.sections() configSections = BMConfigParser().sections()
for addressInKeysFile in configSections: for addressInKeysFile in configSections:
if addressInKeysFile != 'bitmessagesettings': if addressInKeysFile != 'bitmessagesettings':
status, addressVersionNumber, streamNumber, hash01 = decodeAddress( status, addressVersionNumber, streamNumber, hash01 = decodeAddress(
addressInKeysFile) addressInKeysFile)
if len(data) > 20: if len(data) > 20:
data += ',' data += ','
if shared.config.has_option(addressInKeysFile, 'chan'): if BMConfigParser().has_option(addressInKeysFile, 'chan'):
chan = shared.config.getboolean(addressInKeysFile, 'chan') chan = BMConfigParser().getboolean(addressInKeysFile, 'chan')
else: else:
chan = False chan = False
label = shared.config.get(addressInKeysFile, 'label') label = BMConfigParser().get(addressInKeysFile, 'label')
if method == 'listAddresses2': if method == 'listAddresses2':
label = label.encode('base64') label = label.encode('base64')
data += json.dumps({'label': label, 'address': addressInKeysFile, 'stream': data += json.dumps({'label': label, 'address': addressInKeysFile, 'stream':
streamNumber, 'enabled': shared.config.getboolean(addressInKeysFile, 'enabled'), 'chan': chan}, indent=4, separators=(',', ': ')) streamNumber, 'enabled': BMConfigParser().getboolean(addressInKeysFile, 'enabled'), 'chan': chan}, indent=4, separators=(',', ': '))
data += ']}' data += ']}'
return data return data
@ -235,28 +240,28 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
elif len(params) == 1: elif len(params) == 1:
label, = params label, = params
eighteenByteRipe = False eighteenByteRipe = False
nonceTrialsPerByte = shared.config.get( nonceTrialsPerByte = BMConfigParser().get(
'bitmessagesettings', 'defaultnoncetrialsperbyte') 'bitmessagesettings', 'defaultnoncetrialsperbyte')
payloadLengthExtraBytes = shared.config.get( payloadLengthExtraBytes = BMConfigParser().get(
'bitmessagesettings', 'defaultpayloadlengthextrabytes') 'bitmessagesettings', 'defaultpayloadlengthextrabytes')
elif len(params) == 2: elif len(params) == 2:
label, eighteenByteRipe = params label, eighteenByteRipe = params
nonceTrialsPerByte = shared.config.get( nonceTrialsPerByte = BMConfigParser().get(
'bitmessagesettings', 'defaultnoncetrialsperbyte') 'bitmessagesettings', 'defaultnoncetrialsperbyte')
payloadLengthExtraBytes = shared.config.get( payloadLengthExtraBytes = BMConfigParser().get(
'bitmessagesettings', 'defaultpayloadlengthextrabytes') 'bitmessagesettings', 'defaultpayloadlengthextrabytes')
elif len(params) == 3: elif len(params) == 3:
label, eighteenByteRipe, totalDifficulty = params label, eighteenByteRipe, totalDifficulty = params
nonceTrialsPerByte = int( nonceTrialsPerByte = int(
shared.networkDefaultProofOfWorkNonceTrialsPerByte * totalDifficulty) protocol.networkDefaultProofOfWorkNonceTrialsPerByte * totalDifficulty)
payloadLengthExtraBytes = shared.config.get( payloadLengthExtraBytes = BMConfigParser().get(
'bitmessagesettings', 'defaultpayloadlengthextrabytes') 'bitmessagesettings', 'defaultpayloadlengthextrabytes')
elif len(params) == 4: elif len(params) == 4:
label, eighteenByteRipe, totalDifficulty, smallMessageDifficulty = params label, eighteenByteRipe, totalDifficulty, smallMessageDifficulty = params
nonceTrialsPerByte = int( nonceTrialsPerByte = int(
shared.networkDefaultProofOfWorkNonceTrialsPerByte * totalDifficulty) protocol.networkDefaultProofOfWorkNonceTrialsPerByte * totalDifficulty)
payloadLengthExtraBytes = int( payloadLengthExtraBytes = int(
shared.networkDefaultPayloadLengthExtraBytes * smallMessageDifficulty) protocol.networkDefaultPayloadLengthExtraBytes * 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")
@ -279,52 +284,52 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
addressVersionNumber = 0 addressVersionNumber = 0
streamNumber = 0 streamNumber = 0
eighteenByteRipe = False eighteenByteRipe = False
nonceTrialsPerByte = shared.config.get( nonceTrialsPerByte = BMConfigParser().get(
'bitmessagesettings', 'defaultnoncetrialsperbyte') 'bitmessagesettings', 'defaultnoncetrialsperbyte')
payloadLengthExtraBytes = shared.config.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
streamNumber = 0 streamNumber = 0
eighteenByteRipe = False eighteenByteRipe = False
nonceTrialsPerByte = shared.config.get( nonceTrialsPerByte = BMConfigParser().get(
'bitmessagesettings', 'defaultnoncetrialsperbyte') 'bitmessagesettings', 'defaultnoncetrialsperbyte')
payloadLengthExtraBytes = shared.config.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
eighteenByteRipe = False eighteenByteRipe = False
nonceTrialsPerByte = shared.config.get( nonceTrialsPerByte = BMConfigParser().get(
'bitmessagesettings', 'defaultnoncetrialsperbyte') 'bitmessagesettings', 'defaultnoncetrialsperbyte')
payloadLengthExtraBytes = shared.config.get( payloadLengthExtraBytes = BMConfigParser().get(
'bitmessagesettings', 'defaultpayloadlengthextrabytes') 'bitmessagesettings', 'defaultpayloadlengthextrabytes')
elif len(params) == 4: elif len(params) == 4:
passphrase, numberOfAddresses, addressVersionNumber, streamNumber = params passphrase, numberOfAddresses, addressVersionNumber, streamNumber = params
eighteenByteRipe = False eighteenByteRipe = False
nonceTrialsPerByte = shared.config.get( nonceTrialsPerByte = BMConfigParser().get(
'bitmessagesettings', 'defaultnoncetrialsperbyte') 'bitmessagesettings', 'defaultnoncetrialsperbyte')
payloadLengthExtraBytes = shared.config.get( payloadLengthExtraBytes = BMConfigParser().get(
'bitmessagesettings', 'defaultpayloadlengthextrabytes') 'bitmessagesettings', 'defaultpayloadlengthextrabytes')
elif len(params) == 5: elif len(params) == 5:
passphrase, numberOfAddresses, addressVersionNumber, streamNumber, eighteenByteRipe = params passphrase, numberOfAddresses, addressVersionNumber, streamNumber, eighteenByteRipe = params
nonceTrialsPerByte = shared.config.get( nonceTrialsPerByte = BMConfigParser().get(
'bitmessagesettings', 'defaultnoncetrialsperbyte') 'bitmessagesettings', 'defaultnoncetrialsperbyte')
payloadLengthExtraBytes = shared.config.get( payloadLengthExtraBytes = BMConfigParser().get(
'bitmessagesettings', 'defaultpayloadlengthextrabytes') 'bitmessagesettings', 'defaultpayloadlengthextrabytes')
elif len(params) == 6: elif len(params) == 6:
passphrase, numberOfAddresses, addressVersionNumber, streamNumber, eighteenByteRipe, totalDifficulty = params passphrase, numberOfAddresses, addressVersionNumber, streamNumber, eighteenByteRipe, totalDifficulty = params
nonceTrialsPerByte = int( nonceTrialsPerByte = int(
shared.networkDefaultProofOfWorkNonceTrialsPerByte * totalDifficulty) protocol.networkDefaultProofOfWorkNonceTrialsPerByte * totalDifficulty)
payloadLengthExtraBytes = shared.config.get( payloadLengthExtraBytes = BMConfigParser().get(
'bitmessagesettings', 'defaultpayloadlengthextrabytes') 'bitmessagesettings', 'defaultpayloadlengthextrabytes')
elif len(params) == 7: elif len(params) == 7:
passphrase, numberOfAddresses, addressVersionNumber, streamNumber, eighteenByteRipe, totalDifficulty, smallMessageDifficulty = params passphrase, numberOfAddresses, addressVersionNumber, streamNumber, eighteenByteRipe, totalDifficulty, smallMessageDifficulty = params
nonceTrialsPerByte = int( nonceTrialsPerByte = int(
shared.networkDefaultProofOfWorkNonceTrialsPerByte * totalDifficulty) protocol.networkDefaultProofOfWorkNonceTrialsPerByte * totalDifficulty)
payloadLengthExtraBytes = int( payloadLengthExtraBytes = int(
shared.networkDefaultPayloadLengthExtraBytes * smallMessageDifficulty) protocol.networkDefaultPayloadLengthExtraBytes * smallMessageDifficulty)
else: else:
raise APIError(0, 'Too many parameters!') raise APIError(0, 'Too many parameters!')
if len(passphrase) == 0: if len(passphrase) == 0:
@ -442,13 +447,13 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
address, = params address, = params
status, addressVersionNumber, streamNumber, toRipe = self._verifyAddress(address) status, addressVersionNumber, streamNumber, toRipe = self._verifyAddress(address)
address = addBMIfNotPresent(address) address = addBMIfNotPresent(address)
if not shared.config.has_section(address): if not BMConfigParser().has_section(address):
raise APIError(13, 'Could not find this address in your keys.dat file.') raise APIError(13, 'Could not find this address in your keys.dat file.')
if not shared.safeConfigGetBoolean(address, 'chan'): if not BMConfigParser().safeGetBoolean(address, 'chan'):
raise APIError(25, 'Specified address is not a chan address. Use deleteAddress API call instead.') raise APIError(25, 'Specified address is not a chan address. Use deleteAddress API call instead.')
shared.config.remove_section(address) BMConfigParser().remove_section(address)
with open(shared.appdata + 'keys.dat', 'wb') as configfile: with open(state.appdata + 'keys.dat', 'wb') as configfile:
shared.config.write(configfile) BMConfigParser().write(configfile)
return 'success' return 'success'
def HandleDeleteAddress(self, params): def HandleDeleteAddress(self, params):
@ -458,11 +463,11 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
address, = params address, = params
status, addressVersionNumber, streamNumber, toRipe = self._verifyAddress(address) status, addressVersionNumber, streamNumber, toRipe = self._verifyAddress(address)
address = addBMIfNotPresent(address) address = addBMIfNotPresent(address)
if not shared.config.has_section(address): if not BMConfigParser().has_section(address):
raise APIError(13, 'Could not find this address in your keys.dat file.') raise APIError(13, 'Could not find this address in your keys.dat file.')
shared.config.remove_section(address) BMConfigParser().remove_section(address)
with open(shared.appdata + 'keys.dat', 'wb') as configfile: with open(state.appdata + 'keys.dat', 'wb') as configfile:
shared.config.write(configfile) BMConfigParser().write(configfile)
shared.UISignalQueue.put(('rerenderMessagelistFromLabels','')) shared.UISignalQueue.put(('rerenderMessagelistFromLabels',''))
shared.UISignalQueue.put(('rerenderMessagelistToLabels','')) shared.UISignalQueue.put(('rerenderMessagelistToLabels',''))
shared.reloadMyAddressHashes() shared.reloadMyAddressHashes()
@ -658,7 +663,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
status, addressVersionNumber, streamNumber, toRipe = self._verifyAddress(toAddress) status, addressVersionNumber, streamNumber, toRipe = self._verifyAddress(toAddress)
self._verifyAddress(fromAddress) self._verifyAddress(fromAddress)
try: try:
fromAddressEnabled = shared.config.getboolean( fromAddressEnabled = BMConfigParser().getboolean(
fromAddress, 'enabled') fromAddress, 'enabled')
except: except:
raise APIError(13, 'Could not find your fromAddress in the keys.dat file.') raise APIError(13, 'Could not find your fromAddress in the keys.dat file.')
@ -722,7 +727,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
fromAddress = addBMIfNotPresent(fromAddress) fromAddress = addBMIfNotPresent(fromAddress)
self._verifyAddress(fromAddress) self._verifyAddress(fromAddress)
try: try:
fromAddressEnabled = shared.config.getboolean( fromAddressEnabled = BMConfigParser().getboolean(
fromAddress, 'enabled') fromAddress, 'enabled')
except: except:
raise APIError(13, 'could not find your fromAddress in the keys.dat file.') raise APIError(13, 'could not find your fromAddress in the keys.dat file.')
@ -834,7 +839,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
# 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 / ((len(encryptedPayload)+requiredPayloadLengthExtraBytes+8) * requiredAverageProofOfWorkNonceTrialsPerByte) target = 2**64 / ((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) / shared.networkDefaultProofOfWorkNonceTrialsPerByte, 'Required small message difficulty:', float(requiredPayloadLengthExtraBytes) / shared.networkDefaultPayloadLengthExtraBytes print '(For msg message via API) Doing proof of work. Total required difficulty:', float(requiredAverageProofOfWorkNonceTrialsPerByte) / protocol.networkDefaultProofOfWorkNonceTrialsPerByte, 'Required small message difficulty:', float(requiredPayloadLengthExtraBytes) / protocol.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)
@ -849,11 +854,11 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
inventoryHash = calculateInventoryHash(encryptedPayload) inventoryHash = calculateInventoryHash(encryptedPayload)
objectType = 2 objectType = 2
TTL = 2.5 * 24 * 60 * 60 TTL = 2.5 * 24 * 60 * 60
shared.inventory[inventoryHash] = ( Inventory()[inventoryHash] = (
objectType, toStreamNumber, encryptedPayload, int(time.time()) + TTL,'') objectType, toStreamNumber, encryptedPayload, int(time.time()) + TTL,'')
with shared.printLock: with shared.printLock:
print 'Broadcasting inv for msg(API disseminatePreEncryptedMsg command):', hexlify(inventoryHash) print 'Broadcasting inv for msg(API disseminatePreEncryptedMsg command):', hexlify(inventoryHash)
shared.broadcastToSendDataQueues(( protocol.broadcastToSendDataQueues((
toStreamNumber, 'advertiseobject', inventoryHash)) toStreamNumber, 'advertiseobject', inventoryHash))
def HandleTrashSentMessageByAckDAta(self, params): def HandleTrashSentMessageByAckDAta(self, params):
@ -876,8 +881,8 @@ 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 / ((len(payload) + shared.networkDefaultPayloadLengthExtraBytes + target = 2 ** 64 / ((len(payload) + protocol.networkDefaultPayloadLengthExtraBytes +
8) * shared.networkDefaultProofOfWorkNonceTrialsPerByte) 8) * protocol.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)
@ -896,11 +901,11 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
objectType = 1 objectType = 1
#todo: support v4 pubkeys #todo: support v4 pubkeys
TTL = 28 * 24 * 60 * 60 TTL = 28 * 24 * 60 * 60
shared.inventory[inventoryHash] = ( Inventory()[inventoryHash] = (
objectType, pubkeyStreamNumber, payload, int(time.time()) + TTL,'') objectType, pubkeyStreamNumber, payload, int(time.time()) + TTL,'')
with shared.printLock: with shared.printLock:
print 'broadcasting inv within API command disseminatePubkey with hash:', hexlify(inventoryHash) print 'broadcasting inv within API command disseminatePubkey with hash:', hexlify(inventoryHash)
shared.broadcastToSendDataQueues(( protocol.broadcastToSendDataQueues((
streamNumber, 'advertiseobject', inventoryHash)) streamNumber, 'advertiseobject', inventoryHash))
def HandleGetMessageDataByDestinationHash(self, params): def HandleGetMessageDataByDestinationHash(self, params):
@ -945,7 +950,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
networkStatus = 'connectedButHaveNotReceivedIncomingConnections' networkStatus = 'connectedButHaveNotReceivedIncomingConnections'
else: else:
networkStatus = 'connectedAndReceivingIncomingConnections' networkStatus = 'connectedAndReceivingIncomingConnections'
return json.dumps({'networkConnections':len(shared.connectedHostsList),'numberOfMessagesProcessed':shared.numberOfMessagesProcessed, 'numberOfBroadcastsProcessed':shared.numberOfBroadcastsProcessed, 'numberOfPubkeysProcessed':shared.numberOfPubkeysProcessed, 'networkStatus':networkStatus, 'softwareName':'PyBitmessage','softwareVersion':shared.softwareVersion}, indent=4, separators=(',', ': ')) return json.dumps({'networkConnections':len(shared.connectedHostsList),'numberOfMessagesProcessed':shared.numberOfMessagesProcessed, 'numberOfBroadcastsProcessed':shared.numberOfBroadcastsProcessed, 'numberOfPubkeysProcessed':shared.numberOfPubkeysProcessed, 'networkStatus':networkStatus, 'softwareName':'PyBitmessage','softwareVersion':softwareVersion}, indent=4, separators=(',', ': '))
def HandleDecodeAddress(self, params): def HandleDecodeAddress(self, params):
# Return a meaningful decoding of an address. # Return a meaningful decoding of an address.

View File

@ -45,16 +45,6 @@ def restartBmNotify(): #Prompts the user to restart Bitmessage.
print ' WARNING: If Bitmessage is running locally, you must restart it now.' print ' WARNING: If Bitmessage is running locally, you must restart it now.'
print ' *******************************************************************\n' print ' *******************************************************************\n'
def safeConfigGetBoolean(section,field):
global keysPath
config = BMConfigParser()
config.read(keysPath)
try:
return config.getboolean(section,field)
except:
return False
#Begin keys.dat interactions #Begin keys.dat interactions
def lookupAppdataFolder(): #gets the appropriate folders for the .dat files depending on the OS. Taken from bitmessagemain.py def lookupAppdataFolder(): #gets the appropriate folders for the .dat files depending on the OS. Taken from bitmessagemain.py
APPNAME = "PyBitmessage" APPNAME = "PyBitmessage"
@ -74,14 +64,13 @@ def lookupAppdataFolder(): #gets the appropriate folders for the .dat files depe
def configInit(): def configInit():
global keysName global keysName
config = BMConfigParser()
config.add_section('bitmessagesettings') BMConfigParser().add_section('bitmessagesettings')
config.set('bitmessagesettings', 'port', '8444') #Sets the bitmessage port to stop the warning about the api not properly being setup. This is in the event that the keys.dat is in a different directory or is created locally to connect to a machine remotely. BMConfigParser().set('bitmessagesettings', 'port', '8444') #Sets the bitmessage port to stop the warning about the api not properly being setup. This is in the event that the keys.dat is in a different directory or is created locally to connect to a machine remotely.
config.set('bitmessagesettings','apienabled','true') #Sets apienabled to true in keys.dat BMConfigParser().set('bitmessagesettings','apienabled','true') #Sets apienabled to true in keys.dat
with open(keysName, 'wb') as configfile: with open(keysName, 'wb') as configfile:
config.write(configfile) BMConfigParser().write(configfile)
print '\n ' + str(keysName) + ' Initalized in the same directory as daemon.py' print '\n ' + str(keysName) + ' Initalized in the same directory as daemon.py'
print ' You will now need to configure the ' + str(keysName) + ' file.\n' print ' You will now need to configure the ' + str(keysName) + ' file.\n'
@ -89,8 +78,7 @@ def configInit():
def apiInit(apiEnabled): def apiInit(apiEnabled):
global keysPath global keysPath
global usrPrompt global usrPrompt
config = BMConfigParser() BMConfigParser().read(keysPath)
config.read(keysPath)
@ -98,9 +86,9 @@ def apiInit(apiEnabled):
uInput = userInput("The API is not enabled. Would you like to do that now, (Y)es or (N)o?").lower() uInput = userInput("The API is not enabled. Would you like to do that now, (Y)es or (N)o?").lower()
if uInput == "y": # if uInput == "y": #
config.set('bitmessagesettings','apienabled','true') #Sets apienabled to true in keys.dat BMConfigParser().set('bitmessagesettings','apienabled','true') #Sets apienabled to true in keys.dat
with open(keysPath, 'wb') as configfile: with open(keysPath, 'wb') as configfile:
config.write(configfile) BMConfigParser().write(configfile)
print 'Done' print 'Done'
restartBmNotify() restartBmNotify()
@ -143,15 +131,15 @@ def apiInit(apiEnabled):
print ' -----------------------------------\n' print ' -----------------------------------\n'
config.set('bitmessagesettings', 'port', '8444') #sets the bitmessage port to stop the warning about the api not properly being setup. This is in the event that the keys.dat is in a different directory or is created locally to connect to a machine remotely. BMConfigParser().set('bitmessagesettings', 'port', '8444') #sets the bitmessage port to stop the warning about the api not properly being setup. This is in the event that the keys.dat is in a different directory or is created locally to connect to a machine remotely.
config.set('bitmessagesettings','apienabled','true') BMConfigParser().set('bitmessagesettings','apienabled','true')
config.set('bitmessagesettings', 'apiport', apiPort) BMConfigParser().set('bitmessagesettings', 'apiport', apiPort)
config.set('bitmessagesettings', 'apiinterface', '127.0.0.1') BMConfigParser().set('bitmessagesettings', 'apiinterface', '127.0.0.1')
config.set('bitmessagesettings', 'apiusername', apiUsr) BMConfigParser().set('bitmessagesettings', 'apiusername', apiUsr)
config.set('bitmessagesettings', 'apipassword', apiPwd) BMConfigParser().set('bitmessagesettings', 'apipassword', apiPwd)
config.set('bitmessagesettings', 'daemon', daemon) BMConfigParser().set('bitmessagesettings', 'daemon', daemon)
with open(keysPath, 'wb') as configfile: with open(keysPath, 'wb') as configfile:
config.write(configfile) BMConfigParser().write(configfile)
print '\n Finished configuring the keys.dat file with API information.\n' print '\n Finished configuring the keys.dat file with API information.\n'
restartBmNotify() restartBmNotify()
@ -174,21 +162,19 @@ def apiData():
global keysPath global keysPath
global usrPrompt global usrPrompt
config = BMConfigParser() BMConfigParser().read(keysPath) #First try to load the config file (the keys.dat file) from the program directory
config.read(keysPath) #First try to load the config file (the keys.dat file) from the program directory
try: try:
config.get('bitmessagesettings','port') BMConfigParser().get('bitmessagesettings','port')
appDataFolder = '' appDataFolder = ''
except: except:
#Could not load the keys.dat file in the program directory. Perhaps it is in the appdata directory. #Could not load the keys.dat file in the program directory. Perhaps it is in the appdata directory.
appDataFolder = lookupAppdataFolder() appDataFolder = lookupAppdataFolder()
keysPath = appDataFolder + keysPath keysPath = appDataFolder + keysPath
config = BMConfigParser() BMConfigParser().read(keysPath)
config.read(keysPath)
try: try:
config.get('bitmessagesettings','port') BMConfigParser().get('bitmessagesettings','port')
except: except:
#keys.dat was not there either, something is wrong. #keys.dat was not there either, something is wrong.
print '\n ******************************************************************' print '\n ******************************************************************'
@ -215,21 +201,21 @@ def apiData():
main() main()
try: #checks to make sure that everyting is configured correctly. Excluding apiEnabled, it is checked after try: #checks to make sure that everyting is configured correctly. Excluding apiEnabled, it is checked after
config.get('bitmessagesettings', 'apiport') BMConfigParser().get('bitmessagesettings', 'apiport')
config.get('bitmessagesettings', 'apiinterface') BMConfigParser().get('bitmessagesettings', 'apiinterface')
config.get('bitmessagesettings', 'apiusername') BMConfigParser().get('bitmessagesettings', 'apiusername')
config.get('bitmessagesettings', 'apipassword') BMConfigParser().get('bitmessagesettings', 'apipassword')
except: except:
apiInit("") #Initalize the keys.dat file with API information apiInit("") #Initalize the keys.dat file with API information
#keys.dat file was found or appropriately configured, allow information retrieval #keys.dat file was found or appropriately configured, allow information retrieval
apiEnabled = apiInit(safeConfigGetBoolean('bitmessagesettings','apienabled')) #if false it will prompt the user, if true it will return true apiEnabled = apiInit(BMConfigParser().safeGetBoolean('bitmessagesettings','apienabled')) #if false it will prompt the user, if true it will return true
config.read(keysPath)#read again since changes have been made BMConfigParser().read(keysPath)#read again since changes have been made
apiPort = int(config.get('bitmessagesettings', 'apiport')) apiPort = int(BMConfigParser().get('bitmessagesettings', 'apiport'))
apiInterface = config.get('bitmessagesettings', 'apiinterface') apiInterface = BMConfigParser().get('bitmessagesettings', 'apiinterface')
apiUsername = config.get('bitmessagesettings', 'apiusername') apiUsername = BMConfigParser().get('bitmessagesettings', 'apiusername')
apiPassword = config.get('bitmessagesettings', 'apipassword') apiPassword = BMConfigParser().get('bitmessagesettings', 'apipassword')
print '\n API data successfully imported.\n' print '\n API data successfully imported.\n'
@ -253,31 +239,30 @@ def apiTest(): #Tests the API connection to bitmessage. Returns true if it is co
def bmSettings(): #Allows the viewing and modification of keys.dat settings. def bmSettings(): #Allows the viewing and modification of keys.dat settings.
global keysPath global keysPath
global usrPrompt global usrPrompt
config = BMConfigParser()
keysPath = 'keys.dat' keysPath = 'keys.dat'
config.read(keysPath)#Read the keys.dat BMConfigParser().read(keysPath)#Read the keys.dat
try: try:
port = config.get('bitmessagesettings', 'port') port = BMConfigParser().get('bitmessagesettings', 'port')
except: except:
print '\n File not found.\n' print '\n File not found.\n'
usrPrompt = 0 usrPrompt = 0
main() main()
startonlogon = safeConfigGetBoolean('bitmessagesettings', 'startonlogon') startonlogon = BMConfigParser().safeGetBoolean('bitmessagesettings', 'startonlogon')
minimizetotray = safeConfigGetBoolean('bitmessagesettings', 'minimizetotray') minimizetotray = BMConfigParser().safeGetBoolean('bitmessagesettings', 'minimizetotray')
showtraynotifications = safeConfigGetBoolean('bitmessagesettings', 'showtraynotifications') showtraynotifications = BMConfigParser().safeGetBoolean('bitmessagesettings', 'showtraynotifications')
startintray = safeConfigGetBoolean('bitmessagesettings', 'startintray') startintray = BMConfigParser().safeGetBoolean('bitmessagesettings', 'startintray')
defaultnoncetrialsperbyte = config.get('bitmessagesettings', 'defaultnoncetrialsperbyte') defaultnoncetrialsperbyte = BMConfigParser().get('bitmessagesettings', 'defaultnoncetrialsperbyte')
defaultpayloadlengthextrabytes = config.get('bitmessagesettings', 'defaultpayloadlengthextrabytes') defaultpayloadlengthextrabytes = BMConfigParser().get('bitmessagesettings', 'defaultpayloadlengthextrabytes')
daemon = safeConfigGetBoolean('bitmessagesettings', 'daemon') daemon = BMConfigParser().safeGetBoolean('bitmessagesettings', 'daemon')
socksproxytype = config.get('bitmessagesettings', 'socksproxytype') socksproxytype = BMConfigParser().get('bitmessagesettings', 'socksproxytype')
sockshostname = config.get('bitmessagesettings', 'sockshostname') sockshostname = BMConfigParser().get('bitmessagesettings', 'sockshostname')
socksport = config.get('bitmessagesettings', 'socksport') socksport = BMConfigParser().get('bitmessagesettings', 'socksport')
socksauthentication = safeConfigGetBoolean('bitmessagesettings', 'socksauthentication') socksauthentication = BMConfigParser().safeGetBoolean('bitmessagesettings', 'socksauthentication')
socksusername = config.get('bitmessagesettings', 'socksusername') socksusername = BMConfigParser().get('bitmessagesettings', 'socksusername')
sockspassword = config.get('bitmessagesettings', 'sockspassword') sockspassword = BMConfigParser().get('bitmessagesettings', 'sockspassword')
print '\n -----------------------------------' print '\n -----------------------------------'
@ -313,60 +298,60 @@ def bmSettings(): #Allows the viewing and modification of keys.dat settings.
if uInput == "port": if uInput == "port":
print ' Current port number: ' + port print ' Current port number: ' + port
uInput = userInput("Enter the new port number.") uInput = userInput("Enter the new port number.")
config.set('bitmessagesettings', 'port', str(uInput)) BMConfigParser().set('bitmessagesettings', 'port', str(uInput))
elif uInput == "startonlogon": elif uInput == "startonlogon":
print ' Current status: ' + str(startonlogon) print ' Current status: ' + str(startonlogon)
uInput = userInput("Enter the new status.") uInput = userInput("Enter the new status.")
config.set('bitmessagesettings', 'startonlogon', str(uInput)) BMConfigParser().set('bitmessagesettings', 'startonlogon', str(uInput))
elif uInput == "minimizetotray": elif uInput == "minimizetotray":
print ' Current status: ' + str(minimizetotray) print ' Current status: ' + str(minimizetotray)
uInput = userInput("Enter the new status.") uInput = userInput("Enter the new status.")
config.set('bitmessagesettings', 'minimizetotray', str(uInput)) BMConfigParser().set('bitmessagesettings', 'minimizetotray', str(uInput))
elif uInput == "showtraynotifications": elif uInput == "showtraynotifications":
print ' Current status: ' + str(showtraynotifications) print ' Current status: ' + str(showtraynotifications)
uInput = userInput("Enter the new status.") uInput = userInput("Enter the new status.")
config.set('bitmessagesettings', 'showtraynotifications', str(uInput)) BMConfigParser().set('bitmessagesettings', 'showtraynotifications', str(uInput))
elif uInput == "startintray": elif uInput == "startintray":
print ' Current status: ' + str(startintray) print ' Current status: ' + str(startintray)
uInput = userInput("Enter the new status.") uInput = userInput("Enter the new status.")
config.set('bitmessagesettings', 'startintray', str(uInput)) BMConfigParser().set('bitmessagesettings', 'startintray', str(uInput))
elif uInput == "defaultnoncetrialsperbyte": elif uInput == "defaultnoncetrialsperbyte":
print ' Current default nonce trials per byte: ' + defaultnoncetrialsperbyte print ' Current default nonce trials per byte: ' + defaultnoncetrialsperbyte
uInput = userInput("Enter the new defaultnoncetrialsperbyte.") uInput = userInput("Enter the new defaultnoncetrialsperbyte.")
config.set('bitmessagesettings', 'defaultnoncetrialsperbyte', str(uInput)) BMConfigParser().set('bitmessagesettings', 'defaultnoncetrialsperbyte', str(uInput))
elif uInput == "defaultpayloadlengthextrabytes": elif uInput == "defaultpayloadlengthextrabytes":
print ' Current default payload length extra bytes: ' + defaultpayloadlengthextrabytes print ' Current default payload length extra bytes: ' + defaultpayloadlengthextrabytes
uInput = userInput("Enter the new defaultpayloadlengthextrabytes.") uInput = userInput("Enter the new defaultpayloadlengthextrabytes.")
config.set('bitmessagesettings', 'defaultpayloadlengthextrabytes', str(uInput)) BMConfigParser().set('bitmessagesettings', 'defaultpayloadlengthextrabytes', str(uInput))
elif uInput == "daemon": elif uInput == "daemon":
print ' Current status: ' + str(daemon) print ' Current status: ' + str(daemon)
uInput = userInput("Enter the new status.").lower() uInput = userInput("Enter the new status.").lower()
config.set('bitmessagesettings', 'daemon', str(uInput)) BMConfigParser().set('bitmessagesettings', 'daemon', str(uInput))
elif uInput == "socksproxytype": elif uInput == "socksproxytype":
print ' Current socks proxy type: ' + socksproxytype print ' Current socks proxy type: ' + socksproxytype
print "Possibilities: 'none', 'SOCKS4a', 'SOCKS5'." print "Possibilities: 'none', 'SOCKS4a', 'SOCKS5'."
uInput = userInput("Enter the new socksproxytype.") uInput = userInput("Enter the new socksproxytype.")
config.set('bitmessagesettings', 'socksproxytype', str(uInput)) BMConfigParser().set('bitmessagesettings', 'socksproxytype', str(uInput))
elif uInput == "sockshostname": elif uInput == "sockshostname":
print ' Current socks host name: ' + sockshostname print ' Current socks host name: ' + sockshostname
uInput = userInput("Enter the new sockshostname.") uInput = userInput("Enter the new sockshostname.")
config.set('bitmessagesettings', 'sockshostname', str(uInput)) BMConfigParser().set('bitmessagesettings', 'sockshostname', str(uInput))
elif uInput == "socksport": elif uInput == "socksport":
print ' Current socks port number: ' + socksport print ' Current socks port number: ' + socksport
uInput = userInput("Enter the new socksport.") uInput = userInput("Enter the new socksport.")
config.set('bitmessagesettings', 'socksport', str(uInput)) BMConfigParser().set('bitmessagesettings', 'socksport', str(uInput))
elif uInput == "socksauthentication": elif uInput == "socksauthentication":
print ' Current status: ' + str(socksauthentication) print ' Current status: ' + str(socksauthentication)
uInput = userInput("Enter the new status.") uInput = userInput("Enter the new status.")
config.set('bitmessagesettings', 'socksauthentication', str(uInput)) BMConfigParser().set('bitmessagesettings', 'socksauthentication', str(uInput))
elif uInput == "socksusername": elif uInput == "socksusername":
print ' Current socks username: ' + socksusername print ' Current socks username: ' + socksusername
uInput = userInput("Enter the new socksusername.") uInput = userInput("Enter the new socksusername.")
config.set('bitmessagesettings', 'socksusername', str(uInput)) BMConfigParser().set('bitmessagesettings', 'socksusername', str(uInput))
elif uInput == "sockspassword": elif uInput == "sockspassword":
print ' Current socks password: ' + sockspassword print ' Current socks password: ' + sockspassword
uInput = userInput("Enter the new password.") uInput = userInput("Enter the new password.")
config.set('bitmessagesettings', 'sockspassword', str(uInput)) BMConfigParser().set('bitmessagesettings', 'sockspassword', str(uInput))
else: else:
print "\n Invalid input. Please try again.\n" print "\n Invalid input. Please try again.\n"
invalidInput = True invalidInput = True
@ -377,7 +362,7 @@ def bmSettings(): #Allows the viewing and modification of keys.dat settings.
if uInput != "y": if uInput != "y":
print '\n Changes Made.\n' print '\n Changes Made.\n'
with open(keysPath, 'wb') as configfile: with open(keysPath, 'wb') as configfile:
config.write(configfile) BMConfigParser().write(configfile)
restartBmNotify() restartBmNotify()
break break

View File

@ -23,9 +23,11 @@ from helper_sql import *
import shared import shared
import ConfigParser import ConfigParser
from configparser import BMConfigParser
from addresses import * from addresses import *
from pyelliptic.openssl import OpenSSL from pyelliptic.openssl import OpenSSL
import l10n import l10n
from inventory import Inventory
quit = False quit = False
menutab = 1 menutab = 1
@ -108,8 +110,8 @@ def scrollbox(d, text, height=None, width=None):
def resetlookups(): def resetlookups():
global inventorydata global inventorydata
inventorydata = shared.numberOfInventoryLookupsPerformed inventorydata = Inventory().numberOfInventoryLookupsPerformed
shared.numberOfInventoryLookupsPerformed = 0 Inventory().numberOfInventoryLookupsPerformed = 0
Timer(1, resetlookups, ()).start() Timer(1, resetlookups, ()).start()
def drawtab(stdscr): def drawtab(stdscr):
if menutab in range(1, len(menu)+1): if menutab in range(1, len(menu)+1):
@ -481,19 +483,19 @@ def handlech(c, stdscr):
r, t = d.inputbox("New address label", init=label) r, t = d.inputbox("New address label", init=label)
if r == d.DIALOG_OK: if r == d.DIALOG_OK:
label = t label = t
shared.config.set(a, "label", label) BMConfigParser().set(a, "label", label)
# Write config # Write config
shared.writeKeysFile() shared.writeKeysFile()
addresses[addrcur][0] = label addresses[addrcur][0] = label
elif t == "4": # Enable address elif t == "4": # Enable address
a = addresses[addrcur][2] a = addresses[addrcur][2]
shared.config.set(a, "enabled", "true") # Set config BMConfigParser().set(a, "enabled", "true") # Set config
# Write config # Write config
shared.writeKeysFile() shared.writeKeysFile()
# Change color # Change color
if shared.safeConfigGetBoolean(a, 'chan'): if BMConfigParser().safeGetBoolean(a, 'chan'):
addresses[addrcur][3] = 9 # orange addresses[addrcur][3] = 9 # orange
elif shared.safeConfigGetBoolean(a, 'mailinglist'): elif BMConfigParser().safeGetBoolean(a, 'mailinglist'):
addresses[addrcur][3] = 5 # magenta addresses[addrcur][3] = 5 # magenta
else: else:
addresses[addrcur][3] = 0 # black addresses[addrcur][3] = 0 # black
@ -501,7 +503,7 @@ def handlech(c, stdscr):
shared.reloadMyAddressHashes() # Reload address hashes shared.reloadMyAddressHashes() # Reload address hashes
elif t == "5": # Disable address elif t == "5": # Disable address
a = addresses[addrcur][2] a = addresses[addrcur][2]
shared.config.set(a, "enabled", "false") # Set config BMConfigParser().set(a, "enabled", "false") # Set config
addresses[addrcur][3] = 8 # Set color to gray addresses[addrcur][3] = 8 # Set color to gray
# Write config # Write config
shared.writeKeysFile() shared.writeKeysFile()
@ -510,36 +512,36 @@ def handlech(c, stdscr):
elif t == "6": # Delete address elif t == "6": # Delete address
r, t = d.inputbox("Type in \"I want to delete this address\"", width=50) r, t = d.inputbox("Type in \"I want to delete this address\"", width=50)
if r == d.DIALOG_OK and t == "I want to delete this address": if r == d.DIALOG_OK and t == "I want to delete this address":
shared.config.remove_section(addresses[addrcur][2]) BMConfigParser().remove_section(addresses[addrcur][2])
shared.writeKeysFile() shared.writeKeysFile()
del addresses[addrcur] del addresses[addrcur]
elif t == "7": # Special address behavior elif t == "7": # Special address behavior
a = addresses[addrcur][2] a = addresses[addrcur][2]
set_background_title(d, "Special address behavior") set_background_title(d, "Special address behavior")
if shared.safeConfigGetBoolean(a, "chan"): if BMConfigParser().safeGetBoolean(a, "chan"):
scrollbox(d, unicode("This is a chan address. You cannot use it as a pseudo-mailing list.")) scrollbox(d, unicode("This is a chan address. You cannot use it as a pseudo-mailing list."))
else: else:
m = shared.safeConfigGetBoolean(a, "mailinglist") m = BMConfigParser().safeGetBoolean(a, "mailinglist")
r, t = d.radiolist("Select address behavior", r, t = d.radiolist("Select address behavior",
choices=[("1", "Behave as a normal address", not m), choices=[("1", "Behave as a normal address", not m),
("2", "Behave as a pseudo-mailing-list address", m)]) ("2", "Behave as a pseudo-mailing-list address", m)])
if r == d.DIALOG_OK: if r == d.DIALOG_OK:
if t == "1" and m == True: if t == "1" and m == True:
shared.config.set(a, "mailinglist", "false") BMConfigParser().set(a, "mailinglist", "false")
if addresses[addrcur][1]: if addresses[addrcur][1]:
addresses[addrcur][3] = 0 # Set color to black addresses[addrcur][3] = 0 # Set color to black
else: else:
addresses[addrcur][3] = 8 # Set color to gray addresses[addrcur][3] = 8 # Set color to gray
elif t == "2" and m == False: elif t == "2" and m == False:
try: try:
mn = shared.config.get(a, "mailinglistname") mn = BMConfigParser().get(a, "mailinglistname")
except ConfigParser.NoOptionError: except ConfigParser.NoOptionError:
mn = "" mn = ""
r, t = d.inputbox("Mailing list name", init=mn) r, t = d.inputbox("Mailing list name", init=mn)
if r == d.DIALOG_OK: if r == d.DIALOG_OK:
mn = t mn = t
shared.config.set(a, "mailinglist", "true") BMConfigParser().set(a, "mailinglist", "true")
shared.config.set(a, "mailinglistname", mn) BMConfigParser().set(a, "mailinglistname", mn)
addresses[addrcur][3] = 6 # Set color to magenta addresses[addrcur][3] = 6 # Set color to magenta
# Write config # Write config
shared.writeKeysFile() shared.writeKeysFile()
@ -792,7 +794,7 @@ def sendMessage(sender="", recv="", broadcast=None, subject="", body="", reply=F
0, # retryNumber 0, # retryNumber
"sent", "sent",
2, # encodingType 2, # encodingType
shared.config.getint('bitmessagesettings', 'ttl')) BMConfigParser().getint('bitmessagesettings', 'ttl'))
shared.workerQueue.put(("sendmessage", addr)) shared.workerQueue.put(("sendmessage", addr))
else: # Broadcast else: # Broadcast
if recv == "": if recv == "":
@ -818,7 +820,7 @@ def sendMessage(sender="", recv="", broadcast=None, subject="", body="", reply=F
0, # retryNumber 0, # retryNumber
"sent", # folder "sent", # folder
2, # encodingType 2, # encodingType
shared.config.getint('bitmessagesettings', 'ttl')) BMConfigParser().getint('bitmessagesettings', 'ttl'))
shared.workerQueue.put(('sendbroadcast', '')) shared.workerQueue.put(('sendbroadcast', ''))
def loadInbox(): def loadInbox():
@ -842,7 +844,7 @@ def loadInbox():
if toaddr == BROADCAST_STR: if toaddr == BROADCAST_STR:
tolabel = BROADCAST_STR tolabel = BROADCAST_STR
else: else:
tolabel = shared.config.get(toaddr, "label") tolabel = BMConfigParser().get(toaddr, "label")
except: except:
tolabel = "" tolabel = ""
if tolabel == "": if tolabel == "":
@ -851,8 +853,8 @@ def loadInbox():
# Set label for from address # Set label for from address
fromlabel = "" fromlabel = ""
if shared.config.has_section(fromaddr): if BMConfigParser().has_section(fromaddr):
fromlabel = shared.config.get(fromaddr, "label") fromlabel = BMConfigParser().get(fromaddr, "label")
if fromlabel == "": # Check Address Book if fromlabel == "": # Check Address Book
qr = sqlQuery("SELECT label FROM addressbook WHERE address=?", fromaddr) qr = sqlQuery("SELECT label FROM addressbook WHERE address=?", fromaddr)
if qr != []: if qr != []:
@ -899,15 +901,15 @@ def loadSent():
for r in qr: for r in qr:
tolabel, = r tolabel, = r
if tolabel == "": if tolabel == "":
if shared.config.has_section(toaddr): if BMConfigParser().has_section(toaddr):
tolabel = shared.config.get(toaddr, "label") tolabel = BMConfigParser().get(toaddr, "label")
if tolabel == "": if tolabel == "":
tolabel = toaddr tolabel = toaddr
# Set label for from address # Set label for from address
fromlabel = "" fromlabel = ""
if shared.config.has_section(fromaddr): if BMConfigParser().has_section(fromaddr):
fromlabel = shared.config.get(fromaddr, "label") fromlabel = BMConfigParser().get(fromaddr, "label")
if fromlabel == "": if fromlabel == "":
fromlabel = fromaddr fromlabel = fromaddr
@ -968,7 +970,7 @@ def loadSubscriptions():
subscriptions.reverse() subscriptions.reverse()
def loadBlackWhiteList(): def loadBlackWhiteList():
global bwtype global bwtype
bwtype = shared.config.get("bitmessagesettings", "blackwhitelist") bwtype = BMConfigParser().get("bitmessagesettings", "blackwhitelist")
if bwtype == "black": if bwtype == "black":
ret = sqlQuery("SELECT label, address, enabled FROM blacklist") ret = sqlQuery("SELECT label, address, enabled FROM blacklist")
else: else:
@ -1024,17 +1026,17 @@ def run(stdscr):
curses.init_pair(9, curses.COLOR_YELLOW, curses.COLOR_BLACK) # orangish curses.init_pair(9, curses.COLOR_YELLOW, curses.COLOR_BLACK) # orangish
# Init list of address in 'Your Identities' tab # Init list of address in 'Your Identities' tab
configSections = shared.config.sections() configSections = BMConfigParser().sections()
for addressInKeysFile in configSections: for addressInKeysFile in configSections:
if addressInKeysFile != "bitmessagesettings": if addressInKeysFile != "bitmessagesettings":
isEnabled = shared.config.getboolean(addressInKeysFile, "enabled") isEnabled = BMConfigParser().getboolean(addressInKeysFile, "enabled")
addresses.append([shared.config.get(addressInKeysFile, "label"), isEnabled, addressInKeysFile]) addresses.append([BMConfigParser().get(addressInKeysFile, "label"), isEnabled, addressInKeysFile])
# Set address color # Set address color
if not isEnabled: if not isEnabled:
addresses[len(addresses)-1].append(8) # gray addresses[len(addresses)-1].append(8) # gray
elif shared.safeConfigGetBoolean(addressInKeysFile, 'chan'): elif BMConfigParser().safeGetBoolean(addressInKeysFile, 'chan'):
addresses[len(addresses)-1].append(9) # orange addresses[len(addresses)-1].append(9) # orange
elif shared.safeConfigGetBoolean(addressInKeysFile, 'mailinglist'): elif BMConfigParser().safeGetBoolean(addressInKeysFile, 'mailinglist'):
addresses[len(addresses)-1].append(5) # magenta addresses[len(addresses)-1].append(5) # magenta
else: else:
addresses[len(addresses)-1].append(0) # black addresses[len(addresses)-1].append(0) # black

View File

@ -14,7 +14,7 @@ depends.check_dependencies()
import signal # Used to capture a Ctrl-C keypress so that Bitmessage can shutdown gracefully. import signal # Used to capture a Ctrl-C keypress so that Bitmessage can shutdown gracefully.
# The next 3 are used for the API # The next 3 are used for the API
import singleton from singleinstance import singleinstance
import os import os
import socket import socket
import ctypes import ctypes
@ -28,6 +28,8 @@ from helper_startup import isOurOperatingSystemLimitedToHavingVeryFewHalfOpenCon
import shared import shared
from helper_sql import sqlQuery from helper_sql import sqlQuery
import state
import protocol
import threading import threading
# Classes # Classes
@ -40,6 +42,7 @@ from class_singleWorker import singleWorker
from class_addressGenerator import addressGenerator from class_addressGenerator import addressGenerator
from class_smtpDeliver import smtpDeliver from class_smtpDeliver import smtpDeliver
from class_smtpServer import smtpServer from class_smtpServer import smtpServer
from configparser import BMConfigParser
from debug import logger from debug import logger
# Helper Functions # Helper Functions
@ -48,7 +51,7 @@ import helper_generic
from helper_threading import * from helper_threading import *
def connectToStream(streamNumber): def connectToStream(streamNumber):
shared.streamsInWhichIAmParticipating[streamNumber] = 'no data' state.streamsInWhichIAmParticipating[streamNumber] = 'no data'
selfInitiatedConnections[streamNumber] = {} selfInitiatedConnections[streamNumber] = {}
if isOurOperatingSystemLimitedToHavingVeryFewHalfOpenConnections(): if isOurOperatingSystemLimitedToHavingVeryFewHalfOpenConnections():
@ -58,7 +61,7 @@ def connectToStream(streamNumber):
maximumNumberOfHalfOpenConnections = 64 maximumNumberOfHalfOpenConnections = 64
try: try:
# don't overload Tor # don't overload Tor
if shared.config.get('bitmessagesettings', 'socksproxytype') != 'none': if BMConfigParser().get('bitmessagesettings', 'socksproxytype') != 'none':
maximumNumberOfHalfOpenConnections = 4 maximumNumberOfHalfOpenConnections = 4
except: except:
pass pass
@ -128,7 +131,7 @@ class singleAPI(threading.Thread, StoppableThread):
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:
s.connect((shared.config.get('bitmessagesettings', 'apiinterface'), shared.config.getint( s.connect((BMConfigParser().get('bitmessagesettings', 'apiinterface'), BMConfigParser().getint(
'bitmessagesettings', 'apiport'))) 'bitmessagesettings', 'apiport')))
s.shutdown(socket.SHUT_RDWR) s.shutdown(socket.SHUT_RDWR)
s.close() s.close()
@ -136,7 +139,7 @@ class singleAPI(threading.Thread, StoppableThread):
pass pass
def run(self): def run(self):
se = StoppableXMLRPCServer((shared.config.get('bitmessagesettings', 'apiinterface'), shared.config.getint( se = StoppableXMLRPCServer((BMConfigParser().get('bitmessagesettings', 'apiinterface'), BMConfigParser().getint(
'bitmessagesettings', 'apiport')), MySimpleXMLRPCRequestHandler, True, True) 'bitmessagesettings', 'apiport')), MySimpleXMLRPCRequestHandler, True, True)
se.register_introspection_functions() se.register_introspection_functions()
se.serve_forever() se.serve_forever()
@ -145,10 +148,10 @@ class singleAPI(threading.Thread, StoppableThread):
selfInitiatedConnections = {} selfInitiatedConnections = {}
if shared.useVeryEasyProofOfWorkForTesting: if shared.useVeryEasyProofOfWorkForTesting:
shared.networkDefaultProofOfWorkNonceTrialsPerByte = int( protocol.networkDefaultProofOfWorkNonceTrialsPerByte = int(
shared.networkDefaultProofOfWorkNonceTrialsPerByte / 100) protocol.networkDefaultProofOfWorkNonceTrialsPerByte / 100)
shared.networkDefaultPayloadLengthExtraBytes = int( protocol.networkDefaultPayloadLengthExtraBytes = int(
shared.networkDefaultPayloadLengthExtraBytes / 100) protocol.networkDefaultPayloadLengthExtraBytes / 100)
class Main: class Main:
def start(self, daemon=False): def start(self, daemon=False):
@ -162,7 +165,7 @@ class Main:
shared.curses = True shared.curses = True
# is the application already running? If yes then exit. # is the application already running? If yes then exit.
shared.thisapp = singleton.singleinstance("", daemon) shared.thisapp = singleinstance("", daemon)
if daemon: if daemon:
with shared.printLock: with shared.printLock:
@ -188,12 +191,12 @@ class Main:
sqlLookup.start() sqlLookup.start()
# SMTP delivery thread # SMTP delivery thread
if daemon and shared.safeConfigGet("bitmessagesettings", "smtpdeliver", '') != '': if daemon and BMConfigParser().safeGet("bitmessagesettings", "smtpdeliver", '') != '':
smtpDeliveryThread = smtpDeliver() smtpDeliveryThread = smtpDeliver()
smtpDeliveryThread.start() smtpDeliveryThread.start()
# SMTP daemon thread # SMTP daemon thread
if daemon and shared.safeConfigGetBoolean("bitmessagesettings", "smtpd"): if daemon and BMConfigParser().safeGetBoolean("bitmessagesettings", "smtpd"):
smtpServerThread = smtpServer() smtpServerThread = smtpServer()
smtpServerThread.start() smtpServerThread.start()
@ -210,9 +213,9 @@ class Main:
shared.reloadMyAddressHashes() shared.reloadMyAddressHashes()
shared.reloadBroadcastSendersForWhichImWatching() shared.reloadBroadcastSendersForWhichImWatching()
if shared.safeConfigGetBoolean('bitmessagesettings', 'apienabled'): if BMConfigParser().safeGetBoolean('bitmessagesettings', 'apienabled'):
try: try:
apiNotifyPath = shared.config.get( apiNotifyPath = BMConfigParser().get(
'bitmessagesettings', 'apinotifypath') 'bitmessagesettings', 'apinotifypath')
except: except:
apiNotifyPath = '' apiNotifyPath = ''
@ -232,12 +235,12 @@ class Main:
singleListenerThread.daemon = True # close the main program even if there are threads left singleListenerThread.daemon = True # close the main program even if there are threads left
singleListenerThread.start() singleListenerThread.start()
if shared.safeConfigGetBoolean('bitmessagesettings','upnp'): if BMConfigParser().safeGetBoolean('bitmessagesettings','upnp'):
import upnp import upnp
upnpThread = upnp.uPnPThread() upnpThread = upnp.uPnPThread()
upnpThread.start() upnpThread.start()
if daemon == False and shared.safeConfigGetBoolean('bitmessagesettings', 'daemon') == False: if daemon == False and BMConfigParser().safeGetBoolean('bitmessagesettings', 'daemon') == False:
if shared.curses == False: if shared.curses == False:
if not depends.check_pyqt(): if not depends.check_pyqt():
print('PyBitmessage requires PyQt unless you want to run it as a daemon and interact with it using the API. You can download PyQt from http://www.riverbankcomputing.com/software/pyqt/download or by searching Google for \'PyQt Download\'. If you want to run in daemon mode, see https://bitmessage.org/wiki/Daemon') print('PyBitmessage requires PyQt unless you want to run it as a daemon and interact with it using the API. You can download PyQt from http://www.riverbankcomputing.com/software/pyqt/download or by searching Google for \'PyQt Download\'. If you want to run in daemon mode, see https://bitmessage.org/wiki/Daemon')
@ -253,7 +256,7 @@ class Main:
import bitmessagecurses import bitmessagecurses
bitmessagecurses.runwrapper() bitmessagecurses.runwrapper()
else: else:
shared.config.remove_option('bitmessagesettings', 'dontconnect') BMConfigParser().remove_option('bitmessagesettings', 'dontconnect')
while True: while True:
time.sleep(20) time.sleep(20)
@ -290,15 +293,15 @@ class Main:
#TODO: nice function but no one is using this #TODO: nice function but no one is using this
def getApiAddress(self): def getApiAddress(self):
if not shared.safeConfigGetBoolean('bitmessagesettings', 'apienabled'): if not BMConfigParser().safeGetBoolean('bitmessagesettings', 'apienabled'):
return None return None
address = shared.config.get('bitmessagesettings', 'apiinterface') address = BMConfigParser().get('bitmessagesettings', 'apiinterface')
port = shared.config.getint('bitmessagesettings', 'apiport') port = BMConfigParser().getint('bitmessagesettings', 'apiport')
return {'address':address,'port':port} return {'address':address,'port':port}
if __name__ == "__main__": if __name__ == "__main__":
mainprogram = Main() mainprogram = Main()
mainprogram.start(shared.safeConfigGetBoolean('bitmessagesettings', 'daemon')) mainprogram.start(BMConfigParser().safeGetBoolean('bitmessagesettings', 'daemon'))
# So far, the creation of and management of the Bitmessage protocol and this # So far, the creation of and management of the Bitmessage protocol and this

View File

@ -19,6 +19,7 @@ try:
except Exception as err: except Exception as err:
logmsg = 'PyBitmessage requires PyQt unless you want to run it as a daemon and interact with it using the API. You can download it from http://www.riverbankcomputing.com/software/pyqt/download or by searching Google for \'PyQt Download\' (without quotes).' logmsg = 'PyBitmessage requires PyQt unless you want to run it as a daemon and interact with it using the API. You can download it from http://www.riverbankcomputing.com/software/pyqt/download or by searching Google for \'PyQt Download\' (without quotes).'
logger.critical(logmsg, exc_info=True) logger.critical(logmsg, exc_info=True)
import sys
sys.exit() sys.exit()
try: try:
@ -29,6 +30,7 @@ except AttributeError:
from addresses import * from addresses import *
import shared import shared
from bitmessageui import * from bitmessageui import *
from configparser import BMConfigParser
from namecoin import namecoinConnection, ensureNamecoinOptions from namecoin import namecoinConnection, ensureNamecoinOptions
from newaddressdialog import * from newaddressdialog import *
from newaddresswizard import * from newaddresswizard import *
@ -75,8 +77,12 @@ from dialogs import AddAddressDialog
from class_objectHashHolder import objectHashHolder from class_objectHashHolder import objectHashHolder
from class_singleWorker import singleWorker from class_singleWorker import singleWorker
from helper_generic import powQueueSize, invQueueSize from helper_generic import powQueueSize, invQueueSize
import paths
from proofofwork import getPowType from proofofwork import getPowType
import protocol
import state
from statusbar import BMStatusBar from statusbar import BMStatusBar
from version import softwareVersion
def _translate(context, text, disambiguation = None, encoding = None, number = None): def _translate(context, text, disambiguation = None, encoding = None, number = None):
if number is None: if number is None:
@ -98,13 +104,13 @@ def change_translation(newlocale):
pass pass
qmytranslator = QtCore.QTranslator() qmytranslator = QtCore.QTranslator()
translationpath = os.path.join (shared.codePath(), 'translations', 'bitmessage_' + newlocale) translationpath = os.path.join (paths.codePath(), 'translations', 'bitmessage_' + newlocale)
qmytranslator.load(translationpath) qmytranslator.load(translationpath)
QtGui.QApplication.installTranslator(qmytranslator) QtGui.QApplication.installTranslator(qmytranslator)
qsystranslator = QtCore.QTranslator() qsystranslator = QtCore.QTranslator()
if shared.frozen: if paths.frozen:
translationpath = os.path.join (shared.codePath(), 'translations', 'qt_' + newlocale) translationpath = os.path.join (paths.codePath(), 'translations', 'qt_' + newlocale)
else: else:
translationpath = os.path.join (str(QtCore.QLibraryInfo.location(QtCore.QLibraryInfo.TranslationsPath)), 'qt_' + newlocale) translationpath = os.path.join (str(QtCore.QLibraryInfo.location(QtCore.QLibraryInfo.TranslationsPath)), 'qt_' + newlocale)
qsystranslator.load(translationpath) qsystranslator.load(translationpath)
@ -490,11 +496,11 @@ class MyForm(settingsmixin.SMainWindow):
enabled = {} enabled = {}
for toAddress in getSortedAccounts(): for toAddress in getSortedAccounts():
isEnabled = shared.config.getboolean( isEnabled = BMConfigParser().getboolean(
toAddress, 'enabled') toAddress, 'enabled')
isChan = shared.safeConfigGetBoolean( isChan = BMConfigParser().safeGetBoolean(
toAddress, 'chan') toAddress, 'chan')
isMaillinglist = shared.safeConfigGetBoolean( isMaillinglist = BMConfigParser().safeGetBoolean(
toAddress, 'mailinglist') toAddress, 'mailinglist')
if treeWidget == self.ui.treeWidgetYourIdentities: if treeWidget == self.ui.treeWidgetYourIdentities:
@ -603,7 +609,7 @@ class MyForm(settingsmixin.SMainWindow):
reply = QtGui.QMessageBox.question( reply = QtGui.QMessageBox.question(
self, 'Message', displayMsg, QtGui.QMessageBox.Yes, QtGui.QMessageBox.No) self, 'Message', displayMsg, QtGui.QMessageBox.Yes, QtGui.QMessageBox.No)
if reply == QtGui.QMessageBox.Yes: if reply == QtGui.QMessageBox.Yes:
shared.config.remove_section(addressInKeysFile) BMConfigParser().remove_section(addressInKeysFile)
shared.writeKeysFile() shared.writeKeysFile()
# Configure Bitmessage to start on startup (or remove the # Configure Bitmessage to start on startup (or remove the
@ -614,7 +620,7 @@ class MyForm(settingsmixin.SMainWindow):
self.settings = QSettings(RUN_PATH, QSettings.NativeFormat) self.settings = QSettings(RUN_PATH, QSettings.NativeFormat)
self.settings.remove( self.settings.remove(
"PyBitmessage") # In case the user moves the program and the registry entry is no longer valid, this will delete the old registry entry. "PyBitmessage") # In case the user moves the program and the registry entry is no longer valid, this will delete the old registry entry.
if shared.config.getboolean('bitmessagesettings', 'startonlogon'): if BMConfigParser().getboolean('bitmessagesettings', 'startonlogon'):
self.settings.setValue("PyBitmessage", sys.argv[0]) self.settings.setValue("PyBitmessage", sys.argv[0])
elif 'darwin' in sys.platform: elif 'darwin' in sys.platform:
# startup for mac # startup for mac
@ -783,7 +789,7 @@ class MyForm(settingsmixin.SMainWindow):
self.rerenderComboBoxSendFromBroadcast() self.rerenderComboBoxSendFromBroadcast()
# Put the TTL slider in the correct spot # Put the TTL slider in the correct spot
TTL = shared.config.getint('bitmessagesettings', 'ttl') TTL = BMConfigParser().getint('bitmessagesettings', 'ttl')
if TTL < 3600: # an hour if TTL < 3600: # an hour
TTL = 3600 TTL = 3600
elif TTL > 28*24*60*60: # 28 days elif TTL > 28*24*60*60: # 28 days
@ -799,11 +805,11 @@ class MyForm(settingsmixin.SMainWindow):
# Check to see whether we can connect to namecoin. Hide the 'Fetch Namecoin ID' button if we can't. # Check to see whether we can connect to namecoin. Hide the 'Fetch Namecoin ID' button if we can't.
try: try:
options = {} options = {}
options["type"] = shared.config.get('bitmessagesettings', 'namecoinrpctype') options["type"] = BMConfigParser().get('bitmessagesettings', 'namecoinrpctype')
options["host"] = shared.config.get('bitmessagesettings', 'namecoinrpchost') options["host"] = BMConfigParser().get('bitmessagesettings', 'namecoinrpchost')
options["port"] = shared.config.get('bitmessagesettings', 'namecoinrpcport') options["port"] = BMConfigParser().get('bitmessagesettings', 'namecoinrpcport')
options["user"] = shared.config.get('bitmessagesettings', 'namecoinrpcuser') options["user"] = BMConfigParser().get('bitmessagesettings', 'namecoinrpcuser')
options["password"] = shared.config.get('bitmessagesettings', 'namecoinrpcpassword') options["password"] = BMConfigParser().get('bitmessagesettings', 'namecoinrpcpassword')
nc = namecoinConnection(options) nc = namecoinConnection(options)
if nc.test()[0] == 'failed': if nc.test()[0] == 'failed':
self.ui.pushButtonFetchNamecoinID.hide() self.ui.pushButtonFetchNamecoinID.hide()
@ -814,7 +820,7 @@ class MyForm(settingsmixin.SMainWindow):
def updateTTL(self, sliderPosition): def updateTTL(self, sliderPosition):
TTL = int(sliderPosition ** 3.199 + 3600) TTL = int(sliderPosition ** 3.199 + 3600)
self.updateHumanFriendlyTTLDescription(TTL) self.updateHumanFriendlyTTLDescription(TTL)
shared.config.set('bitmessagesettings', 'ttl', str(TTL)) BMConfigParser().set('bitmessagesettings', 'ttl', str(TTL))
shared.writeKeysFile() shared.writeKeysFile()
def updateHumanFriendlyTTLDescription(self, TTL): def updateHumanFriendlyTTLDescription(self, TTL):
@ -1161,7 +1167,7 @@ class MyForm(settingsmixin.SMainWindow):
# show bitmessage # show bitmessage
self.actionShow = QtGui.QAction(_translate( self.actionShow = QtGui.QAction(_translate(
"MainWindow", "Show Bitmessage"), m, checkable=True) "MainWindow", "Show Bitmessage"), m, checkable=True)
self.actionShow.setChecked(not shared.config.getboolean( self.actionShow.setChecked(not BMConfigParser().getboolean(
'bitmessagesettings', 'startintray')) 'bitmessagesettings', 'startintray'))
self.actionShow.triggered.connect(self.appIndicatorShowOrHideWindow) self.actionShow.triggered.connect(self.appIndicatorShowOrHideWindow)
if not sys.platform[0:3] == 'win': if not sys.platform[0:3] == 'win':
@ -1209,8 +1215,6 @@ class MyForm(settingsmixin.SMainWindow):
# When an unread inbox row is selected on then clear the messaging menu # When an unread inbox row is selected on then clear the messaging menu
def ubuntuMessagingMenuClear(self, inventoryHash): def ubuntuMessagingMenuClear(self, inventoryHash):
global withMessagingMenu
# if this isn't ubuntu then don't do anything # if this isn't ubuntu then don't do anything
if not self.isUbuntu(): if not self.isUbuntu():
return return
@ -1250,7 +1254,7 @@ class MyForm(settingsmixin.SMainWindow):
if toAddress == str_broadcast_subscribers: if toAddress == str_broadcast_subscribers:
toLabel = str_broadcast_subscribers toLabel = str_broadcast_subscribers
else: else:
toLabel = shared.config.get(toAddress, 'label') toLabel = BMConfigParser().get(toAddress, 'label')
except: except:
toLabel = '' toLabel = ''
if toLabel == '': if toLabel == '':
@ -1310,8 +1314,6 @@ class MyForm(settingsmixin.SMainWindow):
# update the Ubuntu messaging menu # update the Ubuntu messaging menu
def ubuntuMessagingMenuUpdate(self, drawAttention, newItem, toLabel): def ubuntuMessagingMenuUpdate(self, drawAttention, newItem, toLabel):
global withMessagingMenu
# if this isn't ubuntu then don't do anything # if this isn't ubuntu then don't do anything
if not self.isUbuntu(): if not self.isUbuntu():
return return
@ -1358,9 +1360,9 @@ class MyForm(settingsmixin.SMainWindow):
# if the address had a known label in the address book # if the address had a known label in the address book
if label is not None: if label is not None:
# Does a sound file exist for this particular contact? # Does a sound file exist for this particular contact?
if (os.path.isfile(shared.appdata + 'sounds/' + label + '.wav') or if (os.path.isfile(state.appdata + 'sounds/' + label + '.wav') or
os.path.isfile(shared.appdata + 'sounds/' + label + '.mp3')): os.path.isfile(state.appdata + 'sounds/' + label + '.mp3')):
soundFilename = shared.appdata + 'sounds/' + label soundFilename = state.appdata + 'sounds/' + label
# Avoid making sounds more frequently than the threshold. # Avoid making sounds more frequently than the threshold.
# This suppresses playing sounds repeatedly when there # This suppresses playing sounds repeatedly when there
@ -1376,19 +1378,19 @@ class MyForm(settingsmixin.SMainWindow):
if soundFilename is None: if soundFilename is None:
# the sound is for an address which exists in the address book # the sound is for an address which exists in the address book
if category is self.SOUND_KNOWN: if category is self.SOUND_KNOWN:
soundFilename = shared.appdata + 'sounds/known' soundFilename = state.appdata + 'sounds/known'
# the sound is for an unknown address # the sound is for an unknown address
elif category is self.SOUND_UNKNOWN: elif category is self.SOUND_UNKNOWN:
soundFilename = shared.appdata + 'sounds/unknown' soundFilename = state.appdata + 'sounds/unknown'
# initial connection sound # initial connection sound
elif category is self.SOUND_CONNECTED: elif category is self.SOUND_CONNECTED:
soundFilename = shared.appdata + 'sounds/connected' soundFilename = state.appdata + 'sounds/connected'
# disconnected sound # disconnected sound
elif category is self.SOUND_DISCONNECTED: elif category is self.SOUND_DISCONNECTED:
soundFilename = shared.appdata + 'sounds/disconnected' soundFilename = state.appdata + 'sounds/disconnected'
# sound when the connection status becomes green # sound when the connection status becomes green
elif category is self.SOUND_CONNECTION_GREEN: elif category is self.SOUND_CONNECTION_GREEN:
soundFilename = shared.appdata + 'sounds/green' soundFilename = state.appdata + 'sounds/green'
if soundFilename is not None and play is True: if soundFilename is not None and play is True:
if not self.isConnectionSound(category): if not self.isConnectionSound(category):
@ -1435,14 +1437,11 @@ class MyForm(settingsmixin.SMainWindow):
# initialise the message notifier # initialise the message notifier
def notifierInit(self): def notifierInit(self):
global withMessagingMenu
if withMessagingMenu: if withMessagingMenu:
Notify.init('pybitmessage') Notify.init('pybitmessage')
# shows a notification # shows a notification
def notifierShow(self, title, subtitle, fromCategory, label): def notifierShow(self, title, subtitle, fromCategory, label):
global withMessagingMenu
self.playSound(fromCategory, label) self.playSound(fromCategory, label)
if withMessagingMenu: if withMessagingMenu:
@ -1524,7 +1523,7 @@ class MyForm(settingsmixin.SMainWindow):
# menu button 'manage keys' # menu button 'manage keys'
def click_actionManageKeys(self): def click_actionManageKeys(self):
if 'darwin' in sys.platform or 'linux' in sys.platform: if 'darwin' in sys.platform or 'linux' in sys.platform:
if shared.appdata == '': if state.appdata == '':
# reply = QtGui.QMessageBox.information(self, 'keys.dat?','You # reply = QtGui.QMessageBox.information(self, 'keys.dat?','You
# may manage your keys by editing the keys.dat file stored in # may manage your keys by editing the keys.dat file stored in
# the same directory as this program. It is important that you # the same directory as this program. It is important that you
@ -1534,14 +1533,14 @@ class MyForm(settingsmixin.SMainWindow):
else: else:
QtGui.QMessageBox.information(self, 'keys.dat?', _translate( QtGui.QMessageBox.information(self, 'keys.dat?', _translate(
"MainWindow", "You may manage your keys by editing the keys.dat file stored in\n %1 \nIt is important that you back up this file.").arg(shared.appdata), QMessageBox.Ok) "MainWindow", "You may manage your keys by editing the keys.dat file stored in\n %1 \nIt is important that you back up this file.").arg(state.appdata), QMessageBox.Ok)
elif sys.platform == 'win32' or sys.platform == 'win64': elif sys.platform == 'win32' or sys.platform == 'win64':
if shared.appdata == '': if state.appdata == '':
reply = QtGui.QMessageBox.question(self, _translate("MainWindow", "Open keys.dat?"), _translate( reply = QtGui.QMessageBox.question(self, _translate("MainWindow", "Open keys.dat?"), _translate(
"MainWindow", "You may manage your keys by editing the keys.dat file stored in the same directory as this program. It is important that you back up this file. Would you like to open the file now? (Be sure to close Bitmessage before making any changes.)"), QtGui.QMessageBox.Yes, QtGui.QMessageBox.No) "MainWindow", "You may manage your keys by editing the keys.dat file stored in the same directory as this program. It is important that you back up this file. Would you like to open the file now? (Be sure to close Bitmessage before making any changes.)"), QtGui.QMessageBox.Yes, QtGui.QMessageBox.No)
else: else:
reply = QtGui.QMessageBox.question(self, _translate("MainWindow", "Open keys.dat?"), _translate( reply = QtGui.QMessageBox.question(self, _translate("MainWindow", "Open keys.dat?"), _translate(
"MainWindow", "You may manage your keys by editing the keys.dat file stored in\n %1 \nIt is important that you back up this file. Would you like to open the file now? (Be sure to close Bitmessage before making any changes.)").arg(shared.appdata), QtGui.QMessageBox.Yes, QtGui.QMessageBox.No) "MainWindow", "You may manage your keys by editing the keys.dat file stored in\n %1 \nIt is important that you back up this file. Would you like to open the file now? (Be sure to close Bitmessage before making any changes.)").arg(state.appdata), QtGui.QMessageBox.Yes, QtGui.QMessageBox.No)
if reply == QtGui.QMessageBox.Yes: if reply == QtGui.QMessageBox.Yes:
shared.openKeysFile() shared.openKeysFile()
@ -1595,7 +1594,7 @@ class MyForm(settingsmixin.SMainWindow):
self.connectDialogInstance = connectDialog(self) self.connectDialogInstance = connectDialog(self)
if self.connectDialogInstance.exec_(): if self.connectDialogInstance.exec_():
if self.connectDialogInstance.ui.radioButtonConnectNow.isChecked(): if self.connectDialogInstance.ui.radioButtonConnectNow.isChecked():
shared.config.remove_option('bitmessagesettings', 'dontconnect') BMConfigParser().remove_option('bitmessagesettings', 'dontconnect')
shared.writeKeysFile() shared.writeKeysFile()
else: else:
self.click_actionSettings() self.click_actionSettings()
@ -1619,7 +1618,7 @@ class MyForm(settingsmixin.SMainWindow):
self.ui.blackwhitelist.init_blacklist_popup_menu(False) self.ui.blackwhitelist.init_blacklist_popup_menu(False)
if event.type() == QtCore.QEvent.WindowStateChange: if event.type() == QtCore.QEvent.WindowStateChange:
if self.windowState() & QtCore.Qt.WindowMinimized: if self.windowState() & QtCore.Qt.WindowMinimized:
if shared.config.getboolean('bitmessagesettings', 'minimizetotray') and not 'darwin' in sys.platform: if BMConfigParser().getboolean('bitmessagesettings', 'minimizetotray') and not 'darwin' in sys.platform:
QTimer.singleShot(0, self.appIndicatorHide) QTimer.singleShot(0, self.appIndicatorHide)
elif event.oldState() & QtCore.Qt.WindowMinimized: elif event.oldState() & QtCore.Qt.WindowMinimized:
# The window state has just been changed to # The window state has just been changed to
@ -1637,14 +1636,13 @@ class MyForm(settingsmixin.SMainWindow):
connected = False connected = False
def setStatusIcon(self, color): def setStatusIcon(self, color):
global withMessagingMenu
# print 'setting status icon color' # print 'setting status icon color'
if color == 'red': if color == 'red':
self.pushButtonStatusIcon.setIcon( self.pushButtonStatusIcon.setIcon(
QIcon(":/newPrefix/images/redicon.png")) QIcon(":/newPrefix/images/redicon.png"))
shared.statusIconColor = 'red' shared.statusIconColor = 'red'
# if the connection is lost then show a notification # if the connection is lost then show a notification
if self.connected and not shared.config.getboolean('bitmessagesettings', 'hidetrayconnectionnotifications'): if self.connected and not BMConfigParser().getboolean('bitmessagesettings', 'hidetrayconnectionnotifications'):
self.notifierShow('Bitmessage', unicode(_translate( self.notifierShow('Bitmessage', unicode(_translate(
"MainWindow", "Connection lost").toUtf8(),'utf-8'), "MainWindow", "Connection lost").toUtf8(),'utf-8'),
self.SOUND_DISCONNECTED, None) self.SOUND_DISCONNECTED, None)
@ -1661,7 +1659,7 @@ class MyForm(settingsmixin.SMainWindow):
":/newPrefix/images/yellowicon.png")) ":/newPrefix/images/yellowicon.png"))
shared.statusIconColor = 'yellow' shared.statusIconColor = 'yellow'
# if a new connection has been established then show a notification # if a new connection has been established then show a notification
if not self.connected and not shared.config.getboolean('bitmessagesettings', 'hidetrayconnectionnotifications'): if not self.connected and not BMConfigParser().getboolean('bitmessagesettings', 'hidetrayconnectionnotifications'):
self.notifierShow('Bitmessage', unicode(_translate( self.notifierShow('Bitmessage', unicode(_translate(
"MainWindow", "Connected").toUtf8(),'utf-8'), "MainWindow", "Connected").toUtf8(),'utf-8'),
self.SOUND_CONNECTED, None) self.SOUND_CONNECTED, None)
@ -1677,7 +1675,7 @@ class MyForm(settingsmixin.SMainWindow):
self.pushButtonStatusIcon.setIcon( self.pushButtonStatusIcon.setIcon(
QIcon(":/newPrefix/images/greenicon.png")) QIcon(":/newPrefix/images/greenicon.png"))
shared.statusIconColor = 'green' shared.statusIconColor = 'green'
if not self.connected and not shared.config.getboolean('bitmessagesettings', 'hidetrayconnectionnotifications'): if not self.connected and not BMConfigParser().getboolean('bitmessagesettings', 'hidetrayconnectionnotifications'):
self.notifierShow('Bitmessage', unicode(_translate( self.notifierShow('Bitmessage', unicode(_translate(
"MainWindow", "Connected").toUtf8(),'utf-8'), "MainWindow", "Connected").toUtf8(),'utf-8'),
self.SOUND_CONNECTION_GREEN, None) self.SOUND_CONNECTION_GREEN, None)
@ -1856,7 +1854,7 @@ class MyForm(settingsmixin.SMainWindow):
addresses = getSortedAccounts() addresses = getSortedAccounts()
for address in addresses: for address in addresses:
account = accountClass(address) account = accountClass(address)
if (account.type == AccountMixin.CHAN and shared.safeConfigGetBoolean(address, 'enabled')): if (account.type == AccountMixin.CHAN and BMConfigParser().safeGetBoolean(address, 'enabled')):
newRows[address] = [account.getLabel(), AccountMixin.CHAN] newRows[address] = [account.getLabel(), AccountMixin.CHAN]
# normal accounts # normal accounts
queryreturn = sqlQuery('SELECT * FROM addressbook') queryreturn = sqlQuery('SELECT * FROM addressbook')
@ -1952,8 +1950,8 @@ class MyForm(settingsmixin.SMainWindow):
email = ''.join(random.SystemRandom().choice(string.ascii_lowercase) for _ in range(12)) + "@mailchuck.com" email = ''.join(random.SystemRandom().choice(string.ascii_lowercase) for _ in range(12)) + "@mailchuck.com"
acct = MailchuckAccount(fromAddress) acct = MailchuckAccount(fromAddress)
acct.register(email) acct.register(email)
shared.config.set(fromAddress, 'label', email) BMConfigParser().set(fromAddress, 'label', email)
shared.config.set(fromAddress, 'gateway', 'mailchuck') BMConfigParser().set(fromAddress, 'gateway', 'mailchuck')
shared.writeKeysFile() shared.writeKeysFile()
self.statusBar().showMessage(_translate( self.statusBar().showMessage(_translate(
"MainWindow", "Error: Your account wasn't registered at an email gateway. Sending registration now as %1, please wait for the registration to be processed before retrying sending.").arg(email), 10000) "MainWindow", "Error: Your account wasn't registered at an email gateway. Sending registration now as %1, please wait for the registration to be processed before retrying sending.").arg(email), 10000)
@ -2027,7 +2025,7 @@ class MyForm(settingsmixin.SMainWindow):
0, # retryNumber 0, # retryNumber
'sent', # folder 'sent', # folder
encoding, # encodingtype encoding, # encodingtype
shared.config.getint('bitmessagesettings', 'ttl') BMConfigParser().getint('bitmessagesettings', 'ttl')
) )
toLabel = '' toLabel = ''
@ -2080,7 +2078,7 @@ class MyForm(settingsmixin.SMainWindow):
0, # retryNumber 0, # retryNumber
'sent', # folder 'sent', # folder
encoding, # encoding type encoding, # encoding type
shared.config.getint('bitmessagesettings', 'ttl') BMConfigParser().getint('bitmessagesettings', 'ttl')
) )
sqlExecute( sqlExecute(
'''INSERT INTO sent VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)''', *t) '''INSERT INTO sent VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)''', *t)
@ -2125,7 +2123,7 @@ class MyForm(settingsmixin.SMainWindow):
def setBroadcastEnablementDependingOnWhetherThisIsAMailingListAddress(self, address): def setBroadcastEnablementDependingOnWhetherThisIsAMailingListAddress(self, address):
# If this is a chan then don't let people broadcast because no one # If this is a chan then don't let people broadcast because no one
# should subscribe to chan addresses. # should subscribe to chan addresses.
if shared.safeConfigGetBoolean(str(address), 'mailinglist'): if BMConfigParser().safeGetBoolean(str(address), 'mailinglist'):
self.ui.tabWidgetSend.setCurrentIndex(1) self.ui.tabWidgetSend.setCurrentIndex(1)
else: else:
self.ui.tabWidgetSend.setCurrentIndex(0) self.ui.tabWidgetSend.setCurrentIndex(0)
@ -2133,11 +2131,11 @@ class MyForm(settingsmixin.SMainWindow):
def rerenderComboBoxSendFrom(self): def rerenderComboBoxSendFrom(self):
self.ui.comboBoxSendFrom.clear() self.ui.comboBoxSendFrom.clear()
for addressInKeysFile in getSortedAccounts(): for addressInKeysFile in getSortedAccounts():
isEnabled = shared.config.getboolean( isEnabled = BMConfigParser().getboolean(
addressInKeysFile, 'enabled') # I realize that this is poor programming practice but I don't care. It's easier for others to read. addressInKeysFile, 'enabled') # I realize that this is poor programming practice but I don't care. It's easier for others to read.
isMaillinglist = shared.safeConfigGetBoolean(addressInKeysFile, 'mailinglist') isMaillinglist = BMConfigParser().safeGetBoolean(addressInKeysFile, 'mailinglist')
if isEnabled and not isMaillinglist: if isEnabled and not isMaillinglist:
label = unicode(shared.config.get(addressInKeysFile, 'label'), 'utf-8', 'ignore').strip() label = unicode(BMConfigParser().get(addressInKeysFile, 'label'), 'utf-8', 'ignore').strip()
if label == "": if label == "":
label = addressInKeysFile label = addressInKeysFile
self.ui.comboBoxSendFrom.addItem(avatarize(addressInKeysFile), label, addressInKeysFile) self.ui.comboBoxSendFrom.addItem(avatarize(addressInKeysFile), label, addressInKeysFile)
@ -2154,11 +2152,11 @@ class MyForm(settingsmixin.SMainWindow):
def rerenderComboBoxSendFromBroadcast(self): def rerenderComboBoxSendFromBroadcast(self):
self.ui.comboBoxSendFromBroadcast.clear() self.ui.comboBoxSendFromBroadcast.clear()
for addressInKeysFile in getSortedAccounts(): for addressInKeysFile in getSortedAccounts():
isEnabled = shared.config.getboolean( isEnabled = BMConfigParser().getboolean(
addressInKeysFile, 'enabled') # I realize that this is poor programming practice but I don't care. It's easier for others to read. addressInKeysFile, 'enabled') # I realize that this is poor programming practice but I don't care. It's easier for others to read.
isChan = shared.safeConfigGetBoolean(addressInKeysFile, 'chan') isChan = BMConfigParser().safeGetBoolean(addressInKeysFile, 'chan')
if isEnabled and not isChan: if isEnabled and not isChan:
label = unicode(shared.config.get(addressInKeysFile, 'label'), 'utf-8', 'ignore').strip() label = unicode(BMConfigParser().get(addressInKeysFile, 'label'), 'utf-8', 'ignore').strip()
if label == "": if label == "":
label = addressInKeysFile label = addressInKeysFile
self.ui.comboBoxSendFromBroadcast.addItem(avatarize(addressInKeysFile), label, addressInKeysFile) self.ui.comboBoxSendFromBroadcast.addItem(avatarize(addressInKeysFile), label, addressInKeysFile)
@ -2221,7 +2219,7 @@ class MyForm(settingsmixin.SMainWindow):
else: else:
acct = ret acct = ret
self.propagateUnreadCount(acct.address) self.propagateUnreadCount(acct.address)
if shared.config.getboolean('bitmessagesettings', 'showtraynotifications'): if BMConfigParser().getboolean('bitmessagesettings', 'showtraynotifications'):
self.notifierShow(unicode(_translate("MainWindow",'New Message').toUtf8(),'utf-8'), unicode(_translate("MainWindow",'From ').toUtf8(),'utf-8') + unicode(acct.fromLabel, 'utf-8'), self.SOUND_UNKNOWN, None) self.notifierShow(unicode(_translate("MainWindow",'New Message').toUtf8(),'utf-8'), unicode(_translate("MainWindow",'From ').toUtf8(),'utf-8') + unicode(acct.fromLabel, 'utf-8'), self.SOUND_UNKNOWN, None)
if self.getCurrentAccount() is not None and ((self.getCurrentFolder(treeWidget) != "inbox" and self.getCurrentFolder(treeWidget) is not None) or self.getCurrentAccount(treeWidget) != acct.address): if self.getCurrentAccount() is not None and ((self.getCurrentFolder(treeWidget) != "inbox" and self.getCurrentFolder(treeWidget) is not None) or self.getCurrentAccount(treeWidget) != acct.address):
# Ubuntu should notify of new message irespective of whether it's in current message list or not # Ubuntu should notify of new message irespective of whether it's in current message list or not
@ -2235,8 +2233,8 @@ class MyForm(settingsmixin.SMainWindow):
email = str(self.dialog.ui.lineEditEmail.text().toUtf8()) email = str(self.dialog.ui.lineEditEmail.text().toUtf8())
# register resets address variables # register resets address variables
acct.register(email) acct.register(email)
shared.config.set(acct.fromAddress, 'label', email) BMConfigParser().set(acct.fromAddress, 'label', email)
shared.config.set(acct.fromAddress, 'gateway', 'mailchuck') BMConfigParser().set(acct.fromAddress, 'gateway', 'mailchuck')
shared.writeKeysFile() shared.writeKeysFile()
self.statusBar().showMessage(_translate( self.statusBar().showMessage(_translate(
"MainWindow", "Sending email gateway registration request"), 10000) "MainWindow", "Sending email gateway registration request"), 10000)
@ -2323,71 +2321,71 @@ class MyForm(settingsmixin.SMainWindow):
def click_actionSettings(self): def click_actionSettings(self):
self.settingsDialogInstance = settingsDialog(self) self.settingsDialogInstance = settingsDialog(self)
if self.settingsDialogInstance.exec_(): if self.settingsDialogInstance.exec_():
shared.config.set('bitmessagesettings', 'startonlogon', str( BMConfigParser().set('bitmessagesettings', 'startonlogon', str(
self.settingsDialogInstance.ui.checkBoxStartOnLogon.isChecked())) self.settingsDialogInstance.ui.checkBoxStartOnLogon.isChecked()))
shared.config.set('bitmessagesettings', 'minimizetotray', str( BMConfigParser().set('bitmessagesettings', 'minimizetotray', str(
self.settingsDialogInstance.ui.checkBoxMinimizeToTray.isChecked())) self.settingsDialogInstance.ui.checkBoxMinimizeToTray.isChecked()))
shared.config.set('bitmessagesettings', 'trayonclose', str( BMConfigParser().set('bitmessagesettings', 'trayonclose', str(
self.settingsDialogInstance.ui.checkBoxTrayOnClose.isChecked())) self.settingsDialogInstance.ui.checkBoxTrayOnClose.isChecked()))
shared.config.set('bitmessagesettings', 'hidetrayconnectionnotifications', str( BMConfigParser().set('bitmessagesettings', 'hidetrayconnectionnotifications', str(
self.settingsDialogInstance.ui.checkBoxHideTrayConnectionNotifications.isChecked())) self.settingsDialogInstance.ui.checkBoxHideTrayConnectionNotifications.isChecked()))
shared.config.set('bitmessagesettings', 'showtraynotifications', str( BMConfigParser().set('bitmessagesettings', 'showtraynotifications', str(
self.settingsDialogInstance.ui.checkBoxShowTrayNotifications.isChecked())) self.settingsDialogInstance.ui.checkBoxShowTrayNotifications.isChecked()))
shared.config.set('bitmessagesettings', 'startintray', str( BMConfigParser().set('bitmessagesettings', 'startintray', str(
self.settingsDialogInstance.ui.checkBoxStartInTray.isChecked())) self.settingsDialogInstance.ui.checkBoxStartInTray.isChecked()))
shared.config.set('bitmessagesettings', 'willinglysendtomobile', str( BMConfigParser().set('bitmessagesettings', 'willinglysendtomobile', str(
self.settingsDialogInstance.ui.checkBoxWillinglySendToMobile.isChecked())) self.settingsDialogInstance.ui.checkBoxWillinglySendToMobile.isChecked()))
shared.config.set('bitmessagesettings', 'useidenticons', str( BMConfigParser().set('bitmessagesettings', 'useidenticons', str(
self.settingsDialogInstance.ui.checkBoxUseIdenticons.isChecked())) self.settingsDialogInstance.ui.checkBoxUseIdenticons.isChecked()))
shared.config.set('bitmessagesettings', 'replybelow', str( BMConfigParser().set('bitmessagesettings', 'replybelow', str(
self.settingsDialogInstance.ui.checkBoxReplyBelow.isChecked())) self.settingsDialogInstance.ui.checkBoxReplyBelow.isChecked()))
lang = str(self.settingsDialogInstance.ui.languageComboBox.itemData(self.settingsDialogInstance.ui.languageComboBox.currentIndex()).toString()) lang = str(self.settingsDialogInstance.ui.languageComboBox.itemData(self.settingsDialogInstance.ui.languageComboBox.currentIndex()).toString())
shared.config.set('bitmessagesettings', 'userlocale', lang) BMConfigParser().set('bitmessagesettings', 'userlocale', lang)
change_translation(l10n.getTranslationLanguage()) change_translation(l10n.getTranslationLanguage())
if int(shared.config.get('bitmessagesettings', 'port')) != int(self.settingsDialogInstance.ui.lineEditTCPPort.text()): if int(BMConfigParser().get('bitmessagesettings', 'port')) != int(self.settingsDialogInstance.ui.lineEditTCPPort.text()):
if not shared.safeConfigGetBoolean('bitmessagesettings', 'dontconnect'): if not BMConfigParser().safeGetBoolean('bitmessagesettings', 'dontconnect'):
QMessageBox.about(self, _translate("MainWindow", "Restart"), _translate( QMessageBox.about(self, _translate("MainWindow", "Restart"), _translate(
"MainWindow", "You must restart Bitmessage for the port number change to take effect.")) "MainWindow", "You must restart Bitmessage for the port number change to take effect."))
shared.config.set('bitmessagesettings', 'port', str( BMConfigParser().set('bitmessagesettings', 'port', str(
self.settingsDialogInstance.ui.lineEditTCPPort.text())) self.settingsDialogInstance.ui.lineEditTCPPort.text()))
if self.settingsDialogInstance.ui.checkBoxUPnP.isChecked() != shared.safeConfigGetBoolean('bitmessagesettings', 'upnp'): if self.settingsDialogInstance.ui.checkBoxUPnP.isChecked() != BMConfigParser().safeGetBoolean('bitmessagesettings', 'upnp'):
shared.config.set('bitmessagesettings', 'upnp', str(self.settingsDialogInstance.ui.checkBoxUPnP.isChecked())) BMConfigParser().set('bitmessagesettings', 'upnp', str(self.settingsDialogInstance.ui.checkBoxUPnP.isChecked()))
if self.settingsDialogInstance.ui.checkBoxUPnP.isChecked(): if self.settingsDialogInstance.ui.checkBoxUPnP.isChecked():
import upnp import upnp
upnpThread = upnp.uPnPThread() upnpThread = upnp.uPnPThread()
upnpThread.start() upnpThread.start()
#print 'self.settingsDialogInstance.ui.comboBoxProxyType.currentText()', self.settingsDialogInstance.ui.comboBoxProxyType.currentText() #print 'self.settingsDialogInstance.ui.comboBoxProxyType.currentText()', self.settingsDialogInstance.ui.comboBoxProxyType.currentText()
#print 'self.settingsDialogInstance.ui.comboBoxProxyType.currentText())[0:5]', self.settingsDialogInstance.ui.comboBoxProxyType.currentText()[0:5] #print 'self.settingsDialogInstance.ui.comboBoxProxyType.currentText())[0:5]', self.settingsDialogInstance.ui.comboBoxProxyType.currentText()[0:5]
if shared.config.get('bitmessagesettings', 'socksproxytype') == 'none' and self.settingsDialogInstance.ui.comboBoxProxyType.currentText()[0:5] == 'SOCKS': if BMConfigParser().get('bitmessagesettings', 'socksproxytype') == 'none' and self.settingsDialogInstance.ui.comboBoxProxyType.currentText()[0:5] == 'SOCKS':
if shared.statusIconColor != 'red': if shared.statusIconColor != 'red':
QMessageBox.about(self, _translate("MainWindow", "Restart"), _translate( QMessageBox.about(self, _translate("MainWindow", "Restart"), _translate(
"MainWindow", "Bitmessage will use your proxy from now on but you may want to manually restart Bitmessage now to close existing connections (if any).")) "MainWindow", "Bitmessage will use your proxy from now on but you may want to manually restart Bitmessage now to close existing connections (if any)."))
if shared.config.get('bitmessagesettings', 'socksproxytype')[0:5] == 'SOCKS' and self.settingsDialogInstance.ui.comboBoxProxyType.currentText()[0:5] != 'SOCKS': if BMConfigParser().get('bitmessagesettings', 'socksproxytype')[0:5] == 'SOCKS' and self.settingsDialogInstance.ui.comboBoxProxyType.currentText()[0:5] != 'SOCKS':
self.statusBar().clearMessage() self.statusBar().clearMessage()
if self.settingsDialogInstance.ui.comboBoxProxyType.currentText()[0:5] == 'SOCKS': if self.settingsDialogInstance.ui.comboBoxProxyType.currentText()[0:5] == 'SOCKS':
shared.config.set('bitmessagesettings', 'socksproxytype', str( BMConfigParser().set('bitmessagesettings', 'socksproxytype', str(
self.settingsDialogInstance.ui.comboBoxProxyType.currentText())) self.settingsDialogInstance.ui.comboBoxProxyType.currentText()))
else: else:
shared.config.set('bitmessagesettings', 'socksproxytype', 'none') BMConfigParser().set('bitmessagesettings', 'socksproxytype', 'none')
shared.config.set('bitmessagesettings', 'socksauthentication', str( BMConfigParser().set('bitmessagesettings', 'socksauthentication', str(
self.settingsDialogInstance.ui.checkBoxAuthentication.isChecked())) self.settingsDialogInstance.ui.checkBoxAuthentication.isChecked()))
shared.config.set('bitmessagesettings', 'sockshostname', str( BMConfigParser().set('bitmessagesettings', 'sockshostname', str(
self.settingsDialogInstance.ui.lineEditSocksHostname.text())) self.settingsDialogInstance.ui.lineEditSocksHostname.text()))
shared.config.set('bitmessagesettings', 'socksport', str( BMConfigParser().set('bitmessagesettings', 'socksport', str(
self.settingsDialogInstance.ui.lineEditSocksPort.text())) self.settingsDialogInstance.ui.lineEditSocksPort.text()))
shared.config.set('bitmessagesettings', 'socksusername', str( BMConfigParser().set('bitmessagesettings', 'socksusername', str(
self.settingsDialogInstance.ui.lineEditSocksUsername.text())) self.settingsDialogInstance.ui.lineEditSocksUsername.text()))
shared.config.set('bitmessagesettings', 'sockspassword', str( BMConfigParser().set('bitmessagesettings', 'sockspassword', str(
self.settingsDialogInstance.ui.lineEditSocksPassword.text())) self.settingsDialogInstance.ui.lineEditSocksPassword.text()))
shared.config.set('bitmessagesettings', 'sockslisten', str( BMConfigParser().set('bitmessagesettings', 'sockslisten', str(
self.settingsDialogInstance.ui.checkBoxSocksListen.isChecked())) self.settingsDialogInstance.ui.checkBoxSocksListen.isChecked()))
try: try:
# Rounding to integers just for aesthetics # Rounding to integers just for aesthetics
shared.config.set('bitmessagesettings', 'maxdownloadrate', str( BMConfigParser().set('bitmessagesettings', 'maxdownloadrate', str(
int(float(self.settingsDialogInstance.ui.lineEditMaxDownloadRate.text())))) int(float(self.settingsDialogInstance.ui.lineEditMaxDownloadRate.text()))))
shared.config.set('bitmessagesettings', 'maxuploadrate', str( BMConfigParser().set('bitmessagesettings', 'maxuploadrate', str(
int(float(self.settingsDialogInstance.ui.lineEditMaxUploadRate.text())))) int(float(self.settingsDialogInstance.ui.lineEditMaxUploadRate.text()))))
except: except:
QMessageBox.about(self, _translate("MainWindow", "Number needed"), _translate( QMessageBox.about(self, _translate("MainWindow", "Number needed"), _translate(
@ -2395,50 +2393,50 @@ class MyForm(settingsmixin.SMainWindow):
try: try:
# Ensure we have an integer # Ensure we have an integer
PeterSurda commented 2017-01-11 21:10:54 +01:00 (Migrated from github.com)
Review

Instead of this whole exception handling, try something like
lineEditMaxOutboundConnections.setValidator(QIntValidator(1, 1024, lineEditMaxOutboundConnections))
in settings.py (1 being the lower limit, 1024 the top).

For a more complex example look into newchandialog.py and addressvalidator.py, in your case you don't need a new validator class, you can use the QIntValidator as it is.

Instead of this whole exception handling, try something like `lineEditMaxOutboundConnections.setValidator(QIntValidator(1, 1024, lineEditMaxOutboundConnections))` in settings.py (1 being the lower limit, 1024 the top). For a more complex example look into newchandialog.py and addressvalidator.py, in your case you don't need a new validator class, you can use the QIntValidator as it is.
Review

👍

👍
shared.config.set('bitmessagesettings', 'maxoutboundconnections', str( BMConfigParser().set('bitmessagesettings', 'maxoutboundconnections', str(
int(float(self.settingsDialogInstance.ui.lineEditMaxOutboundConnections.text())))) int(float(self.settingsDialogInstance.ui.lineEditMaxOutboundConnections.text()))))
except: except:
QMessageBox.about(self, _translate("MainWindow", "Number needed"), _translate( QMessageBox.about(self, _translate("MainWindow", "Number needed"), _translate(
"MainWindow", "Your maximum outbound connections must be a number. Ignoring what you typed.")) "MainWindow", "Your maximum outbound connections must be a number. Ignoring what you typed."))
shared.config.set('bitmessagesettings', 'namecoinrpctype', BMConfigParser().set('bitmessagesettings', 'namecoinrpctype',
self.settingsDialogInstance.getNamecoinType()) self.settingsDialogInstance.getNamecoinType())
shared.config.set('bitmessagesettings', 'namecoinrpchost', str( BMConfigParser().set('bitmessagesettings', 'namecoinrpchost', str(
self.settingsDialogInstance.ui.lineEditNamecoinHost.text())) self.settingsDialogInstance.ui.lineEditNamecoinHost.text()))
shared.config.set('bitmessagesettings', 'namecoinrpcport', str( BMConfigParser().set('bitmessagesettings', 'namecoinrpcport', str(
self.settingsDialogInstance.ui.lineEditNamecoinPort.text())) self.settingsDialogInstance.ui.lineEditNamecoinPort.text()))
shared.config.set('bitmessagesettings', 'namecoinrpcuser', str( BMConfigParser().set('bitmessagesettings', 'namecoinrpcuser', str(
self.settingsDialogInstance.ui.lineEditNamecoinUser.text())) self.settingsDialogInstance.ui.lineEditNamecoinUser.text()))
shared.config.set('bitmessagesettings', 'namecoinrpcpassword', str( BMConfigParser().set('bitmessagesettings', 'namecoinrpcpassword', str(
self.settingsDialogInstance.ui.lineEditNamecoinPassword.text())) self.settingsDialogInstance.ui.lineEditNamecoinPassword.text()))
# Demanded difficulty tab # Demanded difficulty tab
if float(self.settingsDialogInstance.ui.lineEditTotalDifficulty.text()) >= 1: if float(self.settingsDialogInstance.ui.lineEditTotalDifficulty.text()) >= 1:
shared.config.set('bitmessagesettings', 'defaultnoncetrialsperbyte', str(int(float( BMConfigParser().set('bitmessagesettings', 'defaultnoncetrialsperbyte', str(int(float(
self.settingsDialogInstance.ui.lineEditTotalDifficulty.text()) * shared.networkDefaultProofOfWorkNonceTrialsPerByte))) self.settingsDialogInstance.ui.lineEditTotalDifficulty.text()) * protocol.networkDefaultProofOfWorkNonceTrialsPerByte)))
if float(self.settingsDialogInstance.ui.lineEditSmallMessageDifficulty.text()) >= 1: if float(self.settingsDialogInstance.ui.lineEditSmallMessageDifficulty.text()) >= 1:
shared.config.set('bitmessagesettings', 'defaultpayloadlengthextrabytes', str(int(float( BMConfigParser().set('bitmessagesettings', 'defaultpayloadlengthextrabytes', str(int(float(
self.settingsDialogInstance.ui.lineEditSmallMessageDifficulty.text()) * shared.networkDefaultPayloadLengthExtraBytes))) self.settingsDialogInstance.ui.lineEditSmallMessageDifficulty.text()) * protocol.networkDefaultPayloadLengthExtraBytes)))
if self.settingsDialogInstance.ui.comboBoxOpenCL.currentText().toUtf8() != shared.safeConfigGet("bitmessagesettings", "opencl"): if self.settingsDialogInstance.ui.comboBoxOpenCL.currentText().toUtf8() != BMConfigParser().safeGet("bitmessagesettings", "opencl"):
shared.config.set('bitmessagesettings', 'opencl', str(self.settingsDialogInstance.ui.comboBoxOpenCL.currentText())) BMConfigParser().set('bitmessagesettings', 'opencl', str(self.settingsDialogInstance.ui.comboBoxOpenCL.currentText()))
acceptableDifficultyChanged = False acceptableDifficultyChanged = False
if float(self.settingsDialogInstance.ui.lineEditMaxAcceptableTotalDifficulty.text()) >= 1 or float(self.settingsDialogInstance.ui.lineEditMaxAcceptableTotalDifficulty.text()) == 0: if float(self.settingsDialogInstance.ui.lineEditMaxAcceptableTotalDifficulty.text()) >= 1 or float(self.settingsDialogInstance.ui.lineEditMaxAcceptableTotalDifficulty.text()) == 0:
if shared.config.get('bitmessagesettings','maxacceptablenoncetrialsperbyte') != str(int(float( if BMConfigParser().get('bitmessagesettings','maxacceptablenoncetrialsperbyte') != str(int(float(
self.settingsDialogInstance.ui.lineEditMaxAcceptableTotalDifficulty.text()) * shared.networkDefaultProofOfWorkNonceTrialsPerByte)): self.settingsDialogInstance.ui.lineEditMaxAcceptableTotalDifficulty.text()) * protocol.networkDefaultProofOfWorkNonceTrialsPerByte)):
# the user changed the max acceptable total difficulty # the user changed the max acceptable total difficulty
acceptableDifficultyChanged = True acceptableDifficultyChanged = True
shared.config.set('bitmessagesettings', 'maxacceptablenoncetrialsperbyte', str(int(float( BMConfigParser().set('bitmessagesettings', 'maxacceptablenoncetrialsperbyte', str(int(float(
self.settingsDialogInstance.ui.lineEditMaxAcceptableTotalDifficulty.text()) * shared.networkDefaultProofOfWorkNonceTrialsPerByte))) self.settingsDialogInstance.ui.lineEditMaxAcceptableTotalDifficulty.text()) * protocol.networkDefaultProofOfWorkNonceTrialsPerByte)))
if float(self.settingsDialogInstance.ui.lineEditMaxAcceptableSmallMessageDifficulty.text()) >= 1 or float(self.settingsDialogInstance.ui.lineEditMaxAcceptableSmallMessageDifficulty.text()) == 0: if float(self.settingsDialogInstance.ui.lineEditMaxAcceptableSmallMessageDifficulty.text()) >= 1 or float(self.settingsDialogInstance.ui.lineEditMaxAcceptableSmallMessageDifficulty.text()) == 0:
if shared.config.get('bitmessagesettings','maxacceptablepayloadlengthextrabytes') != str(int(float( if BMConfigParser().get('bitmessagesettings','maxacceptablepayloadlengthextrabytes') != str(int(float(
self.settingsDialogInstance.ui.lineEditMaxAcceptableSmallMessageDifficulty.text()) * shared.networkDefaultPayloadLengthExtraBytes)): self.settingsDialogInstance.ui.lineEditMaxAcceptableSmallMessageDifficulty.text()) * protocol.networkDefaultPayloadLengthExtraBytes)):
# the user changed the max acceptable small message difficulty # the user changed the max acceptable small message difficulty
acceptableDifficultyChanged = True acceptableDifficultyChanged = True
shared.config.set('bitmessagesettings', 'maxacceptablepayloadlengthextrabytes', str(int(float( BMConfigParser().set('bitmessagesettings', 'maxacceptablepayloadlengthextrabytes', str(int(float(
self.settingsDialogInstance.ui.lineEditMaxAcceptableSmallMessageDifficulty.text()) * shared.networkDefaultPayloadLengthExtraBytes))) self.settingsDialogInstance.ui.lineEditMaxAcceptableSmallMessageDifficulty.text()) * protocol.networkDefaultPayloadLengthExtraBytes)))
if acceptableDifficultyChanged: if acceptableDifficultyChanged:
# It might now be possible to send msgs which were previously marked as toodifficult. # It might now be possible to send msgs which were previously marked as toodifficult.
# Let us change them to 'msgqueued'. The singleWorker will try to send them and will again # Let us change them to 'msgqueued'. The singleWorker will try to send them and will again
@ -2450,8 +2448,8 @@ class MyForm(settingsmixin.SMainWindow):
#start:UI setting to stop trying to send messages after X days/months #start:UI setting to stop trying to send messages after X days/months
# I'm open to changing this UI to something else if someone has a better idea. # I'm open to changing this UI to something else if someone has a better idea.
if ((self.settingsDialogInstance.ui.lineEditDays.text()=='') and (self.settingsDialogInstance.ui.lineEditMonths.text()=='')):#We need to handle this special case. Bitmessage has its default behavior. The input is blank/blank if ((self.settingsDialogInstance.ui.lineEditDays.text()=='') and (self.settingsDialogInstance.ui.lineEditMonths.text()=='')):#We need to handle this special case. Bitmessage has its default behavior. The input is blank/blank
shared.config.set('bitmessagesettings', 'stopresendingafterxdays', '') BMConfigParser().set('bitmessagesettings', 'stopresendingafterxdays', '')
shared.config.set('bitmessagesettings', 'stopresendingafterxmonths', '') BMConfigParser().set('bitmessagesettings', 'stopresendingafterxmonths', '')
shared.maximumLengthOfTimeToBotherResendingMessages = float('inf') shared.maximumLengthOfTimeToBotherResendingMessages = float('inf')
try: try:
float(self.settingsDialogInstance.ui.lineEditDays.text()) float(self.settingsDialogInstance.ui.lineEditDays.text())
@ -2473,13 +2471,13 @@ class MyForm(settingsmixin.SMainWindow):
if shared.maximumLengthOfTimeToBotherResendingMessages < 432000: # If the time period is less than 5 hours, we give zero values to all fields. No message will be sent again. if shared.maximumLengthOfTimeToBotherResendingMessages < 432000: # If the time period is less than 5 hours, we give zero values to all fields. No message will be sent again.
QMessageBox.about(self, _translate("MainWindow", "Will not resend ever"), _translate( QMessageBox.about(self, _translate("MainWindow", "Will not resend ever"), _translate(
"MainWindow", "Note that the time limit you entered is less than the amount of time Bitmessage waits for the first resend attempt therefore your messages will never be resent.")) "MainWindow", "Note that the time limit you entered is less than the amount of time Bitmessage waits for the first resend attempt therefore your messages will never be resent."))
shared.config.set('bitmessagesettings', 'stopresendingafterxdays', '0') BMConfigParser().set('bitmessagesettings', 'stopresendingafterxdays', '0')
shared.config.set('bitmessagesettings', 'stopresendingafterxmonths', '0') BMConfigParser().set('bitmessagesettings', 'stopresendingafterxmonths', '0')
shared.maximumLengthOfTimeToBotherResendingMessages = 0 shared.maximumLengthOfTimeToBotherResendingMessages = 0
else: else:
shared.config.set('bitmessagesettings', 'stopresendingafterxdays', str(float( BMConfigParser().set('bitmessagesettings', 'stopresendingafterxdays', str(float(
self.settingsDialogInstance.ui.lineEditDays.text()))) self.settingsDialogInstance.ui.lineEditDays.text())))
shared.config.set('bitmessagesettings', 'stopresendingafterxmonths', str(float( BMConfigParser().set('bitmessagesettings', 'stopresendingafterxmonths', str(float(
self.settingsDialogInstance.ui.lineEditMonths.text()))) self.settingsDialogInstance.ui.lineEditMonths.text())))
shared.writeKeysFile() shared.writeKeysFile()
@ -2488,7 +2486,7 @@ class MyForm(settingsmixin.SMainWindow):
# Auto-startup for Windows # Auto-startup for Windows
RUN_PATH = "HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Run" RUN_PATH = "HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Run"
self.settings = QSettings(RUN_PATH, QSettings.NativeFormat) self.settings = QSettings(RUN_PATH, QSettings.NativeFormat)
if shared.config.getboolean('bitmessagesettings', 'startonlogon'): if BMConfigParser().getboolean('bitmessagesettings', 'startonlogon'):
self.settings.setValue("PyBitmessage", sys.argv[0]) self.settings.setValue("PyBitmessage", sys.argv[0])
else: else:
self.settings.remove("PyBitmessage") self.settings.remove("PyBitmessage")
@ -2499,21 +2497,21 @@ class MyForm(settingsmixin.SMainWindow):
# startup for linux # startup for linux
pass pass
if shared.appdata != shared.lookupExeFolder() and self.settingsDialogInstance.ui.checkBoxPortableMode.isChecked(): # If we are NOT using portable mode now but the user selected that we should... if state.appdata != paths.lookupExeFolder() and self.settingsDialogInstance.ui.checkBoxPortableMode.isChecked(): # If we are NOT using portable mode now but the user selected that we should...
# Write the keys.dat file to disk in the new location # Write the keys.dat file to disk in the new location
sqlStoredProcedure('movemessagstoprog') sqlStoredProcedure('movemessagstoprog')
with open(shared.lookupExeFolder() + 'keys.dat', 'wb') as configfile: with open(paths.lookupExeFolder() + 'keys.dat', 'wb') as configfile:
shared.config.write(configfile) BMConfigParser().write(configfile)
# Write the knownnodes.dat file to disk in the new location # Write the knownnodes.dat file to disk in the new location
shared.knownNodesLock.acquire() shared.knownNodesLock.acquire()
output = open(shared.lookupExeFolder() + 'knownnodes.dat', 'wb') output = open(paths.lookupExeFolder() + 'knownnodes.dat', 'wb')
pickle.dump(shared.knownNodes, output) pickle.dump(shared.knownNodes, output)
output.close() output.close()
shared.knownNodesLock.release() shared.knownNodesLock.release()
os.remove(shared.appdata + 'keys.dat') os.remove(state.appdata + 'keys.dat')
os.remove(shared.appdata + 'knownnodes.dat') os.remove(state.appdata + 'knownnodes.dat')
previousAppdataLocation = shared.appdata previousAppdataLocation = state.appdata
shared.appdata = shared.lookupExeFolder() state.appdata = paths.lookupExeFolder()
debug.restartLoggingInUpdatedAppdataLocation() debug.restartLoggingInUpdatedAppdataLocation()
try: try:
os.remove(previousAppdataLocation + 'debug.log') os.remove(previousAppdataLocation + 'debug.log')
@ -2521,25 +2519,25 @@ class MyForm(settingsmixin.SMainWindow):
except: except:
pass pass
if shared.appdata == shared.lookupExeFolder() and not self.settingsDialogInstance.ui.checkBoxPortableMode.isChecked(): # If we ARE using portable mode now but the user selected that we shouldn't... if state.appdata == paths.lookupExeFolder() and not self.settingsDialogInstance.ui.checkBoxPortableMode.isChecked(): # If we ARE using portable mode now but the user selected that we shouldn't...
shared.appdata = shared.lookupAppdataFolder() state.appdata = paths.lookupAppdataFolder()
if not os.path.exists(shared.appdata): if not os.path.exists(state.appdata):
os.makedirs(shared.appdata) os.makedirs(state.appdata)
sqlStoredProcedure('movemessagstoappdata') sqlStoredProcedure('movemessagstoappdata')
# Write the keys.dat file to disk in the new location # Write the keys.dat file to disk in the new location
shared.writeKeysFile() shared.writeKeysFile()
# Write the knownnodes.dat file to disk in the new location # Write the knownnodes.dat file to disk in the new location
shared.knownNodesLock.acquire() shared.knownNodesLock.acquire()
output = open(shared.appdata + 'knownnodes.dat', 'wb') output = open(state.appdata + 'knownnodes.dat', 'wb')
pickle.dump(shared.knownNodes, output) pickle.dump(shared.knownNodes, output)
output.close() output.close()
shared.knownNodesLock.release() shared.knownNodesLock.release()
os.remove(shared.lookupExeFolder() + 'keys.dat') os.remove(paths.lookupExeFolder() + 'keys.dat')
os.remove(shared.lookupExeFolder() + 'knownnodes.dat') os.remove(paths.lookupExeFolder() + 'knownnodes.dat')
debug.restartLoggingInUpdatedAppdataLocation() debug.restartLoggingInUpdatedAppdataLocation()
try: try:
os.remove(shared.lookupExeFolder() + 'debug.log') os.remove(paths.lookupExeFolder() + 'debug.log')
os.remove(shared.lookupExeFolder() + 'debug.log.1') os.remove(paths.lookupExeFolder() + 'debug.log.1')
except: except:
pass pass
@ -2548,21 +2546,21 @@ class MyForm(settingsmixin.SMainWindow):
# For Modal dialogs # For Modal dialogs
if self.dialog.exec_(): if self.dialog.exec_():
addressAtCurrentRow = self.getCurrentAccount() addressAtCurrentRow = self.getCurrentAccount()
if shared.safeConfigGetBoolean(addressAtCurrentRow, 'chan'): if BMConfigParser().safeGetBoolean(addressAtCurrentRow, 'chan'):
return return
if self.dialog.ui.radioButtonBehaveNormalAddress.isChecked(): if self.dialog.ui.radioButtonBehaveNormalAddress.isChecked():
shared.config.set(str( BMConfigParser().set(str(
addressAtCurrentRow), 'mailinglist', 'false') addressAtCurrentRow), 'mailinglist', 'false')
# Set the color to either black or grey # Set the color to either black or grey
if shared.config.getboolean(addressAtCurrentRow, 'enabled'): if BMConfigParser().getboolean(addressAtCurrentRow, 'enabled'):
self.setCurrentItemColor(QApplication.palette() self.setCurrentItemColor(QApplication.palette()
.text().color()) .text().color())
else: else:
self.setCurrentItemColor(QtGui.QColor(128, 128, 128)) self.setCurrentItemColor(QtGui.QColor(128, 128, 128))
else: else:
shared.config.set(str( BMConfigParser().set(str(
addressAtCurrentRow), 'mailinglist', 'true') addressAtCurrentRow), 'mailinglist', 'true')
shared.config.set(str(addressAtCurrentRow), 'mailinglistname', str( BMConfigParser().set(str(addressAtCurrentRow), 'mailinglistname', str(
self.dialog.ui.lineEditMailingListName.text().toUtf8())) self.dialog.ui.lineEditMailingListName.text().toUtf8()))
self.setCurrentItemColor(QtGui.QColor(137, 04, 177)) #magenta self.setCurrentItemColor(QtGui.QColor(137, 04, 177)) #magenta
self.rerenderComboBoxSendFrom() self.rerenderComboBoxSendFrom()
@ -2581,7 +2579,7 @@ class MyForm(settingsmixin.SMainWindow):
return return
if self.dialog.ui.radioButtonUnregister.isChecked() and isinstance(acct, GatewayAccount): if self.dialog.ui.radioButtonUnregister.isChecked() and isinstance(acct, GatewayAccount):
acct.unregister() acct.unregister()
shared.config.remove_option(addressAtCurrentRow, 'gateway') BMConfigParser().remove_option(addressAtCurrentRow, 'gateway')
shared.writeKeysFile() shared.writeKeysFile()
self.statusBar().showMessage(_translate( self.statusBar().showMessage(_translate(
"MainWindow", "Sending email gateway unregistration request"), 10000) "MainWindow", "Sending email gateway unregistration request"), 10000)
@ -2607,8 +2605,8 @@ class MyForm(settingsmixin.SMainWindow):
email = str(self.dialog.ui.lineEditEmail.text().toUtf8()) email = str(self.dialog.ui.lineEditEmail.text().toUtf8())
acct = MailchuckAccount(addressAtCurrentRow) acct = MailchuckAccount(addressAtCurrentRow)
acct.register(email) acct.register(email)
shared.config.set(addressAtCurrentRow, 'label', email) BMConfigParser().set(addressAtCurrentRow, 'label', email)
shared.config.set(addressAtCurrentRow, 'gateway', 'mailchuck') BMConfigParser().set(addressAtCurrentRow, 'gateway', 'mailchuck')
shared.writeKeysFile() shared.writeKeysFile()
self.statusBar().showMessage(_translate( self.statusBar().showMessage(_translate(
"MainWindow", "Sending email gateway registration request"), 10000) "MainWindow", "Sending email gateway registration request"), 10000)
@ -2826,7 +2824,7 @@ class MyForm(settingsmixin.SMainWindow):
trayonclose = False trayonclose = False
try: try:
trayonclose = shared.config.getboolean( trayonclose = BMConfigParser().getboolean(
'bitmessagesettings', 'trayonclose') 'bitmessagesettings', 'trayonclose')
except Exception: except Exception:
pass pass
@ -2901,7 +2899,7 @@ class MyForm(settingsmixin.SMainWindow):
# Format predefined text on message reply. # Format predefined text on message reply.
def quoted_text(self, message): def quoted_text(self, message):
if not shared.safeConfigGetBoolean('bitmessagesettings', 'replybelow'): if not BMConfigParser().safeGetBoolean('bitmessagesettings', 'replybelow'):
return '\n\n------------------------------------------------------\n' + message return '\n\n------------------------------------------------------\n' + message
quoteWrapper = textwrap.TextWrapper(replace_whitespace = False, quoteWrapper = textwrap.TextWrapper(replace_whitespace = False,
@ -2972,10 +2970,10 @@ class MyForm(settingsmixin.SMainWindow):
if toAddressAtCurrentInboxRow == str_broadcast_subscribers: if toAddressAtCurrentInboxRow == str_broadcast_subscribers:
self.ui.tabWidgetSend.setCurrentIndex(0) self.ui.tabWidgetSend.setCurrentIndex(0)
# toAddressAtCurrentInboxRow = fromAddressAtCurrentInboxRow # toAddressAtCurrentInboxRow = fromAddressAtCurrentInboxRow
elif not shared.config.has_section(toAddressAtCurrentInboxRow): elif not BMConfigParser().has_section(toAddressAtCurrentInboxRow):
QtGui.QMessageBox.information(self, _translate("MainWindow", "Address is gone"), _translate( QtGui.QMessageBox.information(self, _translate("MainWindow", "Address is gone"), _translate(
"MainWindow", "Bitmessage cannot find your address %1. Perhaps you removed it?").arg(toAddressAtCurrentInboxRow), QMessageBox.Ok) "MainWindow", "Bitmessage cannot find your address %1. Perhaps you removed it?").arg(toAddressAtCurrentInboxRow), QMessageBox.Ok)
elif not shared.config.getboolean(toAddressAtCurrentInboxRow, 'enabled'): elif not BMConfigParser().getboolean(toAddressAtCurrentInboxRow, 'enabled'):
QtGui.QMessageBox.information(self, _translate("MainWindow", "Address disabled"), _translate( QtGui.QMessageBox.information(self, _translate("MainWindow", "Address disabled"), _translate(
"MainWindow", "Error: The address from which you are trying to send is disabled. You\'ll have to enable it on the \'Your Identities\' tab before using it."), QMessageBox.Ok) "MainWindow", "Error: The address from which you are trying to send is disabled. You\'ll have to enable it on the \'Your Identities\' tab before using it."), QMessageBox.Ok)
else: else:
@ -3049,7 +3047,7 @@ class MyForm(settingsmixin.SMainWindow):
queryreturn = sqlQuery('''select * from blacklist where address=?''', queryreturn = sqlQuery('''select * from blacklist where address=?''',
addressAtCurrentInboxRow) addressAtCurrentInboxRow)
if queryreturn == []: if queryreturn == []:
label = "\"" + tableWidget.item(currentInboxRow, 2).subject + "\" in " + shared.config.get(recipientAddress, "label") label = "\"" + tableWidget.item(currentInboxRow, 2).subject + "\" in " + BMConfigParser().get(recipientAddress, "label")
sqlExecute('''INSERT INTO blacklist VALUES (?,?, ?)''', sqlExecute('''INSERT INTO blacklist VALUES (?,?, ?)''',
label, label,
addressAtCurrentInboxRow, True) addressAtCurrentInboxRow, True)
@ -3060,7 +3058,7 @@ class MyForm(settingsmixin.SMainWindow):
self.statusBar().showMessage(_translate( self.statusBar().showMessage(_translate(
"MainWindow", "Error: You cannot add the same address to your blacklist twice. Try renaming the existing one if you want."), 10000) "MainWindow", "Error: You cannot add the same address to your blacklist twice. Try renaming the existing one if you want."), 10000)
def deleteRowFromMessagelist(row = None, inventoryHash = None, ackData = None, messageLists = None): def deleteRowFromMessagelist(self, row = None, inventoryHash = None, ackData = None, messageLists = None):
if messageLists is None: if messageLists is None:
messageLists = (self.ui.tableWidgetInbox, self.ui.tableWidgetInboxChans, self.ui.tableWidgetInboxSubscriptions) messageLists = (self.ui.tableWidgetInbox, self.ui.tableWidgetInboxChans, self.ui.tableWidgetInboxSubscriptions)
elif type(messageLists) not in (list, tuple): elif type(messageLists) not in (list, tuple):
@ -3541,7 +3539,7 @@ class MyForm(settingsmixin.SMainWindow):
return # maybe in the future return # maybe in the future
elif account.type == AccountMixin.CHAN: elif account.type == AccountMixin.CHAN:
if QtGui.QMessageBox.question(self, "Delete channel?", _translate("MainWindow", "If you delete the channel, messages that you already received will become inaccessible. Maybe you can consider disabling the channel instead. Disabled channels will not receive new messages, but you can still view messages you already received.\n\nAre you sure you want to delete the channel?"), QMessageBox.Yes|QMessageBox.No) == QMessageBox.Yes: if QtGui.QMessageBox.question(self, "Delete channel?", _translate("MainWindow", "If you delete the channel, messages that you already received will become inaccessible. Maybe you can consider disabling the channel instead. Disabled channels will not receive new messages, but you can still view messages you already received.\n\nAre you sure you want to delete the channel?"), QMessageBox.Yes|QMessageBox.No) == QMessageBox.Yes:
shared.config.remove_section(str(account.address)) BMConfigParser().remove_section(str(account.address))
else: else:
return return
else: else:
@ -3561,7 +3559,7 @@ class MyForm(settingsmixin.SMainWindow):
account.setEnabled(True) account.setEnabled(True)
def enableIdentity(self, address): def enableIdentity(self, address):
shared.config.set(address, 'enabled', 'true') BMConfigParser().set(address, 'enabled', 'true')
shared.writeKeysFile() shared.writeKeysFile()
shared.reloadMyAddressHashes() shared.reloadMyAddressHashes()
self.rerenderAddressBook() self.rerenderAddressBook()
@ -3573,7 +3571,7 @@ class MyForm(settingsmixin.SMainWindow):
account.setEnabled(False) account.setEnabled(False)
def disableIdentity(self, address): def disableIdentity(self, address):
shared.config.set(str(address), 'enabled', 'false') BMConfigParser().set(str(address), 'enabled', 'false')
shared.writeKeysFile() shared.writeKeysFile()
shared.reloadMyAddressHashes() shared.reloadMyAddressHashes()
self.rerenderAddressBook() self.rerenderAddressBook()
@ -3627,8 +3625,8 @@ class MyForm(settingsmixin.SMainWindow):
currentRow, 0).setIcon(avatarize(addressAtCurrentRow)) currentRow, 0).setIcon(avatarize(addressAtCurrentRow))
def setAvatar(self, addressAtCurrentRow): def setAvatar(self, addressAtCurrentRow):
if not os.path.exists(shared.appdata + 'avatars/'): if not os.path.exists(state.appdata + 'avatars/'):
os.makedirs(shared.appdata + 'avatars/') os.makedirs(state.appdata + 'avatars/')
hash = hashlib.md5(addBMIfNotPresent(addressAtCurrentRow)).hexdigest() hash = hashlib.md5(addBMIfNotPresent(addressAtCurrentRow)).hexdigest()
extensions = ['PNG', 'GIF', 'JPG', 'JPEG', 'SVG', 'BMP', 'MNG', 'PBM', 'PGM', 'PPM', 'TIFF', 'XBM', 'XPM', 'TGA'] extensions = ['PNG', 'GIF', 'JPG', 'JPEG', 'SVG', 'BMP', 'MNG', 'PBM', 'PGM', 'PPM', 'TIFF', 'XBM', 'XPM', 'TGA']
# http://pyqt.sourceforge.net/Docs/PyQt4/qimagereader.html#supportedImageFormats # http://pyqt.sourceforge.net/Docs/PyQt4/qimagereader.html#supportedImageFormats
@ -3639,8 +3637,8 @@ class MyForm(settingsmixin.SMainWindow):
for ext in extensions: for ext in extensions:
filters += [ names[ext] + ' (*.' + ext.lower() + ')' ] filters += [ names[ext] + ' (*.' + ext.lower() + ')' ]
all_images_filter += [ '*.' + ext.lower() ] all_images_filter += [ '*.' + ext.lower() ]
upper = shared.appdata + 'avatars/' + hash + '.' + ext.upper() upper = state.appdata + 'avatars/' + hash + '.' + ext.upper()
lower = shared.appdata + 'avatars/' + hash + '.' + ext.lower() lower = state.appdata + 'avatars/' + hash + '.' + ext.lower()
if os.path.isfile(lower): if os.path.isfile(lower):
current_files += [lower] current_files += [lower]
elif os.path.isfile(upper): elif os.path.isfile(upper):
@ -3649,7 +3647,7 @@ class MyForm(settingsmixin.SMainWindow):
filters[1:1] = ['All files (*.*)'] filters[1:1] = ['All files (*.*)']
sourcefile = QFileDialog.getOpenFileName(self, _translate("MainWindow","Set avatar..."), filter = ';;'.join(filters)) sourcefile = QFileDialog.getOpenFileName(self, _translate("MainWindow","Set avatar..."), filter = ';;'.join(filters))
# determine the correct filename (note that avatars don't use the suffix) # determine the correct filename (note that avatars don't use the suffix)
destination = shared.appdata + 'avatars/' + hash + '.' + sourcefile.split('.')[-1] destination = state.appdata + 'avatars/' + hash + '.' + sourcefile.split('.')[-1]
exists = QtCore.QFile.exists(destination) exists = QtCore.QFile.exists(destination)
if sourcefile == '': if sourcefile == '':
# ask for removal of avatar # ask for removal of avatar
@ -3989,7 +3987,7 @@ class aboutDialog(QtGui.QDialog):
self.ui = Ui_aboutDialog() self.ui = Ui_aboutDialog()
self.ui.setupUi(self) self.ui.setupUi(self)
self.parent = parent self.parent = parent
self.ui.labelVersion.setText('version ' + shared.softwareVersion) self.ui.labelVersion.setText('version ' + softwareVersion)
class regenerateAddressesDialog(QtGui.QDialog): class regenerateAddressesDialog(QtGui.QDialog):
@ -4009,30 +4007,30 @@ class settingsDialog(QtGui.QDialog):
self.ui.setupUi(self) self.ui.setupUi(self)
self.parent = parent self.parent = parent
self.ui.checkBoxStartOnLogon.setChecked( self.ui.checkBoxStartOnLogon.setChecked(
shared.config.getboolean('bitmessagesettings', 'startonlogon')) BMConfigParser().getboolean('bitmessagesettings', 'startonlogon'))
self.ui.checkBoxMinimizeToTray.setChecked( self.ui.checkBoxMinimizeToTray.setChecked(
shared.config.getboolean('bitmessagesettings', 'minimizetotray')) BMConfigParser().getboolean('bitmessagesettings', 'minimizetotray'))
self.ui.checkBoxTrayOnClose.setChecked( self.ui.checkBoxTrayOnClose.setChecked(
shared.safeConfigGetBoolean('bitmessagesettings', 'trayonclose')) BMConfigParser().safeGetBoolean('bitmessagesettings', 'trayonclose'))
self.ui.checkBoxHideTrayConnectionNotifications.setChecked( self.ui.checkBoxHideTrayConnectionNotifications.setChecked(
shared.config.getboolean("bitmessagesettings", "hidetrayconnectionnotifications")) BMConfigParser().getboolean("bitmessagesettings", "hidetrayconnectionnotifications"))
self.ui.checkBoxShowTrayNotifications.setChecked( self.ui.checkBoxShowTrayNotifications.setChecked(
shared.config.getboolean('bitmessagesettings', 'showtraynotifications')) BMConfigParser().getboolean('bitmessagesettings', 'showtraynotifications'))
self.ui.checkBoxStartInTray.setChecked( self.ui.checkBoxStartInTray.setChecked(
shared.config.getboolean('bitmessagesettings', 'startintray')) BMConfigParser().getboolean('bitmessagesettings', 'startintray'))
self.ui.checkBoxWillinglySendToMobile.setChecked( self.ui.checkBoxWillinglySendToMobile.setChecked(
shared.safeConfigGetBoolean('bitmessagesettings', 'willinglysendtomobile')) BMConfigParser().safeGetBoolean('bitmessagesettings', 'willinglysendtomobile'))
self.ui.checkBoxUseIdenticons.setChecked( self.ui.checkBoxUseIdenticons.setChecked(
shared.safeConfigGetBoolean('bitmessagesettings', 'useidenticons')) BMConfigParser().safeGetBoolean('bitmessagesettings', 'useidenticons'))
self.ui.checkBoxReplyBelow.setChecked( self.ui.checkBoxReplyBelow.setChecked(
shared.safeConfigGetBoolean('bitmessagesettings', 'replybelow')) BMConfigParser().safeGetBoolean('bitmessagesettings', 'replybelow'))
if shared.appdata == shared.lookupExeFolder(): if state.appdata == paths.lookupExeFolder():
self.ui.checkBoxPortableMode.setChecked(True) self.ui.checkBoxPortableMode.setChecked(True)
else: else:
try: try:
import tempfile import tempfile
file = tempfile.NamedTemporaryFile(dir=shared.lookupExeFolder(), delete=True) file = tempfile.NamedTemporaryFile(dir=paths.lookupExeFolder(), delete=True)
file.close # should autodelete file.close # should autodelete
except: except:
self.ui.checkBoxPortableMode.setDisabled(True) self.ui.checkBoxPortableMode.setDisabled(True)
@ -4053,14 +4051,14 @@ class settingsDialog(QtGui.QDialog):
"MainWindow", "Start-on-login not yet supported on your OS.")) "MainWindow", "Start-on-login not yet supported on your OS."))
# On the Network settings tab: # On the Network settings tab:
self.ui.lineEditTCPPort.setText(str( self.ui.lineEditTCPPort.setText(str(
shared.config.get('bitmessagesettings', 'port'))) BMConfigParser().get('bitmessagesettings', 'port')))
self.ui.checkBoxUPnP.setChecked( self.ui.checkBoxUPnP.setChecked(
shared.safeConfigGetBoolean('bitmessagesettings', 'upnp')) BMConfigParser().safeGetBoolean('bitmessagesettings', 'upnp'))
self.ui.checkBoxAuthentication.setChecked(shared.config.getboolean( self.ui.checkBoxAuthentication.setChecked(BMConfigParser().getboolean(
'bitmessagesettings', 'socksauthentication')) 'bitmessagesettings', 'socksauthentication'))
self.ui.checkBoxSocksListen.setChecked(shared.config.getboolean( self.ui.checkBoxSocksListen.setChecked(BMConfigParser().getboolean(
'bitmessagesettings', 'sockslisten')) 'bitmessagesettings', 'sockslisten'))
if str(shared.config.get('bitmessagesettings', 'socksproxytype')) == 'none': if str(BMConfigParser().get('bitmessagesettings', 'socksproxytype')) == 'none':
self.ui.comboBoxProxyType.setCurrentIndex(0) self.ui.comboBoxProxyType.setCurrentIndex(0)
self.ui.lineEditSocksHostname.setEnabled(False) self.ui.lineEditSocksHostname.setEnabled(False)
self.ui.lineEditSocksPort.setEnabled(False) self.ui.lineEditSocksPort.setEnabled(False)
@ -4068,41 +4066,41 @@ class settingsDialog(QtGui.QDialog):
self.ui.lineEditSocksPassword.setEnabled(False) self.ui.lineEditSocksPassword.setEnabled(False)
self.ui.checkBoxAuthentication.setEnabled(False) self.ui.checkBoxAuthentication.setEnabled(False)
self.ui.checkBoxSocksListen.setEnabled(False) self.ui.checkBoxSocksListen.setEnabled(False)
elif str(shared.config.get('bitmessagesettings', 'socksproxytype')) == 'SOCKS4a': elif str(BMConfigParser().get('bitmessagesettings', 'socksproxytype')) == 'SOCKS4a':
self.ui.comboBoxProxyType.setCurrentIndex(1) self.ui.comboBoxProxyType.setCurrentIndex(1)
self.ui.lineEditTCPPort.setEnabled(False) self.ui.lineEditTCPPort.setEnabled(False)
elif str(shared.config.get('bitmessagesettings', 'socksproxytype')) == 'SOCKS5': elif str(BMConfigParser().get('bitmessagesettings', 'socksproxytype')) == 'SOCKS5':
self.ui.comboBoxProxyType.setCurrentIndex(2) self.ui.comboBoxProxyType.setCurrentIndex(2)
self.ui.lineEditTCPPort.setEnabled(False) self.ui.lineEditTCPPort.setEnabled(False)
self.ui.lineEditSocksHostname.setText(str( self.ui.lineEditSocksHostname.setText(str(
shared.config.get('bitmessagesettings', 'sockshostname'))) BMConfigParser().get('bitmessagesettings', 'sockshostname')))
self.ui.lineEditSocksPort.setText(str( self.ui.lineEditSocksPort.setText(str(
shared.config.get('bitmessagesettings', 'socksport'))) BMConfigParser().get('bitmessagesettings', 'socksport')))
self.ui.lineEditSocksUsername.setText(str( self.ui.lineEditSocksUsername.setText(str(
shared.config.get('bitmessagesettings', 'socksusername'))) BMConfigParser().get('bitmessagesettings', 'socksusername')))
self.ui.lineEditSocksPassword.setText(str( self.ui.lineEditSocksPassword.setText(str(
shared.config.get('bitmessagesettings', 'sockspassword'))) BMConfigParser().get('bitmessagesettings', 'sockspassword')))
QtCore.QObject.connect(self.ui.comboBoxProxyType, QtCore.SIGNAL( QtCore.QObject.connect(self.ui.comboBoxProxyType, QtCore.SIGNAL(
"currentIndexChanged(int)"), self.comboBoxProxyTypeChanged) "currentIndexChanged(int)"), self.comboBoxProxyTypeChanged)
self.ui.lineEditMaxOutboundConnections.setText(str( self.ui.lineEditMaxOutboundConnections.setText(str(
shared.config.get('bitmessagesettings', 'maxoutboundconnections'))) shared.config.get('bitmessagesettings', 'maxoutboundconnections')))
self.ui.lineEditMaxDownloadRate.setText(str( self.ui.lineEditMaxDownloadRate.setText(str(
shared.config.get('bitmessagesettings', 'maxdownloadrate'))) BMConfigParser().get('bitmessagesettings', 'maxdownloadrate')))
self.ui.lineEditMaxUploadRate.setText(str( self.ui.lineEditMaxUploadRate.setText(str(
shared.config.get('bitmessagesettings', 'maxuploadrate'))) BMConfigParser().get('bitmessagesettings', 'maxuploadrate')))
# Demanded difficulty tab # Demanded difficulty tab
self.ui.lineEditTotalDifficulty.setText(str((float(shared.config.getint( self.ui.lineEditTotalDifficulty.setText(str((float(BMConfigParser().getint(
'bitmessagesettings', 'defaultnoncetrialsperbyte')) / shared.networkDefaultProofOfWorkNonceTrialsPerByte))) 'bitmessagesettings', 'defaultnoncetrialsperbyte')) / protocol.networkDefaultProofOfWorkNonceTrialsPerByte)))
self.ui.lineEditSmallMessageDifficulty.setText(str((float(shared.config.getint( self.ui.lineEditSmallMessageDifficulty.setText(str((float(BMConfigParser().getint(
'bitmessagesettings', 'defaultpayloadlengthextrabytes')) / shared.networkDefaultPayloadLengthExtraBytes))) 'bitmessagesettings', 'defaultpayloadlengthextrabytes')) / protocol.networkDefaultPayloadLengthExtraBytes)))
# Max acceptable difficulty tab # Max acceptable difficulty tab
self.ui.lineEditMaxAcceptableTotalDifficulty.setText(str((float(shared.config.getint( self.ui.lineEditMaxAcceptableTotalDifficulty.setText(str((float(BMConfigParser().getint(
'bitmessagesettings', 'maxacceptablenoncetrialsperbyte')) / shared.networkDefaultProofOfWorkNonceTrialsPerByte))) 'bitmessagesettings', 'maxacceptablenoncetrialsperbyte')) / protocol.networkDefaultProofOfWorkNonceTrialsPerByte)))
self.ui.lineEditMaxAcceptableSmallMessageDifficulty.setText(str((float(shared.config.getint( self.ui.lineEditMaxAcceptableSmallMessageDifficulty.setText(str((float(BMConfigParser().getint(
'bitmessagesettings', 'maxacceptablepayloadlengthextrabytes')) / shared.networkDefaultPayloadLengthExtraBytes))) 'bitmessagesettings', 'maxacceptablepayloadlengthextrabytes')) / protocol.networkDefaultPayloadLengthExtraBytes)))
# OpenCL # OpenCL
if openclpow.openclAvailable(): if openclpow.openclAvailable():
@ -4114,20 +4112,20 @@ class settingsDialog(QtGui.QDialog):
self.ui.comboBoxOpenCL.addItems(openclpow.vendors) self.ui.comboBoxOpenCL.addItems(openclpow.vendors)
self.ui.comboBoxOpenCL.setCurrentIndex(0) self.ui.comboBoxOpenCL.setCurrentIndex(0)
for i in range(self.ui.comboBoxOpenCL.count()): for i in range(self.ui.comboBoxOpenCL.count()):
if self.ui.comboBoxOpenCL.itemText(i) == shared.safeConfigGet('bitmessagesettings', 'opencl'): if self.ui.comboBoxOpenCL.itemText(i) == BMConfigParser().safeGet('bitmessagesettings', 'opencl'):
self.ui.comboBoxOpenCL.setCurrentIndex(i) self.ui.comboBoxOpenCL.setCurrentIndex(i)
break break
# Namecoin integration tab # Namecoin integration tab
nmctype = shared.config.get('bitmessagesettings', 'namecoinrpctype') nmctype = BMConfigParser().get('bitmessagesettings', 'namecoinrpctype')
self.ui.lineEditNamecoinHost.setText(str( self.ui.lineEditNamecoinHost.setText(str(
shared.config.get('bitmessagesettings', 'namecoinrpchost'))) BMConfigParser().get('bitmessagesettings', 'namecoinrpchost')))
self.ui.lineEditNamecoinPort.setText(str( self.ui.lineEditNamecoinPort.setText(str(
shared.config.get('bitmessagesettings', 'namecoinrpcport'))) BMConfigParser().get('bitmessagesettings', 'namecoinrpcport')))
self.ui.lineEditNamecoinUser.setText(str( self.ui.lineEditNamecoinUser.setText(str(
shared.config.get('bitmessagesettings', 'namecoinrpcuser'))) BMConfigParser().get('bitmessagesettings', 'namecoinrpcuser')))
self.ui.lineEditNamecoinPassword.setText(str( self.ui.lineEditNamecoinPassword.setText(str(
shared.config.get('bitmessagesettings', 'namecoinrpcpassword'))) BMConfigParser().get('bitmessagesettings', 'namecoinrpcpassword')))
if nmctype == "namecoind": if nmctype == "namecoind":
self.ui.radioButtonNamecoinNamecoind.setChecked(True) self.ui.radioButtonNamecoinNamecoind.setChecked(True)
@ -4149,14 +4147,14 @@ class settingsDialog(QtGui.QDialog):
#Message Resend tab #Message Resend tab
self.ui.lineEditDays.setText(str( self.ui.lineEditDays.setText(str(
shared.config.get('bitmessagesettings', 'stopresendingafterxdays'))) BMConfigParser().get('bitmessagesettings', 'stopresendingafterxdays')))
self.ui.lineEditMonths.setText(str( self.ui.lineEditMonths.setText(str(
shared.config.get('bitmessagesettings', 'stopresendingafterxmonths'))) BMConfigParser().get('bitmessagesettings', 'stopresendingafterxmonths')))
#'System' tab removed for now. #'System' tab removed for now.
"""try: """try:
maxCores = shared.config.getint('bitmessagesettings', 'maxcores') maxCores = BMConfigParser().getint('bitmessagesettings', 'maxcores')
except: except:
maxCores = 99999 maxCores = 99999
if maxCores <= 1: if maxCores <= 1:
@ -4245,13 +4243,13 @@ class SpecialAddressBehaviorDialog(QtGui.QDialog):
self.ui.setupUi(self) self.ui.setupUi(self)
self.parent = parent self.parent = parent
addressAtCurrentRow = parent.getCurrentAccount() addressAtCurrentRow = parent.getCurrentAccount()
if not shared.safeConfigGetBoolean(addressAtCurrentRow, 'chan'): if not BMConfigParser().safeGetBoolean(addressAtCurrentRow, 'chan'):
if shared.safeConfigGetBoolean(addressAtCurrentRow, 'mailinglist'): if BMConfigParser().safeGetBoolean(addressAtCurrentRow, 'mailinglist'):
self.ui.radioButtonBehaviorMailingList.click() self.ui.radioButtonBehaviorMailingList.click()
else: else:
self.ui.radioButtonBehaveNormalAddress.click() self.ui.radioButtonBehaveNormalAddress.click()
try: try:
mailingListName = shared.config.get( mailingListName = BMConfigParser().get(
addressAtCurrentRow, 'mailinglistname') addressAtCurrentRow, 'mailinglistname')
except: except:
mailingListName = '' mailingListName = ''
@ -4282,7 +4280,7 @@ class EmailGatewayDialog(QtGui.QDialog):
self.ui.radioButtonStatus.setEnabled(False) self.ui.radioButtonStatus.setEnabled(False)
self.ui.radioButtonSettings.setEnabled(False) self.ui.radioButtonSettings.setEnabled(False)
self.ui.radioButtonUnregister.setEnabled(False) self.ui.radioButtonUnregister.setEnabled(False)
label = shared.config.get(addressAtCurrentRow, 'label') label = BMConfigParser().get(addressAtCurrentRow, 'label')
if label.find("@mailchuck.com") > -1: if label.find("@mailchuck.com") > -1:
self.ui.lineEditEmail.setText(label) self.ui.lineEditEmail.setText(label)
@ -4387,7 +4385,7 @@ class iconGlossaryDialog(QtGui.QDialog):
self.ui.setupUi(self) self.ui.setupUi(self)
self.parent = parent self.parent = parent
self.ui.labelPortNumber.setText(_translate( self.ui.labelPortNumber.setText(_translate(
"MainWindow", "You are using TCP port %1. (This can be changed in the settings).").arg(str(shared.config.getint('bitmessagesettings', 'port')))) "MainWindow", "You are using TCP port %1. (This can be changed in the settings).").arg(str(BMConfigParser().getint('bitmessagesettings', 'port'))))
QtGui.QWidget.resize(self, QtGui.QWidget.sizeHint(self)) QtGui.QWidget.resize(self, QtGui.QWidget.sizeHint(self))
@ -4438,7 +4436,7 @@ class MySingleApplication(QApplication):
# Checks if there's an instance of the local server id running # Checks if there's an instance of the local server id running
if self.is_running: if self.is_running:
# This should be ignored, singleton.py will take care of exiting me. # This should be ignored, singleinstance.py will take care of exiting me.
pass pass
else: else:
# Nope, create a local server with this id and assign on_new_connection # Nope, create a local server with this id and assign on_new_connection
@ -4452,7 +4450,6 @@ class MySingleApplication(QApplication):
self.server.close() self.server.close()
def on_new_connection(self): def on_new_connection(self):
global myapp
if myapp: if myapp:
myapp.appIndicatorShow() myapp.appIndicatorShow()
@ -4472,17 +4469,17 @@ def run():
myapp.appIndicatorInit(app) myapp.appIndicatorInit(app)
myapp.ubuntuMessagingMenuInit() myapp.ubuntuMessagingMenuInit()
myapp.notifierInit() myapp.notifierInit()
if shared.safeConfigGetBoolean('bitmessagesettings', 'dontconnect'): if BMConfigParser().safeGetBoolean('bitmessagesettings', 'dontconnect'):
myapp.showConnectDialog() # ask the user if we may connect myapp.showConnectDialog() # ask the user if we may connect
# try: # try:
# if shared.config.get('bitmessagesettings', 'mailchuck') < 1: # if BMConfigParser().get('bitmessagesettings', 'mailchuck') < 1:
# myapp.showMigrationWizard(shared.config.get('bitmessagesettings', 'mailchuck')) # myapp.showMigrationWizard(BMConfigParser().get('bitmessagesettings', 'mailchuck'))
# except: # except:
# myapp.showMigrationWizard(0) # myapp.showMigrationWizard(0)
# only show after wizards and connect dialogs have completed # only show after wizards and connect dialogs have completed
if not shared.config.getboolean('bitmessagesettings', 'startintray'): if not BMConfigParser().getboolean('bitmessagesettings', 'startintray'):
myapp.show() myapp.show()
sys.exit(app.exec_()) sys.exit(app.exec_())

View File

@ -6,15 +6,16 @@ import sys
import inspect import inspect
from helper_sql import * from helper_sql import *
from addresses import decodeAddress from addresses import decodeAddress
from configparser import BMConfigParser
from foldertree import AccountMixin from foldertree import AccountMixin
from pyelliptic.openssl import OpenSSL from pyelliptic.openssl import OpenSSL
from utils import str_broadcast_subscribers from utils import str_broadcast_subscribers
import time import time
def getSortedAccounts(): def getSortedAccounts():
configSections = filter(lambda x: x != 'bitmessagesettings', shared.config.sections()) configSections = filter(lambda x: x != 'bitmessagesettings', BMConfigParser().sections())
configSections.sort(cmp = configSections.sort(cmp =
lambda x,y: cmp(unicode(shared.config.get(x, 'label'), 'utf-8').lower(), unicode(shared.config.get(y, 'label'), 'utf-8').lower()) lambda x,y: cmp(unicode(BMConfigParser().get(x, 'label'), 'utf-8').lower(), unicode(BMConfigParser().get(y, 'label'), 'utf-8').lower())
) )
return configSections return configSections
@ -44,7 +45,7 @@ def getSortedSubscriptions(count = False):
return ret return ret
def accountClass(address): def accountClass(address):
if not shared.config.has_section(address): if not BMConfigParser().has_section(address):
# FIXME: This BROADCAST section makes no sense # FIXME: This BROADCAST section makes no sense
if address == str_broadcast_subscribers: if address == str_broadcast_subscribers:
subscription = BroadcastAccount(address) subscription = BroadcastAccount(address)
@ -56,7 +57,7 @@ def accountClass(address):
return None return None
return subscription return subscription
try: try:
gateway = shared.config.get(address, "gateway") gateway = BMConfigParser().get(address, "gateway")
for name, cls in inspect.getmembers(sys.modules[__name__], inspect.isclass): for name, cls in inspect.getmembers(sys.modules[__name__], inspect.isclass):
# obj = g(address) # obj = g(address)
if issubclass(cls, GatewayAccount) and cls.gatewayName == gateway: if issubclass(cls, GatewayAccount) and cls.gatewayName == gateway:
@ -75,9 +76,9 @@ class AccountColor(AccountMixin):
if type is None: if type is None:
if address is None: if address is None:
self.type = AccountMixin.ALL self.type = AccountMixin.ALL
elif shared.safeConfigGetBoolean(self.address, 'mailinglist'): elif BMConfigParser().safeGetBoolean(self.address, 'mailinglist'):
self.type = AccountMixin.MAILINGLIST self.type = AccountMixin.MAILINGLIST
elif shared.safeConfigGetBoolean(self.address, 'chan'): elif BMConfigParser().safeGetBoolean(self.address, 'chan'):
self.type = AccountMixin.CHAN self.type = AccountMixin.CHAN
elif sqlQuery( elif sqlQuery(
'''select label from subscriptions where address=?''', self.address): '''select label from subscriptions where address=?''', self.address):
@ -92,10 +93,10 @@ class BMAccount(object):
def __init__(self, address = None): def __init__(self, address = None):
self.address = address self.address = address
self.type = AccountMixin.NORMAL self.type = AccountMixin.NORMAL
if shared.config.has_section(address): if BMConfigParser().has_section(address):
if shared.safeConfigGetBoolean(self.address, 'chan'): if BMConfigParser().safeGetBoolean(self.address, 'chan'):
self.type = AccountMixin.CHAN self.type = AccountMixin.CHAN
elif shared.safeConfigGetBoolean(self.address, 'mailinglist'): elif BMConfigParser().safeGetBoolean(self.address, 'mailinglist'):
self.type = AccountMixin.MAILINGLIST self.type = AccountMixin.MAILINGLIST
elif self.address == str_broadcast_subscribers: elif self.address == str_broadcast_subscribers:
self.type = AccountMixin.BROADCAST self.type = AccountMixin.BROADCAST
@ -109,8 +110,8 @@ class BMAccount(object):
if address is None: if address is None:
address = self.address address = self.address
label = address label = address
if shared.config.has_section(address): if BMConfigParser().has_section(address):
label = shared.config.get(address, 'label') label = BMConfigParser().get(address, 'label')
queryreturn = sqlQuery( queryreturn = sqlQuery(
'''select label from addressbook where address=?''', address) '''select label from addressbook where address=?''', address)
if queryreturn != []: if queryreturn != []:
@ -146,7 +147,7 @@ class GatewayAccount(BMAccount):
ALL_OK = 0 ALL_OK = 0
REGISTRATION_DENIED = 1 REGISTRATION_DENIED = 1
def __init__(self, address): def __init__(self, address):
super(BMAccount, self).__init__(address) super(GatewayAccount, self).__init__(address)
def send(self): def send(self):
status, addressVersionNumber, streamNumber, ripe = decodeAddress(self.toAddress) status, addressVersionNumber, streamNumber, ripe = decodeAddress(self.toAddress)
@ -168,13 +169,13 @@ class GatewayAccount(BMAccount):
0, # retryNumber 0, # retryNumber
'sent', # folder 'sent', # folder
2, # encodingtype 2, # encodingtype
min(shared.config.getint('bitmessagesettings', 'ttl'), 86400 * 2) # not necessary to have a TTL higher than 2 days min(BMConfigParser().getint('bitmessagesettings', 'ttl'), 86400 * 2) # not necessary to have a TTL higher than 2 days
) )
shared.workerQueue.put(('sendmessage', self.toAddress)) shared.workerQueue.put(('sendmessage', self.toAddress))
def parseMessage(self, toAddress, fromAddress, subject, message): def parseMessage(self, toAddress, fromAddress, subject, message):
super(BMAccount, self).parseMessage(toAddress, fromAddress, subject, message) super(GatewayAccount, self).parseMessage(toAddress, fromAddress, subject, message)
class MailchuckAccount(GatewayAccount): class MailchuckAccount(GatewayAccount):
# set "gateway" in keys.dat to this # set "gateway" in keys.dat to this
@ -185,7 +186,7 @@ class MailchuckAccount(GatewayAccount):
regExpIncoming = re.compile("(.*)MAILCHUCK-FROM::(\S+) \| (.*)") regExpIncoming = re.compile("(.*)MAILCHUCK-FROM::(\S+) \| (.*)")
regExpOutgoing = re.compile("(\S+) (.*)") regExpOutgoing = re.compile("(\S+) (.*)")
def __init__(self, address): def __init__(self, address):
super(GatewayAccount, self).__init__(address) super(MailchuckAccount, self).__init__(address)
self.feedback = self.ALL_OK self.feedback = self.ALL_OK
def createMessage(self, toAddress, fromAddress, subject, message): def createMessage(self, toAddress, fromAddress, subject, message):
@ -261,7 +262,7 @@ class MailchuckAccount(GatewayAccount):
self.fromAddress = self.address self.fromAddress = self.address
def parseMessage(self, toAddress, fromAddress, subject, message): def parseMessage(self, toAddress, fromAddress, subject, message):
super(GatewayAccount, self).parseMessage(toAddress, fromAddress, subject, message) super(MailchuckAccount, self).parseMessage(toAddress, fromAddress, subject, message)
if fromAddress == self.relayAddress: if fromAddress == self.relayAddress:
matches = self.regExpIncoming.search(subject) matches = self.regExpIncoming.search(subject)
if not matches is None: if not matches is None:

View File

@ -8,13 +8,13 @@
# WARNING! All changes made in this file will be lost! # WARNING! All changes made in this file will be lost!
from PyQt4 import QtCore, QtGui from PyQt4 import QtCore, QtGui
from configparser import BMConfigParser
from foldertree import AddressBookCompleter from foldertree import AddressBookCompleter
from messageview import MessageView from messageview import MessageView
from messagecompose import MessageCompose from messagecompose import MessageCompose
import settingsmixin import settingsmixin
from networkstatus import NetworkStatus from networkstatus import NetworkStatus
from blacklist import Blacklist from blacklist import Blacklist
import shared
try: try:
_fromUtf8 = QtCore.QString.fromUtf8 _fromUtf8 = QtCore.QString.fromUtf8
@ -556,7 +556,7 @@ class Ui_MainWindow(object):
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"), "")
# Initialize the Blacklist or Whitelist # Initialize the Blacklist or Whitelist
if shared.config.get('bitmessagesettings', 'blackwhitelist') == 'white': if BMConfigParser().get('bitmessagesettings', 'blackwhitelist') == 'white':
self.blackwhitelist.radioButtonWhitelist.click() self.blackwhitelist.radioButtonWhitelist.click()
self.blackwhitelist.rerenderBlackWhiteList() self.blackwhitelist.rerenderBlackWhiteList()
@ -680,7 +680,7 @@ class Ui_MainWindow(object):
self.pushButtonTTL.setText(_translate("MainWindow", "TTL:", None)) self.pushButtonTTL.setText(_translate("MainWindow", "TTL:", None))
hours = 48 hours = 48
try: try:
hours = int(shared.config.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))

View File

@ -2,9 +2,9 @@ from PyQt4 import QtCore, QtGui
import shared import shared
from tr import _translate from tr import _translate
import l10n import l10n
from uisignaler import UISignaler
import widgets import widgets
from addresses import addBMIfNotPresent from addresses import addBMIfNotPresent
from configparser import BMConfigParser
from dialogs import AddAddressDialog from dialogs import AddAddressDialog
from helper_sql import sqlExecute, sqlQuery from helper_sql import sqlExecute, sqlQuery
from retranslateui import RetranslateMixin from retranslateui import RetranslateMixin
@ -39,16 +39,16 @@ class Blacklist(QtGui.QWidget, RetranslateMixin):
"rerenderBlackWhiteList()"), self.rerenderBlackWhiteList) "rerenderBlackWhiteList()"), self.rerenderBlackWhiteList)
def click_radioButtonBlacklist(self): def click_radioButtonBlacklist(self):
if shared.config.get('bitmessagesettings', 'blackwhitelist') == 'white': if BMConfigParser().get('bitmessagesettings', 'blackwhitelist') == 'white':
shared.config.set('bitmessagesettings', 'blackwhitelist', 'black') BMConfigParser().set('bitmessagesettings', 'blackwhitelist', 'black')
shared.writeKeysFile() shared.writeKeysFile()
# self.tableWidgetBlacklist.clearContents() # self.tableWidgetBlacklist.clearContents()
self.tableWidgetBlacklist.setRowCount(0) self.tableWidgetBlacklist.setRowCount(0)
self.rerenderBlackWhiteList() self.rerenderBlackWhiteList()
def click_radioButtonWhitelist(self): def click_radioButtonWhitelist(self):
if shared.config.get('bitmessagesettings', 'blackwhitelist') == 'black': if BMConfigParser().get('bitmessagesettings', 'blackwhitelist') == 'black':
shared.config.set('bitmessagesettings', 'blackwhitelist', 'white') BMConfigParser().set('bitmessagesettings', 'blackwhitelist', 'white')
shared.writeKeysFile() shared.writeKeysFile()
# self.tableWidgetBlacklist.clearContents() # self.tableWidgetBlacklist.clearContents()
self.tableWidgetBlacklist.setRowCount(0) self.tableWidgetBlacklist.setRowCount(0)
@ -64,7 +64,7 @@ class Blacklist(QtGui.QWidget, RetranslateMixin):
# address book. The user cannot add it again or else it will # address book. The user cannot add it again or else it will
# cause problems when updating and deleting the entry. # cause problems when updating and deleting the entry.
t = (address,) t = (address,)
if shared.config.get('bitmessagesettings', 'blackwhitelist') == 'black': if BMConfigParser().get('bitmessagesettings', 'blackwhitelist') == 'black':
sql = '''select * from blacklist where address=?''' sql = '''select * from blacklist where address=?'''
else: else:
sql = '''select * from whitelist where address=?''' sql = '''select * from whitelist where address=?'''
@ -82,7 +82,7 @@ class Blacklist(QtGui.QWidget, RetranslateMixin):
self.tableWidgetBlacklist.setItem(0, 1, newItem) self.tableWidgetBlacklist.setItem(0, 1, newItem)
self.tableWidgetBlacklist.setSortingEnabled(True) self.tableWidgetBlacklist.setSortingEnabled(True)
t = (str(self.NewBlacklistDialogInstance.ui.newAddressLabel.text().toUtf8()), address, True) t = (str(self.NewBlacklistDialogInstance.ui.newAddressLabel.text().toUtf8()), address, True)
if shared.config.get('bitmessagesettings', 'blackwhitelist') == 'black': if BMConfigParser().get('bitmessagesettings', 'blackwhitelist') == 'black':
sql = '''INSERT INTO blacklist VALUES (?,?,?)''' sql = '''INSERT INTO blacklist VALUES (?,?,?)'''
else: else:
sql = '''INSERT INTO whitelist VALUES (?,?,?)''' sql = '''INSERT INTO whitelist VALUES (?,?,?)'''
@ -147,12 +147,12 @@ class Blacklist(QtGui.QWidget, RetranslateMixin):
def rerenderBlackWhiteList(self): def rerenderBlackWhiteList(self):
tabs = self.parent().parent() tabs = self.parent().parent()
if shared.config.get('bitmessagesettings', 'blackwhitelist') == 'black': if BMConfigParser().get('bitmessagesettings', 'blackwhitelist') == 'black':
tabs.setTabText(tabs.indexOf(self), _translate('blacklist', 'Blacklist')) tabs.setTabText(tabs.indexOf(self), _translate('blacklist', 'Blacklist'))
else: else:
tabs.setTabText(tabs.indexOf(self), _translate('blacklist', 'Whitelist')) tabs.setTabText(tabs.indexOf(self), _translate('blacklist', 'Whitelist'))
self.tableWidgetBlacklist.setRowCount(0) self.tableWidgetBlacklist.setRowCount(0)
listType = shared.config.get('bitmessagesettings', 'blackwhitelist') listType = BMConfigParser().get('bitmessagesettings', 'blackwhitelist')
if listType == 'black': if listType == 'black':
queryreturn = sqlQuery('''SELECT label, address, enabled FROM blacklist''') queryreturn = sqlQuery('''SELECT label, address, enabled FROM blacklist''')
else: else:
@ -184,7 +184,7 @@ class Blacklist(QtGui.QWidget, RetranslateMixin):
currentRow, 0).text().toUtf8() currentRow, 0).text().toUtf8()
addressAtCurrentRow = self.tableWidgetBlacklist.item( addressAtCurrentRow = self.tableWidgetBlacklist.item(
currentRow, 1).text() currentRow, 1).text()
if shared.config.get('bitmessagesettings', 'blackwhitelist') == 'black': if BMConfigParser().get('bitmessagesettings', 'blackwhitelist') == 'black':
sqlExecute( sqlExecute(
'''DELETE FROM blacklist WHERE label=? AND address=?''', '''DELETE FROM blacklist WHERE label=? AND address=?''',
str(labelAtCurrentRow), str(addressAtCurrentRow)) str(labelAtCurrentRow), str(addressAtCurrentRow))
@ -213,7 +213,7 @@ class Blacklist(QtGui.QWidget, RetranslateMixin):
currentRow, 0).setTextColor(QtGui.QApplication.palette().text().color()) currentRow, 0).setTextColor(QtGui.QApplication.palette().text().color())
self.tableWidgetBlacklist.item( self.tableWidgetBlacklist.item(
currentRow, 1).setTextColor(QtGui.QApplication.palette().text().color()) currentRow, 1).setTextColor(QtGui.QApplication.palette().text().color())
if shared.config.get('bitmessagesettings', 'blackwhitelist') == 'black': if BMConfigParser().get('bitmessagesettings', 'blackwhitelist') == 'black':
sqlExecute( sqlExecute(
'''UPDATE blacklist SET enabled=1 WHERE address=?''', '''UPDATE blacklist SET enabled=1 WHERE address=?''',
str(addressAtCurrentRow)) str(addressAtCurrentRow))
@ -230,7 +230,7 @@ class Blacklist(QtGui.QWidget, RetranslateMixin):
currentRow, 0).setTextColor(QtGui.QColor(128, 128, 128)) currentRow, 0).setTextColor(QtGui.QColor(128, 128, 128))
self.tableWidgetBlacklist.item( self.tableWidgetBlacklist.item(
currentRow, 1).setTextColor(QtGui.QColor(128, 128, 128)) currentRow, 1).setTextColor(QtGui.QColor(128, 128, 128))
if shared.config.get('bitmessagesettings', 'blackwhitelist') == 'black': if BMConfigParser().get('bitmessagesettings', 'blackwhitelist') == 'black':
sqlExecute( sqlExecute(
'''UPDATE blacklist SET enabled=0 WHERE address=?''', str(addressAtCurrentRow)) '''UPDATE blacklist SET enabled=0 WHERE address=?''', str(addressAtCurrentRow))
else: else:

View File

@ -1,6 +1,7 @@
from PyQt4 import QtCore, QtGui from PyQt4 import QtCore, QtGui
from string import find, rfind, rstrip, lstrip from string import find, rfind, rstrip, lstrip
from configparser import BMConfigParser
from helper_sql import * from helper_sql import *
from utils import * from utils import *
import shared import shared
@ -69,9 +70,9 @@ class AccountMixin (object):
if self.address is None: if self.address is None:
self.type = self.ALL self.type = self.ALL
self.setFlags(self.flags() & ~QtCore.Qt.ItemIsEditable) self.setFlags(self.flags() & ~QtCore.Qt.ItemIsEditable)
elif shared.safeConfigGetBoolean(self.address, 'chan'): elif BMConfigParser().safeGetBoolean(self.address, 'chan'):
self.type = self.CHAN self.type = self.CHAN
elif shared.safeConfigGetBoolean(self.address, 'mailinglist'): elif BMConfigParser().safeGetBoolean(self.address, 'mailinglist'):
self.type = self.MAILINGLIST self.type = self.MAILINGLIST
elif sqlQuery( elif sqlQuery(
'''select label from subscriptions where address=?''', self.address): '''select label from subscriptions where address=?''', self.address):
@ -84,7 +85,7 @@ class AccountMixin (object):
retval = None retval = None
if self.type in (AccountMixin.NORMAL, AccountMixin.CHAN, AccountMixin.MAILINGLIST): if self.type in (AccountMixin.NORMAL, AccountMixin.CHAN, AccountMixin.MAILINGLIST):
try: try:
retval = unicode(shared.config.get(self.address, 'label'), 'utf-8') retval = unicode(BMConfigParser().get(self.address, 'label'), 'utf-8')
except Exception as e: except Exception as e:
queryreturn = sqlQuery( queryreturn = sqlQuery(
'''select label from addressbook where address=?''', self.address) '''select label from addressbook where address=?''', self.address)
@ -161,7 +162,7 @@ class Ui_AddressWidget(QtGui.QTreeWidgetItem, AccountMixin, SettingsMixin):
super(QtGui.QTreeWidgetItem, self).__init__() super(QtGui.QTreeWidgetItem, self).__init__()
parent.insertTopLevelItem(pos, self) parent.insertTopLevelItem(pos, self)
# only set default when creating # only set default when creating
#super(QtGui.QTreeWidgetItem, self).setExpanded(shared.config.getboolean(self.address, 'enabled')) #super(QtGui.QTreeWidgetItem, self).setExpanded(BMConfigParser().getboolean(self.address, 'enabled'))
self.setAddress(address) self.setAddress(address)
self.setEnabled(enabled) self.setEnabled(enabled)
self.setUnreadCount(unreadCount) self.setUnreadCount(unreadCount)
@ -172,7 +173,7 @@ class Ui_AddressWidget(QtGui.QTreeWidgetItem, AccountMixin, SettingsMixin):
return unicode(QtGui.QApplication.translate("MainWindow", "All accounts").toUtf8(), 'utf-8', 'ignore') return unicode(QtGui.QApplication.translate("MainWindow", "All accounts").toUtf8(), 'utf-8', 'ignore')
else: else:
try: try:
return unicode(shared.config.get(self.address, 'label'), 'utf-8', 'ignore') return unicode(BMConfigParser().get(self.address, 'label'), 'utf-8', 'ignore')
except: except:
return unicode(self.address, 'utf-8') return unicode(self.address, 'utf-8')
@ -211,9 +212,9 @@ class Ui_AddressWidget(QtGui.QTreeWidgetItem, AccountMixin, SettingsMixin):
def setData(self, column, role, value): def setData(self, column, role, value):
if role == QtCore.Qt.EditRole and self.type != AccountMixin.SUBSCRIPTION: if role == QtCore.Qt.EditRole and self.type != AccountMixin.SUBSCRIPTION:
if isinstance(value, QtCore.QVariant): if isinstance(value, QtCore.QVariant):
shared.config.set(str(self.address), 'label', str(value.toString().toUtf8())) BMConfigParser().set(str(self.address), 'label', str(value.toString().toUtf8()))
else: else:
shared.config.set(str(self.address), 'label', str(value)) BMConfigParser().set(str(self.address), 'label', str(value))
shared.writeKeysFile() shared.writeKeysFile()
return super(Ui_AddressWidget, self).setData(column, role, value) return super(Ui_AddressWidget, self).setData(column, role, value)
@ -250,7 +251,7 @@ class Ui_SubscriptionWidget(Ui_AddressWidget, AccountMixin):
super(QtGui.QTreeWidgetItem, self).__init__() super(QtGui.QTreeWidgetItem, self).__init__()
parent.insertTopLevelItem(pos, self) parent.insertTopLevelItem(pos, self)
# only set default when creating # only set default when creating
#super(QtGui.QTreeWidgetItem, self).setExpanded(shared.config.getboolean(self.address, 'enabled')) #super(QtGui.QTreeWidgetItem, self).setExpanded(BMConfigParser().getboolean(self.address, 'enabled'))
self.setAddress(address) self.setAddress(address)
self.setEnabled(enabled) self.setEnabled(enabled)
self.setType() self.setType()
@ -287,7 +288,7 @@ class MessageList_AddressWidget(QtGui.QTableWidgetItem, AccountMixin, SettingsMi
super(QtGui.QTableWidgetItem, self).__init__() super(QtGui.QTableWidgetItem, self).__init__()
#parent.insertTopLevelItem(pos, self) #parent.insertTopLevelItem(pos, self)
# only set default when creating # only set default when creating
#super(QtGui.QTreeWidgetItem, self).setExpanded(shared.config.getboolean(self.address, 'enabled')) #super(QtGui.QTreeWidgetItem, self).setExpanded(BMConfigParser().getboolean(self.address, 'enabled'))
self.isEnabled = True self.isEnabled = True
self.setAddress(address) self.setAddress(address)
self.setLabel(label) self.setLabel(label)
@ -302,7 +303,7 @@ class MessageList_AddressWidget(QtGui.QTableWidgetItem, AccountMixin, SettingsMi
queryreturn = None queryreturn = None
if self.type in (AccountMixin.NORMAL, AccountMixin.CHAN, AccountMixin.MAILINGLIST): if self.type in (AccountMixin.NORMAL, AccountMixin.CHAN, AccountMixin.MAILINGLIST):
try: try:
newLabel = unicode(shared.config.get(self.address, 'label'), 'utf-8', 'ignore') newLabel = unicode(BMConfigParser().get(self.address, 'label'), 'utf-8', 'ignore')
except: except:
queryreturn = sqlQuery( queryreturn = sqlQuery(
'''select label from addressbook where address=?''', self.address) '''select label from addressbook where address=?''', self.address)
@ -330,7 +331,7 @@ class MessageList_AddressWidget(QtGui.QTableWidgetItem, AccountMixin, SettingsMi
elif role == QtCore.Qt.ToolTipRole: elif role == QtCore.Qt.ToolTipRole:
return self.label + " (" + self.address + ")" return self.label + " (" + self.address + ")"
elif role == QtCore.Qt.DecorationRole: elif role == QtCore.Qt.DecorationRole:
if shared.safeConfigGetBoolean('bitmessagesettings', 'useidenticons'): if BMConfigParser().safeGetBoolean('bitmessagesettings', 'useidenticons'):
if self.address is None: if self.address is None:
return avatarize(self.label) return avatarize(self.label)
else: else:
@ -362,7 +363,7 @@ class MessageList_SubjectWidget(QtGui.QTableWidgetItem, SettingsMixin):
super(QtGui.QTableWidgetItem, self).__init__() super(QtGui.QTableWidgetItem, self).__init__()
#parent.insertTopLevelItem(pos, self) #parent.insertTopLevelItem(pos, self)
# only set default when creating # only set default when creating
#super(QtGui.QTreeWidgetItem, self).setExpanded(shared.config.getboolean(self.address, 'enabled')) #super(QtGui.QTreeWidgetItem, self).setExpanded(BMConfigParser().getboolean(self.address, 'enabled'))
self.setSubject(subject) self.setSubject(subject)
self.setLabel(label) self.setLabel(label)
self.setUnread(unread) self.setUnread(unread)
@ -418,7 +419,7 @@ class Ui_AddressBookWidgetItem(QtGui.QTableWidgetItem, AccountMixin):
elif role == QtCore.Qt.ToolTipRole: elif role == QtCore.Qt.ToolTipRole:
return self.label + " (" + self.address + ")" return self.label + " (" + self.address + ")"
elif role == QtCore.Qt.DecorationRole: elif role == QtCore.Qt.DecorationRole:
if shared.safeConfigGetBoolean('bitmessagesettings', 'useidenticons'): if BMConfigParser().safeGetBoolean('bitmessagesettings', 'useidenticons'):
if self.address is None: if self.address is None:
return avatarize(self.label) return avatarize(self.label)
else: else:
@ -440,8 +441,8 @@ class Ui_AddressBookWidgetItem(QtGui.QTableWidgetItem, AccountMixin):
self.label = str(value) self.label = str(value)
if self.type in (AccountMixin.NORMAL, AccountMixin.MAILINGLIST, AccountMixin.CHAN): if self.type in (AccountMixin.NORMAL, AccountMixin.MAILINGLIST, AccountMixin.CHAN):
try: try:
a = shared.config.get(self.address, 'label') a = BMConfigParser().get(self.address, 'label')
shared.config.set(self.address, 'label', self.label) BMConfigParser().set(self.address, 'label', self.label)
except: except:
sqlExecute('''UPDATE addressbook set label=? WHERE address=?''', self.label, self.address) sqlExecute('''UPDATE addressbook set label=? WHERE address=?''', self.label, self.address)
elif self.type == AccountMixin.SUBSCRIPTION: elif self.type == AccountMixin.SUBSCRIPTION:

View File

@ -2,7 +2,8 @@ import glob
import os import os
from PyQt4 import QtCore, QtGui from PyQt4 import QtCore, QtGui
from shared import codePath, config from configparser import BMConfigParser
import paths
class LanguageBox(QtGui.QComboBox): class LanguageBox(QtGui.QComboBox):
languageName = {"system": "System Settings", "eo": "Esperanto", "en_pirate": "Pirate English"} languageName = {"system": "System Settings", "eo": "Esperanto", "en_pirate": "Pirate English"}
@ -13,10 +14,10 @@ class LanguageBox(QtGui.QComboBox):
def populate(self): def populate(self):
self.languages = [] self.languages = []
self.clear() self.clear()
localesPath = os.path.join (codePath(), 'translations') localesPath = os.path.join (paths.codePath(), 'translations')
configuredLocale = "system" configuredLocale = "system"
try: try:
configuredLocale = config.get('bitmessagesettings', 'userlocale', "system") configuredLocale = BMConfigParser().get('bitmessagesettings', 'userlocale', "system")
except: except:
pass pass
self.addItem(QtGui.QApplication.translate("settingsDialog", "System Settings", "system"), "system") self.addItem(QtGui.QApplication.translate("settingsDialog", "System Settings", "system"), "system")

View File

@ -2,6 +2,7 @@ from PyQt4 import QtCore, QtGui
import time import time
import shared import shared
from tr import _translate from tr import _translate
from inventory import Inventory
import l10n import l10n
from retranslateui import RetranslateMixin from retranslateui import RetranslateMixin
from uisignaler import UISignaler from uisignaler import UISignaler
@ -127,8 +128,8 @@ class NetworkStatus(QtGui.QWidget, RetranslateMixin):
# timer driven # timer driven
def runEveryTwoSeconds(self): def runEveryTwoSeconds(self):
self.labelLookupsPerSecond.setText(_translate( self.labelLookupsPerSecond.setText(_translate(
"networkstatus", "Inventory lookups per second: %1").arg(str(shared.numberOfInventoryLookupsPerformed/2))) "networkstatus", "Inventory lookups per second: %1").arg(str(Inventory().numberOfInventoryLookupsPerformed/2)))
shared.numberOfInventoryLookupsPerformed = 0 Inventory().numberOfInventoryLookupsPerformed = 0
self.updateNumberOfBytes() self.updateNumberOfBytes()
self.updateNumberOfObjectsToBeSynced() self.updateNumberOfObjectsToBeSynced()

View File

@ -316,19 +316,19 @@ class NewAddressThread(QtCore.QThread):
def __del__(self): def __del__(self):
self.wait() self.wait()
def createDeterministic(): def createDeterministic(self):
pass pass
def createPassphrase(): def createPassphrase(self):
pass pass
def broadcastAddress(): def broadcastAddress(self):
pass pass
def registerMailchuck(): def registerMailchuck(self):
pass pass
def waitRegistration(): def waitRegistration(self):
pass pass
def run(self): def run(self):

View File

@ -5,14 +5,19 @@ import sys
import time import time
import account import account
from configparser import BMConfigParser
from debug import logger from debug import logger
from foldertree import AccountMixin from foldertree import AccountMixin
from helper_sql import * from helper_sql import *
from l10n import getTranslationLanguage from l10n import getTranslationLanguage
from openclpow import openclAvailable, openclEnabled from openclpow import openclAvailable, openclEnabled
import paths
from proofofwork import bmpow from proofofwork import bmpow
import protocol
from pyelliptic.openssl import OpenSSL from pyelliptic.openssl import OpenSSL
import shared import shared
import state
from version import softwareVersion
# this is BM support address going to Peter Surda # this is BM support address going to Peter Surda
SUPPORT_ADDRESS = 'BM-2cTkCtMYkrSPwFTpgcBrMrf5d8oZwvMZWK' SUPPORT_ADDRESS = 'BM-2cTkCtMYkrSPwFTpgcBrMrf5d8oZwvMZWK'
@ -55,13 +60,13 @@ def checkAddressBook(myapp):
def checkHasNormalAddress(): def checkHasNormalAddress():
for address in account.getSortedAccounts(): for address in account.getSortedAccounts():
acct = account.accountClass(address) acct = account.accountClass(address)
if acct.type == AccountMixin.NORMAL and shared.safeConfigGetBoolean(address, 'enabled'): if acct.type == AccountMixin.NORMAL and BMConfigParser().safeGetBoolean(address, 'enabled'):
return address return address
return False return False
def createAddressIfNeeded(myapp): def createAddressIfNeeded(myapp):
if not checkHasNormalAddress(): if not checkHasNormalAddress():
shared.addressGeneratorQueue.put(('createRandomAddress', 4, 1, str(QtGui.QApplication.translate("Support", SUPPORT_MY_LABEL)), 1, "", False, shared.networkDefaultProofOfWorkNonceTrialsPerByte, shared.networkDefaultPayloadLengthExtraBytes)) shared.addressGeneratorQueue.put(('createRandomAddress', 4, 1, str(QtGui.QApplication.translate("Support", SUPPORT_MY_LABEL)), 1, "", False, protocol.networkDefaultProofOfWorkNonceTrialsPerByte, protocol.networkDefaultPayloadLengthExtraBytes))
while shared.shutdown == 0 and not checkHasNormalAddress(): while shared.shutdown == 0 and not checkHasNormalAddress():
time.sleep(.2) time.sleep(.2)
myapp.rerenderComboBoxSendFrom() myapp.rerenderComboBoxSendFrom()
@ -80,7 +85,7 @@ def createSupportMessage(myapp):
myapp.ui.comboBoxSendFrom.setCurrentIndex(addrIndex) myapp.ui.comboBoxSendFrom.setCurrentIndex(addrIndex)
myapp.ui.lineEditTo.setText(SUPPORT_ADDRESS) myapp.ui.lineEditTo.setText(SUPPORT_ADDRESS)
version = shared.softwareVersion version = softwareVersion
os = sys.platform os = sys.platform
if os == "win32": if os == "win32":
windowsversion = sys.getwindowsversion() windowsversion = sys.getwindowsversion()
@ -102,20 +107,20 @@ def createSupportMessage(myapp):
opensslversion = "%s (Python internal), %s (external for PyElliptic)" % (ssl.OPENSSL_VERSION, OpenSSL._lib.SSLeay_version(SSLEAY_VERSION)) opensslversion = "%s (Python internal), %s (external for PyElliptic)" % (ssl.OPENSSL_VERSION, OpenSSL._lib.SSLeay_version(SSLEAY_VERSION))
frozen = "N/A" frozen = "N/A"
if shared.frozen: if paths.frozen:
frozen = shared.frozen frozen = paths.frozen
portablemode = "True" if shared.appdata == shared.lookupExeFolder() else "False" portablemode = "True" if state.appdata == paths.lookupExeFolder() else "False"
cpow = "True" if bmpow else "False" cpow = "True" if bmpow else "False"
#cpow = QtGui.QApplication.translate("Support", cpow) #cpow = QtGui.QApplication.translate("Support", cpow)
openclpow = str(shared.safeConfigGet('bitmessagesettings', 'opencl')) if openclEnabled() else "None" openclpow = str(BMConfigParser().safeGet('bitmessagesettings', 'opencl')) if openclEnabled() else "None"
#openclpow = QtGui.QApplication.translate("Support", openclpow) #openclpow = QtGui.QApplication.translate("Support", openclpow)
locale = getTranslationLanguage() locale = getTranslationLanguage()
try: try:
socks = shared.config.get('bitmessagesettings', 'socksproxytype') socks = BMConfigParser().get('bitmessagesettings', 'socksproxytype')
except: except:
socks = "N/A" socks = "N/A"
try: try:
upnp = shared.config.get('bitmessagesettings', 'upnp') upnp = BMConfigParser().get('bitmessagesettings', 'upnp')
except: except:
upnp = "N/A" upnp = "N/A"
connectedhosts = len(shared.connectedHostsList) connectedhosts = len(shared.connectedHostsList)

View File

@ -1,8 +1,9 @@
from PyQt4 import QtGui from PyQt4 import QtGui
import hashlib import hashlib
import os import os
import shared
from addresses import addBMIfNotPresent from addresses import addBMIfNotPresent
from configparser import BMConfigParser
import state
str_broadcast_subscribers = '[Broadcast subscribers]' str_broadcast_subscribers = '[Broadcast subscribers]'
str_chan = '[chan]' str_chan = '[chan]'
@ -15,7 +16,7 @@ def identiconize(address):
# 3fd4bf901b9d4ea1394f0fb358725b28 # 3fd4bf901b9d4ea1394f0fb358725b28
try: try:
identicon_lib = shared.config.get('bitmessagesettings', 'identiconlib') identicon_lib = BMConfigParser().get('bitmessagesettings', 'identiconlib')
except: except:
# default to qidenticon_two_x # default to qidenticon_two_x
identicon_lib = 'qidenticon_two_x' identicon_lib = 'qidenticon_two_x'
@ -23,9 +24,9 @@ def identiconize(address):
# As an 'identiconsuffix' you could put "@bitmessge.ch" or "@bm.addr" to make it compatible with other identicon generators. (Note however, that E-Mail programs might convert the BM-address to lowercase first.) # As an 'identiconsuffix' you could put "@bitmessge.ch" or "@bm.addr" to make it compatible with other identicon generators. (Note however, that E-Mail programs might convert the BM-address to lowercase first.)
# It can be used as a pseudo-password to salt the generation of the identicons to decrease the risk # It can be used as a pseudo-password to salt the generation of the identicons to decrease the risk
# of attacks where someone creates an address to mimic someone else's identicon. # of attacks where someone creates an address to mimic someone else's identicon.
identiconsuffix = shared.config.get('bitmessagesettings', 'identiconsuffix') identiconsuffix = BMConfigParser().get('bitmessagesettings', 'identiconsuffix')
if not shared.config.getboolean('bitmessagesettings', 'useidenticons'): if not BMConfigParser().getboolean('bitmessagesettings', 'useidenticons'):
idcon = QtGui.QIcon() idcon = QtGui.QIcon()
return idcon return idcon
@ -81,8 +82,8 @@ def avatarize(address):
extensions = ['PNG', 'GIF', 'JPG', 'JPEG', 'SVG', 'BMP', 'MNG', 'PBM', 'PGM', 'PPM', 'TIFF', 'XBM', 'XPM', 'TGA'] extensions = ['PNG', 'GIF', 'JPG', 'JPEG', 'SVG', 'BMP', 'MNG', 'PBM', 'PGM', 'PPM', 'TIFF', 'XBM', 'XPM', 'TGA']
# try to find a specific avatar # try to find a specific avatar
for ext in extensions: for ext in extensions:
lower_hash = shared.appdata + 'avatars/' + hash + '.' + ext.lower() lower_hash = state.appdata + 'avatars/' + hash + '.' + ext.lower()
upper_hash = shared.appdata + 'avatars/' + hash + '.' + ext.upper() upper_hash = state.appdata + 'avatars/' + hash + '.' + ext.upper()
if os.path.isfile(lower_hash): if os.path.isfile(lower_hash):
# print 'found avatar of ', address # print 'found avatar of ', address
idcon.addFile(lower_hash) idcon.addFile(lower_hash)
@ -93,8 +94,8 @@ def avatarize(address):
return idcon return idcon
# if we haven't found any, try to find a default avatar # if we haven't found any, try to find a default avatar
for ext in extensions: for ext in extensions:
lower_default = shared.appdata + 'avatars/' + 'default.' + ext.lower() lower_default = state.appdata + 'avatars/' + 'default.' + ext.lower()
upper_default = shared.appdata + 'avatars/' + 'default.' + ext.upper() upper_default = state.appdata + 'avatars/' + 'default.' + ext.upper()
if os.path.isfile(lower_default): if os.path.isfile(lower_default):
default = lower_default default = lower_default
idcon.addFile(lower_default) idcon.addFile(lower_default)

View File

@ -1,10 +1,10 @@
from PyQt4 import uic from PyQt4 import uic
import os.path import os.path
import paths
import sys import sys
from shared import codePath
def resource_path(resFile): def resource_path(resFile):
baseDir = codePath() baseDir = paths.codePath()
for subDir in ["ui", "bitmessageqt"]: for subDir in ["ui", "bitmessageqt"]:
if os.path.isdir(os.path.join(baseDir, subDir)) and os.path.isfile(os.path.join(baseDir, subDir, resFile)): if os.path.isdir(os.path.join(baseDir, subDir)) and os.path.isfile(os.path.join(baseDir, subDir, resFile)):
return os.path.join(baseDir, subDir, resFile) return os.path.join(baseDir, subDir, resFile)

View File

@ -7,8 +7,10 @@ import ctypes
import hashlib import hashlib
import highlevelcrypto import highlevelcrypto
from addresses import * from addresses import *
from configparser import BMConfigParser
from debug import logger from debug import logger
from helper_threading import * from helper_threading import *
import protocol
from pyelliptic import arithmetic from pyelliptic import arithmetic
import tr import tr
from binascii import hexlify from binascii import hexlify
@ -48,7 +50,7 @@ class addressGenerator(threading.Thread, StoppableThread):
elif len(queueValue) == 7: elif len(queueValue) == 7:
command, addressVersionNumber, streamNumber, label, numberOfAddressesToMake, deterministicPassphrase, eighteenByteRipe = queueValue command, addressVersionNumber, streamNumber, label, numberOfAddressesToMake, deterministicPassphrase, eighteenByteRipe = queueValue
try: try:
numberOfNullBytesDemandedOnFrontOfRipeHash = shared.config.getint( numberOfNullBytesDemandedOnFrontOfRipeHash = BMConfigParser().getint(
'bitmessagesettings', 'numberofnullbytesonaddress') 'bitmessagesettings', 'numberofnullbytesonaddress')
except: except:
if eighteenByteRipe: if eighteenByteRipe:
@ -58,7 +60,7 @@ class addressGenerator(threading.Thread, StoppableThread):
elif len(queueValue) == 9: elif len(queueValue) == 9:
command, addressVersionNumber, streamNumber, label, numberOfAddressesToMake, deterministicPassphrase, eighteenByteRipe, nonceTrialsPerByte, payloadLengthExtraBytes = queueValue command, addressVersionNumber, streamNumber, label, numberOfAddressesToMake, deterministicPassphrase, eighteenByteRipe, nonceTrialsPerByte, payloadLengthExtraBytes = queueValue
try: try:
numberOfNullBytesDemandedOnFrontOfRipeHash = shared.config.getint( numberOfNullBytesDemandedOnFrontOfRipeHash = BMConfigParser().getint(
'bitmessagesettings', 'numberofnullbytesonaddress') 'bitmessagesettings', 'numberofnullbytesonaddress')
except: except:
if eighteenByteRipe: if eighteenByteRipe:
@ -74,15 +76,15 @@ class addressGenerator(threading.Thread, StoppableThread):
sys.stderr.write( sys.stderr.write(
'Program error: For some reason the address generator queue has been given a request to create at least one version %s address which it cannot do.\n' % addressVersionNumber) 'Program error: For some reason the address generator queue has been given a request to create at least one version %s address which it cannot do.\n' % addressVersionNumber)
if nonceTrialsPerByte == 0: if nonceTrialsPerByte == 0:
nonceTrialsPerByte = shared.config.getint( nonceTrialsPerByte = BMConfigParser().getint(
'bitmessagesettings', 'defaultnoncetrialsperbyte') 'bitmessagesettings', 'defaultnoncetrialsperbyte')
if nonceTrialsPerByte < shared.networkDefaultProofOfWorkNonceTrialsPerByte: if nonceTrialsPerByte < protocol.networkDefaultProofOfWorkNonceTrialsPerByte:
nonceTrialsPerByte = shared.networkDefaultProofOfWorkNonceTrialsPerByte nonceTrialsPerByte = protocol.networkDefaultProofOfWorkNonceTrialsPerByte
if payloadLengthExtraBytes == 0: if payloadLengthExtraBytes == 0:
payloadLengthExtraBytes = shared.config.getint( payloadLengthExtraBytes = BMConfigParser().getint(
'bitmessagesettings', 'defaultpayloadlengthextrabytes') 'bitmessagesettings', 'defaultpayloadlengthextrabytes')
if payloadLengthExtraBytes < shared.networkDefaultPayloadLengthExtraBytes: if payloadLengthExtraBytes < protocol.networkDefaultPayloadLengthExtraBytes:
payloadLengthExtraBytes = shared.networkDefaultPayloadLengthExtraBytes payloadLengthExtraBytes = protocol.networkDefaultPayloadLengthExtraBytes
if command == 'createRandomAddress': if command == 'createRandomAddress':
shared.UISignalQueue.put(( shared.UISignalQueue.put((
'updateStatusBar', tr._translate("MainWindow", "Generating one new address"))) 'updateStatusBar', tr._translate("MainWindow", "Generating one new address")))
@ -128,17 +130,17 @@ class addressGenerator(threading.Thread, StoppableThread):
privEncryptionKeyWIF = arithmetic.changebase( privEncryptionKeyWIF = arithmetic.changebase(
privEncryptionKey + checksum, 256, 58) privEncryptionKey + checksum, 256, 58)
shared.config.add_section(address) BMConfigParser().add_section(address)
shared.config.set(address, 'label', label) BMConfigParser().set(address, 'label', label)
shared.config.set(address, 'enabled', 'true') BMConfigParser().set(address, 'enabled', 'true')
shared.config.set(address, 'decoy', 'false') BMConfigParser().set(address, 'decoy', 'false')
shared.config.set(address, 'noncetrialsperbyte', str( BMConfigParser().set(address, 'noncetrialsperbyte', str(
nonceTrialsPerByte)) nonceTrialsPerByte))
shared.config.set(address, 'payloadlengthextrabytes', str( BMConfigParser().set(address, 'payloadlengthextrabytes', str(
payloadLengthExtraBytes)) payloadLengthExtraBytes))
shared.config.set( BMConfigParser().set(
address, 'privSigningKey', privSigningKeyWIF) address, 'privSigningKey', privSigningKeyWIF)
shared.config.set( BMConfigParser().set(
address, 'privEncryptionKey', privEncryptionKeyWIF) address, 'privEncryptionKey', privEncryptionKeyWIF)
shared.writeKeysFile() shared.writeKeysFile()
@ -233,7 +235,7 @@ class addressGenerator(threading.Thread, StoppableThread):
try: try:
shared.config.add_section(address) BMConfigParser().add_section(address)
addressAlreadyExists = False addressAlreadyExists = False
except: except:
addressAlreadyExists = True addressAlreadyExists = True
@ -244,18 +246,18 @@ class addressGenerator(threading.Thread, StoppableThread):
'updateStatusBar', tr._translate("MainWindow","%1 is already in 'Your Identities'. Not adding it again.").arg(address))) 'updateStatusBar', tr._translate("MainWindow","%1 is already in 'Your Identities'. Not adding it again.").arg(address)))
else: else:
logger.debug('label: %s' % label) logger.debug('label: %s' % label)
shared.config.set(address, 'label', label) BMConfigParser().set(address, 'label', label)
shared.config.set(address, 'enabled', 'true') BMConfigParser().set(address, 'enabled', 'true')
shared.config.set(address, 'decoy', 'false') BMConfigParser().set(address, 'decoy', 'false')
if command == 'joinChan' or command == 'createChan': if command == 'joinChan' or command == 'createChan':
shared.config.set(address, 'chan', 'true') BMConfigParser().set(address, 'chan', 'true')
shared.config.set(address, 'noncetrialsperbyte', str( BMConfigParser().set(address, 'noncetrialsperbyte', str(
nonceTrialsPerByte)) nonceTrialsPerByte))
shared.config.set(address, 'payloadlengthextrabytes', str( BMConfigParser().set(address, 'payloadlengthextrabytes', str(
payloadLengthExtraBytes)) payloadLengthExtraBytes))
shared.config.set( BMConfigParser().set(
address, 'privSigningKey', privSigningKeyWIF) address, 'privSigningKey', privSigningKeyWIF)
shared.config.set( BMConfigParser().set(
address, 'privEncryptionKey', privEncryptionKeyWIF) address, 'privEncryptionKey', privEncryptionKeyWIF)
shared.writeKeysFile() shared.writeKeysFile()
@ -278,7 +280,7 @@ class addressGenerator(threading.Thread, StoppableThread):
'sendOutOrStoreMyV4Pubkey', address)) 'sendOutOrStoreMyV4Pubkey', address))
shared.UISignalQueue.put(( shared.UISignalQueue.put((
'updateStatusBar', tr._translate("MainWindow", "Done generating address"))) 'updateStatusBar', tr._translate("MainWindow", "Done generating address")))
elif saveAddressToDisk and not live and not shared.config.has_section(address): elif saveAddressToDisk and not live and not BMConfigParser().has_section(address):
listOfNewAddressesToSendOutThroughTheAPI.append(address) listOfNewAddressesToSendOutThroughTheAPI.append(address)
# Done generating addresses. # Done generating addresses.

View File

@ -17,11 +17,11 @@ class objectHashHolder(threading.Thread):
threading.Thread.__init__(self, name="objectHashHolder") threading.Thread.__init__(self, name="objectHashHolder")
self.shutdown = False self.shutdown = False
self.sendDataThreadMailbox = sendDataThreadMailbox # This queue is used to submit data back to our associated sendDataThread. self.sendDataThreadMailbox = sendDataThreadMailbox # This queue is used to submit data back to our associated sendDataThread.
self.collectionOfHashLists = {} self.collectionOfHashLists = []
self.collectionOfPeerLists = {} self.collectionOfPeerLists = []
for i in range(self.size): for i in range(objectHashHolder.size):
self.collectionOfHashLists[i] = [] self.collectionOfHashLists.append([])
self.collectionOfPeerLists[i] = [] self.collectionOfPeerLists.append([])
def run(self): def run(self):
iterator = 0 iterator = 0
@ -33,20 +33,19 @@ class objectHashHolder(threading.Thread):
self.sendDataThreadMailbox.put((0, 'sendaddr', self.collectionOfPeerLists[iterator])) self.sendDataThreadMailbox.put((0, 'sendaddr', self.collectionOfPeerLists[iterator]))
self.collectionOfPeerLists[iterator] = [] self.collectionOfPeerLists[iterator] = []
iterator += 1 iterator += 1
iterator %= self.size iterator %= objectHashHolder.size
time.sleep(1) time.sleep(1)
def holdHash(self,hash): def holdHash(self,hash):
self.collectionOfHashLists[random.randrange(0, self.size)].append(hash) self.collectionOfHashLists[random.randrange(0, objectHashHolder.size)].append(hash)
def hasHash(self, hash): def hasHash(self, hash):
if hash in (hashlist for hashlist in self.collectionOfHashLists): if hash in (hashlist for hashlist in self.collectionOfHashLists):
logger.debug("Hash in hashHolder")
return True return True
return False return False
def holdPeer(self,peerDetails): def holdPeer(self,peerDetails):
self.collectionOfPeerLists[random.randrange(0, self.size)].append(peerDetails) self.collectionOfPeerLists[random.randrange(0, objectHashHolder.size)].append(peerDetails)
def hashCount(self): def hashCount(self):
return sum([len(x) for x in self.collectionOfHashLists if type(x) is list]) return sum([len(x) for x in self.collectionOfHashLists if type(x) is list])

View File

@ -13,6 +13,7 @@ from binascii import hexlify
from pyelliptic.openssl import OpenSSL from pyelliptic.openssl import OpenSSL
import highlevelcrypto import highlevelcrypto
from addresses import * from addresses import *
from configparser import BMConfigParser
import helper_generic import helper_generic
from helper_generic import addDataPadding from helper_generic import addDataPadding
import helper_bitcoin import helper_bitcoin
@ -20,6 +21,8 @@ import helper_inbox
import helper_msgcoding import helper_msgcoding
import helper_sent import helper_sent
from helper_sql import * from helper_sql import *
import protocol
from state import neededPubkeys
import tr import tr
from debug import logger from debug import logger
import l10n import l10n
@ -130,11 +133,11 @@ class objectProcessor(threading.Thread):
if decodeAddress(myAddress)[2] != streamNumber: if decodeAddress(myAddress)[2] != streamNumber:
logger.warning('(Within the processgetpubkey function) Someone requested one of my pubkeys but the stream number on which we heard this getpubkey object doesn\'t match this address\' stream number. Ignoring.') logger.warning('(Within the processgetpubkey function) Someone requested one of my pubkeys but the stream number on which we heard this getpubkey object doesn\'t match this address\' stream number. Ignoring.')
return return
if shared.safeConfigGetBoolean(myAddress, 'chan'): if BMConfigParser().safeGetBoolean(myAddress, 'chan'):
logger.info('Ignoring getpubkey request because it is for one of my chan addresses. The other party should already have the pubkey.') logger.info('Ignoring getpubkey request because it is for one of my chan addresses. The other party should already have the pubkey.')
return return
try: try:
lastPubkeySendTime = int(shared.config.get( lastPubkeySendTime = int(BMConfigParser().get(
myAddress, 'lastpubkeysendtime')) myAddress, 'lastpubkeysendtime'))
except: except:
lastPubkeySendTime = 0 lastPubkeySendTime = 0
@ -283,12 +286,12 @@ class objectProcessor(threading.Thread):
return return
tag = data[readPosition:readPosition + 32] tag = data[readPosition:readPosition + 32]
if tag not in shared.neededPubkeys: if tag not in neededPubkeys:
logger.info('We don\'t need this v4 pubkey. We didn\'t ask for it.') logger.info('We don\'t need this v4 pubkey. We didn\'t ask for it.')
return return
# Let us try to decrypt the pubkey # Let us try to decrypt the pubkey
toAddress, cryptorObject = shared.neededPubkeys[tag] toAddress, cryptorObject = neededPubkeys[tag]
if shared.decryptAndCheckPubkeyPayload(data, toAddress) == 'successful': if shared.decryptAndCheckPubkeyPayload(data, toAddress) == 'successful':
# At this point we know that we have been waiting on this pubkey. # At this point we know that we have been waiting on this pubkey.
# This function will command the workerThread to start work on # This function will command the workerThread to start work on
@ -458,17 +461,17 @@ class objectProcessor(threading.Thread):
# proof of work requirement. If this is bound for one of my chan # proof of work requirement. If this is bound for one of my chan
# addresses then we skip this check; the minimum network POW is # addresses then we skip this check; the minimum network POW is
# fine. # fine.
if decodeAddress(toAddress)[1] >= 3 and not shared.safeConfigGetBoolean(toAddress, 'chan'): # If the toAddress version number is 3 or higher and not one of my chan addresses: if decodeAddress(toAddress)[1] >= 3 and not BMConfigParser().safeGetBoolean(toAddress, 'chan'): # If the toAddress version number is 3 or higher and not one of my chan addresses:
if not shared.isAddressInMyAddressBookSubscriptionsListOrWhitelist(fromAddress): # If I'm not friendly with this person: if not shared.isAddressInMyAddressBookSubscriptionsListOrWhitelist(fromAddress): # If I'm not friendly with this person:
requiredNonceTrialsPerByte = shared.config.getint( requiredNonceTrialsPerByte = BMConfigParser().getint(
toAddress, 'noncetrialsperbyte') toAddress, 'noncetrialsperbyte')
requiredPayloadLengthExtraBytes = shared.config.getint( requiredPayloadLengthExtraBytes = BMConfigParser().getint(
toAddress, 'payloadlengthextrabytes') toAddress, 'payloadlengthextrabytes')
if not shared.isProofOfWorkSufficient(data, requiredNonceTrialsPerByte, requiredPayloadLengthExtraBytes): if not protocol.isProofOfWorkSufficient(data, requiredNonceTrialsPerByte, requiredPayloadLengthExtraBytes):
logger.info('Proof of work in msg is insufficient only because it does not meet our higher requirement.') logger.info('Proof of work in msg is insufficient only because it does not meet our higher requirement.')
return return
blockMessage = False # Gets set to True if the user shouldn't see the message according to black or white lists. blockMessage = False # Gets set to True if the user shouldn't see the message according to black or white lists.
if shared.config.get('bitmessagesettings', 'blackwhitelist') == 'black': # If we are using a blacklist if BMConfigParser().get('bitmessagesettings', 'blackwhitelist') == 'black': # If we are using a blacklist
queryreturn = sqlQuery( queryreturn = sqlQuery(
'''SELECT label FROM blacklist where address=? and enabled='1' ''', '''SELECT label FROM blacklist where address=? and enabled='1' ''',
fromAddress) fromAddress)
@ -484,7 +487,7 @@ class objectProcessor(threading.Thread):
logger.info('Message ignored because address not in whitelist.') logger.info('Message ignored because address not in whitelist.')
blockMessage = True blockMessage = True
toLabel = shared.config.get(toAddress, 'label') toLabel = BMConfigParser().get(toAddress, 'label')
if toLabel == '': if toLabel == '':
toLabel = toAddress toLabel = toAddress
@ -508,9 +511,9 @@ class objectProcessor(threading.Thread):
# If we are behaving as an API then we might need to run an # If we are behaving as an API then we might need to run an
# outside command to let some program know that a new message # outside command to let some program know that a new message
# has arrived. # has arrived.
if shared.safeConfigGetBoolean('bitmessagesettings', 'apienabled'): if BMConfigParser().safeGetBoolean('bitmessagesettings', 'apienabled'):
try: try:
apiNotifyPath = shared.config.get( apiNotifyPath = BMConfigParser().get(
'bitmessagesettings', 'apinotifypath') 'bitmessagesettings', 'apinotifypath')
except: except:
apiNotifyPath = '' apiNotifyPath = ''
@ -519,9 +522,9 @@ class objectProcessor(threading.Thread):
# Let us now check and see whether our receiving address is # Let us now check and see whether our receiving address is
# behaving as a mailing list # behaving as a mailing list
if shared.safeConfigGetBoolean(toAddress, 'mailinglist') and messageEncodingType != 0: if BMConfigParser().safeGetBoolean(toAddress, 'mailinglist') and messageEncodingType != 0:
try: try:
mailingListName = shared.config.get( mailingListName = BMConfigParser().get(
toAddress, 'mailinglistname') toAddress, 'mailinglistname')
except: except:
mailingListName = '' mailingListName = ''
@ -566,8 +569,8 @@ class objectProcessor(threading.Thread):
if self.ackDataHasAValidHeader(ackData) and \ if self.ackDataHasAValidHeader(ackData) and \
not blockMessage and \ not blockMessage and \
messageEncodingType != 0 and \ messageEncodingType != 0 and \
not shared.safeConfigGetBoolean(toAddress, 'dontsendack') and \ not BMConfigParser().safeGetBoolean(toAddress, 'dontsendack') and \
not shared.safeConfigGetBoolean(toAddress, 'chan'): not BMConfigParser().safeGetBoolean(toAddress, 'chan'):
shared.checkAndShareObjectWithPeers(ackData[24:]) shared.checkAndShareObjectWithPeers(ackData[24:])
# Display timing data # Display timing data
@ -756,9 +759,9 @@ class objectProcessor(threading.Thread):
# If we are behaving as an API then we might need to run an # If we are behaving as an API then we might need to run an
# outside command to let some program know that a new message # outside command to let some program know that a new message
# has arrived. # has arrived.
if shared.safeConfigGetBoolean('bitmessagesettings', 'apienabled'): if BMConfigParser().safeGetBoolean('bitmessagesettings', 'apienabled'):
try: try:
apiNotifyPath = shared.config.get( apiNotifyPath = BMConfigParser().get(
'bitmessagesettings', 'apinotifypath') 'bitmessagesettings', 'apinotifypath')
except: except:
apiNotifyPath = '' apiNotifyPath = ''
@ -780,8 +783,8 @@ class objectProcessor(threading.Thread):
# stream number, and RIPE hash. # stream number, and RIPE hash.
status, addressVersion, streamNumber, ripe = decodeAddress(address) status, addressVersion, streamNumber, ripe = decodeAddress(address)
if addressVersion <=3: if addressVersion <=3:
if address in shared.neededPubkeys: if address in neededPubkeys:
del shared.neededPubkeys[address] del neededPubkeys[address]
self.sendMessages(address) self.sendMessages(address)
else: else:
logger.debug('We don\'t need this pub key. We didn\'t ask for it. For address: %s' % address) logger.debug('We don\'t need this pub key. We didn\'t ask for it. For address: %s' % address)
@ -791,8 +794,8 @@ class objectProcessor(threading.Thread):
elif addressVersion >= 4: elif addressVersion >= 4:
tag = hashlib.sha512(hashlib.sha512(encodeVarint( tag = hashlib.sha512(hashlib.sha512(encodeVarint(
addressVersion) + encodeVarint(streamNumber) + ripe).digest()).digest()[32:] addressVersion) + encodeVarint(streamNumber) + ripe).digest()).digest()[32:]
if tag in shared.neededPubkeys: if tag in neededPubkeys:
del shared.neededPubkeys[tag] del neededPubkeys[tag]
self.sendMessages(address) self.sendMessages(address)
def sendMessages(self, address): def sendMessages(self, address):
@ -808,15 +811,15 @@ class objectProcessor(threading.Thread):
shared.workerQueue.put(('sendmessage', '')) shared.workerQueue.put(('sendmessage', ''))
def ackDataHasAValidHeader(self, ackData): def ackDataHasAValidHeader(self, ackData):
if len(ackData) < shared.Header.size: if len(ackData) < protocol.Header.size:
logger.info('The length of ackData is unreasonably short. Not sending ackData.') logger.info('The length of ackData is unreasonably short. Not sending ackData.')
return False return False
magic,command,payloadLength,checksum = shared.Header.unpack(ackData[:shared.Header.size]) magic,command,payloadLength,checksum = protocol.Header.unpack(ackData[:protocol.Header.size])
if magic != 0xE9BEB4D9: if magic != 0xE9BEB4D9:
logger.info('Ackdata magic bytes were wrong. Not sending ackData.') logger.info('Ackdata magic bytes were wrong. Not sending ackData.')
return False return False
payload = ackData[shared.Header.size:] payload = ackData[protocol.Header.size:]
if len(payload) != payloadLength: if len(payload) != payloadLength:
logger.info('ackData payload length doesn\'t match the payload length specified in the header. Not sending ackdata.') logger.info('ackData payload length doesn\'t match the payload length specified in the header. Not sending ackdata.')
return False return False

View File

@ -1,3 +1,4 @@
import errno
import threading import threading
import time import time
import random import random
@ -10,7 +11,9 @@ import tr
from class_sendDataThread import * from class_sendDataThread import *
from class_receiveDataThread import * from class_receiveDataThread import *
from configparser import BMConfigParser
from helper_threading import * from helper_threading import *
import state
# For each stream to which we connect, several outgoingSynSender threads # For each stream to which we connect, several outgoingSynSender threads
# will exist and will collectively create 8 connections with peers. # will exist and will collectively create 8 connections with peers.
@ -45,12 +48,12 @@ class outgoingSynSender(threading.Thread, StoppableThread):
continue continue
priority = (183600 - (time.time() - shared.knownNodes[self.streamNumber][peer])) / 183600 # 2 days and 3 hours priority = (183600 - (time.time() - shared.knownNodes[self.streamNumber][peer])) / 183600 # 2 days and 3 hours
shared.knownNodesLock.release() shared.knownNodesLock.release()
if shared.config.get('bitmessagesettings', 'socksproxytype') != 'none': if BMConfigParser().get('bitmessagesettings', 'socksproxytype') != 'none':
if peer.host.find(".onion") == -1: if peer.host.find(".onion") == -1:
priority /= 10 # hidden services have 10x priority over plain net priority /= 10 # hidden services have 10x priority over plain net
else: else:
# don't connect to self # don't connect to self
if peer.host == shared.config.get('bitmessagesettings', 'onionhostname') and peer.port == shared.config.getint("bitmessagesettings", "onionport"): if peer.host == BMConfigParser().get('bitmessagesettings', 'onionhostname') and peer.port == BMConfigParser().getint("bitmessagesettings", "onionport"):
continue continue
elif peer.host.find(".onion") != -1: # onion address and so proxy elif peer.host.find(".onion") != -1: # onion address and so proxy
continue continue
@ -72,9 +75,9 @@ class outgoingSynSender(threading.Thread, StoppableThread):
pass pass
def run(self): def run(self):
while shared.safeConfigGetBoolean('bitmessagesettings', 'dontconnect') and not self._stopped: while BMConfigParser().safeGetBoolean('bitmessagesettings', 'dontconnect') and not self._stopped:
self.stop.wait(2) self.stop.wait(2)
while shared.safeConfigGetBoolean('bitmessagesettings', 'sendoutgoingconnections') and not self._stopped: while BMConfigParser().safeGetBoolean('bitmessagesettings', 'sendoutgoingconnections') and not self._stopped:
self.name = "outgoingSynSender" self.name = "outgoingSynSender"
maximumConnections = 1 if shared.trustedPeer else shared.config.getint('bitmessagesettings', 'maxoutboundconnections') maximumConnections = 1 if shared.trustedPeer else shared.config.getint('bitmessagesettings', 'maxoutboundconnections')
while len(self.selfInitiatedConnections[self.streamNumber]) >= maximumConnections: while len(self.selfInitiatedConnections[self.streamNumber]) >= maximumConnections:
@ -110,8 +113,8 @@ class outgoingSynSender(threading.Thread, StoppableThread):
self.name = "outgoingSynSender-" + peer.host.replace(":", ".") # log parser field separator self.name = "outgoingSynSender-" + peer.host.replace(":", ".") # log parser field separator
address_family = socket.AF_INET address_family = socket.AF_INET
# Proxy IP is IPv6. Unlikely but possible # Proxy IP is IPv6. Unlikely but possible
if shared.config.get('bitmessagesettings', 'socksproxytype') != 'none': if BMConfigParser().get('bitmessagesettings', 'socksproxytype') != 'none':
if ":" in shared.config.get('bitmessagesettings', 'sockshostname'): if ":" in BMConfigParser().get('bitmessagesettings', 'sockshostname'):
address_family = socket.AF_INET6 address_family = socket.AF_INET6
# No proxy, and destination is IPv6 # No proxy, and destination is IPv6
elif peer.host.find(':') >= 0 : elif peer.host.find(':') >= 0 :
@ -140,44 +143,44 @@ class outgoingSynSender(threading.Thread, StoppableThread):
# can rebind faster # can rebind faster
self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.sock.settimeout(20) self.sock.settimeout(20)
if shared.config.get('bitmessagesettings', 'socksproxytype') == 'none' and shared.verbose >= 2: if BMConfigParser().get('bitmessagesettings', 'socksproxytype') == 'none' and shared.verbose >= 2:
logger.debug('Trying an outgoing connection to ' + str(peer)) logger.debug('Trying an outgoing connection to ' + str(peer))
# sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
elif shared.config.get('bitmessagesettings', 'socksproxytype') == 'SOCKS4a': elif BMConfigParser().get('bitmessagesettings', 'socksproxytype') == 'SOCKS4a':
if shared.verbose >= 2: if shared.verbose >= 2:
logger.debug ('(Using SOCKS4a) Trying an outgoing connection to ' + str(peer)) logger.debug ('(Using SOCKS4a) Trying an outgoing connection to ' + str(peer))
proxytype = socks.PROXY_TYPE_SOCKS4 proxytype = socks.PROXY_TYPE_SOCKS4
sockshostname = shared.config.get( sockshostname = BMConfigParser().get(
'bitmessagesettings', 'sockshostname') 'bitmessagesettings', 'sockshostname')
socksport = shared.config.getint( socksport = BMConfigParser().getint(
'bitmessagesettings', 'socksport') 'bitmessagesettings', 'socksport')
rdns = True # Do domain name lookups through the proxy; though this setting doesn't really matter since we won't be doing any domain name lookups anyway. rdns = True # Do domain name lookups through the proxy; though this setting doesn't really matter since we won't be doing any domain name lookups anyway.
if shared.config.getboolean('bitmessagesettings', 'socksauthentication'): if BMConfigParser().getboolean('bitmessagesettings', 'socksauthentication'):
socksusername = shared.config.get( socksusername = BMConfigParser().get(
'bitmessagesettings', 'socksusername') 'bitmessagesettings', 'socksusername')
sockspassword = shared.config.get( sockspassword = BMConfigParser().get(
'bitmessagesettings', 'sockspassword') 'bitmessagesettings', 'sockspassword')
self.sock.setproxy( self.sock.setproxy(
proxytype, sockshostname, socksport, rdns, socksusername, sockspassword) proxytype, sockshostname, socksport, rdns, socksusername, sockspassword)
else: else:
self.sock.setproxy( self.sock.setproxy(
proxytype, sockshostname, socksport, rdns) proxytype, sockshostname, socksport, rdns)
elif shared.config.get('bitmessagesettings', 'socksproxytype') == 'SOCKS5': elif BMConfigParser().get('bitmessagesettings', 'socksproxytype') == 'SOCKS5':
if shared.verbose >= 2: if shared.verbose >= 2:
logger.debug ('(Using SOCKS5) Trying an outgoing connection to ' + str(peer)) logger.debug ('(Using SOCKS5) Trying an outgoing connection to ' + str(peer))
proxytype = socks.PROXY_TYPE_SOCKS5 proxytype = socks.PROXY_TYPE_SOCKS5
sockshostname = shared.config.get( sockshostname = BMConfigParser().get(
'bitmessagesettings', 'sockshostname') 'bitmessagesettings', 'sockshostname')
socksport = shared.config.getint( socksport = BMConfigParser().getint(
'bitmessagesettings', 'socksport') 'bitmessagesettings', 'socksport')
rdns = True # Do domain name lookups through the proxy; though this setting doesn't really matter since we won't be doing any domain name lookups anyway. rdns = True # Do domain name lookups through the proxy; though this setting doesn't really matter since we won't be doing any domain name lookups anyway.
if shared.config.getboolean('bitmessagesettings', 'socksauthentication'): if BMConfigParser().getboolean('bitmessagesettings', 'socksauthentication'):
socksusername = shared.config.get( socksusername = BMConfigParser().get(
'bitmessagesettings', 'socksusername') 'bitmessagesettings', 'socksusername')
sockspassword = shared.config.get( sockspassword = BMConfigParser().get(
'bitmessagesettings', 'sockspassword') 'bitmessagesettings', 'sockspassword')
self.sock.setproxy( self.sock.setproxy(
proxytype, sockshostname, socksport, rdns, socksusername, sockspassword) proxytype, sockshostname, socksport, rdns, socksusername, sockspassword)
@ -251,12 +254,16 @@ class outgoingSynSender(threading.Thread, StoppableThread):
logger.debug('SOCKS5 error: %s', str(err)) logger.debug('SOCKS5 error: %s', str(err))
else: else:
logger.error('SOCKS5 error: %s', str(err)) logger.error('SOCKS5 error: %s', str(err))
if err[0][0] == 4 or err[0][0] == 2:
state.networkProtocolLastFailed['IPv6'] = time.time()
except socks.Socks4Error as err: except socks.Socks4Error as err:
logger.error('Socks4Error: ' + str(err)) logger.error('Socks4Error: ' + str(err))
except socket.error as err: except socket.error as err:
if shared.config.get('bitmessagesettings', 'socksproxytype')[0:5] == 'SOCKS': if BMConfigParser().get('bitmessagesettings', 'socksproxytype')[0:5] == 'SOCKS':
logger.error('Bitmessage MIGHT be having trouble connecting to the SOCKS server. ' + str(err)) logger.error('Bitmessage MIGHT be having trouble connecting to the SOCKS server. ' + str(err))
else: else:
if ":" in peer.host and err[0] == errno.ENETUNREACH:
state.networkProtocolLastFailed['IPv6'] = time.time()
if shared.verbose >= 1: if shared.verbose >= 1:
logger.debug('Could NOT connect to ' + str(peer) + 'during outgoing attempt. ' + str(err)) logger.debug('Could NOT connect to ' + str(peer) + 'during outgoing attempt. ' + str(err))

View File

@ -23,11 +23,17 @@ from binascii import hexlify
#import highlevelcrypto #import highlevelcrypto
from addresses import * from addresses import *
from configparser import BMConfigParser
from class_objectHashHolder import objectHashHolder from class_objectHashHolder import objectHashHolder
from helper_generic import addDataPadding, isHostInPrivateIPRange from helper_generic import addDataPadding, isHostInPrivateIPRange
from helper_sql import sqlQuery from helper_sql import sqlQuery
from debug import logger from debug import logger
import paths
import protocol
from inventory import Inventory
import state
import tr import tr
from version import softwareVersion
# This thread is created either by the synSenderThread(for outgoing # This thread is created either by the synSenderThread(for outgoing
# connections) or the singleListenerThread(for incoming connections). # connections) or the singleListenerThread(for incoming connections).
@ -58,7 +64,7 @@ class receiveDataThread(threading.Thread):
self.objectsThatWeHaveYetToGetFromThisPeer = {} self.objectsThatWeHaveYetToGetFromThisPeer = {}
self.selfInitiatedConnections = selfInitiatedConnections self.selfInitiatedConnections = selfInitiatedConnections
self.sendDataThreadQueue = sendDataThreadQueue # used to send commands and data to the sendDataThread self.sendDataThreadQueue = sendDataThreadQueue # used to send commands and data to the sendDataThread
self.hostIdent = self.peer.port if ".onion" in shared.config.get('bitmessagesettings', 'onionhostname') and shared.checkSocksIP(self.peer.host) else self.peer.host self.hostIdent = self.peer.port if ".onion" in BMConfigParser().get('bitmessagesettings', 'onionhostname') and protocol.checkSocksIP(self.peer.host) else self.peer.host
shared.connectedHostsList[ shared.connectedHostsList[
self.hostIdent] = 0 # The very fact that this receiveData thread exists shows that we are connected to the remote host. Let's add it to this list so that an outgoingSynSender thread doesn't try to connect to it. self.hostIdent] = 0 # The very fact that this receiveData thread exists shows that we are connected to the remote host. Let's add it to this list so that an outgoingSynSender thread doesn't try to connect to it.
self.connectionIsOrWasFullyEstablished = False # set to true after the remote node and I accept each other's version messages. This is needed to allow the user interface to accurately reflect the current number of connections. self.connectionIsOrWasFullyEstablished = False # set to true after the remote node and I accept each other's version messages. This is needed to allow the user interface to accurately reflect the current number of connections.
@ -76,10 +82,10 @@ class receiveDataThread(threading.Thread):
logger.debug('receiveDataThread starting. ID ' + str(id(self)) + '. The size of the shared.connectedHostsList is now ' + str(len(shared.connectedHostsList))) logger.debug('receiveDataThread starting. ID ' + str(id(self)) + '. The size of the shared.connectedHostsList is now ' + str(len(shared.connectedHostsList)))
while True: while True:
if shared.config.getint('bitmessagesettings', 'maxdownloadrate') == 0: if BMConfigParser().getint('bitmessagesettings', 'maxdownloadrate') == 0:
downloadRateLimitBytes = float("inf") downloadRateLimitBytes = float("inf")
else: else:
downloadRateLimitBytes = shared.config.getint('bitmessagesettings', 'maxdownloadrate') * 1000 downloadRateLimitBytes = BMConfigParser().getint('bitmessagesettings', 'maxdownloadrate') * 1000
with shared.receiveDataLock: with shared.receiveDataLock:
while shared.numberOfBytesReceivedLastSecond >= downloadRateLimitBytes: while shared.numberOfBytesReceivedLastSecond >= downloadRateLimitBytes:
if int(time.time()) == shared.lastTimeWeResetBytesReceived: if int(time.time()) == shared.lastTimeWeResetBytesReceived:
@ -92,9 +98,9 @@ class receiveDataThread(threading.Thread):
dataLen = len(self.data) dataLen = len(self.data)
try: try:
ssl = False ssl = False
if ((self.services & shared.NODE_SSL == shared.NODE_SSL) and if ((self.services & protocol.NODE_SSL == protocol.NODE_SSL) and
self.connectionIsOrWasFullyEstablished and self.connectionIsOrWasFullyEstablished and
shared.haveSSL(not self.initiatedConnection)): protocol.haveSSL(not self.initiatedConnection)):
ssl = True ssl = True
dataRecv = self.sslSock.recv(1024) dataRecv = self.sslSock.recv(1024)
else: else:
@ -105,7 +111,7 @@ class receiveDataThread(threading.Thread):
except socket.timeout: except socket.timeout:
logger.error ('Timeout occurred waiting for data from ' + str(self.peer) + '. Closing receiveData thread. (ID: ' + str(id(self)) + ')') logger.error ('Timeout occurred waiting for data from ' + str(self.peer) + '. Closing receiveData thread. (ID: ' + str(id(self)) + ')')
break break
except Exception as err: except socket.error as err:
if err.errno == 2 or (sys.platform == 'win32' and err.errno == 10035) or (sys.platform != 'win32' and err.errno == errno.EWOULDBLOCK): if err.errno == 2 or (sys.platform == 'win32' and err.errno == 10035) or (sys.platform != 'win32' and err.errno == errno.EWOULDBLOCK):
if ssl: if ssl:
select.select([self.sslSock], [], []) select.select([self.sslSock], [], [])
@ -164,25 +170,25 @@ class receiveDataThread(threading.Thread):
shared.UISignalQueue.put(('updateStatusBar', tr._translate("MainWindow", "The time on your computer, %1, may be wrong. Please verify your settings.").arg(datetime.datetime.now().strftime("%H:%M:%S")))) shared.UISignalQueue.put(('updateStatusBar', tr._translate("MainWindow", "The time on your computer, %1, may be wrong. Please verify your settings.").arg(datetime.datetime.now().strftime("%H:%M:%S"))))
def processData(self): def processData(self):
if len(self.data) < shared.Header.size: # if so little of the data has arrived that we can't even read the checksum then wait for more data. if len(self.data) < protocol.Header.size: # if so little of the data has arrived that we can't even read the checksum then wait for more data.
return return
magic,command,payloadLength,checksum = shared.Header.unpack(self.data[:shared.Header.size]) magic,command,payloadLength,checksum = protocol.Header.unpack(self.data[:protocol.Header.size])
if magic != 0xE9BEB4D9: if magic != 0xE9BEB4D9:
self.data = "" self.data = ""
return return
if payloadLength > 1600100: # ~1.6 MB which is the maximum possible size of an inv message. if payloadLength > 1600100: # ~1.6 MB which is the maximum possible size of an inv message.
logger.info('The incoming message, which we have not yet download, is too large. Ignoring it. (unfortunately there is no way to tell the other node to stop sending it except to disconnect.) Message size: %s' % payloadLength) logger.info('The incoming message, which we have not yet download, is too large. Ignoring it. (unfortunately there is no way to tell the other node to stop sending it except to disconnect.) Message size: %s' % payloadLength)
self.data = self.data[payloadLength + shared.Header.size:] self.data = self.data[payloadLength + protocol.Header.size:]
del magic,command,payloadLength,checksum # we don't need these anymore and better to clean them now before the recursive call rather than after del magic,command,payloadLength,checksum # we don't need these anymore and better to clean them now before the recursive call rather than after
self.processData() self.processData()
return return
if len(self.data) < payloadLength + shared.Header.size: # check if the whole message has arrived yet. if len(self.data) < payloadLength + protocol.Header.size: # check if the whole message has arrived yet.
return return
payload = self.data[shared.Header.size:payloadLength + shared.Header.size] payload = self.data[protocol.Header.size:payloadLength + protocol.Header.size]
if checksum != hashlib.sha512(payload).digest()[0:4]: # test the checksum in the message. if checksum != hashlib.sha512(payload).digest()[0:4]: # test the checksum in the message.
logger.error('Checksum incorrect. Clearing this message.') logger.error('Checksum incorrect. Clearing this message.')
self.data = self.data[payloadLength + shared.Header.size:] self.data = self.data[payloadLength + protocol.Header.size:]
del magic,command,payloadLength,checksum,payload # better to clean up before the recursive call del magic,command,payloadLength,checksum,payload # better to clean up before the recursive call
self.processData() self.processData()
return return
@ -226,14 +232,13 @@ class receiveDataThread(threading.Thread):
logger.critical("Critical error in a receiveDataThread: \n%s" % traceback.format_exc()) logger.critical("Critical error in a receiveDataThread: \n%s" % traceback.format_exc())
del payload del payload
self.data = self.data[payloadLength + shared.Header.size:] # take this message out and then process the next message self.data = self.data[payloadLength + protocol.Header.size:] # take this message out and then process the next message
if self.data == '': # if there are no more messages if self.data == '': # if there are no more messages
while len(self.objectsThatWeHaveYetToGetFromThisPeer) > 0: while len(self.objectsThatWeHaveYetToGetFromThisPeer) > 0:
shared.numberOfInventoryLookupsPerformed += 1
objectHash, = random.sample( objectHash, = random.sample(
self.objectsThatWeHaveYetToGetFromThisPeer, 1) self.objectsThatWeHaveYetToGetFromThisPeer, 1)
if objectHash in shared.inventory: if objectHash in Inventory():
logger.debug('Inventory already has object listed in inv message.') logger.debug('Inventory already has object listed in inv message.')
del self.objectsThatWeHaveYetToGetFromThisPeer[objectHash] del self.objectsThatWeHaveYetToGetFromThisPeer[objectHash]
else: else:
@ -265,9 +270,9 @@ class receiveDataThread(threading.Thread):
self.processData() self.processData()
def sendpong(self): def sendpong(self, payload):
logger.debug('Sending pong') logger.debug('Sending pong')
self.sendDataThreadQueue.put((0, 'sendRawData', shared.CreatePacket('pong'))) self.sendDataThreadQueue.put((0, 'sendRawData', protocol.CreatePacket('pong', payload)))
def recverack(self): def recverack(self):
@ -285,10 +290,10 @@ class receiveDataThread(threading.Thread):
shared.timeOffsetWrongCount = 0 shared.timeOffsetWrongCount = 0
self.sslSock = self.sock self.sslSock = self.sock
if ((self.services & shared.NODE_SSL == shared.NODE_SSL) and if ((self.services & protocol.NODE_SSL == protocol.NODE_SSL) and
shared.haveSSL(not self.initiatedConnection)): protocol.haveSSL(not self.initiatedConnection)):
logger.debug("Initialising TLS") logger.debug("Initialising TLS")
self.sslSock = ssl.wrap_socket(self.sock, keyfile = os.path.join(shared.codePath(), 'sslkeys', 'key.pem'), certfile = os.path.join(shared.codePath(), 'sslkeys', 'cert.pem'), server_side = not self.initiatedConnection, ssl_version=ssl.PROTOCOL_TLSv1, do_handshake_on_connect=False, ciphers='AECDH-AES256-SHA') self.sslSock = ssl.wrap_socket(self.sock, keyfile = os.path.join(paths.codePath(), 'sslkeys', 'key.pem'), certfile = os.path.join(paths.codePath(), 'sslkeys', 'cert.pem'), server_side = not self.initiatedConnection, ssl_version=ssl.PROTOCOL_TLSv1, do_handshake_on_connect=False, ciphers='AECDH-AES256-SHA')
if hasattr(self.sslSock, "context"): if hasattr(self.sslSock, "context"):
self.sslSock.context.set_ecdh_curve("secp256k1") self.sslSock.context.set_ecdh_curve("secp256k1")
while True: while True:
@ -317,12 +322,12 @@ class receiveDataThread(threading.Thread):
shared.UISignalQueue.put(('updateNetworkStatusTab', 'no data')) shared.UISignalQueue.put(('updateNetworkStatusTab', 'no data'))
logger.debug('Connection fully established with ' + str(self.peer) + "\n" + \ logger.debug('Connection fully established with ' + str(self.peer) + "\n" + \
'The size of the connectedHostsList is now ' + str(len(shared.connectedHostsList)) + "\n" + \ 'The size of the connectedHostsList is now ' + str(len(shared.connectedHostsList)) + "\n" + \
'The length of sendDataQueues is now: ' + str(len(shared.sendDataQueues)) + "\n" + \ 'The length of sendDataQueues is now: ' + str(len(state.sendDataQueues)) + "\n" + \
'broadcasting addr from within connectionFullyEstablished function.') 'broadcasting addr from within connectionFullyEstablished function.')
# Let all of our peers know about this new node. # Let all of our peers know about this new node.
dataToSend = (int(time.time()), self.streamNumber, 1, self.peer.host, self.remoteNodeIncomingPort) dataToSend = (int(time.time()), self.streamNumber, 1, self.peer.host, self.remoteNodeIncomingPort)
shared.broadcastToSendDataQueues(( protocol.broadcastToSendDataQueues((
self.streamNumber, 'advertisepeer', dataToSend)) self.streamNumber, 'advertisepeer', dataToSend))
self.sendaddr() # This is one large addr message to this one peer. self.sendaddr() # This is one large addr message to this one peer.
@ -336,7 +341,7 @@ class receiveDataThread(threading.Thread):
def sendBigInv(self): def sendBigInv(self):
# Select all hashes for objects in this stream. # Select all hashes for objects in this stream.
bigInvList = {} bigInvList = {}
for hash in shared.inventory.unexpired_hashes_by_stream(self.streamNumber): for hash in Inventory().unexpired_hashes_by_stream(self.streamNumber):
if hash not in self.someObjectsOfWhichThisRemoteNodeIsAlreadyAware and not self.objectHashHolderInstance.hasHash(hash): if hash not in self.someObjectsOfWhichThisRemoteNodeIsAlreadyAware and not self.objectHashHolderInstance.hasHash(hash):
bigInvList[hash] = 0 bigInvList[hash] = 0
numberOfObjectsInInvMessage = 0 numberOfObjectsInInvMessage = 0
@ -361,7 +366,7 @@ class receiveDataThread(threading.Thread):
def sendinvMessageToJustThisOnePeer(self, numberOfObjects, payload): def sendinvMessageToJustThisOnePeer(self, numberOfObjects, payload):
payload = encodeVarint(numberOfObjects) + payload payload = encodeVarint(numberOfObjects) + payload
logger.debug('Sending huge inv message with ' + str(numberOfObjects) + ' objects to just this one peer') logger.debug('Sending huge inv message with ' + str(numberOfObjects) + ' objects to just this one peer')
self.sendDataThreadQueue.put((0, 'sendRawData', shared.CreatePacket('inv', payload))) self.sendDataThreadQueue.put((0, 'sendRawData', protocol.CreatePacket('inv', payload)))
def _sleepForTimingAttackMitigation(self, sleepTime): def _sleepForTimingAttackMitigation(self, sleepTime):
# We don't need to do the timing attack mitigation if we are # We don't need to do the timing attack mitigation if we are
@ -442,8 +447,7 @@ class receiveDataThread(threading.Thread):
return return
self.someObjectsOfWhichThisRemoteNodeIsAlreadyAware[ self.someObjectsOfWhichThisRemoteNodeIsAlreadyAware[
data[lengthOfVarint:32 + lengthOfVarint]] = 0 data[lengthOfVarint:32 + lengthOfVarint]] = 0
shared.numberOfInventoryLookupsPerformed += 1 if data[lengthOfVarint:32 + lengthOfVarint] in Inventory():
if data[lengthOfVarint:32 + lengthOfVarint] in shared.inventory:
logger.debug('Inventory has inventory item already.') logger.debug('Inventory has inventory item already.')
else: else:
self.sendgetdata(data[lengthOfVarint:32 + lengthOfVarint]) self.sendgetdata(data[lengthOfVarint:32 + lengthOfVarint])
@ -455,7 +459,7 @@ class receiveDataThread(threading.Thread):
advertisedSet = set() advertisedSet = set()
for i in range(numberOfItemsInInv): for i in range(numberOfItemsInInv):
advertisedSet.add(data[lengthOfVarint + (32 * i):32 + lengthOfVarint + (32 * i)]) advertisedSet.add(data[lengthOfVarint + (32 * i):32 + lengthOfVarint + (32 * i)])
objectsNewToMe = advertisedSet - shared.inventory.hashes_by_stream(self.streamNumber) objectsNewToMe = advertisedSet - Inventory().hashes_by_stream(self.streamNumber)
logger.info('inv message lists %s objects. Of those %s are new to me. It took %s seconds to figure that out.', numberOfItemsInInv, len(objectsNewToMe), time.time()-startTime) logger.info('inv message lists %s objects. Of those %s are new to me. It took %s seconds to figure that out.', numberOfItemsInInv, len(objectsNewToMe), time.time()-startTime)
for item in objectsNewToMe: for item in objectsNewToMe:
if totalNumberOfobjectsThatWeHaveYetToGetFromAllPeers > 200000 and len(self.objectsThatWeHaveYetToGetFromThisPeer) > 1000 and shared.trustedPeer == None: # inv flooding attack mitigation if totalNumberOfobjectsThatWeHaveYetToGetFromAllPeers > 200000 and len(self.objectsThatWeHaveYetToGetFromThisPeer) > 1000 and shared.trustedPeer == None: # inv flooding attack mitigation
@ -472,7 +476,7 @@ class receiveDataThread(threading.Thread):
def sendgetdata(self, hash): def sendgetdata(self, hash):
logger.debug('sending getdata to retrieve object with hash: ' + hexlify(hash)) logger.debug('sending getdata to retrieve object with hash: ' + hexlify(hash))
payload = '\x01' + hash payload = '\x01' + hash
self.sendDataThreadQueue.put((0, 'sendRawData', shared.CreatePacket('getdata', payload))) self.sendDataThreadQueue.put((0, 'sendRawData', protocol.CreatePacket('getdata', payload)))
# We have received a getdata request from our peer # We have received a getdata request from our peer
@ -488,15 +492,11 @@ class receiveDataThread(threading.Thread):
i * 32):32 + lengthOfVarint + (i * 32)] i * 32):32 + lengthOfVarint + (i * 32)]
logger.debug('received getdata request for item:' + hexlify(hash)) logger.debug('received getdata request for item:' + hexlify(hash))
shared.numberOfInventoryLookupsPerformed += 1
shared.inventoryLock.acquire()
if self.objectHashHolderInstance.hasHash(hash): if self.objectHashHolderInstance.hasHash(hash):
shared.inventoryLock.release()
self.antiIntersectionDelay() self.antiIntersectionDelay()
else: else:
shared.inventoryLock.release() if hash in Inventory():
if hash in shared.inventory: self.sendObject(Inventory()[hash].payload)
self.sendObject(shared.inventory[hash].payload)
else: else:
self.antiIntersectionDelay() self.antiIntersectionDelay()
logger.warning('%s asked for an object with a getdata which is not in either our memory inventory or our SQL inventory. We probably cleaned it out after advertising it but before they got around to asking for it.' % (self.peer,)) logger.warning('%s asked for an object with a getdata which is not in either our memory inventory or our SQL inventory. We probably cleaned it out after advertising it but before they got around to asking for it.' % (self.peer,))
@ -504,7 +504,7 @@ class receiveDataThread(threading.Thread):
# Our peer has requested (in a getdata message) that we send an object. # Our peer has requested (in a getdata message) that we send an object.
def sendObject(self, payload): def sendObject(self, payload):
logger.debug('sending an object.') logger.debug('sending an object.')
self.sendDataThreadQueue.put((0, 'sendRawData', shared.CreatePacket('object',payload))) self.sendDataThreadQueue.put((0, 'sendRawData', protocol.CreatePacket('object',payload)))
def _checkIPAddress(self, host): def _checkIPAddress(self, host):
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':
@ -596,7 +596,7 @@ class receiveDataThread(threading.Thread):
hostDetails = ( hostDetails = (
timeSomeoneElseReceivedMessageFromThisNode, timeSomeoneElseReceivedMessageFromThisNode,
recaddrStream, recaddrServices, hostStandardFormat, recaddrPort) recaddrStream, recaddrServices, hostStandardFormat, recaddrPort)
shared.broadcastToSendDataQueues(( protocol.broadcastToSendDataQueues((
self.streamNumber, 'advertisepeer', hostDetails)) self.streamNumber, 'advertisepeer', hostDetails))
else: else:
timeLastReceivedMessageFromThisNode = shared.knownNodes[recaddrStream][ timeLastReceivedMessageFromThisNode = shared.knownNodes[recaddrStream][
@ -627,15 +627,15 @@ class receiveDataThread(threading.Thread):
sentOwn = False sentOwn = False
for i in range(500): for i in range(500):
# if current connection is over a proxy, sent our own onion address at a random position # if current connection is over a proxy, sent our own onion address at a random position
if ownPosition == i and ".onion" in shared.config.get("bitmessagesettings", "onionhostname") and \ if ownPosition == i and ".onion" in BMConfigParser().get("bitmessagesettings", "onionhostname") and \
hasattr(self.sock, "getproxytype") and self.sock.getproxytype() != "none" and not sentOwn: hasattr(self.sock, "getproxytype") and self.sock.getproxytype() != "none" and not sentOwn:
peer = shared.Peer(shared.config.get("bitmessagesettings", "onionhostname"), shared.config.getint("bitmessagesettings", "onionport")) peer = shared.Peer(BMConfigParser().get("bitmessagesettings", "onionhostname"), BMConfigParser().getint("bitmessagesettings", "onionport"))
else: else:
# still may contain own onion address, but we don't change it # still may contain own onion address, but we don't change it
peer, = random.sample(shared.knownNodes[self.streamNumber], 1) peer, = random.sample(shared.knownNodes[self.streamNumber], 1)
if isHostInPrivateIPRange(peer.host): if isHostInPrivateIPRange(peer.host):
continue continue
if peer.host == shared.config.get("bitmessagesettings", "onionhostname") and peer.port == shared.config.getint("bitmessagesettings", "onionport") : if peer.host == BMConfigParser().get("bitmessagesettings", "onionhostname") and peer.port == BMConfigParser().getint("bitmessagesettings", "onionport") :
sentOwn = True sentOwn = True
addrsInMyStream[peer] = shared.knownNodes[ addrsInMyStream[peer] = shared.knownNodes[
self.streamNumber][peer] self.streamNumber][peer]
@ -667,7 +667,7 @@ class receiveDataThread(threading.Thread):
payload += pack('>I', self.streamNumber) payload += pack('>I', self.streamNumber)
payload += pack( payload += pack(
'>q', 1) # service bit flags offered by this node '>q', 1) # service bit flags offered by this node
payload += shared.encodeHost(HOST) payload += protocol.encodeHost(HOST)
payload += pack('>H', PORT) # remote port payload += pack('>H', PORT) # remote port
for (HOST, PORT), value in addrsInChildStreamLeft.items(): for (HOST, PORT), value in addrsInChildStreamLeft.items():
timeLastReceivedMessageFromThisNode = value timeLastReceivedMessageFromThisNode = value
@ -678,7 +678,7 @@ class receiveDataThread(threading.Thread):
payload += pack('>I', self.streamNumber * 2) payload += pack('>I', self.streamNumber * 2)
payload += pack( payload += pack(
'>q', 1) # service bit flags offered by this node '>q', 1) # service bit flags offered by this node
payload += shared.encodeHost(HOST) payload += protocol.encodeHost(HOST)
payload += pack('>H', PORT) # remote port payload += pack('>H', PORT) # remote port
for (HOST, PORT), value in addrsInChildStreamRight.items(): for (HOST, PORT), value in addrsInChildStreamRight.items():
timeLastReceivedMessageFromThisNode = value timeLastReceivedMessageFromThisNode = value
@ -689,11 +689,11 @@ class receiveDataThread(threading.Thread):
payload += pack('>I', (self.streamNumber * 2) + 1) payload += pack('>I', (self.streamNumber * 2) + 1)
payload += pack( payload += pack(
'>q', 1) # service bit flags offered by this node '>q', 1) # service bit flags offered by this node
payload += shared.encodeHost(HOST) payload += protocol.encodeHost(HOST)
payload += pack('>H', PORT) # remote port payload += pack('>H', PORT) # remote port
payload = encodeVarint(numberOfAddressesInAddrMessage) + payload payload = encodeVarint(numberOfAddressesInAddrMessage) + payload
self.sendDataThreadQueue.put((0, 'sendRawData', shared.CreatePacket('addr', payload))) self.sendDataThreadQueue.put((0, 'sendRawData', protocol.CreatePacket('addr', payload)))
# We have received a version message # We have received a version message
@ -719,14 +719,14 @@ class receiveDataThread(threading.Thread):
timestamp, = unpack('>Q', data[12:20]) timestamp, = unpack('>Q', data[12:20])
timeOffset = timestamp - int(time.time()) timeOffset = timestamp - int(time.time())
if timeOffset > 3600: if timeOffset > 3600:
self.sendDataThreadQueue.put((0, 'sendRawData', shared.assembleErrorMessage(fatal=2, errorText="Your time is too far in the future compared to mine. Closing connection."))) self.sendDataThreadQueue.put((0, 'sendRawData', protocol.assembleErrorMessage(fatal=2, errorText="Your time is too far in the future compared to mine. Closing connection.")))
logger.info("%s's time is too far in the future (%s seconds). Closing connection to it." % (self.peer, timeOffset)) logger.info("%s's time is too far in the future (%s seconds). Closing connection to it." % (self.peer, timeOffset))
shared.timeOffsetWrongCount += 1 shared.timeOffsetWrongCount += 1
time.sleep(2) time.sleep(2)
self.sendDataThreadQueue.put((0, 'shutdown','no data')) self.sendDataThreadQueue.put((0, 'shutdown','no data'))
return return
elif timeOffset < -3600: elif timeOffset < -3600:
self.sendDataThreadQueue.put((0, 'sendRawData', shared.assembleErrorMessage(fatal=2, errorText="Your time is too far in the past compared to mine. Closing connection."))) self.sendDataThreadQueue.put((0, 'sendRawData', protocol.assembleErrorMessage(fatal=2, errorText="Your time is too far in the past compared to mine. Closing connection.")))
logger.info("%s's time is too far in the past (timeOffset %s seconds). Closing connection to it." % (self.peer, timeOffset)) logger.info("%s's time is too far in the past (timeOffset %s seconds). Closing connection to it." % (self.peer, timeOffset))
shared.timeOffsetWrongCount += 1 shared.timeOffsetWrongCount += 1
time.sleep(2) time.sleep(2)
@ -752,7 +752,7 @@ class receiveDataThread(threading.Thread):
userAgentName = useragent userAgentName = useragent
userAgentVersion = "0.0.0" userAgentVersion = "0.0.0"
if userAgentName == "PyBitmessage": if userAgentName == "PyBitmessage":
myVersion = [int(n) for n in shared.softwareVersion.split(".")] myVersion = [int(n) for n in softwareVersion.split(".")]
try: try:
remoteVersion = [int(n) for n in userAgentVersion.split(".")] remoteVersion = [int(n) for n in userAgentVersion.split(".")]
except: except:
@ -783,7 +783,7 @@ class receiveDataThread(threading.Thread):
# doesn't know the stream. We have to set it. # doesn't know the stream. We have to set it.
if not self.initiatedConnection: if not self.initiatedConnection:
self.sendDataThreadQueue.put((0, 'setStreamNumber', self.streamNumber)) self.sendDataThreadQueue.put((0, 'setStreamNumber', self.streamNumber))
if data[72:80] == shared.eightBytesOfRandomDataUsedToDetectConnectionsToSelf: if data[72:80] == protocol.eightBytesOfRandomDataUsedToDetectConnectionsToSelf:
self.sendDataThreadQueue.put((0, 'shutdown','no data')) self.sendDataThreadQueue.put((0, 'shutdown','no data'))
logger.debug('Closing connection to myself: ' + str(self.peer)) logger.debug('Closing connection to myself: ' + str(self.peer))
return return
@ -806,14 +806,14 @@ class receiveDataThread(threading.Thread):
# Sends a version message # Sends a version message
def sendversion(self): def sendversion(self):
logger.debug('Sending version message') logger.debug('Sending version message')
self.sendDataThreadQueue.put((0, 'sendRawData', shared.assembleVersionMessage( self.sendDataThreadQueue.put((0, 'sendRawData', protocol.assembleVersionMessage(
self.peer.host, self.peer.port, self.streamNumber, not self.initiatedConnection))) self.peer.host, self.peer.port, self.streamNumber, not self.initiatedConnection)))
# Sends a verack message # Sends a verack message
def sendverack(self): def sendverack(self):
logger.debug('Sending verack') logger.debug('Sending verack')
self.sendDataThreadQueue.put((0, 'sendRawData', shared.CreatePacket('verack'))) self.sendDataThreadQueue.put((0, 'sendRawData', protocol.CreatePacket('verack')))
self.verackSent = True self.verackSent = True
if self.verackReceived: if self.verackReceived:
self.connectionFullyEstablished() self.connectionFullyEstablished()

View File

@ -8,10 +8,13 @@ import random
import sys import sys
import socket import socket
from configparser import BMConfigParser
from helper_generic import addDataPadding from helper_generic import addDataPadding
from class_objectHashHolder import * from class_objectHashHolder import *
from addresses import * from addresses import *
from debug import logger from debug import logger
import protocol
import state
# Every connection to a peer has a sendDataThread (and also a # Every connection to a peer has a sendDataThread (and also a
# receiveDataThread). # receiveDataThread).
@ -20,7 +23,7 @@ class sendDataThread(threading.Thread):
def __init__(self, sendDataThreadQueue): def __init__(self, sendDataThreadQueue):
threading.Thread.__init__(self, name="sendData") threading.Thread.__init__(self, name="sendData")
self.sendDataThreadQueue = sendDataThreadQueue self.sendDataThreadQueue = sendDataThreadQueue
shared.sendDataQueues.append(self.sendDataThreadQueue) state.sendDataQueues.append(self.sendDataThreadQueue)
self.data = '' self.data = ''
self.objectHashHolderInstance = objectHashHolder(self.sendDataThreadQueue) self.objectHashHolderInstance = objectHashHolder(self.sendDataThreadQueue)
self.objectHashHolderInstance.start() self.objectHashHolderInstance.start()
@ -53,7 +56,7 @@ class sendDataThread(threading.Thread):
def sendVersionMessage(self): def sendVersionMessage(self):
datatosend = shared.assembleVersionMessage( datatosend = protocol.assembleVersionMessage(
self.peer.host, self.peer.port, self.streamNumber, not self.initiatedConnection) # the IP and port of the remote host, and my streamNumber. self.peer.host, self.peer.port, self.streamNumber, not self.initiatedConnection) # the IP and port of the remote host, and my streamNumber.
logger.debug('Sending version packet: ' + repr(datatosend)) logger.debug('Sending version packet: ' + repr(datatosend))
@ -67,10 +70,10 @@ class sendDataThread(threading.Thread):
self.versionSent = 1 self.versionSent = 1
def sendBytes(self, data): def sendBytes(self, data):
if shared.config.getint('bitmessagesettings', 'maxuploadrate') == 0: if BMConfigParser().getint('bitmessagesettings', 'maxuploadrate') == 0:
uploadRateLimitBytes = 999999999 # float("inf") doesn't work uploadRateLimitBytes = 999999999 # float("inf") doesn't work
else: else:
uploadRateLimitBytes = shared.config.getint('bitmessagesettings', 'maxuploadrate') * 1000 uploadRateLimitBytes = BMConfigParser().getint('bitmessagesettings', 'maxuploadrate') * 1000
with shared.sendDataLock: with shared.sendDataLock:
while data: while data:
while shared.numberOfBytesSentLastSecond >= uploadRateLimitBytes: while shared.numberOfBytesSentLastSecond >= uploadRateLimitBytes:
@ -83,11 +86,11 @@ class sendDataThread(threading.Thread):
# If the user raises or lowers the uploadRateLimit then we should make use of # If the user raises or lowers the uploadRateLimit then we should make use of
# the new setting. If we are hitting the limit then we'll check here about # the new setting. If we are hitting the limit then we'll check here about
# once per second. # once per second.
if shared.config.getint('bitmessagesettings', 'maxuploadrate') == 0: if BMConfigParser().getint('bitmessagesettings', 'maxuploadrate') == 0:
uploadRateLimitBytes = 999999999 # float("inf") doesn't work uploadRateLimitBytes = 999999999 # float("inf") doesn't work
else: else:
uploadRateLimitBytes = shared.config.getint('bitmessagesettings', 'maxuploadrate') * 1000 uploadRateLimitBytes = BMConfigParser().getint('bitmessagesettings', 'maxuploadrate') * 1000
if ((self.services & shared.NODE_SSL == shared.NODE_SSL) and if ((self.services & protocol.NODE_SSL == protocol.NODE_SSL) and
self.connectionIsOrWasFullyEstablished and self.connectionIsOrWasFullyEstablished and
shared.haveSSL(not self.initiatedConnection)): shared.haveSSL(not self.initiatedConnection)):
amountSent = self.sslSock.send(data[:1000]) amountSent = self.sslSock.send(data[:1000])
@ -100,7 +103,7 @@ class sendDataThread(threading.Thread):
def run(self): def run(self):
logger.debug('sendDataThread starting. ID: ' + str(id(self)) + '. Number of queues in sendDataQueues: ' + str(len(shared.sendDataQueues))) logger.debug('sendDataThread starting. ID: ' + str(id(self)) + '. Number of queues in sendDataQueues: ' + str(len(state.sendDataQueues)))
while True: while True:
deststream, command, data = self.sendDataThreadQueue.get() deststream, command, data = self.sendDataThreadQueue.get()
@ -134,11 +137,11 @@ class sendDataThread(threading.Thread):
payload += pack('>I', streamNumber) payload += pack('>I', streamNumber)
payload += pack( payload += pack(
'>q', services) # service bit flags offered by this node '>q', services) # service bit flags offered by this node
payload += shared.encodeHost(host) payload += protocol.encodeHost(host)
payload += pack('>H', port) payload += pack('>H', port)
payload = encodeVarint(numberOfAddressesInAddrMessage) + payload payload = encodeVarint(numberOfAddressesInAddrMessage) + payload
packet = shared.CreatePacket('addr', payload) packet = protocol.CreatePacket('addr', payload)
try: try:
self.sendBytes(packet) self.sendBytes(packet)
except: except:
@ -154,7 +157,7 @@ class sendDataThread(threading.Thread):
payload += hash payload += hash
if payload != '': if payload != '':
payload = encodeVarint(len(payload)/32) + payload payload = encodeVarint(len(payload)/32) + payload
packet = shared.CreatePacket('inv', payload) packet = protocol.CreatePacket('inv', payload)
try: try:
self.sendBytes(packet) self.sendBytes(packet)
except: except:
@ -165,7 +168,7 @@ class sendDataThread(threading.Thread):
if self.lastTimeISentData < (int(time.time()) - 298): if self.lastTimeISentData < (int(time.time()) - 298):
# Send out a pong message to keep the connection alive. # Send out a pong message to keep the connection alive.
logger.debug('Sending pong to ' + str(self.peer) + ' to keep connection alive.') logger.debug('Sending pong to ' + str(self.peer) + ' to keep connection alive.')
packet = shared.CreatePacket('pong') packet = protocol.CreatePacket('pong')
try: try:
self.sendBytes(packet) self.sendBytes(packet)
except: except:
@ -188,6 +191,6 @@ class sendDataThread(threading.Thread):
self.sock.close() self.sock.close()
except: except:
pass pass
shared.sendDataQueues.remove(self.sendDataThreadQueue) state.sendDataQueues.remove(self.sendDataThreadQueue)
logger.info('sendDataThread ending. ID: ' + str(id(self)) + '. Number of queues in sendDataQueues: ' + str(len(shared.sendDataQueues))) logger.info('sendDataThread ending. ID: ' + str(id(self)) + '. Number of queues in sendDataQueues: ' + str(len(state.sendDataQueues)))
self.objectHashHolderInstance.close() self.objectHashHolderInstance.close()

View File

@ -6,9 +6,13 @@ import os
import pickle import pickle
import tr#anslate import tr#anslate
from configparser import BMConfigParser
from helper_sql import * from helper_sql import *
from helper_threading import * from helper_threading import *
from inventory import Inventory
from debug import logger from debug import logger
import protocol
import state
""" """
The singleCleaner class is a timer-driven thread that cleans data structures The singleCleaner class is a timer-driven thread that cleans data structures
@ -39,7 +43,7 @@ class singleCleaner(threading.Thread, StoppableThread):
def run(self): def run(self):
timeWeLastClearedInventoryAndPubkeysTables = 0 timeWeLastClearedInventoryAndPubkeysTables = 0
try: try:
shared.maximumLengthOfTimeToBotherResendingMessages = (float(shared.config.get('bitmessagesettings', 'stopresendingafterxdays')) * 24 * 60 * 60) + (float(shared.config.get('bitmessagesettings', 'stopresendingafterxmonths')) * (60 * 60 * 24 *365)/12) shared.maximumLengthOfTimeToBotherResendingMessages = (float(BMConfigParser().get('bitmessagesettings', 'stopresendingafterxdays')) * 24 * 60 * 60) + (float(BMConfigParser().get('bitmessagesettings', 'stopresendingafterxmonths')) * (60 * 60 * 24 *365)/12)
except: except:
# Either the user hasn't set stopresendingafterxdays and stopresendingafterxmonths yet or the options are missing from the config file. # Either the user hasn't set stopresendingafterxdays and stopresendingafterxmonths yet or the options are missing from the config file.
shared.maximumLengthOfTimeToBotherResendingMessages = float('inf') shared.maximumLengthOfTimeToBotherResendingMessages = float('inf')
@ -47,19 +51,19 @@ class singleCleaner(threading.Thread, StoppableThread):
while shared.shutdown == 0: while shared.shutdown == 0:
shared.UISignalQueue.put(( shared.UISignalQueue.put((
'updateStatusBar', 'Doing housekeeping (Flushing inventory in memory to disk...)')) 'updateStatusBar', 'Doing housekeeping (Flushing inventory in memory to disk...)'))
shared.inventory.flush() Inventory().flush()
shared.UISignalQueue.put(('updateStatusBar', '')) shared.UISignalQueue.put(('updateStatusBar', ''))
shared.broadcastToSendDataQueues(( protocol.broadcastToSendDataQueues((
0, 'pong', 'no data')) # commands the sendData threads to send out a pong message if they haven't sent anything else in the last five minutes. The socket timeout-time is 10 minutes. 0, 'pong', 'no data')) # commands the sendData threads to send out a pong message if they haven't sent anything else in the last five minutes. The socket timeout-time is 10 minutes.
# If we are running as a daemon then we are going to fill up the UI # If we are running as a daemon then we are going to fill up the UI
# queue which will never be handled by a UI. We should clear it to # queue which will never be handled by a UI. We should clear it to
# save memory. # save memory.
if shared.safeConfigGetBoolean('bitmessagesettings', 'daemon'): if BMConfigParser().safeGetBoolean('bitmessagesettings', 'daemon'):
shared.UISignalQueue.queue.clear() shared.UISignalQueue.queue.clear()
if timeWeLastClearedInventoryAndPubkeysTables < int(time.time()) - 7380: if timeWeLastClearedInventoryAndPubkeysTables < int(time.time()) - 7380:
timeWeLastClearedInventoryAndPubkeysTables = int(time.time()) timeWeLastClearedInventoryAndPubkeysTables = int(time.time())
shared.inventory.clean() Inventory().clean()
# pubkeys # pubkeys
sqlExecute( sqlExecute(
'''DELETE FROM pubkeys WHERE time<? AND usedpersonally='no' ''', '''DELETE FROM pubkeys WHERE time<? AND usedpersonally='no' ''',
@ -95,7 +99,7 @@ class singleCleaner(threading.Thread, StoppableThread):
# Let us write out the knowNodes to disk if there is anything new to write out. # Let us write out the knowNodes to disk if there is anything new to write out.
if shared.needToWriteKnownNodesToDisk: if shared.needToWriteKnownNodesToDisk:
shared.knownNodesLock.acquire() shared.knownNodesLock.acquire()
output = open(shared.appdata + 'knownnodes.dat', 'wb') output = open(state.appdata + 'knownnodes.dat', 'wb')
try: try:
pickle.dump(shared.knownNodes, output) pickle.dump(shared.knownNodes, output)
output.close() output.close()
@ -113,8 +117,8 @@ class singleCleaner(threading.Thread, StoppableThread):
def resendPubkeyRequest(address): def resendPubkeyRequest(address):
logger.debug('It has been a long time and we haven\'t heard a response to our getpubkey request. Sending again.') logger.debug('It has been a long time and we haven\'t heard a response to our getpubkey request. Sending again.')
try: try:
del shared.neededPubkeys[ del state.neededPubkeys[
address] # We need to take this entry out of the shared.neededPubkeys structure because the shared.workerQueue checks to see whether the entry is already present and will not do the POW and send the message because it assumes that it has already done it recently. address] # We need to take this entry out of the neededPubkeys structure because the shared.workerQueue checks to see whether the entry is already present and will not do the POW and send the message because it assumes that it has already done it recently.
except: except:
pass pass

View File

@ -1,10 +1,12 @@
import threading import threading
import shared import shared
import socket import socket
from configparser import BMConfigParser
from class_sendDataThread import * from class_sendDataThread import *
from class_receiveDataThread import * from class_receiveDataThread import *
import helper_bootstrap import helper_bootstrap
from helper_threading import * from helper_threading import *
import protocol
import errno import errno
import re import re
@ -28,9 +30,9 @@ class singleListener(threading.Thread, StoppableThread):
def _createListenSocket(self, family): def _createListenSocket(self, family):
HOST = '' # Symbolic name meaning all available interfaces HOST = '' # Symbolic name meaning all available interfaces
# If not sockslisten, but onionhostname defined, only listen on localhost # If not sockslisten, but onionhostname defined, only listen on localhost
if not shared.safeConfigGetBoolean('bitmessagesettings', 'sockslisten') and ".onion" in shared.config.get('bitmessagesettings', 'onionhostname'): if not BMConfigParser().safeGetBoolean('bitmessagesettings', 'sockslisten') and ".onion" in BMConfigParser().get('bitmessagesettings', 'onionhostname'):
HOST = shared.config.get('bitmessagesettings', 'onionbindip') HOST = BMConfigParser().get('bitmessagesettings', 'onionbindip')
PORT = shared.config.getint('bitmessagesettings', 'port') PORT = BMConfigParser().getint('bitmessagesettings', 'port')
sock = socket.socket(family, socket.SOCK_STREAM) sock = socket.socket(family, socket.SOCK_STREAM)
if family == socket.AF_INET6: if family == socket.AF_INET6:
# Make sure we can accept both IPv4 and IPv6 connections. # Make sure we can accept both IPv4 and IPv6 connections.
@ -46,9 +48,9 @@ class singleListener(threading.Thread, StoppableThread):
def stopThread(self): def stopThread(self):
super(singleListener, self).stopThread() super(singleListener, self).stopThread()
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
for ip in ('127.0.0.1', shared.config.get('bitmessagesettings', 'onionbindip')): for ip in ('127.0.0.1', BMConfigParser().get('bitmessagesettings', 'onionbindip')):
try: try:
s.connect((ip, shared.config.getint('bitmessagesettings', 'port'))) s.connect((ip, BMConfigParser().getint('bitmessagesettings', 'port')))
s.shutdown(socket.SHUT_RDWR) s.shutdown(socket.SHUT_RDWR)
s.close() s.close()
break break
@ -61,7 +63,7 @@ class singleListener(threading.Thread, StoppableThread):
if shared.trustedPeer: if shared.trustedPeer:
return return
while shared.safeConfigGetBoolean('bitmessagesettings', 'dontconnect') and shared.shutdown == 0: while BMConfigParser().safeGetBoolean('bitmessagesettings', 'dontconnect') and shared.shutdown == 0:
self.stop.wait(1) self.stop.wait(1)
helper_bootstrap.dns() helper_bootstrap.dns()
# We typically don't want to accept incoming connections if the user is using a # We typically don't want to accept incoming connections if the user is using a
@ -69,9 +71,9 @@ class singleListener(threading.Thread, StoppableThread):
# proxy 'none' or configure SOCKS listening then this will start listening for # proxy 'none' or configure SOCKS listening then this will start listening for
# connections. But if on SOCKS and have an onionhostname, listen # connections. But if on SOCKS and have an onionhostname, listen
# (socket is then only opened for localhost) # (socket is then only opened for localhost)
while shared.config.get('bitmessagesettings', 'socksproxytype')[0:5] == 'SOCKS' and \ while BMConfigParser().get('bitmessagesettings', 'socksproxytype')[0:5] == 'SOCKS' and \
(not shared.config.getboolean('bitmessagesettings', 'sockslisten') and \ (not BMConfigParser().getboolean('bitmessagesettings', 'sockslisten') and \
".onion" not in shared.config.get('bitmessagesettings', 'onionhostname')) and \ ".onion" not in BMConfigParser().get('bitmessagesettings', 'onionhostname')) and \
shared.shutdown == 0: shared.shutdown == 0:
self.stop.wait(5) self.stop.wait(5)
@ -100,7 +102,7 @@ class singleListener(threading.Thread, StoppableThread):
# SOCKS proxy, unless they have configured otherwise. If they eventually select # SOCKS proxy, unless they have configured otherwise. If they eventually select
# proxy 'none' or configure SOCKS listening then this will start listening for # proxy 'none' or configure SOCKS listening then this will start listening for
# connections. # connections.
while shared.config.get('bitmessagesettings', 'socksproxytype')[0:5] == 'SOCKS' and not shared.config.getboolean('bitmessagesettings', 'sockslisten') and ".onion" not in shared.config.get('bitmessagesettings', 'onionhostname') and shared.shutdown == 0: while BMConfigParser().get('bitmessagesettings', 'socksproxytype')[0:5] == 'SOCKS' and not BMConfigParser().getboolean('bitmessagesettings', 'sockslisten') and ".onion" not in BMConfigParser().get('bitmessagesettings', 'onionhostname') and shared.shutdown == 0:
self.stop.wait(10) self.stop.wait(10)
while len(shared.connectedHostsList) > 220 and shared.shutdown == 0: while len(shared.connectedHostsList) > 220 and shared.shutdown == 0:
logger.info('We are connected to too many people. Not accepting further incoming connections for ten seconds.') logger.info('We are connected to too many people. Not accepting further incoming connections for ten seconds.')
@ -123,7 +125,7 @@ class singleListener(threading.Thread, StoppableThread):
# share the same external IP. This is here to prevent # share the same external IP. This is here to prevent
# connection flooding. # connection flooding.
# permit repeated connections from Tor # permit repeated connections from Tor
if HOST in shared.connectedHostsList and (".onion" not in shared.config.get('bitmessagesettings', 'onionhostname') or not shared.checkSocksIP(HOST)): if HOST in shared.connectedHostsList and (".onion" not in BMConfigParser().get('bitmessagesettings', 'onionhostname') or not protocol.checkSocksIP(HOST)):
socketObject.close() socketObject.close()
logger.info('We are already connected to ' + str(HOST) + '. Ignoring connection.') logger.info('We are already connected to ' + str(HOST) + '. Ignoring connection.')
else: else:

View File

@ -11,14 +11,17 @@ import highlevelcrypto
import proofofwork import proofofwork
import sys import sys
import tr import tr
from configparser import BMConfigParser
from debug import logger from debug import logger
from helper_sql import * from helper_sql import *
import helper_inbox import helper_inbox
from helper_generic import addDataPadding from helper_generic import addDataPadding
import helper_msgcoding import helper_msgcoding
from helper_threading import * from helper_threading import *
from inventory import Inventory
import l10n import l10n
from protocol import * import protocol
from state import neededPubkeys
from binascii import hexlify, unhexlify from binascii import hexlify, unhexlify
# This thread, of which there is only one, does the heavy lifting: # This thread, of which there is only one, does the heavy lifting:
@ -54,13 +57,13 @@ class singleWorker(threading.Thread, StoppableThread):
toAddress, = row toAddress, = row
toStatus, toAddressVersionNumber, toStreamNumber, toRipe = decodeAddress(toAddress) toStatus, toAddressVersionNumber, toStreamNumber, toRipe = decodeAddress(toAddress)
if toAddressVersionNumber <= 3 : if toAddressVersionNumber <= 3 :
shared.neededPubkeys[toAddress] = 0 neededPubkeys[toAddress] = 0
elif toAddressVersionNumber >= 4: elif toAddressVersionNumber >= 4:
doubleHashOfAddressData = hashlib.sha512(hashlib.sha512(encodeVarint( doubleHashOfAddressData = hashlib.sha512(hashlib.sha512(encodeVarint(
toAddressVersionNumber) + encodeVarint(toStreamNumber) + toRipe).digest()).digest() toAddressVersionNumber) + encodeVarint(toStreamNumber) + toRipe).digest()).digest()
privEncryptionKey = doubleHashOfAddressData[:32] # Note that this is the first half of the sha512 hash. privEncryptionKey = doubleHashOfAddressData[:32] # Note that this is the first half of the sha512 hash.
tag = doubleHashOfAddressData[32:] tag = doubleHashOfAddressData[32:]
shared.neededPubkeys[tag] = (toAddress, highlevelcrypto.makeCryptor(hexlify(privEncryptionKey))) # We'll need this for when we receive a pubkey reply: it will be encrypted and we'll need to decrypt it. neededPubkeys[tag] = (toAddress, highlevelcrypto.makeCryptor(hexlify(privEncryptionKey))) # We'll need this for when we receive a pubkey reply: it will be encrypted and we'll need to decrypt it.
# Initialize the shared.ackdataForWhichImWatching data structure # Initialize the shared.ackdataForWhichImWatching data structure
queryreturn = sqlQuery( queryreturn = sqlQuery(
@ -138,12 +141,12 @@ class singleWorker(threading.Thread, StoppableThread):
payload += '\x00\x00\x00\x01' # object type: pubkey payload += '\x00\x00\x00\x01' # object type: pubkey
payload += encodeVarint(addressVersionNumber) # Address version number payload += encodeVarint(addressVersionNumber) # Address version number
payload += encodeVarint(streamNumber) payload += encodeVarint(streamNumber)
payload += getBitfield(myAddress) # bitfield of features supported by me (see the wiki). payload += protocol.getBitfield(myAddress) # bitfield of features supported by me (see the wiki).
try: try:
privSigningKeyBase58 = shared.config.get( privSigningKeyBase58 = BMConfigParser().get(
myAddress, 'privsigningkey') myAddress, 'privsigningkey')
privEncryptionKeyBase58 = shared.config.get( privEncryptionKeyBase58 = BMConfigParser().get(
myAddress, 'privencryptionkey') myAddress, 'privencryptionkey')
except Exception as err: except Exception as err:
logger.error('Error within doPOWForMyV2Pubkey. Could not read the keys from the keys.dat file for a requested address. %s\n' % err) logger.error('Error within doPOWForMyV2Pubkey. Could not read the keys from the keys.dat file for a requested address. %s\n' % err)
@ -162,7 +165,7 @@ class singleWorker(threading.Thread, StoppableThread):
payload += pubEncryptionKey[1:] payload += pubEncryptionKey[1:]
# Do the POW for this pubkey message # Do the POW for this pubkey message
target = 2 ** 64 / (shared.networkDefaultProofOfWorkNonceTrialsPerByte*(len(payload) + 8 + shared.networkDefaultPayloadLengthExtraBytes + ((TTL*(len(payload)+8+shared.networkDefaultPayloadLengthExtraBytes))/(2 ** 16)))) target = 2 ** 64 / (protocol.networkDefaultProofOfWorkNonceTrialsPerByte*(len(payload) + 8 + protocol.networkDefaultPayloadLengthExtraBytes + ((TTL*(len(payload)+8+protocol.networkDefaultPayloadLengthExtraBytes))/(2 ** 16))))
logger.info('(For pubkey message) Doing proof of work...') logger.info('(For pubkey message) 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)
@ -171,7 +174,7 @@ class singleWorker(threading.Thread, StoppableThread):
inventoryHash = calculateInventoryHash(payload) inventoryHash = calculateInventoryHash(payload)
objectType = 1 objectType = 1
shared.inventory[inventoryHash] = ( Inventory()[inventoryHash] = (
objectType, streamNumber, payload, embeddedTime,'') objectType, streamNumber, payload, embeddedTime,'')
logger.info('broadcasting inv with hash: ' + hexlify(inventoryHash)) logger.info('broadcasting inv with hash: ' + hexlify(inventoryHash))
@ -180,7 +183,7 @@ class singleWorker(threading.Thread, StoppableThread):
streamNumber, 'advertiseobject', inventoryHash)) streamNumber, 'advertiseobject', inventoryHash))
shared.UISignalQueue.put(('updateStatusBar', '')) shared.UISignalQueue.put(('updateStatusBar', ''))
try: try:
shared.config.set( BMConfigParser().set(
myAddress, 'lastpubkeysendtime', str(int(time.time()))) myAddress, 'lastpubkeysendtime', str(int(time.time())))
shared.writeKeysFile() shared.writeKeysFile()
except: except:
@ -198,7 +201,7 @@ class singleWorker(threading.Thread, StoppableThread):
except: except:
#The address has been deleted. #The address has been deleted.
return return
if shared.safeConfigGetBoolean(myAddress, 'chan'): if BMConfigParser().safeGetBoolean(myAddress, 'chan'):
logger.info('This is a chan address. Not sending pubkey.') logger.info('This is a chan address. Not sending pubkey.')
return return
status, addressVersionNumber, streamNumber, hash = decodeAddress( status, addressVersionNumber, streamNumber, hash = decodeAddress(
@ -218,12 +221,12 @@ class singleWorker(threading.Thread, StoppableThread):
payload += '\x00\x00\x00\x01' # object type: pubkey payload += '\x00\x00\x00\x01' # object type: pubkey
payload += encodeVarint(addressVersionNumber) # Address version number payload += encodeVarint(addressVersionNumber) # Address version number
payload += encodeVarint(streamNumber) payload += encodeVarint(streamNumber)
payload += getBitfield(myAddress) # bitfield of features supported by me (see the wiki). payload += protocol.getBitfield(myAddress) # bitfield of features supported by me (see the wiki).
try: try:
privSigningKeyBase58 = shared.config.get( privSigningKeyBase58 = BMConfigParser().get(
myAddress, 'privsigningkey') myAddress, 'privsigningkey')
privEncryptionKeyBase58 = shared.config.get( privEncryptionKeyBase58 = BMConfigParser().get(
myAddress, 'privencryptionkey') myAddress, 'privencryptionkey')
except Exception as err: except Exception as err:
logger.error('Error within sendOutOrStoreMyV3Pubkey. Could not read the keys from the keys.dat file for a requested address. %s\n' % err) logger.error('Error within sendOutOrStoreMyV3Pubkey. Could not read the keys from the keys.dat file for a requested address. %s\n' % err)
@ -242,9 +245,9 @@ class singleWorker(threading.Thread, StoppableThread):
payload += pubSigningKey[1:] payload += pubSigningKey[1:]
payload += pubEncryptionKey[1:] payload += pubEncryptionKey[1:]
payload += encodeVarint(shared.config.getint( payload += encodeVarint(BMConfigParser().getint(
myAddress, 'noncetrialsperbyte')) myAddress, 'noncetrialsperbyte'))
payload += encodeVarint(shared.config.getint( payload += encodeVarint(BMConfigParser().getint(
myAddress, 'payloadlengthextrabytes')) myAddress, 'payloadlengthextrabytes'))
signature = highlevelcrypto.sign(payload, privSigningKeyHex) signature = highlevelcrypto.sign(payload, privSigningKeyHex)
@ -252,7 +255,7 @@ class singleWorker(threading.Thread, StoppableThread):
payload += signature payload += signature
# Do the POW for this pubkey message # Do the POW for this pubkey message
target = 2 ** 64 / (shared.networkDefaultProofOfWorkNonceTrialsPerByte*(len(payload) + 8 + shared.networkDefaultPayloadLengthExtraBytes + ((TTL*(len(payload)+8+shared.networkDefaultPayloadLengthExtraBytes))/(2 ** 16)))) target = 2 ** 64 / (protocol.networkDefaultProofOfWorkNonceTrialsPerByte*(len(payload) + 8 + protocol.networkDefaultPayloadLengthExtraBytes + ((TTL*(len(payload)+8+protocol.networkDefaultPayloadLengthExtraBytes))/(2 ** 16))))
logger.info('(For pubkey message) Doing proof of work...') logger.info('(For pubkey message) 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)
@ -261,7 +264,7 @@ class singleWorker(threading.Thread, StoppableThread):
payload = pack('>Q', nonce) + payload payload = pack('>Q', nonce) + payload
inventoryHash = calculateInventoryHash(payload) inventoryHash = calculateInventoryHash(payload)
objectType = 1 objectType = 1
shared.inventory[inventoryHash] = ( Inventory()[inventoryHash] = (
objectType, streamNumber, payload, embeddedTime,'') objectType, streamNumber, payload, embeddedTime,'')
logger.info('broadcasting inv with hash: ' + hexlify(inventoryHash)) logger.info('broadcasting inv with hash: ' + hexlify(inventoryHash))
@ -270,7 +273,7 @@ class singleWorker(threading.Thread, StoppableThread):
streamNumber, 'advertiseobject', inventoryHash)) streamNumber, 'advertiseobject', inventoryHash))
shared.UISignalQueue.put(('updateStatusBar', '')) shared.UISignalQueue.put(('updateStatusBar', ''))
try: try:
shared.config.set( BMConfigParser().set(
myAddress, 'lastpubkeysendtime', str(int(time.time()))) myAddress, 'lastpubkeysendtime', str(int(time.time())))
shared.writeKeysFile() shared.writeKeysFile()
except: except:
@ -281,10 +284,10 @@ class singleWorker(threading.Thread, StoppableThread):
# If this isn't a chan address, this function assembles the pubkey data, # If this isn't a chan address, this function assembles the pubkey data,
# does the necessary POW and sends it out. # does the necessary POW and sends it out.
def sendOutOrStoreMyV4Pubkey(self, myAddress): def sendOutOrStoreMyV4Pubkey(self, myAddress):
if not shared.config.has_section(myAddress): if not BMConfigParser().has_section(myAddress):
#The address has been deleted. #The address has been deleted.
return return
if shared.safeConfigGetBoolean(myAddress, 'chan'): if shared.BMConfigParser().safeGetBoolean(myAddress, 'chan'):
logger.info('This is a chan address. Not sending pubkey.') logger.info('This is a chan address. Not sending pubkey.')
return return
status, addressVersionNumber, streamNumber, hash = decodeAddress( status, addressVersionNumber, streamNumber, hash = decodeAddress(
@ -296,12 +299,12 @@ class singleWorker(threading.Thread, StoppableThread):
payload += '\x00\x00\x00\x01' # object type: pubkey payload += '\x00\x00\x00\x01' # object type: pubkey
payload += encodeVarint(addressVersionNumber) # Address version number payload += encodeVarint(addressVersionNumber) # Address version number
payload += encodeVarint(streamNumber) payload += encodeVarint(streamNumber)
dataToEncrypt = getBitfield(myAddress) dataToEncrypt = protocol.getBitfield(myAddress)
try: try:
privSigningKeyBase58 = shared.config.get( privSigningKeyBase58 = BMConfigParser().get(
myAddress, 'privsigningkey') myAddress, 'privsigningkey')
privEncryptionKeyBase58 = shared.config.get( privEncryptionKeyBase58 = BMConfigParser().get(
myAddress, 'privencryptionkey') myAddress, 'privencryptionkey')
except Exception as err: except Exception as err:
logger.error('Error within sendOutOrStoreMyV4Pubkey. Could not read the keys from the keys.dat file for a requested address. %s\n' % err) logger.error('Error within sendOutOrStoreMyV4Pubkey. Could not read the keys from the keys.dat file for a requested address. %s\n' % err)
@ -318,9 +321,9 @@ class singleWorker(threading.Thread, StoppableThread):
dataToEncrypt += pubSigningKey[1:] dataToEncrypt += pubSigningKey[1:]
dataToEncrypt += pubEncryptionKey[1:] dataToEncrypt += pubEncryptionKey[1:]
dataToEncrypt += encodeVarint(shared.config.getint( dataToEncrypt += encodeVarint(BMConfigParser().getint(
myAddress, 'noncetrialsperbyte')) myAddress, 'noncetrialsperbyte'))
dataToEncrypt += encodeVarint(shared.config.getint( dataToEncrypt += encodeVarint(BMConfigParser().getint(
myAddress, 'payloadlengthextrabytes')) myAddress, 'payloadlengthextrabytes'))
# When we encrypt, we'll use a hash of the data # When we encrypt, we'll use a hash of the data
@ -342,7 +345,7 @@ class singleWorker(threading.Thread, StoppableThread):
dataToEncrypt, hexlify(pubEncryptionKey)) dataToEncrypt, hexlify(pubEncryptionKey))
# Do the POW for this pubkey message # Do the POW for this pubkey message
target = 2 ** 64 / (shared.networkDefaultProofOfWorkNonceTrialsPerByte*(len(payload) + 8 + shared.networkDefaultPayloadLengthExtraBytes + ((TTL*(len(payload)+8+shared.networkDefaultPayloadLengthExtraBytes))/(2 ** 16)))) target = 2 ** 64 / (protocol.networkDefaultProofOfWorkNonceTrialsPerByte*(len(payload) + 8 + protocol.networkDefaultPayloadLengthExtraBytes + ((TTL*(len(payload)+8+protocol.networkDefaultPayloadLengthExtraBytes))/(2 ** 16))))
logger.info('(For pubkey message) Doing proof of work...') logger.info('(For pubkey message) 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)
@ -351,7 +354,7 @@ class singleWorker(threading.Thread, StoppableThread):
payload = pack('>Q', nonce) + payload payload = pack('>Q', nonce) + payload
inventoryHash = calculateInventoryHash(payload) inventoryHash = calculateInventoryHash(payload)
objectType = 1 objectType = 1
shared.inventory[inventoryHash] = ( Inventory()[inventoryHash] = (
objectType, streamNumber, payload, embeddedTime, doubleHashOfAddressData[32:]) objectType, streamNumber, payload, embeddedTime, doubleHashOfAddressData[32:])
logger.info('broadcasting inv with hash: ' + hexlify(inventoryHash)) logger.info('broadcasting inv with hash: ' + hexlify(inventoryHash))
@ -360,7 +363,7 @@ class singleWorker(threading.Thread, StoppableThread):
streamNumber, 'advertiseobject', inventoryHash)) streamNumber, 'advertiseobject', inventoryHash))
shared.UISignalQueue.put(('updateStatusBar', '')) shared.UISignalQueue.put(('updateStatusBar', ''))
try: try:
shared.config.set( BMConfigParser().set(
myAddress, 'lastpubkeysendtime', str(int(time.time()))) myAddress, 'lastpubkeysendtime', str(int(time.time())))
shared.writeKeysFile() shared.writeKeysFile()
except Exception as err: except Exception as err:
@ -383,9 +386,9 @@ class singleWorker(threading.Thread, StoppableThread):
# We need to convert our private keys to public keys in order # We need to convert our private keys to public keys in order
# to include them. # to include them.
try: try:
privSigningKeyBase58 = shared.config.get( privSigningKeyBase58 = BMConfigParser().get(
fromaddress, 'privsigningkey') fromaddress, 'privsigningkey')
privEncryptionKeyBase58 = shared.config.get( privEncryptionKeyBase58 = BMConfigParser().get(
fromaddress, 'privencryptionkey') fromaddress, 'privencryptionkey')
except: except:
shared.UISignalQueue.put(('updateSentItemStatusByAckdata', ( shared.UISignalQueue.put(('updateSentItemStatusByAckdata', (
@ -431,12 +434,12 @@ class singleWorker(threading.Thread, StoppableThread):
dataToEncrypt = encodeVarint(addressVersionNumber) dataToEncrypt = encodeVarint(addressVersionNumber)
dataToEncrypt += encodeVarint(streamNumber) dataToEncrypt += encodeVarint(streamNumber)
dataToEncrypt += getBitfield(fromaddress) # behavior bitfield dataToEncrypt += protocol.getBitfield(fromaddress) # behavior bitfield
dataToEncrypt += pubSigningKey[1:] dataToEncrypt += pubSigningKey[1:]
dataToEncrypt += pubEncryptionKey[1:] dataToEncrypt += pubEncryptionKey[1:]
if addressVersionNumber >= 3: if addressVersionNumber >= 3:
dataToEncrypt += encodeVarint(shared.config.getint(fromaddress,'noncetrialsperbyte')) dataToEncrypt += encodeVarint(BMConfigParser().getint(fromaddress,'noncetrialsperbyte'))
dataToEncrypt += encodeVarint(shared.config.getint(fromaddress,'payloadlengthextrabytes')) dataToEncrypt += encodeVarint(BMConfigParser().getint(fromaddress,'payloadlengthextrabytes'))
dataToEncrypt += encodeVarint(encoding) # message encoding type dataToEncrypt += encodeVarint(encoding) # message encoding type
encodedMessage = helper_msgcoding.MsgEncode({"subject": subject, "body": body}, encoding) encodedMessage = helper_msgcoding.MsgEncode({"subject": subject, "body": body}, encoding)
dataToEncrypt += encodeVarint(encodedMessage.length) dataToEncrypt += encodeVarint(encodedMessage.length)
@ -463,7 +466,7 @@ class singleWorker(threading.Thread, StoppableThread):
payload += highlevelcrypto.encrypt( payload += highlevelcrypto.encrypt(
dataToEncrypt, hexlify(pubEncryptionKey)) dataToEncrypt, hexlify(pubEncryptionKey))
target = 2 ** 64 / (shared.networkDefaultProofOfWorkNonceTrialsPerByte*(len(payload) + 8 + shared.networkDefaultPayloadLengthExtraBytes + ((TTL*(len(payload)+8+shared.networkDefaultPayloadLengthExtraBytes))/(2 ** 16)))) target = 2 ** 64 / (protocol.networkDefaultProofOfWorkNonceTrialsPerByte*(len(payload) + 8 + protocol.networkDefaultPayloadLengthExtraBytes + ((TTL*(len(payload)+8+protocol.networkDefaultPayloadLengthExtraBytes))/(2 ** 16))))
logger.info('(For broadcast message) Doing proof of work...') logger.info('(For broadcast message) Doing proof of work...')
shared.UISignalQueue.put(('updateSentItemStatusByAckdata', ( shared.UISignalQueue.put(('updateSentItemStatusByAckdata', (
ackdata, tr._translate("MainWindow", "Doing work necessary to send broadcast...")))) ackdata, tr._translate("MainWindow", "Doing work necessary to send broadcast..."))))
@ -482,7 +485,7 @@ class singleWorker(threading.Thread, StoppableThread):
inventoryHash = calculateInventoryHash(payload) inventoryHash = calculateInventoryHash(payload)
objectType = 3 objectType = 3
shared.inventory[inventoryHash] = ( Inventory()[inventoryHash] = (
objectType, streamNumber, payload, embeddedTime, tag) objectType, streamNumber, payload, embeddedTime, tag)
logger.info('sending inv (within sendBroadcast function) for object: ' + hexlify(inventoryHash)) logger.info('sending inv (within sendBroadcast function) for object: ' + hexlify(inventoryHash))
shared.broadcastToSendDataQueues(( shared.broadcastToSendDataQueues((
@ -524,7 +527,7 @@ class singleWorker(threading.Thread, StoppableThread):
# so let's assume that we have it. # so let's assume that we have it.
pass pass
# If we are sending a message to ourselves or a chan then we won't need an entry in the pubkeys table; we can calculate the needed pubkey using the private keys in our keys.dat file. # If we are sending a message to ourselves or a chan then we won't need an entry in the pubkeys table; we can calculate the needed pubkey using the private keys in our keys.dat file.
elif shared.config.has_section(toaddress): elif BMConfigParser().has_section(toaddress):
sqlExecute( sqlExecute(
'''UPDATE sent SET status='doingmsgpow' WHERE toaddress=? AND status='msgqueued' ''', '''UPDATE sent SET status='doingmsgpow' WHERE toaddress=? AND status='msgqueued' ''',
toaddress) toaddress)
@ -550,7 +553,7 @@ class singleWorker(threading.Thread, StoppableThread):
toTag = '' toTag = ''
else: else:
toTag = hashlib.sha512(hashlib.sha512(encodeVarint(toAddressVersionNumber)+encodeVarint(toStreamNumber)+toRipe).digest()).digest()[32:] toTag = hashlib.sha512(hashlib.sha512(encodeVarint(toAddressVersionNumber)+encodeVarint(toStreamNumber)+toRipe).digest()).digest()[32:]
if toaddress in shared.neededPubkeys or toTag in shared.neededPubkeys: if toaddress in neededPubkeys or toTag in neededPubkeys:
# We already sent a request for the pubkey # We already sent a request for the pubkey
sqlExecute( sqlExecute(
'''UPDATE sent SET status='awaitingpubkey', sleeptill=? WHERE toaddress=? AND status='msgqueued' ''', '''UPDATE sent SET status='awaitingpubkey', sleeptill=? WHERE toaddress=? AND status='msgqueued' ''',
@ -574,15 +577,15 @@ class singleWorker(threading.Thread, StoppableThread):
toAddressVersionNumber) + encodeVarint(toStreamNumber) + toRipe).digest()).digest() toAddressVersionNumber) + encodeVarint(toStreamNumber) + toRipe).digest()).digest()
privEncryptionKey = doubleHashOfToAddressData[:32] # The first half of the sha512 hash. privEncryptionKey = doubleHashOfToAddressData[:32] # The first half of the sha512 hash.
tag = doubleHashOfToAddressData[32:] # The second half of the sha512 hash. tag = doubleHashOfToAddressData[32:] # The second half of the sha512 hash.
shared.neededPubkeys[tag] = (toaddress, highlevelcrypto.makeCryptor(hexlify(privEncryptionKey))) neededPubkeys[tag] = (toaddress, highlevelcrypto.makeCryptor(hexlify(privEncryptionKey)))
for value in shared.inventory.by_type_and_tag(1, toTag): for value in Inventory().by_type_and_tag(1, toTag):
if shared.decryptAndCheckPubkeyPayload(value.payload, toaddress) == 'successful': #if valid, this function also puts it in the pubkeys table. if shared.decryptAndCheckPubkeyPayload(value.payload, toaddress) == 'successful': #if valid, this function also puts it in the pubkeys table.
needToRequestPubkey = False needToRequestPubkey = False
sqlExecute( sqlExecute(
'''UPDATE sent SET status='doingmsgpow', retrynumber=0 WHERE toaddress=? AND (status='msgqueued' or status='awaitingpubkey' or status='doingpubkeypow')''', '''UPDATE sent SET status='doingmsgpow', retrynumber=0 WHERE toaddress=? AND (status='msgqueued' or status='awaitingpubkey' or status='doingpubkeypow')''',
toaddress) toaddress)
del shared.neededPubkeys[tag] del neededPubkeys[tag]
break break
#else: # There was something wrong with this pubkey object even #else: # There was something wrong with this pubkey object even
# though it had the correct tag- almost certainly because # though it had the correct tag- almost certainly because
@ -608,7 +611,7 @@ class singleWorker(threading.Thread, StoppableThread):
TTL = int(TTL + random.randrange(-300, 300))# add some randomness to the TTL TTL = int(TTL + random.randrange(-300, 300))# add some randomness to the TTL
embeddedTime = int(time.time() + TTL) embeddedTime = int(time.time() + TTL)
if not shared.config.has_section(toaddress): # if we aren't sending this to ourselves or a chan if not BMConfigParser().has_section(toaddress): # if we aren't sending this to ourselves or a chan
shared.ackdataForWhichImWatching[ackdata] = 0 shared.ackdataForWhichImWatching[ackdata] = 0
shared.UISignalQueue.put(('updateSentItemStatusByAckdata', ( shared.UISignalQueue.put(('updateSentItemStatusByAckdata', (
ackdata, tr._translate("MainWindow", "Looking up the receiver\'s public key")))) ackdata, tr._translate("MainWindow", "Looking up the receiver\'s public key"))))
@ -642,7 +645,7 @@ class singleWorker(threading.Thread, StoppableThread):
# unencrypted. Before we actually do it the sending human must check a box # unencrypted. Before we actually do it the sending human must check a box
# in the settings menu to allow it. # in the settings menu to allow it.
if shared.isBitSetWithinBitfield(behaviorBitfield,30): # if receiver is a mobile device who expects that their address RIPE is included unencrypted on the front of the message.. if shared.isBitSetWithinBitfield(behaviorBitfield,30): # if receiver is a mobile device who expects that their address RIPE is included unencrypted on the front of the message..
if not shared.safeConfigGetBoolean('bitmessagesettings','willinglysendtomobile'): # if we are Not willing to include the receiver's RIPE hash on the message.. if not shared.BMConfigParser().safeGetBoolean('bitmessagesettings','willinglysendtomobile'): # if we are Not willing to include the receiver's RIPE hash on the message..
logger.info('The receiver is a mobile user but the sender (you) has not selected that you are willing to send to mobiles. Aborting send.') logger.info('The receiver is a mobile user but the sender (you) has not selected that you are willing to send to mobiles. Aborting send.')
shared.UISignalQueue.put(('updateSentItemStatusByAckdata',(ackdata,tr._translate("MainWindow",'Problem: Destination is a mobile device who requests that the destination be included in the message but this is disallowed in your settings. %1').arg(l10n.formatTimestamp())))) shared.UISignalQueue.put(('updateSentItemStatusByAckdata',(ackdata,tr._translate("MainWindow",'Problem: Destination is a mobile device who requests that the destination be included in the message but this is disallowed in your settings. %1').arg(l10n.formatTimestamp()))))
# if the human changes their setting and then sends another message or restarts their client, this one will send at that time. # if the human changes their setting and then sends another message or restarts their client, this one will send at that time.
@ -656,8 +659,8 @@ class singleWorker(threading.Thread, StoppableThread):
# Let us fetch the amount of work required by the recipient. # Let us fetch the amount of work required by the recipient.
if toAddressVersionNumber == 2: if toAddressVersionNumber == 2:
requiredAverageProofOfWorkNonceTrialsPerByte = shared.networkDefaultProofOfWorkNonceTrialsPerByte requiredAverageProofOfWorkNonceTrialsPerByte = protocol.networkDefaultProofOfWorkNonceTrialsPerByte
requiredPayloadLengthExtraBytes = shared.networkDefaultPayloadLengthExtraBytes requiredPayloadLengthExtraBytes = protocol.networkDefaultPayloadLengthExtraBytes
shared.UISignalQueue.put(('updateSentItemStatusByAckdata', ( shared.UISignalQueue.put(('updateSentItemStatusByAckdata', (
ackdata, tr._translate("MainWindow", "Doing work necessary to send message.\nThere is no required difficulty for version 2 addresses like this.")))) ackdata, tr._translate("MainWindow", "Doing work necessary to send message.\nThere is no required difficulty for version 2 addresses like this."))))
elif toAddressVersionNumber >= 3: elif toAddressVersionNumber >= 3:
@ -667,30 +670,30 @@ class singleWorker(threading.Thread, StoppableThread):
requiredPayloadLengthExtraBytes, varintLength = decodeVarint( requiredPayloadLengthExtraBytes, varintLength = decodeVarint(
pubkeyPayload[readPosition:readPosition + 10]) pubkeyPayload[readPosition:readPosition + 10])
readPosition += varintLength readPosition += varintLength
if requiredAverageProofOfWorkNonceTrialsPerByte < shared.networkDefaultProofOfWorkNonceTrialsPerByte: # We still have to meet a minimum POW difficulty regardless of what they say is allowed in order to get our message to propagate through the network. if requiredAverageProofOfWorkNonceTrialsPerByte < protocol.networkDefaultProofOfWorkNonceTrialsPerByte: # We still have to meet a minimum POW difficulty regardless of what they say is allowed in order to get our message to propagate through the network.
requiredAverageProofOfWorkNonceTrialsPerByte = shared.networkDefaultProofOfWorkNonceTrialsPerByte requiredAverageProofOfWorkNonceTrialsPerByte = protocol.networkDefaultProofOfWorkNonceTrialsPerByte
if requiredPayloadLengthExtraBytes < shared.networkDefaultPayloadLengthExtraBytes: if requiredPayloadLengthExtraBytes < protocol.networkDefaultPayloadLengthExtraBytes:
requiredPayloadLengthExtraBytes = shared.networkDefaultPayloadLengthExtraBytes requiredPayloadLengthExtraBytes = protocol.networkDefaultPayloadLengthExtraBytes
logger.debug('Using averageProofOfWorkNonceTrialsPerByte: %s and payloadLengthExtraBytes: %s.' % (requiredAverageProofOfWorkNonceTrialsPerByte, requiredPayloadLengthExtraBytes)) logger.debug('Using averageProofOfWorkNonceTrialsPerByte: %s and payloadLengthExtraBytes: %s.' % (requiredAverageProofOfWorkNonceTrialsPerByte, requiredPayloadLengthExtraBytes))
shared.UISignalQueue.put(('updateSentItemStatusByAckdata', (ackdata, tr._translate("MainWindow", "Doing work necessary to send message.\nReceiver\'s required difficulty: %1 and %2").arg(str(float( shared.UISignalQueue.put(('updateSentItemStatusByAckdata', (ackdata, tr._translate("MainWindow", "Doing work necessary to send message.\nReceiver\'s required difficulty: %1 and %2").arg(str(float(
requiredAverageProofOfWorkNonceTrialsPerByte) / shared.networkDefaultProofOfWorkNonceTrialsPerByte)).arg(str(float(requiredPayloadLengthExtraBytes) / shared.networkDefaultPayloadLengthExtraBytes))))) requiredAverageProofOfWorkNonceTrialsPerByte) / protocol.networkDefaultProofOfWorkNonceTrialsPerByte)).arg(str(float(requiredPayloadLengthExtraBytes) / protocol.networkDefaultPayloadLengthExtraBytes)))))
if status != 'forcepow': if status != 'forcepow':
if (requiredAverageProofOfWorkNonceTrialsPerByte > shared.config.getint('bitmessagesettings', 'maxacceptablenoncetrialsperbyte') and shared.config.getint('bitmessagesettings', 'maxacceptablenoncetrialsperbyte') != 0) or (requiredPayloadLengthExtraBytes > shared.config.getint('bitmessagesettings', 'maxacceptablepayloadlengthextrabytes') and shared.config.getint('bitmessagesettings', 'maxacceptablepayloadlengthextrabytes') != 0): if (requiredAverageProofOfWorkNonceTrialsPerByte > BMConfigParser().getint('bitmessagesettings', 'maxacceptablenoncetrialsperbyte') and BMConfigParser().getint('bitmessagesettings', 'maxacceptablenoncetrialsperbyte') != 0) or (requiredPayloadLengthExtraBytes > BMConfigParser().getint('bitmessagesettings', 'maxacceptablepayloadlengthextrabytes') and BMConfigParser().getint('bitmessagesettings', 'maxacceptablepayloadlengthextrabytes') != 0):
# The demanded difficulty is more than we are willing # The demanded difficulty is more than we are willing
# to do. # to do.
sqlExecute( sqlExecute(
'''UPDATE sent SET status='toodifficult' WHERE ackdata=? ''', '''UPDATE sent SET status='toodifficult' WHERE ackdata=? ''',
ackdata) ackdata)
shared.UISignalQueue.put(('updateSentItemStatusByAckdata', (ackdata, tr._translate("MainWindow", "Problem: The work demanded by the recipient (%1 and %2) is more difficult than you are willing to do. %3").arg(str(float(requiredAverageProofOfWorkNonceTrialsPerByte) / shared.networkDefaultProofOfWorkNonceTrialsPerByte)).arg(str(float( shared.UISignalQueue.put(('updateSentItemStatusByAckdata', (ackdata, tr._translate("MainWindow", "Problem: The work demanded by the recipient (%1 and %2) is more difficult than you are willing to do. %3").arg(str(float(requiredAverageProofOfWorkNonceTrialsPerByte) / protocol.networkDefaultProofOfWorkNonceTrialsPerByte)).arg(str(float(
requiredPayloadLengthExtraBytes) / shared.networkDefaultPayloadLengthExtraBytes)).arg(l10n.formatTimestamp())))) requiredPayloadLengthExtraBytes) / protocol.networkDefaultPayloadLengthExtraBytes)).arg(l10n.formatTimestamp()))))
continue continue
else: # if we are sending a message to ourselves or a chan.. else: # if we are sending a message to ourselves or a chan..
logger.info('Sending a message.') logger.info('Sending a message.')
logger.debug('First 150 characters of message: ' + repr(message[:150])) logger.debug('First 150 characters of message: ' + repr(message[:150]))
behaviorBitfield = getBitfield(fromaddress) behaviorBitfield = protocol.getBitfield(fromaddress)
try: try:
privEncryptionKeyBase58 = shared.config.get( privEncryptionKeyBase58 = BMConfigParser().get(
toaddress, 'privencryptionkey') toaddress, 'privencryptionkey')
except Exception as err: except Exception as err:
shared.UISignalQueue.put(('updateSentItemStatusByAckdata',(ackdata,tr._translate("MainWindow",'Problem: You are trying to send a message to yourself or a chan but your encryption key could not be found in the keys.dat file. Could not encrypt message. %1').arg(l10n.formatTimestamp())))) shared.UISignalQueue.put(('updateSentItemStatusByAckdata',(ackdata,tr._translate("MainWindow",'Problem: You are trying to send a message to yourself or a chan but your encryption key could not be found in the keys.dat file. Could not encrypt message. %1').arg(l10n.formatTimestamp()))))
@ -700,22 +703,23 @@ class singleWorker(threading.Thread, StoppableThread):
privEncryptionKeyBase58)) privEncryptionKeyBase58))
pubEncryptionKeyBase256 = unhexlify(highlevelcrypto.privToPub( pubEncryptionKeyBase256 = unhexlify(highlevelcrypto.privToPub(
privEncryptionKeyHex))[1:] privEncryptionKeyHex))[1:]
requiredAverageProofOfWorkNonceTrialsPerByte = shared.networkDefaultProofOfWorkNonceTrialsPerByte requiredAverageProofOfWorkNonceTrialsPerByte = protocol.networkDefaultProofOfWorkNonceTrialsPerByte
requiredPayloadLengthExtraBytes = shared.networkDefaultPayloadLengthExtraBytes requiredPayloadLengthExtraBytes = protocol.networkDefaultPayloadLengthExtraBytes
shared.UISignalQueue.put(('updateSentItemStatusByAckdata', ( shared.UISignalQueue.put(('updateSentItemStatusByAckdata', (
ackdata, tr._translate("MainWindow", "Doing work necessary to send message.")))) ackdata, tr._translate("MainWindow", "Doing work necessary to send message."))))
# Now we can start to assemble our message. # Now we can start to assemble our message.
payload = encodeVarint(fromAddressVersionNumber) payload = encodeVarint(fromAddressVersionNumber)
payload += encodeVarint(fromStreamNumber) payload += encodeVarint(fromStreamNumber)
payload += getBitfield(fromaddress) # Bitfield of features and behaviors that can be expected from me. (See https://bitmessage.org/wiki/Protocol_specification#Pubkey_bitfield_features ) payload += protocol.getBitfield(fromaddress) # Bitfield of features and behaviors that can be expected from me. (See https://bitmessage.org/wiki/Protocol_specification#Pubkey_bitfield_features )
print("Going to do PoW 4")
# We need to convert our private keys to public keys in order # We need to convert our private keys to public keys in order
# to include them. # to include them.
try: try:
privSigningKeyBase58 = shared.config.get( privSigningKeyBase58 = BMConfigParser().get(
fromaddress, 'privsigningkey') fromaddress, 'privsigningkey')
privEncryptionKeyBase58 = shared.config.get( privEncryptionKeyBase58 = BMConfigParser().get(
fromaddress, 'privencryptionkey') fromaddress, 'privencryptionkey')
except: except:
shared.UISignalQueue.put(('updateSentItemStatusByAckdata', ( shared.UISignalQueue.put(('updateSentItemStatusByAckdata', (
@ -743,13 +747,13 @@ class singleWorker(threading.Thread, StoppableThread):
# the receiver is in any of those lists. # the receiver is in any of those lists.
if shared.isAddressInMyAddressBookSubscriptionsListOrWhitelist(toaddress): if shared.isAddressInMyAddressBookSubscriptionsListOrWhitelist(toaddress):
payload += encodeVarint( payload += encodeVarint(
shared.networkDefaultProofOfWorkNonceTrialsPerByte) protocol.networkDefaultProofOfWorkNonceTrialsPerByte)
payload += encodeVarint( payload += encodeVarint(
shared.networkDefaultPayloadLengthExtraBytes) protocol.networkDefaultPayloadLengthExtraBytes)
else: else:
payload += encodeVarint(shared.config.getint( payload += encodeVarint(BMConfigParser().getint(
fromaddress, 'noncetrialsperbyte')) fromaddress, 'noncetrialsperbyte'))
payload += encodeVarint(shared.config.getint( payload += encodeVarint(BMConfigParser().getint(
fromaddress, 'payloadlengthextrabytes')) fromaddress, 'payloadlengthextrabytes'))
payload += toRipe # This hash will be checked by the receiver of the message to verify that toRipe belongs to them. This prevents a Surreptitious Forwarding Attack. payload += toRipe # This hash will be checked by the receiver of the message to verify that toRipe belongs to them. This prevents a Surreptitious Forwarding Attack.
@ -757,10 +761,10 @@ class singleWorker(threading.Thread, StoppableThread):
encodedMessage = helper_msgcoding.MsgEncode({"subject": subject, "body": message}, encoding) encodedMessage = helper_msgcoding.MsgEncode({"subject": subject, "body": message}, encoding)
payload += encodeVarint(encodedMessage.length) payload += encodeVarint(encodedMessage.length)
payload += encodedMessage.data payload += encodedMessage.data
if shared.config.has_section(toaddress): if BMConfigParser().has_section(toaddress):
logger.info('Not bothering to include ackdata because we are sending to ourselves or a chan.') logger.info('Not bothering to include ackdata because we are sending to ourselves or a chan.')
fullAckPayload = '' fullAckPayload = ''
elif not checkBitfield(behaviorBitfield, shared.BITFIELD_DOESACK): elif not protocol.checkBitfield(behaviorBitfield, protocol.BITFIELD_DOESACK):
logger.info('Not bothering to include ackdata because the receiver said that they won\'t relay it anyway.') logger.info('Not bothering to include ackdata because the receiver said that they won\'t relay it anyway.')
fullAckPayload = '' fullAckPayload = ''
else: else:
@ -786,7 +790,7 @@ class singleWorker(threading.Thread, StoppableThread):
encryptedPayload += encodeVarint(1) # msg version encryptedPayload += encodeVarint(1) # msg version
encryptedPayload += encodeVarint(toStreamNumber) + encrypted encryptedPayload += encodeVarint(toStreamNumber) + encrypted
target = 2 ** 64 / (requiredAverageProofOfWorkNonceTrialsPerByte*(len(encryptedPayload) + 8 + requiredPayloadLengthExtraBytes + ((TTL*(len(encryptedPayload)+8+requiredPayloadLengthExtraBytes))/(2 ** 16)))) target = 2 ** 64 / (requiredAverageProofOfWorkNonceTrialsPerByte*(len(encryptedPayload) + 8 + requiredPayloadLengthExtraBytes + ((TTL*(len(encryptedPayload)+8+requiredPayloadLengthExtraBytes))/(2 ** 16))))
logger.info('(For msg message) Doing proof of work. Total required difficulty: %f. Required small message difficulty: %f.', float(requiredAverageProofOfWorkNonceTrialsPerByte) / shared.networkDefaultProofOfWorkNonceTrialsPerByte, float(requiredPayloadLengthExtraBytes) / shared.networkDefaultPayloadLengthExtraBytes) logger.info('(For msg message) Doing proof of work. Total required difficulty: %f. Required small message difficulty: %f.', float(requiredAverageProofOfWorkNonceTrialsPerByte) / protocol.networkDefaultProofOfWorkNonceTrialsPerByte, float(requiredPayloadLengthExtraBytes) / protocol.networkDefaultPayloadLengthExtraBytes)
powStartTime = time.time() powStartTime = time.time()
initialHash = hashlib.sha512(encryptedPayload).digest() initialHash = hashlib.sha512(encryptedPayload).digest()
@ -808,9 +812,9 @@ class singleWorker(threading.Thread, StoppableThread):
inventoryHash = calculateInventoryHash(encryptedPayload) inventoryHash = calculateInventoryHash(encryptedPayload)
objectType = 2 objectType = 2
shared.inventory[inventoryHash] = ( Inventory()[inventoryHash] = (
objectType, toStreamNumber, encryptedPayload, embeddedTime, '') objectType, toStreamNumber, encryptedPayload, embeddedTime, '')
if shared.config.has_section(toaddress) or not checkBitfield(behaviorBitfield, shared.BITFIELD_DOESACK): if BMConfigParser().has_section(toaddress) or not protocol.checkBitfield(behaviorBitfield, protocol.BITFIELD_DOESACK):
shared.UISignalQueue.put(('updateSentItemStatusByAckdata', (ackdata, tr._translate("MainWindow", "Message sent. Sent at %1").arg(l10n.formatTimestamp())))) shared.UISignalQueue.put(('updateSentItemStatusByAckdata', (ackdata, tr._translate("MainWindow", "Message sent. Sent at %1").arg(l10n.formatTimestamp()))))
else: else:
# not sending to a chan or one of my addresses # not sending to a chan or one of my addresses
@ -820,7 +824,7 @@ class singleWorker(threading.Thread, StoppableThread):
toStreamNumber, 'advertiseobject', inventoryHash)) toStreamNumber, 'advertiseobject', inventoryHash))
# Update the sent message in the sent table with the necessary information. # Update the sent message in the sent table with the necessary information.
if shared.config.has_section(toaddress) or not checkBitfield(behaviorBitfield, shared.BITFIELD_DOESACK): if BMConfigParser().has_section(toaddress) or not protocol.checkBitfield(behaviorBitfield, protocol.BITFIELD_DOESACK):
newStatus = 'msgsentnoackexpected' newStatus = 'msgsentnoackexpected'
else: else:
newStatus = 'msgsent' newStatus = 'msgsent'
@ -838,7 +842,7 @@ class singleWorker(threading.Thread, StoppableThread):
# If we are sending to ourselves or a chan, let's put the message in # If we are sending to ourselves or a chan, let's put the message in
# our own inbox. # our own inbox.
if shared.config.has_section(toaddress): if BMConfigParser().has_section(toaddress):
sigHash = hashlib.sha512(hashlib.sha512(signature).digest()).digest()[32:] # Used to detect and ignore duplicate messages in our inbox sigHash = hashlib.sha512(hashlib.sha512(signature).digest()).digest()[32:] # Used to detect and ignore duplicate messages in our inbox
t = (inventoryHash, toaddress, fromaddress, subject, int( t = (inventoryHash, toaddress, fromaddress, subject, int(
time.time()), message, 'inbox', encoding, 0, sigHash) time.time()), message, 'inbox', encoding, 0, sigHash)
@ -850,9 +854,9 @@ class singleWorker(threading.Thread, StoppableThread):
# If we are behaving as an API then we might need to run an # If we are behaving as an API then we might need to run an
# outside command to let some program know that a new message # outside command to let some program know that a new message
# has arrived. # has arrived.
if shared.safeConfigGetBoolean('bitmessagesettings', 'apienabled'): if BMConfigParser().safeGetBoolean('bitmessagesettings', 'apienabled'):
try: try:
apiNotifyPath = shared.config.get( apiNotifyPath = BMConfigParser().get(
'bitmessagesettings', 'apinotifypath') 'bitmessagesettings', 'apinotifypath')
except: except:
apiNotifyPath = '' apiNotifyPath = ''
@ -876,15 +880,15 @@ class singleWorker(threading.Thread, StoppableThread):
retryNumber = queryReturn[0][0] retryNumber = queryReturn[0][0]
if addressVersionNumber <= 3: if addressVersionNumber <= 3:
shared.neededPubkeys[toAddress] = 0 neededPubkeys[toAddress] = 0
elif addressVersionNumber >= 4: elif addressVersionNumber >= 4:
# If the user just clicked 'send' then the tag (and other information) will already # If the user just clicked 'send' then the tag (and other information) will already
# be in the neededPubkeys dictionary. But if we are recovering from a restart # be in the neededPubkeys dictionary. But if we are recovering from a restart
# of the client then we have to put it in now. # of the client then we have to put it in now.
privEncryptionKey = hashlib.sha512(hashlib.sha512(encodeVarint(addressVersionNumber)+encodeVarint(streamNumber)+ripe).digest()).digest()[:32] # Note that this is the first half of the sha512 hash. privEncryptionKey = hashlib.sha512(hashlib.sha512(encodeVarint(addressVersionNumber)+encodeVarint(streamNumber)+ripe).digest()).digest()[:32] # Note that this is the first half of the sha512 hash.
tag = hashlib.sha512(hashlib.sha512(encodeVarint(addressVersionNumber)+encodeVarint(streamNumber)+ripe).digest()).digest()[32:] # Note that this is the second half of the sha512 hash. tag = hashlib.sha512(hashlib.sha512(encodeVarint(addressVersionNumber)+encodeVarint(streamNumber)+ripe).digest()).digest()[32:] # Note that this is the second half of the sha512 hash.
if tag not in shared.neededPubkeys: if tag not in neededPubkeys:
shared.neededPubkeys[tag] = (toAddress, highlevelcrypto.makeCryptor(hexlify(privEncryptionKey))) # We'll need this for when we receive a pubkey reply: it will be encrypted and we'll need to decrypt it. neededPubkeys[tag] = (toAddress, highlevelcrypto.makeCryptor(hexlify(privEncryptionKey))) # We'll need this for when we receive a pubkey reply: it will be encrypted and we'll need to decrypt it.
if retryNumber == 0: if retryNumber == 0:
TTL = 2.5*24*60*60 # 2.5 days. This was chosen fairly arbitrarily. TTL = 2.5*24*60*60 # 2.5 days. This was chosen fairly arbitrarily.
@ -909,7 +913,7 @@ class singleWorker(threading.Thread, StoppableThread):
shared.UISignalQueue.put(('updateSentItemStatusByToAddress', ( shared.UISignalQueue.put(('updateSentItemStatusByToAddress', (
toAddress, tr._translate("MainWindow",'Doing work necessary to request encryption key.')))) toAddress, tr._translate("MainWindow",'Doing work necessary to request encryption key.'))))
target = 2 ** 64 / (shared.networkDefaultProofOfWorkNonceTrialsPerByte*(len(payload) + 8 + shared.networkDefaultPayloadLengthExtraBytes + ((TTL*(len(payload)+8+shared.networkDefaultPayloadLengthExtraBytes))/(2 ** 16)))) target = 2 ** 64 / (protocol.networkDefaultProofOfWorkNonceTrialsPerByte*(len(payload) + 8 + protocol.networkDefaultPayloadLengthExtraBytes + ((TTL*(len(payload)+8+protocol.networkDefaultPayloadLengthExtraBytes))/(2 ** 16))))
initialHash = hashlib.sha512(payload).digest() initialHash = hashlib.sha512(payload).digest()
trialValue, nonce = proofofwork.run(target, initialHash) trialValue, nonce = proofofwork.run(target, initialHash)
logger.info('Found proof of work ' + str(trialValue) + ' Nonce: ' + str(nonce)) logger.info('Found proof of work ' + str(trialValue) + ' Nonce: ' + str(nonce))
@ -917,7 +921,7 @@ class singleWorker(threading.Thread, StoppableThread):
payload = pack('>Q', nonce) + payload payload = pack('>Q', nonce) + payload
inventoryHash = calculateInventoryHash(payload) inventoryHash = calculateInventoryHash(payload)
objectType = 1 objectType = 1
shared.inventory[inventoryHash] = ( Inventory()[inventoryHash] = (
objectType, streamNumber, payload, embeddedTime, '') objectType, streamNumber, payload, embeddedTime, '')
logger.info('sending inv (for the getpubkey message)') logger.info('sending inv (for the getpubkey message)')
shared.broadcastToSendDataQueues(( shared.broadcastToSendDataQueues((
@ -962,7 +966,7 @@ class singleWorker(threading.Thread, StoppableThread):
payload += encodeVarint(1) # msg version payload += encodeVarint(1) # msg version
payload += encodeVarint(toStreamNumber) + ackdata payload += encodeVarint(toStreamNumber) + ackdata
target = 2 ** 64 / (shared.networkDefaultProofOfWorkNonceTrialsPerByte*(len(payload) + 8 + shared.networkDefaultPayloadLengthExtraBytes + ((TTL*(len(payload)+8+shared.networkDefaultPayloadLengthExtraBytes))/(2 ** 16)))) target = 2 ** 64 / (protocol.networkDefaultProofOfWorkNonceTrialsPerByte*(len(payload) + 8 + protocol.networkDefaultPayloadLengthExtraBytes + ((TTL*(len(payload)+8+protocol.networkDefaultPayloadLengthExtraBytes))/(2 ** 16))))
logger.info('(For ack message) Doing proof of work. TTL set to ' + str(TTL)) logger.info('(For ack message) Doing proof of work. TTL set to ' + str(TTL))
powStartTime = time.time() powStartTime = time.time()
@ -975,4 +979,4 @@ class singleWorker(threading.Thread, StoppableThread):
pass pass
payload = pack('>Q', nonce) + payload payload = pack('>Q', nonce) + payload
return shared.CreatePacket('object', payload) return protocol.CreatePacket('object', payload)

View File

@ -5,8 +5,10 @@ import sys
import threading import threading
import urlparse import urlparse
from configparser import BMConfigParser
from debug import logger from debug import logger
from helper_threading import * from helper_threading import *
from bitmessageqt.uisignaler import UISignaler
import shared import shared
SMTPDOMAIN = "bmaddr.lan" SMTPDOMAIN = "bmaddr.lan"
@ -47,7 +49,7 @@ class smtpDeliver(threading.Thread, StoppableThread):
pass pass
elif command == 'displayNewInboxMessage': elif command == 'displayNewInboxMessage':
inventoryHash, toAddress, fromAddress, subject, body = data inventoryHash, toAddress, fromAddress, subject, body = data
dest = shared.safeConfigGet("bitmessagesettings", "smtpdeliver", '') dest = BMConfigParser().safeGet("bitmessagesettings", "smtpdeliver", '')
if dest == '': if dest == '':
continue continue
try: try:
@ -57,7 +59,7 @@ class smtpDeliver(threading.Thread, StoppableThread):
msg = MIMEText(body, 'plain', 'utf-8') msg = MIMEText(body, 'plain', 'utf-8')
msg['Subject'] = Header(subject, 'utf-8') msg['Subject'] = Header(subject, 'utf-8')
msg['From'] = fromAddress + '@' + SMTPDOMAIN msg['From'] = fromAddress + '@' + SMTPDOMAIN
toLabel = map (lambda y: shared.safeConfigGet(y, "label"), filter(lambda x: x == toAddress, shared.config.sections())) toLabel = map (lambda y: BMConfigParser().safeGet(y, "label"), filter(lambda x: x == toAddress, BMConfigParser().sections()))
if len(toLabel) > 0: if len(toLabel) > 0:
msg['To'] = "\"%s\" <%s>" % (Header(toLabel[0], 'utf-8'), toAddress + '@' + SMTPDOMAIN) msg['To'] = "\"%s\" <%s>" % (Header(toLabel[0], 'utf-8'), toAddress + '@' + SMTPDOMAIN)
else: else:

View File

@ -6,15 +6,18 @@ from email.header import decode_header
import re import re
import signal import signal
import smtpd import smtpd
import socket
import threading import threading
import time import time
from addresses import decodeAddress from addresses import decodeAddress
from configparser import BMConfigParser
from debug import logger from debug import logger
from helper_sql import sqlExecute from helper_sql import sqlExecute
from helper_threading import StoppableThread from helper_threading import StoppableThread
from pyelliptic.openssl import OpenSSL from pyelliptic.openssl import OpenSSL
import shared import shared
from version import softwareVersion
SMTPDOMAIN = "bmaddr.lan" SMTPDOMAIN = "bmaddr.lan"
LISTENPORT = 8425 LISTENPORT = 8425
@ -24,7 +27,7 @@ class smtpServerChannel(smtpd.SMTPChannel):
if not arg: if not arg:
self.push('501 Syntax: HELO hostname') self.push('501 Syntax: HELO hostname')
return return
self.push('250-PyBitmessage %s' % shared.softwareVersion) self.push('250-PyBitmessage %s' % softwareVersion)
self.push('250 AUTH PLAIN') self.push('250 AUTH PLAIN')
def smtp_AUTH(self, arg): def smtp_AUTH(self, arg):
@ -34,14 +37,14 @@ class smtpServerChannel(smtpd.SMTPChannel):
authstring = arg[6:] authstring = arg[6:]
try: try:
decoded = base64.b64decode(authstring) decoded = base64.b64decode(authstring)
correctauth = "\x00" + shared.safeConfigGet("bitmessagesettings", "smtpdusername", "") + \ correctauth = "\x00" + BMConfigParser().safeGet("bitmessagesettings", "smtpdusername", "") + \
"\x00" + shared.safeConfigGet("bitmessagesettings", "smtpdpassword", "") "\x00" + BMConfigParser().safeGet("bitmessagesettings", "smtpdpassword", "")
logger.debug("authstring: %s / %s", correctauth, decoded) logger.debug("authstring: %s / %s", correctauth, decoded)
if correctauth == decoded: if correctauth == decoded:
self.auth = True self.auth = True
self.push('235 2.7.0 Authentication successful') self.push('235 2.7.0 Authentication successful')
else: else:
raise Error("Auth fail") raise Exception("Auth fail")
except: except:
self.push('501 Authentication fail') self.push('501 Authentication fail')
@ -80,7 +83,7 @@ class smtpServerPyBitmessage(smtpd.SMTPServer):
0, # retryNumber 0, # retryNumber
'sent', # folder 'sent', # folder
2, # encodingtype 2, # encodingtype
min(shared.config.getint('bitmessagesettings', 'ttl'), 86400 * 2) # not necessary to have a TTL higher than 2 days min(BMConfigParser().getint('bitmessagesettings', 'ttl'), 86400 * 2) # not necessary to have a TTL higher than 2 days
) )
shared.workerQueue.put(('sendmessage', toAddress)) shared.workerQueue.put(('sendmessage', toAddress))
@ -112,7 +115,7 @@ class smtpServerPyBitmessage(smtpd.SMTPServer):
sender, domain = p.sub(r'\1', mailfrom).split("@") sender, domain = p.sub(r'\1', mailfrom).split("@")
if domain != SMTPDOMAIN: if domain != SMTPDOMAIN:
raise Exception("Bad domain %s", domain) raise Exception("Bad domain %s", domain)
if sender not in shared.config.sections(): if sender not in BMConfigParser().sections():
raise Exception("Nonexisting user %s", sender) raise Exception("Nonexisting user %s", sender)
except Exception as err: except Exception as err:
logger.debug("Bad envelope from %s: %s", mailfrom, repr(err)) logger.debug("Bad envelope from %s: %s", mailfrom, repr(err))
@ -122,7 +125,7 @@ class smtpServerPyBitmessage(smtpd.SMTPServer):
sender, domain = msg_from.split("@") sender, domain = msg_from.split("@")
if domain != SMTPDOMAIN: if domain != SMTPDOMAIN:
raise Exception("Bad domain %s", domain) raise Exception("Bad domain %s", domain)
if sender not in shared.config.sections(): if sender not in BMConfigParser().sections():
raise Exception("Nonexisting user %s", sender) raise Exception("Nonexisting user %s", sender)
except Exception as err: except Exception as err:
logger.error("Bad headers from %s: %s", msg_from, repr(err)) logger.error("Bad headers from %s: %s", msg_from, repr(err))
@ -163,7 +166,7 @@ class smtpServer(threading.Thread, StoppableThread):
self.server.close() self.server.close()
return return
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# for ip in ('127.0.0.1', shared.config.get('bitmessagesettings', 'onionbindip')): # for ip in ('127.0.0.1', BMConfigParser().get('bitmessagesettings', 'onionbindip')):
for ip in ('127.0.0.1'): for ip in ('127.0.0.1'):
try: try:
s.connect((ip, LISTENPORT)) s.connect((ip, LISTENPORT))

View File

@ -1,4 +1,5 @@
import threading import threading
from configparser import BMConfigParser
import shared import shared
import sqlite3 import sqlite3
import time import time
@ -7,7 +8,10 @@ import sys
import os import os
from debug import logger from debug import logger
from namecoin import ensureNamecoinOptions from namecoin import ensureNamecoinOptions
import paths
import protocol
import random import random
import state
import string import string
import tr#anslate import tr#anslate
@ -22,7 +26,7 @@ class sqlThread(threading.Thread):
threading.Thread.__init__(self, name="SQL") threading.Thread.__init__(self, name="SQL")
def run(self): def run(self):
self.conn = sqlite3.connect(shared.appdata + 'messages.dat') self.conn = sqlite3.connect(state.appdata + 'messages.dat')
self.conn.text_factory = str self.conn.text_factory = str
self.cur = self.conn.cursor() self.cur = self.conn.cursor()
@ -65,35 +69,35 @@ class sqlThread(threading.Thread):
'ERROR trying to create database file (message.dat). Error message: %s\n' % str(err)) 'ERROR trying to create database file (message.dat). Error message: %s\n' % str(err))
os._exit(0) os._exit(0)
if shared.config.getint('bitmessagesettings', 'settingsversion') == 1: if BMConfigParser().getint('bitmessagesettings', 'settingsversion') == 1:
shared.config.set('bitmessagesettings', 'settingsversion', '2') BMConfigParser().set('bitmessagesettings', 'settingsversion', '2')
# If the settings version is equal to 2 or 3 then the # If the settings version is equal to 2 or 3 then the
# sqlThread will modify the pubkeys table and change # sqlThread will modify the pubkeys table and change
# the settings version to 4. # the settings version to 4.
shared.config.set('bitmessagesettings', 'socksproxytype', 'none') BMConfigParser().set('bitmessagesettings', 'socksproxytype', 'none')
shared.config.set('bitmessagesettings', 'sockshostname', 'localhost') BMConfigParser().set('bitmessagesettings', 'sockshostname', 'localhost')
shared.config.set('bitmessagesettings', 'socksport', '9050') BMConfigParser().set('bitmessagesettings', 'socksport', '9050')
shared.config.set('bitmessagesettings', 'socksauthentication', 'false') BMConfigParser().set('bitmessagesettings', 'socksauthentication', 'false')
shared.config.set('bitmessagesettings', 'socksusername', '') BMConfigParser().set('bitmessagesettings', 'socksusername', '')
shared.config.set('bitmessagesettings', 'sockspassword', '') BMConfigParser().set('bitmessagesettings', 'sockspassword', '')
shared.config.set('bitmessagesettings', 'sockslisten', 'false') BMConfigParser().set('bitmessagesettings', 'sockslisten', 'false')
shared.config.set('bitmessagesettings', 'keysencrypted', 'false') BMConfigParser().set('bitmessagesettings', 'keysencrypted', 'false')
shared.config.set('bitmessagesettings', 'messagesencrypted', 'false') BMConfigParser().set('bitmessagesettings', 'messagesencrypted', 'false')
# People running earlier versions of PyBitmessage do not have the # People running earlier versions of PyBitmessage do not have the
# usedpersonally field in their pubkeys table. Let's add it. # usedpersonally field in their pubkeys table. Let's add it.
if shared.config.getint('bitmessagesettings', 'settingsversion') == 2: if BMConfigParser().getint('bitmessagesettings', 'settingsversion') == 2:
item = '''ALTER TABLE pubkeys ADD usedpersonally text DEFAULT 'no' ''' item = '''ALTER TABLE pubkeys ADD usedpersonally text DEFAULT 'no' '''
parameters = '' parameters = ''
self.cur.execute(item, parameters) self.cur.execute(item, parameters)
self.conn.commit() self.conn.commit()
shared.config.set('bitmessagesettings', 'settingsversion', '3') BMConfigParser().set('bitmessagesettings', 'settingsversion', '3')
# People running earlier versions of PyBitmessage do not have the # People running earlier versions of PyBitmessage do not have the
# encodingtype field in their inbox and sent tables or the read field # encodingtype field in their inbox and sent tables or the read field
# in the inbox table. Let's add them. # in the inbox table. Let's add them.
if shared.config.getint('bitmessagesettings', 'settingsversion') == 3: if BMConfigParser().getint('bitmessagesettings', 'settingsversion') == 3:
item = '''ALTER TABLE inbox ADD encodingtype int DEFAULT '2' ''' item = '''ALTER TABLE inbox ADD encodingtype int DEFAULT '2' '''
parameters = '' parameters = ''
self.cur.execute(item, parameters) self.cur.execute(item, parameters)
@ -107,21 +111,21 @@ class sqlThread(threading.Thread):
self.cur.execute(item, parameters) self.cur.execute(item, parameters)
self.conn.commit() self.conn.commit()
shared.config.set('bitmessagesettings', 'settingsversion', '4') BMConfigParser().set('bitmessagesettings', 'settingsversion', '4')
if shared.config.getint('bitmessagesettings', 'settingsversion') == 4: if BMConfigParser().getint('bitmessagesettings', 'settingsversion') == 4:
shared.config.set('bitmessagesettings', 'defaultnoncetrialsperbyte', str( BMConfigParser().set('bitmessagesettings', 'defaultnoncetrialsperbyte', str(
shared.networkDefaultProofOfWorkNonceTrialsPerByte)) protocol.networkDefaultProofOfWorkNonceTrialsPerByte))
shared.config.set('bitmessagesettings', 'defaultpayloadlengthextrabytes', str( BMConfigParser().set('bitmessagesettings', 'defaultpayloadlengthextrabytes', str(
shared.networkDefaultPayloadLengthExtraBytes)) protocol.networkDefaultPayloadLengthExtraBytes))
shared.config.set('bitmessagesettings', 'settingsversion', '5') BMConfigParser().set('bitmessagesettings', 'settingsversion', '5')
if shared.config.getint('bitmessagesettings', 'settingsversion') == 5: if BMConfigParser().getint('bitmessagesettings', 'settingsversion') == 5:
shared.config.set( BMConfigParser().set(
'bitmessagesettings', 'maxacceptablenoncetrialsperbyte', '0') 'bitmessagesettings', 'maxacceptablenoncetrialsperbyte', '0')
shared.config.set( BMConfigParser().set(
'bitmessagesettings', 'maxacceptablepayloadlengthextrabytes', '0') 'bitmessagesettings', 'maxacceptablepayloadlengthextrabytes', '0')
shared.config.set('bitmessagesettings', 'settingsversion', '6') BMConfigParser().set('bitmessagesettings', 'settingsversion', '6')
# From now on, let us keep a 'version' embedded in the messages.dat # From now on, let us keep a 'version' embedded in the messages.dat
# file so that when we make changes to the database, the database # file so that when we make changes to the database, the database
@ -174,8 +178,8 @@ class sqlThread(threading.Thread):
'''update sent set status='broadcastqueued' where status='broadcastpending' ''') '''update sent set status='broadcastqueued' where status='broadcastpending' ''')
self.conn.commit() self.conn.commit()
if not shared.config.has_option('bitmessagesettings', 'sockslisten'): if not BMConfigParser().has_option('bitmessagesettings', 'sockslisten'):
shared.config.set('bitmessagesettings', 'sockslisten', 'false') BMConfigParser().set('bitmessagesettings', 'sockslisten', 'false')
ensureNamecoinOptions() ensureNamecoinOptions()
@ -226,18 +230,18 @@ class sqlThread(threading.Thread):
parameters = (4,) parameters = (4,)
self.cur.execute(item, parameters) self.cur.execute(item, parameters)
if not shared.config.has_option('bitmessagesettings', 'userlocale'): if not BMConfigParser().has_option('bitmessagesettings', 'userlocale'):
shared.config.set('bitmessagesettings', 'userlocale', 'system') BMConfigParser().set('bitmessagesettings', 'userlocale', 'system')
if not shared.config.has_option('bitmessagesettings', 'sendoutgoingconnections'): if not BMConfigParser().has_option('bitmessagesettings', 'sendoutgoingconnections'):
shared.config.set('bitmessagesettings', 'sendoutgoingconnections', 'True') BMConfigParser().set('bitmessagesettings', 'sendoutgoingconnections', 'True')
# Raise the default required difficulty from 1 to 2 # Raise the default required difficulty from 1 to 2
# With the change to protocol v3, this is obsolete. # With the change to protocol v3, this is obsolete.
if shared.config.getint('bitmessagesettings', 'settingsversion') == 6: if BMConfigParser().getint('bitmessagesettings', 'settingsversion') == 6:
"""if int(shared.config.get('bitmessagesettings','defaultnoncetrialsperbyte')) == shared.networkDefaultProofOfWorkNonceTrialsPerByte: """if int(shared.config.get('bitmessagesettings','defaultnoncetrialsperbyte')) == protocol.networkDefaultProofOfWorkNonceTrialsPerByte:
shared.config.set('bitmessagesettings','defaultnoncetrialsperbyte', str(shared.networkDefaultProofOfWorkNonceTrialsPerByte * 2)) shared.config.set('bitmessagesettings','defaultnoncetrialsperbyte', str(protocol.networkDefaultProofOfWorkNonceTrialsPerByte * 2))
""" """
shared.config.set('bitmessagesettings', 'settingsversion', '7') BMConfigParser().set('bitmessagesettings', 'settingsversion', '7')
# Add a new column to the pubkeys table to store the address version. # Add a new column to the pubkeys table to store the address version.
# We're going to trash all of our pubkeys and let them be redownloaded. # We're going to trash all of our pubkeys and let them be redownloaded.
@ -255,18 +259,18 @@ class sqlThread(threading.Thread):
parameters = (5,) parameters = (5,)
self.cur.execute(item, parameters) self.cur.execute(item, parameters)
if not shared.config.has_option('bitmessagesettings', 'useidenticons'): if not BMConfigParser().has_option('bitmessagesettings', 'useidenticons'):
shared.config.set('bitmessagesettings', 'useidenticons', 'True') BMConfigParser().set('bitmessagesettings', 'useidenticons', 'True')
if not shared.config.has_option('bitmessagesettings', 'identiconsuffix'): # acts as a salt if not BMConfigParser().has_option('bitmessagesettings', 'identiconsuffix'): # acts as a salt
shared.config.set('bitmessagesettings', 'identiconsuffix', ''.join(random.choice("123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz") for x in range(12))) # a twelve character pseudo-password to salt the identicons BMConfigParser().set('bitmessagesettings', 'identiconsuffix', ''.join(random.choice("123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz") for x in range(12))) # a twelve character pseudo-password to salt the identicons
#Add settings to support no longer resending messages after a certain period of time even if we never get an ack #Add settings to support no longer resending messages after a certain period of time even if we never get an ack
if shared.config.getint('bitmessagesettings', 'settingsversion') == 7: if BMConfigParser().getint('bitmessagesettings', 'settingsversion') == 7:
shared.config.set( BMConfigParser().set(
'bitmessagesettings', 'stopresendingafterxdays', '') 'bitmessagesettings', 'stopresendingafterxdays', '')
shared.config.set( BMConfigParser().set(
'bitmessagesettings', 'stopresendingafterxmonths', '') 'bitmessagesettings', 'stopresendingafterxmonths', '')
shared.config.set('bitmessagesettings', 'settingsversion', '8') BMConfigParser().set('bitmessagesettings', 'settingsversion', '8')
# Add a new table: objectprocessorqueue with which to hold objects # Add a new table: objectprocessorqueue with which to hold objects
# that have yet to be processed if the user shuts down Bitmessage. # that have yet to be processed if the user shuts down Bitmessage.
@ -300,39 +304,39 @@ class sqlThread(threading.Thread):
logger.debug('Finished dropping and recreating the inventory table.') logger.debug('Finished dropping and recreating the inventory table.')
# With the change to protocol version 3, reset the user-settable difficulties to 1 # With the change to protocol version 3, reset the user-settable difficulties to 1
if shared.config.getint('bitmessagesettings', 'settingsversion') == 8: if BMConfigParser().getint('bitmessagesettings', 'settingsversion') == 8:
shared.config.set('bitmessagesettings','defaultnoncetrialsperbyte', str(shared.networkDefaultProofOfWorkNonceTrialsPerByte)) BMConfigParser().set('bitmessagesettings','defaultnoncetrialsperbyte', str(protocol.networkDefaultProofOfWorkNonceTrialsPerByte))
shared.config.set('bitmessagesettings','defaultpayloadlengthextrabytes', str(shared.networkDefaultPayloadLengthExtraBytes)) BMConfigParser().set('bitmessagesettings','defaultpayloadlengthextrabytes', str(protocol.networkDefaultPayloadLengthExtraBytes))
previousTotalDifficulty = int(shared.config.getint('bitmessagesettings', 'maxacceptablenoncetrialsperbyte')) / 320 previousTotalDifficulty = int(BMConfigParser().getint('bitmessagesettings', 'maxacceptablenoncetrialsperbyte')) / 320
previousSmallMessageDifficulty = int(shared.config.getint('bitmessagesettings', 'maxacceptablepayloadlengthextrabytes')) / 14000 previousSmallMessageDifficulty = int(BMConfigParser().getint('bitmessagesettings', 'maxacceptablepayloadlengthextrabytes')) / 14000
shared.config.set('bitmessagesettings','maxacceptablenoncetrialsperbyte', str(previousTotalDifficulty * 1000)) BMConfigParser().set('bitmessagesettings','maxacceptablenoncetrialsperbyte', str(previousTotalDifficulty * 1000))
shared.config.set('bitmessagesettings','maxacceptablepayloadlengthextrabytes', str(previousSmallMessageDifficulty * 1000)) BMConfigParser().set('bitmessagesettings','maxacceptablepayloadlengthextrabytes', str(previousSmallMessageDifficulty * 1000))
shared.config.set('bitmessagesettings', 'settingsversion', '9') BMConfigParser().set('bitmessagesettings', 'settingsversion', '9')
# Adjust the required POW values for each of this user's addresses to conform to protocol v3 norms. # Adjust the required POW values for each of this user's addresses to conform to protocol v3 norms.
if shared.config.getint('bitmessagesettings', 'settingsversion') == 9: if BMConfigParser().getint('bitmessagesettings', 'settingsversion') == 9:
for addressInKeysFile in shared.config.sections(): for addressInKeysFile in BMConfigParser().sections():
try: try:
previousTotalDifficulty = float(shared.config.getint(addressInKeysFile, 'noncetrialsperbyte')) / 320 previousTotalDifficulty = float(BMConfigParser().getint(addressInKeysFile, 'noncetrialsperbyte')) / 320
previousSmallMessageDifficulty = float(shared.config.getint(addressInKeysFile, 'payloadlengthextrabytes')) / 14000 previousSmallMessageDifficulty = float(BMConfigParser().getint(addressInKeysFile, 'payloadlengthextrabytes')) / 14000
if previousTotalDifficulty <= 2: if previousTotalDifficulty <= 2:
previousTotalDifficulty = 1 previousTotalDifficulty = 1
if previousSmallMessageDifficulty < 1: if previousSmallMessageDifficulty < 1:
previousSmallMessageDifficulty = 1 previousSmallMessageDifficulty = 1
shared.config.set(addressInKeysFile,'noncetrialsperbyte', str(int(previousTotalDifficulty * 1000))) BMConfigParser().set(addressInKeysFile,'noncetrialsperbyte', str(int(previousTotalDifficulty * 1000)))
shared.config.set(addressInKeysFile,'payloadlengthextrabytes', str(int(previousSmallMessageDifficulty * 1000))) BMConfigParser().set(addressInKeysFile,'payloadlengthextrabytes', str(int(previousSmallMessageDifficulty * 1000)))
except: except:
continue continue
shared.config.set('bitmessagesettings', 'maxdownloadrate', '0') BMConfigParser().set('bitmessagesettings', 'maxdownloadrate', '0')
shared.config.set('bitmessagesettings', 'maxuploadrate', '0') BMConfigParser().set('bitmessagesettings', 'maxuploadrate', '0')
shared.config.set('bitmessagesettings', 'settingsversion', '10') BMConfigParser().set('bitmessagesettings', 'settingsversion', '10')
shared.writeKeysFile() shared.writeKeysFile()
# sanity check # sanity check
if shared.config.getint('bitmessagesettings', 'maxacceptablenoncetrialsperbyte') == 0: if BMConfigParser().getint('bitmessagesettings', 'maxacceptablenoncetrialsperbyte') == 0:
shared.config.set('bitmessagesettings','maxacceptablenoncetrialsperbyte', str(shared.ridiculousDifficulty * shared.networkDefaultProofOfWorkNonceTrialsPerByte)) BMConfigParser().set('bitmessagesettings','maxacceptablenoncetrialsperbyte', str(shared.ridiculousDifficulty * protocol.networkDefaultProofOfWorkNonceTrialsPerByte))
if shared.config.getint('bitmessagesettings', 'maxacceptablepayloadlengthextrabytes') == 0: if BMConfigParser().getint('bitmessagesettings', 'maxacceptablepayloadlengthextrabytes') == 0:
shared.config.set('bitmessagesettings','maxacceptablepayloadlengthextrabytes', str(shared.ridiculousDifficulty * shared.networkDefaultPayloadLengthExtraBytes)) BMConfigParser().set('bitmessagesettings','maxacceptablepayloadlengthextrabytes', str(shared.ridiculousDifficulty * protocol.networkDefaultPayloadLengthExtraBytes))
# The format of data stored in the pubkeys table has changed. Let's # The format of data stored in the pubkeys table has changed. Let's
# clear it, and the pubkeys from inventory, so that they'll be re-downloaded. # clear it, and the pubkeys from inventory, so that they'll be re-downloaded.
@ -371,8 +375,8 @@ class sqlThread(threading.Thread):
self.cur.execute(item, parameters) self.cur.execute(item, parameters)
# TTL is now user-specifiable. Let's add an option to save whatever the user selects. # TTL is now user-specifiable. Let's add an option to save whatever the user selects.
if not shared.config.has_option('bitmessagesettings', 'ttl'): if not BMConfigParser().has_option('bitmessagesettings', 'ttl'):
shared.config.set('bitmessagesettings', 'ttl', '367200') BMConfigParser().set('bitmessagesettings', 'ttl', '367200')
# We'll also need a `sleeptill` field and a `ttl` field. Also we can combine # We'll also need a `sleeptill` field and a `ttl` field. Also we can combine
# the pubkeyretrynumber and msgretrynumber into one. # the pubkeyretrynumber and msgretrynumber into one.
item = '''SELECT value FROM settings WHERE key='version';''' item = '''SELECT value FROM settings WHERE key='version';'''
@ -419,18 +423,18 @@ class sqlThread(threading.Thread):
logger.debug('In messages.dat database, done adding address field to the pubkeys table and removing the hash field.') logger.debug('In messages.dat database, done adding address field to the pubkeys table and removing the hash field.')
self.cur.execute('''update settings set value=10 WHERE key='version';''') self.cur.execute('''update settings set value=10 WHERE key='version';''')
if not shared.config.has_option('bitmessagesettings', 'onionhostname'): if not BMConfigParser().has_option('bitmessagesettings', 'onionhostname'):
shared.config.set('bitmessagesettings', 'onionhostname', '') BMConfigParser().set('bitmessagesettings', 'onionhostname', '')
if not shared.config.has_option('bitmessagesettings', 'onionport'): if not BMConfigParser().has_option('bitmessagesettings', 'onionport'):
bmng-dev commented 2017-01-11 03:58:27 +01:00 (Migrated from github.com)
Review

Add a check here to ensure the option is a number if it exists

Add a check here to ensure the option is a number if it exists
shared.config.set('bitmessagesettings', 'onionport', '8444') BMConfigParser().set('bitmessagesettings', 'onionport', '8444')
if not shared.config.has_option('bitmessagesettings', 'onionbindip'): if not BMConfigParser().has_option('bitmessagesettings', 'onionbindip'):
shared.config.set('bitmessagesettings', 'onionbindip', '127.0.0.1') BMConfigParser().set('bitmessagesettings', 'onionbindip', '127.0.0.1')
if not shared.config.has_option('bitmessagesettings', 'smtpdeliver'): if not BMConfigParser().has_option('bitmessagesettings', 'smtpdeliver'):
shared.config.set('bitmessagesettings', 'smtpdeliver', '') BMConfigParser().set('bitmessagesettings', 'smtpdeliver', '')
if not shared.config.has_option('bitmessagesettings', 'hidetrayconnectionnotifications'): if not BMConfigParser().has_option('bitmessagesettings', 'hidetrayconnectionnotifications'):
shared.config.set('bitmessagesettings', 'hidetrayconnectionnotifications', 'false') BMConfigParser().set('bitmessagesettings', 'hidetrayconnectionnotifications', 'false')
if not shared.config.has_option('bitmessagesettings', 'maxoutboundconnections'): if not BMConfigParser().has_option('bitmessagesettings', 'maxoutboundconnections'):
shared.config.set('bitmessagesettings', 'maxoutboundconnections', '8') BMConfigParser().set('bitmessagesettings', 'maxoutboundconnections', '8')
shared.writeKeysFile() shared.writeKeysFile()
PeterSurda commented 2017-01-11 21:23:02 +01:00 (Migrated from github.com)
Review

Maybe
if BMConfigParser().getint('bitmessagesettings', 'maxoutboundconnections'))) < 1: throw ValueException

Maybe `if BMConfigParser().getint('bitmessagesettings', 'maxoutboundconnections'))) < 1: throw ValueException `
# Are you hoping to add a new option to the keys.dat file of existing # Are you hoping to add a new option to the keys.dat file of existing
PeterSurda commented 2017-01-11 21:24:15 +01:00 (Migrated from github.com)
Review

And this should be
except ValueException:
because you're supposed to always name the exception. I haven't always done it but in new code we should try to do that.

And this should be `except ValueException:` because you're supposed to always name the exception. I haven't always done it but in new code we should try to do that.
@ -508,8 +512,8 @@ class sqlThread(threading.Thread):
os._exit(0) os._exit(0)
self.conn.close() self.conn.close()
shutil.move( shutil.move(
shared.lookupAppdataFolder() + 'messages.dat', shared.lookupExeFolder() + 'messages.dat') paths.lookupAppdataFolder() + 'messages.dat', paths.lookupExeFolder() + 'messages.dat')
self.conn = sqlite3.connect(shared.lookupExeFolder() + 'messages.dat') self.conn = sqlite3.connect(paths.lookupExeFolder() + 'messages.dat')
self.conn.text_factory = str self.conn.text_factory = str
self.cur = self.conn.cursor() self.cur = self.conn.cursor()
elif item == 'movemessagstoappdata': elif item == 'movemessagstoappdata':
@ -524,8 +528,8 @@ class sqlThread(threading.Thread):
os._exit(0) os._exit(0)
self.conn.close() self.conn.close()
shutil.move( shutil.move(
shared.lookupExeFolder() + 'messages.dat', shared.lookupAppdataFolder() + 'messages.dat') paths.lookupExeFolder() + 'messages.dat', paths.lookupAppdataFolder() + 'messages.dat')
self.conn = sqlite3.connect(shared.lookupAppdataFolder() + 'messages.dat') self.conn = sqlite3.connect(paths.lookupAppdataFolder() + 'messages.dat')
self.conn.text_factory = str self.conn.text_factory = str
self.cur = self.conn.cursor() self.cur = self.conn.cursor()
elif item == 'deleteandvacuume': elif item == 'deleteandvacuume':

View File

@ -1,5 +1,9 @@
import ConfigParser import ConfigParser
from singleton import Singleton
@Singleton
class BMConfigParser(ConfigParser.SafeConfigParser): class BMConfigParser(ConfigParser.SafeConfigParser):
def set(self, section, option, value=None): def set(self, section, option, value=None):
if self._optcre is self.OPTCRE or value: if self._optcre is self.OPTCRE or value:
@ -15,6 +19,20 @@ class BMConfigParser(ConfigParser.SafeConfigParser):
return ConfigParser.ConfigParser.get(self, section, option, True, vars) return ConfigParser.ConfigParser.get(self, section, option, True, vars)
return ConfigParser.ConfigParser.get(self, section, option, True, vars) return ConfigParser.ConfigParser.get(self, section, option, True, vars)
def safeGetBoolean(self, section, field):
if self.has_option(section, field):
try:
return self.getboolean(section, field)
except ValueError:
return False
return False
def safeGet(self, section, option, default = None):
if self.has_option(section, option):
return self.get(section, option)
else:
return default
def items(self, section, raw=False, vars=None): def items(self, section, raw=False, vars=None):
return ConfigParser.ConfigParser.items(self, section, True, vars) return ConfigParser.ConfigParser.items(self, section, True, vars)

View File

@ -19,10 +19,10 @@ Use: `from debug import logger` to import this facility into whatever module you
import logging import logging
import logging.config import logging.config
import os import os
import shared
import sys import sys
import traceback import traceback
import helper_startup import helper_startup
import state
helper_startup.loadConfig() helper_startup.loadConfig()
# Now can be overriden from a config file, which uses standard python logging.config.fileConfig interface # Now can be overriden from a config file, which uses standard python logging.config.fileConfig interface
@ -36,12 +36,12 @@ def log_uncaught_exceptions(ex_cls, ex, tb):
def configureLogging(): def configureLogging():
have_logging = False have_logging = False
try: try:
logging.config.fileConfig(os.path.join (shared.appdata, 'logging.dat')) logging.config.fileConfig(os.path.join (state.appdata, 'logging.dat'))
have_logging = True have_logging = True
print "Loaded logger configuration from %s" % (os.path.join(shared.appdata, 'logging.dat')) print "Loaded logger configuration from %s" % (os.path.join(state.appdata, 'logging.dat'))
except: except:
if os.path.isfile(os.path.join(shared.appdata, 'logging.dat')): if os.path.isfile(os.path.join(state.appdata, 'logging.dat')):
print "Failed to load logger configuration from %s, using default logging config" % (os.path.join(shared.appdata, 'logging.dat')) print "Failed to load logger configuration from %s, using default logging config" % (os.path.join(state.appdata, 'logging.dat'))
print sys.exc_info() print sys.exc_info()
else: else:
# no need to confuse the user if the logger config is missing entirely # no need to confuse the user if the logger config is missing entirely
@ -70,7 +70,7 @@ def configureLogging():
'class': 'logging.handlers.RotatingFileHandler', 'class': 'logging.handlers.RotatingFileHandler',
'formatter': 'default', 'formatter': 'default',
'level': log_level, 'level': log_level,
'filename': shared.appdata + 'debug.log', 'filename': state.appdata + 'debug.log',
'maxBytes': 2097152, # 2 MiB 'maxBytes': 2097152, # 2 MiB
'backupCount': 1, 'backupCount': 1,
'encoding': 'UTF-8', 'encoding': 'UTF-8',

View File

@ -4,14 +4,16 @@ import defaultKnownNodes
import pickle import pickle
import time import time
from configparser import BMConfigParser
from debug import logger from debug import logger
import socks import socks
import state
def knownNodes(): def knownNodes():
try: try:
# We shouldn't have to use the shared.knownNodesLock because this had # We shouldn't have to use the shared.knownNodesLock because this had
# better be the only thread accessing knownNodes right now. # better be the only thread accessing knownNodes right now.
pickleFile = open(shared.appdata + 'knownnodes.dat', 'rb') pickleFile = open(state.appdata + 'knownnodes.dat', 'rb')
loadedKnownNodes = pickle.load(pickleFile) loadedKnownNodes = pickle.load(pickleFile)
pickleFile.close() pickleFile.close()
# The old format of storing knownNodes was as a 'host: (port, time)' # The old format of storing knownNodes was as a 'host: (port, time)'
@ -27,11 +29,11 @@ def knownNodes():
peer, lastseen = node_tuple peer, lastseen = node_tuple
shared.knownNodes[stream][peer] = lastseen shared.knownNodes[stream][peer] = lastseen
except: except:
shared.knownNodes = defaultKnownNodes.createDefaultKnownNodes(shared.appdata) shared.knownNodes = defaultKnownNodes.createDefaultKnownNodes(state.appdata)
# your own onion address, if setup # your own onion address, if setup
if shared.config.has_option('bitmessagesettings', 'onionhostname') and ".onion" in shared.config.get('bitmessagesettings', 'onionhostname'): if BMConfigParser().has_option('bitmessagesettings', 'onionhostname') and ".onion" in BMConfigParser().get('bitmessagesettings', 'onionhostname'):
shared.knownNodes[1][shared.Peer(shared.config.get('bitmessagesettings', 'onionhostname'), shared.config.getint('bitmessagesettings', 'onionport'))] = int(time.time()) shared.knownNodes[1][shared.Peer(BMConfigParser().get('bitmessagesettings', 'onionhostname'), BMConfigParser().getint('bitmessagesettings', 'onionport'))] = int(time.time())
if shared.config.getint('bitmessagesettings', 'settingsversion') > 10: if BMConfigParser().getint('bitmessagesettings', 'settingsversion') > 10:
logger.error('Bitmessage cannot read future versions of the keys file (keys.dat). Run the newer version of Bitmessage.') logger.error('Bitmessage cannot read future versions of the keys file (keys.dat). Run the newer version of Bitmessage.')
raise SystemExit raise SystemExit
@ -41,7 +43,7 @@ def dns():
# defaultKnownNodes.py. Hopefully either they are up to date or the user # defaultKnownNodes.py. Hopefully either they are up to date or the user
# has run Bitmessage recently without SOCKS turned on and received good # has run Bitmessage recently without SOCKS turned on and received good
# bootstrap nodes using that method. # bootstrap nodes using that method.
if shared.config.get('bitmessagesettings', 'socksproxytype') == 'none': if BMConfigParser().get('bitmessagesettings', 'socksproxytype') == 'none':
try: try:
for item in socket.getaddrinfo('bootstrap8080.bitmessage.org', 80): for item in socket.getaddrinfo('bootstrap8080.bitmessage.org', 80):
logger.info('Adding ' + item[4][0] + ' to knownNodes based on DNS bootstrap method') logger.info('Adding ' + item[4][0] + ' to knownNodes based on DNS bootstrap method')
@ -54,7 +56,7 @@ def dns():
shared.knownNodes[1][shared.Peer(item[4][0], 8444)] = int(time.time()) shared.knownNodes[1][shared.Peer(item[4][0], 8444)] = int(time.time())
except: except:
logger.error('bootstrap8444.bitmessage.org DNS bootstrapping failed.') logger.error('bootstrap8444.bitmessage.org DNS bootstrapping failed.')
elif shared.config.get('bitmessagesettings', 'socksproxytype') == 'SOCKS5': elif BMConfigParser().get('bitmessagesettings', 'socksproxytype') == 'SOCKS5':
shared.knownNodes[1][shared.Peer('quzwelsuziwqgpt2.onion', 8444)] = int(time.time()) shared.knownNodes[1][shared.Peer('quzwelsuziwqgpt2.onion', 8444)] = int(time.time())
logger.debug("Adding quzwelsuziwqgpt2.onion:8444 to knownNodes.") logger.debug("Adding quzwelsuziwqgpt2.onion:8444 to knownNodes.")
for port in [8080, 8444]: for port in [8080, 8444]:
@ -64,15 +66,15 @@ def dns():
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.settimeout(20) sock.settimeout(20)
proxytype = socks.PROXY_TYPE_SOCKS5 proxytype = socks.PROXY_TYPE_SOCKS5
sockshostname = shared.config.get( sockshostname = BMConfigParser().get(
'bitmessagesettings', 'sockshostname') 'bitmessagesettings', 'sockshostname')
socksport = shared.config.getint( socksport = BMConfigParser().getint(
'bitmessagesettings', 'socksport') 'bitmessagesettings', 'socksport')
rdns = True # Do domain name lookups through the proxy; though this setting doesn't really matter since we won't be doing any domain name lookups anyway. rdns = True # Do domain name lookups through the proxy; though this setting doesn't really matter since we won't be doing any domain name lookups anyway.
if shared.config.getboolean('bitmessagesettings', 'socksauthentication'): if BMConfigParser().getboolean('bitmessagesettings', 'socksauthentication'):
socksusername = shared.config.get( socksusername = BMConfigParser().get(
'bitmessagesettings', 'socksusername') 'bitmessagesettings', 'socksusername')
sockspassword = shared.config.get( sockspassword = BMConfigParser().get(
'bitmessagesettings', 'sockspassword') 'bitmessagesettings', 'sockspassword')
sock.setproxy( sock.setproxy(
proxytype, sockshostname, socksport, rdns, socksusername, sockspassword) proxytype, sockshostname, socksport, rdns, socksusername, sockspassword)

View File

@ -5,6 +5,7 @@ from binascii import hexlify, unhexlify
from multiprocessing import current_process from multiprocessing import current_process
from threading import current_thread, enumerate from threading import current_thread, enumerate
from configparser import BMConfigParser
from debug import logger from debug import logger
import shared import shared
@ -51,7 +52,7 @@ def signal_handler(signal, frame):
if current_thread().name != "MainThread": if current_thread().name != "MainThread":
return return
logger.error("Got signal %i", signal) logger.error("Got signal %i", signal)
if shared.safeConfigGetBoolean('bitmessagesettings', 'daemon'): if BMConfigParser().safeGetBoolean('bitmessagesettings', 'daemon'):
shared.doCleanShutdown() shared.doCleanShutdown()
else: else:
print 'Unfortunately you cannot use Ctrl+C when running the UI because the UI captures the signal.' print 'Unfortunately you cannot use Ctrl+C when running the UI because the UI captures the signal.'
@ -66,7 +67,7 @@ def isHostInPrivateIPRange(host):
if (ord(hostAddr[0]) & 0xfe) == 0xfc: if (ord(hostAddr[0]) & 0xfe) == 0xfc:
return False return False
pass pass
else: elif ".onion" not in host:
if host[:3] == '10.': if host[:3] == '10.':
return True return True
if host[:4] == '172.': if host[:4] == '172.':
@ -75,6 +76,9 @@ def isHostInPrivateIPRange(host):
return True return True
if host[:8] == '192.168.': if host[:8] == '192.168.':
return True return True
# Multicast
if host[:3] >= 224 and host[:3] <= 239 and host[4] == '.':
return True
return False return False
def addDataPadding(data, desiredMsgLength = 12, paddingChar = '\x00'): def addDataPadding(data, desiredMsgLength = 12, paddingChar = '\x00'):

View File

@ -1,5 +1,6 @@
import shared
import ConfigParser import ConfigParser
import shared
from configparser import BMConfigParser
import sys import sys
import os import os
import locale import locale
@ -9,12 +10,15 @@ import platform
from distutils.version import StrictVersion from distutils.version import StrictVersion
from namecoin import ensureNamecoinOptions from namecoin import ensureNamecoinOptions
import paths
import protocol
import state
storeConfigFilesInSameDirectoryAsProgramByDefault = False # The user may de-select Portable Mode in the settings if they want the config files to stay in the application data folder. storeConfigFilesInSameDirectoryAsProgramByDefault = False # The user may de-select Portable Mode in the settings if they want the config files to stay in the application data folder.
def _loadTrustedPeer(): def _loadTrustedPeer():
try: try:
trustedPeer = shared.config.get('bitmessagesettings', 'trustedpeer') trustedPeer = BMConfigParser().get('bitmessagesettings', 'trustedpeer')
except ConfigParser.Error: except ConfigParser.Error:
# This probably means the trusted peer wasn't specified so we # This probably means the trusted peer wasn't specified so we
# can just leave it as None # can just leave it as None
@ -24,31 +28,31 @@ def _loadTrustedPeer():
shared.trustedPeer = shared.Peer(host, int(port)) shared.trustedPeer = shared.Peer(host, int(port))
def loadConfig(): def loadConfig():
if shared.appdata: if state.appdata:
shared.config.read(shared.appdata + 'keys.dat') BMConfigParser().read(state.appdata + 'keys.dat')
#shared.appdata must have been specified as a startup option. #state.appdata must have been specified as a startup option.
try: try:
shared.config.get('bitmessagesettings', 'settingsversion') BMConfigParser().get('bitmessagesettings', 'settingsversion')
print 'Loading config files from directory specified on startup: ' + shared.appdata print 'Loading config files from directory specified on startup: ' + state.appdata
needToCreateKeysFile = False needToCreateKeysFile = False
except: except:
needToCreateKeysFile = True needToCreateKeysFile = True
else: else:
shared.config.read(shared.lookupExeFolder() + 'keys.dat') BMConfigParser().read(paths.lookupExeFolder() + 'keys.dat')
try: try:
shared.config.get('bitmessagesettings', 'settingsversion') BMConfigParser().get('bitmessagesettings', 'settingsversion')
print 'Loading config files from same directory as program.' print 'Loading config files from same directory as program.'
needToCreateKeysFile = False needToCreateKeysFile = False
shared.appdata = shared.lookupExeFolder() state.appdata = paths.lookupExeFolder()
except: except:
# Could not load the keys.dat file in the program directory. Perhaps it # Could not load the keys.dat file in the program directory. Perhaps it
# is in the appdata directory. # is in the appdata directory.
shared.appdata = shared.lookupAppdataFolder() state.appdata = paths.lookupAppdataFolder()
shared.config.read(shared.appdata + 'keys.dat') BMConfigParser().read(state.appdata + 'keys.dat')
try: try:
shared.config.get('bitmessagesettings', 'settingsversion') BMConfigParser().get('bitmessagesettings', 'settingsversion')
print 'Loading existing config files from', shared.appdata print 'Loading existing config files from', state.appdata
needToCreateKeysFile = False needToCreateKeysFile = False
except: except:
needToCreateKeysFile = True needToCreateKeysFile = True
@ -56,63 +60,63 @@ def loadConfig():
if needToCreateKeysFile: if needToCreateKeysFile:
# This appears to be the first time running the program; there is # This appears to be the first time running the program; there is
# no config file (or it cannot be accessed). Create config file. # no config file (or it cannot be accessed). Create config file.
shared.config.add_section('bitmessagesettings') BMConfigParser().add_section('bitmessagesettings')
shared.config.set('bitmessagesettings', 'settingsversion', '10') BMConfigParser().set('bitmessagesettings', 'settingsversion', '10')
shared.config.set('bitmessagesettings', 'port', '8444') BMConfigParser().set('bitmessagesettings', 'port', '8444')
shared.config.set( BMConfigParser().set(
'bitmessagesettings', 'timeformat', '%%c') 'bitmessagesettings', 'timeformat', '%%c')
shared.config.set('bitmessagesettings', 'blackwhitelist', 'black') BMConfigParser().set('bitmessagesettings', 'blackwhitelist', 'black')
shared.config.set('bitmessagesettings', 'startonlogon', 'false') BMConfigParser().set('bitmessagesettings', 'startonlogon', 'false')
if 'linux' in sys.platform: if 'linux' in sys.platform:
shared.config.set( BMConfigParser().set(
'bitmessagesettings', 'minimizetotray', 'false') 'bitmessagesettings', 'minimizetotray', 'false')
# This isn't implimented yet and when True on # This isn't implimented yet and when True on
# Ubuntu causes Bitmessage to disappear while # Ubuntu causes Bitmessage to disappear while
# running when minimized. # running when minimized.
else: else:
shared.config.set( BMConfigParser().set(
'bitmessagesettings', 'minimizetotray', 'true') 'bitmessagesettings', 'minimizetotray', 'true')
shared.config.set( BMConfigParser().set(
'bitmessagesettings', 'showtraynotifications', 'true') 'bitmessagesettings', 'showtraynotifications', 'true')
shared.config.set('bitmessagesettings', 'startintray', 'false') BMConfigParser().set('bitmessagesettings', 'startintray', 'false')
shared.config.set('bitmessagesettings', 'socksproxytype', 'none') BMConfigParser().set('bitmessagesettings', 'socksproxytype', 'none')
shared.config.set( BMConfigParser().set(
'bitmessagesettings', 'sockshostname', 'localhost') 'bitmessagesettings', 'sockshostname', 'localhost')
shared.config.set('bitmessagesettings', 'socksport', '9050') BMConfigParser().set('bitmessagesettings', 'socksport', '9050')
shared.config.set( BMConfigParser().set(
'bitmessagesettings', 'socksauthentication', 'false') 'bitmessagesettings', 'socksauthentication', 'false')
shared.config.set( BMConfigParser().set(
'bitmessagesettings', 'sockslisten', 'false') 'bitmessagesettings', 'sockslisten', 'false')
shared.config.set('bitmessagesettings', 'socksusername', '') BMConfigParser().set('bitmessagesettings', 'socksusername', '')
shared.config.set('bitmessagesettings', 'sockspassword', '') BMConfigParser().set('bitmessagesettings', 'sockspassword', '')
shared.config.set('bitmessagesettings', 'keysencrypted', 'false') BMConfigParser().set('bitmessagesettings', 'keysencrypted', 'false')
shared.config.set( BMConfigParser().set(
'bitmessagesettings', 'messagesencrypted', 'false') 'bitmessagesettings', 'messagesencrypted', 'false')
shared.config.set('bitmessagesettings', 'defaultnoncetrialsperbyte', str( BMConfigParser().set('bitmessagesettings', 'defaultnoncetrialsperbyte', str(
shared.networkDefaultProofOfWorkNonceTrialsPerByte)) protocol.networkDefaultProofOfWorkNonceTrialsPerByte))
shared.config.set('bitmessagesettings', 'defaultpayloadlengthextrabytes', str( BMConfigParser().set('bitmessagesettings', 'defaultpayloadlengthextrabytes', str(
shared.networkDefaultPayloadLengthExtraBytes)) protocol.networkDefaultPayloadLengthExtraBytes))
shared.config.set('bitmessagesettings', 'minimizeonclose', 'false') BMConfigParser().set('bitmessagesettings', 'minimizeonclose', 'false')
shared.config.set( BMConfigParser().set(
'bitmessagesettings', 'maxacceptablenoncetrialsperbyte', '0') 'bitmessagesettings', 'maxacceptablenoncetrialsperbyte', '0')
shared.config.set( BMConfigParser().set(
'bitmessagesettings', 'maxacceptablepayloadlengthextrabytes', '0') 'bitmessagesettings', 'maxacceptablepayloadlengthextrabytes', '0')
shared.config.set('bitmessagesettings', 'dontconnect', 'true') BMConfigParser().set('bitmessagesettings', 'dontconnect', 'true')
shared.config.set('bitmessagesettings', 'userlocale', 'system') BMConfigParser().set('bitmessagesettings', 'userlocale', 'system')
shared.config.set('bitmessagesettings', 'useidenticons', 'True') BMConfigParser().set('bitmessagesettings', 'useidenticons', 'True')
shared.config.set('bitmessagesettings', 'identiconsuffix', ''.join(random.choice("123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz") for x in range(12))) # a twelve character pseudo-password to salt the identicons BMConfigParser().set('bitmessagesettings', 'identiconsuffix', ''.join(random.choice("123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz") for x in range(12))) # a twelve character pseudo-password to salt the identicons
shared.config.set('bitmessagesettings', 'replybelow', 'False') BMConfigParser().set('bitmessagesettings', 'replybelow', 'False')
shared.config.set('bitmessagesettings', 'maxoutboundconnections', '8') BMConfigParser().set('bitmessagesettings', 'maxdownloadrate', '0')
shared.config.set('bitmessagesettings', 'maxdownloadrate', '0') BMConfigParser().set('bitmessagesettings', 'maxuploadrate', '0')
shared.config.set('bitmessagesettings', 'maxuploadrate', '0') BMConfigParser().set('bitmessagesettings', 'maxoutboundconnections', '8')
shared.config.set('bitmessagesettings', 'ttl', '367200') BMConfigParser().set('bitmessagesettings', 'ttl', '367200')
#start:UI setting to stop trying to send messages after X days/months #start:UI setting to stop trying to send messages after X days/months
shared.config.set( BMConfigParser().set(
'bitmessagesettings', 'stopresendingafterxdays', '') 'bitmessagesettings', 'stopresendingafterxdays', '')
shared.config.set( BMConfigParser().set(
'bitmessagesettings', 'stopresendingafterxmonths', '') 'bitmessagesettings', 'stopresendingafterxmonths', '')
#shared.config.set( #BMConfigParser().set(
# 'bitmessagesettings', 'timeperiod', '-1') # 'bitmessagesettings', 'timeperiod', '-1')
#end #end
@ -127,12 +131,12 @@ def loadConfig():
if storeConfigFilesInSameDirectoryAsProgramByDefault: if storeConfigFilesInSameDirectoryAsProgramByDefault:
# Just use the same directory as the program and forget about # Just use the same directory as the program and forget about
# the appdata folder # the appdata folder
shared.appdata = '' state.appdata = ''
print 'Creating new config files in same directory as program.' print 'Creating new config files in same directory as program.'
else: else:
print 'Creating new config files in', shared.appdata print 'Creating new config files in', state.appdata
if not os.path.exists(shared.appdata): if not os.path.exists(state.appdata):
os.makedirs(shared.appdata) os.makedirs(state.appdata)
if not sys.platform.startswith('win'): if not sys.platform.startswith('win'):
os.umask(0o077) os.umask(0o077)
shared.writeKeysFile() shared.writeKeysFile()

84
src/inventory.py Normal file
View File

@ -0,0 +1,84 @@
import collections
from threading import RLock
import time
from helper_sql import *
from singleton import Singleton
inventoryLock = RLock() # Guarantees that two receiveDataThreads don't receive and process the same message concurrently (probably sent by a malicious individual)
InventoryItem = collections.namedtuple('InventoryItem', 'type stream payload expires tag')
@Singleton
class Inventory(collections.MutableMapping):
def __init__(self):
super(self.__class__, self).__init__()
self._inventory = {} #of objects (like msg payloads and pubkey payloads) Does not include protocol headers (the first 24 bytes of each packet).
self.numberOfInventoryLookupsPerformed = 0
self._streams = collections.defaultdict(set) # key = streamNumer, value = a set which holds the inventory object hashes that we are aware of. This is used whenever we receive an inv message from a peer to check to see what items are new to us. We don't delete things out of it; instead, the singleCleaner thread clears and refills it every couple hours.
def __contains__(self, hash):
with inventoryLock:
self.numberOfInventoryLookupsPerformed += 1
if hash in self._inventory:
return True
return bool(sqlQuery('SELECT 1 FROM inventory WHERE hash=?', hash))
def __getitem__(self, hash):
with inventoryLock:
if hash in self._inventory:
return self._inventory[hash]
rows = sqlQuery('SELECT objecttype, streamnumber, payload, expirestime, tag FROM inventory WHERE hash=?', hash)
if not rows:
raise KeyError(hash)
return InventoryItem(*rows[0])
def __setitem__(self, hash, value):
with inventoryLock:
value = InventoryItem(*value)
self._inventory[hash] = value
self._streams[value.stream].add(hash)
def __delitem__(self, hash):
raise NotImplementedError
def __iter__(self):
with inventoryLock:
hashes = self._inventory.keys()[:]
hashes += (hash for hash, in sqlQuery('SELECT hash FROM inventory'))
return hashes.__iter__()
def __len__(self):
with inventoryLock:
return len(self._inventory) + sqlQuery('SELECT count(*) FROM inventory')[0][0]
def by_type_and_tag(self, type, tag):
with inventoryLock:
values = [value for value in self._inventory.values() if value.type == type and value.tag == tag]
values += (InventoryItem(*value) for value in sqlQuery('SELECT objecttype, streamnumber, payload, expirestime, tag FROM inventory WHERE objecttype=? AND tag=?', type, tag))
return values
def hashes_by_stream(self, stream):
with inventoryLock:
return self._streams[stream]
def unexpired_hashes_by_stream(self, stream):
with inventoryLock:
t = int(time.time())
hashes = [hash for hash, value in self._inventory.items() if value.stream == stream and value.expires > t]
hashes += (payload for payload, in sqlQuery('SELECT hash FROM inventory WHERE streamnumber=? AND expirestime>?', stream, t))
return hashes
def flush(self):
with inventoryLock: # If you use both the inventoryLock and the sqlLock, always use the inventoryLock OUTSIDE of the sqlLock.
with SqlBulkExecute() as sql:
for hash, value in self._inventory.items():
sql.execute('INSERT INTO inventory VALUES (?, ?, ?, ?, ?, ?)', hash, *value)
self._inventory.clear()
def clean(self):
with inventoryLock:
sqlExecute('DELETE FROM inventory WHERE expirestime<?',int(time.time()) - (60 * 60 * 3))
self._streams.clear()
for hash, value in self.items():
self._streams[value.stream].add(hash)

View File

@ -3,7 +3,7 @@ import logging
import os import os
import time import time
import shared from configparser import BMConfigParser
#logger = logging.getLogger(__name__) #logger = logging.getLogger(__name__)
@ -48,8 +48,8 @@ except:
logger.exception('Could not determine language or encoding') logger.exception('Could not determine language or encoding')
if shared.config.has_option('bitmessagesettings', 'timeformat'): if BMConfigParser().has_option('bitmessagesettings', 'timeformat'):
time_format = shared.config.get('bitmessagesettings', 'timeformat') time_format = BMConfigParser().get('bitmessagesettings', 'timeformat')
#Test the format string #Test the format string
try: try:
time.strftime(time_format) time.strftime(time_format)
@ -112,8 +112,8 @@ def formatTimestamp(timestamp = None, as_unicode = True):
def getTranslationLanguage(): def getTranslationLanguage():
userlocale = None userlocale = None
if shared.config.has_option('bitmessagesettings', 'userlocale'): if BMConfigParser().has_option('bitmessagesettings', 'userlocale'):
userlocale = shared.config.get('bitmessagesettings', 'userlocale') userlocale = BMConfigParser().get('bitmessagesettings', 'userlocale')
if userlocale in [None, '', 'system']: if userlocale in [None, '', 'system']:
return language return language

View File

@ -6,10 +6,11 @@ import sqlite3
from time import strftime, localtime from time import strftime, localtime
import sys import sys
import shared import shared
import string import paths
import state
from binascii import hexlify from binascii import hexlify
appdata = shared.lookupAppdataFolder() appdata = paths.lookupAppdataFolder()
conn = sqlite3.connect( appdata + 'messages.dat' ) conn = sqlite3.connect( appdata + 'messages.dat' )
conn.text_factory = str conn.text_factory = str

View File

@ -26,6 +26,7 @@ import socket
import sys import sys
import os import os
from configparser import BMConfigParser
import shared import shared
import tr # translate import tr # translate
@ -63,11 +64,11 @@ class namecoinConnection (object):
# actually changing the values (yet). # actually changing the values (yet).
def __init__ (self, options = None): def __init__ (self, options = None):
if options is None: if options is None:
self.nmctype = shared.config.get (configSection, "namecoinrpctype") self.nmctype = BMConfigParser().get (configSection, "namecoinrpctype")
self.host = shared.config.get (configSection, "namecoinrpchost") self.host = BMConfigParser().get (configSection, "namecoinrpchost")
self.port = int(shared.config.get (configSection, "namecoinrpcport")) self.port = int(BMConfigParser().get (configSection, "namecoinrpcport"))
self.user = shared.config.get (configSection, "namecoinrpcuser") self.user = BMConfigParser().get (configSection, "namecoinrpcuser")
self.password = shared.config.get (configSection, self.password = BMConfigParser().get (configSection,
"namecoinrpcpassword") "namecoinrpcpassword")
else: else:
self.nmctype = options["type"] self.nmctype = options["type"]
@ -261,14 +262,14 @@ def lookupNamecoinFolder ():
# Ensure all namecoin options are set, by setting those to default values # Ensure all namecoin options are set, by setting those to default values
# that aren't there. # that aren't there.
def ensureNamecoinOptions (): def ensureNamecoinOptions ():
if not shared.config.has_option (configSection, "namecoinrpctype"): if not BMConfigParser().has_option (configSection, "namecoinrpctype"):
shared.config.set (configSection, "namecoinrpctype", "namecoind") BMConfigParser().set (configSection, "namecoinrpctype", "namecoind")
if not shared.config.has_option (configSection, "namecoinrpchost"): if not BMConfigParser().has_option (configSection, "namecoinrpchost"):
shared.config.set (configSection, "namecoinrpchost", "localhost") BMConfigParser().set (configSection, "namecoinrpchost", "localhost")
hasUser = shared.config.has_option (configSection, "namecoinrpcuser") hasUser = BMConfigParser().has_option (configSection, "namecoinrpcuser")
hasPass = shared.config.has_option (configSection, "namecoinrpcpassword") hasPass = BMConfigParser().has_option (configSection, "namecoinrpcpassword")
hasPort = shared.config.has_option (configSection, "namecoinrpcport") hasPort = BMConfigParser().has_option (configSection, "namecoinrpcport")
# Try to read user/password from .namecoin configuration file. # Try to read user/password from .namecoin configuration file.
defaultUser = "" defaultUser = ""
@ -302,11 +303,11 @@ def ensureNamecoinOptions ():
# If still nothing found, set empty at least. # If still nothing found, set empty at least.
if (not hasUser): if (not hasUser):
shared.config.set (configSection, "namecoinrpcuser", defaultUser) BMConfigParser().set (configSection, "namecoinrpcuser", defaultUser)
if (not hasPass): if (not hasPass):
shared.config.set (configSection, "namecoinrpcpassword", defaultPass) BMConfigParser().set (configSection, "namecoinrpcpassword", defaultPass)
# Set default port now, possibly to found value. # Set default port now, possibly to found value.
if (not hasPort): if (not hasPort):
shared.config.set (configSection, "namecoinrpcport", BMConfigParser().set (configSection, "namecoinrpcport",
shared.namecoinDefaultRpcPort) shared.namecoinDefaultRpcPort)

View File

@ -0,0 +1,50 @@
class AdvancedDispatcher(asyncore.dispatcher):
_buf_len = 131072
def __init__(self, sock):
asyncore.dispatcher.__init__(self, sock)
self.read_buf = ""
self.write_buf = ""
self.state = "init"
def slice_read_buf(length=0):
self.read_buf = self.read_buf[length:]
def slice_write_buf(length=0):
self.write_buf = self.read_buf[length:]
def read_buf_sufficient(length=0):
if len(self.read_buf) < length:
return False
else:
return True
def process(self):
if len(self.read_buf) == 0:
return
while True:
try:
if getattr(self, "state_" + str(self.state))() is False:
break
except AttributeError:
# missing state
raise
def set_state(self, state, length):
self.slice_read_buf(length)
self.state = state
def writable(self):
return len(self.write_buf) > 0
def readable(self):
return len(self.read_buf) < AdvancedDispatcher._buf_len
def handle_read(self):
self.read_buf += self.recv(AdvancedDispatcher._buf_len)
self.process()
def handle_write(self):
written = self.send(self.write_buf)
self.slice_write_buf(written)
# self.process()

View File

@ -1,9 +1,10 @@
import asyncore import asyncore
from http import HTTPClient from http import HTTPClient
import paths
from tls import TLSHandshake from tls import TLSHandshake
# self.sslSock = ssl.wrap_socket(self.sock, keyfile = os.path.join(shared.codePath(), 'sslkeys', 'key.pem'), certfile = os.path.join(shared.codePath(), 'sslkeys', 'cert.pem'), server_side = not self.initiatedConnection, ssl_version=ssl.PROTOCOL_TLSv1, do_handshake_on_connect=False, ciphers='AECDH-AES256-SHA') # self.sslSock = ssl.wrap_socket(self.sock, keyfile = os.path.join(paths.codePath(), 'sslkeys', 'key.pem'), certfile = os.path.join(paths.codePath(), 'sslkeys', 'cert.pem'), server_side = not self.initiatedConnection, ssl_version=ssl.PROTOCOL_TLSv1, do_handshake_on_connect=False, ciphers='AECDH-AES256-SHA')
class HTTPSClient(HTTPClient, TLSHandshake): class HTTPSClient(HTTPClient, TLSHandshake):

View File

@ -4,13 +4,13 @@ import asyncore
import socket import socket
import struct import struct
from advanceddispatcher import AdvancedDispatcher
class Proxy(asyncore.dispatcher): class Proxy(AdvancedDispatcher):
# these are global, and if you change config during runtime, all active/new # these are global, and if you change config during runtime, all active/new
# instances should change too # instances should change too
_proxy = ["", 1080] _proxy = ["", 1080]
_auth = None _auth = None
_buf_len = 131072
_remote_dns = True _remote_dns = True
@property @property
@ -34,46 +34,17 @@ class Proxy(asyncore.dispatcher):
def __init__(self, address=None): def __init__(self, address=None):
if (not type(address) in (list,tuple)) or (len(address) < 2) or (type(address[0]) != type('')) or (type(address[1]) != int): if (not type(address) in (list,tuple)) or (len(address) < 2) or (type(address[0]) != type('')) or (type(address[1]) != int):
raise raise
asyncore.dispatcher.__init__(self, self.sock) AdvancedDispatcher.__init__(self, self.sock)
self.destination = address self.destination = address
self.read_buf = ""
self.write_buf = ""
self.stage = "init"
self.create_socket(socket.AF_INET, socket.SOCK_STREAM) self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
self.sslSocket.setblocking(0) self.sslSocket.setblocking(0)
self.connect(self.proxy) self.connect(self.proxy)
def process(self):
try:
getattr(self, "state_" + str(self.stage))()
except AttributeError:
# missing stage
raise
def set_state(self, state):
self.state = state
self.read_buf = ""
def writable(self):
return len(self.write_buf) > 0
def readable(self):
return len(self.read_buf) < Proxy._buf_len
def handle_read(self):
self.read_buf += self.recv(Proxy._buf_len)
self.process()
def handle_write(self):
written = self.send(self.write_buf)
self.write_buf = self.write_buf[written:]
self.process()
class SOCKS5(Proxy): class SOCKS5(Proxy):
def __init__(self, address=None, sock=None): def __init__(self, address=None, sock=None):
Proxy.__init__(self, address) Proxy.__init__(self, address)
self.state = 0 self.state = "init"
def handle_connect(self): def handle_connect(self):
self.process() self.process()
@ -83,11 +54,11 @@ class SOCKS5(Proxy):
self.write_buf += struct.pack('BBBB', 0x05, 0x02, 0x00, 0x02) self.write_buf += struct.pack('BBBB', 0x05, 0x02, 0x00, 0x02)
else: else:
self.write_buf += struct.pack('BBB', 0x05, 0x01, 0x00) self.write_buf += struct.pack('BBB', 0x05, 0x01, 0x00)
self.set_state("auth_1") self.set_state("auth_1", 0)
def state_auth_1(self): def state_auth_1(self):
if len(self.read_buf) < 2: if not self.read_buf_sufficient(2):
return return False
ret = struct.unpack('BB', self.read_buf) ret = struct.unpack('BB', self.read_buf)
self.read_buf = self.read_buf[2:] self.read_buf = self.read_buf[2:]
if ret[0] != 5: if ret[0] != 5:
@ -95,13 +66,13 @@ class SOCKS5(Proxy):
raise raise
elif ret[1] == 0: elif ret[1] == 0:
# no auth required # no auth required
self.set_state("auth_done") self.set_state("auth_done", 2)
elif ret[1] == 2: elif ret[1] == 2:
# username/password # username/password
self.write_buf += struct.pack('BB', 1, len(self._auth[0])) + \ self.write_buf += struct.pack('BB', 1, len(self._auth[0])) + \
self._auth[0] + struct.pack('B', len(self._auth[1])) + \ self._auth[0] + struct.pack('B', len(self._auth[1])) + \
self._auth[1] self._auth[1]
self.set_state("auth_1") self.set_state("auth_1", 2)
else: else:
if ret[1] == 0xff: if ret[1] == 0xff:
# auth error # auth error
@ -111,8 +82,8 @@ class SOCKS5(Proxy):
raise raise
def state_auth_needed(self): def state_auth_needed(self):
if len(self.read_buf) < 2: if not self.read_buf_sufficient(2):
return return False
ret = struct.unpack('BB', self.read_buf) ret = struct.unpack('BB', self.read_buf)
if ret[0] != 1: if ret[0] != 1:
# general error # general error
@ -121,37 +92,11 @@ class SOCKS5(Proxy):
# auth error # auth error
raise raise
# all ok # all ok
self.set_state = ("auth_done") self.set_state = ("auth_done", 2)
class SOCKS5Connection(SOCKS5):
def __init__(self, address):
SOCKS5.__init__(self, address)
def state_auth_done(self):
# Now we can request the actual connection
self.write_buf += struct.pack('BBB', 0x05, 0x01, 0x00)
# If the given destination address is an IP address, we'll
# use the IPv4 address request even if remote resolving was specified.
try:
ipaddr = socket.inet_aton(self.destination[0])
self.write_buf += chr(0x01).encode() + ipaddr
except socket.error:
# Well it's not an IP number, so it's probably a DNS name.
if Proxy._remote_dns:
# Resolve remotely
ipaddr = None
self.write_buf += chr(0x03).encode() + chr(len(self.destination[0])).encode() + self.destination[0]
else:
# Resolve locally
ipaddr = socket.inet_aton(socket.gethostbyname(self.destination[0]))
self.write_buf += chr(0x01).encode() + ipaddr
self.write_buf += struct.pack(">H", self.destination[1])
self.set_state = ("pre_connect")
def state_pre_connect(self): def state_pre_connect(self):
if len(self.read_buf) < 4: if not self.read_buf_sufficient(4):
return return False
# Get the response # Get the response
if self.read_buf[0:1] != chr(0x05).encode(): if self.read_buf[0:1] != chr(0x05).encode():
# general error # general error
@ -168,74 +113,78 @@ class SOCKS5Connection(SOCKS5):
raise raise
#raise Socks5Error((9, _socks5errors[9])) #raise Socks5Error((9, _socks5errors[9]))
# Get the bound address/port # Get the bound address/port
elif self_read_buf[3:4] == chr(0x01).encode(): elif self.read_buf[3:4] == chr(0x01).encode():
self.set_state("proxy_addr_long") self.set_state("proxy_addr_1", 4)
elif resp[3:4] == chr(0x03).encode(): elif self.read_buf[3:4] == chr(0x03).encode():
self.set_state("proxy_addr_short") self.set_state("proxy_addr_2_1", 4)
else: else:
self.close() self.close()
raise GeneralProxyError((1,_generalerrors[1])) raise GeneralProxyError((1,_generalerrors[1]))
boundport = struct.unpack(">H", self.__recvall(2))[0]
self.__proxysockname = (boundaddr, boundport)
if ipaddr != None:
self.__proxypeername = (socket.inet_ntoa(ipaddr), destport)
else:
self.__proxypeername = (destaddr, destport)
def state_proxy_addr_long(self): def state_proxy_addr_1(self):
if len(self.read_buf) < 4: if not self.read_buf_sufficient(4):
return return False
self.boundaddr = self.read_buf[0:4] self.boundaddr = self.read_buf[0:4]
self.set_state("proxy_port") self.set_state("proxy_port", 4)
def state_proxy_addr_short(self): def state_proxy_addr_2_1(self):
if len(self.read_buf) < 1: if not self.read_buf_sufficient(1):
return return False
self.boundaddr = self.read_buf[0:1] self.address_length = ord(self.read_buf[0:1])
self.set_state("proxy_port") self.set_state("proxy_addr_2_2", 1)
def state_proxy_addr_2_2(self):
if not self.read_buf_sufficient(self.address_length):
return False
self.boundaddr = read_buf
self.set_state("proxy_port", self.address_length)
def state_proxy_port(self): def state_proxy_port(self):
if len(self.read_buf) < 2: if not self.read_buf_sufficient(2):
return return False
self.boundport = struct.unpack(">H", self.read_buf[0:2])[0] self.boundport = struct.unpack(">H", self.read_buf[0:2])[0]
self.__proxysockname = (self.boundaddr, self.boundport) self.__proxysockname = (self.boundaddr, self.boundport)
if ipaddr != None: if self.ipaddr != None:
self.__proxypeername = (socket.inet_ntoa(ipaddr), destport) self.__proxypeername = (socket.inet_ntoa(self.ipaddr), self.destination[1])
else: else:
self.__proxypeername = (destaddr, destport) self.__proxypeername = (self.destination[1], destport)
class SOCKS5Resolver(SOCKS5): class SOCKS5Connection(SOCKS5):
def __init__(self, destpair): def __init__(self, address):
SOCKS5.__init__(self, destpair) SOCKS5.__init__(self, address)
def state_auth_done(self): def state_auth_done(self):
# Now we can request the actual connection # Now we can request the actual connection
req = struct.pack('BBB', 0x05, 0xF0, 0x00) self.write_buf += struct.pack('BBB', 0x05, 0x01, 0x00)
req += chr(0x03).encode() + chr(len(host)).encode() + host # If the given destination address is an IP address, we'll
req = req + struct.pack(">H", 8444) # use the IPv4 address request even if remote resolving was specified.
self.sendall(req) try:
# Get the response self.ipaddr = socket.inet_aton(self.destination[0])
ip = "" self.write_buf += chr(0x01).encode() + ipaddr
resp = self.__recvall(4) except socket.error:
if resp[0:1] != chr(0x05).encode(): # Well it's not an IP number, so it's probably a DNS name.
self.close() if Proxy._remote_dns:
raise GeneralProxyError((1, _generalerrors[1])) # Resolve remotely
elif resp[1:2] != chr(0x00).encode(): self.ipaddr = None
# Connection failed self.write_buf += chr(0x03).encode() + chr(len(self.destination[0])).encode() + self.destination[0]
self.close()
if ord(resp[1:2])<=8:
raise Socks5Error((ord(resp[1:2]), _socks5errors[ord(resp[1:2])]))
else: else:
raise Socks5Error((9, _socks5errors[9])) # Resolve locally
# Get the bound address/port self.ipaddr = socket.inet_aton(socket.gethostbyname(self.destination[0]))
elif resp[3:4] == chr(0x01).encode(): self.write_buf += chr(0x01).encode() + ipaddr
ip = socket.inet_ntoa(self.__recvall(4)) self.write_buf += struct.pack(">H", self.destination[1])
elif resp[3:4] == chr(0x03).encode(): self.set_state = ("pre_connect", 0)
resp = resp + self.recv(1)
ip = self.__recvall(ord(resp[4:5]))
else: class SOCKS5Resolver(SOCKS5):
self.close() def __init__(self, host):
raise GeneralProxyError((1,_generalerrors[1])) self.host = host
boundport = struct.unpack(">H", self.__recvall(2))[0] self.port = 8444
return ip SOCKS5.__init__(self, [self.host, self.port])
def state_auth_done(self):
# Now we can request the actual connection
self.write_buf += struct.pack('BBB', 0x05, 0xF0, 0x00)
self.write_buf += chr(0x03).encode() + chr(len(self.host)).encode() + self.host
self.write_buf += struct.pack(">H", self.port)
self.state = "pre_connect"

View File

@ -5,7 +5,9 @@ import hashlib
import random import random
import os import os
from shared import codePath, safeConfigGetBoolean, safeConfigGet, shutdown from configparser import BMConfigParser
import paths
from shared import shutdown
from debug import logger from debug import logger
libAvailable = True libAvailable = True
@ -30,7 +32,7 @@ def initCL():
try: try:
for platform in cl.get_platforms(): for platform in cl.get_platforms():
gpus.extend(platform.get_devices(device_type=cl.device_type.GPU)) gpus.extend(platform.get_devices(device_type=cl.device_type.GPU))
if safeConfigGet("bitmessagesettings", "opencl") == platform.vendor: if BMConfigParser().safeGet("bitmessagesettings", "opencl") == platform.vendor:
enabledGpus.extend(platform.get_devices(device_type=cl.device_type.GPU)) enabledGpus.extend(platform.get_devices(device_type=cl.device_type.GPU))
if platform.vendor not in vendors: if platform.vendor not in vendors:
vendors.append(platform.vendor) vendors.append(platform.vendor)
@ -39,7 +41,7 @@ def initCL():
if (len(enabledGpus) > 0): if (len(enabledGpus) > 0):
ctx = cl.Context(devices=enabledGpus) ctx = cl.Context(devices=enabledGpus)
queue = cl.CommandQueue(ctx) queue = cl.CommandQueue(ctx)
f = open(os.path.join(codePath(), "bitmsghash", 'bitmsghash.cl'), 'r') f = open(os.path.join(paths.codePath(), "bitmsghash", 'bitmsghash.cl'), 'r')
fstr = ''.join(f.readlines()) fstr = ''.join(f.readlines())
program = cl.Program(ctx, fstr).build(options="") program = cl.Program(ctx, fstr).build(options="")
logger.info("Loaded OpenCL kernel") logger.info("Loaded OpenCL kernel")
@ -51,16 +53,12 @@ def initCL():
enabledGpus = [] enabledGpus = []
def openclAvailable(): def openclAvailable():
global gpus
return (len(gpus) > 0) return (len(gpus) > 0)
def openclEnabled(): def openclEnabled():
global enabledGpus
return (len(enabledGpus) > 0) return (len(enabledGpus) > 0)
def do_opencl_pow(hash, target): def do_opencl_pow(hash, target):
global ctx, queue, program, enabledGpus, hash_dt
output = numpy.zeros(1, dtype=[('v', numpy.uint64, 1)]) output = numpy.zeros(1, dtype=[('v', numpy.uint64, 1)])
if (len(enabledGpus) == 0): if (len(enabledGpus) == 0):
return output[0][0] return output[0][0]

70
src/paths.py Normal file
View File

@ -0,0 +1,70 @@
from os import environ, path
import sys
# When using py2exe or py2app, the variable frozen is added to the sys
# namespace. This can be used to setup a different code path for
# binary distributions vs source distributions.
frozen = getattr(sys,'frozen', None)
def lookupExeFolder():
if frozen:
if frozen == "macosx_app":
# targetdir/Bitmessage.app/Contents/MacOS/Bitmessage
exeFolder = path.dirname(path.dirname(path.dirname(path.dirname(sys.executable)))) + path.sep
else:
exeFolder = path.dirname(sys.executable) + path.sep
elif __file__:
exeFolder = path.dirname(__file__) + path.sep
else:
exeFolder = ''
return exeFolder
def lookupAppdataFolder():
APPNAME = "PyBitmessage"
if "BITMESSAGE_HOME" in environ:
dataFolder = environ["BITMESSAGE_HOME"]
if dataFolder[-1] not in [path.sep, path.altsep]:
dataFolder += path.sep
elif sys.platform == 'darwin':
if "HOME" in environ:
dataFolder = path.join(environ["HOME"], "Library/Application Support/", APPNAME) + '/'
else:
stringToLog = 'Could not find home folder, please report this message and your OS X version to the BitMessage Github.'
if 'logger' in globals():
logger.critical(stringToLog)
else:
print stringToLog
sys.exit()
elif 'win32' in sys.platform or 'win64' in sys.platform:
dataFolder = path.join(environ['APPDATA'].decode(sys.getfilesystemencoding(), 'ignore'), APPNAME) + path.sep
else:
from shutil import move
try:
dataFolder = path.join(environ["XDG_CONFIG_HOME"], APPNAME)
except KeyError:
dataFolder = path.join(environ["HOME"], ".config", APPNAME)
# Migrate existing data to the proper location if this is an existing install
try:
move(path.join(environ["HOME"], ".%s" % APPNAME), dataFolder)
stringToLog = "Moving data folder to %s" % (dataFolder)
if 'logger' in globals():
logger.info(stringToLog)
else:
print stringToLog
except IOError:
# Old directory may not exist.
pass
dataFolder = dataFolder + '/'
return dataFolder
def codePath():
if frozen == "macosx_app":
codePath = environ.get("RESOURCEPATH")
elif frozen: # windows
codePath = sys._MEIPASS
else:
codePath = path.dirname(__file__)
return codePath

View File

@ -6,7 +6,9 @@ from struct import unpack, pack
from subprocess import call from subprocess import call
import sys import sys
import time import time
from configparser import BMConfigParser
from debug import logger from debug import logger
import paths
import shared import shared
import openclpow import openclpow
import tr import tr
@ -17,8 +19,7 @@ bitmsglib = 'bitmsghash.so'
def _set_idle(): def _set_idle():
if 'linux' in sys.platform: if 'linux' in sys.platform:
import os os.nice(20)
os.nice(20) # @UndefinedVariable
else: else:
try: try:
sys.getwindowsversion() sys.getwindowsversion()
@ -58,7 +59,7 @@ def _doFastPoW(target, initialHash):
except: except:
pool_size = 4 pool_size = 4
try: try:
maxCores = shared.config.getint('bitmessagesettings', 'maxcores') maxCores = BMConfigParser().getint('bitmessagesettings', 'maxcores')
except: except:
maxCores = 99999 maxCores = 99999
if pool_size > maxCores: if pool_size > maxCores:
@ -168,15 +169,15 @@ def buildCPoW():
if bmpow is not None: if bmpow is not None:
return return
if shared.frozen is not None: if paths.frozen is not None:
notifyBuild(False) notifyBuild(False)
return return
if sys.platform in ["win32", "win64"]: if sys.platform in ["win32", "win64"]:
notifyBuild(False) notifyBuild(False)
return return
try: try:
call(["make", "-C", os.path.join(shared.codePath(), "bitmsghash")]) call(["make", "-C", os.path.join(paths.codePath(), "bitmsghash")])
if os.path.exists(os.path.join(shared.codePath(), "bitmsghash", "bitmsghash.so")): if os.path.exists(os.path.join(paths.codePath(), "bitmsghash", "bitmsghash.so")):
init() init()
notifyBuild(True) notifyBuild(True)
else: else:
@ -207,7 +208,7 @@ def run(target, initialHash):
raise raise
except: except:
pass # fallback pass # fallback
if shared.frozen == "macosx_app" or not shared.frozen: if paths.frozen == "macosx_app" or not paths.frozen:
# on my (Peter Surda) Windows 10, Windows Defender # on my (Peter Surda) Windows 10, Windows Defender
# does not like this and fights with PyBitmessage # does not like this and fights with PyBitmessage
# over CPU, resulting in very slow PoW # over CPU, resulting in very slow PoW
@ -237,7 +238,7 @@ def init():
bitmsglib = 'bitmsghash64.dll' bitmsglib = 'bitmsghash64.dll'
try: try:
# MSVS # MSVS
bso = ctypes.WinDLL(os.path.join(shared.codePath(), "bitmsghash", bitmsglib)) bso = ctypes.WinDLL(os.path.join(paths.codePath(), "bitmsghash", bitmsglib))
logger.info("Loaded C PoW DLL (stdcall) %s", bitmsglib) logger.info("Loaded C PoW DLL (stdcall) %s", bitmsglib)
bmpow = bso.BitmessagePOW bmpow = bso.BitmessagePOW
bmpow.restype = ctypes.c_ulonglong bmpow.restype = ctypes.c_ulonglong
@ -247,7 +248,7 @@ def init():
logger.error("C PoW test fail.", exc_info=True) logger.error("C PoW test fail.", exc_info=True)
try: try:
# MinGW # MinGW
bso = ctypes.CDLL(os.path.join(shared.codePath(), "bitmsghash", bitmsglib)) bso = ctypes.CDLL(os.path.join(paths.codePath(), "bitmsghash", bitmsglib))
logger.info("Loaded C PoW DLL (cdecl) %s", bitmsglib) logger.info("Loaded C PoW DLL (cdecl) %s", bitmsglib)
bmpow = bso.BitmessagePOW bmpow = bso.BitmessagePOW
bmpow.restype = ctypes.c_ulonglong bmpow.restype = ctypes.c_ulonglong
@ -258,7 +259,7 @@ def init():
bso = None bso = None
else: else:
try: try:
bso = ctypes.CDLL(os.path.join(shared.codePath(), "bitmsghash", bitmsglib)) bso = ctypes.CDLL(os.path.join(paths.codePath(), "bitmsghash", bitmsglib))
logger.info("Loaded C PoW DLL %s", bitmsglib) logger.info("Loaded C PoW DLL %s", bitmsglib)
except: except:
bso = None bso = None

View File

@ -1,14 +1,485 @@
import struct import base64
import shared from binascii import hexlify
import hashlib
import random
import socket
import ssl
from struct import pack, unpack, Struct
import sys
import time
import traceback
from addresses import calculateInventoryHash, encodeVarint, decodeVarint, decodeAddress, varintDecodeError
from configparser import BMConfigParser
from debug import logger
from helper_sql import sqlExecute
import highlevelcrypto
from inventory import Inventory
import state
from version import softwareVersion
#Service flags
NODE_NETWORK = 1
NODE_SSL = 2
#Bitfield flags
BITFIELD_DOESACK = 1
eightBytesOfRandomDataUsedToDetectConnectionsToSelf = pack(
'>Q', random.randrange(1, 18446744073709551615))
#If changed, these values will cause particularly unexpected behavior: You won't be able to either send or receive messages because the proof of work you do (or demand) won't match that done or demanded by others. Don't change them!
networkDefaultProofOfWorkNonceTrialsPerByte = 1000 #The amount of work that should be performed (and demanded) per byte of the payload.
networkDefaultPayloadLengthExtraBytes = 1000 #To make sending short messages a little more difficult, this value is added to the payload length for use in calculating the proof of work target.
#Compiled struct for packing/unpacking headers
#New code should use CreatePacket instead of Header.pack
Header = Struct('!L12sL4s')
# Bitfield
def getBitfield(address): def getBitfield(address):
# bitfield of features supported by me (see the wiki). # bitfield of features supported by me (see the wiki).
bitfield = 0 bitfield = 0
# send ack # send ack
if not shared.safeConfigGetBoolean(address, 'dontsendack'): if not BMConfigParser().safeGetBoolean(address, 'dontsendack'):
bitfield |= shared.BITFIELD_DOESACK bitfield |= BITFIELD_DOESACK
return struct.pack('>I', bitfield) return pack('>I', bitfield)
def checkBitfield(bitfieldBinary, flags): def checkBitfield(bitfieldBinary, flags):
bitfield, = struct.unpack('>I', bitfieldBinary) bitfield, = unpack('>I', bitfieldBinary)
return (bitfield & flags) == flags return (bitfield & flags) == flags
def isBitSetWithinBitfield(fourByteString, n):
# Uses MSB 0 bit numbering across 4 bytes of data
n = 31 - n
x, = unpack('>L', fourByteString)
return x & 2**n != 0
# data handling
def encodeHost(host):
if host.find('.onion') > -1:
return '\xfd\x87\xd8\x7e\xeb\x43' + base64.b32decode(host.split(".")[0], True)
elif host.find(':') == -1:
return '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF' + \
socket.inet_aton(host)
else:
return socket.inet_pton(socket.AF_INET6, host)
# checks
def haveSSL(server = False):
# python < 2.7.9's ssl library does not support ECDSA server due to missing initialisation of available curves, but client works ok
if server == False:
return True
elif sys.version_info >= (2,7,9):
return True
return False
def sslProtocolVersion():
if sys.version_info >= (2,7,13):
# in the future once TLS is mandatory, change this to ssl.PROTOCOL_TLS1.2
return ssl.PROTOCOL_TLS
elif sys.version_info >= (2,7,9):
# once TLS is mandatory, add "ssl.OP_NO_TLSv1 | ssl.OP_NO_TLSv1.1"
return ssl.PROTOCOL_SSLv23 | ssl.OP_NO_SSLv2 | ssl.OP_NO_SSLv3
else:
return ssl.PROTOCOL_TLS1
def checkSocksIP(host):
try:
if state.socksIP is None or not state.socksIP:
state.socksIP = socket.gethostbyname(BMConfigParser().get("bitmessagesettings", "sockshostname"))
except NameError:
state.socksIP = socket.gethostbyname(BMConfigParser().get("bitmessagesettings", "sockshostname"))
return state.socksIP == host
def isProofOfWorkSufficient(data,
nonceTrialsPerByte=0,
payloadLengthExtraBytes=0):
if nonceTrialsPerByte < networkDefaultProofOfWorkNonceTrialsPerByte:
nonceTrialsPerByte = networkDefaultProofOfWorkNonceTrialsPerByte
if payloadLengthExtraBytes < networkDefaultPayloadLengthExtraBytes:
payloadLengthExtraBytes = networkDefaultPayloadLengthExtraBytes
endOfLifeTime, = unpack('>Q', data[8:16])
TTL = endOfLifeTime - int(time.time())
if TTL < 300:
TTL = 300
POW, = unpack('>Q', hashlib.sha512(hashlib.sha512(data[
:8] + hashlib.sha512(data[8:]).digest()).digest()).digest()[0:8])
return POW <= 2 ** 64 / (nonceTrialsPerByte*(len(data) + payloadLengthExtraBytes + ((TTL*(len(data)+payloadLengthExtraBytes))/(2 ** 16))))
# Packet creation
def CreatePacket(command, payload=''):
payload_length = len(payload)
checksum = hashlib.sha512(payload).digest()[0:4]
b = bytearray(Header.size + payload_length)
Header.pack_into(b, 0, 0xE9BEB4D9, command, payload_length, checksum)
b[Header.size:] = payload
return bytes(b)
def assembleVersionMessage(remoteHost, remotePort, myStreamNumber, server = False):
payload = ''
payload += pack('>L', 3) # protocol version.
payload += pack('>q', NODE_NETWORK|(NODE_SSL if haveSSL(server) else 0)) # bitflags of the services I offer.
payload += pack('>q', int(time.time()))
payload += pack(
'>q', 1) # boolservices of remote connection; ignored by the remote host.
if checkSocksIP(remoteHost) and server: # prevent leaking of tor outbound IP
payload += encodeHost('127.0.0.1')
payload += pack('>H', 8444)
else:
payload += encodeHost(remoteHost)
payload += pack('>H', remotePort) # remote IPv6 and port
payload += pack('>q', 1) # bitflags of the services I offer.
payload += '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF' + pack(
'>L', 2130706433) # = 127.0.0.1. This will be ignored by the remote host. The actual remote connected IP will be used.
# we have a separate extPort and
# incoming over clearnet or
# outgoing through clearnet
if BMConfigParser().safeGetBoolean('bitmessagesettings', 'upnp') and state.extPort \
and ((server and not checkSocksIP(remoteHost)) or \
(BMConfigParser().get("bitmessagesettings", "socksproxytype") == "none" and not server)):
payload += pack('>H', state.extPort)
elif checkSocksIP(remoteHost) and server: # incoming connection over Tor
payload += pack('>H', BMConfigParser().getint('bitmessagesettings', 'onionport'))
else: # no extPort and not incoming over Tor
payload += pack('>H', BMConfigParser().getint('bitmessagesettings', 'port'))
random.seed()
payload += eightBytesOfRandomDataUsedToDetectConnectionsToSelf
userAgent = '/PyBitmessage:' + softwareVersion + '/'
payload += encodeVarint(len(userAgent))
payload += userAgent
payload += encodeVarint(
1) # The number of streams about which I care. PyBitmessage currently only supports 1 per connection.
payload += encodeVarint(myStreamNumber)
return CreatePacket('version', payload)
def assembleErrorMessage(fatal=0, banTime=0, inventoryVector='', errorText=''):
payload = encodeVarint(fatal)
payload += encodeVarint(banTime)
payload += encodeVarint(len(inventoryVector))
payload += inventoryVector
payload += encodeVarint(len(errorText))
payload += errorText
return CreatePacket('error', payload)
# Packet decoding
def decryptAndCheckPubkeyPayload(data, address):
"""
Version 4 pubkeys are encrypted. This function is run when we already have the
address to which we want to try to send a message. The 'data' may come either
off of the wire or we might have had it already in our inventory when we tried
to send a msg to this particular address.
"""
try:
status, addressVersion, streamNumber, ripe = decodeAddress(address)
readPosition = 20 # bypass the nonce, time, and object type
embeddedAddressVersion, varintLength = decodeVarint(data[readPosition:readPosition + 10])
readPosition += varintLength
embeddedStreamNumber, varintLength = decodeVarint(data[readPosition:readPosition + 10])
readPosition += varintLength
storedData = data[20:readPosition] # We'll store the address version and stream number (and some more) in the pubkeys table.
if addressVersion != embeddedAddressVersion:
logger.info('Pubkey decryption was UNsuccessful due to address version mismatch.')
return 'failed'
if streamNumber != embeddedStreamNumber:
logger.info('Pubkey decryption was UNsuccessful due to stream number mismatch.')
return 'failed'
tag = data[readPosition:readPosition + 32]
readPosition += 32
signedData = data[8:readPosition] # the time through the tag. More data is appended onto signedData below after the decryption.
encryptedData = data[readPosition:]
# Let us try to decrypt the pubkey
toAddress, cryptorObject = state.neededPubkeys[tag]
if toAddress != address:
logger.critical('decryptAndCheckPubkeyPayload failed due to toAddress mismatch. This is very peculiar. toAddress: %s, address %s', toAddress, address)
# the only way I can think that this could happen is if someone encodes their address data two different ways.
# That sort of address-malleability should have been caught by the UI or API and an error given to the user.
return 'failed'
try:
decryptedData = cryptorObject.decrypt(encryptedData)
except:
# Someone must have encrypted some data with a different key
# but tagged it with a tag for which we are watching.
logger.info('Pubkey decryption was unsuccessful.')
return 'failed'
readPosition = 0
bitfieldBehaviors = decryptedData[readPosition:readPosition + 4]
readPosition += 4
publicSigningKey = '\x04' + decryptedData[readPosition:readPosition + 64]
readPosition += 64
publicEncryptionKey = '\x04' + decryptedData[readPosition:readPosition + 64]
readPosition += 64
specifiedNonceTrialsPerByte, specifiedNonceTrialsPerByteLength = decodeVarint(
decryptedData[readPosition:readPosition + 10])
readPosition += specifiedNonceTrialsPerByteLength
specifiedPayloadLengthExtraBytes, specifiedPayloadLengthExtraBytesLength = decodeVarint(
decryptedData[readPosition:readPosition + 10])
readPosition += specifiedPayloadLengthExtraBytesLength
storedData += decryptedData[:readPosition]
signedData += decryptedData[:readPosition]
signatureLength, signatureLengthLength = decodeVarint(
decryptedData[readPosition:readPosition + 10])
readPosition += signatureLengthLength
signature = decryptedData[readPosition:readPosition + signatureLength]
if highlevelcrypto.verify(signedData, signature, hexlify(publicSigningKey)):
logger.info('ECDSA verify passed (within decryptAndCheckPubkeyPayload)')
else:
logger.info('ECDSA verify failed (within decryptAndCheckPubkeyPayload)')
return 'failed'
sha = hashlib.new('sha512')
sha.update(publicSigningKey + publicEncryptionKey)
ripeHasher = hashlib.new('ripemd160')
ripeHasher.update(sha.digest())
embeddedRipe = ripeHasher.digest()
if embeddedRipe != ripe:
# Although this pubkey object had the tag were were looking for and was
# encrypted with the correct encryption key, it doesn't contain the
# correct pubkeys. Someone is either being malicious or using buggy software.
logger.info('Pubkey decryption was UNsuccessful due to RIPE mismatch.')
return 'failed'
# Everything checked out. Insert it into the pubkeys table.
logger.info('within decryptAndCheckPubkeyPayload, addressVersion: %s, streamNumber: %s \n\
ripe %s\n\
publicSigningKey in hex: %s\n\
publicEncryptionKey in hex: %s', addressVersion,
streamNumber,
hexlify(ripe),
hexlify(publicSigningKey),
hexlify(publicEncryptionKey)
)
t = (address, addressVersion, storedData, int(time.time()), 'yes')
sqlExecute('''INSERT INTO pubkeys VALUES (?,?,?,?,?)''', *t)
return 'successful'
except varintDecodeError as e:
logger.info('Pubkey decryption was UNsuccessful due to a malformed varint.')
return 'failed'
except Exception as e:
logger.critical('Pubkey decryption was UNsuccessful because of an unhandled exception! This is definitely a bug! \n%s', traceback.format_exc())
return 'failed'
def checkAndShareObjectWithPeers(data):
"""
This function is called after either receiving an object off of the wire
or after receiving one as ackdata.
Returns the length of time that we should reserve to process this message
if we are receiving it off of the wire.
"""
if len(data) > 2 ** 18:
logger.info('The payload length of this object is too large (%s bytes). Ignoring it.', len(data))
return 0
# Let us check to make sure that the proof of work is sufficient.
if not isProofOfWorkSufficient(data):
logger.info('Proof of work is insufficient.')
return 0
endOfLifeTime, = unpack('>Q', data[8:16])
if endOfLifeTime - int(time.time()) > 28 * 24 * 60 * 60 + 10800: # The TTL may not be larger than 28 days + 3 hours of wiggle room
logger.info('This object\'s End of Life time is too far in the future. Ignoring it. Time is %s', endOfLifeTime)
return 0
if endOfLifeTime - int(time.time()) < - 3600: # The EOL time was more than an hour ago. That's too much.
logger.info('This object\'s End of Life time was more than an hour ago. Ignoring the object. Time is %s', endOfLifeTime)
return 0
intObjectType, = unpack('>I', data[16:20])
try:
if intObjectType == 0:
_checkAndShareGetpubkeyWithPeers(data)
return 0.1
elif intObjectType == 1:
_checkAndSharePubkeyWithPeers(data)
return 0.1
elif intObjectType == 2:
_checkAndShareMsgWithPeers(data)
return 0.6
elif intObjectType == 3:
_checkAndShareBroadcastWithPeers(data)
return 0.6
else:
_checkAndShareUndefinedObjectWithPeers(data)
return 0.6
except varintDecodeError as e:
logger.debug("There was a problem with a varint while checking to see whether it was appropriate to share an object with peers. Some details: %s", e)
except Exception as e:
logger.critical('There was a problem while checking to see whether it was appropriate to share an object with peers. This is definitely a bug! \n%s', traceback.format_exc())
return 0
def _checkAndShareUndefinedObjectWithPeers(data):
embeddedTime, = unpack('>Q', data[8:16])
readPosition = 20 # bypass nonce, time, and object type
objectVersion, objectVersionLength = decodeVarint(
data[readPosition:readPosition + 9])
readPosition += objectVersionLength
streamNumber, streamNumberLength = decodeVarint(
data[readPosition:readPosition + 9])
if not streamNumber in state.streamsInWhichIAmParticipating:
logger.debug('The streamNumber %s isn\'t one we are interested in.', streamNumber)
return
inventoryHash = calculateInventoryHash(data)
if inventoryHash in Inventory():
logger.debug('We have already received this undefined object. Ignoring.')
return
objectType, = unpack('>I', data[16:20])
Inventory()[inventoryHash] = (
objectType, streamNumber, data, embeddedTime,'')
logger.debug('advertising inv with hash: %s', hexlify(inventoryHash))
broadcastToSendDataQueues((streamNumber, 'advertiseobject', inventoryHash))
def _checkAndShareMsgWithPeers(data):
embeddedTime, = unpack('>Q', data[8:16])
readPosition = 20 # bypass nonce, time, and object type
objectVersion, objectVersionLength = decodeVarint(
data[readPosition:readPosition + 9])
readPosition += objectVersionLength
streamNumber, streamNumberLength = decodeVarint(
data[readPosition:readPosition + 9])
if not streamNumber in state.streamsInWhichIAmParticipating:
logger.debug('The streamNumber %s isn\'t one we are interested in.', streamNumber)
return
readPosition += streamNumberLength
inventoryHash = calculateInventoryHash(data)
if inventoryHash in Inventory():
logger.debug('We have already received this msg message. Ignoring.')
return
# This msg message is valid. Let's let our peers know about it.
objectType = 2
Inventory()[inventoryHash] = (
objectType, streamNumber, data, embeddedTime,'')
logger.debug('advertising inv with hash: %s', hexlify(inventoryHash))
broadcastToSendDataQueues((streamNumber, 'advertiseobject', inventoryHash))
# Now let's enqueue it to be processed ourselves.
objectProcessorQueue.put((objectType,data))
def _checkAndShareGetpubkeyWithPeers(data):
if len(data) < 42:
logger.info('getpubkey message doesn\'t contain enough data. Ignoring.')
return
if len(data) > 200:
logger.info('getpubkey is abnormally long. Sanity check failed. Ignoring object.')
embeddedTime, = unpack('>Q', data[8:16])
readPosition = 20 # bypass the nonce, time, and object type
requestedAddressVersionNumber, addressVersionLength = decodeVarint(
data[readPosition:readPosition + 10])
readPosition += addressVersionLength
streamNumber, streamNumberLength = decodeVarint(
data[readPosition:readPosition + 10])
if not streamNumber in state.streamsInWhichIAmParticipating:
logger.debug('The streamNumber %s isn\'t one we are interested in.', streamNumber)
return
readPosition += streamNumberLength
inventoryHash = calculateInventoryHash(data)
if inventoryHash in Inventory():
logger.debug('We have already received this getpubkey request. Ignoring it.')
return
objectType = 0
Inventory()[inventoryHash] = (
objectType, streamNumber, data, embeddedTime,'')
# This getpubkey request is valid. Forward to peers.
logger.debug('advertising inv with hash: %s', hexlify(inventoryHash))
broadcastToSendDataQueues((streamNumber, 'advertiseobject', inventoryHash))
# Now let's queue it to be processed ourselves.
objectProcessorQueue.put((objectType,data))
def _checkAndSharePubkeyWithPeers(data):
if len(data) < 146 or len(data) > 440: # sanity check
return
embeddedTime, = unpack('>Q', data[8:16])
readPosition = 20 # bypass the nonce, time, and object type
addressVersion, varintLength = decodeVarint(
data[readPosition:readPosition + 10])
readPosition += varintLength
streamNumber, varintLength = decodeVarint(
data[readPosition:readPosition + 10])
readPosition += varintLength
if not streamNumber in state.streamsInWhichIAmParticipating:
logger.debug('The streamNumber %s isn\'t one we are interested in.', streamNumber)
return
if addressVersion >= 4:
tag = data[readPosition:readPosition + 32]
logger.debug('tag in received pubkey is: %s', hexlify(tag))
else:
tag = ''
inventoryHash = calculateInventoryHash(data)
if inventoryHash in Inventory():
logger.debug('We have already received this pubkey. Ignoring it.')
return
objectType = 1
Inventory()[inventoryHash] = (
objectType, streamNumber, data, embeddedTime, tag)
# This object is valid. Forward it to peers.
logger.debug('advertising inv with hash: %s', hexlify(inventoryHash))
broadcastToSendDataQueues((streamNumber, 'advertiseobject', inventoryHash))
# Now let's queue it to be processed ourselves.
objectProcessorQueue.put((objectType,data))
def _checkAndShareBroadcastWithPeers(data):
if len(data) < 180:
logger.debug('The payload length of this broadcast packet is unreasonably low. Someone is probably trying funny business. Ignoring message.')
return
embeddedTime, = unpack('>Q', data[8:16])
readPosition = 20 # bypass the nonce, time, and object type
broadcastVersion, broadcastVersionLength = decodeVarint(
data[readPosition:readPosition + 10])
readPosition += broadcastVersionLength
if broadcastVersion >= 2:
streamNumber, streamNumberLength = decodeVarint(data[readPosition:readPosition + 10])
readPosition += streamNumberLength
if not streamNumber in state.streamsInWhichIAmParticipating:
logger.debug('The streamNumber %s isn\'t one we are interested in.', streamNumber)
return
if broadcastVersion >= 3:
tag = data[readPosition:readPosition+32]
else:
tag = ''
inventoryHash = calculateInventoryHash(data)
if inventoryHash in Inventory():
logger.debug('We have already received this broadcast object. Ignoring.')
return
# It is valid. Let's let our peers know about it.
objectType = 3
Inventory()[inventoryHash] = (
objectType, streamNumber, data, embeddedTime, tag)
# This object is valid. Forward it to peers.
logger.debug('advertising inv with hash: %s', hexlify(inventoryHash))
broadcastToSendDataQueues((streamNumber, 'advertiseobject', inventoryHash))
# Now let's queue it to be processed ourselves.
objectProcessorQueue.put((objectType,data))
# If you want to command all of the sendDataThreads to do something, like shutdown or send some data, this
# function puts your data into the queues for each of the sendDataThreads. The sendDataThreads are
# responsible for putting their queue into (and out of) the sendDataQueues list.
def broadcastToSendDataQueues(data):
# logger.debug('running broadcastToSendDataQueues')
for q in state.sendDataQueues:
q.put(data)

View File

@ -1,6 +1,5 @@
from __future__ import division from __future__ import division
softwareVersion = '0.6.1'
verbose = 1 verbose = 1
maximumAgeOfAnObjectThatIAmWillingToAccept = 216000 # This is obsolete with the change to protocol v3 but the singleCleaner thread still hasn't been updated so we need this a little longer. maximumAgeOfAnObjectThatIAmWillingToAccept = 216000 # This is obsolete with the change to protocol v3 but the singleCleaner thread still hasn't been updated so we need this a little longer.
lengthOfTimeToHoldOnToAllPubkeys = 2419200 # Equals 4 weeks. You could make this longer if you want but making it shorter would not be advisable because there is a very small possibility that it could keep you from obtaining a needed pubkey for a period of time. lengthOfTimeToHoldOnToAllPubkeys = 2419200 # Equals 4 weeks. You could make this longer if you want but making it shorter would not be advisable because there is a very small possibility that it could keep you from obtaining a needed pubkey for a period of time.
@ -9,22 +8,17 @@ useVeryEasyProofOfWorkForTesting = False # If you set this to True while on the
# Libraries. # Libraries.
import base64
import collections import collections
import os import os
import pickle import pickle
import Queue import Queue
import random
from multiprocessing import active_children, Queue as mpQueue, Lock as mpLock from multiprocessing import active_children, Queue as mpQueue, Lock as mpLock
import socket
import sys import sys
import stat import stat
import threading import threading
import time import time
import shutil # used for moving the data folder and copying keys.dat import shutil # used for moving the data folder and copying keys.dat
import datetime import datetime
from os import path, environ
from struct import Struct
import traceback import traceback
from binascii import hexlify from binascii import hexlify
@ -37,9 +31,11 @@ import shared
#import helper_startup #import helper_startup
from helper_sql import * from helper_sql import *
from helper_threading import * from helper_threading import *
from inventory import Inventory
import protocol
import state
config = BMConfigParser()
myECCryptorObjects = {} myECCryptorObjects = {}
MyECSubscriptionCryptorObjects = {} MyECSubscriptionCryptorObjects = {}
myAddressesByHash = {} #The key in this dictionary is the RIPE hash which is encoded in an address and value is the address itself. myAddressesByHash = {} #The key in this dictionary is the RIPE hash which is encoded in an address and value is the address itself.
@ -54,10 +50,7 @@ parserLock = mpLock()
addressGeneratorQueue = Queue.Queue() addressGeneratorQueue = Queue.Queue()
knownNodesLock = threading.Lock() knownNodesLock = threading.Lock()
knownNodes = {} knownNodes = {}
sendDataQueues = [] #each sendData thread puts its queue in this list.
inventoryLock = threading.RLock() #Guarantees that two receiveDataThreads don't receive and process the same message concurrently (probably sent by a malicious individual)
printLock = threading.Lock() printLock = threading.Lock()
appdata = '' #holds the location of the application data storage directory
statusIconColor = 'red' statusIconColor = 'red'
connectedHostsList = {} #List of hosts to which we are connected. Used to guarantee that the outgoingSynSender threads won't connect to the same remote node twice. connectedHostsList = {} #List of hosts to which we are connected. Used to guarantee that the outgoingSynSender threads won't connect to the same remote node twice.
shutdown = 0 #Set to 1 by the doCleanShutdown function. Used to tell the proof of work worker threads to exit. shutdown = 0 #Set to 1 by the doCleanShutdown function. Used to tell the proof of work worker threads to exit.
@ -68,9 +61,6 @@ alreadyAttemptedConnectionsListLock = threading.Lock()
alreadyAttemptedConnectionsListResetTime = int( alreadyAttemptedConnectionsListResetTime = int(
time.time()) # used to clear out the alreadyAttemptedConnectionsList periodically so that we will retry connecting to hosts to which we have already tried to connect. time.time()) # used to clear out the alreadyAttemptedConnectionsList periodically so that we will retry connecting to hosts to which we have already tried to connect.
numberOfObjectsThatWeHaveYetToGetPerPeer = {} numberOfObjectsThatWeHaveYetToGetPerPeer = {}
neededPubkeys = {}
eightBytesOfRandomDataUsedToDetectConnectionsToSelf = pack(
'>Q', random.randrange(1, 18446744073709551615))
successfullyDecryptMessageTimings = [ successfullyDecryptMessageTimings = [
] # A list of the amounts of time it took to successfully decrypt msg messages ] # A list of the amounts of time it took to successfully decrypt msg messages
apiAddressGeneratorReturnQueue = Queue.Queue( apiAddressGeneratorReturnQueue = Queue.Queue(
@ -80,7 +70,6 @@ clientHasReceivedIncomingConnections = False #used by API command clientStatus
numberOfMessagesProcessed = 0 numberOfMessagesProcessed = 0
numberOfBroadcastsProcessed = 0 numberOfBroadcastsProcessed = 0
numberOfPubkeysProcessed = 0 numberOfPubkeysProcessed = 0
numberOfInventoryLookupsPerformed = 0
numberOfBytesReceived = 0 # Used for the 'network status' page numberOfBytesReceived = 0 # Used for the 'network status' page
numberOfBytesSent = 0 # Used for the 'network status' page numberOfBytesSent = 0 # Used for the 'network status' page
numberOfBytesReceivedLastSecond = 0 # used for the bandwidth rate limit numberOfBytesReceivedLastSecond = 0 # used for the bandwidth rate limit
@ -93,27 +82,17 @@ daemon = False
needToWriteKnownNodesToDisk = False # If True, the singleCleaner will write it to disk eventually. needToWriteKnownNodesToDisk = False # If True, the singleCleaner will write it to disk eventually.
maximumLengthOfTimeToBotherResendingMessages = 0 maximumLengthOfTimeToBotherResendingMessages = 0
objectProcessorQueue = ObjectProcessorQueue() # receiveDataThreads dump objects they hear on the network into this queue to be processed. objectProcessorQueue = ObjectProcessorQueue() # receiveDataThreads dump objects they hear on the network into this queue to be processed.
streamsInWhichIAmParticipating = {}
timeOffsetWrongCount = 0 timeOffsetWrongCount = 0
# sanity check, prevent doing ridiculous PoW # sanity check, prevent doing ridiculous PoW
# 20 million PoWs equals approximately 2 days on dev's dual R9 290 # 20 million PoWs equals approximately 2 days on dev's dual R9 290
ridiculousDifficulty = 20000000 ridiculousDifficulty = 20000000
#If changed, these values will cause particularly unexpected behavior: You won't be able to either send or receive messages because the proof of work you do (or demand) won't match that done or demanded by others. Don't change them!
networkDefaultProofOfWorkNonceTrialsPerByte = 1000 #The amount of work that should be performed (and demanded) per byte of the payload.
networkDefaultPayloadLengthExtraBytes = 1000 #To make sending short messages a little more difficult, this value is added to the payload length for use in calculating the proof of work target.
# Remember here the RPC port read from namecoin.conf so we can restore to # Remember here the RPC port read from namecoin.conf so we can restore to
# it as default whenever the user changes the "method" selection for # it as default whenever the user changes the "method" selection for
# namecoin integration to "namecoind". # namecoin integration to "namecoind".
namecoinDefaultRpcPort = "8336" namecoinDefaultRpcPort = "8336"
# When using py2exe or py2app, the variable frozen is added to the sys
# namespace. This can be used to setup a different code path for
# binary distributions vs source distributions.
frozen = getattr(sys,'frozen', None)
# If the trustedpeer option is specified in keys.dat then this will # If the trustedpeer option is specified in keys.dat then this will
# contain a Peer which will be connected to instead of using the # contain a Peer which will be connected to instead of using the
# addresses advertised by other peers. The client will only connect to # addresses advertised by other peers. The client will only connect to
@ -126,253 +105,6 @@ frozen = getattr(sys,'frozen', None)
# security. # security.
trustedPeer = None trustedPeer = None
# For UPnP
extPort = None
# for Tor hidden service
socksIP = None
#Compiled struct for packing/unpacking headers
#New code should use CreatePacket instead of Header.pack
Header = Struct('!L12sL4s')
#Service flags
NODE_NETWORK = 1
NODE_SSL = 2
#Bitfield flags
BITFIELD_DOESACK = 1
import collections
InventoryItem = collections.namedtuple('InventoryItem', 'type stream payload expires tag')
class Inventory(collections.MutableMapping):
def __init__(self):
super(Inventory, self).__init__()
self._inventory = {} #of objects (like msg payloads and pubkey payloads) Does not include protocol headers (the first 24 bytes of each packet).
self._streams = collections.defaultdict(set) # key = streamNumer, value = a set which holds the inventory object hashes that we are aware of. This is used whenever we receive an inv message from a peer to check to see what items are new to us. We don't delete things out of it; instead, the singleCleaner thread clears and refills it every couple hours.
def __contains__(self, hash):
global numberOfInventoryLookupsPerformed
with inventoryLock:
numberOfInventoryLookupsPerformed += 1
if hash in self._inventory:
return True
return bool(sqlQuery('SELECT 1 FROM inventory WHERE hash=?', hash))
def __getitem__(self, hash):
with inventoryLock:
if hash in self._inventory:
return self._inventory[hash]
rows = sqlQuery('SELECT objecttype, streamnumber, payload, expirestime, tag FROM inventory WHERE hash=?', hash)
if not rows:
raise KeyError(hash)
return InventoryItem(*rows[0])
def __setitem__(self, hash, value):
with inventoryLock:
value = InventoryItem(*value)
self._inventory[hash] = value
self._streams[value.stream].add(hash)
def __delitem__(self, hash):
raise NotImplementedError
def __iter__(self):
with inventoryLock:
hashes = self._inventory.keys()[:]
hashes += (hash for hash, in sqlQuery('SELECT hash FROM inventory'))
return hashes.__iter__()
def __len__(self):
with inventoryLock:
return len(self._inventory) + sqlQuery('SELECT count(*) FROM inventory')[0][0]
def by_type_and_tag(self, type, tag):
with inventoryLock:
values = [value for value in self._inventory.values() if value.type == type and value.tag == tag]
values += (InventoryItem(*value) for value in sqlQuery('SELECT objecttype, streamnumber, payload, expirestime, tag FROM inventory WHERE objecttype=? AND tag=?', type, tag))
return values
def hashes_by_stream(self, stream):
with inventoryLock:
return self._streams[stream]
def unexpired_hashes_by_stream(self, stream):
with inventoryLock:
t = int(time.time())
hashes = [hash for hash, value in self._inventory.items() if value.stream == stream and value.expires > t]
hashes += (payload for payload, in sqlQuery('SELECT hash FROM inventory WHERE streamnumber=? AND expirestime>?', stream, t))
return hashes
def flush(self):
with inventoryLock: # If you use both the inventoryLock and the sqlLock, always use the inventoryLock OUTSIDE of the sqlLock.
with SqlBulkExecute() as sql:
for hash, value in self._inventory.items():
sql.execute('INSERT INTO inventory VALUES (?, ?, ?, ?, ?, ?)', hash, *value)
self._inventory.clear()
def clean(self):
with inventoryLock:
sqlExecute('DELETE FROM inventory WHERE expirestime<?',int(time.time()) - (60 * 60 * 3))
self._streams.clear()
for hash, value in self.items():
self._streams[value.stream].add(hash)
inventory = Inventory()
#Create a packet
def CreatePacket(command, payload=''):
payload_length = len(payload)
checksum = hashlib.sha512(payload).digest()[0:4]
b = bytearray(Header.size + payload_length)
Header.pack_into(b, 0, 0xE9BEB4D9, command, payload_length, checksum)
b[Header.size:] = payload
return bytes(b)
def encodeHost(host):
if host.find('.onion') > -1:
return '\xfd\x87\xd8\x7e\xeb\x43' + base64.b32decode(host.split(".")[0], True)
elif host.find(':') == -1:
return '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF' + \
socket.inet_aton(host)
else:
return socket.inet_pton(socket.AF_INET6, host)
def haveSSL(server = False):
# python < 2.7.9's ssl library does not support ECDSA server due to missing initialisation of available curves, but client works ok
if server == False:
return True
elif sys.version_info >= (2,7,9):
return True
return False
def checkSocksIP(host):
try:
if socksIP is None or not socksIP:
socksIP = socket.gethostbyname(config.get("bitmessagesettings", "sockshostname"))
except NameError:
socksIP = socket.gethostbyname(config.get("bitmessagesettings", "sockshostname"))
return socksIP == host
def assembleVersionMessage(remoteHost, remotePort, myStreamNumber, server = False):
payload = ''
payload += pack('>L', 3) # protocol version.
payload += pack('>q', NODE_NETWORK|(NODE_SSL if haveSSL(server) else 0)) # bitflags of the services I offer.
payload += pack('>q', int(time.time()))
payload += pack(
'>q', 1) # boolservices of remote connection; ignored by the remote host.
if checkSocksIP(remoteHost) and server: # prevent leaking of tor outbound IP
payload += encodeHost('127.0.0.1')
payload += pack('>H', 8444)
else:
payload += encodeHost(remoteHost)
payload += pack('>H', remotePort) # remote IPv6 and port
payload += pack('>q', 1) # bitflags of the services I offer.
payload += '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF' + pack(
'>L', 2130706433) # = 127.0.0.1. This will be ignored by the remote host. The actual remote connected IP will be used.
# we have a separate extPort and
# incoming over clearnet or
# outgoing through clearnet
if safeConfigGetBoolean('bitmessagesettings', 'upnp') and extPort \
and ((server and not checkSocksIP(remoteHost)) or \
(config.get("bitmessagesettings", "socksproxytype") == "none" and not server)):
payload += pack('>H', extPort)
elif checkSocksIP(remoteHost) and server: # incoming connection over Tor
payload += pack('>H', shared.config.getint('bitmessagesettings', 'onionport'))
else: # no extPort and not incoming over Tor
payload += pack('>H', shared.config.getint('bitmessagesettings', 'port'))
random.seed()
payload += eightBytesOfRandomDataUsedToDetectConnectionsToSelf
userAgent = '/PyBitmessage:' + shared.softwareVersion + '/'
payload += encodeVarint(len(userAgent))
payload += userAgent
payload += encodeVarint(
1) # The number of streams about which I care. PyBitmessage currently only supports 1 per connection.
payload += encodeVarint(myStreamNumber)
return CreatePacket('version', payload)
def assembleErrorMessage(fatal=0, banTime=0, inventoryVector='', errorText=''):
payload = encodeVarint(fatal)
payload += encodeVarint(banTime)
payload += encodeVarint(len(inventoryVector))
payload += inventoryVector
payload += encodeVarint(len(errorText))
payload += errorText
return CreatePacket('error', payload)
def lookupExeFolder():
if frozen:
if frozen == "macosx_app":
# targetdir/Bitmessage.app/Contents/MacOS/Bitmessage
exeFolder = path.dirname(path.dirname(path.dirname(path.dirname(sys.executable)))) + path.sep
else:
exeFolder = path.dirname(sys.executable) + path.sep
elif __file__:
exeFolder = path.dirname(__file__) + path.sep
else:
exeFolder = ''
return exeFolder
def lookupAppdataFolder():
APPNAME = "PyBitmessage"
if "BITMESSAGE_HOME" in environ:
dataFolder = environ["BITMESSAGE_HOME"]
if dataFolder[-1] not in [os.path.sep, os.path.altsep]:
dataFolder += os.path.sep
elif sys.platform == 'darwin':
if "HOME" in environ:
dataFolder = path.join(os.environ["HOME"], "Library/Application Support/", APPNAME) + '/'
else:
stringToLog = 'Could not find home folder, please report this message and your OS X version to the BitMessage Github.'
if 'logger' in globals():
logger.critical(stringToLog)
else:
print stringToLog
sys.exit()
elif 'win32' in sys.platform or 'win64' in sys.platform:
dataFolder = path.join(environ['APPDATA'].decode(sys.getfilesystemencoding(), 'ignore'), APPNAME) + path.sep
else:
from shutil import move
try:
dataFolder = path.join(environ["XDG_CONFIG_HOME"], APPNAME)
except KeyError:
dataFolder = path.join(environ["HOME"], ".config", APPNAME)
# Migrate existing data to the proper location if this is an existing install
try:
move(path.join(environ["HOME"], ".%s" % APPNAME), dataFolder)
stringToLog = "Moving data folder to %s" % (dataFolder)
if 'logger' in globals():
logger.info(stringToLog)
else:
print stringToLog
except IOError:
# Old directory may not exist.
pass
dataFolder = dataFolder + '/'
return dataFolder
def codePath():
if frozen == "macosx_app":
codePath = os.environ.get("RESOURCEPATH")
elif frozen: # windows
codePath = sys._MEIPASS
else:
codePath = os.path.dirname(__file__)
return codePath
def isAddressInMyAddressBook(address): def isAddressInMyAddressBook(address):
queryreturn = sqlQuery( queryreturn = sqlQuery(
'''select address from addressbook where address=?''', '''select address from addressbook where address=?''',
@ -401,18 +133,6 @@ def isAddressInMyAddressBookSubscriptionsListOrWhitelist(address):
return True return True
return False return False
def safeConfigGetBoolean(section,field):
try:
return config.getboolean(section,field)
except Exception, err:
return False
def safeConfigGet(section, option, default = None):
if config.has_option (section, option):
return config.get(section, option)
else:
return default
def decodeWalletImportFormat(WIFstring): def decodeWalletImportFormat(WIFstring):
fullString = arithmetic.changebase(WIFstring,58,256) fullString = arithmetic.changebase(WIFstring,58,256)
privkey = fullString[:-4] privkey = fullString[:-4]
@ -440,12 +160,12 @@ def reloadMyAddressHashes():
myAddressesByTag.clear() myAddressesByTag.clear()
#myPrivateKeys.clear() #myPrivateKeys.clear()
keyfileSecure = checkSensitiveFilePermissions(appdata + 'keys.dat') keyfileSecure = checkSensitiveFilePermissions(state.appdata + 'keys.dat')
configSections = config.sections() configSections = BMConfigParser().sections()
hasEnabledKeys = False hasEnabledKeys = False
for addressInKeysFile in configSections: for addressInKeysFile in configSections:
if addressInKeysFile <> 'bitmessagesettings': if addressInKeysFile <> 'bitmessagesettings':
isEnabled = config.getboolean(addressInKeysFile, 'enabled') isEnabled = BMConfigParser().getboolean(addressInKeysFile, 'enabled')
if isEnabled: if isEnabled:
hasEnabledKeys = True hasEnabledKeys = True
status,addressVersionNumber,streamNumber,hash = decodeAddress(addressInKeysFile) status,addressVersionNumber,streamNumber,hash = decodeAddress(addressInKeysFile)
@ -453,7 +173,7 @@ def reloadMyAddressHashes():
# Returns a simple 32 bytes of information encoded in 64 Hex characters, # Returns a simple 32 bytes of information encoded in 64 Hex characters,
# or null if there was an error. # or null if there was an error.
privEncryptionKey = hexlify(decodeWalletImportFormat( privEncryptionKey = hexlify(decodeWalletImportFormat(
config.get(addressInKeysFile, 'privencryptionkey'))) BMConfigParser().get(addressInKeysFile, 'privencryptionkey')))
if len(privEncryptionKey) == 64:#It is 32 bytes encoded as 64 hex characters if len(privEncryptionKey) == 64:#It is 32 bytes encoded as 64 hex characters
myECCryptorObjects[hash] = highlevelcrypto.makeCryptor(privEncryptionKey) myECCryptorObjects[hash] = highlevelcrypto.makeCryptor(privEncryptionKey)
@ -466,7 +186,7 @@ def reloadMyAddressHashes():
logger.error('Error in reloadMyAddressHashes: Can\'t handle address versions other than 2, 3, or 4.\n') logger.error('Error in reloadMyAddressHashes: Can\'t handle address versions other than 2, 3, or 4.\n')
if not keyfileSecure: if not keyfileSecure:
fixSensitiveFilePermissions(appdata + 'keys.dat', hasEnabledKeys) fixSensitiveFilePermissions(state.appdata + 'keys.dat', hasEnabledKeys)
def reloadBroadcastSendersForWhichImWatching(): def reloadBroadcastSendersForWhichImWatching():
broadcastSendersForWhichImWatching.clear() broadcastSendersForWhichImWatching.clear()
@ -490,29 +210,14 @@ def reloadBroadcastSendersForWhichImWatching():
privEncryptionKey = doubleHashOfAddressData[:32] privEncryptionKey = doubleHashOfAddressData[:32]
MyECSubscriptionCryptorObjects[tag] = highlevelcrypto.makeCryptor(hexlify(privEncryptionKey)) MyECSubscriptionCryptorObjects[tag] = highlevelcrypto.makeCryptor(hexlify(privEncryptionKey))
def isProofOfWorkSufficient(data,
nonceTrialsPerByte=0,
payloadLengthExtraBytes=0):
if nonceTrialsPerByte < networkDefaultProofOfWorkNonceTrialsPerByte:
nonceTrialsPerByte = networkDefaultProofOfWorkNonceTrialsPerByte
if payloadLengthExtraBytes < networkDefaultPayloadLengthExtraBytes:
payloadLengthExtraBytes = networkDefaultPayloadLengthExtraBytes
endOfLifeTime, = unpack('>Q', data[8:16])
TTL = endOfLifeTime - int(time.time())
if TTL < 300:
TTL = 300
POW, = unpack('>Q', hashlib.sha512(hashlib.sha512(data[
:8] + hashlib.sha512(data[8:]).digest()).digest()).digest()[0:8])
return POW <= 2 ** 64 / (nonceTrialsPerByte*(len(data) + payloadLengthExtraBytes + ((TTL*(len(data)+payloadLengthExtraBytes))/(2 ** 16))))
def doCleanShutdown(): def doCleanShutdown():
global shutdown, thisapp global shutdown
shutdown = 1 #Used to tell proof of work worker threads and the objectProcessorThread to exit. shutdown = 1 #Used to tell proof of work worker threads and the objectProcessorThread to exit.
try: try:
parserInputQueue.put(None, False) parserInputQueue.put(None, False)
except Queue.Full: except Queue.Full:
pass pass
broadcastToSendDataQueues((0, 'shutdown', 'no data')) protocol.broadcastToSendDataQueues((0, 'shutdown', 'no data'))
objectProcessorQueue.put(('checkShutdownVariable', 'no data')) objectProcessorQueue.put(('checkShutdownVariable', 'no data'))
for thread in threading.enumerate(): for thread in threading.enumerate():
if thread.isAlive() and isinstance(thread, StoppableThread): if thread.isAlive() and isinstance(thread, StoppableThread):
@ -520,7 +225,7 @@ def doCleanShutdown():
knownNodesLock.acquire() knownNodesLock.acquire()
UISignalQueue.put(('updateStatusBar','Saving the knownNodes list of peers to disk...')) UISignalQueue.put(('updateStatusBar','Saving the knownNodes list of peers to disk...'))
output = open(appdata + 'knownnodes.dat', 'wb') output = open(state.appdata + 'knownnodes.dat', 'wb')
logger.info('finished opening knownnodes.dat. Now pickle.dump') logger.info('finished opening knownnodes.dat. Now pickle.dump')
pickle.dump(knownNodes, output) pickle.dump(knownNodes, output)
logger.info('Completed pickle.dump. Closing output...') logger.info('Completed pickle.dump. Closing output...')
@ -533,7 +238,7 @@ def doCleanShutdown():
UISignalQueue.put(( UISignalQueue.put((
'updateStatusBar', 'updateStatusBar',
'Flushing inventory in memory out to disk. This should normally only take a second...')) 'Flushing inventory in memory out to disk. This should normally only take a second...'))
inventory.flush() Inventory().flush()
# Verify that the objectProcessor has finished exiting. It should have incremented the # Verify that the objectProcessor has finished exiting. It should have incremented the
# shutdown variable from 1 to 2. This must finish before we command the sqlThread to exit. # shutdown variable from 1 to 2. This must finish before we command the sqlThread to exit.
@ -556,21 +261,13 @@ def doCleanShutdown():
logger.debug("Waiting for thread %s", thread.name) logger.debug("Waiting for thread %s", thread.name)
thread.join() thread.join()
if safeConfigGetBoolean('bitmessagesettings','daemon'): if BMConfigParser().safeGetBoolean('bitmessagesettings','daemon'):
logger.info('Clean shutdown complete.') logger.info('Clean shutdown complete.')
thisapp.cleanup() thisapp.cleanup()
os._exit(0) os._exit(0)
else: else:
logger.info('Core shutdown complete.') logger.info('Core shutdown complete.')
# If you want to command all of the sendDataThreads to do something, like shutdown or send some data, this
# function puts your data into the queues for each of the sendDataThreads. The sendDataThreads are
# responsible for putting their queue into (and out of) the sendDataQueues list.
def broadcastToSendDataQueues(data):
# logger.debug('running broadcastToSendDataQueues')
for q in sendDataQueues:
q.put(data)
def fixPotentiallyInvalidUTF8Data(text): def fixPotentiallyInvalidUTF8Data(text):
try: try:
unicode(text,'utf-8') unicode(text,'utf-8')
@ -758,7 +455,7 @@ def checkAndShareObjectWithPeers(data):
logger.info('The payload length of this object is too large (%s bytes). Ignoring it.' % len(data)) logger.info('The payload length of this object is too large (%s bytes). Ignoring it.' % len(data))
return 0 return 0
# Let us check to make sure that the proof of work is sufficient. # Let us check to make sure that the proof of work is sufficient.
if not isProofOfWorkSufficient(data): if not protocol.isProofOfWorkSufficient(data):
logger.info('Proof of work is insufficient.') logger.info('Proof of work is insufficient.')
return 0 return 0
@ -801,23 +498,19 @@ def _checkAndShareUndefinedObjectWithPeers(data):
readPosition += objectVersionLength readPosition += objectVersionLength
streamNumber, streamNumberLength = decodeVarint( streamNumber, streamNumberLength = decodeVarint(
data[readPosition:readPosition + 9]) data[readPosition:readPosition + 9])
if not streamNumber in streamsInWhichIAmParticipating: if not streamNumber in state.streamsInWhichIAmParticipating:
logger.debug('The streamNumber %s isn\'t one we are interested in.' % streamNumber) logger.debug('The streamNumber %s isn\'t one we are interested in.' % streamNumber)
return return
inventoryHash = calculateInventoryHash(data) inventoryHash = calculateInventoryHash(data)
shared.numberOfInventoryLookupsPerformed += 1 if inventoryHash in Inventory():
inventoryLock.acquire()
if inventoryHash in inventory:
logger.debug('We have already received this undefined object. Ignoring.') logger.debug('We have already received this undefined object. Ignoring.')
inventoryLock.release()
return return
objectType, = unpack('>I', data[16:20]) objectType, = unpack('>I', data[16:20])
inventory[inventoryHash] = ( Inventory()[inventoryHash] = (
objectType, streamNumber, data, embeddedTime,'') objectType, streamNumber, data, embeddedTime,'')
inventoryLock.release()
logger.debug('advertising inv with hash: %s' % hexlify(inventoryHash)) logger.debug('advertising inv with hash: %s' % hexlify(inventoryHash))
broadcastToSendDataQueues((streamNumber, 'advertiseobject', inventoryHash)) protocol.broadcastToSendDataQueues((streamNumber, 'advertiseobject', inventoryHash))
def _checkAndShareMsgWithPeers(data): def _checkAndShareMsgWithPeers(data):
@ -828,24 +521,20 @@ def _checkAndShareMsgWithPeers(data):
readPosition += objectVersionLength readPosition += objectVersionLength
streamNumber, streamNumberLength = decodeVarint( streamNumber, streamNumberLength = decodeVarint(
data[readPosition:readPosition + 9]) data[readPosition:readPosition + 9])
if not streamNumber in streamsInWhichIAmParticipating: if not streamNumber in state.streamsInWhichIAmParticipating:
logger.debug('The streamNumber %s isn\'t one we are interested in.' % streamNumber) logger.debug('The streamNumber %s isn\'t one we are interested in.' % streamNumber)
return return
readPosition += streamNumberLength readPosition += streamNumberLength
inventoryHash = calculateInventoryHash(data) inventoryHash = calculateInventoryHash(data)
shared.numberOfInventoryLookupsPerformed += 1 if inventoryHash in Inventory():
inventoryLock.acquire()
if inventoryHash in inventory:
logger.debug('We have already received this msg message. Ignoring.') logger.debug('We have already received this msg message. Ignoring.')
inventoryLock.release()
return return
# This msg message is valid. Let's let our peers know about it. # This msg message is valid. Let's let our peers know about it.
objectType = 2 objectType = 2
inventory[inventoryHash] = ( Inventory()[inventoryHash] = (
objectType, streamNumber, data, embeddedTime,'') objectType, streamNumber, data, embeddedTime,'')
inventoryLock.release()
logger.debug('advertising inv with hash: %s' % hexlify(inventoryHash)) logger.debug('advertising inv with hash: %s' % hexlify(inventoryHash))
broadcastToSendDataQueues((streamNumber, 'advertiseobject', inventoryHash)) protocol.broadcastToSendDataQueues((streamNumber, 'advertiseobject', inventoryHash))
# Now let's enqueue it to be processed ourselves. # Now let's enqueue it to be processed ourselves.
objectProcessorQueue.put((objectType,data)) objectProcessorQueue.put((objectType,data))
@ -863,26 +552,22 @@ def _checkAndShareGetpubkeyWithPeers(data):
readPosition += addressVersionLength readPosition += addressVersionLength
streamNumber, streamNumberLength = decodeVarint( streamNumber, streamNumberLength = decodeVarint(
data[readPosition:readPosition + 10]) data[readPosition:readPosition + 10])
if not streamNumber in streamsInWhichIAmParticipating: if not streamNumber in state.streamsInWhichIAmParticipating:
logger.debug('The streamNumber %s isn\'t one we are interested in.' % streamNumber) logger.debug('The streamNumber %s isn\'t one we are interested in.' % streamNumber)
return return
readPosition += streamNumberLength readPosition += streamNumberLength
shared.numberOfInventoryLookupsPerformed += 1
inventoryHash = calculateInventoryHash(data) inventoryHash = calculateInventoryHash(data)
inventoryLock.acquire() if inventoryHash in Inventory():
if inventoryHash in inventory:
logger.debug('We have already received this getpubkey request. Ignoring it.') logger.debug('We have already received this getpubkey request. Ignoring it.')
inventoryLock.release()
return return
objectType = 0 objectType = 0
inventory[inventoryHash] = ( Inventory()[inventoryHash] = (
objectType, streamNumber, data, embeddedTime,'') objectType, streamNumber, data, embeddedTime,'')
inventoryLock.release()
# This getpubkey request is valid. Forward to peers. # This getpubkey request is valid. Forward to peers.
logger.debug('advertising inv with hash: %s' % hexlify(inventoryHash)) logger.debug('advertising inv with hash: %s' % hexlify(inventoryHash))
broadcastToSendDataQueues((streamNumber, 'advertiseobject', inventoryHash)) protocol.broadcastToSendDataQueues((streamNumber, 'advertiseobject', inventoryHash))
# Now let's queue it to be processed ourselves. # Now let's queue it to be processed ourselves.
objectProcessorQueue.put((objectType,data)) objectProcessorQueue.put((objectType,data))
@ -898,7 +583,7 @@ def _checkAndSharePubkeyWithPeers(data):
streamNumber, varintLength = decodeVarint( streamNumber, varintLength = decodeVarint(
data[readPosition:readPosition + 10]) data[readPosition:readPosition + 10])
readPosition += varintLength readPosition += varintLength
if not streamNumber in streamsInWhichIAmParticipating: if not streamNumber in state.streamsInWhichIAmParticipating:
logger.debug('The streamNumber %s isn\'t one we are interested in.' % streamNumber) logger.debug('The streamNumber %s isn\'t one we are interested in.' % streamNumber)
return return
if addressVersion >= 4: if addressVersion >= 4:
@ -907,20 +592,16 @@ def _checkAndSharePubkeyWithPeers(data):
else: else:
tag = '' tag = ''
shared.numberOfInventoryLookupsPerformed += 1
inventoryHash = calculateInventoryHash(data) inventoryHash = calculateInventoryHash(data)
inventoryLock.acquire() if inventoryHash in Inventory():
if inventoryHash in inventory:
logger.debug('We have already received this pubkey. Ignoring it.') logger.debug('We have already received this pubkey. Ignoring it.')
inventoryLock.release()
return return
objectType = 1 objectType = 1
inventory[inventoryHash] = ( Inventory()[inventoryHash] = (
objectType, streamNumber, data, embeddedTime, tag) objectType, streamNumber, data, embeddedTime, tag)
inventoryLock.release()
# This object is valid. Forward it to peers. # This object is valid. Forward it to peers.
logger.debug('advertising inv with hash: %s' % hexlify(inventoryHash)) logger.debug('advertising inv with hash: %s' % hexlify(inventoryHash))
broadcastToSendDataQueues((streamNumber, 'advertiseobject', inventoryHash)) protocol.broadcastToSendDataQueues((streamNumber, 'advertiseobject', inventoryHash))
# Now let's queue it to be processed ourselves. # Now let's queue it to be processed ourselves.
@ -939,40 +620,37 @@ def _checkAndShareBroadcastWithPeers(data):
if broadcastVersion >= 2: if broadcastVersion >= 2:
streamNumber, streamNumberLength = decodeVarint(data[readPosition:readPosition + 10]) streamNumber, streamNumberLength = decodeVarint(data[readPosition:readPosition + 10])
readPosition += streamNumberLength readPosition += streamNumberLength
if not streamNumber in streamsInWhichIAmParticipating: if not streamNumber in state.streamsInWhichIAmParticipating:
logger.debug('The streamNumber %s isn\'t one we are interested in.' % streamNumber) logger.debug('The streamNumber %s isn\'t one we are interested in.' % streamNumber)
return return
if broadcastVersion >= 3: if broadcastVersion >= 3:
tag = data[readPosition:readPosition+32] tag = data[readPosition:readPosition+32]
else: else:
tag = '' tag = ''
shared.numberOfInventoryLookupsPerformed += 1
inventoryLock.acquire()
inventoryHash = calculateInventoryHash(data) inventoryHash = calculateInventoryHash(data)
if inventoryHash in inventory: if inventoryHash in Inventory():
logger.debug('We have already received this broadcast object. Ignoring.') logger.debug('We have already received this broadcast object. Ignoring.')
inventoryLock.release()
return return
# It is valid. Let's let our peers know about it. # It is valid. Let's let our peers know about it.
objectType = 3 objectType = 3
inventory[inventoryHash] = ( Inventory()[inventoryHash] = (
objectType, streamNumber, data, embeddedTime, tag) objectType, streamNumber, data, embeddedTime, tag)
inventoryLock.release()
# This object is valid. Forward it to peers. # This object is valid. Forward it to peers.
logger.debug('advertising inv with hash: %s' % hexlify(inventoryHash)) logger.debug('advertising inv with hash: %s' % hexlify(inventoryHash))
broadcastToSendDataQueues((streamNumber, 'advertiseobject', inventoryHash)) protocol.broadcastToSendDataQueues((streamNumber, 'advertiseobject', inventoryHash))
# Now let's queue it to be processed ourselves. # Now let's queue it to be processed ourselves.
objectProcessorQueue.put((objectType,data)) objectProcessorQueue.put((objectType,data))
def openKeysFile(): def openKeysFile():
if 'linux' in sys.platform: if 'linux' in sys.platform:
subprocess.call(["xdg-open", shared.appdata + 'keys.dat']) import subprocess
subprocess.call(["xdg-open", state.appdata + 'keys.dat'])
else: else:
os.startfile(shared.appdata + 'keys.dat') os.startfile(state.appdata + 'keys.dat')
def writeKeysFile(): def writeKeysFile():
fileName = shared.appdata + 'keys.dat' fileName = state.appdata + 'keys.dat'
fileNameBak = fileName + "." + datetime.datetime.now().strftime("%Y%j%H%M%S%f") + '.bak' fileNameBak = fileName + "." + datetime.datetime.now().strftime("%Y%j%H%M%S%f") + '.bak'
# create a backup copy to prevent the accidental loss due to the disk write failure # create a backup copy to prevent the accidental loss due to the disk write failure
try: try:
@ -984,7 +662,7 @@ def writeKeysFile():
fileNameExisted = False fileNameExisted = False
# write the file # write the file
with open(fileName, 'wb') as configfile: with open(fileName, 'wb') as configfile:
shared.config.write(configfile) BMConfigParser().write(configfile)
# delete the backup # delete the backup
if fileNameExisted: if fileNameExisted:
os.remove(fileNameBak) os.remove(fileNameBak)

85
src/singleinstance.py Normal file
View File

@ -0,0 +1,85 @@
#! /usr/bin/env python
import atexit
import errno
from multiprocessing import Process
import os
import sys
import shared
import state
try:
import fcntl # @UnresolvedImport
except:
pass
class singleinstance:
"""
Implements a single instance application by creating a lock file at appdata.
This is based upon the singleton class from tendo https://github.com/pycontribs/tendo
which is under the Python Software Foundation License version 2
"""
def __init__(self, flavor_id="", daemon=False):
self.initialized = False
self.counter = 0
self.daemon = daemon
self.lockPid = None
self.lockfile = os.path.normpath(os.path.join(state.appdata, 'singleton%s.lock' % flavor_id))
if not self.daemon and not shared.curses:
# Tells the already running (if any) application to get focus.
import bitmessageqt
bitmessageqt.init()
self.lock()
self.initialized = True
atexit.register(self.cleanup)
def lock(self):
if self.lockPid is None:
self.lockPid = os.getpid()
if sys.platform == 'win32':
try:
# file already exists, we try to remove (in case previous execution was interrupted)
if os.path.exists(self.lockfile):
os.unlink(self.lockfile)
self.fd = os.open(self.lockfile, os.O_CREAT | os.O_EXCL | os.O_RDWR)
except OSError:
type, e, tb = sys.exc_info()
if e.errno == 13:
print 'Another instance of this application is already running'
sys.exit(-1)
print(e.errno)
raise
else: # non Windows
self.fp = open(self.lockfile, 'w')
try:
if self.daemon and self.lockPid != os.getpid():
fcntl.lockf(self.fp, fcntl.LOCK_EX) # wait for parent to finish
else:
fcntl.lockf(self.fp, fcntl.LOCK_EX | fcntl.LOCK_NB)
self.lockPid = os.getpid()
except IOError:
print 'Another instance of this application is already running'
sys.exit(-1)
def cleanup(self):
if not self.initialized:
return
if self.daemon and self.lockPid == os.getpid():
# these are the two initial forks while daemonizing
return
print "Cleaning up lockfile"
try:
if sys.platform == 'win32':
if hasattr(self, 'fd'):
os.close(self.fd)
os.unlink(self.lockfile)
else:
fcntl.lockf(self.fp, fcntl.LOCK_UN)
if os.path.isfile(self.lockfile):
os.unlink(self.lockfile)
except Exception, e:
pass

View File

@ -1,84 +1,7 @@
#! /usr/bin/env python def Singleton(cls):
instances = {}
import atexit def getinstance():
import errno if cls not in instances:
from multiprocessing import Process instances[cls] = cls()
import os return instances[cls]
import sys return getinstance
import shared
try:
import fcntl # @UnresolvedImport
except:
pass
class singleinstance:
"""
Implements a single instance application by creating a lock file at appdata.
This is based upon the singleton class from tendo https://github.com/pycontribs/tendo
which is under the Python Software Foundation License version 2
"""
def __init__(self, flavor_id="", daemon=False):
self.initialized = False
self.counter = 0
self.daemon = daemon
self.lockPid = None
self.lockfile = os.path.normpath(os.path.join(shared.appdata, 'singleton%s.lock' % flavor_id))
if not self.daemon and not shared.curses:
# Tells the already running (if any) application to get focus.
import bitmessageqt
bitmessageqt.init()
self.lock()
self.initialized = True
atexit.register(self.cleanup)
def lock(self):
if self.lockPid is None:
self.lockPid = os.getpid()
if sys.platform == 'win32':
try:
# file already exists, we try to remove (in case previous execution was interrupted)
if os.path.exists(self.lockfile):
os.unlink(self.lockfile)
self.fd = os.open(self.lockfile, os.O_CREAT | os.O_EXCL | os.O_RDWR)
except OSError:
type, e, tb = sys.exc_info()
if e.errno == 13:
print 'Another instance of this application is already running'
sys.exit(-1)
print(e.errno)
raise
else: # non Windows
self.fp = open(self.lockfile, 'w')
try:
if self.daemon and self.lockPid != os.getpid():
fcntl.lockf(self.fp, fcntl.LOCK_EX) # wait for parent to finish
else:
fcntl.lockf(self.fp, fcntl.LOCK_EX | fcntl.LOCK_NB)
self.lockPid = os.getpid()
except IOError:
print 'Another instance of this application is already running'
sys.exit(-1)
def cleanup(self):
if not self.initialized:
return
if self.daemon and self.lockPid == os.getpid():
# these are the two initial forks while daemonizing
return
print "Cleaning up lockfile"
try:
if sys.platform == 'win32':
if hasattr(self, 'fd'):
os.close(self.fd)
os.unlink(self.lockfile)
else:
fcntl.lockf(self.fp, fcntl.LOCK_UN)
if os.path.isfile(self.lockfile):
os.unlink(self.lockfile)
except Exception, e:
pass

14
src/state.py Normal file
View File

@ -0,0 +1,14 @@
neededPubkeys = {}
streamsInWhichIAmParticipating = {}
sendDataQueues = [] #each sendData thread puts its queue in this list.
# For UPnP
extPort = None
# for Tor hidden service
socksIP = None
# Network protocols last check failed
networkProtocolLastFailed = {'IPv4': 0, 'IPv6': 0, 'onion': 0}
appdata = '' #holds the location of the application data storage directory

View File

@ -1,6 +1,7 @@
import shared
import os import os
from configparser import BMConfigParser
# This is used so that the translateText function can be used when we are in daemon mode and not using any QT functions. # This is used so that the translateText function can be used when we are in daemon mode and not using any QT functions.
class translateClass: class translateClass:
def __init__(self, context, text): def __init__(self, context, text):
@ -16,7 +17,7 @@ def _translate(context, text, disambiguation = None, encoding = None, n = None):
return translateText(context, text, n) return translateText(context, text, n)
def translateText(context, text, n = None): def translateText(context, text, n = None):
if not shared.safeConfigGetBoolean('bitmessagesettings', 'daemon'): if not BMConfigParser().safeGetBoolean('bitmessagesettings', 'daemon'):
try: try:
from PyQt4 import QtCore, QtGui from PyQt4 import QtCore, QtGui
except Exception as err: except Exception as err:

View File

@ -6,11 +6,12 @@ import socket
from struct import unpack, pack from struct import unpack, pack
import threading import threading
import time import time
from configparser import BMConfigParser
from helper_threading import * from helper_threading import *
import shared import shared
import tr import tr
def createRequestXML(service, action, arguments=[]): def createRequestXML(service, action, arguments=None):
from xml.dom.minidom import Document from xml.dom.minidom import Document
doc = Document() doc = Document()
@ -36,6 +37,7 @@ def createRequestXML(service, action, arguments=[]):
# iterate over arguments, create nodes, create text nodes, # iterate over arguments, create nodes, create text nodes,
# append text nodes to nodes, and finally add the ready product # append text nodes to nodes, and finally add the ready product
# to argument_list # to argument_list
if arguments is not None:
for k, v in arguments: for k, v in arguments:
tmp_node = doc.createElement(k) tmp_node = doc.createElement(k)
tmp_text_node = doc.createTextNode(v) tmp_text_node = doc.createTextNode(v)
@ -139,7 +141,7 @@ class Router:
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=[]): def soapRequest(self, service, action, arguments=None):
from xml.dom.minidom import parseString from xml.dom.minidom import parseString
from debug import logger from debug import logger
conn = httplib.HTTPConnection(self.routerPath.hostname, self.routerPath.port) conn = httplib.HTTPConnection(self.routerPath.hostname, self.routerPath.port)
@ -175,9 +177,9 @@ class uPnPThread(threading.Thread, StoppableThread):
def __init__ (self): def __init__ (self):
threading.Thread.__init__(self, name="uPnPThread") threading.Thread.__init__(self, name="uPnPThread")
self.localPort = shared.config.getint('bitmessagesettings', 'port') self.localPort = BMConfigParser().getint('bitmessagesettings', 'port')
try: try:
self.extPort = shared.config.getint('bitmessagesettings', 'extport') self.extPort = BMConfigParser().getint('bitmessagesettings', 'extport')
except: except:
self.extPort = None self.extPort = None
self.localIP = self.getLocalIP() self.localIP = self.getLocalIP()
@ -195,7 +197,7 @@ class uPnPThread(threading.Thread, StoppableThread):
logger.debug("Starting UPnP thread") logger.debug("Starting UPnP thread")
logger.debug("Local IP: %s", self.localIP) logger.debug("Local IP: %s", self.localIP)
lastSent = 0 lastSent = 0
while shared.shutdown == 0 and shared.safeConfigGetBoolean('bitmessagesettings', 'upnp'): while shared.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 len(self.routers) == 0:
try: try:
self.sendSearchRouter() self.sendSearchRouter()
@ -203,7 +205,7 @@ class uPnPThread(threading.Thread, StoppableThread):
pass pass
lastSent = time.time() lastSent = time.time()
try: try:
while shared.shutdown == 0 and shared.safeConfigGetBoolean('bitmessagesettings', 'upnp'): while shared.shutdown == 0 and BMConfigParser().safeGetBoolean('bitmessagesettings', 'upnp'):
resp,(ip,port) = self.sock.recvfrom(1000) resp,(ip,port) = self.sock.recvfrom(1000)
if resp is None: if resp is None:
continue continue
@ -279,7 +281,7 @@ class uPnPThread(threading.Thread, StoppableThread):
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
shared.config.set('bitmessagesettings', 'extport', str(extPort)) BMConfigParser().set('bitmessagesettings', 'extport', str(extPort))
break break
except UPnPError: except UPnPError:
logger.debug("UPnP error: ", exc_info=True) logger.debug("UPnP error: ", exc_info=True)

1
src/version.py Normal file
View File

@ -0,0 +1 @@
softwareVersion = '0.6.1'