Changelog update for 0.4.0 #516
17
arch.sh
17
arch.sh
|
@ -1,6 +1,5 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
GIT_APP=PyBitmessage
|
|
||||||
APP=pybitmessage
|
APP=pybitmessage
|
||||||
PREV_VERSION=0.4.0
|
PREV_VERSION=0.4.0
|
||||||
VERSION=0.4.0
|
VERSION=0.4.0
|
||||||
|
@ -26,12 +25,24 @@ make clean
|
||||||
rm -f archpackage/*.gz
|
rm -f archpackage/*.gz
|
||||||
|
|
||||||
# having the root directory called name-version seems essential
|
# having the root directory called name-version seems essential
|
||||||
mv ../${GIT_APP} ../${APP}-${VERSION}
|
mv ../${APP} ../${APP}-${VERSION}
|
||||||
tar -cvzf ${SOURCE} ../${APP}-${VERSION} --exclude-vcs
|
tar -cvzf ${SOURCE} ../${APP}-${VERSION} --exclude-vcs
|
||||||
|
|
||||||
# rename the root directory without the version number
|
# rename the root directory without the version number
|
||||||
mv ../${APP}-${VERSION} ../${GIT_APP}
|
mv ../${APP}-${VERSION} ../${APP}
|
||||||
|
|
||||||
# calculate the MD5 checksum
|
# calculate the MD5 checksum
|
||||||
CHECKSM=$(md5sum ${SOURCE})
|
CHECKSM=$(md5sum ${SOURCE})
|
||||||
sed -i "s/md5sums[^)]*)/md5sums=(${CHECKSM%% *})/g" archpackage/PKGBUILD
|
sed -i "s/md5sums[^)]*)/md5sums=(${CHECKSM%% *})/g" archpackage/PKGBUILD
|
||||||
|
|
||||||
|
cd archpackage
|
||||||
|
|
||||||
|
# Create the package
|
||||||
|
tar -c -f ${APP}-${VERSION}.pkg.tar .
|
||||||
|
sync
|
||||||
|
xz ${APP}-${VERSION}.pkg.tar
|
||||||
|
sync
|
||||||
|
|
||||||
|
# Move back to the original directory
|
||||||
|
cd ${CURRDIR}
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,7 @@ install=
|
||||||
changelog=
|
changelog=
|
||||||
source=($pkgname-$pkgver.tar.gz)
|
source=($pkgname-$pkgver.tar.gz)
|
||||||
noextract=()
|
noextract=()
|
||||||
md5sums=(ebf89129571571198473559b4b2e552c)
|
md5sums=(0ee9bcb11dc606788fde94c7857e8720)
|
||||||
build() {
|
build() {
|
||||||
cd "$srcdir/$pkgname-$pkgver"
|
cd "$srcdir/$pkgname-$pkgver"
|
||||||
./configure --prefix=/usr
|
./configure --prefix=/usr
|
||||||
|
|
55
debian/changelog
vendored
55
debian/changelog
vendored
|
@ -1,3 +1,58 @@
|
||||||
|
pybitmessage (0.4.0-1) raring; urgency=low
|
||||||
|
|
||||||
|
* Raised default demanded difficulty from 1 to 2 for new addresses
|
||||||
|
* Added v4 addresses:
|
||||||
|
pubkeys are now encrypted and tagged in the inventory
|
||||||
|
* Use locks when accessing dictionary inventory
|
||||||
|
* Refactored the way inv and addr messages are shared
|
||||||
|
* Give user feedback when disk is full
|
||||||
|
* Added chan true/false to listAddresses results
|
||||||
|
* When replying using chan address, send to whole chan not just sender
|
||||||
|
* Refactored of the way PyBitmessage looks for interesting new objects
|
||||||
|
in large inv messages from peers
|
||||||
|
* Show inventory lookup rate on Network Status tab
|
||||||
|
* Added SqlBulkExecute class
|
||||||
|
so we can update inventory with only one commit
|
||||||
|
* Updated Russian translations
|
||||||
|
* Move duplicated SQL code into helper
|
||||||
|
* Allow specification of alternate settings dir
|
||||||
|
via BITMESSAGE_HOME environment variable
|
||||||
|
* Removed use of gevent. Removed class_bgWorker.py
|
||||||
|
* Added Sip and PyQt to includes in build_osx.py
|
||||||
|
* Show number of each message type processed
|
||||||
|
in the API command clientStatus
|
||||||
|
* Use fast PoW
|
||||||
|
unless we're explicitly a frozen (binary) version of the code
|
||||||
|
* Enable user-set localization in settings
|
||||||
|
* Fix Archlinux package creation
|
||||||
|
* Fallback to language only localization when region doesn't match
|
||||||
|
* Fixed brew install instructions
|
||||||
|
* Added German translation
|
||||||
|
* Made inbox and sent messages table panels read-only
|
||||||
|
* Allow inbox and sent preview panels to resize
|
||||||
|
* Count RE: as a reply header, just like Re: so we don't chain Re: RE:
|
||||||
|
* Fix for traceback on OSX
|
||||||
|
* Added backend ability to understand shorter addresses
|
||||||
|
* Convert 'API Error' to raise APIError()
|
||||||
|
* Added option in settings to allow sending to a mobile device
|
||||||
|
(app not yet done)
|
||||||
|
* Added ability to start daemon mode when using Bitmessage as a module
|
||||||
|
* Improved the way client detects locale
|
||||||
|
* Added API commands:
|
||||||
|
getInboxMessageIds, getSentMessageIds, listAddressBookEntries,
|
||||||
|
trashSentMessageByAckData, addAddressBookEntry,
|
||||||
|
deleteAddressBookEntry, listAddresses2, listSubscriptions
|
||||||
|
* Set a maximum frequency for playing sounds
|
||||||
|
* Show Invalid Method error in same format as other API errors
|
||||||
|
* Update status of separate broadcasts separately
|
||||||
|
even if the sent data is identical
|
||||||
|
* Added Namecoin integration
|
||||||
|
* Internally distinguish peers by IP and port
|
||||||
|
* Inbox message retrieval API
|
||||||
|
functions now also returns read status
|
||||||
|
|
||||||
|
-- Bob Mottram (4096 bits) <bob@robotics.uk.to> Sat, 28 September 2013 09:54:00 +0100
|
||||||
|
|
||||||
pybitmessage (0.3.5-1) raring; urgency=low
|
pybitmessage (0.3.5-1) raring; urgency=low
|
||||||
|
|
||||||
* Inbox message retrieval API functions now also returns read status
|
* Inbox message retrieval API functions now also returns read status
|
||||||
|
|
2
debian/control
vendored
2
debian/control
vendored
|
@ -9,7 +9,7 @@ Vcs-Git: https://github.com/Bitmessage/PyBitmessage.git
|
||||||
|
|
||||||
Package: pybitmessage
|
Package: pybitmessage
|
||||||
Architecture: all
|
Architecture: all
|
||||||
Depends: ${shlibs:Depends}, ${misc:Depends}, python (>= 2.7.0), openssl, python-qt4, libqt4-dev (>= 4.8.0), python-qt4-dev, sqlite3, libsqlite3-dev, gst123
|
Depends: ${shlibs:Depends}, ${misc:Depends}, ${python:Depends}, python (>= 2.7), openssl, python-qt4, libqt4-dev (>= 4.8.0), python-qt4-dev, sqlite3, libsqlite3-dev, gst123
|
||||||
Suggests: libmessaging-menu-dev
|
Suggests: libmessaging-menu-dev
|
||||||
Description: Send encrypted messages
|
Description: Send encrypted messages
|
||||||
Bitmessage is a P2P communications protocol used to send encrypted
|
Bitmessage is a P2P communications protocol used to send encrypted
|
||||||
|
|
17
generate.sh
17
generate.sh
|
@ -7,25 +7,16 @@ rm -f Makefile rpmpackage/*.spec
|
||||||
packagemonkey -n "PyBitmessage" --version "0.4.0" --dir "." -l "mit" \
|
packagemonkey -n "PyBitmessage" --version "0.4.0" --dir "." -l "mit" \
|
||||||
-e "Bob Mottram (4096 bits) <bob@robotics.uk.to>" \
|
-e "Bob Mottram (4096 bits) <bob@robotics.uk.to>" \
|
||||||
--brief "Send encrypted messages" \
|
--brief "Send encrypted messages" \
|
||||||
--desc "Bitmessage is a P2P communications protocol used to send " \
|
--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." \
|
||||||
"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" \
|
--homepage "https://github.com/Bitmessage/PyBitmessage" --section "mail" \
|
||||||
--categories "Office/Email" \
|
--categories "Office/Email" \
|
||||||
--dependsdeb "python (>= 2.7.0), openssl, python-qt4, libqt4-dev " \
|
--dependsdeb "python (>= 2.7), openssl, python-qt4, libqt4-dev (>= 4.8.0), python-qt4-dev, sqlite3, libsqlite3-dev, gst123" \
|
||||||
"(>= 4.8.0), python-qt4-dev, sqlite3, libsqlite3-dev, gst123" \
|
|
||||||
--dependsrpm "python, PyQt4, openssl-compat-bitcoin-libs, gst123" \
|
--dependsrpm "python, PyQt4, openssl-compat-bitcoin-libs, gst123" \
|
||||||
--mainscript "bitmessagemain.py" \
|
--mainscript "bitmessagemain.py" \
|
||||||
--librarypath "/opt/openssl-compat-bitcoin/lib/" \
|
--librarypath "/opt/openssl-compat-bitcoin/lib/" \
|
||||||
--suggestsdeb "libmessaging-menu-dev" \
|
--suggestsdeb "libmessaging-menu-dev" \
|
||||||
--dependspuppy "openssl, python-qt4, sqlite3, sqlite3-dev, " \
|
--dependspuppy "openssl, python-qt4, sqlite3, sqlite3-dev, python-openssl, python-sip, gst123" \
|
||||||
"python-openssl, python-sip, gst123" \
|
--dependsarch "python2, qt4, python2-pyqt4, sqlite, openssl, mpg123" \
|
||||||
--dependsarch "python2, qt4, python2-pyqt4, sqlite, openssl, gst123" \
|
|
||||||
--suggestsarch "python2-gevent: Python network library that uses greenlet and libevent for easy and scalable concurrency" --pythonversion 2 \
|
--suggestsarch "python2-gevent: Python network library that uses greenlet and libevent for easy and scalable concurrency" --pythonversion 2 \
|
||||||
--dependsebuild "dev-libs/openssl, dev-python/PyQt4[${PYTHON_USEDEP}]" \
|
--dependsebuild "dev-libs/openssl, dev-python/PyQt4[${PYTHON_USEDEP}]" \
|
||||||
--buildebuild "\${PYTHON_DEPS}" --pythonreq "sqlite" \
|
--buildebuild "\${PYTHON_DEPS}" --pythonreq "sqlite" \
|
||||||
|
|
|
@ -69,6 +69,58 @@ make install -B DESTDIR=%{buildroot} PREFIX=/usr
|
||||||
%attr(644,root,root) /usr/share/icons/hicolor/24x24/apps/%{name}.png
|
%attr(644,root,root) /usr/share/icons/hicolor/24x24/apps/%{name}.png
|
||||||
|
|
||||||
%changelog
|
%changelog
|
||||||
|
* Sat Sep 28 2013 Bob Mottram (4096 bits) <bob@robotics.uk.to> - 0.4.0-1
|
||||||
|
- Raised default demanded difficulty from 1 to 2 for new addresses
|
||||||
|
- Added v4 addresses:
|
||||||
|
pubkeys are now encrypted and tagged in the inventory
|
||||||
|
- Use locks when accessing dictionary inventory
|
||||||
|
- Refactored the way inv and addr messages are shared
|
||||||
|
- Give user feedback when disk is full
|
||||||
|
- Added chan true/false to listAddresses results
|
||||||
|
- When replying using chan address, send to whole chan not just sender
|
||||||
|
- Refactored of the way PyBitmessage looks for interesting new objects
|
||||||
|
in large inv messages from peers
|
||||||
|
- Show inventory lookup rate on Network Status tab
|
||||||
|
- Added SqlBulkExecute class
|
||||||
|
so we can update inventory with only one commit
|
||||||
|
- Updated Russian translations
|
||||||
|
- Move duplicated SQL code into helper
|
||||||
|
- Allow specification of alternate settings dir
|
||||||
|
via BITMESSAGE_HOME environment variable
|
||||||
|
- Removed use of gevent. Removed class_bgWorker.py
|
||||||
|
- Added Sip and PyQt to includes in build_osx.py
|
||||||
|
- Show number of each message type processed
|
||||||
|
in the API command clientStatus
|
||||||
|
- Use fast PoW
|
||||||
|
unless we're explicitly a frozen (binary) version of the code
|
||||||
|
- Enable user-set localization in settings
|
||||||
|
- Fix Archlinux package creation
|
||||||
|
- Fallback to language only localization when region doesn't match
|
||||||
|
- Fixed brew install instructions
|
||||||
|
- Added German translation
|
||||||
|
- Made inbox and sent messages table panels read-only
|
||||||
|
- Allow inbox and sent preview panels to resize
|
||||||
|
- Count RE: as a reply header, just like Re: so we don't chain Re: RE:
|
||||||
|
- Fix for traceback on OSX
|
||||||
|
- Added backend ability to understand shorter addresses
|
||||||
|
- Convert 'API Error' to raise APIError()
|
||||||
|
- Added option in settings to allow sending to a mobile device
|
||||||
|
(app not yet done)
|
||||||
|
- Added ability to start daemon mode when using Bitmessage as a module
|
||||||
|
- Improved the way client detects locale
|
||||||
|
- Added API commands:
|
||||||
|
getInboxMessageIds, getSentMessageIds, listAddressBookEntries,
|
||||||
|
trashSentMessageByAckData, addAddressBookEntry,
|
||||||
|
deleteAddressBookEntry, listAddresses2, listSubscriptions
|
||||||
|
- Set a maximum frequency for playing sounds
|
||||||
|
- Show Invalid Method error in same format as other API errors
|
||||||
|
- Update status of separate broadcasts separately
|
||||||
|
even if the sent data is identical
|
||||||
|
- Added Namecoin integration
|
||||||
|
- Internally distinguish peers by IP and port
|
||||||
|
- Inbox message retrieval API
|
||||||
|
functions now also returns read status
|
||||||
|
|
||||||
* Mon Jul 29 2013 Bob Mottram (4096 bits) <bob@robotics.uk.to> - 0.3.5-1
|
* 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
|
- Inbox message retrieval API functions now also returns read status
|
||||||
- Added right-click option to mark a message as unread
|
- Added right-click option to mark a message as unread
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#!/usr/bin/env python2.7
|
#!/usr/bin/env python
|
||||||
# Copyright (c) 2012 Jonathan Warren
|
# Copyright (c) 2012 Jonathan Warren
|
||||||
# Copyright (c) 2012 The Bitmessage developers
|
# Copyright (c) 2012 The Bitmessage developers
|
||||||
# Distributed under the MIT/X11 software license. See the accompanying
|
# Distributed under the MIT/X11 software license. See the accompanying
|
||||||
|
@ -152,7 +152,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
|
||||||
return text.decode(decode_type)
|
return text.decode(decode_type)
|
||||||
except TypeError as e:
|
except TypeError as e:
|
||||||
raise APIError(22, "Decode error - " + str(e))
|
raise APIError(22, "Decode error - " + str(e))
|
||||||
|
|
||||||
def _verifyAddress(self, address):
|
def _verifyAddress(self, address):
|
||||||
status, addressVersionNumber, streamNumber, ripe = decodeAddress(address)
|
status, addressVersionNumber, streamNumber, ripe = decodeAddress(address)
|
||||||
if status != 'success':
|
if status != 'success':
|
||||||
|
@ -519,7 +519,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
|
||||||
if len(params) == 0:
|
if len(params) == 0:
|
||||||
raise APIError(0, 'I need parameters!')
|
raise APIError(0, 'I need parameters!')
|
||||||
msgid = self._decode(params[0], "hex")
|
msgid = self._decode(params[0], "hex")
|
||||||
|
|
||||||
# Trash if in inbox table
|
# Trash if in inbox table
|
||||||
helper_inbox.trash(msgid)
|
helper_inbox.trash(msgid)
|
||||||
# Trash if in sent table
|
# Trash if in sent table
|
||||||
|
@ -740,7 +740,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
|
||||||
trialValue, nonce = proofofwork.run(target, initialHash)
|
trialValue, nonce = proofofwork.run(target, initialHash)
|
||||||
print '(For pubkey message via API) Found proof of work', trialValue, 'Nonce:', nonce
|
print '(For pubkey message via API) Found proof of work', trialValue, 'Nonce:', nonce
|
||||||
payload = pack('>Q', nonce) + payload
|
payload = pack('>Q', nonce) + payload
|
||||||
|
|
||||||
pubkeyReadPosition = 8 # bypass the nonce
|
pubkeyReadPosition = 8 # bypass the nonce
|
||||||
if payload[pubkeyReadPosition:pubkeyReadPosition+4] == '\x00\x00\x00\x00': # if this pubkey uses 8 byte time
|
if payload[pubkeyReadPosition:pubkeyReadPosition+4] == '\x00\x00\x00\x00': # if this pubkey uses 8 byte time
|
||||||
pubkeyReadPosition += 8
|
pubkeyReadPosition += 8
|
||||||
|
@ -760,20 +760,20 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
|
||||||
shared.broadcastToSendDataQueues((
|
shared.broadcastToSendDataQueues((
|
||||||
streamNumber, 'advertiseobject', inventoryHash))
|
streamNumber, 'advertiseobject', inventoryHash))
|
||||||
elif method == 'getMessageDataByDestinationHash' or method == 'getMessageDataByDestinationTag':
|
elif method == 'getMessageDataByDestinationHash' or method == 'getMessageDataByDestinationTag':
|
||||||
# Method will eventually be used by a particular Android app to
|
# Method will eventually be used by a particular Android app to
|
||||||
# select relevant messages. Do not yet add this to the api
|
# select relevant messages. Do not yet add this to the api
|
||||||
# doc.
|
# doc.
|
||||||
|
|
||||||
if len(params) != 1:
|
if len(params) != 1:
|
||||||
raise APIError(0, 'I need 1 parameter!')
|
raise APIError(0, 'I need 1 parameter!')
|
||||||
requestedHash, = params
|
requestedHash, = params
|
||||||
if len(requestedHash) != 32:
|
if len(requestedHash) != 32:
|
||||||
raise APIError(19, 'The length of hash should be 32 bytes (encoded in hex thus 64 characters).')
|
raise APIError(19, 'The length of hash should be 32 bytes (encoded in hex thus 64 characters).')
|
||||||
requestedHash = self._decode(requestedHash, "hex")
|
requestedHash = self._decode(requestedHash, "hex")
|
||||||
|
|
||||||
# This is not a particularly commonly used API function. Before we
|
# 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
|
# use it we'll need to fill out a field in our inventory database
|
||||||
# which is blank by default (first20bytesofencryptedmessage).
|
# which is blank by default (first20bytesofencryptedmessage).
|
||||||
queryreturn = sqlQuery(
|
queryreturn = sqlQuery(
|
||||||
'''SELECT hash, payload FROM inventory WHERE tag = '' and objecttype = 'msg' ; ''')
|
'''SELECT hash, payload FROM inventory WHERE tag = '' and objecttype = 'msg' ; ''')
|
||||||
with SqlBulkExecute() as sql:
|
with SqlBulkExecute() as sql:
|
||||||
|
@ -783,7 +783,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
|
||||||
readPosition += decodeVarint(payload[readPosition:readPosition+10])[1] # Stream Number length
|
readPosition += decodeVarint(payload[readPosition:readPosition+10])[1] # Stream Number length
|
||||||
t = (payload[readPosition:readPosition+32],hash)
|
t = (payload[readPosition:readPosition+32],hash)
|
||||||
sql.execute('''UPDATE inventory SET tag=? WHERE hash=?; ''', *t)
|
sql.execute('''UPDATE inventory SET tag=? WHERE hash=?; ''', *t)
|
||||||
|
|
||||||
queryreturn = sqlQuery('''SELECT payload FROM inventory WHERE tag = ?''',
|
queryreturn = sqlQuery('''SELECT payload FROM inventory WHERE tag = ?''',
|
||||||
requestedHash)
|
requestedHash)
|
||||||
data = '{"receivedMessageDatas":['
|
data = '{"receivedMessageDatas":['
|
||||||
|
@ -795,7 +795,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
|
||||||
data += ']}'
|
data += ']}'
|
||||||
return data
|
return data
|
||||||
elif method == 'getPubkeyByHash':
|
elif method == 'getPubkeyByHash':
|
||||||
# Method will eventually be used by a particular Android app to
|
# Method will eventually be used by a particular Android app to
|
||||||
# retrieve pubkeys. Please do not yet add this to the api docs.
|
# retrieve pubkeys. Please do not yet add this to the api docs.
|
||||||
if len(params) != 1:
|
if len(params) != 1:
|
||||||
raise APIError(0, 'I need 1 parameter!')
|
raise APIError(0, 'I need 1 parameter!')
|
||||||
|
@ -937,25 +937,25 @@ class Main:
|
||||||
print 'Running as a daemon. You can use Ctrl+C to exit.'
|
print 'Running as a daemon. You can use Ctrl+C to exit.'
|
||||||
while True:
|
while True:
|
||||||
time.sleep(20)
|
time.sleep(20)
|
||||||
|
|
||||||
def stop(self):
|
def stop(self):
|
||||||
with shared.printLock:
|
with shared.printLock:
|
||||||
print 'Stopping Bitmessage Deamon.'
|
print 'Stopping Bitmessage Deamon.'
|
||||||
shared.doCleanShutdown()
|
shared.doCleanShutdown()
|
||||||
|
|
||||||
|
|
||||||
def getApiAddress(self):
|
def getApiAddress(self):
|
||||||
if not shared.safeConfigGetBoolean('bitmessagesettings', 'apienabled'):
|
if not shared.safeConfigGetBoolean('bitmessagesettings', 'apienabled'):
|
||||||
return None
|
return None
|
||||||
address = shared.config.get('bitmessagesettings', 'apiinterface')
|
address = shared.config.get('bitmessagesettings', 'apiinterface')
|
||||||
port = shared.config.getint('bitmessagesettings', 'apiport')
|
port = shared.config.getint('bitmessagesettings', 'apiport')
|
||||||
return {'address':address,'port':port}
|
return {'address':address,'port':port}
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
mainprogram = Main()
|
mainprogram = Main()
|
||||||
mainprogram.start()
|
mainprogram.start()
|
||||||
|
|
||||||
|
|
||||||
# So far, the creation of and management of the Bitmessage protocol and this
|
# So far, the creation of and management of the Bitmessage protocol and this
|
||||||
# client is a one-man operation. Bitcoin tips are quite appreciated.
|
# client is a one-man operation. Bitcoin tips are quite appreciated.
|
||||||
# 1H5XaDA6fYENLbknwZyjiYXYPQaFjjLX2u
|
# 1H5XaDA6fYENLbknwZyjiYXYPQaFjjLX2u
|
||||||
|
|
Reference in New Issue
Block a user