source: SMSSender/src/persistence/storage/DAStorage.cpp @ 58:685f1614c319

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