From c1a7356e1a2e8c2709adc3c010e701786a2368f6 Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Wed, 11 Sep 2013 22:14:39 +0200 Subject: [PATCH 01/18] Fix German translation of max difficulty tab --- src/translations/bitmessage_de.qm | Bin 62134 -> 62138 bytes src/translations/bitmessage_de.ts | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/src/translations/bitmessage_de.qm b/src/translations/bitmessage_de.qm index 0e8e68a3353d805d725d86ff0bb32a74ed239e8f..c06e4e42ecf42c078a71c2268c213d612018b503 100644 GIT binary patch delta 305 zcmV-10nYxmasS7~|x0N2}-4FMMcy^|#Y zF9FPxRRLE4h?A`WHvwUjPlSKw^0bG-{21fzlll=x)0YH;g2R8wUvyBHA0RaV* zr3g0$&S?Mu>Cv;|2%O6UZ~#b?fz(9-ER)65MFlJXAOLlf&$%g+Hq|ndI!h3&rkIPr+&Y!fva zaI(So@Uo9z5auXnP+*G}U~`J|2n!~6u_0J|h=O47GMJuf?{OtBC6qN4gfkSI2?AZw(){VYupxFf-2LR^9LU2h%8K!2kdN diff --git a/src/translations/bitmessage_de.ts b/src/translations/bitmessage_de.ts index 3814fa86..9eb718c3 100644 --- a/src/translations/bitmessage_de.ts +++ b/src/translations/bitmessage_de.ts @@ -1417,7 +1417,7 @@ Die Zufallszahlen-Option ist standard, jedoch haben deterministische Adressen ei Here you may set the maximum amount of work you are willing to do to send a message to another person. Setting these values to 0 means that any value is acceptable. - hier setzen Sie die maximale Arbeit die Sie bereit sind zu verrichten um eine Nachricht an eine andere Person zu verwenden. Ein Wert von 0 bedeutet, dass Sie jede Arbeit akzeptieren. + Hier setzen Sie die maximale Arbeit, die Sie bereit sind zu verrichten, um eine Nachricht an eine andere Person zu versenden. Ein Wert von 0 bedeutet, dass Sie jede Arbeit akzeptieren. From 2293253d385bf90444261ff368d2fe001e70e29f Mon Sep 17 00:00:00 2001 From: ikarakatsanis Date: Thu, 26 Sep 2013 16:21:11 +0400 Subject: [PATCH 02/18] test to check git usage --- src/bitmessageqt/settings.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/bitmessageqt/settings.py b/src/bitmessageqt/settings.py index a02c4df5..9a4777c2 100644 --- a/src/bitmessageqt/settings.py +++ b/src/bitmessageqt/settings.py @@ -395,3 +395,4 @@ class Ui_settingsDialog(object): self.radioButtonNamecoinNmcontrol.setText(_translate("settingsDialog", "NMControl", None)) self.tabWidgetSettings.setTabText(self.tabWidgetSettings.indexOf(self.tabNamecoin), _translate("settingsDialog", "Namecoin integration", None)) +#just test \ No newline at end of file From 234081cc1725bf4bc1793bb541b720d23f64b4ac Mon Sep 17 00:00:00 2001 From: ikarakatsanis Date: Fri, 27 Sep 2013 02:14:24 +0400 Subject: [PATCH 03/18] New tab "Adjusting time period for resending messages" was added --- src/bitmessageqt/settings.py | 52 +++++++++++++++++++++++++-- src/bitmessageqt/settings.ui | 70 +++++++++++++++++++++++++++++++++++- 2 files changed, 119 insertions(+), 3 deletions(-) diff --git a/src/bitmessageqt/settings.py b/src/bitmessageqt/settings.py index 9a4777c2..56407d7e 100644 --- a/src/bitmessageqt/settings.py +++ b/src/bitmessageqt/settings.py @@ -318,7 +318,49 @@ class Ui_settingsDialog(object): 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) - +#this line existed before +#my new implementation starts here + self.tabResendingMessagesAdjustment=QtGui.QWidget() + self.tabResendingMessagesAdjustment.setObjectName(_fromUtf8("tabResendingMessagesAdjustment")) + self.gridLayout_9 = QtGui.QGridLayout(self.tabResendingMessagesAdjustment) + self.gridLayout_9.setObjectName(_fromUtf8("gridLayout_9")) + self.label_19 = QtGui.QLabel(self.tabResendingMessagesAdjustment) + self.label_19.setWordWrap(True) + self.label_19.setObjectName(_fromUtf8("label_19")) + self.gridLayout_9.addWidget(self.label_19, 0, 0, 1, 0) + spacerItem13 = QtGui.QSpacerItem(102, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum) + self.gridLayout_9.addItem(spacerItem13, 1, 0, 1, 1) + self.horizontalLayout = QtGui.QHBoxLayout() + self.horizontalLayout.setObjectName(_fromUtf8("horizontalLayout")) + self.label_20 = QtGui.QLabel(self.tabResendingMessagesAdjustment) + self.label_20.setLayoutDirection(QtCore.Qt.LeftToRight) + self.label_20.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) + self.label_20.setObjectName(_fromUtf8("label_20")) + self.gridLayout_9.addWidget(self.label_20, 2, 0, 1, 1) + self.lineEditHours = QtGui.QLineEdit(self.tabResendingMessagesAdjustment) + self.lineEditHours.setMaximumSize(QtCore.QSize(33, 16777)) + self.lineEditHours.setObjectName(_fromUtf8("lineEditHours")) + self.gridLayout_9.addWidget(self.lineEditHours, 2, 1, 1, 1) + self.label_22 = QtGui.QLabel(self.tabResendingMessagesAdjustment) + self.label_22.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) + self.label_22.setObjectName(_fromUtf8("label_22")) + self.gridLayout_9.addWidget(self.label_22, 2, 2, 1, 1) + self.lineEditDays = QtGui.QLineEdit(self.tabResendingMessagesAdjustment) + self.lineEditDays.setMaximumSize(QtCore.QSize(33, 16777)) + self.lineEditDays.setObjectName(_fromUtf8("lineEditDays")) + self.gridLayout_9.addWidget(self.lineEditDays, 2, 3, 1, 1) + self.label_23 = QtGui.QLabel(self.tabResendingMessagesAdjustment) + self.label_23.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) + self.label_23.setObjectName(_fromUtf8("label_23")) + self.gridLayout_9.addWidget(self.label_23, 2, 4, 1, 1) + self.lineEditMonths = QtGui.QLineEdit(self.tabResendingMessagesAdjustment) + self.lineEditMonths.setMaximumSize(QtCore.QSize(33, 16777)) + self.lineEditMonths.setObjectName(_fromUtf8("lineEditMonths")) + self.gridLayout_9.addWidget(self.lineEditMonths, 2, 5, 1, 1) + spacerItem15 = QtGui.QSpacerItem(20, 147, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding) + self.gridLayout_9.addItem(spacerItem15, 3, 1, 1, 1) + self.tabWidgetSettings.addTab(self.tabResendingMessagesAdjustment, _fromUtf8("")) + #my new implementation stops here, it wasn't line here self.retranslateUi(settingsDialog) self.tabWidgetSettings.setCurrentIndex(0) QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(_fromUtf8("accepted()")), settingsDialog.accept) @@ -382,6 +424,13 @@ class Ui_settingsDialog(object): self.tabWidgetSettings.setTabText(self.tabWidgetSettings.indexOf(self.tab), _translate("settingsDialog", "Demanded difficulty", None)) self.label_15.setText(_translate("settingsDialog", "Here you may set the maximum amount of work you are willing to do to send a message to another person. Setting these values to 0 means that any value is acceptable.", None)) self.label_13.setText(_translate("settingsDialog", "Maximum acceptable total difficulty:", None)) + #my new implementation starts here,it wasn't line here + self.tabWidgetSettings.setTabText(self.tabWidgetSettings.indexOf(self.tabResendingMessagesAdjustment), _translate("settingsDialog", "Adjusting time period for resending messages", None)) + self.label_19.setText(_translate("settingsDialog", "

If you send a message to someone and he is offline for more than two days, Bitmessage will send the message again after an additional two days. This will be continued with exponential backoff forever. Messages will continue to be sent after 4, 8,16 days and so on until the receiver get them.

Here you can adjust Bitmessage to stop trying to send messages after X hours/days/months. This time period needs to be longer than 5 days.

", None)) + self.label_20.setText(_translate("settingsDialog", "Time in hours/days/months:", None)) + self.label_22.setText(_translate("settingsDialog", "/", None)) + self.label_23.setText(_translate("settingsDialog", "/", None)) + #my new implementation stops here, it wasn't line here self.label_14.setText(_translate("settingsDialog", "Maximum acceptable small message difficulty:", None)) self.tabWidgetSettings.setTabText(self.tabWidgetSettings.indexOf(self.tab_2), _translate("settingsDialog", "Max acceptable difficulty", None)) self.label_16.setText(_translate("settingsDialog", "

Bitmessage can utilize a different Bitcoin-based program called Namecoin to make addresses human-friendly. For example, instead of having to tell your friend your long Bitmessage address, you can simply tell him to send a message to test.

(Getting your own Bitmessage address into Namecoin is still rather difficult).

Bitmessage can use either namecoind directly or a running nmcontrol instance.

", None)) @@ -395,4 +444,3 @@ class Ui_settingsDialog(object): self.radioButtonNamecoinNmcontrol.setText(_translate("settingsDialog", "NMControl", None)) self.tabWidgetSettings.setTabText(self.tabWidgetSettings.indexOf(self.tabNamecoin), _translate("settingsDialog", "Namecoin integration", None)) -#just test \ No newline at end of file diff --git a/src/bitmessageqt/settings.ui b/src/bitmessageqt/settings.ui index 23755b91..9973a1b4 100644 --- a/src/bitmessageqt/settings.ui +++ b/src/bitmessageqt/settings.ui @@ -756,6 +756,74 @@ + + + + Adjusting time period for resending messages + + + + + + If you send a message to someone and he is offline for more than two days, Bitmessage will send the message again after an additional two days. This will be continued with exponential backoff forever. Μessages will continue to be sent after 4, 8,16 days etc. until the receiver get them. Here you can adjust Bitmessage to stop trying to send messages after X hours/days/months. This time period needs to be longer than 5 days./p></body></html> + + + true + + + + + + + Qt::LeftToRight + + + Time in hours/days/months: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 33 + 16777215 + + + + + + + + / + + + + + + + + + / + + + + + + + + 33 + 16777215 + + + + + + + tabWidgetSettings checkBoxStartOnLogon @@ -792,7 +860,7 @@ buttonBox - rejected() + rejected) settingsDialog reject() From ae01c186f42b9942b2df5047581958a47c82f1ed Mon Sep 17 00:00:00 2001 From: ikarakatsanis Date: Fri, 27 Sep 2013 02:24:48 +0400 Subject: [PATCH 04/18] minor change UI --- src/bitmessageqt/settings.ui | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/bitmessageqt/settings.ui b/src/bitmessageqt/settings.ui index 9973a1b4..94610c03 100644 --- a/src/bitmessageqt/settings.ui +++ b/src/bitmessageqt/settings.ui @@ -756,7 +756,6 @@ - Adjusting time period for resending messages @@ -860,7 +859,7 @@ buttonBox - rejected) + rejected() settingsDialog reject() From 4e4827b22d6ef990fdf2e25eea19e08cc0c0cf14 Mon Sep 17 00:00:00 2001 From: "Grant T. Olson" Date: Fri, 27 Sep 2013 10:28:01 -0400 Subject: [PATCH 05/18] Force the right version of osx in the build script --- osx.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osx.sh b/osx.sh index 2f59f446..834a6243 100755 --- a/osx.sh +++ b/osx.sh @@ -14,7 +14,7 @@ fi echo "Creating OS X packages for Bitmessage." -cd src && python build_osx.py py2app +cd src && python2.7 build_osx.py py2app if [[ $? = "0" ]]; then hdiutil create -fs HFS+ -volname "Bitmessage" -srcfolder dist/Bitmessage.app dist/bitmessage-v$1.dmg From 497c29702038180175a42a27ae8c97bf7fd87efe Mon Sep 17 00:00:00 2001 From: "Grant T. Olson" Date: Fri, 27 Sep 2013 10:28:40 -0400 Subject: [PATCH 06/18] Include translation resources --- src/build_osx.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/build_osx.py b/src/build_osx.py index f9ab2c03..097551b7 100644 --- a/src/build_osx.py +++ b/src/build_osx.py @@ -11,7 +11,7 @@ setup( setup_requires = ["py2app"], options = dict( py2app = dict( - resources = ["images"], + resources = ["images", "translations"], includes = ['sip', 'PyQt4._qt'], iconfile = "images/bitmessage.icns" ) From e1fc820226ce6a3c2a2581d7f25fecaa33ab8a30 Mon Sep 17 00:00:00 2001 From: ikarakatsanis Date: Sat, 28 Sep 2013 04:47:16 +0400 Subject: [PATCH 07/18] changes in keys.dat, edit hours/days/months is working now, variable time_period inserted --- src/bitmessageqt/__init__.py | 28 +++++++++++++++++++++++++++- src/class_sqlThread.py | 13 +++++++++++++ src/helper_startup.py | 9 ++++++++- 3 files changed, 48 insertions(+), 2 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 8cbea0f9..3f59ba4e 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -2036,6 +2036,23 @@ class MyForm(QtGui.QMainWindow): if float(self.settingsDialogInstance.ui.lineEditMaxAcceptableSmallMessageDifficulty.text()) >= 1 or float(self.settingsDialogInstance.ui.lineEditMaxAcceptableSmallMessageDifficulty.text()) == 0: shared.config.set('bitmessagesettings', 'maxacceptablepayloadlengthextrabytes', str(int(float( self.settingsDialogInstance.ui.lineEditMaxAcceptableSmallMessageDifficulty.text()) * shared.networkDefaultPayloadLengthExtraBytes))) + #my implementation starts here,it was a line here + time_period = (int(str(self.settingsDialogInstance.ui.lineEditHours.text())) * 60 * 60 + int(str(self.settingsDialogInstance.ui.lineEditDays.text())) * 24 * 60 * 60 + + int(str(self.settingsDialogInstance.ui.lineEditMonths.text())) * (60 * 60 * 24 *365)/12) + if time_period < shared.maximumAgeOfAnObjectThatIAmWillingToAccept * 2: + QMessageBox.about(self, _translate("MainWindow", "Error"), _translate( + "MainWindow", "You must insert a time period longer than 5 days.")) + shared.config.set('bitmessagesettings', 'hours', '0') + shared.config.set('bitmessagesettings', 'days', '5') + shared.config.set('bitmessagesettings', 'months', '0') + else: + shared.config.set('bitmessagesettings', 'hours', str( + self.settingsDialogInstance.ui.lineEditHours.text())) + shared.config.set('bitmessagesettings', 'days', str( + self.settingsDialogInstance.ui.lineEditDays.text())) + shared.config.set('bitmessagesettings', 'months', str( + self.settingsDialogInstance.ui.lineEditMonths.text())) + #my implementation stops here, there is a line # if str(self.settingsDialogInstance.ui.comboBoxMaxCores.currentText()) == 'All': # shared.config.set('bitmessagesettings', 'maxcores', '99999') @@ -2964,7 +2981,7 @@ class settingsDialog(QtGui.QDialog): self.ui.lineEditNamecoinPassword.setEnabled(False) self.ui.labelNamecoinPassword.setEnabled(False) else: - assert False + assert False QtCore.QObject.connect(self.ui.radioButtonNamecoinNamecoind, QtCore.SIGNAL( "toggled(bool)"), self.namecoinTypeChanged) @@ -2973,6 +2990,15 @@ class settingsDialog(QtGui.QDialog): QtCore.QObject.connect(self.ui.pushButtonNamecoinTest, QtCore.SIGNAL( "clicked()"), self.click_pushButtonNamecoinTest) + #Adjust tab + self.ui.lineEditHours.setText(str( + shared.config.get('bitmessagesettings', 'hours'))) + self.ui.lineEditDays.setText(str( + shared.config.get('bitmessagesettings', 'days'))) + self.ui.lineEditMonths.setText(str( + shared.config.get('bitmessagesettings', 'months'))) + + #'System' tab removed for now. """try: maxCores = shared.config.getint('bitmessagesettings', 'maxcores') diff --git a/src/class_sqlThread.py b/src/class_sqlThread.py index 829b243d..ba016eba 100644 --- a/src/class_sqlThread.py +++ b/src/class_sqlThread.py @@ -256,6 +256,19 @@ class sqlThread(threading.Thread): # Are you hoping to add a new option to the keys.dat file of existing # Bitmessage users? Add it right above this line! + #my new implementation starts here + if shared.config.getint('bitmessagesettings', 'settingsversion') == 6: + shared.config.set( + 'bitmessagesettings', 'hours', '0') + shared.config.set( + 'bitmessagesettings', 'days', '5') + shared.config.set( + 'bitmessagesettings', 'months', '0') + shared.config.set('bitmessagesettings', 'settingsversion', '7') + with open(shared.appdata + 'keys.dat', 'wb') as configfile: + shared.config.write(configfile) + #my new implementation stops here + try: testpayload = '\x00\x00' t = ('1234', testpayload, '12345678', 'no') diff --git a/src/helper_startup.py b/src/helper_startup.py index 5a5d7b81..35251f70 100644 --- a/src/helper_startup.py +++ b/src/helper_startup.py @@ -84,12 +84,19 @@ def loadConfig(): 'bitmessagesettings', 'maxacceptablepayloadlengthextrabytes', '0') shared.config.set('bitmessagesettings', 'dontconnect', 'true') shared.config.set('bitmessagesettings', 'userlocale', 'system') - + # Are you hoping to add a new option to the keys.dat file? You're in # the right place for adding it to users who install the software for # the first time. But you must also add it to the keys.dat file of # existing users. To do that, search the class_sqlThread.py file for the # text: "right above this line!" + + shared.config.set( + 'bitmessagesettings', 'hours', '0') + shared.config.set( + 'bitmessagesettings', 'days', '5') + shared.config.set( + 'bitmessagesettings', 'months', '0') ensureNamecoinOptions() From b37e0ec027e78aeed9c50e9d898edaba4ef083d3 Mon Sep 17 00:00:00 2001 From: fuzzgun Date: Sat, 28 Sep 2013 13:09:15 +0100 Subject: [PATCH 08/18] Changelog update for 0.4.0 --- arch.sh | 17 +++++++++-- archpackage/PKGBUILD | 4 +-- debian/changelog | 55 ++++++++++++++++++++++++++++++++++++ debian/control | 2 +- debian/rules | 1 + generate.sh | 15 ++-------- rpmpackage/pybitmessage.spec | 52 ++++++++++++++++++++++++++++++++++ src/bitmessagemain.py | 34 +++++++++++----------- 8 files changed, 145 insertions(+), 35 deletions(-) diff --git a/arch.sh b/arch.sh index 42daefdc..43778da7 100755 --- a/arch.sh +++ b/arch.sh @@ -1,6 +1,5 @@ #!/bin/bash -GIT_APP=PyBitmessage APP=pybitmessage PREV_VERSION=0.4.0 VERSION=0.4.0 @@ -26,12 +25,24 @@ make clean rm -f archpackage/*.gz # having the root directory called name-version seems essential -mv ../${GIT_APP} ../${APP}-${VERSION} +mv ../${APP} ../${APP}-${VERSION} tar -cvzf ${SOURCE} ../${APP}-${VERSION} --exclude-vcs # rename the root directory without the version number -mv ../${APP}-${VERSION} ../${GIT_APP} +mv ../${APP}-${VERSION} ../${APP} # calculate the MD5 checksum CHECKSM=$(md5sum ${SOURCE}) sed -i "s/md5sums[^)]*)/md5sums=(${CHECKSM%% *})/g" archpackage/PKGBUILD + +cd archpackage + +# Create the package +tar -c -f ${APP}-${VERSION}.pkg.tar . +sync +xz ${APP}-${VERSION}.pkg.tar +sync + +# Move back to the original directory +cd ${CURRDIR} + diff --git a/archpackage/PKGBUILD b/archpackage/PKGBUILD index 455180c3..25cc94fa 100644 --- a/archpackage/PKGBUILD +++ b/archpackage/PKGBUILD @@ -7,7 +7,7 @@ arch=('any') url="https://github.com/Bitmessage/PyBitmessage" license=('MIT') groups=() -depends=('python2' 'qt4' 'python2-pyqt4' 'sqlite' 'openssl' 'mpg123') +depends=('python2' 'qt4' 'python2-pyqt4' 'sqlite' 'openssl' 'gst123') makedepends=() optdepends=('python2-gevent: Python network library that uses greenlet and libevent for easy and scalable concurrency') provides=() @@ -19,7 +19,7 @@ install= changelog= source=($pkgname-$pkgver.tar.gz) noextract=() -md5sums=(ebf89129571571198473559b4b2e552c) +md5sums=() build() { cd "$srcdir/$pkgname-$pkgver" ./configure --prefix=/usr diff --git a/debian/changelog b/debian/changelog index 8cdaff2c..a8f35473 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,58 @@ +pybitmessage (0.4.0-1) raring; urgency=low + + * Raised default demanded difficulty from 1 to 2 for new addresses + * Added v4 addresses: + pubkeys are now encrypted and tagged in the inventory + * Use locks when accessing dictionary inventory + * Refactored the way inv and addr messages are shared + * Give user feedback when disk is full + * Added chan true/false to listAddresses results + * When replying using chan address, send to whole chan not just sender + * Refactored of the way PyBitmessage looks for interesting new objects + in large inv messages from peers + * Show inventory lookup rate on Network Status tab + * Added SqlBulkExecute class + so we can update inventory with only one commit + * Updated Russian translations + * Move duplicated SQL code into helper + * Allow specification of alternate settings dir + via BITMESSAGE_HOME environment variable + * Removed use of gevent. Removed class_bgWorker.py + * Added Sip and PyQt to includes in build_osx.py + * Show number of each message type processed + in the API command clientStatus + * Use fast PoW + unless we're explicitly a frozen (binary) version of the code + * Enable user-set localization in settings + * Fix Archlinux package creation + * Fallback to language only localization when region doesn't match + * Fixed brew install instructions + * Added German translation + * Made inbox and sent messages table panels read-only + * Allow inbox and sent preview panels to resize + * Count RE: as a reply header, just like Re: so we don't chain Re: RE: + * Fix for traceback on OSX + * Added backend ability to understand shorter addresses + * Convert 'API Error' to raise APIError() + * Added option in settings to allow sending to a mobile device + (app not yet done) + * Added ability to start daemon mode when using Bitmessage as a module + * Improved the way client detects locale + * Added API commands: + getInboxMessageIds, getSentMessageIds, listAddressBookEntries, + trashSentMessageByAckData, addAddressBookEntry, + deleteAddressBookEntry, listAddresses2, listSubscriptions + * Set a maximum frequency for playing sounds + * Show Invalid Method error in same format as other API errors + * Update status of separate broadcasts separately + even if the sent data is identical + * Added Namecoin integration + * Internally distinguish peers by IP and port + * Inbox message retrieval API + functions now also returns read status + + -- Bob Mottram (4096 bits) Sat, 28 September 2013 09:54:00 +0100 + pybitmessage (0.3.5-1) raring; urgency=low * Inbox message retrieval API functions now also returns read status diff --git a/debian/control b/debian/control index 6fb419f4..8f5c75d8 100644 --- a/debian/control +++ b/debian/control @@ -9,7 +9,7 @@ Vcs-Git: https://github.com/Bitmessage/PyBitmessage.git Package: pybitmessage Architecture: all -Depends: ${shlibs:Depends}, ${misc:Depends}, python (>= 2.7.0), openssl, python-qt4, libqt4-dev (>= 4.8.0), python-qt4-dev, sqlite3, libsqlite3-dev, gst123 +Depends: ${shlibs:Depends}, ${misc:Depends}, ${python:Depends}, python (>= 2.7), openssl, python-qt4, libqt4-dev (>= 4.8.0), python-qt4-dev, sqlite3, libsqlite3-dev, gst123 Suggests: libmessaging-menu-dev Description: Send encrypted messages Bitmessage is a P2P communications protocol used to send encrypted diff --git a/debian/rules b/debian/rules index 5b29d243..fc50f30f 100755 --- a/debian/rules +++ b/debian/rules @@ -37,6 +37,7 @@ binary-indep: build install dh_md5sums dh_builddeb + dh_python2 binary-arch: build install binary: binary-indep binary-arch diff --git a/generate.sh b/generate.sh index 376c1926..d967d279 100755 --- a/generate.sh +++ b/generate.sh @@ -7,24 +7,15 @@ rm -f Makefile rpmpackage/*.spec packagemonkey -n "PyBitmessage" --version "0.4.0" --dir "." -l "mit" \ -e "Bob Mottram (4096 bits) " \ --brief "Send encrypted messages" \ - --desc "Bitmessage is a P2P communications protocol used to send " \ - "encrypted messages to another person or to many subscribers. It is " \ - "decentralized and trustless, meaning that you need-not inherently" \ - "trust any entities like root certificate authorities. It uses strong " \ - "authentication which means that the sender of a message cannot be" \ - "spoofed, and it aims to hide \"non-content\" data, like the sender and " \ - "receiver of messages, from passive eavesdroppers like those running " \ - "warrantless wiretapping programs." \ + --desc "Bitmessage is a P2P communications protocol used to send encrypted messages to another person or to many subscribers. It is decentralized and trustless, meaning that you need-not inherently trust any entities like root certificate authorities. It uses strong authentication which means that the sender of a message cannot be spoofed, and it aims to hide \"non-content\" data, like the sender and receiver of messages, from passive eavesdroppers like those running warrantless wiretapping programs." \ --homepage "https://github.com/Bitmessage/PyBitmessage" --section "mail" \ --categories "Office/Email" \ - --dependsdeb "python (>= 2.7.0), openssl, python-qt4, libqt4-dev " \ - "(>= 4.8.0), python-qt4-dev, sqlite3, libsqlite3-dev, gst123" \ + --dependsdeb "python (>= 2.7), openssl, python-qt4, libqt4-dev (>= 4.8.0), python-qt4-dev, sqlite3, libsqlite3-dev, gst123" \ --dependsrpm "python, PyQt4, openssl-compat-bitcoin-libs, gst123" \ --mainscript "bitmessagemain.py" \ --librarypath "/opt/openssl-compat-bitcoin/lib/" \ --suggestsdeb "libmessaging-menu-dev" \ - --dependspuppy "openssl, python-qt4, sqlite3, sqlite3-dev, " \ - "python-openssl, python-sip, gst123" \ + --dependspuppy "openssl, python-qt4, sqlite3, sqlite3-dev, python-openssl, python-sip, gst123" \ --dependsarch "python2, qt4, python2-pyqt4, sqlite, openssl, gst123" \ --suggestsarch "python2-gevent: Python network library that uses greenlet and libevent for easy and scalable concurrency" --pythonversion 2 \ --dependsebuild "dev-libs/openssl, dev-python/PyQt4[${PYTHON_USEDEP}]" \ diff --git a/rpmpackage/pybitmessage.spec b/rpmpackage/pybitmessage.spec index 00012be9..41875c9a 100644 --- a/rpmpackage/pybitmessage.spec +++ b/rpmpackage/pybitmessage.spec @@ -69,6 +69,58 @@ make install -B DESTDIR=%{buildroot} PREFIX=/usr %attr(644,root,root) /usr/share/icons/hicolor/24x24/apps/%{name}.png %changelog +* Sat Sep 28 2013 Bob Mottram (4096 bits) - 0.4.0-1 +- Raised default demanded difficulty from 1 to 2 for new addresses +- Added v4 addresses: + pubkeys are now encrypted and tagged in the inventory +- Use locks when accessing dictionary inventory +- Refactored the way inv and addr messages are shared +- Give user feedback when disk is full +- Added chan true/false to listAddresses results +- When replying using chan address, send to whole chan not just sender +- Refactored of the way PyBitmessage looks for interesting new objects + in large inv messages from peers +- Show inventory lookup rate on Network Status tab +- Added SqlBulkExecute class + so we can update inventory with only one commit +- Updated Russian translations +- Move duplicated SQL code into helper +- Allow specification of alternate settings dir + via BITMESSAGE_HOME environment variable +- Removed use of gevent. Removed class_bgWorker.py +- Added Sip and PyQt to includes in build_osx.py +- Show number of each message type processed + in the API command clientStatus +- Use fast PoW + unless we're explicitly a frozen (binary) version of the code +- Enable user-set localization in settings +- Fix Archlinux package creation +- Fallback to language only localization when region doesn't match +- Fixed brew install instructions +- Added German translation +- Made inbox and sent messages table panels read-only +- Allow inbox and sent preview panels to resize +- Count RE: as a reply header, just like Re: so we don't chain Re: RE: +- Fix for traceback on OSX +- Added backend ability to understand shorter addresses +- Convert 'API Error' to raise APIError() +- Added option in settings to allow sending to a mobile device + (app not yet done) +- Added ability to start daemon mode when using Bitmessage as a module +- Improved the way client detects locale +- Added API commands: + getInboxMessageIds, getSentMessageIds, listAddressBookEntries, + trashSentMessageByAckData, addAddressBookEntry, + deleteAddressBookEntry, listAddresses2, listSubscriptions +- Set a maximum frequency for playing sounds +- Show Invalid Method error in same format as other API errors +- Update status of separate broadcasts separately + even if the sent data is identical +- Added Namecoin integration +- Internally distinguish peers by IP and port +- Inbox message retrieval API + functions now also returns read status + * Mon Jul 29 2013 Bob Mottram (4096 bits) - 0.3.5-1 - Inbox message retrieval API functions now also returns read status - Added right-click option to mark a message as unread diff --git a/src/bitmessagemain.py b/src/bitmessagemain.py index 47925a46..90e02cc1 100755 --- a/src/bitmessagemain.py +++ b/src/bitmessagemain.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2.7 +#!/usr/bin/env python # Copyright (c) 2012 Jonathan Warren # Copyright (c) 2012 The Bitmessage developers # Distributed under the MIT/X11 software license. See the accompanying @@ -152,7 +152,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): return text.decode(decode_type) except TypeError as e: raise APIError(22, "Decode error - " + str(e)) - + def _verifyAddress(self, address): status, addressVersionNumber, streamNumber, ripe = decodeAddress(address) if status != 'success': @@ -519,7 +519,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): if len(params) == 0: raise APIError(0, 'I need parameters!') msgid = self._decode(params[0], "hex") - + # Trash if in inbox table helper_inbox.trash(msgid) # Trash if in sent table @@ -740,7 +740,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): trialValue, nonce = proofofwork.run(target, initialHash) print '(For pubkey message via API) Found proof of work', trialValue, 'Nonce:', nonce payload = pack('>Q', nonce) + payload - + pubkeyReadPosition = 8 # bypass the nonce if payload[pubkeyReadPosition:pubkeyReadPosition+4] == '\x00\x00\x00\x00': # if this pubkey uses 8 byte time pubkeyReadPosition += 8 @@ -760,20 +760,20 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): shared.broadcastToSendDataQueues(( streamNumber, 'advertiseobject', inventoryHash)) elif method == 'getMessageDataByDestinationHash' or method == 'getMessageDataByDestinationTag': - # Method will eventually be used by a particular Android app to + # Method will eventually be used by a particular Android app to # select relevant messages. Do not yet add this to the api # doc. - + if len(params) != 1: raise APIError(0, 'I need 1 parameter!') requestedHash, = params if len(requestedHash) != 32: raise APIError(19, 'The length of hash should be 32 bytes (encoded in hex thus 64 characters).') requestedHash = self._decode(requestedHash, "hex") - - # This is not a particularly commonly used API function. Before we - # use it we'll need to fill out a field in our inventory database - # which is blank by default (first20bytesofencryptedmessage). + + # This is not a particularly commonly used API function. Before we + # use it we'll need to fill out a field in our inventory database + # which is blank by default (first20bytesofencryptedmessage). queryreturn = sqlQuery( '''SELECT hash, payload FROM inventory WHERE tag = '' and objecttype = 'msg' ; ''') with SqlBulkExecute() as sql: @@ -783,7 +783,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): readPosition += decodeVarint(payload[readPosition:readPosition+10])[1] # Stream Number length t = (payload[readPosition:readPosition+32],hash) sql.execute('''UPDATE inventory SET tag=? WHERE hash=?; ''', *t) - + queryreturn = sqlQuery('''SELECT payload FROM inventory WHERE tag = ?''', requestedHash) data = '{"receivedMessageDatas":[' @@ -795,7 +795,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): data += ']}' return data elif method == 'getPubkeyByHash': - # Method will eventually be used by a particular Android app to + # 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!') @@ -937,25 +937,25 @@ class Main: print 'Running as a daemon. You can use Ctrl+C to exit.' while True: time.sleep(20) - + def stop(self): with shared.printLock: print 'Stopping Bitmessage Deamon.' shared.doCleanShutdown() - - + + def getApiAddress(self): if not shared.safeConfigGetBoolean('bitmessagesettings', 'apienabled'): return None address = shared.config.get('bitmessagesettings', 'apiinterface') port = shared.config.getint('bitmessagesettings', 'apiport') return {'address':address,'port':port} - + if __name__ == "__main__": mainprogram = Main() mainprogram.start() - + # So far, the creation of and management of the Bitmessage protocol and this # client is a one-man operation. Bitcoin tips are quite appreciated. # 1H5XaDA6fYENLbknwZyjiYXYPQaFjjLX2u From ed3685921d281036033a87e787613d06a37c5f5a Mon Sep 17 00:00:00 2001 From: fuzzgun Date: Sat, 28 Sep 2013 13:20:30 +0100 Subject: [PATCH 09/18] Update arch package --- archpackage/PKGBUILD | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/archpackage/PKGBUILD b/archpackage/PKGBUILD index 25cc94fa..c36b318e 100644 --- a/archpackage/PKGBUILD +++ b/archpackage/PKGBUILD @@ -19,7 +19,7 @@ install= changelog= source=($pkgname-$pkgver.tar.gz) noextract=() -md5sums=() +md5sums=(91979c84abb805c12a0c1ee33b257396) build() { cd "$srcdir/$pkgname-$pkgver" ./configure --prefix=/usr From b40f68023b12063bd7ebd200ac0deb4286470e65 Mon Sep 17 00:00:00 2001 From: fuzzgun Date: Sat, 28 Sep 2013 15:26:10 +0100 Subject: [PATCH 10/18] Changes for the OpenSUSE build service --- archpackage/PKGBUILD | 4 ++-- debian/rules | 1 - generate.sh | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/archpackage/PKGBUILD b/archpackage/PKGBUILD index c36b318e..84c4a40b 100644 --- a/archpackage/PKGBUILD +++ b/archpackage/PKGBUILD @@ -7,7 +7,7 @@ arch=('any') url="https://github.com/Bitmessage/PyBitmessage" license=('MIT') groups=() -depends=('python2' 'qt4' 'python2-pyqt4' 'sqlite' 'openssl' 'gst123') +depends=('python2' 'qt4' 'python2-pyqt4' 'sqlite' 'openssl' 'mpg123') makedepends=() optdepends=('python2-gevent: Python network library that uses greenlet and libevent for easy and scalable concurrency') provides=() @@ -19,7 +19,7 @@ install= changelog= source=($pkgname-$pkgver.tar.gz) noextract=() -md5sums=(91979c84abb805c12a0c1ee33b257396) +md5sums=(0ee9bcb11dc606788fde94c7857e8720) build() { cd "$srcdir/$pkgname-$pkgver" ./configure --prefix=/usr diff --git a/debian/rules b/debian/rules index fc50f30f..5b29d243 100755 --- a/debian/rules +++ b/debian/rules @@ -37,7 +37,6 @@ binary-indep: build install dh_md5sums dh_builddeb - dh_python2 binary-arch: build install binary: binary-indep binary-arch diff --git a/generate.sh b/generate.sh index d967d279..943d8a12 100755 --- a/generate.sh +++ b/generate.sh @@ -16,7 +16,7 @@ packagemonkey -n "PyBitmessage" --version "0.4.0" --dir "." -l "mit" \ --librarypath "/opt/openssl-compat-bitcoin/lib/" \ --suggestsdeb "libmessaging-menu-dev" \ --dependspuppy "openssl, python-qt4, sqlite3, sqlite3-dev, python-openssl, python-sip, gst123" \ - --dependsarch "python2, qt4, python2-pyqt4, sqlite, openssl, gst123" \ + --dependsarch "python2, qt4, python2-pyqt4, sqlite, openssl, mpg123" \ --suggestsarch "python2-gevent: Python network library that uses greenlet and libevent for easy and scalable concurrency" --pythonversion 2 \ --dependsebuild "dev-libs/openssl, dev-python/PyQt4[${PYTHON_USEDEP}]" \ --buildebuild "\${PYTHON_DEPS}" --pythonreq "sqlite" \ From 498928405bc673f2066682af36a28c7a22dff3ba Mon Sep 17 00:00:00 2001 From: Jonathan Warren Date: Sun, 29 Sep 2013 19:24:27 -0400 Subject: [PATCH 11/18] Chan fix: initial work completed --- src/bitmessageqt/__init__.py | 9 - src/class_receiveDataThread.py | 38 +-- src/class_singleWorker.py | 406 +++++++++++++++++---------------- src/class_sqlThread.py | 24 +- src/shared.py | 4 +- 5 files changed, 249 insertions(+), 232 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 8cbea0f9..2bd2bb6b 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -1564,15 +1564,6 @@ class MyForm(QtGui.QMainWindow): "MainWindow", "Error: You must specify a From address. If you don\'t have one, go to the \'Your Identities\' tab.")) else: toAddress = addBMIfNotPresent(toAddress) - try: - shared.config.get(toAddress, 'enabled') - # The toAddress is one owned by me. - if not shared.safeConfigGetBoolean(toAddress, 'chan'): - QMessageBox.about(self, _translate("MainWindow", "Sending to your address"), _translate( - "MainWindow", "Error: One of the addresses to which you are sending a message, %1, is yours. Unfortunately the Bitmessage client cannot process its own messages. Please try running a second client on a different computer or within a VM.").arg(toAddress)) - continue - except: - pass if addressVersionNumber > 4 or addressVersionNumber <= 1: QMessageBox.about(self, _translate("MainWindow", "Address version number"), _translate( "MainWindow", "Concerning the address %1, Bitmessage cannot understand address version numbers of %2. Perhaps upgrade Bitmessage to the latest version.").arg(toAddress).arg(str(addressVersionNumber))) diff --git a/src/class_receiveDataThread.py b/src/class_receiveDataThread.py index f9fe403e..97edfb21 100644 --- a/src/class_receiveDataThread.py +++ b/src/class_receiveDataThread.py @@ -1,4 +1,4 @@ -doTimingAttackMitigation = True +doTimingAttackMitigation = False import time import threading @@ -514,8 +514,9 @@ class receiveDataThread(threading.Thread): # the proof of work ourselves, which this program is programmed # to not do.) sqlExecute( - '''INSERT INTO pubkeys VALUES (?,?,?,?)''', + '''INSERT INTO pubkeys VALUES (?,?,?,?,?)''', ripe.digest(), + sendersAddressVersion, '\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF' + '\xFF\xFF\xFF\xFF' + data[beginningOfPubkeyPosition:endOfPubkeyPosition], int(time.time()), 'yes') @@ -655,8 +656,9 @@ class receiveDataThread(threading.Thread): # Let's store the public key in case we want to reply to this # person. - sqlExecute('''INSERT INTO pubkeys VALUES (?,?,?,?)''', + sqlExecute('''INSERT INTO pubkeys VALUES (?,?,?,?,?)''', ripe.digest(), + sendersAddressVersion, '\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF' + '\xFF\xFF\xFF\xFF' + decryptedData[beginningOfPubkeyPosition:endOfPubkeyPosition], int(time.time()), 'yes') @@ -806,8 +808,9 @@ class receiveDataThread(threading.Thread): # Let's store the public key in case we want to reply to this person. sqlExecute( - '''INSERT INTO pubkeys VALUES (?,?,?,?)''', + '''INSERT INTO pubkeys VALUES (?,?,?,?,?)''', calculatedRipe, + sendersAddressVersion, '\x00\x00\x00\x00\x00\x00\x00\x01' + decryptedData[beginningOfPubkeyPosition:endOfPubkeyPosition], int(time.time()), 'yes') @@ -1070,8 +1073,9 @@ class receiveDataThread(threading.Thread): # person. if sendersAddressVersionNumber <= 3: sqlExecute( - '''INSERT INTO pubkeys VALUES (?,?,?,?)''', + '''INSERT INTO pubkeys VALUES (?,?,?,?,?)''', ripe.digest(), + sendersAddressVersionNumber, '\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF' + '\xFF\xFF\xFF\xFF' + decryptedData[messageVersionLength:endOfThePublicKeyPosition], int(time.time()), 'yes') @@ -1081,8 +1085,9 @@ class receiveDataThread(threading.Thread): self.possibleNewPubkey(ripe=ripe.digest()) elif sendersAddressVersionNumber >= 4: sqlExecute( - '''INSERT INTO pubkeys VALUES (?,?,?,?)''', + '''INSERT INTO pubkeys VALUES (?,?,?,?,?)''', ripe.digest(), + sendersAddressVersionNumber, '\x00\x00\x00\x00\x00\x00\x00\x01' + decryptedData[messageVersionLength:endOfThePublicKeyPosition], int(time.time()), 'yes') @@ -1409,15 +1414,15 @@ class receiveDataThread(threading.Thread): queryreturn = sqlQuery( - '''SELECT usedpersonally FROM pubkeys WHERE hash=? AND usedpersonally='yes' ''', ripe) + '''SELECT usedpersonally FROM pubkeys WHERE hash=? AND addressversion=? AND usedpersonally='yes' ''', ripe, addressVersion) if queryreturn != []: # if this pubkey is already in our database and if we have used it personally: print 'We HAVE used this pubkey personally. Updating time.' - t = (ripe, data, embeddedTime, 'yes') + t = (ripe, addressVersion, data, embeddedTime, 'yes') else: print 'We have NOT used this pubkey personally. Inserting in database.' - t = (ripe, data, embeddedTime, 'no') + t = (ripe, addressVersion, data, embeddedTime, 'no') # This will also update the embeddedTime. - sqlExecute('''INSERT INTO pubkeys VALUES (?,?,?,?)''', *t) + sqlExecute('''INSERT INTO pubkeys VALUES (?,?,?,?,?)''', *t) # shared.workerQueue.put(('newpubkey',(addressVersion,streamNumber,ripe))) self.possibleNewPubkey(ripe = ripe) if addressVersion == 3: @@ -1466,19 +1471,18 @@ class receiveDataThread(threading.Thread): print 'publicEncryptionKey in hex:', publicEncryptionKey.encode('hex') - queryreturn = sqlQuery('''SELECT usedpersonally FROM pubkeys WHERE hash=? AND usedpersonally='yes' ''', ripe) + queryreturn = sqlQuery('''SELECT usedpersonally FROM pubkeys WHERE hash=? AND addressversion=? AND usedpersonally='yes' ''', ripe, addressVersion) if queryreturn != []: # if this pubkey is already in our database and if we have used it personally: print 'We HAVE used this pubkey personally. Updating time.' - t = (ripe, data, embeddedTime, 'yes') + t = (ripe, addressVersion, data, embeddedTime, 'yes') else: print 'We have NOT used this pubkey personally. Inserting in database.' - t = (ripe, data, embeddedTime, 'no') + t = (ripe, addressVersion, data, embeddedTime, 'no') # This will also update the embeddedTime. - sqlExecute('''INSERT INTO pubkeys VALUES (?,?,?,?)''', *t) + sqlExecute('''INSERT INTO pubkeys VALUES (?,?,?,?,?)''', *t) self.possibleNewPubkey(ripe = ripe) if addressVersion == 4: - print 'length of v4 pubkey:', len(data) if len(data) < 350: # sanity check. print '(within processpubkey) payloadLength less than 350. Sanity check failed.' return @@ -1554,8 +1558,8 @@ class receiveDataThread(threading.Thread): print 'publicSigningKey in hex:', publicSigningKey.encode('hex') print 'publicEncryptionKey in hex:', publicEncryptionKey.encode('hex') - t = (ripe, signedData, embeddedTime, 'yes') - sqlExecute('''INSERT INTO pubkeys VALUES (?,?,?,?)''', *t) + t = (ripe, addressVersion, signedData, embeddedTime, 'yes') + sqlExecute('''INSERT INTO pubkeys VALUES (?,?,?,?,?)''', *t) fromAddress = encodeAddress(addressVersion, streamNumber, ripe) # That this point we know that we have been waiting on this pubkey. diff --git a/src/class_singleWorker.py b/src/class_singleWorker.py index 8a66c125..a74c2892 100644 --- a/src/class_singleWorker.py +++ b/src/class_singleWorker.py @@ -156,6 +156,10 @@ class singleWorker(threading.Thread): # send messages to "ourselves". def sendOutOrStoreMyV3Pubkey(self, hash): myAddress = shared.myAddressesByHash[hash] + if shared.safeConfigGetBoolean(myAddress, 'chan'): + with shared.printLock: + print 'This is a chan address. Not sending pubkey.' + return status, addressVersionNumber, streamNumber, hash = decodeAddress( myAddress) embeddedTime = int(time.time() + random.randrange( @@ -197,49 +201,39 @@ class singleWorker(threading.Thread): payload += encodeVarint(len(signature)) payload += signature - if not shared.safeConfigGetBoolean(myAddress, 'chan'): - # Do the POW for this pubkey message - target = 2 ** 64 / ((len(payload) + shared.networkDefaultPayloadLengthExtraBytes + - 8) * shared.networkDefaultProofOfWorkNonceTrialsPerByte) - print '(For pubkey message) Doing proof of work...' - initialHash = hashlib.sha512(payload).digest() - trialValue, nonce = proofofwork.run(target, initialHash) - print '(For pubkey message) Found proof of work', trialValue, 'Nonce:', nonce + # Do the POW for this pubkey message + target = 2 ** 64 / ((len(payload) + shared.networkDefaultPayloadLengthExtraBytes + + 8) * shared.networkDefaultProofOfWorkNonceTrialsPerByte) + print '(For pubkey message) Doing proof of work...' + initialHash = hashlib.sha512(payload).digest() + trialValue, nonce = proofofwork.run(target, initialHash) + print '(For pubkey message) Found proof of work', trialValue, 'Nonce:', nonce - payload = pack('>Q', nonce) + payload - inventoryHash = calculateInventoryHash(payload) - objectType = 'pubkey' - shared.inventory[inventoryHash] = ( - objectType, streamNumber, payload, embeddedTime,'') - shared.inventorySets[streamNumber].add(inventoryHash) + payload = pack('>Q', nonce) + payload + inventoryHash = calculateInventoryHash(payload) + objectType = 'pubkey' + shared.inventory[inventoryHash] = ( + objectType, streamNumber, payload, embeddedTime,'') + shared.inventorySets[streamNumber].add(inventoryHash) - with shared.printLock: - print 'broadcasting inv with hash:', inventoryHash.encode('hex') + with shared.printLock: + print 'broadcasting inv with hash:', inventoryHash.encode('hex') - shared.broadcastToSendDataQueues(( - streamNumber, 'advertiseobject', inventoryHash)) - shared.UISignalQueue.put(('updateStatusBar', '')) - # If this is a chan address then we won't send out the pubkey over the - # network but rather will only store it in our pubkeys table so that - # we can send messages to "ourselves". - if shared.safeConfigGetBoolean(myAddress, 'chan'): - payload = '\x00' * 8 + payload # Attach a fake nonce on the front - # just so that it is in the correct format. - sqlExecute('''INSERT INTO pubkeys VALUES (?,?,?,?)''', - hash, - payload, - embeddedTime, - 'yes') + shared.broadcastToSendDataQueues(( + streamNumber, 'advertiseobject', inventoryHash)) + shared.UISignalQueue.put(('updateStatusBar', '')) shared.config.set( myAddress, 'lastpubkeysendtime', str(int(time.time()))) with open(shared.appdata + 'keys.dat', 'wb') as configfile: shared.config.write(configfile) # If this isn't a chan address, this function assembles the pubkey data, - # does the necessary POW and sends it out. If it *is* a chan then it - # assembles the pubkey and stores is in the pubkey table so that we can - # send messages to "ourselves". + # does the necessary POW and sends it out. def sendOutOrStoreMyV4Pubkey(self, myAddress): + if shared.safeConfigGetBoolean(myAddress, 'chan'): + with shared.printLock: + print 'This is a chan address. Not sending pubkey.' + return status, addressVersionNumber, streamNumber, hash = decodeAddress( myAddress) embeddedTime = int(time.time() + random.randrange( @@ -284,52 +278,41 @@ class singleWorker(threading.Thread): dataToEncrypt += encodeVarint(len(signature)) dataToEncrypt += signature - if not shared.safeConfigGetBoolean(myAddress, 'chan'): - # Let us encrypt the necessary data. We will use a hash of the data - # contained in an address as a decryption key. This way in order to - # read the public keys in a pubkey message, a node must know the address - # first. We'll also tag, unencrypted, the pubkey with part of the hash - # so that nodes know which pubkey object to try to decrypt when they - # want to send a message. - doubleHashOfAddressData = hashlib.sha512(hashlib.sha512(encodeVarint( - addressVersionNumber) + encodeVarint(streamNumber) + hash).digest()).digest() - payload += doubleHashOfAddressData[32:] # the tag - privEncryptionKey = doubleHashOfAddressData[:32] - pubEncryptionKey = pointMult(privEncryptionKey) - payload += highlevelcrypto.encrypt( - dataToEncrypt, pubEncryptionKey.encode('hex')) + # Let us encrypt the necessary data. We will use a hash of the data + # contained in an address as a decryption key. This way in order to + # read the public keys in a pubkey message, a node must know the address + # first. We'll also tag, unencrypted, the pubkey with part of the hash + # so that nodes know which pubkey object to try to decrypt when they + # want to send a message. + doubleHashOfAddressData = hashlib.sha512(hashlib.sha512(encodeVarint( + addressVersionNumber) + encodeVarint(streamNumber) + hash).digest()).digest() + payload += doubleHashOfAddressData[32:] # the tag + privEncryptionKey = doubleHashOfAddressData[:32] + pubEncryptionKey = pointMult(privEncryptionKey) + payload += highlevelcrypto.encrypt( + dataToEncrypt, pubEncryptionKey.encode('hex')) - # Do the POW for this pubkey message - target = 2 ** 64 / ((len(payload) + shared.networkDefaultPayloadLengthExtraBytes + - 8) * shared.networkDefaultProofOfWorkNonceTrialsPerByte) - print '(For pubkey message) Doing proof of work...' - initialHash = hashlib.sha512(payload).digest() - trialValue, nonce = proofofwork.run(target, initialHash) - print '(For pubkey message) Found proof of work', trialValue, 'Nonce:', nonce + # Do the POW for this pubkey message + target = 2 ** 64 / ((len(payload) + shared.networkDefaultPayloadLengthExtraBytes + + 8) * shared.networkDefaultProofOfWorkNonceTrialsPerByte) + print '(For pubkey message) Doing proof of work...' + initialHash = hashlib.sha512(payload).digest() + trialValue, nonce = proofofwork.run(target, initialHash) + print '(For pubkey message) Found proof of work', trialValue, 'Nonce:', nonce - payload = pack('>Q', nonce) + payload - inventoryHash = calculateInventoryHash(payload) - objectType = 'pubkey' - shared.inventory[inventoryHash] = ( - objectType, streamNumber, payload, embeddedTime, doubleHashOfAddressData[32:]) - shared.inventorySets[streamNumber].add(inventoryHash) + payload = pack('>Q', nonce) + payload + inventoryHash = calculateInventoryHash(payload) + objectType = 'pubkey' + shared.inventory[inventoryHash] = ( + objectType, streamNumber, payload, embeddedTime, doubleHashOfAddressData[32:]) + shared.inventorySets[streamNumber].add(inventoryHash) - with shared.printLock: - print 'broadcasting inv with hash:', inventoryHash.encode('hex') + with shared.printLock: + print 'broadcasting inv with hash:', inventoryHash.encode('hex') - shared.broadcastToSendDataQueues(( - streamNumber, 'advertiseobject', inventoryHash)) - shared.UISignalQueue.put(('updateStatusBar', '')) - # If this is a chan address then we won't send out the pubkey over the - # network but rather will only store it in our pubkeys table so that - # we can send messages to "ourselves". - if shared.safeConfigGetBoolean(myAddress, 'chan'): - - sqlExecute('''INSERT INTO pubkeys VALUES (?,?,?,?)''', - hash, - dataToStoreInOurPubkeysTable, - embeddedTime, - 'yes') + shared.broadcastToSendDataQueues(( + streamNumber, 'advertiseobject', inventoryHash)) + shared.UISignalQueue.put(('updateStatusBar', '')) shared.config.set( myAddress, 'lastpubkeysendtime', str(int(time.time()))) with open(shared.appdata + 'keys.dat', 'wb') as configfile: @@ -369,8 +352,6 @@ class singleWorker(threading.Thread): pubEncryptionKey = highlevelcrypto.privToPub( privEncryptionKeyHex).decode('hex') - print 'embedding pubEncryptionKey:', pubEncryptionKey.encode('hex') - payload = pack('>Q', (int(time.time()) + random.randrange( -300, 300))) # the current time plus or minus five minutes if addressVersionNumber <= 3: @@ -382,8 +363,6 @@ class singleWorker(threading.Thread): doubleHashOfAddressData = hashlib.sha512(hashlib.sha512(encodeVarint( addressVersionNumber) + encodeVarint(streamNumber) + ripe).digest()).digest() payload += doubleHashOfAddressData[32:] # the tag - print 'embeddedTag is', doubleHashOfAddressData[32:].encode('hex') - print 'embeddedTag is', repr(doubleHashOfAddressData[32:]) if addressVersionNumber <= 3: dataToEncrypt = encodeVarint(2) # broadcast version @@ -458,8 +437,11 @@ class singleWorker(threading.Thread): for row in queryreturn: # For each address to which we need to send a message, check to see if we have its pubkey already. toaddress, = row status, toAddressVersion, toStreamNumber, toRipe = decodeAddress(toaddress) + # 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. + if shared.config.has_section(toaddress): + continue queryreturn = sqlQuery( - '''SELECT hash FROM pubkeys WHERE hash=? ''', toRipe) + '''SELECT hash FROM pubkeys WHERE hash=? AND addressversion=?''', toRipe, toAddressVersion) if queryreturn != []: # If we have the needed pubkey in the pubkey table already, set the status to doingmsgpow (we'll do it further down) sqlExecute( '''UPDATE sent SET status='doingmsgpow' WHERE toaddress=? AND status='msgqueued' ''', @@ -523,130 +505,154 @@ class singleWorker(threading.Thread): int(time.time()) - 2419200) for row in queryreturn: # For each message we need to send.. toaddress, toripe, fromaddress, subject, message, ackdata, status = row - # There is a remote possibility that we may no longer have the - # recipient's pubkey. Let us make sure we still have it or else the - # sendMsg function will appear to freeze. This can happen if the - # user sends a message but doesn't let the POW function finish, - # then leaves their client off for a long time which could cause - # the needed pubkey to expire and be deleted. - queryreturn = sqlQuery( - '''SELECT hash FROM pubkeys WHERE hash=? ''', - toripe) - if queryreturn == [] and toripe not in shared.neededPubkeys: - # We no longer have the needed pubkey and we haven't requested - # it. - with shared.printLock: - sys.stderr.write( - 'For some reason, the status of a message in our outbox is \'doingmsgpow\' even though we lack the pubkey. Here is the RIPE hash of the needed pubkey: %s\n' % toripe.encode('hex')) - - sqlExecute( - '''UPDATE sent SET status='msgqueued' WHERE toaddress=? AND status='doingmsgpow' ''', toaddress) - shared.UISignalQueue.put(('updateSentItemStatusByHash', ( - toripe, tr.translateText("MainWindow",'Sending a request for the recipient\'s encryption key.')))) - self.requestPubKey(toaddress) - continue - shared.ackdataForWhichImWatching[ackdata] = 0 toStatus, toAddressVersionNumber, toStreamNumber, toHash = decodeAddress( toaddress) fromStatus, fromAddressVersionNumber, fromStreamNumber, fromHash = decodeAddress( fromaddress) - shared.UISignalQueue.put(('updateSentItemStatusByAckdata', ( - ackdata, tr.translateText("MainWindow", "Looking up the receiver\'s public key")))) - with shared.printLock: - print 'Found a message in our database that needs to be sent with this pubkey.' - print 'First 150 characters of message:', repr(message[:150]) - - # mark the pubkey as 'usedpersonally' so that we don't ever delete - # it. - sqlExecute( - '''UPDATE pubkeys SET usedpersonally='yes' WHERE hash=?''', - toripe) - # Let us fetch the recipient's public key out of our database. If - # the required proof of work difficulty is too hard then we'll - # abort. - queryreturn = sqlQuery( - 'SELECT transmitdata FROM pubkeys WHERE hash=?', - toripe) - if queryreturn == []: - with shared.printLock: - sys.stderr.write( - '(within sendMsg) The needed pubkey was not found. This should never happen. Aborting send.\n') - - return - for row in queryreturn: - pubkeyPayload, = row - - # The pubkey message is stored the way we originally received it - # which means that we need to read beyond things like the nonce and - # time to get to the actual public keys. - if toAddressVersionNumber <= 3: - readPosition = 8 # to bypass the nonce - elif toAddressVersionNumber >= 4: - readPosition = 0 # the nonce is not included here so we don't need to skip over it. - pubkeyEmbeddedTime, = unpack( - '>I', pubkeyPayload[readPosition:readPosition + 4]) - # This section is used for the transition from 32 bit time to 64 - # bit time in the protocol. - if pubkeyEmbeddedTime == 0: - pubkeyEmbeddedTime, = unpack( - '>Q', pubkeyPayload[readPosition:readPosition + 8]) - readPosition += 8 - else: - readPosition += 4 - readPosition += 1 # to bypass the address version whose length is definitely 1 - streamNumber, streamNumberLength = decodeVarint( - pubkeyPayload[readPosition:readPosition + 10]) - readPosition += streamNumberLength - behaviorBitfield = pubkeyPayload[readPosition:readPosition + 4] - # Mobile users may ask us to include their address's RIPE hash on a message - # unencrypted. Before we actually do it the sending human must check a box - # in the settings menu to allow it. - if shared.isBitSetWithinBitfield(behaviorBitfield,30): # if receiver is a mobile device who expects that their address RIPE is included unencrypted on the front of the message.. - if not shared.safeConfigGetBoolean('bitmessagesettings','willinglysendtomobile'): # if we are Not willing to include the receiver's RIPE hash on the message.. - logger.info('The receiver is a mobile user but the sender (you) has not selected that you are willing to send to mobiles. Aborting send.') - shared.UISignalQueue.put(('updateSentItemStatusByAckdata',(ackdata,tr.translateText("MainWindow",'Problem: Destination is a mobile device who requests that the destination be included in the message but this is disallowed in your settings. %1').arg(unicode(strftime(shared.config.get('bitmessagesettings', 'timeformat'),localtime(int(time.time()))),'utf-8'))))) - # if the human changes their setting and then sends another message or restarts their client, this one will send at that time. + if not shared.config.has_section(toaddress): + # There is a remote possibility that we may no longer have the + # recipient's pubkey. Let us make sure we still have it or else the + # sendMsg function will appear to freeze. This can happen if the + # user sends a message but doesn't let the POW function finish, + # then leaves their client off for a long time which could cause + # the needed pubkey to expire and be deleted. + queryreturn = sqlQuery( + '''SELECT hash FROM pubkeys WHERE hash=? AND addressversion=?''', + toripe, + toAddressVersionNumber) + if queryreturn == [] and toripe not in shared.neededPubkeys: + # We no longer have the needed pubkey and we haven't requested + # it. + with shared.printLock: + sys.stderr.write( + 'For some reason, the status of a message in our outbox is \'doingmsgpow\' even though we lack the pubkey. Here is the RIPE hash of the needed pubkey: %s\n' % toripe.encode('hex')) + sqlExecute( + '''UPDATE sent SET status='msgqueued' WHERE toaddress=? AND status='doingmsgpow' ''', toaddress) + shared.UISignalQueue.put(('updateSentItemStatusByHash', ( + toripe, tr.translateText("MainWindow",'Sending a request for the recipient\'s encryption key.')))) + self.requestPubKey(toaddress) continue - readPosition += 4 # to bypass the bitfield of behaviors - # pubSigningKeyBase256 = - # pubkeyPayload[readPosition:readPosition+64] #We don't use this - # key for anything here. - readPosition += 64 - pubEncryptionKeyBase256 = pubkeyPayload[ - readPosition:readPosition + 64] - readPosition += 64 - - # Let us fetch the amount of work required by the recipient. - if toAddressVersionNumber == 2: + shared.ackdataForWhichImWatching[ackdata] = 0 + shared.UISignalQueue.put(('updateSentItemStatusByAckdata', ( + ackdata, tr.translateText("MainWindow", "Looking up the receiver\'s public key")))) + with shared.printLock: + print 'Sending a message. First 150 characters of message:', repr(message[:150]) + + + # mark the pubkey as 'usedpersonally' so that we don't ever delete + # it. + sqlExecute( + '''UPDATE pubkeys SET usedpersonally='yes' WHERE hash=? and addressversion=?''', + toripe, + toAddressVersionNumber) + # Let us fetch the recipient's public key out of our database. If + # 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) + if queryreturn == []: + with shared.printLock: + sys.stderr.write( + '(within sendMsg) The needed pubkey was not found. This should never happen. Aborting send.\n') + + return + for row in queryreturn: + pubkeyPayload, = row + + # The pubkey message is stored the way we originally received it + # which means that we need to read beyond things like the nonce and + # time to get to the actual public keys. + if toAddressVersionNumber <= 3: + readPosition = 8 # to bypass the nonce + elif toAddressVersionNumber >= 4: + readPosition = 0 # the nonce is not included here so we don't need to skip over it. + pubkeyEmbeddedTime, = unpack( + '>I', pubkeyPayload[readPosition:readPosition + 4]) + # This section is used for the transition from 32 bit time to 64 + # bit time in the protocol. + if pubkeyEmbeddedTime == 0: + pubkeyEmbeddedTime, = unpack( + '>Q', pubkeyPayload[readPosition:readPosition + 8]) + readPosition += 8 + else: + readPosition += 4 + readPosition += 1 # to bypass the address version whose length is definitely 1 + streamNumber, streamNumberLength = decodeVarint( + pubkeyPayload[readPosition:readPosition + 10]) + readPosition += streamNumberLength + behaviorBitfield = pubkeyPayload[readPosition:readPosition + 4] + # Mobile users may ask us to include their address's RIPE hash on a message + # unencrypted. Before we actually do it the sending human must check a box + # in the settings menu to allow it. + if shared.isBitSetWithinBitfield(behaviorBitfield,30): # if receiver is a mobile device who expects that their address RIPE is included unencrypted on the front of the message.. + if not shared.safeConfigGetBoolean('bitmessagesettings','willinglysendtomobile'): # if we are Not willing to include the receiver's RIPE hash on the message.. + logger.info('The receiver is a mobile user but the sender (you) has not selected that you are willing to send to mobiles. Aborting send.') + shared.UISignalQueue.put(('updateSentItemStatusByAckdata',(ackdata,tr.translateText("MainWindow",'Problem: Destination is a mobile device who requests that the destination be included in the message but this is disallowed in your settings. %1').arg(unicode(strftime(shared.config.get('bitmessagesettings', 'timeformat'),localtime(int(time.time()))),'utf-8'))))) + # if the human changes their setting and then sends another message or restarts their client, this one will send at that time. + continue + readPosition += 4 # to bypass the bitfield of behaviors + # pubSigningKeyBase256 = + # pubkeyPayload[readPosition:readPosition+64] #We don't use this + # key for anything here. + readPosition += 64 + pubEncryptionKeyBase256 = pubkeyPayload[ + readPosition:readPosition + 64] + readPosition += 64 + + # Let us fetch the amount of work required by the recipient. + if toAddressVersionNumber == 2: + requiredAverageProofOfWorkNonceTrialsPerByte = shared.networkDefaultProofOfWorkNonceTrialsPerByte + requiredPayloadLengthExtraBytes = shared.networkDefaultPayloadLengthExtraBytes + shared.UISignalQueue.put(('updateSentItemStatusByAckdata', ( + ackdata, tr.translateText("MainWindow", "Doing work necessary to send message.\nThere is no required difficulty for version 2 addresses like this.")))) + elif toAddressVersionNumber >= 3: + requiredAverageProofOfWorkNonceTrialsPerByte, varintLength = decodeVarint( + pubkeyPayload[readPosition:readPosition + 10]) + readPosition += varintLength + requiredPayloadLengthExtraBytes, varintLength = decodeVarint( + pubkeyPayload[readPosition:readPosition + 10]) + readPosition += varintLength + if requiredAverageProofOfWorkNonceTrialsPerByte < shared.networkDefaultProofOfWorkNonceTrialsPerByte: # We still have to meet a minimum POW difficulty regardless of what they say is allowed in order to get our message to propagate through the network. + requiredAverageProofOfWorkNonceTrialsPerByte = shared.networkDefaultProofOfWorkNonceTrialsPerByte + if requiredPayloadLengthExtraBytes < shared.networkDefaultPayloadLengthExtraBytes: + requiredPayloadLengthExtraBytes = shared.networkDefaultPayloadLengthExtraBytes + shared.UISignalQueue.put(('updateSentItemStatusByAckdata', (ackdata, tr.translateText("MainWindow", "Doing work necessary to send message.\nReceiver\'s required difficulty: %1 and %2").arg(str(float( + requiredAverageProofOfWorkNonceTrialsPerByte) / shared.networkDefaultProofOfWorkNonceTrialsPerByte)).arg(str(float(requiredPayloadLengthExtraBytes) / shared.networkDefaultPayloadLengthExtraBytes))))) + if status != 'forcepow': + if (requiredAverageProofOfWorkNonceTrialsPerByte > shared.config.getint('bitmessagesettings', 'maxacceptablenoncetrialsperbyte') and shared.config.getint('bitmessagesettings', 'maxacceptablenoncetrialsperbyte') != 0) or (requiredPayloadLengthExtraBytes > shared.config.getint('bitmessagesettings', 'maxacceptablepayloadlengthextrabytes') and shared.config.getint('bitmessagesettings', 'maxacceptablepayloadlengthextrabytes') != 0): + # The demanded difficulty is more than we are willing + # to do. + sqlExecute( + '''UPDATE sent SET status='toodifficult' WHERE ackdata=? ''', + ackdata) + shared.UISignalQueue.put(('updateSentItemStatusByAckdata', (ackdata, tr.translateText("MainWindow", "Problem: The work demanded by the recipient (%1 and %2) is more difficult than you are willing to do.").arg(str(float(requiredAverageProofOfWorkNonceTrialsPerByte) / shared.networkDefaultProofOfWorkNonceTrialsPerByte)).arg(str(float( + requiredPayloadLengthExtraBytes) / shared.networkDefaultPayloadLengthExtraBytes)).arg(unicode(strftime(shared.config.get('bitmessagesettings', 'timeformat'), localtime(int(time.time()))), 'utf-8'))))) + continue + else: # if we are sending a message to ourselves or a chan.. + with shared.printLock: + print 'Sending a message. First 150 characters of message:', repr(message[:150]) + behaviorBitfield = '\x00\x00\x00\x01' + + try: + privEncryptionKeyBase58 = shared.config.get( + toaddress, 'privencryptionkey') + except Exception as err: + shared.UISignalQueue.put(('updateSentItemStatusByAckdata',(ackdata,tr.translateText("MainWindow",'Problem: You are trying to send a message to yourself or a chan but your encryption key could not be found in the keys.dat file. Could not encrypt message. %1').arg(unicode(strftime(shared.config.get('bitmessagesettings', 'timeformat'),localtime(int(time.time()))),'utf-8'))))) + with shared.printLock: + sys.stderr.write( + 'Error within sendMsg. Could not read the keys from the keys.dat file for our own address. %s\n' % err) + continue + privEncryptionKeyHex = shared.decodeWalletImportFormat( + privEncryptionKeyBase58).encode('hex') + pubEncryptionKeyBase256 = highlevelcrypto.privToPub( + privEncryptionKeyHex).decode('hex')[1:] requiredAverageProofOfWorkNonceTrialsPerByte = shared.networkDefaultProofOfWorkNonceTrialsPerByte requiredPayloadLengthExtraBytes = shared.networkDefaultPayloadLengthExtraBytes shared.UISignalQueue.put(('updateSentItemStatusByAckdata', ( - ackdata, tr.translateText("MainWindow", "Doing work necessary to send message.\nThere is no required difficulty for version 2 addresses like this.")))) - elif toAddressVersionNumber >= 3: - requiredAverageProofOfWorkNonceTrialsPerByte, varintLength = decodeVarint( - pubkeyPayload[readPosition:readPosition + 10]) - readPosition += varintLength - requiredPayloadLengthExtraBytes, varintLength = decodeVarint( - pubkeyPayload[readPosition:readPosition + 10]) - readPosition += varintLength - if requiredAverageProofOfWorkNonceTrialsPerByte < shared.networkDefaultProofOfWorkNonceTrialsPerByte: # We still have to meet a minimum POW difficulty regardless of what they say is allowed in order to get our message to propagate through the network. - requiredAverageProofOfWorkNonceTrialsPerByte = shared.networkDefaultProofOfWorkNonceTrialsPerByte - if requiredPayloadLengthExtraBytes < shared.networkDefaultPayloadLengthExtraBytes: - requiredPayloadLengthExtraBytes = shared.networkDefaultPayloadLengthExtraBytes - shared.UISignalQueue.put(('updateSentItemStatusByAckdata', (ackdata, tr.translateText("MainWindow", "Doing work necessary to send message.\nReceiver\'s required difficulty: %1 and %2").arg(str(float( - requiredAverageProofOfWorkNonceTrialsPerByte) / shared.networkDefaultProofOfWorkNonceTrialsPerByte)).arg(str(float(requiredPayloadLengthExtraBytes) / shared.networkDefaultPayloadLengthExtraBytes))))) - if status != 'forcepow': - if (requiredAverageProofOfWorkNonceTrialsPerByte > shared.config.getint('bitmessagesettings', 'maxacceptablenoncetrialsperbyte') and shared.config.getint('bitmessagesettings', 'maxacceptablenoncetrialsperbyte') != 0) or (requiredPayloadLengthExtraBytes > shared.config.getint('bitmessagesettings', 'maxacceptablepayloadlengthextrabytes') and shared.config.getint('bitmessagesettings', 'maxacceptablepayloadlengthextrabytes') != 0): - # The demanded difficulty is more than we are willing - # to do. - sqlExecute( - '''UPDATE sent SET status='toodifficult' WHERE ackdata=? ''', - ackdata) - shared.UISignalQueue.put(('updateSentItemStatusByAckdata', (ackdata, tr.translateText("MainWindow", "Problem: The work demanded by the recipient (%1 and %2) is more difficult than you are willing to do.").arg(str(float(requiredAverageProofOfWorkNonceTrialsPerByte) / shared.networkDefaultProofOfWorkNonceTrialsPerByte)).arg(str(float( - requiredPayloadLengthExtraBytes) / shared.networkDefaultPayloadLengthExtraBytes)).arg(unicode(strftime(shared.config.get('bitmessagesettings', 'timeformat'), localtime(int(time.time()))), 'utf-8'))))) - continue - + ackdata, tr.translateText("MainWindow", "Doing work necessary to send message.")))) embeddedTime = pack('>Q', (int(time.time()) + random.randrange( -300, 300))) # the current time plus or minus five minutes. We will use this time both for our message and for the ackdata packed within our message. @@ -750,11 +756,11 @@ class singleWorker(threading.Thread): payload += messageToTransmit if shared.safeConfigGetBoolean(toaddress, 'chan'): with shared.printLock: - print 'Not bothering to generate ackdata because we are sending to a chan.' + print 'Not bothering to include ackdata because we are sending to a chan.' fullAckPayload = '' elif not shared.isBitSetWithinBitfield(behaviorBitfield,31): with shared.printLock: - print 'Not bothering to generate ackdata because the receiver said that they won\'t relay it anyway.' + print 'Not bothering to include ackdata because the receiver said that they won\'t relay it anyway.' fullAckPayload = '' else: fullAckPayload = self.generateFullAckMessage( @@ -795,11 +801,11 @@ class singleWorker(threading.Thread): shared.inventory[inventoryHash] = ( objectType, toStreamNumber, encryptedPayload, int(time.time()),'') shared.inventorySets[toStreamNumber].add(inventoryHash) - if shared.safeConfigGetBoolean(toaddress, 'chan'): + if shared.config.has_section(toaddress): shared.UISignalQueue.put(('updateSentItemStatusByAckdata', (ackdata, tr.translateText("MainWindow", "Message sent. Sent on %1").arg(unicode( strftime(shared.config.get('bitmessagesettings', 'timeformat'), localtime(int(time.time()))), 'utf-8'))))) else: - # not sending to a chan + # not sending to a chan or one of my addresses shared.UISignalQueue.put(('updateSentItemStatusByAckdata', (ackdata, tr.translateText("MainWindow", "Message sent. Waiting on acknowledgement. Sent on %1").arg(unicode( strftime(shared.config.get('bitmessagesettings', 'timeformat'), localtime(int(time.time()))), 'utf-8'))))) print 'Broadcasting inv for my msg(within sendmsg function):', inventoryHash.encode('hex') @@ -808,7 +814,7 @@ class singleWorker(threading.Thread): # Update the status of the message in the 'sent' table to have a # 'msgsent' status or 'msgsentnoackexpected' status. - if shared.safeConfigGetBoolean(toaddress, 'chan'): + if not shared.config.has_section(toaddress): newStatus = 'msgsentnoackexpected' else: newStatus = 'msgsent' diff --git a/src/class_sqlThread.py b/src/class_sqlThread.py index 829b243d..2767489f 100644 --- a/src/class_sqlThread.py +++ b/src/class_sqlThread.py @@ -46,7 +46,7 @@ class sqlThread(threading.Thread): # 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, transmitdata blob, time int, usedpersonally text, UNIQUE(hash) ON CONFLICT REPLACE)''' ) + '''CREATE TABLE pubkeys (hash blob, addressversion int, transmitdata blob, time int, usedpersonally text, UNIQUE(hash, addressversion) ON CONFLICT REPLACE)''' ) self.cur.execute( '''CREATE TABLE inventory (hash blob, objecttype text, streamnumber int, payload blob, receivedtime integer, tag blob, UNIQUE(hash) ON CONFLICT REPLACE)''' ) self.cur.execute( @@ -57,7 +57,7 @@ class sqlThread(threading.Thread): '''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','4')''') + self.cur.execute( '''INSERT INTO settings VALUES('version','5')''') self.cur.execute( '''INSERT INTO settings VALUES('lastvacuumtime',?)''', ( int(time.time()),)) self.conn.commit() @@ -253,13 +253,29 @@ class sqlThread(threading.Thread): with open(shared.appdata + 'keys.dat', 'wb') as configfile: shared.config.write(configfile) + # Add a new column to the pubkeys table to store the address version. + # We're going to trash all of our pubkeys and let them be redownloaded. + item = '''SELECT value FROM settings WHERE key='version';''' + parameters = '' + self.cur.execute(item, parameters) + currentVersion = int(self.cur.fetchall()[0][0]) + if currentVersion == 4: + self.cur.execute( '''DROP TABLE pubkeys''') + self.cur.execute( + '''CREATE TABLE pubkeys (hash blob, addressversion int, transmitdata blob, time int, usedpersonally text, UNIQUE(hash, addressversion) ON CONFLICT REPLACE)''' ) + self.cur.execute( + '''delete from inventory where objecttype = 'pubkey';''') + item = '''update settings set value=? WHERE key='version';''' + parameters = (5,) + self.cur.execute(item, parameters) + # Are you hoping to add a new option to the keys.dat file of existing # Bitmessage users? Add it right above this line! try: testpayload = '\x00\x00' - t = ('1234', testpayload, '12345678', 'no') - self.cur.execute( '''INSERT INTO pubkeys VALUES(?,?,?,?)''', t) + t = ('1234', 1, testpayload, '12345678', 'no') + self.cur.execute( '''INSERT INTO pubkeys VALUES(?,?,?,?,?)''', t) self.conn.commit() self.cur.execute( '''SELECT transmitdata FROM pubkeys WHERE hash='1234' ''') diff --git a/src/shared.py b/src/shared.py index 1b67fef9..1d436346 100644 --- a/src/shared.py +++ b/src/shared.py @@ -469,8 +469,8 @@ def decryptAndCheckPubkeyPayload(payload, address): print 'Pubkey decryption was UNsuccessful due to RIPE mismatch. This shouldn\'t have happened.' return 'failed' - t = (ripe, signedData, int(time.time()), 'yes') - sqlExecute('''INSERT INTO pubkeys VALUES (?,?,?,?)''', *t) + t = (ripe, addressVersion, signedData, int(time.time()), 'yes') + sqlExecute('''INSERT INTO pubkeys VALUES (?,?,?,?,?)''', *t) return 'successful' Peer = collections.namedtuple('Peer', ['host', 'port']) From 79dc462b1e797ec763a83c52240611fb6071d75b Mon Sep 17 00:00:00 2001 From: Jonathan Warren Date: Sun, 29 Sep 2013 23:01:56 -0400 Subject: [PATCH 12/18] Chan fix: completed --- src/class_singleWorker.py | 35 +++++++++++++++++++++++++++++++---- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/src/class_singleWorker.py b/src/class_singleWorker.py index a74c2892..1e712c8e 100644 --- a/src/class_singleWorker.py +++ b/src/class_singleWorker.py @@ -3,6 +3,7 @@ import shared import time from time import strftime, localtime, gmtime import random +from subprocess import call # used when the API must execute an outside program from addresses import * import highlevelcrypto import proofofwork @@ -11,6 +12,7 @@ from class_addressGenerator import pointMult import tr from debug import logger from helper_sql import * +import helper_inbox # This thread, of which there is only one, does the heavy lifting: # calculating POWs. @@ -439,6 +441,9 @@ class singleWorker(threading.Thread): status, toAddressVersion, toStreamNumber, toRipe = decodeAddress(toaddress) # 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. if shared.config.has_section(toaddress): + sqlExecute( + '''UPDATE sent SET status='doingmsgpow' WHERE toaddress=? AND status='msgqueued' ''', + toaddress) continue queryreturn = sqlQuery( '''SELECT hash FROM pubkeys WHERE hash=? AND addressversion=?''', toRipe, toAddressVersion) @@ -528,7 +533,7 @@ class singleWorker(threading.Thread): sys.stderr.write( 'For some reason, the status of a message in our outbox is \'doingmsgpow\' even though we lack the pubkey. Here is the RIPE hash of the needed pubkey: %s\n' % toripe.encode('hex')) sqlExecute( - '''UPDATE sent SET status='msgqueued' WHERE toaddress=? AND status='doingmsgpow' ''', toaddress) + '''UPDATE sent SET status='doingpubkeypow' WHERE toaddress=? AND status='doingmsgpow' ''', toaddress) shared.UISignalQueue.put(('updateSentItemStatusByHash', ( toripe, tr.translateText("MainWindow",'Sending a request for the recipient\'s encryption key.')))) self.requestPubKey(toaddress) @@ -754,9 +759,9 @@ class singleWorker(threading.Thread): subject + '\n' + 'Body:' + message payload += encodeVarint(len(messageToTransmit)) payload += messageToTransmit - if shared.safeConfigGetBoolean(toaddress, 'chan'): + if shared.config.has_section(toaddress): with shared.printLock: - print 'Not bothering to include ackdata because we are sending to a chan.' + print 'Not bothering to include ackdata because we are sending to ourselves or a chan.' fullAckPayload = '' elif not shared.isBitSetWithinBitfield(behaviorBitfield,31): with shared.printLock: @@ -810,7 +815,7 @@ class singleWorker(threading.Thread): strftime(shared.config.get('bitmessagesettings', 'timeformat'), localtime(int(time.time()))), 'utf-8'))))) print 'Broadcasting inv for my msg(within sendmsg function):', inventoryHash.encode('hex') shared.broadcastToSendDataQueues(( - streamNumber, 'advertiseobject', inventoryHash)) + toStreamNumber, 'advertiseobject', inventoryHash)) # Update the status of the message in the 'sent' table to have a # 'msgsent' status or 'msgsentnoackexpected' status. @@ -821,6 +826,28 @@ class singleWorker(threading.Thread): sqlExecute('''UPDATE sent SET msgid=?, status=? WHERE ackdata=?''', inventoryHash,newStatus,ackdata) + # If we are sending to ourselves or a chan, let's put the message in + # our own inbox. + if shared.config.has_section(toaddress): + t = (inventoryHash, toaddress, fromaddress, subject, int( + time.time()), message, 'inbox', 2, 0) + helper_inbox.insert(t) + + shared.UISignalQueue.put(('displayNewInboxMessage', ( + inventoryHash, toaddress, fromaddress, subject, message))) + + # If we are behaving as an API then we might need to run an + # outside command to let some program know that a new message + # has arrived. + if shared.safeConfigGetBoolean('bitmessagesettings', 'apienabled'): + try: + apiNotifyPath = shared.config.get( + 'bitmessagesettings', 'apinotifypath') + except: + apiNotifyPath = '' + if apiNotifyPath != '': + call([apiNotifyPath, "newMessage"]) + def requestPubKey(self, toAddress): toStatus, addressVersionNumber, streamNumber, ripe = decodeAddress( toAddress) From 9e34caebefa1f8c7c96437f53bae753e6e34625c Mon Sep 17 00:00:00 2001 From: Jonathan Warren Date: Sun, 29 Sep 2013 23:05:06 -0400 Subject: [PATCH 13/18] increment version number to 0.4.1 --- Makefile | 2 +- arch.sh | 4 ++-- archpackage/PKGBUILD | 2 +- debian.sh | 4 ++-- ebuild.sh | 4 ++-- generate.sh | 2 +- puppy.sh | 4 ++-- rpm.sh | 4 ++-- rpmpackage/pybitmessage.spec | 2 +- slack.sh | 4 ++-- src/build_osx.py | 2 +- src/shared.py | 2 +- 12 files changed, 18 insertions(+), 18 deletions(-) diff --git a/Makefile b/Makefile index b6e6faa5..3f152460 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ APP=pybitmessage -VERSION=0.4.0 +VERSION=0.4.1 RELEASE=1 ARCH_TYPE=`uname -m` PREFIX?=/usr/local diff --git a/arch.sh b/arch.sh index 42daefdc..6502f21a 100755 --- a/arch.sh +++ b/arch.sh @@ -2,8 +2,8 @@ GIT_APP=PyBitmessage APP=pybitmessage -PREV_VERSION=0.4.0 -VERSION=0.4.0 +PREV_VERSION=0.4.1 +VERSION=0.4.1 RELEASE=1 ARCH_TYPE=any CURRDIR=`pwd` diff --git a/archpackage/PKGBUILD b/archpackage/PKGBUILD index 455180c3..2a0e25ac 100644 --- a/archpackage/PKGBUILD +++ b/archpackage/PKGBUILD @@ -1,6 +1,6 @@ # Maintainer: Bob Mottram (4096 bits) pkgname=pybitmessage -pkgver=0.4.0 +pkgver=0.4.1 pkgrel=1 pkgdesc="Bitmessage is a P2P communications protocol used to send encrypted messages to another person or to many subscribers. It is decentralized and trustless, meaning that you need-not inherently trust any entities like root certificate authorities. It uses strong authentication which means that the sender of a message cannot be spoofed, and it aims to hide "non-content" data, like the sender and receiver of messages, from passive eavesdroppers like those running warrantless wiretapping programs." arch=('any') diff --git a/debian.sh b/debian.sh index b8fa4cf6..c279d07e 100755 --- a/debian.sh +++ b/debian.sh @@ -1,8 +1,8 @@ #!/bin/bash APP=pybitmessage -PREV_VERSION=0.4.0 -VERSION=0.4.0 +PREV_VERSION=0.4.1 +VERSION=0.4.1 RELEASE=1 ARCH_TYPE=all DIR=${APP}-${VERSION} diff --git a/ebuild.sh b/ebuild.sh index c13186e4..c2beffb1 100755 --- a/ebuild.sh +++ b/ebuild.sh @@ -1,8 +1,8 @@ #!/bin/bash APP=pybitmessage -PREV_VERSION=0.4.0 -VERSION=0.4.0 +PREV_VERSION=0.4.1 +VERSION=0.4.1 RELEASE=1 SOURCEDIR=. ARCH_TYPE=`uname -m` diff --git a/generate.sh b/generate.sh index 376c1926..58d0b5e2 100755 --- a/generate.sh +++ b/generate.sh @@ -4,7 +4,7 @@ rm -f Makefile rpmpackage/*.spec -packagemonkey -n "PyBitmessage" --version "0.4.0" --dir "." -l "mit" \ +packagemonkey -n "PyBitmessage" --version "0.4.1" --dir "." -l "mit" \ -e "Bob Mottram (4096 bits) " \ --brief "Send encrypted messages" \ --desc "Bitmessage is a P2P communications protocol used to send " \ diff --git a/puppy.sh b/puppy.sh index b9e30c04..549c1200 100755 --- a/puppy.sh +++ b/puppy.sh @@ -1,8 +1,8 @@ #!/bin/bash APP=pybitmessage -PREV_VERSION=0.4.0 -VERSION=0.4.0 +PREV_VERSION=0.4.1 +VERSION=0.4.1 RELEASE=1 BUILDDIR=~/petbuild CURRDIR=`pwd` diff --git a/rpm.sh b/rpm.sh index 893cae97..7595a500 100755 --- a/rpm.sh +++ b/rpm.sh @@ -1,8 +1,8 @@ #!/bin/bash APP=pybitmessage -PREV_VERSION=0.4.0 -VERSION=0.4.0 +PREV_VERSION=0.4.1 +VERSION=0.4.1 RELEASE=1 SOURCEDIR=. ARCH_TYPE=`uname -m` diff --git a/rpmpackage/pybitmessage.spec b/rpmpackage/pybitmessage.spec index 00012be9..c73b6e15 100644 --- a/rpmpackage/pybitmessage.spec +++ b/rpmpackage/pybitmessage.spec @@ -1,5 +1,5 @@ Name: pybitmessage -Version: 0.4.0 +Version: 0.4.1 Release: 1%{?dist} Summary: Send encrypted messages License: MIT diff --git a/slack.sh b/slack.sh index 07987fc2..7a6013a3 100755 --- a/slack.sh +++ b/slack.sh @@ -1,8 +1,8 @@ #!/bin/bash APP=pybitmessage -PREV_VERSION=0.4.0 -VERSION=0.4.0 +PREV_VERSION=0.4.1 +VERSION=0.4.1 RELEASE=1 ARCH_TYPE=`uname -m` BUILDDIR=~/slackbuild diff --git a/src/build_osx.py b/src/build_osx.py index f9ab2c03..109852ef 100644 --- a/src/build_osx.py +++ b/src/build_osx.py @@ -1,7 +1,7 @@ from setuptools import setup name = "Bitmessage" -version = "0.4.0" +version = "0.4.1" mainscript = ["bitmessagemain.py"] setup( diff --git a/src/shared.py b/src/shared.py index 1d436346..54acc014 100644 --- a/src/shared.py +++ b/src/shared.py @@ -1,4 +1,4 @@ -softwareVersion = '0.4.0' +softwareVersion = '0.4.1' verbose = 1 maximumAgeOfAnObjectThatIAmWillingToAccept = 216000 # Equals two days and 12 hours. lengthOfTimeToLeaveObjectsInInventory = 237600 # Equals two days and 18 hours. This should be longer than maximumAgeOfAnObjectThatIAmWillingToAccept so that we don't process messages twice. From f5b92b2fa56fb0ebeba5a584fbe30a8351166b06 Mon Sep 17 00:00:00 2001 From: Jonathan Warren Date: Sun, 29 Sep 2013 23:06:24 -0400 Subject: [PATCH 14/18] turn timing attack mitigation back on --- src/class_receiveDataThread.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/class_receiveDataThread.py b/src/class_receiveDataThread.py index 97edfb21..59597711 100644 --- a/src/class_receiveDataThread.py +++ b/src/class_receiveDataThread.py @@ -1,4 +1,4 @@ -doTimingAttackMitigation = False +doTimingAttackMitigation = True import time import threading From d487b522cfc791013999cf6000f7ce2f90ee2933 Mon Sep 17 00:00:00 2001 From: ikarakatsanis Date: Wed, 2 Oct 2013 04:14:53 +0400 Subject: [PATCH 15/18] feature_v1 --- src/bitmessageqt/__init__.py | 45 +++++++++------- src/bitmessageqt/settings.py | 12 ++--- src/class_singleCleaner.py | 99 ++++++++++++++++++++++++------------ src/class_sqlThread.py | 18 ++++--- src/helper_bootstrap.py | 2 +- src/helper_startup.py | 10 ++-- src/shared.py | 6 +-- 7 files changed, 121 insertions(+), 71 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 3f59ba4e..b9f168ae 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -2036,23 +2036,34 @@ class MyForm(QtGui.QMainWindow): if float(self.settingsDialogInstance.ui.lineEditMaxAcceptableSmallMessageDifficulty.text()) >= 1 or float(self.settingsDialogInstance.ui.lineEditMaxAcceptableSmallMessageDifficulty.text()) == 0: shared.config.set('bitmessagesettings', 'maxacceptablepayloadlengthextrabytes', str(int(float( self.settingsDialogInstance.ui.lineEditMaxAcceptableSmallMessageDifficulty.text()) * shared.networkDefaultPayloadLengthExtraBytes))) - #my implementation starts here,it was a line here - time_period = (int(str(self.settingsDialogInstance.ui.lineEditHours.text())) * 60 * 60 + int(str(self.settingsDialogInstance.ui.lineEditDays.text())) * 24 * 60 * 60 + - int(str(self.settingsDialogInstance.ui.lineEditMonths.text())) * (60 * 60 * 24 *365)/12) - if time_period < shared.maximumAgeOfAnObjectThatIAmWillingToAccept * 2: - QMessageBox.about(self, _translate("MainWindow", "Error"), _translate( - "MainWindow", "You must insert a time period longer than 5 days.")) - shared.config.set('bitmessagesettings', 'hours', '0') - shared.config.set('bitmessagesettings', 'days', '5') - shared.config.set('bitmessagesettings', 'months', '0') - else: - shared.config.set('bitmessagesettings', 'hours', str( + #my implementation starts here,it was a line here.JOHN + if ((self.settingsDialogInstance.ui.lineEditHours.text()=='') and (self.settingsDialogInstance.ui.lineEditDays.text()=='') and (self.settingsDialogInstance.ui.lineEditMonths.text()=='')): + if (((shared.config.get('bitmessagesettings', 'hours')) != str(self.settingsDialogInstance.ui.lineEditHours.text())) or #if we update the time period from one time period(f.e 1/0/0) to default -/-/,inform the user that restart is needed in order his changes to take effect.JOHN + ((shared.config.get('bitmessagesettings', 'days')) != str(self.settingsDialogInstance.ui.lineEditDays.text())) or + ((shared.config.get('bitmessagesettings', 'months')) != str(self.settingsDialogInstance.ui.lineEditMonths.text()))) : + QMessageBox.about(self, _translate("MainWindow", "Restart"), _translate( + "MainWindow", "You must restart Bitmessage for the time period change to take effect.")) + + shared.config.set('bitmessagesettings', 'hours', '')#give default values to fields..this default situation is special and thats why its needs special treatment ;).JOHN + shared.config.set('bitmessagesettings', 'days', '')#these commands update each field in the keys.dat file.JOHN + shared.config.set('bitmessagesettings', 'months', '') + shared.config.set('bitmessagesettings', 'timeperiod', '-1') + else:#So,if all time period fields(hours,months,days) have valid values(valid values---> 0/0/0, 0/3/2, -/-/-, no valid--> -/0/5, 5/-/-), you can calculate the time period + shared.config.set('bitmessagesettings', 'timeperiod', str(int(str(self.settingsDialogInstance.ui.lineEditHours.text())) * 60 * 60 + int(str(self.settingsDialogInstance.ui.lineEditDays.text())) * 24 * 60 * 60 + + int(str(self.settingsDialogInstance.ui.lineEditMonths.text())) * (60 * 60 * 24 *365)/12)) + + if (((shared.config.get('bitmessagesettings', 'hours')) != str(self.settingsDialogInstance.ui.lineEditHours.text())) or#inform user tha he needs to restart bitmessage in order his changes to take effect.JOHN + ((shared.config.get('bitmessagesettings', 'days')) != str(self.settingsDialogInstance.ui.lineEditDays.text())) or + ((shared.config.get('bitmessagesettings', 'months')) != str(self.settingsDialogInstance.ui.lineEditMonths.text()))) : + QMessageBox.about(self, _translate("MainWindow", "Restart"), _translate( + "MainWindow", "You must restart Bitmessage for the time period change to take effect.")) + shared.config.set('bitmessagesettings', 'hours', str(#this three commands update the fields of this new setting in keys.dat file.JOHN self.settingsDialogInstance.ui.lineEditHours.text())) - shared.config.set('bitmessagesettings', 'days', str( + shared.config.set('bitmessagesettings', 'days', str( self.settingsDialogInstance.ui.lineEditDays.text())) - shared.config.set('bitmessagesettings', 'months', str( + shared.config.set('bitmessagesettings', 'months', str( self.settingsDialogInstance.ui.lineEditMonths.text())) - #my implementation stops here, there is a line + #my implementation stops here, there is a line.JOHN # if str(self.settingsDialogInstance.ui.comboBoxMaxCores.currentText()) == 'All': # shared.config.set('bitmessagesettings', 'maxcores', '99999') @@ -2990,13 +3001,13 @@ class settingsDialog(QtGui.QDialog): QtCore.QObject.connect(self.ui.pushButtonNamecoinTest, QtCore.SIGNAL( "clicked()"), self.click_pushButtonNamecoinTest) - #Adjust tab - self.ui.lineEditHours.setText(str( + #Adjusting time period for resending messages tab.JOHN + self.ui.lineEditHours.setText(str(#Giving values to edit boxes in the UI.JOHN shared.config.get('bitmessagesettings', 'hours'))) self.ui.lineEditDays.setText(str( shared.config.get('bitmessagesettings', 'days'))) self.ui.lineEditMonths.setText(str( - shared.config.get('bitmessagesettings', 'months'))) + shared.config.get('bitmessagesettings', 'months')))#JOHN. #'System' tab removed for now. diff --git a/src/bitmessageqt/settings.py b/src/bitmessageqt/settings.py index 56407d7e..d15d1319 100644 --- a/src/bitmessageqt/settings.py +++ b/src/bitmessageqt/settings.py @@ -320,8 +320,8 @@ class Ui_settingsDialog(object): self.gridLayout.addWidget(self.tabWidgetSettings, 0, 0, 1, 1) #this line existed before #my new implementation starts here - self.tabResendingMessagesAdjustment=QtGui.QWidget() - self.tabResendingMessagesAdjustment.setObjectName(_fromUtf8("tabResendingMessagesAdjustment")) + self.tabResendingMessagesAdjustment=QtGui.QWidget()#all these lines are for the UI implementation, I dont think that you need special explanation about them.JOHN + self.tabResendingMessagesAdjustment.setObjectName(_fromUtf8("tabResendingMessagesAdjustment"))#Please note that approximately 58 line codes added to setting.ui also responsible for the UI.JOHN self.gridLayout_9 = QtGui.QGridLayout(self.tabResendingMessagesAdjustment) self.gridLayout_9.setObjectName(_fromUtf8("gridLayout_9")) self.label_19 = QtGui.QLabel(self.tabResendingMessagesAdjustment) @@ -335,11 +335,11 @@ class Ui_settingsDialog(object): self.label_20 = QtGui.QLabel(self.tabResendingMessagesAdjustment) self.label_20.setLayoutDirection(QtCore.Qt.LeftToRight) self.label_20.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) - self.label_20.setObjectName(_fromUtf8("label_20")) + self.label_20.setObjectName(_fromUtf8("label_20"))#This are Qt code..I just add a label to my tab.JOHN self.gridLayout_9.addWidget(self.label_20, 2, 0, 1, 1) self.lineEditHours = QtGui.QLineEdit(self.tabResendingMessagesAdjustment) self.lineEditHours.setMaximumSize(QtCore.QSize(33, 16777)) - self.lineEditHours.setObjectName(_fromUtf8("lineEditHours")) + self.lineEditHours.setObjectName(_fromUtf8("lineEditHours"))##This are Qt code..I just add a edit box to my tab.JOHN self.gridLayout_9.addWidget(self.lineEditHours, 2, 1, 1, 1) self.label_22 = QtGui.QLabel(self.tabResendingMessagesAdjustment) self.label_22.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) @@ -424,9 +424,9 @@ class Ui_settingsDialog(object): self.tabWidgetSettings.setTabText(self.tabWidgetSettings.indexOf(self.tab), _translate("settingsDialog", "Demanded difficulty", None)) self.label_15.setText(_translate("settingsDialog", "Here you may set the maximum amount of work you are willing to do to send a message to another person. Setting these values to 0 means that any value is acceptable.", None)) self.label_13.setText(_translate("settingsDialog", "Maximum acceptable total difficulty:", None)) - #my new implementation starts here,it wasn't line here + #my new implementation starts here,it wasn't line here.Too simple to explain :D..JOHN self.tabWidgetSettings.setTabText(self.tabWidgetSettings.indexOf(self.tabResendingMessagesAdjustment), _translate("settingsDialog", "Adjusting time period for resending messages", None)) - self.label_19.setText(_translate("settingsDialog", "

If you send a message to someone and he is offline for more than two days, Bitmessage will send the message again after an additional two days. This will be continued with exponential backoff forever. Messages will continue to be sent after 4, 8,16 days and so on until the receiver get them.

Here you can adjust Bitmessage to stop trying to send messages after X hours/days/months. This time period needs to be longer than 5 days.

", None)) + self.label_19.setText(_translate("settingsDialog", "

If you send a message to someone and he is offline for more than two days, Bitmessage will send the message again after an additional two days. This will be continued with exponential backoff forever. Messages will continue to be sent after 4, 8,16 days and so on until the receiver get them.

Here you can adjust Bitmessage to stop trying to send messages after X hours/days/months.

", None)) self.label_20.setText(_translate("settingsDialog", "Time in hours/days/months:", None)) self.label_22.setText(_translate("settingsDialog", "/", None)) self.label_23.setText(_translate("settingsDialog", "/", None)) diff --git a/src/class_singleCleaner.py b/src/class_singleCleaner.py index 84829e87..08150970 100644 --- a/src/class_singleCleaner.py +++ b/src/class_singleCleaner.py @@ -10,16 +10,16 @@ from debug import logger '''The singleCleaner class is a timer-driven thread that cleans data structures to free memory, resends messages when a remote node doesn't respond, and sends pong messages to keep connections alive if the network isn't busy. It cleans these data structures in memory: - inventory (moves data to the on-disk sql database) - inventorySets (clears then reloads data out of sql database) +inventory (moves data to the on-disk sql database) +inventorySets (clears then reloads data out of sql database) It cleans these tables on the disk: - inventory (clears data more than 2 days and 12 hours old) - pubkeys (clears pubkeys older than 4 weeks old which we have not used personally) +inventory (clears data more than 2 days and 12 hours old) +pubkeys (clears pubkeys older than 4 weeks old which we have not used personally) It resends messages when there has been no response: - resends getpubkey messages in 4 days (then 8 days, then 16 days, etc...) - resends msg messages in 4 days (then 8 days, then 16 days, etc...) +resends getpubkey messages in 4 days (then 8 days, then 16 days, etc...) +resends msg messages in 4 days (then 8 days, then 16 days, etc...) ''' @@ -52,7 +52,7 @@ class singleCleaner(threading.Thread): del shared.inventory[hash] shared.UISignalQueue.put(('updateStatusBar', '')) shared.broadcastToSendDataQueues(( - 0, 'pong', 'no data')) # commands the sendData threads to send out a pong message if they haven't sent anything else in the last five minutes. The socket timeout-time is 10 minutes. + 0, 'pong', 'no data')) # commands the sendData threads to send out a pong message if they haven't sent anything else in the last five minutes. The socket timeout-time is 10 minutes. # If we are running as a daemon then we are going to fill up the UI # queue which will never be handled by a UI. We should clear it to # save memory. @@ -65,7 +65,7 @@ class singleCleaner(threading.Thread): # inventory (clears pubkeys after 28 days and everything else # after 2 days and 12 hours) sqlExecute( - '''DELETE FROM inventory WHERE (receivedtime'pubkey') OR (receivedtime'pubkey') OR (receivedtime (shared.maximumAgeOfAnObjectThatIAmWillingToAccept * (2 ** (pubkeyretrynumber))): - print '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. - 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) - shared.workerQueue.put(('sendmessage', '')) - else: # status == msgsent - if int(time.time()) - lastactiontime > (shared.maximumAgeOfAnObjectThatIAmWillingToAccept * (2 ** (msgretrynumber))): - print 'It has been a long time and we haven\'t heard an acknowledgement to our msg. Sending again.' - sqlExecute( + if int(shared.config.get('bitmessagesettings', 'timeperiod'))> -1:#My implemenentation starts here.In this file I just added 4 lines.Two here and other two above.The default value of timeperiod is -1.This means that bitmessage resends messages every 5 days(they say 4 but actually is 5)for ever. If user changes the time period, timeperiod variable will have a specific value so the next if will be executed.JOHN + if (int(time.time()) - lastactiontime) > (shared.maximumAgeOfAnObjectThatIAmWillingToAccept * (2 ** (pubkeyretrynumber))) and ((int(time.time()) - lastactiontime) < int(shared.config.get('bitmessagesettings', 'timeperiod'))):#This line does the magic.This if checks if the time that the public key was sent is longer than 5 days. Then it sends the it again. But with this extra AND it will not send it if this time is shorter than timeperiod.JOHN + print '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. + 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) + shared.workerQueue.put(('sendmessage', '')) + else:#first it wasn't an else statement here, I put it for this setting. I just copy-paste the code again. If someone has any suggestion how we can do this without this if-else just say it.JOHN + if int(time.time()) - lastactiontime > (shared.maximumAgeOfAnObjectThatIAmWillingToAccept * (2 ** (pubkeyretrynumber))): + print '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. + 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) + shared.workerQueue.put(('sendmessage', '')) + else: # status == msgsent + if int(shared.config.get('bitmessagesettings', 'timeperiod'))> -1:#same thing here but for the message.Actually this is the most important thing in the whole feature!.JOHN + if (int(time.time()) - lastactiontime) > (shared.maximumAgeOfAnObjectThatIAmWillingToAccept * (2 ** (pubkeyretrynumber))) and ((int(time.time()) - lastactiontime) < int(shared.config.get('bitmessagesettings', 'timeperiod'))):#same thing here.My implementation in this file stops here.JOHN + print '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) - shared.workerQueue.put(('sendmessage', '')) - shared.UISignalQueue.put(( + shared.workerQueue.put(('sendmessage', '')) + shared.UISignalQueue.put(( 'updateStatusBar', 'Doing work necessary to again attempt to deliver a message...')) + else: + if int(time.time()) - lastactiontime > (shared.maximumAgeOfAnObjectThatIAmWillingToAccept * (2 ** (pubkeyretrynumber))): + print '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) + shared.workerQueue.put(('sendmessage', '')) + shared.UISignalQueue.put(( + 'updateStatusBar', 'Doing work necessary to again attempt to deliver a message...')) + # Let's also clear and reload shared.inventorySets to keep it from # taking up an unnecessary amount of memory. @@ -144,4 +177,4 @@ class singleCleaner(threading.Thread): os._exit(0) shared.knownNodesLock.release() shared.needToWriteKnownNodesToDisk = False - time.sleep(300) + time.sleep(300) \ No newline at end of file diff --git a/src/class_sqlThread.py b/src/class_sqlThread.py index ba016eba..6fa44051 100644 --- a/src/class_sqlThread.py +++ b/src/class_sqlThread.py @@ -252,22 +252,24 @@ class sqlThread(threading.Thread): shared.config.set('bitmessagesettings', 'settingsversion', '7') with open(shared.appdata + 'keys.dat', 'wb') as configfile: shared.config.write(configfile) - + # Are you hoping to add a new option to the keys.dat file of existing # Bitmessage users? Add it right above this line! - #my new implementation starts here - if shared.config.getint('bitmessagesettings', 'settingsversion') == 6: + #my new implementation starts here, the most of these comment will be deleted, they are just for documentation + if shared.config.getint('bitmessagesettings', 'settingsversion') == 7:#this is the version that all we have,if you see your keys.dat file this is your version.JOHN + shared.config.set(#in order to not have to change your keys.dat file I update it with the new lines. I add to your keys.dat three new default fields.JOHN + 'bitmessagesettings', 'hours', '')# hours, days, months have no value.This means that bitmessage works as before. It re-sends mails every 4,8,16 days..forever.JOHN shared.config.set( - 'bitmessagesettings', 'hours', '0') + 'bitmessagesettings', 'days', '') shared.config.set( - 'bitmessagesettings', 'days', '5') + 'bitmessagesettings', 'months', '') shared.config.set( - 'bitmessagesettings', 'months', '0') - shared.config.set('bitmessagesettings', 'settingsversion', '7') + 'bitmessagesettings', 'timeperiod', '-1')#time period has default value -1. This is used for checking in class_singleCleaner. If you leave default the time period or after you change it(f.i 1/0/0), again you set it with its default value(-/-/-) this variable will be -1.JOHN + shared.config.set('bitmessagesettings', 'settingsversion', '8') #We update the version.If I leave it 7 every time that Bitmessage starts your setting will be lost.The default values(-/-/-) will be loaded all the time ;).That was juicy.JOHN with open(shared.appdata + 'keys.dat', 'wb') as configfile: shared.config.write(configfile) - #my new implementation stops here + #my new implementation in this file stops here try: testpayload = '\x00\x00' diff --git a/src/helper_bootstrap.py b/src/helper_bootstrap.py index 6b5b98dc..8e9d28e5 100644 --- a/src/helper_bootstrap.py +++ b/src/helper_bootstrap.py @@ -25,7 +25,7 @@ def knownNodes(): shared.knownNodes[stream][peer] = time except: shared.knownNodes = defaultKnownNodes.createDefaultKnownNodes(shared.appdata) - if shared.config.getint('bitmessagesettings', 'settingsversion') > 7: + if shared.config.getint('bitmessagesettings', 'settingsversion') > 8: print 'Bitmessage cannot read future versions of the keys file (keys.dat). Run the newer version of Bitmessage.' raise SystemExit diff --git a/src/helper_startup.py b/src/helper_startup.py index 35251f70..fdc20cff 100644 --- a/src/helper_startup.py +++ b/src/helper_startup.py @@ -91,12 +91,16 @@ def loadConfig(): # existing users. To do that, search the class_sqlThread.py file for the # text: "right above this line!" + #my implementation starts here. JOHN shared.config.set( - 'bitmessagesettings', 'hours', '0') + 'bitmessagesettings', 'hours', '')#here I am adding the new default settings. The first time that the program is going to run these values will be loaded(UI and keys.dat also :) ).JOHN shared.config.set( - 'bitmessagesettings', 'days', '5') + 'bitmessagesettings', 'days', '') shared.config.set( - 'bitmessagesettings', 'months', '0') + 'bitmessagesettings', 'months', '') + shared.config.set( + 'bitmessagesettings', 'timeperiod', '-1') + #my implementation in this file stops here.JOHN ensureNamecoinOptions() diff --git a/src/shared.py b/src/shared.py index 1b67fef9..4825caf4 100644 --- a/src/shared.py +++ b/src/shared.py @@ -1,9 +1,9 @@ softwareVersion = '0.4.0' verbose = 1 -maximumAgeOfAnObjectThatIAmWillingToAccept = 216000 # Equals two days and 12 hours. -lengthOfTimeToLeaveObjectsInInventory = 237600 # Equals two days and 18 hours. This should be longer than maximumAgeOfAnObjectThatIAmWillingToAccept so that we don't process messages twice. +maximumAgeOfAnObjectThatIAmWillingToAccept = 1800 # Equals two days and 12 hours. +lengthOfTimeToLeaveObjectsInInventory = 237600 # Equals two days and 18 hours. This should be longer than maximumAgeOfAnObjectThatIAmWillingToAccept so that we don't process messages twice. lengthOfTimeToHoldOnToAllPubkeys = 2419200 # Equals 4 weeks. You could make this longer if you want but making it shorter would not be advisable because there is a very small possibility that it could keep you from obtaining a needed pubkey for a period of time. -maximumAgeOfObjectsThatIAdvertiseToOthers = 216000 # Equals two days and 12 hours +maximumAgeOfObjectsThatIAdvertiseToOthers = 1800 # Equals two days and 12 hours maximumAgeOfNodesThatIAdvertiseToOthers = 10800 # Equals three hours useVeryEasyProofOfWorkForTesting = False # If you set this to True while on the normal network, you won't be able to send or sometimes receive messages. From 511185055d9a33df9fdcb451a2ebbc228d36d47b Mon Sep 17 00:00:00 2001 From: ikarakatsanis Date: Wed, 2 Oct 2013 04:16:42 +0400 Subject: [PATCH 16/18] feature_v2 --- src/shared.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/shared.py b/src/shared.py index 4825caf4..68a6e719 100644 --- a/src/shared.py +++ b/src/shared.py @@ -1,9 +1,9 @@ softwareVersion = '0.4.0' verbose = 1 -maximumAgeOfAnObjectThatIAmWillingToAccept = 1800 # Equals two days and 12 hours. +maximumAgeOfAnObjectThatIAmWillingToAccept = 216000 # Equals two days and 12 hours. lengthOfTimeToLeaveObjectsInInventory = 237600 # Equals two days and 18 hours. This should be longer than maximumAgeOfAnObjectThatIAmWillingToAccept so that we don't process messages twice. lengthOfTimeToHoldOnToAllPubkeys = 2419200 # Equals 4 weeks. You could make this longer if you want but making it shorter would not be advisable because there is a very small possibility that it could keep you from obtaining a needed pubkey for a period of time. -maximumAgeOfObjectsThatIAdvertiseToOthers = 1800 # Equals two days and 12 hours +maximumAgeOfObjectsThatIAdvertiseToOthers = 216000 # Equals two days and 12 hours maximumAgeOfNodesThatIAdvertiseToOthers = 10800 # Equals three hours useVeryEasyProofOfWorkForTesting = False # If you set this to True while on the normal network, you won't be able to send or sometimes receive messages. From ff8a88422cbc49af7f5d49309c03d5a08c28041e Mon Sep 17 00:00:00 2001 From: Jonathan Warren Date: Tue, 1 Oct 2013 22:44:00 -0400 Subject: [PATCH 17/18] Fix DevTalk discussion issue: sent message has wrong status (doesn't / does expect ack) --- src/class_singleWorker.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/class_singleWorker.py b/src/class_singleWorker.py index 1e712c8e..b10e1919 100644 --- a/src/class_singleWorker.py +++ b/src/class_singleWorker.py @@ -819,7 +819,7 @@ class singleWorker(threading.Thread): # Update the status of the message in the 'sent' table to have a # 'msgsent' status or 'msgsentnoackexpected' status. - if not shared.config.has_section(toaddress): + if shared.config.has_section(toaddress): newStatus = 'msgsentnoackexpected' else: newStatus = 'msgsent' From c16d9787d289b1f6ae05358e55ad46cd4b8d2a30 Mon Sep 17 00:00:00 2001 From: ikarakatsanis Date: Thu, 3 Oct 2013 18:29:50 +0400 Subject: [PATCH 18/18] feature1_v3_AQWA --- src/bitmessageqt/__init__.py | 20 +++---- src/bitmessageqt/settings.py | 10 ++-- src/class_singleCleaner.py | 103 +++++++++++++++-------------------- src/class_sqlThread.py | 10 ++-- src/helper_startup.py | 6 +- 5 files changed, 67 insertions(+), 82 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index b9f168ae..af8946c0 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -2036,34 +2036,34 @@ class MyForm(QtGui.QMainWindow): if float(self.settingsDialogInstance.ui.lineEditMaxAcceptableSmallMessageDifficulty.text()) >= 1 or float(self.settingsDialogInstance.ui.lineEditMaxAcceptableSmallMessageDifficulty.text()) == 0: shared.config.set('bitmessagesettings', 'maxacceptablepayloadlengthextrabytes', str(int(float( self.settingsDialogInstance.ui.lineEditMaxAcceptableSmallMessageDifficulty.text()) * shared.networkDefaultPayloadLengthExtraBytes))) - #my implementation starts here,it was a line here.JOHN + #my implementation starts here,it was a line here.AQWA if ((self.settingsDialogInstance.ui.lineEditHours.text()=='') and (self.settingsDialogInstance.ui.lineEditDays.text()=='') and (self.settingsDialogInstance.ui.lineEditMonths.text()=='')): - if (((shared.config.get('bitmessagesettings', 'hours')) != str(self.settingsDialogInstance.ui.lineEditHours.text())) or #if we update the time period from one time period(f.e 1/0/0) to default -/-/,inform the user that restart is needed in order his changes to take effect.JOHN + if (((shared.config.get('bitmessagesettings', 'hours')) != str(self.settingsDialogInstance.ui.lineEditHours.text())) or #if we update the time period from one time period(f.e 1/0/0) to default -/-/,inform the user that restart is needed in order his changes to take effect.AQWA ((shared.config.get('bitmessagesettings', 'days')) != str(self.settingsDialogInstance.ui.lineEditDays.text())) or ((shared.config.get('bitmessagesettings', 'months')) != str(self.settingsDialogInstance.ui.lineEditMonths.text()))) : QMessageBox.about(self, _translate("MainWindow", "Restart"), _translate( "MainWindow", "You must restart Bitmessage for the time period change to take effect.")) - shared.config.set('bitmessagesettings', 'hours', '')#give default values to fields..this default situation is special and thats why its needs special treatment ;).JOHN - shared.config.set('bitmessagesettings', 'days', '')#these commands update each field in the keys.dat file.JOHN + shared.config.set('bitmessagesettings', 'hours', '')#give default values to fields..this default situation is special and thats why its needs special treatment ;).AQWA + shared.config.set('bitmessagesettings', 'days', '')#these commands update each field in the keys.dat file.AQWA shared.config.set('bitmessagesettings', 'months', '') shared.config.set('bitmessagesettings', 'timeperiod', '-1') else:#So,if all time period fields(hours,months,days) have valid values(valid values---> 0/0/0, 0/3/2, -/-/-, no valid--> -/0/5, 5/-/-), you can calculate the time period shared.config.set('bitmessagesettings', 'timeperiod', str(int(str(self.settingsDialogInstance.ui.lineEditHours.text())) * 60 * 60 + int(str(self.settingsDialogInstance.ui.lineEditDays.text())) * 24 * 60 * 60 + int(str(self.settingsDialogInstance.ui.lineEditMonths.text())) * (60 * 60 * 24 *365)/12)) - if (((shared.config.get('bitmessagesettings', 'hours')) != str(self.settingsDialogInstance.ui.lineEditHours.text())) or#inform user tha he needs to restart bitmessage in order his changes to take effect.JOHN + if (((shared.config.get('bitmessagesettings', 'hours')) != str(self.settingsDialogInstance.ui.lineEditHours.text())) or#inform user tha he needs to restart bitmessage in order his changes to take effect.AQWA ((shared.config.get('bitmessagesettings', 'days')) != str(self.settingsDialogInstance.ui.lineEditDays.text())) or ((shared.config.get('bitmessagesettings', 'months')) != str(self.settingsDialogInstance.ui.lineEditMonths.text()))) : QMessageBox.about(self, _translate("MainWindow", "Restart"), _translate( "MainWindow", "You must restart Bitmessage for the time period change to take effect.")) - shared.config.set('bitmessagesettings', 'hours', str(#this three commands update the fields of this new setting in keys.dat file.JOHN + shared.config.set('bitmessagesettings', 'hours', str(#this three commands update the fields of this new setting in keys.dat file.AQWA self.settingsDialogInstance.ui.lineEditHours.text())) shared.config.set('bitmessagesettings', 'days', str( self.settingsDialogInstance.ui.lineEditDays.text())) shared.config.set('bitmessagesettings', 'months', str( self.settingsDialogInstance.ui.lineEditMonths.text())) - #my implementation stops here, there is a line.JOHN + #my implementation stops here, there is a line.AQWA # if str(self.settingsDialogInstance.ui.comboBoxMaxCores.currentText()) == 'All': # shared.config.set('bitmessagesettings', 'maxcores', '99999') @@ -3001,13 +3001,13 @@ class settingsDialog(QtGui.QDialog): QtCore.QObject.connect(self.ui.pushButtonNamecoinTest, QtCore.SIGNAL( "clicked()"), self.click_pushButtonNamecoinTest) - #Adjusting time period for resending messages tab.JOHN - self.ui.lineEditHours.setText(str(#Giving values to edit boxes in the UI.JOHN + #Adjusting time period for resending messages tab.AQWA + self.ui.lineEditHours.setText(str(#Giving values to edit boxes in the UI.AQWA shared.config.get('bitmessagesettings', 'hours'))) self.ui.lineEditDays.setText(str( shared.config.get('bitmessagesettings', 'days'))) self.ui.lineEditMonths.setText(str( - shared.config.get('bitmessagesettings', 'months')))#JOHN. + shared.config.get('bitmessagesettings', 'months')))#AQWA. #'System' tab removed for now. diff --git a/src/bitmessageqt/settings.py b/src/bitmessageqt/settings.py index d15d1319..f9c3518a 100644 --- a/src/bitmessageqt/settings.py +++ b/src/bitmessageqt/settings.py @@ -320,8 +320,8 @@ class Ui_settingsDialog(object): self.gridLayout.addWidget(self.tabWidgetSettings, 0, 0, 1, 1) #this line existed before #my new implementation starts here - self.tabResendingMessagesAdjustment=QtGui.QWidget()#all these lines are for the UI implementation, I dont think that you need special explanation about them.JOHN - self.tabResendingMessagesAdjustment.setObjectName(_fromUtf8("tabResendingMessagesAdjustment"))#Please note that approximately 58 line codes added to setting.ui also responsible for the UI.JOHN + self.tabResendingMessagesAdjustment=QtGui.QWidget()#all these lines are for the UI implementation, I dont think that you need special explanation about them.AQWA + self.tabResendingMessagesAdjustment.setObjectName(_fromUtf8("tabResendingMessagesAdjustment"))#Please note that approximately 58 line codes added to setting.ui also responsible for the UI.AQWA self.gridLayout_9 = QtGui.QGridLayout(self.tabResendingMessagesAdjustment) self.gridLayout_9.setObjectName(_fromUtf8("gridLayout_9")) self.label_19 = QtGui.QLabel(self.tabResendingMessagesAdjustment) @@ -335,11 +335,11 @@ class Ui_settingsDialog(object): self.label_20 = QtGui.QLabel(self.tabResendingMessagesAdjustment) self.label_20.setLayoutDirection(QtCore.Qt.LeftToRight) self.label_20.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) - self.label_20.setObjectName(_fromUtf8("label_20"))#This are Qt code..I just add a label to my tab.JOHN + self.label_20.setObjectName(_fromUtf8("label_20"))#This are Qt code..I just add a label to my tab.AQWA self.gridLayout_9.addWidget(self.label_20, 2, 0, 1, 1) self.lineEditHours = QtGui.QLineEdit(self.tabResendingMessagesAdjustment) self.lineEditHours.setMaximumSize(QtCore.QSize(33, 16777)) - self.lineEditHours.setObjectName(_fromUtf8("lineEditHours"))##This are Qt code..I just add a edit box to my tab.JOHN + self.lineEditHours.setObjectName(_fromUtf8("lineEditHours"))##This are Qt code..I just add a edit box to my tab.AQWA self.gridLayout_9.addWidget(self.lineEditHours, 2, 1, 1, 1) self.label_22 = QtGui.QLabel(self.tabResendingMessagesAdjustment) self.label_22.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) @@ -424,7 +424,7 @@ class Ui_settingsDialog(object): self.tabWidgetSettings.setTabText(self.tabWidgetSettings.indexOf(self.tab), _translate("settingsDialog", "Demanded difficulty", None)) self.label_15.setText(_translate("settingsDialog", "Here you may set the maximum amount of work you are willing to do to send a message to another person. Setting these values to 0 means that any value is acceptable.", None)) self.label_13.setText(_translate("settingsDialog", "Maximum acceptable total difficulty:", None)) - #my new implementation starts here,it wasn't line here.Too simple to explain :D..JOHN + #my new implementation starts here,it wasn't line here.Too simple to explain :D..AQWA self.tabWidgetSettings.setTabText(self.tabWidgetSettings.indexOf(self.tabResendingMessagesAdjustment), _translate("settingsDialog", "Adjusting time period for resending messages", None)) self.label_19.setText(_translate("settingsDialog", "

If you send a message to someone and he is offline for more than two days, Bitmessage will send the message again after an additional two days. This will be continued with exponential backoff forever. Messages will continue to be sent after 4, 8,16 days and so on until the receiver get them.

Here you can adjust Bitmessage to stop trying to send messages after X hours/days/months.

", None)) self.label_20.setText(_translate("settingsDialog", "Time in hours/days/months:", None)) diff --git a/src/class_singleCleaner.py b/src/class_singleCleaner.py index 08150970..dfeaf4a1 100644 --- a/src/class_singleCleaner.py +++ b/src/class_singleCleaner.py @@ -86,67 +86,19 @@ class singleCleaner(threading.Thread): break toaddress, toripe, fromaddress, subject, message, ackdata, lastactiontime, status, pubkeyretrynumber, msgretrynumber = row if status == 'awaitingpubkey': - if int(shared.config.get('bitmessagesettings', 'timeperiod'))> -1:#My implemenentation starts here.In this file I just added 4 lines.Two here and other two above.The default value of timeperiod is -1.This means that bitmessage resends messages every 5 days(they say 4 but actually is 5)for ever. If user changes the time period, timeperiod variable will have a specific value so the next if will be executed.JOHN - if (int(time.time()) - lastactiontime) > (shared.maximumAgeOfAnObjectThatIAmWillingToAccept * (2 ** (pubkeyretrynumber))) and ((int(time.time()) - lastactiontime) < int(shared.config.get('bitmessagesettings', 'timeperiod'))):#This line does the magic.This if checks if the time that the public key was sent is longer than 5 days. Then it sends the it again. But with this extra AND it will not send it if this time is shorter than timeperiod.JOHN - print '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. - 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) - shared.workerQueue.put(('sendmessage', '')) - else:#first it wasn't an else statement here, I put it for this setting. I just copy-paste the code again. If someone has any suggestion how we can do this without this if-else just say it.JOHN + if int(shared.config.get('bitmessagesettings', 'timeperiod'))> -1:#My implemenentation starts here.This if statement would become very big with my new code,so I created two function(see at the end of this file) to reduce code.I did.The default value of timeperiod is -1.This means that bitmessage resends messages every 5 days(they say 4 but actually is 5)for ever. If user changes the time period, timeperiod variable will have a specific value so the next if will be executed.AQWA + if (int(time.time()) - lastactiontime) > (shared.maximumAgeOfAnObjectThatIAmWillingToAccept * (2 ** (pubkeyretrynumber))) and ((int(time.time()) - lastactiontime) < int(shared.config.get('bitmessagesettings', 'timeperiod'))):#This line does the magic.This if checks if the time that the public key was sent is longer than 5 days. Then it sends the it again. But with this extra AND it will not send it if this time is shorter than timeperiod.AQWA + resendPubkey(pubkeyretrynumber,toripe) + else:#first it wasn't an else statement here, I put it for this setting. I just copy-paste the code again. If someone has any suggestion how we can do this without this if-else just say it.AQWA if int(time.time()) - lastactiontime > (shared.maximumAgeOfAnObjectThatIAmWillingToAccept * (2 ** (pubkeyretrynumber))): - print '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. - 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) - shared.workerQueue.put(('sendmessage', '')) + resendPubkey(pubkeyretrynumber,toripe) else: # status == msgsent - if int(shared.config.get('bitmessagesettings', 'timeperiod'))> -1:#same thing here but for the message.Actually this is the most important thing in the whole feature!.JOHN - if (int(time.time()) - lastactiontime) > (shared.maximumAgeOfAnObjectThatIAmWillingToAccept * (2 ** (pubkeyretrynumber))) and ((int(time.time()) - lastactiontime) < int(shared.config.get('bitmessagesettings', 'timeperiod'))):#same thing here.My implementation in this file stops here.JOHN - print '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) - shared.workerQueue.put(('sendmessage', '')) - shared.UISignalQueue.put(( - 'updateStatusBar', 'Doing work necessary to again attempt to deliver a message...')) + if int(shared.config.get('bitmessagesettings', 'timeperiod'))> -1:#same thing here but for the message.Actually this is the most important thing in the whole feature!.AQWA + if (int(time.time()) - lastactiontime) > (shared.maximumAgeOfAnObjectThatIAmWillingToAccept * (2 ** (msgretrynumber))) and ((int(time.time()) - lastactiontime) < int(shared.config.get('bitmessagesettings', 'timeperiod'))):#same thing here.My implementation in this file stops here.AQWA + resendMsg(msgretrynumber,ackdata) else: - if int(time.time()) - lastactiontime > (shared.maximumAgeOfAnObjectThatIAmWillingToAccept * (2 ** (pubkeyretrynumber))): - print '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) - shared.workerQueue.put(('sendmessage', '')) - shared.UISignalQueue.put(( - 'updateStatusBar', 'Doing work necessary to again attempt to deliver a message...')) + if int(time.time()) - lastactiontime > (shared.maximumAgeOfAnObjectThatIAmWillingToAccept * (2 ** (msgretrynumber))): + resendMsg(msgretrynumber,ackdata) # Let's also clear and reload shared.inventorySets to keep it from @@ -177,4 +129,37 @@ class singleCleaner(threading.Thread): os._exit(0) shared.knownNodesLock.release() shared.needToWriteKnownNodesToDisk = False - time.sleep(300) \ No newline at end of file + time.sleep(300) + +def resendPubkey(pubkeyretrynumber,toripe):#I just structured the code with these two functions. The code inside existed.It is not mine.AQWA + print '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. + 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) + 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.' + sqlExecute( + '''UPDATE sent SET lastactiontime=?, msgretrynumber=?, status=? WHERE ackdata=?''', + int(time.time()), + msgretrynumber + 1, + 'msgqueued', + ackdata) + shared.workerQueue.put(('sendmessage', '')) + shared.UISignalQueue.put(( + 'updateStatusBar', 'Doing work necessary to again attempt to deliver a message...')) + + + \ No newline at end of file diff --git a/src/class_sqlThread.py b/src/class_sqlThread.py index 6fa44051..6e5e9163 100644 --- a/src/class_sqlThread.py +++ b/src/class_sqlThread.py @@ -257,16 +257,16 @@ class sqlThread(threading.Thread): # Bitmessage users? Add it right above this line! #my new implementation starts here, the most of these comment will be deleted, they are just for documentation - if shared.config.getint('bitmessagesettings', 'settingsversion') == 7:#this is the version that all we have,if you see your keys.dat file this is your version.JOHN - shared.config.set(#in order to not have to change your keys.dat file I update it with the new lines. I add to your keys.dat three new default fields.JOHN - 'bitmessagesettings', 'hours', '')# hours, days, months have no value.This means that bitmessage works as before. It re-sends mails every 4,8,16 days..forever.JOHN + if shared.config.getint('bitmessagesettings', 'settingsversion') == 7:#this is the version that all we have,if you see your keys.dat file this is your version.AQWA + shared.config.set(#in order to not have to change your keys.dat file I update it with the new lines. I add to your keys.dat three new default fields.AQWA + 'bitmessagesettings', 'hours', '')# hours, days, months have no value.This means that bitmessage works as before. It re-sends mails every 4,8,16 days..forever.AQWA shared.config.set( 'bitmessagesettings', 'days', '') shared.config.set( 'bitmessagesettings', 'months', '') shared.config.set( - 'bitmessagesettings', 'timeperiod', '-1')#time period has default value -1. This is used for checking in class_singleCleaner. If you leave default the time period or after you change it(f.i 1/0/0), again you set it with its default value(-/-/-) this variable will be -1.JOHN - shared.config.set('bitmessagesettings', 'settingsversion', '8') #We update the version.If I leave it 7 every time that Bitmessage starts your setting will be lost.The default values(-/-/-) will be loaded all the time ;).That was juicy.JOHN + 'bitmessagesettings', 'timeperiod', '-1')#time period has default value -1. This is used for checking in class_singleCleaner. If you leave default the time period or after you change it(f.i 1/0/0), again you set it with its default value(-/-/-) this variable will be -1.AQWA + shared.config.set('bitmessagesettings', 'settingsversion', '8') #We update the version.If I leave it 7 every time that Bitmessage starts your setting will be lost.The default values(-/-/-) will be loaded all the time ;).That was juicy.AQWA with open(shared.appdata + 'keys.dat', 'wb') as configfile: shared.config.write(configfile) #my new implementation in this file stops here diff --git a/src/helper_startup.py b/src/helper_startup.py index fdc20cff..2469f82e 100644 --- a/src/helper_startup.py +++ b/src/helper_startup.py @@ -91,16 +91,16 @@ def loadConfig(): # existing users. To do that, search the class_sqlThread.py file for the # text: "right above this line!" - #my implementation starts here. JOHN + #my implementation starts here. AQWA shared.config.set( - 'bitmessagesettings', 'hours', '')#here I am adding the new default settings. The first time that the program is going to run these values will be loaded(UI and keys.dat also :) ).JOHN + 'bitmessagesettings', 'hours', '')#here I am adding the new default settings. The first time that the program is going to run these values will be loaded(UI and keys.dat also :) ).AQWA shared.config.set( 'bitmessagesettings', 'days', '') shared.config.set( 'bitmessagesettings', 'months', '') shared.config.set( 'bitmessagesettings', 'timeperiod', '-1') - #my implementation in this file stops here.JOHN + #my implementation in this file stops here.AQWA ensureNamecoinOptions()