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
|
wine python -m pip install pytools==2020.2
|
||||||
echo "Upgrading pip"
|
echo "Upgrading pip"
|
||||||
wine python -m pip install --upgrade pip
|
wine python -m pip install --upgrade pip
|
||||||
|
# install pypiwin32 for win32com
|
||||||
|
wine python -m pip install pypiwin32
|
||||||
}
|
}
|
||||||
|
|
||||||
function install_pyqt(){
|
function install_pyqt(){
|
||||||
|
@ -82,6 +84,8 @@ function install_pyqt(){
|
||||||
echo "Installing PyQt-${PYQT_VERSION} 32b"
|
echo "Installing PyQt-${PYQT_VERSION} 32b"
|
||||||
wine PyQt${PYQT_VERSION}-x32.exe /S /WX
|
wine PyQt${PYQT_VERSION}-x32.exe /S /WX
|
||||||
fi
|
fi
|
||||||
|
# and qtpy
|
||||||
|
wine python -m pip install qtpy
|
||||||
}
|
}
|
||||||
|
|
||||||
function install_openssl(){
|
function install_openssl(){
|
||||||
|
|
|
@ -216,8 +216,7 @@ autodoc_mock_imports = [
|
||||||
'pkg_resources',
|
'pkg_resources',
|
||||||
'pycanberra',
|
'pycanberra',
|
||||||
'pyopencl',
|
'pyopencl',
|
||||||
'PyQt4',
|
'qtpy',
|
||||||
'PyQt5',
|
|
||||||
'qrcode',
|
'qrcode',
|
||||||
'stem',
|
'stem',
|
||||||
'xdg',
|
'xdg',
|
||||||
|
|
|
@ -11,11 +11,13 @@ ingredients:
|
||||||
- python-msgpack
|
- python-msgpack
|
||||||
- python-qrcode
|
- python-qrcode
|
||||||
- python-qt4
|
- python-qt4
|
||||||
|
- python-qtpy
|
||||||
- python-setuptools
|
- python-setuptools
|
||||||
- python-sip
|
- python-sip
|
||||||
- python-six
|
- python-six
|
||||||
- python-xdg
|
- python-xdg
|
||||||
- sni-qt
|
- sni-qt
|
||||||
|
- xkb-data
|
||||||
exclude:
|
exclude:
|
||||||
- libdb5.3
|
- libdb5.3
|
||||||
- libglib2.0-0
|
- libglib2.0-0
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
import collectd
|
import collectd
|
||||||
import json
|
import json
|
||||||
import xmlrpclib
|
from six.moves import xmlrpc_client as xmlrpclib
|
||||||
|
|
||||||
pybmurl = ""
|
pybmurl = ""
|
||||||
api = ""
|
api = ""
|
||||||
|
|
|
@ -43,8 +43,16 @@ a = Analysis(
|
||||||
'setuptools.msvc', '_cffi_backend',
|
'setuptools.msvc', '_cffi_backend',
|
||||||
'plugins.menu_qrcode', 'plugins.proxyconfig_stem'
|
'plugins.menu_qrcode', 'plugins.proxyconfig_stem'
|
||||||
],
|
],
|
||||||
runtime_hooks=[os.path.join(hookspath, 'pyinstaller_rthook_plugins.py')],
|
# https://github.com/pyinstaller/pyinstaller/wiki/Recipe-PyQt4-API-Version
|
||||||
excludes=excludes
|
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')]
|
a.datas += [('default.ini', os.path.join(srcPath, 'default.ini'), 'DATA')]
|
||||||
|
|
||||||
excluded_binaries = [
|
excluded_binaries = [
|
||||||
'QtOpenGL4.dll',
|
'QtOpenGL4.dll', 'QtSql4.dll', 'QtSvg4.dll', 'QtTest4.dll',
|
||||||
'QtSvg4.dll',
|
'QtWebKit4.dll', 'QtXml4.dll'
|
||||||
'QtXml4.dll',
|
|
||||||
]
|
]
|
||||||
a.binaries = TOC([x for x in a.binaries if x[0] not in excluded_binaries])
|
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 platform
|
||||||
import shutil
|
import shutil
|
||||||
import sys
|
import sys
|
||||||
|
import six
|
||||||
|
|
||||||
from importlib import import_module
|
from importlib import import_module
|
||||||
from setuptools import setup, Extension
|
from setuptools import setup, Extension
|
||||||
|
@ -83,7 +84,7 @@ if __name__ == "__main__":
|
||||||
'images/kivy/text_images*.png'
|
'images/kivy/text_images*.png'
|
||||||
]}
|
]}
|
||||||
|
|
||||||
if sys.version_info[0] == 3:
|
if six.PY3:
|
||||||
packages.extend(
|
packages.extend(
|
||||||
[
|
[
|
||||||
'pybitmessage.bitmessagekivy',
|
'pybitmessage.bitmessagekivy',
|
||||||
|
|
|
@ -187,7 +187,7 @@ def decodeAddress(address):
|
||||||
integer = decodeBase58(address)
|
integer = decodeBase58(address)
|
||||||
if integer == 0:
|
if integer == 0:
|
||||||
status = 'invalidcharacters'
|
status = 'invalidcharacters'
|
||||||
return status, 0, 0, ''
|
return status, 0, 0, b''
|
||||||
# after converting to hex, the string will be prepended
|
# after converting to hex, the string will be prepended
|
||||||
# with a 0x and appended with a L in python2
|
# with a 0x and appended with a L in python2
|
||||||
hexdata = hex(integer)[2:].rstrip('L')
|
hexdata = hex(integer)[2:].rstrip('L')
|
||||||
|
@ -200,23 +200,23 @@ def decodeAddress(address):
|
||||||
|
|
||||||
if checksum != double_sha512(data[:-4])[0:4]:
|
if checksum != double_sha512(data[:-4])[0:4]:
|
||||||
status = 'checksumfailed'
|
status = 'checksumfailed'
|
||||||
return status, 0, 0, ''
|
return status, 0, 0, b''
|
||||||
|
|
||||||
try:
|
try:
|
||||||
addressVersionNumber, bytesUsedByVersionNumber = decodeVarint(data[:9])
|
addressVersionNumber, bytesUsedByVersionNumber = decodeVarint(data[:9])
|
||||||
except varintDecodeError as e:
|
except varintDecodeError as e:
|
||||||
logger.error(str(e))
|
logger.error(str(e))
|
||||||
status = 'varintmalformed'
|
status = 'varintmalformed'
|
||||||
return status, 0, 0, ''
|
return status, 0, 0, b''
|
||||||
|
|
||||||
if addressVersionNumber > 4:
|
if addressVersionNumber > 4:
|
||||||
logger.error('cannot decode address version numbers this high')
|
logger.error('cannot decode address version numbers this high')
|
||||||
status = 'versiontoohigh'
|
status = 'versiontoohigh'
|
||||||
return status, 0, 0, ''
|
return status, 0, 0, b''
|
||||||
elif addressVersionNumber == 0:
|
elif addressVersionNumber == 0:
|
||||||
logger.error('cannot decode address version numbers of zero.')
|
logger.error('cannot decode address version numbers of zero.')
|
||||||
status = 'versiontoohigh'
|
status = 'versiontoohigh'
|
||||||
return status, 0, 0, ''
|
return status, 0, 0, b''
|
||||||
|
|
||||||
try:
|
try:
|
||||||
streamNumber, bytesUsedByStreamNumber = \
|
streamNumber, bytesUsedByStreamNumber = \
|
||||||
|
@ -224,7 +224,7 @@ def decodeAddress(address):
|
||||||
except varintDecodeError as e:
|
except varintDecodeError as e:
|
||||||
logger.error(str(e))
|
logger.error(str(e))
|
||||||
status = 'varintmalformed'
|
status = 'varintmalformed'
|
||||||
return status, 0, 0, ''
|
return status, 0, 0, b''
|
||||||
|
|
||||||
status = 'success'
|
status = 'success'
|
||||||
if addressVersionNumber == 1:
|
if addressVersionNumber == 1:
|
||||||
|
@ -242,21 +242,21 @@ def decodeAddress(address):
|
||||||
return status, addressVersionNumber, streamNumber, \
|
return status, addressVersionNumber, streamNumber, \
|
||||||
b'\x00\x00' + embeddedRipeData
|
b'\x00\x00' + embeddedRipeData
|
||||||
elif len(embeddedRipeData) < 18:
|
elif len(embeddedRipeData) < 18:
|
||||||
return 'ripetooshort', 0, 0, ''
|
return 'ripetooshort', 0, 0, b''
|
||||||
elif len(embeddedRipeData) > 20:
|
elif len(embeddedRipeData) > 20:
|
||||||
return 'ripetoolong', 0, 0, ''
|
return 'ripetoolong', 0, 0, b''
|
||||||
return 'otherproblem', 0, 0, ''
|
return 'otherproblem', 0, 0, b''
|
||||||
elif addressVersionNumber == 4:
|
elif addressVersionNumber == 4:
|
||||||
embeddedRipeData = \
|
embeddedRipeData = \
|
||||||
data[bytesUsedByVersionNumber + bytesUsedByStreamNumber:-4]
|
data[bytesUsedByVersionNumber + bytesUsedByStreamNumber:-4]
|
||||||
if embeddedRipeData[0:1] == b'\x00':
|
if embeddedRipeData[0:1] == b'\x00':
|
||||||
# In order to enforce address non-malleability, encoded
|
# In order to enforce address non-malleability, encoded
|
||||||
# RIPE data must have NULL bytes removed from the front
|
# RIPE data must have NULL bytes removed from the front
|
||||||
return 'encodingproblem', 0, 0, ''
|
return 'encodingproblem', 0, 0, b''
|
||||||
elif len(embeddedRipeData) > 20:
|
elif len(embeddedRipeData) > 20:
|
||||||
return 'ripetoolong', 0, 0, ''
|
return 'ripetoolong', 0, 0, b''
|
||||||
elif len(embeddedRipeData) < 4:
|
elif len(embeddedRipeData) < 4:
|
||||||
return 'ripetooshort', 0, 0, ''
|
return 'ripetooshort', 0, 0, b''
|
||||||
x00string = b'\x00' * (20 - len(embeddedRipeData))
|
x00string = b'\x00' * (20 - len(embeddedRipeData))
|
||||||
return status, addressVersionNumber, streamNumber, \
|
return status, addressVersionNumber, streamNumber, \
|
||||||
x00string + embeddedRipeData
|
x00string + embeddedRipeData
|
||||||
|
|
109
src/api.py
109
src/api.py
|
@ -67,9 +67,12 @@ import subprocess # nosec B404
|
||||||
import time
|
import time
|
||||||
from binascii import hexlify, unhexlify
|
from binascii import hexlify, unhexlify
|
||||||
from struct import pack, unpack
|
from struct import pack, unpack
|
||||||
|
import sqlite3
|
||||||
|
|
||||||
import six
|
import six
|
||||||
from six.moves import configparser, http_client, xmlrpc_server
|
from six.moves import configparser, http_client, xmlrpc_server
|
||||||
|
from six.moves.reprlib import repr
|
||||||
|
from dbcompat import dbstr
|
||||||
|
|
||||||
import helper_inbox
|
import helper_inbox
|
||||||
import helper_sent
|
import helper_sent
|
||||||
|
@ -531,12 +534,12 @@ class BMRPCDispatcher(object):
|
||||||
message = shared.fixPotentiallyInvalidUTF8Data(message)
|
message = shared.fixPotentiallyInvalidUTF8Data(message)
|
||||||
return {
|
return {
|
||||||
'msgid': hexlify(msgid),
|
'msgid': hexlify(msgid),
|
||||||
'toAddress': toAddress,
|
'toAddress': toAddress.decode("utf-8", "replace"),
|
||||||
'fromAddress': fromAddress,
|
'fromAddress': fromAddress.decode("utf-8", "replace"),
|
||||||
'subject': base64.b64encode(subject),
|
'subject': base64.b64encode(subject),
|
||||||
'message': base64.b64encode(message),
|
'message': base64.b64encode(message),
|
||||||
'encodingType': encodingtype,
|
'encodingType': encodingtype,
|
||||||
'receivedTime': received,
|
'receivedTime': received.decode("utf-8", "replace"),
|
||||||
'read': read
|
'read': read
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -598,11 +601,12 @@ class BMRPCDispatcher(object):
|
||||||
"""
|
"""
|
||||||
queryreturn = sqlQuery(
|
queryreturn = sqlQuery(
|
||||||
"SELECT label, address from addressbook WHERE label = ?",
|
"SELECT label, address from addressbook WHERE label = ?",
|
||||||
label
|
dbstr(label)
|
||||||
) if label else sqlQuery("SELECT label, address from addressbook")
|
) if label else sqlQuery("SELECT label, address from addressbook")
|
||||||
data = []
|
data = []
|
||||||
for label, address in queryreturn:
|
for label, address in queryreturn:
|
||||||
label = shared.fixPotentiallyInvalidUTF8Data(label)
|
label = shared.fixPotentiallyInvalidUTF8Data(label)
|
||||||
|
address = address.decode("utf-8", "replace")
|
||||||
data.append({
|
data.append({
|
||||||
'label': base64.b64encode(label),
|
'label': base64.b64encode(label),
|
||||||
'address': address
|
'address': address
|
||||||
|
@ -618,12 +622,12 @@ class BMRPCDispatcher(object):
|
||||||
self._verifyAddress(address)
|
self._verifyAddress(address)
|
||||||
# TODO: add unique together constraint in the table
|
# TODO: add unique together constraint in the table
|
||||||
queryreturn = sqlQuery(
|
queryreturn = sqlQuery(
|
||||||
"SELECT address FROM addressbook WHERE address=?", address)
|
"SELECT address FROM addressbook WHERE address=?", dbstr(address))
|
||||||
if queryreturn != []:
|
if queryreturn != []:
|
||||||
raise APIError(
|
raise APIError(
|
||||||
16, 'You already have this address in your address book.')
|
16, 'You already have this address in your address book.')
|
||||||
|
|
||||||
sqlExecute("INSERT INTO addressbook VALUES(?,?)", label, address)
|
sqlExecute("INSERT INTO addressbook VALUES(?,?)", dbstr(label), dbstr(address))
|
||||||
queues.UISignalQueue.put(('rerenderMessagelistFromLabels', ''))
|
queues.UISignalQueue.put(('rerenderMessagelistFromLabels', ''))
|
||||||
queues.UISignalQueue.put(('rerenderMessagelistToLabels', ''))
|
queues.UISignalQueue.put(('rerenderMessagelistToLabels', ''))
|
||||||
queues.UISignalQueue.put(('rerenderAddressBook', ''))
|
queues.UISignalQueue.put(('rerenderAddressBook', ''))
|
||||||
|
@ -635,7 +639,7 @@ class BMRPCDispatcher(object):
|
||||||
"""Delete an entry from address book."""
|
"""Delete an entry from address book."""
|
||||||
address = addBMIfNotPresent(address)
|
address = addBMIfNotPresent(address)
|
||||||
self._verifyAddress(address)
|
self._verifyAddress(address)
|
||||||
sqlExecute('DELETE FROM addressbook WHERE address=?', address)
|
sqlExecute('DELETE FROM addressbook WHERE address=?', dbstr(address))
|
||||||
queues.UISignalQueue.put(('rerenderMessagelistFromLabels', ''))
|
queues.UISignalQueue.put(('rerenderMessagelistFromLabels', ''))
|
||||||
queues.UISignalQueue.put(('rerenderMessagelistToLabels', ''))
|
queues.UISignalQueue.put(('rerenderMessagelistToLabels', ''))
|
||||||
queues.UISignalQueue.put(('rerenderAddressBook', ''))
|
queues.UISignalQueue.put(('rerenderAddressBook', ''))
|
||||||
|
@ -919,6 +923,7 @@ class BMRPCDispatcher(object):
|
||||||
" ORDER BY received"
|
" ORDER BY received"
|
||||||
)
|
)
|
||||||
return {"inboxMessages": [
|
return {"inboxMessages": [
|
||||||
|
|
||||||
self._dump_inbox_message(*data) for data in queryreturn
|
self._dump_inbox_message(*data) for data in queryreturn
|
||||||
]}
|
]}
|
||||||
|
|
||||||
|
@ -953,20 +958,32 @@ class BMRPCDispatcher(object):
|
||||||
23, 'Bool expected in readStatus, saw %s instead.'
|
23, 'Bool expected in readStatus, saw %s instead.'
|
||||||
% type(readStatus))
|
% type(readStatus))
|
||||||
queryreturn = sqlQuery(
|
queryreturn = sqlQuery(
|
||||||
"SELECT read FROM inbox WHERE msgid=?", msgid)
|
"SELECT read FROM inbox WHERE msgid=?", sqlite3.Binary(msgid))
|
||||||
|
if len(queryreturn) < 1:
|
||||||
|
queryreturn = sqlQuery(
|
||||||
|
"SELECT read FROM inbox WHERE msgid=CAST(? AS TEXT)", msgid)
|
||||||
# UPDATE is slow, only update if status is different
|
# UPDATE is slow, only update if status is different
|
||||||
try:
|
try:
|
||||||
if (queryreturn[0][0] == 1) != readStatus:
|
if (queryreturn[0][0] == 1) != readStatus:
|
||||||
sqlExecute(
|
rowcount = sqlExecute(
|
||||||
"UPDATE inbox set read = ? WHERE msgid=?",
|
"UPDATE inbox set read = ? WHERE msgid=?",
|
||||||
readStatus, 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))
|
queues.UISignalQueue.put(('changedInboxUnread', None))
|
||||||
except IndexError:
|
except IndexError:
|
||||||
pass
|
pass
|
||||||
queryreturn = sqlQuery(
|
queryreturn = sqlQuery(
|
||||||
"SELECT msgid, toaddress, fromaddress, subject, received, message,"
|
"SELECT msgid, toaddress, fromaddress, subject, received, message,"
|
||||||
" encodingtype, read FROM inbox WHERE msgid=?", msgid
|
" encodingtype, read FROM inbox WHERE msgid=?", sqlite3.Binary(msgid)
|
||||||
)
|
)
|
||||||
|
if len(queryreturn) < 1:
|
||||||
|
queryreturn = sqlQuery(
|
||||||
|
"SELECT msgid, toaddress, fromaddress, subject, received, message,"
|
||||||
|
" encodingtype, read FROM inbox WHERE msgid=CAST(? AS TEXT)", msgid
|
||||||
|
)
|
||||||
try:
|
try:
|
||||||
return {"inboxMessage": [
|
return {"inboxMessage": [
|
||||||
self._dump_inbox_message(*queryreturn[0])]}
|
self._dump_inbox_message(*queryreturn[0])]}
|
||||||
|
@ -1018,7 +1035,7 @@ class BMRPCDispatcher(object):
|
||||||
queryreturn = sqlQuery(
|
queryreturn = sqlQuery(
|
||||||
"SELECT msgid, toaddress, fromaddress, subject, received,"
|
"SELECT msgid, toaddress, fromaddress, subject, received,"
|
||||||
" message, encodingtype, read FROM inbox WHERE folder='inbox'"
|
" message, encodingtype, read FROM inbox WHERE folder='inbox'"
|
||||||
" AND toAddress=?", toAddress)
|
" AND toAddress=?", dbstr(toAddress))
|
||||||
return {"inboxMessages": [
|
return {"inboxMessages": [
|
||||||
self._dump_inbox_message(*data) for data in queryreturn
|
self._dump_inbox_message(*data) for data in queryreturn
|
||||||
]}
|
]}
|
||||||
|
@ -1035,8 +1052,14 @@ class BMRPCDispatcher(object):
|
||||||
queryreturn = sqlQuery(
|
queryreturn = sqlQuery(
|
||||||
"SELECT msgid, toaddress, fromaddress, subject, lastactiontime,"
|
"SELECT msgid, toaddress, fromaddress, subject, lastactiontime,"
|
||||||
" message, encodingtype, status, ackdata FROM sent WHERE msgid=?",
|
" message, encodingtype, status, ackdata FROM sent WHERE msgid=?",
|
||||||
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:
|
try:
|
||||||
return {"sentMessage": [
|
return {"sentMessage": [
|
||||||
self._dump_sent_message(*queryreturn[0])
|
self._dump_sent_message(*queryreturn[0])
|
||||||
|
@ -1055,7 +1078,7 @@ class BMRPCDispatcher(object):
|
||||||
"SELECT msgid, toaddress, fromaddress, subject, lastactiontime,"
|
"SELECT msgid, toaddress, fromaddress, subject, lastactiontime,"
|
||||||
" message, encodingtype, status, ackdata FROM sent"
|
" message, encodingtype, status, ackdata FROM sent"
|
||||||
" WHERE folder='sent' AND fromAddress=? ORDER BY lastactiontime",
|
" WHERE folder='sent' AND fromAddress=? ORDER BY lastactiontime",
|
||||||
fromAddress
|
dbstr(fromAddress)
|
||||||
)
|
)
|
||||||
return {"sentMessages": [
|
return {"sentMessages": [
|
||||||
self._dump_sent_message(*data) for data in queryreturn
|
self._dump_sent_message(*data) for data in queryreturn
|
||||||
|
@ -1072,8 +1095,14 @@ class BMRPCDispatcher(object):
|
||||||
queryreturn = sqlQuery(
|
queryreturn = sqlQuery(
|
||||||
"SELECT msgid, toaddress, fromaddress, subject, lastactiontime,"
|
"SELECT msgid, toaddress, fromaddress, subject, lastactiontime,"
|
||||||
" message, encodingtype, status, ackdata FROM sent"
|
" message, encodingtype, status, ackdata FROM sent"
|
||||||
" WHERE ackdata=?", ackData
|
" WHERE ackdata=?", sqlite3.Binary(ackData)
|
||||||
)
|
)
|
||||||
|
if len(queryreturn) < 1:
|
||||||
|
queryreturn = sqlQuery(
|
||||||
|
"SELECT msgid, toaddress, fromaddress, subject, lastactiontime,"
|
||||||
|
" message, encodingtype, status, ackdata FROM sent"
|
||||||
|
" WHERE ackdata=CAST(? AS TEXT)", ackData
|
||||||
|
)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
return {"sentMessage": [
|
return {"sentMessage": [
|
||||||
|
@ -1093,7 +1122,9 @@ class BMRPCDispatcher(object):
|
||||||
# Trash if in inbox table
|
# Trash if in inbox table
|
||||||
helper_inbox.trash(msgid)
|
helper_inbox.trash(msgid)
|
||||||
# Trash if in sent table
|
# Trash if in sent table
|
||||||
sqlExecute("UPDATE sent SET folder='trash' WHERE msgid=?", msgid)
|
rowcount = sqlExecute("UPDATE sent SET folder='trash' WHERE msgid=?", sqlite3.Binary(msgid))
|
||||||
|
if rowcount < 1:
|
||||||
|
sqlExecute("UPDATE sent SET folder='trash' WHERE msgid=CAST(? AS TEXT)", msgid)
|
||||||
return 'Trashed message (assuming message existed).'
|
return 'Trashed message (assuming message existed).'
|
||||||
|
|
||||||
@command('trashInboxMessage')
|
@command('trashInboxMessage')
|
||||||
|
@ -1107,7 +1138,9 @@ class BMRPCDispatcher(object):
|
||||||
def HandleTrashSentMessage(self, msgid):
|
def HandleTrashSentMessage(self, msgid):
|
||||||
"""Trash sent message by msgid (encoded in hex)."""
|
"""Trash sent message by msgid (encoded in hex)."""
|
||||||
msgid = self._decode(msgid, "hex")
|
msgid = self._decode(msgid, "hex")
|
||||||
sqlExecute('''UPDATE sent SET folder='trash' WHERE msgid=?''', msgid)
|
rowcount = sqlExecute('''UPDATE sent SET folder='trash' WHERE msgid=?''', sqlite3.Binary(msgid))
|
||||||
|
if rowcount < 1:
|
||||||
|
sqlExecute('''UPDATE sent SET folder='trash' WHERE msgid=CAST(? AS TEXT)''', msgid)
|
||||||
return 'Trashed sent message (assuming message existed).'
|
return 'Trashed sent message (assuming message existed).'
|
||||||
|
|
||||||
@command('sendMessage')
|
@command('sendMessage')
|
||||||
|
@ -1150,9 +1183,9 @@ class BMRPCDispatcher(object):
|
||||||
|
|
||||||
toLabel = ''
|
toLabel = ''
|
||||||
queryreturn = sqlQuery(
|
queryreturn = sqlQuery(
|
||||||
"SELECT label FROM addressbook WHERE address=?", toAddress)
|
"SELECT label FROM addressbook WHERE address=?", dbstr(toAddress))
|
||||||
try:
|
try:
|
||||||
toLabel = queryreturn[0][0]
|
toLabel = queryreturn[0][0].decode("utf-8", "replace")
|
||||||
except IndexError:
|
except IndexError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -1217,9 +1250,12 @@ class BMRPCDispatcher(object):
|
||||||
raise APIError(15, 'Invalid ackData object size.')
|
raise APIError(15, 'Invalid ackData object size.')
|
||||||
ackdata = self._decode(ackdata, "hex")
|
ackdata = self._decode(ackdata, "hex")
|
||||||
queryreturn = sqlQuery(
|
queryreturn = sqlQuery(
|
||||||
"SELECT status FROM sent where ackdata=?", ackdata)
|
"SELECT status FROM sent where ackdata=?", sqlite3.Binary(ackdata))
|
||||||
|
if len(queryreturn) < 1:
|
||||||
|
queryreturn = sqlQuery(
|
||||||
|
"SELECT status FROM sent where ackdata=CAST(? AS TEXT)", ackdata)
|
||||||
try:
|
try:
|
||||||
return queryreturn[0][0]
|
return queryreturn[0][0].decode("utf-8", "replace")
|
||||||
except IndexError:
|
except IndexError:
|
||||||
return 'notfound'
|
return 'notfound'
|
||||||
|
|
||||||
|
@ -1238,11 +1274,11 @@ class BMRPCDispatcher(object):
|
||||||
# First we must check to see if the address is already in the
|
# First we must check to see if the address is already in the
|
||||||
# subscriptions list.
|
# subscriptions list.
|
||||||
queryreturn = sqlQuery(
|
queryreturn = sqlQuery(
|
||||||
"SELECT * FROM subscriptions WHERE address=?", address)
|
"SELECT * FROM subscriptions WHERE address=?", dbstr(address))
|
||||||
if queryreturn:
|
if queryreturn:
|
||||||
raise APIError(16, 'You are already subscribed to that address.')
|
raise APIError(16, 'You are already subscribed to that address.')
|
||||||
sqlExecute(
|
sqlExecute(
|
||||||
"INSERT INTO subscriptions VALUES (?,?,?)", label, address, True)
|
"INSERT INTO subscriptions VALUES (?,?,?)", dbstr(label), dbstr(address), True)
|
||||||
shared.reloadBroadcastSendersForWhichImWatching()
|
shared.reloadBroadcastSendersForWhichImWatching()
|
||||||
queues.UISignalQueue.put(('rerenderMessagelistFromLabels', ''))
|
queues.UISignalQueue.put(('rerenderMessagelistFromLabels', ''))
|
||||||
queues.UISignalQueue.put(('rerenderSubscriptions', ''))
|
queues.UISignalQueue.put(('rerenderSubscriptions', ''))
|
||||||
|
@ -1256,7 +1292,7 @@ class BMRPCDispatcher(object):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
address = addBMIfNotPresent(address)
|
address = addBMIfNotPresent(address)
|
||||||
sqlExecute("DELETE FROM subscriptions WHERE address=?", address)
|
sqlExecute("DELETE FROM subscriptions WHERE address=?", dbstr(address))
|
||||||
shared.reloadBroadcastSendersForWhichImWatching()
|
shared.reloadBroadcastSendersForWhichImWatching()
|
||||||
queues.UISignalQueue.put(('rerenderMessagelistFromLabels', ''))
|
queues.UISignalQueue.put(('rerenderMessagelistFromLabels', ''))
|
||||||
queues.UISignalQueue.put(('rerenderSubscriptions', ''))
|
queues.UISignalQueue.put(('rerenderSubscriptions', ''))
|
||||||
|
@ -1274,6 +1310,7 @@ class BMRPCDispatcher(object):
|
||||||
data = []
|
data = []
|
||||||
for label, address, enabled in queryreturn:
|
for label, address, enabled in queryreturn:
|
||||||
label = shared.fixPotentiallyInvalidUTF8Data(label)
|
label = shared.fixPotentiallyInvalidUTF8Data(label)
|
||||||
|
address = address.decode("utf-8", "replace")
|
||||||
data.append({
|
data.append({
|
||||||
'label': base64.b64encode(label),
|
'label': base64.b64encode(label),
|
||||||
'address': address,
|
'address': address,
|
||||||
|
@ -1354,7 +1391,9 @@ class BMRPCDispatcher(object):
|
||||||
"""Trash a sent message by ackdata (hex encoded)"""
|
"""Trash a sent message by ackdata (hex encoded)"""
|
||||||
# This API method should only be used when msgid is not available
|
# This API method should only be used when msgid is not available
|
||||||
ackdata = self._decode(ackdata, "hex")
|
ackdata = self._decode(ackdata, "hex")
|
||||||
sqlExecute("UPDATE sent SET folder='trash' WHERE ackdata=?", ackdata)
|
rowcount = sqlExecute("UPDATE sent SET folder='trash' WHERE ackdata=?", sqlite3.Binary(ackdata))
|
||||||
|
if rowcount < 1:
|
||||||
|
sqlExecute("UPDATE sent SET folder='trash' WHERE ackdata=CAST(? AS TEXT)", ackdata)
|
||||||
return 'Trashed sent message (assuming message existed).'
|
return 'Trashed sent message (assuming message existed).'
|
||||||
|
|
||||||
@command('disseminatePubkey')
|
@command('disseminatePubkey')
|
||||||
|
@ -1421,19 +1460,29 @@ class BMRPCDispatcher(object):
|
||||||
# use it we'll need to fill out a field in our inventory database
|
# use it we'll need to fill out a field in our inventory database
|
||||||
# which is blank by default (first20bytesofencryptedmessage).
|
# which is blank by default (first20bytesofencryptedmessage).
|
||||||
queryreturn = sqlQuery(
|
queryreturn = sqlQuery(
|
||||||
"SELECT hash, payload FROM inventory WHERE tag = ''"
|
"SELECT hash, payload FROM inventory WHERE tag = ?"
|
||||||
" and objecttype = 2")
|
" and objecttype = 2", sqlite3.Binary(b""))
|
||||||
|
if len(queryreturn) < 1:
|
||||||
|
queryreturn = sqlQuery(
|
||||||
|
"SELECT hash, payload FROM inventory WHERE tag = CAST(? AS TEXT)"
|
||||||
|
" and objecttype = 2", b"")
|
||||||
with SqlBulkExecute() as sql:
|
with SqlBulkExecute() as sql:
|
||||||
for hash01, payload in queryreturn:
|
for hash01, payload in queryreturn:
|
||||||
readPosition = 16 # Nonce length + time length
|
readPosition = 16 # Nonce length + time length
|
||||||
# Stream Number length
|
# Stream Number length
|
||||||
readPosition += decodeVarint(
|
readPosition += decodeVarint(
|
||||||
payload[readPosition:readPosition + 10])[1]
|
payload[readPosition:readPosition + 10])[1]
|
||||||
t = (payload[readPosition:readPosition + 32], hash01)
|
t = (sqlite3.Binary(payload[readPosition:readPosition + 32]), sqlite3.Binary(hash01))
|
||||||
sql.execute("UPDATE inventory SET tag=? WHERE hash=?", *t)
|
_, rowcount = sql.execute("UPDATE inventory SET tag=? WHERE hash=?", *t)
|
||||||
|
if rowcount < 1:
|
||||||
|
t = (sqlite3.Binary(payload[readPosition:readPosition + 32]), hash01)
|
||||||
|
sql.execute("UPDATE inventory SET tag=? WHERE hash=CAST(? AS TEXT)", *t)
|
||||||
|
|
||||||
queryreturn = sqlQuery(
|
queryreturn = sqlQuery(
|
||||||
"SELECT payload FROM inventory WHERE tag = ?", requestedHash)
|
"SELECT payload FROM inventory WHERE tag = ?", sqlite3.Binary(requestedHash))
|
||||||
|
if len(queryreturn) < 1:
|
||||||
|
queryreturn = sqlQuery(
|
||||||
|
"SELECT payload FROM inventory WHERE tag = CAST(? AS TEXT)", requestedHash)
|
||||||
return {"receivedMessageDatas": [
|
return {"receivedMessageDatas": [
|
||||||
{'data': hexlify(payload)} for payload, in queryreturn
|
{'data': hexlify(payload)} for payload, in queryreturn
|
||||||
]}
|
]}
|
||||||
|
|
|
@ -21,7 +21,8 @@ import os
|
||||||
import socket
|
import socket
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
import xmlrpclib
|
from six.moves import xmlrpc_client as xmlrpclib
|
||||||
|
from six.moves import input as raw_input
|
||||||
|
|
||||||
from bmconfigparser import config
|
from bmconfigparser import config
|
||||||
|
|
||||||
|
|
|
@ -10,13 +10,15 @@ Bitmessage commandline interface
|
||||||
# * python2-pythondialog
|
# * python2-pythondialog
|
||||||
# * dialog
|
# * dialog
|
||||||
|
|
||||||
import ConfigParser
|
from six.moves import configparser
|
||||||
import curses
|
import curses
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
from textwrap import fill
|
from textwrap import fill
|
||||||
from threading import Timer
|
from threading import Timer
|
||||||
|
import six
|
||||||
|
import sqlite3
|
||||||
|
|
||||||
from dialog import Dialog
|
from dialog import Dialog
|
||||||
import helper_sent
|
import helper_sent
|
||||||
|
@ -30,6 +32,7 @@ import state
|
||||||
from addresses import addBMIfNotPresent, decodeAddress
|
from addresses import addBMIfNotPresent, decodeAddress
|
||||||
from bmconfigparser import config
|
from bmconfigparser import config
|
||||||
from helper_sql import sqlExecute, sqlQuery
|
from helper_sql import sqlExecute, sqlQuery
|
||||||
|
from dbcompat import dbstr
|
||||||
|
|
||||||
# pylint: disable=global-statement
|
# pylint: disable=global-statement
|
||||||
|
|
||||||
|
@ -105,7 +108,7 @@ def ascii(s):
|
||||||
"""ASCII values"""
|
"""ASCII values"""
|
||||||
r = ""
|
r = ""
|
||||||
for c in s:
|
for c in s:
|
||||||
if ord(c) in range(128):
|
if six.byte2int(c) in range(128):
|
||||||
r += c
|
r += c
|
||||||
return r
|
return r
|
||||||
|
|
||||||
|
@ -326,13 +329,13 @@ def handlech(c, stdscr):
|
||||||
if c != curses.ERR:
|
if c != curses.ERR:
|
||||||
global inboxcur, addrcur, sentcur, subcur, abookcur, blackcur
|
global inboxcur, addrcur, sentcur, subcur, abookcur, blackcur
|
||||||
if c in range(256):
|
if c in range(256):
|
||||||
if chr(c) in '12345678':
|
if six.int2byte(c) in '12345678':
|
||||||
global menutab
|
global menutab
|
||||||
menutab = int(chr(c))
|
menutab = int(six.int2byte(c))
|
||||||
elif chr(c) == 'q':
|
elif six.int2byte(c) == 'q':
|
||||||
global quit_
|
global quit_
|
||||||
quit_ = True
|
quit_ = True
|
||||||
elif chr(c) == '\n':
|
elif six.int2byte(c) == '\n':
|
||||||
curses.curs_set(1)
|
curses.curs_set(1)
|
||||||
d = Dialog(dialog="dialog")
|
d = Dialog(dialog="dialog")
|
||||||
if menutab == 1:
|
if menutab == 1:
|
||||||
|
@ -358,7 +361,9 @@ def handlech(c, stdscr):
|
||||||
inbox[inboxcur][1] +
|
inbox[inboxcur][1] +
|
||||||
"\"")
|
"\"")
|
||||||
data = "" # pyint: disable=redefined-outer-name
|
data = "" # pyint: disable=redefined-outer-name
|
||||||
ret = sqlQuery("SELECT message FROM inbox WHERE msgid=?", inbox[inboxcur][0])
|
ret = sqlQuery("SELECT message FROM inbox WHERE msgid=?", sqlite3.Binary(inbox[inboxcur][0]))
|
||||||
|
if len(ret) < 1:
|
||||||
|
ret = sqlQuery("SELECT message FROM inbox WHERE msgid=CAST(? AS TEXT)", inbox[inboxcur][0])
|
||||||
if ret != []:
|
if ret != []:
|
||||||
for row in ret:
|
for row in ret:
|
||||||
data, = row
|
data, = row
|
||||||
|
@ -367,12 +372,16 @@ def handlech(c, stdscr):
|
||||||
for i, item in enumerate(data.split("\n")):
|
for i, item in enumerate(data.split("\n")):
|
||||||
msg += fill(item, replace_whitespace=False) + "\n"
|
msg += fill(item, replace_whitespace=False) + "\n"
|
||||||
scrollbox(d, unicode(ascii(msg)), 30, 80)
|
scrollbox(d, unicode(ascii(msg)), 30, 80)
|
||||||
sqlExecute("UPDATE inbox SET read=1 WHERE msgid=?", inbox[inboxcur][0])
|
rowcount = sqlExecute("UPDATE inbox SET read=1 WHERE msgid=?", sqlite3.Binary(inbox[inboxcur][0]))
|
||||||
|
if rowcount < 1:
|
||||||
|
sqlExecute("UPDATE inbox SET read=1 WHERE msgid=CAST(? AS TEXT)", inbox[inboxcur][0])
|
||||||
inbox[inboxcur][7] = 1
|
inbox[inboxcur][7] = 1
|
||||||
else:
|
else:
|
||||||
scrollbox(d, unicode("Could not fetch message."))
|
scrollbox(d, unicode("Could not fetch message."))
|
||||||
elif t == "2": # Mark unread
|
elif t == "2": # Mark unread
|
||||||
sqlExecute("UPDATE inbox SET read=0 WHERE msgid=?", inbox[inboxcur][0])
|
rowcount = sqlExecute("UPDATE inbox SET read=0 WHERE msgid=?", sqlite3.Binary(inbox[inboxcur][0]))
|
||||||
|
if rowcount < 1:
|
||||||
|
sqlExecute("UPDATE inbox SET read=0 WHERE msgid=CAST(? AS TEXT)", inbox[inboxcur][0])
|
||||||
inbox[inboxcur][7] = 0
|
inbox[inboxcur][7] = 0
|
||||||
elif t == "3": # Reply
|
elif t == "3": # Reply
|
||||||
curses.curs_set(1)
|
curses.curs_set(1)
|
||||||
|
@ -396,11 +405,14 @@ def handlech(c, stdscr):
|
||||||
if not m[5][:4] == "Re: ":
|
if not m[5][:4] == "Re: ":
|
||||||
subject = "Re: " + m[5]
|
subject = "Re: " + m[5]
|
||||||
body = ""
|
body = ""
|
||||||
ret = sqlQuery("SELECT message FROM inbox WHERE msgid=?", m[0])
|
ret = sqlQuery("SELECT message FROM inbox WHERE msgid=?", sqlite3.Binary(m[0]))
|
||||||
|
if len(ret) < 1:
|
||||||
|
ret = sqlQuery("SELECT message FROM inbox WHERE msgid=CAST(? AS TEXT)", m[0])
|
||||||
if ret != []:
|
if ret != []:
|
||||||
body = "\n\n------------------------------------------------------\n"
|
body = "\n\n------------------------------------------------------\n"
|
||||||
for row in ret:
|
for row in ret:
|
||||||
body, = row
|
body, = row
|
||||||
|
body = body.decode("utf-8", "replace")
|
||||||
|
|
||||||
sendMessage(fromaddr, toaddr, ischan, subject, body, True)
|
sendMessage(fromaddr, toaddr, ischan, subject, body, True)
|
||||||
dialogreset(stdscr)
|
dialogreset(stdscr)
|
||||||
|
@ -410,7 +422,7 @@ def handlech(c, stdscr):
|
||||||
r, t = d.inputbox("Label for address \"" + addr + "\"")
|
r, t = d.inputbox("Label for address \"" + addr + "\"")
|
||||||
if r == d.DIALOG_OK:
|
if r == d.DIALOG_OK:
|
||||||
label = t
|
label = t
|
||||||
sqlExecute("INSERT INTO addressbook VALUES (?,?)", label, addr)
|
sqlExecute("INSERT INTO addressbook VALUES (?,?)", dbstr(label), dbstr(addr))
|
||||||
# Prepend entry
|
# Prepend entry
|
||||||
addrbook.reverse()
|
addrbook.reverse()
|
||||||
addrbook.append([label, addr])
|
addrbook.append([label, addr])
|
||||||
|
@ -422,17 +434,22 @@ def handlech(c, stdscr):
|
||||||
r, t = d.inputbox("Filename", init=inbox[inboxcur][5] + ".txt")
|
r, t = d.inputbox("Filename", init=inbox[inboxcur][5] + ".txt")
|
||||||
if r == d.DIALOG_OK:
|
if r == d.DIALOG_OK:
|
||||||
msg = ""
|
msg = ""
|
||||||
ret = sqlQuery("SELECT message FROM inbox WHERE msgid=?", inbox[inboxcur][0])
|
ret = sqlQuery("SELECT message FROM inbox WHERE msgid=?", sqlite3.Binary(inbox[inboxcur][0]))
|
||||||
|
if len(ret) < 1:
|
||||||
|
ret = sqlQuery("SELECT message FROM inbox WHERE msgid=CAST(? AS TEXT)", inbox[inboxcur][0])
|
||||||
if ret != []:
|
if ret != []:
|
||||||
for row in ret:
|
for row in ret:
|
||||||
msg, = row
|
msg, = row
|
||||||
|
msg = msg.decode("utf-8", "replace")
|
||||||
fh = open(t, "a") # Open in append mode just in case
|
fh = open(t, "a") # Open in append mode just in case
|
||||||
fh.write(msg)
|
fh.write(msg)
|
||||||
fh.close()
|
fh.close()
|
||||||
else:
|
else:
|
||||||
scrollbox(d, unicode("Could not fetch message."))
|
scrollbox(d, unicode("Could not fetch message."))
|
||||||
elif t == "6": # Move to trash
|
elif t == "6": # Move to trash
|
||||||
sqlExecute("UPDATE inbox SET folder='trash' WHERE msgid=?", inbox[inboxcur][0])
|
rowcount = sqlExecute("UPDATE inbox SET folder='trash' WHERE msgid=?", sqlite3.Binary(inbox[inboxcur][0]))
|
||||||
|
if rowcount < 1:
|
||||||
|
sqlExecute("UPDATE inbox SET folder='trash' WHERE msgid=CAST(? AS TEXT)", inbox[inboxcur][0])
|
||||||
del inbox[inboxcur]
|
del inbox[inboxcur]
|
||||||
scrollbox(d, unicode(
|
scrollbox(d, unicode(
|
||||||
"Message moved to trash. There is no interface to view your trash,"
|
"Message moved to trash. There is no interface to view your trash,"
|
||||||
|
@ -463,8 +480,13 @@ def handlech(c, stdscr):
|
||||||
data = ""
|
data = ""
|
||||||
ret = sqlQuery(
|
ret = sqlQuery(
|
||||||
"SELECT message FROM sent WHERE subject=? AND ackdata=?",
|
"SELECT message FROM sent WHERE subject=? AND ackdata=?",
|
||||||
sentbox[sentcur][4],
|
dbstr(sentbox[sentcur][4]),
|
||||||
sentbox[sentcur][6])
|
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 != []:
|
if ret != []:
|
||||||
for row in ret:
|
for row in ret:
|
||||||
data, = row
|
data, = row
|
||||||
|
@ -476,10 +498,15 @@ def handlech(c, stdscr):
|
||||||
else:
|
else:
|
||||||
scrollbox(d, unicode("Could not fetch message."))
|
scrollbox(d, unicode("Could not fetch message."))
|
||||||
elif t == "2": # Move to trash
|
elif t == "2": # Move to trash
|
||||||
sqlExecute(
|
rowcount = sqlExecute(
|
||||||
"UPDATE sent SET folder='trash' WHERE subject=? AND ackdata=?",
|
"UPDATE sent SET folder='trash' WHERE subject=? AND ackdata=?",
|
||||||
sentbox[sentcur][4],
|
dbstr(sentbox[sentcur][4]),
|
||||||
sentbox[sentcur][6])
|
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]
|
del sentbox[sentcur]
|
||||||
scrollbox(d, unicode(
|
scrollbox(d, unicode(
|
||||||
"Message moved to trash. There is no interface to view your trash"
|
"Message moved to trash. There is no interface to view your trash"
|
||||||
|
@ -672,7 +699,7 @@ def handlech(c, stdscr):
|
||||||
elif t == "2" and m is False:
|
elif t == "2" and m is False:
|
||||||
try:
|
try:
|
||||||
mn = config.get(a, "mailinglistname")
|
mn = config.get(a, "mailinglistname")
|
||||||
except ConfigParser.NoOptionError:
|
except configparser.NoOptionError:
|
||||||
mn = ""
|
mn = ""
|
||||||
r, t = d.inputbox("Mailing list name", init=mn)
|
r, t = d.inputbox("Mailing list name", init=mn)
|
||||||
if r == d.DIALOG_OK:
|
if r == d.DIALOG_OK:
|
||||||
|
@ -711,29 +738,29 @@ def handlech(c, stdscr):
|
||||||
subscriptions.append([label, addr, True])
|
subscriptions.append([label, addr, True])
|
||||||
subscriptions.reverse()
|
subscriptions.reverse()
|
||||||
|
|
||||||
sqlExecute("INSERT INTO subscriptions VALUES (?,?,?)", label, addr, True)
|
sqlExecute("INSERT INTO subscriptions VALUES (?,?,?)", dbstr(label), dbstr(addr), True)
|
||||||
shared.reloadBroadcastSendersForWhichImWatching()
|
shared.reloadBroadcastSendersForWhichImWatching()
|
||||||
elif t == "2":
|
elif t == "2":
|
||||||
r, t = d.inputbox("Type in \"I want to delete this subscription\"")
|
r, t = d.inputbox("Type in \"I want to delete this subscription\"")
|
||||||
if r == d.DIALOG_OK and t == "I want to delete this subscription":
|
if r == d.DIALOG_OK and t == "I want to delete this subscription":
|
||||||
sqlExecute(
|
sqlExecute(
|
||||||
"DELETE FROM subscriptions WHERE label=? AND address=?",
|
"DELETE FROM subscriptions WHERE label=? AND address=?",
|
||||||
subscriptions[subcur][0],
|
dbstr(subscriptions[subcur][0]),
|
||||||
subscriptions[subcur][1])
|
dbstr(subscriptions[subcur][1]))
|
||||||
shared.reloadBroadcastSendersForWhichImWatching()
|
shared.reloadBroadcastSendersForWhichImWatching()
|
||||||
del subscriptions[subcur]
|
del subscriptions[subcur]
|
||||||
elif t == "3":
|
elif t == "3":
|
||||||
sqlExecute(
|
sqlExecute(
|
||||||
"UPDATE subscriptions SET enabled=1 WHERE label=? AND address=?",
|
"UPDATE subscriptions SET enabled=1 WHERE label=? AND address=?",
|
||||||
subscriptions[subcur][0],
|
dbstr(subscriptions[subcur][0]),
|
||||||
subscriptions[subcur][1])
|
dbstr(subscriptions[subcur][1]))
|
||||||
shared.reloadBroadcastSendersForWhichImWatching()
|
shared.reloadBroadcastSendersForWhichImWatching()
|
||||||
subscriptions[subcur][2] = True
|
subscriptions[subcur][2] = True
|
||||||
elif t == "4":
|
elif t == "4":
|
||||||
sqlExecute(
|
sqlExecute(
|
||||||
"UPDATE subscriptions SET enabled=0 WHERE label=? AND address=?",
|
"UPDATE subscriptions SET enabled=0 WHERE label=? AND address=?",
|
||||||
subscriptions[subcur][0],
|
dbstr(subscriptions[subcur][0]),
|
||||||
subscriptions[subcur][1])
|
dbstr(subscriptions[subcur][1]))
|
||||||
shared.reloadBroadcastSendersForWhichImWatching()
|
shared.reloadBroadcastSendersForWhichImWatching()
|
||||||
subscriptions[subcur][2] = False
|
subscriptions[subcur][2] = False
|
||||||
elif menutab == 6:
|
elif menutab == 6:
|
||||||
|
@ -762,7 +789,7 @@ def handlech(c, stdscr):
|
||||||
subscriptions.append([label, addr, True])
|
subscriptions.append([label, addr, True])
|
||||||
subscriptions.reverse()
|
subscriptions.reverse()
|
||||||
|
|
||||||
sqlExecute("INSERT INTO subscriptions VALUES (?,?,?)", label, addr, True)
|
sqlExecute("INSERT INTO subscriptions VALUES (?,?,?)", dbstr(label), dbstr(addr), True)
|
||||||
shared.reloadBroadcastSendersForWhichImWatching()
|
shared.reloadBroadcastSendersForWhichImWatching()
|
||||||
elif t == "3":
|
elif t == "3":
|
||||||
r, t = d.inputbox("Input new address")
|
r, t = d.inputbox("Input new address")
|
||||||
|
@ -771,7 +798,7 @@ def handlech(c, stdscr):
|
||||||
if addr not in [item[1] for i, item in enumerate(addrbook)]:
|
if addr not in [item[1] for i, item in enumerate(addrbook)]:
|
||||||
r, t = d.inputbox("Label for address \"" + addr + "\"")
|
r, t = d.inputbox("Label for address \"" + addr + "\"")
|
||||||
if r == d.DIALOG_OK:
|
if r == d.DIALOG_OK:
|
||||||
sqlExecute("INSERT INTO addressbook VALUES (?,?)", t, addr)
|
sqlExecute("INSERT INTO addressbook VALUES (?,?)", dbstr(t), dbstr(addr))
|
||||||
# Prepend entry
|
# Prepend entry
|
||||||
addrbook.reverse()
|
addrbook.reverse()
|
||||||
addrbook.append([t, addr])
|
addrbook.append([t, addr])
|
||||||
|
@ -783,8 +810,8 @@ def handlech(c, stdscr):
|
||||||
if r == d.DIALOG_OK and t == "I want to delete this Address Book entry":
|
if r == d.DIALOG_OK and t == "I want to delete this Address Book entry":
|
||||||
sqlExecute(
|
sqlExecute(
|
||||||
"DELETE FROM addressbook WHERE label=? AND address=?",
|
"DELETE FROM addressbook WHERE label=? AND address=?",
|
||||||
addrbook[abookcur][0],
|
dbstr(addrbook[abookcur][0]),
|
||||||
addrbook[abookcur][1])
|
dbstr(addrbook[abookcur][1]))
|
||||||
del addrbook[abookcur]
|
del addrbook[abookcur]
|
||||||
elif menutab == 7:
|
elif menutab == 7:
|
||||||
set_background_title(d, "Blacklist Dialog Box")
|
set_background_title(d, "Blacklist Dialog Box")
|
||||||
|
@ -800,20 +827,20 @@ def handlech(c, stdscr):
|
||||||
if r == d.DIALOG_OK and t == "I want to delete this Blacklist entry":
|
if r == d.DIALOG_OK and t == "I want to delete this Blacklist entry":
|
||||||
sqlExecute(
|
sqlExecute(
|
||||||
"DELETE FROM blacklist WHERE label=? AND address=?",
|
"DELETE FROM blacklist WHERE label=? AND address=?",
|
||||||
blacklist[blackcur][0],
|
dbstr(blacklist[blackcur][0]),
|
||||||
blacklist[blackcur][1])
|
dbstr(blacklist[blackcur][1]))
|
||||||
del blacklist[blackcur]
|
del blacklist[blackcur]
|
||||||
elif t == "2":
|
elif t == "2":
|
||||||
sqlExecute(
|
sqlExecute(
|
||||||
"UPDATE blacklist SET enabled=1 WHERE label=? AND address=?",
|
"UPDATE blacklist SET enabled=1 WHERE label=? AND address=?",
|
||||||
blacklist[blackcur][0],
|
dbstr(blacklist[blackcur][0]),
|
||||||
blacklist[blackcur][1])
|
dbstr(blacklist[blackcur][1]))
|
||||||
blacklist[blackcur][2] = True
|
blacklist[blackcur][2] = True
|
||||||
elif t == "3":
|
elif t == "3":
|
||||||
sqlExecute(
|
sqlExecute(
|
||||||
"UPDATE blacklist SET enabled=0 WHERE label=? AND address=?",
|
"UPDATE blacklist SET enabled=0 WHERE label=? AND address=?",
|
||||||
blacklist[blackcur][0],
|
dbstr(blacklist[blackcur][0]),
|
||||||
blacklist[blackcur][1])
|
dbstr(blacklist[blackcur][1]))
|
||||||
blacklist[blackcur][2] = False
|
blacklist[blackcur][2] = False
|
||||||
dialogreset(stdscr)
|
dialogreset(stdscr)
|
||||||
else:
|
else:
|
||||||
|
@ -991,10 +1018,13 @@ def loadInbox():
|
||||||
ret = sqlQuery("""SELECT msgid, toaddress, fromaddress, subject, received, read
|
ret = sqlQuery("""SELECT msgid, toaddress, fromaddress, subject, received, read
|
||||||
FROM inbox WHERE folder='inbox' AND %s LIKE ?
|
FROM inbox WHERE folder='inbox' AND %s LIKE ?
|
||||||
ORDER BY received
|
ORDER BY received
|
||||||
""" % (where,), what)
|
""" % (where,), dbstr(what))
|
||||||
for row in ret:
|
for row in ret:
|
||||||
msgid, toaddr, fromaddr, subject, received, read = row
|
msgid, toaddr, fromaddr, subject, received, read = row
|
||||||
|
toaddr = toaddr.decode("utf-8", "replace")
|
||||||
|
fromaddr = fromaddr.decode("utf-8", "replace")
|
||||||
subject = ascii(shared.fixPotentiallyInvalidUTF8Data(subject))
|
subject = ascii(shared.fixPotentiallyInvalidUTF8Data(subject))
|
||||||
|
received = received.decode("utf-8", "replace")
|
||||||
|
|
||||||
# Set label for to address
|
# Set label for to address
|
||||||
try:
|
try:
|
||||||
|
@ -1013,18 +1043,19 @@ def loadInbox():
|
||||||
if config.has_section(fromaddr):
|
if config.has_section(fromaddr):
|
||||||
fromlabel = config.get(fromaddr, "label")
|
fromlabel = config.get(fromaddr, "label")
|
||||||
if fromlabel == "": # Check Address Book
|
if fromlabel == "": # Check Address Book
|
||||||
qr = sqlQuery("SELECT label FROM addressbook WHERE address=?", fromaddr)
|
qr = sqlQuery("SELECT label FROM addressbook WHERE address=?", dbstr(fromaddr))
|
||||||
if qr != []:
|
if qr != []:
|
||||||
for r in qr:
|
for r in qr:
|
||||||
fromlabel, = r
|
fromlabel, = r
|
||||||
|
fromlabel = shared.fixPotentiallyInvalidUTF8Data(fromlabel)
|
||||||
if fromlabel == "": # Check Subscriptions
|
if fromlabel == "": # Check Subscriptions
|
||||||
qr = sqlQuery("SELECT label FROM subscriptions WHERE address=?", fromaddr)
|
qr = sqlQuery("SELECT label FROM subscriptions WHERE address=?", dbstr(fromaddr))
|
||||||
if qr != []:
|
if qr != []:
|
||||||
for r in qr:
|
for r in qr:
|
||||||
fromlabel, = r
|
fromlabel, = r
|
||||||
|
fromlabel = shared.fixPotentiallyInvalidUTF8Data(fromlabel)
|
||||||
if fromlabel == "":
|
if fromlabel == "":
|
||||||
fromlabel = fromaddr
|
fromlabel = fromaddr
|
||||||
fromlabel = shared.fixPotentiallyInvalidUTF8Data(fromlabel)
|
|
||||||
|
|
||||||
# Load into array
|
# Load into array
|
||||||
inbox.append([
|
inbox.append([
|
||||||
|
@ -1044,22 +1075,27 @@ def loadSent():
|
||||||
ret = sqlQuery("""SELECT toaddress, fromaddress, subject, status, ackdata, lastactiontime
|
ret = sqlQuery("""SELECT toaddress, fromaddress, subject, status, ackdata, lastactiontime
|
||||||
FROM sent WHERE folder='sent' AND %s LIKE ?
|
FROM sent WHERE folder='sent' AND %s LIKE ?
|
||||||
ORDER BY lastactiontime
|
ORDER BY lastactiontime
|
||||||
""" % (where,), what)
|
""" % (where,), dbstr(what))
|
||||||
for row in ret:
|
for row in ret:
|
||||||
toaddr, fromaddr, subject, status, ackdata, lastactiontime = row
|
toaddr, fromaddr, subject, status, ackdata, lastactiontime = row
|
||||||
|
toaddr = toaddr.decode("utf-8", "replace")
|
||||||
|
fromaddr = fromaddr.decode("utf-8", "replace")
|
||||||
subject = ascii(shared.fixPotentiallyInvalidUTF8Data(subject))
|
subject = ascii(shared.fixPotentiallyInvalidUTF8Data(subject))
|
||||||
|
status = status.decode("utf-8", "replace")
|
||||||
|
|
||||||
# Set label for to address
|
# Set label for to address
|
||||||
tolabel = ""
|
tolabel = ""
|
||||||
qr = sqlQuery("SELECT label FROM addressbook WHERE address=?", toaddr)
|
qr = sqlQuery("SELECT label FROM addressbook WHERE address=?", dbstr(toaddr))
|
||||||
if qr != []:
|
if qr != []:
|
||||||
for r in qr:
|
for r in qr:
|
||||||
tolabel, = r
|
tolabel, = r
|
||||||
|
tolabel = tolabel.decode("utf-8", "replace")
|
||||||
if tolabel == "":
|
if tolabel == "":
|
||||||
qr = sqlQuery("SELECT label FROM subscriptions WHERE address=?", toaddr)
|
qr = sqlQuery("SELECT label FROM subscriptions WHERE address=?", dbstr(toaddr))
|
||||||
if qr != []:
|
if qr != []:
|
||||||
for r in qr:
|
for r in qr:
|
||||||
tolabel, = r
|
tolabel, = r
|
||||||
|
tolabel = tolabel.decode("utf-8", "replace")
|
||||||
if tolabel == "":
|
if tolabel == "":
|
||||||
if config.has_section(toaddr):
|
if config.has_section(toaddr):
|
||||||
tolabel = config.get(toaddr, "label")
|
tolabel = config.get(toaddr, "label")
|
||||||
|
@ -1129,6 +1165,7 @@ def loadAddrBook():
|
||||||
for row in ret:
|
for row in ret:
|
||||||
label, addr = row
|
label, addr = row
|
||||||
label = shared.fixPotentiallyInvalidUTF8Data(label)
|
label = shared.fixPotentiallyInvalidUTF8Data(label)
|
||||||
|
addr = addr.decode("utf-8", "replace")
|
||||||
addrbook.append([label, addr])
|
addrbook.append([label, addr])
|
||||||
addrbook.reverse()
|
addrbook.reverse()
|
||||||
|
|
||||||
|
@ -1138,6 +1175,8 @@ def loadSubscriptions():
|
||||||
ret = sqlQuery("SELECT label, address, enabled FROM subscriptions")
|
ret = sqlQuery("SELECT label, address, enabled FROM subscriptions")
|
||||||
for row in ret:
|
for row in ret:
|
||||||
label, address, enabled = row
|
label, address, enabled = row
|
||||||
|
label = label.decode("utf-8", "replace")
|
||||||
|
address = address.decode("utf-8", "replace")
|
||||||
subscriptions.append([label, address, enabled])
|
subscriptions.append([label, address, enabled])
|
||||||
subscriptions.reverse()
|
subscriptions.reverse()
|
||||||
|
|
||||||
|
@ -1152,6 +1191,8 @@ def loadBlackWhiteList():
|
||||||
ret = sqlQuery("SELECT label, address, enabled FROM whitelist")
|
ret = sqlQuery("SELECT label, address, enabled FROM whitelist")
|
||||||
for row in ret:
|
for row in ret:
|
||||||
label, address, enabled = row
|
label, address, enabled = row
|
||||||
|
label = label.decode("utf-8", "replace")
|
||||||
|
address = address.decode("utf-8", "replace")
|
||||||
blacklist.append([label, address, enabled])
|
blacklist.append([label, address, enabled])
|
||||||
blacklist.reverse()
|
blacklist.reverse()
|
||||||
|
|
||||||
|
|
|
@ -29,6 +29,7 @@ from pybitmessage.bitmessagekivy.baseclass.common import (
|
||||||
from pybitmessage.bitmessagekivy.baseclass.popup import SavedAddressDetailPopup
|
from pybitmessage.bitmessagekivy.baseclass.popup import SavedAddressDetailPopup
|
||||||
from pybitmessage.bitmessagekivy.baseclass.addressbook_widgets import HelperAddressBook
|
from pybitmessage.bitmessagekivy.baseclass.addressbook_widgets import HelperAddressBook
|
||||||
from pybitmessage.helper_sql import sqlExecute
|
from pybitmessage.helper_sql import sqlExecute
|
||||||
|
from dbcompat import dbstr
|
||||||
|
|
||||||
logger = logging.getLogger('default')
|
logger = logging.getLogger('default')
|
||||||
|
|
||||||
|
@ -59,7 +60,7 @@ class AddressBook(Screen, HelperAddressBook):
|
||||||
self.ids.tag_label.text = ''
|
self.ids.tag_label.text = ''
|
||||||
self.queryreturn = kivy_helper_search.search_sql(
|
self.queryreturn = kivy_helper_search.search_sql(
|
||||||
xAddress, account, "addressbook", where, what, False)
|
xAddress, account, "addressbook", where, what, False)
|
||||||
self.queryreturn = [obj for obj in reversed(self.queryreturn)]
|
self.queryreturn = [[obj[0].decode("utf-8", "replace"), obj[1].decode("utf-8", "replace")] for obj in reversed(self.queryreturn)]
|
||||||
if self.queryreturn:
|
if self.queryreturn:
|
||||||
self.ids.tag_label.text = 'Address Book'
|
self.ids.tag_label.text = 'Address Book'
|
||||||
self.has_refreshed = True
|
self.has_refreshed = True
|
||||||
|
@ -131,7 +132,7 @@ class AddressBook(Screen, HelperAddressBook):
|
||||||
if self.ids.ml.children is not None:
|
if self.ids.ml.children is not None:
|
||||||
self.ids.tag_label.text = ''
|
self.ids.tag_label.text = ''
|
||||||
sqlExecute(
|
sqlExecute(
|
||||||
"DELETE FROM addressbook WHERE address = ?", address)
|
"DELETE FROM addressbook WHERE address = ?", dbstr(address))
|
||||||
toast('Address Deleted')
|
toast('Address Deleted')
|
||||||
|
|
||||||
def close_pop(self, instance):
|
def close_pop(self, instance):
|
||||||
|
@ -142,8 +143,13 @@ class AddressBook(Screen, HelperAddressBook):
|
||||||
def update_addbook_label(self, instance):
|
def update_addbook_label(self, instance):
|
||||||
"""Updating the label of address book address"""
|
"""Updating the label of address book address"""
|
||||||
address_list = kivy_helper_search.search_sql(folder="addressbook")
|
address_list = kivy_helper_search.search_sql(folder="addressbook")
|
||||||
stored_labels = [labels[0] for labels in address_list]
|
stored_labels = [labels[0].decode("utf-8", "replace") for labels in address_list]
|
||||||
add_dict = dict(address_list)
|
add_dict = {}
|
||||||
|
for row in address_list:
|
||||||
|
label, address = row
|
||||||
|
label = label.decode("utf-8", "replace")
|
||||||
|
address = address.decode("utf-8", "replace")
|
||||||
|
add_dict[label] = address
|
||||||
label = str(self.addbook_popup.content_cls.ids.add_label.text)
|
label = str(self.addbook_popup.content_cls.ids.add_label.text)
|
||||||
if label in stored_labels and self.address == add_dict[label]:
|
if label in stored_labels and self.address == add_dict[label]:
|
||||||
stored_labels.remove(label)
|
stored_labels.remove(label)
|
||||||
|
@ -151,7 +157,7 @@ class AddressBook(Screen, HelperAddressBook):
|
||||||
sqlExecute("""
|
sqlExecute("""
|
||||||
UPDATE addressbook
|
UPDATE addressbook
|
||||||
SET label = ?
|
SET label = ?
|
||||||
WHERE address = ?""", label, self.addbook_popup.content_cls.address)
|
WHERE address = ?""", dbstr(label), dbstr(self.addbook_popup.content_cls.address))
|
||||||
App.get_running_app().root.ids.id_addressbook.ids.ml.clear_widgets()
|
App.get_running_app().root.ids.id_addressbook.ids.ml.clear_widgets()
|
||||||
App.get_running_app().root.ids.id_addressbook.loadAddresslist(None, 'All', '')
|
App.get_running_app().root.ids.id_addressbook.loadAddresslist(None, 'All', '')
|
||||||
self.addbook_popup.dismiss()
|
self.addbook_popup.dismiss()
|
||||||
|
|
|
@ -7,6 +7,7 @@ Maildetail screen for inbox, sent, draft and trash.
|
||||||
|
|
||||||
import os
|
import os
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
import sqlite3
|
||||||
|
|
||||||
from kivy.core.clipboard import Clipboard
|
from kivy.core.clipboard import Clipboard
|
||||||
from kivy.clock import Clock
|
from kivy.clock import Clock
|
||||||
|
@ -111,7 +112,11 @@ class MailDetail(Screen): # pylint: disable=too-many-instance-attributes
|
||||||
elif self.kivy_state.detail_page_type == 'inbox':
|
elif self.kivy_state.detail_page_type == 'inbox':
|
||||||
data = sqlQuery(
|
data = sqlQuery(
|
||||||
"select toaddress, fromaddress, subject, message, received from inbox"
|
"select toaddress, fromaddress, subject, message, received from inbox"
|
||||||
" where msgid = ?", self.kivy_state.mail_id)
|
" where msgid = ?", sqlite3.Binary(self.kivy_state.mail_id))
|
||||||
|
if len(data) < 1:
|
||||||
|
data = sqlQuery(
|
||||||
|
"select toaddress, fromaddress, subject, message, received from inbox"
|
||||||
|
" where msgid = CAST(? AS TEXT)", self.kivy_state.mail_id)
|
||||||
self.assign_mail_details(data)
|
self.assign_mail_details(data)
|
||||||
App.get_running_app().set_mail_detail_header()
|
App.get_running_app().set_mail_detail_header()
|
||||||
except Exception as e: # pylint: disable=unused-variable
|
except Exception as e: # pylint: disable=unused-variable
|
||||||
|
@ -119,16 +124,16 @@ class MailDetail(Screen): # pylint: disable=too-many-instance-attributes
|
||||||
|
|
||||||
def assign_mail_details(self, data):
|
def assign_mail_details(self, data):
|
||||||
"""Assigning mail details"""
|
"""Assigning mail details"""
|
||||||
subject = data[0][2].decode() if isinstance(data[0][2], bytes) else data[0][2]
|
subject = data[0][2].decode("utf-8", "replace") if isinstance(data[0][2], bytes) else data[0][2]
|
||||||
body = data[0][3].decode() if isinstance(data[0][2], bytes) else data[0][3]
|
body = data[0][3].decode("utf-8", "replace") if isinstance(data[0][2], bytes) else data[0][3]
|
||||||
self.to_addr = data[0][0] if len(data[0][0]) > 4 else ' '
|
self.to_addr = data[0][0].decode("utf-8", "replace") if len(data[0][0]) > 4 else ' '
|
||||||
self.from_addr = data[0][1]
|
self.from_addr = data[0][1].decode("utf-8", "replace")
|
||||||
|
|
||||||
self.subject = subject.capitalize(
|
self.subject = subject.capitalize(
|
||||||
) if subject.capitalize() else self.no_subject
|
) if subject.capitalize() else self.no_subject
|
||||||
self.message = body
|
self.message = body
|
||||||
if len(data[0]) == 7:
|
if len(data[0]) == 7:
|
||||||
self.status = data[0][4]
|
self.status = data[0][4].decode("utf-8", "replace")
|
||||||
self.time_tag = show_time_history(data[0][4]) if self.kivy_state.detail_page_type == 'inbox' \
|
self.time_tag = show_time_history(data[0][4]) if self.kivy_state.detail_page_type == 'inbox' \
|
||||||
else show_time_history(data[0][6])
|
else show_time_history(data[0][6])
|
||||||
self.avatarImg = os.path.join(self.kivy_state.imageDir, 'draft-icon.png') \
|
self.avatarImg = os.path.join(self.kivy_state.imageDir, 'draft-icon.png') \
|
||||||
|
|
|
@ -59,7 +59,7 @@ class AddAddressPopup(BoxLayout):
|
||||||
"""Checking address is valid or not"""
|
"""Checking address is valid or not"""
|
||||||
my_addresses = (
|
my_addresses = (
|
||||||
App.get_running_app().root.ids.content_drawer.ids.identity_dropdown.values)
|
App.get_running_app().root.ids.content_drawer.ids.identity_dropdown.values)
|
||||||
add_book = [addr[1] for addr in kivy_helper_search.search_sql(
|
add_book = [addr[1].decode("utf-8", "replace") for addr in kivy_helper_search.search_sql(
|
||||||
folder="addressbook")]
|
folder="addressbook")]
|
||||||
entered_text = str(instance.text).strip()
|
entered_text = str(instance.text).strip()
|
||||||
if entered_text in add_book:
|
if entered_text in add_book:
|
||||||
|
@ -84,7 +84,7 @@ class AddAddressPopup(BoxLayout):
|
||||||
def checkLabel_valid(self, instance):
|
def checkLabel_valid(self, instance):
|
||||||
"""Checking address label is unique or not"""
|
"""Checking address label is unique or not"""
|
||||||
entered_label = instance.text.strip()
|
entered_label = instance.text.strip()
|
||||||
addr_labels = [labels[0] for labels in kivy_helper_search.search_sql(
|
addr_labels = [labels[0].decode("utf-8", "replace") for labels in kivy_helper_search.search_sql(
|
||||||
folder="addressbook")]
|
folder="addressbook")]
|
||||||
if entered_label in addr_labels:
|
if entered_label in addr_labels:
|
||||||
self.ids.label.error = True
|
self.ids.label.error = True
|
||||||
|
@ -125,8 +125,13 @@ class SavedAddressDetailPopup(BoxLayout):
|
||||||
"""Checking address label is unique of not"""
|
"""Checking address label is unique of not"""
|
||||||
entered_label = str(instance.text.strip())
|
entered_label = str(instance.text.strip())
|
||||||
address_list = kivy_helper_search.search_sql(folder="addressbook")
|
address_list = kivy_helper_search.search_sql(folder="addressbook")
|
||||||
addr_labels = [labels[0] for labels in address_list]
|
addr_labels = [labels[0].decode("utf-8", "replace") for labels in address_list]
|
||||||
add_dict = dict(address_list)
|
add_dict = {}
|
||||||
|
for row in address_list:
|
||||||
|
label, address = row
|
||||||
|
label = label.decode("utf-8", "replace")
|
||||||
|
address = address.decode("utf-8", "replace")
|
||||||
|
add_dict[label] = address
|
||||||
if self.address and entered_label in addr_labels \
|
if self.address and entered_label in addr_labels \
|
||||||
and self.address != add_dict[entered_label]:
|
and self.address != add_dict[entered_label]:
|
||||||
self.ids.add_label.error = True
|
self.ids.add_label.error = True
|
||||||
|
|
|
@ -3,7 +3,7 @@ Core classes for loading images and converting them to a Texture.
|
||||||
The raw image data can be keep in memory for further access
|
The raw image data can be keep in memory for further access
|
||||||
"""
|
"""
|
||||||
import hashlib
|
import hashlib
|
||||||
from io import BytesIO
|
from six import BytesIO
|
||||||
|
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
from kivy.core.image import Image as CoreImage
|
from kivy.core.image import Image as CoreImage
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
Sql queries for bitmessagekivy
|
Sql queries for bitmessagekivy
|
||||||
"""
|
"""
|
||||||
from pybitmessage.helper_sql import sqlQuery
|
from pybitmessage.helper_sql import sqlQuery
|
||||||
|
from dbcompat import dbstr
|
||||||
|
|
||||||
|
|
||||||
def search_sql(
|
def search_sql(
|
||||||
|
@ -30,21 +31,21 @@ def search_sql(
|
||||||
if account is not None:
|
if account is not None:
|
||||||
if xAddress == 'both':
|
if xAddress == 'both':
|
||||||
sqlStatementParts.append("(fromaddress = ? OR toaddress = ?)")
|
sqlStatementParts.append("(fromaddress = ? OR toaddress = ?)")
|
||||||
sqlArguments.append(account)
|
sqlArguments.append(dbstr(account))
|
||||||
sqlArguments.append(account)
|
sqlArguments.append(dbstr(account))
|
||||||
else:
|
else:
|
||||||
sqlStatementParts.append(xAddress + " = ? ")
|
sqlStatementParts.append(xAddress + " = ? ")
|
||||||
sqlArguments.append(account)
|
sqlArguments.append(dbstr(account))
|
||||||
if folder != "addressbook":
|
if folder != "addressbook":
|
||||||
if folder is not None:
|
if folder is not None:
|
||||||
if folder == "new":
|
if folder == "new":
|
||||||
folder = "inbox"
|
folder = "inbox"
|
||||||
unreadOnly = True
|
unreadOnly = True
|
||||||
sqlStatementParts.append("folder = ? ")
|
sqlStatementParts.append("folder = ? ")
|
||||||
sqlArguments.append(folder)
|
sqlArguments.append(dbstr(folder))
|
||||||
else:
|
else:
|
||||||
sqlStatementParts.append("folder != ?")
|
sqlStatementParts.append("folder != ?")
|
||||||
sqlArguments.append("trash")
|
sqlArguments.append(dbstr("trash"))
|
||||||
if what is not None:
|
if what is not None:
|
||||||
for colmns in where:
|
for colmns in where:
|
||||||
if len(where) > 1:
|
if len(where) > 1:
|
||||||
|
@ -54,7 +55,7 @@ def search_sql(
|
||||||
filter_col += " or %s LIKE ? )" % (colmns)
|
filter_col += " or %s LIKE ? )" % (colmns)
|
||||||
else:
|
else:
|
||||||
filter_col = "%s LIKE ?" % (colmns)
|
filter_col = "%s LIKE ?" % (colmns)
|
||||||
sqlArguments.append(what)
|
sqlArguments.append(dbstr(what))
|
||||||
sqlStatementParts.append(filter_col)
|
sqlStatementParts.append(filter_col)
|
||||||
if unreadOnly:
|
if unreadOnly:
|
||||||
sqlStatementParts.append("read = 0")
|
sqlStatementParts.append("read = 0")
|
||||||
|
|
|
@ -6,6 +6,7 @@ import os
|
||||||
import shutil
|
import shutil
|
||||||
import tempfile
|
import tempfile
|
||||||
from time import time, sleep
|
from time import time, sleep
|
||||||
|
from six.moves import getcwdb
|
||||||
|
|
||||||
from requests.exceptions import ChunkedEncodingError
|
from requests.exceptions import ChunkedEncodingError
|
||||||
|
|
||||||
|
@ -34,7 +35,7 @@ def cleanup(files=_files):
|
||||||
|
|
||||||
class TeleniumTestProcess(TeleniumTestCase):
|
class TeleniumTestProcess(TeleniumTestCase):
|
||||||
"""Setting Screen Functionality Testing"""
|
"""Setting Screen Functionality Testing"""
|
||||||
cmd_entrypoint = [os.path.join(os.path.abspath(os.getcwd()), 'src', 'mockbm', 'kivy_main.py')]
|
cmd_entrypoint = [os.path.join(os.path.abspath(getcwdb()), 'src', 'mockbm', 'kivy_main.py')]
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpClass(cls):
|
def setUpClass(cls):
|
||||||
|
|
|
@ -4,6 +4,7 @@ PyQt based UI for bitmessage, the main module
|
||||||
|
|
||||||
import hashlib
|
import hashlib
|
||||||
import locale
|
import locale
|
||||||
|
import logging
|
||||||
import os
|
import os
|
||||||
import random
|
import random
|
||||||
import string
|
import string
|
||||||
|
@ -14,46 +15,52 @@ import threading
|
||||||
import time
|
import time
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
from sqlite3 import register_adapter
|
from sqlite3 import register_adapter
|
||||||
|
import sqlite3
|
||||||
|
import six
|
||||||
|
from six.moves import range as xrange
|
||||||
|
if six.PY3:
|
||||||
|
from codecs import escape_decode
|
||||||
|
|
||||||
from PyQt4 import QtCore, QtGui
|
from unqstr import ustr, unic
|
||||||
from PyQt4.QtNetwork import QLocalSocket, QLocalServer
|
from dbcompat import dbstr
|
||||||
|
from qtpy import QtCore, QtGui, QtWidgets, QtNetwork
|
||||||
|
|
||||||
import shared
|
import shared
|
||||||
import state
|
import state
|
||||||
from debug import logger
|
from debug import logger
|
||||||
from tr import _translate
|
from tr import _translate
|
||||||
from account import (
|
from .account import (
|
||||||
accountClass, getSortedSubscriptions,
|
accountClass, getSortedSubscriptions,
|
||||||
BMAccount, GatewayAccount, MailchuckAccount, AccountColor)
|
BMAccount, GatewayAccount, MailchuckAccount, AccountColor)
|
||||||
from addresses import decodeAddress, addBMIfNotPresent
|
from addresses import decodeAddress, addBMIfNotPresent
|
||||||
from bitmessageui import Ui_MainWindow
|
from bitmessageqt.bitmessageui import Ui_MainWindow
|
||||||
from bmconfigparser import config
|
from bmconfigparser import config
|
||||||
import namecoin
|
import namecoin
|
||||||
from messageview import MessageView
|
from .messageview import MessageView
|
||||||
from migrationwizard import Ui_MigrationWizard
|
from .migrationwizard import Ui_MigrationWizard
|
||||||
from foldertree import (
|
from .foldertree import (
|
||||||
AccountMixin, Ui_FolderWidget, Ui_AddressWidget, Ui_SubscriptionWidget,
|
AccountMixin, Ui_FolderWidget, Ui_AddressWidget, Ui_SubscriptionWidget,
|
||||||
MessageList_AddressWidget, MessageList_SubjectWidget,
|
MessageList_AddressWidget, MessageList_SubjectWidget,
|
||||||
Ui_AddressBookWidgetItemLabel, Ui_AddressBookWidgetItemAddress,
|
Ui_AddressBookWidgetItemLabel, Ui_AddressBookWidgetItemAddress,
|
||||||
MessageList_TimeWidget)
|
MessageList_TimeWidget)
|
||||||
import settingsmixin
|
from bitmessageqt import settingsmixin
|
||||||
import support
|
from bitmessageqt import support
|
||||||
from helper_sql import sqlQuery, sqlExecute, sqlExecuteChunked, sqlStoredProcedure
|
from helper_sql import sqlQuery, sqlExecute, sqlExecuteChunked, sqlStoredProcedure
|
||||||
import helper_addressbook
|
import helper_addressbook
|
||||||
import helper_search
|
import helper_search
|
||||||
import l10n
|
import l10n
|
||||||
from utils import str_broadcast_subscribers, avatarize
|
from .utils import str_broadcast_subscribers, avatarize
|
||||||
import dialogs
|
from bitmessageqt import dialogs
|
||||||
from network.stats import pendingDownload, pendingUpload
|
from network.stats import pendingDownload, pendingUpload
|
||||||
from uisignaler import UISignaler
|
from .uisignaler import UISignaler
|
||||||
import paths
|
import paths
|
||||||
from proofofwork import getPowType
|
from proofofwork import getPowType
|
||||||
import queues
|
import queues
|
||||||
import shutdown
|
import shutdown
|
||||||
from statusbar import BMStatusBar
|
from .statusbar import BMStatusBar
|
||||||
import sound
|
from bitmessageqt import sound
|
||||||
# This is needed for tray icon
|
# This is needed for tray icon
|
||||||
import bitmessage_icons_rc # noqa:F401 pylint: disable=unused-import
|
from bitmessageqt import bitmessage_icons_rc # noqa:F401 pylint: disable=unused-import
|
||||||
import helper_sent
|
import helper_sent
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
@ -61,6 +68,7 @@ try:
|
||||||
except ImportError:
|
except ImportError:
|
||||||
get_plugins = False
|
get_plugins = False
|
||||||
|
|
||||||
|
logger = logging.getLogger('default')
|
||||||
|
|
||||||
is_windows = sys.platform.startswith('win')
|
is_windows = sys.platform.startswith('win')
|
||||||
|
|
||||||
|
@ -87,6 +95,13 @@ def openKeysFile():
|
||||||
os.startfile(keysfile) # pylint: disable=no-member
|
os.startfile(keysfile) # pylint: disable=no-member
|
||||||
|
|
||||||
|
|
||||||
|
def as_msgid(id_data):
|
||||||
|
if six.PY3:
|
||||||
|
return escape_decode(id_data)[0][2:-1]
|
||||||
|
else: # assume six.PY2
|
||||||
|
return id_data
|
||||||
|
|
||||||
|
|
||||||
class MyForm(settingsmixin.SMainWindow):
|
class MyForm(settingsmixin.SMainWindow):
|
||||||
|
|
||||||
# the maximum frequency of message sounds in seconds
|
# the maximum frequency of message sounds in seconds
|
||||||
|
@ -102,12 +117,12 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
newlocale = l10n.getTranslationLanguage()
|
newlocale = l10n.getTranslationLanguage()
|
||||||
try:
|
try:
|
||||||
if not self.qmytranslator.isEmpty():
|
if not self.qmytranslator.isEmpty():
|
||||||
QtGui.QApplication.removeTranslator(self.qmytranslator)
|
QtWidgets.QApplication.removeTranslator(self.qmytranslator)
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
try:
|
try:
|
||||||
if not self.qsystranslator.isEmpty():
|
if not self.qsystranslator.isEmpty():
|
||||||
QtGui.QApplication.removeTranslator(self.qsystranslator)
|
QtWidgets.QApplication.removeTranslator(self.qsystranslator)
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -115,7 +130,7 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
translationpath = os.path.join(
|
translationpath = os.path.join(
|
||||||
paths.codePath(), 'translations', 'bitmessage_' + newlocale)
|
paths.codePath(), 'translations', 'bitmessage_' + newlocale)
|
||||||
self.qmytranslator.load(translationpath)
|
self.qmytranslator.load(translationpath)
|
||||||
QtGui.QApplication.installTranslator(self.qmytranslator)
|
QtWidgets.QApplication.installTranslator(self.qmytranslator)
|
||||||
|
|
||||||
self.qsystranslator = QtCore.QTranslator()
|
self.qsystranslator = QtCore.QTranslator()
|
||||||
if paths.frozen:
|
if paths.frozen:
|
||||||
|
@ -123,10 +138,10 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
paths.codePath(), 'translations', 'qt_' + newlocale)
|
paths.codePath(), 'translations', 'qt_' + newlocale)
|
||||||
else:
|
else:
|
||||||
translationpath = os.path.join(
|
translationpath = os.path.join(
|
||||||
str(QtCore.QLibraryInfo.location(
|
ustr(QtCore.QLibraryInfo.location(
|
||||||
QtCore.QLibraryInfo.TranslationsPath)), 'qt_' + newlocale)
|
QtCore.QLibraryInfo.TranslationsPath)), 'qt_' + newlocale)
|
||||||
self.qsystranslator.load(translationpath)
|
self.qsystranslator.load(translationpath)
|
||||||
QtGui.QApplication.installTranslator(self.qsystranslator)
|
QtWidgets.QApplication.installTranslator(self.qsystranslator)
|
||||||
|
|
||||||
# TODO: move this block into l10n
|
# TODO: move this block into l10n
|
||||||
# FIXME: shouldn't newlocale be used here?
|
# 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)
|
logger.error("Failed to set locale to %s", lang, exc_info=True)
|
||||||
|
|
||||||
def init_file_menu(self):
|
def init_file_menu(self):
|
||||||
QtCore.QObject.connect(self.ui.actionExit, QtCore.SIGNAL(
|
self.ui.actionExit.triggered.connect(self.quit)
|
||||||
"triggered()"), self.quit)
|
self.ui.actionNetworkSwitch.triggered.connect(self.network_switch)
|
||||||
QtCore.QObject.connect(self.ui.actionNetworkSwitch, QtCore.SIGNAL(
|
self.ui.actionManageKeys.triggered.connect(self.click_actionManageKeys)
|
||||||
"triggered()"), self.network_switch)
|
self.ui.actionDeleteAllTrashedMessages.triggered.connect(
|
||||||
QtCore.QObject.connect(self.ui.actionManageKeys, QtCore.SIGNAL(
|
self.click_actionDeleteAllTrashedMessages)
|
||||||
"triggered()"), self.click_actionManageKeys)
|
self.ui.actionRegenerateDeterministicAddresses.triggered.connect(
|
||||||
QtCore.QObject.connect(self.ui.actionDeleteAllTrashedMessages,
|
self.click_actionRegenerateDeterministicAddresses)
|
||||||
QtCore.SIGNAL(
|
self.ui.actionSettings.triggered.connect(self.click_actionSettings)
|
||||||
"triggered()"),
|
self.ui.actionAbout.triggered.connect(self.click_actionAbout)
|
||||||
self.click_actionDeleteAllTrashedMessages)
|
self.ui.actionSupport.triggered.connect(self.click_actionSupport)
|
||||||
QtCore.QObject.connect(self.ui.actionRegenerateDeterministicAddresses,
|
self.ui.actionHelp.triggered.connect(self.click_actionHelp)
|
||||||
QtCore.SIGNAL(
|
|
||||||
"triggered()"),
|
# also used for creating chans.
|
||||||
self.click_actionRegenerateDeterministicAddresses)
|
self.ui.pushButtonAddChan.clicked.connect(self.click_actionJoinChan)
|
||||||
QtCore.QObject.connect(
|
self.ui.pushButtonNewAddress.clicked.connect(
|
||||||
self.ui.pushButtonAddChan,
|
self.click_NewAddressDialog)
|
||||||
QtCore.SIGNAL("clicked()"),
|
self.ui.pushButtonAddAddressBook.clicked.connect(
|
||||||
self.click_actionJoinChan) # also used for creating chans.
|
self.click_pushButtonAddAddressBook)
|
||||||
QtCore.QObject.connect(self.ui.pushButtonNewAddress, QtCore.SIGNAL(
|
self.ui.pushButtonAddSubscription.clicked.connect(
|
||||||
"clicked()"), self.click_NewAddressDialog)
|
self.click_pushButtonAddSubscription)
|
||||||
QtCore.QObject.connect(self.ui.pushButtonAddAddressBook, QtCore.SIGNAL(
|
self.ui.pushButtonTTL.clicked.connect(self.click_pushButtonTTL)
|
||||||
"clicked()"), self.click_pushButtonAddAddressBook)
|
self.ui.pushButtonClear.clicked.connect(self.click_pushButtonClear)
|
||||||
QtCore.QObject.connect(self.ui.pushButtonAddSubscription, QtCore.SIGNAL(
|
self.ui.pushButtonSend.clicked.connect(self.click_pushButtonSend)
|
||||||
"clicked()"), self.click_pushButtonAddSubscription)
|
self.ui.pushButtonFetchNamecoinID.clicked.connect(
|
||||||
QtCore.QObject.connect(self.ui.pushButtonTTL, QtCore.SIGNAL(
|
self.click_pushButtonFetchNamecoinID)
|
||||||
"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)
|
|
||||||
|
|
||||||
def init_inbox_popup_menu(self, connectSignal=True):
|
def init_inbox_popup_menu(self, connectSignal=True):
|
||||||
# Popup menu for the Inbox tab
|
# Popup menu for the Inbox tab
|
||||||
self.ui.inboxContextMenuToolbar = QtGui.QToolBar()
|
self.ui.inboxContextMenuToolbar = QtWidgets.QToolBar()
|
||||||
# Actions
|
# Actions
|
||||||
self.actionReply = self.ui.inboxContextMenuToolbar.addAction(_translate(
|
self.actionReply = self.ui.inboxContextMenuToolbar.addAction(_translate(
|
||||||
"MainWindow", "Reply to sender"), self.on_action_InboxReply)
|
"MainWindow", "Reply to sender"), self.on_action_InboxReply)
|
||||||
|
@ -230,25 +230,22 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
self.ui.tableWidgetInbox.setContextMenuPolicy(
|
self.ui.tableWidgetInbox.setContextMenuPolicy(
|
||||||
QtCore.Qt.CustomContextMenu)
|
QtCore.Qt.CustomContextMenu)
|
||||||
if connectSignal:
|
if connectSignal:
|
||||||
self.connect(self.ui.tableWidgetInbox, QtCore.SIGNAL(
|
self.ui.tableWidgetInbox.customContextMenuRequested.connect(
|
||||||
'customContextMenuRequested(const QPoint&)'),
|
|
||||||
self.on_context_menuInbox)
|
self.on_context_menuInbox)
|
||||||
self.ui.tableWidgetInboxSubscriptions.setContextMenuPolicy(
|
self.ui.tableWidgetInboxSubscriptions.setContextMenuPolicy(
|
||||||
QtCore.Qt.CustomContextMenu)
|
QtCore.Qt.CustomContextMenu)
|
||||||
if connectSignal:
|
if connectSignal:
|
||||||
self.connect(self.ui.tableWidgetInboxSubscriptions, QtCore.SIGNAL(
|
self.ui.tableWidgetInboxSubscriptions.customContextMenuRequested.connect(
|
||||||
'customContextMenuRequested(const QPoint&)'),
|
|
||||||
self.on_context_menuInbox)
|
self.on_context_menuInbox)
|
||||||
self.ui.tableWidgetInboxChans.setContextMenuPolicy(
|
self.ui.tableWidgetInboxChans.setContextMenuPolicy(
|
||||||
QtCore.Qt.CustomContextMenu)
|
QtCore.Qt.CustomContextMenu)
|
||||||
if connectSignal:
|
if connectSignal:
|
||||||
self.connect(self.ui.tableWidgetInboxChans, QtCore.SIGNAL(
|
self.ui.tableWidgetInboxChans.customContextMenuRequested.connect(
|
||||||
'customContextMenuRequested(const QPoint&)'),
|
|
||||||
self.on_context_menuInbox)
|
self.on_context_menuInbox)
|
||||||
|
|
||||||
def init_identities_popup_menu(self, connectSignal=True):
|
def init_identities_popup_menu(self, connectSignal=True):
|
||||||
# Popup menu for the Your Identities tab
|
# Popup menu for the Your Identities tab
|
||||||
self.ui.addressContextMenuToolbarYourIdentities = QtGui.QToolBar()
|
self.ui.addressContextMenuToolbarYourIdentities = QtWidgets.QToolBar()
|
||||||
# Actions
|
# Actions
|
||||||
self.actionNewYourIdentities = self.ui.addressContextMenuToolbarYourIdentities.addAction(_translate(
|
self.actionNewYourIdentities = self.ui.addressContextMenuToolbarYourIdentities.addAction(_translate(
|
||||||
"MainWindow", "New"), self.on_action_YourIdentitiesNew)
|
"MainWindow", "New"), self.on_action_YourIdentitiesNew)
|
||||||
|
@ -282,8 +279,7 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
self.ui.treeWidgetYourIdentities.setContextMenuPolicy(
|
self.ui.treeWidgetYourIdentities.setContextMenuPolicy(
|
||||||
QtCore.Qt.CustomContextMenu)
|
QtCore.Qt.CustomContextMenu)
|
||||||
if connectSignal:
|
if connectSignal:
|
||||||
self.connect(self.ui.treeWidgetYourIdentities, QtCore.SIGNAL(
|
self.ui.treeWidgetYourIdentities.customContextMenuRequested.connect(
|
||||||
'customContextMenuRequested(const QPoint&)'),
|
|
||||||
self.on_context_menuYourIdentities)
|
self.on_context_menuYourIdentities)
|
||||||
|
|
||||||
# load all gui.menu plugins with prefix 'address'
|
# load all gui.menu plugins with prefix 'address'
|
||||||
|
@ -332,13 +328,12 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
self.ui.treeWidgetChans.setContextMenuPolicy(
|
self.ui.treeWidgetChans.setContextMenuPolicy(
|
||||||
QtCore.Qt.CustomContextMenu)
|
QtCore.Qt.CustomContextMenu)
|
||||||
if connectSignal:
|
if connectSignal:
|
||||||
self.connect(self.ui.treeWidgetChans, QtCore.SIGNAL(
|
self.ui.treeWidgetChans.customContextMenuRequested.connect(
|
||||||
'customContextMenuRequested(const QPoint&)'),
|
|
||||||
self.on_context_menuChan)
|
self.on_context_menuChan)
|
||||||
|
|
||||||
def init_addressbook_popup_menu(self, connectSignal=True):
|
def init_addressbook_popup_menu(self, connectSignal=True):
|
||||||
# Popup menu for the Address Book page
|
# Popup menu for the Address Book page
|
||||||
self.ui.addressBookContextMenuToolbar = QtGui.QToolBar()
|
self.ui.addressBookContextMenuToolbar = QtWidgets.QToolBar()
|
||||||
# Actions
|
# Actions
|
||||||
self.actionAddressBookSend = self.ui.addressBookContextMenuToolbar.addAction(
|
self.actionAddressBookSend = self.ui.addressBookContextMenuToolbar.addAction(
|
||||||
_translate(
|
_translate(
|
||||||
|
@ -369,8 +364,7 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
self.ui.tableWidgetAddressBook.setContextMenuPolicy(
|
self.ui.tableWidgetAddressBook.setContextMenuPolicy(
|
||||||
QtCore.Qt.CustomContextMenu)
|
QtCore.Qt.CustomContextMenu)
|
||||||
if connectSignal:
|
if connectSignal:
|
||||||
self.connect(self.ui.tableWidgetAddressBook, QtCore.SIGNAL(
|
self.ui.tableWidgetAddressBook.customContextMenuRequested.connect(
|
||||||
'customContextMenuRequested(const QPoint&)'),
|
|
||||||
self.on_context_menuAddressBook)
|
self.on_context_menuAddressBook)
|
||||||
|
|
||||||
def init_subscriptions_popup_menu(self, connectSignal=True):
|
def init_subscriptions_popup_menu(self, connectSignal=True):
|
||||||
|
@ -398,8 +392,7 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
self.ui.treeWidgetSubscriptions.setContextMenuPolicy(
|
self.ui.treeWidgetSubscriptions.setContextMenuPolicy(
|
||||||
QtCore.Qt.CustomContextMenu)
|
QtCore.Qt.CustomContextMenu)
|
||||||
if connectSignal:
|
if connectSignal:
|
||||||
self.connect(self.ui.treeWidgetSubscriptions, QtCore.SIGNAL(
|
self.ui.treeWidgetSubscriptions.customContextMenuRequested.connect(
|
||||||
'customContextMenuRequested(const QPoint&)'),
|
|
||||||
self.on_context_menuSubscriptions)
|
self.on_context_menuSubscriptions)
|
||||||
|
|
||||||
def init_sent_popup_menu(self, connectSignal=True):
|
def init_sent_popup_menu(self, connectSignal=True):
|
||||||
|
@ -417,14 +410,14 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
self.actionSentReply = self.ui.sentContextMenuToolbar.addAction(
|
self.actionSentReply = self.ui.sentContextMenuToolbar.addAction(
|
||||||
_translate("MainWindow", "Send update"),
|
_translate("MainWindow", "Send update"),
|
||||||
self.on_action_SentReply)
|
self.on_action_SentReply)
|
||||||
# self.popMenuSent = QtGui.QMenu( self )
|
# self.popMenuSent = QtWidgets.QMenu( self )
|
||||||
# self.popMenuSent.addAction( self.actionSentClipboard )
|
# self.popMenuSent.addAction( self.actionSentClipboard )
|
||||||
# self.popMenuSent.addAction( self.actionTrashSentMessage )
|
# self.popMenuSent.addAction( self.actionTrashSentMessage )
|
||||||
|
|
||||||
def rerenderTabTreeSubscriptions(self):
|
def rerenderTabTreeSubscriptions(self):
|
||||||
treeWidget = self.ui.treeWidgetSubscriptions
|
treeWidget = self.ui.treeWidgetSubscriptions
|
||||||
folders = Ui_FolderWidget.folderWeight.keys()
|
folders = Ui_FolderWidget.folderWeight.keys()
|
||||||
folders.remove("new")
|
Ui_FolderWidget.folderWeight.pop("new", None)
|
||||||
|
|
||||||
# sort ascending when creating
|
# sort ascending when creating
|
||||||
if treeWidget.topLevelItemCount() == 0:
|
if treeWidget.topLevelItemCount() == 0:
|
||||||
|
@ -441,7 +434,6 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
if treeWidget.isSortingEnabled():
|
if treeWidget.isSortingEnabled():
|
||||||
treeWidget.setSortingEnabled(False)
|
treeWidget.setSortingEnabled(False)
|
||||||
|
|
||||||
widgets = {}
|
|
||||||
i = 0
|
i = 0
|
||||||
while i < treeWidget.topLevelItemCount():
|
while i < treeWidget.topLevelItemCount():
|
||||||
widget = treeWidget.topLevelItem(i)
|
widget = treeWidget.topLevelItem(i)
|
||||||
|
@ -459,7 +451,8 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
while j < widget.childCount():
|
while j < widget.childCount():
|
||||||
subwidget = widget.child(j)
|
subwidget = widget.child(j)
|
||||||
try:
|
try:
|
||||||
subwidget.setUnreadCount(db[toAddress][subwidget.folderName]['count'])
|
subwidget.setUnreadCount(
|
||||||
|
db[toAddress][subwidget.folderName]['count'])
|
||||||
unread += db[toAddress][subwidget.folderName]['count']
|
unread += db[toAddress][subwidget.folderName]['count']
|
||||||
db[toAddress].pop(subwidget.folderName, None)
|
db[toAddress].pop(subwidget.folderName, None)
|
||||||
except:
|
except:
|
||||||
|
@ -471,9 +464,10 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
# add missing folders
|
# add missing folders
|
||||||
if len(db[toAddress]) > 0:
|
if len(db[toAddress]) > 0:
|
||||||
j = 0
|
j = 0
|
||||||
for f, c in db[toAddress].iteritems():
|
for f, c in six.iteritems(db[toAddress]):
|
||||||
try:
|
try:
|
||||||
subwidget = Ui_FolderWidget(widget, j, toAddress, f, c['count'])
|
subwidget = Ui_FolderWidget(
|
||||||
|
widget, j, toAddress, f, c['count'])
|
||||||
except KeyError:
|
except KeyError:
|
||||||
subwidget = Ui_FolderWidget(widget, j, toAddress, f, 0)
|
subwidget = Ui_FolderWidget(widget, j, toAddress, f, 0)
|
||||||
j += 1
|
j += 1
|
||||||
|
@ -484,20 +478,20 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
i = 0
|
i = 0
|
||||||
for toAddress in db:
|
for toAddress in db:
|
||||||
widget = Ui_SubscriptionWidget(
|
widget = Ui_SubscriptionWidget(
|
||||||
treeWidget,
|
treeWidget, i, toAddress, db[toAddress]["inbox"]['count'],
|
||||||
i,
|
|
||||||
toAddress,
|
|
||||||
db[toAddress]["inbox"]['count'],
|
|
||||||
db[toAddress]["inbox"]['label'],
|
db[toAddress]["inbox"]['label'],
|
||||||
db[toAddress]["inbox"]['enabled'])
|
db[toAddress]["inbox"]['enabled'])
|
||||||
j = 0
|
j = 0
|
||||||
unread = 0
|
unread = 0
|
||||||
for folder in folders:
|
for folder in folders:
|
||||||
try:
|
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']
|
unread += db[toAddress][folder]['count']
|
||||||
except KeyError:
|
except KeyError:
|
||||||
subwidget = Ui_FolderWidget(widget, j, toAddress, folder, 0)
|
subwidget = Ui_FolderWidget(
|
||||||
|
widget, j, toAddress, folder, 0)
|
||||||
j += 1
|
j += 1
|
||||||
widget.setUnreadCount(unread)
|
widget.setUnreadCount(unread)
|
||||||
i += 1
|
i += 1
|
||||||
|
@ -530,8 +524,8 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
toAddress, 'enabled')
|
toAddress, 'enabled')
|
||||||
isChan = config.safeGetBoolean(
|
isChan = config.safeGetBoolean(
|
||||||
toAddress, 'chan')
|
toAddress, 'chan')
|
||||||
isMaillinglist = config.safeGetBoolean(
|
# isMaillinglist = config.safeGetBoolean(
|
||||||
toAddress, 'mailinglist')
|
# toAddress, 'mailinglist')
|
||||||
|
|
||||||
if treeWidget == self.ui.treeWidgetYourIdentities:
|
if treeWidget == self.ui.treeWidgetYourIdentities:
|
||||||
if isChan:
|
if isChan:
|
||||||
|
@ -555,6 +549,8 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
"GROUP BY toaddress, folder")
|
"GROUP BY toaddress, folder")
|
||||||
for row in queryreturn:
|
for row in queryreturn:
|
||||||
toaddress, folder, cnt = row
|
toaddress, folder, cnt = row
|
||||||
|
toaddress = toaddress.decode("utf-8", "replace")
|
||||||
|
folder = folder.decode("utf-8", "replace")
|
||||||
total += cnt
|
total += cnt
|
||||||
if toaddress in db and folder in db[toaddress]:
|
if toaddress in db and folder in db[toaddress]:
|
||||||
db[toaddress][folder] = cnt
|
db[toaddress][folder] = cnt
|
||||||
|
@ -569,7 +565,6 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
if treeWidget.isSortingEnabled():
|
if treeWidget.isSortingEnabled():
|
||||||
treeWidget.setSortingEnabled(False)
|
treeWidget.setSortingEnabled(False)
|
||||||
|
|
||||||
widgets = {}
|
|
||||||
i = 0
|
i = 0
|
||||||
while i < treeWidget.topLevelItemCount():
|
while i < treeWidget.topLevelItemCount():
|
||||||
widget = treeWidget.topLevelItem(i)
|
widget = treeWidget.topLevelItem(i)
|
||||||
|
@ -601,7 +596,7 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
# add missing folders
|
# add missing folders
|
||||||
if len(db[toAddress]) > 0:
|
if len(db[toAddress]) > 0:
|
||||||
j = 0
|
j = 0
|
||||||
for f, c in db[toAddress].iteritems():
|
for f, c in six.iteritems(db[toAddress]):
|
||||||
if toAddress is not None and tab == 'messages' and folder == "new":
|
if toAddress is not None and tab == 'messages' and folder == "new":
|
||||||
continue
|
continue
|
||||||
subwidget = Ui_FolderWidget(widget, j, toAddress, f, c)
|
subwidget = Ui_FolderWidget(widget, j, toAddress, f, c)
|
||||||
|
@ -630,7 +625,7 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
treeWidget.setSortingEnabled(True)
|
treeWidget.setSortingEnabled(True)
|
||||||
|
|
||||||
def __init__(self, parent=None):
|
def __init__(self, parent=None):
|
||||||
QtGui.QWidget.__init__(self, parent)
|
super(MyForm, self).__init__(parent)
|
||||||
self.ui = Ui_MainWindow()
|
self.ui = Ui_MainWindow()
|
||||||
self.ui.setupUi(self)
|
self.ui.setupUi(self)
|
||||||
|
|
||||||
|
@ -649,12 +644,12 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
if addressVersionNumber == 1:
|
if addressVersionNumber == 1:
|
||||||
displayMsg = _translate(
|
displayMsg = _translate(
|
||||||
"MainWindow",
|
"MainWindow",
|
||||||
"One of your addresses, %1, is an old version 1 address. "
|
"One of your addresses, {0}, is an old version 1"
|
||||||
"Version 1 addresses are no longer supported. "
|
" address. Version 1 addresses are no longer supported."
|
||||||
"May we delete it now?").arg(addressInKeysFile)
|
" May we delete it now?").format(addressInKeysFile)
|
||||||
reply = QtGui.QMessageBox.question(
|
reply = QtWidgets.QMessageBox.question(
|
||||||
self, 'Message', displayMsg, QtGui.QMessageBox.Yes, QtGui.QMessageBox.No)
|
self, 'Message', displayMsg, QtWidgets.QMessageBox.Yes, QtWidgets.QMessageBox.No)
|
||||||
if reply == QtGui.QMessageBox.Yes:
|
if reply == QtWidgets.QMessageBox.Yes:
|
||||||
config.remove_section(addressInKeysFile)
|
config.remove_section(addressInKeysFile)
|
||||||
config.save()
|
config.save()
|
||||||
|
|
||||||
|
@ -698,111 +693,97 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
self.rerenderSubscriptions()
|
self.rerenderSubscriptions()
|
||||||
|
|
||||||
# Initialize the inbox search
|
# Initialize the inbox search
|
||||||
QtCore.QObject.connect(self.ui.inboxSearchLineEdit, QtCore.SIGNAL(
|
for line_edit in (
|
||||||
"returnPressed()"), self.inboxSearchLineEditReturnPressed)
|
self.ui.inboxSearchLineEdit,
|
||||||
QtCore.QObject.connect(self.ui.inboxSearchLineEditSubscriptions, QtCore.SIGNAL(
|
self.ui.inboxSearchLineEditSubscriptions,
|
||||||
"returnPressed()"), self.inboxSearchLineEditReturnPressed)
|
self.ui.inboxSearchLineEditChans,
|
||||||
QtCore.QObject.connect(self.ui.inboxSearchLineEditChans, QtCore.SIGNAL(
|
):
|
||||||
"returnPressed()"), self.inboxSearchLineEditReturnPressed)
|
line_edit.returnPressed.connect(
|
||||||
QtCore.QObject.connect(self.ui.inboxSearchLineEdit, QtCore.SIGNAL(
|
self.inboxSearchLineEditReturnPressed)
|
||||||
"textChanged(QString)"), self.inboxSearchLineEditUpdated)
|
line_edit.textChanged.connect(
|
||||||
QtCore.QObject.connect(self.ui.inboxSearchLineEditSubscriptions, QtCore.SIGNAL(
|
self.inboxSearchLineEditUpdated)
|
||||||
"textChanged(QString)"), self.inboxSearchLineEditUpdated)
|
|
||||||
QtCore.QObject.connect(self.ui.inboxSearchLineEditChans, QtCore.SIGNAL(
|
|
||||||
"textChanged(QString)"), self.inboxSearchLineEditUpdated)
|
|
||||||
|
|
||||||
# Initialize addressbook
|
# Initialize addressbook
|
||||||
QtCore.QObject.connect(self.ui.tableWidgetAddressBook, QtCore.SIGNAL(
|
self.ui.tableWidgetAddressBook.itemChanged.connect(
|
||||||
"itemChanged(QTableWidgetItem *)"), self.tableWidgetAddressBookItemChanged)
|
self.tableWidgetAddressBookItemChanged)
|
||||||
|
|
||||||
# This is necessary for the completer to work if multiple recipients
|
# This is necessary for the completer to work if multiple recipients
|
||||||
QtCore.QObject.connect(self.ui.lineEditTo, QtCore.SIGNAL(
|
self.ui.lineEditTo.cursorPositionChanged.connect(
|
||||||
"cursorPositionChanged(int, int)"), self.ui.lineEditTo.completer().onCursorPositionChanged)
|
self.ui.lineEditTo.completer().onCursorPositionChanged)
|
||||||
|
|
||||||
# show messages from message list
|
# show messages from message list
|
||||||
QtCore.QObject.connect(self.ui.tableWidgetInbox, QtCore.SIGNAL(
|
for table_widget in (
|
||||||
"itemSelectionChanged ()"), self.tableWidgetInboxItemClicked)
|
self.ui.tableWidgetInbox,
|
||||||
QtCore.QObject.connect(self.ui.tableWidgetInboxSubscriptions, QtCore.SIGNAL(
|
self.ui.tableWidgetInboxSubscriptions,
|
||||||
"itemSelectionChanged ()"), self.tableWidgetInboxItemClicked)
|
self.ui.tableWidgetInboxChans
|
||||||
QtCore.QObject.connect(self.ui.tableWidgetInboxChans, QtCore.SIGNAL(
|
):
|
||||||
"itemSelectionChanged ()"), self.tableWidgetInboxItemClicked)
|
table_widget.itemSelectionChanged.connect(
|
||||||
|
self.tableWidgetInboxItemClicked)
|
||||||
|
|
||||||
# tree address lists
|
# tree address lists
|
||||||
QtCore.QObject.connect(self.ui.treeWidgetYourIdentities, QtCore.SIGNAL(
|
for tree_widget in (
|
||||||
"itemSelectionChanged ()"), self.treeWidgetItemClicked)
|
self.ui.treeWidgetYourIdentities,
|
||||||
QtCore.QObject.connect(self.ui.treeWidgetYourIdentities, QtCore.SIGNAL(
|
self.ui.treeWidgetSubscriptions,
|
||||||
"itemChanged (QTreeWidgetItem *, int)"), self.treeWidgetItemChanged)
|
self.ui.treeWidgetChans
|
||||||
QtCore.QObject.connect(self.ui.treeWidgetSubscriptions, QtCore.SIGNAL(
|
):
|
||||||
"itemSelectionChanged ()"), self.treeWidgetItemClicked)
|
tree_widget.itemSelectionChanged.connect(
|
||||||
QtCore.QObject.connect(self.ui.treeWidgetSubscriptions, QtCore.SIGNAL(
|
self.treeWidgetItemClicked)
|
||||||
"itemChanged (QTreeWidgetItem *, int)"), self.treeWidgetItemChanged)
|
tree_widget.itemChanged.connect(self.treeWidgetItemChanged)
|
||||||
QtCore.QObject.connect(self.ui.treeWidgetChans, QtCore.SIGNAL(
|
|
||||||
"itemSelectionChanged ()"), self.treeWidgetItemClicked)
|
self.ui.tabWidget.currentChanged.connect(self.tabWidgetCurrentChanged)
|
||||||
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
|
|
||||||
)
|
|
||||||
|
|
||||||
# Put the colored icon on the status bar
|
# Put the colored icon on the status bar
|
||||||
# self.pushButtonStatusIcon.setIcon(QIcon(":/newPrefix/images/yellowicon.png"))
|
# self.pushButtonStatusIcon.setIcon(QIcon(":/newPrefix/images/yellowicon.png"))
|
||||||
self.setStatusBar(BMStatusBar())
|
self.setStatusBar(BMStatusBar())
|
||||||
self.statusbar = self.statusBar()
|
self.statusbar = self.statusBar()
|
||||||
|
|
||||||
self.pushButtonStatusIcon = QtGui.QPushButton(self)
|
self.pushButtonStatusIcon = QtWidgets.QPushButton(self)
|
||||||
self.pushButtonStatusIcon.setText('')
|
self.pushButtonStatusIcon.setText('')
|
||||||
self.pushButtonStatusIcon.setIcon(
|
self.pushButtonStatusIcon.setIcon(
|
||||||
QtGui.QIcon(':/newPrefix/images/redicon.png'))
|
QtGui.QIcon(':/newPrefix/images/redicon.png'))
|
||||||
self.pushButtonStatusIcon.setFlat(True)
|
self.pushButtonStatusIcon.setFlat(True)
|
||||||
self.statusbar.insertPermanentWidget(0, self.pushButtonStatusIcon)
|
self.statusbar.insertPermanentWidget(0, self.pushButtonStatusIcon)
|
||||||
QtCore.QObject.connect(self.pushButtonStatusIcon, QtCore.SIGNAL(
|
self.pushButtonStatusIcon.clicked.connect(
|
||||||
"clicked()"), self.click_pushButtonStatusIcon)
|
self.click_pushButtonStatusIcon)
|
||||||
|
|
||||||
self.unreadCount = 0
|
self.unreadCount = 0
|
||||||
|
|
||||||
# Set the icon sizes for the identicons
|
# Set the icon sizes for the identicons
|
||||||
identicon_size = 3 * 7
|
identicon_size = 3 * 7
|
||||||
self.ui.tableWidgetInbox.setIconSize(QtCore.QSize(identicon_size, identicon_size))
|
for widget in (
|
||||||
self.ui.treeWidgetChans.setIconSize(QtCore.QSize(identicon_size, identicon_size))
|
self.ui.tableWidgetInbox, self.ui.treeWidgetChans,
|
||||||
self.ui.treeWidgetYourIdentities.setIconSize(QtCore.QSize(identicon_size, identicon_size))
|
self.ui.treeWidgetYourIdentities, self.ui.treeWidgetSubscriptions,
|
||||||
self.ui.treeWidgetSubscriptions.setIconSize(QtCore.QSize(identicon_size, identicon_size))
|
self.ui.tableWidgetAddressBook
|
||||||
self.ui.tableWidgetAddressBook.setIconSize(QtCore.QSize(identicon_size, identicon_size))
|
):
|
||||||
|
widget.setIconSize(QtCore.QSize(identicon_size, identicon_size))
|
||||||
|
|
||||||
self.UISignalThread = UISignaler.get()
|
self.UISignalThread = UISignaler.get()
|
||||||
|
self.UISignalThread.writeNewAddressToTable.connect(
|
||||||
QtCore.QObject.connect(self.UISignalThread, QtCore.SIGNAL(
|
self.writeNewAddressToTable)
|
||||||
"writeNewAddressToTable(PyQt_PyObject,PyQt_PyObject,PyQt_PyObject)"), self.writeNewAddressToTable)
|
self.UISignalThread.updateStatusBar.connect(self.updateStatusBar)
|
||||||
QtCore.QObject.connect(self.UISignalThread, QtCore.SIGNAL(
|
self.UISignalThread.updateSentItemStatusByToAddress.connect(
|
||||||
"updateStatusBar(PyQt_PyObject)"), self.updateStatusBar)
|
self.updateSentItemStatusByToAddress)
|
||||||
QtCore.QObject.connect(self.UISignalThread, QtCore.SIGNAL(
|
self.UISignalThread.updateSentItemStatusByAckdata.connect(
|
||||||
"updateSentItemStatusByToAddress(PyQt_PyObject,PyQt_PyObject)"), self.updateSentItemStatusByToAddress)
|
self.updateSentItemStatusByAckdata)
|
||||||
QtCore.QObject.connect(self.UISignalThread, QtCore.SIGNAL(
|
self.UISignalThread.displayNewInboxMessage.connect(
|
||||||
"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.displayNewInboxMessage)
|
self.displayNewInboxMessage)
|
||||||
QtCore.QObject.connect(self.UISignalThread, QtCore.SIGNAL(
|
self.UISignalThread.displayNewSentMessage.connect(
|
||||||
"displayNewSentMessage(PyQt_PyObject,PyQt_PyObject,PyQt_PyObject,PyQt_PyObject,"
|
|
||||||
"PyQt_PyObject,PyQt_PyObject)"),
|
|
||||||
self.displayNewSentMessage)
|
self.displayNewSentMessage)
|
||||||
QtCore.QObject.connect(self.UISignalThread, QtCore.SIGNAL(
|
self.UISignalThread.setStatusIcon.connect(self.setStatusIcon)
|
||||||
"setStatusIcon(PyQt_PyObject)"), self.setStatusIcon)
|
self.UISignalThread.changedInboxUnread.connect(self.changedInboxUnread)
|
||||||
QtCore.QObject.connect(self.UISignalThread, QtCore.SIGNAL(
|
self.UISignalThread.rerenderMessagelistFromLabels.connect(
|
||||||
"changedInboxUnread(PyQt_PyObject)"), self.changedInboxUnread)
|
self.rerenderMessagelistFromLabels)
|
||||||
QtCore.QObject.connect(self.UISignalThread, QtCore.SIGNAL(
|
self.UISignalThread.rerenderMessagelistToLabels.connect(
|
||||||
"rerenderMessagelistFromLabels()"), self.rerenderMessagelistFromLabels)
|
self.rerenderMessagelistToLabels)
|
||||||
QtCore.QObject.connect(self.UISignalThread, QtCore.SIGNAL(
|
self.UISignalThread.rerenderAddressBook.connect(
|
||||||
"rerenderMessgelistToLabels()"), self.rerenderMessagelistToLabels)
|
self.rerenderAddressBook)
|
||||||
QtCore.QObject.connect(self.UISignalThread, QtCore.SIGNAL(
|
self.UISignalThread.rerenderSubscriptions.connect(
|
||||||
"rerenderAddressBook()"), self.rerenderAddressBook)
|
self.rerenderSubscriptions)
|
||||||
QtCore.QObject.connect(self.UISignalThread, QtCore.SIGNAL(
|
self.UISignalThread.removeInboxRowByMsgid.connect(
|
||||||
"rerenderSubscriptions()"), self.rerenderSubscriptions)
|
self.removeInboxRowByMsgid)
|
||||||
QtCore.QObject.connect(self.UISignalThread, QtCore.SIGNAL(
|
self.UISignalThread.newVersionAvailable.connect(
|
||||||
"removeInboxRowByMsgid(PyQt_PyObject)"), self.removeInboxRowByMsgid)
|
self.newVersionAvailable)
|
||||||
QtCore.QObject.connect(self.UISignalThread, QtCore.SIGNAL(
|
self.UISignalThread.displayAlert.connect(self.displayAlert)
|
||||||
"newVersionAvailable(PyQt_PyObject)"), self.newVersionAvailable)
|
|
||||||
QtCore.QObject.connect(self.UISignalThread, QtCore.SIGNAL(
|
|
||||||
"displayAlert(PyQt_PyObject,PyQt_PyObject,PyQt_PyObject)"), self.displayAlert)
|
|
||||||
self.UISignalThread.start()
|
self.UISignalThread.start()
|
||||||
|
|
||||||
# Key press in tree view
|
# Key press in tree view
|
||||||
|
@ -831,16 +812,15 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
|
|
||||||
# Put the TTL slider in the correct spot
|
# Put the TTL slider in the correct spot
|
||||||
TTL = config.getint('bitmessagesettings', 'ttl')
|
TTL = config.getint('bitmessagesettings', 'ttl')
|
||||||
if TTL < 3600: # an hour
|
if TTL < 3600: # an hour
|
||||||
TTL = 3600
|
TTL = 3600
|
||||||
elif TTL > 28*24*60*60: # 28 days
|
elif TTL > 28 * 24 * 60 * 60: # 28 days
|
||||||
TTL = 28*24*60*60
|
TTL = 28 * 24 * 60 * 60
|
||||||
self.ui.horizontalSliderTTL.setSliderPosition((TTL - 3600) ** (1/3.199))
|
self.ui.horizontalSliderTTL.setSliderPosition(
|
||||||
|
int((TTL - 3600) ** (1 / 3.199)))
|
||||||
self.updateHumanFriendlyTTLDescription(TTL)
|
self.updateHumanFriendlyTTLDescription(TTL)
|
||||||
|
|
||||||
QtCore.QObject.connect(self.ui.horizontalSliderTTL, QtCore.SIGNAL(
|
self.ui.horizontalSliderTTL.valueChanged.connect(self.updateTTL)
|
||||||
"valueChanged(int)"), self.updateTTL)
|
|
||||||
|
|
||||||
self.initSettings()
|
self.initSettings()
|
||||||
self.resetNamecoinConnection()
|
self.resetNamecoinConnection()
|
||||||
self.sqlInit()
|
self.sqlInit()
|
||||||
|
@ -895,27 +875,25 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
config.save()
|
config.save()
|
||||||
|
|
||||||
def updateHumanFriendlyTTLDescription(self, TTL):
|
def updateHumanFriendlyTTLDescription(self, TTL):
|
||||||
numberOfHours = int(round(TTL / (60*60)))
|
numberOfHours = int(round(TTL / (60 * 60)))
|
||||||
font = QtGui.QFont()
|
font = QtGui.QFont()
|
||||||
stylesheet = ""
|
stylesheet = ""
|
||||||
|
|
||||||
if numberOfHours < 48:
|
if numberOfHours < 48:
|
||||||
self.ui.labelHumanFriendlyTTLDescription.setText(
|
self.ui.labelHumanFriendlyTTLDescription.setText(
|
||||||
_translate("MainWindow", "%n hour(s)", None, QtCore.QCoreApplication.CodecForTr, numberOfHours) +
|
_translate(
|
||||||
", " +
|
"MainWindow", "%n hour(s)", None, numberOfHours
|
||||||
_translate("MainWindow", "not recommended for chans", None, QtCore.QCoreApplication.CodecForTr)
|
) + ",\n" +
|
||||||
)
|
_translate("MainWindow", "not recommended for chans")
|
||||||
|
)
|
||||||
stylesheet = "QLabel { color : red; }"
|
stylesheet = "QLabel { color : red; }"
|
||||||
font.setBold(True)
|
font.setBold(True)
|
||||||
else:
|
else:
|
||||||
numberOfDays = int(round(TTL / (24*60*60)))
|
numberOfDays = int(round(TTL / (24 * 60 * 60)))
|
||||||
self.ui.labelHumanFriendlyTTLDescription.setText(
|
self.ui.labelHumanFriendlyTTLDescription.setText(
|
||||||
_translate(
|
_translate(
|
||||||
"MainWindow",
|
"MainWindow", "%n day(s)", None, numberOfDays)
|
||||||
"%n day(s)",
|
)
|
||||||
None,
|
|
||||||
QtCore.QCoreApplication.CodecForTr,
|
|
||||||
numberOfDays))
|
|
||||||
font.setBold(False)
|
font.setBold(False)
|
||||||
self.ui.labelHumanFriendlyTTLDescription.setStyleSheet(stylesheet)
|
self.ui.labelHumanFriendlyTTLDescription.setStyleSheet(stylesheet)
|
||||||
self.ui.labelHumanFriendlyTTLDescription.setFont(font)
|
self.ui.labelHumanFriendlyTTLDescription.setFont(font)
|
||||||
|
@ -1026,7 +1004,7 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
# related = related.findItems(msgid, QtCore.Qt.MatchExactly),
|
# related = related.findItems(msgid, QtCore.Qt.MatchExactly),
|
||||||
# returns an empty list
|
# returns an empty list
|
||||||
for rrow in range(related.rowCount()):
|
for rrow in range(related.rowCount()):
|
||||||
if related.item(rrow, 3).data() == msgid:
|
if as_msgid(related.item(rrow, 3).data()) == msgid:
|
||||||
break
|
break
|
||||||
|
|
||||||
for col in range(widget.columnCount()):
|
for col in range(widget.columnCount()):
|
||||||
|
@ -1047,6 +1025,8 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
normalUnread = {}
|
normalUnread = {}
|
||||||
broadcastsUnread = {}
|
broadcastsUnread = {}
|
||||||
for addr, fld, count in queryReturn:
|
for addr, fld, count in queryReturn:
|
||||||
|
addr = addr.decode("utf-8", "replace")
|
||||||
|
fld = fld.decode("utf-8", "replace")
|
||||||
try:
|
try:
|
||||||
normalUnread[addr][fld] = count
|
normalUnread[addr][fld] = count
|
||||||
except KeyError:
|
except KeyError:
|
||||||
|
@ -1066,8 +1046,10 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
queryReturn = sqlQuery(
|
queryReturn = sqlQuery(
|
||||||
'SELECT fromaddress, folder, COUNT(msgid) AS cnt'
|
'SELECT fromaddress, folder, COUNT(msgid) AS cnt'
|
||||||
' FROM inbox WHERE read = 0 AND toaddress = ?'
|
' FROM inbox WHERE read = 0 AND toaddress = ?'
|
||||||
' GROUP BY fromaddress, folder', str_broadcast_subscribers)
|
' GROUP BY fromaddress, folder', dbstr(str_broadcast_subscribers))
|
||||||
for addr, fld, count in queryReturn:
|
for addr, fld, count in queryReturn:
|
||||||
|
addr = addr.decode("utf-8", "replace")
|
||||||
|
fld = fld.decode("utf-8", "replace")
|
||||||
try:
|
try:
|
||||||
broadcastsUnread[addr][fld] = count
|
broadcastsUnread[addr][fld] = count
|
||||||
except KeyError:
|
except KeyError:
|
||||||
|
@ -1078,15 +1060,15 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
for i in range(root.childCount()):
|
for i in range(root.childCount()):
|
||||||
addressItem = root.child(i)
|
addressItem = root.child(i)
|
||||||
if addressItem.type == AccountMixin.ALL:
|
if addressItem.type == AccountMixin.ALL:
|
||||||
newCount = sum(totalUnread.itervalues())
|
newCount = sum(six.itervalues(totalUnread))
|
||||||
self.drawTrayIcon(self.currentTrayIconFileName, newCount)
|
self.drawTrayIcon(self.currentTrayIconFileName, newCount)
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
newCount = sum((
|
newCount = sum(six.itervalues((
|
||||||
broadcastsUnread
|
broadcastsUnread
|
||||||
if addressItem.type == AccountMixin.SUBSCRIPTION
|
if addressItem.type == AccountMixin.SUBSCRIPTION
|
||||||
else normalUnread
|
else normalUnread
|
||||||
)[addressItem.address].itervalues())
|
)[addressItem.address]))
|
||||||
except KeyError:
|
except KeyError:
|
||||||
newCount = 0
|
newCount = 0
|
||||||
if newCount != addressItem.unreadCount:
|
if newCount != addressItem.unreadCount:
|
||||||
|
@ -1143,20 +1125,19 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
elif status == 'msgsent':
|
elif status == 'msgsent':
|
||||||
statusText = _translate(
|
statusText = _translate(
|
||||||
"MainWindow",
|
"MainWindow",
|
||||||
"Message sent. Waiting for acknowledgement. Sent at %1"
|
"Message sent. Waiting for acknowledgement. Sent at {0}"
|
||||||
).arg(l10n.formatTimestamp(lastactiontime))
|
).format(l10n.formatTimestamp(lastactiontime))
|
||||||
elif status == 'msgsentnoackexpected':
|
elif status == 'msgsentnoackexpected':
|
||||||
statusText = _translate(
|
statusText = _translate(
|
||||||
"MainWindow", "Message sent. Sent at %1"
|
"MainWindow", "Message sent. Sent at {0}"
|
||||||
).arg(l10n.formatTimestamp(lastactiontime))
|
).format(l10n.formatTimestamp(lastactiontime))
|
||||||
elif status == 'doingmsgpow':
|
elif status == 'doingmsgpow':
|
||||||
statusText = _translate(
|
statusText = _translate(
|
||||||
"MainWindow", "Doing work necessary to send message.")
|
"MainWindow", "Doing work necessary to send message.")
|
||||||
elif status == 'ackreceived':
|
elif status == 'ackreceived':
|
||||||
statusText = _translate(
|
statusText = _translate(
|
||||||
"MainWindow",
|
"MainWindow", "Acknowledgement of the message received {0}"
|
||||||
"Acknowledgement of the message received %1"
|
).format(l10n.formatTimestamp(lastactiontime))
|
||||||
).arg(l10n.formatTimestamp(lastactiontime))
|
|
||||||
elif status == 'broadcastqueued':
|
elif status == 'broadcastqueued':
|
||||||
statusText = _translate(
|
statusText = _translate(
|
||||||
"MainWindow", "Broadcast queued.")
|
"MainWindow", "Broadcast queued.")
|
||||||
|
@ -1164,36 +1145,36 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
statusText = _translate(
|
statusText = _translate(
|
||||||
"MainWindow", "Doing work necessary to send broadcast.")
|
"MainWindow", "Doing work necessary to send broadcast.")
|
||||||
elif status == 'broadcastsent':
|
elif status == 'broadcastsent':
|
||||||
statusText = _translate("MainWindow", "Broadcast on %1").arg(
|
statusText = _translate("MainWindow", "Broadcast on {0}").format(
|
||||||
l10n.formatTimestamp(lastactiontime))
|
l10n.formatTimestamp(lastactiontime))
|
||||||
elif status == 'toodifficult':
|
elif status == 'toodifficult':
|
||||||
statusText = _translate(
|
statusText = _translate(
|
||||||
"MainWindow",
|
"MainWindow",
|
||||||
"Problem: The work demanded by the recipient is more"
|
"Problem: The work demanded by the recipient is more"
|
||||||
" difficult than you are willing to do. %1"
|
" difficult than you are willing to do. {0}"
|
||||||
).arg(l10n.formatTimestamp(lastactiontime))
|
).format(l10n.formatTimestamp(lastactiontime))
|
||||||
elif status == 'badkey':
|
elif status == 'badkey':
|
||||||
statusText = _translate(
|
statusText = _translate(
|
||||||
"MainWindow",
|
"MainWindow",
|
||||||
"Problem: The recipient\'s encryption key is no good."
|
"Problem: The recipient\'s encryption key is no good."
|
||||||
" Could not encrypt message. %1"
|
" Could not encrypt message. {0}"
|
||||||
).arg(l10n.formatTimestamp(lastactiontime))
|
).format(l10n.formatTimestamp(lastactiontime))
|
||||||
elif status == 'forcepow':
|
elif status == 'forcepow':
|
||||||
statusText = _translate(
|
statusText = _translate(
|
||||||
"MainWindow",
|
"MainWindow",
|
||||||
"Forced difficulty override. Send should start soon.")
|
"Forced difficulty override. Send should start soon.")
|
||||||
else:
|
else:
|
||||||
statusText = _translate(
|
statusText = _translate(
|
||||||
"MainWindow", "Unknown status: %1 %2").arg(status).arg(
|
"MainWindow", "Unknown status: {0} {1}").format(status,
|
||||||
l10n.formatTimestamp(lastactiontime))
|
l10n.formatTimestamp(lastactiontime))
|
||||||
|
|
||||||
items = [
|
items = [
|
||||||
MessageList_AddressWidget(
|
MessageList_AddressWidget(
|
||||||
toAddress, unicode(acct.toLabel, 'utf-8')),
|
toAddress, unic(ustr(acct.toLabel))),
|
||||||
MessageList_AddressWidget(
|
MessageList_AddressWidget(
|
||||||
fromAddress, unicode(acct.fromLabel, 'utf-8')),
|
fromAddress, unic(ustr(acct.fromLabel))),
|
||||||
MessageList_SubjectWidget(
|
MessageList_SubjectWidget(
|
||||||
str(subject), unicode(acct.subject, 'utf-8', 'replace')),
|
ustr(subject), unic(ustr(acct.subject))),
|
||||||
MessageList_TimeWidget(
|
MessageList_TimeWidget(
|
||||||
statusText, False, lastactiontime, ackdata)]
|
statusText, False, lastactiontime, ackdata)]
|
||||||
self.addMessageListItem(tableWidget, items)
|
self.addMessageListItem(tableWidget, items)
|
||||||
|
@ -1214,11 +1195,11 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
|
|
||||||
items = [
|
items = [
|
||||||
MessageList_AddressWidget(
|
MessageList_AddressWidget(
|
||||||
toAddress, unicode(acct.toLabel, 'utf-8'), not read),
|
toAddress, unic(ustr(acct.toLabel)), not read),
|
||||||
MessageList_AddressWidget(
|
MessageList_AddressWidget(
|
||||||
fromAddress, unicode(acct.fromLabel, 'utf-8'), not read),
|
fromAddress, unic(ustr(acct.fromLabel)), not read),
|
||||||
MessageList_SubjectWidget(
|
MessageList_SubjectWidget(
|
||||||
str(subject), unicode(acct.subject, 'utf-8', 'replace'),
|
ustr(subject), unic(ustr(acct.subject)),
|
||||||
not read),
|
not read),
|
||||||
MessageList_TimeWidget(
|
MessageList_TimeWidget(
|
||||||
l10n.formatTimestamp(received), not read, received, msgid)
|
l10n.formatTimestamp(received), not read, received, msgid)
|
||||||
|
@ -1246,7 +1227,14 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
xAddress, account, "sent", where, what, False)
|
xAddress, account, "sent", where, what, False)
|
||||||
|
|
||||||
for row in queryreturn:
|
for row in queryreturn:
|
||||||
self.addMessageListItemSent(tableWidget, *row)
|
r = []
|
||||||
|
r.append(row[0].decode("utf-8", "replace")) # toaddress
|
||||||
|
r.append(row[1].decode("utf-8", "replace")) # fromaddress
|
||||||
|
r.append(row[2].decode("utf-8", "replace")) # subject
|
||||||
|
r.append(row[3].decode("utf-8", "replace")) # status
|
||||||
|
r.append(row[4]) # ackdata
|
||||||
|
r.append(row[5]) # lastactiontime
|
||||||
|
self.addMessageListItemSent(tableWidget, *r)
|
||||||
|
|
||||||
tableWidget.horizontalHeader().setSortIndicator(
|
tableWidget.horizontalHeader().setSortIndicator(
|
||||||
3, QtCore.Qt.DescendingOrder)
|
3, QtCore.Qt.DescendingOrder)
|
||||||
|
@ -1287,6 +1275,10 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
|
|
||||||
for row in queryreturn:
|
for row in queryreturn:
|
||||||
toAddress, fromAddress, subject, _, msgid, received, read = row
|
toAddress, fromAddress, subject, _, msgid, received, read = row
|
||||||
|
toAddress = toAddress.decode("utf-8", "replace")
|
||||||
|
fromAddress = fromAddress.decode("utf-8", "replace")
|
||||||
|
subject = subject.decode("utf-8", "replace")
|
||||||
|
received = received.decode("utf-8", "replace")
|
||||||
self.addMessageListItemInbox(
|
self.addMessageListItemInbox(
|
||||||
tableWidget, toAddress, fromAddress, subject,
|
tableWidget, toAddress, fromAddress, subject,
|
||||||
msgid, received, read)
|
msgid, received, read)
|
||||||
|
@ -1302,23 +1294,21 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
# create application indicator
|
# create application indicator
|
||||||
def appIndicatorInit(self, app):
|
def appIndicatorInit(self, app):
|
||||||
self.initTrayIcon("can-icon-24px-red.png", app)
|
self.initTrayIcon("can-icon-24px-red.png", app)
|
||||||
traySignal = "activated(QSystemTrayIcon::ActivationReason)"
|
self.tray.activated.connect(self.__icon_activated)
|
||||||
QtCore.QObject.connect(self.tray, QtCore.SIGNAL(
|
|
||||||
traySignal), 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)
|
"MainWindow", "Not Connected"), m, checkable=False)
|
||||||
m.addAction(self.actionStatus)
|
m.addAction(self.actionStatus)
|
||||||
|
|
||||||
# separator
|
# separator
|
||||||
actionSeparator = QtGui.QAction('', m, checkable=False)
|
actionSeparator = QtWidgets.QAction('', m, checkable=False)
|
||||||
actionSeparator.setSeparator(True)
|
actionSeparator.setSeparator(True)
|
||||||
m.addAction(actionSeparator)
|
m.addAction(actionSeparator)
|
||||||
|
|
||||||
# show bitmessage
|
# show bitmessage
|
||||||
self.actionShow = QtGui.QAction(_translate(
|
self.actionShow = QtWidgets.QAction(_translate(
|
||||||
"MainWindow", "Show Bitmessage"), m, checkable=True)
|
"MainWindow", "Show Bitmessage"), m, checkable=True)
|
||||||
self.actionShow.setChecked(not config.getboolean(
|
self.actionShow.setChecked(not config.getboolean(
|
||||||
'bitmessagesettings', 'startintray'))
|
'bitmessagesettings', 'startintray'))
|
||||||
|
@ -1327,7 +1317,7 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
m.addAction(self.actionShow)
|
m.addAction(self.actionShow)
|
||||||
|
|
||||||
# quiet mode
|
# quiet mode
|
||||||
self.actionQuiet = QtGui.QAction(_translate(
|
self.actionQuiet = QtWidgets.QAction(_translate(
|
||||||
"MainWindow", "Quiet Mode"), m, checkable=True)
|
"MainWindow", "Quiet Mode"), m, checkable=True)
|
||||||
self.actionQuiet.setChecked(not config.getboolean(
|
self.actionQuiet.setChecked(not config.getboolean(
|
||||||
'bitmessagesettings', 'showtraynotifications'))
|
'bitmessagesettings', 'showtraynotifications'))
|
||||||
|
@ -1335,25 +1325,25 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
m.addAction(self.actionQuiet)
|
m.addAction(self.actionQuiet)
|
||||||
|
|
||||||
# Send
|
# Send
|
||||||
actionSend = QtGui.QAction(_translate(
|
actionSend = QtWidgets.QAction(_translate(
|
||||||
"MainWindow", "Send"), m, checkable=False)
|
"MainWindow", "Send"), m, checkable=False)
|
||||||
actionSend.triggered.connect(self.appIndicatorSend)
|
actionSend.triggered.connect(self.appIndicatorSend)
|
||||||
m.addAction(actionSend)
|
m.addAction(actionSend)
|
||||||
|
|
||||||
# Subscribe
|
# Subscribe
|
||||||
actionSubscribe = QtGui.QAction(_translate(
|
actionSubscribe = QtWidgets.QAction(_translate(
|
||||||
"MainWindow", "Subscribe"), m, checkable=False)
|
"MainWindow", "Subscribe"), m, checkable=False)
|
||||||
actionSubscribe.triggered.connect(self.appIndicatorSubscribe)
|
actionSubscribe.triggered.connect(self.appIndicatorSubscribe)
|
||||||
m.addAction(actionSubscribe)
|
m.addAction(actionSubscribe)
|
||||||
|
|
||||||
# Channels
|
# Channels
|
||||||
actionSubscribe = QtGui.QAction(_translate(
|
actionSubscribe = QtWidgets.QAction(_translate(
|
||||||
"MainWindow", "Channel"), m, checkable=False)
|
"MainWindow", "Channel"), m, checkable=False)
|
||||||
actionSubscribe.triggered.connect(self.appIndicatorChannel)
|
actionSubscribe.triggered.connect(self.appIndicatorChannel)
|
||||||
m.addAction(actionSubscribe)
|
m.addAction(actionSubscribe)
|
||||||
|
|
||||||
# separator
|
# separator
|
||||||
actionSeparator = QtGui.QAction('', m, checkable=False)
|
actionSeparator = QtWidgets.QAction('', m, checkable=False)
|
||||||
actionSeparator.setSeparator(True)
|
actionSeparator.setSeparator(True)
|
||||||
m.addAction(actionSeparator)
|
m.addAction(actionSeparator)
|
||||||
|
|
||||||
|
@ -1372,6 +1362,7 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
SELECT msgid, toaddress, read FROM inbox where folder='inbox'
|
SELECT msgid, toaddress, read FROM inbox where folder='inbox'
|
||||||
''')
|
''')
|
||||||
for msgid, toAddress, read in queryreturn:
|
for msgid, toAddress, read in queryreturn:
|
||||||
|
toAddress = toAddress.decode("utf-8", "replace")
|
||||||
|
|
||||||
if not read:
|
if not read:
|
||||||
# increment the unread subscriptions if True (1)
|
# increment the unread subscriptions if True (1)
|
||||||
|
@ -1450,7 +1441,7 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
|
|
||||||
# Adapters and converters for QT <-> sqlite
|
# Adapters and converters for QT <-> sqlite
|
||||||
def sqlInit(self):
|
def sqlInit(self):
|
||||||
register_adapter(QtCore.QByteArray, str)
|
register_adapter(QtCore.QByteArray, bytes)
|
||||||
|
|
||||||
def indicatorInit(self):
|
def indicatorInit(self):
|
||||||
"""
|
"""
|
||||||
|
@ -1470,11 +1461,10 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
def notifierInit(self):
|
def notifierInit(self):
|
||||||
def _simple_notify(
|
def _simple_notify(
|
||||||
title, subtitle, category, label=None, icon=None):
|
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
|
self._notifier = _simple_notify
|
||||||
# does nothing if isAvailable returns false
|
|
||||||
self._player = QtGui.QSound.play
|
|
||||||
|
|
||||||
if not get_plugins:
|
if not get_plugins:
|
||||||
return
|
return
|
||||||
|
@ -1487,7 +1477,10 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
|
|
||||||
self._theme_player = get_plugin('notification.sound', 'theme')
|
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(
|
_plugin = get_plugin(
|
||||||
'notification.sound', 'file', fallback='file.fallback')
|
'notification.sound', 'file', fallback='file.fallback')
|
||||||
if _plugin:
|
if _plugin:
|
||||||
|
@ -1499,7 +1492,7 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
self, title, subtitle, category, label=None, icon=None):
|
self, title, subtitle, category, label=None, icon=None):
|
||||||
self.playSound(category, label)
|
self.playSound(category, label)
|
||||||
self._notifier(
|
self._notifier(
|
||||||
unicode(title), unicode(subtitle), category, label, icon)
|
unic(ustr(title)), unic(ustr(subtitle)), category, label, icon)
|
||||||
|
|
||||||
# tree
|
# tree
|
||||||
def treeWidgetKeyPressEvent(self, event):
|
def treeWidgetKeyPressEvent(self, event):
|
||||||
|
@ -1511,7 +1504,7 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
if event.key() == QtCore.Qt.Key_Delete:
|
if event.key() == QtCore.Qt.Key_Delete:
|
||||||
self.on_action_AddressBookDelete()
|
self.on_action_AddressBookDelete()
|
||||||
else:
|
else:
|
||||||
return QtGui.QTableWidget.keyPressEvent(
|
return QtWidgets.QTableWidget.keyPressEvent(
|
||||||
self.ui.tableWidgetAddressBook, event)
|
self.ui.tableWidgetAddressBook, event)
|
||||||
|
|
||||||
# inbox / sent
|
# inbox / sent
|
||||||
|
@ -1526,14 +1519,14 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
"""This method handles keypress events for all widgets on MyForm"""
|
"""This method handles keypress events for all widgets on MyForm"""
|
||||||
messagelist = self.getCurrentMessagelist()
|
messagelist = self.getCurrentMessagelist()
|
||||||
if event.key() == QtCore.Qt.Key_Delete:
|
if event.key() == QtCore.Qt.Key_Delete:
|
||||||
if isinstance(focus, (MessageView, QtGui.QTableWidget)):
|
if isinstance(focus, (MessageView, QtWidgets.QTableWidget)):
|
||||||
folder = self.getCurrentFolder()
|
folder = self.getCurrentFolder()
|
||||||
if folder == "sent":
|
if folder == "sent":
|
||||||
self.on_action_SentTrash()
|
self.on_action_SentTrash()
|
||||||
else:
|
else:
|
||||||
self.on_action_InboxTrash()
|
self.on_action_InboxTrash()
|
||||||
event.ignore()
|
event.ignore()
|
||||||
elif QtGui.QApplication.queryKeyboardModifiers() == QtCore.Qt.NoModifier:
|
elif QtWidgets.QApplication.queryKeyboardModifiers() == QtCore.Qt.NoModifier:
|
||||||
if event.key() == QtCore.Qt.Key_N:
|
if event.key() == QtCore.Qt.Key_N:
|
||||||
currentRow = messagelist.currentRow()
|
currentRow = messagelist.currentRow()
|
||||||
if currentRow < messagelist.rowCount() - 1:
|
if currentRow < messagelist.rowCount() - 1:
|
||||||
|
@ -1572,74 +1565,77 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
return
|
return
|
||||||
if isinstance(focus, MessageView):
|
if isinstance(focus, MessageView):
|
||||||
return MessageView.keyPressEvent(focus, event)
|
return MessageView.keyPressEvent(focus, event)
|
||||||
if isinstance(focus, QtGui.QTableWidget):
|
elif isinstance(focus, QtWidgets.QTableWidget):
|
||||||
return QtGui.QTableWidget.keyPressEvent(focus, event)
|
return QtWidgets.QTableWidget.keyPressEvent(focus, event)
|
||||||
if isinstance(focus, QtGui.QTreeWidget):
|
elif isinstance(focus, QtWidgets.QTreeWidget):
|
||||||
return QtGui.QTreeWidget.keyPressEvent(focus, event)
|
return QtWidgets.QTreeWidget.keyPressEvent(focus, event)
|
||||||
|
|
||||||
# menu button 'manage keys'
|
# menu button 'manage keys'
|
||||||
def click_actionManageKeys(self):
|
def click_actionManageKeys(self):
|
||||||
if 'darwin' in sys.platform or 'linux' in sys.platform:
|
if 'darwin' in sys.platform or 'linux' in sys.platform:
|
||||||
if state.appdata == '':
|
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
|
# may manage your keys by editing the keys.dat file stored in
|
||||||
# the same directory as this program. It is important that you
|
# the same directory as this program. It is important that you
|
||||||
# back up this file.', QMessageBox.Ok)
|
# back up this file.', QMessageBox.Ok)
|
||||||
reply = QtGui.QMessageBox.information(
|
reply = QtWidgets.QMessageBox.information(
|
||||||
self,
|
self, 'keys.dat?', _translate(
|
||||||
'keys.dat?',
|
|
||||||
_translate(
|
|
||||||
"MainWindow",
|
"MainWindow",
|
||||||
"You may manage your keys by editing the keys.dat file stored in the same directory"
|
"You may manage your keys by editing the keys.dat"
|
||||||
"as this program. It is important that you back up this file."
|
" file stored in the same directory as this"
|
||||||
),
|
" program. It is important that you back up this"
|
||||||
QtGui.QMessageBox.Ok)
|
" file."), QtWidgets.QMessageBox.Ok)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
QtGui.QMessageBox.information(
|
QtWidgets.QMessageBox.information(
|
||||||
self,
|
self, 'keys.dat?',
|
||||||
'keys.dat?',
|
|
||||||
_translate(
|
_translate(
|
||||||
"MainWindow",
|
"MainWindow",
|
||||||
"You may manage your keys by editing the keys.dat file stored in"
|
"You may manage your keys by editing the keys.dat"
|
||||||
"\n %1 \n"
|
" file stored in\n {0} \nIt is important that you"
|
||||||
"It is important that you back up this file."
|
" back up this file."
|
||||||
).arg(state.appdata),
|
).format(state.appdata),
|
||||||
QtGui.QMessageBox.Ok)
|
QtWidgets.QMessageBox.Ok
|
||||||
|
)
|
||||||
elif sys.platform == 'win32' or sys.platform == 'win64':
|
elif sys.platform == 'win32' or sys.platform == 'win64':
|
||||||
if state.appdata == '':
|
if state.appdata == '':
|
||||||
reply = QtGui.QMessageBox.question(
|
reply = QtWidgets.QMessageBox.question(
|
||||||
self,
|
self, _translate("MainWindow", "Open keys.dat?"),
|
||||||
_translate("MainWindow", "Open keys.dat?"),
|
|
||||||
_translate(
|
_translate(
|
||||||
"MainWindow",
|
"MainWindow",
|
||||||
"You may manage your keys by editing the keys.dat file stored in the same directory as "
|
"You may manage your keys by editing the keys.dat"
|
||||||
"this program. It is important that you back up this file. "
|
" file stored in the same directory as this"
|
||||||
"Would you like to open the file now? "
|
" program. It is important that you back up this"
|
||||||
"(Be sure to close Bitmessage before making any changes.)"),
|
" file. Would you like to open the file now?"
|
||||||
QtGui.QMessageBox.Yes,
|
" (Be sure to close Bitmessage before making any"
|
||||||
QtGui.QMessageBox.No)
|
" changes.)"
|
||||||
|
), QtWidgets.QMessageBox.Yes, QtWidgets.QMessageBox.No)
|
||||||
else:
|
else:
|
||||||
reply = QtGui.QMessageBox.question(
|
reply = QtWidgets.QMessageBox.question(
|
||||||
self,
|
self,
|
||||||
_translate("MainWindow", "Open keys.dat?"),
|
_translate("MainWindow", "Open keys.dat?"),
|
||||||
_translate(
|
_translate(
|
||||||
"MainWindow",
|
"MainWindow",
|
||||||
"You may manage your keys by editing the keys.dat file stored in\n %1 \n"
|
"You may manage your keys by editing the keys.dat"
|
||||||
"It is important that you back up this file. Would you like to open the file now?"
|
" file stored in\n {0} \nIt is important that you"
|
||||||
"(Be sure to close Bitmessage before making any changes.)").arg(state.appdata),
|
" back up this file. Would you like to open the"
|
||||||
QtGui.QMessageBox.Yes, QtGui.QMessageBox.No)
|
" file now? (Be sure to close Bitmessage before"
|
||||||
if reply == QtGui.QMessageBox.Yes:
|
" making any changes.)"
|
||||||
|
).format(state.appdata),
|
||||||
|
QtWidgets.QMessageBox.Yes, QtWidgets.QMessageBox.No
|
||||||
|
)
|
||||||
|
if reply == QtWidgets.QMessageBox.Yes:
|
||||||
openKeysFile()
|
openKeysFile()
|
||||||
|
|
||||||
# menu button 'delete all treshed messages'
|
# menu button 'delete all treshed messages'
|
||||||
def click_actionDeleteAllTrashedMessages(self):
|
def click_actionDeleteAllTrashedMessages(self):
|
||||||
if QtGui.QMessageBox.question(
|
if QtWidgets.QMessageBox.question(
|
||||||
self,
|
self, _translate("MainWindow", "Delete trash?"),
|
||||||
_translate("MainWindow", "Delete trash?"),
|
_translate(
|
||||||
_translate("MainWindow", "Are you sure you want to delete all trashed messages?"),
|
"MainWindow",
|
||||||
QtGui.QMessageBox.Yes,
|
"Are you sure you want to delete all trashed messages?"
|
||||||
QtGui.QMessageBox.No) == QtGui.QMessageBox.No:
|
), QtWidgets.QMessageBox.Yes, QtWidgets.QMessageBox.No
|
||||||
|
) == QtWidgets.QMessageBox.No:
|
||||||
return
|
return
|
||||||
sqlStoredProcedure('deleteandvacuume')
|
sqlStoredProcedure('deleteandvacuume')
|
||||||
self.rerenderTabTreeMessages()
|
self.rerenderTabTreeMessages()
|
||||||
|
@ -1666,7 +1662,7 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
dialog = dialogs.RegenerateAddressesDialog(self)
|
dialog = dialogs.RegenerateAddressesDialog(self)
|
||||||
if dialog.exec_():
|
if dialog.exec_():
|
||||||
if dialog.lineEditPassphrase.text() == "":
|
if dialog.lineEditPassphrase.text() == "":
|
||||||
QtGui.QMessageBox.about(
|
QtWidgets.QMessageBox.about(
|
||||||
self, _translate("MainWindow", "bad passphrase"),
|
self, _translate("MainWindow", "bad passphrase"),
|
||||||
_translate(
|
_translate(
|
||||||
"MainWindow",
|
"MainWindow",
|
||||||
|
@ -1679,7 +1675,7 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
addressVersionNumber = int(
|
addressVersionNumber = int(
|
||||||
dialog.lineEditAddressVersionNumber.text())
|
dialog.lineEditAddressVersionNumber.text())
|
||||||
except:
|
except:
|
||||||
QtGui.QMessageBox.about(
|
QtWidgets.QMessageBox.about(
|
||||||
self,
|
self,
|
||||||
_translate("MainWindow", "Bad address version number"),
|
_translate("MainWindow", "Bad address version number"),
|
||||||
_translate(
|
_translate(
|
||||||
|
@ -1689,7 +1685,7 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
))
|
))
|
||||||
return
|
return
|
||||||
if addressVersionNumber < 3 or addressVersionNumber > 4:
|
if addressVersionNumber < 3 or addressVersionNumber > 4:
|
||||||
QtGui.QMessageBox.about(
|
QtWidgets.QMessageBox.about(
|
||||||
self,
|
self,
|
||||||
_translate("MainWindow", "Bad address version number"),
|
_translate("MainWindow", "Bad address version number"),
|
||||||
_translate(
|
_translate(
|
||||||
|
@ -1702,7 +1698,7 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
addressVersionNumber, streamNumberForAddress,
|
addressVersionNumber, streamNumberForAddress,
|
||||||
"regenerated deterministic address",
|
"regenerated deterministic address",
|
||||||
dialog.spinBoxNumberOfAddressesToMake.value(),
|
dialog.spinBoxNumberOfAddressesToMake.value(),
|
||||||
dialog.lineEditPassphrase.text().toUtf8(),
|
ustr(dialog.lineEditPassphrase.text()).encode("utf-8", "replace"),
|
||||||
dialog.checkBoxEighteenByteRipe.isChecked()
|
dialog.checkBoxEighteenByteRipe.isChecked()
|
||||||
))
|
))
|
||||||
self.ui.tabWidget.setCurrentIndex(
|
self.ui.tabWidget.setCurrentIndex(
|
||||||
|
@ -1753,7 +1749,7 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def __icon_activated(self, reason):
|
def __icon_activated(self, reason):
|
||||||
if reason == QtGui.QSystemTrayIcon.Trigger:
|
if reason == QtWidgets.QSystemTrayIcon.Trigger:
|
||||||
self.actionShow.setChecked(not self.actionShow.isChecked())
|
self.actionShow.setChecked(not self.actionShow.isChecked())
|
||||||
self.appIndicatorShowOrHideWindow()
|
self.appIndicatorShowOrHideWindow()
|
||||||
|
|
||||||
|
@ -1823,7 +1819,7 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
|
|
||||||
def initTrayIcon(self, iconFileName, app):
|
def initTrayIcon(self, iconFileName, app):
|
||||||
self.currentTrayIconFileName = iconFileName
|
self.currentTrayIconFileName = iconFileName
|
||||||
self.tray = QtGui.QSystemTrayIcon(
|
self.tray = QtWidgets.QSystemTrayIcon(
|
||||||
self.calcTrayIcon(iconFileName, self.findInboxUnreadCount()), app)
|
self.calcTrayIcon(iconFileName, self.findInboxUnreadCount()), app)
|
||||||
|
|
||||||
def setTrayIconFile(self, iconFileName):
|
def setTrayIconFile(self, iconFileName):
|
||||||
|
@ -1855,8 +1851,8 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
# draw text
|
# draw text
|
||||||
painter = QtGui.QPainter()
|
painter = QtGui.QPainter()
|
||||||
painter.begin(pixmap)
|
painter.begin(pixmap)
|
||||||
painter.setPen(
|
painter.setPen(QtGui.QPen(QtGui.QColor(255, 0, 0)))
|
||||||
QtGui.QPen(QtGui.QColor(255, 0, 0), QtCore.Qt.SolidPattern))
|
painter.setBrush(QtCore.Qt.SolidPattern)
|
||||||
painter.setFont(font)
|
painter.setFont(font)
|
||||||
painter.drawText(24-rect.right()-marginX, -rect.top()+marginY, txt)
|
painter.drawText(24-rect.right()-marginX, -rect.top()+marginY, txt)
|
||||||
painter.end()
|
painter.end()
|
||||||
|
@ -1903,10 +1899,11 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
if toAddress == rowAddress:
|
if toAddress == rowAddress:
|
||||||
sent.item(i, 3).setToolTip(textToDisplay)
|
sent.item(i, 3).setToolTip(textToDisplay)
|
||||||
try:
|
try:
|
||||||
newlinePosition = textToDisplay.indexOf('\n')
|
newlinePosition = textToDisplay.find('\n')
|
||||||
except:
|
# If someone misses adding a "_translate" to a string
|
||||||
# If someone misses adding a "_translate" to a string before passing it to this function,
|
# before passing it to this function
|
||||||
# this function won't receive a qstring which will cause an exception.
|
# ? why textToDisplay isn't unicode
|
||||||
|
except AttributeError:
|
||||||
newlinePosition = 0
|
newlinePosition = 0
|
||||||
if newlinePosition > 1:
|
if newlinePosition > 1:
|
||||||
sent.item(i, 3).setText(
|
sent.item(i, 3).setText(
|
||||||
|
@ -1915,8 +1912,6 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
sent.item(i, 3).setText(textToDisplay)
|
sent.item(i, 3).setText(textToDisplay)
|
||||||
|
|
||||||
def updateSentItemStatusByAckdata(self, ackdata, textToDisplay):
|
def updateSentItemStatusByAckdata(self, ackdata, textToDisplay):
|
||||||
if type(ackdata) is str:
|
|
||||||
ackdata = QtCore.QByteArray(ackdata)
|
|
||||||
for sent in (
|
for sent in (
|
||||||
self.ui.tableWidgetInbox,
|
self.ui.tableWidgetInbox,
|
||||||
self.ui.tableWidgetInboxSubscriptions,
|
self.ui.tableWidgetInboxSubscriptions,
|
||||||
|
@ -1926,23 +1921,23 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
if self.getCurrentFolder(treeWidget) != "sent":
|
if self.getCurrentFolder(treeWidget) != "sent":
|
||||||
continue
|
continue
|
||||||
for i in range(sent.rowCount()):
|
for i in range(sent.rowCount()):
|
||||||
toAddress = sent.item(i, 0).data(QtCore.Qt.UserRole)
|
# toAddress = sent.item(i, 0).data(QtCore.Qt.UserRole)
|
||||||
tableAckdata = sent.item(i, 3).data()
|
tableAckdata = as_msgid(sent.item(i, 3).data())
|
||||||
status, addressVersionNumber, streamNumber, ripe = decodeAddress(
|
# status, addressVersionNumber, streamNumber, ripe = decodeAddress(
|
||||||
toAddress)
|
# toAddress)
|
||||||
if ackdata == tableAckdata:
|
if ackdata == tableAckdata:
|
||||||
sent.item(i, 3).setToolTip(textToDisplay)
|
sent.item(i, 3).setToolTip(textToDisplay)
|
||||||
try:
|
try:
|
||||||
newlinePosition = textToDisplay.indexOf('\n')
|
newlinePosition = textToDisplay.find('\n')
|
||||||
except:
|
# If someone misses adding a "_translate" to a string
|
||||||
# If someone misses adding a "_translate" to a string before passing it to this function,
|
# before passing it to this function
|
||||||
# this function won't receive a qstring which will cause an exception.
|
# ? why textToDisplay isn't unicode
|
||||||
|
except AttributeError:
|
||||||
newlinePosition = 0
|
newlinePosition = 0
|
||||||
if newlinePosition > 1:
|
if newlinePosition > 1:
|
||||||
sent.item(i, 3).setText(
|
textToDisplay = textToDisplay[:newlinePosition]
|
||||||
textToDisplay[:newlinePosition])
|
|
||||||
else:
|
sent.item(i, 3).setText(textToDisplay)
|
||||||
sent.item(i, 3).setText(textToDisplay)
|
|
||||||
|
|
||||||
def removeInboxRowByMsgid(self, msgid):
|
def removeInboxRowByMsgid(self, msgid):
|
||||||
# msgid and inventoryHash are the same thing
|
# msgid and inventoryHash are the same thing
|
||||||
|
@ -1953,7 +1948,7 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
):
|
):
|
||||||
i = None
|
i = None
|
||||||
for i in range(inbox.rowCount()):
|
for i in range(inbox.rowCount()):
|
||||||
if msgid == inbox.item(i, 3).data():
|
if msgid == as_msgid(inbox.item(i, 3).data()):
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
continue
|
continue
|
||||||
|
@ -1970,14 +1965,15 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
self.notifiedNewVersion = ".".join(str(n) for n in version)
|
self.notifiedNewVersion = ".".join(str(n) for n in version)
|
||||||
self.updateStatusBar(_translate(
|
self.updateStatusBar(_translate(
|
||||||
"MainWindow",
|
"MainWindow",
|
||||||
"New version of PyBitmessage is available: %1. Download it"
|
"New version of PyBitmessage is available: {0}. Download it"
|
||||||
" from https://github.com/Bitmessage/PyBitmessage/releases/latest"
|
" from https://github.com/Bitmessage/PyBitmessage/releases/latest"
|
||||||
).arg(self.notifiedNewVersion)
|
).format(self.notifiedNewVersion)
|
||||||
)
|
)
|
||||||
|
|
||||||
def displayAlert(self, title, text, exitAfterUserClicksOk):
|
def displayAlert(self, title, text, exitAfterUserClicksOk):
|
||||||
self.updateStatusBar(text)
|
self.updateStatusBar(text)
|
||||||
QtGui.QMessageBox.critical(self, title, text, QtGui.QMessageBox.Ok)
|
QtWidgets.QMessageBox.critical(
|
||||||
|
self, title, text, QtWidgets.QMessageBox.Ok)
|
||||||
if exitAfterUserClicksOk:
|
if exitAfterUserClicksOk:
|
||||||
os._exit(0)
|
os._exit(0)
|
||||||
|
|
||||||
|
@ -1996,11 +1992,11 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
messagelist.item(i, 0).setLabel()
|
messagelist.item(i, 0).setLabel()
|
||||||
|
|
||||||
def rerenderAddressBook(self):
|
def rerenderAddressBook(self):
|
||||||
def addRow (address, label, type):
|
def addRow(address, label, type):
|
||||||
self.ui.tableWidgetAddressBook.insertRow(0)
|
self.ui.tableWidgetAddressBook.insertRow(0)
|
||||||
newItem = Ui_AddressBookWidgetItemLabel(address, unicode(label, 'utf-8'), type)
|
newItem = Ui_AddressBookWidgetItemLabel(address, unic(ustr(label)), type)
|
||||||
self.ui.tableWidgetAddressBook.setItem(0, 0, newItem)
|
self.ui.tableWidgetAddressBook.setItem(0, 0, newItem)
|
||||||
newItem = Ui_AddressBookWidgetItemAddress(address, unicode(label, 'utf-8'), type)
|
newItem = Ui_AddressBookWidgetItemAddress(address, unic(ustr(label)), type)
|
||||||
self.ui.tableWidgetAddressBook.setItem(0, 1, newItem)
|
self.ui.tableWidgetAddressBook.setItem(0, 1, newItem)
|
||||||
|
|
||||||
oldRows = {}
|
oldRows = {}
|
||||||
|
@ -2009,7 +2005,8 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
oldRows[item.address] = [item.label, item.type, i]
|
oldRows[item.address] = [item.label, item.type, i]
|
||||||
|
|
||||||
if self.ui.tableWidgetAddressBook.rowCount() == 0:
|
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():
|
if self.ui.tableWidgetAddressBook.isSortingEnabled():
|
||||||
self.ui.tableWidgetAddressBook.setSortingEnabled(False)
|
self.ui.tableWidgetAddressBook.setSortingEnabled(False)
|
||||||
|
|
||||||
|
@ -2018,16 +2015,23 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
queryreturn = sqlQuery('SELECT label, address FROM subscriptions WHERE enabled = 1')
|
queryreturn = sqlQuery('SELECT label, address FROM subscriptions WHERE enabled = 1')
|
||||||
for row in queryreturn:
|
for row in queryreturn:
|
||||||
label, address = row
|
label, address = row
|
||||||
|
label = label.decode("utf-8", "replace")
|
||||||
|
address = address.decode("utf-8", "replace")
|
||||||
newRows[address] = [label, AccountMixin.SUBSCRIPTION]
|
newRows[address] = [label, AccountMixin.SUBSCRIPTION]
|
||||||
# chans
|
# chans
|
||||||
for address in config.addresses(True):
|
for address in config.addresses(True):
|
||||||
account = accountClass(address)
|
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]
|
newRows[address] = [account.getLabel(), AccountMixin.CHAN]
|
||||||
# normal accounts
|
# normal accounts
|
||||||
queryreturn = sqlQuery('SELECT * FROM addressbook')
|
queryreturn = sqlQuery('SELECT label, address FROM addressbook')
|
||||||
for row in queryreturn:
|
for row in queryreturn:
|
||||||
label, address = row
|
label, address = row
|
||||||
|
label = label.decode("utf-8", "replace")
|
||||||
|
address = address.decode("utf-8", "replace")
|
||||||
newRows[address] = [label, AccountMixin.NORMAL]
|
newRows[address] = [label, AccountMixin.NORMAL]
|
||||||
|
|
||||||
completerList = []
|
completerList = []
|
||||||
|
@ -2041,7 +2045,7 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
self.ui.tableWidgetAddressBook.removeRow(oldRows[address][2])
|
self.ui.tableWidgetAddressBook.removeRow(oldRows[address][2])
|
||||||
for address in newRows:
|
for address in newRows:
|
||||||
addRow(address, newRows[address][0], newRows[address][1])
|
addRow(address, newRows[address][0], newRows[address][1])
|
||||||
completerList.append(unicode(newRows[address][0], encoding="UTF-8") + " <" + address + ">")
|
completerList.append(unic(ustr(newRows[address][0]) + " <" + ustr(address) + ">"))
|
||||||
|
|
||||||
# sort
|
# sort
|
||||||
self.ui.tableWidgetAddressBook.sortByColumn(
|
self.ui.tableWidgetAddressBook.sortByColumn(
|
||||||
|
@ -2053,16 +2057,17 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
self.rerenderTabTreeSubscriptions()
|
self.rerenderTabTreeSubscriptions()
|
||||||
|
|
||||||
def click_pushButtonTTL(self):
|
def click_pushButtonTTL(self):
|
||||||
QtGui.QMessageBox.information(
|
QtWidgets.QMessageBox.information(
|
||||||
self,
|
self, 'Time To Live', _translate(
|
||||||
'Time To Live',
|
"MainWindow",
|
||||||
_translate(
|
"The TTL, or Time-To-Live is the length of time that"
|
||||||
"MainWindow", """The TTL, or Time-To-Live is the length of time that the network will hold the message.
|
" the network will hold the message. The recipient must"
|
||||||
The recipient must get it during this time. If your Bitmessage client does not hear an acknowledgement
|
" get it during this time. If your Bitmessage client does"
|
||||||
,it will resend the message automatically. The longer the Time-To-Live, the
|
" not hear an acknowledgement, it will resend the message"
|
||||||
more work your computer must do to send the message.
|
" automatically. The longer the Time-To-Live, the more"
|
||||||
A Time-To-Live of four or five days is often appropriate."""),
|
" work your computer must do to send the message. A"
|
||||||
QtGui.QMessageBox.Ok)
|
" Time-To-Live of four or five days is often appropriate."
|
||||||
|
), QtWidgets.QMessageBox.Ok)
|
||||||
|
|
||||||
def click_pushButtonClear(self):
|
def click_pushButtonClear(self):
|
||||||
self.ui.lineEditSubject.setText("")
|
self.ui.lineEditSubject.setText("")
|
||||||
|
@ -2071,7 +2076,10 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
self.ui.comboBoxSendFrom.setCurrentIndex(0)
|
self.ui.comboBoxSendFrom.setCurrentIndex(0)
|
||||||
|
|
||||||
def click_pushButtonSend(self):
|
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()
|
self.statusbar.clearMessage()
|
||||||
|
|
||||||
|
@ -2079,22 +2087,22 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
self.ui.tabWidgetSend.indexOf(self.ui.sendDirect):
|
self.ui.tabWidgetSend.indexOf(self.ui.sendDirect):
|
||||||
# message to specific people
|
# message to specific people
|
||||||
sendMessageToPeople = True
|
sendMessageToPeople = True
|
||||||
fromAddress = str(self.ui.comboBoxSendFrom.itemData(
|
fromAddress = ustr(self.ui.comboBoxSendFrom.itemData(
|
||||||
self.ui.comboBoxSendFrom.currentIndex(),
|
self.ui.comboBoxSendFrom.currentIndex(),
|
||||||
QtCore.Qt.UserRole).toString())
|
QtCore.Qt.UserRole))
|
||||||
toAddresses = str(self.ui.lineEditTo.text().toUtf8())
|
toAddresses = ustr(self.ui.lineEditTo.text())
|
||||||
subject = str(self.ui.lineEditSubject.text().toUtf8())
|
subject = ustr(self.ui.lineEditSubject.text())
|
||||||
message = str(
|
message = ustr(
|
||||||
self.ui.textEditMessage.document().toPlainText().toUtf8())
|
self.ui.textEditMessage.document().toPlainText())
|
||||||
else:
|
else:
|
||||||
# broadcast message
|
# broadcast message
|
||||||
sendMessageToPeople = False
|
sendMessageToPeople = False
|
||||||
fromAddress = str(self.ui.comboBoxSendFromBroadcast.itemData(
|
fromAddress = ustr(self.ui.comboBoxSendFromBroadcast.itemData(
|
||||||
self.ui.comboBoxSendFromBroadcast.currentIndex(),
|
self.ui.comboBoxSendFromBroadcast.currentIndex(),
|
||||||
QtCore.Qt.UserRole).toString())
|
QtCore.Qt.UserRole))
|
||||||
subject = str(self.ui.lineEditSubjectBroadcast.text().toUtf8())
|
subject = ustr(self.ui.lineEditSubjectBroadcast.text())
|
||||||
message = str(
|
message = ustr(
|
||||||
self.ui.textEditMessageBroadcast.document().toPlainText().toUtf8())
|
self.ui.textEditMessageBroadcast.document().toPlainText())
|
||||||
"""
|
"""
|
||||||
The whole network message must fit in 2^18 bytes.
|
The whole network message must fit in 2^18 bytes.
|
||||||
Let's assume 500 bytes of overhead. If someone wants to get that
|
Let's assume 500 bytes of overhead. If someone wants to get that
|
||||||
|
@ -2103,14 +2111,14 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
users can send messages of any length.
|
users can send messages of any length.
|
||||||
"""
|
"""
|
||||||
if len(message) > (2 ** 18 - 500):
|
if len(message) > (2 ** 18 - 500):
|
||||||
QtGui.QMessageBox.about(
|
QtWidgets.QMessageBox.about(
|
||||||
self, _translate("MainWindow", "Message too long"),
|
self, _translate("MainWindow", "Message too long"),
|
||||||
_translate(
|
_translate(
|
||||||
"MainWindow",
|
"MainWindow",
|
||||||
"The message that you are trying to send is too long"
|
"The message that you are trying to send is too long"
|
||||||
" by %1 bytes. (The maximum is 261644 bytes). Please"
|
" by {0} bytes. (The maximum is 261644 bytes). Please"
|
||||||
" cut it down before sending."
|
" cut it down before sending."
|
||||||
).arg(len(message) - (2 ** 18 - 500)))
|
).format(len(message) - (2 ** 18 - 500)))
|
||||||
return
|
return
|
||||||
|
|
||||||
acct = accountClass(fromAddress)
|
acct = accountClass(fromAddress)
|
||||||
|
@ -2131,25 +2139,32 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
# email address
|
# email address
|
||||||
if toAddress.find("@") >= 0:
|
if toAddress.find("@") >= 0:
|
||||||
if isinstance(acct, GatewayAccount):
|
if isinstance(acct, GatewayAccount):
|
||||||
acct.createMessage(toAddress, fromAddress, subject, message)
|
acct.createMessage(
|
||||||
|
toAddress, fromAddress, subject, message)
|
||||||
subject = acct.subject
|
subject = acct.subject
|
||||||
toAddress = acct.toAddress
|
toAddress = acct.toAddress
|
||||||
else:
|
else:
|
||||||
if QtGui.QMessageBox.question(
|
if QtWidgets.QMessageBox.question(
|
||||||
self,
|
self, "Sending an email?",
|
||||||
"Sending an email?",
|
_translate(
|
||||||
_translate(
|
"MainWindow",
|
||||||
"MainWindow",
|
"You are trying to send an email"
|
||||||
"You are trying to send an email instead of a bitmessage. "
|
" instead of a bitmessage. This"
|
||||||
"This requires registering with a gateway. Attempt to register?"),
|
" requires registering with a"
|
||||||
QtGui.QMessageBox.Yes|QtGui.QMessageBox.No) != QtGui.QMessageBox.Yes:
|
" gateway. Attempt to register?"
|
||||||
|
), QtWidgets.QMessageBox.Yes
|
||||||
|
| QtWidgets.QMessageBox.No
|
||||||
|
) != QtWidgets.QMessageBox.Yes:
|
||||||
continue
|
continue
|
||||||
email = acct.getLabel()
|
email = acct.getLabel()
|
||||||
if email[-14:] != "@mailchuck.com": # attempt register
|
# attempt register
|
||||||
|
if email[-14:] != "@mailchuck.com":
|
||||||
# 12 character random email address
|
# 12 character random email address
|
||||||
email = ''.join(
|
email = u''.join(
|
||||||
random.SystemRandom().choice(string.ascii_lowercase) for _ in range(12)
|
random.SystemRandom().choice(
|
||||||
) + "@mailchuck.com"
|
string.ascii_lowercase
|
||||||
|
) for _ in range(12)
|
||||||
|
) + "@mailchuck.com"
|
||||||
acct = MailchuckAccount(fromAddress)
|
acct = MailchuckAccount(fromAddress)
|
||||||
acct.register(email)
|
acct.register(email)
|
||||||
config.set(fromAddress, 'label', email)
|
config.set(fromAddress, 'label', email)
|
||||||
|
@ -2159,15 +2174,15 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
"MainWindow",
|
"MainWindow",
|
||||||
"Error: Your account wasn't registered at"
|
"Error: Your account wasn't registered at"
|
||||||
" an email gateway. Sending registration"
|
" an email gateway. Sending registration"
|
||||||
" now as %1, please wait for the registration"
|
" now as {0}, please wait for the registration"
|
||||||
" to be processed before retrying sending."
|
" to be processed before retrying sending."
|
||||||
).arg(email)
|
).format(email))
|
||||||
)
|
|
||||||
return
|
return
|
||||||
status, addressVersionNumber, streamNumber = decodeAddress(toAddress)[:3]
|
status, addressVersionNumber, streamNumber = \
|
||||||
|
decodeAddress(toAddress)[:3]
|
||||||
if status != 'success':
|
if status != 'success':
|
||||||
try:
|
try:
|
||||||
toAddress = unicode(toAddress, 'utf-8', 'ignore')
|
toAddress = unic(ustr(toAddress))
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
logger.error('Error: Could not decode recipient address ' + toAddress + ':' + status)
|
logger.error('Error: Could not decode recipient address ' + toAddress + ':' + status)
|
||||||
|
@ -2176,58 +2191,58 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
self.updateStatusBar(_translate(
|
self.updateStatusBar(_translate(
|
||||||
"MainWindow",
|
"MainWindow",
|
||||||
"Error: Bitmessage addresses start with"
|
"Error: Bitmessage addresses start with"
|
||||||
" BM- Please check the recipient address %1"
|
" BM- Please check the recipient address {0}"
|
||||||
).arg(toAddress))
|
).format(toAddress))
|
||||||
elif status == 'checksumfailed':
|
elif status == 'checksumfailed':
|
||||||
self.updateStatusBar(_translate(
|
self.updateStatusBar(_translate(
|
||||||
"MainWindow",
|
"MainWindow",
|
||||||
"Error: The recipient address %1 is not"
|
"Error: The recipient address {0} is not"
|
||||||
" typed or copied correctly. Please check it."
|
" typed or copied correctly. Please check it."
|
||||||
).arg(toAddress))
|
).format(toAddress))
|
||||||
elif status == 'invalidcharacters':
|
elif status == 'invalidcharacters':
|
||||||
self.updateStatusBar(_translate(
|
self.updateStatusBar(_translate(
|
||||||
"MainWindow",
|
"MainWindow",
|
||||||
"Error: The recipient address %1 contains"
|
"Error: The recipient address {0} contains"
|
||||||
" invalid characters. Please check it."
|
" invalid characters. Please check it."
|
||||||
).arg(toAddress))
|
).format(toAddress))
|
||||||
elif status == 'versiontoohigh':
|
elif status == 'versiontoohigh':
|
||||||
self.updateStatusBar(_translate(
|
self.updateStatusBar(_translate(
|
||||||
"MainWindow",
|
"MainWindow",
|
||||||
"Error: The version of the recipient address"
|
"Error: The version of the recipient address"
|
||||||
" %1 is too high. Either you need to upgrade"
|
" {0} is too high. Either you need to upgrade"
|
||||||
" your Bitmessage software or your"
|
" your Bitmessage software or your"
|
||||||
" acquaintance is being clever."
|
" acquaintance is being clever."
|
||||||
).arg(toAddress))
|
).format(toAddress))
|
||||||
elif status == 'ripetooshort':
|
elif status == 'ripetooshort':
|
||||||
self.updateStatusBar(_translate(
|
self.updateStatusBar(_translate(
|
||||||
"MainWindow",
|
"MainWindow",
|
||||||
"Error: Some data encoded in the recipient"
|
"Error: Some data encoded in the recipient"
|
||||||
" address %1 is too short. There might be"
|
" address {0} is too short. There might be"
|
||||||
" something wrong with the software of"
|
" something wrong with the software of"
|
||||||
" your acquaintance."
|
" your acquaintance."
|
||||||
).arg(toAddress))
|
).format(toAddress))
|
||||||
elif status == 'ripetoolong':
|
elif status == 'ripetoolong':
|
||||||
self.updateStatusBar(_translate(
|
self.updateStatusBar(_translate(
|
||||||
"MainWindow",
|
"MainWindow",
|
||||||
"Error: Some data encoded in the recipient"
|
"Error: Some data encoded in the recipient"
|
||||||
" address %1 is too long. There might be"
|
" address {0} is too long. There might be"
|
||||||
" something wrong with the software of"
|
" something wrong with the software of"
|
||||||
" your acquaintance."
|
" your acquaintance."
|
||||||
).arg(toAddress))
|
).format(toAddress))
|
||||||
elif status == 'varintmalformed':
|
elif status == 'varintmalformed':
|
||||||
self.updateStatusBar(_translate(
|
self.updateStatusBar(_translate(
|
||||||
"MainWindow",
|
"MainWindow",
|
||||||
"Error: Some data encoded in the recipient"
|
"Error: Some data encoded in the recipient"
|
||||||
" address %1 is malformed. There might be"
|
" address {0} is malformed. There might be"
|
||||||
" something wrong with the software of"
|
" something wrong with the software of"
|
||||||
" your acquaintance."
|
" your acquaintance."
|
||||||
).arg(toAddress))
|
).format(toAddress))
|
||||||
else:
|
else:
|
||||||
self.updateStatusBar(_translate(
|
self.updateStatusBar(_translate(
|
||||||
"MainWindow",
|
"MainWindow",
|
||||||
"Error: Something is wrong with the"
|
"Error: Something is wrong with the"
|
||||||
" recipient address %1."
|
" recipient address {0}."
|
||||||
).arg(toAddress))
|
).format(toAddress))
|
||||||
elif fromAddress == '':
|
elif fromAddress == '':
|
||||||
self.updateStatusBar(_translate(
|
self.updateStatusBar(_translate(
|
||||||
"MainWindow",
|
"MainWindow",
|
||||||
|
@ -2239,24 +2254,31 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
toAddress = addBMIfNotPresent(toAddress)
|
toAddress = addBMIfNotPresent(toAddress)
|
||||||
|
|
||||||
if addressVersionNumber > 4 or addressVersionNumber <= 1:
|
if addressVersionNumber > 4 or addressVersionNumber <= 1:
|
||||||
QtGui.QMessageBox.about(
|
QtWidgets.QMessageBox.about(
|
||||||
self,
|
self,
|
||||||
_translate("MainWindow", "Address version number"),
|
_translate(
|
||||||
|
"MainWindow", "Address version number"),
|
||||||
_translate(
|
_translate(
|
||||||
"MainWindow",
|
"MainWindow",
|
||||||
"Concerning the address %1, Bitmessage cannot understand address version numbers"
|
"Concerning the address {0}, Bitmessage"
|
||||||
" of %2. Perhaps upgrade Bitmessage to the latest version."
|
" cannot understand address version"
|
||||||
).arg(toAddress).arg(str(addressVersionNumber)))
|
" numbers of {1}. Perhaps upgrade"
|
||||||
|
" Bitmessage to the latest version."
|
||||||
|
).format(toAddress, addressVersionNumber)
|
||||||
|
)
|
||||||
continue
|
continue
|
||||||
if streamNumber > 1 or streamNumber == 0:
|
if streamNumber > 1 or streamNumber == 0:
|
||||||
QtGui.QMessageBox.about(
|
QtWidgets.QMessageBox.about(
|
||||||
self,
|
self,
|
||||||
_translate("MainWindow", "Stream number"),
|
_translate("MainWindow", "Stream number"),
|
||||||
_translate(
|
_translate(
|
||||||
"MainWindow",
|
"MainWindow",
|
||||||
"Concerning the address %1, Bitmessage cannot handle stream numbers of %2."
|
"Concerning the address {0}, Bitmessage"
|
||||||
" Perhaps upgrade Bitmessage to the latest version."
|
" cannot handle stream numbers of {1}."
|
||||||
).arg(toAddress).arg(str(streamNumber)))
|
" Perhaps upgrade Bitmessage to the"
|
||||||
|
" latest version."
|
||||||
|
).format(toAddress, streamNumber)
|
||||||
|
)
|
||||||
continue
|
continue
|
||||||
self.statusbar.clearMessage()
|
self.statusbar.clearMessage()
|
||||||
if state.statusIconColor == 'red':
|
if state.statusIconColor == 'red':
|
||||||
|
@ -2272,10 +2294,11 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
subject=subject, message=message, encoding=encoding)
|
subject=subject, message=message, encoding=encoding)
|
||||||
toLabel = ''
|
toLabel = ''
|
||||||
queryreturn = sqlQuery('''select label from addressbook where address=?''',
|
queryreturn = sqlQuery('''select label from addressbook where address=?''',
|
||||||
toAddress)
|
dbstr(toAddress))
|
||||||
if queryreturn != []:
|
if queryreturn != []:
|
||||||
for row in queryreturn:
|
for row in queryreturn:
|
||||||
toLabel, = row
|
toLabel, = row
|
||||||
|
toLabel = toLabel.decode("utf-8", "replace")
|
||||||
|
|
||||||
self.displayNewSentMessage(
|
self.displayNewSentMessage(
|
||||||
toAddress, toLabel, fromAddress, subject, message, ackdata)
|
toAddress, toLabel, fromAddress, subject, message, ackdata)
|
||||||
|
@ -2341,11 +2364,11 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
))
|
))
|
||||||
|
|
||||||
def click_pushButtonFetchNamecoinID(self):
|
def click_pushButtonFetchNamecoinID(self):
|
||||||
identities = str(self.ui.lineEditTo.text().toUtf8()).split(";")
|
identities = ustr(self.ui.lineEditTo.text()).split(";")
|
||||||
err, addr = self.namecoin.query(identities[-1].strip())
|
err, addr = self.namecoin.query(identities[-1].strip())
|
||||||
if err is not None:
|
if err is not None:
|
||||||
self.updateStatusBar(
|
self.updateStatusBar(
|
||||||
_translate("MainWindow", "Error: %1").arg(err))
|
_translate("MainWindow", "Error: {0}").format(err))
|
||||||
else:
|
else:
|
||||||
identities[-1] = addr
|
identities[-1] = addr
|
||||||
self.ui.lineEditTo.setText("; ".join(identities))
|
self.ui.lineEditTo.setText("; ".join(identities))
|
||||||
|
@ -2358,7 +2381,7 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
self.ui.tabWidgetSend.setCurrentIndex(
|
self.ui.tabWidgetSend.setCurrentIndex(
|
||||||
self.ui.tabWidgetSend.indexOf(
|
self.ui.tabWidgetSend.indexOf(
|
||||||
self.ui.sendBroadcast
|
self.ui.sendBroadcast
|
||||||
if config.safeGetBoolean(str(address), 'mailinglist')
|
if config.safeGetBoolean(ustr(address), 'mailinglist')
|
||||||
else self.ui.sendDirect
|
else self.ui.sendDirect
|
||||||
))
|
))
|
||||||
|
|
||||||
|
@ -2369,21 +2392,22 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
# It's easier for others to read.
|
# It's easier for others to read.
|
||||||
isEnabled = config.getboolean(
|
isEnabled = config.getboolean(
|
||||||
addressInKeysFile, 'enabled')
|
addressInKeysFile, 'enabled')
|
||||||
isMaillinglist = config.safeGetBoolean(addressInKeysFile, 'mailinglist')
|
isMaillinglist = config.safeGetBoolean(
|
||||||
|
addressInKeysFile, 'mailinglist')
|
||||||
if isEnabled and not isMaillinglist:
|
if isEnabled and not isMaillinglist:
|
||||||
label = unicode(config.get(addressInKeysFile, 'label'), 'utf-8', 'ignore').strip()
|
label = unic(ustr(config.get(addressInKeysFile, 'label')).strip()) or addressInKeysFile
|
||||||
if label == "":
|
if label == "":
|
||||||
label = addressInKeysFile
|
label = addressInKeysFile
|
||||||
self.ui.comboBoxSendFrom.addItem(avatarize(addressInKeysFile), label, addressInKeysFile)
|
self.ui.comboBoxSendFrom.addItem(avatarize(addressInKeysFile), label, addressInKeysFile)
|
||||||
# self.ui.comboBoxSendFrom.model().sort(1, Qt.AscendingOrder)
|
# self.ui.comboBoxSendFrom.model().sort(1, Qt.AscendingOrder)
|
||||||
for i in range(self.ui.comboBoxSendFrom.count()):
|
for i in range(self.ui.comboBoxSendFrom.count()):
|
||||||
address = str(self.ui.comboBoxSendFrom.itemData(
|
address = ustr(self.ui.comboBoxSendFrom.itemData(
|
||||||
i, QtCore.Qt.UserRole).toString())
|
i, QtCore.Qt.UserRole))
|
||||||
self.ui.comboBoxSendFrom.setItemData(
|
self.ui.comboBoxSendFrom.setItemData(
|
||||||
i, AccountColor(address).accountColor(),
|
i, AccountColor(address).accountColor(),
|
||||||
QtCore.Qt.ForegroundRole)
|
QtCore.Qt.ForegroundRole)
|
||||||
self.ui.comboBoxSendFrom.insertItem(0, '', '')
|
self.ui.comboBoxSendFrom.insertItem(0, '', '')
|
||||||
if(self.ui.comboBoxSendFrom.count() == 2):
|
if self.ui.comboBoxSendFrom.count() == 2:
|
||||||
self.ui.comboBoxSendFrom.setCurrentIndex(1)
|
self.ui.comboBoxSendFrom.setCurrentIndex(1)
|
||||||
else:
|
else:
|
||||||
self.ui.comboBoxSendFrom.setCurrentIndex(0)
|
self.ui.comboBoxSendFrom.setCurrentIndex(0)
|
||||||
|
@ -2395,18 +2419,16 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
addressInKeysFile, 'enabled')
|
addressInKeysFile, 'enabled')
|
||||||
isChan = config.safeGetBoolean(addressInKeysFile, 'chan')
|
isChan = config.safeGetBoolean(addressInKeysFile, 'chan')
|
||||||
if isEnabled and not isChan:
|
if isEnabled and not isChan:
|
||||||
label = unicode(config.get(addressInKeysFile, 'label'), 'utf-8', 'ignore').strip()
|
label = unic(ustr(config.get(addressInKeysFile, 'label')).strip()) or addressInKeysFile
|
||||||
if label == "":
|
|
||||||
label = addressInKeysFile
|
|
||||||
self.ui.comboBoxSendFromBroadcast.addItem(avatarize(addressInKeysFile), label, addressInKeysFile)
|
self.ui.comboBoxSendFromBroadcast.addItem(avatarize(addressInKeysFile), label, addressInKeysFile)
|
||||||
for i in range(self.ui.comboBoxSendFromBroadcast.count()):
|
for i in range(self.ui.comboBoxSendFromBroadcast.count()):
|
||||||
address = str(self.ui.comboBoxSendFromBroadcast.itemData(
|
address = ustr(self.ui.comboBoxSendFromBroadcast.itemData(
|
||||||
i, QtCore.Qt.UserRole).toString())
|
i, QtCore.Qt.UserRole))
|
||||||
self.ui.comboBoxSendFromBroadcast.setItemData(
|
self.ui.comboBoxSendFromBroadcast.setItemData(
|
||||||
i, AccountColor(address).accountColor(),
|
i, AccountColor(address).accountColor(),
|
||||||
QtCore.Qt.ForegroundRole)
|
QtCore.Qt.ForegroundRole)
|
||||||
self.ui.comboBoxSendFromBroadcast.insertItem(0, '', '')
|
self.ui.comboBoxSendFromBroadcast.insertItem(0, '', '')
|
||||||
if(self.ui.comboBoxSendFromBroadcast.count() == 2):
|
if self.ui.comboBoxSendFromBroadcast.count() == 2:
|
||||||
self.ui.comboBoxSendFromBroadcast.setCurrentIndex(1)
|
self.ui.comboBoxSendFromBroadcast.setCurrentIndex(1)
|
||||||
else:
|
else:
|
||||||
self.ui.comboBoxSendFromBroadcast.setCurrentIndex(0)
|
self.ui.comboBoxSendFromBroadcast.setCurrentIndex(0)
|
||||||
|
@ -2480,6 +2502,8 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
tableWidget = self.widgetConvert(treeWidget)
|
tableWidget = self.widgetConvert(treeWidget)
|
||||||
current_account = self.getCurrentAccount(treeWidget)
|
current_account = self.getCurrentAccount(treeWidget)
|
||||||
current_folder = self.getCurrentFolder(treeWidget)
|
current_folder = self.getCurrentFolder(treeWidget)
|
||||||
|
# inventoryHash surprisingly is of type unicode
|
||||||
|
# inventoryHash = inventoryHash.encode('utf-8')
|
||||||
# pylint: disable=too-many-boolean-expressions
|
# pylint: disable=too-many-boolean-expressions
|
||||||
if ((tableWidget == inbox
|
if ((tableWidget == inbox
|
||||||
and current_account == acct.address
|
and current_account == acct.address
|
||||||
|
@ -2500,13 +2524,13 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
'bitmessagesettings', 'showtraynotifications'):
|
'bitmessagesettings', 'showtraynotifications'):
|
||||||
self.notifierShow(
|
self.notifierShow(
|
||||||
_translate("MainWindow", "New Message"),
|
_translate("MainWindow", "New Message"),
|
||||||
_translate("MainWindow", "From %1").arg(
|
_translate("MainWindow", "From {0}").format(
|
||||||
unicode(acct.fromLabel, 'utf-8')),
|
unic(ustr(acct.fromLabel))),
|
||||||
sound.SOUND_UNKNOWN
|
sound.SOUND_UNKNOWN
|
||||||
)
|
)
|
||||||
if self.getCurrentAccount() is not None and (
|
if self.getCurrentAccount() is not None and (
|
||||||
(self.getCurrentFolder(treeWidget) != "inbox"
|
(self.getCurrentFolder(treeWidget) != "inbox"
|
||||||
and self.getCurrentFolder(treeWidget) is not None)
|
and self.getCurrentFolder(treeWidget) is not None)
|
||||||
or self.getCurrentAccount(treeWidget) != acct.address):
|
or self.getCurrentAccount(treeWidget) != acct.address):
|
||||||
# Ubuntu should notify of new message irrespective of
|
# Ubuntu should notify of new message irrespective of
|
||||||
# whether it's in current message list or not
|
# whether it's in current message list or not
|
||||||
|
@ -2527,7 +2551,7 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
dialog.exec_()
|
dialog.exec_()
|
||||||
try:
|
try:
|
||||||
address, label = dialog.data
|
address, label = dialog.data
|
||||||
except AttributeError:
|
except (AttributeError, TypeError):
|
||||||
return
|
return
|
||||||
|
|
||||||
# First we must check to see if the address is already in the
|
# First we must check to see if the address is already in the
|
||||||
|
@ -2560,7 +2584,7 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
# Add to database (perhaps this should be separated from the MyForm class)
|
# Add to database (perhaps this should be separated from the MyForm class)
|
||||||
sqlExecute(
|
sqlExecute(
|
||||||
'''INSERT INTO subscriptions VALUES (?,?,?)''',
|
'''INSERT INTO subscriptions VALUES (?,?,?)''',
|
||||||
label, address, True
|
dbstr(label), dbstr(address), True
|
||||||
)
|
)
|
||||||
self.rerenderMessagelistFromLabels()
|
self.rerenderMessagelistFromLabels()
|
||||||
shared.reloadBroadcastSendersForWhichImWatching()
|
shared.reloadBroadcastSendersForWhichImWatching()
|
||||||
|
@ -2572,7 +2596,7 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
dialog.exec_()
|
dialog.exec_()
|
||||||
try:
|
try:
|
||||||
address, label = dialog.data
|
address, label = dialog.data
|
||||||
except AttributeError:
|
except (AttributeError, TypeError):
|
||||||
return
|
return
|
||||||
|
|
||||||
# We must check to see if the address is already in the
|
# 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)
|
dialog = dialogs.EmailGatewayDialog(self, config=config)
|
||||||
# For Modal dialogs
|
# For Modal dialogs
|
||||||
dialog.exec_()
|
dialog.exec_()
|
||||||
try:
|
acct = dialog.data
|
||||||
acct = dialog.data
|
if not acct:
|
||||||
except AttributeError:
|
|
||||||
return
|
return
|
||||||
|
|
||||||
# Only settings remain here
|
# Only settings remain here
|
||||||
acct.settings()
|
acct.settings()
|
||||||
for i in range(self.ui.comboBoxSendFrom.count()):
|
for i in range(self.ui.comboBoxSendFrom.count()):
|
||||||
if str(self.ui.comboBoxSendFrom.itemData(i).toPyObject()) \
|
if ustr(self.ui.comboBoxSendFrom.itemData(i)) \
|
||||||
== acct.fromAddress:
|
== acct.fromAddress:
|
||||||
self.ui.comboBoxSendFrom.setCurrentIndex(i)
|
self.ui.comboBoxSendFrom.setCurrentIndex(i)
|
||||||
break
|
break
|
||||||
|
@ -2658,13 +2681,13 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
self.ui.textEditMessage.setFocus()
|
self.ui.textEditMessage.setFocus()
|
||||||
|
|
||||||
def on_action_MarkAllRead(self):
|
def on_action_MarkAllRead(self):
|
||||||
if QtGui.QMessageBox.question(
|
if QtWidgets.QMessageBox.question(
|
||||||
self, "Marking all messages as read?",
|
self, "Marking all messages as read?",
|
||||||
_translate(
|
_translate(
|
||||||
"MainWindow",
|
"MainWindow",
|
||||||
"Are you sure you would like to mark all messages read?"
|
"Are you sure you would like to mark all messages read?"
|
||||||
), QtGui.QMessageBox.Yes | QtGui.QMessageBox.No
|
), QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No
|
||||||
) != QtGui.QMessageBox.Yes:
|
) != QtWidgets.QMessageBox.Yes:
|
||||||
return
|
return
|
||||||
tableWidget = self.getCurrentMessagelist()
|
tableWidget = self.getCurrentMessagelist()
|
||||||
|
|
||||||
|
@ -2674,14 +2697,19 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
|
|
||||||
msgids = []
|
msgids = []
|
||||||
for i in range(0, idCount):
|
for i in range(0, idCount):
|
||||||
msgids.append(tableWidget.item(i, 3).data())
|
msgids.append(sqlite3.Binary(as_msgid(tableWidget.item(i, 3).data())))
|
||||||
for col in xrange(tableWidget.columnCount()):
|
for col in xrange(tableWidget.columnCount()):
|
||||||
tableWidget.item(i, col).setUnread(False)
|
tableWidget.item(i, col).setUnread(False)
|
||||||
|
|
||||||
markread = sqlExecuteChunked(
|
markread = sqlExecuteChunked(
|
||||||
"UPDATE inbox SET read = 1 WHERE msgid IN({0}) AND read=0",
|
"UPDATE inbox SET read = 1 WHERE msgid IN({0}) AND read=0",
|
||||||
idCount, *msgids
|
False, idCount, *msgids
|
||||||
)
|
)
|
||||||
|
if markread < 1:
|
||||||
|
markread = sqlExecuteChunked(
|
||||||
|
"UPDATE inbox SET read = 1 WHERE msgid IN({0}) AND read=0",
|
||||||
|
True, idCount, *msgids
|
||||||
|
)
|
||||||
|
|
||||||
if markread > 0:
|
if markread > 0:
|
||||||
self.propagateUnreadCount()
|
self.propagateUnreadCount()
|
||||||
|
@ -2692,7 +2720,7 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
def network_switch(self):
|
def network_switch(self):
|
||||||
dontconnect_option = not config.safeGetBoolean(
|
dontconnect_option = not config.safeGetBoolean(
|
||||||
'bitmessagesettings', 'dontconnect')
|
'bitmessagesettings', 'dontconnect')
|
||||||
reply = QtGui.QMessageBox.question(
|
reply = QtWidgets.QMessageBox.question(
|
||||||
self, _translate("MainWindow", "Disconnecting")
|
self, _translate("MainWindow", "Disconnecting")
|
||||||
if dontconnect_option else _translate("MainWindow", "Connecting"),
|
if dontconnect_option else _translate("MainWindow", "Connecting"),
|
||||||
_translate(
|
_translate(
|
||||||
|
@ -2701,12 +2729,12 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
) if dontconnect_option else _translate(
|
) if dontconnect_option else _translate(
|
||||||
"MainWindow",
|
"MainWindow",
|
||||||
"Bitmessage will now start connecting to network. Are you sure?"
|
"Bitmessage will now start connecting to network. Are you sure?"
|
||||||
), QtGui.QMessageBox.Yes | QtGui.QMessageBox.Cancel,
|
), QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.Cancel,
|
||||||
QtGui.QMessageBox.Cancel)
|
QtWidgets.QMessageBox.Cancel)
|
||||||
if reply != QtGui.QMessageBox.Yes:
|
if reply != QtWidgets.QMessageBox.Yes:
|
||||||
return
|
return
|
||||||
config.set(
|
config.set(
|
||||||
'bitmessagesettings', 'dontconnect', str(dontconnect_option))
|
'bitmessagesettings', 'dontconnect', ustr(dontconnect_option))
|
||||||
config.save()
|
config.save()
|
||||||
self.ui.updateNetworkSwitchMenuLabel(dontconnect_option)
|
self.ui.updateNetworkSwitchMenuLabel(dontconnect_option)
|
||||||
|
|
||||||
|
@ -2729,68 +2757,66 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
waitForSync = False
|
waitForSync = False
|
||||||
|
|
||||||
# C PoW currently doesn't support interrupting and OpenCL is untested
|
# C PoW currently doesn't support interrupting and OpenCL is untested
|
||||||
if getPowType() == "python" and (powQueueSize() > 0 or pendingUpload() > 0):
|
if getPowType() == "python" and (
|
||||||
reply = QtGui.QMessageBox.question(
|
powQueueSize() > 0 or pendingUpload() > 0):
|
||||||
|
reply = QtWidgets.QMessageBox.question(
|
||||||
self, _translate("MainWindow", "Proof of work pending"),
|
self, _translate("MainWindow", "Proof of work pending"),
|
||||||
_translate(
|
_translate(
|
||||||
"MainWindow",
|
"MainWindow",
|
||||||
"%n object(s) pending proof of work", None,
|
"%n object(s) pending proof of work", None, powQueueSize()
|
||||||
QtCore.QCoreApplication.CodecForTr, powQueueSize()
|
) + ", "
|
||||||
) + ", " +
|
+ _translate(
|
||||||
_translate(
|
|
||||||
"MainWindow",
|
"MainWindow",
|
||||||
"%n object(s) waiting to be distributed", None,
|
"%n object(s) waiting to be distributed",
|
||||||
QtCore.QCoreApplication.CodecForTr, pendingUpload()
|
None, pendingUpload()
|
||||||
) + "\n\n" +
|
) + "\n\n"
|
||||||
_translate(
|
+ _translate("MainWindow", "Wait until these tasks finish?"),
|
||||||
"MainWindow", "Wait until these tasks finish?"),
|
QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No
|
||||||
QtGui.QMessageBox.Yes | QtGui.QMessageBox.No
|
| QtWidgets.QMessageBox.Cancel, QtWidgets.QMessageBox.Cancel
|
||||||
| QtGui.QMessageBox.Cancel, QtGui.QMessageBox.Cancel)
|
)
|
||||||
if reply == QtGui.QMessageBox.No:
|
if reply == QtWidgets.QMessageBox.No:
|
||||||
waitForPow = False
|
waitForPow = False
|
||||||
elif reply == QtGui.QMessageBox.Cancel:
|
elif reply == QtWidgets.QMessageBox.Cancel:
|
||||||
return
|
return
|
||||||
|
|
||||||
if pendingDownload() > 0:
|
if pendingDownload() > 0:
|
||||||
reply = QtGui.QMessageBox.question(
|
reply = QtWidgets.QMessageBox.question(
|
||||||
self, _translate("MainWindow", "Synchronisation pending"),
|
self, _translate("MainWindow", "Synchronisation pending"),
|
||||||
_translate(
|
_translate(
|
||||||
"MainWindow",
|
"MainWindow",
|
||||||
"Bitmessage hasn't synchronised with the network,"
|
"Bitmessage hasn't synchronised with the network,"
|
||||||
" %n object(s) to be downloaded. If you quit now,"
|
" %n object(s) to be downloaded. If you quit now,"
|
||||||
" it may cause delivery delays. Wait until the"
|
" it may cause delivery delays. Wait until the"
|
||||||
" synchronisation finishes?", None,
|
" synchronisation finishes?",
|
||||||
QtCore.QCoreApplication.CodecForTr, pendingDownload()
|
None, pendingDownload()
|
||||||
),
|
), QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No
|
||||||
QtGui.QMessageBox.Yes | QtGui.QMessageBox.No
|
| QtWidgets.QMessageBox.Cancel, QtWidgets.QMessageBox.Cancel)
|
||||||
| QtGui.QMessageBox.Cancel, QtGui.QMessageBox.Cancel)
|
if reply == QtWidgets.QMessageBox.Yes:
|
||||||
if reply == QtGui.QMessageBox.Yes:
|
|
||||||
self.wait = waitForSync = True
|
self.wait = waitForSync = True
|
||||||
elif reply == QtGui.QMessageBox.Cancel:
|
elif reply == QtWidgets.QMessageBox.Cancel:
|
||||||
return
|
return
|
||||||
|
|
||||||
if state.statusIconColor == 'red' and not config.safeGetBoolean(
|
if state.statusIconColor == 'red' and not config.safeGetBoolean(
|
||||||
'bitmessagesettings', 'dontconnect'):
|
'bitmessagesettings', 'dontconnect'):
|
||||||
reply = QtGui.QMessageBox.question(
|
reply = QtWidgets.QMessageBox.question(
|
||||||
self, _translate("MainWindow", "Not connected"),
|
self, _translate("MainWindow", "Not connected"),
|
||||||
_translate(
|
_translate(
|
||||||
"MainWindow",
|
"MainWindow",
|
||||||
"Bitmessage isn't connected to the network. If you"
|
"Bitmessage isn't connected to the network. If you"
|
||||||
" quit now, it may cause delivery delays. Wait until"
|
" quit now, it may cause delivery delays. Wait until"
|
||||||
" connected and the synchronisation finishes?"
|
" connected and the synchronisation finishes?"
|
||||||
),
|
), QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No
|
||||||
QtGui.QMessageBox.Yes | QtGui.QMessageBox.No
|
| QtWidgets.QMessageBox.Cancel, QtWidgets.QMessageBox.Cancel)
|
||||||
| QtGui.QMessageBox.Cancel, QtGui.QMessageBox.Cancel)
|
if reply == QtWidgets.QMessageBox.Yes:
|
||||||
if reply == QtGui.QMessageBox.Yes:
|
|
||||||
waitForConnection = True
|
waitForConnection = True
|
||||||
self.wait = waitForSync = True
|
self.wait = waitForSync = True
|
||||||
elif reply == QtGui.QMessageBox.Cancel:
|
elif reply == QtWidgets.QMessageBox.Cancel:
|
||||||
return
|
return
|
||||||
|
|
||||||
self.quitAccepted = True
|
self.quitAccepted = True
|
||||||
|
|
||||||
self.updateStatusBar(_translate(
|
self.updateStatusBar(_translate(
|
||||||
"MainWindow", "Shutting down PyBitmessage... %1%").arg(0))
|
"MainWindow", "Shutting down PyBitmessage... {0}%").format(0))
|
||||||
|
|
||||||
if waitForConnection:
|
if waitForConnection:
|
||||||
self.updateStatusBar(_translate(
|
self.updateStatusBar(_translate(
|
||||||
|
@ -2824,8 +2850,8 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
maxWorkerQueue = curWorkerQueue
|
maxWorkerQueue = curWorkerQueue
|
||||||
if curWorkerQueue > 0:
|
if curWorkerQueue > 0:
|
||||||
self.updateStatusBar(_translate(
|
self.updateStatusBar(_translate(
|
||||||
"MainWindow", "Waiting for PoW to finish... %1%"
|
"MainWindow", "Waiting for PoW to finish... {0}%"
|
||||||
).arg(50 * (maxWorkerQueue - curWorkerQueue) /
|
).format(50 * (maxWorkerQueue - curWorkerQueue) /
|
||||||
maxWorkerQueue))
|
maxWorkerQueue))
|
||||||
time.sleep(0.5)
|
time.sleep(0.5)
|
||||||
QtCore.QCoreApplication.processEvents(
|
QtCore.QCoreApplication.processEvents(
|
||||||
|
@ -2833,7 +2859,7 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
)
|
)
|
||||||
|
|
||||||
self.updateStatusBar(_translate(
|
self.updateStatusBar(_translate(
|
||||||
"MainWindow", "Shutting down Pybitmessage... %1%").arg(50))
|
"MainWindow", "Shutting down Pybitmessage... {0}%").format(50))
|
||||||
|
|
||||||
QtCore.QCoreApplication.processEvents(
|
QtCore.QCoreApplication.processEvents(
|
||||||
QtCore.QEventLoop.AllEvents, 1000
|
QtCore.QEventLoop.AllEvents, 1000
|
||||||
|
@ -2847,34 +2873,32 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
|
|
||||||
# check if upload (of objects created locally) pending
|
# check if upload (of objects created locally) pending
|
||||||
self.updateStatusBar(_translate(
|
self.updateStatusBar(_translate(
|
||||||
"MainWindow", "Waiting for objects to be sent... %1%").arg(50))
|
"MainWindow", "Waiting for objects to be sent... {0}%"
|
||||||
|
).format(50))
|
||||||
maxPendingUpload = max(1, pendingUpload())
|
maxPendingUpload = max(1, pendingUpload())
|
||||||
|
|
||||||
while pendingUpload() > 1:
|
while pendingUpload() > 1:
|
||||||
self.updateStatusBar(_translate(
|
self.updateStatusBar(_translate(
|
||||||
"MainWindow",
|
"MainWindow",
|
||||||
"Waiting for objects to be sent... %1%"
|
"Waiting for objects to be sent... {0}%"
|
||||||
).arg(int(50 + 20 * (pendingUpload() / maxPendingUpload))))
|
).format(int(50 + 20 * pendingUpload() / maxPendingUpload)))
|
||||||
time.sleep(0.5)
|
time.sleep(0.5)
|
||||||
QtCore.QCoreApplication.processEvents(
|
QtCore.QCoreApplication.processEvents(
|
||||||
QtCore.QEventLoop.AllEvents, 1000
|
QtCore.QEventLoop.AllEvents, 1000
|
||||||
)
|
)
|
||||||
|
|
||||||
QtCore.QCoreApplication.processEvents(
|
|
||||||
QtCore.QEventLoop.AllEvents, 1000
|
|
||||||
)
|
|
||||||
QtCore.QCoreApplication.processEvents(
|
QtCore.QCoreApplication.processEvents(
|
||||||
QtCore.QEventLoop.AllEvents, 1000
|
QtCore.QEventLoop.AllEvents, 1000
|
||||||
)
|
)
|
||||||
|
|
||||||
# save state and geometry self and all widgets
|
# save state and geometry self and all widgets
|
||||||
self.updateStatusBar(_translate(
|
self.updateStatusBar(_translate(
|
||||||
"MainWindow", "Saving settings... %1%").arg(70))
|
"MainWindow", "Saving settings... {0}%").format(70))
|
||||||
QtCore.QCoreApplication.processEvents(
|
QtCore.QCoreApplication.processEvents(
|
||||||
QtCore.QEventLoop.AllEvents, 1000
|
QtCore.QEventLoop.AllEvents, 1000
|
||||||
)
|
)
|
||||||
self.saveSettings()
|
self.saveSettings()
|
||||||
for attr, obj in self.ui.__dict__.iteritems():
|
for attr, obj in six.iteritems(self.ui.__dict__):
|
||||||
if hasattr(obj, "__class__") \
|
if hasattr(obj, "__class__") \
|
||||||
and isinstance(obj, settingsmixin.SettingsMixin):
|
and isinstance(obj, settingsmixin.SettingsMixin):
|
||||||
saveMethod = getattr(obj, "saveSettings", None)
|
saveMethod = getattr(obj, "saveSettings", None)
|
||||||
|
@ -2882,18 +2906,18 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
obj.saveSettings()
|
obj.saveSettings()
|
||||||
|
|
||||||
self.updateStatusBar(_translate(
|
self.updateStatusBar(_translate(
|
||||||
"MainWindow", "Shutting down core... %1%").arg(80))
|
"MainWindow", "Shutting down core... {0}%").format(80))
|
||||||
QtCore.QCoreApplication.processEvents(
|
QtCore.QCoreApplication.processEvents(
|
||||||
QtCore.QEventLoop.AllEvents, 1000
|
QtCore.QEventLoop.AllEvents, 1000
|
||||||
)
|
)
|
||||||
shutdown.doCleanShutdown()
|
shutdown.doCleanShutdown()
|
||||||
|
|
||||||
self.updateStatusBar(_translate(
|
self.updateStatusBar(_translate(
|
||||||
"MainWindow", "Stopping notifications... %1%").arg(90))
|
"MainWindow", "Stopping notifications... {0}%").format(90))
|
||||||
self.tray.hide()
|
self.tray.hide()
|
||||||
|
|
||||||
self.updateStatusBar(_translate(
|
self.updateStatusBar(_translate(
|
||||||
"MainWindow", "Shutdown imminent... %1%").arg(100))
|
"MainWindow", "Shutdown imminent... {0}%").format(100))
|
||||||
|
|
||||||
logger.info("Shutdown complete")
|
logger.info("Shutdown complete")
|
||||||
self.close()
|
self.close()
|
||||||
|
@ -2919,26 +2943,39 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
if not msgid:
|
if not msgid:
|
||||||
return
|
return
|
||||||
queryreturn = sqlQuery(
|
queryreturn = sqlQuery(
|
||||||
'''select message from inbox where msgid=?''', msgid)
|
'SELECT message FROM inbox WHERE msgid=?', sqlite3.Binary(msgid))
|
||||||
if queryreturn != []:
|
if len(queryreturn) < 1:
|
||||||
for row in queryreturn:
|
queryreturn = sqlQuery(
|
||||||
messageText, = row
|
'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)
|
totalLines = len(lines)
|
||||||
for i in xrange(totalLines):
|
for i in xrange(totalLines):
|
||||||
if 'Message ostensibly from ' in lines[i]:
|
if 'Message ostensibly from ' in lines[i]:
|
||||||
lines[i] = '<p style="font-size: 12px; color: grey;">%s</span></p>' % (
|
lines[i] = (
|
||||||
lines[i])
|
'<p style="font-size: 12px; color: grey;">%s</span></p>' %
|
||||||
elif lines[i] == '------------------------------------------------------':
|
lines[i]
|
||||||
|
)
|
||||||
|
elif (
|
||||||
|
lines[i]
|
||||||
|
== '------------------------------------------------------'
|
||||||
|
):
|
||||||
lines[i] = '<hr>'
|
lines[i] = '<hr>'
|
||||||
elif lines[i] == '' and (i+1) < totalLines and \
|
elif (
|
||||||
lines[i+1] != '------------------------------------------------------':
|
lines[i] == '' and (i + 1) < totalLines and lines[i + 1]
|
||||||
|
!= '------------------------------------------------------'
|
||||||
|
):
|
||||||
lines[i] = '<br><br>'
|
lines[i] = '<br><br>'
|
||||||
content = ' '.join(lines) # To keep the whitespace between lines
|
content = ' '.join(lines) # To keep the whitespace between lines
|
||||||
content = shared.fixPotentiallyInvalidUTF8Data(content)
|
content = shared.fixPotentiallyInvalidUTF8Data(content)
|
||||||
content = unicode(content, 'utf-8)')
|
content = unic(ustr(content))
|
||||||
textEdit.setHtml(QtCore.QString(content))
|
textEdit.setHtml(content)
|
||||||
|
|
||||||
def on_action_InboxMarkUnread(self):
|
def on_action_InboxMarkUnread(self):
|
||||||
tableWidget = self.getCurrentMessagelist()
|
tableWidget = self.getCurrentMessagelist()
|
||||||
|
@ -2949,8 +2986,8 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
# modified = 0
|
# modified = 0
|
||||||
for row in tableWidget.selectedIndexes():
|
for row in tableWidget.selectedIndexes():
|
||||||
currentRow = row.row()
|
currentRow = row.row()
|
||||||
msgid = tableWidget.item(currentRow, 3).data()
|
msgid = as_msgid(tableWidget.item(currentRow, 3).data())
|
||||||
msgids.add(msgid)
|
msgids.add(sqlite3.Binary(msgid))
|
||||||
# if not tableWidget.item(currentRow, 0).unread:
|
# if not tableWidget.item(currentRow, 0).unread:
|
||||||
# modified += 1
|
# modified += 1
|
||||||
self.updateUnreadStatus(tableWidget, currentRow, msgid, False)
|
self.updateUnreadStatus(tableWidget, currentRow, msgid, False)
|
||||||
|
@ -2958,24 +2995,25 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
# for 1081
|
# for 1081
|
||||||
idCount = len(msgids)
|
idCount = len(msgids)
|
||||||
# rowcount =
|
# rowcount =
|
||||||
sqlExecuteChunked(
|
total_row_count = sqlExecuteChunked(
|
||||||
'''UPDATE inbox SET read=0 WHERE msgid IN ({0}) AND read=1''',
|
'''UPDATE inbox SET read=0 WHERE msgid IN ({0}) AND read=1''',
|
||||||
idCount, *msgids
|
False, idCount, *msgids
|
||||||
)
|
)
|
||||||
|
if total_row_count < 1:
|
||||||
|
sqlExecuteChunked(
|
||||||
|
'''UPDATE inbox SET read=0 WHERE msgid IN ({0}) AND read=1''',
|
||||||
|
True, idCount, *msgids
|
||||||
|
)
|
||||||
|
|
||||||
self.propagateUnreadCount()
|
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.
|
# Format predefined text on message reply.
|
||||||
def quoted_text(self, message):
|
def quoted_text(self, message):
|
||||||
if not config.safeGetBoolean('bitmessagesettings', 'replybelow'):
|
if not config.safeGetBoolean('bitmessagesettings', 'replybelow'):
|
||||||
return '\n\n------------------------------------------------------\n' + message
|
return (
|
||||||
|
'\n\n------------------------------------------------------\n' +
|
||||||
|
message
|
||||||
|
)
|
||||||
|
|
||||||
quoteWrapper = textwrap.TextWrapper(
|
quoteWrapper = textwrap.TextWrapper(
|
||||||
replace_whitespace=False, initial_indent='> ',
|
replace_whitespace=False, initial_indent='> ',
|
||||||
|
@ -3005,7 +3043,7 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
self.ui.comboBoxSendFrom, self.ui.comboBoxSendFromBroadcast
|
self.ui.comboBoxSendFrom, self.ui.comboBoxSendFromBroadcast
|
||||||
):
|
):
|
||||||
for i in range(box.count()):
|
for i in range(box.count()):
|
||||||
if str(box.itemData(i).toPyObject()) == address:
|
if ustr(box.itemData(i)) == ustr(address):
|
||||||
box.setCurrentIndex(i)
|
box.setCurrentIndex(i)
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
|
@ -3039,17 +3077,23 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
acct = accountClass(toAddressAtCurrentInboxRow)
|
acct = accountClass(toAddressAtCurrentInboxRow)
|
||||||
fromAddressAtCurrentInboxRow = tableWidget.item(
|
fromAddressAtCurrentInboxRow = tableWidget.item(
|
||||||
currentInboxRow, column_from).address
|
currentInboxRow, column_from).address
|
||||||
msgid = tableWidget.item(currentInboxRow, 3).data()
|
msgid = as_msgid(tableWidget.item(currentInboxRow, 3).data())
|
||||||
queryreturn = sqlQuery(
|
queryreturn = sqlQuery(
|
||||||
"SELECT message FROM inbox WHERE msgid=?", msgid
|
"SELECT message FROM inbox WHERE msgid=?", sqlite3.Binary(msgid)
|
||||||
) or sqlQuery("SELECT message FROM sent WHERE ackdata=?", msgid)
|
) or sqlQuery("SELECT message FROM sent WHERE ackdata=?", sqlite3.Binary(msgid))
|
||||||
|
if len(queryreturn) < 1:
|
||||||
|
queryreturn = sqlQuery(
|
||||||
|
"SELECT message FROM inbox WHERE msgid=CAST(? AS TEXT)", msgid
|
||||||
|
) or sqlQuery("SELECT message FROM sent WHERE ackdata=CAST(? AS TEXT)", msgid)
|
||||||
if queryreturn != []:
|
if queryreturn != []:
|
||||||
for row in queryreturn:
|
for row in queryreturn:
|
||||||
messageAtCurrentInboxRow, = row
|
messageAtCurrentInboxRow, = row
|
||||||
|
messageAtCurrentInboxRow = messageAtCurrentInboxRow.decode("utf-8", "replace")
|
||||||
acct.parseMessage(
|
acct.parseMessage(
|
||||||
toAddressAtCurrentInboxRow, fromAddressAtCurrentInboxRow,
|
toAddressAtCurrentInboxRow, fromAddressAtCurrentInboxRow,
|
||||||
tableWidget.item(currentInboxRow, 2).subject,
|
tableWidget.item(currentInboxRow, 2).subject,
|
||||||
messageAtCurrentInboxRow)
|
messageAtCurrentInboxRow
|
||||||
|
)
|
||||||
widget = {
|
widget = {
|
||||||
'subject': self.ui.lineEditSubject,
|
'subject': self.ui.lineEditSubject,
|
||||||
'from': self.ui.comboBoxSendFrom,
|
'from': self.ui.comboBoxSendFrom,
|
||||||
|
@ -3062,23 +3106,26 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
)
|
)
|
||||||
# toAddressAtCurrentInboxRow = fromAddressAtCurrentInboxRow
|
# toAddressAtCurrentInboxRow = fromAddressAtCurrentInboxRow
|
||||||
elif not config.has_section(toAddressAtCurrentInboxRow):
|
elif not config.has_section(toAddressAtCurrentInboxRow):
|
||||||
QtGui.QMessageBox.information(
|
QtWidgets.QMessageBox.information(
|
||||||
self, _translate("MainWindow", "Address is gone"),
|
self,
|
||||||
|
_translate("MainWindow", "Address is gone"),
|
||||||
_translate(
|
_translate(
|
||||||
"MainWindow",
|
"MainWindow",
|
||||||
"Bitmessage cannot find your address %1. Perhaps you"
|
"Bitmessage cannot find your address {0}. Perhaps you"
|
||||||
" removed it?"
|
" removed it?"
|
||||||
).arg(toAddressAtCurrentInboxRow), QtGui.QMessageBox.Ok)
|
).format(toAddressAtCurrentInboxRow),
|
||||||
|
QtWidgets.QMessageBox.Ok)
|
||||||
elif not config.getboolean(
|
elif not config.getboolean(
|
||||||
toAddressAtCurrentInboxRow, 'enabled'):
|
toAddressAtCurrentInboxRow, 'enabled'):
|
||||||
QtGui.QMessageBox.information(
|
QtWidgets.QMessageBox.information(
|
||||||
self, _translate("MainWindow", "Address disabled"),
|
self,
|
||||||
|
_translate("MainWindow", "Address disabled"),
|
||||||
_translate(
|
_translate(
|
||||||
"MainWindow",
|
"MainWindow",
|
||||||
"Error: The address from which you are trying to send"
|
"Error: The address from which you are trying to send"
|
||||||
" is disabled. You\'ll have to enable it on the"
|
" is disabled. You\'ll have to enable it on the \'Your"
|
||||||
" \'Your Identities\' tab before using it."
|
" Identities\' tab before using it."
|
||||||
), QtGui.QMessageBox.Ok)
|
), QtWidgets.QMessageBox.Ok)
|
||||||
else:
|
else:
|
||||||
self.setBroadcastEnablementDependingOnWhetherThisIsAMailingListAddress(toAddressAtCurrentInboxRow)
|
self.setBroadcastEnablementDependingOnWhetherThisIsAMailingListAddress(toAddressAtCurrentInboxRow)
|
||||||
broadcast_tab_index = self.ui.tabWidgetSend.indexOf(
|
broadcast_tab_index = self.ui.tabWidgetSend.indexOf(
|
||||||
|
@ -3096,7 +3143,7 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
tableWidget.item(currentInboxRow, column_from).label or (
|
tableWidget.item(currentInboxRow, column_from).label or (
|
||||||
isinstance(acct, GatewayAccount) and
|
isinstance(acct, GatewayAccount) and
|
||||||
fromAddressAtCurrentInboxRow == acct.relayAddress):
|
fromAddressAtCurrentInboxRow == acct.relayAddress):
|
||||||
self.ui.lineEditTo.setText(str(acct.fromAddress))
|
self.ui.lineEditTo.setText(ustr(acct.fromAddress))
|
||||||
else:
|
else:
|
||||||
self.ui.lineEditTo.setText(
|
self.ui.lineEditTo.setText(
|
||||||
tableWidget.item(currentInboxRow, column_from).accountString()
|
tableWidget.item(currentInboxRow, column_from).accountString()
|
||||||
|
@ -3111,7 +3158,7 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
' reply to the chan address.')
|
' reply to the chan address.')
|
||||||
if toAddressAtCurrentInboxRow == \
|
if toAddressAtCurrentInboxRow == \
|
||||||
tableWidget.item(currentInboxRow, column_to).label:
|
tableWidget.item(currentInboxRow, column_to).label:
|
||||||
self.ui.lineEditTo.setText(str(toAddressAtCurrentInboxRow))
|
self.ui.lineEditTo.setText(ustr(toAddressAtCurrentInboxRow))
|
||||||
else:
|
else:
|
||||||
self.ui.lineEditTo.setText(
|
self.ui.lineEditTo.setText(
|
||||||
tableWidget.item(currentInboxRow, column_to).accountString()
|
tableWidget.item(currentInboxRow, column_to).accountString()
|
||||||
|
@ -3120,7 +3167,7 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
self.setSendFromComboBox(toAddressAtCurrentInboxRow)
|
self.setSendFromComboBox(toAddressAtCurrentInboxRow)
|
||||||
|
|
||||||
quotedText = self.quoted_text(
|
quotedText = self.quoted_text(
|
||||||
unicode(messageAtCurrentInboxRow, 'utf-8', 'replace'))
|
unic(ustr(messageAtCurrentInboxRow)))
|
||||||
widget['message'].setPlainText(quotedText)
|
widget['message'].setPlainText(quotedText)
|
||||||
if acct.subject[0:3] in ('Re:', 'RE:'):
|
if acct.subject[0:3] in ('Re:', 'RE:'):
|
||||||
widget['subject'].setText(
|
widget['subject'].setText(
|
||||||
|
@ -3156,14 +3203,15 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
recipientAddress = tableWidget.item(
|
recipientAddress = tableWidget.item(
|
||||||
currentInboxRow, 0).data(QtCore.Qt.UserRole)
|
currentInboxRow, 0).data(QtCore.Qt.UserRole)
|
||||||
# Let's make sure that it isn't already in the address book
|
# Let's make sure that it isn't already in the address book
|
||||||
queryreturn = sqlQuery('''select * from blacklist where address=?''',
|
queryreturn = sqlQuery(
|
||||||
addressAtCurrentInboxRow)
|
'SELECT * FROM blacklist WHERE address=?',
|
||||||
|
dbstr(addressAtCurrentInboxRow))
|
||||||
if queryreturn == []:
|
if queryreturn == []:
|
||||||
label = "\"" + tableWidget.item(currentInboxRow, 2).subject + "\" in " + config.get(
|
label = "\"" + tableWidget.item(currentInboxRow, 2).subject + "\" in " + config.get(
|
||||||
recipientAddress, "label")
|
recipientAddress, "label")
|
||||||
sqlExecute('''INSERT INTO blacklist VALUES (?,?, ?)''',
|
sqlExecute('''INSERT INTO blacklist VALUES (?,?, ?)''',
|
||||||
label,
|
dbstr(label),
|
||||||
addressAtCurrentInboxRow, True)
|
dbstr(addressAtCurrentInboxRow), True)
|
||||||
self.ui.blackwhitelist.rerenderBlackWhiteList()
|
self.ui.blackwhitelist.rerenderBlackWhiteList()
|
||||||
self.updateStatusBar(_translate(
|
self.updateStatusBar(_translate(
|
||||||
"MainWindow",
|
"MainWindow",
|
||||||
|
@ -3188,15 +3236,15 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
messageLists = (messageLists,)
|
messageLists = (messageLists,)
|
||||||
for messageList in messageLists:
|
for messageList in messageLists:
|
||||||
if row is not None:
|
if row is not None:
|
||||||
inventoryHash = messageList.item(row, 3).data()
|
inventoryHash = as_msgid(messageList.item(row, 3).data())
|
||||||
messageList.removeRow(row)
|
messageList.removeRow(row)
|
||||||
elif inventoryHash is not None:
|
elif inventoryHash is not None:
|
||||||
for i in range(messageList.rowCount() - 1, -1, -1):
|
for i in range(messageList.rowCount() - 1, -1, -1):
|
||||||
if messageList.item(i, 3).data() == inventoryHash:
|
if as_msgid(messageList.item(i, 3).data()) == inventoryHash:
|
||||||
messageList.removeRow(i)
|
messageList.removeRow(i)
|
||||||
elif ackData is not None:
|
elif ackData is not None:
|
||||||
for i in range(messageList.rowCount() - 1, -1, -1):
|
for i in range(messageList.rowCount() - 1, -1, -1):
|
||||||
if messageList.item(i, 3).data() == ackData:
|
if as_msgid(messageList.item(i, 3).data()) == ackData:
|
||||||
messageList.removeRow(i)
|
messageList.removeRow(i)
|
||||||
|
|
||||||
# Send item on the Inbox tab to trash
|
# Send item on the Inbox tab to trash
|
||||||
|
@ -3206,8 +3254,8 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
return
|
return
|
||||||
currentRow = 0
|
currentRow = 0
|
||||||
folder = self.getCurrentFolder()
|
folder = self.getCurrentFolder()
|
||||||
shifted = QtGui.QApplication.queryKeyboardModifiers() \
|
shifted = (QtWidgets.QApplication.queryKeyboardModifiers() &
|
||||||
& QtCore.Qt.ShiftModifier
|
QtCore.Qt.ShiftModifier)
|
||||||
tableWidget.setUpdatesEnabled(False)
|
tableWidget.setUpdatesEnabled(False)
|
||||||
inventoryHashesToTrash = set()
|
inventoryHashesToTrash = set()
|
||||||
# ranges in reversed order
|
# ranges in reversed order
|
||||||
|
@ -3216,16 +3264,21 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
)[::-1]:
|
)[::-1]:
|
||||||
for i in range(r.bottomRow() - r.topRow() + 1):
|
for i in range(r.bottomRow() - r.topRow() + 1):
|
||||||
inventoryHashesToTrash.add(
|
inventoryHashesToTrash.add(
|
||||||
tableWidget.item(r.topRow() + i, 3).data())
|
sqlite3.Binary(as_msgid(tableWidget.item(r.topRow() + i, 3).data())))
|
||||||
currentRow = r.topRow()
|
currentRow = r.topRow()
|
||||||
self.getCurrentMessageTextedit().setText("")
|
self.getCurrentMessageTextedit().setText("")
|
||||||
tableWidget.model().removeRows(
|
tableWidget.model().removeRows(
|
||||||
r.topRow(), r.bottomRow() - r.topRow() + 1)
|
r.topRow(), r.bottomRow() - r.topRow() + 1)
|
||||||
idCount = len(inventoryHashesToTrash)
|
idCount = len(inventoryHashesToTrash)
|
||||||
sqlExecuteChunked(
|
total_row_count = sqlExecuteChunked(
|
||||||
("DELETE FROM inbox" if folder == "trash" or shifted else
|
("DELETE FROM inbox" if folder == "trash" or shifted else
|
||||||
"UPDATE inbox SET folder='trash', read=1") +
|
"UPDATE inbox SET folder='trash', read=1") +
|
||||||
" WHERE msgid IN ({0})", idCount, *inventoryHashesToTrash)
|
" WHERE msgid IN ({0})", 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})", True, idCount, *inventoryHashesToTrash)
|
||||||
tableWidget.selectRow(0 if currentRow == 0 else currentRow - 1)
|
tableWidget.selectRow(0 if currentRow == 0 else currentRow - 1)
|
||||||
tableWidget.setUpdatesEnabled(True)
|
tableWidget.setUpdatesEnabled(True)
|
||||||
self.propagateUnreadCount(folder)
|
self.propagateUnreadCount(folder)
|
||||||
|
@ -3244,16 +3297,20 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
)[::-1]:
|
)[::-1]:
|
||||||
for i in range(r.bottomRow() - r.topRow() + 1):
|
for i in range(r.bottomRow() - r.topRow() + 1):
|
||||||
inventoryHashesToTrash.add(
|
inventoryHashesToTrash.add(
|
||||||
tableWidget.item(r.topRow() + i, 3).data())
|
sqlite3.Binary(as_msgid(tableWidget.item(r.topRow() + i, 3).data())))
|
||||||
currentRow = r.topRow()
|
currentRow = r.topRow()
|
||||||
self.getCurrentMessageTextedit().setText("")
|
self.getCurrentMessageTextedit().setText("")
|
||||||
tableWidget.model().removeRows(
|
tableWidget.model().removeRows(
|
||||||
r.topRow(), r.bottomRow() - r.topRow() + 1)
|
r.topRow(), r.bottomRow() - r.topRow() + 1)
|
||||||
tableWidget.selectRow(0 if currentRow == 0 else currentRow - 1)
|
tableWidget.selectRow(0 if currentRow == 0 else currentRow - 1)
|
||||||
idCount = len(inventoryHashesToTrash)
|
idCount = len(inventoryHashesToTrash)
|
||||||
sqlExecuteChunked(
|
total_row_count = sqlExecuteChunked(
|
||||||
"UPDATE inbox SET folder='inbox' WHERE msgid IN({0})",
|
"UPDATE inbox SET folder='inbox' WHERE msgid IN({0})",
|
||||||
idCount, *inventoryHashesToTrash)
|
False, idCount, *inventoryHashesToTrash)
|
||||||
|
if total_row_count < 1:
|
||||||
|
sqlExecuteChunked(
|
||||||
|
"UPDATE inbox SET folder='inbox' WHERE msgid IN({0})",
|
||||||
|
True, idCount, *inventoryHashesToTrash)
|
||||||
tableWidget.selectRow(0 if currentRow == 0 else currentRow - 1)
|
tableWidget.selectRow(0 if currentRow == 0 else currentRow - 1)
|
||||||
tableWidget.setUpdatesEnabled(True)
|
tableWidget.setUpdatesEnabled(True)
|
||||||
self.propagateUnreadCount()
|
self.propagateUnreadCount()
|
||||||
|
@ -3265,30 +3322,33 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
return
|
return
|
||||||
currentInboxRow = tableWidget.currentRow()
|
currentInboxRow = tableWidget.currentRow()
|
||||||
try:
|
try:
|
||||||
subjectAtCurrentInboxRow = str(tableWidget.item(
|
subjectAtCurrentInboxRow = ustr(tableWidget.item(
|
||||||
currentInboxRow, 2).data(QtCore.Qt.UserRole))
|
currentInboxRow, 2).data(QtCore.Qt.UserRole))
|
||||||
except:
|
except:
|
||||||
subjectAtCurrentInboxRow = ''
|
subjectAtCurrentInboxRow = ''
|
||||||
|
|
||||||
# Retrieve the message data out of the SQL database
|
# Retrieve the message data out of the SQL database
|
||||||
msgid = tableWidget.item(currentInboxRow, 3).data()
|
msgid = as_msgid(tableWidget.item(currentInboxRow, 3).data())
|
||||||
queryreturn = sqlQuery(
|
queryreturn = sqlQuery(
|
||||||
'''select message from inbox where msgid=?''', msgid)
|
'SELECT message FROM inbox WHERE msgid=?', sqlite3.Binary(msgid))
|
||||||
|
if len(queryreturn) < 1:
|
||||||
|
queryreturn = sqlQuery(
|
||||||
|
'SELECT message FROM inbox WHERE msgid=CAST(? AS TEXT)', msgid)
|
||||||
if queryreturn != []:
|
if queryreturn != []:
|
||||||
for row in queryreturn:
|
for row in queryreturn:
|
||||||
message, = row
|
message, = row
|
||||||
|
message = message.decode("utf-8", "replace")
|
||||||
|
|
||||||
defaultFilename = "".join(x for x in subjectAtCurrentInboxRow if x.isalnum()) + '.txt'
|
defaultFilename = "".join(
|
||||||
filename = QtGui.QFileDialog.getSaveFileName(
|
x for x in subjectAtCurrentInboxRow if x.isalnum()) + '.txt'
|
||||||
self,
|
filename = QtWidgets.QFileDialog.getSaveFileName(
|
||||||
_translate("MainWindow","Save As..."),
|
self, _translate("MainWindow", "Save As..."), defaultFilename,
|
||||||
defaultFilename,
|
"Text files (*.txt);;All files (*.*)")[0]
|
||||||
"Text files (*.txt);;All files (*.*)")
|
if not filename:
|
||||||
if filename == '':
|
|
||||||
return
|
return
|
||||||
try:
|
try:
|
||||||
f = open(filename, 'w')
|
f = open(filename, 'w')
|
||||||
f.write(message)
|
f.write(message.encode("utf-8", "replace"))
|
||||||
f.close()
|
f.close()
|
||||||
except Exception:
|
except Exception:
|
||||||
logger.exception('Message not saved', exc_info=True)
|
logger.exception('Message not saved', exc_info=True)
|
||||||
|
@ -3296,19 +3356,27 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
|
|
||||||
# Send item on the Sent tab to trash
|
# Send item on the Sent tab to trash
|
||||||
def on_action_SentTrash(self):
|
def on_action_SentTrash(self):
|
||||||
|
currentRow = 0
|
||||||
tableWidget = self.getCurrentMessagelist()
|
tableWidget = self.getCurrentMessagelist()
|
||||||
if not tableWidget:
|
if not tableWidget:
|
||||||
return
|
return
|
||||||
folder = self.getCurrentFolder()
|
folder = self.getCurrentFolder()
|
||||||
shifted = QtGui.QApplication.queryKeyboardModifiers() & QtCore.Qt.ShiftModifier
|
shifted = (QtWidgets.QApplication.queryKeyboardModifiers() &
|
||||||
|
QtCore.Qt.ShiftModifier)
|
||||||
while tableWidget.selectedIndexes() != []:
|
while tableWidget.selectedIndexes() != []:
|
||||||
currentRow = tableWidget.selectedIndexes()[0].row()
|
currentRow = tableWidget.selectedIndexes()[0].row()
|
||||||
ackdataToTrash = tableWidget.item(currentRow, 3).data()
|
ackdataToTrash = as_msgid(tableWidget.item(currentRow, 3).data())
|
||||||
sqlExecute(
|
rowcount = sqlExecute(
|
||||||
"DELETE FROM sent" if folder == "trash" or shifted else
|
"DELETE FROM sent" if folder == "trash" or shifted else
|
||||||
"UPDATE sent SET folder='trash'"
|
"UPDATE sent SET folder='trash'"
|
||||||
" WHERE ackdata = ?", ackdataToTrash
|
" WHERE ackdata = ?", sqlite3.Binary(ackdataToTrash)
|
||||||
)
|
)
|
||||||
|
if rowcount < 1:
|
||||||
|
sqlExecute(
|
||||||
|
"DELETE FROM sent" if folder == "trash" or shifted else
|
||||||
|
"UPDATE sent SET folder='trash'"
|
||||||
|
" WHERE ackdata = CAST(? AS TEXT)", ackdataToTrash
|
||||||
|
)
|
||||||
self.getCurrentMessageTextedit().setPlainText("")
|
self.getCurrentMessageTextedit().setPlainText("")
|
||||||
tableWidget.removeRow(currentRow)
|
tableWidget.removeRow(currentRow)
|
||||||
self.updateStatusBar(_translate(
|
self.updateStatusBar(_translate(
|
||||||
|
@ -3322,22 +3390,29 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
addressAtCurrentRow = self.ui.tableWidgetInbox.item(
|
addressAtCurrentRow = self.ui.tableWidgetInbox.item(
|
||||||
currentRow, 0).data(QtCore.Qt.UserRole)
|
currentRow, 0).data(QtCore.Qt.UserRole)
|
||||||
toRipe = decodeAddress(addressAtCurrentRow)[3]
|
toRipe = decodeAddress(addressAtCurrentRow)[3]
|
||||||
sqlExecute(
|
rowcount = sqlExecute(
|
||||||
'''UPDATE sent SET status='forcepow' WHERE toripe=? AND status='toodifficult' and folder='sent' ''',
|
'''UPDATE sent SET status='forcepow' WHERE toripe=? AND status='toodifficult' and folder='sent' ''',
|
||||||
toRipe)
|
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' ''')
|
queryreturn = sqlQuery('''select ackdata FROM sent WHERE status='forcepow' ''')
|
||||||
for row in queryreturn:
|
for row in queryreturn:
|
||||||
ackdata, = row
|
ackdata, = row
|
||||||
queues.UISignalQueue.put(('updateSentItemStatusByAckdata', (
|
queues.UISignalQueue.put((
|
||||||
ackdata, 'Overriding maximum-difficulty setting. Work queued.')))
|
'updateSentItemStatusByAckdata',
|
||||||
|
(ackdata, 'Overriding maximum-difficulty setting.'
|
||||||
|
' Work queued.')
|
||||||
|
))
|
||||||
queues.workerQueue.put(('sendmessage', ''))
|
queues.workerQueue.put(('sendmessage', ''))
|
||||||
|
|
||||||
def on_action_SentClipboard(self):
|
def on_action_SentClipboard(self):
|
||||||
currentRow = self.ui.tableWidgetInbox.currentRow()
|
currentRow = self.ui.tableWidgetInbox.currentRow()
|
||||||
addressAtCurrentRow = self.ui.tableWidgetInbox.item(
|
addressAtCurrentRow = self.ui.tableWidgetInbox.item(
|
||||||
currentRow, 0).data(QtCore.Qt.UserRole)
|
currentRow, 0).data(QtCore.Qt.UserRole)
|
||||||
clipboard = QtGui.QApplication.clipboard()
|
clipboard = QtWidgets.QApplication.clipboard()
|
||||||
clipboard.setText(str(addressAtCurrentRow))
|
clipboard.setText(ustr(addressAtCurrentRow))
|
||||||
|
|
||||||
# Group of functions for the Address Book dialog box
|
# Group of functions for the Address Book dialog box
|
||||||
def on_action_AddressBookNew(self):
|
def on_action_AddressBookNew(self):
|
||||||
|
@ -3349,7 +3424,7 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
0].row()
|
0].row()
|
||||||
item = self.ui.tableWidgetAddressBook.item(currentRow, 0)
|
item = self.ui.tableWidgetAddressBook.item(currentRow, 0)
|
||||||
sqlExecute(
|
sqlExecute(
|
||||||
'DELETE FROM addressbook WHERE address=?', item.address)
|
'DELETE FROM addressbook WHERE address=?', dbstr(item.address))
|
||||||
self.ui.tableWidgetAddressBook.removeRow(currentRow)
|
self.ui.tableWidgetAddressBook.removeRow(currentRow)
|
||||||
self.rerenderMessagelistFromLabels()
|
self.rerenderMessagelistFromLabels()
|
||||||
self.rerenderMessagelistToLabels()
|
self.rerenderMessagelistToLabels()
|
||||||
|
@ -3361,7 +3436,7 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
addresses_string = item.address
|
addresses_string = item.address
|
||||||
else:
|
else:
|
||||||
addresses_string += ', ' + item.address
|
addresses_string += ', ' + item.address
|
||||||
clipboard = QtGui.QApplication.clipboard()
|
clipboard = QtWidgets.QApplication.clipboard()
|
||||||
clipboard.setText(addresses_string)
|
clipboard.setText(addresses_string)
|
||||||
|
|
||||||
def on_action_AddressBookSend(self):
|
def on_action_AddressBookSend(self):
|
||||||
|
@ -3371,8 +3446,7 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
return self.updateStatusBar(_translate(
|
return self.updateStatusBar(_translate(
|
||||||
"MainWindow", "No addresses selected."))
|
"MainWindow", "No addresses selected."))
|
||||||
|
|
||||||
addresses_string = unicode(
|
addresses_string = unic(ustr(self.ui.lineEditTo.text()))
|
||||||
self.ui.lineEditTo.text().toUtf8(), 'utf-8')
|
|
||||||
for item in selected_items:
|
for item in selected_items:
|
||||||
address_string = item.accountString()
|
address_string = item.accountString()
|
||||||
if not addresses_string:
|
if not addresses_string:
|
||||||
|
@ -3403,7 +3477,7 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
)
|
)
|
||||||
|
|
||||||
def on_context_menuAddressBook(self, point):
|
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.actionAddressBookSend)
|
||||||
self.popMenuAddressBook.addAction(self.actionAddressBookClipboard)
|
self.popMenuAddressBook.addAction(self.actionAddressBookClipboard)
|
||||||
self.popMenuAddressBook.addAction(self.actionAddressBookSubscribe)
|
self.popMenuAddressBook.addAction(self.actionAddressBookSubscribe)
|
||||||
|
@ -3433,7 +3507,7 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
self.click_pushButtonAddSubscription()
|
self.click_pushButtonAddSubscription()
|
||||||
|
|
||||||
def on_action_SubscriptionsDelete(self):
|
def on_action_SubscriptionsDelete(self):
|
||||||
if QtGui.QMessageBox.question(
|
if QtWidgets.QMessageBox.question(
|
||||||
self, "Delete subscription?",
|
self, "Delete subscription?",
|
||||||
_translate(
|
_translate(
|
||||||
"MainWindow",
|
"MainWindow",
|
||||||
|
@ -3444,12 +3518,12 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
" messages, but you can still view messages you"
|
" messages, but you can still view messages you"
|
||||||
" already received.\n\nAre you sure you want to"
|
" already received.\n\nAre you sure you want to"
|
||||||
" delete the subscription?"
|
" delete the subscription?"
|
||||||
), QtGui.QMessageBox.Yes | QtGui.QMessageBox.No
|
), QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No
|
||||||
) != QtGui.QMessageBox.Yes:
|
) != QtWidgets.QMessageBox.Yes:
|
||||||
return
|
return
|
||||||
address = self.getCurrentAccount()
|
address = self.getCurrentAccount()
|
||||||
sqlExecute('''DELETE FROM subscriptions WHERE address=?''',
|
sqlExecute('''DELETE FROM subscriptions WHERE address=?''',
|
||||||
address)
|
dbstr(address))
|
||||||
self.rerenderTabTreeSubscriptions()
|
self.rerenderTabTreeSubscriptions()
|
||||||
self.rerenderMessagelistFromLabels()
|
self.rerenderMessagelistFromLabels()
|
||||||
self.rerenderAddressBook()
|
self.rerenderAddressBook()
|
||||||
|
@ -3457,14 +3531,14 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
|
|
||||||
def on_action_SubscriptionsClipboard(self):
|
def on_action_SubscriptionsClipboard(self):
|
||||||
address = self.getCurrentAccount()
|
address = self.getCurrentAccount()
|
||||||
clipboard = QtGui.QApplication.clipboard()
|
clipboard = QtWidgets.QApplication.clipboard()
|
||||||
clipboard.setText(str(address))
|
clipboard.setText(ustr(address))
|
||||||
|
|
||||||
def on_action_SubscriptionsEnable(self):
|
def on_action_SubscriptionsEnable(self):
|
||||||
address = self.getCurrentAccount()
|
address = self.getCurrentAccount()
|
||||||
sqlExecute(
|
sqlExecute(
|
||||||
'''update subscriptions set enabled=1 WHERE address=?''',
|
'''update subscriptions set enabled=1 WHERE address=?''',
|
||||||
address)
|
dbstr(address))
|
||||||
account = self.getCurrentItem()
|
account = self.getCurrentItem()
|
||||||
account.setEnabled(True)
|
account.setEnabled(True)
|
||||||
self.rerenderAddressBook()
|
self.rerenderAddressBook()
|
||||||
|
@ -3474,7 +3548,7 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
address = self.getCurrentAccount()
|
address = self.getCurrentAccount()
|
||||||
sqlExecute(
|
sqlExecute(
|
||||||
'''update subscriptions set enabled=0 WHERE address=?''',
|
'''update subscriptions set enabled=0 WHERE address=?''',
|
||||||
address)
|
dbstr(address))
|
||||||
account = self.getCurrentItem()
|
account = self.getCurrentItem()
|
||||||
account.setEnabled(False)
|
account.setEnabled(False)
|
||||||
self.rerenderAddressBook()
|
self.rerenderAddressBook()
|
||||||
|
@ -3482,7 +3556,7 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
|
|
||||||
def on_context_menuSubscriptions(self, point):
|
def on_context_menuSubscriptions(self, point):
|
||||||
currentItem = self.getCurrentItem()
|
currentItem = self.getCurrentItem()
|
||||||
self.popMenuSubscriptions = QtGui.QMenu(self)
|
self.popMenuSubscriptions = QtWidgets.QMenu(self)
|
||||||
if isinstance(currentItem, Ui_AddressWidget):
|
if isinstance(currentItem, Ui_AddressWidget):
|
||||||
self.popMenuSubscriptions.addAction(self.actionsubscriptionsNew)
|
self.popMenuSubscriptions.addAction(self.actionsubscriptionsNew)
|
||||||
self.popMenuSubscriptions.addAction(self.actionsubscriptionsDelete)
|
self.popMenuSubscriptions.addAction(self.actionsubscriptionsDelete)
|
||||||
|
@ -3522,8 +3596,6 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
return self.ui.tableWidgetInboxSubscriptions
|
return self.ui.tableWidgetInboxSubscriptions
|
||||||
elif widget == self.ui.treeWidgetChans:
|
elif widget == self.ui.treeWidgetChans:
|
||||||
return self.ui.tableWidgetInboxChans
|
return self.ui.tableWidgetInboxChans
|
||||||
else:
|
|
||||||
return None
|
|
||||||
|
|
||||||
def getCurrentTreeWidget(self):
|
def getCurrentTreeWidget(self):
|
||||||
currentIndex = self.ui.tabWidget.currentIndex()
|
currentIndex = self.ui.tabWidget.currentIndex()
|
||||||
|
@ -3576,7 +3648,7 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
if messagelist:
|
if messagelist:
|
||||||
currentRow = messagelist.currentRow()
|
currentRow = messagelist.currentRow()
|
||||||
if currentRow >= 0:
|
if currentRow >= 0:
|
||||||
return messagelist.item(currentRow, 3).data()
|
return as_msgid(messagelist.item(currentRow, 3).data())
|
||||||
|
|
||||||
def getCurrentMessageTextedit(self):
|
def getCurrentMessageTextedit(self):
|
||||||
currentIndex = self.ui.tabWidget.currentIndex()
|
currentIndex = self.ui.tabWidget.currentIndex()
|
||||||
|
@ -3610,9 +3682,9 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
self.ui.inboxSearchLineEditChans,
|
self.ui.inboxSearchLineEditChans,
|
||||||
)
|
)
|
||||||
if currentIndex >= 0 and currentIndex < len(messagelistList):
|
if currentIndex >= 0 and currentIndex < len(messagelistList):
|
||||||
return (
|
return ustr(
|
||||||
messagelistList[currentIndex] if retObj
|
messagelistList[currentIndex] if retObj
|
||||||
else messagelistList[currentIndex].text().toUtf8().data())
|
else ustr(messagelistList[currentIndex].text()))
|
||||||
|
|
||||||
def getCurrentSearchOption(self, currentIndex=None):
|
def getCurrentSearchOption(self, currentIndex=None):
|
||||||
if currentIndex is None:
|
if currentIndex is None:
|
||||||
|
@ -3668,7 +3740,7 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
if account.type == AccountMixin.NORMAL:
|
if account.type == AccountMixin.NORMAL:
|
||||||
return # maybe in the future
|
return # maybe in the future
|
||||||
elif account.type == AccountMixin.CHAN:
|
elif account.type == AccountMixin.CHAN:
|
||||||
if QtGui.QMessageBox.question(
|
if QtWidgets.QMessageBox.question(
|
||||||
self, "Delete channel?",
|
self, "Delete channel?",
|
||||||
_translate(
|
_translate(
|
||||||
"MainWindow",
|
"MainWindow",
|
||||||
|
@ -3679,9 +3751,9 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
" messages, but you can still view messages you"
|
" messages, but you can still view messages you"
|
||||||
" already received.\n\nAre you sure you want to"
|
" already received.\n\nAre you sure you want to"
|
||||||
" delete the channel?"
|
" delete the channel?"
|
||||||
), QtGui.QMessageBox.Yes | QtGui.QMessageBox.No
|
), QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No
|
||||||
) == QtGui.QMessageBox.Yes:
|
) == QtWidgets.QMessageBox.Yes:
|
||||||
config.remove_section(str(account.address))
|
config.remove_section(ustr(account.address))
|
||||||
else:
|
else:
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
|
@ -3714,15 +3786,15 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
account.setEnabled(False)
|
account.setEnabled(False)
|
||||||
|
|
||||||
def disableIdentity(self, address):
|
def disableIdentity(self, address):
|
||||||
config.set(str(address), 'enabled', 'false')
|
config.set(ustr(address), 'enabled', 'false')
|
||||||
config.save()
|
config.save()
|
||||||
shared.reloadMyAddressHashes()
|
shared.reloadMyAddressHashes()
|
||||||
self.rerenderAddressBook()
|
self.rerenderAddressBook()
|
||||||
|
|
||||||
def on_action_Clipboard(self):
|
def on_action_Clipboard(self):
|
||||||
address = self.getCurrentAccount()
|
address = self.getCurrentAccount()
|
||||||
clipboard = QtGui.QApplication.clipboard()
|
clipboard = QtWidgets.QApplication.clipboard()
|
||||||
clipboard.setText(str(address))
|
clipboard.setText(ustr(address))
|
||||||
|
|
||||||
def on_action_ClipboardMessagelist(self):
|
def on_action_ClipboardMessagelist(self):
|
||||||
tableWidget = self.getCurrentMessagelist()
|
tableWidget = self.getCurrentMessagelist()
|
||||||
|
@ -3739,14 +3811,14 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
myAddress = tableWidget.item(currentRow, 0).data(QtCore.Qt.UserRole)
|
myAddress = tableWidget.item(currentRow, 0).data(QtCore.Qt.UserRole)
|
||||||
otherAddress = tableWidget.item(currentRow, 1).data(QtCore.Qt.UserRole)
|
otherAddress = tableWidget.item(currentRow, 1).data(QtCore.Qt.UserRole)
|
||||||
account = accountClass(myAddress)
|
account = accountClass(myAddress)
|
||||||
if isinstance(account, GatewayAccount) and otherAddress == account.relayAddress and (
|
if isinstance(account, GatewayAccount) \
|
||||||
(currentColumn in [0, 2] and self.getCurrentFolder() == "sent") or
|
and otherAddress == account.relayAddress and (
|
||||||
(currentColumn in [1, 2] and self.getCurrentFolder() != "sent")):
|
(currentColumn in (0, 2) and currentFolder == "sent") or
|
||||||
text = str(tableWidget.item(currentRow, currentColumn).label)
|
(currentColumn in (1, 2) and currentFolder != "sent")):
|
||||||
|
text = ustr(tableWidget.item(currentRow, currentColumn).label)
|
||||||
else:
|
else:
|
||||||
text = tableWidget.item(currentRow, currentColumn).data(QtCore.Qt.UserRole)
|
text = ustr(tableWidget.item(currentRow, currentColumn).data(QtCore.Qt.UserRole))
|
||||||
|
clipboard = QtWidgets.QApplication.clipboard()
|
||||||
clipboard = QtGui.QApplication.clipboard()
|
|
||||||
clipboard.setText(text)
|
clipboard.setText(text)
|
||||||
|
|
||||||
# set avatar functions
|
# set avatar functions
|
||||||
|
@ -3759,8 +3831,8 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
|
|
||||||
def on_action_SetAvatar(self, thisTableWidget):
|
def on_action_SetAvatar(self, thisTableWidget):
|
||||||
currentRow = thisTableWidget.currentRow()
|
currentRow = thisTableWidget.currentRow()
|
||||||
addressAtCurrentRow = thisTableWidget.item(
|
addressAtCurrentRow = ustr(thisTableWidget.item(
|
||||||
currentRow, 1).text()
|
currentRow, 1).text())
|
||||||
setToIdenticon = not self.setAvatar(addressAtCurrentRow)
|
setToIdenticon = not self.setAvatar(addressAtCurrentRow)
|
||||||
if setToIdenticon:
|
if setToIdenticon:
|
||||||
thisTableWidget.item(
|
thisTableWidget.item(
|
||||||
|
@ -3770,11 +3842,8 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
def setAvatar(self, addressAtCurrentRow):
|
def setAvatar(self, addressAtCurrentRow):
|
||||||
if not os.path.exists(state.appdata + 'avatars/'):
|
if not os.path.exists(state.appdata + 'avatars/'):
|
||||||
os.makedirs(state.appdata + 'avatars/')
|
os.makedirs(state.appdata + 'avatars/')
|
||||||
hash = hashlib.md5(addBMIfNotPresent(addressAtCurrentRow)).hexdigest()
|
hash = hashlib.md5(addBMIfNotPresent(addressAtCurrentRow).encode("utf-8", "replace")).hexdigest()
|
||||||
extensions = [
|
# http://pyqt.sourceforge.net/Docs/PyQt4/qimagereader.html#supportedImageFormats
|
||||||
'PNG', 'GIF', 'JPG', 'JPEG', 'SVG', 'BMP', 'MNG', 'PBM',
|
|
||||||
'PGM', 'PPM', 'TIFF', 'XBM', 'XPM', 'TGA']
|
|
||||||
|
|
||||||
names = {
|
names = {
|
||||||
'BMP': 'Windows Bitmap',
|
'BMP': 'Windows Bitmap',
|
||||||
'GIF': 'Graphic Interchange Format',
|
'GIF': 'Graphic Interchange Format',
|
||||||
|
@ -3789,11 +3858,12 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
'XBM': 'X11 Bitmap',
|
'XBM': 'X11 Bitmap',
|
||||||
'XPM': 'X11 Pixmap',
|
'XPM': 'X11 Pixmap',
|
||||||
'SVG': 'Scalable Vector Graphics',
|
'SVG': 'Scalable Vector Graphics',
|
||||||
'TGA': 'Targa Image Format'}
|
'TGA': 'Targa Image Format'
|
||||||
|
}
|
||||||
filters = []
|
filters = []
|
||||||
all_images_filter = []
|
all_images_filter = []
|
||||||
current_files = []
|
current_files = []
|
||||||
for ext in extensions:
|
for ext in names:
|
||||||
filters += [names[ext] + ' (*.' + ext.lower() + ')']
|
filters += [names[ext] + ' (*.' + ext.lower() + ')']
|
||||||
all_images_filter += ['*.' + ext.lower()]
|
all_images_filter += ['*.' + ext.lower()]
|
||||||
upper = state.appdata + 'avatars/' + hash + '.' + ext.upper()
|
upper = state.appdata + 'avatars/' + hash + '.' + ext.upper()
|
||||||
|
@ -3804,10 +3874,9 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
current_files += [upper]
|
current_files += [upper]
|
||||||
filters[0:0] = ['Image files (' + ' '.join(all_images_filter) + ')']
|
filters[0:0] = ['Image files (' + ' '.join(all_images_filter) + ')']
|
||||||
filters[1:1] = ['All files (*.*)']
|
filters[1:1] = ['All files (*.*)']
|
||||||
sourcefile = QtGui.QFileDialog.getOpenFileName(
|
sourcefile = QtWidgets.QFileDialog.getOpenFileName(
|
||||||
self, _translate("MainWindow", "Set avatar..."),
|
self, _translate("MainWindow", "Set avatar..."),
|
||||||
filter=';;'.join(filters)
|
filter=';;'.join(filters))[0]
|
||||||
)
|
|
||||||
# determine the correct filename (note that avatars don't use the suffix)
|
# determine the correct filename (note that avatars don't use the suffix)
|
||||||
destination = state.appdata + 'avatars/' + hash + '.' + sourcefile.split('.')[-1]
|
destination = state.appdata + 'avatars/' + hash + '.' + sourcefile.split('.')[-1]
|
||||||
exists = QtCore.QFile.exists(destination)
|
exists = QtCore.QFile.exists(destination)
|
||||||
|
@ -3816,11 +3885,11 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
if exists | (len(current_files) > 0):
|
if exists | (len(current_files) > 0):
|
||||||
displayMsg = _translate(
|
displayMsg = _translate(
|
||||||
"MainWindow", "Do you really want to remove this avatar?")
|
"MainWindow", "Do you really want to remove this avatar?")
|
||||||
overwrite = QtGui.QMessageBox.question(
|
overwrite = QtWidgets.QMessageBox.question(
|
||||||
self, 'Message', displayMsg,
|
self, 'Message', displayMsg,
|
||||||
QtGui.QMessageBox.Yes, QtGui.QMessageBox.No)
|
QtWidgets.QMessageBox.Yes, QtWidgets.QMessageBox.No)
|
||||||
else:
|
else:
|
||||||
overwrite = QtGui.QMessageBox.No
|
overwrite = QtWidgets.QMessageBox.No
|
||||||
else:
|
else:
|
||||||
# ask whether to overwrite old avatar
|
# ask whether to overwrite old avatar
|
||||||
if exists | (len(current_files) > 0):
|
if exists | (len(current_files) > 0):
|
||||||
|
@ -3828,15 +3897,15 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
"MainWindow",
|
"MainWindow",
|
||||||
"You have already set an avatar for this address."
|
"You have already set an avatar for this address."
|
||||||
" Do you really want to overwrite it?")
|
" Do you really want to overwrite it?")
|
||||||
overwrite = QtGui.QMessageBox.question(
|
overwrite = QtWidgets.QMessageBox.question(
|
||||||
self, 'Message', displayMsg,
|
self, 'Message', displayMsg,
|
||||||
QtGui.QMessageBox.Yes, QtGui.QMessageBox.No)
|
QtWidgets.QMessageBox.Yes, QtWidgets.QMessageBox.No)
|
||||||
else:
|
else:
|
||||||
overwrite = QtGui.QMessageBox.No
|
overwrite = QtWidgets.QMessageBox.No
|
||||||
|
|
||||||
# copy the image file to the appdata folder
|
# copy the image file to the appdata folder
|
||||||
if (not exists) | (overwrite == QtGui.QMessageBox.Yes):
|
if (not exists) | (overwrite == QtWidgets.QMessageBox.Yes):
|
||||||
if overwrite == QtGui.QMessageBox.Yes:
|
if overwrite == QtWidgets.QMessageBox.Yes:
|
||||||
for file in current_files:
|
for file in current_files:
|
||||||
QtCore.QFile.remove(file)
|
QtCore.QFile.remove(file)
|
||||||
QtCore.QFile.remove(destination)
|
QtCore.QFile.remove(destination)
|
||||||
|
@ -3861,23 +3930,23 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
|
|
||||||
def on_action_AddressBookSetSound(self):
|
def on_action_AddressBookSetSound(self):
|
||||||
widget = self.ui.tableWidgetAddressBook
|
widget = self.ui.tableWidgetAddressBook
|
||||||
self.setAddressSound(widget.item(widget.currentRow(), 0).text())
|
self.setAddressSound(ustr(widget.item(widget.currentRow(), 0).text()))
|
||||||
|
|
||||||
def setAddressSound(self, addr):
|
def setAddressSound(self, addr):
|
||||||
filters = [unicode(_translate(
|
filters = [unic(_translate(
|
||||||
"MainWindow", "Sound files (%s)" %
|
"MainWindow", "Sound files (%s)" %
|
||||||
' '.join(['*%s%s' % (os.extsep, ext) for ext in sound.extensions])
|
' '.join(['*%s%s' % (os.extsep, ext) for ext in sound.extensions])
|
||||||
))]
|
))]
|
||||||
sourcefile = unicode(QtGui.QFileDialog.getOpenFileName(
|
sourcefile = unic(ustr(QtWidgets.QFileDialog.getOpenFileName(
|
||||||
self, _translate("MainWindow", "Set notification sound..."),
|
self, _translate("MainWindow", "Set notification sound..."),
|
||||||
filter=';;'.join(filters)
|
filter=';;'.join(filters)
|
||||||
))
|
)))[0]
|
||||||
|
|
||||||
if not sourcefile:
|
if not sourcefile:
|
||||||
return
|
return
|
||||||
|
|
||||||
destdir = os.path.join(state.appdata, 'sounds')
|
destdir = os.path.join(state.appdata, 'sounds')
|
||||||
destfile = unicode(addr) + os.path.splitext(sourcefile)[-1]
|
destfile = unic(ustr(addr) + os.path.splitext(sourcefile)[-1])
|
||||||
destination = os.path.join(destdir, destfile)
|
destination = os.path.join(destdir, destfile)
|
||||||
|
|
||||||
if sourcefile == destination:
|
if sourcefile == destination:
|
||||||
|
@ -3886,15 +3955,15 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
pattern = destfile.lower()
|
pattern = destfile.lower()
|
||||||
for item in os.listdir(destdir):
|
for item in os.listdir(destdir):
|
||||||
if item.lower() == pattern:
|
if item.lower() == pattern:
|
||||||
overwrite = QtGui.QMessageBox.question(
|
overwrite = QtWidgets.QMessageBox.question(
|
||||||
self, _translate("MainWindow", "Message"),
|
self, _translate("MainWindow", "Message"),
|
||||||
_translate(
|
_translate(
|
||||||
"MainWindow",
|
"MainWindow",
|
||||||
"You have already set a notification sound"
|
"You have already set a notification sound"
|
||||||
" for this address book entry."
|
" for this address book entry."
|
||||||
" Do you really want to overwrite it?"),
|
" Do you really want to overwrite it?"),
|
||||||
QtGui.QMessageBox.Yes, QtGui.QMessageBox.No
|
QtWidgets.QMessageBox.Yes, QtWidgets.QMessageBox.No
|
||||||
) == QtGui.QMessageBox.Yes
|
) == QtWidgets.QMessageBox.Yes
|
||||||
if overwrite:
|
if overwrite:
|
||||||
QtCore.QFile.remove(os.path.join(destdir, item))
|
QtCore.QFile.remove(os.path.join(destdir, item))
|
||||||
break
|
break
|
||||||
|
@ -3905,18 +3974,23 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
|
|
||||||
def on_context_menuYourIdentities(self, point):
|
def on_context_menuYourIdentities(self, point):
|
||||||
currentItem = self.getCurrentItem()
|
currentItem = self.getCurrentItem()
|
||||||
self.popMenuYourIdentities = QtGui.QMenu(self)
|
self.popMenuYourIdentities = QtWidgets.QMenu(self)
|
||||||
if isinstance(currentItem, Ui_AddressWidget):
|
if isinstance(currentItem, Ui_AddressWidget):
|
||||||
self.popMenuYourIdentities.addAction(self.actionNewYourIdentities)
|
self.popMenuYourIdentities.addAction(self.actionNewYourIdentities)
|
||||||
self.popMenuYourIdentities.addSeparator()
|
self.popMenuYourIdentities.addSeparator()
|
||||||
self.popMenuYourIdentities.addAction(self.actionClipboardYourIdentities)
|
self.popMenuYourIdentities.addAction(
|
||||||
|
self.actionClipboardYourIdentities)
|
||||||
self.popMenuYourIdentities.addSeparator()
|
self.popMenuYourIdentities.addSeparator()
|
||||||
if currentItem.isEnabled:
|
if currentItem.isEnabled:
|
||||||
self.popMenuYourIdentities.addAction(self.actionDisableYourIdentities)
|
self.popMenuYourIdentities.addAction(
|
||||||
|
self.actionDisableYourIdentities)
|
||||||
else:
|
else:
|
||||||
self.popMenuYourIdentities.addAction(self.actionEnableYourIdentities)
|
self.popMenuYourIdentities.addAction(
|
||||||
self.popMenuYourIdentities.addAction(self.actionSetAvatarYourIdentities)
|
self.actionEnableYourIdentities)
|
||||||
self.popMenuYourIdentities.addAction(self.actionSpecialAddressBehaviorYourIdentities)
|
self.popMenuYourIdentities.addAction(
|
||||||
|
self.actionSetAvatarYourIdentities)
|
||||||
|
self.popMenuYourIdentities.addAction(
|
||||||
|
self.actionSpecialAddressBehaviorYourIdentities)
|
||||||
self.popMenuYourIdentities.addAction(self.actionEmailGateway)
|
self.popMenuYourIdentities.addAction(self.actionEmailGateway)
|
||||||
self.popMenuYourIdentities.addSeparator()
|
self.popMenuYourIdentities.addSeparator()
|
||||||
if currentItem.type != AccountMixin.ALL:
|
if currentItem.type != AccountMixin.ALL:
|
||||||
|
@ -3935,7 +4009,7 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
# TODO make one popMenu
|
# TODO make one popMenu
|
||||||
def on_context_menuChan(self, point):
|
def on_context_menuChan(self, point):
|
||||||
currentItem = self.getCurrentItem()
|
currentItem = self.getCurrentItem()
|
||||||
self.popMenu = QtGui.QMenu(self)
|
self.popMenu = QtWidgets.QMenu(self)
|
||||||
if isinstance(currentItem, Ui_AddressWidget):
|
if isinstance(currentItem, Ui_AddressWidget):
|
||||||
self.popMenu.addAction(self.actionNew)
|
self.popMenu.addAction(self.actionNew)
|
||||||
self.popMenu.addAction(self.actionDelete)
|
self.popMenu.addAction(self.actionDelete)
|
||||||
|
@ -3971,7 +4045,7 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
self.on_context_menuSent(point)
|
self.on_context_menuSent(point)
|
||||||
return
|
return
|
||||||
|
|
||||||
self.popMenuInbox = QtGui.QMenu(self)
|
self.popMenuInbox = QtWidgets.QMenu(self)
|
||||||
self.popMenuInbox.addAction(self.actionForceHtml)
|
self.popMenuInbox.addAction(self.actionForceHtml)
|
||||||
self.popMenuInbox.addAction(self.actionMarkUnread)
|
self.popMenuInbox.addAction(self.actionMarkUnread)
|
||||||
self.popMenuInbox.addSeparator()
|
self.popMenuInbox.addSeparator()
|
||||||
|
@ -4006,7 +4080,7 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
|
|
||||||
def on_context_menuSent(self, point):
|
def on_context_menuSent(self, point):
|
||||||
currentRow = self.ui.tableWidgetInbox.currentRow()
|
currentRow = self.ui.tableWidgetInbox.currentRow()
|
||||||
self.popMenuSent = QtGui.QMenu(self)
|
self.popMenuSent = QtWidgets.QMenu(self)
|
||||||
self.popMenuSent.addAction(self.actionSentClipboard)
|
self.popMenuSent.addAction(self.actionSentClipboard)
|
||||||
self._contact_selected = self.ui.tableWidgetInbox.item(currentRow, 0)
|
self._contact_selected = self.ui.tableWidgetInbox.item(currentRow, 0)
|
||||||
# preloaded gui.menu plugins with prefix 'address'
|
# 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
|
# Check to see if this item is toodifficult and display an additional
|
||||||
# menu option (Force Send) if it is.
|
# menu option (Force Send) if it is.
|
||||||
if currentRow >= 0:
|
if currentRow >= 0:
|
||||||
ackData = self.ui.tableWidgetInbox.item(currentRow, 3).data()
|
ackData = as_msgid(self.ui.tableWidgetInbox.item(currentRow, 3).data())
|
||||||
queryreturn = sqlQuery('''SELECT status FROM sent where ackdata=?''', ackData)
|
queryreturn = sqlQuery('''SELECT status FROM sent where ackdata=?''', sqlite3.Binary(ackData))
|
||||||
|
if len(queryreturn) < 1:
|
||||||
|
queryreturn = sqlQuery('''SELECT status FROM sent where ackdata=CAST(? AS TEXT)''', ackData)
|
||||||
for row in queryreturn:
|
for row in queryreturn:
|
||||||
status, = row
|
status, = row
|
||||||
|
status = status.decode("utf-8", "replace")
|
||||||
if status == 'toodifficult':
|
if status == 'toodifficult':
|
||||||
self.popMenuSent.addAction(self.actionForceSend)
|
self.popMenuSent.addAction(self.actionForceSend)
|
||||||
|
|
||||||
|
@ -4030,7 +4107,7 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
|
|
||||||
def inboxSearchLineEditUpdated(self, text):
|
def inboxSearchLineEditUpdated(self, text):
|
||||||
# dynamic search for too short text is slow
|
# dynamic search for too short text is slow
|
||||||
text = text.toUtf8()
|
text = ustr(text)
|
||||||
if 0 < len(text) < 3:
|
if 0 < len(text) < 3:
|
||||||
return
|
return
|
||||||
messagelist = self.getCurrentMessagelist()
|
messagelist = self.getCurrentMessagelist()
|
||||||
|
@ -4043,9 +4120,9 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
|
|
||||||
def inboxSearchLineEditReturnPressed(self):
|
def inboxSearchLineEditReturnPressed(self):
|
||||||
logger.debug("Search return pressed")
|
logger.debug("Search return pressed")
|
||||||
searchLine = self.getCurrentSearchLine()
|
searchLine = self.getCurrentSearchLine().encode('utf-8')
|
||||||
messagelist = self.getCurrentMessagelist()
|
messagelist = self.getCurrentMessagelist()
|
||||||
if messagelist and len(str(searchLine)) < 3:
|
if messagelist and len(ustr(searchLine)) < 3:
|
||||||
searchOption = self.getCurrentSearchOption()
|
searchOption = self.getCurrentSearchOption()
|
||||||
account = self.getCurrentAccount()
|
account = self.getCurrentAccount()
|
||||||
folder = self.getCurrentFolder()
|
folder = self.getCurrentFolder()
|
||||||
|
@ -4087,7 +4164,7 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
if item.type == AccountMixin.ALL:
|
if item.type == AccountMixin.ALL:
|
||||||
return
|
return
|
||||||
|
|
||||||
newLabel = unicode(item.text(0), 'utf-8', 'ignore')
|
newLabel = unic(ustr(item.text(0)))
|
||||||
oldLabel = item.defaultLabel()
|
oldLabel = item.defaultLabel()
|
||||||
|
|
||||||
# unchanged, do not do anything either
|
# unchanged, do not do anything either
|
||||||
|
@ -4106,7 +4183,9 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
self.rerenderMessagelistFromLabels()
|
self.rerenderMessagelistFromLabels()
|
||||||
if item.type != AccountMixin.SUBSCRIPTION:
|
if item.type != AccountMixin.SUBSCRIPTION:
|
||||||
self.rerenderMessagelistToLabels()
|
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.rerenderAddressBook()
|
||||||
self.recurDepth -= 1
|
self.recurDepth -= 1
|
||||||
|
|
||||||
|
@ -4119,17 +4198,26 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
folder = self.getCurrentFolder()
|
folder = self.getCurrentFolder()
|
||||||
if msgid:
|
if msgid:
|
||||||
queryreturn = sqlQuery(
|
queryreturn = sqlQuery(
|
||||||
'''SELECT message FROM %s WHERE %s=?''' % (
|
'SELECT message FROM %s WHERE %s=?' % (
|
||||||
('sent', 'ackdata') if folder == 'sent'
|
('sent', 'ackdata') if folder == 'sent'
|
||||||
else ('inbox', 'msgid')
|
else ('inbox', 'msgid')
|
||||||
), 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:
|
try:
|
||||||
message = queryreturn[-1][0]
|
message = queryreturn[-1][0].decode("utf-8", "replace")
|
||||||
except NameError:
|
except NameError:
|
||||||
message = ""
|
message = u''
|
||||||
except IndexError:
|
except IndexError:
|
||||||
|
# _translate() often returns unicode, no redefinition here!
|
||||||
|
# pylint: disable=redefined-variable-type
|
||||||
message = _translate(
|
message = _translate(
|
||||||
"MainWindow",
|
"MainWindow",
|
||||||
"Error occurred: could not load message from disk."
|
"Error occurred: could not load message from disk."
|
||||||
|
@ -4141,10 +4229,16 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
if tableWidget.item(currentRow, 0).unread is True:
|
if tableWidget.item(currentRow, 0).unread is True:
|
||||||
self.updateUnreadStatus(tableWidget, currentRow, msgid)
|
self.updateUnreadStatus(tableWidget, currentRow, msgid)
|
||||||
# propagate
|
# propagate
|
||||||
if folder != 'sent' and sqlExecute(
|
rowcount = sqlExecute(
|
||||||
'''UPDATE inbox SET read=1 WHERE msgid=? AND read=0''',
|
'UPDATE inbox SET read=1 WHERE msgid=? AND read=0',
|
||||||
msgid
|
sqlite3.Binary(msgid)
|
||||||
) > 0:
|
)
|
||||||
|
if rowcount < 1:
|
||||||
|
rowcount = sqlExecute(
|
||||||
|
'UPDATE inbox SET read=1 WHERE msgid=CAST(? AS TEXT) AND read=0',
|
||||||
|
msgid
|
||||||
|
)
|
||||||
|
if folder != 'sent' and rowcount > 0:
|
||||||
self.propagateUnreadCount()
|
self.propagateUnreadCount()
|
||||||
|
|
||||||
messageTextedit.setCurrentFont(QtGui.QFont())
|
messageTextedit.setCurrentFont(QtGui.QFont())
|
||||||
|
@ -4158,8 +4252,9 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
self.rerenderMessagelistToLabels()
|
self.rerenderMessagelistToLabels()
|
||||||
completerList = self.ui.lineEditTo.completer().model().stringList()
|
completerList = self.ui.lineEditTo.completer().model().stringList()
|
||||||
for i in range(len(completerList)):
|
for i in range(len(completerList)):
|
||||||
if unicode(completerList[i]).endswith(" <" + item.address + ">"):
|
address_block = " <" + ustr(item.address) + ">"
|
||||||
completerList[i] = item.label + " <" + 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)
|
self.ui.lineEditTo.completer().model().setStringList(completerList)
|
||||||
|
|
||||||
def tabWidgetCurrentChanged(self, n):
|
def tabWidgetCurrentChanged(self, n):
|
||||||
|
@ -4212,7 +4307,7 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
|
|
||||||
def initSettings(self):
|
def initSettings(self):
|
||||||
self.loadSettings()
|
self.loadSettings()
|
||||||
for attr, obj in self.ui.__dict__.iteritems():
|
for attr, obj in six.iteritems(self.ui.__dict__):
|
||||||
if hasattr(obj, "__class__") and \
|
if hasattr(obj, "__class__") and \
|
||||||
isinstance(obj, settingsmixin.SettingsMixin):
|
isinstance(obj, settingsmixin.SettingsMixin):
|
||||||
loadMethod = getattr(obj, "loadSettings", None)
|
loadMethod = getattr(obj, "loadSettings", None)
|
||||||
|
@ -4224,7 +4319,7 @@ app = None
|
||||||
myapp = 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
|
Listener to allow our Qt form to get focus when another instance of the
|
||||||
application is open.
|
application is open.
|
||||||
|
@ -4263,15 +4358,15 @@ class BitmessageQtApplication(QtGui.QApplication):
|
||||||
self.server = None
|
self.server = None
|
||||||
self.is_running = False
|
self.is_running = False
|
||||||
|
|
||||||
socket = QLocalSocket()
|
socket = QtNetwork.QLocalSocket()
|
||||||
socket.connectToServer(id)
|
socket.connectToServer(id)
|
||||||
self.is_running = socket.waitForConnected()
|
self.is_running = socket.waitForConnected()
|
||||||
|
|
||||||
# Cleanup past crashed servers
|
# Cleanup past crashed servers
|
||||||
if not self.is_running:
|
if not self.is_running:
|
||||||
if socket.error() == QLocalSocket.ConnectionRefusedError:
|
if socket.error() == QtNetwork.QLocalSocket.ConnectionRefusedError:
|
||||||
socket.disconnectFromServer()
|
socket.disconnectFromServer()
|
||||||
QLocalServer.removeServer(id)
|
QtNetwork.QLocalServer.removeServer(id)
|
||||||
|
|
||||||
socket.abort()
|
socket.abort()
|
||||||
|
|
||||||
|
@ -4282,16 +4377,12 @@ class BitmessageQtApplication(QtGui.QApplication):
|
||||||
else:
|
else:
|
||||||
# Nope, create a local server with this id and assign on_new_connection
|
# Nope, create a local server with this id and assign on_new_connection
|
||||||
# for whenever a second instance tries to run focus the application.
|
# for whenever a second instance tries to run focus the application.
|
||||||
self.server = QLocalServer()
|
self.server = QtNetwork.QLocalServer()
|
||||||
self.server.listen(id)
|
self.server.listen(id)
|
||||||
self.server.newConnection.connect(self.on_new_connection)
|
self.server.newConnection.connect(self.on_new_connection)
|
||||||
|
|
||||||
self.setStyleSheet("QStatusBar::item { border: 0px solid black }")
|
self.setStyleSheet("QStatusBar::item { border: 0px solid black }")
|
||||||
|
|
||||||
def __del__(self):
|
|
||||||
if self.server:
|
|
||||||
self.server.close()
|
|
||||||
|
|
||||||
def on_new_connection(self):
|
def on_new_connection(self):
|
||||||
if myapp:
|
if myapp:
|
||||||
myapp.appIndicatorShow()
|
myapp.appIndicatorShow()
|
||||||
|
|
|
@ -1,20 +1,16 @@
|
||||||
# pylint: disable=too-many-instance-attributes,attribute-defined-outside-init
|
|
||||||
"""
|
"""
|
||||||
account.py
|
|
||||||
==========
|
|
||||||
|
|
||||||
Account related functions.
|
Account related functions.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from __future__ import absolute_import
|
|
||||||
|
|
||||||
import inspect
|
import inspect
|
||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
|
import sqlite3
|
||||||
|
|
||||||
from PyQt4 import QtGui
|
from unqstr import ustr, unic
|
||||||
|
from dbcompat import dbstr
|
||||||
|
|
||||||
import queues
|
import queues
|
||||||
from addresses import decodeAddress
|
from addresses import decodeAddress
|
||||||
|
@ -23,6 +19,7 @@ from helper_ackPayload import genAckPayload
|
||||||
from helper_sql import sqlQuery, sqlExecute
|
from helper_sql import sqlQuery, sqlExecute
|
||||||
from .foldertree import AccountMixin
|
from .foldertree import AccountMixin
|
||||||
from .utils import str_broadcast_subscribers
|
from .utils import str_broadcast_subscribers
|
||||||
|
from tr import _translate
|
||||||
|
|
||||||
|
|
||||||
def getSortedSubscriptions(count=False):
|
def getSortedSubscriptions(count=False):
|
||||||
|
@ -34,22 +31,25 @@ def getSortedSubscriptions(count=False):
|
||||||
:retuns: dict keys are addresses, values are dicts containing settings
|
:retuns: dict keys are addresses, values are dicts containing settings
|
||||||
:rtype: dict, default {}
|
: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 = {}
|
ret = {}
|
||||||
for row in queryreturn:
|
for label, address, enabled in queryreturn:
|
||||||
label, address, enabled = row
|
label = label.decode("utf-8", "replace")
|
||||||
ret[address] = {}
|
address = address.decode("utf-8", "replace")
|
||||||
ret[address]["inbox"] = {}
|
ret[address] = {'inbox': {}}
|
||||||
ret[address]["inbox"]['label'] = label
|
ret[address]['inbox'].update(label=label, enabled=enabled, count=0)
|
||||||
ret[address]["inbox"]['enabled'] = enabled
|
|
||||||
ret[address]["inbox"]['count'] = 0
|
|
||||||
if count:
|
if count:
|
||||||
queryreturn = sqlQuery('''SELECT fromaddress, folder, count(msgid) as cnt
|
queryreturn = sqlQuery(
|
||||||
FROM inbox, subscriptions ON subscriptions.address = inbox.fromaddress
|
'SELECT fromaddress, folder, count(msgid) AS cnt'
|
||||||
WHERE read = 0 AND toaddress = ?
|
' FROM inbox, subscriptions'
|
||||||
GROUP BY inbox.fromaddress, folder''', str_broadcast_subscribers)
|
' ON subscriptions.address = inbox.fromaddress WHERE read = 0'
|
||||||
for row in queryreturn:
|
' AND toaddress = ? GROUP BY inbox.fromaddress, folder',
|
||||||
address, folder, cnt = row
|
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]:
|
if folder not in ret[address]:
|
||||||
ret[address][folder] = {
|
ret[address][folder] = {
|
||||||
'label': ret[address]['inbox']['label'],
|
'label': ret[address]['inbox']['label'],
|
||||||
|
@ -75,7 +75,8 @@ def accountClass(address):
|
||||||
return subscription
|
return subscription
|
||||||
try:
|
try:
|
||||||
gateway = config.get(address, "gateway")
|
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:
|
if issubclass(cls, GatewayAccount) and cls.gatewayName == gateway:
|
||||||
return cls(address)
|
return cls(address)
|
||||||
# general gateway
|
# general gateway
|
||||||
|
@ -86,7 +87,7 @@ def accountClass(address):
|
||||||
return BMAccount(address)
|
return BMAccount(address)
|
||||||
|
|
||||||
|
|
||||||
class AccountColor(AccountMixin): # pylint: disable=too-few-public-methods
|
class AccountColor(AccountMixin):
|
||||||
"""Set the type of account"""
|
"""Set the type of account"""
|
||||||
|
|
||||||
def __init__(self, address, address_type=None):
|
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'):
|
elif config.safeGetBoolean(self.address, 'chan'):
|
||||||
self.type = AccountMixin.CHAN
|
self.type = AccountMixin.CHAN
|
||||||
elif sqlQuery(
|
elif sqlQuery(
|
||||||
'''select label from subscriptions where address=?''', self.address):
|
'SELECT label FROM subscriptions WHERE address=?',
|
||||||
|
dbstr(self.address)
|
||||||
|
):
|
||||||
self.type = AccountMixin.SUBSCRIPTION
|
self.type = AccountMixin.SUBSCRIPTION
|
||||||
else:
|
else:
|
||||||
self.type = AccountMixin.NORMAL
|
self.type = AccountMixin.NORMAL
|
||||||
|
@ -108,12 +111,35 @@ class AccountColor(AccountMixin): # pylint: disable=too-few-public-methods
|
||||||
self.type = address_type
|
self.type = address_type
|
||||||
|
|
||||||
|
|
||||||
class BMAccount(object):
|
class NoAccount(object):
|
||||||
"""Encapsulate a Bitmessage account"""
|
"""Minimal account like object (All accounts)"""
|
||||||
|
# pylint: disable=too-many-instance-attributes
|
||||||
def __init__(self, address=None):
|
def __init__(self, address=None):
|
||||||
self.address = address
|
self.address = address
|
||||||
self.type = AccountMixin.NORMAL
|
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.has_section(address):
|
||||||
if config.safeGetBoolean(self.address, 'chan'):
|
if config.safeGetBoolean(self.address, 'chan'):
|
||||||
self.type = AccountMixin.CHAN
|
self.type = AccountMixin.CHAN
|
||||||
|
@ -121,55 +147,25 @@ class BMAccount(object):
|
||||||
self.type = AccountMixin.MAILINGLIST
|
self.type = AccountMixin.MAILINGLIST
|
||||||
elif self.address == str_broadcast_subscribers:
|
elif self.address == str_broadcast_subscribers:
|
||||||
self.type = AccountMixin.BROADCAST
|
self.type = AccountMixin.BROADCAST
|
||||||
else:
|
elif sqlQuery(
|
||||||
queryreturn = sqlQuery(
|
'SELECT label FROM subscriptions WHERE address=?', dbstr(self.address)
|
||||||
'''select label from subscriptions where address=?''', self.address)
|
):
|
||||||
if queryreturn:
|
self.type = AccountMixin.SUBSCRIPTION
|
||||||
self.type = AccountMixin.SUBSCRIPTION
|
|
||||||
|
|
||||||
def getLabel(self, address=None):
|
def getLabel(self, address=None):
|
||||||
"""Get a label for this bitmessage account"""
|
"""Get a label for this bitmessage account"""
|
||||||
if address is None:
|
address = super(BMAccount, self).getLabel(address)
|
||||||
address = self.address
|
|
||||||
label = config.safeGet(address, 'label', address)
|
label = config.safeGet(address, 'label', address)
|
||||||
queryreturn = sqlQuery(
|
queryreturn = sqlQuery(
|
||||||
'''select label from addressbook where address=?''', address)
|
'SELECT label FROM addressbook WHERE address=?', dbstr(address))
|
||||||
if queryreturn != []:
|
if queryreturn:
|
||||||
for row in queryreturn:
|
label = queryreturn[-1][0]
|
||||||
label, = row
|
|
||||||
else:
|
else:
|
||||||
queryreturn = sqlQuery(
|
queryreturn = sqlQuery(
|
||||||
'''select label from subscriptions where address=?''', address)
|
'SELECT label FROM subscriptions WHERE address=?', dbstr(address))
|
||||||
if queryreturn != []:
|
if queryreturn:
|
||||||
for row in queryreturn:
|
label = queryreturn[-1][0]
|
||||||
label, = row
|
return unic(ustr(label))
|
||||||
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
|
|
||||||
|
|
||||||
|
|
||||||
class SubscriptionAccount(BMAccount):
|
class SubscriptionAccount(BMAccount):
|
||||||
|
@ -189,31 +185,27 @@ class GatewayAccount(BMAccount):
|
||||||
ALL_OK = 0
|
ALL_OK = 0
|
||||||
REGISTRATION_DENIED = 1
|
REGISTRATION_DENIED = 1
|
||||||
|
|
||||||
def __init__(self, address):
|
|
||||||
super(GatewayAccount, self).__init__(address)
|
|
||||||
|
|
||||||
def send(self):
|
def send(self):
|
||||||
"""Override the send method for gateway accounts"""
|
"""The send method for gateway accounts"""
|
||||||
|
streamNumber, ripe = decodeAddress(self.toAddress)[2:]
|
||||||
# pylint: disable=unused-variable
|
stealthLevel = config.safeGetInt(
|
||||||
status, addressVersionNumber, streamNumber, ripe = decodeAddress(self.toAddress)
|
'bitmessagesettings', 'ackstealthlevel')
|
||||||
stealthLevel = config.safeGetInt('bitmessagesettings', 'ackstealthlevel')
|
|
||||||
ackdata = genAckPayload(streamNumber, stealthLevel)
|
ackdata = genAckPayload(streamNumber, stealthLevel)
|
||||||
sqlExecute(
|
sqlExecute(
|
||||||
'''INSERT INTO sent VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)''',
|
'''INSERT INTO sent VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)''',
|
||||||
'',
|
sqlite3.Binary(b''),
|
||||||
self.toAddress,
|
dbstr(self.toAddress),
|
||||||
ripe,
|
sqlite3.Binary(ripe),
|
||||||
self.fromAddress,
|
dbstr(self.fromAddress),
|
||||||
self.subject,
|
dbstr(self.subject),
|
||||||
self.message,
|
dbstr(self.message),
|
||||||
ackdata,
|
sqlite3.Binary(ackdata),
|
||||||
int(time.time()), # sentTime (this will never change)
|
int(time.time()), # sentTime (this will never change)
|
||||||
int(time.time()), # lastActionTime
|
int(time.time()), # lastActionTime
|
||||||
0, # sleepTill time. This will get set when the POW gets done.
|
0, # sleepTill time. This will get set when the POW gets done.
|
||||||
'msgqueued',
|
dbstr('msgqueued'),
|
||||||
0, # retryNumber
|
0, # retryNumber
|
||||||
'sent', # folder
|
dbstr('sent'), # folder
|
||||||
2, # encodingtype
|
2, # encodingtype
|
||||||
# not necessary to have a TTL higher than 2 days
|
# not necessary to have a TTL higher than 2 days
|
||||||
min(config.getint('bitmessagesettings', 'ttl'), 86400 * 2)
|
min(config.getint('bitmessagesettings', 'ttl'), 86400 * 2)
|
||||||
|
@ -270,10 +262,9 @@ class MailchuckAccount(GatewayAccount):
|
||||||
|
|
||||||
def settings(self):
|
def settings(self):
|
||||||
"""settings specific to a MailchuckAccount"""
|
"""settings specific to a MailchuckAccount"""
|
||||||
|
|
||||||
self.toAddress = self.registrationAddress
|
self.toAddress = self.registrationAddress
|
||||||
self.subject = "config"
|
self.subject = "config"
|
||||||
self.message = QtGui.QApplication.translate(
|
self.message = _translate(
|
||||||
"Mailchuck",
|
"Mailchuck",
|
||||||
"""# You can use this to configure your email gateway account
|
"""# You can use this to configure your email gateway account
|
||||||
# Uncomment the setting you want to use
|
# Uncomment the setting you want to use
|
||||||
|
@ -319,8 +310,9 @@ class MailchuckAccount(GatewayAccount):
|
||||||
|
|
||||||
def parseMessage(self, toAddress, fromAddress, subject, message):
|
def parseMessage(self, toAddress, fromAddress, subject, message):
|
||||||
"""parseMessage specific to a MailchuckAccount"""
|
"""parseMessage specific to a MailchuckAccount"""
|
||||||
|
super(MailchuckAccount, self).parseMessage(
|
||||||
super(MailchuckAccount, self).parseMessage(toAddress, fromAddress, subject, message)
|
toAddress, fromAddress, subject, message
|
||||||
|
)
|
||||||
if fromAddress == self.relayAddress:
|
if fromAddress == self.relayAddress:
|
||||||
matches = self.regExpIncoming.search(subject)
|
matches = self.regExpIncoming.search(subject)
|
||||||
if matches is not None:
|
if matches is not None:
|
||||||
|
@ -341,6 +333,7 @@ class MailchuckAccount(GatewayAccount):
|
||||||
self.toLabel = matches.group(1)
|
self.toLabel = matches.group(1)
|
||||||
self.toAddress = matches.group(1)
|
self.toAddress = matches.group(1)
|
||||||
self.feedback = self.ALL_OK
|
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
|
self.feedback = self.REGISTRATION_DENIED
|
||||||
return self.feedback
|
return self.feedback
|
||||||
|
|
|
@ -1,40 +1,40 @@
|
||||||
"""
|
"""
|
||||||
Dialogs that work with BM address.
|
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
|
import hashlib
|
||||||
|
|
||||||
from PyQt4 import QtCore, QtGui
|
from unqstr import ustr, unic
|
||||||
|
from qtpy import QtGui, QtWidgets
|
||||||
|
|
||||||
import queues
|
import queues
|
||||||
import widgets
|
from bitmessageqt import widgets
|
||||||
import state
|
import state
|
||||||
from account import AccountMixin, GatewayAccount, MailchuckAccount, accountClass
|
from .account import (
|
||||||
|
GatewayAccount, MailchuckAccount, AccountMixin, accountClass
|
||||||
|
)
|
||||||
from addresses import addBMIfNotPresent, decodeAddress, encodeVarint
|
from addresses import addBMIfNotPresent, decodeAddress, encodeVarint
|
||||||
from bmconfigparser import config as global_config
|
from bmconfigparser import config as global_config
|
||||||
from tr import _translate
|
from tr import _translate
|
||||||
|
|
||||||
|
|
||||||
class AddressCheckMixin(object):
|
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
|
self.valid = False
|
||||||
QtCore.QObject.connect( # pylint: disable=no-member
|
self.lineEditAddress.textChanged.connect(self.addressChanged)
|
||||||
self.lineEditAddress,
|
|
||||||
QtCore.SIGNAL("textChanged(QString)"),
|
|
||||||
self.addressChanged)
|
|
||||||
|
|
||||||
def _onSuccess(self, addressVersion, streamNumber, ripe):
|
def _onSuccess(self, addressVersion, streamNumber, ripe):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def addressChanged(self, QString):
|
def addressChanged(self, address):
|
||||||
"""
|
"""
|
||||||
Address validation callback, performs validation and gives feedback
|
Address validation callback, performs validation and gives feedback
|
||||||
"""
|
"""
|
||||||
status, addressVersion, streamNumber, ripe = decodeAddress(
|
status, addressVersion, streamNumber, ripe = decodeAddress(ustr(address))
|
||||||
str(QString))
|
|
||||||
self.valid = status == 'success'
|
self.valid = status == 'success'
|
||||||
if self.valid:
|
if self.valid:
|
||||||
self.labelAddressCheck.setText(
|
self.labelAddressCheck.setText(
|
||||||
|
@ -79,19 +79,27 @@ class AddressCheckMixin(object):
|
||||||
))
|
))
|
||||||
|
|
||||||
|
|
||||||
class AddressDataDialog(QtGui.QDialog, AddressCheckMixin):
|
class AddressDataDialog(QtWidgets.QDialog, AddressCheckMixin):
|
||||||
"""QDialog with Bitmessage address validation"""
|
"""
|
||||||
|
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):
|
def __init__(self, parent):
|
||||||
super(AddressDataDialog, self).__init__(parent)
|
super(AddressDataDialog, self).__init__(parent)
|
||||||
self.parent = parent
|
self.parent = parent
|
||||||
|
self.data = None
|
||||||
|
|
||||||
def accept(self):
|
def accept(self):
|
||||||
"""Callback for QDIalog accepting value"""
|
"""Callback for QDialog accepting value"""
|
||||||
if self.valid:
|
if self.valid:
|
||||||
self.data = (
|
self.data = (
|
||||||
addBMIfNotPresent(str(self.lineEditAddress.text())),
|
addBMIfNotPresent(ustr(self.lineEditAddress.text())),
|
||||||
str(self.lineEditLabel.text().toUtf8())
|
ustr(self.lineEditLabel.text())
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
queues.UISignalQueue.put(('updateStatusBar', _translate(
|
queues.UISignalQueue.put(('updateStatusBar', _translate(
|
||||||
|
@ -107,12 +115,12 @@ class AddAddressDialog(AddressDataDialog):
|
||||||
def __init__(self, parent=None, address=None):
|
def __init__(self, parent=None, address=None):
|
||||||
super(AddAddressDialog, self).__init__(parent)
|
super(AddAddressDialog, self).__init__(parent)
|
||||||
widgets.load('addaddressdialog.ui', self)
|
widgets.load('addaddressdialog.ui', self)
|
||||||
AddressCheckMixin.__init__(self)
|
self._setup()
|
||||||
if address:
|
if address:
|
||||||
self.lineEditAddress.setText(address)
|
self.lineEditAddress.setText(address)
|
||||||
|
|
||||||
|
|
||||||
class NewAddressDialog(QtGui.QDialog):
|
class NewAddressDialog(QtWidgets.QDialog):
|
||||||
"""QDialog for generating a new address"""
|
"""QDialog for generating a new address"""
|
||||||
|
|
||||||
def __init__(self, parent=None):
|
def __init__(self, parent=None):
|
||||||
|
@ -125,7 +133,7 @@ class NewAddressDialog(QtGui.QDialog):
|
||||||
self.radioButtonExisting.click()
|
self.radioButtonExisting.click()
|
||||||
self.comboBoxExisting.addItem(address)
|
self.comboBoxExisting.addItem(address)
|
||||||
self.groupBoxDeterministic.setHidden(True)
|
self.groupBoxDeterministic.setHidden(True)
|
||||||
QtGui.QWidget.resize(self, QtGui.QWidget.sizeHint(self))
|
QtWidgets.QWidget.resize(self, QtWidgets.QWidget.sizeHint(self))
|
||||||
self.show()
|
self.show()
|
||||||
|
|
||||||
def accept(self):
|
def accept(self):
|
||||||
|
@ -142,13 +150,13 @@ class NewAddressDialog(QtGui.QDialog):
|
||||||
self.comboBoxExisting.currentText())[2]
|
self.comboBoxExisting.currentText())[2]
|
||||||
queues.addressGeneratorQueue.put((
|
queues.addressGeneratorQueue.put((
|
||||||
'createRandomAddress', 4, streamNumberForAddress,
|
'createRandomAddress', 4, streamNumberForAddress,
|
||||||
str(self.newaddresslabel.text().toUtf8()), 1, "",
|
ustr(self.newaddresslabel.text()), 1, "",
|
||||||
self.checkBoxEighteenByteRipe.isChecked()
|
self.checkBoxEighteenByteRipe.isChecked()
|
||||||
))
|
))
|
||||||
else:
|
else:
|
||||||
if self.lineEditPassphrase.text() != \
|
if ustr(self.lineEditPassphrase.text()) != \
|
||||||
self.lineEditPassphraseAgain.text():
|
ustr(self.lineEditPassphraseAgain.text()):
|
||||||
QtGui.QMessageBox.about(
|
QtWidgets.QMessageBox.about(
|
||||||
self, _translate("MainWindow", "Passphrase mismatch"),
|
self, _translate("MainWindow", "Passphrase mismatch"),
|
||||||
_translate(
|
_translate(
|
||||||
"MainWindow",
|
"MainWindow",
|
||||||
|
@ -156,7 +164,7 @@ class NewAddressDialog(QtGui.QDialog):
|
||||||
" match. Try again.")
|
" match. Try again.")
|
||||||
)
|
)
|
||||||
elif self.lineEditPassphrase.text() == "":
|
elif self.lineEditPassphrase.text() == "":
|
||||||
QtGui.QMessageBox.about(
|
QtWidgets.QMessageBox.about(
|
||||||
self, _translate("MainWindow", "Choose a passphrase"),
|
self, _translate("MainWindow", "Choose a passphrase"),
|
||||||
_translate(
|
_translate(
|
||||||
"MainWindow", "You really do need a passphrase.")
|
"MainWindow", "You really do need a passphrase.")
|
||||||
|
@ -169,7 +177,7 @@ class NewAddressDialog(QtGui.QDialog):
|
||||||
'createDeterministicAddresses', 4, streamNumberForAddress,
|
'createDeterministicAddresses', 4, streamNumberForAddress,
|
||||||
"unused deterministic address",
|
"unused deterministic address",
|
||||||
self.spinBoxNumberOfAddressesToMake.value(),
|
self.spinBoxNumberOfAddressesToMake.value(),
|
||||||
self.lineEditPassphrase.text().toUtf8(),
|
ustr(self.lineEditPassphrase.text()),
|
||||||
self.checkBoxEighteenByteRipe.isChecked()
|
self.checkBoxEighteenByteRipe.isChecked()
|
||||||
))
|
))
|
||||||
|
|
||||||
|
@ -180,7 +188,8 @@ class NewSubscriptionDialog(AddressDataDialog):
|
||||||
def __init__(self, parent=None):
|
def __init__(self, parent=None):
|
||||||
super(NewSubscriptionDialog, self).__init__(parent)
|
super(NewSubscriptionDialog, self).__init__(parent)
|
||||||
widgets.load('newsubscriptiondialog.ui', self)
|
widgets.load('newsubscriptiondialog.ui', self)
|
||||||
AddressCheckMixin.__init__(self)
|
self.recent = []
|
||||||
|
self._setup()
|
||||||
|
|
||||||
def _onSuccess(self, addressVersion, streamNumber, ripe):
|
def _onSuccess(self, addressVersion, streamNumber, ripe):
|
||||||
if addressVersion <= 3:
|
if addressVersion <= 3:
|
||||||
|
@ -211,22 +220,21 @@ class NewSubscriptionDialog(AddressDataDialog):
|
||||||
_translate(
|
_translate(
|
||||||
"MainWindow",
|
"MainWindow",
|
||||||
"Display the %n recent broadcast(s) from this address.",
|
"Display the %n recent broadcast(s) from this address.",
|
||||||
None,
|
None, count
|
||||||
QtCore.QCoreApplication.CodecForTr,
|
|
||||||
count
|
|
||||||
))
|
))
|
||||||
|
|
||||||
|
|
||||||
class RegenerateAddressesDialog(QtGui.QDialog):
|
class RegenerateAddressesDialog(QtWidgets.QDialog):
|
||||||
"""QDialog for regenerating deterministic addresses"""
|
"""QDialog for regenerating deterministic addresses"""
|
||||||
|
|
||||||
def __init__(self, parent=None):
|
def __init__(self, parent=None):
|
||||||
super(RegenerateAddressesDialog, self).__init__(parent)
|
super(RegenerateAddressesDialog, self).__init__(parent)
|
||||||
widgets.load('regenerateaddresses.ui', self)
|
widgets.load('regenerateaddresses.ui', self)
|
||||||
self.groupBox.setTitle('')
|
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)
|
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):
|
def __init__(self, parent=None, config=global_config):
|
||||||
super(SpecialAddressBehaviorDialog, self).__init__(parent)
|
super(SpecialAddressBehaviorDialog, self).__init__(parent)
|
||||||
widgets.load('specialaddressbehavior.ui', self)
|
widgets.load('specialaddressbehavior.ui', self)
|
||||||
self.address = parent.getCurrentAccount()
|
self.address = ustr(parent.getCurrentAccount())
|
||||||
self.parent = parent
|
self.parent = parent
|
||||||
self.config = config
|
self.config = config
|
||||||
|
|
||||||
|
@ -257,12 +265,12 @@ class SpecialAddressBehaviorDialog(QtGui.QDialog):
|
||||||
self.radioButtonBehaviorMailingList.click()
|
self.radioButtonBehaviorMailingList.click()
|
||||||
else:
|
else:
|
||||||
self.radioButtonBehaveNormalAddress.click()
|
self.radioButtonBehaveNormalAddress.click()
|
||||||
mailingListName = config.safeGet(self.address, 'mailinglistname', '')
|
mailingListName = config.safeGet(
|
||||||
|
self.address, 'mailinglistname', '')
|
||||||
self.lineEditMailingListName.setText(
|
self.lineEditMailingListName.setText(
|
||||||
unicode(mailingListName, 'utf-8')
|
unic(ustr(mailingListName)))
|
||||||
)
|
|
||||||
|
|
||||||
QtGui.QWidget.resize(self, QtGui.QWidget.sizeHint(self))
|
QtWidgets.QWidget.resize(self, QtWidgets.QWidget.sizeHint(self))
|
||||||
self.show()
|
self.show()
|
||||||
|
|
||||||
def accept(self):
|
def accept(self):
|
||||||
|
@ -271,18 +279,18 @@ class SpecialAddressBehaviorDialog(QtGui.QDialog):
|
||||||
if self.address_is_chan:
|
if self.address_is_chan:
|
||||||
return
|
return
|
||||||
if self.radioButtonBehaveNormalAddress.isChecked():
|
if self.radioButtonBehaveNormalAddress.isChecked():
|
||||||
self.config.set(str(self.address), 'mailinglist', 'false')
|
self.config.set(self.address, 'mailinglist', 'false')
|
||||||
# Set the color to either black or grey
|
# Set the color to either black or grey
|
||||||
if self.config.getboolean(self.address, 'enabled'):
|
if self.config.getboolean(self.address, 'enabled'):
|
||||||
self.parent.setCurrentItemColor(
|
self.parent.setCurrentItemColor(
|
||||||
QtGui.QApplication.palette().text().color()
|
QtWidgets.QApplication.palette().text().color()
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
self.parent.setCurrentItemColor(QtGui.QColor(128, 128, 128))
|
self.parent.setCurrentItemColor(QtGui.QColor(128, 128, 128))
|
||||||
else:
|
else:
|
||||||
self.config.set(str(self.address), 'mailinglist', 'true')
|
self.config.set(self.address, 'mailinglist', 'true')
|
||||||
self.config.set(str(self.address), 'mailinglistname', str(
|
self.config.set(self.address, 'mailinglistname', ustr(
|
||||||
self.lineEditMailingListName.text().toUtf8()))
|
self.lineEditMailingListName.text()))
|
||||||
self.parent.setCurrentItemColor(
|
self.parent.setCurrentItemColor(
|
||||||
QtGui.QColor(137, 4, 177)) # magenta
|
QtGui.QColor(137, 4, 177)) # magenta
|
||||||
self.parent.rerenderComboBoxSendFrom()
|
self.parent.rerenderComboBoxSendFrom()
|
||||||
|
@ -291,13 +299,15 @@ class SpecialAddressBehaviorDialog(QtGui.QDialog):
|
||||||
self.parent.rerenderMessagelistToLabels()
|
self.parent.rerenderMessagelistToLabels()
|
||||||
|
|
||||||
|
|
||||||
class EmailGatewayDialog(QtGui.QDialog):
|
class EmailGatewayDialog(QtWidgets.QDialog):
|
||||||
"""QDialog for email gateway control"""
|
"""QDialog for email gateway control"""
|
||||||
|
|
||||||
def __init__(self, parent, config=global_config, account=None):
|
def __init__(self, parent, config=global_config, account=None):
|
||||||
super(EmailGatewayDialog, self).__init__(parent)
|
super(EmailGatewayDialog, self).__init__(parent)
|
||||||
widgets.load('emailgateway.ui', self)
|
widgets.load('emailgateway.ui', self)
|
||||||
self.parent = parent
|
self.parent = parent
|
||||||
self.config = config
|
self.config = config
|
||||||
|
self.data = None
|
||||||
if account:
|
if account:
|
||||||
self.acct = account
|
self.acct = account
|
||||||
self.setWindowTitle(_translate(
|
self.setWindowTitle(_translate(
|
||||||
|
@ -330,7 +340,7 @@ class EmailGatewayDialog(QtGui.QDialog):
|
||||||
else:
|
else:
|
||||||
self.acct = MailchuckAccount(address)
|
self.acct = MailchuckAccount(address)
|
||||||
self.lineEditEmail.setFocus()
|
self.lineEditEmail.setFocus()
|
||||||
QtGui.QWidget.resize(self, QtGui.QWidget.sizeHint(self))
|
QtWidgets.QWidget.resize(self, QtWidgets.QWidget.sizeHint(self))
|
||||||
|
|
||||||
def accept(self):
|
def accept(self):
|
||||||
"""Accept callback"""
|
"""Accept callback"""
|
||||||
|
@ -344,7 +354,7 @@ class EmailGatewayDialog(QtGui.QDialog):
|
||||||
|
|
||||||
if self.radioButtonRegister.isChecked() \
|
if self.radioButtonRegister.isChecked() \
|
||||||
or self.radioButtonRegister.isHidden():
|
or self.radioButtonRegister.isHidden():
|
||||||
email = str(self.lineEditEmail.text().toUtf8())
|
email = ustr(self.lineEditEmail.text())
|
||||||
self.acct.register(email)
|
self.acct.register(email)
|
||||||
self.config.set(self.acct.fromAddress, 'label', email)
|
self.config.set(self.acct.fromAddress, 'label', email)
|
||||||
self.config.set(self.acct.fromAddress, 'gateway', 'mailchuck')
|
self.config.set(self.acct.fromAddress, 'gateway', 'mailchuck')
|
||||||
|
|
|
@ -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 addresses import decodeAddress, addBMIfNotPresent
|
||||||
from bmconfigparser import config
|
from bmconfigparser import config
|
||||||
from queues import apiAddressGeneratorReturnQueue, addressGeneratorQueue
|
from queues import apiAddressGeneratorReturnQueue, addressGeneratorQueue
|
||||||
from tr import _translate
|
from tr import _translate
|
||||||
from utils import str_chan
|
from .utils import str_chan
|
||||||
|
|
||||||
|
|
||||||
class AddressPassPhraseValidatorMixin(object):
|
class AddressPassPhraseValidatorMixin(object):
|
||||||
"""Bitmessage address or passphrase validator class for Qt UI"""
|
"""Bitmessage address or passphrase validator class for Qt UI"""
|
||||||
def setParams(
|
def setParams(
|
||||||
self,
|
self, passPhraseObject=None, addressObject=None,
|
||||||
passPhraseObject=None,
|
feedBackObject=None, button=None, addressMandatory=True
|
||||||
addressObject=None,
|
|
||||||
feedBackObject=None,
|
|
||||||
buttonBox=None,
|
|
||||||
addressMandatory=True,
|
|
||||||
):
|
):
|
||||||
"""Initialisation"""
|
"""Initialization"""
|
||||||
self.addressObject = addressObject
|
self.addressObject = addressObject
|
||||||
self.passPhraseObject = passPhraseObject
|
self.passPhraseObject = passPhraseObject
|
||||||
self.feedBackObject = feedBackObject
|
self.feedBackObject = feedBackObject
|
||||||
self.buttonBox = buttonBox
|
|
||||||
self.addressMandatory = addressMandatory
|
self.addressMandatory = addressMandatory
|
||||||
self.isValid = False
|
self.isValid = False
|
||||||
# save default text
|
# save default text
|
||||||
self.okButtonLabel = self.buttonBox.button(QtGui.QDialogButtonBox.Ok).text()
|
self.okButton = button
|
||||||
|
self.okButtonLabel = button.text()
|
||||||
|
|
||||||
def setError(self, string):
|
def setError(self, string):
|
||||||
"""Indicate that the validation is pending or failed"""
|
"""Indicate that the validation is pending or failed"""
|
||||||
|
@ -43,13 +41,13 @@ class AddressPassPhraseValidatorMixin(object):
|
||||||
self.feedBackObject.setStyleSheet("QLabel { color : red; }")
|
self.feedBackObject.setStyleSheet("QLabel { color : red; }")
|
||||||
self.feedBackObject.setText(string)
|
self.feedBackObject.setText(string)
|
||||||
self.isValid = False
|
self.isValid = False
|
||||||
if self.buttonBox:
|
if self.okButton:
|
||||||
self.buttonBox.button(QtGui.QDialogButtonBox.Ok).setEnabled(False)
|
self.okButton.setEnabled(False)
|
||||||
if string is not None and self.feedBackObject is not None:
|
if string is not None and self.feedBackObject is not None:
|
||||||
self.buttonBox.button(QtGui.QDialogButtonBox.Ok).setText(
|
self.okButton.setText(
|
||||||
_translate("AddressValidator", "Invalid"))
|
_translate("AddressValidator", "Invalid"))
|
||||||
else:
|
else:
|
||||||
self.buttonBox.button(QtGui.QDialogButtonBox.Ok).setText(
|
self.okButton.setText(
|
||||||
_translate("AddressValidator", "Validating..."))
|
_translate("AddressValidator", "Validating..."))
|
||||||
|
|
||||||
def setOK(self, string):
|
def setOK(self, string):
|
||||||
|
@ -61,9 +59,9 @@ class AddressPassPhraseValidatorMixin(object):
|
||||||
self.feedBackObject.setStyleSheet("QLabel { }")
|
self.feedBackObject.setStyleSheet("QLabel { }")
|
||||||
self.feedBackObject.setText(string)
|
self.feedBackObject.setText(string)
|
||||||
self.isValid = True
|
self.isValid = True
|
||||||
if self.buttonBox:
|
if self.okButton:
|
||||||
self.buttonBox.button(QtGui.QDialogButtonBox.Ok).setEnabled(True)
|
self.okButton.setEnabled(True)
|
||||||
self.buttonBox.button(QtGui.QDialogButtonBox.Ok).setText(self.okButtonLabel)
|
self.okButton.setText(self.okButtonLabel)
|
||||||
|
|
||||||
def checkQueue(self):
|
def checkQueue(self):
|
||||||
"""Validator queue loop"""
|
"""Validator queue loop"""
|
||||||
|
@ -76,7 +74,8 @@ class AddressPassPhraseValidatorMixin(object):
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
addressGeneratorReturnValue = apiAddressGeneratorReturnQueue.get(False)
|
addressGeneratorReturnValue = \
|
||||||
|
apiAddressGeneratorReturnQueue.get(False)
|
||||||
except Empty:
|
except Empty:
|
||||||
if gotOne:
|
if gotOne:
|
||||||
break
|
break
|
||||||
|
@ -86,96 +85,120 @@ class AddressPassPhraseValidatorMixin(object):
|
||||||
gotOne = True
|
gotOne = True
|
||||||
|
|
||||||
if not addressGeneratorReturnValue:
|
if not addressGeneratorReturnValue:
|
||||||
self.setError(_translate("AddressValidator", "Address already present as one of your identities."))
|
self.setError(_translate(
|
||||||
return (QtGui.QValidator.Intermediate, 0)
|
"AddressValidator",
|
||||||
if addressGeneratorReturnValue[0] == 'chan name does not match address':
|
"Address already present as one of your identities."
|
||||||
self.setError(
|
))
|
||||||
_translate(
|
return
|
||||||
"AddressValidator",
|
if addressGeneratorReturnValue[0] == \
|
||||||
"Although the Bitmessage address you "
|
'chan name does not match address':
|
||||||
"entered was valid, it doesn't match the chan name."))
|
self.setError(_translate(
|
||||||
return (QtGui.QValidator.Intermediate, 0)
|
"AddressValidator",
|
||||||
self.setOK(_translate("MainWindow", "Passphrase and address appear to be valid."))
|
"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):
|
def returnValid(self):
|
||||||
"""Return the value of whether the validation was successful"""
|
"""Return the value of whether the validation was successful"""
|
||||||
if self.isValid:
|
return QtGui.QValidator.Acceptable if self.isValid \
|
||||||
return QtGui.QValidator.Acceptable
|
else QtGui.QValidator.Intermediate
|
||||||
return QtGui.QValidator.Intermediate
|
|
||||||
|
|
||||||
def validate(self, s, pos):
|
def validate(self, s, pos):
|
||||||
"""Top level validator method"""
|
"""Top level validator method"""
|
||||||
if self.addressObject is None:
|
try:
|
||||||
|
address = ustr(self.addressObject.text())
|
||||||
|
except AttributeError:
|
||||||
address = None
|
address = None
|
||||||
else:
|
try:
|
||||||
address = str(self.addressObject.text().toUtf8())
|
passPhrase = ustr(self.passPhraseObject.text())
|
||||||
if address == "":
|
except AttributeError:
|
||||||
address = None
|
|
||||||
if self.passPhraseObject is None:
|
|
||||||
passPhrase = ""
|
passPhrase = ""
|
||||||
else:
|
|
||||||
passPhrase = str(self.passPhraseObject.text().toUtf8())
|
|
||||||
if passPhrase == "":
|
|
||||||
passPhrase = None
|
|
||||||
|
|
||||||
# no chan name
|
# no chan name
|
||||||
if passPhrase is None:
|
if not passPhrase:
|
||||||
self.setError(_translate("AddressValidator", "Chan name/passphrase needed. You didn't enter a chan name."))
|
self.setError(_translate(
|
||||||
return (QtGui.QValidator.Intermediate, pos)
|
"AddressValidator",
|
||||||
|
"Chan name/passphrase needed. You didn't enter a chan name."
|
||||||
|
))
|
||||||
|
return (QtGui.QValidator.Intermediate, s, pos)
|
||||||
|
|
||||||
if self.addressMandatory or address is not None:
|
if self.addressMandatory or address:
|
||||||
# check if address already exists:
|
# check if address already exists:
|
||||||
if address in config.addresses():
|
if address in config.addresses(True):
|
||||||
self.setError(_translate("AddressValidator", "Address already present as one of your identities."))
|
self.setError(_translate(
|
||||||
return (QtGui.QValidator.Intermediate, pos)
|
"AddressValidator",
|
||||||
|
"Address already present as one of your identities."
|
||||||
|
))
|
||||||
|
return (QtGui.QValidator.Intermediate, s, pos)
|
||||||
|
|
||||||
|
status = decodeAddress(address)[0]
|
||||||
# version too high
|
# version too high
|
||||||
if decodeAddress(address)[0] == 'versiontoohigh':
|
if status == 'versiontoohigh':
|
||||||
self.setError(
|
self.setError(_translate(
|
||||||
_translate(
|
"AddressValidator",
|
||||||
"AddressValidator",
|
"Address too new. Although that Bitmessage address"
|
||||||
"Address too new. Although that Bitmessage"
|
" might be valid, its version number is too new"
|
||||||
" address might be valid, its version number"
|
" for us to handle. Perhaps you need to upgrade"
|
||||||
" is too new for us to handle. Perhaps you need"
|
" Bitmessage."
|
||||||
" to upgrade Bitmessage."))
|
))
|
||||||
return (QtGui.QValidator.Intermediate, pos)
|
return (QtGui.QValidator.Intermediate, s, pos)
|
||||||
|
|
||||||
# invalid
|
# invalid
|
||||||
if decodeAddress(address)[0] != 'success':
|
if status != 'success':
|
||||||
self.setError(_translate("AddressValidator", "The Bitmessage address is not valid."))
|
self.setError(_translate(
|
||||||
return (QtGui.QValidator.Intermediate, pos)
|
"AddressValidator",
|
||||||
|
"The Bitmessage address is not valid."
|
||||||
|
))
|
||||||
|
return (QtGui.QValidator.Intermediate, s, pos)
|
||||||
|
|
||||||
# this just disables the OK button without changing the feedback text
|
# this just disables the OK button without changing the feedback text
|
||||||
# but only if triggered by textEdited, not by clicking the Ok button
|
# but only if triggered by textEdited, not by clicking the Ok button
|
||||||
if not self.buttonBox.button(QtGui.QDialogButtonBox.Ok).hasFocus():
|
if not self.okButton.hasFocus():
|
||||||
self.setError(None)
|
self.setError(None)
|
||||||
|
|
||||||
# check through generator
|
# check through generator
|
||||||
if address is None:
|
if not address:
|
||||||
addressGeneratorQueue.put(('createChan', 4, 1, str_chan + ' ' + str(passPhrase), passPhrase, False))
|
addressGeneratorQueue.put((
|
||||||
|
'createChan', 4, 1,
|
||||||
|
str_chan + ' ' + passPhrase, passPhrase.encode("utf-8", "replace"), False
|
||||||
|
))
|
||||||
else:
|
else:
|
||||||
addressGeneratorQueue.put(
|
addressGeneratorQueue.put((
|
||||||
('joinChan', addBMIfNotPresent(address),
|
'joinChan', addBMIfNotPresent(address),
|
||||||
"{} {}".format(str_chan, passPhrase), passPhrase, False))
|
"{} {}".format(str_chan, passPhrase), passPhrase.encode("utf-8", "replace"), False
|
||||||
|
))
|
||||||
|
|
||||||
if self.buttonBox.button(QtGui.QDialogButtonBox.Ok).hasFocus():
|
if self.okButton.hasFocus():
|
||||||
return (self.returnValid(), pos)
|
return (self.returnValid(), s, pos)
|
||||||
return (QtGui.QValidator.Intermediate, pos)
|
else:
|
||||||
|
return (QtGui.QValidator.Intermediate, s, pos)
|
||||||
|
|
||||||
def checkData(self):
|
def checkData(self):
|
||||||
"""Validator Qt signal interface"""
|
"""Validator Qt signal interface"""
|
||||||
return self.validate("", 0)
|
return self.validate(u"", 0)
|
||||||
|
|
||||||
|
|
||||||
class AddressValidator(QtGui.QValidator, AddressPassPhraseValidatorMixin):
|
class AddressValidator(QtGui.QValidator, AddressPassPhraseValidatorMixin):
|
||||||
"""AddressValidator class for Qt UI"""
|
"""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)
|
super(AddressValidator, self).__init__(parent)
|
||||||
self.setParams(passPhraseObject, parent, feedBackObject, buttonBox, addressMandatory)
|
self.setParams(
|
||||||
|
passPhraseObject, parent, feedBackObject, button,
|
||||||
|
addressMandatory)
|
||||||
|
|
||||||
|
|
||||||
class PassPhraseValidator(QtGui.QValidator, AddressPassPhraseValidatorMixin):
|
class PassPhraseValidator(QtGui.QValidator, AddressPassPhraseValidatorMixin):
|
||||||
"""PassPhraseValidator class for Qt UI"""
|
"""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)
|
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!
|
# 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\
|
\x00\x00\x03\x66\
|
||||||
\x89\
|
\x89\
|
||||||
\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
|
\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
|
||||||
|
@ -1534,7 +1534,7 @@ qt_resource_data = "\
|
||||||
\x82\
|
\x82\
|
||||||
"
|
"
|
||||||
|
|
||||||
qt_resource_name = "\
|
qt_resource_name = b"\
|
||||||
\x00\x09\
|
\x00\x09\
|
||||||
\x0c\x78\x54\x88\
|
\x0c\x78\x54\x88\
|
||||||
\x00\x6e\
|
\x00\x6e\
|
||||||
|
@ -1639,7 +1639,7 @@ qt_resource_name = "\
|
||||||
\x00\x70\x00\x6e\x00\x67\
|
\x00\x70\x00\x6e\x00\x67\
|
||||||
"
|
"
|
||||||
|
|
||||||
qt_resource_struct = "\
|
qt_resource_struct = b"\
|
||||||
\x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x01\
|
\x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x01\
|
||||||
\x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x02\
|
\x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x02\
|
||||||
\x00\x00\x00\x18\x00\x02\x00\x00\x00\x15\x00\x00\x00\x03\
|
\x00\x00\x00\x18\x00\x02\x00\x00\x00\x15\x00\x00\x00\x03\
|
||||||
|
@ -1666,10 +1666,15 @@ qt_resource_struct = "\
|
||||||
\x00\x00\x01\xe6\x00\x00\x00\x00\x00\x01\x00\x00\x34\xdf\
|
\x00\x00\x01\xe6\x00\x00\x00\x00\x00\x01\x00\x00\x34\xdf\
|
||||||
"
|
"
|
||||||
|
|
||||||
|
|
||||||
def qInitResources():
|
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():
|
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()
|
qInitResources()
|
||||||
|
|
|
@ -1,59 +1,32 @@
|
||||||
# -*- coding: utf-8 -*-
|
# pylint: skip-file
|
||||||
|
# flake8: noqa
|
||||||
|
|
||||||
# Form implementation generated from reading ui file 'bitmessageui.ui'
|
from qtpy import QtCore, QtGui, QtWidgets
|
||||||
#
|
from tr import _translate
|
||||||
# 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 bmconfigparser import config
|
from bmconfigparser import config
|
||||||
from foldertree import AddressBookCompleter
|
from .foldertree import AddressBookCompleter
|
||||||
from messageview import MessageView
|
from .messageview import MessageView
|
||||||
from messagecompose import MessageCompose
|
from .messagecompose import MessageCompose
|
||||||
import settingsmixin
|
from bitmessageqt import settingsmixin
|
||||||
from networkstatus import NetworkStatus
|
from .networkstatus import NetworkStatus
|
||||||
from blacklist import Blacklist
|
from .blacklist import Blacklist
|
||||||
|
from bitmessageqt import bitmessage_icons_rc
|
||||||
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)
|
|
||||||
|
|
||||||
|
|
||||||
class Ui_MainWindow(object):
|
class Ui_MainWindow(object):
|
||||||
def setupUi(self, MainWindow):
|
def setupUi(self, MainWindow):
|
||||||
MainWindow.setObjectName(_fromUtf8("MainWindow"))
|
MainWindow.setObjectName("MainWindow")
|
||||||
MainWindow.resize(885, 580)
|
MainWindow.resize(885, 580)
|
||||||
icon = QtGui.QIcon()
|
icon = QtGui.QIcon()
|
||||||
icon.addPixmap(
|
icon.addPixmap(QtGui.QPixmap(":/newPrefix/images/can-icon-24px.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
||||||
QtGui.QPixmap(_fromUtf8(":/newPrefix/images/can-icon-24px.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off
|
|
||||||
)
|
|
||||||
MainWindow.setWindowIcon(icon)
|
MainWindow.setWindowIcon(icon)
|
||||||
MainWindow.setTabShape(QtGui.QTabWidget.Rounded)
|
MainWindow.setTabShape(QtWidgets.QTabWidget.Rounded)
|
||||||
self.centralwidget = QtGui.QWidget(MainWindow)
|
self.centralwidget = QtWidgets.QWidget(MainWindow)
|
||||||
self.centralwidget.setObjectName(_fromUtf8("centralwidget"))
|
self.centralwidget.setObjectName("centralwidget")
|
||||||
self.gridLayout_10 = QtGui.QGridLayout(self.centralwidget)
|
self.gridLayout_10 = QtWidgets.QGridLayout(self.centralwidget)
|
||||||
self.gridLayout_10.setObjectName(_fromUtf8("gridLayout_10"))
|
self.gridLayout_10.setObjectName("gridLayout_10")
|
||||||
self.tabWidget = QtGui.QTabWidget(self.centralwidget)
|
self.tabWidget = QtWidgets.QTabWidget(self.centralwidget)
|
||||||
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding)
|
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
|
||||||
sizePolicy.setHorizontalStretch(0)
|
sizePolicy.setHorizontalStretch(0)
|
||||||
sizePolicy.setVerticalStretch(0)
|
sizePolicy.setVerticalStretch(0)
|
||||||
sizePolicy.setHeightForWidth(self.tabWidget.sizePolicy().hasHeightForWidth())
|
sizePolicy.setHeightForWidth(self.tabWidget.sizePolicy().hasHeightForWidth())
|
||||||
|
@ -61,32 +34,30 @@ class Ui_MainWindow(object):
|
||||||
self.tabWidget.setMinimumSize(QtCore.QSize(0, 0))
|
self.tabWidget.setMinimumSize(QtCore.QSize(0, 0))
|
||||||
self.tabWidget.setBaseSize(QtCore.QSize(0, 0))
|
self.tabWidget.setBaseSize(QtCore.QSize(0, 0))
|
||||||
font = QtGui.QFont()
|
font = QtGui.QFont()
|
||||||
base_size = QtGui.QApplication.instance().font().pointSize()
|
base_size = QtWidgets.QApplication.instance().font().pointSize()
|
||||||
font.setPointSize(int(base_size * 0.75))
|
font.setPointSize(int(base_size * 0.75))
|
||||||
self.tabWidget.setFont(font)
|
self.tabWidget.setFont(font)
|
||||||
self.tabWidget.setTabPosition(QtGui.QTabWidget.North)
|
self.tabWidget.setTabPosition(QtWidgets.QTabWidget.North)
|
||||||
self.tabWidget.setTabShape(QtGui.QTabWidget.Rounded)
|
self.tabWidget.setTabShape(QtWidgets.QTabWidget.Rounded)
|
||||||
self.tabWidget.setObjectName(_fromUtf8("tabWidget"))
|
self.tabWidget.setObjectName("tabWidget")
|
||||||
self.inbox = QtGui.QWidget()
|
self.inbox = QtWidgets.QWidget()
|
||||||
self.inbox.setObjectName(_fromUtf8("inbox"))
|
self.inbox.setObjectName("inbox")
|
||||||
self.gridLayout = QtGui.QGridLayout(self.inbox)
|
self.gridLayout = QtWidgets.QGridLayout(self.inbox)
|
||||||
self.gridLayout.setObjectName(_fromUtf8("gridLayout"))
|
self.gridLayout.setObjectName("gridLayout")
|
||||||
self.horizontalSplitter_3 = settingsmixin.SSplitter()
|
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 = settingsmixin.SSplitter()
|
||||||
self.verticalSplitter_12.setObjectName(_fromUtf8("verticalSplitter_12"))
|
self.verticalSplitter_12.setObjectName("verticalSplitter_12")
|
||||||
self.verticalSplitter_12.setOrientation(QtCore.Qt.Vertical)
|
self.verticalSplitter_12.setOrientation(QtCore.Qt.Vertical)
|
||||||
self.treeWidgetYourIdentities = settingsmixin.STreeWidget(self.inbox)
|
self.treeWidgetYourIdentities = settingsmixin.STreeWidget(self.inbox)
|
||||||
self.treeWidgetYourIdentities.setObjectName(_fromUtf8("treeWidgetYourIdentities"))
|
self.treeWidgetYourIdentities.setObjectName("treeWidgetYourIdentities")
|
||||||
self.treeWidgetYourIdentities.resize(200, self.treeWidgetYourIdentities.height())
|
self.treeWidgetYourIdentities.resize(200, self.treeWidgetYourIdentities.height())
|
||||||
icon1 = QtGui.QIcon()
|
icon1 = QtGui.QIcon()
|
||||||
icon1.addPixmap(
|
icon1.addPixmap(QtGui.QPixmap(":/newPrefix/images/identities.png"), QtGui.QIcon.Selected, QtGui.QIcon.Off)
|
||||||
QtGui.QPixmap(_fromUtf8(":/newPrefix/images/identities.png")), QtGui.QIcon.Selected, QtGui.QIcon.Off
|
|
||||||
)
|
|
||||||
self.treeWidgetYourIdentities.headerItem().setIcon(0, icon1)
|
self.treeWidgetYourIdentities.headerItem().setIcon(0, icon1)
|
||||||
self.verticalSplitter_12.addWidget(self.treeWidgetYourIdentities)
|
self.verticalSplitter_12.addWidget(self.treeWidgetYourIdentities)
|
||||||
self.pushButtonNewAddress = QtGui.QPushButton(self.inbox)
|
self.pushButtonNewAddress = QtWidgets.QPushButton(self.inbox)
|
||||||
self.pushButtonNewAddress.setObjectName(_fromUtf8("pushButtonNewAddress"))
|
self.pushButtonNewAddress.setObjectName("pushButtonNewAddress")
|
||||||
self.pushButtonNewAddress.resize(200, self.pushButtonNewAddress.height())
|
self.pushButtonNewAddress.resize(200, self.pushButtonNewAddress.height())
|
||||||
self.verticalSplitter_12.addWidget(self.pushButtonNewAddress)
|
self.verticalSplitter_12.addWidget(self.pushButtonNewAddress)
|
||||||
self.verticalSplitter_12.setStretchFactor(0, 1)
|
self.verticalSplitter_12.setStretchFactor(0, 1)
|
||||||
|
@ -96,21 +67,21 @@ class Ui_MainWindow(object):
|
||||||
self.verticalSplitter_12.handle(1).setEnabled(False)
|
self.verticalSplitter_12.handle(1).setEnabled(False)
|
||||||
self.horizontalSplitter_3.addWidget(self.verticalSplitter_12)
|
self.horizontalSplitter_3.addWidget(self.verticalSplitter_12)
|
||||||
self.verticalSplitter_7 = settingsmixin.SSplitter()
|
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.verticalSplitter_7.setOrientation(QtCore.Qt.Vertical)
|
||||||
self.horizontalSplitterSearch = QtGui.QSplitter()
|
self.horizontalSplitterSearch = QtWidgets.QSplitter()
|
||||||
self.horizontalSplitterSearch.setObjectName(_fromUtf8("horizontalSplitterSearch"))
|
self.horizontalSplitterSearch.setObjectName("horizontalSplitterSearch")
|
||||||
self.inboxSearchLineEdit = QtGui.QLineEdit(self.inbox)
|
self.inboxSearchLineEdit = QtWidgets.QLineEdit(self.inbox)
|
||||||
self.inboxSearchLineEdit.setObjectName(_fromUtf8("inboxSearchLineEdit"))
|
self.inboxSearchLineEdit.setObjectName("inboxSearchLineEdit")
|
||||||
self.horizontalSplitterSearch.addWidget(self.inboxSearchLineEdit)
|
self.horizontalSplitterSearch.addWidget(self.inboxSearchLineEdit)
|
||||||
self.inboxSearchOption = QtGui.QComboBox(self.inbox)
|
self.inboxSearchOption = QtWidgets.QComboBox(self.inbox)
|
||||||
self.inboxSearchOption.setObjectName(_fromUtf8("inboxSearchOption"))
|
self.inboxSearchOption.setObjectName("inboxSearchOption")
|
||||||
self.inboxSearchOption.addItem(_fromUtf8(""))
|
self.inboxSearchOption.addItem("")
|
||||||
self.inboxSearchOption.addItem(_fromUtf8(""))
|
self.inboxSearchOption.addItem("")
|
||||||
self.inboxSearchOption.addItem(_fromUtf8(""))
|
self.inboxSearchOption.addItem("")
|
||||||
self.inboxSearchOption.addItem(_fromUtf8(""))
|
self.inboxSearchOption.addItem("")
|
||||||
self.inboxSearchOption.addItem(_fromUtf8(""))
|
self.inboxSearchOption.addItem("")
|
||||||
self.inboxSearchOption.setSizeAdjustPolicy(QtGui.QComboBox.AdjustToContents)
|
self.inboxSearchOption.setSizeAdjustPolicy(QtWidgets.QComboBox.AdjustToContents)
|
||||||
self.inboxSearchOption.setCurrentIndex(3)
|
self.inboxSearchOption.setCurrentIndex(3)
|
||||||
self.horizontalSplitterSearch.addWidget(self.inboxSearchOption)
|
self.horizontalSplitterSearch.addWidget(self.inboxSearchOption)
|
||||||
self.horizontalSplitterSearch.handle(1).setEnabled(False)
|
self.horizontalSplitterSearch.handle(1).setEnabled(False)
|
||||||
|
@ -118,21 +89,21 @@ class Ui_MainWindow(object):
|
||||||
self.horizontalSplitterSearch.setStretchFactor(1, 0)
|
self.horizontalSplitterSearch.setStretchFactor(1, 0)
|
||||||
self.verticalSplitter_7.addWidget(self.horizontalSplitterSearch)
|
self.verticalSplitter_7.addWidget(self.horizontalSplitterSearch)
|
||||||
self.tableWidgetInbox = settingsmixin.STableWidget(self.inbox)
|
self.tableWidgetInbox = settingsmixin.STableWidget(self.inbox)
|
||||||
self.tableWidgetInbox.setEditTriggers(QtGui.QAbstractItemView.NoEditTriggers)
|
self.tableWidgetInbox.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers)
|
||||||
self.tableWidgetInbox.setAlternatingRowColors(True)
|
self.tableWidgetInbox.setAlternatingRowColors(True)
|
||||||
self.tableWidgetInbox.setSelectionMode(QtGui.QAbstractItemView.ExtendedSelection)
|
self.tableWidgetInbox.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection)
|
||||||
self.tableWidgetInbox.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows)
|
self.tableWidgetInbox.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
|
||||||
self.tableWidgetInbox.setWordWrap(False)
|
self.tableWidgetInbox.setWordWrap(False)
|
||||||
self.tableWidgetInbox.setObjectName(_fromUtf8("tableWidgetInbox"))
|
self.tableWidgetInbox.setObjectName("tableWidgetInbox")
|
||||||
self.tableWidgetInbox.setColumnCount(4)
|
self.tableWidgetInbox.setColumnCount(4)
|
||||||
self.tableWidgetInbox.setRowCount(0)
|
self.tableWidgetInbox.setRowCount(0)
|
||||||
item = QtGui.QTableWidgetItem()
|
item = QtWidgets.QTableWidgetItem()
|
||||||
self.tableWidgetInbox.setHorizontalHeaderItem(0, item)
|
self.tableWidgetInbox.setHorizontalHeaderItem(0, item)
|
||||||
item = QtGui.QTableWidgetItem()
|
item = QtWidgets.QTableWidgetItem()
|
||||||
self.tableWidgetInbox.setHorizontalHeaderItem(1, item)
|
self.tableWidgetInbox.setHorizontalHeaderItem(1, item)
|
||||||
item = QtGui.QTableWidgetItem()
|
item = QtWidgets.QTableWidgetItem()
|
||||||
self.tableWidgetInbox.setHorizontalHeaderItem(2, item)
|
self.tableWidgetInbox.setHorizontalHeaderItem(2, item)
|
||||||
item = QtGui.QTableWidgetItem()
|
item = QtWidgets.QTableWidgetItem()
|
||||||
self.tableWidgetInbox.setHorizontalHeaderItem(3, item)
|
self.tableWidgetInbox.setHorizontalHeaderItem(3, item)
|
||||||
self.tableWidgetInbox.horizontalHeader().setCascadingSectionResizes(True)
|
self.tableWidgetInbox.horizontalHeader().setCascadingSectionResizes(True)
|
||||||
self.tableWidgetInbox.horizontalHeader().setDefaultSectionSize(200)
|
self.tableWidgetInbox.horizontalHeader().setDefaultSectionSize(200)
|
||||||
|
@ -146,7 +117,7 @@ class Ui_MainWindow(object):
|
||||||
self.textEditInboxMessage = MessageView(self.inbox)
|
self.textEditInboxMessage = MessageView(self.inbox)
|
||||||
self.textEditInboxMessage.setBaseSize(QtCore.QSize(0, 500))
|
self.textEditInboxMessage.setBaseSize(QtCore.QSize(0, 500))
|
||||||
self.textEditInboxMessage.setReadOnly(True)
|
self.textEditInboxMessage.setReadOnly(True)
|
||||||
self.textEditInboxMessage.setObjectName(_fromUtf8("textEditInboxMessage"))
|
self.textEditInboxMessage.setObjectName("textEditInboxMessage")
|
||||||
self.verticalSplitter_7.addWidget(self.textEditInboxMessage)
|
self.verticalSplitter_7.addWidget(self.textEditInboxMessage)
|
||||||
self.verticalSplitter_7.setStretchFactor(0, 0)
|
self.verticalSplitter_7.setStretchFactor(0, 0)
|
||||||
self.verticalSplitter_7.setStretchFactor(1, 1)
|
self.verticalSplitter_7.setStretchFactor(1, 1)
|
||||||
|
@ -162,52 +133,51 @@ class Ui_MainWindow(object):
|
||||||
self.horizontalSplitter_3.setCollapsible(1, False)
|
self.horizontalSplitter_3.setCollapsible(1, False)
|
||||||
self.gridLayout.addWidget(self.horizontalSplitter_3)
|
self.gridLayout.addWidget(self.horizontalSplitter_3)
|
||||||
icon2 = QtGui.QIcon()
|
icon2 = QtGui.QIcon()
|
||||||
icon2.addPixmap(QtGui.QPixmap(_fromUtf8(":/newPrefix/images/inbox.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
icon2.addPixmap(QtGui.QPixmap(":/newPrefix/images/inbox.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
||||||
self.tabWidget.addTab(self.inbox, icon2, _fromUtf8(""))
|
self.tabWidget.addTab(self.inbox, icon2, "")
|
||||||
self.send = QtGui.QWidget()
|
self.send = QtWidgets.QWidget()
|
||||||
self.send.setObjectName(_fromUtf8("send"))
|
self.send.setObjectName("send")
|
||||||
self.gridLayout_7 = QtGui.QGridLayout(self.send)
|
self.gridLayout_7 = QtWidgets.QGridLayout(self.send)
|
||||||
self.gridLayout_7.setObjectName(_fromUtf8("gridLayout_7"))
|
self.gridLayout_7.setObjectName("gridLayout_7")
|
||||||
self.horizontalSplitter = settingsmixin.SSplitter()
|
self.horizontalSplitter = settingsmixin.SSplitter()
|
||||||
self.horizontalSplitter.setObjectName(_fromUtf8("horizontalSplitter"))
|
self.horizontalSplitter.setObjectName("horizontalSplitter")
|
||||||
self.verticalSplitter_2 = settingsmixin.SSplitter()
|
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.verticalSplitter_2.setOrientation(QtCore.Qt.Vertical)
|
||||||
self.tableWidgetAddressBook = settingsmixin.STableWidget(self.send)
|
self.tableWidgetAddressBook = settingsmixin.STableWidget(self.send)
|
||||||
self.tableWidgetAddressBook.setAlternatingRowColors(True)
|
self.tableWidgetAddressBook.setAlternatingRowColors(True)
|
||||||
self.tableWidgetAddressBook.setSelectionMode(QtGui.QAbstractItemView.ExtendedSelection)
|
self.tableWidgetAddressBook.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection)
|
||||||
self.tableWidgetAddressBook.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows)
|
self.tableWidgetAddressBook.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
|
||||||
self.tableWidgetAddressBook.setObjectName(_fromUtf8("tableWidgetAddressBook"))
|
self.tableWidgetAddressBook.setObjectName("tableWidgetAddressBook")
|
||||||
self.tableWidgetAddressBook.setColumnCount(2)
|
self.tableWidgetAddressBook.setColumnCount(2)
|
||||||
self.tableWidgetAddressBook.setRowCount(0)
|
self.tableWidgetAddressBook.setRowCount(0)
|
||||||
self.tableWidgetAddressBook.resize(200, self.tableWidgetAddressBook.height())
|
self.tableWidgetAddressBook.resize(200, self.tableWidgetAddressBook.height())
|
||||||
item = QtGui.QTableWidgetItem()
|
item = QtWidgets.QTableWidgetItem()
|
||||||
icon3 = QtGui.QIcon()
|
icon3 = QtGui.QIcon()
|
||||||
icon3.addPixmap(
|
icon3.addPixmap(QtGui.QPixmap(":/newPrefix/images/addressbook.png"), QtGui.QIcon.Selected, QtGui.QIcon.Off)
|
||||||
QtGui.QPixmap(_fromUtf8(":/newPrefix/images/addressbook.png")), QtGui.QIcon.Selected, QtGui.QIcon.Off
|
|
||||||
)
|
|
||||||
item.setIcon(icon3)
|
item.setIcon(icon3)
|
||||||
self.tableWidgetAddressBook.setHorizontalHeaderItem(0, item)
|
self.tableWidgetAddressBook.setHorizontalHeaderItem(0, item)
|
||||||
item = QtGui.QTableWidgetItem()
|
item = QtWidgets.QTableWidgetItem()
|
||||||
self.tableWidgetAddressBook.setHorizontalHeaderItem(1, item)
|
self.tableWidgetAddressBook.setHorizontalHeaderItem(1, item)
|
||||||
self.tableWidgetAddressBook.horizontalHeader().setCascadingSectionResizes(True)
|
self.tableWidgetAddressBook.horizontalHeader().setCascadingSectionResizes(True)
|
||||||
self.tableWidgetAddressBook.horizontalHeader().setDefaultSectionSize(200)
|
self.tableWidgetAddressBook.horizontalHeader().setDefaultSectionSize(200)
|
||||||
self.tableWidgetAddressBook.horizontalHeader().setHighlightSections(False)
|
self.tableWidgetAddressBook.horizontalHeader().setHighlightSections(False)
|
||||||
self.tableWidgetAddressBook.horizontalHeader().setStretchLastSection(True)
|
self.tableWidgetAddressBook.horizontalHeader().setStretchLastSection(True)
|
||||||
self.tableWidgetAddressBook.verticalHeader().setVisible(False)
|
self.tableWidgetAddressBook.verticalHeader().setVisible(False)
|
||||||
|
self.tableWidgetAddressBook.setWordWrap(False)
|
||||||
self.verticalSplitter_2.addWidget(self.tableWidgetAddressBook)
|
self.verticalSplitter_2.addWidget(self.tableWidgetAddressBook)
|
||||||
self.addressBookCompleter = AddressBookCompleter()
|
self.addressBookCompleter = AddressBookCompleter()
|
||||||
self.addressBookCompleter.setCompletionMode(QtGui.QCompleter.PopupCompletion)
|
self.addressBookCompleter.setCompletionMode(QtWidgets.QCompleter.PopupCompletion)
|
||||||
self.addressBookCompleter.setCaseSensitivity(QtCore.Qt.CaseInsensitive)
|
self.addressBookCompleter.setCaseSensitivity(QtCore.Qt.CaseInsensitive)
|
||||||
self.addressBookCompleterModel = QtGui.QStringListModel()
|
self.addressBookCompleterModel = QtCore.QStringListModel()
|
||||||
self.addressBookCompleter.setModel(self.addressBookCompleterModel)
|
self.addressBookCompleter.setModel(self.addressBookCompleterModel)
|
||||||
self.pushButtonAddAddressBook = QtGui.QPushButton(self.send)
|
self.pushButtonAddAddressBook = QtWidgets.QPushButton(self.send)
|
||||||
self.pushButtonAddAddressBook.setObjectName(_fromUtf8("pushButtonAddAddressBook"))
|
self.pushButtonAddAddressBook.setObjectName("pushButtonAddAddressBook")
|
||||||
self.pushButtonAddAddressBook.resize(200, self.pushButtonAddAddressBook.height())
|
self.pushButtonAddAddressBook.resize(200, self.pushButtonAddAddressBook.height())
|
||||||
self.verticalSplitter_2.addWidget(self.pushButtonAddAddressBook)
|
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.resize(200, self.pushButtonFetchNamecoinID.height())
|
||||||
self.pushButtonFetchNamecoinID.setObjectName(_fromUtf8("pushButtonFetchNamecoinID"))
|
self.pushButtonFetchNamecoinID.setObjectName("pushButtonFetchNamecoinID")
|
||||||
self.verticalSplitter_2.addWidget(self.pushButtonFetchNamecoinID)
|
self.verticalSplitter_2.addWidget(self.pushButtonFetchNamecoinID)
|
||||||
self.verticalSplitter_2.setStretchFactor(0, 1)
|
self.verticalSplitter_2.setStretchFactor(0, 1)
|
||||||
self.verticalSplitter_2.setStretchFactor(1, 0)
|
self.verticalSplitter_2.setStretchFactor(1, 0)
|
||||||
|
@ -219,45 +189,45 @@ class Ui_MainWindow(object):
|
||||||
self.verticalSplitter_2.handle(2).setEnabled(False)
|
self.verticalSplitter_2.handle(2).setEnabled(False)
|
||||||
self.horizontalSplitter.addWidget(self.verticalSplitter_2)
|
self.horizontalSplitter.addWidget(self.verticalSplitter_2)
|
||||||
self.verticalSplitter = settingsmixin.SSplitter()
|
self.verticalSplitter = settingsmixin.SSplitter()
|
||||||
self.verticalSplitter.setObjectName(_fromUtf8("verticalSplitter"))
|
self.verticalSplitter.setObjectName("verticalSplitter")
|
||||||
self.verticalSplitter.setOrientation(QtCore.Qt.Vertical)
|
self.verticalSplitter.setOrientation(QtCore.Qt.Vertical)
|
||||||
self.tabWidgetSend = QtGui.QTabWidget(self.send)
|
self.tabWidgetSend = QtWidgets.QTabWidget(self.send)
|
||||||
self.tabWidgetSend.setObjectName(_fromUtf8("tabWidgetSend"))
|
self.tabWidgetSend.setObjectName("tabWidgetSend")
|
||||||
self.sendDirect = QtGui.QWidget()
|
self.sendDirect = QtWidgets.QWidget()
|
||||||
self.sendDirect.setObjectName(_fromUtf8("sendDirect"))
|
self.sendDirect.setObjectName("sendDirect")
|
||||||
self.gridLayout_8 = QtGui.QGridLayout(self.sendDirect)
|
self.gridLayout_8 = QtWidgets.QGridLayout(self.sendDirect)
|
||||||
self.gridLayout_8.setObjectName(_fromUtf8("gridLayout_8"))
|
self.gridLayout_8.setObjectName("gridLayout_8")
|
||||||
self.verticalSplitter_5 = settingsmixin.SSplitter()
|
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.verticalSplitter_5.setOrientation(QtCore.Qt.Vertical)
|
||||||
self.gridLayout_2 = QtGui.QGridLayout()
|
self.gridLayout_2 = QtWidgets.QGridLayout()
|
||||||
self.gridLayout_2.setObjectName(_fromUtf8("gridLayout_2"))
|
self.gridLayout_2.setObjectName("gridLayout_2")
|
||||||
self.label_3 = QtGui.QLabel(self.sendDirect)
|
self.label_3 = QtWidgets.QLabel(self.sendDirect)
|
||||||
self.label_3.setObjectName(_fromUtf8("label_3"))
|
self.label_3.setObjectName("label_3")
|
||||||
self.gridLayout_2.addWidget(self.label_3, 2, 0, 1, 1)
|
self.gridLayout_2.addWidget(self.label_3, 2, 0, 1, 1)
|
||||||
self.label_2 = QtGui.QLabel(self.sendDirect)
|
self.label_2 = QtWidgets.QLabel(self.sendDirect)
|
||||||
self.label_2.setObjectName(_fromUtf8("label_2"))
|
self.label_2.setObjectName("label_2")
|
||||||
self.gridLayout_2.addWidget(self.label_2, 0, 0, 1, 1)
|
self.gridLayout_2.addWidget(self.label_2, 0, 0, 1, 1)
|
||||||
self.lineEditSubject = QtGui.QLineEdit(self.sendDirect)
|
self.lineEditSubject = QtWidgets.QLineEdit(self.sendDirect)
|
||||||
self.lineEditSubject.setText(_fromUtf8(""))
|
self.lineEditSubject.setText("")
|
||||||
self.lineEditSubject.setObjectName(_fromUtf8("lineEditSubject"))
|
self.lineEditSubject.setObjectName("lineEditSubject")
|
||||||
self.gridLayout_2.addWidget(self.lineEditSubject, 2, 1, 1, 1)
|
self.gridLayout_2.addWidget(self.lineEditSubject, 2, 1, 1, 1)
|
||||||
self.label = QtGui.QLabel(self.sendDirect)
|
self.label = QtWidgets.QLabel(self.sendDirect)
|
||||||
self.label.setObjectName(_fromUtf8("label"))
|
self.label.setObjectName("label")
|
||||||
self.gridLayout_2.addWidget(self.label, 1, 0, 1, 1)
|
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.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.gridLayout_2.addWidget(self.comboBoxSendFrom, 0, 1, 1, 1)
|
||||||
self.lineEditTo = QtGui.QLineEdit(self.sendDirect)
|
self.lineEditTo = QtWidgets.QLineEdit(self.sendDirect)
|
||||||
self.lineEditTo.setObjectName(_fromUtf8("lineEditTo"))
|
self.lineEditTo.setObjectName("lineEditTo")
|
||||||
self.gridLayout_2.addWidget(self.lineEditTo, 1, 1, 1, 1)
|
self.gridLayout_2.addWidget(self.lineEditTo, 1, 1, 1, 1)
|
||||||
self.lineEditTo.setCompleter(self.addressBookCompleter)
|
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.gridLayout_2_Widget.setLayout(self.gridLayout_2)
|
||||||
self.verticalSplitter_5.addWidget(self.gridLayout_2_Widget)
|
self.verticalSplitter_5.addWidget(self.gridLayout_2_Widget)
|
||||||
self.textEditMessage = MessageCompose(self.sendDirect)
|
self.textEditMessage = MessageCompose(self.sendDirect)
|
||||||
self.textEditMessage.setObjectName(_fromUtf8("textEditMessage"))
|
self.textEditMessage.setObjectName("textEditMessage")
|
||||||
self.verticalSplitter_5.addWidget(self.textEditMessage)
|
self.verticalSplitter_5.addWidget(self.textEditMessage)
|
||||||
self.verticalSplitter_5.setStretchFactor(0, 0)
|
self.verticalSplitter_5.setStretchFactor(0, 0)
|
||||||
self.verticalSplitter_5.setStretchFactor(1, 1)
|
self.verticalSplitter_5.setStretchFactor(1, 1)
|
||||||
|
@ -265,35 +235,35 @@ class Ui_MainWindow(object):
|
||||||
self.verticalSplitter_5.setCollapsible(1, False)
|
self.verticalSplitter_5.setCollapsible(1, False)
|
||||||
self.verticalSplitter_5.handle(1).setEnabled(False)
|
self.verticalSplitter_5.handle(1).setEnabled(False)
|
||||||
self.gridLayout_8.addWidget(self.verticalSplitter_5, 0, 0, 1, 1)
|
self.gridLayout_8.addWidget(self.verticalSplitter_5, 0, 0, 1, 1)
|
||||||
self.tabWidgetSend.addTab(self.sendDirect, _fromUtf8(""))
|
self.tabWidgetSend.addTab(self.sendDirect, "")
|
||||||
self.sendBroadcast = QtGui.QWidget()
|
self.sendBroadcast = QtWidgets.QWidget()
|
||||||
self.sendBroadcast.setObjectName(_fromUtf8("sendBroadcast"))
|
self.sendBroadcast.setObjectName("sendBroadcast")
|
||||||
self.gridLayout_9 = QtGui.QGridLayout(self.sendBroadcast)
|
self.gridLayout_9 = QtWidgets.QGridLayout(self.sendBroadcast)
|
||||||
self.gridLayout_9.setObjectName(_fromUtf8("gridLayout_9"))
|
self.gridLayout_9.setObjectName("gridLayout_9")
|
||||||
self.verticalSplitter_6 = settingsmixin.SSplitter()
|
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.verticalSplitter_6.setOrientation(QtCore.Qt.Vertical)
|
||||||
self.gridLayout_5 = QtGui.QGridLayout()
|
self.gridLayout_5 = QtWidgets.QGridLayout()
|
||||||
self.gridLayout_5.setObjectName(_fromUtf8("gridLayout_5"))
|
self.gridLayout_5.setObjectName("gridLayout_5")
|
||||||
self.label_8 = QtGui.QLabel(self.sendBroadcast)
|
self.label_8 = QtWidgets.QLabel(self.sendBroadcast)
|
||||||
self.label_8.setObjectName(_fromUtf8("label_8"))
|
self.label_8.setObjectName("label_8")
|
||||||
self.gridLayout_5.addWidget(self.label_8, 0, 0, 1, 1)
|
self.gridLayout_5.addWidget(self.label_8, 0, 0, 1, 1)
|
||||||
self.lineEditSubjectBroadcast = QtGui.QLineEdit(self.sendBroadcast)
|
self.lineEditSubjectBroadcast = QtWidgets.QLineEdit(self.sendBroadcast)
|
||||||
self.lineEditSubjectBroadcast.setText(_fromUtf8(""))
|
self.lineEditSubjectBroadcast.setText("")
|
||||||
self.lineEditSubjectBroadcast.setObjectName(_fromUtf8("lineEditSubjectBroadcast"))
|
self.lineEditSubjectBroadcast.setObjectName("lineEditSubjectBroadcast")
|
||||||
self.gridLayout_5.addWidget(self.lineEditSubjectBroadcast, 1, 1, 1, 1)
|
self.gridLayout_5.addWidget(self.lineEditSubjectBroadcast, 1, 1, 1, 1)
|
||||||
self.label_7 = QtGui.QLabel(self.sendBroadcast)
|
self.label_7 = QtWidgets.QLabel(self.sendBroadcast)
|
||||||
self.label_7.setObjectName(_fromUtf8("label_7"))
|
self.label_7.setObjectName("label_7")
|
||||||
self.gridLayout_5.addWidget(self.label_7, 1, 0, 1, 1)
|
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.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.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.gridLayout_5_Widget.setLayout(self.gridLayout_5)
|
||||||
self.verticalSplitter_6.addWidget(self.gridLayout_5_Widget)
|
self.verticalSplitter_6.addWidget(self.gridLayout_5_Widget)
|
||||||
self.textEditMessageBroadcast = MessageCompose(self.sendBroadcast)
|
self.textEditMessageBroadcast = MessageCompose(self.sendBroadcast)
|
||||||
self.textEditMessageBroadcast.setObjectName(_fromUtf8("textEditMessageBroadcast"))
|
self.textEditMessageBroadcast.setObjectName("textEditMessageBroadcast")
|
||||||
self.verticalSplitter_6.addWidget(self.textEditMessageBroadcast)
|
self.verticalSplitter_6.addWidget(self.textEditMessageBroadcast)
|
||||||
self.verticalSplitter_6.setStretchFactor(0, 0)
|
self.verticalSplitter_6.setStretchFactor(0, 0)
|
||||||
self.verticalSplitter_6.setStretchFactor(1, 1)
|
self.verticalSplitter_6.setStretchFactor(1, 1)
|
||||||
|
@ -301,15 +271,15 @@ class Ui_MainWindow(object):
|
||||||
self.verticalSplitter_6.setCollapsible(1, False)
|
self.verticalSplitter_6.setCollapsible(1, False)
|
||||||
self.verticalSplitter_6.handle(1).setEnabled(False)
|
self.verticalSplitter_6.handle(1).setEnabled(False)
|
||||||
self.gridLayout_9.addWidget(self.verticalSplitter_6, 0, 0, 1, 1)
|
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.verticalSplitter.addWidget(self.tabWidgetSend)
|
||||||
self.tTLContainer = QtGui.QWidget()
|
self.tTLContainer = QtWidgets.QWidget()
|
||||||
self.tTLContainer.setSizePolicy(QtGui.QSizePolicy.MinimumExpanding, QtGui.QSizePolicy.Fixed)
|
self.tTLContainer.setSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Fixed)
|
||||||
self.horizontalLayout_5 = QtGui.QHBoxLayout()
|
self.horizontalLayout_5 = QtWidgets.QHBoxLayout()
|
||||||
self.tTLContainer.setLayout(self.horizontalLayout_5)
|
self.tTLContainer.setLayout(self.horizontalLayout_5)
|
||||||
self.horizontalLayout_5.setObjectName(_fromUtf8("horizontalLayout_5"))
|
self.horizontalLayout_5.setObjectName("horizontalLayout_5")
|
||||||
self.pushButtonTTL = QtGui.QPushButton(self.send)
|
self.pushButtonTTL = QtWidgets.QPushButton(self.send)
|
||||||
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.MinimumExpanding, QtGui.QSizePolicy.Fixed)
|
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Fixed)
|
||||||
sizePolicy.setHorizontalStretch(0)
|
sizePolicy.setHorizontalStretch(0)
|
||||||
sizePolicy.setVerticalStretch(0)
|
sizePolicy.setVerticalStretch(0)
|
||||||
sizePolicy.setHeightForWidth(self.pushButtonTTL.sizePolicy().hasHeightForWidth())
|
sizePolicy.setHeightForWidth(self.pushButtonTTL.sizePolicy().hasHeightForWidth())
|
||||||
|
@ -329,29 +299,29 @@ class Ui_MainWindow(object):
|
||||||
font.setUnderline(True)
|
font.setUnderline(True)
|
||||||
self.pushButtonTTL.setFont(font)
|
self.pushButtonTTL.setFont(font)
|
||||||
self.pushButtonTTL.setFlat(True)
|
self.pushButtonTTL.setFlat(True)
|
||||||
self.pushButtonTTL.setObjectName(_fromUtf8("pushButtonTTL"))
|
self.pushButtonTTL.setObjectName("pushButtonTTL")
|
||||||
self.horizontalLayout_5.addWidget(self.pushButtonTTL, 0, QtCore.Qt.AlignRight)
|
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.setMinimumSize(QtCore.QSize(70, 0))
|
||||||
self.horizontalSliderTTL.setOrientation(QtCore.Qt.Horizontal)
|
self.horizontalSliderTTL.setOrientation(QtCore.Qt.Horizontal)
|
||||||
self.horizontalSliderTTL.setInvertedAppearance(False)
|
self.horizontalSliderTTL.setInvertedAppearance(False)
|
||||||
self.horizontalSliderTTL.setInvertedControls(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.horizontalLayout_5.addWidget(self.horizontalSliderTTL, 0, QtCore.Qt.AlignLeft)
|
||||||
self.labelHumanFriendlyTTLDescription = QtGui.QLabel(self.send)
|
self.labelHumanFriendlyTTLDescription = QtWidgets.QLabel(self.send)
|
||||||
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.MinimumExpanding, QtGui.QSizePolicy.Fixed)
|
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Fixed)
|
||||||
sizePolicy.setHorizontalStretch(0)
|
sizePolicy.setHorizontalStretch(0)
|
||||||
sizePolicy.setVerticalStretch(0)
|
sizePolicy.setVerticalStretch(0)
|
||||||
sizePolicy.setHeightForWidth(self.labelHumanFriendlyTTLDescription.sizePolicy().hasHeightForWidth())
|
sizePolicy.setHeightForWidth(self.labelHumanFriendlyTTLDescription.sizePolicy().hasHeightForWidth())
|
||||||
self.labelHumanFriendlyTTLDescription.setSizePolicy(sizePolicy)
|
self.labelHumanFriendlyTTLDescription.setSizePolicy(sizePolicy)
|
||||||
self.labelHumanFriendlyTTLDescription.setMinimumSize(QtCore.QSize(45, 0))
|
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.horizontalLayout_5.addWidget(self.labelHumanFriendlyTTLDescription, 1, QtCore.Qt.AlignLeft)
|
||||||
self.pushButtonClear = QtGui.QPushButton(self.send)
|
self.pushButtonClear = QtWidgets.QPushButton(self.send)
|
||||||
self.pushButtonClear.setObjectName(_fromUtf8("pushButtonClear"))
|
self.pushButtonClear.setObjectName("pushButtonClear")
|
||||||
self.horizontalLayout_5.addWidget(self.pushButtonClear, 0, QtCore.Qt.AlignRight)
|
self.horizontalLayout_5.addWidget(self.pushButtonClear, 0, QtCore.Qt.AlignRight)
|
||||||
self.pushButtonSend = QtGui.QPushButton(self.send)
|
self.pushButtonSend = QtWidgets.QPushButton(self.send)
|
||||||
self.pushButtonSend.setObjectName(_fromUtf8("pushButtonSend"))
|
self.pushButtonSend.setObjectName("pushButtonSend")
|
||||||
self.horizontalLayout_5.addWidget(self.pushButtonSend, 0, QtCore.Qt.AlignRight)
|
self.horizontalLayout_5.addWidget(self.pushButtonSend, 0, QtCore.Qt.AlignRight)
|
||||||
self.horizontalSliderTTL.setMaximumSize(QtCore.QSize(105, self.pushButtonSend.height()))
|
self.horizontalSliderTTL.setMaximumSize(QtCore.QSize(105, self.pushButtonSend.height()))
|
||||||
self.verticalSplitter.addWidget(self.tTLContainer)
|
self.verticalSplitter.addWidget(self.tTLContainer)
|
||||||
|
@ -368,31 +338,29 @@ class Ui_MainWindow(object):
|
||||||
self.horizontalSplitter.setCollapsible(1, False)
|
self.horizontalSplitter.setCollapsible(1, False)
|
||||||
self.gridLayout_7.addWidget(self.horizontalSplitter, 0, 0, 1, 1)
|
self.gridLayout_7.addWidget(self.horizontalSplitter, 0, 0, 1, 1)
|
||||||
icon4 = QtGui.QIcon()
|
icon4 = QtGui.QIcon()
|
||||||
icon4.addPixmap(QtGui.QPixmap(_fromUtf8(":/newPrefix/images/send.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
icon4.addPixmap(QtGui.QPixmap(":/newPrefix/images/send.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
||||||
self.tabWidget.addTab(self.send, icon4, _fromUtf8(""))
|
self.tabWidget.addTab(self.send, icon4, "")
|
||||||
self.subscriptions = QtGui.QWidget()
|
self.subscriptions = QtWidgets.QWidget()
|
||||||
self.subscriptions.setObjectName(_fromUtf8("subscriptions"))
|
self.subscriptions.setObjectName("subscriptions")
|
||||||
self.gridLayout_3 = QtGui.QGridLayout(self.subscriptions)
|
self.gridLayout_3 = QtWidgets.QGridLayout(self.subscriptions)
|
||||||
self.gridLayout_3.setObjectName(_fromUtf8("gridLayout_3"))
|
self.gridLayout_3.setObjectName("gridLayout_3")
|
||||||
self.horizontalSplitter_4 = settingsmixin.SSplitter()
|
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 = settingsmixin.SSplitter()
|
||||||
self.verticalSplitter_3.setObjectName(_fromUtf8("verticalSplitter_3"))
|
self.verticalSplitter_3.setObjectName("verticalSplitter_3")
|
||||||
self.verticalSplitter_3.setOrientation(QtCore.Qt.Vertical)
|
self.verticalSplitter_3.setOrientation(QtCore.Qt.Vertical)
|
||||||
self.treeWidgetSubscriptions = settingsmixin.STreeWidget(self.subscriptions)
|
self.treeWidgetSubscriptions = settingsmixin.STreeWidget(self.subscriptions)
|
||||||
self.treeWidgetSubscriptions.setAlternatingRowColors(True)
|
self.treeWidgetSubscriptions.setAlternatingRowColors(True)
|
||||||
self.treeWidgetSubscriptions.setSelectionMode(QtGui.QAbstractItemView.SingleSelection)
|
self.treeWidgetSubscriptions.setSelectionMode(QtWidgets.QAbstractItemView.SingleSelection)
|
||||||
self.treeWidgetSubscriptions.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows)
|
self.treeWidgetSubscriptions.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
|
||||||
self.treeWidgetSubscriptions.setObjectName(_fromUtf8("treeWidgetSubscriptions"))
|
self.treeWidgetSubscriptions.setObjectName("treeWidgetSubscriptions")
|
||||||
self.treeWidgetSubscriptions.resize(200, self.treeWidgetSubscriptions.height())
|
self.treeWidgetSubscriptions.resize(200, self.treeWidgetSubscriptions.height())
|
||||||
icon5 = QtGui.QIcon()
|
icon5 = QtGui.QIcon()
|
||||||
icon5.addPixmap(
|
icon5.addPixmap(QtGui.QPixmap(":/newPrefix/images/subscriptions.png"), QtGui.QIcon.Selected, QtGui.QIcon.Off)
|
||||||
QtGui.QPixmap(_fromUtf8(":/newPrefix/images/subscriptions.png")), QtGui.QIcon.Selected, QtGui.QIcon.Off
|
|
||||||
)
|
|
||||||
self.treeWidgetSubscriptions.headerItem().setIcon(0, icon5)
|
self.treeWidgetSubscriptions.headerItem().setIcon(0, icon5)
|
||||||
self.verticalSplitter_3.addWidget(self.treeWidgetSubscriptions)
|
self.verticalSplitter_3.addWidget(self.treeWidgetSubscriptions)
|
||||||
self.pushButtonAddSubscription = QtGui.QPushButton(self.subscriptions)
|
self.pushButtonAddSubscription = QtWidgets.QPushButton(self.subscriptions)
|
||||||
self.pushButtonAddSubscription.setObjectName(_fromUtf8("pushButtonAddSubscription"))
|
self.pushButtonAddSubscription.setObjectName("pushButtonAddSubscription")
|
||||||
self.pushButtonAddSubscription.resize(200, self.pushButtonAddSubscription.height())
|
self.pushButtonAddSubscription.resize(200, self.pushButtonAddSubscription.height())
|
||||||
self.verticalSplitter_3.addWidget(self.pushButtonAddSubscription)
|
self.verticalSplitter_3.addWidget(self.pushButtonAddSubscription)
|
||||||
self.verticalSplitter_3.setStretchFactor(0, 1)
|
self.verticalSplitter_3.setStretchFactor(0, 1)
|
||||||
|
@ -402,20 +370,20 @@ class Ui_MainWindow(object):
|
||||||
self.verticalSplitter_3.handle(1).setEnabled(False)
|
self.verticalSplitter_3.handle(1).setEnabled(False)
|
||||||
self.horizontalSplitter_4.addWidget(self.verticalSplitter_3)
|
self.horizontalSplitter_4.addWidget(self.verticalSplitter_3)
|
||||||
self.verticalSplitter_4 = settingsmixin.SSplitter()
|
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.verticalSplitter_4.setOrientation(QtCore.Qt.Vertical)
|
||||||
self.horizontalSplitter_2 = QtGui.QSplitter()
|
self.horizontalSplitter_2 = QtWidgets.QSplitter()
|
||||||
self.horizontalSplitter_2.setObjectName(_fromUtf8("horizontalSplitter_2"))
|
self.horizontalSplitter_2.setObjectName("horizontalSplitter_2")
|
||||||
self.inboxSearchLineEditSubscriptions = QtGui.QLineEdit(self.subscriptions)
|
self.inboxSearchLineEditSubscriptions = QtWidgets.QLineEdit(self.subscriptions)
|
||||||
self.inboxSearchLineEditSubscriptions.setObjectName(_fromUtf8("inboxSearchLineEditSubscriptions"))
|
self.inboxSearchLineEditSubscriptions.setObjectName("inboxSearchLineEditSubscriptions")
|
||||||
self.horizontalSplitter_2.addWidget(self.inboxSearchLineEditSubscriptions)
|
self.horizontalSplitter_2.addWidget(self.inboxSearchLineEditSubscriptions)
|
||||||
self.inboxSearchOptionSubscriptions = QtGui.QComboBox(self.subscriptions)
|
self.inboxSearchOptionSubscriptions = QtWidgets.QComboBox(self.subscriptions)
|
||||||
self.inboxSearchOptionSubscriptions.setObjectName(_fromUtf8("inboxSearchOptionSubscriptions"))
|
self.inboxSearchOptionSubscriptions.setObjectName("inboxSearchOptionSubscriptions")
|
||||||
self.inboxSearchOptionSubscriptions.addItem(_fromUtf8(""))
|
self.inboxSearchOptionSubscriptions.addItem("")
|
||||||
self.inboxSearchOptionSubscriptions.addItem(_fromUtf8(""))
|
self.inboxSearchOptionSubscriptions.addItem("")
|
||||||
self.inboxSearchOptionSubscriptions.addItem(_fromUtf8(""))
|
self.inboxSearchOptionSubscriptions.addItem("")
|
||||||
self.inboxSearchOptionSubscriptions.addItem(_fromUtf8(""))
|
self.inboxSearchOptionSubscriptions.addItem("")
|
||||||
self.inboxSearchOptionSubscriptions.setSizeAdjustPolicy(QtGui.QComboBox.AdjustToContents)
|
self.inboxSearchOptionSubscriptions.setSizeAdjustPolicy(QtWidgets.QComboBox.AdjustToContents)
|
||||||
self.inboxSearchOptionSubscriptions.setCurrentIndex(2)
|
self.inboxSearchOptionSubscriptions.setCurrentIndex(2)
|
||||||
self.horizontalSplitter_2.addWidget(self.inboxSearchOptionSubscriptions)
|
self.horizontalSplitter_2.addWidget(self.inboxSearchOptionSubscriptions)
|
||||||
self.horizontalSplitter_2.handle(1).setEnabled(False)
|
self.horizontalSplitter_2.handle(1).setEnabled(False)
|
||||||
|
@ -423,21 +391,21 @@ class Ui_MainWindow(object):
|
||||||
self.horizontalSplitter_2.setStretchFactor(1, 0)
|
self.horizontalSplitter_2.setStretchFactor(1, 0)
|
||||||
self.verticalSplitter_4.addWidget(self.horizontalSplitter_2)
|
self.verticalSplitter_4.addWidget(self.horizontalSplitter_2)
|
||||||
self.tableWidgetInboxSubscriptions = settingsmixin.STableWidget(self.subscriptions)
|
self.tableWidgetInboxSubscriptions = settingsmixin.STableWidget(self.subscriptions)
|
||||||
self.tableWidgetInboxSubscriptions.setEditTriggers(QtGui.QAbstractItemView.NoEditTriggers)
|
self.tableWidgetInboxSubscriptions.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers)
|
||||||
self.tableWidgetInboxSubscriptions.setAlternatingRowColors(True)
|
self.tableWidgetInboxSubscriptions.setAlternatingRowColors(True)
|
||||||
self.tableWidgetInboxSubscriptions.setSelectionMode(QtGui.QAbstractItemView.ExtendedSelection)
|
self.tableWidgetInboxSubscriptions.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection)
|
||||||
self.tableWidgetInboxSubscriptions.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows)
|
self.tableWidgetInboxSubscriptions.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
|
||||||
self.tableWidgetInboxSubscriptions.setWordWrap(False)
|
self.tableWidgetInboxSubscriptions.setWordWrap(False)
|
||||||
self.tableWidgetInboxSubscriptions.setObjectName(_fromUtf8("tableWidgetInboxSubscriptions"))
|
self.tableWidgetInboxSubscriptions.setObjectName("tableWidgetInboxSubscriptions")
|
||||||
self.tableWidgetInboxSubscriptions.setColumnCount(4)
|
self.tableWidgetInboxSubscriptions.setColumnCount(4)
|
||||||
self.tableWidgetInboxSubscriptions.setRowCount(0)
|
self.tableWidgetInboxSubscriptions.setRowCount(0)
|
||||||
item = QtGui.QTableWidgetItem()
|
item = QtWidgets.QTableWidgetItem()
|
||||||
self.tableWidgetInboxSubscriptions.setHorizontalHeaderItem(0, item)
|
self.tableWidgetInboxSubscriptions.setHorizontalHeaderItem(0, item)
|
||||||
item = QtGui.QTableWidgetItem()
|
item = QtWidgets.QTableWidgetItem()
|
||||||
self.tableWidgetInboxSubscriptions.setHorizontalHeaderItem(1, item)
|
self.tableWidgetInboxSubscriptions.setHorizontalHeaderItem(1, item)
|
||||||
item = QtGui.QTableWidgetItem()
|
item = QtWidgets.QTableWidgetItem()
|
||||||
self.tableWidgetInboxSubscriptions.setHorizontalHeaderItem(2, item)
|
self.tableWidgetInboxSubscriptions.setHorizontalHeaderItem(2, item)
|
||||||
item = QtGui.QTableWidgetItem()
|
item = QtWidgets.QTableWidgetItem()
|
||||||
self.tableWidgetInboxSubscriptions.setHorizontalHeaderItem(3, item)
|
self.tableWidgetInboxSubscriptions.setHorizontalHeaderItem(3, item)
|
||||||
self.tableWidgetInboxSubscriptions.horizontalHeader().setCascadingSectionResizes(True)
|
self.tableWidgetInboxSubscriptions.horizontalHeader().setCascadingSectionResizes(True)
|
||||||
self.tableWidgetInboxSubscriptions.horizontalHeader().setDefaultSectionSize(200)
|
self.tableWidgetInboxSubscriptions.horizontalHeader().setDefaultSectionSize(200)
|
||||||
|
@ -451,7 +419,7 @@ class Ui_MainWindow(object):
|
||||||
self.textEditInboxMessageSubscriptions = MessageView(self.subscriptions)
|
self.textEditInboxMessageSubscriptions = MessageView(self.subscriptions)
|
||||||
self.textEditInboxMessageSubscriptions.setBaseSize(QtCore.QSize(0, 500))
|
self.textEditInboxMessageSubscriptions.setBaseSize(QtCore.QSize(0, 500))
|
||||||
self.textEditInboxMessageSubscriptions.setReadOnly(True)
|
self.textEditInboxMessageSubscriptions.setReadOnly(True)
|
||||||
self.textEditInboxMessageSubscriptions.setObjectName(_fromUtf8("textEditInboxMessageSubscriptions"))
|
self.textEditInboxMessageSubscriptions.setObjectName("textEditInboxMessageSubscriptions")
|
||||||
self.verticalSplitter_4.addWidget(self.textEditInboxMessageSubscriptions)
|
self.verticalSplitter_4.addWidget(self.textEditInboxMessageSubscriptions)
|
||||||
self.verticalSplitter_4.setStretchFactor(0, 0)
|
self.verticalSplitter_4.setStretchFactor(0, 0)
|
||||||
self.verticalSplitter_4.setStretchFactor(1, 1)
|
self.verticalSplitter_4.setStretchFactor(1, 1)
|
||||||
|
@ -467,35 +435,31 @@ class Ui_MainWindow(object):
|
||||||
self.horizontalSplitter_4.setCollapsible(1, False)
|
self.horizontalSplitter_4.setCollapsible(1, False)
|
||||||
self.gridLayout_3.addWidget(self.horizontalSplitter_4, 0, 0, 1, 1)
|
self.gridLayout_3.addWidget(self.horizontalSplitter_4, 0, 0, 1, 1)
|
||||||
icon6 = QtGui.QIcon()
|
icon6 = QtGui.QIcon()
|
||||||
icon6.addPixmap(
|
icon6.addPixmap(QtGui.QPixmap(":/newPrefix/images/subscriptions.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
||||||
QtGui.QPixmap(_fromUtf8(":/newPrefix/images/subscriptions.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off
|
self.tabWidget.addTab(self.subscriptions, icon6, "")
|
||||||
)
|
self.chans = QtWidgets.QWidget()
|
||||||
self.tabWidget.addTab(self.subscriptions, icon6, _fromUtf8(""))
|
self.chans.setObjectName("chans")
|
||||||
self.chans = QtGui.QWidget()
|
self.gridLayout_4 = QtWidgets.QGridLayout(self.chans)
|
||||||
self.chans.setObjectName(_fromUtf8("chans"))
|
self.gridLayout_4.setObjectName("gridLayout_4")
|
||||||
self.gridLayout_4 = QtGui.QGridLayout(self.chans)
|
|
||||||
self.gridLayout_4.setObjectName(_fromUtf8("gridLayout_4"))
|
|
||||||
self.horizontalSplitter_7 = settingsmixin.SSplitter()
|
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 = settingsmixin.SSplitter()
|
||||||
self.verticalSplitter_17.setObjectName(_fromUtf8("verticalSplitter_17"))
|
self.verticalSplitter_17.setObjectName("verticalSplitter_17")
|
||||||
self.verticalSplitter_17.setOrientation(QtCore.Qt.Vertical)
|
self.verticalSplitter_17.setOrientation(QtCore.Qt.Vertical)
|
||||||
self.treeWidgetChans = settingsmixin.STreeWidget(self.chans)
|
self.treeWidgetChans = settingsmixin.STreeWidget(self.chans)
|
||||||
self.treeWidgetChans.setFrameShadow(QtGui.QFrame.Sunken)
|
self.treeWidgetChans.setFrameShadow(QtWidgets.QFrame.Sunken)
|
||||||
self.treeWidgetChans.setLineWidth(1)
|
self.treeWidgetChans.setLineWidth(1)
|
||||||
self.treeWidgetChans.setAlternatingRowColors(True)
|
self.treeWidgetChans.setAlternatingRowColors(True)
|
||||||
self.treeWidgetChans.setSelectionMode(QtGui.QAbstractItemView.SingleSelection)
|
self.treeWidgetChans.setSelectionMode(QtWidgets.QAbstractItemView.SingleSelection)
|
||||||
self.treeWidgetChans.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows)
|
self.treeWidgetChans.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
|
||||||
self.treeWidgetChans.setObjectName(_fromUtf8("treeWidgetChans"))
|
self.treeWidgetChans.setObjectName("treeWidgetChans")
|
||||||
self.treeWidgetChans.resize(200, self.treeWidgetChans.height())
|
self.treeWidgetChans.resize(200, self.treeWidgetChans.height())
|
||||||
icon7 = QtGui.QIcon()
|
icon7 = QtGui.QIcon()
|
||||||
icon7.addPixmap(
|
icon7.addPixmap(QtGui.QPixmap(":/newPrefix/images/can-icon-16px.png"), QtGui.QIcon.Selected, QtGui.QIcon.Off)
|
||||||
QtGui.QPixmap(_fromUtf8(":/newPrefix/images/can-icon-16px.png")), QtGui.QIcon.Selected, QtGui.QIcon.Off
|
|
||||||
)
|
|
||||||
self.treeWidgetChans.headerItem().setIcon(0, icon7)
|
self.treeWidgetChans.headerItem().setIcon(0, icon7)
|
||||||
self.verticalSplitter_17.addWidget(self.treeWidgetChans)
|
self.verticalSplitter_17.addWidget(self.treeWidgetChans)
|
||||||
self.pushButtonAddChan = QtGui.QPushButton(self.chans)
|
self.pushButtonAddChan = QtWidgets.QPushButton(self.chans)
|
||||||
self.pushButtonAddChan.setObjectName(_fromUtf8("pushButtonAddChan"))
|
self.pushButtonAddChan.setObjectName("pushButtonAddChan")
|
||||||
self.pushButtonAddChan.resize(200, self.pushButtonAddChan.height())
|
self.pushButtonAddChan.resize(200, self.pushButtonAddChan.height())
|
||||||
self.verticalSplitter_17.addWidget(self.pushButtonAddChan)
|
self.verticalSplitter_17.addWidget(self.pushButtonAddChan)
|
||||||
self.verticalSplitter_17.setStretchFactor(0, 1)
|
self.verticalSplitter_17.setStretchFactor(0, 1)
|
||||||
|
@ -505,21 +469,21 @@ class Ui_MainWindow(object):
|
||||||
self.verticalSplitter_17.handle(1).setEnabled(False)
|
self.verticalSplitter_17.handle(1).setEnabled(False)
|
||||||
self.horizontalSplitter_7.addWidget(self.verticalSplitter_17)
|
self.horizontalSplitter_7.addWidget(self.verticalSplitter_17)
|
||||||
self.verticalSplitter_8 = settingsmixin.SSplitter()
|
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.verticalSplitter_8.setOrientation(QtCore.Qt.Vertical)
|
||||||
self.horizontalSplitter_6 = QtGui.QSplitter()
|
self.horizontalSplitter_6 = QtWidgets.QSplitter()
|
||||||
self.horizontalSplitter_6.setObjectName(_fromUtf8("horizontalSplitter_6"))
|
self.horizontalSplitter_6.setObjectName("horizontalSplitter_6")
|
||||||
self.inboxSearchLineEditChans = QtGui.QLineEdit(self.chans)
|
self.inboxSearchLineEditChans = QtWidgets.QLineEdit(self.chans)
|
||||||
self.inboxSearchLineEditChans.setObjectName(_fromUtf8("inboxSearchLineEditChans"))
|
self.inboxSearchLineEditChans.setObjectName("inboxSearchLineEditChans")
|
||||||
self.horizontalSplitter_6.addWidget(self.inboxSearchLineEditChans)
|
self.horizontalSplitter_6.addWidget(self.inboxSearchLineEditChans)
|
||||||
self.inboxSearchOptionChans = QtGui.QComboBox(self.chans)
|
self.inboxSearchOptionChans = QtWidgets.QComboBox(self.chans)
|
||||||
self.inboxSearchOptionChans.setObjectName(_fromUtf8("inboxSearchOptionChans"))
|
self.inboxSearchOptionChans.setObjectName("inboxSearchOptionChans")
|
||||||
self.inboxSearchOptionChans.addItem(_fromUtf8(""))
|
self.inboxSearchOptionChans.addItem("")
|
||||||
self.inboxSearchOptionChans.addItem(_fromUtf8(""))
|
self.inboxSearchOptionChans.addItem("")
|
||||||
self.inboxSearchOptionChans.addItem(_fromUtf8(""))
|
self.inboxSearchOptionChans.addItem("")
|
||||||
self.inboxSearchOptionChans.addItem(_fromUtf8(""))
|
self.inboxSearchOptionChans.addItem("")
|
||||||
self.inboxSearchOptionChans.addItem(_fromUtf8(""))
|
self.inboxSearchOptionChans.addItem("")
|
||||||
self.inboxSearchOptionChans.setSizeAdjustPolicy(QtGui.QComboBox.AdjustToContents)
|
self.inboxSearchOptionChans.setSizeAdjustPolicy(QtWidgets.QComboBox.AdjustToContents)
|
||||||
self.inboxSearchOptionChans.setCurrentIndex(3)
|
self.inboxSearchOptionChans.setCurrentIndex(3)
|
||||||
self.horizontalSplitter_6.addWidget(self.inboxSearchOptionChans)
|
self.horizontalSplitter_6.addWidget(self.inboxSearchOptionChans)
|
||||||
self.horizontalSplitter_6.handle(1).setEnabled(False)
|
self.horizontalSplitter_6.handle(1).setEnabled(False)
|
||||||
|
@ -527,21 +491,21 @@ class Ui_MainWindow(object):
|
||||||
self.horizontalSplitter_6.setStretchFactor(1, 0)
|
self.horizontalSplitter_6.setStretchFactor(1, 0)
|
||||||
self.verticalSplitter_8.addWidget(self.horizontalSplitter_6)
|
self.verticalSplitter_8.addWidget(self.horizontalSplitter_6)
|
||||||
self.tableWidgetInboxChans = settingsmixin.STableWidget(self.chans)
|
self.tableWidgetInboxChans = settingsmixin.STableWidget(self.chans)
|
||||||
self.tableWidgetInboxChans.setEditTriggers(QtGui.QAbstractItemView.NoEditTriggers)
|
self.tableWidgetInboxChans.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers)
|
||||||
self.tableWidgetInboxChans.setAlternatingRowColors(True)
|
self.tableWidgetInboxChans.setAlternatingRowColors(True)
|
||||||
self.tableWidgetInboxChans.setSelectionMode(QtGui.QAbstractItemView.ExtendedSelection)
|
self.tableWidgetInboxChans.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection)
|
||||||
self.tableWidgetInboxChans.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows)
|
self.tableWidgetInboxChans.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
|
||||||
self.tableWidgetInboxChans.setWordWrap(False)
|
self.tableWidgetInboxChans.setWordWrap(False)
|
||||||
self.tableWidgetInboxChans.setObjectName(_fromUtf8("tableWidgetInboxChans"))
|
self.tableWidgetInboxChans.setObjectName("tableWidgetInboxChans")
|
||||||
self.tableWidgetInboxChans.setColumnCount(4)
|
self.tableWidgetInboxChans.setColumnCount(4)
|
||||||
self.tableWidgetInboxChans.setRowCount(0)
|
self.tableWidgetInboxChans.setRowCount(0)
|
||||||
item = QtGui.QTableWidgetItem()
|
item = QtWidgets.QTableWidgetItem()
|
||||||
self.tableWidgetInboxChans.setHorizontalHeaderItem(0, item)
|
self.tableWidgetInboxChans.setHorizontalHeaderItem(0, item)
|
||||||
item = QtGui.QTableWidgetItem()
|
item = QtWidgets.QTableWidgetItem()
|
||||||
self.tableWidgetInboxChans.setHorizontalHeaderItem(1, item)
|
self.tableWidgetInboxChans.setHorizontalHeaderItem(1, item)
|
||||||
item = QtGui.QTableWidgetItem()
|
item = QtWidgets.QTableWidgetItem()
|
||||||
self.tableWidgetInboxChans.setHorizontalHeaderItem(2, item)
|
self.tableWidgetInboxChans.setHorizontalHeaderItem(2, item)
|
||||||
item = QtGui.QTableWidgetItem()
|
item = QtWidgets.QTableWidgetItem()
|
||||||
self.tableWidgetInboxChans.setHorizontalHeaderItem(3, item)
|
self.tableWidgetInboxChans.setHorizontalHeaderItem(3, item)
|
||||||
self.tableWidgetInboxChans.horizontalHeader().setCascadingSectionResizes(True)
|
self.tableWidgetInboxChans.horizontalHeader().setCascadingSectionResizes(True)
|
||||||
self.tableWidgetInboxChans.horizontalHeader().setDefaultSectionSize(200)
|
self.tableWidgetInboxChans.horizontalHeader().setDefaultSectionSize(200)
|
||||||
|
@ -555,7 +519,7 @@ class Ui_MainWindow(object):
|
||||||
self.textEditInboxMessageChans = MessageView(self.chans)
|
self.textEditInboxMessageChans = MessageView(self.chans)
|
||||||
self.textEditInboxMessageChans.setBaseSize(QtCore.QSize(0, 500))
|
self.textEditInboxMessageChans.setBaseSize(QtCore.QSize(0, 500))
|
||||||
self.textEditInboxMessageChans.setReadOnly(True)
|
self.textEditInboxMessageChans.setReadOnly(True)
|
||||||
self.textEditInboxMessageChans.setObjectName(_fromUtf8("textEditInboxMessageChans"))
|
self.textEditInboxMessageChans.setObjectName("textEditInboxMessageChans")
|
||||||
self.verticalSplitter_8.addWidget(self.textEditInboxMessageChans)
|
self.verticalSplitter_8.addWidget(self.textEditInboxMessageChans)
|
||||||
self.verticalSplitter_8.setStretchFactor(0, 0)
|
self.verticalSplitter_8.setStretchFactor(0, 0)
|
||||||
self.verticalSplitter_8.setStretchFactor(1, 1)
|
self.verticalSplitter_8.setStretchFactor(1, 1)
|
||||||
|
@ -571,10 +535,8 @@ class Ui_MainWindow(object):
|
||||||
self.horizontalSplitter_7.setCollapsible(1, False)
|
self.horizontalSplitter_7.setCollapsible(1, False)
|
||||||
self.gridLayout_4.addWidget(self.horizontalSplitter_7, 0, 0, 1, 1)
|
self.gridLayout_4.addWidget(self.horizontalSplitter_7, 0, 0, 1, 1)
|
||||||
icon8 = QtGui.QIcon()
|
icon8 = QtGui.QIcon()
|
||||||
icon8.addPixmap(
|
icon8.addPixmap(QtGui.QPixmap(":/newPrefix/images/can-icon-16px.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
||||||
QtGui.QPixmap(_fromUtf8(":/newPrefix/images/can-icon-16px.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off
|
self.tabWidget.addTab(self.chans, icon8, "")
|
||||||
)
|
|
||||||
self.tabWidget.addTab(self.chans, icon8, _fromUtf8(""))
|
|
||||||
self.blackwhitelist = Blacklist()
|
self.blackwhitelist = Blacklist()
|
||||||
self.tabWidget.addTab(self.blackwhitelist, QtGui.QIcon(":/newPrefix/images/blacklist.png"), "")
|
self.tabWidget.addTab(self.blackwhitelist, QtGui.QIcon(":/newPrefix/images/blacklist.png"), "")
|
||||||
# Initialize the Blacklist or Whitelist
|
# 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.tabWidget.addTab(self.networkstatus, QtGui.QIcon(":/newPrefix/images/networkstatus.png"), "")
|
||||||
self.gridLayout_10.addWidget(self.tabWidget, 0, 0, 1, 1)
|
self.gridLayout_10.addWidget(self.tabWidget, 0, 0, 1, 1)
|
||||||
MainWindow.setCentralWidget(self.centralwidget)
|
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.setGeometry(QtCore.QRect(0, 0, 885, 27))
|
||||||
self.menubar.setObjectName(_fromUtf8("menubar"))
|
self.menubar.setObjectName("menubar")
|
||||||
self.menuFile = QtGui.QMenu(self.menubar)
|
self.menuFile = QtWidgets.QMenu(self.menubar)
|
||||||
self.menuFile.setObjectName(_fromUtf8("menuFile"))
|
self.menuFile.setObjectName("menuFile")
|
||||||
self.menuSettings = QtGui.QMenu(self.menubar)
|
self.menuSettings = QtWidgets.QMenu(self.menubar)
|
||||||
self.menuSettings.setObjectName(_fromUtf8("menuSettings"))
|
self.menuSettings.setObjectName("menuSettings")
|
||||||
self.menuHelp = QtGui.QMenu(self.menubar)
|
self.menuHelp = QtWidgets.QMenu(self.menubar)
|
||||||
self.menuHelp.setObjectName(_fromUtf8("menuHelp"))
|
self.menuHelp.setObjectName("menuHelp")
|
||||||
MainWindow.setMenuBar(self.menubar)
|
MainWindow.setMenuBar(self.menubar)
|
||||||
self.statusbar = QtGui.QStatusBar(MainWindow)
|
self.statusbar = QtWidgets.QStatusBar(MainWindow)
|
||||||
self.statusbar.setMaximumSize(QtCore.QSize(16777215, 22))
|
self.statusbar.setMaximumSize(QtCore.QSize(16777215, 22))
|
||||||
self.statusbar.setObjectName(_fromUtf8("statusbar"))
|
self.statusbar.setObjectName("statusbar")
|
||||||
MainWindow.setStatusBar(self.statusbar)
|
MainWindow.setStatusBar(self.statusbar)
|
||||||
self.actionImport_keys = QtGui.QAction(MainWindow)
|
self.actionImport_keys = QtWidgets.QAction(MainWindow)
|
||||||
self.actionImport_keys.setObjectName(_fromUtf8("actionImport_keys"))
|
self.actionImport_keys.setObjectName("actionImport_keys")
|
||||||
self.actionManageKeys = QtGui.QAction(MainWindow)
|
self.actionManageKeys = QtWidgets.QAction(MainWindow)
|
||||||
self.actionManageKeys.setCheckable(False)
|
self.actionManageKeys.setCheckable(False)
|
||||||
self.actionManageKeys.setEnabled(True)
|
self.actionManageKeys.setEnabled(True)
|
||||||
icon = QtGui.QIcon.fromTheme(_fromUtf8("dialog-password"))
|
icon = QtGui.QIcon.fromTheme("dialog-password")
|
||||||
self.actionManageKeys.setIcon(icon)
|
self.actionManageKeys.setIcon(icon)
|
||||||
self.actionManageKeys.setObjectName(_fromUtf8("actionManageKeys"))
|
self.actionManageKeys.setObjectName("actionManageKeys")
|
||||||
self.actionNetworkSwitch = QtGui.QAction(MainWindow)
|
self.actionNetworkSwitch = QtWidgets.QAction(MainWindow)
|
||||||
self.actionNetworkSwitch.setObjectName(_fromUtf8("actionNetworkSwitch"))
|
self.actionNetworkSwitch.setObjectName("actionNetworkSwitch")
|
||||||
self.actionExit = QtGui.QAction(MainWindow)
|
self.actionExit = QtWidgets.QAction(MainWindow)
|
||||||
icon = QtGui.QIcon.fromTheme(_fromUtf8("application-exit"))
|
icon = QtGui.QIcon.fromTheme("application-exit")
|
||||||
self.actionExit.setIcon(icon)
|
self.actionExit.setIcon(icon)
|
||||||
self.actionExit.setObjectName(_fromUtf8("actionExit"))
|
self.actionExit.setObjectName("actionExit")
|
||||||
self.actionHelp = QtGui.QAction(MainWindow)
|
self.actionHelp = QtWidgets.QAction(MainWindow)
|
||||||
icon = QtGui.QIcon.fromTheme(_fromUtf8("help-contents"))
|
icon = QtGui.QIcon.fromTheme("help-contents")
|
||||||
self.actionHelp.setIcon(icon)
|
self.actionHelp.setIcon(icon)
|
||||||
self.actionHelp.setObjectName(_fromUtf8("actionHelp"))
|
self.actionHelp.setObjectName("actionHelp")
|
||||||
self.actionSupport = QtGui.QAction(MainWindow)
|
self.actionSupport = QtWidgets.QAction(MainWindow)
|
||||||
icon = QtGui.QIcon.fromTheme(_fromUtf8("help-support"))
|
icon = QtGui.QIcon.fromTheme("help-support")
|
||||||
self.actionSupport.setIcon(icon)
|
self.actionSupport.setIcon(icon)
|
||||||
self.actionSupport.setObjectName(_fromUtf8("actionSupport"))
|
self.actionSupport.setObjectName("actionSupport")
|
||||||
self.actionAbout = QtGui.QAction(MainWindow)
|
self.actionAbout = QtWidgets.QAction(MainWindow)
|
||||||
icon = QtGui.QIcon.fromTheme(_fromUtf8("help-about"))
|
icon = QtGui.QIcon.fromTheme("help-about")
|
||||||
self.actionAbout.setIcon(icon)
|
self.actionAbout.setIcon(icon)
|
||||||
self.actionAbout.setObjectName(_fromUtf8("actionAbout"))
|
self.actionAbout.setObjectName("actionAbout")
|
||||||
self.actionSettings = QtGui.QAction(MainWindow)
|
self.actionSettings = QtWidgets.QAction(MainWindow)
|
||||||
icon = QtGui.QIcon.fromTheme(_fromUtf8("document-properties"))
|
icon = QtGui.QIcon.fromTheme("document-properties")
|
||||||
self.actionSettings.setIcon(icon)
|
self.actionSettings.setIcon(icon)
|
||||||
self.actionSettings.setObjectName(_fromUtf8("actionSettings"))
|
self.actionSettings.setObjectName("actionSettings")
|
||||||
self.actionRegenerateDeterministicAddresses = QtGui.QAction(MainWindow)
|
self.actionRegenerateDeterministicAddresses = QtWidgets.QAction(MainWindow)
|
||||||
icon = QtGui.QIcon.fromTheme(_fromUtf8("view-refresh"))
|
icon = QtGui.QIcon.fromTheme("view-refresh")
|
||||||
self.actionRegenerateDeterministicAddresses.setIcon(icon)
|
self.actionRegenerateDeterministicAddresses.setIcon(icon)
|
||||||
self.actionRegenerateDeterministicAddresses.setObjectName(_fromUtf8("actionRegenerateDeterministicAddresses"))
|
self.actionRegenerateDeterministicAddresses.setObjectName("actionRegenerateDeterministicAddresses")
|
||||||
self.actionDeleteAllTrashedMessages = QtGui.QAction(MainWindow)
|
self.actionDeleteAllTrashedMessages = QtWidgets.QAction(MainWindow)
|
||||||
icon = QtGui.QIcon.fromTheme(_fromUtf8("user-trash"))
|
icon = QtGui.QIcon.fromTheme("user-trash")
|
||||||
self.actionDeleteAllTrashedMessages.setIcon(icon)
|
self.actionDeleteAllTrashedMessages.setIcon(icon)
|
||||||
self.actionDeleteAllTrashedMessages.setObjectName(_fromUtf8("actionDeleteAllTrashedMessages"))
|
self.actionDeleteAllTrashedMessages.setObjectName("actionDeleteAllTrashedMessages")
|
||||||
self.actionJoinChan = QtGui.QAction(MainWindow)
|
self.actionJoinChan = QtWidgets.QAction(MainWindow)
|
||||||
icon = QtGui.QIcon.fromTheme(_fromUtf8("contact-new"))
|
icon = QtGui.QIcon.fromTheme("contact-new")
|
||||||
self.actionJoinChan.setIcon(icon)
|
self.actionJoinChan.setIcon(icon)
|
||||||
self.actionJoinChan.setObjectName(_fromUtf8("actionJoinChan"))
|
self.actionJoinChan.setObjectName("actionJoinChan")
|
||||||
self.menuFile.addAction(self.actionManageKeys)
|
self.menuFile.addAction(self.actionManageKeys)
|
||||||
self.menuFile.addAction(self.actionDeleteAllTrashedMessages)
|
self.menuFile.addAction(self.actionDeleteAllTrashedMessages)
|
||||||
self.menuFile.addAction(self.actionRegenerateDeterministicAddresses)
|
self.menuFile.addAction(self.actionRegenerateDeterministicAddresses)
|
||||||
|
@ -672,11 +634,11 @@ class Ui_MainWindow(object):
|
||||||
|
|
||||||
# Popup menu actions container for the Sent page
|
# Popup menu actions container for the Sent page
|
||||||
# pylint: disable=attribute-defined-outside-init
|
# pylint: disable=attribute-defined-outside-init
|
||||||
self.sentContextMenuToolbar = QtGui.QToolBar()
|
self.sentContextMenuToolbar = QtWidgets.QToolBar()
|
||||||
# Popup menu actions container for chans tree
|
# Popup menu actions container for chans tree
|
||||||
self.addressContextMenuToolbar = QtGui.QToolBar()
|
self.addressContextMenuToolbar = QtWidgets.QToolBar()
|
||||||
# Popup menu actions container for subscriptions tree
|
# Popup menu actions container for subscriptions tree
|
||||||
self.subscriptionsContextMenuToolbar = QtGui.QToolBar()
|
self.subscriptionsContextMenuToolbar = QtWidgets.QToolBar()
|
||||||
|
|
||||||
def updateNetworkSwitchMenuLabel(self, dontconnect=None):
|
def updateNetworkSwitchMenuLabel(self, dontconnect=None):
|
||||||
if dontconnect is None:
|
if dontconnect is None:
|
||||||
|
@ -733,9 +695,7 @@ class Ui_MainWindow(object):
|
||||||
hours = int(config.getint('bitmessagesettings', 'ttl') / 60 / 60)
|
hours = int(config.getint('bitmessagesettings', 'ttl') / 60 / 60)
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
self.labelHumanFriendlyTTLDescription.setText(
|
self.labelHumanFriendlyTTLDescription.setText(_translate("MainWindow", "%n hour(s)", None, hours))
|
||||||
_translate("MainWindow", "%n hour(s)", None, QtCore.QCoreApplication.CodecForTr, hours)
|
|
||||||
)
|
|
||||||
self.pushButtonClear.setText(_translate("MainWindow", "Clear", None))
|
self.pushButtonClear.setText(_translate("MainWindow", "Clear", None))
|
||||||
self.pushButtonSend.setText(_translate("MainWindow", "Send", None))
|
self.pushButtonSend.setText(_translate("MainWindow", "Send", None))
|
||||||
self.tabWidget.setTabText(self.tabWidget.indexOf(self.send), _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__":
|
if __name__ == "__main__":
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
app = QtGui.QApplication(sys.argv)
|
app = QtWidgets.QApplication(sys.argv)
|
||||||
MainWindow = settingsmixin.SMainWindow()
|
MainWindow = settingsmixin.SMainWindow()
|
||||||
ui = Ui_MainWindow()
|
ui = Ui_MainWindow()
|
||||||
ui.setupUi(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 addresses import addBMIfNotPresent
|
||||||
from bmconfigparser import config
|
from bmconfigparser import config
|
||||||
from dialogs import AddAddressDialog
|
from .dialogs import AddAddressDialog
|
||||||
from helper_sql import sqlExecute, sqlQuery
|
from helper_sql import sqlExecute, sqlQuery
|
||||||
from queues import UISignalQueue
|
from queues import UISignalQueue
|
||||||
from retranslateui import RetranslateMixin
|
from .retranslateui import RetranslateMixin
|
||||||
from tr import _translate
|
from tr import _translate
|
||||||
from uisignaler import UISignaler
|
from .uisignaler import UISignaler
|
||||||
from utils import avatarize
|
from .utils import avatarize
|
||||||
|
|
||||||
|
|
||||||
class Blacklist(QtGui.QWidget, RetranslateMixin):
|
class Blacklist(QtWidgets.QWidget, RetranslateMixin):
|
||||||
def __init__(self, parent=None):
|
def __init__(self, parent=None):
|
||||||
super(Blacklist, self).__init__(parent)
|
super(Blacklist, self).__init__(parent)
|
||||||
widgets.load('blacklist.ui', self)
|
widgets.load('blacklist.ui', self)
|
||||||
|
|
||||||
QtCore.QObject.connect(self.radioButtonBlacklist, QtCore.SIGNAL(
|
self.radioButtonBlacklist.clicked.connect(
|
||||||
"clicked()"), self.click_radioButtonBlacklist)
|
self.click_radioButtonBlacklist)
|
||||||
QtCore.QObject.connect(self.radioButtonWhitelist, QtCore.SIGNAL(
|
self.radioButtonWhitelist.clicked.connect(
|
||||||
"clicked()"), self.click_radioButtonWhitelist)
|
self.click_radioButtonWhitelist)
|
||||||
QtCore.QObject.connect(self.pushButtonAddBlacklist, QtCore.SIGNAL(
|
self.pushButtonAddBlacklist.clicked.connect(
|
||||||
"clicked()"), self.click_pushButtonAddBlacklist)
|
self.click_pushButtonAddBlacklist)
|
||||||
|
|
||||||
self.init_blacklist_popup_menu()
|
self.init_blacklist_popup_menu()
|
||||||
|
|
||||||
# Initialize blacklist
|
self.tableWidgetBlacklist.itemChanged.connect(
|
||||||
QtCore.QObject.connect(self.tableWidgetBlacklist, QtCore.SIGNAL(
|
self.tableWidgetBlacklistItemChanged)
|
||||||
"itemChanged(QTableWidgetItem *)"), self.tableWidgetBlacklistItemChanged)
|
|
||||||
|
|
||||||
# Set the icon sizes for the identicons
|
# Set the icon sizes for the identicons
|
||||||
identicon_size = 3*7
|
identicon_size = 3 * 7
|
||||||
self.tableWidgetBlacklist.setIconSize(QtCore.QSize(identicon_size, identicon_size))
|
self.tableWidgetBlacklist.setIconSize(
|
||||||
|
QtCore.QSize(identicon_size, identicon_size))
|
||||||
|
|
||||||
self.UISignalThread = UISignaler.get()
|
self.UISignalThread = UISignaler.get()
|
||||||
QtCore.QObject.connect(self.UISignalThread, QtCore.SIGNAL(
|
self.UISignalThread.rerenderBlackWhiteList.connect(
|
||||||
"rerenderBlackWhiteList()"), self.rerenderBlackWhiteList)
|
self.rerenderBlackWhiteList)
|
||||||
|
|
||||||
def click_radioButtonBlacklist(self):
|
def click_radioButtonBlacklist(self):
|
||||||
if config.get('bitmessagesettings', 'blackwhitelist') == 'white':
|
if config.get('bitmessagesettings', 'blackwhitelist') == 'white':
|
||||||
|
@ -59,30 +61,30 @@ class Blacklist(QtGui.QWidget, RetranslateMixin):
|
||||||
if self.NewBlacklistDialogInstance.exec_():
|
if self.NewBlacklistDialogInstance.exec_():
|
||||||
if self.NewBlacklistDialogInstance.labelAddressCheck.text() == \
|
if self.NewBlacklistDialogInstance.labelAddressCheck.text() == \
|
||||||
_translate("MainWindow", "Address is valid."):
|
_translate("MainWindow", "Address is valid."):
|
||||||
address = addBMIfNotPresent(str(
|
address = addBMIfNotPresent(ustr(
|
||||||
self.NewBlacklistDialogInstance.lineEditAddress.text()))
|
self.NewBlacklistDialogInstance.lineEditAddress.text()))
|
||||||
# First we must check to see if the address is already in the
|
# First we must check to see if the address is already in the
|
||||||
# address book. The user cannot add it again or else it will
|
# address book. The user cannot add it again or else it will
|
||||||
# cause problems when updating and deleting the entry.
|
# cause problems when updating and deleting the entry.
|
||||||
t = (address,)
|
t = (dbstr(address),)
|
||||||
if config.get('bitmessagesettings', 'blackwhitelist') == 'black':
|
if config.get('bitmessagesettings', 'blackwhitelist') == 'black':
|
||||||
sql = '''select * from blacklist where address=?'''
|
sql = '''select * from blacklist where address=?'''
|
||||||
else:
|
else:
|
||||||
sql = '''select * from whitelist where address=?'''
|
sql = '''select * from whitelist where address=?'''
|
||||||
queryreturn = sqlQuery(sql,*t)
|
queryreturn = sqlQuery(sql, *t)
|
||||||
if queryreturn == []:
|
if queryreturn == []:
|
||||||
self.tableWidgetBlacklist.setSortingEnabled(False)
|
self.tableWidgetBlacklist.setSortingEnabled(False)
|
||||||
self.tableWidgetBlacklist.insertRow(0)
|
self.tableWidgetBlacklist.insertRow(0)
|
||||||
newItem = QtGui.QTableWidgetItem(unicode(
|
newItem = QtGui.QTableWidgetItem(unic(ustr(
|
||||||
self.NewBlacklistDialogInstance.lineEditLabel.text().toUtf8(), 'utf-8'))
|
self.NewBlacklistDialogInstance.lineEditLabel.text())))
|
||||||
newItem.setIcon(avatarize(address))
|
newItem.setIcon(avatarize(address))
|
||||||
self.tableWidgetBlacklist.setItem(0, 0, newItem)
|
self.tableWidgetBlacklist.setItem(0, 0, newItem)
|
||||||
newItem = QtGui.QTableWidgetItem(address)
|
newItem = QtWidgets.QTableWidgetItem(address)
|
||||||
newItem.setFlags(
|
newItem.setFlags(
|
||||||
QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled)
|
QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled)
|
||||||
self.tableWidgetBlacklist.setItem(0, 1, newItem)
|
self.tableWidgetBlacklist.setItem(0, 1, newItem)
|
||||||
self.tableWidgetBlacklist.setSortingEnabled(True)
|
self.tableWidgetBlacklist.setSortingEnabled(True)
|
||||||
t = (str(self.NewBlacklistDialogInstance.lineEditLabel.text().toUtf8()), address, True)
|
t = (dbstr(self.NewBlacklistDialogInstance.lineEditLabel.text()), dbstr(address), True)
|
||||||
if config.get('bitmessagesettings', 'blackwhitelist') == 'black':
|
if config.get('bitmessagesettings', 'blackwhitelist') == 'black':
|
||||||
sql = '''INSERT INTO blacklist VALUES (?,?,?)'''
|
sql = '''INSERT INTO blacklist VALUES (?,?,?)'''
|
||||||
else:
|
else:
|
||||||
|
@ -108,17 +110,17 @@ class Blacklist(QtGui.QWidget, RetranslateMixin):
|
||||||
def tableWidgetBlacklistItemChanged(self, item):
|
def tableWidgetBlacklistItemChanged(self, item):
|
||||||
if item.column() == 0:
|
if item.column() == 0:
|
||||||
addressitem = self.tableWidgetBlacklist.item(item.row(), 1)
|
addressitem = self.tableWidgetBlacklist.item(item.row(), 1)
|
||||||
if isinstance(addressitem, QtGui.QTableWidgetItem):
|
if isinstance(addressitem, QtWidgets.QTableWidgetItem):
|
||||||
if self.radioButtonBlacklist.isChecked():
|
if self.radioButtonBlacklist.isChecked():
|
||||||
sqlExecute('''UPDATE blacklist SET label=? WHERE address=?''',
|
sqlExecute('''UPDATE blacklist SET label=? WHERE address=?''',
|
||||||
str(item.text()), str(addressitem.text()))
|
dbstr(item.text()), dbstr(addressitem.text()))
|
||||||
else:
|
else:
|
||||||
sqlExecute('''UPDATE whitelist SET label=? WHERE address=?''',
|
sqlExecute('''UPDATE whitelist SET label=? WHERE address=?''',
|
||||||
str(item.text()), str(addressitem.text()))
|
dbstr(item.text()), dbstr(addressitem.text()))
|
||||||
|
|
||||||
def init_blacklist_popup_menu(self, connectSignal=True):
|
def init_blacklist_popup_menu(self, connectSignal=True):
|
||||||
# Popup menu for the Blacklist page
|
# Popup menu for the Blacklist page
|
||||||
self.blacklistContextMenuToolbar = QtGui.QToolBar()
|
self.blacklistContextMenuToolbar = QtWidgets.QToolBar()
|
||||||
# Actions
|
# Actions
|
||||||
self.actionBlacklistNew = self.blacklistContextMenuToolbar.addAction(
|
self.actionBlacklistNew = self.blacklistContextMenuToolbar.addAction(
|
||||||
_translate(
|
_translate(
|
||||||
|
@ -143,10 +145,9 @@ class Blacklist(QtGui.QWidget, RetranslateMixin):
|
||||||
self.tableWidgetBlacklist.setContextMenuPolicy(
|
self.tableWidgetBlacklist.setContextMenuPolicy(
|
||||||
QtCore.Qt.CustomContextMenu)
|
QtCore.Qt.CustomContextMenu)
|
||||||
if connectSignal:
|
if connectSignal:
|
||||||
self.connect(self.tableWidgetBlacklist, QtCore.SIGNAL(
|
self.tableWidgetBlacklist.customContextMenuRequested.connect(
|
||||||
'customContextMenuRequested(const QPoint&)'),
|
self.on_context_menuBlacklist)
|
||||||
self.on_context_menuBlacklist)
|
self.popMenuBlacklist = QtWidgets.QMenu(self)
|
||||||
self.popMenuBlacklist = QtGui.QMenu(self)
|
|
||||||
# self.popMenuBlacklist.addAction( self.actionBlacklistNew )
|
# self.popMenuBlacklist.addAction( self.actionBlacklistNew )
|
||||||
self.popMenuBlacklist.addAction(self.actionBlacklistDelete)
|
self.popMenuBlacklist.addAction(self.actionBlacklistDelete)
|
||||||
self.popMenuBlacklist.addSeparator()
|
self.popMenuBlacklist.addSeparator()
|
||||||
|
@ -171,17 +172,19 @@ class Blacklist(QtGui.QWidget, RetranslateMixin):
|
||||||
self.tableWidgetBlacklist.setSortingEnabled(False)
|
self.tableWidgetBlacklist.setSortingEnabled(False)
|
||||||
for row in queryreturn:
|
for row in queryreturn:
|
||||||
label, address, enabled = row
|
label, address, enabled = row
|
||||||
|
label = label.decode("utf-8", "replace")
|
||||||
|
address = address.decode("utf-8", "replace")
|
||||||
self.tableWidgetBlacklist.insertRow(0)
|
self.tableWidgetBlacklist.insertRow(0)
|
||||||
newItem = QtGui.QTableWidgetItem(unicode(label, 'utf-8'))
|
newItem = QtWidgets.QTableWidgetItem(unic(ustr(label)))
|
||||||
if not enabled:
|
if not enabled:
|
||||||
newItem.setTextColor(QtGui.QColor(128, 128, 128))
|
newItem.setForeground(QtGui.QColor(128, 128, 128))
|
||||||
newItem.setIcon(avatarize(address))
|
newItem.setIcon(avatarize(address))
|
||||||
self.tableWidgetBlacklist.setItem(0, 0, newItem)
|
self.tableWidgetBlacklist.setItem(0, 0, newItem)
|
||||||
newItem = QtGui.QTableWidgetItem(address)
|
newItem = QtWidgets.QTableWidgetItem(address)
|
||||||
newItem.setFlags(
|
newItem.setFlags(
|
||||||
QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled)
|
QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled)
|
||||||
if not enabled:
|
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.setItem(0, 1, newItem)
|
||||||
self.tableWidgetBlacklist.setSortingEnabled(True)
|
self.tableWidgetBlacklist.setSortingEnabled(True)
|
||||||
|
|
||||||
|
@ -191,26 +194,26 @@ class Blacklist(QtGui.QWidget, RetranslateMixin):
|
||||||
|
|
||||||
def on_action_BlacklistDelete(self):
|
def on_action_BlacklistDelete(self):
|
||||||
currentRow = self.tableWidgetBlacklist.currentRow()
|
currentRow = self.tableWidgetBlacklist.currentRow()
|
||||||
labelAtCurrentRow = self.tableWidgetBlacklist.item(
|
labelAtCurrentRow = ustr(self.tableWidgetBlacklist.item(
|
||||||
currentRow, 0).text().toUtf8()
|
currentRow, 0).text())
|
||||||
addressAtCurrentRow = self.tableWidgetBlacklist.item(
|
addressAtCurrentRow = self.tableWidgetBlacklist.item(
|
||||||
currentRow, 1).text()
|
currentRow, 1).text()
|
||||||
if config.get('bitmessagesettings', 'blackwhitelist') == 'black':
|
if config.get('bitmessagesettings', 'blackwhitelist') == 'black':
|
||||||
sqlExecute(
|
sqlExecute(
|
||||||
'''DELETE FROM blacklist WHERE label=? AND address=?''',
|
'''DELETE FROM blacklist WHERE label=? AND address=?''',
|
||||||
str(labelAtCurrentRow), str(addressAtCurrentRow))
|
dbstr(labelAtCurrentRow), dbstr(addressAtCurrentRow))
|
||||||
else:
|
else:
|
||||||
sqlExecute(
|
sqlExecute(
|
||||||
'''DELETE FROM whitelist WHERE label=? AND address=?''',
|
'''DELETE FROM whitelist WHERE label=? AND address=?''',
|
||||||
str(labelAtCurrentRow), str(addressAtCurrentRow))
|
dbstr(labelAtCurrentRow), dbstr(addressAtCurrentRow))
|
||||||
self.tableWidgetBlacklist.removeRow(currentRow)
|
self.tableWidgetBlacklist.removeRow(currentRow)
|
||||||
|
|
||||||
def on_action_BlacklistClipboard(self):
|
def on_action_BlacklistClipboard(self):
|
||||||
currentRow = self.tableWidgetBlacklist.currentRow()
|
currentRow = self.tableWidgetBlacklist.currentRow()
|
||||||
addressAtCurrentRow = self.tableWidgetBlacklist.item(
|
addressAtCurrentRow = self.tableWidgetBlacklist.item(
|
||||||
currentRow, 1).text()
|
currentRow, 1).text()
|
||||||
clipboard = QtGui.QApplication.clipboard()
|
clipboard = QtWidgets.QApplication.clipboard()
|
||||||
clipboard.setText(str(addressAtCurrentRow))
|
clipboard.setText(ustr(addressAtCurrentRow))
|
||||||
|
|
||||||
def on_context_menuBlacklist(self, point):
|
def on_context_menuBlacklist(self, point):
|
||||||
self.popMenuBlacklist.exec_(
|
self.popMenuBlacklist.exec_(
|
||||||
|
@ -220,33 +223,33 @@ class Blacklist(QtGui.QWidget, RetranslateMixin):
|
||||||
currentRow = self.tableWidgetBlacklist.currentRow()
|
currentRow = self.tableWidgetBlacklist.currentRow()
|
||||||
addressAtCurrentRow = self.tableWidgetBlacklist.item(
|
addressAtCurrentRow = self.tableWidgetBlacklist.item(
|
||||||
currentRow, 1).text()
|
currentRow, 1).text()
|
||||||
self.tableWidgetBlacklist.item(
|
self.tableWidgetBlacklist.item(currentRow, 0).setForeground(
|
||||||
currentRow, 0).setTextColor(QtGui.QApplication.palette().text().color())
|
QtWidgets.QApplication.palette().text().color())
|
||||||
self.tableWidgetBlacklist.item(
|
self.tableWidgetBlacklist.item(currentRow, 1).setForeground(
|
||||||
currentRow, 1).setTextColor(QtGui.QApplication.palette().text().color())
|
QtWidgets.QApplication.palette().text().color())
|
||||||
if config.get('bitmessagesettings', 'blackwhitelist') == 'black':
|
if config.get('bitmessagesettings', 'blackwhitelist') == 'black':
|
||||||
sqlExecute(
|
sqlExecute(
|
||||||
'''UPDATE blacklist SET enabled=1 WHERE address=?''',
|
'''UPDATE blacklist SET enabled=1 WHERE address=?''',
|
||||||
str(addressAtCurrentRow))
|
dbstr(addressAtCurrentRow))
|
||||||
else:
|
else:
|
||||||
sqlExecute(
|
sqlExecute(
|
||||||
'''UPDATE whitelist SET enabled=1 WHERE address=?''',
|
'''UPDATE whitelist SET enabled=1 WHERE address=?''',
|
||||||
str(addressAtCurrentRow))
|
dbstr(addressAtCurrentRow))
|
||||||
|
|
||||||
def on_action_BlacklistDisable(self):
|
def on_action_BlacklistDisable(self):
|
||||||
currentRow = self.tableWidgetBlacklist.currentRow()
|
currentRow = self.tableWidgetBlacklist.currentRow()
|
||||||
addressAtCurrentRow = self.tableWidgetBlacklist.item(
|
addressAtCurrentRow = self.tableWidgetBlacklist.item(
|
||||||
currentRow, 1).text()
|
currentRow, 1).text()
|
||||||
self.tableWidgetBlacklist.item(
|
self.tableWidgetBlacklist.item(currentRow, 0).setForeground(
|
||||||
currentRow, 0).setTextColor(QtGui.QColor(128, 128, 128))
|
QtGui.QColor(128, 128, 128))
|
||||||
self.tableWidgetBlacklist.item(
|
self.tableWidgetBlacklist.item(currentRow, 1).setForeground(
|
||||||
currentRow, 1).setTextColor(QtGui.QColor(128, 128, 128))
|
QtGui.QColor(128, 128, 128))
|
||||||
if config.get('bitmessagesettings', 'blackwhitelist') == 'black':
|
if config.get('bitmessagesettings', 'blackwhitelist') == 'black':
|
||||||
sqlExecute(
|
sqlExecute(
|
||||||
'''UPDATE blacklist SET enabled=0 WHERE address=?''', str(addressAtCurrentRow))
|
'''UPDATE blacklist SET enabled=0 WHERE address=?''', dbstr(addressAtCurrentRow))
|
||||||
else:
|
else:
|
||||||
sqlExecute(
|
sqlExecute(
|
||||||
'''UPDATE whitelist SET enabled=0 WHERE address=?''', str(addressAtCurrentRow))
|
'''UPDATE whitelist SET enabled=0 WHERE address=?''', dbstr(addressAtCurrentRow))
|
||||||
|
|
||||||
def on_action_BlacklistSetAvatar(self):
|
def on_action_BlacklistSetAvatar(self):
|
||||||
self.window().on_action_SetAvatar(self.tableWidgetBlacklist)
|
self.window().on_action_SetAvatar(self.tableWidgetBlacklist)
|
||||||
|
|
|
@ -62,6 +62,9 @@
|
||||||
<property name="sortingEnabled">
|
<property name="sortingEnabled">
|
||||||
<bool>true</bool>
|
<bool>true</bool>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="wordWrap">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
<attribute name="horizontalHeaderCascadingSectionResizes">
|
<attribute name="horizontalHeaderCascadingSectionResizes">
|
||||||
<bool>true</bool>
|
<bool>true</bool>
|
||||||
</attribute>
|
</attribute>
|
||||||
|
@ -98,11 +101,8 @@
|
||||||
<customwidget>
|
<customwidget>
|
||||||
<class>STableWidget</class>
|
<class>STableWidget</class>
|
||||||
<extends>QTableWidget</extends>
|
<extends>QTableWidget</extends>
|
||||||
<header>bitmessageqt/settingsmixin.h</header>
|
<header>bitmessageqt.settingsmixin</header>
|
||||||
</customwidget>
|
</customwidget>
|
||||||
</customwidgets>
|
</customwidgets>
|
||||||
<resources>
|
|
||||||
<include location="bitmessage_icons.qrc"/>
|
|
||||||
</resources>
|
|
||||||
<connections/>
|
<connections/>
|
||||||
</ui>
|
</ui>
|
||||||
|
|
|
@ -1,22 +1,23 @@
|
||||||
"""
|
"""
|
||||||
Custom dialog classes
|
All dialogs are available in this module.
|
||||||
"""
|
"""
|
||||||
# pylint: disable=too-few-public-methods
|
# pylint: disable=too-few-public-methods
|
||||||
from PyQt4 import QtGui
|
from unqstr import ustr
|
||||||
|
|
||||||
|
from qtpy import QtWidgets
|
||||||
|
|
||||||
import paths
|
import paths
|
||||||
import widgets
|
from bitmessageqt import widgets
|
||||||
from address_dialogs import (
|
from .address_dialogs import (
|
||||||
AddAddressDialog, EmailGatewayDialog, NewAddressDialog,
|
AddAddressDialog, EmailGatewayDialog, NewAddressDialog,
|
||||||
NewSubscriptionDialog, RegenerateAddressesDialog,
|
NewSubscriptionDialog, RegenerateAddressesDialog,
|
||||||
SpecialAddressBehaviorDialog
|
SpecialAddressBehaviorDialog
|
||||||
)
|
)
|
||||||
from newchandialog import NewChanDialog
|
from .newchandialog import NewChanDialog
|
||||||
from settings import SettingsDialog
|
from .settings import SettingsDialog
|
||||||
from tr import _translate
|
from tr import _translate
|
||||||
from version import softwareVersion
|
from version import softwareVersion
|
||||||
|
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
"NewChanDialog", "AddAddressDialog", "NewAddressDialog",
|
"NewChanDialog", "AddAddressDialog", "NewAddressDialog",
|
||||||
"NewSubscriptionDialog", "RegenerateAddressesDialog",
|
"NewSubscriptionDialog", "RegenerateAddressesDialog",
|
||||||
|
@ -25,8 +26,8 @@ __all__ = [
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class AboutDialog(QtGui.QDialog):
|
class AboutDialog(QtWidgets.QDialog):
|
||||||
"""The `About` dialog"""
|
"""The "About" dialog"""
|
||||||
def __init__(self, parent=None):
|
def __init__(self, parent=None):
|
||||||
super(AboutDialog, self).__init__(parent)
|
super(AboutDialog, self).__init__(parent)
|
||||||
widgets.load('about.ui', self)
|
widgets.load('about.ui', self)
|
||||||
|
@ -36,7 +37,7 @@ class AboutDialog(QtGui.QDialog):
|
||||||
if commit:
|
if commit:
|
||||||
version += '-' + commit[:7]
|
version += '-' + commit[:7]
|
||||||
self.labelVersion.setText(
|
self.labelVersion.setText(
|
||||||
self.labelVersion.text().replace(
|
ustr(self.labelVersion.text()).replace(
|
||||||
':version:', version
|
':version:', version
|
||||||
).replace(':branch:', commit or 'v%s' % version)
|
).replace(':branch:', commit or 'v%s' % version)
|
||||||
)
|
)
|
||||||
|
@ -44,17 +45,17 @@ class AboutDialog(QtGui.QDialog):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.label_2.setText(
|
self.label_2.setText(
|
||||||
self.label_2.text().replace(
|
ustr(self.label_2.text()).replace(
|
||||||
'2022', str(last_commit.get('time').year)
|
'2022', ustr(last_commit.get('time').year)
|
||||||
))
|
))
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
self.setFixedSize(QtGui.QWidget.sizeHint(self))
|
self.setFixedSize(QtWidgets.QWidget.sizeHint(self))
|
||||||
|
|
||||||
|
|
||||||
class IconGlossaryDialog(QtGui.QDialog):
|
class IconGlossaryDialog(QtWidgets.QDialog):
|
||||||
"""The `Icon Glossary` dialog, explaining the status icon colors"""
|
"""The "Icon Glossary" dialog, explaining the status icon colors"""
|
||||||
def __init__(self, parent=None, config=None):
|
def __init__(self, parent=None, config=None):
|
||||||
super(IconGlossaryDialog, self).__init__(parent)
|
super(IconGlossaryDialog, self).__init__(parent)
|
||||||
widgets.load('iconglossary.ui', self)
|
widgets.load('iconglossary.ui', self)
|
||||||
|
@ -64,22 +65,23 @@ class IconGlossaryDialog(QtGui.QDialog):
|
||||||
|
|
||||||
self.labelPortNumber.setText(_translate(
|
self.labelPortNumber.setText(_translate(
|
||||||
"iconGlossaryDialog",
|
"iconGlossaryDialog",
|
||||||
"You are using TCP port %1. (This can be changed in the settings)."
|
"You are using TCP port {0}."
|
||||||
).arg(config.getint('bitmessagesettings', 'port')))
|
" (This can be changed in the settings)."
|
||||||
self.setFixedSize(QtGui.QWidget.sizeHint(self))
|
).format(config.getint('bitmessagesettings', 'port')))
|
||||||
|
self.setFixedSize(QtWidgets.QWidget.sizeHint(self))
|
||||||
|
|
||||||
|
|
||||||
class HelpDialog(QtGui.QDialog):
|
class HelpDialog(QtWidgets.QDialog):
|
||||||
"""The `Help` dialog"""
|
"""The "Help" dialog"""
|
||||||
def __init__(self, parent=None):
|
def __init__(self, parent=None):
|
||||||
super(HelpDialog, self).__init__(parent)
|
super(HelpDialog, self).__init__(parent)
|
||||||
widgets.load('help.ui', self)
|
widgets.load('help.ui', self)
|
||||||
self.setFixedSize(QtGui.QWidget.sizeHint(self))
|
self.setFixedSize(QtWidgets.QWidget.sizeHint(self))
|
||||||
|
|
||||||
|
|
||||||
class ConnectDialog(QtGui.QDialog):
|
class ConnectDialog(QtWidgets.QDialog):
|
||||||
"""The `Connect` dialog"""
|
"""The "Connect" dialog"""
|
||||||
def __init__(self, parent=None):
|
def __init__(self, parent=None):
|
||||||
super(ConnectDialog, self).__init__(parent)
|
super(ConnectDialog, self).__init__(parent)
|
||||||
widgets.load('connect.ui', self)
|
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.
|
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
|
# 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 bmconfigparser import config
|
||||||
from helper_sql import sqlExecute, sqlQuery
|
from helper_sql import sqlExecute, sqlQuery
|
||||||
from settingsmixin import SettingsMixin
|
from .settingsmixin import SettingsMixin
|
||||||
from tr import _translate
|
from tr import _translate
|
||||||
from utils import avatarize
|
from .utils import avatarize
|
||||||
|
|
||||||
# for pylupdate
|
# for pylupdate
|
||||||
_translate("MainWindow", "inbox")
|
_translate("MainWindow", "inbox")
|
||||||
|
@ -38,15 +43,16 @@ class AccountMixin(object):
|
||||||
return QtGui.QColor(128, 128, 128)
|
return QtGui.QColor(128, 128, 128)
|
||||||
elif self.type == self.CHAN:
|
elif self.type == self.CHAN:
|
||||||
return QtGui.QColor(216, 119, 0)
|
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.QColor(137, 4, 177)
|
||||||
return QtGui.QApplication.palette().text().color()
|
|
||||||
|
return QtWidgets.QApplication.palette().text().color()
|
||||||
|
|
||||||
def folderColor(self):
|
def folderColor(self):
|
||||||
"""QT UI color for a folder"""
|
"""QT UI color for a folder"""
|
||||||
if not self.parent().isEnabled:
|
if not self.parent().isEnabled:
|
||||||
return QtGui.QColor(128, 128, 128)
|
return QtGui.QColor(128, 128, 128)
|
||||||
return QtGui.QApplication.palette().text().color()
|
return QtWidgets.QApplication.palette().text().color()
|
||||||
|
|
||||||
def accountBrush(self):
|
def accountBrush(self):
|
||||||
"""Account brush (for QT UI)"""
|
"""Account brush (for QT UI)"""
|
||||||
|
@ -62,7 +68,7 @@ class AccountMixin(object):
|
||||||
|
|
||||||
def accountString(self):
|
def accountString(self):
|
||||||
"""Account string suitable for use in To: field: label <address>"""
|
"""Account string suitable for use in To: field: label <address>"""
|
||||||
label = self._getLabel()
|
label = ustr(self._getLabel())
|
||||||
return (
|
return (
|
||||||
self.address if label == self.address
|
self.address if label == self.address
|
||||||
else '%s <%s>' % (label, self.address)
|
else '%s <%s>' % (label, self.address)
|
||||||
|
@ -73,7 +79,7 @@ class AccountMixin(object):
|
||||||
if address is None:
|
if address is None:
|
||||||
self.address = None
|
self.address = None
|
||||||
else:
|
else:
|
||||||
self.address = str(address)
|
self.address = ustr(address)
|
||||||
|
|
||||||
def setUnreadCount(self, cnt):
|
def setUnreadCount(self, cnt):
|
||||||
"""Set number of unread messages"""
|
"""Set number of unread messages"""
|
||||||
|
@ -83,7 +89,7 @@ class AccountMixin(object):
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
pass
|
pass
|
||||||
self.unreadCount = int(cnt)
|
self.unreadCount = int(cnt)
|
||||||
if isinstance(self, QtGui.QTreeWidgetItem):
|
if isinstance(self, QtWidgets.QTreeWidgetItem):
|
||||||
self.emitDataChanged()
|
self.emitDataChanged()
|
||||||
|
|
||||||
def setEnabled(self, enabled):
|
def setEnabled(self, enabled):
|
||||||
|
@ -97,7 +103,7 @@ class AccountMixin(object):
|
||||||
for i in range(self.childCount()):
|
for i in range(self.childCount()):
|
||||||
if isinstance(self.child(i), Ui_FolderWidget):
|
if isinstance(self.child(i), Ui_FolderWidget):
|
||||||
self.child(i).setEnabled(enabled)
|
self.child(i).setEnabled(enabled)
|
||||||
if isinstance(self, QtGui.QTreeWidgetItem):
|
if isinstance(self, QtWidgets.QTreeWidgetItem):
|
||||||
self.emitDataChanged()
|
self.emitDataChanged()
|
||||||
|
|
||||||
def setType(self):
|
def setType(self):
|
||||||
|
@ -111,53 +117,53 @@ class AccountMixin(object):
|
||||||
elif config.safeGetBoolean(self.address, 'mailinglist'):
|
elif config.safeGetBoolean(self.address, 'mailinglist'):
|
||||||
self.type = self.MAILINGLIST
|
self.type = self.MAILINGLIST
|
||||||
elif sqlQuery(
|
elif sqlQuery(
|
||||||
'''select label from subscriptions where address=?''', self.address):
|
'SELECT label FROM subscriptions WHERE address=?',
|
||||||
|
dbstr(self.address)
|
||||||
|
):
|
||||||
self.type = AccountMixin.SUBSCRIPTION
|
self.type = AccountMixin.SUBSCRIPTION
|
||||||
else:
|
else:
|
||||||
self.type = self.NORMAL
|
self.type = self.NORMAL
|
||||||
|
|
||||||
def defaultLabel(self):
|
def defaultLabel(self):
|
||||||
"""Default label (in case no label is set manually)"""
|
"""Default label (in case no label is set manually)"""
|
||||||
queryreturn = None
|
queryreturn = retval = None
|
||||||
retval = None
|
|
||||||
if self.type in (
|
if self.type in (
|
||||||
AccountMixin.NORMAL,
|
AccountMixin.NORMAL,
|
||||||
AccountMixin.CHAN, AccountMixin.MAILINGLIST):
|
AccountMixin.CHAN, AccountMixin.MAILINGLIST):
|
||||||
try:
|
try:
|
||||||
retval = unicode(
|
retval = unic(ustr(config.get(self.address, 'label')))
|
||||||
config.get(self.address, 'label'), 'utf-8')
|
|
||||||
except Exception:
|
except Exception:
|
||||||
queryreturn = sqlQuery(
|
queryreturn = sqlQuery(
|
||||||
'''select label from addressbook where address=?''', self.address)
|
'SELECT label FROM addressbook WHERE address=?',
|
||||||
|
dbstr(self.address)
|
||||||
|
)
|
||||||
elif self.type == AccountMixin.SUBSCRIPTION:
|
elif self.type == AccountMixin.SUBSCRIPTION:
|
||||||
queryreturn = sqlQuery(
|
queryreturn = sqlQuery(
|
||||||
'''select label from subscriptions where address=?''', self.address)
|
'SELECT label FROM subscriptions WHERE address=?',
|
||||||
if queryreturn is not None:
|
dbstr(self.address)
|
||||||
if queryreturn != []:
|
)
|
||||||
for row in queryreturn:
|
if queryreturn:
|
||||||
retval, = row
|
retval = unic(ustr(queryreturn[-1][0]))
|
||||||
retval = unicode(retval, 'utf-8')
|
|
||||||
elif self.address is None or self.type == AccountMixin.ALL:
|
elif self.address is None or self.type == AccountMixin.ALL:
|
||||||
return unicode(
|
return unic(_translate("MainWindow", "All accounts"))
|
||||||
str(_translate("MainWindow", "All accounts")), 'utf-8')
|
|
||||||
|
|
||||||
return retval or unicode(self.address, 'utf-8')
|
return retval or unic(self.address)
|
||||||
|
|
||||||
|
|
||||||
class BMTreeWidgetItem(QtGui.QTreeWidgetItem, AccountMixin):
|
class BMTreeWidgetItem(QtWidgets.QTreeWidgetItem, AccountMixin):
|
||||||
"""A common abstract class for Tree widget item"""
|
"""A common abstract class for Tree widget item"""
|
||||||
|
|
||||||
def __init__(self, parent, pos, address, unreadCount):
|
def __init__(self, parent, pos, address, unreadCount):
|
||||||
super(QtGui.QTreeWidgetItem, self).__init__()
|
super(QtWidgets.QTreeWidgetItem, self).__init__()
|
||||||
self.setAddress(address)
|
self.setAddress(address)
|
||||||
self.setUnreadCount(unreadCount)
|
self.setUnreadCount(unreadCount)
|
||||||
self._setup(parent, pos)
|
self._setup(parent, pos)
|
||||||
|
|
||||||
def _getAddressBracket(self, unreadCount=False):
|
def _getAddressBracket(self, unreadCount=False):
|
||||||
return " (" + str(self.unreadCount) + ")" if unreadCount else ""
|
return " (" + ustr(self.unreadCount) + ")" if unreadCount else ""
|
||||||
|
|
||||||
def data(self, column, role):
|
def data(self, column, role):
|
||||||
"""Override internal QT method for returning object data"""
|
"""Override internal Qt method for returning object data"""
|
||||||
if column == 0:
|
if column == 0:
|
||||||
if role == QtCore.Qt.DisplayRole:
|
if role == QtCore.Qt.DisplayRole:
|
||||||
return self._getLabel() + self._getAddressBracket(
|
return self._getLabel() + self._getAddressBracket(
|
||||||
|
@ -190,11 +196,11 @@ class Ui_FolderWidget(BMTreeWidgetItem):
|
||||||
return _translate("MainWindow", self.folderName)
|
return _translate("MainWindow", self.folderName)
|
||||||
|
|
||||||
def setFolderName(self, fname):
|
def setFolderName(self, fname):
|
||||||
"""Set folder name (for QT UI)"""
|
"""Set folder name (for Qt UI)"""
|
||||||
self.folderName = str(fname)
|
self.folderName = ustr(fname)
|
||||||
|
|
||||||
def data(self, column, role):
|
def data(self, column, role):
|
||||||
"""Override internal QT method for returning object data"""
|
"""Override internal Qt method for returning object data"""
|
||||||
if column == 0 and role == QtCore.Qt.ForegroundRole:
|
if column == 0 and role == QtCore.Qt.ForegroundRole:
|
||||||
return self.folderBrush()
|
return self.folderBrush()
|
||||||
return super(Ui_FolderWidget, self).data(column, role)
|
return super(Ui_FolderWidget, self).data(column, role)
|
||||||
|
@ -216,12 +222,14 @@ class Ui_FolderWidget(BMTreeWidgetItem):
|
||||||
return self.folderName < other.folderName
|
return self.folderName < other.folderName
|
||||||
return x >= y if reverse else x < y
|
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):
|
class Ui_AddressWidget(BMTreeWidgetItem, SettingsMixin):
|
||||||
"""Item in the account/folder tree representing an account"""
|
"""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__(
|
super(Ui_AddressWidget, self).__init__(
|
||||||
parent, pos, address, unreadCount)
|
parent, pos, address, unreadCount)
|
||||||
self.setEnabled(enabled)
|
self.setEnabled(enabled)
|
||||||
|
@ -232,15 +240,13 @@ class Ui_AddressWidget(BMTreeWidgetItem, SettingsMixin):
|
||||||
|
|
||||||
def _getLabel(self):
|
def _getLabel(self):
|
||||||
if self.address is None:
|
if self.address is None:
|
||||||
return unicode(_translate(
|
return unic(_translate("MainWindow", "All accounts"))
|
||||||
"MainWindow", "All accounts").toUtf8(), 'utf-8', 'ignore')
|
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
return unicode(
|
return unic(ustr(
|
||||||
config.get(self.address, 'label'),
|
config.get(self.address, 'label')))
|
||||||
'utf-8', 'ignore')
|
|
||||||
except:
|
except:
|
||||||
return unicode(self.address, 'utf-8')
|
return unic(self.address)
|
||||||
|
|
||||||
def _getAddressBracket(self, unreadCount=False):
|
def _getAddressBracket(self, unreadCount=False):
|
||||||
ret = "" if self.isExpanded() \
|
ret = "" if self.isExpanded() \
|
||||||
|
@ -260,15 +266,13 @@ class Ui_AddressWidget(BMTreeWidgetItem, SettingsMixin):
|
||||||
return super(Ui_AddressWidget, self).data(column, role)
|
return super(Ui_AddressWidget, self).data(column, role)
|
||||||
|
|
||||||
def setData(self, column, role, value):
|
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 \
|
if role == QtCore.Qt.EditRole \
|
||||||
and self.type != AccountMixin.SUBSCRIPTION:
|
and self.type != AccountMixin.SUBSCRIPTION:
|
||||||
config.set(
|
config.set(self.address, 'label', ustr(value))
|
||||||
str(self.address), 'label',
|
|
||||||
str(value.toString().toUtf8())
|
|
||||||
if isinstance(value, QtCore.QVariant)
|
|
||||||
else value.encode('utf-8')
|
|
||||||
)
|
|
||||||
config.save()
|
config.save()
|
||||||
return super(Ui_AddressWidget, self).setData(column, role, value)
|
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
|
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):
|
class Ui_SubscriptionWidget(Ui_AddressWidget):
|
||||||
"""Special treating of subscription addresses"""
|
"""Special treating of subscription addresses"""
|
||||||
# pylint: disable=unused-argument
|
# 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__(
|
super(Ui_SubscriptionWidget, self).__init__(
|
||||||
parent, pos, address, unreadCount, enabled)
|
parent, pos, address, unreadCount, enabled)
|
||||||
|
|
||||||
def _getLabel(self):
|
def _getLabel(self):
|
||||||
queryreturn = sqlQuery(
|
queryreturn = sqlQuery(
|
||||||
'''select label from subscriptions where address=?''', self.address)
|
'SELECT label FROM subscriptions WHERE address=?',
|
||||||
if queryreturn != []:
|
dbstr(self.address))
|
||||||
for row in queryreturn:
|
if queryreturn:
|
||||||
retval, = row
|
return unic(ustr(queryreturn[-1][0]))
|
||||||
return unicode(retval, 'utf-8', 'ignore')
|
return unic(self.address)
|
||||||
return unicode(self.address, 'utf-8')
|
|
||||||
|
|
||||||
def setType(self):
|
def setType(self):
|
||||||
"""Set account type"""
|
"""Set account type"""
|
||||||
|
@ -322,22 +328,17 @@ class Ui_SubscriptionWidget(Ui_AddressWidget):
|
||||||
def setData(self, column, role, value):
|
def setData(self, column, role, value):
|
||||||
"""Save subscription label to database"""
|
"""Save subscription label to database"""
|
||||||
if role == QtCore.Qt.EditRole:
|
if role == QtCore.Qt.EditRole:
|
||||||
if isinstance(value, QtCore.QVariant):
|
|
||||||
label = str(
|
|
||||||
value.toString().toUtf8()).decode('utf-8', 'ignore')
|
|
||||||
else:
|
|
||||||
label = unicode(value, 'utf-8', 'ignore')
|
|
||||||
sqlExecute(
|
sqlExecute(
|
||||||
'''UPDATE subscriptions SET label=? WHERE address=?''',
|
'UPDATE subscriptions SET label=? WHERE address=?',
|
||||||
label, self.address)
|
dbstr(unic(ustr(value))), dbstr(self.address))
|
||||||
return super(Ui_SubscriptionWidget, self).setData(column, role, value)
|
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"""
|
"""A common abstract class for Table widget item"""
|
||||||
|
|
||||||
def __init__(self, label=None, unread=False):
|
def __init__(self, label=None, unread=False):
|
||||||
super(QtGui.QTableWidgetItem, self).__init__()
|
super(QtWidgets.QTableWidgetItem, self).__init__()
|
||||||
self.setLabel(label)
|
self.setLabel(label)
|
||||||
self.setUnread(unread)
|
self.setUnread(unread)
|
||||||
self._setup()
|
self._setup()
|
||||||
|
@ -407,18 +408,17 @@ class MessageList_AddressWidget(BMAddressWidget):
|
||||||
AccountMixin.NORMAL,
|
AccountMixin.NORMAL,
|
||||||
AccountMixin.CHAN, AccountMixin.MAILINGLIST):
|
AccountMixin.CHAN, AccountMixin.MAILINGLIST):
|
||||||
try:
|
try:
|
||||||
newLabel = unicode(
|
newLabel = unic(ustr(config.get(self.address, 'label')))
|
||||||
config.get(self.address, 'label'),
|
|
||||||
'utf-8', 'ignore')
|
|
||||||
except:
|
except:
|
||||||
queryreturn = sqlQuery(
|
queryreturn = sqlQuery(
|
||||||
'''select label from addressbook where address=?''', self.address)
|
'SELECT label FROM addressbook WHERE address=?',
|
||||||
|
dbstr(self.address))
|
||||||
elif self.type == AccountMixin.SUBSCRIPTION:
|
elif self.type == AccountMixin.SUBSCRIPTION:
|
||||||
queryreturn = sqlQuery(
|
queryreturn = sqlQuery(
|
||||||
'''select label from subscriptions where address=?''', self.address)
|
'SELECT label FROM subscriptions WHERE address=?',
|
||||||
|
dbstr(self.address))
|
||||||
if queryreturn:
|
if queryreturn:
|
||||||
for row in queryreturn:
|
newLabel = unic(ustr(queryreturn[-1][0]))
|
||||||
newLabel = unicode(row[0], 'utf-8', 'ignore')
|
|
||||||
|
|
||||||
self.label = newLabel
|
self.label = newLabel
|
||||||
|
|
||||||
|
@ -438,7 +438,7 @@ class MessageList_AddressWidget(BMAddressWidget):
|
||||||
def __lt__(self, other):
|
def __lt__(self, other):
|
||||||
if isinstance(other, MessageList_AddressWidget):
|
if isinstance(other, MessageList_AddressWidget):
|
||||||
return self.label.lower() < other.label.lower()
|
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):
|
class MessageList_SubjectWidget(BMTableWidgetItem):
|
||||||
|
@ -454,16 +454,16 @@ class MessageList_SubjectWidget(BMTableWidgetItem):
|
||||||
def data(self, role):
|
def data(self, role):
|
||||||
"""Return object data (QT UI)"""
|
"""Return object data (QT UI)"""
|
||||||
if role == QtCore.Qt.UserRole:
|
if role == QtCore.Qt.UserRole:
|
||||||
return self.subject
|
return ustr(self.subject)
|
||||||
if role == QtCore.Qt.ToolTipRole:
|
if role == QtCore.Qt.ToolTipRole:
|
||||||
return escape(unicode(self.subject, 'utf-8'))
|
return escape(unic(ustr(self.subject)))
|
||||||
return super(MessageList_SubjectWidget, self).data(role)
|
return super(MessageList_SubjectWidget, self).data(role)
|
||||||
|
|
||||||
# label (or address) alphabetically, disabled at the end
|
# label (or address) alphabetically, disabled at the end
|
||||||
def __lt__(self, other):
|
def __lt__(self, other):
|
||||||
if isinstance(other, MessageList_SubjectWidget):
|
if isinstance(other, MessageList_SubjectWidget):
|
||||||
return self.label.lower() < other.label.lower()
|
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
|
# 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
|
msgid is available by QtCore.Qt.UserRole
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, label=None, unread=False, timestamp=None, msgid=''):
|
def __init__(self, label=None, unread=False, timestamp=None, msgid=b''):
|
||||||
super(MessageList_TimeWidget, self).__init__(label, unread)
|
super(MessageList_TimeWidget, self).__init__(label, unread)
|
||||||
self.setData(QtCore.Qt.UserRole, QtCore.QByteArray(msgid))
|
self.setData(QtCore.Qt.UserRole, QtCore.QByteArray(bytes(msgid)))
|
||||||
self.setData(TimestampRole, int(timestamp))
|
self.setData(TimestampRole, int(timestamp))
|
||||||
|
|
||||||
def __lt__(self, other):
|
def __lt__(self, other):
|
||||||
|
@ -491,15 +491,14 @@ class MessageList_TimeWidget(BMTableWidgetItem):
|
||||||
"""
|
"""
|
||||||
data = super(MessageList_TimeWidget, self).data(role)
|
data = super(MessageList_TimeWidget, self).data(role)
|
||||||
if role == TimestampRole:
|
if role == TimestampRole:
|
||||||
return int(data.toPyObject())
|
return int(data)
|
||||||
if role == QtCore.Qt.UserRole:
|
if role == QtCore.Qt.UserRole:
|
||||||
return str(data.toPyObject())
|
return ustr(data)
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
|
||||||
class Ui_AddressBookWidgetItem(BMAddressWidget):
|
class Ui_AddressBookWidgetItem(BMAddressWidget):
|
||||||
"""Addressbook item"""
|
"""Addressbook item"""
|
||||||
# pylint: disable=unused-argument
|
|
||||||
def __init__(self, label=None, acc_type=AccountMixin.NORMAL):
|
def __init__(self, label=None, acc_type=AccountMixin.NORMAL):
|
||||||
self.type = acc_type
|
self.type = acc_type
|
||||||
super(Ui_AddressBookWidgetItem, self).__init__(label=label)
|
super(Ui_AddressBookWidgetItem, self).__init__(label=label)
|
||||||
|
@ -513,10 +512,7 @@ class Ui_AddressBookWidgetItem(BMAddressWidget):
|
||||||
def setData(self, role, value):
|
def setData(self, role, value):
|
||||||
"""Set data"""
|
"""Set data"""
|
||||||
if role == QtCore.Qt.EditRole:
|
if role == QtCore.Qt.EditRole:
|
||||||
self.label = str(
|
self.label = ustr(value)
|
||||||
value.toString().toUtf8()
|
|
||||||
if isinstance(value, QtCore.QVariant) else value
|
|
||||||
)
|
|
||||||
if self.type in (
|
if self.type in (
|
||||||
AccountMixin.NORMAL,
|
AccountMixin.NORMAL,
|
||||||
AccountMixin.MAILINGLIST, AccountMixin.CHAN):
|
AccountMixin.MAILINGLIST, AccountMixin.CHAN):
|
||||||
|
@ -525,28 +521,33 @@ class Ui_AddressBookWidgetItem(BMAddressWidget):
|
||||||
config.set(self.address, 'label', self.label)
|
config.set(self.address, 'label', self.label)
|
||||||
config.save()
|
config.save()
|
||||||
except:
|
except:
|
||||||
sqlExecute('''UPDATE addressbook set label=? WHERE address=?''', self.label, self.address)
|
sqlExecute(
|
||||||
|
'UPDATE addressbook SET label=? WHERE address=?',
|
||||||
|
dbstr(self.label), dbstr(self.address)
|
||||||
|
)
|
||||||
elif self.type == AccountMixin.SUBSCRIPTION:
|
elif self.type == AccountMixin.SUBSCRIPTION:
|
||||||
sqlExecute('''UPDATE subscriptions set label=? WHERE address=?''', self.label, self.address)
|
sqlExecute(
|
||||||
else:
|
'UPDATE subscriptions SET label=? WHERE address=?',
|
||||||
pass
|
dbstr(self.label), dbstr(self.address))
|
||||||
return super(Ui_AddressBookWidgetItem, self).setData(role, value)
|
return super(Ui_AddressBookWidgetItem, self).setData(role, value)
|
||||||
|
|
||||||
def __lt__(self, other):
|
def __lt__(self, other):
|
||||||
if isinstance(other, Ui_AddressBookWidgetItem):
|
if not isinstance(other, Ui_AddressBookWidgetItem):
|
||||||
reverse = QtCore.Qt.DescendingOrder == \
|
return super(Ui_AddressBookWidgetItem, self).__lt__(other)
|
||||||
self.tableWidget().horizontalHeader().sortIndicatorOrder()
|
|
||||||
|
|
||||||
if self.type == other.type:
|
reverse = QtCore.Qt.DescendingOrder == \
|
||||||
return self.label.lower() < other.label.lower()
|
self.tableWidget().horizontalHeader().sortIndicatorOrder()
|
||||||
return not reverse if self.type < other.type else reverse
|
|
||||||
return super(QtGui.QTableWidgetItem, self).__lt__(other)
|
if self.type == other.type:
|
||||||
|
return self.label.lower() < other.label.lower()
|
||||||
|
|
||||||
|
return not reverse if self.type < other.type else reverse
|
||||||
|
|
||||||
|
|
||||||
class Ui_AddressBookWidgetItemLabel(Ui_AddressBookWidgetItem):
|
class Ui_AddressBookWidgetItemLabel(Ui_AddressBookWidgetItem):
|
||||||
"""Addressbook label item"""
|
"""Addressbook label item"""
|
||||||
def __init__(self, address, label, acc_type):
|
def __init__(self, address, label, acc_type):
|
||||||
self.address = address
|
self.address = ustr(address)
|
||||||
super(Ui_AddressBookWidgetItemLabel, self).__init__(label, acc_type)
|
super(Ui_AddressBookWidgetItemLabel, self).__init__(label, acc_type)
|
||||||
|
|
||||||
def data(self, role):
|
def data(self, role):
|
||||||
|
@ -558,7 +559,7 @@ class Ui_AddressBookWidgetItemLabel(Ui_AddressBookWidgetItem):
|
||||||
class Ui_AddressBookWidgetItemAddress(Ui_AddressBookWidgetItem):
|
class Ui_AddressBookWidgetItemAddress(Ui_AddressBookWidgetItem):
|
||||||
"""Addressbook address item"""
|
"""Addressbook address item"""
|
||||||
def __init__(self, address, label, acc_type):
|
def __init__(self, address, label, acc_type):
|
||||||
self.address = address
|
self.address = ustr(address)
|
||||||
super(Ui_AddressBookWidgetItemAddress, self).__init__(address, acc_type)
|
super(Ui_AddressBookWidgetItemAddress, self).__init__(address, acc_type)
|
||||||
|
|
||||||
def data(self, role):
|
def data(self, role):
|
||||||
|
@ -570,28 +571,27 @@ class Ui_AddressBookWidgetItemAddress(Ui_AddressBookWidgetItem):
|
||||||
return super(Ui_AddressBookWidgetItemAddress, self).data(role)
|
return super(Ui_AddressBookWidgetItemAddress, self).data(role)
|
||||||
|
|
||||||
|
|
||||||
class AddressBookCompleter(QtGui.QCompleter):
|
class AddressBookCompleter(QtWidgets.QCompleter):
|
||||||
"""Addressbook completer"""
|
"""Addressbook completer"""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super(AddressBookCompleter, self).__init__()
|
super(AddressBookCompleter, self).__init__()
|
||||||
self.cursorPos = -1
|
self.cursorPos = -1
|
||||||
|
|
||||||
def onCursorPositionChanged(self, oldPos, newPos): # pylint: disable=unused-argument
|
def onCursorPositionChanged(self, oldPos, newPos):
|
||||||
"""Callback for cursor position change"""
|
"""Callback for cursor position change"""
|
||||||
|
# pylint: disable=unused-argument
|
||||||
if oldPos != self.cursorPos:
|
if oldPos != self.cursorPos:
|
||||||
self.cursorPos = -1
|
self.cursorPos = -1
|
||||||
|
|
||||||
def splitPath(self, path):
|
def splitPath(self, path):
|
||||||
"""Split on semicolon"""
|
"""Split on semicolon"""
|
||||||
text = unicode(path.toUtf8(), 'utf-8')
|
text = unic(ustr(path))
|
||||||
return [text[:self.widget().cursorPosition()].split(';')[-1].strip()]
|
return [text[:self.widget().cursorPosition()].split(';')[-1].strip()]
|
||||||
|
|
||||||
def pathFromIndex(self, index):
|
def pathFromIndex(self, index):
|
||||||
"""Perform autocompletion (reimplemented QCompleter method)"""
|
"""Perform autocompletion (reimplemented QCompleter method)"""
|
||||||
autoString = unicode(
|
autoString = unic(ustr(index.data(QtCore.Qt.EditRole).toString()))
|
||||||
index.data(QtCore.Qt.EditRole).toString().toUtf8(), 'utf-8')
|
text = unic(ustr(self.widget().text()))
|
||||||
text = unicode(self.widget().text().toUtf8(), 'utf-8')
|
|
||||||
|
|
||||||
# If cursor position was saved, restore it, else save it
|
# If cursor position was saved, restore it, else save it
|
||||||
if self.cursorPos != -1:
|
if self.cursorPos != -1:
|
||||||
|
@ -620,7 +620,6 @@ class AddressBookCompleter(QtGui.QCompleter):
|
||||||
|
|
||||||
# Get string value from before auto finished string is selected
|
# Get string value from before auto finished string is selected
|
||||||
# pre = text[prevDelimiterIndex + 1:curIndex - 1]
|
# pre = text[prevDelimiterIndex + 1:curIndex - 1]
|
||||||
|
|
||||||
# Get part of string that occurs AFTER cursor
|
# Get part of string that occurs AFTER cursor
|
||||||
part2 = text[nextDelimiterIndex:]
|
part2 = text[nextDelimiterIndex:]
|
||||||
|
|
||||||
|
|
|
@ -1,48 +1,56 @@
|
||||||
"""Language Box Module for Locale Settings"""
|
"""LanguageBox widget is for selecting UI language"""
|
||||||
# pylint: disable=too-few-public-methods,bad-continuation
|
|
||||||
import glob
|
import glob
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from PyQt4 import QtCore, QtGui
|
from qtpy import QtCore, QtWidgets
|
||||||
|
|
||||||
import paths
|
import paths
|
||||||
from bmconfigparser import config
|
from bmconfigparser import config
|
||||||
|
from tr import _translate
|
||||||
|
|
||||||
|
|
||||||
class LanguageBox(QtGui.QComboBox):
|
# pylint: disable=too-few-public-methods
|
||||||
"""LanguageBox class for Qt UI"""
|
class LanguageBox(QtWidgets.QComboBox):
|
||||||
|
"""A subclass of `QtWidgets.QComboBox` for selecting language"""
|
||||||
languageName = {
|
languageName = {
|
||||||
"system": "System Settings", "eo": "Esperanto",
|
"system": "System Settings",
|
||||||
|
"eo": "Esperanto",
|
||||||
"en_pirate": "Pirate English"
|
"en_pirate": "Pirate English"
|
||||||
}
|
}
|
||||||
|
|
||||||
def __init__(self, parent=None):
|
def __init__(self, parent=None):
|
||||||
super(QtGui.QComboBox, self).__init__(parent)
|
super(LanguageBox, self).__init__(parent)
|
||||||
self.populate()
|
self.populate()
|
||||||
|
|
||||||
def populate(self):
|
def populate(self):
|
||||||
"""Populates drop down list with all available languages."""
|
"""Populates drop down list with all available languages."""
|
||||||
self.clear()
|
self.clear()
|
||||||
localesPath = os.path.join(paths.codePath(), 'translations')
|
localesPath = os.path.join(paths.codePath(), 'translations')
|
||||||
self.addItem(QtGui.QApplication.translate(
|
self.addItem(
|
||||||
"settingsDialog", "System Settings", "system"), "system")
|
_translate("settingsDialog", "System Settings", "system"),
|
||||||
|
"system"
|
||||||
|
)
|
||||||
self.setCurrentIndex(0)
|
self.setCurrentIndex(0)
|
||||||
self.setInsertPolicy(QtGui.QComboBox.InsertAlphabetically)
|
self.setInsertPolicy(QtWidgets.QComboBox.InsertAlphabetically)
|
||||||
for translationFile in sorted(
|
for translationFile in sorted(
|
||||||
glob.glob(os.path.join(localesPath, "bitmessage_*.qm"))
|
glob.glob(os.path.join(localesPath, "bitmessage_*.qm"))
|
||||||
):
|
):
|
||||||
localeShort = \
|
localeShort = \
|
||||||
os.path.split(translationFile)[1].split("_", 1)[1][:-3]
|
os.path.split(translationFile)[1].split("_", 1)[1][:-3]
|
||||||
|
locale = QtCore.QLocale(localeShort)
|
||||||
if localeShort in LanguageBox.languageName:
|
if localeShort in LanguageBox.languageName:
|
||||||
self.addItem(
|
self.addItem(
|
||||||
LanguageBox.languageName[localeShort], localeShort)
|
LanguageBox.languageName[localeShort], localeShort)
|
||||||
|
elif locale.nativeLanguageName() == "":
|
||||||
|
self.addItem(localeShort, localeShort)
|
||||||
else:
|
else:
|
||||||
locale = QtCore.QLocale(localeShort)
|
locale = QtCore.QLocale(localeShort)
|
||||||
self.addItem(
|
self.addItem(
|
||||||
locale.nativeLanguageName() or localeShort, localeShort)
|
locale.nativeLanguageName() or localeShort, localeShort)
|
||||||
|
|
||||||
configuredLocale = config.safeGet(
|
configuredLocale = config.safeGet(
|
||||||
'bitmessagesettings', 'userlocale', "system")
|
'bitmessagesettings', 'userlocale', 'system')
|
||||||
for i in range(self.count()):
|
for i in range(self.count()):
|
||||||
if self.itemData(i) == configuredLocale:
|
if self.itemData(i) == configuredLocale:
|
||||||
self.setCurrentIndex(i)
|
self.setCurrentIndex(i)
|
||||||
|
|
|
@ -1,33 +1,34 @@
|
||||||
"""
|
"""The MessageCompose class definition"""
|
||||||
Message editor with a wheel zoom functionality
|
|
||||||
"""
|
|
||||||
# pylint: disable=bad-continuation
|
|
||||||
|
|
||||||
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"""
|
"""Editor class with wheel zoom functionality"""
|
||||||
def __init__(self, parent=0):
|
def __init__(self, parent=None):
|
||||||
super(MessageCompose, self).__init__(parent)
|
super(MessageCompose, self).__init__(parent)
|
||||||
|
# we'll deal with this later when we have a new message format
|
||||||
self.setAcceptRichText(False)
|
self.setAcceptRichText(False)
|
||||||
self.defaultFontPointSize = self.currentFont().pointSize()
|
self.defaultFontPointSize = self.currentFont().pointSize()
|
||||||
|
|
||||||
def wheelEvent(self, event):
|
def wheelEvent(self, event):
|
||||||
"""Mouse wheel scroll event handler"""
|
"""Mouse wheel scroll event handler"""
|
||||||
if (
|
if (
|
||||||
QtGui.QApplication.queryKeyboardModifiers() & QtCore.Qt.ControlModifier
|
(QtWidgets.QApplication.queryKeyboardModifiers()
|
||||||
) == QtCore.Qt.ControlModifier and event.orientation() == QtCore.Qt.Vertical:
|
& QtCore.Qt.ControlModifier) == QtCore.Qt.ControlModifier
|
||||||
|
and event.angleDelta().y() != 0
|
||||||
|
):
|
||||||
if event.delta() > 0:
|
if event.delta() > 0:
|
||||||
self.zoomIn(1)
|
self.zoomIn(1)
|
||||||
else:
|
else:
|
||||||
self.zoomOut(1)
|
self.zoomOut(1)
|
||||||
zoom = self.currentFont().pointSize() * 100 / self.defaultFontPointSize
|
QtWidgets.QApplication.activeWindow().statusbar.showMessage(
|
||||||
QtGui.QApplication.activeWindow().statusBar().showMessage(
|
_translate("MainWindow", "Zoom level {0}%").format(
|
||||||
QtGui.QApplication.translate("MainWindow", "Zoom level %1%").arg(
|
# zoom percentage
|
||||||
str(zoom)
|
self.currentFont().pointSize() * 100
|
||||||
)
|
/ self.defaultFontPointSize
|
||||||
)
|
))
|
||||||
else:
|
else:
|
||||||
# in QTextEdit, super does not zoom, only scroll
|
# in QTextEdit, super does not zoom, only scroll
|
||||||
super(MessageCompose, self).wheelEvent(event)
|
super(MessageCompose, self).wheelEvent(event)
|
||||||
|
|
|
@ -1,22 +1,22 @@
|
||||||
"""
|
"""
|
||||||
Custom message viewer with support for switching between HTML and plain
|
Custom message viewer with support for switching between HTML and plain
|
||||||
text rendering, HTML sanitization, lazy rendering (as you scroll down),
|
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
|
from tr import _translate
|
||||||
|
|
||||||
|
|
||||||
class MessageView(QtGui.QTextBrowser):
|
class MessageView(QtWidgets.QTextBrowser):
|
||||||
"""Message content viewer class, can switch between plaintext and HTML"""
|
"""Message content viewer class, can switch between plaintext and HTML"""
|
||||||
MODE_PLAIN = 0
|
MODE_PLAIN = 0
|
||||||
MODE_HTML = 1
|
MODE_HTML = 1
|
||||||
|
|
||||||
def __init__(self, parent=0):
|
def __init__(self, parent=None):
|
||||||
super(MessageView, self).__init__(parent)
|
super(MessageView, self).__init__(parent)
|
||||||
self.mode = MessageView.MODE_PLAIN
|
self.mode = MessageView.MODE_PLAIN
|
||||||
self.html = None
|
self.html = None
|
||||||
|
@ -38,8 +38,11 @@ class MessageView(QtGui.QTextBrowser):
|
||||||
|
|
||||||
def mousePressEvent(self, event):
|
def mousePressEvent(self, event):
|
||||||
"""Mouse press button event handler"""
|
"""Mouse press button event handler"""
|
||||||
if event.button() == QtCore.Qt.LeftButton and self.html and self.html.has_html and self.cursorForPosition(
|
if (
|
||||||
event.pos()).block().blockNumber() == 0:
|
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:
|
if self.mode == MessageView.MODE_PLAIN:
|
||||||
self.showHTML()
|
self.showHTML()
|
||||||
else:
|
else:
|
||||||
|
@ -52,23 +55,23 @@ class MessageView(QtGui.QTextBrowser):
|
||||||
# super will actually automatically take care of zooming
|
# super will actually automatically take care of zooming
|
||||||
super(MessageView, self).wheelEvent(event)
|
super(MessageView, self).wheelEvent(event)
|
||||||
if (
|
if (
|
||||||
QtGui.QApplication.queryKeyboardModifiers() & QtCore.Qt.ControlModifier
|
(QtWidgets.QApplication.queryKeyboardModifiers()
|
||||||
) == QtCore.Qt.ControlModifier and event.orientation() == QtCore.Qt.Vertical:
|
& QtCore.Qt.ControlModifier) == QtCore.Qt.ControlModifier
|
||||||
|
and event.angleDelta().y() != 0
|
||||||
|
):
|
||||||
zoom = self.currentFont().pointSize() * 100 / self.defaultFontPointSize
|
zoom = self.currentFont().pointSize() * 100 / self.defaultFontPointSize
|
||||||
QtGui.QApplication.activeWindow().statusBar().showMessage(_translate(
|
QtWidgets.QApplication.activeWindow().statusbar.showMessage(
|
||||||
"MainWindow", "Zoom level %1%").arg(str(zoom)))
|
_translate("MainWindow", "Zoom level {0}%").format(zoom))
|
||||||
|
|
||||||
def setWrappingWidth(self, width=None):
|
def setWrappingWidth(self, width=None):
|
||||||
"""Set word-wrapping width"""
|
"""Set word-wrapping width"""
|
||||||
self.setLineWrapMode(QtGui.QTextEdit.FixedPixelWidth)
|
self.setLineWrapMode(QtWidgets.QTextEdit.FixedPixelWidth)
|
||||||
if width is None:
|
self.setLineWrapColumnOrWidth(width or self.width())
|
||||||
width = self.width()
|
|
||||||
self.setLineWrapColumnOrWidth(width)
|
|
||||||
|
|
||||||
def confirmURL(self, link):
|
def confirmURL(self, link):
|
||||||
"""Show a dialog requesting URL opening confirmation"""
|
"""Show a dialog requesting URL opening confirmation"""
|
||||||
if link.scheme() == "mailto":
|
if link.scheme() == "mailto":
|
||||||
window = QtGui.QApplication.activeWindow()
|
window = QtWidgets.QApplication.activeWindow()
|
||||||
window.ui.lineEditTo.setText(link.path())
|
window.ui.lineEditTo.setText(link.path())
|
||||||
if link.hasQueryItem("subject"):
|
if link.hasQueryItem("subject"):
|
||||||
window.ui.lineEditSubject.setText(
|
window.ui.lineEditSubject.setText(
|
||||||
|
@ -83,39 +86,40 @@ class MessageView(QtGui.QTextBrowser):
|
||||||
)
|
)
|
||||||
window.ui.textEditMessage.setFocus()
|
window.ui.textEditMessage.setFocus()
|
||||||
return
|
return
|
||||||
reply = QtGui.QMessageBox.warning(
|
reply = QtWidgets.QMessageBox.warning(
|
||||||
self,
|
self, _translate("MessageView", "Follow external link"),
|
||||||
QtGui.QApplication.translate(
|
_translate(
|
||||||
"MessageView",
|
"MessageView",
|
||||||
"Follow external link"),
|
"The link \"{0}\" will open in a browser. It may be"
|
||||||
QtGui.QApplication.translate(
|
" a security risk, it could de-anonymise you or download"
|
||||||
"MessageView",
|
" malicious data. Are you sure?"
|
||||||
"The link \"%1\" will open in a browser. It may be a security risk, it could de-anonymise you"
|
).format(unic(ustr(link.toString()))),
|
||||||
" or download malicious data. Are you sure?").arg(unicode(link.toString())),
|
QtWidgets.QMessageBox.Yes, QtWidgets.QMessageBox.No)
|
||||||
QtGui.QMessageBox.Yes,
|
if reply == QtWidgets.QMessageBox.Yes:
|
||||||
QtGui.QMessageBox.No)
|
|
||||||
if reply == QtGui.QMessageBox.Yes:
|
|
||||||
QtGui.QDesktopServices.openUrl(link)
|
QtGui.QDesktopServices.openUrl(link)
|
||||||
|
|
||||||
def loadResource(self, restype, name):
|
def loadResource(self, restype, name):
|
||||||
"""
|
"""
|
||||||
Callback for loading referenced objects, such as an image. For security reasons at the moment doesn't do
|
Callback for loading referenced objects, such as an image.
|
||||||
anything)
|
For security reasons at the moment doesn't do anything
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def lazyRender(self):
|
def lazyRender(self):
|
||||||
"""
|
"""
|
||||||
Partially render a message. This is to avoid UI freezing when loading huge messages. It continues loading as
|
Partially render a message. This is to avoid UI freezing when
|
||||||
you scroll down.
|
loading huge messages. It continues loading as you scroll down.
|
||||||
"""
|
"""
|
||||||
if self.rendering:
|
if self.rendering:
|
||||||
return
|
return
|
||||||
self.rendering = True
|
self.rendering = True
|
||||||
position = self.verticalScrollBar().value()
|
position = self.verticalScrollBar().value()
|
||||||
cursor = QtGui.QTextCursor(self.document())
|
cursor = QtGui.QTextCursor(self.document())
|
||||||
while self.outpos < len(self.out) and self.verticalScrollBar().value(
|
while (
|
||||||
) >= self.document().size().height() - 2 * self.size().height():
|
self.outpos < len(self.out)
|
||||||
|
and self.verticalScrollBar().value()
|
||||||
|
>= self.document().size().height() - 2 * self.size().height()
|
||||||
|
):
|
||||||
startpos = self.outpos
|
startpos = self.outpos
|
||||||
self.outpos += 10240
|
self.outpos += 10240
|
||||||
# find next end of tag
|
# find next end of tag
|
||||||
|
@ -123,8 +127,9 @@ class MessageView(QtGui.QTextBrowser):
|
||||||
pos = self.out.find(">", self.outpos)
|
pos = self.out.find(">", self.outpos)
|
||||||
if pos > self.outpos:
|
if pos > self.outpos:
|
||||||
self.outpos = pos + 1
|
self.outpos = pos + 1
|
||||||
cursor.movePosition(QtGui.QTextCursor.End, QtGui.QTextCursor.MoveAnchor)
|
cursor.movePosition(
|
||||||
cursor.insertHtml(QtCore.QString(self.out[startpos:self.outpos]))
|
QtGui.QTextCursor.End, QtGui.QTextCursor.MoveAnchor)
|
||||||
|
cursor.insertHtml(unic(self.out[startpos:self.outpos]))
|
||||||
self.verticalScrollBar().setValue(position)
|
self.verticalScrollBar().setValue(position)
|
||||||
self.rendering = False
|
self.rendering = False
|
||||||
|
|
||||||
|
@ -133,9 +138,11 @@ class MessageView(QtGui.QTextBrowser):
|
||||||
self.mode = MessageView.MODE_PLAIN
|
self.mode = MessageView.MODE_PLAIN
|
||||||
out = self.html.raw
|
out = self.html.raw
|
||||||
if self.html.has_html:
|
if self.html.has_html:
|
||||||
out = "<div align=\"center\" style=\"text-decoration: underline;\"><b>" + unicode(
|
out = (
|
||||||
QtGui.QApplication.translate(
|
'<div align="center" style="text-decoration: underline;"><b>'
|
||||||
"MessageView", "HTML detected, click here to display")) + "</b></div><br/>" + out
|
+ unic(ustr(_translate(
|
||||||
|
"MessageView", "HTML detected, click here to display"
|
||||||
|
))) + '</b></div><br/>' + out)
|
||||||
self.out = out
|
self.out = out
|
||||||
self.outpos = 0
|
self.outpos = 0
|
||||||
self.setHtml("")
|
self.setHtml("")
|
||||||
|
@ -144,10 +151,10 @@ class MessageView(QtGui.QTextBrowser):
|
||||||
def showHTML(self):
|
def showHTML(self):
|
||||||
"""Render message as HTML"""
|
"""Render message as HTML"""
|
||||||
self.mode = MessageView.MODE_HTML
|
self.mode = MessageView.MODE_HTML
|
||||||
out = self.html.sanitised
|
self.out = (
|
||||||
out = "<div align=\"center\" style=\"text-decoration: underline;\"><b>" + unicode(
|
'<div align="center" style="text-decoration: underline;"><b>'
|
||||||
QtGui.QApplication.translate("MessageView", "Click here to disable HTML")) + "</b></div><br/>" + out
|
+ _translate("MessageView", "Click here to disable HTML")
|
||||||
self.out = out
|
+ '</b></div><br/>' + self.html.sanitised)
|
||||||
self.outpos = 0
|
self.outpos = 0
|
||||||
self.setHtml("")
|
self.setHtml("")
|
||||||
self.lazyRender()
|
self.lazyRender()
|
||||||
|
@ -155,8 +162,6 @@ class MessageView(QtGui.QTextBrowser):
|
||||||
def setContent(self, data):
|
def setContent(self, data):
|
||||||
"""Set message content from argument"""
|
"""Set message content from argument"""
|
||||||
self.html = SafeHTMLParser()
|
self.html = SafeHTMLParser()
|
||||||
self.html.reset()
|
|
||||||
self.html.reset_safe()
|
|
||||||
self.html.allow_picture = True
|
self.html.allow_picture = True
|
||||||
self.html.feed(data)
|
self.html.feed(data)
|
||||||
self.html.close()
|
self.html.close()
|
||||||
|
|
|
@ -1,16 +1,15 @@
|
||||||
#!/usr/bin/env python2.7
|
from qtpy import QtCore, QtWidgets
|
||||||
from PyQt4 import QtCore, QtGui
|
|
||||||
|
|
||||||
class MigrationWizardIntroPage(QtGui.QWizardPage):
|
class MigrationWizardIntroPage(QtWidgets.QWizardPage):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super(QtGui.QWizardPage, self).__init__()
|
super(QtWidgets.QWizardPage, self).__init__()
|
||||||
self.setTitle("Migrating configuration")
|
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.")
|
"You can still keep using PyBitMessage once you migrate, the changes are backwards compatible.")
|
||||||
label.setWordWrap(True)
|
label.setWordWrap(True)
|
||||||
|
|
||||||
layout = QtGui.QVBoxLayout()
|
layout = QtWidgets.QVBoxLayout()
|
||||||
layout.addWidget(label)
|
layout.addWidget(label)
|
||||||
self.setLayout(layout)
|
self.setLayout(layout)
|
||||||
|
|
||||||
|
@ -18,15 +17,15 @@ class MigrationWizardIntroPage(QtGui.QWizardPage):
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
|
|
||||||
class MigrationWizardAddressesPage(QtGui.QWizardPage):
|
class MigrationWizardAddressesPage(QtWidgets.QWizardPage):
|
||||||
def __init__(self, addresses):
|
def __init__(self, addresses):
|
||||||
super(QtGui.QWizardPage, self).__init__()
|
super(QtWidgets.QWizardPage, self).__init__()
|
||||||
self.setTitle("Addresses")
|
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)
|
label.setWordWrap(True)
|
||||||
|
|
||||||
layout = QtGui.QVBoxLayout()
|
layout = QtWidgets.QVBoxLayout()
|
||||||
layout.addWidget(label)
|
layout.addWidget(label)
|
||||||
self.setLayout(layout)
|
self.setLayout(layout)
|
||||||
|
|
||||||
|
@ -34,15 +33,15 @@ class MigrationWizardAddressesPage(QtGui.QWizardPage):
|
||||||
return 10
|
return 10
|
||||||
|
|
||||||
|
|
||||||
class MigrationWizardGPUPage(QtGui.QWizardPage):
|
class MigrationWizardGPUPage(QtWidgets.QWizardPage):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super(QtGui.QWizardPage, self).__init__()
|
super(QtWidgets.QWizardPage, self).__init__()
|
||||||
self.setTitle("GPU")
|
self.setTitle("GPU")
|
||||||
|
|
||||||
label = QtGui.QLabel("Are you using a GPU? ")
|
label = QtWidgets.QLabel("Are you using a GPU? ")
|
||||||
label.setWordWrap(True)
|
label.setWordWrap(True)
|
||||||
|
|
||||||
layout = QtGui.QVBoxLayout()
|
layout = QtWidgets.QVBoxLayout()
|
||||||
layout.addWidget(label)
|
layout.addWidget(label)
|
||||||
self.setLayout(layout)
|
self.setLayout(layout)
|
||||||
|
|
||||||
|
@ -50,22 +49,22 @@ class MigrationWizardGPUPage(QtGui.QWizardPage):
|
||||||
return 10
|
return 10
|
||||||
|
|
||||||
|
|
||||||
class MigrationWizardConclusionPage(QtGui.QWizardPage):
|
class MigrationWizardConclusionPage(QtWidgets.QWizardPage):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super(QtGui.QWizardPage, self).__init__()
|
super(QtWidgets.QWizardPage, self).__init__()
|
||||||
self.setTitle("All done!")
|
self.setTitle("All done!")
|
||||||
|
|
||||||
label = QtGui.QLabel("You successfully migrated.")
|
label = QtWidgets.QLabel("You successfully migrated.")
|
||||||
label.setWordWrap(True)
|
label.setWordWrap(True)
|
||||||
|
|
||||||
layout = QtGui.QVBoxLayout()
|
layout = QtWidgets.QVBoxLayout()
|
||||||
layout.addWidget(label)
|
layout.addWidget(label)
|
||||||
self.setLayout(layout)
|
self.setLayout(layout)
|
||||||
|
|
||||||
|
|
||||||
class Ui_MigrationWizard(QtGui.QWizard):
|
class Ui_MigrationWizard(QtWidgets.QWizard):
|
||||||
def __init__(self, addresses):
|
def __init__(self, addresses):
|
||||||
super(QtGui.QWizard, self).__init__()
|
super(QtWidgets.QWizard, self).__init__()
|
||||||
|
|
||||||
self.pages = {}
|
self.pages = {}
|
||||||
|
|
||||||
|
@ -81,4 +80,4 @@ class Ui_MigrationWizard(QtGui.QWizard):
|
||||||
|
|
||||||
self.setWindowTitle("Migration from PyBitMessage wizard")
|
self.setWindowTitle("Migration from PyBitMessage wizard")
|
||||||
self.adjustSize()
|
self.adjustSize()
|
||||||
self.show()
|
self.show()
|
||||||
|
|
|
@ -4,26 +4,28 @@ Network status tab widget definition.
|
||||||
|
|
||||||
import time
|
import time
|
||||||
|
|
||||||
from PyQt4 import QtCore, QtGui
|
from qtpy import QtCore, QtGui, QtWidgets
|
||||||
|
|
||||||
import l10n
|
import l10n
|
||||||
import network.stats
|
import network.stats
|
||||||
import state
|
import state
|
||||||
import widgets
|
from bitmessageqt import widgets
|
||||||
from network import connectionpool, knownnodes
|
from network import connectionpool, knownnodes
|
||||||
from retranslateui import RetranslateMixin
|
from .retranslateui import RetranslateMixin
|
||||||
from tr import _translate
|
from tr import _translate
|
||||||
from uisignaler import UISignaler
|
from .uisignaler import UISignaler
|
||||||
|
|
||||||
|
|
||||||
class NetworkStatus(QtGui.QWidget, RetranslateMixin):
|
class NetworkStatus(QtWidgets.QWidget, RetranslateMixin):
|
||||||
"""Network status tab"""
|
"""Network status tab"""
|
||||||
def __init__(self, parent=None):
|
def __init__(self, parent=None):
|
||||||
super(NetworkStatus, self).__init__(parent)
|
super(NetworkStatus, self).__init__(parent)
|
||||||
widgets.load('networkstatus.ui', self)
|
widgets.load('networkstatus.ui', self)
|
||||||
|
|
||||||
header = self.tableWidgetConnectionCount.horizontalHeader()
|
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
|
# Somehow this value was 5 when I tested
|
||||||
if header.sortIndicatorSection() > 4:
|
if header.sortIndicatorSection() > 4:
|
||||||
|
@ -32,20 +34,17 @@ class NetworkStatus(QtGui.QWidget, RetranslateMixin):
|
||||||
self.startup = time.localtime()
|
self.startup = time.localtime()
|
||||||
|
|
||||||
self.UISignalThread = UISignaler.get()
|
self.UISignalThread = UISignaler.get()
|
||||||
# pylint: disable=no-member
|
self.UISignalThread.updateNumberOfMessagesProcessed.connect(
|
||||||
QtCore.QObject.connect(self.UISignalThread, QtCore.SIGNAL(
|
self.updateNumberOfMessagesProcessed)
|
||||||
"updateNumberOfMessagesProcessed()"), self.updateNumberOfMessagesProcessed)
|
self.UISignalThread.updateNumberOfPubkeysProcessed.connect(
|
||||||
QtCore.QObject.connect(self.UISignalThread, QtCore.SIGNAL(
|
self.updateNumberOfPubkeysProcessed)
|
||||||
"updateNumberOfPubkeysProcessed()"), self.updateNumberOfPubkeysProcessed)
|
self.UISignalThread.updateNumberOfBroadcastsProcessed.connect(
|
||||||
QtCore.QObject.connect(self.UISignalThread, QtCore.SIGNAL(
|
self.updateNumberOfBroadcastsProcessed)
|
||||||
"updateNumberOfBroadcastsProcessed()"), self.updateNumberOfBroadcastsProcessed)
|
self.UISignalThread.updateNetworkStatusTab.connect(
|
||||||
QtCore.QObject.connect(self.UISignalThread, QtCore.SIGNAL(
|
self.updateNetworkStatusTab)
|
||||||
"updateNetworkStatusTab(PyQt_PyObject,PyQt_PyObject,PyQt_PyObject)"), self.updateNetworkStatusTab)
|
|
||||||
|
|
||||||
self.timer = QtCore.QTimer()
|
self.timer = QtCore.QTimer()
|
||||||
|
self.timer.timeout.connect(self.runEveryTwoSeconds)
|
||||||
QtCore.QObject.connect(self.timer, QtCore.SIGNAL("timeout()"), self.runEveryTwoSeconds)
|
|
||||||
# pylint: enable=no-member
|
|
||||||
|
|
||||||
def startUpdate(self):
|
def startUpdate(self):
|
||||||
"""Start a timer to update counters every 2 seconds"""
|
"""Start a timer to update counters every 2 seconds"""
|
||||||
|
@ -57,91 +56,66 @@ class NetworkStatus(QtGui.QWidget, RetranslateMixin):
|
||||||
"""Stop counter update timer"""
|
"""Stop counter update timer"""
|
||||||
self.timer.stop()
|
self.timer.stop()
|
||||||
|
|
||||||
def formatBytes(self, num):
|
@staticmethod
|
||||||
|
def formatBytes(num):
|
||||||
"""Format bytes nicely (SI prefixes)"""
|
"""Format bytes nicely (SI prefixes)"""
|
||||||
# pylint: disable=no-self-use
|
for x in (
|
||||||
for x in [
|
_translate("networkstatus", "byte(s)", None, num),
|
||||||
_translate(
|
"kB", "MB", "GB"
|
||||||
"networkstatus",
|
):
|
||||||
"byte(s)",
|
|
||||||
None,
|
|
||||||
QtCore.QCoreApplication.CodecForTr,
|
|
||||||
num),
|
|
||||||
"kB",
|
|
||||||
"MB",
|
|
||||||
"GB",
|
|
||||||
]:
|
|
||||||
if num < 1000.0:
|
if num < 1000.0:
|
||||||
return "%3.0f %s" % (num, x)
|
return "%3.0f %s" % (num, x)
|
||||||
num /= 1000.0
|
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"""
|
"""Format transfer speed in kB/s"""
|
||||||
# pylint: disable=no-self-use
|
|
||||||
num /= 1000
|
num /= 1000
|
||||||
return "%4.0f kB" % num
|
return "%4.0f kB" % num
|
||||||
|
|
||||||
def updateNumberOfObjectsToBeSynced(self):
|
def updateNumberOfObjectsToBeSynced(self):
|
||||||
"""Update the counter for number of objects to be synced"""
|
"""Update the counter for number of objects to be synced"""
|
||||||
self.labelSyncStatus.setText(
|
self.labelSyncStatus.setText(_translate(
|
||||||
_translate(
|
"networkstatus", "Object(s) to be synced: %n", None,
|
||||||
"networkstatus",
|
network.stats.pendingDownload() + network.stats.pendingUpload()))
|
||||||
"Object(s) to be synced: %n",
|
|
||||||
None,
|
|
||||||
QtCore.QCoreApplication.CodecForTr,
|
|
||||||
network.stats.pendingDownload()
|
|
||||||
+ network.stats.pendingUpload()))
|
|
||||||
|
|
||||||
def updateNumberOfMessagesProcessed(self):
|
def updateNumberOfMessagesProcessed(self):
|
||||||
"""Update the counter for number of processed messages"""
|
"""Update the counter for number of processed messages"""
|
||||||
self.updateNumberOfObjectsToBeSynced()
|
self.updateNumberOfObjectsToBeSynced()
|
||||||
self.labelMessageCount.setText(
|
self.labelMessageCount.setText(_translate(
|
||||||
_translate(
|
"networkstatus", "Processed %n person-to-person message(s).",
|
||||||
"networkstatus",
|
None, state.numberOfMessagesProcessed))
|
||||||
"Processed %n person-to-person message(s).",
|
|
||||||
None,
|
|
||||||
QtCore.QCoreApplication.CodecForTr,
|
|
||||||
state.numberOfMessagesProcessed))
|
|
||||||
|
|
||||||
def updateNumberOfBroadcastsProcessed(self):
|
def updateNumberOfBroadcastsProcessed(self):
|
||||||
"""Update the counter for the number of processed broadcasts"""
|
"""Update the counter for the number of processed broadcasts"""
|
||||||
self.updateNumberOfObjectsToBeSynced()
|
self.updateNumberOfObjectsToBeSynced()
|
||||||
self.labelBroadcastCount.setText(
|
self.labelBroadcastCount.setText(_translate(
|
||||||
_translate(
|
"networkstatus", "Processed %n broadcast message(s).", None,
|
||||||
"networkstatus",
|
state.numberOfBroadcastsProcessed))
|
||||||
"Processed %n broadcast message(s).",
|
|
||||||
None,
|
|
||||||
QtCore.QCoreApplication.CodecForTr,
|
|
||||||
state.numberOfBroadcastsProcessed))
|
|
||||||
|
|
||||||
def updateNumberOfPubkeysProcessed(self):
|
def updateNumberOfPubkeysProcessed(self):
|
||||||
"""Update the counter for the number of processed pubkeys"""
|
"""Update the counter for the number of processed pubkeys"""
|
||||||
self.updateNumberOfObjectsToBeSynced()
|
self.updateNumberOfObjectsToBeSynced()
|
||||||
self.labelPubkeyCount.setText(
|
self.labelPubkeyCount.setText(_translate(
|
||||||
_translate(
|
"networkstatus", "Processed %n public key(s).", None,
|
||||||
"networkstatus",
|
state.numberOfPubkeysProcessed))
|
||||||
"Processed %n public key(s).",
|
|
||||||
None,
|
|
||||||
QtCore.QCoreApplication.CodecForTr,
|
|
||||||
state.numberOfPubkeysProcessed))
|
|
||||||
|
|
||||||
def updateNumberOfBytes(self):
|
def updateNumberOfBytes(self):
|
||||||
"""
|
"""
|
||||||
This function is run every two seconds, so we divide the rate of bytes
|
This function is run every two seconds, so we divide the rate
|
||||||
sent and received by 2.
|
of bytes sent and received by 2.
|
||||||
"""
|
"""
|
||||||
self.labelBytesRecvCount.setText(
|
self.labelBytesRecvCount.setText(_translate(
|
||||||
_translate(
|
"networkstatus", "Down: {0}/s Total: {1}").format(
|
||||||
"networkstatus",
|
self.formatByteRate(network.stats.downloadSpeed()),
|
||||||
"Down: %1/s Total: %2").arg(
|
self.formatBytes(network.stats.receivedBytes())
|
||||||
self.formatByteRate(network.stats.downloadSpeed()),
|
))
|
||||||
self.formatBytes(network.stats.receivedBytes())))
|
self.labelBytesSentCount.setText(_translate(
|
||||||
self.labelBytesSentCount.setText(
|
"networkstatus", "Up: {0}/s Total: {1}").format(
|
||||||
_translate(
|
self.formatByteRate(network.stats.uploadSpeed()),
|
||||||
"networkstatus", "Up: %1/s Total: %2").arg(
|
self.formatBytes(network.stats.sentBytes())
|
||||||
self.formatByteRate(network.stats.uploadSpeed()),
|
))
|
||||||
self.formatBytes(network.stats.sentBytes())))
|
|
||||||
|
|
||||||
def updateNetworkStatusTab(self, outbound, add, destination):
|
def updateNetworkStatusTab(self, outbound, add, destination):
|
||||||
"""Add or remove an entry to the list of connected peers"""
|
"""Add or remove an entry to the list of connected peers"""
|
||||||
|
@ -168,67 +142,67 @@ class NetworkStatus(QtGui.QWidget, RetranslateMixin):
|
||||||
if add:
|
if add:
|
||||||
self.tableWidgetConnectionCount.insertRow(0)
|
self.tableWidgetConnectionCount.insertRow(0)
|
||||||
self.tableWidgetConnectionCount.setItem(
|
self.tableWidgetConnectionCount.setItem(
|
||||||
0, 0,
|
0, 0, QtWidgets.QTableWidgetItem(
|
||||||
QtGui.QTableWidgetItem("%s:%i" % (destination.host, destination.port))
|
"%s:%i" % (destination.host, destination.port)))
|
||||||
)
|
|
||||||
self.tableWidgetConnectionCount.setItem(
|
self.tableWidgetConnectionCount.setItem(
|
||||||
0, 2,
|
0, 2, QtWidgets.QTableWidgetItem("%s" % (c.userAgent.decode("utf-8", "replace"))))
|
||||||
QtGui.QTableWidgetItem("%s" % (c.userAgent))
|
|
||||||
)
|
|
||||||
self.tableWidgetConnectionCount.setItem(
|
self.tableWidgetConnectionCount.setItem(
|
||||||
0, 3,
|
0, 3, QtWidgets.QTableWidgetItem("%s" % (c.tlsVersion)))
|
||||||
QtGui.QTableWidgetItem("%s" % (c.tlsVersion))
|
|
||||||
)
|
|
||||||
self.tableWidgetConnectionCount.setItem(
|
self.tableWidgetConnectionCount.setItem(
|
||||||
0, 4,
|
0, 4, QtWidgets.QTableWidgetItem(
|
||||||
QtGui.QTableWidgetItem("%s" % (",".join(map(str, c.streams))))
|
"%s" % ",".join(map(str, c.streams))))
|
||||||
)
|
|
||||||
try:
|
try:
|
||||||
# .. todo:: FIXME: hard coded stream no
|
# .. todo:: FIXME: hard coded stream no
|
||||||
rating = "%.1f" % (knownnodes.knownNodes[1][destination]['rating'])
|
rating = "%.1f" % knownnodes.knownNodes[1][destination]['rating']
|
||||||
except KeyError:
|
except KeyError:
|
||||||
rating = "-"
|
rating = "-"
|
||||||
self.tableWidgetConnectionCount.setItem(
|
self.tableWidgetConnectionCount.setItem(
|
||||||
0, 1,
|
0, 1, QtWidgets.QTableWidgetItem("%s" % (rating)))
|
||||||
QtGui.QTableWidgetItem("%s" % (rating))
|
|
||||||
)
|
|
||||||
if outbound:
|
if outbound:
|
||||||
brush = QtGui.QBrush(QtGui.QColor("yellow"), QtCore.Qt.SolidPattern)
|
brush = QtGui.QBrush(
|
||||||
|
QtGui.QColor("yellow"), QtCore.Qt.SolidPattern)
|
||||||
else:
|
else:
|
||||||
brush = QtGui.QBrush(QtGui.QColor("green"), QtCore.Qt.SolidPattern)
|
brush = QtGui.QBrush(
|
||||||
|
QtGui.QColor("green"), QtCore.Qt.SolidPattern)
|
||||||
for j in range(1):
|
for j in range(1):
|
||||||
self.tableWidgetConnectionCount.item(0, j).setBackground(brush)
|
self.tableWidgetConnectionCount.item(0, j).setBackground(brush)
|
||||||
self.tableWidgetConnectionCount.item(0, 0).setData(QtCore.Qt.UserRole, destination)
|
self.tableWidgetConnectionCount.item(0, 0).setData(
|
||||||
self.tableWidgetConnectionCount.item(0, 1).setData(QtCore.Qt.UserRole, outbound)
|
QtCore.Qt.UserRole, destination)
|
||||||
|
self.tableWidgetConnectionCount.item(0, 1).setData(
|
||||||
|
QtCore.Qt.UserRole, outbound)
|
||||||
else:
|
else:
|
||||||
if not connectionpool.pool.inboundConnections:
|
if not connectionpool.pool.inboundConnections:
|
||||||
self.window().setStatusIcon('yellow')
|
self.window().setStatusIcon('yellow')
|
||||||
for i in range(self.tableWidgetConnectionCount.rowCount()):
|
for i in range(self.tableWidgetConnectionCount.rowCount()):
|
||||||
if self.tableWidgetConnectionCount.item(i, 0).data(QtCore.Qt.UserRole).toPyObject() != destination:
|
if self.tableWidgetConnectionCount.item(i, 0).data(
|
||||||
|
QtCore.Qt.UserRole) != destination:
|
||||||
continue
|
continue
|
||||||
if self.tableWidgetConnectionCount.item(i, 1).data(QtCore.Qt.UserRole).toPyObject() == outbound:
|
if self.tableWidgetConnectionCount.item(i, 1).data(
|
||||||
|
QtCore.Qt.UserRole) == outbound:
|
||||||
self.tableWidgetConnectionCount.removeRow(i)
|
self.tableWidgetConnectionCount.removeRow(i)
|
||||||
break
|
break
|
||||||
|
|
||||||
self.tableWidgetConnectionCount.setUpdatesEnabled(True)
|
self.tableWidgetConnectionCount.setUpdatesEnabled(True)
|
||||||
self.tableWidgetConnectionCount.setSortingEnabled(True)
|
self.tableWidgetConnectionCount.setSortingEnabled(True)
|
||||||
self.labelTotalConnections.setText(
|
self.labelTotalConnections.setText(_translate(
|
||||||
_translate(
|
"networkstatus", "Total Connections: {0}").format(
|
||||||
"networkstatus", "Total Connections: %1").arg(
|
self.tableWidgetConnectionCount.rowCount()
|
||||||
str(self.tableWidgetConnectionCount.rowCount())))
|
))
|
||||||
# FYI: The 'singlelistener' thread sets the icon color to green when it
|
# FYI: The 'singlelistener' thread sets the icon color to green
|
||||||
# receives an incoming connection, meaning that the user's firewall is
|
# when it receives an incoming connection, meaning that the user's
|
||||||
# configured correctly.
|
# firewall is configured correctly.
|
||||||
if self.tableWidgetConnectionCount.rowCount() and state.statusIconColor == 'red':
|
if self.tableWidgetConnectionCount.rowCount():
|
||||||
self.window().setStatusIcon('yellow')
|
if state.statusIconColor == 'red':
|
||||||
elif self.tableWidgetConnectionCount.rowCount() == 0 and state.statusIconColor != "red":
|
self.window().setStatusIcon('yellow')
|
||||||
|
elif state.statusIconColor != 'red':
|
||||||
self.window().setStatusIcon('red')
|
self.window().setStatusIcon('red')
|
||||||
|
|
||||||
# timer driven
|
# timer driven
|
||||||
def runEveryTwoSeconds(self):
|
def runEveryTwoSeconds(self):
|
||||||
"""Updates counters, runs every 2 seconds if the timer is running"""
|
"""Updates counters, runs every 2 seconds if the timer is running"""
|
||||||
self.labelLookupsPerSecond.setText(_translate("networkstatus", "Inventory lookups per second: %1").arg(
|
self.labelLookupsPerSecond.setText(_translate(
|
||||||
str(state.Inventory.numberOfInventoryLookupsPerformed / 2)))
|
"networkstatus", "Inventory lookups per second: {0}"
|
||||||
|
).format(state.Inventory.numberOfInventoryLookupsPerformed / 2))
|
||||||
state.Inventory.numberOfInventoryLookupsPerformed = 0
|
state.Inventory.numberOfInventoryLookupsPerformed = 0
|
||||||
self.updateNumberOfBytes()
|
self.updateNumberOfBytes()
|
||||||
self.updateNumberOfObjectsToBeSynced()
|
self.updateNumberOfObjectsToBeSynced()
|
||||||
|
@ -236,13 +210,12 @@ class NetworkStatus(QtGui.QWidget, RetranslateMixin):
|
||||||
def retranslateUi(self):
|
def retranslateUi(self):
|
||||||
"""Conventional Qt Designer method for dynamic l10n"""
|
"""Conventional Qt Designer method for dynamic l10n"""
|
||||||
super(NetworkStatus, self).retranslateUi()
|
super(NetworkStatus, self).retranslateUi()
|
||||||
self.labelTotalConnections.setText(
|
self.labelTotalConnections.setText(_translate(
|
||||||
_translate(
|
"networkstatus", "Total Connections: {0}"
|
||||||
"networkstatus", "Total Connections: %1").arg(
|
).format(self.tableWidgetConnectionCount.rowCount()))
|
||||||
str(self.tableWidgetConnectionCount.rowCount())))
|
|
||||||
self.labelStartupTime.setText(_translate(
|
self.labelStartupTime.setText(_translate(
|
||||||
"networkstatus", "Since startup on %1"
|
"networkstatus", "Since startup on {0}"
|
||||||
).arg(l10n.formatTimestamp(self.startup)))
|
).format(l10n.formatTimestamp(self.startup)))
|
||||||
self.updateNumberOfMessagesProcessed()
|
self.updateNumberOfMessagesProcessed()
|
||||||
self.updateNumberOfBroadcastsProcessed()
|
self.updateNumberOfBroadcastsProcessed()
|
||||||
self.updateNumberOfPubkeysProcessed()
|
self.updateNumberOfPubkeysProcessed()
|
||||||
|
|
|
@ -100,6 +100,9 @@
|
||||||
<property name="sortingEnabled">
|
<property name="sortingEnabled">
|
||||||
<bool>true</bool>
|
<bool>true</bool>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="wordWrap">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
<attribute name="horizontalHeaderCascadingSectionResizes">
|
<attribute name="horizontalHeaderCascadingSectionResizes">
|
||||||
<bool>true</bool>
|
<bool>true</bool>
|
||||||
</attribute>
|
</attribute>
|
||||||
|
@ -109,9 +112,6 @@
|
||||||
<attribute name="horizontalHeaderHighlightSections">
|
<attribute name="horizontalHeaderHighlightSections">
|
||||||
<bool>false</bool>
|
<bool>false</bool>
|
||||||
</attribute>
|
</attribute>
|
||||||
<attribute name="horizontalHeaderStretchLastSection">
|
|
||||||
<bool>true</bool>
|
|
||||||
</attribute>
|
|
||||||
<attribute name="verticalHeaderVisible">
|
<attribute name="verticalHeaderVisible">
|
||||||
<bool>false</bool>
|
<bool>false</bool>
|
||||||
</attribute>
|
</attribute>
|
||||||
|
@ -296,11 +296,8 @@
|
||||||
<customwidget>
|
<customwidget>
|
||||||
<class>STableWidget</class>
|
<class>STableWidget</class>
|
||||||
<extends>QTableWidget</extends>
|
<extends>QTableWidget</extends>
|
||||||
<header>bitmessageqt/settingsmixin.h</header>
|
<header>bitmessageqt.settingsmixin</header>
|
||||||
</customwidget>
|
</customwidget>
|
||||||
</customwidgets>
|
</customwidgets>
|
||||||
<resources>
|
|
||||||
<include location="bitmessage_icons.qrc"/>
|
|
||||||
</resources>
|
|
||||||
<connections/>
|
<connections/>
|
||||||
</ui>
|
</ui>
|
||||||
|
|
|
@ -375,7 +375,7 @@ The 'Random Number' option is selected by default but deterministic addresses ha
|
||||||
<sender>radioButtonDeterministicAddress</sender>
|
<sender>radioButtonDeterministicAddress</sender>
|
||||||
<signal>toggled(bool)</signal>
|
<signal>toggled(bool)</signal>
|
||||||
<receiver>groupBoxDeterministic</receiver>
|
<receiver>groupBoxDeterministic</receiver>
|
||||||
<slot>setShown(bool)</slot>
|
<slot>setVisible(bool)</slot>
|
||||||
<hints>
|
<hints>
|
||||||
<hint type="sourcelabel">
|
<hint type="sourcelabel">
|
||||||
<x>92</x>
|
<x>92</x>
|
||||||
|
@ -391,7 +391,7 @@ The 'Random Number' option is selected by default but deterministic addresses ha
|
||||||
<sender>radioButtonRandomAddress</sender>
|
<sender>radioButtonRandomAddress</sender>
|
||||||
<signal>toggled(bool)</signal>
|
<signal>toggled(bool)</signal>
|
||||||
<receiver>groupBox</receiver>
|
<receiver>groupBox</receiver>
|
||||||
<slot>setShown(bool)</slot>
|
<slot>setVisible(bool)</slot>
|
||||||
<hints>
|
<hints>
|
||||||
<hint type="sourcelabel">
|
<hint type="sourcelabel">
|
||||||
<x>72</x>
|
<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 addresses import addBMIfNotPresent
|
||||||
from addressvalidator import AddressValidator, PassPhraseValidator
|
from .addressvalidator import AddressValidator, PassPhraseValidator
|
||||||
from queues import (
|
from queues import (
|
||||||
addressGeneratorQueue, apiAddressGeneratorReturnQueue, UISignalQueue)
|
addressGeneratorQueue, apiAddressGeneratorReturnQueue, UISignalQueue)
|
||||||
from tr import _translate
|
from tr import _translate
|
||||||
from utils import str_chan
|
from .utils import str_chan
|
||||||
|
|
||||||
|
|
||||||
class NewChanDialog(QtGui.QDialog):
|
class NewChanDialog(QtWidgets.QDialog):
|
||||||
"""The `New Chan` dialog"""
|
"""The "New Chan" dialog"""
|
||||||
def __init__(self, parent=None):
|
def __init__(self, parent=None):
|
||||||
super(NewChanDialog, self).__init__(parent)
|
super(NewChanDialog, self).__init__(parent)
|
||||||
widgets.load('newchandialog.ui', self)
|
widgets.load('newchandialog.ui', self)
|
||||||
self.parent = parent
|
self.parent = parent
|
||||||
self.chanAddress.setValidator(
|
self.chanAddress.setValidator(AddressValidator(
|
||||||
AddressValidator(
|
self.chanAddress, self.chanPassPhrase, self.validatorFeedback,
|
||||||
self.chanAddress,
|
self.buttonBox.button(QtWidgets.QDialogButtonBox.Ok), False))
|
||||||
self.chanPassPhrase,
|
self.chanPassPhrase.setValidator(PassPhraseValidator(
|
||||||
self.validatorFeedback,
|
self.chanPassPhrase, self.chanAddress, self.validatorFeedback,
|
||||||
self.buttonBox,
|
self.buttonBox.button(QtWidgets.QDialogButtonBox.Ok), False))
|
||||||
False))
|
|
||||||
self.chanPassPhrase.setValidator(
|
|
||||||
PassPhraseValidator(
|
|
||||||
self.chanPassPhrase,
|
|
||||||
self.chanAddress,
|
|
||||||
self.validatorFeedback,
|
|
||||||
self.buttonBox,
|
|
||||||
False))
|
|
||||||
|
|
||||||
self.timer = QtCore.QTimer()
|
self.timer = QtCore.QTimer()
|
||||||
QtCore.QObject.connect( # pylint: disable=no-member
|
self.timer.timeout.connect(self.delayedUpdateStatus)
|
||||||
self.timer, QtCore.SIGNAL("timeout()"), self.delayedUpdateStatus)
|
|
||||||
self.timer.start(500) # milliseconds
|
self.timer.start(500) # milliseconds
|
||||||
self.setAttribute(QtCore.Qt.WA_DeleteOnClose)
|
self.setAttribute(QtCore.Qt.WA_DeleteOnClose)
|
||||||
self.show()
|
self.show()
|
||||||
|
@ -52,32 +42,38 @@ class NewChanDialog(QtGui.QDialog):
|
||||||
self.timer.stop()
|
self.timer.stop()
|
||||||
self.hide()
|
self.hide()
|
||||||
apiAddressGeneratorReturnQueue.queue.clear()
|
apiAddressGeneratorReturnQueue.queue.clear()
|
||||||
if self.chanAddress.text().toUtf8() == "":
|
if ustr(self.chanAddress.text()) == "":
|
||||||
addressGeneratorQueue.put(
|
addressGeneratorQueue.put(
|
||||||
('createChan', 4, 1, str_chan + ' ' + str(self.chanPassPhrase.text().toUtf8()),
|
('createChan', 4, 1, str_chan + ' ' + ustr(self.chanPassPhrase.text()),
|
||||||
self.chanPassPhrase.text().toUtf8(),
|
ustr(self.chanPassPhrase.text()).encode("utf-8", "replace"),
|
||||||
True))
|
True))
|
||||||
else:
|
else:
|
||||||
addressGeneratorQueue.put(
|
addressGeneratorQueue.put(
|
||||||
('joinChan', addBMIfNotPresent(self.chanAddress.text().toUtf8()),
|
('joinChan', addBMIfNotPresent(ustr(self.chanAddress.text())),
|
||||||
str_chan + ' ' + str(self.chanPassPhrase.text().toUtf8()),
|
str_chan + ' ' + ustr(self.chanPassPhrase.text()),
|
||||||
self.chanPassPhrase.text().toUtf8(),
|
ustr(self.chanPassPhrase.text()).encode("utf-8", "replace"),
|
||||||
True))
|
True))
|
||||||
addressGeneratorReturnValue = apiAddressGeneratorReturnQueue.get(True)
|
addressGeneratorReturnValue = apiAddressGeneratorReturnQueue.get(True)
|
||||||
if addressGeneratorReturnValue and addressGeneratorReturnValue[0] != 'chan name does not match address':
|
if len(addressGeneratorReturnValue) > 0 and addressGeneratorReturnValue[0] != 'chan name does not match address':
|
||||||
UISignalQueue.put(('updateStatusBar', _translate(
|
UISignalQueue.put(('updateStatusBar', _translate(
|
||||||
"newchandialog", "Successfully created / joined chan %1").arg(unicode(self.chanPassPhrase.text()))))
|
"newchandialog", "Successfully created / joined chan {0}").format(unic(ustr(self.chanPassPhrase.text())))))
|
||||||
self.parent.ui.tabWidget.setCurrentIndex(
|
self.parent.ui.tabWidget.setCurrentIndex(
|
||||||
self.parent.ui.tabWidget.indexOf(self.parent.ui.chans)
|
self.parent.ui.tabWidget.indexOf(self.parent.ui.chans)
|
||||||
)
|
)
|
||||||
self.done(QtGui.QDialog.Accepted)
|
self.done(QtWidgets.QDialog.Accepted)
|
||||||
else:
|
else:
|
||||||
UISignalQueue.put(('updateStatusBar', _translate("newchandialog", "Chan creation / joining failed")))
|
UISignalQueue.put((
|
||||||
self.done(QtGui.QDialog.Rejected)
|
'updateStatusBar',
|
||||||
|
_translate("newchandialog", "Chan creation / joining failed")
|
||||||
|
))
|
||||||
|
self.done(QtWidgets.QDialog.Rejected)
|
||||||
|
|
||||||
def reject(self):
|
def reject(self):
|
||||||
"""Cancel joining the chan"""
|
"""Cancel joining the chan"""
|
||||||
self.timer.stop()
|
self.timer.stop()
|
||||||
self.hide()
|
self.hide()
|
||||||
UISignalQueue.put(('updateStatusBar', _translate("newchandialog", "Chan creation / joining cancelled")))
|
UISignalQueue.put((
|
||||||
self.done(QtGui.QDialog.Rejected)
|
'updateStatusBar',
|
||||||
|
_translate("newchandialog", "Chan creation / joining cancelled")
|
||||||
|
))
|
||||||
|
self.done(QtWidgets.QDialog.Rejected)
|
||||||
|
|
|
@ -1,20 +1,21 @@
|
||||||
from os import path
|
from unqstr import ustr
|
||||||
from PyQt4 import QtGui
|
import six
|
||||||
from debug import logger
|
from bitmessageqt import widgets
|
||||||
import widgets
|
from qtpy import QtWidgets
|
||||||
|
|
||||||
|
|
||||||
class RetranslateMixin(object):
|
class RetranslateMixin(object):
|
||||||
def retranslateUi(self):
|
def retranslateUi(self):
|
||||||
defaults = QtGui.QWidget()
|
defaults = QtWidgets.QWidget()
|
||||||
widgets.load(self.__class__.__name__.lower() + '.ui', defaults)
|
widgets.load(self.__class__.__name__.lower() + '.ui', defaults)
|
||||||
for attr, value in defaults.__dict__.iteritems():
|
for attr, value in six.iteritems(defaults.__dict__):
|
||||||
setTextMethod = getattr(value, "setText", None)
|
setTextMethod = getattr(value, "setText", None)
|
||||||
if callable(setTextMethod):
|
if callable(setTextMethod):
|
||||||
getattr(self, attr).setText(getattr(defaults, attr).text())
|
getattr(self, attr).setText(ustr(getattr(defaults, attr).text()))
|
||||||
elif isinstance(value, QtGui.QTableWidget):
|
elif isinstance(value, QtWidgets.QTableWidget):
|
||||||
for i in range (value.columnCount()):
|
for i in range(value.columnCount()):
|
||||||
getattr(self, attr).horizontalHeaderItem(i).setText(
|
getattr(self, attr).horizontalHeaderItem(i).setText(
|
||||||
getattr(defaults, attr).horizontalHeaderItem(i).text())
|
ustr(getattr(defaults, attr).horizontalHeaderItem(i).text()))
|
||||||
for i in range (value.rowCount()):
|
for i in range(value.rowCount()):
|
||||||
getattr(self, attr).verticalHeaderItem(i).setText(
|
getattr(self, attr).verticalHeaderItem(i).setText(
|
||||||
getattr(defaults, attr).verticalHeaderItem(i).text())
|
ustr(getattr(defaults, attr).verticalHeaderItem(i).text()))
|
||||||
|
|
|
@ -2,11 +2,11 @@
|
||||||
|
|
||||||
import inspect
|
import inspect
|
||||||
import re
|
import re
|
||||||
from HTMLParser import HTMLParser
|
from six.moves.html_parser import HTMLParser
|
||||||
|
|
||||||
from urllib import quote_plus
|
from six.moves.urllib.parse import quote_plus, urlparse
|
||||||
from urlparse import urlparse
|
|
||||||
|
|
||||||
|
from unqstr import ustr, unic
|
||||||
|
|
||||||
class SafeHTMLParser(HTMLParser):
|
class SafeHTMLParser(HTMLParser):
|
||||||
"""HTML parser with sanitisation"""
|
"""HTML parser with sanitisation"""
|
||||||
|
@ -124,9 +124,9 @@ class SafeHTMLParser(HTMLParser):
|
||||||
|
|
||||||
def feed(self, data):
|
def feed(self, data):
|
||||||
try:
|
try:
|
||||||
data = unicode(data, 'utf-8')
|
data = unic(ustr(data))
|
||||||
except UnicodeDecodeError:
|
except TypeError:
|
||||||
data = unicode(data, 'utf-8', errors='replace')
|
pass
|
||||||
HTMLParser.feed(self, data)
|
HTMLParser.feed(self, data)
|
||||||
tmp = SafeHTMLParser.replace_pre(data)
|
tmp = SafeHTMLParser.replace_pre(data)
|
||||||
tmp = self.uriregex1.sub(r'<a href="\1">\1</a>', tmp)
|
tmp = self.uriregex1.sub(r'<a href="\1">\1</a>', tmp)
|
||||||
|
|
|
@ -1,13 +1,14 @@
|
||||||
"""
|
"""
|
||||||
This module setting file is for settings
|
SettingsDialog class definition
|
||||||
"""
|
"""
|
||||||
import ConfigParser
|
from six.moves import configparser
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import tempfile
|
import tempfile
|
||||||
|
|
||||||
|
from qtpy import QtCore, QtGui, QtWidgets
|
||||||
import six
|
import six
|
||||||
from PyQt4 import QtCore, QtGui
|
from unqstr import ustr
|
||||||
|
|
||||||
import debug
|
import debug
|
||||||
import defaults
|
import defaults
|
||||||
|
@ -16,7 +17,7 @@ import openclpow
|
||||||
import paths
|
import paths
|
||||||
import queues
|
import queues
|
||||||
import state
|
import state
|
||||||
import widgets
|
from bitmessageqt import widgets
|
||||||
from bmconfigparser import config as config_obj
|
from bmconfigparser import config as config_obj
|
||||||
from helper_sql import sqlExecute, sqlStoredProcedure
|
from helper_sql import sqlExecute, sqlStoredProcedure
|
||||||
from helper_startup import start_proxyconfig
|
from helper_startup import start_proxyconfig
|
||||||
|
@ -26,12 +27,18 @@ from network.asyncore_pollchoose import set_rates
|
||||||
from tr import _translate
|
from tr import _translate
|
||||||
|
|
||||||
|
|
||||||
|
try:
|
||||||
|
SafeConfigParser = configparser.SafeConfigParser
|
||||||
|
except AttributeError:
|
||||||
|
# alpine linux, python3.12
|
||||||
|
SafeConfigParser = configparser.ConfigParser
|
||||||
|
|
||||||
def getSOCKSProxyType(config):
|
def getSOCKSProxyType(config):
|
||||||
"""Get user socksproxytype setting from *config*"""
|
"""Get user socksproxytype setting from *config*"""
|
||||||
try:
|
try:
|
||||||
result = ConfigParser.SafeConfigParser.get(
|
result = SafeConfigParser.get(
|
||||||
config, 'bitmessagesettings', 'socksproxytype')
|
config, 'bitmessagesettings', 'socksproxytype')
|
||||||
except (ConfigParser.NoSectionError, ConfigParser.NoOptionError):
|
except (configparser.NoSectionError, configparser.NoOptionError):
|
||||||
return None
|
return None
|
||||||
else:
|
else:
|
||||||
if result.lower() in ('', 'none', 'false'):
|
if result.lower() in ('', 'none', 'false'):
|
||||||
|
@ -39,14 +46,14 @@ def getSOCKSProxyType(config):
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
class SettingsDialog(QtGui.QDialog):
|
class SettingsDialog(QtWidgets.QDialog):
|
||||||
"""The "Settings" dialog"""
|
"""The "Settings" dialog"""
|
||||||
# pylint: disable=too-many-instance-attributes
|
# pylint: disable=too-many-instance-attributes
|
||||||
def __init__(self, parent=None, firstrun=False):
|
def __init__(self, parent=None, firstrun=False):
|
||||||
super(SettingsDialog, self).__init__(parent)
|
super(SettingsDialog, self).__init__(parent)
|
||||||
widgets.load('settings.ui', self)
|
widgets.load('settings.ui', self)
|
||||||
|
|
||||||
self.app = QtGui.QApplication.instance()
|
self.app = QtWidgets.QApplication.instance()
|
||||||
self.parent = parent
|
self.parent = parent
|
||||||
self.firstrun = firstrun
|
self.firstrun = firstrun
|
||||||
self.config = config_obj
|
self.config = config_obj
|
||||||
|
@ -83,14 +90,14 @@ class SettingsDialog(QtGui.QDialog):
|
||||||
self.tabWidgetSettings.setCurrentIndex(
|
self.tabWidgetSettings.setCurrentIndex(
|
||||||
self.tabWidgetSettings.indexOf(self.tabNetworkSettings)
|
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):
|
def adjust_from_config(self, config):
|
||||||
"""Adjust all widgets state according to config settings"""
|
"""Adjust all widgets state according to config settings"""
|
||||||
# pylint: disable=too-many-branches,too-many-statements
|
# pylint: disable=too-many-branches,too-many-statements
|
||||||
|
|
||||||
current_style = self.app.get_windowstyle()
|
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)
|
self.comboBoxStyle.addItem(sk)
|
||||||
if sk == current_style:
|
if sk == current_style:
|
||||||
self.comboBoxStyle.setCurrentIndex(i)
|
self.comboBoxStyle.setCurrentIndex(i)
|
||||||
|
@ -187,7 +194,7 @@ class SettingsDialog(QtGui.QDialog):
|
||||||
else:
|
else:
|
||||||
if self.checkBoxOnionOnly.isChecked():
|
if self.checkBoxOnionOnly.isChecked():
|
||||||
self.checkBoxOnionOnly.setText(
|
self.checkBoxOnionOnly.setText(
|
||||||
self.checkBoxOnionOnly.text() + ", " + _translate(
|
ustr(self.checkBoxOnionOnly.text()) + ", " + _translate(
|
||||||
"MainWindow", "may cause connection problems!"))
|
"MainWindow", "may cause connection problems!"))
|
||||||
self.checkBoxOnionOnly.setStyleSheet(
|
self.checkBoxOnionOnly.setStyleSheet(
|
||||||
"QCheckBox { color : red; }")
|
"QCheckBox { color : red; }")
|
||||||
|
@ -324,10 +331,10 @@ class SettingsDialog(QtGui.QDialog):
|
||||||
_translate("MainWindow", "Testing..."))
|
_translate("MainWindow", "Testing..."))
|
||||||
nc = namecoin.namecoinConnection({
|
nc = namecoin.namecoinConnection({
|
||||||
'type': self.getNamecoinType(),
|
'type': self.getNamecoinType(),
|
||||||
'host': str(self.lineEditNamecoinHost.text().toUtf8()),
|
'host': ustr(self.lineEditNamecoinHost.text()),
|
||||||
'port': str(self.lineEditNamecoinPort.text().toUtf8()),
|
'port': ustr(self.lineEditNamecoinPort.text()),
|
||||||
'user': str(self.lineEditNamecoinUser.text().toUtf8()),
|
'user': ustr(self.lineEditNamecoinUser.text()),
|
||||||
'password': str(self.lineEditNamecoinPassword.text().toUtf8())
|
'password': ustr(self.lineEditNamecoinPassword.text())
|
||||||
})
|
})
|
||||||
status, text = nc.test()
|
status, text = nc.test()
|
||||||
self.labelNamecoinTestResult.setText(text)
|
self.labelNamecoinTestResult.setText(text)
|
||||||
|
@ -342,7 +349,7 @@ class SettingsDialog(QtGui.QDialog):
|
||||||
|
|
||||||
def choose_font(self):
|
def choose_font(self):
|
||||||
"""Show the font selection dialog"""
|
"""Show the font selection dialog"""
|
||||||
font, valid = QtGui.QFontDialog.getFont()
|
font, valid = QtWidgets.QFontDialog.getFont()
|
||||||
if valid:
|
if valid:
|
||||||
self.save_font_setting(font)
|
self.save_font_setting(font)
|
||||||
|
|
||||||
|
@ -372,7 +379,7 @@ class SettingsDialog(QtGui.QDialog):
|
||||||
self.config.set('bitmessagesettings', 'replybelow', str(
|
self.config.set('bitmessagesettings', 'replybelow', str(
|
||||||
self.checkBoxReplyBelow.isChecked()))
|
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(
|
if self.app.get_windowstyle() != window_style or self.config.safeGet(
|
||||||
'bitmessagesettings', 'font'
|
'bitmessagesettings', 'font'
|
||||||
) != self.font_setting:
|
) != self.font_setting:
|
||||||
|
@ -386,8 +393,8 @@ class SettingsDialog(QtGui.QDialog):
|
||||||
" the window style or default font."), 1)
|
" the window style or default font."), 1)
|
||||||
))
|
))
|
||||||
|
|
||||||
lang = str(self.languageComboBox.itemData(
|
lang = ustr(self.languageComboBox.itemData(
|
||||||
self.languageComboBox.currentIndex()).toString())
|
self.languageComboBox.currentIndex()))
|
||||||
self.config.set('bitmessagesettings', 'userlocale', lang)
|
self.config.set('bitmessagesettings', 'userlocale', lang)
|
||||||
self.parent.change_translation()
|
self.parent.change_translation()
|
||||||
|
|
||||||
|
@ -469,7 +476,7 @@ class SettingsDialog(QtGui.QDialog):
|
||||||
self.config.set('bitmessagesettings', 'maxuploadrate', str(
|
self.config.set('bitmessagesettings', 'maxuploadrate', str(
|
||||||
int(float(self.lineEditMaxUploadRate.text()))))
|
int(float(self.lineEditMaxUploadRate.text()))))
|
||||||
except ValueError:
|
except ValueError:
|
||||||
QtGui.QMessageBox.about(
|
QtWidgets.QMessageBox.about(
|
||||||
self, _translate("MainWindow", "Number needed"),
|
self, _translate("MainWindow", "Number needed"),
|
||||||
_translate(
|
_translate(
|
||||||
"MainWindow",
|
"MainWindow",
|
||||||
|
@ -486,13 +493,13 @@ class SettingsDialog(QtGui.QDialog):
|
||||||
|
|
||||||
self.config.set(
|
self.config.set(
|
||||||
'bitmessagesettings', 'namecoinrpctype', self.getNamecoinType())
|
'bitmessagesettings', 'namecoinrpctype', self.getNamecoinType())
|
||||||
self.config.set('bitmessagesettings', 'namecoinrpchost', str(
|
self.config.set('bitmessagesettings', 'namecoinrpchost', ustr(
|
||||||
self.lineEditNamecoinHost.text()))
|
self.lineEditNamecoinHost.text()))
|
||||||
self.config.set('bitmessagesettings', 'namecoinrpcport', str(
|
self.config.set('bitmessagesettings', 'namecoinrpcport', ustr(
|
||||||
self.lineEditNamecoinPort.text()))
|
self.lineEditNamecoinPort.text()))
|
||||||
self.config.set('bitmessagesettings', 'namecoinrpcuser', str(
|
self.config.set('bitmessagesettings', 'namecoinrpcuser', ustr(
|
||||||
self.lineEditNamecoinUser.text()))
|
self.lineEditNamecoinUser.text()))
|
||||||
self.config.set('bitmessagesettings', 'namecoinrpcpassword', str(
|
self.config.set('bitmessagesettings', 'namecoinrpcpassword', ustr(
|
||||||
self.lineEditNamecoinPassword.text()))
|
self.lineEditNamecoinPassword.text()))
|
||||||
self.parent.resetNamecoinConnection()
|
self.parent.resetNamecoinConnection()
|
||||||
|
|
||||||
|
@ -510,11 +517,11 @@ class SettingsDialog(QtGui.QDialog):
|
||||||
float(self.lineEditSmallMessageDifficulty.text())
|
float(self.lineEditSmallMessageDifficulty.text())
|
||||||
* defaults.networkDefaultPayloadLengthExtraBytes)))
|
* defaults.networkDefaultPayloadLengthExtraBytes)))
|
||||||
|
|
||||||
if self.comboBoxOpenCL.currentText().toUtf8() != self.config.safeGet(
|
if ustr(self.comboBoxOpenCL.currentText()) != ustr(self.config.safeGet(
|
||||||
'bitmessagesettings', 'opencl'):
|
'bitmessagesettings', 'opencl')):
|
||||||
self.config.set(
|
self.config.set(
|
||||||
'bitmessagesettings', 'opencl',
|
'bitmessagesettings', 'opencl',
|
||||||
str(self.comboBoxOpenCL.currentText()))
|
ustr(self.comboBoxOpenCL.currentText()))
|
||||||
queues.workerQueue.put(('resetPoW', ''))
|
queues.workerQueue.put(('resetPoW', ''))
|
||||||
|
|
||||||
acceptableDifficultyChanged = False
|
acceptableDifficultyChanged = False
|
||||||
|
@ -524,7 +531,7 @@ class SettingsDialog(QtGui.QDialog):
|
||||||
or float(self.lineEditMaxAcceptableTotalDifficulty.text()) == 0
|
or float(self.lineEditMaxAcceptableTotalDifficulty.text()) == 0
|
||||||
):
|
):
|
||||||
if self.config.get(
|
if self.config.get(
|
||||||
'bitmessagesettings', 'maxacceptablenoncetrialsperbyte'
|
'bitmessagesettings', 'maxacceptablenoncetrialsperbyte'
|
||||||
) != str(int(
|
) != str(int(
|
||||||
float(self.lineEditMaxAcceptableTotalDifficulty.text())
|
float(self.lineEditMaxAcceptableTotalDifficulty.text())
|
||||||
* defaults.networkDefaultProofOfWorkNonceTrialsPerByte)):
|
* defaults.networkDefaultProofOfWorkNonceTrialsPerByte)):
|
||||||
|
@ -541,7 +548,7 @@ class SettingsDialog(QtGui.QDialog):
|
||||||
or float(self.lineEditMaxAcceptableSmallMessageDifficulty.text()) == 0
|
or float(self.lineEditMaxAcceptableSmallMessageDifficulty.text()) == 0
|
||||||
):
|
):
|
||||||
if self.config.get(
|
if self.config.get(
|
||||||
'bitmessagesettings', 'maxacceptablepayloadlengthextrabytes'
|
'bitmessagesettings', 'maxacceptablepayloadlengthextrabytes'
|
||||||
) != str(int(
|
) != str(int(
|
||||||
float(self.lineEditMaxAcceptableSmallMessageDifficulty.text())
|
float(self.lineEditMaxAcceptableSmallMessageDifficulty.text())
|
||||||
* defaults.networkDefaultPayloadLengthExtraBytes)):
|
* defaults.networkDefaultPayloadLengthExtraBytes)):
|
||||||
|
@ -593,7 +600,7 @@ class SettingsDialog(QtGui.QDialog):
|
||||||
if state.maximumLengthOfTimeToBotherResendingMessages < 432000:
|
if state.maximumLengthOfTimeToBotherResendingMessages < 432000:
|
||||||
# If the time period is less than 5 hours, we give
|
# If the time period is less than 5 hours, we give
|
||||||
# zero values to all fields. No message will be sent again.
|
# zero values to all fields. No message will be sent again.
|
||||||
QtGui.QMessageBox.about(
|
QtWidgets.QMessageBox.about(
|
||||||
self,
|
self,
|
||||||
_translate("MainWindow", "Will not resend ever"),
|
_translate("MainWindow", "Will not resend ever"),
|
||||||
_translate(
|
_translate(
|
||||||
|
|
|
@ -1112,9 +1112,6 @@
|
||||||
<tabstop>checkBoxSocksListen</tabstop>
|
<tabstop>checkBoxSocksListen</tabstop>
|
||||||
<tabstop>buttonBox</tabstop>
|
<tabstop>buttonBox</tabstop>
|
||||||
</tabstops>
|
</tabstops>
|
||||||
<resources>
|
|
||||||
<include location="bitmessage_icons.qrc"/>
|
|
||||||
</resources>
|
|
||||||
<connections>
|
<connections>
|
||||||
<connection>
|
<connection>
|
||||||
<sender>buttonBox</sender>
|
<sender>buttonBox</sender>
|
||||||
|
|
|
@ -1,15 +1,16 @@
|
||||||
#!/usr/bin/python2.7
|
|
||||||
"""
|
"""
|
||||||
src/settingsmixin.py
|
src/settingsmixin.py
|
||||||
====================
|
====================
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from PyQt4 import QtCore, QtGui
|
from unqstr import ustr
|
||||||
|
from qtpy import QtCore, QtWidgets
|
||||||
|
|
||||||
|
|
||||||
class SettingsMixin(object):
|
class SettingsMixin(object):
|
||||||
"""Mixin for adding geometry and state saving between restarts."""
|
"""Mixin for adding geometry and state saving between restarts"""
|
||||||
|
|
||||||
def warnIfNoObjectName(self):
|
def warnIfNoObjectName(self):
|
||||||
"""
|
"""
|
||||||
Handle objects which don't have a name. Currently it ignores them. Objects without a name can't have their
|
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()
|
self.warnIfNoObjectName()
|
||||||
settings = QtCore.QSettings()
|
settings = QtCore.QSettings()
|
||||||
try:
|
try:
|
||||||
geom = settings.value("/".join([str(self.objectName()), "geometry"]))
|
geom = settings.value(
|
||||||
target.restoreGeometry(geom.toByteArray() if hasattr(geom, 'toByteArray') else geom)
|
"/".join([ustr(self.objectName()), "geometry"]))
|
||||||
|
target.restoreGeometry(geom)
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -50,14 +52,15 @@ class SettingsMixin(object):
|
||||||
self.warnIfNoObjectName()
|
self.warnIfNoObjectName()
|
||||||
settings = QtCore.QSettings()
|
settings = QtCore.QSettings()
|
||||||
try:
|
try:
|
||||||
state = settings.value("/".join([str(self.objectName()), "state"]))
|
state = settings.value("/".join([ustr(self.objectName()), "state"]))
|
||||||
target.restoreState(state.toByteArray() if hasattr(state, 'toByteArray') else state)
|
target.restoreState(state)
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class SMainWindow(QtGui.QMainWindow, SettingsMixin):
|
class SMainWindow(QtWidgets.QMainWindow, SettingsMixin):
|
||||||
"""Main window with Settings functionality."""
|
"""Main window with Settings functionality"""
|
||||||
|
|
||||||
def loadSettings(self):
|
def loadSettings(self):
|
||||||
"""Load main window settings."""
|
"""Load main window settings."""
|
||||||
self.readGeometry(self)
|
self.readGeometry(self)
|
||||||
|
@ -69,9 +72,9 @@ class SMainWindow(QtGui.QMainWindow, SettingsMixin):
|
||||||
self.writeGeometry(self)
|
self.writeGeometry(self)
|
||||||
|
|
||||||
|
|
||||||
class STableWidget(QtGui.QTableWidget, SettingsMixin):
|
class STableWidget(QtWidgets.QTableWidget, SettingsMixin):
|
||||||
"""Table widget with Settings functionality"""
|
"""Table widget with Settings functionality"""
|
||||||
# pylint: disable=too-many-ancestors
|
|
||||||
def loadSettings(self):
|
def loadSettings(self):
|
||||||
"""Load table settings."""
|
"""Load table settings."""
|
||||||
self.readState(self.horizontalHeader())
|
self.readState(self.horizontalHeader())
|
||||||
|
@ -81,8 +84,9 @@ class STableWidget(QtGui.QTableWidget, SettingsMixin):
|
||||||
self.writeState(self.horizontalHeader())
|
self.writeState(self.horizontalHeader())
|
||||||
|
|
||||||
|
|
||||||
class SSplitter(QtGui.QSplitter, SettingsMixin):
|
class SSplitter(QtWidgets.QSplitter, SettingsMixin):
|
||||||
"""Splitter with Settings functionality."""
|
"""Splitter with Settings functionality"""
|
||||||
|
|
||||||
def loadSettings(self):
|
def loadSettings(self):
|
||||||
"""Load splitter settings"""
|
"""Load splitter settings"""
|
||||||
self.readState(self)
|
self.readState(self)
|
||||||
|
@ -92,17 +96,17 @@ class SSplitter(QtGui.QSplitter, SettingsMixin):
|
||||||
self.writeState(self)
|
self.writeState(self)
|
||||||
|
|
||||||
|
|
||||||
class STreeWidget(QtGui.QTreeWidget, SettingsMixin):
|
class STreeWidget(QtWidgets.QTreeWidget, SettingsMixin):
|
||||||
"""Tree widget with settings functionality."""
|
"""Tree widget with settings functionality"""
|
||||||
# pylint: disable=too-many-ancestors
|
|
||||||
def loadSettings(self):
|
def loadSettings(self):
|
||||||
"""Load tree settings."""
|
"""Load tree settings. Unimplemented."""
|
||||||
# recurse children
|
# recurse children
|
||||||
# self.readState(self)
|
# self.readState(self)
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def saveSettings(self):
|
def saveSettings(self):
|
||||||
"""Save tree settings"""
|
"""Save tree settings. Unimplemented."""
|
||||||
# recurse children
|
# recurse children
|
||||||
# self.writeState(self)
|
# self.writeState(self)
|
||||||
pass
|
pass
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
# pylint: disable=unused-argument
|
"""BMStatusBar class definition"""
|
||||||
"""Status bar Module"""
|
|
||||||
|
|
||||||
from time import time
|
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"""
|
"""Status bar with queue and priorities"""
|
||||||
duration = 10000
|
duration = 10000
|
||||||
deleteAfter = 60
|
deleteAfter = 60
|
||||||
|
@ -16,21 +16,24 @@ class BMStatusBar(QtGui.QStatusBar):
|
||||||
self.timer = self.startTimer(BMStatusBar.duration)
|
self.timer = self.startTimer(BMStatusBar.duration)
|
||||||
self.iterator = 0
|
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
|
"""an event handler which allows to queue and prioritise messages to
|
||||||
show in the status bar, for example if many messages come very quickly
|
show in the status bar, for example if many messages come very quickly
|
||||||
after one another, it adds delays and so on"""
|
after one another, it adds delays and so on"""
|
||||||
while len(self.important) > 0:
|
while len(self.important) > 0:
|
||||||
self.iterator += 1
|
self.iterator += 1
|
||||||
try:
|
try:
|
||||||
if time() > self.important[self.iterator][1] + BMStatusBar.deleteAfter:
|
if (
|
||||||
|
self.important[self.iterator][1]
|
||||||
|
+ BMStatusBar.deleteAfter < time()
|
||||||
|
):
|
||||||
del self.important[self.iterator]
|
del self.important[self.iterator]
|
||||||
self.iterator -= 1
|
self.iterator -= 1
|
||||||
continue
|
continue
|
||||||
except IndexError:
|
except IndexError:
|
||||||
self.iterator = -1
|
self.iterator = -1
|
||||||
continue
|
continue
|
||||||
super(BMStatusBar, self).showMessage(self.important[self.iterator][0], 0)
|
self.showMessage(self.important[self.iterator][0], 0)
|
||||||
break
|
break
|
||||||
|
|
||||||
def addImportant(self, message):
|
def addImportant(self, message):
|
||||||
|
|
|
@ -1,14 +1,15 @@
|
||||||
"""Composing support request message functions."""
|
"""Composing support request message functions."""
|
||||||
# pylint: disable=no-member
|
|
||||||
|
|
||||||
import ctypes
|
import ctypes
|
||||||
|
import os
|
||||||
import ssl
|
import ssl
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
|
|
||||||
from PyQt4 import QtCore
|
from unqstr import ustr, unic
|
||||||
|
from dbcompat import dbstr
|
||||||
|
|
||||||
import account
|
from bitmessageqt import account
|
||||||
import defaults
|
import defaults
|
||||||
import network.stats
|
import network.stats
|
||||||
import paths
|
import paths
|
||||||
|
@ -16,12 +17,12 @@ import proofofwork
|
||||||
import queues
|
import queues
|
||||||
import state
|
import state
|
||||||
from bmconfigparser import config
|
from bmconfigparser import config
|
||||||
from foldertree import AccountMixin
|
from .foldertree import AccountMixin
|
||||||
from helper_sql import sqlExecute, sqlQuery
|
from helper_sql import sqlExecute, sqlQuery
|
||||||
from l10n import getTranslationLanguage
|
from l10n import getTranslationLanguage
|
||||||
from openclpow import openclEnabled
|
from openclpow import openclEnabled
|
||||||
from pyelliptic.openssl import OpenSSL
|
from pyelliptic.openssl import OpenSSL
|
||||||
from settings import getSOCKSProxyType
|
from .settings import getSOCKSProxyType
|
||||||
from version import softwareVersion
|
from version import softwareVersion
|
||||||
from tr import _translate
|
from tr import _translate
|
||||||
|
|
||||||
|
@ -31,7 +32,7 @@ OLD_SUPPORT_ADDRESS = 'BM-2cTkCtMYkrSPwFTpgcBrMrf5d8oZwvMZWK'
|
||||||
SUPPORT_ADDRESS = 'BM-2cUdgkDDAahwPAU6oD2A7DnjqZz3hgY832'
|
SUPPORT_ADDRESS = 'BM-2cUdgkDDAahwPAU6oD2A7DnjqZz3hgY832'
|
||||||
SUPPORT_LABEL = _translate("Support", "PyBitmessage support")
|
SUPPORT_LABEL = _translate("Support", "PyBitmessage support")
|
||||||
SUPPORT_MY_LABEL = _translate("Support", "My new address")
|
SUPPORT_MY_LABEL = _translate("Support", "My new address")
|
||||||
SUPPORT_SUBJECT = 'Support request'
|
SUPPORT_SUBJECT = _translate("Support", "Support request")
|
||||||
SUPPORT_MESSAGE = _translate("Support", '''
|
SUPPORT_MESSAGE = _translate("Support", '''
|
||||||
You can use this message to send a report to one of the PyBitmessage core \
|
You can use this message to send a report to one of the PyBitmessage core \
|
||||||
developers regarding PyBitmessage or the mailchuck.com email service. \
|
developers regarding PyBitmessage or the mailchuck.com email service. \
|
||||||
|
@ -55,6 +56,7 @@ Operating system: {}
|
||||||
Architecture: {}bit
|
Architecture: {}bit
|
||||||
Python Version: {}
|
Python Version: {}
|
||||||
OpenSSL Version: {}
|
OpenSSL Version: {}
|
||||||
|
Qt API: {}
|
||||||
Frozen: {}
|
Frozen: {}
|
||||||
Portable mode: {}
|
Portable mode: {}
|
||||||
C PoW: {}
|
C PoW: {}
|
||||||
|
@ -67,28 +69,35 @@ Connected hosts: {}
|
||||||
|
|
||||||
|
|
||||||
def checkAddressBook(myapp):
|
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 == []:
|
if queryreturn == []:
|
||||||
sqlExecute(
|
sqlExecute(
|
||||||
'INSERT INTO addressbook VALUES (?,?)',
|
'INSERT INTO addressbook VALUES (?,?)',
|
||||||
SUPPORT_LABEL.toUtf8(), SUPPORT_ADDRESS)
|
dbstr(SUPPORT_LABEL), dbstr(SUPPORT_ADDRESS))
|
||||||
myapp.rerenderAddressBook()
|
myapp.rerenderAddressBook()
|
||||||
|
|
||||||
|
|
||||||
def checkHasNormalAddress():
|
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)
|
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 address
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def createAddressIfNeeded(myapp):
|
def createAddressIfNeeded(myapp):
|
||||||
|
"""Checks if user has any anabled normal address, creates new one if no."""
|
||||||
if not checkHasNormalAddress():
|
if not checkHasNormalAddress():
|
||||||
queues.addressGeneratorQueue.put((
|
queues.addressGeneratorQueue.put((
|
||||||
'createRandomAddress', 4, 1,
|
'createRandomAddress', 4, 1,
|
||||||
str(SUPPORT_MY_LABEL.toUtf8()),
|
ustr(SUPPORT_MY_LABEL),
|
||||||
1, "", False,
|
1, "", False,
|
||||||
defaults.networkDefaultProofOfWorkNonceTrialsPerByte,
|
defaults.networkDefaultProofOfWorkNonceTrialsPerByte,
|
||||||
defaults.networkDefaultPayloadLengthExtraBytes
|
defaults.networkDefaultPayloadLengthExtraBytes
|
||||||
|
@ -100,15 +109,20 @@ def createAddressIfNeeded(myapp):
|
||||||
|
|
||||||
|
|
||||||
def createSupportMessage(myapp):
|
def createSupportMessage(myapp):
|
||||||
|
"""
|
||||||
|
Prepare the support request message and switch to tab "Send"
|
||||||
|
"""
|
||||||
checkAddressBook(myapp)
|
checkAddressBook(myapp)
|
||||||
address = createAddressIfNeeded(myapp)
|
address = createAddressIfNeeded(myapp)
|
||||||
if state.shutdown:
|
if state.shutdown:
|
||||||
return
|
return
|
||||||
|
|
||||||
myapp.ui.lineEditSubject.setText(SUPPORT_SUBJECT)
|
myapp.ui.lineEditSubject.setText(SUPPORT_SUBJECT)
|
||||||
addrIndex = myapp.ui.comboBoxSendFrom.findData(
|
# addrIndex = myapp.ui.comboBoxSendFrom.findData(
|
||||||
address, QtCore.Qt.UserRole,
|
# address, QtCore.Qt.UserRole,
|
||||||
QtCore.Qt.MatchFixedString | QtCore.Qt.MatchCaseSensitive)
|
# QtCore.Qt.MatchFixedString | QtCore.Qt.MatchCaseSensitive
|
||||||
|
# )
|
||||||
|
addrIndex = myapp.ui.comboBoxSendFrom.findData(address)
|
||||||
if addrIndex == -1: # something is very wrong
|
if addrIndex == -1: # something is very wrong
|
||||||
return
|
return
|
||||||
myapp.ui.comboBoxSendFrom.setCurrentIndex(addrIndex)
|
myapp.ui.comboBoxSendFrom.setCurrentIndex(addrIndex)
|
||||||
|
@ -119,15 +133,13 @@ def createSupportMessage(myapp):
|
||||||
if commit:
|
if commit:
|
||||||
version += " GIT " + commit
|
version += " GIT " + commit
|
||||||
|
|
||||||
os = sys.platform
|
if sys.platform.startswith("win"):
|
||||||
if os == "win32":
|
# pylint: disable=no-member
|
||||||
windowsversion = sys.getwindowsversion()
|
osname = "Windows %s.%s" % sys.getwindowsversion()[:2]
|
||||||
os = "Windows " + str(windowsversion[0]) + "." + str(windowsversion[1])
|
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
from os import uname
|
unixversion = os.uname()
|
||||||
unixversion = uname()
|
osname = unixversion[0] + " " + unixversion[2]
|
||||||
os = unixversion[0] + " " + unixversion[2]
|
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
architecture = "32" if ctypes.sizeof(ctypes.c_voidp) == 4 else "64"
|
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)" % (
|
opensslversion = "%s (Python internal), %s (external for PyElliptic)" % (
|
||||||
ssl.OPENSSL_VERSION, OpenSSL._version)
|
ssl.OPENSSL_VERSION, OpenSSL._version)
|
||||||
|
|
||||||
|
qtapi = os.environ.get('QT_API', 'fallback')
|
||||||
|
|
||||||
frozen = "N/A"
|
frozen = "N/A"
|
||||||
if paths.frozen:
|
if paths.frozen:
|
||||||
frozen = 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"
|
cpow = "True" if proofofwork.bmpow else "False"
|
||||||
openclpow = str(
|
openclpow = ustr(
|
||||||
config.safeGet('bitmessagesettings', 'opencl')
|
config.safeGet('bitmessagesettings', 'opencl')
|
||||||
) if openclEnabled() else "None"
|
) if openclEnabled() else "None"
|
||||||
locale = getTranslationLanguage()
|
locale = getTranslationLanguage()
|
||||||
socks = getSOCKSProxyType(config) or "N/A"
|
socks = getSOCKSProxyType(config) or 'N/A'
|
||||||
upnp = config.safeGet('bitmessagesettings', 'upnp', "N/A")
|
upnp = config.safeGet('bitmessagesettings', 'upnp', 'N/A')
|
||||||
connectedhosts = len(network.stats.connectedHostsList())
|
connectedhosts = len(network.stats.connectedHostsList())
|
||||||
|
|
||||||
myapp.ui.textEditMessage.setText(unicode(SUPPORT_MESSAGE, 'utf-8').format(
|
myapp.ui.textEditMessage.setText(unic(ustr(SUPPORT_MESSAGE).format(
|
||||||
version, os, architecture, pythonversion, opensslversion, frozen,
|
version, osname, architecture, pythonversion, opensslversion, qtapi,
|
||||||
portablemode, cpow, openclpow, locale, socks, upnp, connectedhosts))
|
frozen, portablemode, cpow, openclpow, locale, socks, upnp,
|
||||||
|
connectedhosts
|
||||||
|
)))
|
||||||
|
|
||||||
# single msg tab
|
# single msg tab
|
||||||
myapp.ui.tabWidgetSend.setCurrentIndex(
|
myapp.ui.tabWidgetSend.setCurrentIndex(
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import helper_addressbook
|
import helper_addressbook
|
||||||
from bitmessageqt.support import createAddressIfNeeded
|
from bitmessageqt.support import createAddressIfNeeded
|
||||||
|
|
||||||
from main import TestBase
|
from .main import TestBase
|
||||||
|
|
||||||
|
|
||||||
class TestAddressbook(TestBase):
|
class TestAddressbook(TestBase):
|
||||||
|
|
|
@ -3,7 +3,8 @@
|
||||||
import sys
|
import sys
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
from PyQt4 import QtCore, QtGui
|
from qtpy import QtCore, QtWidgets
|
||||||
|
from six import string_types
|
||||||
from six.moves import queue
|
from six.moves import queue
|
||||||
|
|
||||||
import bitmessageqt
|
import bitmessageqt
|
||||||
|
@ -20,7 +21,7 @@ class TestBase(unittest.TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.app = (
|
self.app = (
|
||||||
QtGui.QApplication.instance()
|
QtWidgets.QApplication.instance()
|
||||||
or bitmessageqt.BitmessageQtApplication(sys.argv))
|
or bitmessageqt.BitmessageQtApplication(sys.argv))
|
||||||
self.window = self.app.activeWindow()
|
self.window = self.app.activeWindow()
|
||||||
if not self.window:
|
if not self.window:
|
||||||
|
@ -50,10 +51,7 @@ class TestMain(unittest.TestCase):
|
||||||
|
|
||||||
def test_translate(self):
|
def test_translate(self):
|
||||||
"""Check the results of _translate() with various args"""
|
"""Check the results of _translate() with various args"""
|
||||||
self.assertIsInstance(
|
self.assertIsInstance(_translate("MainWindow", "Test"), string_types)
|
||||||
_translate("MainWindow", "Test"),
|
|
||||||
QtCore.QString
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class TestUISignaler(TestBase):
|
class TestUISignaler(TestBase):
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
|
|
||||||
from PyQt4 import QtCore, QtGui, QtTest
|
from qtpy import QtCore, QtWidgets, QtTest
|
||||||
|
|
||||||
from bmconfigparser import config
|
from bmconfigparser import config
|
||||||
from bitmessageqt import settings
|
from bitmessageqt import settings
|
||||||
|
@ -48,8 +48,8 @@ class TestSettings(TestBase):
|
||||||
|
|
||||||
def call_font_dialog():
|
def call_font_dialog():
|
||||||
"""A function to get the open font dialog and accept it"""
|
"""A function to get the open font dialog and accept it"""
|
||||||
font_dialog = QtGui.QApplication.activeModalWidget()
|
font_dialog = QtWidgets.QApplication.activeModalWidget()
|
||||||
self.assertTrue(isinstance(font_dialog, QtGui.QFontDialog))
|
self.assertTrue(isinstance(font_dialog, QtWidgets.QFontDialog))
|
||||||
selected_font = font_dialog.currentFont()
|
selected_font = font_dialog.currentFont()
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
config.safeGet('bitmessagesettings', 'font'), '{},{}'.format(
|
config.safeGet('bitmessagesettings', 'font'), '{},{}'.format(
|
||||||
|
@ -64,7 +64,7 @@ class TestSettings(TestBase):
|
||||||
def click_font_button():
|
def click_font_button():
|
||||||
"""Use QtTest to click the button"""
|
"""Use QtTest to click the button"""
|
||||||
QtTest.QTest.mouseClick(
|
QtTest.QTest.mouseClick(
|
||||||
self.dialog.buttonFont, QtCore.Qt.LeftButton)
|
self.dialog.buttonFont, QtCore.Qt.MouseButton.LeftButton)
|
||||||
|
|
||||||
style_count = style_control.count()
|
style_count = style_control.count()
|
||||||
self.assertGreater(style_count, 1)
|
self.assertGreater(style_count, 1)
|
||||||
|
|
|
@ -4,7 +4,9 @@ import sys
|
||||||
|
|
||||||
from shared import isAddressInMyAddressBook
|
from shared import isAddressInMyAddressBook
|
||||||
|
|
||||||
from main import TestBase
|
from .main import TestBase
|
||||||
|
|
||||||
|
from unqstr import ustr
|
||||||
|
|
||||||
|
|
||||||
class TestSupport(TestBase):
|
class TestSupport(TestBase):
|
||||||
|
@ -26,8 +28,8 @@ class TestSupport(TestBase):
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
ui.tabWidget.currentIndex(), ui.tabWidget.indexOf(ui.send))
|
ui.tabWidget.currentIndex(), ui.tabWidget.indexOf(ui.send))
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
ui.lineEditTo.text(), self.SUPPORT_ADDRESS)
|
ustr(ui.lineEditTo.text()), ustr(self.SUPPORT_ADDRESS))
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
ui.lineEditSubject.text(), self.SUPPORT_SUBJECT)
|
ustr(ui.lineEditSubject.text()), ustr(self.SUPPORT_SUBJECT))
|
||||||
self.assertIn(
|
self.assertIn(
|
||||||
sys.version, ui.textEditMessage.toPlainText())
|
sys.version, ui.textEditMessage.toPlainText())
|
||||||
|
|
|
@ -1,15 +1,35 @@
|
||||||
|
|
||||||
from PyQt4.QtCore import QThread, SIGNAL
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
from qtpy import QtCore
|
||||||
|
|
||||||
import queues
|
import queues
|
||||||
|
from network.node import Peer
|
||||||
|
|
||||||
|
|
||||||
class UISignaler(QThread):
|
class UISignaler(QtCore.QThread):
|
||||||
_instance = None
|
_instance = None
|
||||||
|
|
||||||
def __init__(self, parent=None):
|
writeNewAddressToTable = QtCore.Signal(str, str, str)
|
||||||
QThread.__init__(self, parent)
|
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
|
@classmethod
|
||||||
def get(cls):
|
def get(cls):
|
||||||
|
@ -22,69 +42,59 @@ class UISignaler(QThread):
|
||||||
command, data = queues.UISignalQueue.get()
|
command, data = queues.UISignalQueue.get()
|
||||||
if command == 'writeNewAddressToTable':
|
if command == 'writeNewAddressToTable':
|
||||||
label, address, streamNumber = data
|
label, address, streamNumber = data
|
||||||
self.emit(
|
self.writeNewAddressToTable.emit(
|
||||||
SIGNAL("writeNewAddressToTable(PyQt_PyObject,PyQt_PyObject,PyQt_PyObject)"),
|
label, address, str(streamNumber))
|
||||||
label,
|
|
||||||
address,
|
|
||||||
str(streamNumber))
|
|
||||||
elif command == 'updateStatusBar':
|
elif command == 'updateStatusBar':
|
||||||
self.emit(SIGNAL("updateStatusBar(PyQt_PyObject)"), data)
|
self.updateStatusBar.emit(data)
|
||||||
elif command == 'updateSentItemStatusByToAddress':
|
elif command == 'updateSentItemStatusByToAddress':
|
||||||
toAddress, message = data
|
toAddress, message = data
|
||||||
self.emit(SIGNAL(
|
self.updateSentItemStatusByToAddress.emit(toAddress, message)
|
||||||
"updateSentItemStatusByToAddress(PyQt_PyObject,PyQt_PyObject)"), toAddress, message)
|
|
||||||
elif command == 'updateSentItemStatusByAckdata':
|
elif command == 'updateSentItemStatusByAckdata':
|
||||||
ackData, message = data
|
ackData, message = data
|
||||||
self.emit(SIGNAL(
|
self.updateSentItemStatusByAckdata.emit(ackData, message)
|
||||||
"updateSentItemStatusByAckdata(PyQt_PyObject,PyQt_PyObject)"), ackData, message)
|
|
||||||
elif command == 'displayNewInboxMessage':
|
elif command == 'displayNewInboxMessage':
|
||||||
inventoryHash, toAddress, fromAddress, subject, body = data
|
inventoryHash, toAddress, fromAddress, subject, body = data
|
||||||
self.emit(SIGNAL(
|
|
||||||
"displayNewInboxMessage(PyQt_PyObject,PyQt_PyObject,PyQt_PyObject,PyQt_PyObject,PyQt_PyObject)"),
|
self.displayNewInboxMessage.emit(
|
||||||
inventoryHash, toAddress, fromAddress, subject, body)
|
inventoryHash, toAddress, fromAddress,
|
||||||
|
subject, body)
|
||||||
elif command == 'displayNewSentMessage':
|
elif command == 'displayNewSentMessage':
|
||||||
toAddress, fromLabel, fromAddress, subject, message, ackdata = data
|
toAddress, fromLabel, fromAddress, subject, message, ackdata = data
|
||||||
self.emit(SIGNAL(
|
self.displayNewSentMessage.emit(
|
||||||
"displayNewSentMessage(PyQt_PyObject,PyQt_PyObject,PyQt_PyObject,PyQt_PyObject,PyQt_PyObject,PyQt_PyObject)"),
|
toAddress, fromLabel, fromAddress,
|
||||||
toAddress, fromLabel, fromAddress, subject, message, ackdata)
|
subject.decode('utf-8'), message, ackdata)
|
||||||
elif command == 'updateNetworkStatusTab':
|
elif command == 'updateNetworkStatusTab':
|
||||||
outbound, add, destination = data
|
outbound, add, destination = data
|
||||||
self.emit(
|
self.updateNetworkStatusTab.emit(outbound, add, destination)
|
||||||
SIGNAL("updateNetworkStatusTab(PyQt_PyObject,PyQt_PyObject,PyQt_PyObject)"),
|
|
||||||
outbound,
|
|
||||||
add,
|
|
||||||
destination)
|
|
||||||
elif command == 'updateNumberOfMessagesProcessed':
|
elif command == 'updateNumberOfMessagesProcessed':
|
||||||
self.emit(SIGNAL("updateNumberOfMessagesProcessed()"))
|
self.updateNumberOfMessagesProcessed.emit()
|
||||||
elif command == 'updateNumberOfPubkeysProcessed':
|
elif command == 'updateNumberOfPubkeysProcessed':
|
||||||
self.emit(SIGNAL("updateNumberOfPubkeysProcessed()"))
|
self.updateNumberOfPubkeysProcessed.emit()
|
||||||
elif command == 'updateNumberOfBroadcastsProcessed':
|
elif command == 'updateNumberOfBroadcastsProcessed':
|
||||||
self.emit(SIGNAL("updateNumberOfBroadcastsProcessed()"))
|
self.updateNumberOfBroadcastsProcessed.emit()
|
||||||
elif command == 'setStatusIcon':
|
elif command == 'setStatusIcon':
|
||||||
self.emit(SIGNAL("setStatusIcon(PyQt_PyObject)"), data)
|
self.setStatusIcon.emit(data)
|
||||||
elif command == 'changedInboxUnread':
|
elif command == 'changedInboxUnread':
|
||||||
self.emit(SIGNAL("changedInboxUnread(PyQt_PyObject)"), data)
|
self.changedInboxUnread.emit(data)
|
||||||
elif command == 'rerenderMessagelistFromLabels':
|
elif command == 'rerenderMessagelistFromLabels':
|
||||||
self.emit(SIGNAL("rerenderMessagelistFromLabels()"))
|
self.rerenderMessagelistFromLabels.emit()
|
||||||
elif command == 'rerenderMessagelistToLabels':
|
elif command == 'rerenderMessagelistToLabels':
|
||||||
self.emit(SIGNAL("rerenderMessagelistToLabels()"))
|
self.rerenderMessagelistToLabels.emit()
|
||||||
elif command == 'rerenderAddressBook':
|
elif command == 'rerenderAddressBook':
|
||||||
self.emit(SIGNAL("rerenderAddressBook()"))
|
self.rerenderAddressBook.emit()
|
||||||
elif command == 'rerenderSubscriptions':
|
elif command == 'rerenderSubscriptions':
|
||||||
self.emit(SIGNAL("rerenderSubscriptions()"))
|
self.rerenderSubscriptions.emit()
|
||||||
elif command == 'rerenderBlackWhiteList':
|
elif command == 'rerenderBlackWhiteList':
|
||||||
self.emit(SIGNAL("rerenderBlackWhiteList()"))
|
self.rerenderBlackWhiteList.emit()
|
||||||
elif command == 'removeInboxRowByMsgid':
|
elif command == 'removeInboxRowByMsgid':
|
||||||
self.emit(SIGNAL("removeInboxRowByMsgid(PyQt_PyObject)"), data)
|
self.removeInboxRowByMsgid.emit(data)
|
||||||
elif command == 'newVersionAvailable':
|
elif command == 'newVersionAvailable':
|
||||||
self.emit(SIGNAL("newVersionAvailable(PyQt_PyObject)"), data)
|
self.newVersionAvailable.emit(data)
|
||||||
elif command == 'alert':
|
elif command == 'alert':
|
||||||
title, text, exitAfterUserClicksOk = data
|
title, text, exitAfterUserClicksOk = data
|
||||||
self.emit(
|
self.displayAlert.emit(title, text, exitAfterUserClicksOk)
|
||||||
SIGNAL("displayAlert(PyQt_PyObject, PyQt_PyObject, PyQt_PyObject)"),
|
|
||||||
title,
|
|
||||||
text,
|
|
||||||
exitAfterUserClicksOk)
|
|
||||||
else:
|
else:
|
||||||
sys.stderr.write(
|
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 hashlib
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from PyQt4 import QtGui
|
from qtpy import QtGui
|
||||||
|
|
||||||
import state
|
import state
|
||||||
from addresses import addBMIfNotPresent
|
from addresses import addBMIfNotPresent
|
||||||
|
@ -30,16 +30,18 @@ def identiconize(address):
|
||||||
# It can be used as a pseudo-password to salt the generation of
|
# It can be used as a pseudo-password to salt the generation of
|
||||||
# the identicons to decrease the risk of attacks where someone creates
|
# the identicons to decrease the risk of attacks where someone creates
|
||||||
# an address to mimic someone else's identicon.
|
# 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':
|
if identicon_lib[:len('qidenticon')] == 'qidenticon':
|
||||||
# originally by:
|
# originally by:
|
||||||
# :Author:Shin Adachi <shn@glucose.jp>
|
# :Author:Shin Adachi <shn@glucose.jp>
|
||||||
# Licesensed under FreeBSD License.
|
# Licesensed under FreeBSD License.
|
||||||
# stripped from PIL and uses QT instead (by sendiulo, same license)
|
# stripped from PIL and uses QT instead (by sendiulo, same license)
|
||||||
import qidenticon
|
import qidenticon
|
||||||
icon_hash = hashlib.md5(
|
icon_hash = hashlib.md5(data).hexdigest()
|
||||||
addBMIfNotPresent(address) + identiconsuffix).hexdigest()
|
use_two_colors = (
|
||||||
use_two_colors = identicon_lib[:len('qidenticon_two')] == 'qidenticon_two'
|
identicon_lib[:len('qidenticon_two')] == 'qidenticon_two')
|
||||||
opacity = int(
|
opacity = int(
|
||||||
identicon_lib not in (
|
identicon_lib not in (
|
||||||
'qidenticon_x', 'qidenticon_two_x',
|
'qidenticon_x', 'qidenticon_two_x',
|
||||||
|
@ -63,8 +65,7 @@ def identiconize(address):
|
||||||
# https://github.com/azaghal/pydenticon
|
# https://github.com/azaghal/pydenticon
|
||||||
# note that it requires pillow (or PIL) to be installed:
|
# note that it requires pillow (or PIL) to be installed:
|
||||||
# https://python-pillow.org/
|
# https://python-pillow.org/
|
||||||
idcon_render = Pydenticon(
|
idcon_render = Pydenticon(data, size * 3)
|
||||||
addBMIfNotPresent(address) + identiconsuffix, size * 3)
|
|
||||||
rendering = idcon_render._render()
|
rendering = idcon_render._render()
|
||||||
data = rendering.convert("RGBA").tostring("raw", "RGBA")
|
data = rendering.convert("RGBA").tostring("raw", "RGBA")
|
||||||
qim = QtGui.QImage(data, size, size, QtGui.QImage.Format_ARGB32)
|
qim = QtGui.QImage(data, size, size, QtGui.QImage.Format_ARGB32)
|
||||||
|
@ -81,7 +82,7 @@ def avatarize(address):
|
||||||
falls back to identiconize(address)
|
falls back to identiconize(address)
|
||||||
"""
|
"""
|
||||||
idcon = QtGui.QIcon()
|
idcon = QtGui.QIcon()
|
||||||
icon_hash = hashlib.md5(addBMIfNotPresent(address)).hexdigest()
|
icon_hash = hashlib.md5(addBMIfNotPresent(address).encode("utf-8", "replace")).hexdigest()
|
||||||
if address == str_broadcast_subscribers:
|
if address == str_broadcast_subscribers:
|
||||||
# don't hash [Broadcast subscribers]
|
# don't hash [Broadcast subscribers]
|
||||||
icon_hash = address
|
icon_hash = address
|
||||||
|
@ -105,11 +106,9 @@ def avatarize(address):
|
||||||
lower_default = state.appdata + 'avatars/' + 'default.' + ext.lower()
|
lower_default = state.appdata + 'avatars/' + 'default.' + ext.lower()
|
||||||
upper_default = state.appdata + 'avatars/' + 'default.' + ext.upper()
|
upper_default = state.appdata + 'avatars/' + 'default.' + ext.upper()
|
||||||
if os.path.isfile(lower_default):
|
if os.path.isfile(lower_default):
|
||||||
default = lower_default
|
|
||||||
idcon.addFile(lower_default)
|
idcon.addFile(lower_default)
|
||||||
return idcon
|
return idcon
|
||||||
elif os.path.isfile(upper_default):
|
elif os.path.isfile(upper_default):
|
||||||
default = upper_default
|
|
||||||
idcon.addFile(upper_default)
|
idcon.addFile(upper_default)
|
||||||
return idcon
|
return idcon
|
||||||
# If no avatar is found
|
# If no avatar is found
|
||||||
|
|
|
@ -1,13 +1,15 @@
|
||||||
from PyQt4 import uic
|
from qtpy import uic
|
||||||
import os.path
|
import os.path
|
||||||
import paths
|
import paths
|
||||||
import sys
|
|
||||||
|
|
||||||
def resource_path(resFile):
|
def resource_path(resFile):
|
||||||
baseDir = paths.codePath()
|
baseDir = paths.codePath()
|
||||||
for subDir in ["ui", "bitmessageqt"]:
|
for subDir in ("ui", "bitmessageqt"):
|
||||||
if os.path.isdir(os.path.join(baseDir, subDir)) and os.path.isfile(os.path.join(baseDir, subDir, resFile)):
|
path = os.path.join(baseDir, subDir, resFile)
|
||||||
return os.path.join(baseDir, subDir, resFile)
|
if os.path.isfile(path):
|
||||||
|
return path
|
||||||
|
|
||||||
|
|
||||||
def load(resFile, widget):
|
def load(resFile, widget):
|
||||||
uic.loadUi(resource_path(resFile), widget)
|
uic.loadUi(resource_path(resFile), widget)
|
||||||
|
|
|
@ -9,19 +9,24 @@ from datetime import datetime
|
||||||
|
|
||||||
from six import string_types
|
from six import string_types
|
||||||
from six.moves import configparser
|
from six.moves import configparser
|
||||||
|
from unqstr import ustr
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import state
|
import state
|
||||||
except ImportError:
|
except ImportError:
|
||||||
from pybitmessage import state
|
from pybitmessage import state
|
||||||
|
|
||||||
SafeConfigParser = configparser.SafeConfigParser
|
try:
|
||||||
|
SafeConfigParser = configparser.SafeConfigParser
|
||||||
|
except AttributeError:
|
||||||
|
# alpine linux, python3.12
|
||||||
|
SafeConfigParser = configparser.ConfigParser
|
||||||
config_ready = Event()
|
config_ready = Event()
|
||||||
|
|
||||||
|
|
||||||
class BMConfigParser(SafeConfigParser):
|
class BMConfigParser(SafeConfigParser):
|
||||||
"""
|
"""
|
||||||
Singleton class inherited from :class:`ConfigParser.SafeConfigParser`
|
Singleton class inherited from :class:`configparser.SafeConfigParser`
|
||||||
with additional methods specific to bitmessage config.
|
with additional methods specific to bitmessage config.
|
||||||
"""
|
"""
|
||||||
# pylint: disable=too-many-ancestors
|
# pylint: disable=too-many-ancestors
|
||||||
|
@ -114,7 +119,8 @@ class BMConfigParser(SafeConfigParser):
|
||||||
"""Return a list of local bitmessage addresses (from section labels)"""
|
"""Return a list of local bitmessage addresses (from section labels)"""
|
||||||
sections = [x for x in self.sections() if x.startswith('BM-')]
|
sections = [x for x in self.sections() if x.startswith('BM-')]
|
||||||
if sort:
|
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
|
return sections
|
||||||
|
|
||||||
def save(self):
|
def save(self):
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
"""
|
"""
|
||||||
A thread for creating addresses
|
addressGenerator thread class definition
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import time
|
import time
|
||||||
|
@ -211,8 +211,8 @@ class addressGenerator(StoppableThread):
|
||||||
'updateStatusBar',
|
'updateStatusBar',
|
||||||
_translate(
|
_translate(
|
||||||
"MainWindow",
|
"MainWindow",
|
||||||
"Generating %1 new addresses."
|
"Generating {0} new addresses."
|
||||||
).arg(str(numberOfAddressesToMake))
|
).format(str(numberOfAddressesToMake))
|
||||||
))
|
))
|
||||||
signingKeyNonce = 0
|
signingKeyNonce = 0
|
||||||
encryptionKeyNonce = 1
|
encryptionKeyNonce = 1
|
||||||
|
@ -302,9 +302,9 @@ class addressGenerator(StoppableThread):
|
||||||
'updateStatusBar',
|
'updateStatusBar',
|
||||||
_translate(
|
_translate(
|
||||||
"MainWindow",
|
"MainWindow",
|
||||||
"%1 is already in 'Your Identities'."
|
"{0} is already in 'Your Identities'."
|
||||||
" Not adding it again."
|
" Not adding it again."
|
||||||
).arg(address)
|
).format(address)
|
||||||
))
|
))
|
||||||
else:
|
else:
|
||||||
self.logger.debug('label: %s', label)
|
self.logger.debug('label: %s', label)
|
||||||
|
|
|
@ -12,6 +12,7 @@ import subprocess # nosec B404
|
||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
from binascii import hexlify
|
from binascii import hexlify
|
||||||
|
import sqlite3
|
||||||
|
|
||||||
import helper_bitcoin
|
import helper_bitcoin
|
||||||
import helper_inbox
|
import helper_inbox
|
||||||
|
@ -33,6 +34,7 @@ from helper_sql import (
|
||||||
from network import knownnodes, invQueue
|
from network import knownnodes, invQueue
|
||||||
from network.node import Peer
|
from network.node import Peer
|
||||||
from tr import _translate
|
from tr import _translate
|
||||||
|
from dbcompat import dbstr
|
||||||
|
|
||||||
logger = logging.getLogger('default')
|
logger = logging.getLogger('default')
|
||||||
|
|
||||||
|
@ -121,7 +123,7 @@ class objectProcessor(threading.Thread):
|
||||||
objectType, data = queues.objectProcessorQueue.get()
|
objectType, data = queues.objectProcessorQueue.get()
|
||||||
sql.execute(
|
sql.execute(
|
||||||
'INSERT INTO objectprocessorqueue VALUES (?,?)',
|
'INSERT INTO objectprocessorqueue VALUES (?,?)',
|
||||||
objectType, data)
|
objectType, sqlite3.Binary(data))
|
||||||
numberOfObjectsThatWereInTheObjectProcessorQueue += 1
|
numberOfObjectsThatWereInTheObjectProcessorQueue += 1
|
||||||
logger.debug(
|
logger.debug(
|
||||||
'Saved %s objects from the objectProcessorQueue to'
|
'Saved %s objects from the objectProcessorQueue to'
|
||||||
|
@ -140,19 +142,23 @@ class objectProcessor(threading.Thread):
|
||||||
# bypass nonce and time, retain object type/version/stream + body
|
# bypass nonce and time, retain object type/version/stream + body
|
||||||
readPosition = 16
|
readPosition = 16
|
||||||
|
|
||||||
if data[readPosition:] in state.ackdataForWhichImWatching:
|
data_bytes = bytes(data[readPosition:])
|
||||||
|
if data_bytes in state.ackdataForWhichImWatching:
|
||||||
logger.info('This object is an acknowledgement bound for me.')
|
logger.info('This object is an acknowledgement bound for me.')
|
||||||
del state.ackdataForWhichImWatching[data[readPosition:]]
|
del state.ackdataForWhichImWatching[data_bytes]
|
||||||
sqlExecute(
|
rowcount = sqlExecute(
|
||||||
"UPDATE sent SET status='ackreceived', lastactiontime=?"
|
"UPDATE sent SET status='ackreceived', lastactiontime=?"
|
||||||
" WHERE ackdata=?", int(time.time()), data[readPosition:])
|
" WHERE ackdata=?", int(time.time()), sqlite3.Binary(data_bytes))
|
||||||
|
if rowcount < 1:
|
||||||
|
rowcount = sqlExecute(
|
||||||
|
"UPDATE sent SET status='ackreceived', lastactiontime=?"
|
||||||
|
" WHERE ackdata=CAST(? AS TEXT)", int(time.time()), data_bytes)
|
||||||
queues.UISignalQueue.put((
|
queues.UISignalQueue.put((
|
||||||
'updateSentItemStatusByAckdata', (
|
'updateSentItemStatusByAckdata', (
|
||||||
data[readPosition:],
|
data_bytes, _translate(
|
||||||
_translate(
|
|
||||||
"MainWindow",
|
"MainWindow",
|
||||||
"Acknowledgement of the message received %1"
|
"Acknowledgement of the message received {0}"
|
||||||
).arg(l10n.formatTimestamp()))
|
).format(l10n.formatTimestamp()))
|
||||||
))
|
))
|
||||||
else:
|
else:
|
||||||
logger.debug('This object is not an acknowledgement bound for me.')
|
logger.debug('This object is not an acknowledgement bound for me.')
|
||||||
|
@ -215,9 +221,10 @@ class objectProcessor(threading.Thread):
|
||||||
logger.info(
|
logger.info(
|
||||||
'the hash requested in this getpubkey request is: %s',
|
'the hash requested in this getpubkey request is: %s',
|
||||||
hexlify(requestedHash))
|
hexlify(requestedHash))
|
||||||
|
requestedHash_bytes = bytes(requestedHash)
|
||||||
# if this address hash is one of mine
|
# if this address hash is one of mine
|
||||||
if requestedHash in shared.myAddressesByHash:
|
if requestedHash_bytes in shared.myAddressesByHash:
|
||||||
myAddress = shared.myAddressesByHash[requestedHash]
|
myAddress = shared.myAddressesByHash[requestedHash_bytes]
|
||||||
elif requestedAddressVersionNumber >= 4:
|
elif requestedAddressVersionNumber >= 4:
|
||||||
requestedTag = data[readPosition:readPosition + 32]
|
requestedTag = data[readPosition:readPosition + 32]
|
||||||
if len(requestedTag) != 32:
|
if len(requestedTag) != 32:
|
||||||
|
@ -227,8 +234,9 @@ class objectProcessor(threading.Thread):
|
||||||
logger.debug(
|
logger.debug(
|
||||||
'the tag requested in this getpubkey request is: %s',
|
'the tag requested in this getpubkey request is: %s',
|
||||||
hexlify(requestedTag))
|
hexlify(requestedTag))
|
||||||
if requestedTag in shared.myAddressesByTag:
|
requestedTag_bytes = bytes(requestedTag)
|
||||||
myAddress = shared.myAddressesByTag[requestedTag]
|
if requestedTag_bytes in shared.myAddressesByTag:
|
||||||
|
myAddress = shared.myAddressesByTag[requestedTag_bytes]
|
||||||
|
|
||||||
if myAddress == '':
|
if myAddress == '':
|
||||||
logger.info('This getpubkey request is not for any of my keys.')
|
logger.info('This getpubkey request is not for any of my keys.')
|
||||||
|
@ -299,12 +307,12 @@ class objectProcessor(threading.Thread):
|
||||||
'(within processpubkey) payloadLength less than 146.'
|
'(within processpubkey) payloadLength less than 146.'
|
||||||
' Sanity check failed.')
|
' Sanity check failed.')
|
||||||
readPosition += 4
|
readPosition += 4
|
||||||
pubSigningKey = '\x04' + data[readPosition:readPosition + 64]
|
pubSigningKey = b'\x04' + data[readPosition:readPosition + 64]
|
||||||
# Is it possible for a public key to be invalid such that trying to
|
# Is it possible for a public key to be invalid such that trying to
|
||||||
# encrypt or sign with it will cause an error? If it is, it would
|
# encrypt or sign with it will cause an error? If it is, it would
|
||||||
# be easiest to test them here.
|
# be easiest to test them here.
|
||||||
readPosition += 64
|
readPosition += 64
|
||||||
pubEncryptionKey = '\x04' + data[readPosition:readPosition + 64]
|
pubEncryptionKey = b'\x04' + data[readPosition:readPosition + 64]
|
||||||
if len(pubEncryptionKey) < 65:
|
if len(pubEncryptionKey) < 65:
|
||||||
return logger.debug(
|
return logger.debug(
|
||||||
'publicEncryptionKey length less than 64. Sanity check'
|
'publicEncryptionKey length less than 64. Sanity check'
|
||||||
|
@ -327,19 +335,19 @@ class objectProcessor(threading.Thread):
|
||||||
|
|
||||||
queryreturn = sqlQuery(
|
queryreturn = sqlQuery(
|
||||||
"SELECT usedpersonally FROM pubkeys WHERE address=?"
|
"SELECT usedpersonally FROM pubkeys WHERE address=?"
|
||||||
" AND usedpersonally='yes'", address)
|
" AND usedpersonally='yes'", dbstr(address))
|
||||||
# if this pubkey is already in our database and if we have
|
# if this pubkey is already in our database and if we have
|
||||||
# used it personally:
|
# used it personally:
|
||||||
if queryreturn != []:
|
if queryreturn != []:
|
||||||
logger.info(
|
logger.info(
|
||||||
'We HAVE used this pubkey personally. Updating time.')
|
'We HAVE used this pubkey personally. Updating time.')
|
||||||
t = (address, addressVersion, dataToStore,
|
t = (dbstr(address), addressVersion, sqlite3.Binary(dataToStore),
|
||||||
int(time.time()), 'yes')
|
int(time.time()), 'yes')
|
||||||
else:
|
else:
|
||||||
logger.info(
|
logger.info(
|
||||||
'We have NOT used this pubkey personally. Inserting'
|
'We have NOT used this pubkey personally. Inserting'
|
||||||
' in database.')
|
' in database.')
|
||||||
t = (address, addressVersion, dataToStore,
|
t = (dbstr(address), addressVersion, sqlite3.Binary(dataToStore),
|
||||||
int(time.time()), 'no')
|
int(time.time()), 'no')
|
||||||
sqlExecute('''INSERT INTO pubkeys VALUES (?,?,?,?,?)''', *t)
|
sqlExecute('''INSERT INTO pubkeys VALUES (?,?,?,?,?)''', *t)
|
||||||
self.possibleNewPubkey(address)
|
self.possibleNewPubkey(address)
|
||||||
|
@ -350,9 +358,9 @@ class objectProcessor(threading.Thread):
|
||||||
' Sanity check failed.')
|
' Sanity check failed.')
|
||||||
return
|
return
|
||||||
readPosition += 4
|
readPosition += 4
|
||||||
pubSigningKey = '\x04' + data[readPosition:readPosition + 64]
|
pubSigningKey = b'\x04' + data[readPosition:readPosition + 64]
|
||||||
readPosition += 64
|
readPosition += 64
|
||||||
pubEncryptionKey = '\x04' + data[readPosition:readPosition + 64]
|
pubEncryptionKey = b'\x04' + data[readPosition:readPosition + 64]
|
||||||
readPosition += 64
|
readPosition += 64
|
||||||
specifiedNonceTrialsPerByteLength = decodeVarint(
|
specifiedNonceTrialsPerByteLength = decodeVarint(
|
||||||
data[readPosition:readPosition + 10])[1]
|
data[readPosition:readPosition + 10])[1]
|
||||||
|
@ -389,20 +397,20 @@ class objectProcessor(threading.Thread):
|
||||||
address = encodeAddress(addressVersion, streamNumber, ripe)
|
address = encodeAddress(addressVersion, streamNumber, ripe)
|
||||||
queryreturn = sqlQuery(
|
queryreturn = sqlQuery(
|
||||||
"SELECT usedpersonally FROM pubkeys WHERE address=?"
|
"SELECT usedpersonally FROM pubkeys WHERE address=?"
|
||||||
" AND usedpersonally='yes'", address)
|
" AND usedpersonally='yes'", dbstr(address))
|
||||||
# if this pubkey is already in our database and if we have
|
# if this pubkey is already in our database and if we have
|
||||||
# used it personally:
|
# used it personally:
|
||||||
if queryreturn != []:
|
if queryreturn != []:
|
||||||
logger.info(
|
logger.info(
|
||||||
'We HAVE used this pubkey personally. Updating time.')
|
'We HAVE used this pubkey personally. Updating time.')
|
||||||
t = (address, addressVersion, dataToStore,
|
t = (dbstr(address), addressVersion, sqlite3.Binary(dataToStore),
|
||||||
int(time.time()), 'yes')
|
int(time.time()), dbstr('yes'))
|
||||||
else:
|
else:
|
||||||
logger.info(
|
logger.info(
|
||||||
'We have NOT used this pubkey personally. Inserting'
|
'We have NOT used this pubkey personally. Inserting'
|
||||||
' in database.')
|
' in database.')
|
||||||
t = (address, addressVersion, dataToStore,
|
t = (dbstr(address), addressVersion, sqlite3.Binary(dataToStore),
|
||||||
int(time.time()), 'no')
|
int(time.time()), dbstr('no'))
|
||||||
sqlExecute('''INSERT INTO pubkeys VALUES (?,?,?,?,?)''', *t)
|
sqlExecute('''INSERT INTO pubkeys VALUES (?,?,?,?,?)''', *t)
|
||||||
self.possibleNewPubkey(address)
|
self.possibleNewPubkey(address)
|
||||||
|
|
||||||
|
@ -413,12 +421,13 @@ class objectProcessor(threading.Thread):
|
||||||
' Sanity check failed.')
|
' Sanity check failed.')
|
||||||
|
|
||||||
tag = data[readPosition:readPosition + 32]
|
tag = data[readPosition:readPosition + 32]
|
||||||
if tag not in state.neededPubkeys:
|
tag_bytes = bytes(tag)
|
||||||
|
if tag_bytes not in state.neededPubkeys:
|
||||||
return logger.info(
|
return logger.info(
|
||||||
'We don\'t need this v4 pubkey. We didn\'t ask for it.')
|
'We don\'t need this v4 pubkey. We didn\'t ask for it.')
|
||||||
|
|
||||||
# Let us try to decrypt the pubkey
|
# Let us try to decrypt the pubkey
|
||||||
toAddress = state.neededPubkeys[tag][0]
|
toAddress = state.neededPubkeys[tag_bytes][0]
|
||||||
if protocol.decryptAndCheckPubkeyPayload(data, toAddress) == \
|
if protocol.decryptAndCheckPubkeyPayload(data, toAddress) == \
|
||||||
'successful':
|
'successful':
|
||||||
# At this point we know that we have been waiting on this
|
# At this point we know that we have been waiting on this
|
||||||
|
@ -483,7 +492,7 @@ class objectProcessor(threading.Thread):
|
||||||
|
|
||||||
# This is a message bound for me.
|
# This is a message bound for me.
|
||||||
# Look up my address based on the RIPE hash.
|
# Look up my address based on the RIPE hash.
|
||||||
toAddress = shared.myAddressesByHash[toRipe]
|
toAddress = shared.myAddressesByHash[bytes(toRipe)]
|
||||||
readPosition = 0
|
readPosition = 0
|
||||||
sendersAddressVersionNumber, sendersAddressVersionNumberLength = \
|
sendersAddressVersionNumber, sendersAddressVersionNumberLength = \
|
||||||
decodeVarint(decryptedData[readPosition:readPosition + 10])
|
decodeVarint(decryptedData[readPosition:readPosition + 10])
|
||||||
|
@ -507,9 +516,9 @@ class objectProcessor(threading.Thread):
|
||||||
return
|
return
|
||||||
readPosition += sendersStreamNumberLength
|
readPosition += sendersStreamNumberLength
|
||||||
readPosition += 4
|
readPosition += 4
|
||||||
pubSigningKey = '\x04' + decryptedData[readPosition:readPosition + 64]
|
pubSigningKey = b'\x04' + decryptedData[readPosition:readPosition + 64]
|
||||||
readPosition += 64
|
readPosition += 64
|
||||||
pubEncryptionKey = '\x04' + decryptedData[readPosition:readPosition + 64]
|
pubEncryptionKey = b'\x04' + decryptedData[readPosition:readPosition + 64]
|
||||||
readPosition += 64
|
readPosition += 64
|
||||||
if sendersAddressVersionNumber >= 3:
|
if sendersAddressVersionNumber >= 3:
|
||||||
requiredAverageProofOfWorkNonceTrialsPerByte, varintLength = \
|
requiredAverageProofOfWorkNonceTrialsPerByte, varintLength = \
|
||||||
|
@ -558,7 +567,7 @@ class objectProcessor(threading.Thread):
|
||||||
readPosition += signatureLengthLength
|
readPosition += signatureLengthLength
|
||||||
signature = decryptedData[
|
signature = decryptedData[
|
||||||
readPosition:readPosition + signatureLength]
|
readPosition:readPosition + signatureLength]
|
||||||
signedData = data[8:20] + encodeVarint(1) + encodeVarint(
|
signedData = bytes(data[8:20]) + encodeVarint(1) + encodeVarint(
|
||||||
streamNumberAsClaimedByMsg
|
streamNumberAsClaimedByMsg
|
||||||
) + decryptedData[:positionOfBottomOfAckData]
|
) + decryptedData[:positionOfBottomOfAckData]
|
||||||
|
|
||||||
|
@ -590,11 +599,11 @@ class objectProcessor(threading.Thread):
|
||||||
# person.
|
# person.
|
||||||
sqlExecute(
|
sqlExecute(
|
||||||
'''INSERT INTO pubkeys VALUES (?,?,?,?,?)''',
|
'''INSERT INTO pubkeys VALUES (?,?,?,?,?)''',
|
||||||
fromAddress,
|
dbstr(fromAddress),
|
||||||
sendersAddressVersionNumber,
|
sendersAddressVersionNumber,
|
||||||
decryptedData[:endOfThePublicKeyPosition],
|
sqlite3.Binary(decryptedData[:endOfThePublicKeyPosition]),
|
||||||
int(time.time()),
|
int(time.time()),
|
||||||
'yes')
|
dbstr('yes'))
|
||||||
|
|
||||||
# Check to see whether we happen to be awaiting this
|
# Check to see whether we happen to be awaiting this
|
||||||
# pubkey in order to send a message. If we are, it will do the POW
|
# pubkey in order to send a message. If we are, it will do the POW
|
||||||
|
@ -631,7 +640,7 @@ class objectProcessor(threading.Thread):
|
||||||
'bitmessagesettings', 'blackwhitelist') == 'black':
|
'bitmessagesettings', 'blackwhitelist') == 'black':
|
||||||
queryreturn = sqlQuery(
|
queryreturn = sqlQuery(
|
||||||
"SELECT label FROM blacklist where address=? and enabled='1'",
|
"SELECT label FROM blacklist where address=? and enabled='1'",
|
||||||
fromAddress)
|
dbstr(fromAddress))
|
||||||
if queryreturn != []:
|
if queryreturn != []:
|
||||||
logger.info('Message ignored because address is in blacklist.')
|
logger.info('Message ignored because address is in blacklist.')
|
||||||
|
|
||||||
|
@ -639,7 +648,7 @@ class objectProcessor(threading.Thread):
|
||||||
else: # We're using a whitelist
|
else: # We're using a whitelist
|
||||||
queryreturn = sqlQuery(
|
queryreturn = sqlQuery(
|
||||||
"SELECT label FROM whitelist where address=? and enabled='1'",
|
"SELECT label FROM whitelist where address=? and enabled='1'",
|
||||||
fromAddress)
|
dbstr(fromAddress))
|
||||||
if queryreturn == []:
|
if queryreturn == []:
|
||||||
logger.info(
|
logger.info(
|
||||||
'Message ignored because address not in whitelist.')
|
'Message ignored because address not in whitelist.')
|
||||||
|
@ -808,13 +817,14 @@ class objectProcessor(threading.Thread):
|
||||||
elif broadcastVersion == 5:
|
elif broadcastVersion == 5:
|
||||||
embeddedTag = data[readPosition:readPosition + 32]
|
embeddedTag = data[readPosition:readPosition + 32]
|
||||||
readPosition += 32
|
readPosition += 32
|
||||||
if embeddedTag not in shared.MyECSubscriptionCryptorObjects:
|
embeddedTag_bytes = bytes(embeddedTag)
|
||||||
|
if embeddedTag_bytes not in shared.MyECSubscriptionCryptorObjects:
|
||||||
logger.debug('We\'re not interested in this broadcast.')
|
logger.debug('We\'re not interested in this broadcast.')
|
||||||
return
|
return
|
||||||
# We are interested in this broadcast because of its tag.
|
# We are interested in this broadcast because of its tag.
|
||||||
# We're going to add some more data which is signed further down.
|
# We're going to add some more data which is signed further down.
|
||||||
signedData = data[8:readPosition]
|
signedData = bytes(data[8:readPosition])
|
||||||
cryptorObject = shared.MyECSubscriptionCryptorObjects[embeddedTag]
|
cryptorObject = shared.MyECSubscriptionCryptorObjects[embeddedTag_bytes]
|
||||||
try:
|
try:
|
||||||
decryptedData = cryptorObject.decrypt(data[readPosition:])
|
decryptedData = cryptorObject.decrypt(data[readPosition:])
|
||||||
logger.debug('EC decryption successful')
|
logger.debug('EC decryption successful')
|
||||||
|
@ -854,10 +864,10 @@ class objectProcessor(threading.Thread):
|
||||||
)
|
)
|
||||||
readPosition += sendersStreamLength
|
readPosition += sendersStreamLength
|
||||||
readPosition += 4
|
readPosition += 4
|
||||||
sendersPubSigningKey = '\x04' + \
|
sendersPubSigningKey = b'\x04' + \
|
||||||
decryptedData[readPosition:readPosition + 64]
|
decryptedData[readPosition:readPosition + 64]
|
||||||
readPosition += 64
|
readPosition += 64
|
||||||
sendersPubEncryptionKey = '\x04' + \
|
sendersPubEncryptionKey = b'\x04' + \
|
||||||
decryptedData[readPosition:readPosition + 64]
|
decryptedData[readPosition:readPosition + 64]
|
||||||
readPosition += 64
|
readPosition += 64
|
||||||
if sendersAddressVersion >= 3:
|
if sendersAddressVersion >= 3:
|
||||||
|
@ -927,11 +937,11 @@ class objectProcessor(threading.Thread):
|
||||||
|
|
||||||
# Let's store the public key in case we want to reply to this person.
|
# Let's store the public key in case we want to reply to this person.
|
||||||
sqlExecute('''INSERT INTO pubkeys VALUES (?,?,?,?,?)''',
|
sqlExecute('''INSERT INTO pubkeys VALUES (?,?,?,?,?)''',
|
||||||
fromAddress,
|
dbstr(fromAddress),
|
||||||
sendersAddressVersion,
|
dbstr(sendersAddressVersion),
|
||||||
decryptedData[:endOfPubkeyPosition],
|
sqlite3.Binary(decryptedData[:endOfPubkeyPosition]),
|
||||||
int(time.time()),
|
int(time.time()),
|
||||||
'yes')
|
dbstr('yes'))
|
||||||
|
|
||||||
# Check to see whether we happen to be awaiting this
|
# Check to see whether we happen to be awaiting this
|
||||||
# pubkey in order to send a message. If we are, it will do the POW
|
# pubkey in order to send a message. If we are, it will do the POW
|
||||||
|
@ -997,8 +1007,9 @@ class objectProcessor(threading.Thread):
|
||||||
encodeVarint(addressVersion) + encodeVarint(streamNumber)
|
encodeVarint(addressVersion) + encodeVarint(streamNumber)
|
||||||
+ ripe
|
+ ripe
|
||||||
)[32:]
|
)[32:]
|
||||||
if tag in state.neededPubkeys:
|
tag_bytes = bytes(tag)
|
||||||
del state.neededPubkeys[tag]
|
if tag_bytes in state.neededPubkeys:
|
||||||
|
del state.neededPubkeys[tag_bytes]
|
||||||
self.sendMessages(address)
|
self.sendMessages(address)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
@ -1012,7 +1023,7 @@ class objectProcessor(threading.Thread):
|
||||||
"UPDATE sent SET status='doingmsgpow', retrynumber=0"
|
"UPDATE sent SET status='doingmsgpow', retrynumber=0"
|
||||||
" WHERE toaddress=?"
|
" WHERE toaddress=?"
|
||||||
" AND (status='awaitingpubkey' OR status='doingpubkeypow')"
|
" AND (status='awaitingpubkey' OR status='doingpubkeypow')"
|
||||||
" AND folder='sent'", address)
|
" AND folder='sent'", dbstr(address))
|
||||||
queues.workerQueue.put(('sendmessage', ''))
|
queues.workerQueue.put(('sendmessage', ''))
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
@ -1047,8 +1058,8 @@ class objectProcessor(threading.Thread):
|
||||||
if checksum != hashlib.sha512(payload).digest()[0:4]:
|
if checksum != hashlib.sha512(payload).digest()[0:4]:
|
||||||
logger.info('ackdata checksum wrong. Not sending ackdata.')
|
logger.info('ackdata checksum wrong. Not sending ackdata.')
|
||||||
return False
|
return False
|
||||||
command = command.rstrip('\x00')
|
command = command.rstrip(b'\x00')
|
||||||
if command != 'object':
|
if command != b'object':
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,7 @@ It resends messages when there has been no response:
|
||||||
import gc
|
import gc
|
||||||
import os
|
import os
|
||||||
import time
|
import time
|
||||||
|
import sqlite3
|
||||||
|
|
||||||
import queues
|
import queues
|
||||||
import state
|
import state
|
||||||
|
@ -29,6 +30,7 @@ from bmconfigparser import config
|
||||||
from helper_sql import sqlExecute, sqlQuery
|
from helper_sql import sqlExecute, sqlQuery
|
||||||
from network import connectionpool, knownnodes, StoppableThread
|
from network import connectionpool, knownnodes, StoppableThread
|
||||||
from tr import _translate
|
from tr import _translate
|
||||||
|
from dbcompat import dbstr
|
||||||
|
|
||||||
|
|
||||||
#: Equals 4 weeks. You could make this longer if you want
|
#: Equals 4 weeks. You could make this longer if you want
|
||||||
|
@ -99,6 +101,8 @@ class singleCleaner(StoppableThread):
|
||||||
tick - state.maximumLengthOfTimeToBotherResendingMessages
|
tick - state.maximumLengthOfTimeToBotherResendingMessages
|
||||||
)
|
)
|
||||||
for toAddress, ackData, status in queryreturn:
|
for toAddress, ackData, status in queryreturn:
|
||||||
|
toAddress = toAddress.decode("utf-8", "replace")
|
||||||
|
status = status.decode("utf-8", "replace")
|
||||||
if status == 'awaitingpubkey':
|
if status == 'awaitingpubkey':
|
||||||
self.resendPubkeyRequest(toAddress)
|
self.resendPubkeyRequest(toAddress)
|
||||||
elif status == 'msgsent':
|
elif status == 'msgsent':
|
||||||
|
@ -168,7 +172,7 @@ class singleCleaner(StoppableThread):
|
||||||
))
|
))
|
||||||
sqlExecute(
|
sqlExecute(
|
||||||
"UPDATE sent SET status = 'msgqueued'"
|
"UPDATE sent SET status = 'msgqueued'"
|
||||||
" WHERE toaddress = ? AND folder = 'sent'", address)
|
" WHERE toaddress = ? AND folder = 'sent'", dbstr(address))
|
||||||
queues.workerQueue.put(('sendmessage', ''))
|
queues.workerQueue.put(('sendmessage', ''))
|
||||||
|
|
||||||
def resendMsg(self, ackdata):
|
def resendMsg(self, ackdata):
|
||||||
|
@ -177,9 +181,13 @@ class singleCleaner(StoppableThread):
|
||||||
'It has been a long time and we haven\'t heard an acknowledgement'
|
'It has been a long time and we haven\'t heard an acknowledgement'
|
||||||
' to our msg. Sending again.'
|
' to our msg. Sending again.'
|
||||||
)
|
)
|
||||||
sqlExecute(
|
rowcount = sqlExecute(
|
||||||
"UPDATE sent SET status = 'msgqueued'"
|
"UPDATE sent SET status = 'msgqueued'"
|
||||||
" WHERE ackdata = ? AND folder = 'sent'", ackdata)
|
" WHERE ackdata = ? AND folder = 'sent'", sqlite3.Binary(ackdata))
|
||||||
|
if rowcount < 1:
|
||||||
|
sqlExecute(
|
||||||
|
"UPDATE sent SET status = 'msgqueued'"
|
||||||
|
" WHERE ackdata = CAST(? AS TEXT) AND folder = 'sent'", ackdata)
|
||||||
queues.workerQueue.put(('sendmessage', ''))
|
queues.workerQueue.put(('sendmessage', ''))
|
||||||
queues.UISignalQueue.put((
|
queues.UISignalQueue.put((
|
||||||
'updateStatusBar',
|
'updateStatusBar',
|
||||||
|
|
|
@ -11,6 +11,7 @@ import time
|
||||||
from binascii import hexlify, unhexlify
|
from binascii import hexlify, unhexlify
|
||||||
from struct import pack
|
from struct import pack
|
||||||
from subprocess import call # nosec
|
from subprocess import call # nosec
|
||||||
|
import sqlite3
|
||||||
|
|
||||||
import defaults
|
import defaults
|
||||||
import helper_inbox
|
import helper_inbox
|
||||||
|
@ -24,12 +25,15 @@ import protocol
|
||||||
import queues
|
import queues
|
||||||
import shared
|
import shared
|
||||||
import state
|
import state
|
||||||
import tr
|
|
||||||
from addresses import decodeAddress, decodeVarint, encodeVarint
|
from addresses import decodeAddress, decodeVarint, encodeVarint
|
||||||
from bmconfigparser import config
|
from bmconfigparser import config
|
||||||
from helper_sql import sqlExecute, sqlQuery
|
from helper_sql import sqlExecute, sqlQuery
|
||||||
from network import knownnodes, StoppableThread, invQueue
|
from network import knownnodes, StoppableThread, invQueue
|
||||||
from six.moves import configparser, queue
|
from six.moves import configparser, queue
|
||||||
|
from six.moves.reprlib import repr
|
||||||
|
import six
|
||||||
|
from dbcompat import dbstr
|
||||||
|
from tr import _translate
|
||||||
|
|
||||||
|
|
||||||
def sizeof_fmt(num, suffix='h/s'):
|
def sizeof_fmt(num, suffix='h/s'):
|
||||||
|
@ -73,6 +77,7 @@ class singleWorker(StoppableThread):
|
||||||
'''SELECT DISTINCT toaddress FROM sent'''
|
'''SELECT DISTINCT toaddress FROM sent'''
|
||||||
''' WHERE (status='awaitingpubkey' AND folder='sent')''')
|
''' WHERE (status='awaitingpubkey' AND folder='sent')''')
|
||||||
for toAddress, in queryreturn:
|
for toAddress, in queryreturn:
|
||||||
|
toAddress = toAddress.decode("utf-8", "replace")
|
||||||
toAddressVersionNumber, toStreamNumber, toRipe = \
|
toAddressVersionNumber, toStreamNumber, toRipe = \
|
||||||
decodeAddress(toAddress)[1:]
|
decodeAddress(toAddress)[1:]
|
||||||
if toAddressVersionNumber <= 3:
|
if toAddressVersionNumber <= 3:
|
||||||
|
@ -87,7 +92,7 @@ class singleWorker(StoppableThread):
|
||||||
tag = doubleHashOfAddressData[32:]
|
tag = doubleHashOfAddressData[32:]
|
||||||
# We'll need this for when we receive a pubkey reply:
|
# We'll need this for when we receive a pubkey reply:
|
||||||
# it will be encrypted and we'll need to decrypt it.
|
# it will be encrypted and we'll need to decrypt it.
|
||||||
state.neededPubkeys[tag] = (
|
state.neededPubkeys[bytes(tag)] = (
|
||||||
toAddress,
|
toAddress,
|
||||||
highlevelcrypto.makeCryptor(
|
highlevelcrypto.makeCryptor(
|
||||||
hexlify(privEncryptionKey))
|
hexlify(privEncryptionKey))
|
||||||
|
@ -99,18 +104,23 @@ class singleWorker(StoppableThread):
|
||||||
for row in queryreturn:
|
for row in queryreturn:
|
||||||
ackdata, = row
|
ackdata, = row
|
||||||
self.logger.info('Watching for ackdata %s', hexlify(ackdata))
|
self.logger.info('Watching for ackdata %s', hexlify(ackdata))
|
||||||
state.ackdataForWhichImWatching[ackdata] = 0
|
state.ackdataForWhichImWatching[bytes(ackdata)] = 0
|
||||||
|
|
||||||
# Fix legacy (headerless) watched ackdata to include header
|
# Fix legacy (headerless) watched ackdata to include header
|
||||||
for oldack in state.ackdataForWhichImWatching:
|
for oldack in state.ackdataForWhichImWatching:
|
||||||
if len(oldack) == 32:
|
if len(oldack) == 32:
|
||||||
# attach legacy header, always constant (msg/1/1)
|
# attach legacy header, always constant (msg/1/1)
|
||||||
newack = '\x00\x00\x00\x02\x01\x01' + oldack
|
newack = b'\x00\x00\x00\x02\x01\x01' + oldack
|
||||||
state.ackdataForWhichImWatching[newack] = 0
|
state.ackdataForWhichImWatching[bytes(newack)] = 0
|
||||||
sqlExecute(
|
rowcount = sqlExecute(
|
||||||
'''UPDATE sent SET ackdata=? WHERE ackdata=? AND folder = 'sent' ''',
|
'''UPDATE sent SET ackdata=? WHERE ackdata=? AND folder = 'sent' ''',
|
||||||
newack, oldack
|
sqlite3.Binary(newack), sqlite3.Binary(oldack)
|
||||||
)
|
)
|
||||||
|
if rowcount < 1:
|
||||||
|
sqlExecute(
|
||||||
|
'''UPDATE sent SET ackdata=? WHERE ackdata=CAST(? AS TEXT) AND folder = 'sent' ''',
|
||||||
|
sqlite3.Binary(newack), oldack
|
||||||
|
)
|
||||||
del state.ackdataForWhichImWatching[oldack]
|
del state.ackdataForWhichImWatching[oldack]
|
||||||
|
|
||||||
# For the case if user deleted knownnodes
|
# For the case if user deleted knownnodes
|
||||||
|
@ -217,9 +227,8 @@ class singleWorker(StoppableThread):
|
||||||
return privSigningKeyHex, privEncryptionKeyHex, \
|
return privSigningKeyHex, privEncryptionKeyHex, \
|
||||||
pubSigningKey, pubEncryptionKey
|
pubSigningKey, pubEncryptionKey
|
||||||
|
|
||||||
def _doPOWDefaults(self, payload, TTL,
|
def _doPOWDefaults(
|
||||||
log_prefix='',
|
self, payload, TTL, log_prefix='', log_time=False):
|
||||||
log_time=False):
|
|
||||||
target = 2 ** 64 / (
|
target = 2 ** 64 / (
|
||||||
defaults.networkDefaultProofOfWorkNonceTrialsPerByte * (
|
defaults.networkDefaultProofOfWorkNonceTrialsPerByte * (
|
||||||
len(payload) + 8
|
len(payload) + 8
|
||||||
|
@ -245,14 +254,16 @@ class singleWorker(StoppableThread):
|
||||||
'PoW took %.1f seconds, speed %s.',
|
'PoW took %.1f seconds, speed %s.',
|
||||||
delta, sizeof_fmt(nonce / delta)
|
delta, sizeof_fmt(nonce / delta)
|
||||||
)
|
)
|
||||||
except: # noqa:E722 # NameError
|
except NameError:
|
||||||
self.logger.warning("Proof of Work exception")
|
self.logger.warning("Proof of Work exception")
|
||||||
payload = pack('>Q', nonce) + payload
|
payload = pack('>Q', nonce) + payload
|
||||||
return payload
|
return payload
|
||||||
|
|
||||||
def doPOWForMyV2Pubkey(self, adressHash):
|
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
|
# Look up my stream number based on my address hash
|
||||||
myAddress = shared.myAddressesByHash[adressHash]
|
myAddress = shared.myAddressesByHash[adressHash]
|
||||||
addressVersionNumber, streamNumber = decodeAddress(myAddress)[1:3]
|
addressVersionNumber, streamNumber = decodeAddress(myAddress)[1:3]
|
||||||
|
@ -261,7 +272,7 @@ class singleWorker(StoppableThread):
|
||||||
TTL = int(28 * 24 * 60 * 60 + helper_random.randomrandrange(-300, 300))
|
TTL = int(28 * 24 * 60 * 60 + helper_random.randomrandrange(-300, 300))
|
||||||
embeddedTime = int(time.time() + TTL)
|
embeddedTime = int(time.time() + TTL)
|
||||||
payload = pack('>Q', (embeddedTime))
|
payload = pack('>Q', (embeddedTime))
|
||||||
payload += '\x00\x00\x00\x01' # object type: pubkey
|
payload += b'\x00\x00\x00\x01' # object type: pubkey
|
||||||
payload += encodeVarint(addressVersionNumber) # Address version number
|
payload += encodeVarint(addressVersionNumber) # Address version number
|
||||||
payload += encodeVarint(streamNumber)
|
payload += encodeVarint(streamNumber)
|
||||||
# bitfield of features supported by me (see the wiki).
|
# bitfield of features supported by me (see the wiki).
|
||||||
|
@ -308,9 +319,10 @@ class singleWorker(StoppableThread):
|
||||||
|
|
||||||
def sendOutOrStoreMyV3Pubkey(self, adressHash):
|
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 this isn't a chan address, this function assembles the pubkey
|
||||||
If it *is* a chan then it assembles the pubkey and stores is in the pubkey table so that we can send messages
|
data, does the necessary POW and sends it out.
|
||||||
to "ourselves".
|
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:
|
try:
|
||||||
myAddress = shared.myAddressesByHash[adressHash]
|
myAddress = shared.myAddressesByHash[adressHash]
|
||||||
|
@ -338,7 +350,7 @@ class singleWorker(StoppableThread):
|
||||||
# expiresTime time.
|
# expiresTime time.
|
||||||
|
|
||||||
payload = pack('>Q', (embeddedTime))
|
payload = pack('>Q', (embeddedTime))
|
||||||
payload += '\x00\x00\x00\x01' # object type: pubkey
|
payload += b'\x00\x00\x00\x01' # object type: pubkey
|
||||||
payload += encodeVarint(addressVersionNumber) # Address version number
|
payload += encodeVarint(addressVersionNumber) # Address version number
|
||||||
payload += encodeVarint(streamNumber)
|
payload += encodeVarint(streamNumber)
|
||||||
# bitfield of features supported by me (see the wiki).
|
# bitfield of features supported by me (see the wiki).
|
||||||
|
@ -396,9 +408,10 @@ class singleWorker(StoppableThread):
|
||||||
|
|
||||||
def sendOutOrStoreMyV4Pubkey(self, myAddress):
|
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,
|
It doesn't send directly anymore. It put is to a queue for
|
||||||
whereas in the past it directly appended it to the outgoing buffer, I think. Same with all the other methods in
|
another thread to send at an appropriate time, whereas in the
|
||||||
this class.
|
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):
|
if not config.has_section(myAddress):
|
||||||
# The address has been deleted.
|
# The address has been deleted.
|
||||||
|
@ -413,7 +426,7 @@ class singleWorker(StoppableThread):
|
||||||
TTL = int(28 * 24 * 60 * 60 + helper_random.randomrandrange(-300, 300))
|
TTL = int(28 * 24 * 60 * 60 + helper_random.randomrandrange(-300, 300))
|
||||||
embeddedTime = int(time.time() + TTL)
|
embeddedTime = int(time.time() + TTL)
|
||||||
payload = pack('>Q', (embeddedTime))
|
payload = pack('>Q', (embeddedTime))
|
||||||
payload += '\x00\x00\x00\x01' # object type: pubkey
|
payload += b'\x00\x00\x00\x01' # object type: pubkey
|
||||||
payload += encodeVarint(addressVersionNumber) # Address version number
|
payload += encodeVarint(addressVersionNumber) # Address version number
|
||||||
payload += encodeVarint(streamNumber)
|
payload += encodeVarint(streamNumber)
|
||||||
dataToEncrypt = protocol.getBitfield(myAddress)
|
dataToEncrypt = protocol.getBitfield(myAddress)
|
||||||
|
@ -515,9 +528,15 @@ class singleWorker(StoppableThread):
|
||||||
payload, TTL, log_prefix='(For onionpeer object)')
|
payload, TTL, log_prefix='(For onionpeer object)')
|
||||||
|
|
||||||
inventoryHash = highlevelcrypto.calculateInventoryHash(payload)
|
inventoryHash = highlevelcrypto.calculateInventoryHash(payload)
|
||||||
|
if six.PY2:
|
||||||
|
payload_buffer = buffer(payload)
|
||||||
|
tag_buffer = buffer(tag)
|
||||||
|
else: # assume six.PY3
|
||||||
|
payload_buffer = memoryview(payload)
|
||||||
|
tag_buffer = memoryview(tag)
|
||||||
state.Inventory[inventoryHash] = (
|
state.Inventory[inventoryHash] = (
|
||||||
objectType, streamNumber, buffer(payload), # noqa: F821
|
objectType, streamNumber, payload_buffer, # noqa: F821
|
||||||
embeddedTime, buffer(tag) # noqa: F821
|
embeddedTime, tag_buffer # noqa: F821
|
||||||
)
|
)
|
||||||
self.logger.info(
|
self.logger.info(
|
||||||
'sending inv (within sendOnionPeerObj function) for object: %s',
|
'sending inv (within sendOnionPeerObj function) for object: %s',
|
||||||
|
@ -525,7 +544,10 @@ class singleWorker(StoppableThread):
|
||||||
invQueue.put((streamNumber, inventoryHash))
|
invQueue.put((streamNumber, inventoryHash))
|
||||||
|
|
||||||
def sendBroadcast(self):
|
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
|
# Reset just in case
|
||||||
sqlExecute(
|
sqlExecute(
|
||||||
'''UPDATE sent SET status='broadcastqueued' '''
|
'''UPDATE sent SET status='broadcastqueued' '''
|
||||||
|
@ -534,10 +556,13 @@ class singleWorker(StoppableThread):
|
||||||
queryreturn = sqlQuery(
|
queryreturn = sqlQuery(
|
||||||
'''SELECT fromaddress, subject, message, '''
|
'''SELECT fromaddress, subject, message, '''
|
||||||
''' ackdata, ttl, encodingtype FROM sent '''
|
''' ackdata, ttl, encodingtype FROM sent '''
|
||||||
''' WHERE status=? and folder='sent' ''', 'broadcastqueued')
|
''' WHERE status=? and folder='sent' ''', dbstr('broadcastqueued'))
|
||||||
|
|
||||||
for row in queryreturn:
|
for row in queryreturn:
|
||||||
fromaddress, subject, body, ackdata, TTL, encoding = row
|
fromaddress, subject, body, ackdata, TTL, encoding = row
|
||||||
|
fromaddress = fromaddress.decode("utf-8", "replace")
|
||||||
|
subject = subject.decode("utf-8", "replace")
|
||||||
|
body = body.decode("utf-8", "replace")
|
||||||
# status
|
# status
|
||||||
_, addressVersionNumber, streamNumber, ripe = \
|
_, addressVersionNumber, streamNumber, ripe = \
|
||||||
decodeAddress(fromaddress)
|
decodeAddress(fromaddress)
|
||||||
|
@ -556,8 +581,7 @@ class singleWorker(StoppableThread):
|
||||||
except ValueError:
|
except ValueError:
|
||||||
queues.UISignalQueue.put((
|
queues.UISignalQueue.put((
|
||||||
'updateSentItemStatusByAckdata', (
|
'updateSentItemStatusByAckdata', (
|
||||||
ackdata,
|
ackdata, _translate(
|
||||||
tr._translate(
|
|
||||||
"MainWindow",
|
"MainWindow",
|
||||||
"Error! Could not find sender address"
|
"Error! Could not find sender address"
|
||||||
" (your address) in the keys.dat file."))
|
" (your address) in the keys.dat file."))
|
||||||
|
@ -572,17 +596,24 @@ class singleWorker(StoppableThread):
|
||||||
queues.UISignalQueue.put((
|
queues.UISignalQueue.put((
|
||||||
'updateSentItemStatusByAckdata', (
|
'updateSentItemStatusByAckdata', (
|
||||||
ackdata,
|
ackdata,
|
||||||
tr._translate(
|
_translate(
|
||||||
"MainWindow",
|
"MainWindow",
|
||||||
"Error, can't send."))
|
"Error, can't send."))
|
||||||
))
|
))
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if not sqlExecute(
|
rowcount = sqlExecute(
|
||||||
'''UPDATE sent SET status='doingbroadcastpow' '''
|
'''UPDATE sent SET status='doingbroadcastpow' '''
|
||||||
''' WHERE ackdata=? AND status='broadcastqueued' '''
|
''' WHERE ackdata=? AND status='broadcastqueued' '''
|
||||||
''' AND folder='sent' ''',
|
''' AND folder='sent' ''',
|
||||||
ackdata):
|
sqlite3.Binary(ackdata))
|
||||||
|
if rowcount < 1:
|
||||||
|
rowcount = sqlExecute(
|
||||||
|
'''UPDATE sent SET status='doingbroadcastpow' '''
|
||||||
|
''' WHERE ackdata=CAST(? AS TEXT) AND status='broadcastqueued' '''
|
||||||
|
''' AND folder='sent' ''',
|
||||||
|
ackdata)
|
||||||
|
if rowcount < 1:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# At this time these pubkeys are 65 bytes long
|
# At this time these pubkeys are 65 bytes long
|
||||||
|
@ -599,7 +630,7 @@ class singleWorker(StoppableThread):
|
||||||
TTL = int(TTL + helper_random.randomrandrange(-300, 300))
|
TTL = int(TTL + helper_random.randomrandrange(-300, 300))
|
||||||
embeddedTime = int(time.time() + TTL)
|
embeddedTime = int(time.time() + TTL)
|
||||||
payload = pack('>Q', embeddedTime)
|
payload = pack('>Q', embeddedTime)
|
||||||
payload += '\x00\x00\x00\x03' # object type: broadcast
|
payload += b'\x00\x00\x00\x03' # object type: broadcast
|
||||||
|
|
||||||
if addressVersionNumber <= 3:
|
if addressVersionNumber <= 3:
|
||||||
payload += encodeVarint(4) # broadcast version
|
payload += encodeVarint(4) # broadcast version
|
||||||
|
@ -615,7 +646,7 @@ class singleWorker(StoppableThread):
|
||||||
tag = doubleHashOfAddressData[32:]
|
tag = doubleHashOfAddressData[32:]
|
||||||
payload += tag
|
payload += tag
|
||||||
else:
|
else:
|
||||||
tag = ''
|
tag = b''
|
||||||
|
|
||||||
dataToEncrypt = encodeVarint(addressVersionNumber)
|
dataToEncrypt = encodeVarint(addressVersionNumber)
|
||||||
dataToEncrypt += encodeVarint(streamNumber)
|
dataToEncrypt += encodeVarint(streamNumber)
|
||||||
|
@ -661,8 +692,7 @@ class singleWorker(StoppableThread):
|
||||||
|
|
||||||
queues.UISignalQueue.put((
|
queues.UISignalQueue.put((
|
||||||
'updateSentItemStatusByAckdata', (
|
'updateSentItemStatusByAckdata', (
|
||||||
ackdata,
|
ackdata, _translate(
|
||||||
tr._translate(
|
|
||||||
"MainWindow",
|
"MainWindow",
|
||||||
"Doing work necessary to send broadcast..."))
|
"Doing work necessary to send broadcast..."))
|
||||||
))
|
))
|
||||||
|
@ -694,23 +724,30 @@ class singleWorker(StoppableThread):
|
||||||
|
|
||||||
queues.UISignalQueue.put((
|
queues.UISignalQueue.put((
|
||||||
'updateSentItemStatusByAckdata', (
|
'updateSentItemStatusByAckdata', (
|
||||||
ackdata,
|
ackdata, _translate(
|
||||||
tr._translate(
|
"MainWindow", "Broadcast sent on {0}"
|
||||||
"MainWindow",
|
).format(l10n.formatTimestamp()))
|
||||||
"Broadcast sent on %1"
|
|
||||||
).arg(l10n.formatTimestamp()))
|
|
||||||
))
|
))
|
||||||
|
|
||||||
# Update the status of the message in the 'sent' table to have
|
# Update the status of the message in the 'sent' table to have
|
||||||
# a 'broadcastsent' status
|
# a 'broadcastsent' status
|
||||||
sqlExecute(
|
rowcount = sqlExecute(
|
||||||
'''UPDATE sent SET msgid=?, status=?, lastactiontime=? '''
|
'''UPDATE sent SET msgid=?, status=?, lastactiontime=? '''
|
||||||
''' WHERE ackdata=? AND folder='sent' ''',
|
''' WHERE ackdata=? AND folder='sent' ''',
|
||||||
inventoryHash, 'broadcastsent', int(time.time()), ackdata
|
sqlite3.Binary(inventoryHash), dbstr('broadcastsent'), int(time.time()), sqlite3.Binary(ackdata)
|
||||||
)
|
)
|
||||||
|
if rowcount < 1:
|
||||||
|
sqlExecute(
|
||||||
|
'''UPDATE sent SET msgid=?, status=?, lastactiontime=? '''
|
||||||
|
''' WHERE ackdata=CAST(? AS TEXT) AND folder='sent' ''',
|
||||||
|
sqlite3.Binary(inventoryHash), 'broadcastsent', int(time.time()), ackdata
|
||||||
|
)
|
||||||
|
|
||||||
def sendMsg(self):
|
def sendMsg(self):
|
||||||
"""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
|
# pylint: disable=too-many-nested-blocks
|
||||||
# Reset just in case
|
# Reset just in case
|
||||||
sqlExecute(
|
sqlExecute(
|
||||||
|
@ -726,6 +763,11 @@ class singleWorker(StoppableThread):
|
||||||
for row in queryreturn:
|
for row in queryreturn:
|
||||||
toaddress, fromaddress, subject, message, \
|
toaddress, fromaddress, subject, message, \
|
||||||
ackdata, status, TTL, retryNumber, encoding = row
|
ackdata, status, TTL, retryNumber, encoding = row
|
||||||
|
toaddress = toaddress.decode("utf-8", "replace")
|
||||||
|
fromaddress = fromaddress.decode("utf-8", "replace")
|
||||||
|
subject = subject.decode("utf-8", "replace")
|
||||||
|
message = message.decode("utf-8", "replace")
|
||||||
|
status = status.decode("utf-8", "replace")
|
||||||
# toStatus
|
# toStatus
|
||||||
_, toAddressVersionNumber, toStreamNumber, toRipe = \
|
_, toAddressVersionNumber, toStreamNumber, toRipe = \
|
||||||
decodeAddress(toaddress)
|
decodeAddress(toaddress)
|
||||||
|
@ -755,7 +797,7 @@ class singleWorker(StoppableThread):
|
||||||
if not sqlExecute(
|
if not sqlExecute(
|
||||||
'''UPDATE sent SET status='doingmsgpow' '''
|
'''UPDATE sent SET status='doingmsgpow' '''
|
||||||
''' WHERE toaddress=? AND status='msgqueued' AND folder='sent' ''',
|
''' WHERE toaddress=? AND status='msgqueued' AND folder='sent' ''',
|
||||||
toaddress
|
dbstr(toaddress)
|
||||||
):
|
):
|
||||||
continue
|
continue
|
||||||
status = 'doingmsgpow'
|
status = 'doingmsgpow'
|
||||||
|
@ -763,7 +805,7 @@ class singleWorker(StoppableThread):
|
||||||
# Let's see if we already have the pubkey in our pubkeys table
|
# Let's see if we already have the pubkey in our pubkeys table
|
||||||
queryreturn = sqlQuery(
|
queryreturn = sqlQuery(
|
||||||
'''SELECT address FROM pubkeys WHERE address=?''',
|
'''SELECT address FROM pubkeys WHERE address=?''',
|
||||||
toaddress
|
dbstr(toaddress)
|
||||||
)
|
)
|
||||||
# If we have the needed pubkey in the pubkey table already,
|
# If we have the needed pubkey in the pubkey table already,
|
||||||
if queryreturn != []:
|
if queryreturn != []:
|
||||||
|
@ -771,7 +813,7 @@ class singleWorker(StoppableThread):
|
||||||
if not sqlExecute(
|
if not sqlExecute(
|
||||||
'''UPDATE sent SET status='doingmsgpow' '''
|
'''UPDATE sent SET status='doingmsgpow' '''
|
||||||
''' WHERE toaddress=? AND status='msgqueued' AND folder='sent' ''',
|
''' WHERE toaddress=? AND status='msgqueued' AND folder='sent' ''',
|
||||||
toaddress
|
dbstr(toaddress)
|
||||||
):
|
):
|
||||||
continue
|
continue
|
||||||
status = 'doingmsgpow'
|
status = 'doingmsgpow'
|
||||||
|
@ -783,31 +825,31 @@ class singleWorker(StoppableThread):
|
||||||
sqlExecute(
|
sqlExecute(
|
||||||
'''UPDATE pubkeys SET usedpersonally='yes' '''
|
'''UPDATE pubkeys SET usedpersonally='yes' '''
|
||||||
''' WHERE address=?''',
|
''' WHERE address=?''',
|
||||||
toaddress
|
dbstr(toaddress)
|
||||||
)
|
)
|
||||||
# We don't have the needed pubkey in the pubkeys table already.
|
# We don't have the needed pubkey in the pubkeys table already.
|
||||||
else:
|
else:
|
||||||
if toAddressVersionNumber <= 3:
|
if toAddressVersionNumber <= 3:
|
||||||
toTag = ''
|
toTag = b''
|
||||||
else:
|
else:
|
||||||
toTag = highlevelcrypto.double_sha512(
|
toTag = highlevelcrypto.double_sha512(
|
||||||
encodeVarint(toAddressVersionNumber)
|
encodeVarint(toAddressVersionNumber)
|
||||||
+ encodeVarint(toStreamNumber) + toRipe
|
+ encodeVarint(toStreamNumber) + toRipe
|
||||||
)[32:]
|
)[32:]
|
||||||
|
toTag_bytes = bytes(toTag)
|
||||||
if toaddress in state.neededPubkeys or \
|
if toaddress in state.neededPubkeys or \
|
||||||
toTag in state.neededPubkeys:
|
toTag_bytes in state.neededPubkeys:
|
||||||
# We already sent a request for the pubkey
|
# We already sent a request for the pubkey
|
||||||
sqlExecute(
|
sqlExecute(
|
||||||
'''UPDATE sent SET status='awaitingpubkey', '''
|
'''UPDATE sent SET status='awaitingpubkey', '''
|
||||||
''' sleeptill=? WHERE toaddress=? '''
|
''' sleeptill=? WHERE toaddress=? '''
|
||||||
''' AND status='msgqueued' ''',
|
''' AND status='msgqueued' ''',
|
||||||
int(time.time()) + 2.5 * 24 * 60 * 60,
|
int(time.time()) + 2.5 * 24 * 60 * 60,
|
||||||
toaddress
|
dbstr(toaddress)
|
||||||
)
|
)
|
||||||
queues.UISignalQueue.put((
|
queues.UISignalQueue.put((
|
||||||
'updateSentItemStatusByToAddress', (
|
'updateSentItemStatusByToAddress', (
|
||||||
toaddress,
|
toaddress, _translate(
|
||||||
tr._translate(
|
|
||||||
"MainWindow",
|
"MainWindow",
|
||||||
"Encryption key was requested earlier."))
|
"Encryption key was requested earlier."))
|
||||||
))
|
))
|
||||||
|
@ -836,7 +878,8 @@ class singleWorker(StoppableThread):
|
||||||
privEncryptionKey = doubleHashOfToAddressData[:32]
|
privEncryptionKey = doubleHashOfToAddressData[:32]
|
||||||
# The second half of the sha512 hash.
|
# The second half of the sha512 hash.
|
||||||
tag = doubleHashOfToAddressData[32:]
|
tag = doubleHashOfToAddressData[32:]
|
||||||
state.neededPubkeys[tag] = (
|
tag_bytes = bytes(tag)
|
||||||
|
state.neededPubkeys[tag_bytes] = (
|
||||||
toaddress,
|
toaddress,
|
||||||
highlevelcrypto.makeCryptor(
|
highlevelcrypto.makeCryptor(
|
||||||
hexlify(privEncryptionKey))
|
hexlify(privEncryptionKey))
|
||||||
|
@ -858,8 +901,8 @@ class singleWorker(StoppableThread):
|
||||||
''' status='awaitingpubkey' or '''
|
''' status='awaitingpubkey' or '''
|
||||||
''' status='doingpubkeypow') AND '''
|
''' status='doingpubkeypow') AND '''
|
||||||
''' folder='sent' ''',
|
''' folder='sent' ''',
|
||||||
toaddress)
|
dbstr(toaddress))
|
||||||
del state.neededPubkeys[tag]
|
del state.neededPubkeys[tag_bytes]
|
||||||
break
|
break
|
||||||
# else:
|
# else:
|
||||||
# There was something wrong with this
|
# There was something wrong with this
|
||||||
|
@ -875,12 +918,11 @@ class singleWorker(StoppableThread):
|
||||||
'''UPDATE sent SET '''
|
'''UPDATE sent SET '''
|
||||||
''' status='doingpubkeypow' WHERE '''
|
''' status='doingpubkeypow' WHERE '''
|
||||||
''' toaddress=? AND status='msgqueued' AND folder='sent' ''',
|
''' toaddress=? AND status='msgqueued' AND folder='sent' ''',
|
||||||
toaddress
|
dbstr(toaddress)
|
||||||
)
|
)
|
||||||
queues.UISignalQueue.put((
|
queues.UISignalQueue.put((
|
||||||
'updateSentItemStatusByToAddress', (
|
'updateSentItemStatusByToAddress', (
|
||||||
toaddress,
|
toaddress, _translate(
|
||||||
tr._translate(
|
|
||||||
"MainWindow",
|
"MainWindow",
|
||||||
"Sending a request for the"
|
"Sending a request for the"
|
||||||
" recipient\'s encryption key."))
|
" recipient\'s encryption key."))
|
||||||
|
@ -901,11 +943,10 @@ class singleWorker(StoppableThread):
|
||||||
|
|
||||||
# if we aren't sending this to ourselves or a chan
|
# if we aren't sending this to ourselves or a chan
|
||||||
if not config.has_section(toaddress):
|
if not config.has_section(toaddress):
|
||||||
state.ackdataForWhichImWatching[ackdata] = 0
|
state.ackdataForWhichImWatching[bytes(ackdata)] = 0
|
||||||
queues.UISignalQueue.put((
|
queues.UISignalQueue.put((
|
||||||
'updateSentItemStatusByAckdata', (
|
'updateSentItemStatusByAckdata', (
|
||||||
ackdata,
|
ackdata, _translate(
|
||||||
tr._translate(
|
|
||||||
"MainWindow",
|
"MainWindow",
|
||||||
"Looking up the receiver\'s public key"))
|
"Looking up the receiver\'s public key"))
|
||||||
))
|
))
|
||||||
|
@ -920,7 +961,7 @@ class singleWorker(StoppableThread):
|
||||||
# is too hard then we'll abort.
|
# is too hard then we'll abort.
|
||||||
queryreturn = sqlQuery(
|
queryreturn = sqlQuery(
|
||||||
'SELECT transmitdata FROM pubkeys WHERE address=?',
|
'SELECT transmitdata FROM pubkeys WHERE address=?',
|
||||||
toaddress)
|
dbstr(toaddress))
|
||||||
for row in queryreturn: # pylint: disable=redefined-outer-name
|
for row in queryreturn: # pylint: disable=redefined-outer-name
|
||||||
pubkeyPayload, = row
|
pubkeyPayload, = row
|
||||||
|
|
||||||
|
@ -962,15 +1003,14 @@ class singleWorker(StoppableThread):
|
||||||
)
|
)
|
||||||
queues.UISignalQueue.put((
|
queues.UISignalQueue.put((
|
||||||
'updateSentItemStatusByAckdata', (
|
'updateSentItemStatusByAckdata', (
|
||||||
ackdata,
|
ackdata, _translate(
|
||||||
tr._translate(
|
|
||||||
"MainWindow",
|
"MainWindow",
|
||||||
"Problem: Destination is a mobile"
|
"Problem: Destination is a mobile"
|
||||||
" device who requests that the"
|
" device who requests that the"
|
||||||
" destination be included in the"
|
" destination be included in the"
|
||||||
" message but this is disallowed in"
|
" message but this is disallowed in"
|
||||||
" your settings. %1"
|
" your settings. {0}"
|
||||||
).arg(l10n.formatTimestamp()))
|
).format(l10n.formatTimestamp()))
|
||||||
))
|
))
|
||||||
# if the human changes their setting and then
|
# if the human changes their setting and then
|
||||||
# sends another message or restarts their client,
|
# sends another message or restarts their client,
|
||||||
|
@ -993,8 +1033,7 @@ class singleWorker(StoppableThread):
|
||||||
defaults.networkDefaultPayloadLengthExtraBytes
|
defaults.networkDefaultPayloadLengthExtraBytes
|
||||||
queues.UISignalQueue.put((
|
queues.UISignalQueue.put((
|
||||||
'updateSentItemStatusByAckdata', (
|
'updateSentItemStatusByAckdata', (
|
||||||
ackdata,
|
ackdata, _translate(
|
||||||
tr._translate(
|
|
||||||
"MainWindow",
|
"MainWindow",
|
||||||
"Doing work necessary to send message.\n"
|
"Doing work necessary to send message.\n"
|
||||||
"There is no required difficulty for"
|
"There is no required difficulty for"
|
||||||
|
@ -1026,32 +1065,19 @@ class singleWorker(StoppableThread):
|
||||||
requiredAverageProofOfWorkNonceTrialsPerByte,
|
requiredAverageProofOfWorkNonceTrialsPerByte,
|
||||||
requiredPayloadLengthExtraBytes
|
requiredPayloadLengthExtraBytes
|
||||||
)
|
)
|
||||||
|
queues.UISignalQueue.put((
|
||||||
queues.UISignalQueue.put(
|
'updateSentItemStatusByAckdata', (
|
||||||
(
|
ackdata, _translate(
|
||||||
'updateSentItemStatusByAckdata',
|
"MainWindow",
|
||||||
(
|
"Doing work necessary to send message.\n"
|
||||||
ackdata,
|
"Receiver\'s required difficulty: {0} and {1}"
|
||||||
tr._translate(
|
).format(
|
||||||
"MainWindow",
|
float(requiredAverageProofOfWorkNonceTrialsPerByte)
|
||||||
"Doing work necessary to send message.\n"
|
/ defaults.networkDefaultProofOfWorkNonceTrialsPerByte,
|
||||||
"Receiver\'s required difficulty: %1"
|
float(requiredPayloadLengthExtraBytes)
|
||||||
" and %2"
|
/ defaults.networkDefaultPayloadLengthExtraBytes
|
||||||
).arg(
|
))
|
||||||
str(
|
))
|
||||||
float(requiredAverageProofOfWorkNonceTrialsPerByte)
|
|
||||||
/ defaults.networkDefaultProofOfWorkNonceTrialsPerByte
|
|
||||||
)
|
|
||||||
).arg(
|
|
||||||
str(
|
|
||||||
float(requiredPayloadLengthExtraBytes)
|
|
||||||
/ defaults.networkDefaultPayloadLengthExtraBytes
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
if status != 'forcepow':
|
if status != 'forcepow':
|
||||||
maxacceptablenoncetrialsperbyte = config.getint(
|
maxacceptablenoncetrialsperbyte = config.getint(
|
||||||
'bitmessagesettings', 'maxacceptablenoncetrialsperbyte')
|
'bitmessagesettings', 'maxacceptablenoncetrialsperbyte')
|
||||||
|
@ -1065,24 +1091,30 @@ class singleWorker(StoppableThread):
|
||||||
if cond1 or cond2:
|
if cond1 or cond2:
|
||||||
# The demanded difficulty is more than
|
# The demanded difficulty is more than
|
||||||
# we are willing to do.
|
# we are willing to do.
|
||||||
sqlExecute(
|
rowcount = sqlExecute(
|
||||||
'''UPDATE sent SET status='toodifficult' '''
|
'''UPDATE sent SET status='toodifficult' '''
|
||||||
''' WHERE ackdata=? AND folder='sent' ''',
|
''' WHERE ackdata=? AND folder='sent' ''',
|
||||||
ackdata)
|
sqlite3.Binary(ackdata))
|
||||||
|
if rowcount < 1:
|
||||||
|
sqlExecute(
|
||||||
|
'''UPDATE sent SET status='toodifficult' '''
|
||||||
|
''' WHERE ackdata=CAST(? AS TEXT) AND folder='sent' ''',
|
||||||
|
ackdata)
|
||||||
queues.UISignalQueue.put((
|
queues.UISignalQueue.put((
|
||||||
'updateSentItemStatusByAckdata', (
|
'updateSentItemStatusByAckdata', (
|
||||||
ackdata,
|
ackdata, _translate(
|
||||||
tr._translate(
|
|
||||||
"MainWindow",
|
"MainWindow",
|
||||||
"Problem: The work demanded by"
|
"Problem: The work demanded by the"
|
||||||
" the recipient (%1 and %2) is"
|
" recipient ({0} and {1}) is more"
|
||||||
" more difficult than you are"
|
" difficult than you are willing"
|
||||||
" willing to do. %3"
|
" to do. {2}"
|
||||||
).arg(str(float(requiredAverageProofOfWorkNonceTrialsPerByte)
|
).format(
|
||||||
/ defaults.networkDefaultProofOfWorkNonceTrialsPerByte)
|
float(requiredAverageProofOfWorkNonceTrialsPerByte)
|
||||||
).arg(str(float(requiredPayloadLengthExtraBytes)
|
/ defaults.networkDefaultProofOfWorkNonceTrialsPerByte,
|
||||||
/ defaults.networkDefaultPayloadLengthExtraBytes)
|
float(requiredPayloadLengthExtraBytes)
|
||||||
).arg(l10n.formatTimestamp()))))
|
/ defaults.networkDefaultPayloadLengthExtraBytes,
|
||||||
|
l10n.formatTimestamp()))
|
||||||
|
))
|
||||||
continue
|
continue
|
||||||
else: # if we are sending a message to ourselves or a chan..
|
else: # if we are sending a message to ourselves or a chan..
|
||||||
self.logger.info('Sending a message.')
|
self.logger.info('Sending a message.')
|
||||||
|
@ -1096,15 +1128,14 @@ class singleWorker(StoppableThread):
|
||||||
except (configparser.NoSectionError, configparser.NoOptionError) as err:
|
except (configparser.NoSectionError, configparser.NoOptionError) as err:
|
||||||
queues.UISignalQueue.put((
|
queues.UISignalQueue.put((
|
||||||
'updateSentItemStatusByAckdata', (
|
'updateSentItemStatusByAckdata', (
|
||||||
ackdata,
|
ackdata, _translate(
|
||||||
tr._translate(
|
|
||||||
"MainWindow",
|
"MainWindow",
|
||||||
"Problem: You are trying to send a"
|
"Problem: You are trying to send a"
|
||||||
" message to yourself or a chan but your"
|
" message to yourself or a chan but your"
|
||||||
" encryption key could not be found in"
|
" encryption key could not be found in"
|
||||||
" the keys.dat file. Could not encrypt"
|
" the keys.dat file. Could not encrypt"
|
||||||
" message. %1"
|
" message. {0}"
|
||||||
).arg(l10n.formatTimestamp()))
|
).format(l10n.formatTimestamp()))
|
||||||
))
|
))
|
||||||
self.logger.error(
|
self.logger.error(
|
||||||
'Error within sendMsg. Could not read the keys'
|
'Error within sendMsg. Could not read the keys'
|
||||||
|
@ -1122,8 +1153,7 @@ class singleWorker(StoppableThread):
|
||||||
defaults.networkDefaultPayloadLengthExtraBytes
|
defaults.networkDefaultPayloadLengthExtraBytes
|
||||||
queues.UISignalQueue.put((
|
queues.UISignalQueue.put((
|
||||||
'updateSentItemStatusByAckdata', (
|
'updateSentItemStatusByAckdata', (
|
||||||
ackdata,
|
ackdata, _translate(
|
||||||
tr._translate(
|
|
||||||
"MainWindow",
|
"MainWindow",
|
||||||
"Doing work necessary to send message."))
|
"Doing work necessary to send message."))
|
||||||
))
|
))
|
||||||
|
@ -1145,8 +1175,7 @@ class singleWorker(StoppableThread):
|
||||||
except ValueError:
|
except ValueError:
|
||||||
queues.UISignalQueue.put((
|
queues.UISignalQueue.put((
|
||||||
'updateSentItemStatusByAckdata', (
|
'updateSentItemStatusByAckdata', (
|
||||||
ackdata,
|
ackdata, _translate(
|
||||||
tr._translate(
|
|
||||||
"MainWindow",
|
"MainWindow",
|
||||||
"Error! Could not find sender address"
|
"Error! Could not find sender address"
|
||||||
" (your address) in the keys.dat file."))
|
" (your address) in the keys.dat file."))
|
||||||
|
@ -1161,7 +1190,7 @@ class singleWorker(StoppableThread):
|
||||||
queues.UISignalQueue.put((
|
queues.UISignalQueue.put((
|
||||||
'updateSentItemStatusByAckdata', (
|
'updateSentItemStatusByAckdata', (
|
||||||
ackdata,
|
ackdata,
|
||||||
tr._translate(
|
_translate(
|
||||||
"MainWindow",
|
"MainWindow",
|
||||||
"Error, can't send."))
|
"Error, can't send."))
|
||||||
))
|
))
|
||||||
|
@ -1201,23 +1230,22 @@ class singleWorker(StoppableThread):
|
||||||
'Not bothering to include ackdata because we are'
|
'Not bothering to include ackdata because we are'
|
||||||
' sending to ourselves or a chan.'
|
' sending to ourselves or a chan.'
|
||||||
)
|
)
|
||||||
fullAckPayload = ''
|
fullAckPayload = b''
|
||||||
elif not protocol.checkBitfield(
|
elif not protocol.checkBitfield(
|
||||||
behaviorBitfield, protocol.BITFIELD_DOESACK):
|
behaviorBitfield, protocol.BITFIELD_DOESACK):
|
||||||
self.logger.info(
|
self.logger.info(
|
||||||
'Not bothering to include ackdata because'
|
'Not bothering to include ackdata because'
|
||||||
' the receiver said that they won\'t relay it anyway.'
|
' the receiver said that they won\'t relay it anyway.'
|
||||||
)
|
)
|
||||||
fullAckPayload = ''
|
fullAckPayload = b''
|
||||||
else:
|
else:
|
||||||
# The fullAckPayload is a normal msg protocol message
|
# The fullAckPayload is a normal msg protocol message
|
||||||
# with the proof of work already completed that the
|
# with the proof of work already completed that the
|
||||||
# receiver of this message can easily send out.
|
# receiver of this message can easily send out.
|
||||||
fullAckPayload = self.generateFullAckMessage(
|
fullAckPayload = self.generateFullAckMessage(ackdata, TTL)
|
||||||
ackdata, toStreamNumber, TTL)
|
|
||||||
payload += encodeVarint(len(fullAckPayload))
|
payload += encodeVarint(len(fullAckPayload))
|
||||||
payload += fullAckPayload
|
payload += fullAckPayload
|
||||||
dataToSign = pack('>Q', embeddedTime) + '\x00\x00\x00\x02' + \
|
dataToSign = pack('>Q', embeddedTime) + b'\x00\x00\x00\x02' + \
|
||||||
encodeVarint(1) + encodeVarint(toStreamNumber) + payload
|
encodeVarint(1) + encodeVarint(toStreamNumber) + payload
|
||||||
signature = highlevelcrypto.sign(
|
signature = highlevelcrypto.sign(
|
||||||
dataToSign, privSigningKeyHex, self.digestAlg)
|
dataToSign, privSigningKeyHex, self.digestAlg)
|
||||||
|
@ -1227,27 +1255,31 @@ class singleWorker(StoppableThread):
|
||||||
# We have assembled the data that will be encrypted.
|
# We have assembled the data that will be encrypted.
|
||||||
try:
|
try:
|
||||||
encrypted = highlevelcrypto.encrypt(
|
encrypted = highlevelcrypto.encrypt(
|
||||||
payload, "04" + hexlify(pubEncryptionKeyBase256)
|
payload, b"04" + hexlify(pubEncryptionKeyBase256)
|
||||||
)
|
)
|
||||||
except: # noqa:E722
|
except: # noqa:E722
|
||||||
self.logger.warning("highlevelcrypto.encrypt didn't work")
|
self.logger.warning("highlevelcrypto.encrypt didn't work")
|
||||||
sqlExecute(
|
rowcount = sqlExecute(
|
||||||
'''UPDATE sent SET status='badkey' WHERE ackdata=? AND folder='sent' ''',
|
'''UPDATE sent SET status='badkey' WHERE ackdata=? AND folder='sent' ''',
|
||||||
ackdata
|
sqlite3.Binary(ackdata)
|
||||||
)
|
)
|
||||||
|
if rowcount < 1:
|
||||||
|
sqlExecute(
|
||||||
|
'''UPDATE sent SET status='badkey' WHERE ackdata=CAST(? AS TEXT) AND folder='sent' ''',
|
||||||
|
ackdata
|
||||||
|
)
|
||||||
queues.UISignalQueue.put((
|
queues.UISignalQueue.put((
|
||||||
'updateSentItemStatusByAckdata', (
|
'updateSentItemStatusByAckdata', (
|
||||||
ackdata,
|
ackdata, _translate(
|
||||||
tr._translate(
|
|
||||||
"MainWindow",
|
"MainWindow",
|
||||||
"Problem: The recipient\'s encryption key is"
|
"Problem: The recipient\'s encryption key is"
|
||||||
" no good. Could not encrypt message. %1"
|
" no good. Could not encrypt message. {0}"
|
||||||
).arg(l10n.formatTimestamp()))
|
).format(l10n.formatTimestamp()))
|
||||||
))
|
))
|
||||||
continue
|
continue
|
||||||
|
|
||||||
encryptedPayload = pack('>Q', embeddedTime)
|
encryptedPayload = pack('>Q', embeddedTime)
|
||||||
encryptedPayload += '\x00\x00\x00\x02' # object type: msg
|
encryptedPayload += b'\x00\x00\x00\x02' # object type: msg
|
||||||
encryptedPayload += encodeVarint(1) # msg version
|
encryptedPayload += encodeVarint(1) # msg version
|
||||||
encryptedPayload += encodeVarint(toStreamNumber) + encrypted
|
encryptedPayload += encodeVarint(toStreamNumber) + encrypted
|
||||||
target = 2 ** 64 / (
|
target = 2 ** 64 / (
|
||||||
|
@ -1306,21 +1338,19 @@ class singleWorker(StoppableThread):
|
||||||
not protocol.checkBitfield(behaviorBitfield, protocol.BITFIELD_DOESACK):
|
not protocol.checkBitfield(behaviorBitfield, protocol.BITFIELD_DOESACK):
|
||||||
queues.UISignalQueue.put((
|
queues.UISignalQueue.put((
|
||||||
'updateSentItemStatusByAckdata', (
|
'updateSentItemStatusByAckdata', (
|
||||||
ackdata,
|
ackdata, _translate(
|
||||||
tr._translate(
|
"MainWindow", "Message sent. Sent at {0}"
|
||||||
"MainWindow",
|
).format(l10n.formatTimestamp()))
|
||||||
"Message sent. Sent at %1"
|
))
|
||||||
).arg(l10n.formatTimestamp()))))
|
|
||||||
else:
|
else:
|
||||||
# not sending to a chan or one of my addresses
|
# not sending to a chan or one of my addresses
|
||||||
queues.UISignalQueue.put((
|
queues.UISignalQueue.put((
|
||||||
'updateSentItemStatusByAckdata', (
|
'updateSentItemStatusByAckdata', (
|
||||||
ackdata,
|
ackdata, _translate(
|
||||||
tr._translate(
|
|
||||||
"MainWindow",
|
"MainWindow",
|
||||||
"Message sent. Waiting for acknowledgement."
|
"Message sent. Waiting for acknowledgement."
|
||||||
" Sent on %1"
|
" Sent on {0}"
|
||||||
).arg(l10n.formatTimestamp()))
|
).format(l10n.formatTimestamp()))
|
||||||
))
|
))
|
||||||
self.logger.info(
|
self.logger.info(
|
||||||
'Broadcasting inv for my msg(within sendmsg function): %s',
|
'Broadcasting inv for my msg(within sendmsg function): %s',
|
||||||
|
@ -1337,12 +1367,19 @@ class singleWorker(StoppableThread):
|
||||||
newStatus = 'msgsent'
|
newStatus = 'msgsent'
|
||||||
# wait 10% past expiration
|
# wait 10% past expiration
|
||||||
sleepTill = int(time.time() + TTL * 1.1)
|
sleepTill = int(time.time() + TTL * 1.1)
|
||||||
sqlExecute(
|
rowcount = sqlExecute(
|
||||||
'''UPDATE sent SET msgid=?, status=?, retrynumber=?, '''
|
'''UPDATE sent SET msgid=?, status=?, retrynumber=?, '''
|
||||||
''' sleeptill=?, lastactiontime=? WHERE ackdata=? AND folder='sent' ''',
|
''' sleeptill=?, lastactiontime=? WHERE ackdata=? AND folder='sent' ''',
|
||||||
inventoryHash, newStatus, retryNumber + 1,
|
sqlite3.Binary(inventoryHash), dbstr(newStatus), retryNumber + 1,
|
||||||
sleepTill, int(time.time()), ackdata
|
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
|
||||||
|
)
|
||||||
|
|
||||||
# If we are sending to ourselves or a chan, let's put
|
# If we are sending to ourselves or a chan, let's put
|
||||||
# the message in our own inbox.
|
# the message in our own inbox.
|
||||||
|
@ -1386,7 +1423,7 @@ class singleWorker(StoppableThread):
|
||||||
'''SELECT retrynumber FROM sent WHERE toaddress=? '''
|
'''SELECT retrynumber FROM sent WHERE toaddress=? '''
|
||||||
''' AND (status='doingpubkeypow' OR status='awaitingpubkey') '''
|
''' AND (status='doingpubkeypow' OR status='awaitingpubkey') '''
|
||||||
''' AND folder='sent' LIMIT 1''',
|
''' AND folder='sent' LIMIT 1''',
|
||||||
toAddress
|
dbstr(toAddress)
|
||||||
)
|
)
|
||||||
if not queryReturn:
|
if not queryReturn:
|
||||||
self.logger.critical(
|
self.logger.critical(
|
||||||
|
@ -1412,10 +1449,11 @@ class singleWorker(StoppableThread):
|
||||||
privEncryptionKey = doubleHashOfAddressData[:32]
|
privEncryptionKey = doubleHashOfAddressData[:32]
|
||||||
# Note that this is the second half of the sha512 hash.
|
# Note that this is the second half of the sha512 hash.
|
||||||
tag = doubleHashOfAddressData[32:]
|
tag = doubleHashOfAddressData[32:]
|
||||||
if tag not in state.neededPubkeys:
|
tag_bytes = bytes(tag)
|
||||||
|
if tag_bytes not in state.neededPubkeys:
|
||||||
# We'll need this for when we receive a pubkey reply:
|
# We'll need this for when we receive a pubkey reply:
|
||||||
# it will be encrypted and we'll need to decrypt it.
|
# it will be encrypted and we'll need to decrypt it.
|
||||||
state.neededPubkeys[tag] = (
|
state.neededPubkeys[tag_bytes] = (
|
||||||
toAddress,
|
toAddress,
|
||||||
highlevelcrypto.makeCryptor(hexlify(privEncryptionKey))
|
highlevelcrypto.makeCryptor(hexlify(privEncryptionKey))
|
||||||
)
|
)
|
||||||
|
@ -1429,7 +1467,7 @@ class singleWorker(StoppableThread):
|
||||||
TTL = TTL + helper_random.randomrandrange(-300, 300)
|
TTL = TTL + helper_random.randomrandrange(-300, 300)
|
||||||
embeddedTime = int(time.time() + TTL)
|
embeddedTime = int(time.time() + TTL)
|
||||||
payload = pack('>Q', embeddedTime)
|
payload = pack('>Q', embeddedTime)
|
||||||
payload += '\x00\x00\x00\x00' # object type: getpubkey
|
payload += b'\x00\x00\x00\x00' # object type: getpubkey
|
||||||
payload += encodeVarint(addressVersionNumber)
|
payload += encodeVarint(addressVersionNumber)
|
||||||
payload += encodeVarint(streamNumber)
|
payload += encodeVarint(streamNumber)
|
||||||
if addressVersionNumber <= 3:
|
if addressVersionNumber <= 3:
|
||||||
|
@ -1446,8 +1484,7 @@ class singleWorker(StoppableThread):
|
||||||
queues.UISignalQueue.put(('updateStatusBar', statusbar))
|
queues.UISignalQueue.put(('updateStatusBar', statusbar))
|
||||||
queues.UISignalQueue.put((
|
queues.UISignalQueue.put((
|
||||||
'updateSentItemStatusByToAddress', (
|
'updateSentItemStatusByToAddress', (
|
||||||
toAddress,
|
toAddress, _translate(
|
||||||
tr._translate(
|
|
||||||
"MainWindow",
|
"MainWindow",
|
||||||
"Doing work necessary to request encryption key."))
|
"Doing work necessary to request encryption key."))
|
||||||
))
|
))
|
||||||
|
@ -1468,33 +1505,34 @@ class singleWorker(StoppableThread):
|
||||||
''' status='awaitingpubkey', retrynumber=?, sleeptill=? '''
|
''' status='awaitingpubkey', retrynumber=?, sleeptill=? '''
|
||||||
''' WHERE toaddress=? AND (status='doingpubkeypow' OR '''
|
''' WHERE toaddress=? AND (status='doingpubkeypow' OR '''
|
||||||
''' status='awaitingpubkey') AND folder='sent' ''',
|
''' status='awaitingpubkey') AND folder='sent' ''',
|
||||||
int(time.time()), retryNumber + 1, sleeptill, toAddress)
|
int(time.time()), retryNumber + 1, sleeptill, dbstr(toAddress))
|
||||||
|
|
||||||
queues.UISignalQueue.put((
|
queues.UISignalQueue.put((
|
||||||
'updateStatusBar',
|
'updateStatusBar', _translate(
|
||||||
tr._translate(
|
|
||||||
"MainWindow",
|
"MainWindow",
|
||||||
"Broadcasting the public key request. This program will"
|
"Broadcasting the public key request. This program will"
|
||||||
" auto-retry if they are offline.")
|
" auto-retry if they are offline.")
|
||||||
))
|
))
|
||||||
queues.UISignalQueue.put((
|
queues.UISignalQueue.put((
|
||||||
'updateSentItemStatusByToAddress', (
|
'updateSentItemStatusByToAddress', (
|
||||||
toAddress,
|
toAddress, _translate(
|
||||||
tr._translate(
|
|
||||||
"MainWindow",
|
"MainWindow",
|
||||||
"Sending public key request. Waiting for reply."
|
"Sending public key request. Waiting for reply."
|
||||||
" Requested at %1"
|
" Requested at {0}"
|
||||||
).arg(l10n.formatTimestamp()))
|
).format(l10n.formatTimestamp()))
|
||||||
))
|
))
|
||||||
|
|
||||||
def generateFullAckMessage(self, ackdata, _, TTL):
|
def generateFullAckMessage(self, ackdata, TTL):
|
||||||
"""
|
"""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
|
# It might be perfectly fine to just use the same TTL for
|
||||||
rather it be more difficult for attackers to associate ackData with the associated msg object. However, users
|
# the ackdata that we use for the message. But I would rather
|
||||||
would want the TTL of the acknowledgement to be about the same as they set for the message itself. So let's set
|
# it be more difficult for attackers to associate ackData with
|
||||||
the TTL of the acknowledgement to be in one of three 'buckets': 1 hour, 7 days, or 28 days, whichever is
|
# the associated msg object. However, users would want the TTL
|
||||||
relatively close to what the user specified.
|
# 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
|
if TTL < 24 * 60 * 60: # 1 day
|
||||||
TTL = 24 * 60 * 60 # 1 day
|
TTL = 24 * 60 * 60 # 1 day
|
||||||
elif TTL < 7 * 24 * 60 * 60: # 1 week
|
elif TTL < 7 * 24 * 60 * 60: # 1 week
|
||||||
|
@ -1511,4 +1549,4 @@ class singleWorker(StoppableThread):
|
||||||
payload = self._doPOWDefaults(
|
payload = self._doPOWDefaults(
|
||||||
payload, TTL, log_prefix='(For ack message)', log_time=True)
|
payload, TTL, log_prefix='(For ack message)', log_time=True)
|
||||||
|
|
||||||
return protocol.CreatePacket('object', payload)
|
return protocol.CreatePacket(b'object', payload)
|
||||||
|
|
|
@ -4,9 +4,9 @@ SMTP client thread for delivering emails
|
||||||
# pylint: disable=unused-variable
|
# pylint: disable=unused-variable
|
||||||
|
|
||||||
import smtplib
|
import smtplib
|
||||||
import urlparse
|
from six.moves.urllib import parse as urlparse
|
||||||
from email.header import Header
|
from email.header import Header
|
||||||
from email.mime.text import MIMEText
|
from six.moves import email_mime_text
|
||||||
|
|
||||||
import queues
|
import queues
|
||||||
import state
|
import state
|
||||||
|
@ -55,7 +55,7 @@ class smtpDeliver(StoppableThread):
|
||||||
u = urlparse.urlparse(dest)
|
u = urlparse.urlparse(dest)
|
||||||
to = urlparse.parse_qs(u.query)['to']
|
to = urlparse.parse_qs(u.query)['to']
|
||||||
client = smtplib.SMTP(u.hostname, u.port)
|
client = smtplib.SMTP(u.hostname, u.port)
|
||||||
msg = MIMEText(body, 'plain', 'utf-8')
|
msg = email_mime_text(body, 'plain', 'utf-8')
|
||||||
msg['Subject'] = Header(subject, 'utf-8')
|
msg['Subject'] = Header(subject, 'utf-8')
|
||||||
msg['From'] = fromAddress + '@' + SMTPDOMAIN
|
msg['From'] = fromAddress + '@' + SMTPDOMAIN
|
||||||
toLabel = map(
|
toLabel = map(
|
||||||
|
|
|
@ -12,6 +12,7 @@ import threading
|
||||||
import time
|
import time
|
||||||
from email.header import decode_header
|
from email.header import decode_header
|
||||||
from email.parser import Parser
|
from email.parser import Parser
|
||||||
|
import sqlite3
|
||||||
|
|
||||||
import queues
|
import queues
|
||||||
from addresses import decodeAddress
|
from addresses import decodeAddress
|
||||||
|
@ -20,6 +21,7 @@ from helper_ackPayload import genAckPayload
|
||||||
from helper_sql import sqlExecute
|
from helper_sql import sqlExecute
|
||||||
from network.threads import StoppableThread
|
from network.threads import StoppableThread
|
||||||
from version import softwareVersion
|
from version import softwareVersion
|
||||||
|
from dbcompat import dbstr
|
||||||
|
|
||||||
SMTPDOMAIN = "bmaddr.lan"
|
SMTPDOMAIN = "bmaddr.lan"
|
||||||
LISTENPORT = 8425
|
LISTENPORT = 8425
|
||||||
|
@ -88,19 +90,19 @@ class smtpServerPyBitmessage(smtpd.SMTPServer):
|
||||||
ackdata = genAckPayload(streamNumber, stealthLevel)
|
ackdata = genAckPayload(streamNumber, stealthLevel)
|
||||||
sqlExecute(
|
sqlExecute(
|
||||||
'''INSERT INTO sent VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)''',
|
'''INSERT INTO sent VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)''',
|
||||||
'',
|
sqlite3.Binary(b''),
|
||||||
toAddress,
|
dbstr(toAddress),
|
||||||
ripe,
|
sqlite3.Binary(ripe),
|
||||||
fromAddress,
|
dbstr(fromAddress),
|
||||||
subject,
|
dbstr(subject),
|
||||||
message,
|
dbstr(message),
|
||||||
ackdata,
|
sqlite3.Binary(ackdata),
|
||||||
int(time.time()), # sentTime (this will never change)
|
int(time.time()), # sentTime (this will never change)
|
||||||
int(time.time()), # lastActionTime
|
int(time.time()), # lastActionTime
|
||||||
0, # sleepTill time. This will get set when the POW gets done.
|
0, # sleepTill time. This will get set when the POW gets done.
|
||||||
'msgqueued',
|
dbstr('msgqueued'),
|
||||||
0, # retryNumber
|
0, # retryNumber
|
||||||
'sent', # folder
|
dbstr('sent'), # folder
|
||||||
2, # encodingtype
|
2, # encodingtype
|
||||||
# not necessary to have a TTL higher than 2 days
|
# not necessary to have a TTL higher than 2 days
|
||||||
min(config.getint('bitmessagesettings', 'ttl'), 86400 * 2)
|
min(config.getint('bitmessagesettings', 'ttl'), 86400 * 2)
|
||||||
|
|
|
@ -8,6 +8,7 @@ import sqlite3
|
||||||
import sys
|
import sys
|
||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
|
from six.moves.reprlib import repr
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import helper_sql
|
import helper_sql
|
||||||
|
@ -38,7 +39,7 @@ class sqlThread(threading.Thread):
|
||||||
helper_sql.sql_available = True
|
helper_sql.sql_available = True
|
||||||
config_ready.wait()
|
config_ready.wait()
|
||||||
self.conn = sqlite3.connect(state.appdata + 'messages.dat')
|
self.conn = sqlite3.connect(state.appdata + 'messages.dat')
|
||||||
self.conn.text_factory = str
|
self.conn.text_factory = bytes
|
||||||
self.cur = self.conn.cursor()
|
self.cur = self.conn.cursor()
|
||||||
|
|
||||||
self.cur.execute('PRAGMA secure_delete = true')
|
self.cur.execute('PRAGMA secure_delete = true')
|
||||||
|
@ -73,7 +74,7 @@ class sqlThread(threading.Thread):
|
||||||
'''INSERT INTO subscriptions VALUES'''
|
'''INSERT INTO subscriptions VALUES'''
|
||||||
'''('Bitmessage new releases/announcements','BM-GtovgYdgs7qXPkoYaRgrLFuFKz1SFpsw',1)''')
|
'''('Bitmessage new releases/announcements','BM-GtovgYdgs7qXPkoYaRgrLFuFKz1SFpsw',1)''')
|
||||||
self.cur.execute(
|
self.cur.execute(
|
||||||
'''CREATE TABLE settings (key blob, value blob, UNIQUE(key) ON CONFLICT REPLACE)''')
|
'''CREATE TABLE settings (key text, value blob, UNIQUE(key) ON CONFLICT REPLACE)''')
|
||||||
self.cur.execute('''INSERT INTO settings VALUES('version','11')''')
|
self.cur.execute('''INSERT INTO settings VALUES('version','11')''')
|
||||||
self.cur.execute('''INSERT INTO settings VALUES('lastvacuumtime',?)''', (
|
self.cur.execute('''INSERT INTO settings VALUES('lastvacuumtime',?)''', (
|
||||||
int(time.time()),))
|
int(time.time()),))
|
||||||
|
@ -542,7 +543,7 @@ class sqlThread(threading.Thread):
|
||||||
shutil.move(
|
shutil.move(
|
||||||
paths.lookupAppdataFolder() + 'messages.dat', paths.lookupExeFolder() + 'messages.dat')
|
paths.lookupAppdataFolder() + 'messages.dat', paths.lookupExeFolder() + 'messages.dat')
|
||||||
self.conn = sqlite3.connect(paths.lookupExeFolder() + 'messages.dat')
|
self.conn = sqlite3.connect(paths.lookupExeFolder() + 'messages.dat')
|
||||||
self.conn.text_factory = str
|
self.conn.text_factory = bytes
|
||||||
self.cur = self.conn.cursor()
|
self.cur = self.conn.cursor()
|
||||||
elif item == 'movemessagstoappdata':
|
elif item == 'movemessagstoappdata':
|
||||||
logger.debug('the sqlThread is moving the messages.dat file to the Appdata folder.')
|
logger.debug('the sqlThread is moving the messages.dat file to the Appdata folder.')
|
||||||
|
@ -568,7 +569,7 @@ class sqlThread(threading.Thread):
|
||||||
shutil.move(
|
shutil.move(
|
||||||
paths.lookupExeFolder() + 'messages.dat', paths.lookupAppdataFolder() + 'messages.dat')
|
paths.lookupExeFolder() + 'messages.dat', paths.lookupAppdataFolder() + 'messages.dat')
|
||||||
self.conn = sqlite3.connect(paths.lookupAppdataFolder() + 'messages.dat')
|
self.conn = sqlite3.connect(paths.lookupAppdataFolder() + 'messages.dat')
|
||||||
self.conn.text_factory = str
|
self.conn.text_factory = bytes
|
||||||
self.cur = self.conn.cursor()
|
self.cur = self.conn.cursor()
|
||||||
elif item == 'deleteandvacuume':
|
elif item == 'deleteandvacuume':
|
||||||
self.cur.execute('''delete from inbox where folder='trash' ''')
|
self.cur.execute('''delete from inbox where folder='trash' ''')
|
||||||
|
|
22
src/dbcompat.py
Normal file
22
src/dbcompat.py
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
import logging
|
||||||
|
import six
|
||||||
|
|
||||||
|
logger = logging.getLogger("default")
|
||||||
|
|
||||||
|
def dbstr(v):
|
||||||
|
if six.PY3:
|
||||||
|
if isinstance(v, str):
|
||||||
|
return v
|
||||||
|
elif isinstance(v, bytes):
|
||||||
|
return v.decode("utf-8", "replace")
|
||||||
|
logger.debug("unexpected type in dbstr(): {}".format(type(v)))
|
||||||
|
return v # hope this never happens..
|
||||||
|
else: # assume six.PY2
|
||||||
|
if isinstance(v, unicode):
|
||||||
|
return v.encode("utf-8", "replace")
|
||||||
|
elif isinstance(v, str):
|
||||||
|
return v
|
||||||
|
elif isinstance(v, bytes):
|
||||||
|
return str(v)
|
||||||
|
logger.debug("unexpected type in dbstr(): {}".format(type(v)))
|
||||||
|
return v # hope this never happens..
|
121
src/depends.py
121
src/depends.py
|
@ -6,6 +6,7 @@ and suggest how it may be installed
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
|
import six
|
||||||
|
|
||||||
# Only really old versions of Python don't have sys.hexversion. We don't
|
# Only really old versions of Python don't have sys.hexversion. We don't
|
||||||
# support them. The logging module was introduced in Python 2.3
|
# support them. The logging module was introduced in Python 2.3
|
||||||
|
@ -17,6 +18,7 @@ if not hasattr(sys, 'hexversion') or sys.hexversion < 0x20300F0:
|
||||||
)
|
)
|
||||||
|
|
||||||
import logging # noqa:E402
|
import logging # noqa:E402
|
||||||
|
from distutils import version
|
||||||
import subprocess # nosec B404
|
import subprocess # nosec B404
|
||||||
|
|
||||||
from importlib import import_module
|
from importlib import import_module
|
||||||
|
@ -53,23 +55,23 @@ PACKAGE_MANAGER = {
|
||||||
}
|
}
|
||||||
|
|
||||||
PACKAGES = {
|
PACKAGES = {
|
||||||
"PyQt4": {
|
"qtpy": {
|
||||||
"OpenBSD": "py-qt4",
|
"OpenBSD": "py-qtpy",
|
||||||
"FreeBSD": "py27-qt4",
|
"FreeBSD": "py27-QtPy",
|
||||||
"Debian": "python-qt4",
|
"Debian": "python-qtpy",
|
||||||
"Ubuntu": "python-qt4",
|
"Ubuntu": "python-qtpy",
|
||||||
"Ubuntu 12": "python-qt4",
|
"Ubuntu 12": "python-qtpy",
|
||||||
"Ubuntu 20": "",
|
"Ubuntu 20": "python-qtpy",
|
||||||
"openSUSE": "python-qt",
|
"openSUSE": "python-QtPy",
|
||||||
"Fedora": "PyQt4",
|
"Fedora": "python2-QtPy",
|
||||||
"Guix": "python2-pyqt@4.11.4",
|
"Guix": "",
|
||||||
"Gentoo": "dev-python/PyQt4",
|
"Gentoo": "dev-python/QtPy",
|
||||||
"optional": True,
|
"optional": True,
|
||||||
"description":
|
"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"
|
" When only running as a daemon, this can be skipped.\n"
|
||||||
"However, you would have to install it manually"
|
"Also maybe you need to install PyQt5 or PyQt4"
|
||||||
" because setuptools does not support PyQt."
|
" if your package manager not installs it as qtpy dependency"
|
||||||
},
|
},
|
||||||
"msgpack": {
|
"msgpack": {
|
||||||
"OpenBSD": "py-msgpack",
|
"OpenBSD": "py-msgpack",
|
||||||
|
@ -156,19 +158,19 @@ detectOS.result = None
|
||||||
def detectOSRelease():
|
def detectOSRelease():
|
||||||
"""Detecting the release of OS"""
|
"""Detecting the release of OS"""
|
||||||
with open("/etc/os-release", 'r') as osRelease:
|
with open("/etc/os-release", 'r') as osRelease:
|
||||||
version = None
|
ver = None
|
||||||
for line in osRelease:
|
for line in osRelease:
|
||||||
if line.startswith("NAME="):
|
if line.startswith("NAME="):
|
||||||
detectOS.result = OS_RELEASE.get(
|
detectOS.result = OS_RELEASE.get(
|
||||||
line.replace('"', '').split("=")[-1].strip().lower())
|
line.replace('"', '').split("=")[-1].strip().lower())
|
||||||
elif line.startswith("VERSION_ID="):
|
elif line.startswith("VERSION_ID="):
|
||||||
try:
|
try:
|
||||||
version = float(line.split("=")[1].replace("\"", ""))
|
ver = float(line.split("=")[1].replace("\"", ""))
|
||||||
except ValueError:
|
except ValueError:
|
||||||
pass
|
pass
|
||||||
if detectOS.result == "Ubuntu" and version < 14:
|
if detectOS.result == "Ubuntu" and ver < 14:
|
||||||
detectOS.result = "Ubuntu 12"
|
detectOS.result = "Ubuntu 12"
|
||||||
elif detectOS.result == "Ubuntu" and version >= 20:
|
elif detectOS.result == "Ubuntu" and ver >= 20:
|
||||||
detectOS.result = "Ubuntu 20"
|
detectOS.result = "Ubuntu 20"
|
||||||
|
|
||||||
|
|
||||||
|
@ -191,7 +193,7 @@ def try_import(module, log_extra=False):
|
||||||
def check_ripemd160():
|
def check_ripemd160():
|
||||||
"""Check availability of the RIPEMD160 hash function"""
|
"""Check availability of the RIPEMD160 hash function"""
|
||||||
try:
|
try:
|
||||||
from fallback import RIPEMD160Hash # pylint: disable=relative-import
|
from fallback import RIPEMD160Hash
|
||||||
except ImportError:
|
except ImportError:
|
||||||
return False
|
return False
|
||||||
return RIPEMD160Hash is not None
|
return RIPEMD160Hash is not None
|
||||||
|
@ -380,33 +382,71 @@ def check_curses():
|
||||||
def check_pyqt():
|
def check_pyqt():
|
||||||
"""Do pyqt dependency check.
|
"""Do pyqt dependency check.
|
||||||
|
|
||||||
Here we are checking for PyQt4 with its version, as for it require
|
Here we are checking for qtpy with its version, as for it require
|
||||||
PyQt 4.8 or later.
|
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(
|
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:
|
if not QtCore:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
logger.info('PyQt Version: %s', QtCore.PYQT_VERSION_STR)
|
try:
|
||||||
logger.info('Qt Version: %s', QtCore.QT_VERSION_STR)
|
logger.info('PyQt Version: %s', QtCore.PYQT_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
|
passed = True
|
||||||
if QtCore.PYQT_VERSION < 0x40800:
|
|
||||||
logger.error(
|
try:
|
||||||
'This version of PyQt is too old. PyBitmessage requries'
|
if version.LooseVersion(QtCore.PYQT_VERSION_STR) < '4.8':
|
||||||
' PyQt 4.8 or later.')
|
logger.error(
|
||||||
passed = False
|
'This version of PyQt is too old. PyBitmessage requries'
|
||||||
if QtCore.QT_VERSION < 0x40700:
|
' PyQt 4.8 or later.')
|
||||||
logger.error(
|
passed = False
|
||||||
'This version of Qt is too old. PyBitmessage requries'
|
except AttributeError:
|
||||||
' Qt 4.7 or later.')
|
# Can be PySide..
|
||||||
passed = False
|
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
|
return passed
|
||||||
|
|
||||||
|
|
||||||
def check_msgpack():
|
def check_msgpack():
|
||||||
"""Do sgpack module check.
|
"""Do msgpack module check.
|
||||||
|
|
||||||
simply checking if msgpack package with all its dependency
|
simply checking if msgpack package with all its dependency
|
||||||
is available or not as recommended for messages coding.
|
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)
|
logger.info('Python version: %s', sys.version)
|
||||||
if sys.hexversion < 0x20704F0:
|
if sys.hexversion < 0x20704F0:
|
||||||
logger.error(
|
logger.error(
|
||||||
'PyBitmessage requires Python 2.7.4 or greater'
|
'PyBitmessage requires Python 2.7.4 or greater.'
|
||||||
' (but not Python 3+)')
|
' Python 2.7.18 is recommended.')
|
||||||
has_all_dependencies = False
|
has_all_dependencies = False
|
||||||
if sys.hexversion >= 0x3000000:
|
|
||||||
logger.error(
|
|
||||||
'PyBitmessage does not support Python 3+. Python 2.7.4'
|
|
||||||
' or greater is required. Python 2.7.18 is recommended.')
|
|
||||||
sys.exit()
|
|
||||||
|
|
||||||
# FIXME: This needs to be uncommented when more of the code is python3 compatible
|
# FIXME: This needs to be uncommented when more of the code is python3 compatible
|
||||||
# if sys.hexversion >= 0x3000000 and sys.hexversion < 0x3060000:
|
# if sys.hexversion >= 0x3000000 and sys.hexversion < 0x3060000:
|
||||||
|
|
|
@ -49,10 +49,12 @@ License: MIT
|
||||||
# pylint: disable=too-many-lines,too-many-branches,too-many-statements,global-statement,too-many-return-statements
|
# pylint: disable=too-many-lines,too-many-branches,too-many-statements,global-statement,too-many-return-statements
|
||||||
# pylint: disable=unused-argument
|
# pylint: disable=unused-argument
|
||||||
|
|
||||||
import collections
|
from collections import OrderedDict
|
||||||
import io
|
from six.moves.collections_abc import Hashable
|
||||||
|
from six.moves import range as xrange
|
||||||
import struct
|
import struct
|
||||||
import sys
|
import sys
|
||||||
|
import six
|
||||||
|
|
||||||
__version__ = "2.4.1"
|
__version__ = "2.4.1"
|
||||||
"Module version string"
|
"Module version string"
|
||||||
|
@ -99,9 +101,9 @@ class Ext: # pylint: disable=old-style-class
|
||||||
if not isinstance(type, int) or not (type >= 0 and type <= 127):
|
if not isinstance(type, int) or not (type >= 0 and type <= 127):
|
||||||
raise TypeError("ext type out of range")
|
raise TypeError("ext type out of range")
|
||||||
# Check data is type bytes
|
# Check data is type bytes
|
||||||
elif sys.version_info[0] == 3 and not isinstance(data, bytes):
|
elif six.PY3 and not isinstance(data, bytes):
|
||||||
raise TypeError("ext data is not type \'bytes\'")
|
raise TypeError("ext data is not type \'bytes\'")
|
||||||
elif sys.version_info[0] == 2 and not isinstance(data, str):
|
elif six.PY2 and not isinstance(data, str):
|
||||||
raise TypeError("ext data is not type \'str\'")
|
raise TypeError("ext data is not type \'str\'")
|
||||||
self.type = type
|
self.type = type
|
||||||
self.data = data
|
self.data = data
|
||||||
|
@ -125,7 +127,7 @@ class Ext: # pylint: disable=old-style-class
|
||||||
String representation of this Ext object.
|
String representation of this Ext object.
|
||||||
"""
|
"""
|
||||||
s = "Ext Object (Type: 0x%02x, Data: " % self.type
|
s = "Ext Object (Type: 0x%02x, Data: " % self.type
|
||||||
s += " ".join(["0x%02x" % ord(self.data[i:i + 1])
|
s += " ".join(["0x%02x" % six.byte2int(self.data[i:i + 1])
|
||||||
for i in xrange(min(len(self.data), 8))])
|
for i in xrange(min(len(self.data), 8))])
|
||||||
if len(self.data) > 8:
|
if len(self.data) > 8:
|
||||||
s += " ..."
|
s += " ..."
|
||||||
|
@ -549,7 +551,7 @@ def _packb2(obj, **options):
|
||||||
'\x82\xa7compact\xc3\xa6schema\x00'
|
'\x82\xa7compact\xc3\xa6schema\x00'
|
||||||
>>>
|
>>>
|
||||||
"""
|
"""
|
||||||
fp = io.BytesIO()
|
fp = six.BytesIO()
|
||||||
_pack2(obj, fp, **options)
|
_pack2(obj, fp, **options)
|
||||||
return fp.getvalue()
|
return fp.getvalue()
|
||||||
|
|
||||||
|
@ -582,7 +584,7 @@ def _packb3(obj, **options):
|
||||||
b'\x82\xa7compact\xc3\xa6schema\x00'
|
b'\x82\xa7compact\xc3\xa6schema\x00'
|
||||||
>>>
|
>>>
|
||||||
"""
|
"""
|
||||||
fp = io.BytesIO()
|
fp = six.BytesIO()
|
||||||
_pack3(obj, fp, **options)
|
_pack3(obj, fp, **options)
|
||||||
return fp.getvalue()
|
return fp.getvalue()
|
||||||
|
|
||||||
|
@ -599,7 +601,7 @@ def _read_except(fp, n):
|
||||||
|
|
||||||
|
|
||||||
def _unpack_integer(code, fp, options):
|
def _unpack_integer(code, fp, options):
|
||||||
if (ord(code) & 0xe0) == 0xe0:
|
if (six.byte2int(code) & 0xe0) == 0xe0:
|
||||||
return struct.unpack("b", code)[0]
|
return struct.unpack("b", code)[0]
|
||||||
elif code == b'\xd0':
|
elif code == b'\xd0':
|
||||||
return struct.unpack("b", _read_except(fp, 1))[0]
|
return struct.unpack("b", _read_except(fp, 1))[0]
|
||||||
|
@ -609,7 +611,7 @@ def _unpack_integer(code, fp, options):
|
||||||
return struct.unpack(">i", _read_except(fp, 4))[0]
|
return struct.unpack(">i", _read_except(fp, 4))[0]
|
||||||
elif code == b'\xd3':
|
elif code == b'\xd3':
|
||||||
return struct.unpack(">q", _read_except(fp, 8))[0]
|
return struct.unpack(">q", _read_except(fp, 8))[0]
|
||||||
elif (ord(code) & 0x80) == 0x00:
|
elif (six.byte2int(code) & 0x80) == 0x00:
|
||||||
return struct.unpack("B", code)[0]
|
return struct.unpack("B", code)[0]
|
||||||
elif code == b'\xcc':
|
elif code == b'\xcc':
|
||||||
return struct.unpack("B", _read_except(fp, 1))[0]
|
return struct.unpack("B", _read_except(fp, 1))[0]
|
||||||
|
@ -619,21 +621,21 @@ def _unpack_integer(code, fp, options):
|
||||||
return struct.unpack(">I", _read_except(fp, 4))[0]
|
return struct.unpack(">I", _read_except(fp, 4))[0]
|
||||||
elif code == b'\xcf':
|
elif code == b'\xcf':
|
||||||
return struct.unpack(">Q", _read_except(fp, 8))[0]
|
return struct.unpack(">Q", _read_except(fp, 8))[0]
|
||||||
raise Exception("logic error, not int: 0x%02x" % ord(code))
|
raise Exception("logic error, not int: 0x%02x" % six.byte2int(code))
|
||||||
|
|
||||||
|
|
||||||
def _unpack_reserved(code, fp, options):
|
def _unpack_reserved(code, fp, options):
|
||||||
if code == b'\xc1':
|
if code == b'\xc1':
|
||||||
raise ReservedCodeException(
|
raise ReservedCodeException(
|
||||||
"encountered reserved code: 0x%02x" % ord(code))
|
"encountered reserved code: 0x%02x" % six.byte2int(code))
|
||||||
raise Exception(
|
raise Exception(
|
||||||
"logic error, not reserved code: 0x%02x" % ord(code))
|
"logic error, not reserved code: 0x%02x" % six.byte2int(code))
|
||||||
|
|
||||||
|
|
||||||
def _unpack_nil(code, fp, options):
|
def _unpack_nil(code, fp, options):
|
||||||
if code == b'\xc0':
|
if code == b'\xc0':
|
||||||
return None
|
return None
|
||||||
raise Exception("logic error, not nil: 0x%02x" % ord(code))
|
raise Exception("logic error, not nil: 0x%02x" % six.byte2int(code))
|
||||||
|
|
||||||
|
|
||||||
def _unpack_boolean(code, fp, options):
|
def _unpack_boolean(code, fp, options):
|
||||||
|
@ -641,7 +643,7 @@ def _unpack_boolean(code, fp, options):
|
||||||
return False
|
return False
|
||||||
elif code == b'\xc3':
|
elif code == b'\xc3':
|
||||||
return True
|
return True
|
||||||
raise Exception("logic error, not boolean: 0x%02x" % ord(code))
|
raise Exception("logic error, not boolean: 0x%02x" % six.byte2int(code))
|
||||||
|
|
||||||
|
|
||||||
def _unpack_float(code, fp, options):
|
def _unpack_float(code, fp, options):
|
||||||
|
@ -649,12 +651,12 @@ def _unpack_float(code, fp, options):
|
||||||
return struct.unpack(">f", _read_except(fp, 4))[0]
|
return struct.unpack(">f", _read_except(fp, 4))[0]
|
||||||
elif code == b'\xcb':
|
elif code == b'\xcb':
|
||||||
return struct.unpack(">d", _read_except(fp, 8))[0]
|
return struct.unpack(">d", _read_except(fp, 8))[0]
|
||||||
raise Exception("logic error, not float: 0x%02x" % ord(code))
|
raise Exception("logic error, not float: 0x%02x" % six.byte2int(code))
|
||||||
|
|
||||||
|
|
||||||
def _unpack_string(code, fp, options):
|
def _unpack_string(code, fp, options):
|
||||||
if (ord(code) & 0xe0) == 0xa0:
|
if (six.byte2int(code) & 0xe0) == 0xa0:
|
||||||
length = ord(code) & ~0xe0
|
length = six.byte2int(code) & ~0xe0
|
||||||
elif code == b'\xd9':
|
elif code == b'\xd9':
|
||||||
length = struct.unpack("B", _read_except(fp, 1))[0]
|
length = struct.unpack("B", _read_except(fp, 1))[0]
|
||||||
elif code == b'\xda':
|
elif code == b'\xda':
|
||||||
|
@ -662,7 +664,7 @@ def _unpack_string(code, fp, options):
|
||||||
elif code == b'\xdb':
|
elif code == b'\xdb':
|
||||||
length = struct.unpack(">I", _read_except(fp, 4))[0]
|
length = struct.unpack(">I", _read_except(fp, 4))[0]
|
||||||
else:
|
else:
|
||||||
raise Exception("logic error, not string: 0x%02x" % ord(code))
|
raise Exception("logic error, not string: 0x%02x" % six.byte2int(code))
|
||||||
|
|
||||||
# Always return raw bytes in compatibility mode
|
# Always return raw bytes in compatibility mode
|
||||||
global compatibility
|
global compatibility
|
||||||
|
@ -686,7 +688,7 @@ def _unpack_binary(code, fp, options):
|
||||||
elif code == b'\xc6':
|
elif code == b'\xc6':
|
||||||
length = struct.unpack(">I", _read_except(fp, 4))[0]
|
length = struct.unpack(">I", _read_except(fp, 4))[0]
|
||||||
else:
|
else:
|
||||||
raise Exception("logic error, not binary: 0x%02x" % ord(code))
|
raise Exception("logic error, not binary: 0x%02x" % six.byte2int(code))
|
||||||
|
|
||||||
return _read_except(fp, length)
|
return _read_except(fp, length)
|
||||||
|
|
||||||
|
@ -709,9 +711,9 @@ def _unpack_ext(code, fp, options):
|
||||||
elif code == b'\xc9':
|
elif code == b'\xc9':
|
||||||
length = struct.unpack(">I", _read_except(fp, 4))[0]
|
length = struct.unpack(">I", _read_except(fp, 4))[0]
|
||||||
else:
|
else:
|
||||||
raise Exception("logic error, not ext: 0x%02x" % ord(code))
|
raise Exception("logic error, not ext: 0x%02x" % six.byte2int(code))
|
||||||
|
|
||||||
ext = Ext(ord(_read_except(fp, 1)), _read_except(fp, length))
|
ext = Ext(six.byte2int(_read_except(fp, 1)), _read_except(fp, length))
|
||||||
|
|
||||||
# Unpack with ext handler, if we have one
|
# Unpack with ext handler, if we have one
|
||||||
ext_handlers = options.get("ext_handlers")
|
ext_handlers = options.get("ext_handlers")
|
||||||
|
@ -722,14 +724,14 @@ def _unpack_ext(code, fp, options):
|
||||||
|
|
||||||
|
|
||||||
def _unpack_array(code, fp, options):
|
def _unpack_array(code, fp, options):
|
||||||
if (ord(code) & 0xf0) == 0x90:
|
if (six.byte2int(code) & 0xf0) == 0x90:
|
||||||
length = (ord(code) & ~0xf0)
|
length = (six.byte2int(code) & ~0xf0)
|
||||||
elif code == b'\xdc':
|
elif code == b'\xdc':
|
||||||
length = struct.unpack(">H", _read_except(fp, 2))[0]
|
length = struct.unpack(">H", _read_except(fp, 2))[0]
|
||||||
elif code == b'\xdd':
|
elif code == b'\xdd':
|
||||||
length = struct.unpack(">I", _read_except(fp, 4))[0]
|
length = struct.unpack(">I", _read_except(fp, 4))[0]
|
||||||
else:
|
else:
|
||||||
raise Exception("logic error, not array: 0x%02x" % ord(code))
|
raise Exception("logic error, not array: 0x%02x" % six.byte2int(code))
|
||||||
|
|
||||||
return [_unpack(fp, options) for _ in xrange(length)]
|
return [_unpack(fp, options) for _ in xrange(length)]
|
||||||
|
|
||||||
|
@ -741,17 +743,17 @@ def _deep_list_to_tuple(obj):
|
||||||
|
|
||||||
|
|
||||||
def _unpack_map(code, fp, options):
|
def _unpack_map(code, fp, options):
|
||||||
if (ord(code) & 0xf0) == 0x80:
|
if (six.byte2int(code) & 0xf0) == 0x80:
|
||||||
length = (ord(code) & ~0xf0)
|
length = (six.byte2int(code) & ~0xf0)
|
||||||
elif code == b'\xde':
|
elif code == b'\xde':
|
||||||
length = struct.unpack(">H", _read_except(fp, 2))[0]
|
length = struct.unpack(">H", _read_except(fp, 2))[0]
|
||||||
elif code == b'\xdf':
|
elif code == b'\xdf':
|
||||||
length = struct.unpack(">I", _read_except(fp, 4))[0]
|
length = struct.unpack(">I", _read_except(fp, 4))[0]
|
||||||
else:
|
else:
|
||||||
raise Exception("logic error, not map: 0x%02x" % ord(code))
|
raise Exception("logic error, not map: 0x%02x" % six.byte2int(code))
|
||||||
|
|
||||||
d = {} if not options.get('use_ordered_dict') \
|
d = {} if not options.get('use_ordered_dict') \
|
||||||
else collections.OrderedDict()
|
else OrderedDict()
|
||||||
for _ in xrange(length):
|
for _ in xrange(length):
|
||||||
# Unpack key
|
# Unpack key
|
||||||
k = _unpack(fp, options)
|
k = _unpack(fp, options)
|
||||||
|
@ -759,7 +761,7 @@ def _unpack_map(code, fp, options):
|
||||||
if isinstance(k, list):
|
if isinstance(k, list):
|
||||||
# Attempt to convert list into a hashable tuple
|
# Attempt to convert list into a hashable tuple
|
||||||
k = _deep_list_to_tuple(k)
|
k = _deep_list_to_tuple(k)
|
||||||
elif not isinstance(k, collections.Hashable):
|
elif not isinstance(k, Hashable):
|
||||||
raise UnhashableKeyException(
|
raise UnhashableKeyException(
|
||||||
"encountered unhashable key: %s, %s" % (str(k), str(type(k))))
|
"encountered unhashable key: %s, %s" % (str(k), str(type(k))))
|
||||||
elif k in d:
|
elif k in d:
|
||||||
|
@ -911,7 +913,7 @@ def _unpackb2(s, **options):
|
||||||
"""
|
"""
|
||||||
if not isinstance(s, (str, bytearray)):
|
if not isinstance(s, (str, bytearray)):
|
||||||
raise TypeError("packed data must be type 'str' or 'bytearray'")
|
raise TypeError("packed data must be type 'str' or 'bytearray'")
|
||||||
return _unpack(io.BytesIO(s), options)
|
return _unpack(six.BytesIO(s), options)
|
||||||
|
|
||||||
|
|
||||||
# For Python 3, expects a bytes object
|
# For Python 3, expects a bytes object
|
||||||
|
@ -957,7 +959,7 @@ def _unpackb3(s, **options):
|
||||||
"""
|
"""
|
||||||
if not isinstance(s, (bytes, bytearray)):
|
if not isinstance(s, (bytes, bytearray)):
|
||||||
raise TypeError("packed data must be type 'bytes' or 'bytearray'")
|
raise TypeError("packed data must be type 'bytes' or 'bytearray'")
|
||||||
return _unpack(io.BytesIO(s), options)
|
return _unpack(six.BytesIO(s), options)
|
||||||
|
|
||||||
#############################################################################
|
#############################################################################
|
||||||
# Module Initialization
|
# Module Initialization
|
||||||
|
@ -990,7 +992,7 @@ def __init():
|
||||||
_float_precision = "single"
|
_float_precision = "single"
|
||||||
|
|
||||||
# Map packb and unpackb to the appropriate version
|
# Map packb and unpackb to the appropriate version
|
||||||
if sys.version_info[0] == 3:
|
if six.PY3:
|
||||||
pack = _pack3
|
pack = _pack3
|
||||||
packb = _packb3
|
packb = _packb3
|
||||||
dump = _pack3
|
dump = _pack3
|
||||||
|
|
|
@ -4,11 +4,12 @@ Insert value into addressbook
|
||||||
|
|
||||||
from bmconfigparser import config
|
from bmconfigparser import config
|
||||||
from helper_sql import sqlExecute
|
from helper_sql import sqlExecute
|
||||||
|
from dbcompat import dbstr
|
||||||
|
|
||||||
|
|
||||||
def insert(address, label):
|
def insert(address, label):
|
||||||
"""perform insert into addressbook"""
|
"""perform insert into addressbook"""
|
||||||
|
|
||||||
if address not in config.addresses():
|
if address not in config.addresses():
|
||||||
return sqlExecute('''INSERT INTO addressbook VALUES (?,?)''', label, address) == 1
|
return sqlExecute('''INSERT INTO addressbook VALUES (?,?)''', dbstr(label), dbstr(address)) == 1
|
||||||
return False
|
return False
|
||||||
|
|
|
@ -19,17 +19,17 @@ def calculateBitcoinAddressFromPubkey(pubkey):
|
||||||
sha = hashlib.new('sha256')
|
sha = hashlib.new('sha256')
|
||||||
sha.update(pubkey)
|
sha.update(pubkey)
|
||||||
ripe.update(sha.digest())
|
ripe.update(sha.digest())
|
||||||
ripeWithProdnetPrefix = '\x00' + ripe.digest()
|
ripeWithProdnetPrefix = b'\x00' + ripe.digest()
|
||||||
|
|
||||||
checksum = hashlib.sha256(hashlib.sha256(
|
checksum = hashlib.sha256(hashlib.sha256(
|
||||||
ripeWithProdnetPrefix).digest()).digest()[:4]
|
ripeWithProdnetPrefix).digest()).digest()[:4]
|
||||||
binaryBitcoinAddress = ripeWithProdnetPrefix + checksum
|
binaryBitcoinAddress = ripeWithProdnetPrefix + checksum
|
||||||
numberOfZeroBytesOnBinaryBitcoinAddress = 0
|
numberOfZeroBytesOnBinaryBitcoinAddress = 0
|
||||||
while binaryBitcoinAddress[0] == '\x00':
|
while binaryBitcoinAddress[0] == b'\x00':
|
||||||
numberOfZeroBytesOnBinaryBitcoinAddress += 1
|
numberOfZeroBytesOnBinaryBitcoinAddress += 1
|
||||||
binaryBitcoinAddress = binaryBitcoinAddress[1:]
|
binaryBitcoinAddress = binaryBitcoinAddress[1:]
|
||||||
base58encoded = arithmetic.changebase(binaryBitcoinAddress, 256, 58)
|
base58encoded = arithmetic.changebase(binaryBitcoinAddress, 256, 58)
|
||||||
return "1" * numberOfZeroBytesOnBinaryBitcoinAddress + base58encoded
|
return b"1" * numberOfZeroBytesOnBinaryBitcoinAddress + base58encoded
|
||||||
|
|
||||||
|
|
||||||
def calculateTestnetAddressFromPubkey(pubkey):
|
def calculateTestnetAddressFromPubkey(pubkey):
|
||||||
|
@ -43,14 +43,14 @@ def calculateTestnetAddressFromPubkey(pubkey):
|
||||||
sha = hashlib.new('sha256')
|
sha = hashlib.new('sha256')
|
||||||
sha.update(pubkey)
|
sha.update(pubkey)
|
||||||
ripe.update(sha.digest())
|
ripe.update(sha.digest())
|
||||||
ripeWithProdnetPrefix = '\x6F' + ripe.digest()
|
ripeWithProdnetPrefix = b'\x6F' + ripe.digest()
|
||||||
|
|
||||||
checksum = hashlib.sha256(hashlib.sha256(
|
checksum = hashlib.sha256(hashlib.sha256(
|
||||||
ripeWithProdnetPrefix).digest()).digest()[:4]
|
ripeWithProdnetPrefix).digest()).digest()[:4]
|
||||||
binaryBitcoinAddress = ripeWithProdnetPrefix + checksum
|
binaryBitcoinAddress = ripeWithProdnetPrefix + checksum
|
||||||
numberOfZeroBytesOnBinaryBitcoinAddress = 0
|
numberOfZeroBytesOnBinaryBitcoinAddress = 0
|
||||||
while binaryBitcoinAddress[0] == '\x00':
|
while binaryBitcoinAddress[0] == b'\x00':
|
||||||
numberOfZeroBytesOnBinaryBitcoinAddress += 1
|
numberOfZeroBytesOnBinaryBitcoinAddress += 1
|
||||||
binaryBitcoinAddress = binaryBitcoinAddress[1:]
|
binaryBitcoinAddress = binaryBitcoinAddress[1:]
|
||||||
base58encoded = arithmetic.changebase(binaryBitcoinAddress, 256, 58)
|
base58encoded = arithmetic.changebase(binaryBitcoinAddress, 256, 58)
|
||||||
return "1" * numberOfZeroBytesOnBinaryBitcoinAddress + base58encoded
|
return b"1" * numberOfZeroBytesOnBinaryBitcoinAddress + base58encoded
|
||||||
|
|
|
@ -1,12 +1,16 @@
|
||||||
"""Helper Inbox performs inbox messages related operations"""
|
"""Helper Inbox performs inbox messages related operations"""
|
||||||
|
|
||||||
|
import sqlite3
|
||||||
|
|
||||||
import queues
|
import queues
|
||||||
from helper_sql import sqlExecute, sqlQuery
|
from helper_sql import sqlExecute, sqlQuery
|
||||||
|
from dbcompat import dbstr
|
||||||
|
|
||||||
|
|
||||||
def insert(t):
|
def insert(t):
|
||||||
"""Perform an insert into the "inbox" table"""
|
"""Perform an insert into the "inbox" table"""
|
||||||
sqlExecute('''INSERT INTO inbox VALUES (?,?,?,?,?,?,?,?,?,?)''', *t)
|
u = [sqlite3.Binary(t[0]), dbstr(t[1]), dbstr(t[2]), dbstr(t[3]), dbstr(t[4]), dbstr(t[5]), dbstr(t[6]), t[7], t[8], sqlite3.Binary(t[9])]
|
||||||
|
sqlExecute('''INSERT INTO inbox VALUES (?,?,?,?,?,?,?,?,?,?)''', *u)
|
||||||
# shouldn't emit changedInboxUnread and displayNewInboxMessage
|
# shouldn't emit changedInboxUnread and displayNewInboxMessage
|
||||||
# at the same time
|
# at the same time
|
||||||
# queues.UISignalQueue.put(('changedInboxUnread', None))
|
# queues.UISignalQueue.put(('changedInboxUnread', None))
|
||||||
|
@ -14,22 +18,31 @@ def insert(t):
|
||||||
|
|
||||||
def trash(msgid):
|
def trash(msgid):
|
||||||
"""Mark a message in the `inbox` as `trash`"""
|
"""Mark a message in the `inbox` as `trash`"""
|
||||||
sqlExecute('''UPDATE inbox SET folder='trash' WHERE msgid=?''', msgid)
|
rowcount = sqlExecute('''UPDATE inbox SET folder='trash' WHERE msgid=?''', sqlite3.Binary(msgid))
|
||||||
|
if rowcount < 1:
|
||||||
|
sqlExecute('''UPDATE inbox SET folder='trash' WHERE msgid=CAST(? AS TEXT)''', msgid)
|
||||||
queues.UISignalQueue.put(('removeInboxRowByMsgid', msgid))
|
queues.UISignalQueue.put(('removeInboxRowByMsgid', msgid))
|
||||||
|
|
||||||
|
|
||||||
def delete(ack_data):
|
def delete(ack_data):
|
||||||
"""Permanent delete message from trash"""
|
"""Permanent delete message from trash"""
|
||||||
sqlExecute("DELETE FROM inbox WHERE msgid = ?", ack_data)
|
rowcount = sqlExecute("DELETE FROM inbox WHERE msgid = ?", sqlite3.Binary(ack_data))
|
||||||
|
if rowcount < 1:
|
||||||
|
sqlExecute("DELETE FROM inbox WHERE msgid = CAST(? AS TEXT)", ack_data)
|
||||||
|
|
||||||
|
|
||||||
def undeleteMessage(msgid):
|
def undeleteMessage(msgid):
|
||||||
"""Undelte the message"""
|
"""Undelte the message"""
|
||||||
sqlExecute('''UPDATE inbox SET folder='inbox' WHERE msgid=?''', msgid)
|
rowcount = sqlExecute('''UPDATE inbox SET folder='inbox' WHERE msgid=?''', sqlite3.Binary(msgid))
|
||||||
|
if rowcount < 1:
|
||||||
|
sqlExecute('''UPDATE inbox SET folder='inbox' WHERE msgid=CAST(? AS TEXT)''', msgid)
|
||||||
|
|
||||||
|
|
||||||
def isMessageAlreadyInInbox(sigHash):
|
def isMessageAlreadyInInbox(sigHash):
|
||||||
"""Check for previous instances of this message"""
|
"""Check for previous instances of this message"""
|
||||||
queryReturn = sqlQuery(
|
queryReturn = sqlQuery(
|
||||||
'''SELECT COUNT(*) FROM inbox WHERE sighash=?''', sigHash)
|
'''SELECT COUNT(*) FROM inbox WHERE sighash=?''', sqlite3.Binary(sigHash))
|
||||||
|
if len(queryReturn) < 1:
|
||||||
|
queryReturn = sqlQuery(
|
||||||
|
'''SELECT COUNT(*) FROM inbox WHERE sighash=CAST(? AS TEXT)''', sigHash)
|
||||||
return queryReturn[0][0] != 0
|
return queryReturn[0][0] != 0
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
Message encoding end decoding functions
|
Message encoding end decoding functions
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import string
|
|
||||||
import zlib
|
import zlib
|
||||||
|
|
||||||
import messagetypes
|
import messagetypes
|
||||||
|
@ -71,7 +70,8 @@ class MsgEncode(object):
|
||||||
|
|
||||||
def encodeSimple(self, message):
|
def encodeSimple(self, message):
|
||||||
"""Handle simple encoding"""
|
"""Handle simple encoding"""
|
||||||
self.data = 'Subject:%(subject)s\nBody:%(body)s' % message
|
data = 'Subject:%(subject)s\nBody:%(body)s' % message
|
||||||
|
self.data = data.encode("utf-8", "replace")
|
||||||
self.length = len(self.data)
|
self.length = len(self.data)
|
||||||
|
|
||||||
def encodeTrivial(self, message):
|
def encodeTrivial(self, message):
|
||||||
|
@ -99,14 +99,14 @@ class MsgDecode(object):
|
||||||
def decodeExtended(self, data):
|
def decodeExtended(self, data):
|
||||||
"""Handle extended encoding"""
|
"""Handle extended encoding"""
|
||||||
dc = zlib.decompressobj()
|
dc = zlib.decompressobj()
|
||||||
tmp = ""
|
tmp = b""
|
||||||
while len(tmp) <= config.safeGetInt("zlib", "maxsize"):
|
while len(tmp) <= config.safeGetInt("zlib", "maxsize"):
|
||||||
try:
|
try:
|
||||||
got = dc.decompress(
|
got = dc.decompress(
|
||||||
data, config.safeGetInt("zlib", "maxsize")
|
data, config.safeGetInt("zlib", "maxsize")
|
||||||
+ 1 - len(tmp))
|
+ 1 - len(tmp))
|
||||||
# EOF
|
# EOF
|
||||||
if got == "":
|
if got == b"":
|
||||||
break
|
break
|
||||||
tmp += got
|
tmp += got
|
||||||
data = dc.unconsumed_tail
|
data = dc.unconsumed_tail
|
||||||
|
@ -142,7 +142,7 @@ class MsgDecode(object):
|
||||||
|
|
||||||
def decodeSimple(self, data):
|
def decodeSimple(self, data):
|
||||||
"""Handle simple encoding"""
|
"""Handle simple encoding"""
|
||||||
bodyPositionIndex = string.find(data, '\nBody:')
|
bodyPositionIndex = data.find(b'\nBody:')
|
||||||
if bodyPositionIndex > 1:
|
if bodyPositionIndex > 1:
|
||||||
subject = data[8:bodyPositionIndex]
|
subject = data[8:bodyPositionIndex]
|
||||||
# Only save and show the first 500 characters of the subject.
|
# Only save and show the first 500 characters of the subject.
|
||||||
|
@ -150,10 +150,11 @@ class MsgDecode(object):
|
||||||
subject = subject[:500]
|
subject = subject[:500]
|
||||||
body = data[bodyPositionIndex + 6:]
|
body = data[bodyPositionIndex + 6:]
|
||||||
else:
|
else:
|
||||||
subject = ''
|
subject = b''
|
||||||
body = data
|
body = data
|
||||||
# Throw away any extra lines (headers) after the subject.
|
# Throw away any extra lines (headers) after the subject.
|
||||||
if subject:
|
if subject:
|
||||||
subject = subject.splitlines()[0]
|
subject = subject.splitlines()[0]
|
||||||
self.subject = subject
|
# Field types should be the same for all message types
|
||||||
self.body = body
|
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 helper_sql import sqlQuery
|
||||||
from tr import _translate
|
from tr import _translate
|
||||||
|
from dbcompat import dbstr
|
||||||
|
|
||||||
|
|
||||||
def search_sql(
|
def search_sql(
|
||||||
|
@ -52,23 +53,23 @@ def search_sql(
|
||||||
if account is not None:
|
if account is not None:
|
||||||
if xAddress == 'both':
|
if xAddress == 'both':
|
||||||
sqlStatementParts.append('(fromaddress = ? OR toaddress = ?)')
|
sqlStatementParts.append('(fromaddress = ? OR toaddress = ?)')
|
||||||
sqlArguments.append(account)
|
sqlArguments.append(dbstr(account))
|
||||||
sqlArguments.append(account)
|
sqlArguments.append(dbstr(account))
|
||||||
else:
|
else:
|
||||||
sqlStatementParts.append(xAddress + ' = ? ')
|
sqlStatementParts.append(xAddress + ' = ? ')
|
||||||
sqlArguments.append(account)
|
sqlArguments.append(dbstr(account))
|
||||||
if folder is not None:
|
if folder is not None:
|
||||||
if folder == 'new':
|
if folder == 'new':
|
||||||
folder = 'inbox'
|
folder = 'inbox'
|
||||||
unreadOnly = True
|
unreadOnly = True
|
||||||
sqlStatementParts.append('folder = ? ')
|
sqlStatementParts.append('folder = ? ')
|
||||||
sqlArguments.append(folder)
|
sqlArguments.append(dbstr(folder))
|
||||||
else:
|
else:
|
||||||
sqlStatementParts.append('folder != ?')
|
sqlStatementParts.append('folder != ?')
|
||||||
sqlArguments.append('trash')
|
sqlArguments.append(dbstr('trash'))
|
||||||
if what:
|
if what:
|
||||||
sqlStatementParts.append('%s LIKE ?' % (where))
|
sqlStatementParts.append('%s LIKE ?' % (where))
|
||||||
sqlArguments.append(what)
|
sqlArguments.append(dbstr(what))
|
||||||
if unreadOnly:
|
if unreadOnly:
|
||||||
sqlStatementParts.append('read = 0')
|
sqlStatementParts.append('read = 0')
|
||||||
if sqlStatementParts:
|
if sqlStatementParts:
|
||||||
|
|
|
@ -4,10 +4,12 @@ Insert values into sent table
|
||||||
|
|
||||||
import time
|
import time
|
||||||
import uuid
|
import uuid
|
||||||
|
import sqlite3
|
||||||
from addresses import decodeAddress
|
from addresses import decodeAddress
|
||||||
from bmconfigparser import config
|
from bmconfigparser import config
|
||||||
from helper_ackPayload import genAckPayload
|
from helper_ackPayload import genAckPayload
|
||||||
from helper_sql import sqlExecute, sqlQuery
|
from helper_sql import sqlExecute, sqlQuery
|
||||||
|
from dbcompat import dbstr
|
||||||
|
|
||||||
|
|
||||||
# pylint: disable=too-many-arguments
|
# pylint: disable=too-many-arguments
|
||||||
|
@ -38,8 +40,8 @@ def insert(msgid=None, toAddress='[Broadcast subscribers]', fromAddress=None, su
|
||||||
|
|
||||||
ttl = ttl if ttl else config.getint('bitmessagesettings', 'ttl')
|
ttl = ttl if ttl else config.getint('bitmessagesettings', 'ttl')
|
||||||
|
|
||||||
t = (msgid, toAddress, ripe, fromAddress, subject, message, ackdata,
|
t = (sqlite3.Binary(msgid), dbstr(toAddress), sqlite3.Binary(ripe), dbstr(fromAddress), dbstr(subject), dbstr(message), sqlite3.Binary(ackdata),
|
||||||
sentTime, lastActionTime, sleeptill, status, retryNumber, folder,
|
sentTime, lastActionTime, sleeptill, dbstr(status), retryNumber, dbstr(folder),
|
||||||
encoding, ttl)
|
encoding, ttl)
|
||||||
|
|
||||||
sqlExecute('''INSERT INTO sent VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)''', *t)
|
sqlExecute('''INSERT INTO sent VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)''', *t)
|
||||||
|
@ -50,20 +52,30 @@ def insert(msgid=None, toAddress='[Broadcast subscribers]', fromAddress=None, su
|
||||||
|
|
||||||
def delete(ack_data):
|
def delete(ack_data):
|
||||||
"""Perform Delete query"""
|
"""Perform Delete query"""
|
||||||
sqlExecute("DELETE FROM sent WHERE ackdata = ?", ack_data)
|
rowcount = sqlExecute("DELETE FROM sent WHERE ackdata = ?", sqlite3.Binary(ack_data))
|
||||||
|
if rowcount < 1:
|
||||||
|
sqlExecute("DELETE FROM sent WHERE ackdata = CAST(? AS TEXT)", ack_data)
|
||||||
|
|
||||||
|
|
||||||
def retrieve_message_details(ack_data):
|
def retrieve_message_details(ack_data):
|
||||||
"""Retrieving Message details"""
|
"""Retrieving Message details"""
|
||||||
data = sqlQuery(
|
data = sqlQuery(
|
||||||
"select toaddress, fromaddress, subject, message, received from inbox where msgid = ?", ack_data
|
"select toaddress, fromaddress, subject, message, received from inbox where msgid = ?", sqlite3.Binary(ack_data)
|
||||||
)
|
)
|
||||||
|
if len(data) < 1:
|
||||||
|
data = sqlQuery(
|
||||||
|
"select toaddress, fromaddress, subject, message, received from inbox where msgid = CAST(? AS TEXT)", ack_data
|
||||||
|
)
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
|
||||||
def trash(ackdata):
|
def trash(ackdata):
|
||||||
"""Mark a message in the `sent` as `trash`"""
|
"""Mark a message in the `sent` as `trash`"""
|
||||||
rowcount = sqlExecute(
|
rowcount = sqlExecute(
|
||||||
'''UPDATE sent SET folder='trash' WHERE ackdata=?''', ackdata
|
'''UPDATE sent SET folder='trash' WHERE ackdata=?''', sqlite3.Binary(ackdata)
|
||||||
)
|
)
|
||||||
|
if rowcount < 1:
|
||||||
|
rowcount = sqlExecute(
|
||||||
|
'''UPDATE sent SET folder='trash' WHERE ackdata=CAST(? AS TEXT)''', ackdata
|
||||||
|
)
|
||||||
return rowcount
|
return rowcount
|
||||||
|
|
|
@ -61,7 +61,7 @@ def sqlQuery(sql_statement, *args):
|
||||||
return queryreturn
|
return queryreturn
|
||||||
|
|
||||||
|
|
||||||
def sqlExecuteChunked(sql_statement, idCount, *args):
|
def sqlExecuteChunked(sql_statement, as_text, idCount, *args):
|
||||||
"""Execute chunked SQL statement to avoid argument limit"""
|
"""Execute chunked SQL statement to avoid argument limit"""
|
||||||
# SQLITE_MAX_VARIABLE_NUMBER,
|
# SQLITE_MAX_VARIABLE_NUMBER,
|
||||||
# unfortunately getting/setting isn't exposed to python
|
# unfortunately getting/setting isn't exposed to python
|
||||||
|
@ -80,9 +80,18 @@ def sqlExecuteChunked(sql_statement, idCount, *args):
|
||||||
chunk_slice = args[
|
chunk_slice = args[
|
||||||
i:i + sqlExecuteChunked.chunkSize - (len(args) - idCount)
|
i:i + sqlExecuteChunked.chunkSize - (len(args) - idCount)
|
||||||
]
|
]
|
||||||
sqlSubmitQueue.put(
|
if as_text:
|
||||||
sql_statement.format(','.join('?' * len(chunk_slice)))
|
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)))
|
||||||
|
)
|
||||||
# first static args, and then iterative chunk
|
# first static args, and then iterative chunk
|
||||||
sqlSubmitQueue.put(
|
sqlSubmitQueue.put(
|
||||||
args[0:len(args) - idCount] + chunk_slice
|
args[0:len(args) - idCount] + chunk_slice
|
||||||
|
|
|
@ -7,6 +7,8 @@ High level cryptographic functions based on `.pyelliptic` OpenSSL bindings.
|
||||||
`More discussion. <https://github.com/yann2192/pyelliptic/issues/32>`_
|
`More discussion. <https://github.com/yann2192/pyelliptic/issues/32>`_
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
from unqstr import unic
|
||||||
|
|
||||||
import hashlib
|
import hashlib
|
||||||
import os
|
import os
|
||||||
from binascii import hexlify
|
from binascii import hexlify
|
||||||
|
@ -102,7 +104,7 @@ def random_keys():
|
||||||
|
|
||||||
def deterministic_keys(passphrase, nonce):
|
def deterministic_keys(passphrase, nonce):
|
||||||
"""Generate keys from *passphrase* and *nonce* (encoded as varint)"""
|
"""Generate keys from *passphrase* and *nonce* (encoded as varint)"""
|
||||||
priv = hashlib.sha512(passphrase + nonce).digest()[:32]
|
priv = hashlib.sha512(unic(passphrase).encode("utf-8", "replace") + nonce).digest()[:32]
|
||||||
pub = pointMult(priv)
|
pub = pointMult(priv)
|
||||||
return priv, pub
|
return priv, pub
|
||||||
|
|
||||||
|
|
|
@ -28,8 +28,6 @@ class Inventory:
|
||||||
|
|
||||||
# cheap inheritance copied from asyncore
|
# cheap inheritance copied from asyncore
|
||||||
def __getattr__(self, attr):
|
def __getattr__(self, attr):
|
||||||
if attr == "__contains__":
|
|
||||||
self.numberOfInventoryLookupsPerformed += 1
|
|
||||||
try:
|
try:
|
||||||
realRet = getattr(self._realInventory, attr)
|
realRet = getattr(self._realInventory, attr)
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
|
@ -40,6 +38,10 @@ class Inventory:
|
||||||
else:
|
else:
|
||||||
return realRet
|
return realRet
|
||||||
|
|
||||||
|
def __contains__(self, key):
|
||||||
|
self.numberOfInventoryLookupsPerformed += 1
|
||||||
|
return key in self._realInventory
|
||||||
|
|
||||||
# hint for pylint: this is dictionary like object
|
# hint for pylint: this is dictionary like object
|
||||||
def __getitem__(self, key):
|
def __getitem__(self, key):
|
||||||
return self._realInventory[key]
|
return self._realInventory[key]
|
||||||
|
|
|
@ -3,8 +3,8 @@
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import sys
|
|
||||||
import time
|
import time
|
||||||
|
import six
|
||||||
|
|
||||||
from six.moves import range
|
from six.moves import range
|
||||||
|
|
||||||
|
@ -61,7 +61,7 @@ if not re.search(r'\d', time.strftime(time_format)):
|
||||||
|
|
||||||
# It seems some systems lie about the encoding they use
|
# It seems some systems lie about the encoding they use
|
||||||
# so we perform comprehensive decoding tests
|
# so we perform comprehensive decoding tests
|
||||||
elif sys.version_info[0] == 2:
|
elif six.PY2:
|
||||||
try:
|
try:
|
||||||
# Check day names
|
# Check day names
|
||||||
for i in range(7):
|
for i in range(7):
|
||||||
|
@ -118,7 +118,7 @@ def formatTimestamp(timestamp=None):
|
||||||
except ValueError:
|
except ValueError:
|
||||||
timestring = time.strftime(time_format)
|
timestring = time.strftime(time_format)
|
||||||
|
|
||||||
if sys.version_info[0] == 2:
|
if six.PY2:
|
||||||
return timestring.decode(encoding)
|
return timestring.decode(encoding)
|
||||||
return timestring
|
return timestring
|
||||||
|
|
||||||
|
|
116
src/namecoin.py
116
src/namecoin.py
|
@ -1,10 +1,10 @@
|
||||||
"""
|
"""
|
||||||
Namecoin queries
|
Namecoin queries
|
||||||
"""
|
"""
|
||||||
# pylint: disable=too-many-branches,protected-access
|
# pylint: disable=too-many-branches
|
||||||
|
|
||||||
import base64
|
import base64
|
||||||
import httplib
|
from six.moves import http_client as httplib
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
import socket
|
import socket
|
||||||
|
@ -14,14 +14,14 @@ import defaults
|
||||||
from addresses import decodeAddress
|
from addresses import decodeAddress
|
||||||
from bmconfigparser import config
|
from bmconfigparser import config
|
||||||
from debug import logger
|
from debug import logger
|
||||||
from tr import _translate # translate
|
from tr import _translate
|
||||||
|
|
||||||
|
|
||||||
configSection = "bitmessagesettings"
|
configSection = "bitmessagesettings"
|
||||||
|
|
||||||
|
|
||||||
class RPCError(Exception):
|
class RPCError(Exception):
|
||||||
"""Error thrown when the RPC call returns an error."""
|
"""Error thrown when the RPC call returns an error."""
|
||||||
|
|
||||||
error = None
|
error = None
|
||||||
|
|
||||||
def __init__(self, data):
|
def __init__(self, data):
|
||||||
|
@ -29,7 +29,7 @@ class RPCError(Exception):
|
||||||
self.error = data
|
self.error = data
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return "{0}: {1}".format(type(self).__name__, self.error)
|
return '{0}: {1}'.format(type(self).__name__, self.error)
|
||||||
|
|
||||||
|
|
||||||
class namecoinConnection(object):
|
class namecoinConnection(object):
|
||||||
|
@ -46,8 +46,8 @@ class namecoinConnection(object):
|
||||||
|
|
||||||
def __init__(self, options=None):
|
def __init__(self, options=None):
|
||||||
"""
|
"""
|
||||||
Initialise. If options are given, take the connection settings from
|
Initialise. If options are given, take the connection settings from
|
||||||
them instead of loading from the configs. This can be used to test
|
them instead of loading from the configs. This can be used to test
|
||||||
currently entered connection settings in the config dialog without
|
currently entered connection settings in the config dialog without
|
||||||
actually changing the values (yet).
|
actually changing the values (yet).
|
||||||
"""
|
"""
|
||||||
|
@ -69,14 +69,14 @@ class namecoinConnection(object):
|
||||||
self.user = options["user"]
|
self.user = options["user"]
|
||||||
self.password = options["password"]
|
self.password = options["password"]
|
||||||
|
|
||||||
assert self.nmctype == "namecoind" or self.nmctype == "nmcontrol"
|
assert self.nmctype in ("namecoind", "nmcontrol")
|
||||||
if self.nmctype == "namecoind":
|
if self.nmctype == "namecoind":
|
||||||
self.con = httplib.HTTPConnection(self.host, self.port, timeout=3)
|
self.con = httplib.HTTPConnection(self.host, self.port, timeout=3)
|
||||||
|
|
||||||
def query(self, identity):
|
def query(self, identity):
|
||||||
"""
|
"""
|
||||||
Query for the bitmessage address corresponding to the given identity
|
Query for the bitmessage address corresponding to the given identity
|
||||||
string. If it doesn't contain a slash, id/ is prepended. We return
|
string. If it doesn't contain a slash, id/ is prepended. We return
|
||||||
the result as (Error, Address) pair, where the Error is an error
|
the result as (Error, Address) pair, where the Error is an error
|
||||||
message to display or None in case of success.
|
message to display or None in case of success.
|
||||||
"""
|
"""
|
||||||
|
@ -96,8 +96,8 @@ class namecoinConnection(object):
|
||||||
res = res["reply"]
|
res = res["reply"]
|
||||||
if not res:
|
if not res:
|
||||||
return (_translate(
|
return (_translate(
|
||||||
"MainWindow", "The name %1 was not found."
|
"MainWindow", "The name {0} was not found."
|
||||||
).arg(identity.decode("utf-8", "ignore")), None)
|
).format(identity.decode("utf-8", "ignore")), None)
|
||||||
else:
|
else:
|
||||||
assert False
|
assert False
|
||||||
except RPCError as exc:
|
except RPCError as exc:
|
||||||
|
@ -107,12 +107,12 @@ class namecoinConnection(object):
|
||||||
else:
|
else:
|
||||||
errmsg = exc.error
|
errmsg = exc.error
|
||||||
return (_translate(
|
return (_translate(
|
||||||
"MainWindow", "The namecoin query failed (%1)"
|
"MainWindow", "The namecoin query failed ({0})"
|
||||||
).arg(errmsg.decode("utf-8", "ignore")), None)
|
).format(errmsg.decode("utf-8", "ignore")), None)
|
||||||
except AssertionError:
|
except AssertionError:
|
||||||
return (_translate(
|
return (_translate(
|
||||||
"MainWindow", "Unknown namecoin interface type: %1"
|
"MainWindow", "Unknown namecoin interface type: {0}"
|
||||||
).arg(self.nmctype.decode("utf-8", "ignore")), None)
|
).format(self.nmctype.decode("utf-8", "ignore")), None)
|
||||||
except Exception:
|
except Exception:
|
||||||
logger.exception("Namecoin query exception")
|
logger.exception("Namecoin query exception")
|
||||||
return (_translate(
|
return (_translate(
|
||||||
|
@ -135,12 +135,12 @@ class namecoinConnection(object):
|
||||||
) if valid else (
|
) if valid else (
|
||||||
_translate(
|
_translate(
|
||||||
"MainWindow",
|
"MainWindow",
|
||||||
"The name %1 has no associated Bitmessage address."
|
"The name {0} has no associated Bitmessage address."
|
||||||
).arg(identity.decode("utf-8", "ignore")), None)
|
).format(identity.decode("utf-8", "ignore")), None)
|
||||||
|
|
||||||
def test(self):
|
def test(self):
|
||||||
"""
|
"""
|
||||||
Test the connection settings. This routine tries to query a "getinfo"
|
Test the connection settings. This routine tries to query a "getinfo"
|
||||||
command, and builds either an error message or a success message with
|
command, and builds either an error message or a success message with
|
||||||
some info from it.
|
some info from it.
|
||||||
"""
|
"""
|
||||||
|
@ -160,11 +160,10 @@ class namecoinConnection(object):
|
||||||
versStr = "0.%d.%d" % (v1, v2)
|
versStr = "0.%d.%d" % (v1, v2)
|
||||||
else:
|
else:
|
||||||
versStr = "0.%d.%d.%d" % (v1, v2, v3)
|
versStr = "0.%d.%d.%d" % (v1, v2, v3)
|
||||||
message = (
|
return (
|
||||||
"success",
|
'success', _translate(
|
||||||
_translate(
|
|
||||||
"MainWindow",
|
"MainWindow",
|
||||||
"Success! Namecoind version %1 running.").arg(
|
"Success! Namecoind version {0} running.").format(
|
||||||
versStr.decode("utf-8", "ignore")))
|
versStr.decode("utf-8", "ignore")))
|
||||||
|
|
||||||
elif self.nmctype == "nmcontrol":
|
elif self.nmctype == "nmcontrol":
|
||||||
|
@ -172,32 +171,24 @@ class namecoinConnection(object):
|
||||||
prefix = "Plugin data running"
|
prefix = "Plugin data running"
|
||||||
if ("reply" in res) and res["reply"][:len(prefix)] == prefix:
|
if ("reply" in res) and res["reply"][:len(prefix)] == prefix:
|
||||||
return (
|
return (
|
||||||
"success",
|
'success', _translate(
|
||||||
_translate(
|
|
||||||
"MainWindow",
|
"MainWindow",
|
||||||
"Success! NMControll is up and running."
|
"Success! NMControll is up and running.")
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
logger.error("Unexpected nmcontrol reply: %s", res)
|
logger.error("Unexpected nmcontrol reply: %s", res)
|
||||||
message = (
|
return (
|
||||||
"failed",
|
'failed', _translate(
|
||||||
_translate(
|
"MainWindow", "Couldn\'t understand NMControl.")
|
||||||
"MainWindow",
|
|
||||||
"Couldn\'t understand NMControl."
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
sys.exit("Unsupported Namecoin type")
|
sys.exit("Unsupported Namecoin type")
|
||||||
|
|
||||||
return message
|
|
||||||
|
|
||||||
except Exception:
|
except Exception:
|
||||||
logger.info("Namecoin connection test failure")
|
logger.info("Namecoin connection test failure")
|
||||||
return (
|
return (
|
||||||
"failed",
|
'failed', _translate(
|
||||||
_translate(
|
|
||||||
"MainWindow", "The connection to namecoin failed.")
|
"MainWindow", "The connection to namecoin failed.")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -245,26 +236,24 @@ class namecoinConnection(object):
|
||||||
"Authorization", "Basic %s" % base64.b64encode(authstr))
|
"Authorization", "Basic %s" % base64.b64encode(authstr))
|
||||||
self.con.endheaders()
|
self.con.endheaders()
|
||||||
self.con.send(data)
|
self.con.send(data)
|
||||||
|
try:
|
||||||
|
resp = self.con.getresponse()
|
||||||
|
result = resp.read()
|
||||||
|
if resp.status != 200:
|
||||||
|
raise Exception(
|
||||||
|
"Namecoin returned status %i: %s" %
|
||||||
|
(resp.status, resp.reason))
|
||||||
|
except: # noqa:E722
|
||||||
|
logger.info("HTTP receive error")
|
||||||
except: # noqa:E722
|
except: # noqa:E722
|
||||||
logger.info("HTTP connection error")
|
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))
|
|
||||||
except: # noqa:E722
|
|
||||||
logger.info("HTTP receive error")
|
|
||||||
return None
|
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def queryServer(self, data):
|
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:
|
try:
|
||||||
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
|
@ -296,23 +285,24 @@ def lookupNamecoinFolder():
|
||||||
"""
|
"""
|
||||||
|
|
||||||
app = "namecoin"
|
app = "namecoin"
|
||||||
from os import path, environ
|
|
||||||
if sys.platform == "darwin":
|
if sys.platform == "darwin":
|
||||||
if "HOME" in environ:
|
try:
|
||||||
dataFolder = path.join(os.environ["HOME"],
|
dataFolder = os.path.join(
|
||||||
"Library/Application Support/", app) + "/"
|
os.getenv("HOME"), "Library/Application Support/", app)
|
||||||
else:
|
except TypeError: # getenv is None
|
||||||
sys.exit(
|
sys.exit(
|
||||||
"Could not find home folder, please report this message"
|
"Could not find home folder, please report this message"
|
||||||
" and your OS X version to the BitMessage Github."
|
" and your OS X version to the BitMessage Github."
|
||||||
)
|
) # TODO: remove exits from utility modules
|
||||||
|
|
||||||
elif "win32" in sys.platform or "win64" in sys.platform:
|
dataFolder = (
|
||||||
dataFolder = path.join(environ["APPDATA"], app) + "\\"
|
os.path.join(os.getenv("APPDATA"), app)
|
||||||
else:
|
if sys.platform.startswith('win') else
|
||||||
dataFolder = path.join(environ["HOME"], ".%s" % app) + "/"
|
os.path.join(os.getenv("HOME"), ".%s" % app)
|
||||||
|
)
|
||||||
|
|
||||||
return dataFolder
|
return dataFolder + os.path.sep
|
||||||
|
|
||||||
|
|
||||||
def ensureNamecoinOptions():
|
def ensureNamecoinOptions():
|
||||||
|
@ -357,8 +347,8 @@ def ensureNamecoinOptions():
|
||||||
nmc.close()
|
nmc.close()
|
||||||
except IOError:
|
except IOError:
|
||||||
logger.warning(
|
logger.warning(
|
||||||
"%s unreadable or missing, Namecoin support deactivated",
|
"%s unreadable or missing, Namecoin support deactivated", nmcConfig
|
||||||
nmcConfig)
|
)
|
||||||
except Exception:
|
except Exception:
|
||||||
logger.warning("Error processing namecoin.conf", exc_info=True)
|
logger.warning("Error processing namecoin.conf", exc_info=True)
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@ __all__ = ["StoppableThread"]
|
||||||
def start(config, state):
|
def start(config, state):
|
||||||
"""Start network threads"""
|
"""Start network threads"""
|
||||||
from .announcethread import AnnounceThread
|
from .announcethread import AnnounceThread
|
||||||
import connectionpool # pylint: disable=relative-import
|
from network import connectionpool
|
||||||
from .addrthread import AddrThread
|
from .addrthread import AddrThread
|
||||||
from .downloadthread import DownloadThread
|
from .downloadthread import DownloadThread
|
||||||
from .invthread import InvThread
|
from .invthread import InvThread
|
||||||
|
|
|
@ -5,11 +5,11 @@ import random
|
||||||
from six.moves import queue
|
from six.moves import queue
|
||||||
|
|
||||||
# magic imports!
|
# magic imports!
|
||||||
import connectionpool
|
from network import connectionpool
|
||||||
from protocol import assembleAddrMessage
|
from protocol import assembleAddrMessage
|
||||||
from network import addrQueue # FIXME: init with queue
|
from network import addrQueue # FIXME: init with queue
|
||||||
|
|
||||||
from threads import StoppableThread
|
from .threads import StoppableThread
|
||||||
|
|
||||||
|
|
||||||
class AddrThread(StoppableThread):
|
class AddrThread(StoppableThread):
|
||||||
|
|
|
@ -7,7 +7,7 @@ import time
|
||||||
|
|
||||||
import network.asyncore_pollchoose as asyncore
|
import network.asyncore_pollchoose as asyncore
|
||||||
import state
|
import state
|
||||||
from threads import BusyError, nonBlocking
|
from .threads import BusyError, nonBlocking
|
||||||
|
|
||||||
|
|
||||||
class ProcessingError(Exception):
|
class ProcessingError(Exception):
|
||||||
|
|
|
@ -4,12 +4,12 @@ Announce myself (node address)
|
||||||
import time
|
import time
|
||||||
|
|
||||||
# magic imports!
|
# magic imports!
|
||||||
import connectionpool
|
from network import connectionpool
|
||||||
from bmconfigparser import config
|
from bmconfigparser import config
|
||||||
from protocol import assembleAddrMessage
|
from protocol import assembleAddrMessage
|
||||||
|
|
||||||
from node import Peer
|
from .node import Peer
|
||||||
from threads import StoppableThread
|
from .threads import StoppableThread
|
||||||
|
|
||||||
|
|
||||||
class AnnounceThread(StoppableThread):
|
class AnnounceThread(StoppableThread):
|
||||||
|
|
|
@ -19,6 +19,7 @@ from errno import (
|
||||||
ENOTCONN, ENOTSOCK, EPIPE, ESHUTDOWN, ETIMEDOUT, EWOULDBLOCK, errorcode
|
ENOTCONN, ENOTSOCK, EPIPE, ESHUTDOWN, ETIMEDOUT, EWOULDBLOCK, errorcode
|
||||||
)
|
)
|
||||||
from threading import current_thread
|
from threading import current_thread
|
||||||
|
from six.moves.reprlib import repr
|
||||||
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
@ -723,21 +724,6 @@ class dispatcher(object):
|
||||||
if why.args[0] not in (ENOTCONN, EBADF):
|
if why.args[0] not in (ENOTCONN, EBADF):
|
||||||
raise
|
raise
|
||||||
|
|
||||||
# cheap inheritance, used to pass all other attribute
|
|
||||||
# references to the underlying socket object.
|
|
||||||
def __getattr__(self, attr):
|
|
||||||
try:
|
|
||||||
retattr = getattr(self.socket, attr)
|
|
||||||
except AttributeError:
|
|
||||||
raise AttributeError(
|
|
||||||
"%s instance has no attribute '%s'"
|
|
||||||
% (self.__class__.__name__, attr))
|
|
||||||
else:
|
|
||||||
msg = "%(me)s.%(attr)s is deprecated; use %(me)s.socket.%(attr)s"\
|
|
||||||
" instead" % {'me': self.__class__.__name__, 'attr': attr}
|
|
||||||
warnings.warn(msg, DeprecationWarning, stacklevel=2)
|
|
||||||
return retattr
|
|
||||||
|
|
||||||
# log and log_info may be overridden to provide more sophisticated
|
# log and log_info may be overridden to provide more sophisticated
|
||||||
# logging and warning methods. In general, log is for 'hit' logging
|
# logging and warning methods. In general, log is for 'hit' logging
|
||||||
# and 'log_info' is for informational, warning and error logging.
|
# and 'log_info' is for informational, warning and error logging.
|
||||||
|
|
|
@ -6,7 +6,7 @@ import time
|
||||||
|
|
||||||
import protocol
|
import protocol
|
||||||
import state
|
import state
|
||||||
import connectionpool
|
import network.connectionpool # use long name to address recursive import
|
||||||
from network import dandelion_ins
|
from network import dandelion_ins
|
||||||
from highlevelcrypto import calculateInventoryHash
|
from highlevelcrypto import calculateInventoryHash
|
||||||
|
|
||||||
|
@ -100,7 +100,7 @@ class BMObject(object): # pylint: disable=too-many-instance-attributes
|
||||||
logger.warning(
|
logger.warning(
|
||||||
'The object has invalid stream: %s', self.streamNumber)
|
'The object has invalid stream: %s', self.streamNumber)
|
||||||
raise BMObjectInvalidError()
|
raise BMObjectInvalidError()
|
||||||
if self.streamNumber not in connectionpool.pool.streams:
|
if self.streamNumber not in network.connectionpool.pool.streams:
|
||||||
logger.debug(
|
logger.debug(
|
||||||
'The streamNumber %i isn\'t one we are interested in.',
|
'The streamNumber %i isn\'t one we are interested in.',
|
||||||
self.streamNumber)
|
self.streamNumber)
|
||||||
|
|
|
@ -9,13 +9,14 @@ import re
|
||||||
import socket
|
import socket
|
||||||
import struct
|
import struct
|
||||||
import time
|
import time
|
||||||
|
import six
|
||||||
|
|
||||||
# magic imports!
|
# magic imports!
|
||||||
import addresses
|
import addresses
|
||||||
import knownnodes
|
from network import knownnodes
|
||||||
import protocol
|
import protocol
|
||||||
import state
|
import state
|
||||||
import connectionpool
|
import network.connectionpool # use long name to address recursive import
|
||||||
from bmconfigparser import config
|
from bmconfigparser import config
|
||||||
from queues import objectProcessorQueue
|
from queues import objectProcessorQueue
|
||||||
from randomtrackingdict import RandomTrackingDict
|
from randomtrackingdict import RandomTrackingDict
|
||||||
|
@ -26,14 +27,27 @@ from network.bmobject import (
|
||||||
BMObjectUnwantedStreamError
|
BMObjectUnwantedStreamError
|
||||||
)
|
)
|
||||||
from network.proxy import ProxyError
|
from network.proxy import ProxyError
|
||||||
|
|
||||||
from network import dandelion_ins, invQueue, portCheckerQueue
|
from network import dandelion_ins, invQueue, portCheckerQueue
|
||||||
from node import Node, Peer
|
from .node import Node, Peer
|
||||||
from objectracker import ObjectTracker, missingObjects
|
from .objectracker import ObjectTracker, missingObjects
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger('default')
|
logger = logging.getLogger('default')
|
||||||
|
|
||||||
|
|
||||||
|
def _hoststr(v):
|
||||||
|
if six.PY3:
|
||||||
|
return v
|
||||||
|
else: # assume six.PY2
|
||||||
|
return str(v)
|
||||||
|
|
||||||
|
def _restr(v):
|
||||||
|
if six.PY3:
|
||||||
|
return v.decode("utf-8", "replace")
|
||||||
|
else: # assume six.PY2
|
||||||
|
return v
|
||||||
|
|
||||||
class BMProtoError(ProxyError):
|
class BMProtoError(ProxyError):
|
||||||
"""A Bitmessage Protocol Base Error"""
|
"""A Bitmessage Protocol Base Error"""
|
||||||
errorCodes = ("Protocol error")
|
errorCodes = ("Protocol error")
|
||||||
|
@ -82,7 +96,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker):
|
||||||
"""Process incoming header"""
|
"""Process incoming header"""
|
||||||
self.magic, self.command, self.payloadLength, self.checksum = \
|
self.magic, self.command, self.payloadLength, self.checksum = \
|
||||||
protocol.Header.unpack(self.read_buf[:protocol.Header.size])
|
protocol.Header.unpack(self.read_buf[:protocol.Header.size])
|
||||||
self.command = self.command.rstrip('\x00')
|
self.command = self.command.rstrip(b'\x00')
|
||||||
if self.magic != protocol.magic:
|
if self.magic != protocol.magic:
|
||||||
# skip 1 byte in order to sync
|
# skip 1 byte in order to sync
|
||||||
self.set_state("bm_header", length=1)
|
self.set_state("bm_header", length=1)
|
||||||
|
@ -107,7 +121,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker):
|
||||||
self.invalid = True
|
self.invalid = True
|
||||||
retval = True
|
retval = True
|
||||||
if not self.fullyEstablished and self.command not in (
|
if not self.fullyEstablished and self.command not in (
|
||||||
"error", "version", "verack"):
|
b"error", b"version", b"verack"):
|
||||||
logger.error(
|
logger.error(
|
||||||
'Received command %s before connection was fully'
|
'Received command %s before connection was fully'
|
||||||
' established, ignoring', self.command)
|
' established, ignoring', self.command)
|
||||||
|
@ -115,7 +129,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker):
|
||||||
if not self.invalid:
|
if not self.invalid:
|
||||||
try:
|
try:
|
||||||
retval = getattr(
|
retval = getattr(
|
||||||
self, "bm_command_" + str(self.command).lower())()
|
self, "bm_command_" + self.command.decode("utf-8", "replace").lower())()
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
# unimplemented command
|
# unimplemented command
|
||||||
logger.debug('unimplemented command %s', self.command)
|
logger.debug('unimplemented command %s', self.command)
|
||||||
|
@ -168,17 +182,17 @@ class BMProto(AdvancedDispatcher, ObjectTracker):
|
||||||
"""Decode node details from the payload"""
|
"""Decode node details from the payload"""
|
||||||
# protocol.checkIPAddress()
|
# protocol.checkIPAddress()
|
||||||
services, host, port = self.decode_payload_content("Q16sH")
|
services, host, port = self.decode_payload_content("Q16sH")
|
||||||
if host[0:12] == '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF':
|
if host[0:12] == b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF':
|
||||||
host = socket.inet_ntop(socket.AF_INET, str(host[12:16]))
|
host = socket.inet_ntop(socket.AF_INET, _hoststr(host[12:16]))
|
||||||
elif host[0:6] == '\xfd\x87\xd8\x7e\xeb\x43':
|
elif host[0:6] == b'\xfd\x87\xd8\x7e\xeb\x43':
|
||||||
# Onion, based on BMD/bitcoind
|
# Onion, based on BMD/bitcoind
|
||||||
host = base64.b32encode(host[6:]).lower() + ".onion"
|
host = base64.b32encode(host[6:]).lower() + b".onion"
|
||||||
else:
|
else:
|
||||||
host = socket.inet_ntop(socket.AF_INET6, str(host))
|
host = socket.inet_ntop(socket.AF_INET6, _hoststr(host))
|
||||||
if host == "":
|
if host == b"":
|
||||||
# This can happen on Windows systems which are not 64-bit
|
# This can happen on Windows systems which are not 64-bit
|
||||||
# compatible so let us drop the IPv6 address.
|
# compatible so let us drop the IPv6 address.
|
||||||
host = socket.inet_ntop(socket.AF_INET, str(host[12:16]))
|
host = socket.inet_ntop(socket.AF_INET, _hoststr(host[12:16]))
|
||||||
|
|
||||||
return Node(services, host, port)
|
return Node(services, host, port)
|
||||||
|
|
||||||
|
@ -334,7 +348,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker):
|
||||||
if now < self.skipUntil:
|
if now < self.skipUntil:
|
||||||
return True
|
return True
|
||||||
for i in items:
|
for i in items:
|
||||||
self.pendingUpload[str(i)] = now
|
self.pendingUpload[i] = now
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def _command_inv(self, extend_dandelion_stem=False):
|
def _command_inv(self, extend_dandelion_stem=False):
|
||||||
|
@ -353,7 +367,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker):
|
||||||
if extend_dandelion_stem and not dandelion_ins.enabled:
|
if extend_dandelion_stem and not dandelion_ins.enabled:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
for i in map(str, items):
|
for i in items:
|
||||||
if i in state.Inventory and not dandelion_ins.hasHash(i):
|
if i in state.Inventory and not dandelion_ins.hasHash(i):
|
||||||
continue
|
continue
|
||||||
if extend_dandelion_stem and not dandelion_ins.hasHash(i):
|
if extend_dandelion_stem and not dandelion_ins.hasHash(i):
|
||||||
|
@ -409,13 +423,17 @@ class BMProto(AdvancedDispatcher, ObjectTracker):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.object.checkObjectByType()
|
self.object.checkObjectByType()
|
||||||
|
if six.PY2:
|
||||||
|
data_buffer = buffer(self.object.data)
|
||||||
|
else: # assume six.PY3
|
||||||
|
data_buffer = memoryview(self.object.data)
|
||||||
objectProcessorQueue.put((
|
objectProcessorQueue.put((
|
||||||
self.object.objectType, buffer(self.object.data))) # noqa: F821
|
self.object.objectType, data_buffer)) # noqa: F821
|
||||||
except BMObjectInvalidError:
|
except BMObjectInvalidError:
|
||||||
BMProto.stopDownloadingObject(self.object.inventoryHash, True)
|
BMProto.stopDownloadingObject(self.object.inventoryHash, True)
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
del missingObjects[self.object.inventoryHash]
|
del missingObjects[bytes(self.object.inventoryHash)]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -424,10 +442,16 @@ class BMProto(AdvancedDispatcher, ObjectTracker):
|
||||||
dandelion_ins.removeHash(
|
dandelion_ins.removeHash(
|
||||||
self.object.inventoryHash, "cycle detection")
|
self.object.inventoryHash, "cycle detection")
|
||||||
|
|
||||||
|
if six.PY2:
|
||||||
|
object_buffer = buffer(self.payload[objectOffset:])
|
||||||
|
tag_buffer = buffer(self.object.tag)
|
||||||
|
else: # assume six.PY3
|
||||||
|
object_buffer = memoryview(self.payload[objectOffset:])
|
||||||
|
tag_buffer = memoryview(self.object.tag)
|
||||||
state.Inventory[self.object.inventoryHash] = (
|
state.Inventory[self.object.inventoryHash] = (
|
||||||
self.object.objectType, self.object.streamNumber,
|
self.object.objectType, self.object.streamNumber,
|
||||||
buffer(self.payload[objectOffset:]), self.object.expiresTime, # noqa: F821
|
object_buffer, self.object.expiresTime, # noqa: F821
|
||||||
buffer(self.object.tag) # noqa: F821
|
tag_buffer # noqa: F821
|
||||||
)
|
)
|
||||||
self.handleReceivedObject(
|
self.handleReceivedObject(
|
||||||
self.object.streamNumber, self.object.inventoryHash)
|
self.object.streamNumber, self.object.inventoryHash)
|
||||||
|
@ -443,11 +467,10 @@ class BMProto(AdvancedDispatcher, ObjectTracker):
|
||||||
"""Incoming addresses, process them"""
|
"""Incoming addresses, process them"""
|
||||||
# not using services
|
# not using services
|
||||||
for seenTime, stream, _, ip, port in self._decode_addr():
|
for seenTime, stream, _, ip, port in self._decode_addr():
|
||||||
ip = str(ip)
|
|
||||||
if (
|
if (
|
||||||
stream not in connectionpool.pool.streams
|
stream not in network.connectionpool.pool.streams
|
||||||
# FIXME: should check against complete list
|
# FIXME: should check against complete list
|
||||||
or ip.startswith('bootstrap')
|
or ip.decode("utf-8", "replace").startswith('bootstrap')
|
||||||
):
|
):
|
||||||
continue
|
continue
|
||||||
decodedIP = protocol.checkIPAddress(ip)
|
decodedIP = protocol.checkIPAddress(ip)
|
||||||
|
@ -477,7 +500,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker):
|
||||||
|
|
||||||
def bm_command_ping(self):
|
def bm_command_ping(self):
|
||||||
"""Incoming ping, respond to it."""
|
"""Incoming ping, respond to it."""
|
||||||
self.append_write_buf(protocol.CreatePacket('pong'))
|
self.append_write_buf(protocol.CreatePacket(b'pong'))
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
@ -526,21 +549,21 @@ class BMProto(AdvancedDispatcher, ObjectTracker):
|
||||||
logger.debug(
|
logger.debug(
|
||||||
'remote node incoming address: %s:%i',
|
'remote node incoming address: %s:%i',
|
||||||
self.destination.host, self.peerNode.port)
|
self.destination.host, self.peerNode.port)
|
||||||
logger.debug('user agent: %s', self.userAgent)
|
logger.debug('user agent: %s', self.userAgent.decode("utf-8", "replace"))
|
||||||
logger.debug('streams: [%s]', ','.join(map(str, self.streams)))
|
logger.debug('streams: [%s]', ','.join(map(str, self.streams)))
|
||||||
if not self.peerValidityChecks():
|
if not self.peerValidityChecks():
|
||||||
# ABORT afterwards
|
# ABORT afterwards
|
||||||
return True
|
return True
|
||||||
self.append_write_buf(protocol.CreatePacket('verack'))
|
self.append_write_buf(protocol.CreatePacket(b'verack'))
|
||||||
self.verackSent = True
|
self.verackSent = True
|
||||||
ua_valid = re.match(
|
ua_valid = re.match(
|
||||||
r'^/[a-zA-Z]+:[0-9]+\.?[\w\s\(\)\./:;-]*/$', self.userAgent)
|
r'^/[a-zA-Z]+:[0-9]+\.?[\w\s\(\)\./:;-]*/$', _restr(self.userAgent))
|
||||||
if not ua_valid:
|
if not ua_valid:
|
||||||
self.userAgent = '/INVALID:0/'
|
self.userAgent = b'/INVALID:0/'
|
||||||
if not self.isOutbound:
|
if not self.isOutbound:
|
||||||
self.append_write_buf(protocol.assembleVersionMessage(
|
self.append_write_buf(protocol.assembleVersionMessage(
|
||||||
self.destination.host, self.destination.port,
|
self.destination.host, self.destination.port,
|
||||||
connectionpool.pool.streams, dandelion_ins.enabled, True,
|
network.connectionpool.pool.streams, dandelion_ins.enabled, True,
|
||||||
nodeid=self.nodeid))
|
nodeid=self.nodeid))
|
||||||
logger.debug(
|
logger.debug(
|
||||||
'%(host)s:%(port)i sending version',
|
'%(host)s:%(port)i sending version',
|
||||||
|
@ -596,7 +619,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker):
|
||||||
'Closed connection to %s because there is no overlapping'
|
'Closed connection to %s because there is no overlapping'
|
||||||
' interest in streams.', self.destination)
|
' interest in streams.', self.destination)
|
||||||
return False
|
return False
|
||||||
if connectionpool.pool.inboundConnections.get(
|
if network.connectionpool.pool.inboundConnections.get(
|
||||||
self.destination):
|
self.destination):
|
||||||
try:
|
try:
|
||||||
if not protocol.checkSocksIP(self.destination.host):
|
if not protocol.checkSocksIP(self.destination.host):
|
||||||
|
@ -614,8 +637,8 @@ class BMProto(AdvancedDispatcher, ObjectTracker):
|
||||||
# or server full report the same error to counter deanonymisation
|
# or server full report the same error to counter deanonymisation
|
||||||
if (
|
if (
|
||||||
Peer(self.destination.host, self.peerNode.port)
|
Peer(self.destination.host, self.peerNode.port)
|
||||||
in connectionpool.pool.inboundConnections
|
in network.connectionpool.pool.inboundConnections
|
||||||
or len(connectionpool.pool)
|
or len(network.connectionpool.pool)
|
||||||
> config.safeGetInt(
|
> config.safeGetInt(
|
||||||
'bitmessagesettings', 'maxtotalconnections')
|
'bitmessagesettings', 'maxtotalconnections')
|
||||||
+ config.safeGetInt(
|
+ config.safeGetInt(
|
||||||
|
@ -627,7 +650,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker):
|
||||||
'Closed connection to %s due to server full'
|
'Closed connection to %s due to server full'
|
||||||
' or duplicate inbound/outbound.', self.destination)
|
' or duplicate inbound/outbound.', self.destination)
|
||||||
return False
|
return False
|
||||||
if connectionpool.pool.isAlreadyConnected(self.nonce):
|
if network.connectionpool.pool.isAlreadyConnected(self.nonce):
|
||||||
self.append_write_buf(protocol.assembleErrorMessage(
|
self.append_write_buf(protocol.assembleErrorMessage(
|
||||||
errorText="I'm connected to myself. Closing connection.",
|
errorText="I'm connected to myself. Closing connection.",
|
||||||
fatal=2))
|
fatal=2))
|
||||||
|
@ -641,7 +664,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker):
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def stopDownloadingObject(hashId, forwardAnyway=False):
|
def stopDownloadingObject(hashId, forwardAnyway=False):
|
||||||
"""Stop downloading object *hashId*"""
|
"""Stop downloading object *hashId*"""
|
||||||
for connection in connectionpool.pool.connections():
|
for connection in network.connectionpool.pool.connections():
|
||||||
try:
|
try:
|
||||||
del connection.objectsNewToMe[hashId]
|
del connection.objectsNewToMe[hashId]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
|
@ -653,7 +676,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker):
|
||||||
except KeyError:
|
except KeyError:
|
||||||
pass
|
pass
|
||||||
try:
|
try:
|
||||||
del missingObjects[hashId]
|
del missingObjects[bytes(hashId)]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ import random
|
||||||
|
|
||||||
from six.moves import queue
|
from six.moves import queue
|
||||||
|
|
||||||
import knownnodes
|
from network import knownnodes
|
||||||
import protocol
|
import protocol
|
||||||
import state
|
import state
|
||||||
|
|
||||||
|
@ -17,10 +17,16 @@ from network import portCheckerQueue
|
||||||
logger = logging.getLogger('default')
|
logger = logging.getLogger('default')
|
||||||
|
|
||||||
|
|
||||||
|
def _ends_with(s, tail):
|
||||||
|
try:
|
||||||
|
return s.endswith(tail)
|
||||||
|
except:
|
||||||
|
return s.decode("utf-8", "replace").endswith(tail)
|
||||||
|
|
||||||
def getDiscoveredPeer():
|
def getDiscoveredPeer():
|
||||||
"""Get a peer from the local peer discovery list"""
|
"""Get a peer from the local peer discovery list"""
|
||||||
try:
|
try:
|
||||||
peer = random.choice(state.discoveredPeers.keys()) # nosec B311
|
peer = random.choice(list(state.discoveredPeers.keys())) # nosec B311
|
||||||
except (IndexError, KeyError):
|
except (IndexError, KeyError):
|
||||||
raise ValueError
|
raise ValueError
|
||||||
try:
|
try:
|
||||||
|
@ -48,7 +54,7 @@ def chooseConnection(stream):
|
||||||
return getDiscoveredPeer()
|
return getDiscoveredPeer()
|
||||||
for _ in range(50):
|
for _ in range(50):
|
||||||
peer = random.choice( # nosec B311
|
peer = random.choice( # nosec B311
|
||||||
knownnodes.knownNodes[stream].keys())
|
list(knownnodes.knownNodes[stream].keys()))
|
||||||
try:
|
try:
|
||||||
peer_info = knownnodes.knownNodes[stream][peer]
|
peer_info = knownnodes.knownNodes[stream][peer]
|
||||||
if peer_info.get('self'):
|
if peer_info.get('self'):
|
||||||
|
@ -60,10 +66,10 @@ def chooseConnection(stream):
|
||||||
if haveOnion:
|
if haveOnion:
|
||||||
# do not connect to raw IP addresses
|
# do not connect to raw IP addresses
|
||||||
# --keep all traffic within Tor overlay
|
# --keep all traffic within Tor overlay
|
||||||
if onionOnly and not peer.host.endswith('.onion'):
|
if onionOnly and not _ends_with(peer.host, '.onion'):
|
||||||
continue
|
continue
|
||||||
# onion addresses have a higher priority when SOCKS
|
# onion addresses have a higher priority when SOCKS
|
||||||
if peer.host.endswith('.onion') and rating > 0:
|
if _ends_with(peer.host, '.onion') and rating > 0:
|
||||||
rating = 1
|
rating = 1
|
||||||
# TODO: need better check
|
# TODO: need better check
|
||||||
elif not peer.host.startswith('bootstrap'):
|
elif not peer.host.startswith('bootstrap'):
|
||||||
|
|
|
@ -9,22 +9,28 @@ import sys
|
||||||
import time
|
import time
|
||||||
import random
|
import random
|
||||||
|
|
||||||
import asyncore_pollchoose as asyncore
|
from network import asyncore_pollchoose as asyncore
|
||||||
import knownnodes
|
from network import knownnodes
|
||||||
import protocol
|
import protocol
|
||||||
import state
|
import state
|
||||||
from bmconfigparser import config
|
from bmconfigparser import config
|
||||||
from connectionchooser import chooseConnection
|
from .connectionchooser import chooseConnection
|
||||||
from node import Peer
|
from .node import Peer
|
||||||
from proxy import Proxy
|
from .proxy import Proxy
|
||||||
from tcp import (
|
from .tcp import (
|
||||||
bootstrap, Socks4aBMConnection, Socks5BMConnection,
|
bootstrap, Socks4aBMConnection, Socks5BMConnection,
|
||||||
TCPConnection, TCPServer)
|
TCPConnection, TCPServer)
|
||||||
from udp import UDPSocket
|
from .udp import UDPSocket
|
||||||
|
|
||||||
logger = logging.getLogger('default')
|
logger = logging.getLogger('default')
|
||||||
|
|
||||||
|
|
||||||
|
def _ends_with(s, tail):
|
||||||
|
try:
|
||||||
|
return s.endswith(tail)
|
||||||
|
except:
|
||||||
|
return s.decode("utf-8", "replace").endswith(tail)
|
||||||
|
|
||||||
class BMConnectionPool(object):
|
class BMConnectionPool(object):
|
||||||
"""Pool of all existing connections"""
|
"""Pool of all existing connections"""
|
||||||
# pylint: disable=too-many-instance-attributes
|
# pylint: disable=too-many-instance-attributes
|
||||||
|
@ -78,7 +84,7 @@ class BMConnectionPool(object):
|
||||||
Shortcut for combined list of connections from
|
Shortcut for combined list of connections from
|
||||||
`inboundConnections` and `outboundConnections` dicts
|
`inboundConnections` and `outboundConnections` dicts
|
||||||
"""
|
"""
|
||||||
return self.inboundConnections.values() + self.outboundConnections.values()
|
return list(self.inboundConnections.values()) + list(self.outboundConnections.values())
|
||||||
|
|
||||||
def establishedConnections(self):
|
def establishedConnections(self):
|
||||||
"""Shortcut for list of connections having fullyEstablished == True"""
|
"""Shortcut for list of connections having fullyEstablished == True"""
|
||||||
|
@ -160,8 +166,8 @@ class BMConnectionPool(object):
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def getListeningIP():
|
def getListeningIP():
|
||||||
"""What IP are we supposed to be listening on?"""
|
"""What IP are we supposed to be listening on?"""
|
||||||
if config.safeGet(
|
if _ends_with(config.safeGet(
|
||||||
"bitmessagesettings", "onionhostname", "").endswith(".onion"):
|
"bitmessagesettings", "onionhostname", ""), ".onion"):
|
||||||
host = config.safeGet(
|
host = config.safeGet(
|
||||||
"bitmessagesettings", "onionbindip")
|
"bitmessagesettings", "onionbindip")
|
||||||
else:
|
else:
|
||||||
|
@ -314,7 +320,7 @@ class BMConnectionPool(object):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if chosen.host.endswith(".onion") and Proxy.onion_proxy:
|
if _ends_with(chosen.host, ".onion") and Proxy.onion_proxy:
|
||||||
if onionsocksproxytype == "SOCKS5":
|
if onionsocksproxytype == "SOCKS5":
|
||||||
self.addConnection(Socks5BMConnection(chosen))
|
self.addConnection(Socks5BMConnection(chosen))
|
||||||
elif onionsocksproxytype == "SOCKS4a":
|
elif onionsocksproxytype == "SOCKS4a":
|
||||||
|
@ -381,14 +387,14 @@ class BMConnectionPool(object):
|
||||||
minTx -= 300 - 20
|
minTx -= 300 - 20
|
||||||
if i.lastTx < minTx:
|
if i.lastTx < minTx:
|
||||||
if i.fullyEstablished:
|
if i.fullyEstablished:
|
||||||
i.append_write_buf(protocol.CreatePacket('ping'))
|
i.append_write_buf(protocol.CreatePacket(b'ping'))
|
||||||
else:
|
else:
|
||||||
i.close_reason = "Timeout (%is)" % (
|
i.close_reason = "Timeout (%is)" % (
|
||||||
time.time() - i.lastTx)
|
time.time() - i.lastTx)
|
||||||
i.set_state("close")
|
i.set_state("close")
|
||||||
for i in (
|
for i in (
|
||||||
self.connections()
|
self.connections()
|
||||||
+ self.listeningSockets.values() + self.udpSockets.values()
|
+ list(self.listeningSockets.values()) + list(self.udpSockets.values())
|
||||||
):
|
):
|
||||||
if not (i.accepting or i.connecting or i.connected):
|
if not (i.accepting or i.connecting or i.connected):
|
||||||
reaper.append(i)
|
reaper.append(i)
|
||||||
|
|
|
@ -6,6 +6,8 @@ from collections import namedtuple
|
||||||
from random import choice, expovariate, sample
|
from random import choice, expovariate, sample
|
||||||
from threading import RLock
|
from threading import RLock
|
||||||
from time import time
|
from time import time
|
||||||
|
import six
|
||||||
|
from binascii import hexlify
|
||||||
|
|
||||||
|
|
||||||
# randomise routes after 600 seconds
|
# randomise routes after 600 seconds
|
||||||
|
@ -64,7 +66,7 @@ class Dandelion: # pylint: disable=old-style-class
|
||||||
"""Add inventory vector to dandelion stem return status of dandelion enabled"""
|
"""Add inventory vector to dandelion stem return status of dandelion enabled"""
|
||||||
assert self.enabled is not None
|
assert self.enabled is not None
|
||||||
with self.lock:
|
with self.lock:
|
||||||
self.hashMap[hashId] = Stem(
|
self.hashMap[bytes(hashId)] = Stem(
|
||||||
self.getNodeStem(source),
|
self.getNodeStem(source),
|
||||||
stream,
|
stream,
|
||||||
self.poissonTimeout())
|
self.poissonTimeout())
|
||||||
|
@ -75,9 +77,10 @@ class Dandelion: # pylint: disable=old-style-class
|
||||||
include streams, we only learn this after receiving the object)
|
include streams, we only learn this after receiving the object)
|
||||||
"""
|
"""
|
||||||
with self.lock:
|
with self.lock:
|
||||||
if hashId in self.hashMap:
|
hashId_bytes = bytes(hashId)
|
||||||
self.hashMap[hashId] = Stem(
|
if hashId_bytes in self.hashMap:
|
||||||
self.hashMap[hashId].child,
|
self.hashMap[hashId_bytes] = Stem(
|
||||||
|
self.hashMap[hashId_bytes].child,
|
||||||
stream,
|
stream,
|
||||||
self.poissonTimeout())
|
self.poissonTimeout())
|
||||||
|
|
||||||
|
@ -86,20 +89,20 @@ class Dandelion: # pylint: disable=old-style-class
|
||||||
if logger.isEnabledFor(logging.DEBUG):
|
if logger.isEnabledFor(logging.DEBUG):
|
||||||
logger.debug(
|
logger.debug(
|
||||||
'%s entering fluff mode due to %s.',
|
'%s entering fluff mode due to %s.',
|
||||||
''.join('%02x' % ord(i) for i in hashId), reason)
|
hexlify(hashId), reason)
|
||||||
with self.lock:
|
with self.lock:
|
||||||
try:
|
try:
|
||||||
del self.hashMap[hashId]
|
del self.hashMap[bytes(hashId)]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def hasHash(self, hashId):
|
def hasHash(self, hashId):
|
||||||
"""Is inventory vector in stem mode?"""
|
"""Is inventory vector in stem mode?"""
|
||||||
return hashId in self.hashMap
|
return bytes(hashId) in self.hashMap
|
||||||
|
|
||||||
def objectChildStem(self, hashId):
|
def objectChildStem(self, hashId):
|
||||||
"""Child (i.e. next) node for an inventory vector during stem mode"""
|
"""Child (i.e. next) node for an inventory vector during stem mode"""
|
||||||
return self.hashMap[hashId].child
|
return self.hashMap[bytes(hashId)].child
|
||||||
|
|
||||||
def maybeAddStem(self, connection, invQueue):
|
def maybeAddStem(self, connection, invQueue):
|
||||||
"""
|
"""
|
||||||
|
@ -111,12 +114,12 @@ class Dandelion: # pylint: disable=old-style-class
|
||||||
with self.lock:
|
with self.lock:
|
||||||
if len(self.stem) < MAX_STEMS:
|
if len(self.stem) < MAX_STEMS:
|
||||||
self.stem.append(connection)
|
self.stem.append(connection)
|
||||||
for k in (k for k, v in self.nodeMap.iteritems() if v is None):
|
for k in (k for k, v in six.iteritems(self.nodeMap) if v is None):
|
||||||
self.nodeMap[k] = connection
|
self.nodeMap[k] = connection
|
||||||
for k, v in {
|
for k, v in six.iteritems({
|
||||||
k: v for k, v in self.hashMap.iteritems()
|
k: v for k, v in six.iteritems(self.hashMap)
|
||||||
if v.child is None
|
if v.child is None
|
||||||
}.iteritems():
|
}):
|
||||||
self.hashMap[k] = Stem(
|
self.hashMap[k] = Stem(
|
||||||
connection, v.stream, self.poissonTimeout())
|
connection, v.stream, self.poissonTimeout())
|
||||||
invQueue.put((v.stream, k, v.child))
|
invQueue.put((v.stream, k, v.child))
|
||||||
|
@ -132,14 +135,14 @@ class Dandelion: # pylint: disable=old-style-class
|
||||||
self.stem.remove(connection)
|
self.stem.remove(connection)
|
||||||
# active mappings to pointing to the removed node
|
# active mappings to pointing to the removed node
|
||||||
for k in (
|
for k in (
|
||||||
k for k, v in self.nodeMap.iteritems()
|
k for k, v in six.iteritems(self.nodeMap)
|
||||||
if v == connection
|
if v == connection
|
||||||
):
|
):
|
||||||
self.nodeMap[k] = None
|
self.nodeMap[k] = None
|
||||||
for k, v in {
|
for k, v in six.iteritems({
|
||||||
k: v for k, v in self.hashMap.iteritems()
|
k: v for k, v in six.iteritems(self.hashMap)
|
||||||
if v.child == connection
|
if v.child == connection
|
||||||
}.iteritems():
|
}):
|
||||||
self.hashMap[k] = Stem(
|
self.hashMap[k] = Stem(
|
||||||
None, v.stream, self.poissonTimeout())
|
None, v.stream, self.poissonTimeout())
|
||||||
|
|
||||||
|
@ -180,7 +183,7 @@ class Dandelion: # pylint: disable=old-style-class
|
||||||
with self.lock:
|
with self.lock:
|
||||||
deadline = time()
|
deadline = time()
|
||||||
toDelete = [
|
toDelete = [
|
||||||
[v.stream, k, v.child] for k, v in self.hashMap.iteritems()
|
[v.stream, k, v.child] for k, v in six.iteritems(self.hashMap)
|
||||||
if v.timeout < deadline
|
if v.timeout < deadline
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -199,10 +202,10 @@ class Dandelion: # pylint: disable=old-style-class
|
||||||
try:
|
try:
|
||||||
# random two connections
|
# random two connections
|
||||||
self.stem = sample(
|
self.stem = sample(
|
||||||
self.pool.outboundConnections.values(), MAX_STEMS)
|
sorted(self.pool.outboundConnections.values()), MAX_STEMS)
|
||||||
# not enough stems available
|
# not enough stems available
|
||||||
except ValueError:
|
except ValueError:
|
||||||
self.stem = self.pool.outboundConnections.values()
|
self.stem = list(self.pool.outboundConnections.values())
|
||||||
self.nodeMap = {}
|
self.nodeMap = {}
|
||||||
# hashMap stays to cater for pending stems
|
# hashMap stays to cater for pending stems
|
||||||
self.refresh = time() + REASSIGN_INTERVAL
|
self.refresh = time() + REASSIGN_INTERVAL
|
||||||
|
|
|
@ -4,12 +4,13 @@
|
||||||
import time
|
import time
|
||||||
import random
|
import random
|
||||||
import state
|
import state
|
||||||
|
import six
|
||||||
import addresses
|
import addresses
|
||||||
import protocol
|
import protocol
|
||||||
import connectionpool
|
from network import connectionpool
|
||||||
from network import dandelion_ins
|
from network import dandelion_ins
|
||||||
from objectracker import missingObjects
|
from .objectracker import missingObjects
|
||||||
from threads import StoppableThread
|
from .threads import StoppableThread
|
||||||
|
|
||||||
|
|
||||||
class DownloadThread(StoppableThread):
|
class DownloadThread(StoppableThread):
|
||||||
|
@ -29,7 +30,7 @@ class DownloadThread(StoppableThread):
|
||||||
deadline = time.time() - self.requestExpires
|
deadline = time.time() - self.requestExpires
|
||||||
try:
|
try:
|
||||||
toDelete = [
|
toDelete = [
|
||||||
k for k, v in missingObjects.iteritems()
|
k for k, v in six.iteritems(missingObjects)
|
||||||
if v < deadline]
|
if v < deadline]
|
||||||
except RuntimeError:
|
except RuntimeError:
|
||||||
pass
|
pass
|
||||||
|
@ -68,11 +69,11 @@ class DownloadThread(StoppableThread):
|
||||||
continue
|
continue
|
||||||
payload.extend(chunk)
|
payload.extend(chunk)
|
||||||
chunkCount += 1
|
chunkCount += 1
|
||||||
missingObjects[chunk] = now
|
missingObjects[bytes(chunk)] = now
|
||||||
if not chunkCount:
|
if not chunkCount:
|
||||||
continue
|
continue
|
||||||
payload[0:0] = addresses.encodeVarint(chunkCount)
|
payload[0:0] = addresses.encodeVarint(chunkCount)
|
||||||
i.append_write_buf(protocol.CreatePacket('getdata', payload))
|
i.append_write_buf(protocol.CreatePacket(b'getdata', payload))
|
||||||
self.logger.debug(
|
self.logger.debug(
|
||||||
'%s:%i Requesting %i objects',
|
'%s:%i Requesting %i objects',
|
||||||
i.destination.host, i.destination.port, chunkCount)
|
i.destination.host, i.destination.port, chunkCount)
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
import socket
|
import socket
|
||||||
|
|
||||||
from advanceddispatcher import AdvancedDispatcher
|
from .advanceddispatcher import AdvancedDispatcher
|
||||||
import asyncore_pollchoose as asyncore
|
from network import asyncore_pollchoose as asyncore
|
||||||
from proxy import ProxyError
|
from .proxy import ProxyError
|
||||||
from socks5 import Socks5Connection, Socks5Resolver
|
from .socks5 import Socks5Connection, Socks5Resolver
|
||||||
from socks4a import Socks4aConnection, Socks4aResolver
|
from .socks4a import Socks4aConnection, Socks4aResolver
|
||||||
|
|
||||||
|
|
||||||
class HttpError(ProxyError):
|
class HttpError(ProxyError):
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
"""
|
"""
|
||||||
Thread to send inv annoucements
|
Thread to send inv annoucements
|
||||||
"""
|
"""
|
||||||
import Queue
|
from six.moves import queue as Queue
|
||||||
import random
|
import random
|
||||||
from time import time
|
from time import time
|
||||||
|
|
||||||
import addresses
|
import addresses
|
||||||
import protocol
|
import protocol
|
||||||
import state
|
import state
|
||||||
import connectionpool
|
from network import connectionpool
|
||||||
from network import dandelion_ins, invQueue
|
from network import dandelion_ins, invQueue
|
||||||
from threads import StoppableThread
|
from .threads import StoppableThread
|
||||||
|
|
||||||
|
|
||||||
def handleExpiredDandelion(expired):
|
def handleExpiredDandelion(expired):
|
||||||
|
@ -90,15 +90,15 @@ class InvThread(StoppableThread):
|
||||||
if fluffs:
|
if fluffs:
|
||||||
random.shuffle(fluffs)
|
random.shuffle(fluffs)
|
||||||
connection.append_write_buf(protocol.CreatePacket(
|
connection.append_write_buf(protocol.CreatePacket(
|
||||||
'inv',
|
b'inv',
|
||||||
addresses.encodeVarint(
|
addresses.encodeVarint(
|
||||||
len(fluffs)) + ''.join(fluffs)))
|
len(fluffs)) + b''.join(fluffs)))
|
||||||
if stems:
|
if stems:
|
||||||
random.shuffle(stems)
|
random.shuffle(stems)
|
||||||
connection.append_write_buf(protocol.CreatePacket(
|
connection.append_write_buf(protocol.CreatePacket(
|
||||||
'dinv',
|
b'dinv',
|
||||||
addresses.encodeVarint(
|
addresses.encodeVarint(
|
||||||
len(stems)) + ''.join(stems)))
|
len(stems)) + b''.join(stems)))
|
||||||
|
|
||||||
invQueue.iterate()
|
invQueue.iterate()
|
||||||
for _ in range(len(chunk)):
|
for _ in range(len(chunk)):
|
||||||
|
|
|
@ -10,10 +10,8 @@ import os
|
||||||
import pickle # nosec B403
|
import pickle # nosec B403
|
||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
try:
|
from six.moves.collections_abc import Iterable
|
||||||
from collections.abc import Iterable
|
import six
|
||||||
except ImportError:
|
|
||||||
from collections import Iterable
|
|
||||||
|
|
||||||
import state
|
import state
|
||||||
from bmconfigparser import config
|
from bmconfigparser import config
|
||||||
|
@ -54,8 +52,8 @@ def json_serialize_knownnodes(output):
|
||||||
Reorganize knownnodes dict and write it as JSON to output
|
Reorganize knownnodes dict and write it as JSON to output
|
||||||
"""
|
"""
|
||||||
_serialized = []
|
_serialized = []
|
||||||
for stream, peers in knownNodes.iteritems():
|
for stream, peers in six.iteritems(knownNodes):
|
||||||
for peer, info in peers.iteritems():
|
for peer, info in six.iteritems(peers):
|
||||||
info.update(rating=round(info.get('rating', 0), 2))
|
info.update(rating=round(info.get('rating', 0), 2))
|
||||||
_serialized.append({
|
_serialized.append({
|
||||||
'stream': stream, 'peer': peer._asdict(), 'info': info
|
'stream': stream, 'peer': peer._asdict(), 'info': info
|
||||||
|
@ -87,7 +85,7 @@ def pickle_deserialize_old_knownnodes(source):
|
||||||
global knownNodes
|
global knownNodes
|
||||||
knownNodes = pickle.load(source) # nosec B301
|
knownNodes = pickle.load(source) # nosec B301
|
||||||
for stream in knownNodes.keys():
|
for stream in knownNodes.keys():
|
||||||
for node, params in knownNodes[stream].iteritems():
|
for node, params in six.iteritems(knownNodes[stream]):
|
||||||
if isinstance(params, (float, int)):
|
if isinstance(params, (float, int)):
|
||||||
addKnownNode(stream, node, params)
|
addKnownNode(stream, node, params)
|
||||||
|
|
||||||
|
@ -97,7 +95,7 @@ def saveKnownNodes(dirName=None):
|
||||||
if dirName is None:
|
if dirName is None:
|
||||||
dirName = state.appdata
|
dirName = state.appdata
|
||||||
with knownNodesLock:
|
with knownNodesLock:
|
||||||
with open(os.path.join(dirName, 'knownnodes.dat'), 'wb') as output:
|
with open(os.path.join(dirName, 'knownnodes.dat'), 'w') as output:
|
||||||
json_serialize_knownnodes(output)
|
json_serialize_knownnodes(output)
|
||||||
|
|
||||||
|
|
||||||
|
@ -108,6 +106,12 @@ def addKnownNode(stream, peer, lastseen=None, is_self=False):
|
||||||
Returns True if added a new node.
|
Returns True if added a new node.
|
||||||
"""
|
"""
|
||||||
# pylint: disable=too-many-branches
|
# pylint: disable=too-many-branches
|
||||||
|
if not isinstance(peer.host, str):
|
||||||
|
try:
|
||||||
|
peer = Peer(peer.host.decode("ascii"), peer.port)
|
||||||
|
except UnicodeDecodeError as err:
|
||||||
|
logger.warning("Invalid host: {}".format(peer.host.decode("ascii", "backslashreplace")))
|
||||||
|
return
|
||||||
if isinstance(stream, Iterable):
|
if isinstance(stream, Iterable):
|
||||||
with knownNodesLock:
|
with knownNodesLock:
|
||||||
for s in stream:
|
for s in stream:
|
||||||
|
@ -153,7 +157,7 @@ def createDefaultKnownNodes():
|
||||||
def readKnownNodes():
|
def readKnownNodes():
|
||||||
"""Load knownnodes from filesystem"""
|
"""Load knownnodes from filesystem"""
|
||||||
try:
|
try:
|
||||||
with open(state.appdata + 'knownnodes.dat', 'rb') as source:
|
with open(state.appdata + 'knownnodes.dat', 'r') as source:
|
||||||
with knownNodesLock:
|
with knownNodesLock:
|
||||||
try:
|
try:
|
||||||
json_deserialize_knownnodes(source)
|
json_deserialize_knownnodes(source)
|
||||||
|
|
|
@ -2,9 +2,9 @@
|
||||||
A thread to handle network concerns
|
A thread to handle network concerns
|
||||||
"""
|
"""
|
||||||
import network.asyncore_pollchoose as asyncore
|
import network.asyncore_pollchoose as asyncore
|
||||||
import connectionpool
|
from network import connectionpool
|
||||||
from queues import excQueue
|
from queues import excQueue
|
||||||
from threads import StoppableThread
|
from .threads import StoppableThread
|
||||||
|
|
||||||
|
|
||||||
class BMNetworkThread(StoppableThread):
|
class BMNetworkThread(StoppableThread):
|
||||||
|
|
|
@ -3,8 +3,9 @@ Module for tracking objects
|
||||||
"""
|
"""
|
||||||
import time
|
import time
|
||||||
from threading import RLock
|
from threading import RLock
|
||||||
|
import six
|
||||||
|
|
||||||
import connectionpool
|
import network.connectionpool # use long name to address recursive import
|
||||||
from network import dandelion_ins
|
from network import dandelion_ins
|
||||||
from randomtrackingdict import RandomTrackingDict
|
from randomtrackingdict import RandomTrackingDict
|
||||||
|
|
||||||
|
@ -75,32 +76,35 @@ class ObjectTracker(object):
|
||||||
with self.objectsNewToThemLock:
|
with self.objectsNewToThemLock:
|
||||||
self.objectsNewToThem = {
|
self.objectsNewToThem = {
|
||||||
k: v
|
k: v
|
||||||
for k, v in self.objectsNewToThem.iteritems()
|
for k, v in six.iteritems(self.objectsNewToThem)
|
||||||
if v >= deadline}
|
if v >= deadline}
|
||||||
self.lastCleaned = time.time()
|
self.lastCleaned = time.time()
|
||||||
|
|
||||||
def hasObj(self, hashid):
|
def hasObj(self, hashid):
|
||||||
"""Do we already have object?"""
|
"""Do we already have object?"""
|
||||||
|
hashid_bytes = bytes(hashid)
|
||||||
if haveBloom:
|
if haveBloom:
|
||||||
return hashid in self.invBloom
|
return hashid_bytes in self.invBloom
|
||||||
return hashid in self.objectsNewToMe
|
return hashid_bytes in self.objectsNewToMe
|
||||||
|
|
||||||
def handleReceivedInventory(self, hashId):
|
def handleReceivedInventory(self, hashId):
|
||||||
"""Handling received inventory"""
|
"""Handling received inventory"""
|
||||||
|
hashId_bytes = bytes(hashId)
|
||||||
if haveBloom:
|
if haveBloom:
|
||||||
self.invBloom.add(hashId)
|
self.invBloom.add(hashId_bytes)
|
||||||
try:
|
try:
|
||||||
with self.objectsNewToThemLock:
|
with self.objectsNewToThemLock:
|
||||||
del self.objectsNewToThem[hashId]
|
del self.objectsNewToThem[hashId_bytes]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
pass
|
pass
|
||||||
if hashId not in missingObjects:
|
if hashId_bytes not in missingObjects:
|
||||||
missingObjects[hashId] = time.time()
|
missingObjects[hashId_bytes] = time.time()
|
||||||
self.objectsNewToMe[hashId] = True
|
self.objectsNewToMe[hashId] = True
|
||||||
|
|
||||||
def handleReceivedObject(self, streamNumber, hashid):
|
def handleReceivedObject(self, streamNumber, hashid):
|
||||||
"""Handling received object"""
|
"""Handling received object"""
|
||||||
for i in connectionpool.pool.connections():
|
hashid_bytes = bytes(hashid)
|
||||||
|
for i in network.connectionpool.pool.connections():
|
||||||
if not i.fullyEstablished:
|
if not i.fullyEstablished:
|
||||||
continue
|
continue
|
||||||
try:
|
try:
|
||||||
|
@ -110,7 +114,7 @@ class ObjectTracker(object):
|
||||||
not dandelion_ins.hasHash(hashid)
|
not dandelion_ins.hasHash(hashid)
|
||||||
or dandelion_ins.objectChildStem(hashid) == i):
|
or dandelion_ins.objectChildStem(hashid) == i):
|
||||||
with i.objectsNewToThemLock:
|
with i.objectsNewToThemLock:
|
||||||
i.objectsNewToThem[hashid] = time.time()
|
i.objectsNewToThem[hashid_bytes] = time.time()
|
||||||
# update stream number,
|
# update stream number,
|
||||||
# which we didn't have when we just received the dinv
|
# which we didn't have when we just received the dinv
|
||||||
# also resets expiration of the stem mode
|
# also resets expiration of the stem mode
|
||||||
|
@ -119,7 +123,7 @@ class ObjectTracker(object):
|
||||||
if i == self:
|
if i == self:
|
||||||
try:
|
try:
|
||||||
with i.objectsNewToThemLock:
|
with i.objectsNewToThemLock:
|
||||||
del i.objectsNewToThem[hashid]
|
del i.objectsNewToThem[hashid_bytes]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
pass
|
pass
|
||||||
self.objectsNewToMe.setLastObject()
|
self.objectsNewToMe.setLastObject()
|
||||||
|
@ -133,4 +137,4 @@ class ObjectTracker(object):
|
||||||
def addAddr(self, hashid):
|
def addAddr(self, hashid):
|
||||||
"""WIP, should be moved to addrthread.py or removed"""
|
"""WIP, should be moved to addrthread.py or removed"""
|
||||||
if haveBloom:
|
if haveBloom:
|
||||||
self.addrBloom.add(hashid)
|
self.addrBloom.add(bytes(hashid))
|
||||||
|
|
|
@ -6,14 +6,20 @@ import logging
|
||||||
import socket
|
import socket
|
||||||
import time
|
import time
|
||||||
|
|
||||||
import asyncore_pollchoose as asyncore
|
from network import asyncore_pollchoose as asyncore
|
||||||
from advanceddispatcher import AdvancedDispatcher
|
from .advanceddispatcher import AdvancedDispatcher
|
||||||
from bmconfigparser import config
|
from bmconfigparser import config
|
||||||
from node import Peer
|
from .node import Peer
|
||||||
|
|
||||||
logger = logging.getLogger('default')
|
logger = logging.getLogger('default')
|
||||||
|
|
||||||
|
|
||||||
|
def _ends_with(s, tail):
|
||||||
|
try:
|
||||||
|
return s.endswith(tail)
|
||||||
|
except:
|
||||||
|
return s.decode("utf-8", "replace").endswith(tail)
|
||||||
|
|
||||||
class ProxyError(Exception):
|
class ProxyError(Exception):
|
||||||
"""Base proxy exception class"""
|
"""Base proxy exception class"""
|
||||||
errorCodes = ("Unknown error",)
|
errorCodes = ("Unknown error",)
|
||||||
|
@ -125,7 +131,7 @@ class Proxy(AdvancedDispatcher):
|
||||||
self.auth = None
|
self.auth = None
|
||||||
self.connect(
|
self.connect(
|
||||||
self.onion_proxy
|
self.onion_proxy
|
||||||
if address.host.endswith(".onion") and self.onion_proxy else
|
if _ends_with(address.host, ".onion") and self.onion_proxy else
|
||||||
self.proxy
|
self.proxy
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -2,13 +2,13 @@
|
||||||
Process data incoming from network
|
Process data incoming from network
|
||||||
"""
|
"""
|
||||||
import errno
|
import errno
|
||||||
import Queue
|
from six.moves import queue as Queue
|
||||||
import socket
|
import socket
|
||||||
|
|
||||||
import connectionpool
|
from network import connectionpool
|
||||||
from network.advanceddispatcher import UnknownStateError
|
from network.advanceddispatcher import UnknownStateError
|
||||||
from network import receiveDataQueue
|
from network import receiveDataQueue
|
||||||
from threads import StoppableThread
|
from .threads import StoppableThread
|
||||||
|
|
||||||
|
|
||||||
class ReceiveQueueThread(StoppableThread):
|
class ReceiveQueueThread(StoppableThread):
|
||||||
|
|
|
@ -5,8 +5,9 @@ SOCKS4a proxy module
|
||||||
import logging
|
import logging
|
||||||
import socket
|
import socket
|
||||||
import struct
|
import struct
|
||||||
|
import six
|
||||||
|
|
||||||
from proxy import GeneralProxyError, Proxy, ProxyError
|
from .proxy import GeneralProxyError, Proxy, ProxyError
|
||||||
|
|
||||||
logger = logging.getLogger('default')
|
logger = logging.getLogger('default')
|
||||||
|
|
||||||
|
@ -39,16 +40,16 @@ class Socks4a(Proxy):
|
||||||
def state_pre_connect(self):
|
def state_pre_connect(self):
|
||||||
"""Handle feedback from SOCKS4a while it is connecting on our behalf"""
|
"""Handle feedback from SOCKS4a while it is connecting on our behalf"""
|
||||||
# Get the response
|
# Get the response
|
||||||
if self.read_buf[0:1] != chr(0x00).encode():
|
if self.read_buf[0:1] != six.int2byte(0x00):
|
||||||
# bad data
|
# bad data
|
||||||
self.close()
|
self.close()
|
||||||
raise GeneralProxyError(1)
|
raise GeneralProxyError(1)
|
||||||
elif self.read_buf[1:2] != chr(0x5A).encode():
|
elif self.read_buf[1:2] != six.int2byte(0x5A):
|
||||||
# Connection failed
|
# Connection failed
|
||||||
self.close()
|
self.close()
|
||||||
if ord(self.read_buf[1:2]) in (91, 92, 93):
|
if six.byte2int(self.read_buf[1:2]) in (91, 92, 93):
|
||||||
# socks 4 error
|
# socks 4 error
|
||||||
raise Socks4aError(ord(self.read_buf[1:2]) - 90)
|
raise Socks4aError(six.byte2int(self.read_buf[1:2]) - 90)
|
||||||
else:
|
else:
|
||||||
raise Socks4aError(4)
|
raise Socks4aError(4)
|
||||||
# Get the bound address/port
|
# Get the bound address/port
|
||||||
|
@ -102,9 +103,9 @@ class Socks4aConnection(Socks4a):
|
||||||
self.append_write_buf(self.ipaddr)
|
self.append_write_buf(self.ipaddr)
|
||||||
if self._auth:
|
if self._auth:
|
||||||
self.append_write_buf(self._auth[0])
|
self.append_write_buf(self._auth[0])
|
||||||
self.append_write_buf(chr(0x00).encode())
|
self.append_write_buf(six.int2byte(0x00))
|
||||||
if rmtrslv:
|
if rmtrslv:
|
||||||
self.append_write_buf(self.destination[0] + chr(0x00).encode())
|
self.append_write_buf(self.destination[0].encode("utf-8", "replace") + six.int2byte(0x00))
|
||||||
self.set_state("pre_connect", length=0, expectBytes=8)
|
self.set_state("pre_connect", length=0, expectBytes=8)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
@ -132,8 +133,8 @@ class Socks4aResolver(Socks4a):
|
||||||
self.append_write_buf(struct.pack("BBBB", 0x00, 0x00, 0x00, 0x01))
|
self.append_write_buf(struct.pack("BBBB", 0x00, 0x00, 0x00, 0x01))
|
||||||
if self._auth:
|
if self._auth:
|
||||||
self.append_write_buf(self._auth[0])
|
self.append_write_buf(self._auth[0])
|
||||||
self.append_write_buf(chr(0x00).encode())
|
self.append_write_buf(six.int2byte(0x00))
|
||||||
self.append_write_buf(self.host + chr(0x00).encode())
|
self.append_write_buf(self.host + six.int2byte(0x00))
|
||||||
self.set_state("pre_connect", length=0, expectBytes=8)
|
self.set_state("pre_connect", length=0, expectBytes=8)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
|
@ -6,9 +6,10 @@ SOCKS5 proxy module
|
||||||
import logging
|
import logging
|
||||||
import socket
|
import socket
|
||||||
import struct
|
import struct
|
||||||
|
import six
|
||||||
|
|
||||||
from node import Peer
|
from .node import Peer
|
||||||
from proxy import GeneralProxyError, Proxy, ProxyError
|
from .proxy import GeneralProxyError, Proxy, ProxyError
|
||||||
|
|
||||||
logger = logging.getLogger('default')
|
logger = logging.getLogger('default')
|
||||||
|
|
||||||
|
@ -97,20 +98,20 @@ class Socks5(Proxy):
|
||||||
def state_pre_connect(self):
|
def state_pre_connect(self):
|
||||||
"""Handle feedback from socks5 while it is connecting on our behalf."""
|
"""Handle feedback from socks5 while it is connecting on our behalf."""
|
||||||
# Get the response
|
# Get the response
|
||||||
if self.read_buf[0:1] != chr(0x05).encode():
|
if self.read_buf[0:1] != six.int2byte(0x05):
|
||||||
self.close()
|
self.close()
|
||||||
raise GeneralProxyError(1)
|
raise GeneralProxyError(1)
|
||||||
elif self.read_buf[1:2] != chr(0x00).encode():
|
elif self.read_buf[1:2] != six.int2byte(0x00):
|
||||||
# Connection failed
|
# Connection failed
|
||||||
self.close()
|
self.close()
|
||||||
if ord(self.read_buf[1:2]) <= 8:
|
if six.byte2int(self.read_buf[1:2]) <= 8:
|
||||||
raise Socks5Error(ord(self.read_buf[1:2]))
|
raise Socks5Error(six.byte2int(self.read_buf[1:2]))
|
||||||
else:
|
else:
|
||||||
raise Socks5Error(9)
|
raise Socks5Error(9)
|
||||||
# Get the bound address/port
|
# Get the bound address/port
|
||||||
elif self.read_buf[3:4] == chr(0x01).encode():
|
elif self.read_buf[3:4] == six.int2byte(0x01):
|
||||||
self.set_state("proxy_addr_1", length=4, expectBytes=4)
|
self.set_state("proxy_addr_1", length=4, expectBytes=4)
|
||||||
elif self.read_buf[3:4] == chr(0x03).encode():
|
elif self.read_buf[3:4] == six.int2byte(0x03):
|
||||||
self.set_state("proxy_addr_2_1", length=4, expectBytes=1)
|
self.set_state("proxy_addr_2_1", length=4, expectBytes=1)
|
||||||
else:
|
else:
|
||||||
self.close()
|
self.close()
|
||||||
|
@ -129,7 +130,7 @@ class Socks5(Proxy):
|
||||||
(e.g. IPv6, onion, ...). This is part 1 which retrieves the
|
(e.g. IPv6, onion, ...). This is part 1 which retrieves the
|
||||||
length of the data.
|
length of the data.
|
||||||
"""
|
"""
|
||||||
self.address_length = ord(self.read_buf[0:1])
|
self.address_length = six.byte2int(self.read_buf[0:1])
|
||||||
self.set_state(
|
self.set_state(
|
||||||
"proxy_addr_2_2", length=1, expectBytes=self.address_length)
|
"proxy_addr_2_2", length=1, expectBytes=self.address_length)
|
||||||
return True
|
return True
|
||||||
|
@ -171,19 +172,19 @@ class Socks5Connection(Socks5):
|
||||||
# use the IPv4 address request even if remote resolving was specified.
|
# use the IPv4 address request even if remote resolving was specified.
|
||||||
try:
|
try:
|
||||||
self.ipaddr = socket.inet_aton(self.destination[0])
|
self.ipaddr = socket.inet_aton(self.destination[0])
|
||||||
self.append_write_buf(chr(0x01).encode() + self.ipaddr)
|
self.append_write_buf(six.int2byte(0x01) + self.ipaddr)
|
||||||
except socket.error: # may be IPv6!
|
except socket.error: # may be IPv6!
|
||||||
# Well it's not an IP number, so it's probably a DNS name.
|
# Well it's not an IP number, so it's probably a DNS name.
|
||||||
if self._remote_dns:
|
if self._remote_dns:
|
||||||
# Resolve remotely
|
# Resolve remotely
|
||||||
self.ipaddr = None
|
self.ipaddr = None
|
||||||
self.append_write_buf(chr(0x03).encode() + chr(
|
self.append_write_buf(six.int2byte(0x03) + six.int2byte(
|
||||||
len(self.destination[0])).encode() + self.destination[0])
|
len(self.destination[0])) + self.destination[0].encode("utf-8", "replace"))
|
||||||
else:
|
else:
|
||||||
# Resolve locally
|
# Resolve locally
|
||||||
self.ipaddr = socket.inet_aton(
|
self.ipaddr = socket.inet_aton(
|
||||||
socket.gethostbyname(self.destination[0]))
|
socket.gethostbyname(self.destination[0]))
|
||||||
self.append_write_buf(chr(0x01).encode() + self.ipaddr)
|
self.append_write_buf(six.int2byte(0x01) + self.ipaddr)
|
||||||
self.append_write_buf(struct.pack(">H", self.destination[1]))
|
self.append_write_buf(struct.pack(">H", self.destination[1]))
|
||||||
self.set_state("pre_connect", length=0, expectBytes=4)
|
self.set_state("pre_connect", length=0, expectBytes=4)
|
||||||
return True
|
return True
|
||||||
|
@ -208,8 +209,8 @@ class Socks5Resolver(Socks5):
|
||||||
"""Perform resolving"""
|
"""Perform resolving"""
|
||||||
# Now we can request the actual connection
|
# Now we can request the actual connection
|
||||||
self.append_write_buf(struct.pack('BBB', 0x05, 0xF0, 0x00))
|
self.append_write_buf(struct.pack('BBB', 0x05, 0xF0, 0x00))
|
||||||
self.append_write_buf(chr(0x03).encode() + chr(
|
self.append_write_buf(six.int2byte(0x03) + six.int2byte(
|
||||||
len(self.host)).encode() + str(self.host))
|
len(self.host)) + bytes(self.host))
|
||||||
self.append_write_buf(struct.pack(">H", self.port))
|
self.append_write_buf(struct.pack(">H", self.port))
|
||||||
self.set_state("pre_connect", length=0, expectBytes=4)
|
self.set_state("pre_connect", length=0, expectBytes=4)
|
||||||
return True
|
return True
|
||||||
|
|
|
@ -3,9 +3,9 @@ Network statistics
|
||||||
"""
|
"""
|
||||||
import time
|
import time
|
||||||
|
|
||||||
import asyncore_pollchoose as asyncore
|
from network import asyncore_pollchoose as asyncore
|
||||||
import connectionpool
|
from network import connectionpool
|
||||||
from objectracker import missingObjects
|
from .objectracker import missingObjects
|
||||||
|
|
||||||
|
|
||||||
lastReceivedTimestamp = time.time()
|
lastReceivedTimestamp = time.time()
|
||||||
|
|
|
@ -8,28 +8,29 @@ import math
|
||||||
import random
|
import random
|
||||||
import socket
|
import socket
|
||||||
import time
|
import time
|
||||||
|
import six
|
||||||
|
|
||||||
# magic imports!
|
# magic imports!
|
||||||
import addresses
|
import addresses
|
||||||
import l10n
|
import l10n
|
||||||
import protocol
|
import protocol
|
||||||
import state
|
import state
|
||||||
import connectionpool
|
import network.connectionpool # use long name to address recursive import
|
||||||
from bmconfigparser import config
|
from bmconfigparser import config
|
||||||
from highlevelcrypto import randomBytes
|
from highlevelcrypto import randomBytes
|
||||||
from network import dandelion_ins, invQueue, receiveDataQueue
|
from network import dandelion_ins, invQueue, receiveDataQueue
|
||||||
from queues import UISignalQueue
|
from queues import UISignalQueue
|
||||||
from tr import _translate
|
from tr import _translate
|
||||||
|
|
||||||
import asyncore_pollchoose as asyncore
|
from network import asyncore_pollchoose as asyncore
|
||||||
import knownnodes
|
from network import knownnodes
|
||||||
from network.advanceddispatcher import AdvancedDispatcher
|
from network.advanceddispatcher import AdvancedDispatcher
|
||||||
from network.bmproto import BMProto
|
from network.bmproto import BMProto
|
||||||
from network.objectracker import ObjectTracker
|
from network.objectracker import ObjectTracker
|
||||||
from network.socks4a import Socks4aConnection
|
from network.socks4a import Socks4aConnection
|
||||||
from network.socks5 import Socks5Connection
|
from network.socks5 import Socks5Connection
|
||||||
from network.tls import TLSDispatcher
|
from network.tls import TLSDispatcher
|
||||||
from node import Peer
|
from .node import Peer
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger('default')
|
logger = logging.getLogger('default')
|
||||||
|
@ -39,6 +40,12 @@ maximumAgeOfNodesThatIAdvertiseToOthers = 10800 #: Equals three hours
|
||||||
maximumTimeOffsetWrongCount = 3 #: Connections with wrong time offset
|
maximumTimeOffsetWrongCount = 3 #: Connections with wrong time offset
|
||||||
|
|
||||||
|
|
||||||
|
def _ends_with(s, tail):
|
||||||
|
try:
|
||||||
|
return s.endswith(tail)
|
||||||
|
except:
|
||||||
|
return s.decode("utf-8", "replace").endswith(tail)
|
||||||
|
|
||||||
class TCPConnection(BMProto, TLSDispatcher):
|
class TCPConnection(BMProto, TLSDispatcher):
|
||||||
# pylint: disable=too-many-instance-attributes
|
# pylint: disable=too-many-instance-attributes
|
||||||
"""
|
"""
|
||||||
|
@ -138,9 +145,9 @@ class TCPConnection(BMProto, TLSDispatcher):
|
||||||
'updateStatusBar',
|
'updateStatusBar',
|
||||||
_translate(
|
_translate(
|
||||||
"MainWindow",
|
"MainWindow",
|
||||||
"The time on your computer, %1, may be wrong. "
|
"The time on your computer, {0}, may be wrong. "
|
||||||
"Please verify your settings."
|
"Please verify your settings."
|
||||||
).arg(l10n.formatTimestamp())))
|
).format(l10n.formatTimestamp())))
|
||||||
|
|
||||||
def state_connection_fully_established(self):
|
def state_connection_fully_established(self):
|
||||||
"""
|
"""
|
||||||
|
@ -191,10 +198,10 @@ class TCPConnection(BMProto, TLSDispatcher):
|
||||||
# only if more recent than 3 hours
|
# only if more recent than 3 hours
|
||||||
# and having positive or neutral rating
|
# and having positive or neutral rating
|
||||||
filtered = [
|
filtered = [
|
||||||
(k, v) for k, v in nodes.iteritems()
|
(k, v) for k, v in six.iteritems(nodes)
|
||||||
if v["lastseen"] > int(time.time())
|
if v["lastseen"] > int(time.time())
|
||||||
- maximumAgeOfNodesThatIAdvertiseToOthers
|
- maximumAgeOfNodesThatIAdvertiseToOthers
|
||||||
and v["rating"] >= 0 and not k.host.endswith('.onion')
|
and v["rating"] >= 0 and not _ends_with(k.host, '.onion')
|
||||||
]
|
]
|
||||||
# sent 250 only if the remote isn't interested in it
|
# sent 250 only if the remote isn't interested in it
|
||||||
elemCount = min(
|
elemCount = min(
|
||||||
|
@ -220,7 +227,7 @@ class TCPConnection(BMProto, TLSDispatcher):
|
||||||
'Sending huge inv message with %i objects to just this'
|
'Sending huge inv message with %i objects to just this'
|
||||||
' one peer', objectCount)
|
' one peer', objectCount)
|
||||||
self.append_write_buf(protocol.CreatePacket(
|
self.append_write_buf(protocol.CreatePacket(
|
||||||
'inv', addresses.encodeVarint(objectCount) + payload))
|
b'inv', addresses.encodeVarint(objectCount) + payload))
|
||||||
|
|
||||||
# Select all hashes for objects in this stream.
|
# Select all hashes for objects in this stream.
|
||||||
bigInvList = {}
|
bigInvList = {}
|
||||||
|
@ -267,7 +274,7 @@ class TCPConnection(BMProto, TLSDispatcher):
|
||||||
self.append_write_buf(
|
self.append_write_buf(
|
||||||
protocol.assembleVersionMessage(
|
protocol.assembleVersionMessage(
|
||||||
self.destination.host, self.destination.port,
|
self.destination.host, self.destination.port,
|
||||||
connectionpool.pool.streams, dandelion_ins.enabled,
|
network.connectionpool.pool.streams, dandelion_ins.enabled,
|
||||||
False, nodeid=self.nodeid))
|
False, nodeid=self.nodeid))
|
||||||
self.connectedAt = time.time()
|
self.connectedAt = time.time()
|
||||||
receiveDataQueue.put(self.destination)
|
receiveDataQueue.put(self.destination)
|
||||||
|
@ -318,7 +325,7 @@ class Socks5BMConnection(Socks5Connection, TCPConnection):
|
||||||
self.append_write_buf(
|
self.append_write_buf(
|
||||||
protocol.assembleVersionMessage(
|
protocol.assembleVersionMessage(
|
||||||
self.destination.host, self.destination.port,
|
self.destination.host, self.destination.port,
|
||||||
connectionpool.pool.streams, dandelion_ins.enabled,
|
network.connectionpool.pool.streams, dandelion_ins.enabled,
|
||||||
False, nodeid=self.nodeid))
|
False, nodeid=self.nodeid))
|
||||||
self.set_state("bm_header", expectBytes=protocol.Header.size)
|
self.set_state("bm_header", expectBytes=protocol.Header.size)
|
||||||
return True
|
return True
|
||||||
|
@ -342,7 +349,7 @@ class Socks4aBMConnection(Socks4aConnection, TCPConnection):
|
||||||
self.append_write_buf(
|
self.append_write_buf(
|
||||||
protocol.assembleVersionMessage(
|
protocol.assembleVersionMessage(
|
||||||
self.destination.host, self.destination.port,
|
self.destination.host, self.destination.port,
|
||||||
connectionpool.pool.streams, dandelion_ins.enabled,
|
network.connectionpool.pool.streams, dandelion_ins.enabled,
|
||||||
False, nodeid=self.nodeid))
|
False, nodeid=self.nodeid))
|
||||||
self.set_state("bm_header", expectBytes=protocol.Header.size)
|
self.set_state("bm_header", expectBytes=protocol.Header.size)
|
||||||
return True
|
return True
|
||||||
|
@ -430,7 +437,7 @@ class TCPServer(AdvancedDispatcher):
|
||||||
|
|
||||||
state.ownAddresses[Peer(*sock.getsockname())] = True
|
state.ownAddresses[Peer(*sock.getsockname())] = True
|
||||||
if (
|
if (
|
||||||
len(connectionpool.pool)
|
len(network.connectionpool.pool)
|
||||||
> config.safeGetInt(
|
> config.safeGetInt(
|
||||||
'bitmessagesettings', 'maxtotalconnections')
|
'bitmessagesettings', 'maxtotalconnections')
|
||||||
+ config.safeGetInt(
|
+ config.safeGetInt(
|
||||||
|
@ -442,7 +449,7 @@ class TCPServer(AdvancedDispatcher):
|
||||||
sock.close()
|
sock.close()
|
||||||
return
|
return
|
||||||
try:
|
try:
|
||||||
connectionpool.pool.addConnection(
|
network.connectionpool.pool.addConnection(
|
||||||
TCPConnection(sock=sock))
|
TCPConnection(sock=sock))
|
||||||
except socket.error:
|
except socket.error:
|
||||||
pass
|
pass
|
||||||
|
|
|
@ -6,6 +6,7 @@ import os
|
||||||
import socket
|
import socket
|
||||||
import ssl
|
import ssl
|
||||||
import sys
|
import sys
|
||||||
|
import six
|
||||||
|
|
||||||
import network.asyncore_pollchoose as asyncore
|
import network.asyncore_pollchoose as asyncore
|
||||||
import paths
|
import paths
|
||||||
|
@ -34,7 +35,7 @@ else:
|
||||||
# ciphers
|
# ciphers
|
||||||
if (
|
if (
|
||||||
ssl.OPENSSL_VERSION_NUMBER >= 0x10100000
|
ssl.OPENSSL_VERSION_NUMBER >= 0x10100000
|
||||||
and not ssl.OPENSSL_VERSION.startswith(b"LibreSSL")
|
and not ssl.OPENSSL_VERSION.startswith("LibreSSL")
|
||||||
):
|
):
|
||||||
sslProtocolCiphers = "AECDH-AES256-SHA@SECLEVEL=0"
|
sslProtocolCiphers = "AECDH-AES256-SHA@SECLEVEL=0"
|
||||||
else:
|
else:
|
||||||
|
@ -58,25 +59,45 @@ class TLSDispatcher(AdvancedDispatcher):
|
||||||
self.tlsDone = False
|
self.tlsDone = False
|
||||||
self.tlsVersion = "N/A"
|
self.tlsVersion = "N/A"
|
||||||
self.isSSL = False
|
self.isSSL = False
|
||||||
|
if six.PY3 or ssl.OPENSSL_VERSION_NUMBER >= 0x30000000:
|
||||||
|
self.tlsPrepared = False
|
||||||
|
|
||||||
def state_tls_init(self):
|
def state_tls_init(self):
|
||||||
"""Prepare sockets for TLS handshake"""
|
"""Prepare sockets for TLS handshake"""
|
||||||
self.isSSL = True
|
self.isSSL = True
|
||||||
self.tlsStarted = True
|
self.tlsStarted = True
|
||||||
|
|
||||||
|
if six.PY3 or ssl.OPENSSL_VERSION_NUMBER >= 0x30000000:
|
||||||
|
self.want_read = self.want_write = True
|
||||||
|
self.set_state("tls_handshake")
|
||||||
|
return False
|
||||||
|
|
||||||
|
return self.do_tls_init()
|
||||||
|
|
||||||
|
def do_tls_init(self):
|
||||||
# Once the connection has been established,
|
# Once the connection has been established,
|
||||||
# it's safe to wrap the socket.
|
# it's safe to wrap the socket.
|
||||||
if sys.version_info >= (2, 7, 9):
|
if sys.version_info >= (2, 7, 9):
|
||||||
context = ssl.create_default_context(
|
if ssl.OPENSSL_VERSION_NUMBER >= 0x30000000:
|
||||||
purpose=ssl.Purpose.SERVER_AUTH
|
context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER
|
||||||
if self.server_side else ssl.Purpose.CLIENT_AUTH)
|
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)
|
||||||
context.set_ciphers(self.ciphers)
|
context.set_ciphers(self.ciphers)
|
||||||
context.set_ecdh_curve("secp256k1")
|
context.set_ecdh_curve("secp256k1")
|
||||||
context.check_hostname = False
|
context.check_hostname = False
|
||||||
context.verify_mode = ssl.CERT_NONE
|
context.verify_mode = ssl.CERT_NONE
|
||||||
# also exclude TLSv1 and TLSv1.1 in the future
|
# also exclude TLSv1 and TLSv1.1 in the future
|
||||||
context.options = ssl.OP_ALL | ssl.OP_NO_SSLv2 |\
|
if ssl.OPENSSL_VERSION_NUMBER >= 0x30000000:
|
||||||
ssl.OP_NO_SSLv3 | ssl.OP_SINGLE_ECDH_USE |\
|
context.options = ssl.OP_ALL | ssl.OP_NO_SSLv2 |\
|
||||||
ssl.OP_CIPHER_SERVER_PREFERENCE
|
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
|
||||||
self.sslSocket = context.wrap_socket(
|
self.sslSocket = context.wrap_socket(
|
||||||
self.socket, server_side=self.server_side,
|
self.socket, server_side=self.server_side,
|
||||||
do_handshake_on_connect=False)
|
do_handshake_on_connect=False)
|
||||||
|
@ -88,7 +109,10 @@ class TLSDispatcher(AdvancedDispatcher):
|
||||||
ciphers=self.ciphers, do_handshake_on_connect=False)
|
ciphers=self.ciphers, do_handshake_on_connect=False)
|
||||||
self.sslSocket.setblocking(0)
|
self.sslSocket.setblocking(0)
|
||||||
self.want_read = self.want_write = True
|
self.want_read = self.want_write = True
|
||||||
self.set_state("tls_handshake")
|
if six.PY3 or ssl.OPENSSL_VERSION_NUMBER >= 0x30000000:
|
||||||
|
self.tlsPrepared = True
|
||||||
|
else:
|
||||||
|
self.set_state("tls_handshake")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
@ -114,7 +138,9 @@ class TLSDispatcher(AdvancedDispatcher):
|
||||||
# during TLS handshake, and after flushing write buffer,
|
# during TLS handshake, and after flushing write buffer,
|
||||||
# return status of last handshake attempt
|
# return status of last handshake attempt
|
||||||
if self.tlsStarted and not self.tlsDone and not self.write_buf:
|
if self.tlsStarted and not self.tlsDone and not self.write_buf:
|
||||||
logger.debug('tls readable, %r', self.want_read)
|
# 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
|
return self.want_read
|
||||||
# prior to TLS handshake,
|
# prior to TLS handshake,
|
||||||
# receiveDataThread should emulate synchronous behaviour
|
# receiveDataThread should emulate synchronous behaviour
|
||||||
|
@ -134,6 +160,10 @@ class TLSDispatcher(AdvancedDispatcher):
|
||||||
try:
|
try:
|
||||||
# wait for write buffer flush
|
# wait for write buffer flush
|
||||||
if self.tlsStarted and not self.tlsDone and not self.write_buf:
|
if self.tlsStarted and not self.tlsDone and not self.write_buf:
|
||||||
|
if six.PY3 or ssl.OPENSSL_VERSION_NUMBER >= 0x30000000:
|
||||||
|
if not self.tlsPrepared:
|
||||||
|
self.do_tls_init()
|
||||||
|
return
|
||||||
self.tls_handshake()
|
self.tls_handshake()
|
||||||
else:
|
else:
|
||||||
AdvancedDispatcher.handle_read(self)
|
AdvancedDispatcher.handle_read(self)
|
||||||
|
@ -156,6 +186,10 @@ class TLSDispatcher(AdvancedDispatcher):
|
||||||
try:
|
try:
|
||||||
# wait for write buffer flush
|
# wait for write buffer flush
|
||||||
if self.tlsStarted and not self.tlsDone and not self.write_buf:
|
if self.tlsStarted and not self.tlsDone and not self.write_buf:
|
||||||
|
if six.PY3 or ssl.OPENSSL_VERSION_NUMBER >= 0x30000000:
|
||||||
|
if not self.tlsPrepared:
|
||||||
|
self.do_tls_init()
|
||||||
|
return
|
||||||
self.tls_handshake()
|
self.tls_handshake()
|
||||||
else:
|
else:
|
||||||
AdvancedDispatcher.handle_write(self)
|
AdvancedDispatcher.handle_write(self)
|
||||||
|
|
|
@ -8,12 +8,12 @@ import time
|
||||||
# magic imports!
|
# magic imports!
|
||||||
import protocol
|
import protocol
|
||||||
import state
|
import state
|
||||||
import connectionpool
|
import network.connectionpool # use long name to address recursive import
|
||||||
|
|
||||||
from network import receiveDataQueue
|
from network import receiveDataQueue
|
||||||
from bmproto import BMProto
|
from .bmproto import BMProto
|
||||||
from node import Peer
|
from .node import Peer
|
||||||
from objectracker import ObjectTracker
|
from .objectracker import ObjectTracker
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger('default')
|
logger = logging.getLogger('default')
|
||||||
|
@ -81,8 +81,8 @@ class UDPSocket(BMProto): # pylint: disable=too-many-instance-attributes
|
||||||
return True
|
return True
|
||||||
remoteport = False
|
remoteport = False
|
||||||
for seenTime, stream, _, ip, port in addresses:
|
for seenTime, stream, _, ip, port in addresses:
|
||||||
decodedIP = protocol.checkIPAddress(str(ip))
|
decodedIP = protocol.checkIPAddress(ip)
|
||||||
if stream not in connectionpool.pool.streams:
|
if stream not in network.connectionpool.pool.streams:
|
||||||
continue
|
continue
|
||||||
if (seenTime < time.time() - protocol.MAX_TIME_OFFSET
|
if (seenTime < time.time() - protocol.MAX_TIME_OFFSET
|
||||||
or seenTime > time.time() + protocol.MAX_TIME_OFFSET):
|
or seenTime > time.time() + protocol.MAX_TIME_OFFSET):
|
||||||
|
|
|
@ -6,10 +6,10 @@ import time
|
||||||
import random
|
import random
|
||||||
import protocol
|
import protocol
|
||||||
import state
|
import state
|
||||||
import connectionpool
|
from network import connectionpool
|
||||||
from randomtrackingdict import RandomTrackingDict
|
from randomtrackingdict import RandomTrackingDict
|
||||||
from network import dandelion_ins
|
from network import dandelion_ins
|
||||||
from threads import StoppableThread
|
from .threads import StoppableThread
|
||||||
|
|
||||||
|
|
||||||
class UploadThread(StoppableThread):
|
class UploadThread(StoppableThread):
|
||||||
|
@ -50,7 +50,7 @@ class UploadThread(StoppableThread):
|
||||||
break
|
break
|
||||||
try:
|
try:
|
||||||
payload.extend(protocol.CreatePacket(
|
payload.extend(protocol.CreatePacket(
|
||||||
'object', state.Inventory[chunk].payload))
|
b'object', state.Inventory[chunk].payload))
|
||||||
chunk_count += 1
|
chunk_count += 1
|
||||||
except KeyError:
|
except KeyError:
|
||||||
i.antiIntersectionDelay()
|
i.antiIntersectionDelay()
|
||||||
|
|
|
@ -23,9 +23,9 @@ class IndicatorLibmessaging(object):
|
||||||
return
|
return
|
||||||
|
|
||||||
self._menu = {
|
self._menu = {
|
||||||
'send': unicode(_translate('MainWindow', 'Send')),
|
'send': _translate('MainWindow', 'Send'),
|
||||||
'messages': unicode(_translate('MainWindow', 'Messages')),
|
'messages': _translate('MainWindow', 'Messages'),
|
||||||
'subscriptions': unicode(_translate('MainWindow', 'Subscriptions'))
|
'subscriptions': _translate('MainWindow', 'Subscriptions')
|
||||||
}
|
}
|
||||||
|
|
||||||
self.new_message_item = self.new_broadcast_item = None
|
self.new_message_item = self.new_broadcast_item = None
|
||||||
|
@ -45,12 +45,11 @@ class IndicatorLibmessaging(object):
|
||||||
|
|
||||||
def show_unread(self, draw_attention=False):
|
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
|
on the messaging menu
|
||||||
"""
|
"""
|
||||||
for source, count in zip(
|
for source, count in zip(
|
||||||
('messages', 'subscriptions'),
|
('messages', 'subscriptions'), self.form.getUnread()
|
||||||
self.form.getUnread()
|
|
||||||
):
|
):
|
||||||
if count > 0:
|
if count > 0:
|
||||||
if self.app.has_source(source):
|
if self.app.has_source(source):
|
||||||
|
|
|
@ -3,10 +3,10 @@
|
||||||
A menu plugin showing QR-Code for bitmessage address in modal dialog.
|
A menu plugin showing QR-Code for bitmessage address in modal dialog.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import urllib
|
from six.moves.urllib.parse import urlencode
|
||||||
|
|
||||||
import qrcode
|
import qrcode
|
||||||
from PyQt4 import QtCore, QtGui
|
from qtpy import QtGui, QtCore, QtWidgets
|
||||||
|
|
||||||
from pybitmessage.tr import _translate
|
from pybitmessage.tr import _translate
|
||||||
|
|
||||||
|
@ -39,23 +39,23 @@ class Image(qrcode.image.base.BaseImage): # pylint: disable=abstract-method
|
||||||
QtCore.Qt.black)
|
QtCore.Qt.black)
|
||||||
|
|
||||||
|
|
||||||
class QRCodeDialog(QtGui.QDialog):
|
class QRCodeDialog(QtWidgets.QDialog):
|
||||||
"""The dialog"""
|
"""The dialog"""
|
||||||
def __init__(self, parent):
|
def __init__(self, parent):
|
||||||
super(QRCodeDialog, self).__init__(parent)
|
super(QRCodeDialog, self).__init__(parent)
|
||||||
self.image = QtGui.QLabel(self)
|
self.image = QtWidgets.QLabel(self)
|
||||||
self.label = QtGui.QLabel(self)
|
self.label = QtWidgets.QLabel(self)
|
||||||
font = QtGui.QFont()
|
font = QtGui.QFont()
|
||||||
font.setBold(True)
|
font.setBold(True)
|
||||||
font.setWeight(75)
|
font.setWeight(75)
|
||||||
self.label.setFont(font)
|
self.label.setFont(font)
|
||||||
self.label.setAlignment(
|
self.label.setAlignment(
|
||||||
QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter)
|
QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter)
|
||||||
buttonBox = QtGui.QDialogButtonBox(self)
|
buttonBox = QtWidgets.QDialogButtonBox(self)
|
||||||
buttonBox.setOrientation(QtCore.Qt.Horizontal)
|
buttonBox.setOrientation(QtCore.Qt.Horizontal)
|
||||||
buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Ok)
|
buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Ok)
|
||||||
buttonBox.accepted.connect(self.accept)
|
buttonBox.accepted.connect(self.accept)
|
||||||
layout = QtGui.QVBoxLayout(self)
|
layout = QtWidgets.QVBoxLayout(self)
|
||||||
layout.addWidget(self.image)
|
layout.addWidget(self.image)
|
||||||
layout.addWidget(self.label)
|
layout.addWidget(self.label)
|
||||||
layout.addWidget(buttonBox)
|
layout.addWidget(buttonBox)
|
||||||
|
@ -72,7 +72,7 @@ class QRCodeDialog(QtGui.QDialog):
|
||||||
self.label.setText(text)
|
self.label.setText(text)
|
||||||
self.label.setToolTip(text)
|
self.label.setToolTip(text)
|
||||||
self.label.setFixedWidth(pixmap.width())
|
self.label.setFixedWidth(pixmap.width())
|
||||||
self.setFixedSize(QtGui.QWidget.sizeHint(self))
|
self.setFixedSize(QtWidgets.QWidget.sizeHint(self))
|
||||||
|
|
||||||
|
|
||||||
def connect_plugin(form):
|
def connect_plugin(form):
|
||||||
|
@ -93,7 +93,7 @@ def connect_plugin(form):
|
||||||
return
|
return
|
||||||
dialog.render(
|
dialog.render(
|
||||||
'bitmessage:%s' % account.address + (
|
'bitmessage:%s' % account.address + (
|
||||||
'?' + urllib.urlencode({'label': label.encode('utf-8')})
|
'?' + urlencode({'label': label.encode('utf-8')})
|
||||||
if label != account.address else '')
|
if label != account.address else '')
|
||||||
)
|
)
|
||||||
dialog.exec_()
|
dialog.exec_()
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user