1 /* ============================================================
2  *
3  * This file is a part of digiKam project
4  * https://www.digikam.org
5  *
6  * Date        : 2007-03-18
7  * Description : Database Engine storage container for connection parameters.
8  *
9  * Copyright (C) 2007-2008 by Marcel Wiesweg  <marcel dot wiesweg at gmx dot de>
10  * Copyright (C) 2010      by Holger Foerster <hamsi2k at freenet dot de>
11  * Copyright (C) 2010-2021 by Gilles Caulier  <caulier dot gilles at gmail dot com>
12  * Copyright (C) 2018      by Mario Frank     <mario dot frank at uni minus potsdam dot de>
13  *
14  * This program is free software; you can redistribute it
15  * and/or modify it under the terms of the GNU General
16  * Public License as published by the Free Software Foundation;
17  * either version 2, or (at your option)
18  * any later version.
19  *
20  * This program is distributed in the hope that it will be useful,
21  * but WITHOUT ANY WARRANTY; without even the implied warranty of
22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23  * GNU General Public License for more details.
24  *
25  * ============================================================ */
26 
27 #include "dbengineparameters.h"
28 
29 // Qt includes
30 
31 #include <QDir>
32 #include <QUrlQuery>
33 #include <QFile>
34 #include <QCryptographicHash>
35 #include <QStandardPaths>
36 
37 // KDE includes
38 
39 #include <kconfiggroup.h>
40 #include <ksharedconfig.h>
41 
42 // Local includes
43 
44 #include "digikam_config.h"
45 #include "digikam_debug.h"
46 #include "o0simplecrypt.h"      // For password encrypt
47 
48 namespace
49 {
50 
51 static const char* configGroupDatabase                       = "Database Settings";
52 static const char* configInternalDatabaseServer              = "Internal Database Server";
53 static const char* configInternalDatabaseServerPath          = "Internal Database Server Path";
54 static const char* configInternalDatabaseServerMysqlAdminCmd = "Internal Database Server Mysql Admin Command";
55 static const char* configInternalDatabaseServerMysqlServCmd  = "Internal Database Server Mysql Server Command";
56 static const char* configInternalDatabaseServerMysqlInitCmd  = "Internal Database Server Mysql Init Command";
57 static const char* configDatabaseType                        = "Database Type";
58 static const char* configDatabaseName                        = "Database Name";              ///< For Sqlite the DB file path, for Mysql the DB name
59 static const char* configDatabaseNameThumbnails              = "Database Name Thumbnails";   ///< For Sqlite the DB file path, for Mysql the DB name
60 static const char* configDatabaseNameFace                    = "Database Name Face";         ///< For Sqlite the DB file path, for Mysql the DB name
61 static const char* configDatabaseNameSimilarity              = "Database Name Similarity";   ///< For Sqlite the DB file path, for Mysql the DB name
62 static const char* configDatabaseHostName                    = "Database Hostname";
63 static const char* configDatabasePort                        = "Database Port";
64 static const char* configDatabaseUsername                    = "Database Username";
65 static const char* configDatabasePassword                    = "Database Password";          ///< For compatbilitity. Use crypted version instead.
66 static const char* configDatabaseEncryptedPassword           = "Database Encrypted Password";
67 static const char* configDatabaseConnectOptions              = "Database Connectoptions";
68 /// Legacy for older versions.
69 static const char* configDatabaseFilePathEntry               = "Database File Path";
70 static const char* configAlbumPathEntry                      = "Album Path";
71 /// Sqlite DB file names
72 static const char* digikam4db                                = "digikam4.db";
73 static const char* thumbnails_digikamdb                      = "thumbnails-digikam.db";
74 static const char* face_digikamdb                            = "recognition.db";
75 static const char* similarity_digikamdb                      = "similarity.db";
76 
77 }
78 
79 namespace Digikam
80 {
81 
internalServerPrivatePath()82 QString DbEngineParameters::internalServerPrivatePath()
83 {
84     return QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) +
85                                             QLatin1String("/digikam/");
86 }
87 
DbEngineParameters()88 DbEngineParameters::DbEngineParameters()
89     : port          (-1),
90       internalServer(false)
91 {
92 }
93 
DbEngineParameters(const QString & _type,const QString & _databaseNameCore,const QString & _connectOptions,const QString & _hostName,int _port,bool _internalServer,const QString & _userName,const QString & _password,const QString & _databaseNameThumbnails,const QString & _databaseNameFace,const QString & _databaseNameSimilarity,const QString & _internalServerDBPath,const QString & _internalServerMysqlAdminCmd,const QString & _internalServerMysqlServCmd,const QString & _internalServerMysqlInitCmd)94 DbEngineParameters::DbEngineParameters(const QString& _type,
95                                        const QString& _databaseNameCore,
96                                        const QString& _connectOptions,
97                                        const QString& _hostName,
98                                        int            _port,
99                                        bool           _internalServer,
100                                        const QString& _userName,
101                                        const QString& _password,
102                                        const QString& _databaseNameThumbnails,
103                                        const QString& _databaseNameFace,
104                                        const QString& _databaseNameSimilarity,
105                                        const QString& _internalServerDBPath,
106                                        const QString& _internalServerMysqlAdminCmd,
107                                        const QString& _internalServerMysqlServCmd,
108                                        const QString& _internalServerMysqlInitCmd)
109     : databaseType                  (_type),
110       databaseNameCore              (_databaseNameCore),
111       connectOptions                (_connectOptions),
112       hostName                      (_hostName),
113       port                          (_port),
114       internalServer                (_internalServer),
115       userName                      (_userName),
116       password                      (_password),
117       databaseNameThumbnails        (_databaseNameThumbnails),
118       databaseNameFace              (_databaseNameFace),
119       databaseNameSimilarity        (_databaseNameSimilarity),
120       internalServerDBPath          (_internalServerDBPath),
121       internalServerMysqlAdminCmd   (_internalServerMysqlAdminCmd),
122       internalServerMysqlServCmd    (_internalServerMysqlServCmd),
123       internalServerMysqlInitCmd    (_internalServerMysqlInitCmd)
124 {
125 }
126 
DbEngineParameters(const QUrl & url)127 DbEngineParameters::DbEngineParameters(const QUrl& url)
128     : databaseType          (QUrlQuery(url).queryItemValue(QLatin1String("databaseType"))),
129       databaseNameCore      (QUrlQuery(url).queryItemValue(QLatin1String("databaseNameCore"))),
130       connectOptions        (QUrlQuery(url).queryItemValue(QLatin1String("connectOptions"))),
131       hostName              (QUrlQuery(url).queryItemValue(QLatin1String("hostName"))),
132       port                  (-1),
133       internalServer        (false),
134       databaseNameThumbnails(QUrlQuery(url).queryItemValue(QLatin1String("databaseNameThumbnails"))),
135       databaseNameFace      (QUrlQuery(url).queryItemValue(QLatin1String("databaseNameFace"))),
136       databaseNameSimilarity(QUrlQuery(url).queryItemValue(QLatin1String("databaseNameSimilarity")))
137 {
138     QString queryPort   = QUrlQuery(url).queryItemValue(QLatin1String("port"));
139 
140     if (!queryPort.isNull())
141     {
142         port = queryPort.toInt();
143     }
144 
145 #if defined(HAVE_MYSQLSUPPORT) && defined(HAVE_INTERNALMYSQL)
146 
147     QString queryServer = QUrlQuery(url).queryItemValue(QLatin1String("internalServer"));
148 
149     if (!queryServer.isNull())
150     {
151         internalServer = (queryServer == QLatin1String("true"));
152     }
153 
154     queryServer         = QUrlQuery(url).queryItemValue(QLatin1String("internalServerPath"));
155 
156     if (!queryServer.isNull())
157     {
158         internalServerDBPath = QUrlQuery(url).queryItemValue(QLatin1String("internalServerPath"));
159     }
160     else
161     {
162         internalServerDBPath = internalServerPrivatePath();
163     }
164 
165     internalServerMysqlAdminCmd = QUrlQuery(url).queryItemValue(QLatin1String("internalServerMysqlAdminCmd"));
166     internalServerMysqlServCmd  = QUrlQuery(url).queryItemValue(QLatin1String("internalServerMysqlServCmd"));
167     internalServerMysqlInitCmd  = QUrlQuery(url).queryItemValue(QLatin1String("internalServerMysqlInitCmd"));
168 
169 #else
170 
171     internalServer = false;
172 
173 #endif
174 
175     userName       = QUrlQuery(url).queryItemValue(QLatin1String("userName"));
176     password       = QUrlQuery(url).queryItemValue(QLatin1String("password"));
177 }
178 
insertInUrl(QUrl & url) const179 void DbEngineParameters::insertInUrl(QUrl& url) const
180 {
181     removeFromUrl(url);
182 
183     QUrlQuery q(url);
184     q.addQueryItem(QLatin1String("databaseType"),           databaseType);
185     q.addQueryItem(QLatin1String("databaseNameCore"),       databaseNameCore);
186     q.addQueryItem(QLatin1String("databaseNameThumbnails"), databaseNameThumbnails);
187     q.addQueryItem(QLatin1String("databaseNameFace"),       databaseNameFace);
188     q.addQueryItem(QLatin1String("databaseNameSimilarity"), databaseNameSimilarity);
189 
190     if (!connectOptions.isNull())
191     {
192         q.addQueryItem(QLatin1String("connectOptions"), connectOptions);
193     }
194 
195     if (!hostName.isNull())
196     {
197         q.addQueryItem(QLatin1String("hostName"), hostName);
198     }
199 
200     if (port != -1)
201     {
202         q.addQueryItem(QLatin1String("port"), QString::number(port));
203     }
204 
205     if (internalServer)
206     {
207         q.addQueryItem(QLatin1String("internalServer"),              QLatin1String("true"));
208         q.addQueryItem(QLatin1String("internalServerPath"),          internalServerDBPath);
209         q.addQueryItem(QLatin1String("internalServerMysqlAdminCmd"), internalServerMysqlAdminCmd);
210         q.addQueryItem(QLatin1String("internalServerMysqlServCmd"),  internalServerMysqlServCmd);
211         q.addQueryItem(QLatin1String("internalServerMysqlInitCmd"),  internalServerMysqlInitCmd);
212     }
213 
214     if (!userName.isNull())
215     {
216         q.addQueryItem(QLatin1String("userName"), userName);
217     }
218 
219     if (!password.isNull())
220     {
221         q.addQueryItem(QLatin1String("password"), password);
222     }
223 
224     url.setQuery(q);
225 }
226 
removeFromUrl(QUrl & url)227 void DbEngineParameters::removeFromUrl(QUrl& url)
228 {
229     QUrlQuery q(url);
230 
231     q.removeQueryItem(QLatin1String("databaseType"));
232     q.removeQueryItem(QLatin1String("databaseNameCore"));
233     q.removeQueryItem(QLatin1String("databaseNameThumbnails"));
234     q.removeQueryItem(QLatin1String("databaseNameFace"));
235     q.removeQueryItem(QLatin1String("databaseNameSimilarity"));
236     q.removeQueryItem(QLatin1String("connectOptions"));
237     q.removeQueryItem(QLatin1String("hostName"));
238     q.removeQueryItem(QLatin1String("port"));
239     q.removeQueryItem(QLatin1String("internalServer"));
240     q.removeQueryItem(QLatin1String("internalServerPath"));
241     q.removeQueryItem(QLatin1String("internalServerMysqlAdminCmd"));
242     q.removeQueryItem(QLatin1String("internalServerMysqlServCmd"));
243     q.removeQueryItem(QLatin1String("internalServerMysqlInitCmd"));
244     q.removeQueryItem(QLatin1String("userName"));
245     q.removeQueryItem(QLatin1String("password"));
246 
247     url.setQuery(q);
248 }
249 
operator ==(const DbEngineParameters & other) const250 bool DbEngineParameters::operator==(const DbEngineParameters& other) const
251 {
252     return (
253             (databaseType                == other.databaseType)                &&
254             (databaseNameCore            == other.databaseNameCore)            &&
255             (databaseNameThumbnails      == other.databaseNameThumbnails)      &&
256             (databaseNameFace            == other.databaseNameFace)            &&
257             (databaseNameSimilarity      == other.databaseNameSimilarity)      &&
258             (connectOptions              == other.connectOptions)              &&
259             (hostName                    == other.hostName)                    &&
260             (port                        == other.port)                        &&
261             (internalServer              == other.internalServer)              &&
262             (internalServerDBPath        == other.internalServerDBPath)        &&
263             (internalServerMysqlAdminCmd == other.internalServerMysqlAdminCmd) &&
264             (internalServerMysqlServCmd  == other.internalServerMysqlServCmd)  &&
265             (internalServerMysqlInitCmd  == other.internalServerMysqlInitCmd)  &&
266             (userName                    == other.userName)                    &&
267             (password                    == other.password)
268            );
269 }
270 
operator !=(const DbEngineParameters & other) const271 bool DbEngineParameters::operator!=(const DbEngineParameters& other) const
272 {
273     return (!operator == (other));
274 }
275 
isValid() const276 bool DbEngineParameters::isValid() const
277 {
278     if (isSQLite())
279     {
280         return !databaseNameCore.isEmpty();
281     }
282 
283     return false;
284 }
285 
isSQLite() const286 bool DbEngineParameters::isSQLite() const
287 {
288     return (databaseType == QLatin1String("QSQLITE"));
289 }
290 
isMySQL() const291 bool DbEngineParameters::isMySQL() const
292 {
293     return (databaseType == QLatin1String("QMYSQL"));
294 }
295 
SQLiteDatabaseType()296 QString DbEngineParameters::SQLiteDatabaseType()
297 {
298     return QLatin1String("QSQLITE");
299 }
300 
MySQLDatabaseType()301 QString DbEngineParameters::MySQLDatabaseType()
302 {
303     return QLatin1String("QMYSQL");
304 }
305 
SQLiteDatabaseFile() const306 QString DbEngineParameters::SQLiteDatabaseFile() const
307 {
308     if (isSQLite())
309     {
310         return databaseNameCore;
311     }
312 
313     return QString();
314 }
315 
hash() const316 QByteArray DbEngineParameters::hash() const
317 {
318     QCryptographicHash md5(QCryptographicHash::Md5);
319 
320     md5.addData(databaseType.toUtf8());
321     md5.addData(databaseNameCore.toUtf8());
322     md5.addData(databaseNameThumbnails.toUtf8());
323     md5.addData(databaseNameFace.toUtf8());
324     md5.addData(databaseNameSimilarity.toUtf8());
325     md5.addData(connectOptions.toUtf8());
326     md5.addData(hostName.toUtf8());
327     md5.addData((const char*)&port, sizeof(int));
328     md5.addData(userName.toUtf8());
329     md5.addData(password.toUtf8());
330     md5.addData((const char*)&internalServer, sizeof(bool));
331     md5.addData(internalServerDBPath.toUtf8());
332 
333     return md5.result().toHex();
334 }
335 
parametersFromConfig(const QString & configGroup)336 DbEngineParameters DbEngineParameters::parametersFromConfig(const QString& configGroup)
337 {
338     DbEngineParameters parameters;
339     parameters.readFromConfig(configGroup);
340 
341     return parameters;
342 }
343 
readFromConfig(const QString & configGroup)344 void DbEngineParameters::readFromConfig(const QString& configGroup)
345 {
346     KSharedConfig::Ptr config = KSharedConfig::openConfig();
347     KConfigGroup group;
348 
349     if (configGroup.isNull())
350     {
351         group = config->group(configGroupDatabase);
352     }
353     else
354     {
355         group = config->group(configGroup);
356     }
357 
358     databaseType = group.readEntry(configDatabaseType, QString());
359 
360     if (isSQLite())     // see bug #267131
361     {
362         databaseNameCore        = group.readPathEntry(configDatabaseName,                    QString());
363         databaseNameThumbnails  = group.readPathEntry(configDatabaseNameThumbnails,          QString());
364         databaseNameFace        = group.readPathEntry(configDatabaseNameFace,                QString());
365         databaseNameSimilarity  = group.readPathEntry(configDatabaseNameSimilarity,          QString());
366     }
367     else
368     {
369         databaseNameCore        = group.readEntry(configDatabaseName,                        QString());
370         databaseNameThumbnails  = group.readEntry(configDatabaseNameThumbnails,              QString());
371         databaseNameFace        = group.readEntry(configDatabaseNameFace,                    QString());
372         databaseNameSimilarity  = group.readEntry(configDatabaseNameSimilarity,              QString());
373     }
374 
375     hostName                    = group.readEntry(configDatabaseHostName,                    QString());
376     port                        = group.readEntry(configDatabasePort,                        -1);
377     userName                    = group.readEntry(configDatabaseUsername,                    QString());
378 
379     // Non encrypted password for compatibility.
380 
381     password                    = group.readEntry(configDatabasePassword,                    QString());
382 
383     if (password.isEmpty())
384     {
385         password                = group.readEntry(configDatabaseEncryptedPassword,           QString());
386 
387         if (!password.isEmpty())
388         {
389             O0SimpleCrypt crypto(QCryptographicHash::hash(configDatabaseEncryptedPassword,   QCryptographicHash::Sha1).toULongLong());
390             password = crypto.decryptToString(password);
391         }
392     }
393 
394     connectOptions              = group.readEntry(configDatabaseConnectOptions,              QString());
395 
396 #if defined(HAVE_MYSQLSUPPORT) && defined(HAVE_INTERNALMYSQL)
397 
398     internalServer              = group.readEntry(configInternalDatabaseServer,              false);
399     internalServerDBPath        = group.readEntry(configInternalDatabaseServerPath,          internalServerPrivatePath());
400     internalServerMysqlAdminCmd = group.readEntry(configInternalDatabaseServerMysqlAdminCmd, defaultMysqlAdminCmd());
401     internalServerMysqlServCmd  = group.readEntry(configInternalDatabaseServerMysqlServCmd,  defaultMysqlServerCmd());
402     internalServerMysqlInitCmd  = group.readEntry(configInternalDatabaseServerMysqlInitCmd,  defaultMysqlInitCmd());
403 
404 #else
405 
406     internalServer             = false;
407 
408 #endif
409 
410     if (isSQLite() && !databaseNameCore.isNull())
411     {
412         QString orgName = databaseNameCore;
413         setCoreDatabasePath(orgName);
414         setThumbsDatabasePath(orgName);
415         setFaceDatabasePath(orgName);
416         setSimilarityDatabasePath(orgName);
417     }
418 }
419 
setInternalServerPath(const QString & path)420 void DbEngineParameters::setInternalServerPath(const QString& path)
421 {
422     internalServerDBPath = path;
423 }
424 
internalServerPath() const425 QString DbEngineParameters::internalServerPath() const
426 {
427     QFileInfo fileInfo(internalServerDBPath);
428 
429     return QDir::cleanPath(fileInfo.filePath());
430 }
431 
setCoreDatabasePath(const QString & folderOrFileOrName)432 void DbEngineParameters::setCoreDatabasePath(const QString& folderOrFileOrName)
433 {
434     if (isSQLite())
435     {
436         databaseNameCore = coreDatabaseFileSQLite(folderOrFileOrName);
437     }
438     else
439     {
440         databaseNameCore = folderOrFileOrName;
441     }
442 }
443 
setThumbsDatabasePath(const QString & folderOrFileOrName)444 void DbEngineParameters::setThumbsDatabasePath(const QString& folderOrFileOrName)
445 {
446     if (isSQLite())
447     {
448         databaseNameThumbnails = thumbnailDatabaseFileSQLite(folderOrFileOrName);
449     }
450     else
451     {
452         databaseNameThumbnails = folderOrFileOrName;
453     }
454 }
455 
setFaceDatabasePath(const QString & folderOrFileOrName)456 void DbEngineParameters::setFaceDatabasePath(const QString& folderOrFileOrName)
457 {
458     if (isSQLite())
459     {
460         databaseNameFace = faceDatabaseFileSQLite(folderOrFileOrName);
461     }
462     else
463     {
464         databaseNameFace = folderOrFileOrName;
465     }
466 }
467 
setSimilarityDatabasePath(const QString & folderOrFileOrName)468 void DbEngineParameters::setSimilarityDatabasePath(const QString& folderOrFileOrName)
469 {
470     if (isSQLite())
471     {
472         databaseNameSimilarity = similarityDatabaseFileSQLite(folderOrFileOrName);
473     }
474     else
475     {
476         databaseNameSimilarity = folderOrFileOrName;
477     }
478 }
479 
coreDatabaseFileSQLite(const QString & folderOrFile)480 QString DbEngineParameters::coreDatabaseFileSQLite(const QString& folderOrFile)
481 {
482     QFileInfo fileInfo(folderOrFile);
483 
484     if (fileInfo.isDir())
485     {
486         return (QDir::cleanPath(fileInfo.filePath() + QLatin1Char('/') + QLatin1String(digikam4db)));
487     }
488 
489     return QDir::cleanPath(folderOrFile);
490 }
491 
thumbnailDatabaseFileSQLite(const QString & folderOrFile)492 QString DbEngineParameters::thumbnailDatabaseFileSQLite(const QString& folderOrFile)
493 {
494     QFileInfo fileInfo(folderOrFile);
495 
496     if (fileInfo.isDir())
497     {
498         return (QDir::cleanPath(fileInfo.filePath() + QLatin1Char('/') + QLatin1String(thumbnails_digikamdb)));
499     }
500 
501     return QDir::cleanPath(folderOrFile);
502 }
503 
faceDatabaseFileSQLite(const QString & folderOrFile)504 QString DbEngineParameters::faceDatabaseFileSQLite(const QString& folderOrFile)
505 {
506     QFileInfo fileInfo(folderOrFile);
507 
508     if (fileInfo.isDir())
509     {
510         return (QDir::cleanPath(fileInfo.filePath() + QLatin1Char('/') + QLatin1String(face_digikamdb)));
511     }
512 
513     return QDir::cleanPath(folderOrFile);
514 }
515 
similarityDatabaseFileSQLite(const QString & folderOrFile)516 QString DbEngineParameters::similarityDatabaseFileSQLite(const QString& folderOrFile)
517 {
518     QFileInfo fileInfo(folderOrFile);
519 
520     if (fileInfo.isDir())
521     {
522         return (QDir::cleanPath(fileInfo.filePath() + QLatin1Char('/') + QLatin1String(similarity_digikamdb)));
523     }
524 
525     return QDir::cleanPath(folderOrFile);
526 }
527 
legacyAndDefaultChecks(const QString & suggestedPath)528 void DbEngineParameters::legacyAndDefaultChecks(const QString& suggestedPath)
529 {
530     KSharedConfig::Ptr config = KSharedConfig::openConfig();
531 
532     // Additional semantic checks for the database section.
533     // If the internal server should be started, then the connection options must be reset
534 
535     if ((databaseType == QLatin1String("QMYSQL")) && internalServer)
536     {
537         const QString miscDir      = internalServerPrivatePath() + QLatin1String("db_misc");
538         databaseNameCore           = QLatin1String("digikam");
539         databaseNameThumbnails     = QLatin1String("digikam");
540         databaseNameFace           = QLatin1String("digikam");
541         databaseNameSimilarity     = QLatin1String("digikam");
542         internalServer             = true;
543         userName                   = QLatin1String("root");
544         password.clear();
545 
546 #ifdef Q_OS_WIN
547 
548         hostName                   = QLatin1String("localhost");
549         port                       = 3307;
550         connectOptions.clear();
551 
552 #else
553 
554         hostName.clear();
555         port                       = -1;
556         connectOptions             = QString::fromLatin1("UNIX_SOCKET=%1/mysql.socket").arg(miscDir);
557 
558 #endif
559 
560     }
561 
562     if (databaseType.isEmpty())
563     {
564         // Empty 1.3 config: migration from older versions
565 
566         KConfigGroup group = config->group("Album Settings");
567 
568         QString databaseFilePath;
569 
570         if      (group.hasKey(configDatabaseFilePathEntry))
571         {
572             // 1.0 - 1.2 style database file path?
573 
574             databaseFilePath = group.readEntry(configDatabaseFilePathEntry, QString());
575         }
576         else if (group.hasKey(configAlbumPathEntry))
577         {
578             // <= 0.9 style album path entry?
579 
580             databaseFilePath = group.readEntry(configAlbumPathEntry, QString());
581         }
582         else if (!suggestedPath.isNull())
583         {
584             databaseFilePath = suggestedPath;
585         }
586 
587         if (!databaseFilePath.isEmpty())
588         {
589             *this = parametersForSQLite(coreDatabaseFileSQLite(databaseFilePath));
590         }
591 
592         // Be aware that schema updating from version <= 0.9 requires reading the "Album Path", so do not remove it here
593     }
594 }
595 
removeLegacyConfig()596 void DbEngineParameters::removeLegacyConfig()
597 {
598     KSharedConfig::Ptr config = KSharedConfig::openConfig();
599     KConfigGroup group        = config->group("Album Settings");
600 
601     if (group.hasKey(configDatabaseFilePathEntry))
602     {
603         group.deleteEntry(configDatabaseFilePathEntry);
604     }
605 
606     if (group.hasKey(configAlbumPathEntry))
607     {
608         group.deleteEntry(configAlbumPathEntry);
609     }
610 }
611 
writeToConfig(const QString & configGroup) const612 void DbEngineParameters::writeToConfig(const QString& configGroup) const
613 {
614     KSharedConfig::Ptr config = KSharedConfig::openConfig();
615     KConfigGroup group;
616 
617     if (configGroup.isNull())
618     {
619         group = config->group(configGroupDatabase);
620     }
621     else
622     {
623         group = config->group(configGroup);
624     }
625 
626     QString dbName           = getCoreDatabaseNameOrDir();
627     QString dbNameThumbs     = getThumbsDatabaseNameOrDir();
628     QString dbNameFace       = getFaceDatabaseNameOrDir();
629     QString dbNameSimilarity = getSimilarityDatabaseNameOrDir();
630 
631     group.writeEntry(configDatabaseType,                        databaseType);
632     group.writeEntry(configDatabaseName,                        dbName);
633     group.writeEntry(configDatabaseNameThumbnails,              dbNameThumbs);
634     group.writeEntry(configDatabaseNameFace,                    dbNameFace);
635     group.writeEntry(configDatabaseNameSimilarity,              dbNameSimilarity);
636     group.writeEntry(configDatabaseHostName,                    hostName);
637     group.writeEntry(configDatabasePort,                        port);
638     group.writeEntry(configDatabaseUsername,                    userName);
639 
640     O0SimpleCrypt crypto(QCryptographicHash::hash(configDatabaseEncryptedPassword, QCryptographicHash::Sha1).toULongLong());
641     group.writeEntry(configDatabaseEncryptedPassword,           crypto.encryptToString(password));
642 
643     group.writeEntry(configDatabaseConnectOptions,              connectOptions);
644     group.writeEntry(configInternalDatabaseServer,              internalServer);
645     group.writeEntry(configInternalDatabaseServerPath,          internalServerDBPath);
646     group.writeEntry(configInternalDatabaseServerMysqlAdminCmd, internalServerMysqlAdminCmd);
647     group.writeEntry(configInternalDatabaseServerMysqlServCmd,  internalServerMysqlServCmd);
648     group.writeEntry(configInternalDatabaseServerMysqlInitCmd,  internalServerMysqlInitCmd);
649 
650     group.deleteEntry(configDatabasePassword);  // Remove non encrypted password
651 }
652 
getCoreDatabaseNameOrDir() const653 QString DbEngineParameters::getCoreDatabaseNameOrDir() const
654 {
655     if (isSQLite())
656     {
657         return coreDatabaseDirectorySQLite(databaseNameCore);
658     }
659 
660     return databaseNameCore;
661 }
662 
getThumbsDatabaseNameOrDir() const663 QString DbEngineParameters::getThumbsDatabaseNameOrDir() const
664 {
665     if (isSQLite())
666     {
667         return thumbnailDatabaseDirectorySQLite(databaseNameThumbnails);
668     }
669 
670     return databaseNameThumbnails;
671 }
672 
getFaceDatabaseNameOrDir() const673 QString DbEngineParameters::getFaceDatabaseNameOrDir() const
674 {
675     if (isSQLite())
676     {
677         return faceDatabaseDirectorySQLite(databaseNameFace);
678     }
679 
680     return databaseNameFace;
681 }
682 
getSimilarityDatabaseNameOrDir() const683 QString DbEngineParameters::getSimilarityDatabaseNameOrDir() const
684 {
685     if (isSQLite())
686     {
687         return similarityDatabaseDirectorySQLite(databaseNameSimilarity);
688     }
689 
690     return databaseNameSimilarity;
691 }
692 
coreDatabaseDirectorySQLite(const QString & path)693 QString DbEngineParameters::coreDatabaseDirectorySQLite(const QString& path)
694 {
695     if (path.endsWith(QLatin1String(digikam4db)))
696     {
697         QString chopped(path);
698         chopped.chop(QString(QLatin1String(digikam4db)).length());
699 
700         return chopped;
701     }
702 
703     return path;
704 }
705 
thumbnailDatabaseDirectorySQLite(const QString & path)706 QString DbEngineParameters::thumbnailDatabaseDirectorySQLite(const QString& path)
707 {
708     if (path.endsWith(QLatin1String(thumbnails_digikamdb)))
709     {
710         QString chopped(path);
711         chopped.chop(QString(QLatin1String(thumbnails_digikamdb)).length());
712 
713         return chopped;
714     }
715 
716     return path;
717 }
718 
faceDatabaseDirectorySQLite(const QString & path)719 QString DbEngineParameters::faceDatabaseDirectorySQLite(const QString& path)
720 {
721     if (path.endsWith(QLatin1String(face_digikamdb)))
722     {
723         QString chopped(path);
724         chopped.chop(QString(QLatin1String(face_digikamdb)).length());
725 
726         return chopped;
727     }
728 
729     return path;
730 }
731 
similarityDatabaseDirectorySQLite(const QString & path)732 QString DbEngineParameters::similarityDatabaseDirectorySQLite(const QString& path)
733 {
734     if (path.endsWith(QLatin1String(similarity_digikamdb)))
735     {
736         QString chopped(path);
737         chopped.chop(QString(QLatin1String(similarity_digikamdb)).length());
738 
739         return chopped;
740     }
741 
742     return path;
743 }
744 
745 
defaultParameters(const QString & databaseType)746 DbEngineParameters DbEngineParameters::defaultParameters(const QString& databaseType)
747 {
748     DbEngineParameters parameters;
749 
750     // only the database name is needed
751 
752     DbEngineConfigSettings config          = DbEngineConfig::element(databaseType);
753     parameters.databaseType                = databaseType;
754     parameters.databaseNameCore            = config.databaseName;
755     parameters.databaseNameThumbnails      = config.databaseName;
756     parameters.databaseNameFace            = config.databaseName;
757     parameters.databaseNameSimilarity      = config.databaseName;
758     parameters.userName                    = config.userName;
759     parameters.password                    = config.password;
760     parameters.internalServer              = (databaseType == QLatin1String("QMYSQL"));
761     parameters.internalServerDBPath        = (databaseType == QLatin1String("QMYSQL")) ? internalServerPrivatePath() : QString();
762     parameters.internalServerMysqlAdminCmd = (databaseType == QLatin1String("QMYSQL")) ? defaultMysqlAdminCmd()      : QString();
763     parameters.internalServerMysqlServCmd  = (databaseType == QLatin1String("QMYSQL")) ? defaultMysqlServerCmd()     : QString();
764     parameters.internalServerMysqlInitCmd  = (databaseType == QLatin1String("QMYSQL")) ? defaultMysqlInitCmd()       : QString();
765 
766     QString hostName                       = config.hostName;
767     QString port                           = config.port;
768     QString connectOptions                 = config.connectOptions;
769 
770 #ifdef Q_OS_WIN
771 
772     hostName.replace(QLatin1String("$$DBHOSTNAME$$"),      (databaseType == QLatin1String("QMYSQL"))
773                                                            ? QLatin1String("localhost")
774                                                            : QString());
775 
776     port.replace(QLatin1String("$$DBPORT$$"),              (databaseType == QLatin1String("QMYSQL"))
777                                                            ? QLatin1String("3307")
778                                                            : QLatin1String("-1"));
779 
780     connectOptions.replace(QLatin1String("$$DBOPTIONS$$"), QString());
781 
782 #else
783 
784     hostName.replace(QLatin1String("$$DBHOSTNAME$$"),      QString());
785 
786     port.replace(QLatin1String("$$DBPORT$$"),              QLatin1String("-1"));
787 
788     const QString miscDir                 = internalServerPrivatePath() + QLatin1String("db_misc");
789     connectOptions.replace(QLatin1String("$$DBOPTIONS$$"), (databaseType == QLatin1String("QMYSQL"))
790                                                            ? QString::fromLatin1("UNIX_SOCKET=%1/mysql.socket").arg(miscDir)
791                                                            : QString());
792 #endif
793 
794     parameters.hostName                   = hostName;
795     parameters.port                       = port.toInt();
796     parameters.connectOptions             = connectOptions;
797 
798     qCDebug(DIGIKAM_DBENGINE_LOG) << "ConnectOptions " << parameters.connectOptions;
799 
800     return parameters;
801 }
802 
thumbnailParameters() const803 DbEngineParameters DbEngineParameters::thumbnailParameters() const
804 {
805     DbEngineParameters params = *this;
806     params.databaseNameCore   = databaseNameThumbnails;
807 
808     return params;
809 }
810 
faceParameters() const811 DbEngineParameters DbEngineParameters::faceParameters() const
812 {
813     DbEngineParameters params = *this;
814     params.databaseNameCore   = databaseNameFace;
815 
816     return params;
817 }
818 
similarityParameters() const819 DbEngineParameters DbEngineParameters::similarityParameters() const
820 {
821     DbEngineParameters params = *this;
822     params.databaseNameCore   = databaseNameSimilarity;
823 
824     return params;
825 }
826 
parametersForSQLite(const QString & databaseFile)827 DbEngineParameters DbEngineParameters::parametersForSQLite(const QString& databaseFile)
828 {
829     // only the database name is needed
830 
831     DbEngineParameters params(QLatin1String("QSQLITE"), databaseFile);
832     params.setCoreDatabasePath(databaseFile);
833     params.setThumbsDatabasePath(params.getCoreDatabaseNameOrDir());
834     params.setFaceDatabasePath(params.getCoreDatabaseNameOrDir());
835     params.setSimilarityDatabasePath(params.getCoreDatabaseNameOrDir());
836 
837     return params;
838 }
839 
parametersForSQLiteDefaultFile(const QString & directory)840 DbEngineParameters DbEngineParameters::parametersForSQLiteDefaultFile(const QString& directory)
841 {
842     return parametersForSQLite(QDir::cleanPath(directory + QLatin1Char('/') + QLatin1String(digikam4db)));
843 }
844 
defaultMysqlServerCmd()845 QString DbEngineParameters::defaultMysqlServerCmd()
846 {
847     return QLatin1String("mysqld");             // For Linux, Windows and OSX
848 }
849 
defaultMysqlAdminCmd()850 QString DbEngineParameters::defaultMysqlAdminCmd()
851 {
852     return QLatin1String("mysqladmin");         // For Linux, Windows and OSX
853 }
854 
defaultMysqlInitCmd()855 QString DbEngineParameters::defaultMysqlInitCmd()
856 {
857     return QLatin1String("mysql_install_db");   // For Linux, Windows and OSX
858 }
859 
860 // --------------------------------
861 
operator <<(QDebug dbg,const DbEngineParameters & p)862 QDebug operator<<(QDebug dbg, const DbEngineParameters& p)
863 {
864     dbg.nospace() << "Database Parameters:"                                                                  << endl;
865     dbg.nospace() << "   Type:                      " << p.databaseType                                      << endl;
866     dbg.nospace() << "   DB Core Name:              " << p.databaseNameCore                                  << endl;
867     dbg.nospace() << "   DB Thumbs Name:            " << p.databaseNameThumbnails                            << endl;
868     dbg.nospace() << "   DB Face Name:              " << p.databaseNameFace                                  << endl;
869     dbg.nospace() << "   DB Similarity Name:        " << p.databaseNameSimilarity                            << endl;
870     dbg.nospace() << "   Connect Options:           " << p.connectOptions                                    << endl;
871     dbg.nospace() << "   Host Name:                 " << p.hostName                                          << endl;
872     dbg.nospace() << "   Host port:                 " << p.port                                              << endl;
873     dbg.nospace() << "   Internal Server:           " << p.internalServer                                    << endl;
874     dbg.nospace() << "   Internal Server Path:      " << p.internalServerDBPath                              << endl;
875     dbg.nospace() << "   Internal Server Admin Cmd: " << p.internalServerMysqlAdminCmd                       << endl;
876     dbg.nospace() << "   Internal Server Serv Cmd:  " << p.internalServerMysqlServCmd                        << endl;
877     dbg.nospace() << "   Internal Server Init Cmd:  " << p.internalServerMysqlInitCmd                        << endl;
878     dbg.nospace() << "   Username:                  " << p.userName                                          << endl;
879     dbg.nospace() << "   Password:                  " << QString().fill(QLatin1Char('X'), p.password.size()) << endl;
880 
881     return dbg.space();
882 }
883 
884 } // namespace Digikam
885