Runnable with both Python3 and Python2, with both PyQt5 and PyQt4 by using Qt.py #2250
|
@ -72,6 +72,8 @@ function install_python(){
|
|||
wine python -m pip install pytools==2020.2
|
||||
echo "Upgrading pip"
|
||||
wine python -m pip install --upgrade pip
|
||||
# install pypiwin32 for win32com
|
||||
wine python -m pip install pypiwin32
|
||||
}
|
||||
|
||||
function install_pyqt(){
|
||||
|
@ -82,6 +84,8 @@ function install_pyqt(){
|
|||
echo "Installing PyQt-${PYQT_VERSION} 32b"
|
||||
wine PyQt${PYQT_VERSION}-x32.exe /S /WX
|
||||
fi
|
||||
# and qtpy
|
||||
wine python -m pip install qtpy
|
||||
}
|
||||
|
||||
function install_openssl(){
|
||||
|
|
|
@ -216,8 +216,7 @@ autodoc_mock_imports = [
|
|||
'pkg_resources',
|
||||
'pycanberra',
|
||||
'pyopencl',
|
||||
'PyQt4',
|
||||
'PyQt5',
|
||||
'qtpy',
|
||||
'qrcode',
|
||||
'stem',
|
||||
'xdg',
|
||||
|
|
|
@ -11,11 +11,13 @@ ingredients:
|
|||
- python-msgpack
|
||||
- python-qrcode
|
||||
- python-qt4
|
||||
- python-qtpy
|
||||
- python-setuptools
|
||||
- python-sip
|
||||
- python-six
|
||||
- python-xdg
|
||||
- sni-qt
|
||||
- xkb-data
|
||||
exclude:
|
||||
- libdb5.3
|
||||
- libglib2.0-0
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
import collectd
|
||||
import json
|
||||
import xmlrpclib
|
||||
from six.moves import xmlrpc_client as xmlrpclib
|
||||
|
||||
pybmurl = ""
|
||||
api = ""
|
||||
|
|
|
@ -43,8 +43,16 @@ a = Analysis(
|
|||
'setuptools.msvc', '_cffi_backend',
|
||||
'plugins.menu_qrcode', 'plugins.proxyconfig_stem'
|
||||
],
|
||||
runtime_hooks=[os.path.join(hookspath, 'pyinstaller_rthook_plugins.py')],
|
||||
excludes=excludes
|
||||
# https://github.com/pyinstaller/pyinstaller/wiki/Recipe-PyQt4-API-Version
|
||||
runtime_hooks = [
|
||||
os.path.join(hookspath, hook) for hook in (
|
||||
'pyinstaller_rthook_pyqt4.py',
|
||||
'pyinstaller_rthook_plugins.py'
|
||||
)],
|
||||
excludes += [
|
||||
'PyQt4.QtOpenGL','PyQt4.QtSql',
|
||||
'PyQt4.QtSvg', 'PyQt4.QtTest', 'PyQt4.QtWebKit', 'PyQt4.QtXml',
|
||||
'win32ui']
|
||||
)
|
||||
|
||||
|
||||
|
@ -90,9 +98,8 @@ a.datas += addTranslations()
|
|||
a.datas += [('default.ini', os.path.join(srcPath, 'default.ini'), 'DATA')]
|
||||
|
||||
excluded_binaries = [
|
||||
'QtOpenGL4.dll',
|
||||
'QtSvg4.dll',
|
||||
'QtXml4.dll',
|
||||
'QtOpenGL4.dll', 'QtSql4.dll', 'QtSvg4.dll', 'QtTest4.dll',
|
||||
'QtWebKit4.dll', 'QtXml4.dll'
|
||||
]
|
||||
a.binaries = TOC([x for x in a.binaries if x[0] not in excluded_binaries])
|
||||
|
||||
|
|
10
packages/pyinstaller/hooks/pyinstaller_rthook_pyqt4.py
Normal file
10
packages/pyinstaller/hooks/pyinstaller_rthook_pyqt4.py
Normal file
|
@ -0,0 +1,10 @@
|
|||
# https://github.com/pyinstaller/pyinstaller/wiki/Recipe-PyQt4-API-Version
|
||||
import sip
|
||||
|
||||
sip.setapi(u'QDate', 2)
|
||||
sip.setapi(u'QDateTime', 2)
|
||||
sip.setapi(u'QString', 2)
|
||||
sip.setapi(u'QTextStream', 2)
|
||||
sip.setapi(u'QTime', 2)
|
||||
sip.setapi(u'QUrl', 2)
|
||||
sip.setapi(u'QVariant', 2)
|
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 shutil
|
||||
import sys
|
||||
import six
|
||||
|
||||
from importlib import import_module
|
||||
from setuptools import setup, Extension
|
||||
|
@ -83,7 +84,7 @@ if __name__ == "__main__":
|
|||
'images/kivy/text_images*.png'
|
||||
]}
|
||||
|
||||
if sys.version_info[0] == 3:
|
||||
if six.PY3:
|
||||
packages.extend(
|
||||
[
|
||||
'pybitmessage.bitmessagekivy',
|
||||
|
|
|
@ -187,7 +187,7 @@ def decodeAddress(address):
|
|||
integer = decodeBase58(address)
|
||||
if integer == 0:
|
||||
status = 'invalidcharacters'
|
||||
return status, 0, 0, ''
|
||||
return status, 0, 0, b''
|
||||
# after converting to hex, the string will be prepended
|
||||
# with a 0x and appended with a L in python2
|
||||
hexdata = hex(integer)[2:].rstrip('L')
|
||||
|
@ -200,23 +200,23 @@ def decodeAddress(address):
|
|||
|
||||
if checksum != double_sha512(data[:-4])[0:4]:
|
||||
status = 'checksumfailed'
|
||||
return status, 0, 0, ''
|
||||
return status, 0, 0, b''
|
||||
|
||||
try:
|
||||
addressVersionNumber, bytesUsedByVersionNumber = decodeVarint(data[:9])
|
||||
except varintDecodeError as e:
|
||||
logger.error(str(e))
|
||||
status = 'varintmalformed'
|
||||
return status, 0, 0, ''
|
||||
return status, 0, 0, b''
|
||||
|
||||
if addressVersionNumber > 4:
|
||||
logger.error('cannot decode address version numbers this high')
|
||||
status = 'versiontoohigh'
|
||||
return status, 0, 0, ''
|
||||
return status, 0, 0, b''
|
||||
elif addressVersionNumber == 0:
|
||||
logger.error('cannot decode address version numbers of zero.')
|
||||
status = 'versiontoohigh'
|
||||
return status, 0, 0, ''
|
||||
return status, 0, 0, b''
|
||||
|
||||
try:
|
||||
streamNumber, bytesUsedByStreamNumber = \
|
||||
|
@ -224,7 +224,7 @@ def decodeAddress(address):
|
|||
except varintDecodeError as e:
|
||||
logger.error(str(e))
|
||||
status = 'varintmalformed'
|
||||
return status, 0, 0, ''
|
||||
return status, 0, 0, b''
|
||||
|
||||
status = 'success'
|
||||
if addressVersionNumber == 1:
|
||||
|
@ -242,21 +242,21 @@ def decodeAddress(address):
|
|||
return status, addressVersionNumber, streamNumber, \
|
||||
b'\x00\x00' + embeddedRipeData
|
||||
elif len(embeddedRipeData) < 18:
|
||||
return 'ripetooshort', 0, 0, ''
|
||||
return 'ripetooshort', 0, 0, b''
|
||||
elif len(embeddedRipeData) > 20:
|
||||
return 'ripetoolong', 0, 0, ''
|
||||
return 'otherproblem', 0, 0, ''
|
||||
return 'ripetoolong', 0, 0, b''
|
||||
return 'otherproblem', 0, 0, b''
|
||||
elif addressVersionNumber == 4:
|
||||
embeddedRipeData = \
|
||||
data[bytesUsedByVersionNumber + bytesUsedByStreamNumber:-4]
|
||||
if embeddedRipeData[0:1] == b'\x00':
|
||||
# In order to enforce address non-malleability, encoded
|
||||
# RIPE data must have NULL bytes removed from the front
|
||||
return 'encodingproblem', 0, 0, ''
|
||||
return 'encodingproblem', 0, 0, b''
|
||||
elif len(embeddedRipeData) > 20:
|
||||
return 'ripetoolong', 0, 0, ''
|
||||
return 'ripetoolong', 0, 0, b''
|
||||
elif len(embeddedRipeData) < 4:
|
||||
return 'ripetooshort', 0, 0, ''
|
||||
return 'ripetooshort', 0, 0, b''
|
||||
x00string = b'\x00' * (20 - len(embeddedRipeData))
|
||||
return status, addressVersionNumber, streamNumber, \
|
||||
x00string + embeddedRipeData
|
||||
|
|
105
src/api.py
105
src/api.py
|
@ -67,9 +67,12 @@ import subprocess # nosec B404
|
|||
import time
|
||||
from binascii import hexlify, unhexlify
|
||||
from struct import pack, unpack
|
||||
import sqlite3
|
||||
|
||||
import six
|
||||
from six.moves import configparser, http_client, xmlrpc_server
|
||||
from six.moves.reprlib import repr
|
||||
from dbcompat import dbstr
|
||||
|
||||
import helper_inbox
|
||||
import helper_sent
|
||||
|
@ -531,12 +534,12 @@ class BMRPCDispatcher(object):
|
|||
message = shared.fixPotentiallyInvalidUTF8Data(message)
|
||||
return {
|
||||
'msgid': hexlify(msgid),
|
||||
'toAddress': toAddress,
|
||||
'fromAddress': fromAddress,
|
||||
'toAddress': toAddress.decode("utf-8", "replace"),
|
||||
'fromAddress': fromAddress.decode("utf-8", "replace"),
|
||||
'subject': base64.b64encode(subject),
|
||||
'message': base64.b64encode(message),
|
||||
'encodingType': encodingtype,
|
||||
'receivedTime': received,
|
||||
'receivedTime': received.decode("utf-8", "replace"),
|
||||
'read': read
|
||||
}
|
||||
|
||||
|
@ -598,11 +601,12 @@ class BMRPCDispatcher(object):
|
|||
"""
|
||||
queryreturn = sqlQuery(
|
||||
"SELECT label, address from addressbook WHERE label = ?",
|
||||
label
|
||||
dbstr(label)
|
||||
) if label else sqlQuery("SELECT label, address from addressbook")
|
||||
data = []
|
||||
for label, address in queryreturn:
|
||||
label = shared.fixPotentiallyInvalidUTF8Data(label)
|
||||
address = address.decode("utf-8", "replace")
|
||||
data.append({
|
||||
'label': base64.b64encode(label),
|
||||
'address': address
|
||||
|
@ -618,12 +622,12 @@ class BMRPCDispatcher(object):
|
|||
self._verifyAddress(address)
|
||||
# TODO: add unique together constraint in the table
|
||||
queryreturn = sqlQuery(
|
||||
"SELECT address FROM addressbook WHERE address=?", address)
|
||||
"SELECT address FROM addressbook WHERE address=?", dbstr(address))
|
||||
if queryreturn != []:
|
||||
raise APIError(
|
||||
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(('rerenderMessagelistToLabels', ''))
|
||||
queues.UISignalQueue.put(('rerenderAddressBook', ''))
|
||||
|
@ -635,7 +639,7 @@ class BMRPCDispatcher(object):
|
|||
"""Delete an entry from address book."""
|
||||
address = addBMIfNotPresent(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(('rerenderMessagelistToLabels', ''))
|
||||
queues.UISignalQueue.put(('rerenderAddressBook', ''))
|
||||
|
@ -919,6 +923,7 @@ class BMRPCDispatcher(object):
|
|||
" ORDER BY received"
|
||||
)
|
||||
return {"inboxMessages": [
|
||||
|
||||
self._dump_inbox_message(*data) for data in queryreturn
|
||||
]}
|
||||
|
||||
|
@ -953,19 +958,31 @@ class BMRPCDispatcher(object):
|
|||
23, 'Bool expected in readStatus, saw %s instead.'
|
||||
% type(readStatus))
|
||||
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
|
||||
try:
|
||||
if (queryreturn[0][0] == 1) != readStatus:
|
||||
sqlExecute(
|
||||
rowcount = sqlExecute(
|
||||
"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)
|
||||
queues.UISignalQueue.put(('changedInboxUnread', None))
|
||||
except IndexError:
|
||||
pass
|
||||
queryreturn = sqlQuery(
|
||||
"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:
|
||||
return {"inboxMessage": [
|
||||
|
@ -1018,7 +1035,7 @@ class BMRPCDispatcher(object):
|
|||
queryreturn = sqlQuery(
|
||||
"SELECT msgid, toaddress, fromaddress, subject, received,"
|
||||
" message, encodingtype, read FROM inbox WHERE folder='inbox'"
|
||||
" AND toAddress=?", toAddress)
|
||||
" AND toAddress=?", dbstr(toAddress))
|
||||
return {"inboxMessages": [
|
||||
self._dump_inbox_message(*data) for data in queryreturn
|
||||
]}
|
||||
|
@ -1035,6 +1052,12 @@ class BMRPCDispatcher(object):
|
|||
queryreturn = sqlQuery(
|
||||
"SELECT msgid, toaddress, fromaddress, subject, lastactiontime,"
|
||||
" 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
|
||||
)
|
||||
try:
|
||||
|
@ -1055,7 +1078,7 @@ class BMRPCDispatcher(object):
|
|||
"SELECT msgid, toaddress, fromaddress, subject, lastactiontime,"
|
||||
" message, encodingtype, status, ackdata FROM sent"
|
||||
" WHERE folder='sent' AND fromAddress=? ORDER BY lastactiontime",
|
||||
fromAddress
|
||||
dbstr(fromAddress)
|
||||
)
|
||||
return {"sentMessages": [
|
||||
self._dump_sent_message(*data) for data in queryreturn
|
||||
|
@ -1072,7 +1095,13 @@ class BMRPCDispatcher(object):
|
|||
queryreturn = sqlQuery(
|
||||
"SELECT msgid, toaddress, fromaddress, subject, lastactiontime,"
|
||||
" 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:
|
||||
|
@ -1093,7 +1122,9 @@ class BMRPCDispatcher(object):
|
|||
# Trash if in inbox table
|
||||
helper_inbox.trash(msgid)
|
||||
# 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).'
|
||||
|
||||
@command('trashInboxMessage')
|
||||
|
@ -1107,7 +1138,9 @@ class BMRPCDispatcher(object):
|
|||
def HandleTrashSentMessage(self, msgid):
|
||||
"""Trash sent message by msgid (encoded in 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).'
|
||||
|
||||
@command('sendMessage')
|
||||
|
@ -1150,9 +1183,9 @@ class BMRPCDispatcher(object):
|
|||
|
||||
toLabel = ''
|
||||
queryreturn = sqlQuery(
|
||||
"SELECT label FROM addressbook WHERE address=?", toAddress)
|
||||
"SELECT label FROM addressbook WHERE address=?", dbstr(toAddress))
|
||||
try:
|
||||
toLabel = queryreturn[0][0]
|
||||
toLabel = queryreturn[0][0].decode("utf-8", "replace")
|
||||
except IndexError:
|
||||
pass
|
||||
|
||||
|
@ -1217,9 +1250,12 @@ class BMRPCDispatcher(object):
|
|||
raise APIError(15, 'Invalid ackData object size.')
|
||||
ackdata = self._decode(ackdata, "hex")
|
||||
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:
|
||||
return queryreturn[0][0]
|
||||
return queryreturn[0][0].decode("utf-8", "replace")
|
||||
except IndexError:
|
||||
return 'notfound'
|
||||
|
||||
|
@ -1238,11 +1274,11 @@ class BMRPCDispatcher(object):
|
|||
# First we must check to see if the address is already in the
|
||||
# subscriptions list.
|
||||
queryreturn = sqlQuery(
|
||||
"SELECT * FROM subscriptions WHERE address=?", address)
|
||||
"SELECT * FROM subscriptions WHERE address=?", dbstr(address))
|
||||
if queryreturn:
|
||||
raise APIError(16, 'You are already subscribed to that address.')
|
||||
sqlExecute(
|
||||
"INSERT INTO subscriptions VALUES (?,?,?)", label, address, True)
|
||||
"INSERT INTO subscriptions VALUES (?,?,?)", dbstr(label), dbstr(address), True)
|
||||
shared.reloadBroadcastSendersForWhichImWatching()
|
||||
queues.UISignalQueue.put(('rerenderMessagelistFromLabels', ''))
|
||||
queues.UISignalQueue.put(('rerenderSubscriptions', ''))
|
||||
|
@ -1256,7 +1292,7 @@ class BMRPCDispatcher(object):
|
|||
"""
|
||||
|
||||
address = addBMIfNotPresent(address)
|
||||
sqlExecute("DELETE FROM subscriptions WHERE address=?", address)
|
||||
sqlExecute("DELETE FROM subscriptions WHERE address=?", dbstr(address))
|
||||
shared.reloadBroadcastSendersForWhichImWatching()
|
||||
queues.UISignalQueue.put(('rerenderMessagelistFromLabels', ''))
|
||||
queues.UISignalQueue.put(('rerenderSubscriptions', ''))
|
||||
|
@ -1274,6 +1310,7 @@ class BMRPCDispatcher(object):
|
|||
data = []
|
||||
for label, address, enabled in queryreturn:
|
||||
label = shared.fixPotentiallyInvalidUTF8Data(label)
|
||||
address = address.decode("utf-8", "replace")
|
||||
data.append({
|
||||
'label': base64.b64encode(label),
|
||||
'address': address,
|
||||
|
@ -1354,7 +1391,9 @@ class BMRPCDispatcher(object):
|
|||
"""Trash a sent message by ackdata (hex encoded)"""
|
||||
# This API method should only be used when msgid is not available
|
||||
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).'
|
||||
|
||||
@command('disseminatePubkey')
|
||||
|
@ -1421,19 +1460,29 @@ class BMRPCDispatcher(object):
|
|||
# use it we'll need to fill out a field in our inventory database
|
||||
# which is blank by default (first20bytesofencryptedmessage).
|
||||
queryreturn = sqlQuery(
|
||||
"SELECT hash, payload FROM inventory WHERE tag = ''"
|
||||
" and objecttype = 2")
|
||||
"SELECT hash, payload FROM inventory WHERE tag = ?"
|
||||
" 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:
|
||||
for hash01, payload in queryreturn:
|
||||
readPosition = 16 # Nonce length + time length
|
||||
# Stream Number length
|
||||
readPosition += decodeVarint(
|
||||
payload[readPosition:readPosition + 10])[1]
|
||||
t = (payload[readPosition:readPosition + 32], hash01)
|
||||
sql.execute("UPDATE inventory SET tag=? WHERE hash=?", *t)
|
||||
t = (sqlite3.Binary(payload[readPosition:readPosition + 32]), sqlite3.Binary(hash01))
|
||||
_, 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(
|
||||
"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": [
|
||||
{'data': hexlify(payload)} for payload, in queryreturn
|
||||
]}
|
||||
|
|
|
@ -21,7 +21,8 @@ import os
|
|||
import socket
|
||||
import sys
|
||||
import time
|
||||
import xmlrpclib
|
||||
from six.moves import xmlrpc_client as xmlrpclib
|
||||
from six.moves import input as raw_input
|
||||
|
||||
from bmconfigparser import config
|
||||
|
||||
|
|
|
@ -10,13 +10,15 @@ Bitmessage commandline interface
|
|||
# * python2-pythondialog
|
||||
# * dialog
|
||||
|
||||
import ConfigParser
|
||||
from six.moves import configparser
|
||||
import curses
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
from textwrap import fill
|
||||
from threading import Timer
|
||||
import six
|
||||
import sqlite3
|
||||
|
||||
from dialog import Dialog
|
||||
import helper_sent
|
||||
|
@ -30,6 +32,7 @@ import state
|
|||
from addresses import addBMIfNotPresent, decodeAddress
|
||||
from bmconfigparser import config
|
||||
from helper_sql import sqlExecute, sqlQuery
|
||||
from dbcompat import dbstr
|
||||
|
||||
# pylint: disable=global-statement
|
||||
|
||||
|
@ -105,7 +108,7 @@ def ascii(s):
|
|||
"""ASCII values"""
|
||||
r = ""
|
||||
for c in s:
|
||||
if ord(c) in range(128):
|
||||
if six.byte2int(c) in range(128):
|
||||
r += c
|
||||
return r
|
||||
|
||||
|
@ -326,13 +329,13 @@ def handlech(c, stdscr):
|
|||
if c != curses.ERR:
|
||||
global inboxcur, addrcur, sentcur, subcur, abookcur, blackcur
|
||||
if c in range(256):
|
||||
if chr(c) in '12345678':
|
||||
if six.int2byte(c) in '12345678':
|
||||
global menutab
|
||||
menutab = int(chr(c))
|
||||
elif chr(c) == 'q':
|
||||
menutab = int(six.int2byte(c))
|
||||
elif six.int2byte(c) == 'q':
|
||||
global quit_
|
||||
quit_ = True
|
||||
elif chr(c) == '\n':
|
||||
elif six.int2byte(c) == '\n':
|
||||
curses.curs_set(1)
|
||||
d = Dialog(dialog="dialog")
|
||||
if menutab == 1:
|
||||
|
@ -358,7 +361,9 @@ def handlech(c, stdscr):
|
|||
inbox[inboxcur][1] +
|
||||
"\"")
|
||||
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 != []:
|
||||
for row in ret:
|
||||
data, = row
|
||||
|
@ -367,12 +372,16 @@ def handlech(c, stdscr):
|
|||
for i, item in enumerate(data.split("\n")):
|
||||
msg += fill(item, replace_whitespace=False) + "\n"
|
||||
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
|
||||
else:
|
||||
scrollbox(d, unicode("Could not fetch message."))
|
||||
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
|
||||
elif t == "3": # Reply
|
||||
curses.curs_set(1)
|
||||
|
@ -396,11 +405,14 @@ def handlech(c, stdscr):
|
|||
if not m[5][:4] == "Re: ":
|
||||
subject = "Re: " + m[5]
|
||||
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 != []:
|
||||
body = "\n\n------------------------------------------------------\n"
|
||||
for row in ret:
|
||||
body, = row
|
||||
body = body.decode("utf-8", "replace")
|
||||
|
||||
sendMessage(fromaddr, toaddr, ischan, subject, body, True)
|
||||
dialogreset(stdscr)
|
||||
|
@ -410,7 +422,7 @@ def handlech(c, stdscr):
|
|||
r, t = d.inputbox("Label for address \"" + addr + "\"")
|
||||
if r == d.DIALOG_OK:
|
||||
label = t
|
||||
sqlExecute("INSERT INTO addressbook VALUES (?,?)", label, addr)
|
||||
sqlExecute("INSERT INTO addressbook VALUES (?,?)", dbstr(label), dbstr(addr))
|
||||
# Prepend entry
|
||||
addrbook.reverse()
|
||||
addrbook.append([label, addr])
|
||||
|
@ -422,17 +434,22 @@ def handlech(c, stdscr):
|
|||
r, t = d.inputbox("Filename", init=inbox[inboxcur][5] + ".txt")
|
||||
if r == d.DIALOG_OK:
|
||||
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 != []:
|
||||
for row in ret:
|
||||
msg, = row
|
||||
msg = msg.decode("utf-8", "replace")
|
||||
fh = open(t, "a") # Open in append mode just in case
|
||||
fh.write(msg)
|
||||
fh.close()
|
||||
else:
|
||||
scrollbox(d, unicode("Could not fetch message."))
|
||||
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]
|
||||
scrollbox(d, unicode(
|
||||
"Message moved to trash. There is no interface to view your trash,"
|
||||
|
@ -463,7 +480,12 @@ def handlech(c, stdscr):
|
|||
data = ""
|
||||
ret = sqlQuery(
|
||||
"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])
|
||||
if ret != []:
|
||||
for row in ret:
|
||||
|
@ -476,9 +498,14 @@ def handlech(c, stdscr):
|
|||
else:
|
||||
scrollbox(d, unicode("Could not fetch message."))
|
||||
elif t == "2": # Move to trash
|
||||
sqlExecute(
|
||||
rowcount = sqlExecute(
|
||||
"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])
|
||||
del sentbox[sentcur]
|
||||
scrollbox(d, unicode(
|
||||
|
@ -672,7 +699,7 @@ def handlech(c, stdscr):
|
|||
elif t == "2" and m is False:
|
||||
try:
|
||||
mn = config.get(a, "mailinglistname")
|
||||
except ConfigParser.NoOptionError:
|
||||
except configparser.NoOptionError:
|
||||
mn = ""
|
||||
r, t = d.inputbox("Mailing list name", init=mn)
|
||||
if r == d.DIALOG_OK:
|
||||
|
@ -711,29 +738,29 @@ def handlech(c, stdscr):
|
|||
subscriptions.append([label, addr, True])
|
||||
subscriptions.reverse()
|
||||
|
||||
sqlExecute("INSERT INTO subscriptions VALUES (?,?,?)", label, addr, True)
|
||||
sqlExecute("INSERT INTO subscriptions VALUES (?,?,?)", dbstr(label), dbstr(addr), True)
|
||||
shared.reloadBroadcastSendersForWhichImWatching()
|
||||
elif t == "2":
|
||||
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":
|
||||
sqlExecute(
|
||||
"DELETE FROM subscriptions WHERE label=? AND address=?",
|
||||
subscriptions[subcur][0],
|
||||
subscriptions[subcur][1])
|
||||
dbstr(subscriptions[subcur][0]),
|
||||
dbstr(subscriptions[subcur][1]))
|
||||
shared.reloadBroadcastSendersForWhichImWatching()
|
||||
del subscriptions[subcur]
|
||||
elif t == "3":
|
||||
sqlExecute(
|
||||
"UPDATE subscriptions SET enabled=1 WHERE label=? AND address=?",
|
||||
subscriptions[subcur][0],
|
||||
subscriptions[subcur][1])
|
||||
dbstr(subscriptions[subcur][0]),
|
||||
dbstr(subscriptions[subcur][1]))
|
||||
shared.reloadBroadcastSendersForWhichImWatching()
|
||||
subscriptions[subcur][2] = True
|
||||
elif t == "4":
|
||||
sqlExecute(
|
||||
"UPDATE subscriptions SET enabled=0 WHERE label=? AND address=?",
|
||||
subscriptions[subcur][0],
|
||||
subscriptions[subcur][1])
|
||||
dbstr(subscriptions[subcur][0]),
|
||||
dbstr(subscriptions[subcur][1]))
|
||||
shared.reloadBroadcastSendersForWhichImWatching()
|
||||
subscriptions[subcur][2] = False
|
||||
elif menutab == 6:
|
||||
|
@ -762,7 +789,7 @@ def handlech(c, stdscr):
|
|||
subscriptions.append([label, addr, True])
|
||||
subscriptions.reverse()
|
||||
|
||||
sqlExecute("INSERT INTO subscriptions VALUES (?,?,?)", label, addr, True)
|
||||
sqlExecute("INSERT INTO subscriptions VALUES (?,?,?)", dbstr(label), dbstr(addr), True)
|
||||
shared.reloadBroadcastSendersForWhichImWatching()
|
||||
elif t == "3":
|
||||
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)]:
|
||||
r, t = d.inputbox("Label for address \"" + addr + "\"")
|
||||
if r == d.DIALOG_OK:
|
||||
sqlExecute("INSERT INTO addressbook VALUES (?,?)", t, addr)
|
||||
sqlExecute("INSERT INTO addressbook VALUES (?,?)", dbstr(t), dbstr(addr))
|
||||
# Prepend entry
|
||||
addrbook.reverse()
|
||||
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":
|
||||
sqlExecute(
|
||||
"DELETE FROM addressbook WHERE label=? AND address=?",
|
||||
addrbook[abookcur][0],
|
||||
addrbook[abookcur][1])
|
||||
dbstr(addrbook[abookcur][0]),
|
||||
dbstr(addrbook[abookcur][1]))
|
||||
del addrbook[abookcur]
|
||||
elif menutab == 7:
|
||||
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":
|
||||
sqlExecute(
|
||||
"DELETE FROM blacklist WHERE label=? AND address=?",
|
||||
blacklist[blackcur][0],
|
||||
blacklist[blackcur][1])
|
||||
dbstr(blacklist[blackcur][0]),
|
||||
dbstr(blacklist[blackcur][1]))
|
||||
del blacklist[blackcur]
|
||||
elif t == "2":
|
||||
sqlExecute(
|
||||
"UPDATE blacklist SET enabled=1 WHERE label=? AND address=?",
|
||||
blacklist[blackcur][0],
|
||||
blacklist[blackcur][1])
|
||||
dbstr(blacklist[blackcur][0]),
|
||||
dbstr(blacklist[blackcur][1]))
|
||||
blacklist[blackcur][2] = True
|
||||
elif t == "3":
|
||||
sqlExecute(
|
||||
"UPDATE blacklist SET enabled=0 WHERE label=? AND address=?",
|
||||
blacklist[blackcur][0],
|
||||
blacklist[blackcur][1])
|
||||
dbstr(blacklist[blackcur][0]),
|
||||
dbstr(blacklist[blackcur][1]))
|
||||
blacklist[blackcur][2] = False
|
||||
dialogreset(stdscr)
|
||||
else:
|
||||
|
@ -991,10 +1018,13 @@ def loadInbox():
|
|||
ret = sqlQuery("""SELECT msgid, toaddress, fromaddress, subject, received, read
|
||||
FROM inbox WHERE folder='inbox' AND %s LIKE ?
|
||||
ORDER BY received
|
||||
""" % (where,), what)
|
||||
""" % (where,), dbstr(what))
|
||||
for row in ret:
|
||||
msgid, toaddr, fromaddr, subject, received, read = row
|
||||
toaddr = toaddr.decode("utf-8", "replace")
|
||||
fromaddr = fromaddr.decode("utf-8", "replace")
|
||||
subject = ascii(shared.fixPotentiallyInvalidUTF8Data(subject))
|
||||
received = received.decode("utf-8", "replace")
|
||||
|
||||
# Set label for to address
|
||||
try:
|
||||
|
@ -1013,18 +1043,19 @@ def loadInbox():
|
|||
if config.has_section(fromaddr):
|
||||
fromlabel = config.get(fromaddr, "label")
|
||||
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 != []:
|
||||
for r in qr:
|
||||
fromlabel, = r
|
||||
fromlabel = shared.fixPotentiallyInvalidUTF8Data(fromlabel)
|
||||
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 != []:
|
||||
for r in qr:
|
||||
fromlabel, = r
|
||||
fromlabel = shared.fixPotentiallyInvalidUTF8Data(fromlabel)
|
||||
if fromlabel == "":
|
||||
fromlabel = fromaddr
|
||||
fromlabel = shared.fixPotentiallyInvalidUTF8Data(fromlabel)
|
||||
|
||||
# Load into array
|
||||
inbox.append([
|
||||
|
@ -1044,22 +1075,27 @@ def loadSent():
|
|||
ret = sqlQuery("""SELECT toaddress, fromaddress, subject, status, ackdata, lastactiontime
|
||||
FROM sent WHERE folder='sent' AND %s LIKE ?
|
||||
ORDER BY lastactiontime
|
||||
""" % (where,), what)
|
||||
""" % (where,), dbstr(what))
|
||||
for row in ret:
|
||||
toaddr, fromaddr, subject, status, ackdata, lastactiontime = row
|
||||
toaddr = toaddr.decode("utf-8", "replace")
|
||||
fromaddr = fromaddr.decode("utf-8", "replace")
|
||||
subject = ascii(shared.fixPotentiallyInvalidUTF8Data(subject))
|
||||
status = status.decode("utf-8", "replace")
|
||||
|
||||
# Set label for to address
|
||||
tolabel = ""
|
||||
qr = sqlQuery("SELECT label FROM addressbook WHERE address=?", toaddr)
|
||||
qr = sqlQuery("SELECT label FROM addressbook WHERE address=?", dbstr(toaddr))
|
||||
if qr != []:
|
||||
for r in qr:
|
||||
tolabel, = r
|
||||
tolabel = tolabel.decode("utf-8", "replace")
|
||||
if tolabel == "":
|
||||
qr = sqlQuery("SELECT label FROM subscriptions WHERE address=?", toaddr)
|
||||
qr = sqlQuery("SELECT label FROM subscriptions WHERE address=?", dbstr(toaddr))
|
||||
if qr != []:
|
||||
for r in qr:
|
||||
tolabel, = r
|
||||
tolabel = tolabel.decode("utf-8", "replace")
|
||||
if tolabel == "":
|
||||
if config.has_section(toaddr):
|
||||
tolabel = config.get(toaddr, "label")
|
||||
|
@ -1129,6 +1165,7 @@ def loadAddrBook():
|
|||
for row in ret:
|
||||
label, addr = row
|
||||
label = shared.fixPotentiallyInvalidUTF8Data(label)
|
||||
addr = addr.decode("utf-8", "replace")
|
||||
addrbook.append([label, addr])
|
||||
addrbook.reverse()
|
||||
|
||||
|
@ -1138,6 +1175,8 @@ def loadSubscriptions():
|
|||
ret = sqlQuery("SELECT label, address, enabled FROM subscriptions")
|
||||
for row in ret:
|
||||
label, address, enabled = row
|
||||
label = label.decode("utf-8", "replace")
|
||||
address = address.decode("utf-8", "replace")
|
||||
subscriptions.append([label, address, enabled])
|
||||
subscriptions.reverse()
|
||||
|
||||
|
@ -1152,6 +1191,8 @@ def loadBlackWhiteList():
|
|||
ret = sqlQuery("SELECT label, address, enabled FROM whitelist")
|
||||
for row in ret:
|
||||
label, address, enabled = row
|
||||
label = label.decode("utf-8", "replace")
|
||||
address = address.decode("utf-8", "replace")
|
||||
blacklist.append([label, address, enabled])
|
||||
blacklist.reverse()
|
||||
|
||||
|
|
|
@ -29,6 +29,7 @@ from pybitmessage.bitmessagekivy.baseclass.common import (
|
|||
from pybitmessage.bitmessagekivy.baseclass.popup import SavedAddressDetailPopup
|
||||
from pybitmessage.bitmessagekivy.baseclass.addressbook_widgets import HelperAddressBook
|
||||
from pybitmessage.helper_sql import sqlExecute
|
||||
from dbcompat import dbstr
|
||||
|
||||
logger = logging.getLogger('default')
|
||||
|
||||
|
@ -59,7 +60,7 @@ class AddressBook(Screen, HelperAddressBook):
|
|||
self.ids.tag_label.text = ''
|
||||
self.queryreturn = kivy_helper_search.search_sql(
|
||||
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:
|
||||
self.ids.tag_label.text = 'Address Book'
|
||||
self.has_refreshed = True
|
||||
|
@ -131,7 +132,7 @@ class AddressBook(Screen, HelperAddressBook):
|
|||
if self.ids.ml.children is not None:
|
||||
self.ids.tag_label.text = ''
|
||||
sqlExecute(
|
||||
"DELETE FROM addressbook WHERE address = ?", address)
|
||||
"DELETE FROM addressbook WHERE address = ?", dbstr(address))
|
||||
toast('Address Deleted')
|
||||
|
||||
def close_pop(self, instance):
|
||||
|
@ -142,8 +143,13 @@ class AddressBook(Screen, HelperAddressBook):
|
|||
def update_addbook_label(self, instance):
|
||||
"""Updating the label of address book address"""
|
||||
address_list = kivy_helper_search.search_sql(folder="addressbook")
|
||||
stored_labels = [labels[0] for labels in address_list]
|
||||
add_dict = dict(address_list)
|
||||
stored_labels = [labels[0].decode("utf-8", "replace") for labels in 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)
|
||||
if label in stored_labels and self.address == add_dict[label]:
|
||||
stored_labels.remove(label)
|
||||
|
@ -151,7 +157,7 @@ class AddressBook(Screen, HelperAddressBook):
|
|||
sqlExecute("""
|
||||
UPDATE addressbook
|
||||
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.loadAddresslist(None, 'All', '')
|
||||
self.addbook_popup.dismiss()
|
||||
|
|
|
@ -7,6 +7,7 @@ Maildetail screen for inbox, sent, draft and trash.
|
|||
|
||||
import os
|
||||
from datetime import datetime
|
||||
import sqlite3
|
||||
|
||||
from kivy.core.clipboard import Clipboard
|
||||
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':
|
||||
data = sqlQuery(
|
||||
"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)
|
||||
App.get_running_app().set_mail_detail_header()
|
||||
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):
|
||||
"""Assigning mail details"""
|
||||
subject = data[0][2].decode() 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]
|
||||
self.to_addr = data[0][0] if len(data[0][0]) > 4 else ' '
|
||||
self.from_addr = data[0][1]
|
||||
subject = data[0][2].decode("utf-8", "replace") if isinstance(data[0][2], bytes) else data[0][2]
|
||||
body = data[0][3].decode("utf-8", "replace") if isinstance(data[0][2], bytes) else data[0][3]
|
||||
self.to_addr = data[0][0].decode("utf-8", "replace") if len(data[0][0]) > 4 else ' '
|
||||
self.from_addr = data[0][1].decode("utf-8", "replace")
|
||||
|
||||
self.subject = subject.capitalize(
|
||||
) if subject.capitalize() else self.no_subject
|
||||
self.message = body
|
||||
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' \
|
||||
else show_time_history(data[0][6])
|
||||
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"""
|
||||
my_addresses = (
|
||||
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")]
|
||||
entered_text = str(instance.text).strip()
|
||||
if entered_text in add_book:
|
||||
|
@ -84,7 +84,7 @@ class AddAddressPopup(BoxLayout):
|
|||
def checkLabel_valid(self, instance):
|
||||
"""Checking address label is unique or not"""
|
||||
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")]
|
||||
if entered_label in addr_labels:
|
||||
self.ids.label.error = True
|
||||
|
@ -125,8 +125,13 @@ class SavedAddressDetailPopup(BoxLayout):
|
|||
"""Checking address label is unique of not"""
|
||||
entered_label = str(instance.text.strip())
|
||||
address_list = kivy_helper_search.search_sql(folder="addressbook")
|
||||
addr_labels = [labels[0] for labels in address_list]
|
||||
add_dict = dict(address_list)
|
||||
addr_labels = [labels[0].decode("utf-8", "replace") for labels in 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 \
|
||||
and self.address != add_dict[entered_label]:
|
||||
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
|
||||
"""
|
||||
import hashlib
|
||||
from io import BytesIO
|
||||
from six import BytesIO
|
||||
|
||||
from PIL import Image
|
||||
from kivy.core.image import Image as CoreImage
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
Sql queries for bitmessagekivy
|
||||
"""
|
||||
from pybitmessage.helper_sql import sqlQuery
|
||||
from dbcompat import dbstr
|
||||
|
||||
|
||||
def search_sql(
|
||||
|
@ -30,21 +31,21 @@ def search_sql(
|
|||
if account is not None:
|
||||
if xAddress == 'both':
|
||||
sqlStatementParts.append("(fromaddress = ? OR toaddress = ?)")
|
||||
sqlArguments.append(account)
|
||||
sqlArguments.append(account)
|
||||
sqlArguments.append(dbstr(account))
|
||||
sqlArguments.append(dbstr(account))
|
||||
else:
|
||||
sqlStatementParts.append(xAddress + " = ? ")
|
||||
sqlArguments.append(account)
|
||||
sqlArguments.append(dbstr(account))
|
||||
if folder != "addressbook":
|
||||
if folder is not None:
|
||||
if folder == "new":
|
||||
folder = "inbox"
|
||||
unreadOnly = True
|
||||
sqlStatementParts.append("folder = ? ")
|
||||
sqlArguments.append(folder)
|
||||
sqlArguments.append(dbstr(folder))
|
||||
else:
|
||||
sqlStatementParts.append("folder != ?")
|
||||
sqlArguments.append("trash")
|
||||
sqlArguments.append(dbstr("trash"))
|
||||
if what is not None:
|
||||
for colmns in where:
|
||||
if len(where) > 1:
|
||||
|
@ -54,7 +55,7 @@ def search_sql(
|
|||
filter_col += " or %s LIKE ? )" % (colmns)
|
||||
else:
|
||||
filter_col = "%s LIKE ?" % (colmns)
|
||||
sqlArguments.append(what)
|
||||
sqlArguments.append(dbstr(what))
|
||||
sqlStatementParts.append(filter_col)
|
||||
if unreadOnly:
|
||||
sqlStatementParts.append("read = 0")
|
||||
|
|
|
@ -6,6 +6,7 @@ import os
|
|||
import shutil
|
||||
import tempfile
|
||||
from time import time, sleep
|
||||
from six.moves import getcwdb
|
||||
|
||||
from requests.exceptions import ChunkedEncodingError
|
||||
|
||||
|
@ -34,7 +35,7 @@ def cleanup(files=_files):
|
|||
|
||||
class TeleniumTestProcess(TeleniumTestCase):
|
||||
"""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
|
||||
def setUpClass(cls):
|
||||
|
|
|
@ -4,6 +4,7 @@ PyQt based UI for bitmessage, the main module
|
|||
|
||||
import hashlib
|
||||
import locale
|
||||
import logging
|
||||
import os
|
||||
import random
|
||||
import string
|
||||
|
@ -14,46 +15,52 @@ import threading
|
|||
import time
|
||||
from datetime import datetime, timedelta
|
||||
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 PyQt4 import QtCore, QtGui
|
||||
from PyQt4.QtNetwork import QLocalSocket, QLocalServer
|
||||
from unqstr import ustr, unic
|
||||
from dbcompat import dbstr
|
||||
from qtpy import QtCore, QtGui, QtWidgets, QtNetwork
|
||||
|
||||
import shared
|
||||
import state
|
||||
from debug import logger
|
||||
from tr import _translate
|
||||
from account import (
|
||||
from .account import (
|
||||
accountClass, getSortedSubscriptions,
|
||||
BMAccount, GatewayAccount, MailchuckAccount, AccountColor)
|
||||
from addresses import decodeAddress, addBMIfNotPresent
|
||||
from bitmessageui import Ui_MainWindow
|
||||
from bitmessageqt.bitmessageui import Ui_MainWindow
|
||||
from bmconfigparser import config
|
||||
import namecoin
|
||||
from messageview import MessageView
|
||||
from migrationwizard import Ui_MigrationWizard
|
||||
from foldertree import (
|
||||
from .messageview import MessageView
|
||||
from .migrationwizard import Ui_MigrationWizard
|
||||
from .foldertree import (
|
||||
AccountMixin, Ui_FolderWidget, Ui_AddressWidget, Ui_SubscriptionWidget,
|
||||
MessageList_AddressWidget, MessageList_SubjectWidget,
|
||||
Ui_AddressBookWidgetItemLabel, Ui_AddressBookWidgetItemAddress,
|
||||
MessageList_TimeWidget)
|
||||
import settingsmixin
|
||||
import support
|
||||
from bitmessageqt import settingsmixin
|
||||
from bitmessageqt import support
|
||||
from helper_sql import sqlQuery, sqlExecute, sqlExecuteChunked, sqlStoredProcedure
|
||||
import helper_addressbook
|
||||
import helper_search
|
||||
import l10n
|
||||
from utils import str_broadcast_subscribers, avatarize
|
||||
import dialogs
|
||||
from .utils import str_broadcast_subscribers, avatarize
|
||||
from bitmessageqt import dialogs
|
||||
from network.stats import pendingDownload, pendingUpload
|
||||
from uisignaler import UISignaler
|
||||
from .uisignaler import UISignaler
|
||||
import paths
|
||||
from proofofwork import getPowType
|
||||
import queues
|
||||
import shutdown
|
||||
from statusbar import BMStatusBar
|
||||
import sound
|
||||
from .statusbar import BMStatusBar
|
||||
from bitmessageqt import sound
|
||||
# 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
|
||||
|
||||
try:
|
||||
|
@ -61,6 +68,7 @@ try:
|
|||
except ImportError:
|
||||
get_plugins = False
|
||||
|
||||
logger = logging.getLogger('default')
|
||||
|
||||
is_windows = sys.platform.startswith('win')
|
||||
|
||||
|
@ -87,6 +95,13 @@ def openKeysFile():
|
|||
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):
|
||||
|
||||
# the maximum frequency of message sounds in seconds
|
||||
|
@ -102,12 +117,12 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
newlocale = l10n.getTranslationLanguage()
|
||||
try:
|
||||
if not self.qmytranslator.isEmpty():
|
||||
QtGui.QApplication.removeTranslator(self.qmytranslator)
|
||||
QtWidgets.QApplication.removeTranslator(self.qmytranslator)
|
||||
except:
|
||||
pass
|
||||
try:
|
||||
if not self.qsystranslator.isEmpty():
|
||||
QtGui.QApplication.removeTranslator(self.qsystranslator)
|
||||
QtWidgets.QApplication.removeTranslator(self.qsystranslator)
|
||||
except:
|
||||
pass
|
||||
|
||||
|
@ -115,7 +130,7 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
translationpath = os.path.join(
|
||||
paths.codePath(), 'translations', 'bitmessage_' + newlocale)
|
||||
self.qmytranslator.load(translationpath)
|
||||
QtGui.QApplication.installTranslator(self.qmytranslator)
|
||||
QtWidgets.QApplication.installTranslator(self.qmytranslator)
|
||||
|
||||
self.qsystranslator = QtCore.QTranslator()
|
||||
if paths.frozen:
|
||||
|
@ -123,10 +138,10 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
paths.codePath(), 'translations', 'qt_' + newlocale)
|
||||
else:
|
||||
translationpath = os.path.join(
|
||||
str(QtCore.QLibraryInfo.location(
|
||||
ustr(QtCore.QLibraryInfo.location(
|
||||
QtCore.QLibraryInfo.TranslationsPath)), 'qt_' + newlocale)
|
||||
self.qsystranslator.load(translationpath)
|
||||
QtGui.QApplication.installTranslator(self.qsystranslator)
|
||||
QtWidgets.QApplication.installTranslator(self.qsystranslator)
|
||||
|
||||
# TODO: move this block into l10n
|
||||
# FIXME: shouldn't newlocale be used here?
|
||||
|
@ -151,50 +166,35 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
logger.error("Failed to set locale to %s", lang, exc_info=True)
|
||||
|
||||
def init_file_menu(self):
|
||||
QtCore.QObject.connect(self.ui.actionExit, QtCore.SIGNAL(
|
||||
"triggered()"), self.quit)
|
||||
QtCore.QObject.connect(self.ui.actionNetworkSwitch, QtCore.SIGNAL(
|
||||
"triggered()"), self.network_switch)
|
||||
QtCore.QObject.connect(self.ui.actionManageKeys, QtCore.SIGNAL(
|
||||
"triggered()"), self.click_actionManageKeys)
|
||||
QtCore.QObject.connect(self.ui.actionDeleteAllTrashedMessages,
|
||||
QtCore.SIGNAL(
|
||||
"triggered()"),
|
||||
self.ui.actionExit.triggered.connect(self.quit)
|
||||
self.ui.actionNetworkSwitch.triggered.connect(self.network_switch)
|
||||
self.ui.actionManageKeys.triggered.connect(self.click_actionManageKeys)
|
||||
self.ui.actionDeleteAllTrashedMessages.triggered.connect(
|
||||
self.click_actionDeleteAllTrashedMessages)
|
||||
QtCore.QObject.connect(self.ui.actionRegenerateDeterministicAddresses,
|
||||
QtCore.SIGNAL(
|
||||
"triggered()"),
|
||||
self.ui.actionRegenerateDeterministicAddresses.triggered.connect(
|
||||
self.click_actionRegenerateDeterministicAddresses)
|
||||
QtCore.QObject.connect(
|
||||
self.ui.pushButtonAddChan,
|
||||
QtCore.SIGNAL("clicked()"),
|
||||
self.click_actionJoinChan) # also used for creating chans.
|
||||
QtCore.QObject.connect(self.ui.pushButtonNewAddress, QtCore.SIGNAL(
|
||||
"clicked()"), self.click_NewAddressDialog)
|
||||
QtCore.QObject.connect(self.ui.pushButtonAddAddressBook, QtCore.SIGNAL(
|
||||
"clicked()"), self.click_pushButtonAddAddressBook)
|
||||
QtCore.QObject.connect(self.ui.pushButtonAddSubscription, QtCore.SIGNAL(
|
||||
"clicked()"), self.click_pushButtonAddSubscription)
|
||||
QtCore.QObject.connect(self.ui.pushButtonTTL, QtCore.SIGNAL(
|
||||
"clicked()"), self.click_pushButtonTTL)
|
||||
QtCore.QObject.connect(self.ui.pushButtonClear, QtCore.SIGNAL(
|
||||
"clicked()"), self.click_pushButtonClear)
|
||||
QtCore.QObject.connect(self.ui.pushButtonSend, QtCore.SIGNAL(
|
||||
"clicked()"), self.click_pushButtonSend)
|
||||
QtCore.QObject.connect(self.ui.pushButtonFetchNamecoinID, QtCore.SIGNAL(
|
||||
"clicked()"), self.click_pushButtonFetchNamecoinID)
|
||||
QtCore.QObject.connect(self.ui.actionSettings, QtCore.SIGNAL(
|
||||
"triggered()"), self.click_actionSettings)
|
||||
QtCore.QObject.connect(self.ui.actionAbout, QtCore.SIGNAL(
|
||||
"triggered()"), self.click_actionAbout)
|
||||
QtCore.QObject.connect(self.ui.actionSupport, QtCore.SIGNAL(
|
||||
"triggered()"), self.click_actionSupport)
|
||||
QtCore.QObject.connect(self.ui.actionHelp, QtCore.SIGNAL(
|
||||
"triggered()"), self.click_actionHelp)
|
||||
self.ui.actionSettings.triggered.connect(self.click_actionSettings)
|
||||
self.ui.actionAbout.triggered.connect(self.click_actionAbout)
|
||||
self.ui.actionSupport.triggered.connect(self.click_actionSupport)
|
||||
self.ui.actionHelp.triggered.connect(self.click_actionHelp)
|
||||
|
||||
# also used for creating chans.
|
||||
self.ui.pushButtonAddChan.clicked.connect(self.click_actionJoinChan)
|
||||
self.ui.pushButtonNewAddress.clicked.connect(
|
||||
self.click_NewAddressDialog)
|
||||
self.ui.pushButtonAddAddressBook.clicked.connect(
|
||||
self.click_pushButtonAddAddressBook)
|
||||
self.ui.pushButtonAddSubscription.clicked.connect(
|
||||
self.click_pushButtonAddSubscription)
|
||||
self.ui.pushButtonTTL.clicked.connect(self.click_pushButtonTTL)
|
||||
self.ui.pushButtonClear.clicked.connect(self.click_pushButtonClear)
|
||||
self.ui.pushButtonSend.clicked.connect(self.click_pushButtonSend)
|
||||
self.ui.pushButtonFetchNamecoinID.clicked.connect(
|
||||
self.click_pushButtonFetchNamecoinID)
|
||||
|
||||
def init_inbox_popup_menu(self, connectSignal=True):
|
||||
# Popup menu for the Inbox tab
|
||||
self.ui.inboxContextMenuToolbar = QtGui.QToolBar()
|
||||
self.ui.inboxContextMenuToolbar = QtWidgets.QToolBar()
|
||||
# Actions
|
||||
self.actionReply = self.ui.inboxContextMenuToolbar.addAction(_translate(
|
||||
"MainWindow", "Reply to sender"), self.on_action_InboxReply)
|
||||
|
@ -230,25 +230,22 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
self.ui.tableWidgetInbox.setContextMenuPolicy(
|
||||
QtCore.Qt.CustomContextMenu)
|
||||
if connectSignal:
|
||||
self.connect(self.ui.tableWidgetInbox, QtCore.SIGNAL(
|
||||
'customContextMenuRequested(const QPoint&)'),
|
||||
self.ui.tableWidgetInbox.customContextMenuRequested.connect(
|
||||
self.on_context_menuInbox)
|
||||
self.ui.tableWidgetInboxSubscriptions.setContextMenuPolicy(
|
||||
QtCore.Qt.CustomContextMenu)
|
||||
if connectSignal:
|
||||
self.connect(self.ui.tableWidgetInboxSubscriptions, QtCore.SIGNAL(
|
||||
'customContextMenuRequested(const QPoint&)'),
|
||||
self.ui.tableWidgetInboxSubscriptions.customContextMenuRequested.connect(
|
||||
self.on_context_menuInbox)
|
||||
self.ui.tableWidgetInboxChans.setContextMenuPolicy(
|
||||
QtCore.Qt.CustomContextMenu)
|
||||
if connectSignal:
|
||||
self.connect(self.ui.tableWidgetInboxChans, QtCore.SIGNAL(
|
||||
'customContextMenuRequested(const QPoint&)'),
|
||||
self.ui.tableWidgetInboxChans.customContextMenuRequested.connect(
|
||||
self.on_context_menuInbox)
|
||||
|
||||
def init_identities_popup_menu(self, connectSignal=True):
|
||||
# Popup menu for the Your Identities tab
|
||||
self.ui.addressContextMenuToolbarYourIdentities = QtGui.QToolBar()
|
||||
self.ui.addressContextMenuToolbarYourIdentities = QtWidgets.QToolBar()
|
||||
# Actions
|
||||
self.actionNewYourIdentities = self.ui.addressContextMenuToolbarYourIdentities.addAction(_translate(
|
||||
"MainWindow", "New"), self.on_action_YourIdentitiesNew)
|
||||
|
@ -282,8 +279,7 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
self.ui.treeWidgetYourIdentities.setContextMenuPolicy(
|
||||
QtCore.Qt.CustomContextMenu)
|
||||
if connectSignal:
|
||||
self.connect(self.ui.treeWidgetYourIdentities, QtCore.SIGNAL(
|
||||
'customContextMenuRequested(const QPoint&)'),
|
||||
self.ui.treeWidgetYourIdentities.customContextMenuRequested.connect(
|
||||
self.on_context_menuYourIdentities)
|
||||
|
||||
# load all gui.menu plugins with prefix 'address'
|
||||
|
@ -332,13 +328,12 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
self.ui.treeWidgetChans.setContextMenuPolicy(
|
||||
QtCore.Qt.CustomContextMenu)
|
||||
if connectSignal:
|
||||
self.connect(self.ui.treeWidgetChans, QtCore.SIGNAL(
|
||||
'customContextMenuRequested(const QPoint&)'),
|
||||
self.ui.treeWidgetChans.customContextMenuRequested.connect(
|
||||
self.on_context_menuChan)
|
||||
|
||||
def init_addressbook_popup_menu(self, connectSignal=True):
|
||||
# Popup menu for the Address Book page
|
||||
self.ui.addressBookContextMenuToolbar = QtGui.QToolBar()
|
||||
self.ui.addressBookContextMenuToolbar = QtWidgets.QToolBar()
|
||||
# Actions
|
||||
self.actionAddressBookSend = self.ui.addressBookContextMenuToolbar.addAction(
|
||||
_translate(
|
||||
|
@ -369,8 +364,7 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
self.ui.tableWidgetAddressBook.setContextMenuPolicy(
|
||||
QtCore.Qt.CustomContextMenu)
|
||||
if connectSignal:
|
||||
self.connect(self.ui.tableWidgetAddressBook, QtCore.SIGNAL(
|
||||
'customContextMenuRequested(const QPoint&)'),
|
||||
self.ui.tableWidgetAddressBook.customContextMenuRequested.connect(
|
||||
self.on_context_menuAddressBook)
|
||||
|
||||
def init_subscriptions_popup_menu(self, connectSignal=True):
|
||||
|
@ -398,8 +392,7 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
self.ui.treeWidgetSubscriptions.setContextMenuPolicy(
|
||||
QtCore.Qt.CustomContextMenu)
|
||||
if connectSignal:
|
||||
self.connect(self.ui.treeWidgetSubscriptions, QtCore.SIGNAL(
|
||||
'customContextMenuRequested(const QPoint&)'),
|
||||
self.ui.treeWidgetSubscriptions.customContextMenuRequested.connect(
|
||||
self.on_context_menuSubscriptions)
|
||||
|
||||
def init_sent_popup_menu(self, connectSignal=True):
|
||||
|
@ -417,14 +410,14 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
self.actionSentReply = self.ui.sentContextMenuToolbar.addAction(
|
||||
_translate("MainWindow", "Send update"),
|
||||
self.on_action_SentReply)
|
||||
# self.popMenuSent = QtGui.QMenu( self )
|
||||
# self.popMenuSent = QtWidgets.QMenu( self )
|
||||
# self.popMenuSent.addAction( self.actionSentClipboard )
|
||||
# self.popMenuSent.addAction( self.actionTrashSentMessage )
|
||||
|
||||
def rerenderTabTreeSubscriptions(self):
|
||||
treeWidget = self.ui.treeWidgetSubscriptions
|
||||
folders = Ui_FolderWidget.folderWeight.keys()
|
||||
folders.remove("new")
|
||||
Ui_FolderWidget.folderWeight.pop("new", None)
|
||||
|
||||
# sort ascending when creating
|
||||
if treeWidget.topLevelItemCount() == 0:
|
||||
|
@ -441,7 +434,6 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
if treeWidget.isSortingEnabled():
|
||||
treeWidget.setSortingEnabled(False)
|
||||
|
||||
widgets = {}
|
||||
i = 0
|
||||
while i < treeWidget.topLevelItemCount():
|
||||
widget = treeWidget.topLevelItem(i)
|
||||
|
@ -459,7 +451,8 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
while j < widget.childCount():
|
||||
subwidget = widget.child(j)
|
||||
try:
|
||||
subwidget.setUnreadCount(db[toAddress][subwidget.folderName]['count'])
|
||||
subwidget.setUnreadCount(
|
||||
db[toAddress][subwidget.folderName]['count'])
|
||||
unread += db[toAddress][subwidget.folderName]['count']
|
||||
db[toAddress].pop(subwidget.folderName, None)
|
||||
except:
|
||||
|
@ -471,9 +464,10 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
# add missing folders
|
||||
if len(db[toAddress]) > 0:
|
||||
j = 0
|
||||
for f, c in db[toAddress].iteritems():
|
||||
for f, c in six.iteritems(db[toAddress]):
|
||||
try:
|
||||
subwidget = Ui_FolderWidget(widget, j, toAddress, f, c['count'])
|
||||
subwidget = Ui_FolderWidget(
|
||||
widget, j, toAddress, f, c['count'])
|
||||
except KeyError:
|
||||
subwidget = Ui_FolderWidget(widget, j, toAddress, f, 0)
|
||||
j += 1
|
||||
|
@ -484,20 +478,20 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
i = 0
|
||||
for toAddress in db:
|
||||
widget = Ui_SubscriptionWidget(
|
||||
treeWidget,
|
||||
i,
|
||||
toAddress,
|
||||
db[toAddress]["inbox"]['count'],
|
||||
treeWidget, i, toAddress, db[toAddress]["inbox"]['count'],
|
||||
db[toAddress]["inbox"]['label'],
|
||||
db[toAddress]["inbox"]['enabled'])
|
||||
j = 0
|
||||
unread = 0
|
||||
for folder in folders:
|
||||
try:
|
||||
subwidget = Ui_FolderWidget(widget, j, toAddress, folder, db[toAddress][folder]['count'])
|
||||
subwidget = Ui_FolderWidget(
|
||||
widget, j, toAddress, folder,
|
||||
db[toAddress][folder]['count'])
|
||||
unread += db[toAddress][folder]['count']
|
||||
except KeyError:
|
||||
subwidget = Ui_FolderWidget(widget, j, toAddress, folder, 0)
|
||||
subwidget = Ui_FolderWidget(
|
||||
widget, j, toAddress, folder, 0)
|
||||
j += 1
|
||||
widget.setUnreadCount(unread)
|
||||
i += 1
|
||||
|
@ -530,8 +524,8 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
toAddress, 'enabled')
|
||||
isChan = config.safeGetBoolean(
|
||||
toAddress, 'chan')
|
||||
isMaillinglist = config.safeGetBoolean(
|
||||
toAddress, 'mailinglist')
|
||||
# isMaillinglist = config.safeGetBoolean(
|
||||
# toAddress, 'mailinglist')
|
||||
|
||||
if treeWidget == self.ui.treeWidgetYourIdentities:
|
||||
if isChan:
|
||||
|
@ -555,6 +549,8 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
"GROUP BY toaddress, folder")
|
||||
for row in queryreturn:
|
||||
toaddress, folder, cnt = row
|
||||
toaddress = toaddress.decode("utf-8", "replace")
|
||||
folder = folder.decode("utf-8", "replace")
|
||||
total += cnt
|
||||
if toaddress in db and folder in db[toaddress]:
|
||||
db[toaddress][folder] = cnt
|
||||
|
@ -569,7 +565,6 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
if treeWidget.isSortingEnabled():
|
||||
treeWidget.setSortingEnabled(False)
|
||||
|
||||
widgets = {}
|
||||
i = 0
|
||||
while i < treeWidget.topLevelItemCount():
|
||||
widget = treeWidget.topLevelItem(i)
|
||||
|
@ -601,7 +596,7 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
# add missing folders
|
||||
if len(db[toAddress]) > 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":
|
||||
continue
|
||||
subwidget = Ui_FolderWidget(widget, j, toAddress, f, c)
|
||||
|
@ -630,7 +625,7 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
treeWidget.setSortingEnabled(True)
|
||||
|
||||
def __init__(self, parent=None):
|
||||
QtGui.QWidget.__init__(self, parent)
|
||||
super(MyForm, self).__init__(parent)
|
||||
self.ui = Ui_MainWindow()
|
||||
self.ui.setupUi(self)
|
||||
|
||||
|
@ -649,12 +644,12 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
if addressVersionNumber == 1:
|
||||
displayMsg = _translate(
|
||||
"MainWindow",
|
||||
"One of your addresses, %1, is an old version 1 address. "
|
||||
"Version 1 addresses are no longer supported. "
|
||||
"May we delete it now?").arg(addressInKeysFile)
|
||||
reply = QtGui.QMessageBox.question(
|
||||
self, 'Message', displayMsg, QtGui.QMessageBox.Yes, QtGui.QMessageBox.No)
|
||||
if reply == QtGui.QMessageBox.Yes:
|
||||
"One of your addresses, {0}, is an old version 1"
|
||||
" address. Version 1 addresses are no longer supported."
|
||||
" May we delete it now?").format(addressInKeysFile)
|
||||
reply = QtWidgets.QMessageBox.question(
|
||||
self, 'Message', displayMsg, QtWidgets.QMessageBox.Yes, QtWidgets.QMessageBox.No)
|
||||
if reply == QtWidgets.QMessageBox.Yes:
|
||||
config.remove_section(addressInKeysFile)
|
||||
config.save()
|
||||
|
||||
|
@ -698,111 +693,97 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
self.rerenderSubscriptions()
|
||||
|
||||
# Initialize the inbox search
|
||||
QtCore.QObject.connect(self.ui.inboxSearchLineEdit, QtCore.SIGNAL(
|
||||
"returnPressed()"), self.inboxSearchLineEditReturnPressed)
|
||||
QtCore.QObject.connect(self.ui.inboxSearchLineEditSubscriptions, QtCore.SIGNAL(
|
||||
"returnPressed()"), self.inboxSearchLineEditReturnPressed)
|
||||
QtCore.QObject.connect(self.ui.inboxSearchLineEditChans, QtCore.SIGNAL(
|
||||
"returnPressed()"), self.inboxSearchLineEditReturnPressed)
|
||||
QtCore.QObject.connect(self.ui.inboxSearchLineEdit, QtCore.SIGNAL(
|
||||
"textChanged(QString)"), self.inboxSearchLineEditUpdated)
|
||||
QtCore.QObject.connect(self.ui.inboxSearchLineEditSubscriptions, QtCore.SIGNAL(
|
||||
"textChanged(QString)"), self.inboxSearchLineEditUpdated)
|
||||
QtCore.QObject.connect(self.ui.inboxSearchLineEditChans, QtCore.SIGNAL(
|
||||
"textChanged(QString)"), self.inboxSearchLineEditUpdated)
|
||||
for line_edit in (
|
||||
self.ui.inboxSearchLineEdit,
|
||||
self.ui.inboxSearchLineEditSubscriptions,
|
||||
self.ui.inboxSearchLineEditChans,
|
||||
):
|
||||
line_edit.returnPressed.connect(
|
||||
self.inboxSearchLineEditReturnPressed)
|
||||
line_edit.textChanged.connect(
|
||||
self.inboxSearchLineEditUpdated)
|
||||
|
||||
# Initialize addressbook
|
||||
QtCore.QObject.connect(self.ui.tableWidgetAddressBook, QtCore.SIGNAL(
|
||||
"itemChanged(QTableWidgetItem *)"), self.tableWidgetAddressBookItemChanged)
|
||||
self.ui.tableWidgetAddressBook.itemChanged.connect(
|
||||
self.tableWidgetAddressBookItemChanged)
|
||||
|
||||
# This is necessary for the completer to work if multiple recipients
|
||||
QtCore.QObject.connect(self.ui.lineEditTo, QtCore.SIGNAL(
|
||||
"cursorPositionChanged(int, int)"), self.ui.lineEditTo.completer().onCursorPositionChanged)
|
||||
self.ui.lineEditTo.cursorPositionChanged.connect(
|
||||
self.ui.lineEditTo.completer().onCursorPositionChanged)
|
||||
|
||||
# show messages from message list
|
||||
QtCore.QObject.connect(self.ui.tableWidgetInbox, QtCore.SIGNAL(
|
||||
"itemSelectionChanged ()"), self.tableWidgetInboxItemClicked)
|
||||
QtCore.QObject.connect(self.ui.tableWidgetInboxSubscriptions, QtCore.SIGNAL(
|
||||
"itemSelectionChanged ()"), self.tableWidgetInboxItemClicked)
|
||||
QtCore.QObject.connect(self.ui.tableWidgetInboxChans, QtCore.SIGNAL(
|
||||
"itemSelectionChanged ()"), self.tableWidgetInboxItemClicked)
|
||||
for table_widget in (
|
||||
self.ui.tableWidgetInbox,
|
||||
self.ui.tableWidgetInboxSubscriptions,
|
||||
self.ui.tableWidgetInboxChans
|
||||
):
|
||||
table_widget.itemSelectionChanged.connect(
|
||||
self.tableWidgetInboxItemClicked)
|
||||
|
||||
# tree address lists
|
||||
QtCore.QObject.connect(self.ui.treeWidgetYourIdentities, QtCore.SIGNAL(
|
||||
"itemSelectionChanged ()"), self.treeWidgetItemClicked)
|
||||
QtCore.QObject.connect(self.ui.treeWidgetYourIdentities, QtCore.SIGNAL(
|
||||
"itemChanged (QTreeWidgetItem *, int)"), self.treeWidgetItemChanged)
|
||||
QtCore.QObject.connect(self.ui.treeWidgetSubscriptions, QtCore.SIGNAL(
|
||||
"itemSelectionChanged ()"), self.treeWidgetItemClicked)
|
||||
QtCore.QObject.connect(self.ui.treeWidgetSubscriptions, QtCore.SIGNAL(
|
||||
"itemChanged (QTreeWidgetItem *, int)"), self.treeWidgetItemChanged)
|
||||
QtCore.QObject.connect(self.ui.treeWidgetChans, QtCore.SIGNAL(
|
||||
"itemSelectionChanged ()"), self.treeWidgetItemClicked)
|
||||
QtCore.QObject.connect(self.ui.treeWidgetChans, QtCore.SIGNAL(
|
||||
"itemChanged (QTreeWidgetItem *, int)"), self.treeWidgetItemChanged)
|
||||
QtCore.QObject.connect(
|
||||
self.ui.tabWidget, QtCore.SIGNAL("currentChanged(int)"),
|
||||
self.tabWidgetCurrentChanged
|
||||
)
|
||||
for tree_widget in (
|
||||
self.ui.treeWidgetYourIdentities,
|
||||
self.ui.treeWidgetSubscriptions,
|
||||
self.ui.treeWidgetChans
|
||||
):
|
||||
tree_widget.itemSelectionChanged.connect(
|
||||
self.treeWidgetItemClicked)
|
||||
tree_widget.itemChanged.connect(self.treeWidgetItemChanged)
|
||||
|
||||
self.ui.tabWidget.currentChanged.connect(self.tabWidgetCurrentChanged)
|
||||
|
||||
# Put the colored icon on the status bar
|
||||
# self.pushButtonStatusIcon.setIcon(QIcon(":/newPrefix/images/yellowicon.png"))
|
||||
self.setStatusBar(BMStatusBar())
|
||||
self.statusbar = self.statusBar()
|
||||
|
||||
self.pushButtonStatusIcon = QtGui.QPushButton(self)
|
||||
self.pushButtonStatusIcon = QtWidgets.QPushButton(self)
|
||||
self.pushButtonStatusIcon.setText('')
|
||||
self.pushButtonStatusIcon.setIcon(
|
||||
QtGui.QIcon(':/newPrefix/images/redicon.png'))
|
||||
self.pushButtonStatusIcon.setFlat(True)
|
||||
self.statusbar.insertPermanentWidget(0, self.pushButtonStatusIcon)
|
||||
QtCore.QObject.connect(self.pushButtonStatusIcon, QtCore.SIGNAL(
|
||||
"clicked()"), self.click_pushButtonStatusIcon)
|
||||
self.pushButtonStatusIcon.clicked.connect(
|
||||
self.click_pushButtonStatusIcon)
|
||||
|
||||
self.unreadCount = 0
|
||||
|
||||
# Set the icon sizes for the identicons
|
||||
identicon_size = 3 * 7
|
||||
self.ui.tableWidgetInbox.setIconSize(QtCore.QSize(identicon_size, identicon_size))
|
||||
self.ui.treeWidgetChans.setIconSize(QtCore.QSize(identicon_size, identicon_size))
|
||||
self.ui.treeWidgetYourIdentities.setIconSize(QtCore.QSize(identicon_size, identicon_size))
|
||||
self.ui.treeWidgetSubscriptions.setIconSize(QtCore.QSize(identicon_size, identicon_size))
|
||||
self.ui.tableWidgetAddressBook.setIconSize(QtCore.QSize(identicon_size, identicon_size))
|
||||
for widget in (
|
||||
self.ui.tableWidgetInbox, self.ui.treeWidgetChans,
|
||||
self.ui.treeWidgetYourIdentities, self.ui.treeWidgetSubscriptions,
|
||||
self.ui.tableWidgetAddressBook
|
||||
):
|
||||
widget.setIconSize(QtCore.QSize(identicon_size, identicon_size))
|
||||
|
||||
self.UISignalThread = UISignaler.get()
|
||||
|
||||
QtCore.QObject.connect(self.UISignalThread, QtCore.SIGNAL(
|
||||
"writeNewAddressToTable(PyQt_PyObject,PyQt_PyObject,PyQt_PyObject)"), self.writeNewAddressToTable)
|
||||
QtCore.QObject.connect(self.UISignalThread, QtCore.SIGNAL(
|
||||
"updateStatusBar(PyQt_PyObject)"), self.updateStatusBar)
|
||||
QtCore.QObject.connect(self.UISignalThread, QtCore.SIGNAL(
|
||||
"updateSentItemStatusByToAddress(PyQt_PyObject,PyQt_PyObject)"), self.updateSentItemStatusByToAddress)
|
||||
QtCore.QObject.connect(self.UISignalThread, QtCore.SIGNAL(
|
||||
"updateSentItemStatusByAckdata(PyQt_PyObject,PyQt_PyObject)"), self.updateSentItemStatusByAckdata)
|
||||
QtCore.QObject.connect(self.UISignalThread, QtCore.SIGNAL(
|
||||
"displayNewInboxMessage(PyQt_PyObject,PyQt_PyObject,PyQt_PyObject,PyQt_PyObject,PyQt_PyObject)"),
|
||||
self.UISignalThread.writeNewAddressToTable.connect(
|
||||
self.writeNewAddressToTable)
|
||||
self.UISignalThread.updateStatusBar.connect(self.updateStatusBar)
|
||||
self.UISignalThread.updateSentItemStatusByToAddress.connect(
|
||||
self.updateSentItemStatusByToAddress)
|
||||
self.UISignalThread.updateSentItemStatusByAckdata.connect(
|
||||
self.updateSentItemStatusByAckdata)
|
||||
self.UISignalThread.displayNewInboxMessage.connect(
|
||||
self.displayNewInboxMessage)
|
||||
QtCore.QObject.connect(self.UISignalThread, QtCore.SIGNAL(
|
||||
"displayNewSentMessage(PyQt_PyObject,PyQt_PyObject,PyQt_PyObject,PyQt_PyObject,"
|
||||
"PyQt_PyObject,PyQt_PyObject)"),
|
||||
self.UISignalThread.displayNewSentMessage.connect(
|
||||
self.displayNewSentMessage)
|
||||
QtCore.QObject.connect(self.UISignalThread, QtCore.SIGNAL(
|
||||
"setStatusIcon(PyQt_PyObject)"), self.setStatusIcon)
|
||||
QtCore.QObject.connect(self.UISignalThread, QtCore.SIGNAL(
|
||||
"changedInboxUnread(PyQt_PyObject)"), self.changedInboxUnread)
|
||||
QtCore.QObject.connect(self.UISignalThread, QtCore.SIGNAL(
|
||||
"rerenderMessagelistFromLabels()"), self.rerenderMessagelistFromLabels)
|
||||
QtCore.QObject.connect(self.UISignalThread, QtCore.SIGNAL(
|
||||
"rerenderMessgelistToLabels()"), self.rerenderMessagelistToLabels)
|
||||
QtCore.QObject.connect(self.UISignalThread, QtCore.SIGNAL(
|
||||
"rerenderAddressBook()"), self.rerenderAddressBook)
|
||||
QtCore.QObject.connect(self.UISignalThread, QtCore.SIGNAL(
|
||||
"rerenderSubscriptions()"), self.rerenderSubscriptions)
|
||||
QtCore.QObject.connect(self.UISignalThread, QtCore.SIGNAL(
|
||||
"removeInboxRowByMsgid(PyQt_PyObject)"), self.removeInboxRowByMsgid)
|
||||
QtCore.QObject.connect(self.UISignalThread, QtCore.SIGNAL(
|
||||
"newVersionAvailable(PyQt_PyObject)"), self.newVersionAvailable)
|
||||
QtCore.QObject.connect(self.UISignalThread, QtCore.SIGNAL(
|
||||
"displayAlert(PyQt_PyObject,PyQt_PyObject,PyQt_PyObject)"), self.displayAlert)
|
||||
self.UISignalThread.setStatusIcon.connect(self.setStatusIcon)
|
||||
self.UISignalThread.changedInboxUnread.connect(self.changedInboxUnread)
|
||||
self.UISignalThread.rerenderMessagelistFromLabels.connect(
|
||||
self.rerenderMessagelistFromLabels)
|
||||
self.UISignalThread.rerenderMessagelistToLabels.connect(
|
||||
self.rerenderMessagelistToLabels)
|
||||
self.UISignalThread.rerenderAddressBook.connect(
|
||||
self.rerenderAddressBook)
|
||||
self.UISignalThread.rerenderSubscriptions.connect(
|
||||
self.rerenderSubscriptions)
|
||||
self.UISignalThread.removeInboxRowByMsgid.connect(
|
||||
self.removeInboxRowByMsgid)
|
||||
self.UISignalThread.newVersionAvailable.connect(
|
||||
self.newVersionAvailable)
|
||||
self.UISignalThread.displayAlert.connect(self.displayAlert)
|
||||
self.UISignalThread.start()
|
||||
|
||||
# Key press in tree view
|
||||
|
@ -833,14 +814,13 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
TTL = config.getint('bitmessagesettings', 'ttl')
|
||||
if TTL < 3600: # an hour
|
||||
TTL = 3600
|
||||
elif TTL > 28*24*60*60: # 28 days
|
||||
TTL = 28*24*60*60
|
||||
self.ui.horizontalSliderTTL.setSliderPosition((TTL - 3600) ** (1/3.199))
|
||||
elif TTL > 28 * 24 * 60 * 60: # 28 days
|
||||
TTL = 28 * 24 * 60 * 60
|
||||
self.ui.horizontalSliderTTL.setSliderPosition(
|
||||
int((TTL - 3600) ** (1 / 3.199)))
|
||||
self.updateHumanFriendlyTTLDescription(TTL)
|
||||
|
||||
QtCore.QObject.connect(self.ui.horizontalSliderTTL, QtCore.SIGNAL(
|
||||
"valueChanged(int)"), self.updateTTL)
|
||||
|
||||
self.ui.horizontalSliderTTL.valueChanged.connect(self.updateTTL)
|
||||
self.initSettings()
|
||||
self.resetNamecoinConnection()
|
||||
self.sqlInit()
|
||||
|
@ -895,27 +875,25 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
config.save()
|
||||
|
||||
def updateHumanFriendlyTTLDescription(self, TTL):
|
||||
numberOfHours = int(round(TTL / (60*60)))
|
||||
numberOfHours = int(round(TTL / (60 * 60)))
|
||||
font = QtGui.QFont()
|
||||
stylesheet = ""
|
||||
|
||||
if numberOfHours < 48:
|
||||
self.ui.labelHumanFriendlyTTLDescription.setText(
|
||||
_translate("MainWindow", "%n hour(s)", None, QtCore.QCoreApplication.CodecForTr, numberOfHours) +
|
||||
", " +
|
||||
_translate("MainWindow", "not recommended for chans", None, QtCore.QCoreApplication.CodecForTr)
|
||||
_translate(
|
||||
"MainWindow", "%n hour(s)", None, numberOfHours
|
||||
) + ",\n" +
|
||||
_translate("MainWindow", "not recommended for chans")
|
||||
)
|
||||
stylesheet = "QLabel { color : red; }"
|
||||
font.setBold(True)
|
||||
else:
|
||||
numberOfDays = int(round(TTL / (24*60*60)))
|
||||
numberOfDays = int(round(TTL / (24 * 60 * 60)))
|
||||
self.ui.labelHumanFriendlyTTLDescription.setText(
|
||||
_translate(
|
||||
"MainWindow",
|
||||
"%n day(s)",
|
||||
None,
|
||||
QtCore.QCoreApplication.CodecForTr,
|
||||
numberOfDays))
|
||||
"MainWindow", "%n day(s)", None, numberOfDays)
|
||||
)
|
||||
font.setBold(False)
|
||||
self.ui.labelHumanFriendlyTTLDescription.setStyleSheet(stylesheet)
|
||||
self.ui.labelHumanFriendlyTTLDescription.setFont(font)
|
||||
|
@ -1026,7 +1004,7 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
# related = related.findItems(msgid, QtCore.Qt.MatchExactly),
|
||||
# returns an empty list
|
||||
for rrow in range(related.rowCount()):
|
||||
if related.item(rrow, 3).data() == msgid:
|
||||
if as_msgid(related.item(rrow, 3).data()) == msgid:
|
||||
break
|
||||
|
||||
for col in range(widget.columnCount()):
|
||||
|
@ -1047,6 +1025,8 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
normalUnread = {}
|
||||
broadcastsUnread = {}
|
||||
for addr, fld, count in queryReturn:
|
||||
addr = addr.decode("utf-8", "replace")
|
||||
fld = fld.decode("utf-8", "replace")
|
||||
try:
|
||||
normalUnread[addr][fld] = count
|
||||
except KeyError:
|
||||
|
@ -1066,8 +1046,10 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
queryReturn = sqlQuery(
|
||||
'SELECT fromaddress, folder, COUNT(msgid) AS cnt'
|
||||
' 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:
|
||||
addr = addr.decode("utf-8", "replace")
|
||||
fld = fld.decode("utf-8", "replace")
|
||||
try:
|
||||
broadcastsUnread[addr][fld] = count
|
||||
except KeyError:
|
||||
|
@ -1078,15 +1060,15 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
for i in range(root.childCount()):
|
||||
addressItem = root.child(i)
|
||||
if addressItem.type == AccountMixin.ALL:
|
||||
newCount = sum(totalUnread.itervalues())
|
||||
newCount = sum(six.itervalues(totalUnread))
|
||||
self.drawTrayIcon(self.currentTrayIconFileName, newCount)
|
||||
else:
|
||||
try:
|
||||
newCount = sum((
|
||||
newCount = sum(six.itervalues((
|
||||
broadcastsUnread
|
||||
if addressItem.type == AccountMixin.SUBSCRIPTION
|
||||
else normalUnread
|
||||
)[addressItem.address].itervalues())
|
||||
)[addressItem.address]))
|
||||
except KeyError:
|
||||
newCount = 0
|
||||
if newCount != addressItem.unreadCount:
|
||||
|
@ -1143,20 +1125,19 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
elif status == 'msgsent':
|
||||
statusText = _translate(
|
||||
"MainWindow",
|
||||
"Message sent. Waiting for acknowledgement. Sent at %1"
|
||||
).arg(l10n.formatTimestamp(lastactiontime))
|
||||
"Message sent. Waiting for acknowledgement. Sent at {0}"
|
||||
).format(l10n.formatTimestamp(lastactiontime))
|
||||
elif status == 'msgsentnoackexpected':
|
||||
statusText = _translate(
|
||||
"MainWindow", "Message sent. Sent at %1"
|
||||
).arg(l10n.formatTimestamp(lastactiontime))
|
||||
"MainWindow", "Message sent. Sent at {0}"
|
||||
).format(l10n.formatTimestamp(lastactiontime))
|
||||
elif status == 'doingmsgpow':
|
||||
statusText = _translate(
|
||||
"MainWindow", "Doing work necessary to send message.")
|
||||
elif status == 'ackreceived':
|
||||
statusText = _translate(
|
||||
"MainWindow",
|
||||
"Acknowledgement of the message received %1"
|
||||
).arg(l10n.formatTimestamp(lastactiontime))
|
||||
"MainWindow", "Acknowledgement of the message received {0}"
|
||||
).format(l10n.formatTimestamp(lastactiontime))
|
||||
elif status == 'broadcastqueued':
|
||||
statusText = _translate(
|
||||
"MainWindow", "Broadcast queued.")
|
||||
|
@ -1164,36 +1145,36 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
statusText = _translate(
|
||||
"MainWindow", "Doing work necessary to send broadcast.")
|
||||
elif status == 'broadcastsent':
|
||||
statusText = _translate("MainWindow", "Broadcast on %1").arg(
|
||||
statusText = _translate("MainWindow", "Broadcast on {0}").format(
|
||||
l10n.formatTimestamp(lastactiontime))
|
||||
elif status == 'toodifficult':
|
||||
statusText = _translate(
|
||||
"MainWindow",
|
||||
"Problem: The work demanded by the recipient is more"
|
||||
" difficult than you are willing to do. %1"
|
||||
).arg(l10n.formatTimestamp(lastactiontime))
|
||||
" difficult than you are willing to do. {0}"
|
||||
).format(l10n.formatTimestamp(lastactiontime))
|
||||
elif status == 'badkey':
|
||||
statusText = _translate(
|
||||
"MainWindow",
|
||||
"Problem: The recipient\'s encryption key is no good."
|
||||
" Could not encrypt message. %1"
|
||||
).arg(l10n.formatTimestamp(lastactiontime))
|
||||
" Could not encrypt message. {0}"
|
||||
).format(l10n.formatTimestamp(lastactiontime))
|
||||
elif status == 'forcepow':
|
||||
statusText = _translate(
|
||||
"MainWindow",
|
||||
"Forced difficulty override. Send should start soon.")
|
||||
else:
|
||||
statusText = _translate(
|
||||
"MainWindow", "Unknown status: %1 %2").arg(status).arg(
|
||||
"MainWindow", "Unknown status: {0} {1}").format(status,
|
||||
l10n.formatTimestamp(lastactiontime))
|
||||
|
||||
items = [
|
||||
MessageList_AddressWidget(
|
||||
toAddress, unicode(acct.toLabel, 'utf-8')),
|
||||
toAddress, unic(ustr(acct.toLabel))),
|
||||
MessageList_AddressWidget(
|
||||
fromAddress, unicode(acct.fromLabel, 'utf-8')),
|
||||
fromAddress, unic(ustr(acct.fromLabel))),
|
||||
MessageList_SubjectWidget(
|
||||
str(subject), unicode(acct.subject, 'utf-8', 'replace')),
|
||||
ustr(subject), unic(ustr(acct.subject))),
|
||||
MessageList_TimeWidget(
|
||||
statusText, False, lastactiontime, ackdata)]
|
||||
self.addMessageListItem(tableWidget, items)
|
||||
|
@ -1214,11 +1195,11 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
|
||||
items = [
|
||||
MessageList_AddressWidget(
|
||||
toAddress, unicode(acct.toLabel, 'utf-8'), not read),
|
||||
toAddress, unic(ustr(acct.toLabel)), not read),
|
||||
MessageList_AddressWidget(
|
||||
fromAddress, unicode(acct.fromLabel, 'utf-8'), not read),
|
||||
fromAddress, unic(ustr(acct.fromLabel)), not read),
|
||||
MessageList_SubjectWidget(
|
||||
str(subject), unicode(acct.subject, 'utf-8', 'replace'),
|
||||
ustr(subject), unic(ustr(acct.subject)),
|
||||
not read),
|
||||
MessageList_TimeWidget(
|
||||
l10n.formatTimestamp(received), not read, received, msgid)
|
||||
|
@ -1246,7 +1227,14 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
xAddress, account, "sent", where, what, False)
|
||||
|
||||
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(
|
||||
3, QtCore.Qt.DescendingOrder)
|
||||
|
@ -1287,6 +1275,10 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
|
||||
for row in queryreturn:
|
||||
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(
|
||||
tableWidget, toAddress, fromAddress, subject,
|
||||
msgid, received, read)
|
||||
|
@ -1302,23 +1294,21 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
# create application indicator
|
||||
def appIndicatorInit(self, app):
|
||||
self.initTrayIcon("can-icon-24px-red.png", app)
|
||||
traySignal = "activated(QSystemTrayIcon::ActivationReason)"
|
||||
QtCore.QObject.connect(self.tray, QtCore.SIGNAL(
|
||||
traySignal), self.__icon_activated)
|
||||
self.tray.activated.connect(self.__icon_activated)
|
||||
|
||||
m = QtGui.QMenu()
|
||||
m = QtWidgets.QMenu()
|
||||
|
||||
self.actionStatus = QtGui.QAction(_translate(
|
||||
self.actionStatus = QtWidgets.QAction(_translate(
|
||||
"MainWindow", "Not Connected"), m, checkable=False)
|
||||
m.addAction(self.actionStatus)
|
||||
|
||||
# separator
|
||||
actionSeparator = QtGui.QAction('', m, checkable=False)
|
||||
actionSeparator = QtWidgets.QAction('', m, checkable=False)
|
||||
actionSeparator.setSeparator(True)
|
||||
m.addAction(actionSeparator)
|
||||
|
||||
# show bitmessage
|
||||
self.actionShow = QtGui.QAction(_translate(
|
||||
self.actionShow = QtWidgets.QAction(_translate(
|
||||
"MainWindow", "Show Bitmessage"), m, checkable=True)
|
||||
self.actionShow.setChecked(not config.getboolean(
|
||||
'bitmessagesettings', 'startintray'))
|
||||
|
@ -1327,7 +1317,7 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
m.addAction(self.actionShow)
|
||||
|
||||
# quiet mode
|
||||
self.actionQuiet = QtGui.QAction(_translate(
|
||||
self.actionQuiet = QtWidgets.QAction(_translate(
|
||||
"MainWindow", "Quiet Mode"), m, checkable=True)
|
||||
self.actionQuiet.setChecked(not config.getboolean(
|
||||
'bitmessagesettings', 'showtraynotifications'))
|
||||
|
@ -1335,25 +1325,25 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
m.addAction(self.actionQuiet)
|
||||
|
||||
# Send
|
||||
actionSend = QtGui.QAction(_translate(
|
||||
actionSend = QtWidgets.QAction(_translate(
|
||||
"MainWindow", "Send"), m, checkable=False)
|
||||
actionSend.triggered.connect(self.appIndicatorSend)
|
||||
m.addAction(actionSend)
|
||||
|
||||
# Subscribe
|
||||
actionSubscribe = QtGui.QAction(_translate(
|
||||
actionSubscribe = QtWidgets.QAction(_translate(
|
||||
"MainWindow", "Subscribe"), m, checkable=False)
|
||||
actionSubscribe.triggered.connect(self.appIndicatorSubscribe)
|
||||
m.addAction(actionSubscribe)
|
||||
|
||||
# Channels
|
||||
actionSubscribe = QtGui.QAction(_translate(
|
||||
actionSubscribe = QtWidgets.QAction(_translate(
|
||||
"MainWindow", "Channel"), m, checkable=False)
|
||||
actionSubscribe.triggered.connect(self.appIndicatorChannel)
|
||||
m.addAction(actionSubscribe)
|
||||
|
||||
# separator
|
||||
actionSeparator = QtGui.QAction('', m, checkable=False)
|
||||
actionSeparator = QtWidgets.QAction('', m, checkable=False)
|
||||
actionSeparator.setSeparator(True)
|
||||
m.addAction(actionSeparator)
|
||||
|
||||
|
@ -1372,6 +1362,7 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
SELECT msgid, toaddress, read FROM inbox where folder='inbox'
|
||||
''')
|
||||
for msgid, toAddress, read in queryreturn:
|
||||
toAddress = toAddress.decode("utf-8", "replace")
|
||||
|
||||
if not read:
|
||||
# increment the unread subscriptions if True (1)
|
||||
|
@ -1450,7 +1441,7 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
|
||||
# Adapters and converters for QT <-> sqlite
|
||||
def sqlInit(self):
|
||||
register_adapter(QtCore.QByteArray, str)
|
||||
register_adapter(QtCore.QByteArray, bytes)
|
||||
|
||||
def indicatorInit(self):
|
||||
"""
|
||||
|
@ -1470,11 +1461,10 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
def notifierInit(self):
|
||||
def _simple_notify(
|
||||
title, subtitle, category, label=None, icon=None):
|
||||
self.tray.showMessage(title, subtitle, 1, 2000)
|
||||
self.tray.showMessage(
|
||||
title, subtitle, self.tray.NoIcon, msecs=2000)
|
||||
|
||||
self._notifier = _simple_notify
|
||||
# does nothing if isAvailable returns false
|
||||
self._player = QtGui.QSound.play
|
||||
|
||||
if not get_plugins:
|
||||
return
|
||||
|
@ -1487,7 +1477,10 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
|
||||
self._theme_player = get_plugin('notification.sound', 'theme')
|
||||
|
||||
if not QtGui.QSound.isAvailable():
|
||||
try:
|
||||
from qtpy import QtMultimedia
|
||||
self._player = QtMultimedia.QSound.play
|
||||
except ImportError:
|
||||
_plugin = get_plugin(
|
||||
'notification.sound', 'file', fallback='file.fallback')
|
||||
if _plugin:
|
||||
|
@ -1499,7 +1492,7 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
self, title, subtitle, category, label=None, icon=None):
|
||||
self.playSound(category, label)
|
||||
self._notifier(
|
||||
unicode(title), unicode(subtitle), category, label, icon)
|
||||
unic(ustr(title)), unic(ustr(subtitle)), category, label, icon)
|
||||
|
||||
# tree
|
||||
def treeWidgetKeyPressEvent(self, event):
|
||||
|
@ -1511,7 +1504,7 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
if event.key() == QtCore.Qt.Key_Delete:
|
||||
self.on_action_AddressBookDelete()
|
||||
else:
|
||||
return QtGui.QTableWidget.keyPressEvent(
|
||||
return QtWidgets.QTableWidget.keyPressEvent(
|
||||
self.ui.tableWidgetAddressBook, event)
|
||||
|
||||
# inbox / sent
|
||||
|
@ -1526,14 +1519,14 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
"""This method handles keypress events for all widgets on MyForm"""
|
||||
messagelist = self.getCurrentMessagelist()
|
||||
if event.key() == QtCore.Qt.Key_Delete:
|
||||
if isinstance(focus, (MessageView, QtGui.QTableWidget)):
|
||||
if isinstance(focus, (MessageView, QtWidgets.QTableWidget)):
|
||||
folder = self.getCurrentFolder()
|
||||
if folder == "sent":
|
||||
self.on_action_SentTrash()
|
||||
else:
|
||||
self.on_action_InboxTrash()
|
||||
event.ignore()
|
||||
elif QtGui.QApplication.queryKeyboardModifiers() == QtCore.Qt.NoModifier:
|
||||
elif QtWidgets.QApplication.queryKeyboardModifiers() == QtCore.Qt.NoModifier:
|
||||
if event.key() == QtCore.Qt.Key_N:
|
||||
currentRow = messagelist.currentRow()
|
||||
if currentRow < messagelist.rowCount() - 1:
|
||||
|
@ -1572,74 +1565,77 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
return
|
||||
if isinstance(focus, MessageView):
|
||||
return MessageView.keyPressEvent(focus, event)
|
||||
if isinstance(focus, QtGui.QTableWidget):
|
||||
return QtGui.QTableWidget.keyPressEvent(focus, event)
|
||||
if isinstance(focus, QtGui.QTreeWidget):
|
||||
return QtGui.QTreeWidget.keyPressEvent(focus, event)
|
||||
elif isinstance(focus, QtWidgets.QTableWidget):
|
||||
return QtWidgets.QTableWidget.keyPressEvent(focus, event)
|
||||
elif isinstance(focus, QtWidgets.QTreeWidget):
|
||||
return QtWidgets.QTreeWidget.keyPressEvent(focus, event)
|
||||
|
||||
# menu button 'manage keys'
|
||||
def click_actionManageKeys(self):
|
||||
if 'darwin' in sys.platform or 'linux' in sys.platform:
|
||||
if state.appdata == '':
|
||||
# reply = QtGui.QMessageBox.information(self, 'keys.dat?','You
|
||||
# reply = QtWidgets.QMessageBox.information(self, 'keys.dat?','You
|
||||
# may manage your keys by editing the keys.dat file stored in
|
||||
# the same directory as this program. It is important that you
|
||||
# back up this file.', QMessageBox.Ok)
|
||||
reply = QtGui.QMessageBox.information(
|
||||
self,
|
||||
'keys.dat?',
|
||||
_translate(
|
||||
reply = QtWidgets.QMessageBox.information(
|
||||
self, 'keys.dat?', _translate(
|
||||
"MainWindow",
|
||||
"You may manage your keys by editing the keys.dat file stored in the same directory"
|
||||
"as this program. It is important that you back up this file."
|
||||
),
|
||||
QtGui.QMessageBox.Ok)
|
||||
"You may manage your keys by editing the keys.dat"
|
||||
" file stored in the same directory as this"
|
||||
" program. It is important that you back up this"
|
||||
" file."), QtWidgets.QMessageBox.Ok)
|
||||
|
||||
else:
|
||||
QtGui.QMessageBox.information(
|
||||
self,
|
||||
'keys.dat?',
|
||||
QtWidgets.QMessageBox.information(
|
||||
self, 'keys.dat?',
|
||||
_translate(
|
||||
"MainWindow",
|
||||
"You may manage your keys by editing the keys.dat file stored in"
|
||||
"\n %1 \n"
|
||||
"It is important that you back up this file."
|
||||
).arg(state.appdata),
|
||||
QtGui.QMessageBox.Ok)
|
||||
"You may manage your keys by editing the keys.dat"
|
||||
" file stored in\n {0} \nIt is important that you"
|
||||
" back up this file."
|
||||
).format(state.appdata),
|
||||
QtWidgets.QMessageBox.Ok
|
||||
)
|
||||
elif sys.platform == 'win32' or sys.platform == 'win64':
|
||||
if state.appdata == '':
|
||||
reply = QtGui.QMessageBox.question(
|
||||
self,
|
||||
_translate("MainWindow", "Open keys.dat?"),
|
||||
reply = QtWidgets.QMessageBox.question(
|
||||
self, _translate("MainWindow", "Open keys.dat?"),
|
||||
_translate(
|
||||
"MainWindow",
|
||||
"You may manage your keys by editing the keys.dat file stored in the same directory as "
|
||||
"this program. 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.)"),
|
||||
QtGui.QMessageBox.Yes,
|
||||
QtGui.QMessageBox.No)
|
||||
"You may manage your keys by editing the keys.dat"
|
||||
" file stored in the same directory as this"
|
||||
" program. 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.)"
|
||||
), QtWidgets.QMessageBox.Yes, QtWidgets.QMessageBox.No)
|
||||
else:
|
||||
reply = QtGui.QMessageBox.question(
|
||||
reply = QtWidgets.QMessageBox.question(
|
||||
self,
|
||||
_translate("MainWindow", "Open keys.dat?"),
|
||||
_translate(
|
||||
"MainWindow",
|
||||
"You may manage your keys by editing the keys.dat file stored in\n %1 \n"
|
||||
"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),
|
||||
QtGui.QMessageBox.Yes, QtGui.QMessageBox.No)
|
||||
if reply == QtGui.QMessageBox.Yes:
|
||||
"You may manage your keys by editing the keys.dat"
|
||||
" file stored in\n {0} \nIt 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.)"
|
||||
).format(state.appdata),
|
||||
QtWidgets.QMessageBox.Yes, QtWidgets.QMessageBox.No
|
||||
)
|
||||
if reply == QtWidgets.QMessageBox.Yes:
|
||||
openKeysFile()
|
||||
|
||||
# menu button 'delete all treshed messages'
|
||||
def click_actionDeleteAllTrashedMessages(self):
|
||||
if QtGui.QMessageBox.question(
|
||||
self,
|
||||
_translate("MainWindow", "Delete trash?"),
|
||||
_translate("MainWindow", "Are you sure you want to delete all trashed messages?"),
|
||||
QtGui.QMessageBox.Yes,
|
||||
QtGui.QMessageBox.No) == QtGui.QMessageBox.No:
|
||||
if QtWidgets.QMessageBox.question(
|
||||
self, _translate("MainWindow", "Delete trash?"),
|
||||
_translate(
|
||||
"MainWindow",
|
||||
"Are you sure you want to delete all trashed messages?"
|
||||
), QtWidgets.QMessageBox.Yes, QtWidgets.QMessageBox.No
|
||||
) == QtWidgets.QMessageBox.No:
|
||||
return
|
||||
sqlStoredProcedure('deleteandvacuume')
|
||||
self.rerenderTabTreeMessages()
|
||||
|
@ -1666,7 +1662,7 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
dialog = dialogs.RegenerateAddressesDialog(self)
|
||||
if dialog.exec_():
|
||||
if dialog.lineEditPassphrase.text() == "":
|
||||
QtGui.QMessageBox.about(
|
||||
QtWidgets.QMessageBox.about(
|
||||
self, _translate("MainWindow", "bad passphrase"),
|
||||
_translate(
|
||||
"MainWindow",
|
||||
|
@ -1679,7 +1675,7 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
addressVersionNumber = int(
|
||||
dialog.lineEditAddressVersionNumber.text())
|
||||
except:
|
||||
QtGui.QMessageBox.about(
|
||||
QtWidgets.QMessageBox.about(
|
||||
self,
|
||||
_translate("MainWindow", "Bad address version number"),
|
||||
_translate(
|
||||
|
@ -1689,7 +1685,7 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
))
|
||||
return
|
||||
if addressVersionNumber < 3 or addressVersionNumber > 4:
|
||||
QtGui.QMessageBox.about(
|
||||
QtWidgets.QMessageBox.about(
|
||||
self,
|
||||
_translate("MainWindow", "Bad address version number"),
|
||||
_translate(
|
||||
|
@ -1702,7 +1698,7 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
addressVersionNumber, streamNumberForAddress,
|
||||
"regenerated deterministic address",
|
||||
dialog.spinBoxNumberOfAddressesToMake.value(),
|
||||
dialog.lineEditPassphrase.text().toUtf8(),
|
||||
ustr(dialog.lineEditPassphrase.text()).encode("utf-8", "replace"),
|
||||
dialog.checkBoxEighteenByteRipe.isChecked()
|
||||
))
|
||||
self.ui.tabWidget.setCurrentIndex(
|
||||
|
@ -1753,7 +1749,7 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
pass
|
||||
|
||||
def __icon_activated(self, reason):
|
||||
if reason == QtGui.QSystemTrayIcon.Trigger:
|
||||
if reason == QtWidgets.QSystemTrayIcon.Trigger:
|
||||
self.actionShow.setChecked(not self.actionShow.isChecked())
|
||||
self.appIndicatorShowOrHideWindow()
|
||||
|
||||
|
@ -1823,7 +1819,7 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
|
||||
def initTrayIcon(self, iconFileName, app):
|
||||
self.currentTrayIconFileName = iconFileName
|
||||
self.tray = QtGui.QSystemTrayIcon(
|
||||
self.tray = QtWidgets.QSystemTrayIcon(
|
||||
self.calcTrayIcon(iconFileName, self.findInboxUnreadCount()), app)
|
||||
|
||||
def setTrayIconFile(self, iconFileName):
|
||||
|
@ -1855,8 +1851,8 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
# draw text
|
||||
painter = QtGui.QPainter()
|
||||
painter.begin(pixmap)
|
||||
painter.setPen(
|
||||
QtGui.QPen(QtGui.QColor(255, 0, 0), QtCore.Qt.SolidPattern))
|
||||
painter.setPen(QtGui.QPen(QtGui.QColor(255, 0, 0)))
|
||||
painter.setBrush(QtCore.Qt.SolidPattern)
|
||||
painter.setFont(font)
|
||||
painter.drawText(24-rect.right()-marginX, -rect.top()+marginY, txt)
|
||||
painter.end()
|
||||
|
@ -1903,10 +1899,11 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
if toAddress == rowAddress:
|
||||
sent.item(i, 3).setToolTip(textToDisplay)
|
||||
try:
|
||||
newlinePosition = textToDisplay.indexOf('\n')
|
||||
except:
|
||||
# If someone misses adding a "_translate" to a string before passing it to this function,
|
||||
# this function won't receive a qstring which will cause an exception.
|
||||
newlinePosition = textToDisplay.find('\n')
|
||||
# If someone misses adding a "_translate" to a string
|
||||
# before passing it to this function
|
||||
# ? why textToDisplay isn't unicode
|
||||
except AttributeError:
|
||||
newlinePosition = 0
|
||||
if newlinePosition > 1:
|
||||
sent.item(i, 3).setText(
|
||||
|
@ -1915,8 +1912,6 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
sent.item(i, 3).setText(textToDisplay)
|
||||
|
||||
def updateSentItemStatusByAckdata(self, ackdata, textToDisplay):
|
||||
if type(ackdata) is str:
|
||||
ackdata = QtCore.QByteArray(ackdata)
|
||||
for sent in (
|
||||
self.ui.tableWidgetInbox,
|
||||
self.ui.tableWidgetInboxSubscriptions,
|
||||
|
@ -1926,22 +1921,22 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
if self.getCurrentFolder(treeWidget) != "sent":
|
||||
continue
|
||||
for i in range(sent.rowCount()):
|
||||
toAddress = sent.item(i, 0).data(QtCore.Qt.UserRole)
|
||||
tableAckdata = sent.item(i, 3).data()
|
||||
status, addressVersionNumber, streamNumber, ripe = decodeAddress(
|
||||
toAddress)
|
||||
# toAddress = sent.item(i, 0).data(QtCore.Qt.UserRole)
|
||||
tableAckdata = as_msgid(sent.item(i, 3).data())
|
||||
# status, addressVersionNumber, streamNumber, ripe = decodeAddress(
|
||||
# toAddress)
|
||||
if ackdata == tableAckdata:
|
||||
sent.item(i, 3).setToolTip(textToDisplay)
|
||||
try:
|
||||
newlinePosition = textToDisplay.indexOf('\n')
|
||||
except:
|
||||
# If someone misses adding a "_translate" to a string before passing it to this function,
|
||||
# this function won't receive a qstring which will cause an exception.
|
||||
newlinePosition = textToDisplay.find('\n')
|
||||
# If someone misses adding a "_translate" to a string
|
||||
# before passing it to this function
|
||||
# ? why textToDisplay isn't unicode
|
||||
except AttributeError:
|
||||
newlinePosition = 0
|
||||
if newlinePosition > 1:
|
||||
sent.item(i, 3).setText(
|
||||
textToDisplay[:newlinePosition])
|
||||
else:
|
||||
textToDisplay = textToDisplay[:newlinePosition]
|
||||
|
||||
sent.item(i, 3).setText(textToDisplay)
|
||||
|
||||
def removeInboxRowByMsgid(self, msgid):
|
||||
|
@ -1953,7 +1948,7 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
):
|
||||
i = None
|
||||
for i in range(inbox.rowCount()):
|
||||
if msgid == inbox.item(i, 3).data():
|
||||
if msgid == as_msgid(inbox.item(i, 3).data()):
|
||||
break
|
||||
else:
|
||||
continue
|
||||
|
@ -1970,14 +1965,15 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
self.notifiedNewVersion = ".".join(str(n) for n in version)
|
||||
self.updateStatusBar(_translate(
|
||||
"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"
|
||||
).arg(self.notifiedNewVersion)
|
||||
).format(self.notifiedNewVersion)
|
||||
)
|
||||
|
||||
def displayAlert(self, title, text, exitAfterUserClicksOk):
|
||||
self.updateStatusBar(text)
|
||||
QtGui.QMessageBox.critical(self, title, text, QtGui.QMessageBox.Ok)
|
||||
QtWidgets.QMessageBox.critical(
|
||||
self, title, text, QtWidgets.QMessageBox.Ok)
|
||||
if exitAfterUserClicksOk:
|
||||
os._exit(0)
|
||||
|
||||
|
@ -1996,11 +1992,11 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
messagelist.item(i, 0).setLabel()
|
||||
|
||||
def rerenderAddressBook(self):
|
||||
def addRow (address, label, type):
|
||||
def addRow(address, label, type):
|
||||
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)
|
||||
newItem = Ui_AddressBookWidgetItemAddress(address, unicode(label, 'utf-8'), type)
|
||||
newItem = Ui_AddressBookWidgetItemAddress(address, unic(ustr(label)), type)
|
||||
self.ui.tableWidgetAddressBook.setItem(0, 1, newItem)
|
||||
|
||||
oldRows = {}
|
||||
|
@ -2009,7 +2005,8 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
oldRows[item.address] = [item.label, item.type, i]
|
||||
|
||||
if self.ui.tableWidgetAddressBook.rowCount() == 0:
|
||||
self.ui.tableWidgetAddressBook.horizontalHeader().setSortIndicator(0, QtCore.Qt.AscendingOrder)
|
||||
self.ui.tableWidgetAddressBook.horizontalHeader(
|
||||
).setSortIndicator(0, QtCore.Qt.AscendingOrder)
|
||||
if self.ui.tableWidgetAddressBook.isSortingEnabled():
|
||||
self.ui.tableWidgetAddressBook.setSortingEnabled(False)
|
||||
|
||||
|
@ -2018,16 +2015,23 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
queryreturn = sqlQuery('SELECT label, address FROM subscriptions WHERE enabled = 1')
|
||||
for row in queryreturn:
|
||||
label, address = row
|
||||
label = label.decode("utf-8", "replace")
|
||||
address = address.decode("utf-8", "replace")
|
||||
newRows[address] = [label, AccountMixin.SUBSCRIPTION]
|
||||
# chans
|
||||
for address in config.addresses(True):
|
||||
account = accountClass(address)
|
||||
if (account.type == AccountMixin.CHAN and config.safeGetBoolean(address, 'enabled')):
|
||||
if (
|
||||
account.type == AccountMixin.CHAN
|
||||
and config.safeGetBoolean(address, 'enabled')
|
||||
):
|
||||
newRows[address] = [account.getLabel(), AccountMixin.CHAN]
|
||||
# normal accounts
|
||||
queryreturn = sqlQuery('SELECT * FROM addressbook')
|
||||
queryreturn = sqlQuery('SELECT label, address FROM addressbook')
|
||||
for row in queryreturn:
|
||||
label, address = row
|
||||
label = label.decode("utf-8", "replace")
|
||||
address = address.decode("utf-8", "replace")
|
||||
newRows[address] = [label, AccountMixin.NORMAL]
|
||||
|
||||
completerList = []
|
||||
|
@ -2041,7 +2045,7 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
self.ui.tableWidgetAddressBook.removeRow(oldRows[address][2])
|
||||
for address in newRows:
|
||||
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
|
||||
self.ui.tableWidgetAddressBook.sortByColumn(
|
||||
|
@ -2053,16 +2057,17 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
self.rerenderTabTreeSubscriptions()
|
||||
|
||||
def click_pushButtonTTL(self):
|
||||
QtGui.QMessageBox.information(
|
||||
self,
|
||||
'Time To Live',
|
||||
_translate(
|
||||
"MainWindow", """The TTL, or Time-To-Live is the length of time that the network will hold the message.
|
||||
The recipient must get it during this time. If your Bitmessage client does not hear an acknowledgement
|
||||
,it will resend the message automatically. The longer the Time-To-Live, the
|
||||
more work your computer must do to send the message.
|
||||
A Time-To-Live of four or five days is often appropriate."""),
|
||||
QtGui.QMessageBox.Ok)
|
||||
QtWidgets.QMessageBox.information(
|
||||
self, 'Time To Live', _translate(
|
||||
"MainWindow",
|
||||
"The TTL, or Time-To-Live is the length of time that"
|
||||
" the network will hold the message. The recipient must"
|
||||
" get it during this time. If your Bitmessage client does"
|
||||
" not hear an acknowledgement, it will resend the message"
|
||||
" automatically. The longer the Time-To-Live, the more"
|
||||
" work your computer must do to send the message. A"
|
||||
" Time-To-Live of four or five days is often appropriate."
|
||||
), QtWidgets.QMessageBox.Ok)
|
||||
|
||||
def click_pushButtonClear(self):
|
||||
self.ui.lineEditSubject.setText("")
|
||||
|
@ -2071,7 +2076,10 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
self.ui.comboBoxSendFrom.setCurrentIndex(0)
|
||||
|
||||
def click_pushButtonSend(self):
|
||||
encoding = 3 if QtGui.QApplication.queryKeyboardModifiers() & QtCore.Qt.ShiftModifier else 2
|
||||
# pylint: disable=too-many-locals
|
||||
encoding = (
|
||||
3 if QtWidgets.QApplication.queryKeyboardModifiers()
|
||||
& QtCore.Qt.ShiftModifier else 2)
|
||||
|
||||
self.statusbar.clearMessage()
|
||||
|
||||
|
@ -2079,22 +2087,22 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
self.ui.tabWidgetSend.indexOf(self.ui.sendDirect):
|
||||
# message to specific people
|
||||
sendMessageToPeople = True
|
||||
fromAddress = str(self.ui.comboBoxSendFrom.itemData(
|
||||
fromAddress = ustr(self.ui.comboBoxSendFrom.itemData(
|
||||
self.ui.comboBoxSendFrom.currentIndex(),
|
||||
QtCore.Qt.UserRole).toString())
|
||||
toAddresses = str(self.ui.lineEditTo.text().toUtf8())
|
||||
subject = str(self.ui.lineEditSubject.text().toUtf8())
|
||||
message = str(
|
||||
self.ui.textEditMessage.document().toPlainText().toUtf8())
|
||||
QtCore.Qt.UserRole))
|
||||
toAddresses = ustr(self.ui.lineEditTo.text())
|
||||
subject = ustr(self.ui.lineEditSubject.text())
|
||||
message = ustr(
|
||||
self.ui.textEditMessage.document().toPlainText())
|
||||
else:
|
||||
# broadcast message
|
||||
sendMessageToPeople = False
|
||||
fromAddress = str(self.ui.comboBoxSendFromBroadcast.itemData(
|
||||
fromAddress = ustr(self.ui.comboBoxSendFromBroadcast.itemData(
|
||||
self.ui.comboBoxSendFromBroadcast.currentIndex(),
|
||||
QtCore.Qt.UserRole).toString())
|
||||
subject = str(self.ui.lineEditSubjectBroadcast.text().toUtf8())
|
||||
message = str(
|
||||
self.ui.textEditMessageBroadcast.document().toPlainText().toUtf8())
|
||||
QtCore.Qt.UserRole))
|
||||
subject = ustr(self.ui.lineEditSubjectBroadcast.text())
|
||||
message = ustr(
|
||||
self.ui.textEditMessageBroadcast.document().toPlainText())
|
||||
"""
|
||||
The whole network message must fit in 2^18 bytes.
|
||||
Let's assume 500 bytes of overhead. If someone wants to get that
|
||||
|
@ -2103,14 +2111,14 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
users can send messages of any length.
|
||||
"""
|
||||
if len(message) > (2 ** 18 - 500):
|
||||
QtGui.QMessageBox.about(
|
||||
QtWidgets.QMessageBox.about(
|
||||
self, _translate("MainWindow", "Message too long"),
|
||||
_translate(
|
||||
"MainWindow",
|
||||
"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."
|
||||
).arg(len(message) - (2 ** 18 - 500)))
|
||||
).format(len(message) - (2 ** 18 - 500)))
|
||||
return
|
||||
|
||||
acct = accountClass(fromAddress)
|
||||
|
@ -2131,24 +2139,31 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
# email address
|
||||
if toAddress.find("@") >= 0:
|
||||
if isinstance(acct, GatewayAccount):
|
||||
acct.createMessage(toAddress, fromAddress, subject, message)
|
||||
acct.createMessage(
|
||||
toAddress, fromAddress, subject, message)
|
||||
subject = acct.subject
|
||||
toAddress = acct.toAddress
|
||||
else:
|
||||
if QtGui.QMessageBox.question(
|
||||
self,
|
||||
"Sending an email?",
|
||||
if QtWidgets.QMessageBox.question(
|
||||
self, "Sending an email?",
|
||||
_translate(
|
||||
"MainWindow",
|
||||
"You are trying to send an email instead of a bitmessage. "
|
||||
"This requires registering with a gateway. Attempt to register?"),
|
||||
QtGui.QMessageBox.Yes|QtGui.QMessageBox.No) != QtGui.QMessageBox.Yes:
|
||||
"You are trying to send an email"
|
||||
" instead of a bitmessage. This"
|
||||
" requires registering with a"
|
||||
" gateway. Attempt to register?"
|
||||
), QtWidgets.QMessageBox.Yes
|
||||
| QtWidgets.QMessageBox.No
|
||||
) != QtWidgets.QMessageBox.Yes:
|
||||
continue
|
||||
email = acct.getLabel()
|
||||
if email[-14:] != "@mailchuck.com": # attempt register
|
||||
# attempt register
|
||||
if email[-14:] != "@mailchuck.com":
|
||||
# 12 character random email address
|
||||
email = ''.join(
|
||||
random.SystemRandom().choice(string.ascii_lowercase) for _ in range(12)
|
||||
email = u''.join(
|
||||
random.SystemRandom().choice(
|
||||
string.ascii_lowercase
|
||||
) for _ in range(12)
|
||||
) + "@mailchuck.com"
|
||||
acct = MailchuckAccount(fromAddress)
|
||||
acct.register(email)
|
||||
|
@ -2159,15 +2174,15 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
"MainWindow",
|
||||
"Error: Your account wasn't registered at"
|
||||
" 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."
|
||||
).arg(email)
|
||||
)
|
||||
).format(email))
|
||||
return
|
||||
status, addressVersionNumber, streamNumber = decodeAddress(toAddress)[:3]
|
||||
status, addressVersionNumber, streamNumber = \
|
||||
decodeAddress(toAddress)[:3]
|
||||
if status != 'success':
|
||||
try:
|
||||
toAddress = unicode(toAddress, 'utf-8', 'ignore')
|
||||
toAddress = unic(ustr(toAddress))
|
||||
except:
|
||||
pass
|
||||
logger.error('Error: Could not decode recipient address ' + toAddress + ':' + status)
|
||||
|
@ -2176,58 +2191,58 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
self.updateStatusBar(_translate(
|
||||
"MainWindow",
|
||||
"Error: Bitmessage addresses start with"
|
||||
" BM- Please check the recipient address %1"
|
||||
).arg(toAddress))
|
||||
" BM- Please check the recipient address {0}"
|
||||
).format(toAddress))
|
||||
elif status == 'checksumfailed':
|
||||
self.updateStatusBar(_translate(
|
||||
"MainWindow",
|
||||
"Error: The recipient address %1 is not"
|
||||
"Error: The recipient address {0} is not"
|
||||
" typed or copied correctly. Please check it."
|
||||
).arg(toAddress))
|
||||
).format(toAddress))
|
||||
elif status == 'invalidcharacters':
|
||||
self.updateStatusBar(_translate(
|
||||
"MainWindow",
|
||||
"Error: The recipient address %1 contains"
|
||||
"Error: The recipient address {0} contains"
|
||||
" invalid characters. Please check it."
|
||||
).arg(toAddress))
|
||||
).format(toAddress))
|
||||
elif status == 'versiontoohigh':
|
||||
self.updateStatusBar(_translate(
|
||||
"MainWindow",
|
||||
"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"
|
||||
" acquaintance is being clever."
|
||||
).arg(toAddress))
|
||||
).format(toAddress))
|
||||
elif status == 'ripetooshort':
|
||||
self.updateStatusBar(_translate(
|
||||
"MainWindow",
|
||||
"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"
|
||||
" your acquaintance."
|
||||
).arg(toAddress))
|
||||
).format(toAddress))
|
||||
elif status == 'ripetoolong':
|
||||
self.updateStatusBar(_translate(
|
||||
"MainWindow",
|
||||
"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"
|
||||
" your acquaintance."
|
||||
).arg(toAddress))
|
||||
).format(toAddress))
|
||||
elif status == 'varintmalformed':
|
||||
self.updateStatusBar(_translate(
|
||||
"MainWindow",
|
||||
"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"
|
||||
" your acquaintance."
|
||||
).arg(toAddress))
|
||||
).format(toAddress))
|
||||
else:
|
||||
self.updateStatusBar(_translate(
|
||||
"MainWindow",
|
||||
"Error: Something is wrong with the"
|
||||
" recipient address %1."
|
||||
).arg(toAddress))
|
||||
" recipient address {0}."
|
||||
).format(toAddress))
|
||||
elif fromAddress == '':
|
||||
self.updateStatusBar(_translate(
|
||||
"MainWindow",
|
||||
|
@ -2239,24 +2254,31 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
toAddress = addBMIfNotPresent(toAddress)
|
||||
|
||||
if addressVersionNumber > 4 or addressVersionNumber <= 1:
|
||||
QtGui.QMessageBox.about(
|
||||
QtWidgets.QMessageBox.about(
|
||||
self,
|
||||
_translate("MainWindow", "Address version number"),
|
||||
_translate(
|
||||
"MainWindow", "Address version number"),
|
||||
_translate(
|
||||
"MainWindow",
|
||||
"Concerning the address %1, Bitmessage cannot understand address version numbers"
|
||||
" of %2. Perhaps upgrade Bitmessage to the latest version."
|
||||
).arg(toAddress).arg(str(addressVersionNumber)))
|
||||
"Concerning the address {0}, Bitmessage"
|
||||
" cannot understand address version"
|
||||
" numbers of {1}. Perhaps upgrade"
|
||||
" Bitmessage to the latest version."
|
||||
).format(toAddress, addressVersionNumber)
|
||||
)
|
||||
continue
|
||||
if streamNumber > 1 or streamNumber == 0:
|
||||
QtGui.QMessageBox.about(
|
||||
QtWidgets.QMessageBox.about(
|
||||
self,
|
||||
_translate("MainWindow", "Stream number"),
|
||||
_translate(
|
||||
"MainWindow",
|
||||
"Concerning the address %1, Bitmessage cannot handle stream numbers of %2."
|
||||
" Perhaps upgrade Bitmessage to the latest version."
|
||||
).arg(toAddress).arg(str(streamNumber)))
|
||||
"Concerning the address {0}, Bitmessage"
|
||||
" cannot handle stream numbers of {1}."
|
||||
" Perhaps upgrade Bitmessage to the"
|
||||
" latest version."
|
||||
).format(toAddress, streamNumber)
|
||||
)
|
||||
continue
|
||||
self.statusbar.clearMessage()
|
||||
if state.statusIconColor == 'red':
|
||||
|
@ -2272,10 +2294,11 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
subject=subject, message=message, encoding=encoding)
|
||||
toLabel = ''
|
||||
queryreturn = sqlQuery('''select label from addressbook where address=?''',
|
||||
toAddress)
|
||||
dbstr(toAddress))
|
||||
if queryreturn != []:
|
||||
for row in queryreturn:
|
||||
toLabel, = row
|
||||
toLabel = toLabel.decode("utf-8", "replace")
|
||||
|
||||
self.displayNewSentMessage(
|
||||
toAddress, toLabel, fromAddress, subject, message, ackdata)
|
||||
|
@ -2341,11 +2364,11 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
))
|
||||
|
||||
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())
|
||||
if err is not None:
|
||||
self.updateStatusBar(
|
||||
_translate("MainWindow", "Error: %1").arg(err))
|
||||
_translate("MainWindow", "Error: {0}").format(err))
|
||||
else:
|
||||
identities[-1] = addr
|
||||
self.ui.lineEditTo.setText("; ".join(identities))
|
||||
|
@ -2358,7 +2381,7 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
self.ui.tabWidgetSend.setCurrentIndex(
|
||||
self.ui.tabWidgetSend.indexOf(
|
||||
self.ui.sendBroadcast
|
||||
if config.safeGetBoolean(str(address), 'mailinglist')
|
||||
if config.safeGetBoolean(ustr(address), 'mailinglist')
|
||||
else self.ui.sendDirect
|
||||
))
|
||||
|
||||
|
@ -2369,21 +2392,22 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
# It's easier for others to read.
|
||||
isEnabled = config.getboolean(
|
||||
addressInKeysFile, 'enabled')
|
||||
isMaillinglist = config.safeGetBoolean(addressInKeysFile, 'mailinglist')
|
||||
isMaillinglist = config.safeGetBoolean(
|
||||
addressInKeysFile, 'mailinglist')
|
||||
if isEnabled and not isMaillinglist:
|
||||
label = unicode(config.get(addressInKeysFile, 'label'), 'utf-8', 'ignore').strip()
|
||||
label = unic(ustr(config.get(addressInKeysFile, 'label')).strip()) or addressInKeysFile
|
||||
if label == "":
|
||||
label = addressInKeysFile
|
||||
self.ui.comboBoxSendFrom.addItem(avatarize(addressInKeysFile), label, addressInKeysFile)
|
||||
# self.ui.comboBoxSendFrom.model().sort(1, Qt.AscendingOrder)
|
||||
for i in range(self.ui.comboBoxSendFrom.count()):
|
||||
address = str(self.ui.comboBoxSendFrom.itemData(
|
||||
i, QtCore.Qt.UserRole).toString())
|
||||
address = ustr(self.ui.comboBoxSendFrom.itemData(
|
||||
i, QtCore.Qt.UserRole))
|
||||
self.ui.comboBoxSendFrom.setItemData(
|
||||
i, AccountColor(address).accountColor(),
|
||||
QtCore.Qt.ForegroundRole)
|
||||
self.ui.comboBoxSendFrom.insertItem(0, '', '')
|
||||
if(self.ui.comboBoxSendFrom.count() == 2):
|
||||
if self.ui.comboBoxSendFrom.count() == 2:
|
||||
self.ui.comboBoxSendFrom.setCurrentIndex(1)
|
||||
else:
|
||||
self.ui.comboBoxSendFrom.setCurrentIndex(0)
|
||||
|
@ -2395,18 +2419,16 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
addressInKeysFile, 'enabled')
|
||||
isChan = config.safeGetBoolean(addressInKeysFile, 'chan')
|
||||
if isEnabled and not isChan:
|
||||
label = unicode(config.get(addressInKeysFile, 'label'), 'utf-8', 'ignore').strip()
|
||||
if label == "":
|
||||
label = addressInKeysFile
|
||||
label = unic(ustr(config.get(addressInKeysFile, 'label')).strip()) or addressInKeysFile
|
||||
self.ui.comboBoxSendFromBroadcast.addItem(avatarize(addressInKeysFile), label, addressInKeysFile)
|
||||
for i in range(self.ui.comboBoxSendFromBroadcast.count()):
|
||||
address = str(self.ui.comboBoxSendFromBroadcast.itemData(
|
||||
i, QtCore.Qt.UserRole).toString())
|
||||
address = ustr(self.ui.comboBoxSendFromBroadcast.itemData(
|
||||
i, QtCore.Qt.UserRole))
|
||||
self.ui.comboBoxSendFromBroadcast.setItemData(
|
||||
i, AccountColor(address).accountColor(),
|
||||
QtCore.Qt.ForegroundRole)
|
||||
self.ui.comboBoxSendFromBroadcast.insertItem(0, '', '')
|
||||
if(self.ui.comboBoxSendFromBroadcast.count() == 2):
|
||||
if self.ui.comboBoxSendFromBroadcast.count() == 2:
|
||||
self.ui.comboBoxSendFromBroadcast.setCurrentIndex(1)
|
||||
else:
|
||||
self.ui.comboBoxSendFromBroadcast.setCurrentIndex(0)
|
||||
|
@ -2480,6 +2502,8 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
tableWidget = self.widgetConvert(treeWidget)
|
||||
current_account = self.getCurrentAccount(treeWidget)
|
||||
current_folder = self.getCurrentFolder(treeWidget)
|
||||
# inventoryHash surprisingly is of type unicode
|
||||
# inventoryHash = inventoryHash.encode('utf-8')
|
||||
# pylint: disable=too-many-boolean-expressions
|
||||
if ((tableWidget == inbox
|
||||
and current_account == acct.address
|
||||
|
@ -2500,8 +2524,8 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
'bitmessagesettings', 'showtraynotifications'):
|
||||
self.notifierShow(
|
||||
_translate("MainWindow", "New Message"),
|
||||
_translate("MainWindow", "From %1").arg(
|
||||
unicode(acct.fromLabel, 'utf-8')),
|
||||
_translate("MainWindow", "From {0}").format(
|
||||
unic(ustr(acct.fromLabel))),
|
||||
sound.SOUND_UNKNOWN
|
||||
)
|
||||
if self.getCurrentAccount() is not None and (
|
||||
|
@ -2527,7 +2551,7 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
dialog.exec_()
|
||||
try:
|
||||
address, label = dialog.data
|
||||
except AttributeError:
|
||||
except (AttributeError, TypeError):
|
||||
return
|
||||
|
||||
# First we must check to see if the address is already in the
|
||||
|
@ -2560,7 +2584,7 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
# Add to database (perhaps this should be separated from the MyForm class)
|
||||
sqlExecute(
|
||||
'''INSERT INTO subscriptions VALUES (?,?,?)''',
|
||||
label, address, True
|
||||
dbstr(label), dbstr(address), True
|
||||
)
|
||||
self.rerenderMessagelistFromLabels()
|
||||
shared.reloadBroadcastSendersForWhichImWatching()
|
||||
|
@ -2572,7 +2596,7 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
dialog.exec_()
|
||||
try:
|
||||
address, label = dialog.data
|
||||
except AttributeError:
|
||||
except (AttributeError, TypeError):
|
||||
return
|
||||
|
||||
# We must check to see if the address is already in the
|
||||
|
@ -2631,15 +2655,14 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
dialog = dialogs.EmailGatewayDialog(self, config=config)
|
||||
# For Modal dialogs
|
||||
dialog.exec_()
|
||||
try:
|
||||
acct = dialog.data
|
||||
except AttributeError:
|
||||
if not acct:
|
||||
return
|
||||
|
||||
# Only settings remain here
|
||||
acct.settings()
|
||||
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:
|
||||
self.ui.comboBoxSendFrom.setCurrentIndex(i)
|
||||
break
|
||||
|
@ -2658,13 +2681,13 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
self.ui.textEditMessage.setFocus()
|
||||
|
||||
def on_action_MarkAllRead(self):
|
||||
if QtGui.QMessageBox.question(
|
||||
if QtWidgets.QMessageBox.question(
|
||||
self, "Marking all messages as read?",
|
||||
_translate(
|
||||
"MainWindow",
|
||||
"Are you sure you would like to mark all messages read?"
|
||||
), QtGui.QMessageBox.Yes | QtGui.QMessageBox.No
|
||||
) != QtGui.QMessageBox.Yes:
|
||||
), QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No
|
||||
) != QtWidgets.QMessageBox.Yes:
|
||||
return
|
||||
tableWidget = self.getCurrentMessagelist()
|
||||
|
||||
|
@ -2674,13 +2697,18 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
|
||||
msgids = []
|
||||
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()):
|
||||
tableWidget.item(i, col).setUnread(False)
|
||||
|
||||
markread = sqlExecuteChunked(
|
||||
"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:
|
||||
|
@ -2692,7 +2720,7 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
def network_switch(self):
|
||||
dontconnect_option = not config.safeGetBoolean(
|
||||
'bitmessagesettings', 'dontconnect')
|
||||
reply = QtGui.QMessageBox.question(
|
||||
reply = QtWidgets.QMessageBox.question(
|
||||
self, _translate("MainWindow", "Disconnecting")
|
||||
if dontconnect_option else _translate("MainWindow", "Connecting"),
|
||||
_translate(
|
||||
|
@ -2701,12 +2729,12 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
) if dontconnect_option else _translate(
|
||||
"MainWindow",
|
||||
"Bitmessage will now start connecting to network. Are you sure?"
|
||||
), QtGui.QMessageBox.Yes | QtGui.QMessageBox.Cancel,
|
||||
QtGui.QMessageBox.Cancel)
|
||||
if reply != QtGui.QMessageBox.Yes:
|
||||
), QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.Cancel,
|
||||
QtWidgets.QMessageBox.Cancel)
|
||||
if reply != QtWidgets.QMessageBox.Yes:
|
||||
return
|
||||
config.set(
|
||||
'bitmessagesettings', 'dontconnect', str(dontconnect_option))
|
||||
'bitmessagesettings', 'dontconnect', ustr(dontconnect_option))
|
||||
config.save()
|
||||
self.ui.updateNetworkSwitchMenuLabel(dontconnect_option)
|
||||
|
||||
|
@ -2729,68 +2757,66 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
waitForSync = False
|
||||
|
||||
# C PoW currently doesn't support interrupting and OpenCL is untested
|
||||
if getPowType() == "python" and (powQueueSize() > 0 or pendingUpload() > 0):
|
||||
reply = QtGui.QMessageBox.question(
|
||||
if getPowType() == "python" and (
|
||||
powQueueSize() > 0 or pendingUpload() > 0):
|
||||
reply = QtWidgets.QMessageBox.question(
|
||||
self, _translate("MainWindow", "Proof of work pending"),
|
||||
_translate(
|
||||
"MainWindow",
|
||||
"%n object(s) pending proof of work", None,
|
||||
QtCore.QCoreApplication.CodecForTr, powQueueSize()
|
||||
) + ", " +
|
||||
_translate(
|
||||
"%n object(s) pending proof of work", None, powQueueSize()
|
||||
) + ", "
|
||||
+ _translate(
|
||||
"MainWindow",
|
||||
"%n object(s) waiting to be distributed", None,
|
||||
QtCore.QCoreApplication.CodecForTr, pendingUpload()
|
||||
) + "\n\n" +
|
||||
_translate(
|
||||
"MainWindow", "Wait until these tasks finish?"),
|
||||
QtGui.QMessageBox.Yes | QtGui.QMessageBox.No
|
||||
| QtGui.QMessageBox.Cancel, QtGui.QMessageBox.Cancel)
|
||||
if reply == QtGui.QMessageBox.No:
|
||||
"%n object(s) waiting to be distributed",
|
||||
None, pendingUpload()
|
||||
) + "\n\n"
|
||||
+ _translate("MainWindow", "Wait until these tasks finish?"),
|
||||
QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No
|
||||
| QtWidgets.QMessageBox.Cancel, QtWidgets.QMessageBox.Cancel
|
||||
)
|
||||
if reply == QtWidgets.QMessageBox.No:
|
||||
waitForPow = False
|
||||
elif reply == QtGui.QMessageBox.Cancel:
|
||||
elif reply == QtWidgets.QMessageBox.Cancel:
|
||||
return
|
||||
|
||||
if pendingDownload() > 0:
|
||||
reply = QtGui.QMessageBox.question(
|
||||
reply = QtWidgets.QMessageBox.question(
|
||||
self, _translate("MainWindow", "Synchronisation pending"),
|
||||
_translate(
|
||||
"MainWindow",
|
||||
"Bitmessage hasn't synchronised with the network,"
|
||||
" %n object(s) to be downloaded. If you quit now,"
|
||||
" it may cause delivery delays. Wait until the"
|
||||
" synchronisation finishes?", None,
|
||||
QtCore.QCoreApplication.CodecForTr, pendingDownload()
|
||||
),
|
||||
QtGui.QMessageBox.Yes | QtGui.QMessageBox.No
|
||||
| QtGui.QMessageBox.Cancel, QtGui.QMessageBox.Cancel)
|
||||
if reply == QtGui.QMessageBox.Yes:
|
||||
" synchronisation finishes?",
|
||||
None, pendingDownload()
|
||||
), QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No
|
||||
| QtWidgets.QMessageBox.Cancel, QtWidgets.QMessageBox.Cancel)
|
||||
if reply == QtWidgets.QMessageBox.Yes:
|
||||
self.wait = waitForSync = True
|
||||
elif reply == QtGui.QMessageBox.Cancel:
|
||||
elif reply == QtWidgets.QMessageBox.Cancel:
|
||||
return
|
||||
|
||||
if state.statusIconColor == 'red' and not config.safeGetBoolean(
|
||||
'bitmessagesettings', 'dontconnect'):
|
||||
reply = QtGui.QMessageBox.question(
|
||||
reply = QtWidgets.QMessageBox.question(
|
||||
self, _translate("MainWindow", "Not connected"),
|
||||
_translate(
|
||||
"MainWindow",
|
||||
"Bitmessage isn't connected to the network. If you"
|
||||
" quit now, it may cause delivery delays. Wait until"
|
||||
" connected and the synchronisation finishes?"
|
||||
),
|
||||
QtGui.QMessageBox.Yes | QtGui.QMessageBox.No
|
||||
| QtGui.QMessageBox.Cancel, QtGui.QMessageBox.Cancel)
|
||||
if reply == QtGui.QMessageBox.Yes:
|
||||
), QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No
|
||||
| QtWidgets.QMessageBox.Cancel, QtWidgets.QMessageBox.Cancel)
|
||||
if reply == QtWidgets.QMessageBox.Yes:
|
||||
waitForConnection = True
|
||||
self.wait = waitForSync = True
|
||||
elif reply == QtGui.QMessageBox.Cancel:
|
||||
elif reply == QtWidgets.QMessageBox.Cancel:
|
||||
return
|
||||
|
||||
self.quitAccepted = True
|
||||
|
||||
self.updateStatusBar(_translate(
|
||||
"MainWindow", "Shutting down PyBitmessage... %1%").arg(0))
|
||||
"MainWindow", "Shutting down PyBitmessage... {0}%").format(0))
|
||||
|
||||
if waitForConnection:
|
||||
self.updateStatusBar(_translate(
|
||||
|
@ -2824,8 +2850,8 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
maxWorkerQueue = curWorkerQueue
|
||||
if curWorkerQueue > 0:
|
||||
self.updateStatusBar(_translate(
|
||||
"MainWindow", "Waiting for PoW to finish... %1%"
|
||||
).arg(50 * (maxWorkerQueue - curWorkerQueue) /
|
||||
"MainWindow", "Waiting for PoW to finish... {0}%"
|
||||
).format(50 * (maxWorkerQueue - curWorkerQueue) /
|
||||
maxWorkerQueue))
|
||||
time.sleep(0.5)
|
||||
QtCore.QCoreApplication.processEvents(
|
||||
|
@ -2833,7 +2859,7 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
)
|
||||
|
||||
self.updateStatusBar(_translate(
|
||||
"MainWindow", "Shutting down Pybitmessage... %1%").arg(50))
|
||||
"MainWindow", "Shutting down Pybitmessage... {0}%").format(50))
|
||||
|
||||
QtCore.QCoreApplication.processEvents(
|
||||
QtCore.QEventLoop.AllEvents, 1000
|
||||
|
@ -2847,14 +2873,15 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
|
||||
# check if upload (of objects created locally) pending
|
||||
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())
|
||||
|
||||
while pendingUpload() > 1:
|
||||
self.updateStatusBar(_translate(
|
||||
"MainWindow",
|
||||
"Waiting for objects to be sent... %1%"
|
||||
).arg(int(50 + 20 * (pendingUpload() / maxPendingUpload))))
|
||||
"Waiting for objects to be sent... {0}%"
|
||||
).format(int(50 + 20 * pendingUpload() / maxPendingUpload)))
|
||||
time.sleep(0.5)
|
||||
QtCore.QCoreApplication.processEvents(
|
||||
QtCore.QEventLoop.AllEvents, 1000
|
||||
|
@ -2863,18 +2890,15 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
QtCore.QCoreApplication.processEvents(
|
||||
QtCore.QEventLoop.AllEvents, 1000
|
||||
)
|
||||
QtCore.QCoreApplication.processEvents(
|
||||
QtCore.QEventLoop.AllEvents, 1000
|
||||
)
|
||||
|
||||
# save state and geometry self and all widgets
|
||||
self.updateStatusBar(_translate(
|
||||
"MainWindow", "Saving settings... %1%").arg(70))
|
||||
"MainWindow", "Saving settings... {0}%").format(70))
|
||||
QtCore.QCoreApplication.processEvents(
|
||||
QtCore.QEventLoop.AllEvents, 1000
|
||||
)
|
||||
self.saveSettings()
|
||||
for attr, obj in self.ui.__dict__.iteritems():
|
||||
for attr, obj in six.iteritems(self.ui.__dict__):
|
||||
if hasattr(obj, "__class__") \
|
||||
and isinstance(obj, settingsmixin.SettingsMixin):
|
||||
saveMethod = getattr(obj, "saveSettings", None)
|
||||
|
@ -2882,18 +2906,18 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
obj.saveSettings()
|
||||
|
||||
self.updateStatusBar(_translate(
|
||||
"MainWindow", "Shutting down core... %1%").arg(80))
|
||||
"MainWindow", "Shutting down core... {0}%").format(80))
|
||||
QtCore.QCoreApplication.processEvents(
|
||||
QtCore.QEventLoop.AllEvents, 1000
|
||||
)
|
||||
shutdown.doCleanShutdown()
|
||||
|
||||
self.updateStatusBar(_translate(
|
||||
"MainWindow", "Stopping notifications... %1%").arg(90))
|
||||
"MainWindow", "Stopping notifications... {0}%").format(90))
|
||||
self.tray.hide()
|
||||
|
||||
self.updateStatusBar(_translate(
|
||||
"MainWindow", "Shutdown imminent... %1%").arg(100))
|
||||
"MainWindow", "Shutdown imminent... {0}%").format(100))
|
||||
|
||||
logger.info("Shutdown complete")
|
||||
self.close()
|
||||
|
@ -2919,26 +2943,39 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
if not msgid:
|
||||
return
|
||||
queryreturn = sqlQuery(
|
||||
'''select message from inbox where msgid=?''', msgid)
|
||||
if queryreturn != []:
|
||||
for row in queryreturn:
|
||||
messageText, = row
|
||||
'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)
|
||||
try:
|
||||
lines_raw = queryreturn[-1][0].split('\n')
|
||||
lines = []
|
||||
for line in lines_raw:
|
||||
lines.append(line.decode("utf-8", "replace"))
|
||||
except IndexError:
|
||||
lines = ''
|
||||
|
||||
lines = messageText.split('\n')
|
||||
totalLines = len(lines)
|
||||
for i in xrange(totalLines):
|
||||
if 'Message ostensibly from ' in lines[i]:
|
||||
lines[i] = '<p style="font-size: 12px; color: grey;">%s</span></p>' % (
|
||||
lines[i])
|
||||
elif lines[i] == '------------------------------------------------------':
|
||||
lines[i] = (
|
||||
'<p style="font-size: 12px; color: grey;">%s</span></p>' %
|
||||
lines[i]
|
||||
)
|
||||
elif (
|
||||
lines[i]
|
||||
== '------------------------------------------------------'
|
||||
):
|
||||
lines[i] = '<hr>'
|
||||
elif lines[i] == '' and (i+1) < totalLines and \
|
||||
lines[i+1] != '------------------------------------------------------':
|
||||
elif (
|
||||
lines[i] == '' and (i + 1) < totalLines and lines[i + 1]
|
||||
!= '------------------------------------------------------'
|
||||
):
|
||||
lines[i] = '<br><br>'
|
||||
content = ' '.join(lines) # To keep the whitespace between lines
|
||||
content = shared.fixPotentiallyInvalidUTF8Data(content)
|
||||
content = unicode(content, 'utf-8)')
|
||||
textEdit.setHtml(QtCore.QString(content))
|
||||
content = unic(ustr(content))
|
||||
textEdit.setHtml(content)
|
||||
|
||||
def on_action_InboxMarkUnread(self):
|
||||
tableWidget = self.getCurrentMessagelist()
|
||||
|
@ -2949,8 +2986,8 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
# modified = 0
|
||||
for row in tableWidget.selectedIndexes():
|
||||
currentRow = row.row()
|
||||
msgid = tableWidget.item(currentRow, 3).data()
|
||||
msgids.add(msgid)
|
||||
msgid = as_msgid(tableWidget.item(currentRow, 3).data())
|
||||
msgids.add(sqlite3.Binary(msgid))
|
||||
# if not tableWidget.item(currentRow, 0).unread:
|
||||
# modified += 1
|
||||
self.updateUnreadStatus(tableWidget, currentRow, msgid, False)
|
||||
|
@ -2958,24 +2995,25 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
# for 1081
|
||||
idCount = len(msgids)
|
||||
# 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(
|
||||
'''UPDATE inbox SET read=0 WHERE msgid IN ({0}) AND read=1''',
|
||||
idCount, *msgids
|
||||
True, idCount, *msgids
|
||||
)
|
||||
|
||||
self.propagateUnreadCount()
|
||||
# tableWidget.selectRow(currentRow + 1)
|
||||
# This doesn't de-select the last message if you try to mark it
|
||||
# unread, but that doesn't interfere. Might not be necessary.
|
||||
# We could also select upwards, but then our problem would be
|
||||
# with the topmost message.
|
||||
# tableWidget.clearSelection() manages to mark the message
|
||||
# as read again.
|
||||
|
||||
# Format predefined text on message reply.
|
||||
def quoted_text(self, message):
|
||||
if not config.safeGetBoolean('bitmessagesettings', 'replybelow'):
|
||||
return '\n\n------------------------------------------------------\n' + message
|
||||
return (
|
||||
'\n\n------------------------------------------------------\n' +
|
||||
message
|
||||
)
|
||||
|
||||
quoteWrapper = textwrap.TextWrapper(
|
||||
replace_whitespace=False, initial_indent='> ',
|
||||
|
@ -3005,7 +3043,7 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
self.ui.comboBoxSendFrom, self.ui.comboBoxSendFromBroadcast
|
||||
):
|
||||
for i in range(box.count()):
|
||||
if str(box.itemData(i).toPyObject()) == address:
|
||||
if ustr(box.itemData(i)) == ustr(address):
|
||||
box.setCurrentIndex(i)
|
||||
break
|
||||
else:
|
||||
|
@ -3039,17 +3077,23 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
acct = accountClass(toAddressAtCurrentInboxRow)
|
||||
fromAddressAtCurrentInboxRow = tableWidget.item(
|
||||
currentInboxRow, column_from).address
|
||||
msgid = tableWidget.item(currentInboxRow, 3).data()
|
||||
msgid = as_msgid(tableWidget.item(currentInboxRow, 3).data())
|
||||
queryreturn = sqlQuery(
|
||||
"SELECT message FROM inbox WHERE msgid=?", msgid
|
||||
) or sqlQuery("SELECT message FROM sent WHERE ackdata=?", msgid)
|
||||
"SELECT message FROM inbox WHERE msgid=?", sqlite3.Binary(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 != []:
|
||||
for row in queryreturn:
|
||||
messageAtCurrentInboxRow, = row
|
||||
messageAtCurrentInboxRow = messageAtCurrentInboxRow.decode("utf-8", "replace")
|
||||
acct.parseMessage(
|
||||
toAddressAtCurrentInboxRow, fromAddressAtCurrentInboxRow,
|
||||
tableWidget.item(currentInboxRow, 2).subject,
|
||||
messageAtCurrentInboxRow)
|
||||
messageAtCurrentInboxRow
|
||||
)
|
||||
widget = {
|
||||
'subject': self.ui.lineEditSubject,
|
||||
'from': self.ui.comboBoxSendFrom,
|
||||
|
@ -3062,23 +3106,26 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
)
|
||||
# toAddressAtCurrentInboxRow = fromAddressAtCurrentInboxRow
|
||||
elif not config.has_section(toAddressAtCurrentInboxRow):
|
||||
QtGui.QMessageBox.information(
|
||||
self, _translate("MainWindow", "Address is gone"),
|
||||
QtWidgets.QMessageBox.information(
|
||||
self,
|
||||
_translate("MainWindow", "Address is gone"),
|
||||
_translate(
|
||||
"MainWindow",
|
||||
"Bitmessage cannot find your address %1. Perhaps you"
|
||||
"Bitmessage cannot find your address {0}. Perhaps you"
|
||||
" removed it?"
|
||||
).arg(toAddressAtCurrentInboxRow), QtGui.QMessageBox.Ok)
|
||||
).format(toAddressAtCurrentInboxRow),
|
||||
QtWidgets.QMessageBox.Ok)
|
||||
elif not config.getboolean(
|
||||
toAddressAtCurrentInboxRow, 'enabled'):
|
||||
QtGui.QMessageBox.information(
|
||||
self, _translate("MainWindow", "Address disabled"),
|
||||
QtWidgets.QMessageBox.information(
|
||||
self,
|
||||
_translate("MainWindow", "Address disabled"),
|
||||
_translate(
|
||||
"MainWindow",
|
||||
"Error: The address from which you are trying to send"
|
||||
" is disabled. You\'ll have to enable it on the"
|
||||
" \'Your Identities\' tab before using it."
|
||||
), QtGui.QMessageBox.Ok)
|
||||
" is disabled. You\'ll have to enable it on the \'Your"
|
||||
" Identities\' tab before using it."
|
||||
), QtWidgets.QMessageBox.Ok)
|
||||
else:
|
||||
self.setBroadcastEnablementDependingOnWhetherThisIsAMailingListAddress(toAddressAtCurrentInboxRow)
|
||||
broadcast_tab_index = self.ui.tabWidgetSend.indexOf(
|
||||
|
@ -3096,7 +3143,7 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
tableWidget.item(currentInboxRow, column_from).label or (
|
||||
isinstance(acct, GatewayAccount) and
|
||||
fromAddressAtCurrentInboxRow == acct.relayAddress):
|
||||
self.ui.lineEditTo.setText(str(acct.fromAddress))
|
||||
self.ui.lineEditTo.setText(ustr(acct.fromAddress))
|
||||
else:
|
||||
self.ui.lineEditTo.setText(
|
||||
tableWidget.item(currentInboxRow, column_from).accountString()
|
||||
|
@ -3111,7 +3158,7 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
' reply to the chan address.')
|
||||
if toAddressAtCurrentInboxRow == \
|
||||
tableWidget.item(currentInboxRow, column_to).label:
|
||||
self.ui.lineEditTo.setText(str(toAddressAtCurrentInboxRow))
|
||||
self.ui.lineEditTo.setText(ustr(toAddressAtCurrentInboxRow))
|
||||
else:
|
||||
self.ui.lineEditTo.setText(
|
||||
tableWidget.item(currentInboxRow, column_to).accountString()
|
||||
|
@ -3120,7 +3167,7 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
self.setSendFromComboBox(toAddressAtCurrentInboxRow)
|
||||
|
||||
quotedText = self.quoted_text(
|
||||
unicode(messageAtCurrentInboxRow, 'utf-8', 'replace'))
|
||||
unic(ustr(messageAtCurrentInboxRow)))
|
||||
widget['message'].setPlainText(quotedText)
|
||||
if acct.subject[0:3] in ('Re:', 'RE:'):
|
||||
widget['subject'].setText(
|
||||
|
@ -3156,14 +3203,15 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
recipientAddress = tableWidget.item(
|
||||
currentInboxRow, 0).data(QtCore.Qt.UserRole)
|
||||
# Let's make sure that it isn't already in the address book
|
||||
queryreturn = sqlQuery('''select * from blacklist where address=?''',
|
||||
addressAtCurrentInboxRow)
|
||||
queryreturn = sqlQuery(
|
||||
'SELECT * FROM blacklist WHERE address=?',
|
||||
dbstr(addressAtCurrentInboxRow))
|
||||
if queryreturn == []:
|
||||
label = "\"" + tableWidget.item(currentInboxRow, 2).subject + "\" in " + config.get(
|
||||
recipientAddress, "label")
|
||||
sqlExecute('''INSERT INTO blacklist VALUES (?,?, ?)''',
|
||||
label,
|
||||
addressAtCurrentInboxRow, True)
|
||||
dbstr(label),
|
||||
dbstr(addressAtCurrentInboxRow), True)
|
||||
self.ui.blackwhitelist.rerenderBlackWhiteList()
|
||||
self.updateStatusBar(_translate(
|
||||
"MainWindow",
|
||||
|
@ -3188,15 +3236,15 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
messageLists = (messageLists,)
|
||||
for messageList in messageLists:
|
||||
if row is not None:
|
||||
inventoryHash = messageList.item(row, 3).data()
|
||||
inventoryHash = as_msgid(messageList.item(row, 3).data())
|
||||
messageList.removeRow(row)
|
||||
elif inventoryHash is not None:
|
||||
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)
|
||||
elif ackData is not None:
|
||||
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)
|
||||
|
||||
# Send item on the Inbox tab to trash
|
||||
|
@ -3206,8 +3254,8 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
return
|
||||
currentRow = 0
|
||||
folder = self.getCurrentFolder()
|
||||
shifted = QtGui.QApplication.queryKeyboardModifiers() \
|
||||
& QtCore.Qt.ShiftModifier
|
||||
shifted = (QtWidgets.QApplication.queryKeyboardModifiers() &
|
||||
QtCore.Qt.ShiftModifier)
|
||||
tableWidget.setUpdatesEnabled(False)
|
||||
inventoryHashesToTrash = set()
|
||||
# ranges in reversed order
|
||||
|
@ -3216,16 +3264,21 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
)[::-1]:
|
||||
for i in range(r.bottomRow() - r.topRow() + 1):
|
||||
inventoryHashesToTrash.add(
|
||||
tableWidget.item(r.topRow() + i, 3).data())
|
||||
sqlite3.Binary(as_msgid(tableWidget.item(r.topRow() + i, 3).data())))
|
||||
currentRow = r.topRow()
|
||||
self.getCurrentMessageTextedit().setText("")
|
||||
tableWidget.model().removeRows(
|
||||
r.topRow(), r.bottomRow() - r.topRow() + 1)
|
||||
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(
|
||||
("DELETE FROM inbox" if folder == "trash" or shifted else
|
||||
"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.setUpdatesEnabled(True)
|
||||
self.propagateUnreadCount(folder)
|
||||
|
@ -3244,16 +3297,20 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
)[::-1]:
|
||||
for i in range(r.bottomRow() - r.topRow() + 1):
|
||||
inventoryHashesToTrash.add(
|
||||
tableWidget.item(r.topRow() + i, 3).data())
|
||||
sqlite3.Binary(as_msgid(tableWidget.item(r.topRow() + i, 3).data())))
|
||||
currentRow = r.topRow()
|
||||
self.getCurrentMessageTextedit().setText("")
|
||||
tableWidget.model().removeRows(
|
||||
r.topRow(), r.bottomRow() - r.topRow() + 1)
|
||||
tableWidget.selectRow(0 if currentRow == 0 else currentRow - 1)
|
||||
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(
|
||||
"UPDATE inbox SET folder='inbox' WHERE msgid IN({0})",
|
||||
idCount, *inventoryHashesToTrash)
|
||||
True, idCount, *inventoryHashesToTrash)
|
||||
tableWidget.selectRow(0 if currentRow == 0 else currentRow - 1)
|
||||
tableWidget.setUpdatesEnabled(True)
|
||||
self.propagateUnreadCount()
|
||||
|
@ -3265,30 +3322,33 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
return
|
||||
currentInboxRow = tableWidget.currentRow()
|
||||
try:
|
||||
subjectAtCurrentInboxRow = str(tableWidget.item(
|
||||
subjectAtCurrentInboxRow = ustr(tableWidget.item(
|
||||
currentInboxRow, 2).data(QtCore.Qt.UserRole))
|
||||
except:
|
||||
subjectAtCurrentInboxRow = ''
|
||||
|
||||
# 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(
|
||||
'''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 != []:
|
||||
for row in queryreturn:
|
||||
message, = row
|
||||
message = message.decode("utf-8", "replace")
|
||||
|
||||
defaultFilename = "".join(x for x in subjectAtCurrentInboxRow if x.isalnum()) + '.txt'
|
||||
filename = QtGui.QFileDialog.getSaveFileName(
|
||||
self,
|
||||
_translate("MainWindow","Save As..."),
|
||||
defaultFilename,
|
||||
"Text files (*.txt);;All files (*.*)")
|
||||
if filename == '':
|
||||
defaultFilename = "".join(
|
||||
x for x in subjectAtCurrentInboxRow if x.isalnum()) + '.txt'
|
||||
filename = QtWidgets.QFileDialog.getSaveFileName(
|
||||
self, _translate("MainWindow", "Save As..."), defaultFilename,
|
||||
"Text files (*.txt);;All files (*.*)")[0]
|
||||
if not filename:
|
||||
return
|
||||
try:
|
||||
f = open(filename, 'w')
|
||||
f.write(message)
|
||||
f.write(message.encode("utf-8", "replace"))
|
||||
f.close()
|
||||
except Exception:
|
||||
logger.exception('Message not saved', exc_info=True)
|
||||
|
@ -3296,18 +3356,26 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
|
||||
# Send item on the Sent tab to trash
|
||||
def on_action_SentTrash(self):
|
||||
currentRow = 0
|
||||
tableWidget = self.getCurrentMessagelist()
|
||||
if not tableWidget:
|
||||
return
|
||||
folder = self.getCurrentFolder()
|
||||
shifted = QtGui.QApplication.queryKeyboardModifiers() & QtCore.Qt.ShiftModifier
|
||||
shifted = (QtWidgets.QApplication.queryKeyboardModifiers() &
|
||||
QtCore.Qt.ShiftModifier)
|
||||
while tableWidget.selectedIndexes() != []:
|
||||
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(
|
||||
"DELETE FROM sent" if folder == "trash" or shifted else
|
||||
"UPDATE sent SET folder='trash'"
|
||||
" WHERE ackdata = ?", ackdataToTrash
|
||||
" WHERE ackdata = CAST(? AS TEXT)", ackdataToTrash
|
||||
)
|
||||
self.getCurrentMessageTextedit().setPlainText("")
|
||||
tableWidget.removeRow(currentRow)
|
||||
|
@ -3322,22 +3390,29 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
addressAtCurrentRow = self.ui.tableWidgetInbox.item(
|
||||
currentRow, 0).data(QtCore.Qt.UserRole)
|
||||
toRipe = decodeAddress(addressAtCurrentRow)[3]
|
||||
sqlExecute(
|
||||
rowcount = sqlExecute(
|
||||
'''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)
|
||||
queryreturn = sqlQuery('''select ackdata FROM sent WHERE status='forcepow' ''')
|
||||
for row in queryreturn:
|
||||
ackdata, = row
|
||||
queues.UISignalQueue.put(('updateSentItemStatusByAckdata', (
|
||||
ackdata, 'Overriding maximum-difficulty setting. Work queued.')))
|
||||
queues.UISignalQueue.put((
|
||||
'updateSentItemStatusByAckdata',
|
||||
(ackdata, 'Overriding maximum-difficulty setting.'
|
||||
' Work queued.')
|
||||
))
|
||||
queues.workerQueue.put(('sendmessage', ''))
|
||||
|
||||
def on_action_SentClipboard(self):
|
||||
currentRow = self.ui.tableWidgetInbox.currentRow()
|
||||
addressAtCurrentRow = self.ui.tableWidgetInbox.item(
|
||||
currentRow, 0).data(QtCore.Qt.UserRole)
|
||||
clipboard = QtGui.QApplication.clipboard()
|
||||
clipboard.setText(str(addressAtCurrentRow))
|
||||
clipboard = QtWidgets.QApplication.clipboard()
|
||||
clipboard.setText(ustr(addressAtCurrentRow))
|
||||
|
||||
# Group of functions for the Address Book dialog box
|
||||
def on_action_AddressBookNew(self):
|
||||
|
@ -3349,7 +3424,7 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
0].row()
|
||||
item = self.ui.tableWidgetAddressBook.item(currentRow, 0)
|
||||
sqlExecute(
|
||||
'DELETE FROM addressbook WHERE address=?', item.address)
|
||||
'DELETE FROM addressbook WHERE address=?', dbstr(item.address))
|
||||
self.ui.tableWidgetAddressBook.removeRow(currentRow)
|
||||
self.rerenderMessagelistFromLabels()
|
||||
self.rerenderMessagelistToLabels()
|
||||
|
@ -3361,7 +3436,7 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
addresses_string = item.address
|
||||
else:
|
||||
addresses_string += ', ' + item.address
|
||||
clipboard = QtGui.QApplication.clipboard()
|
||||
clipboard = QtWidgets.QApplication.clipboard()
|
||||
clipboard.setText(addresses_string)
|
||||
|
||||
def on_action_AddressBookSend(self):
|
||||
|
@ -3371,8 +3446,7 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
return self.updateStatusBar(_translate(
|
||||
"MainWindow", "No addresses selected."))
|
||||
|
||||
addresses_string = unicode(
|
||||
self.ui.lineEditTo.text().toUtf8(), 'utf-8')
|
||||
addresses_string = unic(ustr(self.ui.lineEditTo.text()))
|
||||
for item in selected_items:
|
||||
address_string = item.accountString()
|
||||
if not addresses_string:
|
||||
|
@ -3403,7 +3477,7 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
)
|
||||
|
||||
def on_context_menuAddressBook(self, point):
|
||||
self.popMenuAddressBook = QtGui.QMenu(self)
|
||||
self.popMenuAddressBook = QtWidgets.QMenu(self)
|
||||
self.popMenuAddressBook.addAction(self.actionAddressBookSend)
|
||||
self.popMenuAddressBook.addAction(self.actionAddressBookClipboard)
|
||||
self.popMenuAddressBook.addAction(self.actionAddressBookSubscribe)
|
||||
|
@ -3433,7 +3507,7 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
self.click_pushButtonAddSubscription()
|
||||
|
||||
def on_action_SubscriptionsDelete(self):
|
||||
if QtGui.QMessageBox.question(
|
||||
if QtWidgets.QMessageBox.question(
|
||||
self, "Delete subscription?",
|
||||
_translate(
|
||||
"MainWindow",
|
||||
|
@ -3444,12 +3518,12 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
" messages, but you can still view messages you"
|
||||
" already received.\n\nAre you sure you want to"
|
||||
" delete the subscription?"
|
||||
), QtGui.QMessageBox.Yes | QtGui.QMessageBox.No
|
||||
) != QtGui.QMessageBox.Yes:
|
||||
), QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No
|
||||
) != QtWidgets.QMessageBox.Yes:
|
||||
return
|
||||
address = self.getCurrentAccount()
|
||||
sqlExecute('''DELETE FROM subscriptions WHERE address=?''',
|
||||
address)
|
||||
dbstr(address))
|
||||
self.rerenderTabTreeSubscriptions()
|
||||
self.rerenderMessagelistFromLabels()
|
||||
self.rerenderAddressBook()
|
||||
|
@ -3457,14 +3531,14 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
|
||||
def on_action_SubscriptionsClipboard(self):
|
||||
address = self.getCurrentAccount()
|
||||
clipboard = QtGui.QApplication.clipboard()
|
||||
clipboard.setText(str(address))
|
||||
clipboard = QtWidgets.QApplication.clipboard()
|
||||
clipboard.setText(ustr(address))
|
||||
|
||||
def on_action_SubscriptionsEnable(self):
|
||||
address = self.getCurrentAccount()
|
||||
sqlExecute(
|
||||
'''update subscriptions set enabled=1 WHERE address=?''',
|
||||
address)
|
||||
dbstr(address))
|
||||
account = self.getCurrentItem()
|
||||
account.setEnabled(True)
|
||||
self.rerenderAddressBook()
|
||||
|
@ -3474,7 +3548,7 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
address = self.getCurrentAccount()
|
||||
sqlExecute(
|
||||
'''update subscriptions set enabled=0 WHERE address=?''',
|
||||
address)
|
||||
dbstr(address))
|
||||
account = self.getCurrentItem()
|
||||
account.setEnabled(False)
|
||||
self.rerenderAddressBook()
|
||||
|
@ -3482,7 +3556,7 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
|
||||
def on_context_menuSubscriptions(self, point):
|
||||
currentItem = self.getCurrentItem()
|
||||
self.popMenuSubscriptions = QtGui.QMenu(self)
|
||||
self.popMenuSubscriptions = QtWidgets.QMenu(self)
|
||||
if isinstance(currentItem, Ui_AddressWidget):
|
||||
self.popMenuSubscriptions.addAction(self.actionsubscriptionsNew)
|
||||
self.popMenuSubscriptions.addAction(self.actionsubscriptionsDelete)
|
||||
|
@ -3522,8 +3596,6 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
return self.ui.tableWidgetInboxSubscriptions
|
||||
elif widget == self.ui.treeWidgetChans:
|
||||
return self.ui.tableWidgetInboxChans
|
||||
else:
|
||||
return None
|
||||
|
||||
def getCurrentTreeWidget(self):
|
||||
currentIndex = self.ui.tabWidget.currentIndex()
|
||||
|
@ -3576,7 +3648,7 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
if messagelist:
|
||||
currentRow = messagelist.currentRow()
|
||||
if currentRow >= 0:
|
||||
return messagelist.item(currentRow, 3).data()
|
||||
return as_msgid(messagelist.item(currentRow, 3).data())
|
||||
|
||||
def getCurrentMessageTextedit(self):
|
||||
currentIndex = self.ui.tabWidget.currentIndex()
|
||||
|
@ -3610,9 +3682,9 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
self.ui.inboxSearchLineEditChans,
|
||||
)
|
||||
if currentIndex >= 0 and currentIndex < len(messagelistList):
|
||||
return (
|
||||
return ustr(
|
||||
messagelistList[currentIndex] if retObj
|
||||
else messagelistList[currentIndex].text().toUtf8().data())
|
||||
else ustr(messagelistList[currentIndex].text()))
|
||||
|
||||
def getCurrentSearchOption(self, currentIndex=None):
|
||||
if currentIndex is None:
|
||||
|
@ -3668,7 +3740,7 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
if account.type == AccountMixin.NORMAL:
|
||||
return # maybe in the future
|
||||
elif account.type == AccountMixin.CHAN:
|
||||
if QtGui.QMessageBox.question(
|
||||
if QtWidgets.QMessageBox.question(
|
||||
self, "Delete channel?",
|
||||
_translate(
|
||||
"MainWindow",
|
||||
|
@ -3679,9 +3751,9 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
" messages, but you can still view messages you"
|
||||
" already received.\n\nAre you sure you want to"
|
||||
" delete the channel?"
|
||||
), QtGui.QMessageBox.Yes | QtGui.QMessageBox.No
|
||||
) == QtGui.QMessageBox.Yes:
|
||||
config.remove_section(str(account.address))
|
||||
), QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No
|
||||
) == QtWidgets.QMessageBox.Yes:
|
||||
config.remove_section(ustr(account.address))
|
||||
else:
|
||||
return
|
||||
else:
|
||||
|
@ -3714,15 +3786,15 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
account.setEnabled(False)
|
||||
|
||||
def disableIdentity(self, address):
|
||||
config.set(str(address), 'enabled', 'false')
|
||||
config.set(ustr(address), 'enabled', 'false')
|
||||
config.save()
|
||||
shared.reloadMyAddressHashes()
|
||||
self.rerenderAddressBook()
|
||||
|
||||
def on_action_Clipboard(self):
|
||||
address = self.getCurrentAccount()
|
||||
clipboard = QtGui.QApplication.clipboard()
|
||||
clipboard.setText(str(address))
|
||||
clipboard = QtWidgets.QApplication.clipboard()
|
||||
clipboard.setText(ustr(address))
|
||||
|
||||
def on_action_ClipboardMessagelist(self):
|
||||
tableWidget = self.getCurrentMessagelist()
|
||||
|
@ -3739,14 +3811,14 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
myAddress = tableWidget.item(currentRow, 0).data(QtCore.Qt.UserRole)
|
||||
otherAddress = tableWidget.item(currentRow, 1).data(QtCore.Qt.UserRole)
|
||||
account = accountClass(myAddress)
|
||||
if isinstance(account, GatewayAccount) and otherAddress == account.relayAddress and (
|
||||
(currentColumn in [0, 2] and self.getCurrentFolder() == "sent") or
|
||||
(currentColumn in [1, 2] and self.getCurrentFolder() != "sent")):
|
||||
text = str(tableWidget.item(currentRow, currentColumn).label)
|
||||
if isinstance(account, GatewayAccount) \
|
||||
and otherAddress == account.relayAddress and (
|
||||
(currentColumn in (0, 2) and currentFolder == "sent") or
|
||||
(currentColumn in (1, 2) and currentFolder != "sent")):
|
||||
text = ustr(tableWidget.item(currentRow, currentColumn).label)
|
||||
else:
|
||||
text = tableWidget.item(currentRow, currentColumn).data(QtCore.Qt.UserRole)
|
||||
|
||||
clipboard = QtGui.QApplication.clipboard()
|
||||
text = ustr(tableWidget.item(currentRow, currentColumn).data(QtCore.Qt.UserRole))
|
||||
clipboard = QtWidgets.QApplication.clipboard()
|
||||
clipboard.setText(text)
|
||||
|
||||
# set avatar functions
|
||||
|
@ -3759,8 +3831,8 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
|
||||
def on_action_SetAvatar(self, thisTableWidget):
|
||||
currentRow = thisTableWidget.currentRow()
|
||||
addressAtCurrentRow = thisTableWidget.item(
|
||||
currentRow, 1).text()
|
||||
addressAtCurrentRow = ustr(thisTableWidget.item(
|
||||
currentRow, 1).text())
|
||||
setToIdenticon = not self.setAvatar(addressAtCurrentRow)
|
||||
if setToIdenticon:
|
||||
thisTableWidget.item(
|
||||
|
@ -3770,11 +3842,8 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
def setAvatar(self, addressAtCurrentRow):
|
||||
if not os.path.exists(state.appdata + 'avatars/'):
|
||||
os.makedirs(state.appdata + 'avatars/')
|
||||
hash = hashlib.md5(addBMIfNotPresent(addressAtCurrentRow)).hexdigest()
|
||||
extensions = [
|
||||
'PNG', 'GIF', 'JPG', 'JPEG', 'SVG', 'BMP', 'MNG', 'PBM',
|
||||
'PGM', 'PPM', 'TIFF', 'XBM', 'XPM', 'TGA']
|
||||
|
||||
hash = hashlib.md5(addBMIfNotPresent(addressAtCurrentRow).encode("utf-8", "replace")).hexdigest()
|
||||
# http://pyqt.sourceforge.net/Docs/PyQt4/qimagereader.html#supportedImageFormats
|
||||
names = {
|
||||
'BMP': 'Windows Bitmap',
|
||||
'GIF': 'Graphic Interchange Format',
|
||||
|
@ -3789,11 +3858,12 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
'XBM': 'X11 Bitmap',
|
||||
'XPM': 'X11 Pixmap',
|
||||
'SVG': 'Scalable Vector Graphics',
|
||||
'TGA': 'Targa Image Format'}
|
||||
'TGA': 'Targa Image Format'
|
||||
}
|
||||
filters = []
|
||||
all_images_filter = []
|
||||
current_files = []
|
||||
for ext in extensions:
|
||||
for ext in names:
|
||||
filters += [names[ext] + ' (*.' + ext.lower() + ')']
|
||||
all_images_filter += ['*.' + ext.lower()]
|
||||
upper = state.appdata + 'avatars/' + hash + '.' + ext.upper()
|
||||
|
@ -3804,10 +3874,9 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
current_files += [upper]
|
||||
filters[0:0] = ['Image files (' + ' '.join(all_images_filter) + ')']
|
||||
filters[1:1] = ['All files (*.*)']
|
||||
sourcefile = QtGui.QFileDialog.getOpenFileName(
|
||||
sourcefile = QtWidgets.QFileDialog.getOpenFileName(
|
||||
self, _translate("MainWindow", "Set avatar..."),
|
||||
filter=';;'.join(filters)
|
||||
)
|
||||
filter=';;'.join(filters))[0]
|
||||
# determine the correct filename (note that avatars don't use the suffix)
|
||||
destination = state.appdata + 'avatars/' + hash + '.' + sourcefile.split('.')[-1]
|
||||
exists = QtCore.QFile.exists(destination)
|
||||
|
@ -3816,11 +3885,11 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
if exists | (len(current_files) > 0):
|
||||
displayMsg = _translate(
|
||||
"MainWindow", "Do you really want to remove this avatar?")
|
||||
overwrite = QtGui.QMessageBox.question(
|
||||
overwrite = QtWidgets.QMessageBox.question(
|
||||
self, 'Message', displayMsg,
|
||||
QtGui.QMessageBox.Yes, QtGui.QMessageBox.No)
|
||||
QtWidgets.QMessageBox.Yes, QtWidgets.QMessageBox.No)
|
||||
else:
|
||||
overwrite = QtGui.QMessageBox.No
|
||||
overwrite = QtWidgets.QMessageBox.No
|
||||
else:
|
||||
# ask whether to overwrite old avatar
|
||||
if exists | (len(current_files) > 0):
|
||||
|
@ -3828,15 +3897,15 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
"MainWindow",
|
||||
"You have already set an avatar for this address."
|
||||
" Do you really want to overwrite it?")
|
||||
overwrite = QtGui.QMessageBox.question(
|
||||
overwrite = QtWidgets.QMessageBox.question(
|
||||
self, 'Message', displayMsg,
|
||||
QtGui.QMessageBox.Yes, QtGui.QMessageBox.No)
|
||||
QtWidgets.QMessageBox.Yes, QtWidgets.QMessageBox.No)
|
||||
else:
|
||||
overwrite = QtGui.QMessageBox.No
|
||||
overwrite = QtWidgets.QMessageBox.No
|
||||
|
||||
# copy the image file to the appdata folder
|
||||
if (not exists) | (overwrite == QtGui.QMessageBox.Yes):
|
||||
if overwrite == QtGui.QMessageBox.Yes:
|
||||
if (not exists) | (overwrite == QtWidgets.QMessageBox.Yes):
|
||||
if overwrite == QtWidgets.QMessageBox.Yes:
|
||||
for file in current_files:
|
||||
QtCore.QFile.remove(file)
|
||||
QtCore.QFile.remove(destination)
|
||||
|
@ -3861,23 +3930,23 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
|
||||
def on_action_AddressBookSetSound(self):
|
||||
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):
|
||||
filters = [unicode(_translate(
|
||||
filters = [unic(_translate(
|
||||
"MainWindow", "Sound files (%s)" %
|
||||
' '.join(['*%s%s' % (os.extsep, ext) for ext in sound.extensions])
|
||||
))]
|
||||
sourcefile = unicode(QtGui.QFileDialog.getOpenFileName(
|
||||
sourcefile = unic(ustr(QtWidgets.QFileDialog.getOpenFileName(
|
||||
self, _translate("MainWindow", "Set notification sound..."),
|
||||
filter=';;'.join(filters)
|
||||
))
|
||||
)))[0]
|
||||
|
||||
if not sourcefile:
|
||||
return
|
||||
|
||||
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)
|
||||
|
||||
if sourcefile == destination:
|
||||
|
@ -3886,15 +3955,15 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
pattern = destfile.lower()
|
||||
for item in os.listdir(destdir):
|
||||
if item.lower() == pattern:
|
||||
overwrite = QtGui.QMessageBox.question(
|
||||
overwrite = QtWidgets.QMessageBox.question(
|
||||
self, _translate("MainWindow", "Message"),
|
||||
_translate(
|
||||
"MainWindow",
|
||||
"You have already set a notification sound"
|
||||
" for this address book entry."
|
||||
" Do you really want to overwrite it?"),
|
||||
QtGui.QMessageBox.Yes, QtGui.QMessageBox.No
|
||||
) == QtGui.QMessageBox.Yes
|
||||
QtWidgets.QMessageBox.Yes, QtWidgets.QMessageBox.No
|
||||
) == QtWidgets.QMessageBox.Yes
|
||||
if overwrite:
|
||||
QtCore.QFile.remove(os.path.join(destdir, item))
|
||||
break
|
||||
|
@ -3905,18 +3974,23 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
|
||||
def on_context_menuYourIdentities(self, point):
|
||||
currentItem = self.getCurrentItem()
|
||||
self.popMenuYourIdentities = QtGui.QMenu(self)
|
||||
self.popMenuYourIdentities = QtWidgets.QMenu(self)
|
||||
if isinstance(currentItem, Ui_AddressWidget):
|
||||
self.popMenuYourIdentities.addAction(self.actionNewYourIdentities)
|
||||
self.popMenuYourIdentities.addSeparator()
|
||||
self.popMenuYourIdentities.addAction(self.actionClipboardYourIdentities)
|
||||
self.popMenuYourIdentities.addAction(
|
||||
self.actionClipboardYourIdentities)
|
||||
self.popMenuYourIdentities.addSeparator()
|
||||
if currentItem.isEnabled:
|
||||
self.popMenuYourIdentities.addAction(self.actionDisableYourIdentities)
|
||||
self.popMenuYourIdentities.addAction(
|
||||
self.actionDisableYourIdentities)
|
||||
else:
|
||||
self.popMenuYourIdentities.addAction(self.actionEnableYourIdentities)
|
||||
self.popMenuYourIdentities.addAction(self.actionSetAvatarYourIdentities)
|
||||
self.popMenuYourIdentities.addAction(self.actionSpecialAddressBehaviorYourIdentities)
|
||||
self.popMenuYourIdentities.addAction(
|
||||
self.actionEnableYourIdentities)
|
||||
self.popMenuYourIdentities.addAction(
|
||||
self.actionSetAvatarYourIdentities)
|
||||
self.popMenuYourIdentities.addAction(
|
||||
self.actionSpecialAddressBehaviorYourIdentities)
|
||||
self.popMenuYourIdentities.addAction(self.actionEmailGateway)
|
||||
self.popMenuYourIdentities.addSeparator()
|
||||
if currentItem.type != AccountMixin.ALL:
|
||||
|
@ -3935,7 +4009,7 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
# TODO make one popMenu
|
||||
def on_context_menuChan(self, point):
|
||||
currentItem = self.getCurrentItem()
|
||||
self.popMenu = QtGui.QMenu(self)
|
||||
self.popMenu = QtWidgets.QMenu(self)
|
||||
if isinstance(currentItem, Ui_AddressWidget):
|
||||
self.popMenu.addAction(self.actionNew)
|
||||
self.popMenu.addAction(self.actionDelete)
|
||||
|
@ -3971,7 +4045,7 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
self.on_context_menuSent(point)
|
||||
return
|
||||
|
||||
self.popMenuInbox = QtGui.QMenu(self)
|
||||
self.popMenuInbox = QtWidgets.QMenu(self)
|
||||
self.popMenuInbox.addAction(self.actionForceHtml)
|
||||
self.popMenuInbox.addAction(self.actionMarkUnread)
|
||||
self.popMenuInbox.addSeparator()
|
||||
|
@ -4006,7 +4080,7 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
|
||||
def on_context_menuSent(self, point):
|
||||
currentRow = self.ui.tableWidgetInbox.currentRow()
|
||||
self.popMenuSent = QtGui.QMenu(self)
|
||||
self.popMenuSent = QtWidgets.QMenu(self)
|
||||
self.popMenuSent.addAction(self.actionSentClipboard)
|
||||
self._contact_selected = self.ui.tableWidgetInbox.item(currentRow, 0)
|
||||
# preloaded gui.menu plugins with prefix 'address'
|
||||
|
@ -4019,10 +4093,13 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
# Check to see if this item is toodifficult and display an additional
|
||||
# menu option (Force Send) if it is.
|
||||
if currentRow >= 0:
|
||||
ackData = self.ui.tableWidgetInbox.item(currentRow, 3).data()
|
||||
queryreturn = sqlQuery('''SELECT status FROM sent where ackdata=?''', ackData)
|
||||
ackData = as_msgid(self.ui.tableWidgetInbox.item(currentRow, 3).data())
|
||||
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:
|
||||
status, = row
|
||||
status = status.decode("utf-8", "replace")
|
||||
if status == 'toodifficult':
|
||||
self.popMenuSent.addAction(self.actionForceSend)
|
||||
|
||||
|
@ -4030,7 +4107,7 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
|
||||
def inboxSearchLineEditUpdated(self, text):
|
||||
# dynamic search for too short text is slow
|
||||
text = text.toUtf8()
|
||||
text = ustr(text)
|
||||
if 0 < len(text) < 3:
|
||||
return
|
||||
messagelist = self.getCurrentMessagelist()
|
||||
|
@ -4043,9 +4120,9 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
|
||||
def inboxSearchLineEditReturnPressed(self):
|
||||
logger.debug("Search return pressed")
|
||||
searchLine = self.getCurrentSearchLine()
|
||||
searchLine = self.getCurrentSearchLine().encode('utf-8')
|
||||
messagelist = self.getCurrentMessagelist()
|
||||
if messagelist and len(str(searchLine)) < 3:
|
||||
if messagelist and len(ustr(searchLine)) < 3:
|
||||
searchOption = self.getCurrentSearchOption()
|
||||
account = self.getCurrentAccount()
|
||||
folder = self.getCurrentFolder()
|
||||
|
@ -4087,7 +4164,7 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
if item.type == AccountMixin.ALL:
|
||||
return
|
||||
|
||||
newLabel = unicode(item.text(0), 'utf-8', 'ignore')
|
||||
newLabel = unic(ustr(item.text(0)))
|
||||
oldLabel = item.defaultLabel()
|
||||
|
||||
# unchanged, do not do anything either
|
||||
|
@ -4106,7 +4183,9 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
self.rerenderMessagelistFromLabels()
|
||||
if item.type != AccountMixin.SUBSCRIPTION:
|
||||
self.rerenderMessagelistToLabels()
|
||||
if item.type in (AccountMixin.NORMAL, AccountMixin.CHAN, AccountMixin.SUBSCRIPTION):
|
||||
if item.type in (
|
||||
AccountMixin.NORMAL, AccountMixin.CHAN, AccountMixin.SUBSCRIPTION
|
||||
):
|
||||
self.rerenderAddressBook()
|
||||
self.recurDepth -= 1
|
||||
|
||||
|
@ -4119,17 +4198,26 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
folder = self.getCurrentFolder()
|
||||
if msgid:
|
||||
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'
|
||||
else ('inbox', 'msgid')
|
||||
), msgid
|
||||
)
|
||||
|
||||
try:
|
||||
message = queryreturn[-1][0]
|
||||
message = queryreturn[-1][0].decode("utf-8", "replace")
|
||||
except NameError:
|
||||
message = ""
|
||||
message = u''
|
||||
except IndexError:
|
||||
# _translate() often returns unicode, no redefinition here!
|
||||
# pylint: disable=redefined-variable-type
|
||||
message = _translate(
|
||||
"MainWindow",
|
||||
"Error occurred: could not load message from disk."
|
||||
|
@ -4141,10 +4229,16 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
if tableWidget.item(currentRow, 0).unread is True:
|
||||
self.updateUnreadStatus(tableWidget, currentRow, msgid)
|
||||
# propagate
|
||||
if folder != 'sent' and sqlExecute(
|
||||
'''UPDATE inbox SET read=1 WHERE msgid=? AND read=0''',
|
||||
rowcount = sqlExecute(
|
||||
'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
|
||||
) > 0:
|
||||
)
|
||||
if folder != 'sent' and rowcount > 0:
|
||||
self.propagateUnreadCount()
|
||||
|
||||
messageTextedit.setCurrentFont(QtGui.QFont())
|
||||
|
@ -4158,8 +4252,9 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
self.rerenderMessagelistToLabels()
|
||||
completerList = self.ui.lineEditTo.completer().model().stringList()
|
||||
for i in range(len(completerList)):
|
||||
if unicode(completerList[i]).endswith(" <" + item.address + ">"):
|
||||
completerList[i] = item.label + " <" + item.address + ">"
|
||||
address_block = " <" + ustr(item.address) + ">"
|
||||
if unic(ustr(completerList[i])).endswith(unic(address_block)):
|
||||
completerList[i] = ustr(item.label) + address_block
|
||||
self.ui.lineEditTo.completer().model().setStringList(completerList)
|
||||
|
||||
def tabWidgetCurrentChanged(self, n):
|
||||
|
@ -4212,7 +4307,7 @@ class MyForm(settingsmixin.SMainWindow):
|
|||
|
||||
def initSettings(self):
|
||||
self.loadSettings()
|
||||
for attr, obj in self.ui.__dict__.iteritems():
|
||||
for attr, obj in six.iteritems(self.ui.__dict__):
|
||||
if hasattr(obj, "__class__") and \
|
||||
isinstance(obj, settingsmixin.SettingsMixin):
|
||||
loadMethod = getattr(obj, "loadSettings", None)
|
||||
|
@ -4224,7 +4319,7 @@ app = None
|
|||
myapp = None
|
||||
|
||||
|
||||
class BitmessageQtApplication(QtGui.QApplication):
|
||||
class BitmessageQtApplication(QtWidgets.QApplication):
|
||||
"""
|
||||
Listener to allow our Qt form to get focus when another instance of the
|
||||
application is open.
|
||||
|
@ -4263,15 +4358,15 @@ class BitmessageQtApplication(QtGui.QApplication):
|
|||
self.server = None
|
||||
self.is_running = False
|
||||
|
||||
socket = QLocalSocket()
|
||||
socket = QtNetwork.QLocalSocket()
|
||||
socket.connectToServer(id)
|
||||
self.is_running = socket.waitForConnected()
|
||||
|
||||
# Cleanup past crashed servers
|
||||
if not self.is_running:
|
||||
if socket.error() == QLocalSocket.ConnectionRefusedError:
|
||||
if socket.error() == QtNetwork.QLocalSocket.ConnectionRefusedError:
|
||||
socket.disconnectFromServer()
|
||||
QLocalServer.removeServer(id)
|
||||
QtNetwork.QLocalServer.removeServer(id)
|
||||
|
||||
socket.abort()
|
||||
|
||||
|
@ -4282,16 +4377,12 @@ class BitmessageQtApplication(QtGui.QApplication):
|
|||
else:
|
||||
# Nope, create a local server with this id and assign on_new_connection
|
||||
# for whenever a second instance tries to run focus the application.
|
||||
self.server = QLocalServer()
|
||||
self.server = QtNetwork.QLocalServer()
|
||||
self.server.listen(id)
|
||||
self.server.newConnection.connect(self.on_new_connection)
|
||||
|
||||
self.setStyleSheet("QStatusBar::item { border: 0px solid black }")
|
||||
|
||||
def __del__(self):
|
||||
if self.server:
|
||||
self.server.close()
|
||||
|
||||
def on_new_connection(self):
|
||||
if myapp:
|
||||
myapp.appIndicatorShow()
|
||||
|
|
|
@ -1,20 +1,16 @@
|
|||
# pylint: disable=too-many-instance-attributes,attribute-defined-outside-init
|
||||
"""
|
||||
account.py
|
||||
==========
|
||||
|
||||
Account related functions.
|
||||
|
||||
"""
|
||||
|
||||
from __future__ import absolute_import
|
||||
|
||||
import inspect
|
||||
import re
|
||||
import sys
|
||||
import time
|
||||
import sqlite3
|
||||
|
||||
from PyQt4 import QtGui
|
||||
from unqstr import ustr, unic
|
||||
from dbcompat import dbstr
|
||||
|
||||
import queues
|
||||
from addresses import decodeAddress
|
||||
|
@ -23,6 +19,7 @@ from helper_ackPayload import genAckPayload
|
|||
from helper_sql import sqlQuery, sqlExecute
|
||||
from .foldertree import AccountMixin
|
||||
from .utils import str_broadcast_subscribers
|
||||
from tr import _translate
|
||||
|
||||
|
||||
def getSortedSubscriptions(count=False):
|
||||
|
@ -34,22 +31,25 @@ def getSortedSubscriptions(count=False):
|
|||
:retuns: dict keys are addresses, values are dicts containing settings
|
||||
:rtype: dict, default {}
|
||||
"""
|
||||
queryreturn = sqlQuery('SELECT label, address, enabled FROM subscriptions ORDER BY label COLLATE NOCASE ASC')
|
||||
queryreturn = sqlQuery(
|
||||
'SELECT label, address, enabled FROM subscriptions'
|
||||
' ORDER BY label COLLATE NOCASE ASC')
|
||||
ret = {}
|
||||
for row in queryreturn:
|
||||
label, address, enabled = row
|
||||
ret[address] = {}
|
||||
ret[address]["inbox"] = {}
|
||||
ret[address]["inbox"]['label'] = label
|
||||
ret[address]["inbox"]['enabled'] = enabled
|
||||
ret[address]["inbox"]['count'] = 0
|
||||
for label, address, enabled in queryreturn:
|
||||
label = label.decode("utf-8", "replace")
|
||||
address = address.decode("utf-8", "replace")
|
||||
ret[address] = {'inbox': {}}
|
||||
ret[address]['inbox'].update(label=label, enabled=enabled, count=0)
|
||||
if count:
|
||||
queryreturn = sqlQuery('''SELECT fromaddress, folder, count(msgid) as cnt
|
||||
FROM inbox, subscriptions ON subscriptions.address = inbox.fromaddress
|
||||
WHERE read = 0 AND toaddress = ?
|
||||
GROUP BY inbox.fromaddress, folder''', str_broadcast_subscribers)
|
||||
for row in queryreturn:
|
||||
address, folder, cnt = row
|
||||
queryreturn = sqlQuery(
|
||||
'SELECT fromaddress, folder, count(msgid) AS cnt'
|
||||
' FROM inbox, subscriptions'
|
||||
' ON subscriptions.address = inbox.fromaddress WHERE read = 0'
|
||||
' AND toaddress = ? GROUP BY inbox.fromaddress, folder',
|
||||
dbstr(str_broadcast_subscribers))
|
||||
for address, folder, cnt in queryreturn:
|
||||
address = address.decode("utf-8", "replace")
|
||||
folder = folder.decode("utf-8", "replace")
|
||||
if folder not in ret[address]:
|
||||
ret[address][folder] = {
|
||||
'label': ret[address]['inbox']['label'],
|
||||
|
@ -75,7 +75,8 @@ def accountClass(address):
|
|||
return subscription
|
||||
try:
|
||||
gateway = config.get(address, "gateway")
|
||||
for _, cls in inspect.getmembers(sys.modules[__name__], inspect.isclass):
|
||||
for _, cls in inspect.getmembers(
|
||||
sys.modules[__name__], inspect.isclass):
|
||||
if issubclass(cls, GatewayAccount) and cls.gatewayName == gateway:
|
||||
return cls(address)
|
||||
# general gateway
|
||||
|
@ -86,7 +87,7 @@ def accountClass(address):
|
|||
return BMAccount(address)
|
||||
|
||||
|
||||
class AccountColor(AccountMixin): # pylint: disable=too-few-public-methods
|
||||
class AccountColor(AccountMixin):
|
||||
"""Set the type of account"""
|
||||
|
||||
def __init__(self, address, address_type=None):
|
||||
|
@ -100,7 +101,9 @@ class AccountColor(AccountMixin): # pylint: disable=too-few-public-methods
|
|||
elif config.safeGetBoolean(self.address, 'chan'):
|
||||
self.type = AccountMixin.CHAN
|
||||
elif sqlQuery(
|
||||
'''select label from subscriptions where address=?''', self.address):
|
||||
'SELECT label FROM subscriptions WHERE address=?',
|
||||
dbstr(self.address)
|
||||
):
|
||||
self.type = AccountMixin.SUBSCRIPTION
|
||||
else:
|
||||
self.type = AccountMixin.NORMAL
|
||||
|
@ -108,12 +111,35 @@ class AccountColor(AccountMixin): # pylint: disable=too-few-public-methods
|
|||
self.type = address_type
|
||||
|
||||
|
||||
class BMAccount(object):
|
||||
"""Encapsulate a Bitmessage account"""
|
||||
|
||||
class NoAccount(object):
|
||||
"""Minimal account like object (All accounts)"""
|
||||
# pylint: disable=too-many-instance-attributes
|
||||
def __init__(self, address=None):
|
||||
self.address = address
|
||||
self.type = AccountMixin.NORMAL
|
||||
self.toAddress = self.fromAddress = ''
|
||||
self.subject = self.message = ''
|
||||
self.fromLabel = self.toLabel = ''
|
||||
|
||||
def getLabel(self, address=None):
|
||||
"""Get a label for this bitmessage account"""
|
||||
return address or self.address
|
||||
|
||||
def parseMessage(self, toAddress, fromAddress, subject, message):
|
||||
"""Set metadata and address labels on self"""
|
||||
self.toAddress = ustr(toAddress)
|
||||
self.fromAddress = ustr(fromAddress)
|
||||
self.subject = ustr(subject)
|
||||
self.message = ustr(message)
|
||||
self.fromLabel = ustr(self.getLabel(fromAddress))
|
||||
self.toLabel = ustr(self.getLabel(toAddress))
|
||||
|
||||
|
||||
class BMAccount(NoAccount):
|
||||
"""Encapsulate a Bitmessage account"""
|
||||
|
||||
def __init__(self, address=None):
|
||||
super(BMAccount, self).__init__(address)
|
||||
if config.has_section(address):
|
||||
if config.safeGetBoolean(self.address, 'chan'):
|
||||
self.type = AccountMixin.CHAN
|
||||
|
@ -121,55 +147,25 @@ class BMAccount(object):
|
|||
self.type = AccountMixin.MAILINGLIST
|
||||
elif self.address == str_broadcast_subscribers:
|
||||
self.type = AccountMixin.BROADCAST
|
||||
else:
|
||||
queryreturn = sqlQuery(
|
||||
'''select label from subscriptions where address=?''', self.address)
|
||||
if queryreturn:
|
||||
elif sqlQuery(
|
||||
'SELECT label FROM subscriptions WHERE address=?', dbstr(self.address)
|
||||
):
|
||||
self.type = AccountMixin.SUBSCRIPTION
|
||||
|
||||
def getLabel(self, address=None):
|
||||
"""Get a label for this bitmessage account"""
|
||||
if address is None:
|
||||
address = self.address
|
||||
address = super(BMAccount, self).getLabel(address)
|
||||
label = config.safeGet(address, 'label', address)
|
||||
queryreturn = sqlQuery(
|
||||
'''select label from addressbook where address=?''', address)
|
||||
if queryreturn != []:
|
||||
for row in queryreturn:
|
||||
label, = row
|
||||
'SELECT label FROM addressbook WHERE address=?', dbstr(address))
|
||||
if queryreturn:
|
||||
label = queryreturn[-1][0]
|
||||
else:
|
||||
queryreturn = sqlQuery(
|
||||
'''select label from subscriptions where address=?''', address)
|
||||
if queryreturn != []:
|
||||
for row in queryreturn:
|
||||
label, = row
|
||||
return label
|
||||
|
||||
def parseMessage(self, toAddress, fromAddress, subject, message):
|
||||
"""Set metadata and address labels on self"""
|
||||
|
||||
self.toAddress = toAddress
|
||||
self.fromAddress = fromAddress
|
||||
if isinstance(subject, unicode):
|
||||
self.subject = str(subject)
|
||||
else:
|
||||
self.subject = subject
|
||||
self.message = message
|
||||
self.fromLabel = self.getLabel(fromAddress)
|
||||
self.toLabel = self.getLabel(toAddress)
|
||||
|
||||
|
||||
class NoAccount(BMAccount):
|
||||
"""Override the __init__ method on a BMAccount"""
|
||||
|
||||
def __init__(self, address=None): # pylint: disable=super-init-not-called
|
||||
self.address = address
|
||||
self.type = AccountMixin.NORMAL
|
||||
|
||||
def getLabel(self, address=None):
|
||||
if address is None:
|
||||
address = self.address
|
||||
return address
|
||||
'SELECT label FROM subscriptions WHERE address=?', dbstr(address))
|
||||
if queryreturn:
|
||||
label = queryreturn[-1][0]
|
||||
return unic(ustr(label))
|
||||
|
||||
|
||||
class SubscriptionAccount(BMAccount):
|
||||
|
@ -189,31 +185,27 @@ class GatewayAccount(BMAccount):
|
|||
ALL_OK = 0
|
||||
REGISTRATION_DENIED = 1
|
||||
|
||||
def __init__(self, address):
|
||||
super(GatewayAccount, self).__init__(address)
|
||||
|
||||
def send(self):
|
||||
"""Override the send method for gateway accounts"""
|
||||
|
||||
# pylint: disable=unused-variable
|
||||
status, addressVersionNumber, streamNumber, ripe = decodeAddress(self.toAddress)
|
||||
stealthLevel = config.safeGetInt('bitmessagesettings', 'ackstealthlevel')
|
||||
"""The send method for gateway accounts"""
|
||||
streamNumber, ripe = decodeAddress(self.toAddress)[2:]
|
||||
stealthLevel = config.safeGetInt(
|
||||
'bitmessagesettings', 'ackstealthlevel')
|
||||
ackdata = genAckPayload(streamNumber, stealthLevel)
|
||||
sqlExecute(
|
||||
'''INSERT INTO sent VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)''',
|
||||
'',
|
||||
self.toAddress,
|
||||
ripe,
|
||||
self.fromAddress,
|
||||
self.subject,
|
||||
self.message,
|
||||
ackdata,
|
||||
sqlite3.Binary(b''),
|
||||
dbstr(self.toAddress),
|
||||
sqlite3.Binary(ripe),
|
||||
dbstr(self.fromAddress),
|
||||
dbstr(self.subject),
|
||||
dbstr(self.message),
|
||||
sqlite3.Binary(ackdata),
|
||||
int(time.time()), # sentTime (this will never change)
|
||||
int(time.time()), # lastActionTime
|
||||
0, # sleepTill time. This will get set when the POW gets done.
|
||||
'msgqueued',
|
||||
dbstr('msgqueued'),
|
||||
0, # retryNumber
|
||||
'sent', # folder
|
||||
dbstr('sent'), # folder
|
||||
2, # encodingtype
|
||||
# not necessary to have a TTL higher than 2 days
|
||||
min(config.getint('bitmessagesettings', 'ttl'), 86400 * 2)
|
||||
|
@ -270,10 +262,9 @@ class MailchuckAccount(GatewayAccount):
|
|||
|
||||
def settings(self):
|
||||
"""settings specific to a MailchuckAccount"""
|
||||
|
||||
self.toAddress = self.registrationAddress
|
||||
self.subject = "config"
|
||||
self.message = QtGui.QApplication.translate(
|
||||
self.message = _translate(
|
||||
"Mailchuck",
|
||||
"""# You can use this to configure your email gateway account
|
||||
# Uncomment the setting you want to use
|
||||
|
@ -319,8 +310,9 @@ class MailchuckAccount(GatewayAccount):
|
|||
|
||||
def parseMessage(self, toAddress, fromAddress, subject, message):
|
||||
"""parseMessage specific to a MailchuckAccount"""
|
||||
|
||||
super(MailchuckAccount, self).parseMessage(toAddress, fromAddress, subject, message)
|
||||
super(MailchuckAccount, self).parseMessage(
|
||||
toAddress, fromAddress, subject, message
|
||||
)
|
||||
if fromAddress == self.relayAddress:
|
||||
matches = self.regExpIncoming.search(subject)
|
||||
if matches is not None:
|
||||
|
@ -341,6 +333,7 @@ class MailchuckAccount(GatewayAccount):
|
|||
self.toLabel = matches.group(1)
|
||||
self.toAddress = matches.group(1)
|
||||
self.feedback = self.ALL_OK
|
||||
if fromAddress == self.registrationAddress and self.subject == "Registration Request Denied":
|
||||
if fromAddress == self.registrationAddress \
|
||||
and self.subject == "Registration Request Denied":
|
||||
self.feedback = self.REGISTRATION_DENIED
|
||||
return self.feedback
|
||||
|
|
|
@ -1,40 +1,40 @@
|
|||
"""
|
||||
Dialogs that work with BM address.
|
||||
"""
|
||||
# pylint: disable=attribute-defined-outside-init,too-few-public-methods,relative-import
|
||||
# pylint: disable=too-few-public-methods
|
||||
# https://github.com/PyCQA/pylint/issues/471
|
||||
|
||||
import hashlib
|
||||
|
||||
from PyQt4 import QtCore, QtGui
|
||||
from unqstr import ustr, unic
|
||||
from qtpy import QtGui, QtWidgets
|
||||
|
||||
import queues
|
||||
import widgets
|
||||
from bitmessageqt import widgets
|
||||
import state
|
||||
from account import AccountMixin, GatewayAccount, MailchuckAccount, accountClass
|
||||
from .account import (
|
||||
GatewayAccount, MailchuckAccount, AccountMixin, accountClass
|
||||
)
|
||||
from addresses import addBMIfNotPresent, decodeAddress, encodeVarint
|
||||
from bmconfigparser import config as global_config
|
||||
from tr import _translate
|
||||
|
||||
|
||||
class AddressCheckMixin(object):
|
||||
"""Base address validation class for QT UI"""
|
||||
"""Base address validation class for Qt UI"""
|
||||
|
||||
def __init__(self):
|
||||
def _setup(self):
|
||||
self.valid = False
|
||||
QtCore.QObject.connect( # pylint: disable=no-member
|
||||
self.lineEditAddress,
|
||||
QtCore.SIGNAL("textChanged(QString)"),
|
||||
self.addressChanged)
|
||||
self.lineEditAddress.textChanged.connect(self.addressChanged)
|
||||
|
||||
def _onSuccess(self, addressVersion, streamNumber, ripe):
|
||||
pass
|
||||
|
||||
def addressChanged(self, QString):
|
||||
def addressChanged(self, address):
|
||||
"""
|
||||
Address validation callback, performs validation and gives feedback
|
||||
"""
|
||||
status, addressVersion, streamNumber, ripe = decodeAddress(
|
||||
str(QString))
|
||||
status, addressVersion, streamNumber, ripe = decodeAddress(ustr(address))
|
||||
self.valid = status == 'success'
|
||||
if self.valid:
|
||||
self.labelAddressCheck.setText(
|
||||
|
@ -79,19 +79,27 @@ class AddressCheckMixin(object):
|
|||
))
|
||||
|
||||
|
||||
class AddressDataDialog(QtGui.QDialog, AddressCheckMixin):
|
||||
"""QDialog with Bitmessage address validation"""
|
||||
class AddressDataDialog(QtWidgets.QDialog, AddressCheckMixin):
|
||||
"""
|
||||
Base class for a dialog getting BM-address data.
|
||||
Corresponding ui-file should define two fields:
|
||||
lineEditAddress - for the address
|
||||
lineEditLabel - for it's label
|
||||
After address validation the values of that fields are put into
|
||||
the data field of the dialog.
|
||||
"""
|
||||
|
||||
def __init__(self, parent):
|
||||
super(AddressDataDialog, self).__init__(parent)
|
||||
self.parent = parent
|
||||
self.data = None
|
||||
|
||||
def accept(self):
|
||||
"""Callback for QDIalog accepting value"""
|
||||
"""Callback for QDialog accepting value"""
|
||||
if self.valid:
|
||||
self.data = (
|
||||
addBMIfNotPresent(str(self.lineEditAddress.text())),
|
||||
str(self.lineEditLabel.text().toUtf8())
|
||||
addBMIfNotPresent(ustr(self.lineEditAddress.text())),
|
||||
ustr(self.lineEditLabel.text())
|
||||
)
|
||||
else:
|
||||
queues.UISignalQueue.put(('updateStatusBar', _translate(
|
||||
|
@ -107,12 +115,12 @@ class AddAddressDialog(AddressDataDialog):
|
|||
def __init__(self, parent=None, address=None):
|
||||
super(AddAddressDialog, self).__init__(parent)
|
||||
widgets.load('addaddressdialog.ui', self)
|
||||
AddressCheckMixin.__init__(self)
|
||||
self._setup()
|
||||
if address:
|
||||
self.lineEditAddress.setText(address)
|
||||
|
||||
|
||||
class NewAddressDialog(QtGui.QDialog):
|
||||
class NewAddressDialog(QtWidgets.QDialog):
|
||||
"""QDialog for generating a new address"""
|
||||
|
||||
def __init__(self, parent=None):
|
||||
|
@ -125,7 +133,7 @@ class NewAddressDialog(QtGui.QDialog):
|
|||
self.radioButtonExisting.click()
|
||||
self.comboBoxExisting.addItem(address)
|
||||
self.groupBoxDeterministic.setHidden(True)
|
||||
QtGui.QWidget.resize(self, QtGui.QWidget.sizeHint(self))
|
||||
QtWidgets.QWidget.resize(self, QtWidgets.QWidget.sizeHint(self))
|
||||
self.show()
|
||||
|
||||
def accept(self):
|
||||
|
@ -142,13 +150,13 @@ class NewAddressDialog(QtGui.QDialog):
|
|||
self.comboBoxExisting.currentText())[2]
|
||||
queues.addressGeneratorQueue.put((
|
||||
'createRandomAddress', 4, streamNumberForAddress,
|
||||
str(self.newaddresslabel.text().toUtf8()), 1, "",
|
||||
ustr(self.newaddresslabel.text()), 1, "",
|
||||
self.checkBoxEighteenByteRipe.isChecked()
|
||||
))
|
||||
else:
|
||||
if self.lineEditPassphrase.text() != \
|
||||
self.lineEditPassphraseAgain.text():
|
||||
QtGui.QMessageBox.about(
|
||||
if ustr(self.lineEditPassphrase.text()) != \
|
||||
ustr(self.lineEditPassphraseAgain.text()):
|
||||
QtWidgets.QMessageBox.about(
|
||||
self, _translate("MainWindow", "Passphrase mismatch"),
|
||||
_translate(
|
||||
"MainWindow",
|
||||
|
@ -156,7 +164,7 @@ class NewAddressDialog(QtGui.QDialog):
|
|||
" match. Try again.")
|
||||
)
|
||||
elif self.lineEditPassphrase.text() == "":
|
||||
QtGui.QMessageBox.about(
|
||||
QtWidgets.QMessageBox.about(
|
||||
self, _translate("MainWindow", "Choose a passphrase"),
|
||||
_translate(
|
||||
"MainWindow", "You really do need a passphrase.")
|
||||
|
@ -169,7 +177,7 @@ class NewAddressDialog(QtGui.QDialog):
|
|||
'createDeterministicAddresses', 4, streamNumberForAddress,
|
||||
"unused deterministic address",
|
||||
self.spinBoxNumberOfAddressesToMake.value(),
|
||||
self.lineEditPassphrase.text().toUtf8(),
|
||||
ustr(self.lineEditPassphrase.text()),
|
||||
self.checkBoxEighteenByteRipe.isChecked()
|
||||
))
|
||||
|
||||
|
@ -180,7 +188,8 @@ class NewSubscriptionDialog(AddressDataDialog):
|
|||
def __init__(self, parent=None):
|
||||
super(NewSubscriptionDialog, self).__init__(parent)
|
||||
widgets.load('newsubscriptiondialog.ui', self)
|
||||
AddressCheckMixin.__init__(self)
|
||||
self.recent = []
|
||||
self._setup()
|
||||
|
||||
def _onSuccess(self, addressVersion, streamNumber, ripe):
|
||||
if addressVersion <= 3:
|
||||
|
@ -211,22 +220,21 @@ class NewSubscriptionDialog(AddressDataDialog):
|
|||
_translate(
|
||||
"MainWindow",
|
||||
"Display the %n recent broadcast(s) from this address.",
|
||||
None,
|
||||
QtCore.QCoreApplication.CodecForTr,
|
||||
count
|
||||
None, count
|
||||
))
|
||||
|
||||
|
||||
class RegenerateAddressesDialog(QtGui.QDialog):
|
||||
class RegenerateAddressesDialog(QtWidgets.QDialog):
|
||||
"""QDialog for regenerating deterministic addresses"""
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super(RegenerateAddressesDialog, self).__init__(parent)
|
||||
widgets.load('regenerateaddresses.ui', self)
|
||||
self.groupBox.setTitle('')
|
||||
QtGui.QWidget.resize(self, QtGui.QWidget.sizeHint(self))
|
||||
QtWidgets.QWidget.resize(self, QtWidgets.QWidget.sizeHint(self))
|
||||
|
||||
|
||||
class SpecialAddressBehaviorDialog(QtGui.QDialog):
|
||||
class SpecialAddressBehaviorDialog(QtWidgets.QDialog):
|
||||
"""
|
||||
QDialog for special address behaviour (e.g. mailing list functionality)
|
||||
"""
|
||||
|
@ -234,7 +242,7 @@ class SpecialAddressBehaviorDialog(QtGui.QDialog):
|
|||
def __init__(self, parent=None, config=global_config):
|
||||
super(SpecialAddressBehaviorDialog, self).__init__(parent)
|
||||
widgets.load('specialaddressbehavior.ui', self)
|
||||
self.address = parent.getCurrentAccount()
|
||||
self.address = ustr(parent.getCurrentAccount())
|
||||
self.parent = parent
|
||||
self.config = config
|
||||
|
||||
|
@ -257,12 +265,12 @@ class SpecialAddressBehaviorDialog(QtGui.QDialog):
|
|||
self.radioButtonBehaviorMailingList.click()
|
||||
else:
|
||||
self.radioButtonBehaveNormalAddress.click()
|
||||
mailingListName = config.safeGet(self.address, 'mailinglistname', '')
|
||||
mailingListName = config.safeGet(
|
||||
self.address, 'mailinglistname', '')
|
||||
self.lineEditMailingListName.setText(
|
||||
unicode(mailingListName, 'utf-8')
|
||||
)
|
||||
unic(ustr(mailingListName)))
|
||||
|
||||
QtGui.QWidget.resize(self, QtGui.QWidget.sizeHint(self))
|
||||
QtWidgets.QWidget.resize(self, QtWidgets.QWidget.sizeHint(self))
|
||||
self.show()
|
||||
|
||||
def accept(self):
|
||||
|
@ -271,18 +279,18 @@ class SpecialAddressBehaviorDialog(QtGui.QDialog):
|
|||
if self.address_is_chan:
|
||||
return
|
||||
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
|
||||
if self.config.getboolean(self.address, 'enabled'):
|
||||
self.parent.setCurrentItemColor(
|
||||
QtGui.QApplication.palette().text().color()
|
||||
QtWidgets.QApplication.palette().text().color()
|
||||
)
|
||||
else:
|
||||
self.parent.setCurrentItemColor(QtGui.QColor(128, 128, 128))
|
||||
else:
|
||||
self.config.set(str(self.address), 'mailinglist', 'true')
|
||||
self.config.set(str(self.address), 'mailinglistname', str(
|
||||
self.lineEditMailingListName.text().toUtf8()))
|
||||
self.config.set(self.address, 'mailinglist', 'true')
|
||||
self.config.set(self.address, 'mailinglistname', ustr(
|
||||
self.lineEditMailingListName.text()))
|
||||
self.parent.setCurrentItemColor(
|
||||
QtGui.QColor(137, 4, 177)) # magenta
|
||||
self.parent.rerenderComboBoxSendFrom()
|
||||
|
@ -291,13 +299,15 @@ class SpecialAddressBehaviorDialog(QtGui.QDialog):
|
|||
self.parent.rerenderMessagelistToLabels()
|
||||
|
||||
|
||||
class EmailGatewayDialog(QtGui.QDialog):
|
||||
class EmailGatewayDialog(QtWidgets.QDialog):
|
||||
"""QDialog for email gateway control"""
|
||||
|
||||
def __init__(self, parent, config=global_config, account=None):
|
||||
super(EmailGatewayDialog, self).__init__(parent)
|
||||
widgets.load('emailgateway.ui', self)
|
||||
self.parent = parent
|
||||
self.config = config
|
||||
self.data = None
|
||||
if account:
|
||||
self.acct = account
|
||||
self.setWindowTitle(_translate(
|
||||
|
@ -330,7 +340,7 @@ class EmailGatewayDialog(QtGui.QDialog):
|
|||
else:
|
||||
self.acct = MailchuckAccount(address)
|
||||
self.lineEditEmail.setFocus()
|
||||
QtGui.QWidget.resize(self, QtGui.QWidget.sizeHint(self))
|
||||
QtWidgets.QWidget.resize(self, QtWidgets.QWidget.sizeHint(self))
|
||||
|
||||
def accept(self):
|
||||
"""Accept callback"""
|
||||
|
@ -344,7 +354,7 @@ class EmailGatewayDialog(QtGui.QDialog):
|
|||
|
||||
if self.radioButtonRegister.isChecked() \
|
||||
or self.radioButtonRegister.isHidden():
|
||||
email = str(self.lineEditEmail.text().toUtf8())
|
||||
email = ustr(self.lineEditEmail.text())
|
||||
self.acct.register(email)
|
||||
self.config.set(self.acct.fromAddress, 'label', email)
|
||||
self.config.set(self.acct.fromAddress, 'gateway', 'mailchuck')
|
||||
|
|
|
@ -1,38 +1,36 @@
|
|||
"""
|
||||
Address validator module.
|
||||
The validator for address and passphrase QLineEdits
|
||||
used in `.dialogs.NewChanDialog`.
|
||||
"""
|
||||
# pylint: disable=too-many-branches,too-many-arguments
|
||||
# pylint: disable=too-many-arguments
|
||||
|
||||
from Queue import Empty
|
||||
from six.moves.queue import Empty
|
||||
|
||||
from PyQt4 import QtGui
|
||||
from unqstr import ustr
|
||||
from qtpy import QtGui
|
||||
|
||||
from addresses import decodeAddress, addBMIfNotPresent
|
||||
from bmconfigparser import config
|
||||
from queues import apiAddressGeneratorReturnQueue, addressGeneratorQueue
|
||||
from tr import _translate
|
||||
from utils import str_chan
|
||||
from .utils import str_chan
|
||||
|
||||
|
||||
class AddressPassPhraseValidatorMixin(object):
|
||||
"""Bitmessage address or passphrase validator class for Qt UI"""
|
||||
def setParams(
|
||||
self,
|
||||
passPhraseObject=None,
|
||||
addressObject=None,
|
||||
feedBackObject=None,
|
||||
buttonBox=None,
|
||||
addressMandatory=True,
|
||||
self, passPhraseObject=None, addressObject=None,
|
||||
feedBackObject=None, button=None, addressMandatory=True
|
||||
):
|
||||
"""Initialisation"""
|
||||
"""Initialization"""
|
||||
self.addressObject = addressObject
|
||||
self.passPhraseObject = passPhraseObject
|
||||
self.feedBackObject = feedBackObject
|
||||
self.buttonBox = buttonBox
|
||||
self.addressMandatory = addressMandatory
|
||||
self.isValid = False
|
||||
# save default text
|
||||
self.okButtonLabel = self.buttonBox.button(QtGui.QDialogButtonBox.Ok).text()
|
||||
self.okButton = button
|
||||
self.okButtonLabel = button.text()
|
||||
|
||||
def setError(self, string):
|
||||
"""Indicate that the validation is pending or failed"""
|
||||
|
@ -43,13 +41,13 @@ class AddressPassPhraseValidatorMixin(object):
|
|||
self.feedBackObject.setStyleSheet("QLabel { color : red; }")
|
||||
self.feedBackObject.setText(string)
|
||||
self.isValid = False
|
||||
if self.buttonBox:
|
||||
self.buttonBox.button(QtGui.QDialogButtonBox.Ok).setEnabled(False)
|
||||
if self.okButton:
|
||||
self.okButton.setEnabled(False)
|
||||
if string is not None and self.feedBackObject is not None:
|
||||
self.buttonBox.button(QtGui.QDialogButtonBox.Ok).setText(
|
||||
self.okButton.setText(
|
||||
_translate("AddressValidator", "Invalid"))
|
||||
else:
|
||||
self.buttonBox.button(QtGui.QDialogButtonBox.Ok).setText(
|
||||
self.okButton.setText(
|
||||
_translate("AddressValidator", "Validating..."))
|
||||
|
||||
def setOK(self, string):
|
||||
|
@ -61,9 +59,9 @@ class AddressPassPhraseValidatorMixin(object):
|
|||
self.feedBackObject.setStyleSheet("QLabel { }")
|
||||
self.feedBackObject.setText(string)
|
||||
self.isValid = True
|
||||
if self.buttonBox:
|
||||
self.buttonBox.button(QtGui.QDialogButtonBox.Ok).setEnabled(True)
|
||||
self.buttonBox.button(QtGui.QDialogButtonBox.Ok).setText(self.okButtonLabel)
|
||||
if self.okButton:
|
||||
self.okButton.setEnabled(True)
|
||||
self.okButton.setText(self.okButtonLabel)
|
||||
|
||||
def checkQueue(self):
|
||||
"""Validator queue loop"""
|
||||
|
@ -76,7 +74,8 @@ class AddressPassPhraseValidatorMixin(object):
|
|||
|
||||
while True:
|
||||
try:
|
||||
addressGeneratorReturnValue = apiAddressGeneratorReturnQueue.get(False)
|
||||
addressGeneratorReturnValue = \
|
||||
apiAddressGeneratorReturnQueue.get(False)
|
||||
except Empty:
|
||||
if gotOne:
|
||||
break
|
||||
|
@ -86,96 +85,120 @@ class AddressPassPhraseValidatorMixin(object):
|
|||
gotOne = True
|
||||
|
||||
if not addressGeneratorReturnValue:
|
||||
self.setError(_translate("AddressValidator", "Address already present as one of your identities."))
|
||||
return (QtGui.QValidator.Intermediate, 0)
|
||||
if addressGeneratorReturnValue[0] == 'chan name does not match address':
|
||||
self.setError(
|
||||
_translate(
|
||||
self.setError(_translate(
|
||||
"AddressValidator",
|
||||
"Although the Bitmessage address you "
|
||||
"entered was valid, it doesn't match the chan name."))
|
||||
return (QtGui.QValidator.Intermediate, 0)
|
||||
self.setOK(_translate("MainWindow", "Passphrase and address appear to be valid."))
|
||||
"Address already present as one of your identities."
|
||||
))
|
||||
return
|
||||
if addressGeneratorReturnValue[0] == \
|
||||
'chan name does not match address':
|
||||
self.setError(_translate(
|
||||
"AddressValidator",
|
||||
"Although the Bitmessage address you entered was valid,"
|
||||
" it doesn\'t match the chan name."
|
||||
))
|
||||
return
|
||||
self.setOK(_translate(
|
||||
"MainWindow", "Passphrase and address appear to be valid."))
|
||||
|
||||
def returnValid(self):
|
||||
"""Return the value of whether the validation was successful"""
|
||||
if self.isValid:
|
||||
return QtGui.QValidator.Acceptable
|
||||
return QtGui.QValidator.Intermediate
|
||||
return QtGui.QValidator.Acceptable if self.isValid \
|
||||
else QtGui.QValidator.Intermediate
|
||||
|
||||
def validate(self, s, pos):
|
||||
"""Top level validator method"""
|
||||
if self.addressObject is None:
|
||||
try:
|
||||
address = ustr(self.addressObject.text())
|
||||
except AttributeError:
|
||||
address = None
|
||||
else:
|
||||
address = str(self.addressObject.text().toUtf8())
|
||||
if address == "":
|
||||
address = None
|
||||
if self.passPhraseObject is None:
|
||||
try:
|
||||
passPhrase = ustr(self.passPhraseObject.text())
|
||||
except AttributeError:
|
||||
passPhrase = ""
|
||||
else:
|
||||
passPhrase = str(self.passPhraseObject.text().toUtf8())
|
||||
if passPhrase == "":
|
||||
passPhrase = None
|
||||
|
||||
# no chan name
|
||||
if passPhrase is None:
|
||||
self.setError(_translate("AddressValidator", "Chan name/passphrase needed. You didn't enter a chan name."))
|
||||
return (QtGui.QValidator.Intermediate, pos)
|
||||
|
||||
if self.addressMandatory or address is not None:
|
||||
# check if address already exists:
|
||||
if address in config.addresses():
|
||||
self.setError(_translate("AddressValidator", "Address already present as one of your identities."))
|
||||
return (QtGui.QValidator.Intermediate, pos)
|
||||
|
||||
# version too high
|
||||
if decodeAddress(address)[0] == 'versiontoohigh':
|
||||
self.setError(
|
||||
_translate(
|
||||
if not passPhrase:
|
||||
self.setError(_translate(
|
||||
"AddressValidator",
|
||||
"Address too new. Although that Bitmessage"
|
||||
" address might be valid, its version number"
|
||||
" is too new for us to handle. Perhaps you need"
|
||||
" to upgrade Bitmessage."))
|
||||
return (QtGui.QValidator.Intermediate, pos)
|
||||
"Chan name/passphrase needed. You didn't enter a chan name."
|
||||
))
|
||||
return (QtGui.QValidator.Intermediate, s, pos)
|
||||
|
||||
if self.addressMandatory or address:
|
||||
# check if address already exists:
|
||||
if address in config.addresses(True):
|
||||
self.setError(_translate(
|
||||
"AddressValidator",
|
||||
"Address already present as one of your identities."
|
||||
))
|
||||
return (QtGui.QValidator.Intermediate, s, pos)
|
||||
|
||||
status = decodeAddress(address)[0]
|
||||
# version too high
|
||||
if status == 'versiontoohigh':
|
||||
self.setError(_translate(
|
||||
"AddressValidator",
|
||||
"Address too new. Although that Bitmessage address"
|
||||
" might be valid, its version number is too new"
|
||||
" for us to handle. Perhaps you need to upgrade"
|
||||
" Bitmessage."
|
||||
))
|
||||
return (QtGui.QValidator.Intermediate, s, pos)
|
||||
# invalid
|
||||
if decodeAddress(address)[0] != 'success':
|
||||
self.setError(_translate("AddressValidator", "The Bitmessage address is not valid."))
|
||||
return (QtGui.QValidator.Intermediate, pos)
|
||||
if status != 'success':
|
||||
self.setError(_translate(
|
||||
"AddressValidator",
|
||||
"The Bitmessage address is not valid."
|
||||
))
|
||||
return (QtGui.QValidator.Intermediate, s, pos)
|
||||
|
||||
# this just disables the OK button without changing the feedback text
|
||||
# but only if triggered by textEdited, not by clicking the Ok button
|
||||
if not self.buttonBox.button(QtGui.QDialogButtonBox.Ok).hasFocus():
|
||||
if not self.okButton.hasFocus():
|
||||
self.setError(None)
|
||||
|
||||
# check through generator
|
||||
if address is None:
|
||||
addressGeneratorQueue.put(('createChan', 4, 1, str_chan + ' ' + str(passPhrase), passPhrase, False))
|
||||
if not address:
|
||||
addressGeneratorQueue.put((
|
||||
'createChan', 4, 1,
|
||||
str_chan + ' ' + passPhrase, passPhrase.encode("utf-8", "replace"), False
|
||||
))
|
||||
else:
|
||||
addressGeneratorQueue.put(
|
||||
('joinChan', addBMIfNotPresent(address),
|
||||
"{} {}".format(str_chan, passPhrase), passPhrase, False))
|
||||
addressGeneratorQueue.put((
|
||||
'joinChan', addBMIfNotPresent(address),
|
||||
"{} {}".format(str_chan, passPhrase), passPhrase.encode("utf-8", "replace"), False
|
||||
))
|
||||
|
||||
if self.buttonBox.button(QtGui.QDialogButtonBox.Ok).hasFocus():
|
||||
return (self.returnValid(), pos)
|
||||
return (QtGui.QValidator.Intermediate, pos)
|
||||
if self.okButton.hasFocus():
|
||||
return (self.returnValid(), s, pos)
|
||||
else:
|
||||
return (QtGui.QValidator.Intermediate, s, pos)
|
||||
|
||||
def checkData(self):
|
||||
"""Validator Qt signal interface"""
|
||||
return self.validate("", 0)
|
||||
return self.validate(u"", 0)
|
||||
|
||||
|
||||
class AddressValidator(QtGui.QValidator, AddressPassPhraseValidatorMixin):
|
||||
"""AddressValidator class for Qt UI"""
|
||||
def __init__(self, parent=None, passPhraseObject=None, feedBackObject=None, buttonBox=None, addressMandatory=True):
|
||||
def __init__(
|
||||
self, parent=None, passPhraseObject=None, feedBackObject=None,
|
||||
button=None, addressMandatory=True
|
||||
):
|
||||
super(AddressValidator, self).__init__(parent)
|
||||
self.setParams(passPhraseObject, parent, feedBackObject, buttonBox, addressMandatory)
|
||||
self.setParams(
|
||||
passPhraseObject, parent, feedBackObject, button,
|
||||
addressMandatory)
|
||||
|
||||
|
||||
class PassPhraseValidator(QtGui.QValidator, AddressPassPhraseValidatorMixin):
|
||||
"""PassPhraseValidator class for Qt UI"""
|
||||
def __init__(self, parent=None, addressObject=None, feedBackObject=None, buttonBox=None, addressMandatory=False):
|
||||
def __init__(
|
||||
self, parent=None, addressObject=None, feedBackObject=None,
|
||||
button=None, addressMandatory=False
|
||||
):
|
||||
super(PassPhraseValidator, self).__init__(parent)
|
||||
self.setParams(parent, addressObject, feedBackObject, buttonBox, addressMandatory)
|
||||
self.setParams(
|
||||
parent, addressObject, feedBackObject, button,
|
||||
addressMandatory)
|
||||
|
|
|
@ -7,9 +7,9 @@
|
|||
#
|
||||
# WARNING! All changes made in this file will be lost!
|
||||
|
||||
from PyQt4 import QtCore
|
||||
from qtpy import QtCore
|
||||
|
||||
qt_resource_data = "\
|
||||
qt_resource_data = b"\
|
||||
\x00\x00\x03\x66\
|
||||
\x89\
|
||||
\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
|
||||
|
@ -1534,7 +1534,7 @@ qt_resource_data = "\
|
|||
\x82\
|
||||
"
|
||||
|
||||
qt_resource_name = "\
|
||||
qt_resource_name = b"\
|
||||
\x00\x09\
|
||||
\x0c\x78\x54\x88\
|
||||
\x00\x6e\
|
||||
|
@ -1639,7 +1639,7 @@ qt_resource_name = "\
|
|||
\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\x02\
|
||||
\x00\x00\x00\x18\x00\x02\x00\x00\x00\x15\x00\x00\x00\x03\
|
||||
|
@ -1666,10 +1666,15 @@ qt_resource_struct = "\
|
|||
\x00\x00\x01\xe6\x00\x00\x00\x00\x00\x01\x00\x00\x34\xdf\
|
||||
"
|
||||
|
||||
|
||||
def qInitResources():
|
||||
QtCore.qRegisterResourceData(0x01, qt_resource_struct, qt_resource_name, qt_resource_data)
|
||||
QtCore.qRegisterResourceData(
|
||||
0x01, qt_resource_struct, qt_resource_name, qt_resource_data)
|
||||
|
||||
|
||||
def qCleanupResources():
|
||||
QtCore.qUnregisterResourceData(0x01, qt_resource_struct, qt_resource_name, qt_resource_data)
|
||||
QtCore.qUnregisterResourceData(
|
||||
0x01, qt_resource_struct, qt_resource_name, qt_resource_data)
|
||||
|
||||
|
||||
qInitResources()
|
||||
|
|
|
@ -1,59 +1,32 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# pylint: skip-file
|
||||
# flake8: noqa
|
||||
|
||||
# Form implementation generated from reading ui file 'bitmessageui.ui'
|
||||
#
|
||||
# Created: Mon Mar 23 22:18:07 2015
|
||||
# by: PyQt4 UI code generator 4.10.4
|
||||
#
|
||||
# WARNING! All changes made in this file will be lost!
|
||||
|
||||
from PyQt4 import QtCore, QtGui
|
||||
from qtpy import QtCore, QtGui, QtWidgets
|
||||
from tr import _translate
|
||||
from bmconfigparser import config
|
||||
from foldertree import AddressBookCompleter
|
||||
from messageview import MessageView
|
||||
from messagecompose import MessageCompose
|
||||
import settingsmixin
|
||||
from networkstatus import NetworkStatus
|
||||
from blacklist import Blacklist
|
||||
|
||||
try:
|
||||
_fromUtf8 = QtCore.QString.fromUtf8
|
||||
except AttributeError:
|
||||
def _fromUtf8(s):
|
||||
return s
|
||||
|
||||
try:
|
||||
_encoding = QtGui.QApplication.UnicodeUTF8
|
||||
|
||||
def _translate(context, text, disambig, encoding=QtCore.QCoreApplication.CodecForTr, n=None):
|
||||
if n is None:
|
||||
return QtGui.QApplication.translate(context, text, disambig, _encoding)
|
||||
else:
|
||||
return QtGui.QApplication.translate(context, text, disambig, _encoding, n)
|
||||
except AttributeError:
|
||||
def _translate(context, text, disambig, encoding=QtCore.QCoreApplication.CodecForTr, n=None):
|
||||
if n is None:
|
||||
return QtGui.QApplication.translate(context, text, disambig)
|
||||
else:
|
||||
return QtGui.QApplication.translate(context, text, disambig, QtCore.QCoreApplication.CodecForTr, n)
|
||||
from .foldertree import AddressBookCompleter
|
||||
from .messageview import MessageView
|
||||
from .messagecompose import MessageCompose
|
||||
from bitmessageqt import settingsmixin
|
||||
from .networkstatus import NetworkStatus
|
||||
from .blacklist import Blacklist
|
||||
from bitmessageqt import bitmessage_icons_rc
|
||||
|
||||
|
||||
class Ui_MainWindow(object):
|
||||
def setupUi(self, MainWindow):
|
||||
MainWindow.setObjectName(_fromUtf8("MainWindow"))
|
||||
MainWindow.setObjectName("MainWindow")
|
||||
MainWindow.resize(885, 580)
|
||||
icon = QtGui.QIcon()
|
||||
icon.addPixmap(
|
||||
QtGui.QPixmap(_fromUtf8(":/newPrefix/images/can-icon-24px.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off
|
||||
)
|
||||
icon.addPixmap(QtGui.QPixmap(":/newPrefix/images/can-icon-24px.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
||||
MainWindow.setWindowIcon(icon)
|
||||
MainWindow.setTabShape(QtGui.QTabWidget.Rounded)
|
||||
self.centralwidget = QtGui.QWidget(MainWindow)
|
||||
self.centralwidget.setObjectName(_fromUtf8("centralwidget"))
|
||||
self.gridLayout_10 = QtGui.QGridLayout(self.centralwidget)
|
||||
self.gridLayout_10.setObjectName(_fromUtf8("gridLayout_10"))
|
||||
self.tabWidget = QtGui.QTabWidget(self.centralwidget)
|
||||
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding)
|
||||
MainWindow.setTabShape(QtWidgets.QTabWidget.Rounded)
|
||||
self.centralwidget = QtWidgets.QWidget(MainWindow)
|
||||
self.centralwidget.setObjectName("centralwidget")
|
||||
self.gridLayout_10 = QtWidgets.QGridLayout(self.centralwidget)
|
||||
self.gridLayout_10.setObjectName("gridLayout_10")
|
||||
self.tabWidget = QtWidgets.QTabWidget(self.centralwidget)
|
||||
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
sizePolicy.setVerticalStretch(0)
|
||||
sizePolicy.setHeightForWidth(self.tabWidget.sizePolicy().hasHeightForWidth())
|
||||
|
@ -61,32 +34,30 @@ class Ui_MainWindow(object):
|
|||
self.tabWidget.setMinimumSize(QtCore.QSize(0, 0))
|
||||
self.tabWidget.setBaseSize(QtCore.QSize(0, 0))
|
||||
font = QtGui.QFont()
|
||||
base_size = QtGui.QApplication.instance().font().pointSize()
|
||||
base_size = QtWidgets.QApplication.instance().font().pointSize()
|
||||
font.setPointSize(int(base_size * 0.75))
|
||||
self.tabWidget.setFont(font)
|
||||
self.tabWidget.setTabPosition(QtGui.QTabWidget.North)
|
||||
self.tabWidget.setTabShape(QtGui.QTabWidget.Rounded)
|
||||
self.tabWidget.setObjectName(_fromUtf8("tabWidget"))
|
||||
self.inbox = QtGui.QWidget()
|
||||
self.inbox.setObjectName(_fromUtf8("inbox"))
|
||||
self.gridLayout = QtGui.QGridLayout(self.inbox)
|
||||
self.gridLayout.setObjectName(_fromUtf8("gridLayout"))
|
||||
self.tabWidget.setTabPosition(QtWidgets.QTabWidget.North)
|
||||
self.tabWidget.setTabShape(QtWidgets.QTabWidget.Rounded)
|
||||
self.tabWidget.setObjectName("tabWidget")
|
||||
self.inbox = QtWidgets.QWidget()
|
||||
self.inbox.setObjectName("inbox")
|
||||
self.gridLayout = QtWidgets.QGridLayout(self.inbox)
|
||||
self.gridLayout.setObjectName("gridLayout")
|
||||
self.horizontalSplitter_3 = settingsmixin.SSplitter()
|
||||
self.horizontalSplitter_3.setObjectName(_fromUtf8("horizontalSplitter_3"))
|
||||
self.horizontalSplitter_3.setObjectName("horizontalSplitter_3")
|
||||
self.verticalSplitter_12 = settingsmixin.SSplitter()
|
||||
self.verticalSplitter_12.setObjectName(_fromUtf8("verticalSplitter_12"))
|
||||
self.verticalSplitter_12.setObjectName("verticalSplitter_12")
|
||||
self.verticalSplitter_12.setOrientation(QtCore.Qt.Vertical)
|
||||
self.treeWidgetYourIdentities = settingsmixin.STreeWidget(self.inbox)
|
||||
self.treeWidgetYourIdentities.setObjectName(_fromUtf8("treeWidgetYourIdentities"))
|
||||
self.treeWidgetYourIdentities.setObjectName("treeWidgetYourIdentities")
|
||||
self.treeWidgetYourIdentities.resize(200, self.treeWidgetYourIdentities.height())
|
||||
icon1 = QtGui.QIcon()
|
||||
icon1.addPixmap(
|
||||
QtGui.QPixmap(_fromUtf8(":/newPrefix/images/identities.png")), QtGui.QIcon.Selected, QtGui.QIcon.Off
|
||||
)
|
||||
icon1.addPixmap(QtGui.QPixmap(":/newPrefix/images/identities.png"), QtGui.QIcon.Selected, QtGui.QIcon.Off)
|
||||
self.treeWidgetYourIdentities.headerItem().setIcon(0, icon1)
|
||||
self.verticalSplitter_12.addWidget(self.treeWidgetYourIdentities)
|
||||
self.pushButtonNewAddress = QtGui.QPushButton(self.inbox)
|
||||
self.pushButtonNewAddress.setObjectName(_fromUtf8("pushButtonNewAddress"))
|
||||
self.pushButtonNewAddress = QtWidgets.QPushButton(self.inbox)
|
||||
self.pushButtonNewAddress.setObjectName("pushButtonNewAddress")
|
||||
self.pushButtonNewAddress.resize(200, self.pushButtonNewAddress.height())
|
||||
self.verticalSplitter_12.addWidget(self.pushButtonNewAddress)
|
||||
self.verticalSplitter_12.setStretchFactor(0, 1)
|
||||
|
@ -96,21 +67,21 @@ class Ui_MainWindow(object):
|
|||
self.verticalSplitter_12.handle(1).setEnabled(False)
|
||||
self.horizontalSplitter_3.addWidget(self.verticalSplitter_12)
|
||||
self.verticalSplitter_7 = settingsmixin.SSplitter()
|
||||
self.verticalSplitter_7.setObjectName(_fromUtf8("verticalSplitter_7"))
|
||||
self.verticalSplitter_7.setObjectName("verticalSplitter_7")
|
||||
self.verticalSplitter_7.setOrientation(QtCore.Qt.Vertical)
|
||||
self.horizontalSplitterSearch = QtGui.QSplitter()
|
||||
self.horizontalSplitterSearch.setObjectName(_fromUtf8("horizontalSplitterSearch"))
|
||||
self.inboxSearchLineEdit = QtGui.QLineEdit(self.inbox)
|
||||
self.inboxSearchLineEdit.setObjectName(_fromUtf8("inboxSearchLineEdit"))
|
||||
self.horizontalSplitterSearch = QtWidgets.QSplitter()
|
||||
self.horizontalSplitterSearch.setObjectName("horizontalSplitterSearch")
|
||||
self.inboxSearchLineEdit = QtWidgets.QLineEdit(self.inbox)
|
||||
self.inboxSearchLineEdit.setObjectName("inboxSearchLineEdit")
|
||||
self.horizontalSplitterSearch.addWidget(self.inboxSearchLineEdit)
|
||||
self.inboxSearchOption = QtGui.QComboBox(self.inbox)
|
||||
self.inboxSearchOption.setObjectName(_fromUtf8("inboxSearchOption"))
|
||||
self.inboxSearchOption.addItem(_fromUtf8(""))
|
||||
self.inboxSearchOption.addItem(_fromUtf8(""))
|
||||
self.inboxSearchOption.addItem(_fromUtf8(""))
|
||||
self.inboxSearchOption.addItem(_fromUtf8(""))
|
||||
self.inboxSearchOption.addItem(_fromUtf8(""))
|
||||
self.inboxSearchOption.setSizeAdjustPolicy(QtGui.QComboBox.AdjustToContents)
|
||||
self.inboxSearchOption = QtWidgets.QComboBox(self.inbox)
|
||||
self.inboxSearchOption.setObjectName("inboxSearchOption")
|
||||
self.inboxSearchOption.addItem("")
|
||||
self.inboxSearchOption.addItem("")
|
||||
self.inboxSearchOption.addItem("")
|
||||
self.inboxSearchOption.addItem("")
|
||||
self.inboxSearchOption.addItem("")
|
||||
self.inboxSearchOption.setSizeAdjustPolicy(QtWidgets.QComboBox.AdjustToContents)
|
||||
self.inboxSearchOption.setCurrentIndex(3)
|
||||
self.horizontalSplitterSearch.addWidget(self.inboxSearchOption)
|
||||
self.horizontalSplitterSearch.handle(1).setEnabled(False)
|
||||
|
@ -118,21 +89,21 @@ class Ui_MainWindow(object):
|
|||
self.horizontalSplitterSearch.setStretchFactor(1, 0)
|
||||
self.verticalSplitter_7.addWidget(self.horizontalSplitterSearch)
|
||||
self.tableWidgetInbox = settingsmixin.STableWidget(self.inbox)
|
||||
self.tableWidgetInbox.setEditTriggers(QtGui.QAbstractItemView.NoEditTriggers)
|
||||
self.tableWidgetInbox.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers)
|
||||
self.tableWidgetInbox.setAlternatingRowColors(True)
|
||||
self.tableWidgetInbox.setSelectionMode(QtGui.QAbstractItemView.ExtendedSelection)
|
||||
self.tableWidgetInbox.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows)
|
||||
self.tableWidgetInbox.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection)
|
||||
self.tableWidgetInbox.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
|
||||
self.tableWidgetInbox.setWordWrap(False)
|
||||
self.tableWidgetInbox.setObjectName(_fromUtf8("tableWidgetInbox"))
|
||||
self.tableWidgetInbox.setObjectName("tableWidgetInbox")
|
||||
self.tableWidgetInbox.setColumnCount(4)
|
||||
self.tableWidgetInbox.setRowCount(0)
|
||||
item = QtGui.QTableWidgetItem()
|
||||
item = QtWidgets.QTableWidgetItem()
|
||||
self.tableWidgetInbox.setHorizontalHeaderItem(0, item)
|
||||
item = QtGui.QTableWidgetItem()
|
||||
item = QtWidgets.QTableWidgetItem()
|
||||
self.tableWidgetInbox.setHorizontalHeaderItem(1, item)
|
||||
item = QtGui.QTableWidgetItem()
|
||||
item = QtWidgets.QTableWidgetItem()
|
||||
self.tableWidgetInbox.setHorizontalHeaderItem(2, item)
|
||||
item = QtGui.QTableWidgetItem()
|
||||
item = QtWidgets.QTableWidgetItem()
|
||||
self.tableWidgetInbox.setHorizontalHeaderItem(3, item)
|
||||
self.tableWidgetInbox.horizontalHeader().setCascadingSectionResizes(True)
|
||||
self.tableWidgetInbox.horizontalHeader().setDefaultSectionSize(200)
|
||||
|
@ -146,7 +117,7 @@ class Ui_MainWindow(object):
|
|||
self.textEditInboxMessage = MessageView(self.inbox)
|
||||
self.textEditInboxMessage.setBaseSize(QtCore.QSize(0, 500))
|
||||
self.textEditInboxMessage.setReadOnly(True)
|
||||
self.textEditInboxMessage.setObjectName(_fromUtf8("textEditInboxMessage"))
|
||||
self.textEditInboxMessage.setObjectName("textEditInboxMessage")
|
||||
self.verticalSplitter_7.addWidget(self.textEditInboxMessage)
|
||||
self.verticalSplitter_7.setStretchFactor(0, 0)
|
||||
self.verticalSplitter_7.setStretchFactor(1, 1)
|
||||
|
@ -162,52 +133,51 @@ class Ui_MainWindow(object):
|
|||
self.horizontalSplitter_3.setCollapsible(1, False)
|
||||
self.gridLayout.addWidget(self.horizontalSplitter_3)
|
||||
icon2 = QtGui.QIcon()
|
||||
icon2.addPixmap(QtGui.QPixmap(_fromUtf8(":/newPrefix/images/inbox.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
||||
self.tabWidget.addTab(self.inbox, icon2, _fromUtf8(""))
|
||||
self.send = QtGui.QWidget()
|
||||
self.send.setObjectName(_fromUtf8("send"))
|
||||
self.gridLayout_7 = QtGui.QGridLayout(self.send)
|
||||
self.gridLayout_7.setObjectName(_fromUtf8("gridLayout_7"))
|
||||
icon2.addPixmap(QtGui.QPixmap(":/newPrefix/images/inbox.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
||||
self.tabWidget.addTab(self.inbox, icon2, "")
|
||||
self.send = QtWidgets.QWidget()
|
||||
self.send.setObjectName("send")
|
||||
self.gridLayout_7 = QtWidgets.QGridLayout(self.send)
|
||||
self.gridLayout_7.setObjectName("gridLayout_7")
|
||||
self.horizontalSplitter = settingsmixin.SSplitter()
|
||||
self.horizontalSplitter.setObjectName(_fromUtf8("horizontalSplitter"))
|
||||
self.horizontalSplitter.setObjectName("horizontalSplitter")
|
||||
self.verticalSplitter_2 = settingsmixin.SSplitter()
|
||||
self.verticalSplitter_2.setObjectName(_fromUtf8("verticalSplitter_2"))
|
||||
self.verticalSplitter_2.setObjectName("verticalSplitter_2")
|
||||
self.verticalSplitter_2.setOrientation(QtCore.Qt.Vertical)
|
||||
self.tableWidgetAddressBook = settingsmixin.STableWidget(self.send)
|
||||
self.tableWidgetAddressBook.setAlternatingRowColors(True)
|
||||
self.tableWidgetAddressBook.setSelectionMode(QtGui.QAbstractItemView.ExtendedSelection)
|
||||
self.tableWidgetAddressBook.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows)
|
||||
self.tableWidgetAddressBook.setObjectName(_fromUtf8("tableWidgetAddressBook"))
|
||||
self.tableWidgetAddressBook.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection)
|
||||
self.tableWidgetAddressBook.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
|
||||
self.tableWidgetAddressBook.setObjectName("tableWidgetAddressBook")
|
||||
self.tableWidgetAddressBook.setColumnCount(2)
|
||||
self.tableWidgetAddressBook.setRowCount(0)
|
||||
self.tableWidgetAddressBook.resize(200, self.tableWidgetAddressBook.height())
|
||||
item = QtGui.QTableWidgetItem()
|
||||
item = QtWidgets.QTableWidgetItem()
|
||||
icon3 = QtGui.QIcon()
|
||||
icon3.addPixmap(
|
||||
QtGui.QPixmap(_fromUtf8(":/newPrefix/images/addressbook.png")), QtGui.QIcon.Selected, QtGui.QIcon.Off
|
||||
)
|
||||
icon3.addPixmap(QtGui.QPixmap(":/newPrefix/images/addressbook.png"), QtGui.QIcon.Selected, QtGui.QIcon.Off)
|
||||
item.setIcon(icon3)
|
||||
self.tableWidgetAddressBook.setHorizontalHeaderItem(0, item)
|
||||
item = QtGui.QTableWidgetItem()
|
||||
item = QtWidgets.QTableWidgetItem()
|
||||
self.tableWidgetAddressBook.setHorizontalHeaderItem(1, item)
|
||||
self.tableWidgetAddressBook.horizontalHeader().setCascadingSectionResizes(True)
|
||||
self.tableWidgetAddressBook.horizontalHeader().setDefaultSectionSize(200)
|
||||
self.tableWidgetAddressBook.horizontalHeader().setHighlightSections(False)
|
||||
self.tableWidgetAddressBook.horizontalHeader().setStretchLastSection(True)
|
||||
self.tableWidgetAddressBook.verticalHeader().setVisible(False)
|
||||
self.tableWidgetAddressBook.setWordWrap(False)
|
||||
self.verticalSplitter_2.addWidget(self.tableWidgetAddressBook)
|
||||
self.addressBookCompleter = AddressBookCompleter()
|
||||
self.addressBookCompleter.setCompletionMode(QtGui.QCompleter.PopupCompletion)
|
||||
self.addressBookCompleter.setCompletionMode(QtWidgets.QCompleter.PopupCompletion)
|
||||
self.addressBookCompleter.setCaseSensitivity(QtCore.Qt.CaseInsensitive)
|
||||
self.addressBookCompleterModel = QtGui.QStringListModel()
|
||||
self.addressBookCompleterModel = QtCore.QStringListModel()
|
||||
self.addressBookCompleter.setModel(self.addressBookCompleterModel)
|
||||
self.pushButtonAddAddressBook = QtGui.QPushButton(self.send)
|
||||
self.pushButtonAddAddressBook.setObjectName(_fromUtf8("pushButtonAddAddressBook"))
|
||||
self.pushButtonAddAddressBook = QtWidgets.QPushButton(self.send)
|
||||
self.pushButtonAddAddressBook.setObjectName("pushButtonAddAddressBook")
|
||||
self.pushButtonAddAddressBook.resize(200, self.pushButtonAddAddressBook.height())
|
||||
self.verticalSplitter_2.addWidget(self.pushButtonAddAddressBook)
|
||||
self.pushButtonFetchNamecoinID = QtGui.QPushButton(self.send)
|
||||
self.pushButtonFetchNamecoinID = QtWidgets.QPushButton(self.send)
|
||||
self.pushButtonFetchNamecoinID.resize(200, self.pushButtonFetchNamecoinID.height())
|
||||
self.pushButtonFetchNamecoinID.setObjectName(_fromUtf8("pushButtonFetchNamecoinID"))
|
||||
self.pushButtonFetchNamecoinID.setObjectName("pushButtonFetchNamecoinID")
|
||||
self.verticalSplitter_2.addWidget(self.pushButtonFetchNamecoinID)
|
||||
self.verticalSplitter_2.setStretchFactor(0, 1)
|
||||
self.verticalSplitter_2.setStretchFactor(1, 0)
|
||||
|
@ -219,45 +189,45 @@ class Ui_MainWindow(object):
|
|||
self.verticalSplitter_2.handle(2).setEnabled(False)
|
||||
self.horizontalSplitter.addWidget(self.verticalSplitter_2)
|
||||
self.verticalSplitter = settingsmixin.SSplitter()
|
||||
self.verticalSplitter.setObjectName(_fromUtf8("verticalSplitter"))
|
||||
self.verticalSplitter.setObjectName("verticalSplitter")
|
||||
self.verticalSplitter.setOrientation(QtCore.Qt.Vertical)
|
||||
self.tabWidgetSend = QtGui.QTabWidget(self.send)
|
||||
self.tabWidgetSend.setObjectName(_fromUtf8("tabWidgetSend"))
|
||||
self.sendDirect = QtGui.QWidget()
|
||||
self.sendDirect.setObjectName(_fromUtf8("sendDirect"))
|
||||
self.gridLayout_8 = QtGui.QGridLayout(self.sendDirect)
|
||||
self.gridLayout_8.setObjectName(_fromUtf8("gridLayout_8"))
|
||||
self.tabWidgetSend = QtWidgets.QTabWidget(self.send)
|
||||
self.tabWidgetSend.setObjectName("tabWidgetSend")
|
||||
self.sendDirect = QtWidgets.QWidget()
|
||||
self.sendDirect.setObjectName("sendDirect")
|
||||
self.gridLayout_8 = QtWidgets.QGridLayout(self.sendDirect)
|
||||
self.gridLayout_8.setObjectName("gridLayout_8")
|
||||
self.verticalSplitter_5 = settingsmixin.SSplitter()
|
||||
self.verticalSplitter_5.setObjectName(_fromUtf8("verticalSplitter_5"))
|
||||
self.verticalSplitter_5.setObjectName("verticalSplitter_5")
|
||||
self.verticalSplitter_5.setOrientation(QtCore.Qt.Vertical)
|
||||
self.gridLayout_2 = QtGui.QGridLayout()
|
||||
self.gridLayout_2.setObjectName(_fromUtf8("gridLayout_2"))
|
||||
self.label_3 = QtGui.QLabel(self.sendDirect)
|
||||
self.label_3.setObjectName(_fromUtf8("label_3"))
|
||||
self.gridLayout_2 = QtWidgets.QGridLayout()
|
||||
self.gridLayout_2.setObjectName("gridLayout_2")
|
||||
self.label_3 = QtWidgets.QLabel(self.sendDirect)
|
||||
self.label_3.setObjectName("label_3")
|
||||
self.gridLayout_2.addWidget(self.label_3, 2, 0, 1, 1)
|
||||
self.label_2 = QtGui.QLabel(self.sendDirect)
|
||||
self.label_2.setObjectName(_fromUtf8("label_2"))
|
||||
self.label_2 = QtWidgets.QLabel(self.sendDirect)
|
||||
self.label_2.setObjectName("label_2")
|
||||
self.gridLayout_2.addWidget(self.label_2, 0, 0, 1, 1)
|
||||
self.lineEditSubject = QtGui.QLineEdit(self.sendDirect)
|
||||
self.lineEditSubject.setText(_fromUtf8(""))
|
||||
self.lineEditSubject.setObjectName(_fromUtf8("lineEditSubject"))
|
||||
self.lineEditSubject = QtWidgets.QLineEdit(self.sendDirect)
|
||||
self.lineEditSubject.setText("")
|
||||
self.lineEditSubject.setObjectName("lineEditSubject")
|
||||
self.gridLayout_2.addWidget(self.lineEditSubject, 2, 1, 1, 1)
|
||||
self.label = QtGui.QLabel(self.sendDirect)
|
||||
self.label.setObjectName(_fromUtf8("label"))
|
||||
self.label = QtWidgets.QLabel(self.sendDirect)
|
||||
self.label.setObjectName("label")
|
||||
self.gridLayout_2.addWidget(self.label, 1, 0, 1, 1)
|
||||
self.comboBoxSendFrom = QtGui.QComboBox(self.sendDirect)
|
||||
self.comboBoxSendFrom = QtWidgets.QComboBox(self.sendDirect)
|
||||
self.comboBoxSendFrom.setMinimumSize(QtCore.QSize(300, 0))
|
||||
self.comboBoxSendFrom.setObjectName(_fromUtf8("comboBoxSendFrom"))
|
||||
self.comboBoxSendFrom.setObjectName("comboBoxSendFrom")
|
||||
self.gridLayout_2.addWidget(self.comboBoxSendFrom, 0, 1, 1, 1)
|
||||
self.lineEditTo = QtGui.QLineEdit(self.sendDirect)
|
||||
self.lineEditTo.setObjectName(_fromUtf8("lineEditTo"))
|
||||
self.lineEditTo = QtWidgets.QLineEdit(self.sendDirect)
|
||||
self.lineEditTo.setObjectName("lineEditTo")
|
||||
self.gridLayout_2.addWidget(self.lineEditTo, 1, 1, 1, 1)
|
||||
self.lineEditTo.setCompleter(self.addressBookCompleter)
|
||||
self.gridLayout_2_Widget = QtGui.QWidget()
|
||||
self.gridLayout_2_Widget = QtWidgets.QWidget()
|
||||
self.gridLayout_2_Widget.setLayout(self.gridLayout_2)
|
||||
self.verticalSplitter_5.addWidget(self.gridLayout_2_Widget)
|
||||
self.textEditMessage = MessageCompose(self.sendDirect)
|
||||
self.textEditMessage.setObjectName(_fromUtf8("textEditMessage"))
|
||||
self.textEditMessage.setObjectName("textEditMessage")
|
||||
self.verticalSplitter_5.addWidget(self.textEditMessage)
|
||||
self.verticalSplitter_5.setStretchFactor(0, 0)
|
||||
self.verticalSplitter_5.setStretchFactor(1, 1)
|
||||
|
@ -265,35 +235,35 @@ class Ui_MainWindow(object):
|
|||
self.verticalSplitter_5.setCollapsible(1, False)
|
||||
self.verticalSplitter_5.handle(1).setEnabled(False)
|
||||
self.gridLayout_8.addWidget(self.verticalSplitter_5, 0, 0, 1, 1)
|
||||
self.tabWidgetSend.addTab(self.sendDirect, _fromUtf8(""))
|
||||
self.sendBroadcast = QtGui.QWidget()
|
||||
self.sendBroadcast.setObjectName(_fromUtf8("sendBroadcast"))
|
||||
self.gridLayout_9 = QtGui.QGridLayout(self.sendBroadcast)
|
||||
self.gridLayout_9.setObjectName(_fromUtf8("gridLayout_9"))
|
||||
self.tabWidgetSend.addTab(self.sendDirect, "")
|
||||
self.sendBroadcast = QtWidgets.QWidget()
|
||||
self.sendBroadcast.setObjectName("sendBroadcast")
|
||||
self.gridLayout_9 = QtWidgets.QGridLayout(self.sendBroadcast)
|
||||
self.gridLayout_9.setObjectName("gridLayout_9")
|
||||
self.verticalSplitter_6 = settingsmixin.SSplitter()
|
||||
self.verticalSplitter_6.setObjectName(_fromUtf8("verticalSplitter_6"))
|
||||
self.verticalSplitter_6.setObjectName("verticalSplitter_6")
|
||||
self.verticalSplitter_6.setOrientation(QtCore.Qt.Vertical)
|
||||
self.gridLayout_5 = QtGui.QGridLayout()
|
||||
self.gridLayout_5.setObjectName(_fromUtf8("gridLayout_5"))
|
||||
self.label_8 = QtGui.QLabel(self.sendBroadcast)
|
||||
self.label_8.setObjectName(_fromUtf8("label_8"))
|
||||
self.gridLayout_5 = QtWidgets.QGridLayout()
|
||||
self.gridLayout_5.setObjectName("gridLayout_5")
|
||||
self.label_8 = QtWidgets.QLabel(self.sendBroadcast)
|
||||
self.label_8.setObjectName("label_8")
|
||||
self.gridLayout_5.addWidget(self.label_8, 0, 0, 1, 1)
|
||||
self.lineEditSubjectBroadcast = QtGui.QLineEdit(self.sendBroadcast)
|
||||
self.lineEditSubjectBroadcast.setText(_fromUtf8(""))
|
||||
self.lineEditSubjectBroadcast.setObjectName(_fromUtf8("lineEditSubjectBroadcast"))
|
||||
self.lineEditSubjectBroadcast = QtWidgets.QLineEdit(self.sendBroadcast)
|
||||
self.lineEditSubjectBroadcast.setText("")
|
||||
self.lineEditSubjectBroadcast.setObjectName("lineEditSubjectBroadcast")
|
||||
self.gridLayout_5.addWidget(self.lineEditSubjectBroadcast, 1, 1, 1, 1)
|
||||
self.label_7 = QtGui.QLabel(self.sendBroadcast)
|
||||
self.label_7.setObjectName(_fromUtf8("label_7"))
|
||||
self.label_7 = QtWidgets.QLabel(self.sendBroadcast)
|
||||
self.label_7.setObjectName("label_7")
|
||||
self.gridLayout_5.addWidget(self.label_7, 1, 0, 1, 1)
|
||||
self.comboBoxSendFromBroadcast = QtGui.QComboBox(self.sendBroadcast)
|
||||
self.comboBoxSendFromBroadcast = QtWidgets.QComboBox(self.sendBroadcast)
|
||||
self.comboBoxSendFromBroadcast.setMinimumSize(QtCore.QSize(300, 0))
|
||||
self.comboBoxSendFromBroadcast.setObjectName(_fromUtf8("comboBoxSendFromBroadcast"))
|
||||
self.comboBoxSendFromBroadcast.setObjectName("comboBoxSendFromBroadcast")
|
||||
self.gridLayout_5.addWidget(self.comboBoxSendFromBroadcast, 0, 1, 1, 1)
|
||||
self.gridLayout_5_Widget = QtGui.QWidget()
|
||||
self.gridLayout_5_Widget = QtWidgets.QWidget()
|
||||
self.gridLayout_5_Widget.setLayout(self.gridLayout_5)
|
||||
self.verticalSplitter_6.addWidget(self.gridLayout_5_Widget)
|
||||
self.textEditMessageBroadcast = MessageCompose(self.sendBroadcast)
|
||||
self.textEditMessageBroadcast.setObjectName(_fromUtf8("textEditMessageBroadcast"))
|
||||
self.textEditMessageBroadcast.setObjectName("textEditMessageBroadcast")
|
||||
self.verticalSplitter_6.addWidget(self.textEditMessageBroadcast)
|
||||
self.verticalSplitter_6.setStretchFactor(0, 0)
|
||||
self.verticalSplitter_6.setStretchFactor(1, 1)
|
||||
|
@ -301,15 +271,15 @@ class Ui_MainWindow(object):
|
|||
self.verticalSplitter_6.setCollapsible(1, False)
|
||||
self.verticalSplitter_6.handle(1).setEnabled(False)
|
||||
self.gridLayout_9.addWidget(self.verticalSplitter_6, 0, 0, 1, 1)
|
||||
self.tabWidgetSend.addTab(self.sendBroadcast, _fromUtf8(""))
|
||||
self.tabWidgetSend.addTab(self.sendBroadcast, "")
|
||||
self.verticalSplitter.addWidget(self.tabWidgetSend)
|
||||
self.tTLContainer = QtGui.QWidget()
|
||||
self.tTLContainer.setSizePolicy(QtGui.QSizePolicy.MinimumExpanding, QtGui.QSizePolicy.Fixed)
|
||||
self.horizontalLayout_5 = QtGui.QHBoxLayout()
|
||||
self.tTLContainer = QtWidgets.QWidget()
|
||||
self.tTLContainer.setSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Fixed)
|
||||
self.horizontalLayout_5 = QtWidgets.QHBoxLayout()
|
||||
self.tTLContainer.setLayout(self.horizontalLayout_5)
|
||||
self.horizontalLayout_5.setObjectName(_fromUtf8("horizontalLayout_5"))
|
||||
self.pushButtonTTL = QtGui.QPushButton(self.send)
|
||||
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.MinimumExpanding, QtGui.QSizePolicy.Fixed)
|
||||
self.horizontalLayout_5.setObjectName("horizontalLayout_5")
|
||||
self.pushButtonTTL = QtWidgets.QPushButton(self.send)
|
||||
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Fixed)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
sizePolicy.setVerticalStretch(0)
|
||||
sizePolicy.setHeightForWidth(self.pushButtonTTL.sizePolicy().hasHeightForWidth())
|
||||
|
@ -329,29 +299,29 @@ class Ui_MainWindow(object):
|
|||
font.setUnderline(True)
|
||||
self.pushButtonTTL.setFont(font)
|
||||
self.pushButtonTTL.setFlat(True)
|
||||
self.pushButtonTTL.setObjectName(_fromUtf8("pushButtonTTL"))
|
||||
self.pushButtonTTL.setObjectName("pushButtonTTL")
|
||||
self.horizontalLayout_5.addWidget(self.pushButtonTTL, 0, QtCore.Qt.AlignRight)
|
||||
self.horizontalSliderTTL = QtGui.QSlider(self.send)
|
||||
self.horizontalSliderTTL = QtWidgets.QSlider(self.send)
|
||||
self.horizontalSliderTTL.setMinimumSize(QtCore.QSize(70, 0))
|
||||
self.horizontalSliderTTL.setOrientation(QtCore.Qt.Horizontal)
|
||||
self.horizontalSliderTTL.setInvertedAppearance(False)
|
||||
self.horizontalSliderTTL.setInvertedControls(False)
|
||||
self.horizontalSliderTTL.setObjectName(_fromUtf8("horizontalSliderTTL"))
|
||||
self.horizontalSliderTTL.setObjectName("horizontalSliderTTL")
|
||||
self.horizontalLayout_5.addWidget(self.horizontalSliderTTL, 0, QtCore.Qt.AlignLeft)
|
||||
self.labelHumanFriendlyTTLDescription = QtGui.QLabel(self.send)
|
||||
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.MinimumExpanding, QtGui.QSizePolicy.Fixed)
|
||||
self.labelHumanFriendlyTTLDescription = QtWidgets.QLabel(self.send)
|
||||
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Fixed)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
sizePolicy.setVerticalStretch(0)
|
||||
sizePolicy.setHeightForWidth(self.labelHumanFriendlyTTLDescription.sizePolicy().hasHeightForWidth())
|
||||
self.labelHumanFriendlyTTLDescription.setSizePolicy(sizePolicy)
|
||||
self.labelHumanFriendlyTTLDescription.setMinimumSize(QtCore.QSize(45, 0))
|
||||
self.labelHumanFriendlyTTLDescription.setObjectName(_fromUtf8("labelHumanFriendlyTTLDescription"))
|
||||
self.labelHumanFriendlyTTLDescription.setObjectName("labelHumanFriendlyTTLDescription")
|
||||
self.horizontalLayout_5.addWidget(self.labelHumanFriendlyTTLDescription, 1, QtCore.Qt.AlignLeft)
|
||||
self.pushButtonClear = QtGui.QPushButton(self.send)
|
||||
self.pushButtonClear.setObjectName(_fromUtf8("pushButtonClear"))
|
||||
self.pushButtonClear = QtWidgets.QPushButton(self.send)
|
||||
self.pushButtonClear.setObjectName("pushButtonClear")
|
||||
self.horizontalLayout_5.addWidget(self.pushButtonClear, 0, QtCore.Qt.AlignRight)
|
||||
self.pushButtonSend = QtGui.QPushButton(self.send)
|
||||
self.pushButtonSend.setObjectName(_fromUtf8("pushButtonSend"))
|
||||
self.pushButtonSend = QtWidgets.QPushButton(self.send)
|
||||
self.pushButtonSend.setObjectName("pushButtonSend")
|
||||
self.horizontalLayout_5.addWidget(self.pushButtonSend, 0, QtCore.Qt.AlignRight)
|
||||
self.horizontalSliderTTL.setMaximumSize(QtCore.QSize(105, self.pushButtonSend.height()))
|
||||
self.verticalSplitter.addWidget(self.tTLContainer)
|
||||
|
@ -368,31 +338,29 @@ class Ui_MainWindow(object):
|
|||
self.horizontalSplitter.setCollapsible(1, False)
|
||||
self.gridLayout_7.addWidget(self.horizontalSplitter, 0, 0, 1, 1)
|
||||
icon4 = QtGui.QIcon()
|
||||
icon4.addPixmap(QtGui.QPixmap(_fromUtf8(":/newPrefix/images/send.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
||||
self.tabWidget.addTab(self.send, icon4, _fromUtf8(""))
|
||||
self.subscriptions = QtGui.QWidget()
|
||||
self.subscriptions.setObjectName(_fromUtf8("subscriptions"))
|
||||
self.gridLayout_3 = QtGui.QGridLayout(self.subscriptions)
|
||||
self.gridLayout_3.setObjectName(_fromUtf8("gridLayout_3"))
|
||||
icon4.addPixmap(QtGui.QPixmap(":/newPrefix/images/send.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
||||
self.tabWidget.addTab(self.send, icon4, "")
|
||||
self.subscriptions = QtWidgets.QWidget()
|
||||
self.subscriptions.setObjectName("subscriptions")
|
||||
self.gridLayout_3 = QtWidgets.QGridLayout(self.subscriptions)
|
||||
self.gridLayout_3.setObjectName("gridLayout_3")
|
||||
self.horizontalSplitter_4 = settingsmixin.SSplitter()
|
||||
self.horizontalSplitter_4.setObjectName(_fromUtf8("horizontalSplitter_4"))
|
||||
self.horizontalSplitter_4.setObjectName("horizontalSplitter_4")
|
||||
self.verticalSplitter_3 = settingsmixin.SSplitter()
|
||||
self.verticalSplitter_3.setObjectName(_fromUtf8("verticalSplitter_3"))
|
||||
self.verticalSplitter_3.setObjectName("verticalSplitter_3")
|
||||
self.verticalSplitter_3.setOrientation(QtCore.Qt.Vertical)
|
||||
self.treeWidgetSubscriptions = settingsmixin.STreeWidget(self.subscriptions)
|
||||
self.treeWidgetSubscriptions.setAlternatingRowColors(True)
|
||||
self.treeWidgetSubscriptions.setSelectionMode(QtGui.QAbstractItemView.SingleSelection)
|
||||
self.treeWidgetSubscriptions.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows)
|
||||
self.treeWidgetSubscriptions.setObjectName(_fromUtf8("treeWidgetSubscriptions"))
|
||||
self.treeWidgetSubscriptions.setSelectionMode(QtWidgets.QAbstractItemView.SingleSelection)
|
||||
self.treeWidgetSubscriptions.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
|
||||
self.treeWidgetSubscriptions.setObjectName("treeWidgetSubscriptions")
|
||||
self.treeWidgetSubscriptions.resize(200, self.treeWidgetSubscriptions.height())
|
||||
icon5 = QtGui.QIcon()
|
||||
icon5.addPixmap(
|
||||
QtGui.QPixmap(_fromUtf8(":/newPrefix/images/subscriptions.png")), QtGui.QIcon.Selected, QtGui.QIcon.Off
|
||||
)
|
||||
icon5.addPixmap(QtGui.QPixmap(":/newPrefix/images/subscriptions.png"), QtGui.QIcon.Selected, QtGui.QIcon.Off)
|
||||
self.treeWidgetSubscriptions.headerItem().setIcon(0, icon5)
|
||||
self.verticalSplitter_3.addWidget(self.treeWidgetSubscriptions)
|
||||
self.pushButtonAddSubscription = QtGui.QPushButton(self.subscriptions)
|
||||
self.pushButtonAddSubscription.setObjectName(_fromUtf8("pushButtonAddSubscription"))
|
||||
self.pushButtonAddSubscription = QtWidgets.QPushButton(self.subscriptions)
|
||||
self.pushButtonAddSubscription.setObjectName("pushButtonAddSubscription")
|
||||
self.pushButtonAddSubscription.resize(200, self.pushButtonAddSubscription.height())
|
||||
self.verticalSplitter_3.addWidget(self.pushButtonAddSubscription)
|
||||
self.verticalSplitter_3.setStretchFactor(0, 1)
|
||||
|
@ -402,20 +370,20 @@ class Ui_MainWindow(object):
|
|||
self.verticalSplitter_3.handle(1).setEnabled(False)
|
||||
self.horizontalSplitter_4.addWidget(self.verticalSplitter_3)
|
||||
self.verticalSplitter_4 = settingsmixin.SSplitter()
|
||||
self.verticalSplitter_4.setObjectName(_fromUtf8("verticalSplitter_4"))
|
||||
self.verticalSplitter_4.setObjectName("verticalSplitter_4")
|
||||
self.verticalSplitter_4.setOrientation(QtCore.Qt.Vertical)
|
||||
self.horizontalSplitter_2 = QtGui.QSplitter()
|
||||
self.horizontalSplitter_2.setObjectName(_fromUtf8("horizontalSplitter_2"))
|
||||
self.inboxSearchLineEditSubscriptions = QtGui.QLineEdit(self.subscriptions)
|
||||
self.inboxSearchLineEditSubscriptions.setObjectName(_fromUtf8("inboxSearchLineEditSubscriptions"))
|
||||
self.horizontalSplitter_2 = QtWidgets.QSplitter()
|
||||
self.horizontalSplitter_2.setObjectName("horizontalSplitter_2")
|
||||
self.inboxSearchLineEditSubscriptions = QtWidgets.QLineEdit(self.subscriptions)
|
||||
self.inboxSearchLineEditSubscriptions.setObjectName("inboxSearchLineEditSubscriptions")
|
||||
self.horizontalSplitter_2.addWidget(self.inboxSearchLineEditSubscriptions)
|
||||
self.inboxSearchOptionSubscriptions = QtGui.QComboBox(self.subscriptions)
|
||||
self.inboxSearchOptionSubscriptions.setObjectName(_fromUtf8("inboxSearchOptionSubscriptions"))
|
||||
self.inboxSearchOptionSubscriptions.addItem(_fromUtf8(""))
|
||||
self.inboxSearchOptionSubscriptions.addItem(_fromUtf8(""))
|
||||
self.inboxSearchOptionSubscriptions.addItem(_fromUtf8(""))
|
||||
self.inboxSearchOptionSubscriptions.addItem(_fromUtf8(""))
|
||||
self.inboxSearchOptionSubscriptions.setSizeAdjustPolicy(QtGui.QComboBox.AdjustToContents)
|
||||
self.inboxSearchOptionSubscriptions = QtWidgets.QComboBox(self.subscriptions)
|
||||
self.inboxSearchOptionSubscriptions.setObjectName("inboxSearchOptionSubscriptions")
|
||||
self.inboxSearchOptionSubscriptions.addItem("")
|
||||
self.inboxSearchOptionSubscriptions.addItem("")
|
||||
self.inboxSearchOptionSubscriptions.addItem("")
|
||||
self.inboxSearchOptionSubscriptions.addItem("")
|
||||
self.inboxSearchOptionSubscriptions.setSizeAdjustPolicy(QtWidgets.QComboBox.AdjustToContents)
|
||||
self.inboxSearchOptionSubscriptions.setCurrentIndex(2)
|
||||
self.horizontalSplitter_2.addWidget(self.inboxSearchOptionSubscriptions)
|
||||
self.horizontalSplitter_2.handle(1).setEnabled(False)
|
||||
|
@ -423,21 +391,21 @@ class Ui_MainWindow(object):
|
|||
self.horizontalSplitter_2.setStretchFactor(1, 0)
|
||||
self.verticalSplitter_4.addWidget(self.horizontalSplitter_2)
|
||||
self.tableWidgetInboxSubscriptions = settingsmixin.STableWidget(self.subscriptions)
|
||||
self.tableWidgetInboxSubscriptions.setEditTriggers(QtGui.QAbstractItemView.NoEditTriggers)
|
||||
self.tableWidgetInboxSubscriptions.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers)
|
||||
self.tableWidgetInboxSubscriptions.setAlternatingRowColors(True)
|
||||
self.tableWidgetInboxSubscriptions.setSelectionMode(QtGui.QAbstractItemView.ExtendedSelection)
|
||||
self.tableWidgetInboxSubscriptions.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows)
|
||||
self.tableWidgetInboxSubscriptions.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection)
|
||||
self.tableWidgetInboxSubscriptions.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
|
||||
self.tableWidgetInboxSubscriptions.setWordWrap(False)
|
||||
self.tableWidgetInboxSubscriptions.setObjectName(_fromUtf8("tableWidgetInboxSubscriptions"))
|
||||
self.tableWidgetInboxSubscriptions.setObjectName("tableWidgetInboxSubscriptions")
|
||||
self.tableWidgetInboxSubscriptions.setColumnCount(4)
|
||||
self.tableWidgetInboxSubscriptions.setRowCount(0)
|
||||
item = QtGui.QTableWidgetItem()
|
||||
item = QtWidgets.QTableWidgetItem()
|
||||
self.tableWidgetInboxSubscriptions.setHorizontalHeaderItem(0, item)
|
||||
item = QtGui.QTableWidgetItem()
|
||||
item = QtWidgets.QTableWidgetItem()
|
||||
self.tableWidgetInboxSubscriptions.setHorizontalHeaderItem(1, item)
|
||||
item = QtGui.QTableWidgetItem()
|
||||
item = QtWidgets.QTableWidgetItem()
|
||||
self.tableWidgetInboxSubscriptions.setHorizontalHeaderItem(2, item)
|
||||
item = QtGui.QTableWidgetItem()
|
||||
item = QtWidgets.QTableWidgetItem()
|
||||
self.tableWidgetInboxSubscriptions.setHorizontalHeaderItem(3, item)
|
||||
self.tableWidgetInboxSubscriptions.horizontalHeader().setCascadingSectionResizes(True)
|
||||
self.tableWidgetInboxSubscriptions.horizontalHeader().setDefaultSectionSize(200)
|
||||
|
@ -451,7 +419,7 @@ class Ui_MainWindow(object):
|
|||
self.textEditInboxMessageSubscriptions = MessageView(self.subscriptions)
|
||||
self.textEditInboxMessageSubscriptions.setBaseSize(QtCore.QSize(0, 500))
|
||||
self.textEditInboxMessageSubscriptions.setReadOnly(True)
|
||||
self.textEditInboxMessageSubscriptions.setObjectName(_fromUtf8("textEditInboxMessageSubscriptions"))
|
||||
self.textEditInboxMessageSubscriptions.setObjectName("textEditInboxMessageSubscriptions")
|
||||
self.verticalSplitter_4.addWidget(self.textEditInboxMessageSubscriptions)
|
||||
self.verticalSplitter_4.setStretchFactor(0, 0)
|
||||
self.verticalSplitter_4.setStretchFactor(1, 1)
|
||||
|
@ -467,35 +435,31 @@ class Ui_MainWindow(object):
|
|||
self.horizontalSplitter_4.setCollapsible(1, False)
|
||||
self.gridLayout_3.addWidget(self.horizontalSplitter_4, 0, 0, 1, 1)
|
||||
icon6 = QtGui.QIcon()
|
||||
icon6.addPixmap(
|
||||
QtGui.QPixmap(_fromUtf8(":/newPrefix/images/subscriptions.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off
|
||||
)
|
||||
self.tabWidget.addTab(self.subscriptions, icon6, _fromUtf8(""))
|
||||
self.chans = QtGui.QWidget()
|
||||
self.chans.setObjectName(_fromUtf8("chans"))
|
||||
self.gridLayout_4 = QtGui.QGridLayout(self.chans)
|
||||
self.gridLayout_4.setObjectName(_fromUtf8("gridLayout_4"))
|
||||
icon6.addPixmap(QtGui.QPixmap(":/newPrefix/images/subscriptions.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
||||
self.tabWidget.addTab(self.subscriptions, icon6, "")
|
||||
self.chans = QtWidgets.QWidget()
|
||||
self.chans.setObjectName("chans")
|
||||
self.gridLayout_4 = QtWidgets.QGridLayout(self.chans)
|
||||
self.gridLayout_4.setObjectName("gridLayout_4")
|
||||
self.horizontalSplitter_7 = settingsmixin.SSplitter()
|
||||
self.horizontalSplitter_7.setObjectName(_fromUtf8("horizontalSplitter_7"))
|
||||
self.horizontalSplitter_7.setObjectName("horizontalSplitter_7")
|
||||
self.verticalSplitter_17 = settingsmixin.SSplitter()
|
||||
self.verticalSplitter_17.setObjectName(_fromUtf8("verticalSplitter_17"))
|
||||
self.verticalSplitter_17.setObjectName("verticalSplitter_17")
|
||||
self.verticalSplitter_17.setOrientation(QtCore.Qt.Vertical)
|
||||
self.treeWidgetChans = settingsmixin.STreeWidget(self.chans)
|
||||
self.treeWidgetChans.setFrameShadow(QtGui.QFrame.Sunken)
|
||||
self.treeWidgetChans.setFrameShadow(QtWidgets.QFrame.Sunken)
|
||||
self.treeWidgetChans.setLineWidth(1)
|
||||
self.treeWidgetChans.setAlternatingRowColors(True)
|
||||
self.treeWidgetChans.setSelectionMode(QtGui.QAbstractItemView.SingleSelection)
|
||||
self.treeWidgetChans.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows)
|
||||
self.treeWidgetChans.setObjectName(_fromUtf8("treeWidgetChans"))
|
||||
self.treeWidgetChans.setSelectionMode(QtWidgets.QAbstractItemView.SingleSelection)
|
||||
self.treeWidgetChans.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
|
||||
self.treeWidgetChans.setObjectName("treeWidgetChans")
|
||||
self.treeWidgetChans.resize(200, self.treeWidgetChans.height())
|
||||
icon7 = QtGui.QIcon()
|
||||
icon7.addPixmap(
|
||||
QtGui.QPixmap(_fromUtf8(":/newPrefix/images/can-icon-16px.png")), QtGui.QIcon.Selected, QtGui.QIcon.Off
|
||||
)
|
||||
icon7.addPixmap(QtGui.QPixmap(":/newPrefix/images/can-icon-16px.png"), QtGui.QIcon.Selected, QtGui.QIcon.Off)
|
||||
self.treeWidgetChans.headerItem().setIcon(0, icon7)
|
||||
self.verticalSplitter_17.addWidget(self.treeWidgetChans)
|
||||
self.pushButtonAddChan = QtGui.QPushButton(self.chans)
|
||||
self.pushButtonAddChan.setObjectName(_fromUtf8("pushButtonAddChan"))
|
||||
self.pushButtonAddChan = QtWidgets.QPushButton(self.chans)
|
||||
self.pushButtonAddChan.setObjectName("pushButtonAddChan")
|
||||
self.pushButtonAddChan.resize(200, self.pushButtonAddChan.height())
|
||||
self.verticalSplitter_17.addWidget(self.pushButtonAddChan)
|
||||
self.verticalSplitter_17.setStretchFactor(0, 1)
|
||||
|
@ -505,21 +469,21 @@ class Ui_MainWindow(object):
|
|||
self.verticalSplitter_17.handle(1).setEnabled(False)
|
||||
self.horizontalSplitter_7.addWidget(self.verticalSplitter_17)
|
||||
self.verticalSplitter_8 = settingsmixin.SSplitter()
|
||||
self.verticalSplitter_8.setObjectName(_fromUtf8("verticalSplitter_8"))
|
||||
self.verticalSplitter_8.setObjectName("verticalSplitter_8")
|
||||
self.verticalSplitter_8.setOrientation(QtCore.Qt.Vertical)
|
||||
self.horizontalSplitter_6 = QtGui.QSplitter()
|
||||
self.horizontalSplitter_6.setObjectName(_fromUtf8("horizontalSplitter_6"))
|
||||
self.inboxSearchLineEditChans = QtGui.QLineEdit(self.chans)
|
||||
self.inboxSearchLineEditChans.setObjectName(_fromUtf8("inboxSearchLineEditChans"))
|
||||
self.horizontalSplitter_6 = QtWidgets.QSplitter()
|
||||
self.horizontalSplitter_6.setObjectName("horizontalSplitter_6")
|
||||
self.inboxSearchLineEditChans = QtWidgets.QLineEdit(self.chans)
|
||||
self.inboxSearchLineEditChans.setObjectName("inboxSearchLineEditChans")
|
||||
self.horizontalSplitter_6.addWidget(self.inboxSearchLineEditChans)
|
||||
self.inboxSearchOptionChans = QtGui.QComboBox(self.chans)
|
||||
self.inboxSearchOptionChans.setObjectName(_fromUtf8("inboxSearchOptionChans"))
|
||||
self.inboxSearchOptionChans.addItem(_fromUtf8(""))
|
||||
self.inboxSearchOptionChans.addItem(_fromUtf8(""))
|
||||
self.inboxSearchOptionChans.addItem(_fromUtf8(""))
|
||||
self.inboxSearchOptionChans.addItem(_fromUtf8(""))
|
||||
self.inboxSearchOptionChans.addItem(_fromUtf8(""))
|
||||
self.inboxSearchOptionChans.setSizeAdjustPolicy(QtGui.QComboBox.AdjustToContents)
|
||||
self.inboxSearchOptionChans = QtWidgets.QComboBox(self.chans)
|
||||
self.inboxSearchOptionChans.setObjectName("inboxSearchOptionChans")
|
||||
self.inboxSearchOptionChans.addItem("")
|
||||
self.inboxSearchOptionChans.addItem("")
|
||||
self.inboxSearchOptionChans.addItem("")
|
||||
self.inboxSearchOptionChans.addItem("")
|
||||
self.inboxSearchOptionChans.addItem("")
|
||||
self.inboxSearchOptionChans.setSizeAdjustPolicy(QtWidgets.QComboBox.AdjustToContents)
|
||||
self.inboxSearchOptionChans.setCurrentIndex(3)
|
||||
self.horizontalSplitter_6.addWidget(self.inboxSearchOptionChans)
|
||||
self.horizontalSplitter_6.handle(1).setEnabled(False)
|
||||
|
@ -527,21 +491,21 @@ class Ui_MainWindow(object):
|
|||
self.horizontalSplitter_6.setStretchFactor(1, 0)
|
||||
self.verticalSplitter_8.addWidget(self.horizontalSplitter_6)
|
||||
self.tableWidgetInboxChans = settingsmixin.STableWidget(self.chans)
|
||||
self.tableWidgetInboxChans.setEditTriggers(QtGui.QAbstractItemView.NoEditTriggers)
|
||||
self.tableWidgetInboxChans.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers)
|
||||
self.tableWidgetInboxChans.setAlternatingRowColors(True)
|
||||
self.tableWidgetInboxChans.setSelectionMode(QtGui.QAbstractItemView.ExtendedSelection)
|
||||
self.tableWidgetInboxChans.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows)
|
||||
self.tableWidgetInboxChans.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection)
|
||||
self.tableWidgetInboxChans.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
|
||||
self.tableWidgetInboxChans.setWordWrap(False)
|
||||
self.tableWidgetInboxChans.setObjectName(_fromUtf8("tableWidgetInboxChans"))
|
||||
self.tableWidgetInboxChans.setObjectName("tableWidgetInboxChans")
|
||||
self.tableWidgetInboxChans.setColumnCount(4)
|
||||
self.tableWidgetInboxChans.setRowCount(0)
|
||||
item = QtGui.QTableWidgetItem()
|
||||
item = QtWidgets.QTableWidgetItem()
|
||||
self.tableWidgetInboxChans.setHorizontalHeaderItem(0, item)
|
||||
item = QtGui.QTableWidgetItem()
|
||||
item = QtWidgets.QTableWidgetItem()
|
||||
self.tableWidgetInboxChans.setHorizontalHeaderItem(1, item)
|
||||
item = QtGui.QTableWidgetItem()
|
||||
item = QtWidgets.QTableWidgetItem()
|
||||
self.tableWidgetInboxChans.setHorizontalHeaderItem(2, item)
|
||||
item = QtGui.QTableWidgetItem()
|
||||
item = QtWidgets.QTableWidgetItem()
|
||||
self.tableWidgetInboxChans.setHorizontalHeaderItem(3, item)
|
||||
self.tableWidgetInboxChans.horizontalHeader().setCascadingSectionResizes(True)
|
||||
self.tableWidgetInboxChans.horizontalHeader().setDefaultSectionSize(200)
|
||||
|
@ -555,7 +519,7 @@ class Ui_MainWindow(object):
|
|||
self.textEditInboxMessageChans = MessageView(self.chans)
|
||||
self.textEditInboxMessageChans.setBaseSize(QtCore.QSize(0, 500))
|
||||
self.textEditInboxMessageChans.setReadOnly(True)
|
||||
self.textEditInboxMessageChans.setObjectName(_fromUtf8("textEditInboxMessageChans"))
|
||||
self.textEditInboxMessageChans.setObjectName("textEditInboxMessageChans")
|
||||
self.verticalSplitter_8.addWidget(self.textEditInboxMessageChans)
|
||||
self.verticalSplitter_8.setStretchFactor(0, 0)
|
||||
self.verticalSplitter_8.setStretchFactor(1, 1)
|
||||
|
@ -571,10 +535,8 @@ class Ui_MainWindow(object):
|
|||
self.horizontalSplitter_7.setCollapsible(1, False)
|
||||
self.gridLayout_4.addWidget(self.horizontalSplitter_7, 0, 0, 1, 1)
|
||||
icon8 = QtGui.QIcon()
|
||||
icon8.addPixmap(
|
||||
QtGui.QPixmap(_fromUtf8(":/newPrefix/images/can-icon-16px.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off
|
||||
)
|
||||
self.tabWidget.addTab(self.chans, icon8, _fromUtf8(""))
|
||||
icon8.addPixmap(QtGui.QPixmap(":/newPrefix/images/can-icon-16px.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
||||
self.tabWidget.addTab(self.chans, icon8, "")
|
||||
self.blackwhitelist = Blacklist()
|
||||
self.tabWidget.addTab(self.blackwhitelist, QtGui.QIcon(":/newPrefix/images/blacklist.png"), "")
|
||||
# Initialize the Blacklist or Whitelist
|
||||
|
@ -586,62 +548,62 @@ class Ui_MainWindow(object):
|
|||
self.tabWidget.addTab(self.networkstatus, QtGui.QIcon(":/newPrefix/images/networkstatus.png"), "")
|
||||
self.gridLayout_10.addWidget(self.tabWidget, 0, 0, 1, 1)
|
||||
MainWindow.setCentralWidget(self.centralwidget)
|
||||
self.menubar = QtGui.QMenuBar(MainWindow)
|
||||
self.menubar = QtWidgets.QMenuBar(MainWindow)
|
||||
self.menubar.setGeometry(QtCore.QRect(0, 0, 885, 27))
|
||||
self.menubar.setObjectName(_fromUtf8("menubar"))
|
||||
self.menuFile = QtGui.QMenu(self.menubar)
|
||||
self.menuFile.setObjectName(_fromUtf8("menuFile"))
|
||||
self.menuSettings = QtGui.QMenu(self.menubar)
|
||||
self.menuSettings.setObjectName(_fromUtf8("menuSettings"))
|
||||
self.menuHelp = QtGui.QMenu(self.menubar)
|
||||
self.menuHelp.setObjectName(_fromUtf8("menuHelp"))
|
||||
self.menubar.setObjectName("menubar")
|
||||
self.menuFile = QtWidgets.QMenu(self.menubar)
|
||||
self.menuFile.setObjectName("menuFile")
|
||||
self.menuSettings = QtWidgets.QMenu(self.menubar)
|
||||
self.menuSettings.setObjectName("menuSettings")
|
||||
self.menuHelp = QtWidgets.QMenu(self.menubar)
|
||||
self.menuHelp.setObjectName("menuHelp")
|
||||
MainWindow.setMenuBar(self.menubar)
|
||||
self.statusbar = QtGui.QStatusBar(MainWindow)
|
||||
self.statusbar = QtWidgets.QStatusBar(MainWindow)
|
||||
self.statusbar.setMaximumSize(QtCore.QSize(16777215, 22))
|
||||
self.statusbar.setObjectName(_fromUtf8("statusbar"))
|
||||
self.statusbar.setObjectName("statusbar")
|
||||
MainWindow.setStatusBar(self.statusbar)
|
||||
self.actionImport_keys = QtGui.QAction(MainWindow)
|
||||
self.actionImport_keys.setObjectName(_fromUtf8("actionImport_keys"))
|
||||
self.actionManageKeys = QtGui.QAction(MainWindow)
|
||||
self.actionImport_keys = QtWidgets.QAction(MainWindow)
|
||||
self.actionImport_keys.setObjectName("actionImport_keys")
|
||||
self.actionManageKeys = QtWidgets.QAction(MainWindow)
|
||||
self.actionManageKeys.setCheckable(False)
|
||||
self.actionManageKeys.setEnabled(True)
|
||||
icon = QtGui.QIcon.fromTheme(_fromUtf8("dialog-password"))
|
||||
icon = QtGui.QIcon.fromTheme("dialog-password")
|
||||
self.actionManageKeys.setIcon(icon)
|
||||
self.actionManageKeys.setObjectName(_fromUtf8("actionManageKeys"))
|
||||
self.actionNetworkSwitch = QtGui.QAction(MainWindow)
|
||||
self.actionNetworkSwitch.setObjectName(_fromUtf8("actionNetworkSwitch"))
|
||||
self.actionExit = QtGui.QAction(MainWindow)
|
||||
icon = QtGui.QIcon.fromTheme(_fromUtf8("application-exit"))
|
||||
self.actionManageKeys.setObjectName("actionManageKeys")
|
||||
self.actionNetworkSwitch = QtWidgets.QAction(MainWindow)
|
||||
self.actionNetworkSwitch.setObjectName("actionNetworkSwitch")
|
||||
self.actionExit = QtWidgets.QAction(MainWindow)
|
||||
icon = QtGui.QIcon.fromTheme("application-exit")
|
||||
self.actionExit.setIcon(icon)
|
||||
self.actionExit.setObjectName(_fromUtf8("actionExit"))
|
||||
self.actionHelp = QtGui.QAction(MainWindow)
|
||||
icon = QtGui.QIcon.fromTheme(_fromUtf8("help-contents"))
|
||||
self.actionExit.setObjectName("actionExit")
|
||||
self.actionHelp = QtWidgets.QAction(MainWindow)
|
||||
icon = QtGui.QIcon.fromTheme("help-contents")
|
||||
self.actionHelp.setIcon(icon)
|
||||
self.actionHelp.setObjectName(_fromUtf8("actionHelp"))
|
||||
self.actionSupport = QtGui.QAction(MainWindow)
|
||||
icon = QtGui.QIcon.fromTheme(_fromUtf8("help-support"))
|
||||
self.actionHelp.setObjectName("actionHelp")
|
||||
self.actionSupport = QtWidgets.QAction(MainWindow)
|
||||
icon = QtGui.QIcon.fromTheme("help-support")
|
||||
self.actionSupport.setIcon(icon)
|
||||
self.actionSupport.setObjectName(_fromUtf8("actionSupport"))
|
||||
self.actionAbout = QtGui.QAction(MainWindow)
|
||||
icon = QtGui.QIcon.fromTheme(_fromUtf8("help-about"))
|
||||
self.actionSupport.setObjectName("actionSupport")
|
||||
self.actionAbout = QtWidgets.QAction(MainWindow)
|
||||
icon = QtGui.QIcon.fromTheme("help-about")
|
||||
self.actionAbout.setIcon(icon)
|
||||
self.actionAbout.setObjectName(_fromUtf8("actionAbout"))
|
||||
self.actionSettings = QtGui.QAction(MainWindow)
|
||||
icon = QtGui.QIcon.fromTheme(_fromUtf8("document-properties"))
|
||||
self.actionAbout.setObjectName("actionAbout")
|
||||
self.actionSettings = QtWidgets.QAction(MainWindow)
|
||||
icon = QtGui.QIcon.fromTheme("document-properties")
|
||||
self.actionSettings.setIcon(icon)
|
||||
self.actionSettings.setObjectName(_fromUtf8("actionSettings"))
|
||||
self.actionRegenerateDeterministicAddresses = QtGui.QAction(MainWindow)
|
||||
icon = QtGui.QIcon.fromTheme(_fromUtf8("view-refresh"))
|
||||
self.actionSettings.setObjectName("actionSettings")
|
||||
self.actionRegenerateDeterministicAddresses = QtWidgets.QAction(MainWindow)
|
||||
icon = QtGui.QIcon.fromTheme("view-refresh")
|
||||
self.actionRegenerateDeterministicAddresses.setIcon(icon)
|
||||
self.actionRegenerateDeterministicAddresses.setObjectName(_fromUtf8("actionRegenerateDeterministicAddresses"))
|
||||
self.actionDeleteAllTrashedMessages = QtGui.QAction(MainWindow)
|
||||
icon = QtGui.QIcon.fromTheme(_fromUtf8("user-trash"))
|
||||
self.actionRegenerateDeterministicAddresses.setObjectName("actionRegenerateDeterministicAddresses")
|
||||
self.actionDeleteAllTrashedMessages = QtWidgets.QAction(MainWindow)
|
||||
icon = QtGui.QIcon.fromTheme("user-trash")
|
||||
self.actionDeleteAllTrashedMessages.setIcon(icon)
|
||||
self.actionDeleteAllTrashedMessages.setObjectName(_fromUtf8("actionDeleteAllTrashedMessages"))
|
||||
self.actionJoinChan = QtGui.QAction(MainWindow)
|
||||
icon = QtGui.QIcon.fromTheme(_fromUtf8("contact-new"))
|
||||
self.actionDeleteAllTrashedMessages.setObjectName("actionDeleteAllTrashedMessages")
|
||||
self.actionJoinChan = QtWidgets.QAction(MainWindow)
|
||||
icon = QtGui.QIcon.fromTheme("contact-new")
|
||||
self.actionJoinChan.setIcon(icon)
|
||||
self.actionJoinChan.setObjectName(_fromUtf8("actionJoinChan"))
|
||||
self.actionJoinChan.setObjectName("actionJoinChan")
|
||||
self.menuFile.addAction(self.actionManageKeys)
|
||||
self.menuFile.addAction(self.actionDeleteAllTrashedMessages)
|
||||
self.menuFile.addAction(self.actionRegenerateDeterministicAddresses)
|
||||
|
@ -672,11 +634,11 @@ class Ui_MainWindow(object):
|
|||
|
||||
# Popup menu actions container for the Sent page
|
||||
# pylint: disable=attribute-defined-outside-init
|
||||
self.sentContextMenuToolbar = QtGui.QToolBar()
|
||||
self.sentContextMenuToolbar = QtWidgets.QToolBar()
|
||||
# Popup menu actions container for chans tree
|
||||
self.addressContextMenuToolbar = QtGui.QToolBar()
|
||||
self.addressContextMenuToolbar = QtWidgets.QToolBar()
|
||||
# Popup menu actions container for subscriptions tree
|
||||
self.subscriptionsContextMenuToolbar = QtGui.QToolBar()
|
||||
self.subscriptionsContextMenuToolbar = QtWidgets.QToolBar()
|
||||
|
||||
def updateNetworkSwitchMenuLabel(self, dontconnect=None):
|
||||
if dontconnect is None:
|
||||
|
@ -733,9 +695,7 @@ class Ui_MainWindow(object):
|
|||
hours = int(config.getint('bitmessagesettings', 'ttl') / 60 / 60)
|
||||
except:
|
||||
pass
|
||||
self.labelHumanFriendlyTTLDescription.setText(
|
||||
_translate("MainWindow", "%n hour(s)", None, QtCore.QCoreApplication.CodecForTr, hours)
|
||||
)
|
||||
self.labelHumanFriendlyTTLDescription.setText(_translate("MainWindow", "%n hour(s)", None, hours))
|
||||
self.pushButtonClear.setText(_translate("MainWindow", "Clear", None))
|
||||
self.pushButtonSend.setText(_translate("MainWindow", "Send", None))
|
||||
self.tabWidget.setTabText(self.tabWidget.indexOf(self.send), _translate("MainWindow", "Send", None))
|
||||
|
@ -810,7 +770,7 @@ class Ui_MainWindow(object):
|
|||
if __name__ == "__main__":
|
||||
import sys
|
||||
|
||||
app = QtGui.QApplication(sys.argv)
|
||||
app = QtWidgets.QApplication(sys.argv)
|
||||
MainWindow = settingsmixin.SMainWindow()
|
||||
ui = Ui_MainWindow()
|
||||
ui.setupUi(MainWindow)
|
||||
|
|
|
@ -1,42 +1,44 @@
|
|||
from PyQt4 import QtCore, QtGui
|
||||
from unqstr import ustr, unic
|
||||
from dbcompat import dbstr
|
||||
from qtpy import QtCore, QtGui, QtWidgets
|
||||
|
||||
import widgets
|
||||
from bitmessageqt import widgets
|
||||
from addresses import addBMIfNotPresent
|
||||
from bmconfigparser import config
|
||||
from dialogs import AddAddressDialog
|
||||
from .dialogs import AddAddressDialog
|
||||
from helper_sql import sqlExecute, sqlQuery
|
||||
from queues import UISignalQueue
|
||||
from retranslateui import RetranslateMixin
|
||||
from .retranslateui import RetranslateMixin
|
||||
from tr import _translate
|
||||
from uisignaler import UISignaler
|
||||
from utils import avatarize
|
||||
from .uisignaler import UISignaler
|
||||
from .utils import avatarize
|
||||
|
||||
|
||||
class Blacklist(QtGui.QWidget, RetranslateMixin):
|
||||
class Blacklist(QtWidgets.QWidget, RetranslateMixin):
|
||||
def __init__(self, parent=None):
|
||||
super(Blacklist, self).__init__(parent)
|
||||
widgets.load('blacklist.ui', self)
|
||||
|
||||
QtCore.QObject.connect(self.radioButtonBlacklist, QtCore.SIGNAL(
|
||||
"clicked()"), self.click_radioButtonBlacklist)
|
||||
QtCore.QObject.connect(self.radioButtonWhitelist, QtCore.SIGNAL(
|
||||
"clicked()"), self.click_radioButtonWhitelist)
|
||||
QtCore.QObject.connect(self.pushButtonAddBlacklist, QtCore.SIGNAL(
|
||||
"clicked()"), self.click_pushButtonAddBlacklist)
|
||||
self.radioButtonBlacklist.clicked.connect(
|
||||
self.click_radioButtonBlacklist)
|
||||
self.radioButtonWhitelist.clicked.connect(
|
||||
self.click_radioButtonWhitelist)
|
||||
self.pushButtonAddBlacklist.clicked.connect(
|
||||
self.click_pushButtonAddBlacklist)
|
||||
|
||||
self.init_blacklist_popup_menu()
|
||||
|
||||
# Initialize blacklist
|
||||
QtCore.QObject.connect(self.tableWidgetBlacklist, QtCore.SIGNAL(
|
||||
"itemChanged(QTableWidgetItem *)"), self.tableWidgetBlacklistItemChanged)
|
||||
self.tableWidgetBlacklist.itemChanged.connect(
|
||||
self.tableWidgetBlacklistItemChanged)
|
||||
|
||||
# Set the icon sizes for the identicons
|
||||
identicon_size = 3*7
|
||||
self.tableWidgetBlacklist.setIconSize(QtCore.QSize(identicon_size, identicon_size))
|
||||
identicon_size = 3 * 7
|
||||
self.tableWidgetBlacklist.setIconSize(
|
||||
QtCore.QSize(identicon_size, identicon_size))
|
||||
|
||||
self.UISignalThread = UISignaler.get()
|
||||
QtCore.QObject.connect(self.UISignalThread, QtCore.SIGNAL(
|
||||
"rerenderBlackWhiteList()"), self.rerenderBlackWhiteList)
|
||||
self.UISignalThread.rerenderBlackWhiteList.connect(
|
||||
self.rerenderBlackWhiteList)
|
||||
|
||||
def click_radioButtonBlacklist(self):
|
||||
if config.get('bitmessagesettings', 'blackwhitelist') == 'white':
|
||||
|
@ -59,30 +61,30 @@ class Blacklist(QtGui.QWidget, RetranslateMixin):
|
|||
if self.NewBlacklistDialogInstance.exec_():
|
||||
if self.NewBlacklistDialogInstance.labelAddressCheck.text() == \
|
||||
_translate("MainWindow", "Address is valid."):
|
||||
address = addBMIfNotPresent(str(
|
||||
address = addBMIfNotPresent(ustr(
|
||||
self.NewBlacklistDialogInstance.lineEditAddress.text()))
|
||||
# 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
|
||||
# cause problems when updating and deleting the entry.
|
||||
t = (address,)
|
||||
t = (dbstr(address),)
|
||||
if config.get('bitmessagesettings', 'blackwhitelist') == 'black':
|
||||
sql = '''select * from blacklist where address=?'''
|
||||
else:
|
||||
sql = '''select * from whitelist where address=?'''
|
||||
queryreturn = sqlQuery(sql,*t)
|
||||
queryreturn = sqlQuery(sql, *t)
|
||||
if queryreturn == []:
|
||||
self.tableWidgetBlacklist.setSortingEnabled(False)
|
||||
self.tableWidgetBlacklist.insertRow(0)
|
||||
newItem = QtGui.QTableWidgetItem(unicode(
|
||||
self.NewBlacklistDialogInstance.lineEditLabel.text().toUtf8(), 'utf-8'))
|
||||
newItem = QtGui.QTableWidgetItem(unic(ustr(
|
||||
self.NewBlacklistDialogInstance.lineEditLabel.text())))
|
||||
newItem.setIcon(avatarize(address))
|
||||
self.tableWidgetBlacklist.setItem(0, 0, newItem)
|
||||
newItem = QtGui.QTableWidgetItem(address)
|
||||
newItem = QtWidgets.QTableWidgetItem(address)
|
||||
newItem.setFlags(
|
||||
QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled)
|
||||
self.tableWidgetBlacklist.setItem(0, 1, newItem)
|
||||
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':
|
||||
sql = '''INSERT INTO blacklist VALUES (?,?,?)'''
|
||||
else:
|
||||
|
@ -108,17 +110,17 @@ class Blacklist(QtGui.QWidget, RetranslateMixin):
|
|||
def tableWidgetBlacklistItemChanged(self, item):
|
||||
if item.column() == 0:
|
||||
addressitem = self.tableWidgetBlacklist.item(item.row(), 1)
|
||||
if isinstance(addressitem, QtGui.QTableWidgetItem):
|
||||
if isinstance(addressitem, QtWidgets.QTableWidgetItem):
|
||||
if self.radioButtonBlacklist.isChecked():
|
||||
sqlExecute('''UPDATE blacklist SET label=? WHERE address=?''',
|
||||
str(item.text()), str(addressitem.text()))
|
||||
dbstr(item.text()), dbstr(addressitem.text()))
|
||||
else:
|
||||
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):
|
||||
# Popup menu for the Blacklist page
|
||||
self.blacklistContextMenuToolbar = QtGui.QToolBar()
|
||||
self.blacklistContextMenuToolbar = QtWidgets.QToolBar()
|
||||
# Actions
|
||||
self.actionBlacklistNew = self.blacklistContextMenuToolbar.addAction(
|
||||
_translate(
|
||||
|
@ -143,10 +145,9 @@ class Blacklist(QtGui.QWidget, RetranslateMixin):
|
|||
self.tableWidgetBlacklist.setContextMenuPolicy(
|
||||
QtCore.Qt.CustomContextMenu)
|
||||
if connectSignal:
|
||||
self.connect(self.tableWidgetBlacklist, QtCore.SIGNAL(
|
||||
'customContextMenuRequested(const QPoint&)'),
|
||||
self.tableWidgetBlacklist.customContextMenuRequested.connect(
|
||||
self.on_context_menuBlacklist)
|
||||
self.popMenuBlacklist = QtGui.QMenu(self)
|
||||
self.popMenuBlacklist = QtWidgets.QMenu(self)
|
||||
# self.popMenuBlacklist.addAction( self.actionBlacklistNew )
|
||||
self.popMenuBlacklist.addAction(self.actionBlacklistDelete)
|
||||
self.popMenuBlacklist.addSeparator()
|
||||
|
@ -171,17 +172,19 @@ class Blacklist(QtGui.QWidget, RetranslateMixin):
|
|||
self.tableWidgetBlacklist.setSortingEnabled(False)
|
||||
for row in queryreturn:
|
||||
label, address, enabled = row
|
||||
label = label.decode("utf-8", "replace")
|
||||
address = address.decode("utf-8", "replace")
|
||||
self.tableWidgetBlacklist.insertRow(0)
|
||||
newItem = QtGui.QTableWidgetItem(unicode(label, 'utf-8'))
|
||||
newItem = QtWidgets.QTableWidgetItem(unic(ustr(label)))
|
||||
if not enabled:
|
||||
newItem.setTextColor(QtGui.QColor(128, 128, 128))
|
||||
newItem.setForeground(QtGui.QColor(128, 128, 128))
|
||||
newItem.setIcon(avatarize(address))
|
||||
self.tableWidgetBlacklist.setItem(0, 0, newItem)
|
||||
newItem = QtGui.QTableWidgetItem(address)
|
||||
newItem = QtWidgets.QTableWidgetItem(address)
|
||||
newItem.setFlags(
|
||||
QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled)
|
||||
if not enabled:
|
||||
newItem.setTextColor(QtGui.QColor(128, 128, 128))
|
||||
newItem.setForeground(QtGui.QColor(128, 128, 128))
|
||||
self.tableWidgetBlacklist.setItem(0, 1, newItem)
|
||||
self.tableWidgetBlacklist.setSortingEnabled(True)
|
||||
|
||||
|
@ -191,26 +194,26 @@ class Blacklist(QtGui.QWidget, RetranslateMixin):
|
|||
|
||||
def on_action_BlacklistDelete(self):
|
||||
currentRow = self.tableWidgetBlacklist.currentRow()
|
||||
labelAtCurrentRow = self.tableWidgetBlacklist.item(
|
||||
currentRow, 0).text().toUtf8()
|
||||
labelAtCurrentRow = ustr(self.tableWidgetBlacklist.item(
|
||||
currentRow, 0).text())
|
||||
addressAtCurrentRow = self.tableWidgetBlacklist.item(
|
||||
currentRow, 1).text()
|
||||
if config.get('bitmessagesettings', 'blackwhitelist') == 'black':
|
||||
sqlExecute(
|
||||
'''DELETE FROM blacklist WHERE label=? AND address=?''',
|
||||
str(labelAtCurrentRow), str(addressAtCurrentRow))
|
||||
dbstr(labelAtCurrentRow), dbstr(addressAtCurrentRow))
|
||||
else:
|
||||
sqlExecute(
|
||||
'''DELETE FROM whitelist WHERE label=? AND address=?''',
|
||||
str(labelAtCurrentRow), str(addressAtCurrentRow))
|
||||
dbstr(labelAtCurrentRow), dbstr(addressAtCurrentRow))
|
||||
self.tableWidgetBlacklist.removeRow(currentRow)
|
||||
|
||||
def on_action_BlacklistClipboard(self):
|
||||
currentRow = self.tableWidgetBlacklist.currentRow()
|
||||
addressAtCurrentRow = self.tableWidgetBlacklist.item(
|
||||
currentRow, 1).text()
|
||||
clipboard = QtGui.QApplication.clipboard()
|
||||
clipboard.setText(str(addressAtCurrentRow))
|
||||
clipboard = QtWidgets.QApplication.clipboard()
|
||||
clipboard.setText(ustr(addressAtCurrentRow))
|
||||
|
||||
def on_context_menuBlacklist(self, point):
|
||||
self.popMenuBlacklist.exec_(
|
||||
|
@ -220,33 +223,33 @@ class Blacklist(QtGui.QWidget, RetranslateMixin):
|
|||
currentRow = self.tableWidgetBlacklist.currentRow()
|
||||
addressAtCurrentRow = self.tableWidgetBlacklist.item(
|
||||
currentRow, 1).text()
|
||||
self.tableWidgetBlacklist.item(
|
||||
currentRow, 0).setTextColor(QtGui.QApplication.palette().text().color())
|
||||
self.tableWidgetBlacklist.item(
|
||||
currentRow, 1).setTextColor(QtGui.QApplication.palette().text().color())
|
||||
self.tableWidgetBlacklist.item(currentRow, 0).setForeground(
|
||||
QtWidgets.QApplication.palette().text().color())
|
||||
self.tableWidgetBlacklist.item(currentRow, 1).setForeground(
|
||||
QtWidgets.QApplication.palette().text().color())
|
||||
if config.get('bitmessagesettings', 'blackwhitelist') == 'black':
|
||||
sqlExecute(
|
||||
'''UPDATE blacklist SET enabled=1 WHERE address=?''',
|
||||
str(addressAtCurrentRow))
|
||||
dbstr(addressAtCurrentRow))
|
||||
else:
|
||||
sqlExecute(
|
||||
'''UPDATE whitelist SET enabled=1 WHERE address=?''',
|
||||
str(addressAtCurrentRow))
|
||||
dbstr(addressAtCurrentRow))
|
||||
|
||||
def on_action_BlacklistDisable(self):
|
||||
currentRow = self.tableWidgetBlacklist.currentRow()
|
||||
addressAtCurrentRow = self.tableWidgetBlacklist.item(
|
||||
currentRow, 1).text()
|
||||
self.tableWidgetBlacklist.item(
|
||||
currentRow, 0).setTextColor(QtGui.QColor(128, 128, 128))
|
||||
self.tableWidgetBlacklist.item(
|
||||
currentRow, 1).setTextColor(QtGui.QColor(128, 128, 128))
|
||||
self.tableWidgetBlacklist.item(currentRow, 0).setForeground(
|
||||
QtGui.QColor(128, 128, 128))
|
||||
self.tableWidgetBlacklist.item(currentRow, 1).setForeground(
|
||||
QtGui.QColor(128, 128, 128))
|
||||
if config.get('bitmessagesettings', 'blackwhitelist') == 'black':
|
||||
sqlExecute(
|
||||
'''UPDATE blacklist SET enabled=0 WHERE address=?''', str(addressAtCurrentRow))
|
||||
'''UPDATE blacklist SET enabled=0 WHERE address=?''', dbstr(addressAtCurrentRow))
|
||||
else:
|
||||
sqlExecute(
|
||||
'''UPDATE whitelist SET enabled=0 WHERE address=?''', str(addressAtCurrentRow))
|
||||
'''UPDATE whitelist SET enabled=0 WHERE address=?''', dbstr(addressAtCurrentRow))
|
||||
|
||||
def on_action_BlacklistSetAvatar(self):
|
||||
self.window().on_action_SetAvatar(self.tableWidgetBlacklist)
|
||||
|
|
|
@ -62,6 +62,9 @@
|
|||
<property name="sortingEnabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<attribute name="horizontalHeaderCascadingSectionResizes">
|
||||
<bool>true</bool>
|
||||
</attribute>
|
||||
|
@ -98,11 +101,8 @@
|
|||
<customwidget>
|
||||
<class>STableWidget</class>
|
||||
<extends>QTableWidget</extends>
|
||||
<header>bitmessageqt/settingsmixin.h</header>
|
||||
<header>bitmessageqt.settingsmixin</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources>
|
||||
<include location="bitmessage_icons.qrc"/>
|
||||
</resources>
|
||||
<connections/>
|
||||
</ui>
|
||||
|
|
|
@ -1,22 +1,23 @@
|
|||
"""
|
||||
Custom dialog classes
|
||||
All dialogs are available in this module.
|
||||
"""
|
||||
# pylint: disable=too-few-public-methods
|
||||
from PyQt4 import QtGui
|
||||
from unqstr import ustr
|
||||
|
||||
from qtpy import QtWidgets
|
||||
|
||||
import paths
|
||||
import widgets
|
||||
from address_dialogs import (
|
||||
from bitmessageqt import widgets
|
||||
from .address_dialogs import (
|
||||
AddAddressDialog, EmailGatewayDialog, NewAddressDialog,
|
||||
NewSubscriptionDialog, RegenerateAddressesDialog,
|
||||
SpecialAddressBehaviorDialog
|
||||
)
|
||||
from newchandialog import NewChanDialog
|
||||
from settings import SettingsDialog
|
||||
from .newchandialog import NewChanDialog
|
||||
from .settings import SettingsDialog
|
||||
from tr import _translate
|
||||
from version import softwareVersion
|
||||
|
||||
|
||||
__all__ = [
|
||||
"NewChanDialog", "AddAddressDialog", "NewAddressDialog",
|
||||
"NewSubscriptionDialog", "RegenerateAddressesDialog",
|
||||
|
@ -25,8 +26,8 @@ __all__ = [
|
|||
]
|
||||
|
||||
|
||||
class AboutDialog(QtGui.QDialog):
|
||||
"""The `About` dialog"""
|
||||
class AboutDialog(QtWidgets.QDialog):
|
||||
"""The "About" dialog"""
|
||||
def __init__(self, parent=None):
|
||||
super(AboutDialog, self).__init__(parent)
|
||||
widgets.load('about.ui', self)
|
||||
|
@ -36,7 +37,7 @@ class AboutDialog(QtGui.QDialog):
|
|||
if commit:
|
||||
version += '-' + commit[:7]
|
||||
self.labelVersion.setText(
|
||||
self.labelVersion.text().replace(
|
||||
ustr(self.labelVersion.text()).replace(
|
||||
':version:', version
|
||||
).replace(':branch:', commit or 'v%s' % version)
|
||||
)
|
||||
|
@ -44,17 +45,17 @@ class AboutDialog(QtGui.QDialog):
|
|||
|
||||
try:
|
||||
self.label_2.setText(
|
||||
self.label_2.text().replace(
|
||||
'2022', str(last_commit.get('time').year)
|
||||
ustr(self.label_2.text()).replace(
|
||||
'2022', ustr(last_commit.get('time').year)
|
||||
))
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
self.setFixedSize(QtGui.QWidget.sizeHint(self))
|
||||
self.setFixedSize(QtWidgets.QWidget.sizeHint(self))
|
||||
|
||||
|
||||
class IconGlossaryDialog(QtGui.QDialog):
|
||||
"""The `Icon Glossary` dialog, explaining the status icon colors"""
|
||||
class IconGlossaryDialog(QtWidgets.QDialog):
|
||||
"""The "Icon Glossary" dialog, explaining the status icon colors"""
|
||||
def __init__(self, parent=None, config=None):
|
||||
super(IconGlossaryDialog, self).__init__(parent)
|
||||
widgets.load('iconglossary.ui', self)
|
||||
|
@ -64,22 +65,23 @@ class IconGlossaryDialog(QtGui.QDialog):
|
|||
|
||||
self.labelPortNumber.setText(_translate(
|
||||
"iconGlossaryDialog",
|
||||
"You are using TCP port %1. (This can be changed in the settings)."
|
||||
).arg(config.getint('bitmessagesettings', 'port')))
|
||||
self.setFixedSize(QtGui.QWidget.sizeHint(self))
|
||||
"You are using TCP port {0}."
|
||||
" (This can be changed in the settings)."
|
||||
).format(config.getint('bitmessagesettings', 'port')))
|
||||
self.setFixedSize(QtWidgets.QWidget.sizeHint(self))
|
||||
|
||||
|
||||
class HelpDialog(QtGui.QDialog):
|
||||
"""The `Help` dialog"""
|
||||
class HelpDialog(QtWidgets.QDialog):
|
||||
"""The "Help" dialog"""
|
||||
def __init__(self, parent=None):
|
||||
super(HelpDialog, self).__init__(parent)
|
||||
widgets.load('help.ui', self)
|
||||
self.setFixedSize(QtGui.QWidget.sizeHint(self))
|
||||
self.setFixedSize(QtWidgets.QWidget.sizeHint(self))
|
||||
|
||||
|
||||
class ConnectDialog(QtGui.QDialog):
|
||||
"""The `Connect` dialog"""
|
||||
class ConnectDialog(QtWidgets.QDialog):
|
||||
"""The "Connect" dialog"""
|
||||
def __init__(self, parent=None):
|
||||
super(ConnectDialog, self).__init__(parent)
|
||||
widgets.load('connect.ui', self)
|
||||
self.setFixedSize(QtGui.QWidget.sizeHint(self))
|
||||
self.setFixedSize(QtWidgets.QWidget.sizeHint(self))
|
||||
|
|
|
@ -1,18 +1,23 @@
|
|||
"""
|
||||
Folder tree and messagelist widgets definitions.
|
||||
"""
|
||||
# pylint: disable=too-many-arguments,bad-super-call
|
||||
# pylint: disable=too-many-arguments
|
||||
# pylint: disable=attribute-defined-outside-init
|
||||
|
||||
from cgi import escape
|
||||
try:
|
||||
from cgi import escape
|
||||
except ImportError:
|
||||
from html import escape
|
||||
|
||||
from PyQt4 import QtCore, QtGui
|
||||
from unqstr import ustr, unic
|
||||
from dbcompat import dbstr
|
||||
from qtpy import QtCore, QtGui, QtWidgets
|
||||
|
||||
from bmconfigparser import config
|
||||
from helper_sql import sqlExecute, sqlQuery
|
||||
from settingsmixin import SettingsMixin
|
||||
from .settingsmixin import SettingsMixin
|
||||
from tr import _translate
|
||||
from utils import avatarize
|
||||
from .utils import avatarize
|
||||
|
||||
# for pylupdate
|
||||
_translate("MainWindow", "inbox")
|
||||
|
@ -38,15 +43,16 @@ class AccountMixin(object):
|
|||
return QtGui.QColor(128, 128, 128)
|
||||
elif self.type == self.CHAN:
|
||||
return QtGui.QColor(216, 119, 0)
|
||||
elif self.type in [self.MAILINGLIST, self.SUBSCRIPTION]:
|
||||
elif self.type in (self.MAILINGLIST, self.SUBSCRIPTION):
|
||||
return QtGui.QColor(137, 4, 177)
|
||||
return QtGui.QApplication.palette().text().color()
|
||||
|
||||
return QtWidgets.QApplication.palette().text().color()
|
||||
|
||||
def folderColor(self):
|
||||
"""QT UI color for a folder"""
|
||||
if not self.parent().isEnabled:
|
||||
return QtGui.QColor(128, 128, 128)
|
||||
return QtGui.QApplication.palette().text().color()
|
||||
return QtWidgets.QApplication.palette().text().color()
|
||||
|
||||
def accountBrush(self):
|
||||
"""Account brush (for QT UI)"""
|
||||
|
@ -62,7 +68,7 @@ class AccountMixin(object):
|
|||
|
||||
def accountString(self):
|
||||
"""Account string suitable for use in To: field: label <address>"""
|
||||
label = self._getLabel()
|
||||
label = ustr(self._getLabel())
|
||||
return (
|
||||
self.address if label == self.address
|
||||
else '%s <%s>' % (label, self.address)
|
||||
|
@ -73,7 +79,7 @@ class AccountMixin(object):
|
|||
if address is None:
|
||||
self.address = None
|
||||
else:
|
||||
self.address = str(address)
|
||||
self.address = ustr(address)
|
||||
|
||||
def setUnreadCount(self, cnt):
|
||||
"""Set number of unread messages"""
|
||||
|
@ -83,7 +89,7 @@ class AccountMixin(object):
|
|||
except AttributeError:
|
||||
pass
|
||||
self.unreadCount = int(cnt)
|
||||
if isinstance(self, QtGui.QTreeWidgetItem):
|
||||
if isinstance(self, QtWidgets.QTreeWidgetItem):
|
||||
self.emitDataChanged()
|
||||
|
||||
def setEnabled(self, enabled):
|
||||
|
@ -97,7 +103,7 @@ class AccountMixin(object):
|
|||
for i in range(self.childCount()):
|
||||
if isinstance(self.child(i), Ui_FolderWidget):
|
||||
self.child(i).setEnabled(enabled)
|
||||
if isinstance(self, QtGui.QTreeWidgetItem):
|
||||
if isinstance(self, QtWidgets.QTreeWidgetItem):
|
||||
self.emitDataChanged()
|
||||
|
||||
def setType(self):
|
||||
|
@ -111,53 +117,53 @@ class AccountMixin(object):
|
|||
elif config.safeGetBoolean(self.address, 'mailinglist'):
|
||||
self.type = self.MAILINGLIST
|
||||
elif sqlQuery(
|
||||
'''select label from subscriptions where address=?''', self.address):
|
||||
'SELECT label FROM subscriptions WHERE address=?',
|
||||
dbstr(self.address)
|
||||
):
|
||||
self.type = AccountMixin.SUBSCRIPTION
|
||||
else:
|
||||
self.type = self.NORMAL
|
||||
|
||||
def defaultLabel(self):
|
||||
"""Default label (in case no label is set manually)"""
|
||||
queryreturn = None
|
||||
retval = None
|
||||
queryreturn = retval = None
|
||||
if self.type in (
|
||||
AccountMixin.NORMAL,
|
||||
AccountMixin.CHAN, AccountMixin.MAILINGLIST):
|
||||
try:
|
||||
retval = unicode(
|
||||
config.get(self.address, 'label'), 'utf-8')
|
||||
retval = unic(ustr(config.get(self.address, 'label')))
|
||||
except Exception:
|
||||
queryreturn = sqlQuery(
|
||||
'''select label from addressbook where address=?''', self.address)
|
||||
'SELECT label FROM addressbook WHERE address=?',
|
||||
dbstr(self.address)
|
||||
)
|
||||
elif self.type == AccountMixin.SUBSCRIPTION:
|
||||
queryreturn = sqlQuery(
|
||||
'''select label from subscriptions where address=?''', self.address)
|
||||
if queryreturn is not None:
|
||||
if queryreturn != []:
|
||||
for row in queryreturn:
|
||||
retval, = row
|
||||
retval = unicode(retval, 'utf-8')
|
||||
'SELECT label FROM subscriptions WHERE address=?',
|
||||
dbstr(self.address)
|
||||
)
|
||||
if queryreturn:
|
||||
retval = unic(ustr(queryreturn[-1][0]))
|
||||
elif self.address is None or self.type == AccountMixin.ALL:
|
||||
return unicode(
|
||||
str(_translate("MainWindow", "All accounts")), 'utf-8')
|
||||
return unic(_translate("MainWindow", "All accounts"))
|
||||
|
||||
return retval or unicode(self.address, 'utf-8')
|
||||
return retval or unic(self.address)
|
||||
|
||||
|
||||
class BMTreeWidgetItem(QtGui.QTreeWidgetItem, AccountMixin):
|
||||
class BMTreeWidgetItem(QtWidgets.QTreeWidgetItem, AccountMixin):
|
||||
"""A common abstract class for Tree widget item"""
|
||||
|
||||
def __init__(self, parent, pos, address, unreadCount):
|
||||
super(QtGui.QTreeWidgetItem, self).__init__()
|
||||
super(QtWidgets.QTreeWidgetItem, self).__init__()
|
||||
self.setAddress(address)
|
||||
self.setUnreadCount(unreadCount)
|
||||
self._setup(parent, pos)
|
||||
|
||||
def _getAddressBracket(self, unreadCount=False):
|
||||
return " (" + str(self.unreadCount) + ")" if unreadCount else ""
|
||||
return " (" + ustr(self.unreadCount) + ")" if unreadCount else ""
|
||||
|
||||
def data(self, column, role):
|
||||
"""Override internal QT method for returning object data"""
|
||||
"""Override internal Qt method for returning object data"""
|
||||
if column == 0:
|
||||
if role == QtCore.Qt.DisplayRole:
|
||||
return self._getLabel() + self._getAddressBracket(
|
||||
|
@ -190,11 +196,11 @@ class Ui_FolderWidget(BMTreeWidgetItem):
|
|||
return _translate("MainWindow", self.folderName)
|
||||
|
||||
def setFolderName(self, fname):
|
||||
"""Set folder name (for QT UI)"""
|
||||
self.folderName = str(fname)
|
||||
"""Set folder name (for Qt UI)"""
|
||||
self.folderName = ustr(fname)
|
||||
|
||||
def data(self, column, role):
|
||||
"""Override internal QT method for returning object data"""
|
||||
"""Override internal Qt method for returning object data"""
|
||||
if column == 0 and role == QtCore.Qt.ForegroundRole:
|
||||
return self.folderBrush()
|
||||
return super(Ui_FolderWidget, self).data(column, role)
|
||||
|
@ -216,12 +222,14 @@ class Ui_FolderWidget(BMTreeWidgetItem):
|
|||
return self.folderName < other.folderName
|
||||
return x >= y if reverse else x < y
|
||||
|
||||
return super(QtGui.QTreeWidgetItem, self).__lt__(other)
|
||||
return super(QtWidgets.QTreeWidgetItem, self).__lt__(other)
|
||||
|
||||
|
||||
class Ui_AddressWidget(BMTreeWidgetItem, SettingsMixin):
|
||||
"""Item in the account/folder tree representing an account"""
|
||||
def __init__(self, parent, pos=0, address=None, unreadCount=0, enabled=True):
|
||||
def __init__(
|
||||
self, parent, pos=0, address=None, unreadCount=0, enabled=True
|
||||
):
|
||||
super(Ui_AddressWidget, self).__init__(
|
||||
parent, pos, address, unreadCount)
|
||||
self.setEnabled(enabled)
|
||||
|
@ -232,15 +240,13 @@ class Ui_AddressWidget(BMTreeWidgetItem, SettingsMixin):
|
|||
|
||||
def _getLabel(self):
|
||||
if self.address is None:
|
||||
return unicode(_translate(
|
||||
"MainWindow", "All accounts").toUtf8(), 'utf-8', 'ignore')
|
||||
return unic(_translate("MainWindow", "All accounts"))
|
||||
else:
|
||||
try:
|
||||
return unicode(
|
||||
config.get(self.address, 'label'),
|
||||
'utf-8', 'ignore')
|
||||
return unic(ustr(
|
||||
config.get(self.address, 'label')))
|
||||
except:
|
||||
return unicode(self.address, 'utf-8')
|
||||
return unic(self.address)
|
||||
|
||||
def _getAddressBracket(self, unreadCount=False):
|
||||
ret = "" if self.isExpanded() \
|
||||
|
@ -260,15 +266,13 @@ class Ui_AddressWidget(BMTreeWidgetItem, SettingsMixin):
|
|||
return super(Ui_AddressWidget, self).data(column, role)
|
||||
|
||||
def setData(self, column, role, value):
|
||||
"""Save account label (if you edit in the the UI, this will be triggered and will save it to keys.dat)"""
|
||||
"""
|
||||
Save account label (if you edit in the the UI, this will be
|
||||
triggered and will save it to keys.dat)
|
||||
"""
|
||||
if role == QtCore.Qt.EditRole \
|
||||
and self.type != AccountMixin.SUBSCRIPTION:
|
||||
config.set(
|
||||
str(self.address), 'label',
|
||||
str(value.toString().toUtf8())
|
||||
if isinstance(value, QtCore.QVariant)
|
||||
else value.encode('utf-8')
|
||||
)
|
||||
config.set(self.address, 'label', ustr(value))
|
||||
config.save()
|
||||
return super(Ui_AddressWidget, self).setData(column, role, value)
|
||||
|
||||
|
@ -295,24 +299,26 @@ class Ui_AddressWidget(BMTreeWidgetItem, SettingsMixin):
|
|||
if self._getSortRank() < other._getSortRank() else reverse
|
||||
)
|
||||
|
||||
return super(QtGui.QTreeWidgetItem, self).__lt__(other)
|
||||
return super(Ui_AddressWidget, self).__lt__(other)
|
||||
|
||||
|
||||
class Ui_SubscriptionWidget(Ui_AddressWidget):
|
||||
"""Special treating of subscription addresses"""
|
||||
# pylint: disable=unused-argument
|
||||
def __init__(self, parent, pos=0, address="", unreadCount=0, label="", enabled=True):
|
||||
def __init__(
|
||||
self, parent, pos=0, address="", unreadCount=0, label="",
|
||||
enabled=True
|
||||
):
|
||||
super(Ui_SubscriptionWidget, self).__init__(
|
||||
parent, pos, address, unreadCount, enabled)
|
||||
|
||||
def _getLabel(self):
|
||||
queryreturn = sqlQuery(
|
||||
'''select label from subscriptions where address=?''', self.address)
|
||||
if queryreturn != []:
|
||||
for row in queryreturn:
|
||||
retval, = row
|
||||
return unicode(retval, 'utf-8', 'ignore')
|
||||
return unicode(self.address, 'utf-8')
|
||||
'SELECT label FROM subscriptions WHERE address=?',
|
||||
dbstr(self.address))
|
||||
if queryreturn:
|
||||
return unic(ustr(queryreturn[-1][0]))
|
||||
return unic(self.address)
|
||||
|
||||
def setType(self):
|
||||
"""Set account type"""
|
||||
|
@ -322,22 +328,17 @@ class Ui_SubscriptionWidget(Ui_AddressWidget):
|
|||
def setData(self, column, role, value):
|
||||
"""Save subscription label to database"""
|
||||
if role == QtCore.Qt.EditRole:
|
||||
if isinstance(value, QtCore.QVariant):
|
||||
label = str(
|
||||
value.toString().toUtf8()).decode('utf-8', 'ignore')
|
||||
else:
|
||||
label = unicode(value, 'utf-8', 'ignore')
|
||||
sqlExecute(
|
||||
'''UPDATE subscriptions SET label=? WHERE address=?''',
|
||||
label, self.address)
|
||||
'UPDATE subscriptions SET label=? WHERE address=?',
|
||||
dbstr(unic(ustr(value))), dbstr(self.address))
|
||||
return super(Ui_SubscriptionWidget, self).setData(column, role, value)
|
||||
|
||||
|
||||
class BMTableWidgetItem(QtGui.QTableWidgetItem, SettingsMixin):
|
||||
class BMTableWidgetItem(QtWidgets.QTableWidgetItem, SettingsMixin):
|
||||
"""A common abstract class for Table widget item"""
|
||||
|
||||
def __init__(self, label=None, unread=False):
|
||||
super(QtGui.QTableWidgetItem, self).__init__()
|
||||
super(QtWidgets.QTableWidgetItem, self).__init__()
|
||||
self.setLabel(label)
|
||||
self.setUnread(unread)
|
||||
self._setup()
|
||||
|
@ -407,18 +408,17 @@ class MessageList_AddressWidget(BMAddressWidget):
|
|||
AccountMixin.NORMAL,
|
||||
AccountMixin.CHAN, AccountMixin.MAILINGLIST):
|
||||
try:
|
||||
newLabel = unicode(
|
||||
config.get(self.address, 'label'),
|
||||
'utf-8', 'ignore')
|
||||
newLabel = unic(ustr(config.get(self.address, 'label')))
|
||||
except:
|
||||
queryreturn = sqlQuery(
|
||||
'''select label from addressbook where address=?''', self.address)
|
||||
'SELECT label FROM addressbook WHERE address=?',
|
||||
dbstr(self.address))
|
||||
elif self.type == AccountMixin.SUBSCRIPTION:
|
||||
queryreturn = sqlQuery(
|
||||
'''select label from subscriptions where address=?''', self.address)
|
||||
'SELECT label FROM subscriptions WHERE address=?',
|
||||
dbstr(self.address))
|
||||
if queryreturn:
|
||||
for row in queryreturn:
|
||||
newLabel = unicode(row[0], 'utf-8', 'ignore')
|
||||
newLabel = unic(ustr(queryreturn[-1][0]))
|
||||
|
||||
self.label = newLabel
|
||||
|
||||
|
@ -438,7 +438,7 @@ class MessageList_AddressWidget(BMAddressWidget):
|
|||
def __lt__(self, other):
|
||||
if isinstance(other, MessageList_AddressWidget):
|
||||
return self.label.lower() < other.label.lower()
|
||||
return super(QtGui.QTableWidgetItem, self).__lt__(other)
|
||||
return super(MessageList_AddressWidget, self).__lt__(other)
|
||||
|
||||
|
||||
class MessageList_SubjectWidget(BMTableWidgetItem):
|
||||
|
@ -454,16 +454,16 @@ class MessageList_SubjectWidget(BMTableWidgetItem):
|
|||
def data(self, role):
|
||||
"""Return object data (QT UI)"""
|
||||
if role == QtCore.Qt.UserRole:
|
||||
return self.subject
|
||||
return ustr(self.subject)
|
||||
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)
|
||||
|
||||
# label (or address) alphabetically, disabled at the end
|
||||
def __lt__(self, other):
|
||||
if isinstance(other, MessageList_SubjectWidget):
|
||||
return self.label.lower() < other.label.lower()
|
||||
return super(QtGui.QTableWidgetItem, self).__lt__(other)
|
||||
return super(MessageList_SubjectWidget, self).__lt__(other)
|
||||
|
||||
|
||||
# In order for the time columns on the Inbox and Sent tabs to be sorted
|
||||
|
@ -476,9 +476,9 @@ class MessageList_TimeWidget(BMTableWidgetItem):
|
|||
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)
|
||||
self.setData(QtCore.Qt.UserRole, QtCore.QByteArray(msgid))
|
||||
self.setData(QtCore.Qt.UserRole, QtCore.QByteArray(bytes(msgid)))
|
||||
self.setData(TimestampRole, int(timestamp))
|
||||
|
||||
def __lt__(self, other):
|
||||
|
@ -491,15 +491,14 @@ class MessageList_TimeWidget(BMTableWidgetItem):
|
|||
"""
|
||||
data = super(MessageList_TimeWidget, self).data(role)
|
||||
if role == TimestampRole:
|
||||
return int(data.toPyObject())
|
||||
return int(data)
|
||||
if role == QtCore.Qt.UserRole:
|
||||
return str(data.toPyObject())
|
||||
return ustr(data)
|
||||
return data
|
||||
|
||||
|
||||
class Ui_AddressBookWidgetItem(BMAddressWidget):
|
||||
"""Addressbook item"""
|
||||
# pylint: disable=unused-argument
|
||||
def __init__(self, label=None, acc_type=AccountMixin.NORMAL):
|
||||
self.type = acc_type
|
||||
super(Ui_AddressBookWidgetItem, self).__init__(label=label)
|
||||
|
@ -513,10 +512,7 @@ class Ui_AddressBookWidgetItem(BMAddressWidget):
|
|||
def setData(self, role, value):
|
||||
"""Set data"""
|
||||
if role == QtCore.Qt.EditRole:
|
||||
self.label = str(
|
||||
value.toString().toUtf8()
|
||||
if isinstance(value, QtCore.QVariant) else value
|
||||
)
|
||||
self.label = ustr(value)
|
||||
if self.type in (
|
||||
AccountMixin.NORMAL,
|
||||
AccountMixin.MAILINGLIST, AccountMixin.CHAN):
|
||||
|
@ -525,28 +521,33 @@ class Ui_AddressBookWidgetItem(BMAddressWidget):
|
|||
config.set(self.address, 'label', self.label)
|
||||
config.save()
|
||||
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:
|
||||
sqlExecute('''UPDATE subscriptions set label=? WHERE address=?''', self.label, self.address)
|
||||
else:
|
||||
pass
|
||||
sqlExecute(
|
||||
'UPDATE subscriptions SET label=? WHERE address=?',
|
||||
dbstr(self.label), dbstr(self.address))
|
||||
return super(Ui_AddressBookWidgetItem, self).setData(role, value)
|
||||
|
||||
def __lt__(self, other):
|
||||
if isinstance(other, Ui_AddressBookWidgetItem):
|
||||
if not isinstance(other, Ui_AddressBookWidgetItem):
|
||||
return super(Ui_AddressBookWidgetItem, self).__lt__(other)
|
||||
|
||||
reverse = QtCore.Qt.DescendingOrder == \
|
||||
self.tableWidget().horizontalHeader().sortIndicatorOrder()
|
||||
|
||||
if self.type == other.type:
|
||||
return self.label.lower() < other.label.lower()
|
||||
|
||||
return not reverse if self.type < other.type else reverse
|
||||
return super(QtGui.QTableWidgetItem, self).__lt__(other)
|
||||
|
||||
|
||||
class Ui_AddressBookWidgetItemLabel(Ui_AddressBookWidgetItem):
|
||||
"""Addressbook label item"""
|
||||
def __init__(self, address, label, acc_type):
|
||||
self.address = address
|
||||
self.address = ustr(address)
|
||||
super(Ui_AddressBookWidgetItemLabel, self).__init__(label, acc_type)
|
||||
|
||||
def data(self, role):
|
||||
|
@ -558,7 +559,7 @@ class Ui_AddressBookWidgetItemLabel(Ui_AddressBookWidgetItem):
|
|||
class Ui_AddressBookWidgetItemAddress(Ui_AddressBookWidgetItem):
|
||||
"""Addressbook address item"""
|
||||
def __init__(self, address, label, acc_type):
|
||||
self.address = address
|
||||
self.address = ustr(address)
|
||||
super(Ui_AddressBookWidgetItemAddress, self).__init__(address, acc_type)
|
||||
|
||||
def data(self, role):
|
||||
|
@ -570,28 +571,27 @@ class Ui_AddressBookWidgetItemAddress(Ui_AddressBookWidgetItem):
|
|||
return super(Ui_AddressBookWidgetItemAddress, self).data(role)
|
||||
|
||||
|
||||
class AddressBookCompleter(QtGui.QCompleter):
|
||||
class AddressBookCompleter(QtWidgets.QCompleter):
|
||||
"""Addressbook completer"""
|
||||
|
||||
def __init__(self):
|
||||
super(AddressBookCompleter, self).__init__()
|
||||
self.cursorPos = -1
|
||||
|
||||
def onCursorPositionChanged(self, oldPos, newPos): # pylint: disable=unused-argument
|
||||
def onCursorPositionChanged(self, oldPos, newPos):
|
||||
"""Callback for cursor position change"""
|
||||
# pylint: disable=unused-argument
|
||||
if oldPos != self.cursorPos:
|
||||
self.cursorPos = -1
|
||||
|
||||
def splitPath(self, path):
|
||||
"""Split on semicolon"""
|
||||
text = unicode(path.toUtf8(), 'utf-8')
|
||||
text = unic(ustr(path))
|
||||
return [text[:self.widget().cursorPosition()].split(';')[-1].strip()]
|
||||
|
||||
def pathFromIndex(self, index):
|
||||
"""Perform autocompletion (reimplemented QCompleter method)"""
|
||||
autoString = unicode(
|
||||
index.data(QtCore.Qt.EditRole).toString().toUtf8(), 'utf-8')
|
||||
text = unicode(self.widget().text().toUtf8(), 'utf-8')
|
||||
autoString = unic(ustr(index.data(QtCore.Qt.EditRole).toString()))
|
||||
text = unic(ustr(self.widget().text()))
|
||||
|
||||
# If cursor position was saved, restore it, else save it
|
||||
if self.cursorPos != -1:
|
||||
|
@ -620,7 +620,6 @@ class AddressBookCompleter(QtGui.QCompleter):
|
|||
|
||||
# Get string value from before auto finished string is selected
|
||||
# pre = text[prevDelimiterIndex + 1:curIndex - 1]
|
||||
|
||||
# Get part of string that occurs AFTER cursor
|
||||
part2 = text[nextDelimiterIndex:]
|
||||
|
||||
|
|
|
@ -1,48 +1,56 @@
|
|||
"""Language Box Module for Locale Settings"""
|
||||
# pylint: disable=too-few-public-methods,bad-continuation
|
||||
"""LanguageBox widget is for selecting UI language"""
|
||||
|
||||
import glob
|
||||
import os
|
||||
|
||||
from PyQt4 import QtCore, QtGui
|
||||
from qtpy import QtCore, QtWidgets
|
||||
|
||||
import paths
|
||||
from bmconfigparser import config
|
||||
from tr import _translate
|
||||
|
||||
|
||||
class LanguageBox(QtGui.QComboBox):
|
||||
"""LanguageBox class for Qt UI"""
|
||||
# pylint: disable=too-few-public-methods
|
||||
class LanguageBox(QtWidgets.QComboBox):
|
||||
"""A subclass of `QtWidgets.QComboBox` for selecting language"""
|
||||
languageName = {
|
||||
"system": "System Settings", "eo": "Esperanto",
|
||||
"system": "System Settings",
|
||||
"eo": "Esperanto",
|
||||
"en_pirate": "Pirate English"
|
||||
}
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super(QtGui.QComboBox, self).__init__(parent)
|
||||
super(LanguageBox, self).__init__(parent)
|
||||
self.populate()
|
||||
|
||||
def populate(self):
|
||||
"""Populates drop down list with all available languages."""
|
||||
self.clear()
|
||||
localesPath = os.path.join(paths.codePath(), 'translations')
|
||||
self.addItem(QtGui.QApplication.translate(
|
||||
"settingsDialog", "System Settings", "system"), "system")
|
||||
self.addItem(
|
||||
_translate("settingsDialog", "System Settings", "system"),
|
||||
"system"
|
||||
)
|
||||
self.setCurrentIndex(0)
|
||||
self.setInsertPolicy(QtGui.QComboBox.InsertAlphabetically)
|
||||
self.setInsertPolicy(QtWidgets.QComboBox.InsertAlphabetically)
|
||||
for translationFile in sorted(
|
||||
glob.glob(os.path.join(localesPath, "bitmessage_*.qm"))
|
||||
):
|
||||
localeShort = \
|
||||
os.path.split(translationFile)[1].split("_", 1)[1][:-3]
|
||||
locale = QtCore.QLocale(localeShort)
|
||||
if localeShort in LanguageBox.languageName:
|
||||
self.addItem(
|
||||
LanguageBox.languageName[localeShort], localeShort)
|
||||
elif locale.nativeLanguageName() == "":
|
||||
self.addItem(localeShort, localeShort)
|
||||
else:
|
||||
locale = QtCore.QLocale(localeShort)
|
||||
self.addItem(
|
||||
locale.nativeLanguageName() or localeShort, localeShort)
|
||||
|
||||
configuredLocale = config.safeGet(
|
||||
'bitmessagesettings', 'userlocale', "system")
|
||||
'bitmessagesettings', 'userlocale', 'system')
|
||||
for i in range(self.count()):
|
||||
if self.itemData(i) == configuredLocale:
|
||||
self.setCurrentIndex(i)
|
||||
|
|
|
@ -1,33 +1,34 @@
|
|||
"""
|
||||
Message editor with a wheel zoom functionality
|
||||
"""
|
||||
# pylint: disable=bad-continuation
|
||||
"""The MessageCompose class definition"""
|
||||
|
||||
from PyQt4 import QtCore, QtGui
|
||||
from qtpy import QtCore, QtWidgets
|
||||
from tr import _translate
|
||||
|
||||
|
||||
class MessageCompose(QtGui.QTextEdit):
|
||||
class MessageCompose(QtWidgets.QTextEdit):
|
||||
"""Editor class with wheel zoom functionality"""
|
||||
def __init__(self, parent=0):
|
||||
def __init__(self, parent=None):
|
||||
super(MessageCompose, self).__init__(parent)
|
||||
# we'll deal with this later when we have a new message format
|
||||
self.setAcceptRichText(False)
|
||||
self.defaultFontPointSize = self.currentFont().pointSize()
|
||||
|
||||
def wheelEvent(self, event):
|
||||
"""Mouse wheel scroll event handler"""
|
||||
if (
|
||||
QtGui.QApplication.queryKeyboardModifiers() & QtCore.Qt.ControlModifier
|
||||
) == QtCore.Qt.ControlModifier and event.orientation() == QtCore.Qt.Vertical:
|
||||
(QtWidgets.QApplication.queryKeyboardModifiers()
|
||||
& QtCore.Qt.ControlModifier) == QtCore.Qt.ControlModifier
|
||||
and event.angleDelta().y() != 0
|
||||
):
|
||||
if event.delta() > 0:
|
||||
self.zoomIn(1)
|
||||
else:
|
||||
self.zoomOut(1)
|
||||
zoom = self.currentFont().pointSize() * 100 / self.defaultFontPointSize
|
||||
QtGui.QApplication.activeWindow().statusBar().showMessage(
|
||||
QtGui.QApplication.translate("MainWindow", "Zoom level %1%").arg(
|
||||
str(zoom)
|
||||
)
|
||||
)
|
||||
QtWidgets.QApplication.activeWindow().statusbar.showMessage(
|
||||
_translate("MainWindow", "Zoom level {0}%").format(
|
||||
# zoom percentage
|
||||
self.currentFont().pointSize() * 100
|
||||
/ self.defaultFontPointSize
|
||||
))
|
||||
else:
|
||||
# in QTextEdit, super does not zoom, only scroll
|
||||
super(MessageCompose, self).wheelEvent(event)
|
||||
|
|
|
@ -1,22 +1,22 @@
|
|||
"""
|
||||
Custom message viewer with support for switching between HTML and plain
|
||||
text rendering, HTML sanitization, lazy rendering (as you scroll down),
|
||||
zoom and URL click warning popup
|
||||
|
||||
zoom and URL click warning popup.
|
||||
"""
|
||||
|
||||
from PyQt4 import QtCore, QtGui
|
||||
from unqstr import ustr, unic
|
||||
from qtpy import QtCore, QtGui, QtWidgets
|
||||
|
||||
from safehtmlparser import SafeHTMLParser
|
||||
from .safehtmlparser import SafeHTMLParser
|
||||
from tr import _translate
|
||||
|
||||
|
||||
class MessageView(QtGui.QTextBrowser):
|
||||
class MessageView(QtWidgets.QTextBrowser):
|
||||
"""Message content viewer class, can switch between plaintext and HTML"""
|
||||
MODE_PLAIN = 0
|
||||
MODE_HTML = 1
|
||||
|
||||
def __init__(self, parent=0):
|
||||
def __init__(self, parent=None):
|
||||
super(MessageView, self).__init__(parent)
|
||||
self.mode = MessageView.MODE_PLAIN
|
||||
self.html = None
|
||||
|
@ -38,8 +38,11 @@ class MessageView(QtGui.QTextBrowser):
|
|||
|
||||
def mousePressEvent(self, event):
|
||||
"""Mouse press button event handler"""
|
||||
if event.button() == QtCore.Qt.LeftButton and self.html and self.html.has_html and self.cursorForPosition(
|
||||
event.pos()).block().blockNumber() == 0:
|
||||
if (
|
||||
event.button() == QtCore.Qt.LeftButton
|
||||
and self.html and self.html.has_html
|
||||
and self.cursorForPosition(event.pos()).block().blockNumber() == 0
|
||||
):
|
||||
if self.mode == MessageView.MODE_PLAIN:
|
||||
self.showHTML()
|
||||
else:
|
||||
|
@ -52,23 +55,23 @@ class MessageView(QtGui.QTextBrowser):
|
|||
# super will actually automatically take care of zooming
|
||||
super(MessageView, self).wheelEvent(event)
|
||||
if (
|
||||
QtGui.QApplication.queryKeyboardModifiers() & QtCore.Qt.ControlModifier
|
||||
) == QtCore.Qt.ControlModifier and event.orientation() == QtCore.Qt.Vertical:
|
||||
(QtWidgets.QApplication.queryKeyboardModifiers()
|
||||
& QtCore.Qt.ControlModifier) == QtCore.Qt.ControlModifier
|
||||
and event.angleDelta().y() != 0
|
||||
):
|
||||
zoom = self.currentFont().pointSize() * 100 / self.defaultFontPointSize
|
||||
QtGui.QApplication.activeWindow().statusBar().showMessage(_translate(
|
||||
"MainWindow", "Zoom level %1%").arg(str(zoom)))
|
||||
QtWidgets.QApplication.activeWindow().statusbar.showMessage(
|
||||
_translate("MainWindow", "Zoom level {0}%").format(zoom))
|
||||
|
||||
def setWrappingWidth(self, width=None):
|
||||
"""Set word-wrapping width"""
|
||||
self.setLineWrapMode(QtGui.QTextEdit.FixedPixelWidth)
|
||||
if width is None:
|
||||
width = self.width()
|
||||
self.setLineWrapColumnOrWidth(width)
|
||||
self.setLineWrapMode(QtWidgets.QTextEdit.FixedPixelWidth)
|
||||
self.setLineWrapColumnOrWidth(width or self.width())
|
||||
|
||||
def confirmURL(self, link):
|
||||
"""Show a dialog requesting URL opening confirmation"""
|
||||
if link.scheme() == "mailto":
|
||||
window = QtGui.QApplication.activeWindow()
|
||||
window = QtWidgets.QApplication.activeWindow()
|
||||
window.ui.lineEditTo.setText(link.path())
|
||||
if link.hasQueryItem("subject"):
|
||||
window.ui.lineEditSubject.setText(
|
||||
|
@ -83,39 +86,40 @@ class MessageView(QtGui.QTextBrowser):
|
|||
)
|
||||
window.ui.textEditMessage.setFocus()
|
||||
return
|
||||
reply = QtGui.QMessageBox.warning(
|
||||
self,
|
||||
QtGui.QApplication.translate(
|
||||
reply = QtWidgets.QMessageBox.warning(
|
||||
self, _translate("MessageView", "Follow external link"),
|
||||
_translate(
|
||||
"MessageView",
|
||||
"Follow external link"),
|
||||
QtGui.QApplication.translate(
|
||||
"MessageView",
|
||||
"The link \"%1\" 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())),
|
||||
QtGui.QMessageBox.Yes,
|
||||
QtGui.QMessageBox.No)
|
||||
if reply == QtGui.QMessageBox.Yes:
|
||||
"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?"
|
||||
).format(unic(ustr(link.toString()))),
|
||||
QtWidgets.QMessageBox.Yes, QtWidgets.QMessageBox.No)
|
||||
if reply == QtWidgets.QMessageBox.Yes:
|
||||
QtGui.QDesktopServices.openUrl(link)
|
||||
|
||||
def loadResource(self, restype, name):
|
||||
"""
|
||||
Callback for loading referenced objects, such as an image. For security reasons at the moment doesn't do
|
||||
anything)
|
||||
Callback for loading referenced objects, such as an image.
|
||||
For security reasons at the moment doesn't do anything
|
||||
"""
|
||||
pass
|
||||
|
||||
def lazyRender(self):
|
||||
"""
|
||||
Partially render a message. This is to avoid UI freezing when loading huge messages. It continues loading as
|
||||
you scroll down.
|
||||
Partially render a message. This is to avoid UI freezing when
|
||||
loading huge messages. It continues loading as you scroll down.
|
||||
"""
|
||||
if self.rendering:
|
||||
return
|
||||
self.rendering = True
|
||||
position = self.verticalScrollBar().value()
|
||||
cursor = QtGui.QTextCursor(self.document())
|
||||
while self.outpos < len(self.out) and self.verticalScrollBar().value(
|
||||
) >= self.document().size().height() - 2 * self.size().height():
|
||||
while (
|
||||
self.outpos < len(self.out)
|
||||
and self.verticalScrollBar().value()
|
||||
>= self.document().size().height() - 2 * self.size().height()
|
||||
):
|
||||
startpos = self.outpos
|
||||
self.outpos += 10240
|
||||
# find next end of tag
|
||||
|
@ -123,8 +127,9 @@ class MessageView(QtGui.QTextBrowser):
|
|||
pos = self.out.find(">", self.outpos)
|
||||
if pos > self.outpos:
|
||||
self.outpos = pos + 1
|
||||
cursor.movePosition(QtGui.QTextCursor.End, QtGui.QTextCursor.MoveAnchor)
|
||||
cursor.insertHtml(QtCore.QString(self.out[startpos:self.outpos]))
|
||||
cursor.movePosition(
|
||||
QtGui.QTextCursor.End, QtGui.QTextCursor.MoveAnchor)
|
||||
cursor.insertHtml(unic(self.out[startpos:self.outpos]))
|
||||
self.verticalScrollBar().setValue(position)
|
||||
self.rendering = False
|
||||
|
||||
|
@ -133,9 +138,11 @@ class MessageView(QtGui.QTextBrowser):
|
|||
self.mode = MessageView.MODE_PLAIN
|
||||
out = self.html.raw
|
||||
if self.html.has_html:
|
||||
out = "<div align=\"center\" style=\"text-decoration: underline;\"><b>" + unicode(
|
||||
QtGui.QApplication.translate(
|
||||
"MessageView", "HTML detected, click here to display")) + "</b></div><br/>" + out
|
||||
out = (
|
||||
'<div align="center" style="text-decoration: underline;"><b>'
|
||||
+ unic(ustr(_translate(
|
||||
"MessageView", "HTML detected, click here to display"
|
||||
))) + '</b></div><br/>' + out)
|
||||
self.out = out
|
||||
self.outpos = 0
|
||||
self.setHtml("")
|
||||
|
@ -144,10 +151,10 @@ class MessageView(QtGui.QTextBrowser):
|
|||
def showHTML(self):
|
||||
"""Render message as HTML"""
|
||||
self.mode = MessageView.MODE_HTML
|
||||
out = self.html.sanitised
|
||||
out = "<div align=\"center\" style=\"text-decoration: underline;\"><b>" + unicode(
|
||||
QtGui.QApplication.translate("MessageView", "Click here to disable HTML")) + "</b></div><br/>" + out
|
||||
self.out = out
|
||||
self.out = (
|
||||
'<div align="center" style="text-decoration: underline;"><b>'
|
||||
+ _translate("MessageView", "Click here to disable HTML")
|
||||
+ '</b></div><br/>' + self.html.sanitised)
|
||||
self.outpos = 0
|
||||
self.setHtml("")
|
||||
self.lazyRender()
|
||||
|
@ -155,8 +162,6 @@ class MessageView(QtGui.QTextBrowser):
|
|||
def setContent(self, data):
|
||||
"""Set message content from argument"""
|
||||
self.html = SafeHTMLParser()
|
||||
self.html.reset()
|
||||
self.html.reset_safe()
|
||||
self.html.allow_picture = True
|
||||
self.html.feed(data)
|
||||
self.html.close()
|
||||
|
|
|
@ -1,16 +1,15 @@
|
|||
#!/usr/bin/env python2.7
|
||||
from PyQt4 import QtCore, QtGui
|
||||
from qtpy import QtCore, QtWidgets
|
||||
|
||||
class MigrationWizardIntroPage(QtGui.QWizardPage):
|
||||
class MigrationWizardIntroPage(QtWidgets.QWizardPage):
|
||||
def __init__(self):
|
||||
super(QtGui.QWizardPage, self).__init__()
|
||||
super(QtWidgets.QWizardPage, self).__init__()
|
||||
self.setTitle("Migrating configuration")
|
||||
|
||||
label = QtGui.QLabel("This wizard will help you to migrate your configuration. "
|
||||
label = QtWidgets.QLabel("This wizard will help you to migrate your configuration. "
|
||||
"You can still keep using PyBitMessage once you migrate, the changes are backwards compatible.")
|
||||
label.setWordWrap(True)
|
||||
|
||||
layout = QtGui.QVBoxLayout()
|
||||
layout = QtWidgets.QVBoxLayout()
|
||||
layout.addWidget(label)
|
||||
self.setLayout(layout)
|
||||
|
||||
|
@ -18,15 +17,15 @@ class MigrationWizardIntroPage(QtGui.QWizardPage):
|
|||
return 1
|
||||
|
||||
|
||||
class MigrationWizardAddressesPage(QtGui.QWizardPage):
|
||||
class MigrationWizardAddressesPage(QtWidgets.QWizardPage):
|
||||
def __init__(self, addresses):
|
||||
super(QtGui.QWizardPage, self).__init__()
|
||||
super(QtWidgets.QWizardPage, self).__init__()
|
||||
self.setTitle("Addresses")
|
||||
|
||||
label = QtGui.QLabel("Please select addresses that you are already using with mailchuck. ")
|
||||
label = QtWidgets.QLabel("Please select addresses that you are already using with mailchuck. ")
|
||||
label.setWordWrap(True)
|
||||
|
||||
layout = QtGui.QVBoxLayout()
|
||||
layout = QtWidgets.QVBoxLayout()
|
||||
layout.addWidget(label)
|
||||
self.setLayout(layout)
|
||||
|
||||
|
@ -34,15 +33,15 @@ class MigrationWizardAddressesPage(QtGui.QWizardPage):
|
|||
return 10
|
||||
|
||||
|
||||
class MigrationWizardGPUPage(QtGui.QWizardPage):
|
||||
class MigrationWizardGPUPage(QtWidgets.QWizardPage):
|
||||
def __init__(self):
|
||||
super(QtGui.QWizardPage, self).__init__()
|
||||
super(QtWidgets.QWizardPage, self).__init__()
|
||||
self.setTitle("GPU")
|
||||
|
||||
label = QtGui.QLabel("Are you using a GPU? ")
|
||||
label = QtWidgets.QLabel("Are you using a GPU? ")
|
||||
label.setWordWrap(True)
|
||||
|
||||
layout = QtGui.QVBoxLayout()
|
||||
layout = QtWidgets.QVBoxLayout()
|
||||
layout.addWidget(label)
|
||||
self.setLayout(layout)
|
||||
|
||||
|
@ -50,22 +49,22 @@ class MigrationWizardGPUPage(QtGui.QWizardPage):
|
|||
return 10
|
||||
|
||||
|
||||
class MigrationWizardConclusionPage(QtGui.QWizardPage):
|
||||
class MigrationWizardConclusionPage(QtWidgets.QWizardPage):
|
||||
def __init__(self):
|
||||
super(QtGui.QWizardPage, self).__init__()
|
||||
super(QtWidgets.QWizardPage, self).__init__()
|
||||
self.setTitle("All done!")
|
||||
|
||||
label = QtGui.QLabel("You successfully migrated.")
|
||||
label = QtWidgets.QLabel("You successfully migrated.")
|
||||
label.setWordWrap(True)
|
||||
|
||||
layout = QtGui.QVBoxLayout()
|
||||
layout = QtWidgets.QVBoxLayout()
|
||||
layout.addWidget(label)
|
||||
self.setLayout(layout)
|
||||
|
||||
|
||||
class Ui_MigrationWizard(QtGui.QWizard):
|
||||
class Ui_MigrationWizard(QtWidgets.QWizard):
|
||||
def __init__(self, addresses):
|
||||
super(QtGui.QWizard, self).__init__()
|
||||
super(QtWidgets.QWizard, self).__init__()
|
||||
|
||||
self.pages = {}
|
||||
|
||||
|
|
|
@ -4,26 +4,28 @@ Network status tab widget definition.
|
|||
|
||||
import time
|
||||
|
||||
from PyQt4 import QtCore, QtGui
|
||||
from qtpy import QtCore, QtGui, QtWidgets
|
||||
|
||||
import l10n
|
||||
import network.stats
|
||||
import state
|
||||
import widgets
|
||||
from bitmessageqt import widgets
|
||||
from network import connectionpool, knownnodes
|
||||
from retranslateui import RetranslateMixin
|
||||
from .retranslateui import RetranslateMixin
|
||||
from tr import _translate
|
||||
from uisignaler import UISignaler
|
||||
from .uisignaler import UISignaler
|
||||
|
||||
|
||||
class NetworkStatus(QtGui.QWidget, RetranslateMixin):
|
||||
class NetworkStatus(QtWidgets.QWidget, RetranslateMixin):
|
||||
"""Network status tab"""
|
||||
def __init__(self, parent=None):
|
||||
super(NetworkStatus, self).__init__(parent)
|
||||
widgets.load('networkstatus.ui', self)
|
||||
|
||||
header = self.tableWidgetConnectionCount.horizontalHeader()
|
||||
header.setResizeMode(QtGui.QHeaderView.ResizeToContents)
|
||||
header.setSectionResizeMode(QtWidgets.QHeaderView.ResizeToContents)
|
||||
header.setSectionResizeMode(0, QtWidgets.QHeaderView.Stretch)
|
||||
header.setSectionResizeMode(2, QtWidgets.QHeaderView.Stretch)
|
||||
|
||||
# Somehow this value was 5 when I tested
|
||||
if header.sortIndicatorSection() > 4:
|
||||
|
@ -32,20 +34,17 @@ class NetworkStatus(QtGui.QWidget, RetranslateMixin):
|
|||
self.startup = time.localtime()
|
||||
|
||||
self.UISignalThread = UISignaler.get()
|
||||
# pylint: disable=no-member
|
||||
QtCore.QObject.connect(self.UISignalThread, QtCore.SIGNAL(
|
||||
"updateNumberOfMessagesProcessed()"), self.updateNumberOfMessagesProcessed)
|
||||
QtCore.QObject.connect(self.UISignalThread, QtCore.SIGNAL(
|
||||
"updateNumberOfPubkeysProcessed()"), self.updateNumberOfPubkeysProcessed)
|
||||
QtCore.QObject.connect(self.UISignalThread, QtCore.SIGNAL(
|
||||
"updateNumberOfBroadcastsProcessed()"), self.updateNumberOfBroadcastsProcessed)
|
||||
QtCore.QObject.connect(self.UISignalThread, QtCore.SIGNAL(
|
||||
"updateNetworkStatusTab(PyQt_PyObject,PyQt_PyObject,PyQt_PyObject)"), self.updateNetworkStatusTab)
|
||||
self.UISignalThread.updateNumberOfMessagesProcessed.connect(
|
||||
self.updateNumberOfMessagesProcessed)
|
||||
self.UISignalThread.updateNumberOfPubkeysProcessed.connect(
|
||||
self.updateNumberOfPubkeysProcessed)
|
||||
self.UISignalThread.updateNumberOfBroadcastsProcessed.connect(
|
||||
self.updateNumberOfBroadcastsProcessed)
|
||||
self.UISignalThread.updateNetworkStatusTab.connect(
|
||||
self.updateNetworkStatusTab)
|
||||
|
||||
self.timer = QtCore.QTimer()
|
||||
|
||||
QtCore.QObject.connect(self.timer, QtCore.SIGNAL("timeout()"), self.runEveryTwoSeconds)
|
||||
# pylint: enable=no-member
|
||||
self.timer.timeout.connect(self.runEveryTwoSeconds)
|
||||
|
||||
def startUpdate(self):
|
||||
"""Start a timer to update counters every 2 seconds"""
|
||||
|
@ -57,91 +56,66 @@ class NetworkStatus(QtGui.QWidget, RetranslateMixin):
|
|||
"""Stop counter update timer"""
|
||||
self.timer.stop()
|
||||
|
||||
def formatBytes(self, num):
|
||||
@staticmethod
|
||||
def formatBytes(num):
|
||||
"""Format bytes nicely (SI prefixes)"""
|
||||
# pylint: disable=no-self-use
|
||||
for x in [
|
||||
_translate(
|
||||
"networkstatus",
|
||||
"byte(s)",
|
||||
None,
|
||||
QtCore.QCoreApplication.CodecForTr,
|
||||
num),
|
||||
"kB",
|
||||
"MB",
|
||||
"GB",
|
||||
]:
|
||||
for x in (
|
||||
_translate("networkstatus", "byte(s)", None, num),
|
||||
"kB", "MB", "GB"
|
||||
):
|
||||
if num < 1000.0:
|
||||
return "%3.0f %s" % (num, x)
|
||||
num /= 1000.0
|
||||
return "%3.0f %s" % (num, 'TB')
|
||||
return "%3.0f %s" % (num, "TB")
|
||||
|
||||
def formatByteRate(self, num):
|
||||
@staticmethod
|
||||
def formatByteRate(num):
|
||||
"""Format transfer speed in kB/s"""
|
||||
# pylint: disable=no-self-use
|
||||
num /= 1000
|
||||
return "%4.0f kB" % num
|
||||
|
||||
def updateNumberOfObjectsToBeSynced(self):
|
||||
"""Update the counter for number of objects to be synced"""
|
||||
self.labelSyncStatus.setText(
|
||||
_translate(
|
||||
"networkstatus",
|
||||
"Object(s) to be synced: %n",
|
||||
None,
|
||||
QtCore.QCoreApplication.CodecForTr,
|
||||
network.stats.pendingDownload()
|
||||
+ network.stats.pendingUpload()))
|
||||
self.labelSyncStatus.setText(_translate(
|
||||
"networkstatus", "Object(s) to be synced: %n", None,
|
||||
network.stats.pendingDownload() + network.stats.pendingUpload()))
|
||||
|
||||
def updateNumberOfMessagesProcessed(self):
|
||||
"""Update the counter for number of processed messages"""
|
||||
self.updateNumberOfObjectsToBeSynced()
|
||||
self.labelMessageCount.setText(
|
||||
_translate(
|
||||
"networkstatus",
|
||||
"Processed %n person-to-person message(s).",
|
||||
None,
|
||||
QtCore.QCoreApplication.CodecForTr,
|
||||
state.numberOfMessagesProcessed))
|
||||
self.labelMessageCount.setText(_translate(
|
||||
"networkstatus", "Processed %n person-to-person message(s).",
|
||||
None, state.numberOfMessagesProcessed))
|
||||
|
||||
def updateNumberOfBroadcastsProcessed(self):
|
||||
"""Update the counter for the number of processed broadcasts"""
|
||||
self.updateNumberOfObjectsToBeSynced()
|
||||
self.labelBroadcastCount.setText(
|
||||
_translate(
|
||||
"networkstatus",
|
||||
"Processed %n broadcast message(s).",
|
||||
None,
|
||||
QtCore.QCoreApplication.CodecForTr,
|
||||
self.labelBroadcastCount.setText(_translate(
|
||||
"networkstatus", "Processed %n broadcast message(s).", None,
|
||||
state.numberOfBroadcastsProcessed))
|
||||
|
||||
def updateNumberOfPubkeysProcessed(self):
|
||||
"""Update the counter for the number of processed pubkeys"""
|
||||
self.updateNumberOfObjectsToBeSynced()
|
||||
self.labelPubkeyCount.setText(
|
||||
_translate(
|
||||
"networkstatus",
|
||||
"Processed %n public key(s).",
|
||||
None,
|
||||
QtCore.QCoreApplication.CodecForTr,
|
||||
self.labelPubkeyCount.setText(_translate(
|
||||
"networkstatus", "Processed %n public key(s).", None,
|
||||
state.numberOfPubkeysProcessed))
|
||||
|
||||
def updateNumberOfBytes(self):
|
||||
"""
|
||||
This function is run every two seconds, so we divide the rate of bytes
|
||||
sent and received by 2.
|
||||
This function is run every two seconds, so we divide the rate
|
||||
of bytes sent and received by 2.
|
||||
"""
|
||||
self.labelBytesRecvCount.setText(
|
||||
_translate(
|
||||
"networkstatus",
|
||||
"Down: %1/s Total: %2").arg(
|
||||
self.labelBytesRecvCount.setText(_translate(
|
||||
"networkstatus", "Down: {0}/s Total: {1}").format(
|
||||
self.formatByteRate(network.stats.downloadSpeed()),
|
||||
self.formatBytes(network.stats.receivedBytes())))
|
||||
self.labelBytesSentCount.setText(
|
||||
_translate(
|
||||
"networkstatus", "Up: %1/s Total: %2").arg(
|
||||
self.formatBytes(network.stats.receivedBytes())
|
||||
))
|
||||
self.labelBytesSentCount.setText(_translate(
|
||||
"networkstatus", "Up: {0}/s Total: {1}").format(
|
||||
self.formatByteRate(network.stats.uploadSpeed()),
|
||||
self.formatBytes(network.stats.sentBytes())))
|
||||
self.formatBytes(network.stats.sentBytes())
|
||||
))
|
||||
|
||||
def updateNetworkStatusTab(self, outbound, add, destination):
|
||||
"""Add or remove an entry to the list of connected peers"""
|
||||
|
@ -168,67 +142,67 @@ class NetworkStatus(QtGui.QWidget, RetranslateMixin):
|
|||
if add:
|
||||
self.tableWidgetConnectionCount.insertRow(0)
|
||||
self.tableWidgetConnectionCount.setItem(
|
||||
0, 0,
|
||||
QtGui.QTableWidgetItem("%s:%i" % (destination.host, destination.port))
|
||||
)
|
||||
0, 0, QtWidgets.QTableWidgetItem(
|
||||
"%s:%i" % (destination.host, destination.port)))
|
||||
self.tableWidgetConnectionCount.setItem(
|
||||
0, 2,
|
||||
QtGui.QTableWidgetItem("%s" % (c.userAgent))
|
||||
)
|
||||
0, 2, QtWidgets.QTableWidgetItem("%s" % (c.userAgent.decode("utf-8", "replace"))))
|
||||
self.tableWidgetConnectionCount.setItem(
|
||||
0, 3,
|
||||
QtGui.QTableWidgetItem("%s" % (c.tlsVersion))
|
||||
)
|
||||
0, 3, QtWidgets.QTableWidgetItem("%s" % (c.tlsVersion)))
|
||||
self.tableWidgetConnectionCount.setItem(
|
||||
0, 4,
|
||||
QtGui.QTableWidgetItem("%s" % (",".join(map(str, c.streams))))
|
||||
)
|
||||
0, 4, QtWidgets.QTableWidgetItem(
|
||||
"%s" % ",".join(map(str, c.streams))))
|
||||
try:
|
||||
# .. todo:: FIXME: hard coded stream no
|
||||
rating = "%.1f" % (knownnodes.knownNodes[1][destination]['rating'])
|
||||
rating = "%.1f" % knownnodes.knownNodes[1][destination]['rating']
|
||||
except KeyError:
|
||||
rating = "-"
|
||||
self.tableWidgetConnectionCount.setItem(
|
||||
0, 1,
|
||||
QtGui.QTableWidgetItem("%s" % (rating))
|
||||
)
|
||||
0, 1, QtWidgets.QTableWidgetItem("%s" % (rating)))
|
||||
if outbound:
|
||||
brush = QtGui.QBrush(QtGui.QColor("yellow"), QtCore.Qt.SolidPattern)
|
||||
brush = QtGui.QBrush(
|
||||
QtGui.QColor("yellow"), QtCore.Qt.SolidPattern)
|
||||
else:
|
||||
brush = QtGui.QBrush(QtGui.QColor("green"), QtCore.Qt.SolidPattern)
|
||||
brush = QtGui.QBrush(
|
||||
QtGui.QColor("green"), QtCore.Qt.SolidPattern)
|
||||
for j in range(1):
|
||||
self.tableWidgetConnectionCount.item(0, j).setBackground(brush)
|
||||
self.tableWidgetConnectionCount.item(0, 0).setData(QtCore.Qt.UserRole, destination)
|
||||
self.tableWidgetConnectionCount.item(0, 1).setData(QtCore.Qt.UserRole, outbound)
|
||||
self.tableWidgetConnectionCount.item(0, 0).setData(
|
||||
QtCore.Qt.UserRole, destination)
|
||||
self.tableWidgetConnectionCount.item(0, 1).setData(
|
||||
QtCore.Qt.UserRole, outbound)
|
||||
else:
|
||||
if not connectionpool.pool.inboundConnections:
|
||||
self.window().setStatusIcon('yellow')
|
||||
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
|
||||
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)
|
||||
break
|
||||
|
||||
self.tableWidgetConnectionCount.setUpdatesEnabled(True)
|
||||
self.tableWidgetConnectionCount.setSortingEnabled(True)
|
||||
self.labelTotalConnections.setText(
|
||||
_translate(
|
||||
"networkstatus", "Total Connections: %1").arg(
|
||||
str(self.tableWidgetConnectionCount.rowCount())))
|
||||
# FYI: The 'singlelistener' thread sets the icon color to green when it
|
||||
# receives an incoming connection, meaning that the user's firewall is
|
||||
# configured correctly.
|
||||
if self.tableWidgetConnectionCount.rowCount() and state.statusIconColor == 'red':
|
||||
self.labelTotalConnections.setText(_translate(
|
||||
"networkstatus", "Total Connections: {0}").format(
|
||||
self.tableWidgetConnectionCount.rowCount()
|
||||
))
|
||||
# FYI: The 'singlelistener' thread sets the icon color to green
|
||||
# when it receives an incoming connection, meaning that the user's
|
||||
# firewall is configured correctly.
|
||||
if self.tableWidgetConnectionCount.rowCount():
|
||||
if state.statusIconColor == 'red':
|
||||
self.window().setStatusIcon('yellow')
|
||||
elif self.tableWidgetConnectionCount.rowCount() == 0 and state.statusIconColor != "red":
|
||||
elif state.statusIconColor != 'red':
|
||||
self.window().setStatusIcon('red')
|
||||
|
||||
# timer driven
|
||||
def runEveryTwoSeconds(self):
|
||||
"""Updates counters, runs every 2 seconds if the timer is running"""
|
||||
self.labelLookupsPerSecond.setText(_translate("networkstatus", "Inventory lookups per second: %1").arg(
|
||||
str(state.Inventory.numberOfInventoryLookupsPerformed / 2)))
|
||||
self.labelLookupsPerSecond.setText(_translate(
|
||||
"networkstatus", "Inventory lookups per second: {0}"
|
||||
).format(state.Inventory.numberOfInventoryLookupsPerformed / 2))
|
||||
state.Inventory.numberOfInventoryLookupsPerformed = 0
|
||||
self.updateNumberOfBytes()
|
||||
self.updateNumberOfObjectsToBeSynced()
|
||||
|
@ -236,13 +210,12 @@ class NetworkStatus(QtGui.QWidget, RetranslateMixin):
|
|||
def retranslateUi(self):
|
||||
"""Conventional Qt Designer method for dynamic l10n"""
|
||||
super(NetworkStatus, self).retranslateUi()
|
||||
self.labelTotalConnections.setText(
|
||||
_translate(
|
||||
"networkstatus", "Total Connections: %1").arg(
|
||||
str(self.tableWidgetConnectionCount.rowCount())))
|
||||
self.labelTotalConnections.setText(_translate(
|
||||
"networkstatus", "Total Connections: {0}"
|
||||
).format(self.tableWidgetConnectionCount.rowCount()))
|
||||
self.labelStartupTime.setText(_translate(
|
||||
"networkstatus", "Since startup on %1"
|
||||
).arg(l10n.formatTimestamp(self.startup)))
|
||||
"networkstatus", "Since startup on {0}"
|
||||
).format(l10n.formatTimestamp(self.startup)))
|
||||
self.updateNumberOfMessagesProcessed()
|
||||
self.updateNumberOfBroadcastsProcessed()
|
||||
self.updateNumberOfPubkeysProcessed()
|
||||
|
|
|
@ -100,6 +100,9 @@
|
|||
<property name="sortingEnabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<attribute name="horizontalHeaderCascadingSectionResizes">
|
||||
<bool>true</bool>
|
||||
</attribute>
|
||||
|
@ -109,9 +112,6 @@
|
|||
<attribute name="horizontalHeaderHighlightSections">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
<attribute name="horizontalHeaderStretchLastSection">
|
||||
<bool>true</bool>
|
||||
</attribute>
|
||||
<attribute name="verticalHeaderVisible">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
|
@ -296,11 +296,8 @@
|
|||
<customwidget>
|
||||
<class>STableWidget</class>
|
||||
<extends>QTableWidget</extends>
|
||||
<header>bitmessageqt/settingsmixin.h</header>
|
||||
<header>bitmessageqt.settingsmixin</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources>
|
||||
<include location="bitmessage_icons.qrc"/>
|
||||
</resources>
|
||||
<connections/>
|
||||
</ui>
|
||||
|
|
|
@ -375,7 +375,7 @@ The 'Random Number' option is selected by default but deterministic addresses ha
|
|||
<sender>radioButtonDeterministicAddress</sender>
|
||||
<signal>toggled(bool)</signal>
|
||||
<receiver>groupBoxDeterministic</receiver>
|
||||
<slot>setShown(bool)</slot>
|
||||
<slot>setVisible(bool)</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>92</x>
|
||||
|
@ -391,7 +391,7 @@ The 'Random Number' option is selected by default but deterministic addresses ha
|
|||
<sender>radioButtonRandomAddress</sender>
|
||||
<signal>toggled(bool)</signal>
|
||||
<receiver>groupBox</receiver>
|
||||
<slot>setShown(bool)</slot>
|
||||
<slot>setVisible(bool)</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>72</x>
|
||||
|
|
|
@ -1,44 +1,34 @@
|
|||
"""
|
||||
src/bitmessageqt/newchandialog.py
|
||||
=================================
|
||||
|
||||
NewChanDialog class definition
|
||||
"""
|
||||
|
||||
from PyQt4 import QtCore, QtGui
|
||||
from unqstr import ustr, unic
|
||||
from qtpy import QtCore, QtWidgets
|
||||
|
||||
import widgets
|
||||
from bitmessageqt import widgets
|
||||
from addresses import addBMIfNotPresent
|
||||
from addressvalidator import AddressValidator, PassPhraseValidator
|
||||
from .addressvalidator import AddressValidator, PassPhraseValidator
|
||||
from queues import (
|
||||
addressGeneratorQueue, apiAddressGeneratorReturnQueue, UISignalQueue)
|
||||
from tr import _translate
|
||||
from utils import str_chan
|
||||
from .utils import str_chan
|
||||
|
||||
|
||||
class NewChanDialog(QtGui.QDialog):
|
||||
"""The `New Chan` dialog"""
|
||||
class NewChanDialog(QtWidgets.QDialog):
|
||||
"""The "New Chan" dialog"""
|
||||
def __init__(self, parent=None):
|
||||
super(NewChanDialog, self).__init__(parent)
|
||||
widgets.load('newchandialog.ui', self)
|
||||
self.parent = parent
|
||||
self.chanAddress.setValidator(
|
||||
AddressValidator(
|
||||
self.chanAddress,
|
||||
self.chanPassPhrase,
|
||||
self.validatorFeedback,
|
||||
self.buttonBox,
|
||||
False))
|
||||
self.chanPassPhrase.setValidator(
|
||||
PassPhraseValidator(
|
||||
self.chanPassPhrase,
|
||||
self.chanAddress,
|
||||
self.validatorFeedback,
|
||||
self.buttonBox,
|
||||
False))
|
||||
self.chanAddress.setValidator(AddressValidator(
|
||||
self.chanAddress, self.chanPassPhrase, self.validatorFeedback,
|
||||
self.buttonBox.button(QtWidgets.QDialogButtonBox.Ok), False))
|
||||
self.chanPassPhrase.setValidator(PassPhraseValidator(
|
||||
self.chanPassPhrase, self.chanAddress, self.validatorFeedback,
|
||||
self.buttonBox.button(QtWidgets.QDialogButtonBox.Ok), False))
|
||||
|
||||
self.timer = QtCore.QTimer()
|
||||
QtCore.QObject.connect( # pylint: disable=no-member
|
||||
self.timer, QtCore.SIGNAL("timeout()"), self.delayedUpdateStatus)
|
||||
self.timer.timeout.connect(self.delayedUpdateStatus)
|
||||
self.timer.start(500) # milliseconds
|
||||
self.setAttribute(QtCore.Qt.WA_DeleteOnClose)
|
||||
self.show()
|
||||
|
@ -52,32 +42,38 @@ class NewChanDialog(QtGui.QDialog):
|
|||
self.timer.stop()
|
||||
self.hide()
|
||||
apiAddressGeneratorReturnQueue.queue.clear()
|
||||
if self.chanAddress.text().toUtf8() == "":
|
||||
if ustr(self.chanAddress.text()) == "":
|
||||
addressGeneratorQueue.put(
|
||||
('createChan', 4, 1, str_chan + ' ' + str(self.chanPassPhrase.text().toUtf8()),
|
||||
self.chanPassPhrase.text().toUtf8(),
|
||||
('createChan', 4, 1, str_chan + ' ' + ustr(self.chanPassPhrase.text()),
|
||||
ustr(self.chanPassPhrase.text()).encode("utf-8", "replace"),
|
||||
True))
|
||||
else:
|
||||
addressGeneratorQueue.put(
|
||||
('joinChan', addBMIfNotPresent(self.chanAddress.text().toUtf8()),
|
||||
str_chan + ' ' + str(self.chanPassPhrase.text().toUtf8()),
|
||||
self.chanPassPhrase.text().toUtf8(),
|
||||
('joinChan', addBMIfNotPresent(ustr(self.chanAddress.text())),
|
||||
str_chan + ' ' + ustr(self.chanPassPhrase.text()),
|
||||
ustr(self.chanPassPhrase.text()).encode("utf-8", "replace"),
|
||||
True))
|
||||
addressGeneratorReturnValue = apiAddressGeneratorReturnQueue.get(True)
|
||||
if addressGeneratorReturnValue and addressGeneratorReturnValue[0] != 'chan name does not match address':
|
||||
if len(addressGeneratorReturnValue) > 0 and addressGeneratorReturnValue[0] != 'chan name does not match address':
|
||||
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.indexOf(self.parent.ui.chans)
|
||||
)
|
||||
self.done(QtGui.QDialog.Accepted)
|
||||
self.done(QtWidgets.QDialog.Accepted)
|
||||
else:
|
||||
UISignalQueue.put(('updateStatusBar', _translate("newchandialog", "Chan creation / joining failed")))
|
||||
self.done(QtGui.QDialog.Rejected)
|
||||
UISignalQueue.put((
|
||||
'updateStatusBar',
|
||||
_translate("newchandialog", "Chan creation / joining failed")
|
||||
))
|
||||
self.done(QtWidgets.QDialog.Rejected)
|
||||
|
||||
def reject(self):
|
||||
"""Cancel joining the chan"""
|
||||
self.timer.stop()
|
||||
self.hide()
|
||||
UISignalQueue.put(('updateStatusBar', _translate("newchandialog", "Chan creation / joining cancelled")))
|
||||
self.done(QtGui.QDialog.Rejected)
|
||||
UISignalQueue.put((
|
||||
'updateStatusBar',
|
||||
_translate("newchandialog", "Chan creation / joining cancelled")
|
||||
))
|
||||
self.done(QtWidgets.QDialog.Rejected)
|
||||
|
|
|
@ -1,20 +1,21 @@
|
|||
from os import path
|
||||
from PyQt4 import QtGui
|
||||
from debug import logger
|
||||
import widgets
|
||||
from unqstr import ustr
|
||||
import six
|
||||
from bitmessageqt import widgets
|
||||
from qtpy import QtWidgets
|
||||
|
||||
|
||||
class RetranslateMixin(object):
|
||||
def retranslateUi(self):
|
||||
defaults = QtGui.QWidget()
|
||||
defaults = QtWidgets.QWidget()
|
||||
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)
|
||||
if callable(setTextMethod):
|
||||
getattr(self, attr).setText(getattr(defaults, attr).text())
|
||||
elif isinstance(value, QtGui.QTableWidget):
|
||||
for i in range (value.columnCount()):
|
||||
getattr(self, attr).setText(ustr(getattr(defaults, attr).text()))
|
||||
elif isinstance(value, QtWidgets.QTableWidget):
|
||||
for i in range(value.columnCount()):
|
||||
getattr(self, attr).horizontalHeaderItem(i).setText(
|
||||
getattr(defaults, attr).horizontalHeaderItem(i).text())
|
||||
for i in range (value.rowCount()):
|
||||
ustr(getattr(defaults, attr).horizontalHeaderItem(i).text()))
|
||||
for i in range(value.rowCount()):
|
||||
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 re
|
||||
from HTMLParser import HTMLParser
|
||||
from six.moves.html_parser import HTMLParser
|
||||
|
||||
from urllib import quote_plus
|
||||
from urlparse import urlparse
|
||||
from six.moves.urllib.parse import quote_plus, urlparse
|
||||
|
||||
from unqstr import ustr, unic
|
||||
|
||||
class SafeHTMLParser(HTMLParser):
|
||||
"""HTML parser with sanitisation"""
|
||||
|
@ -124,9 +124,9 @@ class SafeHTMLParser(HTMLParser):
|
|||
|
||||
def feed(self, data):
|
||||
try:
|
||||
data = unicode(data, 'utf-8')
|
||||
except UnicodeDecodeError:
|
||||
data = unicode(data, 'utf-8', errors='replace')
|
||||
data = unic(ustr(data))
|
||||
except TypeError:
|
||||
pass
|
||||
HTMLParser.feed(self, data)
|
||||
tmp = SafeHTMLParser.replace_pre(data)
|
||||
tmp = self.uriregex1.sub(r'<a href="\1">\1</a>', tmp)
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
"""
|
||||
This module setting file is for settings
|
||||
SettingsDialog class definition
|
||||
"""
|
||||
import ConfigParser
|
||||
from six.moves import configparser
|
||||
import os
|
||||
import sys
|
||||
import tempfile
|
||||
|
||||
from qtpy import QtCore, QtGui, QtWidgets
|
||||
import six
|
||||
from PyQt4 import QtCore, QtGui
|
||||
from unqstr import ustr
|
||||
|
||||
import debug
|
||||
import defaults
|
||||
|
@ -16,7 +17,7 @@ import openclpow
|
|||
import paths
|
||||
import queues
|
||||
import state
|
||||
import widgets
|
||||
from bitmessageqt import widgets
|
||||
from bmconfigparser import config as config_obj
|
||||
from helper_sql import sqlExecute, sqlStoredProcedure
|
||||
from helper_startup import start_proxyconfig
|
||||
|
@ -26,12 +27,18 @@ from network.asyncore_pollchoose import set_rates
|
|||
from tr import _translate
|
||||
|
||||
|
||||
try:
|
||||
SafeConfigParser = configparser.SafeConfigParser
|
||||
except AttributeError:
|
||||
# alpine linux, python3.12
|
||||
SafeConfigParser = configparser.ConfigParser
|
||||
|
||||
def getSOCKSProxyType(config):
|
||||
"""Get user socksproxytype setting from *config*"""
|
||||
try:
|
||||
result = ConfigParser.SafeConfigParser.get(
|
||||
result = SafeConfigParser.get(
|
||||
config, 'bitmessagesettings', 'socksproxytype')
|
||||
except (ConfigParser.NoSectionError, ConfigParser.NoOptionError):
|
||||
except (configparser.NoSectionError, configparser.NoOptionError):
|
||||
return None
|
||||
else:
|
||||
if result.lower() in ('', 'none', 'false'):
|
||||
|
@ -39,14 +46,14 @@ def getSOCKSProxyType(config):
|
|||
return result
|
||||
|
||||
|
||||
class SettingsDialog(QtGui.QDialog):
|
||||
class SettingsDialog(QtWidgets.QDialog):
|
||||
"""The "Settings" dialog"""
|
||||
# pylint: disable=too-many-instance-attributes
|
||||
def __init__(self, parent=None, firstrun=False):
|
||||
super(SettingsDialog, self).__init__(parent)
|
||||
widgets.load('settings.ui', self)
|
||||
|
||||
self.app = QtGui.QApplication.instance()
|
||||
self.app = QtWidgets.QApplication.instance()
|
||||
self.parent = parent
|
||||
self.firstrun = firstrun
|
||||
self.config = config_obj
|
||||
|
@ -83,14 +90,14 @@ class SettingsDialog(QtGui.QDialog):
|
|||
self.tabWidgetSettings.setCurrentIndex(
|
||||
self.tabWidgetSettings.indexOf(self.tabNetworkSettings)
|
||||
)
|
||||
QtGui.QWidget.resize(self, QtGui.QWidget.sizeHint(self))
|
||||
QtWidgets.QWidget.resize(self, QtWidgets.QWidget.sizeHint(self))
|
||||
|
||||
def adjust_from_config(self, config):
|
||||
"""Adjust all widgets state according to config settings"""
|
||||
# pylint: disable=too-many-branches,too-many-statements
|
||||
|
||||
current_style = self.app.get_windowstyle()
|
||||
for i, sk in enumerate(QtGui.QStyleFactory.keys()):
|
||||
for i, sk in enumerate(QtWidgets.QStyleFactory.keys()):
|
||||
self.comboBoxStyle.addItem(sk)
|
||||
if sk == current_style:
|
||||
self.comboBoxStyle.setCurrentIndex(i)
|
||||
|
@ -187,7 +194,7 @@ class SettingsDialog(QtGui.QDialog):
|
|||
else:
|
||||
if self.checkBoxOnionOnly.isChecked():
|
||||
self.checkBoxOnionOnly.setText(
|
||||
self.checkBoxOnionOnly.text() + ", " + _translate(
|
||||
ustr(self.checkBoxOnionOnly.text()) + ", " + _translate(
|
||||
"MainWindow", "may cause connection problems!"))
|
||||
self.checkBoxOnionOnly.setStyleSheet(
|
||||
"QCheckBox { color : red; }")
|
||||
|
@ -324,10 +331,10 @@ class SettingsDialog(QtGui.QDialog):
|
|||
_translate("MainWindow", "Testing..."))
|
||||
nc = namecoin.namecoinConnection({
|
||||
'type': self.getNamecoinType(),
|
||||
'host': str(self.lineEditNamecoinHost.text().toUtf8()),
|
||||
'port': str(self.lineEditNamecoinPort.text().toUtf8()),
|
||||
'user': str(self.lineEditNamecoinUser.text().toUtf8()),
|
||||
'password': str(self.lineEditNamecoinPassword.text().toUtf8())
|
||||
'host': ustr(self.lineEditNamecoinHost.text()),
|
||||
'port': ustr(self.lineEditNamecoinPort.text()),
|
||||
'user': ustr(self.lineEditNamecoinUser.text()),
|
||||
'password': ustr(self.lineEditNamecoinPassword.text())
|
||||
})
|
||||
status, text = nc.test()
|
||||
self.labelNamecoinTestResult.setText(text)
|
||||
|
@ -342,7 +349,7 @@ class SettingsDialog(QtGui.QDialog):
|
|||
|
||||
def choose_font(self):
|
||||
"""Show the font selection dialog"""
|
||||
font, valid = QtGui.QFontDialog.getFont()
|
||||
font, valid = QtWidgets.QFontDialog.getFont()
|
||||
if valid:
|
||||
self.save_font_setting(font)
|
||||
|
||||
|
@ -372,7 +379,7 @@ class SettingsDialog(QtGui.QDialog):
|
|||
self.config.set('bitmessagesettings', 'replybelow', str(
|
||||
self.checkBoxReplyBelow.isChecked()))
|
||||
|
||||
window_style = str(self.comboBoxStyle.currentText())
|
||||
window_style = ustr(self.comboBoxStyle.currentText())
|
||||
if self.app.get_windowstyle() != window_style or self.config.safeGet(
|
||||
'bitmessagesettings', 'font'
|
||||
) != self.font_setting:
|
||||
|
@ -386,8 +393,8 @@ class SettingsDialog(QtGui.QDialog):
|
|||
" the window style or default font."), 1)
|
||||
))
|
||||
|
||||
lang = str(self.languageComboBox.itemData(
|
||||
self.languageComboBox.currentIndex()).toString())
|
||||
lang = ustr(self.languageComboBox.itemData(
|
||||
self.languageComboBox.currentIndex()))
|
||||
self.config.set('bitmessagesettings', 'userlocale', lang)
|
||||
self.parent.change_translation()
|
||||
|
||||
|
@ -469,7 +476,7 @@ class SettingsDialog(QtGui.QDialog):
|
|||
self.config.set('bitmessagesettings', 'maxuploadrate', str(
|
||||
int(float(self.lineEditMaxUploadRate.text()))))
|
||||
except ValueError:
|
||||
QtGui.QMessageBox.about(
|
||||
QtWidgets.QMessageBox.about(
|
||||
self, _translate("MainWindow", "Number needed"),
|
||||
_translate(
|
||||
"MainWindow",
|
||||
|
@ -486,13 +493,13 @@ class SettingsDialog(QtGui.QDialog):
|
|||
|
||||
self.config.set(
|
||||
'bitmessagesettings', 'namecoinrpctype', self.getNamecoinType())
|
||||
self.config.set('bitmessagesettings', 'namecoinrpchost', str(
|
||||
self.config.set('bitmessagesettings', 'namecoinrpchost', ustr(
|
||||
self.lineEditNamecoinHost.text()))
|
||||
self.config.set('bitmessagesettings', 'namecoinrpcport', str(
|
||||
self.config.set('bitmessagesettings', 'namecoinrpcport', ustr(
|
||||
self.lineEditNamecoinPort.text()))
|
||||
self.config.set('bitmessagesettings', 'namecoinrpcuser', str(
|
||||
self.config.set('bitmessagesettings', 'namecoinrpcuser', ustr(
|
||||
self.lineEditNamecoinUser.text()))
|
||||
self.config.set('bitmessagesettings', 'namecoinrpcpassword', str(
|
||||
self.config.set('bitmessagesettings', 'namecoinrpcpassword', ustr(
|
||||
self.lineEditNamecoinPassword.text()))
|
||||
self.parent.resetNamecoinConnection()
|
||||
|
||||
|
@ -510,11 +517,11 @@ class SettingsDialog(QtGui.QDialog):
|
|||
float(self.lineEditSmallMessageDifficulty.text())
|
||||
* defaults.networkDefaultPayloadLengthExtraBytes)))
|
||||
|
||||
if self.comboBoxOpenCL.currentText().toUtf8() != self.config.safeGet(
|
||||
'bitmessagesettings', 'opencl'):
|
||||
if ustr(self.comboBoxOpenCL.currentText()) != ustr(self.config.safeGet(
|
||||
'bitmessagesettings', 'opencl')):
|
||||
self.config.set(
|
||||
'bitmessagesettings', 'opencl',
|
||||
str(self.comboBoxOpenCL.currentText()))
|
||||
ustr(self.comboBoxOpenCL.currentText()))
|
||||
queues.workerQueue.put(('resetPoW', ''))
|
||||
|
||||
acceptableDifficultyChanged = False
|
||||
|
@ -593,7 +600,7 @@ class SettingsDialog(QtGui.QDialog):
|
|||
if state.maximumLengthOfTimeToBotherResendingMessages < 432000:
|
||||
# If the time period is less than 5 hours, we give
|
||||
# zero values to all fields. No message will be sent again.
|
||||
QtGui.QMessageBox.about(
|
||||
QtWidgets.QMessageBox.about(
|
||||
self,
|
||||
_translate("MainWindow", "Will not resend ever"),
|
||||
_translate(
|
||||
|
|
|
@ -1112,9 +1112,6 @@
|
|||
<tabstop>checkBoxSocksListen</tabstop>
|
||||
<tabstop>buttonBox</tabstop>
|
||||
</tabstops>
|
||||
<resources>
|
||||
<include location="bitmessage_icons.qrc"/>
|
||||
</resources>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
|
|
|
@ -1,15 +1,16 @@
|
|||
#!/usr/bin/python2.7
|
||||
"""
|
||||
src/settingsmixin.py
|
||||
====================
|
||||
|
||||
"""
|
||||
|
||||
from PyQt4 import QtCore, QtGui
|
||||
from unqstr import ustr
|
||||
from qtpy import QtCore, QtWidgets
|
||||
|
||||
|
||||
class SettingsMixin(object):
|
||||
"""Mixin for adding geometry and state saving between restarts."""
|
||||
"""Mixin for adding geometry and state saving between restarts"""
|
||||
|
||||
def warnIfNoObjectName(self):
|
||||
"""
|
||||
Handle objects which don't have a name. Currently it ignores them. Objects without a name can't have their
|
||||
|
@ -40,8 +41,9 @@ class SettingsMixin(object):
|
|||
self.warnIfNoObjectName()
|
||||
settings = QtCore.QSettings()
|
||||
try:
|
||||
geom = settings.value("/".join([str(self.objectName()), "geometry"]))
|
||||
target.restoreGeometry(geom.toByteArray() if hasattr(geom, 'toByteArray') else geom)
|
||||
geom = settings.value(
|
||||
"/".join([ustr(self.objectName()), "geometry"]))
|
||||
target.restoreGeometry(geom)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
@ -50,14 +52,15 @@ class SettingsMixin(object):
|
|||
self.warnIfNoObjectName()
|
||||
settings = QtCore.QSettings()
|
||||
try:
|
||||
state = settings.value("/".join([str(self.objectName()), "state"]))
|
||||
target.restoreState(state.toByteArray() if hasattr(state, 'toByteArray') else state)
|
||||
state = settings.value("/".join([ustr(self.objectName()), "state"]))
|
||||
target.restoreState(state)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
class SMainWindow(QtGui.QMainWindow, SettingsMixin):
|
||||
"""Main window with Settings functionality."""
|
||||
class SMainWindow(QtWidgets.QMainWindow, SettingsMixin):
|
||||
"""Main window with Settings functionality"""
|
||||
|
||||
def loadSettings(self):
|
||||
"""Load main window settings."""
|
||||
self.readGeometry(self)
|
||||
|
@ -69,9 +72,9 @@ class SMainWindow(QtGui.QMainWindow, SettingsMixin):
|
|||
self.writeGeometry(self)
|
||||
|
||||
|
||||
class STableWidget(QtGui.QTableWidget, SettingsMixin):
|
||||
class STableWidget(QtWidgets.QTableWidget, SettingsMixin):
|
||||
"""Table widget with Settings functionality"""
|
||||
# pylint: disable=too-many-ancestors
|
||||
|
||||
def loadSettings(self):
|
||||
"""Load table settings."""
|
||||
self.readState(self.horizontalHeader())
|
||||
|
@ -81,8 +84,9 @@ class STableWidget(QtGui.QTableWidget, SettingsMixin):
|
|||
self.writeState(self.horizontalHeader())
|
||||
|
||||
|
||||
class SSplitter(QtGui.QSplitter, SettingsMixin):
|
||||
"""Splitter with Settings functionality."""
|
||||
class SSplitter(QtWidgets.QSplitter, SettingsMixin):
|
||||
"""Splitter with Settings functionality"""
|
||||
|
||||
def loadSettings(self):
|
||||
"""Load splitter settings"""
|
||||
self.readState(self)
|
||||
|
@ -92,17 +96,17 @@ class SSplitter(QtGui.QSplitter, SettingsMixin):
|
|||
self.writeState(self)
|
||||
|
||||
|
||||
class STreeWidget(QtGui.QTreeWidget, SettingsMixin):
|
||||
"""Tree widget with settings functionality."""
|
||||
# pylint: disable=too-many-ancestors
|
||||
class STreeWidget(QtWidgets.QTreeWidget, SettingsMixin):
|
||||
"""Tree widget with settings functionality"""
|
||||
|
||||
def loadSettings(self):
|
||||
"""Load tree settings."""
|
||||
"""Load tree settings. Unimplemented."""
|
||||
# recurse children
|
||||
# self.readState(self)
|
||||
pass
|
||||
|
||||
def saveSettings(self):
|
||||
"""Save tree settings"""
|
||||
"""Save tree settings. Unimplemented."""
|
||||
# recurse children
|
||||
# self.writeState(self)
|
||||
pass
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
# pylint: disable=unused-argument
|
||||
"""Status bar Module"""
|
||||
"""BMStatusBar class definition"""
|
||||
|
||||
from time import time
|
||||
from PyQt4 import QtGui
|
||||
|
||||
from qtpy import QtWidgets
|
||||
|
||||
|
||||
class BMStatusBar(QtGui.QStatusBar):
|
||||
class BMStatusBar(QtWidgets.QStatusBar):
|
||||
"""Status bar with queue and priorities"""
|
||||
duration = 10000
|
||||
deleteAfter = 60
|
||||
|
@ -16,21 +16,24 @@ class BMStatusBar(QtGui.QStatusBar):
|
|||
self.timer = self.startTimer(BMStatusBar.duration)
|
||||
self.iterator = 0
|
||||
|
||||
def timerEvent(self, event):
|
||||
def timerEvent(self, event): # pylint: disable=unused-argument
|
||||
"""an event handler which allows to queue and prioritise messages to
|
||||
show in the status bar, for example if many messages come very quickly
|
||||
after one another, it adds delays and so on"""
|
||||
while len(self.important) > 0:
|
||||
self.iterator += 1
|
||||
try:
|
||||
if time() > self.important[self.iterator][1] + BMStatusBar.deleteAfter:
|
||||
if (
|
||||
self.important[self.iterator][1]
|
||||
+ BMStatusBar.deleteAfter < time()
|
||||
):
|
||||
del self.important[self.iterator]
|
||||
self.iterator -= 1
|
||||
continue
|
||||
except IndexError:
|
||||
self.iterator = -1
|
||||
continue
|
||||
super(BMStatusBar, self).showMessage(self.important[self.iterator][0], 0)
|
||||
self.showMessage(self.important[self.iterator][0], 0)
|
||||
break
|
||||
|
||||
def addImportant(self, message):
|
||||
|
|
|
@ -1,14 +1,15 @@
|
|||
"""Composing support request message functions."""
|
||||
# pylint: disable=no-member
|
||||
|
||||
import ctypes
|
||||
import os
|
||||
import ssl
|
||||
import sys
|
||||
import time
|
||||
|
||||
from PyQt4 import QtCore
|
||||
from unqstr import ustr, unic
|
||||
from dbcompat import dbstr
|
||||
|
||||
import account
|
||||
from bitmessageqt import account
|
||||
import defaults
|
||||
import network.stats
|
||||
import paths
|
||||
|
@ -16,12 +17,12 @@ import proofofwork
|
|||
import queues
|
||||
import state
|
||||
from bmconfigparser import config
|
||||
from foldertree import AccountMixin
|
||||
from .foldertree import AccountMixin
|
||||
from helper_sql import sqlExecute, sqlQuery
|
||||
from l10n import getTranslationLanguage
|
||||
from openclpow import openclEnabled
|
||||
from pyelliptic.openssl import OpenSSL
|
||||
from settings import getSOCKSProxyType
|
||||
from .settings import getSOCKSProxyType
|
||||
from version import softwareVersion
|
||||
from tr import _translate
|
||||
|
||||
|
@ -31,7 +32,7 @@ OLD_SUPPORT_ADDRESS = 'BM-2cTkCtMYkrSPwFTpgcBrMrf5d8oZwvMZWK'
|
|||
SUPPORT_ADDRESS = 'BM-2cUdgkDDAahwPAU6oD2A7DnjqZz3hgY832'
|
||||
SUPPORT_LABEL = _translate("Support", "PyBitmessage support")
|
||||
SUPPORT_MY_LABEL = _translate("Support", "My new address")
|
||||
SUPPORT_SUBJECT = 'Support request'
|
||||
SUPPORT_SUBJECT = _translate("Support", "Support request")
|
||||
SUPPORT_MESSAGE = _translate("Support", '''
|
||||
You can use this message to send a report to one of the PyBitmessage core \
|
||||
developers regarding PyBitmessage or the mailchuck.com email service. \
|
||||
|
@ -55,6 +56,7 @@ Operating system: {}
|
|||
Architecture: {}bit
|
||||
Python Version: {}
|
||||
OpenSSL Version: {}
|
||||
Qt API: {}
|
||||
Frozen: {}
|
||||
Portable mode: {}
|
||||
C PoW: {}
|
||||
|
@ -67,28 +69,35 @@ Connected hosts: {}
|
|||
|
||||
|
||||
def checkAddressBook(myapp):
|
||||
sqlExecute('DELETE from addressbook WHERE address=?', OLD_SUPPORT_ADDRESS)
|
||||
queryreturn = sqlQuery('SELECT * FROM addressbook WHERE address=?', SUPPORT_ADDRESS)
|
||||
"""
|
||||
Add "PyBitmessage support" address to address book, remove old one if found.
|
||||
"""
|
||||
sqlExecute('DELETE from addressbook WHERE address=?', dbstr(OLD_SUPPORT_ADDRESS))
|
||||
queryreturn = sqlQuery(
|
||||
'SELECT * FROM addressbook WHERE address=?', dbstr(SUPPORT_ADDRESS))
|
||||
if queryreturn == []:
|
||||
sqlExecute(
|
||||
'INSERT INTO addressbook VALUES (?,?)',
|
||||
SUPPORT_LABEL.toUtf8(), SUPPORT_ADDRESS)
|
||||
dbstr(SUPPORT_LABEL), dbstr(SUPPORT_ADDRESS))
|
||||
myapp.rerenderAddressBook()
|
||||
|
||||
|
||||
def checkHasNormalAddress():
|
||||
for address in config.addresses():
|
||||
"""Returns first enabled normal address or False if not found."""
|
||||
for address in config.addresses(True):
|
||||
acct = account.accountClass(address)
|
||||
if acct.type == AccountMixin.NORMAL and config.safeGetBoolean(address, 'enabled'):
|
||||
if acct.type == AccountMixin.NORMAL and config.safeGetBoolean(
|
||||
address, 'enabled'):
|
||||
return address
|
||||
return False
|
||||
|
||||
|
||||
def createAddressIfNeeded(myapp):
|
||||
"""Checks if user has any anabled normal address, creates new one if no."""
|
||||
if not checkHasNormalAddress():
|
||||
queues.addressGeneratorQueue.put((
|
||||
'createRandomAddress', 4, 1,
|
||||
str(SUPPORT_MY_LABEL.toUtf8()),
|
||||
ustr(SUPPORT_MY_LABEL),
|
||||
1, "", False,
|
||||
defaults.networkDefaultProofOfWorkNonceTrialsPerByte,
|
||||
defaults.networkDefaultPayloadLengthExtraBytes
|
||||
|
@ -100,15 +109,20 @@ def createAddressIfNeeded(myapp):
|
|||
|
||||
|
||||
def createSupportMessage(myapp):
|
||||
"""
|
||||
Prepare the support request message and switch to tab "Send"
|
||||
"""
|
||||
checkAddressBook(myapp)
|
||||
address = createAddressIfNeeded(myapp)
|
||||
if state.shutdown:
|
||||
return
|
||||
|
||||
myapp.ui.lineEditSubject.setText(SUPPORT_SUBJECT)
|
||||
addrIndex = myapp.ui.comboBoxSendFrom.findData(
|
||||
address, QtCore.Qt.UserRole,
|
||||
QtCore.Qt.MatchFixedString | QtCore.Qt.MatchCaseSensitive)
|
||||
# addrIndex = myapp.ui.comboBoxSendFrom.findData(
|
||||
# address, QtCore.Qt.UserRole,
|
||||
# QtCore.Qt.MatchFixedString | QtCore.Qt.MatchCaseSensitive
|
||||
# )
|
||||
addrIndex = myapp.ui.comboBoxSendFrom.findData(address)
|
||||
if addrIndex == -1: # something is very wrong
|
||||
return
|
||||
myapp.ui.comboBoxSendFrom.setCurrentIndex(addrIndex)
|
||||
|
@ -119,15 +133,13 @@ def createSupportMessage(myapp):
|
|||
if commit:
|
||||
version += " GIT " + commit
|
||||
|
||||
os = sys.platform
|
||||
if os == "win32":
|
||||
windowsversion = sys.getwindowsversion()
|
||||
os = "Windows " + str(windowsversion[0]) + "." + str(windowsversion[1])
|
||||
if sys.platform.startswith("win"):
|
||||
# pylint: disable=no-member
|
||||
osname = "Windows %s.%s" % sys.getwindowsversion()[:2]
|
||||
else:
|
||||
try:
|
||||
from os import uname
|
||||
unixversion = uname()
|
||||
os = unixversion[0] + " " + unixversion[2]
|
||||
unixversion = os.uname()
|
||||
osname = unixversion[0] + " " + unixversion[2]
|
||||
except:
|
||||
pass
|
||||
architecture = "32" if ctypes.sizeof(ctypes.c_voidp) == 4 else "64"
|
||||
|
@ -136,22 +148,26 @@ def createSupportMessage(myapp):
|
|||
opensslversion = "%s (Python internal), %s (external for PyElliptic)" % (
|
||||
ssl.OPENSSL_VERSION, OpenSSL._version)
|
||||
|
||||
qtapi = os.environ.get('QT_API', 'fallback')
|
||||
|
||||
frozen = "N/A"
|
||||
if paths.frozen:
|
||||
frozen = paths.frozen
|
||||
portablemode = "True" if state.appdata == paths.lookupExeFolder() else "False"
|
||||
portablemode = str(state.appdata == paths.lookupExeFolder())
|
||||
cpow = "True" if proofofwork.bmpow else "False"
|
||||
openclpow = str(
|
||||
openclpow = ustr(
|
||||
config.safeGet('bitmessagesettings', 'opencl')
|
||||
) if openclEnabled() else "None"
|
||||
locale = getTranslationLanguage()
|
||||
socks = getSOCKSProxyType(config) or "N/A"
|
||||
upnp = config.safeGet('bitmessagesettings', 'upnp', "N/A")
|
||||
socks = getSOCKSProxyType(config) or 'N/A'
|
||||
upnp = config.safeGet('bitmessagesettings', 'upnp', 'N/A')
|
||||
connectedhosts = len(network.stats.connectedHostsList())
|
||||
|
||||
myapp.ui.textEditMessage.setText(unicode(SUPPORT_MESSAGE, 'utf-8').format(
|
||||
version, os, architecture, pythonversion, opensslversion, frozen,
|
||||
portablemode, cpow, openclpow, locale, socks, upnp, connectedhosts))
|
||||
myapp.ui.textEditMessage.setText(unic(ustr(SUPPORT_MESSAGE).format(
|
||||
version, osname, architecture, pythonversion, opensslversion, qtapi,
|
||||
frozen, portablemode, cpow, openclpow, locale, socks, upnp,
|
||||
connectedhosts
|
||||
)))
|
||||
|
||||
# single msg tab
|
||||
myapp.ui.tabWidgetSend.setCurrentIndex(
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import helper_addressbook
|
||||
from bitmessageqt.support import createAddressIfNeeded
|
||||
|
||||
from main import TestBase
|
||||
from .main import TestBase
|
||||
|
||||
|
||||
class TestAddressbook(TestBase):
|
||||
|
|
|
@ -3,7 +3,8 @@
|
|||
import sys
|
||||
import unittest
|
||||
|
||||
from PyQt4 import QtCore, QtGui
|
||||
from qtpy import QtCore, QtWidgets
|
||||
from six import string_types
|
||||
from six.moves import queue
|
||||
|
||||
import bitmessageqt
|
||||
|
@ -20,7 +21,7 @@ class TestBase(unittest.TestCase):
|
|||
|
||||
def setUp(self):
|
||||
self.app = (
|
||||
QtGui.QApplication.instance()
|
||||
QtWidgets.QApplication.instance()
|
||||
or bitmessageqt.BitmessageQtApplication(sys.argv))
|
||||
self.window = self.app.activeWindow()
|
||||
if not self.window:
|
||||
|
@ -50,10 +51,7 @@ class TestMain(unittest.TestCase):
|
|||
|
||||
def test_translate(self):
|
||||
"""Check the results of _translate() with various args"""
|
||||
self.assertIsInstance(
|
||||
_translate("MainWindow", "Test"),
|
||||
QtCore.QString
|
||||
)
|
||||
self.assertIsInstance(_translate("MainWindow", "Test"), string_types)
|
||||
|
||||
|
||||
class TestUISignaler(TestBase):
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
import threading
|
||||
import time
|
||||
|
||||
from PyQt4 import QtCore, QtGui, QtTest
|
||||
from qtpy import QtCore, QtWidgets, QtTest
|
||||
|
||||
from bmconfigparser import config
|
||||
from bitmessageqt import settings
|
||||
|
@ -48,8 +48,8 @@ class TestSettings(TestBase):
|
|||
|
||||
def call_font_dialog():
|
||||
"""A function to get the open font dialog and accept it"""
|
||||
font_dialog = QtGui.QApplication.activeModalWidget()
|
||||
self.assertTrue(isinstance(font_dialog, QtGui.QFontDialog))
|
||||
font_dialog = QtWidgets.QApplication.activeModalWidget()
|
||||
self.assertTrue(isinstance(font_dialog, QtWidgets.QFontDialog))
|
||||
selected_font = font_dialog.currentFont()
|
||||
self.assertEqual(
|
||||
config.safeGet('bitmessagesettings', 'font'), '{},{}'.format(
|
||||
|
@ -64,7 +64,7 @@ class TestSettings(TestBase):
|
|||
def click_font_button():
|
||||
"""Use QtTest to click the button"""
|
||||
QtTest.QTest.mouseClick(
|
||||
self.dialog.buttonFont, QtCore.Qt.LeftButton)
|
||||
self.dialog.buttonFont, QtCore.Qt.MouseButton.LeftButton)
|
||||
|
||||
style_count = style_control.count()
|
||||
self.assertGreater(style_count, 1)
|
||||
|
|
|
@ -4,7 +4,9 @@ import sys
|
|||
|
||||
from shared import isAddressInMyAddressBook
|
||||
|
||||
from main import TestBase
|
||||
from .main import TestBase
|
||||
|
||||
from unqstr import ustr
|
||||
|
||||
|
||||
class TestSupport(TestBase):
|
||||
|
@ -26,8 +28,8 @@ class TestSupport(TestBase):
|
|||
self.assertEqual(
|
||||
ui.tabWidget.currentIndex(), ui.tabWidget.indexOf(ui.send))
|
||||
self.assertEqual(
|
||||
ui.lineEditTo.text(), self.SUPPORT_ADDRESS)
|
||||
ustr(ui.lineEditTo.text()), ustr(self.SUPPORT_ADDRESS))
|
||||
self.assertEqual(
|
||||
ui.lineEditSubject.text(), self.SUPPORT_SUBJECT)
|
||||
ustr(ui.lineEditSubject.text()), ustr(self.SUPPORT_SUBJECT))
|
||||
self.assertIn(
|
||||
sys.version, ui.textEditMessage.toPlainText())
|
||||
|
|
|
@ -1,15 +1,35 @@
|
|||
|
||||
from PyQt4.QtCore import QThread, SIGNAL
|
||||
import sys
|
||||
|
||||
from qtpy import QtCore
|
||||
|
||||
import queues
|
||||
from network.node import Peer
|
||||
|
||||
|
||||
class UISignaler(QThread):
|
||||
class UISignaler(QtCore.QThread):
|
||||
_instance = None
|
||||
|
||||
def __init__(self, parent=None):
|
||||
QThread.__init__(self, parent)
|
||||
writeNewAddressToTable = QtCore.Signal(str, str, str)
|
||||
updateStatusBar = QtCore.Signal(object)
|
||||
updateSentItemStatusByToAddress = QtCore.Signal(object, str)
|
||||
updateSentItemStatusByAckdata = QtCore.Signal(object, str)
|
||||
displayNewInboxMessage = QtCore.Signal(object, str, object, object, str)
|
||||
displayNewSentMessage = QtCore.Signal(
|
||||
object, str, str, object, object, str)
|
||||
updateNetworkStatusTab = QtCore.Signal(bool, bool, Peer)
|
||||
updateNumberOfMessagesProcessed = QtCore.Signal()
|
||||
updateNumberOfPubkeysProcessed = QtCore.Signal()
|
||||
updateNumberOfBroadcastsProcessed = QtCore.Signal()
|
||||
setStatusIcon = QtCore.Signal(str)
|
||||
changedInboxUnread = QtCore.Signal(str)
|
||||
rerenderMessagelistFromLabels = QtCore.Signal()
|
||||
rerenderMessagelistToLabels = QtCore.Signal()
|
||||
rerenderAddressBook = QtCore.Signal()
|
||||
rerenderSubscriptions = QtCore.Signal()
|
||||
rerenderBlackWhiteList = QtCore.Signal()
|
||||
removeInboxRowByMsgid = QtCore.Signal(str)
|
||||
newVersionAvailable = QtCore.Signal(str)
|
||||
displayAlert = QtCore.Signal(str, str, bool)
|
||||
|
||||
@classmethod
|
||||
def get(cls):
|
||||
|
@ -22,69 +42,59 @@ class UISignaler(QThread):
|
|||
command, data = queues.UISignalQueue.get()
|
||||
if command == 'writeNewAddressToTable':
|
||||
label, address, streamNumber = data
|
||||
self.emit(
|
||||
SIGNAL("writeNewAddressToTable(PyQt_PyObject,PyQt_PyObject,PyQt_PyObject)"),
|
||||
label,
|
||||
address,
|
||||
str(streamNumber))
|
||||
self.writeNewAddressToTable.emit(
|
||||
label, address, str(streamNumber))
|
||||
elif command == 'updateStatusBar':
|
||||
self.emit(SIGNAL("updateStatusBar(PyQt_PyObject)"), data)
|
||||
self.updateStatusBar.emit(data)
|
||||
elif command == 'updateSentItemStatusByToAddress':
|
||||
toAddress, message = data
|
||||
self.emit(SIGNAL(
|
||||
"updateSentItemStatusByToAddress(PyQt_PyObject,PyQt_PyObject)"), toAddress, message)
|
||||
self.updateSentItemStatusByToAddress.emit(toAddress, message)
|
||||
elif command == 'updateSentItemStatusByAckdata':
|
||||
ackData, message = data
|
||||
self.emit(SIGNAL(
|
||||
"updateSentItemStatusByAckdata(PyQt_PyObject,PyQt_PyObject)"), ackData, message)
|
||||
self.updateSentItemStatusByAckdata.emit(ackData, message)
|
||||
elif command == 'displayNewInboxMessage':
|
||||
inventoryHash, toAddress, fromAddress, subject, body = data
|
||||
self.emit(SIGNAL(
|
||||
"displayNewInboxMessage(PyQt_PyObject,PyQt_PyObject,PyQt_PyObject,PyQt_PyObject,PyQt_PyObject)"),
|
||||
inventoryHash, toAddress, fromAddress, subject, body)
|
||||
|
||||
self.displayNewInboxMessage.emit(
|
||||
inventoryHash, toAddress, fromAddress,
|
||||
subject, body)
|
||||
elif command == 'displayNewSentMessage':
|
||||
toAddress, fromLabel, fromAddress, subject, message, ackdata = data
|
||||
self.emit(SIGNAL(
|
||||
"displayNewSentMessage(PyQt_PyObject,PyQt_PyObject,PyQt_PyObject,PyQt_PyObject,PyQt_PyObject,PyQt_PyObject)"),
|
||||
toAddress, fromLabel, fromAddress, subject, message, ackdata)
|
||||
self.displayNewSentMessage.emit(
|
||||
toAddress, fromLabel, fromAddress,
|
||||
subject.decode('utf-8'), message, ackdata)
|
||||
elif command == 'updateNetworkStatusTab':
|
||||
outbound, add, destination = data
|
||||
self.emit(
|
||||
SIGNAL("updateNetworkStatusTab(PyQt_PyObject,PyQt_PyObject,PyQt_PyObject)"),
|
||||
outbound,
|
||||
add,
|
||||
destination)
|
||||
self.updateNetworkStatusTab.emit(outbound, add, destination)
|
||||
elif command == 'updateNumberOfMessagesProcessed':
|
||||
self.emit(SIGNAL("updateNumberOfMessagesProcessed()"))
|
||||
self.updateNumberOfMessagesProcessed.emit()
|
||||
elif command == 'updateNumberOfPubkeysProcessed':
|
||||
self.emit(SIGNAL("updateNumberOfPubkeysProcessed()"))
|
||||
self.updateNumberOfPubkeysProcessed.emit()
|
||||
elif command == 'updateNumberOfBroadcastsProcessed':
|
||||
self.emit(SIGNAL("updateNumberOfBroadcastsProcessed()"))
|
||||
self.updateNumberOfBroadcastsProcessed.emit()
|
||||
elif command == 'setStatusIcon':
|
||||
self.emit(SIGNAL("setStatusIcon(PyQt_PyObject)"), data)
|
||||
self.setStatusIcon.emit(data)
|
||||
elif command == 'changedInboxUnread':
|
||||
self.emit(SIGNAL("changedInboxUnread(PyQt_PyObject)"), data)
|
||||
self.changedInboxUnread.emit(data)
|
||||
elif command == 'rerenderMessagelistFromLabels':
|
||||
self.emit(SIGNAL("rerenderMessagelistFromLabels()"))
|
||||
self.rerenderMessagelistFromLabels.emit()
|
||||
elif command == 'rerenderMessagelistToLabels':
|
||||
self.emit(SIGNAL("rerenderMessagelistToLabels()"))
|
||||
self.rerenderMessagelistToLabels.emit()
|
||||
elif command == 'rerenderAddressBook':
|
||||
self.emit(SIGNAL("rerenderAddressBook()"))
|
||||
self.rerenderAddressBook.emit()
|
||||
elif command == 'rerenderSubscriptions':
|
||||
self.emit(SIGNAL("rerenderSubscriptions()"))
|
||||
self.rerenderSubscriptions.emit()
|
||||
elif command == 'rerenderBlackWhiteList':
|
||||
self.emit(SIGNAL("rerenderBlackWhiteList()"))
|
||||
self.rerenderBlackWhiteList.emit()
|
||||
elif command == 'removeInboxRowByMsgid':
|
||||
self.emit(SIGNAL("removeInboxRowByMsgid(PyQt_PyObject)"), data)
|
||||
self.removeInboxRowByMsgid.emit(data)
|
||||
elif command == 'newVersionAvailable':
|
||||
self.emit(SIGNAL("newVersionAvailable(PyQt_PyObject)"), data)
|
||||
self.newVersionAvailable.emit(data)
|
||||
elif command == 'alert':
|
||||
title, text, exitAfterUserClicksOk = data
|
||||
self.emit(
|
||||
SIGNAL("displayAlert(PyQt_PyObject, PyQt_PyObject, PyQt_PyObject)"),
|
||||
title,
|
||||
text,
|
||||
exitAfterUserClicksOk)
|
||||
self.displayAlert.emit(title, text, exitAfterUserClicksOk)
|
||||
else:
|
||||
sys.stderr.write(
|
||||
'Command sent to UISignaler not recognized: %s\n' % command)
|
||||
'Command sent to UISignaler not recognized: %s\n'
|
||||
% command
|
||||
)
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import hashlib
|
||||
import os
|
||||
|
||||
from PyQt4 import QtGui
|
||||
from qtpy import QtGui
|
||||
|
||||
import state
|
||||
from addresses import addBMIfNotPresent
|
||||
|
@ -30,16 +30,18 @@ def identiconize(address):
|
|||
# It can be used as a pseudo-password to salt the generation of
|
||||
# the identicons to decrease the risk of attacks where someone creates
|
||||
# an address to mimic someone else's identicon.
|
||||
identiconsuffix = config.get('bitmessagesettings', 'identiconsuffix')
|
||||
data = addBMIfNotPresent(address) + config.get(
|
||||
'bitmessagesettings', 'identiconsuffix')
|
||||
data = data.encode("utf-8", "replace")
|
||||
if identicon_lib[:len('qidenticon')] == 'qidenticon':
|
||||
# originally by:
|
||||
# :Author:Shin Adachi <shn@glucose.jp>
|
||||
# Licesensed under FreeBSD License.
|
||||
# stripped from PIL and uses QT instead (by sendiulo, same license)
|
||||
import qidenticon
|
||||
icon_hash = hashlib.md5(
|
||||
addBMIfNotPresent(address) + identiconsuffix).hexdigest()
|
||||
use_two_colors = identicon_lib[:len('qidenticon_two')] == 'qidenticon_two'
|
||||
icon_hash = hashlib.md5(data).hexdigest()
|
||||
use_two_colors = (
|
||||
identicon_lib[:len('qidenticon_two')] == 'qidenticon_two')
|
||||
opacity = int(
|
||||
identicon_lib not in (
|
||||
'qidenticon_x', 'qidenticon_two_x',
|
||||
|
@ -63,8 +65,7 @@ def identiconize(address):
|
|||
# https://github.com/azaghal/pydenticon
|
||||
# note that it requires pillow (or PIL) to be installed:
|
||||
# https://python-pillow.org/
|
||||
idcon_render = Pydenticon(
|
||||
addBMIfNotPresent(address) + identiconsuffix, size * 3)
|
||||
idcon_render = Pydenticon(data, size * 3)
|
||||
rendering = idcon_render._render()
|
||||
data = rendering.convert("RGBA").tostring("raw", "RGBA")
|
||||
qim = QtGui.QImage(data, size, size, QtGui.QImage.Format_ARGB32)
|
||||
|
@ -81,7 +82,7 @@ def avatarize(address):
|
|||
falls back to identiconize(address)
|
||||
"""
|
||||
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:
|
||||
# don't hash [Broadcast subscribers]
|
||||
icon_hash = address
|
||||
|
@ -105,11 +106,9 @@ def avatarize(address):
|
|||
lower_default = state.appdata + 'avatars/' + 'default.' + ext.lower()
|
||||
upper_default = state.appdata + 'avatars/' + 'default.' + ext.upper()
|
||||
if os.path.isfile(lower_default):
|
||||
default = lower_default
|
||||
idcon.addFile(lower_default)
|
||||
return idcon
|
||||
elif os.path.isfile(upper_default):
|
||||
default = upper_default
|
||||
idcon.addFile(upper_default)
|
||||
return idcon
|
||||
# If no avatar is found
|
||||
|
|
|
@ -1,13 +1,15 @@
|
|||
from PyQt4 import uic
|
||||
from qtpy import uic
|
||||
import os.path
|
||||
import paths
|
||||
import sys
|
||||
|
||||
|
||||
def resource_path(resFile):
|
||||
baseDir = paths.codePath()
|
||||
for subDir in ["ui", "bitmessageqt"]:
|
||||
if os.path.isdir(os.path.join(baseDir, subDir)) and os.path.isfile(os.path.join(baseDir, subDir, resFile)):
|
||||
return os.path.join(baseDir, subDir, resFile)
|
||||
for subDir in ("ui", "bitmessageqt"):
|
||||
path = os.path.join(baseDir, subDir, resFile)
|
||||
if os.path.isfile(path):
|
||||
return path
|
||||
|
||||
|
||||
def load(resFile, widget):
|
||||
uic.loadUi(resource_path(resFile), widget)
|
||||
|
|
|
@ -9,19 +9,24 @@ from datetime import datetime
|
|||
|
||||
from six import string_types
|
||||
from six.moves import configparser
|
||||
from unqstr import ustr
|
||||
|
||||
try:
|
||||
import state
|
||||
except ImportError:
|
||||
from pybitmessage import state
|
||||
|
||||
SafeConfigParser = configparser.SafeConfigParser
|
||||
try:
|
||||
SafeConfigParser = configparser.SafeConfigParser
|
||||
except AttributeError:
|
||||
# alpine linux, python3.12
|
||||
SafeConfigParser = configparser.ConfigParser
|
||||
config_ready = Event()
|
||||
|
||||
|
||||
class BMConfigParser(SafeConfigParser):
|
||||
"""
|
||||
Singleton class inherited from :class:`ConfigParser.SafeConfigParser`
|
||||
Singleton class inherited from :class:`configparser.SafeConfigParser`
|
||||
with additional methods specific to bitmessage config.
|
||||
"""
|
||||
# pylint: disable=too-many-ancestors
|
||||
|
@ -114,7 +119,8 @@ class BMConfigParser(SafeConfigParser):
|
|||
"""Return a list of local bitmessage addresses (from section labels)"""
|
||||
sections = [x for x in self.sections() if x.startswith('BM-')]
|
||||
if sort:
|
||||
sections.sort(key=lambda item: self.get(item, 'label').lower())
|
||||
sections.sort(key=lambda item: ustr(self.get(item, 'label')) \
|
||||
.lower())
|
||||
return sections
|
||||
|
||||
def save(self):
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
"""
|
||||
A thread for creating addresses
|
||||
addressGenerator thread class definition
|
||||
"""
|
||||
|
||||
import time
|
||||
|
@ -211,8 +211,8 @@ class addressGenerator(StoppableThread):
|
|||
'updateStatusBar',
|
||||
_translate(
|
||||
"MainWindow",
|
||||
"Generating %1 new addresses."
|
||||
).arg(str(numberOfAddressesToMake))
|
||||
"Generating {0} new addresses."
|
||||
).format(str(numberOfAddressesToMake))
|
||||
))
|
||||
signingKeyNonce = 0
|
||||
encryptionKeyNonce = 1
|
||||
|
@ -302,9 +302,9 @@ class addressGenerator(StoppableThread):
|
|||
'updateStatusBar',
|
||||
_translate(
|
||||
"MainWindow",
|
||||
"%1 is already in 'Your Identities'."
|
||||
"{0} is already in 'Your Identities'."
|
||||
" Not adding it again."
|
||||
).arg(address)
|
||||
).format(address)
|
||||
))
|
||||
else:
|
||||
self.logger.debug('label: %s', label)
|
||||
|
|
|
@ -12,6 +12,7 @@ import subprocess # nosec B404
|
|||
import threading
|
||||
import time
|
||||
from binascii import hexlify
|
||||
import sqlite3
|
||||
|
||||
import helper_bitcoin
|
||||
import helper_inbox
|
||||
|
@ -33,6 +34,7 @@ from helper_sql import (
|
|||
from network import knownnodes, invQueue
|
||||
from network.node import Peer
|
||||
from tr import _translate
|
||||
from dbcompat import dbstr
|
||||
|
||||
logger = logging.getLogger('default')
|
||||
|
||||
|
@ -121,7 +123,7 @@ class objectProcessor(threading.Thread):
|
|||
objectType, data = queues.objectProcessorQueue.get()
|
||||
sql.execute(
|
||||
'INSERT INTO objectprocessorqueue VALUES (?,?)',
|
||||
objectType, data)
|
||||
objectType, sqlite3.Binary(data))
|
||||
numberOfObjectsThatWereInTheObjectProcessorQueue += 1
|
||||
logger.debug(
|
||||
'Saved %s objects from the objectProcessorQueue to'
|
||||
|
@ -140,19 +142,23 @@ class objectProcessor(threading.Thread):
|
|||
# bypass nonce and time, retain object type/version/stream + body
|
||||
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.')
|
||||
del state.ackdataForWhichImWatching[data[readPosition:]]
|
||||
sqlExecute(
|
||||
del state.ackdataForWhichImWatching[data_bytes]
|
||||
rowcount = sqlExecute(
|
||||
"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((
|
||||
'updateSentItemStatusByAckdata', (
|
||||
data[readPosition:],
|
||||
_translate(
|
||||
data_bytes, _translate(
|
||||
"MainWindow",
|
||||
"Acknowledgement of the message received %1"
|
||||
).arg(l10n.formatTimestamp()))
|
||||
"Acknowledgement of the message received {0}"
|
||||
).format(l10n.formatTimestamp()))
|
||||
))
|
||||
else:
|
||||
logger.debug('This object is not an acknowledgement bound for me.')
|
||||
|
@ -215,9 +221,10 @@ class objectProcessor(threading.Thread):
|
|||
logger.info(
|
||||
'the hash requested in this getpubkey request is: %s',
|
||||
hexlify(requestedHash))
|
||||
requestedHash_bytes = bytes(requestedHash)
|
||||
# if this address hash is one of mine
|
||||
if requestedHash in shared.myAddressesByHash:
|
||||
myAddress = shared.myAddressesByHash[requestedHash]
|
||||
if requestedHash_bytes in shared.myAddressesByHash:
|
||||
myAddress = shared.myAddressesByHash[requestedHash_bytes]
|
||||
elif requestedAddressVersionNumber >= 4:
|
||||
requestedTag = data[readPosition:readPosition + 32]
|
||||
if len(requestedTag) != 32:
|
||||
|
@ -227,8 +234,9 @@ class objectProcessor(threading.Thread):
|
|||
logger.debug(
|
||||
'the tag requested in this getpubkey request is: %s',
|
||||
hexlify(requestedTag))
|
||||
if requestedTag in shared.myAddressesByTag:
|
||||
myAddress = shared.myAddressesByTag[requestedTag]
|
||||
requestedTag_bytes = bytes(requestedTag)
|
||||
if requestedTag_bytes in shared.myAddressesByTag:
|
||||
myAddress = shared.myAddressesByTag[requestedTag_bytes]
|
||||
|
||||
if myAddress == '':
|
||||
logger.info('This getpubkey request is not for any of my keys.')
|
||||
|
@ -299,12 +307,12 @@ class objectProcessor(threading.Thread):
|
|||
'(within processpubkey) payloadLength less than 146.'
|
||||
' Sanity check failed.')
|
||||
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
|
||||
# encrypt or sign with it will cause an error? If it is, it would
|
||||
# be easiest to test them here.
|
||||
readPosition += 64
|
||||
pubEncryptionKey = '\x04' + data[readPosition:readPosition + 64]
|
||||
pubEncryptionKey = b'\x04' + data[readPosition:readPosition + 64]
|
||||
if len(pubEncryptionKey) < 65:
|
||||
return logger.debug(
|
||||
'publicEncryptionKey length less than 64. Sanity check'
|
||||
|
@ -327,19 +335,19 @@ class objectProcessor(threading.Thread):
|
|||
|
||||
queryreturn = sqlQuery(
|
||||
"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
|
||||
# used it personally:
|
||||
if queryreturn != []:
|
||||
logger.info(
|
||||
'We HAVE used this pubkey personally. Updating time.')
|
||||
t = (address, addressVersion, dataToStore,
|
||||
t = (dbstr(address), addressVersion, sqlite3.Binary(dataToStore),
|
||||
int(time.time()), 'yes')
|
||||
else:
|
||||
logger.info(
|
||||
'We have NOT used this pubkey personally. Inserting'
|
||||
' in database.')
|
||||
t = (address, addressVersion, dataToStore,
|
||||
t = (dbstr(address), addressVersion, sqlite3.Binary(dataToStore),
|
||||
int(time.time()), 'no')
|
||||
sqlExecute('''INSERT INTO pubkeys VALUES (?,?,?,?,?)''', *t)
|
||||
self.possibleNewPubkey(address)
|
||||
|
@ -350,9 +358,9 @@ class objectProcessor(threading.Thread):
|
|||
' Sanity check failed.')
|
||||
return
|
||||
readPosition += 4
|
||||
pubSigningKey = '\x04' + data[readPosition:readPosition + 64]
|
||||
pubSigningKey = b'\x04' + data[readPosition:readPosition + 64]
|
||||
readPosition += 64
|
||||
pubEncryptionKey = '\x04' + data[readPosition:readPosition + 64]
|
||||
pubEncryptionKey = b'\x04' + data[readPosition:readPosition + 64]
|
||||
readPosition += 64
|
||||
specifiedNonceTrialsPerByteLength = decodeVarint(
|
||||
data[readPosition:readPosition + 10])[1]
|
||||
|
@ -389,20 +397,20 @@ class objectProcessor(threading.Thread):
|
|||
address = encodeAddress(addressVersion, streamNumber, ripe)
|
||||
queryreturn = sqlQuery(
|
||||
"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
|
||||
# used it personally:
|
||||
if queryreturn != []:
|
||||
logger.info(
|
||||
'We HAVE used this pubkey personally. Updating time.')
|
||||
t = (address, addressVersion, dataToStore,
|
||||
int(time.time()), 'yes')
|
||||
t = (dbstr(address), addressVersion, sqlite3.Binary(dataToStore),
|
||||
int(time.time()), dbstr('yes'))
|
||||
else:
|
||||
logger.info(
|
||||
'We have NOT used this pubkey personally. Inserting'
|
||||
' in database.')
|
||||
t = (address, addressVersion, dataToStore,
|
||||
int(time.time()), 'no')
|
||||
t = (dbstr(address), addressVersion, sqlite3.Binary(dataToStore),
|
||||
int(time.time()), dbstr('no'))
|
||||
sqlExecute('''INSERT INTO pubkeys VALUES (?,?,?,?,?)''', *t)
|
||||
self.possibleNewPubkey(address)
|
||||
|
||||
|
@ -413,12 +421,13 @@ class objectProcessor(threading.Thread):
|
|||
' Sanity check failed.')
|
||||
|
||||
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(
|
||||
'We don\'t need this v4 pubkey. We didn\'t ask for it.')
|
||||
|
||||
# Let us try to decrypt the pubkey
|
||||
toAddress = state.neededPubkeys[tag][0]
|
||||
toAddress = state.neededPubkeys[tag_bytes][0]
|
||||
if protocol.decryptAndCheckPubkeyPayload(data, toAddress) == \
|
||||
'successful':
|
||||
# At this point we know that we have been waiting on this
|
||||
|
@ -483,7 +492,7 @@ class objectProcessor(threading.Thread):
|
|||
|
||||
# This is a message bound for me.
|
||||
# Look up my address based on the RIPE hash.
|
||||
toAddress = shared.myAddressesByHash[toRipe]
|
||||
toAddress = shared.myAddressesByHash[bytes(toRipe)]
|
||||
readPosition = 0
|
||||
sendersAddressVersionNumber, sendersAddressVersionNumberLength = \
|
||||
decodeVarint(decryptedData[readPosition:readPosition + 10])
|
||||
|
@ -507,9 +516,9 @@ class objectProcessor(threading.Thread):
|
|||
return
|
||||
readPosition += sendersStreamNumberLength
|
||||
readPosition += 4
|
||||
pubSigningKey = '\x04' + decryptedData[readPosition:readPosition + 64]
|
||||
pubSigningKey = b'\x04' + decryptedData[readPosition:readPosition + 64]
|
||||
readPosition += 64
|
||||
pubEncryptionKey = '\x04' + decryptedData[readPosition:readPosition + 64]
|
||||
pubEncryptionKey = b'\x04' + decryptedData[readPosition:readPosition + 64]
|
||||
readPosition += 64
|
||||
if sendersAddressVersionNumber >= 3:
|
||||
requiredAverageProofOfWorkNonceTrialsPerByte, varintLength = \
|
||||
|
@ -558,7 +567,7 @@ class objectProcessor(threading.Thread):
|
|||
readPosition += signatureLengthLength
|
||||
signature = decryptedData[
|
||||
readPosition:readPosition + signatureLength]
|
||||
signedData = data[8:20] + encodeVarint(1) + encodeVarint(
|
||||
signedData = bytes(data[8:20]) + encodeVarint(1) + encodeVarint(
|
||||
streamNumberAsClaimedByMsg
|
||||
) + decryptedData[:positionOfBottomOfAckData]
|
||||
|
||||
|
@ -590,11 +599,11 @@ class objectProcessor(threading.Thread):
|
|||
# person.
|
||||
sqlExecute(
|
||||
'''INSERT INTO pubkeys VALUES (?,?,?,?,?)''',
|
||||
fromAddress,
|
||||
dbstr(fromAddress),
|
||||
sendersAddressVersionNumber,
|
||||
decryptedData[:endOfThePublicKeyPosition],
|
||||
sqlite3.Binary(decryptedData[:endOfThePublicKeyPosition]),
|
||||
int(time.time()),
|
||||
'yes')
|
||||
dbstr('yes'))
|
||||
|
||||
# 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
|
||||
|
@ -631,7 +640,7 @@ class objectProcessor(threading.Thread):
|
|||
'bitmessagesettings', 'blackwhitelist') == 'black':
|
||||
queryreturn = sqlQuery(
|
||||
"SELECT label FROM blacklist where address=? and enabled='1'",
|
||||
fromAddress)
|
||||
dbstr(fromAddress))
|
||||
if queryreturn != []:
|
||||
logger.info('Message ignored because address is in blacklist.')
|
||||
|
||||
|
@ -639,7 +648,7 @@ class objectProcessor(threading.Thread):
|
|||
else: # We're using a whitelist
|
||||
queryreturn = sqlQuery(
|
||||
"SELECT label FROM whitelist where address=? and enabled='1'",
|
||||
fromAddress)
|
||||
dbstr(fromAddress))
|
||||
if queryreturn == []:
|
||||
logger.info(
|
||||
'Message ignored because address not in whitelist.')
|
||||
|
@ -808,13 +817,14 @@ class objectProcessor(threading.Thread):
|
|||
elif broadcastVersion == 5:
|
||||
embeddedTag = data[readPosition: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.')
|
||||
return
|
||||
# We are interested in this broadcast because of its tag.
|
||||
# We're going to add some more data which is signed further down.
|
||||
signedData = data[8:readPosition]
|
||||
cryptorObject = shared.MyECSubscriptionCryptorObjects[embeddedTag]
|
||||
signedData = bytes(data[8:readPosition])
|
||||
cryptorObject = shared.MyECSubscriptionCryptorObjects[embeddedTag_bytes]
|
||||
try:
|
||||
decryptedData = cryptorObject.decrypt(data[readPosition:])
|
||||
logger.debug('EC decryption successful')
|
||||
|
@ -854,10 +864,10 @@ class objectProcessor(threading.Thread):
|
|||
)
|
||||
readPosition += sendersStreamLength
|
||||
readPosition += 4
|
||||
sendersPubSigningKey = '\x04' + \
|
||||
sendersPubSigningKey = b'\x04' + \
|
||||
decryptedData[readPosition:readPosition + 64]
|
||||
readPosition += 64
|
||||
sendersPubEncryptionKey = '\x04' + \
|
||||
sendersPubEncryptionKey = b'\x04' + \
|
||||
decryptedData[readPosition:readPosition + 64]
|
||||
readPosition += 64
|
||||
if sendersAddressVersion >= 3:
|
||||
|
@ -927,11 +937,11 @@ class objectProcessor(threading.Thread):
|
|||
|
||||
# Let's store the public key in case we want to reply to this person.
|
||||
sqlExecute('''INSERT INTO pubkeys VALUES (?,?,?,?,?)''',
|
||||
fromAddress,
|
||||
sendersAddressVersion,
|
||||
decryptedData[:endOfPubkeyPosition],
|
||||
dbstr(fromAddress),
|
||||
dbstr(sendersAddressVersion),
|
||||
sqlite3.Binary(decryptedData[:endOfPubkeyPosition]),
|
||||
int(time.time()),
|
||||
'yes')
|
||||
dbstr('yes'))
|
||||
|
||||
# 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
|
||||
|
@ -997,8 +1007,9 @@ class objectProcessor(threading.Thread):
|
|||
encodeVarint(addressVersion) + encodeVarint(streamNumber)
|
||||
+ ripe
|
||||
)[32:]
|
||||
if tag in state.neededPubkeys:
|
||||
del state.neededPubkeys[tag]
|
||||
tag_bytes = bytes(tag)
|
||||
if tag_bytes in state.neededPubkeys:
|
||||
del state.neededPubkeys[tag_bytes]
|
||||
self.sendMessages(address)
|
||||
|
||||
@staticmethod
|
||||
|
@ -1012,7 +1023,7 @@ class objectProcessor(threading.Thread):
|
|||
"UPDATE sent SET status='doingmsgpow', retrynumber=0"
|
||||
" WHERE toaddress=?"
|
||||
" AND (status='awaitingpubkey' OR status='doingpubkeypow')"
|
||||
" AND folder='sent'", address)
|
||||
" AND folder='sent'", dbstr(address))
|
||||
queues.workerQueue.put(('sendmessage', ''))
|
||||
|
||||
@staticmethod
|
||||
|
@ -1047,8 +1058,8 @@ class objectProcessor(threading.Thread):
|
|||
if checksum != hashlib.sha512(payload).digest()[0:4]:
|
||||
logger.info('ackdata checksum wrong. Not sending ackdata.')
|
||||
return False
|
||||
command = command.rstrip('\x00')
|
||||
if command != 'object':
|
||||
command = command.rstrip(b'\x00')
|
||||
if command != b'object':
|
||||
return False
|
||||
return True
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@ It resends messages when there has been no response:
|
|||
import gc
|
||||
import os
|
||||
import time
|
||||
import sqlite3
|
||||
|
||||
import queues
|
||||
import state
|
||||
|
@ -29,6 +30,7 @@ from bmconfigparser import config
|
|||
from helper_sql import sqlExecute, sqlQuery
|
||||
from network import connectionpool, knownnodes, StoppableThread
|
||||
from tr import _translate
|
||||
from dbcompat import dbstr
|
||||
|
||||
|
||||
#: Equals 4 weeks. You could make this longer if you want
|
||||
|
@ -99,6 +101,8 @@ class singleCleaner(StoppableThread):
|
|||
tick - state.maximumLengthOfTimeToBotherResendingMessages
|
||||
)
|
||||
for toAddress, ackData, status in queryreturn:
|
||||
toAddress = toAddress.decode("utf-8", "replace")
|
||||
status = status.decode("utf-8", "replace")
|
||||
if status == 'awaitingpubkey':
|
||||
self.resendPubkeyRequest(toAddress)
|
||||
elif status == 'msgsent':
|
||||
|
@ -168,7 +172,7 @@ class singleCleaner(StoppableThread):
|
|||
))
|
||||
sqlExecute(
|
||||
"UPDATE sent SET status = 'msgqueued'"
|
||||
" WHERE toaddress = ? AND folder = 'sent'", address)
|
||||
" WHERE toaddress = ? AND folder = 'sent'", dbstr(address))
|
||||
queues.workerQueue.put(('sendmessage', ''))
|
||||
|
||||
def resendMsg(self, ackdata):
|
||||
|
@ -177,9 +181,13 @@ class singleCleaner(StoppableThread):
|
|||
'It has been a long time and we haven\'t heard an acknowledgement'
|
||||
' to our msg. Sending again.'
|
||||
)
|
||||
rowcount = sqlExecute(
|
||||
"UPDATE sent SET status = 'msgqueued'"
|
||||
" WHERE ackdata = ? AND folder = 'sent'", sqlite3.Binary(ackdata))
|
||||
if rowcount < 1:
|
||||
sqlExecute(
|
||||
"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.UISignalQueue.put((
|
||||
'updateStatusBar',
|
||||
|
|
|
@ -11,6 +11,7 @@ import time
|
|||
from binascii import hexlify, unhexlify
|
||||
from struct import pack
|
||||
from subprocess import call # nosec
|
||||
import sqlite3
|
||||
|
||||
import defaults
|
||||
import helper_inbox
|
||||
|
@ -24,12 +25,15 @@ import protocol
|
|||
import queues
|
||||
import shared
|
||||
import state
|
||||
import tr
|
||||
from addresses import decodeAddress, decodeVarint, encodeVarint
|
||||
from bmconfigparser import config
|
||||
from helper_sql import sqlExecute, sqlQuery
|
||||
from network import knownnodes, StoppableThread, invQueue
|
||||
from six.moves import configparser, queue
|
||||
from six.moves.reprlib import repr
|
||||
import six
|
||||
from dbcompat import dbstr
|
||||
from tr import _translate
|
||||
|
||||
|
||||
def sizeof_fmt(num, suffix='h/s'):
|
||||
|
@ -73,6 +77,7 @@ class singleWorker(StoppableThread):
|
|||
'''SELECT DISTINCT toaddress FROM sent'''
|
||||
''' WHERE (status='awaitingpubkey' AND folder='sent')''')
|
||||
for toAddress, in queryreturn:
|
||||
toAddress = toAddress.decode("utf-8", "replace")
|
||||
toAddressVersionNumber, toStreamNumber, toRipe = \
|
||||
decodeAddress(toAddress)[1:]
|
||||
if toAddressVersionNumber <= 3:
|
||||
|
@ -87,7 +92,7 @@ class singleWorker(StoppableThread):
|
|||
tag = doubleHashOfAddressData[32:]
|
||||
# We'll need this for when we receive a pubkey reply:
|
||||
# it will be encrypted and we'll need to decrypt it.
|
||||
state.neededPubkeys[tag] = (
|
||||
state.neededPubkeys[bytes(tag)] = (
|
||||
toAddress,
|
||||
highlevelcrypto.makeCryptor(
|
||||
hexlify(privEncryptionKey))
|
||||
|
@ -99,17 +104,22 @@ class singleWorker(StoppableThread):
|
|||
for row in queryreturn:
|
||||
ackdata, = row
|
||||
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
|
||||
for oldack in state.ackdataForWhichImWatching:
|
||||
if len(oldack) == 32:
|
||||
# attach legacy header, always constant (msg/1/1)
|
||||
newack = '\x00\x00\x00\x02\x01\x01' + oldack
|
||||
state.ackdataForWhichImWatching[newack] = 0
|
||||
sqlExecute(
|
||||
newack = b'\x00\x00\x00\x02\x01\x01' + oldack
|
||||
state.ackdataForWhichImWatching[bytes(newack)] = 0
|
||||
rowcount = sqlExecute(
|
||||
'''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]
|
||||
|
||||
|
@ -217,9 +227,8 @@ class singleWorker(StoppableThread):
|
|||
return privSigningKeyHex, privEncryptionKeyHex, \
|
||||
pubSigningKey, pubEncryptionKey
|
||||
|
||||
def _doPOWDefaults(self, payload, TTL,
|
||||
log_prefix='',
|
||||
log_time=False):
|
||||
def _doPOWDefaults(
|
||||
self, payload, TTL, log_prefix='', log_time=False):
|
||||
target = 2 ** 64 / (
|
||||
defaults.networkDefaultProofOfWorkNonceTrialsPerByte * (
|
||||
len(payload) + 8
|
||||
|
@ -245,14 +254,16 @@ class singleWorker(StoppableThread):
|
|||
'PoW took %.1f seconds, speed %s.',
|
||||
delta, sizeof_fmt(nonce / delta)
|
||||
)
|
||||
except: # noqa:E722 # NameError
|
||||
except NameError:
|
||||
self.logger.warning("Proof of Work exception")
|
||||
payload = pack('>Q', nonce) + payload
|
||||
return payload
|
||||
|
||||
def doPOWForMyV2Pubkey(self, adressHash):
|
||||
""" This function also broadcasts out the pubkey
|
||||
message once it is done with the POW"""
|
||||
"""
|
||||
This function also broadcasts out the pubkey message once it is
|
||||
done with the POW
|
||||
"""
|
||||
# Look up my stream number based on my address hash
|
||||
myAddress = shared.myAddressesByHash[adressHash]
|
||||
addressVersionNumber, streamNumber = decodeAddress(myAddress)[1:3]
|
||||
|
@ -261,7 +272,7 @@ class singleWorker(StoppableThread):
|
|||
TTL = int(28 * 24 * 60 * 60 + helper_random.randomrandrange(-300, 300))
|
||||
embeddedTime = int(time.time() + TTL)
|
||||
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(streamNumber)
|
||||
# bitfield of features supported by me (see the wiki).
|
||||
|
@ -308,9 +319,10 @@ class singleWorker(StoppableThread):
|
|||
|
||||
def sendOutOrStoreMyV3Pubkey(self, adressHash):
|
||||
"""
|
||||
If this isn't a chan address, this function assembles the pubkey data, does the necessary POW and sends it out.
|
||||
If it *is* a chan then it assembles the pubkey and stores is in the pubkey table so that we can send messages
|
||||
to "ourselves".
|
||||
If this isn't a chan address, this function assembles the pubkey
|
||||
data, does the necessary POW and sends it out.
|
||||
If it *is* a chan then it assembles the pubkey and stores it in
|
||||
the pubkey table so that we can send messages to "ourselves".
|
||||
"""
|
||||
try:
|
||||
myAddress = shared.myAddressesByHash[adressHash]
|
||||
|
@ -338,7 +350,7 @@ class singleWorker(StoppableThread):
|
|||
# expiresTime time.
|
||||
|
||||
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(streamNumber)
|
||||
# bitfield of features supported by me (see the wiki).
|
||||
|
@ -396,9 +408,10 @@ class singleWorker(StoppableThread):
|
|||
|
||||
def sendOutOrStoreMyV4Pubkey(self, myAddress):
|
||||
"""
|
||||
It doesn't send directly anymore. It put is to a queue for another thread to send at an appropriate time,
|
||||
whereas in the past it directly appended it to the outgoing buffer, I think. Same with all the other methods in
|
||||
this class.
|
||||
It doesn't send directly anymore. It put is to a queue for
|
||||
another thread to send at an appropriate time, whereas in the
|
||||
past it directly appended it to the outgoing buffer, I think.
|
||||
Same with all the other methods in this class.
|
||||
"""
|
||||
if not config.has_section(myAddress):
|
||||
# The address has been deleted.
|
||||
|
@ -413,7 +426,7 @@ class singleWorker(StoppableThread):
|
|||
TTL = int(28 * 24 * 60 * 60 + helper_random.randomrandrange(-300, 300))
|
||||
embeddedTime = int(time.time() + TTL)
|
||||
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(streamNumber)
|
||||
dataToEncrypt = protocol.getBitfield(myAddress)
|
||||
|
@ -515,9 +528,15 @@ class singleWorker(StoppableThread):
|
|||
payload, TTL, log_prefix='(For onionpeer object)')
|
||||
|
||||
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] = (
|
||||
objectType, streamNumber, buffer(payload), # noqa: F821
|
||||
embeddedTime, buffer(tag) # noqa: F821
|
||||
objectType, streamNumber, payload_buffer, # noqa: F821
|
||||
embeddedTime, tag_buffer # noqa: F821
|
||||
)
|
||||
self.logger.info(
|
||||
'sending inv (within sendOnionPeerObj function) for object: %s',
|
||||
|
@ -525,7 +544,10 @@ class singleWorker(StoppableThread):
|
|||
invQueue.put((streamNumber, inventoryHash))
|
||||
|
||||
def sendBroadcast(self):
|
||||
"""Send a broadcast-type object (assemble the object, perform PoW and put it to the inv announcement queue)"""
|
||||
"""
|
||||
Send a broadcast-type object (assemble the object, perform PoW
|
||||
and put it to the inv announcement queue)
|
||||
"""
|
||||
# Reset just in case
|
||||
sqlExecute(
|
||||
'''UPDATE sent SET status='broadcastqueued' '''
|
||||
|
@ -534,10 +556,13 @@ class singleWorker(StoppableThread):
|
|||
queryreturn = sqlQuery(
|
||||
'''SELECT fromaddress, subject, message, '''
|
||||
''' ackdata, ttl, encodingtype FROM sent '''
|
||||
''' WHERE status=? and folder='sent' ''', 'broadcastqueued')
|
||||
''' WHERE status=? and folder='sent' ''', dbstr('broadcastqueued'))
|
||||
|
||||
for row in queryreturn:
|
||||
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
|
||||
_, addressVersionNumber, streamNumber, ripe = \
|
||||
decodeAddress(fromaddress)
|
||||
|
@ -556,8 +581,7 @@ class singleWorker(StoppableThread):
|
|||
except ValueError:
|
||||
queues.UISignalQueue.put((
|
||||
'updateSentItemStatusByAckdata', (
|
||||
ackdata,
|
||||
tr._translate(
|
||||
ackdata, _translate(
|
||||
"MainWindow",
|
||||
"Error! Could not find sender address"
|
||||
" (your address) in the keys.dat file."))
|
||||
|
@ -572,17 +596,24 @@ class singleWorker(StoppableThread):
|
|||
queues.UISignalQueue.put((
|
||||
'updateSentItemStatusByAckdata', (
|
||||
ackdata,
|
||||
tr._translate(
|
||||
_translate(
|
||||
"MainWindow",
|
||||
"Error, can't send."))
|
||||
))
|
||||
continue
|
||||
|
||||
if not sqlExecute(
|
||||
rowcount = sqlExecute(
|
||||
'''UPDATE sent SET status='doingbroadcastpow' '''
|
||||
''' WHERE ackdata=? AND status='broadcastqueued' '''
|
||||
''' 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
|
||||
|
||||
# At this time these pubkeys are 65 bytes long
|
||||
|
@ -599,7 +630,7 @@ class singleWorker(StoppableThread):
|
|||
TTL = int(TTL + helper_random.randomrandrange(-300, 300))
|
||||
embeddedTime = int(time.time() + TTL)
|
||||
payload = pack('>Q', embeddedTime)
|
||||
payload += '\x00\x00\x00\x03' # object type: broadcast
|
||||
payload += b'\x00\x00\x00\x03' # object type: broadcast
|
||||
|
||||
if addressVersionNumber <= 3:
|
||||
payload += encodeVarint(4) # broadcast version
|
||||
|
@ -615,7 +646,7 @@ class singleWorker(StoppableThread):
|
|||
tag = doubleHashOfAddressData[32:]
|
||||
payload += tag
|
||||
else:
|
||||
tag = ''
|
||||
tag = b''
|
||||
|
||||
dataToEncrypt = encodeVarint(addressVersionNumber)
|
||||
dataToEncrypt += encodeVarint(streamNumber)
|
||||
|
@ -661,8 +692,7 @@ class singleWorker(StoppableThread):
|
|||
|
||||
queues.UISignalQueue.put((
|
||||
'updateSentItemStatusByAckdata', (
|
||||
ackdata,
|
||||
tr._translate(
|
||||
ackdata, _translate(
|
||||
"MainWindow",
|
||||
"Doing work necessary to send broadcast..."))
|
||||
))
|
||||
|
@ -694,23 +724,30 @@ class singleWorker(StoppableThread):
|
|||
|
||||
queues.UISignalQueue.put((
|
||||
'updateSentItemStatusByAckdata', (
|
||||
ackdata,
|
||||
tr._translate(
|
||||
"MainWindow",
|
||||
"Broadcast sent on %1"
|
||||
).arg(l10n.formatTimestamp()))
|
||||
ackdata, _translate(
|
||||
"MainWindow", "Broadcast sent on {0}"
|
||||
).format(l10n.formatTimestamp()))
|
||||
))
|
||||
|
||||
# Update the status of the message in the 'sent' table to have
|
||||
# a 'broadcastsent' status
|
||||
sqlExecute(
|
||||
rowcount = sqlExecute(
|
||||
'''UPDATE sent SET msgid=?, status=?, lastactiontime=? '''
|
||||
''' 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):
|
||||
"""Send a message-type object (assemble the object, perform PoW and put it to the inv announcement queue)"""
|
||||
"""
|
||||
Send a message-type object (assemble the object, perform PoW
|
||||
and put it to the inv announcement queue)
|
||||
"""
|
||||
# pylint: disable=too-many-nested-blocks
|
||||
# Reset just in case
|
||||
sqlExecute(
|
||||
|
@ -726,6 +763,11 @@ class singleWorker(StoppableThread):
|
|||
for row in queryreturn:
|
||||
toaddress, fromaddress, subject, message, \
|
||||
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
|
||||
_, toAddressVersionNumber, toStreamNumber, toRipe = \
|
||||
decodeAddress(toaddress)
|
||||
|
@ -755,7 +797,7 @@ class singleWorker(StoppableThread):
|
|||
if not sqlExecute(
|
||||
'''UPDATE sent SET status='doingmsgpow' '''
|
||||
''' WHERE toaddress=? AND status='msgqueued' AND folder='sent' ''',
|
||||
toaddress
|
||||
dbstr(toaddress)
|
||||
):
|
||||
continue
|
||||
status = 'doingmsgpow'
|
||||
|
@ -763,7 +805,7 @@ class singleWorker(StoppableThread):
|
|||
# Let's see if we already have the pubkey in our pubkeys table
|
||||
queryreturn = sqlQuery(
|
||||
'''SELECT address FROM pubkeys WHERE address=?''',
|
||||
toaddress
|
||||
dbstr(toaddress)
|
||||
)
|
||||
# If we have the needed pubkey in the pubkey table already,
|
||||
if queryreturn != []:
|
||||
|
@ -771,7 +813,7 @@ class singleWorker(StoppableThread):
|
|||
if not sqlExecute(
|
||||
'''UPDATE sent SET status='doingmsgpow' '''
|
||||
''' WHERE toaddress=? AND status='msgqueued' AND folder='sent' ''',
|
||||
toaddress
|
||||
dbstr(toaddress)
|
||||
):
|
||||
continue
|
||||
status = 'doingmsgpow'
|
||||
|
@ -783,31 +825,31 @@ class singleWorker(StoppableThread):
|
|||
sqlExecute(
|
||||
'''UPDATE pubkeys SET usedpersonally='yes' '''
|
||||
''' WHERE address=?''',
|
||||
toaddress
|
||||
dbstr(toaddress)
|
||||
)
|
||||
# We don't have the needed pubkey in the pubkeys table already.
|
||||
else:
|
||||
if toAddressVersionNumber <= 3:
|
||||
toTag = ''
|
||||
toTag = b''
|
||||
else:
|
||||
toTag = highlevelcrypto.double_sha512(
|
||||
encodeVarint(toAddressVersionNumber)
|
||||
+ encodeVarint(toStreamNumber) + toRipe
|
||||
)[32:]
|
||||
toTag_bytes = bytes(toTag)
|
||||
if toaddress in state.neededPubkeys or \
|
||||
toTag in state.neededPubkeys:
|
||||
toTag_bytes in state.neededPubkeys:
|
||||
# We already sent a request for the pubkey
|
||||
sqlExecute(
|
||||
'''UPDATE sent SET status='awaitingpubkey', '''
|
||||
''' sleeptill=? WHERE toaddress=? '''
|
||||
''' AND status='msgqueued' ''',
|
||||
int(time.time()) + 2.5 * 24 * 60 * 60,
|
||||
toaddress
|
||||
dbstr(toaddress)
|
||||
)
|
||||
queues.UISignalQueue.put((
|
||||
'updateSentItemStatusByToAddress', (
|
||||
toaddress,
|
||||
tr._translate(
|
||||
toaddress, _translate(
|
||||
"MainWindow",
|
||||
"Encryption key was requested earlier."))
|
||||
))
|
||||
|
@ -836,7 +878,8 @@ class singleWorker(StoppableThread):
|
|||
privEncryptionKey = doubleHashOfToAddressData[:32]
|
||||
# The second half of the sha512 hash.
|
||||
tag = doubleHashOfToAddressData[32:]
|
||||
state.neededPubkeys[tag] = (
|
||||
tag_bytes = bytes(tag)
|
||||
state.neededPubkeys[tag_bytes] = (
|
||||
toaddress,
|
||||
highlevelcrypto.makeCryptor(
|
||||
hexlify(privEncryptionKey))
|
||||
|
@ -858,8 +901,8 @@ class singleWorker(StoppableThread):
|
|||
''' status='awaitingpubkey' or '''
|
||||
''' status='doingpubkeypow') AND '''
|
||||
''' folder='sent' ''',
|
||||
toaddress)
|
||||
del state.neededPubkeys[tag]
|
||||
dbstr(toaddress))
|
||||
del state.neededPubkeys[tag_bytes]
|
||||
break
|
||||
# else:
|
||||
# There was something wrong with this
|
||||
|
@ -875,12 +918,11 @@ class singleWorker(StoppableThread):
|
|||
'''UPDATE sent SET '''
|
||||
''' status='doingpubkeypow' WHERE '''
|
||||
''' toaddress=? AND status='msgqueued' AND folder='sent' ''',
|
||||
toaddress
|
||||
dbstr(toaddress)
|
||||
)
|
||||
queues.UISignalQueue.put((
|
||||
'updateSentItemStatusByToAddress', (
|
||||
toaddress,
|
||||
tr._translate(
|
||||
toaddress, _translate(
|
||||
"MainWindow",
|
||||
"Sending a request for the"
|
||||
" recipient\'s encryption key."))
|
||||
|
@ -901,11 +943,10 @@ class singleWorker(StoppableThread):
|
|||
|
||||
# if we aren't sending this to ourselves or a chan
|
||||
if not config.has_section(toaddress):
|
||||
state.ackdataForWhichImWatching[ackdata] = 0
|
||||
state.ackdataForWhichImWatching[bytes(ackdata)] = 0
|
||||
queues.UISignalQueue.put((
|
||||
'updateSentItemStatusByAckdata', (
|
||||
ackdata,
|
||||
tr._translate(
|
||||
ackdata, _translate(
|
||||
"MainWindow",
|
||||
"Looking up the receiver\'s public key"))
|
||||
))
|
||||
|
@ -920,7 +961,7 @@ class singleWorker(StoppableThread):
|
|||
# is too hard then we'll abort.
|
||||
queryreturn = sqlQuery(
|
||||
'SELECT transmitdata FROM pubkeys WHERE address=?',
|
||||
toaddress)
|
||||
dbstr(toaddress))
|
||||
for row in queryreturn: # pylint: disable=redefined-outer-name
|
||||
pubkeyPayload, = row
|
||||
|
||||
|
@ -962,15 +1003,14 @@ class singleWorker(StoppableThread):
|
|||
)
|
||||
queues.UISignalQueue.put((
|
||||
'updateSentItemStatusByAckdata', (
|
||||
ackdata,
|
||||
tr._translate(
|
||||
ackdata, _translate(
|
||||
"MainWindow",
|
||||
"Problem: Destination is a mobile"
|
||||
" device who requests that the"
|
||||
" destination be included in the"
|
||||
" message but this is disallowed in"
|
||||
" your settings. %1"
|
||||
).arg(l10n.formatTimestamp()))
|
||||
" your settings. {0}"
|
||||
).format(l10n.formatTimestamp()))
|
||||
))
|
||||
# if the human changes their setting and then
|
||||
# sends another message or restarts their client,
|
||||
|
@ -993,8 +1033,7 @@ class singleWorker(StoppableThread):
|
|||
defaults.networkDefaultPayloadLengthExtraBytes
|
||||
queues.UISignalQueue.put((
|
||||
'updateSentItemStatusByAckdata', (
|
||||
ackdata,
|
||||
tr._translate(
|
||||
ackdata, _translate(
|
||||
"MainWindow",
|
||||
"Doing work necessary to send message.\n"
|
||||
"There is no required difficulty for"
|
||||
|
@ -1026,32 +1065,19 @@ class singleWorker(StoppableThread):
|
|||
requiredAverageProofOfWorkNonceTrialsPerByte,
|
||||
requiredPayloadLengthExtraBytes
|
||||
)
|
||||
|
||||
queues.UISignalQueue.put(
|
||||
(
|
||||
'updateSentItemStatusByAckdata',
|
||||
(
|
||||
ackdata,
|
||||
tr._translate(
|
||||
queues.UISignalQueue.put((
|
||||
'updateSentItemStatusByAckdata', (
|
||||
ackdata, _translate(
|
||||
"MainWindow",
|
||||
"Doing work necessary to send message.\n"
|
||||
"Receiver\'s required difficulty: %1"
|
||||
" and %2"
|
||||
).arg(
|
||||
str(
|
||||
"Receiver\'s required difficulty: {0} and {1}"
|
||||
).format(
|
||||
float(requiredAverageProofOfWorkNonceTrialsPerByte)
|
||||
/ defaults.networkDefaultProofOfWorkNonceTrialsPerByte
|
||||
)
|
||||
).arg(
|
||||
str(
|
||||
/ defaults.networkDefaultProofOfWorkNonceTrialsPerByte,
|
||||
float(requiredPayloadLengthExtraBytes)
|
||||
/ defaults.networkDefaultPayloadLengthExtraBytes
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
))
|
||||
))
|
||||
if status != 'forcepow':
|
||||
maxacceptablenoncetrialsperbyte = config.getint(
|
||||
'bitmessagesettings', 'maxacceptablenoncetrialsperbyte')
|
||||
|
@ -1065,24 +1091,30 @@ class singleWorker(StoppableThread):
|
|||
if cond1 or cond2:
|
||||
# The demanded difficulty is more than
|
||||
# we are willing to do.
|
||||
sqlExecute(
|
||||
rowcount = sqlExecute(
|
||||
'''UPDATE sent SET status='toodifficult' '''
|
||||
''' 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)
|
||||
queues.UISignalQueue.put((
|
||||
'updateSentItemStatusByAckdata', (
|
||||
ackdata,
|
||||
tr._translate(
|
||||
ackdata, _translate(
|
||||
"MainWindow",
|
||||
"Problem: The work demanded by"
|
||||
" the recipient (%1 and %2) is"
|
||||
" more difficult than you are"
|
||||
" willing to do. %3"
|
||||
).arg(str(float(requiredAverageProofOfWorkNonceTrialsPerByte)
|
||||
/ defaults.networkDefaultProofOfWorkNonceTrialsPerByte)
|
||||
).arg(str(float(requiredPayloadLengthExtraBytes)
|
||||
/ defaults.networkDefaultPayloadLengthExtraBytes)
|
||||
).arg(l10n.formatTimestamp()))))
|
||||
"Problem: The work demanded by the"
|
||||
" recipient ({0} and {1}) is more"
|
||||
" difficult than you are willing"
|
||||
" to do. {2}"
|
||||
).format(
|
||||
float(requiredAverageProofOfWorkNonceTrialsPerByte)
|
||||
/ defaults.networkDefaultProofOfWorkNonceTrialsPerByte,
|
||||
float(requiredPayloadLengthExtraBytes)
|
||||
/ defaults.networkDefaultPayloadLengthExtraBytes,
|
||||
l10n.formatTimestamp()))
|
||||
))
|
||||
continue
|
||||
else: # if we are sending a message to ourselves or a chan..
|
||||
self.logger.info('Sending a message.')
|
||||
|
@ -1096,15 +1128,14 @@ class singleWorker(StoppableThread):
|
|||
except (configparser.NoSectionError, configparser.NoOptionError) as err:
|
||||
queues.UISignalQueue.put((
|
||||
'updateSentItemStatusByAckdata', (
|
||||
ackdata,
|
||||
tr._translate(
|
||||
ackdata, _translate(
|
||||
"MainWindow",
|
||||
"Problem: You are trying to send a"
|
||||
" message to yourself or a chan but your"
|
||||
" encryption key could not be found in"
|
||||
" the keys.dat file. Could not encrypt"
|
||||
" message. %1"
|
||||
).arg(l10n.formatTimestamp()))
|
||||
" message. {0}"
|
||||
).format(l10n.formatTimestamp()))
|
||||
))
|
||||
self.logger.error(
|
||||
'Error within sendMsg. Could not read the keys'
|
||||
|
@ -1122,8 +1153,7 @@ class singleWorker(StoppableThread):
|
|||
defaults.networkDefaultPayloadLengthExtraBytes
|
||||
queues.UISignalQueue.put((
|
||||
'updateSentItemStatusByAckdata', (
|
||||
ackdata,
|
||||
tr._translate(
|
||||
ackdata, _translate(
|
||||
"MainWindow",
|
||||
"Doing work necessary to send message."))
|
||||
))
|
||||
|
@ -1145,8 +1175,7 @@ class singleWorker(StoppableThread):
|
|||
except ValueError:
|
||||
queues.UISignalQueue.put((
|
||||
'updateSentItemStatusByAckdata', (
|
||||
ackdata,
|
||||
tr._translate(
|
||||
ackdata, _translate(
|
||||
"MainWindow",
|
||||
"Error! Could not find sender address"
|
||||
" (your address) in the keys.dat file."))
|
||||
|
@ -1161,7 +1190,7 @@ class singleWorker(StoppableThread):
|
|||
queues.UISignalQueue.put((
|
||||
'updateSentItemStatusByAckdata', (
|
||||
ackdata,
|
||||
tr._translate(
|
||||
_translate(
|
||||
"MainWindow",
|
||||
"Error, can't send."))
|
||||
))
|
||||
|
@ -1201,23 +1230,22 @@ class singleWorker(StoppableThread):
|
|||
'Not bothering to include ackdata because we are'
|
||||
' sending to ourselves or a chan.'
|
||||
)
|
||||
fullAckPayload = ''
|
||||
fullAckPayload = b''
|
||||
elif not protocol.checkBitfield(
|
||||
behaviorBitfield, protocol.BITFIELD_DOESACK):
|
||||
self.logger.info(
|
||||
'Not bothering to include ackdata because'
|
||||
' the receiver said that they won\'t relay it anyway.'
|
||||
)
|
||||
fullAckPayload = ''
|
||||
fullAckPayload = b''
|
||||
else:
|
||||
# The fullAckPayload is a normal msg protocol message
|
||||
# with the proof of work already completed that the
|
||||
# receiver of this message can easily send out.
|
||||
fullAckPayload = self.generateFullAckMessage(
|
||||
ackdata, toStreamNumber, TTL)
|
||||
fullAckPayload = self.generateFullAckMessage(ackdata, TTL)
|
||||
payload += encodeVarint(len(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
|
||||
signature = highlevelcrypto.sign(
|
||||
dataToSign, privSigningKeyHex, self.digestAlg)
|
||||
|
@ -1227,27 +1255,31 @@ class singleWorker(StoppableThread):
|
|||
# We have assembled the data that will be encrypted.
|
||||
try:
|
||||
encrypted = highlevelcrypto.encrypt(
|
||||
payload, "04" + hexlify(pubEncryptionKeyBase256)
|
||||
payload, b"04" + hexlify(pubEncryptionKeyBase256)
|
||||
)
|
||||
except: # noqa:E722
|
||||
self.logger.warning("highlevelcrypto.encrypt didn't work")
|
||||
sqlExecute(
|
||||
rowcount = sqlExecute(
|
||||
'''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
|
||||
)
|
||||
queues.UISignalQueue.put((
|
||||
'updateSentItemStatusByAckdata', (
|
||||
ackdata,
|
||||
tr._translate(
|
||||
ackdata, _translate(
|
||||
"MainWindow",
|
||||
"Problem: The recipient\'s encryption key is"
|
||||
" no good. Could not encrypt message. %1"
|
||||
).arg(l10n.formatTimestamp()))
|
||||
" no good. Could not encrypt message. {0}"
|
||||
).format(l10n.formatTimestamp()))
|
||||
))
|
||||
continue
|
||||
|
||||
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(toStreamNumber) + encrypted
|
||||
target = 2 ** 64 / (
|
||||
|
@ -1306,21 +1338,19 @@ class singleWorker(StoppableThread):
|
|||
not protocol.checkBitfield(behaviorBitfield, protocol.BITFIELD_DOESACK):
|
||||
queues.UISignalQueue.put((
|
||||
'updateSentItemStatusByAckdata', (
|
||||
ackdata,
|
||||
tr._translate(
|
||||
"MainWindow",
|
||||
"Message sent. Sent at %1"
|
||||
).arg(l10n.formatTimestamp()))))
|
||||
ackdata, _translate(
|
||||
"MainWindow", "Message sent. Sent at {0}"
|
||||
).format(l10n.formatTimestamp()))
|
||||
))
|
||||
else:
|
||||
# not sending to a chan or one of my addresses
|
||||
queues.UISignalQueue.put((
|
||||
'updateSentItemStatusByAckdata', (
|
||||
ackdata,
|
||||
tr._translate(
|
||||
ackdata, _translate(
|
||||
"MainWindow",
|
||||
"Message sent. Waiting for acknowledgement."
|
||||
" Sent on %1"
|
||||
).arg(l10n.formatTimestamp()))
|
||||
" Sent on {0}"
|
||||
).format(l10n.formatTimestamp()))
|
||||
))
|
||||
self.logger.info(
|
||||
'Broadcasting inv for my msg(within sendmsg function): %s',
|
||||
|
@ -1337,10 +1367,17 @@ class singleWorker(StoppableThread):
|
|||
newStatus = 'msgsent'
|
||||
# wait 10% past expiration
|
||||
sleepTill = int(time.time() + TTL * 1.1)
|
||||
sqlExecute(
|
||||
rowcount = sqlExecute(
|
||||
'''UPDATE sent SET msgid=?, status=?, retrynumber=?, '''
|
||||
''' 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
|
||||
)
|
||||
|
||||
|
@ -1386,7 +1423,7 @@ class singleWorker(StoppableThread):
|
|||
'''SELECT retrynumber FROM sent WHERE toaddress=? '''
|
||||
''' AND (status='doingpubkeypow' OR status='awaitingpubkey') '''
|
||||
''' AND folder='sent' LIMIT 1''',
|
||||
toAddress
|
||||
dbstr(toAddress)
|
||||
)
|
||||
if not queryReturn:
|
||||
self.logger.critical(
|
||||
|
@ -1412,10 +1449,11 @@ class singleWorker(StoppableThread):
|
|||
privEncryptionKey = doubleHashOfAddressData[:32]
|
||||
# Note that this is the second half of the sha512 hash.
|
||||
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:
|
||||
# it will be encrypted and we'll need to decrypt it.
|
||||
state.neededPubkeys[tag] = (
|
||||
state.neededPubkeys[tag_bytes] = (
|
||||
toAddress,
|
||||
highlevelcrypto.makeCryptor(hexlify(privEncryptionKey))
|
||||
)
|
||||
|
@ -1429,7 +1467,7 @@ class singleWorker(StoppableThread):
|
|||
TTL = TTL + helper_random.randomrandrange(-300, 300)
|
||||
embeddedTime = int(time.time() + TTL)
|
||||
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(streamNumber)
|
||||
if addressVersionNumber <= 3:
|
||||
|
@ -1446,8 +1484,7 @@ class singleWorker(StoppableThread):
|
|||
queues.UISignalQueue.put(('updateStatusBar', statusbar))
|
||||
queues.UISignalQueue.put((
|
||||
'updateSentItemStatusByToAddress', (
|
||||
toAddress,
|
||||
tr._translate(
|
||||
toAddress, _translate(
|
||||
"MainWindow",
|
||||
"Doing work necessary to request encryption key."))
|
||||
))
|
||||
|
@ -1468,33 +1505,34 @@ class singleWorker(StoppableThread):
|
|||
''' status='awaitingpubkey', retrynumber=?, sleeptill=? '''
|
||||
''' WHERE toaddress=? AND (status='doingpubkeypow' OR '''
|
||||
''' status='awaitingpubkey') AND folder='sent' ''',
|
||||
int(time.time()), retryNumber + 1, sleeptill, toAddress)
|
||||
int(time.time()), retryNumber + 1, sleeptill, dbstr(toAddress))
|
||||
|
||||
queues.UISignalQueue.put((
|
||||
'updateStatusBar',
|
||||
tr._translate(
|
||||
'updateStatusBar', _translate(
|
||||
"MainWindow",
|
||||
"Broadcasting the public key request. This program will"
|
||||
" auto-retry if they are offline.")
|
||||
))
|
||||
queues.UISignalQueue.put((
|
||||
'updateSentItemStatusByToAddress', (
|
||||
toAddress,
|
||||
tr._translate(
|
||||
toAddress, _translate(
|
||||
"MainWindow",
|
||||
"Sending public key request. Waiting for reply."
|
||||
" Requested at %1"
|
||||
).arg(l10n.formatTimestamp()))
|
||||
" Requested at {0}"
|
||||
).format(l10n.formatTimestamp()))
|
||||
))
|
||||
|
||||
def generateFullAckMessage(self, ackdata, _, TTL):
|
||||
"""
|
||||
It might be perfectly fine to just use the same TTL for the ackdata that we use for the message. But I would
|
||||
rather it be more difficult for attackers to associate ackData with the associated msg object. However, users
|
||||
would want the TTL of the acknowledgement to be about the same as they set for the message itself. So let's set
|
||||
the TTL of the acknowledgement to be in one of three 'buckets': 1 hour, 7 days, or 28 days, whichever is
|
||||
relatively close to what the user specified.
|
||||
"""
|
||||
def generateFullAckMessage(self, ackdata, TTL):
|
||||
"""Create ACK packet"""
|
||||
# It might be perfectly fine to just use the same TTL for
|
||||
# the ackdata that we use for the message. But I would rather
|
||||
# it be more difficult for attackers to associate ackData with
|
||||
# the associated msg object. However, users would want the TTL
|
||||
# of the acknowledgement to be about the same as they set
|
||||
# for the message itself. So let's set the TTL of the
|
||||
# acknowledgement to be in one of three 'buckets': 1 hour, 7
|
||||
# days, or 28 days, whichever is relatively close to what the
|
||||
# user specified.
|
||||
if TTL < 24 * 60 * 60: # 1 day
|
||||
TTL = 24 * 60 * 60 # 1 day
|
||||
elif TTL < 7 * 24 * 60 * 60: # 1 week
|
||||
|
@ -1511,4 +1549,4 @@ class singleWorker(StoppableThread):
|
|||
payload = self._doPOWDefaults(
|
||||
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
|
||||
|
||||
import smtplib
|
||||
import urlparse
|
||||
from six.moves.urllib import parse as urlparse
|
||||
from email.header import Header
|
||||
from email.mime.text import MIMEText
|
||||
from six.moves import email_mime_text
|
||||
|
||||
import queues
|
||||
import state
|
||||
|
@ -55,7 +55,7 @@ class smtpDeliver(StoppableThread):
|
|||
u = urlparse.urlparse(dest)
|
||||
to = urlparse.parse_qs(u.query)['to']
|
||||
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['From'] = fromAddress + '@' + SMTPDOMAIN
|
||||
toLabel = map(
|
||||
|
|
|
@ -12,6 +12,7 @@ import threading
|
|||
import time
|
||||
from email.header import decode_header
|
||||
from email.parser import Parser
|
||||
import sqlite3
|
||||
|
||||
import queues
|
||||
from addresses import decodeAddress
|
||||
|
@ -20,6 +21,7 @@ from helper_ackPayload import genAckPayload
|
|||
from helper_sql import sqlExecute
|
||||
from network.threads import StoppableThread
|
||||
from version import softwareVersion
|
||||
from dbcompat import dbstr
|
||||
|
||||
SMTPDOMAIN = "bmaddr.lan"
|
||||
LISTENPORT = 8425
|
||||
|
@ -88,19 +90,19 @@ class smtpServerPyBitmessage(smtpd.SMTPServer):
|
|||
ackdata = genAckPayload(streamNumber, stealthLevel)
|
||||
sqlExecute(
|
||||
'''INSERT INTO sent VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)''',
|
||||
'',
|
||||
toAddress,
|
||||
ripe,
|
||||
fromAddress,
|
||||
subject,
|
||||
message,
|
||||
ackdata,
|
||||
sqlite3.Binary(b''),
|
||||
dbstr(toAddress),
|
||||
sqlite3.Binary(ripe),
|
||||
dbstr(fromAddress),
|
||||
dbstr(subject),
|
||||
dbstr(message),
|
||||
sqlite3.Binary(ackdata),
|
||||
int(time.time()), # sentTime (this will never change)
|
||||
int(time.time()), # lastActionTime
|
||||
0, # sleepTill time. This will get set when the POW gets done.
|
||||
'msgqueued',
|
||||
dbstr('msgqueued'),
|
||||
0, # retryNumber
|
||||
'sent', # folder
|
||||
dbstr('sent'), # folder
|
||||
2, # encodingtype
|
||||
# not necessary to have a TTL higher than 2 days
|
||||
min(config.getint('bitmessagesettings', 'ttl'), 86400 * 2)
|
||||
|
|
|
@ -8,6 +8,7 @@ import sqlite3
|
|||
import sys
|
||||
import threading
|
||||
import time
|
||||
from six.moves.reprlib import repr
|
||||
|
||||
try:
|
||||
import helper_sql
|
||||
|
@ -38,7 +39,7 @@ class sqlThread(threading.Thread):
|
|||
helper_sql.sql_available = True
|
||||
config_ready.wait()
|
||||
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.execute('PRAGMA secure_delete = true')
|
||||
|
@ -73,7 +74,7 @@ class sqlThread(threading.Thread):
|
|||
'''INSERT INTO subscriptions VALUES'''
|
||||
'''('Bitmessage new releases/announcements','BM-GtovgYdgs7qXPkoYaRgrLFuFKz1SFpsw',1)''')
|
||||
self.cur.execute(
|
||||
'''CREATE TABLE settings (key blob, value blob, UNIQUE(key) ON CONFLICT REPLACE)''')
|
||||
'''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('lastvacuumtime',?)''', (
|
||||
int(time.time()),))
|
||||
|
@ -542,7 +543,7 @@ class sqlThread(threading.Thread):
|
|||
shutil.move(
|
||||
paths.lookupAppdataFolder() + 'messages.dat', 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()
|
||||
elif item == 'movemessagstoappdata':
|
||||
logger.debug('the sqlThread is moving the messages.dat file to the Appdata folder.')
|
||||
|
@ -568,7 +569,7 @@ class sqlThread(threading.Thread):
|
|||
shutil.move(
|
||||
paths.lookupExeFolder() + 'messages.dat', 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()
|
||||
elif item == 'deleteandvacuume':
|
||||
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..
|
103
src/depends.py
103
src/depends.py
|
@ -6,6 +6,7 @@ and suggest how it may be installed
|
|||
import os
|
||||
import re
|
||||
import sys
|
||||
import six
|
||||
|
||||
# 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
|
||||
|
@ -17,6 +18,7 @@ if not hasattr(sys, 'hexversion') or sys.hexversion < 0x20300F0:
|
|||
)
|
||||
|
||||
import logging # noqa:E402
|
||||
from distutils import version
|
||||
import subprocess # nosec B404
|
||||
|
||||
from importlib import import_module
|
||||
|
@ -53,23 +55,23 @@ PACKAGE_MANAGER = {
|
|||
}
|
||||
|
||||
PACKAGES = {
|
||||
"PyQt4": {
|
||||
"OpenBSD": "py-qt4",
|
||||
"FreeBSD": "py27-qt4",
|
||||
"Debian": "python-qt4",
|
||||
"Ubuntu": "python-qt4",
|
||||
"Ubuntu 12": "python-qt4",
|
||||
"Ubuntu 20": "",
|
||||
"openSUSE": "python-qt",
|
||||
"Fedora": "PyQt4",
|
||||
"Guix": "python2-pyqt@4.11.4",
|
||||
"Gentoo": "dev-python/PyQt4",
|
||||
"qtpy": {
|
||||
"OpenBSD": "py-qtpy",
|
||||
"FreeBSD": "py27-QtPy",
|
||||
"Debian": "python-qtpy",
|
||||
"Ubuntu": "python-qtpy",
|
||||
"Ubuntu 12": "python-qtpy",
|
||||
"Ubuntu 20": "python-qtpy",
|
||||
"openSUSE": "python-QtPy",
|
||||
"Fedora": "python2-QtPy",
|
||||
"Guix": "",
|
||||
"Gentoo": "dev-python/QtPy",
|
||||
"optional": True,
|
||||
"description":
|
||||
"You only need PyQt if you want to use the GUI."
|
||||
"You only need qtpy if you want to use the GUI."
|
||||
" When only running as a daemon, this can be skipped.\n"
|
||||
"However, you would have to install it manually"
|
||||
" because setuptools does not support PyQt."
|
||||
"Also maybe you need to install PyQt5 or PyQt4"
|
||||
" if your package manager not installs it as qtpy dependency"
|
||||
},
|
||||
"msgpack": {
|
||||
"OpenBSD": "py-msgpack",
|
||||
|
@ -156,19 +158,19 @@ detectOS.result = None
|
|||
def detectOSRelease():
|
||||
"""Detecting the release of OS"""
|
||||
with open("/etc/os-release", 'r') as osRelease:
|
||||
version = None
|
||||
ver = None
|
||||
for line in osRelease:
|
||||
if line.startswith("NAME="):
|
||||
detectOS.result = OS_RELEASE.get(
|
||||
line.replace('"', '').split("=")[-1].strip().lower())
|
||||
elif line.startswith("VERSION_ID="):
|
||||
try:
|
||||
version = float(line.split("=")[1].replace("\"", ""))
|
||||
ver = float(line.split("=")[1].replace("\"", ""))
|
||||
except ValueError:
|
||||
pass
|
||||
if detectOS.result == "Ubuntu" and version < 14:
|
||||
if detectOS.result == "Ubuntu" and ver < 14:
|
||||
detectOS.result = "Ubuntu 12"
|
||||
elif detectOS.result == "Ubuntu" and version >= 20:
|
||||
elif detectOS.result == "Ubuntu" and ver >= 20:
|
||||
detectOS.result = "Ubuntu 20"
|
||||
|
||||
|
||||
|
@ -191,7 +193,7 @@ def try_import(module, log_extra=False):
|
|||
def check_ripemd160():
|
||||
"""Check availability of the RIPEMD160 hash function"""
|
||||
try:
|
||||
from fallback import RIPEMD160Hash # pylint: disable=relative-import
|
||||
from fallback import RIPEMD160Hash
|
||||
except ImportError:
|
||||
return False
|
||||
return RIPEMD160Hash is not None
|
||||
|
@ -380,33 +382,71 @@ def check_curses():
|
|||
def check_pyqt():
|
||||
"""Do pyqt dependency check.
|
||||
|
||||
Here we are checking for PyQt4 with its version, as for it require
|
||||
PyQt 4.8 or later.
|
||||
Here we are checking for qtpy with its version, as for it require
|
||||
qtpy.
|
||||
"""
|
||||
# pylint: disable=no-member
|
||||
try:
|
||||
import qtpy
|
||||
except ImportError:
|
||||
logger.error(
|
||||
'PyBitmessage requires qtpy, and PyQt5 or PyQt4, '
|
||||
' PyQt 4.8 or later and Qt 4.7 or later.')
|
||||
return False
|
||||
|
||||
sip_found = False
|
||||
try:
|
||||
import sip
|
||||
sip.setapi("QString", 2)
|
||||
sip.setapi("QVariant", 2)
|
||||
sip_found = True
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
QtCore = try_import(
|
||||
'PyQt4.QtCore', 'PyBitmessage requires PyQt 4.8 or later and Qt 4.7 or later.')
|
||||
'qtpy.QtCore', 'PyBitmessage requires qtpy and Qt 4.7 or later.')
|
||||
|
||||
if not QtCore:
|
||||
return False
|
||||
|
||||
try:
|
||||
logger.info('PyQt Version: %s', QtCore.PYQT_VERSION_STR)
|
||||
logger.info('Qt Version: %s', QtCore.QT_VERSION_STR)
|
||||
except AttributeError:
|
||||
logger.info('Can be PySide..')
|
||||
try:
|
||||
logger.info('Qt Version: %s', QtCore.__version__)
|
||||
except AttributeError:
|
||||
# Can be PySide..
|
||||
pass
|
||||
passed = True
|
||||
if QtCore.PYQT_VERSION < 0x40800:
|
||||
|
||||
try:
|
||||
if version.LooseVersion(QtCore.PYQT_VERSION_STR) < '4.8':
|
||||
logger.error(
|
||||
'This version of PyQt is too old. PyBitmessage requries'
|
||||
' PyQt 4.8 or later.')
|
||||
passed = False
|
||||
if QtCore.QT_VERSION < 0x40700:
|
||||
except AttributeError:
|
||||
# Can be PySide..
|
||||
pass
|
||||
try:
|
||||
if version.LooseVersion(QtCore.__version__) < '4.7':
|
||||
logger.error(
|
||||
'This version of Qt is too old. PyBitmessage requries'
|
||||
' Qt 4.7 or later.')
|
||||
passed = False
|
||||
except AttributeError:
|
||||
# Can be PySide..
|
||||
pass
|
||||
|
||||
if passed and not sip_found:
|
||||
logger.info("sip is not found although PyQt is found")
|
||||
return False
|
||||
|
||||
return passed
|
||||
|
||||
|
||||
def check_msgpack():
|
||||
"""Do sgpack module check.
|
||||
"""Do msgpack module check.
|
||||
|
||||
simply checking if msgpack package with all its dependency
|
||||
is available or not as recommended for messages coding.
|
||||
|
@ -435,14 +475,9 @@ def check_dependencies(verbose=False, optional=False):
|
|||
logger.info('Python version: %s', sys.version)
|
||||
if sys.hexversion < 0x20704F0:
|
||||
logger.error(
|
||||
'PyBitmessage requires Python 2.7.4 or greater'
|
||||
' (but not Python 3+)')
|
||||
'PyBitmessage requires Python 2.7.4 or greater.'
|
||||
' Python 2.7.18 is recommended.')
|
||||
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
|
||||
# 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=unused-argument
|
||||
|
||||
import collections
|
||||
import io
|
||||
from collections import OrderedDict
|
||||
from six.moves.collections_abc import Hashable
|
||||
from six.moves import range as xrange
|
||||
import struct
|
||||
import sys
|
||||
import six
|
||||
|
||||
__version__ = "2.4.1"
|
||||
"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):
|
||||
raise TypeError("ext type out of range")
|
||||
# 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\'")
|
||||
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\'")
|
||||
self.type = type
|
||||
self.data = data
|
||||
|
@ -125,7 +127,7 @@ class Ext: # pylint: disable=old-style-class
|
|||
String representation of this Ext object.
|
||||
"""
|
||||
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))])
|
||||
if len(self.data) > 8:
|
||||
s += " ..."
|
||||
|
@ -549,7 +551,7 @@ def _packb2(obj, **options):
|
|||
'\x82\xa7compact\xc3\xa6schema\x00'
|
||||
>>>
|
||||
"""
|
||||
fp = io.BytesIO()
|
||||
fp = six.BytesIO()
|
||||
_pack2(obj, fp, **options)
|
||||
return fp.getvalue()
|
||||
|
||||
|
@ -582,7 +584,7 @@ def _packb3(obj, **options):
|
|||
b'\x82\xa7compact\xc3\xa6schema\x00'
|
||||
>>>
|
||||
"""
|
||||
fp = io.BytesIO()
|
||||
fp = six.BytesIO()
|
||||
_pack3(obj, fp, **options)
|
||||
return fp.getvalue()
|
||||
|
||||
|
@ -599,7 +601,7 @@ def _read_except(fp, n):
|
|||
|
||||
|
||||
def _unpack_integer(code, fp, options):
|
||||
if (ord(code) & 0xe0) == 0xe0:
|
||||
if (six.byte2int(code) & 0xe0) == 0xe0:
|
||||
return struct.unpack("b", code)[0]
|
||||
elif code == b'\xd0':
|
||||
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]
|
||||
elif code == b'\xd3':
|
||||
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]
|
||||
elif code == b'\xcc':
|
||||
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]
|
||||
elif code == b'\xcf':
|
||||
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):
|
||||
if code == b'\xc1':
|
||||
raise ReservedCodeException(
|
||||
"encountered reserved code: 0x%02x" % ord(code))
|
||||
"encountered reserved code: 0x%02x" % six.byte2int(code))
|
||||
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):
|
||||
if code == b'\xc0':
|
||||
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):
|
||||
|
@ -641,7 +643,7 @@ def _unpack_boolean(code, fp, options):
|
|||
return False
|
||||
elif code == b'\xc3':
|
||||
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):
|
||||
|
@ -649,12 +651,12 @@ def _unpack_float(code, fp, options):
|
|||
return struct.unpack(">f", _read_except(fp, 4))[0]
|
||||
elif code == b'\xcb':
|
||||
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):
|
||||
if (ord(code) & 0xe0) == 0xa0:
|
||||
length = ord(code) & ~0xe0
|
||||
if (six.byte2int(code) & 0xe0) == 0xa0:
|
||||
length = six.byte2int(code) & ~0xe0
|
||||
elif code == b'\xd9':
|
||||
length = struct.unpack("B", _read_except(fp, 1))[0]
|
||||
elif code == b'\xda':
|
||||
|
@ -662,7 +664,7 @@ def _unpack_string(code, fp, options):
|
|||
elif code == b'\xdb':
|
||||
length = struct.unpack(">I", _read_except(fp, 4))[0]
|
||||
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
|
||||
global compatibility
|
||||
|
@ -686,7 +688,7 @@ def _unpack_binary(code, fp, options):
|
|||
elif code == b'\xc6':
|
||||
length = struct.unpack(">I", _read_except(fp, 4))[0]
|
||||
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)
|
||||
|
||||
|
@ -709,9 +711,9 @@ def _unpack_ext(code, fp, options):
|
|||
elif code == b'\xc9':
|
||||
length = struct.unpack(">I", _read_except(fp, 4))[0]
|
||||
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
|
||||
ext_handlers = options.get("ext_handlers")
|
||||
|
@ -722,14 +724,14 @@ def _unpack_ext(code, fp, options):
|
|||
|
||||
|
||||
def _unpack_array(code, fp, options):
|
||||
if (ord(code) & 0xf0) == 0x90:
|
||||
length = (ord(code) & ~0xf0)
|
||||
if (six.byte2int(code) & 0xf0) == 0x90:
|
||||
length = (six.byte2int(code) & ~0xf0)
|
||||
elif code == b'\xdc':
|
||||
length = struct.unpack(">H", _read_except(fp, 2))[0]
|
||||
elif code == b'\xdd':
|
||||
length = struct.unpack(">I", _read_except(fp, 4))[0]
|
||||
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)]
|
||||
|
||||
|
@ -741,17 +743,17 @@ def _deep_list_to_tuple(obj):
|
|||
|
||||
|
||||
def _unpack_map(code, fp, options):
|
||||
if (ord(code) & 0xf0) == 0x80:
|
||||
length = (ord(code) & ~0xf0)
|
||||
if (six.byte2int(code) & 0xf0) == 0x80:
|
||||
length = (six.byte2int(code) & ~0xf0)
|
||||
elif code == b'\xde':
|
||||
length = struct.unpack(">H", _read_except(fp, 2))[0]
|
||||
elif code == b'\xdf':
|
||||
length = struct.unpack(">I", _read_except(fp, 4))[0]
|
||||
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') \
|
||||
else collections.OrderedDict()
|
||||
else OrderedDict()
|
||||
for _ in xrange(length):
|
||||
# Unpack key
|
||||
k = _unpack(fp, options)
|
||||
|
@ -759,7 +761,7 @@ def _unpack_map(code, fp, options):
|
|||
if isinstance(k, list):
|
||||
# Attempt to convert list into a hashable tuple
|
||||
k = _deep_list_to_tuple(k)
|
||||
elif not isinstance(k, collections.Hashable):
|
||||
elif not isinstance(k, Hashable):
|
||||
raise UnhashableKeyException(
|
||||
"encountered unhashable key: %s, %s" % (str(k), str(type(k))))
|
||||
elif k in d:
|
||||
|
@ -911,7 +913,7 @@ def _unpackb2(s, **options):
|
|||
"""
|
||||
if not isinstance(s, (str, 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
|
||||
|
@ -957,7 +959,7 @@ def _unpackb3(s, **options):
|
|||
"""
|
||||
if not isinstance(s, (bytes, 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
|
||||
|
@ -990,7 +992,7 @@ def __init():
|
|||
_float_precision = "single"
|
||||
|
||||
# Map packb and unpackb to the appropriate version
|
||||
if sys.version_info[0] == 3:
|
||||
if six.PY3:
|
||||
pack = _pack3
|
||||
packb = _packb3
|
||||
dump = _pack3
|
||||
|
|
|
@ -4,11 +4,12 @@ Insert value into addressbook
|
|||
|
||||
from bmconfigparser import config
|
||||
from helper_sql import sqlExecute
|
||||
from dbcompat import dbstr
|
||||
|
||||
|
||||
def insert(address, label):
|
||||
"""perform insert into addressbook"""
|
||||
|
||||
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
|
||||
|
|
|
@ -19,17 +19,17 @@ def calculateBitcoinAddressFromPubkey(pubkey):
|
|||
sha = hashlib.new('sha256')
|
||||
sha.update(pubkey)
|
||||
ripe.update(sha.digest())
|
||||
ripeWithProdnetPrefix = '\x00' + ripe.digest()
|
||||
ripeWithProdnetPrefix = b'\x00' + ripe.digest()
|
||||
|
||||
checksum = hashlib.sha256(hashlib.sha256(
|
||||
ripeWithProdnetPrefix).digest()).digest()[:4]
|
||||
binaryBitcoinAddress = ripeWithProdnetPrefix + checksum
|
||||
numberOfZeroBytesOnBinaryBitcoinAddress = 0
|
||||
while binaryBitcoinAddress[0] == '\x00':
|
||||
while binaryBitcoinAddress[0] == b'\x00':
|
||||
numberOfZeroBytesOnBinaryBitcoinAddress += 1
|
||||
binaryBitcoinAddress = binaryBitcoinAddress[1:]
|
||||
base58encoded = arithmetic.changebase(binaryBitcoinAddress, 256, 58)
|
||||
return "1" * numberOfZeroBytesOnBinaryBitcoinAddress + base58encoded
|
||||
return b"1" * numberOfZeroBytesOnBinaryBitcoinAddress + base58encoded
|
||||
|
||||
|
||||
def calculateTestnetAddressFromPubkey(pubkey):
|
||||
|
@ -43,14 +43,14 @@ def calculateTestnetAddressFromPubkey(pubkey):
|
|||
sha = hashlib.new('sha256')
|
||||
sha.update(pubkey)
|
||||
ripe.update(sha.digest())
|
||||
ripeWithProdnetPrefix = '\x6F' + ripe.digest()
|
||||
ripeWithProdnetPrefix = b'\x6F' + ripe.digest()
|
||||
|
||||
checksum = hashlib.sha256(hashlib.sha256(
|
||||
ripeWithProdnetPrefix).digest()).digest()[:4]
|
||||
binaryBitcoinAddress = ripeWithProdnetPrefix + checksum
|
||||
numberOfZeroBytesOnBinaryBitcoinAddress = 0
|
||||
while binaryBitcoinAddress[0] == '\x00':
|
||||
while binaryBitcoinAddress[0] == b'\x00':
|
||||
numberOfZeroBytesOnBinaryBitcoinAddress += 1
|
||||
binaryBitcoinAddress = binaryBitcoinAddress[1:]
|
||||
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"""
|
||||
|
||||
import sqlite3
|
||||
|
||||
import queues
|
||||
from helper_sql import sqlExecute, sqlQuery
|
||||
from dbcompat import dbstr
|
||||
|
||||
|
||||
def insert(t):
|
||||
"""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
|
||||
# at the same time
|
||||
# queues.UISignalQueue.put(('changedInboxUnread', None))
|
||||
|
@ -14,22 +18,31 @@ def insert(t):
|
|||
|
||||
def trash(msgid):
|
||||
"""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))
|
||||
|
||||
|
||||
def delete(ack_data):
|
||||
"""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):
|
||||
"""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):
|
||||
"""Check for previous instances of this message"""
|
||||
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
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
Message encoding end decoding functions
|
||||
"""
|
||||
|
||||
import string
|
||||
import zlib
|
||||
|
||||
import messagetypes
|
||||
|
@ -71,7 +70,8 @@ class MsgEncode(object):
|
|||
|
||||
def encodeSimple(self, message):
|
||||
"""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)
|
||||
|
||||
def encodeTrivial(self, message):
|
||||
|
@ -99,14 +99,14 @@ class MsgDecode(object):
|
|||
def decodeExtended(self, data):
|
||||
"""Handle extended encoding"""
|
||||
dc = zlib.decompressobj()
|
||||
tmp = ""
|
||||
tmp = b""
|
||||
while len(tmp) <= config.safeGetInt("zlib", "maxsize"):
|
||||
try:
|
||||
got = dc.decompress(
|
||||
data, config.safeGetInt("zlib", "maxsize")
|
||||
+ 1 - len(tmp))
|
||||
# EOF
|
||||
if got == "":
|
||||
if got == b"":
|
||||
break
|
||||
tmp += got
|
||||
data = dc.unconsumed_tail
|
||||
|
@ -142,7 +142,7 @@ class MsgDecode(object):
|
|||
|
||||
def decodeSimple(self, data):
|
||||
"""Handle simple encoding"""
|
||||
bodyPositionIndex = string.find(data, '\nBody:')
|
||||
bodyPositionIndex = data.find(b'\nBody:')
|
||||
if bodyPositionIndex > 1:
|
||||
subject = data[8:bodyPositionIndex]
|
||||
# Only save and show the first 500 characters of the subject.
|
||||
|
@ -150,10 +150,11 @@ class MsgDecode(object):
|
|||
subject = subject[:500]
|
||||
body = data[bodyPositionIndex + 6:]
|
||||
else:
|
||||
subject = ''
|
||||
subject = b''
|
||||
body = data
|
||||
# Throw away any extra lines (headers) after the subject.
|
||||
if subject:
|
||||
subject = subject.splitlines()[0]
|
||||
self.subject = subject
|
||||
self.body = body
|
||||
# Field types should be the same for all message types
|
||||
self.subject = subject.decode("utf-8", "replace")
|
||||
self.body = body.decode("utf-8", "replace")
|
||||
|
|
|
@ -5,6 +5,7 @@ Used by :mod:`.bitmessageqt`.
|
|||
|
||||
from helper_sql import sqlQuery
|
||||
from tr import _translate
|
||||
from dbcompat import dbstr
|
||||
|
||||
|
||||
def search_sql(
|
||||
|
@ -52,23 +53,23 @@ def search_sql(
|
|||
if account is not None:
|
||||
if xAddress == 'both':
|
||||
sqlStatementParts.append('(fromaddress = ? OR toaddress = ?)')
|
||||
sqlArguments.append(account)
|
||||
sqlArguments.append(account)
|
||||
sqlArguments.append(dbstr(account))
|
||||
sqlArguments.append(dbstr(account))
|
||||
else:
|
||||
sqlStatementParts.append(xAddress + ' = ? ')
|
||||
sqlArguments.append(account)
|
||||
sqlArguments.append(dbstr(account))
|
||||
if folder is not None:
|
||||
if folder == 'new':
|
||||
folder = 'inbox'
|
||||
unreadOnly = True
|
||||
sqlStatementParts.append('folder = ? ')
|
||||
sqlArguments.append(folder)
|
||||
sqlArguments.append(dbstr(folder))
|
||||
else:
|
||||
sqlStatementParts.append('folder != ?')
|
||||
sqlArguments.append('trash')
|
||||
sqlArguments.append(dbstr('trash'))
|
||||
if what:
|
||||
sqlStatementParts.append('%s LIKE ?' % (where))
|
||||
sqlArguments.append(what)
|
||||
sqlArguments.append(dbstr(what))
|
||||
if unreadOnly:
|
||||
sqlStatementParts.append('read = 0')
|
||||
if sqlStatementParts:
|
||||
|
|
|
@ -4,10 +4,12 @@ Insert values into sent table
|
|||
|
||||
import time
|
||||
import uuid
|
||||
import sqlite3
|
||||
from addresses import decodeAddress
|
||||
from bmconfigparser import config
|
||||
from helper_ackPayload import genAckPayload
|
||||
from helper_sql import sqlExecute, sqlQuery
|
||||
from dbcompat import dbstr
|
||||
|
||||
|
||||
# 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')
|
||||
|
||||
t = (msgid, toAddress, ripe, fromAddress, subject, message, ackdata,
|
||||
sentTime, lastActionTime, sleeptill, status, retryNumber, folder,
|
||||
t = (sqlite3.Binary(msgid), dbstr(toAddress), sqlite3.Binary(ripe), dbstr(fromAddress), dbstr(subject), dbstr(message), sqlite3.Binary(ackdata),
|
||||
sentTime, lastActionTime, sleeptill, dbstr(status), retryNumber, dbstr(folder),
|
||||
encoding, ttl)
|
||||
|
||||
sqlExecute('''INSERT INTO sent VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)''', *t)
|
||||
|
@ -50,13 +52,19 @@ def insert(msgid=None, toAddress='[Broadcast subscribers]', fromAddress=None, su
|
|||
|
||||
def delete(ack_data):
|
||||
"""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):
|
||||
"""Retrieving Message details"""
|
||||
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
|
||||
|
||||
|
@ -64,6 +72,10 @@ def retrieve_message_details(ack_data):
|
|||
def trash(ackdata):
|
||||
"""Mark a message in the `sent` as `trash`"""
|
||||
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
|
||||
|
|
|
@ -61,7 +61,7 @@ def sqlQuery(sql_statement, *args):
|
|||
return queryreturn
|
||||
|
||||
|
||||
def sqlExecuteChunked(sql_statement, idCount, *args):
|
||||
def sqlExecuteChunked(sql_statement, as_text, idCount, *args):
|
||||
"""Execute chunked SQL statement to avoid argument limit"""
|
||||
# SQLITE_MAX_VARIABLE_NUMBER,
|
||||
# unfortunately getting/setting isn't exposed to python
|
||||
|
@ -80,6 +80,15 @@ def sqlExecuteChunked(sql_statement, idCount, *args):
|
|||
chunk_slice = args[
|
||||
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(
|
||||
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>`_
|
||||
"""
|
||||
|
||||
from unqstr import unic
|
||||
|
||||
import hashlib
|
||||
import os
|
||||
from binascii import hexlify
|
||||
|
@ -102,7 +104,7 @@ def random_keys():
|
|||
|
||||
def deterministic_keys(passphrase, nonce):
|
||||
"""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)
|
||||
return priv, pub
|
||||
|
||||
|
|
|
@ -28,8 +28,6 @@ class Inventory:
|
|||
|
||||
# cheap inheritance copied from asyncore
|
||||
def __getattr__(self, attr):
|
||||
if attr == "__contains__":
|
||||
self.numberOfInventoryLookupsPerformed += 1
|
||||
try:
|
||||
realRet = getattr(self._realInventory, attr)
|
||||
except AttributeError:
|
||||
|
@ -40,6 +38,10 @@ class Inventory:
|
|||
else:
|
||||
return realRet
|
||||
|
||||
def __contains__(self, key):
|
||||
self.numberOfInventoryLookupsPerformed += 1
|
||||
return key in self._realInventory
|
||||
|
||||
# hint for pylint: this is dictionary like object
|
||||
def __getitem__(self, key):
|
||||
return self._realInventory[key]
|
||||
|
|
|
@ -3,8 +3,8 @@
|
|||
import logging
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import time
|
||||
import six
|
||||
|
||||
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
|
||||
# so we perform comprehensive decoding tests
|
||||
elif sys.version_info[0] == 2:
|
||||
elif six.PY2:
|
||||
try:
|
||||
# Check day names
|
||||
for i in range(7):
|
||||
|
@ -118,7 +118,7 @@ def formatTimestamp(timestamp=None):
|
|||
except ValueError:
|
||||
timestring = time.strftime(time_format)
|
||||
|
||||
if sys.version_info[0] == 2:
|
||||
if six.PY2:
|
||||
return timestring.decode(encoding)
|
||||
return timestring
|
||||
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
"""
|
||||
Namecoin queries
|
||||
"""
|
||||
# pylint: disable=too-many-branches,protected-access
|
||||
# pylint: disable=too-many-branches
|
||||
|
||||
import base64
|
||||
import httplib
|
||||
from six.moves import http_client as httplib
|
||||
import json
|
||||
import os
|
||||
import socket
|
||||
|
@ -14,14 +14,14 @@ import defaults
|
|||
from addresses import decodeAddress
|
||||
from bmconfigparser import config
|
||||
from debug import logger
|
||||
from tr import _translate # translate
|
||||
from tr import _translate
|
||||
|
||||
|
||||
configSection = "bitmessagesettings"
|
||||
|
||||
|
||||
class RPCError(Exception):
|
||||
"""Error thrown when the RPC call returns an error."""
|
||||
|
||||
error = None
|
||||
|
||||
def __init__(self, data):
|
||||
|
@ -29,7 +29,7 @@ class RPCError(Exception):
|
|||
self.error = data
|
||||
|
||||
def __str__(self):
|
||||
return "{0}: {1}".format(type(self).__name__, self.error)
|
||||
return '{0}: {1}'.format(type(self).__name__, self.error)
|
||||
|
||||
|
||||
class namecoinConnection(object):
|
||||
|
@ -69,7 +69,7 @@ class namecoinConnection(object):
|
|||
self.user = options["user"]
|
||||
self.password = options["password"]
|
||||
|
||||
assert self.nmctype == "namecoind" or self.nmctype == "nmcontrol"
|
||||
assert self.nmctype in ("namecoind", "nmcontrol")
|
||||
if self.nmctype == "namecoind":
|
||||
self.con = httplib.HTTPConnection(self.host, self.port, timeout=3)
|
||||
|
||||
|
@ -96,8 +96,8 @@ class namecoinConnection(object):
|
|||
res = res["reply"]
|
||||
if not res:
|
||||
return (_translate(
|
||||
"MainWindow", "The name %1 was not found."
|
||||
).arg(identity.decode("utf-8", "ignore")), None)
|
||||
"MainWindow", "The name {0} was not found."
|
||||
).format(identity.decode("utf-8", "ignore")), None)
|
||||
else:
|
||||
assert False
|
||||
except RPCError as exc:
|
||||
|
@ -107,12 +107,12 @@ class namecoinConnection(object):
|
|||
else:
|
||||
errmsg = exc.error
|
||||
return (_translate(
|
||||
"MainWindow", "The namecoin query failed (%1)"
|
||||
).arg(errmsg.decode("utf-8", "ignore")), None)
|
||||
"MainWindow", "The namecoin query failed ({0})"
|
||||
).format(errmsg.decode("utf-8", "ignore")), None)
|
||||
except AssertionError:
|
||||
return (_translate(
|
||||
"MainWindow", "Unknown namecoin interface type: %1"
|
||||
).arg(self.nmctype.decode("utf-8", "ignore")), None)
|
||||
"MainWindow", "Unknown namecoin interface type: {0}"
|
||||
).format(self.nmctype.decode("utf-8", "ignore")), None)
|
||||
except Exception:
|
||||
logger.exception("Namecoin query exception")
|
||||
return (_translate(
|
||||
|
@ -135,8 +135,8 @@ class namecoinConnection(object):
|
|||
) if valid else (
|
||||
_translate(
|
||||
"MainWindow",
|
||||
"The name %1 has no associated Bitmessage address."
|
||||
).arg(identity.decode("utf-8", "ignore")), None)
|
||||
"The name {0} has no associated Bitmessage address."
|
||||
).format(identity.decode("utf-8", "ignore")), None)
|
||||
|
||||
def test(self):
|
||||
"""
|
||||
|
@ -160,11 +160,10 @@ class namecoinConnection(object):
|
|||
versStr = "0.%d.%d" % (v1, v2)
|
||||
else:
|
||||
versStr = "0.%d.%d.%d" % (v1, v2, v3)
|
||||
message = (
|
||||
"success",
|
||||
_translate(
|
||||
return (
|
||||
'success', _translate(
|
||||
"MainWindow",
|
||||
"Success! Namecoind version %1 running.").arg(
|
||||
"Success! Namecoind version {0} running.").format(
|
||||
versStr.decode("utf-8", "ignore")))
|
||||
|
||||
elif self.nmctype == "nmcontrol":
|
||||
|
@ -172,32 +171,24 @@ class namecoinConnection(object):
|
|||
prefix = "Plugin data running"
|
||||
if ("reply" in res) and res["reply"][:len(prefix)] == prefix:
|
||||
return (
|
||||
"success",
|
||||
_translate(
|
||||
'success', _translate(
|
||||
"MainWindow",
|
||||
"Success! NMControll is up and running."
|
||||
)
|
||||
"Success! NMControll is up and running.")
|
||||
)
|
||||
|
||||
logger.error("Unexpected nmcontrol reply: %s", res)
|
||||
message = (
|
||||
"failed",
|
||||
_translate(
|
||||
"MainWindow",
|
||||
"Couldn\'t understand NMControl."
|
||||
)
|
||||
return (
|
||||
'failed', _translate(
|
||||
"MainWindow", "Couldn\'t understand NMControl.")
|
||||
)
|
||||
|
||||
else:
|
||||
sys.exit("Unsupported Namecoin type")
|
||||
|
||||
return message
|
||||
|
||||
except Exception:
|
||||
logger.info("Namecoin connection test failure")
|
||||
return (
|
||||
"failed",
|
||||
_translate(
|
||||
'failed', _translate(
|
||||
"MainWindow", "The connection to namecoin failed.")
|
||||
)
|
||||
|
||||
|
@ -245,26 +236,24 @@ class namecoinConnection(object):
|
|||
"Authorization", "Basic %s" % base64.b64encode(authstr))
|
||||
self.con.endheaders()
|
||||
self.con.send(data)
|
||||
except: # noqa:E722
|
||||
logger.info("HTTP connection error")
|
||||
return None
|
||||
|
||||
try:
|
||||
resp = self.con.getresponse()
|
||||
result = resp.read()
|
||||
if resp.status != 200:
|
||||
raise Exception(
|
||||
"Namecoin returned status"
|
||||
" %i: %s" % (resp.status, resp.reason))
|
||||
"Namecoin returned status %i: %s" %
|
||||
(resp.status, resp.reason))
|
||||
except: # noqa:E722
|
||||
logger.info("HTTP receive error")
|
||||
return None
|
||||
except: # noqa:E722
|
||||
logger.info("HTTP connection error")
|
||||
|
||||
return result
|
||||
|
||||
def queryServer(self, data):
|
||||
"""Helper routine sending data to the RPC "
|
||||
"server and returning the result."""
|
||||
"""
|
||||
Helper routine sending data to the RPC server and returning the result.
|
||||
"""
|
||||
|
||||
try:
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
|
@ -296,23 +285,24 @@ def lookupNamecoinFolder():
|
|||
"""
|
||||
|
||||
app = "namecoin"
|
||||
from os import path, environ
|
||||
|
||||
if sys.platform == "darwin":
|
||||
if "HOME" in environ:
|
||||
dataFolder = path.join(os.environ["HOME"],
|
||||
"Library/Application Support/", app) + "/"
|
||||
else:
|
||||
try:
|
||||
dataFolder = os.path.join(
|
||||
os.getenv("HOME"), "Library/Application Support/", app)
|
||||
except TypeError: # getenv is None
|
||||
sys.exit(
|
||||
"Could not find home folder, please report this message"
|
||||
" and your OS X version to the BitMessage Github."
|
||||
) # TODO: remove exits from utility modules
|
||||
|
||||
dataFolder = (
|
||||
os.path.join(os.getenv("APPDATA"), app)
|
||||
if sys.platform.startswith('win') else
|
||||
os.path.join(os.getenv("HOME"), ".%s" % app)
|
||||
)
|
||||
|
||||
elif "win32" in sys.platform or "win64" in sys.platform:
|
||||
dataFolder = path.join(environ["APPDATA"], app) + "\\"
|
||||
else:
|
||||
dataFolder = path.join(environ["HOME"], ".%s" % app) + "/"
|
||||
|
||||
return dataFolder
|
||||
return dataFolder + os.path.sep
|
||||
|
||||
|
||||
def ensureNamecoinOptions():
|
||||
|
@ -357,8 +347,8 @@ def ensureNamecoinOptions():
|
|||
nmc.close()
|
||||
except IOError:
|
||||
logger.warning(
|
||||
"%s unreadable or missing, Namecoin support deactivated",
|
||||
nmcConfig)
|
||||
"%s unreadable or missing, Namecoin support deactivated", nmcConfig
|
||||
)
|
||||
except Exception:
|
||||
logger.warning("Error processing namecoin.conf", exc_info=True)
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@ __all__ = ["StoppableThread"]
|
|||
def start(config, state):
|
||||
"""Start network threads"""
|
||||
from .announcethread import AnnounceThread
|
||||
import connectionpool # pylint: disable=relative-import
|
||||
from network import connectionpool
|
||||
from .addrthread import AddrThread
|
||||
from .downloadthread import DownloadThread
|
||||
from .invthread import InvThread
|
||||
|
|
|
@ -5,11 +5,11 @@ import random
|
|||
from six.moves import queue
|
||||
|
||||
# magic imports!
|
||||
import connectionpool
|
||||
from network import connectionpool
|
||||
from protocol import assembleAddrMessage
|
||||
from network import addrQueue # FIXME: init with queue
|
||||
|
||||
from threads import StoppableThread
|
||||
from .threads import StoppableThread
|
||||
|
||||
|
||||
class AddrThread(StoppableThread):
|
||||
|
|
|
@ -7,7 +7,7 @@ import time
|
|||
|
||||
import network.asyncore_pollchoose as asyncore
|
||||
import state
|
||||
from threads import BusyError, nonBlocking
|
||||
from .threads import BusyError, nonBlocking
|
||||
|
||||
|
||||
class ProcessingError(Exception):
|
||||
|
|
|
@ -4,12 +4,12 @@ Announce myself (node address)
|
|||
import time
|
||||
|
||||
# magic imports!
|
||||
import connectionpool
|
||||
from network import connectionpool
|
||||
from bmconfigparser import config
|
||||
from protocol import assembleAddrMessage
|
||||
|
||||
from node import Peer
|
||||
from threads import StoppableThread
|
||||
from .node import Peer
|
||||
from .threads import StoppableThread
|
||||
|
||||
|
||||
class AnnounceThread(StoppableThread):
|
||||
|
|
|
@ -19,6 +19,7 @@ from errno import (
|
|||
ENOTCONN, ENOTSOCK, EPIPE, ESHUTDOWN, ETIMEDOUT, EWOULDBLOCK, errorcode
|
||||
)
|
||||
from threading import current_thread
|
||||
from six.moves.reprlib import repr
|
||||
|
||||
|
||||
try:
|
||||
|
@ -723,21 +724,6 @@ class dispatcher(object):
|
|||
if why.args[0] not in (ENOTCONN, EBADF):
|
||||
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
|
||||
# logging and warning methods. In general, log is for 'hit' logging
|
||||
# and 'log_info' is for informational, warning and error logging.
|
||||
|
|
|
@ -6,7 +6,7 @@ import time
|
|||
|
||||
import protocol
|
||||
import state
|
||||
import connectionpool
|
||||
import network.connectionpool # use long name to address recursive import
|
||||
from network import dandelion_ins
|
||||
from highlevelcrypto import calculateInventoryHash
|
||||
|
||||
|
@ -100,7 +100,7 @@ class BMObject(object): # pylint: disable=too-many-instance-attributes
|
|||
logger.warning(
|
||||
'The object has invalid stream: %s', self.streamNumber)
|
||||
raise BMObjectInvalidError()
|
||||
if self.streamNumber not in connectionpool.pool.streams:
|
||||
if self.streamNumber not in network.connectionpool.pool.streams:
|
||||
logger.debug(
|
||||
'The streamNumber %i isn\'t one we are interested in.',
|
||||
self.streamNumber)
|
||||
|
|
|
@ -9,13 +9,14 @@ import re
|
|||
import socket
|
||||
import struct
|
||||
import time
|
||||
import six
|
||||
|
||||
# magic imports!
|
||||
import addresses
|
||||
import knownnodes
|
||||
from network import knownnodes
|
||||
import protocol
|
||||
import state
|
||||
import connectionpool
|
||||
import network.connectionpool # use long name to address recursive import
|
||||
from bmconfigparser import config
|
||||
from queues import objectProcessorQueue
|
||||
from randomtrackingdict import RandomTrackingDict
|
||||
|
@ -26,14 +27,27 @@ from network.bmobject import (
|
|||
BMObjectUnwantedStreamError
|
||||
)
|
||||
from network.proxy import ProxyError
|
||||
|
||||
from network import dandelion_ins, invQueue, portCheckerQueue
|
||||
from node import Node, Peer
|
||||
from objectracker import ObjectTracker, missingObjects
|
||||
from .node import Node, Peer
|
||||
from .objectracker import ObjectTracker, missingObjects
|
||||
|
||||
|
||||
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):
|
||||
"""A Bitmessage Protocol Base Error"""
|
||||
errorCodes = ("Protocol error")
|
||||
|
@ -82,7 +96,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker):
|
|||
"""Process incoming header"""
|
||||
self.magic, self.command, self.payloadLength, self.checksum = \
|
||||
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:
|
||||
# skip 1 byte in order to sync
|
||||
self.set_state("bm_header", length=1)
|
||||
|
@ -107,7 +121,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker):
|
|||
self.invalid = True
|
||||
retval = True
|
||||
if not self.fullyEstablished and self.command not in (
|
||||
"error", "version", "verack"):
|
||||
b"error", b"version", b"verack"):
|
||||
logger.error(
|
||||
'Received command %s before connection was fully'
|
||||
' established, ignoring', self.command)
|
||||
|
@ -115,7 +129,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker):
|
|||
if not self.invalid:
|
||||
try:
|
||||
retval = getattr(
|
||||
self, "bm_command_" + str(self.command).lower())()
|
||||
self, "bm_command_" + self.command.decode("utf-8", "replace").lower())()
|
||||
except AttributeError:
|
||||
# unimplemented command
|
||||
logger.debug('unimplemented command %s', self.command)
|
||||
|
@ -168,17 +182,17 @@ class BMProto(AdvancedDispatcher, ObjectTracker):
|
|||
"""Decode node details from the payload"""
|
||||
# protocol.checkIPAddress()
|
||||
services, host, port = self.decode_payload_content("Q16sH")
|
||||
if host[0:12] == '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF':
|
||||
host = socket.inet_ntop(socket.AF_INET, str(host[12:16]))
|
||||
elif host[0:6] == '\xfd\x87\xd8\x7e\xeb\x43':
|
||||
if host[0:12] == b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF':
|
||||
host = socket.inet_ntop(socket.AF_INET, _hoststr(host[12:16]))
|
||||
elif host[0:6] == b'\xfd\x87\xd8\x7e\xeb\x43':
|
||||
# Onion, based on BMD/bitcoind
|
||||
host = base64.b32encode(host[6:]).lower() + ".onion"
|
||||
host = base64.b32encode(host[6:]).lower() + b".onion"
|
||||
else:
|
||||
host = socket.inet_ntop(socket.AF_INET6, str(host))
|
||||
if host == "":
|
||||
host = socket.inet_ntop(socket.AF_INET6, _hoststr(host))
|
||||
if host == b"":
|
||||
# This can happen on Windows systems which are not 64-bit
|
||||
# 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)
|
||||
|
||||
|
@ -334,7 +348,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker):
|
|||
if now < self.skipUntil:
|
||||
return True
|
||||
for i in items:
|
||||
self.pendingUpload[str(i)] = now
|
||||
self.pendingUpload[i] = now
|
||||
return True
|
||||
|
||||
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:
|
||||
return True
|
||||
|
||||
for i in map(str, items):
|
||||
for i in items:
|
||||
if i in state.Inventory and not dandelion_ins.hasHash(i):
|
||||
continue
|
||||
if extend_dandelion_stem and not dandelion_ins.hasHash(i):
|
||||
|
@ -409,13 +423,17 @@ class BMProto(AdvancedDispatcher, ObjectTracker):
|
|||
|
||||
try:
|
||||
self.object.checkObjectByType()
|
||||
if six.PY2:
|
||||
data_buffer = buffer(self.object.data)
|
||||
else: # assume six.PY3
|
||||
data_buffer = memoryview(self.object.data)
|
||||
objectProcessorQueue.put((
|
||||
self.object.objectType, buffer(self.object.data))) # noqa: F821
|
||||
self.object.objectType, data_buffer)) # noqa: F821
|
||||
except BMObjectInvalidError:
|
||||
BMProto.stopDownloadingObject(self.object.inventoryHash, True)
|
||||
else:
|
||||
try:
|
||||
del missingObjects[self.object.inventoryHash]
|
||||
del missingObjects[bytes(self.object.inventoryHash)]
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
|
@ -424,10 +442,16 @@ class BMProto(AdvancedDispatcher, ObjectTracker):
|
|||
dandelion_ins.removeHash(
|
||||
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] = (
|
||||
self.object.objectType, self.object.streamNumber,
|
||||
buffer(self.payload[objectOffset:]), self.object.expiresTime, # noqa: F821
|
||||
buffer(self.object.tag) # noqa: F821
|
||||
object_buffer, self.object.expiresTime, # noqa: F821
|
||||
tag_buffer # noqa: F821
|
||||
)
|
||||
self.handleReceivedObject(
|
||||
self.object.streamNumber, self.object.inventoryHash)
|
||||
|
@ -443,11 +467,10 @@ class BMProto(AdvancedDispatcher, ObjectTracker):
|
|||
"""Incoming addresses, process them"""
|
||||
# not using services
|
||||
for seenTime, stream, _, ip, port in self._decode_addr():
|
||||
ip = str(ip)
|
||||
if (
|
||||
stream not in connectionpool.pool.streams
|
||||
stream not in network.connectionpool.pool.streams
|
||||
# FIXME: should check against complete list
|
||||
or ip.startswith('bootstrap')
|
||||
or ip.decode("utf-8", "replace").startswith('bootstrap')
|
||||
):
|
||||
continue
|
||||
decodedIP = protocol.checkIPAddress(ip)
|
||||
|
@ -477,7 +500,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker):
|
|||
|
||||
def bm_command_ping(self):
|
||||
"""Incoming ping, respond to it."""
|
||||
self.append_write_buf(protocol.CreatePacket('pong'))
|
||||
self.append_write_buf(protocol.CreatePacket(b'pong'))
|
||||
return True
|
||||
|
||||
@staticmethod
|
||||
|
@ -526,21 +549,21 @@ class BMProto(AdvancedDispatcher, ObjectTracker):
|
|||
logger.debug(
|
||||
'remote node incoming address: %s:%i',
|
||||
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)))
|
||||
if not self.peerValidityChecks():
|
||||
# ABORT afterwards
|
||||
return True
|
||||
self.append_write_buf(protocol.CreatePacket('verack'))
|
||||
self.append_write_buf(protocol.CreatePacket(b'verack'))
|
||||
self.verackSent = True
|
||||
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:
|
||||
self.userAgent = '/INVALID:0/'
|
||||
self.userAgent = b'/INVALID:0/'
|
||||
if not self.isOutbound:
|
||||
self.append_write_buf(protocol.assembleVersionMessage(
|
||||
self.destination.host, self.destination.port,
|
||||
connectionpool.pool.streams, dandelion_ins.enabled, True,
|
||||
network.connectionpool.pool.streams, dandelion_ins.enabled, True,
|
||||
nodeid=self.nodeid))
|
||||
logger.debug(
|
||||
'%(host)s:%(port)i sending version',
|
||||
|
@ -596,7 +619,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker):
|
|||
'Closed connection to %s because there is no overlapping'
|
||||
' interest in streams.', self.destination)
|
||||
return False
|
||||
if connectionpool.pool.inboundConnections.get(
|
||||
if network.connectionpool.pool.inboundConnections.get(
|
||||
self.destination):
|
||||
try:
|
||||
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
|
||||
if (
|
||||
Peer(self.destination.host, self.peerNode.port)
|
||||
in connectionpool.pool.inboundConnections
|
||||
or len(connectionpool.pool)
|
||||
in network.connectionpool.pool.inboundConnections
|
||||
or len(network.connectionpool.pool)
|
||||
> config.safeGetInt(
|
||||
'bitmessagesettings', 'maxtotalconnections')
|
||||
+ config.safeGetInt(
|
||||
|
@ -627,7 +650,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker):
|
|||
'Closed connection to %s due to server full'
|
||||
' or duplicate inbound/outbound.', self.destination)
|
||||
return False
|
||||
if connectionpool.pool.isAlreadyConnected(self.nonce):
|
||||
if network.connectionpool.pool.isAlreadyConnected(self.nonce):
|
||||
self.append_write_buf(protocol.assembleErrorMessage(
|
||||
errorText="I'm connected to myself. Closing connection.",
|
||||
fatal=2))
|
||||
|
@ -641,7 +664,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker):
|
|||
@staticmethod
|
||||
def stopDownloadingObject(hashId, forwardAnyway=False):
|
||||
"""Stop downloading object *hashId*"""
|
||||
for connection in connectionpool.pool.connections():
|
||||
for connection in network.connectionpool.pool.connections():
|
||||
try:
|
||||
del connection.objectsNewToMe[hashId]
|
||||
except KeyError:
|
||||
|
@ -653,7 +676,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker):
|
|||
except KeyError:
|
||||
pass
|
||||
try:
|
||||
del missingObjects[hashId]
|
||||
del missingObjects[bytes(hashId)]
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ import random
|
|||
|
||||
from six.moves import queue
|
||||
|
||||
import knownnodes
|
||||
from network import knownnodes
|
||||
import protocol
|
||||
import state
|
||||
|
||||
|
@ -17,10 +17,16 @@ from network import portCheckerQueue
|
|||
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():
|
||||
"""Get a peer from the local peer discovery list"""
|
||||
try:
|
||||
peer = random.choice(state.discoveredPeers.keys()) # nosec B311
|
||||
peer = random.choice(list(state.discoveredPeers.keys())) # nosec B311
|
||||
except (IndexError, KeyError):
|
||||
raise ValueError
|
||||
try:
|
||||
|
@ -48,7 +54,7 @@ def chooseConnection(stream):
|
|||
return getDiscoveredPeer()
|
||||
for _ in range(50):
|
||||
peer = random.choice( # nosec B311
|
||||
knownnodes.knownNodes[stream].keys())
|
||||
list(knownnodes.knownNodes[stream].keys()))
|
||||
try:
|
||||
peer_info = knownnodes.knownNodes[stream][peer]
|
||||
if peer_info.get('self'):
|
||||
|
@ -60,10 +66,10 @@ def chooseConnection(stream):
|
|||
if haveOnion:
|
||||
# do not connect to raw IP addresses
|
||||
# --keep all traffic within Tor overlay
|
||||
if onionOnly and not peer.host.endswith('.onion'):
|
||||
if onionOnly and not _ends_with(peer.host, '.onion'):
|
||||
continue
|
||||
# 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
|
||||
# TODO: need better check
|
||||
elif not peer.host.startswith('bootstrap'):
|
||||
|
|
|
@ -9,22 +9,28 @@ import sys
|
|||
import time
|
||||
import random
|
||||
|
||||
import asyncore_pollchoose as asyncore
|
||||
import knownnodes
|
||||
from network import asyncore_pollchoose as asyncore
|
||||
from network import knownnodes
|
||||
import protocol
|
||||
import state
|
||||
from bmconfigparser import config
|
||||
from connectionchooser import chooseConnection
|
||||
from node import Peer
|
||||
from proxy import Proxy
|
||||
from tcp import (
|
||||
from .connectionchooser import chooseConnection
|
||||
from .node import Peer
|
||||
from .proxy import Proxy
|
||||
from .tcp import (
|
||||
bootstrap, Socks4aBMConnection, Socks5BMConnection,
|
||||
TCPConnection, TCPServer)
|
||||
from udp import UDPSocket
|
||||
from .udp import UDPSocket
|
||||
|
||||
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):
|
||||
"""Pool of all existing connections"""
|
||||
# pylint: disable=too-many-instance-attributes
|
||||
|
@ -78,7 +84,7 @@ class BMConnectionPool(object):
|
|||
Shortcut for combined list of connections from
|
||||
`inboundConnections` and `outboundConnections` dicts
|
||||
"""
|
||||
return self.inboundConnections.values() + self.outboundConnections.values()
|
||||
return list(self.inboundConnections.values()) + list(self.outboundConnections.values())
|
||||
|
||||
def establishedConnections(self):
|
||||
"""Shortcut for list of connections having fullyEstablished == True"""
|
||||
|
@ -160,8 +166,8 @@ class BMConnectionPool(object):
|
|||
@staticmethod
|
||||
def getListeningIP():
|
||||
"""What IP are we supposed to be listening on?"""
|
||||
if config.safeGet(
|
||||
"bitmessagesettings", "onionhostname", "").endswith(".onion"):
|
||||
if _ends_with(config.safeGet(
|
||||
"bitmessagesettings", "onionhostname", ""), ".onion"):
|
||||
host = config.safeGet(
|
||||
"bitmessagesettings", "onionbindip")
|
||||
else:
|
||||
|
@ -314,7 +320,7 @@ class BMConnectionPool(object):
|
|||
continue
|
||||
|
||||
try:
|
||||
if chosen.host.endswith(".onion") and Proxy.onion_proxy:
|
||||
if _ends_with(chosen.host, ".onion") and Proxy.onion_proxy:
|
||||
if onionsocksproxytype == "SOCKS5":
|
||||
self.addConnection(Socks5BMConnection(chosen))
|
||||
elif onionsocksproxytype == "SOCKS4a":
|
||||
|
@ -381,14 +387,14 @@ class BMConnectionPool(object):
|
|||
minTx -= 300 - 20
|
||||
if i.lastTx < minTx:
|
||||
if i.fullyEstablished:
|
||||
i.append_write_buf(protocol.CreatePacket('ping'))
|
||||
i.append_write_buf(protocol.CreatePacket(b'ping'))
|
||||
else:
|
||||
i.close_reason = "Timeout (%is)" % (
|
||||
time.time() - i.lastTx)
|
||||
i.set_state("close")
|
||||
for i in (
|
||||
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):
|
||||
reaper.append(i)
|
||||
|
|
|
@ -6,6 +6,8 @@ from collections import namedtuple
|
|||
from random import choice, expovariate, sample
|
||||
from threading import RLock
|
||||
from time import time
|
||||
import six
|
||||
from binascii import hexlify
|
||||
|
||||
|
||||
# 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"""
|
||||
assert self.enabled is not None
|
||||
with self.lock:
|
||||
self.hashMap[hashId] = Stem(
|
||||
self.hashMap[bytes(hashId)] = Stem(
|
||||
self.getNodeStem(source),
|
||||
stream,
|
||||
self.poissonTimeout())
|
||||
|
@ -75,9 +77,10 @@ class Dandelion: # pylint: disable=old-style-class
|
|||
include streams, we only learn this after receiving the object)
|
||||
"""
|
||||
with self.lock:
|
||||
if hashId in self.hashMap:
|
||||
self.hashMap[hashId] = Stem(
|
||||
self.hashMap[hashId].child,
|
||||
hashId_bytes = bytes(hashId)
|
||||
if hashId_bytes in self.hashMap:
|
||||
self.hashMap[hashId_bytes] = Stem(
|
||||
self.hashMap[hashId_bytes].child,
|
||||
stream,
|
||||
self.poissonTimeout())
|
||||
|
||||
|
@ -86,20 +89,20 @@ class Dandelion: # pylint: disable=old-style-class
|
|||
if logger.isEnabledFor(logging.DEBUG):
|
||||
logger.debug(
|
||||
'%s entering fluff mode due to %s.',
|
||||
''.join('%02x' % ord(i) for i in hashId), reason)
|
||||
hexlify(hashId), reason)
|
||||
with self.lock:
|
||||
try:
|
||||
del self.hashMap[hashId]
|
||||
del self.hashMap[bytes(hashId)]
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
def hasHash(self, hashId):
|
||||
"""Is inventory vector in stem mode?"""
|
||||
return hashId in self.hashMap
|
||||
return bytes(hashId) in self.hashMap
|
||||
|
||||
def objectChildStem(self, hashId):
|
||||
"""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):
|
||||
"""
|
||||
|
@ -111,12 +114,12 @@ class Dandelion: # pylint: disable=old-style-class
|
|||
with self.lock:
|
||||
if len(self.stem) < MAX_STEMS:
|
||||
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
|
||||
for k, v in {
|
||||
k: v for k, v in self.hashMap.iteritems()
|
||||
for k, v in six.iteritems({
|
||||
k: v for k, v in six.iteritems(self.hashMap)
|
||||
if v.child is None
|
||||
}.iteritems():
|
||||
}):
|
||||
self.hashMap[k] = Stem(
|
||||
connection, v.stream, self.poissonTimeout())
|
||||
invQueue.put((v.stream, k, v.child))
|
||||
|
@ -132,14 +135,14 @@ class Dandelion: # pylint: disable=old-style-class
|
|||
self.stem.remove(connection)
|
||||
# active mappings to pointing to the removed node
|
||||
for k in (
|
||||
k for k, v in self.nodeMap.iteritems()
|
||||
k for k, v in six.iteritems(self.nodeMap)
|
||||
if v == connection
|
||||
):
|
||||
self.nodeMap[k] = None
|
||||
for k, v in {
|
||||
k: v for k, v in self.hashMap.iteritems()
|
||||
for k, v in six.iteritems({
|
||||
k: v for k, v in six.iteritems(self.hashMap)
|
||||
if v.child == connection
|
||||
}.iteritems():
|
||||
}):
|
||||
self.hashMap[k] = Stem(
|
||||
None, v.stream, self.poissonTimeout())
|
||||
|
||||
|
@ -180,7 +183,7 @@ class Dandelion: # pylint: disable=old-style-class
|
|||
with self.lock:
|
||||
deadline = time()
|
||||
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
|
||||
]
|
||||
|
||||
|
@ -199,10 +202,10 @@ class Dandelion: # pylint: disable=old-style-class
|
|||
try:
|
||||
# random two connections
|
||||
self.stem = sample(
|
||||
self.pool.outboundConnections.values(), MAX_STEMS)
|
||||
sorted(self.pool.outboundConnections.values()), MAX_STEMS)
|
||||
# not enough stems available
|
||||
except ValueError:
|
||||
self.stem = self.pool.outboundConnections.values()
|
||||
self.stem = list(self.pool.outboundConnections.values())
|
||||
self.nodeMap = {}
|
||||
# hashMap stays to cater for pending stems
|
||||
self.refresh = time() + REASSIGN_INTERVAL
|
||||
|
|
|
@ -4,12 +4,13 @@
|
|||
import time
|
||||
import random
|
||||
import state
|
||||
import six
|
||||
import addresses
|
||||
import protocol
|
||||
import connectionpool
|
||||
from network import connectionpool
|
||||
from network import dandelion_ins
|
||||
from objectracker import missingObjects
|
||||
from threads import StoppableThread
|
||||
from .objectracker import missingObjects
|
||||
from .threads import StoppableThread
|
||||
|
||||
|
||||
class DownloadThread(StoppableThread):
|
||||
|
@ -29,7 +30,7 @@ class DownloadThread(StoppableThread):
|
|||
deadline = time.time() - self.requestExpires
|
||||
try:
|
||||
toDelete = [
|
||||
k for k, v in missingObjects.iteritems()
|
||||
k for k, v in six.iteritems(missingObjects)
|
||||
if v < deadline]
|
||||
except RuntimeError:
|
||||
pass
|
||||
|
@ -68,11 +69,11 @@ class DownloadThread(StoppableThread):
|
|||
continue
|
||||
payload.extend(chunk)
|
||||
chunkCount += 1
|
||||
missingObjects[chunk] = now
|
||||
missingObjects[bytes(chunk)] = now
|
||||
if not chunkCount:
|
||||
continue
|
||||
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(
|
||||
'%s:%i Requesting %i objects',
|
||||
i.destination.host, i.destination.port, chunkCount)
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import socket
|
||||
|
||||
from advanceddispatcher import AdvancedDispatcher
|
||||
import asyncore_pollchoose as asyncore
|
||||
from proxy import ProxyError
|
||||
from socks5 import Socks5Connection, Socks5Resolver
|
||||
from socks4a import Socks4aConnection, Socks4aResolver
|
||||
from .advanceddispatcher import AdvancedDispatcher
|
||||
from network import asyncore_pollchoose as asyncore
|
||||
from .proxy import ProxyError
|
||||
from .socks5 import Socks5Connection, Socks5Resolver
|
||||
from .socks4a import Socks4aConnection, Socks4aResolver
|
||||
|
||||
|
||||
class HttpError(ProxyError):
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
"""
|
||||
Thread to send inv annoucements
|
||||
"""
|
||||
import Queue
|
||||
from six.moves import queue as Queue
|
||||
import random
|
||||
from time import time
|
||||
|
||||
import addresses
|
||||
import protocol
|
||||
import state
|
||||
import connectionpool
|
||||
from network import connectionpool
|
||||
from network import dandelion_ins, invQueue
|
||||
from threads import StoppableThread
|
||||
from .threads import StoppableThread
|
||||
|
||||
|
||||
def handleExpiredDandelion(expired):
|
||||
|
@ -90,15 +90,15 @@ class InvThread(StoppableThread):
|
|||
if fluffs:
|
||||
random.shuffle(fluffs)
|
||||
connection.append_write_buf(protocol.CreatePacket(
|
||||
'inv',
|
||||
b'inv',
|
||||
addresses.encodeVarint(
|
||||
len(fluffs)) + ''.join(fluffs)))
|
||||
len(fluffs)) + b''.join(fluffs)))
|
||||
if stems:
|
||||
random.shuffle(stems)
|
||||
connection.append_write_buf(protocol.CreatePacket(
|
||||
'dinv',
|
||||
b'dinv',
|
||||
addresses.encodeVarint(
|
||||
len(stems)) + ''.join(stems)))
|
||||
len(stems)) + b''.join(stems)))
|
||||
|
||||
invQueue.iterate()
|
||||
for _ in range(len(chunk)):
|
||||
|
|
|
@ -10,10 +10,8 @@ import os
|
|||
import pickle # nosec B403
|
||||
import threading
|
||||
import time
|
||||
try:
|
||||
from collections.abc import Iterable
|
||||
except ImportError:
|
||||
from collections import Iterable
|
||||
from six.moves.collections_abc import Iterable
|
||||
import six
|
||||
|
||||
import state
|
||||
from bmconfigparser import config
|
||||
|
@ -54,8 +52,8 @@ def json_serialize_knownnodes(output):
|
|||
Reorganize knownnodes dict and write it as JSON to output
|
||||
"""
|
||||
_serialized = []
|
||||
for stream, peers in knownNodes.iteritems():
|
||||
for peer, info in peers.iteritems():
|
||||
for stream, peers in six.iteritems(knownNodes):
|
||||
for peer, info in six.iteritems(peers):
|
||||
info.update(rating=round(info.get('rating', 0), 2))
|
||||
_serialized.append({
|
||||
'stream': stream, 'peer': peer._asdict(), 'info': info
|
||||
|
@ -87,7 +85,7 @@ def pickle_deserialize_old_knownnodes(source):
|
|||
global knownNodes
|
||||
knownNodes = pickle.load(source) # nosec B301
|
||||
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)):
|
||||
addKnownNode(stream, node, params)
|
||||
|
||||
|
@ -97,7 +95,7 @@ def saveKnownNodes(dirName=None):
|
|||
if dirName is None:
|
||||
dirName = state.appdata
|
||||
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)
|
||||
|
||||
|
||||
|
@ -108,6 +106,12 @@ def addKnownNode(stream, peer, lastseen=None, is_self=False):
|
|||
Returns True if added a new node.
|
||||
"""
|
||||
# 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):
|
||||
with knownNodesLock:
|
||||
for s in stream:
|
||||
|
@ -153,7 +157,7 @@ def createDefaultKnownNodes():
|
|||
def readKnownNodes():
|
||||
"""Load knownnodes from filesystem"""
|
||||
try:
|
||||
with open(state.appdata + 'knownnodes.dat', 'rb') as source:
|
||||
with open(state.appdata + 'knownnodes.dat', 'r') as source:
|
||||
with knownNodesLock:
|
||||
try:
|
||||
json_deserialize_knownnodes(source)
|
||||
|
|
|
@ -2,9 +2,9 @@
|
|||
A thread to handle network concerns
|
||||
"""
|
||||
import network.asyncore_pollchoose as asyncore
|
||||
import connectionpool
|
||||
from network import connectionpool
|
||||
from queues import excQueue
|
||||
from threads import StoppableThread
|
||||
from .threads import StoppableThread
|
||||
|
||||
|
||||
class BMNetworkThread(StoppableThread):
|
||||
|
|
|
@ -3,8 +3,9 @@ Module for tracking objects
|
|||
"""
|
||||
import time
|
||||
from threading import RLock
|
||||
import six
|
||||
|
||||
import connectionpool
|
||||
import network.connectionpool # use long name to address recursive import
|
||||
from network import dandelion_ins
|
||||
from randomtrackingdict import RandomTrackingDict
|
||||
|
||||
|
@ -75,32 +76,35 @@ class ObjectTracker(object):
|
|||
with self.objectsNewToThemLock:
|
||||
self.objectsNewToThem = {
|
||||
k: v
|
||||
for k, v in self.objectsNewToThem.iteritems()
|
||||
for k, v in six.iteritems(self.objectsNewToThem)
|
||||
if v >= deadline}
|
||||
self.lastCleaned = time.time()
|
||||
|
||||
def hasObj(self, hashid):
|
||||
"""Do we already have object?"""
|
||||
hashid_bytes = bytes(hashid)
|
||||
if haveBloom:
|
||||
return hashid in self.invBloom
|
||||
return hashid in self.objectsNewToMe
|
||||
return hashid_bytes in self.invBloom
|
||||
return hashid_bytes in self.objectsNewToMe
|
||||
|
||||
def handleReceivedInventory(self, hashId):
|
||||
"""Handling received inventory"""
|
||||
hashId_bytes = bytes(hashId)
|
||||
if haveBloom:
|
||||
self.invBloom.add(hashId)
|
||||
self.invBloom.add(hashId_bytes)
|
||||
try:
|
||||
with self.objectsNewToThemLock:
|
||||
del self.objectsNewToThem[hashId]
|
||||
del self.objectsNewToThem[hashId_bytes]
|
||||
except KeyError:
|
||||
pass
|
||||
if hashId not in missingObjects:
|
||||
missingObjects[hashId] = time.time()
|
||||
if hashId_bytes not in missingObjects:
|
||||
missingObjects[hashId_bytes] = time.time()
|
||||
self.objectsNewToMe[hashId] = True
|
||||
|
||||
def handleReceivedObject(self, streamNumber, hashid):
|
||||
"""Handling received object"""
|
||||
for i in connectionpool.pool.connections():
|
||||
hashid_bytes = bytes(hashid)
|
||||
for i in network.connectionpool.pool.connections():
|
||||
if not i.fullyEstablished:
|
||||
continue
|
||||
try:
|
||||
|
@ -110,7 +114,7 @@ class ObjectTracker(object):
|
|||
not dandelion_ins.hasHash(hashid)
|
||||
or dandelion_ins.objectChildStem(hashid) == i):
|
||||
with i.objectsNewToThemLock:
|
||||
i.objectsNewToThem[hashid] = time.time()
|
||||
i.objectsNewToThem[hashid_bytes] = time.time()
|
||||
# update stream number,
|
||||
# which we didn't have when we just received the dinv
|
||||
# also resets expiration of the stem mode
|
||||
|
@ -119,7 +123,7 @@ class ObjectTracker(object):
|
|||
if i == self:
|
||||
try:
|
||||
with i.objectsNewToThemLock:
|
||||
del i.objectsNewToThem[hashid]
|
||||
del i.objectsNewToThem[hashid_bytes]
|
||||
except KeyError:
|
||||
pass
|
||||
self.objectsNewToMe.setLastObject()
|
||||
|
@ -133,4 +137,4 @@ class ObjectTracker(object):
|
|||
def addAddr(self, hashid):
|
||||
"""WIP, should be moved to addrthread.py or removed"""
|
||||
if haveBloom:
|
||||
self.addrBloom.add(hashid)
|
||||
self.addrBloom.add(bytes(hashid))
|
||||
|
|
|
@ -6,14 +6,20 @@ import logging
|
|||
import socket
|
||||
import time
|
||||
|
||||
import asyncore_pollchoose as asyncore
|
||||
from advanceddispatcher import AdvancedDispatcher
|
||||
from network import asyncore_pollchoose as asyncore
|
||||
from .advanceddispatcher import AdvancedDispatcher
|
||||
from bmconfigparser import config
|
||||
from node import Peer
|
||||
from .node import Peer
|
||||
|
||||
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):
|
||||
"""Base proxy exception class"""
|
||||
errorCodes = ("Unknown error",)
|
||||
|
@ -125,7 +131,7 @@ class Proxy(AdvancedDispatcher):
|
|||
self.auth = None
|
||||
self.connect(
|
||||
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
|
||||
)
|
||||
|
||||
|
|
|
@ -2,13 +2,13 @@
|
|||
Process data incoming from network
|
||||
"""
|
||||
import errno
|
||||
import Queue
|
||||
from six.moves import queue as Queue
|
||||
import socket
|
||||
|
||||
import connectionpool
|
||||
from network import connectionpool
|
||||
from network.advanceddispatcher import UnknownStateError
|
||||
from network import receiveDataQueue
|
||||
from threads import StoppableThread
|
||||
from .threads import StoppableThread
|
||||
|
||||
|
||||
class ReceiveQueueThread(StoppableThread):
|
||||
|
|
|
@ -5,8 +5,9 @@ SOCKS4a proxy module
|
|||
import logging
|
||||
import socket
|
||||
import struct
|
||||
import six
|
||||
|
||||
from proxy import GeneralProxyError, Proxy, ProxyError
|
||||
from .proxy import GeneralProxyError, Proxy, ProxyError
|
||||
|
||||
logger = logging.getLogger('default')
|
||||
|
||||
|
@ -39,16 +40,16 @@ class Socks4a(Proxy):
|
|||
def state_pre_connect(self):
|
||||
"""Handle feedback from SOCKS4a while it is connecting on our behalf"""
|
||||
# Get the response
|
||||
if self.read_buf[0:1] != chr(0x00).encode():
|
||||
if self.read_buf[0:1] != six.int2byte(0x00):
|
||||
# bad data
|
||||
self.close()
|
||||
raise GeneralProxyError(1)
|
||||
elif self.read_buf[1:2] != chr(0x5A).encode():
|
||||
elif self.read_buf[1:2] != six.int2byte(0x5A):
|
||||
# Connection failed
|
||||
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
|
||||
raise Socks4aError(ord(self.read_buf[1:2]) - 90)
|
||||
raise Socks4aError(six.byte2int(self.read_buf[1:2]) - 90)
|
||||
else:
|
||||
raise Socks4aError(4)
|
||||
# Get the bound address/port
|
||||
|
@ -102,9 +103,9 @@ class Socks4aConnection(Socks4a):
|
|||
self.append_write_buf(self.ipaddr)
|
||||
if self._auth:
|
||||
self.append_write_buf(self._auth[0])
|
||||
self.append_write_buf(chr(0x00).encode())
|
||||
self.append_write_buf(six.int2byte(0x00))
|
||||
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)
|
||||
return True
|
||||
|
||||
|
@ -132,8 +133,8 @@ class Socks4aResolver(Socks4a):
|
|||
self.append_write_buf(struct.pack("BBBB", 0x00, 0x00, 0x00, 0x01))
|
||||
if self._auth:
|
||||
self.append_write_buf(self._auth[0])
|
||||
self.append_write_buf(chr(0x00).encode())
|
||||
self.append_write_buf(self.host + chr(0x00).encode())
|
||||
self.append_write_buf(six.int2byte(0x00))
|
||||
self.append_write_buf(self.host + six.int2byte(0x00))
|
||||
self.set_state("pre_connect", length=0, expectBytes=8)
|
||||
return True
|
||||
|
||||
|
|
|
@ -6,9 +6,10 @@ SOCKS5 proxy module
|
|||
import logging
|
||||
import socket
|
||||
import struct
|
||||
import six
|
||||
|
||||
from node import Peer
|
||||
from proxy import GeneralProxyError, Proxy, ProxyError
|
||||
from .node import Peer
|
||||
from .proxy import GeneralProxyError, Proxy, ProxyError
|
||||
|
||||
logger = logging.getLogger('default')
|
||||
|
||||
|
@ -97,20 +98,20 @@ class Socks5(Proxy):
|
|||
def state_pre_connect(self):
|
||||
"""Handle feedback from socks5 while it is connecting on our behalf."""
|
||||
# Get the response
|
||||
if self.read_buf[0:1] != chr(0x05).encode():
|
||||
if self.read_buf[0:1] != six.int2byte(0x05):
|
||||
self.close()
|
||||
raise GeneralProxyError(1)
|
||||
elif self.read_buf[1:2] != chr(0x00).encode():
|
||||
elif self.read_buf[1:2] != six.int2byte(0x00):
|
||||
# Connection failed
|
||||
self.close()
|
||||
if ord(self.read_buf[1:2]) <= 8:
|
||||
raise Socks5Error(ord(self.read_buf[1:2]))
|
||||
if six.byte2int(self.read_buf[1:2]) <= 8:
|
||||
raise Socks5Error(six.byte2int(self.read_buf[1:2]))
|
||||
else:
|
||||
raise Socks5Error(9)
|
||||
# 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)
|
||||
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)
|
||||
else:
|
||||
self.close()
|
||||
|
@ -129,7 +130,7 @@ class Socks5(Proxy):
|
|||
(e.g. IPv6, onion, ...). This is part 1 which retrieves the
|
||||
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(
|
||||
"proxy_addr_2_2", length=1, expectBytes=self.address_length)
|
||||
return True
|
||||
|
@ -171,19 +172,19 @@ class Socks5Connection(Socks5):
|
|||
# use the IPv4 address request even if remote resolving was specified.
|
||||
try:
|
||||
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!
|
||||
# Well it's not an IP number, so it's probably a DNS name.
|
||||
if self._remote_dns:
|
||||
# Resolve remotely
|
||||
self.ipaddr = None
|
||||
self.append_write_buf(chr(0x03).encode() + chr(
|
||||
len(self.destination[0])).encode() + self.destination[0])
|
||||
self.append_write_buf(six.int2byte(0x03) + six.int2byte(
|
||||
len(self.destination[0])) + self.destination[0].encode("utf-8", "replace"))
|
||||
else:
|
||||
# Resolve locally
|
||||
self.ipaddr = socket.inet_aton(
|
||||
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.set_state("pre_connect", length=0, expectBytes=4)
|
||||
return True
|
||||
|
@ -208,8 +209,8 @@ class Socks5Resolver(Socks5):
|
|||
"""Perform resolving"""
|
||||
# Now we can request the actual connection
|
||||
self.append_write_buf(struct.pack('BBB', 0x05, 0xF0, 0x00))
|
||||
self.append_write_buf(chr(0x03).encode() + chr(
|
||||
len(self.host)).encode() + str(self.host))
|
||||
self.append_write_buf(six.int2byte(0x03) + six.int2byte(
|
||||
len(self.host)) + bytes(self.host))
|
||||
self.append_write_buf(struct.pack(">H", self.port))
|
||||
self.set_state("pre_connect", length=0, expectBytes=4)
|
||||
return True
|
||||
|
|
|
@ -3,9 +3,9 @@ Network statistics
|
|||
"""
|
||||
import time
|
||||
|
||||
import asyncore_pollchoose as asyncore
|
||||
import connectionpool
|
||||
from objectracker import missingObjects
|
||||
from network import asyncore_pollchoose as asyncore
|
||||
from network import connectionpool
|
||||
from .objectracker import missingObjects
|
||||
|
||||
|
||||
lastReceivedTimestamp = time.time()
|
||||
|
|
|
@ -8,28 +8,29 @@ import math
|
|||
import random
|
||||
import socket
|
||||
import time
|
||||
import six
|
||||
|
||||
# magic imports!
|
||||
import addresses
|
||||
import l10n
|
||||
import protocol
|
||||
import state
|
||||
import connectionpool
|
||||
import network.connectionpool # use long name to address recursive import
|
||||
from bmconfigparser import config
|
||||
from highlevelcrypto import randomBytes
|
||||
from network import dandelion_ins, invQueue, receiveDataQueue
|
||||
from queues import UISignalQueue
|
||||
from tr import _translate
|
||||
|
||||
import asyncore_pollchoose as asyncore
|
||||
import knownnodes
|
||||
from network import asyncore_pollchoose as asyncore
|
||||
from network import knownnodes
|
||||
from network.advanceddispatcher import AdvancedDispatcher
|
||||
from network.bmproto import BMProto
|
||||
from network.objectracker import ObjectTracker
|
||||
from network.socks4a import Socks4aConnection
|
||||
from network.socks5 import Socks5Connection
|
||||
from network.tls import TLSDispatcher
|
||||
from node import Peer
|
||||
from .node import Peer
|
||||
|
||||
|
||||
logger = logging.getLogger('default')
|
||||
|
@ -39,6 +40,12 @@ maximumAgeOfNodesThatIAdvertiseToOthers = 10800 #: Equals three hours
|
|||
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):
|
||||
# pylint: disable=too-many-instance-attributes
|
||||
"""
|
||||
|
@ -138,9 +145,9 @@ class TCPConnection(BMProto, TLSDispatcher):
|
|||
'updateStatusBar',
|
||||
_translate(
|
||||
"MainWindow",
|
||||
"The time on your computer, %1, may be wrong. "
|
||||
"The time on your computer, {0}, may be wrong. "
|
||||
"Please verify your settings."
|
||||
).arg(l10n.formatTimestamp())))
|
||||
).format(l10n.formatTimestamp())))
|
||||
|
||||
def state_connection_fully_established(self):
|
||||
"""
|
||||
|
@ -191,10 +198,10 @@ class TCPConnection(BMProto, TLSDispatcher):
|
|||
# only if more recent than 3 hours
|
||||
# and having positive or neutral rating
|
||||
filtered = [
|
||||
(k, v) for k, v in nodes.iteritems()
|
||||
(k, v) for k, v in six.iteritems(nodes)
|
||||
if v["lastseen"] > int(time.time())
|
||||
- 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
|
||||
elemCount = min(
|
||||
|
@ -220,7 +227,7 @@ class TCPConnection(BMProto, TLSDispatcher):
|
|||
'Sending huge inv message with %i objects to just this'
|
||||
' one peer', objectCount)
|
||||
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.
|
||||
bigInvList = {}
|
||||
|
@ -267,7 +274,7 @@ class TCPConnection(BMProto, TLSDispatcher):
|
|||
self.append_write_buf(
|
||||
protocol.assembleVersionMessage(
|
||||
self.destination.host, self.destination.port,
|
||||
connectionpool.pool.streams, dandelion_ins.enabled,
|
||||
network.connectionpool.pool.streams, dandelion_ins.enabled,
|
||||
False, nodeid=self.nodeid))
|
||||
self.connectedAt = time.time()
|
||||
receiveDataQueue.put(self.destination)
|
||||
|
@ -318,7 +325,7 @@ class Socks5BMConnection(Socks5Connection, TCPConnection):
|
|||
self.append_write_buf(
|
||||
protocol.assembleVersionMessage(
|
||||
self.destination.host, self.destination.port,
|
||||
connectionpool.pool.streams, dandelion_ins.enabled,
|
||||
network.connectionpool.pool.streams, dandelion_ins.enabled,
|
||||
False, nodeid=self.nodeid))
|
||||
self.set_state("bm_header", expectBytes=protocol.Header.size)
|
||||
return True
|
||||
|
@ -342,7 +349,7 @@ class Socks4aBMConnection(Socks4aConnection, TCPConnection):
|
|||
self.append_write_buf(
|
||||
protocol.assembleVersionMessage(
|
||||
self.destination.host, self.destination.port,
|
||||
connectionpool.pool.streams, dandelion_ins.enabled,
|
||||
network.connectionpool.pool.streams, dandelion_ins.enabled,
|
||||
False, nodeid=self.nodeid))
|
||||
self.set_state("bm_header", expectBytes=protocol.Header.size)
|
||||
return True
|
||||
|
@ -430,7 +437,7 @@ class TCPServer(AdvancedDispatcher):
|
|||
|
||||
state.ownAddresses[Peer(*sock.getsockname())] = True
|
||||
if (
|
||||
len(connectionpool.pool)
|
||||
len(network.connectionpool.pool)
|
||||
> config.safeGetInt(
|
||||
'bitmessagesettings', 'maxtotalconnections')
|
||||
+ config.safeGetInt(
|
||||
|
@ -442,7 +449,7 @@ class TCPServer(AdvancedDispatcher):
|
|||
sock.close()
|
||||
return
|
||||
try:
|
||||
connectionpool.pool.addConnection(
|
||||
network.connectionpool.pool.addConnection(
|
||||
TCPConnection(sock=sock))
|
||||
except socket.error:
|
||||
pass
|
||||
|
|
|
@ -6,6 +6,7 @@ import os
|
|||
import socket
|
||||
import ssl
|
||||
import sys
|
||||
import six
|
||||
|
||||
import network.asyncore_pollchoose as asyncore
|
||||
import paths
|
||||
|
@ -34,7 +35,7 @@ else:
|
|||
# ciphers
|
||||
if (
|
||||
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"
|
||||
else:
|
||||
|
@ -58,14 +59,29 @@ class TLSDispatcher(AdvancedDispatcher):
|
|||
self.tlsDone = False
|
||||
self.tlsVersion = "N/A"
|
||||
self.isSSL = False
|
||||
if six.PY3 or ssl.OPENSSL_VERSION_NUMBER >= 0x30000000:
|
||||
self.tlsPrepared = False
|
||||
|
||||
def state_tls_init(self):
|
||||
"""Prepare sockets for TLS handshake"""
|
||||
self.isSSL = 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,
|
||||
# it's safe to wrap the socket.
|
||||
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(
|
||||
purpose=ssl.Purpose.SERVER_AUTH
|
||||
if self.server_side else ssl.Purpose.CLIENT_AUTH)
|
||||
|
@ -74,6 +90,11 @@ class TLSDispatcher(AdvancedDispatcher):
|
|||
context.check_hostname = False
|
||||
context.verify_mode = ssl.CERT_NONE
|
||||
# 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 |\
|
||||
ssl.OP_NO_SSLv3 | ssl.OP_SINGLE_ECDH_USE |\
|
||||
ssl.OP_CIPHER_SERVER_PREFERENCE
|
||||
|
@ -88,6 +109,9 @@ class TLSDispatcher(AdvancedDispatcher):
|
|||
ciphers=self.ciphers, do_handshake_on_connect=False)
|
||||
self.sslSocket.setblocking(0)
|
||||
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")
|
||||
return False
|
||||
|
||||
|
@ -114,6 +138,8 @@ class TLSDispatcher(AdvancedDispatcher):
|
|||
# during TLS handshake, and after flushing write buffer,
|
||||
# return status of last handshake attempt
|
||||
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)
|
||||
return self.want_read
|
||||
# prior to TLS handshake,
|
||||
|
@ -134,6 +160,10 @@ class TLSDispatcher(AdvancedDispatcher):
|
|||
try:
|
||||
# wait for write buffer flush
|
||||
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()
|
||||
else:
|
||||
AdvancedDispatcher.handle_read(self)
|
||||
|
@ -156,6 +186,10 @@ class TLSDispatcher(AdvancedDispatcher):
|
|||
try:
|
||||
# wait for write buffer flush
|
||||
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()
|
||||
else:
|
||||
AdvancedDispatcher.handle_write(self)
|
||||
|
|
|
@ -8,12 +8,12 @@ import time
|
|||
# magic imports!
|
||||
import protocol
|
||||
import state
|
||||
import connectionpool
|
||||
import network.connectionpool # use long name to address recursive import
|
||||
|
||||
from network import receiveDataQueue
|
||||
from bmproto import BMProto
|
||||
from node import Peer
|
||||
from objectracker import ObjectTracker
|
||||
from .bmproto import BMProto
|
||||
from .node import Peer
|
||||
from .objectracker import ObjectTracker
|
||||
|
||||
|
||||
logger = logging.getLogger('default')
|
||||
|
@ -81,8 +81,8 @@ class UDPSocket(BMProto): # pylint: disable=too-many-instance-attributes
|
|||
return True
|
||||
remoteport = False
|
||||
for seenTime, stream, _, ip, port in addresses:
|
||||
decodedIP = protocol.checkIPAddress(str(ip))
|
||||
if stream not in connectionpool.pool.streams:
|
||||
decodedIP = protocol.checkIPAddress(ip)
|
||||
if stream not in network.connectionpool.pool.streams:
|
||||
continue
|
||||
if (seenTime < time.time() - protocol.MAX_TIME_OFFSET
|
||||
or seenTime > time.time() + protocol.MAX_TIME_OFFSET):
|
||||
|
|
|
@ -6,10 +6,10 @@ import time
|
|||
import random
|
||||
import protocol
|
||||
import state
|
||||
import connectionpool
|
||||
from network import connectionpool
|
||||
from randomtrackingdict import RandomTrackingDict
|
||||
from network import dandelion_ins
|
||||
from threads import StoppableThread
|
||||
from .threads import StoppableThread
|
||||
|
||||
|
||||
class UploadThread(StoppableThread):
|
||||
|
@ -50,7 +50,7 @@ class UploadThread(StoppableThread):
|
|||
break
|
||||
try:
|
||||
payload.extend(protocol.CreatePacket(
|
||||
'object', state.Inventory[chunk].payload))
|
||||
b'object', state.Inventory[chunk].payload))
|
||||
chunk_count += 1
|
||||
except KeyError:
|
||||
i.antiIntersectionDelay()
|
||||
|
|
|
@ -23,9 +23,9 @@ class IndicatorLibmessaging(object):
|
|||
return
|
||||
|
||||
self._menu = {
|
||||
'send': unicode(_translate('MainWindow', 'Send')),
|
||||
'messages': unicode(_translate('MainWindow', 'Messages')),
|
||||
'subscriptions': unicode(_translate('MainWindow', 'Subscriptions'))
|
||||
'send': _translate('MainWindow', 'Send'),
|
||||
'messages': _translate('MainWindow', 'Messages'),
|
||||
'subscriptions': _translate('MainWindow', 'Subscriptions')
|
||||
}
|
||||
|
||||
self.new_message_item = self.new_broadcast_item = None
|
||||
|
@ -45,12 +45,11 @@ class IndicatorLibmessaging(object):
|
|||
|
||||
def show_unread(self, draw_attention=False):
|
||||
"""
|
||||
show the number of unread messages and subscriptions
|
||||
Show the number of unread messages and subscriptions
|
||||
on the messaging menu
|
||||
"""
|
||||
for source, count in zip(
|
||||
('messages', 'subscriptions'),
|
||||
self.form.getUnread()
|
||||
('messages', 'subscriptions'), self.form.getUnread()
|
||||
):
|
||||
if count > 0:
|
||||
if self.app.has_source(source):
|
||||
|
|
|
@ -3,10 +3,10 @@
|
|||
A menu plugin showing QR-Code for bitmessage address in modal dialog.
|
||||
"""
|
||||
|
||||
import urllib
|
||||
from six.moves.urllib.parse import urlencode
|
||||
|
||||
import qrcode
|
||||
from PyQt4 import QtCore, QtGui
|
||||
from qtpy import QtGui, QtCore, QtWidgets
|
||||
|
||||
from pybitmessage.tr import _translate
|
||||
|
||||
|
@ -39,23 +39,23 @@ class Image(qrcode.image.base.BaseImage): # pylint: disable=abstract-method
|
|||
QtCore.Qt.black)
|
||||
|
||||
|
||||
class QRCodeDialog(QtGui.QDialog):
|
||||
class QRCodeDialog(QtWidgets.QDialog):
|
||||
"""The dialog"""
|
||||
def __init__(self, parent):
|
||||
super(QRCodeDialog, self).__init__(parent)
|
||||
self.image = QtGui.QLabel(self)
|
||||
self.label = QtGui.QLabel(self)
|
||||
self.image = QtWidgets.QLabel(self)
|
||||
self.label = QtWidgets.QLabel(self)
|
||||
font = QtGui.QFont()
|
||||
font.setBold(True)
|
||||
font.setWeight(75)
|
||||
self.label.setFont(font)
|
||||
self.label.setAlignment(
|
||||
QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter)
|
||||
buttonBox = QtGui.QDialogButtonBox(self)
|
||||
buttonBox = QtWidgets.QDialogButtonBox(self)
|
||||
buttonBox.setOrientation(QtCore.Qt.Horizontal)
|
||||
buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Ok)
|
||||
buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Ok)
|
||||
buttonBox.accepted.connect(self.accept)
|
||||
layout = QtGui.QVBoxLayout(self)
|
||||
layout = QtWidgets.QVBoxLayout(self)
|
||||
layout.addWidget(self.image)
|
||||
layout.addWidget(self.label)
|
||||
layout.addWidget(buttonBox)
|
||||
|
@ -72,7 +72,7 @@ class QRCodeDialog(QtGui.QDialog):
|
|||
self.label.setText(text)
|
||||
self.label.setToolTip(text)
|
||||
self.label.setFixedWidth(pixmap.width())
|
||||
self.setFixedSize(QtGui.QWidget.sizeHint(self))
|
||||
self.setFixedSize(QtWidgets.QWidget.sizeHint(self))
|
||||
|
||||
|
||||
def connect_plugin(form):
|
||||
|
@ -93,7 +93,7 @@ def connect_plugin(form):
|
|||
return
|
||||
dialog.render(
|
||||
'bitmessage:%s' % account.address + (
|
||||
'?' + urllib.urlencode({'label': label.encode('utf-8')})
|
||||
'?' + urlencode({'label': label.encode('utf-8')})
|
||||
if label != account.address else '')
|
||||
)
|
||||
dialog.exec_()
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user