From a293cef8d1085cff0434d2f884c50c141b539100 Mon Sep 17 00:00:00 2001 From: Jonathan Warren Date: Fri, 24 May 2013 16:12:16 -0400 Subject: [PATCH 1/3] Added new deterministic address and subscription-related commands --- Makefile | 2 +- debian.sh | 2 +- src/api client.py | 13 ++- src/bitmessagemain.py | 214 ++++++++++++++++++++++------------- src/bitmessageqt/__init__.py | 52 +++++---- src/shared.py | 2 +- 6 files changed, 182 insertions(+), 103 deletions(-) diff --git a/Makefile b/Makefile index 6c3632e7..5031881c 100755 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ APP=pybitmessage -VERSION=0.3.0 +VERSION=0.3.1 DEST_SHARE=/usr/share DEST_APP=$(DEST_SHARE)/$(APP) diff --git a/debian.sh b/debian.sh index 194d19b2..ac2121d5 100755 --- a/debian.sh +++ b/debian.sh @@ -7,7 +7,7 @@ #!/bin/bash APP=pybitmessage -VERSION=0.3.0 +VERSION=0.3.1 ARCH_TYPE=all # Create a source archive diff --git a/src/api client.py b/src/api client.py index b823a75a..e07258d5 100644 --- a/src/api client.py +++ b/src/api client.py @@ -25,7 +25,7 @@ print jsonAddresses print 'Now that we have our address data in a nice Python data structure, let\'s look at the first address (index 0) and print its label:' print jsonAddresses['addresses'][0]['label'] -print 'Uncomment the next two lines to create a new random address with slightly a slightly higher difficulty setting than normal.' +print 'Uncomment the next two lines to create a new random address with a slightly higher difficulty setting than normal.' #addressLabel = 'new address label'.encode('base64') #print api.createRandomAddress(addressLabel,False,1.05,1.1111) @@ -35,6 +35,15 @@ print 'Uncomment these next four lines to create new deterministic addresses.' #print jsonDeterministicAddresses #print json.loads(jsonDeterministicAddresses) +#print 'Uncomment this next line to print the first deterministic address that would be generated with the given passphrase. This will Not add it to the Bitmessage interface or the keys.dat file.' +#print api.getDeterministicAddress('asdfasdfqwser'.encode('base64'),3,1) + +#print 'Uncomment this line to subscribe to an address. (You must use your own address, this one is invalid).' +#print api.addSubscription('2D94G5d8yp237GGqAheoecBYpdehdT3dha','test sub'.encode('base64')) + +#print 'Uncomment this line to unsubscribe from an address.' +#print api.deleteSubscription('2D94G5d8yp237GGqAheoecBYpdehdT3dha') + print 'Let\'s now print all of our inbox messages:' print api.getAllInboxMessages() inboxMessages = json.loads(api.getAllInboxMessages()) @@ -58,4 +67,4 @@ print 'Uncomment these lines to send a message. The example addresses are invali print 'Uncomment these lines to send a broadcast. The example address is invalid; you will have to put your own in.' #subject = 'subject within broadcast'.encode('base64') #message = 'Hello, this is the message within a broadcast.'.encode('base64') -#print api.sendBroadcast('BM-onf6V1RELPgeNN6xw9yhpAiNiRexSRD4e', subject,message) \ No newline at end of file +#print api.sendBroadcast('BM-onf6V1RELPgeNN6xw9yhpAiNiRexSRD4e', subject,message) diff --git a/src/bitmessagemain.py b/src/bitmessagemain.py index 35d64144..d5bc95de 100755 --- a/src/bitmessagemain.py +++ b/src/bitmessagemain.py @@ -18,7 +18,6 @@ useVeryEasyProofOfWorkForTesting = False #If you set this to True while on the n encryptedBroadcastSwitchoverTime = 1369735200 import sys - import ConfigParser import Queue from addresses import * @@ -3221,10 +3220,10 @@ class addressGenerator(threading.Thread): queueValue = shared.addressGeneratorQueue.get() nonceTrialsPerByte = 0 payloadLengthExtraBytes = 0 - if len(queueValue) == 6: - addressVersionNumber,streamNumber,label,numberOfAddressesToMake,deterministicPassphrase,eighteenByteRipe = queueValue - elif len(queueValue) == 8: - addressVersionNumber,streamNumber,label,numberOfAddressesToMake,deterministicPassphrase,eighteenByteRipe,nonceTrialsPerByte,payloadLengthExtraBytes = queueValue + if len(queueValue) == 7: + command,addressVersionNumber,streamNumber,label,numberOfAddressesToMake,deterministicPassphrase,eighteenByteRipe = queueValue + elif len(queueValue) == 9: + command,addressVersionNumber,streamNumber,label,numberOfAddressesToMake,deterministicPassphrase,eighteenByteRipe,nonceTrialsPerByte,payloadLengthExtraBytes = queueValue else: sys.stderr.write('Programming error: A structure with the wrong number of values was passed into the addressGeneratorQueue. Here is the queueValue: %s\n' % queueValue) if addressVersionNumber < 3 or addressVersionNumber > 3: @@ -3238,7 +3237,7 @@ class addressGenerator(threading.Thread): if payloadLengthExtraBytes < shared.networkDefaultPayloadLengthExtraBytes: payloadLengthExtraBytes = shared.networkDefaultPayloadLengthExtraBytes if addressVersionNumber == 3: #currently the only one supported. - if deterministicPassphrase == "": + if command == 'createRandomAddress': shared.UISignalQueue.put(('updateStatusBar','Generating one new address')) #This next section is a little bit strange. We're going to generate keys over and over until we #find one that starts with either \x00 or \x00\x00. Then when we pack them into a Bitmessage address, @@ -3301,10 +3300,12 @@ class addressGenerator(threading.Thread): shared.reloadMyAddressHashes() shared.workerQueue.put(('doPOWForMyV3Pubkey',ripe.digest())) - else: #There is something in the deterministicPassphrase variable thus we are going to do this deterministically. - statusbar = 'Generating '+str(numberOfAddressesToMake) + ' new addresses.' - #self.emit(SIGNAL("updateStatusBar(PyQt_PyObject)"),statusbar) - shared.UISignalQueue.put(('updateStatusBar',statusbar)) + elif command == 'createDeterministicAddresses' or command == 'getDeterministicAddress': + if len(deterministicPassphrase) == 0: + sys.stderr.write('WARNING: You are creating deterministic address(es) using a blank passphrase. Bitmessage will do it but it is rather stupid.') + if command == 'createDeterministicAddresses': + statusbar = 'Generating '+str(numberOfAddressesToMake) + ' new addresses.' + shared.UISignalQueue.put(('updateStatusBar',statusbar)) signingKeyNonce = 0 encryptionKeyNonce = 1 listOfNewAddressesToSendOutThroughTheAPI = [] #We fill out this list no matter what although we only need it if we end up passing the info to the API. @@ -3340,44 +3341,49 @@ class addressGenerator(threading.Thread): print 'ripe.digest', ripe.digest().encode('hex') print 'Address generator calculated', numberOfAddressesWeHadToMakeBeforeWeFoundOneWithTheCorrectRipePrefix, 'addresses at', numberOfAddressesWeHadToMakeBeforeWeFoundOneWithTheCorrectRipePrefix/(time.time()-startTime),'keys per second.' address = encodeAddress(3,streamNumber,ripe.digest()) - #self.emit(SIGNAL("updateStatusBar(PyQt_PyObject)"),'Finished generating address. Writing to keys.dat') - #An excellent way for us to store our keys is in Wallet Import Format. Let us convert now. - #https://en.bitcoin.it/wiki/Wallet_import_format - privSigningKey = '\x80'+potentialPrivSigningKey - checksum = hashlib.sha256(hashlib.sha256(privSigningKey).digest()).digest()[0:4] - privSigningKeyWIF = arithmetic.changebase(privSigningKey + checksum,256,58) + if command == 'createDeterministicAddresses': + #An excellent way for us to store our keys is in Wallet Import Format. Let us convert now. + #https://en.bitcoin.it/wiki/Wallet_import_format + privSigningKey = '\x80'+potentialPrivSigningKey + checksum = hashlib.sha256(hashlib.sha256(privSigningKey).digest()).digest()[0:4] + privSigningKeyWIF = arithmetic.changebase(privSigningKey + checksum,256,58) - privEncryptionKey = '\x80'+potentialPrivEncryptionKey - checksum = hashlib.sha256(hashlib.sha256(privEncryptionKey).digest()).digest()[0:4] - privEncryptionKeyWIF = arithmetic.changebase(privEncryptionKey + checksum,256,58) + privEncryptionKey = '\x80'+potentialPrivEncryptionKey + checksum = hashlib.sha256(hashlib.sha256(privEncryptionKey).digest()).digest()[0:4] + privEncryptionKeyWIF = arithmetic.changebase(privEncryptionKey + checksum,256,58) - try: - shared.config.add_section(address) - print 'label:', label - shared.config.set(address,'label',label) - shared.config.set(address,'enabled','true') - shared.config.set(address,'decoy','false') - shared.config.set(address,'noncetrialsperbyte',str(nonceTrialsPerByte)) - shared.config.set(address,'payloadlengthextrabytes',str(payloadLengthExtraBytes)) - shared.config.set(address,'privSigningKey',privSigningKeyWIF) - shared.config.set(address,'privEncryptionKey',privEncryptionKeyWIF) - with open(shared.appdata + 'keys.dat', 'wb') as configfile: - shared.config.write(configfile) + try: + shared.config.add_section(address) + print 'label:', label + shared.config.set(address,'label',label) + shared.config.set(address,'enabled','true') + shared.config.set(address,'decoy','false') + shared.config.set(address,'noncetrialsperbyte',str(nonceTrialsPerByte)) + shared.config.set(address,'payloadlengthextrabytes',str(payloadLengthExtraBytes)) + shared.config.set(address,'privSigningKey',privSigningKeyWIF) + shared.config.set(address,'privEncryptionKey',privEncryptionKeyWIF) + with open(shared.appdata + 'keys.dat', 'wb') as configfile: + shared.config.write(configfile) - #self.emit(SIGNAL("writeNewAddressToTable(PyQt_PyObject,PyQt_PyObject,PyQt_PyObject)"),self.label,address,str(self.streamNumber)) - shared.UISignalQueue.put(('writeNewAddressToTable',(label,address,str(streamNumber)))) - listOfNewAddressesToSendOutThroughTheAPI.append(address) - if eighteenByteRipe: - shared.reloadMyAddressHashes()#This is necessary here (rather than just at the end) because otherwise if the human generates a large number of new addresses and uses one before they are done generating, the program will receive a getpubkey message and will ignore it. - except: - print address,'already exists. Not adding it again.' + #self.emit(SIGNAL("writeNewAddressToTable(PyQt_PyObject,PyQt_PyObject,PyQt_PyObject)"),self.label,address,str(self.streamNumber)) + shared.UISignalQueue.put(('writeNewAddressToTable',(label,address,str(streamNumber)))) + listOfNewAddressesToSendOutThroughTheAPI.append(address) + if eighteenByteRipe: + shared.reloadMyAddressHashes()#This is necessary here (rather than just at the end) because otherwise if the human generates a large number of new addresses and uses one before they are done generating, the program will receive a getpubkey message and will ignore it. + except: + print address,'already exists. Not adding it again.' + + #Done generating addresses. #It may be the case that this address is being generated as a result of a call to the API. Let us put the result in the necessary queue. - apiAddressGeneratorReturnQueue.put(listOfNewAddressesToSendOutThroughTheAPI) - #self.emit(SIGNAL("updateStatusBar(PyQt_PyObject)"),'Done generating address') - shared.UISignalQueue.put(('updateStatusBar','Done generating address')) - shared.reloadMyAddressHashes() - + if command == 'createDeterministicAddresses': + apiAddressGeneratorReturnQueue.put(listOfNewAddressesToSendOutThroughTheAPI) + shared.UISignalQueue.put(('updateStatusBar','Done generating address')) + shared.reloadMyAddressHashes() + elif command == 'getDeterministicAddress': + apiAddressGeneratorReturnQueue.put(address) + else: + raise Exception("Error in the addressGenerator thread. Thread was given a command it could not understand: "+command) #This is one of several classes that constitute the API #This class was written by Vaibhav Bhatia. Modified by Jonathan Warren (Atheros). @@ -3512,7 +3518,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): label = label.decode('base64') apiAddressGeneratorReturnQueue.queue.clear() streamNumberForAddress = 1 - shared.addressGeneratorQueue.put((3,streamNumberForAddress,label,1,"",eighteenByteRipe,nonceTrialsPerByte,payloadLengthExtraBytes)) + shared.addressGeneratorQueue.put(('createRandomAddress',3,streamNumberForAddress,label,1,"",eighteenByteRipe,nonceTrialsPerByte,payloadLengthExtraBytes)) return apiAddressGeneratorReturnQueue.get() elif method == 'createDeterministicAddresses': if len(params) == 0: @@ -3563,7 +3569,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): if addressVersionNumber == 0: #0 means "just use the proper addressVersionNumber" addressVersionNumber = 3 if addressVersionNumber != 3: - return 'API Error 0002: The address version number currently must be 3 (or 0 which means auto-select).', addressVersionNumber,' isn\'t supported.' + return 'API Error 0002: The address version number currently must be 3 (or 0 which means auto-select). '+ addressVersionNumber+' isn\'t supported.' if streamNumber == 0: #0 means "just use the most available stream" streamNumber = 1 if streamNumber != 1: @@ -3574,7 +3580,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): return 'API Error 0005: You have (accidentally?) specified too many addresses to make. Maximum 999. This check only exists to prevent mischief; if you really want to create more addresses than this, contact the Bitmessage developers and we can modify the check or you can do it yourself by searching the source code for this message.' apiAddressGeneratorReturnQueue.queue.clear() print 'Requesting that the addressGenerator create', numberOfAddresses, 'addresses.' - shared.addressGeneratorQueue.put((addressVersionNumber,streamNumber,'unused API address',numberOfAddresses,passphrase,eighteenByteRipe,nonceTrialsPerByte,payloadLengthExtraBytes)) + shared.addressGeneratorQueue.put(('createDeterministicAddresses',addressVersionNumber,streamNumber,'unused API address',numberOfAddresses,passphrase,eighteenByteRipe,nonceTrialsPerByte,payloadLengthExtraBytes)) data = '{"addresses":[' queueReturn = apiAddressGeneratorReturnQueue.get() for item in queueReturn: @@ -3583,6 +3589,23 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): data += "\""+item+ "\"" data += ']}' return data + elif method == 'getDeterministicAddress': + if len(params) != 3: + return 'API Error 0000: I need exactly 3 parameters.' + passphrase, addressVersionNumber, streamNumber = params + numberOfAddresses = 1 + eighteenByteRipe = False + if len(passphrase) == 0: + return 'API Error 0001: The specified passphrase is blank.' + passphrase = passphrase.decode('base64') + if addressVersionNumber != 3: + return 'API Error 0002: The address version number currently must be 3. '+ addressVersionNumber +' isn\'t supported.' + if streamNumber != 1: + return 'API Error 0003: The stream number must be 1. Others aren\'t supported.' + apiAddressGeneratorReturnQueue.queue.clear() + print 'Requesting that the addressGenerator create', numberOfAddresses, 'addresses.' + shared.addressGeneratorQueue.put(('getDeterministicAddress',addressVersionNumber,streamNumber,'unused API address',numberOfAddresses,passphrase,eighteenByteRipe)) + return apiAddressGeneratorReturnQueue.get() elif method == 'getAllInboxMessages': shared.sqlLock.acquire() shared.sqlSubmitQueue.put('''SELECT msgid, toaddress, fromaddress, subject, received, message FROM inbox where folder='inbox' ORDER BY received''') @@ -3633,6 +3656,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): return 'API Error 0009: Invalid characters in address: '+ toAddress if status == 'versiontoohigh': return 'API Error 0010: Address version number too high (or zero) in address: ' + toAddress + return 'API Error 0007: Could not decode address: ' + toAddress+ ' : '+ status if addressVersionNumber < 2 or addressVersionNumber > 3: return 'API Error 0011: The address version number currently must be 2 or 3. Others aren\'t supported. Check the toAddress.' if streamNumber != 1: @@ -3648,6 +3672,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): return 'API Error 0009: Invalid characters in address: '+ fromAddress if status == 'versiontoohigh': return 'API Error 0010: Address version number too high (or zero) in address: ' + fromAddress + return 'API Error 0007: Could not decode address: ' + fromAddress+ ' : '+ status if addressVersionNumber < 2 or addressVersionNumber > 3: return 'API Error 0011: The address version number currently must be 2 or 3. Others aren\'t supported. Check the fromAddress.' if streamNumber != 1: @@ -3711,6 +3736,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): return 'API Error 0009: Invalid characters in address: '+ fromAddress if status == 'versiontoohigh': return 'API Error 0010: Address version number too high (or zero) in address: ' + fromAddress + return 'API Error 0007: Could not decode address: ' + fromAddress+ ' : '+ status if addressVersionNumber < 2 or addressVersionNumber > 3: return 'API Error 0011: the address version number currently must be 2 or 3. Others aren\'t supported. Check the fromAddress.' if streamNumber != 1: @@ -3764,6 +3790,71 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): return 'ackReceived' else: return 'otherStatus: '+status + elif method == 'addSubscription': + if len(params) == 0: + return 'API Error 0000: I need parameters!' + if len(params) == 1: + address, = params + label == '' + if len(params) == 2: + address, label = params + label = label.decode('base64') + if len(params) >2: + return 'API Error 0000: I need either 1 or 2 parameters!' + address = addBMIfNotPresent(address) + status,addressVersionNumber,streamNumber,toRipe = decodeAddress(address) + if status <> 'success': + shared.printLock.acquire() + print 'API Error 0007: Could not decode address:', address, ':', status + shared.printLock.release() + if status == 'checksumfailed': + return 'API Error 0008: Checksum failed for address: ' + address + if status == 'invalidcharacters': + return 'API Error 0009: Invalid characters in address: '+ address + if status == 'versiontoohigh': + return 'API Error 0010: Address version number too high (or zero) in address: ' + address + return 'API Error 0007: Could not decode address: ' + address+ ' : '+ status + if addressVersionNumber < 2 or addressVersionNumber > 3: + return 'API Error 0011: The address version number currently must be 2 or 3. Others aren\'t supported.' + if streamNumber != 1: + return 'API Error 0012: The stream number must be 1. Others aren\'t supported.' + #First we must check to see if the address is already in the subscriptions list. + shared.sqlLock.acquire() + t = (address,) + shared.sqlSubmitQueue.put('''select * from subscriptions where address=?''') + shared.sqlSubmitQueue.put(t) + queryreturn = shared.sqlReturnQueue.get() + shared.sqlLock.release() + if queryreturn != []: + return 'API Error 0016: You are already subscribed to that address.' + t = (label,address,True) + shared.sqlLock.acquire() + shared.sqlSubmitQueue.put('''INSERT INTO subscriptions VALUES (?,?,?)''') + shared.sqlSubmitQueue.put(t) + queryreturn = shared.sqlReturnQueue.get() + shared.sqlSubmitQueue.put('commit') + shared.sqlLock.release() + shared.reloadBroadcastSendersForWhichImWatching() + shared.UISignalQueue.put(('rerenderInboxFromLabels','')) + shared.UISignalQueue.put(('rerenderSubscriptions','')) + return 'Added subscription.' + + elif method == 'deleteSubscription': + if len(params) != 1: + return 'API Error 0000: I need 1 parameter!' + address, = params + address = addBMIfNotPresent(address) + t = (address,) + shared.sqlLock.acquire() + shared.sqlSubmitQueue.put('''DELETE FROM subscriptions WHERE address=?''') + shared.sqlSubmitQueue.put(t) + shared.sqlReturnQueue.get() + shared.sqlSubmitQueue.put('commit') + shared.sqlLock.release() + shared.reloadBroadcastSendersForWhichImWatching() + shared.UISignalQueue.put(('rerenderInboxFromLabels','')) + shared.UISignalQueue.put(('rerenderSubscriptions','')) + return 'Deleted subscription if it existed.' else: return 'Invalid Method: %s'%method @@ -3777,37 +3868,6 @@ class singleAPI(threading.Thread): se.register_introspection_functions() se.serve_forever() - -#The MySimpleXMLRPCRequestHandler class cannot emit signals (or at least I don't know how) because it is not a QT thread. It therefore puts data in a queue which this thread monitors and emits the signals on its behalf. -"""class singleAPISignalHandler(QThread): - def __init__(self, parent = None): - QThread.__init__(self, parent) - - def run(self): - while True: - command, data = apiSignalQueue.get() - if command == 'updateStatusBar': - self.emit(SIGNAL("updateStatusBar(PyQt_PyObject)"),data) - elif command == 'createRandomAddress': - label, eighteenByteRipe = data - streamNumberForAddress = 1 - #self.addressGenerator = addressGenerator() - #self.addressGenerator.setup(3,streamNumberForAddress,label,1,"",eighteenByteRipe) - #self.emit(SIGNAL("passAddressGeneratorObjectThrough(PyQt_PyObject)"),self.addressGenerator) - #self.addressGenerator.start() - shared.addressGeneratorQueue.put((3,streamNumberForAddress,label,1,"",eighteenByteRipe)) - elif command == 'createDeterministicAddresses': - passphrase, numberOfAddresses, addressVersionNumber, streamNumber, eighteenByteRipe = data - #self.addressGenerator = addressGenerator() - #self.addressGenerator.setup(addressVersionNumber,streamNumber,'unused API address',numberOfAddresses,passphrase,eighteenByteRipe) - #self.emit(SIGNAL("passAddressGeneratorObjectThrough(PyQt_PyObject)"),self.addressGenerator) - #self.addressGenerator.start() - shared.addressGeneratorQueue.put((addressVersionNumber,streamNumber,'unused API address',numberOfAddresses,passphrase,eighteenByteRipe)) - elif command == 'displayNewSentMessage': - toAddress,toLabel,fromAddress,subject,message,ackdata = data - self.emit(SIGNAL("displayNewSentMessage(PyQt_PyObject,PyQt_PyObject,PyQt_PyObject,PyQt_PyObject,PyQt_PyObject,PyQt_PyObject)"),toAddress,toLabel,fromAddress,subject,message,ackdata)""" - - selfInitiatedConnections = {} #This is a list of current connections (the thread pointers at least) alreadyAttemptedConnectionsList = {} #This is a list of nodes to which we have already attempted a connection ackdataForWhichImWatching = {} diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 5233a532..dd42692c 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -393,23 +393,7 @@ class MyForm(QtGui.QMainWindow): self.ui.tableWidgetAddressBook.setItem(0,1,newItem) #Initialize the Subscriptions - shared.sqlLock.acquire() - shared.sqlSubmitQueue.put('SELECT label, address, enabled FROM subscriptions') - shared.sqlSubmitQueue.put('') - queryreturn = shared.sqlReturnQueue.get() - shared.sqlLock.release() - for row in queryreturn: - label, address, enabled = row - self.ui.tableWidgetSubscriptions.insertRow(0) - newItem = QtGui.QTableWidgetItem(unicode(label,'utf-8')) - if not enabled: - newItem.setTextColor(QtGui.QColor(128,128,128)) - self.ui.tableWidgetSubscriptions.setItem(0,0,newItem) - newItem = QtGui.QTableWidgetItem(address) - newItem.setFlags( QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled ) - if not enabled: - newItem.setTextColor(QtGui.QColor(128,128,128)) - self.ui.tableWidgetSubscriptions.setItem(0,1,newItem) + self.rerenderSubscriptions() #Initialize the Blacklist or Whitelist if shared.config.get('bitmessagesettings', 'blackwhitelist') == 'black': @@ -447,6 +431,8 @@ class MyForm(QtGui.QMainWindow): QtCore.QObject.connect(self.UISignalThread, QtCore.SIGNAL("incrementNumberOfPubkeysProcessed()"), self.incrementNumberOfPubkeysProcessed) QtCore.QObject.connect(self.UISignalThread, QtCore.SIGNAL("incrementNumberOfBroadcastsProcessed()"), self.incrementNumberOfBroadcastsProcessed) QtCore.QObject.connect(self.UISignalThread, QtCore.SIGNAL("setStatusIcon(PyQt_PyObject)"), self.setStatusIcon) + QtCore.QObject.connect(self.UISignalThread, QtCore.SIGNAL("rerenderInboxFromLabels()"), self.rerenderInboxFromLabels) + QtCore.QObject.connect(self.UISignalThread, QtCore.SIGNAL("rerenderSubscriptions()"), self.rerenderSubscriptions) self.UISignalThread.start() #Below this point, it would be good if all of the necessary global data structures were initialized. @@ -795,7 +781,7 @@ class MyForm(QtGui.QMainWindow): #QtCore.QObject.connect(self.addressGenerator, SIGNAL("writeNewAddressToTable(PyQt_PyObject,PyQt_PyObject,PyQt_PyObject)"), self.writeNewAddressToTable) #QtCore.QObject.connect(self.addressGenerator, QtCore.SIGNAL("updateStatusBar(PyQt_PyObject)"), self.updateStatusBar) #self.addressGenerator.start() - shared.addressGeneratorQueue.put((addressVersionNumber,streamNumberForAddress,"regenerated deterministic address",self.regenerateAddressesDialogInstance.ui.spinBoxNumberOfAddressesToMake.value(),self.regenerateAddressesDialogInstance.ui.lineEditPassphrase.text().toUtf8(),self.regenerateAddressesDialogInstance.ui.checkBoxEighteenByteRipe.isChecked())) + shared.addressGeneratorQueue.put(('createDeterministicAddresses',addressVersionNumber,streamNumberForAddress,"regenerated deterministic address",self.regenerateAddressesDialogInstance.ui.spinBoxNumberOfAddressesToMake.value(),self.regenerateAddressesDialogInstance.ui.lineEditPassphrase.text().toUtf8(),self.regenerateAddressesDialogInstance.ui.checkBoxEighteenByteRipe.isChecked())) self.ui.tabWidget.setCurrentIndex(3) def openKeysFile(self): @@ -1031,6 +1017,26 @@ class MyForm(QtGui.QMainWindow): toLabel, = row self.ui.tableWidgetSent.item(i,0).setText(unicode(toLabel,'utf-8')) + def rerenderSubscriptions(self): + self.ui.tableWidgetSubscriptions.setRowCount(0) + shared.sqlLock.acquire() + shared.sqlSubmitQueue.put('SELECT label, address, enabled FROM subscriptions') + shared.sqlSubmitQueue.put('') + queryreturn = shared.sqlReturnQueue.get() + shared.sqlLock.release() + for row in queryreturn: + label, address, enabled = row + self.ui.tableWidgetSubscriptions.insertRow(0) + newItem = QtGui.QTableWidgetItem(unicode(label,'utf-8')) + if not enabled: + newItem.setTextColor(QtGui.QColor(128,128,128)) + self.ui.tableWidgetSubscriptions.setItem(0,0,newItem) + newItem = QtGui.QTableWidgetItem(address) + newItem.setFlags( QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled ) + if not enabled: + newItem.setTextColor(QtGui.QColor(128,128,128)) + self.ui.tableWidgetSubscriptions.setItem(0,1,newItem) + def click_pushButtonSend(self): self.statusBar().showMessage('') toAddresses = str(self.ui.lineEditTo.text()) @@ -1358,7 +1364,7 @@ class MyForm(QtGui.QMainWindow): if self.NewSubscriptionDialogInstance.exec_(): if self.NewSubscriptionDialogInstance.ui.labelSubscriptionAddressCheck.text() == 'Address is valid.': - #First we must check to see if the address is already in the address book. The user cannot add it again or else it will cause problems when updating and deleting the entry. + #First we must check to see if the address is already in the subscriptions list. The user cannot add it again or else it will cause problems when updating and deleting the entry. shared.sqlLock.acquire() t = (addBMIfNotPresent(str(self.NewSubscriptionDialogInstance.ui.lineEditSubscriptionAddress.text())),) shared.sqlSubmitQueue.put('''select * from subscriptions where address=?''') @@ -1605,7 +1611,7 @@ class MyForm(QtGui.QMainWindow): #QtCore.QObject.connect(self.addressGenerator, SIGNAL("writeNewAddressToTable(PyQt_PyObject,PyQt_PyObject,PyQt_PyObject)"), self.writeNewAddressToTable) #QtCore.QObject.connect(self.addressGenerator, QtCore.SIGNAL("updateStatusBar(PyQt_PyObject)"), self.updateStatusBar) #self.addressGenerator.start() - shared.addressGeneratorQueue.put((3,streamNumberForAddress,str(self.dialog.ui.newaddresslabel.text().toUtf8()),1,"",self.dialog.ui.checkBoxEighteenByteRipe.isChecked())) + shared.addressGeneratorQueue.put(('createRandomAddress',3,streamNumberForAddress,str(self.dialog.ui.newaddresslabel.text().toUtf8()),1,"",self.dialog.ui.checkBoxEighteenByteRipe.isChecked())) else: if self.dialog.ui.lineEditPassphrase.text() != self.dialog.ui.lineEditPassphraseAgain.text(): QMessageBox.about(self, "Passphrase mismatch", "The passphrase you entered twice doesn\'t match. Try again.") @@ -1618,7 +1624,7 @@ class MyForm(QtGui.QMainWindow): #QtCore.QObject.connect(self.addressGenerator, SIGNAL("writeNewAddressToTable(PyQt_PyObject,PyQt_PyObject,PyQt_PyObject)"), self.writeNewAddressToTable) #QtCore.QObject.connect(self.addressGenerator, QtCore.SIGNAL("updateStatusBar(PyQt_PyObject)"), self.updateStatusBar) #self.addressGenerator.start() - shared.addressGeneratorQueue.put((3,streamNumberForAddress,"unused deterministic address",self.dialog.ui.spinBoxNumberOfAddressesToMake.value(),self.dialog.ui.lineEditPassphrase.text().toUtf8(),self.dialog.ui.checkBoxEighteenByteRipe.isChecked())) + shared.addressGeneratorQueue.put(('createDeterministicAddresses',3,streamNumberForAddress,"unused deterministic address",self.dialog.ui.spinBoxNumberOfAddressesToMake.value(),self.dialog.ui.lineEditPassphrase.text().toUtf8(),self.dialog.ui.checkBoxEighteenByteRipe.isChecked())) else: print 'new address dialog box rejected' @@ -2287,6 +2293,10 @@ class UISignaler(QThread): self.emit(SIGNAL("incrementNumberOfBroadcastsProcessed()")) elif command == 'setStatusIcon': self.emit(SIGNAL("setStatusIcon(PyQt_PyObject)"),data) + elif command == 'rerenderInboxFromLabels': + self.emit(SIGNAL("rerenderInboxFromLabels()")) + elif command == 'rerenderSubscriptions': + self.emit(SIGNAL("rerenderSubscriptions()")) else: sys.stderr.write('Command sent to UISignaler not recognized: %s\n' % command) diff --git a/src/shared.py b/src/shared.py index a5f635ea..850c84f3 100644 --- a/src/shared.py +++ b/src/shared.py @@ -1,4 +1,4 @@ -softwareVersion = '0.3.0' +softwareVersion = '0.3.1' import threading import sys From 2293f5238059744941c1d32136b66872e31b718e Mon Sep 17 00:00:00 2001 From: Jonathan Warren Date: Fri, 24 May 2013 16:23:35 -0400 Subject: [PATCH 2/3] Small gui change per github issue #162 --- src/bitmessageui.py | 8 ++++---- src/bitmessageui.ui | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/bitmessageui.py b/src/bitmessageui.py index ca2d8b0b..c3253da1 100644 --- a/src/bitmessageui.py +++ b/src/bitmessageui.py @@ -2,7 +2,7 @@ # Form implementation generated from reading ui file 'bitmessageui.ui' # -# Created: Tue May 21 14:09:58 2013 +# Created: Fri May 24 16:22:22 2013 # by: PyQt4 UI code generator 4.9.4 # # WARNING! All changes made in this file will be lost! @@ -500,7 +500,7 @@ class Ui_MainWindow(object): item.setText(QtGui.QApplication.translate("MainWindow", "Stream", None, QtGui.QApplication.UnicodeUTF8)) self.tabWidget.setTabText(self.tabWidget.indexOf(self.youridentities), QtGui.QApplication.translate("MainWindow", "Your Identities", None, QtGui.QApplication.UnicodeUTF8)) self.label_5.setText(QtGui.QApplication.translate("MainWindow", "Here you can subscribe to \'broadcast messages\' that are sent by other users. Messages will appear in your Inbox. Addresses here override those on the Blacklist tab.", None, QtGui.QApplication.UnicodeUTF8)) - self.pushButtonAddSubscription.setText(QtGui.QApplication.translate("MainWindow", "Add", None, QtGui.QApplication.UnicodeUTF8)) + self.pushButtonAddSubscription.setText(QtGui.QApplication.translate("MainWindow", "Add new Subscription", None, QtGui.QApplication.UnicodeUTF8)) self.tableWidgetSubscriptions.setSortingEnabled(True) item = self.tableWidgetSubscriptions.horizontalHeaderItem(0) item.setText(QtGui.QApplication.translate("MainWindow", "Label", None, QtGui.QApplication.UnicodeUTF8)) @@ -508,7 +508,7 @@ class Ui_MainWindow(object): item.setText(QtGui.QApplication.translate("MainWindow", "Address", None, QtGui.QApplication.UnicodeUTF8)) self.tabWidget.setTabText(self.tabWidget.indexOf(self.subscriptions), QtGui.QApplication.translate("MainWindow", "Subscriptions", None, QtGui.QApplication.UnicodeUTF8)) self.label_6.setText(QtGui.QApplication.translate("MainWindow", "The Address book is useful for adding names or labels to other people\'s Bitmessage addresses so that you can recognize them more easily in your inbox. You can add entries here using the \'Add\' button, or from your inbox by right-clicking on a message.", None, QtGui.QApplication.UnicodeUTF8)) - self.pushButtonAddAddressBook.setText(QtGui.QApplication.translate("MainWindow", "Add", None, QtGui.QApplication.UnicodeUTF8)) + self.pushButtonAddAddressBook.setText(QtGui.QApplication.translate("MainWindow", "Add new entry", None, QtGui.QApplication.UnicodeUTF8)) self.tableWidgetAddressBook.setSortingEnabled(True) item = self.tableWidgetAddressBook.horizontalHeaderItem(0) item.setText(QtGui.QApplication.translate("MainWindow", "Name or Label", None, QtGui.QApplication.UnicodeUTF8)) @@ -517,7 +517,7 @@ class Ui_MainWindow(object): self.tabWidget.setTabText(self.tabWidget.indexOf(self.addressbook), QtGui.QApplication.translate("MainWindow", "Address Book", None, QtGui.QApplication.UnicodeUTF8)) self.radioButtonBlacklist.setText(QtGui.QApplication.translate("MainWindow", "Use a Blacklist (Allow all incoming messages except those on the Blacklist)", None, QtGui.QApplication.UnicodeUTF8)) self.radioButtonWhitelist.setText(QtGui.QApplication.translate("MainWindow", "Use a Whitelist (Block all incoming messages except those on the Whitelist)", None, QtGui.QApplication.UnicodeUTF8)) - self.pushButtonAddBlacklist.setText(QtGui.QApplication.translate("MainWindow", "Add", None, QtGui.QApplication.UnicodeUTF8)) + self.pushButtonAddBlacklist.setText(QtGui.QApplication.translate("MainWindow", "Add new entry", None, QtGui.QApplication.UnicodeUTF8)) self.tableWidgetBlacklist.setSortingEnabled(True) item = self.tableWidgetBlacklist.horizontalHeaderItem(0) item.setText(QtGui.QApplication.translate("MainWindow", "Name or Label", None, QtGui.QApplication.UnicodeUTF8)) diff --git a/src/bitmessageui.ui b/src/bitmessageui.ui index 8487b673..010db41e 100644 --- a/src/bitmessageui.ui +++ b/src/bitmessageui.ui @@ -500,7 +500,7 @@ p, li { white-space: pre-wrap; } - Add + Add new Subscription @@ -585,7 +585,7 @@ p, li { white-space: pre-wrap; } - Add + Add new entry @@ -674,7 +674,7 @@ p, li { white-space: pre-wrap; } - Add + Add new entry From 204f1fe52cc82c8b16c223c2929c0cca0e1febeb Mon Sep 17 00:00:00 2001 From: Jonathan Warren Date: Fri, 24 May 2013 17:05:45 -0400 Subject: [PATCH 3/3] Verify label is UTF-8 data --- src/bitmessagemain.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/bitmessagemain.py b/src/bitmessagemain.py index 9448404c..93acfa19 100755 --- a/src/bitmessagemain.py +++ b/src/bitmessagemain.py @@ -3798,6 +3798,10 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): if len(params) == 2: address, label = params label = label.decode('base64') + try: + label.decode('utf-8') + except UnicodeDecodeError: + return 'API Error 0017: Label is not valid UTF-8 data.' if len(params) >2: return 'API Error 0000: I need either 1 or 2 parameters!' address = addBMIfNotPresent(address)