1 /* ============================================================
2  *
3  * This file is a part of digiKam project
4  * https://www.digikam.org
5  *
6  * Date        : 2009-06-27
7  * Description : Database Engine element configuration loader
8  *
9  * Copyright (C) 2009-2010 by Holger Foerster <hamsi2k at freenet dot de>
10  * Copyright (C) 2010-2021 by Gilles Caulier <caulier dot gilles at gmail dot com>
11  *
12  * This program is free software; you can redistribute it
13  * and/or modify it under the terms of the GNU General
14  * Public License as published by the Free Software Foundation;
15  * either version 2, or (at your option)
16  * any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * ============================================================ */
24 
25 #include "dbengineconfigloader.h"
26 
27 // Qt includes
28 
29 #include <QDir>
30 #include <QDomDocument>
31 #include <QDomElement>
32 #include <QDomNode>
33 #include <QDomNodeList>
34 #include <QFile>
35 #include <QIODevice>
36 #include <QTextStream>
37 
38 // KDE includes
39 
40 #include <klocalizedstring.h>
41 
42 // Local includes
43 
44 #include "digikam_debug.h"
45 
46 namespace Digikam
47 {
48 
DbEngineConfigSettingsLoader(const QString & filepath,int xmlVersion)49 DbEngineConfigSettingsLoader::DbEngineConfigSettingsLoader(const QString& filepath, int xmlVersion)
50 {
51     isValid = readConfig(filepath, xmlVersion);
52 
53     if (!isValid)
54     {
55         qCDebug(DIGIKAM_DBENGINE_LOG) << errorMessage;
56     }
57 }
58 
readDatabase(QDomElement & databaseElement)59 DbEngineConfigSettings DbEngineConfigSettingsLoader::readDatabase(QDomElement& databaseElement)
60 {
61     DbEngineConfigSettings configElement;
62     configElement.databaseID = QLatin1String("Unidentified");
63     (void)configElement.databaseID; // prevent cppcheck warning.
64 
65     if (!databaseElement.hasAttribute(QLatin1String("name")))
66     {
67         qCDebug(DIGIKAM_DBENGINE_LOG) << "Missing statement attribute <name>.";
68     }
69 
70     configElement.databaseID = databaseElement.attribute(QLatin1String("name"));
71     QDomElement element      = databaseElement.namedItem(QLatin1String("databaseName")).toElement();
72 
73     if (element.isNull())
74     {
75         qCDebug(DIGIKAM_DBENGINE_LOG) << "Missing element <databaseName>.";
76     }
77 
78     configElement.databaseName = element.text();
79     element                    = databaseElement.namedItem(QLatin1String("userName")).toElement();
80 
81     if (element.isNull())
82     {
83         qCDebug(DIGIKAM_DBENGINE_LOG) << "Missing element <userName>.";
84     }
85 
86     configElement.userName = element.text();
87     element                = databaseElement.namedItem(QLatin1String("password")).toElement();
88 
89     if (element.isNull())
90     {
91         qCDebug(DIGIKAM_DBENGINE_LOG) << "Missing element <password>.";
92     }
93 
94     configElement.password = element.text();
95     element                = databaseElement.namedItem(QLatin1String("hostName")).toElement();
96 
97     if (element.isNull())
98     {
99         qCDebug(DIGIKAM_DBENGINE_LOG) << "Missing element <hostName>.";
100     }
101 
102     configElement.hostName = element.text();
103     element                = databaseElement.namedItem(QLatin1String("port")).toElement();
104 
105     if (element.isNull())
106     {
107         qCDebug(DIGIKAM_DBENGINE_LOG) << "Missing element <port>.";
108     }
109 
110     configElement.port = element.text();
111     element            = databaseElement.namedItem(QLatin1String("connectoptions")).toElement();
112 
113     if (element.isNull())
114     {
115         qCDebug(DIGIKAM_DBENGINE_LOG) << "Missing element <connectoptions>.";
116     }
117 
118     configElement.connectOptions = element.text();
119     element                      = databaseElement.namedItem(QLatin1String("dbactions")).toElement();
120 
121     if (element.isNull())
122     {
123         qCDebug(DIGIKAM_DBENGINE_LOG) << "Missing element <dbactions>.";
124     }
125 
126     readDBActions(element, configElement);
127 
128     return configElement;
129 }
130 
readDBActions(QDomElement & sqlStatementElements,DbEngineConfigSettings & configElement)131 void DbEngineConfigSettingsLoader::readDBActions(QDomElement& sqlStatementElements, DbEngineConfigSettings& configElement)
132 {
133     QDomElement dbActionElement = sqlStatementElements.firstChildElement(QLatin1String("dbaction"));
134 
135     for ( ; !dbActionElement.isNull();  dbActionElement=dbActionElement.nextSiblingElement(QLatin1String("dbaction")))
136     {
137         if (!dbActionElement.hasAttribute(QLatin1String("name")))
138         {
139             qCDebug(DIGIKAM_DBENGINE_LOG) << "Missing statement attribute <name>.";
140         }
141 
142         DbEngineAction action;
143         action.name = dbActionElement.attribute(QLatin1String("name"));
144 
145         //qCDebug(DIGIKAM_DBENGINE_LOG) << "Getting attribute " << dbActionElement.attribute("name");
146 
147         if (dbActionElement.hasAttribute(QLatin1String("mode")))
148         {
149             action.mode = dbActionElement.attribute(QLatin1String("mode"));
150         }
151 
152         QDomElement databaseElement = dbActionElement.firstChildElement(QLatin1String("statement"));
153 
154         for ( ; !databaseElement.isNull();  databaseElement = databaseElement.nextSiblingElement(QLatin1String("statement")))
155         {
156             if (!databaseElement.hasAttribute(QLatin1String("mode")))
157             {
158                 qCDebug(DIGIKAM_DBENGINE_LOG) << "Missing statement attribute <mode>.";
159             }
160 
161             DbEngineActionElement actionElement;
162             actionElement.mode      = databaseElement.attribute(QLatin1String("mode"));
163             actionElement.statement = databaseElement.text();
164 
165             action.dbActionElements.append(actionElement);
166         }
167 
168         configElement.sqlStatements.insert(action.name, action);
169     }
170 }
171 
readConfig(const QString & filepath,int xmlVersion)172 bool DbEngineConfigSettingsLoader::readConfig(const QString& filepath, int xmlVersion)
173 {
174     qCDebug(DIGIKAM_DBENGINE_LOG) << "Loading SQL code from config file" << filepath;
175     QFile file(filepath);
176 
177     if (!file.exists())
178     {
179         errorMessage = i18n("Could not open the configuration file <b>%1</b>. "
180                             "This file is installed with the digikam application "
181                             "and is absolutely required to run digikam. "
182                             "Please check your installation.", filepath);
183         return false;
184     }
185 
186     if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
187     {
188         errorMessage = i18n("Could not open configuration file <b>%1</b>", filepath);
189         return false;
190     }
191 
192     QDomDocument doc(QLatin1String("DBConfig"));
193 
194     if (!doc.setContent(&file))
195     {
196         errorMessage = i18n("The XML in the configuration file <b>%1</b> is invalid and cannot be read.", filepath);
197         file.close();
198         return false;
199     }
200 
201     file.close();
202 
203     QDomElement element = doc.namedItem(QLatin1String("databaseconfig")).toElement();
204 
205     if (element.isNull())
206     {
207         errorMessage = i18n("The XML in the configuration file <b>%1</b> "
208                             "is missing the required element <icode>%2</icode>",
209                             filepath, element.tagName());
210         return false;
211     }
212 
213     QDomElement defaultDB =  element.namedItem(QLatin1String("defaultDB")).toElement();
214 
215     if (defaultDB.isNull())
216     {
217         errorMessage = i18n("The XML in the configuration file <b>%1</b> "
218                             "is missing the required element <b>%2</b>",
219                             filepath, element.tagName());
220         return false;
221     }
222 
223     QDomElement versionElement = element.namedItem(QLatin1String("version")).toElement();
224     int version                = 0;
225 
226     qCDebug(DIGIKAM_DBENGINE_LOG) << "Checking XML version ID => expected: " << xmlVersion
227                                   << " found: " << versionElement.text().toInt();
228 
229     if (!versionElement.isNull())
230     {
231         version = versionElement.text().toInt();
232     }
233 
234     if (version < xmlVersion)
235     {
236         errorMessage = i18n("An old version of the configuration file <b>%1</b> "
237                             "is found. Please ensure that the version released "
238                             "with the running version of digiKam is installed. ",
239                             filepath);
240         return false;
241     }
242 
243     //qCDebug(DIGIKAM_DBENGINE_LOG) << "Default DB Node contains: " << defaultDB.text();
244 
245     QDomElement databaseElement = element.firstChildElement(QLatin1String("database"));
246 
247     for ( ; !databaseElement.isNull(); databaseElement=databaseElement.nextSiblingElement(QLatin1String("database")))
248     {
249         DbEngineConfigSettings l_DBCfgElement = readDatabase(databaseElement);
250         databaseConfigs.insert(l_DBCfgElement.databaseID, l_DBCfgElement);
251     }
252 
253 /*
254     qCDebug(DIGIKAM_DBENGINE_LOG) << "Found entries: " << databaseConfigs.size();
255 
256     foreach (const DbEngineConfigSettings& configElement, databaseConfigs )
257     {
258         qCDebug(DIGIKAM_DBENGINE_LOG) << "DatabaseID: "          << configElement.databaseID;
259         qCDebug(DIGIKAM_DBENGINE_LOG) << "HostName: "            << configElement.hostName;
260         qCDebug(DIGIKAM_DBENGINE_LOG) << "DatabaseName: "        << configElement.databaseName;
261         qCDebug(DIGIKAM_DBENGINE_LOG) << "UserName: "            << configElement.userName;
262         qCDebug(DIGIKAM_DBENGINE_LOG) << "Password: "            << configElement.password;
263         qCDebug(DIGIKAM_DBENGINE_LOG) << "Port: "                << configElement.port;
264         qCDebug(DIGIKAM_DBENGINE_LOG) << "ConnectOptions: "      << configElement.connectOptions;
265         qCDebug(DIGIKAM_DBENGINE_LOG) << "Database Server CMD: " << configElement.dbServerCmd;
266         qCDebug(DIGIKAM_DBENGINE_LOG) << "Database Init CMD: "   << configElement.dbInitCmd;
267         qCDebug(DIGIKAM_DBENGINE_LOG) << "Statements:";
268 
269         foreach (const QString& actionKey, configElement.sqlStatements.keys())
270         {
271             QList<databaseActionElement> l_DBActionElement = configElement.sqlStatements[actionKey].dBActionElements;
272             qCDebug(DIGIKAM_DBENGINE_LOG) << "DBAction [" << actionKey << "] has [" << l_DBActionElement.size() << "] actions";
273 
274             foreach (const databaseActionElement statement, l_DBActionElement)
275             {
276                 qCDebug(DIGIKAM_DBENGINE_LOG) << "\tMode ["<< statement.mode <<"] Value ["<< statement.statement <<"]";
277             }
278         }
279 
280     }
281 */
282     return true;
283 }
284 
285 } // namespace Digikam
286