summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJason A. Donenfeld <Jason@zx2c4.com>2011-02-12 04:52:04 -0500
committerJason A. Donenfeld <Jason@zx2c4.com>2011-02-12 04:52:04 -0500
commitefdb770e67c539722b27e9dd80a5131e4e1ad574 (patch)
tree501611f162e1bb3e5b93d52d95c6b67cba430243
downloadoldgen-zmusicuploader-efdb770e67c539722b27e9dd80a5131e4e1ad574.tar.xz
oldgen-zmusicuploader-efdb770e67c539722b27e9dd80a5131e4e1ad574.zip
Initial version.
-rw-r--r--DirectoryScanner.cpp36
-rw-r--r--DirectoryScanner.h25
-rw-r--r--Uploader.cpp111
-rw-r--r--Uploader.h44
-rw-r--r--XorEncrypter.cpp86
-rw-r--r--XorEncrypter.h37
-rw-r--r--main.cpp19
-rw-r--r--musicuploader.pro15
8 files changed, 373 insertions, 0 deletions
diff --git a/DirectoryScanner.cpp b/DirectoryScanner.cpp
new file mode 100644
index 0000000..56029df
--- /dev/null
+++ b/DirectoryScanner.cpp
@@ -0,0 +1,36 @@
+#include "DirectoryScanner.h"
+#include <QDir>
+#include <QFile>
+#include <QCryptographicHash>
+#include <QDebug>
+
+DirectoryScanner::DirectoryScanner(const QString &rootDirectory, const QString &secretSalt) :
+ m_hasher(QCryptographicHash::Sha1),
+ m_secretSalt(secretSalt)
+{
+ QDir dir(rootDirectory);
+ m_absoluteRoot = dir.canonicalPath();
+ if (dir.exists())
+ scanDirectory(dir);
+}
+void DirectoryScanner::scanDirectory(const QDir &directory)
+{
+ foreach (const QFileInfo &fileInfo, directory.entryInfoList(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot | QDir::Readable)) {
+ if (fileInfo.isDir())
+ scanDirectory(QDir(fileInfo.absoluteFilePath()));
+ else if (fileInfo.isFile()) {
+ QString filePath = fileInfo.canonicalFilePath();
+ if (filePath.startsWith(m_absoluteRoot))
+ filePath = filePath.remove(0, m_absoluteRoot.length());
+ filePath.append(m_secretSalt);
+ filePath.prepend(m_secretSalt);
+ m_hasher.addData(filePath.toUtf8());
+ m_files.insert(m_hasher.result().toHex(), fileInfo);
+ m_hasher.reset();
+ }
+ }
+}
+const QHash<const QString, QFileInfo> DirectoryScanner::fileList() const
+{
+ return m_files;
+}
diff --git a/DirectoryScanner.h b/DirectoryScanner.h
new file mode 100644
index 0000000..dbdc9e9
--- /dev/null
+++ b/DirectoryScanner.h
@@ -0,0 +1,25 @@
+#ifndef DIRECTORYSCANNER_H
+#define DIRECTORYSCANNER_H
+
+#include <QString>
+#include <QByteArray>
+#include <QHash>
+#include <QDateTime>
+#include <QDir>
+#include <QCryptographicHash>
+
+class DirectoryScanner
+{
+public:
+ DirectoryScanner(const QString &rootDirectory, const QString &secretSalt);
+ const QHash<const QString, QFileInfo> fileList() const;
+
+private:
+ void scanDirectory(const QDir &directory);
+ QHash<const QString, QFileInfo> m_files;
+ QCryptographicHash m_hasher;
+ QString m_absoluteRoot;
+ QString m_secretSalt;
+};
+
+#endif // DIRECTORYSCANNER_H
diff --git a/Uploader.cpp b/Uploader.cpp
new file mode 100644
index 0000000..3ea5678
--- /dev/null
+++ b/Uploader.cpp
@@ -0,0 +1,111 @@
+#include "Uploader.h"
+#include "XorEncrypter.h"
+#include <iostream>
+using namespace std;
+
+Uploader::Uploader(const QString &ftpServer, const QString &ftpPath, const QString &username, const QString &password, const QByteArray &secretKey, const QHash<const QString, QFileInfo> &fileList, QObject *parent) :
+ QObject(parent),
+ m_fileList(fileList),
+ m_ftp(this),
+ m_ftpServer(ftpServer),
+ m_ftpPath(ftpPath),
+ m_username(username),
+ m_password(password),
+ m_secretKey(secretKey),
+ m_cdCommand(-1),
+ m_latestCommand(-1),
+ m_latestPut(-1),
+ m_currentFile(0)
+{
+ connect(&m_ftp, SIGNAL(stateChanged(int)), this, SLOT(stateChanged(int)));
+ connect(&m_ftp, SIGNAL(commandFinished(int,bool)), this, SLOT(commandFinished(int,bool)));
+ connect(&m_ftp, SIGNAL(listInfo(QUrlInfo)), this, SLOT(listInfo(QUrlInfo)));
+ connect(&m_ftp, SIGNAL(dataTransferProgress(qint64,qint64)), this, SLOT(dataTransferProgress(qint64,qint64)));
+}
+void Uploader::begin()
+{
+ m_ftp.connectToHost(m_ftpServer);
+}
+void Uploader::stateChanged(int state)
+{
+ switch (state) {
+ case QFtp::Connected:
+ cerr << "Connected." << endl;
+ m_ftp.login(m_username, m_password);
+ break;
+ case QFtp::LoggedIn:
+ cerr << "Logged in." << endl;
+ m_cdCommand = m_ftp.cd(m_ftpPath);
+ break;
+ case QFtp::Unconnected:
+ cerr << "Unconnected" << endl;
+ break;
+ case QFtp::HostLookup:
+ cerr << "Looking up host" << endl;
+ break;
+ case QFtp::Connecting:
+ cerr << "Connecting" << endl;
+ break;
+ case QFtp::Closing:
+ cerr << "Closing" << endl;
+ emit done();
+ break;
+ }
+}
+void Uploader::commandFinished(int id, bool error)
+{
+ if (id == m_latestPut && m_currentFile) {
+ m_currentFile->close();
+ m_currentFile->deleteLater();
+ }
+
+ if (error) {
+ cerr << m_ftp.errorString().toStdString() << endl;
+ emit done();
+ return;
+ }
+ if (id == m_cdCommand)
+ m_latestCommand = m_ftp.list();
+ if (id == m_latestCommand) {
+ if (!m_fileList.size()) {
+ cerr << "No files to upload." << endl;
+ emit done();
+ return;
+ }
+ m_listPosition = m_fileList.constBegin();
+ uploadNextFile();
+ }
+ if (id == m_latestPut) {
+ cerr << endl;
+ uploadNextFile();
+ }
+}
+void Uploader::listInfo(const QUrlInfo &i)
+{
+ if (m_fileList.contains(i.name())) {
+ const QFileInfo &info = m_fileList.value(i.name());
+ if (info.lastModified() < i.lastModified() && info.size() == i.size())
+ m_fileList.remove(i.name());
+ } else {
+ cerr << i.name().toStdString() << " has disappeared locally." << endl;
+ m_latestCommand = m_ftp.remove(i.name());
+ }
+}
+void Uploader::uploadNextFile()
+{
+ if (m_listPosition == m_fileList.constEnd()) {
+ cerr << "Complete!" << endl;
+ emit done();
+ return;
+ }
+ cerr << "Uploading " << m_listPosition.value().absoluteFilePath().toStdString() << endl;
+ m_currentFile = new QFile(m_listPosition.value().absoluteFilePath());
+ m_currentFile->open(QIODevice::ReadOnly);
+ XorEncrypter *xorEncrypter = new XorEncrypter(m_secretKey, m_currentFile);
+ m_latestPut = m_ftp.put(xorEncrypter, m_listPosition.key());
+ ++m_listPosition;
+}
+void Uploader::dataTransferProgress(qint64 done, qint64 total)
+{
+ cerr << done << " of " << total << " bytes transferred.\r";
+}
diff --git a/Uploader.h b/Uploader.h
new file mode 100644
index 0000000..ccd36c1
--- /dev/null
+++ b/Uploader.h
@@ -0,0 +1,44 @@
+#ifndef UPLOADER_H
+#define UPLOADER_H
+
+#include <QObject>
+#include <QFtp>
+#include <QHash>
+#include <QFile>
+#include <QByteArray>
+#include "DirectoryScanner.h"
+
+class Uploader : public QObject
+{
+ Q_OBJECT
+public:
+ Uploader(const QString &ftpServer, const QString &ftpPath, const QString &username, const QString &password, const QByteArray &secretKey, const QHash<const QString, QFileInfo> &fileList, QObject *parent = 0);
+ void begin();
+
+private:
+ void uploadNextFile();
+ QHash<const QString, QFileInfo> m_fileList;
+ QHash<const QString, QFileInfo>::const_iterator m_listPosition;
+ QFtp m_ftp;
+ QString m_ftpServer;
+ QString m_ftpPath;
+ QString m_username;
+ QString m_password;
+ QByteArray m_secretKey;
+ int m_cdCommand;
+ int m_latestCommand;
+ int m_latestPut;
+ QFile *m_currentFile;
+
+private slots:
+ void stateChanged(int state);
+ void commandFinished(int id, bool error);
+ void listInfo(const QUrlInfo &i);
+ void dataTransferProgress(qint64 done, qint64 total);
+
+signals:
+ void done();
+
+};
+
+#endif // UPLOADER_H
diff --git a/XorEncrypter.cpp b/XorEncrypter.cpp
new file mode 100644
index 0000000..71369ca
--- /dev/null
+++ b/XorEncrypter.cpp
@@ -0,0 +1,86 @@
+#include "XorEncrypter.h"
+
+XorEncrypter::XorEncrypter(const QByteArray &key, QIODevice *parentDevice) :
+ QIODevice(parentDevice),
+ m_key(key),
+ m_keyLength(key.length()),
+ m_parentDevice(parentDevice)
+{
+ connect(parentDevice, SIGNAL(aboutToClose()), this, SIGNAL(aboutToClose()));
+ connect(parentDevice, SIGNAL(bytesWritten(qint64)), this, SIGNAL(bytesWritten(qint64)));
+ connect(parentDevice, SIGNAL(readChannelFinished()), this, SIGNAL(readChannelFinished()));
+ connect(parentDevice, SIGNAL(readyRead()), this, SIGNAL(readyRead()));
+ if (parentDevice->isOpen())
+ QIODevice::open(parentDevice->openMode());
+}
+qint64 XorEncrypter::readData(char *data, qint64 maxSize)
+{
+ qint64 startPos = pos();
+ qint64 total = m_parentDevice->read(data, maxSize);
+ for (qint64 i = 0; i < total; ++i)
+ data[i] ^= m_key.at((startPos + i) % m_keyLength);
+ return total;
+}
+qint64 XorEncrypter::writeData(const char *data, qint64 maxSize)
+{
+ char *encryptedData = new char[maxSize];
+ qint64 startPos = pos();
+ for (qint64 i = 0; i < maxSize; ++i)
+ encryptedData[i] = data[i] ^ m_key.at((startPos + i) % m_keyLength);
+ return m_parentDevice->write(encryptedData, maxSize);
+}
+
+bool XorEncrypter::atEnd() const
+{
+ return m_parentDevice->atEnd();
+}
+qint64 XorEncrypter::bytesAvailable() const
+{
+ return m_parentDevice->bytesAvailable();
+}
+qint64 XorEncrypter::bytesToWrite() const
+{
+ return m_parentDevice->bytesToWrite();
+}
+bool XorEncrypter::canReadLine() const
+{
+ return m_parentDevice->canReadLine();
+}
+void XorEncrypter::close()
+{
+ QIODevice::close();
+ return m_parentDevice->close();
+}
+bool XorEncrypter::isSequential() const
+{
+ return m_parentDevice->isSequential();
+}
+bool XorEncrypter::open(OpenMode mode)
+{
+ QIODevice::open(mode);
+ return m_parentDevice->open(mode);
+}
+qint64 XorEncrypter::pos() const
+{
+ return m_parentDevice->pos();
+}
+bool XorEncrypter::reset()
+{
+ return m_parentDevice->reset();
+}
+bool XorEncrypter::seek(qint64 pos)
+{
+ return m_parentDevice->seek(pos);
+}
+qint64 XorEncrypter::XorEncrypter::size() const
+{
+ return m_parentDevice->size();
+}
+bool XorEncrypter::waitForBytesWritten(int msecs)
+{
+ return m_parentDevice->waitForBytesWritten(msecs);
+}
+bool XorEncrypter::waitForReadyRead(int msecs)
+{
+ return m_parentDevice->waitForReadyRead(msecs);
+}
diff --git a/XorEncrypter.h b/XorEncrypter.h
new file mode 100644
index 0000000..e78c5a5
--- /dev/null
+++ b/XorEncrypter.h
@@ -0,0 +1,37 @@
+#ifndef XORENCRYPTER_H
+#define XORENCRYPTER_H
+
+#include <QIODevice>
+
+class XorEncrypter : public QIODevice
+{
+ Q_OBJECT
+public:
+ XorEncrypter(const QByteArray &key, QIODevice *parentDevice);
+ bool atEnd() const;
+ qint64 bytesAvailable() const;
+ qint64 bytesToWrite() const;
+ bool canReadLine() const;
+ void close();
+ bool isSequential() const;
+ bool open(OpenMode mode);
+ qint64 pos() const;
+ bool reset();
+ bool seek(qint64 pos);
+ qint64 size() const;
+ bool waitForBytesWritten(int msecs);
+ bool waitForReadyRead(int msecs);
+
+
+protected:
+ qint64 readData(char *data, qint64 maxSize);
+ qint64 writeData(const char *data, qint64 maxSize);
+
+private:
+ const QByteArray m_key;
+ const int m_keyLength;
+ QIODevice *m_parentDevice;
+
+};
+
+#endif // XORENCRYPTER_H
diff --git a/main.cpp b/main.cpp
new file mode 100644
index 0000000..2bf96d4
--- /dev/null
+++ b/main.cpp
@@ -0,0 +1,19 @@
+#include <QCoreApplication>
+#include <QFile>
+#include "Uploader.h"
+#include "DirectoryScanner.h"
+#include <iostream>
+using namespace std;
+
+int main(int argc, char *argv[])
+{
+ if (argc < 8) {
+ cerr << "Usage: " << argv[0] << " localpath serverhost serverpath username password xorkey hashsalt" << endl;
+ return 1;
+ }
+ QCoreApplication a(argc, argv);
+ Uploader uploader(argv[2], argv[3], argv[4], argv[5], argv[6], DirectoryScanner(argv[1], argv[7]).fileList());
+ QObject::connect(&uploader, SIGNAL(done()), &a, SLOT(quit()));
+ uploader.begin();
+ return a.exec();
+}
diff --git a/musicuploader.pro b/musicuploader.pro
new file mode 100644
index 0000000..935b99e
--- /dev/null
+++ b/musicuploader.pro
@@ -0,0 +1,15 @@
+QT += core network
+QT -= gui
+TARGET = musicuploader
+CONFIG += console
+CONFIG -= app_bundle
+TEMPLATE = app
+SOURCES += main.cpp \
+ XorEncrypter.cpp \
+ DirectoryScanner.cpp \
+ Uploader.cpp
+
+HEADERS += \
+ XorEncrypter.h \
+ DirectoryScanner.h \
+ Uploader.h