From e84b19613e2bfc4ed44e3f6350b23f6c2e01e9e3 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Tue, 10 Jan 2017 21:15:35 +0100 Subject: [PATCH 01/12] Inventory refactoring - minor refactoring, made it into singleton instead of a shared global variable. This makes it a little bit cleaner and moves the class into a separate file - removed duplicate inventory locking - renamed singleton.py to singleinstance.py (this is the code that ensures only one instance of PyBitmessage runs at the same time) --- src/bitmessagecurses/__init__.py | 5 +- src/bitmessagemain.py | 4 +- src/bitmessageqt/__init__.py | 2 +- src/bitmessageqt/networkstatus.py | 5 +- src/class_receiveDataThread.py | 19 ++--- src/class_singleCleaner.py | 5 +- src/class_singleWorker.py | 15 ++-- src/inventory.py | 84 ++++++++++++++++++++ src/shared.py | 127 +++--------------------------- src/singleinstance.py | 84 ++++++++++++++++++++ src/singleton.py | 91 ++------------------- 11 files changed, 214 insertions(+), 227 deletions(-) create mode 100644 src/inventory.py create mode 100644 src/singleinstance.py diff --git a/src/bitmessagecurses/__init__.py b/src/bitmessagecurses/__init__.py index 3b740247..1d667b2b 100644 --- a/src/bitmessagecurses/__init__.py +++ b/src/bitmessagecurses/__init__.py @@ -26,6 +26,7 @@ import ConfigParser from addresses import * from pyelliptic.openssl import OpenSSL import l10n +from inventory import Inventory quit = False menutab = 1 @@ -108,8 +109,8 @@ def scrollbox(d, text, height=None, width=None): def resetlookups(): global inventorydata - inventorydata = shared.numberOfInventoryLookupsPerformed - shared.numberOfInventoryLookupsPerformed = 0 + inventorydata = Inventory().numberOfInventoryLookupsPerformed + Inventory().numberOfInventoryLookupsPerformed = 0 Timer(1, resetlookups, ()).start() def drawtab(stdscr): if menutab in range(1, len(menu)+1): diff --git a/src/bitmessagemain.py b/src/bitmessagemain.py index 830dca31..3b2d1aae 100755 --- a/src/bitmessagemain.py +++ b/src/bitmessagemain.py @@ -14,7 +14,7 @@ depends.check_dependencies() import signal # Used to capture a Ctrl-C keypress so that Bitmessage can shutdown gracefully. # The next 3 are used for the API -import singleton +from singleinstance import singleinstance import os import socket import ctypes @@ -162,7 +162,7 @@ class Main: shared.curses = True # is the application already running? If yes then exit. - shared.thisapp = singleton.singleinstance("", daemon) + shared.thisapp = singleinstance("", daemon) if daemon: with shared.printLock: diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 37c52917..4e3366c7 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -4428,7 +4428,7 @@ class MySingleApplication(QApplication): # Checks if there's an instance of the local server id 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 else: # Nope, create a local server with this id and assign on_new_connection diff --git a/src/bitmessageqt/networkstatus.py b/src/bitmessageqt/networkstatus.py index 09d05c63..c792f81c 100644 --- a/src/bitmessageqt/networkstatus.py +++ b/src/bitmessageqt/networkstatus.py @@ -2,6 +2,7 @@ from PyQt4 import QtCore, QtGui import time import shared from tr import _translate +from inventory import Inventory import l10n from retranslateui import RetranslateMixin from uisignaler import UISignaler @@ -127,8 +128,8 @@ class NetworkStatus(QtGui.QWidget, RetranslateMixin): # timer driven def runEveryTwoSeconds(self): self.labelLookupsPerSecond.setText(_translate( - "networkstatus", "Inventory lookups per second: %1").arg(str(shared.numberOfInventoryLookupsPerformed/2))) - shared.numberOfInventoryLookupsPerformed = 0 + "networkstatus", "Inventory lookups per second: %1").arg(str(Inventory().numberOfInventoryLookupsPerformed/2))) + Inventory().numberOfInventoryLookupsPerformed = 0 self.updateNumberOfBytes() self.updateNumberOfObjectsToBeSynced() diff --git a/src/class_receiveDataThread.py b/src/class_receiveDataThread.py index c69697d6..f29b1f4c 100644 --- a/src/class_receiveDataThread.py +++ b/src/class_receiveDataThread.py @@ -27,6 +27,7 @@ from class_objectHashHolder import objectHashHolder from helper_generic import addDataPadding, isHostInPrivateIPRange from helper_sql import sqlQuery from debug import logger +from inventory import Inventory import tr # This thread is created either by the synSenderThread(for outgoing @@ -230,10 +231,9 @@ class receiveDataThread(threading.Thread): if self.data == '': # if there are no more messages while len(self.objectsThatWeHaveYetToGetFromThisPeer) > 0: - shared.numberOfInventoryLookupsPerformed += 1 objectHash, = random.sample( self.objectsThatWeHaveYetToGetFromThisPeer, 1) - if objectHash in shared.inventory: + if objectHash in Inventory(): logger.debug('Inventory already has object listed in inv message.') del self.objectsThatWeHaveYetToGetFromThisPeer[objectHash] else: @@ -336,7 +336,7 @@ class receiveDataThread(threading.Thread): def sendBigInv(self): # Select all hashes for objects in this stream. 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): bigInvList[hash] = 0 numberOfObjectsInInvMessage = 0 @@ -442,8 +442,7 @@ class receiveDataThread(threading.Thread): return self.someObjectsOfWhichThisRemoteNodeIsAlreadyAware[ data[lengthOfVarint:32 + lengthOfVarint]] = 0 - shared.numberOfInventoryLookupsPerformed += 1 - if data[lengthOfVarint:32 + lengthOfVarint] in shared.inventory: + if data[lengthOfVarint:32 + lengthOfVarint] in Inventory(): logger.debug('Inventory has inventory item already.') else: self.sendgetdata(data[lengthOfVarint:32 + lengthOfVarint]) @@ -455,7 +454,7 @@ class receiveDataThread(threading.Thread): advertisedSet = set() for i in range(numberOfItemsInInv): 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) for item in objectsNewToMe: if totalNumberOfobjectsThatWeHaveYetToGetFromAllPeers > 200000 and len(self.objectsThatWeHaveYetToGetFromThisPeer) > 1000 and shared.trustedPeer == None: # inv flooding attack mitigation @@ -488,15 +487,11 @@ class receiveDataThread(threading.Thread): i * 32):32 + lengthOfVarint + (i * 32)] logger.debug('received getdata request for item:' + hexlify(hash)) - shared.numberOfInventoryLookupsPerformed += 1 - shared.inventoryLock.acquire() if self.objectHashHolderInstance.hasHash(hash): - shared.inventoryLock.release() self.antiIntersectionDelay() else: - shared.inventoryLock.release() - if hash in shared.inventory: - self.sendObject(shared.inventory[hash].payload) + if hash in Inventory(): + self.sendObject(Inventory()[hash].payload) else: self.antiIntersectionDelay() logger.warning('%s asked for an object with a getdata which is not in either our memory inventory or our SQL inventory. We probably cleaned it out after advertising it but before they got around to asking for it.' % (self.peer,)) diff --git a/src/class_singleCleaner.py b/src/class_singleCleaner.py index 04ee3f9b..533184d3 100644 --- a/src/class_singleCleaner.py +++ b/src/class_singleCleaner.py @@ -8,6 +8,7 @@ import pickle import tr#anslate from helper_sql import * from helper_threading import * +from inventory import Inventory from debug import logger """ @@ -47,7 +48,7 @@ class singleCleaner(threading.Thread, StoppableThread): while shared.shutdown == 0: shared.UISignalQueue.put(( 'updateStatusBar', 'Doing housekeeping (Flushing inventory in memory to disk...)')) - shared.inventory.flush() + Inventory().flush() shared.UISignalQueue.put(('updateStatusBar', '')) shared.broadcastToSendDataQueues(( @@ -59,7 +60,7 @@ class singleCleaner(threading.Thread, StoppableThread): shared.UISignalQueue.queue.clear() if timeWeLastClearedInventoryAndPubkeysTables < int(time.time()) - 7380: timeWeLastClearedInventoryAndPubkeysTables = int(time.time()) - shared.inventory.clean() + Inventory().clean() # pubkeys sqlExecute( '''DELETE FROM pubkeys WHERE timeQ', nonce) + payload inventoryHash = calculateInventoryHash(payload) objectType = 1 - shared.inventory[inventoryHash] = ( + Inventory()[inventoryHash] = ( objectType, streamNumber, payload, embeddedTime,'') logger.info('broadcasting inv with hash: ' + hexlify(inventoryHash)) @@ -351,7 +352,7 @@ class singleWorker(threading.Thread, StoppableThread): payload = pack('>Q', nonce) + payload inventoryHash = calculateInventoryHash(payload) objectType = 1 - shared.inventory[inventoryHash] = ( + Inventory()[inventoryHash] = ( objectType, streamNumber, payload, embeddedTime, doubleHashOfAddressData[32:]) logger.info('broadcasting inv with hash: ' + hexlify(inventoryHash)) @@ -482,7 +483,7 @@ class singleWorker(threading.Thread, StoppableThread): inventoryHash = calculateInventoryHash(payload) objectType = 3 - shared.inventory[inventoryHash] = ( + Inventory()[inventoryHash] = ( objectType, streamNumber, payload, embeddedTime, tag) logger.info('sending inv (within sendBroadcast function) for object: ' + hexlify(inventoryHash)) shared.broadcastToSendDataQueues(( @@ -576,7 +577,7 @@ class singleWorker(threading.Thread, StoppableThread): tag = doubleHashOfToAddressData[32:] # The second half of the sha512 hash. shared.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. needToRequestPubkey = False sqlExecute( @@ -808,7 +809,7 @@ class singleWorker(threading.Thread, StoppableThread): inventoryHash = calculateInventoryHash(encryptedPayload) objectType = 2 - shared.inventory[inventoryHash] = ( + Inventory()[inventoryHash] = ( objectType, toStreamNumber, encryptedPayload, embeddedTime, '') if shared.config.has_section(toaddress) or not checkBitfield(behaviorBitfield, shared.BITFIELD_DOESACK): shared.UISignalQueue.put(('updateSentItemStatusByAckdata', (ackdata, tr._translate("MainWindow", "Message sent. Sent at %1").arg(l10n.formatTimestamp())))) @@ -917,7 +918,7 @@ class singleWorker(threading.Thread, StoppableThread): payload = pack('>Q', nonce) + payload inventoryHash = calculateInventoryHash(payload) objectType = 1 - shared.inventory[inventoryHash] = ( + Inventory()[inventoryHash] = ( objectType, streamNumber, payload, embeddedTime, '') logger.info('sending inv (for the getpubkey message)') shared.broadcastToSendDataQueues(( diff --git a/src/inventory.py b/src/inventory.py new file mode 100644 index 00000000..83a9ce82 --- /dev/null +++ b/src/inventory.py @@ -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 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 expirestimeI', data[16:20]) - inventory[inventoryHash] = ( + Inventory()[inventoryHash] = ( objectType, streamNumber, data, embeddedTime,'') - inventoryLock.release() logger.debug('advertising inv with hash: %s' % hexlify(inventoryHash)) broadcastToSendDataQueues((streamNumber, 'advertiseobject', inventoryHash)) @@ -833,17 +746,13 @@ def _checkAndShareMsgWithPeers(data): return readPosition += streamNumberLength inventoryHash = calculateInventoryHash(data) - shared.numberOfInventoryLookupsPerformed += 1 - inventoryLock.acquire() - if inventoryHash in inventory: + if inventoryHash in Inventory(): logger.debug('We have already received this msg message. Ignoring.') - inventoryLock.release() return # This msg message is valid. Let's let our peers know about it. objectType = 2 - inventory[inventoryHash] = ( + Inventory()[inventoryHash] = ( objectType, streamNumber, data, embeddedTime,'') - inventoryLock.release() logger.debug('advertising inv with hash: %s' % hexlify(inventoryHash)) broadcastToSendDataQueues((streamNumber, 'advertiseobject', inventoryHash)) @@ -868,18 +777,14 @@ def _checkAndShareGetpubkeyWithPeers(data): return readPosition += streamNumberLength - shared.numberOfInventoryLookupsPerformed += 1 inventoryHash = calculateInventoryHash(data) - inventoryLock.acquire() - if inventoryHash in inventory: + if inventoryHash in Inventory(): logger.debug('We have already received this getpubkey request. Ignoring it.') - inventoryLock.release() return objectType = 0 - inventory[inventoryHash] = ( + Inventory()[inventoryHash] = ( objectType, streamNumber, data, embeddedTime,'') - inventoryLock.release() # This getpubkey request is valid. Forward to peers. logger.debug('advertising inv with hash: %s' % hexlify(inventoryHash)) broadcastToSendDataQueues((streamNumber, 'advertiseobject', inventoryHash)) @@ -907,17 +812,13 @@ def _checkAndSharePubkeyWithPeers(data): else: tag = '' - shared.numberOfInventoryLookupsPerformed += 1 inventoryHash = calculateInventoryHash(data) - inventoryLock.acquire() - if inventoryHash in inventory: + if inventoryHash in Inventory(): logger.debug('We have already received this pubkey. Ignoring it.') - inventoryLock.release() return objectType = 1 - inventory[inventoryHash] = ( + Inventory()[inventoryHash] = ( objectType, streamNumber, data, embeddedTime, tag) - inventoryLock.release() # This object is valid. Forward it to peers. logger.debug('advertising inv with hash: %s' % hexlify(inventoryHash)) broadcastToSendDataQueues((streamNumber, 'advertiseobject', inventoryHash)) @@ -946,18 +847,14 @@ def _checkAndShareBroadcastWithPeers(data): tag = data[readPosition:readPosition+32] else: tag = '' - shared.numberOfInventoryLookupsPerformed += 1 - inventoryLock.acquire() inventoryHash = calculateInventoryHash(data) - if inventoryHash in inventory: + if inventoryHash in Inventory(): logger.debug('We have already received this broadcast object. Ignoring.') - inventoryLock.release() return # It is valid. Let's let our peers know about it. objectType = 3 - inventory[inventoryHash] = ( + Inventory()[inventoryHash] = ( objectType, streamNumber, data, embeddedTime, tag) - inventoryLock.release() # This object is valid. Forward it to peers. logger.debug('advertising inv with hash: %s' % hexlify(inventoryHash)) broadcastToSendDataQueues((streamNumber, 'advertiseobject', inventoryHash)) diff --git a/src/singleinstance.py b/src/singleinstance.py new file mode 100644 index 00000000..8bf7ed01 --- /dev/null +++ b/src/singleinstance.py @@ -0,0 +1,84 @@ +#! /usr/bin/env python + +import atexit +import errno +from multiprocessing import Process +import os +import sys +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 diff --git a/src/singleton.py b/src/singleton.py index 8bf7ed01..1eef08e1 100644 --- a/src/singleton.py +++ b/src/singleton.py @@ -1,84 +1,7 @@ -#! /usr/bin/env python - -import atexit -import errno -from multiprocessing import Process -import os -import sys -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 +def Singleton(cls): + instances = {} + def getinstance(): + if cls not in instances: + instances[cls] = cls() + return instances[cls] + return getinstance From 9c214b4a249ba0092434c5068ee13b472944e549 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Tue, 10 Jan 2017 21:17:25 +0100 Subject: [PATCH 02/12] Inventory refactoring #2 - forgot to add api.py --- src/api.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/api.py b/src/api.py index 30ab426e..0a76ff1b 100644 --- a/src/api.py +++ b/src/api.py @@ -29,6 +29,7 @@ from struct import pack # Classes from helper_sql import sqlQuery,sqlExecute,SqlBulkExecute,sqlStoredProcedure from debug import logger +from inventory import Inventory # Helper Functions import proofofwork @@ -849,7 +850,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): inventoryHash = calculateInventoryHash(encryptedPayload) objectType = 2 TTL = 2.5 * 24 * 60 * 60 - shared.inventory[inventoryHash] = ( + Inventory()[inventoryHash] = ( objectType, toStreamNumber, encryptedPayload, int(time.time()) + TTL,'') with shared.printLock: print 'Broadcasting inv for msg(API disseminatePreEncryptedMsg command):', hexlify(inventoryHash) @@ -896,7 +897,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): objectType = 1 #todo: support v4 pubkeys TTL = 28 * 24 * 60 * 60 - shared.inventory[inventoryHash] = ( + Inventory()[inventoryHash] = ( objectType, pubkeyStreamNumber, payload, int(time.time()) + TTL,'') with shared.printLock: print 'broadcasting inv within API command disseminatePubkey with hash:', hexlify(inventoryHash) From b4703ec6ce37fda706e5f296ec30038944b9e275 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Tue, 10 Jan 2017 21:19:57 +0100 Subject: [PATCH 03/12] Make objectHashHolder into a list - was a dict --- src/class_objectHashHolder.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/class_objectHashHolder.py b/src/class_objectHashHolder.py index 30d27ea8..24c2438d 100644 --- a/src/class_objectHashHolder.py +++ b/src/class_objectHashHolder.py @@ -17,11 +17,11 @@ class objectHashHolder(threading.Thread): threading.Thread.__init__(self, name="objectHashHolder") self.shutdown = False self.sendDataThreadMailbox = sendDataThreadMailbox # This queue is used to submit data back to our associated sendDataThread. - self.collectionOfHashLists = {} - self.collectionOfPeerLists = {} - for i in range(self.size): - self.collectionOfHashLists[i] = [] - self.collectionOfPeerLists[i] = [] + self.collectionOfHashLists = [] + self.collectionOfPeerLists = [] + for i in range(objectHashHolder.size): + self.collectionOfHashLists.append([]) + self.collectionOfPeerLists.append([]) def run(self): iterator = 0 @@ -33,11 +33,11 @@ class objectHashHolder(threading.Thread): self.sendDataThreadMailbox.put((0, 'sendaddr', self.collectionOfPeerLists[iterator])) self.collectionOfPeerLists[iterator] = [] iterator += 1 - iterator %= self.size + iterator %= objectHashHolder.size time.sleep(1) 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): if hash in (hashlist for hashlist in self.collectionOfHashLists): @@ -46,7 +46,7 @@ class objectHashHolder(threading.Thread): return False 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): return sum([len(x) for x in self.collectionOfHashLists if type(x) is list]) From 75090abaaf1d9190ac250326108ca1882b6f3c45 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Tue, 10 Jan 2017 21:20:49 +0100 Subject: [PATCH 04/12] Advanced dispatcher class - generic class the new asyncore-based network subsystem that handles buffered data transfer --- src/network/advanceddispatcher.py | 50 +++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 src/network/advanceddispatcher.py diff --git a/src/network/advanceddispatcher.py b/src/network/advanceddispatcher.py new file mode 100644 index 00000000..47eacc5a --- /dev/null +++ b/src/network/advanceddispatcher.py @@ -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() From 085e33596998665fbe0bf93daa8bdd227a9dfac5 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Tue, 10 Jan 2017 21:22:22 +0100 Subject: [PATCH 05/12] Proxy update (for the new network subsystem) --- src/network/proxy.py | 195 ++++++++++++++++--------------------------- 1 file changed, 72 insertions(+), 123 deletions(-) diff --git a/src/network/proxy.py b/src/network/proxy.py index aab28c50..d9830431 100644 --- a/src/network/proxy.py +++ b/src/network/proxy.py @@ -4,13 +4,13 @@ import asyncore import socket 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 # instances should change too _proxy = ["", 1080] _auth = None - _buf_len = 131072 _remote_dns = True @property @@ -34,46 +34,17 @@ class Proxy(asyncore.dispatcher): 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): raise - asyncore.dispatcher.__init__(self, self.sock) + AdvancedDispatcher.__init__(self, self.sock) self.destination = address - self.read_buf = "" - self.write_buf = "" - self.stage = "init" self.create_socket(socket.AF_INET, socket.SOCK_STREAM) self.sslSocket.setblocking(0) 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): def __init__(self, address=None, sock=None): Proxy.__init__(self, address) - self.state = 0 + self.state = "init" def handle_connect(self): self.process() @@ -83,11 +54,11 @@ class SOCKS5(Proxy): self.write_buf += struct.pack('BBBB', 0x05, 0x02, 0x00, 0x02) else: 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): - if len(self.read_buf) < 2: - return + if not self.read_buf_sufficient(2): + return False ret = struct.unpack('BB', self.read_buf) self.read_buf = self.read_buf[2:] if ret[0] != 5: @@ -95,13 +66,13 @@ class SOCKS5(Proxy): raise elif ret[1] == 0: # no auth required - self.set_state("auth_done") + self.set_state("auth_done", 2) elif ret[1] == 2: # username/password self.write_buf += struct.pack('BB', 1, len(self._auth[0])) + \ self._auth[0] + struct.pack('B', len(self._auth[1])) + \ self._auth[1] - self.set_state("auth_1") + self.set_state("auth_1", 2) else: if ret[1] == 0xff: # auth error @@ -111,8 +82,8 @@ class SOCKS5(Proxy): raise def state_auth_needed(self): - if len(self.read_buf) < 2: - return + if not self.read_buf_sufficient(2): + return False ret = struct.unpack('BB', self.read_buf) if ret[0] != 1: # general error @@ -121,37 +92,11 @@ class SOCKS5(Proxy): # auth error raise # all ok - self.set_state = ("auth_done") - - -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") + self.set_state = ("auth_done", 2) def state_pre_connect(self): - if len(self.read_buf) < 4: - return + if not self.read_buf_sufficient(4): + return False # Get the response if self.read_buf[0:1] != chr(0x05).encode(): # general error @@ -168,74 +113,78 @@ class SOCKS5Connection(SOCKS5): raise #raise Socks5Error((9, _socks5errors[9])) # Get the bound address/port - elif self_read_buf[3:4] == chr(0x01).encode(): - self.set_state("proxy_addr_long") - elif resp[3:4] == chr(0x03).encode(): - self.set_state("proxy_addr_short") + elif self.read_buf[3:4] == chr(0x01).encode(): + self.set_state("proxy_addr_1", 4) + elif self.read_buf[3:4] == chr(0x03).encode(): + self.set_state("proxy_addr_2_1", 4) else: self.close() 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): - if len(self.read_buf) < 4: - return + def state_proxy_addr_1(self): + if not self.read_buf_sufficient(4): + return False self.boundaddr = self.read_buf[0:4] - self.set_state("proxy_port") + self.set_state("proxy_port", 4) - def state_proxy_addr_short(self): - if len(self.read_buf) < 1: - return - self.boundaddr = self.read_buf[0:1] - self.set_state("proxy_port") + def state_proxy_addr_2_1(self): + if not self.read_buf_sufficient(1): + return False + self.address_length = ord(self.read_buf[0:1]) + 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): - if len(self.read_buf) < 2: - return + if not self.read_buf_sufficient(2): + return False self.boundport = struct.unpack(">H", self.read_buf[0:2])[0] self.__proxysockname = (self.boundaddr, self.boundport) - if ipaddr != None: - self.__proxypeername = (socket.inet_ntoa(ipaddr), destport) + if self.ipaddr != None: + self.__proxypeername = (socket.inet_ntoa(self.ipaddr), self.destination[1]) else: - self.__proxypeername = (destaddr, destport) + self.__proxypeername = (self.destination[1], destport) -class SOCKS5Resolver(SOCKS5): - def __init__(self, destpair): - SOCKS5.__init__(self, destpair) +class SOCKS5Connection(SOCKS5): + def __init__(self, address): + SOCKS5.__init__(self, address) def state_auth_done(self): # Now we can request the actual connection - req = struct.pack('BBB', 0x05, 0xF0, 0x00) - req += chr(0x03).encode() + chr(len(host)).encode() + host - req = req + struct.pack(">H", 8444) - self.sendall(req) - # Get the response - ip = "" - resp = self.__recvall(4) - if resp[0:1] != chr(0x05).encode(): - self.close() - raise GeneralProxyError((1, _generalerrors[1])) - elif resp[1:2] != chr(0x00).encode(): - # Connection failed - self.close() - if ord(resp[1:2])<=8: - raise Socks5Error((ord(resp[1:2]), _socks5errors[ord(resp[1:2])])) + 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: + self.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 + self.ipaddr = None + self.write_buf += chr(0x03).encode() + chr(len(self.destination[0])).encode() + self.destination[0] else: - raise Socks5Error((9, _socks5errors[9])) - # Get the bound address/port - elif resp[3:4] == chr(0x01).encode(): - ip = socket.inet_ntoa(self.__recvall(4)) - elif resp[3:4] == chr(0x03).encode(): - resp = resp + self.recv(1) - ip = self.__recvall(ord(resp[4:5])) - else: - self.close() - raise GeneralProxyError((1,_generalerrors[1])) - boundport = struct.unpack(">H", self.__recvall(2))[0] - return ip + # Resolve locally + self.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", 0) + + +class SOCKS5Resolver(SOCKS5): + def __init__(self, host): + self.host = host + self.port = 8444 + 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" From 2654b61bd721b97dd17e7bc4a4f71a55ea3e546f Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Wed, 11 Jan 2017 14:21:53 +0100 Subject: [PATCH 06/12] Compiletest for non-Windows systems --- build/compiletest.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) mode change 100644 => 100755 build/compiletest.py diff --git a/build/compiletest.py b/build/compiletest.py old mode 100644 new mode 100755 index 91df6c5e..fdbf7db1 --- a/build/compiletest.py +++ b/build/compiletest.py @@ -16,5 +16,8 @@ for filename in matches: try: compile(source, filename, 'exec') except Exception as e: - ctypes.windll.user32.MessageBoxA(0, traceback.format_exc(), "Exception in " + filename, 1) - sys.exit(1) \ No newline at end of file + if 'win' in sys.platform: + 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) From 8bcfe80ad0a33bd2f724697eefef8c9ac336ca2a Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Wed, 11 Jan 2017 14:27:19 +0100 Subject: [PATCH 07/12] Refactoring of config parser and shared.py - got rid of shared config parser and made it into a singleton - refactored safeConfigGetBoolean as a method of the config singleton - refactored safeConfigGet as a method of the config singleton - moved softwareVersion from shared.py into version.py - moved some global variables from shared.py into state.py - moved some protocol-specific functions from shared.py into protocol.py --- src/api.py | 66 ++--- src/bitmessagecli.py | 133 ++++----- src/bitmessagecurses/__init__.py | 56 ++-- src/bitmessagemain.py | 29 +- src/bitmessageqt/__init__.py | 288 ++++++++++---------- src/bitmessageqt/account.py | 25 +- src/bitmessageqt/bitmessageui.py | 5 +- src/bitmessageqt/blacklist.py | 23 +- src/bitmessageqt/foldertree.py | 31 ++- src/bitmessageqt/languagebox.py | 5 +- src/bitmessageqt/support.py | 12 +- src/bitmessageqt/utils.py | 7 +- src/class_addressGenerator.py | 45 +-- src/class_objectProcessor.py | 51 ++-- src/class_outgoingSynSender.py | 41 +-- src/class_receiveDataThread.py | 67 ++--- src/class_sendDataThread.py | 22 +- src/class_singleCleaner.py | 10 +- src/class_singleListener.py | 24 +- src/class_singleWorker.py | 107 ++++---- src/class_smtpDeliver.py | 5 +- src/class_smtpServer.py | 16 +- src/class_sqlThread.py | 145 +++++----- src/configparser.py | 18 ++ src/helper_bootstrap.py | 21 +- src/helper_generic.py | 3 +- src/helper_startup.py | 87 +++--- src/l10n.py | 9 +- src/namecoin.py | 31 ++- src/openclpow.py | 5 +- src/proofofwork.py | 3 +- src/protocol.py | 454 ++++++++++++++++++++++++++++++- src/shared.py | 131 +-------- src/state.py | 7 + src/tr.py | 6 +- src/upnp.py | 11 +- src/version.py | 1 + 37 files changed, 1187 insertions(+), 813 deletions(-) create mode 100644 src/state.py create mode 100644 src/version.py diff --git a/src/api.py b/src/api.py index 0a76ff1b..276e397f 100644 --- a/src/api.py +++ b/src/api.py @@ -19,6 +19,7 @@ from binascii import hexlify import shared import time from addresses import decodeAddress,addBMIfNotPresent,decodeVarint,calculateInventoryHash,varintDecodeError +from configparser import BMConfigParser import helper_inbox import helper_sent import hashlib @@ -30,6 +31,7 @@ from struct import pack from helper_sql import sqlQuery,sqlExecute,SqlBulkExecute,sqlStoredProcedure from debug import logger from inventory import Inventory +from version import softwareVersion # Helper Functions import proofofwork @@ -120,7 +122,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): # handle Basic authentication (enctype, encstr) = self.headers.get('Authorization').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 else: return False @@ -163,22 +165,22 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): def HandleListAddresses(self, method): data = '{"addresses":[' - configSections = shared.config.sections() + configSections = BMConfigParser().sections() for addressInKeysFile in configSections: if addressInKeysFile != 'bitmessagesettings': status, addressVersionNumber, streamNumber, hash01 = decodeAddress( addressInKeysFile) if len(data) > 20: data += ',' - if shared.config.has_option(addressInKeysFile, 'chan'): - chan = shared.config.getboolean(addressInKeysFile, 'chan') + if BMConfigParser().has_option(addressInKeysFile, 'chan'): + chan = BMConfigParser().getboolean(addressInKeysFile, 'chan') else: chan = False - label = shared.config.get(addressInKeysFile, 'label') + label = BMConfigParser().get(addressInKeysFile, 'label') if method == 'listAddresses2': label = label.encode('base64') 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 += ']}' return data @@ -236,21 +238,21 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): elif len(params) == 1: label, = params eighteenByteRipe = False - nonceTrialsPerByte = shared.config.get( + nonceTrialsPerByte = BMConfigParser().get( 'bitmessagesettings', 'defaultnoncetrialsperbyte') - payloadLengthExtraBytes = shared.config.get( + payloadLengthExtraBytes = BMConfigParser().get( 'bitmessagesettings', 'defaultpayloadlengthextrabytes') elif len(params) == 2: label, eighteenByteRipe = params - nonceTrialsPerByte = shared.config.get( + nonceTrialsPerByte = BMConfigParser().get( 'bitmessagesettings', 'defaultnoncetrialsperbyte') - payloadLengthExtraBytes = shared.config.get( + payloadLengthExtraBytes = BMConfigParser().get( 'bitmessagesettings', 'defaultpayloadlengthextrabytes') elif len(params) == 3: label, eighteenByteRipe, totalDifficulty = params nonceTrialsPerByte = int( shared.networkDefaultProofOfWorkNonceTrialsPerByte * totalDifficulty) - payloadLengthExtraBytes = shared.config.get( + payloadLengthExtraBytes = BMConfigParser().get( 'bitmessagesettings', 'defaultpayloadlengthextrabytes') elif len(params) == 4: label, eighteenByteRipe, totalDifficulty, smallMessageDifficulty = params @@ -280,45 +282,45 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): addressVersionNumber = 0 streamNumber = 0 eighteenByteRipe = False - nonceTrialsPerByte = shared.config.get( + nonceTrialsPerByte = BMConfigParser().get( 'bitmessagesettings', 'defaultnoncetrialsperbyte') - payloadLengthExtraBytes = shared.config.get( + payloadLengthExtraBytes = BMConfigParser().get( 'bitmessagesettings', 'defaultpayloadlengthextrabytes') elif len(params) == 2: passphrase, numberOfAddresses = params addressVersionNumber = 0 streamNumber = 0 eighteenByteRipe = False - nonceTrialsPerByte = shared.config.get( + nonceTrialsPerByte = BMConfigParser().get( 'bitmessagesettings', 'defaultnoncetrialsperbyte') - payloadLengthExtraBytes = shared.config.get( + payloadLengthExtraBytes = BMConfigParser().get( 'bitmessagesettings', 'defaultpayloadlengthextrabytes') elif len(params) == 3: passphrase, numberOfAddresses, addressVersionNumber = params streamNumber = 0 eighteenByteRipe = False - nonceTrialsPerByte = shared.config.get( + nonceTrialsPerByte = BMConfigParser().get( 'bitmessagesettings', 'defaultnoncetrialsperbyte') - payloadLengthExtraBytes = shared.config.get( + payloadLengthExtraBytes = BMConfigParser().get( 'bitmessagesettings', 'defaultpayloadlengthextrabytes') elif len(params) == 4: passphrase, numberOfAddresses, addressVersionNumber, streamNumber = params eighteenByteRipe = False - nonceTrialsPerByte = shared.config.get( + nonceTrialsPerByte = BMConfigParser().get( 'bitmessagesettings', 'defaultnoncetrialsperbyte') - payloadLengthExtraBytes = shared.config.get( + payloadLengthExtraBytes = BMConfigParser().get( 'bitmessagesettings', 'defaultpayloadlengthextrabytes') elif len(params) == 5: passphrase, numberOfAddresses, addressVersionNumber, streamNumber, eighteenByteRipe = params - nonceTrialsPerByte = shared.config.get( + nonceTrialsPerByte = BMConfigParser().get( 'bitmessagesettings', 'defaultnoncetrialsperbyte') - payloadLengthExtraBytes = shared.config.get( + payloadLengthExtraBytes = BMConfigParser().get( 'bitmessagesettings', 'defaultpayloadlengthextrabytes') elif len(params) == 6: passphrase, numberOfAddresses, addressVersionNumber, streamNumber, eighteenByteRipe, totalDifficulty = params nonceTrialsPerByte = int( shared.networkDefaultProofOfWorkNonceTrialsPerByte * totalDifficulty) - payloadLengthExtraBytes = shared.config.get( + payloadLengthExtraBytes = BMConfigParser().get( 'bitmessagesettings', 'defaultpayloadlengthextrabytes') elif len(params) == 7: passphrase, numberOfAddresses, addressVersionNumber, streamNumber, eighteenByteRipe, totalDifficulty, smallMessageDifficulty = params @@ -443,13 +445,13 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): address, = params status, addressVersionNumber, streamNumber, toRipe = self._verifyAddress(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.') - 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.') - shared.config.remove_section(address) + BMConfigParser().remove_section(address) with open(shared.appdata + 'keys.dat', 'wb') as configfile: - shared.config.write(configfile) + BMConfigParser().write(configfile) return 'success' def HandleDeleteAddress(self, params): @@ -459,11 +461,11 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): address, = params status, addressVersionNumber, streamNumber, toRipe = self._verifyAddress(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.') - shared.config.remove_section(address) + BMConfigParser().remove_section(address) with open(shared.appdata + 'keys.dat', 'wb') as configfile: - shared.config.write(configfile) + BMConfigParser().write(configfile) shared.UISignalQueue.put(('rerenderMessagelistFromLabels','')) shared.UISignalQueue.put(('rerenderMessagelistToLabels','')) shared.reloadMyAddressHashes() @@ -659,7 +661,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): status, addressVersionNumber, streamNumber, toRipe = self._verifyAddress(toAddress) self._verifyAddress(fromAddress) try: - fromAddressEnabled = shared.config.getboolean( + fromAddressEnabled = BMConfigParser().getboolean( fromAddress, 'enabled') except: raise APIError(13, 'Could not find your fromAddress in the keys.dat file.') @@ -723,7 +725,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): fromAddress = addBMIfNotPresent(fromAddress) self._verifyAddress(fromAddress) try: - fromAddressEnabled = shared.config.getboolean( + fromAddressEnabled = BMConfigParser().getboolean( fromAddress, 'enabled') except: raise APIError(13, 'could not find your fromAddress in the keys.dat file.') @@ -946,7 +948,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): networkStatus = 'connectedButHaveNotReceivedIncomingConnections' else: 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): # Return a meaningful decoding of an address. diff --git a/src/bitmessagecli.py b/src/bitmessagecli.py index c7d8b5cd..79272aee 100644 --- a/src/bitmessagecli.py +++ b/src/bitmessagecli.py @@ -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 ' *******************************************************************\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 def lookupAppdataFolder(): #gets the appropriate folders for the .dat files depending on the OS. Taken from bitmessagemain.py APPNAME = "PyBitmessage" @@ -74,14 +64,13 @@ def lookupAppdataFolder(): #gets the appropriate folders for the .dat files depe def configInit(): global keysName - config = BMConfigParser() - config.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. - config.set('bitmessagesettings','apienabled','true') #Sets apienabled to true in keys.dat + BMConfigParser().add_section('bitmessagesettings') + 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. + BMConfigParser().set('bitmessagesettings','apienabled','true') #Sets apienabled to true in keys.dat 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 ' You will now need to configure the ' + str(keysName) + ' file.\n' @@ -89,8 +78,7 @@ def configInit(): def apiInit(apiEnabled): global keysPath global usrPrompt - config = BMConfigParser() - config.read(keysPath) + BMConfigParser().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() 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: - config.write(configfile) + BMConfigParser().write(configfile) print 'Done' restartBmNotify() @@ -143,15 +131,15 @@ def apiInit(apiEnabled): 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. - config.set('bitmessagesettings','apienabled','true') - config.set('bitmessagesettings', 'apiport', apiPort) - config.set('bitmessagesettings', 'apiinterface', '127.0.0.1') - config.set('bitmessagesettings', 'apiusername', apiUsr) - config.set('bitmessagesettings', 'apipassword', apiPwd) - config.set('bitmessagesettings', 'daemon', daemon) + 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. + BMConfigParser().set('bitmessagesettings','apienabled','true') + BMConfigParser().set('bitmessagesettings', 'apiport', apiPort) + BMConfigParser().set('bitmessagesettings', 'apiinterface', '127.0.0.1') + BMConfigParser().set('bitmessagesettings', 'apiusername', apiUsr) + BMConfigParser().set('bitmessagesettings', 'apipassword', apiPwd) + BMConfigParser().set('bitmessagesettings', 'daemon', daemon) with open(keysPath, 'wb') as configfile: - config.write(configfile) + BMConfigParser().write(configfile) print '\n Finished configuring the keys.dat file with API information.\n' restartBmNotify() @@ -174,21 +162,19 @@ def apiData(): global keysPath global usrPrompt - config = BMConfigParser() - config.read(keysPath) #First try to load the config file (the keys.dat file) from the program directory + BMConfigParser().read(keysPath) #First try to load the config file (the keys.dat file) from the program directory try: - config.get('bitmessagesettings','port') + BMConfigParser().get('bitmessagesettings','port') appDataFolder = '' except: #Could not load the keys.dat file in the program directory. Perhaps it is in the appdata directory. appDataFolder = lookupAppdataFolder() keysPath = appDataFolder + keysPath - config = BMConfigParser() - config.read(keysPath) + BMConfigParser().read(keysPath) try: - config.get('bitmessagesettings','port') + BMConfigParser().get('bitmessagesettings','port') except: #keys.dat was not there either, something is wrong. print '\n ******************************************************************' @@ -215,21 +201,21 @@ def apiData(): main() try: #checks to make sure that everyting is configured correctly. Excluding apiEnabled, it is checked after - config.get('bitmessagesettings', 'apiport') - config.get('bitmessagesettings', 'apiinterface') - config.get('bitmessagesettings', 'apiusername') - config.get('bitmessagesettings', 'apipassword') + BMConfigParser().get('bitmessagesettings', 'apiport') + BMConfigParser().get('bitmessagesettings', 'apiinterface') + BMConfigParser().get('bitmessagesettings', 'apiusername') + BMConfigParser().get('bitmessagesettings', 'apipassword') except: apiInit("") #Initalize the keys.dat file with API information #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 - apiPort = int(config.get('bitmessagesettings', 'apiport')) - apiInterface = config.get('bitmessagesettings', 'apiinterface') - apiUsername = config.get('bitmessagesettings', 'apiusername') - apiPassword = config.get('bitmessagesettings', 'apipassword') + BMConfigParser().read(keysPath)#read again since changes have been made + apiPort = int(BMConfigParser().get('bitmessagesettings', 'apiport')) + apiInterface = BMConfigParser().get('bitmessagesettings', 'apiinterface') + apiUsername = BMConfigParser().get('bitmessagesettings', 'apiusername') + apiPassword = BMConfigParser().get('bitmessagesettings', 'apipassword') 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. global keysPath global usrPrompt - config = BMConfigParser() keysPath = 'keys.dat' - config.read(keysPath)#Read the keys.dat + BMConfigParser().read(keysPath)#Read the keys.dat try: - port = config.get('bitmessagesettings', 'port') + port = BMConfigParser().get('bitmessagesettings', 'port') except: print '\n File not found.\n' usrPrompt = 0 main() - startonlogon = safeConfigGetBoolean('bitmessagesettings', 'startonlogon') - minimizetotray = safeConfigGetBoolean('bitmessagesettings', 'minimizetotray') - showtraynotifications = safeConfigGetBoolean('bitmessagesettings', 'showtraynotifications') - startintray = safeConfigGetBoolean('bitmessagesettings', 'startintray') - defaultnoncetrialsperbyte = config.get('bitmessagesettings', 'defaultnoncetrialsperbyte') - defaultpayloadlengthextrabytes = config.get('bitmessagesettings', 'defaultpayloadlengthextrabytes') - daemon = safeConfigGetBoolean('bitmessagesettings', 'daemon') + startonlogon = BMConfigParser().safeGetBoolean('bitmessagesettings', 'startonlogon') + minimizetotray = BMConfigParser().safeGetBoolean('bitmessagesettings', 'minimizetotray') + showtraynotifications = BMConfigParser().safeGetBoolean('bitmessagesettings', 'showtraynotifications') + startintray = BMConfigParser().safeGetBoolean('bitmessagesettings', 'startintray') + defaultnoncetrialsperbyte = BMConfigParser().get('bitmessagesettings', 'defaultnoncetrialsperbyte') + defaultpayloadlengthextrabytes = BMConfigParser().get('bitmessagesettings', 'defaultpayloadlengthextrabytes') + daemon = BMConfigParser().safeGetBoolean('bitmessagesettings', 'daemon') - socksproxytype = config.get('bitmessagesettings', 'socksproxytype') - sockshostname = config.get('bitmessagesettings', 'sockshostname') - socksport = config.get('bitmessagesettings', 'socksport') - socksauthentication = safeConfigGetBoolean('bitmessagesettings', 'socksauthentication') - socksusername = config.get('bitmessagesettings', 'socksusername') - sockspassword = config.get('bitmessagesettings', 'sockspassword') + socksproxytype = BMConfigParser().get('bitmessagesettings', 'socksproxytype') + sockshostname = BMConfigParser().get('bitmessagesettings', 'sockshostname') + socksport = BMConfigParser().get('bitmessagesettings', 'socksport') + socksauthentication = BMConfigParser().safeGetBoolean('bitmessagesettings', 'socksauthentication') + socksusername = BMConfigParser().get('bitmessagesettings', 'socksusername') + sockspassword = BMConfigParser().get('bitmessagesettings', 'sockspassword') print '\n -----------------------------------' @@ -313,60 +298,60 @@ def bmSettings(): #Allows the viewing and modification of keys.dat settings. if uInput == "port": print ' Current port number: ' + port uInput = userInput("Enter the new port number.") - config.set('bitmessagesettings', 'port', str(uInput)) + BMConfigParser().set('bitmessagesettings', 'port', str(uInput)) elif uInput == "startonlogon": print ' Current status: ' + str(startonlogon) uInput = userInput("Enter the new status.") - config.set('bitmessagesettings', 'startonlogon', str(uInput)) + BMConfigParser().set('bitmessagesettings', 'startonlogon', str(uInput)) elif uInput == "minimizetotray": print ' Current status: ' + str(minimizetotray) uInput = userInput("Enter the new status.") - config.set('bitmessagesettings', 'minimizetotray', str(uInput)) + BMConfigParser().set('bitmessagesettings', 'minimizetotray', str(uInput)) elif uInput == "showtraynotifications": print ' Current status: ' + str(showtraynotifications) uInput = userInput("Enter the new status.") - config.set('bitmessagesettings', 'showtraynotifications', str(uInput)) + BMConfigParser().set('bitmessagesettings', 'showtraynotifications', str(uInput)) elif uInput == "startintray": print ' Current status: ' + str(startintray) uInput = userInput("Enter the new status.") - config.set('bitmessagesettings', 'startintray', str(uInput)) + BMConfigParser().set('bitmessagesettings', 'startintray', str(uInput)) elif uInput == "defaultnoncetrialsperbyte": print ' Current default nonce trials per byte: ' + defaultnoncetrialsperbyte uInput = userInput("Enter the new defaultnoncetrialsperbyte.") - config.set('bitmessagesettings', 'defaultnoncetrialsperbyte', str(uInput)) + BMConfigParser().set('bitmessagesettings', 'defaultnoncetrialsperbyte', str(uInput)) elif uInput == "defaultpayloadlengthextrabytes": print ' Current default payload length extra bytes: ' + defaultpayloadlengthextrabytes uInput = userInput("Enter the new defaultpayloadlengthextrabytes.") - config.set('bitmessagesettings', 'defaultpayloadlengthextrabytes', str(uInput)) + BMConfigParser().set('bitmessagesettings', 'defaultpayloadlengthextrabytes', str(uInput)) elif uInput == "daemon": print ' Current status: ' + str(daemon) uInput = userInput("Enter the new status.").lower() - config.set('bitmessagesettings', 'daemon', str(uInput)) + BMConfigParser().set('bitmessagesettings', 'daemon', str(uInput)) elif uInput == "socksproxytype": print ' Current socks proxy type: ' + socksproxytype print "Possibilities: 'none', 'SOCKS4a', 'SOCKS5'." uInput = userInput("Enter the new socksproxytype.") - config.set('bitmessagesettings', 'socksproxytype', str(uInput)) + BMConfigParser().set('bitmessagesettings', 'socksproxytype', str(uInput)) elif uInput == "sockshostname": print ' Current socks host name: ' + sockshostname uInput = userInput("Enter the new sockshostname.") - config.set('bitmessagesettings', 'sockshostname', str(uInput)) + BMConfigParser().set('bitmessagesettings', 'sockshostname', str(uInput)) elif uInput == "socksport": print ' Current socks port number: ' + socksport uInput = userInput("Enter the new socksport.") - config.set('bitmessagesettings', 'socksport', str(uInput)) + BMConfigParser().set('bitmessagesettings', 'socksport', str(uInput)) elif uInput == "socksauthentication": print ' Current status: ' + str(socksauthentication) uInput = userInput("Enter the new status.") - config.set('bitmessagesettings', 'socksauthentication', str(uInput)) + BMConfigParser().set('bitmessagesettings', 'socksauthentication', str(uInput)) elif uInput == "socksusername": print ' Current socks username: ' + socksusername uInput = userInput("Enter the new socksusername.") - config.set('bitmessagesettings', 'socksusername', str(uInput)) + BMConfigParser().set('bitmessagesettings', 'socksusername', str(uInput)) elif uInput == "sockspassword": print ' Current socks password: ' + sockspassword uInput = userInput("Enter the new password.") - config.set('bitmessagesettings', 'sockspassword', str(uInput)) + BMConfigParser().set('bitmessagesettings', 'sockspassword', str(uInput)) else: print "\n Invalid input. Please try again.\n" invalidInput = True @@ -377,7 +362,7 @@ def bmSettings(): #Allows the viewing and modification of keys.dat settings. if uInput != "y": print '\n Changes Made.\n' with open(keysPath, 'wb') as configfile: - config.write(configfile) + BMConfigParser().write(configfile) restartBmNotify() break diff --git a/src/bitmessagecurses/__init__.py b/src/bitmessagecurses/__init__.py index 1d667b2b..165873b5 100644 --- a/src/bitmessagecurses/__init__.py +++ b/src/bitmessagecurses/__init__.py @@ -22,7 +22,7 @@ from dialog import Dialog from helper_sql import * import shared -import ConfigParser +from configparser import BMConfigParser from addresses import * from pyelliptic.openssl import OpenSSL import l10n @@ -482,19 +482,19 @@ def handlech(c, stdscr): r, t = d.inputbox("New address label", init=label) if r == d.DIALOG_OK: label = t - shared.config.set(a, "label", label) + BMConfigParser().set(a, "label", label) # Write config shared.writeKeysFile() addresses[addrcur][0] = label elif t == "4": # Enable address a = addresses[addrcur][2] - shared.config.set(a, "enabled", "true") # Set config + BMConfigParser().set(a, "enabled", "true") # Set config # Write config shared.writeKeysFile() # Change color - if shared.safeConfigGetBoolean(a, 'chan'): + if BMConfigParser().safeGetBoolean(a, 'chan'): addresses[addrcur][3] = 9 # orange - elif shared.safeConfigGetBoolean(a, 'mailinglist'): + elif BMConfigParser().safeGetBoolean(a, 'mailinglist'): addresses[addrcur][3] = 5 # magenta else: addresses[addrcur][3] = 0 # black @@ -502,7 +502,7 @@ def handlech(c, stdscr): shared.reloadMyAddressHashes() # Reload address hashes elif t == "5": # Disable address 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 # Write config shared.writeKeysFile() @@ -511,36 +511,36 @@ def handlech(c, stdscr): elif t == "6": # Delete address 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": - shared.config.remove_section(addresses[addrcur][2]) + BMConfigParser().remove_section(addresses[addrcur][2]) shared.writeKeysFile() del addresses[addrcur] elif t == "7": # Special address behavior a = addresses[addrcur][2] 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.")) else: - m = shared.safeConfigGetBoolean(a, "mailinglist") + m = BMConfigParser().safeGetBoolean(a, "mailinglist") r, t = d.radiolist("Select address behavior", choices=[("1", "Behave as a normal address", not m), ("2", "Behave as a pseudo-mailing-list address", m)]) if r == d.DIALOG_OK: if t == "1" and m == True: - shared.config.set(a, "mailinglist", "false") + BMConfigParser().set(a, "mailinglist", "false") if addresses[addrcur][1]: addresses[addrcur][3] = 0 # Set color to black else: addresses[addrcur][3] = 8 # Set color to gray elif t == "2" and m == False: try: - mn = shared.config.get(a, "mailinglistname") + mn = BMConfigParser().get(a, "mailinglistname") except ConfigParser.NoOptionError: mn = "" r, t = d.inputbox("Mailing list name", init=mn) if r == d.DIALOG_OK: mn = t - shared.config.set(a, "mailinglist", "true") - shared.config.set(a, "mailinglistname", mn) + BMConfigParser().set(a, "mailinglist", "true") + BMConfigParser().set(a, "mailinglistname", mn) addresses[addrcur][3] = 6 # Set color to magenta # Write config shared.writeKeysFile() @@ -793,7 +793,7 @@ def sendMessage(sender="", recv="", broadcast=None, subject="", body="", reply=F 0, # retryNumber "sent", 2, # encodingType - shared.config.getint('bitmessagesettings', 'ttl')) + BMConfigParser().getint('bitmessagesettings', 'ttl')) shared.workerQueue.put(("sendmessage", addr)) else: # Broadcast if recv == "": @@ -819,7 +819,7 @@ def sendMessage(sender="", recv="", broadcast=None, subject="", body="", reply=F 0, # retryNumber "sent", # folder 2, # encodingType - shared.config.getint('bitmessagesettings', 'ttl')) + BMConfigParser().getint('bitmessagesettings', 'ttl')) shared.workerQueue.put(('sendbroadcast', '')) def loadInbox(): @@ -843,7 +843,7 @@ def loadInbox(): if toaddr == BROADCAST_STR: tolabel = BROADCAST_STR else: - tolabel = shared.config.get(toaddr, "label") + tolabel = BMConfigParser().get(toaddr, "label") except: tolabel = "" if tolabel == "": @@ -852,8 +852,8 @@ def loadInbox(): # Set label for from address fromlabel = "" - if shared.config.has_section(fromaddr): - fromlabel = shared.config.get(fromaddr, "label") + if BMConfigParser().has_section(fromaddr): + fromlabel = BMConfigParser().get(fromaddr, "label") if fromlabel == "": # Check Address Book qr = sqlQuery("SELECT label FROM addressbook WHERE address=?", fromaddr) if qr != []: @@ -900,15 +900,15 @@ def loadSent(): for r in qr: tolabel, = r if tolabel == "": - if shared.config.has_section(toaddr): - tolabel = shared.config.get(toaddr, "label") + if BMConfigParser().has_section(toaddr): + tolabel = BMConfigParser().get(toaddr, "label") if tolabel == "": tolabel = toaddr # Set label for from address fromlabel = "" - if shared.config.has_section(fromaddr): - fromlabel = shared.config.get(fromaddr, "label") + if BMConfigParser().has_section(fromaddr): + fromlabel = BMConfigParser().get(fromaddr, "label") if fromlabel == "": fromlabel = fromaddr @@ -969,7 +969,7 @@ def loadSubscriptions(): subscriptions.reverse() def loadBlackWhiteList(): global bwtype - bwtype = shared.config.get("bitmessagesettings", "blackwhitelist") + bwtype = BMConfigParser().get("bitmessagesettings", "blackwhitelist") if bwtype == "black": ret = sqlQuery("SELECT label, address, enabled FROM blacklist") else: @@ -1025,17 +1025,17 @@ def run(stdscr): curses.init_pair(9, curses.COLOR_YELLOW, curses.COLOR_BLACK) # orangish # Init list of address in 'Your Identities' tab - configSections = shared.config.sections() + configSections = BMConfigParser().sections() for addressInKeysFile in configSections: if addressInKeysFile != "bitmessagesettings": - isEnabled = shared.config.getboolean(addressInKeysFile, "enabled") - addresses.append([shared.config.get(addressInKeysFile, "label"), isEnabled, addressInKeysFile]) + isEnabled = BMConfigParser().getboolean(addressInKeysFile, "enabled") + addresses.append([BMConfigParser().get(addressInKeysFile, "label"), isEnabled, addressInKeysFile]) # Set address color if not isEnabled: addresses[len(addresses)-1].append(8) # gray - elif shared.safeConfigGetBoolean(addressInKeysFile, 'chan'): + elif BMConfigParser().safeGetBoolean(addressInKeysFile, 'chan'): addresses[len(addresses)-1].append(9) # orange - elif shared.safeConfigGetBoolean(addressInKeysFile, 'mailinglist'): + elif BMConfigParser().safeGetBoolean(addressInKeysFile, 'mailinglist'): addresses[len(addresses)-1].append(5) # magenta else: addresses[len(addresses)-1].append(0) # black diff --git a/src/bitmessagemain.py b/src/bitmessagemain.py index 3b2d1aae..dd71488d 100755 --- a/src/bitmessagemain.py +++ b/src/bitmessagemain.py @@ -40,6 +40,7 @@ from class_singleWorker import singleWorker from class_addressGenerator import addressGenerator from class_smtpDeliver import smtpDeliver from class_smtpServer import smtpServer +from configparser import BMConfigParser from debug import logger # Helper Functions @@ -58,7 +59,7 @@ def connectToStream(streamNumber): maximumNumberOfHalfOpenConnections = 64 try: # don't overload Tor - if shared.config.get('bitmessagesettings', 'socksproxytype') != 'none': + if BMConfigParser().get('bitmessagesettings', 'socksproxytype') != 'none': maximumNumberOfHalfOpenConnections = 4 except: pass @@ -128,7 +129,7 @@ class singleAPI(threading.Thread, StoppableThread): super(singleAPI, self).stopThread() s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) try: - s.connect((shared.config.get('bitmessagesettings', 'apiinterface'), shared.config.getint( + s.connect((BMConfigParser().get('bitmessagesettings', 'apiinterface'), BMConfigParser().getint( 'bitmessagesettings', 'apiport'))) s.shutdown(socket.SHUT_RDWR) s.close() @@ -136,7 +137,7 @@ class singleAPI(threading.Thread, StoppableThread): pass 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) se.register_introspection_functions() se.serve_forever() @@ -188,12 +189,12 @@ class Main: sqlLookup.start() # SMTP delivery thread - if daemon and shared.safeConfigGet("bitmessagesettings", "smtpdeliver", '') != '': + if daemon and BMConfigParser().safeGet("bitmessagesettings", "smtpdeliver", '') != '': smtpDeliveryThread = smtpDeliver() smtpDeliveryThread.start() # SMTP daemon thread - if daemon and shared.safeConfigGetBoolean("bitmessagesettings", "smtpd"): + if daemon and BMConfigParser().safeGetBoolean("bitmessagesettings", "smtpd"): smtpServerThread = smtpServer() smtpServerThread.start() @@ -210,9 +211,9 @@ class Main: shared.reloadMyAddressHashes() shared.reloadBroadcastSendersForWhichImWatching() - if shared.safeConfigGetBoolean('bitmessagesettings', 'apienabled'): + if BMConfigParser().safeGetBoolean('bitmessagesettings', 'apienabled'): try: - apiNotifyPath = shared.config.get( + apiNotifyPath = BMConfigParser().get( 'bitmessagesettings', 'apinotifypath') except: apiNotifyPath = '' @@ -232,12 +233,12 @@ class Main: singleListenerThread.daemon = True # close the main program even if there are threads left singleListenerThread.start() - if shared.safeConfigGetBoolean('bitmessagesettings','upnp'): + if BMConfigParser().safeGetBoolean('bitmessagesettings','upnp'): import upnp upnpThread = upnp.uPnPThread() 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 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') @@ -253,7 +254,7 @@ class Main: import bitmessagecurses bitmessagecurses.runwrapper() else: - shared.config.remove_option('bitmessagesettings', 'dontconnect') + BMConfigParser().remove_option('bitmessagesettings', 'dontconnect') while True: time.sleep(20) @@ -290,15 +291,15 @@ class Main: #TODO: nice function but no one is using this def getApiAddress(self): - if not shared.safeConfigGetBoolean('bitmessagesettings', 'apienabled'): + if not BMConfigParser().safeGetBoolean('bitmessagesettings', 'apienabled'): return None - address = shared.config.get('bitmessagesettings', 'apiinterface') - port = shared.config.getint('bitmessagesettings', 'apiport') + address = BMConfigParser().get('bitmessagesettings', 'apiinterface') + port = BMConfigParser().getint('bitmessagesettings', 'apiport') return {'address':address,'port':port} if __name__ == "__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 diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 4e3366c7..9869d734 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -29,6 +29,7 @@ except AttributeError: from addresses import * import shared from bitmessageui import * +from configparser import BMConfigParser from namecoin import namecoinConnection, ensureNamecoinOptions from newaddressdialog import * from newaddresswizard import * @@ -77,6 +78,7 @@ from class_singleWorker import singleWorker from helper_generic import powQueueSize, invQueueSize from proofofwork import getPowType from statusbar import BMStatusBar +from version import softwareVersion def _translate(context, text, disambiguation = None, encoding = None, number = None): if number is None: @@ -490,11 +492,11 @@ class MyForm(settingsmixin.SMainWindow): enabled = {} for toAddress in getSortedAccounts(): - isEnabled = shared.config.getboolean( + isEnabled = BMConfigParser().getboolean( toAddress, 'enabled') - isChan = shared.safeConfigGetBoolean( + isChan = BMConfigParser().safeGetBoolean( toAddress, 'chan') - isMaillinglist = shared.safeConfigGetBoolean( + isMaillinglist = BMConfigParser().safeGetBoolean( toAddress, 'mailinglist') if treeWidget == self.ui.treeWidgetYourIdentities: @@ -603,7 +605,7 @@ class MyForm(settingsmixin.SMainWindow): reply = QtGui.QMessageBox.question( self, 'Message', displayMsg, QtGui.QMessageBox.Yes, QtGui.QMessageBox.No) if reply == QtGui.QMessageBox.Yes: - shared.config.remove_section(addressInKeysFile) + BMConfigParser().remove_section(addressInKeysFile) shared.writeKeysFile() # Configure Bitmessage to start on startup (or remove the @@ -614,7 +616,7 @@ class MyForm(settingsmixin.SMainWindow): self.settings = QSettings(RUN_PATH, QSettings.NativeFormat) 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. - if shared.config.getboolean('bitmessagesettings', 'startonlogon'): + if BMConfigParser().getboolean('bitmessagesettings', 'startonlogon'): self.settings.setValue("PyBitmessage", sys.argv[0]) elif 'darwin' in sys.platform: # startup for mac @@ -783,7 +785,7 @@ class MyForm(settingsmixin.SMainWindow): self.rerenderComboBoxSendFromBroadcast() # Put the TTL slider in the correct spot - TTL = shared.config.getint('bitmessagesettings', 'ttl') + TTL = BMConfigParser().getint('bitmessagesettings', 'ttl') if TTL < 3600: # an hour TTL = 3600 elif TTL > 28*24*60*60: # 28 days @@ -799,11 +801,11 @@ class MyForm(settingsmixin.SMainWindow): # Check to see whether we can connect to namecoin. Hide the 'Fetch Namecoin ID' button if we can't. try: options = {} - options["type"] = shared.config.get('bitmessagesettings', 'namecoinrpctype') - options["host"] = shared.config.get('bitmessagesettings', 'namecoinrpchost') - options["port"] = shared.config.get('bitmessagesettings', 'namecoinrpcport') - options["user"] = shared.config.get('bitmessagesettings', 'namecoinrpcuser') - options["password"] = shared.config.get('bitmessagesettings', 'namecoinrpcpassword') + options["type"] = BMConfigParser().get('bitmessagesettings', 'namecoinrpctype') + options["host"] = BMConfigParser().get('bitmessagesettings', 'namecoinrpchost') + options["port"] = BMConfigParser().get('bitmessagesettings', 'namecoinrpcport') + options["user"] = BMConfigParser().get('bitmessagesettings', 'namecoinrpcuser') + options["password"] = BMConfigParser().get('bitmessagesettings', 'namecoinrpcpassword') nc = namecoinConnection(options) if nc.test()[0] == 'failed': self.ui.pushButtonFetchNamecoinID.hide() @@ -814,7 +816,7 @@ class MyForm(settingsmixin.SMainWindow): def updateTTL(self, sliderPosition): TTL = int(sliderPosition ** 3.199 + 3600) self.updateHumanFriendlyTTLDescription(TTL) - shared.config.set('bitmessagesettings', 'ttl', str(TTL)) + BMConfigParser().set('bitmessagesettings', 'ttl', str(TTL)) shared.writeKeysFile() def updateHumanFriendlyTTLDescription(self, TTL): @@ -1161,7 +1163,7 @@ class MyForm(settingsmixin.SMainWindow): # show bitmessage self.actionShow = QtGui.QAction(_translate( "MainWindow", "Show Bitmessage"), m, checkable=True) - self.actionShow.setChecked(not shared.config.getboolean( + self.actionShow.setChecked(not BMConfigParser().getboolean( 'bitmessagesettings', 'startintray')) self.actionShow.triggered.connect(self.appIndicatorShowOrHideWindow) if not sys.platform[0:3] == 'win': @@ -1250,7 +1252,7 @@ class MyForm(settingsmixin.SMainWindow): if toAddress == str_broadcast_subscribers: toLabel = str_broadcast_subscribers else: - toLabel = shared.config.get(toAddress, 'label') + toLabel = BMConfigParser().get(toAddress, 'label') except: toLabel = '' if toLabel == '': @@ -1595,7 +1597,7 @@ class MyForm(settingsmixin.SMainWindow): self.connectDialogInstance = connectDialog(self) if self.connectDialogInstance.exec_(): if self.connectDialogInstance.ui.radioButtonConnectNow.isChecked(): - shared.config.remove_option('bitmessagesettings', 'dontconnect') + BMConfigParser().remove_option('bitmessagesettings', 'dontconnect') shared.writeKeysFile() else: self.click_actionSettings() @@ -1619,7 +1621,7 @@ class MyForm(settingsmixin.SMainWindow): self.ui.blackwhitelist.init_blacklist_popup_menu(False) if event.type() == QtCore.QEvent.WindowStateChange: 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) elif event.oldState() & QtCore.Qt.WindowMinimized: # The window state has just been changed to @@ -1644,7 +1646,7 @@ class MyForm(settingsmixin.SMainWindow): QIcon(":/newPrefix/images/redicon.png")) shared.statusIconColor = 'red' # 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( "MainWindow", "Connection lost").toUtf8(),'utf-8'), self.SOUND_DISCONNECTED, None) @@ -1661,7 +1663,7 @@ class MyForm(settingsmixin.SMainWindow): ":/newPrefix/images/yellowicon.png")) shared.statusIconColor = 'yellow' # 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( "MainWindow", "Connected").toUtf8(),'utf-8'), self.SOUND_CONNECTED, None) @@ -1677,7 +1679,7 @@ class MyForm(settingsmixin.SMainWindow): self.pushButtonStatusIcon.setIcon( QIcon(":/newPrefix/images/greenicon.png")) 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( "MainWindow", "Connected").toUtf8(),'utf-8'), self.SOUND_CONNECTION_GREEN, None) @@ -1856,7 +1858,7 @@ class MyForm(settingsmixin.SMainWindow): addresses = getSortedAccounts() for address in addresses: 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] # normal accounts queryreturn = sqlQuery('SELECT * FROM addressbook') @@ -1952,8 +1954,8 @@ class MyForm(settingsmixin.SMainWindow): email = ''.join(random.SystemRandom().choice(string.ascii_lowercase) for _ in range(12)) + "@mailchuck.com" acct = MailchuckAccount(fromAddress) acct.register(email) - shared.config.set(fromAddress, 'label', email) - shared.config.set(fromAddress, 'gateway', 'mailchuck') + BMConfigParser().set(fromAddress, 'label', email) + BMConfigParser().set(fromAddress, 'gateway', 'mailchuck') shared.writeKeysFile() 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) @@ -2027,7 +2029,7 @@ class MyForm(settingsmixin.SMainWindow): 0, # retryNumber 'sent', # folder encoding, # encodingtype - shared.config.getint('bitmessagesettings', 'ttl') + BMConfigParser().getint('bitmessagesettings', 'ttl') ) toLabel = '' @@ -2080,7 +2082,7 @@ class MyForm(settingsmixin.SMainWindow): 0, # retryNumber 'sent', # folder encoding, # encoding type - shared.config.getint('bitmessagesettings', 'ttl') + BMConfigParser().getint('bitmessagesettings', 'ttl') ) sqlExecute( '''INSERT INTO sent VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)''', *t) @@ -2125,7 +2127,7 @@ class MyForm(settingsmixin.SMainWindow): def setBroadcastEnablementDependingOnWhetherThisIsAMailingListAddress(self, address): # If this is a chan then don't let people broadcast because no one # should subscribe to chan addresses. - if shared.safeConfigGetBoolean(str(address), 'mailinglist'): + if BMConfigParser().safeGetBoolean(str(address), 'mailinglist'): self.ui.tabWidgetSend.setCurrentIndex(1) else: self.ui.tabWidgetSend.setCurrentIndex(0) @@ -2133,11 +2135,11 @@ class MyForm(settingsmixin.SMainWindow): def rerenderComboBoxSendFrom(self): self.ui.comboBoxSendFrom.clear() 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. - isMaillinglist = shared.safeConfigGetBoolean(addressInKeysFile, 'mailinglist') + isMaillinglist = BMConfigParser().safeGetBoolean(addressInKeysFile, 'mailinglist') 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 == "": label = addressInKeysFile self.ui.comboBoxSendFrom.addItem(avatarize(addressInKeysFile), label, addressInKeysFile) @@ -2154,11 +2156,11 @@ class MyForm(settingsmixin.SMainWindow): def rerenderComboBoxSendFromBroadcast(self): self.ui.comboBoxSendFromBroadcast.clear() 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. - isChan = shared.safeConfigGetBoolean(addressInKeysFile, 'chan') + isChan = BMConfigParser().safeGetBoolean(addressInKeysFile, 'chan') 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 == "": label = addressInKeysFile self.ui.comboBoxSendFromBroadcast.addItem(avatarize(addressInKeysFile), label, addressInKeysFile) @@ -2221,7 +2223,7 @@ class MyForm(settingsmixin.SMainWindow): else: acct = ret 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) 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 @@ -2235,8 +2237,8 @@ class MyForm(settingsmixin.SMainWindow): email = str(self.dialog.ui.lineEditEmail.text().toUtf8()) # register resets address variables acct.register(email) - shared.config.set(acct.fromAddress, 'label', email) - shared.config.set(acct.fromAddress, 'gateway', 'mailchuck') + BMConfigParser().set(acct.fromAddress, 'label', email) + BMConfigParser().set(acct.fromAddress, 'gateway', 'mailchuck') shared.writeKeysFile() self.statusBar().showMessage(_translate( "MainWindow", "Sending email gateway registration request"), 10000) @@ -2323,113 +2325,113 @@ class MyForm(settingsmixin.SMainWindow): def click_actionSettings(self): self.settingsDialogInstance = settingsDialog(self) if self.settingsDialogInstance.exec_(): - shared.config.set('bitmessagesettings', 'startonlogon', str( + BMConfigParser().set('bitmessagesettings', 'startonlogon', str( self.settingsDialogInstance.ui.checkBoxStartOnLogon.isChecked())) - shared.config.set('bitmessagesettings', 'minimizetotray', str( + BMConfigParser().set('bitmessagesettings', 'minimizetotray', str( self.settingsDialogInstance.ui.checkBoxMinimizeToTray.isChecked())) - shared.config.set('bitmessagesettings', 'trayonclose', str( + BMConfigParser().set('bitmessagesettings', 'trayonclose', str( self.settingsDialogInstance.ui.checkBoxTrayOnClose.isChecked())) - shared.config.set('bitmessagesettings', 'hidetrayconnectionnotifications', str( + BMConfigParser().set('bitmessagesettings', 'hidetrayconnectionnotifications', str( self.settingsDialogInstance.ui.checkBoxHideTrayConnectionNotifications.isChecked())) - shared.config.set('bitmessagesettings', 'showtraynotifications', str( + BMConfigParser().set('bitmessagesettings', 'showtraynotifications', str( self.settingsDialogInstance.ui.checkBoxShowTrayNotifications.isChecked())) - shared.config.set('bitmessagesettings', 'startintray', str( + BMConfigParser().set('bitmessagesettings', 'startintray', str( self.settingsDialogInstance.ui.checkBoxStartInTray.isChecked())) - shared.config.set('bitmessagesettings', 'willinglysendtomobile', str( + BMConfigParser().set('bitmessagesettings', 'willinglysendtomobile', str( self.settingsDialogInstance.ui.checkBoxWillinglySendToMobile.isChecked())) - shared.config.set('bitmessagesettings', 'useidenticons', str( + BMConfigParser().set('bitmessagesettings', 'useidenticons', str( self.settingsDialogInstance.ui.checkBoxUseIdenticons.isChecked())) - shared.config.set('bitmessagesettings', 'replybelow', str( + BMConfigParser().set('bitmessagesettings', 'replybelow', str( self.settingsDialogInstance.ui.checkBoxReplyBelow.isChecked())) 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()) - if int(shared.config.get('bitmessagesettings', 'port')) != int(self.settingsDialogInstance.ui.lineEditTCPPort.text()): - if not shared.safeConfigGetBoolean('bitmessagesettings', 'dontconnect'): + if int(BMConfigParser().get('bitmessagesettings', 'port')) != int(self.settingsDialogInstance.ui.lineEditTCPPort.text()): + if not BMConfigParser().safeGetBoolean('bitmessagesettings', 'dontconnect'): QMessageBox.about(self, _translate("MainWindow", "Restart"), _translate( "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())) - if self.settingsDialogInstance.ui.checkBoxUPnP.isChecked() != shared.safeConfigGetBoolean('bitmessagesettings', 'upnp'): - shared.config.set('bitmessagesettings', 'upnp', str(self.settingsDialogInstance.ui.checkBoxUPnP.isChecked())) + if self.settingsDialogInstance.ui.checkBoxUPnP.isChecked() != BMConfigParser().safeGetBoolean('bitmessagesettings', 'upnp'): + BMConfigParser().set('bitmessagesettings', 'upnp', str(self.settingsDialogInstance.ui.checkBoxUPnP.isChecked())) if self.settingsDialogInstance.ui.checkBoxUPnP.isChecked(): import upnp upnpThread = upnp.uPnPThread() upnpThread.start() #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] - 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': 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).")) - 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() 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())) else: - shared.config.set('bitmessagesettings', 'socksproxytype', 'none') - shared.config.set('bitmessagesettings', 'socksauthentication', str( + BMConfigParser().set('bitmessagesettings', 'socksproxytype', 'none') + BMConfigParser().set('bitmessagesettings', 'socksauthentication', str( self.settingsDialogInstance.ui.checkBoxAuthentication.isChecked())) - shared.config.set('bitmessagesettings', 'sockshostname', str( + BMConfigParser().set('bitmessagesettings', 'sockshostname', str( self.settingsDialogInstance.ui.lineEditSocksHostname.text())) - shared.config.set('bitmessagesettings', 'socksport', str( + BMConfigParser().set('bitmessagesettings', 'socksport', str( self.settingsDialogInstance.ui.lineEditSocksPort.text())) - shared.config.set('bitmessagesettings', 'socksusername', str( + BMConfigParser().set('bitmessagesettings', 'socksusername', str( self.settingsDialogInstance.ui.lineEditSocksUsername.text())) - shared.config.set('bitmessagesettings', 'sockspassword', str( + BMConfigParser().set('bitmessagesettings', 'sockspassword', str( self.settingsDialogInstance.ui.lineEditSocksPassword.text())) - shared.config.set('bitmessagesettings', 'sockslisten', str( + BMConfigParser().set('bitmessagesettings', 'sockslisten', str( self.settingsDialogInstance.ui.checkBoxSocksListen.isChecked())) try: # Rounding to integers just for aesthetics - shared.config.set('bitmessagesettings', 'maxdownloadrate', str( + BMConfigParser().set('bitmessagesettings', 'maxdownloadrate', str( 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())))) except: QMessageBox.about(self, _translate("MainWindow", "Number needed"), _translate( "MainWindow", "Your maximum download and upload rate must be numbers. Ignoring what you typed.")) - shared.config.set('bitmessagesettings', 'namecoinrpctype', + BMConfigParser().set('bitmessagesettings', 'namecoinrpctype', self.settingsDialogInstance.getNamecoinType()) - shared.config.set('bitmessagesettings', 'namecoinrpchost', str( + BMConfigParser().set('bitmessagesettings', 'namecoinrpchost', str( self.settingsDialogInstance.ui.lineEditNamecoinHost.text())) - shared.config.set('bitmessagesettings', 'namecoinrpcport', str( + BMConfigParser().set('bitmessagesettings', 'namecoinrpcport', str( self.settingsDialogInstance.ui.lineEditNamecoinPort.text())) - shared.config.set('bitmessagesettings', 'namecoinrpcuser', str( + BMConfigParser().set('bitmessagesettings', 'namecoinrpcuser', str( self.settingsDialogInstance.ui.lineEditNamecoinUser.text())) - shared.config.set('bitmessagesettings', 'namecoinrpcpassword', str( + BMConfigParser().set('bitmessagesettings', 'namecoinrpcpassword', str( self.settingsDialogInstance.ui.lineEditNamecoinPassword.text())) # Demanded difficulty tab 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))) 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))) - if self.settingsDialogInstance.ui.comboBoxOpenCL.currentText().toUtf8() != shared.safeConfigGet("bitmessagesettings", "opencl"): - shared.config.set('bitmessagesettings', 'opencl', str(self.settingsDialogInstance.ui.comboBoxOpenCL.currentText())) + if self.settingsDialogInstance.ui.comboBoxOpenCL.currentText().toUtf8() != BMConfigParser().safeGet("bitmessagesettings", "opencl"): + BMConfigParser().set('bitmessagesettings', 'opencl', str(self.settingsDialogInstance.ui.comboBoxOpenCL.currentText())) acceptableDifficultyChanged = False 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)): # the user changed the max acceptable total difficulty acceptableDifficultyChanged = True - shared.config.set('bitmessagesettings', 'maxacceptablenoncetrialsperbyte', str(int(float( + BMConfigParser().set('bitmessagesettings', 'maxacceptablenoncetrialsperbyte', str(int(float( self.settingsDialogInstance.ui.lineEditMaxAcceptableTotalDifficulty.text()) * shared.networkDefaultProofOfWorkNonceTrialsPerByte))) 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)): # the user changed the max acceptable small message difficulty acceptableDifficultyChanged = True - shared.config.set('bitmessagesettings', 'maxacceptablepayloadlengthextrabytes', str(int(float( + BMConfigParser().set('bitmessagesettings', 'maxacceptablepayloadlengthextrabytes', str(int(float( self.settingsDialogInstance.ui.lineEditMaxAcceptableSmallMessageDifficulty.text()) * shared.networkDefaultPayloadLengthExtraBytes))) if acceptableDifficultyChanged: # It might now be possible to send msgs which were previously marked as toodifficult. @@ -2442,8 +2444,8 @@ class MyForm(settingsmixin.SMainWindow): #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. 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', '') - shared.config.set('bitmessagesettings', 'stopresendingafterxmonths', '') + BMConfigParser().set('bitmessagesettings', 'stopresendingafterxdays', '') + BMConfigParser().set('bitmessagesettings', 'stopresendingafterxmonths', '') shared.maximumLengthOfTimeToBotherResendingMessages = float('inf') try: float(self.settingsDialogInstance.ui.lineEditDays.text()) @@ -2465,13 +2467,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. 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.")) - shared.config.set('bitmessagesettings', 'stopresendingafterxdays', '0') - shared.config.set('bitmessagesettings', 'stopresendingafterxmonths', '0') + BMConfigParser().set('bitmessagesettings', 'stopresendingafterxdays', '0') + BMConfigParser().set('bitmessagesettings', 'stopresendingafterxmonths', '0') shared.maximumLengthOfTimeToBotherResendingMessages = 0 else: - shared.config.set('bitmessagesettings', 'stopresendingafterxdays', str(float( + BMConfigParser().set('bitmessagesettings', 'stopresendingafterxdays', str(float( self.settingsDialogInstance.ui.lineEditDays.text()))) - shared.config.set('bitmessagesettings', 'stopresendingafterxmonths', str(float( + BMConfigParser().set('bitmessagesettings', 'stopresendingafterxmonths', str(float( self.settingsDialogInstance.ui.lineEditMonths.text()))) shared.writeKeysFile() @@ -2480,7 +2482,7 @@ class MyForm(settingsmixin.SMainWindow): # Auto-startup for Windows RUN_PATH = "HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Run" 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]) else: self.settings.remove("PyBitmessage") @@ -2495,7 +2497,7 @@ class MyForm(settingsmixin.SMainWindow): # Write the keys.dat file to disk in the new location sqlStoredProcedure('movemessagstoprog') with open(shared.lookupExeFolder() + 'keys.dat', 'wb') as configfile: - shared.config.write(configfile) + BMConfigParser().write(configfile) # Write the knownnodes.dat file to disk in the new location shared.knownNodesLock.acquire() output = open(shared.lookupExeFolder() + 'knownnodes.dat', 'wb') @@ -2540,21 +2542,21 @@ class MyForm(settingsmixin.SMainWindow): # For Modal dialogs if self.dialog.exec_(): addressAtCurrentRow = self.getCurrentAccount() - if shared.safeConfigGetBoolean(addressAtCurrentRow, 'chan'): + if BMConfigParser().safeGetBoolean(addressAtCurrentRow, 'chan'): return if self.dialog.ui.radioButtonBehaveNormalAddress.isChecked(): - shared.config.set(str( + BMConfigParser().set(str( addressAtCurrentRow), 'mailinglist', 'false') # Set the color to either black or grey - if shared.config.getboolean(addressAtCurrentRow, 'enabled'): + if BMConfigParser().getboolean(addressAtCurrentRow, 'enabled'): self.setCurrentItemColor(QApplication.palette() .text().color()) else: self.setCurrentItemColor(QtGui.QColor(128, 128, 128)) else: - shared.config.set(str( + BMConfigParser().set(str( addressAtCurrentRow), 'mailinglist', 'true') - shared.config.set(str(addressAtCurrentRow), 'mailinglistname', str( + BMConfigParser().set(str(addressAtCurrentRow), 'mailinglistname', str( self.dialog.ui.lineEditMailingListName.text().toUtf8())) self.setCurrentItemColor(QtGui.QColor(137, 04, 177)) #magenta self.rerenderComboBoxSendFrom() @@ -2573,7 +2575,7 @@ class MyForm(settingsmixin.SMainWindow): return if self.dialog.ui.radioButtonUnregister.isChecked() and isinstance(acct, GatewayAccount): acct.unregister() - shared.config.remove_option(addressAtCurrentRow, 'gateway') + BMConfigParser().remove_option(addressAtCurrentRow, 'gateway') shared.writeKeysFile() self.statusBar().showMessage(_translate( "MainWindow", "Sending email gateway unregistration request"), 10000) @@ -2599,8 +2601,8 @@ class MyForm(settingsmixin.SMainWindow): email = str(self.dialog.ui.lineEditEmail.text().toUtf8()) acct = MailchuckAccount(addressAtCurrentRow) acct.register(email) - shared.config.set(addressAtCurrentRow, 'label', email) - shared.config.set(addressAtCurrentRow, 'gateway', 'mailchuck') + BMConfigParser().set(addressAtCurrentRow, 'label', email) + BMConfigParser().set(addressAtCurrentRow, 'gateway', 'mailchuck') shared.writeKeysFile() self.statusBar().showMessage(_translate( "MainWindow", "Sending email gateway registration request"), 10000) @@ -2818,7 +2820,7 @@ class MyForm(settingsmixin.SMainWindow): trayonclose = False try: - trayonclose = shared.config.getboolean( + trayonclose = BMConfigParser().getboolean( 'bitmessagesettings', 'trayonclose') except Exception: pass @@ -2893,7 +2895,7 @@ class MyForm(settingsmixin.SMainWindow): # Format predefined text on message reply. def quoted_text(self, message): - if not shared.safeConfigGetBoolean('bitmessagesettings', 'replybelow'): + if not BMConfigParser().safeGetBoolean('bitmessagesettings', 'replybelow'): return '\n\n------------------------------------------------------\n' + message quoteWrapper = textwrap.TextWrapper(replace_whitespace = False, @@ -2964,10 +2966,10 @@ class MyForm(settingsmixin.SMainWindow): if toAddressAtCurrentInboxRow == str_broadcast_subscribers: self.ui.tabWidgetSend.setCurrentIndex(0) # 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( "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( "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: @@ -3041,7 +3043,7 @@ class MyForm(settingsmixin.SMainWindow): queryreturn = sqlQuery('''select * from blacklist where address=?''', addressAtCurrentInboxRow) 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 (?,?, ?)''', label, addressAtCurrentInboxRow, True) @@ -3533,7 +3535,7 @@ class MyForm(settingsmixin.SMainWindow): return # maybe in the future 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: - shared.config.remove_section(str(account.address)) + BMConfigParser().remove_section(str(account.address)) else: return else: @@ -3553,7 +3555,7 @@ class MyForm(settingsmixin.SMainWindow): account.setEnabled(True) def enableIdentity(self, address): - shared.config.set(address, 'enabled', 'true') + BMConfigParser().set(address, 'enabled', 'true') shared.writeKeysFile() shared.reloadMyAddressHashes() self.rerenderAddressBook() @@ -3565,7 +3567,7 @@ class MyForm(settingsmixin.SMainWindow): account.setEnabled(False) def disableIdentity(self, address): - shared.config.set(str(address), 'enabled', 'false') + BMConfigParser().set(str(address), 'enabled', 'false') shared.writeKeysFile() shared.reloadMyAddressHashes() self.rerenderAddressBook() @@ -3981,7 +3983,7 @@ class aboutDialog(QtGui.QDialog): self.ui = Ui_aboutDialog() self.ui.setupUi(self) self.parent = parent - self.ui.labelVersion.setText('version ' + shared.softwareVersion) + self.ui.labelVersion.setText('version ' + softwareVersion) class regenerateAddressesDialog(QtGui.QDialog): @@ -4001,23 +4003,23 @@ class settingsDialog(QtGui.QDialog): self.ui.setupUi(self) self.parent = parent self.ui.checkBoxStartOnLogon.setChecked( - shared.config.getboolean('bitmessagesettings', 'startonlogon')) + BMConfigParser().getboolean('bitmessagesettings', 'startonlogon')) self.ui.checkBoxMinimizeToTray.setChecked( - shared.config.getboolean('bitmessagesettings', 'minimizetotray')) + BMConfigParser().getboolean('bitmessagesettings', 'minimizetotray')) self.ui.checkBoxTrayOnClose.setChecked( - shared.safeConfigGetBoolean('bitmessagesettings', 'trayonclose')) + BMConfigParser().safeGetBoolean('bitmessagesettings', 'trayonclose')) self.ui.checkBoxHideTrayConnectionNotifications.setChecked( - shared.config.getboolean("bitmessagesettings", "hidetrayconnectionnotifications")) + BMConfigParser().getboolean("bitmessagesettings", "hidetrayconnectionnotifications")) self.ui.checkBoxShowTrayNotifications.setChecked( - shared.config.getboolean('bitmessagesettings', 'showtraynotifications')) + BMConfigParser().getboolean('bitmessagesettings', 'showtraynotifications')) self.ui.checkBoxStartInTray.setChecked( - shared.config.getboolean('bitmessagesettings', 'startintray')) + BMConfigParser().getboolean('bitmessagesettings', 'startintray')) self.ui.checkBoxWillinglySendToMobile.setChecked( - shared.safeConfigGetBoolean('bitmessagesettings', 'willinglysendtomobile')) + BMConfigParser().safeGetBoolean('bitmessagesettings', 'willinglysendtomobile')) self.ui.checkBoxUseIdenticons.setChecked( - shared.safeConfigGetBoolean('bitmessagesettings', 'useidenticons')) + BMConfigParser().safeGetBoolean('bitmessagesettings', 'useidenticons')) self.ui.checkBoxReplyBelow.setChecked( - shared.safeConfigGetBoolean('bitmessagesettings', 'replybelow')) + BMConfigParser().safeGetBoolean('bitmessagesettings', 'replybelow')) if shared.appdata == shared.lookupExeFolder(): self.ui.checkBoxPortableMode.setChecked(True) @@ -4045,14 +4047,14 @@ class settingsDialog(QtGui.QDialog): "MainWindow", "Start-on-login not yet supported on your OS.")) # On the Network settings tab: self.ui.lineEditTCPPort.setText(str( - shared.config.get('bitmessagesettings', 'port'))) + BMConfigParser().get('bitmessagesettings', 'port'))) self.ui.checkBoxUPnP.setChecked( - shared.safeConfigGetBoolean('bitmessagesettings', 'upnp')) - self.ui.checkBoxAuthentication.setChecked(shared.config.getboolean( + BMConfigParser().safeGetBoolean('bitmessagesettings', 'upnp')) + self.ui.checkBoxAuthentication.setChecked(BMConfigParser().getboolean( 'bitmessagesettings', 'socksauthentication')) - self.ui.checkBoxSocksListen.setChecked(shared.config.getboolean( + self.ui.checkBoxSocksListen.setChecked(BMConfigParser().getboolean( 'bitmessagesettings', 'sockslisten')) - if str(shared.config.get('bitmessagesettings', 'socksproxytype')) == 'none': + if str(BMConfigParser().get('bitmessagesettings', 'socksproxytype')) == 'none': self.ui.comboBoxProxyType.setCurrentIndex(0) self.ui.lineEditSocksHostname.setEnabled(False) self.ui.lineEditSocksPort.setEnabled(False) @@ -4060,38 +4062,38 @@ class settingsDialog(QtGui.QDialog): self.ui.lineEditSocksPassword.setEnabled(False) self.ui.checkBoxAuthentication.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.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.lineEditTCPPort.setEnabled(False) self.ui.lineEditSocksHostname.setText(str( - shared.config.get('bitmessagesettings', 'sockshostname'))) + BMConfigParser().get('bitmessagesettings', 'sockshostname'))) self.ui.lineEditSocksPort.setText(str( - shared.config.get('bitmessagesettings', 'socksport'))) + BMConfigParser().get('bitmessagesettings', 'socksport'))) self.ui.lineEditSocksUsername.setText(str( - shared.config.get('bitmessagesettings', 'socksusername'))) + BMConfigParser().get('bitmessagesettings', 'socksusername'))) self.ui.lineEditSocksPassword.setText(str( - shared.config.get('bitmessagesettings', 'sockspassword'))) + BMConfigParser().get('bitmessagesettings', 'sockspassword'))) QtCore.QObject.connect(self.ui.comboBoxProxyType, QtCore.SIGNAL( "currentIndexChanged(int)"), self.comboBoxProxyTypeChanged) self.ui.lineEditMaxDownloadRate.setText(str( - shared.config.get('bitmessagesettings', 'maxdownloadrate'))) + BMConfigParser().get('bitmessagesettings', 'maxdownloadrate'))) self.ui.lineEditMaxUploadRate.setText(str( - shared.config.get('bitmessagesettings', 'maxuploadrate'))) + BMConfigParser().get('bitmessagesettings', 'maxuploadrate'))) # Demanded difficulty tab - self.ui.lineEditTotalDifficulty.setText(str((float(shared.config.getint( + self.ui.lineEditTotalDifficulty.setText(str((float(BMConfigParser().getint( 'bitmessagesettings', 'defaultnoncetrialsperbyte')) / shared.networkDefaultProofOfWorkNonceTrialsPerByte))) - self.ui.lineEditSmallMessageDifficulty.setText(str((float(shared.config.getint( + self.ui.lineEditSmallMessageDifficulty.setText(str((float(BMConfigParser().getint( 'bitmessagesettings', 'defaultpayloadlengthextrabytes')) / shared.networkDefaultPayloadLengthExtraBytes))) # 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))) - self.ui.lineEditMaxAcceptableSmallMessageDifficulty.setText(str((float(shared.config.getint( + self.ui.lineEditMaxAcceptableSmallMessageDifficulty.setText(str((float(BMConfigParser().getint( 'bitmessagesettings', 'maxacceptablepayloadlengthextrabytes')) / shared.networkDefaultPayloadLengthExtraBytes))) # OpenCL @@ -4104,20 +4106,20 @@ class settingsDialog(QtGui.QDialog): self.ui.comboBoxOpenCL.addItems(openclpow.vendors) self.ui.comboBoxOpenCL.setCurrentIndex(0) 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) break # Namecoin integration tab - nmctype = shared.config.get('bitmessagesettings', 'namecoinrpctype') + nmctype = BMConfigParser().get('bitmessagesettings', 'namecoinrpctype') self.ui.lineEditNamecoinHost.setText(str( - shared.config.get('bitmessagesettings', 'namecoinrpchost'))) + BMConfigParser().get('bitmessagesettings', 'namecoinrpchost'))) self.ui.lineEditNamecoinPort.setText(str( - shared.config.get('bitmessagesettings', 'namecoinrpcport'))) + BMConfigParser().get('bitmessagesettings', 'namecoinrpcport'))) self.ui.lineEditNamecoinUser.setText(str( - shared.config.get('bitmessagesettings', 'namecoinrpcuser'))) + BMConfigParser().get('bitmessagesettings', 'namecoinrpcuser'))) self.ui.lineEditNamecoinPassword.setText(str( - shared.config.get('bitmessagesettings', 'namecoinrpcpassword'))) + BMConfigParser().get('bitmessagesettings', 'namecoinrpcpassword'))) if nmctype == "namecoind": self.ui.radioButtonNamecoinNamecoind.setChecked(True) @@ -4139,14 +4141,14 @@ class settingsDialog(QtGui.QDialog): #Message Resend tab self.ui.lineEditDays.setText(str( - shared.config.get('bitmessagesettings', 'stopresendingafterxdays'))) + BMConfigParser().get('bitmessagesettings', 'stopresendingafterxdays'))) self.ui.lineEditMonths.setText(str( - shared.config.get('bitmessagesettings', 'stopresendingafterxmonths'))) + BMConfigParser().get('bitmessagesettings', 'stopresendingafterxmonths'))) #'System' tab removed for now. """try: - maxCores = shared.config.getint('bitmessagesettings', 'maxcores') + maxCores = BMConfigParser().getint('bitmessagesettings', 'maxcores') except: maxCores = 99999 if maxCores <= 1: @@ -4235,13 +4237,13 @@ class SpecialAddressBehaviorDialog(QtGui.QDialog): self.ui.setupUi(self) self.parent = parent addressAtCurrentRow = parent.getCurrentAccount() - if not shared.safeConfigGetBoolean(addressAtCurrentRow, 'chan'): - if shared.safeConfigGetBoolean(addressAtCurrentRow, 'mailinglist'): + if not BMConfigParser().safeGetBoolean(addressAtCurrentRow, 'chan'): + if BMConfigParser().safeGetBoolean(addressAtCurrentRow, 'mailinglist'): self.ui.radioButtonBehaviorMailingList.click() else: self.ui.radioButtonBehaveNormalAddress.click() try: - mailingListName = shared.config.get( + mailingListName = BMConfigParser().get( addressAtCurrentRow, 'mailinglistname') except: mailingListName = '' @@ -4272,7 +4274,7 @@ class EmailGatewayDialog(QtGui.QDialog): self.ui.radioButtonStatus.setEnabled(False) self.ui.radioButtonSettings.setEnabled(False) self.ui.radioButtonUnregister.setEnabled(False) - label = shared.config.get(addressAtCurrentRow, 'label') + label = BMConfigParser().get(addressAtCurrentRow, 'label') if label.find("@mailchuck.com") > -1: self.ui.lineEditEmail.setText(label) @@ -4377,7 +4379,7 @@ class iconGlossaryDialog(QtGui.QDialog): self.ui.setupUi(self) self.parent = parent 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)) @@ -4462,17 +4464,17 @@ def run(): myapp.appIndicatorInit(app) myapp.ubuntuMessagingMenuInit() myapp.notifierInit() - if shared.safeConfigGetBoolean('bitmessagesettings', 'dontconnect'): + if BMConfigParser().safeGetBoolean('bitmessagesettings', 'dontconnect'): myapp.showConnectDialog() # ask the user if we may connect # try: -# if shared.config.get('bitmessagesettings', 'mailchuck') < 1: -# myapp.showMigrationWizard(shared.config.get('bitmessagesettings', 'mailchuck')) +# if BMConfigParser().get('bitmessagesettings', 'mailchuck') < 1: +# myapp.showMigrationWizard(BMConfigParser().get('bitmessagesettings', 'mailchuck')) # except: # myapp.showMigrationWizard(0) # only show after wizards and connect dialogs have completed - if not shared.config.getboolean('bitmessagesettings', 'startintray'): + if not BMConfigParser().getboolean('bitmessagesettings', 'startintray'): myapp.show() sys.exit(app.exec_()) diff --git a/src/bitmessageqt/account.py b/src/bitmessageqt/account.py index dc6bf6b8..6e830b38 100644 --- a/src/bitmessageqt/account.py +++ b/src/bitmessageqt/account.py @@ -6,15 +6,16 @@ import sys import inspect from helper_sql import * from addresses import decodeAddress +from configparser import BMConfigParser from foldertree import AccountMixin from pyelliptic.openssl import OpenSSL from utils import str_broadcast_subscribers import time def getSortedAccounts(): - configSections = filter(lambda x: x != 'bitmessagesettings', shared.config.sections()) + configSections = filter(lambda x: x != 'bitmessagesettings', BMConfigParser().sections()) 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 @@ -44,7 +45,7 @@ def getSortedSubscriptions(count = False): return ret def accountClass(address): - if not shared.config.has_section(address): + if not BMConfigParser().has_section(address): # FIXME: This BROADCAST section makes no sense if address == str_broadcast_subscribers: subscription = BroadcastAccount(address) @@ -56,7 +57,7 @@ def accountClass(address): return None return subscription try: - gateway = shared.config.get(address, "gateway") + gateway = BMConfigParser().get(address, "gateway") for name, cls in inspect.getmembers(sys.modules[__name__], inspect.isclass): # obj = g(address) if issubclass(cls, GatewayAccount) and cls.gatewayName == gateway: @@ -75,9 +76,9 @@ class AccountColor(AccountMixin): if type is None: if address is None: self.type = AccountMixin.ALL - elif shared.safeConfigGetBoolean(self.address, 'mailinglist'): + elif BMConfigParser().safeGetBoolean(self.address, 'mailinglist'): self.type = AccountMixin.MAILINGLIST - elif shared.safeConfigGetBoolean(self.address, 'chan'): + elif BMConfigParser().safeGetBoolean(self.address, 'chan'): self.type = AccountMixin.CHAN elif sqlQuery( '''select label from subscriptions where address=?''', self.address): @@ -92,10 +93,10 @@ class BMAccount(object): def __init__(self, address = None): self.address = address self.type = AccountMixin.NORMAL - if shared.config.has_section(address): - if shared.safeConfigGetBoolean(self.address, 'chan'): + if BMConfigParser().has_section(address): + if BMConfigParser().safeGetBoolean(self.address, 'chan'): self.type = AccountMixin.CHAN - elif shared.safeConfigGetBoolean(self.address, 'mailinglist'): + elif BMConfigParser().safeGetBoolean(self.address, 'mailinglist'): self.type = AccountMixin.MAILINGLIST elif self.address == str_broadcast_subscribers: self.type = AccountMixin.BROADCAST @@ -109,8 +110,8 @@ class BMAccount(object): if address is None: address = self.address label = address - if shared.config.has_section(address): - label = shared.config.get(address, 'label') + if BMConfigParser().has_section(address): + label = BMConfigParser().get(address, 'label') queryreturn = sqlQuery( '''select label from addressbook where address=?''', address) if queryreturn != []: @@ -168,7 +169,7 @@ class GatewayAccount(BMAccount): 0, # retryNumber 'sent', # folder 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)) diff --git a/src/bitmessageqt/bitmessageui.py b/src/bitmessageqt/bitmessageui.py index b1587335..e480258c 100644 --- a/src/bitmessageqt/bitmessageui.py +++ b/src/bitmessageqt/bitmessageui.py @@ -8,6 +8,7 @@ # WARNING! All changes made in this file will be lost! from PyQt4 import QtCore, QtGui +from configparser import BMConfigParser from foldertree import AddressBookCompleter from messageview import MessageView from messagecompose import MessageCompose @@ -556,7 +557,7 @@ class Ui_MainWindow(object): self.blackwhitelist = Blacklist() self.tabWidget.addTab(self.blackwhitelist, QtGui.QIcon(":/newPrefix/images/blacklist.png"), "") # Initialize the Blacklist or Whitelist - if shared.config.get('bitmessagesettings', 'blackwhitelist') == 'white': + if BMConfigParser().get('bitmessagesettings', 'blackwhitelist') == 'white': self.blackwhitelist.radioButtonWhitelist.click() self.blackwhitelist.rerenderBlackWhiteList() @@ -680,7 +681,7 @@ class Ui_MainWindow(object): self.pushButtonTTL.setText(_translate("MainWindow", "TTL:", None)) hours = 48 try: - hours = int(shared.config.getint('bitmessagesettings', 'ttl')/60/60) + hours = int(BMConfigParser().getint('bitmessagesettings', 'ttl')/60/60) except: pass self.labelHumanFriendlyTTLDescription.setText(_translate("MainWindow", "%n hour(s)", None, QtCore.QCoreApplication.CodecForTr, hours)) diff --git a/src/bitmessageqt/blacklist.py b/src/bitmessageqt/blacklist.py index 1e4be35a..6fcb8f11 100644 --- a/src/bitmessageqt/blacklist.py +++ b/src/bitmessageqt/blacklist.py @@ -5,6 +5,7 @@ import l10n from uisignaler import UISignaler import widgets from addresses import addBMIfNotPresent +from configparser import BMConfigParser from dialogs import AddAddressDialog from helper_sql import sqlExecute, sqlQuery from retranslateui import RetranslateMixin @@ -39,16 +40,16 @@ class Blacklist(QtGui.QWidget, RetranslateMixin): "rerenderBlackWhiteList()"), self.rerenderBlackWhiteList) def click_radioButtonBlacklist(self): - if shared.config.get('bitmessagesettings', 'blackwhitelist') == 'white': - shared.config.set('bitmessagesettings', 'blackwhitelist', 'black') + if BMConfigParser().get('bitmessagesettings', 'blackwhitelist') == 'white': + BMConfigParser().set('bitmessagesettings', 'blackwhitelist', 'black') shared.writeKeysFile() # self.tableWidgetBlacklist.clearContents() self.tableWidgetBlacklist.setRowCount(0) self.rerenderBlackWhiteList() def click_radioButtonWhitelist(self): - if shared.config.get('bitmessagesettings', 'blackwhitelist') == 'black': - shared.config.set('bitmessagesettings', 'blackwhitelist', 'white') + if BMConfigParser().get('bitmessagesettings', 'blackwhitelist') == 'black': + BMConfigParser().set('bitmessagesettings', 'blackwhitelist', 'white') shared.writeKeysFile() # self.tableWidgetBlacklist.clearContents() self.tableWidgetBlacklist.setRowCount(0) @@ -64,7 +65,7 @@ class Blacklist(QtGui.QWidget, RetranslateMixin): # address book. The user cannot add it again or else it will # cause problems when updating and deleting the entry. t = (address,) - if shared.config.get('bitmessagesettings', 'blackwhitelist') == 'black': + if BMConfigParser().get('bitmessagesettings', 'blackwhitelist') == 'black': sql = '''select * from blacklist where address=?''' else: sql = '''select * from whitelist where address=?''' @@ -82,7 +83,7 @@ class Blacklist(QtGui.QWidget, RetranslateMixin): self.tableWidgetBlacklist.setItem(0, 1, newItem) self.tableWidgetBlacklist.setSortingEnabled(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 (?,?,?)''' else: sql = '''INSERT INTO whitelist VALUES (?,?,?)''' @@ -147,12 +148,12 @@ class Blacklist(QtGui.QWidget, RetranslateMixin): def rerenderBlackWhiteList(self): 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')) else: tabs.setTabText(tabs.indexOf(self), _translate('blacklist', 'Whitelist')) self.tableWidgetBlacklist.setRowCount(0) - listType = shared.config.get('bitmessagesettings', 'blackwhitelist') + listType = BMConfigParser().get('bitmessagesettings', 'blackwhitelist') if listType == 'black': queryreturn = sqlQuery('''SELECT label, address, enabled FROM blacklist''') else: @@ -184,7 +185,7 @@ class Blacklist(QtGui.QWidget, RetranslateMixin): currentRow, 0).text().toUtf8() addressAtCurrentRow = self.tableWidgetBlacklist.item( currentRow, 1).text() - if shared.config.get('bitmessagesettings', 'blackwhitelist') == 'black': + if BMConfigParser().get('bitmessagesettings', 'blackwhitelist') == 'black': sqlExecute( '''DELETE FROM blacklist WHERE label=? AND address=?''', str(labelAtCurrentRow), str(addressAtCurrentRow)) @@ -213,7 +214,7 @@ class Blacklist(QtGui.QWidget, RetranslateMixin): currentRow, 0).setTextColor(QtGui.QApplication.palette().text().color()) self.tableWidgetBlacklist.item( currentRow, 1).setTextColor(QtGui.QApplication.palette().text().color()) - if shared.config.get('bitmessagesettings', 'blackwhitelist') == 'black': + if BMConfigParser().get('bitmessagesettings', 'blackwhitelist') == 'black': sqlExecute( '''UPDATE blacklist SET enabled=1 WHERE address=?''', str(addressAtCurrentRow)) @@ -230,7 +231,7 @@ class Blacklist(QtGui.QWidget, RetranslateMixin): currentRow, 0).setTextColor(QtGui.QColor(128, 128, 128)) self.tableWidgetBlacklist.item( currentRow, 1).setTextColor(QtGui.QColor(128, 128, 128)) - if shared.config.get('bitmessagesettings', 'blackwhitelist') == 'black': + if BMConfigParser().get('bitmessagesettings', 'blackwhitelist') == 'black': sqlExecute( '''UPDATE blacklist SET enabled=0 WHERE address=?''', str(addressAtCurrentRow)) else: diff --git a/src/bitmessageqt/foldertree.py b/src/bitmessageqt/foldertree.py index 1204b7ca..8b0e519b 100644 --- a/src/bitmessageqt/foldertree.py +++ b/src/bitmessageqt/foldertree.py @@ -1,6 +1,7 @@ from PyQt4 import QtCore, QtGui from string import find, rfind, rstrip, lstrip +from configparser import BMConfigParser from helper_sql import * from utils import * import shared @@ -69,9 +70,9 @@ class AccountMixin (object): if self.address is None: self.type = self.ALL self.setFlags(self.flags() & ~QtCore.Qt.ItemIsEditable) - elif shared.safeConfigGetBoolean(self.address, 'chan'): + elif BMConfigParser().safeGetBoolean(self.address, 'chan'): self.type = self.CHAN - elif shared.safeConfigGetBoolean(self.address, 'mailinglist'): + elif BMConfigParser().safeGetBoolean(self.address, 'mailinglist'): self.type = self.MAILINGLIST elif sqlQuery( '''select label from subscriptions where address=?''', self.address): @@ -84,7 +85,7 @@ class AccountMixin (object): retval = None if self.type in (AccountMixin.NORMAL, AccountMixin.CHAN, AccountMixin.MAILINGLIST): try: - retval = unicode(shared.config.get(self.address, 'label'), 'utf-8') + retval = unicode(BMConfigParser().get(self.address, 'label'), 'utf-8') except Exception as e: queryreturn = sqlQuery( '''select label from addressbook where address=?''', self.address) @@ -161,7 +162,7 @@ class Ui_AddressWidget(QtGui.QTreeWidgetItem, AccountMixin, SettingsMixin): super(QtGui.QTreeWidgetItem, self).__init__() parent.insertTopLevelItem(pos, self) # 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.setEnabled(enabled) 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') else: try: - return unicode(shared.config.get(self.address, 'label'), 'utf-8', 'ignore') + return unicode(BMConfigParser().get(self.address, 'label'), 'utf-8', 'ignore') except: return unicode(self.address, 'utf-8') @@ -211,9 +212,9 @@ class Ui_AddressWidget(QtGui.QTreeWidgetItem, AccountMixin, SettingsMixin): def setData(self, column, role, value): if role == QtCore.Qt.EditRole and self.type != AccountMixin.SUBSCRIPTION: 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: - shared.config.set(str(self.address), 'label', str(value)) + BMConfigParser().set(str(self.address), 'label', str(value)) shared.writeKeysFile() return super(Ui_AddressWidget, self).setData(column, role, value) @@ -250,7 +251,7 @@ class Ui_SubscriptionWidget(Ui_AddressWidget, AccountMixin): super(QtGui.QTreeWidgetItem, self).__init__() parent.insertTopLevelItem(pos, self) # 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.setEnabled(enabled) self.setType() @@ -287,7 +288,7 @@ class MessageList_AddressWidget(QtGui.QTableWidgetItem, AccountMixin, SettingsMi super(QtGui.QTableWidgetItem, self).__init__() #parent.insertTopLevelItem(pos, self) # 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.setAddress(address) self.setLabel(label) @@ -302,7 +303,7 @@ class MessageList_AddressWidget(QtGui.QTableWidgetItem, AccountMixin, SettingsMi queryreturn = None if self.type in (AccountMixin.NORMAL, AccountMixin.CHAN, AccountMixin.MAILINGLIST): try: - newLabel = unicode(shared.config.get(self.address, 'label'), 'utf-8', 'ignore') + newLabel = unicode(BMConfigParser().get(self.address, 'label'), 'utf-8', 'ignore') except: queryreturn = sqlQuery( '''select label from addressbook where address=?''', self.address) @@ -330,7 +331,7 @@ class MessageList_AddressWidget(QtGui.QTableWidgetItem, AccountMixin, SettingsMi elif role == QtCore.Qt.ToolTipRole: return self.label + " (" + self.address + ")" elif role == QtCore.Qt.DecorationRole: - if shared.safeConfigGetBoolean('bitmessagesettings', 'useidenticons'): + if BMConfigParser().safeGetBoolean('bitmessagesettings', 'useidenticons'): if self.address is None: return avatarize(self.label) else: @@ -362,7 +363,7 @@ class MessageList_SubjectWidget(QtGui.QTableWidgetItem, SettingsMixin): super(QtGui.QTableWidgetItem, self).__init__() #parent.insertTopLevelItem(pos, self) # 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.setLabel(label) self.setUnread(unread) @@ -418,7 +419,7 @@ class Ui_AddressBookWidgetItem(QtGui.QTableWidgetItem, AccountMixin): elif role == QtCore.Qt.ToolTipRole: return self.label + " (" + self.address + ")" elif role == QtCore.Qt.DecorationRole: - if shared.safeConfigGetBoolean('bitmessagesettings', 'useidenticons'): + if BMConfigParser().safeGetBoolean('bitmessagesettings', 'useidenticons'): if self.address is None: return avatarize(self.label) else: @@ -440,8 +441,8 @@ class Ui_AddressBookWidgetItem(QtGui.QTableWidgetItem, AccountMixin): self.label = str(value) if self.type in (AccountMixin.NORMAL, AccountMixin.MAILINGLIST, AccountMixin.CHAN): try: - a = shared.config.get(self.address, 'label') - shared.config.set(self.address, 'label', self.label) + a = BMConfigParser().get(self.address, 'label') + BMConfigParser().set(self.address, 'label', self.label) except: sqlExecute('''UPDATE addressbook set label=? WHERE address=?''', self.label, self.address) elif self.type == AccountMixin.SUBSCRIPTION: diff --git a/src/bitmessageqt/languagebox.py b/src/bitmessageqt/languagebox.py index 2a8cb865..4ece7d83 100644 --- a/src/bitmessageqt/languagebox.py +++ b/src/bitmessageqt/languagebox.py @@ -2,7 +2,8 @@ import glob import os from PyQt4 import QtCore, QtGui -from shared import codePath, config +from configparser import BMConfigParser +from shared import codePath class LanguageBox(QtGui.QComboBox): languageName = {"system": "System Settings", "eo": "Esperanto", "en_pirate": "Pirate English"} @@ -16,7 +17,7 @@ class LanguageBox(QtGui.QComboBox): localesPath = os.path.join (codePath(), 'translations') configuredLocale = "system" try: - configuredLocale = config.get('bitmessagesettings', 'userlocale', "system") + configuredLocale = BMConfigParser().get('bitmessagesettings', 'userlocale', "system") except: pass self.addItem(QtGui.QApplication.translate("settingsDialog", "System Settings", "system"), "system") diff --git a/src/bitmessageqt/support.py b/src/bitmessageqt/support.py index 0f52ec04..92658a17 100644 --- a/src/bitmessageqt/support.py +++ b/src/bitmessageqt/support.py @@ -5,6 +5,7 @@ import sys import time import account +from configparser import BMConfigParser from debug import logger from foldertree import AccountMixin from helper_sql import * @@ -13,6 +14,7 @@ from openclpow import openclAvailable, openclEnabled from proofofwork import bmpow from pyelliptic.openssl import OpenSSL import shared +from version import softwareVersion # this is BM support address going to Peter Surda SUPPORT_ADDRESS = 'BM-2cTkCtMYkrSPwFTpgcBrMrf5d8oZwvMZWK' @@ -55,7 +57,7 @@ def checkAddressBook(myapp): def checkHasNormalAddress(): for address in account.getSortedAccounts(): 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 False @@ -80,7 +82,7 @@ def createSupportMessage(myapp): myapp.ui.comboBoxSendFrom.setCurrentIndex(addrIndex) myapp.ui.lineEditTo.setText(SUPPORT_ADDRESS) - version = shared.softwareVersion + version = softwareVersion os = sys.platform if os == "win32": windowsversion = sys.getwindowsversion() @@ -107,15 +109,15 @@ def createSupportMessage(myapp): portablemode = "True" if shared.appdata == shared.lookupExeFolder() else "False" cpow = "True" if bmpow else "False" #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) locale = getTranslationLanguage() try: - socks = shared.config.get('bitmessagesettings', 'socksproxytype') + socks = BMConfigParser().get('bitmessagesettings', 'socksproxytype') except: socks = "N/A" try: - upnp = shared.config.get('bitmessagesettings', 'upnp') + upnp = BMConfigParser().get('bitmessagesettings', 'upnp') except: upnp = "N/A" connectedhosts = len(shared.connectedHostsList) diff --git a/src/bitmessageqt/utils.py b/src/bitmessageqt/utils.py index 6f592a63..7361f37d 100644 --- a/src/bitmessageqt/utils.py +++ b/src/bitmessageqt/utils.py @@ -3,6 +3,7 @@ import hashlib import os import shared from addresses import addBMIfNotPresent +from configparser import BMConfigParser str_broadcast_subscribers = '[Broadcast subscribers]' str_chan = '[chan]' @@ -15,7 +16,7 @@ def identiconize(address): # 3fd4bf901b9d4ea1394f0fb358725b28 try: - identicon_lib = shared.config.get('bitmessagesettings', 'identiconlib') + identicon_lib = BMConfigParser().get('bitmessagesettings', 'identiconlib') except: # default to 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.) # 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. - 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() return idcon diff --git a/src/class_addressGenerator.py b/src/class_addressGenerator.py index 8a5945fd..c215fa3c 100644 --- a/src/class_addressGenerator.py +++ b/src/class_addressGenerator.py @@ -7,6 +7,7 @@ import ctypes import hashlib import highlevelcrypto from addresses import * +from configparser import BMConfigParser from debug import logger from helper_threading import * from pyelliptic import arithmetic @@ -48,7 +49,7 @@ class addressGenerator(threading.Thread, StoppableThread): elif len(queueValue) == 7: command, addressVersionNumber, streamNumber, label, numberOfAddressesToMake, deterministicPassphrase, eighteenByteRipe = queueValue try: - numberOfNullBytesDemandedOnFrontOfRipeHash = shared.config.getint( + numberOfNullBytesDemandedOnFrontOfRipeHash = BMConfigParser().getint( 'bitmessagesettings', 'numberofnullbytesonaddress') except: if eighteenByteRipe: @@ -58,7 +59,7 @@ class addressGenerator(threading.Thread, StoppableThread): elif len(queueValue) == 9: command, addressVersionNumber, streamNumber, label, numberOfAddressesToMake, deterministicPassphrase, eighteenByteRipe, nonceTrialsPerByte, payloadLengthExtraBytes = queueValue try: - numberOfNullBytesDemandedOnFrontOfRipeHash = shared.config.getint( + numberOfNullBytesDemandedOnFrontOfRipeHash = BMConfigParser().getint( 'bitmessagesettings', 'numberofnullbytesonaddress') except: if eighteenByteRipe: @@ -74,12 +75,12 @@ class addressGenerator(threading.Thread, StoppableThread): 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) if nonceTrialsPerByte == 0: - nonceTrialsPerByte = shared.config.getint( + nonceTrialsPerByte = BMConfigParser().getint( 'bitmessagesettings', 'defaultnoncetrialsperbyte') if nonceTrialsPerByte < shared.networkDefaultProofOfWorkNonceTrialsPerByte: nonceTrialsPerByte = shared.networkDefaultProofOfWorkNonceTrialsPerByte if payloadLengthExtraBytes == 0: - payloadLengthExtraBytes = shared.config.getint( + payloadLengthExtraBytes = BMConfigParser().getint( 'bitmessagesettings', 'defaultpayloadlengthextrabytes') if payloadLengthExtraBytes < shared.networkDefaultPayloadLengthExtraBytes: payloadLengthExtraBytes = shared.networkDefaultPayloadLengthExtraBytes @@ -128,17 +129,17 @@ class addressGenerator(threading.Thread, StoppableThread): privEncryptionKeyWIF = arithmetic.changebase( privEncryptionKey + checksum, 256, 58) - shared.config.add_section(address) - shared.config.set(address, 'label', label) - shared.config.set(address, 'enabled', 'true') - shared.config.set(address, 'decoy', 'false') - shared.config.set(address, 'noncetrialsperbyte', str( + BMConfigParser().add_section(address) + BMConfigParser().set(address, 'label', label) + BMConfigParser().set(address, 'enabled', 'true') + BMConfigParser().set(address, 'decoy', 'false') + BMConfigParser().set(address, 'noncetrialsperbyte', str( nonceTrialsPerByte)) - shared.config.set(address, 'payloadlengthextrabytes', str( + BMConfigParser().set(address, 'payloadlengthextrabytes', str( payloadLengthExtraBytes)) - shared.config.set( + BMConfigParser().set( address, 'privSigningKey', privSigningKeyWIF) - shared.config.set( + BMConfigParser().set( address, 'privEncryptionKey', privEncryptionKeyWIF) shared.writeKeysFile() @@ -233,7 +234,7 @@ class addressGenerator(threading.Thread, StoppableThread): try: - shared.config.add_section(address) + BMConfigParser().add_section(address) addressAlreadyExists = False except: addressAlreadyExists = True @@ -244,18 +245,18 @@ class addressGenerator(threading.Thread, StoppableThread): 'updateStatusBar', tr._translate("MainWindow","%1 is already in 'Your Identities'. Not adding it again.").arg(address))) else: logger.debug('label: %s' % label) - shared.config.set(address, 'label', label) - shared.config.set(address, 'enabled', 'true') - shared.config.set(address, 'decoy', 'false') + BMConfigParser().set(address, 'label', label) + BMConfigParser().set(address, 'enabled', 'true') + BMConfigParser().set(address, 'decoy', 'false') if command == 'joinChan' or command == 'createChan': - shared.config.set(address, 'chan', 'true') - shared.config.set(address, 'noncetrialsperbyte', str( + BMConfigParser().set(address, 'chan', 'true') + BMConfigParser().set(address, 'noncetrialsperbyte', str( nonceTrialsPerByte)) - shared.config.set(address, 'payloadlengthextrabytes', str( + BMConfigParser().set(address, 'payloadlengthextrabytes', str( payloadLengthExtraBytes)) - shared.config.set( + BMConfigParser().set( address, 'privSigningKey', privSigningKeyWIF) - shared.config.set( + BMConfigParser().set( address, 'privEncryptionKey', privEncryptionKeyWIF) shared.writeKeysFile() @@ -278,7 +279,7 @@ class addressGenerator(threading.Thread, StoppableThread): 'sendOutOrStoreMyV4Pubkey', address)) shared.UISignalQueue.put(( '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) # Done generating addresses. diff --git a/src/class_objectProcessor.py b/src/class_objectProcessor.py index c85b58a1..9170ae5b 100644 --- a/src/class_objectProcessor.py +++ b/src/class_objectProcessor.py @@ -13,6 +13,7 @@ from binascii import hexlify from pyelliptic.openssl import OpenSSL import highlevelcrypto from addresses import * +from configparser import BMConfigParser import helper_generic from helper_generic import addDataPadding import helper_bitcoin @@ -20,6 +21,8 @@ import helper_inbox import helper_msgcoding import helper_sent from helper_sql import * +import protocol +from state import neededPubkeys import tr from debug import logger import l10n @@ -130,11 +133,11 @@ class objectProcessor(threading.Thread): 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.') 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.') return try: - lastPubkeySendTime = int(shared.config.get( + lastPubkeySendTime = int(BMConfigParser().get( myAddress, 'lastpubkeysendtime')) except: lastPubkeySendTime = 0 @@ -283,12 +286,12 @@ class objectProcessor(threading.Thread): return 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.') return # Let us try to decrypt the pubkey - toAddress, cryptorObject = shared.neededPubkeys[tag] + toAddress, cryptorObject = neededPubkeys[tag] if shared.decryptAndCheckPubkeyPayload(data, toAddress) == 'successful': # At this point we know that we have been waiting on this pubkey. # 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 # addresses then we skip this check; the minimum network POW is # 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: - requiredNonceTrialsPerByte = shared.config.getint( + requiredNonceTrialsPerByte = BMConfigParser().getint( toAddress, 'noncetrialsperbyte') - requiredPayloadLengthExtraBytes = shared.config.getint( + requiredPayloadLengthExtraBytes = BMConfigParser().getint( toAddress, 'payloadlengthextrabytes') if not shared.isProofOfWorkSufficient(data, requiredNonceTrialsPerByte, requiredPayloadLengthExtraBytes): logger.info('Proof of work in msg is insufficient only because it does not meet our higher requirement.') return 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( '''SELECT label FROM blacklist where address=? and enabled='1' ''', fromAddress) @@ -484,7 +487,7 @@ class objectProcessor(threading.Thread): logger.info('Message ignored because address not in whitelist.') blockMessage = True - toLabel = shared.config.get(toAddress, 'label') + toLabel = BMConfigParser().get(toAddress, 'label') if toLabel == '': toLabel = toAddress @@ -508,9 +511,9 @@ class objectProcessor(threading.Thread): # 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 # has arrived. - if shared.safeConfigGetBoolean('bitmessagesettings', 'apienabled'): + if BMConfigParser().safeGetBoolean('bitmessagesettings', 'apienabled'): try: - apiNotifyPath = shared.config.get( + apiNotifyPath = BMConfigParser().get( 'bitmessagesettings', 'apinotifypath') except: apiNotifyPath = '' @@ -519,9 +522,9 @@ class objectProcessor(threading.Thread): # Let us now check and see whether our receiving address is # behaving as a mailing list - if shared.safeConfigGetBoolean(toAddress, 'mailinglist') and messageEncodingType != 0: + if BMConfigParser().safeGetBoolean(toAddress, 'mailinglist') and messageEncodingType != 0: try: - mailingListName = shared.config.get( + mailingListName = BMConfigParser().get( toAddress, 'mailinglistname') except: mailingListName = '' @@ -566,8 +569,8 @@ class objectProcessor(threading.Thread): if self.ackDataHasAValidHeader(ackData) and \ not blockMessage and \ messageEncodingType != 0 and \ - not shared.safeConfigGetBoolean(toAddress, 'dontsendack') and \ - not shared.safeConfigGetBoolean(toAddress, 'chan'): + not BMConfigParser().safeGetBoolean(toAddress, 'dontsendack') and \ + not BMConfigParser().safeGetBoolean(toAddress, 'chan'): shared.checkAndShareObjectWithPeers(ackData[24:]) # 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 # outside command to let some program know that a new message # has arrived. - if shared.safeConfigGetBoolean('bitmessagesettings', 'apienabled'): + if BMConfigParser().safeGetBoolean('bitmessagesettings', 'apienabled'): try: - apiNotifyPath = shared.config.get( + apiNotifyPath = BMConfigParser().get( 'bitmessagesettings', 'apinotifypath') except: apiNotifyPath = '' @@ -780,8 +783,8 @@ class objectProcessor(threading.Thread): # stream number, and RIPE hash. status, addressVersion, streamNumber, ripe = decodeAddress(address) if addressVersion <=3: - if address in shared.neededPubkeys: - del shared.neededPubkeys[address] + if address in neededPubkeys: + del neededPubkeys[address] self.sendMessages(address) else: 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: tag = hashlib.sha512(hashlib.sha512(encodeVarint( addressVersion) + encodeVarint(streamNumber) + ripe).digest()).digest()[32:] - if tag in shared.neededPubkeys: - del shared.neededPubkeys[tag] + if tag in neededPubkeys: + del neededPubkeys[tag] self.sendMessages(address) def sendMessages(self, address): @@ -808,15 +811,15 @@ class objectProcessor(threading.Thread): shared.workerQueue.put(('sendmessage', '')) 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.') 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: logger.info('Ackdata magic bytes were wrong. Not sending ackData.') return False - payload = ackData[shared.Header.size:] + payload = ackData[protocol.Header.size:] if len(payload) != payloadLength: logger.info('ackData payload length doesn\'t match the payload length specified in the header. Not sending ackdata.') return False diff --git a/src/class_outgoingSynSender.py b/src/class_outgoingSynSender.py index bca56b33..caa14aa0 100644 --- a/src/class_outgoingSynSender.py +++ b/src/class_outgoingSynSender.py @@ -10,6 +10,7 @@ import tr from class_sendDataThread import * from class_receiveDataThread import * +from configparser import BMConfigParser from helper_threading import * # For each stream to which we connect, several outgoingSynSender threads @@ -45,12 +46,12 @@ class outgoingSynSender(threading.Thread, StoppableThread): continue priority = (183600 - (time.time() - shared.knownNodes[self.streamNumber][peer])) / 183600 # 2 days and 3 hours shared.knownNodesLock.release() - if shared.config.get('bitmessagesettings', 'socksproxytype') != 'none': + if BMConfigParser().get('bitmessagesettings', 'socksproxytype') != 'none': if peer.host.find(".onion") == -1: priority /= 10 # hidden services have 10x priority over plain net else: # don't connect to self - if peer.host == 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 elif peer.host.find(".onion") != -1: # onion address and so proxy continue @@ -72,9 +73,9 @@ class outgoingSynSender(threading.Thread, StoppableThread): pass 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) - while shared.safeConfigGetBoolean('bitmessagesettings', 'sendoutgoingconnections') and not self._stopped: + while BMConfigParser().safeGetBoolean('bitmessagesettings', 'sendoutgoingconnections') and not self._stopped: self.name = "outgoingSynSender" maximumConnections = 1 if shared.trustedPeer else 8 # maximum number of outgoing connections = 8 while len(self.selfInitiatedConnections[self.streamNumber]) >= maximumConnections: @@ -110,8 +111,8 @@ class outgoingSynSender(threading.Thread, StoppableThread): self.name = "outgoingSynSender-" + peer.host.replace(":", ".") # log parser field separator address_family = socket.AF_INET # Proxy IP is IPv6. Unlikely but possible - if shared.config.get('bitmessagesettings', 'socksproxytype') != 'none': - if ":" in shared.config.get('bitmessagesettings', 'sockshostname'): + if BMConfigParser().get('bitmessagesettings', 'socksproxytype') != 'none': + if ":" in BMConfigParser().get('bitmessagesettings', 'sockshostname'): address_family = socket.AF_INET6 # No proxy, and destination is IPv6 elif peer.host.find(':') >= 0 : @@ -140,44 +141,44 @@ class outgoingSynSender(threading.Thread, StoppableThread): # can rebind faster self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 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)) # 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: logger.debug ('(Using SOCKS4a) Trying an outgoing connection to ' + str(peer)) proxytype = socks.PROXY_TYPE_SOCKS4 - sockshostname = shared.config.get( + sockshostname = BMConfigParser().get( 'bitmessagesettings', 'sockshostname') - socksport = shared.config.getint( + socksport = BMConfigParser().getint( 'bitmessagesettings', 'socksport') rdns = True # Do domain name lookups through the proxy; though this setting doesn't really matter since we won't be doing any domain name lookups anyway. - if shared.config.getboolean('bitmessagesettings', 'socksauthentication'): - socksusername = shared.config.get( + if BMConfigParser().getboolean('bitmessagesettings', 'socksauthentication'): + socksusername = BMConfigParser().get( 'bitmessagesettings', 'socksusername') - sockspassword = shared.config.get( + sockspassword = BMConfigParser().get( 'bitmessagesettings', 'sockspassword') self.sock.setproxy( proxytype, sockshostname, socksport, rdns, socksusername, sockspassword) else: self.sock.setproxy( proxytype, sockshostname, socksport, rdns) - elif shared.config.get('bitmessagesettings', 'socksproxytype') == 'SOCKS5': + elif BMConfigParser().get('bitmessagesettings', 'socksproxytype') == 'SOCKS5': if shared.verbose >= 2: logger.debug ('(Using SOCKS5) Trying an outgoing connection to ' + str(peer)) proxytype = socks.PROXY_TYPE_SOCKS5 - sockshostname = shared.config.get( + sockshostname = BMConfigParser().get( 'bitmessagesettings', 'sockshostname') - socksport = shared.config.getint( + socksport = BMConfigParser().getint( 'bitmessagesettings', 'socksport') rdns = True # Do domain name lookups through the proxy; though this setting doesn't really matter since we won't be doing any domain name lookups anyway. - if shared.config.getboolean('bitmessagesettings', 'socksauthentication'): - socksusername = shared.config.get( + if BMConfigParser().getboolean('bitmessagesettings', 'socksauthentication'): + socksusername = BMConfigParser().get( 'bitmessagesettings', 'socksusername') - sockspassword = shared.config.get( + sockspassword = BMConfigParser().get( 'bitmessagesettings', 'sockspassword') self.sock.setproxy( proxytype, sockshostname, socksport, rdns, socksusername, sockspassword) @@ -254,7 +255,7 @@ class outgoingSynSender(threading.Thread, StoppableThread): except socks.Socks4Error as err: logger.error('Socks4Error: ' + str(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)) else: if shared.verbose >= 1: diff --git a/src/class_receiveDataThread.py b/src/class_receiveDataThread.py index f29b1f4c..fb25db4c 100644 --- a/src/class_receiveDataThread.py +++ b/src/class_receiveDataThread.py @@ -23,12 +23,15 @@ from binascii import hexlify #import highlevelcrypto from addresses import * +from configparser import BMConfigParser from class_objectHashHolder import objectHashHolder from helper_generic import addDataPadding, isHostInPrivateIPRange from helper_sql import sqlQuery from debug import logger +import protocol from inventory import Inventory import tr +from version import softwareVersion # This thread is created either by the synSenderThread(for outgoing # connections) or the singleListenerThread(for incoming connections). @@ -59,7 +62,7 @@ class receiveDataThread(threading.Thread): self.objectsThatWeHaveYetToGetFromThisPeer = {} self.selfInitiatedConnections = selfInitiatedConnections 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[ 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. @@ -77,10 +80,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))) while True: - if shared.config.getint('bitmessagesettings', 'maxdownloadrate') == 0: + if BMConfigParser().getint('bitmessagesettings', 'maxdownloadrate') == 0: downloadRateLimitBytes = float("inf") else: - downloadRateLimitBytes = shared.config.getint('bitmessagesettings', 'maxdownloadrate') * 1000 + downloadRateLimitBytes = BMConfigParser().getint('bitmessagesettings', 'maxdownloadrate') * 1000 with shared.receiveDataLock: while shared.numberOfBytesReceivedLastSecond >= downloadRateLimitBytes: if int(time.time()) == shared.lastTimeWeResetBytesReceived: @@ -93,9 +96,9 @@ class receiveDataThread(threading.Thread): dataLen = len(self.data) try: 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 - shared.haveSSL(not self.initiatedConnection)): + protocol.haveSSL(not self.initiatedConnection)): ssl = True dataRecv = self.sslSock.recv(1024) else: @@ -106,7 +109,7 @@ class receiveDataThread(threading.Thread): except socket.timeout: logger.error ('Timeout occurred waiting for data from ' + str(self.peer) + '. Closing receiveData thread. (ID: ' + str(id(self)) + ')') 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 ssl: select.select([self.sslSock], [], []) @@ -165,25 +168,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")))) 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 - 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: self.data = "" return if payloadLength > 1600100: # ~1.6 MB which is the maximum possible size of an inv message. logger.info('The incoming message, which we have not yet download, is too large. Ignoring it. (unfortunately there is no way to tell the other node to stop sending it except to disconnect.) Message size: %s' % payloadLength) - self.data = self.data[payloadLength + 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 self.processData() 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 - 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. 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 self.processData() return @@ -227,7 +230,7 @@ class receiveDataThread(threading.Thread): logger.critical("Critical error in a receiveDataThread: \n%s" % traceback.format_exc()) 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 while len(self.objectsThatWeHaveYetToGetFromThisPeer) > 0: @@ -267,7 +270,7 @@ class receiveDataThread(threading.Thread): def sendpong(self): logger.debug('Sending pong') - self.sendDataThreadQueue.put((0, 'sendRawData', shared.CreatePacket('pong'))) + self.sendDataThreadQueue.put((0, 'sendRawData', protocol.CreatePacket('pong'))) def recverack(self): @@ -285,8 +288,8 @@ class receiveDataThread(threading.Thread): shared.timeOffsetWrongCount = 0 self.sslSock = self.sock - if ((self.services & shared.NODE_SSL == shared.NODE_SSL) and - shared.haveSSL(not self.initiatedConnection)): + if ((self.services & protocol.NODE_SSL == protocol.NODE_SSL) and + protocol.haveSSL(not self.initiatedConnection)): 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') if hasattr(self.sslSock, "context"): @@ -361,7 +364,7 @@ class receiveDataThread(threading.Thread): def sendinvMessageToJustThisOnePeer(self, numberOfObjects, payload): payload = encodeVarint(numberOfObjects) + payload logger.debug('Sending huge inv message with ' + str(numberOfObjects) + ' objects to just this one peer') - self.sendDataThreadQueue.put((0, 'sendRawData', shared.CreatePacket('inv', payload))) + self.sendDataThreadQueue.put((0, 'sendRawData', protocol.CreatePacket('inv', payload))) def _sleepForTimingAttackMitigation(self, sleepTime): # We don't need to do the timing attack mitigation if we are @@ -471,7 +474,7 @@ class receiveDataThread(threading.Thread): def sendgetdata(self, hash): logger.debug('sending getdata to retrieve object with hash: ' + hexlify(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 @@ -499,7 +502,7 @@ class receiveDataThread(threading.Thread): # Our peer has requested (in a getdata message) that we send an object. def sendObject(self, payload): 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): if host[0:12] == '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF': @@ -622,15 +625,15 @@ class receiveDataThread(threading.Thread): sentOwn = False for i in range(500): # 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: - 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: # still may contain own onion address, but we don't change it peer, = random.sample(shared.knownNodes[self.streamNumber], 1) if isHostInPrivateIPRange(peer.host): 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 addrsInMyStream[peer] = shared.knownNodes[ self.streamNumber][peer] @@ -662,7 +665,7 @@ class receiveDataThread(threading.Thread): payload += pack('>I', self.streamNumber) payload += pack( '>q', 1) # service bit flags offered by this node - payload += shared.encodeHost(HOST) + payload += protocol.encodeHost(HOST) payload += pack('>H', PORT) # remote port for (HOST, PORT), value in addrsInChildStreamLeft.items(): timeLastReceivedMessageFromThisNode = value @@ -673,7 +676,7 @@ class receiveDataThread(threading.Thread): payload += pack('>I', self.streamNumber * 2) payload += pack( '>q', 1) # service bit flags offered by this node - payload += shared.encodeHost(HOST) + payload += protocol.encodeHost(HOST) payload += pack('>H', PORT) # remote port for (HOST, PORT), value in addrsInChildStreamRight.items(): timeLastReceivedMessageFromThisNode = value @@ -684,11 +687,11 @@ class receiveDataThread(threading.Thread): payload += pack('>I', (self.streamNumber * 2) + 1) payload += pack( '>q', 1) # service bit flags offered by this node - payload += shared.encodeHost(HOST) + payload += protocol.encodeHost(HOST) payload += pack('>H', PORT) # remote port 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 @@ -714,14 +717,14 @@ class receiveDataThread(threading.Thread): timestamp, = unpack('>Q', data[12:20]) timeOffset = timestamp - int(time.time()) 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)) shared.timeOffsetWrongCount += 1 time.sleep(2) self.sendDataThreadQueue.put((0, 'shutdown','no data')) return 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)) shared.timeOffsetWrongCount += 1 time.sleep(2) @@ -747,7 +750,7 @@ class receiveDataThread(threading.Thread): userAgentName = useragent userAgentVersion = "0.0.0" if userAgentName == "PyBitmessage": - myVersion = [int(n) for n in shared.softwareVersion.split(".")] + myVersion = [int(n) for n in softwareVersion.split(".")] try: remoteVersion = [int(n) for n in userAgentVersion.split(".")] except: @@ -778,7 +781,7 @@ class receiveDataThread(threading.Thread): # doesn't know the stream. We have to set it. if not self.initiatedConnection: 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')) logger.debug('Closing connection to myself: ' + str(self.peer)) return @@ -801,14 +804,14 @@ class receiveDataThread(threading.Thread): # Sends a version message def sendversion(self): 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))) # Sends a verack message def sendverack(self): logger.debug('Sending verack') - self.sendDataThreadQueue.put((0, 'sendRawData', shared.CreatePacket('verack'))) + self.sendDataThreadQueue.put((0, 'sendRawData', protocol.CreatePacket('verack'))) self.verackSent = True if self.verackReceived: self.connectionFullyEstablished() diff --git a/src/class_sendDataThread.py b/src/class_sendDataThread.py index 9c048d32..0a49e95c 100644 --- a/src/class_sendDataThread.py +++ b/src/class_sendDataThread.py @@ -8,10 +8,12 @@ import random import sys import socket +from configparser import BMConfigParser from helper_generic import addDataPadding from class_objectHashHolder import * from addresses import * from debug import logger +import protocol # Every connection to a peer has a sendDataThread (and also a # receiveDataThread). @@ -53,7 +55,7 @@ class sendDataThread(threading.Thread): 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. logger.debug('Sending version packet: ' + repr(datatosend)) @@ -67,10 +69,10 @@ class sendDataThread(threading.Thread): self.versionSent = 1 def sendBytes(self, data): - if shared.config.getint('bitmessagesettings', 'maxuploadrate') == 0: + if BMConfigParser().getint('bitmessagesettings', 'maxuploadrate') == 0: uploadRateLimitBytes = 999999999 # float("inf") doesn't work else: - uploadRateLimitBytes = shared.config.getint('bitmessagesettings', 'maxuploadrate') * 1000 + uploadRateLimitBytes = BMConfigParser().getint('bitmessagesettings', 'maxuploadrate') * 1000 with shared.sendDataLock: while data: while shared.numberOfBytesSentLastSecond >= uploadRateLimitBytes: @@ -83,11 +85,11 @@ class sendDataThread(threading.Thread): # 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 # once per second. - if shared.config.getint('bitmessagesettings', 'maxuploadrate') == 0: + if BMConfigParser().getint('bitmessagesettings', 'maxuploadrate') == 0: uploadRateLimitBytes = 999999999 # float("inf") doesn't work else: - uploadRateLimitBytes = shared.config.getint('bitmessagesettings', 'maxuploadrate') * 1000 - if ((self.services & shared.NODE_SSL == shared.NODE_SSL) and + uploadRateLimitBytes = BMConfigParser().getint('bitmessagesettings', 'maxuploadrate') * 1000 + if ((self.services & protocol.NODE_SSL == protocol.NODE_SSL) and self.connectionIsOrWasFullyEstablished and shared.haveSSL(not self.initiatedConnection)): amountSent = self.sslSock.send(data[:1000]) @@ -134,11 +136,11 @@ class sendDataThread(threading.Thread): payload += pack('>I', streamNumber) payload += pack( '>q', services) # service bit flags offered by this node - payload += shared.encodeHost(host) + payload += protocol.encodeHost(host) payload += pack('>H', port) payload = encodeVarint(numberOfAddressesInAddrMessage) + payload - packet = shared.CreatePacket('addr', payload) + packet = protocol.CreatePacket('addr', payload) try: self.sendBytes(packet) except: @@ -154,7 +156,7 @@ class sendDataThread(threading.Thread): payload += hash if payload != '': payload = encodeVarint(len(payload)/32) + payload - packet = shared.CreatePacket('inv', payload) + packet = protocol.CreatePacket('inv', payload) try: self.sendBytes(packet) except: @@ -165,7 +167,7 @@ class sendDataThread(threading.Thread): if self.lastTimeISentData < (int(time.time()) - 298): # Send out a pong message to keep the connection alive. logger.debug('Sending pong to ' + str(self.peer) + ' to keep connection alive.') - packet = shared.CreatePacket('pong') + packet = protocol.CreatePacket('pong') try: self.sendBytes(packet) except: diff --git a/src/class_singleCleaner.py b/src/class_singleCleaner.py index 533184d3..0c25c5ec 100644 --- a/src/class_singleCleaner.py +++ b/src/class_singleCleaner.py @@ -6,10 +6,12 @@ import os import pickle import tr#anslate +from configparser import BMConfigParser from helper_sql import * from helper_threading import * from inventory import Inventory from debug import logger +from state import neededPubkeys """ The singleCleaner class is a timer-driven thread that cleans data structures @@ -40,7 +42,7 @@ class singleCleaner(threading.Thread, StoppableThread): def run(self): timeWeLastClearedInventoryAndPubkeysTables = 0 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: # Either the user hasn't set stopresendingafterxdays and stopresendingafterxmonths yet or the options are missing from the config file. shared.maximumLengthOfTimeToBotherResendingMessages = float('inf') @@ -56,7 +58,7 @@ class singleCleaner(threading.Thread, StoppableThread): # 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 # save memory. - if shared.safeConfigGetBoolean('bitmessagesettings', 'daemon'): + if BMConfigParser().safeGetBoolean('bitmessagesettings', 'daemon'): shared.UISignalQueue.queue.clear() if timeWeLastClearedInventoryAndPubkeysTables < int(time.time()) - 7380: timeWeLastClearedInventoryAndPubkeysTables = int(time.time()) @@ -114,8 +116,8 @@ class singleCleaner(threading.Thread, StoppableThread): def resendPubkeyRequest(address): logger.debug('It has been a long time and we haven\'t heard a response to our getpubkey request. Sending again.') try: - del shared.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. + del neededPubkeys[ + 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: pass diff --git a/src/class_singleListener.py b/src/class_singleListener.py index 0a093d0e..896a34bc 100644 --- a/src/class_singleListener.py +++ b/src/class_singleListener.py @@ -1,10 +1,12 @@ import threading import shared import socket +from configparser import BMConfigParser from class_sendDataThread import * from class_receiveDataThread import * import helper_bootstrap from helper_threading import * +import protocol import errno import re @@ -28,9 +30,9 @@ class singleListener(threading.Thread, StoppableThread): def _createListenSocket(self, family): HOST = '' # Symbolic name meaning all available interfaces # If not sockslisten, but onionhostname defined, only listen on localhost - if not shared.safeConfigGetBoolean('bitmessagesettings', 'sockslisten') and ".onion" in shared.config.get('bitmessagesettings', 'onionhostname'): - HOST = shared.config.get('bitmessagesettings', 'onionbindip') - PORT = shared.config.getint('bitmessagesettings', 'port') + if not BMConfigParser().safeGetBoolean('bitmessagesettings', 'sockslisten') and ".onion" in BMConfigParser().get('bitmessagesettings', 'onionhostname'): + HOST = BMConfigParser().get('bitmessagesettings', 'onionbindip') + PORT = BMConfigParser().getint('bitmessagesettings', 'port') sock = socket.socket(family, socket.SOCK_STREAM) if family == socket.AF_INET6: # Make sure we can accept both IPv4 and IPv6 connections. @@ -46,9 +48,9 @@ class singleListener(threading.Thread, StoppableThread): def stopThread(self): super(singleListener, self).stopThread() 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: - s.connect((ip, shared.config.getint('bitmessagesettings', 'port'))) + s.connect((ip, BMConfigParser().getint('bitmessagesettings', 'port'))) s.shutdown(socket.SHUT_RDWR) s.close() break @@ -61,7 +63,7 @@ class singleListener(threading.Thread, StoppableThread): if shared.trustedPeer: return - while shared.safeConfigGetBoolean('bitmessagesettings', 'dontconnect') and shared.shutdown == 0: + while BMConfigParser().safeGetBoolean('bitmessagesettings', 'dontconnect') and shared.shutdown == 0: self.stop.wait(1) helper_bootstrap.dns() # 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 # connections. But if on SOCKS and have an onionhostname, listen # (socket is then only opened for localhost) - 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 \ + 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(5) @@ -100,7 +102,7 @@ class singleListener(threading.Thread, StoppableThread): # SOCKS proxy, unless they have configured otherwise. If they eventually select # proxy 'none' or configure SOCKS listening then this will start listening for # connections. - while 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) 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.') @@ -123,7 +125,7 @@ class singleListener(threading.Thread, StoppableThread): # share the same external IP. This is here to prevent # connection flooding. # permit repeated connections from Tor - if HOST in shared.connectedHostsList and (".onion" not in 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() logger.info('We are already connected to ' + str(HOST) + '. Ignoring connection.') else: diff --git a/src/class_singleWorker.py b/src/class_singleWorker.py index ea1fbf3d..94dc0f9a 100644 --- a/src/class_singleWorker.py +++ b/src/class_singleWorker.py @@ -11,6 +11,7 @@ import highlevelcrypto import proofofwork import sys import tr +from configparser import BMConfigParser from debug import logger from helper_sql import * import helper_inbox @@ -19,7 +20,8 @@ import helper_msgcoding from helper_threading import * from inventory import Inventory import l10n -from protocol import * +import protocol +from state import neededPubkeys from binascii import hexlify, unhexlify # This thread, of which there is only one, does the heavy lifting: @@ -55,13 +57,13 @@ class singleWorker(threading.Thread, StoppableThread): toAddress, = row toStatus, toAddressVersionNumber, toStreamNumber, toRipe = decodeAddress(toAddress) if toAddressVersionNumber <= 3 : - shared.neededPubkeys[toAddress] = 0 + neededPubkeys[toAddress] = 0 elif toAddressVersionNumber >= 4: doubleHashOfAddressData = hashlib.sha512(hashlib.sha512(encodeVarint( toAddressVersionNumber) + encodeVarint(toStreamNumber) + toRipe).digest()).digest() privEncryptionKey = doubleHashOfAddressData[:32] # Note that this is the first half of the sha512 hash. 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 queryreturn = sqlQuery( @@ -139,12 +141,12 @@ class singleWorker(threading.Thread, StoppableThread): payload += '\x00\x00\x00\x01' # object type: pubkey payload += encodeVarint(addressVersionNumber) # Address version number 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: - privSigningKeyBase58 = shared.config.get( + privSigningKeyBase58 = BMConfigParser().get( myAddress, 'privsigningkey') - privEncryptionKeyBase58 = shared.config.get( + privEncryptionKeyBase58 = BMConfigParser().get( myAddress, 'privencryptionkey') 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) @@ -181,7 +183,7 @@ class singleWorker(threading.Thread, StoppableThread): streamNumber, 'advertiseobject', inventoryHash)) shared.UISignalQueue.put(('updateStatusBar', '')) try: - shared.config.set( + BMConfigParser().set( myAddress, 'lastpubkeysendtime', str(int(time.time()))) shared.writeKeysFile() except: @@ -199,7 +201,7 @@ class singleWorker(threading.Thread, StoppableThread): except: #The address has been deleted. return - if shared.safeConfigGetBoolean(myAddress, 'chan'): + if BMConfigParser().safeGetBoolean(myAddress, 'chan'): logger.info('This is a chan address. Not sending pubkey.') return status, addressVersionNumber, streamNumber, hash = decodeAddress( @@ -219,12 +221,12 @@ class singleWorker(threading.Thread, StoppableThread): payload += '\x00\x00\x00\x01' # object type: pubkey payload += encodeVarint(addressVersionNumber) # Address version number 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: - privSigningKeyBase58 = shared.config.get( + privSigningKeyBase58 = BMConfigParser().get( myAddress, 'privsigningkey') - privEncryptionKeyBase58 = shared.config.get( + privEncryptionKeyBase58 = BMConfigParser().get( myAddress, 'privencryptionkey') 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) @@ -243,9 +245,9 @@ class singleWorker(threading.Thread, StoppableThread): payload += pubSigningKey[1:] payload += pubEncryptionKey[1:] - payload += encodeVarint(shared.config.getint( + payload += encodeVarint(BMConfigParser().getint( myAddress, 'noncetrialsperbyte')) - payload += encodeVarint(shared.config.getint( + payload += encodeVarint(BMConfigParser().getint( myAddress, 'payloadlengthextrabytes')) signature = highlevelcrypto.sign(payload, privSigningKeyHex) @@ -271,7 +273,7 @@ class singleWorker(threading.Thread, StoppableThread): streamNumber, 'advertiseobject', inventoryHash)) shared.UISignalQueue.put(('updateStatusBar', '')) try: - shared.config.set( + BMConfigParser().set( myAddress, 'lastpubkeysendtime', str(int(time.time()))) shared.writeKeysFile() except: @@ -282,10 +284,10 @@ class singleWorker(threading.Thread, StoppableThread): # If this isn't a chan address, this function assembles the pubkey data, # does the necessary POW and sends it out. def sendOutOrStoreMyV4Pubkey(self, myAddress): - if not shared.config.has_section(myAddress): + if not BMConfigParser().has_section(myAddress): #The address has been deleted. return - if shared.safeConfigGetBoolean(myAddress, 'chan'): + if shared.BMConfigParser().safeGetBoolean(myAddress, 'chan'): logger.info('This is a chan address. Not sending pubkey.') return status, addressVersionNumber, streamNumber, hash = decodeAddress( @@ -297,12 +299,12 @@ class singleWorker(threading.Thread, StoppableThread): payload += '\x00\x00\x00\x01' # object type: pubkey payload += encodeVarint(addressVersionNumber) # Address version number payload += encodeVarint(streamNumber) - dataToEncrypt = getBitfield(myAddress) + dataToEncrypt = protocol.getBitfield(myAddress) try: - privSigningKeyBase58 = shared.config.get( + privSigningKeyBase58 = BMConfigParser().get( myAddress, 'privsigningkey') - privEncryptionKeyBase58 = shared.config.get( + privEncryptionKeyBase58 = BMConfigParser().get( myAddress, 'privencryptionkey') 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) @@ -319,9 +321,9 @@ class singleWorker(threading.Thread, StoppableThread): dataToEncrypt += pubSigningKey[1:] dataToEncrypt += pubEncryptionKey[1:] - dataToEncrypt += encodeVarint(shared.config.getint( + dataToEncrypt += encodeVarint(BMConfigParser().getint( myAddress, 'noncetrialsperbyte')) - dataToEncrypt += encodeVarint(shared.config.getint( + dataToEncrypt += encodeVarint(BMConfigParser().getint( myAddress, 'payloadlengthextrabytes')) # When we encrypt, we'll use a hash of the data @@ -361,7 +363,7 @@ class singleWorker(threading.Thread, StoppableThread): streamNumber, 'advertiseobject', inventoryHash)) shared.UISignalQueue.put(('updateStatusBar', '')) try: - shared.config.set( + BMConfigParser().set( myAddress, 'lastpubkeysendtime', str(int(time.time()))) shared.writeKeysFile() except Exception as err: @@ -384,9 +386,9 @@ class singleWorker(threading.Thread, StoppableThread): # We need to convert our private keys to public keys in order # to include them. try: - privSigningKeyBase58 = shared.config.get( + privSigningKeyBase58 = BMConfigParser().get( fromaddress, 'privsigningkey') - privEncryptionKeyBase58 = shared.config.get( + privEncryptionKeyBase58 = BMConfigParser().get( fromaddress, 'privencryptionkey') except: shared.UISignalQueue.put(('updateSentItemStatusByAckdata', ( @@ -432,12 +434,12 @@ class singleWorker(threading.Thread, StoppableThread): dataToEncrypt = encodeVarint(addressVersionNumber) dataToEncrypt += encodeVarint(streamNumber) - dataToEncrypt += getBitfield(fromaddress) # behavior bitfield + dataToEncrypt += protocol.getBitfield(fromaddress) # behavior bitfield dataToEncrypt += pubSigningKey[1:] dataToEncrypt += pubEncryptionKey[1:] if addressVersionNumber >= 3: - dataToEncrypt += encodeVarint(shared.config.getint(fromaddress,'noncetrialsperbyte')) - dataToEncrypt += encodeVarint(shared.config.getint(fromaddress,'payloadlengthextrabytes')) + dataToEncrypt += encodeVarint(BMConfigParser().getint(fromaddress,'noncetrialsperbyte')) + dataToEncrypt += encodeVarint(BMConfigParser().getint(fromaddress,'payloadlengthextrabytes')) dataToEncrypt += encodeVarint(encoding) # message encoding type encodedMessage = helper_msgcoding.MsgEncode({"subject": subject, "body": body}, encoding) dataToEncrypt += encodeVarint(encodedMessage.length) @@ -525,7 +527,7 @@ class singleWorker(threading.Thread, StoppableThread): # so let's assume that we have it. 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. - elif shared.config.has_section(toaddress): + elif BMConfigParser().has_section(toaddress): sqlExecute( '''UPDATE sent SET status='doingmsgpow' WHERE toaddress=? AND status='msgqueued' ''', toaddress) @@ -551,7 +553,7 @@ class singleWorker(threading.Thread, StoppableThread): toTag = '' else: 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 sqlExecute( '''UPDATE sent SET status='awaitingpubkey', sleeptill=? WHERE toaddress=? AND status='msgqueued' ''', @@ -575,7 +577,7 @@ class singleWorker(threading.Thread, StoppableThread): toAddressVersionNumber) + encodeVarint(toStreamNumber) + toRipe).digest()).digest() privEncryptionKey = doubleHashOfToAddressData[:32] # The first 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 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. @@ -583,7 +585,7 @@ class singleWorker(threading.Thread, StoppableThread): sqlExecute( '''UPDATE sent SET status='doingmsgpow', retrynumber=0 WHERE toaddress=? AND (status='msgqueued' or status='awaitingpubkey' or status='doingpubkeypow')''', toaddress) - del shared.neededPubkeys[tag] + del neededPubkeys[tag] break #else: # There was something wrong with this pubkey object even # though it had the correct tag- almost certainly because @@ -609,7 +611,7 @@ class singleWorker(threading.Thread, StoppableThread): TTL = int(TTL + random.randrange(-300, 300))# add some randomness to the 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.UISignalQueue.put(('updateSentItemStatusByAckdata', ( ackdata, tr._translate("MainWindow", "Looking up the receiver\'s public key")))) @@ -643,7 +645,7 @@ class singleWorker(threading.Thread, StoppableThread): # unencrypted. Before we actually do it the sending human must check a box # 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 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.') 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. @@ -676,7 +678,7 @@ class singleWorker(threading.Thread, StoppableThread): 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))))) 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 # to do. sqlExecute( @@ -688,10 +690,10 @@ class singleWorker(threading.Thread, StoppableThread): else: # if we are sending a message to ourselves or a chan.. logger.info('Sending a message.') logger.debug('First 150 characters of message: ' + repr(message[:150])) - behaviorBitfield = getBitfield(fromaddress) + behaviorBitfield = protocol.getBitfield(fromaddress) try: - privEncryptionKeyBase58 = shared.config.get( + privEncryptionKeyBase58 = BMConfigParser().get( toaddress, 'privencryptionkey') 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())))) @@ -709,14 +711,15 @@ class singleWorker(threading.Thread, StoppableThread): # Now we can start to assemble our message. payload = encodeVarint(fromAddressVersionNumber) 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 # to include them. try: - privSigningKeyBase58 = shared.config.get( + privSigningKeyBase58 = BMConfigParser().get( fromaddress, 'privsigningkey') - privEncryptionKeyBase58 = shared.config.get( + privEncryptionKeyBase58 = BMConfigParser().get( fromaddress, 'privencryptionkey') except: shared.UISignalQueue.put(('updateSentItemStatusByAckdata', ( @@ -748,9 +751,9 @@ class singleWorker(threading.Thread, StoppableThread): payload += encodeVarint( shared.networkDefaultPayloadLengthExtraBytes) else: - payload += encodeVarint(shared.config.getint( + payload += encodeVarint(BMConfigParser().getint( fromaddress, 'noncetrialsperbyte')) - payload += encodeVarint(shared.config.getint( + payload += encodeVarint(BMConfigParser().getint( 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. @@ -758,10 +761,10 @@ class singleWorker(threading.Thread, StoppableThread): encodedMessage = helper_msgcoding.MsgEncode({"subject": subject, "body": message}, encoding) payload += encodeVarint(encodedMessage.length) 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.') 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.') fullAckPayload = '' else: @@ -811,7 +814,7 @@ class singleWorker(threading.Thread, StoppableThread): objectType = 2 Inventory()[inventoryHash] = ( 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())))) else: # not sending to a chan or one of my addresses @@ -821,7 +824,7 @@ class singleWorker(threading.Thread, StoppableThread): toStreamNumber, 'advertiseobject', inventoryHash)) # 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' else: newStatus = 'msgsent' @@ -839,7 +842,7 @@ class singleWorker(threading.Thread, StoppableThread): # If we are sending to ourselves or a chan, let's put the message in # 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 t = (inventoryHash, toaddress, fromaddress, subject, int( time.time()), message, 'inbox', encoding, 0, sigHash) @@ -851,9 +854,9 @@ class singleWorker(threading.Thread, StoppableThread): # 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 # has arrived. - if shared.safeConfigGetBoolean('bitmessagesettings', 'apienabled'): + if BMConfigParser().safeGetBoolean('bitmessagesettings', 'apienabled'): try: - apiNotifyPath = shared.config.get( + apiNotifyPath = BMConfigParser().get( 'bitmessagesettings', 'apinotifypath') except: apiNotifyPath = '' @@ -877,15 +880,15 @@ class singleWorker(threading.Thread, StoppableThread): retryNumber = queryReturn[0][0] if addressVersionNumber <= 3: - shared.neededPubkeys[toAddress] = 0 + neededPubkeys[toAddress] = 0 elif addressVersionNumber >= 4: # 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 # 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. 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: - 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. + if tag not in neededPubkeys: + 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: TTL = 2.5*24*60*60 # 2.5 days. This was chosen fairly arbitrarily. @@ -976,4 +979,4 @@ class singleWorker(threading.Thread, StoppableThread): pass payload = pack('>Q', nonce) + payload - return shared.CreatePacket('object', payload) + return protocol.CreatePacket('object', payload) diff --git a/src/class_smtpDeliver.py b/src/class_smtpDeliver.py index 42baf989..ca51946f 100644 --- a/src/class_smtpDeliver.py +++ b/src/class_smtpDeliver.py @@ -5,6 +5,7 @@ import sys import threading import urlparse +from configparser import BMConfigParser from debug import logger from helper_threading import * import shared @@ -47,7 +48,7 @@ class smtpDeliver(threading.Thread, StoppableThread): pass elif command == 'displayNewInboxMessage': inventoryHash, toAddress, fromAddress, subject, body = data - dest = shared.safeConfigGet("bitmessagesettings", "smtpdeliver", '') + dest = BMConfigParser().safeGet("bitmessagesettings", "smtpdeliver", '') if dest == '': continue try: @@ -57,7 +58,7 @@ class smtpDeliver(threading.Thread, StoppableThread): msg = MIMEText(body, 'plain', 'utf-8') msg['Subject'] = Header(subject, 'utf-8') 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: msg['To'] = "\"%s\" <%s>" % (Header(toLabel[0], 'utf-8'), toAddress + '@' + SMTPDOMAIN) else: diff --git a/src/class_smtpServer.py b/src/class_smtpServer.py index af3056be..4043600c 100644 --- a/src/class_smtpServer.py +++ b/src/class_smtpServer.py @@ -10,11 +10,13 @@ import threading import time from addresses import decodeAddress +from configparser import BMConfigParser from debug import logger from helper_sql import sqlExecute from helper_threading import StoppableThread from pyelliptic.openssl import OpenSSL import shared +from version import softwareVersion SMTPDOMAIN = "bmaddr.lan" LISTENPORT = 8425 @@ -24,7 +26,7 @@ class smtpServerChannel(smtpd.SMTPChannel): if not arg: self.push('501 Syntax: HELO hostname') return - self.push('250-PyBitmessage %s' % shared.softwareVersion) + self.push('250-PyBitmessage %s' % softwareVersion) self.push('250 AUTH PLAIN') def smtp_AUTH(self, arg): @@ -34,8 +36,8 @@ class smtpServerChannel(smtpd.SMTPChannel): authstring = arg[6:] try: decoded = base64.b64decode(authstring) - correctauth = "\x00" + shared.safeConfigGet("bitmessagesettings", "smtpdusername", "") + \ - "\x00" + shared.safeConfigGet("bitmessagesettings", "smtpdpassword", "") + correctauth = "\x00" + BMConfigParser().safeGet("bitmessagesettings", "smtpdusername", "") + \ + "\x00" + BMConfigParser().safeGet("bitmessagesettings", "smtpdpassword", "") logger.debug("authstring: %s / %s", correctauth, decoded) if correctauth == decoded: self.auth = True @@ -80,7 +82,7 @@ class smtpServerPyBitmessage(smtpd.SMTPServer): 0, # retryNumber 'sent', # folder 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)) @@ -112,7 +114,7 @@ class smtpServerPyBitmessage(smtpd.SMTPServer): sender, domain = p.sub(r'\1', mailfrom).split("@") if domain != SMTPDOMAIN: 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) except Exception as err: logger.debug("Bad envelope from %s: %s", mailfrom, repr(err)) @@ -122,7 +124,7 @@ class smtpServerPyBitmessage(smtpd.SMTPServer): sender, domain = msg_from.split("@") if domain != SMTPDOMAIN: 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) except Exception as err: logger.error("Bad headers from %s: %s", msg_from, repr(err)) @@ -163,7 +165,7 @@ class smtpServer(threading.Thread, StoppableThread): self.server.close() return 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'): try: s.connect((ip, LISTENPORT)) diff --git a/src/class_sqlThread.py b/src/class_sqlThread.py index 9d45cdcf..320f6315 100644 --- a/src/class_sqlThread.py +++ b/src/class_sqlThread.py @@ -1,4 +1,5 @@ import threading +from configparser import BMConfigParser import shared import sqlite3 import time @@ -65,35 +66,35 @@ class sqlThread(threading.Thread): 'ERROR trying to create database file (message.dat). Error message: %s\n' % str(err)) os._exit(0) - if shared.config.getint('bitmessagesettings', 'settingsversion') == 1: - shared.config.set('bitmessagesettings', 'settingsversion', '2') + if BMConfigParser().getint('bitmessagesettings', 'settingsversion') == 1: + BMConfigParser().set('bitmessagesettings', 'settingsversion', '2') # If the settings version is equal to 2 or 3 then the # sqlThread will modify the pubkeys table and change # the settings version to 4. - shared.config.set('bitmessagesettings', 'socksproxytype', 'none') - shared.config.set('bitmessagesettings', 'sockshostname', 'localhost') - shared.config.set('bitmessagesettings', 'socksport', '9050') - shared.config.set('bitmessagesettings', 'socksauthentication', 'false') - shared.config.set('bitmessagesettings', 'socksusername', '') - shared.config.set('bitmessagesettings', 'sockspassword', '') - shared.config.set('bitmessagesettings', 'sockslisten', 'false') - shared.config.set('bitmessagesettings', 'keysencrypted', 'false') - shared.config.set('bitmessagesettings', 'messagesencrypted', 'false') + BMConfigParser().set('bitmessagesettings', 'socksproxytype', 'none') + BMConfigParser().set('bitmessagesettings', 'sockshostname', 'localhost') + BMConfigParser().set('bitmessagesettings', 'socksport', '9050') + BMConfigParser().set('bitmessagesettings', 'socksauthentication', 'false') + BMConfigParser().set('bitmessagesettings', 'socksusername', '') + BMConfigParser().set('bitmessagesettings', 'sockspassword', '') + BMConfigParser().set('bitmessagesettings', 'sockslisten', 'false') + BMConfigParser().set('bitmessagesettings', 'keysencrypted', 'false') + BMConfigParser().set('bitmessagesettings', 'messagesencrypted', 'false') # People running earlier versions of PyBitmessage do not have the # 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' ''' parameters = '' self.cur.execute(item, parameters) self.conn.commit() - shared.config.set('bitmessagesettings', 'settingsversion', '3') + BMConfigParser().set('bitmessagesettings', 'settingsversion', '3') # People running earlier versions of PyBitmessage do not have the # encodingtype field in their inbox and sent tables or the read field # 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' ''' parameters = '' self.cur.execute(item, parameters) @@ -107,21 +108,21 @@ class sqlThread(threading.Thread): self.cur.execute(item, parameters) self.conn.commit() - shared.config.set('bitmessagesettings', 'settingsversion', '4') + BMConfigParser().set('bitmessagesettings', 'settingsversion', '4') - if shared.config.getint('bitmessagesettings', 'settingsversion') == 4: - shared.config.set('bitmessagesettings', 'defaultnoncetrialsperbyte', str( + if BMConfigParser().getint('bitmessagesettings', 'settingsversion') == 4: + BMConfigParser().set('bitmessagesettings', 'defaultnoncetrialsperbyte', str( shared.networkDefaultProofOfWorkNonceTrialsPerByte)) - shared.config.set('bitmessagesettings', 'defaultpayloadlengthextrabytes', str( + BMConfigParser().set('bitmessagesettings', 'defaultpayloadlengthextrabytes', str( shared.networkDefaultPayloadLengthExtraBytes)) - shared.config.set('bitmessagesettings', 'settingsversion', '5') + BMConfigParser().set('bitmessagesettings', 'settingsversion', '5') - if shared.config.getint('bitmessagesettings', 'settingsversion') == 5: - shared.config.set( + if BMConfigParser().getint('bitmessagesettings', 'settingsversion') == 5: + BMConfigParser().set( 'bitmessagesettings', 'maxacceptablenoncetrialsperbyte', '0') - shared.config.set( + BMConfigParser().set( '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 # file so that when we make changes to the database, the database @@ -174,8 +175,8 @@ class sqlThread(threading.Thread): '''update sent set status='broadcastqueued' where status='broadcastpending' ''') self.conn.commit() - if not shared.config.has_option('bitmessagesettings', 'sockslisten'): - shared.config.set('bitmessagesettings', 'sockslisten', 'false') + if not BMConfigParser().has_option('bitmessagesettings', 'sockslisten'): + BMConfigParser().set('bitmessagesettings', 'sockslisten', 'false') ensureNamecoinOptions() @@ -226,18 +227,18 @@ class sqlThread(threading.Thread): parameters = (4,) self.cur.execute(item, parameters) - if not shared.config.has_option('bitmessagesettings', 'userlocale'): - shared.config.set('bitmessagesettings', 'userlocale', 'system') - if not shared.config.has_option('bitmessagesettings', 'sendoutgoingconnections'): - shared.config.set('bitmessagesettings', 'sendoutgoingconnections', 'True') + if not BMConfigParser().has_option('bitmessagesettings', 'userlocale'): + BMConfigParser().set('bitmessagesettings', 'userlocale', 'system') + if not BMConfigParser().has_option('bitmessagesettings', 'sendoutgoingconnections'): + BMConfigParser().set('bitmessagesettings', 'sendoutgoingconnections', 'True') # Raise the default required difficulty from 1 to 2 # 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: shared.config.set('bitmessagesettings','defaultnoncetrialsperbyte', str(shared.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. # We're going to trash all of our pubkeys and let them be redownloaded. @@ -255,18 +256,18 @@ class sqlThread(threading.Thread): parameters = (5,) self.cur.execute(item, parameters) - if not shared.config.has_option('bitmessagesettings', 'useidenticons'): - shared.config.set('bitmessagesettings', 'useidenticons', 'True') - if not shared.config.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 + if not BMConfigParser().has_option('bitmessagesettings', 'useidenticons'): + BMConfigParser().set('bitmessagesettings', 'useidenticons', 'True') + if not BMConfigParser().has_option('bitmessagesettings', 'identiconsuffix'): # acts as a salt + 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 - if shared.config.getint('bitmessagesettings', 'settingsversion') == 7: - shared.config.set( + if BMConfigParser().getint('bitmessagesettings', 'settingsversion') == 7: + BMConfigParser().set( 'bitmessagesettings', 'stopresendingafterxdays', '') - shared.config.set( + BMConfigParser().set( 'bitmessagesettings', 'stopresendingafterxmonths', '') - shared.config.set('bitmessagesettings', 'settingsversion', '8') + BMConfigParser().set('bitmessagesettings', 'settingsversion', '8') # Add a new table: objectprocessorqueue with which to hold objects # that have yet to be processed if the user shuts down Bitmessage. @@ -300,39 +301,39 @@ class sqlThread(threading.Thread): logger.debug('Finished dropping and recreating the inventory table.') # With the change to protocol version 3, reset the user-settable difficulties to 1 - if shared.config.getint('bitmessagesettings', 'settingsversion') == 8: - shared.config.set('bitmessagesettings','defaultnoncetrialsperbyte', str(shared.networkDefaultProofOfWorkNonceTrialsPerByte)) - shared.config.set('bitmessagesettings','defaultpayloadlengthextrabytes', str(shared.networkDefaultPayloadLengthExtraBytes)) - previousTotalDifficulty = int(shared.config.getint('bitmessagesettings', 'maxacceptablenoncetrialsperbyte')) / 320 - previousSmallMessageDifficulty = int(shared.config.getint('bitmessagesettings', 'maxacceptablepayloadlengthextrabytes')) / 14000 - shared.config.set('bitmessagesettings','maxacceptablenoncetrialsperbyte', str(previousTotalDifficulty * 1000)) - shared.config.set('bitmessagesettings','maxacceptablepayloadlengthextrabytes', str(previousSmallMessageDifficulty * 1000)) - shared.config.set('bitmessagesettings', 'settingsversion', '9') + if BMConfigParser().getint('bitmessagesettings', 'settingsversion') == 8: + BMConfigParser().set('bitmessagesettings','defaultnoncetrialsperbyte', str(shared.networkDefaultProofOfWorkNonceTrialsPerByte)) + BMConfigParser().set('bitmessagesettings','defaultpayloadlengthextrabytes', str(shared.networkDefaultPayloadLengthExtraBytes)) + previousTotalDifficulty = int(BMConfigParser().getint('bitmessagesettings', 'maxacceptablenoncetrialsperbyte')) / 320 + previousSmallMessageDifficulty = int(BMConfigParser().getint('bitmessagesettings', 'maxacceptablepayloadlengthextrabytes')) / 14000 + BMConfigParser().set('bitmessagesettings','maxacceptablenoncetrialsperbyte', str(previousTotalDifficulty * 1000)) + BMConfigParser().set('bitmessagesettings','maxacceptablepayloadlengthextrabytes', str(previousSmallMessageDifficulty * 1000)) + BMConfigParser().set('bitmessagesettings', 'settingsversion', '9') # 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: - for addressInKeysFile in shared.config.sections(): + if BMConfigParser().getint('bitmessagesettings', 'settingsversion') == 9: + for addressInKeysFile in BMConfigParser().sections(): try: - previousTotalDifficulty = float(shared.config.getint(addressInKeysFile, 'noncetrialsperbyte')) / 320 - previousSmallMessageDifficulty = float(shared.config.getint(addressInKeysFile, 'payloadlengthextrabytes')) / 14000 + previousTotalDifficulty = float(BMConfigParser().getint(addressInKeysFile, 'noncetrialsperbyte')) / 320 + previousSmallMessageDifficulty = float(BMConfigParser().getint(addressInKeysFile, 'payloadlengthextrabytes')) / 14000 if previousTotalDifficulty <= 2: previousTotalDifficulty = 1 if previousSmallMessageDifficulty < 1: previousSmallMessageDifficulty = 1 - shared.config.set(addressInKeysFile,'noncetrialsperbyte', str(int(previousTotalDifficulty * 1000))) - shared.config.set(addressInKeysFile,'payloadlengthextrabytes', str(int(previousSmallMessageDifficulty * 1000))) + BMConfigParser().set(addressInKeysFile,'noncetrialsperbyte', str(int(previousTotalDifficulty * 1000))) + BMConfigParser().set(addressInKeysFile,'payloadlengthextrabytes', str(int(previousSmallMessageDifficulty * 1000))) except: continue - shared.config.set('bitmessagesettings', 'maxdownloadrate', '0') - shared.config.set('bitmessagesettings', 'maxuploadrate', '0') - shared.config.set('bitmessagesettings', 'settingsversion', '10') + BMConfigParser().set('bitmessagesettings', 'maxdownloadrate', '0') + BMConfigParser().set('bitmessagesettings', 'maxuploadrate', '0') + BMConfigParser().set('bitmessagesettings', 'settingsversion', '10') shared.writeKeysFile() # sanity check - if shared.config.getint('bitmessagesettings', 'maxacceptablenoncetrialsperbyte') == 0: - shared.config.set('bitmessagesettings','maxacceptablenoncetrialsperbyte', str(shared.ridiculousDifficulty * shared.networkDefaultProofOfWorkNonceTrialsPerByte)) - if shared.config.getint('bitmessagesettings', 'maxacceptablepayloadlengthextrabytes') == 0: - shared.config.set('bitmessagesettings','maxacceptablepayloadlengthextrabytes', str(shared.ridiculousDifficulty * shared.networkDefaultPayloadLengthExtraBytes)) + if BMConfigParser().getint('bitmessagesettings', 'maxacceptablenoncetrialsperbyte') == 0: + BMConfigParser().set('bitmessagesettings','maxacceptablenoncetrialsperbyte', str(shared.ridiculousDifficulty * shared.networkDefaultProofOfWorkNonceTrialsPerByte)) + if BMConfigParser().getint('bitmessagesettings', 'maxacceptablepayloadlengthextrabytes') == 0: + BMConfigParser().set('bitmessagesettings','maxacceptablepayloadlengthextrabytes', str(shared.ridiculousDifficulty * shared.networkDefaultPayloadLengthExtraBytes)) # 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. @@ -371,8 +372,8 @@ class sqlThread(threading.Thread): self.cur.execute(item, parameters) # TTL is now user-specifiable. Let's add an option to save whatever the user selects. - if not shared.config.has_option('bitmessagesettings', 'ttl'): - shared.config.set('bitmessagesettings', 'ttl', '367200') + if not BMConfigParser().has_option('bitmessagesettings', 'ttl'): + BMConfigParser().set('bitmessagesettings', 'ttl', '367200') # We'll also need a `sleeptill` field and a `ttl` field. Also we can combine # the pubkeyretrynumber and msgretrynumber into one. item = '''SELECT value FROM settings WHERE key='version';''' @@ -419,16 +420,16 @@ class sqlThread(threading.Thread): 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';''') - if not shared.config.has_option('bitmessagesettings', 'onionhostname'): - shared.config.set('bitmessagesettings', 'onionhostname', '') - if not shared.config.has_option('bitmessagesettings', 'onionport'): - shared.config.set('bitmessagesettings', 'onionport', '8444') - if not shared.config.has_option('bitmessagesettings', 'onionbindip'): - shared.config.set('bitmessagesettings', 'onionbindip', '127.0.0.1') - if not shared.config.has_option('bitmessagesettings', 'smtpdeliver'): - shared.config.set('bitmessagesettings', 'smtpdeliver', '') - if not shared.config.has_option('bitmessagesettings', 'hidetrayconnectionnotifications'): - shared.config.set('bitmessagesettings', 'hidetrayconnectionnotifications', 'false') + if not BMConfigParser().has_option('bitmessagesettings', 'onionhostname'): + BMConfigParser().set('bitmessagesettings', 'onionhostname', '') + if not BMConfigParser().has_option('bitmessagesettings', 'onionport'): + BMConfigParser().set('bitmessagesettings', 'onionport', '8444') + if not BMConfigParser().has_option('bitmessagesettings', 'onionbindip'): + BMConfigParser().set('bitmessagesettings', 'onionbindip', '127.0.0.1') + if not BMConfigParser().has_option('bitmessagesettings', 'smtpdeliver'): + BMConfigParser().set('bitmessagesettings', 'smtpdeliver', '') + if not BMConfigParser().has_option('bitmessagesettings', 'hidetrayconnectionnotifications'): + BMConfigParser().set('bitmessagesettings', 'hidetrayconnectionnotifications', 'false') shared.writeKeysFile() # Are you hoping to add a new option to the keys.dat file of existing diff --git a/src/configparser.py b/src/configparser.py index 900bef50..7a4258be 100644 --- a/src/configparser.py +++ b/src/configparser.py @@ -1,5 +1,9 @@ import ConfigParser +from singleton import Singleton + + +@Singleton class BMConfigParser(ConfigParser.SafeConfigParser): def set(self, section, option, value=None): 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) + 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): return ConfigParser.ConfigParser.items(self, section, True, vars) diff --git a/src/helper_bootstrap.py b/src/helper_bootstrap.py index 82f5b5bc..44bd190a 100644 --- a/src/helper_bootstrap.py +++ b/src/helper_bootstrap.py @@ -4,6 +4,7 @@ import defaultKnownNodes import pickle import time +from configparser import BMConfigParser from debug import logger import socks @@ -29,9 +30,9 @@ def knownNodes(): except: shared.knownNodes = defaultKnownNodes.createDefaultKnownNodes(shared.appdata) # your own onion address, if setup - if shared.config.has_option('bitmessagesettings', 'onionhostname') and ".onion" in shared.config.get('bitmessagesettings', 'onionhostname'): - shared.knownNodes[1][shared.Peer(shared.config.get('bitmessagesettings', 'onionhostname'), shared.config.getint('bitmessagesettings', 'onionport'))] = int(time.time()) - if shared.config.getint('bitmessagesettings', 'settingsversion') > 10: + if BMConfigParser().has_option('bitmessagesettings', 'onionhostname') and ".onion" in BMConfigParser().get('bitmessagesettings', 'onionhostname'): + shared.knownNodes[1][shared.Peer(BMConfigParser().get('bitmessagesettings', 'onionhostname'), BMConfigParser().getint('bitmessagesettings', 'onionport'))] = int(time.time()) + 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.') raise SystemExit @@ -41,7 +42,7 @@ def dns(): # defaultKnownNodes.py. Hopefully either they are up to date or the user # has run Bitmessage recently without SOCKS turned on and received good # bootstrap nodes using that method. - if shared.config.get('bitmessagesettings', 'socksproxytype') == 'none': + if BMConfigParser().get('bitmessagesettings', 'socksproxytype') == 'none': try: for item in socket.getaddrinfo('bootstrap8080.bitmessage.org', 80): logger.info('Adding ' + item[4][0] + ' to knownNodes based on DNS bootstrap method') @@ -54,7 +55,7 @@ def dns(): shared.knownNodes[1][shared.Peer(item[4][0], 8444)] = int(time.time()) except: 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()) logger.debug("Adding quzwelsuziwqgpt2.onion:8444 to knownNodes.") for port in [8080, 8444]: @@ -64,15 +65,15 @@ def dns(): sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) sock.settimeout(20) proxytype = socks.PROXY_TYPE_SOCKS5 - sockshostname = shared.config.get( + sockshostname = BMConfigParser().get( 'bitmessagesettings', 'sockshostname') - socksport = shared.config.getint( + socksport = BMConfigParser().getint( 'bitmessagesettings', 'socksport') rdns = True # Do domain name lookups through the proxy; though this setting doesn't really matter since we won't be doing any domain name lookups anyway. - if shared.config.getboolean('bitmessagesettings', 'socksauthentication'): - socksusername = shared.config.get( + if BMConfigParser().getboolean('bitmessagesettings', 'socksauthentication'): + socksusername = BMConfigParser().get( 'bitmessagesettings', 'socksusername') - sockspassword = shared.config.get( + sockspassword = BMConfigParser().get( 'bitmessagesettings', 'sockspassword') sock.setproxy( proxytype, sockshostname, socksport, rdns, socksusername, sockspassword) diff --git a/src/helper_generic.py b/src/helper_generic.py index 5997a8ca..a36c273e 100644 --- a/src/helper_generic.py +++ b/src/helper_generic.py @@ -5,6 +5,7 @@ from binascii import hexlify, unhexlify from multiprocessing import current_process from threading import current_thread, enumerate +from configparser import BMConfigParser from debug import logger import shared @@ -51,7 +52,7 @@ def signal_handler(signal, frame): if current_thread().name != "MainThread": return logger.error("Got signal %i", signal) - if shared.safeConfigGetBoolean('bitmessagesettings', 'daemon'): + if BMConfigParser().safeGetBoolean('bitmessagesettings', 'daemon'): shared.doCleanShutdown() else: print 'Unfortunately you cannot use Ctrl+C when running the UI because the UI captures the signal.' diff --git a/src/helper_startup.py b/src/helper_startup.py index cc74649a..d685882e 100644 --- a/src/helper_startup.py +++ b/src/helper_startup.py @@ -1,5 +1,6 @@ -import shared import ConfigParser +import shared +from configparser import BMConfigParser import sys import os import locale @@ -14,7 +15,7 @@ storeConfigFilesInSameDirectoryAsProgramByDefault = False # The user may de-sel def _loadTrustedPeer(): try: - trustedPeer = shared.config.get('bitmessagesettings', 'trustedpeer') + trustedPeer = BMConfigParser().get('bitmessagesettings', 'trustedpeer') except ConfigParser.Error: # This probably means the trusted peer wasn't specified so we # can just leave it as None @@ -25,19 +26,19 @@ def _loadTrustedPeer(): def loadConfig(): if shared.appdata: - shared.config.read(shared.appdata + 'keys.dat') + BMConfigParser().read(shared.appdata + 'keys.dat') #shared.appdata must have been specified as a startup option. try: - shared.config.get('bitmessagesettings', 'settingsversion') + BMConfigParser().get('bitmessagesettings', 'settingsversion') print 'Loading config files from directory specified on startup: ' + shared.appdata needToCreateKeysFile = False except: needToCreateKeysFile = True else: - shared.config.read(shared.lookupExeFolder() + 'keys.dat') + BMConfigParser().read(shared.lookupExeFolder() + 'keys.dat') try: - shared.config.get('bitmessagesettings', 'settingsversion') + BMConfigParser().get('bitmessagesettings', 'settingsversion') print 'Loading config files from same directory as program.' needToCreateKeysFile = False shared.appdata = shared.lookupExeFolder() @@ -45,9 +46,9 @@ def loadConfig(): # Could not load the keys.dat file in the program directory. Perhaps it # is in the appdata directory. shared.appdata = shared.lookupAppdataFolder() - shared.config.read(shared.appdata + 'keys.dat') + BMConfigParser().read(shared.appdata + 'keys.dat') try: - shared.config.get('bitmessagesettings', 'settingsversion') + BMConfigParser().get('bitmessagesettings', 'settingsversion') print 'Loading existing config files from', shared.appdata needToCreateKeysFile = False except: @@ -56,62 +57,62 @@ def loadConfig(): if needToCreateKeysFile: # This appears to be the first time running the program; there is # no config file (or it cannot be accessed). Create config file. - shared.config.add_section('bitmessagesettings') - shared.config.set('bitmessagesettings', 'settingsversion', '10') - shared.config.set('bitmessagesettings', 'port', '8444') - shared.config.set( + BMConfigParser().add_section('bitmessagesettings') + BMConfigParser().set('bitmessagesettings', 'settingsversion', '10') + BMConfigParser().set('bitmessagesettings', 'port', '8444') + BMConfigParser().set( 'bitmessagesettings', 'timeformat', '%%c') - shared.config.set('bitmessagesettings', 'blackwhitelist', 'black') - shared.config.set('bitmessagesettings', 'startonlogon', 'false') + BMConfigParser().set('bitmessagesettings', 'blackwhitelist', 'black') + BMConfigParser().set('bitmessagesettings', 'startonlogon', 'false') if 'linux' in sys.platform: - shared.config.set( + BMConfigParser().set( 'bitmessagesettings', 'minimizetotray', 'false') # This isn't implimented yet and when True on # Ubuntu causes Bitmessage to disappear while # running when minimized. else: - shared.config.set( + BMConfigParser().set( 'bitmessagesettings', 'minimizetotray', 'true') - shared.config.set( + BMConfigParser().set( 'bitmessagesettings', 'showtraynotifications', 'true') - shared.config.set('bitmessagesettings', 'startintray', 'false') - shared.config.set('bitmessagesettings', 'socksproxytype', 'none') - shared.config.set( + BMConfigParser().set('bitmessagesettings', 'startintray', 'false') + BMConfigParser().set('bitmessagesettings', 'socksproxytype', 'none') + BMConfigParser().set( 'bitmessagesettings', 'sockshostname', 'localhost') - shared.config.set('bitmessagesettings', 'socksport', '9050') - shared.config.set( + BMConfigParser().set('bitmessagesettings', 'socksport', '9050') + BMConfigParser().set( 'bitmessagesettings', 'socksauthentication', 'false') - shared.config.set( + BMConfigParser().set( 'bitmessagesettings', 'sockslisten', 'false') - shared.config.set('bitmessagesettings', 'socksusername', '') - shared.config.set('bitmessagesettings', 'sockspassword', '') - shared.config.set('bitmessagesettings', 'keysencrypted', 'false') - shared.config.set( + BMConfigParser().set('bitmessagesettings', 'socksusername', '') + BMConfigParser().set('bitmessagesettings', 'sockspassword', '') + BMConfigParser().set('bitmessagesettings', 'keysencrypted', 'false') + BMConfigParser().set( 'bitmessagesettings', 'messagesencrypted', 'false') - shared.config.set('bitmessagesettings', 'defaultnoncetrialsperbyte', str( + BMConfigParser().set('bitmessagesettings', 'defaultnoncetrialsperbyte', str( shared.networkDefaultProofOfWorkNonceTrialsPerByte)) - shared.config.set('bitmessagesettings', 'defaultpayloadlengthextrabytes', str( + BMConfigParser().set('bitmessagesettings', 'defaultpayloadlengthextrabytes', str( shared.networkDefaultPayloadLengthExtraBytes)) - shared.config.set('bitmessagesettings', 'minimizeonclose', 'false') - shared.config.set( + BMConfigParser().set('bitmessagesettings', 'minimizeonclose', 'false') + BMConfigParser().set( 'bitmessagesettings', 'maxacceptablenoncetrialsperbyte', '0') - shared.config.set( + BMConfigParser().set( 'bitmessagesettings', 'maxacceptablepayloadlengthextrabytes', '0') - shared.config.set('bitmessagesettings', 'dontconnect', 'true') - shared.config.set('bitmessagesettings', 'userlocale', 'system') - shared.config.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 - shared.config.set('bitmessagesettings', 'replybelow', 'False') - shared.config.set('bitmessagesettings', 'maxdownloadrate', '0') - shared.config.set('bitmessagesettings', 'maxuploadrate', '0') - shared.config.set('bitmessagesettings', 'ttl', '367200') + BMConfigParser().set('bitmessagesettings', 'dontconnect', 'true') + BMConfigParser().set('bitmessagesettings', 'userlocale', 'system') + BMConfigParser().set('bitmessagesettings', 'useidenticons', 'True') + BMConfigParser().set('bitmessagesettings', 'identiconsuffix', ''.join(random.choice("123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz") for x in range(12))) # a twelve character pseudo-password to salt the identicons + BMConfigParser().set('bitmessagesettings', 'replybelow', 'False') + BMConfigParser().set('bitmessagesettings', 'maxdownloadrate', '0') + BMConfigParser().set('bitmessagesettings', 'maxuploadrate', '0') + BMConfigParser().set('bitmessagesettings', 'ttl', '367200') #start:UI setting to stop trying to send messages after X days/months - shared.config.set( + BMConfigParser().set( 'bitmessagesettings', 'stopresendingafterxdays', '') - shared.config.set( + BMConfigParser().set( 'bitmessagesettings', 'stopresendingafterxmonths', '') - #shared.config.set( + #BMConfigParser().set( # 'bitmessagesettings', 'timeperiod', '-1') #end diff --git a/src/l10n.py b/src/l10n.py index 0300085a..f8b72650 100644 --- a/src/l10n.py +++ b/src/l10n.py @@ -3,6 +3,7 @@ import logging import os import time +from configparser import BMConfigParser import shared @@ -48,8 +49,8 @@ except: logger.exception('Could not determine language or encoding') -if shared.config.has_option('bitmessagesettings', 'timeformat'): - time_format = shared.config.get('bitmessagesettings', 'timeformat') +if BMConfigParser().has_option('bitmessagesettings', 'timeformat'): + time_format = BMConfigParser().get('bitmessagesettings', 'timeformat') #Test the format string try: time.strftime(time_format) @@ -112,8 +113,8 @@ def formatTimestamp(timestamp = None, as_unicode = True): def getTranslationLanguage(): userlocale = None - if shared.config.has_option('bitmessagesettings', 'userlocale'): - userlocale = shared.config.get('bitmessagesettings', 'userlocale') + if BMConfigParser().has_option('bitmessagesettings', 'userlocale'): + userlocale = BMConfigParser().get('bitmessagesettings', 'userlocale') if userlocale in [None, '', 'system']: return language diff --git a/src/namecoin.py b/src/namecoin.py index 5b50bb67..7fca0162 100644 --- a/src/namecoin.py +++ b/src/namecoin.py @@ -26,6 +26,7 @@ import socket import sys import os +from configparser import BMConfigParser import shared import tr # translate @@ -63,11 +64,11 @@ class namecoinConnection (object): # actually changing the values (yet). def __init__ (self, options = None): if options is None: - self.nmctype = shared.config.get (configSection, "namecoinrpctype") - self.host = shared.config.get (configSection, "namecoinrpchost") - self.port = int(shared.config.get (configSection, "namecoinrpcport")) - self.user = shared.config.get (configSection, "namecoinrpcuser") - self.password = shared.config.get (configSection, + self.nmctype = BMConfigParser().get (configSection, "namecoinrpctype") + self.host = BMConfigParser().get (configSection, "namecoinrpchost") + self.port = int(BMConfigParser().get (configSection, "namecoinrpcport")) + self.user = BMConfigParser().get (configSection, "namecoinrpcuser") + self.password = BMConfigParser().get (configSection, "namecoinrpcpassword") else: self.nmctype = options["type"] @@ -261,14 +262,14 @@ def lookupNamecoinFolder (): # Ensure all namecoin options are set, by setting those to default values # that aren't there. def ensureNamecoinOptions (): - if not shared.config.has_option (configSection, "namecoinrpctype"): - shared.config.set (configSection, "namecoinrpctype", "namecoind") - if not shared.config.has_option (configSection, "namecoinrpchost"): - shared.config.set (configSection, "namecoinrpchost", "localhost") + if not BMConfigParser().has_option (configSection, "namecoinrpctype"): + BMConfigParser().set (configSection, "namecoinrpctype", "namecoind") + if not BMConfigParser().has_option (configSection, "namecoinrpchost"): + BMConfigParser().set (configSection, "namecoinrpchost", "localhost") - hasUser = shared.config.has_option (configSection, "namecoinrpcuser") - hasPass = shared.config.has_option (configSection, "namecoinrpcpassword") - hasPort = shared.config.has_option (configSection, "namecoinrpcport") + hasUser = BMConfigParser().has_option (configSection, "namecoinrpcuser") + hasPass = BMConfigParser().has_option (configSection, "namecoinrpcpassword") + hasPort = BMConfigParser().has_option (configSection, "namecoinrpcport") # Try to read user/password from .namecoin configuration file. defaultUser = "" @@ -302,11 +303,11 @@ def ensureNamecoinOptions (): # If still nothing found, set empty at least. if (not hasUser): - shared.config.set (configSection, "namecoinrpcuser", defaultUser) + BMConfigParser().set (configSection, "namecoinrpcuser", defaultUser) if (not hasPass): - shared.config.set (configSection, "namecoinrpcpassword", defaultPass) + BMConfigParser().set (configSection, "namecoinrpcpassword", defaultPass) # Set default port now, possibly to found value. if (not hasPort): - shared.config.set (configSection, "namecoinrpcport", + BMConfigParser().set (configSection, "namecoinrpcport", shared.namecoinDefaultRpcPort) diff --git a/src/openclpow.py b/src/openclpow.py index 641db324..766cbffe 100644 --- a/src/openclpow.py +++ b/src/openclpow.py @@ -5,7 +5,8 @@ import hashlib import random import os -from shared import codePath, safeConfigGetBoolean, safeConfigGet, shutdown +from configparser import BMConfigParser +from shared import codePath, shutdown from debug import logger libAvailable = True @@ -30,7 +31,7 @@ def initCL(): try: for platform in cl.get_platforms(): 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)) if platform.vendor not in vendors: vendors.append(platform.vendor) diff --git a/src/proofofwork.py b/src/proofofwork.py index 4bb02fd7..244f268c 100644 --- a/src/proofofwork.py +++ b/src/proofofwork.py @@ -6,6 +6,7 @@ from struct import unpack, pack from subprocess import call import sys import time +from configparser import BMConfigParser from debug import logger import shared import openclpow @@ -58,7 +59,7 @@ def _doFastPoW(target, initialHash): except: pool_size = 4 try: - maxCores = shared.config.getint('bitmessagesettings', 'maxcores') + maxCores = BMConfigParser().getint('bitmessagesettings', 'maxcores') except: maxCores = 99999 if pool_size > maxCores: diff --git a/src/protocol.py b/src/protocol.py index 40feaaf4..ecc0f8cc 100644 --- a/src/protocol.py +++ b/src/protocol.py @@ -1,14 +1,454 @@ -import struct -import shared +import base64 +import hashlib +import random +import socket +import ssl +from struct import pack, unpack, Struct +import sys +import time + +from addresses import encodeVarint, decodeVarint +from configparser import BMConfigParser +from state import neededPubkeys, extPort, socksIP +from version import softwareVersion + +#Service flags +NODE_NETWORK = 1 +NODE_SSL = 2 + +#Bitfield flags +BITFIELD_DOESACK = 1 + +eightBytesOfRandomDataUsedToDetectConnectionsToSelf = pack( + '>Q', random.randrange(1, 18446744073709551615)) + +#Compiled struct for packing/unpacking headers +#New code should use CreatePacket instead of Header.pack +Header = Struct('!L12sL4s') + +# Bitfield def getBitfield(address): # bitfield of features supported by me (see the wiki). bitfield = 0 # send ack - if not shared.safeConfigGetBoolean(address, 'dontsendack'): - bitfield |= shared.BITFIELD_DOESACK - return struct.pack('>I', bitfield) + if not BMConfigParser().safeGetBoolean(address, 'dontsendack'): + bitfield |= BITFIELD_DOESACK + return pack('>I', bitfield) def checkBitfield(bitfieldBinary, flags): - bitfield, = struct.unpack('>I', bitfieldBinary) - return (bitfield & flags) == flags \ No newline at end of file + bitfield, = unpack('>I', bitfieldBinary) + 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 socksIP is None or not socksIP: + socksIP = socket.gethostbyname(BMConfigParser().get("bitmessagesettings", "sockshostname")) + except NameError: + socksIP = socket.gethostbyname(BMConfigParser().get("bitmessagesettings", "sockshostname")) + return socksIP == host + +# 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 extPort \ + and ((server and not checkSocksIP(remoteHost)) or \ + (BMConfigParser().get("bitmessagesettings", "socksproxytype") == "none" and not server)): + payload += pack('>H', 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 = 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 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 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 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 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 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)) + diff --git a/src/shared.py b/src/shared.py index 6bbb28ae..7f8aca53 100644 --- a/src/shared.py +++ b/src/shared.py @@ -1,6 +1,5 @@ from __future__ import division -softwareVersion = '0.6.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. 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. @@ -24,7 +23,6 @@ import time import shutil # used for moving the data folder and copying keys.dat import datetime from os import path, environ -from struct import Struct import traceback from binascii import hexlify @@ -40,7 +38,6 @@ from helper_threading import * from inventory import Inventory -config = BMConfigParser() myECCryptorObjects = {} MyECSubscriptionCryptorObjects = {} myAddressesByHash = {} #The key in this dictionary is the RIPE hash which is encoded in an address and value is the address itself. @@ -68,9 +65,6 @@ alreadyAttemptedConnectionsListLock = threading.Lock() 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. numberOfObjectsThatWeHaveYetToGetPerPeer = {} -neededPubkeys = {} -eightBytesOfRandomDataUsedToDetectConnectionsToSelf = pack( - '>Q', random.randrange(1, 18446744073709551615)) successfullyDecryptMessageTimings = [ ] # A list of the amounts of time it took to successfully decrypt msg messages apiAddressGeneratorReturnQueue = Queue.Queue( @@ -125,109 +119,6 @@ frozen = getattr(sys,'frozen', None) # security. 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 - -#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": @@ -318,18 +209,6 @@ def isAddressInMyAddressBookSubscriptionsListOrWhitelist(address): return True 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): fullString = arithmetic.changebase(WIFstring,58,256) privkey = fullString[:-4] @@ -358,11 +237,11 @@ def reloadMyAddressHashes(): #myPrivateKeys.clear() keyfileSecure = checkSensitiveFilePermissions(appdata + 'keys.dat') - configSections = config.sections() + configSections = BMConfigParser().sections() hasEnabledKeys = False for addressInKeysFile in configSections: if addressInKeysFile <> 'bitmessagesettings': - isEnabled = config.getboolean(addressInKeysFile, 'enabled') + isEnabled = BMConfigParser().getboolean(addressInKeysFile, 'enabled') if isEnabled: hasEnabledKeys = True status,addressVersionNumber,streamNumber,hash = decodeAddress(addressInKeysFile) @@ -370,7 +249,7 @@ def reloadMyAddressHashes(): # Returns a simple 32 bytes of information encoded in 64 Hex characters, # or null if there was an error. privEncryptionKey = hexlify(decodeWalletImportFormat( - config.get(addressInKeysFile, 'privencryptionkey'))) + BMConfigParser().get(addressInKeysFile, 'privencryptionkey'))) if len(privEncryptionKey) == 64:#It is 32 bytes encoded as 64 hex characters myECCryptorObjects[hash] = highlevelcrypto.makeCryptor(privEncryptionKey) @@ -473,7 +352,7 @@ def doCleanShutdown(): logger.debug("Waiting for thread %s", thread.name) thread.join() - if safeConfigGetBoolean('bitmessagesettings','daemon'): + if BMConfigParser().safeGetBoolean('bitmessagesettings','daemon'): logger.info('Clean shutdown complete.') thisapp.cleanup() os._exit(0) @@ -881,7 +760,7 @@ def writeKeysFile(): fileNameExisted = False # write the file with open(fileName, 'wb') as configfile: - shared.config.write(configfile) + BMConfigParser().write(configfile) # delete the backup if fileNameExisted: os.remove(fileNameBak) diff --git a/src/state.py b/src/state.py new file mode 100644 index 00000000..e3ff6289 --- /dev/null +++ b/src/state.py @@ -0,0 +1,7 @@ +neededPubkeys = {} + +# For UPnP +extPort = None + +# for Tor hidden service +socksIP = None diff --git a/src/tr.py b/src/tr.py index d61d6c34..b7a8e6f0 100644 --- a/src/tr.py +++ b/src/tr.py @@ -1,6 +1,8 @@ -import shared import os +from configparser import BMConfigParser +import shared + # 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: def __init__(self, context, text): @@ -16,7 +18,7 @@ def _translate(context, text, disambiguation = None, encoding = None, n = None): return translateText(context, text, n) def translateText(context, text, n = None): - if not shared.safeConfigGetBoolean('bitmessagesettings', 'daemon'): + if not BMConfigParser().safeGetBoolean('bitmessagesettings', 'daemon'): try: from PyQt4 import QtCore, QtGui except Exception as err: diff --git a/src/upnp.py b/src/upnp.py index 50b25b8e..fd6f3852 100644 --- a/src/upnp.py +++ b/src/upnp.py @@ -6,6 +6,7 @@ import socket from struct import unpack, pack import threading import time +from configparser import BMConfigParser from helper_threading import * import shared import tr @@ -175,9 +176,9 @@ class uPnPThread(threading.Thread, StoppableThread): def __init__ (self): threading.Thread.__init__(self, name="uPnPThread") - self.localPort = shared.config.getint('bitmessagesettings', 'port') + self.localPort = BMConfigParser().getint('bitmessagesettings', 'port') try: - self.extPort = shared.config.getint('bitmessagesettings', 'extport') + self.extPort = BMConfigParser().getint('bitmessagesettings', 'extport') except: self.extPort = None self.localIP = self.getLocalIP() @@ -195,7 +196,7 @@ class uPnPThread(threading.Thread, StoppableThread): logger.debug("Starting UPnP thread") logger.debug("Local IP: %s", self.localIP) 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: try: self.sendSearchRouter() @@ -203,7 +204,7 @@ class uPnPThread(threading.Thread, StoppableThread): pass lastSent = time.time() 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) if resp is None: continue @@ -279,7 +280,7 @@ class uPnPThread(threading.Thread, StoppableThread): router.AddPortMapping(extPort, self.localPort, localIP, 'TCP', 'BitMessage') shared.extPort = extPort self.extPort = extPort - shared.config.set('bitmessagesettings', 'extport', str(extPort)) + BMConfigParser().set('bitmessagesettings', 'extport', str(extPort)) break except UPnPError: logger.debug("UPnP error: ", exc_info=True) diff --git a/src/version.py b/src/version.py new file mode 100644 index 00000000..85210f5f --- /dev/null +++ b/src/version.py @@ -0,0 +1 @@ +softwareVersion = '0.6.1' From 5d2bebae28bb26d3ed9a02f4531d822d293848b3 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Wed, 11 Jan 2017 14:46:10 +0100 Subject: [PATCH 08/12] Add IPv4 multicast range to ignored addresses --- src/helper_generic.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/helper_generic.py b/src/helper_generic.py index a36c273e..9e2eb9ba 100644 --- a/src/helper_generic.py +++ b/src/helper_generic.py @@ -67,7 +67,7 @@ def isHostInPrivateIPRange(host): if (ord(hostAddr[0]) & 0xfe) == 0xfc: return False pass - else: + elif ".onion" not in host: if host[:3] == '10.': return True if host[:4] == '172.': @@ -76,6 +76,9 @@ def isHostInPrivateIPRange(host): return True if host[:8] == '192.168.': return True + # Multicast + if host[:3] >= 224 and host[:3] <= 239 and host[4] == '.': + return True return False def addDataPadding(data, desiredMsgLength = 12, paddingChar = '\x00'): From ac348e4e6b90fb6df85cbc6733020b6128555c66 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Wed, 11 Jan 2017 17:00:00 +0100 Subject: [PATCH 09/12] Fixes and refactoring - fixes errors introduced in the earlier refactoring - more variables moved to state.py - path finding functions moved to paths.py - remembers IPv6 network unreachable (in the future can be used to skip IPv6 for a while) --- src/api.py | 27 +++--- src/bitmessagecurses/__init__.py | 1 + src/bitmessagemain.py | 11 +-- src/bitmessageqt/__init__.py | 99 +++++++++++----------- src/bitmessageqt/bitmessageui.py | 1 - src/bitmessageqt/languagebox.py | 4 +- src/bitmessageqt/support.py | 10 ++- src/bitmessageqt/utils.py | 9 +- src/bitmessageqt/widgets.py | 4 +- src/class_addressGenerator.py | 8 +- src/class_objectProcessor.py | 2 +- src/class_outgoingSynSender.py | 6 ++ src/class_receiveDataThread.py | 10 ++- src/class_sendDataThread.py | 9 +- src/class_singleCleaner.py | 9 +- src/class_singleWorker.py | 40 ++++----- src/class_sqlThread.py | 28 ++++--- src/debug.py | 11 +-- src/helper_bootstrap.py | 5 +- src/helper_startup.py | 32 +++---- src/l10n.py | 1 - src/message_data_reader.py | 3 +- src/network/https.py | 3 +- src/openclpow.py | 5 +- src/paths.py | 70 ++++++++++++++++ src/proofofwork.py | 15 ++-- src/protocol.py | 59 +++++++++---- src/shared.py | 138 +++++-------------------------- src/singleinstance.py | 3 +- src/state.py | 7 ++ src/tr.py | 1 - 31 files changed, 334 insertions(+), 297 deletions(-) create mode 100644 src/paths.py diff --git a/src/api.py b/src/api.py index 276e397f..a3c80283 100644 --- a/src/api.py +++ b/src/api.py @@ -24,6 +24,7 @@ import helper_inbox import helper_sent import hashlib +import state from pyelliptic.openssl import OpenSSL from struct import pack @@ -251,15 +252,15 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): elif len(params) == 3: label, eighteenByteRipe, totalDifficulty = params nonceTrialsPerByte = int( - shared.networkDefaultProofOfWorkNonceTrialsPerByte * totalDifficulty) + protocol.networkDefaultProofOfWorkNonceTrialsPerByte * totalDifficulty) payloadLengthExtraBytes = BMConfigParser().get( 'bitmessagesettings', 'defaultpayloadlengthextrabytes') elif len(params) == 4: label, eighteenByteRipe, totalDifficulty, smallMessageDifficulty = params nonceTrialsPerByte = int( - shared.networkDefaultProofOfWorkNonceTrialsPerByte * totalDifficulty) + protocol.networkDefaultProofOfWorkNonceTrialsPerByte * totalDifficulty) payloadLengthExtraBytes = int( - shared.networkDefaultPayloadLengthExtraBytes * smallMessageDifficulty) + protocol.networkDefaultPayloadLengthExtraBytes * smallMessageDifficulty) else: raise APIError(0, 'Too many parameters!') label = self._decode(label, "base64") @@ -319,15 +320,15 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): elif len(params) == 6: passphrase, numberOfAddresses, addressVersionNumber, streamNumber, eighteenByteRipe, totalDifficulty = params nonceTrialsPerByte = int( - shared.networkDefaultProofOfWorkNonceTrialsPerByte * totalDifficulty) + protocol.networkDefaultProofOfWorkNonceTrialsPerByte * totalDifficulty) payloadLengthExtraBytes = BMConfigParser().get( 'bitmessagesettings', 'defaultpayloadlengthextrabytes') elif len(params) == 7: passphrase, numberOfAddresses, addressVersionNumber, streamNumber, eighteenByteRipe, totalDifficulty, smallMessageDifficulty = params nonceTrialsPerByte = int( - shared.networkDefaultProofOfWorkNonceTrialsPerByte * totalDifficulty) + protocol.networkDefaultProofOfWorkNonceTrialsPerByte * totalDifficulty) payloadLengthExtraBytes = int( - shared.networkDefaultPayloadLengthExtraBytes * smallMessageDifficulty) + protocol.networkDefaultPayloadLengthExtraBytes * smallMessageDifficulty) else: raise APIError(0, 'Too many parameters!') if len(passphrase) == 0: @@ -450,7 +451,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): if not BMConfigParser().safeGetBoolean(address, 'chan'): raise APIError(25, 'Specified address is not a chan address. Use deleteAddress API call instead.') BMConfigParser().remove_section(address) - with open(shared.appdata + 'keys.dat', 'wb') as configfile: + with open(state.appdata + 'keys.dat', 'wb') as configfile: BMConfigParser().write(configfile) return 'success' @@ -464,7 +465,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): if not BMConfigParser().has_section(address): raise APIError(13, 'Could not find this address in your keys.dat file.') BMConfigParser().remove_section(address) - with open(shared.appdata + 'keys.dat', 'wb') as configfile: + with open(state.appdata + 'keys.dat', 'wb') as configfile: BMConfigParser().write(configfile) shared.UISignalQueue.put(('rerenderMessagelistFromLabels','')) shared.UISignalQueue.put(('rerenderMessagelistToLabels','')) @@ -837,7 +838,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): # Let us do the POW and attach it to the front target = 2**64 / ((len(encryptedPayload)+requiredPayloadLengthExtraBytes+8) * requiredAverageProofOfWorkNonceTrialsPerByte) 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() initialHash = hashlib.sha512(encryptedPayload).digest() trialValue, nonce = proofofwork.run(target, initialHash) @@ -856,7 +857,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): objectType, toStreamNumber, encryptedPayload, int(time.time()) + TTL,'') with shared.printLock: print 'Broadcasting inv for msg(API disseminatePreEncryptedMsg command):', hexlify(inventoryHash) - shared.broadcastToSendDataQueues(( + protocol.broadcastToSendDataQueues(( toStreamNumber, 'advertiseobject', inventoryHash)) def HandleTrashSentMessageByAckDAta(self, params): @@ -879,8 +880,8 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): payload = self._decode(payload, "hex") # Let us do the POW - target = 2 ** 64 / ((len(payload) + shared.networkDefaultPayloadLengthExtraBytes + - 8) * shared.networkDefaultProofOfWorkNonceTrialsPerByte) + target = 2 ** 64 / ((len(payload) + protocol.networkDefaultPayloadLengthExtraBytes + + 8) * protocol.networkDefaultProofOfWorkNonceTrialsPerByte) print '(For pubkey message via API) Doing proof of work...' initialHash = hashlib.sha512(payload).digest() trialValue, nonce = proofofwork.run(target, initialHash) @@ -903,7 +904,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): objectType, pubkeyStreamNumber, payload, int(time.time()) + TTL,'') with shared.printLock: print 'broadcasting inv within API command disseminatePubkey with hash:', hexlify(inventoryHash) - shared.broadcastToSendDataQueues(( + protocol.broadcastToSendDataQueues(( streamNumber, 'advertiseobject', inventoryHash)) def HandleGetMessageDataByDestinationHash(self, params): diff --git a/src/bitmessagecurses/__init__.py b/src/bitmessagecurses/__init__.py index 165873b5..a8840f2f 100644 --- a/src/bitmessagecurses/__init__.py +++ b/src/bitmessagecurses/__init__.py @@ -22,6 +22,7 @@ from dialog import Dialog from helper_sql import * import shared +import ConfigParser from configparser import BMConfigParser from addresses import * from pyelliptic.openssl import OpenSSL diff --git a/src/bitmessagemain.py b/src/bitmessagemain.py index dd71488d..5c41e4e5 100755 --- a/src/bitmessagemain.py +++ b/src/bitmessagemain.py @@ -28,6 +28,7 @@ from helper_startup import isOurOperatingSystemLimitedToHavingVeryFewHalfOpenCon import shared from helper_sql import sqlQuery +import state import threading # Classes @@ -49,7 +50,7 @@ import helper_generic from helper_threading import * def connectToStream(streamNumber): - shared.streamsInWhichIAmParticipating[streamNumber] = 'no data' + state.streamsInWhichIAmParticipating[streamNumber] = 'no data' selfInitiatedConnections[streamNumber] = {} if isOurOperatingSystemLimitedToHavingVeryFewHalfOpenConnections(): @@ -146,10 +147,10 @@ class singleAPI(threading.Thread, StoppableThread): selfInitiatedConnections = {} if shared.useVeryEasyProofOfWorkForTesting: - shared.networkDefaultProofOfWorkNonceTrialsPerByte = int( - shared.networkDefaultProofOfWorkNonceTrialsPerByte / 100) - shared.networkDefaultPayloadLengthExtraBytes = int( - shared.networkDefaultPayloadLengthExtraBytes / 100) + protocol.networkDefaultProofOfWorkNonceTrialsPerByte = int( + protocol.networkDefaultProofOfWorkNonceTrialsPerByte / 100) + protocol.networkDefaultPayloadLengthExtraBytes = int( + protocol.networkDefaultPayloadLengthExtraBytes / 100) class Main: def start(self, daemon=False): diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 9869d734..91424c86 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -76,7 +76,10 @@ from dialogs import AddAddressDialog from class_objectHashHolder import objectHashHolder from class_singleWorker import singleWorker from helper_generic import powQueueSize, invQueueSize +import paths from proofofwork import getPowType +import protocol +import state from statusbar import BMStatusBar from version import softwareVersion @@ -100,13 +103,13 @@ def change_translation(newlocale): pass qmytranslator = QtCore.QTranslator() - translationpath = os.path.join (shared.codePath(), 'translations', 'bitmessage_' + newlocale) + translationpath = os.path.join (paths.codePath(), 'translations', 'bitmessage_' + newlocale) qmytranslator.load(translationpath) QtGui.QApplication.installTranslator(qmytranslator) qsystranslator = QtCore.QTranslator() - if shared.frozen: - translationpath = os.path.join (shared.codePath(), 'translations', 'qt_' + newlocale) + if paths.frozen: + translationpath = os.path.join (paths.codePath(), 'translations', 'qt_' + newlocale) else: translationpath = os.path.join (str(QtCore.QLibraryInfo.location(QtCore.QLibraryInfo.TranslationsPath)), 'qt_' + newlocale) qsystranslator.load(translationpath) @@ -1360,9 +1363,9 @@ class MyForm(settingsmixin.SMainWindow): # if the address had a known label in the address book if label is not None: # Does a sound file exist for this particular contact? - if (os.path.isfile(shared.appdata + 'sounds/' + label + '.wav') or - os.path.isfile(shared.appdata + 'sounds/' + label + '.mp3')): - soundFilename = shared.appdata + 'sounds/' + label + if (os.path.isfile(state.appdata + 'sounds/' + label + '.wav') or + os.path.isfile(state.appdata + 'sounds/' + label + '.mp3')): + soundFilename = state.appdata + 'sounds/' + label # Avoid making sounds more frequently than the threshold. # This suppresses playing sounds repeatedly when there @@ -1378,19 +1381,19 @@ class MyForm(settingsmixin.SMainWindow): if soundFilename is None: # the sound is for an address which exists in the address book if category is self.SOUND_KNOWN: - soundFilename = shared.appdata + 'sounds/known' + soundFilename = state.appdata + 'sounds/known' # the sound is for an unknown address elif category is self.SOUND_UNKNOWN: - soundFilename = shared.appdata + 'sounds/unknown' + soundFilename = state.appdata + 'sounds/unknown' # initial connection sound elif category is self.SOUND_CONNECTED: - soundFilename = shared.appdata + 'sounds/connected' + soundFilename = state.appdata + 'sounds/connected' # disconnected sound elif category is self.SOUND_DISCONNECTED: - soundFilename = shared.appdata + 'sounds/disconnected' + soundFilename = state.appdata + 'sounds/disconnected' # sound when the connection status becomes 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 not self.isConnectionSound(category): @@ -1526,7 +1529,7 @@ class MyForm(settingsmixin.SMainWindow): # menu button 'manage keys' def click_actionManageKeys(self): if 'darwin' in sys.platform or 'linux' in sys.platform: - if shared.appdata == '': + if state.appdata == '': # reply = QtGui.QMessageBox.information(self, 'keys.dat?','You # may manage your keys by editing the keys.dat file stored in # the same directory as this program. It is important that you @@ -1536,14 +1539,14 @@ class MyForm(settingsmixin.SMainWindow): else: 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': - if shared.appdata == '': + if state.appdata == '': 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) else: 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: shared.openKeysFile() @@ -2409,10 +2412,10 @@ class MyForm(settingsmixin.SMainWindow): # Demanded difficulty tab if float(self.settingsDialogInstance.ui.lineEditTotalDifficulty.text()) >= 1: 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: 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() != BMConfigParser().safeGet("bitmessagesettings", "opencl"): BMConfigParser().set('bitmessagesettings', 'opencl', str(self.settingsDialogInstance.ui.comboBoxOpenCL.currentText())) @@ -2421,18 +2424,18 @@ class MyForm(settingsmixin.SMainWindow): if float(self.settingsDialogInstance.ui.lineEditMaxAcceptableTotalDifficulty.text()) >= 1 or float(self.settingsDialogInstance.ui.lineEditMaxAcceptableTotalDifficulty.text()) == 0: 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 acceptableDifficultyChanged = True 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 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 acceptableDifficultyChanged = True BMConfigParser().set('bitmessagesettings', 'maxacceptablepayloadlengthextrabytes', str(int(float( - self.settingsDialogInstance.ui.lineEditMaxAcceptableSmallMessageDifficulty.text()) * shared.networkDefaultPayloadLengthExtraBytes))) + self.settingsDialogInstance.ui.lineEditMaxAcceptableSmallMessageDifficulty.text()) * protocol.networkDefaultPayloadLengthExtraBytes))) if acceptableDifficultyChanged: # 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 @@ -2493,21 +2496,21 @@ class MyForm(settingsmixin.SMainWindow): # startup for linux 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 sqlStoredProcedure('movemessagstoprog') - with open(shared.lookupExeFolder() + 'keys.dat', 'wb') as configfile: + with open(paths.lookupExeFolder() + 'keys.dat', 'wb') as configfile: BMConfigParser().write(configfile) # Write the knownnodes.dat file to disk in the new location shared.knownNodesLock.acquire() - output = open(shared.lookupExeFolder() + 'knownnodes.dat', 'wb') + output = open(paths.lookupExeFolder() + 'knownnodes.dat', 'wb') pickle.dump(shared.knownNodes, output) output.close() shared.knownNodesLock.release() - os.remove(shared.appdata + 'keys.dat') - os.remove(shared.appdata + 'knownnodes.dat') - previousAppdataLocation = shared.appdata - shared.appdata = shared.lookupExeFolder() + os.remove(state.appdata + 'keys.dat') + os.remove(state.appdata + 'knownnodes.dat') + previousAppdataLocation = state.appdata + state.appdata = paths.lookupExeFolder() debug.restartLoggingInUpdatedAppdataLocation() try: os.remove(previousAppdataLocation + 'debug.log') @@ -2515,25 +2518,25 @@ class MyForm(settingsmixin.SMainWindow): except: 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... - shared.appdata = shared.lookupAppdataFolder() - if not os.path.exists(shared.appdata): - os.makedirs(shared.appdata) + 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... + state.appdata = paths.lookupAppdataFolder() + if not os.path.exists(state.appdata): + os.makedirs(state.appdata) sqlStoredProcedure('movemessagstoappdata') # Write the keys.dat file to disk in the new location shared.writeKeysFile() # Write the knownnodes.dat file to disk in the new location shared.knownNodesLock.acquire() - output = open(shared.appdata + 'knownnodes.dat', 'wb') + output = open(state.appdata + 'knownnodes.dat', 'wb') pickle.dump(shared.knownNodes, output) output.close() shared.knownNodesLock.release() - os.remove(shared.lookupExeFolder() + 'keys.dat') - os.remove(shared.lookupExeFolder() + 'knownnodes.dat') + os.remove(paths.lookupExeFolder() + 'keys.dat') + os.remove(paths.lookupExeFolder() + 'knownnodes.dat') debug.restartLoggingInUpdatedAppdataLocation() try: - os.remove(shared.lookupExeFolder() + 'debug.log') - os.remove(shared.lookupExeFolder() + 'debug.log.1') + os.remove(paths.lookupExeFolder() + 'debug.log') + os.remove(paths.lookupExeFolder() + 'debug.log.1') except: pass @@ -3621,8 +3624,8 @@ class MyForm(settingsmixin.SMainWindow): currentRow, 0).setIcon(avatarize(addressAtCurrentRow)) def setAvatar(self, addressAtCurrentRow): - if not os.path.exists(shared.appdata + 'avatars/'): - os.makedirs(shared.appdata + 'avatars/') + if not os.path.exists(state.appdata + 'avatars/'): + os.makedirs(state.appdata + 'avatars/') hash = hashlib.md5(addBMIfNotPresent(addressAtCurrentRow)).hexdigest() extensions = ['PNG', 'GIF', 'JPG', 'JPEG', 'SVG', 'BMP', 'MNG', 'PBM', 'PGM', 'PPM', 'TIFF', 'XBM', 'XPM', 'TGA'] # http://pyqt.sourceforge.net/Docs/PyQt4/qimagereader.html#supportedImageFormats @@ -3633,8 +3636,8 @@ class MyForm(settingsmixin.SMainWindow): for ext in extensions: filters += [ names[ext] + ' (*.' + ext.lower() + ')' ] all_images_filter += [ '*.' + ext.lower() ] - upper = shared.appdata + 'avatars/' + hash + '.' + ext.upper() - lower = shared.appdata + 'avatars/' + hash + '.' + ext.lower() + upper = state.appdata + 'avatars/' + hash + '.' + ext.upper() + lower = state.appdata + 'avatars/' + hash + '.' + ext.lower() if os.path.isfile(lower): current_files += [lower] elif os.path.isfile(upper): @@ -3643,7 +3646,7 @@ class MyForm(settingsmixin.SMainWindow): filters[1:1] = ['All files (*.*)'] sourcefile = QFileDialog.getOpenFileName(self, _translate("MainWindow","Set avatar..."), filter = ';;'.join(filters)) # 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) if sourcefile == '': # ask for removal of avatar @@ -4021,12 +4024,12 @@ class settingsDialog(QtGui.QDialog): self.ui.checkBoxReplyBelow.setChecked( BMConfigParser().safeGetBoolean('bitmessagesettings', 'replybelow')) - if shared.appdata == shared.lookupExeFolder(): + if state.appdata == paths.lookupExeFolder(): self.ui.checkBoxPortableMode.setChecked(True) else: try: import tempfile - file = tempfile.NamedTemporaryFile(dir=shared.lookupExeFolder(), delete=True) + file = tempfile.NamedTemporaryFile(dir=paths.lookupExeFolder(), delete=True) file.close # should autodelete except: self.ui.checkBoxPortableMode.setDisabled(True) @@ -4086,15 +4089,15 @@ class settingsDialog(QtGui.QDialog): # Demanded difficulty tab self.ui.lineEditTotalDifficulty.setText(str((float(BMConfigParser().getint( - 'bitmessagesettings', 'defaultnoncetrialsperbyte')) / shared.networkDefaultProofOfWorkNonceTrialsPerByte))) + 'bitmessagesettings', 'defaultnoncetrialsperbyte')) / protocol.networkDefaultProofOfWorkNonceTrialsPerByte))) self.ui.lineEditSmallMessageDifficulty.setText(str((float(BMConfigParser().getint( - 'bitmessagesettings', 'defaultpayloadlengthextrabytes')) / shared.networkDefaultPayloadLengthExtraBytes))) + 'bitmessagesettings', 'defaultpayloadlengthextrabytes')) / protocol.networkDefaultPayloadLengthExtraBytes))) # Max acceptable difficulty tab self.ui.lineEditMaxAcceptableTotalDifficulty.setText(str((float(BMConfigParser().getint( - 'bitmessagesettings', 'maxacceptablenoncetrialsperbyte')) / shared.networkDefaultProofOfWorkNonceTrialsPerByte))) + 'bitmessagesettings', 'maxacceptablenoncetrialsperbyte')) / protocol.networkDefaultProofOfWorkNonceTrialsPerByte))) self.ui.lineEditMaxAcceptableSmallMessageDifficulty.setText(str((float(BMConfigParser().getint( - 'bitmessagesettings', 'maxacceptablepayloadlengthextrabytes')) / shared.networkDefaultPayloadLengthExtraBytes))) + 'bitmessagesettings', 'maxacceptablepayloadlengthextrabytes')) / protocol.networkDefaultPayloadLengthExtraBytes))) # OpenCL if openclpow.openclAvailable(): diff --git a/src/bitmessageqt/bitmessageui.py b/src/bitmessageqt/bitmessageui.py index e480258c..668fbffd 100644 --- a/src/bitmessageqt/bitmessageui.py +++ b/src/bitmessageqt/bitmessageui.py @@ -15,7 +15,6 @@ from messagecompose import MessageCompose import settingsmixin from networkstatus import NetworkStatus from blacklist import Blacklist -import shared try: _fromUtf8 = QtCore.QString.fromUtf8 diff --git a/src/bitmessageqt/languagebox.py b/src/bitmessageqt/languagebox.py index 4ece7d83..8cce1e03 100644 --- a/src/bitmessageqt/languagebox.py +++ b/src/bitmessageqt/languagebox.py @@ -3,7 +3,7 @@ import os from PyQt4 import QtCore, QtGui from configparser import BMConfigParser -from shared import codePath +import paths class LanguageBox(QtGui.QComboBox): languageName = {"system": "System Settings", "eo": "Esperanto", "en_pirate": "Pirate English"} @@ -14,7 +14,7 @@ class LanguageBox(QtGui.QComboBox): def populate(self): self.languages = [] self.clear() - localesPath = os.path.join (codePath(), 'translations') + localesPath = os.path.join (paths.codePath(), 'translations') configuredLocale = "system" try: configuredLocale = BMConfigParser().get('bitmessagesettings', 'userlocale', "system") diff --git a/src/bitmessageqt/support.py b/src/bitmessageqt/support.py index 92658a17..aae5134f 100644 --- a/src/bitmessageqt/support.py +++ b/src/bitmessageqt/support.py @@ -11,9 +11,11 @@ from foldertree import AccountMixin from helper_sql import * from l10n import getTranslationLanguage from openclpow import openclAvailable, openclEnabled +import paths from proofofwork import bmpow from pyelliptic.openssl import OpenSSL import shared +import state from version import softwareVersion # this is BM support address going to Peter Surda @@ -63,7 +65,7 @@ def checkHasNormalAddress(): def createAddressIfNeeded(myapp): 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(): time.sleep(.2) myapp.rerenderComboBoxSendFrom() @@ -104,9 +106,9 @@ def createSupportMessage(myapp): opensslversion = "%s (Python internal), %s (external for PyElliptic)" % (ssl.OPENSSL_VERSION, OpenSSL._lib.SSLeay_version(SSLEAY_VERSION)) frozen = "N/A" - if shared.frozen: - frozen = shared.frozen - portablemode = "True" if shared.appdata == shared.lookupExeFolder() else "False" + if paths.frozen: + frozen = paths.frozen + portablemode = "True" if state.appdata == paths.lookupExeFolder() else "False" cpow = "True" if bmpow else "False" #cpow = QtGui.QApplication.translate("Support", cpow) openclpow = str(BMConfigParser().safeGet('bitmessagesettings', 'opencl')) if openclEnabled() else "None" diff --git a/src/bitmessageqt/utils.py b/src/bitmessageqt/utils.py index 7361f37d..1a5b67d7 100644 --- a/src/bitmessageqt/utils.py +++ b/src/bitmessageqt/utils.py @@ -4,6 +4,7 @@ import os import shared from addresses import addBMIfNotPresent from configparser import BMConfigParser +import state str_broadcast_subscribers = '[Broadcast subscribers]' str_chan = '[chan]' @@ -82,8 +83,8 @@ def avatarize(address): extensions = ['PNG', 'GIF', 'JPG', 'JPEG', 'SVG', 'BMP', 'MNG', 'PBM', 'PGM', 'PPM', 'TIFF', 'XBM', 'XPM', 'TGA'] # try to find a specific avatar for ext in extensions: - lower_hash = shared.appdata + 'avatars/' + hash + '.' + ext.lower() - upper_hash = shared.appdata + 'avatars/' + hash + '.' + ext.upper() + lower_hash = state.appdata + 'avatars/' + hash + '.' + ext.lower() + upper_hash = state.appdata + 'avatars/' + hash + '.' + ext.upper() if os.path.isfile(lower_hash): # print 'found avatar of ', address idcon.addFile(lower_hash) @@ -94,8 +95,8 @@ def avatarize(address): return idcon # if we haven't found any, try to find a default avatar for ext in extensions: - lower_default = shared.appdata + 'avatars/' + 'default.' + ext.lower() - upper_default = shared.appdata + 'avatars/' + 'default.' + ext.upper() + lower_default = state.appdata + 'avatars/' + 'default.' + ext.lower() + upper_default = state.appdata + 'avatars/' + 'default.' + ext.upper() if os.path.isfile(lower_default): default = lower_default idcon.addFile(lower_default) diff --git a/src/bitmessageqt/widgets.py b/src/bitmessageqt/widgets.py index 02394296..8ef807f2 100644 --- a/src/bitmessageqt/widgets.py +++ b/src/bitmessageqt/widgets.py @@ -1,10 +1,10 @@ from PyQt4 import uic import os.path +import paths import sys -from shared import codePath def resource_path(resFile): - baseDir = codePath() + baseDir = paths.codePath() for subDir in ["ui", "bitmessageqt"]: 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) diff --git a/src/class_addressGenerator.py b/src/class_addressGenerator.py index c215fa3c..ff5eb25e 100644 --- a/src/class_addressGenerator.py +++ b/src/class_addressGenerator.py @@ -77,13 +77,13 @@ class addressGenerator(threading.Thread, StoppableThread): if nonceTrialsPerByte == 0: nonceTrialsPerByte = BMConfigParser().getint( 'bitmessagesettings', 'defaultnoncetrialsperbyte') - if nonceTrialsPerByte < shared.networkDefaultProofOfWorkNonceTrialsPerByte: - nonceTrialsPerByte = shared.networkDefaultProofOfWorkNonceTrialsPerByte + if nonceTrialsPerByte < protocol.networkDefaultProofOfWorkNonceTrialsPerByte: + nonceTrialsPerByte = protocol.networkDefaultProofOfWorkNonceTrialsPerByte if payloadLengthExtraBytes == 0: payloadLengthExtraBytes = BMConfigParser().getint( 'bitmessagesettings', 'defaultpayloadlengthextrabytes') - if payloadLengthExtraBytes < shared.networkDefaultPayloadLengthExtraBytes: - payloadLengthExtraBytes = shared.networkDefaultPayloadLengthExtraBytes + if payloadLengthExtraBytes < protocol.networkDefaultPayloadLengthExtraBytes: + payloadLengthExtraBytes = protocol.networkDefaultPayloadLengthExtraBytes if command == 'createRandomAddress': shared.UISignalQueue.put(( 'updateStatusBar', tr._translate("MainWindow", "Generating one new address"))) diff --git a/src/class_objectProcessor.py b/src/class_objectProcessor.py index 9170ae5b..4d0b7be0 100644 --- a/src/class_objectProcessor.py +++ b/src/class_objectProcessor.py @@ -467,7 +467,7 @@ class objectProcessor(threading.Thread): toAddress, 'noncetrialsperbyte') requiredPayloadLengthExtraBytes = BMConfigParser().getint( 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.') return blockMessage = False # Gets set to True if the user shouldn't see the message according to black or white lists. diff --git a/src/class_outgoingSynSender.py b/src/class_outgoingSynSender.py index caa14aa0..1754962e 100644 --- a/src/class_outgoingSynSender.py +++ b/src/class_outgoingSynSender.py @@ -1,3 +1,4 @@ +import errno import threading import time import random @@ -12,6 +13,7 @@ from class_sendDataThread import * from class_receiveDataThread import * from configparser import BMConfigParser from helper_threading import * +import state # For each stream to which we connect, several outgoingSynSender threads # will exist and will collectively create 8 connections with peers. @@ -252,12 +254,16 @@ class outgoingSynSender(threading.Thread, StoppableThread): logger.debug('SOCKS5 error: %s', str(err)) else: logger.error('SOCKS5 error: %s', str(err)) + if err[0][0] == 4 or err[0][0] == 2: + state.networkProtocolLastFailed['IPv6'] = time.time() except socks.Socks4Error as err: logger.error('Socks4Error: ' + str(err)) except socket.error as err: if BMConfigParser().get('bitmessagesettings', 'socksproxytype')[0:5] == 'SOCKS': logger.error('Bitmessage MIGHT be having trouble connecting to the SOCKS server. ' + str(err)) else: + if ":" in peer.host and err[0] == errno.ENETUNREACH: + state.networkProtocolLastFailed['IPv6'] = time.time() if shared.verbose >= 1: logger.debug('Could NOT connect to ' + str(peer) + 'during outgoing attempt. ' + str(err)) diff --git a/src/class_receiveDataThread.py b/src/class_receiveDataThread.py index fb25db4c..cf43f7b3 100644 --- a/src/class_receiveDataThread.py +++ b/src/class_receiveDataThread.py @@ -28,8 +28,10 @@ from class_objectHashHolder import objectHashHolder from helper_generic import addDataPadding, isHostInPrivateIPRange from helper_sql import sqlQuery from debug import logger +import paths import protocol from inventory import Inventory +import state import tr from version import softwareVersion @@ -291,7 +293,7 @@ class receiveDataThread(threading.Thread): if ((self.services & protocol.NODE_SSL == protocol.NODE_SSL) and protocol.haveSSL(not self.initiatedConnection)): 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"): self.sslSock.context.set_ecdh_curve("secp256k1") while True: @@ -320,12 +322,12 @@ class receiveDataThread(threading.Thread): shared.UISignalQueue.put(('updateNetworkStatusTab', 'no data')) logger.debug('Connection fully established with ' + str(self.peer) + "\n" + \ 'The size of the connectedHostsList is now ' + str(len(shared.connectedHostsList)) + "\n" + \ - 'The length of sendDataQueues is now: ' + str(len(shared.sendDataQueues)) + "\n" + \ + 'The length of sendDataQueues is now: ' + str(len(state.sendDataQueues)) + "\n" + \ 'broadcasting addr from within connectionFullyEstablished function.') # Let all of our peers know about this new node. dataToSend = (int(time.time()), self.streamNumber, 1, self.peer.host, self.remoteNodeIncomingPort) - shared.broadcastToSendDataQueues(( + protocol.broadcastToSendDataQueues(( self.streamNumber, 'advertisepeer', dataToSend)) self.sendaddr() # This is one large addr message to this one peer. @@ -594,7 +596,7 @@ class receiveDataThread(threading.Thread): hostDetails = ( timeSomeoneElseReceivedMessageFromThisNode, recaddrStream, recaddrServices, hostStandardFormat, recaddrPort) - shared.broadcastToSendDataQueues(( + protocol.broadcastToSendDataQueues(( self.streamNumber, 'advertisepeer', hostDetails)) else: timeLastReceivedMessageFromThisNode = shared.knownNodes[recaddrStream][ diff --git a/src/class_sendDataThread.py b/src/class_sendDataThread.py index 0a49e95c..60babb1f 100644 --- a/src/class_sendDataThread.py +++ b/src/class_sendDataThread.py @@ -14,6 +14,7 @@ from class_objectHashHolder import * from addresses import * from debug import logger import protocol +import state # Every connection to a peer has a sendDataThread (and also a # receiveDataThread). @@ -22,7 +23,7 @@ class sendDataThread(threading.Thread): def __init__(self, sendDataThreadQueue): threading.Thread.__init__(self, name="sendData") self.sendDataThreadQueue = sendDataThreadQueue - shared.sendDataQueues.append(self.sendDataThreadQueue) + state.sendDataQueues.append(self.sendDataThreadQueue) self.data = '' self.objectHashHolderInstance = objectHashHolder(self.sendDataThreadQueue) self.objectHashHolderInstance.start() @@ -102,7 +103,7 @@ class sendDataThread(threading.Thread): 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: deststream, command, data = self.sendDataThreadQueue.get() @@ -190,6 +191,6 @@ class sendDataThread(threading.Thread): self.sock.close() except: pass - shared.sendDataQueues.remove(self.sendDataThreadQueue) - logger.info('sendDataThread ending. ID: ' + str(id(self)) + '. Number of queues in sendDataQueues: ' + str(len(shared.sendDataQueues))) + state.sendDataQueues.remove(self.sendDataThreadQueue) + logger.info('sendDataThread ending. ID: ' + str(id(self)) + '. Number of queues in sendDataQueues: ' + str(len(state.sendDataQueues))) self.objectHashHolderInstance.close() diff --git a/src/class_singleCleaner.py b/src/class_singleCleaner.py index 0c25c5ec..03ebc633 100644 --- a/src/class_singleCleaner.py +++ b/src/class_singleCleaner.py @@ -11,7 +11,8 @@ from helper_sql import * from helper_threading import * from inventory import Inventory from debug import logger -from state import neededPubkeys +import protocol +import state """ The singleCleaner class is a timer-driven thread that cleans data structures @@ -53,7 +54,7 @@ class singleCleaner(threading.Thread, StoppableThread): Inventory().flush() 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. # 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 @@ -98,7 +99,7 @@ class singleCleaner(threading.Thread, StoppableThread): # Let us write out the knowNodes to disk if there is anything new to write out. if shared.needToWriteKnownNodesToDisk: shared.knownNodesLock.acquire() - output = open(shared.appdata + 'knownnodes.dat', 'wb') + output = open(state.appdata + 'knownnodes.dat', 'wb') try: pickle.dump(shared.knownNodes, output) output.close() @@ -116,7 +117,7 @@ class singleCleaner(threading.Thread, StoppableThread): def resendPubkeyRequest(address): logger.debug('It has been a long time and we haven\'t heard a response to our getpubkey request. Sending again.') try: - del neededPubkeys[ + del state.neededPubkeys[ 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: pass diff --git a/src/class_singleWorker.py b/src/class_singleWorker.py index 94dc0f9a..c27a9cbb 100644 --- a/src/class_singleWorker.py +++ b/src/class_singleWorker.py @@ -165,7 +165,7 @@ class singleWorker(threading.Thread, StoppableThread): payload += pubEncryptionKey[1:] # 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...') initialHash = hashlib.sha512(payload).digest() trialValue, nonce = proofofwork.run(target, initialHash) @@ -255,7 +255,7 @@ class singleWorker(threading.Thread, StoppableThread): payload += signature # 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...') initialHash = hashlib.sha512(payload).digest() trialValue, nonce = proofofwork.run(target, initialHash) @@ -345,7 +345,7 @@ class singleWorker(threading.Thread, StoppableThread): dataToEncrypt, hexlify(pubEncryptionKey)) # 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...') initialHash = hashlib.sha512(payload).digest() trialValue, nonce = proofofwork.run(target, initialHash) @@ -466,7 +466,7 @@ class singleWorker(threading.Thread, StoppableThread): payload += highlevelcrypto.encrypt( 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...') shared.UISignalQueue.put(('updateSentItemStatusByAckdata', ( ackdata, tr._translate("MainWindow", "Doing work necessary to send broadcast...")))) @@ -659,8 +659,8 @@ class singleWorker(threading.Thread, StoppableThread): # Let us fetch the amount of work required by the recipient. if toAddressVersionNumber == 2: - requiredAverageProofOfWorkNonceTrialsPerByte = shared.networkDefaultProofOfWorkNonceTrialsPerByte - requiredPayloadLengthExtraBytes = shared.networkDefaultPayloadLengthExtraBytes + requiredAverageProofOfWorkNonceTrialsPerByte = protocol.networkDefaultProofOfWorkNonceTrialsPerByte + requiredPayloadLengthExtraBytes = protocol.networkDefaultPayloadLengthExtraBytes 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.")))) elif toAddressVersionNumber >= 3: @@ -670,13 +670,13 @@ class singleWorker(threading.Thread, StoppableThread): requiredPayloadLengthExtraBytes, varintLength = decodeVarint( pubkeyPayload[readPosition:readPosition + 10]) 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. - requiredAverageProofOfWorkNonceTrialsPerByte = shared.networkDefaultProofOfWorkNonceTrialsPerByte - if requiredPayloadLengthExtraBytes < shared.networkDefaultPayloadLengthExtraBytes: - requiredPayloadLengthExtraBytes = shared.networkDefaultPayloadLengthExtraBytes + 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 = protocol.networkDefaultProofOfWorkNonceTrialsPerByte + if requiredPayloadLengthExtraBytes < protocol.networkDefaultPayloadLengthExtraBytes: + requiredPayloadLengthExtraBytes = protocol.networkDefaultPayloadLengthExtraBytes 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( - requiredAverageProofOfWorkNonceTrialsPerByte) / shared.networkDefaultProofOfWorkNonceTrialsPerByte)).arg(str(float(requiredPayloadLengthExtraBytes) / shared.networkDefaultPayloadLengthExtraBytes))))) + requiredAverageProofOfWorkNonceTrialsPerByte) / protocol.networkDefaultProofOfWorkNonceTrialsPerByte)).arg(str(float(requiredPayloadLengthExtraBytes) / protocol.networkDefaultPayloadLengthExtraBytes))))) if status != 'forcepow': 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 @@ -684,8 +684,8 @@ class singleWorker(threading.Thread, StoppableThread): sqlExecute( '''UPDATE sent SET status='toodifficult' WHERE 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( - requiredPayloadLengthExtraBytes) / shared.networkDefaultPayloadLengthExtraBytes)).arg(l10n.formatTimestamp())))) + 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) / protocol.networkDefaultPayloadLengthExtraBytes)).arg(l10n.formatTimestamp())))) continue else: # if we are sending a message to ourselves or a chan.. logger.info('Sending a message.') @@ -703,8 +703,8 @@ class singleWorker(threading.Thread, StoppableThread): privEncryptionKeyBase58)) pubEncryptionKeyBase256 = unhexlify(highlevelcrypto.privToPub( privEncryptionKeyHex))[1:] - requiredAverageProofOfWorkNonceTrialsPerByte = shared.networkDefaultProofOfWorkNonceTrialsPerByte - requiredPayloadLengthExtraBytes = shared.networkDefaultPayloadLengthExtraBytes + requiredAverageProofOfWorkNonceTrialsPerByte = protocol.networkDefaultProofOfWorkNonceTrialsPerByte + requiredPayloadLengthExtraBytes = protocol.networkDefaultPayloadLengthExtraBytes shared.UISignalQueue.put(('updateSentItemStatusByAckdata', ( ackdata, tr._translate("MainWindow", "Doing work necessary to send message.")))) @@ -747,9 +747,9 @@ class singleWorker(threading.Thread, StoppableThread): # the receiver is in any of those lists. if shared.isAddressInMyAddressBookSubscriptionsListOrWhitelist(toaddress): payload += encodeVarint( - shared.networkDefaultProofOfWorkNonceTrialsPerByte) + protocol.networkDefaultProofOfWorkNonceTrialsPerByte) payload += encodeVarint( - shared.networkDefaultPayloadLengthExtraBytes) + protocol.networkDefaultPayloadLengthExtraBytes) else: payload += encodeVarint(BMConfigParser().getint( fromaddress, 'noncetrialsperbyte')) @@ -790,7 +790,7 @@ class singleWorker(threading.Thread, StoppableThread): encryptedPayload += encodeVarint(1) # msg version encryptedPayload += encodeVarint(toStreamNumber) + encrypted 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() initialHash = hashlib.sha512(encryptedPayload).digest() @@ -913,7 +913,7 @@ class singleWorker(threading.Thread, StoppableThread): shared.UISignalQueue.put(('updateSentItemStatusByToAddress', ( 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() trialValue, nonce = proofofwork.run(target, initialHash) logger.info('Found proof of work ' + str(trialValue) + ' Nonce: ' + str(nonce)) @@ -966,7 +966,7 @@ class singleWorker(threading.Thread, StoppableThread): payload += encodeVarint(1) # msg version 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)) powStartTime = time.time() diff --git a/src/class_sqlThread.py b/src/class_sqlThread.py index 320f6315..2beb50dc 100644 --- a/src/class_sqlThread.py +++ b/src/class_sqlThread.py @@ -8,7 +8,9 @@ import sys import os from debug import logger from namecoin import ensureNamecoinOptions +import paths import random +import state import string import tr#anslate @@ -23,7 +25,7 @@ class sqlThread(threading.Thread): threading.Thread.__init__(self, name="SQL") 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.cur = self.conn.cursor() @@ -112,9 +114,9 @@ class sqlThread(threading.Thread): if BMConfigParser().getint('bitmessagesettings', 'settingsversion') == 4: BMConfigParser().set('bitmessagesettings', 'defaultnoncetrialsperbyte', str( - shared.networkDefaultProofOfWorkNonceTrialsPerByte)) + protocol.networkDefaultProofOfWorkNonceTrialsPerByte)) BMConfigParser().set('bitmessagesettings', 'defaultpayloadlengthextrabytes', str( - shared.networkDefaultPayloadLengthExtraBytes)) + protocol.networkDefaultPayloadLengthExtraBytes)) BMConfigParser().set('bitmessagesettings', 'settingsversion', '5') if BMConfigParser().getint('bitmessagesettings', 'settingsversion') == 5: @@ -235,8 +237,8 @@ class sqlThread(threading.Thread): # Raise the default required difficulty from 1 to 2 # With the change to protocol v3, this is obsolete. if BMConfigParser().getint('bitmessagesettings', 'settingsversion') == 6: - """if int(shared.config.get('bitmessagesettings','defaultnoncetrialsperbyte')) == shared.networkDefaultProofOfWorkNonceTrialsPerByte: - shared.config.set('bitmessagesettings','defaultnoncetrialsperbyte', str(shared.networkDefaultProofOfWorkNonceTrialsPerByte * 2)) + """if int(shared.config.get('bitmessagesettings','defaultnoncetrialsperbyte')) == protocol.networkDefaultProofOfWorkNonceTrialsPerByte: + shared.config.set('bitmessagesettings','defaultnoncetrialsperbyte', str(protocol.networkDefaultProofOfWorkNonceTrialsPerByte * 2)) """ BMConfigParser().set('bitmessagesettings', 'settingsversion', '7') @@ -302,8 +304,8 @@ class sqlThread(threading.Thread): # With the change to protocol version 3, reset the user-settable difficulties to 1 if BMConfigParser().getint('bitmessagesettings', 'settingsversion') == 8: - BMConfigParser().set('bitmessagesettings','defaultnoncetrialsperbyte', str(shared.networkDefaultProofOfWorkNonceTrialsPerByte)) - BMConfigParser().set('bitmessagesettings','defaultpayloadlengthextrabytes', str(shared.networkDefaultPayloadLengthExtraBytes)) + BMConfigParser().set('bitmessagesettings','defaultnoncetrialsperbyte', str(protocol.networkDefaultProofOfWorkNonceTrialsPerByte)) + BMConfigParser().set('bitmessagesettings','defaultpayloadlengthextrabytes', str(protocol.networkDefaultPayloadLengthExtraBytes)) previousTotalDifficulty = int(BMConfigParser().getint('bitmessagesettings', 'maxacceptablenoncetrialsperbyte')) / 320 previousSmallMessageDifficulty = int(BMConfigParser().getint('bitmessagesettings', 'maxacceptablepayloadlengthextrabytes')) / 14000 BMConfigParser().set('bitmessagesettings','maxacceptablenoncetrialsperbyte', str(previousTotalDifficulty * 1000)) @@ -331,9 +333,9 @@ class sqlThread(threading.Thread): # sanity check if BMConfigParser().getint('bitmessagesettings', 'maxacceptablenoncetrialsperbyte') == 0: - BMConfigParser().set('bitmessagesettings','maxacceptablenoncetrialsperbyte', str(shared.ridiculousDifficulty * shared.networkDefaultProofOfWorkNonceTrialsPerByte)) + BMConfigParser().set('bitmessagesettings','maxacceptablenoncetrialsperbyte', str(shared.ridiculousDifficulty * protocol.networkDefaultProofOfWorkNonceTrialsPerByte)) if BMConfigParser().getint('bitmessagesettings', 'maxacceptablepayloadlengthextrabytes') == 0: - BMConfigParser().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 # clear it, and the pubkeys from inventory, so that they'll be re-downloaded. @@ -507,8 +509,8 @@ class sqlThread(threading.Thread): os._exit(0) self.conn.close() shutil.move( - shared.lookupAppdataFolder() + 'messages.dat', shared.lookupExeFolder() + 'messages.dat') - self.conn = sqlite3.connect(shared.lookupExeFolder() + 'messages.dat') + paths.lookupAppdataFolder() + 'messages.dat', paths.lookupExeFolder() + 'messages.dat') + self.conn = sqlite3.connect(paths.lookupExeFolder() + 'messages.dat') self.conn.text_factory = str self.cur = self.conn.cursor() elif item == 'movemessagstoappdata': @@ -523,8 +525,8 @@ class sqlThread(threading.Thread): os._exit(0) self.conn.close() shutil.move( - shared.lookupExeFolder() + 'messages.dat', shared.lookupAppdataFolder() + 'messages.dat') - self.conn = sqlite3.connect(shared.lookupAppdataFolder() + 'messages.dat') + paths.lookupExeFolder() + 'messages.dat', paths.lookupAppdataFolder() + 'messages.dat') + self.conn = sqlite3.connect(paths.lookupAppdataFolder() + 'messages.dat') self.conn.text_factory = str self.cur = self.conn.cursor() elif item == 'deleteandvacuume': diff --git a/src/debug.py b/src/debug.py index cdf8d8cb..24e43332 100644 --- a/src/debug.py +++ b/src/debug.py @@ -23,6 +23,7 @@ import shared import sys import traceback import helper_startup +import state helper_startup.loadConfig() # Now can be overriden from a config file, which uses standard python logging.config.fileConfig interface @@ -36,12 +37,12 @@ def log_uncaught_exceptions(ex_cls, ex, tb): def configureLogging(): have_logging = False try: - logging.config.fileConfig(os.path.join (shared.appdata, 'logging.dat')) + logging.config.fileConfig(os.path.join (state.appdata, 'logging.dat')) 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: - if os.path.isfile(os.path.join(shared.appdata, 'logging.dat')): - print "Failed to load logger configuration from %s, using default logging config" % (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(state.appdata, 'logging.dat')) print sys.exc_info() else: # no need to confuse the user if the logger config is missing entirely @@ -70,7 +71,7 @@ def configureLogging(): 'class': 'logging.handlers.RotatingFileHandler', 'formatter': 'default', 'level': log_level, - 'filename': shared.appdata + 'debug.log', + 'filename': state.appdata + 'debug.log', 'maxBytes': 2097152, # 2 MiB 'backupCount': 1, 'encoding': 'UTF-8', diff --git a/src/helper_bootstrap.py b/src/helper_bootstrap.py index 44bd190a..4acf7105 100644 --- a/src/helper_bootstrap.py +++ b/src/helper_bootstrap.py @@ -7,12 +7,13 @@ import time from configparser import BMConfigParser from debug import logger import socks +import state def knownNodes(): try: # We shouldn't have to use the shared.knownNodesLock because this had # 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) pickleFile.close() # The old format of storing knownNodes was as a 'host: (port, time)' @@ -28,7 +29,7 @@ def knownNodes(): peer, lastseen = node_tuple shared.knownNodes[stream][peer] = lastseen except: - shared.knownNodes = defaultKnownNodes.createDefaultKnownNodes(shared.appdata) + shared.knownNodes = defaultKnownNodes.createDefaultKnownNodes(state.appdata) # your own onion address, if setup if BMConfigParser().has_option('bitmessagesettings', 'onionhostname') and ".onion" in BMConfigParser().get('bitmessagesettings', 'onionhostname'): shared.knownNodes[1][shared.Peer(BMConfigParser().get('bitmessagesettings', 'onionhostname'), BMConfigParser().getint('bitmessagesettings', 'onionport'))] = int(time.time()) diff --git a/src/helper_startup.py b/src/helper_startup.py index d685882e..c0f84635 100644 --- a/src/helper_startup.py +++ b/src/helper_startup.py @@ -10,6 +10,8 @@ import platform from distutils.version import StrictVersion from namecoin import ensureNamecoinOptions +import paths +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. @@ -25,31 +27,31 @@ def _loadTrustedPeer(): shared.trustedPeer = shared.Peer(host, int(port)) def loadConfig(): - if shared.appdata: - BMConfigParser().read(shared.appdata + 'keys.dat') - #shared.appdata must have been specified as a startup option. + if state.appdata: + BMConfigParser().read(state.appdata + 'keys.dat') + #state.appdata must have been specified as a startup option. try: 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 except: needToCreateKeysFile = True else: - BMConfigParser().read(shared.lookupExeFolder() + 'keys.dat') + BMConfigParser().read(paths.lookupExeFolder() + 'keys.dat') try: BMConfigParser().get('bitmessagesettings', 'settingsversion') print 'Loading config files from same directory as program.' needToCreateKeysFile = False - shared.appdata = shared.lookupExeFolder() + state.appdata = paths.lookupExeFolder() except: # Could not load the keys.dat file in the program directory. Perhaps it # is in the appdata directory. - shared.appdata = shared.lookupAppdataFolder() - BMConfigParser().read(shared.appdata + 'keys.dat') + state.appdata = paths.lookupAppdataFolder() + BMConfigParser().read(state.appdata + 'keys.dat') try: BMConfigParser().get('bitmessagesettings', 'settingsversion') - print 'Loading existing config files from', shared.appdata + print 'Loading existing config files from', state.appdata needToCreateKeysFile = False except: needToCreateKeysFile = True @@ -90,9 +92,9 @@ def loadConfig(): BMConfigParser().set( 'bitmessagesettings', 'messagesencrypted', 'false') BMConfigParser().set('bitmessagesettings', 'defaultnoncetrialsperbyte', str( - shared.networkDefaultProofOfWorkNonceTrialsPerByte)) + protocol.networkDefaultProofOfWorkNonceTrialsPerByte)) BMConfigParser().set('bitmessagesettings', 'defaultpayloadlengthextrabytes', str( - shared.networkDefaultPayloadLengthExtraBytes)) + protocol.networkDefaultPayloadLengthExtraBytes)) BMConfigParser().set('bitmessagesettings', 'minimizeonclose', 'false') BMConfigParser().set( 'bitmessagesettings', 'maxacceptablenoncetrialsperbyte', '0') @@ -127,12 +129,12 @@ def loadConfig(): if storeConfigFilesInSameDirectoryAsProgramByDefault: # Just use the same directory as the program and forget about # the appdata folder - shared.appdata = '' + state.appdata = '' print 'Creating new config files in same directory as program.' else: - print 'Creating new config files in', shared.appdata - if not os.path.exists(shared.appdata): - os.makedirs(shared.appdata) + print 'Creating new config files in', state.appdata + if not os.path.exists(state.appdata): + os.makedirs(state.appdata) if not sys.platform.startswith('win'): os.umask(0o077) shared.writeKeysFile() diff --git a/src/l10n.py b/src/l10n.py index f8b72650..31df0656 100644 --- a/src/l10n.py +++ b/src/l10n.py @@ -4,7 +4,6 @@ import os import time from configparser import BMConfigParser -import shared #logger = logging.getLogger(__name__) diff --git a/src/message_data_reader.py b/src/message_data_reader.py index a99be336..0c38a291 100644 --- a/src/message_data_reader.py +++ b/src/message_data_reader.py @@ -6,10 +6,11 @@ import sqlite3 from time import strftime, localtime import sys import shared +import state import string from binascii import hexlify -appdata = shared.lookupAppdataFolder() +appdata = paths.lookupAppdataFolder() conn = sqlite3.connect( appdata + 'messages.dat' ) conn.text_factory = str diff --git a/src/network/https.py b/src/network/https.py index 9744a6dc..151efcb8 100644 --- a/src/network/https.py +++ b/src/network/https.py @@ -1,9 +1,10 @@ import asyncore from http import HTTPClient +import paths 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): diff --git a/src/openclpow.py b/src/openclpow.py index 766cbffe..7181c077 100644 --- a/src/openclpow.py +++ b/src/openclpow.py @@ -6,7 +6,8 @@ import random import os from configparser import BMConfigParser -from shared import codePath, shutdown +import paths +from shared import shutdown from debug import logger libAvailable = True @@ -40,7 +41,7 @@ def initCL(): if (len(enabledGpus) > 0): ctx = cl.Context(devices=enabledGpus) 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()) program = cl.Program(ctx, fstr).build(options="") logger.info("Loaded OpenCL kernel") diff --git a/src/paths.py b/src/paths.py new file mode 100644 index 00000000..6b0baf15 --- /dev/null +++ b/src/paths.py @@ -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 [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 = environ.get("RESOURCEPATH") + elif frozen: # windows + codePath = sys._MEIPASS + else: + codePath = path.dirname(__file__) + return codePath + diff --git a/src/proofofwork.py b/src/proofofwork.py index 244f268c..ca48e28b 100644 --- a/src/proofofwork.py +++ b/src/proofofwork.py @@ -8,6 +8,7 @@ import sys import time from configparser import BMConfigParser from debug import logger +import paths import shared import openclpow import tr @@ -169,15 +170,15 @@ def buildCPoW(): if bmpow is not None: return - if shared.frozen is not None: + if paths.frozen is not None: notifyBuild(False) return if sys.platform in ["win32", "win64"]: notifyBuild(False) return try: - call(["make", "-C", os.path.join(shared.codePath(), "bitmsghash")]) - if os.path.exists(os.path.join(shared.codePath(), "bitmsghash", "bitmsghash.so")): + call(["make", "-C", os.path.join(paths.codePath(), "bitmsghash")]) + if os.path.exists(os.path.join(paths.codePath(), "bitmsghash", "bitmsghash.so")): init() notifyBuild(True) else: @@ -208,7 +209,7 @@ def run(target, initialHash): raise except: 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 # does not like this and fights with PyBitmessage # over CPU, resulting in very slow PoW @@ -238,7 +239,7 @@ def init(): bitmsglib = 'bitmsghash64.dll' try: # 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) bmpow = bso.BitmessagePOW bmpow.restype = ctypes.c_ulonglong @@ -248,7 +249,7 @@ def init(): logger.error("C PoW test fail.", exc_info=True) try: # 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) bmpow = bso.BitmessagePOW bmpow.restype = ctypes.c_ulonglong @@ -259,7 +260,7 @@ def init(): bso = None else: 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) except: bso = None diff --git a/src/protocol.py b/src/protocol.py index ecc0f8cc..cb6726e3 100644 --- a/src/protocol.py +++ b/src/protocol.py @@ -1,4 +1,5 @@ import base64 +from binascii import hexlify import hashlib import random import socket @@ -7,9 +8,13 @@ from struct import pack, unpack, Struct import sys import time -from addresses import encodeVarint, decodeVarint +from addresses import calculateInventoryHash, encodeVarint, decodeVarint, decodeAddress, varintDecodeError from configparser import BMConfigParser -from state import neededPubkeys, extPort, socksIP +from debug import logger +from helper_sql import sqlExecute +import highlevelcrypto +from inventory import Inventory +import state from version import softwareVersion #Service flags @@ -22,6 +27,10 @@ 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') @@ -79,11 +88,26 @@ def sslProtocolVersion(): def checkSocksIP(host): try: - if socksIP is None or not socksIP: - socksIP = socket.gethostbyname(BMConfigParser().get("bitmessagesettings", "sockshostname")) + if state.socksIP is None or not state.socksIP: + state.socksIP = socket.gethostbyname(BMConfigParser().get("bitmessagesettings", "sockshostname")) except NameError: - socksIP = socket.gethostbyname(BMConfigParser().get("bitmessagesettings", "sockshostname")) - return socksIP == host + 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 @@ -117,10 +141,10 @@ def assembleVersionMessage(remoteHost, remotePort, myStreamNumber, server = Fals # we have a separate extPort and # incoming over clearnet or # outgoing through clearnet - if BMConfigParser().safeGetBoolean('bitmessagesettings', 'upnp') and extPort \ + 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', extPort) + 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 @@ -178,7 +202,7 @@ def decryptAndCheckPubkeyPayload(data, address): encryptedData = data[readPosition:] # Let us try to decrypt the pubkey - toAddress, cryptorObject = neededPubkeys[tag] + 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. @@ -308,7 +332,7 @@ def _checkAndShareUndefinedObjectWithPeers(data): readPosition += objectVersionLength streamNumber, streamNumberLength = decodeVarint( 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) return @@ -331,7 +355,7 @@ def _checkAndShareMsgWithPeers(data): readPosition += objectVersionLength streamNumber, streamNumberLength = decodeVarint( 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) return readPosition += streamNumberLength @@ -362,7 +386,7 @@ def _checkAndShareGetpubkeyWithPeers(data): readPosition += addressVersionLength streamNumber, streamNumberLength = decodeVarint( 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) return readPosition += streamNumberLength @@ -393,7 +417,7 @@ def _checkAndSharePubkeyWithPeers(data): streamNumber, varintLength = decodeVarint( data[readPosition:readPosition + 10]) 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) return if addressVersion >= 4: @@ -430,7 +454,7 @@ def _checkAndShareBroadcastWithPeers(data): if broadcastVersion >= 2: streamNumber, streamNumberLength = decodeVarint(data[readPosition:readPosition + 10]) 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) return if broadcastVersion >= 3: @@ -452,3 +476,10 @@ def _checkAndShareBroadcastWithPeers(data): # 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) diff --git a/src/shared.py b/src/shared.py index 7f8aca53..d55b3b78 100644 --- a/src/shared.py +++ b/src/shared.py @@ -8,14 +8,11 @@ useVeryEasyProofOfWorkForTesting = False # If you set this to True while on the # Libraries. -import base64 import collections import os import pickle import Queue -import random from multiprocessing import active_children, Queue as mpQueue, Lock as mpLock -import socket import sys import stat import threading @@ -36,6 +33,8 @@ import shared from helper_sql import * from helper_threading import * from inventory import Inventory +import protocol +import state myECCryptorObjects = {} @@ -52,9 +51,7 @@ parserLock = mpLock() addressGeneratorQueue = Queue.Queue() knownNodesLock = threading.Lock() knownNodes = {} -sendDataQueues = [] #each sendData thread puts its queue in this list. printLock = threading.Lock() -appdata = '' #holds the location of the application data storage directory 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. shutdown = 0 #Set to 1 by the doCleanShutdown function. Used to tell the proof of work worker threads to exit. @@ -86,27 +83,17 @@ daemon = False needToWriteKnownNodesToDisk = False # If True, the singleCleaner will write it to disk eventually. maximumLengthOfTimeToBotherResendingMessages = 0 objectProcessorQueue = ObjectProcessorQueue() # receiveDataThreads dump objects they hear on the network into this queue to be processed. -streamsInWhichIAmParticipating = {} timeOffsetWrongCount = 0 # sanity check, prevent doing ridiculous PoW # 20 million PoWs equals approximately 2 days on dev's dual R9 290 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 # it as default whenever the user changes the "method" selection for # namecoin integration to "namecoind". 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 # contain a Peer which will be connected to instead of using the # addresses advertised by other peers. The client will only connect to @@ -119,68 +106,6 @@ frozen = getattr(sys,'frozen', None) # security. trustedPeer = 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 [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): queryreturn = sqlQuery( '''select address from addressbook where address=?''', @@ -236,7 +161,7 @@ def reloadMyAddressHashes(): myAddressesByTag.clear() #myPrivateKeys.clear() - keyfileSecure = checkSensitiveFilePermissions(appdata + 'keys.dat') + keyfileSecure = checkSensitiveFilePermissions(state.appdata + 'keys.dat') configSections = BMConfigParser().sections() hasEnabledKeys = False for addressInKeysFile in configSections: @@ -262,7 +187,7 @@ def reloadMyAddressHashes(): logger.error('Error in reloadMyAddressHashes: Can\'t handle address versions other than 2, 3, or 4.\n') if not keyfileSecure: - fixSensitiveFilePermissions(appdata + 'keys.dat', hasEnabledKeys) + fixSensitiveFilePermissions(state.appdata + 'keys.dat', hasEnabledKeys) def reloadBroadcastSendersForWhichImWatching(): broadcastSendersForWhichImWatching.clear() @@ -286,21 +211,6 @@ def reloadBroadcastSendersForWhichImWatching(): privEncryptionKey = doubleHashOfAddressData[:32] 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(): global shutdown, thisapp shutdown = 1 #Used to tell proof of work worker threads and the objectProcessorThread to exit. @@ -308,7 +218,7 @@ def doCleanShutdown(): parserInputQueue.put(None, False) except Queue.Full: pass - broadcastToSendDataQueues((0, 'shutdown', 'no data')) + protocol.broadcastToSendDataQueues((0, 'shutdown', 'no data')) objectProcessorQueue.put(('checkShutdownVariable', 'no data')) for thread in threading.enumerate(): if thread.isAlive() and isinstance(thread, StoppableThread): @@ -316,7 +226,7 @@ def doCleanShutdown(): knownNodesLock.acquire() 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') pickle.dump(knownNodes, output) logger.info('Completed pickle.dump. Closing output...') @@ -359,14 +269,6 @@ def doCleanShutdown(): else: 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): try: unicode(text,'utf-8') @@ -554,7 +456,7 @@ def checkAndShareObjectWithPeers(data): 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): + if not protocol.isProofOfWorkSufficient(data): logger.info('Proof of work is insufficient.') return 0 @@ -597,7 +499,7 @@ def _checkAndShareUndefinedObjectWithPeers(data): readPosition += objectVersionLength streamNumber, streamNumberLength = decodeVarint( 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) return @@ -609,7 +511,7 @@ def _checkAndShareUndefinedObjectWithPeers(data): Inventory()[inventoryHash] = ( objectType, streamNumber, data, embeddedTime,'') logger.debug('advertising inv with hash: %s' % hexlify(inventoryHash)) - broadcastToSendDataQueues((streamNumber, 'advertiseobject', inventoryHash)) + protocol.broadcastToSendDataQueues((streamNumber, 'advertiseobject', inventoryHash)) def _checkAndShareMsgWithPeers(data): @@ -620,7 +522,7 @@ def _checkAndShareMsgWithPeers(data): readPosition += objectVersionLength streamNumber, streamNumberLength = decodeVarint( 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) return readPosition += streamNumberLength @@ -633,7 +535,7 @@ def _checkAndShareMsgWithPeers(data): Inventory()[inventoryHash] = ( objectType, streamNumber, data, embeddedTime,'') 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. objectProcessorQueue.put((objectType,data)) @@ -651,7 +553,7 @@ def _checkAndShareGetpubkeyWithPeers(data): readPosition += addressVersionLength streamNumber, streamNumberLength = decodeVarint( 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) return readPosition += streamNumberLength @@ -666,7 +568,7 @@ def _checkAndShareGetpubkeyWithPeers(data): 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)) + protocol.broadcastToSendDataQueues((streamNumber, 'advertiseobject', inventoryHash)) # Now let's queue it to be processed ourselves. objectProcessorQueue.put((objectType,data)) @@ -682,7 +584,7 @@ def _checkAndSharePubkeyWithPeers(data): streamNumber, varintLength = decodeVarint( data[readPosition:readPosition + 10]) 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) return if addressVersion >= 4: @@ -700,7 +602,7 @@ def _checkAndSharePubkeyWithPeers(data): 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)) + protocol.broadcastToSendDataQueues((streamNumber, 'advertiseobject', inventoryHash)) # Now let's queue it to be processed ourselves. @@ -719,7 +621,7 @@ def _checkAndShareBroadcastWithPeers(data): if broadcastVersion >= 2: streamNumber, streamNumberLength = decodeVarint(data[readPosition:readPosition + 10]) 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) return if broadcastVersion >= 3: @@ -736,19 +638,19 @@ def _checkAndShareBroadcastWithPeers(data): 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)) + protocol.broadcastToSendDataQueues((streamNumber, 'advertiseobject', inventoryHash)) # Now let's queue it to be processed ourselves. objectProcessorQueue.put((objectType,data)) def openKeysFile(): if 'linux' in sys.platform: - subprocess.call(["xdg-open", shared.appdata + 'keys.dat']) + subprocess.call(["xdg-open", state.appdata + 'keys.dat']) else: - os.startfile(shared.appdata + 'keys.dat') + os.startfile(state.appdata + 'keys.dat') 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' # create a backup copy to prevent the accidental loss due to the disk write failure try: diff --git a/src/singleinstance.py b/src/singleinstance.py index 8bf7ed01..1fd2ff20 100644 --- a/src/singleinstance.py +++ b/src/singleinstance.py @@ -6,6 +6,7 @@ from multiprocessing import Process import os import sys import shared +import state try: import fcntl # @UnresolvedImport @@ -24,7 +25,7 @@ class singleinstance: self.counter = 0 self.daemon = daemon self.lockPid = None - self.lockfile = os.path.normpath(os.path.join(shared.appdata, 'singleton%s.lock' % flavor_id)) + 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. diff --git a/src/state.py b/src/state.py index e3ff6289..f3fb8a53 100644 --- a/src/state.py +++ b/src/state.py @@ -1,7 +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 diff --git a/src/tr.py b/src/tr.py index b7a8e6f0..5146a162 100644 --- a/src/tr.py +++ b/src/tr.py @@ -1,7 +1,6 @@ import os from configparser import BMConfigParser -import shared # 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: From fa0a3135e78d033530cd48a5048262b97cebe50b Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Wed, 11 Jan 2017 17:26:25 +0100 Subject: [PATCH 10/12] Fixes pointed out by landscape.io - missing/wrong/obsolete imports - logger formatting --- src/api.py | 1 + src/bitmessagemain.py | 1 + src/bitmessageqt/support.py | 1 + src/bitmessageqt/utils.py | 1 - src/class_addressGenerator.py | 1 + src/class_sqlThread.py | 1 + src/debug.py | 1 - src/helper_startup.py | 1 + src/message_data_reader.py | 2 +- src/paths.py | 6 +++--- src/protocol.py | 39 +++++++++++++++++------------------ src/shared.py | 2 +- 12 files changed, 30 insertions(+), 27 deletions(-) diff --git a/src/api.py b/src/api.py index a3c80283..18b2dd20 100644 --- a/src/api.py +++ b/src/api.py @@ -24,6 +24,7 @@ import helper_inbox import helper_sent import hashlib +import protocol import state from pyelliptic.openssl import OpenSSL from struct import pack diff --git a/src/bitmessagemain.py b/src/bitmessagemain.py index 5c41e4e5..cd7205e8 100755 --- a/src/bitmessagemain.py +++ b/src/bitmessagemain.py @@ -29,6 +29,7 @@ from helper_startup import isOurOperatingSystemLimitedToHavingVeryFewHalfOpenCon import shared from helper_sql import sqlQuery import state +import protocol import threading # Classes diff --git a/src/bitmessageqt/support.py b/src/bitmessageqt/support.py index aae5134f..07d0ab3a 100644 --- a/src/bitmessageqt/support.py +++ b/src/bitmessageqt/support.py @@ -13,6 +13,7 @@ from l10n import getTranslationLanguage from openclpow import openclAvailable, openclEnabled import paths from proofofwork import bmpow +import protocol from pyelliptic.openssl import OpenSSL import shared import state diff --git a/src/bitmessageqt/utils.py b/src/bitmessageqt/utils.py index 1a5b67d7..fd18183d 100644 --- a/src/bitmessageqt/utils.py +++ b/src/bitmessageqt/utils.py @@ -1,7 +1,6 @@ from PyQt4 import QtGui import hashlib import os -import shared from addresses import addBMIfNotPresent from configparser import BMConfigParser import state diff --git a/src/class_addressGenerator.py b/src/class_addressGenerator.py index ff5eb25e..ebedf2f9 100644 --- a/src/class_addressGenerator.py +++ b/src/class_addressGenerator.py @@ -10,6 +10,7 @@ from addresses import * from configparser import BMConfigParser from debug import logger from helper_threading import * +import protocol from pyelliptic import arithmetic import tr from binascii import hexlify diff --git a/src/class_sqlThread.py b/src/class_sqlThread.py index 2beb50dc..df747aea 100644 --- a/src/class_sqlThread.py +++ b/src/class_sqlThread.py @@ -9,6 +9,7 @@ import os from debug import logger from namecoin import ensureNamecoinOptions import paths +import protocol import random import state import string diff --git a/src/debug.py b/src/debug.py index 24e43332..663bbeeb 100644 --- a/src/debug.py +++ b/src/debug.py @@ -19,7 +19,6 @@ Use: `from debug import logger` to import this facility into whatever module you import logging import logging.config import os -import shared import sys import traceback import helper_startup diff --git a/src/helper_startup.py b/src/helper_startup.py index c0f84635..86d3de42 100644 --- a/src/helper_startup.py +++ b/src/helper_startup.py @@ -11,6 +11,7 @@ from distutils.version import StrictVersion 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. diff --git a/src/message_data_reader.py b/src/message_data_reader.py index 0c38a291..79a3a607 100644 --- a/src/message_data_reader.py +++ b/src/message_data_reader.py @@ -6,8 +6,8 @@ import sqlite3 from time import strftime, localtime import sys import shared +import paths import state -import string from binascii import hexlify appdata = paths.lookupAppdataFolder() diff --git a/src/paths.py b/src/paths.py index 6b0baf15..e92116c0 100644 --- a/src/paths.py +++ b/src/paths.py @@ -23,11 +23,11 @@ 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 + if dataFolder[-1] not in [path.sep, path.altsep]: + dataFolder += path.sep elif sys.platform == 'darwin': if "HOME" in environ: - dataFolder = path.join(os.environ["HOME"], "Library/Application Support/", APPNAME) + '/' + 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(): diff --git a/src/protocol.py b/src/protocol.py index cb6726e3..cf0d65d4 100644 --- a/src/protocol.py +++ b/src/protocol.py @@ -204,7 +204,7 @@ def decryptAndCheckPubkeyPayload(data, address): # 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)) + 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' @@ -260,12 +260,11 @@ def decryptAndCheckPubkeyPayload(data, address): logger.info('within decryptAndCheckPubkeyPayload, addressVersion: %s, streamNumber: %s \n\ ripe %s\n\ publicSigningKey in hex: %s\n\ - publicEncryptionKey in hex: %s' % (addressVersion, + publicEncryptionKey in hex: %s', addressVersion, streamNumber, hexlify(ripe), hexlify(publicSigningKey), hexlify(publicEncryptionKey) - ) ) t = (address, addressVersion, storedData, int(time.time()), 'yes') @@ -275,7 +274,7 @@ def decryptAndCheckPubkeyPayload(data, address): 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()) + 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): @@ -286,7 +285,7 @@ def checkAndShareObjectWithPeers(data): 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)) + 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): @@ -295,10 +294,10 @@ def checkAndShareObjectWithPeers(data): 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) + 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) + 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: @@ -318,9 +317,9 @@ def checkAndShareObjectWithPeers(data): _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) + 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()) + 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 @@ -333,7 +332,7 @@ def _checkAndShareUndefinedObjectWithPeers(data): 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) + logger.debug('The streamNumber %s isn\'t one we are interested in.', streamNumber) return inventoryHash = calculateInventoryHash(data) @@ -343,7 +342,7 @@ def _checkAndShareUndefinedObjectWithPeers(data): objectType, = unpack('>I', data[16:20]) Inventory()[inventoryHash] = ( objectType, streamNumber, data, embeddedTime,'') - logger.debug('advertising inv with hash: %s' % hexlify(inventoryHash)) + logger.debug('advertising inv with hash: %s', hexlify(inventoryHash)) broadcastToSendDataQueues((streamNumber, 'advertiseobject', inventoryHash)) @@ -356,7 +355,7 @@ def _checkAndShareMsgWithPeers(data): 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) + logger.debug('The streamNumber %s isn\'t one we are interested in.', streamNumber) return readPosition += streamNumberLength inventoryHash = calculateInventoryHash(data) @@ -367,7 +366,7 @@ def _checkAndShareMsgWithPeers(data): objectType = 2 Inventory()[inventoryHash] = ( objectType, streamNumber, data, embeddedTime,'') - logger.debug('advertising inv with hash: %s' % hexlify(inventoryHash)) + logger.debug('advertising inv with hash: %s', hexlify(inventoryHash)) broadcastToSendDataQueues((streamNumber, 'advertiseobject', inventoryHash)) # Now let's enqueue it to be processed ourselves. @@ -387,7 +386,7 @@ def _checkAndShareGetpubkeyWithPeers(data): 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) + logger.debug('The streamNumber %s isn\'t one we are interested in.', streamNumber) return readPosition += streamNumberLength @@ -400,7 +399,7 @@ def _checkAndShareGetpubkeyWithPeers(data): Inventory()[inventoryHash] = ( objectType, streamNumber, data, embeddedTime,'') # 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)) # Now let's queue it to be processed ourselves. @@ -418,11 +417,11 @@ def _checkAndSharePubkeyWithPeers(data): 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) + 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)) + logger.debug('tag in received pubkey is: %s', hexlify(tag)) else: tag = '' @@ -434,7 +433,7 @@ def _checkAndSharePubkeyWithPeers(data): Inventory()[inventoryHash] = ( objectType, streamNumber, data, embeddedTime, tag) # 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)) @@ -455,7 +454,7 @@ def _checkAndShareBroadcastWithPeers(data): 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) + logger.debug('The streamNumber %s isn\'t one we are interested in.', streamNumber) return if broadcastVersion >= 3: tag = data[readPosition:readPosition+32] @@ -470,7 +469,7 @@ def _checkAndShareBroadcastWithPeers(data): Inventory()[inventoryHash] = ( objectType, streamNumber, data, embeddedTime, tag) # 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)) # Now let's queue it to be processed ourselves. diff --git a/src/shared.py b/src/shared.py index d55b3b78..11058fd7 100644 --- a/src/shared.py +++ b/src/shared.py @@ -19,7 +19,6 @@ import threading import time import shutil # used for moving the data folder and copying keys.dat import datetime -from os import path, environ import traceback from binascii import hexlify @@ -645,6 +644,7 @@ def _checkAndShareBroadcastWithPeers(data): def openKeysFile(): if 'linux' in sys.platform: + import subprocess subprocess.call(["xdg-open", state.appdata + 'keys.dat']) else: os.startfile(state.appdata + 'keys.dat') From cdcdf11d59d47d4c21eb21dce12f5fb3b46e6dc3 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Wed, 11 Jan 2017 17:46:33 +0100 Subject: [PATCH 11/12] Missing import fix --- src/protocol.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/protocol.py b/src/protocol.py index cf0d65d4..970b63b0 100644 --- a/src/protocol.py +++ b/src/protocol.py @@ -7,6 +7,7 @@ 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 c738d93056b0f1b04c723ab5ac3bc82a9521fc37 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Wed, 11 Jan 2017 18:13:00 +0100 Subject: [PATCH 12/12] Assorted fixes - landscape.io was complaining, this fixes most easily fixable errors --- src/bitmessageqt/__init__.py | 12 ++---------- src/bitmessageqt/account.py | 8 ++++---- src/bitmessageqt/blacklist.py | 1 - src/bitmessageqt/newaddresswizard.py | 10 +++++----- src/class_objectHashHolder.py | 1 - src/class_receiveDataThread.py | 4 ++-- src/class_smtpDeliver.py | 1 + src/class_smtpServer.py | 3 ++- src/openclpow.py | 4 ---- src/proofofwork.py | 3 +-- src/shared.py | 2 +- src/upnp.py | 15 ++++++++------- 12 files changed, 26 insertions(+), 38 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 91424c86..008647ab 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -19,6 +19,7 @@ try: 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).' logger.critical(logmsg, exc_info=True) + import sys sys.exit() try: @@ -1214,8 +1215,6 @@ class MyForm(settingsmixin.SMainWindow): # When an unread inbox row is selected on then clear the messaging menu def ubuntuMessagingMenuClear(self, inventoryHash): - global withMessagingMenu - # if this isn't ubuntu then don't do anything if not self.isUbuntu(): return @@ -1315,8 +1314,6 @@ class MyForm(settingsmixin.SMainWindow): # update the Ubuntu messaging menu def ubuntuMessagingMenuUpdate(self, drawAttention, newItem, toLabel): - global withMessagingMenu - # if this isn't ubuntu then don't do anything if not self.isUbuntu(): return @@ -1440,14 +1437,11 @@ class MyForm(settingsmixin.SMainWindow): # initialise the message notifier def notifierInit(self): - global withMessagingMenu if withMessagingMenu: Notify.init('pybitmessage') # shows a notification def notifierShow(self, title, subtitle, fromCategory, label): - global withMessagingMenu - self.playSound(fromCategory, label) if withMessagingMenu: @@ -1642,7 +1636,6 @@ class MyForm(settingsmixin.SMainWindow): connected = False def setStatusIcon(self, color): - global withMessagingMenu # print 'setting status icon color' if color == 'red': self.pushButtonStatusIcon.setIcon( @@ -3057,7 +3050,7 @@ class MyForm(settingsmixin.SMainWindow): 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) - 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: messageLists = (self.ui.tableWidgetInbox, self.ui.tableWidgetInboxChans, self.ui.tableWidgetInboxSubscriptions) elif type(messageLists) not in (list, tuple): @@ -4447,7 +4440,6 @@ class MySingleApplication(QApplication): self.server.close() def on_new_connection(self): - global myapp if myapp: myapp.appIndicatorShow() diff --git a/src/bitmessageqt/account.py b/src/bitmessageqt/account.py index 6e830b38..bdfeaed3 100644 --- a/src/bitmessageqt/account.py +++ b/src/bitmessageqt/account.py @@ -147,7 +147,7 @@ class GatewayAccount(BMAccount): ALL_OK = 0 REGISTRATION_DENIED = 1 def __init__(self, address): - super(BMAccount, self).__init__(address) + super(GatewayAccount, self).__init__(address) def send(self): status, addressVersionNumber, streamNumber, ripe = decodeAddress(self.toAddress) @@ -175,7 +175,7 @@ class GatewayAccount(BMAccount): shared.workerQueue.put(('sendmessage', self.toAddress)) 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): # set "gateway" in keys.dat to this @@ -186,7 +186,7 @@ class MailchuckAccount(GatewayAccount): regExpIncoming = re.compile("(.*)MAILCHUCK-FROM::(\S+) \| (.*)") regExpOutgoing = re.compile("(\S+) (.*)") def __init__(self, address): - super(GatewayAccount, self).__init__(address) + super(MailchuckAccount, self).__init__(address) self.feedback = self.ALL_OK def createMessage(self, toAddress, fromAddress, subject, message): @@ -262,7 +262,7 @@ class MailchuckAccount(GatewayAccount): self.fromAddress = self.address 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: matches = self.regExpIncoming.search(subject) if not matches is None: diff --git a/src/bitmessageqt/blacklist.py b/src/bitmessageqt/blacklist.py index 6fcb8f11..94844da5 100644 --- a/src/bitmessageqt/blacklist.py +++ b/src/bitmessageqt/blacklist.py @@ -2,7 +2,6 @@ from PyQt4 import QtCore, QtGui import shared from tr import _translate import l10n -from uisignaler import UISignaler import widgets from addresses import addBMIfNotPresent from configparser import BMConfigParser diff --git a/src/bitmessageqt/newaddresswizard.py b/src/bitmessageqt/newaddresswizard.py index e54b18c3..2311239c 100644 --- a/src/bitmessageqt/newaddresswizard.py +++ b/src/bitmessageqt/newaddresswizard.py @@ -316,19 +316,19 @@ class NewAddressThread(QtCore.QThread): def __del__(self): self.wait() - def createDeterministic(): + def createDeterministic(self): pass - def createPassphrase(): + def createPassphrase(self): pass - def broadcastAddress(): + def broadcastAddress(self): pass - def registerMailchuck(): + def registerMailchuck(self): pass - def waitRegistration(): + def waitRegistration(self): pass def run(self): diff --git a/src/class_objectHashHolder.py b/src/class_objectHashHolder.py index 24c2438d..2e456d8c 100644 --- a/src/class_objectHashHolder.py +++ b/src/class_objectHashHolder.py @@ -41,7 +41,6 @@ class objectHashHolder(threading.Thread): def hasHash(self, hash): if hash in (hashlist for hashlist in self.collectionOfHashLists): - logger.debug("Hash in hashHolder") return True return False diff --git a/src/class_receiveDataThread.py b/src/class_receiveDataThread.py index cf43f7b3..3112575a 100644 --- a/src/class_receiveDataThread.py +++ b/src/class_receiveDataThread.py @@ -270,9 +270,9 @@ class receiveDataThread(threading.Thread): self.processData() - def sendpong(self): + def sendpong(self, payload): logger.debug('Sending pong') - self.sendDataThreadQueue.put((0, 'sendRawData', protocol.CreatePacket('pong'))) + self.sendDataThreadQueue.put((0, 'sendRawData', protocol.CreatePacket('pong', payload))) def recverack(self): diff --git a/src/class_smtpDeliver.py b/src/class_smtpDeliver.py index ca51946f..18206065 100644 --- a/src/class_smtpDeliver.py +++ b/src/class_smtpDeliver.py @@ -8,6 +8,7 @@ import urlparse from configparser import BMConfigParser from debug import logger from helper_threading import * +from bitmessageqt.uisignaler import UISignaler import shared SMTPDOMAIN = "bmaddr.lan" diff --git a/src/class_smtpServer.py b/src/class_smtpServer.py index 4043600c..65a7e1fc 100644 --- a/src/class_smtpServer.py +++ b/src/class_smtpServer.py @@ -6,6 +6,7 @@ from email.header import decode_header import re import signal import smtpd +import socket import threading import time @@ -43,7 +44,7 @@ class smtpServerChannel(smtpd.SMTPChannel): self.auth = True self.push('235 2.7.0 Authentication successful') else: - raise Error("Auth fail") + raise Exception("Auth fail") except: self.push('501 Authentication fail') diff --git a/src/openclpow.py b/src/openclpow.py index 7181c077..001333e5 100644 --- a/src/openclpow.py +++ b/src/openclpow.py @@ -53,16 +53,12 @@ def initCL(): enabledGpus = [] def openclAvailable(): - global gpus return (len(gpus) > 0) def openclEnabled(): - global enabledGpus return (len(enabledGpus) > 0) def do_opencl_pow(hash, target): - global ctx, queue, program, enabledGpus, hash_dt - output = numpy.zeros(1, dtype=[('v', numpy.uint64, 1)]) if (len(enabledGpus) == 0): return output[0][0] diff --git a/src/proofofwork.py b/src/proofofwork.py index ca48e28b..78188777 100644 --- a/src/proofofwork.py +++ b/src/proofofwork.py @@ -19,8 +19,7 @@ bitmsglib = 'bitmsghash.so' def _set_idle(): if 'linux' in sys.platform: - import os - os.nice(20) # @UndefinedVariable + os.nice(20) else: try: sys.getwindowsversion() diff --git a/src/shared.py b/src/shared.py index 11058fd7..d5438b1c 100644 --- a/src/shared.py +++ b/src/shared.py @@ -211,7 +211,7 @@ def reloadBroadcastSendersForWhichImWatching(): MyECSubscriptionCryptorObjects[tag] = highlevelcrypto.makeCryptor(hexlify(privEncryptionKey)) def doCleanShutdown(): - global shutdown, thisapp + global shutdown shutdown = 1 #Used to tell proof of work worker threads and the objectProcessorThread to exit. try: parserInputQueue.put(None, False) diff --git a/src/upnp.py b/src/upnp.py index fd6f3852..69f89233 100644 --- a/src/upnp.py +++ b/src/upnp.py @@ -11,7 +11,7 @@ from helper_threading import * import shared import tr -def createRequestXML(service, action, arguments=[]): +def createRequestXML(service, action, arguments=None): from xml.dom.minidom import Document doc = Document() @@ -37,11 +37,12 @@ def createRequestXML(service, action, arguments=[]): # iterate over arguments, create nodes, create text nodes, # append text nodes to nodes, and finally add the ready product # to argument_list - for k, v in arguments: - tmp_node = doc.createElement(k) - tmp_text_node = doc.createTextNode(v) - tmp_node.appendChild(tmp_text_node) - argument_list.append(tmp_node) + if arguments is not None: + for k, v in arguments: + tmp_node = doc.createElement(k) + tmp_text_node = doc.createTextNode(v) + tmp_node.appendChild(tmp_text_node) + argument_list.append(tmp_node) # append the prepared argument nodes to the function element for arg in argument_list: @@ -140,7 +141,7 @@ class Router: dom = parseString(resp) 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 debug import logger conn = httplib.HTTPConnection(self.routerPath.hostname, self.routerPath.port)