diff options
author | 2011-02-12 04:52:04 -0500 | |
---|---|---|
committer | 2011-02-12 04:52:04 -0500 | |
commit | efdb770e67c539722b27e9dd80a5131e4e1ad574 (patch) | |
tree | 501611f162e1bb3e5b93d52d95c6b67cba430243 | |
download | oldgen-zmusicuploader-efdb770e67c539722b27e9dd80a5131e4e1ad574.tar.xz oldgen-zmusicuploader-efdb770e67c539722b27e9dd80a5131e4e1ad574.zip |
Initial version.
-rw-r--r-- | DirectoryScanner.cpp | 36 | ||||
-rw-r--r-- | DirectoryScanner.h | 25 | ||||
-rw-r--r-- | Uploader.cpp | 111 | ||||
-rw-r--r-- | Uploader.h | 44 | ||||
-rw-r--r-- | XorEncrypter.cpp | 86 | ||||
-rw-r--r-- | XorEncrypter.h | 37 | ||||
-rw-r--r-- | main.cpp | 19 | ||||
-rw-r--r-- | musicuploader.pro | 15 |
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 |