From 8f39e3518408d83b98d4f03ded007b2bcab2eacc Mon Sep 17 00:00:00 2001 From: Daniel Kraft Date: Thu, 4 Jul 2013 21:51:48 +0200 Subject: [PATCH 01/13] Add executable flag. Mark bitmessagemain.py as executable. --- src/bitmessagemain.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 src/bitmessagemain.py diff --git a/src/bitmessagemain.py b/src/bitmessagemain.py old mode 100644 new mode 100755 From 9a5d04869150a19b6307ebfdc3e532846bb10163 Mon Sep 17 00:00:00 2001 From: Daniel Kraft Date: Thu, 4 Jul 2013 22:06:30 +0200 Subject: [PATCH 02/13] Add fetch from namecoin button to UI. Add the new button to the UI, and register onclick handler to fill in the to field with a dummy address for now. --- src/bitmessageqt/__init__.py | 5 + src/bitmessageqt/bitmessageui.py | 160 ++++++++++++++----------------- src/bitmessageqt/bitmessageui.ui | 14 ++- 3 files changed, 92 insertions(+), 87 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index ce477836..4c9fd2c0 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -117,6 +117,8 @@ class MyForm(QtGui.QMainWindow): "clicked()"), self.click_pushButtonSend) QtCore.QObject.connect(self.ui.pushButtonLoadFromAddressBook, QtCore.SIGNAL( "clicked()"), self.click_pushButtonLoadFromAddressBook) + QtCore.QObject.connect(self.ui.pushButtonFetchNamecoinID, QtCore.SIGNAL( + "clicked()"), self.click_pushButtonFetchNamecoinID) QtCore.QObject.connect(self.ui.radioButtonBlacklist, QtCore.SIGNAL( "clicked()"), self.click_radioButtonBlacklist) QtCore.QObject.connect(self.ui.radioButtonWhitelist, QtCore.SIGNAL( @@ -1454,6 +1456,9 @@ class MyForm(QtGui.QMainWindow): self.statusBar().showMessage(_translate( "MainWindow", "Right click one or more entries in your address book and select \'Send message to this address\'.")) + def click_pushButtonFetchNamecoinID(self): + self.ui.lineEditTo.setText ("BM-Foobar") + def redrawLabelFrom(self, index): self.ui.labelFrom.setText( self.ui.comboBoxSendFrom.itemData(index).toPyObject()) diff --git a/src/bitmessageqt/bitmessageui.py b/src/bitmessageqt/bitmessageui.py index 1186e814..e4ff59d8 100644 --- a/src/bitmessageqt/bitmessageui.py +++ b/src/bitmessageqt/bitmessageui.py @@ -2,8 +2,8 @@ # Form implementation generated from reading ui file 'bitmessageui.ui' # -# Created: Thu Jun 13 01:02:50 2013 -# by: PyQt4 UI code generator 4.10.1 +# Created: Thu Jul 4 22:00:02 2013 +# by: PyQt4 UI code generator 4.9.3 # # WARNING! All changes made in this file will be lost! @@ -12,16 +12,7 @@ from PyQt4 import QtCore, QtGui try: _fromUtf8 = QtCore.QString.fromUtf8 except AttributeError: - def _fromUtf8(s): - return 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) + _fromUtf8 = lambda s: s class Ui_MainWindow(object): def setupUi(self, MainWindow): @@ -95,7 +86,13 @@ class Ui_MainWindow(object): font.setPointSize(7) self.pushButtonLoadFromAddressBook.setFont(font) self.pushButtonLoadFromAddressBook.setObjectName(_fromUtf8("pushButtonLoadFromAddressBook")) - self.gridLayout_2.addWidget(self.pushButtonLoadFromAddressBook, 3, 2, 1, 2) + self.gridLayout_2.addWidget(self.pushButtonLoadFromAddressBook, 3, 2, 1, 1) + self.pushButtonFetchNamecoinID = QtGui.QPushButton(self.send) + font = QtGui.QFont() + font.setPointSize(7) + self.pushButtonFetchNamecoinID.setFont(font) + self.pushButtonFetchNamecoinID.setObjectName(_fromUtf8("pushButtonFetchNamecoinID")) + self.gridLayout_2.addWidget(self.pushButtonFetchNamecoinID, 3, 3, 1, 1) self.label_4 = QtGui.QLabel(self.send) self.label_4.setObjectName(_fromUtf8("label_4")) self.gridLayout_2.addWidget(self.label_4, 5, 0, 1, 1) @@ -466,106 +463,97 @@ class Ui_MainWindow(object): MainWindow.setTabOrder(self.tableWidgetConnectionCount, self.pushButtonStatusIcon) def retranslateUi(self, MainWindow): - MainWindow.setWindowTitle(_translate("MainWindow", "Bitmessage", None)) + MainWindow.setWindowTitle(QtGui.QApplication.translate("MainWindow", "Bitmessage", None, QtGui.QApplication.UnicodeUTF8)) self.tableWidgetInbox.setSortingEnabled(True) item = self.tableWidgetInbox.horizontalHeaderItem(0) - item.setText(_translate("MainWindow", "To", None)) + item.setText(QtGui.QApplication.translate("MainWindow", "To", None, QtGui.QApplication.UnicodeUTF8)) item = self.tableWidgetInbox.horizontalHeaderItem(1) - item.setText(_translate("MainWindow", "From", None)) + item.setText(QtGui.QApplication.translate("MainWindow", "From", None, QtGui.QApplication.UnicodeUTF8)) item = self.tableWidgetInbox.horizontalHeaderItem(2) - item.setText(_translate("MainWindow", "Subject", None)) + item.setText(QtGui.QApplication.translate("MainWindow", "Subject", None, QtGui.QApplication.UnicodeUTF8)) item = self.tableWidgetInbox.horizontalHeaderItem(3) - item.setText(_translate("MainWindow", "Received", None)) - self.tabWidget.setTabText(self.tabWidget.indexOf(self.inbox), _translate("MainWindow", "Inbox", None)) - self.pushButtonLoadFromAddressBook.setText(_translate("MainWindow", "Load from Address book", None)) - self.label_4.setText(_translate("MainWindow", "Message:", None)) - self.label_3.setText(_translate("MainWindow", "Subject:", None)) - self.radioButtonSpecific.setText(_translate("MainWindow", "Send to one or more specific people", None)) - self.textEditMessage.setHtml(_translate("MainWindow", "\n" + item.setText(QtGui.QApplication.translate("MainWindow", "Received", None, QtGui.QApplication.UnicodeUTF8)) + self.tabWidget.setTabText(self.tabWidget.indexOf(self.inbox), QtGui.QApplication.translate("MainWindow", "Inbox", None, QtGui.QApplication.UnicodeUTF8)) + self.pushButtonLoadFromAddressBook.setText(QtGui.QApplication.translate("MainWindow", "Load from Address book", None, QtGui.QApplication.UnicodeUTF8)) + self.pushButtonFetchNamecoinID.setText(QtGui.QApplication.translate("MainWindow", "Fetch Namecoin ID", None, QtGui.QApplication.UnicodeUTF8)) + self.label_4.setText(QtGui.QApplication.translate("MainWindow", "Message:", None, QtGui.QApplication.UnicodeUTF8)) + self.label_3.setText(QtGui.QApplication.translate("MainWindow", "Subject:", None, QtGui.QApplication.UnicodeUTF8)) + self.radioButtonSpecific.setText(QtGui.QApplication.translate("MainWindow", "Send to one or more specific people", None, QtGui.QApplication.UnicodeUTF8)) + self.textEditMessage.setHtml(QtGui.QApplication.translate("MainWindow", "\n" "\n" -"


", None)) - self.label.setText(_translate("MainWindow", "To:", None)) - self.label_2.setText(_translate("MainWindow", "From:", None)) - self.radioButtonBroadcast.setText(_translate("MainWindow", "Broadcast to everyone who is subscribed to your address", None)) - self.pushButtonSend.setText(_translate("MainWindow", "Send", None)) - self.labelSendBroadcastWarning.setText(_translate("MainWindow", "Be aware that broadcasts are only encrypted with your address. Anyone who knows your address can read them.", None)) - self.tabWidget.setTabText(self.tabWidget.indexOf(self.send), _translate("MainWindow", "Send", None)) +"


", None, QtGui.QApplication.UnicodeUTF8)) + self.label.setText(QtGui.QApplication.translate("MainWindow", "To:", None, QtGui.QApplication.UnicodeUTF8)) + self.label_2.setText(QtGui.QApplication.translate("MainWindow", "From:", None, QtGui.QApplication.UnicodeUTF8)) + self.radioButtonBroadcast.setText(QtGui.QApplication.translate("MainWindow", "Broadcast to everyone who is subscribed to your address", None, QtGui.QApplication.UnicodeUTF8)) + self.pushButtonSend.setText(QtGui.QApplication.translate("MainWindow", "Send", None, QtGui.QApplication.UnicodeUTF8)) + self.labelSendBroadcastWarning.setText(QtGui.QApplication.translate("MainWindow", "Be aware that broadcasts are only encrypted with your address. Anyone who knows your address can read them.", None, QtGui.QApplication.UnicodeUTF8)) + self.tabWidget.setTabText(self.tabWidget.indexOf(self.send), QtGui.QApplication.translate("MainWindow", "Send", None, QtGui.QApplication.UnicodeUTF8)) self.tableWidgetSent.setSortingEnabled(True) item = self.tableWidgetSent.horizontalHeaderItem(0) - item.setText(_translate("MainWindow", "To", None)) + item.setText(QtGui.QApplication.translate("MainWindow", "To", None, QtGui.QApplication.UnicodeUTF8)) item = self.tableWidgetSent.horizontalHeaderItem(1) - item.setText(_translate("MainWindow", "From", None)) + item.setText(QtGui.QApplication.translate("MainWindow", "From", None, QtGui.QApplication.UnicodeUTF8)) item = self.tableWidgetSent.horizontalHeaderItem(2) - item.setText(_translate("MainWindow", "Subject", None)) + item.setText(QtGui.QApplication.translate("MainWindow", "Subject", None, QtGui.QApplication.UnicodeUTF8)) item = self.tableWidgetSent.horizontalHeaderItem(3) - item.setText(_translate("MainWindow", "Status", None)) - self.tabWidget.setTabText(self.tabWidget.indexOf(self.sent), _translate("MainWindow", "Sent", None)) - self.pushButtonNewAddress.setText(_translate("MainWindow", "New", None)) + item.setText(QtGui.QApplication.translate("MainWindow", "Status", None, QtGui.QApplication.UnicodeUTF8)) + self.tabWidget.setTabText(self.tabWidget.indexOf(self.sent), QtGui.QApplication.translate("MainWindow", "Sent", None, QtGui.QApplication.UnicodeUTF8)) + self.pushButtonNewAddress.setText(QtGui.QApplication.translate("MainWindow", "New", None, QtGui.QApplication.UnicodeUTF8)) self.tableWidgetYourIdentities.setSortingEnabled(True) item = self.tableWidgetYourIdentities.horizontalHeaderItem(0) - item.setText(_translate("MainWindow", "Label (not shown to anyone)", None)) + item.setText(QtGui.QApplication.translate("MainWindow", "Label (not shown to anyone)", None, QtGui.QApplication.UnicodeUTF8)) item = self.tableWidgetYourIdentities.horizontalHeaderItem(1) - item.setText(_translate("MainWindow", "Address", None)) + item.setText(QtGui.QApplication.translate("MainWindow", "Address", None, QtGui.QApplication.UnicodeUTF8)) item = self.tableWidgetYourIdentities.horizontalHeaderItem(2) - item.setText(_translate("MainWindow", "Stream", None)) - self.tabWidget.setTabText(self.tabWidget.indexOf(self.youridentities), _translate("MainWindow", "Your Identities", None)) - self.label_5.setText(_translate("MainWindow", "Here you can subscribe to \'broadcast messages\' that are sent by other users. Messages will appear in your Inbox. Addresses here override those on the Blacklist tab.", None)) - self.pushButtonAddSubscription.setText(_translate("MainWindow", "Add new Subscription", None)) + item.setText(QtGui.QApplication.translate("MainWindow", "Stream", None, QtGui.QApplication.UnicodeUTF8)) + self.tabWidget.setTabText(self.tabWidget.indexOf(self.youridentities), QtGui.QApplication.translate("MainWindow", "Your Identities", None, QtGui.QApplication.UnicodeUTF8)) + self.label_5.setText(QtGui.QApplication.translate("MainWindow", "Here you can subscribe to \'broadcast messages\' that are sent by other users. Messages will appear in your Inbox. Addresses here override those on the Blacklist tab.", None, QtGui.QApplication.UnicodeUTF8)) + self.pushButtonAddSubscription.setText(QtGui.QApplication.translate("MainWindow", "Add new Subscription", None, QtGui.QApplication.UnicodeUTF8)) self.tableWidgetSubscriptions.setSortingEnabled(True) item = self.tableWidgetSubscriptions.horizontalHeaderItem(0) - item.setText(_translate("MainWindow", "Label", None)) + item.setText(QtGui.QApplication.translate("MainWindow", "Label", None, QtGui.QApplication.UnicodeUTF8)) item = self.tableWidgetSubscriptions.horizontalHeaderItem(1) - item.setText(_translate("MainWindow", "Address", None)) - self.tabWidget.setTabText(self.tabWidget.indexOf(self.subscriptions), _translate("MainWindow", "Subscriptions", None)) - self.label_6.setText(_translate("MainWindow", "The Address book is useful for adding names or labels to other people\'s Bitmessage addresses so that you can recognize them more easily in your inbox. You can add entries here using the \'Add\' button, or from your inbox by right-clicking on a message.", None)) - self.pushButtonAddAddressBook.setText(_translate("MainWindow", "Add new entry", None)) + item.setText(QtGui.QApplication.translate("MainWindow", "Address", None, QtGui.QApplication.UnicodeUTF8)) + self.tabWidget.setTabText(self.tabWidget.indexOf(self.subscriptions), QtGui.QApplication.translate("MainWindow", "Subscriptions", None, QtGui.QApplication.UnicodeUTF8)) + self.label_6.setText(QtGui.QApplication.translate("MainWindow", "The Address book is useful for adding names or labels to other people\'s Bitmessage addresses so that you can recognize them more easily in your inbox. You can add entries here using the \'Add\' button, or from your inbox by right-clicking on a message.", None, QtGui.QApplication.UnicodeUTF8)) + self.pushButtonAddAddressBook.setText(QtGui.QApplication.translate("MainWindow", "Add new entry", None, QtGui.QApplication.UnicodeUTF8)) self.tableWidgetAddressBook.setSortingEnabled(True) item = self.tableWidgetAddressBook.horizontalHeaderItem(0) - item.setText(_translate("MainWindow", "Name or Label", None)) + item.setText(QtGui.QApplication.translate("MainWindow", "Name or Label", None, QtGui.QApplication.UnicodeUTF8)) item = self.tableWidgetAddressBook.horizontalHeaderItem(1) - item.setText(_translate("MainWindow", "Address", None)) - self.tabWidget.setTabText(self.tabWidget.indexOf(self.addressbook), _translate("MainWindow", "Address Book", None)) - self.radioButtonBlacklist.setText(_translate("MainWindow", "Use a Blacklist (Allow all incoming messages except those on the Blacklist)", None)) - self.radioButtonWhitelist.setText(_translate("MainWindow", "Use a Whitelist (Block all incoming messages except those on the Whitelist)", None)) - self.pushButtonAddBlacklist.setText(_translate("MainWindow", "Add new entry", None)) + item.setText(QtGui.QApplication.translate("MainWindow", "Address", None, QtGui.QApplication.UnicodeUTF8)) + self.tabWidget.setTabText(self.tabWidget.indexOf(self.addressbook), QtGui.QApplication.translate("MainWindow", "Address Book", None, QtGui.QApplication.UnicodeUTF8)) + self.radioButtonBlacklist.setText(QtGui.QApplication.translate("MainWindow", "Use a Blacklist (Allow all incoming messages except those on the Blacklist)", None, QtGui.QApplication.UnicodeUTF8)) + self.radioButtonWhitelist.setText(QtGui.QApplication.translate("MainWindow", "Use a Whitelist (Block all incoming messages except those on the Whitelist)", None, QtGui.QApplication.UnicodeUTF8)) + self.pushButtonAddBlacklist.setText(QtGui.QApplication.translate("MainWindow", "Add new entry", None, QtGui.QApplication.UnicodeUTF8)) self.tableWidgetBlacklist.setSortingEnabled(True) item = self.tableWidgetBlacklist.horizontalHeaderItem(0) - item.setText(_translate("MainWindow", "Name or Label", None)) + item.setText(QtGui.QApplication.translate("MainWindow", "Name or Label", None, QtGui.QApplication.UnicodeUTF8)) item = self.tableWidgetBlacklist.horizontalHeaderItem(1) - item.setText(_translate("MainWindow", "Address", None)) - self.tabWidget.setTabText(self.tabWidget.indexOf(self.blackwhitelist), _translate("MainWindow", "Blacklist", None)) + item.setText(QtGui.QApplication.translate("MainWindow", "Address", None, QtGui.QApplication.UnicodeUTF8)) + self.tabWidget.setTabText(self.tabWidget.indexOf(self.blackwhitelist), QtGui.QApplication.translate("MainWindow", "Blacklist", None, QtGui.QApplication.UnicodeUTF8)) item = self.tableWidgetConnectionCount.horizontalHeaderItem(0) - item.setText(_translate("MainWindow", "Stream #", None)) + item.setText(QtGui.QApplication.translate("MainWindow", "Stream #", None, QtGui.QApplication.UnicodeUTF8)) item = self.tableWidgetConnectionCount.horizontalHeaderItem(1) - item.setText(_translate("MainWindow", "Connections", None)) - self.labelTotalConnections.setText(_translate("MainWindow", "Total connections: 0", None)) - self.labelStartupTime.setText(_translate("MainWindow", "Since startup at asdf:", None)) - self.labelMessageCount.setText(_translate("MainWindow", "Processed 0 person-to-person message.", None)) - self.labelPubkeyCount.setText(_translate("MainWindow", "Processed 0 public key.", None)) - self.labelBroadcastCount.setText(_translate("MainWindow", "Processed 0 broadcast.", None)) - self.tabWidget.setTabText(self.tabWidget.indexOf(self.networkstatus), _translate("MainWindow", "Network Status", None)) - self.menuFile.setTitle(_translate("MainWindow", "File", None)) - self.menuSettings.setTitle(_translate("MainWindow", "Settings", None)) - self.menuHelp.setTitle(_translate("MainWindow", "Help", None)) - self.actionImport_keys.setText(_translate("MainWindow", "Import keys", None)) - self.actionManageKeys.setText(_translate("MainWindow", "Manage keys", None)) - self.actionExit.setText(_translate("MainWindow", "Quit", None)) - self.actionHelp.setText(_translate("MainWindow", "Help", 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.actionDeleteAllTrashedMessages.setText(_translate("MainWindow", "Delete all trashed messages", None)) + item.setText(QtGui.QApplication.translate("MainWindow", "Connections", None, QtGui.QApplication.UnicodeUTF8)) + self.labelTotalConnections.setText(QtGui.QApplication.translate("MainWindow", "Total connections: 0", None, QtGui.QApplication.UnicodeUTF8)) + self.labelStartupTime.setText(QtGui.QApplication.translate("MainWindow", "Since startup at asdf:", None, QtGui.QApplication.UnicodeUTF8)) + self.labelMessageCount.setText(QtGui.QApplication.translate("MainWindow", "Processed 0 person-to-person message.", None, QtGui.QApplication.UnicodeUTF8)) + self.labelPubkeyCount.setText(QtGui.QApplication.translate("MainWindow", "Processed 0 public key.", None, QtGui.QApplication.UnicodeUTF8)) + self.labelBroadcastCount.setText(QtGui.QApplication.translate("MainWindow", "Processed 0 broadcast.", None, QtGui.QApplication.UnicodeUTF8)) + self.tabWidget.setTabText(self.tabWidget.indexOf(self.networkstatus), QtGui.QApplication.translate("MainWindow", "Network Status", None, QtGui.QApplication.UnicodeUTF8)) + self.menuFile.setTitle(QtGui.QApplication.translate("MainWindow", "File", None, QtGui.QApplication.UnicodeUTF8)) + self.menuSettings.setTitle(QtGui.QApplication.translate("MainWindow", "Settings", None, QtGui.QApplication.UnicodeUTF8)) + self.menuHelp.setTitle(QtGui.QApplication.translate("MainWindow", "Help", None, QtGui.QApplication.UnicodeUTF8)) + self.actionImport_keys.setText(QtGui.QApplication.translate("MainWindow", "Import keys", None, QtGui.QApplication.UnicodeUTF8)) + self.actionManageKeys.setText(QtGui.QApplication.translate("MainWindow", "Manage keys", None, QtGui.QApplication.UnicodeUTF8)) + self.actionExit.setText(QtGui.QApplication.translate("MainWindow", "Quit", None, QtGui.QApplication.UnicodeUTF8)) + self.actionHelp.setText(QtGui.QApplication.translate("MainWindow", "Help", None, QtGui.QApplication.UnicodeUTF8)) + self.actionAbout.setText(QtGui.QApplication.translate("MainWindow", "About", None, QtGui.QApplication.UnicodeUTF8)) + self.actionSettings.setText(QtGui.QApplication.translate("MainWindow", "Settings", None, QtGui.QApplication.UnicodeUTF8)) + self.actionRegenerateDeterministicAddresses.setText(QtGui.QApplication.translate("MainWindow", "Regenerate deterministic addresses", None, QtGui.QApplication.UnicodeUTF8)) + self.actionDeleteAllTrashedMessages.setText(QtGui.QApplication.translate("MainWindow", "Delete all trashed messages", None, QtGui.QApplication.UnicodeUTF8)) import bitmessage_icons_rc - -if __name__ == "__main__": - import sys - app = QtGui.QApplication(sys.argv) - MainWindow = QtGui.QMainWindow() - ui = Ui_MainWindow() - ui.setupUi(MainWindow) - MainWindow.show() - sys.exit(app.exec_()) - diff --git a/src/bitmessageqt/bitmessageui.ui b/src/bitmessageqt/bitmessageui.ui index 48f5c224..e1964592 100644 --- a/src/bitmessageqt/bitmessageui.ui +++ b/src/bitmessageqt/bitmessageui.ui @@ -152,7 +152,7 @@ Send - + @@ -164,6 +164,18 @@ + + + + + 7 + + + + Fetch Namecoin ID + + + From 19331b641a596a0351919c9e1705a42a01e65b75 Mon Sep 17 00:00:00 2001 From: Daniel Kraft Date: Fri, 5 Jul 2013 17:29:49 +0200 Subject: [PATCH 03/13] Start with namecoin connection module. Create a still mostly empty module to encapsulate the namecoin address query, and use it from the UI. --- src/bitmessageqt/__init__.py | 9 ++++++++- src/class_namecoin.py | 20 ++++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 src/class_namecoin.py diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 4c9fd2c0..b04320d2 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -14,6 +14,7 @@ except ImportError: from addresses import * import shared from bitmessageui import * +from class_namecoin import * from newaddressdialog import * from newsubscriptiondialog import * from regenerateaddresses import * @@ -1457,7 +1458,13 @@ class MyForm(QtGui.QMainWindow): "MainWindow", "Right click one or more entries in your address book and select \'Send message to this address\'.")) def click_pushButtonFetchNamecoinID(self): - self.ui.lineEditTo.setText ("BM-Foobar") + nc = namecoinConnection() + err, addr = nc.query("") + if err is not None: + self.statusBar().showMessage(_translate( + "MainWindow", "Error: " + err)) + else: + self.ui.lineEditTo.setText(addr) def redrawLabelFrom(self, index): self.ui.labelFrom.setText( diff --git a/src/class_namecoin.py b/src/class_namecoin.py new file mode 100644 index 00000000..6239cd78 --- /dev/null +++ b/src/class_namecoin.py @@ -0,0 +1,20 @@ +from jsonrpc import ServiceProxy, JSONRPCException + +# This class handles the Namecoin identity integration. + +class namecoinConnection(object): + + def __init__(self): + user = "daniel" + password = "password" + host = "localhost" + port = "8336" + self.s = ServiceProxy ("http://" + user + ":" + password + + "@" + host + ":" + port) + + # 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 + # message to display or None in case of success. + def query(self,string): + return None, "BM-Foobar2" From 9aa82db81f659e0ed93fef11fc0fe2809ae9e475 Mon Sep 17 00:00:00 2001 From: Daniel Kraft Date: Fri, 5 Jul 2013 18:14:47 +0200 Subject: [PATCH 04/13] Basic implementation. Implement very rough first query implementation, with still hardcoded connection details. --- src/bitmessageqt/__init__.py | 2 +- src/class_namecoin.py | 32 +++++++++++++++++++++++++++++--- 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index b04320d2..d6f6d369 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -1459,7 +1459,7 @@ class MyForm(QtGui.QMainWindow): def click_pushButtonFetchNamecoinID(self): nc = namecoinConnection() - err, addr = nc.query("") + err, addr = nc.query(str(self.ui.lineEditTo.text())) if err is not None: self.statusBar().showMessage(_translate( "MainWindow", "Error: " + err)) diff --git a/src/class_namecoin.py b/src/class_namecoin.py index 6239cd78..d5a9543a 100644 --- a/src/class_namecoin.py +++ b/src/class_namecoin.py @@ -1,3 +1,4 @@ +import json from jsonrpc import ServiceProxy, JSONRPCException # This class handles the Namecoin identity integration. @@ -9,12 +10,37 @@ class namecoinConnection(object): password = "password" host = "localhost" port = "8336" - self.s = ServiceProxy ("http://" + user + ":" + password - + "@" + host + ":" + port) + self.s = ServiceProxy("http://" + user + ":" + password + + "@" + host + ":" + port) # 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 # message to display or None in case of success. def query(self,string): - return None, "BM-Foobar2" + slashPos = string.find("/") + if slashPos < 0: + string = "id/" + string + + try: + res = self.s.name_show(string) + except JSONRPCException as err: + if err.error["code"] == -4: + return ("The name '" + string + "' was not found.", None) + else: + return ("The namecoin query failed (" + + err.error["message"] + ")", None) + except: + return ("The namecoin query failed.", None) + + try: + print res["value"] + val = json.loads(res["value"]) + except: + return ("The name '" + string + "' has no valid JSON data.", None) + + if "bitmessage" in val: + return (None, val["bitmessage"]) + + return ("The name '" + string + + "' has no associated Bitmessage address.", None) From 09c0aa993fc533542c666b0c4ee959484c42c7e4 Mon Sep 17 00:00:00 2001 From: Daniel Kraft Date: Fri, 5 Jul 2013 19:08:39 +0200 Subject: [PATCH 05/13] Implement JSON RPC myself. Write my own implementation of JSON RPC and HTTP queries, because the jsonrpc module failed to let me configure what to do with failed HTTP authentications. --- src/bitmessageqt/__init__.py | 2 +- src/class_namecoin.py | 142 +++++++++++++++++++++++++++++------ 2 files changed, 119 insertions(+), 25 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index d6f6d369..6374a81f 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -14,7 +14,7 @@ except ImportError: from addresses import * import shared from bitmessageui import * -from class_namecoin import * +from class_namecoin import namecoinConnection from newaddressdialog import * from newsubscriptiondialog import * from regenerateaddresses import * diff --git a/src/class_namecoin.py b/src/class_namecoin.py index d5a9543a..f11cd97b 100644 --- a/src/class_namecoin.py +++ b/src/class_namecoin.py @@ -1,46 +1,140 @@ +# Copyright (C) 2013 by Daniel Kraft +# This file is part of the Bitmessage project. +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +import base64 import json -from jsonrpc import ServiceProxy, JSONRPCException +import socket + +# Error thrown when the RPC call returns an error. +class RPCError (Exception): + error = None + + def __init__ (self, data): + self.error = data # This class handles the Namecoin identity integration. +class namecoinConnection (object): + user = None + password = None + host = None + port = None + bufsize = 4096 + queryid = 1 -class namecoinConnection(object): - - def __init__(self): - user = "daniel" - password = "password" - host = "localhost" - port = "8336" - self.s = ServiceProxy("http://" + user + ":" + password - + "@" + host + ":" + port) + def __init__ (self): + self.user = "daniel" + self.password = "password" + self.host = "localhost" + self.port = "8336" # 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 # message to display or None in case of success. - def query(self,string): - slashPos = string.find("/") + def query (self, string): + slashPos = string.find ("/") if slashPos < 0: string = "id/" + string try: - res = self.s.name_show(string) - except JSONRPCException as err: - if err.error["code"] == -4: - return ("The name '" + string + "' was not found.", None) + res = self.callRPC ("name_show", [string]) + except RPCError as exc: + if exc.error["code"] == -4: + return ("The name '%s' was not found." % string, None) else: - return ("The namecoin query failed (" - + err.error["message"] + ")", None) - except: + return ("The namecoin query failed (%s)" % exc.error["message"], + None) + except Exception as exc: + print "Namecoin query exception: %s" % str (exc) return ("The namecoin query failed.", None) try: - print res["value"] - val = json.loads(res["value"]) + val = json.loads (res["value"]) except: - return ("The name '" + string + "' has no valid JSON data.", None) + return ("The name '%s' has no valid JSON data." % string, None) if "bitmessage" in val: return (None, val["bitmessage"]) - return ("The name '" + string - + "' has no associated Bitmessage address.", None) + return ("The name '%s' has no associated Bitmessage address." % string, + None) + + # 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)) + val = json.loads (resp) + + if val["id"] != self.queryid: + raise Exception ("ID mismatch in JSON RPC answer.") + self.queryid = self.queryid + 1 + + if val["error"] is not None: + raise RPCError (val["error"]) + + return val["result"] + + # Query the server via HTTP. + def queryHTTP (self, data): + header = "POST / HTTP/1.1\n" + header += "User-Agent: bitmessage\n" + header += "Host: %s\n" % self.host + header += "Content-Type: application/json\n" + header += "Content-Length: %d\n" % len (data) + header += "Accept: application/json\n" + authstr = "%s:%s" % (self.user, self.password) + header += "Authorization: Basic %s\n" % base64.b64encode (authstr) + + resp = self.queryServer ("%s\n%s" % (header, data)) + lines = resp.split ("\r\n") + result = None + body = False + for line in lines: + if line == "" and not body: + body = True + elif body: + if result is not None: + raise Exception ("Expected a single line in HTTP response.") + result = line + + return result + + # Helper routine sending data to the RPC server and returning the result. + def queryServer (self, data): + try: + s = socket.socket (socket.AF_INET, socket.SOCK_STREAM) + s.setsockopt (socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + s.connect ((self.host, int (self.port))) + s.sendall (data) + result = "" + + while True: + tmp = s.recv (self.bufsize) + if not tmp: + break + result += tmp + + s.close () + + return result + + except socket.error as exc: + raise Exception ("Socket error in RPC connection: %s" % str (exc)) From 03bb54fc98b5a1244fa510dcb0e97df296ed539e Mon Sep 17 00:00:00 2001 From: Daniel Kraft Date: Fri, 5 Jul 2013 20:08:19 +0200 Subject: [PATCH 06/13] Handle options for RPC connection. Handle config options for RPC connection, and also implement loading default user/password from namecoin config file. No UI yet. --- src/bitmessageqt/__init__.py | 2 +- src/helper_startup.py | 3 + src/{class_namecoin.py => namecoin.py} | 78 ++++++++++++++++++++++++-- 3 files changed, 78 insertions(+), 5 deletions(-) rename src/{class_namecoin.py => namecoin.py} (61%) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 6374a81f..3064ef4f 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -14,7 +14,7 @@ except ImportError: from addresses import * import shared from bitmessageui import * -from class_namecoin import namecoinConnection +from namecoin import namecoinConnection from newaddressdialog import * from newsubscriptiondialog import * from regenerateaddresses import * diff --git a/src/helper_startup.py b/src/helper_startup.py index e6590b0e..e3df91d6 100644 --- a/src/helper_startup.py +++ b/src/helper_startup.py @@ -3,6 +3,8 @@ import ConfigParser import sys import os +from namecoin import ensureNamecoinOptions + storeConfigFilesInSameDirectoryAsProgramByDefault = False # The user may de-select Portable Mode in the settings if they want the config files to stay in the application data folder. def loadConfig(): @@ -64,6 +66,7 @@ def loadConfig(): 'bitmessagesettings', 'maxacceptablenoncetrialsperbyte', '0') shared.config.set( 'bitmessagesettings', 'maxacceptablepayloadlengthextrabytes', '0') + ensureNamecoinOptions() if storeConfigFilesInSameDirectoryAsProgramByDefault: # Just use the same directory as the program and forget about diff --git a/src/class_namecoin.py b/src/namecoin.py similarity index 61% rename from src/class_namecoin.py rename to src/namecoin.py index f11cd97b..184545f9 100644 --- a/src/class_namecoin.py +++ b/src/namecoin.py @@ -22,6 +22,11 @@ import base64 import json import socket +import sys + +import shared + +configSection = "bitmessagesettings" # Error thrown when the RPC call returns an error. class RPCError (Exception): @@ -40,10 +45,11 @@ class namecoinConnection (object): queryid = 1 def __init__ (self): - self.user = "daniel" - self.password = "password" - self.host = "localhost" - self.port = "8336" + ensureNamecoinOptions () + self.user = shared.config.get (configSection, "namecoinrpcuser") + self.password = shared.config.get (configSection, "namecoinrpcpassword") + self.host = shared.config.get (configSection, "namecoinrpchost") + self.port = shared.config.get (configSection, "namecoinrpcport") # Query for the bitmessage address corresponding to the given identity # string. If it doesn't contain a slash, id/ is prepended. We return @@ -138,3 +144,67 @@ class namecoinConnection (object): except socket.error as exc: raise Exception ("Socket error in RPC connection: %s" % str (exc)) + +# Look up the namecoin data folder. +# FIXME: Check whether this works on other platforms as well! +def lookupNamecoinFolder (): + app = "namecoin" + from os import path, environ + if sys.platform == "darwin": + if "HOME" in environ: + dataFolder = path.join (os.environ["HOME"], + "Library/Application Support/", app) + '/' + else: + print ("Could not find home folder, please report this message" + + " and your OS X version to the BitMessage Github.") + sys.exit() + + elif "win32" in sys.platform or "win64" in sys.platform: + dataFolder = path.join(environ["APPDATA"], app) + "\\" + else: + dataFolder = path.join(environ["HOME"], ".%s" % app) + "/" + + return dataFolder + +# 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, "namecoinrpchost"): + shared.config.set (configSection, "namecoinrpchost", "localhost") + if not shared.config.has_option (configSection, "namecoinrpcport"): + shared.config.set (configSection, "namecoinrpcport", "8336") + + hasUser = shared.config.has_option (configSection, "namecoinrpcuser") + hasPass = shared.config.has_option (configSection, "namecoinrpcpassword") + + # Try to read user/password from .namecoin configuration file. + if (not hasUser) or (not hasPass): + try: + nmcFolder = lookupNamecoinFolder () + nmcConfig = nmcFolder + "bitcoin.conf" + nmc = open (nmcConfig, "r") + + while True: + line = nmc.readline () + if line == "": + break + parts = line.split ("=") + if len (parts) == 2: + key = parts[0] + val = parts[1].rstrip () + + if key == "rpcuser" and not hasUser: + shared.config.set (configSection, + "namecoinrpcuser", val) + if key == "rpcpassword" and not hasPass: + shared.config.set (configSection, + "namecoinrpcpassword", val) + + nmc.close () + + except Exception as exc: + print "Failure reading namecoin config file: %s" % str (exc) + if (not hasUser): + shared.config.set (configSection, "namecoinrpcuser", "") + if (not hasPass): + shared.config.set (configSection, "namecoinrpcpassword", "") From 68fbc4b344a4fd6601c7147ed96f43053758998a Mon Sep 17 00:00:00 2001 From: Daniel Kraft Date: Sun, 7 Jul 2013 17:34:43 +0200 Subject: [PATCH 07/13] UI for namecoin connection settings. Add a pane to the settings dialog UI which allows to edit the connection settings for namecoin. --- src/bitmessageqt/__init__.py | 23 +++++- src/bitmessageqt/settings.py | 59 ++++++++++++++- src/bitmessageqt/settings.ui | 141 +++++++++++++++++++++++++++++++++++ 3 files changed, 220 insertions(+), 3 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 90da7881..88512a21 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -14,7 +14,7 @@ except ImportError: from addresses import * import shared from bitmessageui import * -from namecoin import namecoinConnection +from namecoin import namecoinConnection, ensureNamecoinOptions from newaddressdialog import * from newsubscriptiondialog import * from regenerateaddresses import * @@ -1776,6 +1776,16 @@ class MyForm(QtGui.QMainWindow): self.settingsDialogInstance.ui.lineEditSocksUsername.text())) shared.config.set('bitmessagesettings', 'sockspassword', str( self.settingsDialogInstance.ui.lineEditSocksPassword.text())) + + shared.config.set('bitmessagesettings', 'namecoinrpchost', str( + self.settingsDialogInstance.ui.lineEditNamecoinHost.text())) + shared.config.set('bitmessagesettings', 'namecoinrpcport', str( + self.settingsDialogInstance.ui.lineEditNamecoinPort.text())) + shared.config.set('bitmessagesettings', 'namecoinrpcuser', str( + self.settingsDialogInstance.ui.lineEditNamecoinUser.text())) + shared.config.set('bitmessagesettings', 'namecoinrpcpassword', str( + self.settingsDialogInstance.ui.lineEditNamecoinPassword.text())) + if float(self.settingsDialogInstance.ui.lineEditTotalDifficulty.text()) >= 1: shared.config.set('bitmessagesettings', 'defaultnoncetrialsperbyte', str(int(float( self.settingsDialogInstance.ui.lineEditTotalDifficulty.text()) * shared.networkDefaultProofOfWorkNonceTrialsPerByte))) @@ -2739,6 +2749,17 @@ class settingsDialog(QtGui.QDialog): self.ui.lineEditMaxAcceptableSmallMessageDifficulty.setText(str((float(shared.config.getint( 'bitmessagesettings', 'maxacceptablepayloadlengthextrabytes')) / shared.networkDefaultPayloadLengthExtraBytes))) + # Namecoin integration tab + ensureNamecoinOptions() + self.ui.lineEditNamecoinHost.setText(str( + shared.config.get('bitmessagesettings', 'namecoinrpchost'))) + self.ui.lineEditNamecoinPort.setText(str( + shared.config.get('bitmessagesettings', 'namecoinrpcport'))) + self.ui.lineEditNamecoinUser.setText(str( + shared.config.get('bitmessagesettings', 'namecoinrpcuser'))) + self.ui.lineEditNamecoinPassword.setText(str( + shared.config.get('bitmessagesettings', 'namecoinrpcpassword'))) + #'System' tab removed for now. """try: maxCores = shared.config.getint('bitmessagesettings', 'maxcores') diff --git a/src/bitmessageqt/settings.py b/src/bitmessageqt/settings.py index 8c94333c..d11859b2 100644 --- a/src/bitmessageqt/settings.py +++ b/src/bitmessageqt/settings.py @@ -2,8 +2,8 @@ # Form implementation generated from reading ui file 'settings.ui' # -# Created: Mon Jun 10 11:31:56 2013 -# by: PyQt4 UI code generator 4.9.4 +# Created: Sun Jul 7 17:25:43 2013 +# by: PyQt4 UI code generator 4.9.3 # # WARNING! All changes made in this file will be lost! @@ -215,6 +215,55 @@ class Ui_settingsDialog(object): spacerItem7 = QtGui.QSpacerItem(20, 147, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding) self.gridLayout_7.addItem(spacerItem7, 3, 1, 1, 1) self.tabWidgetSettings.addTab(self.tab_2, _fromUtf8("")) + self.tabNamecoin = QtGui.QWidget() + self.tabNamecoin.setObjectName(_fromUtf8("tabNamecoin")) + 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.label_16 = QtGui.QLabel(self.tabNamecoin) + self.label_16.setWordWrap(True) + 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.setObjectName(_fromUtf8("label_17")) + self.gridLayout_8.addWidget(self.label_17, 1, 1, 1, 1) + self.lineEditNamecoinHost = QtGui.QLineEdit(self.tabNamecoin) + self.lineEditNamecoinHost.setObjectName(_fromUtf8("lineEditNamecoinHost")) + self.gridLayout_8.addWidget(self.lineEditNamecoinHost, 1, 2, 1, 1) + spacerItem9 = QtGui.QSpacerItem(40, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum) + self.gridLayout_8.addItem(spacerItem9, 2, 0, 1, 1) + self.label_18 = QtGui.QLabel(self.tabNamecoin) + 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.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, 5, 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.lineEditNamecoinUser = QtGui.QLineEdit(self.tabNamecoin) + self.lineEditNamecoinUser.setObjectName(_fromUtf8("lineEditNamecoinUser")) + self.gridLayout_8.addWidget(self.lineEditNamecoinUser, 3, 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.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.tabWidgetSettings.addTab(self.tabNamecoin, _fromUtf8("")) self.gridLayout.addWidget(self.tabWidgetSettings, 0, 0, 1, 1) self.retranslateUi(settingsDialog) @@ -269,4 +318,10 @@ 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_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.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 a1bb7c88..24132635 100644 --- a/src/bitmessageqt/settings.ui +++ b/src/bitmessageqt/settings.ui @@ -491,6 +491,147 @@ + + + Namecoin integration + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + 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. + + + true + + + + + + + Host: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Port: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Username: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Password: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Qt::ImhHiddenText|Qt::ImhNoAutoUppercase|Qt::ImhNoPredictiveText + + + QLineEdit::Password + + + + + From 213d92b88a48a09fcc7edf96191b3ed1d2a07baf Mon Sep 17 00:00:00 2001 From: Daniel Kraft Date: Sun, 7 Jul 2013 18:41:13 +0200 Subject: [PATCH 08/13] Add UI to test namecoin connection. Add a test button to namecoin UI settings, which tries out the connection and reports its result back. Also use namecoin.conf as config file to load default RPC user/pass combination from. --- src/bitmessageqt/__init__.py | 13 ++++++++++ src/bitmessageqt/settings.py | 12 +++++++-- src/bitmessageqt/settings.ui | 16 +++++++++++- src/namecoin.py | 48 ++++++++++++++++++++++++++++++------ 4 files changed, 79 insertions(+), 10 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 88512a21..ba967bb7 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -2759,6 +2759,8 @@ class settingsDialog(QtGui.QDialog): shared.config.get('bitmessagesettings', 'namecoinrpcuser'))) self.ui.lineEditNamecoinPassword.setText(str( shared.config.get('bitmessagesettings', 'namecoinrpcpassword'))) + QtCore.QObject.connect(self.ui.pushButtonNamecoinTest, QtCore.SIGNAL( + "clicked()"), self.click_pushButtonNamecoinTest) #'System' tab removed for now. """try: @@ -2797,6 +2799,17 @@ class settingsDialog(QtGui.QDialog): self.ui.lineEditSocksPassword.setEnabled(True) self.ui.lineEditTCPPort.setEnabled(False) + # Test the namecoin settings specified in the settings dialog. + def click_pushButtonNamecoinTest(self): + options = {} + options["host"] = self.ui.lineEditNamecoinHost.text() + options["port"] = self.ui.lineEditNamecoinPort.text() + options["user"] = self.ui.lineEditNamecoinUser.text() + options["password"] = self.ui.lineEditNamecoinPassword.text() + nc = namecoinConnection(options) + res = nc.test() + self.ui.labelNamecoinTestResult.setText(res) + class SpecialAddressBehaviorDialog(QtGui.QDialog): diff --git a/src/bitmessageqt/settings.py b/src/bitmessageqt/settings.py index d11859b2..2f93ce88 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 17:25:43 2013 +# Created: Sun Jul 7 18:40:01 2013 # by: PyQt4 UI code generator 4.9.3 # # WARNING! All changes made in this file will be lost! @@ -242,7 +242,7 @@ class Ui_settingsDialog(object): 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, 5, 1, 1, 1) + 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) @@ -263,6 +263,13 @@ class Ui_settingsDialog(object): self.lineEditNamecoinPassword.setEchoMode(QtGui.QLineEdit.Password) self.lineEditNamecoinPassword.setObjectName(_fromUtf8("lineEditNamecoinPassword")) self.gridLayout_8.addWidget(self.lineEditNamecoinPassword, 4, 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.pushButtonNamecoinTest = QtGui.QPushButton(self.tabNamecoin) + self.pushButtonNamecoinTest.setObjectName(_fromUtf8("pushButtonNamecoinTest")) + self.gridLayout_8.addWidget(self.pushButtonNamecoinTest, 6, 2, 1, 1) self.tabWidgetSettings.addTab(self.tabNamecoin, _fromUtf8("")) self.gridLayout.addWidget(self.tabWidgetSettings, 0, 0, 1, 1) @@ -323,5 +330,6 @@ class Ui_settingsDialog(object): 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.pushButtonNamecoinTest.setText(QtGui.QApplication.translate("settingsDialog", "Test", 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 24132635..4c1e14eb 100644 --- a/src/bitmessageqt/settings.ui +++ b/src/bitmessageqt/settings.ui @@ -558,7 +558,7 @@ - + Qt::Vertical @@ -630,6 +630,20 @@ + + + + + + + + + + + Test + + + diff --git a/src/namecoin.py b/src/namecoin.py index 184545f9..9e98c2d0 100644 --- a/src/namecoin.py +++ b/src/namecoin.py @@ -44,12 +44,23 @@ class namecoinConnection (object): bufsize = 4096 queryid = 1 - def __init__ (self): - ensureNamecoinOptions () - self.user = shared.config.get (configSection, "namecoinrpcuser") - self.password = shared.config.get (configSection, "namecoinrpcpassword") - self.host = shared.config.get (configSection, "namecoinrpchost") - self.port = shared.config.get (configSection, "namecoinrpcport") + # Initialise. If options are given, take the connection settings from + # them instead of loading from the configs. This can be used to test + # currently entered connection settings in the config dialog without + # actually changing the values (yet). + def __init__ (self, options = None): + if options is None: + ensureNamecoinOptions () + 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.host = options["host"] + self.port = options["port"] + self.user = options["user"] + self.password = options["password"] # Query for the bitmessage address corresponding to the given identity # string. If it doesn't contain a slash, id/ is prepended. We return @@ -83,6 +94,29 @@ class namecoinConnection (object): return ("The name '%s' has no associated Bitmessage address." % string, None) + # Test the connection settings. This routine tries to query a "getinfo" + # command, and builds either an error message or a success message with + # 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) + else: + versStr = "0.%d.%d.%d" % (v1, v2, v3) + + return "Success! Namecoind version %s running." % versStr + + except: + return "The connection to namecoind failed." + # Helper routine that actually performs an JSON RPC call. def callRPC (self, method, params): data = {"method": method, "params": params, "id": self.queryid} @@ -181,7 +215,7 @@ def ensureNamecoinOptions (): if (not hasUser) or (not hasPass): try: nmcFolder = lookupNamecoinFolder () - nmcConfig = nmcFolder + "bitcoin.conf" + nmcConfig = nmcFolder + "namecoin.conf" nmc = open (nmcConfig, "r") while True: From 06bdc030bd7ba700359786e8e593313e97b93238 Mon Sep 17 00:00:00 2001 From: Daniel Kraft Date: Sun, 7 Jul 2013 18:43:09 +0200 Subject: [PATCH 09/13] Report success in status bar. Report success when fetching a BM address from namecoin in the status bar. --- src/bitmessageqt/__init__.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index ba967bb7..69f9126b 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -1465,6 +1465,8 @@ class MyForm(QtGui.QMainWindow): "MainWindow", "Error: " + err)) else: self.ui.lineEditTo.setText(addr) + self.statusBar().showMessage(_translate( + "MainWindow", "Fetched address from namecoin identity.")) def redrawLabelFrom(self, index): self.ui.labelFrom.setText( From 92e297076730e0b17fa6885ced305fc08aa77161 Mon Sep 17 00:00:00 2001 From: Daniel Kraft Date: Sun, 7 Jul 2013 20:04:57 +0200 Subject: [PATCH 10/13] 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"): From 810387df3eb652d7db688d337369503ff437ce30 Mon Sep 17 00:00:00 2001 From: Daniel Kraft Date: Wed, 17 Jul 2013 18:33:26 +0200 Subject: [PATCH 11/13] Read also rpcport from namecoin.conf. Read also the rpcport setting from namecoin.conf when it is available and use that as default when switching the setting in the UI dialog. --- src/bitmessageqt/__init__.py | 2 +- src/namecoin.py | 55 ++++++++++++++++++------------------ src/shared.py | 7 ++++- 3 files changed, 35 insertions(+), 29 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 748f6954..1a7dbc42 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -2936,7 +2936,7 @@ class settingsDialog(QtGui.QDialog): self.ui.labelNamecoinPassword.setEnabled(isNamecoind) if isNamecoind: - self.ui.lineEditNamecoinPort.setText("8336") + self.ui.lineEditNamecoinPort.setText(shared.namecoinDefaultRpcPort) else: self.ui.lineEditNamecoinPort.setText("9000") diff --git a/src/namecoin.py b/src/namecoin.py index 17cd74ea..5ad1c049 100644 --- a/src/namecoin.py +++ b/src/namecoin.py @@ -247,33 +247,34 @@ def ensureNamecoinOptions (): hasPass = shared.config.has_option (configSection, "namecoinrpcpassword") # Try to read user/password from .namecoin configuration file. - if (not hasUser) or (not hasPass): - try: - nmcFolder = lookupNamecoinFolder () - nmcConfig = nmcFolder + "namecoin.conf" - nmc = open (nmcConfig, "r") + try: + nmcFolder = lookupNamecoinFolder () + nmcConfig = nmcFolder + "namecoin.conf" + nmc = open (nmcConfig, "r") - while True: - line = nmc.readline () - if line == "": - break - parts = line.split ("=") - if len (parts) == 2: - key = parts[0] - val = parts[1].rstrip () + while True: + line = nmc.readline () + if line == "": + break + parts = line.split ("=") + if len (parts) == 2: + key = parts[0] + val = parts[1].rstrip () - if key == "rpcuser" and not hasUser: - shared.config.set (configSection, - "namecoinrpcuser", val) - if key == "rpcpassword" and not hasPass: - shared.config.set (configSection, - "namecoinrpcpassword", val) - - nmc.close () + if key == "rpcuser" and not hasUser: + shared.config.set (configSection, + "namecoinrpcuser", val) + if key == "rpcpassword" and not hasPass: + shared.config.set (configSection, + "namecoinrpcpassword", val) + if key == "rpcport": + shared.namecoinDefaultRpcPort = val + + nmc.close () - except Exception as exc: - print "Failure reading namecoin config file: %s" % str (exc) - if (not hasUser): - shared.config.set (configSection, "namecoinrpcuser", "") - if (not hasPass): - shared.config.set (configSection, "namecoinrpcpassword", "") + except Exception as exc: + print "Failure reading namecoin config file: %s" % str (exc) + if (not hasUser): + shared.config.set (configSection, "namecoinrpcuser", "") + if (not hasPass): + shared.config.set (configSection, "namecoinrpcpassword", "") diff --git a/src/shared.py b/src/shared.py index 557b332d..98e540d7 100644 --- a/src/shared.py +++ b/src/shared.py @@ -68,6 +68,11 @@ ackdataForWhichImWatching = {} networkDefaultProofOfWorkNonceTrialsPerByte = 320 #The amount of work that should be performed (and demanded) per byte of the payload. Double this number to double the work. networkDefaultPayloadLengthExtraBytes = 14000 #To make sending short messages a little more difficult, this value is added to the payload length for use in calculating the proof of work target. +# Remember here the RPC port read from namecoin.conf so we can restore to +# it as default whenever the user changes the "method" selection for +# namecoin integration to "namecoind". +namecoinDefaultRpcPort = "8336" + def isInSqlInventory(hash): t = (hash,) shared.sqlLock.acquire() @@ -371,4 +376,4 @@ def fixSensitiveFilePermissions(filename, hasEnabledKeys): raise helper_startup.loadConfig() -from debug import logger \ No newline at end of file +from debug import logger From 25f0192fd6f902d714a75b23ca5ab083290b9511 Mon Sep 17 00:00:00 2001 From: Daniel Kraft Date: Wed, 17 Jul 2013 18:40:02 +0200 Subject: [PATCH 12/13] Also set RPC port default from namecoin.conf Also use the found rpcport in namecoin.conf to initialise the RPC port setting at first if it is not yet set. --- src/namecoin.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/namecoin.py b/src/namecoin.py index 5ad1c049..02f80639 100644 --- a/src/namecoin.py +++ b/src/namecoin.py @@ -240,11 +240,10 @@ def ensureNamecoinOptions (): 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"): - shared.config.set (configSection, "namecoinrpcport", "8336") hasUser = shared.config.has_option (configSection, "namecoinrpcuser") hasPass = shared.config.has_option (configSection, "namecoinrpcpassword") + hasPort = shared.config.has_option (configSection, "namecoinrpcport") # Try to read user/password from .namecoin configuration file. try: @@ -269,6 +268,7 @@ def ensureNamecoinOptions (): "namecoinrpcpassword", val) if key == "rpcport": shared.namecoinDefaultRpcPort = val + # Will be set in config below anyway. nmc.close () @@ -278,3 +278,8 @@ def ensureNamecoinOptions (): shared.config.set (configSection, "namecoinrpcuser", "") if (not hasPass): shared.config.set (configSection, "namecoinrpcpassword", "") + + # Set default port now, possibly to found value. + if (not hasPort): + shared.config.set (configSection, "namecoinrpcport", + shared.namecoinDefaultRpcPort) From 260bc80afeee4d76c53cf5c5551bb91984fdf5ce Mon Sep 17 00:00:00 2001 From: Daniel Kraft Date: Thu, 18 Jul 2013 07:09:49 +0200 Subject: [PATCH 13/13] Get default user/password in every case. Tweaks to fetching user/password from namecoin.conf that should now always set values (in particular even if namecoin.conf is there but has no rpcuser / rpcpassword set). --- src/namecoin.py | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/namecoin.py b/src/namecoin.py index 02f80639..57059a1c 100644 --- a/src/namecoin.py +++ b/src/namecoin.py @@ -246,6 +246,8 @@ def ensureNamecoinOptions (): hasPort = shared.config.has_option (configSection, "namecoinrpcport") # Try to read user/password from .namecoin configuration file. + defaultUser = "" + defaultPass = "" try: nmcFolder = lookupNamecoinFolder () nmcConfig = nmcFolder + "namecoin.conf" @@ -261,23 +263,22 @@ def ensureNamecoinOptions (): val = parts[1].rstrip () if key == "rpcuser" and not hasUser: - shared.config.set (configSection, - "namecoinrpcuser", val) + defaultUser = val if key == "rpcpassword" and not hasPass: - shared.config.set (configSection, - "namecoinrpcpassword", val) + defaultPass = val if key == "rpcport": shared.namecoinDefaultRpcPort = val - # Will be set in config below anyway. nmc.close () except Exception as exc: print "Failure reading namecoin config file: %s" % str (exc) - if (not hasUser): - shared.config.set (configSection, "namecoinrpcuser", "") - if (not hasPass): - shared.config.set (configSection, "namecoinrpcpassword", "") + + # If still nothing found, set empty at least. + if (not hasUser): + shared.config.set (configSection, "namecoinrpcuser", defaultUser) + if (not hasPass): + shared.config.set (configSection, "namecoinrpcpassword", defaultPass) # Set default port now, possibly to found value. if (not hasPort):