Runnable with both Python3 and Python2, with PyQt4 #2249
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
import collectd
|
import collectd
|
||||||
import json
|
import json
|
||||||
import xmlrpclib
|
from six.moves import xmlrpc_client as xmlrpclib
|
||||||
|
|
||||||
pybmurl = ""
|
pybmurl = ""
|
||||||
api = ""
|
api = ""
|
||||||
|
|
3
py3start.sh
Executable file
3
py3start.sh
Executable file
|
@ -0,0 +1,3 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
python3 pybitmessage/bitmessagemain.py "$@"
|
3
revert_blob_to_text.sh
Executable file
3
revert_blob_to_text.sh
Executable file
|
@ -0,0 +1,3 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
python3 pybitmessage/revert_blob_to_text.py "$@"
|
3
setup.py
3
setup.py
|
@ -4,6 +4,7 @@ import os
|
||||||
import platform
|
import platform
|
||||||
import shutil
|
import shutil
|
||||||
import sys
|
import sys
|
||||||
|
import six
|
||||||
|
|
||||||
from importlib import import_module
|
from importlib import import_module
|
||||||
from setuptools import setup, Extension
|
from setuptools import setup, Extension
|
||||||
|
@ -83,7 +84,7 @@ if __name__ == "__main__":
|
||||||
'images/kivy/text_images*.png'
|
'images/kivy/text_images*.png'
|
||||||
]}
|
]}
|
||||||
|
|
||||||
if sys.version_info[0] == 3:
|
if six.PY3:
|
||||||
packages.extend(
|
packages.extend(
|
||||||
[
|
[
|
||||||
'pybitmessage.bitmessagekivy',
|
'pybitmessage.bitmessagekivy',
|
||||||
|
|
|
@ -187,7 +187,7 @@ def decodeAddress(address):
|
||||||
integer = decodeBase58(address)
|
integer = decodeBase58(address)
|
||||||
if integer == 0:
|
if integer == 0:
|
||||||
status = 'invalidcharacters'
|
status = 'invalidcharacters'
|
||||||
return status, 0, 0, ''
|
return status, 0, 0, b''
|
||||||
# after converting to hex, the string will be prepended
|
# after converting to hex, the string will be prepended
|
||||||
# with a 0x and appended with a L in python2
|
# with a 0x and appended with a L in python2
|
||||||
hexdata = hex(integer)[2:].rstrip('L')
|
hexdata = hex(integer)[2:].rstrip('L')
|
||||||
|
@ -200,23 +200,23 @@ def decodeAddress(address):
|
||||||
|
|
||||||
if checksum != double_sha512(data[:-4])[0:4]:
|
if checksum != double_sha512(data[:-4])[0:4]:
|
||||||
status = 'checksumfailed'
|
status = 'checksumfailed'
|
||||||
return status, 0, 0, ''
|
return status, 0, 0, b''
|
||||||
|
|
||||||
try:
|
try:
|
||||||
addressVersionNumber, bytesUsedByVersionNumber = decodeVarint(data[:9])
|
addressVersionNumber, bytesUsedByVersionNumber = decodeVarint(data[:9])
|
||||||
except varintDecodeError as e:
|
except varintDecodeError as e:
|
||||||
logger.error(str(e))
|
logger.error(str(e))
|
||||||
status = 'varintmalformed'
|
status = 'varintmalformed'
|
||||||
return status, 0, 0, ''
|
return status, 0, 0, b''
|
||||||
|
|
||||||
if addressVersionNumber > 4:
|
if addressVersionNumber > 4:
|
||||||
logger.error('cannot decode address version numbers this high')
|
logger.error('cannot decode address version numbers this high')
|
||||||
status = 'versiontoohigh'
|
status = 'versiontoohigh'
|
||||||
return status, 0, 0, ''
|
return status, 0, 0, b''
|
||||||
elif addressVersionNumber == 0:
|
elif addressVersionNumber == 0:
|
||||||
logger.error('cannot decode address version numbers of zero.')
|
logger.error('cannot decode address version numbers of zero.')
|
||||||
status = 'versiontoohigh'
|
status = 'versiontoohigh'
|
||||||
return status, 0, 0, ''
|
return status, 0, 0, b''
|
||||||
|
|
||||||
try:
|
try:
|
||||||
streamNumber, bytesUsedByStreamNumber = \
|
streamNumber, bytesUsedByStreamNumber = \
|
||||||
|
@ -224,7 +224,7 @@ def decodeAddress(address):
|
||||||
except varintDecodeError as e:
|
except varintDecodeError as e:
|
||||||
logger.error(str(e))
|
logger.error(str(e))
|
||||||
status = 'varintmalformed'
|
status = 'varintmalformed'
|
||||||
return status, 0, 0, ''
|
return status, 0, 0, b''
|
||||||
|
|
||||||
status = 'success'
|
status = 'success'
|
||||||
if addressVersionNumber == 1:
|
if addressVersionNumber == 1:
|
||||||
|
@ -242,21 +242,21 @@ def decodeAddress(address):
|
||||||
return status, addressVersionNumber, streamNumber, \
|
return status, addressVersionNumber, streamNumber, \
|
||||||
b'\x00\x00' + embeddedRipeData
|
b'\x00\x00' + embeddedRipeData
|
||||||
elif len(embeddedRipeData) < 18:
|
elif len(embeddedRipeData) < 18:
|
||||||
return 'ripetooshort', 0, 0, ''
|
return 'ripetooshort', 0, 0, b''
|
||||||
elif len(embeddedRipeData) > 20:
|
elif len(embeddedRipeData) > 20:
|
||||||
return 'ripetoolong', 0, 0, ''
|
return 'ripetoolong', 0, 0, b''
|
||||||
return 'otherproblem', 0, 0, ''
|
return 'otherproblem', 0, 0, b''
|
||||||
elif addressVersionNumber == 4:
|
elif addressVersionNumber == 4:
|
||||||
embeddedRipeData = \
|
embeddedRipeData = \
|
||||||
data[bytesUsedByVersionNumber + bytesUsedByStreamNumber:-4]
|
data[bytesUsedByVersionNumber + bytesUsedByStreamNumber:-4]
|
||||||
if embeddedRipeData[0:1] == b'\x00':
|
if embeddedRipeData[0:1] == b'\x00':
|
||||||
# In order to enforce address non-malleability, encoded
|
# In order to enforce address non-malleability, encoded
|
||||||
# RIPE data must have NULL bytes removed from the front
|
# RIPE data must have NULL bytes removed from the front
|
||||||
return 'encodingproblem', 0, 0, ''
|
return 'encodingproblem', 0, 0, b''
|
||||||
elif len(embeddedRipeData) > 20:
|
elif len(embeddedRipeData) > 20:
|
||||||
return 'ripetoolong', 0, 0, ''
|
return 'ripetoolong', 0, 0, b''
|
||||||
elif len(embeddedRipeData) < 4:
|
elif len(embeddedRipeData) < 4:
|
||||||
return 'ripetooshort', 0, 0, ''
|
return 'ripetooshort', 0, 0, b''
|
||||||
x00string = b'\x00' * (20 - len(embeddedRipeData))
|
x00string = b'\x00' * (20 - len(embeddedRipeData))
|
||||||
return status, addressVersionNumber, streamNumber, \
|
return status, addressVersionNumber, streamNumber, \
|
||||||
x00string + embeddedRipeData
|
x00string + embeddedRipeData
|
||||||
|
|
105
src/api.py
105
src/api.py
|
@ -67,9 +67,12 @@ import subprocess # nosec B404
|
||||||
import time
|
import time
|
||||||
from binascii import hexlify, unhexlify
|
from binascii import hexlify, unhexlify
|
||||||
from struct import pack, unpack
|
from struct import pack, unpack
|
||||||
|
import sqlite3
|
||||||
|
|
||||||
import six
|
import six
|
||||||
from six.moves import configparser, http_client, xmlrpc_server
|
from six.moves import configparser, http_client, xmlrpc_server
|
||||||
|
from six.moves.reprlib import repr
|
||||||
|
from dbcompat import dbstr
|
||||||
|
|
||||||
import helper_inbox
|
import helper_inbox
|
||||||
import helper_sent
|
import helper_sent
|
||||||
|
@ -531,12 +534,12 @@ class BMRPCDispatcher(object):
|
||||||
message = shared.fixPotentiallyInvalidUTF8Data(message)
|
message = shared.fixPotentiallyInvalidUTF8Data(message)
|
||||||
return {
|
return {
|
||||||
'msgid': hexlify(msgid),
|
'msgid': hexlify(msgid),
|
||||||
'toAddress': toAddress,
|
'toAddress': toAddress.decode("utf-8", "replace"),
|
||||||
'fromAddress': fromAddress,
|
'fromAddress': fromAddress.decode("utf-8", "replace"),
|
||||||
'subject': base64.b64encode(subject),
|
'subject': base64.b64encode(subject),
|
||||||
'message': base64.b64encode(message),
|
'message': base64.b64encode(message),
|
||||||
'encodingType': encodingtype,
|
'encodingType': encodingtype,
|
||||||
'receivedTime': received,
|
'receivedTime': received.decode("utf-8", "replace"),
|
||||||
'read': read
|
'read': read
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -598,11 +601,12 @@ class BMRPCDispatcher(object):
|
||||||
"""
|
"""
|
||||||
queryreturn = sqlQuery(
|
queryreturn = sqlQuery(
|
||||||
"SELECT label, address from addressbook WHERE label = ?",
|
"SELECT label, address from addressbook WHERE label = ?",
|
||||||
label
|
dbstr(label)
|
||||||
) if label else sqlQuery("SELECT label, address from addressbook")
|
) if label else sqlQuery("SELECT label, address from addressbook")
|
||||||
data = []
|
data = []
|
||||||
for label, address in queryreturn:
|
for label, address in queryreturn:
|
||||||
label = shared.fixPotentiallyInvalidUTF8Data(label)
|
label = shared.fixPotentiallyInvalidUTF8Data(label)
|
||||||
|
address = address.decode("utf-8", "replace")
|
||||||
data.append({
|
data.append({
|
||||||
'label': base64.b64encode(label),
|
'label': base64.b64encode(label),
|
||||||
'address': address
|
'address': address
|
||||||
|
@ -618,12 +622,12 @@ class BMRPCDispatcher(object):
|
||||||
self._verifyAddress(address)
|
self._verifyAddress(address)
|
||||||
# TODO: add unique together constraint in the table
|
# TODO: add unique together constraint in the table
|
||||||
queryreturn = sqlQuery(
|
queryreturn = sqlQuery(
|
||||||
"SELECT address FROM addressbook WHERE address=?", address)
|
"SELECT address FROM addressbook WHERE address=?", dbstr(address))
|
||||||
if queryreturn != []:
|
if queryreturn != []:
|
||||||
raise APIError(
|
raise APIError(
|
||||||
16, 'You already have this address in your address book.')
|
16, 'You already have this address in your address book.')
|
||||||
|
|
||||||
sqlExecute("INSERT INTO addressbook VALUES(?,?)", label, address)
|
sqlExecute("INSERT INTO addressbook VALUES(?,?)", dbstr(label), dbstr(address))
|
||||||
queues.UISignalQueue.put(('rerenderMessagelistFromLabels', ''))
|
queues.UISignalQueue.put(('rerenderMessagelistFromLabels', ''))
|
||||||
queues.UISignalQueue.put(('rerenderMessagelistToLabels', ''))
|
queues.UISignalQueue.put(('rerenderMessagelistToLabels', ''))
|
||||||
queues.UISignalQueue.put(('rerenderAddressBook', ''))
|
queues.UISignalQueue.put(('rerenderAddressBook', ''))
|
||||||
|
@ -635,7 +639,7 @@ class BMRPCDispatcher(object):
|
||||||
"""Delete an entry from address book."""
|
"""Delete an entry from address book."""
|
||||||
address = addBMIfNotPresent(address)
|
address = addBMIfNotPresent(address)
|
||||||
self._verifyAddress(address)
|
self._verifyAddress(address)
|
||||||
sqlExecute('DELETE FROM addressbook WHERE address=?', address)
|
sqlExecute('DELETE FROM addressbook WHERE address=?', dbstr(address))
|
||||||
queues.UISignalQueue.put(('rerenderMessagelistFromLabels', ''))
|
queues.UISignalQueue.put(('rerenderMessagelistFromLabels', ''))
|
||||||
queues.UISignalQueue.put(('rerenderMessagelistToLabels', ''))
|
queues.UISignalQueue.put(('rerenderMessagelistToLabels', ''))
|
||||||
queues.UISignalQueue.put(('rerenderAddressBook', ''))
|
queues.UISignalQueue.put(('rerenderAddressBook', ''))
|
||||||
|
@ -919,6 +923,7 @@ class BMRPCDispatcher(object):
|
||||||
" ORDER BY received"
|
" ORDER BY received"
|
||||||
)
|
)
|
||||||
return {"inboxMessages": [
|
return {"inboxMessages": [
|
||||||
|
|
||||||
self._dump_inbox_message(*data) for data in queryreturn
|
self._dump_inbox_message(*data) for data in queryreturn
|
||||||
]}
|
]}
|
||||||
|
|
||||||
|
@ -953,19 +958,31 @@ class BMRPCDispatcher(object):
|
||||||
23, 'Bool expected in readStatus, saw %s instead.'
|
23, 'Bool expected in readStatus, saw %s instead.'
|
||||||
% type(readStatus))
|
% type(readStatus))
|
||||||
queryreturn = sqlQuery(
|
queryreturn = sqlQuery(
|
||||||
"SELECT read FROM inbox WHERE msgid=?", msgid)
|
"SELECT read FROM inbox WHERE msgid=?", sqlite3.Binary(msgid))
|
||||||
|
if len(queryreturn) < 1:
|
||||||
|
queryreturn = sqlQuery(
|
||||||
|
"SELECT read FROM inbox WHERE msgid=CAST(? AS TEXT)", msgid)
|
||||||
# UPDATE is slow, only update if status is different
|
# UPDATE is slow, only update if status is different
|
||||||
try:
|
try:
|
||||||
if (queryreturn[0][0] == 1) != readStatus:
|
if (queryreturn[0][0] == 1) != readStatus:
|
||||||
sqlExecute(
|
rowcount = sqlExecute(
|
||||||
"UPDATE inbox set read = ? WHERE msgid=?",
|
"UPDATE inbox set read = ? WHERE msgid=?",
|
||||||
|
readStatus, sqlite3.Binary(msgid))
|
||||||
|
if rowcount < 1:
|
||||||
|
rowcount = sqlExecute(
|
||||||
|
"UPDATE inbox set read = ? WHERE msgid=CAST(? AS TEXT)",
|
||||||
readStatus, msgid)
|
readStatus, msgid)
|
||||||
queues.UISignalQueue.put(('changedInboxUnread', None))
|
queues.UISignalQueue.put(('changedInboxUnread', None))
|
||||||
except IndexError:
|
except IndexError:
|
||||||
pass
|
pass
|
||||||
queryreturn = sqlQuery(
|
queryreturn = sqlQuery(
|
||||||
"SELECT msgid, toaddress, fromaddress, subject, received, message,"
|
"SELECT msgid, toaddress, fromaddress, subject, received, message,"
|
||||||
" encodingtype, read FROM inbox WHERE msgid=?", msgid
|
" encodingtype, read FROM inbox WHERE msgid=?", sqlite3.Binary(msgid)
|
||||||
|
)
|
||||||
|
if len(queryreturn) < 1:
|
||||||
|
queryreturn = sqlQuery(
|
||||||
|
"SELECT msgid, toaddress, fromaddress, subject, received, message,"
|
||||||
|
" encodingtype, read FROM inbox WHERE msgid=CAST(? AS TEXT)", msgid
|
||||||
)
|
)
|
||||||
try:
|
try:
|
||||||
return {"inboxMessage": [
|
return {"inboxMessage": [
|
||||||
|
@ -1018,7 +1035,7 @@ class BMRPCDispatcher(object):
|
||||||
queryreturn = sqlQuery(
|
queryreturn = sqlQuery(
|
||||||
"SELECT msgid, toaddress, fromaddress, subject, received,"
|
"SELECT msgid, toaddress, fromaddress, subject, received,"
|
||||||
" message, encodingtype, read FROM inbox WHERE folder='inbox'"
|
" message, encodingtype, read FROM inbox WHERE folder='inbox'"
|
||||||
" AND toAddress=?", toAddress)
|
" AND toAddress=?", dbstr(toAddress))
|
||||||
return {"inboxMessages": [
|
return {"inboxMessages": [
|
||||||
self._dump_inbox_message(*data) for data in queryreturn
|
self._dump_inbox_message(*data) for data in queryreturn
|
||||||
]}
|
]}
|
||||||
|
@ -1035,6 +1052,12 @@ class BMRPCDispatcher(object):
|
||||||
queryreturn = sqlQuery(
|
queryreturn = sqlQuery(
|
||||||
"SELECT msgid, toaddress, fromaddress, subject, lastactiontime,"
|
"SELECT msgid, toaddress, fromaddress, subject, lastactiontime,"
|
||||||
" message, encodingtype, status, ackdata FROM sent WHERE msgid=?",
|
" message, encodingtype, status, ackdata FROM sent WHERE msgid=?",
|
||||||
|
sqlite3.Binary(msgid)
|
||||||
|
)
|
||||||
|
if len(queryreturn) < 1:
|
||||||
|
queryreturn = sqlQuery(
|
||||||
|
"SELECT msgid, toaddress, fromaddress, subject, lastactiontime,"
|
||||||
|
" message, encodingtype, status, ackdata FROM sent WHERE msgid=CAST(? AS TEXT)",
|
||||||
msgid
|
msgid
|
||||||
)
|
)
|
||||||
try:
|
try:
|
||||||
|
@ -1055,7 +1078,7 @@ class BMRPCDispatcher(object):
|
||||||
"SELECT msgid, toaddress, fromaddress, subject, lastactiontime,"
|
"SELECT msgid, toaddress, fromaddress, subject, lastactiontime,"
|
||||||
" message, encodingtype, status, ackdata FROM sent"
|
" message, encodingtype, status, ackdata FROM sent"
|
||||||
" WHERE folder='sent' AND fromAddress=? ORDER BY lastactiontime",
|
" WHERE folder='sent' AND fromAddress=? ORDER BY lastactiontime",
|
||||||
fromAddress
|
dbstr(fromAddress)
|
||||||
)
|
)
|
||||||
return {"sentMessages": [
|
return {"sentMessages": [
|
||||||
self._dump_sent_message(*data) for data in queryreturn
|
self._dump_sent_message(*data) for data in queryreturn
|
||||||
|
@ -1072,7 +1095,13 @@ class BMRPCDispatcher(object):
|
||||||
queryreturn = sqlQuery(
|
queryreturn = sqlQuery(
|
||||||
"SELECT msgid, toaddress, fromaddress, subject, lastactiontime,"
|
"SELECT msgid, toaddress, fromaddress, subject, lastactiontime,"
|
||||||
" message, encodingtype, status, ackdata FROM sent"
|
" message, encodingtype, status, ackdata FROM sent"
|
||||||
" WHERE ackdata=?", ackData
|
" WHERE ackdata=?", sqlite3.Binary(ackData)
|
||||||
|
)
|
||||||
|
if len(queryreturn) < 1:
|
||||||
|
queryreturn = sqlQuery(
|
||||||
|
"SELECT msgid, toaddress, fromaddress, subject, lastactiontime,"
|
||||||
|
" message, encodingtype, status, ackdata FROM sent"
|
||||||
|
" WHERE ackdata=CAST(? AS TEXT)", ackData
|
||||||
)
|
)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
@ -1093,7 +1122,9 @@ class BMRPCDispatcher(object):
|
||||||
# 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
|
||||||
sqlExecute("UPDATE sent SET folder='trash' WHERE msgid=?", msgid)
|
rowcount = sqlExecute("UPDATE sent SET folder='trash' WHERE msgid=?", sqlite3.Binary(msgid))
|
||||||
|
if rowcount < 1:
|
||||||
|
sqlExecute("UPDATE sent SET folder='trash' WHERE msgid=CAST(? AS TEXT)", msgid)
|
||||||
return 'Trashed message (assuming message existed).'
|
return 'Trashed message (assuming message existed).'
|
||||||
|
|
||||||
@command('trashInboxMessage')
|
@command('trashInboxMessage')
|
||||||
|
@ -1107,7 +1138,9 @@ class BMRPCDispatcher(object):
|
||||||
def HandleTrashSentMessage(self, msgid):
|
def HandleTrashSentMessage(self, msgid):
|
||||||
"""Trash sent message by msgid (encoded in hex)."""
|
"""Trash sent message by msgid (encoded in hex)."""
|
||||||
msgid = self._decode(msgid, "hex")
|
msgid = self._decode(msgid, "hex")
|
||||||
sqlExecute('''UPDATE sent SET folder='trash' WHERE msgid=?''', msgid)
|
rowcount = sqlExecute('''UPDATE sent SET folder='trash' WHERE msgid=?''', sqlite3.Binary(msgid))
|
||||||
|
if rowcount < 1:
|
||||||
|
sqlExecute('''UPDATE sent SET folder='trash' WHERE msgid=CAST(? AS TEXT)''', msgid)
|
||||||
return 'Trashed sent message (assuming message existed).'
|
return 'Trashed sent message (assuming message existed).'
|
||||||
|
|
||||||
@command('sendMessage')
|
@command('sendMessage')
|
||||||
|
@ -1150,9 +1183,9 @@ class BMRPCDispatcher(object):
|
||||||
|
|
||||||
toLabel = ''
|
toLabel = ''
|
||||||
queryreturn = sqlQuery(
|
queryreturn = sqlQuery(
|
||||||
"SELECT label FROM addressbook WHERE address=?", toAddress)
|
"SELECT label FROM addressbook WHERE address=?", dbstr(toAddress))
|
||||||
try:
|
try:
|
||||||
toLabel = queryreturn[0][0]
|
toLabel = queryreturn[0][0].decode("utf-8", "replace")
|
||||||
except IndexError:
|
except IndexError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -1217,9 +1250,12 @@ class BMRPCDispatcher(object):
|
||||||
raise APIError(15, 'Invalid ackData object size.')
|
raise APIError(15, 'Invalid ackData object size.')
|
||||||
ackdata = self._decode(ackdata, "hex")
|
ackdata = self._decode(ackdata, "hex")
|
||||||
queryreturn = sqlQuery(
|
queryreturn = sqlQuery(
|
||||||
"SELECT status FROM sent where ackdata=?", ackdata)
|
"SELECT status FROM sent where ackdata=?", sqlite3.Binary(ackdata))
|
||||||
|
if len(queryreturn) < 1:
|
||||||
|
queryreturn = sqlQuery(
|
||||||
|
"SELECT status FROM sent where ackdata=CAST(? AS TEXT)", ackdata)
|
||||||
try:
|
try:
|
||||||
return queryreturn[0][0]
|
return queryreturn[0][0].decode("utf-8", "replace")
|
||||||
except IndexError:
|
except IndexError:
|
||||||
return 'notfound'
|
return 'notfound'
|
||||||
|
|
||||||
|
@ -1238,11 +1274,11 @@ class BMRPCDispatcher(object):
|
||||||
# First we must check to see if the address is already in the
|
# First we must check to see if the address is already in the
|
||||||
# subscriptions list.
|
# subscriptions list.
|
||||||
queryreturn = sqlQuery(
|
queryreturn = sqlQuery(
|
||||||
"SELECT * FROM subscriptions WHERE address=?", address)
|
"SELECT * FROM subscriptions WHERE address=?", dbstr(address))
|
||||||
if queryreturn:
|
if queryreturn:
|
||||||
raise APIError(16, 'You are already subscribed to that address.')
|
raise APIError(16, 'You are already subscribed to that address.')
|
||||||
sqlExecute(
|
sqlExecute(
|
||||||
"INSERT INTO subscriptions VALUES (?,?,?)", label, address, True)
|
"INSERT INTO subscriptions VALUES (?,?,?)", dbstr(label), dbstr(address), True)
|
||||||
shared.reloadBroadcastSendersForWhichImWatching()
|
shared.reloadBroadcastSendersForWhichImWatching()
|
||||||
queues.UISignalQueue.put(('rerenderMessagelistFromLabels', ''))
|
queues.UISignalQueue.put(('rerenderMessagelistFromLabels', ''))
|
||||||
queues.UISignalQueue.put(('rerenderSubscriptions', ''))
|
queues.UISignalQueue.put(('rerenderSubscriptions', ''))
|
||||||
|
@ -1256,7 +1292,7 @@ class BMRPCDispatcher(object):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
address = addBMIfNotPresent(address)
|
address = addBMIfNotPresent(address)
|
||||||
sqlExecute("DELETE FROM subscriptions WHERE address=?", address)
|
sqlExecute("DELETE FROM subscriptions WHERE address=?", dbstr(address))
|
||||||
shared.reloadBroadcastSendersForWhichImWatching()
|
shared.reloadBroadcastSendersForWhichImWatching()
|
||||||
queues.UISignalQueue.put(('rerenderMessagelistFromLabels', ''))
|
queues.UISignalQueue.put(('rerenderMessagelistFromLabels', ''))
|
||||||
queues.UISignalQueue.put(('rerenderSubscriptions', ''))
|
queues.UISignalQueue.put(('rerenderSubscriptions', ''))
|
||||||
|
@ -1274,6 +1310,7 @@ class BMRPCDispatcher(object):
|
||||||
data = []
|
data = []
|
||||||
for label, address, enabled in queryreturn:
|
for label, address, enabled in queryreturn:
|
||||||
label = shared.fixPotentiallyInvalidUTF8Data(label)
|
label = shared.fixPotentiallyInvalidUTF8Data(label)
|
||||||
|
address = address.decode("utf-8", "replace")
|
||||||
data.append({
|
data.append({
|
||||||
'label': base64.b64encode(label),
|
'label': base64.b64encode(label),
|
||||||
'address': address,
|
'address': address,
|
||||||
|
@ -1354,7 +1391,9 @@ class BMRPCDispatcher(object):
|
||||||
"""Trash a sent message by ackdata (hex encoded)"""
|
"""Trash a sent message by ackdata (hex encoded)"""
|
||||||
# This API method should only be used when msgid is not available
|
# This API method should only be used when msgid is not available
|
||||||
ackdata = self._decode(ackdata, "hex")
|
ackdata = self._decode(ackdata, "hex")
|
||||||
sqlExecute("UPDATE sent SET folder='trash' WHERE ackdata=?", ackdata)
|
rowcount = sqlExecute("UPDATE sent SET folder='trash' WHERE ackdata=?", sqlite3.Binary(ackdata))
|
||||||
|
if rowcount < 1:
|
||||||
|
sqlExecute("UPDATE sent SET folder='trash' WHERE ackdata=CAST(? AS TEXT)", ackdata)
|
||||||
return 'Trashed sent message (assuming message existed).'
|
return 'Trashed sent message (assuming message existed).'
|
||||||
|
|
||||||
@command('disseminatePubkey')
|
@command('disseminatePubkey')
|
||||||
|
@ -1421,19 +1460,29 @@ class BMRPCDispatcher(object):
|
||||||
# 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 = ''"
|
"SELECT hash, payload FROM inventory WHERE tag = ?"
|
||||||
" and objecttype = 2")
|
" and objecttype = 2", sqlite3.Binary(b""))
|
||||||
|
if len(queryreturn) < 1:
|
||||||
|
queryreturn = sqlQuery(
|
||||||
|
"SELECT hash, payload FROM inventory WHERE tag = CAST(? AS TEXT)"
|
||||||
|
" and objecttype = 2", b"")
|
||||||
with SqlBulkExecute() as sql:
|
with SqlBulkExecute() as sql:
|
||||||
for hash01, payload in queryreturn:
|
for hash01, payload in queryreturn:
|
||||||
readPosition = 16 # Nonce length + time length
|
readPosition = 16 # Nonce length + time length
|
||||||
# Stream Number length
|
# Stream Number length
|
||||||
readPosition += decodeVarint(
|
readPosition += decodeVarint(
|
||||||
payload[readPosition:readPosition + 10])[1]
|
payload[readPosition:readPosition + 10])[1]
|
||||||
t = (payload[readPosition:readPosition + 32], hash01)
|
t = (sqlite3.Binary(payload[readPosition:readPosition + 32]), sqlite3.Binary(hash01))
|
||||||
sql.execute("UPDATE inventory SET tag=? WHERE hash=?", *t)
|
_, rowcount = sql.execute("UPDATE inventory SET tag=? WHERE hash=?", *t)
|
||||||
|
if rowcount < 1:
|
||||||
|
t = (sqlite3.Binary(payload[readPosition:readPosition + 32]), hash01)
|
||||||
|
sql.execute("UPDATE inventory SET tag=? WHERE hash=CAST(? AS TEXT)", *t)
|
||||||
|
|
||||||
queryreturn = sqlQuery(
|
queryreturn = sqlQuery(
|
||||||
"SELECT payload FROM inventory WHERE tag = ?", requestedHash)
|
"SELECT payload FROM inventory WHERE tag = ?", sqlite3.Binary(requestedHash))
|
||||||
|
if len(queryreturn) < 1:
|
||||||
|
queryreturn = sqlQuery(
|
||||||
|
"SELECT payload FROM inventory WHERE tag = CAST(? AS TEXT)", requestedHash)
|
||||||
return {"receivedMessageDatas": [
|
return {"receivedMessageDatas": [
|
||||||
{'data': hexlify(payload)} for payload, in queryreturn
|
{'data': hexlify(payload)} for payload, in queryreturn
|
||||||
]}
|
]}
|
||||||
|
|
|
@ -21,7 +21,8 @@ import os
|
||||||
import socket
|
import socket
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
import xmlrpclib
|
from six.moves import xmlrpc_client as xmlrpclib
|
||||||
|
from six.moves import input as raw_input
|
||||||
|
|
||||||
from bmconfigparser import config
|
from bmconfigparser import config
|
||||||
|
|
||||||
|
|
|
@ -10,13 +10,15 @@ Bitmessage commandline interface
|
||||||
# * python2-pythondialog
|
# * python2-pythondialog
|
||||||
# * dialog
|
# * dialog
|
||||||
|
|
||||||
import ConfigParser
|
from six.moves import configparser
|
||||||
import curses
|
import curses
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
from textwrap import fill
|
from textwrap import fill
|
||||||
from threading import Timer
|
from threading import Timer
|
||||||
|
import six
|
||||||
|
import sqlite3
|
||||||
|
|
||||||
from dialog import Dialog
|
from dialog import Dialog
|
||||||
import helper_sent
|
import helper_sent
|
||||||
|
@ -30,6 +32,7 @@ import state
|
||||||
from addresses import addBMIfNotPresent, decodeAddress
|
from addresses import addBMIfNotPresent, decodeAddress
|
||||||
from bmconfigparser import config
|
from bmconfigparser import config
|
||||||
from helper_sql import sqlExecute, sqlQuery
|
from helper_sql import sqlExecute, sqlQuery
|
||||||
|
from dbcompat import dbstr
|
||||||
|
|
||||||
# pylint: disable=global-statement
|
# pylint: disable=global-statement
|
||||||
|
|
||||||
|
@ -105,7 +108,7 @@ def ascii(s):
|
||||||
"""ASCII values"""
|
"""ASCII values"""
|
||||||
r = ""
|
r = ""
|
||||||
for c in s:
|
for c in s:
|
||||||
if ord(c) in range(128):
|
if six.byte2int(c) in range(128):
|
||||||
r += c
|
r += c
|
||||||
return r
|
return r
|
||||||
|
|
||||||
|
@ -326,13 +329,13 @@ def handlech(c, stdscr):
|
||||||
if c != curses.ERR:
|
if c != curses.ERR:
|
||||||
global inboxcur, addrcur, sentcur, subcur, abookcur, blackcur
|
global inboxcur, addrcur, sentcur, subcur, abookcur, blackcur
|
||||||
if c in range(256):
|
if c in range(256):
|
||||||
if chr(c) in '12345678':
|
if six.int2byte(c) in '12345678':
|
||||||
global menutab
|
global menutab
|
||||||
menutab = int(chr(c))
|
menutab = int(six.int2byte(c))
|
||||||
elif chr(c) == 'q':
|
elif six.int2byte(c) == 'q':
|
||||||
global quit_
|
global quit_
|
||||||
quit_ = True
|
quit_ = True
|
||||||
elif chr(c) == '\n':
|
elif six.int2byte(c) == '\n':
|
||||||
curses.curs_set(1)
|
curses.curs_set(1)
|
||||||
d = Dialog(dialog="dialog")
|
d = Dialog(dialog="dialog")
|
||||||
if menutab == 1:
|
if menutab == 1:
|
||||||
|
@ -358,7 +361,9 @@ def handlech(c, stdscr):
|
||||||
inbox[inboxcur][1] +
|
inbox[inboxcur][1] +
|
||||||
"\"")
|
"\"")
|
||||||
data = "" # pyint: disable=redefined-outer-name
|
data = "" # pyint: disable=redefined-outer-name
|
||||||
ret = sqlQuery("SELECT message FROM inbox WHERE msgid=?", inbox[inboxcur][0])
|
ret = sqlQuery("SELECT message FROM inbox WHERE msgid=?", sqlite3.Binary(inbox[inboxcur][0]))
|
||||||
|
if len(ret) < 1:
|
||||||
|
ret = sqlQuery("SELECT message FROM inbox WHERE msgid=CAST(? AS TEXT)", inbox[inboxcur][0])
|
||||||
if ret != []:
|
if ret != []:
|
||||||
for row in ret:
|
for row in ret:
|
||||||
data, = row
|
data, = row
|
||||||
|
@ -367,12 +372,16 @@ def handlech(c, stdscr):
|
||||||
for i, item in enumerate(data.split("\n")):
|
for i, item in enumerate(data.split("\n")):
|
||||||
msg += fill(item, replace_whitespace=False) + "\n"
|
msg += fill(item, replace_whitespace=False) + "\n"
|
||||||
scrollbox(d, unicode(ascii(msg)), 30, 80)
|
scrollbox(d, unicode(ascii(msg)), 30, 80)
|
||||||
sqlExecute("UPDATE inbox SET read=1 WHERE msgid=?", inbox[inboxcur][0])
|
rowcount = sqlExecute("UPDATE inbox SET read=1 WHERE msgid=?", sqlite3.Binary(inbox[inboxcur][0]))
|
||||||
|
if rowcount < 1:
|
||||||
|
sqlExecute("UPDATE inbox SET read=1 WHERE msgid=CAST(? AS TEXT)", inbox[inboxcur][0])
|
||||||
inbox[inboxcur][7] = 1
|
inbox[inboxcur][7] = 1
|
||||||
else:
|
else:
|
||||||
scrollbox(d, unicode("Could not fetch message."))
|
scrollbox(d, unicode("Could not fetch message."))
|
||||||
elif t == "2": # Mark unread
|
elif t == "2": # Mark unread
|
||||||
sqlExecute("UPDATE inbox SET read=0 WHERE msgid=?", inbox[inboxcur][0])
|
rowcount = sqlExecute("UPDATE inbox SET read=0 WHERE msgid=?", sqlite3.Binary(inbox[inboxcur][0]))
|
||||||
|
if rowcount < 1:
|
||||||
|
sqlExecute("UPDATE inbox SET read=0 WHERE msgid=CAST(? AS TEXT)", inbox[inboxcur][0])
|
||||||
inbox[inboxcur][7] = 0
|
inbox[inboxcur][7] = 0
|
||||||
elif t == "3": # Reply
|
elif t == "3": # Reply
|
||||||
curses.curs_set(1)
|
curses.curs_set(1)
|
||||||
|
@ -396,11 +405,14 @@ def handlech(c, stdscr):
|
||||||
if not m[5][:4] == "Re: ":
|
if not m[5][:4] == "Re: ":
|
||||||
subject = "Re: " + m[5]
|
subject = "Re: " + m[5]
|
||||||
body = ""
|
body = ""
|
||||||
ret = sqlQuery("SELECT message FROM inbox WHERE msgid=?", m[0])
|
ret = sqlQuery("SELECT message FROM inbox WHERE msgid=?", sqlite3.Binary(m[0]))
|
||||||
|
if len(ret) < 1:
|
||||||
|
ret = sqlQuery("SELECT message FROM inbox WHERE msgid=CAST(? AS TEXT)", m[0])
|
||||||
if ret != []:
|
if ret != []:
|
||||||
body = "\n\n------------------------------------------------------\n"
|
body = "\n\n------------------------------------------------------\n"
|
||||||
for row in ret:
|
for row in ret:
|
||||||
body, = row
|
body, = row
|
||||||
|
body = body.decode("utf-8", "replace")
|
||||||
|
|
||||||
sendMessage(fromaddr, toaddr, ischan, subject, body, True)
|
sendMessage(fromaddr, toaddr, ischan, subject, body, True)
|
||||||
dialogreset(stdscr)
|
dialogreset(stdscr)
|
||||||
|
@ -410,7 +422,7 @@ def handlech(c, stdscr):
|
||||||
r, t = d.inputbox("Label for address \"" + addr + "\"")
|
r, t = d.inputbox("Label for address \"" + addr + "\"")
|
||||||
if r == d.DIALOG_OK:
|
if r == d.DIALOG_OK:
|
||||||
label = t
|
label = t
|
||||||
sqlExecute("INSERT INTO addressbook VALUES (?,?)", label, addr)
|
sqlExecute("INSERT INTO addressbook VALUES (?,?)", dbstr(label), dbstr(addr))
|
||||||
# Prepend entry
|
# Prepend entry
|
||||||
addrbook.reverse()
|
addrbook.reverse()
|
||||||
addrbook.append([label, addr])
|
addrbook.append([label, addr])
|
||||||
|
@ -422,17 +434,22 @@ def handlech(c, stdscr):
|
||||||
r, t = d.inputbox("Filename", init=inbox[inboxcur][5] + ".txt")
|
r, t = d.inputbox("Filename", init=inbox[inboxcur][5] + ".txt")
|
||||||
if r == d.DIALOG_OK:
|
if r == d.DIALOG_OK:
|
||||||
msg = ""
|
msg = ""
|
||||||
ret = sqlQuery("SELECT message FROM inbox WHERE msgid=?", inbox[inboxcur][0])
|
ret = sqlQuery("SELECT message FROM inbox WHERE msgid=?", sqlite3.Binary(inbox[inboxcur][0]))
|
||||||
|
if len(ret) < 1:
|
||||||
|
ret = sqlQuery("SELECT message FROM inbox WHERE msgid=CAST(? AS TEXT)", inbox[inboxcur][0])
|
||||||
if ret != []:
|
if ret != []:
|
||||||
for row in ret:
|
for row in ret:
|
||||||
msg, = row
|
msg, = row
|
||||||
|
msg = msg.decode("utf-8", "replace")
|
||||||
fh = open(t, "a") # Open in append mode just in case
|
fh = open(t, "a") # Open in append mode just in case
|
||||||
fh.write(msg)
|
fh.write(msg)
|
||||||
fh.close()
|
fh.close()
|
||||||
else:
|
else:
|
||||||
scrollbox(d, unicode("Could not fetch message."))
|
scrollbox(d, unicode("Could not fetch message."))
|
||||||
elif t == "6": # Move to trash
|
elif t == "6": # Move to trash
|
||||||
sqlExecute("UPDATE inbox SET folder='trash' WHERE msgid=?", inbox[inboxcur][0])
|
rowcount = sqlExecute("UPDATE inbox SET folder='trash' WHERE msgid=?", sqlite3.Binary(inbox[inboxcur][0]))
|
||||||
|
if rowcount < 1:
|
||||||
|
sqlExecute("UPDATE inbox SET folder='trash' WHERE msgid=CAST(? AS TEXT)", inbox[inboxcur][0])
|
||||||
del inbox[inboxcur]
|
del inbox[inboxcur]
|
||||||
scrollbox(d, unicode(
|
scrollbox(d, unicode(
|
||||||
"Message moved to trash. There is no interface to view your trash,"
|
"Message moved to trash. There is no interface to view your trash,"
|
||||||
|
@ -463,7 +480,12 @@ def handlech(c, stdscr):
|
||||||
data = ""
|
data = ""
|
||||||
ret = sqlQuery(
|
ret = sqlQuery(
|
||||||
"SELECT message FROM sent WHERE subject=? AND ackdata=?",
|
"SELECT message FROM sent WHERE subject=? AND ackdata=?",
|
||||||
sentbox[sentcur][4],
|
dbstr(sentbox[sentcur][4]),
|
||||||
|
sqlite3.Binary(sentbox[sentcur][6]))
|
||||||
|
if len(ret) < 1:
|
||||||
|
ret = sqlQuery(
|
||||||
|
"SELECT message FROM sent WHERE subject=? AND ackdata=CAST(? AS TEXT)",
|
||||||
|
dbstr(sentbox[sentcur][4]),
|
||||||
sentbox[sentcur][6])
|
sentbox[sentcur][6])
|
||||||
if ret != []:
|
if ret != []:
|
||||||
for row in ret:
|
for row in ret:
|
||||||
|
@ -476,9 +498,14 @@ def handlech(c, stdscr):
|
||||||
else:
|
else:
|
||||||
scrollbox(d, unicode("Could not fetch message."))
|
scrollbox(d, unicode("Could not fetch message."))
|
||||||
elif t == "2": # Move to trash
|
elif t == "2": # Move to trash
|
||||||
sqlExecute(
|
rowcount = sqlExecute(
|
||||||
"UPDATE sent SET folder='trash' WHERE subject=? AND ackdata=?",
|
"UPDATE sent SET folder='trash' WHERE subject=? AND ackdata=?",
|
||||||
sentbox[sentcur][4],
|
dbstr(sentbox[sentcur][4]),
|
||||||
|
sqlite3.Binary(sentbox[sentcur][6]))
|
||||||
|
if rowcount < 1:
|
||||||
|
rowcount = sqlExecute(
|
||||||
|
"UPDATE sent SET folder='trash' WHERE subject=? AND ackdata=CAST(? AS TEXT)",
|
||||||
|
dbstr(sentbox[sentcur][4]),
|
||||||
sentbox[sentcur][6])
|
sentbox[sentcur][6])
|
||||||
del sentbox[sentcur]
|
del sentbox[sentcur]
|
||||||
scrollbox(d, unicode(
|
scrollbox(d, unicode(
|
||||||
|
@ -672,7 +699,7 @@ def handlech(c, stdscr):
|
||||||
elif t == "2" and m is False:
|
elif t == "2" and m is False:
|
||||||
try:
|
try:
|
||||||
mn = config.get(a, "mailinglistname")
|
mn = config.get(a, "mailinglistname")
|
||||||
except ConfigParser.NoOptionError:
|
except configparser.NoOptionError:
|
||||||
mn = ""
|
mn = ""
|
||||||
r, t = d.inputbox("Mailing list name", init=mn)
|
r, t = d.inputbox("Mailing list name", init=mn)
|
||||||
if r == d.DIALOG_OK:
|
if r == d.DIALOG_OK:
|
||||||
|
@ -711,29 +738,29 @@ def handlech(c, stdscr):
|
||||||
subscriptions.append([label, addr, True])
|
subscriptions.append([label, addr, True])
|
||||||
subscriptions.reverse()
|
subscriptions.reverse()
|
||||||
|
|
||||||
sqlExecute("INSERT INTO subscriptions VALUES (?,?,?)", label, addr, True)
|
sqlExecute("INSERT INTO subscriptions VALUES (?,?,?)", dbstr(label), dbstr(addr), True)
|
||||||
shared.reloadBroadcastSendersForWhichImWatching()
|
shared.reloadBroadcastSendersForWhichImWatching()
|
||||||
elif t == "2":
|
elif t == "2":
|
||||||
r, t = d.inputbox("Type in \"I want to delete this subscription\"")
|
r, t = d.inputbox("Type in \"I want to delete this subscription\"")
|
||||||
if r == d.DIALOG_OK and t == "I want to delete this subscription":
|
if r == d.DIALOG_OK and t == "I want to delete this subscription":
|
||||||
sqlExecute(
|
sqlExecute(
|
||||||
"DELETE FROM subscriptions WHERE label=? AND address=?",
|
"DELETE FROM subscriptions WHERE label=? AND address=?",
|
||||||
subscriptions[subcur][0],
|
dbstr(subscriptions[subcur][0]),
|
||||||
subscriptions[subcur][1])
|
dbstr(subscriptions[subcur][1]))
|
||||||
shared.reloadBroadcastSendersForWhichImWatching()
|
shared.reloadBroadcastSendersForWhichImWatching()
|
||||||
del subscriptions[subcur]
|
del subscriptions[subcur]
|
||||||
elif t == "3":
|
elif t == "3":
|
||||||
sqlExecute(
|
sqlExecute(
|
||||||
"UPDATE subscriptions SET enabled=1 WHERE label=? AND address=?",
|
"UPDATE subscriptions SET enabled=1 WHERE label=? AND address=?",
|
||||||
subscriptions[subcur][0],
|
dbstr(subscriptions[subcur][0]),
|
||||||
subscriptions[subcur][1])
|
dbstr(subscriptions[subcur][1]))
|
||||||
shared.reloadBroadcastSendersForWhichImWatching()
|
shared.reloadBroadcastSendersForWhichImWatching()
|
||||||
subscriptions[subcur][2] = True
|
subscriptions[subcur][2] = True
|
||||||
elif t == "4":
|
elif t == "4":
|
||||||
sqlExecute(
|
sqlExecute(
|
||||||
"UPDATE subscriptions SET enabled=0 WHERE label=? AND address=?",
|
"UPDATE subscriptions SET enabled=0 WHERE label=? AND address=?",
|
||||||
subscriptions[subcur][0],
|
dbstr(subscriptions[subcur][0]),
|
||||||
subscriptions[subcur][1])
|
dbstr(subscriptions[subcur][1]))
|
||||||
shared.reloadBroadcastSendersForWhichImWatching()
|
shared.reloadBroadcastSendersForWhichImWatching()
|
||||||
subscriptions[subcur][2] = False
|
subscriptions[subcur][2] = False
|
||||||
elif menutab == 6:
|
elif menutab == 6:
|
||||||
|
@ -762,7 +789,7 @@ def handlech(c, stdscr):
|
||||||
subscriptions.append([label, addr, True])
|
subscriptions.append([label, addr, True])
|
||||||
subscriptions.reverse()
|
subscriptions.reverse()
|
||||||
|
|
||||||
sqlExecute("INSERT INTO subscriptions VALUES (?,?,?)", label, addr, True)
|
sqlExecute("INSERT INTO subscriptions VALUES (?,?,?)", dbstr(label), dbstr(addr), True)
|
||||||
shared.reloadBroadcastSendersForWhichImWatching()
|
shared.reloadBroadcastSendersForWhichImWatching()
|
||||||
elif t == "3":
|
elif t == "3":
|
||||||
r, t = d.inputbox("Input new address")
|
r, t = d.inputbox("Input new address")
|
||||||
|
@ -771,7 +798,7 @@ def handlech(c, stdscr):
|
||||||
if addr not in [item[1] for i, item in enumerate(addrbook)]:
|
if addr not in [item[1] for i, item in enumerate(addrbook)]:
|
||||||
r, t = d.inputbox("Label for address \"" + addr + "\"")
|
r, t = d.inputbox("Label for address \"" + addr + "\"")
|
||||||
if r == d.DIALOG_OK:
|
if r == d.DIALOG_OK:
|
||||||
sqlExecute("INSERT INTO addressbook VALUES (?,?)", t, addr)
|
sqlExecute("INSERT INTO addressbook VALUES (?,?)", dbstr(t), dbstr(addr))
|
||||||
# Prepend entry
|
# Prepend entry
|
||||||
addrbook.reverse()
|
addrbook.reverse()
|
||||||
addrbook.append([t, addr])
|
addrbook.append([t, addr])
|
||||||
|
@ -783,8 +810,8 @@ def handlech(c, stdscr):
|
||||||
if r == d.DIALOG_OK and t == "I want to delete this Address Book entry":
|
if r == d.DIALOG_OK and t == "I want to delete this Address Book entry":
|
||||||
sqlExecute(
|
sqlExecute(
|
||||||
"DELETE FROM addressbook WHERE label=? AND address=?",
|
"DELETE FROM addressbook WHERE label=? AND address=?",
|
||||||
addrbook[abookcur][0],
|
dbstr(addrbook[abookcur][0]),
|
||||||
addrbook[abookcur][1])
|
dbstr(addrbook[abookcur][1]))
|
||||||
del addrbook[abookcur]
|
del addrbook[abookcur]
|
||||||
elif menutab == 7:
|
elif menutab == 7:
|
||||||
set_background_title(d, "Blacklist Dialog Box")
|
set_background_title(d, "Blacklist Dialog Box")
|
||||||
|
@ -800,20 +827,20 @@ def handlech(c, stdscr):
|
||||||
if r == d.DIALOG_OK and t == "I want to delete this Blacklist entry":
|
if r == d.DIALOG_OK and t == "I want to delete this Blacklist entry":
|
||||||
sqlExecute(
|
sqlExecute(
|
||||||
"DELETE FROM blacklist WHERE label=? AND address=?",
|
"DELETE FROM blacklist WHERE label=? AND address=?",
|
||||||
blacklist[blackcur][0],
|
dbstr(blacklist[blackcur][0]),
|
||||||
blacklist[blackcur][1])
|
dbstr(blacklist[blackcur][1]))
|
||||||
del blacklist[blackcur]
|
del blacklist[blackcur]
|
||||||
elif t == "2":
|
elif t == "2":
|
||||||
sqlExecute(
|
sqlExecute(
|
||||||
"UPDATE blacklist SET enabled=1 WHERE label=? AND address=?",
|
"UPDATE blacklist SET enabled=1 WHERE label=? AND address=?",
|
||||||
blacklist[blackcur][0],
|
dbstr(blacklist[blackcur][0]),
|
||||||
blacklist[blackcur][1])
|
dbstr(blacklist[blackcur][1]))
|
||||||
blacklist[blackcur][2] = True
|
blacklist[blackcur][2] = True
|
||||||
elif t == "3":
|
elif t == "3":
|
||||||
sqlExecute(
|
sqlExecute(
|
||||||
"UPDATE blacklist SET enabled=0 WHERE label=? AND address=?",
|
"UPDATE blacklist SET enabled=0 WHERE label=? AND address=?",
|
||||||
blacklist[blackcur][0],
|
dbstr(blacklist[blackcur][0]),
|
||||||
blacklist[blackcur][1])
|
dbstr(blacklist[blackcur][1]))
|
||||||
blacklist[blackcur][2] = False
|
blacklist[blackcur][2] = False
|
||||||
dialogreset(stdscr)
|
dialogreset(stdscr)
|
||||||
else:
|
else:
|
||||||
|
@ -991,10 +1018,13 @@ def loadInbox():
|
||||||
ret = sqlQuery("""SELECT msgid, toaddress, fromaddress, subject, received, read
|
ret = sqlQuery("""SELECT msgid, toaddress, fromaddress, subject, received, read
|
||||||
FROM inbox WHERE folder='inbox' AND %s LIKE ?
|
FROM inbox WHERE folder='inbox' AND %s LIKE ?
|
||||||
ORDER BY received
|
ORDER BY received
|
||||||
""" % (where,), what)
|
""" % (where,), dbstr(what))
|
||||||
for row in ret:
|
for row in ret:
|
||||||
msgid, toaddr, fromaddr, subject, received, read = row
|
msgid, toaddr, fromaddr, subject, received, read = row
|
||||||
|
toaddr = toaddr.decode("utf-8", "replace")
|
||||||
|
fromaddr = fromaddr.decode("utf-8", "replace")
|
||||||
subject = ascii(shared.fixPotentiallyInvalidUTF8Data(subject))
|
subject = ascii(shared.fixPotentiallyInvalidUTF8Data(subject))
|
||||||
|
received = received.decode("utf-8", "replace")
|
||||||
|
|
||||||
# Set label for to address
|
# Set label for to address
|
||||||
try:
|
try:
|
||||||
|
@ -1013,18 +1043,19 @@ def loadInbox():
|
||||||
if config.has_section(fromaddr):
|
if config.has_section(fromaddr):
|
||||||
fromlabel = config.get(fromaddr, "label")
|
fromlabel = config.get(fromaddr, "label")
|
||||||
if fromlabel == "": # Check Address Book
|
if fromlabel == "": # Check Address Book
|
||||||
qr = sqlQuery("SELECT label FROM addressbook WHERE address=?", fromaddr)
|
qr = sqlQuery("SELECT label FROM addressbook WHERE address=?", dbstr(fromaddr))
|
||||||
if qr != []:
|
if qr != []:
|
||||||
for r in qr:
|
for r in qr:
|
||||||
fromlabel, = r
|
fromlabel, = r
|
||||||
|
fromlabel = shared.fixPotentiallyInvalidUTF8Data(fromlabel)
|
||||||
if fromlabel == "": # Check Subscriptions
|
if fromlabel == "": # Check Subscriptions
|
||||||
qr = sqlQuery("SELECT label FROM subscriptions WHERE address=?", fromaddr)
|
qr = sqlQuery("SELECT label FROM subscriptions WHERE address=?", dbstr(fromaddr))
|
||||||
if qr != []:
|
if qr != []:
|
||||||
for r in qr:
|
for r in qr:
|
||||||
fromlabel, = r
|
fromlabel, = r
|
||||||
|
fromlabel = shared.fixPotentiallyInvalidUTF8Data(fromlabel)
|
||||||
if fromlabel == "":
|
if fromlabel == "":
|
||||||
fromlabel = fromaddr
|
fromlabel = fromaddr
|
||||||
fromlabel = shared.fixPotentiallyInvalidUTF8Data(fromlabel)
|
|
||||||
|
|
||||||
# Load into array
|
# Load into array
|
||||||
inbox.append([
|
inbox.append([
|
||||||
|
@ -1044,22 +1075,27 @@ def loadSent():
|
||||||
ret = sqlQuery("""SELECT toaddress, fromaddress, subject, status, ackdata, lastactiontime
|
ret = sqlQuery("""SELECT toaddress, fromaddress, subject, status, ackdata, lastactiontime
|
||||||
FROM sent WHERE folder='sent' AND %s LIKE ?
|
FROM sent WHERE folder='sent' AND %s LIKE ?
|
||||||
ORDER BY lastactiontime
|
ORDER BY lastactiontime
|
||||||
""" % (where,), what)
|
""" % (where,), dbstr(what))
|
||||||
for row in ret:
|
for row in ret:
|
||||||
toaddr, fromaddr, subject, status, ackdata, lastactiontime = row
|
toaddr, fromaddr, subject, status, ackdata, lastactiontime = row
|
||||||
|
toaddr = toaddr.decode("utf-8", "replace")
|
||||||
|
fromaddr = fromaddr.decode("utf-8", "replace")
|
||||||
subject = ascii(shared.fixPotentiallyInvalidUTF8Data(subject))
|
subject = ascii(shared.fixPotentiallyInvalidUTF8Data(subject))
|
||||||
|
status = status.decode("utf-8", "replace")
|
||||||
|
|
||||||
# Set label for to address
|
# Set label for to address
|
||||||
tolabel = ""
|
tolabel = ""
|
||||||
qr = sqlQuery("SELECT label FROM addressbook WHERE address=?", toaddr)
|
qr = sqlQuery("SELECT label FROM addressbook WHERE address=?", dbstr(toaddr))
|
||||||
if qr != []:
|
if qr != []:
|
||||||
for r in qr:
|
for r in qr:
|
||||||
tolabel, = r
|
tolabel, = r
|
||||||
|
tolabel = tolabel.decode("utf-8", "replace")
|
||||||
if tolabel == "":
|
if tolabel == "":
|
||||||
qr = sqlQuery("SELECT label FROM subscriptions WHERE address=?", toaddr)
|
qr = sqlQuery("SELECT label FROM subscriptions WHERE address=?", dbstr(toaddr))
|
||||||
if qr != []:
|
if qr != []:
|
||||||
for r in qr:
|
for r in qr:
|
||||||
tolabel, = r
|
tolabel, = r
|
||||||
|
tolabel = tolabel.decode("utf-8", "replace")
|
||||||
if tolabel == "":
|
if tolabel == "":
|
||||||
if config.has_section(toaddr):
|
if config.has_section(toaddr):
|
||||||
tolabel = config.get(toaddr, "label")
|
tolabel = config.get(toaddr, "label")
|
||||||
|
@ -1129,6 +1165,7 @@ def loadAddrBook():
|
||||||
for row in ret:
|
for row in ret:
|
||||||
label, addr = row
|
label, addr = row
|
||||||
label = shared.fixPotentiallyInvalidUTF8Data(label)
|
label = shared.fixPotentiallyInvalidUTF8Data(label)
|
||||||
|
addr = addr.decode("utf-8", "replace")
|
||||||
addrbook.append([label, addr])
|
addrbook.append([label, addr])
|
||||||
addrbook.reverse()
|
addrbook.reverse()
|
||||||
|
|
||||||
|
@ -1138,6 +1175,8 @@ def loadSubscriptions():
|
||||||
ret = sqlQuery("SELECT label, address, enabled FROM subscriptions")
|
ret = sqlQuery("SELECT label, address, enabled FROM subscriptions")
|
||||||
for row in ret:
|
for row in ret:
|
||||||
label, address, enabled = row
|
label, address, enabled = row
|
||||||
|
label = label.decode("utf-8", "replace")
|
||||||
|
address = address.decode("utf-8", "replace")
|
||||||
subscriptions.append([label, address, enabled])
|
subscriptions.append([label, address, enabled])
|
||||||
subscriptions.reverse()
|
subscriptions.reverse()
|
||||||
|
|
||||||
|
@ -1152,6 +1191,8 @@ def loadBlackWhiteList():
|
||||||
ret = sqlQuery("SELECT label, address, enabled FROM whitelist")
|
ret = sqlQuery("SELECT label, address, enabled FROM whitelist")
|
||||||
for row in ret:
|
for row in ret:
|
||||||
label, address, enabled = row
|
label, address, enabled = row
|
||||||
|
label = label.decode("utf-8", "replace")
|
||||||
|
address = address.decode("utf-8", "replace")
|
||||||
blacklist.append([label, address, enabled])
|
blacklist.append([label, address, enabled])
|
||||||
blacklist.reverse()
|
blacklist.reverse()
|
||||||
|
|
||||||
|
|
|
@ -29,6 +29,7 @@ from pybitmessage.bitmessagekivy.baseclass.common import (
|
||||||
from pybitmessage.bitmessagekivy.baseclass.popup import SavedAddressDetailPopup
|
from pybitmessage.bitmessagekivy.baseclass.popup import SavedAddressDetailPopup
|
||||||
from pybitmessage.bitmessagekivy.baseclass.addressbook_widgets import HelperAddressBook
|
from pybitmessage.bitmessagekivy.baseclass.addressbook_widgets import HelperAddressBook
|
||||||
from pybitmessage.helper_sql import sqlExecute
|
from pybitmessage.helper_sql import sqlExecute
|
||||||
|
from dbcompat import dbstr
|
||||||
|
|
||||||
logger = logging.getLogger('default')
|
logger = logging.getLogger('default')
|
||||||
|
|
||||||
|
@ -59,7 +60,7 @@ class AddressBook(Screen, HelperAddressBook):
|
||||||
self.ids.tag_label.text = ''
|
self.ids.tag_label.text = ''
|
||||||
self.queryreturn = kivy_helper_search.search_sql(
|
self.queryreturn = kivy_helper_search.search_sql(
|
||||||
xAddress, account, "addressbook", where, what, False)
|
xAddress, account, "addressbook", where, what, False)
|
||||||
self.queryreturn = [obj for obj in reversed(self.queryreturn)]
|
self.queryreturn = [[obj[0].decode("utf-8", "replace"), obj[1].decode("utf-8", "replace")] for obj in reversed(self.queryreturn)]
|
||||||
if self.queryreturn:
|
if self.queryreturn:
|
||||||
self.ids.tag_label.text = 'Address Book'
|
self.ids.tag_label.text = 'Address Book'
|
||||||
self.has_refreshed = True
|
self.has_refreshed = True
|
||||||
|
@ -131,7 +132,7 @@ class AddressBook(Screen, HelperAddressBook):
|
||||||
if self.ids.ml.children is not None:
|
if self.ids.ml.children is not None:
|
||||||
self.ids.tag_label.text = ''
|
self.ids.tag_label.text = ''
|
||||||
sqlExecute(
|
sqlExecute(
|
||||||
"DELETE FROM addressbook WHERE address = ?", address)
|
"DELETE FROM addressbook WHERE address = ?", dbstr(address))
|
||||||
toast('Address Deleted')
|
toast('Address Deleted')
|
||||||
|
|
||||||
def close_pop(self, instance):
|
def close_pop(self, instance):
|
||||||
|
@ -142,8 +143,13 @@ class AddressBook(Screen, HelperAddressBook):
|
||||||
def update_addbook_label(self, instance):
|
def update_addbook_label(self, instance):
|
||||||
"""Updating the label of address book address"""
|
"""Updating the label of address book address"""
|
||||||
address_list = kivy_helper_search.search_sql(folder="addressbook")
|
address_list = kivy_helper_search.search_sql(folder="addressbook")
|
||||||
stored_labels = [labels[0] for labels in address_list]
|
stored_labels = [labels[0].decode("utf-8", "replace") for labels in address_list]
|
||||||
add_dict = dict(address_list)
|
add_dict = {}
|
||||||
|
for row in address_list:
|
||||||
|
label, address = row
|
||||||
|
label = label.decode("utf-8", "replace")
|
||||||
|
address = address.decode("utf-8", "replace")
|
||||||
|
add_dict[label] = address
|
||||||
label = str(self.addbook_popup.content_cls.ids.add_label.text)
|
label = str(self.addbook_popup.content_cls.ids.add_label.text)
|
||||||
if label in stored_labels and self.address == add_dict[label]:
|
if label in stored_labels and self.address == add_dict[label]:
|
||||||
stored_labels.remove(label)
|
stored_labels.remove(label)
|
||||||
|
@ -151,7 +157,7 @@ class AddressBook(Screen, HelperAddressBook):
|
||||||
sqlExecute("""
|
sqlExecute("""
|
||||||
UPDATE addressbook
|
UPDATE addressbook
|
||||||
SET label = ?
|
SET label = ?
|
||||||
WHERE address = ?""", label, self.addbook_popup.content_cls.address)
|
WHERE address = ?""", dbstr(label), dbstr(self.addbook_popup.content_cls.address))
|
||||||
App.get_running_app().root.ids.id_addressbook.ids.ml.clear_widgets()
|
App.get_running_app().root.ids.id_addressbook.ids.ml.clear_widgets()
|
||||||
App.get_running_app().root.ids.id_addressbook.loadAddresslist(None, 'All', '')
|
App.get_running_app().root.ids.id_addressbook.loadAddresslist(None, 'All', '')
|
||||||
self.addbook_popup.dismiss()
|
self.addbook_popup.dismiss()
|
||||||
|
|
|
@ -7,6 +7,7 @@ Maildetail screen for inbox, sent, draft and trash.
|
||||||
|
|
||||||
import os
|
import os
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
import sqlite3
|
||||||
|
|
||||||
from kivy.core.clipboard import Clipboard
|
from kivy.core.clipboard import Clipboard
|
||||||
from kivy.clock import Clock
|
from kivy.clock import Clock
|
||||||
|
@ -111,7 +112,11 @@ class MailDetail(Screen): # pylint: disable=too-many-instance-attributes
|
||||||
elif self.kivy_state.detail_page_type == 'inbox':
|
elif self.kivy_state.detail_page_type == 'inbox':
|
||||||
data = sqlQuery(
|
data = sqlQuery(
|
||||||
"select toaddress, fromaddress, subject, message, received from inbox"
|
"select toaddress, fromaddress, subject, message, received from inbox"
|
||||||
" where msgid = ?", self.kivy_state.mail_id)
|
" where msgid = ?", sqlite3.Binary(self.kivy_state.mail_id))
|
||||||
|
if len(data) < 1:
|
||||||
|
data = sqlQuery(
|
||||||
|
"select toaddress, fromaddress, subject, message, received from inbox"
|
||||||
|
" where msgid = CAST(? AS TEXT)", self.kivy_state.mail_id)
|
||||||
self.assign_mail_details(data)
|
self.assign_mail_details(data)
|
||||||
App.get_running_app().set_mail_detail_header()
|
App.get_running_app().set_mail_detail_header()
|
||||||
except Exception as e: # pylint: disable=unused-variable
|
except Exception as e: # pylint: disable=unused-variable
|
||||||
|
@ -119,16 +124,16 @@ class MailDetail(Screen): # pylint: disable=too-many-instance-attributes
|
||||||
|
|
||||||
def assign_mail_details(self, data):
|
def assign_mail_details(self, data):
|
||||||
"""Assigning mail details"""
|
"""Assigning mail details"""
|
||||||
subject = data[0][2].decode() if isinstance(data[0][2], bytes) else data[0][2]
|
subject = data[0][2].decode("utf-8", "replace") if isinstance(data[0][2], bytes) else data[0][2]
|
||||||
body = data[0][3].decode() if isinstance(data[0][2], bytes) else data[0][3]
|
body = data[0][3].decode("utf-8", "replace") if isinstance(data[0][2], bytes) else data[0][3]
|
||||||
self.to_addr = data[0][0] if len(data[0][0]) > 4 else ' '
|
self.to_addr = data[0][0].decode("utf-8", "replace") if len(data[0][0]) > 4 else ' '
|
||||||
self.from_addr = data[0][1]
|
self.from_addr = data[0][1].decode("utf-8", "replace")
|
||||||
|
|
||||||
self.subject = subject.capitalize(
|
self.subject = subject.capitalize(
|
||||||
) if subject.capitalize() else self.no_subject
|
) if subject.capitalize() else self.no_subject
|
||||||
self.message = body
|
self.message = body
|
||||||
if len(data[0]) == 7:
|
if len(data[0]) == 7:
|
||||||
self.status = data[0][4]
|
self.status = data[0][4].decode("utf-8", "replace")
|
||||||
self.time_tag = show_time_history(data[0][4]) if self.kivy_state.detail_page_type == 'inbox' \
|
self.time_tag = show_time_history(data[0][4]) if self.kivy_state.detail_page_type == 'inbox' \
|
||||||
else show_time_history(data[0][6])
|
else show_time_history(data[0][6])
|
||||||
self.avatarImg = os.path.join(self.kivy_state.imageDir, 'draft-icon.png') \
|
self.avatarImg = os.path.join(self.kivy_state.imageDir, 'draft-icon.png') \
|
||||||
|
|
|
@ -59,7 +59,7 @@ class AddAddressPopup(BoxLayout):
|
||||||
"""Checking address is valid or not"""
|
"""Checking address is valid or not"""
|
||||||
my_addresses = (
|
my_addresses = (
|
||||||
App.get_running_app().root.ids.content_drawer.ids.identity_dropdown.values)
|
App.get_running_app().root.ids.content_drawer.ids.identity_dropdown.values)
|
||||||
add_book = [addr[1] for addr in kivy_helper_search.search_sql(
|
add_book = [addr[1].decode("utf-8", "replace") for addr in kivy_helper_search.search_sql(
|
||||||
folder="addressbook")]
|
folder="addressbook")]
|
||||||
entered_text = str(instance.text).strip()
|
entered_text = str(instance.text).strip()
|
||||||
if entered_text in add_book:
|
if entered_text in add_book:
|
||||||
|
@ -84,7 +84,7 @@ class AddAddressPopup(BoxLayout):
|
||||||
def checkLabel_valid(self, instance):
|
def checkLabel_valid(self, instance):
|
||||||
"""Checking address label is unique or not"""
|
"""Checking address label is unique or not"""
|
||||||
entered_label = instance.text.strip()
|
entered_label = instance.text.strip()
|
||||||
addr_labels = [labels[0] for labels in kivy_helper_search.search_sql(
|
addr_labels = [labels[0].decode("utf-8", "replace") for labels in kivy_helper_search.search_sql(
|
||||||
folder="addressbook")]
|
folder="addressbook")]
|
||||||
if entered_label in addr_labels:
|
if entered_label in addr_labels:
|
||||||
self.ids.label.error = True
|
self.ids.label.error = True
|
||||||
|
@ -125,8 +125,13 @@ class SavedAddressDetailPopup(BoxLayout):
|
||||||
"""Checking address label is unique of not"""
|
"""Checking address label is unique of not"""
|
||||||
entered_label = str(instance.text.strip())
|
entered_label = str(instance.text.strip())
|
||||||
address_list = kivy_helper_search.search_sql(folder="addressbook")
|
address_list = kivy_helper_search.search_sql(folder="addressbook")
|
||||||
addr_labels = [labels[0] for labels in address_list]
|
addr_labels = [labels[0].decode("utf-8", "replace") for labels in address_list]
|
||||||
add_dict = dict(address_list)
|
add_dict = {}
|
||||||
|
for row in address_list:
|
||||||
|
label, address = row
|
||||||
|
label = label.decode("utf-8", "replace")
|
||||||
|
address = address.decode("utf-8", "replace")
|
||||||
|
add_dict[label] = address
|
||||||
if self.address and entered_label in addr_labels \
|
if self.address and entered_label in addr_labels \
|
||||||
and self.address != add_dict[entered_label]:
|
and self.address != add_dict[entered_label]:
|
||||||
self.ids.add_label.error = True
|
self.ids.add_label.error = True
|
||||||
|
|
|
@ -3,7 +3,7 @@ Core classes for loading images and converting them to a Texture.
|
||||||
The raw image data can be keep in memory for further access
|
The raw image data can be keep in memory for further access
|
||||||
"""
|
"""
|
||||||
import hashlib
|
import hashlib
|
||||||
from io import BytesIO
|
from six import BytesIO
|
||||||
|
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
from kivy.core.image import Image as CoreImage
|
from kivy.core.image import Image as CoreImage
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
Sql queries for bitmessagekivy
|
Sql queries for bitmessagekivy
|
||||||
"""
|
"""
|
||||||
from pybitmessage.helper_sql import sqlQuery
|
from pybitmessage.helper_sql import sqlQuery
|
||||||
|
from dbcompat import dbstr
|
||||||
|
|
||||||
|
|
||||||
def search_sql(
|
def search_sql(
|
||||||
|
@ -30,21 +31,21 @@ def search_sql(
|
||||||
if account is not None:
|
if account is not None:
|
||||||
if xAddress == 'both':
|
if xAddress == 'both':
|
||||||
sqlStatementParts.append("(fromaddress = ? OR toaddress = ?)")
|
sqlStatementParts.append("(fromaddress = ? OR toaddress = ?)")
|
||||||
sqlArguments.append(account)
|
sqlArguments.append(dbstr(account))
|
||||||
sqlArguments.append(account)
|
sqlArguments.append(dbstr(account))
|
||||||
else:
|
else:
|
||||||
sqlStatementParts.append(xAddress + " = ? ")
|
sqlStatementParts.append(xAddress + " = ? ")
|
||||||
sqlArguments.append(account)
|
sqlArguments.append(dbstr(account))
|
||||||
if folder != "addressbook":
|
if folder != "addressbook":
|
||||||
if folder is not None:
|
if folder is not None:
|
||||||
if folder == "new":
|
if folder == "new":
|
||||||
folder = "inbox"
|
folder = "inbox"
|
||||||
unreadOnly = True
|
unreadOnly = True
|
||||||
sqlStatementParts.append("folder = ? ")
|
sqlStatementParts.append("folder = ? ")
|
||||||
sqlArguments.append(folder)
|
sqlArguments.append(dbstr(folder))
|
||||||
else:
|
else:
|
||||||
sqlStatementParts.append("folder != ?")
|
sqlStatementParts.append("folder != ?")
|
||||||
sqlArguments.append("trash")
|
sqlArguments.append(dbstr("trash"))
|
||||||
if what is not None:
|
if what is not None:
|
||||||
for colmns in where:
|
for colmns in where:
|
||||||
if len(where) > 1:
|
if len(where) > 1:
|
||||||
|
@ -54,7 +55,7 @@ def search_sql(
|
||||||
filter_col += " or %s LIKE ? )" % (colmns)
|
filter_col += " or %s LIKE ? )" % (colmns)
|
||||||
else:
|
else:
|
||||||
filter_col = "%s LIKE ?" % (colmns)
|
filter_col = "%s LIKE ?" % (colmns)
|
||||||
sqlArguments.append(what)
|
sqlArguments.append(dbstr(what))
|
||||||
sqlStatementParts.append(filter_col)
|
sqlStatementParts.append(filter_col)
|
||||||
if unreadOnly:
|
if unreadOnly:
|
||||||
sqlStatementParts.append("read = 0")
|
sqlStatementParts.append("read = 0")
|
||||||
|
|
|
@ -6,6 +6,7 @@ import os
|
||||||
import shutil
|
import shutil
|
||||||
import tempfile
|
import tempfile
|
||||||
from time import time, sleep
|
from time import time, sleep
|
||||||
|
from six.moves import getcwdb
|
||||||
|
|
||||||
from requests.exceptions import ChunkedEncodingError
|
from requests.exceptions import ChunkedEncodingError
|
||||||
|
|
||||||
|
@ -34,7 +35,7 @@ def cleanup(files=_files):
|
||||||
|
|
||||||
class TeleniumTestProcess(TeleniumTestCase):
|
class TeleniumTestProcess(TeleniumTestCase):
|
||||||
"""Setting Screen Functionality Testing"""
|
"""Setting Screen Functionality Testing"""
|
||||||
cmd_entrypoint = [os.path.join(os.path.abspath(os.getcwd()), 'src', 'mockbm', 'kivy_main.py')]
|
cmd_entrypoint = [os.path.join(os.path.abspath(getcwdb()), 'src', 'mockbm', 'kivy_main.py')]
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpClass(cls):
|
def setUpClass(cls):
|
||||||
|
|
|
@ -14,46 +14,53 @@ import threading
|
||||||
import time
|
import time
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
from sqlite3 import register_adapter
|
from sqlite3 import register_adapter
|
||||||
|
import sqlite3
|
||||||
|
import six
|
||||||
|
from six.moves import range as xrange
|
||||||
|
if six.PY3:
|
||||||
|
from codecs import escape_decode
|
||||||
|
|
||||||
|
from unqstr import ustr, unic
|
||||||
from PyQt4 import QtCore, QtGui
|
from PyQt4 import QtCore, QtGui
|
||||||
from PyQt4.QtNetwork import QLocalSocket, QLocalServer
|
from PyQt4.QtNetwork import QLocalSocket, QLocalServer
|
||||||
|
from dbcompat import dbstr
|
||||||
|
|
||||||
import shared
|
import shared
|
||||||
import state
|
import state
|
||||||
from debug import logger
|
from debug import logger
|
||||||
from tr import _translate
|
from tr import _translate
|
||||||
from account import (
|
from .account import (
|
||||||
accountClass, getSortedSubscriptions,
|
accountClass, getSortedSubscriptions,
|
||||||
BMAccount, GatewayAccount, MailchuckAccount, AccountColor)
|
BMAccount, GatewayAccount, MailchuckAccount, AccountColor)
|
||||||
from addresses import decodeAddress, addBMIfNotPresent
|
from addresses import decodeAddress, addBMIfNotPresent
|
||||||
from bitmessageui import Ui_MainWindow
|
from bitmessageqt.bitmessageui import Ui_MainWindow
|
||||||
from bmconfigparser import config
|
from bmconfigparser import config
|
||||||
import namecoin
|
import namecoin
|
||||||
from messageview import MessageView
|
from .messageview import MessageView
|
||||||
from migrationwizard import Ui_MigrationWizard
|
from .migrationwizard import Ui_MigrationWizard
|
||||||
from foldertree import (
|
from .foldertree import (
|
||||||
AccountMixin, Ui_FolderWidget, Ui_AddressWidget, Ui_SubscriptionWidget,
|
AccountMixin, Ui_FolderWidget, Ui_AddressWidget, Ui_SubscriptionWidget,
|
||||||
MessageList_AddressWidget, MessageList_SubjectWidget,
|
MessageList_AddressWidget, MessageList_SubjectWidget,
|
||||||
Ui_AddressBookWidgetItemLabel, Ui_AddressBookWidgetItemAddress,
|
Ui_AddressBookWidgetItemLabel, Ui_AddressBookWidgetItemAddress,
|
||||||
MessageList_TimeWidget)
|
MessageList_TimeWidget)
|
||||||
import settingsmixin
|
from bitmessageqt import settingsmixin
|
||||||
import support
|
from bitmessageqt import support
|
||||||
from helper_sql import sqlQuery, sqlExecute, sqlExecuteChunked, sqlStoredProcedure
|
from helper_sql import sqlQuery, sqlExecute, sqlExecuteChunked, sqlStoredProcedure
|
||||||
import helper_addressbook
|
import helper_addressbook
|
||||||
import helper_search
|
import helper_search
|
||||||
import l10n
|
import l10n
|
||||||
from utils import str_broadcast_subscribers, avatarize
|
from .utils import str_broadcast_subscribers, avatarize
|
||||||
import dialogs
|
from bitmessageqt import dialogs
|
||||||
from network.stats import pendingDownload, pendingUpload
|
from network.stats import pendingDownload, pendingUpload
|
||||||
from uisignaler import UISignaler
|
from .uisignaler import UISignaler
|
||||||
import paths
|
import paths
|
||||||
from proofofwork import getPowType
|
from proofofwork import getPowType
|
||||||
import queues
|
import queues
|
||||||
import shutdown
|
import shutdown
|
||||||
from statusbar import BMStatusBar
|
from .statusbar import BMStatusBar
|
||||||
import sound
|
from bitmessageqt import sound
|
||||||
# This is needed for tray icon
|
# This is needed for tray icon
|
||||||
import bitmessage_icons_rc # noqa:F401 pylint: disable=unused-import
|
from bitmessageqt import bitmessage_icons_rc # noqa:F401 pylint: disable=unused-import
|
||||||
import helper_sent
|
import helper_sent
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
@ -87,6 +94,13 @@ def openKeysFile():
|
||||||
os.startfile(keysfile) # pylint: disable=no-member
|
os.startfile(keysfile) # pylint: disable=no-member
|
||||||
|
|
||||||
|
|
||||||
|
def as_msgid(id_data):
|
||||||
|
if six.PY3:
|
||||||
|
return escape_decode(id_data)[0][2:-1]
|
||||||
|
else: # assume six.PY2
|
||||||
|
return id_data
|
||||||
|
|
||||||
|
|
||||||
class MyForm(settingsmixin.SMainWindow):
|
class MyForm(settingsmixin.SMainWindow):
|
||||||
|
|
||||||
# the maximum frequency of message sounds in seconds
|
# the maximum frequency of message sounds in seconds
|
||||||
|
@ -123,7 +137,7 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
paths.codePath(), 'translations', 'qt_' + newlocale)
|
paths.codePath(), 'translations', 'qt_' + newlocale)
|
||||||
else:
|
else:
|
||||||
translationpath = os.path.join(
|
translationpath = os.path.join(
|
||||||
str(QtCore.QLibraryInfo.location(
|
ustr(QtCore.QLibraryInfo.location(
|
||||||
QtCore.QLibraryInfo.TranslationsPath)), 'qt_' + newlocale)
|
QtCore.QLibraryInfo.TranslationsPath)), 'qt_' + newlocale)
|
||||||
self.qsystranslator.load(translationpath)
|
self.qsystranslator.load(translationpath)
|
||||||
QtGui.QApplication.installTranslator(self.qsystranslator)
|
QtGui.QApplication.installTranslator(self.qsystranslator)
|
||||||
|
@ -424,7 +438,7 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
def rerenderTabTreeSubscriptions(self):
|
def rerenderTabTreeSubscriptions(self):
|
||||||
treeWidget = self.ui.treeWidgetSubscriptions
|
treeWidget = self.ui.treeWidgetSubscriptions
|
||||||
folders = Ui_FolderWidget.folderWeight.keys()
|
folders = Ui_FolderWidget.folderWeight.keys()
|
||||||
folders.remove("new")
|
Ui_FolderWidget.folderWeight.pop("new", None)
|
||||||
|
|
||||||
# sort ascending when creating
|
# sort ascending when creating
|
||||||
if treeWidget.topLevelItemCount() == 0:
|
if treeWidget.topLevelItemCount() == 0:
|
||||||
|
@ -471,7 +485,7 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
# add missing folders
|
# add missing folders
|
||||||
if len(db[toAddress]) > 0:
|
if len(db[toAddress]) > 0:
|
||||||
j = 0
|
j = 0
|
||||||
for f, c in db[toAddress].iteritems():
|
for f, c in six.iteritems(db[toAddress]):
|
||||||
try:
|
try:
|
||||||
subwidget = Ui_FolderWidget(widget, j, toAddress, f, c['count'])
|
subwidget = Ui_FolderWidget(widget, j, toAddress, f, c['count'])
|
||||||
except KeyError:
|
except KeyError:
|
||||||
|
@ -555,6 +569,8 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
"GROUP BY toaddress, folder")
|
"GROUP BY toaddress, folder")
|
||||||
for row in queryreturn:
|
for row in queryreturn:
|
||||||
toaddress, folder, cnt = row
|
toaddress, folder, cnt = row
|
||||||
|
toaddress = toaddress.decode("utf-8", "replace")
|
||||||
|
folder = folder.decode("utf-8", "replace")
|
||||||
total += cnt
|
total += cnt
|
||||||
if toaddress in db and folder in db[toaddress]:
|
if toaddress in db and folder in db[toaddress]:
|
||||||
db[toaddress][folder] = cnt
|
db[toaddress][folder] = cnt
|
||||||
|
@ -601,7 +617,7 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
# add missing folders
|
# add missing folders
|
||||||
if len(db[toAddress]) > 0:
|
if len(db[toAddress]) > 0:
|
||||||
j = 0
|
j = 0
|
||||||
for f, c in db[toAddress].iteritems():
|
for f, c in six.iteritems(db[toAddress]):
|
||||||
if toAddress is not None and tab == 'messages' and folder == "new":
|
if toAddress is not None and tab == 'messages' and folder == "new":
|
||||||
continue
|
continue
|
||||||
subwidget = Ui_FolderWidget(widget, j, toAddress, f, c)
|
subwidget = Ui_FolderWidget(widget, j, toAddress, f, c)
|
||||||
|
@ -649,9 +665,9 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
if addressVersionNumber == 1:
|
if addressVersionNumber == 1:
|
||||||
displayMsg = _translate(
|
displayMsg = _translate(
|
||||||
"MainWindow",
|
"MainWindow",
|
||||||
"One of your addresses, %1, is an old version 1 address. "
|
"One of your addresses, {0}, is an old version 1 address. "
|
||||||
"Version 1 addresses are no longer supported. "
|
"Version 1 addresses are no longer supported. "
|
||||||
"May we delete it now?").arg(addressInKeysFile)
|
"May we delete it now?").format(addressInKeysFile)
|
||||||
reply = QtGui.QMessageBox.question(
|
reply = QtGui.QMessageBox.question(
|
||||||
self, 'Message', displayMsg, QtGui.QMessageBox.Yes, QtGui.QMessageBox.No)
|
self, 'Message', displayMsg, QtGui.QMessageBox.Yes, QtGui.QMessageBox.No)
|
||||||
if reply == QtGui.QMessageBox.Yes:
|
if reply == QtGui.QMessageBox.Yes:
|
||||||
|
@ -833,9 +849,10 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
TTL = config.getint('bitmessagesettings', 'ttl')
|
TTL = config.getint('bitmessagesettings', 'ttl')
|
||||||
if TTL < 3600: # an hour
|
if TTL < 3600: # an hour
|
||||||
TTL = 3600
|
TTL = 3600
|
||||||
elif TTL > 28*24*60*60: # 28 days
|
elif TTL > 28 * 24 * 60 * 60: # 28 days
|
||||||
TTL = 28*24*60*60
|
TTL = 28 * 24 * 60 * 60
|
||||||
self.ui.horizontalSliderTTL.setSliderPosition((TTL - 3600) ** (1/3.199))
|
self.ui.horizontalSliderTTL.setSliderPosition(
|
||||||
|
int((TTL - 3600) ** (1 / 3.199)))
|
||||||
self.updateHumanFriendlyTTLDescription(TTL)
|
self.updateHumanFriendlyTTLDescription(TTL)
|
||||||
|
|
||||||
QtCore.QObject.connect(self.ui.horizontalSliderTTL, QtCore.SIGNAL(
|
QtCore.QObject.connect(self.ui.horizontalSliderTTL, QtCore.SIGNAL(
|
||||||
|
@ -1026,7 +1043,7 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
# related = related.findItems(msgid, QtCore.Qt.MatchExactly),
|
# related = related.findItems(msgid, QtCore.Qt.MatchExactly),
|
||||||
# returns an empty list
|
# returns an empty list
|
||||||
for rrow in range(related.rowCount()):
|
for rrow in range(related.rowCount()):
|
||||||
if related.item(rrow, 3).data() == msgid:
|
if as_msgid(related.item(rrow, 3).data()) == msgid:
|
||||||
break
|
break
|
||||||
|
|
||||||
for col in range(widget.columnCount()):
|
for col in range(widget.columnCount()):
|
||||||
|
@ -1047,6 +1064,8 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
normalUnread = {}
|
normalUnread = {}
|
||||||
broadcastsUnread = {}
|
broadcastsUnread = {}
|
||||||
for addr, fld, count in queryReturn:
|
for addr, fld, count in queryReturn:
|
||||||
|
addr = addr.decode("utf-8", "replace")
|
||||||
|
fld = fld.decode("utf-8", "replace")
|
||||||
try:
|
try:
|
||||||
normalUnread[addr][fld] = count
|
normalUnread[addr][fld] = count
|
||||||
except KeyError:
|
except KeyError:
|
||||||
|
@ -1066,8 +1085,10 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
queryReturn = sqlQuery(
|
queryReturn = sqlQuery(
|
||||||
'SELECT fromaddress, folder, COUNT(msgid) AS cnt'
|
'SELECT fromaddress, folder, COUNT(msgid) AS cnt'
|
||||||
' FROM inbox WHERE read = 0 AND toaddress = ?'
|
' FROM inbox WHERE read = 0 AND toaddress = ?'
|
||||||
' GROUP BY fromaddress, folder', str_broadcast_subscribers)
|
' GROUP BY fromaddress, folder', dbstr(str_broadcast_subscribers))
|
||||||
for addr, fld, count in queryReturn:
|
for addr, fld, count in queryReturn:
|
||||||
|
addr = addr.decode("utf-8", "replace")
|
||||||
|
fld = fld.decode("utf-8", "replace")
|
||||||
try:
|
try:
|
||||||
broadcastsUnread[addr][fld] = count
|
broadcastsUnread[addr][fld] = count
|
||||||
except KeyError:
|
except KeyError:
|
||||||
|
@ -1078,15 +1099,15 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
for i in range(root.childCount()):
|
for i in range(root.childCount()):
|
||||||
addressItem = root.child(i)
|
addressItem = root.child(i)
|
||||||
if addressItem.type == AccountMixin.ALL:
|
if addressItem.type == AccountMixin.ALL:
|
||||||
newCount = sum(totalUnread.itervalues())
|
newCount = sum(six.itervalues(totalUnread))
|
||||||
self.drawTrayIcon(self.currentTrayIconFileName, newCount)
|
self.drawTrayIcon(self.currentTrayIconFileName, newCount)
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
newCount = sum((
|
newCount = sum(six.itervalues((
|
||||||
broadcastsUnread
|
broadcastsUnread
|
||||||
if addressItem.type == AccountMixin.SUBSCRIPTION
|
if addressItem.type == AccountMixin.SUBSCRIPTION
|
||||||
else normalUnread
|
else normalUnread
|
||||||
)[addressItem.address].itervalues())
|
)[addressItem.address]))
|
||||||
except KeyError:
|
except KeyError:
|
||||||
newCount = 0
|
newCount = 0
|
||||||
if newCount != addressItem.unreadCount:
|
if newCount != addressItem.unreadCount:
|
||||||
|
@ -1143,20 +1164,20 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
elif status == 'msgsent':
|
elif status == 'msgsent':
|
||||||
statusText = _translate(
|
statusText = _translate(
|
||||||
"MainWindow",
|
"MainWindow",
|
||||||
"Message sent. Waiting for acknowledgement. Sent at %1"
|
"Message sent. Waiting for acknowledgement. Sent at {0}"
|
||||||
).arg(l10n.formatTimestamp(lastactiontime))
|
).format(l10n.formatTimestamp(lastactiontime))
|
||||||
elif status == 'msgsentnoackexpected':
|
elif status == 'msgsentnoackexpected':
|
||||||
statusText = _translate(
|
statusText = _translate(
|
||||||
"MainWindow", "Message sent. Sent at %1"
|
"MainWindow", "Message sent. Sent at {0}"
|
||||||
).arg(l10n.formatTimestamp(lastactiontime))
|
).format(l10n.formatTimestamp(lastactiontime))
|
||||||
elif status == 'doingmsgpow':
|
elif status == 'doingmsgpow':
|
||||||
statusText = _translate(
|
statusText = _translate(
|
||||||
"MainWindow", "Doing work necessary to send message.")
|
"MainWindow", "Doing work necessary to send message.")
|
||||||
elif status == 'ackreceived':
|
elif status == 'ackreceived':
|
||||||
statusText = _translate(
|
statusText = _translate(
|
||||||
"MainWindow",
|
"MainWindow",
|
||||||
"Acknowledgement of the message received %1"
|
"Acknowledgement of the message received {0}"
|
||||||
).arg(l10n.formatTimestamp(lastactiontime))
|
).format(l10n.formatTimestamp(lastactiontime))
|
||||||
elif status == 'broadcastqueued':
|
elif status == 'broadcastqueued':
|
||||||
statusText = _translate(
|
statusText = _translate(
|
||||||
"MainWindow", "Broadcast queued.")
|
"MainWindow", "Broadcast queued.")
|
||||||
|
@ -1164,36 +1185,36 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
statusText = _translate(
|
statusText = _translate(
|
||||||
"MainWindow", "Doing work necessary to send broadcast.")
|
"MainWindow", "Doing work necessary to send broadcast.")
|
||||||
elif status == 'broadcastsent':
|
elif status == 'broadcastsent':
|
||||||
statusText = _translate("MainWindow", "Broadcast on %1").arg(
|
statusText = _translate("MainWindow", "Broadcast on {0}").format(
|
||||||
l10n.formatTimestamp(lastactiontime))
|
l10n.formatTimestamp(lastactiontime))
|
||||||
elif status == 'toodifficult':
|
elif status == 'toodifficult':
|
||||||
statusText = _translate(
|
statusText = _translate(
|
||||||
"MainWindow",
|
"MainWindow",
|
||||||
"Problem: The work demanded by the recipient is more"
|
"Problem: The work demanded by the recipient is more"
|
||||||
" difficult than you are willing to do. %1"
|
" difficult than you are willing to do. {0}"
|
||||||
).arg(l10n.formatTimestamp(lastactiontime))
|
).format(l10n.formatTimestamp(lastactiontime))
|
||||||
elif status == 'badkey':
|
elif status == 'badkey':
|
||||||
statusText = _translate(
|
statusText = _translate(
|
||||||
"MainWindow",
|
"MainWindow",
|
||||||
"Problem: The recipient\'s encryption key is no good."
|
"Problem: The recipient\'s encryption key is no good."
|
||||||
" Could not encrypt message. %1"
|
" Could not encrypt message. {0}"
|
||||||
).arg(l10n.formatTimestamp(lastactiontime))
|
).format(l10n.formatTimestamp(lastactiontime))
|
||||||
elif status == 'forcepow':
|
elif status == 'forcepow':
|
||||||
statusText = _translate(
|
statusText = _translate(
|
||||||
"MainWindow",
|
"MainWindow",
|
||||||
"Forced difficulty override. Send should start soon.")
|
"Forced difficulty override. Send should start soon.")
|
||||||
else:
|
else:
|
||||||
statusText = _translate(
|
statusText = _translate(
|
||||||
"MainWindow", "Unknown status: %1 %2").arg(status).arg(
|
"MainWindow", "Unknown status: {0} {1}").format(status,
|
||||||
l10n.formatTimestamp(lastactiontime))
|
l10n.formatTimestamp(lastactiontime))
|
||||||
|
|
||||||
items = [
|
items = [
|
||||||
MessageList_AddressWidget(
|
MessageList_AddressWidget(
|
||||||
toAddress, unicode(acct.toLabel, 'utf-8')),
|
toAddress, unic(ustr(acct.toLabel))),
|
||||||
MessageList_AddressWidget(
|
MessageList_AddressWidget(
|
||||||
fromAddress, unicode(acct.fromLabel, 'utf-8')),
|
fromAddress, unic(ustr(acct.fromLabel))),
|
||||||
MessageList_SubjectWidget(
|
MessageList_SubjectWidget(
|
||||||
str(subject), unicode(acct.subject, 'utf-8', 'replace')),
|
ustr(subject), unic(ustr(acct.subject))),
|
||||||
MessageList_TimeWidget(
|
MessageList_TimeWidget(
|
||||||
statusText, False, lastactiontime, ackdata)]
|
statusText, False, lastactiontime, ackdata)]
|
||||||
self.addMessageListItem(tableWidget, items)
|
self.addMessageListItem(tableWidget, items)
|
||||||
|
@ -1214,11 +1235,11 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
|
|
||||||
items = [
|
items = [
|
||||||
MessageList_AddressWidget(
|
MessageList_AddressWidget(
|
||||||
toAddress, unicode(acct.toLabel, 'utf-8'), not read),
|
toAddress, unic(ustr(acct.toLabel)), not read),
|
||||||
MessageList_AddressWidget(
|
MessageList_AddressWidget(
|
||||||
fromAddress, unicode(acct.fromLabel, 'utf-8'), not read),
|
fromAddress, unic(ustr(acct.fromLabel)), not read),
|
||||||
MessageList_SubjectWidget(
|
MessageList_SubjectWidget(
|
||||||
str(subject), unicode(acct.subject, 'utf-8', 'replace'),
|
ustr(subject), unic(ustr(acct.subject)),
|
||||||
not read),
|
not read),
|
||||||
MessageList_TimeWidget(
|
MessageList_TimeWidget(
|
||||||
l10n.formatTimestamp(received), not read, received, msgid)
|
l10n.formatTimestamp(received), not read, received, msgid)
|
||||||
|
@ -1246,7 +1267,14 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
xAddress, account, "sent", where, what, False)
|
xAddress, account, "sent", where, what, False)
|
||||||
|
|
||||||
for row in queryreturn:
|
for row in queryreturn:
|
||||||
self.addMessageListItemSent(tableWidget, *row)
|
r = []
|
||||||
|
r.append(row[0].decode("utf-8", "replace")) # toaddress
|
||||||
|
r.append(row[1].decode("utf-8", "replace")) # fromaddress
|
||||||
|
r.append(row[2].decode("utf-8", "replace")) # subject
|
||||||
|
r.append(row[3].decode("utf-8", "replace")) # status
|
||||||
|
r.append(row[4]) # ackdata
|
||||||
|
r.append(row[5]) # lastactiontime
|
||||||
|
self.addMessageListItemSent(tableWidget, *r)
|
||||||
|
|
||||||
tableWidget.horizontalHeader().setSortIndicator(
|
tableWidget.horizontalHeader().setSortIndicator(
|
||||||
3, QtCore.Qt.DescendingOrder)
|
3, QtCore.Qt.DescendingOrder)
|
||||||
|
@ -1287,6 +1315,10 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
|
|
||||||
for row in queryreturn:
|
for row in queryreturn:
|
||||||
toAddress, fromAddress, subject, _, msgid, received, read = row
|
toAddress, fromAddress, subject, _, msgid, received, read = row
|
||||||
|
toAddress = toAddress.decode("utf-8", "replace")
|
||||||
|
fromAddress = fromAddress.decode("utf-8", "replace")
|
||||||
|
subject = subject.decode("utf-8", "replace")
|
||||||
|
received = received.decode("utf-8", "replace")
|
||||||
self.addMessageListItemInbox(
|
self.addMessageListItemInbox(
|
||||||
tableWidget, toAddress, fromAddress, subject,
|
tableWidget, toAddress, fromAddress, subject,
|
||||||
msgid, received, read)
|
msgid, received, read)
|
||||||
|
@ -1372,6 +1404,7 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
SELECT msgid, toaddress, read FROM inbox where folder='inbox'
|
SELECT msgid, toaddress, read FROM inbox where folder='inbox'
|
||||||
''')
|
''')
|
||||||
for msgid, toAddress, read in queryreturn:
|
for msgid, toAddress, read in queryreturn:
|
||||||
|
toAddress = toAddress.decode("utf-8", "replace")
|
||||||
|
|
||||||
if not read:
|
if not read:
|
||||||
# increment the unread subscriptions if True (1)
|
# increment the unread subscriptions if True (1)
|
||||||
|
@ -1450,7 +1483,7 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
|
|
||||||
# Adapters and converters for QT <-> sqlite
|
# Adapters and converters for QT <-> sqlite
|
||||||
def sqlInit(self):
|
def sqlInit(self):
|
||||||
register_adapter(QtCore.QByteArray, str)
|
register_adapter(QtCore.QByteArray, bytes)
|
||||||
|
|
||||||
def indicatorInit(self):
|
def indicatorInit(self):
|
||||||
"""
|
"""
|
||||||
|
@ -1499,7 +1532,7 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
self, title, subtitle, category, label=None, icon=None):
|
self, title, subtitle, category, label=None, icon=None):
|
||||||
self.playSound(category, label)
|
self.playSound(category, label)
|
||||||
self._notifier(
|
self._notifier(
|
||||||
unicode(title), unicode(subtitle), category, label, icon)
|
unic(ustr(title)), unic(ustr(subtitle)), category, label, icon)
|
||||||
|
|
||||||
# tree
|
# tree
|
||||||
def treeWidgetKeyPressEvent(self, event):
|
def treeWidgetKeyPressEvent(self, event):
|
||||||
|
@ -1602,9 +1635,9 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
_translate(
|
_translate(
|
||||||
"MainWindow",
|
"MainWindow",
|
||||||
"You may manage your keys by editing the keys.dat file stored in"
|
"You may manage your keys by editing the keys.dat file stored in"
|
||||||
"\n %1 \n"
|
"\n {0} \n"
|
||||||
"It is important that you back up this file."
|
"It is important that you back up this file."
|
||||||
).arg(state.appdata),
|
).format(state.appdata),
|
||||||
QtGui.QMessageBox.Ok)
|
QtGui.QMessageBox.Ok)
|
||||||
elif sys.platform == 'win32' or sys.platform == 'win64':
|
elif sys.platform == 'win32' or sys.platform == 'win64':
|
||||||
if state.appdata == '':
|
if state.appdata == '':
|
||||||
|
@ -1625,9 +1658,9 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
_translate("MainWindow", "Open keys.dat?"),
|
_translate("MainWindow", "Open keys.dat?"),
|
||||||
_translate(
|
_translate(
|
||||||
"MainWindow",
|
"MainWindow",
|
||||||
"You may manage your keys by editing the keys.dat file stored in\n %1 \n"
|
"You may manage your keys by editing the keys.dat file stored in\n {0} \n"
|
||||||
"It is important that you back up this file. Would you like to open the file now?"
|
"It is important that you back up this file. Would you like to open the file now?"
|
||||||
"(Be sure to close Bitmessage before making any changes.)").arg(state.appdata),
|
"(Be sure to close Bitmessage before making any changes.)").format(state.appdata),
|
||||||
QtGui.QMessageBox.Yes, QtGui.QMessageBox.No)
|
QtGui.QMessageBox.Yes, QtGui.QMessageBox.No)
|
||||||
if reply == QtGui.QMessageBox.Yes:
|
if reply == QtGui.QMessageBox.Yes:
|
||||||
openKeysFile()
|
openKeysFile()
|
||||||
|
@ -1702,7 +1735,7 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
addressVersionNumber, streamNumberForAddress,
|
addressVersionNumber, streamNumberForAddress,
|
||||||
"regenerated deterministic address",
|
"regenerated deterministic address",
|
||||||
dialog.spinBoxNumberOfAddressesToMake.value(),
|
dialog.spinBoxNumberOfAddressesToMake.value(),
|
||||||
dialog.lineEditPassphrase.text().toUtf8(),
|
ustr(dialog.lineEditPassphrase.text()).encode("utf-8", "replace"),
|
||||||
dialog.checkBoxEighteenByteRipe.isChecked()
|
dialog.checkBoxEighteenByteRipe.isChecked()
|
||||||
))
|
))
|
||||||
self.ui.tabWidget.setCurrentIndex(
|
self.ui.tabWidget.setCurrentIndex(
|
||||||
|
@ -1915,8 +1948,6 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
sent.item(i, 3).setText(textToDisplay)
|
sent.item(i, 3).setText(textToDisplay)
|
||||||
|
|
||||||
def updateSentItemStatusByAckdata(self, ackdata, textToDisplay):
|
def updateSentItemStatusByAckdata(self, ackdata, textToDisplay):
|
||||||
if type(ackdata) is str:
|
|
||||||
ackdata = QtCore.QByteArray(ackdata)
|
|
||||||
for sent in (
|
for sent in (
|
||||||
self.ui.tableWidgetInbox,
|
self.ui.tableWidgetInbox,
|
||||||
self.ui.tableWidgetInboxSubscriptions,
|
self.ui.tableWidgetInboxSubscriptions,
|
||||||
|
@ -1927,7 +1958,7 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
continue
|
continue
|
||||||
for i in range(sent.rowCount()):
|
for i in range(sent.rowCount()):
|
||||||
toAddress = sent.item(i, 0).data(QtCore.Qt.UserRole)
|
toAddress = sent.item(i, 0).data(QtCore.Qt.UserRole)
|
||||||
tableAckdata = sent.item(i, 3).data()
|
tableAckdata = as_msgid(sent.item(i, 3).data())
|
||||||
status, addressVersionNumber, streamNumber, ripe = decodeAddress(
|
status, addressVersionNumber, streamNumber, ripe = decodeAddress(
|
||||||
toAddress)
|
toAddress)
|
||||||
if ackdata == tableAckdata:
|
if ackdata == tableAckdata:
|
||||||
|
@ -1953,7 +1984,7 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
):
|
):
|
||||||
i = None
|
i = None
|
||||||
for i in range(inbox.rowCount()):
|
for i in range(inbox.rowCount()):
|
||||||
if msgid == inbox.item(i, 3).data():
|
if msgid == as_msgid(inbox.item(i, 3).data()):
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
continue
|
continue
|
||||||
|
@ -1970,9 +2001,9 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
self.notifiedNewVersion = ".".join(str(n) for n in version)
|
self.notifiedNewVersion = ".".join(str(n) for n in version)
|
||||||
self.updateStatusBar(_translate(
|
self.updateStatusBar(_translate(
|
||||||
"MainWindow",
|
"MainWindow",
|
||||||
"New version of PyBitmessage is available: %1. Download it"
|
"New version of PyBitmessage is available: {0}. Download it"
|
||||||
" from https://github.com/Bitmessage/PyBitmessage/releases/latest"
|
" from https://github.com/Bitmessage/PyBitmessage/releases/latest"
|
||||||
).arg(self.notifiedNewVersion)
|
).format(self.notifiedNewVersion)
|
||||||
)
|
)
|
||||||
|
|
||||||
def displayAlert(self, title, text, exitAfterUserClicksOk):
|
def displayAlert(self, title, text, exitAfterUserClicksOk):
|
||||||
|
@ -1998,9 +2029,9 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
def rerenderAddressBook(self):
|
def rerenderAddressBook(self):
|
||||||
def addRow (address, label, type):
|
def addRow (address, label, type):
|
||||||
self.ui.tableWidgetAddressBook.insertRow(0)
|
self.ui.tableWidgetAddressBook.insertRow(0)
|
||||||
newItem = Ui_AddressBookWidgetItemLabel(address, unicode(label, 'utf-8'), type)
|
newItem = Ui_AddressBookWidgetItemLabel(address, unic(ustr(label)), type)
|
||||||
self.ui.tableWidgetAddressBook.setItem(0, 0, newItem)
|
self.ui.tableWidgetAddressBook.setItem(0, 0, newItem)
|
||||||
newItem = Ui_AddressBookWidgetItemAddress(address, unicode(label, 'utf-8'), type)
|
newItem = Ui_AddressBookWidgetItemAddress(address, unic(ustr(label)), type)
|
||||||
self.ui.tableWidgetAddressBook.setItem(0, 1, newItem)
|
self.ui.tableWidgetAddressBook.setItem(0, 1, newItem)
|
||||||
|
|
||||||
oldRows = {}
|
oldRows = {}
|
||||||
|
@ -2018,6 +2049,8 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
queryreturn = sqlQuery('SELECT label, address FROM subscriptions WHERE enabled = 1')
|
queryreturn = sqlQuery('SELECT label, address FROM subscriptions WHERE enabled = 1')
|
||||||
for row in queryreturn:
|
for row in queryreturn:
|
||||||
label, address = row
|
label, address = row
|
||||||
|
label = label.decode("utf-8", "replace")
|
||||||
|
address = address.decode("utf-8", "replace")
|
||||||
newRows[address] = [label, AccountMixin.SUBSCRIPTION]
|
newRows[address] = [label, AccountMixin.SUBSCRIPTION]
|
||||||
# chans
|
# chans
|
||||||
for address in config.addresses(True):
|
for address in config.addresses(True):
|
||||||
|
@ -2028,6 +2061,8 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
queryreturn = sqlQuery('SELECT * FROM addressbook')
|
queryreturn = sqlQuery('SELECT * FROM addressbook')
|
||||||
for row in queryreturn:
|
for row in queryreturn:
|
||||||
label, address = row
|
label, address = row
|
||||||
|
label = label.decode("utf-8", "replace")
|
||||||
|
address = address.decode("utf-8", "replace")
|
||||||
newRows[address] = [label, AccountMixin.NORMAL]
|
newRows[address] = [label, AccountMixin.NORMAL]
|
||||||
|
|
||||||
completerList = []
|
completerList = []
|
||||||
|
@ -2041,7 +2076,7 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
self.ui.tableWidgetAddressBook.removeRow(oldRows[address][2])
|
self.ui.tableWidgetAddressBook.removeRow(oldRows[address][2])
|
||||||
for address in newRows:
|
for address in newRows:
|
||||||
addRow(address, newRows[address][0], newRows[address][1])
|
addRow(address, newRows[address][0], newRows[address][1])
|
||||||
completerList.append(unicode(newRows[address][0], encoding="UTF-8") + " <" + address + ">")
|
completerList.append(unic(ustr(newRows[address][0]) + " <" + ustr(address) + ">"))
|
||||||
|
|
||||||
# sort
|
# sort
|
||||||
self.ui.tableWidgetAddressBook.sortByColumn(
|
self.ui.tableWidgetAddressBook.sortByColumn(
|
||||||
|
@ -2079,22 +2114,22 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
self.ui.tabWidgetSend.indexOf(self.ui.sendDirect):
|
self.ui.tabWidgetSend.indexOf(self.ui.sendDirect):
|
||||||
# message to specific people
|
# message to specific people
|
||||||
sendMessageToPeople = True
|
sendMessageToPeople = True
|
||||||
fromAddress = str(self.ui.comboBoxSendFrom.itemData(
|
fromAddress = ustr(self.ui.comboBoxSendFrom.itemData(
|
||||||
self.ui.comboBoxSendFrom.currentIndex(),
|
self.ui.comboBoxSendFrom.currentIndex(),
|
||||||
QtCore.Qt.UserRole).toString())
|
QtCore.Qt.UserRole))
|
||||||
toAddresses = str(self.ui.lineEditTo.text().toUtf8())
|
toAddresses = ustr(self.ui.lineEditTo.text())
|
||||||
subject = str(self.ui.lineEditSubject.text().toUtf8())
|
subject = ustr(self.ui.lineEditSubject.text())
|
||||||
message = str(
|
message = ustr(
|
||||||
self.ui.textEditMessage.document().toPlainText().toUtf8())
|
self.ui.textEditMessage.document().toPlainText())
|
||||||
else:
|
else:
|
||||||
# broadcast message
|
# broadcast message
|
||||||
sendMessageToPeople = False
|
sendMessageToPeople = False
|
||||||
fromAddress = str(self.ui.comboBoxSendFromBroadcast.itemData(
|
fromAddress = ustr(self.ui.comboBoxSendFromBroadcast.itemData(
|
||||||
self.ui.comboBoxSendFromBroadcast.currentIndex(),
|
self.ui.comboBoxSendFromBroadcast.currentIndex(),
|
||||||
QtCore.Qt.UserRole).toString())
|
QtCore.Qt.UserRole))
|
||||||
subject = str(self.ui.lineEditSubjectBroadcast.text().toUtf8())
|
subject = ustr(self.ui.lineEditSubjectBroadcast.text())
|
||||||
message = str(
|
message = ustr(
|
||||||
self.ui.textEditMessageBroadcast.document().toPlainText().toUtf8())
|
self.ui.textEditMessageBroadcast.document().toPlainText())
|
||||||
"""
|
"""
|
||||||
The whole network message must fit in 2^18 bytes.
|
The whole network message must fit in 2^18 bytes.
|
||||||
Let's assume 500 bytes of overhead. If someone wants to get that
|
Let's assume 500 bytes of overhead. If someone wants to get that
|
||||||
|
@ -2108,9 +2143,9 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
_translate(
|
_translate(
|
||||||
"MainWindow",
|
"MainWindow",
|
||||||
"The message that you are trying to send is too long"
|
"The message that you are trying to send is too long"
|
||||||
" by %1 bytes. (The maximum is 261644 bytes). Please"
|
" by {0} bytes. (The maximum is 261644 bytes). Please"
|
||||||
" cut it down before sending."
|
" cut it down before sending."
|
||||||
).arg(len(message) - (2 ** 18 - 500)))
|
).format(len(message) - (2 ** 18 - 500)))
|
||||||
return
|
return
|
||||||
|
|
||||||
acct = accountClass(fromAddress)
|
acct = accountClass(fromAddress)
|
||||||
|
@ -2159,15 +2194,15 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
"MainWindow",
|
"MainWindow",
|
||||||
"Error: Your account wasn't registered at"
|
"Error: Your account wasn't registered at"
|
||||||
" an email gateway. Sending registration"
|
" an email gateway. Sending registration"
|
||||||
" now as %1, please wait for the registration"
|
" now as {0}, please wait for the registration"
|
||||||
" to be processed before retrying sending."
|
" to be processed before retrying sending."
|
||||||
).arg(email)
|
).format(email)
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
status, addressVersionNumber, streamNumber = decodeAddress(toAddress)[:3]
|
status, addressVersionNumber, streamNumber = decodeAddress(toAddress)[:3]
|
||||||
if status != 'success':
|
if status != 'success':
|
||||||
try:
|
try:
|
||||||
toAddress = unicode(toAddress, 'utf-8', 'ignore')
|
toAddress = unic(ustr(toAddress))
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
logger.error('Error: Could not decode recipient address ' + toAddress + ':' + status)
|
logger.error('Error: Could not decode recipient address ' + toAddress + ':' + status)
|
||||||
|
@ -2176,58 +2211,58 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
self.updateStatusBar(_translate(
|
self.updateStatusBar(_translate(
|
||||||
"MainWindow",
|
"MainWindow",
|
||||||
"Error: Bitmessage addresses start with"
|
"Error: Bitmessage addresses start with"
|
||||||
" BM- Please check the recipient address %1"
|
" BM- Please check the recipient address {0}"
|
||||||
).arg(toAddress))
|
).format(toAddress))
|
||||||
elif status == 'checksumfailed':
|
elif status == 'checksumfailed':
|
||||||
self.updateStatusBar(_translate(
|
self.updateStatusBar(_translate(
|
||||||
"MainWindow",
|
"MainWindow",
|
||||||
"Error: The recipient address %1 is not"
|
"Error: The recipient address {0} is not"
|
||||||
" typed or copied correctly. Please check it."
|
" typed or copied correctly. Please check it."
|
||||||
).arg(toAddress))
|
).format(toAddress))
|
||||||
elif status == 'invalidcharacters':
|
elif status == 'invalidcharacters':
|
||||||
self.updateStatusBar(_translate(
|
self.updateStatusBar(_translate(
|
||||||
"MainWindow",
|
"MainWindow",
|
||||||
"Error: The recipient address %1 contains"
|
"Error: The recipient address {0} contains"
|
||||||
" invalid characters. Please check it."
|
" invalid characters. Please check it."
|
||||||
).arg(toAddress))
|
).format(toAddress))
|
||||||
elif status == 'versiontoohigh':
|
elif status == 'versiontoohigh':
|
||||||
self.updateStatusBar(_translate(
|
self.updateStatusBar(_translate(
|
||||||
"MainWindow",
|
"MainWindow",
|
||||||
"Error: The version of the recipient address"
|
"Error: The version of the recipient address"
|
||||||
" %1 is too high. Either you need to upgrade"
|
" {0} is too high. Either you need to upgrade"
|
||||||
" your Bitmessage software or your"
|
" your Bitmessage software or your"
|
||||||
" acquaintance is being clever."
|
" acquaintance is being clever."
|
||||||
).arg(toAddress))
|
).format(toAddress))
|
||||||
elif status == 'ripetooshort':
|
elif status == 'ripetooshort':
|
||||||
self.updateStatusBar(_translate(
|
self.updateStatusBar(_translate(
|
||||||
"MainWindow",
|
"MainWindow",
|
||||||
"Error: Some data encoded in the recipient"
|
"Error: Some data encoded in the recipient"
|
||||||
" address %1 is too short. There might be"
|
" address {0} is too short. There might be"
|
||||||
" something wrong with the software of"
|
" something wrong with the software of"
|
||||||
" your acquaintance."
|
" your acquaintance."
|
||||||
).arg(toAddress))
|
).format(toAddress))
|
||||||
elif status == 'ripetoolong':
|
elif status == 'ripetoolong':
|
||||||
self.updateStatusBar(_translate(
|
self.updateStatusBar(_translate(
|
||||||
"MainWindow",
|
"MainWindow",
|
||||||
"Error: Some data encoded in the recipient"
|
"Error: Some data encoded in the recipient"
|
||||||
" address %1 is too long. There might be"
|
" address {0} is too long. There might be"
|
||||||
" something wrong with the software of"
|
" something wrong with the software of"
|
||||||
" your acquaintance."
|
" your acquaintance."
|
||||||
).arg(toAddress))
|
).format(toAddress))
|
||||||
elif status == 'varintmalformed':
|
elif status == 'varintmalformed':
|
||||||
self.updateStatusBar(_translate(
|
self.updateStatusBar(_translate(
|
||||||
"MainWindow",
|
"MainWindow",
|
||||||
"Error: Some data encoded in the recipient"
|
"Error: Some data encoded in the recipient"
|
||||||
" address %1 is malformed. There might be"
|
" address {0} is malformed. There might be"
|
||||||
" something wrong with the software of"
|
" something wrong with the software of"
|
||||||
" your acquaintance."
|
" your acquaintance."
|
||||||
).arg(toAddress))
|
).format(toAddress))
|
||||||
else:
|
else:
|
||||||
self.updateStatusBar(_translate(
|
self.updateStatusBar(_translate(
|
||||||
"MainWindow",
|
"MainWindow",
|
||||||
"Error: Something is wrong with the"
|
"Error: Something is wrong with the"
|
||||||
" recipient address %1."
|
" recipient address {0}."
|
||||||
).arg(toAddress))
|
).format(toAddress))
|
||||||
elif fromAddress == '':
|
elif fromAddress == '':
|
||||||
self.updateStatusBar(_translate(
|
self.updateStatusBar(_translate(
|
||||||
"MainWindow",
|
"MainWindow",
|
||||||
|
@ -2244,9 +2279,9 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
_translate("MainWindow", "Address version number"),
|
_translate("MainWindow", "Address version number"),
|
||||||
_translate(
|
_translate(
|
||||||
"MainWindow",
|
"MainWindow",
|
||||||
"Concerning the address %1, Bitmessage cannot understand address version numbers"
|
"Concerning the address {0}, Bitmessage cannot understand address version numbers"
|
||||||
" of %2. Perhaps upgrade Bitmessage to the latest version."
|
" of {1}. Perhaps upgrade Bitmessage to the latest version."
|
||||||
).arg(toAddress).arg(str(addressVersionNumber)))
|
).format(toAddress, str(addressVersionNumber)))
|
||||||
continue
|
continue
|
||||||
if streamNumber > 1 or streamNumber == 0:
|
if streamNumber > 1 or streamNumber == 0:
|
||||||
QtGui.QMessageBox.about(
|
QtGui.QMessageBox.about(
|
||||||
|
@ -2254,9 +2289,9 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
_translate("MainWindow", "Stream number"),
|
_translate("MainWindow", "Stream number"),
|
||||||
_translate(
|
_translate(
|
||||||
"MainWindow",
|
"MainWindow",
|
||||||
"Concerning the address %1, Bitmessage cannot handle stream numbers of %2."
|
"Concerning the address {0}, Bitmessage cannot handle stream numbers of {1}."
|
||||||
" Perhaps upgrade Bitmessage to the latest version."
|
" Perhaps upgrade Bitmessage to the latest version."
|
||||||
).arg(toAddress).arg(str(streamNumber)))
|
).format(toAddress, str(streamNumber)))
|
||||||
continue
|
continue
|
||||||
self.statusbar.clearMessage()
|
self.statusbar.clearMessage()
|
||||||
if state.statusIconColor == 'red':
|
if state.statusIconColor == 'red':
|
||||||
|
@ -2272,10 +2307,11 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
subject=subject, message=message, encoding=encoding)
|
subject=subject, message=message, encoding=encoding)
|
||||||
toLabel = ''
|
toLabel = ''
|
||||||
queryreturn = sqlQuery('''select label from addressbook where address=?''',
|
queryreturn = sqlQuery('''select label from addressbook where address=?''',
|
||||||
toAddress)
|
dbstr(toAddress))
|
||||||
if queryreturn != []:
|
if queryreturn != []:
|
||||||
for row in queryreturn:
|
for row in queryreturn:
|
||||||
toLabel, = row
|
toLabel, = row
|
||||||
|
toLabel = toLabel.decode("utf-8", "replace")
|
||||||
|
|
||||||
self.displayNewSentMessage(
|
self.displayNewSentMessage(
|
||||||
toAddress, toLabel, fromAddress, subject, message, ackdata)
|
toAddress, toLabel, fromAddress, subject, message, ackdata)
|
||||||
|
@ -2341,11 +2377,11 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
))
|
))
|
||||||
|
|
||||||
def click_pushButtonFetchNamecoinID(self):
|
def click_pushButtonFetchNamecoinID(self):
|
||||||
identities = str(self.ui.lineEditTo.text().toUtf8()).split(";")
|
identities = ustr(self.ui.lineEditTo.text()).split(";")
|
||||||
err, addr = self.namecoin.query(identities[-1].strip())
|
err, addr = self.namecoin.query(identities[-1].strip())
|
||||||
if err is not None:
|
if err is not None:
|
||||||
self.updateStatusBar(
|
self.updateStatusBar(
|
||||||
_translate("MainWindow", "Error: %1").arg(err))
|
_translate("MainWindow", "Error: {0}").format(err))
|
||||||
else:
|
else:
|
||||||
identities[-1] = addr
|
identities[-1] = addr
|
||||||
self.ui.lineEditTo.setText("; ".join(identities))
|
self.ui.lineEditTo.setText("; ".join(identities))
|
||||||
|
@ -2358,7 +2394,7 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
self.ui.tabWidgetSend.setCurrentIndex(
|
self.ui.tabWidgetSend.setCurrentIndex(
|
||||||
self.ui.tabWidgetSend.indexOf(
|
self.ui.tabWidgetSend.indexOf(
|
||||||
self.ui.sendBroadcast
|
self.ui.sendBroadcast
|
||||||
if config.safeGetBoolean(str(address), 'mailinglist')
|
if config.safeGetBoolean(ustr(address), 'mailinglist')
|
||||||
else self.ui.sendDirect
|
else self.ui.sendDirect
|
||||||
))
|
))
|
||||||
|
|
||||||
|
@ -2371,14 +2407,14 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
addressInKeysFile, 'enabled')
|
addressInKeysFile, 'enabled')
|
||||||
isMaillinglist = config.safeGetBoolean(addressInKeysFile, 'mailinglist')
|
isMaillinglist = config.safeGetBoolean(addressInKeysFile, 'mailinglist')
|
||||||
if isEnabled and not isMaillinglist:
|
if isEnabled and not isMaillinglist:
|
||||||
label = unicode(config.get(addressInKeysFile, 'label'), 'utf-8', 'ignore').strip()
|
label = unic(ustr(config.get(addressInKeysFile, 'label')).strip())
|
||||||
if label == "":
|
if label == "":
|
||||||
label = addressInKeysFile
|
label = addressInKeysFile
|
||||||
self.ui.comboBoxSendFrom.addItem(avatarize(addressInKeysFile), label, addressInKeysFile)
|
self.ui.comboBoxSendFrom.addItem(avatarize(addressInKeysFile), label, addressInKeysFile)
|
||||||
# self.ui.comboBoxSendFrom.model().sort(1, Qt.AscendingOrder)
|
# self.ui.comboBoxSendFrom.model().sort(1, Qt.AscendingOrder)
|
||||||
for i in range(self.ui.comboBoxSendFrom.count()):
|
for i in range(self.ui.comboBoxSendFrom.count()):
|
||||||
address = str(self.ui.comboBoxSendFrom.itemData(
|
address = ustr(self.ui.comboBoxSendFrom.itemData(
|
||||||
i, QtCore.Qt.UserRole).toString())
|
i, QtCore.Qt.UserRole))
|
||||||
self.ui.comboBoxSendFrom.setItemData(
|
self.ui.comboBoxSendFrom.setItemData(
|
||||||
i, AccountColor(address).accountColor(),
|
i, AccountColor(address).accountColor(),
|
||||||
QtCore.Qt.ForegroundRole)
|
QtCore.Qt.ForegroundRole)
|
||||||
|
@ -2395,13 +2431,13 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
addressInKeysFile, 'enabled')
|
addressInKeysFile, 'enabled')
|
||||||
isChan = config.safeGetBoolean(addressInKeysFile, 'chan')
|
isChan = config.safeGetBoolean(addressInKeysFile, 'chan')
|
||||||
if isEnabled and not isChan:
|
if isEnabled and not isChan:
|
||||||
label = unicode(config.get(addressInKeysFile, 'label'), 'utf-8', 'ignore').strip()
|
label = unic(ustr(config.get(addressInKeysFile, 'label')).strip())
|
||||||
if label == "":
|
if label == "":
|
||||||
label = addressInKeysFile
|
label = addressInKeysFile
|
||||||
self.ui.comboBoxSendFromBroadcast.addItem(avatarize(addressInKeysFile), label, addressInKeysFile)
|
self.ui.comboBoxSendFromBroadcast.addItem(avatarize(addressInKeysFile), label, addressInKeysFile)
|
||||||
for i in range(self.ui.comboBoxSendFromBroadcast.count()):
|
for i in range(self.ui.comboBoxSendFromBroadcast.count()):
|
||||||
address = str(self.ui.comboBoxSendFromBroadcast.itemData(
|
address = ustr(self.ui.comboBoxSendFromBroadcast.itemData(
|
||||||
i, QtCore.Qt.UserRole).toString())
|
i, QtCore.Qt.UserRole))
|
||||||
self.ui.comboBoxSendFromBroadcast.setItemData(
|
self.ui.comboBoxSendFromBroadcast.setItemData(
|
||||||
i, AccountColor(address).accountColor(),
|
i, AccountColor(address).accountColor(),
|
||||||
QtCore.Qt.ForegroundRole)
|
QtCore.Qt.ForegroundRole)
|
||||||
|
@ -2500,8 +2536,8 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
'bitmessagesettings', 'showtraynotifications'):
|
'bitmessagesettings', 'showtraynotifications'):
|
||||||
self.notifierShow(
|
self.notifierShow(
|
||||||
_translate("MainWindow", "New Message"),
|
_translate("MainWindow", "New Message"),
|
||||||
_translate("MainWindow", "From %1").arg(
|
_translate("MainWindow", "From {0}").format(
|
||||||
unicode(acct.fromLabel, 'utf-8')),
|
unic(ustr(acct.fromLabel))),
|
||||||
sound.SOUND_UNKNOWN
|
sound.SOUND_UNKNOWN
|
||||||
)
|
)
|
||||||
if self.getCurrentAccount() is not None and (
|
if self.getCurrentAccount() is not None and (
|
||||||
|
@ -2560,7 +2596,7 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
# Add to database (perhaps this should be separated from the MyForm class)
|
# Add to database (perhaps this should be separated from the MyForm class)
|
||||||
sqlExecute(
|
sqlExecute(
|
||||||
'''INSERT INTO subscriptions VALUES (?,?,?)''',
|
'''INSERT INTO subscriptions VALUES (?,?,?)''',
|
||||||
label, address, True
|
dbstr(label), dbstr(address), True
|
||||||
)
|
)
|
||||||
self.rerenderMessagelistFromLabels()
|
self.rerenderMessagelistFromLabels()
|
||||||
shared.reloadBroadcastSendersForWhichImWatching()
|
shared.reloadBroadcastSendersForWhichImWatching()
|
||||||
|
@ -2639,7 +2675,7 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
# Only settings remain here
|
# Only settings remain here
|
||||||
acct.settings()
|
acct.settings()
|
||||||
for i in range(self.ui.comboBoxSendFrom.count()):
|
for i in range(self.ui.comboBoxSendFrom.count()):
|
||||||
if str(self.ui.comboBoxSendFrom.itemData(i).toPyObject()) \
|
if ustr(self.ui.comboBoxSendFrom.itemData(i)) \
|
||||||
== acct.fromAddress:
|
== acct.fromAddress:
|
||||||
self.ui.comboBoxSendFrom.setCurrentIndex(i)
|
self.ui.comboBoxSendFrom.setCurrentIndex(i)
|
||||||
break
|
break
|
||||||
|
@ -2674,13 +2710,18 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
|
|
||||||
msgids = []
|
msgids = []
|
||||||
for i in range(0, idCount):
|
for i in range(0, idCount):
|
||||||
msgids.append(tableWidget.item(i, 3).data())
|
msgids.append(sqlite3.Binary(as_msgid(tableWidget.item(i, 3).data())))
|
||||||
for col in xrange(tableWidget.columnCount()):
|
for col in xrange(tableWidget.columnCount()):
|
||||||
tableWidget.item(i, col).setUnread(False)
|
tableWidget.item(i, col).setUnread(False)
|
||||||
|
|
||||||
markread = sqlExecuteChunked(
|
markread = sqlExecuteChunked(
|
||||||
"UPDATE inbox SET read = 1 WHERE msgid IN({0}) AND read=0",
|
"UPDATE inbox SET read = 1 WHERE msgid IN({0}) AND read=0",
|
||||||
idCount, *msgids
|
False, idCount, *msgids
|
||||||
|
)
|
||||||
|
if markread < 1:
|
||||||
|
markread = sqlExecuteChunked(
|
||||||
|
"UPDATE inbox SET read = 1 WHERE msgid IN({0}) AND read=0",
|
||||||
|
True, idCount, *msgids
|
||||||
)
|
)
|
||||||
|
|
||||||
if markread > 0:
|
if markread > 0:
|
||||||
|
@ -2706,7 +2747,7 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
if reply != QtGui.QMessageBox.Yes:
|
if reply != QtGui.QMessageBox.Yes:
|
||||||
return
|
return
|
||||||
config.set(
|
config.set(
|
||||||
'bitmessagesettings', 'dontconnect', str(dontconnect_option))
|
'bitmessagesettings', 'dontconnect', ustr(dontconnect_option))
|
||||||
config.save()
|
config.save()
|
||||||
self.ui.updateNetworkSwitchMenuLabel(dontconnect_option)
|
self.ui.updateNetworkSwitchMenuLabel(dontconnect_option)
|
||||||
|
|
||||||
|
@ -2790,7 +2831,7 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
self.quitAccepted = True
|
self.quitAccepted = True
|
||||||
|
|
||||||
self.updateStatusBar(_translate(
|
self.updateStatusBar(_translate(
|
||||||
"MainWindow", "Shutting down PyBitmessage... %1%").arg(0))
|
"MainWindow", "Shutting down PyBitmessage... {0}%").format(0))
|
||||||
|
|
||||||
if waitForConnection:
|
if waitForConnection:
|
||||||
self.updateStatusBar(_translate(
|
self.updateStatusBar(_translate(
|
||||||
|
@ -2824,8 +2865,8 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
maxWorkerQueue = curWorkerQueue
|
maxWorkerQueue = curWorkerQueue
|
||||||
if curWorkerQueue > 0:
|
if curWorkerQueue > 0:
|
||||||
self.updateStatusBar(_translate(
|
self.updateStatusBar(_translate(
|
||||||
"MainWindow", "Waiting for PoW to finish... %1%"
|
"MainWindow", "Waiting for PoW to finish... {0}%"
|
||||||
).arg(50 * (maxWorkerQueue - curWorkerQueue) /
|
).format(50 * (maxWorkerQueue - curWorkerQueue) /
|
||||||
maxWorkerQueue))
|
maxWorkerQueue))
|
||||||
time.sleep(0.5)
|
time.sleep(0.5)
|
||||||
QtCore.QCoreApplication.processEvents(
|
QtCore.QCoreApplication.processEvents(
|
||||||
|
@ -2833,7 +2874,7 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
)
|
)
|
||||||
|
|
||||||
self.updateStatusBar(_translate(
|
self.updateStatusBar(_translate(
|
||||||
"MainWindow", "Shutting down Pybitmessage... %1%").arg(50))
|
"MainWindow", "Shutting down Pybitmessage... {0}%").format(50))
|
||||||
|
|
||||||
QtCore.QCoreApplication.processEvents(
|
QtCore.QCoreApplication.processEvents(
|
||||||
QtCore.QEventLoop.AllEvents, 1000
|
QtCore.QEventLoop.AllEvents, 1000
|
||||||
|
@ -2847,14 +2888,14 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
|
|
||||||
# check if upload (of objects created locally) pending
|
# check if upload (of objects created locally) pending
|
||||||
self.updateStatusBar(_translate(
|
self.updateStatusBar(_translate(
|
||||||
"MainWindow", "Waiting for objects to be sent... %1%").arg(50))
|
"MainWindow", "Waiting for objects to be sent... {0}%").format(50))
|
||||||
maxPendingUpload = max(1, pendingUpload())
|
maxPendingUpload = max(1, pendingUpload())
|
||||||
|
|
||||||
while pendingUpload() > 1:
|
while pendingUpload() > 1:
|
||||||
self.updateStatusBar(_translate(
|
self.updateStatusBar(_translate(
|
||||||
"MainWindow",
|
"MainWindow",
|
||||||
"Waiting for objects to be sent... %1%"
|
"Waiting for objects to be sent... {0}%"
|
||||||
).arg(int(50 + 20 * (pendingUpload() / maxPendingUpload))))
|
).format(int(50 + 20 * (pendingUpload() / maxPendingUpload))))
|
||||||
time.sleep(0.5)
|
time.sleep(0.5)
|
||||||
QtCore.QCoreApplication.processEvents(
|
QtCore.QCoreApplication.processEvents(
|
||||||
QtCore.QEventLoop.AllEvents, 1000
|
QtCore.QEventLoop.AllEvents, 1000
|
||||||
|
@ -2869,12 +2910,12 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
|
|
||||||
# save state and geometry self and all widgets
|
# save state and geometry self and all widgets
|
||||||
self.updateStatusBar(_translate(
|
self.updateStatusBar(_translate(
|
||||||
"MainWindow", "Saving settings... %1%").arg(70))
|
"MainWindow", "Saving settings... {0}%").format(70))
|
||||||
QtCore.QCoreApplication.processEvents(
|
QtCore.QCoreApplication.processEvents(
|
||||||
QtCore.QEventLoop.AllEvents, 1000
|
QtCore.QEventLoop.AllEvents, 1000
|
||||||
)
|
)
|
||||||
self.saveSettings()
|
self.saveSettings()
|
||||||
for attr, obj in self.ui.__dict__.iteritems():
|
for attr, obj in six.iteritems(self.ui.__dict__):
|
||||||
if hasattr(obj, "__class__") \
|
if hasattr(obj, "__class__") \
|
||||||
and isinstance(obj, settingsmixin.SettingsMixin):
|
and isinstance(obj, settingsmixin.SettingsMixin):
|
||||||
saveMethod = getattr(obj, "saveSettings", None)
|
saveMethod = getattr(obj, "saveSettings", None)
|
||||||
|
@ -2882,18 +2923,18 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
obj.saveSettings()
|
obj.saveSettings()
|
||||||
|
|
||||||
self.updateStatusBar(_translate(
|
self.updateStatusBar(_translate(
|
||||||
"MainWindow", "Shutting down core... %1%").arg(80))
|
"MainWindow", "Shutting down core... {0}%").format(80))
|
||||||
QtCore.QCoreApplication.processEvents(
|
QtCore.QCoreApplication.processEvents(
|
||||||
QtCore.QEventLoop.AllEvents, 1000
|
QtCore.QEventLoop.AllEvents, 1000
|
||||||
)
|
)
|
||||||
shutdown.doCleanShutdown()
|
shutdown.doCleanShutdown()
|
||||||
|
|
||||||
self.updateStatusBar(_translate(
|
self.updateStatusBar(_translate(
|
||||||
"MainWindow", "Stopping notifications... %1%").arg(90))
|
"MainWindow", "Stopping notifications... {0}%").format(90))
|
||||||
self.tray.hide()
|
self.tray.hide()
|
||||||
|
|
||||||
self.updateStatusBar(_translate(
|
self.updateStatusBar(_translate(
|
||||||
"MainWindow", "Shutdown imminent... %1%").arg(100))
|
"MainWindow", "Shutdown imminent... {0}%").format(100))
|
||||||
|
|
||||||
logger.info("Shutdown complete")
|
logger.info("Shutdown complete")
|
||||||
self.close()
|
self.close()
|
||||||
|
@ -2919,10 +2960,14 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
if not msgid:
|
if not msgid:
|
||||||
return
|
return
|
||||||
queryreturn = sqlQuery(
|
queryreturn = sqlQuery(
|
||||||
'''select message from inbox where msgid=?''', msgid)
|
'SELECT message FROM inbox WHERE msgid=?', sqlite3.Binary(msgid))
|
||||||
|
if len(queryreturn) < 1:
|
||||||
|
queryreturn = sqlQuery(
|
||||||
|
'SELECT message FROM inbox WHERE msgid=CAST(? AS TEXT)', msgid)
|
||||||
if queryreturn != []:
|
if queryreturn != []:
|
||||||
for row in queryreturn:
|
for row in queryreturn:
|
||||||
messageText, = row
|
messageText, = row
|
||||||
|
messageText = messageText.decode("utf-8", "replace")
|
||||||
|
|
||||||
lines = messageText.split('\n')
|
lines = messageText.split('\n')
|
||||||
totalLines = len(lines)
|
totalLines = len(lines)
|
||||||
|
@ -2937,8 +2982,8 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
lines[i] = '<br><br>'
|
lines[i] = '<br><br>'
|
||||||
content = ' '.join(lines) # To keep the whitespace between lines
|
content = ' '.join(lines) # To keep the whitespace between lines
|
||||||
content = shared.fixPotentiallyInvalidUTF8Data(content)
|
content = shared.fixPotentiallyInvalidUTF8Data(content)
|
||||||
content = unicode(content, 'utf-8)')
|
content = unic(ustr(content))
|
||||||
textEdit.setHtml(QtCore.QString(content))
|
textEdit.setHtml(content)
|
||||||
|
|
||||||
def on_action_InboxMarkUnread(self):
|
def on_action_InboxMarkUnread(self):
|
||||||
tableWidget = self.getCurrentMessagelist()
|
tableWidget = self.getCurrentMessagelist()
|
||||||
|
@ -2949,8 +2994,8 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
# modified = 0
|
# modified = 0
|
||||||
for row in tableWidget.selectedIndexes():
|
for row in tableWidget.selectedIndexes():
|
||||||
currentRow = row.row()
|
currentRow = row.row()
|
||||||
msgid = tableWidget.item(currentRow, 3).data()
|
msgid = as_msgid(tableWidget.item(currentRow, 3).data())
|
||||||
msgids.add(msgid)
|
msgids.add(sqlite3.Binary(msgid))
|
||||||
# if not tableWidget.item(currentRow, 0).unread:
|
# if not tableWidget.item(currentRow, 0).unread:
|
||||||
# modified += 1
|
# modified += 1
|
||||||
self.updateUnreadStatus(tableWidget, currentRow, msgid, False)
|
self.updateUnreadStatus(tableWidget, currentRow, msgid, False)
|
||||||
|
@ -2958,9 +3003,14 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
# for 1081
|
# for 1081
|
||||||
idCount = len(msgids)
|
idCount = len(msgids)
|
||||||
# rowcount =
|
# rowcount =
|
||||||
|
total_row_count = sqlExecuteChunked(
|
||||||
|
'''UPDATE inbox SET read=0 WHERE msgid IN ({0}) AND read=1''',
|
||||||
|
False, idCount, *msgids
|
||||||
|
)
|
||||||
|
if total_row_count < 1:
|
||||||
sqlExecuteChunked(
|
sqlExecuteChunked(
|
||||||
'''UPDATE inbox SET read=0 WHERE msgid IN ({0}) AND read=1''',
|
'''UPDATE inbox SET read=0 WHERE msgid IN ({0}) AND read=1''',
|
||||||
idCount, *msgids
|
True, idCount, *msgids
|
||||||
)
|
)
|
||||||
|
|
||||||
self.propagateUnreadCount()
|
self.propagateUnreadCount()
|
||||||
|
@ -3005,7 +3055,7 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
self.ui.comboBoxSendFrom, self.ui.comboBoxSendFromBroadcast
|
self.ui.comboBoxSendFrom, self.ui.comboBoxSendFromBroadcast
|
||||||
):
|
):
|
||||||
for i in range(box.count()):
|
for i in range(box.count()):
|
||||||
if str(box.itemData(i).toPyObject()) == address:
|
if ustr(box.itemData(i)) == ustr(address):
|
||||||
box.setCurrentIndex(i)
|
box.setCurrentIndex(i)
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
|
@ -3039,13 +3089,18 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
acct = accountClass(toAddressAtCurrentInboxRow)
|
acct = accountClass(toAddressAtCurrentInboxRow)
|
||||||
fromAddressAtCurrentInboxRow = tableWidget.item(
|
fromAddressAtCurrentInboxRow = tableWidget.item(
|
||||||
currentInboxRow, column_from).address
|
currentInboxRow, column_from).address
|
||||||
msgid = tableWidget.item(currentInboxRow, 3).data()
|
msgid = as_msgid(tableWidget.item(currentInboxRow, 3).data())
|
||||||
queryreturn = sqlQuery(
|
queryreturn = sqlQuery(
|
||||||
"SELECT message FROM inbox WHERE msgid=?", msgid
|
"SELECT message FROM inbox WHERE msgid=?", sqlite3.Binary(msgid)
|
||||||
) or sqlQuery("SELECT message FROM sent WHERE ackdata=?", msgid)
|
) or sqlQuery("SELECT message FROM sent WHERE ackdata=?", sqlite3.Binary(msgid))
|
||||||
|
if len(queryreturn) < 1:
|
||||||
|
queryreturn = sqlQuery(
|
||||||
|
"SELECT message FROM inbox WHERE msgid=CAST(? AS TEXT)", msgid
|
||||||
|
) or sqlQuery("SELECT message FROM sent WHERE ackdata=CAST(? AS TEXT)", msgid)
|
||||||
if queryreturn != []:
|
if queryreturn != []:
|
||||||
for row in queryreturn:
|
for row in queryreturn:
|
||||||
messageAtCurrentInboxRow, = row
|
messageAtCurrentInboxRow, = row
|
||||||
|
messageAtCurrentInboxRow = messageAtCurrentInboxRow.decode("utf-8", "replace")
|
||||||
acct.parseMessage(
|
acct.parseMessage(
|
||||||
toAddressAtCurrentInboxRow, fromAddressAtCurrentInboxRow,
|
toAddressAtCurrentInboxRow, fromAddressAtCurrentInboxRow,
|
||||||
tableWidget.item(currentInboxRow, 2).subject,
|
tableWidget.item(currentInboxRow, 2).subject,
|
||||||
|
@ -3066,9 +3121,9 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
self, _translate("MainWindow", "Address is gone"),
|
self, _translate("MainWindow", "Address is gone"),
|
||||||
_translate(
|
_translate(
|
||||||
"MainWindow",
|
"MainWindow",
|
||||||
"Bitmessage cannot find your address %1. Perhaps you"
|
"Bitmessage cannot find your address {0}. Perhaps you"
|
||||||
" removed it?"
|
" removed it?"
|
||||||
).arg(toAddressAtCurrentInboxRow), QtGui.QMessageBox.Ok)
|
).format(toAddressAtCurrentInboxRow), QtGui.QMessageBox.Ok)
|
||||||
elif not config.getboolean(
|
elif not config.getboolean(
|
||||||
toAddressAtCurrentInboxRow, 'enabled'):
|
toAddressAtCurrentInboxRow, 'enabled'):
|
||||||
QtGui.QMessageBox.information(
|
QtGui.QMessageBox.information(
|
||||||
|
@ -3096,7 +3151,7 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
tableWidget.item(currentInboxRow, column_from).label or (
|
tableWidget.item(currentInboxRow, column_from).label or (
|
||||||
isinstance(acct, GatewayAccount) and
|
isinstance(acct, GatewayAccount) and
|
||||||
fromAddressAtCurrentInboxRow == acct.relayAddress):
|
fromAddressAtCurrentInboxRow == acct.relayAddress):
|
||||||
self.ui.lineEditTo.setText(str(acct.fromAddress))
|
self.ui.lineEditTo.setText(ustr(acct.fromAddress))
|
||||||
else:
|
else:
|
||||||
self.ui.lineEditTo.setText(
|
self.ui.lineEditTo.setText(
|
||||||
tableWidget.item(currentInboxRow, column_from).accountString()
|
tableWidget.item(currentInboxRow, column_from).accountString()
|
||||||
|
@ -3111,7 +3166,7 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
' reply to the chan address.')
|
' reply to the chan address.')
|
||||||
if toAddressAtCurrentInboxRow == \
|
if toAddressAtCurrentInboxRow == \
|
||||||
tableWidget.item(currentInboxRow, column_to).label:
|
tableWidget.item(currentInboxRow, column_to).label:
|
||||||
self.ui.lineEditTo.setText(str(toAddressAtCurrentInboxRow))
|
self.ui.lineEditTo.setText(ustr(toAddressAtCurrentInboxRow))
|
||||||
else:
|
else:
|
||||||
self.ui.lineEditTo.setText(
|
self.ui.lineEditTo.setText(
|
||||||
tableWidget.item(currentInboxRow, column_to).accountString()
|
tableWidget.item(currentInboxRow, column_to).accountString()
|
||||||
|
@ -3120,7 +3175,7 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
self.setSendFromComboBox(toAddressAtCurrentInboxRow)
|
self.setSendFromComboBox(toAddressAtCurrentInboxRow)
|
||||||
|
|
||||||
quotedText = self.quoted_text(
|
quotedText = self.quoted_text(
|
||||||
unicode(messageAtCurrentInboxRow, 'utf-8', 'replace'))
|
unic(ustr(messageAtCurrentInboxRow)))
|
||||||
widget['message'].setPlainText(quotedText)
|
widget['message'].setPlainText(quotedText)
|
||||||
if acct.subject[0:3] in ('Re:', 'RE:'):
|
if acct.subject[0:3] in ('Re:', 'RE:'):
|
||||||
widget['subject'].setText(
|
widget['subject'].setText(
|
||||||
|
@ -3157,13 +3212,13 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
currentInboxRow, 0).data(QtCore.Qt.UserRole)
|
currentInboxRow, 0).data(QtCore.Qt.UserRole)
|
||||||
# Let's make sure that it isn't already in the address book
|
# Let's make sure that it isn't already in the address book
|
||||||
queryreturn = sqlQuery('''select * from blacklist where address=?''',
|
queryreturn = sqlQuery('''select * from blacklist where address=?''',
|
||||||
addressAtCurrentInboxRow)
|
dbstr(addressAtCurrentInboxRow))
|
||||||
if queryreturn == []:
|
if queryreturn == []:
|
||||||
label = "\"" + tableWidget.item(currentInboxRow, 2).subject + "\" in " + config.get(
|
label = "\"" + tableWidget.item(currentInboxRow, 2).subject + "\" in " + config.get(
|
||||||
recipientAddress, "label")
|
recipientAddress, "label")
|
||||||
sqlExecute('''INSERT INTO blacklist VALUES (?,?, ?)''',
|
sqlExecute('''INSERT INTO blacklist VALUES (?,?, ?)''',
|
||||||
label,
|
dbstr(label),
|
||||||
addressAtCurrentInboxRow, True)
|
dbstr(addressAtCurrentInboxRow), True)
|
||||||
self.ui.blackwhitelist.rerenderBlackWhiteList()
|
self.ui.blackwhitelist.rerenderBlackWhiteList()
|
||||||
self.updateStatusBar(_translate(
|
self.updateStatusBar(_translate(
|
||||||
"MainWindow",
|
"MainWindow",
|
||||||
|
@ -3188,15 +3243,15 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
messageLists = (messageLists,)
|
messageLists = (messageLists,)
|
||||||
for messageList in messageLists:
|
for messageList in messageLists:
|
||||||
if row is not None:
|
if row is not None:
|
||||||
inventoryHash = messageList.item(row, 3).data()
|
inventoryHash = as_msgid(messageList.item(row, 3).data())
|
||||||
messageList.removeRow(row)
|
messageList.removeRow(row)
|
||||||
elif inventoryHash is not None:
|
elif inventoryHash is not None:
|
||||||
for i in range(messageList.rowCount() - 1, -1, -1):
|
for i in range(messageList.rowCount() - 1, -1, -1):
|
||||||
if messageList.item(i, 3).data() == inventoryHash:
|
if as_msgid(messageList.item(i, 3).data()) == inventoryHash:
|
||||||
messageList.removeRow(i)
|
messageList.removeRow(i)
|
||||||
elif ackData is not None:
|
elif ackData is not None:
|
||||||
for i in range(messageList.rowCount() - 1, -1, -1):
|
for i in range(messageList.rowCount() - 1, -1, -1):
|
||||||
if messageList.item(i, 3).data() == ackData:
|
if as_msgid(messageList.item(i, 3).data()) == ackData:
|
||||||
messageList.removeRow(i)
|
messageList.removeRow(i)
|
||||||
|
|
||||||
# Send item on the Inbox tab to trash
|
# Send item on the Inbox tab to trash
|
||||||
|
@ -3216,16 +3271,21 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
)[::-1]:
|
)[::-1]:
|
||||||
for i in range(r.bottomRow() - r.topRow() + 1):
|
for i in range(r.bottomRow() - r.topRow() + 1):
|
||||||
inventoryHashesToTrash.add(
|
inventoryHashesToTrash.add(
|
||||||
tableWidget.item(r.topRow() + i, 3).data())
|
sqlite3.Binary(as_msgid(tableWidget.item(r.topRow() + i, 3).data())))
|
||||||
currentRow = r.topRow()
|
currentRow = r.topRow()
|
||||||
self.getCurrentMessageTextedit().setText("")
|
self.getCurrentMessageTextedit().setText("")
|
||||||
tableWidget.model().removeRows(
|
tableWidget.model().removeRows(
|
||||||
r.topRow(), r.bottomRow() - r.topRow() + 1)
|
r.topRow(), r.bottomRow() - r.topRow() + 1)
|
||||||
idCount = len(inventoryHashesToTrash)
|
idCount = len(inventoryHashesToTrash)
|
||||||
|
total_row_count = sqlExecuteChunked(
|
||||||
|
("DELETE FROM inbox" if folder == "trash" or shifted else
|
||||||
|
"UPDATE inbox SET folder='trash', read=1") +
|
||||||
|
" WHERE msgid IN ({0})", False, idCount, *inventoryHashesToTrash)
|
||||||
|
if total_row_count < 1:
|
||||||
sqlExecuteChunked(
|
sqlExecuteChunked(
|
||||||
("DELETE FROM inbox" if folder == "trash" or shifted else
|
("DELETE FROM inbox" if folder == "trash" or shifted else
|
||||||
"UPDATE inbox SET folder='trash', read=1") +
|
"UPDATE inbox SET folder='trash', read=1") +
|
||||||
" WHERE msgid IN ({0})", idCount, *inventoryHashesToTrash)
|
" WHERE msgid IN ({0})", True, idCount, *inventoryHashesToTrash)
|
||||||
tableWidget.selectRow(0 if currentRow == 0 else currentRow - 1)
|
tableWidget.selectRow(0 if currentRow == 0 else currentRow - 1)
|
||||||
tableWidget.setUpdatesEnabled(True)
|
tableWidget.setUpdatesEnabled(True)
|
||||||
self.propagateUnreadCount(folder)
|
self.propagateUnreadCount(folder)
|
||||||
|
@ -3244,16 +3304,20 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
)[::-1]:
|
)[::-1]:
|
||||||
for i in range(r.bottomRow() - r.topRow() + 1):
|
for i in range(r.bottomRow() - r.topRow() + 1):
|
||||||
inventoryHashesToTrash.add(
|
inventoryHashesToTrash.add(
|
||||||
tableWidget.item(r.topRow() + i, 3).data())
|
sqlite3.Binary(as_msgid(tableWidget.item(r.topRow() + i, 3).data())))
|
||||||
currentRow = r.topRow()
|
currentRow = r.topRow()
|
||||||
self.getCurrentMessageTextedit().setText("")
|
self.getCurrentMessageTextedit().setText("")
|
||||||
tableWidget.model().removeRows(
|
tableWidget.model().removeRows(
|
||||||
r.topRow(), r.bottomRow() - r.topRow() + 1)
|
r.topRow(), r.bottomRow() - r.topRow() + 1)
|
||||||
tableWidget.selectRow(0 if currentRow == 0 else currentRow - 1)
|
tableWidget.selectRow(0 if currentRow == 0 else currentRow - 1)
|
||||||
idCount = len(inventoryHashesToTrash)
|
idCount = len(inventoryHashesToTrash)
|
||||||
|
total_row_count = sqlExecuteChunked(
|
||||||
|
"UPDATE inbox SET folder='inbox' WHERE msgid IN({0})",
|
||||||
|
False, idCount, *inventoryHashesToTrash)
|
||||||
|
if total_row_count < 1:
|
||||||
sqlExecuteChunked(
|
sqlExecuteChunked(
|
||||||
"UPDATE inbox SET folder='inbox' WHERE msgid IN({0})",
|
"UPDATE inbox SET folder='inbox' WHERE msgid IN({0})",
|
||||||
idCount, *inventoryHashesToTrash)
|
True, idCount, *inventoryHashesToTrash)
|
||||||
tableWidget.selectRow(0 if currentRow == 0 else currentRow - 1)
|
tableWidget.selectRow(0 if currentRow == 0 else currentRow - 1)
|
||||||
tableWidget.setUpdatesEnabled(True)
|
tableWidget.setUpdatesEnabled(True)
|
||||||
self.propagateUnreadCount()
|
self.propagateUnreadCount()
|
||||||
|
@ -3265,18 +3329,22 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
return
|
return
|
||||||
currentInboxRow = tableWidget.currentRow()
|
currentInboxRow = tableWidget.currentRow()
|
||||||
try:
|
try:
|
||||||
subjectAtCurrentInboxRow = str(tableWidget.item(
|
subjectAtCurrentInboxRow = ustr(tableWidget.item(
|
||||||
currentInboxRow, 2).data(QtCore.Qt.UserRole))
|
currentInboxRow, 2).data(QtCore.Qt.UserRole))
|
||||||
except:
|
except:
|
||||||
subjectAtCurrentInboxRow = ''
|
subjectAtCurrentInboxRow = ''
|
||||||
|
|
||||||
# Retrieve the message data out of the SQL database
|
# Retrieve the message data out of the SQL database
|
||||||
msgid = tableWidget.item(currentInboxRow, 3).data()
|
msgid = as_msgid(tableWidget.item(currentInboxRow, 3).data())
|
||||||
queryreturn = sqlQuery(
|
queryreturn = sqlQuery(
|
||||||
'''select message from inbox where msgid=?''', msgid)
|
'''select message from inbox where msgid=?''', sqlite3.Binary(msgid))
|
||||||
|
if len(queryreturn) < 1:
|
||||||
|
queryreturn = sqlQuery(
|
||||||
|
'''select message from inbox where msgid=CAST(? AS TEXT)''', msgid)
|
||||||
if queryreturn != []:
|
if queryreturn != []:
|
||||||
for row in queryreturn:
|
for row in queryreturn:
|
||||||
message, = row
|
message, = row
|
||||||
|
message = message.decode("utf-8", "replace")
|
||||||
|
|
||||||
defaultFilename = "".join(x for x in subjectAtCurrentInboxRow if x.isalnum()) + '.txt'
|
defaultFilename = "".join(x for x in subjectAtCurrentInboxRow if x.isalnum()) + '.txt'
|
||||||
filename = QtGui.QFileDialog.getSaveFileName(
|
filename = QtGui.QFileDialog.getSaveFileName(
|
||||||
|
@ -3288,7 +3356,7 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
return
|
return
|
||||||
try:
|
try:
|
||||||
f = open(filename, 'w')
|
f = open(filename, 'w')
|
||||||
f.write(message)
|
f.write(message.encode("utf-8", "replace"))
|
||||||
f.close()
|
f.close()
|
||||||
except Exception:
|
except Exception:
|
||||||
logger.exception('Message not saved', exc_info=True)
|
logger.exception('Message not saved', exc_info=True)
|
||||||
|
@ -3303,11 +3371,17 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
shifted = QtGui.QApplication.queryKeyboardModifiers() & QtCore.Qt.ShiftModifier
|
shifted = QtGui.QApplication.queryKeyboardModifiers() & QtCore.Qt.ShiftModifier
|
||||||
while tableWidget.selectedIndexes() != []:
|
while tableWidget.selectedIndexes() != []:
|
||||||
currentRow = tableWidget.selectedIndexes()[0].row()
|
currentRow = tableWidget.selectedIndexes()[0].row()
|
||||||
ackdataToTrash = tableWidget.item(currentRow, 3).data()
|
ackdataToTrash = as_msgid(tableWidget.item(currentRow, 3).data())
|
||||||
|
rowcount = sqlExecute(
|
||||||
|
"DELETE FROM sent" if folder == "trash" or shifted else
|
||||||
|
"UPDATE sent SET folder='trash'"
|
||||||
|
" WHERE ackdata = ?", sqlite3.Binary(ackdataToTrash)
|
||||||
|
)
|
||||||
|
if rowcount < 1:
|
||||||
sqlExecute(
|
sqlExecute(
|
||||||
"DELETE FROM sent" if folder == "trash" or shifted else
|
"DELETE FROM sent" if folder == "trash" or shifted else
|
||||||
"UPDATE sent SET folder='trash'"
|
"UPDATE sent SET folder='trash'"
|
||||||
" WHERE ackdata = ?", ackdataToTrash
|
" WHERE ackdata = CAST(? AS TEXT)", ackdataToTrash
|
||||||
)
|
)
|
||||||
self.getCurrentMessageTextedit().setPlainText("")
|
self.getCurrentMessageTextedit().setPlainText("")
|
||||||
tableWidget.removeRow(currentRow)
|
tableWidget.removeRow(currentRow)
|
||||||
|
@ -3322,8 +3396,12 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
addressAtCurrentRow = self.ui.tableWidgetInbox.item(
|
addressAtCurrentRow = self.ui.tableWidgetInbox.item(
|
||||||
currentRow, 0).data(QtCore.Qt.UserRole)
|
currentRow, 0).data(QtCore.Qt.UserRole)
|
||||||
toRipe = decodeAddress(addressAtCurrentRow)[3]
|
toRipe = decodeAddress(addressAtCurrentRow)[3]
|
||||||
sqlExecute(
|
rowcount = sqlExecute(
|
||||||
'''UPDATE sent SET status='forcepow' WHERE toripe=? AND status='toodifficult' and folder='sent' ''',
|
'''UPDATE sent SET status='forcepow' WHERE toripe=? AND status='toodifficult' and folder='sent' ''',
|
||||||
|
sqlite3.Binary(toRipe))
|
||||||
|
if rowcount < 1:
|
||||||
|
sqlExecute(
|
||||||
|
'''UPDATE sent SET status='forcepow' WHERE toripe=CAST(? AS TEXT) AND status='toodifficult' and folder='sent' ''',
|
||||||
toRipe)
|
toRipe)
|
||||||
queryreturn = sqlQuery('''select ackdata FROM sent WHERE status='forcepow' ''')
|
queryreturn = sqlQuery('''select ackdata FROM sent WHERE status='forcepow' ''')
|
||||||
for row in queryreturn:
|
for row in queryreturn:
|
||||||
|
@ -3337,7 +3415,7 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
addressAtCurrentRow = self.ui.tableWidgetInbox.item(
|
addressAtCurrentRow = self.ui.tableWidgetInbox.item(
|
||||||
currentRow, 0).data(QtCore.Qt.UserRole)
|
currentRow, 0).data(QtCore.Qt.UserRole)
|
||||||
clipboard = QtGui.QApplication.clipboard()
|
clipboard = QtGui.QApplication.clipboard()
|
||||||
clipboard.setText(str(addressAtCurrentRow))
|
clipboard.setText(ustr(addressAtCurrentRow))
|
||||||
|
|
||||||
# Group of functions for the Address Book dialog box
|
# Group of functions for the Address Book dialog box
|
||||||
def on_action_AddressBookNew(self):
|
def on_action_AddressBookNew(self):
|
||||||
|
@ -3349,7 +3427,7 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
0].row()
|
0].row()
|
||||||
item = self.ui.tableWidgetAddressBook.item(currentRow, 0)
|
item = self.ui.tableWidgetAddressBook.item(currentRow, 0)
|
||||||
sqlExecute(
|
sqlExecute(
|
||||||
'DELETE FROM addressbook WHERE address=?', item.address)
|
'DELETE FROM addressbook WHERE address=?', dbstr(item.address))
|
||||||
self.ui.tableWidgetAddressBook.removeRow(currentRow)
|
self.ui.tableWidgetAddressBook.removeRow(currentRow)
|
||||||
self.rerenderMessagelistFromLabels()
|
self.rerenderMessagelistFromLabels()
|
||||||
self.rerenderMessagelistToLabels()
|
self.rerenderMessagelistToLabels()
|
||||||
|
@ -3371,8 +3449,8 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
return self.updateStatusBar(_translate(
|
return self.updateStatusBar(_translate(
|
||||||
"MainWindow", "No addresses selected."))
|
"MainWindow", "No addresses selected."))
|
||||||
|
|
||||||
addresses_string = unicode(
|
addresses_string = unic(ustr(
|
||||||
self.ui.lineEditTo.text().toUtf8(), 'utf-8')
|
self.ui.lineEditTo.text()))
|
||||||
for item in selected_items:
|
for item in selected_items:
|
||||||
address_string = item.accountString()
|
address_string = item.accountString()
|
||||||
if not addresses_string:
|
if not addresses_string:
|
||||||
|
@ -3449,7 +3527,7 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
return
|
return
|
||||||
address = self.getCurrentAccount()
|
address = self.getCurrentAccount()
|
||||||
sqlExecute('''DELETE FROM subscriptions WHERE address=?''',
|
sqlExecute('''DELETE FROM subscriptions WHERE address=?''',
|
||||||
address)
|
dbstr(address))
|
||||||
self.rerenderTabTreeSubscriptions()
|
self.rerenderTabTreeSubscriptions()
|
||||||
self.rerenderMessagelistFromLabels()
|
self.rerenderMessagelistFromLabels()
|
||||||
self.rerenderAddressBook()
|
self.rerenderAddressBook()
|
||||||
|
@ -3458,13 +3536,13 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
def on_action_SubscriptionsClipboard(self):
|
def on_action_SubscriptionsClipboard(self):
|
||||||
address = self.getCurrentAccount()
|
address = self.getCurrentAccount()
|
||||||
clipboard = QtGui.QApplication.clipboard()
|
clipboard = QtGui.QApplication.clipboard()
|
||||||
clipboard.setText(str(address))
|
clipboard.setText(ustr(address))
|
||||||
|
|
||||||
def on_action_SubscriptionsEnable(self):
|
def on_action_SubscriptionsEnable(self):
|
||||||
address = self.getCurrentAccount()
|
address = self.getCurrentAccount()
|
||||||
sqlExecute(
|
sqlExecute(
|
||||||
'''update subscriptions set enabled=1 WHERE address=?''',
|
'''update subscriptions set enabled=1 WHERE address=?''',
|
||||||
address)
|
dbstr(address))
|
||||||
account = self.getCurrentItem()
|
account = self.getCurrentItem()
|
||||||
account.setEnabled(True)
|
account.setEnabled(True)
|
||||||
self.rerenderAddressBook()
|
self.rerenderAddressBook()
|
||||||
|
@ -3474,7 +3552,7 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
address = self.getCurrentAccount()
|
address = self.getCurrentAccount()
|
||||||
sqlExecute(
|
sqlExecute(
|
||||||
'''update subscriptions set enabled=0 WHERE address=?''',
|
'''update subscriptions set enabled=0 WHERE address=?''',
|
||||||
address)
|
dbstr(address))
|
||||||
account = self.getCurrentItem()
|
account = self.getCurrentItem()
|
||||||
account.setEnabled(False)
|
account.setEnabled(False)
|
||||||
self.rerenderAddressBook()
|
self.rerenderAddressBook()
|
||||||
|
@ -3576,7 +3654,7 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
if messagelist:
|
if messagelist:
|
||||||
currentRow = messagelist.currentRow()
|
currentRow = messagelist.currentRow()
|
||||||
if currentRow >= 0:
|
if currentRow >= 0:
|
||||||
return messagelist.item(currentRow, 3).data()
|
return as_msgid(messagelist.item(currentRow, 3).data())
|
||||||
|
|
||||||
def getCurrentMessageTextedit(self):
|
def getCurrentMessageTextedit(self):
|
||||||
currentIndex = self.ui.tabWidget.currentIndex()
|
currentIndex = self.ui.tabWidget.currentIndex()
|
||||||
|
@ -3610,9 +3688,9 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
self.ui.inboxSearchLineEditChans,
|
self.ui.inboxSearchLineEditChans,
|
||||||
)
|
)
|
||||||
if currentIndex >= 0 and currentIndex < len(messagelistList):
|
if currentIndex >= 0 and currentIndex < len(messagelistList):
|
||||||
return (
|
return ustr(
|
||||||
messagelistList[currentIndex] if retObj
|
messagelistList[currentIndex] if retObj
|
||||||
else messagelistList[currentIndex].text().toUtf8().data())
|
else ustr(messagelistList[currentIndex].text()))
|
||||||
|
|
||||||
def getCurrentSearchOption(self, currentIndex=None):
|
def getCurrentSearchOption(self, currentIndex=None):
|
||||||
if currentIndex is None:
|
if currentIndex is None:
|
||||||
|
@ -3681,7 +3759,7 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
" delete the channel?"
|
" delete the channel?"
|
||||||
), QtGui.QMessageBox.Yes | QtGui.QMessageBox.No
|
), QtGui.QMessageBox.Yes | QtGui.QMessageBox.No
|
||||||
) == QtGui.QMessageBox.Yes:
|
) == QtGui.QMessageBox.Yes:
|
||||||
config.remove_section(str(account.address))
|
config.remove_section(ustr(account.address))
|
||||||
else:
|
else:
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
|
@ -3714,7 +3792,7 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
account.setEnabled(False)
|
account.setEnabled(False)
|
||||||
|
|
||||||
def disableIdentity(self, address):
|
def disableIdentity(self, address):
|
||||||
config.set(str(address), 'enabled', 'false')
|
config.set(ustr(address), 'enabled', 'false')
|
||||||
config.save()
|
config.save()
|
||||||
shared.reloadMyAddressHashes()
|
shared.reloadMyAddressHashes()
|
||||||
self.rerenderAddressBook()
|
self.rerenderAddressBook()
|
||||||
|
@ -3722,7 +3800,7 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
def on_action_Clipboard(self):
|
def on_action_Clipboard(self):
|
||||||
address = self.getCurrentAccount()
|
address = self.getCurrentAccount()
|
||||||
clipboard = QtGui.QApplication.clipboard()
|
clipboard = QtGui.QApplication.clipboard()
|
||||||
clipboard.setText(str(address))
|
clipboard.setText(ustr(address))
|
||||||
|
|
||||||
def on_action_ClipboardMessagelist(self):
|
def on_action_ClipboardMessagelist(self):
|
||||||
tableWidget = self.getCurrentMessagelist()
|
tableWidget = self.getCurrentMessagelist()
|
||||||
|
@ -3742,7 +3820,7 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
if isinstance(account, GatewayAccount) and otherAddress == account.relayAddress and (
|
if isinstance(account, GatewayAccount) and otherAddress == account.relayAddress and (
|
||||||
(currentColumn in [0, 2] and self.getCurrentFolder() == "sent") or
|
(currentColumn in [0, 2] and self.getCurrentFolder() == "sent") or
|
||||||
(currentColumn in [1, 2] and self.getCurrentFolder() != "sent")):
|
(currentColumn in [1, 2] and self.getCurrentFolder() != "sent")):
|
||||||
text = str(tableWidget.item(currentRow, currentColumn).label)
|
text = ustr(tableWidget.item(currentRow, currentColumn).label)
|
||||||
else:
|
else:
|
||||||
text = tableWidget.item(currentRow, currentColumn).data(QtCore.Qt.UserRole)
|
text = tableWidget.item(currentRow, currentColumn).data(QtCore.Qt.UserRole)
|
||||||
|
|
||||||
|
@ -3759,8 +3837,8 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
|
|
||||||
def on_action_SetAvatar(self, thisTableWidget):
|
def on_action_SetAvatar(self, thisTableWidget):
|
||||||
currentRow = thisTableWidget.currentRow()
|
currentRow = thisTableWidget.currentRow()
|
||||||
addressAtCurrentRow = thisTableWidget.item(
|
addressAtCurrentRow = ustr(thisTableWidget.item(
|
||||||
currentRow, 1).text()
|
currentRow, 1).text())
|
||||||
setToIdenticon = not self.setAvatar(addressAtCurrentRow)
|
setToIdenticon = not self.setAvatar(addressAtCurrentRow)
|
||||||
if setToIdenticon:
|
if setToIdenticon:
|
||||||
thisTableWidget.item(
|
thisTableWidget.item(
|
||||||
|
@ -3770,7 +3848,7 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
def setAvatar(self, addressAtCurrentRow):
|
def setAvatar(self, addressAtCurrentRow):
|
||||||
if not os.path.exists(state.appdata + 'avatars/'):
|
if not os.path.exists(state.appdata + 'avatars/'):
|
||||||
os.makedirs(state.appdata + 'avatars/')
|
os.makedirs(state.appdata + 'avatars/')
|
||||||
hash = hashlib.md5(addBMIfNotPresent(addressAtCurrentRow)).hexdigest()
|
hash = hashlib.md5(addBMIfNotPresent(addressAtCurrentRow).encode("utf-8", "replace")).hexdigest()
|
||||||
extensions = [
|
extensions = [
|
||||||
'PNG', 'GIF', 'JPG', 'JPEG', 'SVG', 'BMP', 'MNG', 'PBM',
|
'PNG', 'GIF', 'JPG', 'JPEG', 'SVG', 'BMP', 'MNG', 'PBM',
|
||||||
'PGM', 'PPM', 'TIFF', 'XBM', 'XPM', 'TGA']
|
'PGM', 'PPM', 'TIFF', 'XBM', 'XPM', 'TGA']
|
||||||
|
@ -3861,23 +3939,23 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
|
|
||||||
def on_action_AddressBookSetSound(self):
|
def on_action_AddressBookSetSound(self):
|
||||||
widget = self.ui.tableWidgetAddressBook
|
widget = self.ui.tableWidgetAddressBook
|
||||||
self.setAddressSound(widget.item(widget.currentRow(), 0).text())
|
self.setAddressSound(ustr(widget.item(widget.currentRow(), 0).text()))
|
||||||
|
|
||||||
def setAddressSound(self, addr):
|
def setAddressSound(self, addr):
|
||||||
filters = [unicode(_translate(
|
filters = [unic(_translate(
|
||||||
"MainWindow", "Sound files (%s)" %
|
"MainWindow", "Sound files (%s)" %
|
||||||
' '.join(['*%s%s' % (os.extsep, ext) for ext in sound.extensions])
|
' '.join(['*%s%s' % (os.extsep, ext) for ext in sound.extensions])
|
||||||
))]
|
))]
|
||||||
sourcefile = unicode(QtGui.QFileDialog.getOpenFileName(
|
sourcefile = unic(ustr(QtGui.QFileDialog.getOpenFileName(
|
||||||
self, _translate("MainWindow", "Set notification sound..."),
|
self, _translate("MainWindow", "Set notification sound..."),
|
||||||
filter=';;'.join(filters)
|
filter=';;'.join(filters)
|
||||||
))
|
)))
|
||||||
|
|
||||||
if not sourcefile:
|
if not sourcefile:
|
||||||
return
|
return
|
||||||
|
|
||||||
destdir = os.path.join(state.appdata, 'sounds')
|
destdir = os.path.join(state.appdata, 'sounds')
|
||||||
destfile = unicode(addr) + os.path.splitext(sourcefile)[-1]
|
destfile = unic(ustr(addr) + os.path.splitext(sourcefile)[-1])
|
||||||
destination = os.path.join(destdir, destfile)
|
destination = os.path.join(destdir, destfile)
|
||||||
|
|
||||||
if sourcefile == destination:
|
if sourcefile == destination:
|
||||||
|
@ -4019,10 +4097,13 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
# Check to see if this item is toodifficult and display an additional
|
# Check to see if this item is toodifficult and display an additional
|
||||||
# menu option (Force Send) if it is.
|
# menu option (Force Send) if it is.
|
||||||
if currentRow >= 0:
|
if currentRow >= 0:
|
||||||
ackData = self.ui.tableWidgetInbox.item(currentRow, 3).data()
|
ackData = as_msgid(self.ui.tableWidgetInbox.item(currentRow, 3).data())
|
||||||
queryreturn = sqlQuery('''SELECT status FROM sent where ackdata=?''', ackData)
|
queryreturn = sqlQuery('''SELECT status FROM sent where ackdata=?''', sqlite3.Binary(ackData))
|
||||||
|
if len(queryreturn) < 1:
|
||||||
|
queryreturn = sqlQuery('''SELECT status FROM sent where ackdata=CAST(? AS TEXT)''', ackData)
|
||||||
for row in queryreturn:
|
for row in queryreturn:
|
||||||
status, = row
|
status, = row
|
||||||
|
status = status.decode("utf-8", "replace")
|
||||||
if status == 'toodifficult':
|
if status == 'toodifficult':
|
||||||
self.popMenuSent.addAction(self.actionForceSend)
|
self.popMenuSent.addAction(self.actionForceSend)
|
||||||
|
|
||||||
|
@ -4030,7 +4111,7 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
|
|
||||||
def inboxSearchLineEditUpdated(self, text):
|
def inboxSearchLineEditUpdated(self, text):
|
||||||
# dynamic search for too short text is slow
|
# dynamic search for too short text is slow
|
||||||
text = text.toUtf8()
|
text = ustr(text)
|
||||||
if 0 < len(text) < 3:
|
if 0 < len(text) < 3:
|
||||||
return
|
return
|
||||||
messagelist = self.getCurrentMessagelist()
|
messagelist = self.getCurrentMessagelist()
|
||||||
|
@ -4045,7 +4126,7 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
logger.debug("Search return pressed")
|
logger.debug("Search return pressed")
|
||||||
searchLine = self.getCurrentSearchLine()
|
searchLine = self.getCurrentSearchLine()
|
||||||
messagelist = self.getCurrentMessagelist()
|
messagelist = self.getCurrentMessagelist()
|
||||||
if messagelist and len(str(searchLine)) < 3:
|
if messagelist and len(ustr(searchLine)) < 3:
|
||||||
searchOption = self.getCurrentSearchOption()
|
searchOption = self.getCurrentSearchOption()
|
||||||
account = self.getCurrentAccount()
|
account = self.getCurrentAccount()
|
||||||
folder = self.getCurrentFolder()
|
folder = self.getCurrentFolder()
|
||||||
|
@ -4087,7 +4168,7 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
if item.type == AccountMixin.ALL:
|
if item.type == AccountMixin.ALL:
|
||||||
return
|
return
|
||||||
|
|
||||||
newLabel = unicode(item.text(0), 'utf-8', 'ignore')
|
newLabel = unic(ustr(item.text(0)))
|
||||||
oldLabel = item.defaultLabel()
|
oldLabel = item.defaultLabel()
|
||||||
|
|
||||||
# unchanged, do not do anything either
|
# unchanged, do not do anything either
|
||||||
|
@ -4119,7 +4200,14 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
folder = self.getCurrentFolder()
|
folder = self.getCurrentFolder()
|
||||||
if msgid:
|
if msgid:
|
||||||
queryreturn = sqlQuery(
|
queryreturn = sqlQuery(
|
||||||
'''SELECT message FROM %s WHERE %s=?''' % (
|
'SELECT message FROM %s WHERE %s=?' % (
|
||||||
|
('sent', 'ackdata') if folder == 'sent'
|
||||||
|
else ('inbox', 'msgid')
|
||||||
|
), sqlite3.Binary(msgid)
|
||||||
|
)
|
||||||
|
if len(queryreturn) < 1:
|
||||||
|
queryreturn = sqlQuery(
|
||||||
|
'SELECT message FROM %s WHERE %s=CAST(? AS TEXT)' % (
|
||||||
('sent', 'ackdata') if folder == 'sent'
|
('sent', 'ackdata') if folder == 'sent'
|
||||||
else ('inbox', 'msgid')
|
else ('inbox', 'msgid')
|
||||||
), msgid
|
), msgid
|
||||||
|
@ -4127,6 +4215,7 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
message = queryreturn[-1][0]
|
message = queryreturn[-1][0]
|
||||||
|
message = message.decode("utf-8", "replace")
|
||||||
except NameError:
|
except NameError:
|
||||||
message = ""
|
message = ""
|
||||||
except IndexError:
|
except IndexError:
|
||||||
|
@ -4141,10 +4230,16 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
if tableWidget.item(currentRow, 0).unread is True:
|
if tableWidget.item(currentRow, 0).unread is True:
|
||||||
self.updateUnreadStatus(tableWidget, currentRow, msgid)
|
self.updateUnreadStatus(tableWidget, currentRow, msgid)
|
||||||
# propagate
|
# propagate
|
||||||
if folder != 'sent' and sqlExecute(
|
rowcount = sqlExecute(
|
||||||
'''UPDATE inbox SET read=1 WHERE msgid=? AND read=0''',
|
'''UPDATE inbox SET read=1 WHERE msgid=? AND read=0''',
|
||||||
|
sqlite3.Binary(msgid)
|
||||||
|
)
|
||||||
|
if rowcount < 1:
|
||||||
|
rowcount = sqlExecute(
|
||||||
|
'''UPDATE inbox SET read=1 WHERE msgid=CAST(? AS TEXT) AND read=0''',
|
||||||
msgid
|
msgid
|
||||||
) > 0:
|
)
|
||||||
|
if folder != 'sent' and rowcount > 0:
|
||||||
self.propagateUnreadCount()
|
self.propagateUnreadCount()
|
||||||
|
|
||||||
messageTextedit.setCurrentFont(QtGui.QFont())
|
messageTextedit.setCurrentFont(QtGui.QFont())
|
||||||
|
@ -4158,8 +4253,8 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
self.rerenderMessagelistToLabels()
|
self.rerenderMessagelistToLabels()
|
||||||
completerList = self.ui.lineEditTo.completer().model().stringList()
|
completerList = self.ui.lineEditTo.completer().model().stringList()
|
||||||
for i in range(len(completerList)):
|
for i in range(len(completerList)):
|
||||||
if unicode(completerList[i]).endswith(" <" + item.address + ">"):
|
if unic(ustr(completerList[i])).endswith(" <" + ustr(item.address) + ">"):
|
||||||
completerList[i] = item.label + " <" + item.address + ">"
|
completerList[i] = ustr(item.label) + " <" + ustr(item.address) + ">"
|
||||||
self.ui.lineEditTo.completer().model().setStringList(completerList)
|
self.ui.lineEditTo.completer().model().setStringList(completerList)
|
||||||
|
|
||||||
def tabWidgetCurrentChanged(self, n):
|
def tabWidgetCurrentChanged(self, n):
|
||||||
|
@ -4212,7 +4307,7 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
|
|
||||||
def initSettings(self):
|
def initSettings(self):
|
||||||
self.loadSettings()
|
self.loadSettings()
|
||||||
for attr, obj in self.ui.__dict__.iteritems():
|
for attr, obj in six.iteritems(self.ui.__dict__):
|
||||||
if hasattr(obj, "__class__") and \
|
if hasattr(obj, "__class__") and \
|
||||||
isinstance(obj, settingsmixin.SettingsMixin):
|
isinstance(obj, settingsmixin.SettingsMixin):
|
||||||
loadMethod = getattr(obj, "loadSettings", None)
|
loadMethod = getattr(obj, "loadSettings", None)
|
||||||
|
|
|
@ -13,8 +13,11 @@ import inspect
|
||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
|
import sqlite3
|
||||||
|
|
||||||
|
from unqstr import ustr
|
||||||
from PyQt4 import QtGui
|
from PyQt4 import QtGui
|
||||||
|
from dbcompat import dbstr
|
||||||
|
|
||||||
import queues
|
import queues
|
||||||
from addresses import decodeAddress
|
from addresses import decodeAddress
|
||||||
|
@ -38,6 +41,8 @@ def getSortedSubscriptions(count=False):
|
||||||
ret = {}
|
ret = {}
|
||||||
for row in queryreturn:
|
for row in queryreturn:
|
||||||
label, address, enabled = row
|
label, address, enabled = row
|
||||||
|
label = label.decode("utf-8", "replace")
|
||||||
|
address = address.decode("utf-8", "replace")
|
||||||
ret[address] = {}
|
ret[address] = {}
|
||||||
ret[address]["inbox"] = {}
|
ret[address]["inbox"] = {}
|
||||||
ret[address]["inbox"]['label'] = label
|
ret[address]["inbox"]['label'] = label
|
||||||
|
@ -47,9 +52,11 @@ def getSortedSubscriptions(count=False):
|
||||||
queryreturn = sqlQuery('''SELECT fromaddress, folder, count(msgid) as cnt
|
queryreturn = sqlQuery('''SELECT fromaddress, folder, count(msgid) as cnt
|
||||||
FROM inbox, subscriptions ON subscriptions.address = inbox.fromaddress
|
FROM inbox, subscriptions ON subscriptions.address = inbox.fromaddress
|
||||||
WHERE read = 0 AND toaddress = ?
|
WHERE read = 0 AND toaddress = ?
|
||||||
GROUP BY inbox.fromaddress, folder''', str_broadcast_subscribers)
|
GROUP BY inbox.fromaddress, folder''', dbstr(str_broadcast_subscribers))
|
||||||
for row in queryreturn:
|
for row in queryreturn:
|
||||||
address, folder, cnt = row
|
address, folder, cnt = row
|
||||||
|
address = address.decode("utf-8", "replace")
|
||||||
|
folder = folder.decode("utf-8", "replace")
|
||||||
if folder not in ret[address]:
|
if folder not in ret[address]:
|
||||||
ret[address][folder] = {
|
ret[address][folder] = {
|
||||||
'label': ret[address]['inbox']['label'],
|
'label': ret[address]['inbox']['label'],
|
||||||
|
@ -100,7 +107,7 @@ class AccountColor(AccountMixin): # pylint: disable=too-few-public-methods
|
||||||
elif config.safeGetBoolean(self.address, 'chan'):
|
elif config.safeGetBoolean(self.address, 'chan'):
|
||||||
self.type = AccountMixin.CHAN
|
self.type = AccountMixin.CHAN
|
||||||
elif sqlQuery(
|
elif sqlQuery(
|
||||||
'''select label from subscriptions where address=?''', self.address):
|
'''select label from subscriptions where address=?''', dbstr(self.address)):
|
||||||
self.type = AccountMixin.SUBSCRIPTION
|
self.type = AccountMixin.SUBSCRIPTION
|
||||||
else:
|
else:
|
||||||
self.type = AccountMixin.NORMAL
|
self.type = AccountMixin.NORMAL
|
||||||
|
@ -123,7 +130,7 @@ class BMAccount(object):
|
||||||
self.type = AccountMixin.BROADCAST
|
self.type = AccountMixin.BROADCAST
|
||||||
else:
|
else:
|
||||||
queryreturn = sqlQuery(
|
queryreturn = sqlQuery(
|
||||||
'''select label from subscriptions where address=?''', self.address)
|
'''select label from subscriptions where address=?''', dbstr(self.address))
|
||||||
if queryreturn:
|
if queryreturn:
|
||||||
self.type = AccountMixin.SUBSCRIPTION
|
self.type = AccountMixin.SUBSCRIPTION
|
||||||
|
|
||||||
|
@ -131,32 +138,33 @@ class BMAccount(object):
|
||||||
"""Get a label for this bitmessage account"""
|
"""Get a label for this bitmessage account"""
|
||||||
if address is None:
|
if address is None:
|
||||||
address = self.address
|
address = self.address
|
||||||
|
else:
|
||||||
|
address = ustr(address)
|
||||||
label = config.safeGet(address, 'label', address)
|
label = config.safeGet(address, 'label', address)
|
||||||
queryreturn = sqlQuery(
|
queryreturn = sqlQuery(
|
||||||
'''select label from addressbook where address=?''', address)
|
'''select label from addressbook where address=?''', dbstr(address))
|
||||||
if queryreturn != []:
|
if queryreturn != []:
|
||||||
for row in queryreturn:
|
for row in queryreturn:
|
||||||
label, = row
|
label, = row
|
||||||
|
label = label.decode("utf-8", "replace")
|
||||||
else:
|
else:
|
||||||
queryreturn = sqlQuery(
|
queryreturn = sqlQuery(
|
||||||
'''select label from subscriptions where address=?''', address)
|
'''select label from subscriptions where address=?''', dbstr(address))
|
||||||
if queryreturn != []:
|
if queryreturn != []:
|
||||||
for row in queryreturn:
|
for row in queryreturn:
|
||||||
label, = row
|
label, = row
|
||||||
|
label = label.decode("utf-8", "replace")
|
||||||
return label
|
return label
|
||||||
|
|
||||||
def parseMessage(self, toAddress, fromAddress, subject, message):
|
def parseMessage(self, toAddress, fromAddress, subject, message):
|
||||||
"""Set metadata and address labels on self"""
|
"""Set metadata and address labels on self"""
|
||||||
|
|
||||||
self.toAddress = toAddress
|
self.toAddress = ustr(toAddress)
|
||||||
self.fromAddress = fromAddress
|
self.fromAddress = ustr(fromAddress)
|
||||||
if isinstance(subject, unicode):
|
self.subject = ustr(subject)
|
||||||
self.subject = str(subject)
|
self.message = ustr(message)
|
||||||
else:
|
self.fromLabel = ustr(self.getLabel(fromAddress))
|
||||||
self.subject = subject
|
self.toLabel = ustr(self.getLabel(toAddress))
|
||||||
self.message = message
|
|
||||||
self.fromLabel = self.getLabel(fromAddress)
|
|
||||||
self.toLabel = self.getLabel(toAddress)
|
|
||||||
|
|
||||||
|
|
||||||
class NoAccount(BMAccount):
|
class NoAccount(BMAccount):
|
||||||
|
@ -201,19 +209,19 @@ class GatewayAccount(BMAccount):
|
||||||
ackdata = genAckPayload(streamNumber, stealthLevel)
|
ackdata = genAckPayload(streamNumber, stealthLevel)
|
||||||
sqlExecute(
|
sqlExecute(
|
||||||
'''INSERT INTO sent VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)''',
|
'''INSERT INTO sent VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)''',
|
||||||
'',
|
sqlite3.Binary(b''),
|
||||||
self.toAddress,
|
dbstr(self.toAddress),
|
||||||
ripe,
|
sqlite3.Binary(ripe),
|
||||||
self.fromAddress,
|
dbstr(self.fromAddress),
|
||||||
self.subject,
|
dbstr(self.subject),
|
||||||
self.message,
|
dbstr(self.message),
|
||||||
ackdata,
|
sqlite3.Binary(ackdata),
|
||||||
int(time.time()), # sentTime (this will never change)
|
int(time.time()), # sentTime (this will never change)
|
||||||
int(time.time()), # lastActionTime
|
int(time.time()), # lastActionTime
|
||||||
0, # sleepTill time. This will get set when the POW gets done.
|
0, # sleepTill time. This will get set when the POW gets done.
|
||||||
'msgqueued',
|
dbstr('msgqueued'),
|
||||||
0, # retryNumber
|
0, # retryNumber
|
||||||
'sent', # folder
|
dbstr('sent'), # folder
|
||||||
2, # encodingtype
|
2, # encodingtype
|
||||||
# not necessary to have a TTL higher than 2 days
|
# not necessary to have a TTL higher than 2 days
|
||||||
min(config.getint('bitmessagesettings', 'ttl'), 86400 * 2)
|
min(config.getint('bitmessagesettings', 'ttl'), 86400 * 2)
|
||||||
|
|
|
@ -5,12 +5,13 @@ Dialogs that work with BM address.
|
||||||
|
|
||||||
import hashlib
|
import hashlib
|
||||||
|
|
||||||
|
from unqstr import ustr, unic
|
||||||
from PyQt4 import QtCore, QtGui
|
from PyQt4 import QtCore, QtGui
|
||||||
|
|
||||||
import queues
|
import queues
|
||||||
import widgets
|
from bitmessageqt import widgets
|
||||||
import state
|
import state
|
||||||
from account import AccountMixin, GatewayAccount, MailchuckAccount, accountClass
|
from .account import AccountMixin, GatewayAccount, MailchuckAccount, accountClass
|
||||||
from addresses import addBMIfNotPresent, decodeAddress, encodeVarint
|
from addresses import addBMIfNotPresent, decodeAddress, encodeVarint
|
||||||
from bmconfigparser import config as global_config
|
from bmconfigparser import config as global_config
|
||||||
from tr import _translate
|
from tr import _translate
|
||||||
|
@ -29,12 +30,12 @@ class AddressCheckMixin(object):
|
||||||
def _onSuccess(self, addressVersion, streamNumber, ripe):
|
def _onSuccess(self, addressVersion, streamNumber, ripe):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def addressChanged(self, QString):
|
def addressChanged(self, addr):
|
||||||
"""
|
"""
|
||||||
Address validation callback, performs validation and gives feedback
|
Address validation callback, performs validation and gives feedback
|
||||||
"""
|
"""
|
||||||
status, addressVersion, streamNumber, ripe = decodeAddress(
|
status, addressVersion, streamNumber, ripe = decodeAddress(
|
||||||
str(QString))
|
ustr(addr))
|
||||||
self.valid = status == 'success'
|
self.valid = status == 'success'
|
||||||
if self.valid:
|
if self.valid:
|
||||||
self.labelAddressCheck.setText(
|
self.labelAddressCheck.setText(
|
||||||
|
@ -90,8 +91,8 @@ class AddressDataDialog(QtGui.QDialog, AddressCheckMixin):
|
||||||
"""Callback for QDIalog accepting value"""
|
"""Callback for QDIalog accepting value"""
|
||||||
if self.valid:
|
if self.valid:
|
||||||
self.data = (
|
self.data = (
|
||||||
addBMIfNotPresent(str(self.lineEditAddress.text())),
|
addBMIfNotPresent(ustr(self.lineEditAddress.text())),
|
||||||
str(self.lineEditLabel.text().toUtf8())
|
ustr(self.lineEditLabel.text())
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
queues.UISignalQueue.put(('updateStatusBar', _translate(
|
queues.UISignalQueue.put(('updateStatusBar', _translate(
|
||||||
|
@ -142,12 +143,12 @@ class NewAddressDialog(QtGui.QDialog):
|
||||||
self.comboBoxExisting.currentText())[2]
|
self.comboBoxExisting.currentText())[2]
|
||||||
queues.addressGeneratorQueue.put((
|
queues.addressGeneratorQueue.put((
|
||||||
'createRandomAddress', 4, streamNumberForAddress,
|
'createRandomAddress', 4, streamNumberForAddress,
|
||||||
str(self.newaddresslabel.text().toUtf8()), 1, "",
|
ustr(self.newaddresslabel.text()), 1, "",
|
||||||
self.checkBoxEighteenByteRipe.isChecked()
|
self.checkBoxEighteenByteRipe.isChecked()
|
||||||
))
|
))
|
||||||
else:
|
else:
|
||||||
if self.lineEditPassphrase.text() != \
|
if ustr(self.lineEditPassphrase.text()) != \
|
||||||
self.lineEditPassphraseAgain.text():
|
ustr(self.lineEditPassphraseAgain.text()):
|
||||||
QtGui.QMessageBox.about(
|
QtGui.QMessageBox.about(
|
||||||
self, _translate("MainWindow", "Passphrase mismatch"),
|
self, _translate("MainWindow", "Passphrase mismatch"),
|
||||||
_translate(
|
_translate(
|
||||||
|
@ -169,7 +170,7 @@ class NewAddressDialog(QtGui.QDialog):
|
||||||
'createDeterministicAddresses', 4, streamNumberForAddress,
|
'createDeterministicAddresses', 4, streamNumberForAddress,
|
||||||
"unused deterministic address",
|
"unused deterministic address",
|
||||||
self.spinBoxNumberOfAddressesToMake.value(),
|
self.spinBoxNumberOfAddressesToMake.value(),
|
||||||
self.lineEditPassphrase.text().toUtf8(),
|
ustr(self.lineEditPassphrase.text()),
|
||||||
self.checkBoxEighteenByteRipe.isChecked()
|
self.checkBoxEighteenByteRipe.isChecked()
|
||||||
))
|
))
|
||||||
|
|
||||||
|
@ -234,7 +235,7 @@ class SpecialAddressBehaviorDialog(QtGui.QDialog):
|
||||||
def __init__(self, parent=None, config=global_config):
|
def __init__(self, parent=None, config=global_config):
|
||||||
super(SpecialAddressBehaviorDialog, self).__init__(parent)
|
super(SpecialAddressBehaviorDialog, self).__init__(parent)
|
||||||
widgets.load('specialaddressbehavior.ui', self)
|
widgets.load('specialaddressbehavior.ui', self)
|
||||||
self.address = parent.getCurrentAccount()
|
self.address = ustr(parent.getCurrentAccount())
|
||||||
self.parent = parent
|
self.parent = parent
|
||||||
self.config = config
|
self.config = config
|
||||||
|
|
||||||
|
@ -259,7 +260,7 @@ class SpecialAddressBehaviorDialog(QtGui.QDialog):
|
||||||
self.radioButtonBehaveNormalAddress.click()
|
self.radioButtonBehaveNormalAddress.click()
|
||||||
mailingListName = config.safeGet(self.address, 'mailinglistname', '')
|
mailingListName = config.safeGet(self.address, 'mailinglistname', '')
|
||||||
self.lineEditMailingListName.setText(
|
self.lineEditMailingListName.setText(
|
||||||
unicode(mailingListName, 'utf-8')
|
unic(ustr(mailingListName))
|
||||||
)
|
)
|
||||||
|
|
||||||
QtGui.QWidget.resize(self, QtGui.QWidget.sizeHint(self))
|
QtGui.QWidget.resize(self, QtGui.QWidget.sizeHint(self))
|
||||||
|
@ -271,7 +272,7 @@ class SpecialAddressBehaviorDialog(QtGui.QDialog):
|
||||||
if self.address_is_chan:
|
if self.address_is_chan:
|
||||||
return
|
return
|
||||||
if self.radioButtonBehaveNormalAddress.isChecked():
|
if self.radioButtonBehaveNormalAddress.isChecked():
|
||||||
self.config.set(str(self.address), 'mailinglist', 'false')
|
self.config.set(self.address, 'mailinglist', 'false')
|
||||||
# Set the color to either black or grey
|
# Set the color to either black or grey
|
||||||
if self.config.getboolean(self.address, 'enabled'):
|
if self.config.getboolean(self.address, 'enabled'):
|
||||||
self.parent.setCurrentItemColor(
|
self.parent.setCurrentItemColor(
|
||||||
|
@ -280,9 +281,9 @@ class SpecialAddressBehaviorDialog(QtGui.QDialog):
|
||||||
else:
|
else:
|
||||||
self.parent.setCurrentItemColor(QtGui.QColor(128, 128, 128))
|
self.parent.setCurrentItemColor(QtGui.QColor(128, 128, 128))
|
||||||
else:
|
else:
|
||||||
self.config.set(str(self.address), 'mailinglist', 'true')
|
self.config.set(self.address, 'mailinglist', 'true')
|
||||||
self.config.set(str(self.address), 'mailinglistname', str(
|
self.config.set(self.address, 'mailinglistname', ustr(
|
||||||
self.lineEditMailingListName.text().toUtf8()))
|
self.lineEditMailingListName.text()))
|
||||||
self.parent.setCurrentItemColor(
|
self.parent.setCurrentItemColor(
|
||||||
QtGui.QColor(137, 4, 177)) # magenta
|
QtGui.QColor(137, 4, 177)) # magenta
|
||||||
self.parent.rerenderComboBoxSendFrom()
|
self.parent.rerenderComboBoxSendFrom()
|
||||||
|
@ -344,7 +345,7 @@ class EmailGatewayDialog(QtGui.QDialog):
|
||||||
|
|
||||||
if self.radioButtonRegister.isChecked() \
|
if self.radioButtonRegister.isChecked() \
|
||||||
or self.radioButtonRegister.isHidden():
|
or self.radioButtonRegister.isHidden():
|
||||||
email = str(self.lineEditEmail.text().toUtf8())
|
email = ustr(self.lineEditEmail.text())
|
||||||
self.acct.register(email)
|
self.acct.register(email)
|
||||||
self.config.set(self.acct.fromAddress, 'label', email)
|
self.config.set(self.acct.fromAddress, 'label', email)
|
||||||
self.config.set(self.acct.fromAddress, 'gateway', 'mailchuck')
|
self.config.set(self.acct.fromAddress, 'gateway', 'mailchuck')
|
||||||
|
|
|
@ -3,15 +3,16 @@ Address validator module.
|
||||||
"""
|
"""
|
||||||
# pylint: disable=too-many-branches,too-many-arguments
|
# pylint: disable=too-many-branches,too-many-arguments
|
||||||
|
|
||||||
from Queue import Empty
|
from six.moves.queue import Empty
|
||||||
|
|
||||||
|
from unqstr import ustr
|
||||||
from PyQt4 import QtGui
|
from PyQt4 import QtGui
|
||||||
|
|
||||||
from addresses import decodeAddress, addBMIfNotPresent
|
from addresses import decodeAddress, addBMIfNotPresent
|
||||||
from bmconfigparser import config
|
from bmconfigparser import config
|
||||||
from queues import apiAddressGeneratorReturnQueue, addressGeneratorQueue
|
from queues import apiAddressGeneratorReturnQueue, addressGeneratorQueue
|
||||||
from tr import _translate
|
from tr import _translate
|
||||||
from utils import str_chan
|
from .utils import str_chan
|
||||||
|
|
||||||
|
|
||||||
class AddressPassPhraseValidatorMixin(object):
|
class AddressPassPhraseValidatorMixin(object):
|
||||||
|
@ -108,26 +109,26 @@ class AddressPassPhraseValidatorMixin(object):
|
||||||
if self.addressObject is None:
|
if self.addressObject is None:
|
||||||
address = None
|
address = None
|
||||||
else:
|
else:
|
||||||
address = str(self.addressObject.text().toUtf8())
|
address = ustr(self.addressObject.text())
|
||||||
if address == "":
|
if address == "":
|
||||||
address = None
|
address = None
|
||||||
if self.passPhraseObject is None:
|
if self.passPhraseObject is None:
|
||||||
passPhrase = ""
|
passPhrase = ""
|
||||||
else:
|
else:
|
||||||
passPhrase = str(self.passPhraseObject.text().toUtf8())
|
passPhrase = ustr(self.passPhraseObject.text())
|
||||||
if passPhrase == "":
|
if passPhrase == "":
|
||||||
passPhrase = None
|
passPhrase = None
|
||||||
|
|
||||||
# no chan name
|
# no chan name
|
||||||
if passPhrase is None:
|
if passPhrase is None:
|
||||||
self.setError(_translate("AddressValidator", "Chan name/passphrase needed. You didn't enter a chan name."))
|
self.setError(_translate("AddressValidator", "Chan name/passphrase needed. You didn't enter a chan name."))
|
||||||
return (QtGui.QValidator.Intermediate, pos)
|
return (QtGui.QValidator.Intermediate, s, pos)
|
||||||
|
|
||||||
if self.addressMandatory or address is not None:
|
if self.addressMandatory or address is not None:
|
||||||
# check if address already exists:
|
# check if address already exists:
|
||||||
if address in config.addresses():
|
if address in config.addresses():
|
||||||
self.setError(_translate("AddressValidator", "Address already present as one of your identities."))
|
self.setError(_translate("AddressValidator", "Address already present as one of your identities."))
|
||||||
return (QtGui.QValidator.Intermediate, pos)
|
return (QtGui.QValidator.Intermediate, s, pos)
|
||||||
|
|
||||||
# version too high
|
# version too high
|
||||||
if decodeAddress(address)[0] == 'versiontoohigh':
|
if decodeAddress(address)[0] == 'versiontoohigh':
|
||||||
|
@ -138,12 +139,12 @@ class AddressPassPhraseValidatorMixin(object):
|
||||||
" address might be valid, its version number"
|
" address might be valid, its version number"
|
||||||
" is too new for us to handle. Perhaps you need"
|
" is too new for us to handle. Perhaps you need"
|
||||||
" to upgrade Bitmessage."))
|
" to upgrade Bitmessage."))
|
||||||
return (QtGui.QValidator.Intermediate, pos)
|
return (QtGui.QValidator.Intermediate, s, pos)
|
||||||
|
|
||||||
# invalid
|
# invalid
|
||||||
if decodeAddress(address)[0] != 'success':
|
if decodeAddress(address)[0] != 'success':
|
||||||
self.setError(_translate("AddressValidator", "The Bitmessage address is not valid."))
|
self.setError(_translate("AddressValidator", "The Bitmessage address is not valid."))
|
||||||
return (QtGui.QValidator.Intermediate, pos)
|
return (QtGui.QValidator.Intermediate, s, pos)
|
||||||
|
|
||||||
# this just disables the OK button without changing the feedback text
|
# this just disables the OK button without changing the feedback text
|
||||||
# but only if triggered by textEdited, not by clicking the Ok button
|
# but only if triggered by textEdited, not by clicking the Ok button
|
||||||
|
@ -152,15 +153,15 @@ class AddressPassPhraseValidatorMixin(object):
|
||||||
|
|
||||||
# check through generator
|
# check through generator
|
||||||
if address is None:
|
if address is None:
|
||||||
addressGeneratorQueue.put(('createChan', 4, 1, str_chan + ' ' + str(passPhrase), passPhrase, False))
|
addressGeneratorQueue.put(('createChan', 4, 1, str_chan + ' ' + ustr(passPhrase), passPhrase.encode("utf-8", "replace"), False))
|
||||||
else:
|
else:
|
||||||
addressGeneratorQueue.put(
|
addressGeneratorQueue.put(
|
||||||
('joinChan', addBMIfNotPresent(address),
|
('joinChan', addBMIfNotPresent(address),
|
||||||
"{} {}".format(str_chan, passPhrase), passPhrase, False))
|
"{} {}".format(str_chan, passPhrase), passPhrase.encode("utf-8", "replace"), False))
|
||||||
|
|
||||||
if self.buttonBox.button(QtGui.QDialogButtonBox.Ok).hasFocus():
|
if self.buttonBox.button(QtGui.QDialogButtonBox.Ok).hasFocus():
|
||||||
return (self.returnValid(), pos)
|
return (self.returnValid(), s, pos)
|
||||||
return (QtGui.QValidator.Intermediate, pos)
|
return (QtGui.QValidator.Intermediate, s, pos)
|
||||||
|
|
||||||
def checkData(self):
|
def checkData(self):
|
||||||
"""Validator Qt signal interface"""
|
"""Validator Qt signal interface"""
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
|
|
||||||
from PyQt4 import QtCore
|
from PyQt4 import QtCore
|
||||||
|
|
||||||
qt_resource_data = "\
|
qt_resource_data = b"\
|
||||||
\x00\x00\x03\x66\
|
\x00\x00\x03\x66\
|
||||||
\x89\
|
\x89\
|
||||||
\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
|
\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
|
||||||
|
@ -1534,7 +1534,7 @@ qt_resource_data = "\
|
||||||
\x82\
|
\x82\
|
||||||
"
|
"
|
||||||
|
|
||||||
qt_resource_name = "\
|
qt_resource_name = b"\
|
||||||
\x00\x09\
|
\x00\x09\
|
||||||
\x0c\x78\x54\x88\
|
\x0c\x78\x54\x88\
|
||||||
\x00\x6e\
|
\x00\x6e\
|
||||||
|
@ -1639,7 +1639,7 @@ qt_resource_name = "\
|
||||||
\x00\x70\x00\x6e\x00\x67\
|
\x00\x70\x00\x6e\x00\x67\
|
||||||
"
|
"
|
||||||
|
|
||||||
qt_resource_struct = "\
|
qt_resource_struct = b"\
|
||||||
\x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x01\
|
\x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x01\
|
||||||
\x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x02\
|
\x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x02\
|
||||||
\x00\x00\x00\x18\x00\x02\x00\x00\x00\x15\x00\x00\x00\x03\
|
\x00\x00\x00\x18\x00\x02\x00\x00\x00\x15\x00\x00\x00\x03\
|
||||||
|
|
|
@ -9,12 +9,12 @@
|
||||||
|
|
||||||
from PyQt4 import QtCore, QtGui
|
from PyQt4 import QtCore, QtGui
|
||||||
from bmconfigparser import config
|
from bmconfigparser import config
|
||||||
from foldertree import AddressBookCompleter
|
from .foldertree import AddressBookCompleter
|
||||||
from messageview import MessageView
|
from .messageview import MessageView
|
||||||
from messagecompose import MessageCompose
|
from .messagecompose import MessageCompose
|
||||||
import settingsmixin
|
from bitmessageqt import settingsmixin
|
||||||
from networkstatus import NetworkStatus
|
from .networkstatus import NetworkStatus
|
||||||
from blacklist import Blacklist
|
from .blacklist import Blacklist
|
||||||
|
|
||||||
try:
|
try:
|
||||||
_fromUtf8 = QtCore.QString.fromUtf8
|
_fromUtf8 = QtCore.QString.fromUtf8
|
||||||
|
|
|
@ -1,15 +1,17 @@
|
||||||
|
from unqstr import ustr, unic
|
||||||
from PyQt4 import QtCore, QtGui
|
from PyQt4 import QtCore, QtGui
|
||||||
|
from dbcompat import dbstr
|
||||||
|
|
||||||
import widgets
|
from bitmessageqt import widgets
|
||||||
from addresses import addBMIfNotPresent
|
from addresses import addBMIfNotPresent
|
||||||
from bmconfigparser import config
|
from bmconfigparser import config
|
||||||
from dialogs import AddAddressDialog
|
from .dialogs import AddAddressDialog
|
||||||
from helper_sql import sqlExecute, sqlQuery
|
from helper_sql import sqlExecute, sqlQuery
|
||||||
from queues import UISignalQueue
|
from queues import UISignalQueue
|
||||||
from retranslateui import RetranslateMixin
|
from .retranslateui import RetranslateMixin
|
||||||
from tr import _translate
|
from tr import _translate
|
||||||
from uisignaler import UISignaler
|
from .uisignaler import UISignaler
|
||||||
from utils import avatarize
|
from .utils import avatarize
|
||||||
|
|
||||||
|
|
||||||
class Blacklist(QtGui.QWidget, RetranslateMixin):
|
class Blacklist(QtGui.QWidget, RetranslateMixin):
|
||||||
|
@ -59,12 +61,12 @@ class Blacklist(QtGui.QWidget, RetranslateMixin):
|
||||||
if self.NewBlacklistDialogInstance.exec_():
|
if self.NewBlacklistDialogInstance.exec_():
|
||||||
if self.NewBlacklistDialogInstance.labelAddressCheck.text() == \
|
if self.NewBlacklistDialogInstance.labelAddressCheck.text() == \
|
||||||
_translate("MainWindow", "Address is valid."):
|
_translate("MainWindow", "Address is valid."):
|
||||||
address = addBMIfNotPresent(str(
|
address = addBMIfNotPresent(ustr(
|
||||||
self.NewBlacklistDialogInstance.lineEditAddress.text()))
|
self.NewBlacklistDialogInstance.lineEditAddress.text()))
|
||||||
# First we must check to see if the address is already in the
|
# First we must check to see if the address is already in the
|
||||||
# address book. The user cannot add it again or else it will
|
# address book. The user cannot add it again or else it will
|
||||||
# cause problems when updating and deleting the entry.
|
# cause problems when updating and deleting the entry.
|
||||||
t = (address,)
|
t = (dbstr(address),)
|
||||||
if config.get('bitmessagesettings', 'blackwhitelist') == 'black':
|
if config.get('bitmessagesettings', 'blackwhitelist') == 'black':
|
||||||
sql = '''select * from blacklist where address=?'''
|
sql = '''select * from blacklist where address=?'''
|
||||||
else:
|
else:
|
||||||
|
@ -73,8 +75,8 @@ class Blacklist(QtGui.QWidget, RetranslateMixin):
|
||||||
if queryreturn == []:
|
if queryreturn == []:
|
||||||
self.tableWidgetBlacklist.setSortingEnabled(False)
|
self.tableWidgetBlacklist.setSortingEnabled(False)
|
||||||
self.tableWidgetBlacklist.insertRow(0)
|
self.tableWidgetBlacklist.insertRow(0)
|
||||||
newItem = QtGui.QTableWidgetItem(unicode(
|
newItem = QtGui.QTableWidgetItem(unic(ustr(
|
||||||
self.NewBlacklistDialogInstance.lineEditLabel.text().toUtf8(), 'utf-8'))
|
self.NewBlacklistDialogInstance.lineEditLabel.text())))
|
||||||
newItem.setIcon(avatarize(address))
|
newItem.setIcon(avatarize(address))
|
||||||
self.tableWidgetBlacklist.setItem(0, 0, newItem)
|
self.tableWidgetBlacklist.setItem(0, 0, newItem)
|
||||||
newItem = QtGui.QTableWidgetItem(address)
|
newItem = QtGui.QTableWidgetItem(address)
|
||||||
|
@ -82,7 +84,7 @@ class Blacklist(QtGui.QWidget, RetranslateMixin):
|
||||||
QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled)
|
QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled)
|
||||||
self.tableWidgetBlacklist.setItem(0, 1, newItem)
|
self.tableWidgetBlacklist.setItem(0, 1, newItem)
|
||||||
self.tableWidgetBlacklist.setSortingEnabled(True)
|
self.tableWidgetBlacklist.setSortingEnabled(True)
|
||||||
t = (str(self.NewBlacklistDialogInstance.lineEditLabel.text().toUtf8()), address, True)
|
t = (dbstr(self.NewBlacklistDialogInstance.lineEditLabel.text()), dbstr(address), True)
|
||||||
if config.get('bitmessagesettings', 'blackwhitelist') == 'black':
|
if config.get('bitmessagesettings', 'blackwhitelist') == 'black':
|
||||||
sql = '''INSERT INTO blacklist VALUES (?,?,?)'''
|
sql = '''INSERT INTO blacklist VALUES (?,?,?)'''
|
||||||
else:
|
else:
|
||||||
|
@ -111,10 +113,10 @@ class Blacklist(QtGui.QWidget, RetranslateMixin):
|
||||||
if isinstance(addressitem, QtGui.QTableWidgetItem):
|
if isinstance(addressitem, QtGui.QTableWidgetItem):
|
||||||
if self.radioButtonBlacklist.isChecked():
|
if self.radioButtonBlacklist.isChecked():
|
||||||
sqlExecute('''UPDATE blacklist SET label=? WHERE address=?''',
|
sqlExecute('''UPDATE blacklist SET label=? WHERE address=?''',
|
||||||
str(item.text()), str(addressitem.text()))
|
dbstr(item.text()), dbstr(addressitem.text()))
|
||||||
else:
|
else:
|
||||||
sqlExecute('''UPDATE whitelist SET label=? WHERE address=?''',
|
sqlExecute('''UPDATE whitelist SET label=? WHERE address=?''',
|
||||||
str(item.text()), str(addressitem.text()))
|
dbstr(item.text()), dbstr(addressitem.text()))
|
||||||
|
|
||||||
def init_blacklist_popup_menu(self, connectSignal=True):
|
def init_blacklist_popup_menu(self, connectSignal=True):
|
||||||
# Popup menu for the Blacklist page
|
# Popup menu for the Blacklist page
|
||||||
|
@ -171,8 +173,10 @@ class Blacklist(QtGui.QWidget, RetranslateMixin):
|
||||||
self.tableWidgetBlacklist.setSortingEnabled(False)
|
self.tableWidgetBlacklist.setSortingEnabled(False)
|
||||||
for row in queryreturn:
|
for row in queryreturn:
|
||||||
label, address, enabled = row
|
label, address, enabled = row
|
||||||
|
label = label.decode("utf-8", "replace")
|
||||||
|
address = address.decode("utf-8", "replace")
|
||||||
self.tableWidgetBlacklist.insertRow(0)
|
self.tableWidgetBlacklist.insertRow(0)
|
||||||
newItem = QtGui.QTableWidgetItem(unicode(label, 'utf-8'))
|
newItem = QtGui.QTableWidgetItem(unic(ustr(label)))
|
||||||
if not enabled:
|
if not enabled:
|
||||||
newItem.setTextColor(QtGui.QColor(128, 128, 128))
|
newItem.setTextColor(QtGui.QColor(128, 128, 128))
|
||||||
newItem.setIcon(avatarize(address))
|
newItem.setIcon(avatarize(address))
|
||||||
|
@ -191,18 +195,18 @@ class Blacklist(QtGui.QWidget, RetranslateMixin):
|
||||||
|
|
||||||
def on_action_BlacklistDelete(self):
|
def on_action_BlacklistDelete(self):
|
||||||
currentRow = self.tableWidgetBlacklist.currentRow()
|
currentRow = self.tableWidgetBlacklist.currentRow()
|
||||||
labelAtCurrentRow = self.tableWidgetBlacklist.item(
|
labelAtCurrentRow = ustr(self.tableWidgetBlacklist.item(
|
||||||
currentRow, 0).text().toUtf8()
|
currentRow, 0).text())
|
||||||
addressAtCurrentRow = self.tableWidgetBlacklist.item(
|
addressAtCurrentRow = self.tableWidgetBlacklist.item(
|
||||||
currentRow, 1).text()
|
currentRow, 1).text()
|
||||||
if config.get('bitmessagesettings', 'blackwhitelist') == 'black':
|
if config.get('bitmessagesettings', 'blackwhitelist') == 'black':
|
||||||
sqlExecute(
|
sqlExecute(
|
||||||
'''DELETE FROM blacklist WHERE label=? AND address=?''',
|
'''DELETE FROM blacklist WHERE label=? AND address=?''',
|
||||||
str(labelAtCurrentRow), str(addressAtCurrentRow))
|
dbstr(labelAtCurrentRow), dbstr(addressAtCurrentRow))
|
||||||
else:
|
else:
|
||||||
sqlExecute(
|
sqlExecute(
|
||||||
'''DELETE FROM whitelist WHERE label=? AND address=?''',
|
'''DELETE FROM whitelist WHERE label=? AND address=?''',
|
||||||
str(labelAtCurrentRow), str(addressAtCurrentRow))
|
dbstr(labelAtCurrentRow), dbstr(addressAtCurrentRow))
|
||||||
self.tableWidgetBlacklist.removeRow(currentRow)
|
self.tableWidgetBlacklist.removeRow(currentRow)
|
||||||
|
|
||||||
def on_action_BlacklistClipboard(self):
|
def on_action_BlacklistClipboard(self):
|
||||||
|
@ -210,7 +214,7 @@ class Blacklist(QtGui.QWidget, RetranslateMixin):
|
||||||
addressAtCurrentRow = self.tableWidgetBlacklist.item(
|
addressAtCurrentRow = self.tableWidgetBlacklist.item(
|
||||||
currentRow, 1).text()
|
currentRow, 1).text()
|
||||||
clipboard = QtGui.QApplication.clipboard()
|
clipboard = QtGui.QApplication.clipboard()
|
||||||
clipboard.setText(str(addressAtCurrentRow))
|
clipboard.setText(ustr(addressAtCurrentRow))
|
||||||
|
|
||||||
def on_context_menuBlacklist(self, point):
|
def on_context_menuBlacklist(self, point):
|
||||||
self.popMenuBlacklist.exec_(
|
self.popMenuBlacklist.exec_(
|
||||||
|
@ -227,11 +231,11 @@ class Blacklist(QtGui.QWidget, RetranslateMixin):
|
||||||
if config.get('bitmessagesettings', 'blackwhitelist') == 'black':
|
if config.get('bitmessagesettings', 'blackwhitelist') == 'black':
|
||||||
sqlExecute(
|
sqlExecute(
|
||||||
'''UPDATE blacklist SET enabled=1 WHERE address=?''',
|
'''UPDATE blacklist SET enabled=1 WHERE address=?''',
|
||||||
str(addressAtCurrentRow))
|
dbstr(addressAtCurrentRow))
|
||||||
else:
|
else:
|
||||||
sqlExecute(
|
sqlExecute(
|
||||||
'''UPDATE whitelist SET enabled=1 WHERE address=?''',
|
'''UPDATE whitelist SET enabled=1 WHERE address=?''',
|
||||||
str(addressAtCurrentRow))
|
dbstr(addressAtCurrentRow))
|
||||||
|
|
||||||
def on_action_BlacklistDisable(self):
|
def on_action_BlacklistDisable(self):
|
||||||
currentRow = self.tableWidgetBlacklist.currentRow()
|
currentRow = self.tableWidgetBlacklist.currentRow()
|
||||||
|
@ -243,10 +247,10 @@ class Blacklist(QtGui.QWidget, RetranslateMixin):
|
||||||
currentRow, 1).setTextColor(QtGui.QColor(128, 128, 128))
|
currentRow, 1).setTextColor(QtGui.QColor(128, 128, 128))
|
||||||
if config.get('bitmessagesettings', 'blackwhitelist') == 'black':
|
if config.get('bitmessagesettings', 'blackwhitelist') == 'black':
|
||||||
sqlExecute(
|
sqlExecute(
|
||||||
'''UPDATE blacklist SET enabled=0 WHERE address=?''', str(addressAtCurrentRow))
|
'''UPDATE blacklist SET enabled=0 WHERE address=?''', dbstr(addressAtCurrentRow))
|
||||||
else:
|
else:
|
||||||
sqlExecute(
|
sqlExecute(
|
||||||
'''UPDATE whitelist SET enabled=0 WHERE address=?''', str(addressAtCurrentRow))
|
'''UPDATE whitelist SET enabled=0 WHERE address=?''', dbstr(addressAtCurrentRow))
|
||||||
|
|
||||||
def on_action_BlacklistSetAvatar(self):
|
def on_action_BlacklistSetAvatar(self):
|
||||||
self.window().on_action_SetAvatar(self.tableWidgetBlacklist)
|
self.window().on_action_SetAvatar(self.tableWidgetBlacklist)
|
||||||
|
|
|
@ -2,17 +2,18 @@
|
||||||
Custom dialog classes
|
Custom dialog classes
|
||||||
"""
|
"""
|
||||||
# pylint: disable=too-few-public-methods
|
# pylint: disable=too-few-public-methods
|
||||||
|
from unqstr import ustr
|
||||||
from PyQt4 import QtGui
|
from PyQt4 import QtGui
|
||||||
|
|
||||||
import paths
|
import paths
|
||||||
import widgets
|
from bitmessageqt import widgets
|
||||||
from address_dialogs import (
|
from .address_dialogs import (
|
||||||
AddAddressDialog, EmailGatewayDialog, NewAddressDialog,
|
AddAddressDialog, EmailGatewayDialog, NewAddressDialog,
|
||||||
NewSubscriptionDialog, RegenerateAddressesDialog,
|
NewSubscriptionDialog, RegenerateAddressesDialog,
|
||||||
SpecialAddressBehaviorDialog
|
SpecialAddressBehaviorDialog
|
||||||
)
|
)
|
||||||
from newchandialog import NewChanDialog
|
from .newchandialog import NewChanDialog
|
||||||
from settings import SettingsDialog
|
from .settings import SettingsDialog
|
||||||
from tr import _translate
|
from tr import _translate
|
||||||
from version import softwareVersion
|
from version import softwareVersion
|
||||||
|
|
||||||
|
@ -36,7 +37,7 @@ class AboutDialog(QtGui.QDialog):
|
||||||
if commit:
|
if commit:
|
||||||
version += '-' + commit[:7]
|
version += '-' + commit[:7]
|
||||||
self.labelVersion.setText(
|
self.labelVersion.setText(
|
||||||
self.labelVersion.text().replace(
|
ustr(self.labelVersion.text()).replace(
|
||||||
':version:', version
|
':version:', version
|
||||||
).replace(':branch:', commit or 'v%s' % version)
|
).replace(':branch:', commit or 'v%s' % version)
|
||||||
)
|
)
|
||||||
|
@ -44,8 +45,8 @@ class AboutDialog(QtGui.QDialog):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.label_2.setText(
|
self.label_2.setText(
|
||||||
self.label_2.text().replace(
|
ustr(self.label_2.text()).replace(
|
||||||
'2022', str(last_commit.get('time').year)
|
'2022', ustr(last_commit.get('time').year)
|
||||||
))
|
))
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
pass
|
pass
|
||||||
|
@ -64,8 +65,8 @@ class IconGlossaryDialog(QtGui.QDialog):
|
||||||
|
|
||||||
self.labelPortNumber.setText(_translate(
|
self.labelPortNumber.setText(_translate(
|
||||||
"iconGlossaryDialog",
|
"iconGlossaryDialog",
|
||||||
"You are using TCP port %1. (This can be changed in the settings)."
|
"You are using TCP port {0}. (This can be changed in the settings)."
|
||||||
).arg(config.getint('bitmessagesettings', 'port')))
|
).format(config.getint('bitmessagesettings', 'port')))
|
||||||
self.setFixedSize(QtGui.QWidget.sizeHint(self))
|
self.setFixedSize(QtGui.QWidget.sizeHint(self))
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -4,15 +4,20 @@ Folder tree and messagelist widgets definitions.
|
||||||
# pylint: disable=too-many-arguments,bad-super-call
|
# pylint: disable=too-many-arguments,bad-super-call
|
||||||
# pylint: disable=attribute-defined-outside-init
|
# pylint: disable=attribute-defined-outside-init
|
||||||
|
|
||||||
from cgi import escape
|
try:
|
||||||
|
from cgi import escape
|
||||||
|
except ImportError:
|
||||||
|
from html import escape
|
||||||
|
|
||||||
|
from unqstr import ustr, unic
|
||||||
from PyQt4 import QtCore, QtGui
|
from PyQt4 import QtCore, QtGui
|
||||||
|
from dbcompat import dbstr
|
||||||
|
|
||||||
from bmconfigparser import config
|
from bmconfigparser import config
|
||||||
from helper_sql import sqlExecute, sqlQuery
|
from helper_sql import sqlExecute, sqlQuery
|
||||||
from settingsmixin import SettingsMixin
|
from .settingsmixin import SettingsMixin
|
||||||
from tr import _translate
|
from tr import _translate
|
||||||
from utils import avatarize
|
from .utils import avatarize
|
||||||
|
|
||||||
# for pylupdate
|
# for pylupdate
|
||||||
_translate("MainWindow", "inbox")
|
_translate("MainWindow", "inbox")
|
||||||
|
@ -62,7 +67,7 @@ class AccountMixin(object):
|
||||||
|
|
||||||
def accountString(self):
|
def accountString(self):
|
||||||
"""Account string suitable for use in To: field: label <address>"""
|
"""Account string suitable for use in To: field: label <address>"""
|
||||||
label = self._getLabel()
|
label = ustr(self._getLabel())
|
||||||
return (
|
return (
|
||||||
self.address if label == self.address
|
self.address if label == self.address
|
||||||
else '%s <%s>' % (label, self.address)
|
else '%s <%s>' % (label, self.address)
|
||||||
|
@ -73,7 +78,7 @@ class AccountMixin(object):
|
||||||
if address is None:
|
if address is None:
|
||||||
self.address = None
|
self.address = None
|
||||||
else:
|
else:
|
||||||
self.address = str(address)
|
self.address = ustr(address)
|
||||||
|
|
||||||
def setUnreadCount(self, cnt):
|
def setUnreadCount(self, cnt):
|
||||||
"""Set number of unread messages"""
|
"""Set number of unread messages"""
|
||||||
|
@ -111,7 +116,7 @@ class AccountMixin(object):
|
||||||
elif config.safeGetBoolean(self.address, 'mailinglist'):
|
elif config.safeGetBoolean(self.address, 'mailinglist'):
|
||||||
self.type = self.MAILINGLIST
|
self.type = self.MAILINGLIST
|
||||||
elif sqlQuery(
|
elif sqlQuery(
|
||||||
'''select label from subscriptions where address=?''', self.address):
|
'''select label from subscriptions where address=?''', dbstr(self.address)):
|
||||||
self.type = AccountMixin.SUBSCRIPTION
|
self.type = AccountMixin.SUBSCRIPTION
|
||||||
else:
|
else:
|
||||||
self.type = self.NORMAL
|
self.type = self.NORMAL
|
||||||
|
@ -124,24 +129,23 @@ class AccountMixin(object):
|
||||||
AccountMixin.NORMAL,
|
AccountMixin.NORMAL,
|
||||||
AccountMixin.CHAN, AccountMixin.MAILINGLIST):
|
AccountMixin.CHAN, AccountMixin.MAILINGLIST):
|
||||||
try:
|
try:
|
||||||
retval = unicode(
|
retval = unic(ustr(
|
||||||
config.get(self.address, 'label'), 'utf-8')
|
config.get(self.address, 'label')))
|
||||||
except Exception:
|
except Exception:
|
||||||
queryreturn = sqlQuery(
|
queryreturn = sqlQuery(
|
||||||
'''select label from addressbook where address=?''', self.address)
|
'''select label from addressbook where address=?''', dbstr(self.address))
|
||||||
elif self.type == AccountMixin.SUBSCRIPTION:
|
elif self.type == AccountMixin.SUBSCRIPTION:
|
||||||
queryreturn = sqlQuery(
|
queryreturn = sqlQuery(
|
||||||
'''select label from subscriptions where address=?''', self.address)
|
'''select label from subscriptions where address=?''', dbstr(self.address))
|
||||||
if queryreturn is not None:
|
if queryreturn is not None:
|
||||||
if queryreturn != []:
|
if queryreturn != []:
|
||||||
for row in queryreturn:
|
for row in queryreturn:
|
||||||
retval, = row
|
retval, = row
|
||||||
retval = unicode(retval, 'utf-8')
|
retval = unic(ustr(retval))
|
||||||
elif self.address is None or self.type == AccountMixin.ALL:
|
elif self.address is None or self.type == AccountMixin.ALL:
|
||||||
return unicode(
|
return unic(_translate("MainWindow", "All accounts"))
|
||||||
str(_translate("MainWindow", "All accounts")), 'utf-8')
|
|
||||||
|
|
||||||
return retval or unicode(self.address, 'utf-8')
|
return retval or unic(self.address)
|
||||||
|
|
||||||
|
|
||||||
class BMTreeWidgetItem(QtGui.QTreeWidgetItem, AccountMixin):
|
class BMTreeWidgetItem(QtGui.QTreeWidgetItem, AccountMixin):
|
||||||
|
@ -154,7 +158,7 @@ class BMTreeWidgetItem(QtGui.QTreeWidgetItem, AccountMixin):
|
||||||
self._setup(parent, pos)
|
self._setup(parent, pos)
|
||||||
|
|
||||||
def _getAddressBracket(self, unreadCount=False):
|
def _getAddressBracket(self, unreadCount=False):
|
||||||
return " (" + str(self.unreadCount) + ")" if unreadCount else ""
|
return " (" + ustr(self.unreadCount) + ")" if unreadCount else ""
|
||||||
|
|
||||||
def data(self, column, role):
|
def data(self, column, role):
|
||||||
"""Override internal QT method for returning object data"""
|
"""Override internal QT method for returning object data"""
|
||||||
|
@ -191,7 +195,7 @@ class Ui_FolderWidget(BMTreeWidgetItem):
|
||||||
|
|
||||||
def setFolderName(self, fname):
|
def setFolderName(self, fname):
|
||||||
"""Set folder name (for QT UI)"""
|
"""Set folder name (for QT UI)"""
|
||||||
self.folderName = str(fname)
|
self.folderName = ustr(fname)
|
||||||
|
|
||||||
def data(self, column, role):
|
def data(self, column, role):
|
||||||
"""Override internal QT method for returning object data"""
|
"""Override internal QT method for returning object data"""
|
||||||
|
@ -232,15 +236,14 @@ class Ui_AddressWidget(BMTreeWidgetItem, SettingsMixin):
|
||||||
|
|
||||||
def _getLabel(self):
|
def _getLabel(self):
|
||||||
if self.address is None:
|
if self.address is None:
|
||||||
return unicode(_translate(
|
return unic(_translate(
|
||||||
"MainWindow", "All accounts").toUtf8(), 'utf-8', 'ignore')
|
"MainWindow", "All accounts"))
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
return unicode(
|
return unic(ustr(
|
||||||
config.get(self.address, 'label'),
|
config.get(self.address, 'label')))
|
||||||
'utf-8', 'ignore')
|
|
||||||
except:
|
except:
|
||||||
return unicode(self.address, 'utf-8')
|
return unic(self.address)
|
||||||
|
|
||||||
def _getAddressBracket(self, unreadCount=False):
|
def _getAddressBracket(self, unreadCount=False):
|
||||||
ret = "" if self.isExpanded() \
|
ret = "" if self.isExpanded() \
|
||||||
|
@ -264,8 +267,8 @@ class Ui_AddressWidget(BMTreeWidgetItem, SettingsMixin):
|
||||||
if role == QtCore.Qt.EditRole \
|
if role == QtCore.Qt.EditRole \
|
||||||
and self.type != AccountMixin.SUBSCRIPTION:
|
and self.type != AccountMixin.SUBSCRIPTION:
|
||||||
config.set(
|
config.set(
|
||||||
str(self.address), 'label',
|
self.address, 'label',
|
||||||
str(value.toString().toUtf8())
|
ustr(value)
|
||||||
if isinstance(value, QtCore.QVariant)
|
if isinstance(value, QtCore.QVariant)
|
||||||
else value.encode('utf-8')
|
else value.encode('utf-8')
|
||||||
)
|
)
|
||||||
|
@ -307,12 +310,12 @@ class Ui_SubscriptionWidget(Ui_AddressWidget):
|
||||||
|
|
||||||
def _getLabel(self):
|
def _getLabel(self):
|
||||||
queryreturn = sqlQuery(
|
queryreturn = sqlQuery(
|
||||||
'''select label from subscriptions where address=?''', self.address)
|
'''select label from subscriptions where address=?''', dbstr(self.address))
|
||||||
if queryreturn != []:
|
if queryreturn != []:
|
||||||
for row in queryreturn:
|
for row in queryreturn:
|
||||||
retval, = row
|
retval, = row
|
||||||
return unicode(retval, 'utf-8', 'ignore')
|
return unic(ustr(retval))
|
||||||
return unicode(self.address, 'utf-8')
|
return unic(self.address)
|
||||||
|
|
||||||
def setType(self):
|
def setType(self):
|
||||||
"""Set account type"""
|
"""Set account type"""
|
||||||
|
@ -323,13 +326,13 @@ class Ui_SubscriptionWidget(Ui_AddressWidget):
|
||||||
"""Save subscription label to database"""
|
"""Save subscription label to database"""
|
||||||
if role == QtCore.Qt.EditRole:
|
if role == QtCore.Qt.EditRole:
|
||||||
if isinstance(value, QtCore.QVariant):
|
if isinstance(value, QtCore.QVariant):
|
||||||
label = str(
|
label = ustr(
|
||||||
value.toString().toUtf8()).decode('utf-8', 'ignore')
|
value)
|
||||||
else:
|
else:
|
||||||
label = unicode(value, 'utf-8', 'ignore')
|
label = unic(ustr(value))
|
||||||
sqlExecute(
|
sqlExecute(
|
||||||
'''UPDATE subscriptions SET label=? WHERE address=?''',
|
'''UPDATE subscriptions SET label=? WHERE address=?''',
|
||||||
label, self.address)
|
dbstr(label), dbstr(self.address))
|
||||||
return super(Ui_SubscriptionWidget, self).setData(column, role, value)
|
return super(Ui_SubscriptionWidget, self).setData(column, role, value)
|
||||||
|
|
||||||
|
|
||||||
|
@ -407,18 +410,18 @@ class MessageList_AddressWidget(BMAddressWidget):
|
||||||
AccountMixin.NORMAL,
|
AccountMixin.NORMAL,
|
||||||
AccountMixin.CHAN, AccountMixin.MAILINGLIST):
|
AccountMixin.CHAN, AccountMixin.MAILINGLIST):
|
||||||
try:
|
try:
|
||||||
newLabel = unicode(
|
newLabel = unic(ustr(
|
||||||
config.get(self.address, 'label'),
|
config.get(self.address, 'label')))
|
||||||
'utf-8', 'ignore')
|
|
||||||
except:
|
except:
|
||||||
queryreturn = sqlQuery(
|
queryreturn = sqlQuery(
|
||||||
'''select label from addressbook where address=?''', self.address)
|
'''select label from addressbook where address=?''', dbstr(self.address))
|
||||||
elif self.type == AccountMixin.SUBSCRIPTION:
|
elif self.type == AccountMixin.SUBSCRIPTION:
|
||||||
queryreturn = sqlQuery(
|
queryreturn = sqlQuery(
|
||||||
'''select label from subscriptions where address=?''', self.address)
|
'''select label from subscriptions where address=?''', dbstr(self.address))
|
||||||
if queryreturn:
|
if queryreturn:
|
||||||
for row in queryreturn:
|
for row in queryreturn:
|
||||||
newLabel = unicode(row[0], 'utf-8', 'ignore')
|
newLabel = row[0]
|
||||||
|
newLabel = unic(ustr(newLabel))
|
||||||
|
|
||||||
self.label = newLabel
|
self.label = newLabel
|
||||||
|
|
||||||
|
@ -454,9 +457,9 @@ class MessageList_SubjectWidget(BMTableWidgetItem):
|
||||||
def data(self, role):
|
def data(self, role):
|
||||||
"""Return object data (QT UI)"""
|
"""Return object data (QT UI)"""
|
||||||
if role == QtCore.Qt.UserRole:
|
if role == QtCore.Qt.UserRole:
|
||||||
return self.subject
|
return ustr(self.subject)
|
||||||
if role == QtCore.Qt.ToolTipRole:
|
if role == QtCore.Qt.ToolTipRole:
|
||||||
return escape(unicode(self.subject, 'utf-8'))
|
return escape(unic(ustr(self.subject)))
|
||||||
return super(MessageList_SubjectWidget, self).data(role)
|
return super(MessageList_SubjectWidget, self).data(role)
|
||||||
|
|
||||||
# label (or address) alphabetically, disabled at the end
|
# label (or address) alphabetically, disabled at the end
|
||||||
|
@ -476,9 +479,9 @@ class MessageList_TimeWidget(BMTableWidgetItem):
|
||||||
msgid is available by QtCore.Qt.UserRole
|
msgid is available by QtCore.Qt.UserRole
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, label=None, unread=False, timestamp=None, msgid=''):
|
def __init__(self, label=None, unread=False, timestamp=None, msgid=b''):
|
||||||
super(MessageList_TimeWidget, self).__init__(label, unread)
|
super(MessageList_TimeWidget, self).__init__(label, unread)
|
||||||
self.setData(QtCore.Qt.UserRole, QtCore.QByteArray(msgid))
|
self.setData(QtCore.Qt.UserRole, QtCore.QByteArray(bytes(msgid)))
|
||||||
self.setData(TimestampRole, int(timestamp))
|
self.setData(TimestampRole, int(timestamp))
|
||||||
|
|
||||||
def __lt__(self, other):
|
def __lt__(self, other):
|
||||||
|
@ -491,9 +494,9 @@ class MessageList_TimeWidget(BMTableWidgetItem):
|
||||||
"""
|
"""
|
||||||
data = super(MessageList_TimeWidget, self).data(role)
|
data = super(MessageList_TimeWidget, self).data(role)
|
||||||
if role == TimestampRole:
|
if role == TimestampRole:
|
||||||
return int(data.toPyObject())
|
return int(data)
|
||||||
if role == QtCore.Qt.UserRole:
|
if role == QtCore.Qt.UserRole:
|
||||||
return str(data.toPyObject())
|
return ustr(data)
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
|
||||||
|
@ -513,8 +516,8 @@ class Ui_AddressBookWidgetItem(BMAddressWidget):
|
||||||
def setData(self, role, value):
|
def setData(self, role, value):
|
||||||
"""Set data"""
|
"""Set data"""
|
||||||
if role == QtCore.Qt.EditRole:
|
if role == QtCore.Qt.EditRole:
|
||||||
self.label = str(
|
self.label = ustr(
|
||||||
value.toString().toUtf8()
|
value
|
||||||
if isinstance(value, QtCore.QVariant) else value
|
if isinstance(value, QtCore.QVariant) else value
|
||||||
)
|
)
|
||||||
if self.type in (
|
if self.type in (
|
||||||
|
@ -525,9 +528,9 @@ class Ui_AddressBookWidgetItem(BMAddressWidget):
|
||||||
config.set(self.address, 'label', self.label)
|
config.set(self.address, 'label', self.label)
|
||||||
config.save()
|
config.save()
|
||||||
except:
|
except:
|
||||||
sqlExecute('''UPDATE addressbook set label=? WHERE address=?''', self.label, self.address)
|
sqlExecute('''UPDATE addressbook set label=? WHERE address=?''', dbstr(self.label), dbstr(self.address))
|
||||||
elif self.type == AccountMixin.SUBSCRIPTION:
|
elif self.type == AccountMixin.SUBSCRIPTION:
|
||||||
sqlExecute('''UPDATE subscriptions set label=? WHERE address=?''', self.label, self.address)
|
sqlExecute('''UPDATE subscriptions set label=? WHERE address=?''', dbstr(self.label), dbstr(self.address))
|
||||||
else:
|
else:
|
||||||
pass
|
pass
|
||||||
return super(Ui_AddressBookWidgetItem, self).setData(role, value)
|
return super(Ui_AddressBookWidgetItem, self).setData(role, value)
|
||||||
|
@ -546,7 +549,7 @@ class Ui_AddressBookWidgetItem(BMAddressWidget):
|
||||||
class Ui_AddressBookWidgetItemLabel(Ui_AddressBookWidgetItem):
|
class Ui_AddressBookWidgetItemLabel(Ui_AddressBookWidgetItem):
|
||||||
"""Addressbook label item"""
|
"""Addressbook label item"""
|
||||||
def __init__(self, address, label, acc_type):
|
def __init__(self, address, label, acc_type):
|
||||||
self.address = address
|
self.address = ustr(address)
|
||||||
super(Ui_AddressBookWidgetItemLabel, self).__init__(label, acc_type)
|
super(Ui_AddressBookWidgetItemLabel, self).__init__(label, acc_type)
|
||||||
|
|
||||||
def data(self, role):
|
def data(self, role):
|
||||||
|
@ -558,7 +561,7 @@ class Ui_AddressBookWidgetItemLabel(Ui_AddressBookWidgetItem):
|
||||||
class Ui_AddressBookWidgetItemAddress(Ui_AddressBookWidgetItem):
|
class Ui_AddressBookWidgetItemAddress(Ui_AddressBookWidgetItem):
|
||||||
"""Addressbook address item"""
|
"""Addressbook address item"""
|
||||||
def __init__(self, address, label, acc_type):
|
def __init__(self, address, label, acc_type):
|
||||||
self.address = address
|
self.address = ustr(address)
|
||||||
super(Ui_AddressBookWidgetItemAddress, self).__init__(address, acc_type)
|
super(Ui_AddressBookWidgetItemAddress, self).__init__(address, acc_type)
|
||||||
|
|
||||||
def data(self, role):
|
def data(self, role):
|
||||||
|
@ -584,14 +587,14 @@ class AddressBookCompleter(QtGui.QCompleter):
|
||||||
|
|
||||||
def splitPath(self, path):
|
def splitPath(self, path):
|
||||||
"""Split on semicolon"""
|
"""Split on semicolon"""
|
||||||
text = unicode(path.toUtf8(), 'utf-8')
|
text = unic(ustr(path))
|
||||||
return [text[:self.widget().cursorPosition()].split(';')[-1].strip()]
|
return [text[:self.widget().cursorPosition()].split(';')[-1].strip()]
|
||||||
|
|
||||||
def pathFromIndex(self, index):
|
def pathFromIndex(self, index):
|
||||||
"""Perform autocompletion (reimplemented QCompleter method)"""
|
"""Perform autocompletion (reimplemented QCompleter method)"""
|
||||||
autoString = unicode(
|
autoString = unic(ustr(
|
||||||
index.data(QtCore.Qt.EditRole).toString().toUtf8(), 'utf-8')
|
index.data(QtCore.Qt.EditRole)))
|
||||||
text = unicode(self.widget().text().toUtf8(), 'utf-8')
|
text = unic(ustr(self.widget().text()))
|
||||||
|
|
||||||
# If cursor position was saved, restore it, else save it
|
# If cursor position was saved, restore it, else save it
|
||||||
if self.cursorPos != -1:
|
if self.cursorPos != -1:
|
||||||
|
|
|
@ -24,7 +24,7 @@ class MessageCompose(QtGui.QTextEdit):
|
||||||
self.zoomOut(1)
|
self.zoomOut(1)
|
||||||
zoom = self.currentFont().pointSize() * 100 / self.defaultFontPointSize
|
zoom = self.currentFont().pointSize() * 100 / self.defaultFontPointSize
|
||||||
QtGui.QApplication.activeWindow().statusBar().showMessage(
|
QtGui.QApplication.activeWindow().statusBar().showMessage(
|
||||||
QtGui.QApplication.translate("MainWindow", "Zoom level %1%").arg(
|
QtGui.QApplication.translate("MainWindow", "Zoom level {0}%").format(
|
||||||
str(zoom)
|
str(zoom)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
|
@ -5,9 +5,10 @@ zoom and URL click warning popup
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
from unqstr import ustr, unic
|
||||||
from PyQt4 import QtCore, QtGui
|
from PyQt4 import QtCore, QtGui
|
||||||
|
|
||||||
from safehtmlparser import SafeHTMLParser
|
from .safehtmlparser import SafeHTMLParser
|
||||||
from tr import _translate
|
from tr import _translate
|
||||||
|
|
||||||
|
|
||||||
|
@ -56,7 +57,7 @@ class MessageView(QtGui.QTextBrowser):
|
||||||
) == QtCore.Qt.ControlModifier and event.orientation() == QtCore.Qt.Vertical:
|
) == QtCore.Qt.ControlModifier and event.orientation() == QtCore.Qt.Vertical:
|
||||||
zoom = self.currentFont().pointSize() * 100 / self.defaultFontPointSize
|
zoom = self.currentFont().pointSize() * 100 / self.defaultFontPointSize
|
||||||
QtGui.QApplication.activeWindow().statusBar().showMessage(_translate(
|
QtGui.QApplication.activeWindow().statusBar().showMessage(_translate(
|
||||||
"MainWindow", "Zoom level %1%").arg(str(zoom)))
|
"MainWindow", "Zoom level {0}%").format(ustr(zoom)))
|
||||||
|
|
||||||
def setWrappingWidth(self, width=None):
|
def setWrappingWidth(self, width=None):
|
||||||
"""Set word-wrapping width"""
|
"""Set word-wrapping width"""
|
||||||
|
@ -90,8 +91,8 @@ class MessageView(QtGui.QTextBrowser):
|
||||||
"Follow external link"),
|
"Follow external link"),
|
||||||
QtGui.QApplication.translate(
|
QtGui.QApplication.translate(
|
||||||
"MessageView",
|
"MessageView",
|
||||||
"The link \"%1\" will open in a browser. It may be a security risk, it could de-anonymise you"
|
"The link \"{0}\" will open in a browser. It may be a security risk, it could de-anonymise you"
|
||||||
" or download malicious data. Are you sure?").arg(unicode(link.toString())),
|
" or download malicious data. Are you sure?").format(unic(ustr(link))),
|
||||||
QtGui.QMessageBox.Yes,
|
QtGui.QMessageBox.Yes,
|
||||||
QtGui.QMessageBox.No)
|
QtGui.QMessageBox.No)
|
||||||
if reply == QtGui.QMessageBox.Yes:
|
if reply == QtGui.QMessageBox.Yes:
|
||||||
|
@ -124,7 +125,7 @@ class MessageView(QtGui.QTextBrowser):
|
||||||
if pos > self.outpos:
|
if pos > self.outpos:
|
||||||
self.outpos = pos + 1
|
self.outpos = pos + 1
|
||||||
cursor.movePosition(QtGui.QTextCursor.End, QtGui.QTextCursor.MoveAnchor)
|
cursor.movePosition(QtGui.QTextCursor.End, QtGui.QTextCursor.MoveAnchor)
|
||||||
cursor.insertHtml(QtCore.QString(self.out[startpos:self.outpos]))
|
cursor.insertHtml(unic(self.out[startpos:self.outpos]))
|
||||||
self.verticalScrollBar().setValue(position)
|
self.verticalScrollBar().setValue(position)
|
||||||
self.rendering = False
|
self.rendering = False
|
||||||
|
|
||||||
|
@ -133,9 +134,9 @@ class MessageView(QtGui.QTextBrowser):
|
||||||
self.mode = MessageView.MODE_PLAIN
|
self.mode = MessageView.MODE_PLAIN
|
||||||
out = self.html.raw
|
out = self.html.raw
|
||||||
if self.html.has_html:
|
if self.html.has_html:
|
||||||
out = "<div align=\"center\" style=\"text-decoration: underline;\"><b>" + unicode(
|
out = "<div align=\"center\" style=\"text-decoration: underline;\"><b>" + unic(ustr(
|
||||||
QtGui.QApplication.translate(
|
QtGui.QApplication.translate(
|
||||||
"MessageView", "HTML detected, click here to display")) + "</b></div><br/>" + out
|
"MessageView", "HTML detected, click here to display")) + "</b></div><br/>" + out)
|
||||||
self.out = out
|
self.out = out
|
||||||
self.outpos = 0
|
self.outpos = 0
|
||||||
self.setHtml("")
|
self.setHtml("")
|
||||||
|
@ -145,8 +146,8 @@ class MessageView(QtGui.QTextBrowser):
|
||||||
"""Render message as HTML"""
|
"""Render message as HTML"""
|
||||||
self.mode = MessageView.MODE_HTML
|
self.mode = MessageView.MODE_HTML
|
||||||
out = self.html.sanitised
|
out = self.html.sanitised
|
||||||
out = "<div align=\"center\" style=\"text-decoration: underline;\"><b>" + unicode(
|
out = "<div align=\"center\" style=\"text-decoration: underline;\"><b>" + unic(ustr(
|
||||||
QtGui.QApplication.translate("MessageView", "Click here to disable HTML")) + "</b></div><br/>" + out
|
QtGui.QApplication.translate("MessageView", "Click here to disable HTML")) + "</b></div><br/>" + out)
|
||||||
self.out = out
|
self.out = out
|
||||||
self.outpos = 0
|
self.outpos = 0
|
||||||
self.setHtml("")
|
self.setHtml("")
|
||||||
|
|
|
@ -9,11 +9,11 @@ from PyQt4 import QtCore, QtGui
|
||||||
import l10n
|
import l10n
|
||||||
import network.stats
|
import network.stats
|
||||||
import state
|
import state
|
||||||
import widgets
|
from bitmessageqt import widgets
|
||||||
from network import connectionpool, knownnodes
|
from network import connectionpool, knownnodes
|
||||||
from retranslateui import RetranslateMixin
|
from .retranslateui import RetranslateMixin
|
||||||
from tr import _translate
|
from tr import _translate
|
||||||
from uisignaler import UISignaler
|
from .uisignaler import UISignaler
|
||||||
|
|
||||||
|
|
||||||
class NetworkStatus(QtGui.QWidget, RetranslateMixin):
|
class NetworkStatus(QtGui.QWidget, RetranslateMixin):
|
||||||
|
@ -134,12 +134,12 @@ class NetworkStatus(QtGui.QWidget, RetranslateMixin):
|
||||||
self.labelBytesRecvCount.setText(
|
self.labelBytesRecvCount.setText(
|
||||||
_translate(
|
_translate(
|
||||||
"networkstatus",
|
"networkstatus",
|
||||||
"Down: %1/s Total: %2").arg(
|
"Down: {0}/s Total: {1}").format(
|
||||||
self.formatByteRate(network.stats.downloadSpeed()),
|
self.formatByteRate(network.stats.downloadSpeed()),
|
||||||
self.formatBytes(network.stats.receivedBytes())))
|
self.formatBytes(network.stats.receivedBytes())))
|
||||||
self.labelBytesSentCount.setText(
|
self.labelBytesSentCount.setText(
|
||||||
_translate(
|
_translate(
|
||||||
"networkstatus", "Up: %1/s Total: %2").arg(
|
"networkstatus", "Up: {0}/s Total: {1}").format(
|
||||||
self.formatByteRate(network.stats.uploadSpeed()),
|
self.formatByteRate(network.stats.uploadSpeed()),
|
||||||
self.formatBytes(network.stats.sentBytes())))
|
self.formatBytes(network.stats.sentBytes())))
|
||||||
|
|
||||||
|
@ -204,9 +204,9 @@ class NetworkStatus(QtGui.QWidget, RetranslateMixin):
|
||||||
if not connectionpool.pool.inboundConnections:
|
if not connectionpool.pool.inboundConnections:
|
||||||
self.window().setStatusIcon('yellow')
|
self.window().setStatusIcon('yellow')
|
||||||
for i in range(self.tableWidgetConnectionCount.rowCount()):
|
for i in range(self.tableWidgetConnectionCount.rowCount()):
|
||||||
if self.tableWidgetConnectionCount.item(i, 0).data(QtCore.Qt.UserRole).toPyObject() != destination:
|
if self.tableWidgetConnectionCount.item(i, 0).data(QtCore.Qt.UserRole) != destination:
|
||||||
continue
|
continue
|
||||||
if self.tableWidgetConnectionCount.item(i, 1).data(QtCore.Qt.UserRole).toPyObject() == outbound:
|
if self.tableWidgetConnectionCount.item(i, 1).data(QtCore.Qt.UserRole) == outbound:
|
||||||
self.tableWidgetConnectionCount.removeRow(i)
|
self.tableWidgetConnectionCount.removeRow(i)
|
||||||
break
|
break
|
||||||
|
|
||||||
|
@ -214,7 +214,7 @@ class NetworkStatus(QtGui.QWidget, RetranslateMixin):
|
||||||
self.tableWidgetConnectionCount.setSortingEnabled(True)
|
self.tableWidgetConnectionCount.setSortingEnabled(True)
|
||||||
self.labelTotalConnections.setText(
|
self.labelTotalConnections.setText(
|
||||||
_translate(
|
_translate(
|
||||||
"networkstatus", "Total Connections: %1").arg(
|
"networkstatus", "Total Connections: {0}").format(
|
||||||
str(self.tableWidgetConnectionCount.rowCount())))
|
str(self.tableWidgetConnectionCount.rowCount())))
|
||||||
# FYI: The 'singlelistener' thread sets the icon color to green when it
|
# FYI: The 'singlelistener' thread sets the icon color to green when it
|
||||||
# receives an incoming connection, meaning that the user's firewall is
|
# receives an incoming connection, meaning that the user's firewall is
|
||||||
|
@ -227,7 +227,7 @@ class NetworkStatus(QtGui.QWidget, RetranslateMixin):
|
||||||
# timer driven
|
# timer driven
|
||||||
def runEveryTwoSeconds(self):
|
def runEveryTwoSeconds(self):
|
||||||
"""Updates counters, runs every 2 seconds if the timer is running"""
|
"""Updates counters, runs every 2 seconds if the timer is running"""
|
||||||
self.labelLookupsPerSecond.setText(_translate("networkstatus", "Inventory lookups per second: %1").arg(
|
self.labelLookupsPerSecond.setText(_translate("networkstatus", "Inventory lookups per second: {0}").format(
|
||||||
str(state.Inventory.numberOfInventoryLookupsPerformed / 2)))
|
str(state.Inventory.numberOfInventoryLookupsPerformed / 2)))
|
||||||
state.Inventory.numberOfInventoryLookupsPerformed = 0
|
state.Inventory.numberOfInventoryLookupsPerformed = 0
|
||||||
self.updateNumberOfBytes()
|
self.updateNumberOfBytes()
|
||||||
|
@ -238,11 +238,11 @@ class NetworkStatus(QtGui.QWidget, RetranslateMixin):
|
||||||
super(NetworkStatus, self).retranslateUi()
|
super(NetworkStatus, self).retranslateUi()
|
||||||
self.labelTotalConnections.setText(
|
self.labelTotalConnections.setText(
|
||||||
_translate(
|
_translate(
|
||||||
"networkstatus", "Total Connections: %1").arg(
|
"networkstatus", "Total Connections: {0}").format(
|
||||||
str(self.tableWidgetConnectionCount.rowCount())))
|
str(self.tableWidgetConnectionCount.rowCount())))
|
||||||
self.labelStartupTime.setText(_translate(
|
self.labelStartupTime.setText(_translate(
|
||||||
"networkstatus", "Since startup on %1"
|
"networkstatus", "Since startup on {0}"
|
||||||
).arg(l10n.formatTimestamp(self.startup)))
|
).format(l10n.formatTimestamp(self.startup)))
|
||||||
self.updateNumberOfMessagesProcessed()
|
self.updateNumberOfMessagesProcessed()
|
||||||
self.updateNumberOfBroadcastsProcessed()
|
self.updateNumberOfBroadcastsProcessed()
|
||||||
self.updateNumberOfPubkeysProcessed()
|
self.updateNumberOfPubkeysProcessed()
|
||||||
|
|
|
@ -4,15 +4,16 @@ src/bitmessageqt/newchandialog.py
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
from unqstr import ustr, unic
|
||||||
from PyQt4 import QtCore, QtGui
|
from PyQt4 import QtCore, QtGui
|
||||||
|
|
||||||
import widgets
|
from bitmessageqt import widgets
|
||||||
from addresses import addBMIfNotPresent
|
from addresses import addBMIfNotPresent
|
||||||
from addressvalidator import AddressValidator, PassPhraseValidator
|
from .addressvalidator import AddressValidator, PassPhraseValidator
|
||||||
from queues import (
|
from queues import (
|
||||||
addressGeneratorQueue, apiAddressGeneratorReturnQueue, UISignalQueue)
|
addressGeneratorQueue, apiAddressGeneratorReturnQueue, UISignalQueue)
|
||||||
from tr import _translate
|
from tr import _translate
|
||||||
from utils import str_chan
|
from .utils import str_chan
|
||||||
|
|
||||||
|
|
||||||
class NewChanDialog(QtGui.QDialog):
|
class NewChanDialog(QtGui.QDialog):
|
||||||
|
@ -52,21 +53,21 @@ class NewChanDialog(QtGui.QDialog):
|
||||||
self.timer.stop()
|
self.timer.stop()
|
||||||
self.hide()
|
self.hide()
|
||||||
apiAddressGeneratorReturnQueue.queue.clear()
|
apiAddressGeneratorReturnQueue.queue.clear()
|
||||||
if self.chanAddress.text().toUtf8() == "":
|
if ustr(self.chanAddress.text()) == "":
|
||||||
addressGeneratorQueue.put(
|
addressGeneratorQueue.put(
|
||||||
('createChan', 4, 1, str_chan + ' ' + str(self.chanPassPhrase.text().toUtf8()),
|
('createChan', 4, 1, str_chan + ' ' + ustr(self.chanPassPhrase.text()),
|
||||||
self.chanPassPhrase.text().toUtf8(),
|
ustr(self.chanPassPhrase.text()).encode("utf-8", "replace"),
|
||||||
True))
|
True))
|
||||||
else:
|
else:
|
||||||
addressGeneratorQueue.put(
|
addressGeneratorQueue.put(
|
||||||
('joinChan', addBMIfNotPresent(self.chanAddress.text().toUtf8()),
|
('joinChan', addBMIfNotPresent(ustr(self.chanAddress.text())),
|
||||||
str_chan + ' ' + str(self.chanPassPhrase.text().toUtf8()),
|
str_chan + ' ' + ustr(self.chanPassPhrase.text()),
|
||||||
self.chanPassPhrase.text().toUtf8(),
|
ustr(self.chanPassPhrase.text()).encode("utf-8", "replace"),
|
||||||
True))
|
True))
|
||||||
addressGeneratorReturnValue = apiAddressGeneratorReturnQueue.get(True)
|
addressGeneratorReturnValue = apiAddressGeneratorReturnQueue.get(True)
|
||||||
if addressGeneratorReturnValue and addressGeneratorReturnValue[0] != 'chan name does not match address':
|
if addressGeneratorReturnValue and addressGeneratorReturnValue[0] != 'chan name does not match address':
|
||||||
UISignalQueue.put(('updateStatusBar', _translate(
|
UISignalQueue.put(('updateStatusBar', _translate(
|
||||||
"newchandialog", "Successfully created / joined chan %1").arg(unicode(self.chanPassPhrase.text()))))
|
"newchandialog", "Successfully created / joined chan {0}").format(unic(ustr(self.chanPassPhrase.text())))))
|
||||||
self.parent.ui.tabWidget.setCurrentIndex(
|
self.parent.ui.tabWidget.setCurrentIndex(
|
||||||
self.parent.ui.tabWidget.indexOf(self.parent.ui.chans)
|
self.parent.ui.tabWidget.indexOf(self.parent.ui.chans)
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,20 +1,22 @@
|
||||||
from os import path
|
from os import path
|
||||||
|
from unqstr import ustr
|
||||||
|
import six
|
||||||
from PyQt4 import QtGui
|
from PyQt4 import QtGui
|
||||||
from debug import logger
|
from debug import logger
|
||||||
import widgets
|
from bitmessageqt import widgets
|
||||||
|
|
||||||
class RetranslateMixin(object):
|
class RetranslateMixin(object):
|
||||||
def retranslateUi(self):
|
def retranslateUi(self):
|
||||||
defaults = QtGui.QWidget()
|
defaults = QtGui.QWidget()
|
||||||
widgets.load(self.__class__.__name__.lower() + '.ui', defaults)
|
widgets.load(self.__class__.__name__.lower() + '.ui', defaults)
|
||||||
for attr, value in defaults.__dict__.iteritems():
|
for attr, value in six.iteritems(defaults.__dict__):
|
||||||
setTextMethod = getattr(value, "setText", None)
|
setTextMethod = getattr(value, "setText", None)
|
||||||
if callable(setTextMethod):
|
if callable(setTextMethod):
|
||||||
getattr(self, attr).setText(getattr(defaults, attr).text())
|
getattr(self, attr).setText(ustr(getattr(defaults, attr).text()))
|
||||||
elif isinstance(value, QtGui.QTableWidget):
|
elif isinstance(value, QtGui.QTableWidget):
|
||||||
for i in range (value.columnCount()):
|
for i in range (value.columnCount()):
|
||||||
getattr(self, attr).horizontalHeaderItem(i).setText(
|
getattr(self, attr).horizontalHeaderItem(i).setText(
|
||||||
getattr(defaults, attr).horizontalHeaderItem(i).text())
|
ustr(getattr(defaults, attr).horizontalHeaderItem(i).text()))
|
||||||
for i in range (value.rowCount()):
|
for i in range (value.rowCount()):
|
||||||
getattr(self, attr).verticalHeaderItem(i).setText(
|
getattr(self, attr).verticalHeaderItem(i).setText(
|
||||||
getattr(defaults, attr).verticalHeaderItem(i).text())
|
ustr(getattr(defaults, attr).verticalHeaderItem(i).text()))
|
||||||
|
|
|
@ -2,11 +2,11 @@
|
||||||
|
|
||||||
import inspect
|
import inspect
|
||||||
import re
|
import re
|
||||||
from HTMLParser import HTMLParser
|
from six.moves.html_parser import HTMLParser
|
||||||
|
|
||||||
from urllib import quote_plus
|
from six.moves.urllib.parse import quote_plus, urlparse
|
||||||
from urlparse import urlparse
|
|
||||||
|
|
||||||
|
from unqstr import ustr, unic
|
||||||
|
|
||||||
class SafeHTMLParser(HTMLParser):
|
class SafeHTMLParser(HTMLParser):
|
||||||
"""HTML parser with sanitisation"""
|
"""HTML parser with sanitisation"""
|
||||||
|
@ -124,9 +124,9 @@ class SafeHTMLParser(HTMLParser):
|
||||||
|
|
||||||
def feed(self, data):
|
def feed(self, data):
|
||||||
try:
|
try:
|
||||||
data = unicode(data, 'utf-8')
|
data = unic(ustr(data))
|
||||||
except UnicodeDecodeError:
|
except TypeError:
|
||||||
data = unicode(data, 'utf-8', errors='replace')
|
pass
|
||||||
HTMLParser.feed(self, data)
|
HTMLParser.feed(self, data)
|
||||||
tmp = SafeHTMLParser.replace_pre(data)
|
tmp = SafeHTMLParser.replace_pre(data)
|
||||||
tmp = self.uriregex1.sub(r'<a href="\1">\1</a>', tmp)
|
tmp = self.uriregex1.sub(r'<a href="\1">\1</a>', tmp)
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
"""
|
"""
|
||||||
This module setting file is for settings
|
This module setting file is for settings
|
||||||
"""
|
"""
|
||||||
import ConfigParser
|
from six.moves import configparser
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import tempfile
|
import tempfile
|
||||||
|
|
||||||
import six
|
import six
|
||||||
|
from unqstr import ustr
|
||||||
from PyQt4 import QtCore, QtGui
|
from PyQt4 import QtCore, QtGui
|
||||||
|
|
||||||
import debug
|
import debug
|
||||||
|
@ -16,7 +17,7 @@ import openclpow
|
||||||
import paths
|
import paths
|
||||||
import queues
|
import queues
|
||||||
import state
|
import state
|
||||||
import widgets
|
from bitmessageqt import widgets
|
||||||
from bmconfigparser import config as config_obj
|
from bmconfigparser import config as config_obj
|
||||||
from helper_sql import sqlExecute, sqlStoredProcedure
|
from helper_sql import sqlExecute, sqlStoredProcedure
|
||||||
from helper_startup import start_proxyconfig
|
from helper_startup import start_proxyconfig
|
||||||
|
@ -26,12 +27,18 @@ from network.asyncore_pollchoose import set_rates
|
||||||
from tr import _translate
|
from tr import _translate
|
||||||
|
|
||||||
|
|
||||||
|
try:
|
||||||
|
SafeConfigParser = configparser.SafeConfigParser
|
||||||
|
except AttributeError:
|
||||||
|
# alpine linux, python3.12
|
||||||
|
SafeConfigParser = configparser.ConfigParser
|
||||||
|
|
||||||
def getSOCKSProxyType(config):
|
def getSOCKSProxyType(config):
|
||||||
"""Get user socksproxytype setting from *config*"""
|
"""Get user socksproxytype setting from *config*"""
|
||||||
try:
|
try:
|
||||||
result = ConfigParser.SafeConfigParser.get(
|
result = SafeConfigParser.get(
|
||||||
config, 'bitmessagesettings', 'socksproxytype')
|
config, 'bitmessagesettings', 'socksproxytype')
|
||||||
except (ConfigParser.NoSectionError, ConfigParser.NoOptionError):
|
except (configparser.NoSectionError, configparser.NoOptionError):
|
||||||
return None
|
return None
|
||||||
else:
|
else:
|
||||||
if result.lower() in ('', 'none', 'false'):
|
if result.lower() in ('', 'none', 'false'):
|
||||||
|
@ -187,7 +194,7 @@ class SettingsDialog(QtGui.QDialog):
|
||||||
else:
|
else:
|
||||||
if self.checkBoxOnionOnly.isChecked():
|
if self.checkBoxOnionOnly.isChecked():
|
||||||
self.checkBoxOnionOnly.setText(
|
self.checkBoxOnionOnly.setText(
|
||||||
self.checkBoxOnionOnly.text() + ", " + _translate(
|
ustr(self.checkBoxOnionOnly.text()) + ", " + _translate(
|
||||||
"MainWindow", "may cause connection problems!"))
|
"MainWindow", "may cause connection problems!"))
|
||||||
self.checkBoxOnionOnly.setStyleSheet(
|
self.checkBoxOnionOnly.setStyleSheet(
|
||||||
"QCheckBox { color : red; }")
|
"QCheckBox { color : red; }")
|
||||||
|
@ -324,10 +331,10 @@ class SettingsDialog(QtGui.QDialog):
|
||||||
_translate("MainWindow", "Testing..."))
|
_translate("MainWindow", "Testing..."))
|
||||||
nc = namecoin.namecoinConnection({
|
nc = namecoin.namecoinConnection({
|
||||||
'type': self.getNamecoinType(),
|
'type': self.getNamecoinType(),
|
||||||
'host': str(self.lineEditNamecoinHost.text().toUtf8()),
|
'host': ustr(self.lineEditNamecoinHost.text()),
|
||||||
'port': str(self.lineEditNamecoinPort.text().toUtf8()),
|
'port': ustr(self.lineEditNamecoinPort.text()),
|
||||||
'user': str(self.lineEditNamecoinUser.text().toUtf8()),
|
'user': ustr(self.lineEditNamecoinUser.text()),
|
||||||
'password': str(self.lineEditNamecoinPassword.text().toUtf8())
|
'password': ustr(self.lineEditNamecoinPassword.text())
|
||||||
})
|
})
|
||||||
status, text = nc.test()
|
status, text = nc.test()
|
||||||
self.labelNamecoinTestResult.setText(text)
|
self.labelNamecoinTestResult.setText(text)
|
||||||
|
@ -387,7 +394,7 @@ class SettingsDialog(QtGui.QDialog):
|
||||||
))
|
))
|
||||||
|
|
||||||
lang = str(self.languageComboBox.itemData(
|
lang = str(self.languageComboBox.itemData(
|
||||||
self.languageComboBox.currentIndex()).toString())
|
self.languageComboBox.currentIndex()))
|
||||||
self.config.set('bitmessagesettings', 'userlocale', lang)
|
self.config.set('bitmessagesettings', 'userlocale', lang)
|
||||||
self.parent.change_translation()
|
self.parent.change_translation()
|
||||||
|
|
||||||
|
@ -486,13 +493,13 @@ class SettingsDialog(QtGui.QDialog):
|
||||||
|
|
||||||
self.config.set(
|
self.config.set(
|
||||||
'bitmessagesettings', 'namecoinrpctype', self.getNamecoinType())
|
'bitmessagesettings', 'namecoinrpctype', self.getNamecoinType())
|
||||||
self.config.set('bitmessagesettings', 'namecoinrpchost', str(
|
self.config.set('bitmessagesettings', 'namecoinrpchost', ustr(
|
||||||
self.lineEditNamecoinHost.text()))
|
self.lineEditNamecoinHost.text()))
|
||||||
self.config.set('bitmessagesettings', 'namecoinrpcport', str(
|
self.config.set('bitmessagesettings', 'namecoinrpcport', ustr(
|
||||||
self.lineEditNamecoinPort.text()))
|
self.lineEditNamecoinPort.text()))
|
||||||
self.config.set('bitmessagesettings', 'namecoinrpcuser', str(
|
self.config.set('bitmessagesettings', 'namecoinrpcuser', ustr(
|
||||||
self.lineEditNamecoinUser.text()))
|
self.lineEditNamecoinUser.text()))
|
||||||
self.config.set('bitmessagesettings', 'namecoinrpcpassword', str(
|
self.config.set('bitmessagesettings', 'namecoinrpcpassword', ustr(
|
||||||
self.lineEditNamecoinPassword.text()))
|
self.lineEditNamecoinPassword.text()))
|
||||||
self.parent.resetNamecoinConnection()
|
self.parent.resetNamecoinConnection()
|
||||||
|
|
||||||
|
@ -510,11 +517,11 @@ class SettingsDialog(QtGui.QDialog):
|
||||||
float(self.lineEditSmallMessageDifficulty.text())
|
float(self.lineEditSmallMessageDifficulty.text())
|
||||||
* defaults.networkDefaultPayloadLengthExtraBytes)))
|
* defaults.networkDefaultPayloadLengthExtraBytes)))
|
||||||
|
|
||||||
if self.comboBoxOpenCL.currentText().toUtf8() != self.config.safeGet(
|
if ustr(self.comboBoxOpenCL.currentText()) != ustr(self.config.safeGet(
|
||||||
'bitmessagesettings', 'opencl'):
|
'bitmessagesettings', 'opencl')):
|
||||||
self.config.set(
|
self.config.set(
|
||||||
'bitmessagesettings', 'opencl',
|
'bitmessagesettings', 'opencl',
|
||||||
str(self.comboBoxOpenCL.currentText()))
|
ustr(self.comboBoxOpenCL.currentText()))
|
||||||
queues.workerQueue.put(('resetPoW', ''))
|
queues.workerQueue.put(('resetPoW', ''))
|
||||||
|
|
||||||
acceptableDifficultyChanged = False
|
acceptableDifficultyChanged = False
|
||||||
|
|
|
@ -5,6 +5,7 @@ src/settingsmixin.py
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
from unqstr import ustr
|
||||||
from PyQt4 import QtCore, QtGui
|
from PyQt4 import QtCore, QtGui
|
||||||
|
|
||||||
|
|
||||||
|
@ -40,7 +41,7 @@ class SettingsMixin(object):
|
||||||
self.warnIfNoObjectName()
|
self.warnIfNoObjectName()
|
||||||
settings = QtCore.QSettings()
|
settings = QtCore.QSettings()
|
||||||
try:
|
try:
|
||||||
geom = settings.value("/".join([str(self.objectName()), "geometry"]))
|
geom = settings.value("/".join([ustr(self.objectName()), "geometry"]))
|
||||||
target.restoreGeometry(geom.toByteArray() if hasattr(geom, 'toByteArray') else geom)
|
target.restoreGeometry(geom.toByteArray() if hasattr(geom, 'toByteArray') else geom)
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
@ -50,7 +51,7 @@ class SettingsMixin(object):
|
||||||
self.warnIfNoObjectName()
|
self.warnIfNoObjectName()
|
||||||
settings = QtCore.QSettings()
|
settings = QtCore.QSettings()
|
||||||
try:
|
try:
|
||||||
state = settings.value("/".join([str(self.objectName()), "state"]))
|
state = settings.value("/".join([ustr(self.objectName()), "state"]))
|
||||||
target.restoreState(state.toByteArray() if hasattr(state, 'toByteArray') else state)
|
target.restoreState(state.toByteArray() if hasattr(state, 'toByteArray') else state)
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
|
|
@ -6,9 +6,11 @@ import ssl
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
|
|
||||||
|
from unqstr import ustr, unic
|
||||||
from PyQt4 import QtCore
|
from PyQt4 import QtCore
|
||||||
|
from dbcompat import dbstr
|
||||||
|
|
||||||
import account
|
from bitmessageqt import account
|
||||||
import defaults
|
import defaults
|
||||||
import network.stats
|
import network.stats
|
||||||
import paths
|
import paths
|
||||||
|
@ -16,12 +18,12 @@ import proofofwork
|
||||||
import queues
|
import queues
|
||||||
import state
|
import state
|
||||||
from bmconfigparser import config
|
from bmconfigparser import config
|
||||||
from foldertree import AccountMixin
|
from .foldertree import AccountMixin
|
||||||
from helper_sql import sqlExecute, sqlQuery
|
from helper_sql import sqlExecute, sqlQuery
|
||||||
from l10n import getTranslationLanguage
|
from l10n import getTranslationLanguage
|
||||||
from openclpow import openclEnabled
|
from openclpow import openclEnabled
|
||||||
from pyelliptic.openssl import OpenSSL
|
from pyelliptic.openssl import OpenSSL
|
||||||
from settings import getSOCKSProxyType
|
from .settings import getSOCKSProxyType
|
||||||
from version import softwareVersion
|
from version import softwareVersion
|
||||||
from tr import _translate
|
from tr import _translate
|
||||||
|
|
||||||
|
@ -67,12 +69,12 @@ Connected hosts: {}
|
||||||
|
|
||||||
|
|
||||||
def checkAddressBook(myapp):
|
def checkAddressBook(myapp):
|
||||||
sqlExecute('DELETE from addressbook WHERE address=?', OLD_SUPPORT_ADDRESS)
|
sqlExecute('DELETE from addressbook WHERE address=?', dbstr(OLD_SUPPORT_ADDRESS))
|
||||||
queryreturn = sqlQuery('SELECT * FROM addressbook WHERE address=?', SUPPORT_ADDRESS)
|
queryreturn = sqlQuery('SELECT * FROM addressbook WHERE address=?', dbstr(SUPPORT_ADDRESS))
|
||||||
if queryreturn == []:
|
if queryreturn == []:
|
||||||
sqlExecute(
|
sqlExecute(
|
||||||
'INSERT INTO addressbook VALUES (?,?)',
|
'INSERT INTO addressbook VALUES (?,?)',
|
||||||
SUPPORT_LABEL.toUtf8(), SUPPORT_ADDRESS)
|
dbstr(SUPPORT_LABEL), dbstr(SUPPORT_ADDRESS))
|
||||||
myapp.rerenderAddressBook()
|
myapp.rerenderAddressBook()
|
||||||
|
|
||||||
|
|
||||||
|
@ -88,7 +90,7 @@ def createAddressIfNeeded(myapp):
|
||||||
if not checkHasNormalAddress():
|
if not checkHasNormalAddress():
|
||||||
queues.addressGeneratorQueue.put((
|
queues.addressGeneratorQueue.put((
|
||||||
'createRandomAddress', 4, 1,
|
'createRandomAddress', 4, 1,
|
||||||
str(SUPPORT_MY_LABEL.toUtf8()),
|
ustr(SUPPORT_MY_LABEL),
|
||||||
1, "", False,
|
1, "", False,
|
||||||
defaults.networkDefaultProofOfWorkNonceTrialsPerByte,
|
defaults.networkDefaultProofOfWorkNonceTrialsPerByte,
|
||||||
defaults.networkDefaultPayloadLengthExtraBytes
|
defaults.networkDefaultPayloadLengthExtraBytes
|
||||||
|
@ -122,7 +124,7 @@ def createSupportMessage(myapp):
|
||||||
os = sys.platform
|
os = sys.platform
|
||||||
if os == "win32":
|
if os == "win32":
|
||||||
windowsversion = sys.getwindowsversion()
|
windowsversion = sys.getwindowsversion()
|
||||||
os = "Windows " + str(windowsversion[0]) + "." + str(windowsversion[1])
|
os = "Windows " + ustr(windowsversion[0]) + "." + ustr(windowsversion[1])
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
from os import uname
|
from os import uname
|
||||||
|
@ -141,7 +143,7 @@ def createSupportMessage(myapp):
|
||||||
frozen = paths.frozen
|
frozen = paths.frozen
|
||||||
portablemode = "True" if state.appdata == paths.lookupExeFolder() else "False"
|
portablemode = "True" if state.appdata == paths.lookupExeFolder() else "False"
|
||||||
cpow = "True" if proofofwork.bmpow else "False"
|
cpow = "True" if proofofwork.bmpow else "False"
|
||||||
openclpow = str(
|
openclpow = ustr(
|
||||||
config.safeGet('bitmessagesettings', 'opencl')
|
config.safeGet('bitmessagesettings', 'opencl')
|
||||||
) if openclEnabled() else "None"
|
) if openclEnabled() else "None"
|
||||||
locale = getTranslationLanguage()
|
locale = getTranslationLanguage()
|
||||||
|
@ -149,9 +151,9 @@ def createSupportMessage(myapp):
|
||||||
upnp = config.safeGet('bitmessagesettings', 'upnp', "N/A")
|
upnp = config.safeGet('bitmessagesettings', 'upnp', "N/A")
|
||||||
connectedhosts = len(network.stats.connectedHostsList())
|
connectedhosts = len(network.stats.connectedHostsList())
|
||||||
|
|
||||||
myapp.ui.textEditMessage.setText(unicode(SUPPORT_MESSAGE, 'utf-8').format(
|
myapp.ui.textEditMessage.setText(unic(ustr(SUPPORT_MESSAGE).format(
|
||||||
version, os, architecture, pythonversion, opensslversion, frozen,
|
version, os, architecture, pythonversion, opensslversion, frozen,
|
||||||
portablemode, cpow, openclpow, locale, socks, upnp, connectedhosts))
|
portablemode, cpow, openclpow, locale, socks, upnp, connectedhosts)))
|
||||||
|
|
||||||
# single msg tab
|
# single msg tab
|
||||||
myapp.ui.tabWidgetSend.setCurrentIndex(
|
myapp.ui.tabWidgetSend.setCurrentIndex(
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import helper_addressbook
|
import helper_addressbook
|
||||||
from bitmessageqt.support import createAddressIfNeeded
|
from bitmessageqt.support import createAddressIfNeeded
|
||||||
|
|
||||||
from main import TestBase
|
from .main import TestBase
|
||||||
|
|
||||||
|
|
||||||
class TestAddressbook(TestBase):
|
class TestAddressbook(TestBase):
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
"""Common definitions for bitmessageqt tests"""
|
"""Common definitions for bitmessageqt tests"""
|
||||||
|
|
||||||
|
from six.moves import queue as Queue
|
||||||
import sys
|
import sys
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
|
@ -52,7 +53,7 @@ class TestMain(unittest.TestCase):
|
||||||
"""Check the results of _translate() with various args"""
|
"""Check the results of _translate() with various args"""
|
||||||
self.assertIsInstance(
|
self.assertIsInstance(
|
||||||
_translate("MainWindow", "Test"),
|
_translate("MainWindow", "Test"),
|
||||||
QtCore.QString
|
str
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,9 @@ import sys
|
||||||
|
|
||||||
from shared import isAddressInMyAddressBook
|
from shared import isAddressInMyAddressBook
|
||||||
|
|
||||||
from main import TestBase
|
from .main import TestBase
|
||||||
|
|
||||||
|
from unqstr import ustr
|
||||||
|
|
||||||
|
|
||||||
class TestSupport(TestBase):
|
class TestSupport(TestBase):
|
||||||
|
@ -26,8 +28,8 @@ class TestSupport(TestBase):
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
ui.tabWidget.currentIndex(), ui.tabWidget.indexOf(ui.send))
|
ui.tabWidget.currentIndex(), ui.tabWidget.indexOf(ui.send))
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
ui.lineEditTo.text(), self.SUPPORT_ADDRESS)
|
ustr(ui.lineEditTo.text()), ustr(self.SUPPORT_ADDRESS))
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
ui.lineEditSubject.text(), self.SUPPORT_SUBJECT)
|
ustr(ui.lineEditSubject.text()), ustr(self.SUPPORT_SUBJECT))
|
||||||
self.assertIn(
|
self.assertIn(
|
||||||
sys.version, ui.textEditMessage.toPlainText())
|
sys.version, ui.textEditMessage.toPlainText())
|
||||||
|
|
|
@ -38,7 +38,7 @@ def identiconize(address):
|
||||||
# stripped from PIL and uses QT instead (by sendiulo, same license)
|
# stripped from PIL and uses QT instead (by sendiulo, same license)
|
||||||
import qidenticon
|
import qidenticon
|
||||||
icon_hash = hashlib.md5(
|
icon_hash = hashlib.md5(
|
||||||
addBMIfNotPresent(address) + identiconsuffix).hexdigest()
|
(addBMIfNotPresent(address) + identiconsuffix).encode("utf-8", "replace")).hexdigest()
|
||||||
use_two_colors = identicon_lib[:len('qidenticon_two')] == 'qidenticon_two'
|
use_two_colors = identicon_lib[:len('qidenticon_two')] == 'qidenticon_two'
|
||||||
opacity = int(
|
opacity = int(
|
||||||
identicon_lib not in (
|
identicon_lib not in (
|
||||||
|
@ -81,7 +81,7 @@ def avatarize(address):
|
||||||
falls back to identiconize(address)
|
falls back to identiconize(address)
|
||||||
"""
|
"""
|
||||||
idcon = QtGui.QIcon()
|
idcon = QtGui.QIcon()
|
||||||
icon_hash = hashlib.md5(addBMIfNotPresent(address)).hexdigest()
|
icon_hash = hashlib.md5(addBMIfNotPresent(address).encode("utf-8", "replace")).hexdigest()
|
||||||
if address == str_broadcast_subscribers:
|
if address == str_broadcast_subscribers:
|
||||||
# don't hash [Broadcast subscribers]
|
# don't hash [Broadcast subscribers]
|
||||||
icon_hash = address
|
icon_hash = address
|
||||||
|
|
|
@ -15,13 +15,17 @@ try:
|
||||||
except ImportError:
|
except ImportError:
|
||||||
from pybitmessage import state
|
from pybitmessage import state
|
||||||
|
|
||||||
SafeConfigParser = configparser.SafeConfigParser
|
try:
|
||||||
|
SafeConfigParser = configparser.SafeConfigParser
|
||||||
|
except AttributeError:
|
||||||
|
# alpine linux, python3.12
|
||||||
|
SafeConfigParser = configparser.ConfigParser
|
||||||
config_ready = Event()
|
config_ready = Event()
|
||||||
|
|
||||||
|
|
||||||
class BMConfigParser(SafeConfigParser):
|
class BMConfigParser(SafeConfigParser):
|
||||||
"""
|
"""
|
||||||
Singleton class inherited from :class:`ConfigParser.SafeConfigParser`
|
Singleton class inherited from :class:`configparser.SafeConfigParser`
|
||||||
with additional methods specific to bitmessage config.
|
with additional methods specific to bitmessage config.
|
||||||
"""
|
"""
|
||||||
# pylint: disable=too-many-ancestors
|
# pylint: disable=too-many-ancestors
|
||||||
|
|
|
@ -211,8 +211,8 @@ class addressGenerator(StoppableThread):
|
||||||
'updateStatusBar',
|
'updateStatusBar',
|
||||||
_translate(
|
_translate(
|
||||||
"MainWindow",
|
"MainWindow",
|
||||||
"Generating %1 new addresses."
|
"Generating {0} new addresses."
|
||||||
).arg(str(numberOfAddressesToMake))
|
).format(str(numberOfAddressesToMake))
|
||||||
))
|
))
|
||||||
signingKeyNonce = 0
|
signingKeyNonce = 0
|
||||||
encryptionKeyNonce = 1
|
encryptionKeyNonce = 1
|
||||||
|
@ -302,9 +302,9 @@ class addressGenerator(StoppableThread):
|
||||||
'updateStatusBar',
|
'updateStatusBar',
|
||||||
_translate(
|
_translate(
|
||||||
"MainWindow",
|
"MainWindow",
|
||||||
"%1 is already in 'Your Identities'."
|
"{0} is already in 'Your Identities'."
|
||||||
" Not adding it again."
|
" Not adding it again."
|
||||||
).arg(address)
|
).format(address)
|
||||||
))
|
))
|
||||||
else:
|
else:
|
||||||
self.logger.debug('label: %s', label)
|
self.logger.debug('label: %s', label)
|
||||||
|
|
|
@ -12,6 +12,7 @@ import subprocess # nosec B404
|
||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
from binascii import hexlify
|
from binascii import hexlify
|
||||||
|
import sqlite3
|
||||||
|
|
||||||
import helper_bitcoin
|
import helper_bitcoin
|
||||||
import helper_inbox
|
import helper_inbox
|
||||||
|
@ -33,6 +34,7 @@ from helper_sql import (
|
||||||
from network import knownnodes, invQueue
|
from network import knownnodes, invQueue
|
||||||
from network.node import Peer
|
from network.node import Peer
|
||||||
from tr import _translate
|
from tr import _translate
|
||||||
|
from dbcompat import dbstr
|
||||||
|
|
||||||
logger = logging.getLogger('default')
|
logger = logging.getLogger('default')
|
||||||
|
|
||||||
|
@ -121,7 +123,7 @@ class objectProcessor(threading.Thread):
|
||||||
objectType, data = queues.objectProcessorQueue.get()
|
objectType, data = queues.objectProcessorQueue.get()
|
||||||
sql.execute(
|
sql.execute(
|
||||||
'INSERT INTO objectprocessorqueue VALUES (?,?)',
|
'INSERT INTO objectprocessorqueue VALUES (?,?)',
|
||||||
objectType, data)
|
objectType, sqlite3.Binary(data))
|
||||||
numberOfObjectsThatWereInTheObjectProcessorQueue += 1
|
numberOfObjectsThatWereInTheObjectProcessorQueue += 1
|
||||||
logger.debug(
|
logger.debug(
|
||||||
'Saved %s objects from the objectProcessorQueue to'
|
'Saved %s objects from the objectProcessorQueue to'
|
||||||
|
@ -140,19 +142,24 @@ class objectProcessor(threading.Thread):
|
||||||
# bypass nonce and time, retain object type/version/stream + body
|
# bypass nonce and time, retain object type/version/stream + body
|
||||||
readPosition = 16
|
readPosition = 16
|
||||||
|
|
||||||
if data[readPosition:] in state.ackdataForWhichImWatching:
|
data_bytes = bytes(data[readPosition:])
|
||||||
|
if data_bytes in state.ackdataForWhichImWatching:
|
||||||
logger.info('This object is an acknowledgement bound for me.')
|
logger.info('This object is an acknowledgement bound for me.')
|
||||||
del state.ackdataForWhichImWatching[data[readPosition:]]
|
del state.ackdataForWhichImWatching[data_bytes]
|
||||||
sqlExecute(
|
rowcount = sqlExecute(
|
||||||
"UPDATE sent SET status='ackreceived', lastactiontime=?"
|
"UPDATE sent SET status='ackreceived', lastactiontime=?"
|
||||||
" WHERE ackdata=?", int(time.time()), data[readPosition:])
|
" WHERE ackdata=?", int(time.time()), sqlite3.Binary(data_bytes))
|
||||||
|
if rowcount < 1:
|
||||||
|
rowcount = sqlExecute(
|
||||||
|
"UPDATE sent SET status='ackreceived', lastactiontime=?"
|
||||||
|
" WHERE ackdata=CAST(? AS TEXT)", int(time.time()), data_bytes)
|
||||||
queues.UISignalQueue.put((
|
queues.UISignalQueue.put((
|
||||||
'updateSentItemStatusByAckdata', (
|
'updateSentItemStatusByAckdata', (
|
||||||
data[readPosition:],
|
data_bytes,
|
||||||
_translate(
|
_translate(
|
||||||
"MainWindow",
|
"MainWindow",
|
||||||
"Acknowledgement of the message received %1"
|
"Acknowledgement of the message received {0}"
|
||||||
).arg(l10n.formatTimestamp()))
|
).format(l10n.formatTimestamp()))
|
||||||
))
|
))
|
||||||
else:
|
else:
|
||||||
logger.debug('This object is not an acknowledgement bound for me.')
|
logger.debug('This object is not an acknowledgement bound for me.')
|
||||||
|
@ -215,9 +222,10 @@ class objectProcessor(threading.Thread):
|
||||||
logger.info(
|
logger.info(
|
||||||
'the hash requested in this getpubkey request is: %s',
|
'the hash requested in this getpubkey request is: %s',
|
||||||
hexlify(requestedHash))
|
hexlify(requestedHash))
|
||||||
|
requestedHash_bytes = bytes(requestedHash)
|
||||||
# if this address hash is one of mine
|
# if this address hash is one of mine
|
||||||
if requestedHash in shared.myAddressesByHash:
|
if requestedHash_bytes in shared.myAddressesByHash:
|
||||||
myAddress = shared.myAddressesByHash[requestedHash]
|
myAddress = shared.myAddressesByHash[requestedHash_bytes]
|
||||||
elif requestedAddressVersionNumber >= 4:
|
elif requestedAddressVersionNumber >= 4:
|
||||||
requestedTag = data[readPosition:readPosition + 32]
|
requestedTag = data[readPosition:readPosition + 32]
|
||||||
if len(requestedTag) != 32:
|
if len(requestedTag) != 32:
|
||||||
|
@ -227,8 +235,9 @@ class objectProcessor(threading.Thread):
|
||||||
logger.debug(
|
logger.debug(
|
||||||
'the tag requested in this getpubkey request is: %s',
|
'the tag requested in this getpubkey request is: %s',
|
||||||
hexlify(requestedTag))
|
hexlify(requestedTag))
|
||||||
if requestedTag in shared.myAddressesByTag:
|
requestedTag_bytes = bytes(requestedTag)
|
||||||
myAddress = shared.myAddressesByTag[requestedTag]
|
if requestedTag_bytes in shared.myAddressesByTag:
|
||||||
|
myAddress = shared.myAddressesByTag[requestedTag_bytes]
|
||||||
|
|
||||||
if myAddress == '':
|
if myAddress == '':
|
||||||
logger.info('This getpubkey request is not for any of my keys.')
|
logger.info('This getpubkey request is not for any of my keys.')
|
||||||
|
@ -299,12 +308,12 @@ class objectProcessor(threading.Thread):
|
||||||
'(within processpubkey) payloadLength less than 146.'
|
'(within processpubkey) payloadLength less than 146.'
|
||||||
' Sanity check failed.')
|
' Sanity check failed.')
|
||||||
readPosition += 4
|
readPosition += 4
|
||||||
pubSigningKey = '\x04' + data[readPosition:readPosition + 64]
|
pubSigningKey = b'\x04' + data[readPosition:readPosition + 64]
|
||||||
# Is it possible for a public key to be invalid such that trying to
|
# Is it possible for a public key to be invalid such that trying to
|
||||||
# encrypt or sign with it will cause an error? If it is, it would
|
# encrypt or sign with it will cause an error? If it is, it would
|
||||||
# be easiest to test them here.
|
# be easiest to test them here.
|
||||||
readPosition += 64
|
readPosition += 64
|
||||||
pubEncryptionKey = '\x04' + data[readPosition:readPosition + 64]
|
pubEncryptionKey = b'\x04' + data[readPosition:readPosition + 64]
|
||||||
if len(pubEncryptionKey) < 65:
|
if len(pubEncryptionKey) < 65:
|
||||||
return logger.debug(
|
return logger.debug(
|
||||||
'publicEncryptionKey length less than 64. Sanity check'
|
'publicEncryptionKey length less than 64. Sanity check'
|
||||||
|
@ -327,19 +336,19 @@ class objectProcessor(threading.Thread):
|
||||||
|
|
||||||
queryreturn = sqlQuery(
|
queryreturn = sqlQuery(
|
||||||
"SELECT usedpersonally FROM pubkeys WHERE address=?"
|
"SELECT usedpersonally FROM pubkeys WHERE address=?"
|
||||||
" AND usedpersonally='yes'", address)
|
" AND usedpersonally='yes'", dbstr(address))
|
||||||
# if this pubkey is already in our database and if we have
|
# if this pubkey is already in our database and if we have
|
||||||
# used it personally:
|
# used it personally:
|
||||||
if queryreturn != []:
|
if queryreturn != []:
|
||||||
logger.info(
|
logger.info(
|
||||||
'We HAVE used this pubkey personally. Updating time.')
|
'We HAVE used this pubkey personally. Updating time.')
|
||||||
t = (address, addressVersion, dataToStore,
|
t = (dbstr(address), addressVersion, sqlite3.Binary(dataToStore),
|
||||||
int(time.time()), 'yes')
|
int(time.time()), 'yes')
|
||||||
else:
|
else:
|
||||||
logger.info(
|
logger.info(
|
||||||
'We have NOT used this pubkey personally. Inserting'
|
'We have NOT used this pubkey personally. Inserting'
|
||||||
' in database.')
|
' in database.')
|
||||||
t = (address, addressVersion, dataToStore,
|
t = (dbstr(address), addressVersion, sqlite3.Binary(dataToStore),
|
||||||
int(time.time()), 'no')
|
int(time.time()), 'no')
|
||||||
sqlExecute('''INSERT INTO pubkeys VALUES (?,?,?,?,?)''', *t)
|
sqlExecute('''INSERT INTO pubkeys VALUES (?,?,?,?,?)''', *t)
|
||||||
self.possibleNewPubkey(address)
|
self.possibleNewPubkey(address)
|
||||||
|
@ -350,9 +359,9 @@ class objectProcessor(threading.Thread):
|
||||||
' Sanity check failed.')
|
' Sanity check failed.')
|
||||||
return
|
return
|
||||||
readPosition += 4
|
readPosition += 4
|
||||||
pubSigningKey = '\x04' + data[readPosition:readPosition + 64]
|
pubSigningKey = b'\x04' + data[readPosition:readPosition + 64]
|
||||||
readPosition += 64
|
readPosition += 64
|
||||||
pubEncryptionKey = '\x04' + data[readPosition:readPosition + 64]
|
pubEncryptionKey = b'\x04' + data[readPosition:readPosition + 64]
|
||||||
readPosition += 64
|
readPosition += 64
|
||||||
specifiedNonceTrialsPerByteLength = decodeVarint(
|
specifiedNonceTrialsPerByteLength = decodeVarint(
|
||||||
data[readPosition:readPosition + 10])[1]
|
data[readPosition:readPosition + 10])[1]
|
||||||
|
@ -389,20 +398,20 @@ class objectProcessor(threading.Thread):
|
||||||
address = encodeAddress(addressVersion, streamNumber, ripe)
|
address = encodeAddress(addressVersion, streamNumber, ripe)
|
||||||
queryreturn = sqlQuery(
|
queryreturn = sqlQuery(
|
||||||
"SELECT usedpersonally FROM pubkeys WHERE address=?"
|
"SELECT usedpersonally FROM pubkeys WHERE address=?"
|
||||||
" AND usedpersonally='yes'", address)
|
" AND usedpersonally='yes'", dbstr(address))
|
||||||
# if this pubkey is already in our database and if we have
|
# if this pubkey is already in our database and if we have
|
||||||
# used it personally:
|
# used it personally:
|
||||||
if queryreturn != []:
|
if queryreturn != []:
|
||||||
logger.info(
|
logger.info(
|
||||||
'We HAVE used this pubkey personally. Updating time.')
|
'We HAVE used this pubkey personally. Updating time.')
|
||||||
t = (address, addressVersion, dataToStore,
|
t = (dbstr(address), addressVersion, sqlite3.Binary(dataToStore),
|
||||||
int(time.time()), 'yes')
|
int(time.time()), dbstr('yes'))
|
||||||
else:
|
else:
|
||||||
logger.info(
|
logger.info(
|
||||||
'We have NOT used this pubkey personally. Inserting'
|
'We have NOT used this pubkey personally. Inserting'
|
||||||
' in database.')
|
' in database.')
|
||||||
t = (address, addressVersion, dataToStore,
|
t = (dbstr(address), addressVersion, sqlite3.Binary(dataToStore),
|
||||||
int(time.time()), 'no')
|
int(time.time()), dbstr('no'))
|
||||||
sqlExecute('''INSERT INTO pubkeys VALUES (?,?,?,?,?)''', *t)
|
sqlExecute('''INSERT INTO pubkeys VALUES (?,?,?,?,?)''', *t)
|
||||||
self.possibleNewPubkey(address)
|
self.possibleNewPubkey(address)
|
||||||
|
|
||||||
|
@ -413,12 +422,13 @@ class objectProcessor(threading.Thread):
|
||||||
' Sanity check failed.')
|
' Sanity check failed.')
|
||||||
|
|
||||||
tag = data[readPosition:readPosition + 32]
|
tag = data[readPosition:readPosition + 32]
|
||||||
if tag not in state.neededPubkeys:
|
tag_bytes = bytes(tag)
|
||||||
|
if tag_bytes not in state.neededPubkeys:
|
||||||
return logger.info(
|
return logger.info(
|
||||||
'We don\'t need this v4 pubkey. We didn\'t ask for it.')
|
'We don\'t need this v4 pubkey. We didn\'t ask for it.')
|
||||||
|
|
||||||
# Let us try to decrypt the pubkey
|
# Let us try to decrypt the pubkey
|
||||||
toAddress = state.neededPubkeys[tag][0]
|
toAddress = state.neededPubkeys[tag_bytes][0]
|
||||||
if protocol.decryptAndCheckPubkeyPayload(data, toAddress) == \
|
if protocol.decryptAndCheckPubkeyPayload(data, toAddress) == \
|
||||||
'successful':
|
'successful':
|
||||||
# At this point we know that we have been waiting on this
|
# At this point we know that we have been waiting on this
|
||||||
|
@ -483,7 +493,7 @@ class objectProcessor(threading.Thread):
|
||||||
|
|
||||||
# This is a message bound for me.
|
# This is a message bound for me.
|
||||||
# Look up my address based on the RIPE hash.
|
# Look up my address based on the RIPE hash.
|
||||||
toAddress = shared.myAddressesByHash[toRipe]
|
toAddress = shared.myAddressesByHash[bytes(toRipe)]
|
||||||
readPosition = 0
|
readPosition = 0
|
||||||
sendersAddressVersionNumber, sendersAddressVersionNumberLength = \
|
sendersAddressVersionNumber, sendersAddressVersionNumberLength = \
|
||||||
decodeVarint(decryptedData[readPosition:readPosition + 10])
|
decodeVarint(decryptedData[readPosition:readPosition + 10])
|
||||||
|
@ -507,9 +517,9 @@ class objectProcessor(threading.Thread):
|
||||||
return
|
return
|
||||||
readPosition += sendersStreamNumberLength
|
readPosition += sendersStreamNumberLength
|
||||||
readPosition += 4
|
readPosition += 4
|
||||||
pubSigningKey = '\x04' + decryptedData[readPosition:readPosition + 64]
|
pubSigningKey = b'\x04' + decryptedData[readPosition:readPosition + 64]
|
||||||
readPosition += 64
|
readPosition += 64
|
||||||
pubEncryptionKey = '\x04' + decryptedData[readPosition:readPosition + 64]
|
pubEncryptionKey = b'\x04' + decryptedData[readPosition:readPosition + 64]
|
||||||
readPosition += 64
|
readPosition += 64
|
||||||
if sendersAddressVersionNumber >= 3:
|
if sendersAddressVersionNumber >= 3:
|
||||||
requiredAverageProofOfWorkNonceTrialsPerByte, varintLength = \
|
requiredAverageProofOfWorkNonceTrialsPerByte, varintLength = \
|
||||||
|
@ -558,7 +568,7 @@ class objectProcessor(threading.Thread):
|
||||||
readPosition += signatureLengthLength
|
readPosition += signatureLengthLength
|
||||||
signature = decryptedData[
|
signature = decryptedData[
|
||||||
readPosition:readPosition + signatureLength]
|
readPosition:readPosition + signatureLength]
|
||||||
signedData = data[8:20] + encodeVarint(1) + encodeVarint(
|
signedData = bytes(data[8:20]) + encodeVarint(1) + encodeVarint(
|
||||||
streamNumberAsClaimedByMsg
|
streamNumberAsClaimedByMsg
|
||||||
) + decryptedData[:positionOfBottomOfAckData]
|
) + decryptedData[:positionOfBottomOfAckData]
|
||||||
|
|
||||||
|
@ -590,11 +600,11 @@ class objectProcessor(threading.Thread):
|
||||||
# person.
|
# person.
|
||||||
sqlExecute(
|
sqlExecute(
|
||||||
'''INSERT INTO pubkeys VALUES (?,?,?,?,?)''',
|
'''INSERT INTO pubkeys VALUES (?,?,?,?,?)''',
|
||||||
fromAddress,
|
dbstr(fromAddress),
|
||||||
sendersAddressVersionNumber,
|
sendersAddressVersionNumber,
|
||||||
decryptedData[:endOfThePublicKeyPosition],
|
sqlite3.Binary(decryptedData[:endOfThePublicKeyPosition]),
|
||||||
int(time.time()),
|
int(time.time()),
|
||||||
'yes')
|
dbstr('yes'))
|
||||||
|
|
||||||
# Check to see whether we happen to be awaiting this
|
# Check to see whether we happen to be awaiting this
|
||||||
# pubkey in order to send a message. If we are, it will do the POW
|
# pubkey in order to send a message. If we are, it will do the POW
|
||||||
|
@ -631,7 +641,7 @@ class objectProcessor(threading.Thread):
|
||||||
'bitmessagesettings', 'blackwhitelist') == 'black':
|
'bitmessagesettings', 'blackwhitelist') == 'black':
|
||||||
queryreturn = sqlQuery(
|
queryreturn = sqlQuery(
|
||||||
"SELECT label FROM blacklist where address=? and enabled='1'",
|
"SELECT label FROM blacklist where address=? and enabled='1'",
|
||||||
fromAddress)
|
dbstr(fromAddress))
|
||||||
if queryreturn != []:
|
if queryreturn != []:
|
||||||
logger.info('Message ignored because address is in blacklist.')
|
logger.info('Message ignored because address is in blacklist.')
|
||||||
|
|
||||||
|
@ -639,7 +649,7 @@ class objectProcessor(threading.Thread):
|
||||||
else: # We're using a whitelist
|
else: # We're using a whitelist
|
||||||
queryreturn = sqlQuery(
|
queryreturn = sqlQuery(
|
||||||
"SELECT label FROM whitelist where address=? and enabled='1'",
|
"SELECT label FROM whitelist where address=? and enabled='1'",
|
||||||
fromAddress)
|
dbstr(fromAddress))
|
||||||
if queryreturn == []:
|
if queryreturn == []:
|
||||||
logger.info(
|
logger.info(
|
||||||
'Message ignored because address not in whitelist.')
|
'Message ignored because address not in whitelist.')
|
||||||
|
@ -808,13 +818,14 @@ class objectProcessor(threading.Thread):
|
||||||
elif broadcastVersion == 5:
|
elif broadcastVersion == 5:
|
||||||
embeddedTag = data[readPosition:readPosition + 32]
|
embeddedTag = data[readPosition:readPosition + 32]
|
||||||
readPosition += 32
|
readPosition += 32
|
||||||
if embeddedTag not in shared.MyECSubscriptionCryptorObjects:
|
embeddedTag_bytes = bytes(embeddedTag)
|
||||||
|
if embeddedTag_bytes not in shared.MyECSubscriptionCryptorObjects:
|
||||||
logger.debug('We\'re not interested in this broadcast.')
|
logger.debug('We\'re not interested in this broadcast.')
|
||||||
return
|
return
|
||||||
# We are interested in this broadcast because of its tag.
|
# We are interested in this broadcast because of its tag.
|
||||||
# We're going to add some more data which is signed further down.
|
# We're going to add some more data which is signed further down.
|
||||||
signedData = data[8:readPosition]
|
signedData = bytes(data[8:readPosition])
|
||||||
cryptorObject = shared.MyECSubscriptionCryptorObjects[embeddedTag]
|
cryptorObject = shared.MyECSubscriptionCryptorObjects[embeddedTag_bytes]
|
||||||
try:
|
try:
|
||||||
decryptedData = cryptorObject.decrypt(data[readPosition:])
|
decryptedData = cryptorObject.decrypt(data[readPosition:])
|
||||||
logger.debug('EC decryption successful')
|
logger.debug('EC decryption successful')
|
||||||
|
@ -854,10 +865,10 @@ class objectProcessor(threading.Thread):
|
||||||
)
|
)
|
||||||
readPosition += sendersStreamLength
|
readPosition += sendersStreamLength
|
||||||
readPosition += 4
|
readPosition += 4
|
||||||
sendersPubSigningKey = '\x04' + \
|
sendersPubSigningKey = b'\x04' + \
|
||||||
decryptedData[readPosition:readPosition + 64]
|
decryptedData[readPosition:readPosition + 64]
|
||||||
readPosition += 64
|
readPosition += 64
|
||||||
sendersPubEncryptionKey = '\x04' + \
|
sendersPubEncryptionKey = b'\x04' + \
|
||||||
decryptedData[readPosition:readPosition + 64]
|
decryptedData[readPosition:readPosition + 64]
|
||||||
readPosition += 64
|
readPosition += 64
|
||||||
if sendersAddressVersion >= 3:
|
if sendersAddressVersion >= 3:
|
||||||
|
@ -927,11 +938,11 @@ class objectProcessor(threading.Thread):
|
||||||
|
|
||||||
# Let's store the public key in case we want to reply to this person.
|
# Let's store the public key in case we want to reply to this person.
|
||||||
sqlExecute('''INSERT INTO pubkeys VALUES (?,?,?,?,?)''',
|
sqlExecute('''INSERT INTO pubkeys VALUES (?,?,?,?,?)''',
|
||||||
fromAddress,
|
dbstr(fromAddress),
|
||||||
sendersAddressVersion,
|
dbstr(sendersAddressVersion),
|
||||||
decryptedData[:endOfPubkeyPosition],
|
sqlite3.Binary(decryptedData[:endOfPubkeyPosition]),
|
||||||
int(time.time()),
|
int(time.time()),
|
||||||
'yes')
|
dbstr('yes'))
|
||||||
|
|
||||||
# Check to see whether we happen to be awaiting this
|
# Check to see whether we happen to be awaiting this
|
||||||
# pubkey in order to send a message. If we are, it will do the POW
|
# pubkey in order to send a message. If we are, it will do the POW
|
||||||
|
@ -997,8 +1008,9 @@ class objectProcessor(threading.Thread):
|
||||||
encodeVarint(addressVersion) + encodeVarint(streamNumber)
|
encodeVarint(addressVersion) + encodeVarint(streamNumber)
|
||||||
+ ripe
|
+ ripe
|
||||||
)[32:]
|
)[32:]
|
||||||
if tag in state.neededPubkeys:
|
tag_bytes = bytes(tag)
|
||||||
del state.neededPubkeys[tag]
|
if tag_bytes in state.neededPubkeys:
|
||||||
|
del state.neededPubkeys[tag_bytes]
|
||||||
self.sendMessages(address)
|
self.sendMessages(address)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
@ -1012,7 +1024,7 @@ class objectProcessor(threading.Thread):
|
||||||
"UPDATE sent SET status='doingmsgpow', retrynumber=0"
|
"UPDATE sent SET status='doingmsgpow', retrynumber=0"
|
||||||
" WHERE toaddress=?"
|
" WHERE toaddress=?"
|
||||||
" AND (status='awaitingpubkey' OR status='doingpubkeypow')"
|
" AND (status='awaitingpubkey' OR status='doingpubkeypow')"
|
||||||
" AND folder='sent'", address)
|
" AND folder='sent'", dbstr(address))
|
||||||
queues.workerQueue.put(('sendmessage', ''))
|
queues.workerQueue.put(('sendmessage', ''))
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
@ -1047,8 +1059,8 @@ class objectProcessor(threading.Thread):
|
||||||
if checksum != hashlib.sha512(payload).digest()[0:4]:
|
if checksum != hashlib.sha512(payload).digest()[0:4]:
|
||||||
logger.info('ackdata checksum wrong. Not sending ackdata.')
|
logger.info('ackdata checksum wrong. Not sending ackdata.')
|
||||||
return False
|
return False
|
||||||
command = command.rstrip('\x00')
|
command = command.rstrip(b'\x00')
|
||||||
if command != 'object':
|
if command != b'object':
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,7 @@ It resends messages when there has been no response:
|
||||||
import gc
|
import gc
|
||||||
import os
|
import os
|
||||||
import time
|
import time
|
||||||
|
import sqlite3
|
||||||
|
|
||||||
import queues
|
import queues
|
||||||
import state
|
import state
|
||||||
|
@ -29,6 +30,7 @@ from bmconfigparser import config
|
||||||
from helper_sql import sqlExecute, sqlQuery
|
from helper_sql import sqlExecute, sqlQuery
|
||||||
from network import connectionpool, knownnodes, StoppableThread
|
from network import connectionpool, knownnodes, StoppableThread
|
||||||
from tr import _translate
|
from tr import _translate
|
||||||
|
from dbcompat import dbstr
|
||||||
|
|
||||||
|
|
||||||
#: Equals 4 weeks. You could make this longer if you want
|
#: Equals 4 weeks. You could make this longer if you want
|
||||||
|
@ -99,6 +101,8 @@ class singleCleaner(StoppableThread):
|
||||||
tick - state.maximumLengthOfTimeToBotherResendingMessages
|
tick - state.maximumLengthOfTimeToBotherResendingMessages
|
||||||
)
|
)
|
||||||
for toAddress, ackData, status in queryreturn:
|
for toAddress, ackData, status in queryreturn:
|
||||||
|
toAddress = toAddress.decode("utf-8", "replace")
|
||||||
|
status = status.decode("utf-8", "replace")
|
||||||
if status == 'awaitingpubkey':
|
if status == 'awaitingpubkey':
|
||||||
self.resendPubkeyRequest(toAddress)
|
self.resendPubkeyRequest(toAddress)
|
||||||
elif status == 'msgsent':
|
elif status == 'msgsent':
|
||||||
|
@ -168,7 +172,7 @@ class singleCleaner(StoppableThread):
|
||||||
))
|
))
|
||||||
sqlExecute(
|
sqlExecute(
|
||||||
"UPDATE sent SET status = 'msgqueued'"
|
"UPDATE sent SET status = 'msgqueued'"
|
||||||
" WHERE toaddress = ? AND folder = 'sent'", address)
|
" WHERE toaddress = ? AND folder = 'sent'", dbstr(address))
|
||||||
queues.workerQueue.put(('sendmessage', ''))
|
queues.workerQueue.put(('sendmessage', ''))
|
||||||
|
|
||||||
def resendMsg(self, ackdata):
|
def resendMsg(self, ackdata):
|
||||||
|
@ -177,9 +181,13 @@ class singleCleaner(StoppableThread):
|
||||||
'It has been a long time and we haven\'t heard an acknowledgement'
|
'It has been a long time and we haven\'t heard an acknowledgement'
|
||||||
' to our msg. Sending again.'
|
' to our msg. Sending again.'
|
||||||
)
|
)
|
||||||
|
rowcount = sqlExecute(
|
||||||
|
"UPDATE sent SET status = 'msgqueued'"
|
||||||
|
" WHERE ackdata = ? AND folder = 'sent'", sqlite3.Binary(ackdata))
|
||||||
|
if rowcount < 1:
|
||||||
sqlExecute(
|
sqlExecute(
|
||||||
"UPDATE sent SET status = 'msgqueued'"
|
"UPDATE sent SET status = 'msgqueued'"
|
||||||
" WHERE ackdata = ? AND folder = 'sent'", ackdata)
|
" WHERE ackdata = CAST(? AS TEXT) AND folder = 'sent'", ackdata)
|
||||||
queues.workerQueue.put(('sendmessage', ''))
|
queues.workerQueue.put(('sendmessage', ''))
|
||||||
queues.UISignalQueue.put((
|
queues.UISignalQueue.put((
|
||||||
'updateStatusBar',
|
'updateStatusBar',
|
||||||
|
|
|
@ -11,6 +11,7 @@ import time
|
||||||
from binascii import hexlify, unhexlify
|
from binascii import hexlify, unhexlify
|
||||||
from struct import pack
|
from struct import pack
|
||||||
from subprocess import call # nosec
|
from subprocess import call # nosec
|
||||||
|
import sqlite3
|
||||||
|
|
||||||
import defaults
|
import defaults
|
||||||
import helper_inbox
|
import helper_inbox
|
||||||
|
@ -30,6 +31,9 @@ from bmconfigparser import config
|
||||||
from helper_sql import sqlExecute, sqlQuery
|
from helper_sql import sqlExecute, sqlQuery
|
||||||
from network import knownnodes, StoppableThread, invQueue
|
from network import knownnodes, StoppableThread, invQueue
|
||||||
from six.moves import configparser, queue
|
from six.moves import configparser, queue
|
||||||
|
from six.moves.reprlib import repr
|
||||||
|
import six
|
||||||
|
from dbcompat import dbstr
|
||||||
|
|
||||||
|
|
||||||
def sizeof_fmt(num, suffix='h/s'):
|
def sizeof_fmt(num, suffix='h/s'):
|
||||||
|
@ -73,6 +77,7 @@ class singleWorker(StoppableThread):
|
||||||
'''SELECT DISTINCT toaddress FROM sent'''
|
'''SELECT DISTINCT toaddress FROM sent'''
|
||||||
''' WHERE (status='awaitingpubkey' AND folder='sent')''')
|
''' WHERE (status='awaitingpubkey' AND folder='sent')''')
|
||||||
for toAddress, in queryreturn:
|
for toAddress, in queryreturn:
|
||||||
|
toAddress = toAddress.decode("utf-8", "replace")
|
||||||
toAddressVersionNumber, toStreamNumber, toRipe = \
|
toAddressVersionNumber, toStreamNumber, toRipe = \
|
||||||
decodeAddress(toAddress)[1:]
|
decodeAddress(toAddress)[1:]
|
||||||
if toAddressVersionNumber <= 3:
|
if toAddressVersionNumber <= 3:
|
||||||
|
@ -87,7 +92,7 @@ class singleWorker(StoppableThread):
|
||||||
tag = doubleHashOfAddressData[32:]
|
tag = doubleHashOfAddressData[32:]
|
||||||
# We'll need this for when we receive a pubkey reply:
|
# We'll need this for when we receive a pubkey reply:
|
||||||
# it will be encrypted and we'll need to decrypt it.
|
# it will be encrypted and we'll need to decrypt it.
|
||||||
state.neededPubkeys[tag] = (
|
state.neededPubkeys[bytes(tag)] = (
|
||||||
toAddress,
|
toAddress,
|
||||||
highlevelcrypto.makeCryptor(
|
highlevelcrypto.makeCryptor(
|
||||||
hexlify(privEncryptionKey))
|
hexlify(privEncryptionKey))
|
||||||
|
@ -99,17 +104,22 @@ class singleWorker(StoppableThread):
|
||||||
for row in queryreturn:
|
for row in queryreturn:
|
||||||
ackdata, = row
|
ackdata, = row
|
||||||
self.logger.info('Watching for ackdata %s', hexlify(ackdata))
|
self.logger.info('Watching for ackdata %s', hexlify(ackdata))
|
||||||
state.ackdataForWhichImWatching[ackdata] = 0
|
state.ackdataForWhichImWatching[bytes(ackdata)] = 0
|
||||||
|
|
||||||
# Fix legacy (headerless) watched ackdata to include header
|
# Fix legacy (headerless) watched ackdata to include header
|
||||||
for oldack in state.ackdataForWhichImWatching:
|
for oldack in state.ackdataForWhichImWatching:
|
||||||
if len(oldack) == 32:
|
if len(oldack) == 32:
|
||||||
# attach legacy header, always constant (msg/1/1)
|
# attach legacy header, always constant (msg/1/1)
|
||||||
newack = '\x00\x00\x00\x02\x01\x01' + oldack
|
newack = b'\x00\x00\x00\x02\x01\x01' + oldack
|
||||||
state.ackdataForWhichImWatching[newack] = 0
|
state.ackdataForWhichImWatching[bytes(newack)] = 0
|
||||||
sqlExecute(
|
rowcount = sqlExecute(
|
||||||
'''UPDATE sent SET ackdata=? WHERE ackdata=? AND folder = 'sent' ''',
|
'''UPDATE sent SET ackdata=? WHERE ackdata=? AND folder = 'sent' ''',
|
||||||
newack, oldack
|
sqlite3.Binary(newack), sqlite3.Binary(oldack)
|
||||||
|
)
|
||||||
|
if rowcount < 1:
|
||||||
|
sqlExecute(
|
||||||
|
'''UPDATE sent SET ackdata=? WHERE ackdata=CAST(? AS TEXT) AND folder = 'sent' ''',
|
||||||
|
sqlite3.Binary(newack), oldack
|
||||||
)
|
)
|
||||||
del state.ackdataForWhichImWatching[oldack]
|
del state.ackdataForWhichImWatching[oldack]
|
||||||
|
|
||||||
|
@ -261,7 +271,7 @@ class singleWorker(StoppableThread):
|
||||||
TTL = int(28 * 24 * 60 * 60 + helper_random.randomrandrange(-300, 300))
|
TTL = int(28 * 24 * 60 * 60 + helper_random.randomrandrange(-300, 300))
|
||||||
embeddedTime = int(time.time() + TTL)
|
embeddedTime = int(time.time() + TTL)
|
||||||
payload = pack('>Q', (embeddedTime))
|
payload = pack('>Q', (embeddedTime))
|
||||||
payload += '\x00\x00\x00\x01' # object type: pubkey
|
payload += b'\x00\x00\x00\x01' # object type: pubkey
|
||||||
payload += encodeVarint(addressVersionNumber) # Address version number
|
payload += encodeVarint(addressVersionNumber) # Address version number
|
||||||
payload += encodeVarint(streamNumber)
|
payload += encodeVarint(streamNumber)
|
||||||
# bitfield of features supported by me (see the wiki).
|
# bitfield of features supported by me (see the wiki).
|
||||||
|
@ -338,7 +348,7 @@ class singleWorker(StoppableThread):
|
||||||
# expiresTime time.
|
# expiresTime time.
|
||||||
|
|
||||||
payload = pack('>Q', (embeddedTime))
|
payload = pack('>Q', (embeddedTime))
|
||||||
payload += '\x00\x00\x00\x01' # object type: pubkey
|
payload += b'\x00\x00\x00\x01' # object type: pubkey
|
||||||
payload += encodeVarint(addressVersionNumber) # Address version number
|
payload += encodeVarint(addressVersionNumber) # Address version number
|
||||||
payload += encodeVarint(streamNumber)
|
payload += encodeVarint(streamNumber)
|
||||||
# bitfield of features supported by me (see the wiki).
|
# bitfield of features supported by me (see the wiki).
|
||||||
|
@ -413,7 +423,7 @@ class singleWorker(StoppableThread):
|
||||||
TTL = int(28 * 24 * 60 * 60 + helper_random.randomrandrange(-300, 300))
|
TTL = int(28 * 24 * 60 * 60 + helper_random.randomrandrange(-300, 300))
|
||||||
embeddedTime = int(time.time() + TTL)
|
embeddedTime = int(time.time() + TTL)
|
||||||
payload = pack('>Q', (embeddedTime))
|
payload = pack('>Q', (embeddedTime))
|
||||||
payload += '\x00\x00\x00\x01' # object type: pubkey
|
payload += b'\x00\x00\x00\x01' # object type: pubkey
|
||||||
payload += encodeVarint(addressVersionNumber) # Address version number
|
payload += encodeVarint(addressVersionNumber) # Address version number
|
||||||
payload += encodeVarint(streamNumber)
|
payload += encodeVarint(streamNumber)
|
||||||
dataToEncrypt = protocol.getBitfield(myAddress)
|
dataToEncrypt = protocol.getBitfield(myAddress)
|
||||||
|
@ -515,9 +525,15 @@ class singleWorker(StoppableThread):
|
||||||
payload, TTL, log_prefix='(For onionpeer object)')
|
payload, TTL, log_prefix='(For onionpeer object)')
|
||||||
|
|
||||||
inventoryHash = highlevelcrypto.calculateInventoryHash(payload)
|
inventoryHash = highlevelcrypto.calculateInventoryHash(payload)
|
||||||
|
if six.PY2:
|
||||||
|
payload_buffer = buffer(payload)
|
||||||
|
tag_buffer = buffer(tag)
|
||||||
|
else: # assume six.PY3
|
||||||
|
payload_buffer = memoryview(payload)
|
||||||
|
tag_buffer = memoryview(tag)
|
||||||
state.Inventory[inventoryHash] = (
|
state.Inventory[inventoryHash] = (
|
||||||
objectType, streamNumber, buffer(payload), # noqa: F821
|
objectType, streamNumber, payload_buffer, # noqa: F821
|
||||||
embeddedTime, buffer(tag) # noqa: F821
|
embeddedTime, tag_buffer # noqa: F821
|
||||||
)
|
)
|
||||||
self.logger.info(
|
self.logger.info(
|
||||||
'sending inv (within sendOnionPeerObj function) for object: %s',
|
'sending inv (within sendOnionPeerObj function) for object: %s',
|
||||||
|
@ -534,10 +550,13 @@ class singleWorker(StoppableThread):
|
||||||
queryreturn = sqlQuery(
|
queryreturn = sqlQuery(
|
||||||
'''SELECT fromaddress, subject, message, '''
|
'''SELECT fromaddress, subject, message, '''
|
||||||
''' ackdata, ttl, encodingtype FROM sent '''
|
''' ackdata, ttl, encodingtype FROM sent '''
|
||||||
''' WHERE status=? and folder='sent' ''', 'broadcastqueued')
|
''' WHERE status=? and folder='sent' ''', dbstr('broadcastqueued'))
|
||||||
|
|
||||||
for row in queryreturn:
|
for row in queryreturn:
|
||||||
fromaddress, subject, body, ackdata, TTL, encoding = row
|
fromaddress, subject, body, ackdata, TTL, encoding = row
|
||||||
|
fromaddress = fromaddress.decode("utf-8", "replace")
|
||||||
|
subject = subject.decode("utf-8", "replace")
|
||||||
|
body = body.decode("utf-8", "replace")
|
||||||
# status
|
# status
|
||||||
_, addressVersionNumber, streamNumber, ripe = \
|
_, addressVersionNumber, streamNumber, ripe = \
|
||||||
decodeAddress(fromaddress)
|
decodeAddress(fromaddress)
|
||||||
|
@ -578,11 +597,18 @@ class singleWorker(StoppableThread):
|
||||||
))
|
))
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if not sqlExecute(
|
rowcount = sqlExecute(
|
||||||
'''UPDATE sent SET status='doingbroadcastpow' '''
|
'''UPDATE sent SET status='doingbroadcastpow' '''
|
||||||
''' WHERE ackdata=? AND status='broadcastqueued' '''
|
''' WHERE ackdata=? AND status='broadcastqueued' '''
|
||||||
''' AND folder='sent' ''',
|
''' AND folder='sent' ''',
|
||||||
ackdata):
|
sqlite3.Binary(ackdata))
|
||||||
|
if rowcount < 1:
|
||||||
|
rowcount = sqlExecute(
|
||||||
|
'''UPDATE sent SET status='doingbroadcastpow' '''
|
||||||
|
''' WHERE ackdata=CAST(? AS TEXT) AND status='broadcastqueued' '''
|
||||||
|
''' AND folder='sent' ''',
|
||||||
|
ackdata)
|
||||||
|
if rowcount < 1:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# At this time these pubkeys are 65 bytes long
|
# At this time these pubkeys are 65 bytes long
|
||||||
|
@ -599,7 +625,7 @@ class singleWorker(StoppableThread):
|
||||||
TTL = int(TTL + helper_random.randomrandrange(-300, 300))
|
TTL = int(TTL + helper_random.randomrandrange(-300, 300))
|
||||||
embeddedTime = int(time.time() + TTL)
|
embeddedTime = int(time.time() + TTL)
|
||||||
payload = pack('>Q', embeddedTime)
|
payload = pack('>Q', embeddedTime)
|
||||||
payload += '\x00\x00\x00\x03' # object type: broadcast
|
payload += b'\x00\x00\x00\x03' # object type: broadcast
|
||||||
|
|
||||||
if addressVersionNumber <= 3:
|
if addressVersionNumber <= 3:
|
||||||
payload += encodeVarint(4) # broadcast version
|
payload += encodeVarint(4) # broadcast version
|
||||||
|
@ -615,7 +641,7 @@ class singleWorker(StoppableThread):
|
||||||
tag = doubleHashOfAddressData[32:]
|
tag = doubleHashOfAddressData[32:]
|
||||||
payload += tag
|
payload += tag
|
||||||
else:
|
else:
|
||||||
tag = ''
|
tag = b''
|
||||||
|
|
||||||
dataToEncrypt = encodeVarint(addressVersionNumber)
|
dataToEncrypt = encodeVarint(addressVersionNumber)
|
||||||
dataToEncrypt += encodeVarint(streamNumber)
|
dataToEncrypt += encodeVarint(streamNumber)
|
||||||
|
@ -697,16 +723,22 @@ class singleWorker(StoppableThread):
|
||||||
ackdata,
|
ackdata,
|
||||||
tr._translate(
|
tr._translate(
|
||||||
"MainWindow",
|
"MainWindow",
|
||||||
"Broadcast sent on %1"
|
"Broadcast sent on {0}"
|
||||||
).arg(l10n.formatTimestamp()))
|
).format(l10n.formatTimestamp()))
|
||||||
))
|
))
|
||||||
|
|
||||||
# Update the status of the message in the 'sent' table to have
|
# Update the status of the message in the 'sent' table to have
|
||||||
# a 'broadcastsent' status
|
# a 'broadcastsent' status
|
||||||
sqlExecute(
|
rowcount = sqlExecute(
|
||||||
'''UPDATE sent SET msgid=?, status=?, lastactiontime=? '''
|
'''UPDATE sent SET msgid=?, status=?, lastactiontime=? '''
|
||||||
''' WHERE ackdata=? AND folder='sent' ''',
|
''' WHERE ackdata=? AND folder='sent' ''',
|
||||||
inventoryHash, 'broadcastsent', int(time.time()), ackdata
|
sqlite3.Binary(inventoryHash), dbstr('broadcastsent'), int(time.time()), sqlite3.Binary(ackdata)
|
||||||
|
)
|
||||||
|
if rowcount < 1:
|
||||||
|
sqlExecute(
|
||||||
|
'''UPDATE sent SET msgid=?, status=?, lastactiontime=? '''
|
||||||
|
''' WHERE ackdata=CAST(? AS TEXT) AND folder='sent' ''',
|
||||||
|
sqlite3.Binary(inventoryHash), 'broadcastsent', int(time.time()), ackdata
|
||||||
)
|
)
|
||||||
|
|
||||||
def sendMsg(self):
|
def sendMsg(self):
|
||||||
|
@ -726,6 +758,11 @@ class singleWorker(StoppableThread):
|
||||||
for row in queryreturn:
|
for row in queryreturn:
|
||||||
toaddress, fromaddress, subject, message, \
|
toaddress, fromaddress, subject, message, \
|
||||||
ackdata, status, TTL, retryNumber, encoding = row
|
ackdata, status, TTL, retryNumber, encoding = row
|
||||||
|
toaddress = toaddress.decode("utf-8", "replace")
|
||||||
|
fromaddress = fromaddress.decode("utf-8", "replace")
|
||||||
|
subject = subject.decode("utf-8", "replace")
|
||||||
|
message = message.decode("utf-8", "replace")
|
||||||
|
status = status.decode("utf-8", "replace")
|
||||||
# toStatus
|
# toStatus
|
||||||
_, toAddressVersionNumber, toStreamNumber, toRipe = \
|
_, toAddressVersionNumber, toStreamNumber, toRipe = \
|
||||||
decodeAddress(toaddress)
|
decodeAddress(toaddress)
|
||||||
|
@ -755,7 +792,7 @@ class singleWorker(StoppableThread):
|
||||||
if not sqlExecute(
|
if not sqlExecute(
|
||||||
'''UPDATE sent SET status='doingmsgpow' '''
|
'''UPDATE sent SET status='doingmsgpow' '''
|
||||||
''' WHERE toaddress=? AND status='msgqueued' AND folder='sent' ''',
|
''' WHERE toaddress=? AND status='msgqueued' AND folder='sent' ''',
|
||||||
toaddress
|
dbstr(toaddress)
|
||||||
):
|
):
|
||||||
continue
|
continue
|
||||||
status = 'doingmsgpow'
|
status = 'doingmsgpow'
|
||||||
|
@ -763,7 +800,7 @@ class singleWorker(StoppableThread):
|
||||||
# Let's see if we already have the pubkey in our pubkeys table
|
# Let's see if we already have the pubkey in our pubkeys table
|
||||||
queryreturn = sqlQuery(
|
queryreturn = sqlQuery(
|
||||||
'''SELECT address FROM pubkeys WHERE address=?''',
|
'''SELECT address FROM pubkeys WHERE address=?''',
|
||||||
toaddress
|
dbstr(toaddress)
|
||||||
)
|
)
|
||||||
# If we have the needed pubkey in the pubkey table already,
|
# If we have the needed pubkey in the pubkey table already,
|
||||||
if queryreturn != []:
|
if queryreturn != []:
|
||||||
|
@ -771,7 +808,7 @@ class singleWorker(StoppableThread):
|
||||||
if not sqlExecute(
|
if not sqlExecute(
|
||||||
'''UPDATE sent SET status='doingmsgpow' '''
|
'''UPDATE sent SET status='doingmsgpow' '''
|
||||||
''' WHERE toaddress=? AND status='msgqueued' AND folder='sent' ''',
|
''' WHERE toaddress=? AND status='msgqueued' AND folder='sent' ''',
|
||||||
toaddress
|
dbstr(toaddress)
|
||||||
):
|
):
|
||||||
continue
|
continue
|
||||||
status = 'doingmsgpow'
|
status = 'doingmsgpow'
|
||||||
|
@ -783,26 +820,27 @@ class singleWorker(StoppableThread):
|
||||||
sqlExecute(
|
sqlExecute(
|
||||||
'''UPDATE pubkeys SET usedpersonally='yes' '''
|
'''UPDATE pubkeys SET usedpersonally='yes' '''
|
||||||
''' WHERE address=?''',
|
''' WHERE address=?''',
|
||||||
toaddress
|
dbstr(toaddress)
|
||||||
)
|
)
|
||||||
# We don't have the needed pubkey in the pubkeys table already.
|
# We don't have the needed pubkey in the pubkeys table already.
|
||||||
else:
|
else:
|
||||||
if toAddressVersionNumber <= 3:
|
if toAddressVersionNumber <= 3:
|
||||||
toTag = ''
|
toTag = b''
|
||||||
else:
|
else:
|
||||||
toTag = highlevelcrypto.double_sha512(
|
toTag = highlevelcrypto.double_sha512(
|
||||||
encodeVarint(toAddressVersionNumber)
|
encodeVarint(toAddressVersionNumber)
|
||||||
+ encodeVarint(toStreamNumber) + toRipe
|
+ encodeVarint(toStreamNumber) + toRipe
|
||||||
)[32:]
|
)[32:]
|
||||||
|
toTag_bytes = bytes(toTag)
|
||||||
if toaddress in state.neededPubkeys or \
|
if toaddress in state.neededPubkeys or \
|
||||||
toTag in state.neededPubkeys:
|
toTag_bytes in state.neededPubkeys:
|
||||||
# We already sent a request for the pubkey
|
# We already sent a request for the pubkey
|
||||||
sqlExecute(
|
sqlExecute(
|
||||||
'''UPDATE sent SET status='awaitingpubkey', '''
|
'''UPDATE sent SET status='awaitingpubkey', '''
|
||||||
''' sleeptill=? WHERE toaddress=? '''
|
''' sleeptill=? WHERE toaddress=? '''
|
||||||
''' AND status='msgqueued' ''',
|
''' AND status='msgqueued' ''',
|
||||||
int(time.time()) + 2.5 * 24 * 60 * 60,
|
int(time.time()) + 2.5 * 24 * 60 * 60,
|
||||||
toaddress
|
dbstr(toaddress)
|
||||||
)
|
)
|
||||||
queues.UISignalQueue.put((
|
queues.UISignalQueue.put((
|
||||||
'updateSentItemStatusByToAddress', (
|
'updateSentItemStatusByToAddress', (
|
||||||
|
@ -836,7 +874,8 @@ class singleWorker(StoppableThread):
|
||||||
privEncryptionKey = doubleHashOfToAddressData[:32]
|
privEncryptionKey = doubleHashOfToAddressData[:32]
|
||||||
# The second half of the sha512 hash.
|
# The second half of the sha512 hash.
|
||||||
tag = doubleHashOfToAddressData[32:]
|
tag = doubleHashOfToAddressData[32:]
|
||||||
state.neededPubkeys[tag] = (
|
tag_bytes = bytes(tag)
|
||||||
|
state.neededPubkeys[tag_bytes] = (
|
||||||
toaddress,
|
toaddress,
|
||||||
highlevelcrypto.makeCryptor(
|
highlevelcrypto.makeCryptor(
|
||||||
hexlify(privEncryptionKey))
|
hexlify(privEncryptionKey))
|
||||||
|
@ -858,8 +897,8 @@ class singleWorker(StoppableThread):
|
||||||
''' status='awaitingpubkey' or '''
|
''' status='awaitingpubkey' or '''
|
||||||
''' status='doingpubkeypow') AND '''
|
''' status='doingpubkeypow') AND '''
|
||||||
''' folder='sent' ''',
|
''' folder='sent' ''',
|
||||||
toaddress)
|
dbstr(toaddress))
|
||||||
del state.neededPubkeys[tag]
|
del state.neededPubkeys[tag_bytes]
|
||||||
break
|
break
|
||||||
# else:
|
# else:
|
||||||
# There was something wrong with this
|
# There was something wrong with this
|
||||||
|
@ -875,7 +914,7 @@ class singleWorker(StoppableThread):
|
||||||
'''UPDATE sent SET '''
|
'''UPDATE sent SET '''
|
||||||
''' status='doingpubkeypow' WHERE '''
|
''' status='doingpubkeypow' WHERE '''
|
||||||
''' toaddress=? AND status='msgqueued' AND folder='sent' ''',
|
''' toaddress=? AND status='msgqueued' AND folder='sent' ''',
|
||||||
toaddress
|
dbstr(toaddress)
|
||||||
)
|
)
|
||||||
queues.UISignalQueue.put((
|
queues.UISignalQueue.put((
|
||||||
'updateSentItemStatusByToAddress', (
|
'updateSentItemStatusByToAddress', (
|
||||||
|
@ -901,7 +940,7 @@ class singleWorker(StoppableThread):
|
||||||
|
|
||||||
# if we aren't sending this to ourselves or a chan
|
# if we aren't sending this to ourselves or a chan
|
||||||
if not config.has_section(toaddress):
|
if not config.has_section(toaddress):
|
||||||
state.ackdataForWhichImWatching[ackdata] = 0
|
state.ackdataForWhichImWatching[bytes(ackdata)] = 0
|
||||||
queues.UISignalQueue.put((
|
queues.UISignalQueue.put((
|
||||||
'updateSentItemStatusByAckdata', (
|
'updateSentItemStatusByAckdata', (
|
||||||
ackdata,
|
ackdata,
|
||||||
|
@ -920,7 +959,7 @@ class singleWorker(StoppableThread):
|
||||||
# is too hard then we'll abort.
|
# is too hard then we'll abort.
|
||||||
queryreturn = sqlQuery(
|
queryreturn = sqlQuery(
|
||||||
'SELECT transmitdata FROM pubkeys WHERE address=?',
|
'SELECT transmitdata FROM pubkeys WHERE address=?',
|
||||||
toaddress)
|
dbstr(toaddress))
|
||||||
for row in queryreturn: # pylint: disable=redefined-outer-name
|
for row in queryreturn: # pylint: disable=redefined-outer-name
|
||||||
pubkeyPayload, = row
|
pubkeyPayload, = row
|
||||||
|
|
||||||
|
@ -969,8 +1008,8 @@ class singleWorker(StoppableThread):
|
||||||
" device who requests that the"
|
" device who requests that the"
|
||||||
" destination be included in the"
|
" destination be included in the"
|
||||||
" message but this is disallowed in"
|
" message but this is disallowed in"
|
||||||
" your settings. %1"
|
" your settings. {0}"
|
||||||
).arg(l10n.formatTimestamp()))
|
).format(l10n.formatTimestamp()))
|
||||||
))
|
))
|
||||||
# if the human changes their setting and then
|
# if the human changes their setting and then
|
||||||
# sends another message or restarts their client,
|
# sends another message or restarts their client,
|
||||||
|
@ -1035,14 +1074,13 @@ class singleWorker(StoppableThread):
|
||||||
tr._translate(
|
tr._translate(
|
||||||
"MainWindow",
|
"MainWindow",
|
||||||
"Doing work necessary to send message.\n"
|
"Doing work necessary to send message.\n"
|
||||||
"Receiver\'s required difficulty: %1"
|
"Receiver\'s required difficulty: {0}"
|
||||||
" and %2"
|
" and {1}"
|
||||||
).arg(
|
).format(
|
||||||
str(
|
str(
|
||||||
float(requiredAverageProofOfWorkNonceTrialsPerByte)
|
float(requiredAverageProofOfWorkNonceTrialsPerByte)
|
||||||
/ defaults.networkDefaultProofOfWorkNonceTrialsPerByte
|
/ defaults.networkDefaultProofOfWorkNonceTrialsPerByte
|
||||||
)
|
),
|
||||||
).arg(
|
|
||||||
str(
|
str(
|
||||||
float(requiredPayloadLengthExtraBytes)
|
float(requiredPayloadLengthExtraBytes)
|
||||||
/ defaults.networkDefaultPayloadLengthExtraBytes
|
/ defaults.networkDefaultPayloadLengthExtraBytes
|
||||||
|
@ -1065,9 +1103,14 @@ class singleWorker(StoppableThread):
|
||||||
if cond1 or cond2:
|
if cond1 or cond2:
|
||||||
# The demanded difficulty is more than
|
# The demanded difficulty is more than
|
||||||
# we are willing to do.
|
# we are willing to do.
|
||||||
sqlExecute(
|
rowcount = sqlExecute(
|
||||||
'''UPDATE sent SET status='toodifficult' '''
|
'''UPDATE sent SET status='toodifficult' '''
|
||||||
''' WHERE ackdata=? AND folder='sent' ''',
|
''' WHERE ackdata=? AND folder='sent' ''',
|
||||||
|
sqlite3.Binary(ackdata))
|
||||||
|
if rowcount < 1:
|
||||||
|
sqlExecute(
|
||||||
|
'''UPDATE sent SET status='toodifficult' '''
|
||||||
|
''' WHERE ackdata=CAST(? AS TEXT) AND folder='sent' ''',
|
||||||
ackdata)
|
ackdata)
|
||||||
queues.UISignalQueue.put((
|
queues.UISignalQueue.put((
|
||||||
'updateSentItemStatusByAckdata', (
|
'updateSentItemStatusByAckdata', (
|
||||||
|
@ -1075,14 +1118,14 @@ class singleWorker(StoppableThread):
|
||||||
tr._translate(
|
tr._translate(
|
||||||
"MainWindow",
|
"MainWindow",
|
||||||
"Problem: The work demanded by"
|
"Problem: The work demanded by"
|
||||||
" the recipient (%1 and %2) is"
|
" the recipient ({0} and {1}) is"
|
||||||
" more difficult than you are"
|
" more difficult than you are"
|
||||||
" willing to do. %3"
|
" willing to do. {2}"
|
||||||
).arg(str(float(requiredAverageProofOfWorkNonceTrialsPerByte)
|
).format(str(float(requiredAverageProofOfWorkNonceTrialsPerByte)
|
||||||
/ defaults.networkDefaultProofOfWorkNonceTrialsPerByte)
|
/ defaults.networkDefaultProofOfWorkNonceTrialsPerByte),
|
||||||
).arg(str(float(requiredPayloadLengthExtraBytes)
|
str(float(requiredPayloadLengthExtraBytes)
|
||||||
/ defaults.networkDefaultPayloadLengthExtraBytes)
|
/ defaults.networkDefaultPayloadLengthExtraBytes),
|
||||||
).arg(l10n.formatTimestamp()))))
|
l10n.formatTimestamp()))))
|
||||||
continue
|
continue
|
||||||
else: # if we are sending a message to ourselves or a chan..
|
else: # if we are sending a message to ourselves or a chan..
|
||||||
self.logger.info('Sending a message.')
|
self.logger.info('Sending a message.')
|
||||||
|
@ -1103,8 +1146,8 @@ class singleWorker(StoppableThread):
|
||||||
" message to yourself or a chan but your"
|
" message to yourself or a chan but your"
|
||||||
" encryption key could not be found in"
|
" encryption key could not be found in"
|
||||||
" the keys.dat file. Could not encrypt"
|
" the keys.dat file. Could not encrypt"
|
||||||
" message. %1"
|
" message. {0}"
|
||||||
).arg(l10n.formatTimestamp()))
|
).format(l10n.formatTimestamp()))
|
||||||
))
|
))
|
||||||
self.logger.error(
|
self.logger.error(
|
||||||
'Error within sendMsg. Could not read the keys'
|
'Error within sendMsg. Could not read the keys'
|
||||||
|
@ -1201,14 +1244,14 @@ class singleWorker(StoppableThread):
|
||||||
'Not bothering to include ackdata because we are'
|
'Not bothering to include ackdata because we are'
|
||||||
' sending to ourselves or a chan.'
|
' sending to ourselves or a chan.'
|
||||||
)
|
)
|
||||||
fullAckPayload = ''
|
fullAckPayload = b''
|
||||||
elif not protocol.checkBitfield(
|
elif not protocol.checkBitfield(
|
||||||
behaviorBitfield, protocol.BITFIELD_DOESACK):
|
behaviorBitfield, protocol.BITFIELD_DOESACK):
|
||||||
self.logger.info(
|
self.logger.info(
|
||||||
'Not bothering to include ackdata because'
|
'Not bothering to include ackdata because'
|
||||||
' the receiver said that they won\'t relay it anyway.'
|
' the receiver said that they won\'t relay it anyway.'
|
||||||
)
|
)
|
||||||
fullAckPayload = ''
|
fullAckPayload = b''
|
||||||
else:
|
else:
|
||||||
# The fullAckPayload is a normal msg protocol message
|
# The fullAckPayload is a normal msg protocol message
|
||||||
# with the proof of work already completed that the
|
# with the proof of work already completed that the
|
||||||
|
@ -1217,7 +1260,7 @@ class singleWorker(StoppableThread):
|
||||||
ackdata, toStreamNumber, TTL)
|
ackdata, toStreamNumber, TTL)
|
||||||
payload += encodeVarint(len(fullAckPayload))
|
payload += encodeVarint(len(fullAckPayload))
|
||||||
payload += fullAckPayload
|
payload += fullAckPayload
|
||||||
dataToSign = pack('>Q', embeddedTime) + '\x00\x00\x00\x02' + \
|
dataToSign = pack('>Q', embeddedTime) + b'\x00\x00\x00\x02' + \
|
||||||
encodeVarint(1) + encodeVarint(toStreamNumber) + payload
|
encodeVarint(1) + encodeVarint(toStreamNumber) + payload
|
||||||
signature = highlevelcrypto.sign(
|
signature = highlevelcrypto.sign(
|
||||||
dataToSign, privSigningKeyHex, self.digestAlg)
|
dataToSign, privSigningKeyHex, self.digestAlg)
|
||||||
|
@ -1227,12 +1270,17 @@ class singleWorker(StoppableThread):
|
||||||
# We have assembled the data that will be encrypted.
|
# We have assembled the data that will be encrypted.
|
||||||
try:
|
try:
|
||||||
encrypted = highlevelcrypto.encrypt(
|
encrypted = highlevelcrypto.encrypt(
|
||||||
payload, "04" + hexlify(pubEncryptionKeyBase256)
|
payload, b"04" + hexlify(pubEncryptionKeyBase256)
|
||||||
)
|
)
|
||||||
except: # noqa:E722
|
except: # noqa:E722
|
||||||
self.logger.warning("highlevelcrypto.encrypt didn't work")
|
self.logger.warning("highlevelcrypto.encrypt didn't work")
|
||||||
sqlExecute(
|
rowcount = sqlExecute(
|
||||||
'''UPDATE sent SET status='badkey' WHERE ackdata=? AND folder='sent' ''',
|
'''UPDATE sent SET status='badkey' WHERE ackdata=? AND folder='sent' ''',
|
||||||
|
sqlite3.Binary(ackdata)
|
||||||
|
)
|
||||||
|
if rowcount < 1:
|
||||||
|
sqlExecute(
|
||||||
|
'''UPDATE sent SET status='badkey' WHERE ackdata=CAST(? AS TEXT) AND folder='sent' ''',
|
||||||
ackdata
|
ackdata
|
||||||
)
|
)
|
||||||
queues.UISignalQueue.put((
|
queues.UISignalQueue.put((
|
||||||
|
@ -1241,13 +1289,13 @@ class singleWorker(StoppableThread):
|
||||||
tr._translate(
|
tr._translate(
|
||||||
"MainWindow",
|
"MainWindow",
|
||||||
"Problem: The recipient\'s encryption key is"
|
"Problem: The recipient\'s encryption key is"
|
||||||
" no good. Could not encrypt message. %1"
|
" no good. Could not encrypt message. {0}"
|
||||||
).arg(l10n.formatTimestamp()))
|
).format(l10n.formatTimestamp()))
|
||||||
))
|
))
|
||||||
continue
|
continue
|
||||||
|
|
||||||
encryptedPayload = pack('>Q', embeddedTime)
|
encryptedPayload = pack('>Q', embeddedTime)
|
||||||
encryptedPayload += '\x00\x00\x00\x02' # object type: msg
|
encryptedPayload += b'\x00\x00\x00\x02' # object type: msg
|
||||||
encryptedPayload += encodeVarint(1) # msg version
|
encryptedPayload += encodeVarint(1) # msg version
|
||||||
encryptedPayload += encodeVarint(toStreamNumber) + encrypted
|
encryptedPayload += encodeVarint(toStreamNumber) + encrypted
|
||||||
target = 2 ** 64 / (
|
target = 2 ** 64 / (
|
||||||
|
@ -1309,8 +1357,8 @@ class singleWorker(StoppableThread):
|
||||||
ackdata,
|
ackdata,
|
||||||
tr._translate(
|
tr._translate(
|
||||||
"MainWindow",
|
"MainWindow",
|
||||||
"Message sent. Sent at %1"
|
"Message sent. Sent at {0}"
|
||||||
).arg(l10n.formatTimestamp()))))
|
).format(l10n.formatTimestamp()))))
|
||||||
else:
|
else:
|
||||||
# not sending to a chan or one of my addresses
|
# not sending to a chan or one of my addresses
|
||||||
queues.UISignalQueue.put((
|
queues.UISignalQueue.put((
|
||||||
|
@ -1319,8 +1367,8 @@ class singleWorker(StoppableThread):
|
||||||
tr._translate(
|
tr._translate(
|
||||||
"MainWindow",
|
"MainWindow",
|
||||||
"Message sent. Waiting for acknowledgement."
|
"Message sent. Waiting for acknowledgement."
|
||||||
" Sent on %1"
|
" Sent on {0}"
|
||||||
).arg(l10n.formatTimestamp()))
|
).format(l10n.formatTimestamp()))
|
||||||
))
|
))
|
||||||
self.logger.info(
|
self.logger.info(
|
||||||
'Broadcasting inv for my msg(within sendmsg function): %s',
|
'Broadcasting inv for my msg(within sendmsg function): %s',
|
||||||
|
@ -1337,10 +1385,17 @@ class singleWorker(StoppableThread):
|
||||||
newStatus = 'msgsent'
|
newStatus = 'msgsent'
|
||||||
# wait 10% past expiration
|
# wait 10% past expiration
|
||||||
sleepTill = int(time.time() + TTL * 1.1)
|
sleepTill = int(time.time() + TTL * 1.1)
|
||||||
sqlExecute(
|
rowcount = sqlExecute(
|
||||||
'''UPDATE sent SET msgid=?, status=?, retrynumber=?, '''
|
'''UPDATE sent SET msgid=?, status=?, retrynumber=?, '''
|
||||||
''' sleeptill=?, lastactiontime=? WHERE ackdata=? AND folder='sent' ''',
|
''' sleeptill=?, lastactiontime=? WHERE ackdata=? AND folder='sent' ''',
|
||||||
inventoryHash, newStatus, retryNumber + 1,
|
sqlite3.Binary(inventoryHash), dbstr(newStatus), retryNumber + 1,
|
||||||
|
sleepTill, int(time.time()), sqlite3.Binary(ackdata)
|
||||||
|
)
|
||||||
|
if rowcount < 1:
|
||||||
|
sqlExecute(
|
||||||
|
'''UPDATE sent SET msgid=?, status=?, retrynumber=?, '''
|
||||||
|
''' sleeptill=?, lastactiontime=? WHERE ackdata=CAST(? AS TEXT) AND folder='sent' ''',
|
||||||
|
sqlite3.Binary(inventoryHash), newStatus, retryNumber + 1,
|
||||||
sleepTill, int(time.time()), ackdata
|
sleepTill, int(time.time()), ackdata
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -1386,7 +1441,7 @@ class singleWorker(StoppableThread):
|
||||||
'''SELECT retrynumber FROM sent WHERE toaddress=? '''
|
'''SELECT retrynumber FROM sent WHERE toaddress=? '''
|
||||||
''' AND (status='doingpubkeypow' OR status='awaitingpubkey') '''
|
''' AND (status='doingpubkeypow' OR status='awaitingpubkey') '''
|
||||||
''' AND folder='sent' LIMIT 1''',
|
''' AND folder='sent' LIMIT 1''',
|
||||||
toAddress
|
dbstr(toAddress)
|
||||||
)
|
)
|
||||||
if not queryReturn:
|
if not queryReturn:
|
||||||
self.logger.critical(
|
self.logger.critical(
|
||||||
|
@ -1412,10 +1467,11 @@ class singleWorker(StoppableThread):
|
||||||
privEncryptionKey = doubleHashOfAddressData[:32]
|
privEncryptionKey = doubleHashOfAddressData[:32]
|
||||||
# Note that this is the second half of the sha512 hash.
|
# Note that this is the second half of the sha512 hash.
|
||||||
tag = doubleHashOfAddressData[32:]
|
tag = doubleHashOfAddressData[32:]
|
||||||
if tag not in state.neededPubkeys:
|
tag_bytes = bytes(tag)
|
||||||
|
if tag_bytes not in state.neededPubkeys:
|
||||||
# We'll need this for when we receive a pubkey reply:
|
# We'll need this for when we receive a pubkey reply:
|
||||||
# it will be encrypted and we'll need to decrypt it.
|
# it will be encrypted and we'll need to decrypt it.
|
||||||
state.neededPubkeys[tag] = (
|
state.neededPubkeys[tag_bytes] = (
|
||||||
toAddress,
|
toAddress,
|
||||||
highlevelcrypto.makeCryptor(hexlify(privEncryptionKey))
|
highlevelcrypto.makeCryptor(hexlify(privEncryptionKey))
|
||||||
)
|
)
|
||||||
|
@ -1429,7 +1485,7 @@ class singleWorker(StoppableThread):
|
||||||
TTL = TTL + helper_random.randomrandrange(-300, 300)
|
TTL = TTL + helper_random.randomrandrange(-300, 300)
|
||||||
embeddedTime = int(time.time() + TTL)
|
embeddedTime = int(time.time() + TTL)
|
||||||
payload = pack('>Q', embeddedTime)
|
payload = pack('>Q', embeddedTime)
|
||||||
payload += '\x00\x00\x00\x00' # object type: getpubkey
|
payload += b'\x00\x00\x00\x00' # object type: getpubkey
|
||||||
payload += encodeVarint(addressVersionNumber)
|
payload += encodeVarint(addressVersionNumber)
|
||||||
payload += encodeVarint(streamNumber)
|
payload += encodeVarint(streamNumber)
|
||||||
if addressVersionNumber <= 3:
|
if addressVersionNumber <= 3:
|
||||||
|
@ -1468,7 +1524,7 @@ class singleWorker(StoppableThread):
|
||||||
''' status='awaitingpubkey', retrynumber=?, sleeptill=? '''
|
''' status='awaitingpubkey', retrynumber=?, sleeptill=? '''
|
||||||
''' WHERE toaddress=? AND (status='doingpubkeypow' OR '''
|
''' WHERE toaddress=? AND (status='doingpubkeypow' OR '''
|
||||||
''' status='awaitingpubkey') AND folder='sent' ''',
|
''' status='awaitingpubkey') AND folder='sent' ''',
|
||||||
int(time.time()), retryNumber + 1, sleeptill, toAddress)
|
int(time.time()), retryNumber + 1, sleeptill, dbstr(toAddress))
|
||||||
|
|
||||||
queues.UISignalQueue.put((
|
queues.UISignalQueue.put((
|
||||||
'updateStatusBar',
|
'updateStatusBar',
|
||||||
|
@ -1483,8 +1539,8 @@ class singleWorker(StoppableThread):
|
||||||
tr._translate(
|
tr._translate(
|
||||||
"MainWindow",
|
"MainWindow",
|
||||||
"Sending public key request. Waiting for reply."
|
"Sending public key request. Waiting for reply."
|
||||||
" Requested at %1"
|
" Requested at {0}"
|
||||||
).arg(l10n.formatTimestamp()))
|
).format(l10n.formatTimestamp()))
|
||||||
))
|
))
|
||||||
|
|
||||||
def generateFullAckMessage(self, ackdata, _, TTL):
|
def generateFullAckMessage(self, ackdata, _, TTL):
|
||||||
|
@ -1511,4 +1567,4 @@ class singleWorker(StoppableThread):
|
||||||
payload = self._doPOWDefaults(
|
payload = self._doPOWDefaults(
|
||||||
payload, TTL, log_prefix='(For ack message)', log_time=True)
|
payload, TTL, log_prefix='(For ack message)', log_time=True)
|
||||||
|
|
||||||
return protocol.CreatePacket('object', payload)
|
return protocol.CreatePacket(b'object', payload)
|
||||||
|
|
|
@ -4,9 +4,9 @@ SMTP client thread for delivering emails
|
||||||
# pylint: disable=unused-variable
|
# pylint: disable=unused-variable
|
||||||
|
|
||||||
import smtplib
|
import smtplib
|
||||||
import urlparse
|
from six.moves.urllib import parse as urlparse
|
||||||
from email.header import Header
|
from email.header import Header
|
||||||
from email.mime.text import MIMEText
|
from six.moves import email_mime_text
|
||||||
|
|
||||||
import queues
|
import queues
|
||||||
import state
|
import state
|
||||||
|
@ -55,7 +55,7 @@ class smtpDeliver(StoppableThread):
|
||||||
u = urlparse.urlparse(dest)
|
u = urlparse.urlparse(dest)
|
||||||
to = urlparse.parse_qs(u.query)['to']
|
to = urlparse.parse_qs(u.query)['to']
|
||||||
client = smtplib.SMTP(u.hostname, u.port)
|
client = smtplib.SMTP(u.hostname, u.port)
|
||||||
msg = MIMEText(body, 'plain', 'utf-8')
|
msg = email_mime_text(body, 'plain', 'utf-8')
|
||||||
msg['Subject'] = Header(subject, 'utf-8')
|
msg['Subject'] = Header(subject, 'utf-8')
|
||||||
msg['From'] = fromAddress + '@' + SMTPDOMAIN
|
msg['From'] = fromAddress + '@' + SMTPDOMAIN
|
||||||
toLabel = map(
|
toLabel = map(
|
||||||
|
|
|
@ -12,6 +12,7 @@ import threading
|
||||||
import time
|
import time
|
||||||
from email.header import decode_header
|
from email.header import decode_header
|
||||||
from email.parser import Parser
|
from email.parser import Parser
|
||||||
|
import sqlite3
|
||||||
|
|
||||||
import queues
|
import queues
|
||||||
from addresses import decodeAddress
|
from addresses import decodeAddress
|
||||||
|
@ -20,6 +21,7 @@ from helper_ackPayload import genAckPayload
|
||||||
from helper_sql import sqlExecute
|
from helper_sql import sqlExecute
|
||||||
from network.threads import StoppableThread
|
from network.threads import StoppableThread
|
||||||
from version import softwareVersion
|
from version import softwareVersion
|
||||||
|
from dbcompat import dbstr
|
||||||
|
|
||||||
SMTPDOMAIN = "bmaddr.lan"
|
SMTPDOMAIN = "bmaddr.lan"
|
||||||
LISTENPORT = 8425
|
LISTENPORT = 8425
|
||||||
|
@ -88,19 +90,19 @@ class smtpServerPyBitmessage(smtpd.SMTPServer):
|
||||||
ackdata = genAckPayload(streamNumber, stealthLevel)
|
ackdata = genAckPayload(streamNumber, stealthLevel)
|
||||||
sqlExecute(
|
sqlExecute(
|
||||||
'''INSERT INTO sent VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)''',
|
'''INSERT INTO sent VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)''',
|
||||||
'',
|
sqlite3.Binary(b''),
|
||||||
toAddress,
|
dbstr(toAddress),
|
||||||
ripe,
|
sqlite3.Binary(ripe),
|
||||||
fromAddress,
|
dbstr(fromAddress),
|
||||||
subject,
|
dbstr(subject),
|
||||||
message,
|
dbstr(message),
|
||||||
ackdata,
|
sqlite3.Binary(ackdata),
|
||||||
int(time.time()), # sentTime (this will never change)
|
int(time.time()), # sentTime (this will never change)
|
||||||
int(time.time()), # lastActionTime
|
int(time.time()), # lastActionTime
|
||||||
0, # sleepTill time. This will get set when the POW gets done.
|
0, # sleepTill time. This will get set when the POW gets done.
|
||||||
'msgqueued',
|
dbstr('msgqueued'),
|
||||||
0, # retryNumber
|
0, # retryNumber
|
||||||
'sent', # folder
|
dbstr('sent'), # folder
|
||||||
2, # encodingtype
|
2, # encodingtype
|
||||||
# not necessary to have a TTL higher than 2 days
|
# not necessary to have a TTL higher than 2 days
|
||||||
min(config.getint('bitmessagesettings', 'ttl'), 86400 * 2)
|
min(config.getint('bitmessagesettings', 'ttl'), 86400 * 2)
|
||||||
|
|
|
@ -8,6 +8,7 @@ import sqlite3
|
||||||
import sys
|
import sys
|
||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
|
from six.moves.reprlib import repr
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import helper_sql
|
import helper_sql
|
||||||
|
@ -38,7 +39,7 @@ class sqlThread(threading.Thread):
|
||||||
helper_sql.sql_available = True
|
helper_sql.sql_available = True
|
||||||
config_ready.wait()
|
config_ready.wait()
|
||||||
self.conn = sqlite3.connect(state.appdata + 'messages.dat')
|
self.conn = sqlite3.connect(state.appdata + 'messages.dat')
|
||||||
self.conn.text_factory = str
|
self.conn.text_factory = bytes
|
||||||
self.cur = self.conn.cursor()
|
self.cur = self.conn.cursor()
|
||||||
|
|
||||||
self.cur.execute('PRAGMA secure_delete = true')
|
self.cur.execute('PRAGMA secure_delete = true')
|
||||||
|
@ -73,7 +74,7 @@ class sqlThread(threading.Thread):
|
||||||
'''INSERT INTO subscriptions VALUES'''
|
'''INSERT INTO subscriptions VALUES'''
|
||||||
'''('Bitmessage new releases/announcements','BM-GtovgYdgs7qXPkoYaRgrLFuFKz1SFpsw',1)''')
|
'''('Bitmessage new releases/announcements','BM-GtovgYdgs7qXPkoYaRgrLFuFKz1SFpsw',1)''')
|
||||||
self.cur.execute(
|
self.cur.execute(
|
||||||
'''CREATE TABLE settings (key blob, value blob, UNIQUE(key) ON CONFLICT REPLACE)''')
|
'''CREATE TABLE settings (key text, value blob, UNIQUE(key) ON CONFLICT REPLACE)''')
|
||||||
self.cur.execute('''INSERT INTO settings VALUES('version','11')''')
|
self.cur.execute('''INSERT INTO settings VALUES('version','11')''')
|
||||||
self.cur.execute('''INSERT INTO settings VALUES('lastvacuumtime',?)''', (
|
self.cur.execute('''INSERT INTO settings VALUES('lastvacuumtime',?)''', (
|
||||||
int(time.time()),))
|
int(time.time()),))
|
||||||
|
@ -542,7 +543,7 @@ class sqlThread(threading.Thread):
|
||||||
shutil.move(
|
shutil.move(
|
||||||
paths.lookupAppdataFolder() + 'messages.dat', paths.lookupExeFolder() + 'messages.dat')
|
paths.lookupAppdataFolder() + 'messages.dat', paths.lookupExeFolder() + 'messages.dat')
|
||||||
self.conn = sqlite3.connect(paths.lookupExeFolder() + 'messages.dat')
|
self.conn = sqlite3.connect(paths.lookupExeFolder() + 'messages.dat')
|
||||||
self.conn.text_factory = str
|
self.conn.text_factory = bytes
|
||||||
self.cur = self.conn.cursor()
|
self.cur = self.conn.cursor()
|
||||||
elif item == 'movemessagstoappdata':
|
elif item == 'movemessagstoappdata':
|
||||||
logger.debug('the sqlThread is moving the messages.dat file to the Appdata folder.')
|
logger.debug('the sqlThread is moving the messages.dat file to the Appdata folder.')
|
||||||
|
@ -568,7 +569,7 @@ class sqlThread(threading.Thread):
|
||||||
shutil.move(
|
shutil.move(
|
||||||
paths.lookupExeFolder() + 'messages.dat', paths.lookupAppdataFolder() + 'messages.dat')
|
paths.lookupExeFolder() + 'messages.dat', paths.lookupAppdataFolder() + 'messages.dat')
|
||||||
self.conn = sqlite3.connect(paths.lookupAppdataFolder() + 'messages.dat')
|
self.conn = sqlite3.connect(paths.lookupAppdataFolder() + 'messages.dat')
|
||||||
self.conn.text_factory = str
|
self.conn.text_factory = bytes
|
||||||
self.cur = self.conn.cursor()
|
self.cur = self.conn.cursor()
|
||||||
elif item == 'deleteandvacuume':
|
elif item == 'deleteandvacuume':
|
||||||
self.cur.execute('''delete from inbox where folder='trash' ''')
|
self.cur.execute('''delete from inbox where folder='trash' ''')
|
||||||
|
|
22
src/dbcompat.py
Normal file
22
src/dbcompat.py
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
import logging
|
||||||
|
import six
|
||||||
|
|
||||||
|
logger = logging.getLogger("default")
|
||||||
|
|
||||||
|
def dbstr(v):
|
||||||
|
if six.PY3:
|
||||||
|
if isinstance(v, str):
|
||||||
|
return v
|
||||||
|
elif isinstance(v, bytes):
|
||||||
|
return v.decode("utf-8", "replace")
|
||||||
|
logger.debug("unexpected type in dbstr(): {}".format(type(v)))
|
||||||
|
return v # hope this never happens..
|
||||||
|
else: # assume six.PY2
|
||||||
|
if isinstance(v, unicode):
|
||||||
|
return v.encode("utf-8", "replace")
|
||||||
|
elif isinstance(v, str):
|
||||||
|
return v
|
||||||
|
elif isinstance(v, bytes):
|
||||||
|
return str(v)
|
||||||
|
logger.debug("unexpected type in dbstr(): {}".format(type(v)))
|
||||||
|
return v # hope this never happens..
|
|
@ -6,6 +6,7 @@ and suggest how it may be installed
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
|
import six
|
||||||
|
|
||||||
# Only really old versions of Python don't have sys.hexversion. We don't
|
# Only really old versions of Python don't have sys.hexversion. We don't
|
||||||
# support them. The logging module was introduced in Python 2.3
|
# support them. The logging module was introduced in Python 2.3
|
||||||
|
@ -383,6 +384,15 @@ def check_pyqt():
|
||||||
Here we are checking for PyQt4 with its version, as for it require
|
Here we are checking for PyQt4 with its version, as for it require
|
||||||
PyQt 4.8 or later.
|
PyQt 4.8 or later.
|
||||||
"""
|
"""
|
||||||
|
sip_found = False
|
||||||
|
try:
|
||||||
|
import sip
|
||||||
|
sip.setapi("QString", 2)
|
||||||
|
sip.setapi("QVariant", 2)
|
||||||
|
sip_found = True
|
||||||
|
except ImportError:
|
||||||
|
pass
|
||||||
|
|
||||||
QtCore = try_import(
|
QtCore = try_import(
|
||||||
'PyQt4.QtCore', 'PyBitmessage requires PyQt 4.8 or later and Qt 4.7 or later.')
|
'PyQt4.QtCore', 'PyBitmessage requires PyQt 4.8 or later and Qt 4.7 or later.')
|
||||||
|
|
||||||
|
@ -402,6 +412,11 @@ def check_pyqt():
|
||||||
'This version of Qt is too old. PyBitmessage requries'
|
'This version of Qt is too old. PyBitmessage requries'
|
||||||
' Qt 4.7 or later.')
|
' Qt 4.7 or later.')
|
||||||
passed = False
|
passed = False
|
||||||
|
|
||||||
|
if passed and not sip_found:
|
||||||
|
logger.info("sip is not found although PyQt is found")
|
||||||
|
return False
|
||||||
|
|
||||||
return passed
|
return passed
|
||||||
|
|
||||||
|
|
||||||
|
@ -435,14 +450,9 @@ def check_dependencies(verbose=False, optional=False):
|
||||||
logger.info('Python version: %s', sys.version)
|
logger.info('Python version: %s', sys.version)
|
||||||
if sys.hexversion < 0x20704F0:
|
if sys.hexversion < 0x20704F0:
|
||||||
logger.error(
|
logger.error(
|
||||||
'PyBitmessage requires Python 2.7.4 or greater'
|
'PyBitmessage requires Python 2.7.4 or greater.'
|
||||||
' (but not Python 3+)')
|
' Python 2.7.18 is recommended.')
|
||||||
has_all_dependencies = False
|
has_all_dependencies = False
|
||||||
if sys.hexversion >= 0x3000000:
|
|
||||||
logger.error(
|
|
||||||
'PyBitmessage does not support Python 3+. Python 2.7.4'
|
|
||||||
' or greater is required. Python 2.7.18 is recommended.')
|
|
||||||
sys.exit()
|
|
||||||
|
|
||||||
# FIXME: This needs to be uncommented when more of the code is python3 compatible
|
# FIXME: This needs to be uncommented when more of the code is python3 compatible
|
||||||
# if sys.hexversion >= 0x3000000 and sys.hexversion < 0x3060000:
|
# if sys.hexversion >= 0x3000000 and sys.hexversion < 0x3060000:
|
||||||
|
|
|
@ -49,10 +49,12 @@ License: MIT
|
||||||
# pylint: disable=too-many-lines,too-many-branches,too-many-statements,global-statement,too-many-return-statements
|
# pylint: disable=too-many-lines,too-many-branches,too-many-statements,global-statement,too-many-return-statements
|
||||||
# pylint: disable=unused-argument
|
# pylint: disable=unused-argument
|
||||||
|
|
||||||
import collections
|
from collections import OrderedDict
|
||||||
import io
|
from six.moves.collections_abc import Hashable
|
||||||
|
from six.moves import range as xrange
|
||||||
import struct
|
import struct
|
||||||
import sys
|
import sys
|
||||||
|
import six
|
||||||
|
|
||||||
__version__ = "2.4.1"
|
__version__ = "2.4.1"
|
||||||
"Module version string"
|
"Module version string"
|
||||||
|
@ -99,9 +101,9 @@ class Ext: # pylint: disable=old-style-class
|
||||||
if not isinstance(type, int) or not (type >= 0 and type <= 127):
|
if not isinstance(type, int) or not (type >= 0 and type <= 127):
|
||||||
raise TypeError("ext type out of range")
|
raise TypeError("ext type out of range")
|
||||||
# Check data is type bytes
|
# Check data is type bytes
|
||||||
elif sys.version_info[0] == 3 and not isinstance(data, bytes):
|
elif six.PY3 and not isinstance(data, bytes):
|
||||||
raise TypeError("ext data is not type \'bytes\'")
|
raise TypeError("ext data is not type \'bytes\'")
|
||||||
elif sys.version_info[0] == 2 and not isinstance(data, str):
|
elif six.PY2 and not isinstance(data, str):
|
||||||
raise TypeError("ext data is not type \'str\'")
|
raise TypeError("ext data is not type \'str\'")
|
||||||
self.type = type
|
self.type = type
|
||||||
self.data = data
|
self.data = data
|
||||||
|
@ -125,7 +127,7 @@ class Ext: # pylint: disable=old-style-class
|
||||||
String representation of this Ext object.
|
String representation of this Ext object.
|
||||||
"""
|
"""
|
||||||
s = "Ext Object (Type: 0x%02x, Data: " % self.type
|
s = "Ext Object (Type: 0x%02x, Data: " % self.type
|
||||||
s += " ".join(["0x%02x" % ord(self.data[i:i + 1])
|
s += " ".join(["0x%02x" % six.byte2int(self.data[i:i + 1])
|
||||||
for i in xrange(min(len(self.data), 8))])
|
for i in xrange(min(len(self.data), 8))])
|
||||||
if len(self.data) > 8:
|
if len(self.data) > 8:
|
||||||
s += " ..."
|
s += " ..."
|
||||||
|
@ -549,7 +551,7 @@ def _packb2(obj, **options):
|
||||||
'\x82\xa7compact\xc3\xa6schema\x00'
|
'\x82\xa7compact\xc3\xa6schema\x00'
|
||||||
>>>
|
>>>
|
||||||
"""
|
"""
|
||||||
fp = io.BytesIO()
|
fp = six.BytesIO()
|
||||||
_pack2(obj, fp, **options)
|
_pack2(obj, fp, **options)
|
||||||
return fp.getvalue()
|
return fp.getvalue()
|
||||||
|
|
||||||
|
@ -582,7 +584,7 @@ def _packb3(obj, **options):
|
||||||
b'\x82\xa7compact\xc3\xa6schema\x00'
|
b'\x82\xa7compact\xc3\xa6schema\x00'
|
||||||
>>>
|
>>>
|
||||||
"""
|
"""
|
||||||
fp = io.BytesIO()
|
fp = six.BytesIO()
|
||||||
_pack3(obj, fp, **options)
|
_pack3(obj, fp, **options)
|
||||||
return fp.getvalue()
|
return fp.getvalue()
|
||||||
|
|
||||||
|
@ -599,7 +601,7 @@ def _read_except(fp, n):
|
||||||
|
|
||||||
|
|
||||||
def _unpack_integer(code, fp, options):
|
def _unpack_integer(code, fp, options):
|
||||||
if (ord(code) & 0xe0) == 0xe0:
|
if (six.byte2int(code) & 0xe0) == 0xe0:
|
||||||
return struct.unpack("b", code)[0]
|
return struct.unpack("b", code)[0]
|
||||||
elif code == b'\xd0':
|
elif code == b'\xd0':
|
||||||
return struct.unpack("b", _read_except(fp, 1))[0]
|
return struct.unpack("b", _read_except(fp, 1))[0]
|
||||||
|
@ -609,7 +611,7 @@ def _unpack_integer(code, fp, options):
|
||||||
return struct.unpack(">i", _read_except(fp, 4))[0]
|
return struct.unpack(">i", _read_except(fp, 4))[0]
|
||||||
elif code == b'\xd3':
|
elif code == b'\xd3':
|
||||||
return struct.unpack(">q", _read_except(fp, 8))[0]
|
return struct.unpack(">q", _read_except(fp, 8))[0]
|
||||||
elif (ord(code) & 0x80) == 0x00:
|
elif (six.byte2int(code) & 0x80) == 0x00:
|
||||||
return struct.unpack("B", code)[0]
|
return struct.unpack("B", code)[0]
|
||||||
elif code == b'\xcc':
|
elif code == b'\xcc':
|
||||||
return struct.unpack("B", _read_except(fp, 1))[0]
|
return struct.unpack("B", _read_except(fp, 1))[0]
|
||||||
|
@ -619,21 +621,21 @@ def _unpack_integer(code, fp, options):
|
||||||
return struct.unpack(">I", _read_except(fp, 4))[0]
|
return struct.unpack(">I", _read_except(fp, 4))[0]
|
||||||
elif code == b'\xcf':
|
elif code == b'\xcf':
|
||||||
return struct.unpack(">Q", _read_except(fp, 8))[0]
|
return struct.unpack(">Q", _read_except(fp, 8))[0]
|
||||||
raise Exception("logic error, not int: 0x%02x" % ord(code))
|
raise Exception("logic error, not int: 0x%02x" % six.byte2int(code))
|
||||||
|
|
||||||
|
|
||||||
def _unpack_reserved(code, fp, options):
|
def _unpack_reserved(code, fp, options):
|
||||||
if code == b'\xc1':
|
if code == b'\xc1':
|
||||||
raise ReservedCodeException(
|
raise ReservedCodeException(
|
||||||
"encountered reserved code: 0x%02x" % ord(code))
|
"encountered reserved code: 0x%02x" % six.byte2int(code))
|
||||||
raise Exception(
|
raise Exception(
|
||||||
"logic error, not reserved code: 0x%02x" % ord(code))
|
"logic error, not reserved code: 0x%02x" % six.byte2int(code))
|
||||||
|
|
||||||
|
|
||||||
def _unpack_nil(code, fp, options):
|
def _unpack_nil(code, fp, options):
|
||||||
if code == b'\xc0':
|
if code == b'\xc0':
|
||||||
return None
|
return None
|
||||||
raise Exception("logic error, not nil: 0x%02x" % ord(code))
|
raise Exception("logic error, not nil: 0x%02x" % six.byte2int(code))
|
||||||
|
|
||||||
|
|
||||||
def _unpack_boolean(code, fp, options):
|
def _unpack_boolean(code, fp, options):
|
||||||
|
@ -641,7 +643,7 @@ def _unpack_boolean(code, fp, options):
|
||||||
return False
|
return False
|
||||||
elif code == b'\xc3':
|
elif code == b'\xc3':
|
||||||
return True
|
return True
|
||||||
raise Exception("logic error, not boolean: 0x%02x" % ord(code))
|
raise Exception("logic error, not boolean: 0x%02x" % six.byte2int(code))
|
||||||
|
|
||||||
|
|
||||||
def _unpack_float(code, fp, options):
|
def _unpack_float(code, fp, options):
|
||||||
|
@ -649,12 +651,12 @@ def _unpack_float(code, fp, options):
|
||||||
return struct.unpack(">f", _read_except(fp, 4))[0]
|
return struct.unpack(">f", _read_except(fp, 4))[0]
|
||||||
elif code == b'\xcb':
|
elif code == b'\xcb':
|
||||||
return struct.unpack(">d", _read_except(fp, 8))[0]
|
return struct.unpack(">d", _read_except(fp, 8))[0]
|
||||||
raise Exception("logic error, not float: 0x%02x" % ord(code))
|
raise Exception("logic error, not float: 0x%02x" % six.byte2int(code))
|
||||||
|
|
||||||
|
|
||||||
def _unpack_string(code, fp, options):
|
def _unpack_string(code, fp, options):
|
||||||
if (ord(code) & 0xe0) == 0xa0:
|
if (six.byte2int(code) & 0xe0) == 0xa0:
|
||||||
length = ord(code) & ~0xe0
|
length = six.byte2int(code) & ~0xe0
|
||||||
elif code == b'\xd9':
|
elif code == b'\xd9':
|
||||||
length = struct.unpack("B", _read_except(fp, 1))[0]
|
length = struct.unpack("B", _read_except(fp, 1))[0]
|
||||||
elif code == b'\xda':
|
elif code == b'\xda':
|
||||||
|
@ -662,7 +664,7 @@ def _unpack_string(code, fp, options):
|
||||||
elif code == b'\xdb':
|
elif code == b'\xdb':
|
||||||
length = struct.unpack(">I", _read_except(fp, 4))[0]
|
length = struct.unpack(">I", _read_except(fp, 4))[0]
|
||||||
else:
|
else:
|
||||||
raise Exception("logic error, not string: 0x%02x" % ord(code))
|
raise Exception("logic error, not string: 0x%02x" % six.byte2int(code))
|
||||||
|
|
||||||
# Always return raw bytes in compatibility mode
|
# Always return raw bytes in compatibility mode
|
||||||
global compatibility
|
global compatibility
|
||||||
|
@ -686,7 +688,7 @@ def _unpack_binary(code, fp, options):
|
||||||
elif code == b'\xc6':
|
elif code == b'\xc6':
|
||||||
length = struct.unpack(">I", _read_except(fp, 4))[0]
|
length = struct.unpack(">I", _read_except(fp, 4))[0]
|
||||||
else:
|
else:
|
||||||
raise Exception("logic error, not binary: 0x%02x" % ord(code))
|
raise Exception("logic error, not binary: 0x%02x" % six.byte2int(code))
|
||||||
|
|
||||||
return _read_except(fp, length)
|
return _read_except(fp, length)
|
||||||
|
|
||||||
|
@ -709,9 +711,9 @@ def _unpack_ext(code, fp, options):
|
||||||
elif code == b'\xc9':
|
elif code == b'\xc9':
|
||||||
length = struct.unpack(">I", _read_except(fp, 4))[0]
|
length = struct.unpack(">I", _read_except(fp, 4))[0]
|
||||||
else:
|
else:
|
||||||
raise Exception("logic error, not ext: 0x%02x" % ord(code))
|
raise Exception("logic error, not ext: 0x%02x" % six.byte2int(code))
|
||||||
|
|
||||||
ext = Ext(ord(_read_except(fp, 1)), _read_except(fp, length))
|
ext = Ext(six.byte2int(_read_except(fp, 1)), _read_except(fp, length))
|
||||||
|
|
||||||
# Unpack with ext handler, if we have one
|
# Unpack with ext handler, if we have one
|
||||||
ext_handlers = options.get("ext_handlers")
|
ext_handlers = options.get("ext_handlers")
|
||||||
|
@ -722,14 +724,14 @@ def _unpack_ext(code, fp, options):
|
||||||
|
|
||||||
|
|
||||||
def _unpack_array(code, fp, options):
|
def _unpack_array(code, fp, options):
|
||||||
if (ord(code) & 0xf0) == 0x90:
|
if (six.byte2int(code) & 0xf0) == 0x90:
|
||||||
length = (ord(code) & ~0xf0)
|
length = (six.byte2int(code) & ~0xf0)
|
||||||
elif code == b'\xdc':
|
elif code == b'\xdc':
|
||||||
length = struct.unpack(">H", _read_except(fp, 2))[0]
|
length = struct.unpack(">H", _read_except(fp, 2))[0]
|
||||||
elif code == b'\xdd':
|
elif code == b'\xdd':
|
||||||
length = struct.unpack(">I", _read_except(fp, 4))[0]
|
length = struct.unpack(">I", _read_except(fp, 4))[0]
|
||||||
else:
|
else:
|
||||||
raise Exception("logic error, not array: 0x%02x" % ord(code))
|
raise Exception("logic error, not array: 0x%02x" % six.byte2int(code))
|
||||||
|
|
||||||
return [_unpack(fp, options) for _ in xrange(length)]
|
return [_unpack(fp, options) for _ in xrange(length)]
|
||||||
|
|
||||||
|
@ -741,17 +743,17 @@ def _deep_list_to_tuple(obj):
|
||||||
|
|
||||||
|
|
||||||
def _unpack_map(code, fp, options):
|
def _unpack_map(code, fp, options):
|
||||||
if (ord(code) & 0xf0) == 0x80:
|
if (six.byte2int(code) & 0xf0) == 0x80:
|
||||||
length = (ord(code) & ~0xf0)
|
length = (six.byte2int(code) & ~0xf0)
|
||||||
elif code == b'\xde':
|
elif code == b'\xde':
|
||||||
length = struct.unpack(">H", _read_except(fp, 2))[0]
|
length = struct.unpack(">H", _read_except(fp, 2))[0]
|
||||||
elif code == b'\xdf':
|
elif code == b'\xdf':
|
||||||
length = struct.unpack(">I", _read_except(fp, 4))[0]
|
length = struct.unpack(">I", _read_except(fp, 4))[0]
|
||||||
else:
|
else:
|
||||||
raise Exception("logic error, not map: 0x%02x" % ord(code))
|
raise Exception("logic error, not map: 0x%02x" % six.byte2int(code))
|
||||||
|
|
||||||
d = {} if not options.get('use_ordered_dict') \
|
d = {} if not options.get('use_ordered_dict') \
|
||||||
else collections.OrderedDict()
|
else OrderedDict()
|
||||||
for _ in xrange(length):
|
for _ in xrange(length):
|
||||||
# Unpack key
|
# Unpack key
|
||||||
k = _unpack(fp, options)
|
k = _unpack(fp, options)
|
||||||
|
@ -759,7 +761,7 @@ def _unpack_map(code, fp, options):
|
||||||
if isinstance(k, list):
|
if isinstance(k, list):
|
||||||
# Attempt to convert list into a hashable tuple
|
# Attempt to convert list into a hashable tuple
|
||||||
k = _deep_list_to_tuple(k)
|
k = _deep_list_to_tuple(k)
|
||||||
elif not isinstance(k, collections.Hashable):
|
elif not isinstance(k, Hashable):
|
||||||
raise UnhashableKeyException(
|
raise UnhashableKeyException(
|
||||||
"encountered unhashable key: %s, %s" % (str(k), str(type(k))))
|
"encountered unhashable key: %s, %s" % (str(k), str(type(k))))
|
||||||
elif k in d:
|
elif k in d:
|
||||||
|
@ -911,7 +913,7 @@ def _unpackb2(s, **options):
|
||||||
"""
|
"""
|
||||||
if not isinstance(s, (str, bytearray)):
|
if not isinstance(s, (str, bytearray)):
|
||||||
raise TypeError("packed data must be type 'str' or 'bytearray'")
|
raise TypeError("packed data must be type 'str' or 'bytearray'")
|
||||||
return _unpack(io.BytesIO(s), options)
|
return _unpack(six.BytesIO(s), options)
|
||||||
|
|
||||||
|
|
||||||
# For Python 3, expects a bytes object
|
# For Python 3, expects a bytes object
|
||||||
|
@ -957,7 +959,7 @@ def _unpackb3(s, **options):
|
||||||
"""
|
"""
|
||||||
if not isinstance(s, (bytes, bytearray)):
|
if not isinstance(s, (bytes, bytearray)):
|
||||||
raise TypeError("packed data must be type 'bytes' or 'bytearray'")
|
raise TypeError("packed data must be type 'bytes' or 'bytearray'")
|
||||||
return _unpack(io.BytesIO(s), options)
|
return _unpack(six.BytesIO(s), options)
|
||||||
|
|
||||||
#############################################################################
|
#############################################################################
|
||||||
# Module Initialization
|
# Module Initialization
|
||||||
|
@ -990,7 +992,7 @@ def __init():
|
||||||
_float_precision = "single"
|
_float_precision = "single"
|
||||||
|
|
||||||
# Map packb and unpackb to the appropriate version
|
# Map packb and unpackb to the appropriate version
|
||||||
if sys.version_info[0] == 3:
|
if six.PY3:
|
||||||
pack = _pack3
|
pack = _pack3
|
||||||
packb = _packb3
|
packb = _packb3
|
||||||
dump = _pack3
|
dump = _pack3
|
||||||
|
|
|
@ -4,11 +4,12 @@ Insert value into addressbook
|
||||||
|
|
||||||
from bmconfigparser import config
|
from bmconfigparser import config
|
||||||
from helper_sql import sqlExecute
|
from helper_sql import sqlExecute
|
||||||
|
from dbcompat import dbstr
|
||||||
|
|
||||||
|
|
||||||
def insert(address, label):
|
def insert(address, label):
|
||||||
"""perform insert into addressbook"""
|
"""perform insert into addressbook"""
|
||||||
|
|
||||||
if address not in config.addresses():
|
if address not in config.addresses():
|
||||||
return sqlExecute('''INSERT INTO addressbook VALUES (?,?)''', label, address) == 1
|
return sqlExecute('''INSERT INTO addressbook VALUES (?,?)''', dbstr(label), dbstr(address)) == 1
|
||||||
return False
|
return False
|
||||||
|
|
|
@ -19,17 +19,17 @@ def calculateBitcoinAddressFromPubkey(pubkey):
|
||||||
sha = hashlib.new('sha256')
|
sha = hashlib.new('sha256')
|
||||||
sha.update(pubkey)
|
sha.update(pubkey)
|
||||||
ripe.update(sha.digest())
|
ripe.update(sha.digest())
|
||||||
ripeWithProdnetPrefix = '\x00' + ripe.digest()
|
ripeWithProdnetPrefix = b'\x00' + ripe.digest()
|
||||||
|
|
||||||
checksum = hashlib.sha256(hashlib.sha256(
|
checksum = hashlib.sha256(hashlib.sha256(
|
||||||
ripeWithProdnetPrefix).digest()).digest()[:4]
|
ripeWithProdnetPrefix).digest()).digest()[:4]
|
||||||
binaryBitcoinAddress = ripeWithProdnetPrefix + checksum
|
binaryBitcoinAddress = ripeWithProdnetPrefix + checksum
|
||||||
numberOfZeroBytesOnBinaryBitcoinAddress = 0
|
numberOfZeroBytesOnBinaryBitcoinAddress = 0
|
||||||
while binaryBitcoinAddress[0] == '\x00':
|
while binaryBitcoinAddress[0] == b'\x00':
|
||||||
numberOfZeroBytesOnBinaryBitcoinAddress += 1
|
numberOfZeroBytesOnBinaryBitcoinAddress += 1
|
||||||
binaryBitcoinAddress = binaryBitcoinAddress[1:]
|
binaryBitcoinAddress = binaryBitcoinAddress[1:]
|
||||||
base58encoded = arithmetic.changebase(binaryBitcoinAddress, 256, 58)
|
base58encoded = arithmetic.changebase(binaryBitcoinAddress, 256, 58)
|
||||||
return "1" * numberOfZeroBytesOnBinaryBitcoinAddress + base58encoded
|
return b"1" * numberOfZeroBytesOnBinaryBitcoinAddress + base58encoded
|
||||||
|
|
||||||
|
|
||||||
def calculateTestnetAddressFromPubkey(pubkey):
|
def calculateTestnetAddressFromPubkey(pubkey):
|
||||||
|
@ -43,14 +43,14 @@ def calculateTestnetAddressFromPubkey(pubkey):
|
||||||
sha = hashlib.new('sha256')
|
sha = hashlib.new('sha256')
|
||||||
sha.update(pubkey)
|
sha.update(pubkey)
|
||||||
ripe.update(sha.digest())
|
ripe.update(sha.digest())
|
||||||
ripeWithProdnetPrefix = '\x6F' + ripe.digest()
|
ripeWithProdnetPrefix = b'\x6F' + ripe.digest()
|
||||||
|
|
||||||
checksum = hashlib.sha256(hashlib.sha256(
|
checksum = hashlib.sha256(hashlib.sha256(
|
||||||
ripeWithProdnetPrefix).digest()).digest()[:4]
|
ripeWithProdnetPrefix).digest()).digest()[:4]
|
||||||
binaryBitcoinAddress = ripeWithProdnetPrefix + checksum
|
binaryBitcoinAddress = ripeWithProdnetPrefix + checksum
|
||||||
numberOfZeroBytesOnBinaryBitcoinAddress = 0
|
numberOfZeroBytesOnBinaryBitcoinAddress = 0
|
||||||
while binaryBitcoinAddress[0] == '\x00':
|
while binaryBitcoinAddress[0] == b'\x00':
|
||||||
numberOfZeroBytesOnBinaryBitcoinAddress += 1
|
numberOfZeroBytesOnBinaryBitcoinAddress += 1
|
||||||
binaryBitcoinAddress = binaryBitcoinAddress[1:]
|
binaryBitcoinAddress = binaryBitcoinAddress[1:]
|
||||||
base58encoded = arithmetic.changebase(binaryBitcoinAddress, 256, 58)
|
base58encoded = arithmetic.changebase(binaryBitcoinAddress, 256, 58)
|
||||||
return "1" * numberOfZeroBytesOnBinaryBitcoinAddress + base58encoded
|
return b"1" * numberOfZeroBytesOnBinaryBitcoinAddress + base58encoded
|
||||||
|
|
|
@ -1,12 +1,16 @@
|
||||||
"""Helper Inbox performs inbox messages related operations"""
|
"""Helper Inbox performs inbox messages related operations"""
|
||||||
|
|
||||||
|
import sqlite3
|
||||||
|
|
||||||
import queues
|
import queues
|
||||||
from helper_sql import sqlExecute, sqlQuery
|
from helper_sql import sqlExecute, sqlQuery
|
||||||
|
from dbcompat import dbstr
|
||||||
|
|
||||||
|
|
||||||
def insert(t):
|
def insert(t):
|
||||||
"""Perform an insert into the "inbox" table"""
|
"""Perform an insert into the "inbox" table"""
|
||||||
sqlExecute('''INSERT INTO inbox VALUES (?,?,?,?,?,?,?,?,?,?)''', *t)
|
u = [sqlite3.Binary(t[0]), dbstr(t[1]), dbstr(t[2]), dbstr(t[3]), dbstr(t[4]), dbstr(t[5]), dbstr(t[6]), t[7], t[8], sqlite3.Binary(t[9])]
|
||||||
|
sqlExecute('''INSERT INTO inbox VALUES (?,?,?,?,?,?,?,?,?,?)''', *u)
|
||||||
# shouldn't emit changedInboxUnread and displayNewInboxMessage
|
# shouldn't emit changedInboxUnread and displayNewInboxMessage
|
||||||
# at the same time
|
# at the same time
|
||||||
# queues.UISignalQueue.put(('changedInboxUnread', None))
|
# queues.UISignalQueue.put(('changedInboxUnread', None))
|
||||||
|
@ -14,22 +18,31 @@ def insert(t):
|
||||||
|
|
||||||
def trash(msgid):
|
def trash(msgid):
|
||||||
"""Mark a message in the `inbox` as `trash`"""
|
"""Mark a message in the `inbox` as `trash`"""
|
||||||
sqlExecute('''UPDATE inbox SET folder='trash' WHERE msgid=?''', msgid)
|
rowcount = sqlExecute('''UPDATE inbox SET folder='trash' WHERE msgid=?''', sqlite3.Binary(msgid))
|
||||||
|
if rowcount < 1:
|
||||||
|
sqlExecute('''UPDATE inbox SET folder='trash' WHERE msgid=CAST(? AS TEXT)''', msgid)
|
||||||
queues.UISignalQueue.put(('removeInboxRowByMsgid', msgid))
|
queues.UISignalQueue.put(('removeInboxRowByMsgid', msgid))
|
||||||
|
|
||||||
|
|
||||||
def delete(ack_data):
|
def delete(ack_data):
|
||||||
"""Permanent delete message from trash"""
|
"""Permanent delete message from trash"""
|
||||||
sqlExecute("DELETE FROM inbox WHERE msgid = ?", ack_data)
|
rowcount = sqlExecute("DELETE FROM inbox WHERE msgid = ?", sqlite3.Binary(ack_data))
|
||||||
|
if rowcount < 1:
|
||||||
|
sqlExecute("DELETE FROM inbox WHERE msgid = CAST(? AS TEXT)", ack_data)
|
||||||
|
|
||||||
|
|
||||||
def undeleteMessage(msgid):
|
def undeleteMessage(msgid):
|
||||||
"""Undelte the message"""
|
"""Undelte the message"""
|
||||||
sqlExecute('''UPDATE inbox SET folder='inbox' WHERE msgid=?''', msgid)
|
rowcount = sqlExecute('''UPDATE inbox SET folder='inbox' WHERE msgid=?''', sqlite3.Binary(msgid))
|
||||||
|
if rowcount < 1:
|
||||||
|
sqlExecute('''UPDATE inbox SET folder='inbox' WHERE msgid=CAST(? AS TEXT)''', msgid)
|
||||||
|
|
||||||
|
|
||||||
def isMessageAlreadyInInbox(sigHash):
|
def isMessageAlreadyInInbox(sigHash):
|
||||||
"""Check for previous instances of this message"""
|
"""Check for previous instances of this message"""
|
||||||
queryReturn = sqlQuery(
|
queryReturn = sqlQuery(
|
||||||
'''SELECT COUNT(*) FROM inbox WHERE sighash=?''', sigHash)
|
'''SELECT COUNT(*) FROM inbox WHERE sighash=?''', sqlite3.Binary(sigHash))
|
||||||
|
if len(queryReturn) < 1:
|
||||||
|
queryReturn = sqlQuery(
|
||||||
|
'''SELECT COUNT(*) FROM inbox WHERE sighash=CAST(? AS TEXT)''', sigHash)
|
||||||
return queryReturn[0][0] != 0
|
return queryReturn[0][0] != 0
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
Message encoding end decoding functions
|
Message encoding end decoding functions
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import string
|
|
||||||
import zlib
|
import zlib
|
||||||
|
|
||||||
import messagetypes
|
import messagetypes
|
||||||
|
@ -71,7 +70,8 @@ class MsgEncode(object):
|
||||||
|
|
||||||
def encodeSimple(self, message):
|
def encodeSimple(self, message):
|
||||||
"""Handle simple encoding"""
|
"""Handle simple encoding"""
|
||||||
self.data = 'Subject:%(subject)s\nBody:%(body)s' % message
|
data = 'Subject:%(subject)s\nBody:%(body)s' % message
|
||||||
|
self.data = data.encode("utf-8", "replace")
|
||||||
self.length = len(self.data)
|
self.length = len(self.data)
|
||||||
|
|
||||||
def encodeTrivial(self, message):
|
def encodeTrivial(self, message):
|
||||||
|
@ -99,14 +99,14 @@ class MsgDecode(object):
|
||||||
def decodeExtended(self, data):
|
def decodeExtended(self, data):
|
||||||
"""Handle extended encoding"""
|
"""Handle extended encoding"""
|
||||||
dc = zlib.decompressobj()
|
dc = zlib.decompressobj()
|
||||||
tmp = ""
|
tmp = b""
|
||||||
while len(tmp) <= config.safeGetInt("zlib", "maxsize"):
|
while len(tmp) <= config.safeGetInt("zlib", "maxsize"):
|
||||||
try:
|
try:
|
||||||
got = dc.decompress(
|
got = dc.decompress(
|
||||||
data, config.safeGetInt("zlib", "maxsize")
|
data, config.safeGetInt("zlib", "maxsize")
|
||||||
+ 1 - len(tmp))
|
+ 1 - len(tmp))
|
||||||
# EOF
|
# EOF
|
||||||
if got == "":
|
if got == b"":
|
||||||
break
|
break
|
||||||
tmp += got
|
tmp += got
|
||||||
data = dc.unconsumed_tail
|
data = dc.unconsumed_tail
|
||||||
|
@ -142,7 +142,7 @@ class MsgDecode(object):
|
||||||
|
|
||||||
def decodeSimple(self, data):
|
def decodeSimple(self, data):
|
||||||
"""Handle simple encoding"""
|
"""Handle simple encoding"""
|
||||||
bodyPositionIndex = string.find(data, '\nBody:')
|
bodyPositionIndex = data.find(b'\nBody:')
|
||||||
if bodyPositionIndex > 1:
|
if bodyPositionIndex > 1:
|
||||||
subject = data[8:bodyPositionIndex]
|
subject = data[8:bodyPositionIndex]
|
||||||
# Only save and show the first 500 characters of the subject.
|
# Only save and show the first 500 characters of the subject.
|
||||||
|
@ -150,10 +150,10 @@ class MsgDecode(object):
|
||||||
subject = subject[:500]
|
subject = subject[:500]
|
||||||
body = data[bodyPositionIndex + 6:]
|
body = data[bodyPositionIndex + 6:]
|
||||||
else:
|
else:
|
||||||
subject = ''
|
subject = b''
|
||||||
body = data
|
body = data
|
||||||
# Throw away any extra lines (headers) after the subject.
|
# Throw away any extra lines (headers) after the subject.
|
||||||
if subject:
|
if subject:
|
||||||
subject = subject.splitlines()[0]
|
subject = subject.splitlines()[0]
|
||||||
self.subject = subject
|
self.subject = subject.decode("utf-8", "replace")
|
||||||
self.body = body
|
self.body = body.decode("utf-8", "replace")
|
||||||
|
|
|
@ -5,6 +5,7 @@ Used by :mod:`.bitmessageqt`.
|
||||||
|
|
||||||
from helper_sql import sqlQuery
|
from helper_sql import sqlQuery
|
||||||
from tr import _translate
|
from tr import _translate
|
||||||
|
from dbcompat import dbstr
|
||||||
|
|
||||||
|
|
||||||
def search_sql(
|
def search_sql(
|
||||||
|
@ -52,23 +53,23 @@ def search_sql(
|
||||||
if account is not None:
|
if account is not None:
|
||||||
if xAddress == 'both':
|
if xAddress == 'both':
|
||||||
sqlStatementParts.append('(fromaddress = ? OR toaddress = ?)')
|
sqlStatementParts.append('(fromaddress = ? OR toaddress = ?)')
|
||||||
sqlArguments.append(account)
|
sqlArguments.append(dbstr(account))
|
||||||
sqlArguments.append(account)
|
sqlArguments.append(dbstr(account))
|
||||||
else:
|
else:
|
||||||
sqlStatementParts.append(xAddress + ' = ? ')
|
sqlStatementParts.append(xAddress + ' = ? ')
|
||||||
sqlArguments.append(account)
|
sqlArguments.append(dbstr(account))
|
||||||
if folder is not None:
|
if folder is not None:
|
||||||
if folder == 'new':
|
if folder == 'new':
|
||||||
folder = 'inbox'
|
folder = 'inbox'
|
||||||
unreadOnly = True
|
unreadOnly = True
|
||||||
sqlStatementParts.append('folder = ? ')
|
sqlStatementParts.append('folder = ? ')
|
||||||
sqlArguments.append(folder)
|
sqlArguments.append(dbstr(folder))
|
||||||
else:
|
else:
|
||||||
sqlStatementParts.append('folder != ?')
|
sqlStatementParts.append('folder != ?')
|
||||||
sqlArguments.append('trash')
|
sqlArguments.append(dbstr('trash'))
|
||||||
if what:
|
if what:
|
||||||
sqlStatementParts.append('%s LIKE ?' % (where))
|
sqlStatementParts.append('%s LIKE ?' % (where))
|
||||||
sqlArguments.append(what)
|
sqlArguments.append(dbstr(what))
|
||||||
if unreadOnly:
|
if unreadOnly:
|
||||||
sqlStatementParts.append('read = 0')
|
sqlStatementParts.append('read = 0')
|
||||||
if sqlStatementParts:
|
if sqlStatementParts:
|
||||||
|
|
|
@ -4,10 +4,12 @@ Insert values into sent table
|
||||||
|
|
||||||
import time
|
import time
|
||||||
import uuid
|
import uuid
|
||||||
|
import sqlite3
|
||||||
from addresses import decodeAddress
|
from addresses import decodeAddress
|
||||||
from bmconfigparser import config
|
from bmconfigparser import config
|
||||||
from helper_ackPayload import genAckPayload
|
from helper_ackPayload import genAckPayload
|
||||||
from helper_sql import sqlExecute, sqlQuery
|
from helper_sql import sqlExecute, sqlQuery
|
||||||
|
from dbcompat import dbstr
|
||||||
|
|
||||||
|
|
||||||
# pylint: disable=too-many-arguments
|
# pylint: disable=too-many-arguments
|
||||||
|
@ -38,8 +40,8 @@ def insert(msgid=None, toAddress='[Broadcast subscribers]', fromAddress=None, su
|
||||||
|
|
||||||
ttl = ttl if ttl else config.getint('bitmessagesettings', 'ttl')
|
ttl = ttl if ttl else config.getint('bitmessagesettings', 'ttl')
|
||||||
|
|
||||||
t = (msgid, toAddress, ripe, fromAddress, subject, message, ackdata,
|
t = (sqlite3.Binary(msgid), dbstr(toAddress), sqlite3.Binary(ripe), dbstr(fromAddress), dbstr(subject), dbstr(message), sqlite3.Binary(ackdata),
|
||||||
sentTime, lastActionTime, sleeptill, status, retryNumber, folder,
|
sentTime, lastActionTime, sleeptill, dbstr(status), retryNumber, dbstr(folder),
|
||||||
encoding, ttl)
|
encoding, ttl)
|
||||||
|
|
||||||
sqlExecute('''INSERT INTO sent VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)''', *t)
|
sqlExecute('''INSERT INTO sent VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)''', *t)
|
||||||
|
@ -50,13 +52,19 @@ def insert(msgid=None, toAddress='[Broadcast subscribers]', fromAddress=None, su
|
||||||
|
|
||||||
def delete(ack_data):
|
def delete(ack_data):
|
||||||
"""Perform Delete query"""
|
"""Perform Delete query"""
|
||||||
sqlExecute("DELETE FROM sent WHERE ackdata = ?", ack_data)
|
rowcount = sqlExecute("DELETE FROM sent WHERE ackdata = ?", sqlite3.Binary(ack_data))
|
||||||
|
if rowcount < 1:
|
||||||
|
sqlExecute("DELETE FROM sent WHERE ackdata = CAST(? AS TEXT)", ack_data)
|
||||||
|
|
||||||
|
|
||||||
def retrieve_message_details(ack_data):
|
def retrieve_message_details(ack_data):
|
||||||
"""Retrieving Message details"""
|
"""Retrieving Message details"""
|
||||||
data = sqlQuery(
|
data = sqlQuery(
|
||||||
"select toaddress, fromaddress, subject, message, received from inbox where msgid = ?", ack_data
|
"select toaddress, fromaddress, subject, message, received from inbox where msgid = ?", sqlite3.Binary(ack_data)
|
||||||
|
)
|
||||||
|
if len(data) < 1:
|
||||||
|
data = sqlQuery(
|
||||||
|
"select toaddress, fromaddress, subject, message, received from inbox where msgid = CAST(? AS TEXT)", ack_data
|
||||||
)
|
)
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
@ -64,6 +72,10 @@ def retrieve_message_details(ack_data):
|
||||||
def trash(ackdata):
|
def trash(ackdata):
|
||||||
"""Mark a message in the `sent` as `trash`"""
|
"""Mark a message in the `sent` as `trash`"""
|
||||||
rowcount = sqlExecute(
|
rowcount = sqlExecute(
|
||||||
'''UPDATE sent SET folder='trash' WHERE ackdata=?''', ackdata
|
'''UPDATE sent SET folder='trash' WHERE ackdata=?''', sqlite3.Binary(ackdata)
|
||||||
|
)
|
||||||
|
if rowcount < 1:
|
||||||
|
rowcount = sqlExecute(
|
||||||
|
'''UPDATE sent SET folder='trash' WHERE ackdata=CAST(? AS TEXT)''', ackdata
|
||||||
)
|
)
|
||||||
return rowcount
|
return rowcount
|
||||||
|
|
|
@ -61,7 +61,7 @@ def sqlQuery(sql_statement, *args):
|
||||||
return queryreturn
|
return queryreturn
|
||||||
|
|
||||||
|
|
||||||
def sqlExecuteChunked(sql_statement, idCount, *args):
|
def sqlExecuteChunked(sql_statement, as_text, idCount, *args):
|
||||||
"""Execute chunked SQL statement to avoid argument limit"""
|
"""Execute chunked SQL statement to avoid argument limit"""
|
||||||
# SQLITE_MAX_VARIABLE_NUMBER,
|
# SQLITE_MAX_VARIABLE_NUMBER,
|
||||||
# unfortunately getting/setting isn't exposed to python
|
# unfortunately getting/setting isn't exposed to python
|
||||||
|
@ -80,6 +80,15 @@ def sqlExecuteChunked(sql_statement, idCount, *args):
|
||||||
chunk_slice = args[
|
chunk_slice = args[
|
||||||
i:i + sqlExecuteChunked.chunkSize - (len(args) - idCount)
|
i:i + sqlExecuteChunked.chunkSize - (len(args) - idCount)
|
||||||
]
|
]
|
||||||
|
if as_text:
|
||||||
|
q = ""
|
||||||
|
n = len(chunk_slice)
|
||||||
|
for i in range(n):
|
||||||
|
q += "CAST(? AS TEXT)"
|
||||||
|
if i != n - 1:
|
||||||
|
q += ","
|
||||||
|
sqlSubmitQueue.put(sql_statement.format(q))
|
||||||
|
else:
|
||||||
sqlSubmitQueue.put(
|
sqlSubmitQueue.put(
|
||||||
sql_statement.format(','.join('?' * len(chunk_slice)))
|
sql_statement.format(','.join('?' * len(chunk_slice)))
|
||||||
)
|
)
|
||||||
|
|
|
@ -7,6 +7,8 @@ High level cryptographic functions based on `.pyelliptic` OpenSSL bindings.
|
||||||
`More discussion. <https://github.com/yann2192/pyelliptic/issues/32>`_
|
`More discussion. <https://github.com/yann2192/pyelliptic/issues/32>`_
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
from unqstr import unic
|
||||||
|
|
||||||
import hashlib
|
import hashlib
|
||||||
import os
|
import os
|
||||||
from binascii import hexlify
|
from binascii import hexlify
|
||||||
|
@ -102,7 +104,7 @@ def random_keys():
|
||||||
|
|
||||||
def deterministic_keys(passphrase, nonce):
|
def deterministic_keys(passphrase, nonce):
|
||||||
"""Generate keys from *passphrase* and *nonce* (encoded as varint)"""
|
"""Generate keys from *passphrase* and *nonce* (encoded as varint)"""
|
||||||
priv = hashlib.sha512(passphrase + nonce).digest()[:32]
|
priv = hashlib.sha512(unic(passphrase).encode("utf-8", "replace") + nonce).digest()[:32]
|
||||||
pub = pointMult(priv)
|
pub = pointMult(priv)
|
||||||
return priv, pub
|
return priv, pub
|
||||||
|
|
||||||
|
|
|
@ -28,8 +28,6 @@ class Inventory:
|
||||||
|
|
||||||
# cheap inheritance copied from asyncore
|
# cheap inheritance copied from asyncore
|
||||||
def __getattr__(self, attr):
|
def __getattr__(self, attr):
|
||||||
if attr == "__contains__":
|
|
||||||
self.numberOfInventoryLookupsPerformed += 1
|
|
||||||
try:
|
try:
|
||||||
realRet = getattr(self._realInventory, attr)
|
realRet = getattr(self._realInventory, attr)
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
|
@ -40,6 +38,10 @@ class Inventory:
|
||||||
else:
|
else:
|
||||||
return realRet
|
return realRet
|
||||||
|
|
||||||
|
def __contains__(self, key):
|
||||||
|
self.numberOfInventoryLookupsPerformed += 1
|
||||||
|
return key in self._realInventory
|
||||||
|
|
||||||
# hint for pylint: this is dictionary like object
|
# hint for pylint: this is dictionary like object
|
||||||
def __getitem__(self, key):
|
def __getitem__(self, key):
|
||||||
return self._realInventory[key]
|
return self._realInventory[key]
|
||||||
|
|
|
@ -3,8 +3,8 @@
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import sys
|
|
||||||
import time
|
import time
|
||||||
|
import six
|
||||||
|
|
||||||
from six.moves import range
|
from six.moves import range
|
||||||
|
|
||||||
|
@ -61,7 +61,7 @@ if not re.search(r'\d', time.strftime(time_format)):
|
||||||
|
|
||||||
# It seems some systems lie about the encoding they use
|
# It seems some systems lie about the encoding they use
|
||||||
# so we perform comprehensive decoding tests
|
# so we perform comprehensive decoding tests
|
||||||
elif sys.version_info[0] == 2:
|
elif six.PY2:
|
||||||
try:
|
try:
|
||||||
# Check day names
|
# Check day names
|
||||||
for i in range(7):
|
for i in range(7):
|
||||||
|
@ -118,7 +118,7 @@ def formatTimestamp(timestamp=None):
|
||||||
except ValueError:
|
except ValueError:
|
||||||
timestring = time.strftime(time_format)
|
timestring = time.strftime(time_format)
|
||||||
|
|
||||||
if sys.version_info[0] == 2:
|
if six.PY2:
|
||||||
return timestring.decode(encoding)
|
return timestring.decode(encoding)
|
||||||
return timestring
|
return timestring
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ Namecoin queries
|
||||||
# pylint: disable=too-many-branches,protected-access
|
# pylint: disable=too-many-branches,protected-access
|
||||||
|
|
||||||
import base64
|
import base64
|
||||||
import httplib
|
from six.moves import http_client as httplib
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
import socket
|
import socket
|
||||||
|
@ -96,8 +96,8 @@ class namecoinConnection(object):
|
||||||
res = res["reply"]
|
res = res["reply"]
|
||||||
if not res:
|
if not res:
|
||||||
return (_translate(
|
return (_translate(
|
||||||
"MainWindow", "The name %1 was not found."
|
"MainWindow", "The name {0} was not found."
|
||||||
).arg(identity.decode("utf-8", "ignore")), None)
|
).format(identity.decode("utf-8", "ignore")), None)
|
||||||
else:
|
else:
|
||||||
assert False
|
assert False
|
||||||
except RPCError as exc:
|
except RPCError as exc:
|
||||||
|
@ -107,12 +107,12 @@ class namecoinConnection(object):
|
||||||
else:
|
else:
|
||||||
errmsg = exc.error
|
errmsg = exc.error
|
||||||
return (_translate(
|
return (_translate(
|
||||||
"MainWindow", "The namecoin query failed (%1)"
|
"MainWindow", "The namecoin query failed ({0})"
|
||||||
).arg(errmsg.decode("utf-8", "ignore")), None)
|
).format(errmsg.decode("utf-8", "ignore")), None)
|
||||||
except AssertionError:
|
except AssertionError:
|
||||||
return (_translate(
|
return (_translate(
|
||||||
"MainWindow", "Unknown namecoin interface type: %1"
|
"MainWindow", "Unknown namecoin interface type: {0}"
|
||||||
).arg(self.nmctype.decode("utf-8", "ignore")), None)
|
).format(self.nmctype.decode("utf-8", "ignore")), None)
|
||||||
except Exception:
|
except Exception:
|
||||||
logger.exception("Namecoin query exception")
|
logger.exception("Namecoin query exception")
|
||||||
return (_translate(
|
return (_translate(
|
||||||
|
@ -135,8 +135,8 @@ class namecoinConnection(object):
|
||||||
) if valid else (
|
) if valid else (
|
||||||
_translate(
|
_translate(
|
||||||
"MainWindow",
|
"MainWindow",
|
||||||
"The name %1 has no associated Bitmessage address."
|
"The name {0} has no associated Bitmessage address."
|
||||||
).arg(identity.decode("utf-8", "ignore")), None)
|
).format(identity.decode("utf-8", "ignore")), None)
|
||||||
|
|
||||||
def test(self):
|
def test(self):
|
||||||
"""
|
"""
|
||||||
|
@ -164,7 +164,7 @@ class namecoinConnection(object):
|
||||||
"success",
|
"success",
|
||||||
_translate(
|
_translate(
|
||||||
"MainWindow",
|
"MainWindow",
|
||||||
"Success! Namecoind version %1 running.").arg(
|
"Success! Namecoind version {0} running.").format(
|
||||||
versStr.decode("utf-8", "ignore")))
|
versStr.decode("utf-8", "ignore")))
|
||||||
|
|
||||||
elif self.nmctype == "nmcontrol":
|
elif self.nmctype == "nmcontrol":
|
||||||
|
|
|
@ -20,7 +20,7 @@ __all__ = ["StoppableThread"]
|
||||||
def start(config, state):
|
def start(config, state):
|
||||||
"""Start network threads"""
|
"""Start network threads"""
|
||||||
from .announcethread import AnnounceThread
|
from .announcethread import AnnounceThread
|
||||||
import connectionpool # pylint: disable=relative-import
|
from network import connectionpool
|
||||||
from .addrthread import AddrThread
|
from .addrthread import AddrThread
|
||||||
from .downloadthread import DownloadThread
|
from .downloadthread import DownloadThread
|
||||||
from .invthread import InvThread
|
from .invthread import InvThread
|
||||||
|
|
|
@ -5,11 +5,11 @@ import random
|
||||||
from six.moves import queue
|
from six.moves import queue
|
||||||
|
|
||||||
# magic imports!
|
# magic imports!
|
||||||
import connectionpool
|
from network import connectionpool
|
||||||
from protocol import assembleAddrMessage
|
from protocol import assembleAddrMessage
|
||||||
from network import addrQueue # FIXME: init with queue
|
from network import addrQueue # FIXME: init with queue
|
||||||
|
|
||||||
from threads import StoppableThread
|
from .threads import StoppableThread
|
||||||
|
|
||||||
|
|
||||||
class AddrThread(StoppableThread):
|
class AddrThread(StoppableThread):
|
||||||
|
|
|
@ -7,7 +7,7 @@ import time
|
||||||
|
|
||||||
import network.asyncore_pollchoose as asyncore
|
import network.asyncore_pollchoose as asyncore
|
||||||
import state
|
import state
|
||||||
from threads import BusyError, nonBlocking
|
from .threads import BusyError, nonBlocking
|
||||||
|
|
||||||
|
|
||||||
class ProcessingError(Exception):
|
class ProcessingError(Exception):
|
||||||
|
|
|
@ -4,12 +4,12 @@ Announce myself (node address)
|
||||||
import time
|
import time
|
||||||
|
|
||||||
# magic imports!
|
# magic imports!
|
||||||
import connectionpool
|
from network import connectionpool
|
||||||
from bmconfigparser import config
|
from bmconfigparser import config
|
||||||
from protocol import assembleAddrMessage
|
from protocol import assembleAddrMessage
|
||||||
|
|
||||||
from node import Peer
|
from .node import Peer
|
||||||
from threads import StoppableThread
|
from .threads import StoppableThread
|
||||||
|
|
||||||
|
|
||||||
class AnnounceThread(StoppableThread):
|
class AnnounceThread(StoppableThread):
|
||||||
|
|
|
@ -19,6 +19,7 @@ from errno import (
|
||||||
ENOTCONN, ENOTSOCK, EPIPE, ESHUTDOWN, ETIMEDOUT, EWOULDBLOCK, errorcode
|
ENOTCONN, ENOTSOCK, EPIPE, ESHUTDOWN, ETIMEDOUT, EWOULDBLOCK, errorcode
|
||||||
)
|
)
|
||||||
from threading import current_thread
|
from threading import current_thread
|
||||||
|
from six.moves.reprlib import repr
|
||||||
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
@ -723,21 +724,6 @@ class dispatcher(object):
|
||||||
if why.args[0] not in (ENOTCONN, EBADF):
|
if why.args[0] not in (ENOTCONN, EBADF):
|
||||||
raise
|
raise
|
||||||
|
|
||||||
# cheap inheritance, used to pass all other attribute
|
|
||||||
# references to the underlying socket object.
|
|
||||||
def __getattr__(self, attr):
|
|
||||||
try:
|
|
||||||
retattr = getattr(self.socket, attr)
|
|
||||||
except AttributeError:
|
|
||||||
raise AttributeError(
|
|
||||||
"%s instance has no attribute '%s'"
|
|
||||||
% (self.__class__.__name__, attr))
|
|
||||||
else:
|
|
||||||
msg = "%(me)s.%(attr)s is deprecated; use %(me)s.socket.%(attr)s"\
|
|
||||||
" instead" % {'me': self.__class__.__name__, 'attr': attr}
|
|
||||||
warnings.warn(msg, DeprecationWarning, stacklevel=2)
|
|
||||||
return retattr
|
|
||||||
|
|
||||||
# log and log_info may be overridden to provide more sophisticated
|
# log and log_info may be overridden to provide more sophisticated
|
||||||
# logging and warning methods. In general, log is for 'hit' logging
|
# logging and warning methods. In general, log is for 'hit' logging
|
||||||
# and 'log_info' is for informational, warning and error logging.
|
# and 'log_info' is for informational, warning and error logging.
|
||||||
|
|
|
@ -6,7 +6,7 @@ import time
|
||||||
|
|
||||||
import protocol
|
import protocol
|
||||||
import state
|
import state
|
||||||
import connectionpool
|
import network.connectionpool # use long name to address recursive import
|
||||||
from network import dandelion_ins
|
from network import dandelion_ins
|
||||||
from highlevelcrypto import calculateInventoryHash
|
from highlevelcrypto import calculateInventoryHash
|
||||||
|
|
||||||
|
@ -100,7 +100,7 @@ class BMObject(object): # pylint: disable=too-many-instance-attributes
|
||||||
logger.warning(
|
logger.warning(
|
||||||
'The object has invalid stream: %s', self.streamNumber)
|
'The object has invalid stream: %s', self.streamNumber)
|
||||||
raise BMObjectInvalidError()
|
raise BMObjectInvalidError()
|
||||||
if self.streamNumber not in connectionpool.pool.streams:
|
if self.streamNumber not in network.connectionpool.pool.streams:
|
||||||
logger.debug(
|
logger.debug(
|
||||||
'The streamNumber %i isn\'t one we are interested in.',
|
'The streamNumber %i isn\'t one we are interested in.',
|
||||||
self.streamNumber)
|
self.streamNumber)
|
||||||
|
|
|
@ -9,13 +9,14 @@ import re
|
||||||
import socket
|
import socket
|
||||||
import struct
|
import struct
|
||||||
import time
|
import time
|
||||||
|
import six
|
||||||
|
|
||||||
# magic imports!
|
# magic imports!
|
||||||
import addresses
|
import addresses
|
||||||
import knownnodes
|
from network import knownnodes
|
||||||
import protocol
|
import protocol
|
||||||
import state
|
import state
|
||||||
import connectionpool
|
import network.connectionpool # use long name to address recursive import
|
||||||
from bmconfigparser import config
|
from bmconfigparser import config
|
||||||
from queues import objectProcessorQueue
|
from queues import objectProcessorQueue
|
||||||
from randomtrackingdict import RandomTrackingDict
|
from randomtrackingdict import RandomTrackingDict
|
||||||
|
@ -26,14 +27,27 @@ from network.bmobject import (
|
||||||
BMObjectUnwantedStreamError
|
BMObjectUnwantedStreamError
|
||||||
)
|
)
|
||||||
from network.proxy import ProxyError
|
from network.proxy import ProxyError
|
||||||
|
|
||||||
from network import dandelion_ins, invQueue, portCheckerQueue
|
from network import dandelion_ins, invQueue, portCheckerQueue
|
||||||
from node import Node, Peer
|
from .node import Node, Peer
|
||||||
from objectracker import ObjectTracker, missingObjects
|
from .objectracker import ObjectTracker, missingObjects
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger('default')
|
logger = logging.getLogger('default')
|
||||||
|
|
||||||
|
|
||||||
|
def _hoststr(v):
|
||||||
|
if six.PY3:
|
||||||
|
return v
|
||||||
|
else: # assume six.PY2
|
||||||
|
return str(v)
|
||||||
|
|
||||||
|
def _restr(v):
|
||||||
|
if six.PY3:
|
||||||
|
return v.decode("utf-8", "replace")
|
||||||
|
else: # assume six.PY2
|
||||||
|
return v
|
||||||
|
|
||||||
class BMProtoError(ProxyError):
|
class BMProtoError(ProxyError):
|
||||||
"""A Bitmessage Protocol Base Error"""
|
"""A Bitmessage Protocol Base Error"""
|
||||||
errorCodes = ("Protocol error")
|
errorCodes = ("Protocol error")
|
||||||
|
@ -82,7 +96,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker):
|
||||||
"""Process incoming header"""
|
"""Process incoming header"""
|
||||||
self.magic, self.command, self.payloadLength, self.checksum = \
|
self.magic, self.command, self.payloadLength, self.checksum = \
|
||||||
protocol.Header.unpack(self.read_buf[:protocol.Header.size])
|
protocol.Header.unpack(self.read_buf[:protocol.Header.size])
|
||||||
self.command = self.command.rstrip('\x00')
|
self.command = self.command.rstrip(b'\x00')
|
||||||
if self.magic != protocol.magic:
|
if self.magic != protocol.magic:
|
||||||
# skip 1 byte in order to sync
|
# skip 1 byte in order to sync
|
||||||
self.set_state("bm_header", length=1)
|
self.set_state("bm_header", length=1)
|
||||||
|
@ -107,7 +121,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker):
|
||||||
self.invalid = True
|
self.invalid = True
|
||||||
retval = True
|
retval = True
|
||||||
if not self.fullyEstablished and self.command not in (
|
if not self.fullyEstablished and self.command not in (
|
||||||
"error", "version", "verack"):
|
b"error", b"version", b"verack"):
|
||||||
logger.error(
|
logger.error(
|
||||||
'Received command %s before connection was fully'
|
'Received command %s before connection was fully'
|
||||||
' established, ignoring', self.command)
|
' established, ignoring', self.command)
|
||||||
|
@ -115,7 +129,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker):
|
||||||
if not self.invalid:
|
if not self.invalid:
|
||||||
try:
|
try:
|
||||||
retval = getattr(
|
retval = getattr(
|
||||||
self, "bm_command_" + str(self.command).lower())()
|
self, "bm_command_" + self.command.decode("utf-8", "replace").lower())()
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
# unimplemented command
|
# unimplemented command
|
||||||
logger.debug('unimplemented command %s', self.command)
|
logger.debug('unimplemented command %s', self.command)
|
||||||
|
@ -168,17 +182,17 @@ class BMProto(AdvancedDispatcher, ObjectTracker):
|
||||||
"""Decode node details from the payload"""
|
"""Decode node details from the payload"""
|
||||||
# protocol.checkIPAddress()
|
# protocol.checkIPAddress()
|
||||||
services, host, port = self.decode_payload_content("Q16sH")
|
services, host, port = self.decode_payload_content("Q16sH")
|
||||||
if host[0:12] == '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF':
|
if host[0:12] == b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF':
|
||||||
host = socket.inet_ntop(socket.AF_INET, str(host[12:16]))
|
host = socket.inet_ntop(socket.AF_INET, _hoststr(host[12:16]))
|
||||||
elif host[0:6] == '\xfd\x87\xd8\x7e\xeb\x43':
|
elif host[0:6] == b'\xfd\x87\xd8\x7e\xeb\x43':
|
||||||
# Onion, based on BMD/bitcoind
|
# Onion, based on BMD/bitcoind
|
||||||
host = base64.b32encode(host[6:]).lower() + ".onion"
|
host = base64.b32encode(host[6:]).lower() + b".onion"
|
||||||
else:
|
else:
|
||||||
host = socket.inet_ntop(socket.AF_INET6, str(host))
|
host = socket.inet_ntop(socket.AF_INET6, _hoststr(host))
|
||||||
if host == "":
|
if host == b"":
|
||||||
# This can happen on Windows systems which are not 64-bit
|
# This can happen on Windows systems which are not 64-bit
|
||||||
# compatible so let us drop the IPv6 address.
|
# compatible so let us drop the IPv6 address.
|
||||||
host = socket.inet_ntop(socket.AF_INET, str(host[12:16]))
|
host = socket.inet_ntop(socket.AF_INET, _hoststr(host[12:16]))
|
||||||
|
|
||||||
return Node(services, host, port)
|
return Node(services, host, port)
|
||||||
|
|
||||||
|
@ -334,7 +348,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker):
|
||||||
if now < self.skipUntil:
|
if now < self.skipUntil:
|
||||||
return True
|
return True
|
||||||
for i in items:
|
for i in items:
|
||||||
self.pendingUpload[str(i)] = now
|
self.pendingUpload[i] = now
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def _command_inv(self, extend_dandelion_stem=False):
|
def _command_inv(self, extend_dandelion_stem=False):
|
||||||
|
@ -353,7 +367,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker):
|
||||||
if extend_dandelion_stem and not dandelion_ins.enabled:
|
if extend_dandelion_stem and not dandelion_ins.enabled:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
for i in map(str, items):
|
for i in items:
|
||||||
if i in state.Inventory and not dandelion_ins.hasHash(i):
|
if i in state.Inventory and not dandelion_ins.hasHash(i):
|
||||||
continue
|
continue
|
||||||
if extend_dandelion_stem and not dandelion_ins.hasHash(i):
|
if extend_dandelion_stem and not dandelion_ins.hasHash(i):
|
||||||
|
@ -409,13 +423,17 @@ class BMProto(AdvancedDispatcher, ObjectTracker):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.object.checkObjectByType()
|
self.object.checkObjectByType()
|
||||||
|
if six.PY2:
|
||||||
|
data_buffer = buffer(self.object.data)
|
||||||
|
else: # assume six.PY3
|
||||||
|
data_buffer = memoryview(self.object.data)
|
||||||
objectProcessorQueue.put((
|
objectProcessorQueue.put((
|
||||||
self.object.objectType, buffer(self.object.data))) # noqa: F821
|
self.object.objectType, data_buffer)) # noqa: F821
|
||||||
except BMObjectInvalidError:
|
except BMObjectInvalidError:
|
||||||
BMProto.stopDownloadingObject(self.object.inventoryHash, True)
|
BMProto.stopDownloadingObject(self.object.inventoryHash, True)
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
del missingObjects[self.object.inventoryHash]
|
del missingObjects[bytes(self.object.inventoryHash)]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -424,10 +442,16 @@ class BMProto(AdvancedDispatcher, ObjectTracker):
|
||||||
dandelion_ins.removeHash(
|
dandelion_ins.removeHash(
|
||||||
self.object.inventoryHash, "cycle detection")
|
self.object.inventoryHash, "cycle detection")
|
||||||
|
|
||||||
|
if six.PY2:
|
||||||
|
object_buffer = buffer(self.payload[objectOffset:])
|
||||||
|
tag_buffer = buffer(self.object.tag)
|
||||||
|
else: # assume six.PY3
|
||||||
|
object_buffer = memoryview(self.payload[objectOffset:])
|
||||||
|
tag_buffer = memoryview(self.object.tag)
|
||||||
state.Inventory[self.object.inventoryHash] = (
|
state.Inventory[self.object.inventoryHash] = (
|
||||||
self.object.objectType, self.object.streamNumber,
|
self.object.objectType, self.object.streamNumber,
|
||||||
buffer(self.payload[objectOffset:]), self.object.expiresTime, # noqa: F821
|
object_buffer, self.object.expiresTime, # noqa: F821
|
||||||
buffer(self.object.tag) # noqa: F821
|
tag_buffer # noqa: F821
|
||||||
)
|
)
|
||||||
self.handleReceivedObject(
|
self.handleReceivedObject(
|
||||||
self.object.streamNumber, self.object.inventoryHash)
|
self.object.streamNumber, self.object.inventoryHash)
|
||||||
|
@ -443,11 +467,10 @@ class BMProto(AdvancedDispatcher, ObjectTracker):
|
||||||
"""Incoming addresses, process them"""
|
"""Incoming addresses, process them"""
|
||||||
# not using services
|
# not using services
|
||||||
for seenTime, stream, _, ip, port in self._decode_addr():
|
for seenTime, stream, _, ip, port in self._decode_addr():
|
||||||
ip = str(ip)
|
|
||||||
if (
|
if (
|
||||||
stream not in connectionpool.pool.streams
|
stream not in network.connectionpool.pool.streams
|
||||||
# FIXME: should check against complete list
|
# FIXME: should check against complete list
|
||||||
or ip.startswith('bootstrap')
|
or ip.decode("utf-8", "replace").startswith('bootstrap')
|
||||||
):
|
):
|
||||||
continue
|
continue
|
||||||
decodedIP = protocol.checkIPAddress(ip)
|
decodedIP = protocol.checkIPAddress(ip)
|
||||||
|
@ -477,7 +500,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker):
|
||||||
|
|
||||||
def bm_command_ping(self):
|
def bm_command_ping(self):
|
||||||
"""Incoming ping, respond to it."""
|
"""Incoming ping, respond to it."""
|
||||||
self.append_write_buf(protocol.CreatePacket('pong'))
|
self.append_write_buf(protocol.CreatePacket(b'pong'))
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
@ -526,21 +549,21 @@ class BMProto(AdvancedDispatcher, ObjectTracker):
|
||||||
logger.debug(
|
logger.debug(
|
||||||
'remote node incoming address: %s:%i',
|
'remote node incoming address: %s:%i',
|
||||||
self.destination.host, self.peerNode.port)
|
self.destination.host, self.peerNode.port)
|
||||||
logger.debug('user agent: %s', self.userAgent)
|
logger.debug('user agent: %s', self.userAgent.decode("utf-8", "replace"))
|
||||||
logger.debug('streams: [%s]', ','.join(map(str, self.streams)))
|
logger.debug('streams: [%s]', ','.join(map(str, self.streams)))
|
||||||
if not self.peerValidityChecks():
|
if not self.peerValidityChecks():
|
||||||
# ABORT afterwards
|
# ABORT afterwards
|
||||||
return True
|
return True
|
||||||
self.append_write_buf(protocol.CreatePacket('verack'))
|
self.append_write_buf(protocol.CreatePacket(b'verack'))
|
||||||
self.verackSent = True
|
self.verackSent = True
|
||||||
ua_valid = re.match(
|
ua_valid = re.match(
|
||||||
r'^/[a-zA-Z]+:[0-9]+\.?[\w\s\(\)\./:;-]*/$', self.userAgent)
|
r'^/[a-zA-Z]+:[0-9]+\.?[\w\s\(\)\./:;-]*/$', _restr(self.userAgent))
|
||||||
if not ua_valid:
|
if not ua_valid:
|
||||||
self.userAgent = '/INVALID:0/'
|
self.userAgent = b'/INVALID:0/'
|
||||||
if not self.isOutbound:
|
if not self.isOutbound:
|
||||||
self.append_write_buf(protocol.assembleVersionMessage(
|
self.append_write_buf(protocol.assembleVersionMessage(
|
||||||
self.destination.host, self.destination.port,
|
self.destination.host, self.destination.port,
|
||||||
connectionpool.pool.streams, dandelion_ins.enabled, True,
|
network.connectionpool.pool.streams, dandelion_ins.enabled, True,
|
||||||
nodeid=self.nodeid))
|
nodeid=self.nodeid))
|
||||||
logger.debug(
|
logger.debug(
|
||||||
'%(host)s:%(port)i sending version',
|
'%(host)s:%(port)i sending version',
|
||||||
|
@ -596,7 +619,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker):
|
||||||
'Closed connection to %s because there is no overlapping'
|
'Closed connection to %s because there is no overlapping'
|
||||||
' interest in streams.', self.destination)
|
' interest in streams.', self.destination)
|
||||||
return False
|
return False
|
||||||
if connectionpool.pool.inboundConnections.get(
|
if network.connectionpool.pool.inboundConnections.get(
|
||||||
self.destination):
|
self.destination):
|
||||||
try:
|
try:
|
||||||
if not protocol.checkSocksIP(self.destination.host):
|
if not protocol.checkSocksIP(self.destination.host):
|
||||||
|
@ -614,8 +637,8 @@ class BMProto(AdvancedDispatcher, ObjectTracker):
|
||||||
# or server full report the same error to counter deanonymisation
|
# or server full report the same error to counter deanonymisation
|
||||||
if (
|
if (
|
||||||
Peer(self.destination.host, self.peerNode.port)
|
Peer(self.destination.host, self.peerNode.port)
|
||||||
in connectionpool.pool.inboundConnections
|
in network.connectionpool.pool.inboundConnections
|
||||||
or len(connectionpool.pool)
|
or len(network.connectionpool.pool)
|
||||||
> config.safeGetInt(
|
> config.safeGetInt(
|
||||||
'bitmessagesettings', 'maxtotalconnections')
|
'bitmessagesettings', 'maxtotalconnections')
|
||||||
+ config.safeGetInt(
|
+ config.safeGetInt(
|
||||||
|
@ -627,7 +650,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker):
|
||||||
'Closed connection to %s due to server full'
|
'Closed connection to %s due to server full'
|
||||||
' or duplicate inbound/outbound.', self.destination)
|
' or duplicate inbound/outbound.', self.destination)
|
||||||
return False
|
return False
|
||||||
if connectionpool.pool.isAlreadyConnected(self.nonce):
|
if network.connectionpool.pool.isAlreadyConnected(self.nonce):
|
||||||
self.append_write_buf(protocol.assembleErrorMessage(
|
self.append_write_buf(protocol.assembleErrorMessage(
|
||||||
errorText="I'm connected to myself. Closing connection.",
|
errorText="I'm connected to myself. Closing connection.",
|
||||||
fatal=2))
|
fatal=2))
|
||||||
|
@ -641,7 +664,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker):
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def stopDownloadingObject(hashId, forwardAnyway=False):
|
def stopDownloadingObject(hashId, forwardAnyway=False):
|
||||||
"""Stop downloading object *hashId*"""
|
"""Stop downloading object *hashId*"""
|
||||||
for connection in connectionpool.pool.connections():
|
for connection in network.connectionpool.pool.connections():
|
||||||
try:
|
try:
|
||||||
del connection.objectsNewToMe[hashId]
|
del connection.objectsNewToMe[hashId]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
|
@ -653,7 +676,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker):
|
||||||
except KeyError:
|
except KeyError:
|
||||||
pass
|
pass
|
||||||
try:
|
try:
|
||||||
del missingObjects[hashId]
|
del missingObjects[bytes(hashId)]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ import random
|
||||||
|
|
||||||
from six.moves import queue
|
from six.moves import queue
|
||||||
|
|
||||||
import knownnodes
|
from network import knownnodes
|
||||||
import protocol
|
import protocol
|
||||||
import state
|
import state
|
||||||
|
|
||||||
|
@ -17,10 +17,16 @@ from network import portCheckerQueue
|
||||||
logger = logging.getLogger('default')
|
logger = logging.getLogger('default')
|
||||||
|
|
||||||
|
|
||||||
|
def _ends_with(s, tail):
|
||||||
|
try:
|
||||||
|
return s.endswith(tail)
|
||||||
|
except:
|
||||||
|
return s.decode("utf-8", "replace").endswith(tail)
|
||||||
|
|
||||||
def getDiscoveredPeer():
|
def getDiscoveredPeer():
|
||||||
"""Get a peer from the local peer discovery list"""
|
"""Get a peer from the local peer discovery list"""
|
||||||
try:
|
try:
|
||||||
peer = random.choice(state.discoveredPeers.keys()) # nosec B311
|
peer = random.choice(list(state.discoveredPeers.keys())) # nosec B311
|
||||||
except (IndexError, KeyError):
|
except (IndexError, KeyError):
|
||||||
raise ValueError
|
raise ValueError
|
||||||
try:
|
try:
|
||||||
|
@ -48,7 +54,7 @@ def chooseConnection(stream):
|
||||||
return getDiscoveredPeer()
|
return getDiscoveredPeer()
|
||||||
for _ in range(50):
|
for _ in range(50):
|
||||||
peer = random.choice( # nosec B311
|
peer = random.choice( # nosec B311
|
||||||
knownnodes.knownNodes[stream].keys())
|
list(knownnodes.knownNodes[stream].keys()))
|
||||||
try:
|
try:
|
||||||
peer_info = knownnodes.knownNodes[stream][peer]
|
peer_info = knownnodes.knownNodes[stream][peer]
|
||||||
if peer_info.get('self'):
|
if peer_info.get('self'):
|
||||||
|
@ -60,10 +66,10 @@ def chooseConnection(stream):
|
||||||
if haveOnion:
|
if haveOnion:
|
||||||
# do not connect to raw IP addresses
|
# do not connect to raw IP addresses
|
||||||
# --keep all traffic within Tor overlay
|
# --keep all traffic within Tor overlay
|
||||||
if onionOnly and not peer.host.endswith('.onion'):
|
if onionOnly and not _ends_with(peer.host, '.onion'):
|
||||||
continue
|
continue
|
||||||
# onion addresses have a higher priority when SOCKS
|
# onion addresses have a higher priority when SOCKS
|
||||||
if peer.host.endswith('.onion') and rating > 0:
|
if _ends_with(peer.host, '.onion') and rating > 0:
|
||||||
rating = 1
|
rating = 1
|
||||||
# TODO: need better check
|
# TODO: need better check
|
||||||
elif not peer.host.startswith('bootstrap'):
|
elif not peer.host.startswith('bootstrap'):
|
||||||
|
|
|
@ -9,22 +9,28 @@ import sys
|
||||||
import time
|
import time
|
||||||
import random
|
import random
|
||||||
|
|
||||||
import asyncore_pollchoose as asyncore
|
from network import asyncore_pollchoose as asyncore
|
||||||
import knownnodes
|
from network import knownnodes
|
||||||
import protocol
|
import protocol
|
||||||
import state
|
import state
|
||||||
from bmconfigparser import config
|
from bmconfigparser import config
|
||||||
from connectionchooser import chooseConnection
|
from .connectionchooser import chooseConnection
|
||||||
from node import Peer
|
from .node import Peer
|
||||||
from proxy import Proxy
|
from .proxy import Proxy
|
||||||
from tcp import (
|
from .tcp import (
|
||||||
bootstrap, Socks4aBMConnection, Socks5BMConnection,
|
bootstrap, Socks4aBMConnection, Socks5BMConnection,
|
||||||
TCPConnection, TCPServer)
|
TCPConnection, TCPServer)
|
||||||
from udp import UDPSocket
|
from .udp import UDPSocket
|
||||||
|
|
||||||
logger = logging.getLogger('default')
|
logger = logging.getLogger('default')
|
||||||
|
|
||||||
|
|
||||||
|
def _ends_with(s, tail):
|
||||||
|
try:
|
||||||
|
return s.endswith(tail)
|
||||||
|
except:
|
||||||
|
return s.decode("utf-8", "replace").endswith(tail)
|
||||||
|
|
||||||
class BMConnectionPool(object):
|
class BMConnectionPool(object):
|
||||||
"""Pool of all existing connections"""
|
"""Pool of all existing connections"""
|
||||||
# pylint: disable=too-many-instance-attributes
|
# pylint: disable=too-many-instance-attributes
|
||||||
|
@ -78,7 +84,7 @@ class BMConnectionPool(object):
|
||||||
Shortcut for combined list of connections from
|
Shortcut for combined list of connections from
|
||||||
`inboundConnections` and `outboundConnections` dicts
|
`inboundConnections` and `outboundConnections` dicts
|
||||||
"""
|
"""
|
||||||
return self.inboundConnections.values() + self.outboundConnections.values()
|
return list(self.inboundConnections.values()) + list(self.outboundConnections.values())
|
||||||
|
|
||||||
def establishedConnections(self):
|
def establishedConnections(self):
|
||||||
"""Shortcut for list of connections having fullyEstablished == True"""
|
"""Shortcut for list of connections having fullyEstablished == True"""
|
||||||
|
@ -160,8 +166,8 @@ class BMConnectionPool(object):
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def getListeningIP():
|
def getListeningIP():
|
||||||
"""What IP are we supposed to be listening on?"""
|
"""What IP are we supposed to be listening on?"""
|
||||||
if config.safeGet(
|
if _ends_with(config.safeGet(
|
||||||
"bitmessagesettings", "onionhostname", "").endswith(".onion"):
|
"bitmessagesettings", "onionhostname", ""), ".onion"):
|
||||||
host = config.safeGet(
|
host = config.safeGet(
|
||||||
"bitmessagesettings", "onionbindip")
|
"bitmessagesettings", "onionbindip")
|
||||||
else:
|
else:
|
||||||
|
@ -314,7 +320,7 @@ class BMConnectionPool(object):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if chosen.host.endswith(".onion") and Proxy.onion_proxy:
|
if _ends_with(chosen.host, ".onion") and Proxy.onion_proxy:
|
||||||
if onionsocksproxytype == "SOCKS5":
|
if onionsocksproxytype == "SOCKS5":
|
||||||
self.addConnection(Socks5BMConnection(chosen))
|
self.addConnection(Socks5BMConnection(chosen))
|
||||||
elif onionsocksproxytype == "SOCKS4a":
|
elif onionsocksproxytype == "SOCKS4a":
|
||||||
|
@ -381,14 +387,14 @@ class BMConnectionPool(object):
|
||||||
minTx -= 300 - 20
|
minTx -= 300 - 20
|
||||||
if i.lastTx < minTx:
|
if i.lastTx < minTx:
|
||||||
if i.fullyEstablished:
|
if i.fullyEstablished:
|
||||||
i.append_write_buf(protocol.CreatePacket('ping'))
|
i.append_write_buf(protocol.CreatePacket(b'ping'))
|
||||||
else:
|
else:
|
||||||
i.close_reason = "Timeout (%is)" % (
|
i.close_reason = "Timeout (%is)" % (
|
||||||
time.time() - i.lastTx)
|
time.time() - i.lastTx)
|
||||||
i.set_state("close")
|
i.set_state("close")
|
||||||
for i in (
|
for i in (
|
||||||
self.connections()
|
self.connections()
|
||||||
+ self.listeningSockets.values() + self.udpSockets.values()
|
+ list(self.listeningSockets.values()) + list(self.udpSockets.values())
|
||||||
):
|
):
|
||||||
if not (i.accepting or i.connecting or i.connected):
|
if not (i.accepting or i.connecting or i.connected):
|
||||||
reaper.append(i)
|
reaper.append(i)
|
||||||
|
|
|
@ -6,6 +6,8 @@ from collections import namedtuple
|
||||||
from random import choice, expovariate, sample
|
from random import choice, expovariate, sample
|
||||||
from threading import RLock
|
from threading import RLock
|
||||||
from time import time
|
from time import time
|
||||||
|
import six
|
||||||
|
from binascii import hexlify
|
||||||
|
|
||||||
|
|
||||||
# randomise routes after 600 seconds
|
# randomise routes after 600 seconds
|
||||||
|
@ -64,7 +66,7 @@ class Dandelion: # pylint: disable=old-style-class
|
||||||
"""Add inventory vector to dandelion stem return status of dandelion enabled"""
|
"""Add inventory vector to dandelion stem return status of dandelion enabled"""
|
||||||
assert self.enabled is not None
|
assert self.enabled is not None
|
||||||
with self.lock:
|
with self.lock:
|
||||||
self.hashMap[hashId] = Stem(
|
self.hashMap[bytes(hashId)] = Stem(
|
||||||
self.getNodeStem(source),
|
self.getNodeStem(source),
|
||||||
stream,
|
stream,
|
||||||
self.poissonTimeout())
|
self.poissonTimeout())
|
||||||
|
@ -75,9 +77,10 @@ class Dandelion: # pylint: disable=old-style-class
|
||||||
include streams, we only learn this after receiving the object)
|
include streams, we only learn this after receiving the object)
|
||||||
"""
|
"""
|
||||||
with self.lock:
|
with self.lock:
|
||||||
if hashId in self.hashMap:
|
hashId_bytes = bytes(hashId)
|
||||||
self.hashMap[hashId] = Stem(
|
if hashId_bytes in self.hashMap:
|
||||||
self.hashMap[hashId].child,
|
self.hashMap[hashId_bytes] = Stem(
|
||||||
|
self.hashMap[hashId_bytes].child,
|
||||||
stream,
|
stream,
|
||||||
self.poissonTimeout())
|
self.poissonTimeout())
|
||||||
|
|
||||||
|
@ -86,20 +89,20 @@ class Dandelion: # pylint: disable=old-style-class
|
||||||
if logger.isEnabledFor(logging.DEBUG):
|
if logger.isEnabledFor(logging.DEBUG):
|
||||||
logger.debug(
|
logger.debug(
|
||||||
'%s entering fluff mode due to %s.',
|
'%s entering fluff mode due to %s.',
|
||||||
''.join('%02x' % ord(i) for i in hashId), reason)
|
hexlify(hashId), reason)
|
||||||
with self.lock:
|
with self.lock:
|
||||||
try:
|
try:
|
||||||
del self.hashMap[hashId]
|
del self.hashMap[bytes(hashId)]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def hasHash(self, hashId):
|
def hasHash(self, hashId):
|
||||||
"""Is inventory vector in stem mode?"""
|
"""Is inventory vector in stem mode?"""
|
||||||
return hashId in self.hashMap
|
return bytes(hashId) in self.hashMap
|
||||||
|
|
||||||
def objectChildStem(self, hashId):
|
def objectChildStem(self, hashId):
|
||||||
"""Child (i.e. next) node for an inventory vector during stem mode"""
|
"""Child (i.e. next) node for an inventory vector during stem mode"""
|
||||||
return self.hashMap[hashId].child
|
return self.hashMap[bytes(hashId)].child
|
||||||
|
|
||||||
def maybeAddStem(self, connection, invQueue):
|
def maybeAddStem(self, connection, invQueue):
|
||||||
"""
|
"""
|
||||||
|
@ -111,12 +114,12 @@ class Dandelion: # pylint: disable=old-style-class
|
||||||
with self.lock:
|
with self.lock:
|
||||||
if len(self.stem) < MAX_STEMS:
|
if len(self.stem) < MAX_STEMS:
|
||||||
self.stem.append(connection)
|
self.stem.append(connection)
|
||||||
for k in (k for k, v in self.nodeMap.iteritems() if v is None):
|
for k in (k for k, v in six.iteritems(self.nodeMap) if v is None):
|
||||||
self.nodeMap[k] = connection
|
self.nodeMap[k] = connection
|
||||||
for k, v in {
|
for k, v in six.iteritems({
|
||||||
k: v for k, v in self.hashMap.iteritems()
|
k: v for k, v in six.iteritems(self.hashMap)
|
||||||
if v.child is None
|
if v.child is None
|
||||||
}.iteritems():
|
}):
|
||||||
self.hashMap[k] = Stem(
|
self.hashMap[k] = Stem(
|
||||||
connection, v.stream, self.poissonTimeout())
|
connection, v.stream, self.poissonTimeout())
|
||||||
invQueue.put((v.stream, k, v.child))
|
invQueue.put((v.stream, k, v.child))
|
||||||
|
@ -132,14 +135,14 @@ class Dandelion: # pylint: disable=old-style-class
|
||||||
self.stem.remove(connection)
|
self.stem.remove(connection)
|
||||||
# active mappings to pointing to the removed node
|
# active mappings to pointing to the removed node
|
||||||
for k in (
|
for k in (
|
||||||
k for k, v in self.nodeMap.iteritems()
|
k for k, v in six.iteritems(self.nodeMap)
|
||||||
if v == connection
|
if v == connection
|
||||||
):
|
):
|
||||||
self.nodeMap[k] = None
|
self.nodeMap[k] = None
|
||||||
for k, v in {
|
for k, v in six.iteritems({
|
||||||
k: v for k, v in self.hashMap.iteritems()
|
k: v for k, v in six.iteritems(self.hashMap)
|
||||||
if v.child == connection
|
if v.child == connection
|
||||||
}.iteritems():
|
}):
|
||||||
self.hashMap[k] = Stem(
|
self.hashMap[k] = Stem(
|
||||||
None, v.stream, self.poissonTimeout())
|
None, v.stream, self.poissonTimeout())
|
||||||
|
|
||||||
|
@ -180,7 +183,7 @@ class Dandelion: # pylint: disable=old-style-class
|
||||||
with self.lock:
|
with self.lock:
|
||||||
deadline = time()
|
deadline = time()
|
||||||
toDelete = [
|
toDelete = [
|
||||||
[v.stream, k, v.child] for k, v in self.hashMap.iteritems()
|
[v.stream, k, v.child] for k, v in six.iteritems(self.hashMap)
|
||||||
if v.timeout < deadline
|
if v.timeout < deadline
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -199,10 +202,10 @@ class Dandelion: # pylint: disable=old-style-class
|
||||||
try:
|
try:
|
||||||
# random two connections
|
# random two connections
|
||||||
self.stem = sample(
|
self.stem = sample(
|
||||||
self.pool.outboundConnections.values(), MAX_STEMS)
|
sorted(self.pool.outboundConnections.values()), MAX_STEMS)
|
||||||
# not enough stems available
|
# not enough stems available
|
||||||
except ValueError:
|
except ValueError:
|
||||||
self.stem = self.pool.outboundConnections.values()
|
self.stem = list(self.pool.outboundConnections.values())
|
||||||
self.nodeMap = {}
|
self.nodeMap = {}
|
||||||
# hashMap stays to cater for pending stems
|
# hashMap stays to cater for pending stems
|
||||||
self.refresh = time() + REASSIGN_INTERVAL
|
self.refresh = time() + REASSIGN_INTERVAL
|
||||||
|
|
|
@ -4,12 +4,13 @@
|
||||||
import time
|
import time
|
||||||
import random
|
import random
|
||||||
import state
|
import state
|
||||||
|
import six
|
||||||
import addresses
|
import addresses
|
||||||
import protocol
|
import protocol
|
||||||
import connectionpool
|
from network import connectionpool
|
||||||
from network import dandelion_ins
|
from network import dandelion_ins
|
||||||
from objectracker import missingObjects
|
from .objectracker import missingObjects
|
||||||
from threads import StoppableThread
|
from .threads import StoppableThread
|
||||||
|
|
||||||
|
|
||||||
class DownloadThread(StoppableThread):
|
class DownloadThread(StoppableThread):
|
||||||
|
@ -29,7 +30,7 @@ class DownloadThread(StoppableThread):
|
||||||
deadline = time.time() - self.requestExpires
|
deadline = time.time() - self.requestExpires
|
||||||
try:
|
try:
|
||||||
toDelete = [
|
toDelete = [
|
||||||
k for k, v in missingObjects.iteritems()
|
k for k, v in six.iteritems(missingObjects)
|
||||||
if v < deadline]
|
if v < deadline]
|
||||||
except RuntimeError:
|
except RuntimeError:
|
||||||
pass
|
pass
|
||||||
|
@ -68,11 +69,11 @@ class DownloadThread(StoppableThread):
|
||||||
continue
|
continue
|
||||||
payload.extend(chunk)
|
payload.extend(chunk)
|
||||||
chunkCount += 1
|
chunkCount += 1
|
||||||
missingObjects[chunk] = now
|
missingObjects[bytes(chunk)] = now
|
||||||
if not chunkCount:
|
if not chunkCount:
|
||||||
continue
|
continue
|
||||||
payload[0:0] = addresses.encodeVarint(chunkCount)
|
payload[0:0] = addresses.encodeVarint(chunkCount)
|
||||||
i.append_write_buf(protocol.CreatePacket('getdata', payload))
|
i.append_write_buf(protocol.CreatePacket(b'getdata', payload))
|
||||||
self.logger.debug(
|
self.logger.debug(
|
||||||
'%s:%i Requesting %i objects',
|
'%s:%i Requesting %i objects',
|
||||||
i.destination.host, i.destination.port, chunkCount)
|
i.destination.host, i.destination.port, chunkCount)
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
import socket
|
import socket
|
||||||
|
|
||||||
from advanceddispatcher import AdvancedDispatcher
|
from .advanceddispatcher import AdvancedDispatcher
|
||||||
import asyncore_pollchoose as asyncore
|
from network import asyncore_pollchoose as asyncore
|
||||||
from proxy import ProxyError
|
from .proxy import ProxyError
|
||||||
from socks5 import Socks5Connection, Socks5Resolver
|
from .socks5 import Socks5Connection, Socks5Resolver
|
||||||
from socks4a import Socks4aConnection, Socks4aResolver
|
from .socks4a import Socks4aConnection, Socks4aResolver
|
||||||
|
|
||||||
|
|
||||||
class HttpError(ProxyError):
|
class HttpError(ProxyError):
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
"""
|
"""
|
||||||
Thread to send inv annoucements
|
Thread to send inv annoucements
|
||||||
"""
|
"""
|
||||||
import Queue
|
from six.moves import queue as Queue
|
||||||
import random
|
import random
|
||||||
from time import time
|
from time import time
|
||||||
|
|
||||||
import addresses
|
import addresses
|
||||||
import protocol
|
import protocol
|
||||||
import state
|
import state
|
||||||
import connectionpool
|
from network import connectionpool
|
||||||
from network import dandelion_ins, invQueue
|
from network import dandelion_ins, invQueue
|
||||||
from threads import StoppableThread
|
from .threads import StoppableThread
|
||||||
|
|
||||||
|
|
||||||
def handleExpiredDandelion(expired):
|
def handleExpiredDandelion(expired):
|
||||||
|
@ -90,15 +90,15 @@ class InvThread(StoppableThread):
|
||||||
if fluffs:
|
if fluffs:
|
||||||
random.shuffle(fluffs)
|
random.shuffle(fluffs)
|
||||||
connection.append_write_buf(protocol.CreatePacket(
|
connection.append_write_buf(protocol.CreatePacket(
|
||||||
'inv',
|
b'inv',
|
||||||
addresses.encodeVarint(
|
addresses.encodeVarint(
|
||||||
len(fluffs)) + ''.join(fluffs)))
|
len(fluffs)) + b''.join(fluffs)))
|
||||||
if stems:
|
if stems:
|
||||||
random.shuffle(stems)
|
random.shuffle(stems)
|
||||||
connection.append_write_buf(protocol.CreatePacket(
|
connection.append_write_buf(protocol.CreatePacket(
|
||||||
'dinv',
|
b'dinv',
|
||||||
addresses.encodeVarint(
|
addresses.encodeVarint(
|
||||||
len(stems)) + ''.join(stems)))
|
len(stems)) + b''.join(stems)))
|
||||||
|
|
||||||
invQueue.iterate()
|
invQueue.iterate()
|
||||||
for _ in range(len(chunk)):
|
for _ in range(len(chunk)):
|
||||||
|
|
|
@ -10,10 +10,8 @@ import os
|
||||||
import pickle # nosec B403
|
import pickle # nosec B403
|
||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
try:
|
from six.moves.collections_abc import Iterable
|
||||||
from collections.abc import Iterable
|
import six
|
||||||
except ImportError:
|
|
||||||
from collections import Iterable
|
|
||||||
|
|
||||||
import state
|
import state
|
||||||
from bmconfigparser import config
|
from bmconfigparser import config
|
||||||
|
@ -54,8 +52,8 @@ def json_serialize_knownnodes(output):
|
||||||
Reorganize knownnodes dict and write it as JSON to output
|
Reorganize knownnodes dict and write it as JSON to output
|
||||||
"""
|
"""
|
||||||
_serialized = []
|
_serialized = []
|
||||||
for stream, peers in knownNodes.iteritems():
|
for stream, peers in six.iteritems(knownNodes):
|
||||||
for peer, info in peers.iteritems():
|
for peer, info in six.iteritems(peers):
|
||||||
info.update(rating=round(info.get('rating', 0), 2))
|
info.update(rating=round(info.get('rating', 0), 2))
|
||||||
_serialized.append({
|
_serialized.append({
|
||||||
'stream': stream, 'peer': peer._asdict(), 'info': info
|
'stream': stream, 'peer': peer._asdict(), 'info': info
|
||||||
|
@ -87,7 +85,7 @@ def pickle_deserialize_old_knownnodes(source):
|
||||||
global knownNodes
|
global knownNodes
|
||||||
knownNodes = pickle.load(source) # nosec B301
|
knownNodes = pickle.load(source) # nosec B301
|
||||||
for stream in knownNodes.keys():
|
for stream in knownNodes.keys():
|
||||||
for node, params in knownNodes[stream].iteritems():
|
for node, params in six.iteritems(knownNodes[stream]):
|
||||||
if isinstance(params, (float, int)):
|
if isinstance(params, (float, int)):
|
||||||
addKnownNode(stream, node, params)
|
addKnownNode(stream, node, params)
|
||||||
|
|
||||||
|
@ -97,7 +95,7 @@ def saveKnownNodes(dirName=None):
|
||||||
if dirName is None:
|
if dirName is None:
|
||||||
dirName = state.appdata
|
dirName = state.appdata
|
||||||
with knownNodesLock:
|
with knownNodesLock:
|
||||||
with open(os.path.join(dirName, 'knownnodes.dat'), 'wb') as output:
|
with open(os.path.join(dirName, 'knownnodes.dat'), 'w') as output:
|
||||||
json_serialize_knownnodes(output)
|
json_serialize_knownnodes(output)
|
||||||
|
|
||||||
|
|
||||||
|
@ -108,6 +106,12 @@ def addKnownNode(stream, peer, lastseen=None, is_self=False):
|
||||||
Returns True if added a new node.
|
Returns True if added a new node.
|
||||||
"""
|
"""
|
||||||
# pylint: disable=too-many-branches
|
# pylint: disable=too-many-branches
|
||||||
|
if not isinstance(peer.host, str):
|
||||||
|
try:
|
||||||
|
peer = Peer(peer.host.decode("ascii"), peer.port)
|
||||||
|
except UnicodeDecodeError as err:
|
||||||
|
logger.warning("Invalid host: {}".format(peer.host.decode("ascii", "backslashreplace")))
|
||||||
|
return
|
||||||
if isinstance(stream, Iterable):
|
if isinstance(stream, Iterable):
|
||||||
with knownNodesLock:
|
with knownNodesLock:
|
||||||
for s in stream:
|
for s in stream:
|
||||||
|
@ -153,7 +157,7 @@ def createDefaultKnownNodes():
|
||||||
def readKnownNodes():
|
def readKnownNodes():
|
||||||
"""Load knownnodes from filesystem"""
|
"""Load knownnodes from filesystem"""
|
||||||
try:
|
try:
|
||||||
with open(state.appdata + 'knownnodes.dat', 'rb') as source:
|
with open(state.appdata + 'knownnodes.dat', 'r') as source:
|
||||||
with knownNodesLock:
|
with knownNodesLock:
|
||||||
try:
|
try:
|
||||||
json_deserialize_knownnodes(source)
|
json_deserialize_knownnodes(source)
|
||||||
|
|
|
@ -2,9 +2,9 @@
|
||||||
A thread to handle network concerns
|
A thread to handle network concerns
|
||||||
"""
|
"""
|
||||||
import network.asyncore_pollchoose as asyncore
|
import network.asyncore_pollchoose as asyncore
|
||||||
import connectionpool
|
from network import connectionpool
|
||||||
from queues import excQueue
|
from queues import excQueue
|
||||||
from threads import StoppableThread
|
from .threads import StoppableThread
|
||||||
|
|
||||||
|
|
||||||
class BMNetworkThread(StoppableThread):
|
class BMNetworkThread(StoppableThread):
|
||||||
|
|
|
@ -3,8 +3,9 @@ Module for tracking objects
|
||||||
"""
|
"""
|
||||||
import time
|
import time
|
||||||
from threading import RLock
|
from threading import RLock
|
||||||
|
import six
|
||||||
|
|
||||||
import connectionpool
|
import network.connectionpool # use long name to address recursive import
|
||||||
from network import dandelion_ins
|
from network import dandelion_ins
|
||||||
from randomtrackingdict import RandomTrackingDict
|
from randomtrackingdict import RandomTrackingDict
|
||||||
|
|
||||||
|
@ -75,32 +76,35 @@ class ObjectTracker(object):
|
||||||
with self.objectsNewToThemLock:
|
with self.objectsNewToThemLock:
|
||||||
self.objectsNewToThem = {
|
self.objectsNewToThem = {
|
||||||
k: v
|
k: v
|
||||||
for k, v in self.objectsNewToThem.iteritems()
|
for k, v in six.iteritems(self.objectsNewToThem)
|
||||||
if v >= deadline}
|
if v >= deadline}
|
||||||
self.lastCleaned = time.time()
|
self.lastCleaned = time.time()
|
||||||
|
|
||||||
def hasObj(self, hashid):
|
def hasObj(self, hashid):
|
||||||
"""Do we already have object?"""
|
"""Do we already have object?"""
|
||||||
|
hashid_bytes = bytes(hashid)
|
||||||
if haveBloom:
|
if haveBloom:
|
||||||
return hashid in self.invBloom
|
return hashid_bytes in self.invBloom
|
||||||
return hashid in self.objectsNewToMe
|
return hashid_bytes in self.objectsNewToMe
|
||||||
|
|
||||||
def handleReceivedInventory(self, hashId):
|
def handleReceivedInventory(self, hashId):
|
||||||
"""Handling received inventory"""
|
"""Handling received inventory"""
|
||||||
|
hashId_bytes = bytes(hashId)
|
||||||
if haveBloom:
|
if haveBloom:
|
||||||
self.invBloom.add(hashId)
|
self.invBloom.add(hashId_bytes)
|
||||||
try:
|
try:
|
||||||
with self.objectsNewToThemLock:
|
with self.objectsNewToThemLock:
|
||||||
del self.objectsNewToThem[hashId]
|
del self.objectsNewToThem[hashId_bytes]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
pass
|
pass
|
||||||
if hashId not in missingObjects:
|
if hashId_bytes not in missingObjects:
|
||||||
missingObjects[hashId] = time.time()
|
missingObjects[hashId_bytes] = time.time()
|
||||||
self.objectsNewToMe[hashId] = True
|
self.objectsNewToMe[hashId] = True
|
||||||
|
|
||||||
def handleReceivedObject(self, streamNumber, hashid):
|
def handleReceivedObject(self, streamNumber, hashid):
|
||||||
"""Handling received object"""
|
"""Handling received object"""
|
||||||
for i in connectionpool.pool.connections():
|
hashid_bytes = bytes(hashid)
|
||||||
|
for i in network.connectionpool.pool.connections():
|
||||||
if not i.fullyEstablished:
|
if not i.fullyEstablished:
|
||||||
continue
|
continue
|
||||||
try:
|
try:
|
||||||
|
@ -110,7 +114,7 @@ class ObjectTracker(object):
|
||||||
not dandelion_ins.hasHash(hashid)
|
not dandelion_ins.hasHash(hashid)
|
||||||
or dandelion_ins.objectChildStem(hashid) == i):
|
or dandelion_ins.objectChildStem(hashid) == i):
|
||||||
with i.objectsNewToThemLock:
|
with i.objectsNewToThemLock:
|
||||||
i.objectsNewToThem[hashid] = time.time()
|
i.objectsNewToThem[hashid_bytes] = time.time()
|
||||||
# update stream number,
|
# update stream number,
|
||||||
# which we didn't have when we just received the dinv
|
# which we didn't have when we just received the dinv
|
||||||
# also resets expiration of the stem mode
|
# also resets expiration of the stem mode
|
||||||
|
@ -119,7 +123,7 @@ class ObjectTracker(object):
|
||||||
if i == self:
|
if i == self:
|
||||||
try:
|
try:
|
||||||
with i.objectsNewToThemLock:
|
with i.objectsNewToThemLock:
|
||||||
del i.objectsNewToThem[hashid]
|
del i.objectsNewToThem[hashid_bytes]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
pass
|
pass
|
||||||
self.objectsNewToMe.setLastObject()
|
self.objectsNewToMe.setLastObject()
|
||||||
|
@ -133,4 +137,4 @@ class ObjectTracker(object):
|
||||||
def addAddr(self, hashid):
|
def addAddr(self, hashid):
|
||||||
"""WIP, should be moved to addrthread.py or removed"""
|
"""WIP, should be moved to addrthread.py or removed"""
|
||||||
if haveBloom:
|
if haveBloom:
|
||||||
self.addrBloom.add(hashid)
|
self.addrBloom.add(bytes(hashid))
|
||||||
|
|
|
@ -6,14 +6,20 @@ import logging
|
||||||
import socket
|
import socket
|
||||||
import time
|
import time
|
||||||
|
|
||||||
import asyncore_pollchoose as asyncore
|
from network import asyncore_pollchoose as asyncore
|
||||||
from advanceddispatcher import AdvancedDispatcher
|
from .advanceddispatcher import AdvancedDispatcher
|
||||||
from bmconfigparser import config
|
from bmconfigparser import config
|
||||||
from node import Peer
|
from .node import Peer
|
||||||
|
|
||||||
logger = logging.getLogger('default')
|
logger = logging.getLogger('default')
|
||||||
|
|
||||||
|
|
||||||
|
def _ends_with(s, tail):
|
||||||
|
try:
|
||||||
|
return s.endswith(tail)
|
||||||
|
except:
|
||||||
|
return s.decode("utf-8", "replace").endswith(tail)
|
||||||
|
|
||||||
class ProxyError(Exception):
|
class ProxyError(Exception):
|
||||||
"""Base proxy exception class"""
|
"""Base proxy exception class"""
|
||||||
errorCodes = ("Unknown error",)
|
errorCodes = ("Unknown error",)
|
||||||
|
@ -125,7 +131,7 @@ class Proxy(AdvancedDispatcher):
|
||||||
self.auth = None
|
self.auth = None
|
||||||
self.connect(
|
self.connect(
|
||||||
self.onion_proxy
|
self.onion_proxy
|
||||||
if address.host.endswith(".onion") and self.onion_proxy else
|
if _ends_with(address.host, ".onion") and self.onion_proxy else
|
||||||
self.proxy
|
self.proxy
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -2,13 +2,13 @@
|
||||||
Process data incoming from network
|
Process data incoming from network
|
||||||
"""
|
"""
|
||||||
import errno
|
import errno
|
||||||
import Queue
|
from six.moves import queue as Queue
|
||||||
import socket
|
import socket
|
||||||
|
|
||||||
import connectionpool
|
from network import connectionpool
|
||||||
from network.advanceddispatcher import UnknownStateError
|
from network.advanceddispatcher import UnknownStateError
|
||||||
from network import receiveDataQueue
|
from network import receiveDataQueue
|
||||||
from threads import StoppableThread
|
from .threads import StoppableThread
|
||||||
|
|
||||||
|
|
||||||
class ReceiveQueueThread(StoppableThread):
|
class ReceiveQueueThread(StoppableThread):
|
||||||
|
|
|
@ -5,8 +5,9 @@ SOCKS4a proxy module
|
||||||
import logging
|
import logging
|
||||||
import socket
|
import socket
|
||||||
import struct
|
import struct
|
||||||
|
import six
|
||||||
|
|
||||||
from proxy import GeneralProxyError, Proxy, ProxyError
|
from .proxy import GeneralProxyError, Proxy, ProxyError
|
||||||
|
|
||||||
logger = logging.getLogger('default')
|
logger = logging.getLogger('default')
|
||||||
|
|
||||||
|
@ -39,16 +40,16 @@ class Socks4a(Proxy):
|
||||||
def state_pre_connect(self):
|
def state_pre_connect(self):
|
||||||
"""Handle feedback from SOCKS4a while it is connecting on our behalf"""
|
"""Handle feedback from SOCKS4a while it is connecting on our behalf"""
|
||||||
# Get the response
|
# Get the response
|
||||||
if self.read_buf[0:1] != chr(0x00).encode():
|
if self.read_buf[0:1] != six.int2byte(0x00):
|
||||||
# bad data
|
# bad data
|
||||||
self.close()
|
self.close()
|
||||||
raise GeneralProxyError(1)
|
raise GeneralProxyError(1)
|
||||||
elif self.read_buf[1:2] != chr(0x5A).encode():
|
elif self.read_buf[1:2] != six.int2byte(0x5A):
|
||||||
# Connection failed
|
# Connection failed
|
||||||
self.close()
|
self.close()
|
||||||
if ord(self.read_buf[1:2]) in (91, 92, 93):
|
if six.byte2int(self.read_buf[1:2]) in (91, 92, 93):
|
||||||
# socks 4 error
|
# socks 4 error
|
||||||
raise Socks4aError(ord(self.read_buf[1:2]) - 90)
|
raise Socks4aError(six.byte2int(self.read_buf[1:2]) - 90)
|
||||||
else:
|
else:
|
||||||
raise Socks4aError(4)
|
raise Socks4aError(4)
|
||||||
# Get the bound address/port
|
# Get the bound address/port
|
||||||
|
@ -102,9 +103,9 @@ class Socks4aConnection(Socks4a):
|
||||||
self.append_write_buf(self.ipaddr)
|
self.append_write_buf(self.ipaddr)
|
||||||
if self._auth:
|
if self._auth:
|
||||||
self.append_write_buf(self._auth[0])
|
self.append_write_buf(self._auth[0])
|
||||||
self.append_write_buf(chr(0x00).encode())
|
self.append_write_buf(six.int2byte(0x00))
|
||||||
if rmtrslv:
|
if rmtrslv:
|
||||||
self.append_write_buf(self.destination[0] + chr(0x00).encode())
|
self.append_write_buf(self.destination[0].encode("utf-8", "replace") + six.int2byte(0x00))
|
||||||
self.set_state("pre_connect", length=0, expectBytes=8)
|
self.set_state("pre_connect", length=0, expectBytes=8)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
@ -132,8 +133,8 @@ class Socks4aResolver(Socks4a):
|
||||||
self.append_write_buf(struct.pack("BBBB", 0x00, 0x00, 0x00, 0x01))
|
self.append_write_buf(struct.pack("BBBB", 0x00, 0x00, 0x00, 0x01))
|
||||||
if self._auth:
|
if self._auth:
|
||||||
self.append_write_buf(self._auth[0])
|
self.append_write_buf(self._auth[0])
|
||||||
self.append_write_buf(chr(0x00).encode())
|
self.append_write_buf(six.int2byte(0x00))
|
||||||
self.append_write_buf(self.host + chr(0x00).encode())
|
self.append_write_buf(self.host + six.int2byte(0x00))
|
||||||
self.set_state("pre_connect", length=0, expectBytes=8)
|
self.set_state("pre_connect", length=0, expectBytes=8)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
|
@ -6,9 +6,10 @@ SOCKS5 proxy module
|
||||||
import logging
|
import logging
|
||||||
import socket
|
import socket
|
||||||
import struct
|
import struct
|
||||||
|
import six
|
||||||
|
|
||||||
from node import Peer
|
from .node import Peer
|
||||||
from proxy import GeneralProxyError, Proxy, ProxyError
|
from .proxy import GeneralProxyError, Proxy, ProxyError
|
||||||
|
|
||||||
logger = logging.getLogger('default')
|
logger = logging.getLogger('default')
|
||||||
|
|
||||||
|
@ -97,20 +98,20 @@ class Socks5(Proxy):
|
||||||
def state_pre_connect(self):
|
def state_pre_connect(self):
|
||||||
"""Handle feedback from socks5 while it is connecting on our behalf."""
|
"""Handle feedback from socks5 while it is connecting on our behalf."""
|
||||||
# Get the response
|
# Get the response
|
||||||
if self.read_buf[0:1] != chr(0x05).encode():
|
if self.read_buf[0:1] != six.int2byte(0x05):
|
||||||
self.close()
|
self.close()
|
||||||
raise GeneralProxyError(1)
|
raise GeneralProxyError(1)
|
||||||
elif self.read_buf[1:2] != chr(0x00).encode():
|
elif self.read_buf[1:2] != six.int2byte(0x00):
|
||||||
# Connection failed
|
# Connection failed
|
||||||
self.close()
|
self.close()
|
||||||
if ord(self.read_buf[1:2]) <= 8:
|
if six.byte2int(self.read_buf[1:2]) <= 8:
|
||||||
raise Socks5Error(ord(self.read_buf[1:2]))
|
raise Socks5Error(six.byte2int(self.read_buf[1:2]))
|
||||||
else:
|
else:
|
||||||
raise Socks5Error(9)
|
raise Socks5Error(9)
|
||||||
# Get the bound address/port
|
# Get the bound address/port
|
||||||
elif self.read_buf[3:4] == chr(0x01).encode():
|
elif self.read_buf[3:4] == six.int2byte(0x01):
|
||||||
self.set_state("proxy_addr_1", length=4, expectBytes=4)
|
self.set_state("proxy_addr_1", length=4, expectBytes=4)
|
||||||
elif self.read_buf[3:4] == chr(0x03).encode():
|
elif self.read_buf[3:4] == six.int2byte(0x03):
|
||||||
self.set_state("proxy_addr_2_1", length=4, expectBytes=1)
|
self.set_state("proxy_addr_2_1", length=4, expectBytes=1)
|
||||||
else:
|
else:
|
||||||
self.close()
|
self.close()
|
||||||
|
@ -129,7 +130,7 @@ class Socks5(Proxy):
|
||||||
(e.g. IPv6, onion, ...). This is part 1 which retrieves the
|
(e.g. IPv6, onion, ...). This is part 1 which retrieves the
|
||||||
length of the data.
|
length of the data.
|
||||||
"""
|
"""
|
||||||
self.address_length = ord(self.read_buf[0:1])
|
self.address_length = six.byte2int(self.read_buf[0:1])
|
||||||
self.set_state(
|
self.set_state(
|
||||||
"proxy_addr_2_2", length=1, expectBytes=self.address_length)
|
"proxy_addr_2_2", length=1, expectBytes=self.address_length)
|
||||||
return True
|
return True
|
||||||
|
@ -171,19 +172,19 @@ class Socks5Connection(Socks5):
|
||||||
# use the IPv4 address request even if remote resolving was specified.
|
# use the IPv4 address request even if remote resolving was specified.
|
||||||
try:
|
try:
|
||||||
self.ipaddr = socket.inet_aton(self.destination[0])
|
self.ipaddr = socket.inet_aton(self.destination[0])
|
||||||
self.append_write_buf(chr(0x01).encode() + self.ipaddr)
|
self.append_write_buf(six.int2byte(0x01) + self.ipaddr)
|
||||||
except socket.error: # may be IPv6!
|
except socket.error: # may be IPv6!
|
||||||
# Well it's not an IP number, so it's probably a DNS name.
|
# Well it's not an IP number, so it's probably a DNS name.
|
||||||
if self._remote_dns:
|
if self._remote_dns:
|
||||||
# Resolve remotely
|
# Resolve remotely
|
||||||
self.ipaddr = None
|
self.ipaddr = None
|
||||||
self.append_write_buf(chr(0x03).encode() + chr(
|
self.append_write_buf(six.int2byte(0x03) + six.int2byte(
|
||||||
len(self.destination[0])).encode() + self.destination[0])
|
len(self.destination[0])) + self.destination[0].encode("utf-8", "replace"))
|
||||||
else:
|
else:
|
||||||
# Resolve locally
|
# Resolve locally
|
||||||
self.ipaddr = socket.inet_aton(
|
self.ipaddr = socket.inet_aton(
|
||||||
socket.gethostbyname(self.destination[0]))
|
socket.gethostbyname(self.destination[0]))
|
||||||
self.append_write_buf(chr(0x01).encode() + self.ipaddr)
|
self.append_write_buf(six.int2byte(0x01) + self.ipaddr)
|
||||||
self.append_write_buf(struct.pack(">H", self.destination[1]))
|
self.append_write_buf(struct.pack(">H", self.destination[1]))
|
||||||
self.set_state("pre_connect", length=0, expectBytes=4)
|
self.set_state("pre_connect", length=0, expectBytes=4)
|
||||||
return True
|
return True
|
||||||
|
@ -208,8 +209,8 @@ class Socks5Resolver(Socks5):
|
||||||
"""Perform resolving"""
|
"""Perform resolving"""
|
||||||
# Now we can request the actual connection
|
# Now we can request the actual connection
|
||||||
self.append_write_buf(struct.pack('BBB', 0x05, 0xF0, 0x00))
|
self.append_write_buf(struct.pack('BBB', 0x05, 0xF0, 0x00))
|
||||||
self.append_write_buf(chr(0x03).encode() + chr(
|
self.append_write_buf(six.int2byte(0x03) + six.int2byte(
|
||||||
len(self.host)).encode() + str(self.host))
|
len(self.host)) + bytes(self.host))
|
||||||
self.append_write_buf(struct.pack(">H", self.port))
|
self.append_write_buf(struct.pack(">H", self.port))
|
||||||
self.set_state("pre_connect", length=0, expectBytes=4)
|
self.set_state("pre_connect", length=0, expectBytes=4)
|
||||||
return True
|
return True
|
||||||
|
|
|
@ -3,9 +3,9 @@ Network statistics
|
||||||
"""
|
"""
|
||||||
import time
|
import time
|
||||||
|
|
||||||
import asyncore_pollchoose as asyncore
|
from network import asyncore_pollchoose as asyncore
|
||||||
import connectionpool
|
from network import connectionpool
|
||||||
from objectracker import missingObjects
|
from .objectracker import missingObjects
|
||||||
|
|
||||||
|
|
||||||
lastReceivedTimestamp = time.time()
|
lastReceivedTimestamp = time.time()
|
||||||
|
|
|
@ -8,28 +8,29 @@ import math
|
||||||
import random
|
import random
|
||||||
import socket
|
import socket
|
||||||
import time
|
import time
|
||||||
|
import six
|
||||||
|
|
||||||
# magic imports!
|
# magic imports!
|
||||||
import addresses
|
import addresses
|
||||||
import l10n
|
import l10n
|
||||||
import protocol
|
import protocol
|
||||||
import state
|
import state
|
||||||
import connectionpool
|
import network.connectionpool # use long name to address recursive import
|
||||||
from bmconfigparser import config
|
from bmconfigparser import config
|
||||||
from highlevelcrypto import randomBytes
|
from highlevelcrypto import randomBytes
|
||||||
from network import dandelion_ins, invQueue, receiveDataQueue
|
from network import dandelion_ins, invQueue, receiveDataQueue
|
||||||
from queues import UISignalQueue
|
from queues import UISignalQueue
|
||||||
from tr import _translate
|
from tr import _translate
|
||||||
|
|
||||||
import asyncore_pollchoose as asyncore
|
from network import asyncore_pollchoose as asyncore
|
||||||
import knownnodes
|
from network import knownnodes
|
||||||
from network.advanceddispatcher import AdvancedDispatcher
|
from network.advanceddispatcher import AdvancedDispatcher
|
||||||
from network.bmproto import BMProto
|
from network.bmproto import BMProto
|
||||||
from network.objectracker import ObjectTracker
|
from network.objectracker import ObjectTracker
|
||||||
from network.socks4a import Socks4aConnection
|
from network.socks4a import Socks4aConnection
|
||||||
from network.socks5 import Socks5Connection
|
from network.socks5 import Socks5Connection
|
||||||
from network.tls import TLSDispatcher
|
from network.tls import TLSDispatcher
|
||||||
from node import Peer
|
from .node import Peer
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger('default')
|
logger = logging.getLogger('default')
|
||||||
|
@ -39,6 +40,12 @@ maximumAgeOfNodesThatIAdvertiseToOthers = 10800 #: Equals three hours
|
||||||
maximumTimeOffsetWrongCount = 3 #: Connections with wrong time offset
|
maximumTimeOffsetWrongCount = 3 #: Connections with wrong time offset
|
||||||
|
|
||||||
|
|
||||||
|
def _ends_with(s, tail):
|
||||||
|
try:
|
||||||
|
return s.endswith(tail)
|
||||||
|
except:
|
||||||
|
return s.decode("utf-8", "replace").endswith(tail)
|
||||||
|
|
||||||
class TCPConnection(BMProto, TLSDispatcher):
|
class TCPConnection(BMProto, TLSDispatcher):
|
||||||
# pylint: disable=too-many-instance-attributes
|
# pylint: disable=too-many-instance-attributes
|
||||||
"""
|
"""
|
||||||
|
@ -138,9 +145,9 @@ class TCPConnection(BMProto, TLSDispatcher):
|
||||||
'updateStatusBar',
|
'updateStatusBar',
|
||||||
_translate(
|
_translate(
|
||||||
"MainWindow",
|
"MainWindow",
|
||||||
"The time on your computer, %1, may be wrong. "
|
"The time on your computer, {0}, may be wrong. "
|
||||||
"Please verify your settings."
|
"Please verify your settings."
|
||||||
).arg(l10n.formatTimestamp())))
|
).format(l10n.formatTimestamp())))
|
||||||
|
|
||||||
def state_connection_fully_established(self):
|
def state_connection_fully_established(self):
|
||||||
"""
|
"""
|
||||||
|
@ -191,10 +198,10 @@ class TCPConnection(BMProto, TLSDispatcher):
|
||||||
# only if more recent than 3 hours
|
# only if more recent than 3 hours
|
||||||
# and having positive or neutral rating
|
# and having positive or neutral rating
|
||||||
filtered = [
|
filtered = [
|
||||||
(k, v) for k, v in nodes.iteritems()
|
(k, v) for k, v in six.iteritems(nodes)
|
||||||
if v["lastseen"] > int(time.time())
|
if v["lastseen"] > int(time.time())
|
||||||
- maximumAgeOfNodesThatIAdvertiseToOthers
|
- maximumAgeOfNodesThatIAdvertiseToOthers
|
||||||
and v["rating"] >= 0 and not k.host.endswith('.onion')
|
and v["rating"] >= 0 and not _ends_with(k.host, '.onion')
|
||||||
]
|
]
|
||||||
# sent 250 only if the remote isn't interested in it
|
# sent 250 only if the remote isn't interested in it
|
||||||
elemCount = min(
|
elemCount = min(
|
||||||
|
@ -220,7 +227,7 @@ class TCPConnection(BMProto, TLSDispatcher):
|
||||||
'Sending huge inv message with %i objects to just this'
|
'Sending huge inv message with %i objects to just this'
|
||||||
' one peer', objectCount)
|
' one peer', objectCount)
|
||||||
self.append_write_buf(protocol.CreatePacket(
|
self.append_write_buf(protocol.CreatePacket(
|
||||||
'inv', addresses.encodeVarint(objectCount) + payload))
|
b'inv', addresses.encodeVarint(objectCount) + payload))
|
||||||
|
|
||||||
# Select all hashes for objects in this stream.
|
# Select all hashes for objects in this stream.
|
||||||
bigInvList = {}
|
bigInvList = {}
|
||||||
|
@ -267,7 +274,7 @@ class TCPConnection(BMProto, TLSDispatcher):
|
||||||
self.append_write_buf(
|
self.append_write_buf(
|
||||||
protocol.assembleVersionMessage(
|
protocol.assembleVersionMessage(
|
||||||
self.destination.host, self.destination.port,
|
self.destination.host, self.destination.port,
|
||||||
connectionpool.pool.streams, dandelion_ins.enabled,
|
network.connectionpool.pool.streams, dandelion_ins.enabled,
|
||||||
False, nodeid=self.nodeid))
|
False, nodeid=self.nodeid))
|
||||||
self.connectedAt = time.time()
|
self.connectedAt = time.time()
|
||||||
receiveDataQueue.put(self.destination)
|
receiveDataQueue.put(self.destination)
|
||||||
|
@ -318,7 +325,7 @@ class Socks5BMConnection(Socks5Connection, TCPConnection):
|
||||||
self.append_write_buf(
|
self.append_write_buf(
|
||||||
protocol.assembleVersionMessage(
|
protocol.assembleVersionMessage(
|
||||||
self.destination.host, self.destination.port,
|
self.destination.host, self.destination.port,
|
||||||
connectionpool.pool.streams, dandelion_ins.enabled,
|
network.connectionpool.pool.streams, dandelion_ins.enabled,
|
||||||
False, nodeid=self.nodeid))
|
False, nodeid=self.nodeid))
|
||||||
self.set_state("bm_header", expectBytes=protocol.Header.size)
|
self.set_state("bm_header", expectBytes=protocol.Header.size)
|
||||||
return True
|
return True
|
||||||
|
@ -342,7 +349,7 @@ class Socks4aBMConnection(Socks4aConnection, TCPConnection):
|
||||||
self.append_write_buf(
|
self.append_write_buf(
|
||||||
protocol.assembleVersionMessage(
|
protocol.assembleVersionMessage(
|
||||||
self.destination.host, self.destination.port,
|
self.destination.host, self.destination.port,
|
||||||
connectionpool.pool.streams, dandelion_ins.enabled,
|
network.connectionpool.pool.streams, dandelion_ins.enabled,
|
||||||
False, nodeid=self.nodeid))
|
False, nodeid=self.nodeid))
|
||||||
self.set_state("bm_header", expectBytes=protocol.Header.size)
|
self.set_state("bm_header", expectBytes=protocol.Header.size)
|
||||||
return True
|
return True
|
||||||
|
@ -430,7 +437,7 @@ class TCPServer(AdvancedDispatcher):
|
||||||
|
|
||||||
state.ownAddresses[Peer(*sock.getsockname())] = True
|
state.ownAddresses[Peer(*sock.getsockname())] = True
|
||||||
if (
|
if (
|
||||||
len(connectionpool.pool)
|
len(network.connectionpool.pool)
|
||||||
> config.safeGetInt(
|
> config.safeGetInt(
|
||||||
'bitmessagesettings', 'maxtotalconnections')
|
'bitmessagesettings', 'maxtotalconnections')
|
||||||
+ config.safeGetInt(
|
+ config.safeGetInt(
|
||||||
|
@ -442,7 +449,7 @@ class TCPServer(AdvancedDispatcher):
|
||||||
sock.close()
|
sock.close()
|
||||||
return
|
return
|
||||||
try:
|
try:
|
||||||
connectionpool.pool.addConnection(
|
network.connectionpool.pool.addConnection(
|
||||||
TCPConnection(sock=sock))
|
TCPConnection(sock=sock))
|
||||||
except socket.error:
|
except socket.error:
|
||||||
pass
|
pass
|
||||||
|
|
|
@ -6,6 +6,7 @@ import os
|
||||||
import socket
|
import socket
|
||||||
import ssl
|
import ssl
|
||||||
import sys
|
import sys
|
||||||
|
import six
|
||||||
|
|
||||||
import network.asyncore_pollchoose as asyncore
|
import network.asyncore_pollchoose as asyncore
|
||||||
import paths
|
import paths
|
||||||
|
@ -34,7 +35,7 @@ else:
|
||||||
# ciphers
|
# ciphers
|
||||||
if (
|
if (
|
||||||
ssl.OPENSSL_VERSION_NUMBER >= 0x10100000
|
ssl.OPENSSL_VERSION_NUMBER >= 0x10100000
|
||||||
and not ssl.OPENSSL_VERSION.startswith(b"LibreSSL")
|
and not ssl.OPENSSL_VERSION.startswith("LibreSSL")
|
||||||
):
|
):
|
||||||
sslProtocolCiphers = "AECDH-AES256-SHA@SECLEVEL=0"
|
sslProtocolCiphers = "AECDH-AES256-SHA@SECLEVEL=0"
|
||||||
else:
|
else:
|
||||||
|
@ -58,14 +59,29 @@ class TLSDispatcher(AdvancedDispatcher):
|
||||||
self.tlsDone = False
|
self.tlsDone = False
|
||||||
self.tlsVersion = "N/A"
|
self.tlsVersion = "N/A"
|
||||||
self.isSSL = False
|
self.isSSL = False
|
||||||
|
if six.PY3 or ssl.OPENSSL_VERSION_NUMBER >= 0x30000000:
|
||||||
|
self.tlsPrepared = False
|
||||||
|
|
||||||
def state_tls_init(self):
|
def state_tls_init(self):
|
||||||
"""Prepare sockets for TLS handshake"""
|
"""Prepare sockets for TLS handshake"""
|
||||||
self.isSSL = True
|
self.isSSL = True
|
||||||
self.tlsStarted = True
|
self.tlsStarted = True
|
||||||
|
|
||||||
|
if six.PY3 or ssl.OPENSSL_VERSION_NUMBER >= 0x30000000:
|
||||||
|
self.want_read = self.want_write = True
|
||||||
|
self.set_state("tls_handshake")
|
||||||
|
return False
|
||||||
|
|
||||||
|
return self.do_tls_init()
|
||||||
|
|
||||||
|
def do_tls_init(self):
|
||||||
# Once the connection has been established,
|
# Once the connection has been established,
|
||||||
# it's safe to wrap the socket.
|
# it's safe to wrap the socket.
|
||||||
if sys.version_info >= (2, 7, 9):
|
if sys.version_info >= (2, 7, 9):
|
||||||
|
if ssl.OPENSSL_VERSION_NUMBER >= 0x30000000:
|
||||||
|
context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER
|
||||||
|
if self.server_side else ssl.PROTOCOL_TLS_CLIENT)
|
||||||
|
else:
|
||||||
context = ssl.create_default_context(
|
context = ssl.create_default_context(
|
||||||
purpose=ssl.Purpose.SERVER_AUTH
|
purpose=ssl.Purpose.SERVER_AUTH
|
||||||
if self.server_side else ssl.Purpose.CLIENT_AUTH)
|
if self.server_side else ssl.Purpose.CLIENT_AUTH)
|
||||||
|
@ -74,6 +90,11 @@ class TLSDispatcher(AdvancedDispatcher):
|
||||||
context.check_hostname = False
|
context.check_hostname = False
|
||||||
context.verify_mode = ssl.CERT_NONE
|
context.verify_mode = ssl.CERT_NONE
|
||||||
# also exclude TLSv1 and TLSv1.1 in the future
|
# also exclude TLSv1 and TLSv1.1 in the future
|
||||||
|
if ssl.OPENSSL_VERSION_NUMBER >= 0x30000000:
|
||||||
|
context.options = ssl.OP_ALL | ssl.OP_NO_SSLv2 |\
|
||||||
|
ssl.OP_NO_SSLv3 | ssl.OP_SINGLE_ECDH_USE |\
|
||||||
|
ssl.OP_CIPHER_SERVER_PREFERENCE | ssl.OP_NO_TLSv1_3
|
||||||
|
else:
|
||||||
context.options = ssl.OP_ALL | ssl.OP_NO_SSLv2 |\
|
context.options = ssl.OP_ALL | ssl.OP_NO_SSLv2 |\
|
||||||
ssl.OP_NO_SSLv3 | ssl.OP_SINGLE_ECDH_USE |\
|
ssl.OP_NO_SSLv3 | ssl.OP_SINGLE_ECDH_USE |\
|
||||||
ssl.OP_CIPHER_SERVER_PREFERENCE
|
ssl.OP_CIPHER_SERVER_PREFERENCE
|
||||||
|
@ -88,6 +109,9 @@ class TLSDispatcher(AdvancedDispatcher):
|
||||||
ciphers=self.ciphers, do_handshake_on_connect=False)
|
ciphers=self.ciphers, do_handshake_on_connect=False)
|
||||||
self.sslSocket.setblocking(0)
|
self.sslSocket.setblocking(0)
|
||||||
self.want_read = self.want_write = True
|
self.want_read = self.want_write = True
|
||||||
|
if six.PY3 or ssl.OPENSSL_VERSION_NUMBER >= 0x30000000:
|
||||||
|
self.tlsPrepared = True
|
||||||
|
else:
|
||||||
self.set_state("tls_handshake")
|
self.set_state("tls_handshake")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
@ -114,6 +138,8 @@ class TLSDispatcher(AdvancedDispatcher):
|
||||||
# during TLS handshake, and after flushing write buffer,
|
# during TLS handshake, and after flushing write buffer,
|
||||||
# return status of last handshake attempt
|
# return status of last handshake attempt
|
||||||
if self.tlsStarted and not self.tlsDone and not self.write_buf:
|
if self.tlsStarted and not self.tlsDone and not self.write_buf:
|
||||||
|
# with OpenSSL 3, excessive logs are spitted
|
||||||
|
if ssl.OPENSSL_VERSION_NUMBER < 0x30000000:
|
||||||
logger.debug('tls readable, %r', self.want_read)
|
logger.debug('tls readable, %r', self.want_read)
|
||||||
return self.want_read
|
return self.want_read
|
||||||
# prior to TLS handshake,
|
# prior to TLS handshake,
|
||||||
|
@ -134,6 +160,10 @@ class TLSDispatcher(AdvancedDispatcher):
|
||||||
try:
|
try:
|
||||||
# wait for write buffer flush
|
# wait for write buffer flush
|
||||||
if self.tlsStarted and not self.tlsDone and not self.write_buf:
|
if self.tlsStarted and not self.tlsDone and not self.write_buf:
|
||||||
|
if six.PY3 or ssl.OPENSSL_VERSION_NUMBER >= 0x30000000:
|
||||||
|
if not self.tlsPrepared:
|
||||||
|
self.do_tls_init()
|
||||||
|
return
|
||||||
self.tls_handshake()
|
self.tls_handshake()
|
||||||
else:
|
else:
|
||||||
AdvancedDispatcher.handle_read(self)
|
AdvancedDispatcher.handle_read(self)
|
||||||
|
@ -156,6 +186,10 @@ class TLSDispatcher(AdvancedDispatcher):
|
||||||
try:
|
try:
|
||||||
# wait for write buffer flush
|
# wait for write buffer flush
|
||||||
if self.tlsStarted and not self.tlsDone and not self.write_buf:
|
if self.tlsStarted and not self.tlsDone and not self.write_buf:
|
||||||
|
if six.PY3 or ssl.OPENSSL_VERSION_NUMBER >= 0x30000000:
|
||||||
|
if not self.tlsPrepared:
|
||||||
|
self.do_tls_init()
|
||||||
|
return
|
||||||
self.tls_handshake()
|
self.tls_handshake()
|
||||||
else:
|
else:
|
||||||
AdvancedDispatcher.handle_write(self)
|
AdvancedDispatcher.handle_write(self)
|
||||||
|
|
|
@ -8,12 +8,12 @@ import time
|
||||||
# magic imports!
|
# magic imports!
|
||||||
import protocol
|
import protocol
|
||||||
import state
|
import state
|
||||||
import connectionpool
|
import network.connectionpool # use long name to address recursive import
|
||||||
|
|
||||||
from network import receiveDataQueue
|
from network import receiveDataQueue
|
||||||
from bmproto import BMProto
|
from .bmproto import BMProto
|
||||||
from node import Peer
|
from .node import Peer
|
||||||
from objectracker import ObjectTracker
|
from .objectracker import ObjectTracker
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger('default')
|
logger = logging.getLogger('default')
|
||||||
|
@ -81,8 +81,8 @@ class UDPSocket(BMProto): # pylint: disable=too-many-instance-attributes
|
||||||
return True
|
return True
|
||||||
remoteport = False
|
remoteport = False
|
||||||
for seenTime, stream, _, ip, port in addresses:
|
for seenTime, stream, _, ip, port in addresses:
|
||||||
decodedIP = protocol.checkIPAddress(str(ip))
|
decodedIP = protocol.checkIPAddress(ip)
|
||||||
if stream not in connectionpool.pool.streams:
|
if stream not in network.connectionpool.pool.streams:
|
||||||
continue
|
continue
|
||||||
if (seenTime < time.time() - protocol.MAX_TIME_OFFSET
|
if (seenTime < time.time() - protocol.MAX_TIME_OFFSET
|
||||||
or seenTime > time.time() + protocol.MAX_TIME_OFFSET):
|
or seenTime > time.time() + protocol.MAX_TIME_OFFSET):
|
||||||
|
|
|
@ -6,10 +6,10 @@ import time
|
||||||
import random
|
import random
|
||||||
import protocol
|
import protocol
|
||||||
import state
|
import state
|
||||||
import connectionpool
|
from network import connectionpool
|
||||||
from randomtrackingdict import RandomTrackingDict
|
from randomtrackingdict import RandomTrackingDict
|
||||||
from network import dandelion_ins
|
from network import dandelion_ins
|
||||||
from threads import StoppableThread
|
from .threads import StoppableThread
|
||||||
|
|
||||||
|
|
||||||
class UploadThread(StoppableThread):
|
class UploadThread(StoppableThread):
|
||||||
|
@ -50,7 +50,7 @@ class UploadThread(StoppableThread):
|
||||||
break
|
break
|
||||||
try:
|
try:
|
||||||
payload.extend(protocol.CreatePacket(
|
payload.extend(protocol.CreatePacket(
|
||||||
'object', state.Inventory[chunk].payload))
|
b'object', state.Inventory[chunk].payload))
|
||||||
chunk_count += 1
|
chunk_count += 1
|
||||||
except KeyError:
|
except KeyError:
|
||||||
i.antiIntersectionDelay()
|
i.antiIntersectionDelay()
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
A menu plugin showing QR-Code for bitmessage address in modal dialog.
|
A menu plugin showing QR-Code for bitmessage address in modal dialog.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import urllib
|
from six.moves.urllib.parse import urlencode
|
||||||
|
|
||||||
import qrcode
|
import qrcode
|
||||||
from PyQt4 import QtCore, QtGui
|
from PyQt4 import QtCore, QtGui
|
||||||
|
@ -93,7 +93,7 @@ def connect_plugin(form):
|
||||||
return
|
return
|
||||||
dialog.render(
|
dialog.render(
|
||||||
'bitmessage:%s' % account.address + (
|
'bitmessage:%s' % account.address + (
|
||||||
'?' + urllib.urlencode({'label': label.encode('utf-8')})
|
'?' + urlencode({'label': label.encode('utf-8')})
|
||||||
if label != account.address else '')
|
if label != account.address else '')
|
||||||
)
|
)
|
||||||
dialog.exec_()
|
dialog.exec_()
|
||||||
|
|
|
@ -12,6 +12,8 @@ import sys
|
||||||
import time
|
import time
|
||||||
from binascii import hexlify
|
from binascii import hexlify
|
||||||
from struct import Struct, pack, unpack
|
from struct import Struct, pack, unpack
|
||||||
|
import six
|
||||||
|
import sqlite3
|
||||||
|
|
||||||
import defaults
|
import defaults
|
||||||
import highlevelcrypto
|
import highlevelcrypto
|
||||||
|
@ -23,6 +25,7 @@ from debug import logger
|
||||||
from helper_sql import sqlExecute
|
from helper_sql import sqlExecute
|
||||||
from network.node import Peer
|
from network.node import Peer
|
||||||
from version import softwareVersion
|
from version import softwareVersion
|
||||||
|
from dbcompat import dbstr
|
||||||
|
|
||||||
# Network constants
|
# Network constants
|
||||||
magic = 0xE9BEB4D9
|
magic = 0xE9BEB4D9
|
||||||
|
@ -168,11 +171,11 @@ def checkIPAddress(host, private=False):
|
||||||
otherwise returns False
|
otherwise returns False
|
||||||
"""
|
"""
|
||||||
if host[0:12] == b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF':
|
if host[0:12] == b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF':
|
||||||
hostStandardFormat = socket.inet_ntop(socket.AF_INET, host[12:])
|
hostStandardFormat = socket.inet_ntop(socket.AF_INET, bytes(host[12:]))
|
||||||
return checkIPv4Address(host[12:], hostStandardFormat, private)
|
return checkIPv4Address(host[12:], hostStandardFormat, private)
|
||||||
elif host[0:6] == b'\xfd\x87\xd8\x7e\xeb\x43':
|
elif host[0:6] == b'\xfd\x87\xd8\x7e\xeb\x43':
|
||||||
# Onion, based on BMD/bitcoind
|
# Onion, based on BMD/bitcoind
|
||||||
hostStandardFormat = base64.b32encode(host[6:]).lower() + ".onion"
|
hostStandardFormat = base64.b32encode(host[6:]).lower() + b".onion"
|
||||||
if private:
|
if private:
|
||||||
return False
|
return False
|
||||||
return hostStandardFormat
|
return hostStandardFormat
|
||||||
|
@ -227,7 +230,7 @@ def checkIPv6Address(host, hostStandardFormat, private=False):
|
||||||
logger.debug('Ignoring loopback address: %s', hostStandardFormat)
|
logger.debug('Ignoring loopback address: %s', hostStandardFormat)
|
||||||
return False
|
return False
|
||||||
try:
|
try:
|
||||||
host = [ord(c) for c in host[:2]]
|
host = [six.byte2int(c) for c in host[:2]]
|
||||||
except TypeError: # python3 has ints already
|
except TypeError: # python3 has ints already
|
||||||
pass
|
pass
|
||||||
if host[0] == 0xfe and host[1] & 0xc0 == 0x80:
|
if host[0] == 0xfe and host[1] & 0xc0 == 0x80:
|
||||||
|
@ -293,7 +296,7 @@ def isProofOfWorkSufficient(
|
||||||
if TTL < 300:
|
if TTL < 300:
|
||||||
TTL = 300
|
TTL = 300
|
||||||
POW, = unpack('>Q', highlevelcrypto.double_sha512(
|
POW, = unpack('>Q', highlevelcrypto.double_sha512(
|
||||||
data[:8] + hashlib.sha512(data[8:]).digest())[0:8])
|
bytes(data[:8]) + hashlib.sha512(data[8:]).digest())[0:8])
|
||||||
return POW <= 2 ** 64 / (
|
return POW <= 2 ** 64 / (
|
||||||
nonceTrialsPerByte * (
|
nonceTrialsPerByte * (
|
||||||
len(data) + payloadLengthExtraBytes
|
len(data) + payloadLengthExtraBytes
|
||||||
|
@ -417,7 +420,7 @@ def assembleVersionMessage( # pylint: disable=too-many-arguments
|
||||||
return CreatePacket(b'version', payload)
|
return CreatePacket(b'version', payload)
|
||||||
|
|
||||||
|
|
||||||
def assembleErrorMessage(fatal=0, banTime=0, inventoryVector='', errorText=''):
|
def assembleErrorMessage(fatal=0, banTime=0, inventoryVector=b'', errorText=''):
|
||||||
"""
|
"""
|
||||||
Construct the payload of an error message,
|
Construct the payload of an error message,
|
||||||
return the resulting bytes of running `CreatePacket` on it
|
return the resulting bytes of running `CreatePacket` on it
|
||||||
|
@ -426,6 +429,8 @@ def assembleErrorMessage(fatal=0, banTime=0, inventoryVector='', errorText=''):
|
||||||
payload += encodeVarint(banTime)
|
payload += encodeVarint(banTime)
|
||||||
payload += encodeVarint(len(inventoryVector))
|
payload += encodeVarint(len(inventoryVector))
|
||||||
payload += inventoryVector
|
payload += inventoryVector
|
||||||
|
if isinstance(errorText, str):
|
||||||
|
errorText = errorText.encode("utf-8", "replace")
|
||||||
payload += encodeVarint(len(errorText))
|
payload += encodeVarint(len(errorText))
|
||||||
payload += errorText
|
payload += errorText
|
||||||
return CreatePacket(b'error', payload)
|
return CreatePacket(b'error', payload)
|
||||||
|
@ -465,7 +470,7 @@ def decryptAndCheckPubkeyPayload(data, address):
|
||||||
readPosition += varintLength
|
readPosition += varintLength
|
||||||
# We'll store the address version and stream number
|
# We'll store the address version and stream number
|
||||||
# (and some more) in the pubkeys table.
|
# (and some more) in the pubkeys table.
|
||||||
storedData = data[20:readPosition]
|
storedData = bytes(data[20:readPosition])
|
||||||
|
|
||||||
if addressVersion != embeddedAddressVersion:
|
if addressVersion != embeddedAddressVersion:
|
||||||
logger.info(
|
logger.info(
|
||||||
|
@ -482,11 +487,11 @@ def decryptAndCheckPubkeyPayload(data, address):
|
||||||
readPosition += 32
|
readPosition += 32
|
||||||
# the time through the tag. More data is appended onto
|
# the time through the tag. More data is appended onto
|
||||||
# signedData below after the decryption.
|
# signedData below after the decryption.
|
||||||
signedData = data[8:readPosition]
|
signedData = bytes(data[8:readPosition])
|
||||||
encryptedData = data[readPosition:]
|
encryptedData = data[readPosition:]
|
||||||
|
|
||||||
# Let us try to decrypt the pubkey
|
# Let us try to decrypt the pubkey
|
||||||
toAddress, cryptorObject = state.neededPubkeys[tag]
|
toAddress, cryptorObject = state.neededPubkeys[bytes(tag)]
|
||||||
if toAddress != address:
|
if toAddress != address:
|
||||||
logger.critical(
|
logger.critical(
|
||||||
'decryptAndCheckPubkeyPayload failed due to toAddress'
|
'decryptAndCheckPubkeyPayload failed due to toAddress'
|
||||||
|
@ -511,9 +516,9 @@ def decryptAndCheckPubkeyPayload(data, address):
|
||||||
readPosition = 0
|
readPosition = 0
|
||||||
# bitfieldBehaviors = decryptedData[readPosition:readPosition + 4]
|
# bitfieldBehaviors = decryptedData[readPosition:readPosition + 4]
|
||||||
readPosition += 4
|
readPosition += 4
|
||||||
pubSigningKey = '\x04' + decryptedData[readPosition:readPosition + 64]
|
pubSigningKey = b'\x04' + decryptedData[readPosition:readPosition + 64]
|
||||||
readPosition += 64
|
readPosition += 64
|
||||||
pubEncryptionKey = '\x04' + decryptedData[readPosition:readPosition + 64]
|
pubEncryptionKey = b'\x04' + decryptedData[readPosition:readPosition + 64]
|
||||||
readPosition += 64
|
readPosition += 64
|
||||||
specifiedNonceTrialsPerByteLength = decodeVarint(
|
specifiedNonceTrialsPerByteLength = decodeVarint(
|
||||||
decryptedData[readPosition:readPosition + 10])[1]
|
decryptedData[readPosition:readPosition + 10])[1]
|
||||||
|
@ -558,7 +563,7 @@ def decryptAndCheckPubkeyPayload(data, address):
|
||||||
hexlify(pubSigningKey), hexlify(pubEncryptionKey)
|
hexlify(pubSigningKey), hexlify(pubEncryptionKey)
|
||||||
)
|
)
|
||||||
|
|
||||||
t = (address, addressVersion, storedData, int(time.time()), 'yes')
|
t = (dbstr(address), addressVersion, sqlite3.Binary(storedData), int(time.time()), dbstr('yes'))
|
||||||
sqlExecute('''INSERT INTO pubkeys VALUES (?,?,?,?,?)''', *t)
|
sqlExecute('''INSERT INTO pubkeys VALUES (?,?,?,?,?)''', *t)
|
||||||
return 'successful'
|
return 'successful'
|
||||||
except varintDecodeError:
|
except varintDecodeError:
|
||||||
|
|
13
src/py3bitmessage
Executable file
13
src/py3bitmessage
Executable file
|
@ -0,0 +1,13 @@
|
||||||
|
#!/usr/bin/python3
|
||||||
|
|
||||||
|
import os
|
||||||
|
import pkg_resources
|
||||||
|
|
||||||
|
import pybitmessage
|
||||||
|
|
||||||
|
dist = pkg_resources.get_distribution('pybitmessage')
|
||||||
|
script_file = os.path.join(dist.location, dist.key, 'bitmessagemain.py')
|
||||||
|
new_globals = globals()
|
||||||
|
new_globals.update(__file__=script_file)
|
||||||
|
|
||||||
|
execfile(script_file, new_globals)
|
0
src/pybitmessage
Normal file → Executable file
0
src/pybitmessage
Normal file → Executable file
|
@ -3,6 +3,7 @@ Arithmetic Expressions
|
||||||
"""
|
"""
|
||||||
import hashlib
|
import hashlib
|
||||||
import re
|
import re
|
||||||
|
import six
|
||||||
|
|
||||||
P = 2**256 - 2**32 - 2**9 - 2**8 - 2**7 - 2**6 - 2**4 - 1
|
P = 2**256 - 2**32 - 2**9 - 2**8 - 2**7 - 2**6 - 2**4 - 1
|
||||||
A = 0
|
A = 0
|
||||||
|
@ -34,7 +35,7 @@ def get_code_string(base):
|
||||||
return b'123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
|
return b'123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
|
||||||
if base == 256:
|
if base == 256:
|
||||||
try:
|
try:
|
||||||
return b''.join([chr(x) for x in range(256)])
|
return b''.join([six.int2byte(x) for x in range(256)])
|
||||||
except TypeError:
|
except TypeError:
|
||||||
return bytes([x for x in range(256)])
|
return bytes([x for x in range(256)])
|
||||||
|
|
||||||
|
|
|
@ -30,7 +30,7 @@ class Cipher(object):
|
||||||
self.ctx = OpenSSL.EVP_CIPHER_CTX_new()
|
self.ctx = OpenSSL.EVP_CIPHER_CTX_new()
|
||||||
if do == 1 or do == 0:
|
if do == 1 or do == 0:
|
||||||
k = OpenSSL.malloc(key, len(key))
|
k = OpenSSL.malloc(key, len(key))
|
||||||
IV = OpenSSL.malloc(iv, len(iv))
|
IV = OpenSSL.malloc(bytes(iv), len(iv))
|
||||||
OpenSSL.EVP_CipherInit_ex(
|
OpenSSL.EVP_CipherInit_ex(
|
||||||
self.ctx, self.cipher.get_pointer(), 0, k, IV, do)
|
self.ctx, self.cipher.get_pointer(), 0, k, IV, do)
|
||||||
else:
|
else:
|
||||||
|
@ -59,7 +59,7 @@ class Cipher(object):
|
||||||
"""Update result with more data"""
|
"""Update result with more data"""
|
||||||
i = OpenSSL.c_int(0)
|
i = OpenSSL.c_int(0)
|
||||||
buffer = OpenSSL.malloc(b"", len(input) + self.cipher.get_blocksize())
|
buffer = OpenSSL.malloc(b"", len(input) + self.cipher.get_blocksize())
|
||||||
inp = OpenSSL.malloc(input, len(input))
|
inp = OpenSSL.malloc(bytes(input), len(input))
|
||||||
if OpenSSL.EVP_CipherUpdate(self.ctx, OpenSSL.byref(buffer),
|
if OpenSSL.EVP_CipherUpdate(self.ctx, OpenSSL.byref(buffer),
|
||||||
OpenSSL.byref(i), inp, len(input)) == 0:
|
OpenSSL.byref(i), inp, len(input)) == 0:
|
||||||
raise Exception("[OpenSSL] EVP_CipherUpdate FAIL ...")
|
raise Exception("[OpenSSL] EVP_CipherUpdate FAIL ...")
|
||||||
|
|
|
@ -7,6 +7,7 @@ Asymmetric cryptography using elliptic curves
|
||||||
|
|
||||||
from hashlib import sha512
|
from hashlib import sha512
|
||||||
from struct import pack, unpack
|
from struct import pack, unpack
|
||||||
|
from ctypes import c_char_p
|
||||||
|
|
||||||
from .cipher import Cipher
|
from .cipher import Cipher
|
||||||
from .hash import equals, hmac_sha256
|
from .hash import equals, hmac_sha256
|
||||||
|
@ -218,8 +219,8 @@ class ECC(object):
|
||||||
if other_key == 0:
|
if other_key == 0:
|
||||||
raise Exception("[OpenSSL] EC_KEY_new_by_curve_name FAIL ...")
|
raise Exception("[OpenSSL] EC_KEY_new_by_curve_name FAIL ...")
|
||||||
|
|
||||||
other_pub_key_x = OpenSSL.BN_bin2bn(pubkey_x, len(pubkey_x), None)
|
other_pub_key_x = OpenSSL.BN_bin2bn(c_char_p(bytes(pubkey_x)), len(pubkey_x), None)
|
||||||
other_pub_key_y = OpenSSL.BN_bin2bn(pubkey_y, len(pubkey_y), None)
|
other_pub_key_y = OpenSSL.BN_bin2bn(c_char_p(bytes(pubkey_y)), len(pubkey_y), None)
|
||||||
|
|
||||||
other_group = OpenSSL.EC_KEY_get0_group(other_key)
|
other_group = OpenSSL.EC_KEY_get0_group(other_key)
|
||||||
other_pub_key = OpenSSL.EC_POINT_new(other_group)
|
other_pub_key = OpenSSL.EC_POINT_new(other_group)
|
||||||
|
|
|
@ -4,6 +4,8 @@ Wrappers for hash functions from OpenSSL.
|
||||||
# Copyright (C) 2011 Yann GUIBET <yannguibet@gmail.com>
|
# Copyright (C) 2011 Yann GUIBET <yannguibet@gmail.com>
|
||||||
# See LICENSE for details.
|
# See LICENSE for details.
|
||||||
|
|
||||||
|
import six
|
||||||
|
|
||||||
from .openssl import OpenSSL
|
from .openssl import OpenSSL
|
||||||
|
|
||||||
|
|
||||||
|
@ -22,7 +24,7 @@ def _equals_str(a, b):
|
||||||
return False
|
return False
|
||||||
result = 0
|
result = 0
|
||||||
for x, y in zip(a, b):
|
for x, y in zip(a, b):
|
||||||
result |= ord(x) ^ ord(y)
|
result |= six.byte2int(x) ^ six.byte2int(y)
|
||||||
return result == 0
|
return result == 0
|
||||||
|
|
||||||
|
|
||||||
|
@ -38,7 +40,7 @@ def hmac_sha256(k, m):
|
||||||
Compute the key and the message with HMAC SHA5256
|
Compute the key and the message with HMAC SHA5256
|
||||||
"""
|
"""
|
||||||
key = OpenSSL.malloc(k, len(k))
|
key = OpenSSL.malloc(k, len(k))
|
||||||
d = OpenSSL.malloc(m, len(m))
|
d = OpenSSL.malloc(bytes(m), len(m))
|
||||||
md = OpenSSL.malloc(0, 32)
|
md = OpenSSL.malloc(0, 32)
|
||||||
i = OpenSSL.pointer(OpenSSL.c_int(0))
|
i = OpenSSL.pointer(OpenSSL.c_int(0))
|
||||||
OpenSSL.HMAC(OpenSSL.EVP_sha256(), key, len(k), d, len(m), md, i)
|
OpenSSL.HMAC(OpenSSL.EVP_sha256(), key, len(k), d, len(m), md, i)
|
||||||
|
|
|
@ -8,6 +8,7 @@ needed openssl functionality in class _OpenSSL.
|
||||||
"""
|
"""
|
||||||
import ctypes
|
import ctypes
|
||||||
import sys
|
import sys
|
||||||
|
import six
|
||||||
|
|
||||||
# pylint: disable=protected-access
|
# pylint: disable=protected-access
|
||||||
|
|
||||||
|
@ -691,7 +692,7 @@ class _OpenSSL(object):
|
||||||
length = self.BN_num_bytes(x)
|
length = self.BN_num_bytes(x)
|
||||||
data = self.malloc(0, length)
|
data = self.malloc(0, length)
|
||||||
OpenSSL.BN_bn2bin(x, data)
|
OpenSSL.BN_bn2bin(x, data)
|
||||||
return ord(data[length - 1]) & 1
|
return six.byte2int(data[length - 1]) & 1
|
||||||
|
|
||||||
def get_cipher(self, name):
|
def get_cipher(self, name):
|
||||||
"""
|
"""
|
||||||
|
@ -745,7 +746,7 @@ class _OpenSSL(object):
|
||||||
"""
|
"""
|
||||||
buffer_ = None
|
buffer_ = None
|
||||||
if data != 0:
|
if data != 0:
|
||||||
if sys.version_info.major == 3 and isinstance(data, type('')):
|
if six.PY3 and isinstance(data, type('')):
|
||||||
data = data.encode()
|
data = data.encode()
|
||||||
buffer_ = self.create_string_buffer(data, size)
|
buffer_ = self.create_string_buffer(data, size)
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -38,10 +38,10 @@ class RandomTrackingDict(object):
|
||||||
return self.len
|
return self.len
|
||||||
|
|
||||||
def __contains__(self, key):
|
def __contains__(self, key):
|
||||||
return key in self.dictionary
|
return bytes(key) in self.dictionary
|
||||||
|
|
||||||
def __getitem__(self, key):
|
def __getitem__(self, key):
|
||||||
return self.dictionary[key][1]
|
return self.dictionary[bytes(key)][1]
|
||||||
|
|
||||||
def _swap(self, i1, i2):
|
def _swap(self, i1, i2):
|
||||||
with self.lock:
|
with self.lock:
|
||||||
|
@ -49,26 +49,28 @@ class RandomTrackingDict(object):
|
||||||
key2 = self.indexDict[i2]
|
key2 = self.indexDict[i2]
|
||||||
self.indexDict[i1] = key2
|
self.indexDict[i1] = key2
|
||||||
self.indexDict[i2] = key1
|
self.indexDict[i2] = key1
|
||||||
self.dictionary[key1][0] = i2
|
self.dictionary[bytes(key1)][0] = i2
|
||||||
self.dictionary[key2][0] = i1
|
self.dictionary[bytes(key2)][0] = i1
|
||||||
# for quick reassignment
|
# for quick reassignment
|
||||||
return i2
|
return i2
|
||||||
|
|
||||||
def __setitem__(self, key, value):
|
def __setitem__(self, key, value):
|
||||||
with self.lock:
|
with self.lock:
|
||||||
if key in self.dictionary:
|
key_bytes = bytes(key)
|
||||||
self.dictionary[key][1] = value
|
if key_bytes in self.dictionary:
|
||||||
|
self.dictionary[key_bytes][1] = value
|
||||||
else:
|
else:
|
||||||
self.indexDict.append(key)
|
self.indexDict.append(key)
|
||||||
self.dictionary[key] = [self.len, value]
|
self.dictionary[key_bytes] = [self.len, value]
|
||||||
self._swap(self.len, self.len - self.pendingLen)
|
self._swap(self.len, self.len - self.pendingLen)
|
||||||
self.len += 1
|
self.len += 1
|
||||||
|
|
||||||
def __delitem__(self, key):
|
def __delitem__(self, key):
|
||||||
if key not in self.dictionary:
|
key_bytes = bytes(key)
|
||||||
|
if key_bytes not in self.dictionary:
|
||||||
raise KeyError
|
raise KeyError
|
||||||
with self.lock:
|
with self.lock:
|
||||||
index = self.dictionary[key][0]
|
index = self.dictionary[key_bytes][0]
|
||||||
# not pending
|
# not pending
|
||||||
if index < self.len - self.pendingLen:
|
if index < self.len - self.pendingLen:
|
||||||
# left of pending part
|
# left of pending part
|
||||||
|
@ -82,7 +84,7 @@ class RandomTrackingDict(object):
|
||||||
# operation can improve 4x, but it's already very fast so we'll
|
# operation can improve 4x, but it's already very fast so we'll
|
||||||
# ignore it for the time being
|
# ignore it for the time being
|
||||||
del self.indexDict[-1]
|
del self.indexDict[-1]
|
||||||
del self.dictionary[key]
|
del self.dictionary[key_bytes]
|
||||||
self.len -= 1
|
self.len -= 1
|
||||||
|
|
||||||
def setMaxPending(self, maxPending):
|
def setMaxPending(self, maxPending):
|
||||||
|
|
52
src/revert_blob_to_text.py
Normal file
52
src/revert_blob_to_text.py
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
import helper_startup
|
||||||
|
import state
|
||||||
|
import shutil
|
||||||
|
import sqlite3
|
||||||
|
|
||||||
|
expected_ver = 11
|
||||||
|
|
||||||
|
print("Looking up database file..")
|
||||||
|
helper_startup.loadConfig()
|
||||||
|
db_path = state.appdata + "messages.dat"
|
||||||
|
print("Database path: {}".format(db_path))
|
||||||
|
db_backup_path = db_path + ".blob-keys"
|
||||||
|
print("Backup path: {}".format(db_backup_path))
|
||||||
|
shutil.copyfile(db_path, db_backup_path)
|
||||||
|
print("Copied to backup")
|
||||||
|
|
||||||
|
print()
|
||||||
|
|
||||||
|
print("Open the database")
|
||||||
|
conn = sqlite3.connect(db_path)
|
||||||
|
cur = conn.cursor()
|
||||||
|
|
||||||
|
cur.execute("SELECT value FROM settings WHERE key='version';")
|
||||||
|
ver = int(cur.fetchall()[0][0])
|
||||||
|
print("PyBitmessage database version: {}".format(ver))
|
||||||
|
if ver != expected_ver:
|
||||||
|
print("Error: version must be {}".format(expected_ver))
|
||||||
|
conn.close()
|
||||||
|
print("Quitting..")
|
||||||
|
quit()
|
||||||
|
print("Version OK")
|
||||||
|
|
||||||
|
print()
|
||||||
|
|
||||||
|
print("Converting..")
|
||||||
|
q = "UPDATE inbox SET msgid=CAST(msgid AS TEXT), sighash=CAST(sighash AS TEXT);"
|
||||||
|
print(q)
|
||||||
|
cur.execute(q)
|
||||||
|
q = "UPDATE pubkeys SET transmitdata=CAST(transmitdata AS TEXT);"
|
||||||
|
print(q)
|
||||||
|
cur.execute(q)
|
||||||
|
q = "UPDATE sent SET msgid=CAST(msgid AS TEXT), toripe=CAST(toripe AS TEXT), ackdata=CAST(ackdata AS TEXT);"
|
||||||
|
print(q)
|
||||||
|
cur.execute(q)
|
||||||
|
|
||||||
|
print("Commiting..")
|
||||||
|
conn.commit()
|
||||||
|
print("Conversion done")
|
||||||
|
|
||||||
|
print("Close the database")
|
||||||
|
conn.close()
|
||||||
|
print("Finished")
|
|
@ -14,6 +14,7 @@ import stat
|
||||||
import subprocess # nosec B404
|
import subprocess # nosec B404
|
||||||
import sys
|
import sys
|
||||||
from binascii import hexlify
|
from binascii import hexlify
|
||||||
|
from six.moves.reprlib import repr
|
||||||
|
|
||||||
# Project imports.
|
# Project imports.
|
||||||
import highlevelcrypto
|
import highlevelcrypto
|
||||||
|
@ -22,6 +23,7 @@ from addresses import decodeAddress, encodeVarint
|
||||||
from bmconfigparser import config
|
from bmconfigparser import config
|
||||||
from debug import logger
|
from debug import logger
|
||||||
from helper_sql import sqlQuery
|
from helper_sql import sqlQuery
|
||||||
|
from dbcompat import dbstr
|
||||||
|
|
||||||
|
|
||||||
myECCryptorObjects = {}
|
myECCryptorObjects = {}
|
||||||
|
@ -37,8 +39,8 @@ broadcastSendersForWhichImWatching = {}
|
||||||
def isAddressInMyAddressBook(address):
|
def isAddressInMyAddressBook(address):
|
||||||
"""Is address in my addressbook?"""
|
"""Is address in my addressbook?"""
|
||||||
queryreturn = sqlQuery(
|
queryreturn = sqlQuery(
|
||||||
'''select address from addressbook where address=?''',
|
'''select TRUE from addressbook where address=?''',
|
||||||
address)
|
dbstr(address))
|
||||||
return queryreturn != []
|
return queryreturn != []
|
||||||
|
|
||||||
|
|
||||||
|
@ -46,8 +48,8 @@ def isAddressInMyAddressBook(address):
|
||||||
def isAddressInMySubscriptionsList(address):
|
def isAddressInMySubscriptionsList(address):
|
||||||
"""Am I subscribed to this address?"""
|
"""Am I subscribed to this address?"""
|
||||||
queryreturn = sqlQuery(
|
queryreturn = sqlQuery(
|
||||||
'''select * from subscriptions where address=?''',
|
'''select TRUE from subscriptions where address=?''',
|
||||||
str(address))
|
dbstr(address))
|
||||||
return queryreturn != []
|
return queryreturn != []
|
||||||
|
|
||||||
|
|
||||||
|
@ -61,14 +63,14 @@ def isAddressInMyAddressBookSubscriptionsListOrWhitelist(address):
|
||||||
queryreturn = sqlQuery(
|
queryreturn = sqlQuery(
|
||||||
'''SELECT address FROM whitelist where address=?'''
|
'''SELECT address FROM whitelist where address=?'''
|
||||||
''' and enabled = '1' ''',
|
''' and enabled = '1' ''',
|
||||||
address)
|
dbstr(address))
|
||||||
if queryreturn != []:
|
if queryreturn != []:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
queryreturn = sqlQuery(
|
queryreturn = sqlQuery(
|
||||||
'''select address from subscriptions where address=?'''
|
'''select address from subscriptions where address=?'''
|
||||||
''' and enabled = '1' ''',
|
''' and enabled = '1' ''',
|
||||||
address)
|
dbstr(address))
|
||||||
if queryreturn != []:
|
if queryreturn != []:
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
@ -114,11 +116,11 @@ def reloadMyAddressHashes():
|
||||||
if len(privEncryptionKey) == 64:
|
if len(privEncryptionKey) == 64:
|
||||||
myECCryptorObjects[hashobj] = \
|
myECCryptorObjects[hashobj] = \
|
||||||
highlevelcrypto.makeCryptor(privEncryptionKey)
|
highlevelcrypto.makeCryptor(privEncryptionKey)
|
||||||
myAddressesByHash[hashobj] = addressInKeysFile
|
myAddressesByHash[bytes(hashobj)] = addressInKeysFile
|
||||||
tag = highlevelcrypto.double_sha512(
|
tag = highlevelcrypto.double_sha512(
|
||||||
encodeVarint(addressVersionNumber)
|
encodeVarint(addressVersionNumber)
|
||||||
+ encodeVarint(streamNumber) + hashobj)[32:]
|
+ encodeVarint(streamNumber) + hashobj)[32:]
|
||||||
myAddressesByTag[tag] = addressInKeysFile
|
myAddressesByTag[bytes(tag)] = addressInKeysFile
|
||||||
|
|
||||||
if not keyfileSecure:
|
if not keyfileSecure:
|
||||||
fixSensitiveFilePermissions(os.path.join(
|
fixSensitiveFilePermissions(os.path.join(
|
||||||
|
@ -136,6 +138,7 @@ def reloadBroadcastSendersForWhichImWatching():
|
||||||
logger.debug('reloading subscriptions...')
|
logger.debug('reloading subscriptions...')
|
||||||
for row in queryreturn:
|
for row in queryreturn:
|
||||||
address, = row
|
address, = row
|
||||||
|
address = address.decode("utf-8", "replace")
|
||||||
# status
|
# status
|
||||||
addressVersionNumber, streamNumber, hashobj = decodeAddress(address)[1:]
|
addressVersionNumber, streamNumber, hashobj = decodeAddress(address)[1:]
|
||||||
if addressVersionNumber == 2:
|
if addressVersionNumber == 2:
|
||||||
|
@ -149,7 +152,7 @@ def reloadBroadcastSendersForWhichImWatching():
|
||||||
encodeVarint(addressVersionNumber)
|
encodeVarint(addressVersionNumber)
|
||||||
+ encodeVarint(streamNumber) + hashobj
|
+ encodeVarint(streamNumber) + hashobj
|
||||||
).digest()[:32]
|
).digest()[:32]
|
||||||
MyECSubscriptionCryptorObjects[hashobj] = \
|
MyECSubscriptionCryptorObjects[bytes(hashobj)] = \
|
||||||
highlevelcrypto.makeCryptor(hexlify(privEncryptionKey))
|
highlevelcrypto.makeCryptor(hexlify(privEncryptionKey))
|
||||||
else:
|
else:
|
||||||
doubleHashOfAddressData = highlevelcrypto.double_sha512(
|
doubleHashOfAddressData = highlevelcrypto.double_sha512(
|
||||||
|
@ -158,7 +161,7 @@ def reloadBroadcastSendersForWhichImWatching():
|
||||||
)
|
)
|
||||||
tag = doubleHashOfAddressData[32:]
|
tag = doubleHashOfAddressData[32:]
|
||||||
privEncryptionKey = doubleHashOfAddressData[:32]
|
privEncryptionKey = doubleHashOfAddressData[:32]
|
||||||
MyECSubscriptionCryptorObjects[tag] = \
|
MyECSubscriptionCryptorObjects[bytes(tag)] = \
|
||||||
highlevelcrypto.makeCryptor(hexlify(privEncryptionKey))
|
highlevelcrypto.makeCryptor(hexlify(privEncryptionKey))
|
||||||
|
|
||||||
|
|
||||||
|
@ -169,7 +172,7 @@ def fixPotentiallyInvalidUTF8Data(text):
|
||||||
return text
|
return text
|
||||||
except UnicodeDecodeError:
|
except UnicodeDecodeError:
|
||||||
return 'Part of the message is corrupt. The message cannot be' \
|
return 'Part of the message is corrupt. The message cannot be' \
|
||||||
' displayed the normal way.\n\n' + repr(text)
|
' displayed the normal way.\n\n' + text.decode("utf-8", "replace")
|
||||||
|
|
||||||
|
|
||||||
def checkSensitiveFilePermissions(filename):
|
def checkSensitiveFilePermissions(filename):
|
||||||
|
@ -193,7 +196,7 @@ def checkSensitiveFilePermissions(filename):
|
||||||
['/usr/bin/stat', '-f', '-c', '%T', filename],
|
['/usr/bin/stat', '-f', '-c', '%T', filename],
|
||||||
stderr=subprocess.STDOUT
|
stderr=subprocess.STDOUT
|
||||||
) # nosec B603
|
) # nosec B603
|
||||||
if 'fuseblk' in fstype:
|
if b'fuseblk' in fstype:
|
||||||
logger.info(
|
logger.info(
|
||||||
'Skipping file permissions check for %s.'
|
'Skipping file permissions check for %s.'
|
||||||
' Filesystem fuseblk detected.', filename)
|
' Filesystem fuseblk detected.', filename)
|
||||||
|
|
|
@ -23,7 +23,11 @@ def doCleanShutdown():
|
||||||
|
|
||||||
objectProcessorQueue.put(('checkShutdownVariable', 'no data'))
|
objectProcessorQueue.put(('checkShutdownVariable', 'no data'))
|
||||||
for thread in threading.enumerate():
|
for thread in threading.enumerate():
|
||||||
if thread.isAlive() and isinstance(thread, StoppableThread):
|
try:
|
||||||
|
alive = thread.isAlive()
|
||||||
|
except AttributeError:
|
||||||
|
alive = thread.is_alive()
|
||||||
|
if alive and isinstance(thread, StoppableThread):
|
||||||
thread.stopThread()
|
thread.stopThread()
|
||||||
|
|
||||||
UISignalQueue.put((
|
UISignalQueue.put((
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
"""
|
"""
|
||||||
Sqlite Inventory
|
Sqlite Inventory
|
||||||
"""
|
"""
|
||||||
|
import six
|
||||||
import sqlite3
|
import sqlite3
|
||||||
import time
|
import time
|
||||||
from threading import RLock
|
from threading import RLock
|
||||||
|
@ -29,20 +30,22 @@ class SqliteInventory(InventoryStorage):
|
||||||
|
|
||||||
def __contains__(self, hash_):
|
def __contains__(self, hash_):
|
||||||
with self.lock:
|
with self.lock:
|
||||||
if hash_ in self._objects:
|
hash_bytes = bytes(hash_)
|
||||||
|
if hash_bytes in self._objects:
|
||||||
return True
|
return True
|
||||||
rows = sqlQuery(
|
rows = sqlQuery(
|
||||||
'SELECT streamnumber FROM inventory WHERE hash=?',
|
'SELECT streamnumber FROM inventory WHERE hash=?',
|
||||||
sqlite3.Binary(hash_))
|
sqlite3.Binary(hash_))
|
||||||
if not rows:
|
if not rows:
|
||||||
return False
|
return False
|
||||||
self._objects[hash_] = rows[0][0]
|
self._objects[hash_bytes] = rows[0][0]
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def __getitem__(self, hash_):
|
def __getitem__(self, hash_):
|
||||||
with self.lock:
|
with self.lock:
|
||||||
if hash_ in self._inventory:
|
hash_bytes = bytes(hash_)
|
||||||
return self._inventory[hash_]
|
if hash_bytes in self._inventory:
|
||||||
|
return self._inventory[hash_bytes]
|
||||||
rows = sqlQuery(
|
rows = sqlQuery(
|
||||||
'SELECT objecttype, streamnumber, payload, expirestime, tag'
|
'SELECT objecttype, streamnumber, payload, expirestime, tag'
|
||||||
' FROM inventory WHERE hash=?', sqlite3.Binary(hash_))
|
' FROM inventory WHERE hash=?', sqlite3.Binary(hash_))
|
||||||
|
@ -53,15 +56,16 @@ class SqliteInventory(InventoryStorage):
|
||||||
def __setitem__(self, hash_, value):
|
def __setitem__(self, hash_, value):
|
||||||
with self.lock:
|
with self.lock:
|
||||||
value = InventoryItem(*value)
|
value = InventoryItem(*value)
|
||||||
self._inventory[hash_] = value
|
hash_bytes = bytes(hash_)
|
||||||
self._objects[hash_] = value.stream
|
self._inventory[hash_bytes] = value
|
||||||
|
self._objects[hash_bytes] = value.stream
|
||||||
|
|
||||||
def __delitem__(self, hash_):
|
def __delitem__(self, hash_):
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
def __iter__(self):
|
def __iter__(self):
|
||||||
with self.lock:
|
with self.lock:
|
||||||
hashes = self._inventory.keys()[:]
|
hashes = [] + self._inventory.keys()[:]
|
||||||
hashes += (x for x, in sqlQuery('SELECT hash FROM inventory'))
|
hashes += (x for x, in sqlQuery('SELECT hash FROM inventory'))
|
||||||
return hashes.__iter__()
|
return hashes.__iter__()
|
||||||
|
|
||||||
|
@ -95,7 +99,7 @@ class SqliteInventory(InventoryStorage):
|
||||||
t = int(time.time())
|
t = int(time.time())
|
||||||
hashes = [x for x, value in self._inventory.items()
|
hashes = [x for x, value in self._inventory.items()
|
||||||
if value.stream == stream and value.expires > t]
|
if value.stream == stream and value.expires > t]
|
||||||
hashes += (str(payload) for payload, in sqlQuery(
|
hashes += (bytes(payload) for payload, in sqlQuery(
|
||||||
'SELECT hash FROM inventory WHERE streamnumber=?'
|
'SELECT hash FROM inventory WHERE streamnumber=?'
|
||||||
' AND expirestime>?', stream, t))
|
' AND expirestime>?', stream, t))
|
||||||
return hashes
|
return hashes
|
||||||
|
@ -107,6 +111,10 @@ class SqliteInventory(InventoryStorage):
|
||||||
# always use the inventoryLock OUTSIDE of the sqlLock.
|
# always use the inventoryLock OUTSIDE of the sqlLock.
|
||||||
with SqlBulkExecute() as sql:
|
with SqlBulkExecute() as sql:
|
||||||
for objectHash, value in self._inventory.items():
|
for objectHash, value in self._inventory.items():
|
||||||
|
tag = value[4]
|
||||||
|
if six.PY3 and isinstance(tag, str):
|
||||||
|
tag = tag.encode("utf-8", "replace")
|
||||||
|
value = [value[0], value[1], sqlite3.Binary(value[2]), value[3], sqlite3.Binary(tag)]
|
||||||
sql.execute(
|
sql.execute(
|
||||||
'INSERT INTO inventory VALUES (?, ?, ?, ?, ?, ?)',
|
'INSERT INTO inventory VALUES (?, ?, ?, ?, ?, ?)',
|
||||||
sqlite3.Binary(objectHash), *value)
|
sqlite3.Binary(objectHash), *value)
|
||||||
|
|
|
@ -4,10 +4,7 @@ Storing inventory items
|
||||||
|
|
||||||
from abc import abstractmethod
|
from abc import abstractmethod
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
try:
|
from six.moves.collections_abc import MutableMapping # pylint: disable=deprecated-class
|
||||||
from collections import MutableMapping # pylint: disable=deprecated-class
|
|
||||||
except ImportError:
|
|
||||||
from collections.abc import MutableMapping
|
|
||||||
|
|
||||||
|
|
||||||
InventoryItem = namedtuple('InventoryItem', 'type stream payload expires tag')
|
InventoryItem = namedtuple('InventoryItem', 'type stream payload expires tag')
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import os
|
import os
|
||||||
import sys
|
|
||||||
import time
|
import time
|
||||||
import unittest
|
import unittest
|
||||||
|
import six
|
||||||
|
|
||||||
|
|
||||||
_files = (
|
_files = (
|
||||||
|
@ -33,7 +33,7 @@ def checkup():
|
||||||
|
|
||||||
def skip_python3():
|
def skip_python3():
|
||||||
"""Raise unittest.SkipTest() if detected python3"""
|
"""Raise unittest.SkipTest() if detected python3"""
|
||||||
if sys.hexversion >= 0x3000000:
|
if six.PY3:
|
||||||
raise unittest.SkipTest('Module is not ported to python3')
|
raise unittest.SkipTest('Module is not ported to python3')
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ Tests for core and those that do not work outside
|
||||||
import atexit
|
import atexit
|
||||||
import os
|
import os
|
||||||
import pickle # nosec
|
import pickle # nosec
|
||||||
import Queue
|
from six.moves import queue as Queue
|
||||||
import random # nosec
|
import random # nosec
|
||||||
import shutil
|
import shutil
|
||||||
import socket
|
import socket
|
||||||
|
@ -15,6 +15,8 @@ import sys
|
||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
import unittest
|
import unittest
|
||||||
|
import six
|
||||||
|
import sqlite3
|
||||||
|
|
||||||
import protocol
|
import protocol
|
||||||
import state
|
import state
|
||||||
|
@ -31,6 +33,7 @@ from network.node import Node, Peer
|
||||||
from network.tcp import Socks4aBMConnection, Socks5BMConnection, TCPConnection
|
from network.tcp import Socks4aBMConnection, Socks5BMConnection, TCPConnection
|
||||||
from queues import excQueue
|
from queues import excQueue
|
||||||
from version import softwareVersion
|
from version import softwareVersion
|
||||||
|
from dbcompat import dbstr
|
||||||
|
|
||||||
from common import cleanup
|
from common import cleanup
|
||||||
|
|
||||||
|
@ -137,8 +140,8 @@ class TestCore(unittest.TestCase):
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _outdate_knownnodes():
|
def _outdate_knownnodes():
|
||||||
with knownnodes.knownNodesLock:
|
with knownnodes.knownNodesLock:
|
||||||
for nodes in knownnodes.knownNodes.itervalues():
|
for nodes in six.itervalues(knownnodes.knownNodes):
|
||||||
for node in nodes.itervalues():
|
for node in six.itervalues(nodes):
|
||||||
node['lastseen'] -= 2419205 # older than 28 days
|
node['lastseen'] -= 2419205 # older than 28 days
|
||||||
|
|
||||||
def test_knownnodes_pickle(self):
|
def test_knownnodes_pickle(self):
|
||||||
|
@ -146,9 +149,9 @@ class TestCore(unittest.TestCase):
|
||||||
pickle_knownnodes()
|
pickle_knownnodes()
|
||||||
self._wipe_knownnodes()
|
self._wipe_knownnodes()
|
||||||
knownnodes.readKnownNodes()
|
knownnodes.readKnownNodes()
|
||||||
for nodes in knownnodes.knownNodes.itervalues():
|
for nodes in six.itervalues(knownnodes.knownNodes):
|
||||||
self_count = n = 0
|
self_count = n = 0
|
||||||
for n, node in enumerate(nodes.itervalues()):
|
for n, node in enumerate(six.itervalues(nodes)):
|
||||||
if node.get('self'):
|
if node.get('self'):
|
||||||
self_count += 1
|
self_count += 1
|
||||||
self.assertEqual(n - self_count, 2)
|
self.assertEqual(n - self_count, 2)
|
||||||
|
@ -202,7 +205,7 @@ class TestCore(unittest.TestCase):
|
||||||
while c > 0:
|
while c > 0:
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
c -= 2
|
c -= 2
|
||||||
for peer, con in connectionpool.pool.outboundConnections.iteritems():
|
for peer, con in six.iteritems(connectionpool.pool.outboundConnections):
|
||||||
if (
|
if (
|
||||||
peer.host.startswith('bootstrap')
|
peer.host.startswith('bootstrap')
|
||||||
or peer.host == 'quzwelsuziwqgpt2.onion'
|
or peer.host == 'quzwelsuziwqgpt2.onion'
|
||||||
|
@ -223,7 +226,7 @@ class TestCore(unittest.TestCase):
|
||||||
'Failed to connect during %.2f sec' % (time.time() - _started))
|
'Failed to connect during %.2f sec' % (time.time() - _started))
|
||||||
|
|
||||||
def _check_knownnodes(self):
|
def _check_knownnodes(self):
|
||||||
for stream in knownnodes.knownNodes.itervalues():
|
for stream in six.itervalues(knownnodes.knownNodes):
|
||||||
for peer in stream:
|
for peer in stream:
|
||||||
if peer.host.startswith('bootstrap'):
|
if peer.host.startswith('bootstrap'):
|
||||||
self.fail(
|
self.fail(
|
||||||
|
@ -346,12 +349,18 @@ class TestCore(unittest.TestCase):
|
||||||
subject=subject, message=message
|
subject=subject, message=message
|
||||||
)
|
)
|
||||||
queryreturn = sqlQuery(
|
queryreturn = sqlQuery(
|
||||||
'''select msgid from sent where ackdata=?''', result)
|
'''select msgid from sent where ackdata=?''', sqlite3.Binary(result))
|
||||||
self.assertNotEqual(queryreturn[0][0] if queryreturn else '', '')
|
if len(queryreturn) < 1:
|
||||||
|
queryreturn = sqlQuery(
|
||||||
|
'''select msgid from sent where ackdata=CAST(? AS TEXT)''', result)
|
||||||
|
self.assertNotEqual(queryreturn[0][0] if queryreturn else b'', b'')
|
||||||
|
|
||||||
column_type = sqlQuery(
|
column_type = sqlQuery(
|
||||||
'''select typeof(msgid) from sent where ackdata=?''', result)
|
'''select typeof(msgid) from sent where ackdata=?''', sqlite3.Binary(result))
|
||||||
self.assertEqual(column_type[0][0] if column_type else '', 'text')
|
if len(column_type) < 1:
|
||||||
|
column_type = sqlQuery(
|
||||||
|
'''select typeof(msgid) from sent where ackdata=CAST(? AS TEXT)''', result)
|
||||||
|
self.assertEqual(column_type[0][0] if column_type else '', 'blob')
|
||||||
|
|
||||||
@unittest.skipIf(frozen, 'not packed test_pattern into the bundle')
|
@unittest.skipIf(frozen, 'not packed test_pattern into the bundle')
|
||||||
def test_old_knownnodes_pickle(self):
|
def test_old_knownnodes_pickle(self):
|
||||||
|
@ -369,7 +378,7 @@ class TestCore(unittest.TestCase):
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def delete_address_from_addressbook(address):
|
def delete_address_from_addressbook(address):
|
||||||
"""Clean up addressbook"""
|
"""Clean up addressbook"""
|
||||||
sqlQuery('''delete from addressbook where address=?''', address)
|
sqlQuery('''delete from addressbook where address=?''', dbstr(address))
|
||||||
|
|
||||||
def test_add_same_address_twice_in_addressbook(self):
|
def test_add_same_address_twice_in_addressbook(self):
|
||||||
"""checking same address is added twice in addressbook"""
|
"""checking same address is added twice in addressbook"""
|
||||||
|
@ -383,7 +392,7 @@ class TestCore(unittest.TestCase):
|
||||||
"""checking is address added in addressbook or not"""
|
"""checking is address added in addressbook or not"""
|
||||||
helper_addressbook.insert(label='test1', address=self.addr)
|
helper_addressbook.insert(label='test1', address=self.addr)
|
||||||
queryreturn = sqlQuery(
|
queryreturn = sqlQuery(
|
||||||
'select count(*) from addressbook where address=?', self.addr)
|
'select count(*) from addressbook where address=?', dbstr(self.addr))
|
||||||
self.assertEqual(queryreturn[0][0], 1)
|
self.assertEqual(queryreturn[0][0], 1)
|
||||||
self.delete_address_from_addressbook(self.addr)
|
self.delete_address_from_addressbook(self.addr)
|
||||||
|
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user