def start(self): """Start main application""" # pylint: disable=too-many-statements,too-many-branches,too-many-locals _fixSocket() adjustHalfOpenConnectionsLimit() config = BMConfigParser() daemon = config.safeGetBoolean('bitmessagesettings', 'daemon') try: opts, _ = getopt.getopt( sys.argv[1:], "hcdt", ["help", "curses", "daemon", "test"]) except getopt.GetoptError: self.usage() sys.exit(2) for opt, _ in opts: if opt in ("-h", "--help"): self.usage() sys.exit() elif opt in ("-d", "--daemon"): daemon = True elif opt in ("-c", "--curses"): state.curses = True elif opt in ("-t", "--test"): state.testmode = True if os.path.isfile(os.path.join( state.appdata, 'unittest.lock')): daemon = True state.enableGUI = False # run without a UI # Fallback: in case when no api command was issued state.last_api_response = time.time() # Apply special settings config.set( 'bitmessagesettings', 'apienabled', 'true') config.set( 'bitmessagesettings', 'apiusername', 'username') config.set( 'bitmessagesettings', 'apipassword', 'password') config.set( 'bitmessagesettings', 'apinotifypath', os.path.join(app_dir, 'tests', 'apinotify_handler.py') ) if daemon: state.enableGUI = False # run without a UI if state.enableGUI and not state.curses and not depends.check_pyqt(): sys.exit( 'PyBitmessage requires PyQt unless you want' ' to run it as a daemon and interact with it' ' using the API. You can download PyQt from ' 'http://www.riverbankcomputing.com/software/pyqt/download' ' or by searching Google for \'PyQt Download\'.' ' If you want to run in daemon mode, see ' 'https://bitmessage.org/wiki/Daemon\n' 'You can also run PyBitmessage with' ' the new curses interface by providing' ' \'-c\' as a commandline argument.' ) # is the application already running? If yes then exit. state.thisapp = singleinstance("", daemon) if daemon: with printLock: print('Running as a daemon. Send TERM signal to end.') self.daemonize() self.setSignalHandler() set_thread_name("PyBitmessage") state.dandelion = config.safeGetInt('network', 'dandelion') # dandelion requires outbound connections, without them, # stem objects will get stuck forever if state.dandelion and not config.safeGetBoolean( 'bitmessagesettings', 'sendoutgoingconnections'): state.dandelion = 0 if state.testmode or config.safeGetBoolean( 'bitmessagesettings', 'extralowdifficulty'): defaults.networkDefaultProofOfWorkNonceTrialsPerByte = int( defaults.networkDefaultProofOfWorkNonceTrialsPerByte / 100) defaults.networkDefaultPayloadLengthExtraBytes = int( defaults.networkDefaultPayloadLengthExtraBytes / 100) readKnownNodes() # Not needed if objproc is disabled if state.enableObjProc: # Start the address generation thread addressGeneratorThread = addressGenerator() # close the main program even if there are threads left addressGeneratorThread.daemon = True addressGeneratorThread.start() # Start the thread that calculates POWs singleWorkerThread = singleWorker() # close the main program even if there are threads left singleWorkerThread.daemon = True singleWorkerThread.start() # Start the SQL thread sqlLookup = sqlThread() # DON'T close the main program even if there are threads left. # The closeEvent should command this thread to exit gracefully. sqlLookup.daemon = False sqlLookup.start() Inventory() # init # init, needs to be early because other thread may access it early Dandelion() # Enable object processor and SMTP only if objproc enabled if state.enableObjProc: # SMTP delivery thread if daemon and config.safeGet( 'bitmessagesettings', 'smtpdeliver', '') != '': from class_smtpDeliver import smtpDeliver smtpDeliveryThread = smtpDeliver() smtpDeliveryThread.start() # SMTP daemon thread if daemon and config.safeGetBoolean( 'bitmessagesettings', 'smtpd'): from class_smtpServer import smtpServer smtpServerThread = smtpServer() smtpServerThread.start() # Start the thread that calculates POWs objectProcessorThread = objectProcessor() # DON'T close the main program even the thread remains. # This thread checks the shutdown variable after processing # each object. objectProcessorThread.daemon = False objectProcessorThread.start() # Start the cleanerThread singleCleanerThread = singleCleaner() # close the main program even if there are threads left singleCleanerThread.daemon = True singleCleanerThread.start() # Not needed if objproc disabled if state.enableObjProc: shared.reloadMyAddressHashes() shared.reloadBroadcastSendersForWhichImWatching() # API is also objproc dependent if config.safeGetBoolean('bitmessagesettings', 'apienabled'): import api # pylint: disable=relative-import singleAPIThread = api.singleAPI() # close the main program even if there are threads left singleAPIThread.daemon = True singleAPIThread.start() # start network components if networking is enabled if state.enableNetwork: start_proxyconfig() BMConnectionPool().connectToStream(1) asyncoreThread = BMNetworkThread() asyncoreThread.daemon = True asyncoreThread.start() for i in range(config.getint('threads', 'receive')): receiveQueueThread = ReceiveQueueThread(i) receiveQueueThread.daemon = True receiveQueueThread.start() announceThread = AnnounceThread() announceThread.daemon = True announceThread.start() state.invThread = InvThread() state.invThread.daemon = True state.invThread.start() state.addrThread = AddrThread() state.addrThread.daemon = True state.addrThread.start() state.downloadThread = DownloadThread() state.downloadThread.daemon = True state.downloadThread.start() state.uploadThread = UploadThread() state.uploadThread.daemon = True state.uploadThread.start() if config.safeGetBoolean('bitmessagesettings', 'upnp'): import upnp upnpThread = upnp.uPnPThread() upnpThread.start() else: # Populate with hardcoded value (same as connectToStream above) state.streamsInWhichIAmParticipating.append(1) if not daemon and state.enableGUI: if state.curses: if not depends.check_curses(): sys.exit() print('Running with curses') import bitmessagecurses bitmessagecurses.runwrapper() elif state.kivy: config.remove_option('bitmessagesettings', 'dontconnect') from bitmessagekivy.mpybit import NavigateApp NavigateApp().run() else: import bitmessageqt bitmessageqt.run() else: config.remove_option('bitmessagesettings', 'dontconnect') if daemon: while state.shutdown == 0: time.sleep(1) if ( state.testmode and time.time() - state.last_api_response >= 30 ): self.stop() elif not state.enableGUI: state.enableGUI = True # pylint: disable=relative-import from tests import core as test_core test_core_result = test_core.run() state.enableGUI = True self.stop() test_core.cleanup() sys.exit( 'Core tests failed!' if test_core_result.errors or test_core_result.failures else 0 )
def start(self): _fixSocket() daemon = BMConfigParser().safeGetBoolean('bitmessagesettings', 'daemon') try: opts, args = getopt.getopt(sys.argv[1:], "hcdt", ["help", "curses", "daemon", "test"]) except getopt.GetoptError: self.usage() sys.exit(2) for opt, arg in opts: if opt in ("-h", "--help"): self.usage() sys.exit() elif opt in ("-d", "--daemon"): daemon = True state.enableGUI = False # run without a UI elif opt in ("-c", "--curses"): state.curses = True elif opt in ("-t", "--test"): state.testmode = True if os.path.isfile(os.path.join(state.appdata, 'unittest.lock')): daemon = True state.enableGUI = False # run without a UI # Fallback: in case when no api command was issued state.last_api_response = datetime.now() # Apply special settings config = BMConfigParser() config.set('bitmessagesettings', 'apienabled', 'true') config.set('bitmessagesettings', 'apiusername', 'username') config.set('bitmessagesettings', 'apipassword', 'password') config.set( 'bitmessagesettings', 'apinotifypath', os.path.join(app_dir, 'tests', 'apinotify_handler.py')) # is the application already running? If yes then exit. shared.thisapp = singleinstance("", daemon) if daemon: with shared.printLock: print('Running as a daemon. Send TERM signal to end.') self.daemonize() self.setSignalHandler() helper_threading.set_thread_name("PyBitmessage") state.dandelion = BMConfigParser().safeGetInt('network', 'dandelion') # dandelion requires outbound connections, without them, stem objects will get stuck forever if state.dandelion and not BMConfigParser().safeGetBoolean( 'bitmessagesettings', 'sendoutgoingconnections'): state.dandelion = 0 helper_bootstrap.knownNodes() # Not needed if objproc is disabled if state.enableObjProc: # Start the address generation thread addressGeneratorThread = addressGenerator() addressGeneratorThread.daemon = True # close the main program even if there are threads left addressGeneratorThread.start() # Start the thread that calculates POWs singleWorkerThread = singleWorker() singleWorkerThread.daemon = True # close the main program even if there are threads left singleWorkerThread.start() # Start the SQL thread sqlLookup = sqlThread() sqlLookup.daemon = False # DON'T close the main program even if there are threads left. The closeEvent should command this thread to exit gracefully. sqlLookup.start() Inventory() # init Dandelion( ) # init, needs to be early because other thread may access it early # Enable object processor and SMTP only if objproc enabled if state.enableObjProc: # SMTP delivery thread if daemon and BMConfigParser().safeGet("bitmessagesettings", "smtpdeliver", '') != '': smtpDeliveryThread = smtpDeliver() smtpDeliveryThread.start() # SMTP daemon thread if daemon and BMConfigParser().safeGetBoolean( "bitmessagesettings", "smtpd"): smtpServerThread = smtpServer() smtpServerThread.start() # Start the thread that calculates POWs objectProcessorThread = objectProcessor() objectProcessorThread.daemon = False # DON'T close the main program even the thread remains. This thread checks the shutdown variable after processing each object. objectProcessorThread.start() # Start the cleanerThread singleCleanerThread = singleCleaner() singleCleanerThread.daemon = True # close the main program even if there are threads left singleCleanerThread.start() # Not needed if objproc disabled if state.enableObjProc: shared.reloadMyAddressHashes() shared.reloadBroadcastSendersForWhichImWatching() # API is also objproc dependent if BMConfigParser().safeGetBoolean('bitmessagesettings', 'apienabled'): singleAPIThread = singleAPI() singleAPIThread.daemon = True # close the main program even if there are threads left singleAPIThread.start() # start network components if networking is enabled if state.enableNetwork: BMConnectionPool() asyncoreThread = BMNetworkThread() asyncoreThread.daemon = True asyncoreThread.start() for i in range(BMConfigParser().getint("threads", "receive")): receiveQueueThread = ReceiveQueueThread(i) receiveQueueThread.daemon = True receiveQueueThread.start() announceThread = AnnounceThread() announceThread.daemon = True announceThread.start() state.invThread = InvThread() state.invThread.daemon = True state.invThread.start() state.addrThread = AddrThread() state.addrThread.daemon = True state.addrThread.start() state.downloadThread = DownloadThread() state.downloadThread.daemon = True state.downloadThread.start() connectToStream(1) if BMConfigParser().safeGetBoolean('bitmessagesettings', 'upnp'): import upnp upnpThread = upnp.uPnPThread() upnpThread.start() else: # Populate with hardcoded value (same as connectToStream above) state.streamsInWhichIAmParticipating.append(1) if daemon is False and state.enableGUI: # FIXME redundant? if state.curses is False: if not depends.check_pyqt(): sys.exit( 'PyBitmessage requires PyQt unless you want' ' to run it as a daemon and interact with it' ' using the API. You can download PyQt from ' 'http://www.riverbankcomputing.com/software/pyqt/download' ' or by searching Google for \'PyQt Download\'.' ' If you want to run in daemon mode, see ' 'https://bitmessage.org/wiki/Daemon\n' 'You can also run PyBitmessage with' ' the new curses interface by providing' ' \'-c\' as a commandline argument.') import bitmessageqt bitmessageqt.run() else: if True: # if depends.check_curses(): print('Running with curses') import bitmessagecurses bitmessagecurses.runwrapper() else: BMConfigParser().remove_option('bitmessagesettings', 'dontconnect') if daemon: while state.shutdown == 0: sleep(1) if state.testmode and 30 <= \ (datetime.now() - state.last_api_response).seconds: self.stop() elif not state.enableGUI: from tests import core test_core_result = core.run() state.enableGUI = True self.stop() sys.exit('Core tests failed!' if test_core_result.errors or test_core_result.failures else 0)
def updateConfig(): """Save the config""" config = BMConfigParser() settingsversion = config.getint('bitmessagesettings', 'settingsversion') if settingsversion == 1: config.set('bitmessagesettings', 'socksproxytype', 'none') config.set('bitmessagesettings', 'sockshostname', 'localhost') config.set('bitmessagesettings', 'socksport', '9050') config.set('bitmessagesettings', 'socksauthentication', 'false') config.set('bitmessagesettings', 'socksusername', '') config.set('bitmessagesettings', 'sockspassword', '') config.set('bitmessagesettings', 'sockslisten', 'false') config.set('bitmessagesettings', 'keysencrypted', 'false') config.set('bitmessagesettings', 'messagesencrypted', 'false') settingsversion = 2 # let class_sqlThread update SQL and continue elif settingsversion == 4: config.set('bitmessagesettings', 'defaultnoncetrialsperbyte', str(defaults.networkDefaultProofOfWorkNonceTrialsPerByte)) config.set('bitmessagesettings', 'defaultpayloadlengthextrabytes', str(defaults.networkDefaultPayloadLengthExtraBytes)) settingsversion = 5 if settingsversion == 5: config.set('bitmessagesettings', 'maxacceptablenoncetrialsperbyte', '0') config.set('bitmessagesettings', 'maxacceptablepayloadlengthextrabytes', '0') settingsversion = 7 if not config.has_option('bitmessagesettings', 'sockslisten'): config.set('bitmessagesettings', 'sockslisten', 'false') if not config.has_option('bitmessagesettings', 'userlocale'): config.set('bitmessagesettings', 'userlocale', 'system') if not config.has_option('bitmessagesettings', 'sendoutgoingconnections'): config.set('bitmessagesettings', 'sendoutgoingconnections', 'True') if not config.has_option('bitmessagesettings', 'useidenticons'): config.set('bitmessagesettings', 'useidenticons', 'True') if not config.has_option('bitmessagesettings', 'identiconsuffix'): # acts as a salt config.set('bitmessagesettings', 'identiconsuffix', ''.join( helper_random.randomchoice( "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz") for x in range(12) )) # a twelve character pseudo-password to salt the identicons # Add settings to support no longer resending messages after # a certain period of time even if we never get an ack if settingsversion == 7: config.set('bitmessagesettings', 'stopresendingafterxdays', '') config.set('bitmessagesettings', 'stopresendingafterxmonths', '') settingsversion = 8 # With the change to protocol version 3, reset the user-settable # difficulties to 1 if settingsversion == 8: config.set('bitmessagesettings', 'defaultnoncetrialsperbyte', str(defaults.networkDefaultProofOfWorkNonceTrialsPerByte)) config.set('bitmessagesettings', 'defaultpayloadlengthextrabytes', str(defaults.networkDefaultPayloadLengthExtraBytes)) previousTotalDifficulty = int( config.getint('bitmessagesettings', 'maxacceptablenoncetrialsperbyte')) / 320 previousSmallMessageDifficulty = int( config.getint('bitmessagesettings', 'maxacceptablepayloadlengthextrabytes')) / 14000 config.set('bitmessagesettings', 'maxacceptablenoncetrialsperbyte', str(previousTotalDifficulty * 1000)) config.set('bitmessagesettings', 'maxacceptablepayloadlengthextrabytes', str(previousSmallMessageDifficulty * 1000)) settingsversion = 9 # Adjust the required POW values for each of this user's addresses # to conform to protocol v3 norms. if settingsversion == 9: for addressInKeysFile in config.addresses(): try: previousTotalDifficulty = float( config.getint(addressInKeysFile, 'noncetrialsperbyte')) / 320 previousSmallMessageDifficulty = float( config.getint(addressInKeysFile, 'payloadlengthextrabytes')) / 14000 if previousTotalDifficulty <= 2: previousTotalDifficulty = 1 if previousSmallMessageDifficulty < 1: previousSmallMessageDifficulty = 1 config.set(addressInKeysFile, 'noncetrialsperbyte', str(int(previousTotalDifficulty * 1000))) config.set(addressInKeysFile, 'payloadlengthextrabytes', str(int(previousSmallMessageDifficulty * 1000))) except Exception: continue config.set('bitmessagesettings', 'maxdownloadrate', '0') config.set('bitmessagesettings', 'maxuploadrate', '0') settingsversion = 10 # sanity check if config.safeGetInt('bitmessagesettings', 'maxacceptablenoncetrialsperbyte') == 0: config.set( 'bitmessagesettings', 'maxacceptablenoncetrialsperbyte', str(defaults.ridiculousDifficulty * defaults.networkDefaultProofOfWorkNonceTrialsPerByte)) if config.safeGetInt('bitmessagesettings', 'maxacceptablepayloadlengthextrabytes') == 0: config.set( 'bitmessagesettings', 'maxacceptablepayloadlengthextrabytes', str(defaults.ridiculousDifficulty * defaults.networkDefaultPayloadLengthExtraBytes)) if not config.has_option('bitmessagesettings', 'onionhostname'): config.set('bitmessagesettings', 'onionhostname', '') if not config.has_option('bitmessagesettings', 'onionport'): config.set('bitmessagesettings', 'onionport', '8444') if not config.has_option('bitmessagesettings', 'onionbindip'): config.set('bitmessagesettings', 'onionbindip', '127.0.0.1') if not config.has_option('bitmessagesettings', 'smtpdeliver'): config.set('bitmessagesettings', 'smtpdeliver', '') if not config.has_option('bitmessagesettings', 'hidetrayconnectionnotifications'): config.set('bitmessagesettings', 'hidetrayconnectionnotifications', 'false') if config.safeGetInt('bitmessagesettings', 'maxoutboundconnections') < 1: config.set('bitmessagesettings', 'maxoutboundconnections', '8') print('WARNING: your maximum outbound connections must be a number.') # TTL is now user-specifiable. Let's add an option to save # whatever the user selects. if not config.has_option('bitmessagesettings', 'ttl'): config.set('bitmessagesettings', 'ttl', '367200') config.set('bitmessagesettings', 'settingsversion', str(settingsversion)) config.save()
def loadConfig(): """Load the config""" config = BMConfigParser() if state.appdata: config.read(state.appdata + 'keys.dat') # state.appdata must have been specified as a startup option. needToCreateKeysFile = config.safeGet('bitmessagesettings', 'settingsversion') is None if not needToCreateKeysFile: print('Loading config files from directory specified' ' on startup: %s' % state.appdata) else: config.read(paths.lookupExeFolder() + 'keys.dat') try: config.get('bitmessagesettings', 'settingsversion') print('Loading config files from same directory as program.') needToCreateKeysFile = False state.appdata = paths.lookupExeFolder() except: # Could not load the keys.dat file in the program directory. # Perhaps it is in the appdata directory. state.appdata = paths.lookupAppdataFolder() config.read(state.appdata + 'keys.dat') needToCreateKeysFile = config.safeGet('bitmessagesettings', 'settingsversion') is None if not needToCreateKeysFile: print('Loading existing config files from', state.appdata) if needToCreateKeysFile: # This appears to be the first time running the program; there is # no config file (or it cannot be accessed). Create config file. config.add_section('bitmessagesettings') config.set('bitmessagesettings', 'settingsversion', '10') config.set('bitmessagesettings', 'port', '8444') config.set('bitmessagesettings', 'timeformat', '%%c') config.set('bitmessagesettings', 'blackwhitelist', 'black') config.set('bitmessagesettings', 'startonlogon', 'false') if 'linux' in sys.platform: config.set('bitmessagesettings', 'minimizetotray', 'false') # This isn't implimented yet and when True on # Ubuntu causes Bitmessage to disappear while # running when minimized. else: config.set('bitmessagesettings', 'minimizetotray', 'true') config.set('bitmessagesettings', 'showtraynotifications', 'true') config.set('bitmessagesettings', 'startintray', 'false') config.set('bitmessagesettings', 'socksproxytype', 'none') config.set('bitmessagesettings', 'sockshostname', 'localhost') config.set('bitmessagesettings', 'socksport', '9050') config.set('bitmessagesettings', 'socksauthentication', 'false') config.set('bitmessagesettings', 'socksusername', '') config.set('bitmessagesettings', 'sockspassword', '') config.set('bitmessagesettings', 'keysencrypted', 'false') config.set('bitmessagesettings', 'messagesencrypted', 'false') config.set('bitmessagesettings', 'defaultnoncetrialsperbyte', str(defaults.networkDefaultProofOfWorkNonceTrialsPerByte)) config.set('bitmessagesettings', 'defaultpayloadlengthextrabytes', str(defaults.networkDefaultPayloadLengthExtraBytes)) config.set('bitmessagesettings', 'minimizeonclose', 'false') config.set('bitmessagesettings', 'dontconnect', 'true') config.set('bitmessagesettings', 'replybelow', 'False') config.set('bitmessagesettings', 'maxdownloadrate', '0') config.set('bitmessagesettings', 'maxuploadrate', '0') # UI setting to stop trying to send messages after X days/months config.set('bitmessagesettings', 'stopresendingafterxdays', '') config.set('bitmessagesettings', 'stopresendingafterxmonths', '') # Are you hoping to add a new option to the keys.dat file? You're in # the right place for adding it to users who install the software for # the first time. But you must also add it to the keys.dat file of # existing users. To do that, search the class_sqlThread.py file # for the text: "right above this line!" if StoreConfigFilesInSameDirectoryAsProgramByDefault: # Just use the same directory as the program and forget about # the appdata folder state.appdata = '' print('Creating new config files in same directory as program.') else: print('Creating new config files in', state.appdata) if not os.path.exists(state.appdata): os.makedirs(state.appdata) if not sys.platform.startswith('win'): os.umask(0o077) config.save() else: updateConfig() _loadTrustedPeer()
class SettingsDialog(QtGui.QDialog): """The "Settings" dialog""" def __init__(self, parent=None, firstrun=False): super(SettingsDialog, self).__init__(parent) widgets.load('settings.ui', self) self.parent = parent self.firstrun = firstrun self.config = BMConfigParser() self.net_restart_needed = False self.timer = QtCore.QTimer() try: import pkg_resources except ImportError: pass else: # Append proxy types defined in plugins for ep in pkg_resources.iter_entry_points( 'bitmessage.proxyconfig'): self.comboBoxProxyType.addItem(ep.name) self.lineEditMaxOutboundConnections.setValidator( QtGui.QIntValidator(0, 8, self.lineEditMaxOutboundConnections)) self.adjust_from_config(self.config) if firstrun: # switch to "Network Settings" tab if user selected # "Let me configure special network settings first" on first run self.tabWidgetSettings.setCurrentIndex( self.tabWidgetSettings.indexOf(self.tabNetworkSettings)) QtGui.QWidget.resize(self, QtGui.QWidget.sizeHint(self)) def adjust_from_config(self, config): """Adjust all widgets state according to config settings""" # pylint: disable=too-many-branches,too-many-statements if not self.parent.tray.isSystemTrayAvailable(): self.groupBoxTray.setEnabled(False) self.groupBoxTray.setTitle( _translate("MainWindow", "Tray (not available in your system)")) for setting in ('minimizetotray', 'trayonclose', 'startintray'): config.set('bitmessagesettings', setting, 'false') else: self.checkBoxMinimizeToTray.setChecked( config.getboolean('bitmessagesettings', 'minimizetotray')) self.checkBoxTrayOnClose.setChecked( config.safeGetBoolean('bitmessagesettings', 'trayonclose')) self.checkBoxStartInTray.setChecked( config.getboolean('bitmessagesettings', 'startintray')) self.checkBoxHideTrayConnectionNotifications.setChecked( config.getboolean('bitmessagesettings', 'hidetrayconnectionnotifications')) self.checkBoxShowTrayNotifications.setChecked( config.getboolean('bitmessagesettings', 'showtraynotifications')) self.checkBoxStartOnLogon.setChecked( config.getboolean('bitmessagesettings', 'startonlogon')) self.checkBoxWillinglySendToMobile.setChecked( config.safeGetBoolean('bitmessagesettings', 'willinglysendtomobile')) self.checkBoxUseIdenticons.setChecked( config.safeGetBoolean('bitmessagesettings', 'useidenticons')) self.checkBoxReplyBelow.setChecked( config.safeGetBoolean('bitmessagesettings', 'replybelow')) if state.appdata == paths.lookupExeFolder(): self.checkBoxPortableMode.setChecked(True) else: try: tempfile.NamedTemporaryFile( dir=paths.lookupExeFolder(), delete=True).close() # should autodelete except Exception: self.checkBoxPortableMode.setDisabled(True) if 'darwin' in sys.platform: self.checkBoxStartOnLogon.setDisabled(True) self.checkBoxStartOnLogon.setText( _translate("MainWindow", "Start-on-login not yet supported on your OS.")) self.checkBoxMinimizeToTray.setDisabled(True) self.checkBoxMinimizeToTray.setText( _translate("MainWindow", "Minimize-to-tray not yet supported on your OS.")) self.checkBoxShowTrayNotifications.setDisabled(True) self.checkBoxShowTrayNotifications.setText( _translate("MainWindow", "Tray notifications not yet supported on your OS.")) elif 'linux' in sys.platform: self.checkBoxStartOnLogon.setDisabled(True) self.checkBoxStartOnLogon.setText( _translate("MainWindow", "Start-on-login not yet supported on your OS.")) # On the Network settings tab: self.lineEditTCPPort.setText( str(config.get('bitmessagesettings', 'port'))) self.checkBoxUPnP.setChecked( config.safeGetBoolean('bitmessagesettings', 'upnp')) self.checkBoxAuthentication.setChecked( config.getboolean('bitmessagesettings', 'socksauthentication')) self.checkBoxSocksListen.setChecked( config.getboolean('bitmessagesettings', 'sockslisten')) self.checkBoxOnionOnly.setChecked( config.safeGetBoolean('bitmessagesettings', 'onionservicesonly')) self._proxy_type = getSOCKSProxyType(config) self.comboBoxProxyType.setCurrentIndex( 0 if not self._proxy_type else self.comboBoxProxyType. findText(self._proxy_type)) self.comboBoxProxyTypeChanged(self.comboBoxProxyType.currentIndex()) self.lineEditSocksHostname.setText( config.get('bitmessagesettings', 'sockshostname')) self.lineEditSocksPort.setText( str(config.get('bitmessagesettings', 'socksport'))) self.lineEditSocksUsername.setText( config.get('bitmessagesettings', 'socksusername')) self.lineEditSocksPassword.setText( config.get('bitmessagesettings', 'sockspassword')) self.lineEditMaxDownloadRate.setText( str(config.get('bitmessagesettings', 'maxdownloadrate'))) self.lineEditMaxUploadRate.setText( str(config.get('bitmessagesettings', 'maxuploadrate'))) self.lineEditMaxOutboundConnections.setText( str(config.get('bitmessagesettings', 'maxoutboundconnections'))) # Demanded difficulty tab self.lineEditTotalDifficulty.setText( str((float( config.getint('bitmessagesettings', 'defaultnoncetrialsperbyte')) / defaults.networkDefaultProofOfWorkNonceTrialsPerByte))) self.lineEditSmallMessageDifficulty.setText( str((float( config.getint('bitmessagesettings', 'defaultpayloadlengthextrabytes')) / defaults.networkDefaultPayloadLengthExtraBytes))) # Max acceptable difficulty tab self.lineEditMaxAcceptableTotalDifficulty.setText( str((float( config.getint('bitmessagesettings', 'maxacceptablenoncetrialsperbyte')) / defaults.networkDefaultProofOfWorkNonceTrialsPerByte))) self.lineEditMaxAcceptableSmallMessageDifficulty.setText( str((float( config.getint('bitmessagesettings', 'maxacceptablepayloadlengthextrabytes')) / defaults.networkDefaultPayloadLengthExtraBytes))) # OpenCL self.comboBoxOpenCL.setEnabled(openclpow.openclAvailable()) self.comboBoxOpenCL.clear() self.comboBoxOpenCL.addItem("None") self.comboBoxOpenCL.addItems(openclpow.vendors) self.comboBoxOpenCL.setCurrentIndex(0) for i in range(self.comboBoxOpenCL.count()): if self.comboBoxOpenCL.itemText(i) == config.safeGet( 'bitmessagesettings', 'opencl'): self.comboBoxOpenCL.setCurrentIndex(i) break # Namecoin integration tab nmctype = config.get('bitmessagesettings', 'namecoinrpctype') self.lineEditNamecoinHost.setText( config.get('bitmessagesettings', 'namecoinrpchost')) self.lineEditNamecoinPort.setText( str(config.get('bitmessagesettings', 'namecoinrpcport'))) self.lineEditNamecoinUser.setText( config.get('bitmessagesettings', 'namecoinrpcuser')) self.lineEditNamecoinPassword.setText( config.get('bitmessagesettings', 'namecoinrpcpassword')) if nmctype == "namecoind": self.radioButtonNamecoinNamecoind.setChecked(True) elif nmctype == "nmcontrol": self.radioButtonNamecoinNmcontrol.setChecked(True) self.lineEditNamecoinUser.setEnabled(False) self.labelNamecoinUser.setEnabled(False) self.lineEditNamecoinPassword.setEnabled(False) self.labelNamecoinPassword.setEnabled(False) else: assert False # Message Resend tab self.lineEditDays.setText( str(config.get('bitmessagesettings', 'stopresendingafterxdays'))) self.lineEditMonths.setText( str(config.get('bitmessagesettings', 'stopresendingafterxmonths'))) def comboBoxProxyTypeChanged(self, comboBoxIndex): """A callback for currentIndexChanged event of comboBoxProxyType""" if comboBoxIndex == 0: self.lineEditSocksHostname.setEnabled(False) self.lineEditSocksPort.setEnabled(False) self.lineEditSocksUsername.setEnabled(False) self.lineEditSocksPassword.setEnabled(False) self.checkBoxAuthentication.setEnabled(False) self.checkBoxSocksListen.setEnabled(False) self.checkBoxOnionOnly.setEnabled(False) else: self.lineEditSocksHostname.setEnabled(True) self.lineEditSocksPort.setEnabled(True) self.checkBoxAuthentication.setEnabled(True) self.checkBoxSocksListen.setEnabled(True) self.checkBoxOnionOnly.setEnabled(True) if self.checkBoxAuthentication.isChecked(): self.lineEditSocksUsername.setEnabled(True) self.lineEditSocksPassword.setEnabled(True) def getNamecoinType(self): """ Check status of namecoin integration radio buttons and translate it to a string as in the options. """ if self.radioButtonNamecoinNamecoind.isChecked(): return "namecoind" if self.radioButtonNamecoinNmcontrol.isChecked(): return "nmcontrol" assert False # Namecoin connection type was changed. def namecoinTypeChanged(self, checked): # pylint: disable=unused-argument """A callback for toggled event of radioButtonNamecoinNamecoind""" nmctype = self.getNamecoinType() assert nmctype == "namecoind" or nmctype == "nmcontrol" isNamecoind = (nmctype == "namecoind") self.lineEditNamecoinUser.setEnabled(isNamecoind) self.labelNamecoinUser.setEnabled(isNamecoind) self.lineEditNamecoinPassword.setEnabled(isNamecoind) self.labelNamecoinPassword.setEnabled(isNamecoind) if isNamecoind: self.lineEditNamecoinPort.setText(defaults.namecoinDefaultRpcPort) else: self.lineEditNamecoinPort.setText("9000") def click_pushButtonNamecoinTest(self): """Test the namecoin settings specified in the settings dialog.""" self.labelNamecoinTestResult.setText( _translate("MainWindow", "Testing...")) nc = namecoin.namecoinConnection({ 'type': self.getNamecoinType(), 'host': str(self.lineEditNamecoinHost.text().toUtf8()), 'port': str(self.lineEditNamecoinPort.text().toUtf8()), 'user': str(self.lineEditNamecoinUser.text().toUtf8()), 'password': str(self.lineEditNamecoinPassword.text().toUtf8()) }) status, text = nc.test() self.labelNamecoinTestResult.setText(text) if status == 'success': self.parent.namecoin = nc def accept(self): """A callback for accepted event of buttonBox (OK button pressed)""" # pylint: disable=too-many-branches,too-many-statements super(SettingsDialog, self).accept() if self.firstrun: self.config.remove_option('bitmessagesettings', 'dontconnect') self.config.set('bitmessagesettings', 'startonlogon', str(self.checkBoxStartOnLogon.isChecked())) self.config.set('bitmessagesettings', 'minimizetotray', str(self.checkBoxMinimizeToTray.isChecked())) self.config.set('bitmessagesettings', 'trayonclose', str(self.checkBoxTrayOnClose.isChecked())) self.config.set( 'bitmessagesettings', 'hidetrayconnectionnotifications', str(self.checkBoxHideTrayConnectionNotifications.isChecked())) self.config.set('bitmessagesettings', 'showtraynotifications', str(self.checkBoxShowTrayNotifications.isChecked())) self.config.set('bitmessagesettings', 'startintray', str(self.checkBoxStartInTray.isChecked())) self.config.set('bitmessagesettings', 'willinglysendtomobile', str(self.checkBoxWillinglySendToMobile.isChecked())) self.config.set('bitmessagesettings', 'useidenticons', str(self.checkBoxUseIdenticons.isChecked())) self.config.set('bitmessagesettings', 'replybelow', str(self.checkBoxReplyBelow.isChecked())) lang = str( self.languageComboBox.itemData( self.languageComboBox.currentIndex()).toString()) self.config.set('bitmessagesettings', 'userlocale', lang) self.parent.change_translation() if int(self.config.get('bitmessagesettings', 'port')) != int( self.lineEditTCPPort.text()): self.config.set('bitmessagesettings', 'port', str(self.lineEditTCPPort.text())) if not self.config.safeGetBoolean('bitmessagesettings', 'dontconnect'): self.net_restart_needed = True if self.checkBoxUPnP.isChecked() != self.config.safeGetBoolean( 'bitmessagesettings', 'upnp'): self.config.set('bitmessagesettings', 'upnp', str(self.checkBoxUPnP.isChecked())) if self.checkBoxUPnP.isChecked(): import upnp upnpThread = upnp.uPnPThread() upnpThread.start() proxytype_index = self.comboBoxProxyType.currentIndex() if proxytype_index == 0: if self._proxy_type and state.statusIconColor != 'red': self.net_restart_needed = True elif self.comboBoxProxyType.currentText() != self._proxy_type: self.net_restart_needed = True self.parent.statusbar.clearMessage() self.config.set( 'bitmessagesettings', 'socksproxytype', 'none' if self.comboBoxProxyType.currentIndex() == 0 else str( self.comboBoxProxyType.currentText())) if proxytype_index > 2: # last literal proxytype in ui start_proxyconfig() self.config.set('bitmessagesettings', 'socksauthentication', str(self.checkBoxAuthentication.isChecked())) self.config.set('bitmessagesettings', 'sockshostname', str(self.lineEditSocksHostname.text())) self.config.set('bitmessagesettings', 'socksport', str(self.lineEditSocksPort.text())) self.config.set('bitmessagesettings', 'socksusername', str(self.lineEditSocksUsername.text())) self.config.set('bitmessagesettings', 'sockspassword', str(self.lineEditSocksPassword.text())) self.config.set('bitmessagesettings', 'sockslisten', str(self.checkBoxSocksListen.isChecked())) if self.checkBoxOnionOnly.isChecked() \ and not self.config.safeGetBoolean('bitmessagesettings', 'onionservicesonly'): self.net_restart_needed = True self.config.set('bitmessagesettings', 'onionservicesonly', str(self.checkBoxOnionOnly.isChecked())) try: # Rounding to integers just for aesthetics self.config.set( 'bitmessagesettings', 'maxdownloadrate', str(int(float(self.lineEditMaxDownloadRate.text())))) self.config.set('bitmessagesettings', 'maxuploadrate', str(int(float(self.lineEditMaxUploadRate.text())))) except ValueError: QtGui.QMessageBox.about( self, _translate("MainWindow", "Number needed"), _translate( "MainWindow", "Your maximum download and upload rate must be numbers." " Ignoring what you typed.")) else: set_rates( self.config.safeGetInt('bitmessagesettings', 'maxdownloadrate'), self.config.safeGetInt('bitmessagesettings', 'maxuploadrate')) self.config.set( 'bitmessagesettings', 'maxoutboundconnections', str(int(float(self.lineEditMaxOutboundConnections.text())))) self.config.set('bitmessagesettings', 'namecoinrpctype', self.getNamecoinType()) self.config.set('bitmessagesettings', 'namecoinrpchost', str(self.lineEditNamecoinHost.text())) self.config.set('bitmessagesettings', 'namecoinrpcport', str(self.lineEditNamecoinPort.text())) self.config.set('bitmessagesettings', 'namecoinrpcuser', str(self.lineEditNamecoinUser.text())) self.config.set('bitmessagesettings', 'namecoinrpcpassword', str(self.lineEditNamecoinPassword.text())) self.parent.resetNamecoinConnection() # Demanded difficulty tab if float(self.lineEditTotalDifficulty.text()) >= 1: self.config.set( 'bitmessagesettings', 'defaultnoncetrialsperbyte', str( int( float(self.lineEditTotalDifficulty.text()) * defaults.networkDefaultProofOfWorkNonceTrialsPerByte))) if float(self.lineEditSmallMessageDifficulty.text()) >= 1: self.config.set( 'bitmessagesettings', 'defaultpayloadlengthextrabytes', str( int( float(self.lineEditSmallMessageDifficulty.text()) * defaults.networkDefaultPayloadLengthExtraBytes))) if self.comboBoxOpenCL.currentText().toUtf8() != self.config.safeGet( 'bitmessagesettings', 'opencl'): self.config.set('bitmessagesettings', 'opencl', str(self.comboBoxOpenCL.currentText())) queues.workerQueue.put(('resetPoW', '')) acceptableDifficultyChanged = False if (float(self.lineEditMaxAcceptableTotalDifficulty.text()) >= 1 or float(self.lineEditMaxAcceptableTotalDifficulty.text()) == 0): if self.config.get( 'bitmessagesettings', 'maxacceptablenoncetrialsperbyte' ) != str( int( float( self.lineEditMaxAcceptableTotalDifficulty.text()) * defaults.networkDefaultProofOfWorkNonceTrialsPerByte)): # the user changed the max acceptable total difficulty acceptableDifficultyChanged = True self.config.set( 'bitmessagesettings', 'maxacceptablenoncetrialsperbyte', str( int( float(self.lineEditMaxAcceptableTotalDifficulty. text()) * defaults. networkDefaultProofOfWorkNonceTrialsPerByte))) if (float(self.lineEditMaxAcceptableSmallMessageDifficulty.text()) >= 1 or float( self.lineEditMaxAcceptableSmallMessageDifficulty.text()) == 0): if self.config.get( 'bitmessagesettings', 'maxacceptablepayloadlengthextrabytes' ) != str( int( float(self.lineEditMaxAcceptableSmallMessageDifficulty. text()) * defaults.networkDefaultPayloadLengthExtraBytes)): # the user changed the max acceptable small message difficulty acceptableDifficultyChanged = True self.config.set( 'bitmessagesettings', 'maxacceptablepayloadlengthextrabytes', str( int( float(self. lineEditMaxAcceptableSmallMessageDifficulty. text()) * defaults.networkDefaultPayloadLengthExtraBytes))) if acceptableDifficultyChanged: # It might now be possible to send msgs which were previously # marked as toodifficult. Let us change them to 'msgqueued'. # The singleWorker will try to send them and will again mark # them as toodifficult if the receiver's required difficulty # is still higher than we are willing to do. sqlExecute("UPDATE sent SET status='msgqueued'" " WHERE status='toodifficult'") queues.workerQueue.put(('sendmessage', '')) stopResendingDefaults = False # UI setting to stop trying to send messages after X days/months # I'm open to changing this UI to something else if someone has a better idea. if self.lineEditDays.text() == '' and self.lineEditMonths.text() == '': # We need to handle this special case. Bitmessage has its # default behavior. The input is blank/blank self.config.set('bitmessagesettings', 'stopresendingafterxdays', '') self.config.set('bitmessagesettings', 'stopresendingafterxmonths', '') state.maximumLengthOfTimeToBotherResendingMessages = float('inf') stopResendingDefaults = True try: days = float(self.lineEditDays.text()) except ValueError: self.lineEditDays.setText("0") days = 0.0 try: months = float(self.lineEditMonths.text()) except ValueError: self.lineEditMonths.setText("0") months = 0.0 if days >= 0 and months >= 0 and not stopResendingDefaults: state.maximumLengthOfTimeToBotherResendingMessages = \ days * 24 * 60 * 60 + months * 60 * 60 * 24 * 365 / 12 if state.maximumLengthOfTimeToBotherResendingMessages < 432000: # If the time period is less than 5 hours, we give # zero values to all fields. No message will be sent again. QtGui.QMessageBox.about( self, _translate("MainWindow", "Will not resend ever"), _translate( "MainWindow", "Note that the time limit you entered is less" " than the amount of time Bitmessage waits for" " the first resend attempt therefore your" " messages will never be resent.")) self.config.set('bitmessagesettings', 'stopresendingafterxdays', '0') self.config.set('bitmessagesettings', 'stopresendingafterxmonths', '0') state.maximumLengthOfTimeToBotherResendingMessages = 0.0 else: self.config.set('bitmessagesettings', 'stopresendingafterxdays', str(days)) self.config.set('bitmessagesettings', 'stopresendingafterxmonths', str(months)) self.config.save() if self.net_restart_needed: self.net_restart_needed = False self.config.setTemp('bitmessagesettings', 'dontconnect', 'true') self.timer.singleShot( 5000, lambda: self.config.setTemp('bitmessagesettings', 'dontconnect', 'false')) self.parent.updateStartOnLogon() if (state.appdata != paths.lookupExeFolder() and self.checkBoxPortableMode.isChecked()): # If we are NOT using portable mode now but the user selected # that we should... # Write the keys.dat file to disk in the new location sqlStoredProcedure('movemessagstoprog') with open(paths.lookupExeFolder() + 'keys.dat', 'wb') as configfile: self.config.write(configfile) # Write the knownnodes.dat file to disk in the new location knownnodes.saveKnownNodes(paths.lookupExeFolder()) os.remove(state.appdata + 'keys.dat') os.remove(state.appdata + 'knownnodes.dat') previousAppdataLocation = state.appdata state.appdata = paths.lookupExeFolder() debug.resetLogging() try: os.remove(previousAppdataLocation + 'debug.log') os.remove(previousAppdataLocation + 'debug.log.1') except Exception: pass if (state.appdata == paths.lookupExeFolder() and not self.checkBoxPortableMode.isChecked()): # If we ARE using portable mode now but the user selected # that we shouldn't... state.appdata = paths.lookupAppdataFolder() if not os.path.exists(state.appdata): os.makedirs(state.appdata) sqlStoredProcedure('movemessagstoappdata') # Write the keys.dat file to disk in the new location self.config.save() # Write the knownnodes.dat file to disk in the new location knownnodes.saveKnownNodes(state.appdata) os.remove(paths.lookupExeFolder() + 'keys.dat') os.remove(paths.lookupExeFolder() + 'knownnodes.dat') debug.resetLogging() try: os.remove(paths.lookupExeFolder() + 'debug.log') os.remove(paths.lookupExeFolder() + 'debug.log.1') except Exception: pass