From 92e297076730e0b17fa6885ced305fc08aa77161 Mon Sep 17 00:00:00 2001 From: Daniel Kraft Date: Sun, 7 Jul 2013 20:04:57 +0200 Subject: [PATCH] Support NMControl. Optionally support querying nmcontrol instead of namecoind, including UI for selecting the preference. --- src/bitmessageqt/__init__.py | 46 +++++++++++++++ src/bitmessageqt/settings.py | 70 ++++++++++++++--------- src/bitmessageqt/settings.ui | 108 ++++++++++++++++++++++------------- src/namecoin.py | 71 +++++++++++++++++------ 4 files changed, 210 insertions(+), 85 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 69f9126b..f256d3ac 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -1779,6 +1779,8 @@ class MyForm(QtGui.QMainWindow): shared.config.set('bitmessagesettings', 'sockspassword', str( self.settingsDialogInstance.ui.lineEditSocksPassword.text())) + shared.config.set('bitmessagesettings', 'namecoinrpctype', + self.settingsDialogInstance.getNamecoinType()) shared.config.set('bitmessagesettings', 'namecoinrpchost', str( self.settingsDialogInstance.ui.lineEditNamecoinHost.text())) shared.config.set('bitmessagesettings', 'namecoinrpcport', str( @@ -2752,7 +2754,9 @@ class settingsDialog(QtGui.QDialog): 'bitmessagesettings', 'maxacceptablepayloadlengthextrabytes')) / shared.networkDefaultPayloadLengthExtraBytes))) # Namecoin integration tab + ensureNamecoinOptions() + nmctype = shared.config.get('bitmessagesettings', 'namecoinrpctype') self.ui.lineEditNamecoinHost.setText(str( shared.config.get('bitmessagesettings', 'namecoinrpchost'))) self.ui.lineEditNamecoinPort.setText(str( @@ -2761,6 +2765,22 @@ class settingsDialog(QtGui.QDialog): shared.config.get('bitmessagesettings', 'namecoinrpcuser'))) self.ui.lineEditNamecoinPassword.setText(str( shared.config.get('bitmessagesettings', 'namecoinrpcpassword'))) + + if nmctype == "namecoind": + self.ui.radioButtonNamecoinNamecoind.setChecked(True) + elif nmctype == "nmcontrol": + self.ui.radioButtonNamecoinNmcontrol.setChecked(True) + self.ui.lineEditNamecoinUser.setEnabled(False) + self.ui.labelNamecoinUser.setEnabled(False) + self.ui.lineEditNamecoinPassword.setEnabled(False) + self.ui.labelNamecoinPassword.setEnabled(False) + else: + assert False + + QtCore.QObject.connect(self.ui.radioButtonNamecoinNamecoind, QtCore.SIGNAL( + "toggled(bool)"), self.namecoinTypeChanged) + QtCore.QObject.connect(self.ui.radioButtonNamecoinNmcontrol, QtCore.SIGNAL( + "toggled(bool)"), self.namecoinTypeChanged) QtCore.QObject.connect(self.ui.pushButtonNamecoinTest, QtCore.SIGNAL( "clicked()"), self.click_pushButtonNamecoinTest) @@ -2801,9 +2821,35 @@ class settingsDialog(QtGui.QDialog): self.ui.lineEditSocksPassword.setEnabled(True) self.ui.lineEditTCPPort.setEnabled(False) + # Check status of namecoin integration radio buttons and translate + # it to a string as in the options. + def getNamecoinType(self): + if self.ui.radioButtonNamecoinNamecoind.isChecked(): + return "namecoind" + if self.ui.radioButtonNamecoinNmcontrol.isChecked(): + return "nmcontrol" + assert False + + # Namecoin connection type was changed. + def namecoinTypeChanged(self, checked): + nmctype = self.getNamecoinType() + assert nmctype == "namecoind" or nmctype == "nmcontrol" + + isNamecoind = (nmctype == "namecoind") + self.ui.lineEditNamecoinUser.setEnabled(isNamecoind) + self.ui.labelNamecoinUser.setEnabled(isNamecoind) + self.ui.lineEditNamecoinPassword.setEnabled(isNamecoind) + self.ui.labelNamecoinPassword.setEnabled(isNamecoind) + + if isNamecoind: + self.ui.lineEditNamecoinPort.setText("8336") + else: + self.ui.lineEditNamecoinPort.setText("9000") + # Test the namecoin settings specified in the settings dialog. def click_pushButtonNamecoinTest(self): options = {} + options["type"] = self.getNamecoinType() options["host"] = self.ui.lineEditNamecoinHost.text() options["port"] = self.ui.lineEditNamecoinPort.text() options["user"] = self.ui.lineEditNamecoinUser.text() diff --git a/src/bitmessageqt/settings.py b/src/bitmessageqt/settings.py index 2f93ce88..3bb185a3 100644 --- a/src/bitmessageqt/settings.py +++ b/src/bitmessageqt/settings.py @@ -2,7 +2,7 @@ # Form implementation generated from reading ui file 'settings.ui' # -# Created: Sun Jul 7 18:40:01 2013 +# Created: Sun Jul 7 19:23:55 2013 # by: PyQt4 UI code generator 4.9.3 # # WARNING! All changes made in this file will be lost! @@ -220,7 +220,7 @@ class Ui_settingsDialog(object): self.gridLayout_8 = QtGui.QGridLayout(self.tabNamecoin) self.gridLayout_8.setObjectName(_fromUtf8("gridLayout_8")) spacerItem8 = QtGui.QSpacerItem(40, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum) - self.gridLayout_8.addItem(spacerItem8, 1, 0, 1, 1) + self.gridLayout_8.addItem(spacerItem8, 2, 0, 1, 1) self.label_16 = QtGui.QLabel(self.tabNamecoin) self.label_16.setWordWrap(True) self.label_16.setObjectName(_fromUtf8("label_16")) @@ -228,48 +228,61 @@ class Ui_settingsDialog(object): self.label_17 = QtGui.QLabel(self.tabNamecoin) 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, 1, 1, 1, 1) + self.gridLayout_8.addWidget(self.label_17, 2, 1, 1, 1) self.lineEditNamecoinHost = QtGui.QLineEdit(self.tabNamecoin) self.lineEditNamecoinHost.setObjectName(_fromUtf8("lineEditNamecoinHost")) - self.gridLayout_8.addWidget(self.lineEditNamecoinHost, 1, 2, 1, 1) + self.gridLayout_8.addWidget(self.lineEditNamecoinHost, 2, 2, 1, 1) spacerItem9 = QtGui.QSpacerItem(40, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum) - self.gridLayout_8.addItem(spacerItem9, 2, 0, 1, 1) + self.gridLayout_8.addItem(spacerItem9, 3, 0, 1, 1) + spacerItem10 = QtGui.QSpacerItem(40, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum) + self.gridLayout_8.addItem(spacerItem10, 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.setObjectName(_fromUtf8("label_18")) - self.gridLayout_8.addWidget(self.label_18, 2, 1, 1, 1) + self.gridLayout_8.addWidget(self.label_18, 3, 1, 1, 1) self.lineEditNamecoinPort = QtGui.QLineEdit(self.tabNamecoin) self.lineEditNamecoinPort.setObjectName(_fromUtf8("lineEditNamecoinPort")) - self.gridLayout_8.addWidget(self.lineEditNamecoinPort, 2, 2, 1, 1) - spacerItem10 = QtGui.QSpacerItem(20, 40, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding) - self.gridLayout_8.addItem(spacerItem10, 7, 1, 1, 1) - spacerItem11 = QtGui.QSpacerItem(40, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum) - self.gridLayout_8.addItem(spacerItem11, 3, 0, 1, 1) - self.label_19 = QtGui.QLabel(self.tabNamecoin) - self.label_19.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) - self.label_19.setObjectName(_fromUtf8("label_19")) - self.gridLayout_8.addWidget(self.label_19, 3, 1, 1, 1) + self.gridLayout_8.addWidget(self.lineEditNamecoinPort, 3, 2, 1, 1) + spacerItem11 = QtGui.QSpacerItem(20, 40, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding) + self.gridLayout_8.addItem(spacerItem11, 8, 1, 1, 1) + self.labelNamecoinUser = QtGui.QLabel(self.tabNamecoin) + 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) self.lineEditNamecoinUser.setObjectName(_fromUtf8("lineEditNamecoinUser")) - self.gridLayout_8.addWidget(self.lineEditNamecoinUser, 3, 2, 1, 1) + self.gridLayout_8.addWidget(self.lineEditNamecoinUser, 4, 2, 1, 1) spacerItem12 = QtGui.QSpacerItem(40, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum) - self.gridLayout_8.addItem(spacerItem12, 4, 0, 1, 1) - self.label_20 = QtGui.QLabel(self.tabNamecoin) - self.label_20.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) - self.label_20.setObjectName(_fromUtf8("label_20")) - self.gridLayout_8.addWidget(self.label_20, 4, 1, 1, 1) + self.gridLayout_8.addItem(spacerItem12, 5, 0, 1, 1) + self.labelNamecoinPassword = QtGui.QLabel(self.tabNamecoin) + 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.setEchoMode(QtGui.QLineEdit.Password) self.lineEditNamecoinPassword.setObjectName(_fromUtf8("lineEditNamecoinPassword")) - self.gridLayout_8.addWidget(self.lineEditNamecoinPassword, 4, 2, 1, 1) + self.gridLayout_8.addWidget(self.lineEditNamecoinPassword, 5, 2, 1, 1) self.labelNamecoinTestResult = QtGui.QLabel(self.tabNamecoin) self.labelNamecoinTestResult.setText(_fromUtf8("")) self.labelNamecoinTestResult.setObjectName(_fromUtf8("labelNamecoinTestResult")) - self.gridLayout_8.addWidget(self.labelNamecoinTestResult, 6, 0, 1, 2) + self.gridLayout_8.addWidget(self.labelNamecoinTestResult, 7, 0, 1, 2) self.pushButtonNamecoinTest = QtGui.QPushButton(self.tabNamecoin) self.pushButtonNamecoinTest.setObjectName(_fromUtf8("pushButtonNamecoinTest")) - self.gridLayout_8.addWidget(self.pushButtonNamecoinTest, 6, 2, 1, 1) + self.gridLayout_8.addWidget(self.pushButtonNamecoinTest, 7, 2, 1, 1) + self.horizontalLayout = QtGui.QHBoxLayout() + self.horizontalLayout.setObjectName(_fromUtf8("horizontalLayout")) + self.label_21 = QtGui.QLabel(self.tabNamecoin) + self.label_21.setObjectName(_fromUtf8("label_21")) + self.horizontalLayout.addWidget(self.label_21) + self.radioButtonNamecoinNamecoind = QtGui.QRadioButton(self.tabNamecoin) + self.radioButtonNamecoinNamecoind.setObjectName(_fromUtf8("radioButtonNamecoinNamecoind")) + self.horizontalLayout.addWidget(self.radioButtonNamecoinNamecoind) + self.radioButtonNamecoinNmcontrol = QtGui.QRadioButton(self.tabNamecoin) + self.radioButtonNamecoinNmcontrol.setObjectName(_fromUtf8("radioButtonNamecoinNmcontrol")) + self.horizontalLayout.addWidget(self.radioButtonNamecoinNmcontrol) + self.gridLayout_8.addLayout(self.horizontalLayout, 1, 0, 1, 3) self.tabWidgetSettings.addTab(self.tabNamecoin, _fromUtf8("")) self.gridLayout.addWidget(self.tabWidgetSettings, 0, 0, 1, 1) @@ -325,11 +338,14 @@ class Ui_settingsDialog(object): self.label_13.setText(QtGui.QApplication.translate("settingsDialog", "Maximum acceptable total difficulty:", None, QtGui.QApplication.UnicodeUTF8)) self.label_14.setText(QtGui.QApplication.translate("settingsDialog", "Maximum acceptable small message difficulty:", None, QtGui.QApplication.UnicodeUTF8)) self.tabWidgetSettings.setTabText(self.tabWidgetSettings.indexOf(self.tab_2), QtGui.QApplication.translate("settingsDialog", "Max acceptable difficulty", None, QtGui.QApplication.UnicodeUTF8)) - self.label_16.setText(QtGui.QApplication.translate("settingsDialog", "Bitmessage addresses can be fetched automatically from Namecoin identities. If you have namecoind installed and running, chances are that the automatic configuration below works already for you. If not, you can fine-tune the settings to use for connecting to your local namecoind instance. Alternatively, you may also use nmcontrol instead of namecoind.", None, QtGui.QApplication.UnicodeUTF8)) + self.label_16.setText(QtGui.QApplication.translate("settingsDialog", "Bitmessage addresses can be fetched automatically from Namecoin identities. You can use either namecoind directly or a running nmcontrol instance.", None, QtGui.QApplication.UnicodeUTF8)) self.label_17.setText(QtGui.QApplication.translate("settingsDialog", "Host:", None, QtGui.QApplication.UnicodeUTF8)) self.label_18.setText(QtGui.QApplication.translate("settingsDialog", "Port:", None, QtGui.QApplication.UnicodeUTF8)) - self.label_19.setText(QtGui.QApplication.translate("settingsDialog", "Username:", None, QtGui.QApplication.UnicodeUTF8)) - self.label_20.setText(QtGui.QApplication.translate("settingsDialog", "Password:", None, QtGui.QApplication.UnicodeUTF8)) + self.labelNamecoinUser.setText(QtGui.QApplication.translate("settingsDialog", "Username:", None, QtGui.QApplication.UnicodeUTF8)) + self.labelNamecoinPassword.setText(QtGui.QApplication.translate("settingsDialog", "Password:", None, QtGui.QApplication.UnicodeUTF8)) self.pushButtonNamecoinTest.setText(QtGui.QApplication.translate("settingsDialog", "Test", None, QtGui.QApplication.UnicodeUTF8)) + self.label_21.setText(QtGui.QApplication.translate("settingsDialog", "Connect to:", None, QtGui.QApplication.UnicodeUTF8)) + self.radioButtonNamecoinNamecoind.setText(QtGui.QApplication.translate("settingsDialog", "Namecoind", None, QtGui.QApplication.UnicodeUTF8)) + self.radioButtonNamecoinNmcontrol.setText(QtGui.QApplication.translate("settingsDialog", "NMControl", None, QtGui.QApplication.UnicodeUTF8)) self.tabWidgetSettings.setTabText(self.tabWidgetSettings.indexOf(self.tabNamecoin), QtGui.QApplication.translate("settingsDialog", "Namecoin integration", None, QtGui.QApplication.UnicodeUTF8)) diff --git a/src/bitmessageqt/settings.ui b/src/bitmessageqt/settings.ui index 4c1e14eb..f8674928 100644 --- a/src/bitmessageqt/settings.ui +++ b/src/bitmessageqt/settings.ui @@ -496,7 +496,7 @@ Namecoin integration - + Qt::Horizontal @@ -512,14 +512,14 @@ - Bitmessage addresses can be fetched automatically from Namecoin identities. If you have namecoind installed and running, chances are that the automatic configuration below works already for you. If not, you can fine-tune the settings to use for connecting to your local namecoind instance. Alternatively, you may also use nmcontrol instead of namecoind. + Bitmessage addresses can be fetched automatically from Namecoin identities. You can use either namecoind directly or a running nmcontrol instance. true - + Host: @@ -529,10 +529,10 @@ - + - + Qt::Horizontal @@ -545,33 +545,7 @@ - - - - Port: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - + Qt::Horizontal @@ -585,7 +559,36 @@ - + + + true + + + Port: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + Username: @@ -594,10 +597,10 @@ - + - + Qt::Horizontal @@ -610,8 +613,8 @@ - - + + Password: @@ -620,7 +623,7 @@ - + Qt::ImhHiddenText|Qt::ImhNoAutoUppercase|Qt::ImhNoPredictiveText @@ -630,20 +633,45 @@ - + - + Test + + + + + + Connect to: + + + + + + + Namecoind + + + + + + + NMControl + + + + + diff --git a/src/namecoin.py b/src/namecoin.py index 9e98c2d0..17cd74ea 100644 --- a/src/namecoin.py +++ b/src/namecoin.py @@ -41,6 +41,7 @@ class namecoinConnection (object): password = None host = None port = None + nmctype = None bufsize = 4096 queryid = 1 @@ -51,17 +52,21 @@ class namecoinConnection (object): def __init__ (self, options = None): if options is None: ensureNamecoinOptions () + self.nmctype = shared.config.get (configSection, "namecoinrpctype") self.host = shared.config.get (configSection, "namecoinrpchost") self.port = shared.config.get (configSection, "namecoinrpcport") self.user = shared.config.get (configSection, "namecoinrpcuser") self.password = shared.config.get (configSection, "namecoinrpcpassword") else: + self.nmctype = options["type"] self.host = options["host"] self.port = options["port"] self.user = options["user"] self.password = options["password"] + assert self.nmctype == "namecoind" or self.nmctype == "nmcontrol" + # Query for the bitmessage address corresponding to the given identity # string. If it doesn't contain a slash, id/ is prepended. We return # the result as (Error, Address) pair, where the Error is an error @@ -72,7 +77,16 @@ class namecoinConnection (object): string = "id/" + string try: - res = self.callRPC ("name_show", [string]) + if self.nmctype == "namecoind": + res = self.callRPC ("name_show", [string]) + res = res["value"] + elif self.nmctype == "nmcontrol": + res = self.callRPC ("data", ["getValue", string]) + res = res["reply"] + if res == False: + raise RPCError ({"code": -4}) + else: + assert False except RPCError as exc: if exc.error["code"] == -4: return ("The name '%s' was not found." % string, None) @@ -84,7 +98,7 @@ class namecoinConnection (object): return ("The namecoin query failed.", None) try: - val = json.loads (res["value"]) + val = json.loads (res) except: return ("The name '%s' has no valid JSON data." % string, None) @@ -99,28 +113,47 @@ class namecoinConnection (object): # some info from it. def test (self): try: - res = self.callRPC ("getinfo", []) - vers = res["version"] - - v3 = vers % 100 - vers = vers / 100 - v2 = vers % 100 - vers = vers / 100 - v1 = vers - if v3 == 0: - versStr = "0.%d.%d" % (v1, v2) + if self.nmctype == "namecoind": + res = self.callRPC ("getinfo", []) + vers = res["version"] + + v3 = vers % 100 + vers = vers / 100 + v2 = vers % 100 + vers = vers / 100 + v1 = vers + if v3 == 0: + versStr = "0.%d.%d" % (v1, v2) + else: + versStr = "0.%d.%d.%d" % (v1, v2, v3) + + return "Success! Namecoind version %s running." % versStr + + elif self.nmctype == "nmcontrol": + res = self.callRPC ("data", ["status"]) + prefix = "Plugin data running" + if ("reply" in res) and res["reply"][:len(prefix)] == prefix: + return "Success! NMControll is up and running." + + print "Unexpected nmcontrol reply: %s" % res + return "Couldn't understand NMControl." + else: - versStr = "0.%d.%d.%d" % (v1, v2, v3) + assert False - return "Success! Namecoind version %s running." % versStr - - except: - return "The connection to namecoind failed." + except Exception as exc: + print "Exception testing the namecoin connection:\n%s" % str (exc) + return "The connection to namecoin failed." # Helper routine that actually performs an JSON RPC call. def callRPC (self, method, params): data = {"method": method, "params": params, "id": self.queryid} - resp = self.queryHTTP (json.dumps (data)) + if self.nmctype == "namecoind": + resp = self.queryHTTP (json.dumps (data)) + elif self.nmctype == "nmcontrol": + resp = self.queryServer (json.dumps (data)) + else: + assert False val = json.loads (resp) if val["id"] != self.queryid: @@ -203,6 +236,8 @@ def lookupNamecoinFolder (): # Ensure all namecoin options are set, by setting those to default values # that aren't there. def ensureNamecoinOptions (): + if not shared.config.has_option (configSection, "namecoinrpctype"): + shared.config.set (configSection, "namecoinrpctype", "namecoind") if not shared.config.has_option (configSection, "namecoinrpchost"): shared.config.set (configSection, "namecoinrpchost", "localhost") if not shared.config.has_option (configSection, "namecoinrpcport"):