diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c288530e7..73f4e7b4b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -26,6 +26,7 @@ set(keepassx_SOURCES core/Parser.cpp core/TimeInfo.cpp core/Uuid.cpp + core/Writer.cpp gui/EntryModel.cpp gui/GroupModel.cpp ) diff --git a/src/core/Entry.cpp b/src/core/Entry.cpp index 69bd96fe1..0685105b2 100644 --- a/src/core/Entry.cpp +++ b/src/core/Entry.cpp @@ -46,6 +46,16 @@ QImage Entry::icon() const return Database::icon(m_iconNumber); } +int Entry::iconNumber() const +{ + return m_iconNumber; +} + +Uuid Entry::iconUuid() const +{ + return m_customIcon; +} + QColor Entry::foregroundColor() const { return m_foregroundColor; diff --git a/src/core/Entry.h b/src/core/Entry.h index b68cc01dc..a50f22226 100644 --- a/src/core/Entry.h +++ b/src/core/Entry.h @@ -44,6 +44,8 @@ public: ~Entry(); Uuid uuid() const; QImage icon() const; + int iconNumber() const; + Uuid iconUuid() const; QColor foregroundColor() const; QColor backgroundColor() const; QString overrideUrl() const; diff --git a/src/core/Group.cpp b/src/core/Group.cpp index 85fe8ae2f..fa2983bf0 100644 --- a/src/core/Group.cpp +++ b/src/core/Group.cpp @@ -56,6 +56,16 @@ QImage Group::icon() const return Database::icon(m_iconNumber); } +int Group::iconNumber() const +{ + return m_iconNumber; +} + +Uuid Group::iconUuid() const +{ + return m_customIcon; +} + TimeInfo Group::timeInfo() const { return m_timeInfo; diff --git a/src/core/Group.h b/src/core/Group.h index 246000a22..1f82820a7 100644 --- a/src/core/Group.h +++ b/src/core/Group.h @@ -37,6 +37,8 @@ public: QString name() const; QString notes() const; QImage icon() const; + int iconNumber() const; + Uuid iconUuid() const; TimeInfo timeInfo() const; bool isExpanded() const; QString defaultAutoTypeSequence() const; diff --git a/src/core/Writer.cpp b/src/core/Writer.cpp new file mode 100644 index 000000000..b889e3b59 --- /dev/null +++ b/src/core/Writer.cpp @@ -0,0 +1,319 @@ +/* + * Copyright (C) 2010 Felix Geyer + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 or (at your option) + * version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "Writer.h" + +#include + +#include "core/Database.h" +#include "core/Metadata.h" + +Writer::Writer(Database* db) + : QObject(db) + , m_db(db) + , m_meta(db->metadata()) +{ + m_xml.setAutoFormatting(true); + m_xml.setAutoFormattingIndent(-1); + m_xml.setCodec("UTF-8"); + +} + +bool Writer::write(const QString& filename) +{ + m_xml.writeStartDocument("1.0", true); + + m_xml.writeStartElement("KeePassFile"); + + writeMetadata(); + writeRoot(); + + m_xml.writeEndElement(); + + m_xml.writeEndDocument(); + + return true; // TODO +} + +void Writer::writeMetadata() +{ + m_xml.writeStartElement("Meta"); + + writeString("Generator", m_meta->generator()); + writeString("DatabaseName", m_meta->name()); + writeDateTime("DatabaseNameChanged", m_meta->nameChanged()); + writeString("DatabaseDescription", m_meta->description()); + writeDateTime("DatabaseDescriptionChanged", m_meta->descriptionChanged()); + writeString("DefaultUserName", m_meta->defaultUserName()); + writeDateTime("DefaultUserNameChanged", m_meta->defaultUserNameChanged()); + writeNumber("MaintenanceHistoryDays", m_meta->maintenanceHistoryDays()); + writeMemoryProtection(); + writeCustomIcons(); + writeBool("RecycleBinEnabled", m_meta->recycleBinEnabled()); + writeUuid("RecycleBinUUID", m_meta->recycleBin()); + writeDateTime("RecycleBinChanged", m_meta->recycleBinChanged()); + writeUuid("EntryTemplatesGroup", m_meta->entryTemplatesGroup()); + writeDateTime("EntryTemplatesGroupChanged", m_meta->entryTemplatesGroupChanged()); + writeUuid("LastSelectedGroup", m_meta->lastSelectedGroup()); + writeUuid("LastTopVisibleGroup", m_meta->lastTopVisibleGroup()); + writeCustomData(); + + m_xml.writeEndElement(); +} + +void Writer::writeMemoryProtection() +{ + m_xml.writeStartElement("MemoryProtection"); + + writeBool("ProtectTitle", m_meta->protectTitle()); + writeBool("ProtectUserName", m_meta->protectUsername()); + writeBool("ProtectPassword", m_meta->protectPassword()); + writeBool("ProtectURL", m_meta->protectUrl()); + writeBool("ProtectNotes", m_meta->protectNotes()); + writeBool("AutoEnableVisualHiding", m_meta->autoEnableVisualHiding()); + + m_xml.writeEndElement(); +} + +void Writer::writeCustomIcons() +{ + m_xml.writeStartElement("CustomIcons"); + + Q_FOREACH (const Uuid& uuid, m_meta->customIcons().keys()) { + writeIcon(uuid, m_meta->customIcons().value(uuid)); + } + + m_xml.writeEndElement(); +} + +void Writer::writeIcon(const Uuid& uuid, const QImage& image) +{ + m_xml.writeStartElement("Icon"); + + writeUuid("UUID", uuid); + + QByteArray ba; + QBuffer buffer(&ba); + buffer.open(QIODevice::WriteOnly); + image.save(&buffer, "PNG"); + buffer.close(); + writeBinary("Data", ba); + + m_xml.writeEndElement(); +} + +void Writer::writeCustomData() +{ + m_xml.writeStartElement("CustomData"); + + // TODO implement + + m_xml.writeEndElement(); +} + +void Writer::writeRoot() +{ + Q_ASSERT(m_db->rootGroup()); + + m_xml.writeStartElement("Root"); + + writeGroup(m_db->rootGroup()); + + m_xml.writeEndElement(); +} + +void Writer::writeGroup(const Group* group) +{ + m_xml.writeStartElement("Group"); + + writeUuid("UUID", group->uuid()); + writeString("Name", group->name()); + writeNumber("IconID", group->iconNumber()); + writeUuid("CustomIconUUID", group->iconUuid()); + writeTimes(group->timeInfo()); + writeBool("IsExpanded", group->isExpanded()); + writeString("DefaultAutoTypeSequence", group->defaultAutoTypeSequence()); + // TODO EnableAutoType + // TODO EnableSearching + writeUuid("LastTopVisibleEntry", group->lastTopVisibleEntry()); + + Q_FOREACH (const Group* child, group->children()) { + writeGroup(child); + } + + Q_FOREACH (const Entry* entry, group->entries()) { + writeEntry(entry); + } + + m_xml.writeEndElement(); +} + +void Writer::writeTimes(const TimeInfo& ti) +{ + m_xml.writeStartElement("Times"); + + writeDateTime("LastModificationTime", ti.lastModificationTime()); + writeDateTime("CreationTime", ti.creationTime()); + writeDateTime("LastAccessTime", ti.lastAccessTime()); + writeDateTime("ExpiryTime", ti.expiryTime()); + writeBool("Expires", ti.expires()); + writeNumber("UsageCount", ti.usageCount()); + writeDateTime("LocationChanged", ti.locationChanged()); + + m_xml.writeEndElement(); +} + +void Writer::writeEntry(const Entry* entry) +{ + m_xml.writeStartElement("Entry"); + + writeUuid("UUID", entry->uuid()); + writeNumber("IconID", entry->iconNumber()); + writeUuid("CustomIconUUID", entry->iconUuid()); + writeColor("ForegroundColor", entry->foregroundColor()); + writeColor("BackgroundColor", entry->backgroundColor()); + writeString("OverrideURL", entry->overrideUrl()); + writeTimes(entry->timeInfo()); + + Q_FOREACH (const QString& key, entry->attributes()) { + m_xml.writeStartElement("String"); + writeString("Key", key); + writeString("Value", entry->attributes().value(key)); + m_xml.writeEndElement(); + } + + Q_FOREACH (const QString& key, entry->attachments()) { + m_xml.writeStartElement("Binary"); + writeString("Key", key); + writeBinary("Value", entry->attachments().value(key)); + m_xml.writeEndElement(); + } + + writeAutoType(entry); + writeEntryHistory(entry); + + m_xml.writeEndElement(); +} + +void Writer::writeAutoType(const Entry* entry) +{ + m_xml.writeStartElement("AutoType"); + + writeBool("Enabled", entry->autoTypeEnabled()); + writeNumber("DataTransferObfuscation", entry->autoTypeObfuscation()); + writeString("DefaultSequence", entry->defaultAutoTypeSequence()); + + Q_FOREACH (const AutoTypeAssociation& assoc, entry->autoTypeAssociations()) { + writeAutoTypeAssoc(assoc); + } + + m_xml.writeEndElement(); +} + +void Writer::writeAutoTypeAssoc(const AutoTypeAssociation& assoc) +{ + m_xml.writeStartElement("Association"); + + writeString("Window", assoc.window); + writeString("KeystrokeSequence", assoc.sequence); + + m_xml.writeEndElement(); +} + +void Writer::writeEntryHistory(const Entry* entry) +{ + m_xml.writeStartElement("History"); + + // TODO implement + Q_UNUSED(entry); + + m_xml.writeEndElement(); +} + +void Writer::writeString(const QString& qualifiedName, const QString& string) +{ + m_xml.writeTextElement(qualifiedName, string); +} + +void Writer::writeNumber(const QString& qualifiedName, int number) +{ + writeString(qualifiedName, QString::number(number)); +} + +void Writer::writeBool(const QString& qualifiedName, bool b) +{ + if (b) { + writeString(qualifiedName, "True"); + } + else { + writeString(qualifiedName, "False"); + } +} + +void Writer::writeDateTime(const QString& qualifiedName, const QDateTime& dateTime) +{ + writeString(qualifiedName, dateTime.toString(Qt::ISODate)); +} + +void Writer::writeUuid(const QString& qualifiedName, const Uuid& uuid) +{ + writeString(qualifiedName, uuid.toBase64()); +} + +void Writer::writeUuid(const QString& qualifiedName, const Group* group) +{ + if (group) { + writeUuid(qualifiedName, group->uuid()); + } + else { + writeUuid(qualifiedName, Uuid()); + } +} + +void Writer::writeUuid(const QString& qualifiedName, const Entry* entry) +{ + if (entry) { + writeUuid(qualifiedName, entry->uuid()); + } + else { + writeUuid(qualifiedName, Uuid()); + } +} + +void Writer::writeBinary(const QString& qualifiedName, const QByteArray& ba) +{ + writeString(qualifiedName, QString::fromAscii(ba.toBase64())); +} + +void Writer::writeColor(const QString& qualifiedName, const QColor& color) +{ + QString colorStr = QString("#%1%2%3").arg(colorPartToString(color.red())) + .arg(colorPartToString(color.green())) + .arg(colorPartToString(color.blue())); + + writeString(qualifiedName, colorStr); +} + +QString Writer::colorPartToString(int value) +{ + QString str = QString::number(value, 16).toUpper(); + if (str.length() == 1) { + str.prepend("0"); + } + + return str; +} diff --git a/src/core/Writer.h b/src/core/Writer.h new file mode 100644 index 000000000..b71f06af0 --- /dev/null +++ b/src/core/Writer.h @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2010 Felix Geyer + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 or (at your option) + * version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef KEEPASSX_WRITER_H +#define KEEPASSX_WRITER_H + +#include +#include +#include +#include + +#include "core/Entry.h" +#include "core/TimeInfo.h" +#include "core/Uuid.h" + +class Database; +class Group; +class Metadata; + +class Writer : public QObject +{ + Q_OBJECT + +public: + Writer(Database* db); + bool write(const QString& filename); + +private: + void writeMetadata(); + void writeMemoryProtection(); + void writeCustomIcons(); + void writeIcon(const Uuid& uuid, const QImage& image); + void writeCustomData(); + void writeRoot(); + void writeGroup(const Group* group); + void writeTimes(const TimeInfo& ti); + void writeEntry(const Entry* entry); + void writeAutoType(const Entry* entry); + void writeAutoTypeAssoc(const AutoTypeAssociation& assoc); + void writeEntryHistory(const Entry* entry); + + void writeString(const QString& qualifiedName, const QString& string); + void writeNumber(const QString& qualifiedName, int number); + void writeBool(const QString& qualifiedName, bool b); + void writeDateTime(const QString& qualifiedName, const QDateTime& dateTime); + void writeUuid(const QString& qualifiedName, const Uuid& uuid); + void writeUuid(const QString& qualifiedName, const Group* group); + void writeUuid(const QString& qualifiedName, const Entry* entry); + void writeBinary(const QString& qualifiedName, const QByteArray& ba); + void writeColor(const QString& qualifiedName, const QColor& color); + QString colorPartToString(int value); + + QXmlStreamWriter m_xml; + Database* m_db; + Metadata* m_meta; +}; + +#endif // KEEPASSX_WRITER_H