Merge branch 'master' of https://github.com/Bitmessage/PyBitmessage into keyfile_perm_fix

This commit is contained in:
Gregor Robinson 2013-06-27 12:42:18 +00:00
commit eba0878172
14 changed files with 378 additions and 55 deletions

View File

@ -1,5 +1,5 @@
APP=pybitmessage
VERSION=0.3.3-2
VERSION=0.3.4
DEST_SHARE=$(DESTDIR)/usr/share
DEST_APP=$(DEST_SHARE)/$(APP)
@ -18,6 +18,7 @@ install:
mkdir -m 755 -p $(DEST_APP)/pyelliptic
mkdir -m 755 -p $(DEST_APP)/socks
mkdir -m 755 -p $(DEST_APP)/bitmessageqt
mkdir -m 755 -p $(DEST_APP)/translations
mkdir -m 755 -p $(DEST_SHARE)/pixmaps
mkdir -m 755 -p $(DEST_SHARE)/icons
mkdir -m 755 -p $(DEST_SHARE)/icons/hicolor
@ -35,6 +36,7 @@ install:
install -m 644 src/pyelliptic/*.py $(DEST_APP)/pyelliptic
install -m 644 src/socks/*.py $(DEST_APP)/socks
install -m 644 src/bitmessageqt/*.py $(DEST_APP)/bitmessageqt
install -m 644 src/translations/*.qm $(DEST_APP)/translations
install -m 755 debian/pybm $(DESTDIR)/usr/bin/$(APP)
install -m 644 desktop/$(APP).desktop $(DEST_SHARE)/applications/$(APP).desktop

View File

@ -7,8 +7,8 @@
#!/bin/bash
APP=pybitmessage
PREV_VERSION=0.3.2
VERSION=0.3.3-2
PREV_VERSION=0.3.3
VERSION=0.3.4
ARCH_TYPE=all
#update version numbers automatically - so you don't have to

View File

@ -706,11 +706,6 @@ if __name__ == "__main__":
signal.signal(signal.SIGINT, helper_generic.signal_handler)
# signal.signal(signal.SIGINT, signal.SIG_DFL)
# Check the Major version, the first element in the array
if sqlite3.sqlite_version_info[0] < 3:
print 'This program requires sqlite version 3 or higher because 2 and lower cannot store NULL values. I see version:', sqlite3.sqlite_version_info
os._exit(0)
helper_startup.loadConfig()
helper_bootstrap.knownNodes()

View File

@ -2844,6 +2844,16 @@ class NewAddressDialog(QtGui.QDialog):
self.ui.groupBoxDeterministic.setHidden(True)
QtGui.QWidget.resize(self, QtGui.QWidget.sizeHint(self))
class NewChanDialog(QtGui.QDialog):
def __init__(self, parent):
QtGui.QWidget.__init__(self, parent)
self.ui = Ui_NewChanDialog()
self.ui.setupUi(self)
self.parent = parent
self.ui.groupBoxCreateChan.setHidden(True)
QtGui.QWidget.resize(self, QtGui.QWidget.sizeHint(self))
class iconGlossaryDialog(QtGui.QDialog):

View File

@ -0,0 +1,99 @@
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'newchandialog.ui'
#
# Created: Tue Jun 25 17:03:01 2013
# by: PyQt4 UI code generator 4.10.2
#
# WARNING! All changes made in this file will be lost!
from PyQt4 import QtCore, QtGui
try:
_fromUtf8 = QtCore.QString.fromUtf8
except AttributeError:
def _fromUtf8(s):
return s
try:
_encoding = QtGui.QApplication.UnicodeUTF8
def _translate(context, text, disambig):
return QtGui.QApplication.translate(context, text, disambig, _encoding)
except AttributeError:
def _translate(context, text, disambig):
return QtGui.QApplication.translate(context, text, disambig)
class Ui_NewChanDialog(object):
def setupUi(self, NewChanDialog):
NewChanDialog.setObjectName(_fromUtf8("NewChanDialog"))
NewChanDialog.resize(447, 441)
self.formLayout = QtGui.QFormLayout(NewChanDialog)
self.formLayout.setObjectName(_fromUtf8("formLayout"))
self.radioButtonCreateChan = QtGui.QRadioButton(NewChanDialog)
self.radioButtonCreateChan.setObjectName(_fromUtf8("radioButtonCreateChan"))
self.formLayout.setWidget(0, QtGui.QFormLayout.LabelRole, self.radioButtonCreateChan)
self.radioButtonJoinChan = QtGui.QRadioButton(NewChanDialog)
self.radioButtonJoinChan.setChecked(True)
self.radioButtonJoinChan.setObjectName(_fromUtf8("radioButtonJoinChan"))
self.formLayout.setWidget(1, QtGui.QFormLayout.LabelRole, self.radioButtonJoinChan)
self.groupBoxJoinChan = QtGui.QGroupBox(NewChanDialog)
self.groupBoxJoinChan.setObjectName(_fromUtf8("groupBoxJoinChan"))
self.gridLayout_2 = QtGui.QGridLayout(self.groupBoxJoinChan)
self.gridLayout_2.setObjectName(_fromUtf8("gridLayout_2"))
self.label = QtGui.QLabel(self.groupBoxJoinChan)
self.label.setWordWrap(True)
self.label.setObjectName(_fromUtf8("label"))
self.gridLayout_2.addWidget(self.label, 0, 0, 1, 1)
self.label_2 = QtGui.QLabel(self.groupBoxJoinChan)
self.label_2.setObjectName(_fromUtf8("label_2"))
self.gridLayout_2.addWidget(self.label_2, 1, 0, 1, 1)
self.lineEditChanNameJoin = QtGui.QLineEdit(self.groupBoxJoinChan)
self.lineEditChanNameJoin.setObjectName(_fromUtf8("lineEditChanNameJoin"))
self.gridLayout_2.addWidget(self.lineEditChanNameJoin, 2, 0, 1, 1)
self.label_3 = QtGui.QLabel(self.groupBoxJoinChan)
self.label_3.setObjectName(_fromUtf8("label_3"))
self.gridLayout_2.addWidget(self.label_3, 3, 0, 1, 1)
self.lineEditChanBitmessageAddress = QtGui.QLineEdit(self.groupBoxJoinChan)
self.lineEditChanBitmessageAddress.setObjectName(_fromUtf8("lineEditChanBitmessageAddress"))
self.gridLayout_2.addWidget(self.lineEditChanBitmessageAddress, 4, 0, 1, 1)
self.formLayout.setWidget(3, QtGui.QFormLayout.SpanningRole, self.groupBoxJoinChan)
self.groupBoxCreateChan = QtGui.QGroupBox(NewChanDialog)
self.groupBoxCreateChan.setObjectName(_fromUtf8("groupBoxCreateChan"))
self.gridLayout = QtGui.QGridLayout(self.groupBoxCreateChan)
self.gridLayout.setObjectName(_fromUtf8("gridLayout"))
self.label_4 = QtGui.QLabel(self.groupBoxCreateChan)
self.label_4.setWordWrap(True)
self.label_4.setObjectName(_fromUtf8("label_4"))
self.gridLayout.addWidget(self.label_4, 0, 0, 1, 1)
self.label_5 = QtGui.QLabel(self.groupBoxCreateChan)
self.label_5.setObjectName(_fromUtf8("label_5"))
self.gridLayout.addWidget(self.label_5, 1, 0, 1, 1)
self.lineEditChanNameCreate = QtGui.QLineEdit(self.groupBoxCreateChan)
self.lineEditChanNameCreate.setObjectName(_fromUtf8("lineEditChanNameCreate"))
self.gridLayout.addWidget(self.lineEditChanNameCreate, 2, 0, 1, 1)
self.formLayout.setWidget(2, QtGui.QFormLayout.SpanningRole, self.groupBoxCreateChan)
self.buttonBox = QtGui.QDialogButtonBox(NewChanDialog)
self.buttonBox.setOrientation(QtCore.Qt.Horizontal)
self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Cancel|QtGui.QDialogButtonBox.Ok)
self.buttonBox.setObjectName(_fromUtf8("buttonBox"))
self.formLayout.setWidget(4, QtGui.QFormLayout.FieldRole, self.buttonBox)
self.retranslateUi(NewChanDialog)
QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(_fromUtf8("accepted()")), NewChanDialog.accept)
QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(_fromUtf8("rejected()")), NewChanDialog.reject)
QtCore.QObject.connect(self.radioButtonJoinChan, QtCore.SIGNAL(_fromUtf8("toggled(bool)")), self.groupBoxJoinChan.setShown)
QtCore.QObject.connect(self.radioButtonCreateChan, QtCore.SIGNAL(_fromUtf8("toggled(bool)")), self.groupBoxCreateChan.setShown)
QtCore.QMetaObject.connectSlotsByName(NewChanDialog)
def retranslateUi(self, NewChanDialog):
NewChanDialog.setWindowTitle(_translate("NewChanDialog", "Dialog", None))
self.radioButtonCreateChan.setText(_translate("NewChanDialog", "Create a new chan", None))
self.radioButtonJoinChan.setText(_translate("NewChanDialog", "Join a chan", None))
self.groupBoxJoinChan.setTitle(_translate("NewChanDialog", "Join a chan", None))
self.label.setText(_translate("NewChanDialog", "<html><head/><body><p>A chan is a set of encryption keys that is shared by a group of people. The keys and bitmessage address used by a chan is generated from a human-friendly word or phrase (the chan name).</p><p>Chans are experimental and are unmoderatable.</p></body></html>", None))
self.label_2.setText(_translate("NewChanDialog", "Chan name:", None))
self.label_3.setText(_translate("NewChanDialog", "Chan bitmessage address:", None))
self.groupBoxCreateChan.setTitle(_translate("NewChanDialog", "Create a chan", None))
self.label_4.setText(_translate("NewChanDialog", "Enter a name for your chan. If you choose a sufficiently complex chan name (like a strong and unique passphrase) and none of your friends share it publicly then the chan will be secure and private.", None))
self.label_5.setText(_translate("NewChanDialog", "Chan name:", None))

View File

@ -0,0 +1,181 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>NewChanDialog</class>
<widget class="QDialog" name="NewChanDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>447</width>
<height>441</height>
</rect>
</property>
<property name="windowTitle">
<string>Dialog</string>
</property>
<layout class="QFormLayout" name="formLayout">
<item row="0" column="0">
<widget class="QRadioButton" name="radioButtonCreateChan">
<property name="text">
<string>Create a new chan</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QRadioButton" name="radioButtonJoinChan">
<property name="text">
<string>Join a chan</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="3" column="0" colspan="2">
<widget class="QGroupBox" name="groupBoxJoinChan">
<property name="title">
<string>Join a chan</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;A chan is a set of encryption keys that is shared by a group of people. The keys and bitmessage address used by a chan is generated from a human-friendly word or phrase (the chan name).&lt;/p&gt;&lt;p&gt;Chans are experimental and are unmoderatable.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Chan name:</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLineEdit" name="lineEditChanNameJoin"/>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Chan bitmessage address:</string>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLineEdit" name="lineEditChanBitmessageAddress"/>
</item>
</layout>
</widget>
</item>
<item row="2" column="0" colspan="2">
<widget class="QGroupBox" name="groupBoxCreateChan">
<property name="title">
<string>Create a chan</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Enter a name for your chan. If you choose a sufficiently complex chan name (like a strong and unique passphrase) and none of your friends share it publicly then the chan will be secure and private.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Chan name:</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLineEdit" name="lineEditChanNameCreate"/>
</item>
</layout>
</widget>
</item>
<item row="4" column="1">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>NewChanDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>428</x>
<y>454</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>NewChanDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>430</x>
<y>460</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>radioButtonJoinChan</sender>
<signal>toggled(bool)</signal>
<receiver>groupBoxJoinChan</receiver>
<slot>setShown(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>74</x>
<y>49</y>
</hint>
<hint type="destinationlabel">
<x>96</x>
<y>227</y>
</hint>
</hints>
</connection>
<connection>
<sender>radioButtonCreateChan</sender>
<signal>toggled(bool)</signal>
<receiver>groupBoxCreateChan</receiver>
<slot>setShown(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>72</x>
<y>28</y>
</hint>
<hint type="destinationlabel">
<x>65</x>
<y>92</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -14,7 +14,7 @@ from setuptools import setup # @UnresolvedImport
name = "Bitmessage"
mainscript = 'bitmessagemain.py'
version = "0.3.3"
version = "0.3.4"
if sys.platform == 'darwin':
extra_options = dict(

View File

@ -21,7 +21,15 @@ class addressGenerator(threading.Thread):
queueValue = shared.addressGeneratorQueue.get()
nonceTrialsPerByte = 0
payloadLengthExtraBytes = 0
if len(queueValue) == 7:
if queueValue[0] == 'createChan':
command, addressVersionNumber, streamNumber, label, deterministicPassphrase = queueValue
eighteenByteRipe = False
numberOfAddressesToMake = 1
elif queueValue[0] == 'joinChan':
command, chanAddress, label, deterministicPassphrase = queueValue
eighteenByteRipe = False
numberOfAddressesToMake = 1
elif len(queueValue) == 7:
command, addressVersionNumber, streamNumber, label, numberOfAddressesToMake, deterministicPassphrase, eighteenByteRipe = queueValue
elif len(queueValue) == 9:
command, addressVersionNumber, streamNumber, label, numberOfAddressesToMake, deterministicPassphrase, eighteenByteRipe, nonceTrialsPerByte, payloadLengthExtraBytes = queueValue
@ -122,7 +130,7 @@ class addressGenerator(threading.Thread):
shared.workerQueue.put((
'doPOWForMyV3Pubkey', ripe.digest()))
elif command == 'createDeterministicAddresses' or command == 'getDeterministicAddress':
elif command == 'createDeterministicAddresses' or command == 'getDeterministicAddress' or command == 'createChan' or command == 'joinChan':
if len(deterministicPassphrase) == 0:
sys.stderr.write(
'WARNING: You are creating deterministic address(es) using a blank passphrase. Bitmessage will do it but it is rather stupid.')
@ -176,7 +184,17 @@ class addressGenerator(threading.Thread):
print 'Address generator calculated', numberOfAddressesWeHadToMakeBeforeWeFoundOneWithTheCorrectRipePrefix, 'addresses at', numberOfAddressesWeHadToMakeBeforeWeFoundOneWithTheCorrectRipePrefix / (time.time() - startTime), 'keys per second.'
address = encodeAddress(3, streamNumber, ripe.digest())
if command == 'createDeterministicAddresses':
saveAddressToDisk = True
# If we are joining an existing chan, let us check to make sure it matches the provided Bitmessage address
if command == 'joinChan':
if address != chanAddress:
#todo: show an error message in the UI
shared.apiAddressGeneratorReturnQueue.put('API Error 0018: Chan name does not match address.')
saveAddressToDisk = False
if command == 'getDeterministicAddress':
saveAddressToDisk = False
if saveAddressToDisk:
# An excellent way for us to store our keys is in Wallet Import Format. Let us convert now.
# https://en.bitcoin.it/wiki/Wallet_import_format
privSigningKey = '\x80' + potentialPrivSigningKey
@ -198,6 +216,8 @@ class addressGenerator(threading.Thread):
shared.config.set(address, 'label', label)
shared.config.set(address, 'enabled', 'true')
shared.config.set(address, 'decoy', 'false')
if command == 'joinChan' or command == 'createChan':
shared.config.set(address, 'chan', 'true')
shared.config.set(address, 'noncetrialsperbyte', str(
nonceTrialsPerByte))
shared.config.set(address, 'payloadlengthextrabytes', str(
@ -213,18 +233,11 @@ class addressGenerator(threading.Thread):
label, address, str(streamNumber))))
listOfNewAddressesToSendOutThroughTheAPI.append(
address)
# if eighteenByteRipe:
# shared.reloadMyAddressHashes()#This is
# necessary here (rather than just at the end)
# because otherwise if the human generates a
# large number of new addresses and uses one
# before they are done generating, the program
# will receive a getpubkey message and will
# ignore it.
shared.myECCryptorObjects[ripe.digest()] = highlevelcrypto.makeCryptor(
potentialPrivEncryptionKey.encode('hex'))
shared.myAddressesByHash[
ripe.digest()] = address
#todo: don't send out pubkey if dealing with a chan; save in pubkeys table instead.
shared.workerQueue.put((
'doPOWForMyV3Pubkey', ripe.digest()))
except:
@ -242,6 +255,7 @@ class addressGenerator(threading.Thread):
# shared.reloadMyAddressHashes()
elif command == 'getDeterministicAddress':
shared.apiAddressGeneratorReturnQueue.put(address)
#todo: return things to the API if createChan or joinChan assuming saveAddressToDisk
else:
raise Exception(
"Error in the addressGenerator thread. Thread was given a command it could not understand: " + command)

View File

@ -69,6 +69,22 @@ class sqlThread(threading.Thread):
'ERROR trying to create database file (message.dat). Error message: %s\n' % str(err))
os._exit(0)
if shared.config.getint('bitmessagesettings', 'settingsversion') == 1:
shared.config.set('bitmessagesettings', 'settingsversion', '2')
# If the settings version is equal to 2 or 3 then the
# sqlThread will modify the pubkeys table and change
# the settings version to 4.
shared.config.set('bitmessagesettings', 'socksproxytype', 'none')
shared.config.set('bitmessagesettings', 'sockshostname', 'localhost')
shared.config.set('bitmessagesettings', 'socksport', '9050')
shared.config.set('bitmessagesettings', 'socksauthentication', 'false')
shared.config.set('bitmessagesettings', 'socksusername', '')
shared.config.set('bitmessagesettings', 'sockspassword', '')
shared.config.set('bitmessagesettings', 'keysencrypted', 'false')
shared.config.set('bitmessagesettings', 'messagesencrypted', 'false')
with open(shared.appdata + 'keys.dat', 'wb') as configfile:
shared.config.write(configfile)
# People running earlier versions of PyBitmessage do not have the
# usedpersonally field in their pubkeys table. Let's add it.
if shared.config.getint('bitmessagesettings', 'settingsversion') == 2:
@ -158,7 +174,7 @@ class sqlThread(threading.Thread):
self.cur.execute( ''' VACUUM ''')
# After code refactoring, the possible status values for sent messages
# as changed.
# have changed.
self.cur.execute(
'''update sent set status='doingmsgpow' where status='doingpow' ''')
self.cur.execute(

View File

@ -78,19 +78,3 @@ def loadConfig():
os.umask(0o077)
with open(shared.appdata + 'keys.dat', 'wb') as configfile:
shared.config.write(configfile)
if shared.config.getint('bitmessagesettings', 'settingsversion') == 1:
shared.config.set('bitmessagesettings', 'settingsversion', '4')
# If the settings version is equal to 2 or 3 then the
# sqlThread will modify the pubkeys table and change
# the settings version to 4.
shared.config.set('bitmessagesettings', 'socksproxytype', 'none')
shared.config.set('bitmessagesettings', 'sockshostname', 'localhost')
shared.config.set('bitmessagesettings', 'socksport', '9050')
shared.config.set('bitmessagesettings', 'socksauthentication', 'false')
shared.config.set('bitmessagesettings', 'socksusername', '')
shared.config.set('bitmessagesettings', 'sockspassword', '')
shared.config.set('bitmessagesettings', 'keysencrypted', 'false')
shared.config.set('bitmessagesettings', 'messagesencrypted', 'false')
with open(shared.appdata + 'keys.dat', 'wb') as configfile:
shared.config.write(configfile)

View File

@ -1,4 +1,4 @@
softwareVersion = '0.3.3-2'
softwareVersion = '0.3.4'
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.
@ -125,7 +125,18 @@ def lookupAppdataFolder():
elif 'win32' in sys.platform or 'win64' in sys.platform:
dataFolder = path.join(environ['APPDATA'], APPNAME) + '\\'
else:
dataFolder = path.expanduser(path.join("~", "." + APPNAME + "/"))
from shutil import move
try:
dataFolder = path.join(environ["XDG_CONFIG_HOME"], APPNAME)
except KeyError:
dataFolder = path.join(environ["HOME"], ".config", APPNAME)
# Migrate existing data to the proper location if this is an existing install
try:
print "Moving data folder to ~/.config/%s" % APPNAME
move(path.join(environ["HOME"], ".%s" % APPNAME), dataFolder)
dataFolder = dataFolder + '/'
except IOError:
dataFolder = dataFolder + '/'
return dataFolder
def isAddressInMyAddressBook(address):

View File

@ -1,21 +1,32 @@
SOURCES = ../about.py\
../addresses.py\
../bitmessage_icons_rc.py\
SOURCES = ../addresses.py\
../bitmessagemain.py\
../class_addressGenerator.py\
../class_outgoingSynSender.py\
../class_receiveDataThread.py\
../class_sendDataThread.py\
../class_singleCleaner.py\
../class_singleListener.py\
../class_singleWorker.py\
../class_sqlThread.py\
../helper_bitcoin.py\
../helper_bootstrap.py\
../helper_generic.py\
../helper_inbox.py\
../helper_sent.py\
../helper_startup.py\
../shared.py
../bitmessageqt/__init__.py\
../bitmessageui.py\
../defaultKnownNodes.py\
../help.py\
../highlevelcrypto.py\
../iconglossary.py\
../newaddressdialog.py\
../newsubscriptiondialog.py\
../proofofwork.py\
../regenerateaddresses.py\
../settings.py\
../shared.py\
../singleton.py\
../specialaddressbehavior.py
../bitmessageqt/about.py\
../bitmessageqt/bitmessageui.py\
../bitmessageqt/help.py\
../bitmessageqt/iconglossary.py\
../bitmessageqt/newaddressdialog.py\
../bitmessageqt/newchandialog.py\
../bitmessageqt/newsubscriptiondialog.py\
../bitmessageqt/regenerateaddresses.py\
../bitmessageqt/settings.py\
../bitmessageqt/specialaddressbehavior.py
TRANSLATIONS = bitmessage_fr_BE.ts