diff --git a/setup.cfg b/setup.cfg index 32abcdc7..4e185775 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,9 +1,11 @@ [pycodestyle] max-line-length = 119 +ignore = E722,E402 [flake8] max-line-length = 119 -ignore = E722 +ignore = E722,E402 +# E402: pylint is preferred for wrong-import-position # pylint [MESSAGES CONTROL] diff --git a/src/api.py b/src/api.py index a32519e4..6709162b 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 not 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 a9cb7986..3a116709 100755 --- a/src/bitmessagemain.py +++ b/src/bitmessagemain.py @@ -1,37 +1,40 @@ #!/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. -import os -import sys +The software version variable is now held in shared.py -app_dir = os.path.dirname(os.path.abspath(__file__)) -os.chdir(app_dir) -sys.path.insert(0, app_dir) +""" +from __future__ import absolute_import -import depends -depends.check_dependencies() - -# Used to capture a Ctrl-C keypress so that Bitmessage can shutdown gracefully. -import signal -# The next 3 are used for the API -from singleinstance import singleinstance -import errno -import socket import ctypes +import 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 -from random import randint -import getopt + + +# Used to capture a Ctrl-C keypress so that Bitmessage can shutdown gracefully. +# The next 3 are used for the API +from singleinstance import singleinstance from api import MySimpleXMLRPCRequestHandler, StoppableXMLRPCServer from helper_startup import ( @@ -39,11 +42,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 @@ -72,7 +75,12 @@ import helper_generic import helper_threading +depends.check_dependencies() + + def connectToStream(streamNumber): + """Connect to a stream""" + state.streamsInWhichIAmParticipating.append(streamNumber) selfInitiatedConnections[streamNumber] = {} @@ -93,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) @@ -114,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") @@ -135,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), @@ -158,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: @@ -178,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): @@ -215,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"]) @@ -231,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() @@ -249,7 +267,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() @@ -381,8 +399,7 @@ class Main: BMConfigParser().remove_option('bitmessagesettings', 'dontconnect') elif daemon is False: if state.curses: - # if depends.check_curses(): - print('Running with curses') + print 'Running with curses' import bitmessagecurses bitmessagecurses.runwrapper() elif depends.check_pyqt(): @@ -411,6 +428,7 @@ class Main: sleep(1) def daemonize(self): + """Daemonise""" grandfatherPid = os.getpid() parentPid = None try: @@ -420,7 +438,7 @@ class Main: # wait until grandchild ready while True: sleep(1) - os._exit(0) + sys.exit(0) except AttributeError: # fork not implemented pass @@ -441,7 +459,7 @@ class Main: # wait until child ready while True: sleep(1) - os._exit(0) + sys.exit(0) except AttributeError: # fork not implemented pass @@ -463,11 +481,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: @@ -480,12 +500,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 @@ -495,14 +521,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/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 index 2311239c..1cc2bef1 100644 --- a/src/bitmessageqt/newaddresswizard.py +++ b/src/bitmessageqt/newaddresswizard.py @@ -1,12 +1,26 @@ #!/usr/bin/env python2.7 +# pylint: disable=no-self-use +""" +newaddresswizard.py +=================== +""" + +import sys +import time + from PyQt4 import QtCore, QtGui + class NewAddressWizardIntroPage(QtGui.QWizardPage): + """The introduction page for the new address wizard""" + def __init__(self): - super(QtGui.QWizardPage, self).__init__() + super(NewAddressWizardIntroPage, 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" + 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) @@ -22,30 +36,35 @@ class NewAddressWizardIntroPage(QtGui.QWizardPage): layout.addWidget(self.emailAsWell) layout.addWidget(self.onlyBM) self.setLayout(layout) - + def nextId(self): + """Page 1 or 4""" + if self.emailAsWell.isChecked(): return 4 - else: - return 1 - + return 1 + class NewAddressWizardRngPassphrasePage(QtGui.QWizardPage): + """The user chose a random or passphrase-based address""" + def __init__(self): - super(QtGui.QWizardPage, self).__init__() + super(NewAddressWizardRngPassphrasePage, 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 = QtGui.QLabel( + " |
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")
@@ -59,14 +78,18 @@ class NewAddressWizardRngPassphrasePage(QtGui.QWizardPage):
self.setLayout(layout)
def nextId(self):
+ """Page 2"""
+
if self.randomAddress.isChecked():
return 2
- else:
- return 3
+ return 3
+
class NewAddressWizardRandomPage(QtGui.QWizardPage):
+ """The user chose a new random address"""
+
def __init__(self, addresses):
- super(QtGui.QWizardPage, self).__init__()
+ super(NewAddressWizardRandomPage, self).__init__()
self.setTitle("Random")
label = QtGui.QLabel("Random address.")
@@ -75,10 +98,11 @@ class NewAddressWizardRandomPage(QtGui.QWizardPage):
labelLabel = QtGui.QLabel("Label (not shown to anyone except you):")
self.labelLineEdit = QtGui.QLineEdit()
- self.radioButtonMostAvailable = QtGui.QRadioButton("Use the most available stream\n"
+ self.radioButtonMostAvailable = QtGui.QRadioButton(
+ "Use the most available stream\n"
"(best if this is the first of many addresses you will create)")
self.radioButtonExisting = QtGui.QRadioButton("Use the same stream as an existing address\n"
- "(saves you some bandwidth and processing power)")
+ "(saves you some bandwidth and processing power)")
self.radioButtonMostAvailable.setChecked(True)
self.comboBoxExisting = QtGui.QComboBox()
self.comboBoxExisting.setEnabled(False)
@@ -86,10 +110,10 @@ class NewAddressWizardRandomPage(QtGui.QWizardPage):
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")
-
+
+ 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)
@@ -100,24 +124,27 @@ class NewAddressWizardRandomPage(QtGui.QWizardPage):
layout.addWidget(self.checkBoxEighteenByteRipe, 6, 0)
self.setLayout(layout)
- QtCore.QObject.connect(self.radioButtonExisting, QtCore.SIGNAL("toggled(bool)"), self.comboBoxExisting.setEnabled)
-
+ QtCore.QObject.connect( # pylint: disable=no-member
+ self.radioButtonExisting,
+ QtCore.SIGNAL("toggled(bool)"),
+ self.comboBoxExisting.setEnabled)
+
self.registerField("label", self.labelLineEdit)
self.registerField("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):
+ """Page 6"""
+
return 6
-
+
class NewAddressWizardPassphrasePage(QtGui.QWizardPage):
+ """The user chose a passphrase-based address"""
+
def __init__(self):
- super(QtGui.QWizardPage, self).__init__()
+ super(NewAddressWizardPassphrasePage, self).__init__()
self.setTitle("Passphrase")
label = QtGui.QLabel("Deterministric address.")
@@ -126,7 +153,8 @@ class NewAddressWizardPassphrasePage(QtGui.QWizardPage):
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)
+ 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)
@@ -135,11 +163,11 @@ class NewAddressWizardPassphrasePage(QtGui.QWizardPage):
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)
@@ -155,34 +183,39 @@ class NewAddressWizardPassphrasePage(QtGui.QWizardPage):
self.setLayout(layout)
def nextId(self):
+ """Page 6"""
+
return 6
-
+
class NewAddressWizardEmailProviderPage(QtGui.QWizardPage):
+ """The user choses the email gateway address type"""
+
def __init__(self):
- super(QtGui.QWizardPage, self).__init__()
+ super(NewAddressWizardEmailProviderPage, 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.")
+ "(@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):
+ """Page 5"""
+
return 5
-
+
class NewAddressWizardEmailAddressPage(QtGui.QWizardPage):
+ """The user provides their email gateway detauils"""
+
def __init__(self):
- super(QtGui.QWizardPage, self).__init__()
+ super(NewAddressWizardEmailAddressPage, self).__init__()
self.setTitle("Email address")
label = QtGui.QLabel("Choosing an email address. Address must end with @mailchuck.com")
@@ -192,8 +225,9 @@ class NewAddressWizardEmailAddressPage(QtGui.QWizardPage):
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)
+
+ QtCore.QObject.connect( # pylint: disable=no-member
+ self.specificEmail, QtCore.SIGNAL("toggled(bool)"), self.emailLineEdit.setEnabled)
layout = QtGui.QVBoxLayout()
layout.addWidget(label)
@@ -203,33 +237,37 @@ class NewAddressWizardEmailAddressPage(QtGui.QWizardPage):
self.setLayout(layout)
def nextId(self):
+ """Page 6"""
+
return 6
-
+
class NewAddressWizardWaitPage(QtGui.QWizardPage):
+ """Wait for the address to be generated"""
+
def __init__(self):
- super(QtGui.QWizardPage, self).__init__()
+ super(NewAddressWizardWaitPage, 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):
+ """
+ Update the progress bar
+
+ .. todo:: remove print statement?
+ """
if i == 101 and self.wizard().currentId() == 6:
self.wizard().button(QtGui.QWizard.NextButton).click()
return
@@ -239,15 +277,17 @@ class NewAddressWizardWaitPage(QtGui.QWizardPage):
self.progressBar.setValue(i)
if i == 50:
self.emit(QtCore.SIGNAL('completeChanged()'))
-
+
def isComplete(self):
-# print "val = " + str(self.progressBar.value())
+ """Predicate to indicate progress is complete"""
+
if self.progressBar.value() >= 50:
return True
- else:
- return False
-
+ return False
+
def initializePage(self):
+ """Initialize the underlying QWizardPage"""
+
if self.field("emailAsWell").toBool():
val = "yes/"
else:
@@ -258,19 +298,23 @@ class NewAddressWizardWaitPage(QtGui.QWizardPage):
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):
+ """Page 10"""
+
return 10
-
+
class NewAddressWizardConclusionPage(QtGui.QWizardPage):
+ """The user is informed their address has been created"""
+
def __init__(self):
- super(QtGui.QWizardPage, self).__init__()
+ super(NewAddressWizardConclusionPage, self).__init__()
self.setTitle("All done!")
label = QtGui.QLabel("You successfully created a new address.")
@@ -278,14 +322,17 @@ class NewAddressWizardConclusionPage(QtGui.QWizardPage):
layout = QtGui.QVBoxLayout()
layout.addWidget(label)
- self.setLayout(layout)
+ self.setLayout(layout)
+
class Ui_NewAddressWizard(QtGui.QWizard):
+ """The wizard is a collection of pages"""
+
def __init__(self, addresses):
- super(QtGui.QWizard, self).__init__()
+ super(Ui_NewAddressWizard, self).__init__()
self.pages = {}
-
+
page = NewAddressWizardIntroPage()
self.setPage(0, page)
self.setStartId(0)
@@ -308,45 +355,45 @@ class Ui_NewAddressWizard(QtGui.QWizard):
self.adjustSize()
self.show()
+
class NewAddressThread(QtCore.QThread):
+ # pylint: disable=missing-docstring
+
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
+ 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_()):
+ if wizard.exec_():
print "Email: " + ("yes" if wizard.field("emailAsWell").toBool() else "no")
print "BM: " + ("yes" if wizard.field("onlyBM").toBool() else "no")
else:
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 |