2019-10-27 14:15:45 +01:00
|
|
|
"""
|
|
|
|
sqlThread is defined here
|
|
|
|
"""
|
|
|
|
|
2013-06-20 23:23:03 +02:00
|
|
|
import threading
|
2017-02-22 09:34:54 +01:00
|
|
|
from bmconfigparser import BMConfigParser
|
2013-06-20 23:23:03 +02:00
|
|
|
import sqlite3
|
|
|
|
import time
|
2013-06-21 21:44:28 +02:00
|
|
|
import shutil # used for moving the messages.dat file
|
2013-06-23 08:38:21 +02:00
|
|
|
import sys
|
2013-06-23 21:52:39 +02:00
|
|
|
import os
|
2013-07-15 21:45:03 +02:00
|
|
|
from debug import logger
|
2017-02-08 13:41:56 +01:00
|
|
|
import helper_sql
|
2018-03-03 16:31:49 +01:00
|
|
|
import helper_startup
|
2017-01-11 17:00:00 +01:00
|
|
|
import paths
|
2017-02-08 13:41:56 +01:00
|
|
|
import queues
|
2017-01-11 17:00:00 +01:00
|
|
|
import state
|
2018-03-03 16:31:49 +01:00
|
|
|
import tr
|
|
|
|
|
2013-06-20 23:23:03 +02:00
|
|
|
# This thread exists because SQLITE3 is so un-threadsafe that we must
|
|
|
|
# submit queries to it and it puts results back in a different queue. They
|
|
|
|
# won't let us just use locks.
|
|
|
|
|
|
|
|
|
|
|
|
class sqlThread(threading.Thread):
|
2019-10-27 14:15:45 +01:00
|
|
|
"""A thread for all SQL operations"""
|
2013-06-20 23:23:03 +02:00
|
|
|
|
|
|
|
def __init__(self):
|
2015-11-18 16:22:17 +01:00
|
|
|
threading.Thread.__init__(self, name="SQL")
|
2013-06-20 23:23:03 +02:00
|
|
|
|
2018-05-02 17:29:55 +02:00
|
|
|
def run(self):
|
2019-10-27 14:15:45 +01:00
|
|
|
"""Process SQL queries from `.helper_sql.sqlSubmitQueue`"""
|
2017-01-11 17:00:00 +01:00
|
|
|
self.conn = sqlite3.connect(state.appdata + 'messages.dat')
|
2013-06-20 23:23:03 +02:00
|
|
|
self.conn.text_factory = str
|
|
|
|
self.cur = self.conn.cursor()
|
2018-05-02 17:29:55 +02:00
|
|
|
|
2015-11-09 17:21:47 +01:00
|
|
|
self.cur.execute('PRAGMA secure_delete = true')
|
2013-12-02 07:35:34 +01:00
|
|
|
|
2013-06-20 23:23:03 +02:00
|
|
|
try:
|
|
|
|
self.cur.execute(
|
2019-10-05 09:31:48 +02:00
|
|
|
'''CREATE TABLE inbox (msgid blob, toaddress text, fromaddress text, subject text,'''
|
|
|
|
''' received text, message text, folder text, encodingtype int, read bool, sighash blob,'''
|
|
|
|
''' UNIQUE(msgid) ON CONFLICT REPLACE)''')
|
2013-06-20 23:23:03 +02:00
|
|
|
self.cur.execute(
|
2019-10-05 09:31:48 +02:00
|
|
|
'''CREATE TABLE sent (msgid blob, toaddress text, toripe blob, fromaddress text, subject text,'''
|
|
|
|
''' message text, ackdata blob, senttime integer, lastactiontime integer,'''
|
|
|
|
''' sleeptill integer, status text, retrynumber integer, folder text, encodingtype int, ttl int)''')
|
2013-06-20 23:23:03 +02:00
|
|
|
self.cur.execute(
|
2019-10-05 09:31:48 +02:00
|
|
|
'''CREATE TABLE subscriptions (label text, address text, enabled bool)''')
|
2013-06-20 23:23:03 +02:00
|
|
|
self.cur.execute(
|
2019-10-05 09:31:48 +02:00
|
|
|
'''CREATE TABLE addressbook (label text, address text)''')
|
2013-06-20 23:23:03 +02:00
|
|
|
self.cur.execute(
|
2019-10-05 09:31:48 +02:00
|
|
|
'''CREATE TABLE blacklist (label text, address text, enabled bool)''')
|
2013-06-20 23:23:03 +02:00
|
|
|
self.cur.execute(
|
2019-10-05 09:31:48 +02:00
|
|
|
'''CREATE TABLE whitelist (label text, address text, enabled bool)''')
|
2013-06-20 23:23:03 +02:00
|
|
|
self.cur.execute(
|
2019-10-05 09:31:48 +02:00
|
|
|
'''CREATE TABLE pubkeys (address text, addressversion int, transmitdata blob, time int,'''
|
|
|
|
''' usedpersonally text, UNIQUE(address) ON CONFLICT REPLACE)''')
|
2013-06-20 23:23:03 +02:00
|
|
|
self.cur.execute(
|
2019-10-05 09:31:48 +02:00
|
|
|
'''CREATE TABLE inventory (hash blob, objecttype int, streamnumber int, payload blob,'''
|
|
|
|
''' expirestime integer, tag blob, UNIQUE(hash) ON CONFLICT REPLACE)''')
|
2013-06-20 23:23:03 +02:00
|
|
|
self.cur.execute(
|
2019-10-05 09:31:48 +02:00
|
|
|
'''INSERT INTO subscriptions VALUES'''
|
|
|
|
'''('Bitmessage new releases/announcements','BM-GtovgYdgs7qXPkoYaRgrLFuFKz1SFpsw',1)''')
|
2013-06-20 23:23:03 +02:00
|
|
|
self.cur.execute(
|
2019-10-05 09:31:48 +02:00
|
|
|
'''CREATE TABLE settings (key blob, value blob, UNIQUE(key) ON CONFLICT REPLACE)''')
|
|
|
|
self.cur.execute('''INSERT INTO settings VALUES('version','10')''')
|
|
|
|
self.cur.execute('''INSERT INTO settings VALUES('lastvacuumtime',?)''', (
|
2013-06-20 23:23:03 +02:00
|
|
|
int(time.time()),))
|
2013-12-02 07:35:34 +01:00
|
|
|
self.cur.execute(
|
2019-10-05 09:31:48 +02:00
|
|
|
'''CREATE TABLE objectprocessorqueue'''
|
|
|
|
''' (objecttype int, data blob, UNIQUE(objecttype, data) ON CONFLICT REPLACE)''')
|
2013-06-20 23:23:03 +02:00
|
|
|
self.conn.commit()
|
2013-08-11 01:02:38 +02:00
|
|
|
logger.info('Created messages database file')
|
2013-06-20 23:23:03 +02:00
|
|
|
except Exception as err:
|
|
|
|
if str(err) == 'table inbox already exists':
|
2013-08-11 01:02:38 +02:00
|
|
|
logger.debug('Database file already exists.')
|
2013-06-29 19:29:35 +02:00
|
|
|
|
2013-06-20 23:23:03 +02:00
|
|
|
else:
|
|
|
|
sys.stderr.write(
|
|
|
|
'ERROR trying to create database file (message.dat). Error message: %s\n' % str(err))
|
|
|
|
os._exit(0)
|
|
|
|
|
2018-03-03 16:31:49 +01:00
|
|
|
# If the settings version is equal to 2 or 3 then the
|
|
|
|
# sqlThread will modify the pubkeys table and change
|
|
|
|
# the settings version to 4.
|
|
|
|
settingsversion = BMConfigParser().getint(
|
|
|
|
'bitmessagesettings', 'settingsversion')
|
2013-06-26 19:35:53 +02:00
|
|
|
|
2013-06-20 23:23:03 +02:00
|
|
|
# People running earlier versions of PyBitmessage do not have the
|
|
|
|
# usedpersonally field in their pubkeys table. Let's add it.
|
2018-03-03 16:31:49 +01:00
|
|
|
if settingsversion == 2:
|
2013-06-20 23:23:03 +02:00
|
|
|
item = '''ALTER TABLE pubkeys ADD usedpersonally text DEFAULT 'no' '''
|
|
|
|
parameters = ''
|
|
|
|
self.cur.execute(item, parameters)
|
|
|
|
self.conn.commit()
|
|
|
|
|
2018-03-03 16:31:49 +01:00
|
|
|
settingsversion = 3
|
2013-06-20 23:23:03 +02:00
|
|
|
|
|
|
|
# People running earlier versions of PyBitmessage do not have the
|
|
|
|
# encodingtype field in their inbox and sent tables or the read field
|
|
|
|
# in the inbox table. Let's add them.
|
2018-03-03 16:31:49 +01:00
|
|
|
if settingsversion == 3:
|
2013-06-20 23:23:03 +02:00
|
|
|
item = '''ALTER TABLE inbox ADD encodingtype int DEFAULT '2' '''
|
|
|
|
parameters = ''
|
|
|
|
self.cur.execute(item, parameters)
|
|
|
|
|
|
|
|
item = '''ALTER TABLE inbox ADD read bool DEFAULT '1' '''
|
|
|
|
parameters = ''
|
|
|
|
self.cur.execute(item, parameters)
|
|
|
|
|
|
|
|
item = '''ALTER TABLE sent ADD encodingtype int DEFAULT '2' '''
|
|
|
|
parameters = ''
|
|
|
|
self.cur.execute(item, parameters)
|
|
|
|
self.conn.commit()
|
|
|
|
|
2018-03-03 16:31:49 +01:00
|
|
|
settingsversion = 4
|
2013-06-20 23:23:03 +02:00
|
|
|
|
2018-03-03 16:31:49 +01:00
|
|
|
BMConfigParser().set(
|
|
|
|
'bitmessagesettings', 'settingsversion', str(settingsversion))
|
|
|
|
BMConfigParser().save()
|
2013-06-20 23:23:03 +02:00
|
|
|
|
2018-03-03 16:31:49 +01:00
|
|
|
helper_startup.updateConfig()
|
2013-06-20 23:23:03 +02:00
|
|
|
|
|
|
|
# From now on, let us keep a 'version' embedded in the messages.dat
|
|
|
|
# file so that when we make changes to the database, the database
|
|
|
|
# version we are on can stay embedded in the messages.dat file. Let us
|
|
|
|
# check to see if the settings table exists yet.
|
|
|
|
item = '''SELECT name FROM sqlite_master WHERE type='table' AND name='settings';'''
|
|
|
|
parameters = ''
|
|
|
|
self.cur.execute(item, parameters)
|
|
|
|
if self.cur.fetchall() == []:
|
|
|
|
# The settings table doesn't exist. We need to make it.
|
2018-03-03 16:31:49 +01:00
|
|
|
logger.debug(
|
|
|
|
"In messages.dat database, creating new 'settings' table.")
|
2013-06-20 23:23:03 +02:00
|
|
|
self.cur.execute(
|
2019-10-05 09:31:48 +02:00
|
|
|
'''CREATE TABLE settings (key text, value blob, UNIQUE(key) ON CONFLICT REPLACE)''')
|
|
|
|
self.cur.execute('''INSERT INTO settings VALUES('version','1')''')
|
|
|
|
self.cur.execute('''INSERT INTO settings VALUES('lastvacuumtime',?)''', (
|
2013-06-20 23:23:03 +02:00
|
|
|
int(time.time()),))
|
2013-08-11 01:02:38 +02:00
|
|
|
logger.debug('In messages.dat database, removing an obsolete field from the pubkeys table.')
|
2013-06-20 23:23:03 +02:00
|
|
|
self.cur.execute(
|
2019-10-05 09:31:48 +02:00
|
|
|
'''CREATE TEMPORARY TABLE pubkeys_backup(hash blob, transmitdata blob, time int,'''
|
|
|
|
''' usedpersonally text, UNIQUE(hash) ON CONFLICT REPLACE);''')
|
2013-06-20 23:23:03 +02:00
|
|
|
self.cur.execute(
|
|
|
|
'''INSERT INTO pubkeys_backup SELECT hash, transmitdata, time, usedpersonally FROM pubkeys;''')
|
2019-10-05 09:31:48 +02:00
|
|
|
self.cur.execute('''DROP TABLE pubkeys''')
|
2013-06-20 23:23:03 +02:00
|
|
|
self.cur.execute(
|
2019-10-05 09:31:48 +02:00
|
|
|
'''CREATE TABLE pubkeys'''
|
|
|
|
''' (hash blob, transmitdata blob, time int, usedpersonally text, UNIQUE(hash) ON CONFLICT REPLACE)''')
|
2013-06-20 23:23:03 +02:00
|
|
|
self.cur.execute(
|
|
|
|
'''INSERT INTO pubkeys SELECT hash, transmitdata, time, usedpersonally FROM pubkeys_backup;''')
|
2019-10-05 09:31:48 +02:00
|
|
|
self.cur.execute('''DROP TABLE pubkeys_backup;''')
|
|
|
|
logger.debug(
|
|
|
|
'Deleting all pubkeys from inventory.'
|
|
|
|
' They will be redownloaded and then saved with the correct times.')
|
2013-06-20 23:23:03 +02:00
|
|
|
self.cur.execute(
|
|
|
|
'''delete from inventory where objecttype = 'pubkey';''')
|
2013-08-11 01:02:38 +02:00
|
|
|
logger.debug('replacing Bitmessage announcements mailing list with a new one.')
|
2013-06-20 23:23:03 +02:00
|
|
|
self.cur.execute(
|
|
|
|
'''delete from subscriptions where address='BM-BbkPSZbzPwpVcYZpU4yHwf9ZPEapN5Zx' ''')
|
|
|
|
self.cur.execute(
|
2019-10-05 09:31:48 +02:00
|
|
|
'''INSERT INTO subscriptions VALUES'''
|
|
|
|
'''('Bitmessage new releases/announcements','BM-GtovgYdgs7qXPkoYaRgrLFuFKz1SFpsw',1)''')
|
2013-08-11 01:02:38 +02:00
|
|
|
logger.debug('Commiting.')
|
2013-06-20 23:23:03 +02:00
|
|
|
self.conn.commit()
|
2013-08-11 01:02:38 +02:00
|
|
|
logger.debug('Vacuuming message.dat. You might notice that the file size gets much smaller.')
|
2019-10-05 09:31:48 +02:00
|
|
|
self.cur.execute(''' VACUUM ''')
|
2013-06-20 23:23:03 +02:00
|
|
|
|
|
|
|
# After code refactoring, the possible status values for sent messages
|
2013-06-26 19:35:53 +02:00
|
|
|
# have changed.
|
2013-06-20 23:23:03 +02:00
|
|
|
self.cur.execute(
|
|
|
|
'''update sent set status='doingmsgpow' where status='doingpow' ''')
|
|
|
|
self.cur.execute(
|
|
|
|
'''update sent set status='msgsent' where status='sentmessage' ''')
|
|
|
|
self.cur.execute(
|
|
|
|
'''update sent set status='doingpubkeypow' where status='findingpubkey' ''')
|
|
|
|
self.cur.execute(
|
|
|
|
'''update sent set status='broadcastqueued' where status='broadcastpending' ''')
|
|
|
|
self.conn.commit()
|
2018-05-02 17:29:55 +02:00
|
|
|
|
2018-03-03 16:31:49 +01:00
|
|
|
# Let's get rid of the first20bytesofencryptedmessage field in
|
|
|
|
# the inventory table.
|
2013-09-13 06:27:34 +02:00
|
|
|
item = '''SELECT value FROM settings WHERE key='version';'''
|
|
|
|
parameters = ''
|
|
|
|
self.cur.execute(item, parameters)
|
|
|
|
if int(self.cur.fetchall()[0][0]) == 2:
|
2018-03-03 16:31:49 +01:00
|
|
|
logger.debug(
|
|
|
|
'In messages.dat database, removing an obsolete field from'
|
|
|
|
' the inventory table.')
|
2013-09-15 03:06:26 +02:00
|
|
|
self.cur.execute(
|
2019-10-05 09:31:48 +02:00
|
|
|
'''CREATE TEMPORARY TABLE inventory_backup'''
|
|
|
|
'''(hash blob, objecttype text, streamnumber int, payload blob,'''
|
|
|
|
''' receivedtime integer, UNIQUE(hash) ON CONFLICT REPLACE);''')
|
2013-09-15 03:06:26 +02:00
|
|
|
self.cur.execute(
|
2019-10-05 09:31:48 +02:00
|
|
|
'''INSERT INTO inventory_backup SELECT hash, objecttype, streamnumber, payload, receivedtime'''
|
|
|
|
''' FROM inventory;''')
|
|
|
|
self.cur.execute('''DROP TABLE inventory''')
|
2013-09-15 03:06:26 +02:00
|
|
|
self.cur.execute(
|
2019-10-05 09:31:48 +02:00
|
|
|
'''CREATE TABLE inventory'''
|
|
|
|
''' (hash blob, objecttype text, streamnumber int, payload blob, receivedtime integer,'''
|
|
|
|
''' UNIQUE(hash) ON CONFLICT REPLACE)''')
|
2013-09-15 03:06:26 +02:00
|
|
|
self.cur.execute(
|
2019-10-05 09:31:48 +02:00
|
|
|
'''INSERT INTO inventory SELECT hash, objecttype, streamnumber, payload, receivedtime'''
|
|
|
|
''' FROM inventory_backup;''')
|
|
|
|
self.cur.execute('''DROP TABLE inventory_backup;''')
|
2013-09-15 03:06:26 +02:00
|
|
|
item = '''update settings set value=? WHERE key='version';'''
|
|
|
|
parameters = (3,)
|
|
|
|
self.cur.execute(item, parameters)
|
|
|
|
|
|
|
|
# Add a new column to the inventory table to store tags.
|
|
|
|
item = '''SELECT value FROM settings WHERE key='version';'''
|
|
|
|
parameters = ''
|
|
|
|
self.cur.execute(item, parameters)
|
|
|
|
currentVersion = int(self.cur.fetchall()[0][0])
|
|
|
|
if currentVersion == 1 or currentVersion == 3:
|
2018-03-03 16:31:49 +01:00
|
|
|
logger.debug(
|
|
|
|
'In messages.dat database, adding tag field to'
|
|
|
|
' the inventory table.')
|
2013-09-13 06:27:34 +02:00
|
|
|
item = '''ALTER TABLE inventory ADD tag blob DEFAULT '' '''
|
|
|
|
parameters = ''
|
|
|
|
self.cur.execute(item, parameters)
|
|
|
|
item = '''update settings set value=? WHERE key='version';'''
|
2013-09-15 03:06:26 +02:00
|
|
|
parameters = (4,)
|
2013-09-13 06:27:34 +02:00
|
|
|
self.cur.execute(item, parameters)
|
|
|
|
|
2013-09-30 01:24:27 +02:00
|
|
|
# Add a new column to the pubkeys table to store the address version.
|
|
|
|
# We're going to trash all of our pubkeys and let them be redownloaded.
|
|
|
|
item = '''SELECT value FROM settings WHERE key='version';'''
|
|
|
|
parameters = ''
|
|
|
|
self.cur.execute(item, parameters)
|
|
|
|
currentVersion = int(self.cur.fetchall()[0][0])
|
|
|
|
if currentVersion == 4:
|
2018-03-03 16:31:49 +01:00
|
|
|
self.cur.execute('''DROP TABLE pubkeys''')
|
2013-09-30 01:24:27 +02:00
|
|
|
self.cur.execute(
|
2019-10-05 09:31:48 +02:00
|
|
|
'''CREATE TABLE pubkeys (hash blob, addressversion int, transmitdata blob, time int,'''
|
|
|
|
'''usedpersonally text, UNIQUE(hash, addressversion) ON CONFLICT REPLACE)''')
|
2013-09-30 01:24:27 +02:00
|
|
|
self.cur.execute(
|
|
|
|
'''delete from inventory where objecttype = 'pubkey';''')
|
|
|
|
item = '''update settings set value=? WHERE key='version';'''
|
|
|
|
parameters = (5,)
|
|
|
|
self.cur.execute(item, parameters)
|
2018-05-02 17:29:55 +02:00
|
|
|
|
2013-12-02 07:35:34 +01:00
|
|
|
# Add a new table: objectprocessorqueue with which to hold objects
|
|
|
|
# that have yet to be processed if the user shuts down Bitmessage.
|
|
|
|
item = '''SELECT value FROM settings WHERE key='version';'''
|
|
|
|
parameters = ''
|
|
|
|
self.cur.execute(item, parameters)
|
|
|
|
currentVersion = int(self.cur.fetchall()[0][0])
|
|
|
|
if currentVersion == 5:
|
2018-03-03 16:31:49 +01:00
|
|
|
self.cur.execute('''DROP TABLE knownnodes''')
|
2013-12-02 07:35:34 +01:00
|
|
|
self.cur.execute(
|
2019-10-05 09:31:48 +02:00
|
|
|
'''CREATE TABLE objectprocessorqueue'''
|
|
|
|
''' (objecttype text, data blob, UNIQUE(objecttype, data) ON CONFLICT REPLACE)''')
|
2013-12-02 07:35:34 +01:00
|
|
|
item = '''update settings set value=? WHERE key='version';'''
|
|
|
|
parameters = (6,)
|
|
|
|
self.cur.execute(item, parameters)
|
2018-05-02 17:29:55 +02:00
|
|
|
|
2014-08-27 09:14:32 +02:00
|
|
|
# changes related to protocol v3
|
2018-03-03 16:31:49 +01:00
|
|
|
# In table inventory and objectprocessorqueue, objecttype is now
|
|
|
|
# an integer (it was a human-friendly string previously)
|
2014-08-27 09:14:32 +02:00
|
|
|
item = '''SELECT value FROM settings WHERE key='version';'''
|
|
|
|
parameters = ''
|
|
|
|
self.cur.execute(item, parameters)
|
|
|
|
currentVersion = int(self.cur.fetchall()[0][0])
|
|
|
|
if currentVersion == 6:
|
2018-03-03 16:31:49 +01:00
|
|
|
logger.debug(
|
|
|
|
'In messages.dat database, dropping and recreating'
|
|
|
|
' the inventory table.')
|
2019-10-05 09:31:48 +02:00
|
|
|
self.cur.execute('''DROP TABLE inventory''')
|
|
|
|
self.cur.execute(
|
|
|
|
'''CREATE TABLE inventory'''
|
|
|
|
''' (hash blob, objecttype int, streamnumber int, payload blob, expirestime integer,'''
|
|
|
|
''' tag blob, UNIQUE(hash) ON CONFLICT REPLACE)''')
|
|
|
|
self.cur.execute('''DROP TABLE objectprocessorqueue''')
|
|
|
|
self.cur.execute(
|
|
|
|
'''CREATE TABLE objectprocessorqueue'''
|
|
|
|
''' (objecttype int, data blob, UNIQUE(objecttype, data) ON CONFLICT REPLACE)''')
|
2014-08-27 09:14:32 +02:00
|
|
|
item = '''update settings set value=? WHERE key='version';'''
|
|
|
|
parameters = (7,)
|
|
|
|
self.cur.execute(item, parameters)
|
2018-03-03 16:31:49 +01:00
|
|
|
logger.debug(
|
|
|
|
'Finished dropping and recreating the inventory table.')
|
2014-12-26 02:37:04 +01:00
|
|
|
|
2014-12-25 09:57:34 +01:00
|
|
|
# The format of data stored in the pubkeys table has changed. Let's
|
2018-03-03 16:31:49 +01:00
|
|
|
# clear it, and the pubkeys from inventory, so that they'll
|
|
|
|
# be re-downloaded.
|
2014-12-25 09:57:34 +01:00
|
|
|
item = '''SELECT value FROM settings WHERE key='version';'''
|
|
|
|
parameters = ''
|
|
|
|
self.cur.execute(item, parameters)
|
|
|
|
currentVersion = int(self.cur.fetchall()[0][0])
|
|
|
|
if currentVersion == 7:
|
2018-03-03 16:31:49 +01:00
|
|
|
logger.debug(
|
|
|
|
'In messages.dat database, clearing pubkeys table'
|
|
|
|
' because the data format has been updated.')
|
2014-12-25 09:57:34 +01:00
|
|
|
self.cur.execute(
|
|
|
|
'''delete from inventory where objecttype = 1;''')
|
|
|
|
self.cur.execute(
|
|
|
|
'''delete from pubkeys;''')
|
2018-03-03 16:31:49 +01:00
|
|
|
# Any sending messages for which we *thought* that we had
|
|
|
|
# the pubkey must be rechecked.
|
2014-12-25 09:57:34 +01:00
|
|
|
self.cur.execute(
|
|
|
|
'''UPDATE sent SET status='msgqueued' WHERE status='doingmsgpow' or status='badkey';''')
|
|
|
|
query = '''update settings set value=? WHERE key='version';'''
|
|
|
|
parameters = (8,)
|
|
|
|
self.cur.execute(query, parameters)
|
|
|
|
logger.debug('Finished clearing currently held pubkeys.')
|
2015-02-21 03:03:20 +01:00
|
|
|
|
2018-03-03 16:31:49 +01:00
|
|
|
# Add a new column to the inbox table to store the hash of
|
|
|
|
# the message signature. We'll use this as temporary message UUID
|
|
|
|
# in order to detect duplicates.
|
2015-02-21 03:03:20 +01:00
|
|
|
item = '''SELECT value FROM settings WHERE key='version';'''
|
|
|
|
parameters = ''
|
|
|
|
self.cur.execute(item, parameters)
|
|
|
|
currentVersion = int(self.cur.fetchall()[0][0])
|
|
|
|
if currentVersion == 8:
|
2018-03-03 16:31:49 +01:00
|
|
|
logger.debug(
|
|
|
|
'In messages.dat database, adding sighash field to'
|
|
|
|
' the inbox table.')
|
2015-02-21 03:03:20 +01:00
|
|
|
item = '''ALTER TABLE inbox ADD sighash blob DEFAULT '' '''
|
|
|
|
parameters = ''
|
|
|
|
self.cur.execute(item, parameters)
|
|
|
|
item = '''update settings set value=? WHERE key='version';'''
|
|
|
|
parameters = (9,)
|
|
|
|
self.cur.execute(item, parameters)
|
2018-05-02 17:29:55 +02:00
|
|
|
|
2018-03-03 16:31:49 +01:00
|
|
|
# We'll also need a `sleeptill` field and a `ttl` field. Also we
|
|
|
|
# can combine the pubkeyretrynumber and msgretrynumber into one.
|
2015-03-09 07:35:32 +01:00
|
|
|
item = '''SELECT value FROM settings WHERE key='version';'''
|
|
|
|
parameters = ''
|
|
|
|
self.cur.execute(item, parameters)
|
|
|
|
currentVersion = int(self.cur.fetchall()[0][0])
|
|
|
|
if currentVersion == 9:
|
2018-03-03 16:31:49 +01:00
|
|
|
logger.info(
|
|
|
|
'In messages.dat database, making TTL-related changes:'
|
|
|
|
' combining the pubkeyretrynumber and msgretrynumber'
|
|
|
|
' fields into the retrynumber field and adding the'
|
|
|
|
' sleeptill and ttl fields...')
|
2015-03-09 07:35:32 +01:00
|
|
|
self.cur.execute(
|
2019-10-05 09:31:48 +02:00
|
|
|
'''CREATE TEMPORARY TABLE sent_backup'''
|
|
|
|
''' (msgid blob, toaddress text, toripe blob, fromaddress text, subject text, message text,'''
|
|
|
|
''' ackdata blob, lastactiontime integer, status text, retrynumber integer,'''
|
|
|
|
''' folder text, encodingtype int)''')
|
2015-03-09 07:35:32 +01:00
|
|
|
self.cur.execute(
|
2019-10-05 09:31:48 +02:00
|
|
|
'''INSERT INTO sent_backup SELECT msgid, toaddress, toripe, fromaddress,'''
|
|
|
|
''' subject, message, ackdata, lastactiontime,'''
|
|
|
|
''' status, 0, folder, encodingtype FROM sent;''')
|
|
|
|
self.cur.execute('''DROP TABLE sent''')
|
2015-03-09 07:35:32 +01:00
|
|
|
self.cur.execute(
|
2019-10-05 09:31:48 +02:00
|
|
|
'''CREATE TABLE sent'''
|
|
|
|
''' (msgid blob, toaddress text, toripe blob, fromaddress text, subject text, message text,'''
|
|
|
|
''' ackdata blob, senttime integer, lastactiontime integer, sleeptill int, status text,'''
|
|
|
|
''' retrynumber integer, folder text, encodingtype int, ttl int)''')
|
2015-03-09 07:35:32 +01:00
|
|
|
self.cur.execute(
|
2019-10-05 09:31:48 +02:00
|
|
|
'''INSERT INTO sent SELECT msgid, toaddress, toripe, fromaddress, subject, message, ackdata,'''
|
|
|
|
''' lastactiontime, lastactiontime, 0, status, 0, folder, encodingtype, 216000 FROM sent_backup;''')
|
|
|
|
self.cur.execute('''DROP TABLE sent_backup''')
|
2015-03-09 07:35:32 +01:00
|
|
|
logger.info('In messages.dat database, finished making TTL-related changes.')
|
|
|
|
logger.debug('In messages.dat database, adding address field to the pubkeys table.')
|
|
|
|
# We're going to have to calculate the address for each row in the pubkeys
|
2018-05-02 17:29:55 +02:00
|
|
|
# table. Then we can take out the hash field.
|
2015-03-09 07:35:32 +01:00
|
|
|
self.cur.execute('''ALTER TABLE pubkeys ADD address text DEFAULT '' ''')
|
|
|
|
self.cur.execute('''SELECT hash, addressversion FROM pubkeys''')
|
|
|
|
queryResult = self.cur.fetchall()
|
|
|
|
from addresses import encodeAddress
|
|
|
|
for row in queryResult:
|
2018-05-02 17:29:55 +02:00
|
|
|
addressHash, addressVersion = row
|
2015-03-09 07:35:32 +01:00
|
|
|
address = encodeAddress(addressVersion, 1, hash)
|
|
|
|
item = '''UPDATE pubkeys SET address=? WHERE hash=?;'''
|
2018-05-02 17:29:55 +02:00
|
|
|
parameters = (address, addressHash)
|
2015-03-09 07:35:32 +01:00
|
|
|
self.cur.execute(item, parameters)
|
|
|
|
# Now we can remove the hash field from the pubkeys table.
|
|
|
|
self.cur.execute(
|
2019-10-05 09:31:48 +02:00
|
|
|
'''CREATE TEMPORARY TABLE pubkeys_backup'''
|
|
|
|
''' (address text, addressversion int, transmitdata blob, time int,'''
|
|
|
|
''' usedpersonally text, UNIQUE(address) ON CONFLICT REPLACE)''')
|
2015-03-09 07:35:32 +01:00
|
|
|
self.cur.execute(
|
2019-10-05 09:31:48 +02:00
|
|
|
'''INSERT INTO pubkeys_backup'''
|
|
|
|
''' SELECT address, addressversion, transmitdata, time, usedpersonally FROM pubkeys;''')
|
|
|
|
self.cur.execute('''DROP TABLE pubkeys''')
|
2015-03-09 07:35:32 +01:00
|
|
|
self.cur.execute(
|
2019-10-05 09:31:48 +02:00
|
|
|
'''CREATE TABLE pubkeys'''
|
|
|
|
''' (address text, addressversion int, transmitdata blob, time int, usedpersonally text,'''
|
|
|
|
''' UNIQUE(address) ON CONFLICT REPLACE)''')
|
2015-03-09 07:35:32 +01:00
|
|
|
self.cur.execute(
|
2019-10-05 09:31:48 +02:00
|
|
|
'''INSERT INTO pubkeys SELECT'''
|
|
|
|
''' address, addressversion, transmitdata, time, usedpersonally FROM pubkeys_backup;''')
|
|
|
|
self.cur.execute('''DROP TABLE pubkeys_backup''')
|
|
|
|
logger.debug(
|
|
|
|
'In messages.dat database, done adding address field to the pubkeys table'
|
|
|
|
' and removing the hash field.')
|
2015-03-09 07:35:32 +01:00
|
|
|
self.cur.execute('''update settings set value=10 WHERE key='version';''')
|
2018-05-02 17:29:55 +02:00
|
|
|
|
2013-08-28 04:29:39 +02:00
|
|
|
# Are you hoping to add a new option to the keys.dat file of existing
|
2018-03-03 16:31:49 +01:00
|
|
|
# Bitmessage users or modify the SQLite database? Add it right
|
|
|
|
# above this line!
|
2018-05-02 17:29:55 +02:00
|
|
|
|
2013-06-20 23:23:03 +02:00
|
|
|
try:
|
|
|
|
testpayload = '\x00\x00'
|
2013-09-30 01:24:27 +02:00
|
|
|
t = ('1234', 1, testpayload, '12345678', 'no')
|
2019-10-05 09:31:48 +02:00
|
|
|
self.cur.execute('''INSERT INTO pubkeys VALUES(?,?,?,?,?)''', t)
|
2013-06-20 23:23:03 +02:00
|
|
|
self.conn.commit()
|
|
|
|
self.cur.execute(
|
2015-03-09 07:35:32 +01:00
|
|
|
'''SELECT transmitdata FROM pubkeys WHERE address='1234' ''')
|
2013-06-20 23:23:03 +02:00
|
|
|
queryreturn = self.cur.fetchall()
|
|
|
|
for row in queryreturn:
|
|
|
|
transmitdata, = row
|
2015-03-09 07:35:32 +01:00
|
|
|
self.cur.execute('''DELETE FROM pubkeys WHERE address='1234' ''')
|
2013-06-20 23:23:03 +02:00
|
|
|
self.conn.commit()
|
|
|
|
if transmitdata == '':
|
2019-10-05 09:31:48 +02:00
|
|
|
logger.fatal(
|
|
|
|
'Problem: The version of SQLite you have cannot store Null values.'
|
|
|
|
' Please download and install the latest revision of your version of Python'
|
|
|
|
' (for example, the latest Python 2.7 revision) and try again.\n')
|
|
|
|
logger.fatal(
|
|
|
|
'PyBitmessage will now exit very abruptly.'
|
|
|
|
' You may now see threading errors related to this abrupt exit'
|
|
|
|
' but the problem you need to solve is related to SQLite.\n\n')
|
2013-06-20 23:23:03 +02:00
|
|
|
os._exit(0)
|
|
|
|
except Exception as err:
|
2013-09-05 02:14:25 +02:00
|
|
|
if str(err) == 'database or disk is full':
|
2019-10-05 09:31:48 +02:00
|
|
|
logger.fatal(
|
|
|
|
'(While null value test) Alert: Your disk or data storage volume is full.'
|
|
|
|
' sqlThread will now exit.')
|
|
|
|
queues.UISignalQueue.put((
|
|
|
|
'alert', (
|
|
|
|
tr._translate(
|
|
|
|
"MainWindow",
|
|
|
|
"Disk full"),
|
|
|
|
tr._translate(
|
|
|
|
"MainWindow",
|
|
|
|
'Alert: Your disk or data storage volume is full. Bitmessage will now exit.'),
|
|
|
|
True)))
|
2016-06-29 22:08:34 +02:00
|
|
|
os._exit(0)
|
2013-09-05 02:14:25 +02:00
|
|
|
else:
|
|
|
|
logger.error(err)
|
2013-06-20 23:23:03 +02:00
|
|
|
|
|
|
|
# Let us check to see the last time we vaccumed the messages.dat file.
|
|
|
|
# If it has been more than a month let's do it now.
|
|
|
|
item = '''SELECT value FROM settings WHERE key='lastvacuumtime';'''
|
|
|
|
parameters = ''
|
|
|
|
self.cur.execute(item, parameters)
|
|
|
|
queryreturn = self.cur.fetchall()
|
|
|
|
for row in queryreturn:
|
|
|
|
value, = row
|
2015-06-20 09:54:15 +02:00
|
|
|
if int(value) < int(time.time()) - 86400:
|
2013-08-11 01:02:38 +02:00
|
|
|
logger.info('It has been a long time since the messages.dat file has been vacuumed. Vacuuming now...')
|
2013-09-05 02:14:25 +02:00
|
|
|
try:
|
2019-10-05 09:31:48 +02:00
|
|
|
self.cur.execute(''' VACUUM ''')
|
2013-09-05 02:14:25 +02:00
|
|
|
except Exception as err:
|
|
|
|
if str(err) == 'database or disk is full':
|
2019-10-05 09:31:48 +02:00
|
|
|
logger.fatal(
|
|
|
|
'(While VACUUM) Alert: Your disk or data storage volume is full.'
|
|
|
|
' sqlThread will now exit.')
|
|
|
|
queues.UISignalQueue.put((
|
|
|
|
'alert', (
|
|
|
|
tr._translate(
|
|
|
|
"MainWindow",
|
|
|
|
"Disk full"),
|
|
|
|
tr._translate(
|
|
|
|
"MainWindow",
|
|
|
|
'Alert: Your disk or data storage volume is full. Bitmessage will now exit.'),
|
|
|
|
True)))
|
2016-06-29 22:08:34 +02:00
|
|
|
os._exit(0)
|
2013-06-20 23:23:03 +02:00
|
|
|
item = '''update settings set value=? WHERE key='lastvacuumtime';'''
|
|
|
|
parameters = (int(time.time()),)
|
|
|
|
self.cur.execute(item, parameters)
|
|
|
|
|
2017-02-26 20:44:56 +01:00
|
|
|
state.sqlReady = True
|
|
|
|
|
2013-06-20 23:23:03 +02:00
|
|
|
while True:
|
2017-02-08 13:41:56 +01:00
|
|
|
item = helper_sql.sqlSubmitQueue.get()
|
2013-06-20 23:23:03 +02:00
|
|
|
if item == 'commit':
|
2013-09-05 02:14:25 +02:00
|
|
|
try:
|
|
|
|
self.conn.commit()
|
|
|
|
except Exception as err:
|
|
|
|
if str(err) == 'database or disk is full':
|
2019-10-05 09:31:48 +02:00
|
|
|
logger.fatal(
|
|
|
|
'(While committing) Alert: Your disk or data storage volume is full.'
|
|
|
|
' sqlThread will now exit.')
|
|
|
|
queues.UISignalQueue.put((
|
|
|
|
'alert', (
|
|
|
|
tr._translate(
|
|
|
|
"MainWindow",
|
|
|
|
"Disk full"),
|
|
|
|
tr._translate(
|
|
|
|
"MainWindow",
|
|
|
|
'Alert: Your disk or data storage volume is full. Bitmessage will now exit.'),
|
|
|
|
True)))
|
2016-06-29 22:08:34 +02:00
|
|
|
os._exit(0)
|
2013-06-20 23:23:03 +02:00
|
|
|
elif item == 'exit':
|
|
|
|
self.conn.close()
|
2013-08-11 01:02:38 +02:00
|
|
|
logger.info('sqlThread exiting gracefully.')
|
2013-06-29 19:29:35 +02:00
|
|
|
|
2013-06-20 23:23:03 +02:00
|
|
|
return
|
|
|
|
elif item == 'movemessagstoprog':
|
2013-08-11 01:02:38 +02:00
|
|
|
logger.debug('the sqlThread is moving the messages.dat file to the local program directory.')
|
2013-06-29 19:29:35 +02:00
|
|
|
|
2013-09-05 02:14:25 +02:00
|
|
|
try:
|
|
|
|
self.conn.commit()
|
|
|
|
except Exception as err:
|
|
|
|
if str(err) == 'database or disk is full':
|
2019-10-05 09:31:48 +02:00
|
|
|
logger.fatal(
|
|
|
|
'(while movemessagstoprog) Alert: Your disk or data storage volume is full.'
|
|
|
|
' sqlThread will now exit.')
|
|
|
|
queues.UISignalQueue.put((
|
|
|
|
'alert', (
|
|
|
|
tr._translate(
|
|
|
|
"MainWindow",
|
|
|
|
"Disk full"),
|
|
|
|
tr._translate(
|
|
|
|
"MainWindow",
|
|
|
|
'Alert: Your disk or data storage volume is full. Bitmessage will now exit.'),
|
|
|
|
True)))
|
2016-06-29 22:08:34 +02:00
|
|
|
os._exit(0)
|
2013-06-20 23:23:03 +02:00
|
|
|
self.conn.close()
|
|
|
|
shutil.move(
|
2017-01-11 17:00:00 +01:00
|
|
|
paths.lookupAppdataFolder() + 'messages.dat', paths.lookupExeFolder() + 'messages.dat')
|
|
|
|
self.conn = sqlite3.connect(paths.lookupExeFolder() + 'messages.dat')
|
2013-06-20 23:23:03 +02:00
|
|
|
self.conn.text_factory = str
|
|
|
|
self.cur = self.conn.cursor()
|
|
|
|
elif item == 'movemessagstoappdata':
|
2013-08-11 01:02:38 +02:00
|
|
|
logger.debug('the sqlThread is moving the messages.dat file to the Appdata folder.')
|
2013-06-29 19:29:35 +02:00
|
|
|
|
2013-09-05 02:14:25 +02:00
|
|
|
try:
|
|
|
|
self.conn.commit()
|
|
|
|
except Exception as err:
|
|
|
|
if str(err) == 'database or disk is full':
|
2019-10-05 09:31:48 +02:00
|
|
|
logger.fatal(
|
|
|
|
'(while movemessagstoappdata) Alert: Your disk or data storage volume is full.'
|
|
|
|
' sqlThread will now exit.')
|
|
|
|
queues.UISignalQueue.put((
|
|
|
|
'alert', (
|
|
|
|
tr._translate(
|
|
|
|
"MainWindow",
|
|
|
|
"Disk full"),
|
|
|
|
tr._translate(
|
|
|
|
"MainWindow",
|
|
|
|
'Alert: Your disk or data storage volume is full. Bitmessage will now exit.'),
|
|
|
|
True)))
|
2016-06-29 22:08:34 +02:00
|
|
|
os._exit(0)
|
2013-06-20 23:23:03 +02:00
|
|
|
self.conn.close()
|
|
|
|
shutil.move(
|
2017-01-11 17:00:00 +01:00
|
|
|
paths.lookupExeFolder() + 'messages.dat', paths.lookupAppdataFolder() + 'messages.dat')
|
|
|
|
self.conn = sqlite3.connect(paths.lookupAppdataFolder() + 'messages.dat')
|
2013-06-20 23:23:03 +02:00
|
|
|
self.conn.text_factory = str
|
|
|
|
self.cur = self.conn.cursor()
|
|
|
|
elif item == 'deleteandvacuume':
|
|
|
|
self.cur.execute('''delete from inbox where folder='trash' ''')
|
|
|
|
self.cur.execute('''delete from sent where folder='trash' ''')
|
|
|
|
self.conn.commit()
|
2013-09-05 02:14:25 +02:00
|
|
|
try:
|
2019-10-05 09:31:48 +02:00
|
|
|
self.cur.execute(''' VACUUM ''')
|
2013-09-05 02:14:25 +02:00
|
|
|
except Exception as err:
|
|
|
|
if str(err) == 'database or disk is full':
|
2019-10-05 09:31:48 +02:00
|
|
|
logger.fatal(
|
|
|
|
'(while deleteandvacuume) Alert: Your disk or data storage volume is full.'
|
|
|
|
' sqlThread will now exit.')
|
|
|
|
queues.UISignalQueue.put((
|
|
|
|
'alert', (
|
|
|
|
tr._translate(
|
|
|
|
"MainWindow",
|
|
|
|
"Disk full"),
|
|
|
|
tr._translate(
|
|
|
|
"MainWindow",
|
|
|
|
'Alert: Your disk or data storage volume is full. Bitmessage will now exit.'),
|
|
|
|
True)))
|
2016-06-29 22:08:34 +02:00
|
|
|
os._exit(0)
|
2013-06-20 23:23:03 +02:00
|
|
|
else:
|
2017-02-08 13:41:56 +01:00
|
|
|
parameters = helper_sql.sqlSubmitQueue.get()
|
2016-03-22 17:17:45 +01:00
|
|
|
rowcount = 0
|
2013-06-20 23:23:03 +02:00
|
|
|
# print 'item', item
|
|
|
|
# print 'parameters', parameters
|
|
|
|
try:
|
|
|
|
self.cur.execute(item, parameters)
|
2016-03-22 17:17:45 +01:00
|
|
|
rowcount = self.cur.rowcount
|
2013-06-20 23:23:03 +02:00
|
|
|
except Exception as err:
|
2013-09-05 02:14:25 +02:00
|
|
|
if str(err) == 'database or disk is full':
|
2019-10-05 09:31:48 +02:00
|
|
|
logger.fatal(
|
|
|
|
'(while cur.execute) Alert: Your disk or data storage volume is full.'
|
|
|
|
' sqlThread will now exit.')
|
|
|
|
queues.UISignalQueue.put((
|
|
|
|
'alert', (
|
|
|
|
tr._translate(
|
|
|
|
"MainWindow",
|
|
|
|
"Disk full"),
|
|
|
|
tr._translate(
|
|
|
|
"MainWindow",
|
|
|
|
'Alert: Your disk or data storage volume is full. Bitmessage will now exit.'),
|
|
|
|
True)))
|
2016-06-29 22:08:34 +02:00
|
|
|
os._exit(0)
|
2013-09-05 02:14:25 +02:00
|
|
|
else:
|
2019-10-05 09:31:48 +02:00
|
|
|
logger.fatal(
|
|
|
|
'Major error occurred when trying to execute a SQL statement within the sqlThread.'
|
|
|
|
' Please tell Atheros about this error message or post it in the forum!'
|
|
|
|
' Error occurred while trying to execute statement: "%s" Here are the parameters;'
|
|
|
|
' you might want to censor this data with asterisks (***)'
|
|
|
|
' as it can contain private information: %s.'
|
|
|
|
' Here is the actual error message thrown by the sqlThread: %s',
|
|
|
|
str(item),
|
|
|
|
str(repr(parameters)),
|
|
|
|
str(err))
|
2013-09-05 02:14:25 +02:00
|
|
|
logger.fatal('This program shall now abruptly exit!')
|
2013-06-29 19:29:35 +02:00
|
|
|
|
2013-06-20 23:23:03 +02:00
|
|
|
os._exit(0)
|
|
|
|
|
2017-02-08 13:41:56 +01:00
|
|
|
helper_sql.sqlReturnQueue.put((self.cur.fetchall(), rowcount))
|
|
|
|
# helper_sql.sqlSubmitQueue.task_done()
|