diff --git a/setup.cfg b/setup.cfg index 32abcdc703..4e18577510 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 a32519e412..6709162b55 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 @@ 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 @@ def __str__(self): 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. + + 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 + 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 @@ def do_POST(self): # 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 @@ def do_POST(self): 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 @@ def _decode(self, text, decode_type): 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 @@ def _verifyAddress(self, address): 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 @@ def _verifyAddress(self, address): # 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 @@ def HandleListAddresses(self, method): '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 @@ def HandleListAddressBookEntries(self, params): 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 @@ def HandleAddAddressBookEntry(self, params): 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 @@ def HandleDeleteAddressBookEntry(self, params): 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 @@ def HandleCreateRandomAddress(self, params): 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 @@ def HandleCreateRandomAddress(self, params): 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 @@ def HandleCreateDeterministicAddresses(self, params): 'bitmessagesettings', 'defaultnoncetrialsperbyte') payloadLengthExtraBytes = BMConfigParser().get( 'bitmessagesettings', 'defaultpayloadlengthextrabytes') + elif len(params) == 2: passphrase, numberOfAddresses = params addressVersionNumber = 0 @@ -342,6 +364,7 @@ def HandleCreateDeterministicAddresses(self, params): 'bitmessagesettings', 'defaultnoncetrialsperbyte') payloadLengthExtraBytes = BMConfigParser().get( 'bitmessagesettings', 'defaultpayloadlengthextrabytes') + elif len(params) == 3: passphrase, numberOfAddresses, addressVersionNumber = params streamNumber = 0 @@ -350,6 +373,7 @@ def HandleCreateDeterministicAddresses(self, params): 'bitmessagesettings', 'defaultnoncetrialsperbyte') payloadLengthExtraBytes = BMConfigParser().get( 'bitmessagesettings', 'defaultpayloadlengthextrabytes') + elif len(params) == 4: passphrase, numberOfAddresses, addressVersionNumber, \ streamNumber = params @@ -358,6 +382,7 @@ def HandleCreateDeterministicAddresses(self, params): 'bitmessagesettings', 'defaultnoncetrialsperbyte') payloadLengthExtraBytes = BMConfigParser().get( 'bitmessagesettings', 'defaultpayloadlengthextrabytes') + elif len(params) == 5: passphrase, numberOfAddresses, addressVersionNumber, \ streamNumber, eighteenByteRipe = params @@ -365,27 +390,26 @@ def HandleCreateDeterministicAddresses(self, params): '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 @@ def HandleCreateDeterministicAddresses(self, params): 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 @@ def HandleGetDeterministicAddress(self, params): 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 @@ def HandleCreateChan(self, params): 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 @@ def HandleJoinChan(self, params): 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 @@ def HandleJoinChan(self, params): 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 @@ def HandleLeaveChan(self, params): 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 @@ def HandleDeleteAddress(self, params): 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 @@ def HandleGetAllInboxMessages(self, params): 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 @@ def HandleGetAllInboxMessageIds(self, params): 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 @@ def HandleGetInboxMessageById(self, params): 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 @@ def HandleGetAllSentMessages(self, params): 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 @@ def HandleGetAllSentMessageIds(self, params): 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 @@ def HandleInboxMessagesByReceiver(self, params): 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 @@ def HandleGetSentMessageById(self, params): 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 @@ def HandleGetSentMessagesByAddress(self, params): 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 @@ def HandleGetSentMessagesByAddress(self, params): 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 @@ def HandleGetSentMessagesByAckData(self, params): 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 @@ def HandleTrashMessage(self, params): 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 @@ def HandleSendMessage(self, params): 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 @@ def HandleSendMessage(self, params): 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 @@ def HandleSendMessage(self, params): 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 @@ def HandleSendBroadcast(self, params): 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 @@ def HandleGetStatus(self, params): 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 @@ def HandleAddSubscription(self, params): 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 @@ def HandleDeleteSubscription(self, params): 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 @@ def ListSubscriptions(self, params): 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 @@ def HandleDisseminatePreEncryptedMsg(self, params): 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 @@ def HandleDisseminatePreEncryptedMsg(self, params): 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 @@ def HandleDissimatePubKey(self, params): 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 @@ def HandleDissimatePubKey(self, params): 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 @@ def HandleDissimatePubKey(self, params): 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 @@ def HandleGetMessageDataByDestinationHash(self, params): 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 @@ def HandleGetMessageDataByDestinationHash(self, params): 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 @@ def HandleClientStatus(self, params): '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 @@ def HandleDecodeAddress(self, params): '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 @@ def _handle_request(self, method, params): 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 a9cb79860b..3a11670966 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 - -app_dir = os.path.dirname(os.path.abspath(__file__)) -os.chdir(app_dir) -sys.path.insert(0, app_dir) +The software version variable is now held in shared.py +""" -import depends -depends.check_dependencies() +from __future__ import absolute_import -# 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 ctypes import errno +import getopt +import os +import signal import socket -import ctypes +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 @@ ) 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_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 inet_ntop(family, host): 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 inet_pton(family, host): 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 @@ def stopThread(self): 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 @@ def run(self): 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 @@ def start(self): 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 @@ def start(self): 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 @@ def start(self): 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 @@ def start(self): sleep(1) def daemonize(self): + """Daemonise""" grandfatherPid = os.getpid() parentPid = None try: @@ -420,7 +438,7 @@ def daemonize(self): # wait until grandchild ready while True: sleep(1) - os._exit(0) + sys.exit(0) except AttributeError: # fork not implemented pass @@ -441,7 +459,7 @@ def daemonize(self): # wait until child ready while True: sleep(1) - os._exit(0) + sys.exit(0) except AttributeError: # fork not implemented pass @@ -463,11 +481,13 @@ def daemonize(self): 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 @@ def usage(self): ''' 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 @@ def getApiAddress(self): 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/account.py b/src/bitmessageqt/account.py index 92d497f8f7..cf3373dbee 100644 --- a/src/bitmessageqt/account.py +++ b/src/bitmessageqt/account.py @@ -1,26 +1,58 @@ -from PyQt4 import QtCore, QtGui +# pylint: disable=too-many-instance-attributes,attribute-defined-outside-init +""" +account.py +========== -import queues +Account related functions. + +""" + +from __future__ import absolute_import + +import inspect import re import sys -import inspect -from helper_sql import * -from helper_ackPayload import genAckPayload +import time + +from PyQt4 import QtGui + +import queues from addresses import decodeAddress from bmconfigparser import BMConfigParser -from foldertree import AccountMixin -from pyelliptic.openssl import OpenSSL -from utils import str_broadcast_subscribers -import time +from helper_ackPayload import genAckPayload +from helper_sql import sqlQuery, sqlExecute +from .foldertree import AccountMixin +from .utils import str_broadcast_subscribers + def getSortedAccounts(): + """Get a sorted list of configSections""" + configSections = BMConfigParser().addresses() - configSections.sort(cmp = - lambda x,y: cmp(unicode(BMConfigParser().get(x, 'label'), 'utf-8').lower(), unicode(BMConfigParser().get(y, 'label'), 'utf-8').lower()) - ) + configSections.sort( + cmp=lambda x, y: cmp( + unicode( + BMConfigParser().get( + x, + 'label'), + 'utf-8').lower(), + unicode( + BMConfigParser().get( + y, + 'label'), + 'utf-8').lower())) return configSections -def getSortedSubscriptions(count = False): + +def getSortedSubscriptions(count=False): + """ + Actually return a grouped dictionary rather than a sorted list + + :param count: Whether to count messages for each fromaddress in the inbox + :type count: bool, default False + :retuns: dict keys are addresses, values are dicts containing settings + :rtype: dict, default {} + """ queryreturn = sqlQuery('SELECT label, address, enabled FROM subscriptions ORDER BY label COLLATE NOCASE ASC') ret = {} for row in queryreturn: @@ -37,7 +69,7 @@ def getSortedSubscriptions(count = False): GROUP BY inbox.fromaddress, folder''', str_broadcast_subscribers) for row in queryreturn: address, folder, cnt = row - if not folder in ret[address]: + if folder not in ret[address]: ret[address][folder] = { 'label': ret[address]['inbox']['label'], 'enabled': ret[address]['inbox']['enabled'] @@ -45,9 +77,11 @@ def getSortedSubscriptions(count = False): ret[address][folder]['count'] = cnt return ret + def accountClass(address): + """Return a BMAccount for the address""" if not BMConfigParser().has_section(address): - # FIXME: This BROADCAST section makes no sense + # .. todo:: This BROADCAST section makes no sense if address == str_broadcast_subscribers: subscription = BroadcastAccount(address) if subscription.type != AccountMixin.BROADCAST: @@ -60,8 +94,7 @@ def accountClass(address): return subscription try: gateway = BMConfigParser().get(address, "gateway") - for name, cls in inspect.getmembers(sys.modules[__name__], inspect.isclass): -# obj = g(address) + for _, cls in inspect.getmembers(sys.modules[__name__], inspect.isclass): if issubclass(cls, GatewayAccount) and cls.gatewayName == gateway: return cls(address) # general gateway @@ -70,12 +103,15 @@ def accountClass(address): pass # no gateway return BMAccount(address) - -class AccountColor(AccountMixin): - def __init__(self, address, type = None): + + +class AccountColor(AccountMixin): # pylint: disable=too-few-public-methods + """Set the type of account""" + + def __init__(self, address, address_type=None): self.isEnabled = True self.address = address - if type is None: + if address_type is None: if address is None: self.type = AccountMixin.ALL elif BMConfigParser().safeGetBoolean(self.address, 'mailinglist'): @@ -83,16 +119,18 @@ def __init__(self, address, type = None): elif BMConfigParser().safeGetBoolean(self.address, 'chan'): self.type = AccountMixin.CHAN elif sqlQuery( - '''select label from subscriptions where address=?''', self.address): + '''select label from subscriptions where address=?''', self.address): self.type = AccountMixin.SUBSCRIPTION else: self.type = AccountMixin.NORMAL else: - self.type = type + self.type = address_type + - class BMAccount(object): - def __init__(self, address = None): + """Encapsulate a Bitmessage account""" + + def __init__(self, address=None): self.address = address self.type = AccountMixin.NORMAL if BMConfigParser().has_section(address): @@ -108,7 +146,8 @@ def __init__(self, address = None): if queryreturn: self.type = AccountMixin.SUBSCRIPTION - def getLabel(self, address = None): + def getLabel(self, address=None): + """Get a label for this bitmessage account""" if address is None: address = self.address label = address @@ -126,8 +165,10 @@ def getLabel(self, address = None): for row in queryreturn: label, = row return label - + def parseMessage(self, toAddress, fromAddress, subject, message): + """Set metadata and address labels on self""" + self.toAddress = toAddress self.fromAddress = fromAddress if isinstance(subject, unicode): @@ -140,36 +181,45 @@ def parseMessage(self, toAddress, fromAddress, subject, message): class NoAccount(BMAccount): - def __init__(self, address = None): + """Override the __init__ method on a BMAccount""" + + def __init__(self, address=None): # pylint: disable=super-init-not-called self.address = address self.type = AccountMixin.NORMAL - def getLabel(self, address = None): + def getLabel(self, address=None): if address is None: address = self.address return address - + class SubscriptionAccount(BMAccount): + """Encapsulate a subscription account""" pass - + class BroadcastAccount(BMAccount): + """Encapsulate a broadcast account""" pass - - + + class GatewayAccount(BMAccount): + """Encapsulate a gateway account""" + gatewayName = None ALL_OK = 0 REGISTRATION_DENIED = 1 + def __init__(self, address): super(GatewayAccount, self).__init__(address) - + def send(self): + """Override the send method for gateway accounts""" + + # pylint: disable=unused-variable status, addressVersionNumber, streamNumber, ripe = decodeAddress(self.toAddress) stealthLevel = BMConfigParser().safeGetInt('bitmessagesettings', 'ackstealthlevel') ackdata = genAckPayload(streamNumber, stealthLevel) - t = () sqlExecute( '''INSERT INTO sent VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)''', '', @@ -179,47 +229,52 @@ def send(self): self.subject, self.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. + int(time.time()), # sentTime (this will never change) + int(time.time()), # lastActionTime + 0, # sleepTill time. This will get set when the POW gets done. 'msgqueued', - 0, # retryNumber - 'sent', # folder - 2, # encodingtype - min(BMConfigParser().getint('bitmessagesettings', 'ttl'), 86400 * 2) # not necessary to have a TTL higher than 2 days + 0, # retryNumber + 'sent', # folder + 2, # encodingtype + # not necessary to have a TTL higher than 2 days + min(BMConfigParser().getint('bitmessagesettings', 'ttl'), 86400 * 2) ) queues.workerQueue.put(('sendmessage', self.toAddress)) - - def parseMessage(self, toAddress, fromAddress, subject, message): - super(GatewayAccount, self).parseMessage(toAddress, fromAddress, subject, message) + class MailchuckAccount(GatewayAccount): + """Encapsulate a particular kind of gateway account""" + # set "gateway" in keys.dat to this gatewayName = "mailchuck" registrationAddress = "BM-2cVYYrhaY5Gbi3KqrX9Eae2NRNrkfrhCSA" unregistrationAddress = "BM-2cVMAHTRjZHCTPMue75XBK5Tco175DtJ9J" relayAddress = "BM-2cWim8aZwUNqxzjMxstnUMtVEUQJeezstf" - regExpIncoming = re.compile("(.*)MAILCHUCK-FROM::(\S+) \| (.*)") - regExpOutgoing = re.compile("(\S+) (.*)") + regExpIncoming = re.compile(r"(.*)MAILCHUCK-FROM::(\S+) \| (.*)") + regExpOutgoing = re.compile(r"(\S+) (.*)") + def __init__(self, address): super(MailchuckAccount, self).__init__(address) self.feedback = self.ALL_OK - + def createMessage(self, toAddress, fromAddress, subject, message): + """createMessage specific to a MailchuckAccount""" self.subject = toAddress + " " + subject self.toAddress = self.relayAddress self.fromAddress = fromAddress self.message = message - + def register(self, email): + """register specific to a MailchuckAccount""" self.toAddress = self.registrationAddress self.subject = email self.message = "" self.fromAddress = self.address self.send() - + def unregister(self): + """unregister specific to a MailchuckAccount""" self.toAddress = self.unregistrationAddress self.subject = "" self.message = "" @@ -227,6 +282,7 @@ def unregister(self): self.send() def status(self): + """status specific to a MailchuckAccount""" self.toAddress = self.registrationAddress self.subject = "status" self.message = "" @@ -234,12 +290,16 @@ def status(self): self.send() def settings(self): + """settings specific to a MailchuckAccount""" + self.toAddress = self.registrationAddress self.subject = "config" - self.message = QtGui.QApplication.translate("Mailchuck", """# You can use this to configure your email gateway account + self.message = QtGui.QApplication.translate( + "Mailchuck", + """# You can use this to configure your email gateway account # Uncomment the setting you want to use # Here are the options: -# +# # pgp: server # The email gateway will create and maintain PGP keys for you and sign, verify, # encrypt and decrypt on your behalf. When you want to use PGP but are lazy, @@ -255,7 +315,7 @@ def settings(self): # # attachments: no # Attachments will be ignored. -# +# # archive: yes # Your incoming emails will be archived on the server. Use this if you need # help with debugging problems or you need a third party proof of emails. This @@ -279,10 +339,12 @@ def settings(self): self.fromAddress = self.address def parseMessage(self, toAddress, fromAddress, subject, message): + """parseMessage specific to a MailchuckAccount""" + super(MailchuckAccount, self).parseMessage(toAddress, fromAddress, subject, message) if fromAddress == self.relayAddress: matches = self.regExpIncoming.search(subject) - if not matches is None: + if matches is not None: self.subject = "" if not matches.group(1) is None: self.subject += matches.group(1) @@ -293,7 +355,7 @@ def parseMessage(self, toAddress, fromAddress, subject, message): self.fromAddress = matches.group(2) if toAddress == self.relayAddress: matches = self.regExpOutgoing.search(subject) - if not matches is None: + if matches is not None: if not matches.group(2) is None: self.subject = matches.group(2) if not matches.group(1) is None: diff --git a/src/bitmessageqt/bitmessageui.py b/src/bitmessageqt/bitmessageui.py index cb3578c08f..7aec31f214 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 @@ def _fromUtf8(s): 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 @@ def setupUi(self, MainWindow): 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 @@ def setupUi(self, MainWindow): 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 @@ def setupUi(self, MainWindow): 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 @@ def setupUi(self, MainWindow): 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 @@ def setupUi(self, MainWindow): 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 @@ def setupUi(self, MainWindow): 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 @@ def setupUi(self, MainWindow): 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 @@ def updateNetworkSwitchMenuLabel(self, dontconnect=None): ) 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 @@ def retranslateUi(self, MainWindow): 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 @@ def retranslateUi(self, MainWindow): 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 @@ def retranslateUi(self, MainWindow): 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 @@ def retranslateUi(self, MainWindow): 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() + ThisMainWindow = settingsmixin.SMainWindow() ui = Ui_MainWindow() - ui.setupUi(MainWindow) - MainWindow.show() + ui.setupUi(ThisMainWindow) + ThisMainWindow.show() sys.exit(app.exec_()) - diff --git a/src/bitmessageqt/newaddresswizard.py b/src/bitmessageqt/newaddresswizard.py index 2311239c81..1cc2bef137 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 @@ def __init__(self): 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 @@ def __init__(self): 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 @@ def __init__(self, addresses): 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 @@ def __init__(self, addresses): 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 @@ def __init__(self, addresses): 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 @@ def __init__(self): 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 @@ def __init__(self): 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 @@ def __init__(self): 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 @@ def __init__(self): 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 @@ def __init__(self): 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 @@ def update(self, i): 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 @@ def initializePage(self): 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 @@ def __init__(self): 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 @@ def __init__(self, addresses): 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 +if __name__ == '__main__': 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/bitmessageqt/settings.py b/src/bitmessageqt/settings.py index 4342fd090d..22c38a626f 100644 --- a/src/bitmessageqt/settings.py +++ b/src/bitmessageqt/settings.py @@ -1,16 +1,24 @@ # -*- coding: utf-8 -*- +# pylint: disable=too-many-instance-attributes,too-many-locals,too-many-statements,attribute-defined-outside-init +""" +Form implementation generated from reading ui file 'settings.ui' -# Form implementation generated from reading ui file 'settings.ui' -# -# Created: Thu Dec 25 23:21:20 2014 -# by: PyQt4 UI code generator 4.10.3 -# -# WARNING! All changes made in this file will be lost! +Created: Thu Dec 25 23:21:20 2014 + by: PyQt4 UI code generator 4.10.3 + +WARNING! All changes made in this file will be lost! +""" + +from __future__ import absolute_import -from PyQt4 import QtCore, QtGui -from languagebox import LanguageBox from sys import platform +from PyQt4 import QtCore, QtGui + +from . import bitmessage_icons_rc # pylint: disable=unused-import +from .languagebox import LanguageBox + + try: _fromUtf8 = QtCore.QString.fromUtf8 except AttributeError: @@ -19,21 +27,27 @@ def _fromUtf8(s): try: _encoding = QtGui.QApplication.UnicodeUTF8 + def _translate(context, text, disambig): return QtGui.QApplication.translate(context, text, disambig, _encoding) except AttributeError: def _translate(context, text, disambig): return QtGui.QApplication.translate(context, text, disambig) + class Ui_settingsDialog(object): + """Encapsulate a UI settings dialog object""" + def setupUi(self, settingsDialog): + """Set up the UI""" + settingsDialog.setObjectName(_fromUtf8("settingsDialog")) settingsDialog.resize(521, 413) self.gridLayout = QtGui.QGridLayout(settingsDialog) self.gridLayout.setObjectName(_fromUtf8("gridLayout")) self.buttonBox = QtGui.QDialogButtonBox(settingsDialog) self.buttonBox.setOrientation(QtCore.Qt.Horizontal) - self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Cancel|QtGui.QDialogButtonBox.Ok) + self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Cancel | QtGui.QDialogButtonBox.Ok) self.buttonBox.setObjectName(_fromUtf8("buttonBox")) self.gridLayout.addWidget(self.buttonBox, 1, 0, 1, 1) self.tabWidgetSettings = QtGui.QTabWidget(settingsDialog) @@ -64,7 +78,8 @@ def setupUi(self, settingsDialog): self.formLayout.setWidget(1, QtGui.QFormLayout.SpanningRole, self.groupBoxTray) self.checkBoxHideTrayConnectionNotifications = QtGui.QCheckBox(self.tabUserInterface) self.checkBoxHideTrayConnectionNotifications.setChecked(False) - self.checkBoxHideTrayConnectionNotifications.setObjectName(_fromUtf8("checkBoxHideTrayConnectionNotifications")) + self.checkBoxHideTrayConnectionNotifications.setObjectName( + _fromUtf8("checkBoxHideTrayConnectionNotifications")) self.formLayout.setWidget(2, QtGui.QFormLayout.LabelRole, self.checkBoxHideTrayConnectionNotifications) self.checkBoxShowTrayNotifications = QtGui.QCheckBox(self.tabUserInterface) self.checkBoxShowTrayNotifications.setObjectName(_fromUtf8("checkBoxShowTrayNotifications")) @@ -96,7 +111,7 @@ def setupUi(self, settingsDialog): self.formLayout_2.setObjectName(_fromUtf8("formLayout_2")) self.languageComboBox = LanguageBox(self.groupBox) self.languageComboBox.setMinimumSize(QtCore.QSize(100, 0)) - self.languageComboBox.setObjectName(_fromUtf8("languageComboBox")) + self.languageComboBox.setObjectName(_fromUtf8("languageComboBox")) # pylint: disable=not-callable self.formLayout_2.setWidget(0, QtGui.QFormLayout.LabelRole, self.languageComboBox) self.formLayout.setWidget(9, QtGui.QFormLayout.FieldRole, self.groupBox) self.tabWidgetSettings.addTab(self.tabUserInterface, _fromUtf8("")) @@ -108,8 +123,6 @@ def setupUi(self, settingsDialog): self.groupBox1.setObjectName(_fromUtf8("groupBox1")) self.gridLayout_3 = QtGui.QGridLayout(self.groupBox1) self.gridLayout_3.setObjectName(_fromUtf8("gridLayout_3")) - #spacerItem = QtGui.QSpacerItem(125, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum) - #self.gridLayout_3.addItem(spacerItem, 0, 0, 1, 1) self.label = QtGui.QLabel(self.groupBox1) self.label.setObjectName(_fromUtf8("label")) self.gridLayout_3.addWidget(self.label, 0, 0, 1, 1, QtCore.Qt.AlignRight) @@ -165,7 +178,8 @@ def setupUi(self, settingsDialog): self.lineEditMaxOutboundConnections.setSizePolicy(sizePolicy) self.lineEditMaxOutboundConnections.setMaximumSize(QtCore.QSize(60, 16777215)) self.lineEditMaxOutboundConnections.setObjectName(_fromUtf8("lineEditMaxOutboundConnections")) - self.lineEditMaxOutboundConnections.setValidator(QtGui.QIntValidator(0, 8, self.lineEditMaxOutboundConnections)) + self.lineEditMaxOutboundConnections.setValidator( + QtGui.QIntValidator(0, 8, self.lineEditMaxOutboundConnections)) self.gridLayout_9.addWidget(self.lineEditMaxOutboundConnections, 2, 2, 1, 1) self.gridLayout_4.addWidget(self.groupBox_3, 2, 0, 1, 1) self.groupBox_2 = QtGui.QGroupBox(self.tabNetworkSettings) @@ -207,7 +221,8 @@ def setupUi(self, settingsDialog): self.gridLayout_2.addWidget(self.label_6, 2, 4, 1, 1) self.lineEditSocksPassword = QtGui.QLineEdit(self.groupBox_2) self.lineEditSocksPassword.setEnabled(False) - self.lineEditSocksPassword.setInputMethodHints(QtCore.Qt.ImhHiddenText|QtCore.Qt.ImhNoAutoUppercase|QtCore.Qt.ImhNoPredictiveText) + self.lineEditSocksPassword.setInputMethodHints( + QtCore.Qt.ImhHiddenText | QtCore.Qt.ImhNoAutoUppercase | QtCore.Qt.ImhNoPredictiveText) self.lineEditSocksPassword.setEchoMode(QtGui.QLineEdit.Password) self.lineEditSocksPassword.setObjectName(_fromUtf8("lineEditSocksPassword")) self.gridLayout_2.addWidget(self.lineEditSocksPassword, 2, 5, 1, 1) @@ -215,7 +230,7 @@ def setupUi(self, settingsDialog): self.checkBoxSocksListen.setObjectName(_fromUtf8("checkBoxSocksListen")) self.gridLayout_2.addWidget(self.checkBoxSocksListen, 3, 1, 1, 4) self.comboBoxProxyType = QtGui.QComboBox(self.groupBox_2) - self.comboBoxProxyType.setObjectName(_fromUtf8("comboBoxProxyType")) + self.comboBoxProxyType.setObjectName(_fromUtf8("comboBoxProxyType")) # pylint: disable=not-callable self.comboBoxProxyType.addItem(_fromUtf8("")) self.comboBoxProxyType.addItem(_fromUtf8("")) self.comboBoxProxyType.addItem(_fromUtf8("")) @@ -229,7 +244,7 @@ def setupUi(self, settingsDialog): self.gridLayout_6 = QtGui.QGridLayout(self.tabDemandedDifficulty) self.gridLayout_6.setObjectName(_fromUtf8("gridLayout_6")) self.label_9 = QtGui.QLabel(self.tabDemandedDifficulty) - self.label_9.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) + self.label_9.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignTrailing | QtCore.Qt.AlignVCenter) self.label_9.setObjectName(_fromUtf8("label_9")) self.gridLayout_6.addWidget(self.label_9, 1, 1, 1, 1) self.label_10 = QtGui.QLabel(self.tabDemandedDifficulty) @@ -237,7 +252,7 @@ def setupUi(self, settingsDialog): self.label_10.setObjectName(_fromUtf8("label_10")) self.gridLayout_6.addWidget(self.label_10, 2, 0, 1, 3) self.label_11 = QtGui.QLabel(self.tabDemandedDifficulty) - self.label_11.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) + self.label_11.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignTrailing | QtCore.Qt.AlignVCenter) self.label_11.setObjectName(_fromUtf8("label_11")) self.gridLayout_6.addWidget(self.label_11, 3, 1, 1, 1) self.label_8 = QtGui.QLabel(self.tabDemandedDifficulty) @@ -285,7 +300,7 @@ def setupUi(self, settingsDialog): self.gridLayout_7.addItem(spacerItem6, 1, 0, 1, 1) self.label_13 = QtGui.QLabel(self.tabMaxAcceptableDifficulty) self.label_13.setLayoutDirection(QtCore.Qt.LeftToRight) - self.label_13.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) + self.label_13.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignTrailing | QtCore.Qt.AlignVCenter) self.label_13.setObjectName(_fromUtf8("label_13")) self.gridLayout_7.addWidget(self.label_13, 1, 1, 1, 1) self.lineEditMaxAcceptableTotalDifficulty = QtGui.QLineEdit(self.tabMaxAcceptableDifficulty) @@ -300,7 +315,7 @@ def setupUi(self, settingsDialog): spacerItem7 = QtGui.QSpacerItem(102, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum) self.gridLayout_7.addItem(spacerItem7, 2, 0, 1, 1) self.label_14 = QtGui.QLabel(self.tabMaxAcceptableDifficulty) - self.label_14.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) + self.label_14.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignTrailing | QtCore.Qt.AlignVCenter) self.label_14.setObjectName(_fromUtf8("label_14")) self.gridLayout_7.addWidget(self.label_14, 2, 1, 1, 1) self.lineEditMaxAcceptableSmallMessageDifficulty = QtGui.QLineEdit(self.tabMaxAcceptableDifficulty) @@ -310,7 +325,8 @@ def setupUi(self, settingsDialog): sizePolicy.setHeightForWidth(self.lineEditMaxAcceptableSmallMessageDifficulty.sizePolicy().hasHeightForWidth()) self.lineEditMaxAcceptableSmallMessageDifficulty.setSizePolicy(sizePolicy) self.lineEditMaxAcceptableSmallMessageDifficulty.setMaximumSize(QtCore.QSize(70, 16777215)) - self.lineEditMaxAcceptableSmallMessageDifficulty.setObjectName(_fromUtf8("lineEditMaxAcceptableSmallMessageDifficulty")) + self.lineEditMaxAcceptableSmallMessageDifficulty.setObjectName( + _fromUtf8("lineEditMaxAcceptableSmallMessageDifficulty")) self.gridLayout_7.addWidget(self.lineEditMaxAcceptableSmallMessageDifficulty, 2, 2, 1, 1) spacerItem8 = QtGui.QSpacerItem(20, 147, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding) self.gridLayout_7.addItem(spacerItem8, 3, 1, 1, 1) @@ -332,7 +348,7 @@ def setupUi(self, settingsDialog): self.label_16.setObjectName(_fromUtf8("label_16")) self.gridLayout_8.addWidget(self.label_16, 0, 0, 1, 3) self.label_17 = QtGui.QLabel(self.tabNamecoin) - self.label_17.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) + self.label_17.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignTrailing | QtCore.Qt.AlignVCenter) self.label_17.setObjectName(_fromUtf8("label_17")) self.gridLayout_8.addWidget(self.label_17, 2, 1, 1, 1) self.lineEditNamecoinHost = QtGui.QLineEdit(self.tabNamecoin) @@ -344,7 +360,7 @@ def setupUi(self, settingsDialog): self.gridLayout_8.addItem(spacerItem11, 4, 0, 1, 1) self.label_18 = QtGui.QLabel(self.tabNamecoin) self.label_18.setEnabled(True) - self.label_18.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) + self.label_18.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignTrailing | QtCore.Qt.AlignVCenter) self.label_18.setObjectName(_fromUtf8("label_18")) self.gridLayout_8.addWidget(self.label_18, 3, 1, 1, 1) self.lineEditNamecoinPort = QtGui.QLineEdit(self.tabNamecoin) @@ -353,7 +369,7 @@ def setupUi(self, settingsDialog): spacerItem12 = QtGui.QSpacerItem(20, 40, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding) self.gridLayout_8.addItem(spacerItem12, 8, 1, 1, 1) self.labelNamecoinUser = QtGui.QLabel(self.tabNamecoin) - self.labelNamecoinUser.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) + self.labelNamecoinUser.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignTrailing | QtCore.Qt.AlignVCenter) self.labelNamecoinUser.setObjectName(_fromUtf8("labelNamecoinUser")) self.gridLayout_8.addWidget(self.labelNamecoinUser, 4, 1, 1, 1) self.lineEditNamecoinUser = QtGui.QLineEdit(self.tabNamecoin) @@ -362,11 +378,13 @@ def setupUi(self, settingsDialog): spacerItem13 = QtGui.QSpacerItem(40, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum) self.gridLayout_8.addItem(spacerItem13, 5, 0, 1, 1) self.labelNamecoinPassword = QtGui.QLabel(self.tabNamecoin) - self.labelNamecoinPassword.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) + self.labelNamecoinPassword.setAlignment( + QtCore.Qt.AlignRight | QtCore.Qt.AlignTrailing | QtCore.Qt.AlignVCenter) self.labelNamecoinPassword.setObjectName(_fromUtf8("labelNamecoinPassword")) self.gridLayout_8.addWidget(self.labelNamecoinPassword, 5, 1, 1, 1) self.lineEditNamecoinPassword = QtGui.QLineEdit(self.tabNamecoin) - self.lineEditNamecoinPassword.setInputMethodHints(QtCore.Qt.ImhHiddenText|QtCore.Qt.ImhNoAutoUppercase|QtCore.Qt.ImhNoPredictiveText) + self.lineEditNamecoinPassword.setInputMethodHints( + QtCore.Qt.ImhHiddenText | QtCore.Qt.ImhNoAutoUppercase | QtCore.Qt.ImhNoPredictiveText) self.lineEditNamecoinPassword.setEchoMode(QtGui.QLineEdit.Password) self.lineEditNamecoinPassword.setObjectName(_fromUtf8("lineEditNamecoinPassword")) self.gridLayout_8.addWidget(self.lineEditNamecoinPassword, 5, 2, 1, 1) @@ -405,11 +423,11 @@ def setupUi(self, settingsDialog): self.widget.setObjectName(_fromUtf8("widget")) self.label_19 = QtGui.QLabel(self.widget) self.label_19.setGeometry(QtCore.QRect(10, 20, 101, 20)) - self.label_19.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) + self.label_19.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignTrailing | QtCore.Qt.AlignVCenter) self.label_19.setObjectName(_fromUtf8("label_19")) self.label_20 = QtGui.QLabel(self.widget) self.label_20.setGeometry(QtCore.QRect(30, 40, 80, 16)) - self.label_20.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) + self.label_20.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignTrailing | QtCore.Qt.AlignVCenter) self.label_20.setObjectName(_fromUtf8("label_20")) self.lineEditDays = QtGui.QLineEdit(self.widget) self.lineEditDays.setGeometry(QtCore.QRect(113, 20, 51, 20)) @@ -431,10 +449,20 @@ def setupUi(self, settingsDialog): self.retranslateUi(settingsDialog) self.tabWidgetSettings.setCurrentIndex(0) - QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(_fromUtf8("accepted()")), settingsDialog.accept) - QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(_fromUtf8("rejected()")), settingsDialog.reject) - QtCore.QObject.connect(self.checkBoxAuthentication, QtCore.SIGNAL(_fromUtf8("toggled(bool)")), self.lineEditSocksUsername.setEnabled) - QtCore.QObject.connect(self.checkBoxAuthentication, QtCore.SIGNAL(_fromUtf8("toggled(bool)")), self.lineEditSocksPassword.setEnabled) + QtCore.QObject.connect( # pylint: disable=no-member + self.buttonBox, QtCore.SIGNAL(_fromUtf8("accepted()")), settingsDialog.accept) + QtCore.QObject.connect( # pylint: disable=no-member + self.buttonBox, QtCore.SIGNAL(_fromUtf8("rejected()")), settingsDialog.reject) + QtCore.QObject.connect( # pylint: disable=no-member + self.checkBoxAuthentication, + QtCore.SIGNAL( + _fromUtf8("toggled(bool)")), + self.lineEditSocksUsername.setEnabled) + QtCore.QObject.connect( # pylint: disable=no-member + self.checkBoxAuthentication, + QtCore.SIGNAL( + _fromUtf8("toggled(bool)")), + self.lineEditSocksPassword.setEnabled) QtCore.QMetaObject.connectSlotsByName(settingsDialog) settingsDialog.setTabOrder(self.tabWidgetSettings, self.checkBoxStartOnLogon) settingsDialog.setTabOrder(self.checkBoxStartOnLogon, self.checkBoxStartInTray) @@ -450,22 +478,47 @@ def setupUi(self, settingsDialog): settingsDialog.setTabOrder(self.checkBoxSocksListen, self.buttonBox) def retranslateUi(self, settingsDialog): + """Re-translate the UI into the supported languages""" + settingsDialog.setWindowTitle(_translate("settingsDialog", "Settings", None)) self.checkBoxStartOnLogon.setText(_translate("settingsDialog", "Start Bitmessage on user login", None)) self.groupBoxTray.setTitle(_translate("settingsDialog", "Tray", None)) - self.checkBoxStartInTray.setText(_translate("settingsDialog", "Start Bitmessage in the tray (don\'t show main window)", None)) + self.checkBoxStartInTray.setText( + _translate( + "settingsDialog", + "Start Bitmessage in the tray (don\'t show main window)", + None)) self.checkBoxMinimizeToTray.setText(_translate("settingsDialog", "Minimize to tray", None)) self.checkBoxTrayOnClose.setText(_translate("settingsDialog", "Close to tray", None)) - self.checkBoxHideTrayConnectionNotifications.setText(_translate("settingsDialog", "Hide connection notifications", None)) - self.checkBoxShowTrayNotifications.setText(_translate("settingsDialog", "Show notification when message received", None)) + self.checkBoxHideTrayConnectionNotifications.setText( + _translate("settingsDialog", "Hide connection notifications", None)) + self.checkBoxShowTrayNotifications.setText( + _translate( + "settingsDialog", + "Show notification when message received", + None)) self.checkBoxPortableMode.setText(_translate("settingsDialog", "Run in Portable Mode", None)) - self.PortableModeDescription.setText(_translate("settingsDialog", "In Portable Mode, messages and config files are stored in the same directory as the program rather than the normal application-data folder. This makes it convenient to run Bitmessage from a USB thumb drive.", None)) - self.checkBoxWillinglySendToMobile.setText(_translate("settingsDialog", "Willingly include unencrypted destination address when sending to a mobile device", None)) + self.PortableModeDescription.setText( + _translate( + "settingsDialog", + "In Portable Mode, messages and config files are stored in the same directory as the" + " program rather than the normal application-data folder. This makes it convenient to" + " run Bitmessage from a USB thumb drive.", + None)) + self.checkBoxWillinglySendToMobile.setText( + _translate( + "settingsDialog", + "Willingly include unencrypted destination address when sending to a mobile device", + None)) self.checkBoxUseIdenticons.setText(_translate("settingsDialog", "Use Identicons", None)) self.checkBoxReplyBelow.setText(_translate("settingsDialog", "Reply below Quote", None)) self.groupBox.setTitle(_translate("settingsDialog", "Interface Language", None)) self.languageComboBox.setItemText(0, _translate("settingsDialog", "System Settings", "system")) - self.tabWidgetSettings.setTabText(self.tabWidgetSettings.indexOf(self.tabUserInterface), _translate("settingsDialog", "User Interface", None)) + self.tabWidgetSettings.setTabText( + self.tabWidgetSettings.indexOf( + self.tabUserInterface), + _translate( + "settingsDialog", "User Interface", None)) self.groupBox1.setTitle(_translate("settingsDialog", "Listening port", None)) self.label.setText(_translate("settingsDialog", "Listen for connections on port:", None)) self.labelUPnP.setText(_translate("settingsDialog", "UPnP:", None)) @@ -480,23 +533,70 @@ def retranslateUi(self, settingsDialog): self.checkBoxAuthentication.setText(_translate("settingsDialog", "Authentication", None)) self.label_5.setText(_translate("settingsDialog", "Username:", None)) self.label_6.setText(_translate("settingsDialog", "Pass:", None)) - self.checkBoxSocksListen.setText(_translate("settingsDialog", "Listen for incoming connections when using proxy", None)) + self.checkBoxSocksListen.setText( + _translate( + "settingsDialog", + "Listen for incoming connections when using proxy", + None)) self.comboBoxProxyType.setItemText(0, _translate("settingsDialog", "none", None)) self.comboBoxProxyType.setItemText(1, _translate("settingsDialog", "SOCKS4a", None)) self.comboBoxProxyType.setItemText(2, _translate("settingsDialog", "SOCKS5", None)) - self.tabWidgetSettings.setTabText(self.tabWidgetSettings.indexOf(self.tabNetworkSettings), _translate("settingsDialog", "Network Settings", None)) + self.tabWidgetSettings.setTabText( + self.tabWidgetSettings.indexOf( + self.tabNetworkSettings), + _translate( + "settingsDialog", "Network Settings", None)) self.label_9.setText(_translate("settingsDialog", "Total difficulty:", None)) - self.label_10.setText(_translate("settingsDialog", "The \'Total difficulty\' affects the absolute amount of work the sender must complete. Doubling this value doubles the amount of work.", None)) + self.label_10.setText( + _translate( + "settingsDialog", + "The \'Total difficulty\' affects the absolute amount of work the sender must complete." + " Doubling this value doubles the amount of work.", + None)) self.label_11.setText(_translate("settingsDialog", "Small message difficulty:", None)) - self.label_8.setText(_translate("settingsDialog", "When someone sends you a message, their computer must first complete some work. The difficulty of this work, by default, is 1. You may raise this default for new addresses you create by changing the values here. Any new addresses you create will require senders to meet the higher difficulty. There is one exception: if you add a friend or acquaintance to your address book, Bitmessage will automatically notify them when you next send a message that they need only complete the minimum amount of work: difficulty 1. ", None)) - self.label_12.setText(_translate("settingsDialog", "The \'Small message difficulty\' mostly only affects the difficulty of sending small messages. Doubling this value makes it almost twice as difficult to send a small message but doesn\'t really affect large messages.", None)) - self.tabWidgetSettings.setTabText(self.tabWidgetSettings.indexOf(self.tabDemandedDifficulty), _translate("settingsDialog", "Demanded difficulty", None)) - self.label_15.setText(_translate("settingsDialog", "Here you may set the maximum amount of work you are willing to do to send a message to another person. Setting these values to 0 means that any value is acceptable.", None)) + self.label_8.setText(_translate( + "settingsDialog", + "When someone sends you a message, their computer must first complete some work. The difficulty of this" + " work, by default, is 1. You may raise this default for new addresses you create by changing the values" + " here. Any new addresses you create will require senders to meet the higher difficulty. There is one" + " exception: if you add a friend or acquaintance to your address book, Bitmessage will automatically" + " notify them when you next send a message that they need only complete the minimum amount of" + " work: difficulty 1. ", + None)) + self.label_12.setText( + _translate( + "settingsDialog", + "The \'Small message difficulty\' mostly only affects the difficulty of sending small messages." + " Doubling this value makes it almost twice as difficult to send a small message but doesn\'t really" + " affect large messages.", + None)) + self.tabWidgetSettings.setTabText( + self.tabWidgetSettings.indexOf( + self.tabDemandedDifficulty), + _translate( + "settingsDialog", "Demanded difficulty", None)) + self.label_15.setText( + _translate( + "settingsDialog", + "Here you may set the maximum amount of work you are willing to do to send a message to another" + " person. Setting these values to 0 means that any value is acceptable.", + None)) self.label_13.setText(_translate("settingsDialog", "Maximum acceptable total difficulty:", None)) self.label_14.setText(_translate("settingsDialog", "Maximum acceptable small message difficulty:", None)) - self.tabWidgetSettings.setTabText(self.tabWidgetSettings.indexOf(self.tabMaxAcceptableDifficulty), _translate("settingsDialog", "Max acceptable difficulty", None)) + self.tabWidgetSettings.setTabText( + self.tabWidgetSettings.indexOf( + self.tabMaxAcceptableDifficulty), + _translate( + "settingsDialog", "Max acceptable difficulty", None)) self.labelOpenCL.setText(_translate("settingsDialog", "Hardware GPU acceleration (OpenCL):", None)) - self.label_16.setText(_translate("settingsDialog", " |
By default, if you send a message to someone and he is offline for more than two days, Bitmessage will send the message again after an additional two days. This will be continued with exponential backoff forever; messages will be resent after 5, 10, 20 days ect. until the receiver acknowledges them. Here you may change that behavior by having Bitmessage give up after a certain number of days or months.
Leave these input fields blank for the default behavior.
", None)) + self.tabWidgetSettings.setTabText( + self.tabWidgetSettings.indexOf( + self.tabNamecoin), + _translate( + "settingsDialog", "Namecoin integration", None)) + self.label_7.setText(_translate( + "settingsDialog", + "By default, if you send a message to someone and he is offline for more than two" + " days, Bitmessage will send the message again after an additional two days. This will be continued with" + " exponential backoff forever; messages will be resent after 5, 10, 20 days ect. until the receiver" + " acknowledges them. Here you may change that behavior by having Bitmessage give up after a certain" + " number of days or months.
Leave these input fields blank for the default behavior." + "
", + None)) self.label_19.setText(_translate("settingsDialog", "Give up after", None)) self.label_20.setText(_translate("settingsDialog", "and", None)) self.label_22.setText(_translate("settingsDialog", "days", None)) self.label_23.setText(_translate("settingsDialog", "months.", None)) - self.tabWidgetSettings.setTabText(self.tabWidgetSettings.indexOf(self.tabResendsExpire), _translate("settingsDialog", "Resends Expire", None)) - -import bitmessage_icons_rc + self.tabWidgetSettings.setTabText( + self.tabWidgetSettings.indexOf( + self.tabResendsExpire), + _translate( + "settingsDialog", "Resends Expire", None)) diff --git a/src/namecoin.py b/src/namecoin.py index 9b3c3c3ed2..7f081bc631 100644 --- a/src/namecoin.py +++ b/src/namecoin.py @@ -1,54 +1,64 @@ -# Copyright (C) 2013 by Daniel Kraft