Merge branch 'foo'
This commit is contained in:
commit
5f64271800
101
INSTALL.md
Normal file
101
INSTALL.md
Normal 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
|
4
arch.sh
4
arch.sh
|
@ -1,8 +1,8 @@
|
|||
#!/bin/bash
|
||||
|
||||
APP=pybitmessage
|
||||
PREV_VERSION=0.3.4
|
||||
VERSION=0.3.4
|
||||
PREV_VERSION=0.3.5
|
||||
VERSION=0.3.5
|
||||
RELEASE=1
|
||||
ARCH_TYPE=`uname -m`
|
||||
CURRDIR=`pwd`
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# Maintainer: Bob Mottram (4096 bits) <bob@robotics.uk.to>
|
||||
pkgname=pybitmessage
|
||||
pkgver=0.3.4
|
||||
pkgver=0.3.5
|
||||
pkgrel=1
|
||||
pkgdesc="Bitmessage is a P2P communications protocol used to send encrypted messages to another person or to many subscribers. It is decentralized and trustless, meaning that you need-not inherently trust any entities like root certificate authorities. It uses strong authentication which means that the sender of a message cannot be spoofed, and it aims to hide "non-content" data, like the sender and receiver of messages, from passive eavesdroppers like those running warrantless wiretapping programs."
|
||||
arch=('i686' 'x86_64')
|
||||
|
|
2
debian.sh
Normal file → Executable file
2
debian.sh
Normal file → Executable file
|
@ -2,7 +2,7 @@
|
|||
|
||||
APP=pybitmessage
|
||||
PREV_VERSION=0.3.4
|
||||
VERSION=0.3.4
|
||||
VERSION=0.3.5
|
||||
RELEASE=1
|
||||
ARCH_TYPE=`uname -m`
|
||||
DIR=${APP}-${VERSION}
|
||||
|
|
28
debian/changelog
vendored
28
debian/changelog
vendored
|
@ -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
|
||||
|
||||
* Switched addr, msg, broadcast, and getpubkey message types
|
||||
|
|
0
debian/rules
vendored
Normal file → Executable file
0
debian/rules
vendored
Normal file → Executable file
|
@ -1,8 +1,8 @@
|
|||
#!/bin/bash
|
||||
|
||||
APP=pybitmessage
|
||||
PREV_VERSION=0.3.4
|
||||
VERSION=0.3.4
|
||||
PREV_VERSION=0.3.5
|
||||
VERSION=0.3.5
|
||||
RELEASE=1
|
||||
SOURCEDIR=.
|
||||
ARCH_TYPE=`uname -m`
|
||||
|
|
27
generate.sh
27
generate.sh
|
@ -4,4 +4,29 @@
|
|||
|
||||
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"
|
||||
|
|
4
puppy.sh
4
puppy.sh
|
@ -1,8 +1,8 @@
|
|||
#!/bin/bash
|
||||
|
||||
APP=pybitmessage
|
||||
PREV_VERSION=0.3.4
|
||||
VERSION=0.3.4
|
||||
PREV_VERSION=0.3.5
|
||||
VERSION=0.3.5
|
||||
RELEASE=1
|
||||
BUILDDIR=~/petbuild
|
||||
CURRDIR=`pwd`
|
||||
|
|
|
@ -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|
|
1
puppypackage/pybitmessage-0.3.5.pet.specs
Normal file
1
puppypackage/pybitmessage-0.3.5.pet.specs
Normal 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
4
rpm.sh
|
@ -1,8 +1,8 @@
|
|||
#!/bin/bash
|
||||
|
||||
APP=pybitmessage
|
||||
PREV_VERSION=0.3.4
|
||||
VERSION=0.3.4
|
||||
PREV_VERSION=0.3.5
|
||||
VERSION=0.3.5
|
||||
RELEASE=1
|
||||
SOURCEDIR=.
|
||||
ARCH_TYPE=`uname -m`
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
Name: pybitmessage
|
||||
Version: 0.3.4
|
||||
Version: 0.3.5
|
||||
Release: 1%{?dist}
|
||||
Summary: Send encrypted messages
|
||||
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
|
||||
|
||||
%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
|
||||
- Switched addr, msg, broadcast, and getpubkey message types
|
||||
to 8 byte time. Last remaining type is pubkey.
|
||||
|
|
4
slack.sh
4
slack.sh
|
@ -1,8 +1,8 @@
|
|||
#!/bin/bash
|
||||
|
||||
APP=pybitmessage
|
||||
PREV_VERSION=0.3.4
|
||||
VERSION=0.3.4
|
||||
PREV_VERSION=0.3.5
|
||||
VERSION=0.3.5
|
||||
RELEASE=1
|
||||
ARCH_TYPE=`uname -m`
|
||||
BUILDDIR=~/slackbuild
|
||||
|
|
|
@ -329,6 +329,21 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
|
|||
'base64'), 'message': message.encode('base64'), 'encodingType': encodingtype, 'receivedTime': received, 'read': read}, indent=4, separators=(',', ': '))
|
||||
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':
|
||||
if len(params) == 0:
|
||||
return 'API Error 0000: I need parameters!'
|
||||
|
@ -345,8 +360,8 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
|
|||
subject = shared.fixPotentiallyInvalidUTF8Data(subject)
|
||||
message = shared.fixPotentiallyInvalidUTF8Data(message)
|
||||
data += json.dumps({'msgid':msgid.encode('hex'), 'toAddress':toAddress, 'fromAddress':fromAddress, 'subject':subject.encode('base64'), 'message':message.encode('base64'), 'encodingType':encodingtype, 'receivedTime':received, 'read': read}, indent=4, separators=(',', ': '))
|
||||
data += ']}'
|
||||
return data
|
||||
data += ']}'
|
||||
return data
|
||||
elif method == 'getAllSentMessages':
|
||||
shared.sqlLock.acquire()
|
||||
shared.sqlSubmitQueue.put('''SELECT msgid, toaddress, fromaddress, subject, lastactiontime, message, encodingtype, status, ackdata FROM sent where folder='sent' ORDER BY lastactiontime''')
|
||||
|
@ -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 += ']}'
|
||||
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:
|
||||
return 'API Error 0000: I need parameters!'
|
||||
toAddress = params[0]
|
||||
|
@ -399,8 +428,8 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
|
|||
subject = shared.fixPotentiallyInvalidUTF8Data(subject)
|
||||
message = shared.fixPotentiallyInvalidUTF8Data(message)
|
||||
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 += ']}'
|
||||
return data
|
||||
data += ']}'
|
||||
return data
|
||||
elif method == 'getSentMessagesByAddress' or method == 'getSentMessagesBySender':
|
||||
if len(params) == 0:
|
||||
return 'API Error 0000: I need parameters!'
|
||||
|
@ -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 += ']}'
|
||||
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:
|
||||
return 'API Error 0000: I need parameters!'
|
||||
msgid = params[0].decode('hex')
|
||||
|
@ -681,10 +727,134 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
|
|||
shared.UISignalQueue.put(('rerenderInboxFromLabels', ''))
|
||||
shared.UISignalQueue.put(('rerenderSubscriptions', ''))
|
||||
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':
|
||||
return '{ "networkConnections" : "%s" }' % str(len(shared.connectedHostsList))
|
||||
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.
|
||||
|
||||
|
@ -700,11 +870,8 @@ class singleAPI(threading.Thread):
|
|||
se.register_introspection_functions()
|
||||
se.serve_forever()
|
||||
|
||||
# This is a list of current connections (the thread pointers at least)
|
||||
selfInitiatedConnections = {}
|
||||
# This is a list of current connections (the thread pointers at least)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
if shared.useVeryEasyProofOfWorkForTesting:
|
||||
|
@ -713,89 +880,113 @@ if shared.useVeryEasyProofOfWorkForTesting:
|
|||
shared.networkDefaultPayloadLengthExtraBytes = int(
|
||||
shared.networkDefaultPayloadLengthExtraBytes / 7000)
|
||||
|
||||
if __name__ == "__main__":
|
||||
# is the application already running? If yes then exit.
|
||||
thisapp = singleton.singleinstance()
|
||||
class Main:
|
||||
def start(self, deamon=False):
|
||||
# is the application already running? If yes then exit.
|
||||
thisapp = singleton.singleinstance()
|
||||
|
||||
signal.signal(signal.SIGINT, helper_generic.signal_handler)
|
||||
# signal.signal(signal.SIGINT, signal.SIG_DFL)
|
||||
signal.signal(signal.SIGINT, helper_generic.signal_handler)
|
||||
# signal.signal(signal.SIGINT, signal.SIG_DFL)
|
||||
|
||||
helper_bootstrap.knownNodes()
|
||||
# Start the address generation thread
|
||||
addressGeneratorThread = addressGenerator()
|
||||
addressGeneratorThread.daemon = True # close the main program even if there are threads left
|
||||
addressGeneratorThread.start()
|
||||
helper_bootstrap.knownNodes()
|
||||
# Start the address generation thread
|
||||
addressGeneratorThread = addressGenerator()
|
||||
addressGeneratorThread.daemon = True # close the main program even if there are threads left
|
||||
addressGeneratorThread.start()
|
||||
|
||||
# Start the thread that calculates POWs
|
||||
singleWorkerThread = singleWorker()
|
||||
singleWorkerThread.daemon = True # close the main program even if there are threads left
|
||||
singleWorkerThread.start()
|
||||
# Start the thread that calculates POWs
|
||||
singleWorkerThread = singleWorker()
|
||||
singleWorkerThread.daemon = True # close the main program even if there are threads left
|
||||
singleWorkerThread.start()
|
||||
|
||||
# Start the SQL thread
|
||||
sqlLookup = sqlThread()
|
||||
sqlLookup.daemon = False # DON'T close the main program even if there are threads left. The closeEvent should command this thread to exit gracefully.
|
||||
sqlLookup.start()
|
||||
# Start the SQL thread
|
||||
sqlLookup = sqlThread()
|
||||
sqlLookup.daemon = False # DON'T close the main program even if there are threads left. The closeEvent should command this thread to exit gracefully.
|
||||
sqlLookup.start()
|
||||
|
||||
# Start the cleanerThread
|
||||
singleCleanerThread = singleCleaner()
|
||||
singleCleanerThread.daemon = True # close the main program even if there are threads left
|
||||
singleCleanerThread.start()
|
||||
# Start the cleanerThread
|
||||
singleCleanerThread = singleCleaner()
|
||||
singleCleanerThread.daemon = True # close the main program even if there are threads left
|
||||
singleCleanerThread.start()
|
||||
|
||||
# Start the SMTP and POP3 server if necessary
|
||||
try:
|
||||
if shared.config.getboolean('bitmessagesettings', 'smtppop3enable'):
|
||||
shared.startSMTPPOP3Servers()
|
||||
except NoOptionError:
|
||||
pass
|
||||
|
||||
# And finally launch asyncore
|
||||
asyncoreThread = asyncoreThread()
|
||||
asyncoreThread.daemon = True
|
||||
asyncoreThread.start()
|
||||
|
||||
shared.reloadMyAddressHashes()
|
||||
shared.reloadBroadcastSendersForWhichImWatching()
|
||||
|
||||
if shared.safeConfigGetBoolean('bitmessagesettings', 'apienabled'):
|
||||
# Start the SMTP and POP3 server if necessary
|
||||
try:
|
||||
apiNotifyPath = shared.config.get(
|
||||
'bitmessagesettings', 'apinotifypath')
|
||||
except:
|
||||
apiNotifyPath = ''
|
||||
if apiNotifyPath != '':
|
||||
with shared.printLock:
|
||||
print 'Trying to call', apiNotifyPath
|
||||
if shared.config.getboolean('bitmessagesettings', 'smtppop3enable'):
|
||||
shared.startSMTPPOP3Servers()
|
||||
except NoOptionError:
|
||||
pass
|
||||
|
||||
call([apiNotifyPath, "startingUp"])
|
||||
singleAPIThread = singleAPI()
|
||||
singleAPIThread.daemon = True # close the main program even if there are threads left
|
||||
singleAPIThread.start()
|
||||
# And finally launch asyncore
|
||||
asyncoreThreadInstance = asyncoreThread()
|
||||
asyncoreThreadInstance.daemon = True
|
||||
asyncoreThreadInstance.start()
|
||||
|
||||
connectToStream(1)
|
||||
shared.reloadMyAddressHashes()
|
||||
shared.reloadBroadcastSendersForWhichImWatching()
|
||||
|
||||
singleListenerThread = singleListener()
|
||||
singleListenerThread.setup(selfInitiatedConnections)
|
||||
singleListenerThread.daemon = True # close the main program even if there are threads left
|
||||
singleListenerThread.start()
|
||||
if shared.safeConfigGetBoolean('bitmessagesettings', 'apienabled'):
|
||||
try:
|
||||
apiNotifyPath = shared.config.get(
|
||||
'bitmessagesettings', 'apinotifypath')
|
||||
except:
|
||||
apiNotifyPath = ''
|
||||
if apiNotifyPath != '':
|
||||
with shared.printLock:
|
||||
print 'Trying to call', apiNotifyPath
|
||||
|
||||
if not shared.safeConfigGetBoolean('bitmessagesettings', 'daemon'):
|
||||
try:
|
||||
from PyQt4 import QtCore, QtGui
|
||||
except Exception as err:
|
||||
print 'PyBitmessage requires PyQt unless you want to run it as a daemon and interact with it using the API. You can download PyQt from http://www.riverbankcomputing.com/software/pyqt/download or by searching Google for \'PyQt Download\'. If you want to run in daemon mode, see https://bitmessage.org/wiki/Daemon'
|
||||
print 'Error message:', err
|
||||
os._exit(0)
|
||||
call([apiNotifyPath, "startingUp"])
|
||||
singleAPIThread = singleAPI()
|
||||
singleAPIThread.daemon = True # close the main program even if there are threads left
|
||||
singleAPIThread.start()
|
||||
|
||||
import bitmessageqt
|
||||
bitmessageqt.run()
|
||||
else:
|
||||
shared.config.remove_option('bitmessagesettings', 'dontconnect')
|
||||
connectToStream(1)
|
||||
|
||||
singleListenerThread = singleListener()
|
||||
singleListenerThread.setup(selfInitiatedConnections)
|
||||
singleListenerThread.daemon = True # close the main program even if there are threads left
|
||||
singleListenerThread.start()
|
||||
|
||||
if deamon == False and shared.safeConfigGetBoolean('bitmessagesettings', 'daemon') == False:
|
||||
try:
|
||||
from PyQt4 import QtCore, QtGui
|
||||
except Exception as err:
|
||||
print 'PyBitmessage requires PyQt unless you want to run it as a daemon and interact with it using the API. You can download PyQt from http://www.riverbankcomputing.com/software/pyqt/download or by searching Google for \'PyQt Download\'. If you want to run in daemon mode, see https://bitmessage.org/wiki/Daemon'
|
||||
print 'Error message:', err
|
||||
os._exit(0)
|
||||
|
||||
import bitmessageqt
|
||||
bitmessageqt.run()
|
||||
else:
|
||||
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:
|
||||
print 'Running as a daemon. You can use Ctrl+C to exit.'
|
||||
while True:
|
||||
time.sleep(20)
|
||||
|
||||
def stop(self):
|
||||
with shared.printLock:
|
||||
print 'Running as a daemon. You can use Ctrl+C to exit.'
|
||||
|
||||
while True:
|
||||
time.sleep(20)
|
||||
print 'Stopping Bitmessage Deamon.'
|
||||
shared.doCleanShutdown()
|
||||
|
||||
|
||||
def getApiAddress(self):
|
||||
if not shared.safeConfigGetBoolean('bitmessagesettings', 'apienabled'):
|
||||
return None
|
||||
|
||||
address = shared.config.get('bitmessagesettings', 'apiinterface')
|
||||
port = shared.config.getint('bitmessagesettings', 'apiport')
|
||||
return {'address':address,'port':port}
|
||||
|
||||
if __name__ == "__main__":
|
||||
mainprogram = Main()
|
||||
mainprogram.start()
|
||||
|
||||
|
||||
# So far, the creation of and management of the Bitmessage protocol and this
|
||||
# client is a one-man operation. Bitcoin tips are quite appreciated.
|
||||
# 1H5XaDA6fYENLbknwZyjiYXYPQaFjjLX2u
|
||||
|
|
|
@ -34,7 +34,7 @@ import platform
|
|||
import debug
|
||||
from debug import logger
|
||||
import subprocess
|
||||
|
||||
import datetime
|
||||
|
||||
try:
|
||||
from PyQt4 import QtCore, QtGui
|
||||
|
@ -65,6 +65,12 @@ class MyForm(QtGui.QMainWindow):
|
|||
SOUND_DISCONNECTED = 4
|
||||
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_chan = '[chan]'
|
||||
|
||||
|
@ -429,7 +435,6 @@ class MyForm(QtGui.QMainWindow):
|
|||
self.rerenderComboBoxSendFrom()
|
||||
|
||||
|
||||
|
||||
# Show or hide the application window after clicking an item within the
|
||||
# tray icon or, on Windows, the try icon itself.
|
||||
def appIndicatorShowOrHideWindow(self):
|
||||
|
@ -982,29 +987,63 @@ class MyForm(QtGui.QMainWindow):
|
|||
# update the menu entries
|
||||
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
|
||||
def playSound(self, category, label):
|
||||
# filename of the sound to be played
|
||||
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:
|
||||
# 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
|
||||
os.path.isfile(shared.appdata + 'sounds/' + label + '.mp3')):
|
||||
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:
|
||||
# the sound is for an address which exists in the address book
|
||||
if category is self.SOUND_KNOWN:
|
||||
soundFilename = shared.appdata + 'sounds/known'
|
||||
# the sound is for an unknown address
|
||||
elif category is self.SOUND_UNKNOWN:
|
||||
soundFilename = shared.appdata + 'sounds/unknown'
|
||||
# initial connection sound
|
||||
elif category is self.SOUND_CONNECTED:
|
||||
soundFilename = shared.appdata + 'sounds/connected'
|
||||
# disconnected sound
|
||||
elif category is self.SOUND_DISCONNECTED:
|
||||
soundFilename = shared.appdata + 'sounds/disconnected'
|
||||
# sound when the connection status becomes green
|
||||
elif category is self.SOUND_CONNECTION_GREEN:
|
||||
soundFilename = shared.appdata + 'sounds/green'
|
||||
soundFilename = shared.appdata + 'sounds/green'
|
||||
|
||||
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 soundFilename is not None:
|
||||
# if not wav then try mp3 format
|
||||
if not os.path.isfile(soundFilename + '.wav'):
|
||||
soundFilename = soundFilename + '.mp3'
|
||||
|
@ -2008,6 +2047,8 @@ class MyForm(QtGui.QMainWindow):
|
|||
else:
|
||||
shared.config.set('bitmessagesettings', 'keyfile', str(
|
||||
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 not shared.safeConfigGetBoolean('bitmessagesettings', 'dontconnect'):
|
||||
QMessageBox.about(self, _translate("MainWindow", "Restart"), _translate(
|
||||
|
@ -2838,6 +2879,11 @@ class MyForm(QtGui.QMainWindow):
|
|||
def tableWidgetInboxItemClicked(self):
|
||||
currentRow = self.ui.tableWidgetInbox.currentRow()
|
||||
if currentRow >= 0:
|
||||
|
||||
font = QFont()
|
||||
font.setBold(False)
|
||||
self.ui.textEditInboxMessage.setCurrentFont(font)
|
||||
|
||||
fromAddress = str(self.ui.tableWidgetInbox.item(
|
||||
currentRow, 1).data(Qt.UserRole).toPyObject())
|
||||
# If we have received this message from either a broadcast address
|
||||
|
@ -2856,9 +2902,7 @@ class MyForm(QtGui.QMainWindow):
|
|||
else:
|
||||
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
|
||||
|
||||
font = QFont()
|
||||
font.setBold(False)
|
||||
|
||||
self.ui.tableWidgetInbox.item(currentRow, 0).setFont(font)
|
||||
self.ui.tableWidgetInbox.item(currentRow, 1).setFont(font)
|
||||
self.ui.tableWidgetInbox.item(currentRow, 2).setFont(font)
|
||||
|
@ -3021,7 +3065,8 @@ class settingsDialog(QtGui.QDialog):
|
|||
except:
|
||||
self.ui.checkBoxStripMessageHeaders.setChecked(True)
|
||||
self.ui.lineEditMessageHeadersToStrip.setText('User-Agent')
|
||||
|
||||
self.ui.checkBoxWillinglySendToMobile.setChecked(
|
||||
shared.safeConfigGetBoolean('bitmessagesettings', 'willinglysendtomobile'))
|
||||
if shared.appdata == '':
|
||||
self.ui.checkBoxPortableMode.setChecked(True)
|
||||
if 'darwin' in sys.platform:
|
||||
|
@ -3506,7 +3551,8 @@ def run():
|
|||
translator = QtCore.QTranslator()
|
||||
|
||||
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:
|
||||
# The above is not compatible with all versions of OSX.
|
||||
translator.load("translations/bitmessage_en_US") # Default to english.
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
# 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
|
||||
#
|
||||
# WARNING! All changes made in this file will be lost!
|
||||
|
@ -26,7 +26,7 @@ except AttributeError:
|
|||
class Ui_MainWindow(object):
|
||||
def setupUi(self, MainWindow):
|
||||
MainWindow.setObjectName(_fromUtf8("MainWindow"))
|
||||
MainWindow.resize(795, 561)
|
||||
MainWindow.resize(795, 580)
|
||||
icon = QtGui.QIcon()
|
||||
icon.addPixmap(QtGui.QPixmap(_fromUtf8(":/newPrefix/images/can-icon-24px.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
||||
MainWindow.setWindowIcon(icon)
|
||||
|
@ -424,7 +424,7 @@ class Ui_MainWindow(object):
|
|||
self.gridLayout.addWidget(self.tabWidget, 0, 0, 1, 1)
|
||||
MainWindow.setCentralWidget(self.centralwidget)
|
||||
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.menuFile = QtGui.QMenu(self.menubar)
|
||||
self.menuFile.setObjectName(_fromUtf8("menuFile"))
|
||||
|
@ -442,20 +442,36 @@ class Ui_MainWindow(object):
|
|||
self.actionManageKeys = QtGui.QAction(MainWindow)
|
||||
self.actionManageKeys.setCheckable(False)
|
||||
self.actionManageKeys.setEnabled(True)
|
||||
icon = QtGui.QIcon.fromTheme(_fromUtf8("dialog-password"))
|
||||
self.actionManageKeys.setIcon(icon)
|
||||
self.actionManageKeys.setObjectName(_fromUtf8("actionManageKeys"))
|
||||
self.actionExit = QtGui.QAction(MainWindow)
|
||||
icon = QtGui.QIcon.fromTheme(_fromUtf8("application-exit"))
|
||||
self.actionExit.setIcon(icon)
|
||||
self.actionExit.setObjectName(_fromUtf8("actionExit"))
|
||||
self.actionHelp = QtGui.QAction(MainWindow)
|
||||
icon = QtGui.QIcon.fromTheme(_fromUtf8("help-contents"))
|
||||
self.actionHelp.setIcon(icon)
|
||||
self.actionHelp.setObjectName(_fromUtf8("actionHelp"))
|
||||
self.actionAbout = QtGui.QAction(MainWindow)
|
||||
icon = QtGui.QIcon.fromTheme(_fromUtf8("help-about"))
|
||||
self.actionAbout.setIcon(icon)
|
||||
self.actionAbout.setObjectName(_fromUtf8("actionAbout"))
|
||||
self.actionSettings = QtGui.QAction(MainWindow)
|
||||
icon = QtGui.QIcon.fromTheme(_fromUtf8("document-properties"))
|
||||
self.actionSettings.setIcon(icon)
|
||||
self.actionSettings.setObjectName(_fromUtf8("actionSettings"))
|
||||
self.actionRegenerateDeterministicAddresses = QtGui.QAction(MainWindow)
|
||||
icon = QtGui.QIcon.fromTheme(_fromUtf8("view-refresh"))
|
||||
self.actionRegenerateDeterministicAddresses.setIcon(icon)
|
||||
self.actionRegenerateDeterministicAddresses.setObjectName(_fromUtf8("actionRegenerateDeterministicAddresses"))
|
||||
self.actionDeleteAllTrashedMessages = QtGui.QAction(MainWindow)
|
||||
icon = QtGui.QIcon.fromTheme(_fromUtf8("user-trash"))
|
||||
self.actionDeleteAllTrashedMessages.setIcon(icon)
|
||||
self.actionDeleteAllTrashedMessages.setObjectName(_fromUtf8("actionDeleteAllTrashedMessages"))
|
||||
self.actionJoinChan = QtGui.QAction(MainWindow)
|
||||
icon = QtGui.QIcon.fromTheme(_fromUtf8("contact-new"))
|
||||
self.actionJoinChan.setIcon(icon)
|
||||
self.actionJoinChan.setObjectName(_fromUtf8("actionJoinChan"))
|
||||
self.menuFile.addAction(self.actionManageKeys)
|
||||
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"
|
||||
"<html><head><meta name=\"qrichtext\" content=\"1\" /><style type=\"text/css\">\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"
|
||||
"<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))
|
||||
"</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; font-family:\'MS Shell Dlg 2\';\"><br /></p></body></html>", None))
|
||||
self.label.setText(_translate("MainWindow", "To:", None))
|
||||
self.label_2.setText(_translate("MainWindow", "From:", None))
|
||||
self.radioButtonBroadcast.setText(_translate("MainWindow", "Broadcast to everyone who is subscribed to your address", None))
|
||||
|
@ -601,7 +617,9 @@ class Ui_MainWindow(object):
|
|||
self.actionImport_keys.setText(_translate("MainWindow", "Import keys", None))
|
||||
self.actionManageKeys.setText(_translate("MainWindow", "Manage keys", None))
|
||||
self.actionExit.setText(_translate("MainWindow", "Quit", None))
|
||||
self.actionExit.setShortcut(_translate("MainWindow", "Ctrl+Q", None))
|
||||
self.actionHelp.setText(_translate("MainWindow", "Help", None))
|
||||
self.actionHelp.setShortcut(_translate("MainWindow", "F1", None))
|
||||
self.actionAbout.setText(_translate("MainWindow", "About", None))
|
||||
self.actionSettings.setText(_translate("MainWindow", "Settings", None))
|
||||
self.actionRegenerateDeterministicAddresses.setText(_translate("MainWindow", "Regenerate deterministic addresses", None))
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>795</width>
|
||||
<height>561</height>
|
||||
<height>580</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
|
@ -257,8 +257,8 @@
|
|||
<string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
|
||||
<html><head><meta name="qrichtext" content="1" /><style type="text/css">
|
||||
p, li { white-space: pre-wrap; }
|
||||
</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:9pt; font-weight:400; font-style:normal;">
|
||||
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html></string>
|
||||
</style></head><body style=" font-family:'Droid Sans'; font-size:9pt; font-weight:400; font-style:normal;">
|
||||
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2';"><br /></p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
@ -1016,7 +1016,7 @@ p, li { white-space: pre-wrap; }
|
|||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>795</width>
|
||||
<height>18</height>
|
||||
<height>27</height>
|
||||
</rect>
|
||||
</property>
|
||||
<widget class="QMenu" name="menuFile">
|
||||
|
@ -1066,41 +1066,87 @@ p, li { white-space: pre-wrap; }
|
|||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="dialog-password">
|
||||
<normaloff/>
|
||||
</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Manage keys</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionExit">
|
||||
<property name="icon">
|
||||
<iconset theme="application-exit">
|
||||
<normaloff/>
|
||||
</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Quit</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+Q</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionHelp">
|
||||
<property name="icon">
|
||||
<iconset theme="help-contents">
|
||||
<normaloff/>
|
||||
</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Help</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>F1</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionAbout">
|
||||
<property name="icon">
|
||||
<iconset theme="help-about">
|
||||
<normaloff/>
|
||||
</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>About</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionSettings">
|
||||
<property name="icon">
|
||||
<iconset theme="document-properties">
|
||||
<normaloff/>
|
||||
</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Settings</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionRegenerateDeterministicAddresses">
|
||||
<property name="icon">
|
||||
<iconset theme="view-refresh">
|
||||
<normaloff/>
|
||||
</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Regenerate deterministic addresses</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionDeleteAllTrashedMessages">
|
||||
<property name="icon">
|
||||
<iconset theme="user-trash">
|
||||
<normaloff/>
|
||||
</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Delete all trashed messages</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionJoinChan">
|
||||
<property name="icon">
|
||||
<iconset theme="contact-new">
|
||||
<normaloff/>
|
||||
</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Join / Create chan</string>
|
||||
</property>
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
|
||||
# Form implementation generated from reading ui file 'newchandialog.ui'
|
||||
#
|
||||
# Created: Mon Jul 22 01:05:35 2013
|
||||
# by: PyQt4 UI code generator 4.10.2
|
||||
# Created: Wed Aug 7 16:51:29 2013
|
||||
# by: PyQt4 UI code generator 4.10
|
||||
#
|
||||
# WARNING! All changes made in this file will be lost!
|
||||
|
||||
|
@ -26,7 +26,7 @@ except AttributeError:
|
|||
class Ui_newChanDialog(object):
|
||||
def setupUi(self, newChanDialog):
|
||||
newChanDialog.setObjectName(_fromUtf8("newChanDialog"))
|
||||
newChanDialog.resize(530, 422)
|
||||
newChanDialog.resize(553, 422)
|
||||
newChanDialog.setMinimumSize(QtCore.QSize(0, 0))
|
||||
self.formLayout = QtGui.QFormLayout(newChanDialog)
|
||||
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.radioButtonCreateChan, QtCore.SIGNAL(_fromUtf8("toggled(bool)")), self.groupBoxCreateChan.setShown)
|
||||
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):
|
||||
newChanDialog.setWindowTitle(_translate("newChanDialog", "Dialog", None))
|
||||
self.radioButtonCreateChan.setText(_translate("newChanDialog", "Create a new chan", None))
|
||||
self.radioButtonJoinChan.setText(_translate("newChanDialog", "Join a chan", None))
|
||||
self.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.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))
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>530</width>
|
||||
<width>553</width>
|
||||
<height>422</height>
|
||||
</rect>
|
||||
</property>
|
||||
|
@ -46,7 +46,7 @@
|
|||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>Enter a name for your chan. If you choose a sufficiently complex chan name (like a strong and unique passphrase) and none of your friends share it publicly then the chan will be secure and private.</string>
|
||||
<string><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></string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
|
@ -130,6 +130,14 @@
|
|||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<tabstops>
|
||||
<tabstop>radioButtonJoinChan</tabstop>
|
||||
<tabstop>radioButtonCreateChan</tabstop>
|
||||
<tabstop>lineEditChanNameCreate</tabstop>
|
||||
<tabstop>lineEditChanNameJoin</tabstop>
|
||||
<tabstop>lineEditChanBitmessageAddress</tabstop>
|
||||
<tabstop>buttonBox</tabstop>
|
||||
</tabstops>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
# 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
|
||||
#
|
||||
# WARNING! All changes made in this file will be lost!
|
||||
|
@ -41,33 +41,36 @@ class Ui_settingsDialog(object):
|
|||
self.tabUserInterface.setObjectName(_fromUtf8("tabUserInterface"))
|
||||
self.gridLayout_5 = QtGui.QGridLayout(self.tabUserInterface)
|
||||
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.setText(_fromUtf8(""))
|
||||
self.labelSettingsNote.setWordWrap(True)
|
||||
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)
|
||||
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.tabNetworkSettings = QtGui.QWidget()
|
||||
self.tabNetworkSettings.setObjectName(_fromUtf8("tabNetworkSettings"))
|
||||
|
@ -396,12 +399,13 @@ class Ui_settingsDialog(object):
|
|||
|
||||
def retranslateUi(self, settingsDialog):
|
||||
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.checkBoxMinimizeToTray.setText(_translate("settingsDialog", "Minimize to tray", 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.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.groupBox.setTitle(_translate("settingsDialog", "Listening port", None))
|
||||
self.label.setText(_translate("settingsDialog", "Listen for connections on port:", None))
|
||||
|
|
|
@ -37,13 +37,29 @@
|
|||
<string>User Interface</string>
|
||||
</attribute>
|
||||
<layout class="QGridLayout" name="gridLayout_5">
|
||||
<item row="0" column="0">
|
||||
<widget class="QCheckBox" name="checkBoxStartOnLogon">
|
||||
<item row="7" column="0">
|
||||
<widget class="QLabel" name="labelSettingsNote">
|
||||
<property name="text">
|
||||
<string>Start Bitmessage on user login</string>
|
||||
<string/>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</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">
|
||||
<widget class="QCheckBox" name="checkBoxStartInTray">
|
||||
<property name="text">
|
||||
|
@ -51,6 +67,13 @@
|
|||
</property>
|
||||
</widget>
|
||||
</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">
|
||||
<widget class="QCheckBox" name="checkBoxMinimizeToTray">
|
||||
<property name="text">
|
||||
|
@ -61,20 +84,6 @@
|
|||
</property>
|
||||
</widget>
|
||||
</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">
|
||||
<widget class="QLabel" name="label_7">
|
||||
<property name="text">
|
||||
|
@ -85,28 +94,26 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<widget class="QLabel" name="labelSettingsNote">
|
||||
<item row="0" column="0">
|
||||
<widget class="QCheckBox" name="checkBoxStartOnLogon">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
<string>Start Bitmessage on user login</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="0">
|
||||
<spacer name="verticalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
<item row="4" column="0">
|
||||
<widget class="QCheckBox" name="checkBoxPortableMode">
|
||||
<property name="text">
|
||||
<string>Run in Portable Mode</string>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<widget class="QCheckBox" name="checkBoxWillinglySendToMobile">
|
||||
<property name="text">
|
||||
<string>Willingly include unencrypted destination address when sending to a mobile device</string>
|
||||
</property>
|
||||
</spacer>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
|
|
|
@ -1,80 +1,16 @@
|
|||
"""
|
||||
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
|
||||
|
||||
from setuptools import setup
|
||||
|
||||
name = "Bitmessage"
|
||||
mainscript = 'bitmessagemain.py'
|
||||
version = "0.3.5"
|
||||
|
||||
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],
|
||||
)
|
||||
version = "0.3.4"
|
||||
mainscript = ["bitmessagemain.py"]
|
||||
|
||||
setup(
|
||||
name = name,
|
||||
version = version,
|
||||
**extra_options
|
||||
name = name,
|
||||
version = version,
|
||||
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)
|
||||
|
||||
|
|
|
@ -32,15 +32,15 @@ class outgoingSynSender(threading.Thread):
|
|||
break
|
||||
random.seed()
|
||||
shared.knownNodesLock.acquire()
|
||||
HOST, = random.sample(shared.knownNodes[self.streamNumber], 1)
|
||||
peer, = random.sample(shared.knownNodes[self.streamNumber], 1)
|
||||
shared.knownNodesLock.release()
|
||||
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()
|
||||
# print 'choosing new sample'
|
||||
random.seed()
|
||||
shared.knownNodesLock.acquire()
|
||||
HOST, = random.sample(shared.knownNodes[self.streamNumber], 1)
|
||||
peer, = random.sample(shared.knownNodes[self.streamNumber], 1)
|
||||
shared.knownNodesLock.release()
|
||||
time.sleep(1)
|
||||
# Clear out the shared.alreadyAttemptedConnectionsList every half
|
||||
|
@ -51,10 +51,10 @@ class outgoingSynSender(threading.Thread):
|
|||
shared.alreadyAttemptedConnectionsListResetTime = int(
|
||||
time.time())
|
||||
shared.alreadyAttemptedConnectionsListLock.acquire()
|
||||
shared.alreadyAttemptedConnectionsList[HOST] = 0
|
||||
shared.alreadyAttemptedConnectionsList[peer] = 0
|
||||
shared.alreadyAttemptedConnectionsListLock.release()
|
||||
PORT, timeNodeLastSeen = shared.knownNodes[
|
||||
self.streamNumber][HOST]
|
||||
timeNodeLastSeen = shared.knownNodes[
|
||||
self.streamNumber][peer]
|
||||
sock = socks.socksocket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
# This option apparently avoids the TIME_WAIT state so that we
|
||||
# can rebind faster
|
||||
|
@ -62,13 +62,13 @@ class outgoingSynSender(threading.Thread):
|
|||
sock.settimeout(20)
|
||||
if shared.config.get('bitmessagesettings', 'socksproxytype') == 'none' and shared.verbose >= 2:
|
||||
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)
|
||||
elif shared.config.get('bitmessagesettings', 'socksproxytype') == 'SOCKS4a':
|
||||
if shared.verbose >= 2:
|
||||
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
|
||||
sockshostname = shared.config.get(
|
||||
|
@ -89,7 +89,7 @@ class outgoingSynSender(threading.Thread):
|
|||
elif shared.config.get('bitmessagesettings', 'socksproxytype') == 'SOCKS5':
|
||||
if shared.verbose >= 2:
|
||||
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
|
||||
sockshostname = shared.config.get(
|
||||
|
@ -109,19 +109,19 @@ class outgoingSynSender(threading.Thread):
|
|||
proxytype, sockshostname, socksport, rdns)
|
||||
|
||||
try:
|
||||
sock.connect((HOST, PORT))
|
||||
sock.connect((peer.host, peer.port))
|
||||
rd = receiveDataThread()
|
||||
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.
|
||||
rd.setup(sock, HOST, PORT, self.streamNumber,
|
||||
rd.setup(sock, peer.host, peer.port, self.streamNumber,
|
||||
someObjectsOfWhichThisRemoteNodeIsAlreadyAware, self.selfInitiatedConnections)
|
||||
rd.start()
|
||||
with shared.printLock:
|
||||
print self, 'connected to', HOST, 'during an outgoing attempt.'
|
||||
print self, 'connected to', peer, 'during an outgoing attempt.'
|
||||
|
||||
|
||||
sd = sendDataThread()
|
||||
sd.setup(sock, HOST, PORT, self.streamNumber,
|
||||
sd.setup(sock, peer.host, peer.port, self.streamNumber,
|
||||
someObjectsOfWhichThisRemoteNodeIsAlreadyAware)
|
||||
sd.start()
|
||||
sd.sendVersionMessage()
|
||||
|
@ -129,16 +129,16 @@ class outgoingSynSender(threading.Thread):
|
|||
except socks.GeneralProxyError as err:
|
||||
if shared.verbose >= 2:
|
||||
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[
|
||||
self.streamNumber][HOST]
|
||||
timeLastSeen = shared.knownNodes[
|
||||
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.
|
||||
shared.knownNodesLock.acquire()
|
||||
del shared.knownNodes[self.streamNumber][HOST]
|
||||
del shared.knownNodes[self.streamNumber][peer]
|
||||
shared.knownNodesLock.release()
|
||||
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:
|
||||
shared.UISignalQueue.put((
|
||||
|
@ -155,16 +155,16 @@ class outgoingSynSender(threading.Thread):
|
|||
else:
|
||||
if shared.verbose >= 1:
|
||||
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[
|
||||
self.streamNumber][HOST]
|
||||
timeLastSeen = shared.knownNodes[
|
||||
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.
|
||||
shared.knownNodesLock.acquire()
|
||||
del shared.knownNodes[self.streamNumber][HOST]
|
||||
del shared.knownNodes[self.streamNumber][peer]
|
||||
shared.knownNodesLock.release()
|
||||
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:
|
||||
sys.stderr.write(
|
||||
|
|
|
@ -212,10 +212,18 @@ class bitmessagePOP3Connection(asyncore.dispatcher):
|
|||
|
||||
def handleList(self, data):
|
||||
self.populateMessageIndex()
|
||||
yield "+OK {} messages ({} octets)".format(len(self.messages), self.storage_size)
|
||||
for i, msg in enumerate(self.messages):
|
||||
yield "{} {}".format(i + 1, msg['size'])
|
||||
yield "."
|
||||
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)
|
||||
for i, msg in enumerate(self.messages):
|
||||
yield "{} {}".format(i + 1, msg['size'])
|
||||
yield "."
|
||||
|
||||
#def handleTop(self, data):
|
||||
# cmd, num, lines = data.split()
|
||||
|
|
|
@ -44,14 +44,13 @@ class receiveDataThread(threading.Thread):
|
|||
someObjectsOfWhichThisRemoteNodeIsAlreadyAware,
|
||||
selfInitiatedConnections):
|
||||
self.sock = sock
|
||||
self.HOST = HOST
|
||||
self.PORT = port
|
||||
self.peer = shared.Peer(HOST, port)
|
||||
self.streamNumber = streamNumber
|
||||
self.payloadLength = 0 # This is the protocol payload length thus it doesn't include the 24 byte message header
|
||||
self.objectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHave = {}
|
||||
self.selfInitiatedConnections = selfInitiatedConnections
|
||||
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.
|
||||
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
|
||||
|
@ -72,18 +71,18 @@ class receiveDataThread(threading.Thread):
|
|||
self.data += self.sock.recv(4096)
|
||||
except socket.timeout:
|
||||
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
|
||||
except Exception as err:
|
||||
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
|
||||
# print 'Received', repr(self.data)
|
||||
if len(self.data) == dataLen: # If self.sock.recv returned no data:
|
||||
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
|
||||
else:
|
||||
self.processData()
|
||||
|
@ -95,16 +94,16 @@ class receiveDataThread(threading.Thread):
|
|||
|
||||
except:
|
||||
pass
|
||||
shared.broadcastToSendDataQueues((0, 'shutdown', self.HOST))
|
||||
shared.broadcastToSendDataQueues((0, 'shutdown', self.peer))
|
||||
try:
|
||||
del shared.connectedHostsList[self.HOST]
|
||||
del shared.connectedHostsList[self.peer.host]
|
||||
except Exception as err:
|
||||
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:
|
||||
del shared.numberOfObjectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHavePerPeer[
|
||||
self.HOST]
|
||||
self.peer]
|
||||
except:
|
||||
pass
|
||||
shared.UISignalQueue.put(('updateNetworkStatusTab', 'no data'))
|
||||
|
@ -139,13 +138,12 @@ class receiveDataThread(threading.Thread):
|
|||
# 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).
|
||||
shared.knownNodesLock.acquire()
|
||||
shared.knownNodes[self.streamNumber][
|
||||
self.HOST] = (self.PORT, int(time.time()))
|
||||
shared.knownNodes[self.streamNumber][self.peer] = int(time.time())
|
||||
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.)
|
||||
remoteCommand = self.data[4:16]
|
||||
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':
|
||||
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.
|
||||
if len(self.objectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHave) == 0:
|
||||
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:
|
||||
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:
|
||||
pass
|
||||
break
|
||||
if len(self.objectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHave) == 0:
|
||||
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:
|
||||
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:
|
||||
pass
|
||||
if len(self.objectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHave) > 0:
|
||||
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.
|
||||
if len(self.ackDataThatWeHaveYetToSend) > 0:
|
||||
self.data = self.ackDataThatWeHaveYetToSend.pop()
|
||||
|
@ -264,22 +262,22 @@ class receiveDataThread(threading.Thread):
|
|||
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.
|
||||
shared.UISignalQueue.put(('updateNetworkStatusTab', 'no data'))
|
||||
remoteNodeIncomingPort, remoteNodeSeenTime = shared.knownNodes[
|
||||
self.streamNumber][self.HOST]
|
||||
remoteNodeSeenTime = shared.knownNodes[
|
||||
self.streamNumber][self.peer]
|
||||
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 length of sendDataQueues is now:', len(shared.sendDataQueues)
|
||||
print 'broadcasting addr from within connectionFullyEstablished function.'
|
||||
|
||||
self.broadcastaddr([(int(time.time()), self.streamNumber, 1, self.HOST,
|
||||
remoteNodeIncomingPort)]) # This lets all of our peers know about this new node.
|
||||
self.broadcastaddr([(int(time.time()), self.streamNumber, 1, self.peer.host,
|
||||
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.
|
||||
if not self.initiatedConnection and len(shared.connectedHostsList) > 200:
|
||||
with shared.printLock:
|
||||
print 'We are connected to too many people. Closing connection.'
|
||||
|
||||
shared.broadcastToSendDataQueues((0, 'shutdown', self.HOST))
|
||||
shared.broadcastToSendDataQueues((0, 'shutdown', self.peer))
|
||||
return
|
||||
self.sendBigInv()
|
||||
|
||||
|
@ -1545,7 +1543,7 @@ class receiveDataThread(threading.Thread):
|
|||
self.objectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHave[
|
||||
data[lengthOfVarint + (32 * i):32 + lengthOfVarint + (32 * i)]] = 0
|
||||
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
|
||||
# hash
|
||||
|
@ -1727,11 +1725,11 @@ class receiveDataThread(threading.Thread):
|
|||
shared.knownNodesLock.acquire()
|
||||
shared.knownNodes[recaddrStream] = {}
|
||||
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.
|
||||
shared.knownNodesLock.acquire()
|
||||
shared.knownNodes[recaddrStream][hostFromAddrMessage] = (
|
||||
recaddrPort, timeSomeoneElseReceivedMessageFromThisNode)
|
||||
shared.knownNodes[recaddrStream][peerFromAddrMessage] = timeSomeoneElseReceivedMessageFromThisNode
|
||||
shared.knownNodesLock.release()
|
||||
needToWriteKnownNodesToDisk = True
|
||||
hostDetails = (
|
||||
|
@ -1740,15 +1738,12 @@ class receiveDataThread(threading.Thread):
|
|||
listOfAddressDetailsToBroadcastToPeers.append(
|
||||
hostDetails)
|
||||
else:
|
||||
PORT, 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.
|
||||
timeLastReceivedMessageFromThisNode = shared.knownNodes[recaddrStream][
|
||||
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())):
|
||||
shared.knownNodesLock.acquire()
|
||||
shared.knownNodes[recaddrStream][hostFromAddrMessage] = (
|
||||
PORT, timeSomeoneElseReceivedMessageFromThisNode)
|
||||
shared.knownNodes[recaddrStream][peerFromAddrMessage] = timeSomeoneElseReceivedMessageFromThisNode
|
||||
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.
|
||||
shared.knownNodesLock.acquire()
|
||||
output = open(shared.appdata + 'knownnodes.dat', 'wb')
|
||||
|
@ -1834,14 +1829,15 @@ class receiveDataThread(threading.Thread):
|
|||
shared.knownNodesLock.acquire()
|
||||
shared.knownNodes[recaddrStream] = {}
|
||||
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.
|
||||
shared.knownNodesLock.acquire()
|
||||
shared.knownNodes[recaddrStream][hostFromAddrMessage] = (
|
||||
recaddrPort, timeSomeoneElseReceivedMessageFromThisNode)
|
||||
shared.knownNodes[recaddrStream][peerFromAddrMessage] = (
|
||||
timeSomeoneElseReceivedMessageFromThisNode)
|
||||
shared.knownNodesLock.release()
|
||||
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
|
||||
hostDetails = (
|
||||
|
@ -1850,15 +1846,12 @@ class receiveDataThread(threading.Thread):
|
|||
listOfAddressDetailsToBroadcastToPeers.append(
|
||||
hostDetails)
|
||||
else:
|
||||
PORT, 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.
|
||||
timeLastReceivedMessageFromThisNode = shared.knownNodes[recaddrStream][
|
||||
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())):
|
||||
shared.knownNodesLock.acquire()
|
||||
shared.knownNodes[recaddrStream][hostFromAddrMessage] = (
|
||||
PORT, timeSomeoneElseReceivedMessageFromThisNode)
|
||||
shared.knownNodes[recaddrStream][peerFromAddrMessage] = timeSomeoneElseReceivedMessageFromThisNode
|
||||
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.
|
||||
shared.knownNodesLock.acquire()
|
||||
output = open(shared.appdata + 'knownnodes.dat', 'wb')
|
||||
|
@ -1915,35 +1908,35 @@ class receiveDataThread(threading.Thread):
|
|||
if len(shared.knownNodes[self.streamNumber]) > 0:
|
||||
for i in range(500):
|
||||
random.seed()
|
||||
HOST, = random.sample(shared.knownNodes[self.streamNumber], 1)
|
||||
if helper_generic.isHostInPrivateIPRange(HOST):
|
||||
peer, = random.sample(shared.knownNodes[self.streamNumber], 1)
|
||||
if helper_generic.isHostInPrivateIPRange(peer.host):
|
||||
continue
|
||||
addrsInMyStream[HOST] = shared.knownNodes[
|
||||
self.streamNumber][HOST]
|
||||
addrsInMyStream[peer] = shared.knownNodes[
|
||||
self.streamNumber][peer]
|
||||
if len(shared.knownNodes[self.streamNumber * 2]) > 0:
|
||||
for i in range(250):
|
||||
random.seed()
|
||||
HOST, = random.sample(shared.knownNodes[
|
||||
peer, = random.sample(shared.knownNodes[
|
||||
self.streamNumber * 2], 1)
|
||||
if helper_generic.isHostInPrivateIPRange(HOST):
|
||||
if helper_generic.isHostInPrivateIPRange(peer.host):
|
||||
continue
|
||||
addrsInChildStreamLeft[HOST] = shared.knownNodes[
|
||||
self.streamNumber * 2][HOST]
|
||||
addrsInChildStreamLeft[peer] = shared.knownNodes[
|
||||
self.streamNumber * 2][peer]
|
||||
if len(shared.knownNodes[(self.streamNumber * 2) + 1]) > 0:
|
||||
for i in range(250):
|
||||
random.seed()
|
||||
HOST, = random.sample(shared.knownNodes[
|
||||
peer, = random.sample(shared.knownNodes[
|
||||
(self.streamNumber * 2) + 1], 1)
|
||||
if helper_generic.isHostInPrivateIPRange(HOST):
|
||||
if helper_generic.isHostInPrivateIPRange(peer.host):
|
||||
continue
|
||||
addrsInChildStreamRight[HOST] = shared.knownNodes[
|
||||
(self.streamNumber * 2) + 1][HOST]
|
||||
addrsInChildStreamRight[peer] = shared.knownNodes[
|
||||
(self.streamNumber * 2) + 1][peer]
|
||||
shared.knownNodesLock.release()
|
||||
numberOfAddressesInAddrMessage = 0
|
||||
payload = ''
|
||||
# print 'addrsInMyStream.items()', addrsInMyStream.items()
|
||||
for HOST, value in addrsInMyStream.items():
|
||||
PORT, timeLastReceivedMessageFromThisNode = value
|
||||
for (HOST, PORT), value in addrsInMyStream.items():
|
||||
timeLastReceivedMessageFromThisNode = value
|
||||
if timeLastReceivedMessageFromThisNode > (int(time.time()) - shared.maximumAgeOfNodesThatIAdvertiseToOthers): # If it is younger than 3 hours old..
|
||||
numberOfAddressesInAddrMessage += 1
|
||||
payload += pack(
|
||||
|
@ -1954,8 +1947,8 @@ class receiveDataThread(threading.Thread):
|
|||
payload += '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF' + \
|
||||
socket.inet_aton(HOST)
|
||||
payload += pack('>H', PORT) # remote port
|
||||
for HOST, value in addrsInChildStreamLeft.items():
|
||||
PORT, timeLastReceivedMessageFromThisNode = value
|
||||
for (HOST, PORT), value in addrsInChildStreamLeft.items():
|
||||
timeLastReceivedMessageFromThisNode = value
|
||||
if timeLastReceivedMessageFromThisNode > (int(time.time()) - shared.maximumAgeOfNodesThatIAdvertiseToOthers): # If it is younger than 3 hours old..
|
||||
numberOfAddressesInAddrMessage += 1
|
||||
payload += pack(
|
||||
|
@ -1966,8 +1959,8 @@ class receiveDataThread(threading.Thread):
|
|||
payload += '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF' + \
|
||||
socket.inet_aton(HOST)
|
||||
payload += pack('>H', PORT) # remote port
|
||||
for HOST, value in addrsInChildStreamRight.items():
|
||||
PORT, timeLastReceivedMessageFromThisNode = value
|
||||
for (HOST, PORT), value in addrsInChildStreamRight.items():
|
||||
timeLastReceivedMessageFromThisNode = value
|
||||
if timeLastReceivedMessageFromThisNode > (int(time.time()) - shared.maximumAgeOfNodesThatIAdvertiseToOthers): # If it is younger than 3 hours old..
|
||||
numberOfAddressesInAddrMessage += 1
|
||||
payload += pack(
|
||||
|
@ -2004,9 +1997,9 @@ class receiveDataThread(threading.Thread):
|
|||
elif not self.verackSent:
|
||||
self.remoteProtocolVersion, = unpack('>L', data[:4])
|
||||
if self.remoteProtocolVersion <= 1:
|
||||
shared.broadcastToSendDataQueues((0, 'shutdown', self.HOST))
|
||||
shared.broadcastToSendDataQueues((0, 'shutdown', self.peer))
|
||||
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
|
||||
# print 'remoteProtocolVersion', self.remoteProtocolVersion
|
||||
|
@ -2028,30 +2021,29 @@ class receiveDataThread(threading.Thread):
|
|||
print 'Remote node useragent:', useragent, ' stream number:', self.streamNumber
|
||||
|
||||
if self.streamNumber != 1:
|
||||
shared.broadcastToSendDataQueues((0, 'shutdown', self.HOST))
|
||||
shared.broadcastToSendDataQueues((0, 'shutdown', self.peer))
|
||||
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
|
||||
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
|
||||
# doesn't know the stream. We have to set it.
|
||||
if not self.initiatedConnection:
|
||||
shared.broadcastToSendDataQueues((
|
||||
0, 'setStreamNumber', (self.HOST, self.streamNumber)))
|
||||
0, 'setStreamNumber', (self.peer, self.streamNumber)))
|
||||
if data[72:80] == shared.eightBytesOfRandomDataUsedToDetectConnectionsToSelf:
|
||||
shared.broadcastToSendDataQueues((0, 'shutdown', self.HOST))
|
||||
shared.broadcastToSendDataQueues((0, 'shutdown', self.peer))
|
||||
with shared.printLock:
|
||||
print 'Closing connection to myself: ', self.HOST
|
||||
print 'Closing connection to myself: ', self.peer
|
||||
|
||||
return
|
||||
shared.broadcastToSendDataQueues((0, 'setRemoteProtocolVersion', (
|
||||
self.HOST, self.remoteProtocolVersion)))
|
||||
self.peer, self.remoteProtocolVersion)))
|
||||
|
||||
shared.knownNodesLock.acquire()
|
||||
shared.knownNodes[self.streamNumber][self.HOST] = (
|
||||
self.remoteNodeIncomingPort, int(time.time()))
|
||||
shared.knownNodes[self.streamNumber][self.peer] = int(time.time())
|
||||
output = open(shared.appdata + 'knownnodes.dat', 'wb')
|
||||
pickle.dump(shared.knownNodes, output)
|
||||
output.close()
|
||||
|
@ -2068,7 +2060,7 @@ class receiveDataThread(threading.Thread):
|
|||
|
||||
try:
|
||||
self.sock.sendall(shared.assembleVersionMessage(
|
||||
self.HOST, self.PORT, self.streamNumber))
|
||||
self.peer.host, self.peer.port, self.streamNumber))
|
||||
except Exception as err:
|
||||
# if not 'Bad file descriptor' in err:
|
||||
with shared.printLock:
|
||||
|
|
|
@ -31,8 +31,7 @@ class sendDataThread(threading.Thread):
|
|||
streamNumber,
|
||||
someObjectsOfWhichThisRemoteNodeIsAlreadyAware):
|
||||
self.sock = sock
|
||||
self.HOST = HOST
|
||||
self.PORT = PORT
|
||||
self.peer = shared.Peer(HOST, PORT)
|
||||
self.streamNumber = streamNumber
|
||||
self.remoteProtocolVersion = - \
|
||||
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):
|
||||
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:
|
||||
print 'Sending version packet: ', repr(datatosend)
|
||||
|
@ -62,15 +61,12 @@ class sendDataThread(threading.Thread):
|
|||
def run(self):
|
||||
while True:
|
||||
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 command == 'shutdown':
|
||||
if data == self.HOST or data == 'all':
|
||||
if data == self.peer or data == 'all':
|
||||
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:
|
||||
self.sock.shutdown(socket.SHUT_RDWR)
|
||||
|
@ -89,15 +85,15 @@ class sendDataThread(threading.Thread):
|
|||
# will continue on with the connection and will set the
|
||||
# streamNumber of this send data thread here:
|
||||
elif command == 'setStreamNumber':
|
||||
hostInMessage, specifiedStreamNumber = data
|
||||
if hostInMessage == self.HOST:
|
||||
peerInMessage, specifiedStreamNumber = data
|
||||
if peerInMessage == self.peer:
|
||||
with shared.printLock:
|
||||
print 'setting the stream number in the sendData thread (ID:', id(self), ') to', specifiedStreamNumber
|
||||
|
||||
self.streamNumber = specifiedStreamNumber
|
||||
elif command == 'setRemoteProtocolVersion':
|
||||
hostInMessage, specifiedRemoteProtocolVersion = data
|
||||
if hostInMessage == self.HOST:
|
||||
peerInMessage, specifiedRemoteProtocolVersion = data
|
||||
if peerInMessage == self.peer:
|
||||
with shared.printLock:
|
||||
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.lastTimeISentData = int(time.time())
|
||||
except:
|
||||
print 'self.sock.sendall failed'
|
||||
print 'sendaddr: self.sock.sendall failed'
|
||||
try:
|
||||
self.sock.shutdown(socket.SHUT_RDWR)
|
||||
self.sock.close()
|
||||
except:
|
||||
pass
|
||||
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
|
||||
elif command == 'sendinv':
|
||||
if data not in self.someObjectsOfWhichThisRemoteNodeIsAlreadyAware:
|
||||
|
@ -137,21 +133,21 @@ class sendDataThread(threading.Thread):
|
|||
self.sock.sendall(headerData + payload)
|
||||
self.lastTimeISentData = int(time.time())
|
||||
except:
|
||||
print 'self.sock.sendall failed'
|
||||
print 'sendinv: self.sock.sendall failed'
|
||||
try:
|
||||
self.sock.shutdown(socket.SHUT_RDWR)
|
||||
self.sock.close()
|
||||
except:
|
||||
pass
|
||||
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
|
||||
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.
|
||||
if self.lastTimeISentData < (int(time.time()) - 298):
|
||||
# Send out a pong message to keep the connection alive.
|
||||
with shared.printLock:
|
||||
print 'Sending pong to', self.HOST, 'to keep connection alive.'
|
||||
print 'Sending pong to', self.peer, 'to keep connection alive.'
|
||||
|
||||
try:
|
||||
self.sock.sendall(
|
||||
|
@ -165,7 +161,7 @@ class sendDataThread(threading.Thread):
|
|||
except:
|
||||
pass
|
||||
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
|
||||
else:
|
||||
with shared.printLock:
|
||||
|
|
|
@ -33,9 +33,9 @@ class singleCleaner(threading.Thread):
|
|||
for hash, storedValue in shared.inventory.items():
|
||||
objectType, streamNumber, payload, receivedTime = storedValue
|
||||
if int(time.time()) - 3600 > receivedTime:
|
||||
t = (hash, objectType, streamNumber, payload, receivedTime)
|
||||
t = (hash, objectType, streamNumber, payload, receivedTime,'')
|
||||
shared.sqlSubmitQueue.put(
|
||||
'''INSERT INTO inventory VALUES (?,?,?,?,?)''')
|
||||
'''INSERT INTO inventory VALUES (?,?,?,?,?,?)''')
|
||||
shared.sqlSubmitQueue.put(t)
|
||||
shared.sqlReturnQueue.get()
|
||||
del shared.inventory[hash]
|
||||
|
|
|
@ -9,6 +9,7 @@ import proofofwork
|
|||
import sys
|
||||
from class_addressGenerator import pointMult
|
||||
import tr
|
||||
from debug import logger
|
||||
|
||||
# This thread, of which there is only one, does the heavy lifting:
|
||||
# calculating POWs.
|
||||
|
@ -271,172 +272,99 @@ class singleWorker(threading.Thread):
|
|||
fromaddress, subject, body, ackdata = row
|
||||
status, addressVersionNumber, streamNumber, ripe = decodeAddress(
|
||||
fromaddress)
|
||||
"""if addressVersionNumber == 2 and int(time.time()) < shared.encryptedBroadcastSwitchoverTime:
|
||||
# We need to convert our private keys to public keys in order
|
||||
# to include them.
|
||||
try:
|
||||
privSigningKeyBase58 = shared.config.get(
|
||||
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
|
||||
# to include them.
|
||||
try:
|
||||
privSigningKeyBase58 = shared.config.get(
|
||||
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(2) # broadcast version
|
||||
payload += encodeVarint(streamNumber)
|
||||
|
||||
dataToEncrypt = encodeVarint(2) # broadcast version
|
||||
dataToEncrypt += encodeVarint(addressVersionNumber)
|
||||
dataToEncrypt += encodeVarint(streamNumber)
|
||||
dataToEncrypt += '\x00\x00\x00\x01' # behavior bitfield
|
||||
dataToEncrypt += pubSigningKey[1:]
|
||||
dataToEncrypt += pubEncryptionKey[1:]
|
||||
if addressVersionNumber >= 3:
|
||||
dataToEncrypt += encodeVarint(shared.config.getint(fromaddress,'noncetrialsperbyte'))
|
||||
dataToEncrypt += encodeVarint(shared.config.getint(fromaddress,'payloadlengthextrabytes'))
|
||||
dataToEncrypt += '\x02' # message encoding type
|
||||
dataToEncrypt += encodeVarint(len('Subject:' + subject + '\n' + 'Body:' + body)) #Type 2 is simple UTF-8 message encoding per the documentation on the wiki.
|
||||
dataToEncrypt += 'Subject:' + subject + '\n' + 'Body:' + body
|
||||
signature = highlevelcrypto.sign(
|
||||
dataToEncrypt, privSigningKeyHex)
|
||||
dataToEncrypt += encodeVarint(len(signature))
|
||||
dataToEncrypt += signature
|
||||
|
||||
# Encrypt the broadcast with the information contained in the broadcaster's address. Anyone who knows the address can generate
|
||||
# the private encryption key to decrypt the broadcast. This provides virtually no privacy; its purpose is to keep questionable
|
||||
# and illegal content from flowing through the Internet connections and being stored on the disk of 3rd parties.
|
||||
privEncryptionKey = hashlib.sha512(encodeVarint(
|
||||
addressVersionNumber) + encodeVarint(streamNumber) + ripe).digest()[:32]
|
||||
pubEncryptionKey = pointMult(privEncryptionKey)
|
||||
payload += highlevelcrypto.encrypt(
|
||||
dataToEncrypt, pubEncryptionKey.encode('hex'))
|
||||
|
||||
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 'sending inv (within sendBroadcast function)'
|
||||
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 = (inventoryHash,'broadcastsent', int(
|
||||
time.time()), fromaddress, subject, body, 'broadcastqueued')
|
||||
shared.sqlSubmitQueue.put(
|
||||
'UPDATE sent SET msgid=?, 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()
|
||||
else:
|
||||
if addressVersionNumber <= 1:
|
||||
with shared.printLock:
|
||||
sys.stderr.write(
|
||||
'Error: In the singleWorker thread, the sendBroadcast function doesn\'t understand the address version.\n')
|
||||
return
|
||||
# We need to convert our private keys to public keys in order
|
||||
# to include them.
|
||||
try:
|
||||
privSigningKeyBase58 = shared.config.get(
|
||||
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(2) # broadcast version
|
||||
payload += encodeVarint(streamNumber)
|
||||
|
||||
dataToEncrypt = encodeVarint(2) # broadcast version
|
||||
dataToEncrypt += encodeVarint(addressVersionNumber)
|
||||
dataToEncrypt += encodeVarint(streamNumber)
|
||||
dataToEncrypt += '\x00\x00\x00\x01' # behavior bitfield
|
||||
dataToEncrypt += pubSigningKey[1:]
|
||||
dataToEncrypt += pubEncryptionKey[1:]
|
||||
if addressVersionNumber >= 3:
|
||||
dataToEncrypt += encodeVarint(shared.config.getint(fromaddress,'noncetrialsperbyte'))
|
||||
dataToEncrypt += encodeVarint(shared.config.getint(fromaddress,'payloadlengthextrabytes'))
|
||||
dataToEncrypt += '\x02' # message encoding type
|
||||
dataToEncrypt += encodeVarint(len('Subject:' + subject + '\n' + 'Body:' + body)) #Type 2 is simple UTF-8 message encoding per the documentation on the wiki.
|
||||
dataToEncrypt += 'Subject:' + subject + '\n' + 'Body:' + body
|
||||
signature = highlevelcrypto.sign(
|
||||
dataToEncrypt, privSigningKeyHex)
|
||||
dataToEncrypt += encodeVarint(len(signature))
|
||||
dataToEncrypt += signature
|
||||
|
||||
# Encrypt the broadcast with the information contained in the broadcaster's address. Anyone who knows the address can generate
|
||||
# the private encryption key to decrypt the broadcast. This provides virtually no privacy; its purpose is to keep questionable
|
||||
# and illegal content from flowing through the Internet connections and being stored on the disk of 3rd parties.
|
||||
privEncryptionKey = hashlib.sha512(encodeVarint(
|
||||
addressVersionNumber) + encodeVarint(streamNumber) + ripe).digest()[:32]
|
||||
pubEncryptionKey = pointMult(privEncryptionKey)
|
||||
payload += highlevelcrypto.encrypt(
|
||||
dataToEncrypt, pubEncryptionKey.encode('hex'))
|
||||
|
||||
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()))
|
||||
with shared.printLock:
|
||||
print 'sending inv (within sendBroadcast function) for object:', 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 = (inventoryHash,'broadcastsent', int(
|
||||
time.time()), ackdata)
|
||||
shared.sqlSubmitQueue.put(
|
||||
'UPDATE sent SET msgid=?, status=?, lastactiontime=? WHERE ackdata=?')
|
||||
shared.sqlSubmitQueue.put(t)
|
||||
queryreturn = shared.sqlReturnQueue.get()
|
||||
shared.sqlSubmitQueue.put('commit')
|
||||
shared.sqlLock.release()
|
||||
|
||||
|
||||
def sendMsg(self):
|
||||
# Check to see if there are any messages queued to be sent
|
||||
|
@ -590,6 +518,15 @@ class singleWorker(threading.Thread):
|
|||
pubkeyPayload[readPosition:readPosition + 10])
|
||||
readPosition += streamNumberLength
|
||||
behaviorBitfield = pubkeyPayload[readPosition:readPosition + 4]
|
||||
# Mobile users may ask us to include their address's RIPE hash on a message
|
||||
# unencrypted. Before we actually do it the sending human must check a box
|
||||
# in the settings menu to allow it.
|
||||
if shared.isBitSetWithinBitfield(behaviorBitfield,30): # if receiver is a mobile device who expects that their address RIPE is included unencrypted on the front of the message..
|
||||
if not shared.safeConfigGetBoolean('bitmessagesettings','willinglysendtomobile'): # if we are Not willing to include the receiver's RIPE hash on the message..
|
||||
logger.info('The receiver is a mobile user but the sender (you) has not selected that you are willing to send to mobiles. Aborting send.')
|
||||
shared.UISignalQueue.put(('updateSentItemStatusByAckdata',(ackdata,tr.translateText("MainWindow",'Problem: Destination is a mobile device who requests that the destination be included in the message but this is disallowed in your settings. %1').arg(unicode(strftime(shared.config.get('bitmessagesettings', 'timeformat'),localtime(int(time.time()))),'utf-8')))))
|
||||
# if the human changes their setting and then sends another message or restarts their client, this one will send at that time.
|
||||
continue
|
||||
readPosition += 4 # to bypass the bitfield of behaviors
|
||||
# pubSigningKeyBase256 =
|
||||
# pubkeyPayload[readPosition:readPosition+64] #We don't use this
|
||||
|
@ -736,6 +673,10 @@ class singleWorker(threading.Thread):
|
|||
with shared.printLock:
|
||||
print 'Not bothering to generate ackdata because we are sending to a chan.'
|
||||
fullAckPayload = ''
|
||||
elif not shared.isBitSetWithinBitfield(behaviorBitfield,31):
|
||||
with shared.printLock:
|
||||
print 'Not bothering to generate ackdata because the receiver said that they won\'t relay it anyway.'
|
||||
fullAckPayload = ''
|
||||
else:
|
||||
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.
|
||||
|
|
|
@ -46,7 +46,7 @@ class sqlThread(threading.Thread):
|
|||
self.cur.execute(
|
||||
'''CREATE TABLE pubkeys (hash blob, transmitdata blob, time int, usedpersonally text, UNIQUE(hash) ON CONFLICT REPLACE)''' )
|
||||
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(
|
||||
'''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
|
||||
|
@ -55,7 +55,7 @@ class sqlThread(threading.Thread):
|
|||
'''INSERT INTO subscriptions VALUES('Bitmessage new releases/announcements','BM-GtovgYdgs7qXPkoYaRgrLFuFKz1SFpsw',1)''')
|
||||
self.cur.execute(
|
||||
'''CREATE TABLE settings (key blob, value blob, UNIQUE(key) ON CONFLICT REPLACE)''' )
|
||||
self.cur.execute( '''INSERT INTO settings VALUES('version','1')''')
|
||||
self.cur.execute( '''INSERT INTO settings VALUES('version','2')''')
|
||||
self.cur.execute( '''INSERT INTO settings VALUES('lastvacuumtime',?)''', (
|
||||
int(time.time()),))
|
||||
self.conn.commit()
|
||||
|
@ -189,7 +189,20 @@ class sqlThread(threading.Thread):
|
|||
|
||||
if not shared.config.has_option('bitmessagesettings', 'sockslisten'):
|
||||
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:
|
||||
testpayload = '\x00\x00'
|
||||
t = ('1234', testpayload, '12345678', 'no')
|
||||
|
|
|
@ -5,19 +5,20 @@ import time
|
|||
import random
|
||||
import sys
|
||||
from time import strftime, localtime
|
||||
import shared
|
||||
|
||||
def createDefaultKnownNodes(appdata):
|
||||
############## Stream 1 ################
|
||||
stream1 = {}
|
||||
|
||||
stream1['85.171.174.131'] = (8444,int(time.time()))
|
||||
stream1['23.28.68.159'] = (8444,int(time.time()))
|
||||
stream1['66.108.210.240'] = (8080,int(time.time()))
|
||||
stream1['204.236.246.212'] = (8444,int(time.time()))
|
||||
stream1['78.81.56.239'] = (8444,int(time.time()))
|
||||
stream1['122.60.235.157'] = (8444,int(time.time()))
|
||||
stream1['204.236.246.212'] = (8444,int(time.time()))
|
||||
stream1['24.98.219.109'] = (8444,int(time.time()))
|
||||
stream1[shared.Peer('85.171.174.131', 8444)] = int(time.time())
|
||||
stream1[shared.Peer('23.28.68.159', 8444)] = int(time.time())
|
||||
stream1[shared.Peer('66.108.210.240', 8444)] = int(time.time())
|
||||
stream1[shared.Peer('204.236.246.212', 8444)] = int(time.time())
|
||||
stream1[shared.Peer('78.81.56.239', 8444)] = int(time.time())
|
||||
stream1[shared.Peer('122.60.235.157', 8444)] = int(time.time())
|
||||
stream1[shared.Peer('204.236.246.212', 8444)] = int(time.time())
|
||||
stream1[shared.Peer('24.98.219.109', 8444)] = int(time.time())
|
||||
|
||||
|
||||
############# Stream 2 #################
|
||||
|
@ -36,22 +37,25 @@ def createDefaultKnownNodes(appdata):
|
|||
#print stream1
|
||||
#print allKnownNodes
|
||||
|
||||
output = open(appdata + 'knownnodes.dat', 'wb')
|
||||
with open(appdata + 'knownnodes.dat', 'wb') as output:
|
||||
# Pickle dictionary using protocol 0.
|
||||
pickle.dump(allKnownNodes, output)
|
||||
|
||||
# Pickle dictionary using protocol 0.
|
||||
pickle.dump(allKnownNodes, output)
|
||||
|
||||
output.close()
|
||||
return allKnownNodes
|
||||
|
||||
def readDefaultKnownNodes(appdata):
|
||||
pickleFile = open(appdata + 'knownnodes.dat', 'rb')
|
||||
knownNodes = pickle.load(pickleFile)
|
||||
pickleFile.close()
|
||||
knownNodes
|
||||
for stream, storedValue in knownNodes.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')
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
|
|
@ -9,8 +9,20 @@ def knownNodes():
|
|||
# We shouldn't have to use the shared.knownNodesLock because this had
|
||||
# better be the only thread accessing knownNodes right now.
|
||||
pickleFile = open(shared.appdata + 'knownnodes.dat', 'rb')
|
||||
shared.knownNodes = pickle.load(pickleFile)
|
||||
loadedKnownNodes = pickle.load(pickleFile)
|
||||
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:
|
||||
shared.knownNodes = defaultKnownNodes.createDefaultKnownNodes(shared.appdata)
|
||||
if shared.config.getint('bitmessagesettings', 'settingsversion') > 6:
|
||||
|
@ -28,13 +40,13 @@ def dns():
|
|||
try:
|
||||
for item in socket.getaddrinfo('bootstrap8080.bitmessage.org', 80):
|
||||
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:
|
||||
print 'bootstrap8080.bitmessage.org DNS bootstrapping failed.'
|
||||
try:
|
||||
for item in socket.getaddrinfo('bootstrap8444.bitmessage.org', 80):
|
||||
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:
|
||||
print 'bootstrap8444.bitmessage.org DNS bootstrapping failed.'
|
||||
else:
|
||||
|
|
|
@ -5,19 +5,10 @@
|
|||
import sqlite3
|
||||
from time import strftime, localtime
|
||||
import sys
|
||||
import shared
|
||||
import string
|
||||
|
||||
APPNAME = "PyBitmessage"
|
||||
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 + "/"))
|
||||
appdata = shared.lookupAppdataFolder()
|
||||
|
||||
conn = sqlite3.connect( appdata + 'messages.dat' )
|
||||
conn.text_factory = str
|
||||
|
|
|
@ -9,6 +9,7 @@ useVeryEasyProofOfWorkForTesting = False # If you set this to True while on the
|
|||
|
||||
|
||||
# Libraries.
|
||||
import collections
|
||||
import ConfigParser
|
||||
import os
|
||||
import pickle
|
||||
|
@ -122,10 +123,8 @@ def assembleVersionMessage(remoteHost, remotePort, myStreamNumber):
|
|||
|
||||
random.seed()
|
||||
payload += eightBytesOfRandomDataUsedToDetectConnectionsToSelf
|
||||
userAgent = '/PyBitmessage:' + shared.softwareVersion + \
|
||||
'/' # Length of userAgent must be less than 253.
|
||||
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.
|
||||
userAgent = '/PyBitmessage:' + shared.softwareVersion + '/'
|
||||
payload += encodeVarint(len(userAgent))
|
||||
payload += userAgent
|
||||
payload += encodeVarint(
|
||||
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)
|
||||
privkey = fullString[:-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 '
|
||||
'failed. Here is the PRIVATE key: %s\n' % str(WIFstring))
|
||||
logger.critical('Major problem! When trying to decode one of your private keys, the checksum '
|
||||
'failed. Here is the PRIVATE key: %s' % str(WIFstring))
|
||||
return ""
|
||||
else:
|
||||
#checksum passed
|
||||
if privkey[0] == '\x80':
|
||||
return privkey[1:]
|
||||
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 '
|
||||
'PRIVATE key: %s\n' % str(WIFstring))
|
||||
'PRIVATE key: %s' % str(WIFstring))
|
||||
return ""
|
||||
|
||||
|
||||
|
@ -264,8 +263,7 @@ def reloadMyAddressHashes():
|
|||
myAddressesByHash[hash] = addressInKeysFile
|
||||
|
||||
else:
|
||||
logger.error('Error in reloadMyAddressHashes: Can\'t handle address '
|
||||
'versions other than 2 or 3.\n')
|
||||
logger.error('Error in reloadMyAddressHashes: Can\'t handle address versions other than 2 or 3.\n')
|
||||
|
||||
if not keyfileSecure:
|
||||
fixSensitiveFilePermissions(appdata + 'keys.dat', hasEnabledKeys)
|
||||
|
@ -341,8 +339,8 @@ def flushInventory():
|
|||
sqlLock.acquire()
|
||||
for hash, storedValue in inventory.items():
|
||||
objectType, streamNumber, payload, receivedTime = storedValue
|
||||
t = (hash,objectType,streamNumber,payload,receivedTime)
|
||||
sqlSubmitQueue.put('''INSERT INTO inventory VALUES (?,?,?,?,?)''')
|
||||
t = (hash,objectType,streamNumber,payload,receivedTime,'')
|
||||
sqlSubmitQueue.put('''INSERT INTO inventory VALUES (?,?,?,?,?,?)''')
|
||||
sqlSubmitQueue.put(t)
|
||||
sqlReturnQueue.get()
|
||||
del inventory[hash]
|
||||
|
@ -367,6 +365,19 @@ def checkSensitiveFilePermissions(filename):
|
|||
# Windows systems.
|
||||
return True
|
||||
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]
|
||||
disallowed_permissions = stat.S_IRWXG | stat.S_IRWXO
|
||||
return present_permissions & disallowed_permissions == 0
|
||||
|
@ -391,6 +402,14 @@ def fixSensitiveFilePermissions(filename, hasEnabledKeys):
|
|||
except Exception, e:
|
||||
logger.exception('Keyfile permissions could not be fixed.')
|
||||
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()
|
||||
from debug import logger
|
||||
|
|
Reference in New Issue
Block a user