settings.py
1 """ 2 This module setting file is for settings 3 """ 4 import configparser 5 import os 6 import sys 7 import tempfile 8 9 import six 10 from PyQt4 import QtCore, QtGui 11 12 import debug 13 import defaults 14 import namecoin 15 import openclpow 16 import paths 17 import queues 18 import state 19 from . import widgets 20 from bmconfigparser import config as config_obj 21 from helper_sql import sqlExecute, sqlStoredProcedure 22 from helper_startup import start_proxyconfig 23 from network import connectionpool, knownnodes 24 from network.announcethread import AnnounceThread 25 from network.asyncore_pollchoose import set_rates 26 from tr import _translate 27 28 29 def getSOCKSProxyType(config): 30 """Get user socksproxytype setting from *config*""" 31 try: 32 result = configparser.SafeConfigParser.get( 33 config, 'bitmessagesettings', 'socksproxytype') 34 except (configparser.NoSectionError, configparser.NoOptionError): 35 return None 36 else: 37 if result.lower() in ('', 'none', 'false'): 38 result = None 39 return result 40 41 42 class SettingsDialog(QtGui.QDialog): 43 """The "Settings" dialog""" 44 # pylint: disable=too-many-instance-attributes 45 def __init__(self, parent=None, firstrun=False): 46 super(SettingsDialog, self).__init__(parent) 47 widgets.load('settings.ui', self) 48 49 self.app = QtGui.QApplication.instance() 50 self.parent = parent 51 self.firstrun = firstrun 52 self.config = config_obj 53 self.net_restart_needed = False 54 self.font_setting = None 55 self.timer = QtCore.QTimer() 56 57 if self.config.safeGetBoolean('bitmessagesettings', 'dontconnect'): 58 self.firstrun = False 59 try: 60 import pkg_resources 61 except ImportError: 62 pass 63 else: 64 # Append proxy types defined in plugins 65 # FIXME: this should be a function in mod:`plugin` 66 for ep in pkg_resources.iter_entry_points( 67 'bitmessage.proxyconfig'): 68 try: 69 ep.load() 70 except Exception: # it should add only functional plugins 71 # many possible exceptions, which are don't matter 72 pass 73 else: 74 self.comboBoxProxyType.addItem(ep.name) 75 76 self.lineEditMaxOutboundConnections.setValidator( 77 QtGui.QIntValidator(0, 8, self.lineEditMaxOutboundConnections)) 78 79 self.adjust_from_config(self.config) 80 if firstrun: 81 # switch to "Network Settings" tab if user selected 82 # "Let me configure special network settings first" on first run 83 self.tabWidgetSettings.setCurrentIndex( 84 self.tabWidgetSettings.indexOf(self.tabNetworkSettings) 85 ) 86 QtGui.QWidget.resize(self, QtGui.QWidget.sizeHint(self)) 87 88 def adjust_from_config(self, config): 89 """Adjust all widgets state according to config settings""" 90 # pylint: disable=too-many-branches,too-many-statements 91 92 current_style = self.app.get_windowstyle() 93 for i, sk in enumerate(QtGui.QStyleFactory.keys()): 94 self.comboBoxStyle.addItem(sk) 95 if sk == current_style: 96 self.comboBoxStyle.setCurrentIndex(i) 97 98 self.save_font_setting(self.app.font()) 99 100 if not self.parent.tray.isSystemTrayAvailable(): 101 self.groupBoxTray.setEnabled(False) 102 self.groupBoxTray.setTitle(_translate( 103 "MainWindow", "Tray (not available in your system)")) 104 for setting in ( 105 'minimizetotray', 'trayonclose', 'startintray'): 106 config.set('bitmessagesettings', setting, 'false') 107 else: 108 self.checkBoxMinimizeToTray.setChecked( 109 config.getboolean('bitmessagesettings', 'minimizetotray')) 110 self.checkBoxTrayOnClose.setChecked( 111 config.safeGetBoolean('bitmessagesettings', 'trayonclose')) 112 self.checkBoxStartInTray.setChecked( 113 config.getboolean('bitmessagesettings', 'startintray')) 114 115 self.checkBoxHideTrayConnectionNotifications.setChecked( 116 config.getboolean( 117 'bitmessagesettings', 'hidetrayconnectionnotifications')) 118 self.checkBoxShowTrayNotifications.setChecked( 119 config.getboolean('bitmessagesettings', 'showtraynotifications')) 120 121 self.checkBoxStartOnLogon.setChecked( 122 config.getboolean('bitmessagesettings', 'startonlogon')) 123 124 self.checkBoxWillinglySendToMobile.setChecked( 125 config.safeGetBoolean( 126 'bitmessagesettings', 'willinglysendtomobile')) 127 self.checkBoxUseIdenticons.setChecked( 128 config.safeGetBoolean('bitmessagesettings', 'useidenticons')) 129 self.checkBoxReplyBelow.setChecked( 130 config.safeGetBoolean('bitmessagesettings', 'replybelow')) 131 132 if state.appdata == paths.lookupExeFolder(): 133 self.checkBoxPortableMode.setChecked(True) 134 else: 135 try: 136 tempfile.NamedTemporaryFile( 137 dir=paths.lookupExeFolder(), delete=True 138 ).close() # should autodelete 139 except Exception: 140 self.checkBoxPortableMode.setDisabled(True) 141 142 if 'darwin' in sys.platform: 143 self.checkBoxMinimizeToTray.setDisabled(True) 144 self.checkBoxMinimizeToTray.setText(_translate( 145 "MainWindow", 146 "Minimize-to-tray not yet supported on your OS.")) 147 self.checkBoxShowTrayNotifications.setDisabled(True) 148 self.checkBoxShowTrayNotifications.setText(_translate( 149 "MainWindow", 150 "Tray notifications not yet supported on your OS.")) 151 152 if not sys.platform.startswith('win') and not self.parent.desktop: 153 self.checkBoxStartOnLogon.setDisabled(True) 154 self.checkBoxStartOnLogon.setText(_translate( 155 "MainWindow", "Start-on-login not yet supported on your OS.")) 156 157 # On the Network settings tab: 158 self.lineEditTCPPort.setText(str( 159 config.get('bitmessagesettings', 'port'))) 160 self.checkBoxUPnP.setChecked( 161 config.safeGetBoolean('bitmessagesettings', 'upnp')) 162 self.checkBoxUDP.setChecked( 163 config.safeGetBoolean('bitmessagesettings', 'udp')) 164 self.checkBoxAuthentication.setChecked( 165 config.getboolean('bitmessagesettings', 'socksauthentication')) 166 self.checkBoxSocksListen.setChecked( 167 config.getboolean('bitmessagesettings', 'sockslisten')) 168 self.checkBoxOnionOnly.setChecked( 169 config.safeGetBoolean('bitmessagesettings', 'onionservicesonly')) 170 171 self._proxy_type = getSOCKSProxyType(config) 172 self.comboBoxProxyType.setCurrentIndex( 173 0 if not self._proxy_type 174 else self.comboBoxProxyType.findText(self._proxy_type)) 175 self.comboBoxProxyTypeChanged(self.comboBoxProxyType.currentIndex()) 176 177 if self._proxy_type: 178 for node, info in six.iteritems( 179 knownnodes.knownNodes.get( 180 min(connectionpool.pool.streams), []) 181 ): 182 if ( 183 node.host.endswith('.onion') and len(node.host) > 22 184 and not info.get('self') 185 ): 186 break 187 else: 188 if self.checkBoxOnionOnly.isChecked(): 189 self.checkBoxOnionOnly.setText( 190 self.checkBoxOnionOnly.text() + ", " + _translate( 191 "MainWindow", "may cause connection problems!")) 192 self.checkBoxOnionOnly.setStyleSheet( 193 "QCheckBox { color : red; }") 194 else: 195 self.checkBoxOnionOnly.setEnabled(False) 196 197 self.lineEditSocksHostname.setText( 198 config.get('bitmessagesettings', 'sockshostname')) 199 self.lineEditSocksPort.setText(str( 200 config.get('bitmessagesettings', 'socksport'))) 201 self.lineEditSocksUsername.setText( 202 config.get('bitmessagesettings', 'socksusername')) 203 self.lineEditSocksPassword.setText( 204 config.get('bitmessagesettings', 'sockspassword')) 205 206 self.lineEditMaxDownloadRate.setText(str( 207 config.get('bitmessagesettings', 'maxdownloadrate'))) 208 self.lineEditMaxUploadRate.setText(str( 209 config.get('bitmessagesettings', 'maxuploadrate'))) 210 self.lineEditMaxOutboundConnections.setText(str( 211 config.get('bitmessagesettings', 'maxoutboundconnections'))) 212 213 # Demanded difficulty tab 214 self.lineEditTotalDifficulty.setText(str((float( 215 config.getint( 216 'bitmessagesettings', 'defaultnoncetrialsperbyte') 217 ) / defaults.networkDefaultProofOfWorkNonceTrialsPerByte))) 218 self.lineEditSmallMessageDifficulty.setText(str((float( 219 config.getint( 220 'bitmessagesettings', 'defaultpayloadlengthextrabytes') 221 ) / defaults.networkDefaultPayloadLengthExtraBytes))) 222 223 # Max acceptable difficulty tab 224 self.lineEditMaxAcceptableTotalDifficulty.setText(str((float( 225 config.getint( 226 'bitmessagesettings', 'maxacceptablenoncetrialsperbyte') 227 ) / defaults.networkDefaultProofOfWorkNonceTrialsPerByte))) 228 self.lineEditMaxAcceptableSmallMessageDifficulty.setText(str((float( 229 config.getint( 230 'bitmessagesettings', 'maxacceptablepayloadlengthextrabytes') 231 ) / defaults.networkDefaultPayloadLengthExtraBytes))) 232 233 # OpenCL 234 self.comboBoxOpenCL.setEnabled(openclpow.openclAvailable()) 235 self.comboBoxOpenCL.clear() 236 self.comboBoxOpenCL.addItem("None") 237 self.comboBoxOpenCL.addItems(openclpow.vendors) 238 self.comboBoxOpenCL.setCurrentIndex(0) 239 for i in range(self.comboBoxOpenCL.count()): 240 if self.comboBoxOpenCL.itemText(i) == config.safeGet( 241 'bitmessagesettings', 'opencl'): 242 self.comboBoxOpenCL.setCurrentIndex(i) 243 break 244 245 # Namecoin integration tab 246 nmctype = config.get('bitmessagesettings', 'namecoinrpctype') 247 self.lineEditNamecoinHost.setText( 248 config.get('bitmessagesettings', 'namecoinrpchost')) 249 self.lineEditNamecoinPort.setText(str( 250 config.get('bitmessagesettings', 'namecoinrpcport'))) 251 self.lineEditNamecoinUser.setText( 252 config.get('bitmessagesettings', 'namecoinrpcuser')) 253 self.lineEditNamecoinPassword.setText( 254 config.get('bitmessagesettings', 'namecoinrpcpassword')) 255 256 if nmctype == "namecoind": 257 self.radioButtonNamecoinNamecoind.setChecked(True) 258 elif nmctype == "nmcontrol": 259 self.radioButtonNamecoinNmcontrol.setChecked(True) 260 self.lineEditNamecoinUser.setEnabled(False) 261 self.labelNamecoinUser.setEnabled(False) 262 self.lineEditNamecoinPassword.setEnabled(False) 263 self.labelNamecoinPassword.setEnabled(False) 264 else: 265 assert False 266 267 # Message Resend tab 268 self.lineEditDays.setText(str( 269 config.get('bitmessagesettings', 'stopresendingafterxdays'))) 270 self.lineEditMonths.setText(str( 271 config.get('bitmessagesettings', 'stopresendingafterxmonths'))) 272 273 def comboBoxProxyTypeChanged(self, comboBoxIndex): 274 """A callback for currentIndexChanged event of comboBoxProxyType""" 275 if comboBoxIndex == 0: 276 self.lineEditSocksHostname.setEnabled(False) 277 self.lineEditSocksPort.setEnabled(False) 278 self.lineEditSocksUsername.setEnabled(False) 279 self.lineEditSocksPassword.setEnabled(False) 280 self.checkBoxAuthentication.setEnabled(False) 281 self.checkBoxSocksListen.setEnabled(False) 282 self.checkBoxOnionOnly.setEnabled(False) 283 else: 284 self.lineEditSocksHostname.setEnabled(True) 285 self.lineEditSocksPort.setEnabled(True) 286 self.checkBoxAuthentication.setEnabled(True) 287 self.checkBoxSocksListen.setEnabled(True) 288 self.checkBoxOnionOnly.setEnabled(True) 289 if self.checkBoxAuthentication.isChecked(): 290 self.lineEditSocksUsername.setEnabled(True) 291 self.lineEditSocksPassword.setEnabled(True) 292 293 def getNamecoinType(self): 294 """ 295 Check status of namecoin integration radio buttons 296 and translate it to a string as in the options. 297 """ 298 if self.radioButtonNamecoinNamecoind.isChecked(): 299 return "namecoind" 300 if self.radioButtonNamecoinNmcontrol.isChecked(): 301 return "nmcontrol" 302 assert False 303 304 # Namecoin connection type was changed. 305 def namecoinTypeChanged(self, checked): # pylint: disable=unused-argument 306 """A callback for toggled event of radioButtonNamecoinNamecoind""" 307 nmctype = self.getNamecoinType() 308 assert nmctype == "namecoind" or nmctype == "nmcontrol" 309 310 isNamecoind = (nmctype == "namecoind") 311 self.lineEditNamecoinUser.setEnabled(isNamecoind) 312 self.labelNamecoinUser.setEnabled(isNamecoind) 313 self.lineEditNamecoinPassword.setEnabled(isNamecoind) 314 self.labelNamecoinPassword.setEnabled(isNamecoind) 315 316 if isNamecoind: 317 self.lineEditNamecoinPort.setText(defaults.namecoinDefaultRpcPort) 318 else: 319 self.lineEditNamecoinPort.setText("9000") 320 321 def click_pushButtonNamecoinTest(self): 322 """Test the namecoin settings specified in the settings dialog.""" 323 self.labelNamecoinTestResult.setText( 324 _translate("MainWindow", "Testing...")) 325 nc = namecoin.namecoinConnection({ 326 'type': self.getNamecoinType(), 327 'host': str(self.lineEditNamecoinHost.text().toUtf8()), 328 'port': str(self.lineEditNamecoinPort.text().toUtf8()), 329 'user': str(self.lineEditNamecoinUser.text().toUtf8()), 330 'password': str(self.lineEditNamecoinPassword.text().toUtf8()) 331 }) 332 status, text = nc.test() 333 self.labelNamecoinTestResult.setText(text) 334 if status == 'success': 335 self.parent.namecoin = nc 336 337 def save_font_setting(self, font): 338 """Save user font setting and set the buttonFont text""" 339 font_setting = (font.family(), font.pointSize()) 340 self.buttonFont.setText('{} {}'.format(*font_setting)) 341 self.font_setting = '{},{}'.format(*font_setting) 342 343 def choose_font(self): 344 """Show the font selection dialog""" 345 font, valid = QtGui.QFontDialog.getFont() 346 if valid: 347 self.save_font_setting(font) 348 349 def accept(self): 350 """A callback for accepted event of buttonBox (OK button pressed)""" 351 # pylint: disable=too-many-branches,too-many-statements 352 super(SettingsDialog, self).accept() 353 if self.firstrun: 354 self.config.remove_option('bitmessagesettings', 'dontconnect') 355 self.config.set('bitmessagesettings', 'startonlogon', str( 356 self.checkBoxStartOnLogon.isChecked())) 357 self.config.set('bitmessagesettings', 'minimizetotray', str( 358 self.checkBoxMinimizeToTray.isChecked())) 359 self.config.set('bitmessagesettings', 'trayonclose', str( 360 self.checkBoxTrayOnClose.isChecked())) 361 self.config.set( 362 'bitmessagesettings', 'hidetrayconnectionnotifications', 363 str(self.checkBoxHideTrayConnectionNotifications.isChecked())) 364 self.config.set('bitmessagesettings', 'showtraynotifications', str( 365 self.checkBoxShowTrayNotifications.isChecked())) 366 self.config.set('bitmessagesettings', 'startintray', str( 367 self.checkBoxStartInTray.isChecked())) 368 self.config.set('bitmessagesettings', 'willinglysendtomobile', str( 369 self.checkBoxWillinglySendToMobile.isChecked())) 370 self.config.set('bitmessagesettings', 'useidenticons', str( 371 self.checkBoxUseIdenticons.isChecked())) 372 self.config.set('bitmessagesettings', 'replybelow', str( 373 self.checkBoxReplyBelow.isChecked())) 374 375 window_style = str(self.comboBoxStyle.currentText()) 376 if self.app.get_windowstyle() != window_style or self.config.safeGet( 377 'bitmessagesettings', 'font' 378 ) != self.font_setting: 379 self.config.set('bitmessagesettings', 'windowstyle', window_style) 380 self.config.set('bitmessagesettings', 'font', self.font_setting) 381 queues.UISignalQueue.put(( 382 'updateStatusBar', ( 383 _translate( 384 "MainWindow", 385 "You need to restart the application to apply" 386 " the window style or default font."), 1) 387 )) 388 389 lang = str(self.languageComboBox.itemData( 390 self.languageComboBox.currentIndex()).toString()) 391 self.config.set('bitmessagesettings', 'userlocale', lang) 392 self.parent.change_translation() 393 394 if int(self.config.get('bitmessagesettings', 'port')) != int( 395 self.lineEditTCPPort.text()): 396 self.config.set( 397 'bitmessagesettings', 'port', str(self.lineEditTCPPort.text())) 398 if not self.config.safeGetBoolean( 399 'bitmessagesettings', 'dontconnect'): 400 self.net_restart_needed = True 401 402 if self.checkBoxUPnP.isChecked() != self.config.safeGetBoolean( 403 'bitmessagesettings', 'upnp'): 404 self.config.set( 405 'bitmessagesettings', 'upnp', 406 str(self.checkBoxUPnP.isChecked())) 407 if self.checkBoxUPnP.isChecked(): 408 import upnp 409 upnpThread = upnp.uPnPThread() 410 upnpThread.start() 411 412 udp_enabled = self.checkBoxUDP.isChecked() 413 if udp_enabled != self.config.safeGetBoolean( 414 'bitmessagesettings', 'udp'): 415 self.config.set('bitmessagesettings', 'udp', str(udp_enabled)) 416 if udp_enabled: 417 announceThread = AnnounceThread() 418 announceThread.daemon = True 419 announceThread.start() 420 else: 421 try: 422 state.announceThread.stopThread() 423 except AttributeError: 424 pass 425 426 proxytype_index = self.comboBoxProxyType.currentIndex() 427 if proxytype_index == 0: 428 if self._proxy_type and state.statusIconColor != 'red': 429 self.net_restart_needed = True 430 elif state.statusIconColor == 'red' and self.config.safeGetBoolean( 431 'bitmessagesettings', 'dontconnect'): 432 self.net_restart_needed = False 433 elif self.comboBoxProxyType.currentText() != self._proxy_type: 434 self.net_restart_needed = True 435 self.parent.statusbar.clearMessage() 436 437 self.config.set( 438 'bitmessagesettings', 'socksproxytype', 439 'none' if self.comboBoxProxyType.currentIndex() == 0 440 else str(self.comboBoxProxyType.currentText()) 441 ) 442 if proxytype_index > 2: # last literal proxytype in ui 443 start_proxyconfig() 444 445 self.config.set('bitmessagesettings', 'socksauthentication', str( 446 self.checkBoxAuthentication.isChecked())) 447 self.config.set('bitmessagesettings', 'sockshostname', str( 448 self.lineEditSocksHostname.text())) 449 self.config.set('bitmessagesettings', 'socksport', str( 450 self.lineEditSocksPort.text())) 451 self.config.set('bitmessagesettings', 'socksusername', str( 452 self.lineEditSocksUsername.text())) 453 self.config.set('bitmessagesettings', 'sockspassword', str( 454 self.lineEditSocksPassword.text())) 455 self.config.set('bitmessagesettings', 'sockslisten', str( 456 self.checkBoxSocksListen.isChecked())) 457 if ( 458 self.checkBoxOnionOnly.isChecked() 459 and not self.config.safeGetBoolean( 460 'bitmessagesettings', 'onionservicesonly') 461 ): 462 self.net_restart_needed = True 463 self.config.set('bitmessagesettings', 'onionservicesonly', str( 464 self.checkBoxOnionOnly.isChecked())) 465 try: 466 # Rounding to integers just for aesthetics 467 self.config.set('bitmessagesettings', 'maxdownloadrate', str( 468 int(float(self.lineEditMaxDownloadRate.text())))) 469 self.config.set('bitmessagesettings', 'maxuploadrate', str( 470 int(float(self.lineEditMaxUploadRate.text())))) 471 except ValueError: 472 QtGui.QMessageBox.about( 473 self, _translate("MainWindow", "Number needed"), 474 _translate( 475 "MainWindow", 476 "Your maximum download and upload rate must be numbers." 477 " Ignoring what you typed.") 478 ) 479 else: 480 set_rates( 481 self.config.safeGetInt('bitmessagesettings', 'maxdownloadrate'), 482 self.config.safeGetInt('bitmessagesettings', 'maxuploadrate')) 483 484 self.config.set('bitmessagesettings', 'maxoutboundconnections', str( 485 int(float(self.lineEditMaxOutboundConnections.text())))) 486 487 self.config.set( 488 'bitmessagesettings', 'namecoinrpctype', self.getNamecoinType()) 489 self.config.set('bitmessagesettings', 'namecoinrpchost', str( 490 self.lineEditNamecoinHost.text())) 491 self.config.set('bitmessagesettings', 'namecoinrpcport', str( 492 self.lineEditNamecoinPort.text())) 493 self.config.set('bitmessagesettings', 'namecoinrpcuser', str( 494 self.lineEditNamecoinUser.text())) 495 self.config.set('bitmessagesettings', 'namecoinrpcpassword', str( 496 self.lineEditNamecoinPassword.text())) 497 self.parent.resetNamecoinConnection() 498 499 # Demanded difficulty tab 500 if float(self.lineEditTotalDifficulty.text()) >= 1: 501 self.config.set( 502 'bitmessagesettings', 'defaultnoncetrialsperbyte', 503 str(int( 504 float(self.lineEditTotalDifficulty.text()) 505 * defaults.networkDefaultProofOfWorkNonceTrialsPerByte))) 506 if float(self.lineEditSmallMessageDifficulty.text()) >= 1: 507 self.config.set( 508 'bitmessagesettings', 'defaultpayloadlengthextrabytes', 509 str(int( 510 float(self.lineEditSmallMessageDifficulty.text()) 511 * defaults.networkDefaultPayloadLengthExtraBytes))) 512 513 if self.comboBoxOpenCL.currentText().toUtf8() != self.config.safeGet( 514 'bitmessagesettings', 'opencl'): 515 self.config.set( 516 'bitmessagesettings', 'opencl', 517 str(self.comboBoxOpenCL.currentText())) 518 queues.workerQueue.put(('resetPoW', '')) 519 520 acceptableDifficultyChanged = False 521 522 if ( 523 float(self.lineEditMaxAcceptableTotalDifficulty.text()) >= 1 524 or float(self.lineEditMaxAcceptableTotalDifficulty.text()) == 0 525 ): 526 if self.config.get( 527 'bitmessagesettings', 'maxacceptablenoncetrialsperbyte' 528 ) != str(int( 529 float(self.lineEditMaxAcceptableTotalDifficulty.text()) 530 * defaults.networkDefaultProofOfWorkNonceTrialsPerByte)): 531 # the user changed the max acceptable total difficulty 532 acceptableDifficultyChanged = True 533 self.config.set( 534 'bitmessagesettings', 'maxacceptablenoncetrialsperbyte', 535 str(int( 536 float(self.lineEditMaxAcceptableTotalDifficulty.text()) 537 * defaults.networkDefaultProofOfWorkNonceTrialsPerByte)) 538 ) 539 if ( 540 float(self.lineEditMaxAcceptableSmallMessageDifficulty.text()) >= 1 541 or float(self.lineEditMaxAcceptableSmallMessageDifficulty.text()) == 0 542 ): 543 if self.config.get( 544 'bitmessagesettings', 'maxacceptablepayloadlengthextrabytes' 545 ) != str(int( 546 float(self.lineEditMaxAcceptableSmallMessageDifficulty.text()) 547 * defaults.networkDefaultPayloadLengthExtraBytes)): 548 # the user changed the max acceptable small message difficulty 549 acceptableDifficultyChanged = True 550 self.config.set( 551 'bitmessagesettings', 'maxacceptablepayloadlengthextrabytes', 552 str(int( 553 float(self.lineEditMaxAcceptableSmallMessageDifficulty.text()) 554 * defaults.networkDefaultPayloadLengthExtraBytes)) 555 ) 556 if acceptableDifficultyChanged: 557 # It might now be possible to send msgs which were previously 558 # marked as toodifficult. Let us change them to 'msgqueued'. 559 # The singleWorker will try to send them and will again mark 560 # them as toodifficult if the receiver's required difficulty 561 # is still higher than we are willing to do. 562 sqlExecute( 563 "UPDATE sent SET status='msgqueued'" 564 " WHERE status='toodifficult'") 565 queues.workerQueue.put(('sendmessage', '')) 566 567 stopResendingDefaults = False 568 569 # UI setting to stop trying to send messages after X days/months 570 # I'm open to changing this UI to something else if someone has a better idea. 571 if self.lineEditDays.text() == '' and self.lineEditMonths.text() == '': 572 # We need to handle this special case. Bitmessage has its 573 # default behavior. The input is blank/blank 574 self.config.set('bitmessagesettings', 'stopresendingafterxdays', '') 575 self.config.set('bitmessagesettings', 'stopresendingafterxmonths', '') 576 state.maximumLengthOfTimeToBotherResendingMessages = float('inf') 577 stopResendingDefaults = True 578 579 try: 580 days = float(self.lineEditDays.text()) 581 except ValueError: 582 self.lineEditDays.setText("0") 583 days = 0.0 584 try: 585 months = float(self.lineEditMonths.text()) 586 except ValueError: 587 self.lineEditMonths.setText("0") 588 months = 0.0 589 590 if days >= 0 and months >= 0 and not stopResendingDefaults: 591 state.maximumLengthOfTimeToBotherResendingMessages = \ 592 days * 24 * 60 * 60 + months * 60 * 60 * 24 * 365 / 12 593 if state.maximumLengthOfTimeToBotherResendingMessages < 432000: 594 # If the time period is less than 5 hours, we give 595 # zero values to all fields. No message will be sent again. 596 QtGui.QMessageBox.about( 597 self, 598 _translate("MainWindow", "Will not resend ever"), 599 _translate( 600 "MainWindow", 601 "Note that the time limit you entered is less" 602 " than the amount of time Bitmessage waits for" 603 " the first resend attempt therefore your" 604 " messages will never be resent.") 605 ) 606 self.config.set( 607 'bitmessagesettings', 'stopresendingafterxdays', '0') 608 self.config.set( 609 'bitmessagesettings', 'stopresendingafterxmonths', '0') 610 state.maximumLengthOfTimeToBotherResendingMessages = 0.0 611 else: 612 self.config.set( 613 'bitmessagesettings', 'stopresendingafterxdays', str(days)) 614 self.config.set( 615 'bitmessagesettings', 'stopresendingafterxmonths', 616 str(months)) 617 618 self.config.save() 619 620 if self.net_restart_needed: 621 self.net_restart_needed = False 622 self.config.setTemp('bitmessagesettings', 'dontconnect', 'true') 623 self.timer.singleShot( 624 5000, lambda: 625 self.config.setTemp( 626 'bitmessagesettings', 'dontconnect', 'false') 627 ) 628 629 self.parent.updateStartOnLogon() 630 631 if ( 632 state.appdata != paths.lookupExeFolder() 633 and self.checkBoxPortableMode.isChecked() 634 ): 635 # If we are NOT using portable mode now but the user selected 636 # that we should... 637 # Write the keys.dat file to disk in the new location 638 sqlStoredProcedure('movemessagstoprog') 639 with open(paths.lookupExeFolder() + 'keys.dat', 'wb') as configfile: 640 self.config.write(configfile) 641 # Write the knownnodes.dat file to disk in the new location 642 knownnodes.saveKnownNodes(paths.lookupExeFolder()) 643 os.remove(state.appdata + 'keys.dat') 644 os.remove(state.appdata + 'knownnodes.dat') 645 previousAppdataLocation = state.appdata 646 state.appdata = paths.lookupExeFolder() 647 debug.resetLogging() 648 try: 649 os.remove(previousAppdataLocation + 'debug.log') 650 os.remove(previousAppdataLocation + 'debug.log.1') 651 except Exception: 652 pass 653 654 if ( 655 state.appdata == paths.lookupExeFolder() 656 and not self.checkBoxPortableMode.isChecked() 657 ): 658 # If we ARE using portable mode now but the user selected 659 # that we shouldn't... 660 state.appdata = paths.lookupAppdataFolder() 661 if not os.path.exists(state.appdata): 662 os.makedirs(state.appdata) 663 sqlStoredProcedure('movemessagstoappdata') 664 # Write the keys.dat file to disk in the new location 665 self.config.save() 666 # Write the knownnodes.dat file to disk in the new location 667 knownnodes.saveKnownNodes(state.appdata) 668 os.remove(paths.lookupExeFolder() + 'keys.dat') 669 os.remove(paths.lookupExeFolder() + 'knownnodes.dat') 670 debug.resetLogging() 671 try: 672 os.remove(paths.lookupExeFolder() + 'debug.log') 673 os.remove(paths.lookupExeFolder() + 'debug.log.1') 674 except Exception: 675 pass