Merge branch 'foo'

This commit is contained in:
Chuck 2013-08-14 14:42:30 +07:00
commit 5f64271800
35 changed files with 999 additions and 583 deletions

101
INSTALL.md Normal file
View File

@ -0,0 +1,101 @@
#PyBitmessage Installation Instructions
For an up-to-date version of these instructions, please visit the
[Bitmessage Wiki](https://bitmessage.org/wiki/Compiling_instructions).
PyBitmessage can be run either straight from source or from an installed
packaged.
##Dependencies
Before running PyBitmessage, make sure you have all the needed dependencies
installed on your system.
Here's a list of dependencies needed for PyBitmessage
- python2.7
- python2-qt4 (python-qt4 on Debian/Ubuntu)
- openssl
- (Fedora & Redhat only) openssl-compat-bitcoin-libs
##Running PyBitmessage
PyBitmessage can be run two ways: straight from source or via a package which
is installed on your system. Since PyBitmessage is Beta, it is best to run
PyBitmessage from source, so that you may update as needed.
####Updating
To update PyBitmessage from source (Linux/OS X), you can do these easy steps:
```
cd PyBitmessage/src/
git fetch --all
git reset --hard origin/master
python bitmessagemain.py
```
Viola! Bitmessage is updated!
####Linux
To run PyBitmessage from the command-line, you must download the source, then
run `src/bitmessagemain.py`.
```
git clone git://github.com/Bitmessage/PyBitmessage.git
cd PyBitmessage/ && python src/bitmessagemain.py
```
That's it! *Honestly*!
####Windows
In Windows you can download an executable for Bitmessage
[here](https://bitmessage.org/download/windows/Bitmessage.exe).
However, if you would like to run PyBitmessage via Python in Windows, you can
go [here](https://bitmessage.org/wiki/Compiling_instructions#Windows) for
information on how to do so.
####OS X
First off, install Homebrew.
```
ruby -e "$(curl -fsSL https://raw.github.com/mxcl/homebrew/go)"
```
Now, install the required dependencies
```
sudo port install python27 py27-pyqt4 openssl
sudo port install git-core +svn +doc +bash_completion +gitweb
```
Download and run PyBitmessage:
```
git clone git://github.com/Bitmessage/PyBitmessage.git
cd PyBitmessage && python src/bitmessagemain.py
```
##Creating a package for installation
If you really want, you can make a package for PyBitmessage which you may
install yourself or distribute to friends. This isn't reccomended, since
PyBitmessage is in Beta, and subject to frequent change.
####Linux
First off, since PyBitmessage uses something nifty called
[packagemonkey](https://github.com/fuzzgun/packagemonkey), go ahead and get
that installed. You may have to build it from source.
Next, edit the generate.sh script. To your liking.
Now, run the appropriate script for the type of package you'd like to make
```
arch.sh - create a package for Arch Linux
debian.sh - create a package for Debian/Ubuntu
ebuild.sh - create a package for Gentoo
osx.sh - create a package for OS X
puppy.sh - create a package for Puppy Linux
rpm.sh - create a RPM package
slack.sh - create a package for Slackware
```
####OS X
Please refer to
[this page](https://bitmessage.org/forum/index.php/topic,2761.0.html) on the
forums for instructions on how to create a package on OS X.
Please note that some versions of OS X don't work.
###Windows
#TODO: Create Windows package creation instructions

View File

@ -1,8 +1,8 @@
#!/bin/bash #!/bin/bash
APP=pybitmessage APP=pybitmessage
PREV_VERSION=0.3.4 PREV_VERSION=0.3.5
VERSION=0.3.4 VERSION=0.3.5
RELEASE=1 RELEASE=1
ARCH_TYPE=`uname -m` ARCH_TYPE=`uname -m`
CURRDIR=`pwd` CURRDIR=`pwd`

View File

@ -1,6 +1,6 @@
# Maintainer: Bob Mottram (4096 bits) <bob@robotics.uk.to> # Maintainer: Bob Mottram (4096 bits) <bob@robotics.uk.to>
pkgname=pybitmessage pkgname=pybitmessage
pkgver=0.3.4 pkgver=0.3.5
pkgrel=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." 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=('i686' 'x86_64') arch=('i686' 'x86_64')

2
debian.sh Normal file → Executable file
View File

@ -2,7 +2,7 @@
APP=pybitmessage APP=pybitmessage
PREV_VERSION=0.3.4 PREV_VERSION=0.3.4
VERSION=0.3.4 VERSION=0.3.5
RELEASE=1 RELEASE=1
ARCH_TYPE=`uname -m` ARCH_TYPE=`uname -m`
DIR=${APP}-${VERSION} DIR=${APP}-${VERSION}

28
debian/changelog vendored
View File

@ -1,3 +1,31 @@
pybitmessage (0.3.5-1) raring; urgency=low
* Inbox message retrieval API functions now also returns read status
* Added right-click option to mark a message as unread
* Prompt user to connect at first startup
* Install into /usr/local by default
* Add a missing rm -f to the uninstall task.
* Use system text color for enabled addresses instead of black
* Added support for Chans
* Start storing msgid in sent table
* Optionally play sounds on connection/disconnection or when messages arrive
* Adding configuration option to listen for connections when using SOCKS
* Added packaging for multiple distros (Arch, Puppy, Slack, etc.)
* Added Russian translation
* Added search support in the UI
* Added 'make uninstall'
* To improve OSX support, use PKCS5_PBKDF2_HMAC_SHA1 if PKCS5_PBKDF2_HMAC is unavailable
* Added better warnings for OSX users who are using old versions of Python
* Repaired debian packaging
* Altered Makefile to avoid needing to chase changes
* Added logger module
* Added bgWorker class for background tasks
* Added use of gevent module
* On not-Windows: Fix insecure keyfile permissions
* Fix 100% CPU usage issue
-- Bob Mottram (4096 bits) <bob@robotics.uk.to> Mon, 29 July 2013 22:11:00 +0100
pybitmessage (0.3.4-1) raring; urgency=low pybitmessage (0.3.4-1) raring; urgency=low
* Switched addr, msg, broadcast, and getpubkey message types * Switched addr, msg, broadcast, and getpubkey message types

0
debian/rules vendored Normal file → Executable file
View File

View File

@ -1,8 +1,8 @@
#!/bin/bash #!/bin/bash
APP=pybitmessage APP=pybitmessage
PREV_VERSION=0.3.4 PREV_VERSION=0.3.5
VERSION=0.3.4 VERSION=0.3.5
RELEASE=1 RELEASE=1
SOURCEDIR=. SOURCEDIR=.
ARCH_TYPE=`uname -m` ARCH_TYPE=`uname -m`

View File

@ -4,4 +4,29 @@
rm -f Makefile rpmpackage/*.spec rm -f Makefile rpmpackage/*.spec
packagemonkey -n "PyBitmessage" --version "0.3.4" --dir "." -l "mit" -e "Bob Mottram (4096 bits) <bob@robotics.uk.to>" --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." --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" --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" --dependsarch "python2, qt4, python2-pyqt4, sqlite, openssl, gst123" --suggestsarch "python2-gevent" --pythonversion 2 --dependsebuild "dev-libs/openssl, dev-python/PyQt4[${PYTHON_USEDEP}]" --buildebuild "\${PYTHON_DEPS}" --pythonreq "sqlite" --repository "https://github.com/Bitmessage/PyBitmessage.git" packagemonkey -n "PyBitmessage" --version "0.3.5" --dir "." -l "mit" \
-e "Bob Mottram (4096 bits) <bob@robotics.uk.to>" \
--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." \
--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" \
--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" \
--dependsarch "python2, qt4, python2-pyqt4, sqlite, openssl, gst123" \
--suggestsarch "python2-gevent" --pythonversion 2 \
--dependsebuild "dev-libs/openssl, dev-python/PyQt4[${PYTHON_USEDEP}]" \
--buildebuild "\${PYTHON_DEPS}" --pythonreq "sqlite" \
--repository "https://github.com/Bitmessage/PyBitmessage.git"

View File

@ -1,8 +1,8 @@
#!/bin/bash #!/bin/bash
APP=pybitmessage APP=pybitmessage
PREV_VERSION=0.3.4 PREV_VERSION=0.3.5
VERSION=0.3.4 VERSION=0.3.5
RELEASE=1 RELEASE=1
BUILDDIR=~/petbuild BUILDDIR=~/petbuild
CURRDIR=`pwd` CURRDIR=`pwd`

View File

@ -1 +0,0 @@
pybitmessage-0.3.4-1|PyBitmessage|0.3.4|1|Internet;mailnews;|5.8M||pybitmessage-0.3.4-1.pet|+openssl,+python-qt4,+sqlite3,+sqlite3-dev,+python-openssl,+python-sip,+gst123|Send encrypted messages|ubuntu|precise|5|

View File

@ -0,0 +1 @@
pybitmessage-0.3.5-1|PyBitmessage|0.3.5|1|Internet;mailnews;|7.2M||pybitmessage-0.3.5-1.pet|+openssl,+python-qt4,+sqlite3,+sqlite3-dev,+python-openssl,+python-sip,+gst123|Send encrypted messages|ubuntu|precise|5|

4
rpm.sh
View File

@ -1,8 +1,8 @@
#!/bin/bash #!/bin/bash
APP=pybitmessage APP=pybitmessage
PREV_VERSION=0.3.4 PREV_VERSION=0.3.5
VERSION=0.3.4 VERSION=0.3.5
RELEASE=1 RELEASE=1
SOURCEDIR=. SOURCEDIR=.
ARCH_TYPE=`uname -m` ARCH_TYPE=`uname -m`

View File

@ -1,5 +1,5 @@
Name: pybitmessage Name: pybitmessage
Version: 0.3.4 Version: 0.3.5
Release: 1%{?dist} Release: 1%{?dist}
Summary: Send encrypted messages Summary: Send encrypted messages
License: MIT License: MIT
@ -68,6 +68,31 @@ make install -B DESTDIR=%{buildroot} PREFIX=/usr
%attr(644,root,root) /usr/share/icons/hicolor/24x24/apps/%{name}.png %attr(644,root,root) /usr/share/icons/hicolor/24x24/apps/%{name}.png
%changelog %changelog
* Mon Jul 29 2013 Bob Mottram (4096 bits) <bob@robotics.uk.to> - 0.3.5-1
- Inbox message retrieval API functions now also returns read status
- Added right-click option to mark a message as unread
- Prompt user to connect at first startup
- Install into /usr/local by default
- Add a missing rm -f to the uninstall task.
- Use system text color for enabled addresses instead of black
- Added support for Chans
- Start storing msgid in sent table
- Optionally play sounds on connection/disconnection or when messages arrive
- Adding configuration option to listen for connections when using SOCKS
- Added packaging for multiple distros (Arch, Puppy, Slack, etc.)
- Added Russian translation
- Added search support in the UI
- Added 'make uninstall'
- To improve OSX support, use PKCS5_PBKDF2_HMAC_SHA1 if PKCS5_PBKDF2_HMAC is unavailable
- Added better warnings for OSX users who are using old versions of Python
- Repaired debian packaging
- Altered Makefile to avoid needing to chase changes
- Added logger module
- Added bgWorker class for background tasks
- Added use of gevent module
- On not-Windows: Fix insecure keyfile permissions
- Fix 100% CPU usage issue
* Sun Jun 30 2013 Bob Mottram (4096 bits) <bob@robotics.uk.to> - 0.3.4-1 * Sun Jun 30 2013 Bob Mottram (4096 bits) <bob@robotics.uk.to> - 0.3.4-1
- Switched addr, msg, broadcast, and getpubkey message types - Switched addr, msg, broadcast, and getpubkey message types
to 8 byte time. Last remaining type is pubkey. to 8 byte time. Last remaining type is pubkey.

View File

@ -1,8 +1,8 @@
#!/bin/bash #!/bin/bash
APP=pybitmessage APP=pybitmessage
PREV_VERSION=0.3.4 PREV_VERSION=0.3.5
VERSION=0.3.4 VERSION=0.3.5
RELEASE=1 RELEASE=1
ARCH_TYPE=`uname -m` ARCH_TYPE=`uname -m`
BUILDDIR=~/slackbuild BUILDDIR=~/slackbuild

View File

@ -329,6 +329,21 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
'base64'), 'message': message.encode('base64'), 'encodingType': encodingtype, 'receivedTime': received, 'read': read}, indent=4, separators=(',', ': ')) 'base64'), 'message': message.encode('base64'), 'encodingType': encodingtype, 'receivedTime': received, 'read': read}, indent=4, separators=(',', ': '))
data += ']}' data += ']}'
return data return data
elif method == 'getAllInboxMessageIds' or method == 'getAllInboxMessageIDs':
shared.sqlLock.acquire()
shared.sqlSubmitQueue.put(
'''SELECT msgid FROM inbox where folder='inbox' ORDER BY received''')
shared.sqlSubmitQueue.put('')
queryreturn = shared.sqlReturnQueue.get()
shared.sqlLock.release()
data = '{"inboxMessageIds":['
for row in queryreturn:
msgid = row[0]
if len(data) > 25:
data += ','
data += json.dumps({'msgid': msgid.encode('hex')}, indent=4, separators=(',', ': '))
data += ']}'
return data
elif method == 'getInboxMessageById' or method == 'getInboxMessageByID': elif method == 'getInboxMessageById' or method == 'getInboxMessageByID':
if len(params) == 0: if len(params) == 0:
return 'API Error 0000: I need parameters!' return 'API Error 0000: I need parameters!'
@ -363,7 +378,21 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
data += json.dumps({'msgid':msgid.encode('hex'), 'toAddress':toAddress, 'fromAddress':fromAddress, 'subject':subject.encode('base64'), 'message':message.encode('base64'), 'encodingType':encodingtype, 'lastActionTime':lastactiontime, 'status':status, 'ackData':ackdata.encode('hex')}, indent=4, separators=(',', ': ')) data += json.dumps({'msgid':msgid.encode('hex'), 'toAddress':toAddress, 'fromAddress':fromAddress, 'subject':subject.encode('base64'), 'message':message.encode('base64'), 'encodingType':encodingtype, 'lastActionTime':lastactiontime, 'status':status, 'ackData':ackdata.encode('hex')}, indent=4, separators=(',', ': '))
data += ']}' data += ']}'
return data return data
elif method == 'getInboxMessagesByAddress': elif method == 'getAllSentMessageIds' or method == 'getAllSentMessageIDs':
shared.sqlLock.acquire()
shared.sqlSubmitQueue.put('''SELECT msgid FROM sent where folder='sent' ORDER BY lastactiontime''')
shared.sqlSubmitQueue.put('')
queryreturn = shared.sqlReturnQueue.get()
shared.sqlLock.release()
data = '{"sentMessageIds":['
for row in queryreturn:
msgid = row[0]
if len(data) > 25:
data += ','
data += json.dumps({'msgid':msgid.encode('hex')}, indent=4, separators=(',', ': '))
data += ']}'
return data
elif method == 'getInboxMessagesByReceiver' or method == 'getInboxMessagesByAddress': #after some time getInboxMessagesByAddress should be removed
if len(params) == 0: if len(params) == 0:
return 'API Error 0000: I need parameters!' return 'API Error 0000: I need parameters!'
toAddress = params[0] toAddress = params[0]
@ -439,7 +468,24 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
data += json.dumps({'msgid':msgid.encode('hex'), 'toAddress':toAddress, 'fromAddress':fromAddress, 'subject':subject.encode('base64'), 'message':message.encode('base64'), 'encodingType':encodingtype, 'lastActionTime':lastactiontime, 'status':status, 'ackData':ackdata.encode('hex')}, indent=4, separators=(',', ': ')) data += json.dumps({'msgid':msgid.encode('hex'), 'toAddress':toAddress, 'fromAddress':fromAddress, 'subject':subject.encode('base64'), 'message':message.encode('base64'), 'encodingType':encodingtype, 'lastActionTime':lastactiontime, 'status':status, 'ackData':ackdata.encode('hex')}, indent=4, separators=(',', ': '))
data += ']}' data += ']}'
return data return data
elif (method == 'trashMessage') or (method == 'trashInboxMessage'): elif method == 'trashMessage':
if len(params) == 0:
return 'API Error 0000: I need parameters!'
msgid = params[0].decode('hex')
# Trash if in inbox table
helper_inbox.trash(msgid)
# Trash if in sent table
t = (msgid,)
shared.sqlLock.acquire()
shared.sqlSubmitQueue.put('''UPDATE sent SET folder='trash' WHERE msgid=?''')
shared.sqlSubmitQueue.put(t)
shared.sqlReturnQueue.get()
shared.sqlSubmitQueue.put('commit')
shared.sqlLock.release()
# shared.UISignalQueue.put(('removeSentRowByMsgid',msgid)) This function doesn't exist yet.
return 'Trashed message (assuming message existed).'
elif method == 'trashInboxMessage':
if len(params) == 0: if len(params) == 0:
return 'API Error 0000: I need parameters!' return 'API Error 0000: I need parameters!'
msgid = params[0].decode('hex') msgid = params[0].decode('hex')
@ -681,10 +727,134 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
shared.UISignalQueue.put(('rerenderInboxFromLabels', '')) shared.UISignalQueue.put(('rerenderInboxFromLabels', ''))
shared.UISignalQueue.put(('rerenderSubscriptions', '')) shared.UISignalQueue.put(('rerenderSubscriptions', ''))
return 'Deleted subscription if it existed.' return 'Deleted subscription if it existed.'
elif method == 'listSubscriptions':
shared.sqlLock.acquire()
shared.sqlSubmitQueue.put('''SELECT label, address, enabled FROM subscriptions''')
shared.sqlSubmitQueue.put('')
queryreturn = shared.sqlReturnQueue.get()
shared.sqlLock.release()
data = '{"subscriptions":['
for row in queryreturn:
label, address, enabled = row
label = shared.fixPotentiallyInvalidUTF8Data(label)
if len(data) > 20:
data += ','
data += json.dumps({'label':label.encode('base64'), 'address': address, 'enabled': enabled == 1}, indent=4, separators=(',',': '))
data += ']}'
return data
elif method == 'disseminatePreEncryptedMsg':
# The device issuing this command to PyBitmessage supplies a msg object that has
# already been encrypted and had the necessary proof of work done for it to be
# disseminated to the rest of the Bitmessage network. PyBitmessage accepts this msg
# object and sends it out to the rest of the Bitmessage network as if it had generated the
# message itself. Please do not yet add this to the api doc.
if len(params) != 1:
return 'API Error 0000: I need 1 parameter!'
encryptedPayload, = params
encryptedPayload = encryptedPayload.decode('hex')
toStreamNumber = decodeVarint(encryptedPayload[16:26])[0]
inventoryHash = calculateInventoryHash(encryptedPayload)
objectType = 'msg'
shared.inventory[inventoryHash] = (
objectType, toStreamNumber, encryptedPayload, int(time.time()))
with shared.printLock:
print 'Broadcasting inv for msg(API disseminatePreEncryptedMsg command):', inventoryHash.encode('hex')
shared.broadcastToSendDataQueues((
toStreamNumber, 'sendinv', inventoryHash))
elif method == 'disseminatePubkey':
# The device issuing this command to PyBitmessage supplies a pubkey object that has
# already had the necessary proof of work done for it to be disseminated to the rest of the
# Bitmessage network. PyBitmessage accepts this pubkey object and sends it out to the
# rest of the Bitmessage network as if it had generated the pubkey object itself. Please
# do not yet add this to the api doc.
if len(params) != 1:
return 'API Error 0000: I need 1 parameter!'
payload, = params
payload = payload.decode('hex')
pubkeyReadPosition = 8 # bypass the nonce
if payload[pubkeyReadPosition:pubkeyReadPosition+4] == '\x00\x00\x00\x00': # if this pubkey uses 8 byte time
pubkeyReadPosition += 8
else:
pubkeyReadPosition += 4
addressVersion, addressVersionLength = decodeVarint(payload[pubkeyReadPosition:pubkeyReadPosition+10])
pubkeyReadPosition += addressVersionLength
pubkeyStreamNumber = decodeVarint(payload[pubkeyReadPosition:pubkeyReadPosition+10])[0]
inventoryHash = calculateInventoryHash(payload)
objectType = 'pubkey'
shared.inventory[inventoryHash] = (
objectType, pubkeyStreamNumber, payload, int(time.time()))
with shared.printLock:
print 'broadcasting inv within API command disseminatePubkey with hash:', inventoryHash.encode('hex')
shared.broadcastToSendDataQueues((
streamNumber, 'sendinv', inventoryHash))
elif method == 'getMessageDataByDestinationHash':
# 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:
return 'API Error 0000: I need 1 parameter!'
requestedHash, = params
if len(requestedHash) != 40:
return 'API Error 0019: The length of hash should be 20 bytes (encoded in hex thus 40 characters).'
requestedHash = requestedHash.decode('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).
parameters = ''
with shared.sqlLock:
shared.sqlSubmitQueue.put('''SELECT hash, payload FROM inventory WHERE first20bytesofencryptedmessage = '' and objecttype = 'msg' ; ''')
shared.sqlSubmitQueue.put(parameters)
queryreturn = shared.sqlReturnQueue.get()
for row in queryreturn:
hash, payload = row
readPosition = 16 # Nonce length + time length
readPosition += decodeVarint(payload[readPosition:readPosition+10])[1] # Stream Number length
t = (payload[readPosition:readPosition+20],hash)
shared.sqlSubmitQueue.put('''UPDATE inventory SET first20bytesofencryptedmessage=? WHERE hash=?; ''')
shared.sqlSubmitQueue.put(t)
shared.sqlReturnQueue.get()
parameters = (requestedHash,)
with shared.sqlLock:
shared.sqlSubmitQueue.put('commit')
shared.sqlSubmitQueue.put('''SELECT payload FROM inventory WHERE first20bytesofencryptedmessage = ?''')
shared.sqlSubmitQueue.put(parameters)
queryreturn = shared.sqlReturnQueue.get()
data = '{"receivedMessageDatas":['
for row in queryreturn:
payload, = row
if len(data) > 25:
data += ','
data += json.dumps({'data':payload.encode('hex')}, indent=4, separators=(',', ': '))
data += ']}'
return data
elif method == 'getPubkeyByHash':
# Method will eventually be used by a particular Android app to
# retrieve pubkeys. Please do not yet add this to the api docs.
if len(params) != 1:
return 'API Error 0000: I need 1 parameter!'
requestedHash, = params
if len(requestedHash) != 40:
return 'API Error 0019: The length of hash should be 20 bytes (encoded in hex thus 40 characters).'
requestedHash = requestedHash.decode('hex')
parameters = (requestedHash,)
with shared.sqlLock:
shared.sqlSubmitQueue.put('''SELECT transmitdata FROM pubkeys WHERE hash = ? ; ''')
shared.sqlSubmitQueue.put(parameters)
queryreturn = shared.sqlReturnQueue.get()
data = '{"pubkey":['
for row in queryreturn:
transmitdata, = row
data += json.dumps({'data':transmitdata.encode('hex')}, indent=4, separators=(',', ': '))
data += ']}'
return data
elif method == 'clientStatus': elif method == 'clientStatus':
return '{ "networkConnections" : "%s" }' % str(len(shared.connectedHostsList)) return '{ "networkConnections" : "%s" }' % str(len(shared.connectedHostsList))
else: else:
return 'Invalid Method: %s' % method return 'API Error 0020: Invalid method: %s' % method
# This thread, of which there is only one, runs the API. # This thread, of which there is only one, runs the API.
@ -700,11 +870,8 @@ class singleAPI(threading.Thread):
se.register_introspection_functions() se.register_introspection_functions()
se.serve_forever() se.serve_forever()
# This is a list of current connections (the thread pointers at least)
selfInitiatedConnections = {} selfInitiatedConnections = {}
# This is a list of current connections (the thread pointers at least)
if shared.useVeryEasyProofOfWorkForTesting: if shared.useVeryEasyProofOfWorkForTesting:
@ -713,7 +880,8 @@ if shared.useVeryEasyProofOfWorkForTesting:
shared.networkDefaultPayloadLengthExtraBytes = int( shared.networkDefaultPayloadLengthExtraBytes = int(
shared.networkDefaultPayloadLengthExtraBytes / 7000) shared.networkDefaultPayloadLengthExtraBytes / 7000)
if __name__ == "__main__": class Main:
def start(self, deamon=False):
# is the application already running? If yes then exit. # is the application already running? If yes then exit.
thisapp = singleton.singleinstance() thisapp = singleton.singleinstance()
@ -749,9 +917,9 @@ if __name__ == "__main__":
pass pass
# And finally launch asyncore # And finally launch asyncore
asyncoreThread = asyncoreThread() asyncoreThreadInstance = asyncoreThread()
asyncoreThread.daemon = True asyncoreThreadInstance.daemon = True
asyncoreThread.start() asyncoreThreadInstance.start()
shared.reloadMyAddressHashes() shared.reloadMyAddressHashes()
shared.reloadBroadcastSendersForWhichImWatching() shared.reloadBroadcastSendersForWhichImWatching()
@ -778,7 +946,7 @@ if __name__ == "__main__":
singleListenerThread.daemon = True # close the main program even if there are threads left singleListenerThread.daemon = True # close the main program even if there are threads left
singleListenerThread.start() singleListenerThread.start()
if not shared.safeConfigGetBoolean('bitmessagesettings', 'daemon'): if deamon == False and shared.safeConfigGetBoolean('bitmessagesettings', 'daemon') == False:
try: try:
from PyQt4 import QtCore, QtGui from PyQt4 import QtCore, QtGui
except Exception as err: except Exception as err:
@ -790,12 +958,35 @@ if __name__ == "__main__":
bitmessageqt.run() bitmessageqt.run()
else: else:
shared.config.remove_option('bitmessagesettings', 'dontconnect') shared.config.remove_option('bitmessagesettings', 'dontconnect')
if deamon:
with shared.printLock:
print 'Running as a daemon. The main program should exit this thread.'
else:
with shared.printLock: with shared.printLock:
print 'Running as a daemon. You can use Ctrl+C to exit.' print 'Running as a daemon. You can use Ctrl+C to exit.'
while True: while True:
time.sleep(20) 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 # So far, the creation of and management of the Bitmessage protocol and this
# client is a one-man operation. Bitcoin tips are quite appreciated. # client is a one-man operation. Bitcoin tips are quite appreciated.
# 1H5XaDA6fYENLbknwZyjiYXYPQaFjjLX2u # 1H5XaDA6fYENLbknwZyjiYXYPQaFjjLX2u

View File

@ -34,7 +34,7 @@ import platform
import debug import debug
from debug import logger from debug import logger
import subprocess import subprocess
import datetime
try: try:
from PyQt4 import QtCore, QtGui from PyQt4 import QtCore, QtGui
@ -65,6 +65,12 @@ class MyForm(QtGui.QMainWindow):
SOUND_DISCONNECTED = 4 SOUND_DISCONNECTED = 4
SOUND_CONNECTION_GREEN = 5 SOUND_CONNECTION_GREEN = 5
# the last time that a message arrival sound was played
lastSoundTime = datetime.datetime.now() - datetime.timedelta(days=1)
# the maximum frequency of message sounds in seconds
maxSoundFrequencySec = 60
str_broadcast_subscribers = '[Broadcast subscribers]' str_broadcast_subscribers = '[Broadcast subscribers]'
str_chan = '[chan]' str_chan = '[chan]'
@ -429,7 +435,6 @@ class MyForm(QtGui.QMainWindow):
self.rerenderComboBoxSendFrom() self.rerenderComboBoxSendFrom()
# Show or hide the application window after clicking an item within the # Show or hide the application window after clicking an item within the
# tray icon or, on Windows, the try icon itself. # tray icon or, on Windows, the try icon itself.
def appIndicatorShowOrHideWindow(self): def appIndicatorShowOrHideWindow(self):
@ -982,29 +987,63 @@ class MyForm(QtGui.QMainWindow):
# update the menu entries # update the menu entries
self.ubuntuMessagingMenuUnread(drawAttention) self.ubuntuMessagingMenuUnread(drawAttention)
# returns true if the given sound category is a connection sound
# rather than a received message sound
def isConnectionSound(self, category):
if (category is self.SOUND_CONNECTED or
category is self.SOUND_DISCONNECTED or
category is self.SOUND_CONNECTION_GREEN):
return True
return False
# play a sound # play a sound
def playSound(self, category, label): def playSound(self, category, label):
# filename of the sound to be played
soundFilename = None soundFilename = None
# whether to play a sound or not
play = True
# if the address had a known label in the address book
if label is not None: if label is not None:
# does a sound file exist for this particular contact? # Does a sound file exist for this particular contact?
if (os.path.isfile(shared.appdata + 'sounds/' + label + '.wav') or if (os.path.isfile(shared.appdata + 'sounds/' + label + '.wav') or
os.path.isfile(shared.appdata + 'sounds/' + label + '.mp3')): os.path.isfile(shared.appdata + 'sounds/' + label + '.mp3')):
soundFilename = shared.appdata + 'sounds/' + label soundFilename = shared.appdata + 'sounds/' + label
# Avoid making sounds more frequently than the threshold.
# This suppresses playing sounds repeatedly when there
# are many new messages
if (soundFilename is None and
not self.isConnectionSound(category)):
# elapsed time since the last sound was played
dt = datetime.datetime.now() - self.lastSoundTime
# suppress sounds which are more frequent than the threshold
if dt.total_seconds() < self.maxSoundFrequencySec:
play = False
if soundFilename is None: if soundFilename is None:
# the sound is for an address which exists in the address book
if category is self.SOUND_KNOWN: if category is self.SOUND_KNOWN:
soundFilename = shared.appdata + 'sounds/known' soundFilename = shared.appdata + 'sounds/known'
# the sound is for an unknown address
elif category is self.SOUND_UNKNOWN: elif category is self.SOUND_UNKNOWN:
soundFilename = shared.appdata + 'sounds/unknown' soundFilename = shared.appdata + 'sounds/unknown'
# initial connection sound
elif category is self.SOUND_CONNECTED: elif category is self.SOUND_CONNECTED:
soundFilename = shared.appdata + 'sounds/connected' soundFilename = shared.appdata + 'sounds/connected'
# disconnected sound
elif category is self.SOUND_DISCONNECTED: elif category is self.SOUND_DISCONNECTED:
soundFilename = shared.appdata + 'sounds/disconnected' soundFilename = shared.appdata + 'sounds/disconnected'
# sound when the connection status becomes green
elif category is self.SOUND_CONNECTION_GREEN: elif category is self.SOUND_CONNECTION_GREEN:
soundFilename = shared.appdata + 'sounds/green' soundFilename = shared.appdata + 'sounds/green'
if soundFilename is not None: if soundFilename is not None and play is True:
if not self.isConnectionSound(category):
# record the last time that a received message sound was played
self.lastSoundTime = datetime.datetime.now()
# if not wav then try mp3 format # if not wav then try mp3 format
if not os.path.isfile(soundFilename + '.wav'): if not os.path.isfile(soundFilename + '.wav'):
soundFilename = soundFilename + '.mp3' soundFilename = soundFilename + '.mp3'
@ -2008,6 +2047,8 @@ class MyForm(QtGui.QMainWindow):
else: else:
shared.config.set('bitmessagesettings', 'keyfile', str( shared.config.set('bitmessagesettings', 'keyfile', str(
self.settingsDialogInstance.sslKeyFile)) self.settingsDialogInstance.sslKeyFile))
shared.config.set('bitmessagesettings', 'willinglysendtomobile', str(
self.settingsDialogInstance.ui.checkBoxWillinglySendToMobile.isChecked()))
if int(shared.config.get('bitmessagesettings', 'port')) != int(self.settingsDialogInstance.ui.lineEditTCPPort.text()): if int(shared.config.get('bitmessagesettings', 'port')) != int(self.settingsDialogInstance.ui.lineEditTCPPort.text()):
if not shared.safeConfigGetBoolean('bitmessagesettings', 'dontconnect'): if not shared.safeConfigGetBoolean('bitmessagesettings', 'dontconnect'):
QMessageBox.about(self, _translate("MainWindow", "Restart"), _translate( QMessageBox.about(self, _translate("MainWindow", "Restart"), _translate(
@ -2838,6 +2879,11 @@ class MyForm(QtGui.QMainWindow):
def tableWidgetInboxItemClicked(self): def tableWidgetInboxItemClicked(self):
currentRow = self.ui.tableWidgetInbox.currentRow() currentRow = self.ui.tableWidgetInbox.currentRow()
if currentRow >= 0: if currentRow >= 0:
font = QFont()
font.setBold(False)
self.ui.textEditInboxMessage.setCurrentFont(font)
fromAddress = str(self.ui.tableWidgetInbox.item( fromAddress = str(self.ui.tableWidgetInbox.item(
currentRow, 1).data(Qt.UserRole).toPyObject()) currentRow, 1).data(Qt.UserRole).toPyObject())
# If we have received this message from either a broadcast address # If we have received this message from either a broadcast address
@ -2857,8 +2903,6 @@ class MyForm(QtGui.QMainWindow):
self.ui.textEditInboxMessage.setPlainText(self.ui.tableWidgetInbox.item(currentRow, 2).data(Qt.UserRole).toPyObject()[ self.ui.textEditInboxMessage.setPlainText(self.ui.tableWidgetInbox.item(currentRow, 2).data(Qt.UserRole).toPyObject()[
:30000] + '\n\nDisplay of the remainder of the message truncated because it is too long.') # Only show the first 30K characters :30000] + '\n\nDisplay of the remainder of the message truncated because it is too long.') # Only show the first 30K characters
font = QFont()
font.setBold(False)
self.ui.tableWidgetInbox.item(currentRow, 0).setFont(font) self.ui.tableWidgetInbox.item(currentRow, 0).setFont(font)
self.ui.tableWidgetInbox.item(currentRow, 1).setFont(font) self.ui.tableWidgetInbox.item(currentRow, 1).setFont(font)
self.ui.tableWidgetInbox.item(currentRow, 2).setFont(font) self.ui.tableWidgetInbox.item(currentRow, 2).setFont(font)
@ -3021,7 +3065,8 @@ class settingsDialog(QtGui.QDialog):
except: except:
self.ui.checkBoxStripMessageHeaders.setChecked(True) self.ui.checkBoxStripMessageHeaders.setChecked(True)
self.ui.lineEditMessageHeadersToStrip.setText('User-Agent') self.ui.lineEditMessageHeadersToStrip.setText('User-Agent')
self.ui.checkBoxWillinglySendToMobile.setChecked(
shared.safeConfigGetBoolean('bitmessagesettings', 'willinglysendtomobile'))
if shared.appdata == '': if shared.appdata == '':
self.ui.checkBoxPortableMode.setChecked(True) self.ui.checkBoxPortableMode.setChecked(True)
if 'darwin' in sys.platform: if 'darwin' in sys.platform:
@ -3506,7 +3551,8 @@ def run():
translator = QtCore.QTranslator() translator = QtCore.QTranslator()
try: try:
translator.load("translations/bitmessage_" + str(locale.getlocale()[0])) translator.load("translations/bitmessage_" + str(locale.getdefaultlocale()[0]))
#translator.load("translations/bitmessage_fr_BE") # test French
except: except:
# The above is not compatible with all versions of OSX. # The above is not compatible with all versions of OSX.
translator.load("translations/bitmessage_en_US") # Default to english. translator.load("translations/bitmessage_en_US") # Default to english.

View File

@ -2,7 +2,7 @@
# Form implementation generated from reading ui file 'bitmessageui.ui' # Form implementation generated from reading ui file 'bitmessageui.ui'
# #
# Created: Mon Jul 29 14:54:01 2013 # Created: Wed Aug 14 13:43:40 2013
# by: PyQt4 UI code generator 4.10.1 # by: PyQt4 UI code generator 4.10.1
# #
# WARNING! All changes made in this file will be lost! # WARNING! All changes made in this file will be lost!
@ -26,7 +26,7 @@ except AttributeError:
class Ui_MainWindow(object): class Ui_MainWindow(object):
def setupUi(self, MainWindow): def setupUi(self, MainWindow):
MainWindow.setObjectName(_fromUtf8("MainWindow")) MainWindow.setObjectName(_fromUtf8("MainWindow"))
MainWindow.resize(795, 561) MainWindow.resize(795, 580)
icon = QtGui.QIcon() icon = QtGui.QIcon()
icon.addPixmap(QtGui.QPixmap(_fromUtf8(":/newPrefix/images/can-icon-24px.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off) icon.addPixmap(QtGui.QPixmap(_fromUtf8(":/newPrefix/images/can-icon-24px.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off)
MainWindow.setWindowIcon(icon) MainWindow.setWindowIcon(icon)
@ -424,7 +424,7 @@ class Ui_MainWindow(object):
self.gridLayout.addWidget(self.tabWidget, 0, 0, 1, 1) self.gridLayout.addWidget(self.tabWidget, 0, 0, 1, 1)
MainWindow.setCentralWidget(self.centralwidget) MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtGui.QMenuBar(MainWindow) self.menubar = QtGui.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 795, 18)) self.menubar.setGeometry(QtCore.QRect(0, 0, 795, 27))
self.menubar.setObjectName(_fromUtf8("menubar")) self.menubar.setObjectName(_fromUtf8("menubar"))
self.menuFile = QtGui.QMenu(self.menubar) self.menuFile = QtGui.QMenu(self.menubar)
self.menuFile.setObjectName(_fromUtf8("menuFile")) self.menuFile.setObjectName(_fromUtf8("menuFile"))
@ -442,20 +442,36 @@ class Ui_MainWindow(object):
self.actionManageKeys = QtGui.QAction(MainWindow) self.actionManageKeys = QtGui.QAction(MainWindow)
self.actionManageKeys.setCheckable(False) self.actionManageKeys.setCheckable(False)
self.actionManageKeys.setEnabled(True) self.actionManageKeys.setEnabled(True)
icon = QtGui.QIcon.fromTheme(_fromUtf8("dialog-password"))
self.actionManageKeys.setIcon(icon)
self.actionManageKeys.setObjectName(_fromUtf8("actionManageKeys")) self.actionManageKeys.setObjectName(_fromUtf8("actionManageKeys"))
self.actionExit = QtGui.QAction(MainWindow) self.actionExit = QtGui.QAction(MainWindow)
icon = QtGui.QIcon.fromTheme(_fromUtf8("application-exit"))
self.actionExit.setIcon(icon)
self.actionExit.setObjectName(_fromUtf8("actionExit")) self.actionExit.setObjectName(_fromUtf8("actionExit"))
self.actionHelp = QtGui.QAction(MainWindow) self.actionHelp = QtGui.QAction(MainWindow)
icon = QtGui.QIcon.fromTheme(_fromUtf8("help-contents"))
self.actionHelp.setIcon(icon)
self.actionHelp.setObjectName(_fromUtf8("actionHelp")) self.actionHelp.setObjectName(_fromUtf8("actionHelp"))
self.actionAbout = QtGui.QAction(MainWindow) self.actionAbout = QtGui.QAction(MainWindow)
icon = QtGui.QIcon.fromTheme(_fromUtf8("help-about"))
self.actionAbout.setIcon(icon)
self.actionAbout.setObjectName(_fromUtf8("actionAbout")) self.actionAbout.setObjectName(_fromUtf8("actionAbout"))
self.actionSettings = QtGui.QAction(MainWindow) self.actionSettings = QtGui.QAction(MainWindow)
icon = QtGui.QIcon.fromTheme(_fromUtf8("document-properties"))
self.actionSettings.setIcon(icon)
self.actionSettings.setObjectName(_fromUtf8("actionSettings")) self.actionSettings.setObjectName(_fromUtf8("actionSettings"))
self.actionRegenerateDeterministicAddresses = QtGui.QAction(MainWindow) self.actionRegenerateDeterministicAddresses = QtGui.QAction(MainWindow)
icon = QtGui.QIcon.fromTheme(_fromUtf8("view-refresh"))
self.actionRegenerateDeterministicAddresses.setIcon(icon)
self.actionRegenerateDeterministicAddresses.setObjectName(_fromUtf8("actionRegenerateDeterministicAddresses")) self.actionRegenerateDeterministicAddresses.setObjectName(_fromUtf8("actionRegenerateDeterministicAddresses"))
self.actionDeleteAllTrashedMessages = QtGui.QAction(MainWindow) self.actionDeleteAllTrashedMessages = QtGui.QAction(MainWindow)
icon = QtGui.QIcon.fromTheme(_fromUtf8("user-trash"))
self.actionDeleteAllTrashedMessages.setIcon(icon)
self.actionDeleteAllTrashedMessages.setObjectName(_fromUtf8("actionDeleteAllTrashedMessages")) self.actionDeleteAllTrashedMessages.setObjectName(_fromUtf8("actionDeleteAllTrashedMessages"))
self.actionJoinChan = QtGui.QAction(MainWindow) self.actionJoinChan = QtGui.QAction(MainWindow)
icon = QtGui.QIcon.fromTheme(_fromUtf8("contact-new"))
self.actionJoinChan.setIcon(icon)
self.actionJoinChan.setObjectName(_fromUtf8("actionJoinChan")) self.actionJoinChan.setObjectName(_fromUtf8("actionJoinChan"))
self.menuFile.addAction(self.actionManageKeys) self.menuFile.addAction(self.actionManageKeys)
self.menuFile.addAction(self.actionDeleteAllTrashedMessages) self.menuFile.addAction(self.actionDeleteAllTrashedMessages)
@ -525,8 +541,8 @@ class Ui_MainWindow(object):
self.textEditMessage.setHtml(_translate("MainWindow", "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" \"http://www.w3.org/TR/REC-html40/strict.dtd\">\n" self.textEditMessage.setHtml(_translate("MainWindow", "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" \"http://www.w3.org/TR/REC-html40/strict.dtd\">\n"
"<html><head><meta name=\"qrichtext\" content=\"1\" /><style type=\"text/css\">\n" "<html><head><meta name=\"qrichtext\" content=\"1\" /><style type=\"text/css\">\n"
"p, li { white-space: pre-wrap; }\n" "p, li { white-space: pre-wrap; }\n"
"</style></head><body style=\" font-family:\'MS Shell Dlg 2\'; font-size:9pt; font-weight:400; font-style:normal;\">\n" "</style></head><body style=\" font-family:\'Droid Sans\'; font-size:9pt; font-weight:400; font-style:normal;\">\n"
"<p style=\"-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><br /></p></body></html>", None)) "<p style=\"-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:\'MS Shell Dlg 2\';\"><br /></p></body></html>", None))
self.label.setText(_translate("MainWindow", "To:", None)) self.label.setText(_translate("MainWindow", "To:", None))
self.label_2.setText(_translate("MainWindow", "From:", None)) self.label_2.setText(_translate("MainWindow", "From:", None))
self.radioButtonBroadcast.setText(_translate("MainWindow", "Broadcast to everyone who is subscribed to your address", None)) self.radioButtonBroadcast.setText(_translate("MainWindow", "Broadcast to everyone who is subscribed to your address", None))
@ -601,7 +617,9 @@ class Ui_MainWindow(object):
self.actionImport_keys.setText(_translate("MainWindow", "Import keys", None)) self.actionImport_keys.setText(_translate("MainWindow", "Import keys", None))
self.actionManageKeys.setText(_translate("MainWindow", "Manage keys", None)) self.actionManageKeys.setText(_translate("MainWindow", "Manage keys", None))
self.actionExit.setText(_translate("MainWindow", "Quit", None)) self.actionExit.setText(_translate("MainWindow", "Quit", None))
self.actionExit.setShortcut(_translate("MainWindow", "Ctrl+Q", None))
self.actionHelp.setText(_translate("MainWindow", "Help", None)) self.actionHelp.setText(_translate("MainWindow", "Help", None))
self.actionHelp.setShortcut(_translate("MainWindow", "F1", None))
self.actionAbout.setText(_translate("MainWindow", "About", None)) self.actionAbout.setText(_translate("MainWindow", "About", None))
self.actionSettings.setText(_translate("MainWindow", "Settings", None)) self.actionSettings.setText(_translate("MainWindow", "Settings", None))
self.actionRegenerateDeterministicAddresses.setText(_translate("MainWindow", "Regenerate deterministic addresses", None)) self.actionRegenerateDeterministicAddresses.setText(_translate("MainWindow", "Regenerate deterministic addresses", None))

View File

@ -7,7 +7,7 @@
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>795</width> <width>795</width>
<height>561</height> <height>580</height>
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
@ -257,8 +257,8 @@
<string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt; <string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt; &lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; } p, li { white-space: pre-wrap; }
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'MS Shell Dlg 2'; font-size:9pt; font-weight:400; font-style:normal;&quot;&gt; &lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Droid Sans'; font-size:9pt; font-weight:400; font-style:normal;&quot;&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string> &lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2';&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property> </property>
</widget> </widget>
</item> </item>
@ -1016,7 +1016,7 @@ p, li { white-space: pre-wrap; }
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>795</width> <width>795</width>
<height>18</height> <height>27</height>
</rect> </rect>
</property> </property>
<widget class="QMenu" name="menuFile"> <widget class="QMenu" name="menuFile">
@ -1066,41 +1066,87 @@ p, li { white-space: pre-wrap; }
<property name="enabled"> <property name="enabled">
<bool>true</bool> <bool>true</bool>
</property> </property>
<property name="icon">
<iconset theme="dialog-password">
<normaloff/>
</iconset>
</property>
<property name="text"> <property name="text">
<string>Manage keys</string> <string>Manage keys</string>
</property> </property>
</action> </action>
<action name="actionExit"> <action name="actionExit">
<property name="icon">
<iconset theme="application-exit">
<normaloff/>
</iconset>
</property>
<property name="text"> <property name="text">
<string>Quit</string> <string>Quit</string>
</property> </property>
<property name="shortcut">
<string>Ctrl+Q</string>
</property>
</action> </action>
<action name="actionHelp"> <action name="actionHelp">
<property name="icon">
<iconset theme="help-contents">
<normaloff/>
</iconset>
</property>
<property name="text"> <property name="text">
<string>Help</string> <string>Help</string>
</property> </property>
<property name="shortcut">
<string>F1</string>
</property>
</action> </action>
<action name="actionAbout"> <action name="actionAbout">
<property name="icon">
<iconset theme="help-about">
<normaloff/>
</iconset>
</property>
<property name="text"> <property name="text">
<string>About</string> <string>About</string>
</property> </property>
</action> </action>
<action name="actionSettings"> <action name="actionSettings">
<property name="icon">
<iconset theme="document-properties">
<normaloff/>
</iconset>
</property>
<property name="text"> <property name="text">
<string>Settings</string> <string>Settings</string>
</property> </property>
</action> </action>
<action name="actionRegenerateDeterministicAddresses"> <action name="actionRegenerateDeterministicAddresses">
<property name="icon">
<iconset theme="view-refresh">
<normaloff/>
</iconset>
</property>
<property name="text"> <property name="text">
<string>Regenerate deterministic addresses</string> <string>Regenerate deterministic addresses</string>
</property> </property>
</action> </action>
<action name="actionDeleteAllTrashedMessages"> <action name="actionDeleteAllTrashedMessages">
<property name="icon">
<iconset theme="user-trash">
<normaloff/>
</iconset>
</property>
<property name="text"> <property name="text">
<string>Delete all trashed messages</string> <string>Delete all trashed messages</string>
</property> </property>
</action> </action>
<action name="actionJoinChan"> <action name="actionJoinChan">
<property name="icon">
<iconset theme="contact-new">
<normaloff/>
</iconset>
</property>
<property name="text"> <property name="text">
<string>Join / Create chan</string> <string>Join / Create chan</string>
</property> </property>

View File

@ -2,8 +2,8 @@
# Form implementation generated from reading ui file 'newchandialog.ui' # Form implementation generated from reading ui file 'newchandialog.ui'
# #
# Created: Mon Jul 22 01:05:35 2013 # Created: Wed Aug 7 16:51:29 2013
# by: PyQt4 UI code generator 4.10.2 # by: PyQt4 UI code generator 4.10
# #
# WARNING! All changes made in this file will be lost! # WARNING! All changes made in this file will be lost!
@ -26,7 +26,7 @@ except AttributeError:
class Ui_newChanDialog(object): class Ui_newChanDialog(object):
def setupUi(self, newChanDialog): def setupUi(self, newChanDialog):
newChanDialog.setObjectName(_fromUtf8("newChanDialog")) newChanDialog.setObjectName(_fromUtf8("newChanDialog"))
newChanDialog.resize(530, 422) newChanDialog.resize(553, 422)
newChanDialog.setMinimumSize(QtCore.QSize(0, 0)) newChanDialog.setMinimumSize(QtCore.QSize(0, 0))
self.formLayout = QtGui.QFormLayout(newChanDialog) self.formLayout = QtGui.QFormLayout(newChanDialog)
self.formLayout.setObjectName(_fromUtf8("formLayout")) self.formLayout.setObjectName(_fromUtf8("formLayout"))
@ -87,13 +87,18 @@ class Ui_newChanDialog(object):
QtCore.QObject.connect(self.radioButtonJoinChan, QtCore.SIGNAL(_fromUtf8("toggled(bool)")), self.groupBoxJoinChan.setShown) 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.QObject.connect(self.radioButtonCreateChan, QtCore.SIGNAL(_fromUtf8("toggled(bool)")), self.groupBoxCreateChan.setShown)
QtCore.QMetaObject.connectSlotsByName(newChanDialog) QtCore.QMetaObject.connectSlotsByName(newChanDialog)
newChanDialog.setTabOrder(self.radioButtonJoinChan, self.radioButtonCreateChan)
newChanDialog.setTabOrder(self.radioButtonCreateChan, self.lineEditChanNameCreate)
newChanDialog.setTabOrder(self.lineEditChanNameCreate, self.lineEditChanNameJoin)
newChanDialog.setTabOrder(self.lineEditChanNameJoin, self.lineEditChanBitmessageAddress)
newChanDialog.setTabOrder(self.lineEditChanBitmessageAddress, self.buttonBox)
def retranslateUi(self, newChanDialog): def retranslateUi(self, newChanDialog):
newChanDialog.setWindowTitle(_translate("newChanDialog", "Dialog", None)) newChanDialog.setWindowTitle(_translate("newChanDialog", "Dialog", None))
self.radioButtonCreateChan.setText(_translate("newChanDialog", "Create a new chan", None)) self.radioButtonCreateChan.setText(_translate("newChanDialog", "Create a new chan", None))
self.radioButtonJoinChan.setText(_translate("newChanDialog", "Join a chan", None)) self.radioButtonJoinChan.setText(_translate("newChanDialog", "Join a chan", None))
self.groupBoxCreateChan.setTitle(_translate("newChanDialog", "Create a chan", 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_4.setText(_translate("newChanDialog", "<html><head/><body><p>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. If you and someone else both create a chan with the same chan name then it is currently very likely that they will be the same chan.</p></body></html>", None))
self.label_5.setText(_translate("newChanDialog", "Chan name:", None)) self.label_5.setText(_translate("newChanDialog", "Chan name:", None))
self.groupBoxJoinChan.setTitle(_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 exists when a group of people share the same decryption keys. The keys and bitmessage address used by a chan are generated from a human-friendly word or phrase (the chan name). To send a message to everyone in the chan, send a normal person-to-person message to the chan address.</p><p>Chans are experimental and completely unmoderatable.</p></body></html>", None)) self.label.setText(_translate("newChanDialog", "<html><head/><body><p>A chan exists when a group of people share the same decryption keys. The keys and bitmessage address used by a chan are generated from a human-friendly word or phrase (the chan name). To send a message to everyone in the chan, send a normal person-to-person message to the chan address.</p><p>Chans are experimental and completely unmoderatable.</p></body></html>", None))

View File

@ -6,7 +6,7 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>530</width> <width>553</width>
<height>422</height> <height>422</height>
</rect> </rect>
</property> </property>
@ -46,7 +46,7 @@
<item row="0" column="0"> <item row="0" column="0">
<widget class="QLabel" name="label_4"> <widget class="QLabel" name="label_4">
<property name="text"> <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> <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;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. If you and someone else both create a chan with the same chan name then it is currently very likely that they will be the same chan.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property> </property>
<property name="wordWrap"> <property name="wordWrap">
<bool>true</bool> <bool>true</bool>
@ -130,6 +130,14 @@
</item> </item>
</layout> </layout>
</widget> </widget>
<tabstops>
<tabstop>radioButtonJoinChan</tabstop>
<tabstop>radioButtonCreateChan</tabstop>
<tabstop>lineEditChanNameCreate</tabstop>
<tabstop>lineEditChanNameJoin</tabstop>
<tabstop>lineEditChanBitmessageAddress</tabstop>
<tabstop>buttonBox</tabstop>
</tabstops>
<resources/> <resources/>
<connections> <connections>
<connection> <connection>

View File

@ -2,7 +2,7 @@
# Form implementation generated from reading ui file 'settings.ui' # Form implementation generated from reading ui file 'settings.ui'
# #
# Created: Mon Jul 29 14:53:58 2013 # Created: Wed Aug 14 13:44:07 2013
# by: PyQt4 UI code generator 4.10.1 # by: PyQt4 UI code generator 4.10.1
# #
# WARNING! All changes made in this file will be lost! # WARNING! All changes made in this file will be lost!
@ -41,33 +41,36 @@ class Ui_settingsDialog(object):
self.tabUserInterface.setObjectName(_fromUtf8("tabUserInterface")) self.tabUserInterface.setObjectName(_fromUtf8("tabUserInterface"))
self.gridLayout_5 = QtGui.QGridLayout(self.tabUserInterface) self.gridLayout_5 = QtGui.QGridLayout(self.tabUserInterface)
self.gridLayout_5.setObjectName(_fromUtf8("gridLayout_5")) self.gridLayout_5.setObjectName(_fromUtf8("gridLayout_5"))
self.checkBoxStartOnLogon = QtGui.QCheckBox(self.tabUserInterface)
self.checkBoxStartOnLogon.setObjectName(_fromUtf8("checkBoxStartOnLogon"))
self.gridLayout_5.addWidget(self.checkBoxStartOnLogon, 0, 0, 1, 1)
self.checkBoxStartInTray = QtGui.QCheckBox(self.tabUserInterface)
self.checkBoxStartInTray.setObjectName(_fromUtf8("checkBoxStartInTray"))
self.gridLayout_5.addWidget(self.checkBoxStartInTray, 1, 0, 1, 1)
self.checkBoxMinimizeToTray = QtGui.QCheckBox(self.tabUserInterface)
self.checkBoxMinimizeToTray.setChecked(True)
self.checkBoxMinimizeToTray.setObjectName(_fromUtf8("checkBoxMinimizeToTray"))
self.gridLayout_5.addWidget(self.checkBoxMinimizeToTray, 2, 0, 1, 1)
self.checkBoxShowTrayNotifications = QtGui.QCheckBox(self.tabUserInterface)
self.checkBoxShowTrayNotifications.setObjectName(_fromUtf8("checkBoxShowTrayNotifications"))
self.gridLayout_5.addWidget(self.checkBoxShowTrayNotifications, 3, 0, 1, 1)
self.checkBoxPortableMode = QtGui.QCheckBox(self.tabUserInterface)
self.checkBoxPortableMode.setObjectName(_fromUtf8("checkBoxPortableMode"))
self.gridLayout_5.addWidget(self.checkBoxPortableMode, 4, 0, 1, 1)
self.label_7 = QtGui.QLabel(self.tabUserInterface)
self.label_7.setWordWrap(True)
self.label_7.setObjectName(_fromUtf8("label_7"))
self.gridLayout_5.addWidget(self.label_7, 5, 0, 1, 1)
self.labelSettingsNote = QtGui.QLabel(self.tabUserInterface) self.labelSettingsNote = QtGui.QLabel(self.tabUserInterface)
self.labelSettingsNote.setText(_fromUtf8("")) self.labelSettingsNote.setText(_fromUtf8(""))
self.labelSettingsNote.setWordWrap(True) self.labelSettingsNote.setWordWrap(True)
self.labelSettingsNote.setObjectName(_fromUtf8("labelSettingsNote")) self.labelSettingsNote.setObjectName(_fromUtf8("labelSettingsNote"))
self.gridLayout_5.addWidget(self.labelSettingsNote, 6, 0, 1, 1) self.gridLayout_5.addWidget(self.labelSettingsNote, 7, 0, 1, 1)
spacerItem = QtGui.QSpacerItem(20, 40, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding) spacerItem = QtGui.QSpacerItem(20, 40, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding)
self.gridLayout_5.addItem(spacerItem, 7, 0, 1, 1) self.gridLayout_5.addItem(spacerItem, 8, 0, 1, 1)
self.checkBoxStartInTray = QtGui.QCheckBox(self.tabUserInterface)
self.checkBoxStartInTray.setObjectName(_fromUtf8("checkBoxStartInTray"))
self.gridLayout_5.addWidget(self.checkBoxStartInTray, 1, 0, 1, 1)
self.checkBoxShowTrayNotifications = QtGui.QCheckBox(self.tabUserInterface)
self.checkBoxShowTrayNotifications.setObjectName(_fromUtf8("checkBoxShowTrayNotifications"))
self.gridLayout_5.addWidget(self.checkBoxShowTrayNotifications, 3, 0, 1, 1)
self.checkBoxMinimizeToTray = QtGui.QCheckBox(self.tabUserInterface)
self.checkBoxMinimizeToTray.setChecked(True)
self.checkBoxMinimizeToTray.setObjectName(_fromUtf8("checkBoxMinimizeToTray"))
self.gridLayout_5.addWidget(self.checkBoxMinimizeToTray, 2, 0, 1, 1)
self.label_7 = QtGui.QLabel(self.tabUserInterface)
self.label_7.setWordWrap(True)
self.label_7.setObjectName(_fromUtf8("label_7"))
self.gridLayout_5.addWidget(self.label_7, 5, 0, 1, 1)
self.checkBoxStartOnLogon = QtGui.QCheckBox(self.tabUserInterface)
self.checkBoxStartOnLogon.setObjectName(_fromUtf8("checkBoxStartOnLogon"))
self.gridLayout_5.addWidget(self.checkBoxStartOnLogon, 0, 0, 1, 1)
self.checkBoxPortableMode = QtGui.QCheckBox(self.tabUserInterface)
self.checkBoxPortableMode.setObjectName(_fromUtf8("checkBoxPortableMode"))
self.gridLayout_5.addWidget(self.checkBoxPortableMode, 4, 0, 1, 1)
self.checkBoxWillinglySendToMobile = QtGui.QCheckBox(self.tabUserInterface)
self.checkBoxWillinglySendToMobile.setObjectName(_fromUtf8("checkBoxWillinglySendToMobile"))
self.gridLayout_5.addWidget(self.checkBoxWillinglySendToMobile, 6, 0, 1, 1)
self.tabWidgetSettings.addTab(self.tabUserInterface, _fromUtf8("")) self.tabWidgetSettings.addTab(self.tabUserInterface, _fromUtf8(""))
self.tabNetworkSettings = QtGui.QWidget() self.tabNetworkSettings = QtGui.QWidget()
self.tabNetworkSettings.setObjectName(_fromUtf8("tabNetworkSettings")) self.tabNetworkSettings.setObjectName(_fromUtf8("tabNetworkSettings"))
@ -396,12 +399,13 @@ class Ui_settingsDialog(object):
def retranslateUi(self, settingsDialog): def retranslateUi(self, settingsDialog):
settingsDialog.setWindowTitle(_translate("settingsDialog", "Settings", None)) settingsDialog.setWindowTitle(_translate("settingsDialog", "Settings", None))
self.checkBoxStartOnLogon.setText(_translate("settingsDialog", "Start Bitmessage on user login", None))
self.checkBoxStartInTray.setText(_translate("settingsDialog", "Start Bitmessage in the tray (don\'t show main window)", None)) self.checkBoxStartInTray.setText(_translate("settingsDialog", "Start Bitmessage in the tray (don\'t show main window)", None))
self.checkBoxMinimizeToTray.setText(_translate("settingsDialog", "Minimize to tray", None))
self.checkBoxShowTrayNotifications.setText(_translate("settingsDialog", "Show notification when message received", None)) self.checkBoxShowTrayNotifications.setText(_translate("settingsDialog", "Show notification when message received", None))
self.checkBoxPortableMode.setText(_translate("settingsDialog", "Run in Portable Mode", None)) self.checkBoxMinimizeToTray.setText(_translate("settingsDialog", "Minimize to tray", None))
self.label_7.setText(_translate("settingsDialog", "In Portable Mode, messages and config files are stored in the same directory as the program rather than the normal application-data folder. This makes it convenient to run Bitmessage from a USB thumb drive.", None)) self.label_7.setText(_translate("settingsDialog", "In Portable Mode, messages and config files are stored in the same directory as the program rather than the normal application-data folder. This makes it convenient to run Bitmessage from a USB thumb drive.", None))
self.checkBoxStartOnLogon.setText(_translate("settingsDialog", "Start Bitmessage on user login", None))
self.checkBoxPortableMode.setText(_translate("settingsDialog", "Run in Portable Mode", None))
self.checkBoxWillinglySendToMobile.setText(_translate("settingsDialog", "Willingly include unencrypted destination address when sending to a mobile device", None))
self.tabWidgetSettings.setTabText(self.tabWidgetSettings.indexOf(self.tabUserInterface), _translate("settingsDialog", "User Interface", None)) self.tabWidgetSettings.setTabText(self.tabWidgetSettings.indexOf(self.tabUserInterface), _translate("settingsDialog", "User Interface", None))
self.groupBox.setTitle(_translate("settingsDialog", "Listening port", None)) self.groupBox.setTitle(_translate("settingsDialog", "Listening port", None))
self.label.setText(_translate("settingsDialog", "Listen for connections on port:", None)) self.label.setText(_translate("settingsDialog", "Listen for connections on port:", None))

View File

@ -37,13 +37,29 @@
<string>User Interface</string> <string>User Interface</string>
</attribute> </attribute>
<layout class="QGridLayout" name="gridLayout_5"> <layout class="QGridLayout" name="gridLayout_5">
<item row="0" column="0"> <item row="7" column="0">
<widget class="QCheckBox" name="checkBoxStartOnLogon"> <widget class="QLabel" name="labelSettingsNote">
<property name="text"> <property name="text">
<string>Start Bitmessage on user login</string> <string/>
</property>
<property name="wordWrap">
<bool>true</bool>
</property> </property>
</widget> </widget>
</item> </item>
<item row="8" column="0">
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="0"> <item row="1" column="0">
<widget class="QCheckBox" name="checkBoxStartInTray"> <widget class="QCheckBox" name="checkBoxStartInTray">
<property name="text"> <property name="text">
@ -51,6 +67,13 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="3" column="0">
<widget class="QCheckBox" name="checkBoxShowTrayNotifications">
<property name="text">
<string>Show notification when message received</string>
</property>
</widget>
</item>
<item row="2" column="0"> <item row="2" column="0">
<widget class="QCheckBox" name="checkBoxMinimizeToTray"> <widget class="QCheckBox" name="checkBoxMinimizeToTray">
<property name="text"> <property name="text">
@ -61,20 +84,6 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="3" column="0">
<widget class="QCheckBox" name="checkBoxShowTrayNotifications">
<property name="text">
<string>Show notification when message received</string>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QCheckBox" name="checkBoxPortableMode">
<property name="text">
<string>Run in Portable Mode</string>
</property>
</widget>
</item>
<item row="5" column="0"> <item row="5" column="0">
<widget class="QLabel" name="label_7"> <widget class="QLabel" name="label_7">
<property name="text"> <property name="text">
@ -85,28 +94,26 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="6" column="0"> <item row="0" column="0">
<widget class="QLabel" name="labelSettingsNote"> <widget class="QCheckBox" name="checkBoxStartOnLogon">
<property name="text"> <property name="text">
<string/> <string>Start Bitmessage on user login</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property> </property>
</widget> </widget>
</item> </item>
<item row="7" column="0"> <item row="4" column="0">
<spacer name="verticalSpacer_2"> <widget class="QCheckBox" name="checkBoxPortableMode">
<property name="orientation"> <property name="text">
<enum>Qt::Vertical</enum> <string>Run in Portable Mode</string>
</property> </property>
<property name="sizeHint" stdset="0"> </widget>
<size> </item>
<width>20</width> <item row="6" column="0">
<height>40</height> <widget class="QCheckBox" name="checkBoxWillinglySendToMobile">
</size> <property name="text">
<string>Willingly include unencrypted destination address when sending to a mobile device</string>
</property> </property>
</spacer> </widget>
</item> </item>
</layout> </layout>
</widget> </widget>

View File

@ -1,80 +1,16 @@
""" from setuptools import setup
py2app/py2exe build script for Bitmessage
Usage (Mac OS X):
python setup.py py2app
Usage (Windows):
python setup.py py2exe
"""
import sys, os, shutil, re
from setuptools import setup # @UnresolvedImport
name = "Bitmessage" name = "Bitmessage"
mainscript = 'bitmessagemain.py' version = "0.3.4"
version = "0.3.5" mainscript = ["bitmessagemain.py"]
if sys.platform == 'darwin':
extra_options = dict(
setup_requires=['py2app'],
app=[mainscript],
options=dict(py2app=dict(argv_emulation=True,
includes = ['PyQt4.QtCore','PyQt4.QtGui', 'sip', 'sqlite3'],
packages = ['bitmessageqt'],
frameworks = ['/usr/local/opt/openssl/lib/libcrypto.dylib'],
iconfile='images/bitmessage.icns',
resources=["images"])),
)
elif sys.platform == 'win32':
extra_options = dict(
setup_requires=['py2exe'],
app=[mainscript],
)
else:
extra_options = dict(
# Normally unix-like platforms will use "setup.py install"
# and install the main script as such
scripts=[mainscript],
)
setup( setup(
name = name, name = name,
version = version, version = version,
**extra_options app = mainscript,
setup_requires = ["py2app"],
options = dict(py2app=dict(
resources = ["images"],
iconfile = "images/bitmessage.icns"
))
) )
from distutils import dir_util
import glob
if sys.platform == 'darwin':
resource = "dist/" + name + ".app/Contents/Resources/"
framework = "dist/" + name + ".app/Contents/Frameworks/"
# The pyElliptive module only works with hardcoded libcrypto paths so rename it so it can actually find it.
libs = glob.glob(framework + "libcrypto*.dylib")
for lib in libs:
os.rename(lib, framework + "libcrypto.dylib")
break
# Try to locate qt_menu
# Let's try the port version first!
if os.path.isfile("/opt/local/lib/Resources/qt_menu.nib"):
qt_menu_location = "/opt/local/lib/Resources/qt_menu.nib"
else:
# No dice? Then let's try the brew version
qt_menu_location = os.popen("find /usr/local/Cellar -name qt_menu.nib | tail -n 1").read()
qt_menu_location = re.sub('\n','', qt_menu_location)
if(len(qt_menu_location) == 0):
print "Sorry couldn't find your qt_menu.nib this probably won't work"
else:
print "Found your qib: " + qt_menu_location
# Need to include a copy of qt_menu.nib
shutil.copytree(qt_menu_location, resource + "qt_menu.nib")
# Need to touch qt.conf to avoid loading 2 sets of Qt libraries
fname = resource + "qt.conf"
with file(fname, 'a'):
os.utime(fname, None)

View File

@ -32,15 +32,15 @@ class outgoingSynSender(threading.Thread):
break break
random.seed() random.seed()
shared.knownNodesLock.acquire() shared.knownNodesLock.acquire()
HOST, = random.sample(shared.knownNodes[self.streamNumber], 1) peer, = random.sample(shared.knownNodes[self.streamNumber], 1)
shared.knownNodesLock.release() shared.knownNodesLock.release()
shared.alreadyAttemptedConnectionsListLock.acquire() shared.alreadyAttemptedConnectionsListLock.acquire()
while HOST in shared.alreadyAttemptedConnectionsList or HOST in shared.connectedHostsList: while peer in shared.alreadyAttemptedConnectionsList or peer.host in shared.connectedHostsList:
shared.alreadyAttemptedConnectionsListLock.release() shared.alreadyAttemptedConnectionsListLock.release()
# print 'choosing new sample' # print 'choosing new sample'
random.seed() random.seed()
shared.knownNodesLock.acquire() shared.knownNodesLock.acquire()
HOST, = random.sample(shared.knownNodes[self.streamNumber], 1) peer, = random.sample(shared.knownNodes[self.streamNumber], 1)
shared.knownNodesLock.release() shared.knownNodesLock.release()
time.sleep(1) time.sleep(1)
# Clear out the shared.alreadyAttemptedConnectionsList every half # Clear out the shared.alreadyAttemptedConnectionsList every half
@ -51,10 +51,10 @@ class outgoingSynSender(threading.Thread):
shared.alreadyAttemptedConnectionsListResetTime = int( shared.alreadyAttemptedConnectionsListResetTime = int(
time.time()) time.time())
shared.alreadyAttemptedConnectionsListLock.acquire() shared.alreadyAttemptedConnectionsListLock.acquire()
shared.alreadyAttemptedConnectionsList[HOST] = 0 shared.alreadyAttemptedConnectionsList[peer] = 0
shared.alreadyAttemptedConnectionsListLock.release() shared.alreadyAttemptedConnectionsListLock.release()
PORT, timeNodeLastSeen = shared.knownNodes[ timeNodeLastSeen = shared.knownNodes[
self.streamNumber][HOST] self.streamNumber][peer]
sock = socks.socksocket(socket.AF_INET, socket.SOCK_STREAM) sock = socks.socksocket(socket.AF_INET, socket.SOCK_STREAM)
# This option apparently avoids the TIME_WAIT state so that we # This option apparently avoids the TIME_WAIT state so that we
# can rebind faster # can rebind faster
@ -62,13 +62,13 @@ class outgoingSynSender(threading.Thread):
sock.settimeout(20) sock.settimeout(20)
if shared.config.get('bitmessagesettings', 'socksproxytype') == 'none' and shared.verbose >= 2: if shared.config.get('bitmessagesettings', 'socksproxytype') == 'none' and shared.verbose >= 2:
with shared.printLock: with shared.printLock:
print 'Trying an outgoing connection to', HOST, ':', PORT print 'Trying an outgoing connection to', peer
# sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
elif shared.config.get('bitmessagesettings', 'socksproxytype') == 'SOCKS4a': elif shared.config.get('bitmessagesettings', 'socksproxytype') == 'SOCKS4a':
if shared.verbose >= 2: if shared.verbose >= 2:
with shared.printLock: with shared.printLock:
print '(Using SOCKS4a) Trying an outgoing connection to', HOST, ':', PORT print '(Using SOCKS4a) Trying an outgoing connection to', peer
proxytype = socks.PROXY_TYPE_SOCKS4 proxytype = socks.PROXY_TYPE_SOCKS4
sockshostname = shared.config.get( sockshostname = shared.config.get(
@ -89,7 +89,7 @@ class outgoingSynSender(threading.Thread):
elif shared.config.get('bitmessagesettings', 'socksproxytype') == 'SOCKS5': elif shared.config.get('bitmessagesettings', 'socksproxytype') == 'SOCKS5':
if shared.verbose >= 2: if shared.verbose >= 2:
with shared.printLock: with shared.printLock:
print '(Using SOCKS5) Trying an outgoing connection to', HOST, ':', PORT print '(Using SOCKS5) Trying an outgoing connection to', peer
proxytype = socks.PROXY_TYPE_SOCKS5 proxytype = socks.PROXY_TYPE_SOCKS5
sockshostname = shared.config.get( sockshostname = shared.config.get(
@ -109,19 +109,19 @@ class outgoingSynSender(threading.Thread):
proxytype, sockshostname, socksport, rdns) proxytype, sockshostname, socksport, rdns)
try: try:
sock.connect((HOST, PORT)) sock.connect((peer.host, peer.port))
rd = receiveDataThread() rd = receiveDataThread()
rd.daemon = True # close the main program even if there are threads left rd.daemon = True # close the main program even if there are threads left
someObjectsOfWhichThisRemoteNodeIsAlreadyAware = {} # This is not necessairly a complete list; we clear it from time to time to save memory. someObjectsOfWhichThisRemoteNodeIsAlreadyAware = {} # This is not necessairly a complete list; we clear it from time to time to save memory.
rd.setup(sock, HOST, PORT, self.streamNumber, rd.setup(sock, peer.host, peer.port, self.streamNumber,
someObjectsOfWhichThisRemoteNodeIsAlreadyAware, self.selfInitiatedConnections) someObjectsOfWhichThisRemoteNodeIsAlreadyAware, self.selfInitiatedConnections)
rd.start() rd.start()
with shared.printLock: with shared.printLock:
print self, 'connected to', HOST, 'during an outgoing attempt.' print self, 'connected to', peer, 'during an outgoing attempt.'
sd = sendDataThread() sd = sendDataThread()
sd.setup(sock, HOST, PORT, self.streamNumber, sd.setup(sock, peer.host, peer.port, self.streamNumber,
someObjectsOfWhichThisRemoteNodeIsAlreadyAware) someObjectsOfWhichThisRemoteNodeIsAlreadyAware)
sd.start() sd.start()
sd.sendVersionMessage() sd.sendVersionMessage()
@ -129,16 +129,16 @@ class outgoingSynSender(threading.Thread):
except socks.GeneralProxyError as err: except socks.GeneralProxyError as err:
if shared.verbose >= 2: if shared.verbose >= 2:
with shared.printLock: with shared.printLock:
print 'Could NOT connect to', HOST, 'during outgoing attempt.', err print 'Could NOT connect to', peer, 'during outgoing attempt.', err
PORT, timeLastSeen = shared.knownNodes[ timeLastSeen = shared.knownNodes[
self.streamNumber][HOST] self.streamNumber][peer]
if (int(time.time()) - timeLastSeen) > 172800 and len(shared.knownNodes[self.streamNumber]) > 1000: # for nodes older than 48 hours old if we have more than 1000 hosts in our list, delete from the shared.knownNodes data-structure. if (int(time.time()) - timeLastSeen) > 172800 and len(shared.knownNodes[self.streamNumber]) > 1000: # for nodes older than 48 hours old if we have more than 1000 hosts in our list, delete from the shared.knownNodes data-structure.
shared.knownNodesLock.acquire() shared.knownNodesLock.acquire()
del shared.knownNodes[self.streamNumber][HOST] del shared.knownNodes[self.streamNumber][peer]
shared.knownNodesLock.release() shared.knownNodesLock.release()
with shared.printLock: with shared.printLock:
print 'deleting ', HOST, 'from shared.knownNodes because it is more than 48 hours old and we could not connect to it.' print 'deleting ', peer, 'from shared.knownNodes because it is more than 48 hours old and we could not connect to it.'
except socks.Socks5AuthError as err: except socks.Socks5AuthError as err:
shared.UISignalQueue.put(( shared.UISignalQueue.put((
@ -155,16 +155,16 @@ class outgoingSynSender(threading.Thread):
else: else:
if shared.verbose >= 1: if shared.verbose >= 1:
with shared.printLock: with shared.printLock:
print 'Could NOT connect to', HOST, 'during outgoing attempt.', err print 'Could NOT connect to', peer, 'during outgoing attempt.', err
PORT, timeLastSeen = shared.knownNodes[ timeLastSeen = shared.knownNodes[
self.streamNumber][HOST] self.streamNumber][peer]
if (int(time.time()) - timeLastSeen) > 172800 and len(shared.knownNodes[self.streamNumber]) > 1000: # for nodes older than 48 hours old if we have more than 1000 hosts in our list, delete from the knownNodes data-structure. if (int(time.time()) - timeLastSeen) > 172800 and len(shared.knownNodes[self.streamNumber]) > 1000: # for nodes older than 48 hours old if we have more than 1000 hosts in our list, delete from the knownNodes data-structure.
shared.knownNodesLock.acquire() shared.knownNodesLock.acquire()
del shared.knownNodes[self.streamNumber][HOST] del shared.knownNodes[self.streamNumber][peer]
shared.knownNodesLock.release() shared.knownNodesLock.release()
with shared.printLock: with shared.printLock:
print 'deleting ', HOST, 'from knownNodes because it is more than 48 hours old and we could not connect to it.' print 'deleting ', peer, 'from knownNodes because it is more than 48 hours old and we could not connect to it.'
except Exception as err: except Exception as err:
sys.stderr.write( sys.stderr.write(

View File

@ -212,6 +212,14 @@ class bitmessagePOP3Connection(asyncore.dispatcher):
def handleList(self, data): def handleList(self, data):
self.populateMessageIndex() self.populateMessageIndex()
if len(data):
index = int(data.decode('ascii')) - 1
assert index >= 0
if index < len(self.messages):
yield "+OK {} {}".format(index, self.messages[index]['size'])
else:
yield "-ERR no such message"
else:
yield "+OK {} messages ({} octets)".format(len(self.messages), self.storage_size) yield "+OK {} messages ({} octets)".format(len(self.messages), self.storage_size)
for i, msg in enumerate(self.messages): for i, msg in enumerate(self.messages):
yield "{} {}".format(i + 1, msg['size']) yield "{} {}".format(i + 1, msg['size'])

View File

@ -44,14 +44,13 @@ class receiveDataThread(threading.Thread):
someObjectsOfWhichThisRemoteNodeIsAlreadyAware, someObjectsOfWhichThisRemoteNodeIsAlreadyAware,
selfInitiatedConnections): selfInitiatedConnections):
self.sock = sock self.sock = sock
self.HOST = HOST self.peer = shared.Peer(HOST, port)
self.PORT = port
self.streamNumber = streamNumber self.streamNumber = streamNumber
self.payloadLength = 0 # This is the protocol payload length thus it doesn't include the 24 byte message header self.payloadLength = 0 # This is the protocol payload length thus it doesn't include the 24 byte message header
self.objectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHave = {} self.objectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHave = {}
self.selfInitiatedConnections = selfInitiatedConnections self.selfInitiatedConnections = selfInitiatedConnections
shared.connectedHostsList[ shared.connectedHostsList[
self.HOST] = 0 # The very fact that this receiveData thread exists shows that we are connected to the remote host. Let's add it to this list so that an outgoingSynSender thread doesn't try to connect to it. self.peer.host] = 0 # The very fact that this receiveData thread exists shows that we are connected to the remote host. Let's add it to this list so that an outgoingSynSender thread doesn't try to connect to it.
self.connectionIsOrWasFullyEstablished = False # set to true after the remote node and I accept each other's version messages. This is needed to allow the user interface to accurately reflect the current number of connections. self.connectionIsOrWasFullyEstablished = False # set to true after the remote node and I accept each other's version messages. This is needed to allow the user interface to accurately reflect the current number of connections.
if self.streamNumber == -1: # This was an incoming connection. Send out a version message if we accept the other node's version message. if self.streamNumber == -1: # This was an incoming connection. Send out a version message if we accept the other node's version message.
self.initiatedConnection = False self.initiatedConnection = False
@ -72,18 +71,18 @@ class receiveDataThread(threading.Thread):
self.data += self.sock.recv(4096) self.data += self.sock.recv(4096)
except socket.timeout: except socket.timeout:
with shared.printLock: with shared.printLock:
print 'Timeout occurred waiting for data from', self.HOST + '. Closing receiveData thread. (ID:', str(id(self)) + ')' print 'Timeout occurred waiting for data from', self.peer, '. Closing receiveData thread. (ID:', str(id(self)) + ')'
break break
except Exception as err: except Exception as err:
with shared.printLock: with shared.printLock:
print 'sock.recv error. Closing receiveData thread (HOST:', self.HOST, 'ID:', str(id(self)) + ').', err print 'sock.recv error. Closing receiveData thread (HOST:', self.peer, 'ID:', str(id(self)) + ').', err
break break
# print 'Received', repr(self.data) # print 'Received', repr(self.data)
if len(self.data) == dataLen: # If self.sock.recv returned no data: if len(self.data) == dataLen: # If self.sock.recv returned no data:
with shared.printLock: with shared.printLock:
print 'Connection to', self.HOST, 'closed. Closing receiveData thread. (ID:', str(id(self)) + ')' print 'Connection to', self.peer, 'closed. Closing receiveData thread. (ID:', str(id(self)) + ')'
break break
else: else:
self.processData() self.processData()
@ -95,16 +94,16 @@ class receiveDataThread(threading.Thread):
except: except:
pass pass
shared.broadcastToSendDataQueues((0, 'shutdown', self.HOST)) shared.broadcastToSendDataQueues((0, 'shutdown', self.peer))
try: try:
del shared.connectedHostsList[self.HOST] del shared.connectedHostsList[self.peer.host]
except Exception as err: except Exception as err:
with shared.printLock: with shared.printLock:
print 'Could not delete', self.HOST, 'from shared.connectedHostsList.', err print 'Could not delete', self.peer.host, 'from shared.connectedHostsList.', err
try: try:
del shared.numberOfObjectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHavePerPeer[ del shared.numberOfObjectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHavePerPeer[
self.HOST] self.peer]
except: except:
pass pass
shared.UISignalQueue.put(('updateNetworkStatusTab', 'no data')) shared.UISignalQueue.put(('updateNetworkStatusTab', 'no data'))
@ -139,13 +138,12 @@ class receiveDataThread(threading.Thread):
# that other peers can be made aware of its existance. # that other peers can be made aware of its existance.
if self.initiatedConnection and self.connectionIsOrWasFullyEstablished: # The remote port is only something we should share with others if it is the remote node's incoming port (rather than some random operating-system-assigned outgoing port). if self.initiatedConnection and self.connectionIsOrWasFullyEstablished: # The remote port is only something we should share with others if it is the remote node's incoming port (rather than some random operating-system-assigned outgoing port).
shared.knownNodesLock.acquire() shared.knownNodesLock.acquire()
shared.knownNodes[self.streamNumber][ shared.knownNodes[self.streamNumber][self.peer] = int(time.time())
self.HOST] = (self.PORT, int(time.time()))
shared.knownNodesLock.release() shared.knownNodesLock.release()
if self.payloadLength <= 180000000: # If the size of the message is greater than 180MB, ignore it. (I get memory errors when processing messages much larger than this though it is concievable that this value will have to be lowered if some systems are less tolarant of large messages.) if self.payloadLength <= 180000000: # If the size of the message is greater than 180MB, ignore it. (I get memory errors when processing messages much larger than this though it is concievable that this value will have to be lowered if some systems are less tolarant of large messages.)
remoteCommand = self.data[4:16] remoteCommand = self.data[4:16]
with shared.printLock: with shared.printLock:
print 'remoteCommand', repr(remoteCommand.replace('\x00', '')), ' from', self.HOST print 'remoteCommand', repr(remoteCommand.replace('\x00', '')), ' from', self.peer
if remoteCommand == 'version\x00\x00\x00\x00\x00': if remoteCommand == 'version\x00\x00\x00\x00\x00':
self.recversion(self.data[24:self.payloadLength + 24]) self.recversion(self.data[24:self.payloadLength + 24])
@ -198,28 +196,28 @@ class receiveDataThread(threading.Thread):
objectHash] # It is possible that the remote node doesn't respond with the object. In that case, we'll very likely get it from someone else anyway. objectHash] # It is possible that the remote node doesn't respond with the object. In that case, we'll very likely get it from someone else anyway.
if len(self.objectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHave) == 0: if len(self.objectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHave) == 0:
with shared.printLock: with shared.printLock:
print '(concerning', self.HOST + ')', 'number of objectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHave is now', len(self.objectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHave) print '(concerning', str(self.peer) + ')', 'number of objectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHave is now', len(self.objectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHave)
try: try:
del shared.numberOfObjectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHavePerPeer[ del shared.numberOfObjectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHavePerPeer[
self.HOST] # this data structure is maintained so that we can keep track of how many total objects, across all connections, are currently outstanding. If it goes too high it can indicate that we are under attack by multiple nodes working together. self.peer] # this data structure is maintained so that we can keep track of how many total objects, across all connections, are currently outstanding. If it goes too high it can indicate that we are under attack by multiple nodes working together.
except: except:
pass pass
break break
if len(self.objectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHave) == 0: if len(self.objectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHave) == 0:
with shared.printLock: with shared.printLock:
print '(concerning', self.HOST + ')', 'number of objectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHave is now', len(self.objectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHave) print '(concerning', str(self.peer) + ')', 'number of objectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHave is now', len(self.objectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHave)
try: try:
del shared.numberOfObjectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHavePerPeer[ del shared.numberOfObjectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHavePerPeer[
self.HOST] # this data structure is maintained so that we can keep track of how many total objects, across all connections, are currently outstanding. If it goes too high it can indicate that we are under attack by multiple nodes working together. self.peer] # this data structure is maintained so that we can keep track of how many total objects, across all connections, are currently outstanding. If it goes too high it can indicate that we are under attack by multiple nodes working together.
except: except:
pass pass
if len(self.objectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHave) > 0: if len(self.objectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHave) > 0:
with shared.printLock: with shared.printLock:
print '(concerning', self.HOST + ')', 'number of objectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHave is now', len(self.objectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHave) print '(concerning', str(self.peer) + ')', 'number of objectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHave is now', len(self.objectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHave)
shared.numberOfObjectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHavePerPeer[self.HOST] = len( shared.numberOfObjectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHavePerPeer[self.peer] = len(
self.objectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHave) # this data structure is maintained so that we can keep track of how many total objects, across all connections, are currently outstanding. If it goes too high it can indicate that we are under attack by multiple nodes working together. self.objectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHave) # this data structure is maintained so that we can keep track of how many total objects, across all connections, are currently outstanding. If it goes too high it can indicate that we are under attack by multiple nodes working together.
if len(self.ackDataThatWeHaveYetToSend) > 0: if len(self.ackDataThatWeHaveYetToSend) > 0:
self.data = self.ackDataThatWeHaveYetToSend.pop() self.data = self.ackDataThatWeHaveYetToSend.pop()
@ -264,22 +262,22 @@ class receiveDataThread(threading.Thread):
self.sock.settimeout( self.sock.settimeout(
600) # We'll send out a pong every 5 minutes to make sure the connection stays alive if there has been no other traffic to send lately. 600) # We'll send out a pong every 5 minutes to make sure the connection stays alive if there has been no other traffic to send lately.
shared.UISignalQueue.put(('updateNetworkStatusTab', 'no data')) shared.UISignalQueue.put(('updateNetworkStatusTab', 'no data'))
remoteNodeIncomingPort, remoteNodeSeenTime = shared.knownNodes[ remoteNodeSeenTime = shared.knownNodes[
self.streamNumber][self.HOST] self.streamNumber][self.peer]
with shared.printLock: with shared.printLock:
print 'Connection fully established with', self.HOST, remoteNodeIncomingPort print 'Connection fully established with', self.peer
print 'The size of the connectedHostsList is now', len(shared.connectedHostsList) print 'The size of the connectedHostsList is now', len(shared.connectedHostsList)
print 'The length of sendDataQueues is now:', len(shared.sendDataQueues) print 'The length of sendDataQueues is now:', len(shared.sendDataQueues)
print 'broadcasting addr from within connectionFullyEstablished function.' print 'broadcasting addr from within connectionFullyEstablished function.'
self.broadcastaddr([(int(time.time()), self.streamNumber, 1, self.HOST, self.broadcastaddr([(int(time.time()), self.streamNumber, 1, self.peer.host,
remoteNodeIncomingPort)]) # This lets all of our peers know about this new node. self.peer.port)]) # This lets all of our peers know about this new node.
self.sendaddr() # This is one large addr message to this one peer. self.sendaddr() # This is one large addr message to this one peer.
if not self.initiatedConnection and len(shared.connectedHostsList) > 200: if not self.initiatedConnection and len(shared.connectedHostsList) > 200:
with shared.printLock: with shared.printLock:
print 'We are connected to too many people. Closing connection.' print 'We are connected to too many people. Closing connection.'
shared.broadcastToSendDataQueues((0, 'shutdown', self.HOST)) shared.broadcastToSendDataQueues((0, 'shutdown', self.peer))
return return
self.sendBigInv() self.sendBigInv()
@ -1545,7 +1543,7 @@ class receiveDataThread(threading.Thread):
self.objectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHave[ self.objectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHave[
data[lengthOfVarint + (32 * i):32 + lengthOfVarint + (32 * i)]] = 0 data[lengthOfVarint + (32 * i):32 + lengthOfVarint + (32 * i)]] = 0
shared.numberOfObjectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHavePerPeer[ shared.numberOfObjectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHavePerPeer[
self.HOST] = len(self.objectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHave) self.peer] = len(self.objectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHave)
# Send a getdata message to our peer to request the object with the given # Send a getdata message to our peer to request the object with the given
# hash # hash
@ -1727,11 +1725,11 @@ class receiveDataThread(threading.Thread):
shared.knownNodesLock.acquire() shared.knownNodesLock.acquire()
shared.knownNodes[recaddrStream] = {} shared.knownNodes[recaddrStream] = {}
shared.knownNodesLock.release() shared.knownNodesLock.release()
if hostFromAddrMessage not in shared.knownNodes[recaddrStream]: peerFromAddrMessage = shared.Peer(hostFromAddrMessage, recaddrPort)
if peerFromAddrMessage not in shared.knownNodes[recaddrStream]:
if len(shared.knownNodes[recaddrStream]) < 20000 and timeSomeoneElseReceivedMessageFromThisNode > (int(time.time()) - 10800) and timeSomeoneElseReceivedMessageFromThisNode < (int(time.time()) + 10800): # If we have more than 20000 nodes in our list already then just forget about adding more. Also, make sure that the time that someone else received a message from this node is within three hours from now. if len(shared.knownNodes[recaddrStream]) < 20000 and timeSomeoneElseReceivedMessageFromThisNode > (int(time.time()) - 10800) and timeSomeoneElseReceivedMessageFromThisNode < (int(time.time()) + 10800): # If we have more than 20000 nodes in our list already then just forget about adding more. Also, make sure that the time that someone else received a message from this node is within three hours from now.
shared.knownNodesLock.acquire() shared.knownNodesLock.acquire()
shared.knownNodes[recaddrStream][hostFromAddrMessage] = ( shared.knownNodes[recaddrStream][peerFromAddrMessage] = timeSomeoneElseReceivedMessageFromThisNode
recaddrPort, timeSomeoneElseReceivedMessageFromThisNode)
shared.knownNodesLock.release() shared.knownNodesLock.release()
needToWriteKnownNodesToDisk = True needToWriteKnownNodesToDisk = True
hostDetails = ( hostDetails = (
@ -1740,15 +1738,12 @@ class receiveDataThread(threading.Thread):
listOfAddressDetailsToBroadcastToPeers.append( listOfAddressDetailsToBroadcastToPeers.append(
hostDetails) hostDetails)
else: else:
PORT, timeLastReceivedMessageFromThisNode = shared.knownNodes[recaddrStream][ timeLastReceivedMessageFromThisNode = shared.knownNodes[recaddrStream][
hostFromAddrMessage] # PORT in this case is either the port we used to connect to the remote node, or the port that was specified by someone else in a past addr message. peerFromAddrMessage] # PORT in this case is either the port we used to connect to the remote node, or the port that was specified by someone else in a past addr message.
if (timeLastReceivedMessageFromThisNode < timeSomeoneElseReceivedMessageFromThisNode) and (timeSomeoneElseReceivedMessageFromThisNode < int(time.time())): if (timeLastReceivedMessageFromThisNode < timeSomeoneElseReceivedMessageFromThisNode) and (timeSomeoneElseReceivedMessageFromThisNode < int(time.time())):
shared.knownNodesLock.acquire() shared.knownNodesLock.acquire()
shared.knownNodes[recaddrStream][hostFromAddrMessage] = ( shared.knownNodes[recaddrStream][peerFromAddrMessage] = timeSomeoneElseReceivedMessageFromThisNode
PORT, timeSomeoneElseReceivedMessageFromThisNode)
shared.knownNodesLock.release() shared.knownNodesLock.release()
if PORT != recaddrPort:
print 'Strange occurance: The port specified in an addr message', str(recaddrPort), 'does not match the port', str(PORT), 'that this program (or some other peer) used to connect to it', str(hostFromAddrMessage), '. Perhaps they changed their port or are using a strange NAT configuration.'
if needToWriteKnownNodesToDisk: # Runs if any nodes were new to us. Also, share those nodes with our peers. if needToWriteKnownNodesToDisk: # Runs if any nodes were new to us. Also, share those nodes with our peers.
shared.knownNodesLock.acquire() shared.knownNodesLock.acquire()
output = open(shared.appdata + 'knownnodes.dat', 'wb') output = open(shared.appdata + 'knownnodes.dat', 'wb')
@ -1834,14 +1829,15 @@ class receiveDataThread(threading.Thread):
shared.knownNodesLock.acquire() shared.knownNodesLock.acquire()
shared.knownNodes[recaddrStream] = {} shared.knownNodes[recaddrStream] = {}
shared.knownNodesLock.release() shared.knownNodesLock.release()
if hostFromAddrMessage not in shared.knownNodes[recaddrStream]: peerFromAddrMessage = shared.Peer(hostFromAddrMessage, recaddrPort)
if peerFromAddrMessage not in shared.knownNodes[recaddrStream]:
if len(shared.knownNodes[recaddrStream]) < 20000 and timeSomeoneElseReceivedMessageFromThisNode > (int(time.time()) - 10800) and timeSomeoneElseReceivedMessageFromThisNode < (int(time.time()) + 10800): # If we have more than 20000 nodes in our list already then just forget about adding more. Also, make sure that the time that someone else received a message from this node is within three hours from now. if len(shared.knownNodes[recaddrStream]) < 20000 and timeSomeoneElseReceivedMessageFromThisNode > (int(time.time()) - 10800) and timeSomeoneElseReceivedMessageFromThisNode < (int(time.time()) + 10800): # If we have more than 20000 nodes in our list already then just forget about adding more. Also, make sure that the time that someone else received a message from this node is within three hours from now.
shared.knownNodesLock.acquire() shared.knownNodesLock.acquire()
shared.knownNodes[recaddrStream][hostFromAddrMessage] = ( shared.knownNodes[recaddrStream][peerFromAddrMessage] = (
recaddrPort, timeSomeoneElseReceivedMessageFromThisNode) timeSomeoneElseReceivedMessageFromThisNode)
shared.knownNodesLock.release() shared.knownNodesLock.release()
with shared.printLock: with shared.printLock:
print 'added new node', hostFromAddrMessage, 'to knownNodes in stream', recaddrStream print 'added new node', peerFromAddrMessage, 'to knownNodes in stream', recaddrStream
needToWriteKnownNodesToDisk = True needToWriteKnownNodesToDisk = True
hostDetails = ( hostDetails = (
@ -1850,15 +1846,12 @@ class receiveDataThread(threading.Thread):
listOfAddressDetailsToBroadcastToPeers.append( listOfAddressDetailsToBroadcastToPeers.append(
hostDetails) hostDetails)
else: else:
PORT, timeLastReceivedMessageFromThisNode = shared.knownNodes[recaddrStream][ timeLastReceivedMessageFromThisNode = shared.knownNodes[recaddrStream][
hostFromAddrMessage] # PORT in this case is either the port we used to connect to the remote node, or the port that was specified by someone else in a past addr message. peerFromAddrMessage] # PORT in this case is either the port we used to connect to the remote node, or the port that was specified by someone else in a past addr message.
if (timeLastReceivedMessageFromThisNode < timeSomeoneElseReceivedMessageFromThisNode) and (timeSomeoneElseReceivedMessageFromThisNode < int(time.time())): if (timeLastReceivedMessageFromThisNode < timeSomeoneElseReceivedMessageFromThisNode) and (timeSomeoneElseReceivedMessageFromThisNode < int(time.time())):
shared.knownNodesLock.acquire() shared.knownNodesLock.acquire()
shared.knownNodes[recaddrStream][hostFromAddrMessage] = ( shared.knownNodes[recaddrStream][peerFromAddrMessage] = timeSomeoneElseReceivedMessageFromThisNode
PORT, timeSomeoneElseReceivedMessageFromThisNode)
shared.knownNodesLock.release() shared.knownNodesLock.release()
if PORT != recaddrPort:
print 'Strange occurance: The port specified in an addr message', str(recaddrPort), 'does not match the port', str(PORT), 'that this program (or some other peer) used to connect to it', str(hostFromAddrMessage), '. Perhaps they changed their port or are using a strange NAT configuration.'
if needToWriteKnownNodesToDisk: # Runs if any nodes were new to us. Also, share those nodes with our peers. if needToWriteKnownNodesToDisk: # Runs if any nodes were new to us. Also, share those nodes with our peers.
shared.knownNodesLock.acquire() shared.knownNodesLock.acquire()
output = open(shared.appdata + 'knownnodes.dat', 'wb') output = open(shared.appdata + 'knownnodes.dat', 'wb')
@ -1915,35 +1908,35 @@ class receiveDataThread(threading.Thread):
if len(shared.knownNodes[self.streamNumber]) > 0: if len(shared.knownNodes[self.streamNumber]) > 0:
for i in range(500): for i in range(500):
random.seed() random.seed()
HOST, = random.sample(shared.knownNodes[self.streamNumber], 1) peer, = random.sample(shared.knownNodes[self.streamNumber], 1)
if helper_generic.isHostInPrivateIPRange(HOST): if helper_generic.isHostInPrivateIPRange(peer.host):
continue continue
addrsInMyStream[HOST] = shared.knownNodes[ addrsInMyStream[peer] = shared.knownNodes[
self.streamNumber][HOST] self.streamNumber][peer]
if len(shared.knownNodes[self.streamNumber * 2]) > 0: if len(shared.knownNodes[self.streamNumber * 2]) > 0:
for i in range(250): for i in range(250):
random.seed() random.seed()
HOST, = random.sample(shared.knownNodes[ peer, = random.sample(shared.knownNodes[
self.streamNumber * 2], 1) self.streamNumber * 2], 1)
if helper_generic.isHostInPrivateIPRange(HOST): if helper_generic.isHostInPrivateIPRange(peer.host):
continue continue
addrsInChildStreamLeft[HOST] = shared.knownNodes[ addrsInChildStreamLeft[peer] = shared.knownNodes[
self.streamNumber * 2][HOST] self.streamNumber * 2][peer]
if len(shared.knownNodes[(self.streamNumber * 2) + 1]) > 0: if len(shared.knownNodes[(self.streamNumber * 2) + 1]) > 0:
for i in range(250): for i in range(250):
random.seed() random.seed()
HOST, = random.sample(shared.knownNodes[ peer, = random.sample(shared.knownNodes[
(self.streamNumber * 2) + 1], 1) (self.streamNumber * 2) + 1], 1)
if helper_generic.isHostInPrivateIPRange(HOST): if helper_generic.isHostInPrivateIPRange(peer.host):
continue continue
addrsInChildStreamRight[HOST] = shared.knownNodes[ addrsInChildStreamRight[peer] = shared.knownNodes[
(self.streamNumber * 2) + 1][HOST] (self.streamNumber * 2) + 1][peer]
shared.knownNodesLock.release() shared.knownNodesLock.release()
numberOfAddressesInAddrMessage = 0 numberOfAddressesInAddrMessage = 0
payload = '' payload = ''
# print 'addrsInMyStream.items()', addrsInMyStream.items() # print 'addrsInMyStream.items()', addrsInMyStream.items()
for HOST, value in addrsInMyStream.items(): for (HOST, PORT), value in addrsInMyStream.items():
PORT, timeLastReceivedMessageFromThisNode = value timeLastReceivedMessageFromThisNode = value
if timeLastReceivedMessageFromThisNode > (int(time.time()) - shared.maximumAgeOfNodesThatIAdvertiseToOthers): # If it is younger than 3 hours old.. if timeLastReceivedMessageFromThisNode > (int(time.time()) - shared.maximumAgeOfNodesThatIAdvertiseToOthers): # If it is younger than 3 hours old..
numberOfAddressesInAddrMessage += 1 numberOfAddressesInAddrMessage += 1
payload += pack( payload += pack(
@ -1954,8 +1947,8 @@ class receiveDataThread(threading.Thread):
payload += '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF' + \ payload += '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF' + \
socket.inet_aton(HOST) socket.inet_aton(HOST)
payload += pack('>H', PORT) # remote port payload += pack('>H', PORT) # remote port
for HOST, value in addrsInChildStreamLeft.items(): for (HOST, PORT), value in addrsInChildStreamLeft.items():
PORT, timeLastReceivedMessageFromThisNode = value timeLastReceivedMessageFromThisNode = value
if timeLastReceivedMessageFromThisNode > (int(time.time()) - shared.maximumAgeOfNodesThatIAdvertiseToOthers): # If it is younger than 3 hours old.. if timeLastReceivedMessageFromThisNode > (int(time.time()) - shared.maximumAgeOfNodesThatIAdvertiseToOthers): # If it is younger than 3 hours old..
numberOfAddressesInAddrMessage += 1 numberOfAddressesInAddrMessage += 1
payload += pack( payload += pack(
@ -1966,8 +1959,8 @@ class receiveDataThread(threading.Thread):
payload += '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF' + \ payload += '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF' + \
socket.inet_aton(HOST) socket.inet_aton(HOST)
payload += pack('>H', PORT) # remote port payload += pack('>H', PORT) # remote port
for HOST, value in addrsInChildStreamRight.items(): for (HOST, PORT), value in addrsInChildStreamRight.items():
PORT, timeLastReceivedMessageFromThisNode = value timeLastReceivedMessageFromThisNode = value
if timeLastReceivedMessageFromThisNode > (int(time.time()) - shared.maximumAgeOfNodesThatIAdvertiseToOthers): # If it is younger than 3 hours old.. if timeLastReceivedMessageFromThisNode > (int(time.time()) - shared.maximumAgeOfNodesThatIAdvertiseToOthers): # If it is younger than 3 hours old..
numberOfAddressesInAddrMessage += 1 numberOfAddressesInAddrMessage += 1
payload += pack( payload += pack(
@ -2004,9 +1997,9 @@ class receiveDataThread(threading.Thread):
elif not self.verackSent: elif not self.verackSent:
self.remoteProtocolVersion, = unpack('>L', data[:4]) self.remoteProtocolVersion, = unpack('>L', data[:4])
if self.remoteProtocolVersion <= 1: if self.remoteProtocolVersion <= 1:
shared.broadcastToSendDataQueues((0, 'shutdown', self.HOST)) shared.broadcastToSendDataQueues((0, 'shutdown', self.peer))
with shared.printLock: with shared.printLock:
print 'Closing connection to old protocol version 1 node: ', self.HOST print 'Closing connection to old protocol version 1 node: ', self.peer
return return
# print 'remoteProtocolVersion', self.remoteProtocolVersion # print 'remoteProtocolVersion', self.remoteProtocolVersion
@ -2028,30 +2021,29 @@ class receiveDataThread(threading.Thread):
print 'Remote node useragent:', useragent, ' stream number:', self.streamNumber print 'Remote node useragent:', useragent, ' stream number:', self.streamNumber
if self.streamNumber != 1: if self.streamNumber != 1:
shared.broadcastToSendDataQueues((0, 'shutdown', self.HOST)) shared.broadcastToSendDataQueues((0, 'shutdown', self.peer))
with shared.printLock: with shared.printLock:
print 'Closed connection to', self.HOST, 'because they are interested in stream', self.streamNumber, '.' print 'Closed connection to', self.peer, 'because they are interested in stream', self.streamNumber, '.'
return return
shared.connectedHostsList[ shared.connectedHostsList[
self.HOST] = 1 # We use this data structure to not only keep track of what hosts we are connected to so that we don't try to connect to them again, but also to list the connections count on the Network Status tab. self.peer.host] = 1 # We use this data structure to not only keep track of what hosts we are connected to so that we don't try to connect to them again, but also to list the connections count on the Network Status tab.
# If this was an incoming connection, then the sendData thread # If this was an incoming connection, then the sendData thread
# doesn't know the stream. We have to set it. # doesn't know the stream. We have to set it.
if not self.initiatedConnection: if not self.initiatedConnection:
shared.broadcastToSendDataQueues(( shared.broadcastToSendDataQueues((
0, 'setStreamNumber', (self.HOST, self.streamNumber))) 0, 'setStreamNumber', (self.peer, self.streamNumber)))
if data[72:80] == shared.eightBytesOfRandomDataUsedToDetectConnectionsToSelf: if data[72:80] == shared.eightBytesOfRandomDataUsedToDetectConnectionsToSelf:
shared.broadcastToSendDataQueues((0, 'shutdown', self.HOST)) shared.broadcastToSendDataQueues((0, 'shutdown', self.peer))
with shared.printLock: with shared.printLock:
print 'Closing connection to myself: ', self.HOST print 'Closing connection to myself: ', self.peer
return return
shared.broadcastToSendDataQueues((0, 'setRemoteProtocolVersion', ( shared.broadcastToSendDataQueues((0, 'setRemoteProtocolVersion', (
self.HOST, self.remoteProtocolVersion))) self.peer, self.remoteProtocolVersion)))
shared.knownNodesLock.acquire() shared.knownNodesLock.acquire()
shared.knownNodes[self.streamNumber][self.HOST] = ( shared.knownNodes[self.streamNumber][self.peer] = int(time.time())
self.remoteNodeIncomingPort, int(time.time()))
output = open(shared.appdata + 'knownnodes.dat', 'wb') output = open(shared.appdata + 'knownnodes.dat', 'wb')
pickle.dump(shared.knownNodes, output) pickle.dump(shared.knownNodes, output)
output.close() output.close()
@ -2068,7 +2060,7 @@ class receiveDataThread(threading.Thread):
try: try:
self.sock.sendall(shared.assembleVersionMessage( self.sock.sendall(shared.assembleVersionMessage(
self.HOST, self.PORT, self.streamNumber)) self.peer.host, self.peer.port, self.streamNumber))
except Exception as err: except Exception as err:
# if not 'Bad file descriptor' in err: # if not 'Bad file descriptor' in err:
with shared.printLock: with shared.printLock:

View File

@ -31,8 +31,7 @@ class sendDataThread(threading.Thread):
streamNumber, streamNumber,
someObjectsOfWhichThisRemoteNodeIsAlreadyAware): someObjectsOfWhichThisRemoteNodeIsAlreadyAware):
self.sock = sock self.sock = sock
self.HOST = HOST self.peer = shared.Peer(HOST, PORT)
self.PORT = PORT
self.streamNumber = streamNumber self.streamNumber = streamNumber
self.remoteProtocolVersion = - \ self.remoteProtocolVersion = - \
1 # This must be set using setRemoteProtocolVersion command which is sent through the self.mailbox queue. 1 # This must be set using setRemoteProtocolVersion command which is sent through the self.mailbox queue.
@ -45,7 +44,7 @@ class sendDataThread(threading.Thread):
def sendVersionMessage(self): def sendVersionMessage(self):
datatosend = shared.assembleVersionMessage( datatosend = shared.assembleVersionMessage(
self.HOST, self.PORT, self.streamNumber) # the IP and port of the remote host, and my streamNumber. self.peer.host, self.peer.port, self.streamNumber) # the IP and port of the remote host, and my streamNumber.
with shared.printLock: with shared.printLock:
print 'Sending version packet: ', repr(datatosend) print 'Sending version packet: ', repr(datatosend)
@ -62,15 +61,12 @@ class sendDataThread(threading.Thread):
def run(self): def run(self):
while True: while True:
deststream, command, data = self.mailbox.get() deststream, command, data = self.mailbox.get()
# with shared.printLock:
# print 'sendDataThread, destream:', deststream, ', Command:', command, ', ID:',id(self), ', HOST:', self.HOST
#
if deststream == self.streamNumber or deststream == 0: if deststream == self.streamNumber or deststream == 0:
if command == 'shutdown': if command == 'shutdown':
if data == self.HOST or data == 'all': if data == self.peer or data == 'all':
with shared.printLock: with shared.printLock:
print 'sendDataThread (associated with', self.HOST, ') ID:', id(self), 'shutting down now.' print 'sendDataThread (associated with', self.peer, ') ID:', id(self), 'shutting down now.'
try: try:
self.sock.shutdown(socket.SHUT_RDWR) self.sock.shutdown(socket.SHUT_RDWR)
@ -89,15 +85,15 @@ class sendDataThread(threading.Thread):
# will continue on with the connection and will set the # will continue on with the connection and will set the
# streamNumber of this send data thread here: # streamNumber of this send data thread here:
elif command == 'setStreamNumber': elif command == 'setStreamNumber':
hostInMessage, specifiedStreamNumber = data peerInMessage, specifiedStreamNumber = data
if hostInMessage == self.HOST: if peerInMessage == self.peer:
with shared.printLock: with shared.printLock:
print 'setting the stream number in the sendData thread (ID:', id(self), ') to', specifiedStreamNumber print 'setting the stream number in the sendData thread (ID:', id(self), ') to', specifiedStreamNumber
self.streamNumber = specifiedStreamNumber self.streamNumber = specifiedStreamNumber
elif command == 'setRemoteProtocolVersion': elif command == 'setRemoteProtocolVersion':
hostInMessage, specifiedRemoteProtocolVersion = data peerInMessage, specifiedRemoteProtocolVersion = data
if hostInMessage == self.HOST: if peerInMessage == self.peer:
with shared.printLock: with shared.printLock:
print 'setting the remote node\'s protocol version in the sendData thread (ID:', id(self), ') to', specifiedRemoteProtocolVersion print 'setting the remote node\'s protocol version in the sendData thread (ID:', id(self), ') to', specifiedRemoteProtocolVersion
@ -113,14 +109,14 @@ class sendDataThread(threading.Thread):
self.sock.sendall(data) self.sock.sendall(data)
self.lastTimeISentData = int(time.time()) self.lastTimeISentData = int(time.time())
except: except:
print 'self.sock.sendall failed' print 'sendaddr: self.sock.sendall failed'
try: try:
self.sock.shutdown(socket.SHUT_RDWR) self.sock.shutdown(socket.SHUT_RDWR)
self.sock.close() self.sock.close()
except: except:
pass pass
shared.sendDataQueues.remove(self.mailbox) shared.sendDataQueues.remove(self.mailbox)
print 'sendDataThread thread (ID:', str(id(self)) + ') ending now. Was connected to', self.HOST print 'sendDataThread thread (ID:', str(id(self)) + ') ending now. Was connected to', self.peer
break break
elif command == 'sendinv': elif command == 'sendinv':
if data not in self.someObjectsOfWhichThisRemoteNodeIsAlreadyAware: if data not in self.someObjectsOfWhichThisRemoteNodeIsAlreadyAware:
@ -137,21 +133,21 @@ class sendDataThread(threading.Thread):
self.sock.sendall(headerData + payload) self.sock.sendall(headerData + payload)
self.lastTimeISentData = int(time.time()) self.lastTimeISentData = int(time.time())
except: except:
print 'self.sock.sendall failed' print 'sendinv: self.sock.sendall failed'
try: try:
self.sock.shutdown(socket.SHUT_RDWR) self.sock.shutdown(socket.SHUT_RDWR)
self.sock.close() self.sock.close()
except: except:
pass pass
shared.sendDataQueues.remove(self.mailbox) shared.sendDataQueues.remove(self.mailbox)
print 'sendDataThread thread (ID:', str(id(self)) + ') ending now. Was connected to', self.HOST print 'sendDataThread thread (ID:', str(id(self)) + ') ending now. Was connected to', self.peer
break break
elif command == 'pong': elif command == 'pong':
self.someObjectsOfWhichThisRemoteNodeIsAlreadyAware.clear() # To save memory, let us clear this data structure from time to time. As its function is to help us keep from sending inv messages to peers which sent us the same inv message mere seconds earlier, it will be fine to clear this data structure from time to time. self.someObjectsOfWhichThisRemoteNodeIsAlreadyAware.clear() # To save memory, let us clear this data structure from time to time. As its function is to help us keep from sending inv messages to peers which sent us the same inv message mere seconds earlier, it will be fine to clear this data structure from time to time.
if self.lastTimeISentData < (int(time.time()) - 298): if self.lastTimeISentData < (int(time.time()) - 298):
# Send out a pong message to keep the connection alive. # Send out a pong message to keep the connection alive.
with shared.printLock: with shared.printLock:
print 'Sending pong to', self.HOST, 'to keep connection alive.' print 'Sending pong to', self.peer, 'to keep connection alive.'
try: try:
self.sock.sendall( self.sock.sendall(
@ -165,7 +161,7 @@ class sendDataThread(threading.Thread):
except: except:
pass pass
shared.sendDataQueues.remove(self.mailbox) shared.sendDataQueues.remove(self.mailbox)
print 'sendDataThread thread', self, 'ending now. Was connected to', self.HOST print 'sendDataThread thread', self, 'ending now. Was connected to', self.peer
break break
else: else:
with shared.printLock: with shared.printLock:

View File

@ -33,9 +33,9 @@ class singleCleaner(threading.Thread):
for hash, storedValue in shared.inventory.items(): for hash, storedValue in shared.inventory.items():
objectType, streamNumber, payload, receivedTime = storedValue objectType, streamNumber, payload, receivedTime = storedValue
if int(time.time()) - 3600 > receivedTime: if int(time.time()) - 3600 > receivedTime:
t = (hash, objectType, streamNumber, payload, receivedTime) t = (hash, objectType, streamNumber, payload, receivedTime,'')
shared.sqlSubmitQueue.put( shared.sqlSubmitQueue.put(
'''INSERT INTO inventory VALUES (?,?,?,?,?)''') '''INSERT INTO inventory VALUES (?,?,?,?,?,?)''')
shared.sqlSubmitQueue.put(t) shared.sqlSubmitQueue.put(t)
shared.sqlReturnQueue.get() shared.sqlReturnQueue.get()
del shared.inventory[hash] del shared.inventory[hash]

View File

@ -9,6 +9,7 @@ import proofofwork
import sys import sys
from class_addressGenerator import pointMult from class_addressGenerator import pointMult
import tr import tr
from debug import logger
# This thread, of which there is only one, does the heavy lifting: # This thread, of which there is only one, does the heavy lifting:
# calculating POWs. # calculating POWs.
@ -271,81 +272,11 @@ class singleWorker(threading.Thread):
fromaddress, subject, body, ackdata = row fromaddress, subject, body, ackdata = row
status, addressVersionNumber, streamNumber, ripe = decodeAddress( status, addressVersionNumber, streamNumber, ripe = decodeAddress(
fromaddress) fromaddress)
"""if addressVersionNumber == 2 and int(time.time()) < shared.encryptedBroadcastSwitchoverTime: if addressVersionNumber <= 1:
# We need to convert our private keys to public keys in order with shared.printLock:
# to include them. sys.stderr.write(
try: 'Error: In the singleWorker thread, the sendBroadcast function doesn\'t understand the address version.\n')
privSigningKeyBase58 = shared.config.get( return
fromaddress, 'privsigningkey')
privEncryptionKeyBase58 = shared.config.get(
fromaddress, 'privencryptionkey')
except:
shared.UISignalQueue.put(('updateSentItemStatusByAckdata', (
ackdata, tr.translateText("MainWindow", "Error! Could not find sender address (your address) in the keys.dat file."))))
continue
privSigningKeyHex = shared.decodeWalletImportFormat(
privSigningKeyBase58).encode('hex')
privEncryptionKeyHex = shared.decodeWalletImportFormat(
privEncryptionKeyBase58).encode('hex')
pubSigningKey = highlevelcrypto.privToPub(privSigningKeyHex).decode(
'hex') # At this time these pubkeys are 65 bytes long because they include the encoding byte which we won't be sending in the broadcast message.
pubEncryptionKey = highlevelcrypto.privToPub(
privEncryptionKeyHex).decode('hex')
payload = pack('>Q', (int(time.time()) + random.randrange(
-300, 300))) # the current time plus or minus five minutes
payload += encodeVarint(1) # broadcast version
payload += encodeVarint(addressVersionNumber)
payload += encodeVarint(streamNumber)
payload += '\x00\x00\x00\x01' # behavior bitfield
payload += pubSigningKey[1:]
payload += pubEncryptionKey[1:]
payload += ripe
payload += '\x02' # message encoding type
payload += encodeVarint(len(
'Subject:' + subject + '\n' + 'Body:' + body)) # Type 2 is simple UTF-8 message encoding.
payload += 'Subject:' + subject + '\n' + 'Body:' + body
signature = highlevelcrypto.sign(payload, privSigningKeyHex)
payload += encodeVarint(len(signature))
payload += signature
target = 2 ** 64 / ((len(
payload) + shared.networkDefaultPayloadLengthExtraBytes + 8) * shared.networkDefaultProofOfWorkNonceTrialsPerByte)
print '(For broadcast message) Doing proof of work...'
shared.UISignalQueue.put(('updateSentItemStatusByAckdata', (
ackdata, tr.translateText("MainWindow", "Doing work necessary to send broadcast..."))))
initialHash = hashlib.sha512(payload).digest()
trialValue, nonce = proofofwork.run(target, initialHash)
print '(For broadcast message) Found proof of work', trialValue, 'Nonce:', nonce
payload = pack('>Q', nonce) + payload
inventoryHash = calculateInventoryHash(payload)
objectType = 'broadcast'
shared.inventory[inventoryHash] = (
objectType, streamNumber, payload, int(time.time()))
print 'Broadcasting inv for my broadcast (within sendBroadcast function):', inventoryHash.encode('hex')
shared.broadcastToSendDataQueues((
streamNumber, 'sendinv', inventoryHash))
shared.UISignalQueue.put(('updateSentItemStatusByAckdata', (ackdata, tr.translateText("MainWindow", "Broadcast sent on %1").arg(unicode(
strftime(shared.config.get('bitmessagesettings', 'timeformat'), localtime(int(time.time()))), 'utf-8')))))
# Update the status of the message in the 'sent' table to have
# a 'broadcastsent' status
shared.sqlLock.acquire()
t = ('broadcastsent', int(
time.time()), fromaddress, subject, body, 'broadcastqueued')
shared.sqlSubmitQueue.put(
'UPDATE sent SET status=?, lastactiontime=? WHERE fromaddress=? AND subject=? AND message=? AND status=?')
shared.sqlSubmitQueue.put(t)
queryreturn = shared.sqlReturnQueue.get()
shared.sqlSubmitQueue.put('commit')
shared.sqlLock.release()"""
if addressVersionNumber == 2 or addressVersionNumber == 3:
# We need to convert our private keys to public keys in order # We need to convert our private keys to public keys in order
# to include them. # to include them.
try: try:
@ -414,7 +345,8 @@ class singleWorker(threading.Thread):
objectType = 'broadcast' objectType = 'broadcast'
shared.inventory[inventoryHash] = ( shared.inventory[inventoryHash] = (
objectType, streamNumber, payload, int(time.time())) objectType, streamNumber, payload, int(time.time()))
print 'sending inv (within sendBroadcast function)' with shared.printLock:
print 'sending inv (within sendBroadcast function) for object:', inventoryHash.encode('hex')
shared.broadcastToSendDataQueues(( shared.broadcastToSendDataQueues((
streamNumber, 'sendinv', inventoryHash)) streamNumber, 'sendinv', inventoryHash))
@ -425,17 +357,13 @@ class singleWorker(threading.Thread):
# a 'broadcastsent' status # a 'broadcastsent' status
shared.sqlLock.acquire() shared.sqlLock.acquire()
t = (inventoryHash,'broadcastsent', int( t = (inventoryHash,'broadcastsent', int(
time.time()), fromaddress, subject, body, 'broadcastqueued') time.time()), ackdata)
shared.sqlSubmitQueue.put( shared.sqlSubmitQueue.put(
'UPDATE sent SET msgid=?, status=?, lastactiontime=? WHERE fromaddress=? AND subject=? AND message=? AND status=?') 'UPDATE sent SET msgid=?, status=?, lastactiontime=? WHERE ackdata=?')
shared.sqlSubmitQueue.put(t) shared.sqlSubmitQueue.put(t)
queryreturn = shared.sqlReturnQueue.get() queryreturn = shared.sqlReturnQueue.get()
shared.sqlSubmitQueue.put('commit') shared.sqlSubmitQueue.put('commit')
shared.sqlLock.release() shared.sqlLock.release()
else:
with shared.printLock:
sys.stderr.write(
'Error: In the singleWorker thread, the sendBroadcast function doesn\'t understand the address version.\n')
def sendMsg(self): def sendMsg(self):
@ -590,6 +518,15 @@ class singleWorker(threading.Thread):
pubkeyPayload[readPosition:readPosition + 10]) pubkeyPayload[readPosition:readPosition + 10])
readPosition += streamNumberLength readPosition += streamNumberLength
behaviorBitfield = pubkeyPayload[readPosition:readPosition + 4] 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 readPosition += 4 # to bypass the bitfield of behaviors
# pubSigningKeyBase256 = # pubSigningKeyBase256 =
# pubkeyPayload[readPosition:readPosition+64] #We don't use this # pubkeyPayload[readPosition:readPosition+64] #We don't use this
@ -736,6 +673,10 @@ class singleWorker(threading.Thread):
with shared.printLock: with shared.printLock:
print 'Not bothering to generate ackdata because we are sending to a chan.' print 'Not bothering to generate ackdata because we are sending to a chan.'
fullAckPayload = '' 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.'
fullAckPayload = ''
else: else:
fullAckPayload = self.generateFullAckMessage( fullAckPayload = self.generateFullAckMessage(
ackdata, toStreamNumber, embeddedTime) # The fullAckPayload is a normal msg protocol message with the proof of work already completed that the receiver of this message can easily send out. ackdata, toStreamNumber, embeddedTime) # The fullAckPayload is a normal msg protocol message with the proof of work already completed that the receiver of this message can easily send out.

View File

@ -46,7 +46,7 @@ class sqlThread(threading.Thread):
self.cur.execute( self.cur.execute(
'''CREATE TABLE pubkeys (hash blob, transmitdata blob, time int, usedpersonally text, UNIQUE(hash) ON CONFLICT REPLACE)''' ) '''CREATE TABLE pubkeys (hash blob, transmitdata blob, time int, usedpersonally text, UNIQUE(hash) ON CONFLICT REPLACE)''' )
self.cur.execute( self.cur.execute(
'''CREATE TABLE inventory (hash blob, objecttype text, streamnumber int, payload blob, receivedtime integer, UNIQUE(hash) ON CONFLICT REPLACE)''' ) '''CREATE TABLE inventory (hash blob, objecttype text, streamnumber int, payload blob, receivedtime integer, first20bytesofencryptedmessage blob, UNIQUE(hash) ON CONFLICT REPLACE)''' )
self.cur.execute( self.cur.execute(
'''CREATE TABLE knownnodes (timelastseen int, stream int, services blob, host blob, port blob, UNIQUE(host, stream, port) ON CONFLICT REPLACE)''' ) '''CREATE TABLE knownnodes (timelastseen int, stream int, services blob, host blob, port blob, UNIQUE(host, stream, port) ON CONFLICT REPLACE)''' )
# This table isn't used in the program yet but I # This table isn't used in the program yet but I
@ -55,7 +55,7 @@ class sqlThread(threading.Thread):
'''INSERT INTO subscriptions VALUES('Bitmessage new releases/announcements','BM-GtovgYdgs7qXPkoYaRgrLFuFKz1SFpsw',1)''') '''INSERT INTO subscriptions VALUES('Bitmessage new releases/announcements','BM-GtovgYdgs7qXPkoYaRgrLFuFKz1SFpsw',1)''')
self.cur.execute( self.cur.execute(
'''CREATE TABLE settings (key blob, value blob, UNIQUE(key) ON CONFLICT REPLACE)''' ) '''CREATE TABLE settings (key blob, value blob, UNIQUE(key) ON CONFLICT REPLACE)''' )
self.cur.execute( '''INSERT INTO settings VALUES('version','1')''') self.cur.execute( '''INSERT INTO settings VALUES('version','2')''')
self.cur.execute( '''INSERT INTO settings VALUES('lastvacuumtime',?)''', ( self.cur.execute( '''INSERT INTO settings VALUES('lastvacuumtime',?)''', (
int(time.time()),)) int(time.time()),))
self.conn.commit() self.conn.commit()
@ -190,6 +190,19 @@ class sqlThread(threading.Thread):
if not shared.config.has_option('bitmessagesettings', 'sockslisten'): if not shared.config.has_option('bitmessagesettings', 'sockslisten'):
shared.config.set('bitmessagesettings', 'sockslisten', 'false') shared.config.set('bitmessagesettings', 'sockslisten', 'false')
# Add a new column to the inventory table to store the first 20 bytes of encrypted messages to support Android app
item = '''SELECT value FROM settings WHERE key='version';'''
parameters = ''
self.cur.execute(item, parameters)
if int(self.cur.fetchall()[0][0]) == 1:
print 'upgrading database'
item = '''ALTER TABLE inventory ADD first20bytesofencryptedmessage blob DEFAULT '' '''
parameters = ''
self.cur.execute(item, parameters)
item = '''update settings set value=? WHERE key='version';'''
parameters = (2,)
self.cur.execute(item, parameters)
try: try:
testpayload = '\x00\x00' testpayload = '\x00\x00'
t = ('1234', testpayload, '12345678', 'no') t = ('1234', testpayload, '12345678', 'no')

View File

@ -5,19 +5,20 @@ import time
import random import random
import sys import sys
from time import strftime, localtime from time import strftime, localtime
import shared
def createDefaultKnownNodes(appdata): def createDefaultKnownNodes(appdata):
############## Stream 1 ################ ############## Stream 1 ################
stream1 = {} stream1 = {}
stream1['85.171.174.131'] = (8444,int(time.time())) stream1[shared.Peer('85.171.174.131', 8444)] = int(time.time())
stream1['23.28.68.159'] = (8444,int(time.time())) stream1[shared.Peer('23.28.68.159', 8444)] = int(time.time())
stream1['66.108.210.240'] = (8080,int(time.time())) stream1[shared.Peer('66.108.210.240', 8444)] = int(time.time())
stream1['204.236.246.212'] = (8444,int(time.time())) stream1[shared.Peer('204.236.246.212', 8444)] = int(time.time())
stream1['78.81.56.239'] = (8444,int(time.time())) stream1[shared.Peer('78.81.56.239', 8444)] = int(time.time())
stream1['122.60.235.157'] = (8444,int(time.time())) stream1[shared.Peer('122.60.235.157', 8444)] = int(time.time())
stream1['204.236.246.212'] = (8444,int(time.time())) stream1[shared.Peer('204.236.246.212', 8444)] = int(time.time())
stream1['24.98.219.109'] = (8444,int(time.time())) stream1[shared.Peer('24.98.219.109', 8444)] = int(time.time())
############# Stream 2 ################# ############# Stream 2 #################
@ -36,22 +37,25 @@ def createDefaultKnownNodes(appdata):
#print stream1 #print stream1
#print allKnownNodes #print allKnownNodes
output = open(appdata + 'knownnodes.dat', 'wb') with open(appdata + 'knownnodes.dat', 'wb') as output:
# Pickle dictionary using protocol 0. # Pickle dictionary using protocol 0.
pickle.dump(allKnownNodes, output) pickle.dump(allKnownNodes, output)
output.close()
return allKnownNodes return allKnownNodes
def readDefaultKnownNodes(appdata): def readDefaultKnownNodes(appdata):
pickleFile = open(appdata + 'knownnodes.dat', 'rb') pickleFile = open(appdata + 'knownnodes.dat', 'rb')
knownNodes = pickle.load(pickleFile) knownNodes = pickle.load(pickleFile)
pickleFile.close() pickleFile.close()
knownNodes
for stream, storedValue in knownNodes.items(): for stream, storedValue in knownNodes.items():
for host,value in storedValue.items(): for host,value in storedValue.items():
port, storedtime = storedValue[host] try:
# Old knownNodes format.
port, storedtime = value
except:
# New knownNodes format.
host, port = host
storedtime = value
print host, '\t', port, '\t', unicode(strftime('%a, %d %b %Y %I:%M %p',localtime(storedtime)),'utf-8') print host, '\t', port, '\t', unicode(strftime('%a, %d %b %Y %I:%M %p',localtime(storedtime)),'utf-8')
if __name__ == "__main__": if __name__ == "__main__":

View File

@ -9,8 +9,20 @@ def knownNodes():
# We shouldn't have to use the shared.knownNodesLock because this had # We shouldn't have to use the shared.knownNodesLock because this had
# better be the only thread accessing knownNodes right now. # better be the only thread accessing knownNodes right now.
pickleFile = open(shared.appdata + 'knownnodes.dat', 'rb') pickleFile = open(shared.appdata + 'knownnodes.dat', 'rb')
shared.knownNodes = pickle.load(pickleFile) loadedKnownNodes = pickle.load(pickleFile)
pickleFile.close() pickleFile.close()
# The old format of storing knownNodes was as a 'host: (port, time)'
# mapping. The new format is as 'Peer: time' pairs. If we loaded
# data in the old format, transform it to the new style.
for stream, nodes in loadedKnownNodes.items():
shared.knownNodes[stream] = {}
for node_tuple in nodes.items():
try:
host, (port, time) = node_tuple
peer = shared.Peer(host, port)
except:
peer, time = node_tuple
shared.knownNodes[stream][peer] = time
except: except:
shared.knownNodes = defaultKnownNodes.createDefaultKnownNodes(shared.appdata) shared.knownNodes = defaultKnownNodes.createDefaultKnownNodes(shared.appdata)
if shared.config.getint('bitmessagesettings', 'settingsversion') > 6: if shared.config.getint('bitmessagesettings', 'settingsversion') > 6:
@ -28,13 +40,13 @@ def dns():
try: try:
for item in socket.getaddrinfo('bootstrap8080.bitmessage.org', 80): for item in socket.getaddrinfo('bootstrap8080.bitmessage.org', 80):
print 'Adding', item[4][0], 'to knownNodes based on DNS boostrap method' print 'Adding', item[4][0], 'to knownNodes based on DNS boostrap method'
shared.knownNodes[1][item[4][0]] = (8080, int(time.time())) shared.knownNodes[1][shared.Peer(item[4][0], 8080)] = int(time.time())
except: except:
print 'bootstrap8080.bitmessage.org DNS bootstrapping failed.' print 'bootstrap8080.bitmessage.org DNS bootstrapping failed.'
try: try:
for item in socket.getaddrinfo('bootstrap8444.bitmessage.org', 80): for item in socket.getaddrinfo('bootstrap8444.bitmessage.org', 80):
print 'Adding', item[4][0], 'to knownNodes based on DNS boostrap method' print 'Adding', item[4][0], 'to knownNodes based on DNS boostrap method'
shared.knownNodes[1][item[4][0]] = (8444, int(time.time())) shared.knownNodes[1][shared.Peer(item[4][0], 8444)] = int(time.time())
except: except:
print 'bootstrap8444.bitmessage.org DNS bootstrapping failed.' print 'bootstrap8444.bitmessage.org DNS bootstrapping failed.'
else: else:

View File

@ -5,19 +5,10 @@
import sqlite3 import sqlite3
from time import strftime, localtime from time import strftime, localtime
import sys import sys
import shared
import string
APPNAME = "PyBitmessage" appdata = shared.lookupAppdataFolder()
from os import path, environ
if sys.platform == 'darwin':
if "HOME" in environ:
appdata = path.join(environ["HOME"], "Library/Application support/", APPNAME) + '/'
else:
print 'Could not find home folder, please report this message and your OS X version to the BitMessage Github.'
sys.exit()
elif 'win' in sys.platform:
appdata = path.join(environ['APPDATA'], APPNAME) + '\\'
else:
appdata = path.expanduser(path.join("~", "." + APPNAME + "/"))
conn = sqlite3.connect( appdata + 'messages.dat' ) conn = sqlite3.connect( appdata + 'messages.dat' )
conn.text_factory = str conn.text_factory = str

View File

@ -9,6 +9,7 @@ useVeryEasyProofOfWorkForTesting = False # If you set this to True while on the
# Libraries. # Libraries.
import collections
import ConfigParser import ConfigParser
import os import os
import pickle import pickle
@ -122,10 +123,8 @@ def assembleVersionMessage(remoteHost, remotePort, myStreamNumber):
random.seed() random.seed()
payload += eightBytesOfRandomDataUsedToDetectConnectionsToSelf payload += eightBytesOfRandomDataUsedToDetectConnectionsToSelf
userAgent = '/PyBitmessage:' + shared.softwareVersion + \ userAgent = '/PyBitmessage:' + shared.softwareVersion + '/'
'/' # Length of userAgent must be less than 253. payload += encodeVarint(len(userAgent))
payload += pack('>B', len(
userAgent)) # user agent string length. If the user agent is more than 252 bytes long, this code isn't going to work.
payload += userAgent payload += userAgent
payload += encodeVarint( payload += encodeVarint(
1) # The number of streams about which I care. PyBitmessage currently only supports 1 per connection. 1) # The number of streams about which I care. PyBitmessage currently only supports 1 per connection.
@ -224,17 +223,17 @@ def decodeWalletImportFormat(WIFstring):
fullString = arithmetic.changebase(WIFstring,58,256) fullString = arithmetic.changebase(WIFstring,58,256)
privkey = fullString[:-4] privkey = fullString[:-4]
if fullString[-4:] != hashlib.sha256(hashlib.sha256(privkey).digest()).digest()[:4]: if fullString[-4:] != hashlib.sha256(hashlib.sha256(privkey).digest()).digest()[:4]:
logger.error('Major problem! When trying to decode one of your private keys, the checksum ' logger.critical('Major problem! When trying to decode one of your private keys, the checksum '
'failed. Here is the PRIVATE key: %s\n' % str(WIFstring)) 'failed. Here is the PRIVATE key: %s' % str(WIFstring))
return "" return ""
else: else:
#checksum passed #checksum passed
if privkey[0] == '\x80': if privkey[0] == '\x80':
return privkey[1:] return privkey[1:]
else: else:
logger.error('Major problem! When trying to decode one of your private keys, the ' logger.critical('Major problem! When trying to decode one of your private keys, the '
'checksum passed but the key doesn\'t begin with hex 80. Here is the ' 'checksum passed but the key doesn\'t begin with hex 80. Here is the '
'PRIVATE key: %s\n' % str(WIFstring)) 'PRIVATE key: %s' % str(WIFstring))
return "" return ""
@ -264,8 +263,7 @@ def reloadMyAddressHashes():
myAddressesByHash[hash] = addressInKeysFile myAddressesByHash[hash] = addressInKeysFile
else: else:
logger.error('Error in reloadMyAddressHashes: Can\'t handle address ' logger.error('Error in reloadMyAddressHashes: Can\'t handle address versions other than 2 or 3.\n')
'versions other than 2 or 3.\n')
if not keyfileSecure: if not keyfileSecure:
fixSensitiveFilePermissions(appdata + 'keys.dat', hasEnabledKeys) fixSensitiveFilePermissions(appdata + 'keys.dat', hasEnabledKeys)
@ -341,8 +339,8 @@ def flushInventory():
sqlLock.acquire() sqlLock.acquire()
for hash, storedValue in inventory.items(): for hash, storedValue in inventory.items():
objectType, streamNumber, payload, receivedTime = storedValue objectType, streamNumber, payload, receivedTime = storedValue
t = (hash,objectType,streamNumber,payload,receivedTime) t = (hash,objectType,streamNumber,payload,receivedTime,'')
sqlSubmitQueue.put('''INSERT INTO inventory VALUES (?,?,?,?,?)''') sqlSubmitQueue.put('''INSERT INTO inventory VALUES (?,?,?,?,?,?)''')
sqlSubmitQueue.put(t) sqlSubmitQueue.put(t)
sqlReturnQueue.get() sqlReturnQueue.get()
del inventory[hash] del inventory[hash]
@ -367,6 +365,19 @@ def checkSensitiveFilePermissions(filename):
# Windows systems. # Windows systems.
return True return True
else: else:
try:
# Skip known problems for non-Win32 filesystems without POSIX permissions.
import subprocess
fstype = subprocess.check_output('stat -f -c "%%T" %s' % (filename),
shell=True,
stderr=subprocess.STDOUT)
if 'fuseblk' in fstype:
logger.info('Skipping file permissions check for %s. Filesystem fuseblk detected.',
filename)
return True
except:
# Swallow exception here, but we might run into trouble later!
logger.error('Could not determine filesystem type. %s', filename)
present_permissions = os.stat(filename)[0] present_permissions = os.stat(filename)[0]
disallowed_permissions = stat.S_IRWXG | stat.S_IRWXO disallowed_permissions = stat.S_IRWXG | stat.S_IRWXO
return present_permissions & disallowed_permissions == 0 return present_permissions & disallowed_permissions == 0
@ -392,5 +403,13 @@ def fixSensitiveFilePermissions(filename, hasEnabledKeys):
logger.exception('Keyfile permissions could not be fixed.') logger.exception('Keyfile permissions could not be fixed.')
raise raise
def isBitSetWithinBitfield(fourByteString, n):
# Uses MSB 0 bit numbering across 4 bytes of data
n = 31 - n
x, = unpack('>L', fourByteString)
return x & 2**n != 0
Peer = collections.namedtuple('Peer', ['host', 'port'])
helper_startup.loadConfig() helper_startup.loadConfig()
from debug import logger from debug import logger