diff --git a/build/scripts-2.7/pybitmessage b/build/scripts-2.7/pybitmessage new file mode 100755 index 00000000..7f9e2e37 --- /dev/null +++ b/build/scripts-2.7/pybitmessage @@ -0,0 +1,15 @@ +#!/home/coffeedogs/.virtualenvs/pybitmessage-devops/bin/python + +import os +import sys + +import pkg_resources + +import pybitmessage.pathmagic + +dist = pkg_resources.get_distribution('pybitmessage') +script_file = os.path.join(dist.location, dist.key, 'bitmessagemain.py') +new_globals = globals() +new_globals.update(__file__=script_file) + +execfile(script_file, new_globals) diff --git a/desktop/icons/24x24/pybitmessage.png b/desktop/icons/24x24/pybitmessage.png new file mode 100644 index 00000000..30f7313e Binary files /dev/null and b/desktop/icons/24x24/pybitmessage.png differ diff --git a/desktop/icons/scalable/pybitmessage.svg b/desktop/icons/scalable/pybitmessage.svg new file mode 100644 index 00000000..7c854e34 --- /dev/null +++ b/desktop/icons/scalable/pybitmessage.svg @@ -0,0 +1,149 @@ + + + + diff --git a/setup.cfg b/setup.cfg index 93efd2d5..d6d2afc5 100644 --- a/setup.cfg +++ b/setup.cfg @@ -3,10 +3,12 @@ [pycodestyle] max-line-length = 119 +ignore = E722,E402 [flake8] max-line-length = 119 -ignore = E722,F841 +ignore = E402,E722,F841 +# E402: pylint is preferred for wrong-import-position # E722: pylint is preferred for bare-except # F841: pylint is preferred for unused-variable diff --git a/src/api.py b/src/api.py index a32519e4..d88bbc87 100644 --- a/src/api.py +++ b/src/api.py @@ -1,19 +1,24 @@ +# pylint: disable=too-many-locals,too-many-lines,no-self-use,too-many-public-methods,too-many-branches +# pylint: disable=too-many-statements +""" # Copyright (c) 2012-2016 Jonathan Warren # Copyright (c) 2012-2018 The Bitmessage developers -""" This is not what you run to run the Bitmessage API. Instead, enable the API ( https://bitmessage.org/wiki/API ) and optionally enable daemon mode ( https://bitmessage.org/wiki/Daemon ) then run bitmessagemain.py. """ +from __future__ import absolute_import + import base64 import hashlib import json +from struct import pack import time from binascii import hexlify, unhexlify + from SimpleXMLRPCServer import SimpleXMLRPCRequestHandler, SimpleXMLRPCServer -from struct import pack import shared from addresses import ( @@ -43,6 +48,8 @@ str_chan = '[chan]' class APIError(Exception): + """APIError exception class""" + def __init__(self, error_number, error_message): super(APIError, self).__init__() self.error_number = error_number @@ -53,26 +60,34 @@ class APIError(Exception): class StoppableXMLRPCServer(SimpleXMLRPCServer): + """A SimpleXMLRPCServer that honours state.shutdown""" allow_reuse_address = True def serve_forever(self): + """Start the SimpleXMLRPCServer""" + # pylint: disable=arguments-differ while state.shutdown == 0: self.handle_request() -# This is one of several classes that constitute the API -# This class was written by Vaibhav Bhatia. -# Modified by Jonathan Warren (Atheros). -# http://code.activestate.com/recipes/501148-xmlrpc-serverclient-which-does-cookie-handling-and/ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): + """ + This is one of several classes that constitute the API + + This class was written by Vaibhav Bhatia. Modified by Jonathan Warren (Atheros). + http://code.activestate.com/recipes/501148-xmlrpc-serverclient-which-does-cookie-handling-and/ + """ def do_POST(self): - # Handles the HTTP POST request. - # Attempts to interpret all HTTP POST requests as XML-RPC calls, - # which are forwarded to the server's _dispatch method for handling. + """ + Handles the HTTP POST request. - # Note: this method is the same as in SimpleXMLRPCRequestHandler, - # just hacked to handle cookies + Attempts to interpret all HTTP POST requests as XML-RPC calls, + which are forwarded to the server's _dispatch method for handling. + + Note: this method is the same as in SimpleXMLRPCRequestHandler, + just hacked to handle cookies + """ # Check that the path is legal if not self.is_rpc_path_valid(): @@ -98,7 +113,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): # SimpleXMLRPCDispatcher. To maintain backwards compatibility, # check to see if a subclass implements _dispatch and dispatch # using that method if present. - response = self.server._marshaled_dispatch( + response = self.server._marshaled_dispatch( # pylint: disable=protected-access data, getattr(self, '_dispatch', None) ) except: # This should only happen if the module is buggy @@ -125,22 +140,21 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): self.connection.shutdown(1) def APIAuthenticateClient(self): + """Predicate to check for valid API credentials in the request header""" + if 'Authorization' in self.headers: # handle Basic authentication - enctype, encstr = self.headers.get('Authorization').split() + _, encstr = self.headers.get('Authorization').split() emailid, password = encstr.decode('base64').split(':') return ( - emailid == - BMConfigParser().get('bitmessagesettings', 'apiusername') - and password == - BMConfigParser().get('bitmessagesettings', 'apipassword') + emailid == BMConfigParser().get('bitmessagesettings', 'apiusername') and + password == BMConfigParser().get('bitmessagesettings', 'apipassword') ) else: logger.warning( 'Authentication failed because header lacks' ' Authentication field') time.sleep(2) - return False return False @@ -155,6 +169,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): 22, "Decode error - %s. Had trouble while decoding string: %r" % (e, text) ) + return None def _verifyAddress(self, address): status, addressVersionNumber, streamNumber, ripe = \ @@ -170,15 +185,10 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): if status == 'invalidcharacters': raise APIError(9, 'Invalid characters in address: ' + address) if status == 'versiontoohigh': - raise APIError( - 10, - 'Address version number too high (or zero) in address: ' - + address - ) + raise APIError(10, 'Address version number too high (or zero) in address: ' + address) if status == 'varintmalformed': raise APIError(26, 'Malformed varint in address: ' + address) - raise APIError( - 7, 'Could not decode address: %s : %s' % (address, status)) + raise APIError(7, 'Could not decode address: %s : %s' % (address, status)) if addressVersionNumber < 2 or addressVersionNumber > 4: raise APIError( 11, 'The address version number currently must be 2, 3 or 4.' @@ -195,9 +205,11 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): # Request Handlers def HandleListAddresses(self, method): + """Handle a request to list addresses""" + data = '{"addresses":[' for addressInKeysFile in BMConfigParser().addresses(): - status, addressVersionNumber, streamNumber, hash01 = decodeAddress( + status, addressVersionNumber, streamNumber, hash01 = decodeAddress( # pylint: disable=unused-variable addressInKeysFile) if len(data) > 20: data += ',' @@ -215,11 +227,13 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): 'enabled': BMConfigParser().getboolean(addressInKeysFile, 'enabled'), 'chan': chan - }, indent=4, separators=(',', ': ')) + }, indent=4, separators=(',', ': ')) data += ']}' return data def HandleListAddressBookEntries(self, params): + """Handle a request to list address book entries""" + if len(params) == 1: label, = params label = self._decode(label, "base64") @@ -243,6 +257,8 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): return data def HandleAddAddressBookEntry(self, params): + """Handle a request to add an address book entry""" + if len(params) != 2: raise APIError(0, "I need label and address") address, label = params @@ -262,6 +278,8 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): return "Added address %s to address book" % address def HandleDeleteAddressBookEntry(self, params): + """Handle a request to delete an address book entry""" + if len(params) != 1: raise APIError(0, "I need an address") address, = params @@ -274,8 +292,11 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): return "Deleted address book entry for %s if it existed" % address def HandleCreateRandomAddress(self, params): - if len(params) == 0: + """Handle a request to create a random address""" + + if not params: raise APIError(0, 'I need parameters!') + elif len(params) == 1: label, = params eighteenByteRipe = False @@ -292,19 +313,16 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): elif len(params) == 3: label, eighteenByteRipe, totalDifficulty = params nonceTrialsPerByte = int( - defaults.networkDefaultProofOfWorkNonceTrialsPerByte - * totalDifficulty) + defaults.networkDefaultProofOfWorkNonceTrialsPerByte * totalDifficulty) payloadLengthExtraBytes = BMConfigParser().get( 'bitmessagesettings', 'defaultpayloadlengthextrabytes') elif len(params) == 4: label, eighteenByteRipe, totalDifficulty, \ smallMessageDifficulty = params nonceTrialsPerByte = int( - defaults.networkDefaultProofOfWorkNonceTrialsPerByte - * totalDifficulty) + defaults.networkDefaultProofOfWorkNonceTrialsPerByte * totalDifficulty) payloadLengthExtraBytes = int( - defaults.networkDefaultPayloadLengthExtraBytes - * smallMessageDifficulty) + defaults.networkDefaultPayloadLengthExtraBytes * smallMessageDifficulty) else: raise APIError(0, 'Too many parameters!') label = self._decode(label, "base64") @@ -321,8 +339,11 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): return queues.apiAddressGeneratorReturnQueue.get() def HandleCreateDeterministicAddresses(self, params): - if len(params) == 0: + """Handle a request to create a deterministic address""" + + if not params: raise APIError(0, 'I need parameters!') + elif len(params) == 1: passphrase, = params numberOfAddresses = 1 @@ -333,6 +354,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): 'bitmessagesettings', 'defaultnoncetrialsperbyte') payloadLengthExtraBytes = BMConfigParser().get( 'bitmessagesettings', 'defaultpayloadlengthextrabytes') + elif len(params) == 2: passphrase, numberOfAddresses = params addressVersionNumber = 0 @@ -342,6 +364,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): 'bitmessagesettings', 'defaultnoncetrialsperbyte') payloadLengthExtraBytes = BMConfigParser().get( 'bitmessagesettings', 'defaultpayloadlengthextrabytes') + elif len(params) == 3: passphrase, numberOfAddresses, addressVersionNumber = params streamNumber = 0 @@ -350,6 +373,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): 'bitmessagesettings', 'defaultnoncetrialsperbyte') payloadLengthExtraBytes = BMConfigParser().get( 'bitmessagesettings', 'defaultpayloadlengthextrabytes') + elif len(params) == 4: passphrase, numberOfAddresses, addressVersionNumber, \ streamNumber = params @@ -358,6 +382,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): 'bitmessagesettings', 'defaultnoncetrialsperbyte') payloadLengthExtraBytes = BMConfigParser().get( 'bitmessagesettings', 'defaultpayloadlengthextrabytes') + elif len(params) == 5: passphrase, numberOfAddresses, addressVersionNumber, \ streamNumber, eighteenByteRipe = params @@ -365,27 +390,26 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): 'bitmessagesettings', 'defaultnoncetrialsperbyte') payloadLengthExtraBytes = BMConfigParser().get( 'bitmessagesettings', 'defaultpayloadlengthextrabytes') + elif len(params) == 6: passphrase, numberOfAddresses, addressVersionNumber, \ streamNumber, eighteenByteRipe, totalDifficulty = params nonceTrialsPerByte = int( - defaults.networkDefaultProofOfWorkNonceTrialsPerByte - * totalDifficulty) + defaults.networkDefaultProofOfWorkNonceTrialsPerByte * totalDifficulty) payloadLengthExtraBytes = BMConfigParser().get( 'bitmessagesettings', 'defaultpayloadlengthextrabytes') + elif len(params) == 7: passphrase, numberOfAddresses, addressVersionNumber, \ streamNumber, eighteenByteRipe, totalDifficulty, \ smallMessageDifficulty = params nonceTrialsPerByte = int( - defaults.networkDefaultProofOfWorkNonceTrialsPerByte - * totalDifficulty) + defaults.networkDefaultProofOfWorkNonceTrialsPerByte * totalDifficulty) payloadLengthExtraBytes = int( - defaults.networkDefaultPayloadLengthExtraBytes - * smallMessageDifficulty) + defaults.networkDefaultPayloadLengthExtraBytes * smallMessageDifficulty) else: raise APIError(0, 'Too many parameters!') - if len(passphrase) == 0: + if not passphrase: raise APIError(1, 'The specified passphrase is blank.') if not isinstance(eighteenByteRipe, bool): raise APIError( @@ -436,12 +460,14 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): return data def HandleGetDeterministicAddress(self, params): + """Handle a request to get a deterministic address""" + if len(params) != 3: raise APIError(0, 'I need exactly 3 parameters.') passphrase, addressVersionNumber, streamNumber = params numberOfAddresses = 1 eighteenByteRipe = False - if len(passphrase) == 0: + if not passphrase: raise APIError(1, 'The specified passphrase is blank.') passphrase = self._decode(passphrase, "base64") if addressVersionNumber != 3 and addressVersionNumber != 4: @@ -463,12 +489,16 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): return queues.apiAddressGeneratorReturnQueue.get() def HandleCreateChan(self, params): - if len(params) == 0: + """Handle a request to create a chan""" + + if not params: raise APIError(0, 'I need parameters.') + elif len(params) == 1: passphrase, = params passphrase = self._decode(passphrase, "base64") - if len(passphrase) == 0: + + if not passphrase: raise APIError(1, 'The specified passphrase is blank.') # It would be nice to make the label the passphrase but it is # possible that the passphrase contains non-utf-8 characters. @@ -488,18 +518,20 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): passphrase, True )) queueReturn = queues.apiAddressGeneratorReturnQueue.get() - if len(queueReturn) == 0: + if not queueReturn: raise APIError(24, 'Chan address is already present.') address = queueReturn[0] return address def HandleJoinChan(self, params): + """Handle a request to join a chan""" + if len(params) < 2: raise APIError(0, 'I need two parameters.') elif len(params) == 2: passphrase, suppliedAddress = params passphrase = self._decode(passphrase, "base64") - if len(passphrase) == 0: + if not passphrase: raise APIError(1, 'The specified passphrase is blank.') # It would be nice to make the label the passphrase but it is # possible that the passphrase contains non-utf-8 characters. @@ -509,8 +541,8 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): except: label = str_chan + ' ' + repr(passphrase) - status, addressVersionNumber, streamNumber, toRipe = \ - self._verifyAddress(suppliedAddress) + status, addressVersionNumber, streamNumber, toRipe = self._verifyAddress( # pylint: disable=unused-variable + suppliedAddress) suppliedAddress = addBMIfNotPresent(suppliedAddress) queues.apiAddressGeneratorReturnQueue.queue.clear() queues.addressGeneratorQueue.put(( @@ -522,20 +554,19 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): if addressGeneratorReturnValue[0] == \ 'chan name does not match address': raise APIError(18, 'Chan name does not match address.') - if len(addressGeneratorReturnValue) == 0: + if not addressGeneratorReturnValue: raise APIError(24, 'Chan address is already present.') - # TODO: this variable is not used to anything - # in case we ever want it for anything. - # createdAddress = addressGeneratorReturnValue[0] return "success" def HandleLeaveChan(self, params): - if len(params) == 0: + """Handle a request to leave a chan""" + + if not params: raise APIError(0, 'I need parameters.') elif len(params) == 1: address, = params - status, addressVersionNumber, streamNumber, toRipe = \ - self._verifyAddress(address) + # pylint: disable=unused-variable + status, addressVersionNumber, streamNumber, toRipe = self._verifyAddress(address) address = addBMIfNotPresent(address) if not BMConfigParser().has_section(address): raise APIError( @@ -550,12 +581,14 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): return 'success' def HandleDeleteAddress(self, params): - if len(params) == 0: + """Handle a request to delete an address""" + + if not params: raise APIError(0, 'I need parameters.') elif len(params) == 1: address, = params - status, addressVersionNumber, streamNumber, toRipe = \ - self._verifyAddress(address) + # pylint: disable=unused-variable + status, addressVersionNumber, streamNumber, toRipe = self._verifyAddress(address) address = addBMIfNotPresent(address) if not BMConfigParser().has_section(address): raise APIError( @@ -568,7 +601,9 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): shared.reloadMyAddressHashes() return 'success' - def HandleGetAllInboxMessages(self, params): + def HandleGetAllInboxMessages(self, params): # pylint: disable=unused-argument + """Handle a request to get all inbox messages""" + queryreturn = sqlQuery( "SELECT msgid, toaddress, fromaddress, subject, received, message," " encodingtype, read FROM inbox where folder='inbox'" @@ -594,7 +629,9 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): data += ']}' return data - def HandleGetAllInboxMessageIds(self, params): + def HandleGetAllInboxMessageIds(self, params): # pylint: disable=unused-argument + """Handle a request to get all inbox message IDs""" + queryreturn = sqlQuery( "SELECT msgid FROM inbox where folder='inbox' ORDER BY received") data = '{"inboxMessageIds":[' @@ -608,7 +645,9 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): return data def HandleGetInboxMessageById(self, params): - if len(params) == 0: + """Handle a request to get an inbox messsage by ID""" + + if not params: raise APIError(0, 'I need parameters!') elif len(params) == 1: msgid = self._decode(params[0], "hex") @@ -649,7 +688,9 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): data += ']}' return data - def HandleGetAllSentMessages(self, params): + def HandleGetAllSentMessages(self, params): # pylint: disable=unused-argument + """Handle a request to get all sent messages""" + queryreturn = sqlQuery( "SELECT msgid, toaddress, fromaddress, subject, lastactiontime," " message, encodingtype, status, ackdata FROM sent" @@ -676,7 +717,9 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): data += ']}' return data - def HandleGetAllSentMessageIds(self, params): + def HandleGetAllSentMessageIds(self, params): # pylint: disable=unused-argument + """Handle a request to get all sent message IDs""" + queryreturn = sqlQuery( "SELECT msgid FROM sent where folder='sent'" " ORDER BY lastactiontime" @@ -692,7 +735,9 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): return data def HandleInboxMessagesByReceiver(self, params): - if len(params) == 0: + """Handle a request to get inbox messages by receiver""" + + if not params: raise APIError(0, 'I need parameters!') toAddress = params[0] queryreturn = sqlQuery( @@ -719,7 +764,9 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): return data def HandleGetSentMessageById(self, params): - if len(params) == 0: + """Handle a request to get a sent message by ID""" + + if not params: raise APIError(0, 'I need parameters!') msgid = self._decode(params[0], "hex") queryreturn = sqlQuery( @@ -747,7 +794,9 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): return data def HandleGetSentMessagesByAddress(self, params): - if len(params) == 0: + """Handle a request to get sent messages by address""" + + if not params: raise APIError(0, 'I need parameters!') fromAddress = params[0] queryreturn = sqlQuery( @@ -759,7 +808,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): data = '{"sentMessages":[' for row in queryreturn: msgid, toAddress, fromAddress, subject, lastactiontime, message, \ - encodingtype, status, ackdata = row + encodingtype, status, ackdata = row # pylint: disable=unused-variable subject = shared.fixPotentiallyInvalidUTF8Data(subject) message = shared.fixPotentiallyInvalidUTF8Data(message) if len(data) > 25: @@ -778,7 +827,9 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): return data def HandleGetSentMessagesByAckData(self, params): - if len(params) == 0: + """Handle a request to get sent messages by ack data""" + + if not params: raise APIError(0, 'I need parameters!') ackData = self._decode(params[0], "hex") queryreturn = sqlQuery( @@ -806,7 +857,9 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): return data def HandleTrashMessage(self, params): - if len(params) == 0: + """Handle a request to trash a message by ID""" + + if not params: raise APIError(0, 'I need parameters!') msgid = self._decode(params[0], "hex") @@ -817,32 +870,42 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): return 'Trashed message (assuming message existed).' def HandleTrashInboxMessage(self, params): - if len(params) == 0: + """Handle a request to trash an inbox message by ID""" + + if not params: raise APIError(0, 'I need parameters!') msgid = self._decode(params[0], "hex") helper_inbox.trash(msgid) return 'Trashed inbox message (assuming message existed).' def HandleTrashSentMessage(self, params): - if len(params) == 0: + """Handle a request to trash a sent message by ID""" + + if not params: raise APIError(0, 'I need parameters!') msgid = self._decode(params[0], "hex") sqlExecute('''UPDATE sent SET folder='trash' WHERE msgid=?''', msgid) return 'Trashed sent message (assuming message existed).' def HandleSendMessage(self, params): - if len(params) == 0: + """Handle a request to send a message""" + + if not params: raise APIError(0, 'I need parameters!') + elif len(params) == 4: toAddress, fromAddress, subject, message = params encodingType = 2 TTL = 4 * 24 * 60 * 60 + elif len(params) == 5: toAddress, fromAddress, subject, message, encodingType = params TTL = 4 * 24 * 60 * 60 + elif len(params) == 6: toAddress, fromAddress, subject, message, encodingType, TTL = \ params + if encodingType not in [2, 3]: raise APIError(6, 'The encoding type must be 2 or 3.') subject = self._decode(subject, "base64") @@ -855,6 +918,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): TTL = 28 * 24 * 60 * 60 toAddress = addBMIfNotPresent(toAddress) fromAddress = addBMIfNotPresent(fromAddress) + # pylint: disable=unused-variable status, addressVersionNumber, streamNumber, toRipe = \ self._verifyAddress(toAddress) self._verifyAddress(fromAddress) @@ -894,7 +958,6 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): if queryreturn != []: for row in queryreturn: toLabel, = row - # apiSignalQueue.put(('displayNewSentMessage',(toAddress,toLabel,fromAddress,subject,message,ackdata))) queues.UISignalQueue.put(('displayNewSentMessage', ( toAddress, toLabel, fromAddress, subject, message, ackdata))) @@ -903,19 +966,25 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): return hexlify(ackdata) def HandleSendBroadcast(self, params): - if len(params) == 0: + """Handle a request to send a broadcast message""" + + if not params: raise APIError(0, 'I need parameters!') + if len(params) == 3: fromAddress, subject, message = params encodingType = 2 TTL = 4 * 24 * 60 * 60 + elif len(params) == 4: fromAddress, subject, message, encodingType = params TTL = 4 * 24 * 60 * 60 elif len(params) == 5: fromAddress, subject, message, encodingType, TTL = params + if encodingType not in [2, 3]: raise APIError(6, 'The encoding type must be 2 or 3.') + subject = self._decode(subject, "base64") message = self._decode(message, "base64") if len(subject + message) > (2 ** 18 - 500): @@ -961,6 +1030,8 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): return hexlify(ackdata) def HandleGetStatus(self, params): + """Handle a request to get the status of a sent message""" + if len(params) != 1: raise APIError(0, 'I need one parameter!') ackdata, = params @@ -977,7 +1048,9 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): return status def HandleAddSubscription(self, params): - if len(params) == 0: + """Handle a request to add a subscription""" + + if not params: raise APIError(0, 'I need parameters!') if len(params) == 1: address, = params @@ -1007,6 +1080,8 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): return 'Added subscription.' def HandleDeleteSubscription(self, params): + """Handle a request to delete a subscription""" + if len(params) != 1: raise APIError(0, 'I need 1 parameter!') address, = params @@ -1017,7 +1092,10 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): queues.UISignalQueue.put(('rerenderSubscriptions', '')) return 'Deleted subscription if it existed.' - def ListSubscriptions(self, params): + def ListSubscriptions(self, params): # pylint: disable=unused-argument + """Handle a request to list susbcriptions""" + + # pylint: disable=unused-variable queryreturn = sqlQuery( "SELECT label, address, enabled FROM subscriptions") data = {'subscriptions': []} @@ -1032,6 +1110,8 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): return json.dumps(data, indent=4, separators=(',', ': ')) def HandleDisseminatePreEncryptedMsg(self, params): + """Handle a request to disseminate an encrypted message""" + # The device issuing this command to PyBitmessage supplies a msg # object that has already been encrypted but which still needs the POW # to be done. PyBitmessage accepts this msg object and sends it out @@ -1044,17 +1124,29 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): encryptedPayload = self._decode(encryptedPayload, "hex") # Let us do the POW and attach it to the front target = 2**64 / ( - (len(encryptedPayload) + requiredPayloadLengthExtraBytes + 8) - * requiredAverageProofOfWorkNonceTrialsPerByte) + ( + len(encryptedPayload) + requiredPayloadLengthExtraBytes + 8 + ) * requiredAverageProofOfWorkNonceTrialsPerByte + ) with shared.printLock: - print '(For msg message via API) Doing proof of work. Total required difficulty:', float(requiredAverageProofOfWorkNonceTrialsPerByte) / defaults.networkDefaultProofOfWorkNonceTrialsPerByte, 'Required small message difficulty:', float(requiredPayloadLengthExtraBytes) / defaults.networkDefaultPayloadLengthExtraBytes + print( + '(For msg message via API) Doing proof of work. Total required difficulty:', + float( + requiredAverageProofOfWorkNonceTrialsPerByte + ) / defaults.networkDefaultProofOfWorkNonceTrialsPerByte, + 'Required small message difficulty:', + float(requiredPayloadLengthExtraBytes) / defaults.networkDefaultPayloadLengthExtraBytes, + ) powStartTime = time.time() initialHash = hashlib.sha512(encryptedPayload).digest() trialValue, nonce = proofofwork.run(target, initialHash) with shared.printLock: print '(For msg message via API) Found proof of work', trialValue, 'Nonce:', nonce try: - print 'POW took', int(time.time() - powStartTime), 'seconds.', nonce / (time.time() - powStartTime), 'nonce trials per second.' + print( + 'POW took', int(time.time() - powStartTime), 'seconds.', + nonce / (time.time() - powStartTime), 'nonce trials per second.', + ) except: pass encryptedPayload = pack('>Q', nonce) + encryptedPayload @@ -1071,14 +1163,18 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): queues.invQueue.put((toStreamNumber, inventoryHash)) def HandleTrashSentMessageByAckDAta(self, params): + """Handle a request to trash a sent message by ackdata""" + # This API method should only be used when msgid is not available - if len(params) == 0: + if not params: raise APIError(0, 'I need parameters!') ackdata = self._decode(params[0], "hex") sqlExecute("UPDATE sent SET folder='trash' WHERE ackdata=?", ackdata) return 'Trashed sent message (assuming message existed).' - def HandleDissimatePubKey(self, params): + def HandleDissimatePubKey(self, params): # pylint: disable=unused-argument + """Handle a request to disseminate a public key""" + # The device issuing this command to PyBitmessage supplies a pubkey # object to be disseminated to the rest of the Bitmessage network. # PyBitmessage accepts this pubkey object and sends it out to the rest @@ -1090,9 +1186,9 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): payload = self._decode(payload, "hex") # Let us do the POW - target = 2 ** 64 / ( - (len(payload) + defaults.networkDefaultPayloadLengthExtraBytes - + 8) * defaults.networkDefaultProofOfWorkNonceTrialsPerByte) + target = 2 ** 64 / (( + len(payload) + defaults.networkDefaultPayloadLengthExtraBytes + 8 + ) * defaults.networkDefaultProofOfWorkNonceTrialsPerByte) print '(For pubkey message via API) Doing proof of work...' initialHash = hashlib.sha512(payload).digest() trialValue, nonce = proofofwork.run(target, initialHash) @@ -1100,18 +1196,19 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): payload = pack('>Q', nonce) + payload pubkeyReadPosition = 8 # bypass the nonce - if payload[pubkeyReadPosition:pubkeyReadPosition+4] == \ + if payload[pubkeyReadPosition:pubkeyReadPosition + 4] == \ '\x00\x00\x00\x00': # if this pubkey uses 8 byte time pubkeyReadPosition += 8 else: pubkeyReadPosition += 4 + # pylint: disable=unused-variable addressVersion, addressVersionLength = decodeVarint( - payload[pubkeyReadPosition:pubkeyReadPosition+10]) + payload[pubkeyReadPosition:pubkeyReadPosition + 10]) pubkeyReadPosition += addressVersionLength pubkeyStreamNumber = decodeVarint( - payload[pubkeyReadPosition:pubkeyReadPosition+10])[0] + payload[pubkeyReadPosition:pubkeyReadPosition + 10])[0] inventoryHash = calculateInventoryHash(payload) - objectType = 1 # TODO: support v4 pubkeys + objectType = 1 # .. todo::: support v4 pubkeys TTL = 28 * 24 * 60 * 60 Inventory()[inventoryHash] = ( objectType, pubkeyStreamNumber, payload, int(time.time()) + TTL, '' @@ -1121,6 +1218,8 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): queues.invQueue.put((pubkeyStreamNumber, inventoryHash)) def HandleGetMessageDataByDestinationHash(self, params): + """Handle a request to get message data by destination hash""" + # Method will eventually be used by a particular Android app to # select relevant messages. Do not yet add this to the api # doc. @@ -1145,8 +1244,8 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): readPosition = 16 # Nonce length + time length # Stream Number length readPosition += decodeVarint( - payload[readPosition:readPosition+10])[1] - t = (payload[readPosition:readPosition+32], hash01) + payload[readPosition:readPosition + 10])[1] + t = (payload[readPosition:readPosition + 32], hash01) sql.execute("UPDATE inventory SET tag=? WHERE hash=?", *t) queryreturn = sqlQuery( @@ -1161,10 +1260,12 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): data += ']}' return data - def HandleClientStatus(self, params): - if len(network.stats.connectedHostsList()) == 0: + def HandleClientStatus(self, params): # pylint: disable=unused-argument + """Handle a request to get the status of the client""" + + if network.stats.connectedHostsList(): networkStatus = 'notConnected' - elif len(network.stats.connectedHostsList()) > 0 \ + elif not network.stats.connectedHostsList() \ and not shared.clientHasReceivedIncomingConnections: networkStatus = 'connectedButHaveNotReceivedIncomingConnections' else: @@ -1177,9 +1278,11 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): 'networkStatus': networkStatus, 'softwareName': 'PyBitmessage', 'softwareVersion': softwareVersion - }, indent=4, separators=(',', ': ')) + }, indent=4, separators=(',', ': ')) def HandleDecodeAddress(self, params): + """Handle a request to decode an address""" + # Return a meaningful decoding of an address. if len(params) != 1: raise APIError(0, 'I need 1 parameter!') @@ -1190,29 +1293,41 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): 'addressVersion': addressVersion, 'streamNumber': streamNumber, 'ripe': base64.b64encode(ripe) - }, indent=4, separators=(',', ': ')) + }, indent=4, separators=(',', ': ')) def HandleHelloWorld(self, params): + """Test two string params""" + a, b = params return a + '-' + b def HandleAdd(self, params): + """Test two numeric params""" + a, b = params return a + b def HandleStatusBar(self, params): + """Handle a request to update the status bar""" + message, = params queues.UISignalQueue.put(('updateStatusBar', message)) def HandleDeleteAndVacuum(self, params): + """Handle a request to run the deleteandvacuum stored procedure""" + if not params: sqlStoredProcedure('deleteandvacuume') return 'done' + return None def HandleShutdown(self, params): + """Handle a request to huutdown the client""" + if not params: shutdown.doCleanShutdown() return 'done' + return None handlers = {} handlers['helloWorld'] = HandleHelloWorld @@ -1279,6 +1394,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): return self.handlers[method](self, params) def _dispatch(self, method, params): + # pylint: disable=attribute-defined-outside-init self.cookies = [] validuser = self.APIAuthenticateClient() diff --git a/src/bitmessagemain.py b/src/bitmessagemain.py index 0848b0e4..d2749cdd 100755 --- a/src/bitmessagemain.py +++ b/src/bitmessagemain.py @@ -1,37 +1,43 @@ #!/usr/bin/python2.7 -# Copyright (c) 2012-2016 Jonathan Warren -# Copyright (c) 2012-2018 The Bitmessage developers -# Distributed under the MIT/X11 software license. See the accompanying -# file COPYING or http://www.opensource.org/licenses/mit-license.php. +# pylint: disable=no-self-use,too-many-branches,too-many-statements,too-many-locals +""" +bitmessagemain.py +================= -# Right now, PyBitmessage only support connecting to stream 1. It doesn't -# yet contain logic to expand into further streams. +Copyright (c) 2012-2016 Jonathan Warren +Copyright (c) 2012-2018 The Bitmessage developers +Distributed under the MIT/X11 software license. See the accompanying +file COPYING or http://www.opensource.org/licenses/mit-license.php. -# The software version variable is now held in shared.py +Right now, PyBitmessage only support connecting to stream 1. It doesn't +yet contain logic to expand into further streams. +The software version variable is now held in shared.py + +""" + +from __future__ import absolute_import + +import ctypes +import errno +import getopt import os +import signal +import socket import sys +import threading +from random import randint +from struct import pack +from subprocess import call +from time import sleep app_dir = os.path.dirname(os.path.abspath(__file__)) os.chdir(app_dir) sys.path.insert(0, app_dir) - -import depends -depends.check_dependencies() - # Used to capture a Ctrl-C keypress so that Bitmessage can shutdown gracefully. -import signal # The next 3 are used for the API from singleinstance import singleinstance -import errno -import socket -import ctypes -from struct import pack -from subprocess import call -from time import sleep -from random import randint -import getopt from api import MySimpleXMLRPCRequestHandler, StoppableXMLRPCServer from helper_startup import ( @@ -39,11 +45,11 @@ from helper_startup import ( ) import defaults +import depends import shared import knownnodes import state import shutdown -import threading # Classes from class_sqlThread import sqlThread @@ -69,7 +75,12 @@ import helper_bootstrap import helper_generic import helper_threading +depends.check_dependencies() + + def connectToStream(streamNumber): + """Connect to a stream""" + state.streamsInWhichIAmParticipating.append(streamNumber) selfInitiatedConnections[streamNumber] = {} @@ -90,10 +101,10 @@ def connectToStream(streamNumber): with knownnodes.knownNodesLock: if streamNumber not in knownnodes.knownNodes: knownnodes.knownNodes[streamNumber] = {} - if streamNumber*2 not in knownnodes.knownNodes: - knownnodes.knownNodes[streamNumber*2] = {} - if streamNumber*2+1 not in knownnodes.knownNodes: - knownnodes.knownNodes[streamNumber*2+1] = {} + if streamNumber * 2 not in knownnodes.knownNodes: + knownnodes.knownNodes[streamNumber * 2] = {} + if streamNumber * 2 + 1 not in knownnodes.knownNodes: + knownnodes.knownNodes[streamNumber * 2 + 1] = {} BMConnectionPool().connectToStream(streamNumber) @@ -111,6 +122,8 @@ def _fixSocket(): addressToString = ctypes.windll.ws2_32.WSAAddressToStringA def inet_ntop(family, host): + """Convert IPv4 and IPv6 addresses from binary to text form""" + if family == socket.AF_INET: if len(host) != 4: raise ValueError("invalid IPv4 host") @@ -132,6 +145,8 @@ def _fixSocket(): stringToAddress = ctypes.windll.ws2_32.WSAStringToAddressA def inet_pton(family, host): + """Convert IPv4 and IPv6 addresses from text to binary form""" + buf = "\0" * 28 lengthBuf = pack("I", len(buf)) if stringToAddress(str(host), @@ -155,13 +170,15 @@ def _fixSocket(): socket.IPV6_V6ONLY = 27 -# This thread, of which there is only one, runs the API. class singleAPI(threading.Thread, helper_threading.StoppableThread): + """This thread, of which there is only one, runs the API.""" + def __init__(self): threading.Thread.__init__(self, name="singleAPI") self.initStop() def stopThread(self): + """Stop the API thread""" super(singleAPI, self).stopThread() s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) try: @@ -175,9 +192,10 @@ class singleAPI(threading.Thread, helper_threading.StoppableThread): pass def run(self): + """Run the API thread""" port = BMConfigParser().getint('bitmessagesettings', 'apiport') try: - from errno import WSAEADDRINUSE + from errno import WSAEADDRINUSE # pylint: disable=unused-variable except (ImportError, AttributeError): errno.WSAEADDRINUSE = errno.EADDRINUSE for attempt in range(50): @@ -212,15 +230,18 @@ if shared.useVeryEasyProofOfWorkForTesting: defaults.networkDefaultPayloadLengthExtraBytes / 100) -class Main: +class Main(object): + """The main app""" + def start(self): + """Start the main app""" _fixSocket() daemon = BMConfigParser().safeGetBoolean( 'bitmessagesettings', 'daemon') try: - opts, args = getopt.getopt( + opts, _ = getopt.getopt( sys.argv[1:], "hcdt", ["help", "curses", "daemon", "test"]) @@ -228,7 +249,7 @@ class Main: self.usage() sys.exit(2) - for opt, arg in opts: + for opt, _ in opts: if opt in ("-h", "--help"): self.usage() sys.exit() @@ -259,7 +280,7 @@ class Main: if daemon and not state.testmode: with shared.printLock: - print('Running as a daemon. Send TERM signal to end.') + print 'Running as a daemon. Send TERM signal to end.' self.daemonize() self.setSignalHandler() @@ -415,6 +436,7 @@ class Main: sleep(1) def daemonize(self): + """Daemonise""" grandfatherPid = os.getpid() parentPid = None try: @@ -424,7 +446,7 @@ class Main: # wait until grandchild ready while True: sleep(1) - os._exit(0) + sys.exit(0) except AttributeError: # fork not implemented pass @@ -445,7 +467,7 @@ class Main: # wait until child ready while True: sleep(1) - os._exit(0) + sys.exit(0) except AttributeError: # fork not implemented pass @@ -467,11 +489,13 @@ class Main: os.kill(grandfatherPid, signal.SIGTERM) def setSignalHandler(self): + """Register signal handlers""" signal.signal(signal.SIGINT, helper_generic.signal_handler) signal.signal(signal.SIGTERM, helper_generic.signal_handler) - # signal.signal(signal.SIGINT, signal.SIG_DFL) def usage(self): + """Print usage message""" + print 'Usage: ' + sys.argv[0] + ' [OPTIONS]' print ''' Options: @@ -484,12 +508,18 @@ All parameters are optional. ''' def stop(self): + """Stop the daemon""" with shared.printLock: - print('Stopping Bitmessage Deamon.') + print 'Stopping Bitmessage Daemon.' shutdown.doCleanShutdown() - # TODO: nice function but no one is using this def getApiAddress(self): + """ + Return the address and port the API is configured to use + + .. todo:: nice function but no one is using this + """ + if not BMConfigParser().safeGetBoolean( 'bitmessagesettings', 'apienabled'): return None @@ -499,14 +529,10 @@ All parameters are optional. def main(): + """Create and start the main app""" mainprogram = Main() mainprogram.start() if __name__ == "__main__": main() - - -# So far, the creation of and management of the Bitmessage protocol and this -# client is a one-man operation. Bitcoin tips are quite appreciated. -# 1H5XaDA6fYENLbknwZyjiYXYPQaFjjLX2u diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 5e4c18fd..97a3a420 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -395,13 +395,13 @@ class MyForm(settingsmixin.SMainWindow): treeWidget.header().setSortIndicator( 0, QtCore.Qt.AscendingOrder) # init dictionary - + db = getSortedSubscriptions(True) for address in db: for folder in folders: if not folder in db[address]: db[address][folder] = {} - + if treeWidget.isSortingEnabled(): treeWidget.setSortingEnabled(False) @@ -413,7 +413,7 @@ class MyForm(settingsmixin.SMainWindow): toAddress = widget.address else: toAddress = None - + if not toAddress in db: treeWidget.takeTopLevelItem(i) # no increment @@ -444,7 +444,7 @@ class MyForm(settingsmixin.SMainWindow): widget.setUnreadCount(unread) db.pop(toAddress, None) i += 1 - + i = 0 for toAddress in db: widget = Ui_SubscriptionWidget(treeWidget, i, toAddress, db[toAddress]["inbox"]['count'], db[toAddress]["inbox"]['label'], db[toAddress]["inbox"]['enabled']) @@ -459,7 +459,7 @@ class MyForm(settingsmixin.SMainWindow): j += 1 widget.setUnreadCount(unread) i += 1 - + treeWidget.setSortingEnabled(True) @@ -468,14 +468,14 @@ class MyForm(settingsmixin.SMainWindow): def rerenderTabTreeChans(self): self.rerenderTabTree('chan') - + def rerenderTabTree(self, tab): if tab == 'messages': treeWidget = self.ui.treeWidgetYourIdentities elif tab == 'chan': treeWidget = self.ui.treeWidgetChans folders = Ui_FolderWidget.folderWeight.keys() - + # sort ascending when creating if treeWidget.topLevelItemCount() == 0: treeWidget.header().setSortIndicator( @@ -483,7 +483,7 @@ class MyForm(settingsmixin.SMainWindow): # init dictionary db = {} enabled = {} - + for toAddress in getSortedAccounts(): isEnabled = BMConfigParser().getboolean( toAddress, 'enabled') @@ -502,7 +502,7 @@ class MyForm(settingsmixin.SMainWindow): db[toAddress] = {} for folder in folders: db[toAddress][folder] = 0 - + enabled[toAddress] = isEnabled # get number of (unread) messages @@ -520,10 +520,10 @@ class MyForm(settingsmixin.SMainWindow): db[None]["sent"] = 0 db[None]["trash"] = 0 enabled[None] = True - + if treeWidget.isSortingEnabled(): treeWidget.setSortingEnabled(False) - + widgets = {} i = 0 while i < treeWidget.topLevelItemCount(): @@ -532,7 +532,7 @@ class MyForm(settingsmixin.SMainWindow): toAddress = widget.address else: toAddress = None - + if not toAddress in db: treeWidget.takeTopLevelItem(i) # no increment @@ -565,7 +565,7 @@ class MyForm(settingsmixin.SMainWindow): widget.setUnreadCount(unread) db.pop(toAddress, None) i += 1 - + i = 0 for toAddress in db: widget = Ui_AddressWidget(treeWidget, i, toAddress, db[toAddress]["inbox"], enabled[toAddress]) @@ -580,7 +580,7 @@ class MyForm(settingsmixin.SMainWindow): j += 1 widget.setUnreadCount(unread) i += 1 - + treeWidget.setSortingEnabled(True) def __init__(self, parent=None): @@ -622,13 +622,13 @@ class MyForm(settingsmixin.SMainWindow): # e.g. for editing labels self.recurDepth = 0 - + # switch back to this when replying self.replyFromTab = None # so that quit won't loop self.quitAccepted = False - + self.init_file_menu() self.init_inbox_popup_menu() self.init_identities_popup_menu() @@ -730,7 +730,7 @@ class MyForm(settingsmixin.SMainWindow): self.ui.treeWidgetYourIdentities.setIconSize(QtCore.QSize(identicon_size, identicon_size)) self.ui.treeWidgetSubscriptions.setIconSize(QtCore.QSize(identicon_size, identicon_size)) self.ui.tableWidgetAddressBook.setIconSize(QtCore.QSize(identicon_size, identicon_size)) - + self.UISignalThread = UISignaler.get() QtCore.QObject.connect(self.UISignalThread, QtCore.SIGNAL( "writeNewAddressToTable(PyQt_PyObject,PyQt_PyObject,PyQt_PyObject)"), self.writeNewAddressToTable) @@ -784,7 +784,7 @@ class MyForm(settingsmixin.SMainWindow): self.rerenderComboBoxSendFrom() self.rerenderComboBoxSendFromBroadcast() - + # Put the TTL slider in the correct spot TTL = BMConfigParser().getint('bitmessagesettings', 'ttl') if TTL < 3600: # an hour @@ -793,7 +793,7 @@ class MyForm(settingsmixin.SMainWindow): TTL = 28*24*60*60 self.ui.horizontalSliderTTL.setSliderPosition((TTL - 3600) ** (1/3.199)) self.updateHumanFriendlyTTLDescription(TTL) - + QtCore.QObject.connect(self.ui.horizontalSliderTTL, QtCore.SIGNAL( "valueChanged(int)"), self.updateTTL) @@ -817,7 +817,7 @@ class MyForm(settingsmixin.SMainWindow): self.updateHumanFriendlyTTLDescription(TTL) BMConfigParser().set('bitmessagesettings', 'ttl', str(TTL)) BMConfigParser().save() - + def updateHumanFriendlyTTLDescription(self, TTL): numberOfHours = int(round(TTL / (60*60))) font = QtGui.QFont() @@ -981,7 +981,7 @@ class MyForm(settingsmixin.SMainWindow): for row in queryReturn: broadcastsUnread[row[0]] = {} broadcastsUnread[row[0]][row[1]] = row[2] - + for treeWidget in widgets: root = treeWidget.invisibleRootItem() for i in range(root.childCount()): @@ -1100,7 +1100,7 @@ class MyForm(settingsmixin.SMainWindow): if acct is None: acct = BMAccount(fromAddress) acct.parseMessage(toAddress, fromAddress, subject, "") - + items = [] #to MessageList_AddressWidget(items, toAddress, unicode(acct.toLabel, 'utf-8'), not read) @@ -1176,7 +1176,7 @@ class MyForm(settingsmixin.SMainWindow): tableWidget.setRowCount(0) queryreturn = helper_search.search_sql(xAddress, account, folder, where, what, unreadOnly) - + for row in queryreturn: msgfolder, msgid, toAddress, fromAddress, subject, received, read = row self.addMessageListItemInbox(tableWidget, msgfolder, msgid, toAddress, fromAddress, subject, received, read) @@ -1934,7 +1934,7 @@ class MyForm(settingsmixin.SMainWindow): subject = acct.subject toAddress = acct.toAddress else: - if QtGui.QMessageBox.question(self, "Sending an email?", _translate("MainWindow", + if QtGui.QMessageBox.question(self, "Sending an email?", _translate("MainWindow", "You are trying to send an email instead of a bitmessage. This requires registering with a gateway. Attempt to register?"), QtGui.QMessageBox.Yes|QtGui.QMessageBox.No) != QtGui.QMessageBox.Yes: continue @@ -2111,17 +2111,17 @@ class MyForm(settingsmixin.SMainWindow): ackdata = genAckPayload(streamNumber, 0) toAddress = str_broadcast_subscribers ripe = '' - t = ('', # msgid. We don't know what this will be until the POW is done. - toAddress, - ripe, - fromAddress, - subject, - message, - ackdata, + t = ('', # msgid. We don't know what this will be until the POW is done. + toAddress, + ripe, + fromAddress, + subject, + message, + ackdata, int(time.time()), # sentTime (this will never change) int(time.time()), # lastActionTime 0, # sleepTill time. This will get set when the POW gets done. - 'broadcastqueued', + 'broadcastqueued', 0, # retryNumber 'sent', # folder encoding, # encoding type @@ -2131,7 +2131,7 @@ class MyForm(settingsmixin.SMainWindow): '''INSERT INTO sent VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)''', *t) toLabel = str_broadcast_subscribers - + self.displayNewSentMessage( toAddress, toLabel, fromAddress, subject, message, ackdata) @@ -2250,7 +2250,7 @@ class MyForm(settingsmixin.SMainWindow): continue elif not helper_search.check_match(toAddress, fromAddress, subject, message, self.getCurrentSearchOption(tab), self.getCurrentSearchLine(tab)): continue - + self.addMessageListItemSent(sent, toAddress, fromAddress, subject, "msgqueued", ackdata, time.time()) self.getAccountTextedit(acct).setPlainText(unicode(message, 'utf-8', 'replace')) sent.setCurrentCell(0, 0) @@ -2412,11 +2412,11 @@ class MyForm(settingsmixin.SMainWindow): self.settingsDialogInstance.ui.checkBoxUseIdenticons.isChecked())) BMConfigParser().set('bitmessagesettings', 'replybelow', str( self.settingsDialogInstance.ui.checkBoxReplyBelow.isChecked())) - + lang = str(self.settingsDialogInstance.ui.languageComboBox.itemData(self.settingsDialogInstance.ui.languageComboBox.currentIndex()).toString()) BMConfigParser().set('bitmessagesettings', 'userlocale', lang) change_translation(l10n.getTranslationLanguage()) - + if int(BMConfigParser().get('bitmessagesettings', 'port')) != int(self.settingsDialogInstance.ui.lineEditTCPPort.text()): if not BMConfigParser().safeGetBoolean('bitmessagesettings', 'dontconnect'): QtGui.QMessageBox.about(self, _translate("MainWindow", "Restart"), _translate( @@ -2481,7 +2481,7 @@ class MyForm(settingsmixin.SMainWindow): self.settingsDialogInstance.ui.lineEditNamecoinUser.text())) BMConfigParser().set('bitmessagesettings', 'namecoinrpcpassword', str( self.settingsDialogInstance.ui.lineEditNamecoinPassword.text())) - + # Demanded difficulty tab if float(self.settingsDialogInstance.ui.lineEditTotalDifficulty.text()) >= 1: BMConfigParser().set('bitmessagesettings', 'defaultnoncetrialsperbyte', str(int(float( @@ -2495,7 +2495,7 @@ class MyForm(settingsmixin.SMainWindow): queues.workerQueue.put(('resetPoW', '')) acceptableDifficultyChanged = False - + 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()) * defaults.networkDefaultProofOfWorkNonceTrialsPerByte)): @@ -2511,13 +2511,13 @@ class MyForm(settingsmixin.SMainWindow): BMConfigParser().set('bitmessagesettings', 'maxacceptablepayloadlengthextrabytes', str(int(float( self.settingsDialogInstance.ui.lineEditMaxAcceptableSmallMessageDifficulty.text()) * defaults.networkDefaultPayloadLengthExtraBytes))) if acceptableDifficultyChanged: - # It might now be possible to send msgs which were previously marked as toodifficult. + # It might now be possible to send msgs which were previously marked as toodifficult. # Let us change them to 'msgqueued'. The singleWorker will try to send them and will again # mark them as toodifficult if the receiver's required difficulty is still higher than # we are willing to do. sqlExecute('''UPDATE sent SET status='msgqueued' WHERE status='toodifficult' ''') queues.workerQueue.put(('sendmessage', '')) - + #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 @@ -2718,7 +2718,7 @@ class MyForm(settingsmixin.SMainWindow): if getPowType() == "python" and (powQueueSize() > 0 or pendingUpload() > 0): reply = QtGui.QMessageBox.question(self, _translate("MainWindow", "Proof of work pending"), _translate("MainWindow", "%n object(s) pending proof of work", None, QtCore.QCoreApplication.CodecForTr, powQueueSize()) + ", " + - _translate("MainWindow", "%n object(s) waiting to be distributed", None, QtCore.QCoreApplication.CodecForTr, pendingUpload()) + "\n\n" + + _translate("MainWindow", "%n object(s) waiting to be distributed", None, QtCore.QCoreApplication.CodecForTr, pendingUpload()) + "\n\n" + _translate("MainWindow", "Wait until these tasks finish?"), QtGui.QMessageBox.Yes|QtGui.QMessageBox.No|QtGui.QMessageBox.Cancel, QtGui.QMessageBox.Cancel) if reply == QtGui.QMessageBox.No: @@ -2807,7 +2807,7 @@ class MyForm(settingsmixin.SMainWindow): self.updateStatusBar(_translate( "MainWindow", "Waiting for objects to be sent... %1%").arg(50)) maxPendingUpload = max(1, pendingUpload()) - + while pendingUpload() > 1: self.updateStatusBar(_translate( "MainWindow", @@ -2936,7 +2936,7 @@ class MyForm(settingsmixin.SMainWindow): # self.propagateUnreadCount(tableWidget.item(currentRow, 1 if tableWidget.item(currentRow, 1).type == AccountMixin.SUBSCRIPTION else 0).data(QtCore.Qt.UserRole), self.getCurrentFolder()) # else: # self.propagateUnreadCount(tableWidget.item(currentRow, 1 if tableWidget.item(currentRow, 1).type == AccountMixin.SUBSCRIPTION else 0).data(QtCore.Qt.UserRole), self.getCurrentFolder(), self.getCurrentTreeWidget(), 0) - # tableWidget.selectRow(currentRow + 1) + # tableWidget.selectRow(currentRow + 1) # This doesn't de-select the last message if you try to mark it unread, but that doesn't interfere. Might not be necessary. # We could also select upwards, but then our problem would be with the topmost message. # tableWidget.clearSelection() manages to mark the message as read again. @@ -2980,18 +2980,18 @@ class MyForm(settingsmixin.SMainWindow): def on_action_InboxReplyChan(self): self.on_action_InboxReply(self.REPLY_TYPE_CHAN) - + def on_action_InboxReply(self, replyType = None): tableWidget = self.getCurrentMessagelist() if not tableWidget: return - + if replyType is None: replyType = self.REPLY_TYPE_SENDER - + # save this to return back after reply is done self.replyFromTab = self.ui.tabWidget.currentIndex() - + currentInboxRow = tableWidget.currentRow() toAddressAtCurrentInboxRow = tableWidget.item( currentInboxRow, 0).address @@ -3040,7 +3040,7 @@ class MyForm(settingsmixin.SMainWindow): self.ui.lineEditTo.setText(str(acct.fromAddress)) else: self.ui.lineEditTo.setText(tableWidget.item(currentInboxRow, 1).label + " <" + str(acct.fromAddress) + ">") - + # If the previous message was to a chan then we should send our reply to the chan rather than to the particular person who sent the message. if acct.type == AccountMixin.CHAN and replyType == self.REPLY_TYPE_CHAN: logger.debug('original sent to a chan. Setting the to address in the reply to the chan address.') @@ -3048,9 +3048,9 @@ class MyForm(settingsmixin.SMainWindow): self.ui.lineEditTo.setText(str(toAddressAtCurrentInboxRow)) else: self.ui.lineEditTo.setText(tableWidget.item(currentInboxRow, 0).label + " <" + str(acct.toAddress) + ">") - + self.setSendFromComboBox(toAddressAtCurrentInboxRow) - + quotedText = self.quoted_text(unicode(messageAtCurrentInboxRow, 'utf-8', 'replace')) widget['message'].setPlainText(quotedText) if acct.subject[0:3] in ['Re:', 'RE:']: @@ -3497,7 +3497,7 @@ class MyForm(settingsmixin.SMainWindow): return messagelistList[currentIndex] else: return False - + def getAccountMessagelist(self, account): try: if account.type == AccountMixin.CHAN: @@ -3584,7 +3584,7 @@ class MyForm(settingsmixin.SMainWindow): if currentItem: return currentItem return False - + def getCurrentAccount(self, treeWidget=None): currentItem = self.getCurrentItem(treeWidget) if currentItem: @@ -3711,7 +3711,7 @@ class MyForm(settingsmixin.SMainWindow): def on_action_AddressBookSetAvatar(self): self.on_action_SetAvatar(self.ui.tableWidgetAddressBook) - + def on_action_SetAvatar(self, thisTableWidget): currentRow = thisTableWidget.currentRow() addressAtCurrentRow = thisTableWidget.item( @@ -3765,7 +3765,7 @@ class MyForm(settingsmixin.SMainWindow): self, 'Message', displayMsg, QtGui.QMessageBox.Yes, QtGui.QMessageBox.No) else: overwrite = QtGui.QMessageBox.No - + # copy the image file to the appdata folder if (not exists) | (overwrite == QtGui.QMessageBox.Yes): if overwrite == QtGui.QMessageBox.Yes: @@ -3983,7 +3983,11 @@ class MyForm(settingsmixin.SMainWindow): if column != 0: return # only account names of normal addresses (no chans/mailinglists) - if (not isinstance(item, Ui_AddressWidget)) or (not self.getCurrentTreeWidget()) or self.getCurrentTreeWidget().currentItem() is None: + if ( + not isinstance(item, Ui_AddressWidget) or + not self.getCurrentTreeWidget() or + self.getCurrentTreeWidget().currentItem() is None + ): return # not visible if (not self.getCurrentItem()) or (not isinstance (self.getCurrentItem(), Ui_AddressWidget)): @@ -3994,7 +3998,7 @@ class MyForm(settingsmixin.SMainWindow): # "All accounts" can't be renamed if item.type == AccountMixin.ALL: return - + newLabel = unicode(item.text(0), 'utf-8', 'ignore') oldLabel = item.defaultLabel() @@ -4137,7 +4141,7 @@ class settingsDialog(QtGui.QDialog): BMConfigParser().safeGetBoolean('bitmessagesettings', 'useidenticons')) self.ui.checkBoxReplyBelow.setChecked( BMConfigParser().safeGetBoolean('bitmessagesettings', 'replybelow')) - + if state.appdata == paths.lookupExeFolder(): self.ui.checkBoxPortableMode.setChecked(True) else: @@ -4262,8 +4266,8 @@ class settingsDialog(QtGui.QDialog): BMConfigParser().get('bitmessagesettings', 'stopresendingafterxdays'))) self.ui.lineEditMonths.setText(str( BMConfigParser().get('bitmessagesettings', 'stopresendingafterxmonths'))) - - + + #'System' tab removed for now. """try: maxCores = BMConfigParser().getint('bitmessagesettings', 'maxcores') @@ -4314,7 +4318,7 @@ class settingsDialog(QtGui.QDialog): def namecoinTypeChanged(self, checked): nmctype = self.getNamecoinType() assert nmctype == "namecoind" or nmctype == "nmcontrol" - + isNamecoind = (nmctype == "namecoind") self.ui.lineEditNamecoinUser.setEnabled(isNamecoind) self.ui.labelNamecoinUser.setEnabled(isNamecoind) @@ -4438,7 +4442,7 @@ def run(): # myapp.showMigrationWizard(BMConfigParser().get('bitmessagesettings', 'mailchuck')) # except: # myapp.showMigrationWizard(0) - + # only show after wizards and connect dialogs have completed if not BMConfigParser().getboolean('bitmessagesettings', 'startintray'): myapp.show() diff --git a/src/bitmessageqt/bitmessageui.py b/src/bitmessageqt/bitmessageui.py index cb3578c0..7aec31f2 100644 --- a/src/bitmessageqt/bitmessageui.py +++ b/src/bitmessageqt/bitmessageui.py @@ -1,20 +1,29 @@ # -*- coding: utf-8 -*- +# pylint: disable=too-many-locals +""" +Form implementation generated from reading ui file 'bitmessageui.ui' -# Form implementation generated from reading ui file 'bitmessageui.ui' -# -# Created: Mon Mar 23 22:18:07 2015 -# by: PyQt4 UI code generator 4.10.4 -# -# WARNING! All changes made in this file will be lost! +Created: Mon Mar 23 22:18:07 2015 + by: PyQt4 UI code generator 4.10.4 + +WARNING! All changes made in this file will be lost! +""" + +from __future__ import absolute_import + +import sys from PyQt4 import QtCore, QtGui + from bmconfigparser import BMConfigParser -from foldertree import AddressBookCompleter -from messageview import MessageView -from messagecompose import MessageCompose -import settingsmixin -from networkstatus import NetworkStatus -from blacklist import Blacklist +from . import bitmessage_icons_rc # pylint: disable=unused-import +from . import settingsmixin +from .messageview import MessageView +from .messagecompose import MessageCompose +from .networkstatus import NetworkStatus +from .blacklist import Blacklist +from .foldertree import AddressBookCompleter + try: _fromUtf8 = QtCore.QString.fromUtf8 @@ -24,24 +33,38 @@ except AttributeError: try: _encoding = QtGui.QApplication.UnicodeUTF8 - def _translate(context, text, disambig, encoding = QtCore.QCoreApplication.CodecForTr, n = None): + + def _translate(context, text, disambig, encoding=QtCore.QCoreApplication.CodecForTr, n=None): + # pylint: disable=unused-argument if n is None: return QtGui.QApplication.translate(context, text, disambig, _encoding) - else: - return QtGui.QApplication.translate(context, text, disambig, _encoding, n) + return QtGui.QApplication.translate(context, text, disambig, _encoding, n) + except AttributeError: - def _translate(context, text, disambig, encoding = QtCore.QCoreApplication.CodecForTr, n = None): + + def _translate(context, text, disambig, encoding=QtCore.QCoreApplication.CodecForTr, n=None): + # pylint: disable=unused-argument if n is None: return QtGui.QApplication.translate(context, text, disambig) - else: - return QtGui.QApplication.translate(context, text, disambig, QtCore.QCoreApplication.CodecForTr, n) + return QtGui.QApplication.translate(context, text, disambig, QtCore.QCoreApplication.CodecForTr, n) + class Ui_MainWindow(object): + """Encapsulate the main UI""" + # pylint: disable=too-many-instance-attributes,too-many-statements + def setupUi(self, MainWindow): + """Set up the UI""" + # pylint: disable=attribute-defined-outside-init + MainWindow.setObjectName(_fromUtf8("MainWindow")) MainWindow.resize(885, 580) icon = QtGui.QIcon() - icon.addPixmap(QtGui.QPixmap(_fromUtf8(":/newPrefix/images/can-icon-24px.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off) + icon.addPixmap( + QtGui.QPixmap( + _fromUtf8(":/newPrefix/images/can-icon-24px.png")), + QtGui.QIcon.Normal, + QtGui.QIcon.Off) MainWindow.setWindowIcon(icon) MainWindow.setTabShape(QtGui.QTabWidget.Rounded) self.centralwidget = QtGui.QWidget(MainWindow) @@ -75,7 +98,11 @@ class Ui_MainWindow(object): self.treeWidgetYourIdentities.setObjectName(_fromUtf8("treeWidgetYourIdentities")) self.treeWidgetYourIdentities.resize(200, self.treeWidgetYourIdentities.height()) icon1 = QtGui.QIcon() - icon1.addPixmap(QtGui.QPixmap(_fromUtf8(":/newPrefix/images/identities.png")), QtGui.QIcon.Selected, QtGui.QIcon.Off) + icon1.addPixmap( + QtGui.QPixmap( + _fromUtf8(":/newPrefix/images/identities.png")), + QtGui.QIcon.Selected, + QtGui.QIcon.Off) self.treeWidgetYourIdentities.headerItem().setIcon(0, icon1) self.verticalSplitter_12.addWidget(self.treeWidgetYourIdentities) self.pushButtonNewAddress = QtGui.QPushButton(self.inbox) @@ -175,7 +202,11 @@ class Ui_MainWindow(object): self.tableWidgetAddressBook.resize(200, self.tableWidgetAddressBook.height()) item = QtGui.QTableWidgetItem() icon3 = QtGui.QIcon() - icon3.addPixmap(QtGui.QPixmap(_fromUtf8(":/newPrefix/images/addressbook.png")), QtGui.QIcon.Selected, QtGui.QIcon.Off) + icon3.addPixmap( + QtGui.QPixmap( + _fromUtf8(":/newPrefix/images/addressbook.png")), + QtGui.QIcon.Selected, + QtGui.QIcon.Off) item.setIcon(icon3) self.tableWidgetAddressBook.setHorizontalHeaderItem(0, item) item = QtGui.QTableWidgetItem() @@ -376,7 +407,11 @@ class Ui_MainWindow(object): self.treeWidgetSubscriptions.setObjectName(_fromUtf8("treeWidgetSubscriptions")) self.treeWidgetSubscriptions.resize(200, self.treeWidgetSubscriptions.height()) icon5 = QtGui.QIcon() - icon5.addPixmap(QtGui.QPixmap(_fromUtf8(":/newPrefix/images/subscriptions.png")), QtGui.QIcon.Selected, QtGui.QIcon.Off) + icon5.addPixmap( + QtGui.QPixmap( + _fromUtf8(":/newPrefix/images/subscriptions.png")), + QtGui.QIcon.Selected, + QtGui.QIcon.Off) self.treeWidgetSubscriptions.headerItem().setIcon(0, icon5) self.verticalSplitter_3.addWidget(self.treeWidgetSubscriptions) self.pushButtonAddSubscription = QtGui.QPushButton(self.subscriptions) @@ -455,7 +490,11 @@ class Ui_MainWindow(object): self.horizontalSplitter_4.setCollapsible(1, False) self.gridLayout_3.addWidget(self.horizontalSplitter_4, 0, 0, 1, 1) icon6 = QtGui.QIcon() - icon6.addPixmap(QtGui.QPixmap(_fromUtf8(":/newPrefix/images/subscriptions.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off) + icon6.addPixmap( + QtGui.QPixmap( + _fromUtf8(":/newPrefix/images/subscriptions.png")), + QtGui.QIcon.Normal, + QtGui.QIcon.Off) self.tabWidget.addTab(self.subscriptions, icon6, _fromUtf8("")) self.chans = QtGui.QWidget() self.chans.setObjectName(_fromUtf8("chans")) @@ -475,7 +514,11 @@ class Ui_MainWindow(object): self.treeWidgetChans.setObjectName(_fromUtf8("treeWidgetChans")) self.treeWidgetChans.resize(200, self.treeWidgetChans.height()) icon7 = QtGui.QIcon() - icon7.addPixmap(QtGui.QPixmap(_fromUtf8(":/newPrefix/images/can-icon-16px.png")), QtGui.QIcon.Selected, QtGui.QIcon.Off) + icon7.addPixmap( + QtGui.QPixmap( + _fromUtf8(":/newPrefix/images/can-icon-16px.png")), + QtGui.QIcon.Selected, + QtGui.QIcon.Off) self.treeWidgetChans.headerItem().setIcon(0, icon7) self.verticalSplitter_17.addWidget(self.treeWidgetChans) self.pushButtonAddChan = QtGui.QPushButton(self.chans) @@ -554,7 +597,11 @@ class Ui_MainWindow(object): self.horizontalSplitter_7.setCollapsible(1, False) self.gridLayout_4.addWidget(self.horizontalSplitter_7, 0, 0, 1, 1) icon8 = QtGui.QIcon() - icon8.addPixmap(QtGui.QPixmap(_fromUtf8(":/newPrefix/images/can-icon-16px.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off) + icon8.addPixmap( + QtGui.QPixmap( + _fromUtf8(":/newPrefix/images/can-icon-16px.png")), + QtGui.QIcon.Normal, + QtGui.QIcon.Off) self.tabWidget.addTab(self.chans, icon8, _fromUtf8("")) self.blackwhitelist = Blacklist() self.tabWidget.addTab(self.blackwhitelist, QtGui.QIcon(":/newPrefix/images/blacklist.png"), "") @@ -652,6 +699,8 @@ class Ui_MainWindow(object): MainWindow.setTabOrder(self.textEditMessage, self.pushButtonAddSubscription) def updateNetworkSwitchMenuLabel(self, dontconnect=None): + """Restore last online/offline setting""" + if dontconnect is None: dontconnect = BMConfigParser().safeGetBoolean( 'bitmessagesettings', 'dontconnect') @@ -662,6 +711,8 @@ class Ui_MainWindow(object): ) def retranslateUi(self, MainWindow): + """Re-translate the UI""" + MainWindow.setWindowTitle(_translate("MainWindow", "Bitmessage", None)) self.treeWidgetYourIdentities.headerItem().setText(0, _translate("MainWindow", "Identities", None)) self.pushButtonNewAddress.setText(_translate("MainWindow", "New Identity", None)) @@ -691,19 +742,33 @@ class Ui_MainWindow(object): self.label_3.setText(_translate("MainWindow", "Subject:", None)) self.label_2.setText(_translate("MainWindow", "From:", None)) self.label.setText(_translate("MainWindow", "To:", None)) - #self.textEditMessage.setHtml("") - self.tabWidgetSend.setTabText(self.tabWidgetSend.indexOf(self.sendDirect), _translate("MainWindow", "Send ordinary Message", None)) + # self.textEditMessage.setHtml("") + self.tabWidgetSend.setTabText( + self.tabWidgetSend.indexOf( + self.sendDirect), + _translate( + "MainWindow", "Send ordinary Message", None)) self.label_8.setText(_translate("MainWindow", "From:", None)) self.label_7.setText(_translate("MainWindow", "Subject:", None)) - #self.textEditMessageBroadcast.setHtml("") - self.tabWidgetSend.setTabText(self.tabWidgetSend.indexOf(self.sendBroadcast), _translate("MainWindow", "Send Message to your Subscribers", None)) + # self.textEditMessageBroadcast.setHtml("") + self.tabWidgetSend.setTabText( + self.tabWidgetSend.indexOf( + self.sendBroadcast), + _translate( + "MainWindow", "Send Message to your Subscribers", None)) self.pushButtonTTL.setText(_translate("MainWindow", "TTL:", None)) hours = 48 try: - hours = int(BMConfigParser().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)) + self.labelHumanFriendlyTTLDescription.setText( + _translate( + "MainWindow", + "%n hour(s)", + None, + QtCore.QCoreApplication.CodecForTr, + hours)) self.pushButtonClear.setText(_translate("MainWindow", "Clear", None)) self.pushButtonSend.setText(_translate("MainWindow", "Send", None)) self.tabWidget.setTabText(self.tabWidget.indexOf(self.send), _translate("MainWindow", "Send", None)) @@ -724,7 +789,11 @@ class Ui_MainWindow(object): item.setText(_translate("MainWindow", "Subject", None)) item = self.tableWidgetInboxSubscriptions.horizontalHeaderItem(3) item.setText(_translate("MainWindow", "Received", None)) - self.tabWidget.setTabText(self.tabWidget.indexOf(self.subscriptions), _translate("MainWindow", "Subscriptions", None)) + self.tabWidget.setTabText( + self.tabWidget.indexOf( + self.subscriptions), + _translate( + "MainWindow", "Subscriptions", None)) self.treeWidgetChans.headerItem().setText(0, _translate("MainWindow", "Chans", None)) self.pushButtonAddChan.setText(_translate("MainWindow", "Add Chan", None)) self.inboxSearchLineEditChans.setPlaceholderText(_translate("MainWindow", "Search", None)) @@ -744,9 +813,17 @@ class Ui_MainWindow(object): item.setText(_translate("MainWindow", "Received", None)) self.tabWidget.setTabText(self.tabWidget.indexOf(self.chans), _translate("MainWindow", "Chans", None)) self.blackwhitelist.retranslateUi() - self.tabWidget.setTabText(self.tabWidget.indexOf(self.blackwhitelist), _translate("blacklist", "Blacklist", None)) + self.tabWidget.setTabText( + self.tabWidget.indexOf( + self.blackwhitelist), + _translate( + "blacklist", "Blacklist", None)) self.networkstatus.retranslateUi() - self.tabWidget.setTabText(self.tabWidget.indexOf(self.networkstatus), _translate("networkstatus", "Network Status", None)) + self.tabWidget.setTabText( + self.tabWidget.indexOf( + self.networkstatus), + _translate( + "networkstatus", "Network Status", None)) self.menuFile.setTitle(_translate("MainWindow", "File", None)) self.menuSettings.setTitle(_translate("MainWindow", "Settings", None)) self.menuHelp.setTitle(_translate("MainWindow", "Help", None)) @@ -759,19 +836,17 @@ class Ui_MainWindow(object): self.actionSupport.setText(_translate("MainWindow", "Contact support", None)) self.actionAbout.setText(_translate("MainWindow", "About", None)) self.actionSettings.setText(_translate("MainWindow", "Settings", None)) - self.actionRegenerateDeterministicAddresses.setText(_translate("MainWindow", "Regenerate deterministic addresses", None)) + self.actionRegenerateDeterministicAddresses.setText( + _translate("MainWindow", "Regenerate deterministic addresses", None)) self.actionDeleteAllTrashedMessages.setText(_translate("MainWindow", "Delete all trashed messages", None)) self.actionJoinChan.setText(_translate("MainWindow", "Join / Create chan", None)) -import bitmessage_icons_rc if __name__ == "__main__": - import sys - - app = QtGui.QApplication(sys.argv) - MainWindow = settingsmixin.SMainWindow() - ui = Ui_MainWindow() - ui.setupUi(MainWindow) - MainWindow.show() - sys.exit(app.exec_()) + app = QtGui.QApplication(sys.argv) + ThisMainWindow = settingsmixin.SMainWindow() + ui = Ui_MainWindow() + ui.setupUi(ThisMainWindow) + ThisMainWindow.show() + sys.exit(app.exec_()) diff --git a/src/bitmessageqt/newaddresswizard.py b/src/bitmessageqt/newaddresswizard.py deleted file mode 100644 index 2311239c..00000000 --- a/src/bitmessageqt/newaddresswizard.py +++ /dev/null @@ -1,354 +0,0 @@ -#!/usr/bin/env python2.7 -from PyQt4 import QtCore, QtGui - -class NewAddressWizardIntroPage(QtGui.QWizardPage): - def __init__(self): - super(QtGui.QWizardPage, self).__init__() - self.setTitle("Creating a new address") - - label = QtGui.QLabel("This wizard will help you create as many addresses as you like. Indeed, creating and abandoning addresses is encouraged.\n\n" - "What type of address would you like? Would you like to send emails or not?\n" - "You can still change your mind later, and register/unregister with an email service provider.\n\n") - label.setWordWrap(True) - - self.emailAsWell = QtGui.QRadioButton("Combined email and bitmessage address") - self.onlyBM = QtGui.QRadioButton("Bitmessage-only address (no email)") - self.emailAsWell.setChecked(True) - self.registerField("emailAsWell", self.emailAsWell) - self.registerField("onlyBM", self.onlyBM) - - layout = QtGui.QVBoxLayout() - layout.addWidget(label) - layout.addWidget(self.emailAsWell) - layout.addWidget(self.onlyBM) - self.setLayout(layout) - - def nextId(self): - if self.emailAsWell.isChecked(): - return 4 - else: - return 1 - - -class NewAddressWizardRngPassphrasePage(QtGui.QWizardPage): - def __init__(self): - super(QtGui.QWizardPage, self).__init__() - self.setTitle("Random or Passphrase") - - label = QtGui.QLabel("
You may generate addresses by using either random numbers or by using a passphrase. " - "If you use a passphrase, the address is called a "deterministic" address. " - "The \'Random Number\' option is selected by default but deterministic addresses have several pros and cons:
" - "Pros: | Cons: |
You can recreate your addresses on any computer from memory. " - "You need-not worry about backing up your keys.dat file as long as you can remember your passphrase. | " - "You must remember (or write down) your passphrase if you expect to be able "
- "to recreate your keys if they are lost. "
-# "You must remember the address version number and the stream number along with your passphrase. "
- "If you choose a weak passphrase and someone on the Internet can brute-force it, they can read your messages and send messages as you."
- "")
- label.setWordWrap(True)
-
- self.randomAddress = QtGui.QRadioButton("Use a random number generator to make an address")
- self.deterministicAddress = QtGui.QRadioButton("Use a passphrase to make an address")
- self.randomAddress.setChecked(True)
-
- layout = QtGui.QVBoxLayout()
- layout.addWidget(label)
- layout.addWidget(self.randomAddress)
- layout.addWidget(self.deterministicAddress)
- self.setLayout(layout)
-
- def nextId(self):
- if self.randomAddress.isChecked():
- return 2
- else:
- return 3
-
-class NewAddressWizardRandomPage(QtGui.QWizardPage):
- def __init__(self, addresses):
- super(QtGui.QWizardPage, self).__init__()
- self.setTitle("Random")
-
- label = QtGui.QLabel("Random address.")
- label.setWordWrap(True)
-
- labelLabel = QtGui.QLabel("Label (not shown to anyone except you):")
- self.labelLineEdit = QtGui.QLineEdit()
-
- self.radioButtonMostAvailable = QtGui.QRadioButton("Use the most available stream\n"
- "(best if this is the first of many addresses you will create)")
- self.radioButtonExisting = QtGui.QRadioButton("Use the same stream as an existing address\n"
- "(saves you some bandwidth and processing power)")
- self.radioButtonMostAvailable.setChecked(True)
- self.comboBoxExisting = QtGui.QComboBox()
- self.comboBoxExisting.setEnabled(False)
- self.comboBoxExisting.setEditable(True)
-
- for address in addresses:
- self.comboBoxExisting.addItem(address)
-
-# self.comboBoxExisting.setObjectName(_fromUtf8("comboBoxExisting"))
- self.checkBoxEighteenByteRipe = QtGui.QCheckBox("Spend several minutes of extra computing time to make the address(es) 1 or 2 characters shorter")
-
- layout = QtGui.QGridLayout()
- layout.addWidget(label, 0, 0)
- layout.addWidget(labelLabel, 1, 0)
- layout.addWidget(self.labelLineEdit, 2, 0)
- layout.addWidget(self.radioButtonMostAvailable, 3, 0)
- layout.addWidget(self.radioButtonExisting, 4, 0)
- layout.addWidget(self.comboBoxExisting, 5, 0)
- layout.addWidget(self.checkBoxEighteenByteRipe, 6, 0)
- self.setLayout(layout)
-
- QtCore.QObject.connect(self.radioButtonExisting, QtCore.SIGNAL("toggled(bool)"), self.comboBoxExisting.setEnabled)
-
- self.registerField("label", self.labelLineEdit)
- self.registerField("radioButtonMostAvailable", self.radioButtonMostAvailable)
- self.registerField("radioButtonExisting", self.radioButtonExisting)
- self.registerField("comboBoxExisting", self.comboBoxExisting)
-
-# self.emailAsWell = QtGui.QRadioButton("Combined email and bitmessage account")
-# self.onlyBM = QtGui.QRadioButton("Bitmessage-only account (no email)")
-# self.emailAsWell.setChecked(True)
-
- def nextId(self):
- return 6
-
-
-class NewAddressWizardPassphrasePage(QtGui.QWizardPage):
- def __init__(self):
- super(QtGui.QWizardPage, self).__init__()
- self.setTitle("Passphrase")
-
- label = QtGui.QLabel("Deterministric address.")
- label.setWordWrap(True)
-
- passphraseLabel = QtGui.QLabel("Passphrase")
- self.lineEditPassphrase = QtGui.QLineEdit()
- self.lineEditPassphrase.setEchoMode(QtGui.QLineEdit.Password)
- self.lineEditPassphrase.setInputMethodHints(QtCore.Qt.ImhHiddenText|QtCore.Qt.ImhNoAutoUppercase|QtCore.Qt.ImhNoPredictiveText)
- retypePassphraseLabel = QtGui.QLabel("Retype passphrase")
- self.lineEditPassphraseAgain = QtGui.QLineEdit()
- self.lineEditPassphraseAgain.setEchoMode(QtGui.QLineEdit.Password)
-
- numberLabel = QtGui.QLabel("Number of addresses to make based on your passphrase:")
- self.spinBoxNumberOfAddressesToMake = QtGui.QSpinBox()
- self.spinBoxNumberOfAddressesToMake.setMinimum(1)
- self.spinBoxNumberOfAddressesToMake.setProperty("value", 8)
-# self.spinBoxNumberOfAddressesToMake.setObjectName(_fromUtf8("spinBoxNumberOfAddressesToMake"))
- label2 = QtGui.QLabel("In addition to your passphrase, you must remember these numbers:")
- label3 = QtGui.QLabel("Address version number: 4")
- label4 = QtGui.QLabel("Stream number: 1")
-
- layout = QtGui.QGridLayout()
- layout.addWidget(label, 0, 0, 1, 4)
- layout.addWidget(passphraseLabel, 1, 0, 1, 4)
- layout.addWidget(self.lineEditPassphrase, 2, 0, 1, 4)
- layout.addWidget(retypePassphraseLabel, 3, 0, 1, 4)
- layout.addWidget(self.lineEditPassphraseAgain, 4, 0, 1, 4)
- layout.addWidget(numberLabel, 5, 0, 1, 3)
- layout.addWidget(self.spinBoxNumberOfAddressesToMake, 5, 3)
- layout.setColumnMinimumWidth(3, 1)
- layout.addWidget(label2, 6, 0, 1, 4)
- layout.addWidget(label3, 7, 0, 1, 2)
- layout.addWidget(label4, 7, 2, 1, 2)
- self.setLayout(layout)
-
- def nextId(self):
- return 6
-
-
-class NewAddressWizardEmailProviderPage(QtGui.QWizardPage):
- def __init__(self):
- super(QtGui.QWizardPage, self).__init__()
- self.setTitle("Choose email provider")
-
- label = QtGui.QLabel("Currently only Mailchuck email gateway is available "
- "(@mailchuck.com email address). In the future, maybe other gateways will be available. "
- "Press Next.")
- label.setWordWrap(True)
-
-# self.mailchuck = QtGui.QRadioButton("Mailchuck email gateway (@mailchuck.com)")
-# self.mailchuck.setChecked(True)
-
- layout = QtGui.QVBoxLayout()
- layout.addWidget(label)
-# layout.addWidget(self.mailchuck)
- self.setLayout(layout)
-
- def nextId(self):
- return 5
-
-
-class NewAddressWizardEmailAddressPage(QtGui.QWizardPage):
- def __init__(self):
- super(QtGui.QWizardPage, self).__init__()
- self.setTitle("Email address")
-
- label = QtGui.QLabel("Choosing an email address. Address must end with @mailchuck.com")
- label.setWordWrap(True)
-
- self.specificEmail = QtGui.QRadioButton("Pick your own email address:")
- self.specificEmail.setChecked(True)
- self.emailLineEdit = QtGui.QLineEdit()
- self.randomEmail = QtGui.QRadioButton("Generate a random email address")
-
- QtCore.QObject.connect(self.specificEmail, QtCore.SIGNAL("toggled(bool)"), self.emailLineEdit.setEnabled)
-
- layout = QtGui.QVBoxLayout()
- layout.addWidget(label)
- layout.addWidget(self.specificEmail)
- layout.addWidget(self.emailLineEdit)
- layout.addWidget(self.randomEmail)
- self.setLayout(layout)
-
- def nextId(self):
- return 6
-
-
-class NewAddressWizardWaitPage(QtGui.QWizardPage):
- def __init__(self):
- super(QtGui.QWizardPage, self).__init__()
- self.setTitle("Wait")
-
- self.label = QtGui.QLabel("Wait!")
- self.label.setWordWrap(True)
- self.progressBar = QtGui.QProgressBar()
- self.progressBar.setMinimum(0)
- self.progressBar.setMaximum(100)
- self.progressBar.setValue(0)
-
-# self.emailAsWell = QtGui.QRadioButton("Combined email and bitmessage account")
-# self.onlyBM = QtGui.QRadioButton("Bitmessage-only account (no email)")
-# self.emailAsWell.setChecked(True)
-
- layout = QtGui.QVBoxLayout()
- layout.addWidget(self.label)
- layout.addWidget(self.progressBar)
-# layout.addWidget(self.emailAsWell)
-# layout.addWidget(self.onlyBM)
- self.setLayout(layout)
-
- def update(self, i):
- if i == 101 and self.wizard().currentId() == 6:
- self.wizard().button(QtGui.QWizard.NextButton).click()
- return
- elif i == 101:
- print "haha"
- return
- self.progressBar.setValue(i)
- if i == 50:
- self.emit(QtCore.SIGNAL('completeChanged()'))
-
- def isComplete(self):
-# print "val = " + str(self.progressBar.value())
- if self.progressBar.value() >= 50:
- return True
- else:
- return False
-
- def initializePage(self):
- if self.field("emailAsWell").toBool():
- val = "yes/"
- else:
- val = "no/"
- if self.field("onlyBM").toBool():
- val += "yes"
- else:
- val += "no"
-
- self.label.setText("Wait! " + val)
-# self.wizard().button(QtGui.QWizard.NextButton).setEnabled(False)
- self.progressBar.setValue(0)
- self.thread = NewAddressThread()
- self.connect(self.thread, self.thread.signal, self.update)
- self.thread.start()
-
- def nextId(self):
- return 10
-
-
-class NewAddressWizardConclusionPage(QtGui.QWizardPage):
- def __init__(self):
- super(QtGui.QWizardPage, self).__init__()
- self.setTitle("All done!")
-
- label = QtGui.QLabel("You successfully created a new address.")
- label.setWordWrap(True)
-
- layout = QtGui.QVBoxLayout()
- layout.addWidget(label)
- self.setLayout(layout)
-
-class Ui_NewAddressWizard(QtGui.QWizard):
- def __init__(self, addresses):
- super(QtGui.QWizard, self).__init__()
-
- self.pages = {}
-
- page = NewAddressWizardIntroPage()
- self.setPage(0, page)
- self.setStartId(0)
- page = NewAddressWizardRngPassphrasePage()
- self.setPage(1, page)
- page = NewAddressWizardRandomPage(addresses)
- self.setPage(2, page)
- page = NewAddressWizardPassphrasePage()
- self.setPage(3, page)
- page = NewAddressWizardEmailProviderPage()
- self.setPage(4, page)
- page = NewAddressWizardEmailAddressPage()
- self.setPage(5, page)
- page = NewAddressWizardWaitPage()
- self.setPage(6, page)
- page = NewAddressWizardConclusionPage()
- self.setPage(10, page)
-
- self.setWindowTitle("New address wizard")
- self.adjustSize()
- self.show()
-
-class NewAddressThread(QtCore.QThread):
- def __init__(self):
- QtCore.QThread.__init__(self)
- self.signal = QtCore.SIGNAL("signal")
-
- def __del__(self):
- self.wait()
-
- def createDeterministic(self):
- pass
-
- def createPassphrase(self):
- pass
-
- def broadcastAddress(self):
- pass
-
- def registerMailchuck(self):
- pass
-
- def waitRegistration(self):
- pass
-
- def run(self):
- import time
- for i in range(1, 101):
- time.sleep(0.1) # artificial time delay
- self.emit(self.signal, i)
- self.emit(self.signal, 101)
-# self.terminate()
-
-if __name__ == '__main__':
-
- import sys
-
- app = QtGui.QApplication(sys.argv)
-
- wizard = Ui_NewAddressWizard(["a", "b", "c", "d"])
- if (wizard.exec_()):
- print "Email: " + ("yes" if wizard.field("emailAsWell").toBool() else "no")
- print "BM: " + ("yes" if wizard.field("onlyBM").toBool() else "no")
- else:
- print "Wizard cancelled"
- sys.exit()
diff --git a/src/network/asyncore_pollchoose.py b/src/network/asyncore_pollchoose.py
index e50be61b..233a49b1 100644
--- a/src/network/asyncore_pollchoose.py
+++ b/src/network/asyncore_pollchoose.py
@@ -1,7 +1,9 @@
# -*- Mode: Python -*-
# Id: asyncore.py,v 2.51 2000/09/07 22:29:26 rushing Exp
# Author: Sam Rushing |