diff options
Diffstat (limited to 'smartpensyncer.cc')
-rw-r--r-- | smartpensyncer.cc | 214 |
1 files changed, 214 insertions, 0 deletions
diff --git a/smartpensyncer.cc b/smartpensyncer.cc new file mode 100644 index 0000000..50304a3 --- /dev/null +++ b/smartpensyncer.cc @@ -0,0 +1,214 @@ +#include <QtCore/QBuffer> +#include <QtCore/QScopedArrayPointer> +#include <QtCore/QThread> +#include <QtCore/QDebug> +#include <QtGui/QDesktopServices> +#include <quazip/quazipfile.h> +#include "smartpensyncer.h" + +#define BUFFER_SIZE 16 * 1024 + +namespace { +static QString cleanFilename(QString s) +{ + static const QRegExp re("[^0-9A-Za-z-_]+"); + return s.replace(re, "_"); +} + +static QDateTime getTimestampFileDate(const QString &path) +{ + QFileInfo info(path); + qDebug() << "Checking timestamp" << info.filePath(); + if (info.exists()) { + return info.lastModified(); + } else { + return QDateTime(); + } +} + +static void setTimestampFileDate(const QString &path) +{ + QFile f(path); + if (!f.open(QIODevice::WriteOnly | QIODevice::Truncate)) { + qWarning() << "Could not set timestamp file:" << path; + return; + } + f.close(); +} + +void removeTimestampFile(const QString &path) +{ + QFile f(path); + if (!f.remove()) { + qWarning() << "Cannot remove timestamp file:" << path; + } +} +} + +SmartpenSyncer::SmartpenSyncer(const Smartpen::Address &addr, QObject *parent) : + QThread(parent), _addr(addr), _pen(new Smartpen(this)), _errored(false), _aborted(false) +{ +} + +SmartpenSyncer::~SmartpenSyncer() +{ + if (isRunning()) { + _aborted = true; + wait(); + } +} + +Smartpen::Address SmartpenSyncer::penAddress() const +{ + return _addr; +} + +void SmartpenSyncer::abort() +{ + _aborted = true; +} + +void SmartpenSyncer::run() +{ + if (!_pen->connectToPen(_addr)) { + qWarning() << "Could not connect to pen with USB address: " << _addr; + _errored = true; + return; + } + + _penName = _pen->getPenName(); + qDebug() << "got pen name:" << _penName; + + QVariantMap penInfo = _pen->getPenInfo(); + if (penInfo.isEmpty()) { + qWarning() << "Could not get pen info"; + _errored = true; + return; + } + + _penSerial = penInfo["penserial"].toString(); + + _penDataDir.setPath(QDesktopServices::storageLocation(QDesktopServices::DataLocation) + "/" + _penName + ".pen"); + if (!_penDataDir.exists()) { + if (!_penDataDir.mkpath(".")) { + qWarning() << "Cannot create pen data directory:" << _penDataDir.absolutePath(); + } + } + + if (!syncPen()) { + _errored = true; + } + + _pen->disconnectFromPen(); +} + +bool SmartpenSyncer::syncPen() +{ + QDateTime lastSyncTime = getTimestampFileDate(_penDataDir.filePath(".lastsync")); + QList<Smartpen::ChangeReport> changes = _pen->getChangeList(lastSyncTime); + + foreach(const Smartpen::ChangeReport &change, changes) { + qDebug() << "Synchronizing guid: " << change.guid << change.title; + if (!syncNotebook(change)) { + return false; + } + } + + setTimestampFileDate(_penDataDir.filePath(".lastsync")); + + return true; +} + +bool SmartpenSyncer::syncNotebook(const Smartpen::ChangeReport &change) +{ + QDir notebookDir(_penDataDir.filePath(change.title + ".afd")); + if (!notebookDir.exists()) { + if (!notebookDir.mkpath(".")) { + qWarning() << "Cannot create notebook data directory:" << notebookDir.absolutePath(); + } + } + + setTimestampFileDate(notebookDir.filePath(".sync.lck")); + + QDateTime lastSyncTime = getTimestampFileDate(notebookDir.filePath(".lastsync")); + QByteArray lspData = _pen->getLspData(change.guid, lastSyncTime); + + if (!extractZip(lspData, notebookDir)) { + return false; + } + + setTimestampFileDate(notebookDir.filePath(".lastsync")); + removeTimestampFile(notebookDir.filePath(".sync.lck")); + + return true; +} + +bool SmartpenSyncer::extractZip(QByteArray &zipData, QDir &dir) +{ + QBuffer zipBuffer(&zipData); + QuaZip zip(&zipBuffer); + QuaZipFile zipFile(&zip); + + if (!zip.open(QuaZip::mdUnzip)) { + qWarning() << "Could not open zip file"; + return false; + } + + QScopedArrayPointer<char> buffer(new char[BUFFER_SIZE]); + + for (bool more=zip.goToFirstFile(); more; more=zip.goToNextFile()) { + QString zipName = zip.getCurrentFileName(); + if (!dir.absoluteFilePath(zipName).startsWith(dir.absolutePath())) { + qWarning() << "broken zip filename:" << zipName; + continue; + } + QFileInfo finfo(dir.filePath(zipName)); + if (!dir.mkpath(finfo.path())) { + qWarning() << "cannot mkpath for:" << finfo.absoluteFilePath(); + } + + if (zipName.endsWith('/')) { + // Nothing to do + continue; + } + + if (!zipFile.open(QIODevice::ReadOnly)) { + qWarning() << "cannot open zip file for reading:" << zipName; + continue; + } + + QFile file(finfo.filePath()); + if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate)) { + qWarning() << "cannot open for writing:" << finfo.absoluteFilePath(); + zipFile.close(); + continue; + } + + while (!zipFile.atEnd()) { + qint64 read = zipFile.read(buffer.data(), BUFFER_SIZE); + if (read <= 0) { + qWarning() << "short read on:" << zipName; + zipFile.close(); + continue; + } + qint64 written = file.write(buffer.data(), read); + if (written != read) { + qWarning() << "short write on:" << file.fileName(); + zipFile.close(); + continue; + } + } + + file.close(); + zipFile.close(); + } + + buffer.reset(); + + if (zip.getZipError() == UNZ_OK) { + return true; + } else { + qWarning() << "Error while decompressing"; + return false; + } +} |