1 /*
2  * %kadu copyright begin%
3  * Copyright 2011, 2012, 2013 Bartosz Brachaczek (b.brachaczek@gmail.com)
4  * Copyright 2011, 2012, 2013, 2014 Rafał Przemysław Malinowski (rafal.przemyslaw.malinowski@gmail.com)
5  * %kadu copyright end%
6  * Copyright 2011 Wojciech Treter (juzefwt@gmail.com)
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License as
10  * published by the Free Software Foundation; either version 2 of
11  * the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program. If not, see <http://www.gnu.org/licenses/>.
20  */
21 
22 #include <QtCore/QDir>
23 #include <QtCore/QFile>
24 #include <QtCore/QFileInfo>
25 #include <QtCore/QThread>
26 #include <QtSql/QSqlError>
27 
28 #include "configuration/configuration.h"
29 #include "configuration/deprecated-configuration-api.h"
30 #include "misc/paths-provider.h"
31 #include "plugin/plugin-injected-factory.h"
32 
33 #include "storage/history-sql-storage.h"
34 #include "storage/sql-import.h"
35 #include "storage/sql-restore.h"
36 
37 #include "sql-initializer.h"
38 
39 #define HISTORY_FILE_0 "history/history.db"
40 #define HISTORY_FILE_1 "history1.db"
41 #define HISTORY_FILE_CURRENT "history2.db"
42 
SqlInitializer(QObject * parent)43 SqlInitializer::SqlInitializer(QObject *parent) :
44 		QObject(parent)
45 {
46 }
47 
~SqlInitializer()48 SqlInitializer::~SqlInitializer()
49 {
50 }
51 
setConfiguration(Configuration * configuration)52 void SqlInitializer::setConfiguration(Configuration *configuration)
53 {
54 	m_configuration = configuration;
55 }
56 
setPluginInjectedFactory(PluginInjectedFactory * pluginInjectedFactory)57 void SqlInitializer::setPluginInjectedFactory(PluginInjectedFactory *pluginInjectedFactory)
58 {
59 	m_pluginInjectedFactory = pluginInjectedFactory;
60 }
61 
setPathsProvider(PathsProvider * pathsProvider)62 void SqlInitializer::setPathsProvider(PathsProvider *pathsProvider)
63 {
64 	m_pathsProvider = pathsProvider;
65 }
66 
initialize()67 void SqlInitializer::initialize()
68 {
69 	initDatabase();
70 
71 	bool ok = Database.isOpen() && !Database.isOpenError();
72 	Database.close();
73 
74 	emit databaseReady(ok);
75 
76 	deleteLater();
77 }
78 
oldHistoryFileExists()79 bool SqlInitializer::oldHistoryFileExists()
80 {
81 	QFileInfo scheme0FileInfo(m_pathsProvider->profilePath() + QStringLiteral(HISTORY_FILE_0));
82 	QFileInfo scheme1FileInfo(m_pathsProvider->profilePath() + QStringLiteral(HISTORY_FILE_1));
83 	return scheme0FileInfo.exists() || scheme1FileInfo.exists();
84 }
85 
currentHistoryFileExists()86 bool SqlInitializer::currentHistoryFileExists()
87 {
88 	QFileInfo schemeCurrentFileInfo(m_pathsProvider->profilePath() + QStringLiteral(HISTORY_FILE_CURRENT));
89 	return schemeCurrentFileInfo.exists();
90 }
91 
copyHistoryFile()92 bool SqlInitializer::copyHistoryFile()
93 {
94 	QFileInfo schemeCurrentFileInfo(m_pathsProvider->profilePath() + QStringLiteral(HISTORY_FILE_CURRENT));
95 	if (schemeCurrentFileInfo.exists())
96 		return true;
97 
98 	QFileInfo scheme1FileInfo(m_pathsProvider->profilePath() + QStringLiteral(HISTORY_FILE_1));
99 	if (scheme1FileInfo.exists())
100 		return QFile::copy(scheme1FileInfo.absoluteFilePath(), schemeCurrentFileInfo.absoluteFilePath());
101 
102 	QFileInfo scheme0FileInfo(m_pathsProvider->profilePath() + QStringLiteral(HISTORY_FILE_0));
103 	if (scheme0FileInfo.exists())
104 		return QFile::copy(scheme0FileInfo.absoluteFilePath(), schemeCurrentFileInfo.absoluteFilePath());
105 
106 	return false;
107 }
108 
initDatabase()109 void SqlInitializer::initDatabase()
110 {
111 	if (QSqlDatabase::contains("kadu-history"))
112 	{
113 		if (Database.isOpen())
114 			Database.close();
115 		QSqlDatabase::removeDatabase("kadu-history");
116 	}
117 
118 	bool currentFileExists = currentHistoryFileExists();
119 	bool anyHistoryFileExists = currentFileExists || oldHistoryFileExists();
120 
121 	if (!currentFileExists && oldHistoryFileExists())
122 	{
123 		emit progressMessage("dialog-information", tr("Copying history file to new location: %1 ...").arg(m_pathsProvider->profilePath() + QStringLiteral(HISTORY_FILE_CURRENT)));
124 		if (!copyHistoryFile())
125 		{
126 			emit progressFinished(false, "dialog-error", tr("Unable to copy history file to new location. Check if disk is full."));
127 			return;
128 		}
129 	}
130 
131 	QString historyFilePath = m_pathsProvider->profilePath() + QStringLiteral(HISTORY_FILE_CURRENT);
132 
133 	Database = QSqlDatabase::addDatabase("QSQLITE", "kadu-history");
134 	Database.setDatabaseName(historyFilePath);
135 
136 	if (!Database.open())
137 	{
138 		emit progressFinished(false, "dialog-error", tr("Unable to open database: %1").arg(Database.lastError().text()));
139 		return;
140 	}
141 
142 	if (anyHistoryFileExists && SqlRestore::isCorrupted(Database)) // this is not new database
143 	{
144 		Database.close();
145 
146 		emit progressMessage("dialog-warning", tr("History file is corrupted, performing recovery..."));
147 
148 		auto sqlRestore = m_pluginInjectedFactory->makeUnique<SqlRestore>();
149 		SqlRestore::RestoreError error = sqlRestore->performRestore(historyFilePath);
150 		if (SqlRestore::ErrorNoError == error)
151 			emit progressMessage("dialog-information", tr("Recovery completed."));
152 		else
153 			emit progressMessage("dialog-error", tr("Recovery failed: %s").arg(SqlRestore::errorMessage(error)));
154 
155 		if (!Database.open())
156 		{
157 			emit progressFinished(false, "dialog-error", tr("Unable to open database: %1").arg(Database.lastError().text()));
158 			return;
159 		}
160 	}
161 
162 	if (SqlImport::importNeeded(Database))
163 	{
164 		if (anyHistoryFileExists)
165 			emit progressMessage("dialog-warning", tr("History file is outdated, performing import..."));
166 
167 		auto sqlImport = m_pluginInjectedFactory->makeUnique<SqlImport>();
168 		sqlImport->performImport(Database);
169 
170 		if (anyHistoryFileExists)
171 			emit progressFinished(true, "dialog-information", tr("Import completed."));
172 	}
173 	else
174 	{
175 		m_configuration->deprecatedApi()->writeEntry("History", "Schema", SqlImport::databaseSchemaVersion(Database));
176 		emit progressFinished(true, "dialog-information", tr("Copying completed."));
177 	}
178 }
179 
180 #include "moc_sql-initializer.cpp"
181