source: SMSSender/src/persistence/storage/DAStorage.cpp @ 71:415b45c71663

3.0
Last change on this file since 71:415b45c71663 was 71:415b45c71663, checked in by Sämy Zehnder <saemy.zehnder@…>, 12 years ago
  • Reorganized all the libraries. libinterfaces and libgateways are removed now and libdatatypes contains now all these files.
File size: 15.4 KB
Line 
1/*
2 * DASQLiteStorage.cpp
3 *
4 *  Created on: May 1, 2009
5 *      Author: saemy
6 */
7
8#include "DAStorage.h"
9
10#include <QBuffer>
11#include <QStringList>
12#include <QDebug>
13#include <QSqlError>
14
15#include <crypto++/default.h>
16
17#include <iaccount.h>
18
19#include <stdexceptions.h>
20#include <persistence/storageexceptions.h>
21
22#include <scontact.h>
23#include <sgroup.h>
24#include <sshortcut.h>
25#include "business/BCSettings.h"
26#include "business/BCContactManager.h"
27
28#include <typeconvert.h>
29
30DAStorage* DAStorage::instance_=0;
31DAStorage* DAStorage::instance(){
32    return instance_ ? instance_ : (instance_ = new DAStorage);
33}
34
35
36
37DAStorage::DAStorage() {
38    dbConnection_ = QSqlDatabase::addDatabase("QSQLITE");
39    dbConnection_.setDatabaseName(BCSettings::instance()->getSettingsPath().absoluteFilePath("data.db"));
40    if (!dbConnection_.open()) {
41        qCritical() << dbConnection_.lastError().text();
42        throw Storage::EReadException(tr("Can't open the database!"));
43    }
44
45    bool somethingFailed = false;
46    QSqlQuery query;
47    somethingFailed |= !query.exec("CREATE TABLE IF NOT EXISTS t_contacts ("
48                                     "contactId INTEGER PRIMARY KEY AUTOINCREMENT, "
49                                     "name      TEXT    NOT NULL UNIQUE, "
50                                     "number    TEXT    NOT NULL UNIQUE "
51                                   "); ");
52    somethingFailed |= !query.exec("CREATE TABLE IF NOT EXISTS t_groups ("
53                                     "groupId INTEGER PRIMARY KEY AUTOINCREMENT, "
54                                     "name      TEXT    NOT NULL UNIQUE "
55                                   "); ");
56    somethingFailed |= !query.exec("CREATE TABLE IF NOT EXISTS t_settings ("
57                                     "namespace TEXT NOT NULL, "
58                                     "key       TEXT NOT NULL, "
59                                     "value     BLOB, "
60                                     "PRIMARY KEY(namespace, key) "
61                                   "); ");
62
63    if (somethingFailed) {
64        throw Storage::EWriteException(tr("Could not write the table definitions to the database."));
65    }
66}
67
68QSqlDatabase DAStorage::connection() const {
69    return dbConnection_;
70}
71QSqlQuery DAStorage::createQuery() const {
72    return QSqlQuery(connection());
73}
74
75
76QVariant DAStorage::readValue(const QString& _namespace, const QString& key, const QVariant& defaultValue){
77    QSqlQuery query = createQuery();
78    query.prepare("SELECT value "
79                    "FROM t_settings "
80                    "WHERE (namespace = :namespace) "
81                      "AND (key = :key); ");
82    query.bindValue(":namespace", _namespace);
83    query.bindValue(":key", key);
84    if (!query.exec() || !query.next()) {
85        qWarning() << query.lastError().text();
86        return defaultValue;
87    }
88    return query.value(0);
89}
90bool DAStorage::readBool(const QString& _namespace, const QString& key, bool defaultValue){
91    return readValue(_namespace, key, defaultValue).toBool();
92}
93int DAStorage::readInt(const QString& _namespace, const QString& key, int defaultValue){
94    return readValue(_namespace, key, defaultValue).toInt();
95}
96QString DAStorage::readString(const QString& _namespace, const QString& key, const QString& defaultValue){
97    return readValue(_namespace, key, defaultValue).toString();
98}
99QString DAStorage::readEncryptedString(const QString& _namespace, const QString& key, const QString& password, const QString& defaultValue) {
100    QString value = readString(_namespace, key, defaultValue);
101    if (value == defaultValue){
102        return defaultValue;
103    }
104
105    std::string decrypted;
106
107    try {
108        CryptoPP::StringSource(
109            value.toStdString(),
110            true,
111            new CryptoPP::DefaultDecryptor(
112                password.toUtf8().data(),
113                new CryptoPP::StringSink(decrypted)
114            )
115        );
116
117        return QString::fromStdString(decrypted);
118    } catch (...) {
119        qCritical() << "Could not decrypt an encrypted password";
120        return "";
121    }
122}
123QImage DAStorage::readImage(const QString& _namespace, const QString& key, const QImage& defaultValue) {
124    return QImage::fromData(readValue(_namespace, key, defaultValue).toByteArray());
125}
126
127IContact* DAStorage::readContact(int contactId){
128    IContact* contact = new SContact();
129
130    QSqlQuery query = createQuery();
131    query.exec("SELECT name, number "
132                    "FROM t_contacts "
133                    "WHERE (contactId = '" + QString::number(contactId) + "'); ");
134    if (!query.next()) {
135        throw Storage::EReadException(tr("No such contact in the database! [contactId: %1]").arg(contactId));
136    }
137
138    contact->setId(contactId);
139    contact->setName(query.value(0).toString());
140    contact->setNumber(query.value(1).toString());
141
142    QString aliasesStr  = readString("contact_" + QString::number(contactId), "aliases", "");
143    QStringList aliases = aliasesStr.split("\t", QString::SkipEmptyParts);
144    contact->setAliases(aliases);
145
146    contact->setImage(readImage("contact_" + QString::number(contactId), "image", QImage()));
147    return contact;
148}
149
150IGroup* DAStorage::readGroup(int groupId){
151    IGroup* group = new SGroup();
152
153    QSqlQuery query = createQuery();
154    query.exec("SELECT name "
155                    "FROM t_groups "
156                    "WHERE (groupId = '" + QString::number(groupId) + "'); ");
157    if (!query.next()) {
158        throw Storage::EReadException(tr("No such group in the database! [groupId: %1]").arg(groupId));
159    }
160
161    group->setId(groupId);
162    group->setName(query.value(0).toString());
163    group->setImage(readImage("group_" + QString::number(groupId), "image", QImage()));
164
165    QString contactIdsStr  = readString("group_" + QString::number(groupId), "contacts", "");
166    QStringList contactIds = contactIdsStr.split("\t", QString::SkipEmptyParts);
167    foreach (QString contactStr, contactIds) {
168        bool ok;
169        int contactId = contactStr.toInt(&ok);
170        if (ok) {
171            IContact* contact = BCContactManager::instance()->getContact(contactId);
172            group->addContact(contact);
173        }
174    }
175
176    return group;
177}
178
179SShortcut DAStorage::readShortcut(const QString& key){
180    SShortcut shortcut;
181    shortcut.fromString(readString("shortcut", key, ""));
182    return shortcut;
183//    BCShortcut shortcut = from_string<BCShortcut>(readString("shortcut", key, ""));
184//    return new BCShortcut(shortcut);
185}
186
187
188QSet<IContact*> DAStorage::readContactList(){
189    QSet<IContact*> contactList;
190
191    QSqlQuery query = createQuery();
192    query.exec("SELECT contactId "
193                 "FROM t_contacts; ");
194    while (query.next()) {
195        try{
196            int contactId = query.value(0).toInt();
197            contactList.insert(readContact(contactId));
198        }catch (const Storage::EReadException& e){
199            // TODO: What shall be done here?
200        }catch (const EParseException& e){
201            // ... and here?
202        }
203    }
204    return contactList;
205}
206
207QSet<IGroup*> DAStorage::readGroupList(){
208    QSet<IGroup*> groupList;
209
210    QSqlQuery query = createQuery();
211    query.exec("SELECT groupId "
212                 "FROM t_groups; ");
213    while (query.next()) {
214        try{
215            int groupId = query.value(0).toInt();
216            groupList.insert(readGroup(groupId));
217        }catch (const Storage::EReadException& e){
218            // TODO: What shall be done here?
219        }catch (const EParseException& e){
220            // ... and here?
221        }
222    }
223    return groupList;
224}
225
226
227void DAStorage::writeValue(const QString& _namespace, const QString& key, const QVariant& value) {
228    QSqlQuery query = createQuery();
229    query.prepare("INSERT OR REPLACE INTO t_settings (namespace, key, value) "
230                    "VALUES (:namespace, :key, :value)");
231    query.bindValue(":namespace", _namespace);
232    query.bindValue(":key", key);
233    query.bindValue(":value", value);
234
235    if (!query.exec()) {
236        throw Storage::EWriteException(tr("Could not write setting to the database."));
237    }
238
239}
240void DAStorage::writeBool(const QString& _namespace, const QString& key, bool value){
241    writeValue(_namespace, key, value);
242}
243void DAStorage::writeInt(const QString& _namespace, const QString& key, int value){
244    writeValue(_namespace, key, value);
245}
246void DAStorage::writeString(const QString& _namespace, const QString& key, const QString& value){
247    writeValue(_namespace, key, value);
248}
249void DAStorage::writeEncryptedString(const QString& _namespace, const QString& key, const QString& password, const QString& value){
250    int x = 0;
251    while (readEncryptedString(_namespace, key, password, "") != value) {
252        /* Do not write the password, if it is already in the storage. (Because it is an other every write -> hack is possible)
253         * Write the password as many times, until the reading of it results in the same value as written... (prevents data-loss because of invalid chars)
254         */
255
256        if (x > 10) {
257            throw Storage::EWriteException(tr("Could not write an encrypted string to the database. [%1, %2]").arg(_namespace).arg(key));
258        }
259
260        std::string encrypted;
261        CryptoPP::StringSource(
262            value.toStdString(),
263            true,
264            new CryptoPP::DefaultEncryptor(
265                password.toUtf8().data(),
266                new CryptoPP::StringSink(encrypted)
267            )
268        );
269
270        writeString(_namespace, key, QString::fromStdString(encrypted));
271        x++;
272    }
273}
274void DAStorage::writeImage(const QString& _namespace, const QString& key, const QImage& image) {
275    QByteArray ba;
276    QBuffer buffer(&ba);
277    buffer.open(QIODevice::WriteOnly);
278    image.save(&buffer, "PNG");
279    writeValue(_namespace, key, ba);
280}
281
282
283void DAStorage::writeContact(IContact* contact) {
284    QSqlQuery query = createQuery();
285    query.exec("SELECT contactId "
286                 "FROM t_contacts "
287                 "WHERE (contactId = '" + QString::number(contact->id()) + "'); ");
288
289    if (!query.next()){
290        // Insert
291        query.prepare("INSERT INTO t_contacts (name, number) "
292                        "VALUES (:name, :number);");
293        query.bindValue(":name", contact->name());
294        query.bindValue(":number", contact->number().toString());
295        if (!query.exec()) {
296            throw Storage::EWriteException(tr("The contact could not have been written to the database."));
297        }
298
299        // Set the contactId since it is undefined if the contact was not saved before.
300        query.exec("SELECT contactId "
301                     "FROM t_contacts "
302                     "WHERE (name = '" + contact->name() + "'); ");
303        if (!query.next()) {
304            throw Storage::EWriteException(tr("The contact could not have been written to the database."));
305        }
306        contact->setId(query.value(0).toInt());
307    }else{
308        // Update
309        query.prepare("UPDATE t_contacts SET "
310                        "name=:name, "
311                        "number=:number "
312                      "WHERE (contactId = :contactId); ");
313        query.bindValue(":name", contact->name());
314        query.bindValue(":number", contact->number().toString());
315        query.bindValue(":contactId", contact->id());
316
317        if (!query.exec()) {
318            throw Storage::EWriteException(tr("The contact could not have been written to the database."));
319        }
320    }
321
322    // Save the aliases of the contact
323    QString aliasesStr = "";
324    QStringList aliases = contact->aliases();
325    for (int x = 0; x < aliases.size(); ++x){
326        QString alias = aliases.at(x);
327        alias.replace("\t", " ");
328
329        aliasesStr += alias + "\t";
330    }
331    aliasesStr.remove(QRegExp("\\t$")); // Remove last "\t"
332    writeString("contact_" + QString::number(contact->id()), "aliases", aliasesStr);
333
334    writeImage("contact_" + QString::number(contact->id()), "image", contact->image());
335}
336
337void DAStorage::writeGroup(IGroup* group){
338    QSqlQuery query = createQuery();
339    query.exec("SELECT groupId "
340                 "FROM t_groups "
341                 "WHERE (groupId = '" + QString::number(group->id()) + "'); ");
342    if (!query.next()) {
343        // Insert
344        query.prepare("INSERT INTO t_groups (name) "
345                        "VALUES (:name);");
346        query.bindValue(":name", group->name());
347        if (!query.exec()) {
348            throw Storage::EWriteException(tr("The group could not have been written to the database."));
349        }
350
351        // Set the groupId since it is undefined if the group was not saved before.
352        query.exec("SELECT groupId "
353                     "FROM t_groups "
354                     "WHERE (name = '" + group->name() + "'); ");
355        if (!query.next()) {
356            throw Storage::EWriteException(tr("The group could not have been written to the database."));
357        }
358        group->setId(query.value(0).toInt());
359    }else{
360        // Update
361        query.prepare("UPDATE t_groups SET "
362                        "name=:name "
363                      "WHERE (groupId = :groupId); ");
364        query.bindValue(":name", group->name());
365        query.bindValue(":groupId", group->id());
366
367        if (!query.exec()) {
368            throw Storage::EWriteException(tr("The group could not have been written to the database."));
369        }
370    }
371    writeImage("group_" + QString::number(group->id()), "image", group->image());
372
373    // Save the contacts of the group
374    QString contactIdsStr = "";
375    foreach (IContact* contact, group->contacts()) {
376        contactIdsStr += to_string(contact->id()) + "\t";
377    }
378    contactIdsStr.resize(contactIdsStr.size() - 1); // Remove last "\t"
379    writeString("group_" + to_string(group->id()), "contacts", contactIdsStr);
380}
381
382void DAStorage::writeShortcut(const QString& key, const SShortcut& shortcut){
383    if (shortcut.isValid()) {
384        writeString("shortcut", key, shortcut.toString());
385    } else {
386        removeValue("shortcut", key);
387    }
388}
389
390
391void DAStorage::removeValue(const QString& _namespace, const QString& key) {
392    QSqlQuery query = createQuery();
393    query.prepare("DELETE FROM t_settings "
394                    "WHERE (namespace = '" + _namespace + "') "
395                      "AND (key = '" + key + "'); ");
396    if (!query.exec()) {
397        throw Storage::EWriteException(tr("Could not remove the setting from the database."));
398    }
399}
400
401void DAStorage::removeValues(const QString& _namespace) {
402    QSqlQuery query = createQuery();
403    query.prepare("DELETE FROM t_settings "
404                    "WHERE (namespace = '" + _namespace + "'); ");
405    if (!query.exec()) {
406        throw Storage::EWriteException(tr("Could not remove the settings from the database."));
407    }
408}
409
410
411void DAStorage::removeContact(int contactId){
412    try {
413        // Remove the settings of the contact
414        removeValues("contact_" + contactId);
415
416        // Remove the contact itself
417        QSqlQuery query = createQuery();
418        query.prepare("DELETE FROM t_contacts "
419                        "WHERE (contactId = '" + QString::number(contactId) + "'); ");
420        if (!query.exec()) {
421            throw;
422        }
423    } catch (...) {
424        throw Storage::EWriteException(tr("Could not remove the contact from the database."));
425    }
426}
427
428void DAStorage::removeGroup(int groupId){
429    try {
430        // Remove the settings of the group
431        removeValues("group_" + groupId);
432
433        // Remove the group itself
434        QSqlQuery query = createQuery();
435        query.prepare("DELETE FROM t_groups "
436                        "WHERE (groupId = '" + QString::number(groupId) + "'); ");
437        if (!query.exec()) {
438            throw;
439        }
440    } catch (...) {
441        throw Storage::EWriteException(tr("Could not remove the group from the database."));
442    }
443}
Note: See TracBrowser for help on using the repository browser.