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