From 9044e8409304ecf2542128041cef86c752b80dd6 Mon Sep 17 00:00:00 2001 From: Jonathan Warren Date: Tue, 3 Mar 2015 14:04:12 -0500 Subject: [PATCH 1/4] some specifyTTL work completed --- src/bitmessageqt/__init__.py | 56 ++++-- src/bitmessageqt/bitmessageui.py | 143 +++++++++------ src/bitmessageqt/bitmessageui.ui | 288 +++++++++++++++++++++---------- src/class_sqlThread.py | 4 + src/helper_startup.py | 1 + 5 files changed, 339 insertions(+), 153 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 1e5acdca..38d025dd 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -212,6 +212,8 @@ class MyForm(QtGui.QMainWindow): "clicked()"), self.click_pushButtonAddSubscription) QtCore.QObject.connect(self.ui.pushButtonAddBlacklist, QtCore.SIGNAL( "clicked()"), self.click_pushButtonAddBlacklist) + QtCore.QObject.connect(self.ui.pushButtonTTL, QtCore.SIGNAL( + "clicked()"), self.click_pushButtonTTL) QtCore.QObject.connect(self.ui.pushButtonSend, QtCore.SIGNAL( "clicked()"), self.click_pushButtonSend) QtCore.QObject.connect(self.ui.pushButtonLoadFromAddressBook, @@ -648,6 +650,18 @@ class MyForm(QtGui.QMainWindow): self.rerenderComboBoxSendFrom() + # Put the TTL slider in the correct spot + TTL = shared.config.getint('bitmessagesettings', 'ttl') + if TTL < 3600: # an hour + TTL = 3600 + elif TTL > 28*24*60*60: # 28 days + TTL = 28*24*60*60 + self.ui.horizontalSliderTTL.setSliderPosition((TTL - 3600) ** (1/3.199)) + self.updateHumanFriendlyTTLDescription(TTL) + + QtCore.QObject.connect(self.ui.horizontalSliderTTL, QtCore.SIGNAL( + "valueChanged(int)"), self.updateTTL) + # Check to see whether we can connect to namecoin. Hide the 'Fetch Namecoin ID' button if we can't. try: options = {} @@ -662,7 +676,23 @@ class MyForm(QtGui.QMainWindow): except: print 'There was a problem testing for a Namecoin daemon. Hiding the Fetch Namecoin ID button' self.ui.pushButtonFetchNamecoinID.hide() - + + def updateTTL(self, sliderPosition): + TTL = int(sliderPosition ** 3.199 + 3600) + self.updateHumanFriendlyTTLDescription(TTL) + shared.config.set('bitmessagesettings', 'ttl', str(TTL)) + shared.writeKeysFile() + + def updateHumanFriendlyTTLDescription(self, TTL): + numberOfHours = int(round(TTL / (60*60))) + if numberOfHours < 48: + if numberOfHours == 1: + self.ui.labelHumanFriendlyTTLDescription.setText(_translate("MainWindow", "1 hour")) + else: + self.ui.labelHumanFriendlyTTLDescription.setText(_translate("MainWindow", "%1 hours").arg(numberOfHours)) + else: + numberOfDays = int(round(TTL / (24*60*60))) + self.ui.labelHumanFriendlyTTLDescription.setText(_translate("MainWindow", "%1 days").arg(numberOfDays)) # Show or hide the application window after clicking an item within the # tray icon or, on Windows, the try icon itself. @@ -1868,6 +1898,14 @@ class MyForm(QtGui.QMainWindow): newItem.setTextColor(QtGui.QColor(128, 128, 128)) self.ui.tableWidgetBlacklist.setItem(0, 1, newItem) + def click_pushButtonTTL(self): + QtGui.QMessageBox.information(self, 'Time To Live', _translate( + "MainWindow", "The TTL, or Time-To-Live is the length of time that the network will hold the message. \ +The recipient must get it during this time. If your client does not hear an acknowledgement, your \ +Bitmessage client will resend the message automatically if it is open. The longer the Time-To-Live, the \ +more work your computer must do to send the message. A Time-To-Live of four or five days is often appropriate."), QMessageBox.Ok) + ############### + def click_pushButtonSend(self): self.statusBar().showMessage('') toAddresses = str(self.ui.lineEditTo.text()) @@ -1953,10 +1991,11 @@ class MyForm(QtGui.QMainWindow): ackdata, int(time.time()), 'msgqueued', - 1, - 1, + 1, # pubkeyretrynumber + 1, # msgretrynumber 'sent', - 2) + 2 # encodingtype + ) toLabel = '' queryreturn = sqlQuery('''select label from addressbook where address=?''', @@ -2421,13 +2460,6 @@ class MyForm(QtGui.QMainWindow): self.settingsDialogInstance.ui.lineEditDays.text()))) shared.config.set('bitmessagesettings', 'stopresendingafterxmonths', str(float( self.settingsDialogInstance.ui.lineEditMonths.text()))) - #end - - # if str(self.settingsDialogInstance.ui.comboBoxMaxCores.currentText()) == 'All': - # shared.config.set('bitmessagesettings', 'maxcores', '99999') - # else: - # shared.config.set('bitmessagesettings', 'maxcores', - # str(self.settingsDialogInstance.ui.comboBoxMaxCores.currentText())) shared.writeKeysFile() @@ -3756,8 +3788,6 @@ class NewAddressDialog(QtGui.QDialog): # the 'Your Identities' tab. while self.parent.ui.tableWidgetYourIdentities.item(row - 1, 1): self.ui.radioButtonExisting.click() - # print - # self.parent.ui.tableWidgetYourIdentities.item(row-1,1).text() self.ui.comboBoxExisting.addItem( self.parent.ui.tableWidgetYourIdentities.item(row - 1, 1).text()) row += 1 diff --git a/src/bitmessageqt/bitmessageui.py b/src/bitmessageqt/bitmessageui.py index 318c1caf..c2d45a76 100644 --- a/src/bitmessageqt/bitmessageui.py +++ b/src/bitmessageqt/bitmessageui.py @@ -2,7 +2,7 @@ # Form implementation generated from reading ui file 'bitmessageui.ui' # -# Created: Mon Jan 05 16:21:20 2015 +# Created: Fri Feb 27 18:48:36 2015 # by: PyQt4 UI code generator 4.10.3 # # WARNING! All changes made in this file will be lost! @@ -109,62 +109,55 @@ class Ui_MainWindow(object): self.send.setObjectName(_fromUtf8("send")) self.gridLayout_2 = QtGui.QGridLayout(self.send) self.gridLayout_2.setObjectName(_fromUtf8("gridLayout_2")) + self.lineEditSubject = QtGui.QLineEdit(self.send) + self.lineEditSubject.setText(_fromUtf8("")) + self.lineEditSubject.setObjectName(_fromUtf8("lineEditSubject")) + self.gridLayout_2.addWidget(self.lineEditSubject, 4, 1, 1, 1) self.pushButtonLoadFromAddressBook = QtGui.QPushButton(self.send) font = QtGui.QFont() font.setPointSize(7) self.pushButtonLoadFromAddressBook.setFont(font) self.pushButtonLoadFromAddressBook.setObjectName(_fromUtf8("pushButtonLoadFromAddressBook")) 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) + self.label_3 = QtGui.QLabel(self.send) + self.label_3.setObjectName(_fromUtf8("label_3")) + self.gridLayout_2.addWidget(self.label_3, 4, 0, 1, 1) + self.pushButtonSend = QtGui.QPushButton(self.send) + self.pushButtonSend.setObjectName(_fromUtf8("pushButtonSend")) + self.gridLayout_2.addWidget(self.pushButtonSend, 7, 8, 1, 1) + self.horizontalSliderTTL = QtGui.QSlider(self.send) + self.horizontalSliderTTL.setMaximumSize(QtCore.QSize(70, 16777215)) + self.horizontalSliderTTL.setOrientation(QtCore.Qt.Horizontal) + self.horizontalSliderTTL.setInvertedAppearance(False) + self.horizontalSliderTTL.setInvertedControls(False) + self.horizontalSliderTTL.setObjectName(_fromUtf8("horizontalSliderTTL")) + self.gridLayout_2.addWidget(self.horizontalSliderTTL, 7, 6, 1, 1) + spacerItem = QtGui.QSpacerItem(20, 297, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding) + self.gridLayout_2.addItem(spacerItem, 6, 0, 1, 1) self.comboBoxSendFrom = QtGui.QComboBox(self.send) self.comboBoxSendFrom.setMinimumSize(QtCore.QSize(300, 0)) self.comboBoxSendFrom.setObjectName(_fromUtf8("comboBoxSendFrom")) self.gridLayout_2.addWidget(self.comboBoxSendFrom, 2, 1, 1, 1) - self.label_3 = QtGui.QLabel(self.send) - self.label_3.setObjectName(_fromUtf8("label_3")) - self.gridLayout_2.addWidget(self.label_3, 4, 0, 1, 1) - self.labelFrom = QtGui.QLabel(self.send) - self.labelFrom.setText(_fromUtf8("")) - self.labelFrom.setObjectName(_fromUtf8("labelFrom")) - self.gridLayout_2.addWidget(self.labelFrom, 2, 2, 1, 3) + self.labelHumanFriendlyTTLDescription = QtGui.QLabel(self.send) + sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Preferred) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.labelHumanFriendlyTTLDescription.sizePolicy().hasHeightForWidth()) + self.labelHumanFriendlyTTLDescription.setSizePolicy(sizePolicy) + self.labelHumanFriendlyTTLDescription.setMinimumSize(QtCore.QSize(45, 0)) + self.labelHumanFriendlyTTLDescription.setMaximumSize(QtCore.QSize(45, 16777215)) + self.labelHumanFriendlyTTLDescription.setObjectName(_fromUtf8("labelHumanFriendlyTTLDescription")) + self.gridLayout_2.addWidget(self.labelHumanFriendlyTTLDescription, 7, 7, 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) + self.label = QtGui.QLabel(self.send) + self.label.setObjectName(_fromUtf8("label")) + self.gridLayout_2.addWidget(self.label, 3, 0, 1, 1) self.radioButtonSpecific = QtGui.QRadioButton(self.send) self.radioButtonSpecific.setChecked(True) self.radioButtonSpecific.setObjectName(_fromUtf8("radioButtonSpecific")) self.gridLayout_2.addWidget(self.radioButtonSpecific, 0, 1, 1, 1) - self.lineEditTo = QtGui.QLineEdit(self.send) - self.lineEditTo.setObjectName(_fromUtf8("lineEditTo")) - self.gridLayout_2.addWidget(self.lineEditTo, 3, 1, 1, 1) - self.textEditMessage = QtGui.QTextEdit(self.send) - self.textEditMessage.setObjectName(_fromUtf8("textEditMessage")) - self.gridLayout_2.addWidget(self.textEditMessage, 5, 1, 2, 5) - self.label = QtGui.QLabel(self.send) - self.label.setObjectName(_fromUtf8("label")) - self.gridLayout_2.addWidget(self.label, 3, 0, 1, 1) - self.label_2 = QtGui.QLabel(self.send) - self.label_2.setObjectName(_fromUtf8("label_2")) - self.gridLayout_2.addWidget(self.label_2, 2, 0, 1, 1) - spacerItem = QtGui.QSpacerItem(20, 297, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding) - self.gridLayout_2.addItem(spacerItem, 6, 0, 1, 1) - self.radioButtonBroadcast = QtGui.QRadioButton(self.send) - self.radioButtonBroadcast.setObjectName(_fromUtf8("radioButtonBroadcast")) - self.gridLayout_2.addWidget(self.radioButtonBroadcast, 1, 1, 1, 3) - self.lineEditSubject = QtGui.QLineEdit(self.send) - self.lineEditSubject.setText(_fromUtf8("")) - self.lineEditSubject.setObjectName(_fromUtf8("lineEditSubject")) - self.gridLayout_2.addWidget(self.lineEditSubject, 4, 1, 1, 5) - spacerItem1 = QtGui.QSpacerItem(20, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum) - self.gridLayout_2.addItem(spacerItem1, 3, 4, 1, 1) - self.pushButtonSend = QtGui.QPushButton(self.send) - self.pushButtonSend.setObjectName(_fromUtf8("pushButtonSend")) - self.gridLayout_2.addWidget(self.pushButtonSend, 7, 5, 1, 1) self.labelSendBroadcastWarning = QtGui.QLabel(self.send) self.labelSendBroadcastWarning.setEnabled(True) sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Ignored, QtGui.QSizePolicy.Preferred) @@ -175,6 +168,54 @@ class Ui_MainWindow(object): self.labelSendBroadcastWarning.setIndent(-1) self.labelSendBroadcastWarning.setObjectName(_fromUtf8("labelSendBroadcastWarning")) self.gridLayout_2.addWidget(self.labelSendBroadcastWarning, 7, 1, 1, 4) + self.radioButtonBroadcast = QtGui.QRadioButton(self.send) + self.radioButtonBroadcast.setObjectName(_fromUtf8("radioButtonBroadcast")) + self.gridLayout_2.addWidget(self.radioButtonBroadcast, 1, 1, 1, 2) + self.pushButtonTTL = QtGui.QPushButton(self.send) + sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.pushButtonTTL.sizePolicy().hasHeightForWidth()) + self.pushButtonTTL.setSizePolicy(sizePolicy) + self.pushButtonTTL.setMaximumSize(QtCore.QSize(32, 16777215)) + palette = QtGui.QPalette() + brush = QtGui.QBrush(QtGui.QColor(0, 0, 255)) + brush.setStyle(QtCore.Qt.SolidPattern) + palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.ButtonText, brush) + brush = QtGui.QBrush(QtGui.QColor(0, 0, 255)) + brush.setStyle(QtCore.Qt.SolidPattern) + palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.ButtonText, brush) + brush = QtGui.QBrush(QtGui.QColor(120, 120, 120)) + brush.setStyle(QtCore.Qt.SolidPattern) + palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.ButtonText, brush) + self.pushButtonTTL.setPalette(palette) + font = QtGui.QFont() + font.setUnderline(True) + self.pushButtonTTL.setFont(font) + self.pushButtonTTL.setFlat(True) + self.pushButtonTTL.setObjectName(_fromUtf8("pushButtonTTL")) + self.gridLayout_2.addWidget(self.pushButtonTTL, 7, 5, 1, 1) + self.label_2 = QtGui.QLabel(self.send) + self.label_2.setObjectName(_fromUtf8("label_2")) + self.gridLayout_2.addWidget(self.label_2, 2, 0, 1, 1) + self.labelFrom = QtGui.QLabel(self.send) + self.labelFrom.setText(_fromUtf8("")) + self.labelFrom.setObjectName(_fromUtf8("labelFrom")) + self.gridLayout_2.addWidget(self.labelFrom, 2, 2, 1, 1) + spacerItem1 = QtGui.QSpacerItem(20, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum) + self.gridLayout_2.addItem(spacerItem1, 3, 4, 1, 1) + self.lineEditTo = QtGui.QLineEdit(self.send) + self.lineEditTo.setObjectName(_fromUtf8("lineEditTo")) + self.gridLayout_2.addWidget(self.lineEditTo, 3, 1, 1, 1) + self.textEditMessage = QtGui.QTextEdit(self.send) + self.textEditMessage.setObjectName(_fromUtf8("textEditMessage")) + self.gridLayout_2.addWidget(self.textEditMessage, 5, 1, 2, 8) + 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) icon2 = QtGui.QIcon() icon2.addPixmap(QtGui.QPixmap(_fromUtf8(":/newPrefix/images/send.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.tabWidget.addTab(self.send, icon2, _fromUtf8("")) @@ -556,20 +597,22 @@ class Ui_MainWindow(object): 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.pushButtonFetchNamecoinID.setText(_translate("MainWindow", "Fetch Namecoin ID", None)) - self.label_4.setText(_translate("MainWindow", "Message:", None)) self.label_3.setText(_translate("MainWindow", "Subject:", None)) + self.pushButtonSend.setText(_translate("MainWindow", "Send", None)) + self.labelHumanFriendlyTTLDescription.setText(_translate("MainWindow", "X days", None)) + self.label_4.setText(_translate("MainWindow", "Message:", None)) + self.label.setText(_translate("MainWindow", "To:", None)) self.radioButtonSpecific.setText(_translate("MainWindow", "Send to one or more specific people", 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.radioButtonBroadcast.setText(_translate("MainWindow", "Broadcast to everyone who is subscribed to your address", None)) + self.pushButtonTTL.setText(_translate("MainWindow", "TTL:", None)) + self.label_2.setText(_translate("MainWindow", "From:", None)) self.textEditMessage.setHtml(_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.pushButtonFetchNamecoinID.setText(_translate("MainWindow", "Fetch Namecoin ID", None)) self.tabWidget.setTabText(self.tabWidget.indexOf(self.send), _translate("MainWindow", "Send", None)) self.sentSearchLineEdit.setPlaceholderText(_translate("MainWindow", "Search", None)) self.sentSearchOptionCB.setItemText(0, _translate("MainWindow", "All", None)) diff --git a/src/bitmessageqt/bitmessageui.ui b/src/bitmessageqt/bitmessageui.ui index 58e115d7..09ce6ff8 100644 --- a/src/bitmessageqt/bitmessageui.ui +++ b/src/bitmessageqt/bitmessageui.ui @@ -204,6 +204,13 @@ Send + + + + + + + @@ -216,35 +223,6 @@ - - - - - 7 - - - - Fetch Namecoin ID - - - - - - - Message: - - - - - - - - 300 - 0 - - - - @@ -252,48 +230,29 @@ - - + + - + Send - - - - Send to one or more specific people + + + + + 70 + 16777215 + - - true + + Qt::Horizontal - - - - - - - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:9pt; font-weight:400; font-style:normal;"> -<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> + + false - - - - - - To: - - - - - - - From: + + false @@ -310,37 +269,62 @@ p, li { white-space: pre-wrap; } - - - - Broadcast to everyone who is subscribed to your address - - - - - - - - - - - - - - Qt::Horizontal - - + + + - 20 - 20 + 300 + 0 - + - - + + + + + 0 + 0 + + + + + 45 + 0 + + + + + 45 + 16777215 + + - Send + X days + + + + + + + Message: + + + + + + + To: + + + + + + + Send to one or more specific people + + + true @@ -363,6 +347,130 @@ p, li { white-space: pre-wrap; } + + + + Broadcast to everyone who is subscribed to your address + + + + + + + + 0 + 0 + + + + + 32 + 16777215 + + + + + + + + + 0 + 0 + 255 + + + + + + + + + 0 + 0 + 255 + + + + + + + + + 120 + 120 + 120 + + + + + + + + + true + + + + TTL: + + + true + + + + + + + From: + + + + + + + + + + + + + + Qt::Horizontal + + + + 20 + 20 + + + + + + + + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:9pt; font-weight:400; font-style:normal;"> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> + + + + + + + + 7 + + + + Fetch Namecoin ID + + + diff --git a/src/class_sqlThread.py b/src/class_sqlThread.py index d4c69b59..56e86118 100644 --- a/src/class_sqlThread.py +++ b/src/class_sqlThread.py @@ -375,6 +375,10 @@ class sqlThread(threading.Thread): item = '''update settings set value=? WHERE key='version';''' parameters = (9,) self.cur.execute(item, parameters) + + # TTL is now user-specifyable. Let's add an option to save whatever the user selects. + if not shared.config.has_option('bitmessagesettings', 'ttl'): + shared.config.set('bitmessagesettings', 'ttl', '367200') # Are you hoping to add a new option to the keys.dat file of existing # Bitmessage users or modify the SQLite database? Add it right above this line! diff --git a/src/helper_startup.py b/src/helper_startup.py index c71ee436..ef40dd51 100644 --- a/src/helper_startup.py +++ b/src/helper_startup.py @@ -104,6 +104,7 @@ def loadConfig(): shared.config.set('bitmessagesettings', 'replybelow', 'False') shared.config.set('bitmessagesettings', 'maxdownloadrate', '0') shared.config.set('bitmessagesettings', 'maxuploadrate', '0') + shared.config.set('bitmessagesettings', 'ttl', '367200') #start:UI setting to stop trying to send messages after X days/months shared.config.set( From cc712cb8ff02a0076a0ed17a276122e37713b441 Mon Sep 17 00:00:00 2001 From: Jonathan Warren Date: Mon, 9 Mar 2015 02:35:32 -0400 Subject: [PATCH 2/4] finished work on specifyTTL --- src/api.py | 67 +++++++++----- src/bitmessagecurses/__init__.py | 26 +++--- src/bitmessageqt/__init__.py | 55 ++++++----- src/bitmessageqt/bitmessageui.py | 37 ++++---- src/bitmessageqt/bitmessageui.ui | 47 ++++------ src/class_objectProcessor.py | 97 ++++++++++++-------- src/class_receiveDataThread.py | 6 +- src/class_singleCleaner.py | 42 ++++----- src/class_singleWorker.py | 153 +++++++++++++++++++++---------- src/class_sqlThread.py | 74 ++++++++++----- src/helper_sent.py | 2 +- src/message_data_reader.py | 10 +- src/shared.py | 2 +- 13 files changed, 376 insertions(+), 242 deletions(-) diff --git a/src/api.py b/src/api.py index 9e498f46..b395cf02 100644 --- a/src/api.py +++ b/src/api.py @@ -615,14 +615,22 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): elif len(params) == 4: toAddress, fromAddress, subject, message = params encodingType = 2 + TTL = 4*24*60*60 elif len(params) == 5: toAddress, fromAddress, subject, message, encodingType = params + TTL = 4*24*60*60 + elif len(params) == 6: + toAddress, fromAddress, subject, message, encodingType, TTL = params if encodingType != 2: raise APIError(6, 'The encoding type must be 2 because that is the only one this program currently supports.') subject = self._decode(subject, "base64") message = self._decode(message, "base64") if len(subject + message) > (2 ** 18 - 500): raise APIError(27, 'Message is too long.') + if TTL < 60*60: + TTL = 60*60 + if TTL > 28*24*60*60: + TTL = 28*24*60*60 toAddress = addBMIfNotPresent(toAddress) fromAddress = addBMIfNotPresent(fromAddress) status, addressVersionNumber, streamNumber, toRipe = self._verifyAddress(toAddress) @@ -637,8 +645,21 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): ackdata = OpenSSL.rand(32) - t = ('', toAddress, toRipe, fromAddress, subject, message, ackdata, int( - time.time()), 'msgqueued', 1, 1, 'sent', 2) + t = ('', + toAddress, + toRipe, + fromAddress, + subject, + message, + ackdata, + int(time.time()), # sentTime (this won't change) + int(time.time()), # lastActionTime + 0, + 'msgqueued', + 0, + 'sent', + 2, + TTL) helper_sent.insert(t) toLabel = '' @@ -660,14 +681,22 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): if len(params) == 3: fromAddress, subject, message = params encodingType = 2 + TTL = 4*24*60*60 elif len(params) == 4: fromAddress, subject, message, encodingType = params + TTL = 4*24*60*60 + elif len(params) == 5: + fromAddress, subject, message, encodingType, TTL = params if encodingType != 2: raise APIError(6, 'The encoding type must be 2 because that is the only one this program currently supports.') subject = self._decode(subject, "base64") message = self._decode(message, "base64") if len(subject + message) > (2 ** 18 - 500): raise APIError(27, 'Message is too long.') + if TTL < 60*60: + TTL = 60*60 + if TTL > 28*24*60*60: + TTL = 28*24*60*60 fromAddress = addBMIfNotPresent(fromAddress) self._verifyAddress(fromAddress) try: @@ -679,9 +708,21 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): toAddress = '[Broadcast subscribers]' ripe = '' - - t = ('', toAddress, ripe, fromAddress, subject, message, ackdata, int( - time.time()), 'broadcastqueued', 1, 1, 'sent', 2) + t = ('', + toAddress, + ripe, + fromAddress, + subject, + message, + ackdata, + int(time.time()), # sentTime (this doesn't change) + int(time.time()), # lastActionTime + 0, + 'broadcastqueued', + 0, + 'sent', + 2, + TTL) helper_sent.insert(t) toLabel = '[Broadcast subscribers]' @@ -918,22 +959,6 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): data += json.dumps({'data':payload.encode('hex')}, indent=4, separators=(',', ': ')) data += ']}' return data - elif method == 'getPubkeyByHash': - # Method will eventually be used by a particular Android app to - # retrieve pubkeys. Please do not yet add this to the api docs. - if len(params) != 1: - raise APIError(0, 'I need 1 parameter!') - requestedHash, = params - if len(requestedHash) != 40: - raise APIError(19, 'The length of hash should be 20 bytes (encoded in hex thus 40 characters).') - requestedHash = self._decode(requestedHash, "hex") - queryreturn = sqlQuery('''SELECT transmitdata FROM pubkeys WHERE hash = ? ; ''', requestedHash) - data = '{"pubkey":[' - for row in queryreturn: - transmitdata, = row - data += json.dumps({'data':transmitdata.encode('hex')}, indent=4, separators=(',', ': ')) - data += ']}' - return data elif method == 'clientStatus': if len(shared.connectedHostsList) == 0: networkStatus = 'notConnected' diff --git a/src/bitmessagecurses/__init__.py b/src/bitmessagecurses/__init__.py index a4546c08..8a4d6768 100644 --- a/src/bitmessagecurses/__init__.py +++ b/src/bitmessagecurses/__init__.py @@ -760,7 +760,7 @@ def sendMessage(sender="", recv="", broadcast=None, subject="", body="", reply=F exit_label="Continue") ackdata = OpenSSL.rand(32) sqlExecute( - "INSERT INTO sent VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)", + "INSERT INTO sent VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)", "", addr, ripe, @@ -768,12 +768,14 @@ def sendMessage(sender="", recv="", broadcast=None, subject="", body="", reply=F subject, body, ackdata, - int(time.time()), + int(time.time()), # sentTime (this will never change) + int(time.time()), # lastActionTime + 0, # sleepTill time. This will get set when the POW gets done. "msgqueued", - 1, - 1, + 0, # retryNumber "sent", - 2) + 2, # encodingType + shared.config.getint('bitmessagesettings', 'ttl')) shared.workerQueue.put(("sendmessage", addr)) else: # Broadcast if recv == "": @@ -785,7 +787,7 @@ def sendMessage(sender="", recv="", broadcast=None, subject="", body="", reply=F recv = BROADCAST_STR ripe = "" sqlExecute( - "INSERT INTO sent VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)", + "INSERT INTO sent VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?)", "", recv, ripe, @@ -793,12 +795,14 @@ def sendMessage(sender="", recv="", broadcast=None, subject="", body="", reply=F subject, body, ackdata, - int(time.time()), + int(time.time()), # sentTime (this will never change) + int(time.time()), # lastActionTime + 0, # sleepTill time. This will get set when the POW gets done. "broadcastqueued", - 1, - 1, - "sent", - 2) + 0, # retryNumber + "sent", # folder + 2, # encodingType + shared.config.getint('bitmessagesettings', 'ttl')) shared.workerQueue.put(('sendbroadcast', '')) def loadInbox(): diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 38d025dd..1819628b 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -610,7 +610,7 @@ class MyForm(QtGui.QMainWindow): QtCore.QObject.connect(self.UISignalThread, QtCore.SIGNAL( "updateStatusBar(PyQt_PyObject)"), self.updateStatusBar) QtCore.QObject.connect(self.UISignalThread, QtCore.SIGNAL( - "updateSentItemStatusByHash(PyQt_PyObject,PyQt_PyObject)"), self.updateSentItemStatusByHash) + "updateSentItemStatusByToAddress(PyQt_PyObject,PyQt_PyObject)"), self.updateSentItemStatusByToAddress) QtCore.QObject.connect(self.UISignalThread, QtCore.SIGNAL( "updateSentItemStatusByAckdata(PyQt_PyObject,PyQt_PyObject)"), self.updateSentItemStatusByAckdata) QtCore.QObject.connect(self.UISignalThread, QtCore.SIGNAL( @@ -1694,13 +1694,11 @@ class MyForm(QtGui.QMainWindow): cnt, = row return int(cnt) - def updateSentItemStatusByHash(self, toRipe, textToDisplay): + def updateSentItemStatusByToAddress(self, toAddress, textToDisplay): for i in range(self.ui.tableWidgetSent.rowCount()): - toAddress = str(self.ui.tableWidgetSent.item( + rowAddress = str(self.ui.tableWidgetSent.item( i, 0).data(Qt.UserRole).toPyObject()) - status, addressVersionNumber, streamNumber, ripe = decodeAddress( - toAddress) - if ripe == toRipe: + if toAddress == rowAddress: self.ui.tableWidgetSent.item(i, 3).setToolTip(textToDisplay) try: newlinePosition = textToDisplay.indexOf('\n') @@ -1901,10 +1899,9 @@ class MyForm(QtGui.QMainWindow): def click_pushButtonTTL(self): QtGui.QMessageBox.information(self, 'Time To Live', _translate( "MainWindow", "The TTL, or Time-To-Live is the length of time that the network will hold the message. \ -The recipient must get it during this time. If your client does not hear an acknowledgement, your \ -Bitmessage client will resend the message automatically if it is open. The longer the Time-To-Live, the \ +The recipient must get it during this time. If your Bitmessage client does not hear an acknowledgement, it \ +will resend the message automatically. The longer the Time-To-Live, the \ more work your computer must do to send the message. A Time-To-Live of four or five days is often appropriate."), QMessageBox.Ok) - ############### def click_pushButtonSend(self): self.statusBar().showMessage('') @@ -1981,7 +1978,7 @@ more work your computer must do to send the message. A Time-To-Live of four or f ackdata = OpenSSL.rand(32) t = () sqlExecute( - '''INSERT INTO sent VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)''', + '''INSERT INTO sent VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)''', '', toAddress, ripe, @@ -1989,12 +1986,14 @@ more work your computer must do to send the message. A Time-To-Live of four or f subject, message, ackdata, - int(time.time()), + int(time.time()), # sentTime (this will never change) + int(time.time()), # lastActionTime + 0, # sleepTill time. This will get set when the POW gets done. 'msgqueued', - 1, # pubkeyretrynumber - 1, # msgretrynumber - 'sent', - 2 # encodingtype + 0, # retryNumber + 'sent', # folder + 2, # encodingtype + shared.config.getint('bitmessagesettings', 'ttl') ) toLabel = '' @@ -2030,10 +2029,24 @@ more work your computer must do to send the message. A Time-To-Live of four or f ackdata = OpenSSL.rand(32) toAddress = self.str_broadcast_subscribers ripe = '' - t = ('', toAddress, ripe, fromAddress, subject, message, ackdata, int( - time.time()), 'broadcastqueued', 1, 1, 'sent', 2) + t = ('', # msgid. We don't know what this will be until the POW is done. + toAddress, + ripe, + fromAddress, + subject, + message, + ackdata, + int(time.time()), # sentTime (this will never change) + int(time.time()), # lastActionTime + 0, # sleepTill time. This will get set when the POW gets done. + 'broadcastqueued', + 0, # retryNumber + 'sent', # folder + 2, # encoding type + shared.config.getint('bitmessagesettings', 'ttl') + ) sqlExecute( - '''INSERT INTO sent VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)''', *t) + '''INSERT INTO sent VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)''', *t) toLabel = self.str_broadcast_subscribers @@ -3839,10 +3852,10 @@ class UISignaler(QThread): "writeNewAddressToTable(PyQt_PyObject,PyQt_PyObject,PyQt_PyObject)"), label, address, str(streamNumber)) elif command == 'updateStatusBar': self.emit(SIGNAL("updateStatusBar(PyQt_PyObject)"), data) - elif command == 'updateSentItemStatusByHash': - hash, message = data + elif command == 'updateSentItemStatusByToAddress': + toAddress, message = data self.emit(SIGNAL( - "updateSentItemStatusByHash(PyQt_PyObject,PyQt_PyObject)"), hash, message) + "updateSentItemStatusByToAddress(PyQt_PyObject,PyQt_PyObject)"), toAddress, message) elif command == 'updateSentItemStatusByAckdata': ackData, message = data self.emit(SIGNAL( diff --git a/src/bitmessageqt/bitmessageui.py b/src/bitmessageqt/bitmessageui.py index c2d45a76..e35b30cd 100644 --- a/src/bitmessageqt/bitmessageui.py +++ b/src/bitmessageqt/bitmessageui.py @@ -2,7 +2,7 @@ # Form implementation generated from reading ui file 'bitmessageui.ui' # -# Created: Fri Feb 27 18:48:36 2015 +# Created: Sun Mar 08 22:07:43 2015 # by: PyQt4 UI code generator 4.10.3 # # WARNING! All changes made in this file will be lost! @@ -109,10 +109,6 @@ class Ui_MainWindow(object): self.send.setObjectName(_fromUtf8("send")) self.gridLayout_2 = QtGui.QGridLayout(self.send) self.gridLayout_2.setObjectName(_fromUtf8("gridLayout_2")) - self.lineEditSubject = QtGui.QLineEdit(self.send) - self.lineEditSubject.setText(_fromUtf8("")) - self.lineEditSubject.setObjectName(_fromUtf8("lineEditSubject")) - self.gridLayout_2.addWidget(self.lineEditSubject, 4, 1, 1, 1) self.pushButtonLoadFromAddressBook = QtGui.QPushButton(self.send) font = QtGui.QFont() font.setPointSize(7) @@ -126,6 +122,7 @@ class Ui_MainWindow(object): self.pushButtonSend.setObjectName(_fromUtf8("pushButtonSend")) self.gridLayout_2.addWidget(self.pushButtonSend, 7, 8, 1, 1) self.horizontalSliderTTL = QtGui.QSlider(self.send) + self.horizontalSliderTTL.setMinimumSize(QtCore.QSize(35, 0)) self.horizontalSliderTTL.setMaximumSize(QtCore.QSize(70, 16777215)) self.horizontalSliderTTL.setOrientation(QtCore.Qt.Horizontal) self.horizontalSliderTTL.setInvertedAppearance(False) @@ -198,12 +195,6 @@ class Ui_MainWindow(object): self.label_2 = QtGui.QLabel(self.send) self.label_2.setObjectName(_fromUtf8("label_2")) self.gridLayout_2.addWidget(self.label_2, 2, 0, 1, 1) - self.labelFrom = QtGui.QLabel(self.send) - self.labelFrom.setText(_fromUtf8("")) - self.labelFrom.setObjectName(_fromUtf8("labelFrom")) - self.gridLayout_2.addWidget(self.labelFrom, 2, 2, 1, 1) - spacerItem1 = QtGui.QSpacerItem(20, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum) - self.gridLayout_2.addItem(spacerItem1, 3, 4, 1, 1) self.lineEditTo = QtGui.QLineEdit(self.send) self.lineEditTo.setObjectName(_fromUtf8("lineEditTo")) self.gridLayout_2.addWidget(self.lineEditTo, 3, 1, 1, 1) @@ -216,6 +207,14 @@ class Ui_MainWindow(object): self.pushButtonFetchNamecoinID.setFont(font) self.pushButtonFetchNamecoinID.setObjectName(_fromUtf8("pushButtonFetchNamecoinID")) self.gridLayout_2.addWidget(self.pushButtonFetchNamecoinID, 3, 3, 1, 1) + self.labelFrom = QtGui.QLabel(self.send) + self.labelFrom.setText(_fromUtf8("")) + self.labelFrom.setObjectName(_fromUtf8("labelFrom")) + self.gridLayout_2.addWidget(self.labelFrom, 2, 2, 1, 7) + self.lineEditSubject = QtGui.QLineEdit(self.send) + self.lineEditSubject.setText(_fromUtf8("")) + self.lineEditSubject.setObjectName(_fromUtf8("lineEditSubject")) + self.gridLayout_2.addWidget(self.lineEditSubject, 4, 1, 1, 8) icon2 = QtGui.QIcon() icon2.addPixmap(QtGui.QPixmap(_fromUtf8(":/newPrefix/images/send.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.tabWidget.addTab(self.send, icon2, _fromUtf8("")) @@ -280,8 +279,8 @@ class Ui_MainWindow(object): self.pushButtonNewAddress = QtGui.QPushButton(self.youridentities) self.pushButtonNewAddress.setObjectName(_fromUtf8("pushButtonNewAddress")) self.gridLayout_3.addWidget(self.pushButtonNewAddress, 0, 0, 1, 1) - spacerItem2 = QtGui.QSpacerItem(689, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum) - self.gridLayout_3.addItem(spacerItem2, 0, 1, 1, 1) + spacerItem1 = QtGui.QSpacerItem(689, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum) + self.gridLayout_3.addItem(spacerItem1, 0, 1, 1, 1) self.tableWidgetYourIdentities = QtGui.QTableWidget(self.youridentities) self.tableWidgetYourIdentities.setFrameShadow(QtGui.QFrame.Sunken) self.tableWidgetYourIdentities.setLineWidth(1) @@ -324,8 +323,8 @@ class Ui_MainWindow(object): self.pushButtonAddSubscription = QtGui.QPushButton(self.subscriptions) self.pushButtonAddSubscription.setObjectName(_fromUtf8("pushButtonAddSubscription")) self.gridLayout_4.addWidget(self.pushButtonAddSubscription, 1, 0, 1, 1) - spacerItem3 = QtGui.QSpacerItem(689, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum) - self.gridLayout_4.addItem(spacerItem3, 1, 1, 1, 1) + spacerItem2 = QtGui.QSpacerItem(689, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum) + self.gridLayout_4.addItem(spacerItem2, 1, 1, 1, 1) self.tableWidgetSubscriptions = QtGui.QTableWidget(self.subscriptions) self.tableWidgetSubscriptions.setAlternatingRowColors(True) self.tableWidgetSubscriptions.setSelectionMode(QtGui.QAbstractItemView.SingleSelection) @@ -358,8 +357,8 @@ class Ui_MainWindow(object): self.pushButtonAddAddressBook = QtGui.QPushButton(self.addressbook) self.pushButtonAddAddressBook.setObjectName(_fromUtf8("pushButtonAddAddressBook")) self.gridLayout_5.addWidget(self.pushButtonAddAddressBook, 1, 0, 1, 1) - spacerItem4 = QtGui.QSpacerItem(689, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum) - self.gridLayout_5.addItem(spacerItem4, 1, 1, 1, 1) + spacerItem3 = QtGui.QSpacerItem(689, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum) + self.gridLayout_5.addItem(spacerItem3, 1, 1, 1, 1) self.tableWidgetAddressBook = QtGui.QTableWidget(self.addressbook) self.tableWidgetAddressBook.setAlternatingRowColors(True) self.tableWidgetAddressBook.setSelectionMode(QtGui.QAbstractItemView.ExtendedSelection) @@ -394,8 +393,8 @@ class Ui_MainWindow(object): self.pushButtonAddBlacklist = QtGui.QPushButton(self.blackwhitelist) self.pushButtonAddBlacklist.setObjectName(_fromUtf8("pushButtonAddBlacklist")) self.gridLayout_6.addWidget(self.pushButtonAddBlacklist, 2, 0, 1, 1) - spacerItem5 = QtGui.QSpacerItem(689, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum) - self.gridLayout_6.addItem(spacerItem5, 2, 1, 1, 1) + spacerItem4 = QtGui.QSpacerItem(689, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum) + self.gridLayout_6.addItem(spacerItem4, 2, 1, 1, 1) self.tableWidgetBlacklist = QtGui.QTableWidget(self.blackwhitelist) self.tableWidgetBlacklist.setAlternatingRowColors(True) self.tableWidgetBlacklist.setSelectionMode(QtGui.QAbstractItemView.SingleSelection) diff --git a/src/bitmessageqt/bitmessageui.ui b/src/bitmessageqt/bitmessageui.ui index 09ce6ff8..e45cc22d 100644 --- a/src/bitmessageqt/bitmessageui.ui +++ b/src/bitmessageqt/bitmessageui.ui @@ -204,13 +204,6 @@ Send - - - - - - - @@ -239,6 +232,12 @@ + + + 35 + 0 + + 70 @@ -425,26 +424,6 @@ - - - - - - - - - - - Qt::Horizontal - - - - 20 - 20 - - - - @@ -471,6 +450,20 @@ p, li { white-space: pre-wrap; } + + + + + + + + + + + + + + diff --git a/src/class_objectProcessor.py b/src/class_objectProcessor.py index 6cb55c25..f9972fe6 100644 --- a/src/class_objectProcessor.py +++ b/src/class_objectProcessor.py @@ -201,7 +201,7 @@ class objectProcessor(threading.Thread): ripe = ripeHasher.digest() - logger.info('within recpubkey, addressVersion: %s, streamNumber: %s \n\ + logger.debug('within recpubkey, addressVersion: %s, streamNumber: %s \n\ ripe %s\n\ publicSigningKey in hex: %s\n\ publicEncryptionKey in hex: %s' % (addressVersion, @@ -212,17 +212,19 @@ class objectProcessor(threading.Thread): ) ) - queryreturn = sqlQuery( - '''SELECT usedpersonally FROM pubkeys WHERE hash=? AND addressversion=? AND usedpersonally='yes' ''', ripe, addressVersion) + address = encodeAddress(addressVersion, streamNumber, ripe) + + queryreturn = sqlQuery( + '''SELECT usedpersonally FROM pubkeys WHERE address=? AND usedpersonally='yes' ''', address) if queryreturn != []: # if this pubkey is already in our database and if we have used it personally: logger.info('We HAVE used this pubkey personally. Updating time.') - t = (ripe, addressVersion, dataToStore, int(time.time()), 'yes') + t = (address, addressVersion, dataToStore, int(time.time()), 'yes') else: logger.info('We have NOT used this pubkey personally. Inserting in database.') - t = (ripe, addressVersion, dataToStore, int(time.time()), 'no') + t = (address, addressVersion, dataToStore, int(time.time()), 'no') sqlExecute('''INSERT INTO pubkeys VALUES (?,?,?,?,?)''', *t) - self.possibleNewPubkey(ripe = ripe) + self.possibleNewPubkey(address) if addressVersion == 3: if len(data) < 170: # sanity check. logger.warning('(within processpubkey) payloadLength less than 170. Sanity check failed.') @@ -258,7 +260,7 @@ class objectProcessor(threading.Thread): ripe = ripeHasher.digest() - logger.info('within recpubkey, addressVersion: %s, streamNumber: %s \n\ + logger.debug('within recpubkey, addressVersion: %s, streamNumber: %s \n\ ripe %s\n\ publicSigningKey in hex: %s\n\ publicEncryptionKey in hex: %s' % (addressVersion, @@ -269,16 +271,16 @@ class objectProcessor(threading.Thread): ) ) - - queryreturn = sqlQuery('''SELECT usedpersonally FROM pubkeys WHERE hash=? AND addressversion=? AND usedpersonally='yes' ''', ripe, addressVersion) + address = encodeAddress(addressVersion, streamNumber, ripe) + queryreturn = sqlQuery('''SELECT usedpersonally FROM pubkeys WHERE address=? AND usedpersonally='yes' ''', address) if queryreturn != []: # if this pubkey is already in our database and if we have used it personally: logger.info('We HAVE used this pubkey personally. Updating time.') - t = (ripe, addressVersion, dataToStore, int(time.time()), 'yes') + t = (address, addressVersion, dataToStore, int(time.time()), 'yes') else: logger.info('We have NOT used this pubkey personally. Inserting in database.') - t = (ripe, addressVersion, dataToStore, int(time.time()), 'no') + t = (address, addressVersion, dataToStore, int(time.time()), 'no') sqlExecute('''INSERT INTO pubkeys VALUES (?,?,?,?,?)''', *t) - self.possibleNewPubkey(ripe = ripe) + self.possibleNewPubkey(address) if addressVersion == 4: if len(data) < 350: # sanity check. @@ -296,7 +298,7 @@ class objectProcessor(threading.Thread): # At this point we know that we have been waiting on this pubkey. # This function will command the workerThread to start work on # the messages that require it. - self.possibleNewPubkey(address=toAddress) + self.possibleNewPubkey(toAddress) # Display timing data timeRequiredToProcessPubkey = time.time( @@ -325,8 +327,10 @@ class objectProcessor(threading.Thread): if data[-32:] in shared.ackdataForWhichImWatching: logger.info('This msg IS an acknowledgement bound for me.') del shared.ackdataForWhichImWatching[data[-32:]] - sqlExecute('UPDATE sent SET status=? WHERE ackdata=?', - 'ackreceived', data[-32:]) + sqlExecute('UPDATE sent SET status=?, lastactiontime=? WHERE ackdata=?', + 'ackreceived', + int(time.time()), + data[-32:]) shared.UISignalQueue.put(('updateSentItemStatusByAckdata', (data[-32:], tr.translateText("MainWindow",'Acknowledgement of the message received. %1').arg(l10n.formatTimestamp())))) return else: @@ -441,7 +445,7 @@ class objectProcessor(threading.Thread): # person. sqlExecute( '''INSERT INTO pubkeys VALUES (?,?,?,?,?)''', - ripe.digest(), + fromAddress, sendersAddressVersionNumber, decryptedData[:endOfThePublicKeyPosition], int(time.time()), @@ -450,10 +454,7 @@ class objectProcessor(threading.Thread): # Check to see whether we happen to be awaiting this # pubkey in order to send a message. If we are, it will do the POW # and send it. - if sendersAddressVersionNumber <= 3: - self.possibleNewPubkey(ripe=ripe.digest()) - elif sendersAddressVersionNumber >= 4: - self.possibleNewPubkey(address = fromAddress) + self.possibleNewPubkey(fromAddress) # If this message is bound for one of my version 3 addresses (or # higher), then we must check to make sure it meets our demanded @@ -548,8 +549,25 @@ class objectProcessor(threading.Thread): toAddress = '[Broadcast subscribers]' ripe = '' - t = ('', toAddress, ripe, fromAddress, subject, message, ackdataForBroadcast, int( - time.time()), 'broadcastqueued', 1, 1, 'sent', 2) + # We really should have a discussion about how to + # set the TTL for mailing list broadcasts. This is obviously + # hard-coded. + TTL = 2*7*24*60*60 # 2 weeks + t = ('', + toAddress, + ripe, + fromAddress, + subject, + message, + ackdataForBroadcast, + int(time.time()), # sentTime (this doesn't change) + int(time.time()), # lastActionTime + 0, + 'broadcastqueued', + 0, + 'sent', + 2, + TTL) helper_sent.insert(t) shared.UISignalQueue.put(('displayNewSentMessage', ( @@ -710,7 +728,7 @@ class objectProcessor(threading.Thread): # Let's store the public key in case we want to reply to this person. sqlExecute('''INSERT INTO pubkeys VALUES (?,?,?,?,?)''', - calculatedRipe, + fromAddress, sendersAddressVersion, decryptedData[:endOfPubkeyPosition], int(time.time()), @@ -719,10 +737,7 @@ class objectProcessor(threading.Thread): # Check to see whether we happen to be awaiting this # pubkey in order to send a message. If we are, it will do the POW # and send it. - if broadcastVersion == 4: - self.possibleNewPubkey(ripe=calculatedRipe) - elif broadcastVersion == 5: - self.possibleNewPubkey(address=fromAddress) + self.possibleNewPubkey(fromAddress) fromAddress = encodeAddress( sendersAddressVersion, sendersStream, calculatedRipe) @@ -769,31 +784,33 @@ class objectProcessor(threading.Thread): logger.info('Time spent processing this interesting broadcast: %s' % (time.time() - messageProcessingStartTime,)) - def possibleNewPubkey(self, ripe=None, address=None): + def possibleNewPubkey(self, address): """ We have inserted a pubkey into our pubkey table which we received from a pubkey, msg, or broadcast message. It might be one that we have been waiting for. Let's check. """ - # For address versions <= 3, we wait on a key with the correct ripe hash - if ripe != None: - if ripe in shared.neededPubkeys: - del shared.neededPubkeys[ripe] - self.sendMessages(ripe) + + # For address versions <= 3, we wait on a key with the correct address version, + # stream number, and RIPE hash. + status, addressVersion, streamNumber, ripe = decodeAddress(address) + if addressVersion <=3: + if address in shared.neededPubkeys: + del shared.neededPubkeys[address] + self.sendMessages(address) else: - logger.debug('We don\'t need this pub key. We didn\'t ask for it. Pubkey hash: %s' % ripe.encode('hex')) + logger.debug('We don\'t need this pub key. We didn\'t ask for it. For address: %s' % address) # For address versions >= 4, we wait on a pubkey with the correct tag. # Let us create the tag from the address and see if we were waiting # for it. - elif address != None: - status, addressVersion, streamNumber, ripe = decodeAddress(address) + elif addressVersion >= 4: tag = hashlib.sha512(hashlib.sha512(encodeVarint( addressVersion) + encodeVarint(streamNumber) + ripe).digest()).digest()[32:] if tag in shared.neededPubkeys: del shared.neededPubkeys[tag] - self.sendMessages(ripe) + self.sendMessages(address) - def sendMessages(self, ripe): + def sendMessages(self, address): """ This function is called by the possibleNewPubkey function when that function sees that we now have the necessary pubkey @@ -801,8 +818,8 @@ class objectProcessor(threading.Thread): """ logger.info('We have been awaiting the arrival of this pubkey.') sqlExecute( - '''UPDATE sent SET status='doingmsgpow' WHERE toripe=? AND (status='awaitingpubkey' or status='doingpubkeypow') and folder='sent' ''', - ripe) + '''UPDATE sent SET status='doingmsgpow', retrynumber=0 WHERE toaddress=? AND (status='awaitingpubkey' or status='doingpubkeypow') AND folder='sent' ''', + address) shared.workerQueue.put(('sendmessage', '')) def ackDataHasAVaildHeader(self, ackData): diff --git a/src/class_receiveDataThread.py b/src/class_receiveDataThread.py index 5d56e98a..ff5371ad 100644 --- a/src/class_receiveDataThread.py +++ b/src/class_receiveDataThread.py @@ -16,11 +16,7 @@ import traceback #import highlevelcrypto from addresses import * from helper_generic import addDataPadding, isHostInPrivateIPRange -#import helper_bitcoin -#import helper_inbox -#import helper_sent -from helper_sql import * -#import tr +from helper_sql import sqlQuery from debug import logger # This thread is created either by the synSenderThread(for outgoing diff --git a/src/class_singleCleaner.py b/src/class_singleCleaner.py index 31c697d5..b441d11c 100644 --- a/src/class_singleCleaner.py +++ b/src/class_singleCleaner.py @@ -76,23 +76,23 @@ class singleCleaner(threading.Thread): '''DELETE FROM pubkeys WHERE time?) ''', - int(time.time()) - shared.maximumLengthOfTimeToBotherResendingMessages) # If the message's folder='trash' then we'll ignore it. + '''select toaddress, ackdata, status FROM sent WHERE ((status='awaitingpubkey' OR status='msgsent') AND folder='sent' AND sleeptill?) ''', + int(time.time()), + int(time.time()) - shared.maximumLengthOfTimeToBotherResendingMessages) for row in queryreturn: - if len(row) < 5: + if len(row) < 2: with shared.printLock: sys.stderr.write( 'Something went wrong in the singleCleaner thread: a query did not return the requested fields. ' + repr(row)) time.sleep(3) break - toaddress, toripe, fromaddress, subject, message, ackdata, lastactiontime, status, pubkeyretrynumber, msgretrynumber = row + toAddress, ackData, status = row if status == 'awaitingpubkey': - if (int(time.time()) - lastactiontime) > (shared.maximumAgeOfAnObjectThatIAmWillingToAccept * (2 ** (pubkeyretrynumber))): - resendPubkey(pubkeyretrynumber,toripe) - else: # status == msgsent - if (int(time.time()) - lastactiontime) > (shared.maximumAgeOfAnObjectThatIAmWillingToAccept * (2 ** (msgretrynumber))): - resendMsg(msgretrynumber,ackdata) + resendPubkeyRequest(toAddress) + elif status == 'msgsent': + resendMsg(ackData) # Let's also clear and reload shared.inventorySets to keep it from # taking up an unnecessary amount of memory. @@ -126,32 +126,26 @@ class singleCleaner(threading.Thread): time.sleep(300) -def resendPubkey(pubkeyretrynumber,toripe): - print 'It has been a long time and we haven\'t heard a response to our getpubkey request. Sending again.' +def resendPubkeyRequest(address): + logger.debug('It has been a long time and we haven\'t heard a response to our getpubkey request. Sending again.') try: del shared.neededPubkeys[ - toripe] # We need to take this entry out of the shared.neededPubkeys structure because the shared.workerQueue checks to see whether the entry is already present and will not do the POW and send the message because it assumes that it has already done it recently. + address] # We need to take this entry out of the shared.neededPubkeys structure because the shared.workerQueue checks to see whether the entry is already present and will not do the POW and send the message because it assumes that it has already done it recently. except: pass shared.UISignalQueue.put(( 'updateStatusBar', 'Doing work necessary to again attempt to request a public key...')) - t = () sqlExecute( - '''UPDATE sent SET lastactiontime=?, pubkeyretrynumber=?, status='msgqueued' WHERE toripe=?''', - int(time.time()), - pubkeyretrynumber + 1, - toripe) + '''UPDATE sent SET status='msgqueued' WHERE toaddress=?''', + address) shared.workerQueue.put(('sendmessage', '')) -def resendMsg(msgretrynumber,ackdata): - print 'It has been a long time and we haven\'t heard an acknowledgement to our msg. Sending again.' +def resendMsg(ackdata): + logger.debug('It has been a long time and we haven\'t heard an acknowledgement to our msg. Sending again.') sqlExecute( - '''UPDATE sent SET lastactiontime=?, msgretrynumber=?, status=? WHERE ackdata=?''', - int(time.time()), - msgretrynumber + 1, - 'msgqueued', - ackdata) + '''UPDATE sent SET status='msgqueued' WHERE ackdata=?''', + ackdata) shared.workerQueue.put(('sendmessage', '')) shared.UISignalQueue.put(( 'updateStatusBar', 'Doing work necessary to again attempt to deliver a message...')) diff --git a/src/class_singleWorker.py b/src/class_singleWorker.py index feda7638..327f526a 100644 --- a/src/class_singleWorker.py +++ b/src/class_singleWorker.py @@ -28,13 +28,15 @@ class singleWorker(threading.Thread): threading.Thread.__init__(self) def run(self): + + # Initialize the neededPubkeys dictionary. queryreturn = sqlQuery( '''SELECT DISTINCT toaddress FROM sent WHERE (status='awaitingpubkey' AND folder='sent')''') for row in queryreturn: toAddress, = row toStatus, toAddressVersionNumber, toStreamNumber, toRipe = decodeAddress(toAddress) if toAddressVersionNumber <= 3 : - shared.neededPubkeys[toRipe] = 0 + shared.neededPubkeys[toAddress] = 0 elif toAddressVersionNumber >= 4: doubleHashOfAddressData = hashlib.sha512(hashlib.sha512(encodeVarint( toAddressVersionNumber) + encodeVarint(toStreamNumber) + toRipe).digest()).digest() @@ -50,15 +52,15 @@ class singleWorker(threading.Thread): print 'Watching for ackdata', ackdata.encode('hex') shared.ackdataForWhichImWatching[ackdata] = 0 + time.sleep( + 10) # give some time for the GUI to start before we start on existing POW tasks. + queryreturn = sqlQuery( '''SELECT DISTINCT toaddress FROM sent WHERE (status='doingpubkeypow' AND folder='sent')''') for row in queryreturn: toaddress, = row self.requestPubKey(toaddress) - time.sleep( - 10) # give some time for the GUI to start before we start on existing POW tasks. - self.sendMsg() # just in case there are any pending tasks for msg # messages that have yet to be sent. @@ -351,9 +353,9 @@ class singleWorker(threading.Thread): def sendBroadcast(self): queryreturn = sqlQuery( - '''SELECT fromaddress, subject, message, ackdata FROM sent WHERE status=? and folder='sent' ''', 'broadcastqueued') + '''SELECT fromaddress, subject, message, ackdata, ttl FROM sent WHERE status=? and folder='sent' ''', 'broadcastqueued') for row in queryreturn: - fromaddress, subject, body, ackdata = row + fromaddress, subject, body, ackdata, TTL = row status, addressVersionNumber, streamNumber, ripe = decodeAddress( fromaddress) if addressVersionNumber <= 1: @@ -383,7 +385,11 @@ class singleWorker(threading.Thread): pubEncryptionKey = highlevelcrypto.privToPub( privEncryptionKeyHex).decode('hex') - TTL = int(28 * 24 * 60 * 60 + random.randrange(-300, 300))# 28 days from now plus or minus five minutes + if TTL > 28 * 24 * 60 * 60: + TTL = 28 * 24 * 60 * 60 + if TTL < 60*60: + TTL = 60*60 + TTL = int(TTL + random.randrange(-300, 300))# add some randomness to the TTL embeddedTime = int(time.time() + TTL) payload = pack('>Q', embeddedTime) payload += '\x00\x00\x00\x03' # object type: broadcast @@ -479,12 +485,12 @@ class singleWorker(threading.Thread): # Select just one msg that needs work. queryreturn = sqlQuery( - '''SELECT toaddress, toripe, fromaddress, subject, message, ackdata, status FROM sent WHERE (status='msgqueued' or status='doingmsgpow' or status='forcepow') and folder='sent' LIMIT 1''') + '''SELECT toaddress, fromaddress, subject, message, ackdata, status, ttl, retrynumber FROM sent WHERE (status='msgqueued' or status='doingmsgpow' or status='forcepow') and folder='sent' LIMIT 1''') if len(queryreturn) == 0: # if there is no work to do then break # break out of this sendMsg loop and # wait for something to get put in the shared.workerQueue. row = queryreturn[0] - toaddress, toripe, fromaddress, subject, message, ackdata, status = row + toaddress, fromaddress, subject, message, ackdata, status, TTL, retryNumber = row toStatus, toAddressVersionNumber, toStreamNumber, toRipe = decodeAddress( toaddress) fromStatus, fromAddressVersionNumber, fromStreamNumber, fromRipe = decodeAddress( @@ -496,38 +502,45 @@ class singleWorker(threading.Thread): # because the user could not have overridden the message about the POW being # too difficult without knowing the required difficulty. pass + elif status == 'doingmsgpow': + # We wouldn't have set the status to doingmsgpow if we didn't already have the pubkey + # so let's assume that we have it. + pass # If we are sending a message to ourselves or a chan then we won't need an entry in the pubkeys table; we can calculate the needed pubkey using the private keys in our keys.dat file. elif shared.config.has_section(toaddress): sqlExecute( '''UPDATE sent SET status='doingmsgpow' WHERE toaddress=? AND status='msgqueued' ''', toaddress) status='doingmsgpow' - else: + elif status == 'msgqueued': # Let's see if we already have the pubkey in our pubkeys table queryreturn = sqlQuery( - '''SELECT hash FROM pubkeys WHERE hash=? AND addressversion=?''', toRipe, toAddressVersionNumber) + '''SELECT address FROM pubkeys WHERE address=?''', toaddress) if queryreturn != []: # If we have the needed pubkey in the pubkey table already, # set the status of this msg to doingmsgpow sqlExecute( '''UPDATE sent SET status='doingmsgpow' WHERE toaddress=? AND status='msgqueued' ''', toaddress) status = 'doingmsgpow' - # mark the pubkey as 'usedpersonally' so that we don't delete it later + # mark the pubkey as 'usedpersonally' so that we don't delete it later. If the pubkey version + # is >= 4 then usedpersonally will already be set to yes because we'll only ever have + # usedpersonally v4 pubkeys in the pubkeys table. sqlExecute( - '''UPDATE pubkeys SET usedpersonally='yes' WHERE hash=? and addressversion=?''', - toRipe, - toAddressVersionNumber) + '''UPDATE pubkeys SET usedpersonally='yes' WHERE address=?''', + toaddress) else: # We don't have the needed pubkey in the pubkeys table already. if toAddressVersionNumber <= 3: toTag = '' else: toTag = hashlib.sha512(hashlib.sha512(encodeVarint(toAddressVersionNumber)+encodeVarint(toStreamNumber)+toRipe).digest()).digest()[32:] - if toRipe in shared.neededPubkeys or toTag in shared.neededPubkeys: + if toaddress in shared.neededPubkeys or toTag in shared.neededPubkeys: # We already sent a request for the pubkey sqlExecute( - '''UPDATE sent SET status='awaitingpubkey' WHERE toaddress=? AND status='msgqueued' ''', toaddress) - shared.UISignalQueue.put(('updateSentItemStatusByHash', ( - toRipe, tr.translateText("MainWindow",'Encryption key was requested earlier.')))) + '''UPDATE sent SET status='awaitingpubkey', sleeptill=? WHERE toaddress=? AND status='msgqueued' ''', + int(time.time()) + 2.5*24*60*60, + toaddress) + shared.UISignalQueue.put(('updateSentItemStatusByToAddress', ( + toaddress, tr.translateText("MainWindow",'Encryption key was requested earlier.')))) continue #on with the next msg on which we can do some work else: # We have not yet sent a request for the pubkey @@ -554,13 +567,13 @@ class singleWorker(threading.Thread): if shared.decryptAndCheckPubkeyPayload(payload, toaddress) == 'successful': needToRequestPubkey = False sqlExecute( - '''UPDATE sent SET status='doingmsgpow' WHERE toaddress=? AND (status='msgqueued' or status='awaitingpubkey' or status='doingpubkeypow')''', + '''UPDATE sent SET status='doingmsgpow', retrynumber=0 WHERE toaddress=? AND (status='msgqueued' or status='awaitingpubkey' or status='doingpubkeypow')''', toaddress) del shared.neededPubkeys[tag] - continue # We'll start back at the beginning, pick up this msg, mark the pubkey as 'usedpersonally', and then send the msg. + break #else: # There was something wrong with this pubkey object even # though it had the correct tag- almost certainly because - # of malicious behavior or a badly programmed client. If + # of malicious behavior or a badly programmed client. If # there are any other pubkeys in our inventory with the correct # tag then we'll try to decrypt those. @@ -572,21 +585,27 @@ class singleWorker(threading.Thread): if shared.decryptAndCheckPubkeyPayload(payload, toaddress) == 'successful': #if valid, this function also puts it in the pubkeys table. needToRequestPubkey = False sqlExecute( - '''UPDATE sent SET status='doingmsgpow' WHERE toaddress=? AND (status='msgqueued' or status='awaitingpubkey' or status='doingpubkeypow')''', + '''UPDATE sent SET status='doingmsgpow', retrynumber=0 WHERE toaddress=? AND (status='msgqueued' or status='awaitingpubkey' or status='doingpubkeypow')''', toaddress) del shared.neededPubkeys[tag] - continue # We'll start back at the beginning, pick up this msg, mark the pubkey as 'usedpersonally', and then send the msg. + break if needToRequestPubkey: sqlExecute( '''UPDATE sent SET status='doingpubkeypow' WHERE toaddress=? AND status='msgqueued' ''', toaddress) - shared.UISignalQueue.put(('updateSentItemStatusByHash', ( - toRipe, tr.translateText("MainWindow",'Sending a request for the recipient\'s encryption key.')))) + shared.UISignalQueue.put(('updateSentItemStatusByToAddress', ( + toaddress, tr.translateText("MainWindow",'Sending a request for the recipient\'s encryption key.')))) self.requestPubKey(toaddress) continue #on with the next msg on which we can do some work # At this point we know that we have the necessary pubkey in the pubkeys table. - TTL = int(28 * 24 * 60 * 60 + random.randrange(-300, 300))# 28 days from now plus or minus five minutes + + if retryNumber == 0: + if TTL > 28 * 24 * 60 * 60: + TTL = 28 * 24 * 60 * 60 + else: + TTL = 28 * 24 * 60 * 60 + TTL = int(TTL + random.randrange(-300, 300))# add some randomness to the TTL embeddedTime = int(time.time() + TTL) if not shared.config.has_section(toaddress): # if we aren't sending this to ourselves or a chan @@ -600,9 +619,8 @@ class singleWorker(threading.Thread): # the required proof of work difficulty is too hard then we'll # abort. queryreturn = sqlQuery( - 'SELECT transmitdata FROM pubkeys WHERE hash=? and addressversion=?', - toRipe, - toAddressVersionNumber) + 'SELECT transmitdata FROM pubkeys WHERE address=?', + toaddress) for row in queryreturn: pubkeyPayload, = row @@ -752,7 +770,7 @@ class singleWorker(threading.Thread): fullAckPayload = '' else: fullAckPayload = self.generateFullAckMessage( - ackdata, toStreamNumber) # The fullAckPayload is a normal msg protocol message with the proof of work already completed that the receiver of this message can easily send out. + ackdata, toStreamNumber, TTL) # The fullAckPayload is a normal msg protocol message with the proof of work already completed that the receiver of this message can easily send out. payload += encodeVarint(len(fullAckPayload)) payload += fullAckPayload dataToSign = pack('>Q', embeddedTime) + '\x00\x00\x00\x02' + encodeVarint(1) + encodeVarint(toStreamNumber) + payload @@ -809,14 +827,22 @@ class singleWorker(threading.Thread): shared.broadcastToSendDataQueues(( toStreamNumber, 'advertiseobject', inventoryHash)) - # Update the status of the message in the 'sent' table to have a - # 'msgsent' or 'msgsentnoackexpected' status. + # Update the sent message in the sent table with the necessary information. if shared.config.has_section(toaddress): newStatus = 'msgsentnoackexpected' else: newStatus = 'msgsent' - sqlExecute('''UPDATE sent SET msgid=?, status=? WHERE ackdata=?''', - inventoryHash,newStatus,ackdata) + if retryNumber == 0: + sleepTill = int(time.time()) + TTL + else: + sleepTill = int(time.time()) + 28*24*60*60 * 2**retryNumber + sqlExecute('''UPDATE sent SET msgid=?, status=?, retrynumber=?, sleeptill=?, lastactiontime=? WHERE ackdata=?''', + inventoryHash, + newStatus, + retryNumber+1, + sleepTill, + int(time.time()), + ackdata) # If we are sending to ourselves or a chan, let's put the message in # our own inbox. @@ -848,10 +874,18 @@ class singleWorker(threading.Thread): with shared.printLock: sys.stderr.write('Very abnormal error occurred in requestPubKey. toAddress is: ' + repr( toAddress) + '. Please report this error to Atheros.') - return + + queryReturn = sqlQuery( + '''SELECT retrynumber FROM sent WHERE toaddress=? AND (status='doingpubkeypow' OR status='awaitingpubkey') LIMIT 1''', + toAddress) + if len(queryReturn) == 0: + logger.critical("BUG: Why are we requesting the pubkey for %s if there are no messages in the sent folder to that address?" % toAddress) + return + retryNumber = queryReturn[0][0] + if addressVersionNumber <= 3: - shared.neededPubkeys[ripe] = 0 + shared.neededPubkeys[toAddress] = 0 elif addressVersionNumber >= 4: # If the user just clicked 'send' then the tag (and other information) will already # be in the neededPubkeys dictionary. But if we are recovering from a restart @@ -861,7 +895,11 @@ class singleWorker(threading.Thread): if tag not in shared.neededPubkeys: shared.neededPubkeys[tag] = (toAddress, highlevelcrypto.makeCryptor(privEncryptionKey.encode('hex'))) # We'll need this for when we receive a pubkey reply: it will be encrypted and we'll need to decrypt it. - TTL = int(2.5 * 24 * 60 * 60 + random.randrange(-300, 300)) # 2.5 days from now plus or minus five minutes + if retryNumber == 0: + TTL = 2.5*24*60*60 # 2.5 days. This was chosen fairly arbitrarily. + else: + TTL = 28*24*60*60 + TTL = TTL + random.randrange(-300, 300) # add some randomness to the TTL embeddedTime = int(time.time() + TTL) payload = pack('>Q', embeddedTime) payload += '\x00\x00\x00\x00' # object type: getpubkey @@ -879,8 +917,8 @@ class singleWorker(threading.Thread): # print 'trial value', trialValue statusbar = 'Doing the computations necessary to request the recipient\'s public key.' shared.UISignalQueue.put(('updateStatusBar', statusbar)) - shared.UISignalQueue.put(('updateSentItemStatusByHash', ( - ripe, tr.translateText("MainWindow",'Doing work necessary to request encryption key.')))) + shared.UISignalQueue.put(('updateSentItemStatusByToAddress', ( + toAddress, tr.translateText("MainWindow",'Doing work necessary to request encryption key.')))) target = 2 ** 64 / (shared.networkDefaultProofOfWorkNonceTrialsPerByte*(len(payload) + 8 + shared.networkDefaultPayloadLengthExtraBytes + ((TTL*(len(payload)+8+shared.networkDefaultPayloadLengthExtraBytes))/(2 ** 16)))) initialHash = hashlib.sha512(payload).digest() @@ -897,17 +935,40 @@ class singleWorker(threading.Thread): print 'sending inv (for the getpubkey message)' shared.broadcastToSendDataQueues(( streamNumber, 'advertiseobject', inventoryHash)) - + + if retryNumber == 0: + sleeptill = int(time.time()) + TTL + else: + sleeptill = int(time.time()) + 28*24*60*60 * 2**retryNumber sqlExecute( - '''UPDATE sent SET status='awaitingpubkey' WHERE toaddress=? AND status='doingpubkeypow' ''', + '''UPDATE sent SET lastactiontime=?, status='awaitingpubkey', retrynumber=?, sleeptill=? WHERE toaddress=? AND (status='doingpubkeypow' OR status='awaitingpubkey') ''', + int(time.time()), + retryNumber+1, + sleeptill, toAddress) shared.UISignalQueue.put(( 'updateStatusBar', tr.translateText("MainWindow",'Broacasting the public key request. This program will auto-retry if they are offline.'))) - shared.UISignalQueue.put(('updateSentItemStatusByHash', (ripe, tr.translateText("MainWindow",'Sending public key request. Waiting for reply. Requested at %1').arg(l10n.formatTimestamp())))) + shared.UISignalQueue.put(('updateSentItemStatusByToAddress', (toAddress, tr.translateText("MainWindow",'Sending public key request. Waiting for reply. Requested at %1').arg(l10n.formatTimestamp())))) - def generateFullAckMessage(self, ackdata, toStreamNumber): - TTL = int(2.5 * 24 * 60 * 60 + random.randrange(-300, 300)) # 2.5 days plus or minus 5 minutes + def generateFullAckMessage(self, ackdata, toStreamNumber, TTL): + + # It might be perfectly fine to just use the same TTL for + # the ackdata that we use for the message. But I would rather + # it be more difficult for attackers to associate ackData with + # the associated msg object. However, users would want the TTL + # of the acknowledgement to be about the same as they set + # for the message itself. So let's set the TTL of the + # acknowledgement to be in one of three 'buckets': 1 hour, 7 + # days, or 28 days, whichever is relatively close to what the + # user specified. + if TTL < 24*60*60: # 1 day + TTL = 24*60*60 # 1 day + elif TTL < 7*24*60*60: # 1 week + TTL = 7*24*60*60 # 1 week + else: + TTL = 28*24*60*60 # 4 weeks + TTL = int(TTL + random.randrange(-300, 300)) # Add some randomness to the TTL embeddedTime = int(time.time() + TTL) payload = pack('>Q', (embeddedTime)) payload += '\x00\x00\x00\x02' # object type: msg @@ -916,7 +977,7 @@ class singleWorker(threading.Thread): target = 2 ** 64 / (shared.networkDefaultProofOfWorkNonceTrialsPerByte*(len(payload) + 8 + shared.networkDefaultPayloadLengthExtraBytes + ((TTL*(len(payload)+8+shared.networkDefaultPayloadLengthExtraBytes))/(2 ** 16)))) with shared.printLock: - print '(For ack message) Doing proof of work...' + print '(For ack message) Doing proof of work. TTL set to', TTL powStartTime = time.time() initialHash = hashlib.sha512(payload).digest() diff --git a/src/class_sqlThread.py b/src/class_sqlThread.py index 56e86118..514f772e 100644 --- a/src/class_sqlThread.py +++ b/src/class_sqlThread.py @@ -30,7 +30,7 @@ class sqlThread(threading.Thread): self.cur.execute( '''CREATE TABLE inbox (msgid blob, toaddress text, fromaddress text, subject text, received text, message text, folder text, encodingtype int, read bool, sighash blob, UNIQUE(msgid) ON CONFLICT REPLACE)''' ) self.cur.execute( - '''CREATE TABLE sent (msgid blob, toaddress text, toripe blob, fromaddress text, subject text, message text, ackdata blob, lastactiontime integer, status text, pubkeyretrynumber integer, msgretrynumber integer, folder text, encodingtype int)''' ) + '''CREATE TABLE sent (msgid blob, toaddress text, toripe blob, fromaddress text, subject text, message text, ackdata blob, senttime integer, lastactiontime integer, sleeptill integer, status text, retrynumber integer, folder text, encodingtype int, ttl int)''' ) self.cur.execute( '''CREATE TABLE subscriptions (label text, address text, enabled bool)''' ) self.cur.execute( @@ -39,29 +39,15 @@ class sqlThread(threading.Thread): '''CREATE TABLE blacklist (label text, address text, enabled bool)''' ) self.cur.execute( '''CREATE TABLE whitelist (label text, address text, enabled bool)''' ) - """ - Explanation of what is in the pubkeys table: - The hash is the RIPEMD160 hash that is encoded in the Bitmessage address. - - transmitdata /was/ literally the data that was included in the Bitmessage pubkey message when it arrived, - except for the 24 byte protocol header- ie, it started with the POW nonce. Since protocol v3, to maintain - backwards compability, the data format of the data on disk is staying the same even though the wire format has changed. - - time is the time that the pubkey was broadcast on the network same as with every other type of Bitmessage object. - - usedpersonally is set to "yes" if we have used the key personally. This keeps us from deleting it because we may want to - reply to a message in the future. This field is not a bool because we may need more flexability in the future and it doesn't - take up much more space anyway. - """ self.cur.execute( - '''CREATE TABLE pubkeys (hash blob, addressversion int, transmitdata blob, time int, usedpersonally text, UNIQUE(hash, addressversion) ON CONFLICT REPLACE)''' ) + '''CREATE TABLE pubkeys (address text, addressversion int, transmitdata blob, time int, usedpersonally text, UNIQUE(address) ON CONFLICT REPLACE)''' ) self.cur.execute( '''CREATE TABLE inventory (hash blob, objecttype int, streamnumber int, payload blob, expirestime integer, tag blob, UNIQUE(hash) ON CONFLICT REPLACE)''' ) self.cur.execute( '''INSERT INTO subscriptions VALUES('Bitmessage new releases/announcements','BM-GtovgYdgs7qXPkoYaRgrLFuFKz1SFpsw',1)''') self.cur.execute( '''CREATE TABLE settings (key blob, value blob, UNIQUE(key) ON CONFLICT REPLACE)''' ) - self.cur.execute( '''INSERT INTO settings VALUES('version','9')''') + self.cur.execute( '''INSERT INTO settings VALUES('version','10')''') self.cur.execute( '''INSERT INTO settings VALUES('lastvacuumtime',?)''', ( int(time.time()),)) self.cur.execute( @@ -376,10 +362,56 @@ class sqlThread(threading.Thread): parameters = (9,) self.cur.execute(item, parameters) - # TTL is now user-specifyable. Let's add an option to save whatever the user selects. + # TTL is now user-specifiable. Let's add an option to save whatever the user selects. if not shared.config.has_option('bitmessagesettings', 'ttl'): shared.config.set('bitmessagesettings', 'ttl', '367200') - + # We'll also need a `sleeptill` field and a `ttl` field. Also we can combine + # the pubkeyretrynumber and msgretrynumber into one. + item = '''SELECT value FROM settings WHERE key='version';''' + parameters = '' + self.cur.execute(item, parameters) + currentVersion = int(self.cur.fetchall()[0][0]) + if currentVersion == 9: + logger.info('In messages.dat database, making TTL-related changes: combining the pubkeyretrynumber and msgretrynumber fields into the retrynumber field and adding the sleeptill and ttl fields...') + self.cur.execute( + '''CREATE TEMPORARY TABLE sent_backup (msgid blob, toaddress text, toripe blob, fromaddress text, subject text, message text, ackdata blob, lastactiontime integer, status text, retrynumber integer, folder text, encodingtype int)''' ) + self.cur.execute( + '''INSERT INTO sent_backup SELECT msgid, toaddress, toripe, fromaddress, subject, message, ackdata, lastactiontime, status, 0, folder, encodingtype FROM sent;''') + self.cur.execute( '''DROP TABLE sent''') + self.cur.execute( + '''CREATE TABLE sent (msgid blob, toaddress text, toripe blob, fromaddress text, subject text, message text, ackdata blob, senttime integer, lastactiontime integer, sleeptill int, status text, retrynumber integer, folder text, encodingtype int, ttl int)''' ) + self.cur.execute( + '''INSERT INTO sent SELECT msgid, toaddress, toripe, fromaddress, subject, message, ackdata, lastactiontime, lastactiontime, 0, status, 0, folder, encodingtype, 216000 FROM sent_backup;''') + self.cur.execute( '''DROP TABLE sent_backup''') + logger.info('In messages.dat database, finished making TTL-related changes.') + logger.debug('In messages.dat database, adding address field to the pubkeys table.') + # We're going to have to calculate the address for each row in the pubkeys + # table. Then we can take out the hash field. + self.cur.execute('''ALTER TABLE pubkeys ADD address text DEFAULT '' ''') + self.cur.execute('''SELECT hash, addressversion FROM pubkeys''') + queryResult = self.cur.fetchall() + from addresses import encodeAddress + for row in queryResult: + hash, addressVersion = row + address = encodeAddress(addressVersion, 1, hash) + item = '''UPDATE pubkeys SET address=? WHERE hash=?;''' + parameters = (address, hash) + self.cur.execute(item, parameters) + # Now we can remove the hash field from the pubkeys table. + self.cur.execute( + '''CREATE TEMPORARY TABLE pubkeys_backup (address text, addressversion int, transmitdata blob, time int, usedpersonally text, UNIQUE(address) ON CONFLICT REPLACE)''' ) + self.cur.execute( + '''INSERT INTO pubkeys_backup SELECT address, addressversion, transmitdata, time, usedpersonally FROM pubkeys;''') + self.cur.execute( '''DROP TABLE pubkeys''') + self.cur.execute( + '''CREATE TABLE pubkeys (address text, addressversion int, transmitdata blob, time int, usedpersonally text, UNIQUE(address) ON CONFLICT REPLACE)''' ) + self.cur.execute( + '''INSERT INTO pubkeys SELECT address, addressversion, transmitdata, time, usedpersonally FROM pubkeys_backup;''') + self.cur.execute( '''DROP TABLE pubkeys_backup''') + logger.debug('In messages.dat database, done adding address field to the pubkeys table and removing the hash field.') + self.cur.execute('''update settings set value=10 WHERE key='version';''') + + # Are you hoping to add a new option to the keys.dat file of existing # Bitmessage users or modify the SQLite database? Add it right above this line! @@ -389,11 +421,11 @@ class sqlThread(threading.Thread): self.cur.execute( '''INSERT INTO pubkeys VALUES(?,?,?,?,?)''', t) self.conn.commit() self.cur.execute( - '''SELECT transmitdata FROM pubkeys WHERE hash='1234' ''') + '''SELECT transmitdata FROM pubkeys WHERE address='1234' ''') queryreturn = self.cur.fetchall() for row in queryreturn: transmitdata, = row - self.cur.execute('''DELETE FROM pubkeys WHERE hash='1234' ''') + self.cur.execute('''DELETE FROM pubkeys WHERE address='1234' ''') self.conn.commit() if transmitdata == '': logger.fatal('Problem: The version of SQLite you have cannot store Null values. Please download and install the latest revision of your version of Python (for example, the latest Python 2.7 revision) and try again.\n') diff --git a/src/helper_sent.py b/src/helper_sent.py index 75634b49..8dde7215 100644 --- a/src/helper_sent.py +++ b/src/helper_sent.py @@ -1,4 +1,4 @@ from helper_sql import * def insert(t): - sqlExecute('''INSERT INTO sent VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)''', *t) + sqlExecute('''INSERT INTO sent VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)''', *t) diff --git a/src/message_data_reader.py b/src/message_data_reader.py index 80cea70a..250e06a9 100644 --- a/src/message_data_reader.py +++ b/src/message_data_reader.py @@ -30,8 +30,8 @@ def readSent(): cur.execute(item, parameters) output = cur.fetchall() for row in output: - msgid, toaddress, toripe, fromaddress, subject, message, ackdata, lastactiontime, status, pubkeyretrynumber, msgretrynumber, folder, encodingtype = row - print msgid.encode('hex'), toaddress, 'toripe:', toripe.encode('hex'), 'fromaddress:', fromaddress, 'ENCODING TYPE:', encodingtype, 'SUBJECT:', repr(subject), 'MESSAGE:', repr(message), 'ACKDATA:', ackdata.encode('hex'), lastactiontime, status, pubkeyretrynumber, msgretrynumber, folder + msgid, toaddress, toripe, fromaddress, subject, message, ackdata, lastactiontime, sleeptill, status, retrynumber, folder, encodingtype, ttl = row + print msgid.encode('hex'), toaddress, 'toripe:', toripe.encode('hex'), 'fromaddress:', fromaddress, 'ENCODING TYPE:', encodingtype, 'SUBJECT:', repr(subject), 'MESSAGE:', repr(message), 'ACKDATA:', ackdata.encode('hex'), lastactiontime, status, retrynumber, folder def readSubscriptions(): print 'Printing everything in subscriptions table:' @@ -44,13 +44,13 @@ def readSubscriptions(): def readPubkeys(): print 'Printing everything in pubkeys table:' - item = '''select hash, transmitdata, time, usedpersonally from pubkeys''' + item = '''select address, transmitdata, time, usedpersonally from pubkeys''' parameters = '' cur.execute(item, parameters) output = cur.fetchall() for row in output: - hash, transmitdata, time, usedpersonally = row - print 'Hash:', hash.encode('hex'), '\tTime first broadcast:', unicode(strftime('%a, %d %b %Y %I:%M %p',localtime(time)),'utf-8'), '\tUsed by me personally:', usedpersonally, '\tFull pubkey message:', transmitdata.encode('hex') + address, transmitdata, time, usedpersonally = row + print 'Address:', address, '\tTime first broadcast:', unicode(strftime('%a, %d %b %Y %I:%M %p',localtime(time)),'utf-8'), '\tUsed by me personally:', usedpersonally, '\tFull pubkey message:', transmitdata.encode('hex') def readInventory(): print 'Printing everything in inventory table:' diff --git a/src/shared.py b/src/shared.py index cfe24340..d82f00a5 100644 --- a/src/shared.py +++ b/src/shared.py @@ -570,7 +570,7 @@ def decryptAndCheckPubkeyPayload(data, address): ) ) - t = (ripe, addressVersion, storedData, int(time.time()), 'yes') + t = (address, addressVersion, storedData, int(time.time()), 'yes') sqlExecute('''INSERT INTO pubkeys VALUES (?,?,?,?,?)''', *t) return 'successful' except varintDecodeError as e: From ce9480ab575f5eb2a61c811f105defd7a6c11835 Mon Sep 17 00:00:00 2001 From: Jonathan Warren Date: Mon, 9 Mar 2015 02:42:28 -0400 Subject: [PATCH 3/4] forgot a question mark character in a sql query --- src/bitmessagecurses/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bitmessagecurses/__init__.py b/src/bitmessagecurses/__init__.py index 8a4d6768..77d09729 100644 --- a/src/bitmessagecurses/__init__.py +++ b/src/bitmessagecurses/__init__.py @@ -787,7 +787,7 @@ def sendMessage(sender="", recv="", broadcast=None, subject="", body="", reply=F recv = BROADCAST_STR ripe = "" sqlExecute( - "INSERT INTO sent VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?)", + "INSERT INTO sent VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)", "", recv, ripe, From 4622d952e47a7dbb3a90aa79f4d20163aa14b041 Mon Sep 17 00:00:00 2001 From: Jonathan Warren Date: Mon, 9 Mar 2015 22:33:46 -0400 Subject: [PATCH 4/4] update list of defaultKnownNodes --- src/defaultKnownNodes.py | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/defaultKnownNodes.py b/src/defaultKnownNodes.py index 3a7fe309..f91e6fe6 100644 --- a/src/defaultKnownNodes.py +++ b/src/defaultKnownNodes.py @@ -12,16 +12,15 @@ def createDefaultKnownNodes(appdata): stream1 = {} #stream1[shared.Peer('2604:2000:1380:9f:82e:148b:2746:d0c7', 8080)] = int(time.time()) - stream1[shared.Peer('23.239.9.147', 8444)] = int(time.time()) - stream1[shared.Peer('98.218.125.214', 8444)] = int(time.time()) - stream1[shared.Peer('192.121.170.162', 8444)] = int(time.time()) - stream1[shared.Peer('108.61.72.12', 28444)] = int(time.time()) + stream1[shared.Peer('5.45.99.75', 8444)] = int(time.time()) + stream1[shared.Peer('75.167.159.54', 8444)] = int(time.time()) + stream1[shared.Peer('95.165.168.168', 8444)] = int(time.time()) + stream1[shared.Peer('85.180.139.241', 8444)] = int(time.time()) stream1[shared.Peer('158.222.211.81', 8080)] = int(time.time()) - stream1[shared.Peer('79.163.240.110', 8446)] = int(time.time()) - stream1[shared.Peer('178.62.154.250', 8444)] = int(time.time()) - stream1[shared.Peer('178.62.155.6', 8444)] = int(time.time()) - stream1[shared.Peer('178.62.155.8', 8444)] = int(time.time()) - stream1[shared.Peer('68.42.42.120', 8444)] = int(time.time()) + stream1[shared.Peer('178.62.12.187', 8448)] = int(time.time()) + stream1[shared.Peer('24.188.198.204', 8111)] = int(time.time()) + stream1[shared.Peer('109.147.204.113', 1195)] = int(time.time()) + stream1[shared.Peer('178.11.46.221', 8444)] = int(time.time()) ############# Stream 2 ################# stream2 = {}